static u8 * eap_otp_process(struct eap_sm *sm, void *priv, struct eap_method_ret *ret, const u8 *reqData, size_t reqDataLen, size_t *respDataLen) { const struct eap_hdr *req; struct eap_hdr *resp; const u8 *pos, *password; u8 *rpos; size_t password_len, len; int otp; pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_OTP, reqData, reqDataLen, &len); if (pos == NULL) { ret->ignore = TRUE; return NULL; } req = (const struct eap_hdr *) reqData; wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-OTP: Request message", pos, len); password = eap_get_config_otp(sm, &password_len); if (password) otp = 1; else { password = eap_get_config_password(sm, &password_len); otp = 0; } if (password == NULL) { wpa_printf(MSG_INFO, "EAP-OTP: Password not configured"); eap_sm_request_otp(sm, (const char *) pos, len); ret->ignore = TRUE; return NULL; } ret->ignore = FALSE; ret->methodState = METHOD_DONE; ret->decision = DECISION_COND_SUCC; ret->allowNotifications = FALSE; resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_OTP, respDataLen, password_len, EAP_CODE_RESPONSE, req->identifier, &rpos); if (resp == NULL) return NULL; os_memcpy(rpos, password, password_len); wpa_hexdump_ascii_key(MSG_MSGDUMP, "EAP-OTP: Response", password, password_len); if (otp) { wpa_printf(MSG_DEBUG, "EAP-OTP: Forgetting used password"); eap_clear_config_otp(sm); } return (u8 *) resp; }
static void * eap_pwd_init(struct eap_sm *sm) { struct eap_pwd_data *data; const u8 *identity, *password; size_t identity_len, password_len; password = eap_get_config_password(sm, &password_len); if (password == NULL) { wpa_printf(MSG_INFO, "EAP-PWD: No password configured!"); return NULL; } identity = eap_get_config_identity(sm, &identity_len); if (identity == NULL) { wpa_printf(MSG_INFO, "EAP-PWD: No identity configured!"); return NULL; } if ((data = os_zalloc(sizeof(*data))) == NULL) { wpa_printf(MSG_INFO, "EAP-PWD: memory allocation data fail"); return NULL; } if ((data->bnctx = BN_CTX_new()) == NULL) { wpa_printf(MSG_INFO, "EAP-PWD: bn context allocation fail"); os_free(data); return NULL; } if ((data->id_peer = os_malloc(identity_len)) == NULL) { wpa_printf(MSG_INFO, "EAP-PWD: memory allocation id fail"); BN_CTX_free(data->bnctx); os_free(data); return NULL; } os_memcpy(data->id_peer, identity, identity_len); data->id_peer_len = identity_len; if ((data->password = os_malloc(password_len)) == NULL) { wpa_printf(MSG_INFO, "EAP-PWD: memory allocation psk fail"); BN_CTX_free(data->bnctx); os_free(data->id_peer); os_free(data); return NULL; } os_memcpy(data->password, password, password_len); data->password_len = password_len; data->out_frag_pos = data->in_frag_pos = 0; data->inbuf = data->outbuf = NULL; data->mtu = 1020; /* default from RFC 5931, make it configurable! */ data->state = PWD_ID_Req; return data; }
/** * eap_mschapv2_process - Process an EAP-MSCHAPv2 challenge message * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() * @data: Pointer to private EAP method data from eap_mschapv2_init() * @ret: Return values from EAP request validation and processing * @req: Pointer to EAP-MSCHAPv2 header from the request * @req_len: Length of the EAP-MSCHAPv2 data * @id: EAP identifier used in the request * Returns: Pointer to allocated EAP response packet (eapRespData) or %NULL if * no reply available */ static struct wpabuf * eap_mschapv2_challenge( struct eap_sm *sm, struct eap_mschapv2_data *data, struct eap_method_ret *ret, const struct eap_mschapv2_hdr *req, size_t req_len, u8 id) { size_t len, challenge_len; const u8 *pos, *challenge; if (eap_get_config_identity(sm, &len) == NULL || eap_get_config_password(sm, &len) == NULL) return NULL; wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Received challenge"); if (req_len < sizeof(*req) + 1) { wpa_printf(MSG_INFO, "EAP-MSCHAPV2: Too short challenge data " "(len %lu)", (unsigned long) req_len); ret->ignore = TRUE; return NULL; } pos = (const u8 *) (req + 1); challenge_len = *pos++; len = req_len - sizeof(*req) - 1; if (challenge_len != MSCHAPV2_CHAL_LEN) { wpa_printf(MSG_INFO, "EAP-MSCHAPV2: Invalid challenge length " "%lu", (unsigned long) challenge_len); ret->ignore = TRUE; return NULL; } if (len < challenge_len) { wpa_printf(MSG_INFO, "EAP-MSCHAPV2: Too short challenge" " packet: len=%lu challenge_len=%lu", (unsigned long) len, (unsigned long) challenge_len); ret->ignore = TRUE; return NULL; } if (data->passwd_change_challenge_valid) { wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Using challenge from the " "failure message"); challenge = data->passwd_change_challenge; } else challenge = pos; pos += challenge_len; len -= challenge_len; wpa_hexdump_ascii(MSG_DEBUG, "EAP-MSCHAPV2: Authentication Servername", pos, len); ret->ignore = FALSE; ret->methodState = METHOD_MAY_CONT; ret->decision = DECISION_FAIL; ret->allowNotifications = TRUE; return eap_mschapv2_challenge_reply(sm, data, id, req->mschapv2_id, challenge); }
static struct wpabuf * eap_leap_process(struct eap_sm *sm, void *priv, struct eap_method_ret *ret, const struct wpabuf *reqData) { const struct eap_hdr *eap; size_t password_len; const u8 *password; password = eap_get_config_password(sm, &password_len); if (password == NULL) { wpa_printf(MSG_INFO, "EAP-LEAP: Password not configured"); eap_sm_request_password(sm); ret->ignore = TRUE; return NULL; } /* * LEAP needs to be able to handle EAP-Success frame which does not * include Type field. Consequently, eap_hdr_validate() cannot be used * here. This validation will be done separately for EAP-Request and * EAP-Response frames. */ eap = wpabuf_head(reqData); if (wpabuf_len(reqData) < sizeof(*eap) || be_to_host16(eap->length) > wpabuf_len(reqData)) { wpa_printf(MSG_INFO, "EAP-LEAP: Invalid frame"); ret->ignore = TRUE; return NULL; } ret->ignore = FALSE; ret->allowNotifications = TRUE; ret->methodState = METHOD_MAY_CONT; ret->decision = DECISION_FAIL; sm->leap_done = FALSE; switch (eap->code) { case EAP_CODE_REQUEST: return eap_leap_process_request(sm, priv, ret, reqData); case EAP_CODE_SUCCESS: return eap_leap_process_success(sm, priv, ret, reqData); case EAP_CODE_RESPONSE: return eap_leap_process_response(sm, priv, ret, reqData); default: wpa_printf(MSG_INFO, "EAP-LEAP: Unexpected EAP code (%d) - " "ignored", eap->code); ret->ignore = TRUE; return NULL; } }
static void * eap_gpsk_init(struct eap_sm *sm) { struct eap_gpsk_data *data; const u8 *identity, *password; size_t identity_len, password_len; const char *phase1; password = eap_get_config_password(sm, &password_len); if (password == NULL) { wpa_printf(MSG_INFO, "EAP-GPSK: No key (password) configured"); return NULL; } data = os_zalloc(sizeof(*data)); if (data == NULL) return NULL; data->state = GPSK_1; identity = eap_get_config_identity(sm, &identity_len); if (identity) { data->id_peer = os_malloc(identity_len); if (data->id_peer == NULL) { eap_gpsk_deinit(sm, data); return NULL; } os_memcpy(data->id_peer, identity, identity_len); data->id_peer_len = identity_len; } phase1 = eap_get_config_phase1(sm); if (phase1) { const char *pos; pos = os_strstr(phase1, "cipher="); if (pos) { data->forced_cipher = atoi(pos + 7); wpa_printf(MSG_DEBUG, "EAP-GPSK: Forced cipher %u", data->forced_cipher); } } data->psk = os_malloc(password_len); if (data->psk == NULL) { eap_gpsk_deinit(sm, data); return NULL; } os_memcpy(data->psk, password, password_len); data->psk_len = password_len; return data; }
static void * eap_ikev2_init(struct eap_sm *sm) { struct eap_ikev2_data *data; const u8 *identity, *password; size_t identity_len, password_len; int fragment_size; identity = eap_get_config_identity(sm, &identity_len); if (identity == NULL) { wpa_printf(MSG_INFO, "EAP-IKEV2: No identity available"); return NULL; } data = os_zalloc(sizeof(*data)); if (data == NULL) return NULL; data->state = WAIT_START; fragment_size = eap_get_config_fragment_size(sm); if (fragment_size <= 0) data->fragment_size = IKEV2_FRAGMENT_SIZE; else data->fragment_size = fragment_size; data->ikev2.state = SA_INIT; data->ikev2.peer_auth = PEER_AUTH_SECRET; data->ikev2.key_pad = (u8 *) os_strdup("Key Pad for EAP-IKEv2"); if (data->ikev2.key_pad == NULL) goto failed; data->ikev2.key_pad_len = 21; data->ikev2.IDr = os_malloc(identity_len); if (data->ikev2.IDr == NULL) goto failed; os_memcpy(data->ikev2.IDr, identity, identity_len); data->ikev2.IDr_len = identity_len; password = eap_get_config_password(sm, &password_len); if (password) { data->ikev2.shared_secret = os_malloc(password_len); if (data->ikev2.shared_secret == NULL) goto failed; os_memcpy(data->ikev2.shared_secret, password, password_len); data->ikev2.shared_secret_len = password_len; } return data; failed: ikev2_responder_deinit(&data->ikev2); os_free(data); return NULL; }
static u8 * eap_leap_process(struct eap_sm *sm, void *priv, struct eap_method_ret *ret, const u8 *reqData, size_t reqDataLen, size_t *respDataLen) { const struct eap_hdr *eap; size_t len, password_len; const u8 *password; password = eap_get_config_password(sm, &password_len); if (password == NULL) { wpa_printf(MSG_INFO, "EAP-LEAP: Password not configured"); eap_sm_request_password(sm); ret->ignore = TRUE; return NULL; } eap = (const struct eap_hdr *) reqData; if (reqDataLen < sizeof(*eap) || (len = be_to_host16(eap->length)) > reqDataLen) { wpa_printf(MSG_INFO, "EAP-LEAP: Invalid frame"); ret->ignore = TRUE; return NULL; } ret->ignore = FALSE; ret->allowNotifications = TRUE; ret->methodState = METHOD_MAY_CONT; ret->decision = DECISION_FAIL; sm->leap_done = FALSE; switch (eap->code) { case EAP_CODE_REQUEST: return eap_leap_process_request(sm, priv, ret, reqData, len, respDataLen); case EAP_CODE_SUCCESS: return eap_leap_process_success(sm, priv, ret, reqData, respDataLen); case EAP_CODE_RESPONSE: return eap_leap_process_response(sm, priv, ret, reqData, len); default: wpa_printf(MSG_INFO, "EAP-LEAP: Unexpected EAP code (%d) - " "ignored", eap->code); ret->ignore = TRUE; return NULL; } }
static u8 * eap_leap_getKey(struct eap_sm *sm, void *priv, size_t *len) { struct eap_leap_data *data = priv; u8 *key, pw_hash_hash[16], pw_hash[16]; const u8 *addr[5], *password; size_t elen[5], password_len; if (data->state != LEAP_DONE) return NULL; password = eap_get_config_password(sm, &password_len); if (password == NULL) return NULL; key = os_malloc(LEAP_KEY_LEN); if (key == NULL) return NULL; nt_password_hash(password, password_len, pw_hash); hash_nt_password_hash(pw_hash, pw_hash_hash); wpa_hexdump_key(MSG_DEBUG, "EAP-LEAP: pw_hash_hash", pw_hash_hash, 16); wpa_hexdump(MSG_DEBUG, "EAP-LEAP: peer_challenge", data->peer_challenge, LEAP_CHALLENGE_LEN); wpa_hexdump(MSG_DEBUG, "EAP-LEAP: peer_response", data->peer_response, LEAP_RESPONSE_LEN); wpa_hexdump(MSG_DEBUG, "EAP-LEAP: ap_challenge", data->ap_challenge, LEAP_CHALLENGE_LEN); wpa_hexdump(MSG_DEBUG, "EAP-LEAP: ap_response", data->ap_response, LEAP_RESPONSE_LEN); addr[0] = pw_hash_hash; elen[0] = 16; addr[1] = data->ap_challenge; elen[1] = LEAP_CHALLENGE_LEN; addr[2] = data->ap_response; elen[2] = LEAP_RESPONSE_LEN; addr[3] = data->peer_challenge; elen[3] = LEAP_CHALLENGE_LEN; addr[4] = data->peer_response; elen[4] = LEAP_RESPONSE_LEN; md5_vector(5, addr, elen, key); wpa_hexdump_key(MSG_DEBUG, "EAP-LEAP: master key", key, LEAP_KEY_LEN); *len = LEAP_KEY_LEN; return key; }
static struct wpabuf * eap_mschapv2_challenge( struct eap_sm *sm, struct eap_mschapv2_data *data, struct eap_method_ret *ret, const struct eap_mschapv2_hdr *req, size_t req_len, u8 id) { size_t len, challenge_len; const u8 *pos, *challenge; if (eap_get_config_identity(sm, &len) == NULL || eap_get_config_password(sm, &len) == NULL) return NULL; if (req_len < sizeof(*req) + 1) { ret->ignore = true; return NULL; } pos = (const u8 *)(req + 1); challenge_len = *pos++; len = req_len - sizeof(*req) - 1; if (challenge_len != MSCHAPV2_CHAL_LEN) { ret->ignore = true; return NULL; } if (len < challenge_len) { ret->ignore = true; return NULL; } if (data->passwd_change_challenge_valid) challenge = data->passwd_change_challenge; else challenge = pos; pos += challenge_len; len -= challenge_len; ret->ignore = false; ret->methodState = METHOD_MAY_CONT; ret->decision = DECISION_FAIL; ret->allowNotifications = true; return eap_mschapv2_challenge_reply(sm, data, id, req->mschapv2_id, challenge); }
static int eap_mschapv2_check_config(struct eap_sm *sm) { size_t len; if (eap_get_config_identity(sm, &len) == NULL) { wpa_printf(MSG_INFO, "EAP-MSCHAPV2: Identity not configured"); eap_sm_request_identity(sm); return -1; } if (eap_get_config_password(sm, &len) == NULL) { wpa_printf(MSG_INFO, "EAP-MSCHAPV2: Password not configured"); eap_sm_request_password(sm); return -1; } return 0; }
static void * eap_psk_init(struct eap_sm *sm) { struct eap_psk_data *data; const u8 *identity, *password; size_t identity_len, password_len; password = eap_get_config_password(sm, &password_len); if (!password || password_len != 16) { wpa_printf(MSG_INFO, "EAP-PSK: 16-octet pre-shared key not " "configured"); return NULL; } data = os_zalloc(sizeof(*data)); if (data == NULL) return NULL; if (eap_psk_key_setup(password, data->ak, data->kdk)) { os_free(data); return NULL; } wpa_hexdump_key(MSG_DEBUG, "EAP-PSK: AK", data->ak, EAP_PSK_AK_LEN); wpa_hexdump_key(MSG_DEBUG, "EAP-PSK: KDK", data->kdk, EAP_PSK_KDK_LEN); data->state = PSK_INIT; identity = eap_get_config_identity(sm, &identity_len); if (identity) { data->id_p = os_malloc(identity_len); if (data->id_p) os_memcpy(data->id_p, identity, identity_len); data->id_p_len = identity_len; } if (data->id_p == NULL) { wpa_printf(MSG_INFO, "EAP-PSK: could not get own identity"); os_free(data); return NULL; } return data; }
static void * eap_gpsk_init(struct eap_sm *sm) { struct eap_gpsk_data *data; const u8 *identity, *password; size_t identity_len, password_len; password = eap_get_config_password(sm, &password_len); if (password == NULL) { wpa_printf(MSG_INFO, "EAP-GPSK: No key (password) configured"); return NULL; } data = os_zalloc(sizeof(*data)); if (data == NULL) return NULL; data->state = GPSK_1; identity = eap_get_config_identity(sm, &identity_len); if (identity) { data->id_peer = os_malloc(identity_len); if (data->id_peer == NULL) { eap_gpsk_deinit(sm, data); return NULL; } os_memcpy(data->id_peer, identity, identity_len); data->id_peer_len = identity_len; } data->psk = os_malloc(password_len); if (data->psk == NULL) { eap_gpsk_deinit(sm, data); return NULL; } os_memcpy(data->psk, password, password_len); data->psk_len = password_len; return data; }
static void * eap_pax_init(struct eap_sm *sm) { struct eap_pax_data *data; const u8 *identity, *password; size_t identity_len, password_len; identity = eap_get_config_identity(sm, &identity_len); password = eap_get_config_password(sm, &password_len); if (!identity || !password) { wpa_printf(MSG_INFO, "EAP-PAX: CID (nai) or key (password) " "not configured"); return NULL; } if (password_len != EAP_PAX_AK_LEN) { wpa_printf(MSG_INFO, "EAP-PAX: Invalid PSK length"); return NULL; } data = os_zalloc(sizeof(*data)); if (data == NULL) return NULL; data->state = PAX_INIT; data->cid = os_malloc(identity_len); if (data->cid == NULL) { eap_pax_deinit(sm, data); return NULL; } os_memcpy(data->cid, identity, identity_len); data->cid_len = identity_len; os_memcpy(data->ak, password, EAP_PAX_AK_LEN); return data; }
static void * eap_sake_init(struct eap_sm *sm) { struct eap_sake_data *data; const u8 *identity, *password; size_t identity_len, password_len; password = eap_get_config_password(sm, &password_len); if (!password || password_len != 2 * EAP_SAKE_ROOT_SECRET_LEN) { wpa_printf(MSG_INFO, "EAP-SAKE: No key of correct length " "configured"); return NULL; } data = os_zalloc(sizeof(*data)); if (data == NULL) return NULL; data->state = IDENTITY; identity = eap_get_config_identity(sm, &identity_len); if (identity) { data->peerid = os_malloc(identity_len); if (data->peerid == NULL) { eap_sake_deinit(sm, data); return NULL; } os_memcpy(data->peerid, identity, identity_len); data->peerid_len = identity_len; } os_memcpy(data->root_secret_a, password, EAP_SAKE_ROOT_SECRET_LEN); os_memcpy(data->root_secret_b, password + EAP_SAKE_ROOT_SECRET_LEN, EAP_SAKE_ROOT_SECRET_LEN); return data; }
static struct wpabuf * eap_gtc_process(struct eap_sm *sm, void *priv, struct eap_method_ret *ret, const struct wpabuf *reqData) { struct eap_gtc_data *data = priv; struct wpabuf *resp; const u8 *pos, *password, *identity; size_t password_len, identity_len, len, plen; int otp; u8 id; pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_GTC, reqData, &len); if (pos == NULL) { ret->ignore = TRUE; return NULL; } id = eap_get_id(reqData); wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-GTC: Request message", pos, len); if (data->prefix && (len < 10 || os_memcmp(pos, "CHALLENGE=", 10) != 0)) { wpa_printf(MSG_DEBUG, "EAP-GTC: Challenge did not start with " "expected prefix"); wpa_printf(MSG_DEBUG, "Unrecoverable error - Restarting\n"); /* Send an empty response in order to allow tunneled * acknowledgement of the failure. This will also cover the * error case which seems to use EAP-MSCHAPv2 like error * reporting with EAP-GTC inside EAP-FAST tunnel. */ resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_GTC, 0, EAP_CODE_RESPONSE, id); return resp; } password = eap_get_config_otp(sm, &password_len); if (password) otp = 1; else { password = eap_get_config_password(sm, &password_len); otp = 0; } if (password == NULL) { wpa_printf(MSG_INFO, "EAP-GTC: Password not configured"); eap_sm_request_otp(sm, (const char *) pos, len); ret->ignore = TRUE; return NULL; } ret->ignore = FALSE; ret->methodState = data->prefix ? METHOD_MAY_CONT : METHOD_DONE; ret->decision = DECISION_COND_SUCC; ret->allowNotifications = FALSE; plen = password_len; identity = eap_get_config_identity(sm, &identity_len); if (identity == NULL) return NULL; if (data->prefix) plen += 9 + identity_len + 1; resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_GTC, plen, EAP_CODE_RESPONSE, id); if (resp == NULL) return NULL; if (data->prefix) { wpabuf_put_data(resp, "RESPONSE=", 9); wpabuf_put_data(resp, identity, identity_len); wpabuf_put_u8(resp, '\0'); } wpabuf_put_data(resp, password, password_len); wpa_hexdump_ascii_key(MSG_MSGDUMP, "EAP-GTC: Response", wpabuf_head_u8(resp) + sizeof(struct eap_hdr) + 1, plen); if (otp) { wpa_printf(MSG_DEBUG, "EAP-GTC: Forgetting used password"); eap_clear_config_otp(sm); } return resp; }
static void * eap_eke_init(struct eap_sm *sm) { struct eap_eke_data *data; const u8 *identity, *password; size_t identity_len, password_len; const char *phase1; password = eap_get_config_password(sm, &password_len); if (!password) { wpa_printf(MSG_INFO, "EAP-EKE: No password configured"); return NULL; } data = os_zalloc(sizeof(*data)); if (data == NULL) return NULL; eap_eke_state(data, IDENTITY); identity = eap_get_config_identity(sm, &identity_len); if (identity) { data->peerid = os_malloc(identity_len); if (data->peerid == NULL) { eap_eke_deinit(sm, data); return NULL; } os_memcpy(data->peerid, identity, identity_len); data->peerid_len = identity_len; } phase1 = eap_get_config_phase1(sm); if (phase1) { const char *pos; pos = os_strstr(phase1, "dhgroup="); if (pos) { data->dhgroup = atoi(pos + 8); wpa_printf(MSG_DEBUG, "EAP-EKE: Forced dhgroup %u", data->dhgroup); } pos = os_strstr(phase1, "encr="); if (pos) { data->encr = atoi(pos + 5); wpa_printf(MSG_DEBUG, "EAP-EKE: Forced encr %u", data->encr); } pos = os_strstr(phase1, "prf="); if (pos) { data->prf = atoi(pos + 4); wpa_printf(MSG_DEBUG, "EAP-EKE: Forced prf %u", data->prf); } pos = os_strstr(phase1, "mac="); if (pos) { data->mac = atoi(pos + 4); wpa_printf(MSG_DEBUG, "EAP-EKE: Forced mac %u", data->mac); } } return data; }
static u8 * eap_leap_process_request(struct eap_sm *sm, void *priv, struct eap_method_ret *ret, const u8 *reqData, size_t reqDataLen, size_t *respDataLen) { struct eap_leap_data *data = priv; const struct eap_hdr *req; struct eap_hdr *resp; const u8 *pos, *challenge, *identity, *password; u8 challenge_len, *rpos; size_t identity_len, password_len; wpa_printf(MSG_DEBUG, "EAP-LEAP: Processing EAP-Request"); identity = eap_get_config_identity(sm, &identity_len); password = eap_get_config_password(sm, &password_len); if (identity == NULL || password == NULL) return NULL; req = (const struct eap_hdr *) reqData; pos = (const u8 *) (req + 1); if (reqDataLen < sizeof(*req) + 4 || *pos != EAP_TYPE_LEAP) { wpa_printf(MSG_INFO, "EAP-LEAP: Invalid EAP-Request frame"); ret->ignore = TRUE; return NULL; } pos++; if (*pos != LEAP_VERSION) { wpa_printf(MSG_WARNING, "EAP-LEAP: Unsupported LEAP version " "%d", *pos); ret->ignore = TRUE; return NULL; } pos++; pos++; /* skip unused byte */ challenge_len = *pos++; if (challenge_len != LEAP_CHALLENGE_LEN || challenge_len > reqDataLen - sizeof(*req) - 4) { wpa_printf(MSG_INFO, "EAP-LEAP: Invalid challenge " "(challenge_len=%d reqDataLen=%lu)", challenge_len, (unsigned long) reqDataLen); ret->ignore = TRUE; return NULL; } challenge = pos; os_memcpy(data->peer_challenge, challenge, LEAP_CHALLENGE_LEN); wpa_hexdump(MSG_MSGDUMP, "EAP-LEAP: Challenge from AP", challenge, LEAP_CHALLENGE_LEN); wpa_printf(MSG_DEBUG, "EAP-LEAP: Generating Challenge Response"); resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_LEAP, respDataLen, 3 + LEAP_RESPONSE_LEN + identity_len, EAP_CODE_RESPONSE, req->identifier, &rpos); if (resp == NULL) return NULL; *rpos++ = LEAP_VERSION; *rpos++ = 0; /* unused */ *rpos++ = LEAP_RESPONSE_LEN; nt_challenge_response(challenge, password, password_len, rpos); os_memcpy(data->peer_response, rpos, LEAP_RESPONSE_LEN); wpa_hexdump(MSG_MSGDUMP, "EAP-LEAP: Response", rpos, LEAP_RESPONSE_LEN); rpos += LEAP_RESPONSE_LEN; os_memcpy(rpos, identity, identity_len); data->state = LEAP_WAIT_SUCCESS; return (u8 *) resp; }
static u8 * eap_leap_process_response(struct eap_sm *sm, void *priv, struct eap_method_ret *ret, const u8 *reqData, size_t reqDataLen) { struct eap_leap_data *data = priv; const struct eap_hdr *resp; const u8 *pos, *password; u8 response_len, pw_hash[16], pw_hash_hash[16], expected[LEAP_RESPONSE_LEN]; size_t password_len; wpa_printf(MSG_DEBUG, "EAP-LEAP: Processing EAP-Response"); password = eap_get_config_password(sm, &password_len); if (password == NULL) return NULL; resp = (const struct eap_hdr *) reqData; pos = (const u8 *) (resp + 1); if (reqDataLen < sizeof(*resp) + 4 || *pos != EAP_TYPE_LEAP) { wpa_printf(MSG_INFO, "EAP-LEAP: Invalid EAP-Response frame"); ret->ignore = TRUE; return NULL; } pos++; if (*pos != LEAP_VERSION) { wpa_printf(MSG_WARNING, "EAP-LEAP: Unsupported LEAP version " "%d", *pos); ret->ignore = TRUE; return NULL; } pos++; pos++; /* skip unused byte */ response_len = *pos++; if (response_len != LEAP_RESPONSE_LEN || response_len > reqDataLen - sizeof(*resp) - 4) { wpa_printf(MSG_INFO, "EAP-LEAP: Invalid response " "(response_len=%d reqDataLen=%lu)", response_len, (unsigned long) reqDataLen); ret->ignore = TRUE; return NULL; } wpa_hexdump(MSG_DEBUG, "EAP-LEAP: Response from AP", pos, LEAP_RESPONSE_LEN); os_memcpy(data->ap_response, pos, LEAP_RESPONSE_LEN); nt_password_hash(password, password_len, pw_hash); hash_nt_password_hash(pw_hash, pw_hash_hash); challenge_response(data->ap_challenge, pw_hash_hash, expected); ret->methodState = METHOD_DONE; ret->allowNotifications = FALSE; if (os_memcmp(pos, expected, LEAP_RESPONSE_LEN) != 0) { wpa_printf(MSG_WARNING, "EAP-LEAP: AP sent an invalid " "response - authentication failed"); wpa_hexdump(MSG_DEBUG, "EAP-LEAP: Expected response from AP", expected, LEAP_RESPONSE_LEN); ret->decision = DECISION_FAIL; return NULL; } ret->decision = DECISION_UNCOND_SUCC; /* LEAP is somewhat odd method since it sends EAP-Success in the middle * of the authentication. Use special variable to transit EAP state * machine to SUCCESS state. */ sm->leap_done = TRUE; data->state = LEAP_DONE; /* No more authentication messages expected; AP will send EAPOL-Key * frames if encryption is enabled. */ return NULL; }
static struct wpabuf * eap_md5_process(struct eap_sm *sm, void *priv, struct eap_method_ret *ret, const struct wpabuf *reqData) { struct wpabuf *resp; const u8 *pos, *challenge, *password; u8 *rpos, id; size_t len, challenge_len, password_len; password = eap_get_config_password(sm, &password_len); if (password == NULL) { wpa_printf(MSG_INFO, "EAP-MD5: Password not configured"); eap_sm_request_password(sm); ret->ignore = TRUE; return NULL; } pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_MD5, reqData, &len); if (pos == NULL || len == 0) { wpa_printf(MSG_INFO, "EAP-MD5: Invalid frame (pos=%p len=%lu)", pos, (unsigned long) len); ret->ignore = TRUE; return NULL; } /* * CHAP Challenge: * Value-Size (1 octet) | Value(Challenge) | Name(optional) */ 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_COND_SUCC; ret->allowNotifications = TRUE; resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_MD5, 1 + CHAP_MD5_LEN, EAP_CODE_RESPONSE, eap_get_id(reqData)); if (resp == NULL) return NULL; /* * CHAP Response: * Value-Size (1 octet) | Value(Response) | Name(optional) */ wpabuf_put_u8(resp, CHAP_MD5_LEN); id = eap_get_id(resp); rpos = wpabuf_put(resp, CHAP_MD5_LEN); chap_md5(id, password, password_len, challenge, challenge_len, rpos); wpa_hexdump(MSG_MSGDUMP, "EAP-MD5: Response", rpos, CHAP_MD5_LEN); return resp; }
static u8 * eap_mschapv2_challenge(struct eap_sm *sm, struct eap_mschapv2_data *data, struct eap_method_ret *ret, const struct eap_mschapv2_hdr *req, size_t *respDataLen) { u8 *challenge, *peer_challenge, *pos; int ms_len; size_t i, len, challenge_len, username_len, identity_len, password_len; struct eap_mschapv2_hdr *resp; u8 password_hash[16], password_hash_hash[16]; const u8 *username, *identity, *password; identity = eap_get_config_identity(sm, &identity_len); password = eap_get_config_password(sm, &password_len); if (identity == NULL || password == NULL) return NULL; /* MSCHAPv2 does not include optional domain name in the * challenge-response calculation, so remove domain prefix * (if present). */ username = identity; username_len = identity_len; for (i = 0; i < username_len; i++) { if (username[i] == '\\') { username_len -= i + 1; username += i + 1; break; } } wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Received challenge"); len = be_to_host16(req->length); pos = (u8 *) (req + 1); challenge_len = *pos++; if (challenge_len != 16) { wpa_printf(MSG_INFO, "EAP-MSCHAPV2: Invalid challenge length " "%lu", (unsigned long) challenge_len); ret->ignore = TRUE; return NULL; } if (len < 10 || len - 10 < challenge_len) { wpa_printf(MSG_INFO, "EAP-MSCHAPV2: Too short challenge" " packet: len=%lu challenge_len=%lu", (unsigned long) len, (unsigned long) challenge_len); ret->ignore = TRUE; return NULL; } if (data->passwd_change_challenge_valid) { wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Using challenge from the " "failure message"); challenge = data->passwd_change_challenge; } else challenge = pos; pos += challenge_len; wpa_hexdump_ascii(MSG_DEBUG, "EAP-MSCHAPV2: Authentication Servername", pos, len - challenge_len - 10); ret->ignore = FALSE; ret->methodState = METHOD_MAY_CONT; ret->decision = DECISION_FAIL; ret->allowNotifications = TRUE; wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Generating Challenge Response"); *respDataLen = sizeof(*resp) + 1 + MSCHAPV2_RESP_LEN + identity_len; resp = wpa_zalloc(*respDataLen); if (resp == NULL) return NULL; resp->code = EAP_CODE_RESPONSE; resp->identifier = req->identifier; resp->length = host_to_be16(*respDataLen); resp->type = EAP_TYPE_MSCHAPV2; resp->op_code = MSCHAPV2_OP_RESPONSE; resp->mschapv2_id = req->mschapv2_id; if (data->prev_error) { /* * TODO: this does not seem to be enough when processing two * or more failure messages. IAS did not increment mschapv2_id * in its own packets, but it seemed to expect the peer to * increment this for all packets(?). */ resp->mschapv2_id++; } ms_len = *respDataLen - 5; WPA_PUT_BE16(resp->ms_length, ms_len); pos = (u8 *) (resp + 1); *pos++ = MSCHAPV2_RESP_LEN; /* Value-Size */ /* Response */ peer_challenge = pos; if (data->peer_challenge) { wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: peer_challenge generated " "in Phase 1"); peer_challenge = data->peer_challenge; } else if (hostapd_get_rand(peer_challenge, 16)) { free(resp); return NULL; } pos += 16; pos += 8; /* Reserved, must be zero */ if (data->auth_challenge) { wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: auth_challenge generated " "in Phase 1"); challenge = data->auth_challenge; } wpa_hexdump(MSG_DEBUG, "EAP-MSCHAPV2: auth_challenge", challenge, 16); wpa_hexdump(MSG_DEBUG, "EAP-MSCHAPV2: peer_challenge", peer_challenge, 16); wpa_hexdump_ascii(MSG_DEBUG, "EAP-MSCHAPV2: username", username, username_len); wpa_hexdump_ascii_key(MSG_DEBUG, "EAP-MSCHAPV2: password", password, password_len); generate_nt_response(challenge, peer_challenge, username, username_len, password, password_len, pos); wpa_hexdump(MSG_DEBUG, "EAP-MSCHAPV2: response", pos, 24); /* Authenticator response is not really needed yet, but calculate it * here so that challenges need not be saved. */ generate_authenticator_response(password, password_len, peer_challenge, challenge, username, username_len, pos, data->auth_response); data->auth_response_valid = 1; /* Likewise, generate master_key here since we have the needed data * available. */ nt_password_hash(password, password_len, password_hash); hash_nt_password_hash(password_hash, password_hash_hash); get_master_key(password_hash_hash, pos /* nt_response */, data->master_key); data->master_key_valid = 1; pos += 24; pos++; /* Flag / reserved, must be zero */ memcpy(pos, identity, identity_len); wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: TX identifier %d mschapv2_id %d " "(response)", resp->identifier, resp->mschapv2_id); return (u8 *) resp; }
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) { const struct eap_hdr *req; struct eap_hdr *resp; const u8 *pos, *challenge, *password; u8 *rpos; size_t len, challenge_len, password_len; const u8 *addr[3]; size_t elen[3]; password = eap_get_config_password(sm, &password_len); if (password == NULL) { wpa_printf(MSG_INFO, "EAP-MD5: Password not configured"); eap_sm_request_password(sm); ret->ignore = TRUE; return NULL; } pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_MD5, reqData, reqDataLen, &len); if (pos == NULL || len == 0) { wpa_printf(MSG_INFO, "EAP-MD5: Invalid frame (pos=%p len=%lu)", pos, (unsigned long) len); ret->ignore = TRUE; return NULL; } /* * CHAP Challenge: * Value-Size (1 octet) | Value(Challenge) | Name(optional) */ 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; resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_MD5, respDataLen, 1 + MD5_MAC_LEN, EAP_CODE_RESPONSE, req->identifier, &rpos); if (resp == NULL) return NULL; /* * CHAP Response: * Value-Size (1 octet) | Value(Response) | Name(optional) */ *rpos++ = MD5_MAC_LEN; addr[0] = &resp->identifier; elen[0] = 1; addr[1] = password; elen[1] = 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 u8 * eap_mschapv2_process(struct eap_sm *sm, void *priv, struct eap_method_ret *ret, const u8 *reqData, size_t reqDataLen, size_t *respDataLen) { struct eap_mschapv2_data *data = priv; struct wpa_ssid *config = eap_get_config(sm); const struct eap_mschapv2_hdr *req; int using_prev_challenge = 0; const u8 *pos; size_t ms_len, len; if (eap_get_config_identity(sm, &len) == NULL) { wpa_printf(MSG_INFO, "EAP-MSCHAPV2: Identity not configured"); eap_sm_request_identity(sm); ret->ignore = TRUE; return NULL; } if (eap_get_config_password(sm, &len) == NULL) { wpa_printf(MSG_INFO, "EAP-MSCHAPV2: Password not configured"); eap_sm_request_password(sm); ret->ignore = TRUE; return NULL; } if (config->mschapv2_retry && data->prev_challenge && data->prev_error == ERROR_AUTHENTICATION_FAILURE) { wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Replacing pending packet " "with the previous challenge"); reqData = data->prev_challenge; reqDataLen = data->prev_challenge_len; using_prev_challenge = 1; config->mschapv2_retry = 0; } pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2, reqData, reqDataLen, &len); if (pos == NULL || len < 5) { ret->ignore = TRUE; return NULL; } req = (const struct eap_mschapv2_hdr *) reqData; len = be_to_host16(req->length); ms_len = WPA_GET_BE16(req->ms_length); if (ms_len != len - 5) { wpa_printf(MSG_INFO, "EAP-MSCHAPV2: Invalid header: len=%lu " "ms_len=%lu", (unsigned long) len, (unsigned long) ms_len); if (sm->workaround) { /* Some authentication servers use invalid ms_len, * ignore it for interoperability. */ wpa_printf(MSG_INFO, "EAP-MSCHAPV2: workaround, ignore" " invalid ms_len"); } else { ret->ignore = TRUE; return NULL; } } wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: RX identifier %d mschapv2_id %d", req->identifier, req->mschapv2_id); switch (req->op_code) { case MSCHAPV2_OP_CHALLENGE: if (!using_prev_challenge) { free(data->prev_challenge); data->prev_challenge = malloc(len); if (data->prev_challenge) { data->prev_challenge_len = len; memcpy(data->prev_challenge, reqData, len); } } return eap_mschapv2_challenge(sm, data, ret, req, respDataLen); case MSCHAPV2_OP_SUCCESS: return eap_mschapv2_success(sm, data, ret, req, respDataLen); case MSCHAPV2_OP_FAILURE: return eap_mschapv2_failure(sm, data, ret, req, respDataLen); default: wpa_printf(MSG_INFO, "EAP-MSCHAPV2: Unknown op %d - ignored", req->op_code); ret->ignore = TRUE; return NULL; } }
static int eap_ttls_phase2_request(struct eap_sm *sm, struct eap_ttls_data *data, struct eap_method_ret *ret, const struct eap_hdr *req, struct eap_hdr *hdr, u8 **resp, size_t *resp_len) { int res = 0; size_t len; if (data->phase2_type == EAP_TTLS_PHASE2_MSCHAPV2 || data->phase2_type == EAP_TTLS_PHASE2_MSCHAP || data->phase2_type == EAP_TTLS_PHASE2_PAP || data->phase2_type == EAP_TTLS_PHASE2_CHAP) { if (eap_get_config_identity(sm, &len) == NULL) { wpa_printf(MSG_INFO, "EAP-TTLS: Identity not configured"); eap_sm_request_identity(sm); if (eap_get_config_password(sm, &len) == NULL) eap_sm_request_password(sm); return 0; } if (eap_get_config_password(sm, &len) == NULL) { wpa_printf(MSG_INFO, "EAP-TTLS: Password not configured"); eap_sm_request_password(sm); return 0; } } switch (data->phase2_type) { case EAP_TTLS_PHASE2_EAP: res = eap_ttls_phase2_request_eap(sm, data, ret, hdr, resp, resp_len); break; case EAP_TTLS_PHASE2_MSCHAPV2: res = eap_ttls_phase2_request_mschapv2(sm, data, ret, resp, resp_len); break; case EAP_TTLS_PHASE2_MSCHAP: res = eap_ttls_phase2_request_mschap(sm, data, ret, resp, resp_len); break; case EAP_TTLS_PHASE2_PAP: res = eap_ttls_phase2_request_pap(sm, data, ret, resp, resp_len); break; case EAP_TTLS_PHASE2_CHAP: res = eap_ttls_phase2_request_chap(sm, data, ret, resp, resp_len); break; default: wpa_printf(MSG_ERROR, "EAP-TTLS: Phase 2 - Unknown"); res = -1; break; } if (res < 0) { ret->methodState = METHOD_DONE; ret->decision = DECISION_FAIL; } return res; }
static struct wpabuf * eap_eke_process_commit(struct eap_sm *sm, struct eap_eke_data *data, struct eap_method_ret *ret, const struct wpabuf *reqData, const u8 *payload, size_t payload_len) { struct wpabuf *resp; const u8 *pos, *end, *dhcomp; size_t prot_len; u8 *rpos; u8 key[EAP_EKE_MAX_KEY_LEN]; u8 pub[EAP_EKE_MAX_DH_LEN]; const u8 *password; size_t password_len; u8 id = eap_get_id(reqData); if (data->state != COMMIT) { wpa_printf(MSG_DEBUG, "EAP-EKE: EAP-EKE-Commit/Request received in unexpected state (%d)", data->state); return eap_eke_build_fail(data, ret, id, EAP_EKE_FAIL_PROTO_ERROR); } wpa_printf(MSG_DEBUG, "EAP-EKE: Received EAP-EKE-Commit/Request"); password = eap_get_config_password(sm, &password_len); if (password == NULL) { wpa_printf(MSG_INFO, "EAP-EKE: No password configured!"); return eap_eke_build_fail(data, ret, id, EAP_EKE_FAIL_PASSWD_NOT_FOUND); } pos = payload; end = payload + payload_len; if (pos + data->sess.dhcomp_len > end) { wpa_printf(MSG_DEBUG, "EAP-EKE: Too short EAP-EKE-Commit"); return eap_eke_build_fail(data, ret, id, EAP_EKE_FAIL_PROTO_ERROR); } wpa_hexdump(MSG_DEBUG, "EAP-EKE: DHComponent_S", pos, data->sess.dhcomp_len); dhcomp = pos; pos += data->sess.dhcomp_len; wpa_hexdump(MSG_DEBUG, "EAP-EKE: CBValue", pos, end - pos); /* * temp = prf(0+, password) * key = prf+(temp, ID_S | ID_P) */ if (eap_eke_derive_key(&data->sess, password, password_len, data->serverid, data->serverid_len, data->peerid, data->peerid_len, key) < 0) { wpa_printf(MSG_INFO, "EAP-EKE: Failed to derive key"); return eap_eke_build_fail(data, ret, id, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR); } /* * y_p = g ^ x_p (mod p) * x_p = random number 2 .. p-1 */ if (eap_eke_dh_init(data->sess.dhgroup, data->dh_priv, pub) < 0) { wpa_printf(MSG_INFO, "EAP-EKE: Failed to initialize DH"); os_memset(key, 0, sizeof(key)); return eap_eke_build_fail(data, ret, id, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR); } if (eap_eke_shared_secret(&data->sess, key, data->dh_priv, dhcomp) < 0) { wpa_printf(MSG_INFO, "EAP-EKE: Failed to derive shared secret"); os_memset(key, 0, sizeof(key)); return eap_eke_build_fail(data, ret, id, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR); } if (eap_eke_derive_ke_ki(&data->sess, data->serverid, data->serverid_len, data->peerid, data->peerid_len) < 0) { wpa_printf(MSG_INFO, "EAP-EKE: Failed to derive Ke/Ki"); os_memset(key, 0, sizeof(key)); return eap_eke_build_fail(data, ret, id, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR); } wpa_printf(MSG_DEBUG, "EAP-EKE: Sending EAP-EKE-Commit/Response"); resp = eap_eke_build_msg(data, id, data->sess.dhcomp_len + data->sess.pnonce_len, EAP_EKE_COMMIT); if (resp == NULL) { os_memset(key, 0, sizeof(key)); return eap_eke_build_fail(data, ret, id, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR); } /* DHComponent_P = Encr(key, y_p) */ rpos = wpabuf_put(resp, data->sess.dhcomp_len); if (eap_eke_dhcomp(&data->sess, key, pub, rpos) < 0) { wpabuf_free(resp); wpa_printf(MSG_INFO, "EAP-EKE: Failed to build DHComponent_P"); os_memset(key, 0, sizeof(key)); return eap_eke_build_fail(data, ret, id, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR); } os_memset(key, 0, sizeof(key)); wpa_hexdump(MSG_DEBUG, "EAP-EKE: DHComponent_P", rpos, data->sess.dhcomp_len); if (random_get_bytes(data->nonce_p, data->sess.nonce_len)) { wpabuf_free(resp); return eap_eke_build_fail(data, ret, id, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR); } wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: Nonce_P", data->nonce_p, data->sess.nonce_len); prot_len = wpabuf_tailroom(resp); if (eap_eke_prot(&data->sess, data->nonce_p, data->sess.nonce_len, wpabuf_put(resp, 0), &prot_len) < 0) { wpabuf_free(resp); return eap_eke_build_fail(data, ret, id, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR); } wpa_hexdump(MSG_DEBUG, "EAP-EKE: PNonce_P", wpabuf_put(resp, 0), prot_len); wpabuf_put(resp, prot_len); /* TODO: CBValue */ if (wpabuf_resize(&data->msgs, wpabuf_len(reqData) + wpabuf_len(resp)) < 0) { wpabuf_free(resp); return eap_eke_build_fail(data, ret, id, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR); } wpabuf_put_buf(data->msgs, reqData); wpabuf_put_buf(data->msgs, resp); eap_eke_state(data, CONFIRM); return resp; }