X-Git-Url: http://vcs.maemo.org/git/?a=blobdiff_plain;f=src%2Feap_server%2Feap_fast.c;h=356390848bb8550732bb7d94d35ae2386835e457;hb=73267b9ca433288c207c4e06a938eaa326c8672a;hp=c811fedc71286c61b3a9ff7574ade06939c1a0ac;hpb=a11c90a64a45953c1edb19e0af63fe5afca94525;p=wpasupplicant diff --git a/src/eap_server/eap_fast.c b/src/eap_server/eap_fast.c index c811fed..3563908 100644 --- a/src/eap_server/eap_fast.c +++ b/src/eap_server/eap_fast.c @@ -56,7 +56,9 @@ struct eap_fast_data { int simck_idx; u8 pac_opaque_encr[16]; - char *srv_id; + u8 *srv_id; + size_t srv_id_len; + char *srv_id_info; int anon_provisioning; int send_new_pac; /* server triggered re-keying of Tunnel PAC */ @@ -239,12 +241,20 @@ static int eap_fast_session_ticket_cb(void *ctx, const u8 *ticket, size_t 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); - os_free(buf); - return 0; - } - - if (lifetime - now.sec < data->pac_key_refresh_time) + data->send_new_pac = 2; + /* + * Allow PAC to be used to allow a PAC update with some level + * of server authentication (i.e., do not fall back to full TLS + * handshake since we cannot be sure that the peer would be + * able to validate server certificate now). However, reject + * the authentication since the PAC was not valid anymore. Peer + * can connect again with the newly provisioned PAC after this. + */ + } else if (lifetime - now.sec < data->pac_key_refresh_time) { + wpa_printf(MSG_DEBUG, "EAP-FAST: PAC-Key soft timeout; send " + "an update if authentication succeeds"); data->send_new_pac = 1; + } eap_fast_derive_master_secret(pac_key, server_random, client_random, master_secret); @@ -344,7 +354,18 @@ static int eap_fast_get_phase2_key(struct eap_sm *sm, if (key_len > isk_len) key_len = isk_len; - os_memcpy(isk, key, key_len); + if (key_len == 32 && + data->phase2_method->vendor == EAP_VENDOR_IETF && + data->phase2_method->method == EAP_TYPE_MSCHAPV2) { + /* + * EAP-FAST uses reverse order for MS-MPPE keys when deriving + * MSK from EAP-MSCHAPv2. Swap the keys here to get the correct + * ISK for EAP-FAST cryptobinding. + */ + os_memcpy(isk, key + 16, 16); + os_memcpy(isk + 16, key, 16); + } else + os_memcpy(isk, key, key_len); os_free(key); return 0; @@ -445,11 +466,24 @@ static void * eap_fast_init(struct eap_sm *sm) eap_fast_reset(sm, data); return NULL; } - data->srv_id = os_strdup(sm->eap_fast_a_id); + data->srv_id = os_malloc(sm->eap_fast_a_id_len); if (data->srv_id == NULL) { eap_fast_reset(sm, data); return NULL; } + os_memcpy(data->srv_id, sm->eap_fast_a_id, sm->eap_fast_a_id_len); + data->srv_id_len = sm->eap_fast_a_id_len; + + if (sm->eap_fast_a_id_info == NULL) { + wpa_printf(MSG_INFO, "EAP-FAST: No A-ID-Info configured"); + eap_fast_reset(sm, data); + return NULL; + } + data->srv_id_info = os_strdup(sm->eap_fast_a_id_info); + if (data->srv_id_info == NULL) { + eap_fast_reset(sm, data); + return NULL; + } /* PAC-Key lifetime in seconds (hard limit) */ data->pac_key_lifetime = sm->pac_key_lifetime; @@ -474,6 +508,7 @@ static void eap_fast_reset(struct eap_sm *sm, void *priv) data->phase2_method->reset(sm, data->phase2_priv); eap_server_tls_ssl_deinit(sm, &data->ssl); os_free(data->srv_id); + os_free(data->srv_id_info); os_free(data->key_block_p); wpabuf_free(data->pending_phase2_resp); os_free(data->identity); @@ -485,10 +520,9 @@ static struct wpabuf * eap_fast_build_start(struct eap_sm *sm, struct eap_fast_data *data, u8 id) { struct wpabuf *req; - size_t srv_id_len = os_strlen(data->srv_id); req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_FAST, - 1 + sizeof(struct pac_tlv_hdr) + srv_id_len, + 1 + sizeof(struct pac_tlv_hdr) + data->srv_id_len, EAP_CODE_REQUEST, id); if (req == NULL) { wpa_printf(MSG_ERROR, "EAP-FAST: Failed to allocate memory for" @@ -500,7 +534,7 @@ static struct wpabuf * eap_fast_build_start(struct eap_sm *sm, wpabuf_put_u8(req, EAP_TLS_FLAGS_START | data->fast_version); /* RFC 4851, 4.1.1. Authority ID Data */ - eap_fast_put_tlv(req, PAC_TYPE_A_ID, data->srv_id, srv_id_len); + eap_fast_put_tlv(req, PAC_TYPE_A_ID, data->srv_id, data->srv_id_len); eap_fast_state(data, PHASE1); @@ -648,7 +682,7 @@ static struct wpabuf * eap_fast_build_pac(struct eap_sm *sm, u8 *pac_buf, *pac_opaque; struct wpabuf *buf; u8 *pos; - size_t buf_len, srv_id_len, pac_len; + size_t buf_len, srv_id_info_len, pac_len; struct eap_tlv_hdr *pac_tlv; struct pac_tlv_hdr *pac_info; struct eap_tlv_result_tlv *result; @@ -666,7 +700,7 @@ static struct wpabuf * eap_fast_build_pac(struct eap_sm *sm, if (pac_buf == NULL) return NULL; - srv_id_len = os_strlen(data->srv_id); + srv_id_info_len = os_strlen(data->srv_id_info); pos = pac_buf; *pos++ = PAC_OPAQUE_TYPE_KEY; @@ -712,7 +746,7 @@ static struct wpabuf * eap_fast_build_pac(struct eap_sm *sm, buf_len = sizeof(*pac_tlv) + sizeof(struct pac_tlv_hdr) + EAP_FAST_PAC_KEY_LEN + sizeof(struct pac_tlv_hdr) + pac_len + - 2 * srv_id_len + 100 + sizeof(*result); + data->srv_id_len + srv_id_info_len + 100 + sizeof(*result); buf = wpabuf_alloc(buf_len); if (buf == NULL) { os_free(pac_opaque); @@ -749,12 +783,13 @@ static struct wpabuf * eap_fast_build_pac(struct eap_sm *sm, wpabuf_put_be32(buf, now.sec + data->pac_key_lifetime); /* A-ID (inside PAC-Info) */ - eap_fast_put_tlv(buf, PAC_TYPE_A_ID, data->srv_id, srv_id_len); + eap_fast_put_tlv(buf, PAC_TYPE_A_ID, data->srv_id, data->srv_id_len); /* Note: headers may be misaligned after A-ID */ /* A-ID-Info (inside PAC-Info) */ - eap_fast_put_tlv(buf, PAC_TYPE_A_ID_INFO, data->srv_id, srv_id_len); + eap_fast_put_tlv(buf, PAC_TYPE_A_ID_INFO, data->srv_id_info, + srv_id_info_len); /* PAC-Type (inside PAC-Info) */ eap_fast_put_tlv_hdr(buf, PAC_TYPE_PAC_TYPE, 2); @@ -907,7 +942,7 @@ static void eap_fast_process_phase2_response(struct eap_sm *sm, left = in_len - sizeof(*hdr); wpa_hexdump(MSG_DEBUG, "EAP-FAST: Phase2 type Nak'ed; " "allowed types", pos + 1, left - 1); -#ifdef EAP_TNC +#ifdef EAP_SERVER_TNC if (m && m->vendor == EAP_VENDOR_IETF && m->method == EAP_TYPE_TNC) { wpa_printf(MSG_DEBUG, "EAP-FAST: Peer Nak'ed required " @@ -916,7 +951,7 @@ static void eap_fast_process_phase2_response(struct eap_sm *sm, eap_fast_phase2_init(sm, data, next_type); return; } -#endif /* EAP_TNC */ +#endif /* EAP_SERVER_TNC */ eap_sm_process_nak(sm, pos + 1, left - 1); if (sm->user && sm->user_eap_method_index < EAP_MAX_METHODS && sm->user->methods[sm->user_eap_method_index].method != @@ -984,13 +1019,13 @@ static void eap_fast_process_phase2_response(struct eap_sm *sm, eap_fast_state(data, CRYPTO_BINDING); data->eap_seq++; next_type = EAP_TYPE_NONE; -#ifdef EAP_TNC +#ifdef EAP_SERVER_TNC if (sm->tnc && !data->tnc_started) { wpa_printf(MSG_DEBUG, "EAP-FAST: Initialize TNC"); next_type = EAP_TYPE_TNC; data->tnc_started = 1; } -#endif /* EAP_TNC */ +#endif /* EAP_SERVER_TNC */ break; case FAILURE: break; @@ -1014,20 +1049,21 @@ static void eap_fast_process_phase2_eap(struct eap_sm *sm, hdr = (struct eap_hdr *) in_data; if (in_len < (int) sizeof(*hdr)) { wpa_printf(MSG_INFO, "EAP-FAST: Too short Phase 2 " - "EAP frame (len=%d)", in_len); + "EAP frame (len=%lu)", (unsigned long) in_len); eap_fast_req_failure(sm, data); return; } len = be_to_host16(hdr->length); if (len > in_len) { wpa_printf(MSG_INFO, "EAP-FAST: Length mismatch in " - "Phase 2 EAP frame (len=%d hdr->length=%d)", - in_len, len); + "Phase 2 EAP frame (len=%lu hdr->length=%lu)", + (unsigned long) in_len, (unsigned long) len); eap_fast_req_failure(sm, data); return; } wpa_printf(MSG_DEBUG, "EAP-FAST: Received Phase 2: code=%d " - "identifier=%d length=%d", hdr->code, hdr->identifier, len); + "identifier=%d length=%lu", hdr->code, hdr->identifier, + (unsigned long) len); switch (hdr->code) { case EAP_CODE_RESPONSE: eap_fast_process_phase2_response(sm, data, (u8 *) hdr, len); @@ -1201,7 +1237,8 @@ static void eap_fast_process_phase2_tlvs(struct eap_sm *sm, wpa_printf(MSG_DEBUG, "EAP-FAST: PAC-Acknowledgement received " "- PAC provisioning succeeded"); - eap_fast_state(data, data->anon_provisioning ? + eap_fast_state(data, (data->anon_provisioning || + data->send_new_pac == 2) ? FAILURE : SUCCESS); return; }