static int eap_tls_process_input(struct eap_sm *sm, struct eap_ssl_data *data, const u8 *in_data, size_t in_len, u8 **out_data, size_t *out_len) { const u8 *msg; size_t msg_len; int need_more_input; u8 *appl_data; size_t appl_data_len; msg = eap_tls_data_reassemble(sm, data, in_data, in_len, &msg_len, &need_more_input); if (msg == NULL) return need_more_input ? 1 : -1; /* Full TLS message reassembled - continue handshake processing */ if (data->tls_out) { /* This should not happen.. */ wpa_printf(MSG_INFO, "SSL: eap_tls_process_helper - pending " "tls_out data even though tls_out_len = 0"); os_free(data->tls_out); WPA_ASSERT(data->tls_out == NULL); } appl_data = NULL; data->tls_out = tls_connection_handshake(sm->ssl_ctx, data->conn, msg, msg_len, &data->tls_out_len, &appl_data, &appl_data_len); /* Clear reassembled input data (if the buffer was needed). */ data->tls_in_left = data->tls_in_total = data->tls_in_len = 0; os_free(data->tls_in); data->tls_in = NULL; if (appl_data && tls_connection_established(sm->ssl_ctx, data->conn) && !tls_connection_get_failed(sm->ssl_ctx, data->conn)) { wpa_hexdump_key(MSG_MSGDUMP, "SSL: Application data", appl_data, appl_data_len); *out_data = appl_data; *out_len = appl_data_len; return 2; } os_free(appl_data); return 0; }
int eap_tls_process_helper(struct eap_sm *sm, struct eap_ssl_data *data, u8 *in_data, size_t in_len) { WPA_ASSERT(data->tls_out_len == 0 || in_len == 0); if (data->tls_out_len == 0) { /* No more data to send out - expect to receive more data from * the peer. */ int res = eap_tls_data_reassemble(sm, data, &in_data, &in_len); if (res < 0 || res == 1) { wpa_printf(MSG_DEBUG, "SSL: data reassembly failed"); return res; } /* Full TLS message reassembled - continue handshake processing */ if (data->tls_out) { /* This should not happen.. */ wpa_printf(MSG_INFO, "SSL: eap_tls_process_helper - " "pending tls_out data even though " "tls_out_len = 0"); free(data->tls_out); WPA_ASSERT(data->tls_out == NULL); } data->tls_out = tls_connection_server_handshake( sm->ssl_ctx, data->conn, in_data, in_len, &data->tls_out_len); /* Clear reassembled input data (if the buffer was needed). */ data->tls_in_left = data->tls_in_total = data->tls_in_len = 0; free(data->tls_in); data->tls_in = NULL; } if (data->tls_out == NULL) { wpa_printf(MSG_DEBUG, "SSL: failed to generate output data"); data->tls_out_len = 0; return -1; } if (data->tls_out_len == 0) { /* TLS negotiation should now be complete since all other cases * needing more that should have been catched above based on * the TLS Message Length field. */ wpa_printf(MSG_DEBUG, "SSL: No data to be sent out"); free(data->tls_out); data->tls_out = NULL; if (tls_connection_get_read_alerts(sm->ssl_ctx, data->conn)) { wpa_printf(MSG_DEBUG, "SSL: Remote end sent a fatal " "alert - abort handshake"); return -1; } return 1; } wpa_printf(MSG_DEBUG, "SSL: %lu bytes left to be sent out (of total " "%lu bytes)", (unsigned long) data->tls_out_len - data->tls_out_pos, (unsigned long) data->tls_out_len); return 0; }
int eap_tls_process_helper(struct eap_sm *sm, struct eap_ssl_data *data, int eap_type, int peap_version, u8 id, const u8 *in_data, size_t in_len, u8 **out_data, size_t *out_len) { size_t len; u8 *pos, *flags; struct eap_hdr *resp; int ret = 0; WPA_ASSERT(data->tls_out_len == 0 || in_len == 0); *out_len = 0; if (data->tls_out_len == 0) { /* No more data to send out - expect to receive more data from * the AS. */ const u8 *msg; size_t msg_len; int need_more_input; msg = eap_tls_data_reassemble(sm, data, in_data, in_len, &msg_len, &need_more_input); if (msg == NULL) return need_more_input ? 1 : -1; /* Full TLS message reassembled - continue handshake processing */ if (data->tls_out) { /* This should not happen.. */ wpa_printf(MSG_INFO, "SSL: eap_tls_process_helper - " "pending tls_out data even though " "tls_out_len = 0"); free(data->tls_out); WPA_ASSERT(data->tls_out == NULL); } data->tls_out = tls_connection_handshake(sm->ssl_ctx, data->conn, msg, msg_len, &data->tls_out_len); /* Clear reassembled input data (if the buffer was needed). */ data->tls_in_left = data->tls_in_total = data->tls_in_len = 0; free(data->tls_in); data->tls_in = NULL; } if (data->tls_out == NULL) { data->tls_out_len = 0; return -1; } if (tls_connection_get_failed(sm->ssl_ctx, data->conn)) { wpa_printf(MSG_DEBUG, "SSL: Failed - tls_out available to " "report error"); ret = -1; /* TODO: clean pin if engine used? */ } if (data->tls_out_len == 0) { /* TLS negotiation should now be complete since all other cases * needing more that should have been catched above based on * the TLS Message Length field. */ wpa_printf(MSG_DEBUG, "SSL: No data to be sent out"); free(data->tls_out); data->tls_out = NULL; return 1; } wpa_printf(MSG_DEBUG, "SSL: %lu bytes left to be sent out (of total " "%lu bytes)", (unsigned long) data->tls_out_len - data->tls_out_pos, (unsigned long) data->tls_out_len); resp = malloc(sizeof(struct eap_hdr) + 2 + 4 + data->tls_out_limit); if (resp == NULL) { *out_data = NULL; return -1; } resp->code = EAP_CODE_RESPONSE; resp->identifier = id; pos = (u8 *) (resp + 1); *pos++ = eap_type; flags = pos++; *flags = peap_version; if (data->tls_out_pos == 0 && (data->tls_out_len > data->tls_out_limit || data->include_tls_length)) { *flags |= EAP_TLS_FLAGS_LENGTH_INCLUDED; *pos++ = (data->tls_out_len >> 24) & 0xff; *pos++ = (data->tls_out_len >> 16) & 0xff; *pos++ = (data->tls_out_len >> 8) & 0xff; *pos++ = data->tls_out_len & 0xff; }
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); }