📄 eap_fast.c
字号:
switch (hdr->code) { case EAP_CODE_RESPONSE: eap_fast_process_phase2_response(sm, data, (u8 *) hdr, len); break; default: wpa_printf(MSG_INFO, "EAP-FAST: Unexpected code=%d in " "Phase 2 EAP header", hdr->code); break; }}static int eap_fast_parse_tlvs(u8 *data, size_t data_len, struct eap_fast_tlv_parse *tlv){ int mandatory, tlv_type, len, res; u8 *pos, *end; os_memset(tlv, 0, sizeof(*tlv)); pos = data; end = data + data_len; while (pos + 4 < end) { mandatory = pos[0] & 0x80; tlv_type = WPA_GET_BE16(pos) & 0x3fff; pos += 2; len = WPA_GET_BE16(pos); pos += 2; if (pos + len > end) { wpa_printf(MSG_INFO, "EAP-FAST: TLV overflow"); return -1; } wpa_printf(MSG_DEBUG, "EAP-FAST: Received Phase 2: " "TLV type %d length %d%s", tlv_type, len, mandatory ? " (mandatory)" : ""); res = eap_fast_parse_tlv(tlv, tlv_type, pos, len); if (res == -2) break; if (res < 0) { if (mandatory) { wpa_printf(MSG_DEBUG, "EAP-FAST: Nak unknown " "mandatory TLV type %d", tlv_type); /* TODO: generate Nak TLV */ break; } else { wpa_printf(MSG_DEBUG, "EAP-FAST: Ignored " "unknown optional TLV type %d", tlv_type); } } pos += len; } return 0;}static int eap_fast_validate_crypto_binding( struct eap_fast_data *data, struct eap_tlv_crypto_binding_tlv *b, size_t bind_len){ u8 cmac[SHA1_MAC_LEN]; wpa_printf(MSG_DEBUG, "EAP-FAST: Reply Crypto-Binding TLV: " "Version %d Received Version %d SubType %d", b->version, b->received_version, b->subtype); wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: NONCE", b->nonce, sizeof(b->nonce)); wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Compound MAC", b->compound_mac, sizeof(b->compound_mac)); if (b->version != EAP_FAST_VERSION || b->received_version != EAP_FAST_VERSION) { wpa_printf(MSG_DEBUG, "EAP-FAST: Unexpected version " "in Crypto-Binding: version %d " "received_version %d", b->version, b->received_version); return -1; } if (b->subtype != EAP_TLV_CRYPTO_BINDING_SUBTYPE_RESPONSE) { wpa_printf(MSG_DEBUG, "EAP-FAST: Unexpected subtype in " "Crypto-Binding: %d", b->subtype); return -1; } if (os_memcmp(data->crypto_binding_nonce, b->nonce, 31) != 0 || (data->crypto_binding_nonce[31] | 1) != b->nonce[31]) { wpa_printf(MSG_DEBUG, "EAP-FAST: Invalid nonce in " "Crypto-Binding"); return -1; } os_memcpy(cmac, b->compound_mac, sizeof(cmac)); os_memset(b->compound_mac, 0, sizeof(cmac)); wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Crypto-Binding TLV for " "Compound MAC calculation", (u8 *) b, bind_len); hmac_sha1(data->cmk, EAP_FAST_CMK_LEN, (u8 *) b, bind_len, b->compound_mac); if (os_memcmp(cmac, b->compound_mac, sizeof(cmac)) != 0) { wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Calculated Compound MAC", b->compound_mac, sizeof(cmac)); wpa_printf(MSG_INFO, "EAP-FAST: Compound MAC did not " "match"); return -1; } return 0;}static int eap_fast_pac_type(u8 *pac, size_t len, u16 type){ struct eap_tlv_pac_type_tlv *tlv; if (pac == NULL || len != sizeof(*tlv)) return 0; tlv = (struct eap_tlv_pac_type_tlv *) pac; return be_to_host16(tlv->tlv_type) == PAC_TYPE_PAC_TYPE && be_to_host16(tlv->length) == 2 && be_to_host16(tlv->pac_type) == type;}static void eap_fast_process_phase2_tlvs(struct eap_sm *sm, struct eap_fast_data *data, u8 *in_data, size_t in_len){ struct eap_fast_tlv_parse tlv; int check_crypto_binding = data->state == CRYPTO_BINDING; if (eap_fast_parse_tlvs(in_data, in_len, &tlv) < 0) { wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to parse received " "Phase 2 TLVs"); return; } if (tlv.result == EAP_TLV_RESULT_FAILURE) { wpa_printf(MSG_DEBUG, "EAP-FAST: Result TLV indicated " "failure"); eap_fast_state(data, FAILURE); return; } if (data->state == REQUEST_PAC) { u16 type, len, res; if (tlv.pac == NULL || tlv.pac_len < 6) { wpa_printf(MSG_DEBUG, "EAP-FAST: No PAC " "Acknowledgement received"); eap_fast_state(data, FAILURE); return; } type = WPA_GET_BE16(tlv.pac); len = WPA_GET_BE16(tlv.pac + 2); res = WPA_GET_BE16(tlv.pac + 4); if (type != PAC_TYPE_PAC_ACKNOWLEDGEMENT || len != 2 || res != EAP_TLV_RESULT_SUCCESS) { wpa_printf(MSG_DEBUG, "EAP-FAST: PAC TLV did not " "contain acknowledgement"); eap_fast_state(data, FAILURE); return; } wpa_printf(MSG_DEBUG, "EAP-FAST: PAC-Acknowledgement received " "- PAC provisioning succeeded"); eap_fast_state(data, (data->anon_provisioning || data->send_new_pac == 2) ? FAILURE : SUCCESS); return; } if (check_crypto_binding) { if (tlv.crypto_binding == NULL) { wpa_printf(MSG_DEBUG, "EAP-FAST: No Crypto-Binding " "TLV received"); eap_fast_state(data, FAILURE); return; } if (data->final_result && tlv.result != EAP_TLV_RESULT_SUCCESS) { wpa_printf(MSG_DEBUG, "EAP-FAST: Crypto-Binding TLV " "without Success Result"); eap_fast_state(data, FAILURE); return; } if (!data->final_result && tlv.iresult != EAP_TLV_RESULT_SUCCESS) { wpa_printf(MSG_DEBUG, "EAP-FAST: Crypto-Binding TLV " "without intermediate Success Result"); eap_fast_state(data, FAILURE); return; } if (eap_fast_validate_crypto_binding(data, tlv.crypto_binding, tlv.crypto_binding_len)) { eap_fast_state(data, FAILURE); return; } wpa_printf(MSG_DEBUG, "EAP-FAST: Valid Crypto-Binding TLV " "received"); if (data->final_result) { wpa_printf(MSG_DEBUG, "EAP-FAST: Authentication " "completed successfully"); } if (data->anon_provisioning && sm->eap_fast_prov != ANON_PROV && sm->eap_fast_prov != BOTH_PROV) { wpa_printf(MSG_DEBUG, "EAP-FAST: Client is trying to " "use unauthenticated provisioning which is " "disabled"); eap_fast_state(data, FAILURE); return; } if (sm->eap_fast_prov != AUTH_PROV && sm->eap_fast_prov != BOTH_PROV && tlv.request_action == EAP_TLV_ACTION_PROCESS_TLV && eap_fast_pac_type(tlv.pac, tlv.pac_len, PAC_TYPE_TUNNEL_PAC)) { wpa_printf(MSG_DEBUG, "EAP-FAST: Client is trying to " "use authenticated provisioning which is " "disabled"); eap_fast_state(data, FAILURE); return; } if (data->anon_provisioning || (tlv.request_action == EAP_TLV_ACTION_PROCESS_TLV && eap_fast_pac_type(tlv.pac, tlv.pac_len, PAC_TYPE_TUNNEL_PAC))) { wpa_printf(MSG_DEBUG, "EAP-FAST: Requested a new " "Tunnel PAC"); eap_fast_state(data, REQUEST_PAC); } else if (data->send_new_pac) { wpa_printf(MSG_DEBUG, "EAP-FAST: Server triggered " "re-keying of Tunnel PAC"); eap_fast_state(data, REQUEST_PAC); } else if (data->final_result) eap_fast_state(data, SUCCESS); } if (tlv.eap_payload_tlv) { eap_fast_process_phase2_eap(sm, data, tlv.eap_payload_tlv, tlv.eap_payload_tlv_len); }}static void eap_fast_process_phase2(struct eap_sm *sm, struct eap_fast_data *data, struct wpabuf *in_buf){ u8 *in_decrypted; int len_decrypted; size_t buf_len; u8 *in_data; size_t in_len; in_data = wpabuf_mhead(in_buf); in_len = wpabuf_len(in_buf); wpa_printf(MSG_DEBUG, "EAP-FAST: Received %lu bytes encrypted data for" " Phase 2", (unsigned long) in_len); if (data->pending_phase2_resp) { wpa_printf(MSG_DEBUG, "EAP-PEAP: Pending Phase 2 response - " "skip decryption and use old data"); eap_fast_process_phase2_tlvs( sm, data, wpabuf_mhead(data->pending_phase2_resp), wpabuf_len(data->pending_phase2_resp)); wpabuf_free(data->pending_phase2_resp); data->pending_phase2_resp = NULL; return; } buf_len = in_len; /* * Even though we try to disable TLS compression, it is possible that * this cannot be done with all TLS libraries. Add extra buffer space * to handle the possibility of the decrypted data being longer than * input data. */ buf_len += 500; buf_len *= 3; in_decrypted = os_malloc(buf_len); if (in_decrypted == NULL) { wpa_printf(MSG_WARNING, "EAP-FAST: Failed to allocate memory " "for decryption"); return; } len_decrypted = tls_connection_decrypt(sm->ssl_ctx, data->ssl.conn, in_data, in_len, in_decrypted, buf_len); if (len_decrypted < 0) { wpa_printf(MSG_INFO, "EAP-FAST: Failed to decrypt Phase 2 " "data"); os_free(in_decrypted); eap_fast_state(data, FAILURE); return; } wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: Decrypted Phase 2 TLVs", in_decrypted, len_decrypted); eap_fast_process_phase2_tlvs(sm, data, in_decrypted, len_decrypted); if (sm->method_pending == METHOD_PENDING_WAIT) { wpa_printf(MSG_DEBUG, "EAP-FAST: Phase2 method is in " "pending wait state - save decrypted response"); wpabuf_free(data->pending_phase2_resp); data->pending_phase2_resp = wpabuf_alloc_copy(in_decrypted, len_decrypted); } os_free(in_decrypted);}static int eap_fast_process_version(struct eap_sm *sm, void *priv, int peer_version){ struct eap_fast_data *data = priv; data->peer_version = peer_version; if (data->force_version >= 0 && peer_version != data->force_version) { wpa_printf(MSG_INFO, "EAP-FAST: peer did not select the forced" " version (forced=%d peer=%d) - reject", data->force_version, peer_version); return -1; } if (peer_version < data->fast_version) { wpa_printf(MSG_DEBUG, "EAP-FAST: peer ver=%d, own ver=%d; " "use version %d", peer_version, data->fast_version, peer_version); data->fast_version = peer_version; } return 0;}static int eap_fast_process_phase1(struct eap_sm *sm, struct eap_fast_data *data){ if (eap_server_tls_phase1(sm, &data->ssl) < 0) { wpa_printf(MSG_INFO, "EAP-FAST: TLS processing failed"); eap_fast_state(data, FAILURE); return -1; } if (!tls_connection_established(sm->ssl_ctx, data->ssl.conn) || wpabuf_len(data->ssl.out_buf) > 0) return 1; /* * Phase 1 was completed with the received message (e.g., when using * abbreviated handshake), so Phase 2 can be started immediately * without having to send through an empty message to the peer. */ return eap_fast_phase1_done(sm, data);}static void eap_fast_process_phase2_start(struct eap_sm *sm, struct eap_fast_data *data){ u8 next_type; if (data->identity) { os_free(sm->identity); sm->identity = data->identity; data->identity = NULL; sm->identity_len = data->identity_len; data->identity_len = 0; sm->require_identity_match = 1; 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);}static void eap_fast_process_msg(struct eap_sm *sm, void *priv, const struct wpabuf *respData){ struct eap_fast_data *data = priv; switch (data->state) { case PHASE1: if (eap_fast_process_phase1(sm, data)) break; /* fall through to PHASE2_START */ case PHASE2_START: eap_fast_process_phase2_start(sm, data); break; case PHASE2_ID: case PHASE2_METHOD: case CRYPTO_BINDING: case REQUEST_PAC: eap_fast_process_phase2(sm, data, data->ssl.in_buf); break; default: wpa_printf(MSG_DEBUG, "EAP-FAST: Unexpected state %d in %s", data->state, __func__); break; }}static void eap_fast_process(struct eap_sm *sm, void *priv, struct wpabuf *respData){ struct eap_fast_data *data = priv; if (eap_server_tls_process(sm, &data->ssl, respData, data, EAP_TYPE_FAST, eap_fast_process_version, eap_fast_process_msg) < 0) eap_fast_state(data, FAILURE);}static Boolean eap_fast_isDone(struct eap_sm *sm, void *priv){ struct eap_fast_data *data = priv; return data->state == SUCCESS || data->state == FAILURE;}static u8 * eap_fast_getKey(struct eap_sm *sm, void *priv, size_t *len){ struct eap_fast_data *data = priv; u8 *eapKeyData; if (data->state != SUCCESS) return NULL; eapKeyData = os_malloc(EAP_FAST_KEY_LEN); if (eapKeyData == NULL) return NULL; eap_fast_derive_eap_msk(data->simck, eapKeyData); *len = EAP_FAST_KEY_LEN; return eapKeyData;}static u8 * eap_fast_get_emsk(struct eap_sm *sm, void *priv, size_t *len){ struct eap_fast_data *data = priv; u8 *eapKeyData; if (data->state != SUCCESS) return NULL; eapKeyData = os_malloc(EAP_EMSK_LEN); if (eapKeyData == NULL) return NULL; eap_fast_derive_eap_emsk(data->simck, eapKeyData); *len = EAP_EMSK_LEN; return eapKeyData;}static Boolean eap_fast_isSuccess(struct eap_sm *sm, void *priv){ struct eap_fast_data *data = priv; return data->state == SUCCESS;}int eap_server_fast_register(void){ struct eap_method *eap; int ret; eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION, EAP_VENDOR_IETF, EAP_TYPE_FAST, "FAST"); if (eap == NULL) return -1; eap->init = eap_fast_init; eap->reset = eap_fast_reset; eap->buildReq = eap_fast_buildReq; eap->check = eap_fast_check; eap->process = eap_fast_process; eap->isDone = eap_fast_isDone; eap->getKey = eap_fast_getKey; eap->get_emsk = eap_fast_get_emsk; eap->isSuccess = eap_fast_isSuccess; ret = eap_server_method_register(eap); if (ret) eap_server_method_free(eap); return ret;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -