static void eap_peap_process_phase2_response(struct eap_sm *sm, struct eap_peap_data *data, struct wpabuf *in_data) { int next_vendor = EAP_VENDOR_IETF; u32 next_type = EAP_TYPE_NONE; const struct eap_hdr *hdr; const u8 *pos; size_t left; if (data->state == PHASE2_TLV) { eap_peap_process_phase2_tlv(sm, data, in_data); return; } #ifdef EAP_SERVER_TNC if (data->state == PHASE2_SOH) { eap_peap_process_phase2_soh(sm, data, in_data); return; } #endif /* EAP_SERVER_TNC */ if (data->phase2_priv == NULL) { wpa_printf(MSG_DEBUG, "EAP-PEAP: %s - Phase2 not " "initialized?!", __func__); return; } hdr = wpabuf_head(in_data); pos = (const u8 *) (hdr + 1); if (wpabuf_len(in_data) > sizeof(*hdr) && *pos == EAP_TYPE_NAK) { left = wpabuf_len(in_data) - sizeof(*hdr); wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Phase2 type Nak'ed; " "allowed types", pos + 1, left - 1); 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].vendor != EAP_VENDOR_IETF || sm->user->methods[sm->user_eap_method_index].method != EAP_TYPE_NONE)) { next_vendor = sm->user->methods[ sm->user_eap_method_index].vendor; next_type = sm->user->methods[ sm->user_eap_method_index++].method; wpa_printf(MSG_DEBUG, "EAP-PEAP: try EAP vendor %d type 0x%x", next_vendor, next_type); } else { eap_peap_req_failure(sm, data); next_vendor = EAP_VENDOR_IETF; next_type = EAP_TYPE_NONE; } eap_peap_phase2_init(sm, data, next_vendor, next_type); return; } if (data->phase2_method->check(sm, data->phase2_priv, in_data)) { wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase2 check() asked to " "ignore the packet"); return; } data->phase2_method->process(sm, data->phase2_priv, in_data); if (sm->method_pending == METHOD_PENDING_WAIT) { wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase2 method is in " "pending wait state - save decrypted response"); wpabuf_free(data->pending_phase2_resp); data->pending_phase2_resp = wpabuf_dup(in_data); } if (!data->phase2_method->isDone(sm, data->phase2_priv)) return; 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_vendor = EAP_VENDOR_IETF; next_type = EAP_TYPE_NONE; eap_peap_phase2_init(sm, data, next_vendor, 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_VENDOR_IETF, EAP_TYPE_NONE); return; } } 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_vendor = EAP_VENDOR_IETF; next_type = EAP_TYPE_NONE; break; } #ifdef EAP_SERVER_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_vendor = EAP_VENDOR_IETF; next_type = EAP_TYPE_NONE; break; } #endif /* EAP_SERVER_TNC */ eap_peap_state(data, PHASE2_METHOD); next_vendor = sm->user->methods[0].vendor; next_type = sm->user->methods[0].method; sm->user_eap_method_index = 1; wpa_printf(MSG_DEBUG, "EAP-PEAP: try EAP vendor %d type 0x%x", next_vendor, next_type); break; case PHASE2_METHOD: eap_peap_req_success(sm, data); next_vendor = EAP_VENDOR_IETF; 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_vendor, 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; const struct eap_hdr *hdr; size_t len; wpa_printf(MSG_DEBUG, "EAP-PEAP: received %lu bytes encrypted data for" " Phase 2", (unsigned long) wpabuf_len(in_buf)); 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; } in_decrypted = tls_connection_decrypt(sm->ssl_ctx, data->ssl.conn, in_buf); if (in_decrypted == NULL) { wpa_printf(MSG_INFO, "EAP-PEAP: Failed to decrypt Phase 2 " "data"); eap_peap_state(data, FAILURE); return; } wpa_hexdump_buf_key(MSG_DEBUG, "EAP-PEAP: Decrypted Phase 2 EAP", 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; } 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; } wpabuf_free(in_decrypted); }
static void eap_peap_process_phase2(struct eap_sm *sm, struct eap_peap_data *data, struct eap_hdr *resp, u8 *in_data, size_t in_len) { u8 *in_decrypted; int buf_len, len_decrypted, len, res; struct eap_hdr *hdr; wpa_printf(MSG_DEBUG, "EAP-PEAP: received %lu bytes encrypted data for" " Phase 2", (unsigned long) in_len); res = eap_tls_data_reassemble(sm, &data->ssl, &in_data, &in_len); if (res < 0 || res == 1) return; buf_len = in_len; if (data->ssl.tls_in_total > buf_len) buf_len = data->ssl.tls_in_total; in_decrypted = malloc(buf_len); if (in_decrypted == NULL) { free(data->ssl.tls_in); data->ssl.tls_in = NULL; data->ssl.tls_in_len = 0; 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, in_decrypted, buf_len); free(data->ssl.tls_in); data->ssl.tls_in = NULL; data->ssl.tls_in_len = 0; if (len_decrypted < 0) { wpa_printf(MSG_INFO, "EAP-PEAP: Failed to decrypt Phase 2 " "data"); free(in_decrypted); eap_peap_state(data, FAILURE); return; } wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: Decrypted Phase 2 EAP", in_decrypted, len_decrypted); hdr = (struct eap_hdr *) in_decrypted; if (data->peap_version == 0 && data->state != PHASE2_TLV) { struct eap_hdr *nhdr = malloc(sizeof(struct eap_hdr) + len_decrypted); if (nhdr == NULL) { free(in_decrypted); return; } memcpy((u8 *) (nhdr + 1), in_decrypted, len_decrypted); free(in_decrypted); nhdr->code = resp->code; nhdr->identifier = resp->identifier; nhdr->length = host_to_be16(sizeof(struct eap_hdr) + len_decrypted); len_decrypted += sizeof(struct eap_hdr); in_decrypted = (u8 *) nhdr; } hdr = (struct eap_hdr *) in_decrypted; if (len_decrypted < sizeof(*hdr)) { free(in_decrypted); wpa_printf(MSG_INFO, "EAP-PEAP: Too short Phase 2 " "EAP frame (len=%d)", len_decrypted); eap_peap_req_failure(sm, data); return; } len = be_to_host16(hdr->length); if (len > len_decrypted) { free(in_decrypted); wpa_printf(MSG_INFO, "EAP-PEAP: Length mismatch in " "Phase 2 EAP frame (len=%d hdr->length=%d)", len_decrypted, len); eap_peap_req_failure(sm, data); return; } wpa_printf(MSG_DEBUG, "EAP-PEAP: received Phase 2: code=%d " "identifier=%d length=%d", hdr->code, hdr->identifier, len); switch (hdr->code) { case EAP_CODE_RESPONSE: eap_peap_process_phase2_response(sm, data, (u8 *) hdr, len); 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; } free(in_decrypted); }
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 void eap_peap_process_phase2_response(struct eap_sm *sm, struct eap_peap_data *data, u8 *in_data, size_t in_len) { u8 next_type = EAP_TYPE_NONE; struct eap_hdr *hdr; u8 *pos; size_t left; if (data->phase2_priv == NULL) { wpa_printf(MSG_DEBUG, "EAP-PEAP: %s - Phase2 not " "initialized?!", __func__); return; } hdr = (struct eap_hdr *) in_data; pos = (u8 *) (hdr + 1); left = in_len - sizeof(*hdr); if (in_len > sizeof(*hdr) && *pos == EAP_TYPE_NAK) { wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Phase2 type Nak'ed; " "allowed types", pos + 1, left - 1); 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] != EAP_TYPE_NONE) { next_type = sm->user->methods[sm->user_eap_method_index++]; wpa_printf(MSG_DEBUG, "EAP-PEAP: try EAP type %d", next_type); } else { next_type = eap_peap_req_failure(sm, data); } eap_peap_phase2_init(sm, data, next_type); return; } if (data->phase2_method->check(sm, data->phase2_priv, in_data, in_len)) { wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase2 check() asked to " "ignore the packet"); return; } data->phase2_method->process(sm, data->phase2_priv, in_data, in_len); if (!data->phase2_method->isDone(sm, data->phase2_priv)) return; if (!data->phase2_method->isSuccess(sm, data->phase2_priv)) { wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase2 method failed"); next_type = eap_peap_req_failure(sm, data); eap_peap_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_PEAP: Phase2 " "Identity not found in the user " "database", sm->identity, sm->identity_len); next_type = eap_peap_req_failure(sm, data); break; } eap_peap_state(data, PHASE2_METHOD); next_type = sm->user->methods[0]; sm->user_eap_method_index = 1; wpa_printf(MSG_DEBUG, "EAP-PEAP: try EAP type %d", next_type); break; case PHASE2_METHOD: next_type = eap_peap_req_success(sm, data); break; case PHASE2_TLV: if (sm->tlv_request == TLV_REQ_SUCCESS || data->state == SUCCESS_REQ) { eap_peap_state(data, SUCCESS); } else { eap_peap_state(data, FAILURE); } 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); }