static void eap_ikev2_process(struct eap_sm *sm, void *priv, struct wpabuf *respData) { struct eap_ikev2_data *data = priv; const u8 *start, *pos, *end; size_t len; u8 flags; u32 message_length = 0; struct wpabuf tmpbuf; pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_IKEV2, respData, &len); if (pos == NULL) return; /* Should not happen; message already verified */ start = pos; end = start + len; if (len == 0) { /* fragment ack */ flags = 0; } else flags = *pos++; if (eap_ikev2_process_icv(data, respData, flags, pos, &end, data->state == WAIT_FRAG_ACK && len == 0) < 0) { eap_ikev2_state(data, FAIL); return; } if (flags & IKEV2_FLAGS_LENGTH_INCLUDED) { if (end - pos < 4) { wpa_printf(MSG_DEBUG, "EAP-IKEV2: Message underflow"); eap_ikev2_state(data, FAIL); return; } message_length = WPA_GET_BE32(pos); pos += 4; if (message_length < (u32) (end - pos)) { wpa_printf(MSG_DEBUG, "EAP-IKEV2: Invalid Message " "Length (%d; %ld remaining in this msg)", message_length, (long) (end - pos)); eap_ikev2_state(data, FAIL); return; } } wpa_printf(MSG_DEBUG, "EAP-IKEV2: Received packet: Flags 0x%x " "Message Length %u", flags, message_length); if (data->state == WAIT_FRAG_ACK) { if (len != 0) { wpa_printf(MSG_DEBUG, "EAP-IKEV2: Unexpected payload " "in WAIT_FRAG_ACK state"); eap_ikev2_state(data, FAIL); return; } wpa_printf(MSG_DEBUG, "EAP-IKEV2: Fragment acknowledged"); eap_ikev2_state(data, MSG); return; } if (data->in_buf && eap_ikev2_process_cont(data, pos, end - pos) < 0) { eap_ikev2_state(data, FAIL); return; } if (flags & IKEV2_FLAGS_MORE_FRAGMENTS) { if (eap_ikev2_process_fragment(data, flags, message_length, pos, end - pos) < 0) eap_ikev2_state(data, FAIL); else eap_ikev2_state(data, FRAG_ACK); return; } else if (data->state == FRAG_ACK) { wpa_printf(MSG_DEBUG, "EAP-TNC: All fragments received"); data->state = MSG; } if (data->in_buf == NULL) { /* Wrap unfragmented messages as wpabuf without extra copy */ wpabuf_set(&tmpbuf, pos, end - pos); data->in_buf = &tmpbuf; } if (ikev2_initiator_process(&data->ikev2, data->in_buf) < 0) { if (data->in_buf == &tmpbuf) data->in_buf = NULL; eap_ikev2_state(data, FAIL); return; } switch (data->ikev2.state) { case SA_AUTH: /* SA_INIT was sent out, so message have to be * integrity protected from now on. */ data->keys_ready = 1; break; case IKEV2_DONE: if (data->state == FAIL) break; wpa_printf(MSG_DEBUG, "EAP-IKEV2: Authentication completed " "successfully"); if (eap_ikev2_server_keymat(data)) break; eap_ikev2_state(data, DONE); break; default: break; } if (data->in_buf != &tmpbuf) wpabuf_free(data->in_buf); data->in_buf = NULL; }
static struct wpabuf * eap_ikev2_process(struct eap_sm *sm, void *priv, struct eap_method_ret *ret, const struct wpabuf *reqData) { struct eap_ikev2_data *data = priv; const u8 *start, *pos, *end; size_t len; u8 flags, id; u32 message_length = 0; struct wpabuf tmpbuf; pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_IKEV2, reqData, &len); if (pos == NULL) { ret->ignore = TRUE; return NULL; } id = eap_get_id(reqData); start = pos; end = start + len; if (len == 0) flags = 0; /* fragment ack */ else flags = *pos++; if (eap_ikev2_process_icv(data, reqData, flags, pos, &end) < 0) { ret->ignore = TRUE; return NULL; } if (flags & IKEV2_FLAGS_LENGTH_INCLUDED) { if (end - pos < 4) { wpa_printf(MSG_DEBUG, "EAP-IKEV2: Message underflow"); ret->ignore = TRUE; return NULL; } message_length = WPA_GET_BE32(pos); pos += 4; if (message_length < (u32) (end - pos)) { wpa_printf(MSG_DEBUG, "EAP-IKEV2: Invalid Message " "Length (%d; %ld remaining in this msg)", message_length, (long) (end - pos)); ret->ignore = TRUE; return NULL; } } wpa_printf(MSG_DEBUG, "EAP-IKEV2: Received packet: Flags 0x%x " "Message Length %u", flags, message_length); if (data->state == WAIT_FRAG_ACK) { #ifdef CCNS_PL if (len > 1) /* Empty Flags field included in ACK */ #else /* CCNS_PL */ if (len != 0) #endif /* CCNS_PL */ { wpa_printf(MSG_DEBUG, "EAP-IKEV2: Unexpected payload " "in WAIT_FRAG_ACK state"); ret->ignore = TRUE; return NULL; } wpa_printf(MSG_DEBUG, "EAP-IKEV2: Fragment acknowledged"); eap_ikev2_state(data, PROC_MSG); return eap_ikev2_build_msg(data, ret, id); } if (data->in_buf && eap_ikev2_process_cont(data, pos, end - pos) < 0) { ret->ignore = TRUE; return NULL; } if (flags & IKEV2_FLAGS_MORE_FRAGMENTS) { return eap_ikev2_process_fragment(data, ret, id, flags, message_length, pos, end - pos); } if (data->in_buf == NULL) { /* Wrap unfragmented messages as wpabuf without extra copy */ wpabuf_set(&tmpbuf, pos, end - pos); data->in_buf = &tmpbuf; } if (ikev2_responder_process(&data->ikev2, data->in_buf) < 0) { if (data->in_buf == &tmpbuf) data->in_buf = NULL; eap_ikev2_state(data, FAIL); return NULL; } if (data->in_buf != &tmpbuf) wpabuf_free(data->in_buf); data->in_buf = NULL; if (data->out_buf == NULL) { data->out_buf = ikev2_responder_build(&data->ikev2); if (data->out_buf == NULL) { wpa_printf(MSG_DEBUG, "EAP-IKEV2: Failed to generate " "IKEv2 message"); return NULL; } data->out_used = 0; } eap_ikev2_state(data, PROC_MSG); return eap_ikev2_build_msg(data, ret, id); }