static Boolean eap_identity_check(struct eap_sm *sm, void *priv, struct wpabuf *respData) { const u8 *pos; size_t len; pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_IDENTITY, respData, &len); if (pos == NULL) { wpa_printf(MSG_INFO, "EAP-Identity: Invalid frame"); return TRUE; } return FALSE; }
static struct wpabuf * eap_gpsk_process(struct eap_sm *sm, void *priv, struct eap_method_ret *ret, const struct wpabuf *reqData) { struct eap_gpsk_data *data = priv; struct wpabuf *resp; const u8 *pos; size_t len; pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_GPSK, reqData, &len); if (pos == NULL || len < 1) { ret->ignore = TRUE; return NULL; } wpa_printf(MSG_DEBUG, "EAP-GPSK: Received frame: opcode %d", *
static Boolean eap_aka_check(struct eap_sm *sm, void *priv, struct wpabuf *respData) { struct eap_aka_data *data = priv; const u8 *pos; size_t len; pos = eap_hdr_validate(EAP_VENDOR_IETF, data->eap_method, respData, &len); if (pos == NULL || len < 3) { wpa_printf(MSG_INFO, "EAP-AKA: Invalid frame"); return TRUE; } return FALSE; }
static void eap_sim_process(struct eap_sm *sm, void *priv, struct wpabuf *respData) { struct eap_sim_data *data = priv; const u8 *pos, *end; u8 subtype; size_t len; struct eap_sim_attrs attr; pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_SIM, respData, &len); if (pos == NULL || len < 3) return; end = pos + len; subtype = *pos; pos += 3; if (eap_sim_parse_attr(pos, end, &attr, 0, 0)) { wpa_printf(MSG_DEBUG, "EAP-SIM: Failed to parse attributes"); eap_sim_state(data, FAILURE); return; } if (subtype == EAP_SIM_SUBTYPE_CLIENT_ERROR) { eap_sim_process_client_error(sm, data, respData, &attr); return; } switch (data->state) { case START: eap_sim_process_start(sm, data, respData, &attr); break; case CHALLENGE: eap_sim_process_challenge(sm, data, respData, &attr); break; case REAUTH: eap_sim_process_reauth(sm, data, respData, &attr); break; case NOTIFICATION: eap_sim_process_notification(sm, data, respData, &attr); break; default: wpa_printf(MSG_DEBUG, "EAP-SIM: Unknown state %d in " "process", data->state); break; } }
static Boolean eap_gtc_check(struct eap_sm *sm, void *priv, u8 *respData, size_t respDataLen) { const u8 *pos; size_t len; (void)sm; (void)priv; pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_GTC, respData, respDataLen, &len); if (pos == NULL || len < 1) { wpa_printf(MSG_INFO, "EAP-GTC: Invalid frame"); return TRUE; } return FALSE; }
static Boolean eap_md5_check(struct eap_sm *sm, void *priv, struct wpabuf *respData) { const u8 *pos; size_t len; pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_MD5, respData, &len); if (pos == NULL || len < 1) { wpa_printf(MSG_INFO, "EAP-MD5: Invalid frame"); return TRUE; } if (*pos != CHAP_MD5_LEN || 1 + CHAP_MD5_LEN > len) { wpa_printf(MSG_INFO, "EAP-MD5: Invalid response " "(response_len=%d payload_len=%lu", *pos, (unsigned long)len); return TRUE; } return FALSE; }
static struct wpabuf * eap_pwd_process(struct eap_sm *sm, void *priv, struct eap_method_ret *ret, const struct wpabuf *reqData) { struct eap_pwd_data *data = priv; struct wpabuf *resp = NULL; const u8 *pos; size_t len; u8 exch; pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PWD, reqData, &len); if ((pos == NULL) || (len < 1)) { ret->ignore = TRUE; return NULL; } wpa_printf(MSG_INFO, "EAP-pwd: Received frame: opcode %d", *pos); ret->ignore = FALSE; ret->methodState = METHOD_MAY_CONT; ret->decision = DECISION_FAIL; ret->allowNotifications = FALSE; exch = *pos & 0x3f; switch (exch) { case EAP_PWD_OPCODE_ID_EXCH: resp = eap_pwd_perform_id_exchange(sm, data, ret, reqData, pos + 1, len - 1); break; case EAP_PWD_OPCODE_COMMIT_EXCH: resp = eap_pwd_perform_commit_exchange(sm, data, ret, reqData, pos + 1, len - 1); break; case EAP_PWD_OPCODE_CONFIRM_EXCH: resp = eap_pwd_perform_confirm_exchange(sm, data, ret, reqData, pos + 1, len - 1); break; default: wpa_printf(MSG_INFO, "EAP-pwd: Ignoring message with unknown " "opcode %d", exch); break; } return resp; }
int eap_server_tls_process(struct eap_sm *sm, struct eap_ssl_data *data, struct wpabuf *respData, void *priv, int eap_type, int (*proc_version)(struct eap_sm *sm, void *priv, int peer_version), void (*proc_msg)(struct eap_sm *sm, void *priv, const struct wpabuf *respData)) { const u8 *pos; u8 flags; size_t left; int ret, res = 0; pos = eap_hdr_validate(EAP_VENDOR_IETF, eap_type, respData, &left); if (pos == NULL || left < 1) return 0; /* Should not happen - frame already validated */ flags = *pos++; left--; wpa_printf(MSG_DEBUG, "SSL: Received packet(len=%lu) - Flags 0x%02x", (unsigned long) wpabuf_len(respData), flags); if (proc_version && proc_version(sm, priv, flags & EAP_TLS_VERSION_MASK) < 0) return -1; ret = eap_server_tls_reassemble(data, flags, &pos, &left); if (ret < 0) { res = -1; goto done; } else if (ret == 1) return 0; if (proc_msg) proc_msg(sm, priv, respData); if (tls_connection_get_write_alerts(sm->ssl_ctx, data->conn) > 1) { wpa_printf(MSG_INFO, "SSL: Locally detected fatal error in " "TLS processing"); res = -1; } done: eap_server_tls_free_in_buf(data); return res; }
static u8 * eap_gpsk_process(struct eap_sm *sm, void *priv, struct eap_method_ret *ret, const u8 *reqData, size_t reqDataLen, size_t *respDataLen) { struct eap_gpsk_data *data = priv; u8 *resp; const u8 *pos; size_t len; pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_GPSK, reqData, reqDataLen, &len); if (pos == NULL || len < 1) { ret->ignore = TRUE; return NULL; } wpa_printf(MSG_DEBUG, "EAP-GPSK: Received frame: opcode %d", *pos); ret->ignore = FALSE; ret->methodState = METHOD_MAY_CONT; ret->decision = DECISION_FAIL; ret->allowNotifications = FALSE; switch (*pos) { case EAP_GPSK_OPCODE_GPSK_1: resp = eap_gpsk_process_gpsk_1(sm, data, ret, reqData, reqDataLen, pos + 1, len - 1, respDataLen); break; case EAP_GPSK_OPCODE_GPSK_3: resp = eap_gpsk_process_gpsk_3(sm, data, ret, reqData, reqDataLen, pos + 1, len - 1, respDataLen); break; default: wpa_printf(MSG_DEBUG, "EAP-GPSK: Ignoring message with " "unknown opcode %d", *pos); ret->ignore = TRUE; return NULL; } return resp; }
static void eap_md5_process(struct eap_sm *sm, void *priv, u8 *respData, size_t respDataLen) { struct eap_md5_data *data = priv; struct eap_hdr *resp; const u8 *pos; const u8 *addr[3]; size_t len[3], plen; u8 hash[MD5_MAC_LEN]; if (sm->user == NULL || sm->user->password == NULL || sm->user->password_hash) { wpa_printf(MSG_INFO, "EAP-MD5: Plaintext password not " "configured"); data->state = FAILURE; return; } pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_MD5, respData, respDataLen, &plen); if (pos == NULL || *pos != MD5_MAC_LEN || plen < 1 + MD5_MAC_LEN) return; /* Should not happen - frame already validated */ pos++; /* Skip response len */ wpa_hexdump(MSG_MSGDUMP, "EAP-MD5: Response", pos, MD5_MAC_LEN); resp = (struct eap_hdr *) respData; addr[0] = &resp->identifier; len[0] = 1; addr[1] = sm->user->password; len[1] = sm->user->password_len; addr[2] = data->challenge; len[2] = CHALLENGE_LEN; md5_vector(3, addr, len, hash); if (memcmp(hash, pos, MD5_MAC_LEN) == 0) { wpa_printf(MSG_DEBUG, "EAP-MD5: Done - Success"); data->state = SUCCESS; } else { wpa_printf(MSG_DEBUG, "EAP-MD5: Done - Failure"); data->state = FAILURE; } }
static void eap_identity_process(struct eap_sm *sm, void *priv, struct wpabuf *respData) { struct eap_identity_data *data = priv; const u8 *pos; size_t len; char *buf; if (data->pick_up) { if (eap_identity_check(sm, data, respData)) { wpa_printf(MSG_DEBUG, "EAP-Identity: failed to pick " "up already started negotiation"); data->state = FAILURE; return; } data->pick_up = 0; } pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_IDENTITY, respData, &len); if (pos == NULL) return; /* Should not happen - frame already validated */ wpa_hexdump_ascii(MSG_DEBUG, "EAP-Identity: Peer identity", pos, len); buf = os_malloc(len * 4 + 1); if (buf) { printf_encode(buf, len * 4 + 1, pos, len); eap_log_msg(sm, "EAP-Response/Identity '%s'", buf); os_free(buf); } if (sm->identity) sm->update_user = TRUE; os_free(sm->identity); sm->identity = os_malloc(len ? len : 1); if (sm->identity == NULL) { data->state = FAILURE; } else { os_memcpy(sm->identity, pos, len); sm->identity_len = len; data->state = SUCCESS; } }
static void eap_gpsk_process(struct eap_sm *sm, void *priv, struct wpabuf *respData) { struct eap_gpsk_data *data = priv; const u8 *pos; size_t len; pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_GPSK, respData, &len); if (pos == NULL || len < 1) return; switch (*pos) { case EAP_GPSK_OPCODE_GPSK_2: eap_gpsk_process_gpsk_2(sm, data, pos + 1, len - 1); break; case EAP_GPSK_OPCODE_GPSK_4: eap_gpsk_process_gpsk_4(sm, data, pos + 1, len - 1); break; } }
static Boolean eap_mschapv2_check(struct eap_sm *sm, void *priv, struct wpabuf *respData) { struct eap_mschapv2_data *data = priv; struct eap_mschapv2_hdr *resp; const u8 *pos; size_t len; pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2, respData, &len); if (pos == NULL || len < 1) { wpa_printf(MSG_INFO, "EAP-MSCHAPV2: Invalid frame"); return TRUE; } resp = (struct eap_mschapv2_hdr *) pos; if (data->state == CHALLENGE && resp->op_code != MSCHAPV2_OP_RESPONSE) { wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Expected Response - " "ignore op %d", resp->op_code); return TRUE; } if (data->state == SUCCESS_REQ && resp->op_code != MSCHAPV2_OP_SUCCESS && resp->op_code != MSCHAPV2_OP_FAILURE) { wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Expected Success or " "Failure - ignore op %d", resp->op_code); return TRUE; } if (data->state == FAILURE_REQ && resp->op_code != MSCHAPV2_OP_FAILURE) { wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Expected Failure " "- ignore op %d", resp->op_code); return TRUE; } return FALSE; }
static struct wpabuf * eap_psk_process(struct eap_sm *sm, void *priv, struct eap_method_ret *ret, const struct wpabuf *reqData) { struct eap_psk_data *data = priv; const u8 *pos; struct wpabuf *resp = NULL; size_t len; pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PSK, reqData, &len); if (pos == NULL) { ret->ignore = TRUE; return NULL; } ret->ignore = FALSE; ret->methodState = METHOD_MAY_CONT; ret->decision = DECISION_FAIL; ret->allowNotifications = TRUE; switch (data->state) { case PSK_INIT: resp = eap_psk_process_1(data, ret, reqData); break; case PSK_MAC_SENT: resp = eap_psk_process_3(data, ret, reqData); break; case PSK_DONE: wpa_printf(MSG_DEBUG, "EAP-PSK: in DONE state - ignore " "unexpected message"); ret->ignore = TRUE; return NULL; } if (ret->methodState == METHOD_DONE) { ret->allowNotifications = FALSE; } return resp; }
static void eap_sake_process(struct eap_sm *sm, void *priv, struct wpabuf *respData) { struct eap_sake_data *data = priv; struct eap_sake_hdr *resp; u8 subtype; size_t len; const u8 *pos, *end; pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_SAKE, respData, &len); if (pos == NULL || len < sizeof(struct eap_sake_hdr)) return; resp = (struct eap_sake_hdr *) pos; end = pos + len; subtype = resp->subtype; pos = (u8 *) (resp + 1); wpa_hexdump(MSG_DEBUG, "EAP-SAKE: Received attributes", pos, end - pos); switch (subtype) { case EAP_SAKE_SUBTYPE_IDENTITY: eap_sake_process_identity(sm, data, respData, pos, end - pos); break; case EAP_SAKE_SUBTYPE_CHALLENGE: eap_sake_process_challenge(sm, data, respData, pos, end - pos); break; case EAP_SAKE_SUBTYPE_CONFIRM: eap_sake_process_confirm(sm, data, respData, pos, end - pos); break; case EAP_SAKE_SUBTYPE_AUTH_REJECT: eap_sake_process_auth_reject(sm, data, respData, pos, end - pos); break; } }
static Boolean eap_psk_check(struct eap_sm *sm, void *priv, struct wpabuf *respData) { struct eap_psk_data *data = priv; size_t len; u8 t; const u8 *pos; pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PSK, respData, &len); if (pos == NULL || len < 1) { wpa_printf(MSG_INFO, "EAP-PSK: Invalid frame"); return TRUE; } t = EAP_PSK_FLAGS_GET_T(*pos); wpa_printf(MSG_DEBUG, "EAP-PSK: received frame: T=%d", t); if (data->state == PSK_1 && t != 1) { wpa_printf(MSG_DEBUG, "EAP-PSK: Expected PSK-2 - " "ignore T=%d", t); return TRUE; } if (data->state == PSK_3 && t != 3) { wpa_printf(MSG_DEBUG, "EAP-PSK: Expected PSK-4 - " "ignore T=%d", t); return TRUE; } if ((t == 1 && len < sizeof(struct eap_psk_hdr_2)) || (t == 3 && len < sizeof(struct eap_psk_hdr_4))) { wpa_printf(MSG_DEBUG, "EAP-PSK: Too short frame"); return TRUE; } return FALSE; }
static void eap_md5_process(struct eap_sm *sm, void *priv, struct wpabuf *respData) { struct eap_md5_data *data = priv; const u8 *pos; size_t plen; u8 hash[CHAP_MD5_LEN], id; if (sm->user == NULL || sm->user->password == NULL || sm->user->password_hash) { wpa_printf(MSG_INFO, "EAP-MD5: Plaintext password not " "configured"); data->state = FAILURE; return; } pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_MD5, respData, &plen); if (pos == NULL || *pos != CHAP_MD5_LEN || plen < 1 + CHAP_MD5_LEN) { return; /* Should not happen - frame already validated */ } pos++; /* Skip response len */ wpa_hexdump(MSG_MSGDUMP, "EAP-MD5: Response", pos, CHAP_MD5_LEN); id = eap_get_id(respData); if (chap_md5(id, sm->user->password, sm->user->password_len, data->challenge, CHALLENGE_LEN, hash)) { wpa_printf(MSG_INFO, "EAP-MD5: CHAP MD5 operation failed"); data->state = FAILURE; return; } if (os_memcmp_const(hash, pos, CHAP_MD5_LEN) == 0) { wpa_printf(MSG_DEBUG, "EAP-MD5: Done - Success"); data->state = SUCCESS; } else { wpa_printf(MSG_DEBUG, "EAP-MD5: Done - Failure"); data->state = FAILURE; } }
static void eap_vendor_test_process(struct eap_sm *sm, void *priv, struct wpabuf *respData) { struct eap_vendor_test_data *data = priv; const u8 *pos; size_t len; pos = eap_hdr_validate(EAP_VENDOR_ID, EAP_VENDOR_TYPE, respData, &len); if (pos == NULL || len < 1) return; if (data->state == INIT) { if (*pos == 2) eap_vendor_test_state(data, CONFIRM); else eap_vendor_test_state(data, FAILURE); } else if (data->state == CONFIRM) { if (*pos == 4) eap_vendor_test_state(data, SUCCESS); else eap_vendor_test_state(data, FAILURE); } else eap_vendor_test_state(data, FAILURE); }
static void eap_wsc_process(struct eap_sm *sm, void *priv, struct wpabuf *respData) { struct eap_wsc_data *data = priv; const u8 *start, *pos, *end; size_t len; u8 op_code, flags; u16 message_length = 0; enum wps_process_res res; struct wpabuf tmpbuf; eloop_cancel_timeout(eap_wsc_ext_reg_timeout, sm, data); if (data->ext_reg_timeout) { eap_wsc_state(data, FAIL); return; } pos = eap_hdr_validate(EAP_VENDOR_WFA, EAP_VENDOR_TYPE_WSC, respData, &len); if (pos == NULL || len < 2) return; /* Should not happen; message already verified */ start = pos; end = start + len; op_code = *pos++; flags = *pos++; if (flags & WSC_FLAGS_LF) { if (end - pos < 2) { wpa_printf(MSG_DEBUG, "EAP-WSC: Message underflow"); return; } message_length = WPA_GET_BE16(pos); pos += 2; if (message_length < end - pos) { wpa_printf(MSG_DEBUG, "EAP-WSC: Invalid Message " "Length"); return; } } wpa_printf(MSG_DEBUG, "EAP-WSC: Received packet: Op-Code %d " "Flags 0x%x Message Length %d", op_code, flags, message_length); if (data->state == WAIT_FRAG_ACK) { if (op_code != WSC_FRAG_ACK) { wpa_printf(MSG_DEBUG, "EAP-WSC: Unexpected Op-Code %d " "in WAIT_FRAG_ACK state", op_code); eap_wsc_state(data, FAIL); return; } wpa_printf(MSG_DEBUG, "EAP-WSC: Fragment acknowledged"); eap_wsc_state(data, MESG); return; } if (op_code != WSC_ACK && op_code != WSC_NACK && op_code != WSC_MSG && op_code != WSC_Done) { wpa_printf(MSG_DEBUG, "EAP-WSC: Unexpected Op-Code %d", op_code); eap_wsc_state(data, FAIL); return; } if (data->in_buf && eap_wsc_process_cont(data, pos, end - pos, op_code) < 0) { eap_wsc_state(data, FAIL); return; } if (flags & WSC_FLAGS_MF) { if (eap_wsc_process_fragment(data, flags, op_code, message_length, pos, end - pos) < 0) eap_wsc_state(data, FAIL); else eap_wsc_state(data, FRAG_ACK); return; } if (data->in_buf == NULL) { /* Wrap unfragmented messages as wpabuf without extra copy */ wpabuf_set(&tmpbuf, pos, end - pos); data->in_buf = &tmpbuf; } res = wps_process_msg(data->wps, op_code, data->in_buf); switch (res) { case WPS_DONE: wpa_printf(MSG_DEBUG, "EAP-WSC: WPS processing completed " "successfully - report EAP failure"); eap_wsc_state(data, FAIL); break; case WPS_CONTINUE: eap_wsc_state(data, MESG); break; case WPS_FAILURE: wpa_printf(MSG_DEBUG, "EAP-WSC: WPS processing failed"); eap_wsc_state(data, FAIL); break; case WPS_PENDING: eap_wsc_state(data, MESG); sm->method_pending = METHOD_PENDING_WAIT; eloop_cancel_timeout(eap_wsc_ext_reg_timeout, sm, data); eloop_register_timeout(5, 0, eap_wsc_ext_reg_timeout, sm, data); break; } if (data->in_buf != &tmpbuf) wpabuf_free(data->in_buf); data->in_buf = NULL; }
static struct wpabuf * eap_pwd_process(struct eap_sm *sm, void *priv, struct eap_method_ret *ret, const struct wpabuf *reqData) { struct eap_pwd_data *data = priv; struct wpabuf *resp = NULL; const u8 *pos, *buf; size_t len; u16 tot_len = 0; u8 lm_exch; pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PWD, reqData, &len); if ((pos == NULL) || (len < 1)) { wpa_printf(MSG_DEBUG, "EAP-pwd: Got a frame but pos is %s and " "len is %d", pos == NULL ? "NULL" : "not NULL", (int) len); ret->ignore = TRUE; return NULL; } ret->ignore = FALSE; ret->methodState = METHOD_MAY_CONT; ret->decision = DECISION_FAIL; ret->allowNotifications = FALSE; lm_exch = *pos; pos++; /* skip over the bits and the exch */ len--; /* * we're fragmenting so send out the next fragment */ if (data->out_frag_pos) { /* * this should be an ACK */ if (len) wpa_printf(MSG_INFO, "Bad Response! Fragmenting but " "not an ACK"); wpa_printf(MSG_DEBUG, "EAP-pwd: Got an ACK for a fragment"); /* * check if there are going to be more fragments */ len = wpabuf_len(data->outbuf) - data->out_frag_pos; if ((len + EAP_PWD_HDR_SIZE) > data->mtu) { len = data->mtu - EAP_PWD_HDR_SIZE; EAP_PWD_SET_MORE_BIT(lm_exch); } resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PWD, EAP_PWD_HDR_SIZE + len, EAP_CODE_RESPONSE, eap_get_id(reqData)); if (resp == NULL) { wpa_printf(MSG_INFO, "Unable to allocate memory for " "next fragment!"); return NULL; } wpabuf_put_u8(resp, lm_exch); buf = wpabuf_head_u8(data->outbuf); wpabuf_put_data(resp, buf + data->out_frag_pos, len); data->out_frag_pos += len; /* * this is the last fragment so get rid of the out buffer */ if (data->out_frag_pos >= wpabuf_len(data->outbuf)) { wpabuf_free(data->outbuf); data->outbuf = NULL; data->out_frag_pos = 0; } wpa_printf(MSG_DEBUG, "EAP-pwd: Send %s fragment of %d bytes", data->out_frag_pos == 0 ? "last" : "next", (int) len); return resp; } /* * see if this is a fragment that needs buffering * * if it's the first fragment there'll be a length field */ if (EAP_PWD_GET_LENGTH_BIT(lm_exch)) { tot_len = WPA_GET_BE16(pos); wpa_printf(MSG_DEBUG, "EAP-pwd: Incoming fragments whose " "total length = %d", tot_len); data->inbuf = wpabuf_alloc(tot_len); if (data->inbuf == NULL) { wpa_printf(MSG_INFO, "Out of memory to buffer " "fragments!"); return NULL; } pos += sizeof(u16); len -= sizeof(u16); } /* * buffer and ACK the fragment */ if (EAP_PWD_GET_MORE_BIT(lm_exch)) { data->in_frag_pos += len; if (data->in_frag_pos > wpabuf_size(data->inbuf)) { wpa_printf(MSG_INFO, "EAP-pwd: Buffer overflow attack " "detected (%d vs. %d)!", (int) data->in_frag_pos, (int) wpabuf_len(data->inbuf)); wpabuf_free(data->inbuf); data->in_frag_pos = 0; return NULL; } wpabuf_put_data(data->inbuf, pos, len); resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PWD, EAP_PWD_HDR_SIZE, EAP_CODE_RESPONSE, eap_get_id(reqData)); if (resp != NULL) wpabuf_put_u8(resp, (EAP_PWD_GET_EXCHANGE(lm_exch))); wpa_printf(MSG_DEBUG, "EAP-pwd: ACKing a %d byte fragment", (int) len); return resp; } /* * we're buffering and this is the last fragment */ if (data->in_frag_pos) { wpabuf_put_data(data->inbuf, pos, len); wpa_printf(MSG_DEBUG, "EAP-pwd: Last fragment, %d bytes", (int) len); data->in_frag_pos += len; pos = wpabuf_head_u8(data->inbuf); len = data->in_frag_pos; } wpa_printf(MSG_DEBUG, "EAP-pwd: processing frame: exch %d, len %d", EAP_PWD_GET_EXCHANGE(lm_exch), (int) len); switch (EAP_PWD_GET_EXCHANGE(lm_exch)) { case EAP_PWD_OPCODE_ID_EXCH: eap_pwd_perform_id_exchange(sm, data, ret, reqData, pos, len); break; case EAP_PWD_OPCODE_COMMIT_EXCH: eap_pwd_perform_commit_exchange(sm, data, ret, reqData, pos, len); break; case EAP_PWD_OPCODE_CONFIRM_EXCH: eap_pwd_perform_confirm_exchange(sm, data, ret, reqData, pos, len); break; default: wpa_printf(MSG_INFO, "EAP-pwd: Ignoring message with unknown " "opcode %d", lm_exch); break; } /* * if we buffered the just processed input now's the time to free it */ if (data->in_frag_pos) { wpabuf_free(data->inbuf); data->in_frag_pos = 0; } if (data->outbuf == NULL) return NULL; /* generic failure */ /* * we have output! Do we need to fragment it? */ len = wpabuf_len(data->outbuf); if ((len + EAP_PWD_HDR_SIZE) > data->mtu) { resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PWD, data->mtu, EAP_CODE_RESPONSE, eap_get_id(reqData)); /* * if so it's the first so include a length field */ EAP_PWD_SET_LENGTH_BIT(lm_exch); EAP_PWD_SET_MORE_BIT(lm_exch); tot_len = len; /* * keep the packet at the MTU */ len = data->mtu - EAP_PWD_HDR_SIZE - sizeof(u16); wpa_printf(MSG_DEBUG, "EAP-pwd: Fragmenting output, total " "length = %d", tot_len); } else { resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PWD, EAP_PWD_HDR_SIZE + len, EAP_CODE_RESPONSE, eap_get_id(reqData)); } if (resp == NULL) return NULL; wpabuf_put_u8(resp, lm_exch); if (EAP_PWD_GET_LENGTH_BIT(lm_exch)) { wpabuf_put_be16(resp, tot_len); data->out_frag_pos += len; } buf = wpabuf_head_u8(data->outbuf); wpabuf_put_data(resp, buf, len); /* * if we're not fragmenting then there's no need to carry this around */ if (data->out_frag_pos == 0) { wpabuf_free(data->outbuf); data->outbuf = NULL; data->out_frag_pos = 0; } return resp; }
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_aka_process(struct eap_sm *sm, void *priv, struct eap_method_ret *ret, const struct wpabuf *reqData) { struct eap_aka_data *data = priv; const struct eap_hdr *req; u8 subtype, id; struct wpabuf *res; const u8 *pos; struct eap_sim_attrs attr; size_t len; wpa_hexdump_buf(MSG_DEBUG, "EAP-AKA: EAP data", reqData); if (eap_get_config_identity(sm, &len) == NULL) { wpa_printf(MSG_INFO, "EAP-AKA: Identity not configured"); eap_sm_request_identity(sm); ret->ignore = TRUE; return NULL; } pos = eap_hdr_validate(EAP_VENDOR_IETF, data->eap_method, reqData, &len); if (pos == NULL || len < 1) { ret->ignore = TRUE; return NULL; } req = wpabuf_head(reqData); id = req->identifier; len = be_to_host16(req->length); ret->ignore = FALSE; ret->methodState = METHOD_MAY_CONT; ret->decision = DECISION_FAIL; ret->allowNotifications = TRUE; subtype = *pos++; wpa_printf(MSG_DEBUG, "EAP-AKA: Subtype=%d", subtype); pos += 2; /* Reserved */ if (eap_sim_parse_attr(pos, wpabuf_head_u8(reqData) + len, &attr, data->eap_method == EAP_TYPE_AKA_PRIME ? 2 : 1, 0)) { res = eap_aka_client_error(data, id, EAP_AKA_UNABLE_TO_PROCESS_PACKET); goto done; } switch (subtype) { case EAP_AKA_SUBTYPE_IDENTITY: res = eap_aka_process_identity(sm, data, id, reqData, &attr); break; case EAP_AKA_SUBTYPE_CHALLENGE: res = eap_aka_process_challenge(sm, data, id, reqData, &attr); break; case EAP_AKA_SUBTYPE_NOTIFICATION: res = eap_aka_process_notification(sm, data, id, reqData, &attr); break; case EAP_AKA_SUBTYPE_REAUTHENTICATION: res = eap_aka_process_reauthentication(sm, data, id, reqData, &attr); break; case EAP_AKA_SUBTYPE_CLIENT_ERROR: wpa_printf(MSG_DEBUG, "EAP-AKA: subtype Client-Error"); res = eap_aka_client_error(data, id, EAP_AKA_UNABLE_TO_PROCESS_PACKET); break; default: wpa_printf(MSG_DEBUG, "EAP-AKA: Unknown subtype=%d", subtype); res = eap_aka_client_error(data, id, EAP_AKA_UNABLE_TO_PROCESS_PACKET); break; } done: if (data->state == FAILURE) { ret->decision = DECISION_FAIL; ret->methodState = METHOD_DONE; } else if (data->state == SUCCESS) { ret->decision = data->use_result_ind ? DECISION_UNCOND_SUCC : DECISION_COND_SUCC; /* * It is possible for the server to reply with AKA * Notification, so we must allow the method to continue and * not only accept EAP-Success at this point. */ ret->methodState = data->use_result_ind ? METHOD_DONE : METHOD_MAY_CONT; } else if (data->state == RESULT_FAILURE) ret->methodState = METHOD_CONT; else if (data->state == RESULT_SUCCESS) ret->methodState = METHOD_CONT; if (ret->methodState == METHOD_DONE) { ret->allowNotifications = FALSE; } return res; }
static void eap_pax_process_std_2(struct eap_sm *sm, struct eap_pax_data *data, struct wpabuf *respData) { struct eap_pax_hdr *resp; u8 mac[EAP_PAX_MAC_LEN], icvbuf[EAP_PAX_ICV_LEN]; const u8 *pos; size_t len, left; int i; if (data->state != PAX_STD_1) return; wpa_printf(MSG_DEBUG, "EAP-PAX: Received PAX_STD-2"); pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PAX, respData, &len); if (pos == NULL || len < sizeof(*resp) + EAP_PAX_ICV_LEN) return; resp = (struct eap_pax_hdr *) pos; pos = (u8 *) (resp + 1); left = len - sizeof(*resp); if (left < 2 + EAP_PAX_RAND_LEN || WPA_GET_BE16(pos) != EAP_PAX_RAND_LEN) { wpa_printf(MSG_INFO, "EAP-PAX: Too short PAX_STD-2 (B)"); return; } pos += 2; left -= 2; os_memcpy(data->rand.r.y, pos, EAP_PAX_RAND_LEN); wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: Y (client rand)", data->rand.r.y, EAP_PAX_RAND_LEN); pos += EAP_PAX_RAND_LEN; left -= EAP_PAX_RAND_LEN; if (left < 2 || (size_t) 2 + WPA_GET_BE16(pos) > left) { wpa_printf(MSG_INFO, "EAP-PAX: Too short PAX_STD-2 (CID)"); return; } data->cid_len = WPA_GET_BE16(pos); os_free(data->cid); data->cid = os_malloc(data->cid_len); if (data->cid == NULL) { wpa_printf(MSG_INFO, "EAP-PAX: Failed to allocate memory for " "CID"); return; } os_memcpy(data->cid, pos + 2, data->cid_len); pos += 2 + data->cid_len; left -= 2 + data->cid_len; wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-PAX: CID", (u8 *) data->cid, data->cid_len); if (left < 2 + EAP_PAX_MAC_LEN || WPA_GET_BE16(pos) != EAP_PAX_MAC_LEN) { wpa_printf(MSG_INFO, "EAP-PAX: Too short PAX_STD-2 (MAC_CK)"); return; } pos += 2; left -= 2; wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: MAC_CK(A, B, CID)", pos, EAP_PAX_MAC_LEN); if (eap_user_get(sm, (u8 *) data->cid, data->cid_len, 0) < 0) { wpa_hexdump_ascii(MSG_DEBUG, "EAP-PAX: unknown CID", (u8 *) data->cid, data->cid_len); data->state = FAILURE; return; } for (i = 0; i < EAP_MAX_METHODS && (sm->user->methods[i].vendor != EAP_VENDOR_IETF || sm->user->methods[i].method != EAP_TYPE_NONE); i++) { if (sm->user->methods[i].vendor == EAP_VENDOR_IETF && sm->user->methods[i].method == EAP_TYPE_PAX) break; } if (i >= EAP_MAX_METHODS || sm->user->methods[i].vendor != EAP_VENDOR_IETF || sm->user->methods[i].method != EAP_TYPE_PAX) { wpa_hexdump_ascii(MSG_DEBUG, "EAP-PAX: EAP-PAX not enabled for CID", (u8 *) data->cid, data->cid_len); data->state = FAILURE; return; } if (sm->user->password == NULL || sm->user->password_len != EAP_PAX_AK_LEN) { wpa_hexdump_ascii(MSG_DEBUG, "EAP-PAX: invalid password in " "user database for CID", (u8 *) data->cid, data->cid_len); data->state = FAILURE; return; } os_memcpy(data->ak, sm->user->password, EAP_PAX_AK_LEN); if (eap_pax_initial_key_derivation(data->mac_id, data->ak, data->rand.e, data->mk, data->ck, data->ick) < 0) { wpa_printf(MSG_INFO, "EAP-PAX: Failed to complete initial " "key derivation"); data->state = FAILURE; return; } data->keys_set = 1; eap_pax_mac(data->mac_id, data->ck, EAP_PAX_CK_LEN, data->rand.r.x, EAP_PAX_RAND_LEN, data->rand.r.y, EAP_PAX_RAND_LEN, (u8 *) data->cid, data->cid_len, mac); if (os_memcmp_const(mac, pos, EAP_PAX_MAC_LEN) != 0) { wpa_printf(MSG_INFO, "EAP-PAX: Invalid MAC_CK(A, B, CID) in " "PAX_STD-2"); wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: Expected MAC_CK(A, B, CID)", mac, EAP_PAX_MAC_LEN); data->state = FAILURE; return; } pos += EAP_PAX_MAC_LEN; left -= EAP_PAX_MAC_LEN; if (left < EAP_PAX_ICV_LEN) { wpa_printf(MSG_INFO, "EAP-PAX: Too short ICV (%lu) in " "PAX_STD-2", (unsigned long) left); return; } wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: ICV", pos, EAP_PAX_ICV_LEN); eap_pax_mac(data->mac_id, data->ick, EAP_PAX_ICK_LEN, wpabuf_head(respData), wpabuf_len(respData) - EAP_PAX_ICV_LEN, NULL, 0, NULL, 0, icvbuf); if (os_memcmp_const(icvbuf, pos, EAP_PAX_ICV_LEN) != 0) { wpa_printf(MSG_INFO, "EAP-PAX: Invalid ICV in PAX_STD-2"); wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: Expected ICV", icvbuf, EAP_PAX_ICV_LEN); return; } pos += EAP_PAX_ICV_LEN; left -= EAP_PAX_ICV_LEN; if (left > 0) { wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: ignored extra payload", pos, left); } data->state = PAX_STD_3; }
/** * eap_tlv_process - Process a received EAP-TLV message and generate a response * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() * @ret: Return values from EAP request validation and processing * @req: EAP-TLV request to be processed. The caller must have validated that * the buffer is large enough to contain full request (hdr->length bytes) and * that the EAP type is EAP_TYPE_TLV. * @resp: Buffer to return a pointer to the allocated response message. This * field should be initialized to %NULL before the call. The value will be * updated if a response message is generated. The caller is responsible for * freeing the allocated message. * @force_failure: Force negotiation to fail * Returns: 0 on success, -1 on failure */ static int eap_tlv_process(struct eap_sm *sm, struct eap_peap_data *data, struct eap_method_ret *ret, const struct wpabuf *req, struct wpabuf **resp, int force_failure) { size_t left, tlv_len; const u8 *pos; const u8 *result_tlv = NULL, *crypto_tlv = NULL; size_t result_tlv_len = 0, crypto_tlv_len = 0; int tlv_type, mandatory; /* Parse TLVs */ pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_TLV, req, &left); if (pos == NULL) return -1; wpa_hexdump(MSG_DEBUG, "EAP-TLV: Received TLVs", pos, left); while (left >= 4) { mandatory = !!(pos[0] & 0x80); tlv_type = WPA_GET_BE16(pos) & 0x3fff; pos += 2; tlv_len = WPA_GET_BE16(pos); pos += 2; left -= 4; if (tlv_len > left) { wpa_printf(MSG_DEBUG, "EAP-TLV: TLV underrun " "(tlv_len=%lu left=%lu)", (unsigned long) tlv_len, (unsigned long) left); return -1; } switch (tlv_type) { case EAP_TLV_RESULT_TLV: result_tlv = pos; result_tlv_len = tlv_len; break; case EAP_TLV_CRYPTO_BINDING_TLV: crypto_tlv = pos; crypto_tlv_len = tlv_len; break; default: wpa_printf(MSG_DEBUG, "EAP-TLV: Unsupported TLV Type " "%d%s", tlv_type, mandatory ? " (mandatory)" : ""); if (mandatory) { /* NAK TLV and ignore all TLVs in this packet. */ *resp = eap_tlv_build_nak(eap_get_id(req), tlv_type); return *resp == NULL ? -1 : 0; } /* Ignore this TLV, but process other TLVs */ break; } pos += tlv_len; left -= tlv_len; } if (left) { wpa_printf(MSG_DEBUG, "EAP-TLV: Last TLV too short in " "Request (left=%lu)", (unsigned long) left); return -1; } /* Process supported TLVs */ if (crypto_tlv && data->crypto_binding != NO_BINDING) { wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Cryptobinding TLV", crypto_tlv, crypto_tlv_len); if (eap_tlv_validate_cryptobinding(sm, data, crypto_tlv - 4, crypto_tlv_len + 4) < 0) { if (result_tlv == NULL) return -1; force_failure = 1; crypto_tlv = NULL; /* do not include Cryptobinding TLV * in response, if the received * cryptobinding was invalid. */ } } else if (!crypto_tlv && data->crypto_binding == REQUIRE_BINDING) { wpa_printf(MSG_DEBUG, "EAP-PEAP: No cryptobinding TLV"); return -1; } if (result_tlv) { int status, resp_status; wpa_hexdump(MSG_DEBUG, "EAP-TLV: Result TLV", result_tlv, result_tlv_len); if (result_tlv_len < 2) { wpa_printf(MSG_INFO, "EAP-TLV: Too short Result TLV " "(len=%lu)", (unsigned long) result_tlv_len); return -1; } status = WPA_GET_BE16(result_tlv); if (status == EAP_TLV_RESULT_SUCCESS) { wpa_printf(MSG_INFO, "EAP-TLV: TLV Result - Success " "- EAP-TLV/Phase2 Completed"); if (force_failure) { wpa_printf(MSG_INFO, "EAP-TLV: Earlier failure" " - force failed Phase 2"); resp_status = EAP_TLV_RESULT_FAILURE; ret->decision = DECISION_FAIL; } else { resp_status = EAP_TLV_RESULT_SUCCESS; ret->decision = DECISION_UNCOND_SUCC; } } else if (status == EAP_TLV_RESULT_FAILURE) { wpa_printf(MSG_INFO, "EAP-TLV: TLV Result - Failure"); resp_status = EAP_TLV_RESULT_FAILURE; ret->decision = DECISION_FAIL; } else { wpa_printf(MSG_INFO, "EAP-TLV: Unknown TLV Result " "Status %d", status); resp_status = EAP_TLV_RESULT_FAILURE; ret->decision = DECISION_FAIL; } ret->methodState = METHOD_DONE; *resp = eap_tlv_build_result(sm, data, crypto_tlv != NULL, eap_get_id(req), resp_status); } return 0; }
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); }
static void eap_tnc_process(struct eap_sm *sm, void *priv, struct wpabuf *respData) { struct eap_tnc_data *data = priv; const u8 *pos, *end; size_t len; u8 flags; u32 message_length = 0; struct wpabuf tmpbuf; pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_TNC, respData, &len); if (pos == NULL) return; /* Should not happen; message already verified */ end = pos + len; if (len == 1 && (data->state == DONE || data->state == FAIL)) { wpa_printf(MSG_DEBUG, "EAP-TNC: Peer acknowledged the last " "message"); return; } if (len == 0) { /* fragment ack */ flags = 0; } else flags = *pos++; if (flags & EAP_TNC_FLAGS_LENGTH_INCLUDED) { if (end - pos < 4) { wpa_printf(MSG_DEBUG, "EAP-TNC: Message underflow"); eap_tnc_set_state(data, FAIL); return; } message_length = WPA_GET_BE32(pos); pos += 4; if (message_length < (u32) (end - pos) || message_length > 75000) { wpa_printf(MSG_DEBUG, "EAP-TNC: Invalid Message " "Length (%d; %ld remaining in this msg)", message_length, (long) (end - pos)); eap_tnc_set_state(data, FAIL); return; } } wpa_printf(MSG_DEBUG, "EAP-TNC: Received packet: Flags 0x%x " "Message Length %u", flags, message_length); if (data->state == WAIT_FRAG_ACK) { if (len > 1) { wpa_printf(MSG_DEBUG, "EAP-TNC: Unexpected payload " "in WAIT_FRAG_ACK state"); eap_tnc_set_state(data, FAIL); return; } wpa_printf(MSG_DEBUG, "EAP-TNC: Fragment acknowledged"); eap_tnc_set_state(data, CONTINUE); return; } if (data->in_buf && eap_tnc_process_cont(data, pos, end - pos) < 0) { eap_tnc_set_state(data, FAIL); return; } if (flags & EAP_TNC_FLAGS_MORE_FRAGMENTS) { if (eap_tnc_process_fragment(data, flags, message_length, pos, end - pos) < 0) eap_tnc_set_state(data, FAIL); else eap_tnc_set_state(data, FRAG_ACK); return; } else if (data->state == FRAG_ACK) { wpa_printf(MSG_DEBUG, "EAP-TNC: All fragments received"); eap_tnc_set_state(data, CONTINUE); } if (data->in_buf == NULL) { /* Wrap unfragmented messages as wpabuf without extra copy */ wpabuf_set(&tmpbuf, pos, end - pos); data->in_buf = &tmpbuf; } wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-TNC: Received payload", wpabuf_head(data->in_buf), wpabuf_len(data->in_buf)); tncs_process(data, data->in_buf); if (data->in_buf != &tmpbuf) wpabuf_free(data->in_buf); data->in_buf = NULL; }
static u8 * eap_md5_process(struct eap_sm *sm, void *priv, struct eap_method_ret *ret, const u8 *reqData, size_t reqDataLen, size_t *respDataLen) { struct wpa_ssid *config = eap_get_config(sm); const struct eap_hdr *req; struct eap_hdr *resp; const u8 *pos, *challenge; u8 *rpos; size_t len, challenge_len; const u8 *addr[3]; size_t elen[3]; if (config == NULL || config->password == NULL) { wpa_printf(MSG_INFO, "EAP-MD5: Password not configured"); eap_sm_request_password(sm, config); ret->ignore = TRUE; return NULL; } pos = eap_hdr_validate(EAP_TYPE_MD5, reqData, reqDataLen, &len); if (pos == NULL) { ret->ignore = TRUE; return NULL; } req = (const struct eap_hdr *) reqData; challenge_len = *pos++; if (challenge_len == 0 || challenge_len > len - 1) { wpa_printf(MSG_INFO, "EAP-MD5: Invalid challenge " "(challenge_len=%lu len=%lu", (unsigned long) challenge_len, (unsigned long) len); ret->ignore = TRUE; return NULL; } ret->ignore = FALSE; challenge = pos; wpa_hexdump(MSG_MSGDUMP, "EAP-MD5: Challenge", challenge, challenge_len); wpa_printf(MSG_DEBUG, "EAP-MD5: generating Challenge Response"); ret->methodState = METHOD_DONE; ret->decision = DECISION_UNCOND_SUCC; ret->allowNotifications = TRUE; *respDataLen = sizeof(struct eap_hdr) + 1 + 1 + MD5_MAC_LEN; resp = malloc(*respDataLen); if (resp == NULL) return NULL; resp->code = EAP_CODE_RESPONSE; resp->identifier = req->identifier; resp->length = host_to_be16(*respDataLen); rpos = (u8 *) (resp + 1); *rpos++ = EAP_TYPE_MD5; *rpos++ = MD5_MAC_LEN; /* Value-Size */ addr[0] = &resp->identifier; elen[0] = 1; addr[1] = config->password; elen[1] = config->password_len; addr[2] = challenge; elen[2] = challenge_len; md5_vector(3, addr, elen, rpos); wpa_hexdump(MSG_MSGDUMP, "EAP-MD5: Response", rpos, MD5_MAC_LEN); return (u8 *) resp; }
static struct wpabuf * eap_tnc_process(struct eap_sm *sm, void *priv, struct eap_method_ret *ret, const struct wpabuf *reqData) { struct eap_tnc_data *data = priv; struct wpabuf *resp; const u8 *pos, *end; u8 *rpos, *rpos1; size_t len, rlen; size_t imc_len; char *start_buf, *end_buf; size_t start_len, end_len; int tncs_done = 0; u8 flags, id; u32 message_length = 0; struct wpabuf tmpbuf; pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_TNC, reqData, &len); if (pos == NULL) { wpa_printf(MSG_INFO, "EAP-TNC: Invalid frame (pos=%p len=%lu)", pos, (unsigned long) len); ret->ignore = TRUE; return NULL; } id = eap_get_id(reqData); end = pos + len; if (len == 0) flags = 0; /* fragment ack */ else flags = *pos++; if (len > 0 && (flags & EAP_TNC_VERSION_MASK) != EAP_TNC_VERSION) { wpa_printf(MSG_DEBUG, "EAP-TNC: Unsupported version %d", flags & EAP_TNC_VERSION_MASK); ret->ignore = TRUE; return NULL; } if (flags & EAP_TNC_FLAGS_LENGTH_INCLUDED) { if (end - pos < 4) { wpa_printf(MSG_DEBUG, "EAP-TNC: 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-TNC: Invalid Message " "Length (%d; %ld remaining in this msg)", message_length, (long) (end - pos)); ret->ignore = TRUE; return NULL; } } wpa_printf(MSG_DEBUG, "EAP-TNC: Received packet: Flags 0x%x " "Message Length %u", flags, message_length); if (data->state == WAIT_FRAG_ACK) { if (len > 1) { wpa_printf(MSG_DEBUG, "EAP-TNC: Unexpected payload in " "WAIT_FRAG_ACK state"); ret->ignore = TRUE; return NULL; } wpa_printf(MSG_DEBUG, "EAP-TNC: Fragment acknowledged"); data->state = PROC_MSG; return eap_tnc_build_msg(data, ret, id); } if (data->in_buf && eap_tnc_process_cont(data, pos, end - pos) < 0) { ret->ignore = TRUE; return NULL; } if (flags & EAP_TNC_FLAGS_MORE_FRAGMENTS) { return eap_tnc_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 (data->state == WAIT_START) { if (!(flags & EAP_TNC_FLAGS_START)) { wpa_printf(MSG_DEBUG, "EAP-TNC: Server did not use " "start flag in the first message"); ret->ignore = TRUE; goto fail; } tncc_init_connection(data->tncc); data->state = PROC_MSG; } else { enum tncc_process_res res; if (flags & EAP_TNC_FLAGS_START) { wpa_printf(MSG_DEBUG, "EAP-TNC: Server used start " "flag again"); ret->ignore = TRUE; goto fail; } res = tncc_process_if_tnccs(data->tncc, wpabuf_head(data->in_buf), wpabuf_len(data->in_buf)); switch (res) { case TNCCS_PROCESS_ERROR: ret->ignore = TRUE; goto fail; case TNCCS_PROCESS_OK_NO_RECOMMENDATION: case TNCCS_RECOMMENDATION_ERROR: wpa_printf(MSG_DEBUG, "EAP-TNC: No " "TNCCS-Recommendation received"); break; case TNCCS_RECOMMENDATION_ALLOW: wpa_msg(sm->msg_ctx, MSG_INFO, "TNC: Recommendation = allow"); tncs_done = 1; break; case TNCCS_RECOMMENDATION_NONE: wpa_msg(sm->msg_ctx, MSG_INFO, "TNC: Recommendation = none"); tncs_done = 1; break; case TNCCS_RECOMMENDATION_ISOLATE: wpa_msg(sm->msg_ctx, MSG_INFO, "TNC: Recommendation = isolate"); tncs_done = 1; break; } } if (data->in_buf != &tmpbuf) wpabuf_free(data->in_buf); data->in_buf = NULL; ret->ignore = FALSE; ret->methodState = METHOD_MAY_CONT; ret->decision = DECISION_UNCOND_SUCC; ret->allowNotifications = TRUE; if (data->out_buf) { data->state = PROC_MSG; return eap_tnc_build_msg(data, ret, id); } if (tncs_done) { resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TNC, 1, EAP_CODE_RESPONSE, eap_get_id(reqData)); if (resp == NULL) return NULL; wpabuf_put_u8(resp, EAP_TNC_VERSION); wpa_printf(MSG_DEBUG, "EAP-TNC: TNCS done - reply with an " "empty ACK message"); return resp; } imc_len = tncc_total_send_len(data->tncc); start_buf = tncc_if_tnccs_start(data->tncc); if (start_buf == NULL) return NULL; start_len = os_strlen(start_buf); end_buf = tncc_if_tnccs_end(); if (end_buf == NULL) { os_free(start_buf); return NULL; } end_len = os_strlen(end_buf); rlen = start_len + imc_len + end_len; resp = wpabuf_alloc(rlen); if (resp == NULL) { os_free(start_buf); os_free(end_buf); return NULL; } wpabuf_put_data(resp, start_buf, start_len); os_free(start_buf); rpos1 = wpabuf_put(resp, 0); rpos = tncc_copy_send_buf(data->tncc, rpos1); wpabuf_put(resp, rpos - rpos1); wpabuf_put_data(resp, end_buf, end_len); os_free(end_buf); wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-TNC: Response", wpabuf_head(resp), wpabuf_len(resp)); data->out_buf = resp; data->state = PROC_MSG; return eap_tnc_build_msg(data, ret, id); fail: if (data->in_buf == &tmpbuf) data->in_buf = NULL; return NULL; }
static int eap_peap_phase2_request(struct eap_sm *sm, struct eap_peap_data *data, struct eap_method_ret *ret, struct wpabuf *req, struct wpabuf **resp) { struct eap_hdr *hdr = wpabuf_mhead(req); size_t len = be_to_host16(hdr->length); u8 *pos; struct eap_method_ret iret; struct eap_peer_config *config = eap_get_config(sm); if (len <= sizeof(struct eap_hdr)) { wpa_printf(MSG_INFO, "EAP-PEAP: too short " "Phase 2 request (len=%lu)", (unsigned long) len); return -1; } pos = (u8 *) (hdr + 1); wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase 2 Request: type=%d", *pos); switch (*pos) { case EAP_TYPE_IDENTITY: *resp = eap_sm_buildIdentity(sm, hdr->identifier, 1); break; case EAP_TYPE_TLV: os_memset(&iret, 0, sizeof(iret)); if (eap_tlv_process(sm, data, &iret, req, resp, data->phase2_eap_started && !data->phase2_eap_success)) { ret->methodState = METHOD_DONE; ret->decision = DECISION_FAIL; return -1; } if (iret.methodState == METHOD_DONE || iret.methodState == METHOD_MAY_CONT) { ret->methodState = iret.methodState; ret->decision = iret.decision; data->phase2_success = 1; } break; case EAP_TYPE_EXPANDED: #ifdef EAP_TNC if (data->soh) { const u8 *epos; size_t eleft; epos = eap_hdr_validate(EAP_VENDOR_MICROSOFT, 0x21, req, &eleft); if (epos) { struct wpabuf *buf; wpa_printf(MSG_DEBUG, "EAP-PEAP: SoH EAP Extensions"); buf = tncc_process_soh_request(data->soh, epos, eleft); if (buf) { *resp = eap_msg_alloc( EAP_VENDOR_MICROSOFT, 0x21, wpabuf_len(buf), EAP_CODE_RESPONSE, hdr->identifier); if (*resp == NULL) { ret->methodState = METHOD_DONE; ret->decision = DECISION_FAIL; return -1; } wpabuf_put_buf(*resp, buf); wpabuf_free(buf); break; } } } #endif /* EAP_TNC */ /* fall through */ default: if (data->phase2_type.vendor == EAP_VENDOR_IETF && data->phase2_type.method == EAP_TYPE_NONE) { size_t i; for (i = 0; i < data->num_phase2_types; i++) { if (data->phase2_types[i].vendor != EAP_VENDOR_IETF || data->phase2_types[i].method != *pos) continue; data->phase2_type.vendor = data->phase2_types[i].vendor; data->phase2_type.method = data->phase2_types[i].method; wpa_printf(MSG_DEBUG, "EAP-PEAP: Selected " "Phase 2 EAP vendor %d method %d", data->phase2_type.vendor, data->phase2_type.method); break; } } if (*pos != data->phase2_type.method || *pos == EAP_TYPE_NONE) { if (eap_peer_tls_phase2_nak(data->phase2_types, data->num_phase2_types, hdr, resp)) return -1; return 0; } if (data->phase2_priv == NULL) { data->phase2_method = eap_peer_get_eap_method( data->phase2_type.vendor, data->phase2_type.method); if (data->phase2_method) { sm->init_phase2 = 1; data->phase2_priv = data->phase2_method->init(sm); sm->init_phase2 = 0; } } if (data->phase2_priv == NULL || data->phase2_method == NULL) { wpa_printf(MSG_INFO, "EAP-PEAP: failed to initialize " "Phase 2 EAP method %d", *pos); ret->methodState = METHOD_DONE; ret->decision = DECISION_FAIL; return -1; } data->phase2_eap_started = 1; os_memset(&iret, 0, sizeof(iret)); *resp = data->phase2_method->process(sm, data->phase2_priv, &iret, req); if ((iret.methodState == METHOD_DONE || iret.methodState == METHOD_MAY_CONT) && (iret.decision == DECISION_UNCOND_SUCC || iret.decision == DECISION_COND_SUCC)) { data->phase2_eap_success = 1; data->phase2_success = 1; } break; } if (*resp == NULL && (config->pending_req_identity || config->pending_req_password || config->pending_req_otp || config->pending_req_new_password)) { wpabuf_free(data->pending_phase2_req); data->pending_phase2_req = wpabuf_alloc_copy(hdr, len); } return 0; }
static Boolean eap_pax_check(struct eap_sm *sm, void *priv, struct wpabuf *respData) { struct eap_pax_data *data = priv; struct eap_pax_hdr *resp; const u8 *pos; size_t len, mlen; u8 icvbuf[EAP_PAX_ICV_LEN], *icv; pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PAX, respData, &len); if (pos == NULL || len < sizeof(*resp)) { wpa_printf(MSG_INFO, "EAP-PAX: Invalid frame"); return TRUE; } mlen = sizeof(struct eap_hdr) + 1 + len; resp = (struct eap_pax_hdr *) pos; wpa_printf(MSG_DEBUG, "EAP-PAX: received frame: op_code 0x%x " "flags 0x%x mac_id 0x%x dh_group_id 0x%x " "public_key_id 0x%x", resp->op_code, resp->flags, resp->mac_id, resp->dh_group_id, resp->public_key_id); wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: received payload", (u8 *) (resp + 1), len - sizeof(*resp) - EAP_PAX_ICV_LEN); if (data->state == PAX_STD_1 && resp->op_code != EAP_PAX_OP_STD_2) { wpa_printf(MSG_DEBUG, "EAP-PAX: Expected PAX_STD-2 - " "ignore op %d", resp->op_code); return TRUE; } if (data->state == PAX_STD_3 && resp->op_code != EAP_PAX_OP_ACK) { wpa_printf(MSG_DEBUG, "EAP-PAX: Expected PAX-ACK - " "ignore op %d", resp->op_code); return TRUE; } if (resp->op_code != EAP_PAX_OP_STD_2 && resp->op_code != EAP_PAX_OP_ACK) { wpa_printf(MSG_DEBUG, "EAP-PAX: Unknown op_code 0x%x", resp->op_code); } if (data->mac_id != resp->mac_id) { wpa_printf(MSG_DEBUG, "EAP-PAX: Expected MAC ID 0x%x, " "received 0x%x", data->mac_id, resp->mac_id); return TRUE; } if (resp->dh_group_id != EAP_PAX_DH_GROUP_NONE) { wpa_printf(MSG_INFO, "EAP-PAX: Expected DH Group ID 0x%x, " "received 0x%x", EAP_PAX_DH_GROUP_NONE, resp->dh_group_id); return TRUE; } if (resp->public_key_id != EAP_PAX_PUBLIC_KEY_NONE) { wpa_printf(MSG_INFO, "EAP-PAX: Expected Public Key ID 0x%x, " "received 0x%x", EAP_PAX_PUBLIC_KEY_NONE, resp->public_key_id); return TRUE; } if (resp->flags & EAP_PAX_FLAGS_MF) { /* TODO: add support for reassembling fragments */ wpa_printf(MSG_INFO, "EAP-PAX: fragmentation not supported"); return TRUE; } if (resp->flags & EAP_PAX_FLAGS_CE) { wpa_printf(MSG_INFO, "EAP-PAX: Unexpected CE flag"); return TRUE; } if (data->keys_set) { if (len - sizeof(*resp) < EAP_PAX_ICV_LEN) { wpa_printf(MSG_INFO, "EAP-PAX: No ICV in the packet"); return TRUE; } icv = wpabuf_mhead_u8(respData) + mlen - EAP_PAX_ICV_LEN; wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: ICV", icv, EAP_PAX_ICV_LEN); eap_pax_mac(data->mac_id, data->ick, EAP_PAX_ICK_LEN, wpabuf_mhead(respData), wpabuf_len(respData) - EAP_PAX_ICV_LEN, NULL, 0, NULL, 0, icvbuf); if (os_memcmp_const(icvbuf, icv, EAP_PAX_ICV_LEN) != 0) { wpa_printf(MSG_INFO, "EAP-PAX: Invalid ICV"); wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: Expected ICV", icvbuf, EAP_PAX_ICV_LEN); return TRUE; } } return FALSE; }