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.
This commit is contained in:
Jouni Malinen 2008-02-27 17:55:40 -08:00
parent 67b941993a
commit 829f14be17
2 changed files with 111 additions and 22 deletions

View file

@ -1,5 +1,9 @@
ChangeLog for hostapd 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 2008-02-22 - v0.6.3
* fixed Reassociation Response callback processing when using internal * fixed Reassociation Response callback processing when using internal
MLME (driver_{hostap,nl80211,test}.c) MLME (driver_{hostap,nl80211,test}.c)

View file

@ -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_PAD 0
#define PAC_OPAQUE_TYPE_KEY 1 #define PAC_OPAQUE_TYPE_KEY 1
#define PAC_OPAQUE_TYPE_LIFETIME 2 #define PAC_OPAQUE_TYPE_LIFETIME 2
#define PAC_OPAQUE_TYPE_IDENTITY 3
/* PAC-Key lifetime in seconds (hard limit) */ /* PAC-Key lifetime in seconds (hard limit) */
#define PAC_KEY_LIFETIME (7 * 24 * 60 * 60) #define PAC_KEY_LIFETIME (7 * 24 * 60 * 60)
@ -71,6 +72,8 @@ struct eap_fast_data {
int anon_provisioning; int anon_provisioning;
int send_new_pac; /* server triggered re-keying of Tunnel PAC */ int send_new_pac; /* server triggered re-keying of Tunnel PAC */
struct wpabuf *pending_phase2_resp; 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; u8 *buf, *pos, *end, *pac_key = NULL;
os_time_t lifetime = 0; os_time_t lifetime = 0;
struct os_time now; struct os_time now;
u8 *identity = NULL;
size_t identity_len = 0;
wpa_printf(MSG_DEBUG, "EAP-FAST: SessionTicket callback"); wpa_printf(MSG_DEBUG, "EAP-FAST: SessionTicket callback");
wpa_hexdump(MSG_DEBUG, "EAP-FAST: SessionTicket (PAC-Opaque)", 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); lifetime = WPA_GET_BE32(pos + 2);
break; break;
case PAC_OPAQUE_TYPE_IDENTITY:
identity = pos + 2;
identity_len = pos[1];
break;
} }
pos += 2 + pos[1]; 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; 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) { if (os_get_time(&now) < 0 || lifetime <= 0 || now.sec > lifetime) {
wpa_printf(MSG_DEBUG, "EAP-FAST: PAC-Key not valid anymore " wpa_printf(MSG_DEBUG, "EAP-FAST: PAC-Key not valid anymore "
"(lifetime=%ld now=%ld)", lifetime, now.sec); "(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->srv_id);
os_free(data->key_block_p); os_free(data->key_block_p);
wpabuf_free(data->pending_phase2_resp); wpabuf_free(data->pending_phase2_resp);
os_free(data->identity);
os_free(data); 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, static struct wpabuf * eap_fast_build_pac(struct eap_sm *sm,
struct eap_fast_data *data) struct eap_fast_data *data)
{ {
u8 pac_key[2 + EAP_FAST_PAC_KEY_LEN + 6]; u8 pac_key[EAP_FAST_PAC_KEY_LEN];
u8 pac_opaque[8 + EAP_FAST_PAC_KEY_LEN + 8]; u8 *pac_buf, *pac_opaque;
struct wpabuf *buf; struct wpabuf *buf;
u8 *pos; 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 eap_tlv_hdr *pac_tlv;
struct pac_tlv_hdr *hdr, *pac_info; struct pac_tlv_hdr *hdr, *pac_info;
struct eap_tlv_result_tlv *result; struct eap_tlv_result_tlv *result;
struct os_time now; struct os_time now;
srv_id_len = os_strlen(data->srv_id); if (os_get_random(pac_key, EAP_FAST_PAC_KEY_LEN) < 0 ||
os_get_time(&now) < 0)
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)
return NULL; return NULL;
wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: Generated PAC-Key", wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: Generated PAC-Key",
pac_key + 2, EAP_FAST_PAC_KEY_LEN); pac_key, EAP_FAST_PAC_KEY_LEN);
pos = pac_key + 2 + 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++ = PAC_OPAQUE_TYPE_LIFETIME;
*pos++ = 4; *pos++ = 4;
WPA_PUT_BE32(pos, now.sec + PAC_KEY_LIFETIME); WPA_PUT_BE32(pos, now.sec + PAC_KEY_LIFETIME);
pos += 4;
if (aes_wrap(data->pac_opaque_encr, sizeof(pac_key) / 8, pac_key, if (sm->identity) {
pac_opaque) < 0) *pos++ = PAC_OPAQUE_TYPE_IDENTITY;
*pos++ = sm->identity_len;
os_memcpy(pos, sm->identity, sm->identity_len);
pos += sm->identity_len;
}
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; 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", wpa_hexdump(MSG_DEBUG, "EAP-FAST: PAC-Opaque",
pac_opaque, sizeof(pac_opaque)); pac_opaque, pac_len);
buf_len = sizeof(*pac_tlv) + buf_len = sizeof(*pac_tlv) +
sizeof(*hdr) + EAP_FAST_PAC_KEY_LEN + sizeof(*hdr) + EAP_FAST_PAC_KEY_LEN +
sizeof(*hdr) + sizeof(pac_opaque) + sizeof(*hdr) + pac_len +
2 * srv_id_len + 100 + sizeof(*result); 2 * srv_id_len + 100 + sizeof(*result);
buf = wpabuf_alloc(buf_len); buf = wpabuf_alloc(buf_len);
if (buf == NULL) if (buf == NULL) {
os_free(pac_opaque);
return NULL; return NULL;
}
/* PAC TLV */ /* PAC TLV */
wpa_printf(MSG_DEBUG, "EAP-FAST: Add 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 = wpabuf_put(buf, sizeof(*hdr));
hdr->type = host_to_be16(PAC_TYPE_PAC_KEY); hdr->type = host_to_be16(PAC_TYPE_PAC_KEY);
hdr->len = host_to_be16(EAP_FAST_PAC_KEY_LEN); 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 */ /* PAC-Opaque */
hdr = wpabuf_put(buf, sizeof(*hdr)); hdr = wpabuf_put(buf, sizeof(*hdr));
hdr->type = host_to_be16(PAC_TYPE_PAC_OPAQUE); hdr->type = host_to_be16(PAC_TYPE_PAC_OPAQUE);
hdr->len = host_to_be16(sizeof(pac_opaque)); hdr->len = host_to_be16(pac_len);
wpabuf_put_data(buf, pac_opaque, sizeof(pac_opaque)); wpabuf_put_data(buf, pac_opaque, pac_len);
os_free(pac_opaque);
/* PAC-Info */ /* PAC-Info */
pac_info = wpabuf_put(buf, sizeof(*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; size_t left;
unsigned int tls_msg_len; unsigned int tls_msg_len;
int peer_version; int peer_version;
u8 next_type;
pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_FAST, respData, pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_FAST, respData,
&left); &left);
@ -1594,8 +1652,35 @@ static void eap_fast_process(struct eap_sm *sm, void *priv,
/* fall through to PHASE2_START */ /* fall through to PHASE2_START */
case PHASE2_START: case PHASE2_START:
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); eap_fast_state(data, PHASE2_ID);
eap_fast_phase2_init(sm, data, EAP_TYPE_IDENTITY); next_type = EAP_TYPE_IDENTITY;
}
eap_fast_phase2_init(sm, data, next_type);
break; break;
case PHASE2_ID: case PHASE2_ID:
case PHASE2_METHOD: case PHASE2_METHOD: