Parcourir la source

EAP-FAST: Add peer identity into EAP-FAST PAC-Opaque

This allows Phase 2 Identity Request to be skipped if the identity is
already known from PAC-Opaque received in TLS handshake in order to save
one roundtrip from normal authentication.
Jouni Malinen il y a 17 ans
Parent
commit
829f14be17
2 fichiers modifiés avec 111 ajouts et 22 suppressions
  1. 4 0
      hostapd/ChangeLog
  2. 107 22
      src/eap_server/eap_fast.c

+ 4 - 0
hostapd/ChangeLog

@@ -1,5 +1,9 @@
 ChangeLog for hostapd
 
+????-??-?? - v0.6.4
+	* added peer identity into EAP-FAST PAC-Opaque and skip Phase 2
+	  Identity Request if identity is already known
+
 2008-02-22 - v0.6.3
 	* fixed Reassociation Response callback processing when using internal
 	  MLME (driver_{hostap,nl80211,test}.c)

+ 107 - 22
src/eap_server/eap_fast.c

@@ -31,6 +31,7 @@ static void eap_fast_reset(struct eap_sm *sm, void *priv);
 #define PAC_OPAQUE_TYPE_PAD 0
 #define PAC_OPAQUE_TYPE_KEY 1
 #define PAC_OPAQUE_TYPE_LIFETIME 2
+#define PAC_OPAQUE_TYPE_IDENTITY 3
 
 /* PAC-Key lifetime in seconds (hard limit) */
 #define PAC_KEY_LIFETIME (7 * 24 * 60 * 60)
@@ -71,6 +72,8 @@ struct eap_fast_data {
 	int anon_provisioning;
 	int send_new_pac; /* server triggered re-keying of Tunnel PAC */
 	struct wpabuf *pending_phase2_resp;
+	u8 *identity; /* from PAC-Opaque */
+	size_t identity_len;
 };
 
 
@@ -133,6 +136,8 @@ static int eap_fast_session_ticket_cb(void *ctx, const u8 *ticket, size_t len,
 	u8 *buf, *pos, *end, *pac_key = NULL;
 	os_time_t lifetime = 0;
 	struct os_time now;
+	u8 *identity = NULL;
+	size_t identity_len = 0;
 
 	wpa_printf(MSG_DEBUG, "EAP-FAST: SessionTicket callback");
 	wpa_hexdump(MSG_DEBUG, "EAP-FAST: SessionTicket (PAC-Opaque)",
@@ -217,6 +222,10 @@ static int eap_fast_session_ticket_cb(void *ctx, const u8 *ticket, size_t len,
 			}
 			lifetime = WPA_GET_BE32(pos + 2);
 			break;
+		case PAC_OPAQUE_TYPE_IDENTITY:
+			identity = pos + 2;
+			identity_len = pos[1];
+			break;
 		}
 
 		pos += 2 + pos[1];
@@ -229,6 +238,17 @@ static int eap_fast_session_ticket_cb(void *ctx, const u8 *ticket, size_t len,
 		return -1;
 	}
 
+	if (identity) {
+		wpa_hexdump_ascii(MSG_DEBUG, "EAP-FAST: Identity from "
+				  "PAC-Opaque", identity, identity_len);
+		os_free(data->identity);
+		data->identity = os_malloc(identity_len);
+		if (data->identity) {
+			os_memcpy(data->identity, identity, identity_len);
+			data->identity_len = identity_len;
+		}
+	}
+
 	if (os_get_time(&now) < 0 || lifetime <= 0 || now.sec > lifetime) {
 		wpa_printf(MSG_DEBUG, "EAP-FAST: PAC-Key not valid anymore "
 			   "(lifetime=%ld now=%ld)", lifetime, now.sec);
@@ -517,6 +537,7 @@ static void eap_fast_reset(struct eap_sm *sm, void *priv)
 	os_free(data->srv_id);
 	os_free(data->key_block_p);
 	wpabuf_free(data->pending_phase2_resp);
+	os_free(data->identity);
 	os_free(data);
 }
 
@@ -756,45 +777,80 @@ static struct wpabuf * eap_fast_build_crypto_binding(
 static struct wpabuf * eap_fast_build_pac(struct eap_sm *sm,
 					  struct eap_fast_data *data)
 {
-	u8 pac_key[2 + EAP_FAST_PAC_KEY_LEN + 6];
-	u8 pac_opaque[8 + EAP_FAST_PAC_KEY_LEN + 8];
+	u8 pac_key[EAP_FAST_PAC_KEY_LEN];
+	u8 *pac_buf, *pac_opaque;
 	struct wpabuf *buf;
 	u8 *pos;
-	size_t buf_len, srv_id_len;
+	size_t buf_len, srv_id_len, pac_len;
 	struct eap_tlv_hdr *pac_tlv;
 	struct pac_tlv_hdr *hdr, *pac_info;
 	struct eap_tlv_result_tlv *result;
 	struct os_time now;
 
-	srv_id_len = os_strlen(data->srv_id);
-
-	pac_key[0] = PAC_OPAQUE_TYPE_KEY;
-	pac_key[1] = EAP_FAST_PAC_KEY_LEN;
-	if (os_get_random(pac_key + 2, EAP_FAST_PAC_KEY_LEN) < 0)
-		return NULL;
-	if (os_get_time(&now) < 0)
+	if (os_get_random(pac_key, EAP_FAST_PAC_KEY_LEN) < 0 ||
+	    os_get_time(&now) < 0)
 		return NULL;
 	wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: Generated PAC-Key",
-			pac_key + 2, EAP_FAST_PAC_KEY_LEN);
-	pos = pac_key + 2 + EAP_FAST_PAC_KEY_LEN;
+			pac_key, EAP_FAST_PAC_KEY_LEN);
+
+	pac_len = (2 + EAP_FAST_PAC_KEY_LEN) + (2 + 4) +
+		(2 + sm->identity_len) + 8;
+	pac_buf = os_malloc(pac_len);
+	if (pac_buf == NULL)
+		return NULL;
+
+	srv_id_len = os_strlen(data->srv_id);
+
+	pos = pac_buf;
+	*pos++ = PAC_OPAQUE_TYPE_KEY;
+	*pos++ = EAP_FAST_PAC_KEY_LEN;
+	os_memcpy(pos, pac_key, EAP_FAST_PAC_KEY_LEN);
+	pos += EAP_FAST_PAC_KEY_LEN;
+
 	*pos++ = PAC_OPAQUE_TYPE_LIFETIME;
 	*pos++ = 4;
 	WPA_PUT_BE32(pos, now.sec + PAC_KEY_LIFETIME);
+	pos += 4;
+
+	if (sm->identity) {
+		*pos++ = PAC_OPAQUE_TYPE_IDENTITY;
+		*pos++ = sm->identity_len;
+		os_memcpy(pos, sm->identity, sm->identity_len);
+		pos += sm->identity_len;
+	}
 
-	if (aes_wrap(data->pac_opaque_encr, sizeof(pac_key) / 8, pac_key,
-		     pac_opaque) < 0)
+	pac_len = pos - pac_buf;
+	if (pac_len % 8) {
+		*pos++ = PAC_OPAQUE_TYPE_PAD;
+		pac_len++;
+	}
+
+	pac_opaque = os_malloc(pac_len + 8);
+	if (pac_opaque == NULL) {
+		os_free(pac_buf);
+		return NULL;
+	}
+	if (aes_wrap(data->pac_opaque_encr, pac_len / 8, pac_buf,
+		     pac_opaque) < 0) {
+		os_free(pac_buf);
+		os_free(pac_opaque);
 		return NULL;
+	}
+	os_free(pac_buf);
 
+	pac_len += 8;
 	wpa_hexdump(MSG_DEBUG, "EAP-FAST: PAC-Opaque",
-		    pac_opaque, sizeof(pac_opaque));
+		    pac_opaque, pac_len);
 
 	buf_len = sizeof(*pac_tlv) +
 		sizeof(*hdr) + EAP_FAST_PAC_KEY_LEN +
-		sizeof(*hdr) + sizeof(pac_opaque) +
+		sizeof(*hdr) + pac_len +
 		2 * srv_id_len + 100 + sizeof(*result);
 	buf = wpabuf_alloc(buf_len);
-	if (buf == NULL)
+	if (buf == NULL) {
+		os_free(pac_opaque);
 		return NULL;
+	}
 
 	/* PAC TLV */
 	wpa_printf(MSG_DEBUG, "EAP-FAST: Add PAC TLV");
@@ -806,13 +862,14 @@ static struct wpabuf * eap_fast_build_pac(struct eap_sm *sm,
 	hdr = wpabuf_put(buf, sizeof(*hdr));
 	hdr->type = host_to_be16(PAC_TYPE_PAC_KEY);
 	hdr->len = host_to_be16(EAP_FAST_PAC_KEY_LEN);
-	wpabuf_put_data(buf, pac_key + 2, EAP_FAST_PAC_KEY_LEN);
+	wpabuf_put_data(buf, pac_key, EAP_FAST_PAC_KEY_LEN);
 
 	/* PAC-Opaque */
 	hdr = wpabuf_put(buf, sizeof(*hdr));
 	hdr->type = host_to_be16(PAC_TYPE_PAC_OPAQUE);
-	hdr->len = host_to_be16(sizeof(pac_opaque));
-	wpabuf_put_data(buf, pac_opaque, sizeof(pac_opaque));
+	hdr->len = host_to_be16(pac_len);
+	wpabuf_put_data(buf, pac_opaque, pac_len);
+	os_free(pac_opaque);
 
 	/* PAC-Info */
 	pac_info = wpabuf_put(buf, sizeof(*pac_info));
@@ -1524,6 +1581,7 @@ static void eap_fast_process(struct eap_sm *sm, void *priv,
 	size_t left;
 	unsigned int tls_msg_len;
 	int peer_version;
+	u8 next_type;
 
 	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_FAST, respData,
 			       &left);
@@ -1594,8 +1652,35 @@ static void eap_fast_process(struct eap_sm *sm, void *priv,
 
 		/* fall through to PHASE2_START */
 	case PHASE2_START:
-		eap_fast_state(data, PHASE2_ID);
-		eap_fast_phase2_init(sm, data, EAP_TYPE_IDENTITY);
+		if (data->identity) {
+			os_free(sm->identity);
+			sm->identity = data->identity;
+			data->identity = NULL;
+			sm->identity_len = data->identity_len;
+			data->identity_len = 0;
+			if (eap_user_get(sm, sm->identity, sm->identity_len, 1)
+			    != 0) {
+				wpa_hexdump_ascii(MSG_DEBUG, "EAP-FAST: "
+						  "Phase2 Identity not found "
+						  "in the user database",
+						  sm->identity,
+						  sm->identity_len);
+				next_type = eap_fast_req_failure(sm, data);
+			} else {
+				wpa_printf(MSG_DEBUG, "EAP-FAST: Identity "
+					   "already known - skip Phase 2 "
+					   "Identity Request");
+				next_type = sm->user->methods[0].method;
+				sm->user_eap_method_index = 1;
+			}
+
+			eap_fast_state(data, PHASE2_METHOD);
+		} else {
+			eap_fast_state(data, PHASE2_ID);
+			next_type = EAP_TYPE_IDENTITY;
+		}
+
+		eap_fast_phase2_init(sm, data, next_type);
 		break;
 	case PHASE2_ID:
 	case PHASE2_METHOD: