📄 eap_fast.c
字号:
wpa_printf(MSG_INFO, "EAP-FAST: Failed to decrypt Phase 2 " "data"); os_free(in_decrypted); return -1; } wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Decrypted Phase 2 TLV(s)", in_decrypted, len_decrypted); if (len_decrypted < 4) { os_free(in_decrypted); wpa_printf(MSG_INFO, "EAP-FAST: Too short Phase 2 " "TLV frame (len=%d)", len_decrypted); return -1; } pos = in_decrypted; end = in_decrypted + len_decrypted; stop = 0; while (pos + 4 < end && !stop) { mandatory = pos[0] & 0x80; tlv_type = WPA_GET_BE16(pos) & 0x3fff; pos += 2; len = WPA_GET_BE16(pos); pos += 2; if (pos + len > end) { os_free(in_decrypted); wpa_printf(MSG_INFO, "EAP-FAST: TLV overflow"); return 0; } wpa_printf(MSG_DEBUG, "EAP-FAST: received Phase 2: " "TLV type %d length %d%s", tlv_type, len, mandatory ? " (mandatory)" : ""); switch (tlv_type) { case EAP_TLV_EAP_PAYLOAD_TLV: wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: EAP Payload TLV", pos, len); eap_payload_tlv = pos; eap_payload_tlv_len = len; break; case EAP_TLV_RESULT_TLV: wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Result TLV", pos, len); if (len < 2) { wpa_printf(MSG_DEBUG, "EAP-FAST: Too short " "Result TLV"); result = EAP_TLV_RESULT_FAILURE; break; } result = WPA_GET_BE16(pos); if (result != EAP_TLV_RESULT_SUCCESS && result != EAP_TLV_RESULT_FAILURE) { wpa_printf(MSG_DEBUG, "EAP-FAST: Unknown " "Result %d", result); result = EAP_TLV_RESULT_FAILURE; } wpa_printf(MSG_DEBUG, "EAP-FAST: Result: %s", result == EAP_TLV_RESULT_SUCCESS ? "Success" : "Failure"); break; case EAP_TLV_INTERMEDIATE_RESULT_TLV: wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Intermediate " "Result TLV", pos, len); if (len < 2) { wpa_printf(MSG_DEBUG, "EAP-FAST: Too short " "Intermediate Result TLV"); iresult = EAP_TLV_RESULT_FAILURE; break; } iresult = WPA_GET_BE16(pos); if (iresult != EAP_TLV_RESULT_SUCCESS && iresult != EAP_TLV_RESULT_FAILURE) { wpa_printf(MSG_DEBUG, "EAP-FAST: Unknown " "Intermediate Result %d", iresult); iresult = EAP_TLV_RESULT_FAILURE; } wpa_printf(MSG_DEBUG, "EAP-FAST: Intermediate Result: %s", iresult == EAP_TLV_RESULT_SUCCESS ? "Success" : "Failure"); break; case EAP_TLV_CRYPTO_BINDING_TLV_: wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Crypto-Binding " "TLV", pos, len); crypto_binding_len = sizeof(struct eap_tlv_hdr) + len; if (crypto_binding_len < sizeof(*crypto_binding)) { wpa_printf(MSG_DEBUG, "EAP-FAST: Too short " "Crypto-Binding TLV"); iresult = EAP_TLV_RESULT_FAILURE; pos = end; break; } crypto_binding = (struct eap_tlv_crypto_binding__tlv *) (pos - sizeof(struct eap_tlv_hdr)); break; case EAP_TLV_PAC_TLV: wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: PAC TLV", pos, len); pac = pos; pac_len = len; break; default: if (mandatory) { wpa_printf(MSG_DEBUG, "EAP-FAST: Nak unknown " "mandatory TLV type %d", tlv_type); resp = eap_fast_tlv_nak(0, tlv_type, &resp_len); stop = 1; } else { wpa_printf(MSG_DEBUG, "EAP-FAST: ignored " "unknown optional TLV type %d", tlv_type); } break; } pos += len; } if (!resp && result == EAP_TLV_RESULT_FAILURE) { resp = eap_fast_tlv_result(EAP_TLV_RESULT_FAILURE, 0, &resp_len); if (!resp) { os_free(in_decrypted); return 0; } } if (!resp && iresult == EAP_TLV_RESULT_FAILURE) { resp = eap_fast_tlv_result(EAP_TLV_RESULT_FAILURE, 1, &resp_len); if (!resp) { os_free(in_decrypted); return 0; } } if (!resp && eap_payload_tlv) { if (eap_payload_tlv_len < sizeof(*hdr)) { wpa_printf(MSG_DEBUG, "EAP-FAST: too short EAP " "Payload TLV (len=%lu)", (unsigned long) eap_payload_tlv_len); os_free(in_decrypted); return 0; } hdr = (struct eap_hdr *) eap_payload_tlv; if (be_to_host16(hdr->length) > eap_payload_tlv_len) { wpa_printf(MSG_DEBUG, "EAP-FAST: EAP packet overflow " "in EAP Payload TLV"); os_free(in_decrypted); return 0; } if (hdr->code == EAP_CODE_REQUEST) { if (eap_fast_phase2_request(sm, data, ret, hdr, &resp, &resp_len)) { os_free(in_decrypted); wpa_printf(MSG_INFO, "EAP-FAST: Phase2 " "Request processing failed"); return 0; } resp = eap_fast_tlv_eap_payload(resp, &resp_len); if (resp == NULL) { os_free(in_decrypted); return 0; } } else { wpa_printf(MSG_INFO, "EAP-FAST: Unexpected code=%d in " "Phase 2 EAP header", hdr->code); os_free(in_decrypted); return 0; } } if (!resp && crypto_binding) { int final = result == EAP_TLV_RESULT_SUCCESS; resp = eap_fast_process_crypto_binding(sm, data, ret, crypto_binding, crypto_binding_len, &resp_len, final); if (!resp) { os_free(in_decrypted); return 0; } } if (!resp && pac && result != EAP_TLV_RESULT_SUCCESS) { wpa_printf(MSG_DEBUG, "EAP-FAST: PAC TLV without Result TLV " "acknowledging success"); resp = eap_fast_tlv_result(EAP_TLV_RESULT_FAILURE, 0, &resp_len); if (!resp) { os_free(in_decrypted); return 0; } } if (!resp && pac && result == EAP_TLV_RESULT_SUCCESS) { resp = eap_fast_process_pac(sm, data, ret, pac, pac_len, &resp_len); if (!resp) { os_free(in_decrypted); return 0; } } os_free(in_decrypted); if (resp == NULL) { wpa_printf(MSG_DEBUG, "EAP-FAST: No recognized TLVs - send " "empty response packet"); resp = os_malloc(1); if (resp == NULL) return 0; resp_len = 0; } wpa_hexdump(MSG_DEBUG, "EAP-FAST: Encrypting Phase 2 data", resp, resp_len); if (eap_fast_encrypt(sm, data, req->identifier, resp, resp_len, out_data, out_len)) { wpa_printf(MSG_INFO, "EAP-FAST: Failed to encrypt a Phase 2 " "frame"); } os_free(resp); return 0;}static u8 * eap_fast_process(struct eap_sm *sm, void *priv, struct eap_method_ret *ret, const u8 *reqData, size_t reqDataLen, size_t *respDataLen){ const struct eap_hdr *req; size_t left; int res; u8 flags, *resp, id; const u8 *pos; struct eap_fast_data *data = priv; pos = eap_tls_process_init(sm, &data->ssl, EAP_TYPE_FAST, ret, reqData, reqDataLen, &left, &flags); if (pos == NULL) return NULL; req = (const struct eap_hdr *) reqData; id = req->identifier; if (flags & EAP_TLS_FLAGS_START) { const u8 *a_id; size_t a_id_len; struct pac_tlv_hdr *hdr; wpa_printf(MSG_DEBUG, "EAP-FAST: Start (server ver=%d, own " "ver=%d)", flags & EAP_PEAP_VERSION_MASK, data->fast_version); if ((flags & EAP_PEAP_VERSION_MASK) < data->fast_version) data->fast_version = flags & EAP_PEAP_VERSION_MASK; wpa_printf(MSG_DEBUG, "EAP-FAST: Using FAST version %d", data->fast_version); a_id = pos; a_id_len = left; if (left > sizeof(*hdr)) { int tlen; hdr = (struct pac_tlv_hdr *) pos; tlen = be_to_host16(hdr->len); if (be_to_host16(hdr->type) == PAC_TYPE_A_ID && sizeof(*hdr) + tlen <= left) { a_id = (u8 *) (hdr + 1); a_id_len = tlen; } } wpa_hexdump_ascii(MSG_DEBUG, "EAP-FAST: A-ID", a_id, a_id_len); data->current_pac = eap_fast_get_pac(data, a_id, a_id_len); if (data->current_pac) { wpa_printf(MSG_DEBUG, "EAP-FAST: PAC found for this " "A-ID"); wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-FAST: A-ID-Info", data->current_pac->a_id_info, data->current_pac->a_id_info_len); } if (data->resuming && data->current_pac) { wpa_printf(MSG_DEBUG, "EAP-FAST: Trying to resume " "session - do not add PAC-Opaque to TLS " "ClientHello"); if (tls_connection_client_hello_ext( sm->ssl_ctx, data->ssl.conn, TLS_EXT_PAC_OPAQUE, NULL, 0) < 0) { wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to " "remove PAC-Opaque TLS extension"); return NULL; } } else if (data->current_pac) { u8 *tlv; size_t tlv_len, olen; struct eap_tlv_hdr *ehdr; olen = data->current_pac->pac_opaque_len; tlv_len = sizeof(*ehdr) + olen; tlv = os_malloc(tlv_len); if (tlv) { ehdr = (struct eap_tlv_hdr *) tlv; ehdr->tlv_type = host_to_be16(PAC_TYPE_PAC_OPAQUE); ehdr->length = host_to_be16(olen); os_memcpy(ehdr + 1, data->current_pac->pac_opaque, olen); } if (tlv == NULL || tls_connection_client_hello_ext( sm->ssl_ctx, data->ssl.conn, TLS_EXT_PAC_OPAQUE, tlv, tlv_len) < 0) { wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to " "add PAC-Opaque TLS extension"); os_free(tlv); return NULL; } os_free(tlv); } else { u8 ciphers[2]; if (!data->provisioning_allowed) { wpa_printf(MSG_DEBUG, "EAP-FAST: No PAC found " "and provisioning disabled"); return NULL; } wpa_printf(MSG_DEBUG, "EAP-FAST: No PAC found - " "starting provisioning"); ciphers[0] = TLS_CIPHER_ANON_DH_AES128_SHA; ciphers[1] = TLS_CIPHER_NONE; if (tls_connection_set_cipher_list(sm->ssl_ctx, data->ssl.conn, ciphers)) { wpa_printf(MSG_INFO, "EAP-FAST: Could not " "configure anonymous DH for TLS " "connection"); return NULL; } if (tls_connection_client_hello_ext( sm->ssl_ctx, data->ssl.conn, TLS_EXT_PAC_OPAQUE, NULL, 0) < 0) { wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to " "remove PAC-Opaque TLS extension"); return NULL; } data->provisioning = 1; } left = 0; /* A-ID is not used in further packet processing */ } resp = NULL; if (tls_connection_established(sm->ssl_ctx, data->ssl.conn) && !data->resuming) { res = eap_fast_decrypt(sm, data, ret, req, pos, left, &resp, respDataLen); if (res < 0) { ret->methodState = METHOD_DONE; ret->decision = DECISION_FAIL; /* Ack possible Alert that may have caused failure in * decryption */ res = 1; } } else { if (eap_fast_set_tls_master_secret(sm, data, pos, left) < 0) { wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to configure " "TLS master secret"); ret->methodState = METHOD_DONE; ret->decision = DECISION_FAIL; return NULL; } res = eap_tls_process_helper(sm, &data->ssl, EAP_TYPE_FAST, data->fast_version, id, pos, left, &resp, respDataLen); if (tls_connection_established(sm->ssl_ctx, data->ssl.conn)) { wpa_printf(MSG_DEBUG, "EAP-FAST: TLS done, proceed to Phase 2"); data->resuming = 0; eap_fast_derive_keys(sm, data); } } if (res == 1) return eap_tls_build_ack(&data->ssl, respDataLen, id, EAP_TYPE_FAST, data->fast_version); return resp;}#if 0 /* FIX */static Boolean eap_fast_has_reauth_data(struct eap_sm *sm, void *priv){ struct eap_fast_data *data = priv; return tls_connection_established(sm->ssl_ctx, data->ssl.conn);}static void eap_fast_deinit_for_reauth(struct eap_sm *sm, void *priv){ struct eap_fast_data *data = priv; os_free(data->key_block_p); data->key_block_p = NULL;}static void * eap_fast_init_for_reauth(struct eap_sm *sm, void *priv){ struct eap_fast_data *data = priv; if (eap_tls_reauth_init(sm, &data->ssl)) { os_free(data); return NULL; } if (data->phase2_priv && data->phase2_method && data->phase2_method->init_for_reauth) data->phase2_method->init_for_reauth(sm, data->phase2_priv); data->phase2_success = 0; data->resuming = 1; data->provisioning = 0; data->simck_idx = 0; return priv;}#endifstatic int eap_fast_get_status(struct eap_sm *sm, void *priv, char *buf, size_t buflen, int verbose){ struct eap_fast_data *data = priv; int len, ret; len = eap_tls_status(sm, &data->ssl, buf, buflen, verbose); if (data->phase2_method) { ret = os_snprintf(buf + len, buflen - len, "EAP-FAST Phase2 method=%s\n", data->phase2_method->name); if (ret < 0 || (size_t) ret >= buflen - len) return len; len += ret; } return len;}static Boolean eap_fast_isKeyAvailable(struct eap_sm *sm, void *priv){ struct eap_fast_data *data = priv; return data->success;}static u8 * eap_fast_getKey(struct eap_sm *sm, void *priv, size_t *len){ struct eap_fast_data *data = priv; u8 *key; if (!data->success) return NULL; key = os_malloc(EAP_FAST_KEY_LEN); if (key == NULL) return NULL; *len = EAP_FAST_KEY_LEN; os_memcpy(key, data->key_data, EAP_FAST_KEY_LEN); return key;}static u8 * eap_fast_get_emsk(struct eap_sm *sm, void *priv, size_t *len){ struct eap_fast_data *data = priv; u8 *key; if (!data->success) return NULL; key = os_malloc(EAP_EMSK_LEN); if (key == NULL) return NULL; *len = EAP_EMSK_LEN; os_memcpy(key, data->emsk, EAP_EMSK_LEN); return key;}int eap_peer_fast_register(void){ struct eap_method *eap; int ret; eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION, EAP_VENDOR_IETF, EAP_TYPE_FAST, "FAST"); if (eap == NULL) return -1; eap->init = eap_fast_init; eap->deinit = eap_fast_deinit; eap->process = eap_fast_process; eap->isKeyAvailable = eap_fast_isKeyAvailable; eap->getKey = eap_fast_getKey; eap->get_status = eap_fast_get_status;#if 0 eap->has_reauth_data = eap_fast_has_reauth_data; eap->deinit_for_reauth = eap_fast_deinit_for_reauth; eap->init_for_reauth = eap_fast_init_for_reauth;#endif eap->get_emsk = eap_fast_get_emsk; ret = eap_peer_method_register(eap); if (ret) eap_peer_method_free(eap); return ret;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -