134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt/*
234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt * EAP peer method: EAP-EKE (RFC 6124)
334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt * Copyright (c) 2013, Jouni Malinen <j@w1.fi>
434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt *
534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt * This software may be distributed under the terms of the BSD license.
634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt * See README for more details.
734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt */
834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt#include "includes.h"
1034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
1134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt#include "common.h"
1234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt#include "crypto/random.h"
1334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt#include "eap_peer/eap_i.h"
1434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt#include "eap_common/eap_eke_common.h"
1534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
1634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidtstruct eap_eke_data {
1734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	enum {
1834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		IDENTITY, COMMIT, CONFIRM, SUCCESS, FAILURE
1934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	} state;
2034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	u8 msk[EAP_MSK_LEN];
2134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	u8 emsk[EAP_EMSK_LEN];
2234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	u8 *peerid;
2334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	size_t peerid_len;
2434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	u8 *serverid;
2534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	size_t serverid_len;
2634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	u8 dh_priv[EAP_EKE_MAX_DH_LEN];
2734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	struct eap_eke_session sess;
2834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	u8 nonce_p[EAP_EKE_MAX_NONCE_LEN];
2934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	u8 nonce_s[EAP_EKE_MAX_NONCE_LEN];
3034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	struct wpabuf *msgs;
31fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	u8 dhgroup; /* forced DH group or 0 to allow all supported */
32fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	u8 encr; /* forced encryption algorithm or 0 to allow all supported */
33fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	u8 prf; /* forced PRF or 0 to allow all supported */
34fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	u8 mac; /* forced MAC or 0 to allow all supported */
3534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt};
3634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
3734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
3834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidtstatic const char * eap_eke_state_txt(int state)
3934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt{
4034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	switch (state) {
4134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	case IDENTITY:
4234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		return "IDENTITY";
4334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	case COMMIT:
4434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		return "COMMIT";
4534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	case CONFIRM:
4634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		return "CONFIRM";
4734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	case SUCCESS:
4834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		return "SUCCESS";
4934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	case FAILURE:
5034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		return "FAILURE";
5134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	default:
5234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		return "?";
5334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	}
5434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt}
5534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
5634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
5734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidtstatic void eap_eke_state(struct eap_eke_data *data, int state)
5834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt{
5934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	wpa_printf(MSG_DEBUG, "EAP-EKE: %s -> %s",
6034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		   eap_eke_state_txt(data->state), eap_eke_state_txt(state));
6134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	data->state = state;
6234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt}
6334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
6434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
6534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidtstatic void eap_eke_deinit(struct eap_sm *sm, void *priv);
6634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
6734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
6834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidtstatic void * eap_eke_init(struct eap_sm *sm)
6934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt{
7034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	struct eap_eke_data *data;
7134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	const u8 *identity, *password;
7234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	size_t identity_len, password_len;
73fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	const char *phase1;
7434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
7534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	password = eap_get_config_password(sm, &password_len);
7634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	if (!password) {
7734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		wpa_printf(MSG_INFO, "EAP-EKE: No password configured");
7834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		return NULL;
7934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	}
8034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
8134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	data = os_zalloc(sizeof(*data));
8234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	if (data == NULL)
8334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		return NULL;
8434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	eap_eke_state(data, IDENTITY);
8534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
8634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	identity = eap_get_config_identity(sm, &identity_len);
8734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	if (identity) {
8834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		data->peerid = os_malloc(identity_len);
8934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		if (data->peerid == NULL) {
9034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt			eap_eke_deinit(sm, data);
9134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt			return NULL;
9234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		}
9334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		os_memcpy(data->peerid, identity, identity_len);
9434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		data->peerid_len = identity_len;
9534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	}
9634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
97fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	phase1 = eap_get_config_phase1(sm);
98fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	if (phase1) {
99fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		const char *pos;
100fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt
101fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		pos = os_strstr(phase1, "dhgroup=");
102fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		if (pos) {
103fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt			data->dhgroup = atoi(pos + 8);
104fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt			wpa_printf(MSG_DEBUG, "EAP-EKE: Forced dhgroup %u",
105fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt				   data->dhgroup);
106fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		}
107fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt
108fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		pos = os_strstr(phase1, "encr=");
109fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		if (pos) {
110fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt			data->encr = atoi(pos + 5);
111fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt			wpa_printf(MSG_DEBUG, "EAP-EKE: Forced encr %u",
112fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt				   data->encr);
113fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		}
114fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt
115fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		pos = os_strstr(phase1, "prf=");
116fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		if (pos) {
117fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt			data->prf = atoi(pos + 4);
118fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt			wpa_printf(MSG_DEBUG, "EAP-EKE: Forced prf %u",
119fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt				   data->prf);
120fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		}
121fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt
122fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		pos = os_strstr(phase1, "mac=");
123fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		if (pos) {
124fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt			data->mac = atoi(pos + 4);
125fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt			wpa_printf(MSG_DEBUG, "EAP-EKE: Forced mac %u",
126fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt				   data->mac);
127fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		}
128fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	}
129fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt
13034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	return data;
13134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt}
13234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
13334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
13434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidtstatic void eap_eke_deinit(struct eap_sm *sm, void *priv)
13534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt{
13634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	struct eap_eke_data *data = priv;
13734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	eap_eke_session_clean(&data->sess);
13834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	os_free(data->serverid);
13934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	os_free(data->peerid);
14034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	wpabuf_free(data->msgs);
141c28170251eb54dbf64a9074a07fee377587425b2Dmitry Shmidt	bin_clear_free(data, sizeof(*data));
14234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt}
14334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
14434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
14534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidtstatic struct wpabuf * eap_eke_build_msg(struct eap_eke_data *data, int id,
14634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt					 size_t length, u8 eke_exch)
14734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt{
14834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	struct wpabuf *msg;
14934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	size_t plen;
15034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
15134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	plen = 1 + length;
15234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
15334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	msg = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_EKE, plen,
15434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt			    EAP_CODE_RESPONSE, id);
15534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	if (msg == NULL) {
15634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		wpa_printf(MSG_ERROR, "EAP-EKE: Failed to allocate memory");
15734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		return NULL;
15834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	}
15934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
16034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	wpabuf_put_u8(msg, eke_exch);
16134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
16234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	return msg;
16334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt}
16434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
16534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
16634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidtstatic int eap_eke_supp_dhgroup(u8 dhgroup)
16734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt{
16834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	return dhgroup == EAP_EKE_DHGROUP_EKE_2 ||
16934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		dhgroup == EAP_EKE_DHGROUP_EKE_5 ||
17034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		dhgroup == EAP_EKE_DHGROUP_EKE_14 ||
17134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		dhgroup == EAP_EKE_DHGROUP_EKE_15 ||
17234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		dhgroup == EAP_EKE_DHGROUP_EKE_16;
17334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt}
17434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
17534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
17634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidtstatic int eap_eke_supp_encr(u8 encr)
17734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt{
17834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	return encr == EAP_EKE_ENCR_AES128_CBC;
17934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt}
18034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
18134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
18234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidtstatic int eap_eke_supp_prf(u8 prf)
18334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt{
18434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	return prf == EAP_EKE_PRF_HMAC_SHA1 ||
18534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		prf == EAP_EKE_PRF_HMAC_SHA2_256;
18634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt}
18734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
18834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
18934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidtstatic int eap_eke_supp_mac(u8 mac)
19034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt{
19134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	return mac == EAP_EKE_MAC_HMAC_SHA1 ||
19234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		mac == EAP_EKE_MAC_HMAC_SHA2_256;
19334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt}
19434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
19534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
19634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidtstatic struct wpabuf * eap_eke_build_fail(struct eap_eke_data *data,
19734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt					  struct eap_method_ret *ret,
19834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt					  const struct wpabuf *reqData,
19934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt					  u32 failure_code)
20034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt{
20134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	struct wpabuf *resp;
20234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
20334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	wpa_printf(MSG_DEBUG, "EAP-EKE: Sending EAP-EKE-Failure/Response - code=0x%x",
20434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		   failure_code);
20534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
20634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	resp = eap_eke_build_msg(data, eap_get_id(reqData), 4, EAP_EKE_FAILURE);
20734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	if (resp)
20834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		wpabuf_put_be32(resp, failure_code);
20934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
21034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	os_memset(data->dh_priv, 0, sizeof(data->dh_priv));
21134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	eap_eke_session_clean(&data->sess);
21234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
21334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	eap_eke_state(data, FAILURE);
21434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	ret->methodState = METHOD_DONE;
21534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	ret->decision = DECISION_FAIL;
21634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	ret->allowNotifications = FALSE;
21734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
21834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	return resp;
21934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt}
22034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
22134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
22234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidtstatic struct wpabuf * eap_eke_process_id(struct eap_eke_data *data,
22334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt					  struct eap_method_ret *ret,
22434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt					  const struct wpabuf *reqData,
22534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt					  const u8 *payload,
22634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt					  size_t payload_len)
22734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt{
22834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	struct wpabuf *resp;
22934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	unsigned num_prop, i;
23034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	const u8 *pos, *end;
23134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	const u8 *prop = NULL;
23234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	u8 idtype;
23334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
23434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	if (data->state != IDENTITY) {
23534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		return eap_eke_build_fail(data, ret, reqData,
23634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt					  EAP_EKE_FAIL_PROTO_ERROR);
23734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	}
23834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
23934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	wpa_printf(MSG_DEBUG, "EAP-EKE: Received EAP-EKE-ID/Request");
24034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
24134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	if (payload_len < 2 + 4) {
24234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		wpa_printf(MSG_DEBUG, "EAP-EKE: Too short ID/Request Data");
24334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		return eap_eke_build_fail(data, ret, reqData,
24434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt					  EAP_EKE_FAIL_PROTO_ERROR);
24534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	}
24634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
24734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	pos = payload;
24834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	end = payload + payload_len;
24934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
25034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	num_prop = *pos++;
25134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	pos++; /* Ignore Reserved field */
25234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
25334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	if (pos + num_prop * 4 > end) {
25434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		wpa_printf(MSG_DEBUG, "EAP-EKE: Too short ID/Request Data (num_prop=%u)",
25534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt			   num_prop);
25634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		return eap_eke_build_fail(data, ret, reqData,
25734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt					  EAP_EKE_FAIL_PROTO_ERROR);
25834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	}
25934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
26034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	for (i = 0; i < num_prop; i++) {
26134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		const u8 *tmp = pos;
26234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
26334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		wpa_printf(MSG_DEBUG, "EAP-EKE: Proposal #%u: dh=%u encr=%u prf=%u mac=%u",
26434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt			   i, pos[0], pos[1], pos[2], pos[3]);
26534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		pos += 4;
26634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
267fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		if ((data->dhgroup && data->dhgroup != *tmp) ||
268fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		    !eap_eke_supp_dhgroup(*tmp))
26934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt			continue;
27034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		tmp++;
271fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		if ((data->encr && data->encr != *tmp) ||
272fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		    !eap_eke_supp_encr(*tmp))
27334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt			continue;
27434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		tmp++;
275fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		if ((data->prf && data->prf != *tmp) ||
276fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		    !eap_eke_supp_prf(*tmp))
27734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt			continue;
27834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		tmp++;
279fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		if ((data->mac && data->mac != *tmp) ||
280fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		    !eap_eke_supp_mac(*tmp))
28134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt			continue;
28234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
28334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		prop = tmp - 3;
28434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		if (eap_eke_session_init(&data->sess, prop[0], prop[1], prop[2],
28534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt					 prop[3]) < 0) {
28634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt			prop = NULL;
28734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt			continue;
28834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		}
28934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
29034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		wpa_printf(MSG_DEBUG, "EAP-EKE: Selected proposal");
29134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		break;
29234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	}
29334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
29434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	if (prop == NULL) {
29534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		wpa_printf(MSG_DEBUG, "EAP-EKE: No acceptable proposal found");
29634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		return eap_eke_build_fail(data, ret, reqData,
29734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt					  EAP_EKE_FAIL_NO_PROPOSAL_CHOSEN);
29834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	}
29934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
30034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	pos += (num_prop - i - 1) * 4;
30134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
30234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	if (pos == end) {
30334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		wpa_printf(MSG_DEBUG, "EAP-EKE: Too short ID/Request Data to include IDType/Identity");
30434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		return eap_eke_build_fail(data, ret, reqData,
30534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt					  EAP_EKE_FAIL_PROTO_ERROR);
30634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	}
30734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
30834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	idtype = *pos++;
30934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	wpa_printf(MSG_DEBUG, "EAP-EKE: Server IDType %u", idtype);
31034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	wpa_hexdump_ascii(MSG_DEBUG, "EAP-EKE: Server Identity",
31134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt			  pos, end - pos);
31234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	os_free(data->serverid);
31334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	data->serverid = os_malloc(end - pos);
31434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	if (data->serverid == NULL) {
31534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		return eap_eke_build_fail(data, ret, reqData,
31634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt					  EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
31734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	}
31834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	os_memcpy(data->serverid, pos, end - pos);
31934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	data->serverid_len = end - pos;
32034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
32134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	wpa_printf(MSG_DEBUG, "EAP-EKE: Sending EAP-EKE-ID/Response");
32234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
32334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	resp = eap_eke_build_msg(data, eap_get_id(reqData),
32434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt				 2 + 4 + 1 + data->peerid_len,
32534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt				 EAP_EKE_ID);
32634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	if (resp == NULL) {
32734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		return eap_eke_build_fail(data, ret, reqData,
32834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt					  EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
32934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	}
33034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
33134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	wpabuf_put_u8(resp, 1); /* NumProposals */
33234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	wpabuf_put_u8(resp, 0); /* Reserved */
33334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	wpabuf_put_data(resp, prop, 4); /* Selected Proposal */
33434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	wpabuf_put_u8(resp, EAP_EKE_ID_NAI);
33534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	if (data->peerid)
33634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		wpabuf_put_data(resp, data->peerid, data->peerid_len);
33734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
33834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	wpabuf_free(data->msgs);
33934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	data->msgs = wpabuf_alloc(wpabuf_len(reqData) + wpabuf_len(resp));
34034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	if (data->msgs == NULL) {
34134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		wpabuf_free(resp);
34234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		return eap_eke_build_fail(data, ret, reqData,
34334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt					  EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
34434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	}
34534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	wpabuf_put_buf(data->msgs, reqData);
34634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	wpabuf_put_buf(data->msgs, resp);
34734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
34834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	eap_eke_state(data, COMMIT);
34934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
35034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	return resp;
35134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt}
35234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
35334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
35434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidtstatic struct wpabuf * eap_eke_process_commit(struct eap_sm *sm,
35534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt					      struct eap_eke_data *data,
35634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt					      struct eap_method_ret *ret,
35734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt					      const struct wpabuf *reqData,
35834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt					      const u8 *payload,
35934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt					      size_t payload_len)
36034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt{
36134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	struct wpabuf *resp;
36234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	const u8 *pos, *end, *dhcomp;
36334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	size_t prot_len;
36434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	u8 *rpos;
36534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	u8 key[EAP_EKE_MAX_KEY_LEN];
36634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	u8 pub[EAP_EKE_MAX_DH_LEN];
36734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	const u8 *password;
36834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	size_t password_len;
36934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
37034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	if (data->state != COMMIT) {
37134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		wpa_printf(MSG_DEBUG, "EAP-EKE: EAP-EKE-Commit/Request received in unexpected state (%d)", data->state);
37234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		return eap_eke_build_fail(data, ret, reqData,
37334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt					  EAP_EKE_FAIL_PROTO_ERROR);
37434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	}
37534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
37634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	wpa_printf(MSG_DEBUG, "EAP-EKE: Received EAP-EKE-Commit/Request");
37734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
37834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	password = eap_get_config_password(sm, &password_len);
37934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	if (password == NULL) {
38034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		wpa_printf(MSG_INFO, "EAP-EKE: No password configured!");
38134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		return eap_eke_build_fail(data, ret, reqData,
38234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt					  EAP_EKE_FAIL_PASSWD_NOT_FOUND);
38334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	}
38434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
38534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	pos = payload;
38634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	end = payload + payload_len;
38734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
38834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	if (pos + data->sess.dhcomp_len > end) {
38934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		wpa_printf(MSG_DEBUG, "EAP-EKE: Too short EAP-EKE-Commit");
39034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		return eap_eke_build_fail(data, ret, reqData,
39134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt					  EAP_EKE_FAIL_PROTO_ERROR);
39234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	}
39334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
39434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	wpa_hexdump(MSG_DEBUG, "EAP-EKE: DHComponent_S",
39534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		    pos, data->sess.dhcomp_len);
39634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	dhcomp = pos;
39734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	pos += data->sess.dhcomp_len;
39834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	wpa_hexdump(MSG_DEBUG, "EAP-EKE: CBValue", pos, end - pos);
39934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
40034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	/*
40134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	 * temp = prf(0+, password)
40234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	 * key = prf+(temp, ID_S | ID_P)
40334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	 */
40434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	if (eap_eke_derive_key(&data->sess, password, password_len,
40534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt			       data->serverid, data->serverid_len,
40634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt			       data->peerid, data->peerid_len, key) < 0) {
40734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		wpa_printf(MSG_INFO, "EAP-EKE: Failed to derive key");
40834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		return eap_eke_build_fail(data, ret, reqData,
40934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt					  EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
41034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	}
41134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
41234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	/*
41334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	 * y_p = g ^ x_p (mod p)
41434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	 * x_p = random number 2 .. p-1
41534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	 */
41634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	if (eap_eke_dh_init(data->sess.dhgroup, data->dh_priv, pub) < 0) {
41734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		wpa_printf(MSG_INFO, "EAP-EKE: Failed to initialize DH");
41834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		os_memset(key, 0, sizeof(key));
41934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		return eap_eke_build_fail(data, ret, reqData,
42034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt					  EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
42134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	}
42234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
42334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	if (eap_eke_shared_secret(&data->sess, key, data->dh_priv, dhcomp) < 0)
42434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	{
42534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		wpa_printf(MSG_INFO, "EAP-EKE: Failed to derive shared secret");
42634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		os_memset(key, 0, sizeof(key));
42734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		return eap_eke_build_fail(data, ret, reqData,
42834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt					  EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
42934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	}
43034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
43134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	if (eap_eke_derive_ke_ki(&data->sess,
43234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt				 data->serverid, data->serverid_len,
43334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt				 data->peerid, data->peerid_len) < 0) {
43434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		wpa_printf(MSG_INFO, "EAP-EKE: Failed to derive Ke/Ki");
43534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		os_memset(key, 0, sizeof(key));
43634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		return eap_eke_build_fail(data, ret, reqData,
43734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt					  EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
43834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	}
43934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
44034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	wpa_printf(MSG_DEBUG, "EAP-EKE: Sending EAP-EKE-Commit/Response");
44134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
44234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	resp = eap_eke_build_msg(data, eap_get_id(reqData),
44334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt				 data->sess.dhcomp_len + data->sess.pnonce_len,
44434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt				 EAP_EKE_COMMIT);
44534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	if (resp == NULL) {
44634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		os_memset(key, 0, sizeof(key));
44734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		return eap_eke_build_fail(data, ret, reqData,
44834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt					  EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
44934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	}
45034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
45134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	/* DHComponent_P = Encr(key, y_p) */
45234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	rpos = wpabuf_put(resp, data->sess.dhcomp_len);
45334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	if (eap_eke_dhcomp(&data->sess, key, pub, rpos) < 0) {
45443cb578dfe2c492257636f6234a24178ed27789eDmitry Shmidt		wpa_printf(MSG_INFO, "EAP-EKE: Failed to build DHComponent_P");
45534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		os_memset(key, 0, sizeof(key));
45634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		return eap_eke_build_fail(data, ret, reqData,
45734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt					  EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
45834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	}
45934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	os_memset(key, 0, sizeof(key));
46034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
46134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	wpa_hexdump(MSG_DEBUG, "EAP-EKE: DHComponent_P",
46234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		    rpos, data->sess.dhcomp_len);
46334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
46434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	if (random_get_bytes(data->nonce_p, data->sess.nonce_len)) {
46534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		wpabuf_free(resp);
46634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		return eap_eke_build_fail(data, ret, reqData,
46734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt					  EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
46834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	}
46934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: Nonce_P",
47034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt			data->nonce_p, data->sess.nonce_len);
47134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	prot_len = wpabuf_tailroom(resp);
47234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	if (eap_eke_prot(&data->sess, data->nonce_p, data->sess.nonce_len,
47334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt			 wpabuf_put(resp, 0), &prot_len) < 0) {
47434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		wpabuf_free(resp);
47534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		return eap_eke_build_fail(data, ret, reqData,
47634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt					  EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
47734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	}
47834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	wpa_hexdump(MSG_DEBUG, "EAP-EKE: PNonce_P",
47934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		    wpabuf_put(resp, 0), prot_len);
48034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	wpabuf_put(resp, prot_len);
48134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
48234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	/* TODO: CBValue */
48334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
48434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	if (wpabuf_resize(&data->msgs, wpabuf_len(reqData) + wpabuf_len(resp))
48534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	    < 0) {
48634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		wpabuf_free(resp);
48734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		return eap_eke_build_fail(data, ret, reqData,
48834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt					  EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
48934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	}
49034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	wpabuf_put_buf(data->msgs, reqData);
49134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	wpabuf_put_buf(data->msgs, resp);
49234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
49334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	eap_eke_state(data, CONFIRM);
49434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
49534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	return resp;
49634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt}
49734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
49834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
49934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidtstatic struct wpabuf * eap_eke_process_confirm(struct eap_eke_data *data,
50034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt					       struct eap_method_ret *ret,
50134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt					       const struct wpabuf *reqData,
50234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt					       const u8 *payload,
50334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt					       size_t payload_len)
50434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt{
50534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	struct wpabuf *resp;
50634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	const u8 *pos, *end;
50734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	size_t prot_len;
50834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	u8 nonces[2 * EAP_EKE_MAX_NONCE_LEN];
50934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	u8 auth_s[EAP_EKE_MAX_HASH_LEN];
51034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	size_t decrypt_len;
51134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	u8 *auth;
51234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
51334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	if (data->state != CONFIRM) {
51434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		wpa_printf(MSG_DEBUG, "EAP-EKE: EAP-EKE-Confirm/Request received in unexpected state (%d)",
51534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt			   data->state);
51634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		return eap_eke_build_fail(data, ret, reqData,
51734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt					  EAP_EKE_FAIL_PROTO_ERROR);
51834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	}
51934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
52034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	wpa_printf(MSG_DEBUG, "EAP-EKE: Received EAP-EKE-Confirm/Request");
52134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
52234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	pos = payload;
52334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	end = payload + payload_len;
52434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
52534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	if (pos + data->sess.pnonce_ps_len + data->sess.prf_len > end) {
52643cb578dfe2c492257636f6234a24178ed27789eDmitry Shmidt		wpa_printf(MSG_DEBUG, "EAP-EKE: Too short EAP-EKE-Confirm");
52734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		return eap_eke_build_fail(data, ret, reqData,
52834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt					  EAP_EKE_FAIL_PROTO_ERROR);
52934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	}
53034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
53134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	decrypt_len = sizeof(nonces);
53234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	if (eap_eke_decrypt_prot(&data->sess, pos, data->sess.pnonce_ps_len,
53334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt				 nonces, &decrypt_len) < 0) {
53434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		wpa_printf(MSG_INFO, "EAP-EKE: Failed to decrypt PNonce_PS");
53534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		return eap_eke_build_fail(data, ret, reqData,
53634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt					  EAP_EKE_FAIL_AUTHENTICATION_FAIL);
53734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	}
53834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	if (decrypt_len != (size_t) 2 * data->sess.nonce_len) {
53934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		wpa_printf(MSG_INFO, "EAP-EKE: PNonce_PS protected data length does not match length of Nonce_P and Nonce_S");
54034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		return eap_eke_build_fail(data, ret, reqData,
54134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt					  EAP_EKE_FAIL_AUTHENTICATION_FAIL);
54234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	}
54334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: Received Nonce_P | Nonce_S",
54434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt			nonces, 2 * data->sess.nonce_len);
54534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	if (os_memcmp(data->nonce_p, nonces, data->sess.nonce_len) != 0) {
54643cb578dfe2c492257636f6234a24178ed27789eDmitry Shmidt		wpa_printf(MSG_INFO, "EAP-EKE: Received Nonce_P does not match transmitted Nonce_P");
54734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		return eap_eke_build_fail(data, ret, reqData,
54834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt					  EAP_EKE_FAIL_AUTHENTICATION_FAIL);
54934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	}
55034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
55134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	os_memcpy(data->nonce_s, nonces + data->sess.nonce_len,
55234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		  data->sess.nonce_len);
55334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: Nonce_S",
55434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt			data->nonce_s, data->sess.nonce_len);
55534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
55634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	if (eap_eke_derive_ka(&data->sess, data->serverid, data->serverid_len,
55734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt			      data->peerid, data->peerid_len,
55834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt			      data->nonce_p, data->nonce_s) < 0) {
55934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		return eap_eke_build_fail(data, ret, reqData,
56034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt					  EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
56134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	}
56234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
56334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	if (eap_eke_auth(&data->sess, "EAP-EKE server", data->msgs, auth_s) < 0)
56434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	{
56534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		return eap_eke_build_fail(data, ret, reqData,
56634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt					  EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
56734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	}
56834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	wpa_hexdump(MSG_DEBUG, "EAP-EKE: Auth_S", auth_s, data->sess.prf_len);
569c28170251eb54dbf64a9074a07fee377587425b2Dmitry Shmidt	if (os_memcmp_const(auth_s, pos + data->sess.pnonce_ps_len,
570c28170251eb54dbf64a9074a07fee377587425b2Dmitry Shmidt			    data->sess.prf_len) != 0) {
57134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		wpa_printf(MSG_INFO, "EAP-EKE: Auth_S does not match");
57234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		return eap_eke_build_fail(data, ret, reqData,
57334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt					  EAP_EKE_FAIL_AUTHENTICATION_FAIL);
57434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	}
57534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
57634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	wpa_printf(MSG_DEBUG, "EAP-EKE: Sending EAP-EKE-Confirm/Response");
57734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
57834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	resp = eap_eke_build_msg(data, eap_get_id(reqData),
57934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt				 data->sess.pnonce_len + data->sess.prf_len,
58034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt				 EAP_EKE_CONFIRM);
58134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	if (resp == NULL) {
58234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		return eap_eke_build_fail(data, ret, reqData,
58334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt					  EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
58434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	}
58534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
58634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	prot_len = wpabuf_tailroom(resp);
58734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	if (eap_eke_prot(&data->sess, data->nonce_s, data->sess.nonce_len,
58834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt			 wpabuf_put(resp, 0), &prot_len) < 0) {
58934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		wpabuf_free(resp);
59034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		return eap_eke_build_fail(data, ret, reqData,
59134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt					  EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
59234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	}
59334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	wpabuf_put(resp, prot_len);
59434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
59534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	auth = wpabuf_put(resp, data->sess.prf_len);
59634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	if (eap_eke_auth(&data->sess, "EAP-EKE peer", data->msgs, auth) < 0) {
59734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		wpabuf_free(resp);
59834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		return eap_eke_build_fail(data, ret, reqData,
59934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt					  EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
60034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	}
60134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	wpa_hexdump(MSG_DEBUG, "EAP-EKE: Auth_P", auth, data->sess.prf_len);
60234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
60334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	if (eap_eke_derive_msk(&data->sess, data->serverid, data->serverid_len,
60434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt			       data->peerid, data->peerid_len,
60534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt			       data->nonce_s, data->nonce_p,
60634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt			       data->msk, data->emsk) < 0) {
60734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		wpa_printf(MSG_INFO, "EAP-EKE: Failed to derive MSK/EMSK");
60834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		wpabuf_free(resp);
60934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		return eap_eke_build_fail(data, ret, reqData,
61034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt					  EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
61134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	}
61234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
61334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	os_memset(data->dh_priv, 0, sizeof(data->dh_priv));
61434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	eap_eke_session_clean(&data->sess);
61534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
61634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	eap_eke_state(data, SUCCESS);
61734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	ret->methodState = METHOD_MAY_CONT;
61834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	ret->decision = DECISION_COND_SUCC;
61934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	ret->allowNotifications = FALSE;
62034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
62134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	return resp;
62234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt}
62334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
62434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
62534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidtstatic struct wpabuf * eap_eke_process_failure(struct eap_eke_data *data,
62634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt					       struct eap_method_ret *ret,
62734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt					       const struct wpabuf *reqData,
62834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt					       const u8 *payload,
62934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt					       size_t payload_len)
63034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt{
63134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	wpa_printf(MSG_DEBUG, "EAP-EKE: Received EAP-EKE-Failure/Request");
63234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
63334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	if (payload_len < 4) {
63434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		wpa_printf(MSG_DEBUG, "EAP-EKE: Too short EAP-EKE-Failure");
63534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	} else {
63634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		u32 code;
63734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		code = WPA_GET_BE32(payload);
63834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		wpa_printf(MSG_INFO, "EAP-EKE: Failure-Code 0x%x", code);
63934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	}
64034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
64134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	return eap_eke_build_fail(data, ret, reqData, EAP_EKE_FAIL_NO_ERROR);
64234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt}
64334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
64434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
64534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidtstatic struct wpabuf * eap_eke_process(struct eap_sm *sm, void *priv,
64634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt				       struct eap_method_ret *ret,
64734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt				       const struct wpabuf *reqData)
64834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt{
64934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	struct eap_eke_data *data = priv;
65034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	struct wpabuf *resp;
65134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	const u8 *pos, *end;
65234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	size_t len;
65334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	u8 eke_exch;
65434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
65534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_EKE, reqData, &len);
65634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	if (pos == NULL || len < 1) {
65734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		ret->ignore = TRUE;
65834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		return NULL;
65934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	}
66034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
66134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	end = pos + len;
66234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	eke_exch = *pos++;
66334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
66434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	wpa_printf(MSG_DEBUG, "EAP-EKE: Received frame: exch %d", eke_exch);
66534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	wpa_hexdump(MSG_DEBUG, "EAP-EKE: Received Data", pos, end - pos);
66634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
66734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	ret->ignore = FALSE;
66834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	ret->methodState = METHOD_MAY_CONT;
66934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	ret->decision = DECISION_FAIL;
67034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	ret->allowNotifications = TRUE;
67134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
67234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	switch (eke_exch) {
67334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	case EAP_EKE_ID:
67434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		resp = eap_eke_process_id(data, ret, reqData, pos, end - pos);
67534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		break;
67634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	case EAP_EKE_COMMIT:
67734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		resp = eap_eke_process_commit(sm, data, ret, reqData,
67834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt					      pos, end - pos);
67934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		break;
68034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	case EAP_EKE_CONFIRM:
68134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		resp = eap_eke_process_confirm(data, ret, reqData,
68234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt					       pos, end - pos);
68334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		break;
68434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	case EAP_EKE_FAILURE:
68534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		resp = eap_eke_process_failure(data, ret, reqData,
68634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt					       pos, end - pos);
68734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		break;
68834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	default:
68934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		wpa_printf(MSG_DEBUG, "EAP-EKE: Ignoring message with unknown EKE-Exch %d", eke_exch);
69034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		ret->ignore = TRUE;
69134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		return NULL;
69234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	}
69334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
69434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	if (ret->methodState == METHOD_DONE)
69534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		ret->allowNotifications = FALSE;
69634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
69734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	return resp;
69834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt}
69934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
70034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
70134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidtstatic Boolean eap_eke_isKeyAvailable(struct eap_sm *sm, void *priv)
70234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt{
70334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	struct eap_eke_data *data = priv;
70434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	return data->state == SUCCESS;
70534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt}
70634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
70734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
70834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidtstatic u8 * eap_eke_getKey(struct eap_sm *sm, void *priv, size_t *len)
70934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt{
71034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	struct eap_eke_data *data = priv;
71134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	u8 *key;
71234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
71334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	if (data->state != SUCCESS)
71434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		return NULL;
71534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
71634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	key = os_malloc(EAP_MSK_LEN);
71734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	if (key == NULL)
71834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		return NULL;
71934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	os_memcpy(key, data->msk, EAP_MSK_LEN);
72034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	*len = EAP_MSK_LEN;
72134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
72234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	return key;
72334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt}
72434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
72534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
72634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidtstatic u8 * eap_eke_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
72734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt{
72834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	struct eap_eke_data *data = priv;
72934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	u8 *key;
73034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
73134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	if (data->state != SUCCESS)
73234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		return NULL;
73334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
73434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	key = os_malloc(EAP_EMSK_LEN);
73534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	if (key == NULL)
73634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		return NULL;
73734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	os_memcpy(key, data->emsk, EAP_EMSK_LEN);
73834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	*len = EAP_EMSK_LEN;
73934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
74034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	return key;
74134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt}
74234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
74334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
74434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidtint eap_peer_eke_register(void)
74534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt{
74634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	struct eap_method *eap;
74734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	int ret;
74834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
74934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
75034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt				    EAP_VENDOR_IETF, EAP_TYPE_EKE, "EKE");
75134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	if (eap == NULL)
75234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		return -1;
75334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
75434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	eap->init = eap_eke_init;
75534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	eap->deinit = eap_eke_deinit;
75634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	eap->process = eap_eke_process;
75734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	eap->isKeyAvailable = eap_eke_isKeyAvailable;
75834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	eap->getKey = eap_eke_getKey;
75934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	eap->get_emsk = eap_eke_get_emsk;
76034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
76134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	ret = eap_peer_method_register(eap);
76234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	if (ret)
76334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		eap_peer_method_free(eap);
76434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	return ret;
76534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt}
766