📄 eap_fast.c
字号:
wpa_printf(MSG_INFO, "EAP-FAST: Phase2 Request processing " "failed"); return NULL; } return eap_fast_tlv_eap_payload(resp);}static int eap_fast_validate_crypto_binding( struct eap_tlv_crypto_binding_tlv *_bind){ wpa_printf(MSG_DEBUG, "EAP-FAST: Crypto-Binding TLV: Version %d " "Received Version %d SubType %d", _bind->version, _bind->received_version, _bind->subtype); wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: NONCE", _bind->nonce, sizeof(_bind->nonce)); wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Compound MAC", _bind->compound_mac, sizeof(_bind->compound_mac)); if (_bind->version != EAP_FAST_VERSION || _bind->received_version != EAP_FAST_VERSION || _bind->subtype != EAP_TLV_CRYPTO_BINDING_SUBTYPE_REQUEST) { wpa_printf(MSG_INFO, "EAP-FAST: Invalid version/subtype in " "Crypto-Binding TLV: Version %d " "Received Version %d SubType %d", _bind->version, _bind->received_version, _bind->subtype); return -1; } return 0;}static void eap_fast_write_crypto_binding( struct eap_tlv_crypto_binding_tlv *rbind, struct eap_tlv_crypto_binding_tlv *_bind, const u8 *cmk){ rbind->tlv_type = host_to_be16(EAP_TLV_TYPE_MANDATORY | EAP_TLV_CRYPTO_BINDING_TLV); rbind->length = host_to_be16(sizeof(*rbind) - sizeof(struct eap_tlv_hdr)); rbind->version = EAP_FAST_VERSION; rbind->received_version = _bind->version; rbind->subtype = EAP_TLV_CRYPTO_BINDING_SUBTYPE_RESPONSE; os_memcpy(rbind->nonce, _bind->nonce, sizeof(_bind->nonce)); inc_byte_array(rbind->nonce, sizeof(rbind->nonce)); hmac_sha1(cmk, EAP_FAST_CMK_LEN, (u8 *) rbind, sizeof(*rbind), rbind->compound_mac); wpa_printf(MSG_DEBUG, "EAP-FAST: Reply Crypto-Binding TLV: Version %d " "Received Version %d SubType %d", rbind->version, rbind->received_version, rbind->subtype); wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: NONCE", rbind->nonce, sizeof(rbind->nonce)); wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Compound MAC", rbind->compound_mac, sizeof(rbind->compound_mac));}static int eap_fast_get_phase2_key(struct eap_sm *sm, struct eap_fast_data *data, u8 *isk, size_t isk_len){ u8 *key; size_t key_len; os_memset(isk, 0, isk_len); if (data->phase2_method == NULL || data->phase2_priv == NULL) { wpa_printf(MSG_DEBUG, "EAP-FAST: Phase 2 method not " "available"); return -1; } if (data->phase2_method->isKeyAvailable == NULL || data->phase2_method->getKey == NULL) return 0; if (!data->phase2_method->isKeyAvailable(sm, data->phase2_priv) || (key = data->phase2_method->getKey(sm, data->phase2_priv, &key_len)) == NULL) { wpa_printf(MSG_DEBUG, "EAP-FAST: Could not get key material " "from Phase 2"); return -1; } if (key_len > isk_len) key_len = isk_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;}static int eap_fast_get_cmk(struct eap_sm *sm, struct eap_fast_data *data, u8 *cmk){ u8 isk[32], imck[60]; wpa_printf(MSG_DEBUG, "EAP-FAST: Determining CMK[%d] for Compound MIC " "calculation", data->simck_idx + 1); /* * RFC 4851, Section 5.2: * IMCK[j] = T-PRF(S-IMCK[j-1], "Inner Methods Compound Keys", * MSK[j], 60) * S-IMCK[j] = first 40 octets of IMCK[j] * CMK[j] = last 20 octets of IMCK[j] */ if (eap_fast_get_phase2_key(sm, data, isk, sizeof(isk)) < 0) return -1; wpa_hexdump_key(MSG_MSGDUMP, "EAP-FAST: ISK[j]", isk, sizeof(isk)); sha1_t_prf(data->simck, EAP_FAST_SIMCK_LEN, "Inner Methods Compound Keys", isk, sizeof(isk), imck, sizeof(imck)); data->simck_idx++; os_memcpy(data->simck, imck, EAP_FAST_SIMCK_LEN); wpa_hexdump_key(MSG_MSGDUMP, "EAP-FAST: S-IMCK[j]", data->simck, EAP_FAST_SIMCK_LEN); os_memcpy(cmk, imck + EAP_FAST_SIMCK_LEN, EAP_FAST_CMK_LEN); wpa_hexdump_key(MSG_MSGDUMP, "EAP-FAST: CMK[j]", cmk, EAP_FAST_CMK_LEN); return 0;}static u8 * eap_fast_write_pac_request(u8 *pos, u16 pac_type){ struct eap_tlv_hdr *pac; struct eap_tlv_request_action_tlv *act; struct eap_tlv_pac_type_tlv *type; act = (struct eap_tlv_request_action_tlv *) pos; act->tlv_type = host_to_be16(EAP_TLV_REQUEST_ACTION_TLV); act->length = host_to_be16(2); act->action = host_to_be16(EAP_TLV_ACTION_PROCESS_TLV); pac = (struct eap_tlv_hdr *) (act + 1); pac->tlv_type = host_to_be16(EAP_TLV_PAC_TLV); pac->length = host_to_be16(sizeof(*type)); type = (struct eap_tlv_pac_type_tlv *) (pac + 1); type->tlv_type = host_to_be16(PAC_TYPE_PAC_TYPE); type->length = host_to_be16(2); type->pac_type = host_to_be16(pac_type); return (u8 *) (type + 1);}static struct wpabuf * eap_fast_process_crypto_binding( struct eap_sm *sm, struct eap_fast_data *data, struct eap_method_ret *ret, struct eap_tlv_crypto_binding_tlv *_bind, size_t bind_len){ struct wpabuf *resp; u8 *pos; u8 cmk[EAP_FAST_CMK_LEN], cmac[SHA1_MAC_LEN]; int res; size_t len; if (eap_fast_validate_crypto_binding(_bind) < 0) return NULL; if (eap_fast_get_cmk(sm, data, cmk) < 0) return NULL; /* Validate received Compound MAC */ os_memcpy(cmac, _bind->compound_mac, sizeof(cmac)); os_memset(_bind->compound_mac, 0, sizeof(cmac)); wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Crypto-Binding TLV for Compound " "MAC calculation", (u8 *) _bind, bind_len); hmac_sha1(cmk, EAP_FAST_CMK_LEN, (u8 *) _bind, bind_len, _bind->compound_mac); res = os_memcmp(cmac, _bind->compound_mac, sizeof(cmac)); wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Received Compound MAC", cmac, sizeof(cmac)); wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Calculated Compound MAC", _bind->compound_mac, sizeof(cmac)); if (res != 0) { wpa_printf(MSG_INFO, "EAP-FAST: Compound MAC did not match"); os_memcpy(_bind->compound_mac, cmac, sizeof(cmac)); return NULL; } /* * Compound MAC was valid, so authentication succeeded. Reply with * crypto binding to allow server to complete authentication. */ len = sizeof(struct eap_tlv_crypto_binding_tlv); resp = wpabuf_alloc(len); if (resp == NULL) return NULL; if (!data->anon_provisioning && data->phase2_success && eap_fast_derive_msk(data) < 0) { wpa_printf(MSG_INFO, "EAP-FAST: Failed to generate MSK"); ret->methodState = METHOD_DONE; ret->decision = DECISION_FAIL; data->phase2_success = 0; wpabuf_free(resp); return NULL; } pos = wpabuf_put(resp, sizeof(struct eap_tlv_crypto_binding_tlv)); eap_fast_write_crypto_binding((struct eap_tlv_crypto_binding_tlv *) pos, _bind, cmk); return resp;}static void eap_fast_parse_pac_tlv(struct eap_fast_pac *entry, int type, u8 *pos, size_t len, int *pac_key_found){ switch (type & 0x7fff) { case PAC_TYPE_PAC_KEY: wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: PAC-Key", pos, len); if (len != EAP_FAST_PAC_KEY_LEN) { wpa_printf(MSG_DEBUG, "EAP-FAST: Invalid PAC-Key " "length %lu", (unsigned long) len); break; } *pac_key_found = 1; os_memcpy(entry->pac_key, pos, len); break; case PAC_TYPE_PAC_OPAQUE: wpa_hexdump(MSG_DEBUG, "EAP-FAST: PAC-Opaque", pos, len); entry->pac_opaque = pos; entry->pac_opaque_len = len; break; case PAC_TYPE_PAC_INFO: wpa_hexdump(MSG_DEBUG, "EAP-FAST: PAC-Info", pos, len); entry->pac_info = pos; entry->pac_info_len = len; break; default: wpa_printf(MSG_DEBUG, "EAP-FAST: Ignored unknown PAC type %d", type); break; }}static int eap_fast_process_pac_tlv(struct eap_fast_pac *entry, u8 *pac, size_t pac_len){ struct pac_tlv_hdr *hdr; u8 *pos; size_t left, len; int type, pac_key_found = 0; pos = pac; left = pac_len; while (left > sizeof(*hdr)) { hdr = (struct pac_tlv_hdr *) pos; type = be_to_host16(hdr->type); len = be_to_host16(hdr->len); pos += sizeof(*hdr); left -= sizeof(*hdr); if (len > left) { wpa_printf(MSG_DEBUG, "EAP-FAST: PAC TLV overrun " "(type=%d len=%lu left=%lu)", type, (unsigned long) len, (unsigned long) left); return -1; } eap_fast_parse_pac_tlv(entry, type, pos, len, &pac_key_found); pos += len; left -= len; } if (!pac_key_found || !entry->pac_opaque || !entry->pac_info) { wpa_printf(MSG_DEBUG, "EAP-FAST: PAC TLV does not include " "all the required fields"); return -1; } return 0;}static int eap_fast_parse_pac_info(struct eap_fast_pac *entry, int type, u8 *pos, size_t len){ u16 pac_type; u32 lifetime; struct os_time now; switch (type & 0x7fff) { case PAC_TYPE_CRED_LIFETIME: if (len != 4) { wpa_hexdump(MSG_DEBUG, "EAP-FAST: PAC-Info - " "Invalid CRED_LIFETIME length - ignored", pos, len); return 0; } /* * This is not currently saved separately in PAC files since * the server can automatically initiate PAC update when * needed. Anyway, the information is available from PAC-Info * dump if it is needed for something in the future. */ lifetime = WPA_GET_BE32(pos); os_get_time(&now); wpa_printf(MSG_DEBUG, "EAP-FAST: PAC-Info - CRED_LIFETIME %d " "(%d days)", lifetime, (lifetime - (u32) now.sec) / 86400); break; case PAC_TYPE_A_ID: wpa_hexdump_ascii(MSG_DEBUG, "EAP-FAST: PAC-Info - A-ID", pos, len); entry->a_id = pos; entry->a_id_len = len; break; case PAC_TYPE_I_ID: wpa_hexdump_ascii(MSG_DEBUG, "EAP-FAST: PAC-Info - I-ID", pos, len); entry->i_id = pos; entry->i_id_len = len; break; case PAC_TYPE_A_ID_INFO: wpa_hexdump_ascii(MSG_DEBUG, "EAP-FAST: PAC-Info - A-ID-Info", pos, len); entry->a_id_info = pos; entry->a_id_info_len = len; break; case PAC_TYPE_PAC_TYPE: /* RFC 5422, Section 4.2.6 - PAC-Type TLV */ if (len != 2) { wpa_printf(MSG_INFO, "EAP-FAST: Invalid PAC-Type " "length %lu (expected 2)", (unsigned long) len); wpa_hexdump_ascii(MSG_DEBUG, "EAP-FAST: PAC-Info - PAC-Type", pos, len); return -1; } pac_type = WPA_GET_BE16(pos); if (pac_type != PAC_TYPE_TUNNEL_PAC && pac_type != PAC_TYPE_USER_AUTHORIZATION && pac_type != PAC_TYPE_MACHINE_AUTHENTICATION) { wpa_printf(MSG_INFO, "EAP-FAST: Unsupported PAC Type " "%d", pac_type); return -1; } wpa_printf(MSG_DEBUG, "EAP-FAST: PAC-Info - PAC-Type %d", pac_type); entry->pac_type = pac_type; break; default: wpa_printf(MSG_DEBUG, "EAP-FAST: Ignored unknown PAC-Info " "type %d", type); break; } return 0;}static int eap_fast_process_pac_info(struct eap_fast_pac *entry){ struct pac_tlv_hdr *hdr; u8 *pos; size_t left, len; int type; /* RFC 5422, Section 4.2.4 */ /* PAC-Type defaults to Tunnel PAC (Type 1) */ entry->pac_type = PAC_TYPE_TUNNEL_PAC; pos = entry->pac_info; left = entry->pac_info_len; while (left > sizeof(*hdr)) { hdr = (struct pac_tlv_hdr *) pos; type = be_to_host16(hdr->type); len = be_to_host16(hdr->len); pos += sizeof(*hdr); left -= sizeof(*hdr); if (len > left) { wpa_printf(MSG_DEBUG, "EAP-FAST: PAC-Info overrun " "(type=%d len=%lu left=%lu)", type, (unsigned long) len, (unsigned long) left); return -1; } if (eap_fast_parse_pac_info(entry, type, pos, len) < 0) return -1; pos += len; left -= len; } if (entry->a_id == NULL || entry->a_id_info == NULL) { wpa_printf(MSG_DEBUG, "EAP-FAST: PAC-Info does not include " "all the required fields"); return -1; } return 0;}static struct wpabuf * eap_fast_process_pac(struct eap_sm *sm, struct eap_fast_data *data, struct eap_method_ret *ret, u8 *pac, size_t pac_len){ struct eap_peer_config *config = eap_get_config(sm); struct eap_fast_pac entry; os_memset(&entry, 0, sizeof(entry)); if (eap_fast_process_pac_tlv(&entry, pac, pac_len) || eap_fast_process_pac_info(&entry)) return NULL; eap_fast_add_pac(&data->pac, &data->current_pac, &entry); eap_fast_pac_list_truncate(data->pac, data->max_pac_list_len); if (data->use_pac_binary_format) eap_fast_save_pac_bin(sm, data->pac, config->pac_file); else eap_fast_save_pac(sm, data->pac, config->pac_file); if (data->provisioning) { if (data->anon_provisioning) { /* * Unauthenticated provisioning does not provide keying * material and must end with an EAP-Failure. * Authentication will be done separately after this. */ data->success = 0; ret->decision = DECISION_FAIL; } else { /* * Server may or may not allow authenticated * provisioning also for key generation. */ ret->decision = DECISION_COND_SUCC; } wpa_printf(MSG_DEBUG, "EAP-FAST: Send PAC-Acknowledgement TLV " "- Provisioning completed successfully"); } else { /* * This is PAC refreshing, i.e., normal authentication that is * expected to be completed with an EAP-Success. */ wpa_printf(MSG_DEBUG, "EAP-FAST: Send PAC-Acknowledgement TLV " "- PAC refreshing completed successfully"); ret->decision = DECISION_UNCOND_SUCC; } ret->methodState = METHOD_DONE; return eap_fast_tlv_pac_ack();}static int eap_fast_parse_decrypted(struct wpabuf *decrypted, struct eap_fast_tlv_parse *tlv, struct wpabuf **resp){ int mandatory, tlv_type, len, res; u8 *pos, *end; os_memset(tlv, 0, sizeof(*tlv)); /* Parse TLVs from the decrypted Phase 2 data */ pos = wpabuf_mhead(decrypted); end = pos + wpabuf_len(decrypted); 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); *resp = eap_fast_tlv_nak(0, tlv_type); break; } else { wpa_printf(MSG_DEBUG, "EAP-FAST: ignored " "unknown optional TLV type %d", tlv_type); } } pos += len; } return 0;}static int eap_fast_encrypt_response(struct eap_sm *sm, struct eap_fast_data *data, struct wpabuf *resp, u8 identifier, struct wpabuf **out_data){ if (resp == NULL) return 0; wpa_hexdump_buf(MSG_DEBUG, "EAP-FAST: Encrypting Phase 2 data", resp); if (eap_peer_tls_encrypt(sm, &data->ssl, EAP_TYPE_FAST, data->fast_version, identifier, resp, out_data)) { wpa_printf(MSG_INFO, "EAP-FAST: Failed to encrypt a Phase 2 " "frame"); } wpabuf_free(resp); return 0;}static struct wpabuf * eap_fast_pac_request(void){ struct wpabuf *tmp; u8 *pos, *pos2; tmp = wpabuf_alloc(sizeof(struct eap_tlv_hdr) + sizeof(struct eap_tlv_request_action_tlv) + sizeof(struct eap_tlv_pac_type_tlv)); if (tmp == NULL) return NULL; pos = wpabuf_put(tmp, 0); pos2 = eap_fast_write_pac_request(pos, PAC_TYPE_TUNNEL_PAC); wpabuf_put(tmp, pos2 - pos); return tmp;}static int eap_fast_process_decrypted(struct eap_sm *sm, struct eap_fast_data *data, struct eap_method_ret *ret,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -