📄 eap_peap.c
字号:
if (!data->phase2_method->isSuccess(sm, data->phase2_priv)) { wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase2 method failed"); eap_peap_req_failure(sm, data); next_type = EAP_TYPE_NONE; eap_peap_phase2_init(sm, data, next_type); return; } os_free(data->phase2_key); if (data->phase2_method->getKey) { data->phase2_key = data->phase2_method->getKey( sm, data->phase2_priv, &data->phase2_key_len); if (data->phase2_key == NULL) { wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase2 getKey " "failed"); eap_peap_req_failure(sm, data); eap_peap_phase2_init(sm, data, EAP_TYPE_NONE); return; } if (data->phase2_key_len == 32 && data->phase2_method->vendor == EAP_VENDOR_IETF && data->phase2_method->method == EAP_TYPE_MSCHAPV2) { /* * Microsoft uses reverse order for MS-MPPE keys in * EAP-PEAP when compared to EAP-FAST derivation of * ISK. Swap the keys here to get the correct ISK for * EAP-PEAPv0 cryptobinding. */ u8 tmp[16]; os_memcpy(tmp, data->phase2_key, 16); os_memcpy(data->phase2_key, data->phase2_key + 16, 16); os_memcpy(data->phase2_key + 16, tmp, 16); } } switch (data->state) { case PHASE1_ID2: case PHASE2_ID: case PHASE2_SOH: if (eap_user_get(sm, sm->identity, sm->identity_len, 1) != 0) { wpa_hexdump_ascii(MSG_DEBUG, "EAP_PEAP: Phase2 " "Identity not found in the user " "database", sm->identity, sm->identity_len); eap_peap_req_failure(sm, data); next_type = EAP_TYPE_NONE; break; }#ifdef EAP_TNC if (data->state != PHASE2_SOH && sm->tnc && data->peap_version == 0) { eap_peap_state(data, PHASE2_SOH); wpa_printf(MSG_DEBUG, "EAP-PEAP: Try to initialize " "TNC (NAP SOH)"); next_type = EAP_TYPE_NONE; break; }#endif /* EAP_TNC */ eap_peap_state(data, PHASE2_METHOD); next_type = sm->user->methods[0].method; sm->user_eap_method_index = 1; wpa_printf(MSG_DEBUG, "EAP-PEAP: try EAP type %d", next_type); break; case PHASE2_METHOD: eap_peap_req_success(sm, data); next_type = EAP_TYPE_NONE; break; case FAILURE: break; default: wpa_printf(MSG_DEBUG, "EAP-PEAP: %s - unexpected state %d", __func__, data->state); break; } eap_peap_phase2_init(sm, data, next_type);}static void eap_peap_process_phase2(struct eap_sm *sm, struct eap_peap_data *data, const struct wpabuf *respData, struct wpabuf *in_buf){ struct wpabuf *in_decrypted; int len_decrypted; const struct eap_hdr *hdr; size_t buf_len, 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-PEAP: 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_peap_process_phase2_response(sm, data, 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 = wpabuf_alloc(buf_len); if (in_decrypted == NULL) { wpa_printf(MSG_WARNING, "EAP-PEAP: failed to allocate memory " "for decryption"); return; } len_decrypted = tls_connection_decrypt(sm->ssl_ctx, data->ssl.conn, in_data, in_len, wpabuf_mhead(in_decrypted), buf_len); if (len_decrypted < 0) { wpa_printf(MSG_INFO, "EAP-PEAP: Failed to decrypt Phase 2 " "data"); wpabuf_free(in_decrypted); eap_peap_state(data, FAILURE); return; } wpabuf_put(in_decrypted, len_decrypted); wpa_hexdump_buf_key(MSG_DEBUG, "EAP-PEAP: Decrypted Phase 2 EAP", in_decrypted); hdr = wpabuf_head(in_decrypted); if (data->peap_version == 0 && data->state != PHASE2_TLV) { const struct eap_hdr *resp; struct eap_hdr *nhdr; struct wpabuf *nbuf = wpabuf_alloc(sizeof(struct eap_hdr) + wpabuf_len(in_decrypted)); if (nbuf == NULL) { wpabuf_free(in_decrypted); return; } resp = wpabuf_head(respData); nhdr = wpabuf_put(nbuf, sizeof(*nhdr)); nhdr->code = resp->code; nhdr->identifier = resp->identifier; nhdr->length = host_to_be16(sizeof(struct eap_hdr) + wpabuf_len(in_decrypted)); wpabuf_put_buf(nbuf, in_decrypted); wpabuf_free(in_decrypted); in_decrypted = nbuf; } else if (data->peap_version >= 2) { struct eap_tlv_hdr *tlv; struct wpabuf *nmsg; if (wpabuf_len(in_decrypted) < sizeof(*tlv) + sizeof(*hdr)) { wpa_printf(MSG_INFO, "EAP-PEAPv2: Too short Phase 2 " "EAP TLV"); wpabuf_free(in_decrypted); return; } tlv = wpabuf_mhead(in_decrypted); if ((be_to_host16(tlv->tlv_type) & EAP_TLV_TYPE_MASK) != EAP_TLV_EAP_PAYLOAD_TLV) { wpa_printf(MSG_INFO, "EAP-PEAPv2: Not an EAP TLV"); wpabuf_free(in_decrypted); return; } if (sizeof(*tlv) + be_to_host16(tlv->length) > wpabuf_len(in_decrypted)) { wpa_printf(MSG_INFO, "EAP-PEAPv2: Invalid EAP TLV " "length"); wpabuf_free(in_decrypted); return; } hdr = (struct eap_hdr *) (tlv + 1); if (be_to_host16(hdr->length) > be_to_host16(tlv->length)) { wpa_printf(MSG_INFO, "EAP-PEAPv2: No room for full " "EAP packet in EAP TLV"); wpabuf_free(in_decrypted); return; } nmsg = wpabuf_alloc(be_to_host16(hdr->length)); if (nmsg == NULL) { wpabuf_free(in_decrypted); return; } wpabuf_put_data(nmsg, hdr, be_to_host16(hdr->length)); wpabuf_free(in_decrypted); in_decrypted = nmsg; } hdr = wpabuf_head(in_decrypted); if (wpabuf_len(in_decrypted) < (int) sizeof(*hdr)) { wpa_printf(MSG_INFO, "EAP-PEAP: Too short Phase 2 " "EAP frame (len=%lu)", (unsigned long) wpabuf_len(in_decrypted)); wpabuf_free(in_decrypted); eap_peap_req_failure(sm, data); return; } len = be_to_host16(hdr->length); if (len > wpabuf_len(in_decrypted)) { wpa_printf(MSG_INFO, "EAP-PEAP: Length mismatch in " "Phase 2 EAP frame (len=%lu hdr->length=%lu)", (unsigned long) wpabuf_len(in_decrypted), (unsigned long) len); wpabuf_free(in_decrypted); eap_peap_req_failure(sm, data); return; } wpa_printf(MSG_DEBUG, "EAP-PEAP: received Phase 2: code=%d " "identifier=%d length=%lu", hdr->code, hdr->identifier, (unsigned long) len); switch (hdr->code) { case EAP_CODE_RESPONSE: eap_peap_process_phase2_response(sm, data, in_decrypted); break; case EAP_CODE_SUCCESS: wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase 2 Success"); if (data->state == SUCCESS_REQ) { eap_peap_state(data, SUCCESS); } break; case EAP_CODE_FAILURE: wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase 2 Failure"); eap_peap_state(data, FAILURE); break; default: wpa_printf(MSG_INFO, "EAP-PEAP: Unexpected code=%d in " "Phase 2 EAP header", hdr->code); break; } os_free(in_decrypted);}static int eap_peapv2_start_phase2(struct eap_sm *sm, struct eap_peap_data *data){ struct wpabuf *buf, *buf2; int res; wpa_printf(MSG_DEBUG, "EAP-PEAPv2: Phase1 done, include first Phase2 " "payload in the same message"); eap_peap_state(data, PHASE1_ID2); if (eap_peap_phase2_init(sm, data, EAP_TYPE_IDENTITY)) return -1; /* TODO: which Id to use here? */ buf = data->phase2_method->buildReq(sm, data->phase2_priv, 6); if (buf == NULL) return -1; buf2 = eap_peapv2_tlv_eap_payload(buf); if (buf2 == NULL) return -1; wpa_hexdump_buf(MSG_DEBUG, "EAP-PEAPv2: Identity Request", buf2); buf = wpabuf_alloc(data->ssl.tls_out_limit); if (buf == NULL) { wpabuf_free(buf2); return -1; } res = tls_connection_encrypt(sm->ssl_ctx, data->ssl.conn, wpabuf_head(buf2), wpabuf_len(buf2), wpabuf_put(buf, 0), data->ssl.tls_out_limit); wpabuf_free(buf2); if (res < 0) { wpa_printf(MSG_INFO, "EAP-PEAPv2: Failed to encrypt Phase 2 " "data"); wpabuf_free(buf); return -1; } wpabuf_put(buf, res); wpa_hexdump_buf(MSG_DEBUG, "EAP-PEAPv2: Encrypted Identity Request", buf); /* Append TLS data into the pending buffer after the Server Finished */ if (wpabuf_resize(&data->ssl.out_buf, wpabuf_len(buf)) < 0) { wpabuf_free(buf); return -1; } wpabuf_put_buf(data->ssl.out_buf, buf); wpabuf_free(buf); return 0;}static int eap_peap_process_version(struct eap_sm *sm, void *priv, int peer_version){ struct eap_peap_data *data = priv; data->recv_version = peer_version; if (data->force_version >= 0 && peer_version != data->force_version) { wpa_printf(MSG_INFO, "EAP-PEAP: peer did not select the forced" " version (forced=%d peer=%d) - reject", data->force_version, peer_version); return -1; } if (peer_version < data->peap_version) { wpa_printf(MSG_DEBUG, "EAP-PEAP: peer ver=%d, own ver=%d; " "use version %d", peer_version, data->peap_version, peer_version); data->peap_version = peer_version; } return 0;}static void eap_peap_process_msg(struct eap_sm *sm, void *priv, const struct wpabuf *respData){ struct eap_peap_data *data = priv; switch (data->state) { case PHASE1: if (eap_server_tls_phase1(sm, &data->ssl) < 0) { eap_peap_state(data, FAILURE); break; } if (data->peap_version >= 2 && tls_connection_established(sm->ssl_ctx, data->ssl.conn)) { if (eap_peapv2_start_phase2(sm, data)) { eap_peap_state(data, FAILURE); break; } } break; case PHASE2_START: eap_peap_state(data, PHASE2_ID); eap_peap_phase2_init(sm, data, EAP_TYPE_IDENTITY); break; case PHASE1_ID2: case PHASE2_ID: case PHASE2_METHOD: case PHASE2_SOH: case PHASE2_TLV: eap_peap_process_phase2(sm, data, respData, data->ssl.in_buf); break; case SUCCESS_REQ: eap_peap_state(data, SUCCESS); break; case FAILURE_REQ: eap_peap_state(data, FAILURE); break; default: wpa_printf(MSG_DEBUG, "EAP-PEAP: Unexpected state %d in %s", data->state, __func__); break; }}static void eap_peap_process(struct eap_sm *sm, void *priv, struct wpabuf *respData){ struct eap_peap_data *data = priv; if (eap_server_tls_process(sm, &data->ssl, respData, data, EAP_TYPE_PEAP, eap_peap_process_version, eap_peap_process_msg) < 0) eap_peap_state(data, FAILURE);}static Boolean eap_peap_isDone(struct eap_sm *sm, void *priv){ struct eap_peap_data *data = priv; return data->state == SUCCESS || data->state == FAILURE;}static u8 * eap_peap_getKey(struct eap_sm *sm, void *priv, size_t *len){ struct eap_peap_data *data = priv; u8 *eapKeyData; if (data->state != SUCCESS) return NULL; if (data->crypto_binding_used) { u8 csk[128]; /* * Note: It looks like Microsoft implementation requires null * termination for this label while the one used for deriving * IPMK|CMK did not use null termination. */ peap_prfplus(data->peap_version, data->ipmk, 40, "Session Key Generating Function", (u8 *) "\00", 1, csk, sizeof(csk)); wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: CSK", csk, sizeof(csk)); eapKeyData = os_malloc(EAP_TLS_KEY_LEN); if (eapKeyData) { os_memcpy(eapKeyData, csk, EAP_TLS_KEY_LEN); *len = EAP_TLS_KEY_LEN; wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Derived key", eapKeyData, EAP_TLS_KEY_LEN); } else { wpa_printf(MSG_DEBUG, "EAP-PEAP: Failed to derive " "key"); } return eapKeyData; } /* TODO: PEAPv1 - different label in some cases */ eapKeyData = eap_server_tls_derive_key(sm, &data->ssl, "client EAP encryption", EAP_TLS_KEY_LEN); if (eapKeyData) { *len = EAP_TLS_KEY_LEN; wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Derived key", eapKeyData, EAP_TLS_KEY_LEN); } else { wpa_printf(MSG_DEBUG, "EAP-PEAP: Failed to derive key"); } return eapKeyData;}static Boolean eap_peap_isSuccess(struct eap_sm *sm, void *priv){ struct eap_peap_data *data = priv; return data->state == SUCCESS;}int eap_server_peap_register(void){ struct eap_method *eap; int ret; eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION, EAP_VENDOR_IETF, EAP_TYPE_PEAP, "PEAP"); if (eap == NULL) return -1; eap->init = eap_peap_init; eap->reset = eap_peap_reset; eap->buildReq = eap_peap_buildReq; eap->check = eap_peap_check; eap->process = eap_peap_process; eap->isDone = eap_peap_isDone; eap->getKey = eap_peap_getKey; eap->isSuccess = eap_peap_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 + -