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) {
88d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt		data->peerid = os_memdup(identity, identity_len);
8934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		if (data->peerid == NULL) {
9034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt			eap_eke_deinit(sm, data);
9134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt			return NULL;
9234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		}
9334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		data->peerid_len = identity_len;
9434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	}
9534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
96fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	phase1 = eap_get_config_phase1(sm);
97fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	if (phase1) {
98fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		const char *pos;
99fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt
100fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		pos = os_strstr(phase1, "dhgroup=");
101fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		if (pos) {
102fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt			data->dhgroup = atoi(pos + 8);
103fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt			wpa_printf(MSG_DEBUG, "EAP-EKE: Forced dhgroup %u",
104fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt				   data->dhgroup);
105fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		}
106fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt
107fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		pos = os_strstr(phase1, "encr=");
108fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		if (pos) {
109fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt			data->encr = atoi(pos + 5);
110fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt			wpa_printf(MSG_DEBUG, "EAP-EKE: Forced encr %u",
111fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt				   data->encr);
112fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		}
113fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt
114fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		pos = os_strstr(phase1, "prf=");
115fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		if (pos) {
116fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt			data->prf = atoi(pos + 4);
117fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt			wpa_printf(MSG_DEBUG, "EAP-EKE: Forced prf %u",
118fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt				   data->prf);
119fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		}
120fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt
121fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		pos = os_strstr(phase1, "mac=");
122fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		if (pos) {
123fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt			data->mac = atoi(pos + 4);
124fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt			wpa_printf(MSG_DEBUG, "EAP-EKE: Forced mac %u",
125fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt				   data->mac);
126fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		}
127fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	}
128fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt
12934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	return data;
13034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt}
13134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
13234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
13334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidtstatic void eap_eke_deinit(struct eap_sm *sm, void *priv)
13434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt{
13534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	struct eap_eke_data *data = priv;
13634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	eap_eke_session_clean(&data->sess);
13734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	os_free(data->serverid);
13834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	os_free(data->peerid);
13934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	wpabuf_free(data->msgs);
140c28170251eb54dbf64a9074a07fee377587425b2Dmitry Shmidt	bin_clear_free(data, sizeof(*data));
14134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt}
14234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
14334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
14434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidtstatic struct wpabuf * eap_eke_build_msg(struct eap_eke_data *data, int id,
14534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt					 size_t length, u8 eke_exch)
14634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt{
14734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	struct wpabuf *msg;
14834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	size_t plen;
14934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
15034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	plen = 1 + length;
15134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
15234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	msg = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_EKE, plen,
15334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt			    EAP_CODE_RESPONSE, id);
15434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	if (msg == NULL) {
15534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		wpa_printf(MSG_ERROR, "EAP-EKE: Failed to allocate memory");
15634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		return NULL;
15734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	}
15834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
15934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	wpabuf_put_u8(msg, eke_exch);
16034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
16134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	return msg;
16234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt}
16334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
16434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
16534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidtstatic int eap_eke_supp_dhgroup(u8 dhgroup)
16634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt{
16734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	return dhgroup == EAP_EKE_DHGROUP_EKE_2 ||
16834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		dhgroup == EAP_EKE_DHGROUP_EKE_5 ||
16934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		dhgroup == EAP_EKE_DHGROUP_EKE_14 ||
17034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		dhgroup == EAP_EKE_DHGROUP_EKE_15 ||
17134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		dhgroup == EAP_EKE_DHGROUP_EKE_16;
17234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt}
17334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
17434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
17534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidtstatic int eap_eke_supp_encr(u8 encr)
17634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt{
17734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	return encr == EAP_EKE_ENCR_AES128_CBC;
17834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt}
17934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
18034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
18134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidtstatic int eap_eke_supp_prf(u8 prf)
18234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt{
18334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	return prf == EAP_EKE_PRF_HMAC_SHA1 ||
18434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		prf == EAP_EKE_PRF_HMAC_SHA2_256;
18534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt}
18634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
18734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
18834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidtstatic int eap_eke_supp_mac(u8 mac)
18934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt{
19034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	return mac == EAP_EKE_MAC_HMAC_SHA1 ||
19134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		mac == EAP_EKE_MAC_HMAC_SHA2_256;
19234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt}
19334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
19434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
19534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidtstatic struct wpabuf * eap_eke_build_fail(struct eap_eke_data *data,
19634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt					  struct eap_method_ret *ret,
197cc00d5dc8483e32158b2ba61ea44b0c38d790ed7Dmitry Shmidt					  u8 id, u32 failure_code)
19834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt{
19934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	struct wpabuf *resp;
20034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
20134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	wpa_printf(MSG_DEBUG, "EAP-EKE: Sending EAP-EKE-Failure/Response - code=0x%x",
20234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		   failure_code);
20334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
204cc00d5dc8483e32158b2ba61ea44b0c38d790ed7Dmitry Shmidt	resp = eap_eke_build_msg(data, id, 4, EAP_EKE_FAILURE);
20534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	if (resp)
20634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		wpabuf_put_be32(resp, failure_code);
20734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
20834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	os_memset(data->dh_priv, 0, sizeof(data->dh_priv));
20934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	eap_eke_session_clean(&data->sess);
21034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
21134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	eap_eke_state(data, FAILURE);
21234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	ret->methodState = METHOD_DONE;
21334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	ret->decision = DECISION_FAIL;
21434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	ret->allowNotifications = FALSE;
21534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
21634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	return resp;
21734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt}
21834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
21934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
22034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidtstatic struct wpabuf * eap_eke_process_id(struct eap_eke_data *data,
22134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt					  struct eap_method_ret *ret,
22234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt					  const struct wpabuf *reqData,
22334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt					  const u8 *payload,
22434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt					  size_t payload_len)
22534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt{
22634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	struct wpabuf *resp;
22734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	unsigned num_prop, i;
22834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	const u8 *pos, *end;
22934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	const u8 *prop = NULL;
23034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	u8 idtype;
231cc00d5dc8483e32158b2ba61ea44b0c38d790ed7Dmitry Shmidt	u8 id = eap_get_id(reqData);
23234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
23334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	if (data->state != IDENTITY) {
234cc00d5dc8483e32158b2ba61ea44b0c38d790ed7Dmitry Shmidt		return eap_eke_build_fail(data, ret, id,
23534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt					  EAP_EKE_FAIL_PROTO_ERROR);
23634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	}
23734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
23834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	wpa_printf(MSG_DEBUG, "EAP-EKE: Received EAP-EKE-ID/Request");
23934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
24034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	if (payload_len < 2 + 4) {
24134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		wpa_printf(MSG_DEBUG, "EAP-EKE: Too short ID/Request Data");
242cc00d5dc8483e32158b2ba61ea44b0c38d790ed7Dmitry Shmidt		return eap_eke_build_fail(data, ret, id,
24334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt					  EAP_EKE_FAIL_PROTO_ERROR);
24434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	}
24534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
24634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	pos = payload;
24734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	end = payload + payload_len;
24834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
24934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	num_prop = *pos++;
25034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	pos++; /* Ignore Reserved field */
25134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
25234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	if (pos + num_prop * 4 > end) {
25334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		wpa_printf(MSG_DEBUG, "EAP-EKE: Too short ID/Request Data (num_prop=%u)",
25434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt			   num_prop);
255cc00d5dc8483e32158b2ba61ea44b0c38d790ed7Dmitry Shmidt		return eap_eke_build_fail(data, ret, id,
25634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt					  EAP_EKE_FAIL_PROTO_ERROR);
25734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	}
25834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
25934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	for (i = 0; i < num_prop; i++) {
26034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		const u8 *tmp = pos;
26134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
26234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		wpa_printf(MSG_DEBUG, "EAP-EKE: Proposal #%u: dh=%u encr=%u prf=%u mac=%u",
26334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt			   i, pos[0], pos[1], pos[2], pos[3]);
26434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		pos += 4;
26534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
266fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		if ((data->dhgroup && data->dhgroup != *tmp) ||
267fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		    !eap_eke_supp_dhgroup(*tmp))
26834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt			continue;
26934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		tmp++;
270fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		if ((data->encr && data->encr != *tmp) ||
271fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		    !eap_eke_supp_encr(*tmp))
27234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt			continue;
27334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		tmp++;
274fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		if ((data->prf && data->prf != *tmp) ||
275fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		    !eap_eke_supp_prf(*tmp))
27634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt			continue;
27734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		tmp++;
278fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		if ((data->mac && data->mac != *tmp) ||
279fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		    !eap_eke_supp_mac(*tmp))
28034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt			continue;
28134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
28234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		prop = tmp - 3;
28334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		if (eap_eke_session_init(&data->sess, prop[0], prop[1], prop[2],
28434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt					 prop[3]) < 0) {
28534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt			prop = NULL;
28634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt			continue;
28734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		}
28834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
28934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		wpa_printf(MSG_DEBUG, "EAP-EKE: Selected proposal");
29034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		break;
29134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	}
29234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
29334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	if (prop == NULL) {
29434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		wpa_printf(MSG_DEBUG, "EAP-EKE: No acceptable proposal found");
295cc00d5dc8483e32158b2ba61ea44b0c38d790ed7Dmitry Shmidt		return eap_eke_build_fail(data, ret, id,
29634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt					  EAP_EKE_FAIL_NO_PROPOSAL_CHOSEN);
29734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	}
29834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
29934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	pos += (num_prop - i - 1) * 4;
30034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
30134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	if (pos == end) {
30234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		wpa_printf(MSG_DEBUG, "EAP-EKE: Too short ID/Request Data to include IDType/Identity");
303cc00d5dc8483e32158b2ba61ea44b0c38d790ed7Dmitry Shmidt		return eap_eke_build_fail(data, ret, id,
30434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt					  EAP_EKE_FAIL_PROTO_ERROR);
30534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	}
30634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
30734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	idtype = *pos++;
30834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	wpa_printf(MSG_DEBUG, "EAP-EKE: Server IDType %u", idtype);
30934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	wpa_hexdump_ascii(MSG_DEBUG, "EAP-EKE: Server Identity",
31034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt			  pos, end - pos);
31134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	os_free(data->serverid);
312d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt	data->serverid = os_memdup(pos, end - pos);
31334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	if (data->serverid == NULL) {
314cc00d5dc8483e32158b2ba61ea44b0c38d790ed7Dmitry Shmidt		return eap_eke_build_fail(data, ret, id,
31534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt					  EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
31634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	}
31734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	data->serverid_len = end - pos;
31834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
31934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	wpa_printf(MSG_DEBUG, "EAP-EKE: Sending EAP-EKE-ID/Response");
32034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
321cc00d5dc8483e32158b2ba61ea44b0c38d790ed7Dmitry Shmidt	resp = eap_eke_build_msg(data, id,
32234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt				 2 + 4 + 1 + data->peerid_len,
32334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt				 EAP_EKE_ID);
32434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	if (resp == NULL) {
325cc00d5dc8483e32158b2ba61ea44b0c38d790ed7Dmitry Shmidt		return eap_eke_build_fail(data, ret, id,
32634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt					  EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
32734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	}
32834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
32934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	wpabuf_put_u8(resp, 1); /* NumProposals */
33034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	wpabuf_put_u8(resp, 0); /* Reserved */
33134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	wpabuf_put_data(resp, prop, 4); /* Selected Proposal */
33234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	wpabuf_put_u8(resp, EAP_EKE_ID_NAI);
33334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	if (data->peerid)
33434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		wpabuf_put_data(resp, data->peerid, data->peerid_len);
33534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
33634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	wpabuf_free(data->msgs);
33734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	data->msgs = wpabuf_alloc(wpabuf_len(reqData) + wpabuf_len(resp));
33834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	if (data->msgs == NULL) {
33934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		wpabuf_free(resp);
340cc00d5dc8483e32158b2ba61ea44b0c38d790ed7Dmitry Shmidt		return eap_eke_build_fail(data, ret, id,
34134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt					  EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
34234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	}
34334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	wpabuf_put_buf(data->msgs, reqData);
34434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	wpabuf_put_buf(data->msgs, resp);
34534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
34634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	eap_eke_state(data, COMMIT);
34734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
34834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	return resp;
34934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt}
35034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
35134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
35234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidtstatic struct wpabuf * eap_eke_process_commit(struct eap_sm *sm,
35334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt					      struct eap_eke_data *data,
35434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt					      struct eap_method_ret *ret,
35534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt					      const struct wpabuf *reqData,
35634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt					      const u8 *payload,
35734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt					      size_t payload_len)
35834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt{
35934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	struct wpabuf *resp;
36034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	const u8 *pos, *end, *dhcomp;
36134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	size_t prot_len;
36234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	u8 *rpos;
36334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	u8 key[EAP_EKE_MAX_KEY_LEN];
36434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	u8 pub[EAP_EKE_MAX_DH_LEN];
36534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	const u8 *password;
36634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	size_t password_len;
367cc00d5dc8483e32158b2ba61ea44b0c38d790ed7Dmitry Shmidt	u8 id = eap_get_id(reqData);
36834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
36934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	if (data->state != COMMIT) {
37034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		wpa_printf(MSG_DEBUG, "EAP-EKE: EAP-EKE-Commit/Request received in unexpected state (%d)", data->state);
371cc00d5dc8483e32158b2ba61ea44b0c38d790ed7Dmitry Shmidt		return eap_eke_build_fail(data, ret, id,
37234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt					  EAP_EKE_FAIL_PROTO_ERROR);
37334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	}
37434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
37534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	wpa_printf(MSG_DEBUG, "EAP-EKE: Received EAP-EKE-Commit/Request");
37634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
37734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	password = eap_get_config_password(sm, &password_len);
37834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	if (password == NULL) {
37934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		wpa_printf(MSG_INFO, "EAP-EKE: No password configured!");
380cc00d5dc8483e32158b2ba61ea44b0c38d790ed7Dmitry Shmidt		return eap_eke_build_fail(data, ret, id,
38134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt					  EAP_EKE_FAIL_PASSWD_NOT_FOUND);
38234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	}
38334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
38434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	pos = payload;
38534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	end = payload + payload_len;
38634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
38734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	if (pos + data->sess.dhcomp_len > end) {
38834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		wpa_printf(MSG_DEBUG, "EAP-EKE: Too short EAP-EKE-Commit");
389cc00d5dc8483e32158b2ba61ea44b0c38d790ed7Dmitry Shmidt		return eap_eke_build_fail(data, ret, id,
39034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt					  EAP_EKE_FAIL_PROTO_ERROR);
39134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	}
39234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
39334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	wpa_hexdump(MSG_DEBUG, "EAP-EKE: DHComponent_S",
39434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		    pos, data->sess.dhcomp_len);
39534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	dhcomp = pos;
39634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	pos += data->sess.dhcomp_len;
39734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	wpa_hexdump(MSG_DEBUG, "EAP-EKE: CBValue", pos, end - pos);
39834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
39934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	/*
40034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	 * temp = prf(0+, password)
40134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	 * key = prf+(temp, ID_S | ID_P)
40234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	 */
40334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	if (eap_eke_derive_key(&data->sess, password, password_len,
40434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt			       data->serverid, data->serverid_len,
40534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt			       data->peerid, data->peerid_len, key) < 0) {
40634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		wpa_printf(MSG_INFO, "EAP-EKE: Failed to derive key");
407cc00d5dc8483e32158b2ba61ea44b0c38d790ed7Dmitry Shmidt		return eap_eke_build_fail(data, ret, id,
40834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt					  EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
40934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	}
41034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
41134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	/*
41234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	 * y_p = g ^ x_p (mod p)
41334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	 * x_p = random number 2 .. p-1
41434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	 */
41534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	if (eap_eke_dh_init(data->sess.dhgroup, data->dh_priv, pub) < 0) {
41634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		wpa_printf(MSG_INFO, "EAP-EKE: Failed to initialize DH");
41734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		os_memset(key, 0, sizeof(key));
418cc00d5dc8483e32158b2ba61ea44b0c38d790ed7Dmitry Shmidt		return eap_eke_build_fail(data, ret, id,
41934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt					  EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
42034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	}
42134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
42234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	if (eap_eke_shared_secret(&data->sess, key, data->dh_priv, dhcomp) < 0)
42334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	{
42434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		wpa_printf(MSG_INFO, "EAP-EKE: Failed to derive shared secret");
42534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		os_memset(key, 0, sizeof(key));
426cc00d5dc8483e32158b2ba61ea44b0c38d790ed7Dmitry Shmidt		return eap_eke_build_fail(data, ret, id,
42734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt					  EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
42834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	}
42934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
43034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	if (eap_eke_derive_ke_ki(&data->sess,
43134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt				 data->serverid, data->serverid_len,
43234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt				 data->peerid, data->peerid_len) < 0) {
43334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		wpa_printf(MSG_INFO, "EAP-EKE: Failed to derive Ke/Ki");
43434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		os_memset(key, 0, sizeof(key));
435cc00d5dc8483e32158b2ba61ea44b0c38d790ed7Dmitry Shmidt		return eap_eke_build_fail(data, ret, id,
43634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt					  EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
43734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	}
43834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
43934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	wpa_printf(MSG_DEBUG, "EAP-EKE: Sending EAP-EKE-Commit/Response");
44034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
441cc00d5dc8483e32158b2ba61ea44b0c38d790ed7Dmitry Shmidt	resp = eap_eke_build_msg(data, id,
44234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt				 data->sess.dhcomp_len + data->sess.pnonce_len,
44334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt				 EAP_EKE_COMMIT);
44434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	if (resp == NULL) {
44534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		os_memset(key, 0, sizeof(key));
446cc00d5dc8483e32158b2ba61ea44b0c38d790ed7Dmitry Shmidt		return eap_eke_build_fail(data, ret, id,
44734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt					  EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
44834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	}
44934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
45034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	/* DHComponent_P = Encr(key, y_p) */
45134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	rpos = wpabuf_put(resp, data->sess.dhcomp_len);
45234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	if (eap_eke_dhcomp(&data->sess, key, pub, rpos) < 0) {
453d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt		wpabuf_free(resp);
45443cb578dfe2c492257636f6234a24178ed27789eDmitry Shmidt		wpa_printf(MSG_INFO, "EAP-EKE: Failed to build DHComponent_P");
45534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		os_memset(key, 0, sizeof(key));
456cc00d5dc8483e32158b2ba61ea44b0c38d790ed7Dmitry Shmidt		return eap_eke_build_fail(data, ret, id,
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);
466cc00d5dc8483e32158b2ba61ea44b0c38d790ed7Dmitry Shmidt		return eap_eke_build_fail(data, ret, id,
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);
475cc00d5dc8483e32158b2ba61ea44b0c38d790ed7Dmitry Shmidt		return eap_eke_build_fail(data, ret, id,
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);
487cc00d5dc8483e32158b2ba61ea44b0c38d790ed7Dmitry Shmidt		return eap_eke_build_fail(data, ret, id,
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;
512cc00d5dc8483e32158b2ba61ea44b0c38d790ed7Dmitry Shmidt	u8 id = eap_get_id(reqData);
51334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
51434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	if (data->state != CONFIRM) {
51534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		wpa_printf(MSG_DEBUG, "EAP-EKE: EAP-EKE-Confirm/Request received in unexpected state (%d)",
51634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt			   data->state);
517cc00d5dc8483e32158b2ba61ea44b0c38d790ed7Dmitry Shmidt		return eap_eke_build_fail(data, ret, id,
51834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt					  EAP_EKE_FAIL_PROTO_ERROR);
51934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	}
52034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
52134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	wpa_printf(MSG_DEBUG, "EAP-EKE: Received EAP-EKE-Confirm/Request");
52234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
52334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	pos = payload;
52434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	end = payload + payload_len;
52534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
52634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	if (pos + data->sess.pnonce_ps_len + data->sess.prf_len > end) {
52743cb578dfe2c492257636f6234a24178ed27789eDmitry Shmidt		wpa_printf(MSG_DEBUG, "EAP-EKE: Too short EAP-EKE-Confirm");
528cc00d5dc8483e32158b2ba61ea44b0c38d790ed7Dmitry Shmidt		return eap_eke_build_fail(data, ret, id,
52934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt					  EAP_EKE_FAIL_PROTO_ERROR);
53034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	}
53134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
53234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	decrypt_len = sizeof(nonces);
53334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	if (eap_eke_decrypt_prot(&data->sess, pos, data->sess.pnonce_ps_len,
53434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt				 nonces, &decrypt_len) < 0) {
53534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		wpa_printf(MSG_INFO, "EAP-EKE: Failed to decrypt PNonce_PS");
536cc00d5dc8483e32158b2ba61ea44b0c38d790ed7Dmitry Shmidt		return eap_eke_build_fail(data, ret, id,
53734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt					  EAP_EKE_FAIL_AUTHENTICATION_FAIL);
53834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	}
53934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	if (decrypt_len != (size_t) 2 * data->sess.nonce_len) {
54034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		wpa_printf(MSG_INFO, "EAP-EKE: PNonce_PS protected data length does not match length of Nonce_P and Nonce_S");
541cc00d5dc8483e32158b2ba61ea44b0c38d790ed7Dmitry Shmidt		return eap_eke_build_fail(data, ret, id,
54234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt					  EAP_EKE_FAIL_AUTHENTICATION_FAIL);
54334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	}
54434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: Received Nonce_P | Nonce_S",
54534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt			nonces, 2 * data->sess.nonce_len);
54634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	if (os_memcmp(data->nonce_p, nonces, data->sess.nonce_len) != 0) {
54743cb578dfe2c492257636f6234a24178ed27789eDmitry Shmidt		wpa_printf(MSG_INFO, "EAP-EKE: Received Nonce_P does not match transmitted Nonce_P");
548cc00d5dc8483e32158b2ba61ea44b0c38d790ed7Dmitry Shmidt		return eap_eke_build_fail(data, ret, id,
54934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt					  EAP_EKE_FAIL_AUTHENTICATION_FAIL);
55034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	}
55134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
55234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	os_memcpy(data->nonce_s, nonces + data->sess.nonce_len,
55334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		  data->sess.nonce_len);
55434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: Nonce_S",
55534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt			data->nonce_s, data->sess.nonce_len);
55634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
55734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	if (eap_eke_derive_ka(&data->sess, data->serverid, data->serverid_len,
55834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt			      data->peerid, data->peerid_len,
55934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt			      data->nonce_p, data->nonce_s) < 0) {
560cc00d5dc8483e32158b2ba61ea44b0c38d790ed7Dmitry Shmidt		return eap_eke_build_fail(data, ret, id,
56134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt					  EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
56234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	}
56334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
56434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	if (eap_eke_auth(&data->sess, "EAP-EKE server", data->msgs, auth_s) < 0)
56534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	{
566cc00d5dc8483e32158b2ba61ea44b0c38d790ed7Dmitry Shmidt		return eap_eke_build_fail(data, ret, id,
56734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt					  EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
56834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	}
56934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	wpa_hexdump(MSG_DEBUG, "EAP-EKE: Auth_S", auth_s, data->sess.prf_len);
570c28170251eb54dbf64a9074a07fee377587425b2Dmitry Shmidt	if (os_memcmp_const(auth_s, pos + data->sess.pnonce_ps_len,
571c28170251eb54dbf64a9074a07fee377587425b2Dmitry Shmidt			    data->sess.prf_len) != 0) {
57234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		wpa_printf(MSG_INFO, "EAP-EKE: Auth_S does not match");
573cc00d5dc8483e32158b2ba61ea44b0c38d790ed7Dmitry Shmidt		return eap_eke_build_fail(data, ret, id,
57434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt					  EAP_EKE_FAIL_AUTHENTICATION_FAIL);
57534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	}
57634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
57734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	wpa_printf(MSG_DEBUG, "EAP-EKE: Sending EAP-EKE-Confirm/Response");
57834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
579cc00d5dc8483e32158b2ba61ea44b0c38d790ed7Dmitry Shmidt	resp = eap_eke_build_msg(data, id,
58034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt				 data->sess.pnonce_len + data->sess.prf_len,
58134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt				 EAP_EKE_CONFIRM);
58234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	if (resp == NULL) {
583cc00d5dc8483e32158b2ba61ea44b0c38d790ed7Dmitry Shmidt		return eap_eke_build_fail(data, ret, id,
58434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt					  EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
58534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	}
58634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
58734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	prot_len = wpabuf_tailroom(resp);
58834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	if (eap_eke_prot(&data->sess, data->nonce_s, data->sess.nonce_len,
58934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt			 wpabuf_put(resp, 0), &prot_len) < 0) {
59034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		wpabuf_free(resp);
591cc00d5dc8483e32158b2ba61ea44b0c38d790ed7Dmitry Shmidt		return eap_eke_build_fail(data, ret, id,
59234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt					  EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
59334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	}
59434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	wpabuf_put(resp, prot_len);
59534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
59634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	auth = wpabuf_put(resp, data->sess.prf_len);
59734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	if (eap_eke_auth(&data->sess, "EAP-EKE peer", data->msgs, auth) < 0) {
59834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		wpabuf_free(resp);
599cc00d5dc8483e32158b2ba61ea44b0c38d790ed7Dmitry Shmidt		return eap_eke_build_fail(data, ret, id,
60034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt					  EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
60134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	}
60234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	wpa_hexdump(MSG_DEBUG, "EAP-EKE: Auth_P", auth, data->sess.prf_len);
60334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
60434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	if (eap_eke_derive_msk(&data->sess, data->serverid, data->serverid_len,
60534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt			       data->peerid, data->peerid_len,
60634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt			       data->nonce_s, data->nonce_p,
60734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt			       data->msk, data->emsk) < 0) {
60834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		wpa_printf(MSG_INFO, "EAP-EKE: Failed to derive MSK/EMSK");
60934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		wpabuf_free(resp);
610cc00d5dc8483e32158b2ba61ea44b0c38d790ed7Dmitry Shmidt		return eap_eke_build_fail(data, ret, id,
61134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt					  EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
61234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	}
61334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
61434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	os_memset(data->dh_priv, 0, sizeof(data->dh_priv));
61534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	eap_eke_session_clean(&data->sess);
61634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
61734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	eap_eke_state(data, SUCCESS);
61834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	ret->methodState = METHOD_MAY_CONT;
61934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	ret->decision = DECISION_COND_SUCC;
62034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	ret->allowNotifications = FALSE;
62134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
62234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	return resp;
62334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt}
62434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
62534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
62634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidtstatic struct wpabuf * eap_eke_process_failure(struct eap_eke_data *data,
62734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt					       struct eap_method_ret *ret,
62834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt					       const struct wpabuf *reqData,
62934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt					       const u8 *payload,
63034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt					       size_t payload_len)
63134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt{
63234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	wpa_printf(MSG_DEBUG, "EAP-EKE: Received EAP-EKE-Failure/Request");
63334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
63434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	if (payload_len < 4) {
63534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		wpa_printf(MSG_DEBUG, "EAP-EKE: Too short EAP-EKE-Failure");
63634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	} else {
63734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		u32 code;
63834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		code = WPA_GET_BE32(payload);
63934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		wpa_printf(MSG_INFO, "EAP-EKE: Failure-Code 0x%x", code);
64034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	}
64134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
642cc00d5dc8483e32158b2ba61ea44b0c38d790ed7Dmitry Shmidt	return eap_eke_build_fail(data, ret, eap_get_id(reqData),
643cc00d5dc8483e32158b2ba61ea44b0c38d790ed7Dmitry Shmidt				  EAP_EKE_FAIL_NO_ERROR);
64434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt}
64534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
64634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
64734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidtstatic struct wpabuf * eap_eke_process(struct eap_sm *sm, void *priv,
64834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt				       struct eap_method_ret *ret,
64934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt				       const struct wpabuf *reqData)
65034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt{
65134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	struct eap_eke_data *data = priv;
65234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	struct wpabuf *resp;
65334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	const u8 *pos, *end;
65434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	size_t len;
65534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	u8 eke_exch;
65634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
65734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_EKE, reqData, &len);
65834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	if (pos == NULL || len < 1) {
65934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		ret->ignore = TRUE;
66034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		return NULL;
66134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	}
66234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
66334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	end = pos + len;
66434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	eke_exch = *pos++;
66534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
66634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	wpa_printf(MSG_DEBUG, "EAP-EKE: Received frame: exch %d", eke_exch);
66734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	wpa_hexdump(MSG_DEBUG, "EAP-EKE: Received Data", pos, end - pos);
66834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
66934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	ret->ignore = FALSE;
67034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	ret->methodState = METHOD_MAY_CONT;
67134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	ret->decision = DECISION_FAIL;
67234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	ret->allowNotifications = TRUE;
67334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
67434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	switch (eke_exch) {
67534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	case EAP_EKE_ID:
67634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		resp = eap_eke_process_id(data, ret, reqData, pos, end - pos);
67734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		break;
67834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	case EAP_EKE_COMMIT:
67934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		resp = eap_eke_process_commit(sm, data, ret, reqData,
68034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt					      pos, end - pos);
68134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		break;
68234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	case EAP_EKE_CONFIRM:
68334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		resp = eap_eke_process_confirm(data, ret, reqData,
68434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt					       pos, end - pos);
68534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		break;
68634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	case EAP_EKE_FAILURE:
68734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		resp = eap_eke_process_failure(data, ret, reqData,
68834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt					       pos, end - pos);
68934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		break;
69034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	default:
69134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		wpa_printf(MSG_DEBUG, "EAP-EKE: Ignoring message with unknown EKE-Exch %d", eke_exch);
69234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		ret->ignore = TRUE;
69334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		return NULL;
69434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	}
69534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
69634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	if (ret->methodState == METHOD_DONE)
69734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		ret->allowNotifications = FALSE;
69834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
69934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	return resp;
70034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt}
70134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
70234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
70334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidtstatic Boolean eap_eke_isKeyAvailable(struct eap_sm *sm, void *priv)
70434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt{
70534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	struct eap_eke_data *data = priv;
70634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	return data->state == SUCCESS;
70734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt}
70834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
70934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
71034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidtstatic u8 * eap_eke_getKey(struct eap_sm *sm, void *priv, size_t *len)
71134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt{
71234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	struct eap_eke_data *data = priv;
71334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	u8 *key;
71434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
71534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	if (data->state != SUCCESS)
71634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		return NULL;
71734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
718d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt	key = os_memdup(data->msk, EAP_MSK_LEN);
71934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	if (key == NULL)
72034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		return NULL;
72134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	*len = EAP_MSK_LEN;
72234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
72334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	return key;
72434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt}
72534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
72634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
72734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidtstatic u8 * eap_eke_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
72834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt{
72934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	struct eap_eke_data *data = priv;
73034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	u8 *key;
73134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
73234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	if (data->state != SUCCESS)
73334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		return NULL;
73434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
735d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt	key = os_memdup(data->emsk, EAP_EMSK_LEN);
73634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	if (key == NULL)
73734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		return NULL;
73834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	*len = EAP_EMSK_LEN;
73934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
74034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	return key;
74134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt}
74234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
74334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
7448bd70b7d6ba220544ee2f0e201e5df23e277fa1dDmitry Shmidtstatic u8 * eap_eke_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
7458bd70b7d6ba220544ee2f0e201e5df23e277fa1dDmitry Shmidt{
7468bd70b7d6ba220544ee2f0e201e5df23e277fa1dDmitry Shmidt	struct eap_eke_data *data = priv;
7478bd70b7d6ba220544ee2f0e201e5df23e277fa1dDmitry Shmidt	u8 *sid;
7488bd70b7d6ba220544ee2f0e201e5df23e277fa1dDmitry Shmidt	size_t sid_len;
7498bd70b7d6ba220544ee2f0e201e5df23e277fa1dDmitry Shmidt
7508bd70b7d6ba220544ee2f0e201e5df23e277fa1dDmitry Shmidt	if (data->state != SUCCESS)
7518bd70b7d6ba220544ee2f0e201e5df23e277fa1dDmitry Shmidt		return NULL;
7528bd70b7d6ba220544ee2f0e201e5df23e277fa1dDmitry Shmidt
7538bd70b7d6ba220544ee2f0e201e5df23e277fa1dDmitry Shmidt	sid_len = 1 + 2 * data->sess.nonce_len;
7548bd70b7d6ba220544ee2f0e201e5df23e277fa1dDmitry Shmidt	sid = os_malloc(sid_len);
7558bd70b7d6ba220544ee2f0e201e5df23e277fa1dDmitry Shmidt	if (sid == NULL)
7568bd70b7d6ba220544ee2f0e201e5df23e277fa1dDmitry Shmidt		return NULL;
7578bd70b7d6ba220544ee2f0e201e5df23e277fa1dDmitry Shmidt	sid[0] = EAP_TYPE_EKE;
7588bd70b7d6ba220544ee2f0e201e5df23e277fa1dDmitry Shmidt	os_memcpy(sid + 1, data->nonce_p, data->sess.nonce_len);
7598bd70b7d6ba220544ee2f0e201e5df23e277fa1dDmitry Shmidt	os_memcpy(sid + 1 + data->sess.nonce_len, data->nonce_s,
7608bd70b7d6ba220544ee2f0e201e5df23e277fa1dDmitry Shmidt		  data->sess.nonce_len);
7618bd70b7d6ba220544ee2f0e201e5df23e277fa1dDmitry Shmidt	*len = sid_len;
7628bd70b7d6ba220544ee2f0e201e5df23e277fa1dDmitry Shmidt
7638bd70b7d6ba220544ee2f0e201e5df23e277fa1dDmitry Shmidt	return sid;
7648bd70b7d6ba220544ee2f0e201e5df23e277fa1dDmitry Shmidt}
7658bd70b7d6ba220544ee2f0e201e5df23e277fa1dDmitry Shmidt
7668bd70b7d6ba220544ee2f0e201e5df23e277fa1dDmitry Shmidt
76734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidtint eap_peer_eke_register(void)
76834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt{
76934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	struct eap_method *eap;
77034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
77134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
77234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt				    EAP_VENDOR_IETF, EAP_TYPE_EKE, "EKE");
77334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	if (eap == NULL)
77434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		return -1;
77534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
77634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	eap->init = eap_eke_init;
77734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	eap->deinit = eap_eke_deinit;
77834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	eap->process = eap_eke_process;
77934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	eap->isKeyAvailable = eap_eke_isKeyAvailable;
78034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	eap->getKey = eap_eke_getKey;
78134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	eap->get_emsk = eap_eke_get_emsk;
7828bd70b7d6ba220544ee2f0e201e5df23e277fa1dDmitry Shmidt	eap->getSessionId = eap_eke_get_session_id;
78334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
7841d6bf427f4769edb60865a3999d01eeb8f8fcb19Dmitry Shmidt	return eap_peer_method_register(eap);
78534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt}
786