📄 eap_fast.c
字号:
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, data->srv_id_len); eap_fast_state(data, PHASE1); return req;}static int eap_fast_phase1_done(struct eap_sm *sm, struct eap_fast_data *data){ char cipher[64]; wpa_printf(MSG_DEBUG, "EAP-FAST: Phase1 done, starting Phase2"); if (tls_get_cipher(sm->ssl_ctx, data->ssl.conn, cipher, sizeof(cipher)) < 0) { wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to get cipher " "information"); eap_fast_state(data, FAILURE); return -1; } data->anon_provisioning = os_strstr(cipher, "ADH") != NULL; if (data->anon_provisioning) { wpa_printf(MSG_DEBUG, "EAP-FAST: Anonymous provisioning"); eap_fast_derive_key_provisioning(sm, data); } else eap_fast_derive_key_auth(sm, data); eap_fast_state(data, PHASE2_START); return 0;}static struct wpabuf * eap_fast_build_phase2_req(struct eap_sm *sm, struct eap_fast_data *data, u8 id){ struct wpabuf *req; if (data->phase2_priv == NULL) { wpa_printf(MSG_DEBUG, "EAP-FAST: Phase 2 method not " "initialized"); return NULL; } req = data->phase2_method->buildReq(sm, data->phase2_priv, id); if (req == NULL) return NULL; wpa_hexdump_buf_key(MSG_MSGDUMP, "EAP-FAST: Phase 2 EAP-Request", req); return eap_fast_tlv_eap_payload(req);}static struct wpabuf * eap_fast_build_crypto_binding( struct eap_sm *sm, struct eap_fast_data *data){ struct wpabuf *buf; struct eap_tlv_result_tlv *result; struct eap_tlv_crypto_binding_tlv *binding; buf = wpabuf_alloc(2 * sizeof(*result) + sizeof(*binding)); if (buf == NULL) return NULL; if (data->send_new_pac || data->anon_provisioning || data->phase2_method) data->final_result = 0; else data->final_result = 1; if (!data->final_result || data->eap_seq > 1) { /* Intermediate-Result */ wpa_printf(MSG_DEBUG, "EAP-FAST: Add Intermediate-Result TLV " "(status=SUCCESS)"); result = wpabuf_put(buf, sizeof(*result)); result->tlv_type = host_to_be16( EAP_TLV_TYPE_MANDATORY | EAP_TLV_INTERMEDIATE_RESULT_TLV); result->length = host_to_be16(2); result->status = host_to_be16(EAP_TLV_RESULT_SUCCESS); } if (data->final_result) { /* Result TLV */ wpa_printf(MSG_DEBUG, "EAP-FAST: Add Result TLV " "(status=SUCCESS)"); result = wpabuf_put(buf, sizeof(*result)); result->tlv_type = host_to_be16(EAP_TLV_TYPE_MANDATORY | EAP_TLV_RESULT_TLV); result->length = host_to_be16(2); result->status = host_to_be16(EAP_TLV_RESULT_SUCCESS); } /* Crypto-Binding TLV */ binding = wpabuf_put(buf, sizeof(*binding)); binding->tlv_type = host_to_be16(EAP_TLV_TYPE_MANDATORY | EAP_TLV_CRYPTO_BINDING_TLV); binding->length = host_to_be16(sizeof(*binding) - sizeof(struct eap_tlv_hdr)); binding->version = EAP_FAST_VERSION; binding->received_version = data->peer_version; binding->subtype = EAP_TLV_CRYPTO_BINDING_SUBTYPE_REQUEST; if (os_get_random(binding->nonce, sizeof(binding->nonce)) < 0) { wpabuf_free(buf); return NULL; } /* * RFC 4851, Section 4.2.8: * The nonce in a request MUST have its least significant bit set to 0. */ binding->nonce[sizeof(binding->nonce) - 1] &= ~0x01; os_memcpy(data->crypto_binding_nonce, binding->nonce, sizeof(binding->nonce)); /* * RFC 4851, Section 5.3: * CMK = CMK[j] * Compound-MAC = HMAC-SHA1( CMK, Crypto-Binding TLV ) */ hmac_sha1(data->cmk, EAP_FAST_CMK_LEN, (u8 *) binding, sizeof(*binding), binding->compound_mac); wpa_printf(MSG_DEBUG, "EAP-FAST: Add Crypto-Binding TLV: Version %d " "Received Version %d SubType %d", binding->version, binding->received_version, binding->subtype); wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: NONCE", binding->nonce, sizeof(binding->nonce)); wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Compound MAC", binding->compound_mac, sizeof(binding->compound_mac)); return buf;}static struct wpabuf * eap_fast_build_pac(struct eap_sm *sm, struct eap_fast_data *data){ u8 pac_key[EAP_FAST_PAC_KEY_LEN]; u8 *pac_buf, *pac_opaque; struct wpabuf *buf; u8 *pos; 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; struct os_time now; 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, 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_info_len = os_strlen(data->srv_id_info); 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 + data->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; } pac_len = pos - pac_buf; while (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, pac_len); buf_len = sizeof(*pac_tlv) + sizeof(struct pac_tlv_hdr) + EAP_FAST_PAC_KEY_LEN + sizeof(struct pac_tlv_hdr) + pac_len + data->srv_id_len + srv_id_info_len + 100 + sizeof(*result); buf = wpabuf_alloc(buf_len); if (buf == NULL) { os_free(pac_opaque); return NULL; } /* Result TLV */ wpa_printf(MSG_DEBUG, "EAP-FAST: Add Result TLV (status=SUCCESS)"); result = wpabuf_put(buf, sizeof(*result)); WPA_PUT_BE16((u8 *) &result->tlv_type, EAP_TLV_TYPE_MANDATORY | EAP_TLV_RESULT_TLV); WPA_PUT_BE16((u8 *) &result->length, 2); WPA_PUT_BE16((u8 *) &result->status, EAP_TLV_RESULT_SUCCESS); /* PAC TLV */ wpa_printf(MSG_DEBUG, "EAP-FAST: Add PAC TLV"); pac_tlv = wpabuf_put(buf, sizeof(*pac_tlv)); pac_tlv->tlv_type = host_to_be16(EAP_TLV_TYPE_MANDATORY | EAP_TLV_PAC_TLV); /* PAC-Key */ eap_fast_put_tlv(buf, PAC_TYPE_PAC_KEY, pac_key, EAP_FAST_PAC_KEY_LEN); /* PAC-Opaque */ eap_fast_put_tlv(buf, PAC_TYPE_PAC_OPAQUE, pac_opaque, pac_len); os_free(pac_opaque); /* PAC-Info */ pac_info = wpabuf_put(buf, sizeof(*pac_info)); pac_info->type = host_to_be16(PAC_TYPE_PAC_INFO); /* PAC-Lifetime (inside PAC-Info) */ eap_fast_put_tlv_hdr(buf, PAC_TYPE_CRED_LIFETIME, 4); 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, 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_info, srv_id_info_len); /* PAC-Type (inside PAC-Info) */ eap_fast_put_tlv_hdr(buf, PAC_TYPE_PAC_TYPE, 2); wpabuf_put_be16(buf, PAC_TYPE_TUNNEL_PAC); /* Update PAC-Info and PAC TLV Length fields */ pos = wpabuf_put(buf, 0); pac_info->len = host_to_be16(pos - (u8 *) (pac_info + 1)); pac_tlv->length = host_to_be16(pos - (u8 *) (pac_tlv + 1)); return buf;}static struct wpabuf * eap_fast_buildReq(struct eap_sm *sm, void *priv, u8 id){ struct eap_fast_data *data = priv; struct wpabuf *req = NULL; struct wpabuf *encr; if (data->ssl.state == FRAG_ACK) { return eap_server_tls_build_ack(id, EAP_TYPE_FAST, data->fast_version); } if (data->ssl.state == WAIT_FRAG_ACK) { return eap_server_tls_build_msg(&data->ssl, EAP_TYPE_FAST, data->fast_version, id); } switch (data->state) { case START: return eap_fast_build_start(sm, data, id); case PHASE1: if (tls_connection_established(sm->ssl_ctx, data->ssl.conn)) { if (eap_fast_phase1_done(sm, data) < 0) return NULL; } break; case PHASE2_ID: case PHASE2_METHOD: req = eap_fast_build_phase2_req(sm, data, id); break; case CRYPTO_BINDING: req = eap_fast_build_crypto_binding(sm, data); if (data->phase2_method) { /* * Include the start of the next EAP method in the * sequence in the same message with Crypto-Binding to * save a round-trip. */ struct wpabuf *eap; eap = eap_fast_build_phase2_req(sm, data, id); req = wpabuf_concat(req, eap); eap_fast_state(data, PHASE2_METHOD); } break; case REQUEST_PAC: req = eap_fast_build_pac(sm, data); break; default: wpa_printf(MSG_DEBUG, "EAP-FAST: %s - unexpected state %d", __func__, data->state); return NULL; } if (req) { wpa_hexdump_buf_key(MSG_DEBUG, "EAP-FAST: Encrypting Phase 2 " "TLVs", req); encr = eap_server_tls_encrypt(sm, &data->ssl, wpabuf_mhead(req), wpabuf_len(req)); wpabuf_free(req); wpabuf_free(data->ssl.out_buf); data->ssl.out_used = 0; data->ssl.out_buf = encr; } return eap_server_tls_build_msg(&data->ssl, EAP_TYPE_FAST, data->fast_version, id);}static Boolean eap_fast_check(struct eap_sm *sm, void *priv, struct wpabuf *respData){ const u8 *pos; size_t len; pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_FAST, respData, &len); if (pos == NULL || len < 1) { wpa_printf(MSG_INFO, "EAP-FAST: Invalid frame"); return TRUE; } return FALSE;}static int eap_fast_phase2_init(struct eap_sm *sm, struct eap_fast_data *data, EapType eap_type){ if (data->phase2_priv && data->phase2_method) { data->phase2_method->reset(sm, data->phase2_priv); data->phase2_method = NULL; data->phase2_priv = NULL; } data->phase2_method = eap_server_get_eap_method(EAP_VENDOR_IETF, eap_type); if (!data->phase2_method) return -1; if (data->key_block_p) { sm->auth_challenge = data->key_block_p->server_challenge; sm->peer_challenge = data->key_block_p->client_challenge; } sm->init_phase2 = 1; data->phase2_priv = data->phase2_method->init(sm); sm->init_phase2 = 0; sm->auth_challenge = NULL; sm->peer_challenge = NULL; return data->phase2_priv == NULL ? -1 : 0;}static void eap_fast_process_phase2_response(struct eap_sm *sm, struct eap_fast_data *data, u8 *in_data, size_t in_len){ u8 next_type = EAP_TYPE_NONE; struct eap_hdr *hdr; u8 *pos; size_t left; struct wpabuf buf; const struct eap_method *m = data->phase2_method; void *priv = data->phase2_priv; if (priv == NULL) { wpa_printf(MSG_DEBUG, "EAP-FAST: %s - Phase2 not " "initialized?!", __func__); return; } hdr = (struct eap_hdr *) in_data; pos = (u8 *) (hdr + 1); if (in_len > sizeof(*hdr) && *pos == EAP_TYPE_NAK) { left = in_len - sizeof(*hdr); wpa_hexdump(MSG_DEBUG, "EAP-FAST: Phase2 type Nak'ed; " "allowed types", pos + 1, left - 1);#ifdef EAP_TNC if (m && m->vendor == EAP_VENDOR_IETF && m->method == EAP_TYPE_TNC) { wpa_printf(MSG_DEBUG, "EAP-FAST: Peer Nak'ed required " "TNC negotiation"); next_type = eap_fast_req_failure(sm, data); eap_fast_phase2_init(sm, data, next_type); return; }#endif /* EAP_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 != EAP_TYPE_NONE) { next_type = sm->user->methods[ sm->user_eap_method_index++].method; wpa_printf(MSG_DEBUG, "EAP-FAST: try EAP type %d", next_type); } else { next_type = eap_fast_req_failure(sm, data); } eap_fast_phase2_init(sm, data, next_type); return; } wpabuf_set(&buf, in_data, in_len); if (m->check(sm, priv, &buf)) { wpa_printf(MSG_DEBUG, "EAP-FAST: Phase2 check() asked to " "ignore the packet"); next_type = eap_fast_req_failure(sm, data); return; } m->process(sm, priv, &buf); if (!m->isDone(sm, priv)) return; if (!m->isSuccess(sm, priv)) { wpa_printf(MSG_DEBUG, "EAP-FAST: Phase2 method failed"); next_type = eap_fast_req_failure(sm, data); eap_fast_phase2_init(sm, data, next_type); return; } switch (data->state) { case PHASE2_ID: 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); break; } eap_fast_state(data, PHASE2_METHOD); if (data->anon_provisioning) { /* * Only EAP-MSCHAPv2 is allowed for anonymous * provisioning. */ next_type = EAP_TYPE_MSCHAPV2; sm->user_eap_method_index = 0; } else { next_type = sm->user->methods[0].method; sm->user_eap_method_index = 1; } wpa_printf(MSG_DEBUG, "EAP-FAST: try EAP type %d", next_type); break; case PHASE2_METHOD: case CRYPTO_BINDING: eap_fast_update_icmk(sm, data); eap_fast_state(data, CRYPTO_BINDING); data->eap_seq++; next_type = EAP_TYPE_NONE;#ifdef EAP_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 */ break; case FAILURE: break; default: wpa_printf(MSG_DEBUG, "EAP-FAST: %s - unexpected state %d", __func__, data->state); break; } eap_fast_phase2_init(sm, data, next_type);}static void eap_fast_process_phase2_eap(struct eap_sm *sm, struct eap_fast_data *data, u8 *in_data, size_t in_len){ struct eap_hdr *hdr; size_t len; 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=%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=%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=%lu", hdr->code, hdr->identifier, (unsigned long) len);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -