[PATCH v2 2/2] EAP peer/server: support for draft-ietf-emu-tls-eap-types-00

Alexander Clouter alex at digriz.org.uk
Thu Sep 17 17:30:23 EDT 2020


---
 src/eap_peer/eap_peap.c                | 13 ++++--
 src/eap_peer/eap_tls.c                 | 11 ++---
 src/eap_peer/eap_tls_common.c          |  4 +-
 src/eap_peer/eap_ttls.c                | 24 +++++++++-
 src/eap_server/eap_server_peap.c       | 65 ++++++++++++++++++++++----
 src/eap_server/eap_server_tls.c        | 33 -------------
 src/eap_server/eap_server_tls_common.c | 51 +++++++++++++++++++-
 src/eap_server/eap_server_ttls.c       | 28 +++++++++--
 8 files changed, 167 insertions(+), 62 deletions(-)

diff --git a/src/eap_peer/eap_peap.c b/src/eap_peer/eap_peap.c
index cb34a0fc3..6997f71cd 100644
--- a/src/eap_peer/eap_peap.c
+++ b/src/eap_peer/eap_peap.c
@@ -1101,10 +1101,17 @@ static struct wpabuf * eap_peap_process(struct eap_sm *sm, void *priv,
 		}
 
 		if (tls_connection_established(sm->ssl_ctx, data->ssl.conn)) {
-			char *label;
+			const char *label;
+			const u8 eap_tls13_context[] = { EAP_TYPE_PEAP };
+			const u8 *context = NULL;
+			size_t context_len = 0;
 			wpa_printf(MSG_DEBUG,
 				   "EAP-PEAP: TLS done, proceed to Phase 2");
 			eap_peap_free_key(data);
+			if (data->ssl.tls_v13) {
+				label = "EXPORTER_EAP_TLS_Key_Material";
+				context = eap_tls13_context;
+				context_len = 1;
 			/* draft-josefsson-ppext-eap-tls-eap-05.txt
 			 * specifies that PEAPv1 would use "client PEAP
 			 * encryption" as the label. However, most existing
@@ -1112,7 +1119,7 @@ static struct wpabuf * eap_peap_process(struct eap_sm *sm, void *priv,
 			 * label, "client EAP encryption", instead. Use the old
 			 * label by default, but allow it to be configured with
 			 * phase1 parameter peaplabel=1. */
-			if (data->force_new_label)
+			} else if (data->force_new_label)
 				label = "client PEAP encryption";
 			else
 				label = "client EAP encryption";
@@ -1120,7 +1127,7 @@ static struct wpabuf * eap_peap_process(struct eap_sm *sm, void *priv,
 				   "key derivation", label);
 			data->key_data =
 				eap_peer_tls_derive_key(sm, &data->ssl, label,
-							NULL, 0,
+							context, context_len,
 							EAP_TLS_KEY_LEN +
 							EAP_EMSK_LEN);
 			if (data->key_data) {
diff --git a/src/eap_peer/eap_tls.c b/src/eap_peer/eap_tls.c
index ad079a7b7..616cd947a 100644
--- a/src/eap_peer/eap_tls.c
+++ b/src/eap_peer/eap_tls.c
@@ -302,15 +302,10 @@ static struct wpabuf * eap_tls_process(struct eap_sm *sm, void *priv,
 		return NULL;
 	}
 
-	if (res == 2) {
-		/* Application data included in the handshake message (used by
-		 * EAP-TLS 1.3 to indicate conclusion of the exchange). */
-		wpa_hexdump_buf(MSG_DEBUG, "EAP-TLS: Received Application Data",
-				resp);
-		wpa_hexdump_buf(MSG_DEBUG, "EAP-TLS: Remaining tls_out data",
-				data->ssl.tls_out);
+	/* https://tools.ietf.org/html/draft-ietf-emu-eap-tls13#section-2.5 */
+	if (res == 2 && data->ssl.tls_v13 && wpabuf_len(resp) == 1 && *(u8 *)wpabuf_mhead(resp) == 0) {
+		wpa_printf(MSG_DEBUG, "EAP-TLS: ACKing Commitment Message");
 		eap_peer_tls_reset_output(&data->ssl);
-		/* Send an ACK to allow the server to complete exchange */
 		res = 1;
 	}
 
diff --git a/src/eap_peer/eap_tls_common.c b/src/eap_peer/eap_tls_common.c
index ab1067878..c1837db06 100644
--- a/src/eap_peer/eap_tls_common.c
+++ b/src/eap_peer/eap_tls_common.c
@@ -413,9 +413,9 @@ u8 * eap_peer_tls_derive_session_id(struct eap_sm *sm,
 	struct tls_random keys;
 	u8 *out;
 
-	if (eap_type == EAP_TYPE_TLS && data->tls_v13) {
+	if (data->tls_v13) {
 		u8 *id, *method_id;
-		const u8 context[] = { EAP_TYPE_TLS };
+		const u8 context[] = { eap_type };
 
 		/* Session-Id = <EAP-Type> || Method-Id
 		 * Method-Id = TLS-Exporter("EXPORTER_EAP_TLS_Method-Id",
diff --git a/src/eap_peer/eap_ttls.c b/src/eap_peer/eap_ttls.c
index 3bf1e97e6..3e8676374 100644
--- a/src/eap_peer/eap_ttls.c
+++ b/src/eap_peer/eap_ttls.c
@@ -268,10 +268,22 @@ static int eap_ttls_avp_encapsulate(struct wpabuf **resp, u32 avp_code,
 static int eap_ttls_v0_derive_key(struct eap_sm *sm,
 				  struct eap_ttls_data *data)
 {
+	const char *label;
+	const u8 eap_tls13_context[] = { EAP_TYPE_TTLS };
+	const u8 *context = NULL;
+	size_t context_len = 0;
+
+	if (data->ssl.tls_v13) {
+		label = "EXPORTER_EAP_TLS_Key_Material";
+		context = eap_tls13_context;
+		context_len = 1;
+	} else
+		label = "ttls keying material";
+
 	eap_ttls_free_key(data);
 	data->key_data = eap_peer_tls_derive_key(sm, &data->ssl,
-						 "ttls keying material",
-						 NULL, 0,
+						 label,
+						 context, context_len,
 						 EAP_TLS_KEY_LEN +
 						 EAP_EMSK_LEN);
 	if (!data->key_data) {
@@ -1461,6 +1473,14 @@ start:
 		goto start;
 	}
 
+	/* https://tools.ietf.org/html/draft-ietf-emu-eap-tls13#section-2.5 */
+	if (data->ssl.tls_v13 && wpabuf_len(in_decrypted) == 1 && *(u8 *)wpabuf_mhead(in_decrypted) == 0) {
+		wpa_printf(MSG_DEBUG, "EAP-TTLS: ACKing EAP-TLS Commitment Message");
+		eap_peer_tls_reset_output(&data->ssl);
+		wpabuf_free(in_decrypted);
+		return 1;
+	}
+
 continue_req:
 	data->phase2_start = 0;
 
diff --git a/src/eap_server/eap_server_peap.c b/src/eap_server/eap_server_peap.c
index f234f6fa5..6da4d69f6 100644
--- a/src/eap_server/eap_server_peap.c
+++ b/src/eap_server/eap_server_peap.c
@@ -325,13 +325,25 @@ static int eap_peap_derive_cmk(struct eap_sm *sm, struct eap_peap_data *data)
 	u8 *tk;
 	u8 isk[32], imck[60];
 	int res;
+	const char *label;
+	const u8 eap_tls13_context[] = { EAP_TYPE_PEAP };
+	const u8 *context = NULL;
+	size_t context_len = 0;
+
+	if (data->ssl.tls_v13) {
+		label = "EXPORTER_EAP_TLS_Key_Material";
+		context = eap_tls13_context;
+		context_len = 1;
+	} else
+		label = "client EAP encryption";	/* TODO: PEAPv1 - different label in some cases */
 
 	/*
 	 * Tunnel key (TK) is the first 60 octets of the key generated by
 	 * phase 1 of PEAP (based on TLS).
 	 */
-	tk = eap_server_tls_derive_key(sm, &data->ssl, "client EAP encryption",
-				       NULL, 0, EAP_TLS_KEY_LEN);
+	tk = eap_server_tls_derive_key(sm, &data->ssl, label,
+				       context, context_len,
+				       EAP_TLS_KEY_LEN);
 	if (tk == NULL)
 		return -1;
 	wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: TK", tk, 60);
@@ -498,7 +510,24 @@ static struct wpabuf * eap_peap_build_phase2_term(struct eap_sm *sm,
 	encr_req = eap_server_tls_encrypt(sm, &data->ssl, &msgbuf);
 	os_free(hdr);
 
-	return encr_req;
+	if (!(data->ssl.tls_v13 && tls_connection_resumed(sm->cfg->ssl_ctx, data->ssl.conn))) {
+		wpabuf_free(data->ssl.tls_out);
+		data->ssl.tls_out_pos = 0;
+		return encr_req;
+	}
+
+	if (wpabuf_resize(&data->ssl.tls_out, wpabuf_len(encr_req)) < 0) {
+		wpa_printf(MSG_INFO,
+			   "EAP-TLS: Failed to resize output buffer");
+		wpabuf_free(encr_req);
+		return NULL;
+	}
+	wpabuf_put_buf(data->ssl.tls_out, encr_req);
+	wpa_hexdump_buf(MSG_DEBUG,
+			"EAP-TLS: Data appended to the message", encr_req);
+	os_free(encr_req);
+
+	return data->ssl.tls_out;
 }
 
 
@@ -547,8 +576,6 @@ static struct wpabuf * eap_peap_buildReq(struct eap_sm *sm, void *priv, u8 id)
 		data->ssl.tls_out = eap_peap_build_phase2_tlv(sm, data, id);
 		break;
 	case SUCCESS_REQ:
-		wpabuf_free(data->ssl.tls_out);
-		data->ssl.tls_out_pos = 0;
 		data->ssl.tls_out = eap_peap_build_phase2_term(sm, data, id,
 							       1);
 		break;
@@ -1300,6 +1327,10 @@ static u8 * eap_peap_getKey(struct eap_sm *sm, void *priv, size_t *len)
 {
 	struct eap_peap_data *data = priv;
 	u8 *eapKeyData;
+	const char *label;
+	const u8 eap_tls13_context[] = { EAP_TYPE_PEAP };
+	const u8 *context = NULL;
+	size_t context_len = 0;
 
 	if (data->state != SUCCESS)
 		return NULL;
@@ -1332,9 +1363,15 @@ static u8 * eap_peap_getKey(struct eap_sm *sm, void *priv, size_t *len)
 		return eapKeyData;
 	}
 
-	/* TODO: PEAPv1 - different label in some cases */
+	if (data->ssl.tls_v13) {
+		label = "EXPORTER_EAP_TLS_Key_Material";
+		context = eap_tls13_context;
+		context_len = 1;
+	} else
+		label = "client EAP encryption";	/* TODO: PEAPv1 - different label in some cases */
+
 	eapKeyData = eap_server_tls_derive_key(sm, &data->ssl,
-					       "client EAP encryption", NULL, 0,
+					       label, context, context_len,
 					       EAP_TLS_KEY_LEN + EAP_EMSK_LEN);
 	if (eapKeyData) {
 		os_memset(eapKeyData + EAP_TLS_KEY_LEN, 0, EAP_EMSK_LEN);
@@ -1353,6 +1390,10 @@ static u8 * eap_peap_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
 {
 	struct eap_peap_data *data = priv;
 	u8 *eapKeyData, *emsk;
+	const char *label;
+	const u8 eap_tls13_context[] = { EAP_TYPE_PEAP };
+	const u8 *context = NULL;
+	size_t context_len = 0;
 
 	if (data->state != SUCCESS)
 		return NULL;
@@ -1362,9 +1403,15 @@ static u8 * eap_peap_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
 		return NULL;
 	}
 
-	/* TODO: PEAPv1 - different label in some cases */
+	if (data->ssl.tls_v13) {
+		label = "EXPORTER_EAP_TLS_Key_Material";
+		context = eap_tls13_context;
+		context_len = 1;
+	} else
+		label = "client EAP encryption";	/* TODO: PEAPv1 - different label in some cases */
+
 	eapKeyData = eap_server_tls_derive_key(sm, &data->ssl,
-					       "client EAP encryption", NULL, 0,
+					       label, context, context_len,
 					       EAP_TLS_KEY_LEN + EAP_EMSK_LEN);
 	if (eapKeyData) {
 		emsk = os_memdup(eapKeyData + EAP_TLS_KEY_LEN, EAP_EMSK_LEN);
diff --git a/src/eap_server/eap_server_tls.c b/src/eap_server/eap_server_tls.c
index 769fd1fe0..00a496f2c 100644
--- a/src/eap_server/eap_server_tls.c
+++ b/src/eap_server/eap_server_tls.c
@@ -266,39 +266,6 @@ static void eap_tls_process_msg(struct eap_sm *sm, void *priv,
 		eap_tls_state(data, FAILURE);
 		return;
 	}
-
-	if (data->ssl.tls_v13 &&
-	    tls_connection_established(sm->cfg->ssl_ctx, data->ssl.conn)) {
-		struct wpabuf *plain, *encr;
-
-		wpa_printf(MSG_DEBUG,
-			   "EAP-TLS: Send empty application data to indicate end of exchange");
-		/* FIX: This should be an empty application data based on
-		 * draft-ietf-emu-eap-tls13-05, but OpenSSL does not allow zero
-		 * length payload (SSL_write() documentation explicitly
-		 * describes this as not allowed), so work around that for now
-		 * by sending out a payload of one octet. Hopefully the draft
-		 * specification will change to allow this so that no crypto
-		 * library changes are needed. */
-		plain = wpabuf_alloc(1);
-		if (!plain)
-			return;
-		wpabuf_put_u8(plain, 0);
-		encr = eap_server_tls_encrypt(sm, &data->ssl, plain);
-		wpabuf_free(plain);
-		if (!encr)
-			return;
-		if (wpabuf_resize(&data->ssl.tls_out, wpabuf_len(encr)) < 0) {
-			wpa_printf(MSG_INFO,
-				   "EAP-TLS: Failed to resize output buffer");
-			wpabuf_free(encr);
-			return;
-		}
-		wpabuf_put_buf(data->ssl.tls_out, encr);
-		wpa_hexdump_buf(MSG_DEBUG,
-				"EAP-TLS: Data appended to the message", encr);
-		wpabuf_free(encr);
-	}
 }
 
 
diff --git a/src/eap_server/eap_server_tls_common.c b/src/eap_server/eap_server_tls_common.c
index b38f1e0ba..c06c85c87 100644
--- a/src/eap_server/eap_server_tls_common.c
+++ b/src/eap_server/eap_server_tls_common.c
@@ -146,10 +146,10 @@ u8 * eap_server_tls_derive_session_id(struct eap_sm *sm,
 {
 	struct tls_random keys;
 	u8 *out;
-	const u8 context[] = { EAP_TYPE_TLS };
 
-	if (eap_type == EAP_TYPE_TLS && data->tls_v13) {
+	if (data->tls_v13) {
 		u8 *id, *method_id;
+		const u8 context[] = { eap_type };
 
 		/* Session-Id = <EAP-Type> || Method-Id
 		 * Method-Id = TLS-Exporter("EXPORTER_EAP_TLS_Method-Id",
@@ -366,6 +366,53 @@ int eap_server_tls_phase1(struct eap_sm *sm, struct eap_ssl_data *data)
 		sm->serial_num = tls_connection_peer_serial_num(
 			sm->cfg->ssl_ctx, data->conn);
 
+        /**
+	 * https://tools.ietf.org/html/draft-ietf-emu-eap-tls13#section-2.5
+         *
+         * We need to signal the other end that TLS negotiation
+         * is done.  We can't send a zero-length application data
+         * message, so we send application data which is one byte
+         * of zero.
+         *
+         * Note this is only done for when there is no application
+         * data to be sent. So this is done always for EAP-TLS but
+         * notibly not for PEAP even on resumption.
+         */
+	if (tls_connection_established(sm->cfg->ssl_ctx, data->conn) && data->tls_v13) {
+		switch (sm->currentMethod) {
+		case EAP_TYPE_PEAP:
+			break;
+		default:
+			if (!tls_connection_resumed(sm->cfg->ssl_ctx, data->conn)) break;
+			/* fallthrough */
+		case EAP_TYPE_TLS:
+		{
+			struct wpabuf *plain, *encr;
+
+			wpa_printf(MSG_DEBUG, "EAP-TLS: Send Commitment Message");
+
+			plain = wpabuf_alloc(1);
+			if (!plain)
+				return -1;
+			wpabuf_put_u8(plain, 0);
+			encr = eap_server_tls_encrypt(sm, data, plain);
+			wpabuf_free(plain);
+			if (!encr)
+				return -1;
+			if (wpabuf_resize(&data->tls_out, wpabuf_len(encr)) < 0) {
+				wpa_printf(MSG_INFO,
+					   "EAP-TLS: Failed to resize output buffer");
+				wpabuf_free(encr);
+				return -1;
+			}
+			wpabuf_put_buf(data->tls_out, encr);
+			wpa_hexdump_buf(MSG_DEBUG,
+					"EAP-TLS: Data appended to the message", encr);
+			wpabuf_free(encr);
+		}
+		}
+	}
+
 	return 0;
 }
 
diff --git a/src/eap_server/eap_server_ttls.c b/src/eap_server/eap_server_ttls.c
index 2f0c041d5..88493c58f 100644
--- a/src/eap_server/eap_server_ttls.c
+++ b/src/eap_server/eap_server_ttls.c
@@ -1271,13 +1271,24 @@ static u8 * eap_ttls_getKey(struct eap_sm *sm, void *priv, size_t *len)
 {
 	struct eap_ttls_data *data = priv;
 	u8 *eapKeyData;
+	const char *label;
+	const u8 eap_tls13_context[] = { EAP_TYPE_TTLS };
+	const u8 *context = NULL;
+	size_t context_len = 0;
 
 	if (data->state != SUCCESS)
 		return NULL;
 
+	if (data->ssl.tls_v13) {
+		label = "EXPORTER_EAP_TLS_Key_Material";
+		context = eap_tls13_context;
+		context_len = 1;
+	} else
+		label = "ttls keying material";
+
 	eapKeyData = eap_server_tls_derive_key(sm, &data->ssl,
-					       "ttls keying material", NULL, 0,
-					       EAP_TLS_KEY_LEN);
+					       label, context, context_len,
+					       EAP_TLS_KEY_LEN + EAP_EMSK_LEN);
 	if (eapKeyData) {
 		*len = EAP_TLS_KEY_LEN;
 		wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS: Derived key",
@@ -1313,12 +1324,23 @@ static u8 * eap_ttls_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
 {
 	struct eap_ttls_data *data = priv;
 	u8 *eapKeyData, *emsk;
+	const char *label;
+	const u8 eap_tls13_context[] = { EAP_TYPE_TTLS };
+	const u8 *context = NULL;
+	size_t context_len = 0;
 
 	if (data->state != SUCCESS)
 		return NULL;
 
+	if (data->ssl.tls_v13) {
+		label = "EXPORTER_EAP_TLS_Key_Material";
+		context = eap_tls13_context;
+		context_len = 1;
+	} else
+		label = "ttls keying material";
+
 	eapKeyData = eap_server_tls_derive_key(sm, &data->ssl,
-					       "ttls keying material", NULL, 0,
+					       label, context, context_len,
 					       EAP_TLS_KEY_LEN + EAP_EMSK_LEN);
 	if (eapKeyData) {
 		emsk = os_malloc(EAP_EMSK_LEN);
-- 
2.20.1




More information about the Hostap mailing list