xref: /dflybsd-src/contrib/wpa_supplicant/src/eap_peer/eap_eke.c (revision 3a84a4273475ed07d0ab1c2dfeffdfedef35d9cd)
13ff40c12SJohn Marino /*
23ff40c12SJohn Marino  * EAP peer method: EAP-EKE (RFC 6124)
33ff40c12SJohn Marino  * Copyright (c) 2013, Jouni Malinen <j@w1.fi>
43ff40c12SJohn Marino  *
53ff40c12SJohn Marino  * This software may be distributed under the terms of the BSD license.
63ff40c12SJohn Marino  * See README for more details.
73ff40c12SJohn Marino  */
83ff40c12SJohn Marino 
93ff40c12SJohn Marino #include "includes.h"
103ff40c12SJohn Marino 
113ff40c12SJohn Marino #include "common.h"
123ff40c12SJohn Marino #include "crypto/random.h"
133ff40c12SJohn Marino #include "eap_peer/eap_i.h"
143ff40c12SJohn Marino #include "eap_common/eap_eke_common.h"
153ff40c12SJohn Marino 
163ff40c12SJohn Marino struct eap_eke_data {
173ff40c12SJohn Marino 	enum {
183ff40c12SJohn Marino 		IDENTITY, COMMIT, CONFIRM, SUCCESS, FAILURE
193ff40c12SJohn Marino 	} state;
203ff40c12SJohn Marino 	u8 msk[EAP_MSK_LEN];
213ff40c12SJohn Marino 	u8 emsk[EAP_EMSK_LEN];
223ff40c12SJohn Marino 	u8 *peerid;
233ff40c12SJohn Marino 	size_t peerid_len;
243ff40c12SJohn Marino 	u8 *serverid;
253ff40c12SJohn Marino 	size_t serverid_len;
263ff40c12SJohn Marino 	u8 dh_priv[EAP_EKE_MAX_DH_LEN];
273ff40c12SJohn Marino 	struct eap_eke_session sess;
283ff40c12SJohn Marino 	u8 nonce_p[EAP_EKE_MAX_NONCE_LEN];
293ff40c12SJohn Marino 	u8 nonce_s[EAP_EKE_MAX_NONCE_LEN];
303ff40c12SJohn Marino 	struct wpabuf *msgs;
313ff40c12SJohn Marino 	u8 dhgroup; /* forced DH group or 0 to allow all supported */
323ff40c12SJohn Marino 	u8 encr; /* forced encryption algorithm or 0 to allow all supported */
333ff40c12SJohn Marino 	u8 prf; /* forced PRF or 0 to allow all supported */
343ff40c12SJohn Marino 	u8 mac; /* forced MAC or 0 to allow all supported */
353ff40c12SJohn Marino };
363ff40c12SJohn Marino 
373ff40c12SJohn Marino 
eap_eke_state_txt(int state)383ff40c12SJohn Marino static const char * eap_eke_state_txt(int state)
393ff40c12SJohn Marino {
403ff40c12SJohn Marino 	switch (state) {
413ff40c12SJohn Marino 	case IDENTITY:
423ff40c12SJohn Marino 		return "IDENTITY";
433ff40c12SJohn Marino 	case COMMIT:
443ff40c12SJohn Marino 		return "COMMIT";
453ff40c12SJohn Marino 	case CONFIRM:
463ff40c12SJohn Marino 		return "CONFIRM";
473ff40c12SJohn Marino 	case SUCCESS:
483ff40c12SJohn Marino 		return "SUCCESS";
493ff40c12SJohn Marino 	case FAILURE:
503ff40c12SJohn Marino 		return "FAILURE";
513ff40c12SJohn Marino 	default:
523ff40c12SJohn Marino 		return "?";
533ff40c12SJohn Marino 	}
543ff40c12SJohn Marino }
553ff40c12SJohn Marino 
563ff40c12SJohn Marino 
eap_eke_state(struct eap_eke_data * data,int state)573ff40c12SJohn Marino static void eap_eke_state(struct eap_eke_data *data, int state)
583ff40c12SJohn Marino {
593ff40c12SJohn Marino 	wpa_printf(MSG_DEBUG, "EAP-EKE: %s -> %s",
603ff40c12SJohn Marino 		   eap_eke_state_txt(data->state), eap_eke_state_txt(state));
613ff40c12SJohn Marino 	data->state = state;
623ff40c12SJohn Marino }
633ff40c12SJohn Marino 
643ff40c12SJohn Marino 
653ff40c12SJohn Marino static void eap_eke_deinit(struct eap_sm *sm, void *priv);
663ff40c12SJohn Marino 
673ff40c12SJohn Marino 
eap_eke_init(struct eap_sm * sm)683ff40c12SJohn Marino static void * eap_eke_init(struct eap_sm *sm)
693ff40c12SJohn Marino {
703ff40c12SJohn Marino 	struct eap_eke_data *data;
713ff40c12SJohn Marino 	const u8 *identity, *password;
723ff40c12SJohn Marino 	size_t identity_len, password_len;
733ff40c12SJohn Marino 	const char *phase1;
743ff40c12SJohn Marino 
753ff40c12SJohn Marino 	password = eap_get_config_password(sm, &password_len);
763ff40c12SJohn Marino 	if (!password) {
773ff40c12SJohn Marino 		wpa_printf(MSG_INFO, "EAP-EKE: No password configured");
783ff40c12SJohn Marino 		return NULL;
793ff40c12SJohn Marino 	}
803ff40c12SJohn Marino 
813ff40c12SJohn Marino 	data = os_zalloc(sizeof(*data));
823ff40c12SJohn Marino 	if (data == NULL)
833ff40c12SJohn Marino 		return NULL;
843ff40c12SJohn Marino 	eap_eke_state(data, IDENTITY);
853ff40c12SJohn Marino 
863ff40c12SJohn Marino 	identity = eap_get_config_identity(sm, &identity_len);
873ff40c12SJohn Marino 	if (identity) {
88*a1157835SDaniel Fojt 		data->peerid = os_memdup(identity, identity_len);
893ff40c12SJohn Marino 		if (data->peerid == NULL) {
903ff40c12SJohn Marino 			eap_eke_deinit(sm, data);
913ff40c12SJohn Marino 			return NULL;
923ff40c12SJohn Marino 		}
933ff40c12SJohn Marino 		data->peerid_len = identity_len;
943ff40c12SJohn Marino 	}
953ff40c12SJohn Marino 
963ff40c12SJohn Marino 	phase1 = eap_get_config_phase1(sm);
973ff40c12SJohn Marino 	if (phase1) {
983ff40c12SJohn Marino 		const char *pos;
993ff40c12SJohn Marino 
1003ff40c12SJohn Marino 		pos = os_strstr(phase1, "dhgroup=");
1013ff40c12SJohn Marino 		if (pos) {
1023ff40c12SJohn Marino 			data->dhgroup = atoi(pos + 8);
1033ff40c12SJohn Marino 			wpa_printf(MSG_DEBUG, "EAP-EKE: Forced dhgroup %u",
1043ff40c12SJohn Marino 				   data->dhgroup);
1053ff40c12SJohn Marino 		}
1063ff40c12SJohn Marino 
1073ff40c12SJohn Marino 		pos = os_strstr(phase1, "encr=");
1083ff40c12SJohn Marino 		if (pos) {
1093ff40c12SJohn Marino 			data->encr = atoi(pos + 5);
1103ff40c12SJohn Marino 			wpa_printf(MSG_DEBUG, "EAP-EKE: Forced encr %u",
1113ff40c12SJohn Marino 				   data->encr);
1123ff40c12SJohn Marino 		}
1133ff40c12SJohn Marino 
1143ff40c12SJohn Marino 		pos = os_strstr(phase1, "prf=");
1153ff40c12SJohn Marino 		if (pos) {
1163ff40c12SJohn Marino 			data->prf = atoi(pos + 4);
1173ff40c12SJohn Marino 			wpa_printf(MSG_DEBUG, "EAP-EKE: Forced prf %u",
1183ff40c12SJohn Marino 				   data->prf);
1193ff40c12SJohn Marino 		}
1203ff40c12SJohn Marino 
1213ff40c12SJohn Marino 		pos = os_strstr(phase1, "mac=");
1223ff40c12SJohn Marino 		if (pos) {
1233ff40c12SJohn Marino 			data->mac = atoi(pos + 4);
1243ff40c12SJohn Marino 			wpa_printf(MSG_DEBUG, "EAP-EKE: Forced mac %u",
1253ff40c12SJohn Marino 				   data->mac);
1263ff40c12SJohn Marino 		}
1273ff40c12SJohn Marino 	}
1283ff40c12SJohn Marino 
1293ff40c12SJohn Marino 	return data;
1303ff40c12SJohn Marino }
1313ff40c12SJohn Marino 
1323ff40c12SJohn Marino 
eap_eke_deinit(struct eap_sm * sm,void * priv)1333ff40c12SJohn Marino static void eap_eke_deinit(struct eap_sm *sm, void *priv)
1343ff40c12SJohn Marino {
1353ff40c12SJohn Marino 	struct eap_eke_data *data = priv;
1363ff40c12SJohn Marino 	eap_eke_session_clean(&data->sess);
1373ff40c12SJohn Marino 	os_free(data->serverid);
1383ff40c12SJohn Marino 	os_free(data->peerid);
1393ff40c12SJohn Marino 	wpabuf_free(data->msgs);
140*a1157835SDaniel Fojt 	bin_clear_free(data, sizeof(*data));
1413ff40c12SJohn Marino }
1423ff40c12SJohn Marino 
1433ff40c12SJohn Marino 
eap_eke_build_msg(struct eap_eke_data * data,int id,size_t length,u8 eke_exch)1443ff40c12SJohn Marino static struct wpabuf * eap_eke_build_msg(struct eap_eke_data *data, int id,
1453ff40c12SJohn Marino 					 size_t length, u8 eke_exch)
1463ff40c12SJohn Marino {
1473ff40c12SJohn Marino 	struct wpabuf *msg;
1483ff40c12SJohn Marino 	size_t plen;
1493ff40c12SJohn Marino 
1503ff40c12SJohn Marino 	plen = 1 + length;
1513ff40c12SJohn Marino 
1523ff40c12SJohn Marino 	msg = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_EKE, plen,
1533ff40c12SJohn Marino 			    EAP_CODE_RESPONSE, id);
1543ff40c12SJohn Marino 	if (msg == NULL) {
1553ff40c12SJohn Marino 		wpa_printf(MSG_ERROR, "EAP-EKE: Failed to allocate memory");
1563ff40c12SJohn Marino 		return NULL;
1573ff40c12SJohn Marino 	}
1583ff40c12SJohn Marino 
1593ff40c12SJohn Marino 	wpabuf_put_u8(msg, eke_exch);
1603ff40c12SJohn Marino 
1613ff40c12SJohn Marino 	return msg;
1623ff40c12SJohn Marino }
1633ff40c12SJohn Marino 
1643ff40c12SJohn Marino 
eap_eke_supp_dhgroup(u8 dhgroup)1653ff40c12SJohn Marino static int eap_eke_supp_dhgroup(u8 dhgroup)
1663ff40c12SJohn Marino {
1673ff40c12SJohn Marino 	return dhgroup == EAP_EKE_DHGROUP_EKE_2 ||
1683ff40c12SJohn Marino 		dhgroup == EAP_EKE_DHGROUP_EKE_5 ||
1693ff40c12SJohn Marino 		dhgroup == EAP_EKE_DHGROUP_EKE_14 ||
1703ff40c12SJohn Marino 		dhgroup == EAP_EKE_DHGROUP_EKE_15 ||
1713ff40c12SJohn Marino 		dhgroup == EAP_EKE_DHGROUP_EKE_16;
1723ff40c12SJohn Marino }
1733ff40c12SJohn Marino 
1743ff40c12SJohn Marino 
eap_eke_supp_encr(u8 encr)1753ff40c12SJohn Marino static int eap_eke_supp_encr(u8 encr)
1763ff40c12SJohn Marino {
1773ff40c12SJohn Marino 	return encr == EAP_EKE_ENCR_AES128_CBC;
1783ff40c12SJohn Marino }
1793ff40c12SJohn Marino 
1803ff40c12SJohn Marino 
eap_eke_supp_prf(u8 prf)1813ff40c12SJohn Marino static int eap_eke_supp_prf(u8 prf)
1823ff40c12SJohn Marino {
1833ff40c12SJohn Marino 	return prf == EAP_EKE_PRF_HMAC_SHA1 ||
1843ff40c12SJohn Marino 		prf == EAP_EKE_PRF_HMAC_SHA2_256;
1853ff40c12SJohn Marino }
1863ff40c12SJohn Marino 
1873ff40c12SJohn Marino 
eap_eke_supp_mac(u8 mac)1883ff40c12SJohn Marino static int eap_eke_supp_mac(u8 mac)
1893ff40c12SJohn Marino {
1903ff40c12SJohn Marino 	return mac == EAP_EKE_MAC_HMAC_SHA1 ||
1913ff40c12SJohn Marino 		mac == EAP_EKE_MAC_HMAC_SHA2_256;
1923ff40c12SJohn Marino }
1933ff40c12SJohn Marino 
1943ff40c12SJohn Marino 
eap_eke_build_fail(struct eap_eke_data * data,struct eap_method_ret * ret,u8 id,u32 failure_code)1953ff40c12SJohn Marino static struct wpabuf * eap_eke_build_fail(struct eap_eke_data *data,
1963ff40c12SJohn Marino 					  struct eap_method_ret *ret,
197*a1157835SDaniel Fojt 					  u8 id, u32 failure_code)
1983ff40c12SJohn Marino {
1993ff40c12SJohn Marino 	struct wpabuf *resp;
2003ff40c12SJohn Marino 
2013ff40c12SJohn Marino 	wpa_printf(MSG_DEBUG, "EAP-EKE: Sending EAP-EKE-Failure/Response - code=0x%x",
2023ff40c12SJohn Marino 		   failure_code);
2033ff40c12SJohn Marino 
204*a1157835SDaniel Fojt 	resp = eap_eke_build_msg(data, id, 4, EAP_EKE_FAILURE);
2053ff40c12SJohn Marino 	if (resp)
2063ff40c12SJohn Marino 		wpabuf_put_be32(resp, failure_code);
2073ff40c12SJohn Marino 
2083ff40c12SJohn Marino 	os_memset(data->dh_priv, 0, sizeof(data->dh_priv));
2093ff40c12SJohn Marino 	eap_eke_session_clean(&data->sess);
2103ff40c12SJohn Marino 
2113ff40c12SJohn Marino 	eap_eke_state(data, FAILURE);
2123ff40c12SJohn Marino 	ret->methodState = METHOD_DONE;
2133ff40c12SJohn Marino 	ret->decision = DECISION_FAIL;
2143ff40c12SJohn Marino 	ret->allowNotifications = FALSE;
2153ff40c12SJohn Marino 
2163ff40c12SJohn Marino 	return resp;
2173ff40c12SJohn Marino }
2183ff40c12SJohn Marino 
2193ff40c12SJohn Marino 
eap_eke_process_id(struct eap_eke_data * data,struct eap_method_ret * ret,const struct wpabuf * reqData,const u8 * payload,size_t payload_len)2203ff40c12SJohn Marino static struct wpabuf * eap_eke_process_id(struct eap_eke_data *data,
2213ff40c12SJohn Marino 					  struct eap_method_ret *ret,
2223ff40c12SJohn Marino 					  const struct wpabuf *reqData,
2233ff40c12SJohn Marino 					  const u8 *payload,
2243ff40c12SJohn Marino 					  size_t payload_len)
2253ff40c12SJohn Marino {
2263ff40c12SJohn Marino 	struct wpabuf *resp;
2273ff40c12SJohn Marino 	unsigned num_prop, i;
2283ff40c12SJohn Marino 	const u8 *pos, *end;
2293ff40c12SJohn Marino 	const u8 *prop = NULL;
2303ff40c12SJohn Marino 	u8 idtype;
231*a1157835SDaniel Fojt 	u8 id = eap_get_id(reqData);
2323ff40c12SJohn Marino 
2333ff40c12SJohn Marino 	if (data->state != IDENTITY) {
234*a1157835SDaniel Fojt 		return eap_eke_build_fail(data, ret, id,
2353ff40c12SJohn Marino 					  EAP_EKE_FAIL_PROTO_ERROR);
2363ff40c12SJohn Marino 	}
2373ff40c12SJohn Marino 
2383ff40c12SJohn Marino 	wpa_printf(MSG_DEBUG, "EAP-EKE: Received EAP-EKE-ID/Request");
2393ff40c12SJohn Marino 
2403ff40c12SJohn Marino 	if (payload_len < 2 + 4) {
2413ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "EAP-EKE: Too short ID/Request Data");
242*a1157835SDaniel Fojt 		return eap_eke_build_fail(data, ret, id,
2433ff40c12SJohn Marino 					  EAP_EKE_FAIL_PROTO_ERROR);
2443ff40c12SJohn Marino 	}
2453ff40c12SJohn Marino 
2463ff40c12SJohn Marino 	pos = payload;
2473ff40c12SJohn Marino 	end = payload + payload_len;
2483ff40c12SJohn Marino 
2493ff40c12SJohn Marino 	num_prop = *pos++;
2503ff40c12SJohn Marino 	pos++; /* Ignore Reserved field */
2513ff40c12SJohn Marino 
2523ff40c12SJohn Marino 	if (pos + num_prop * 4 > end) {
2533ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "EAP-EKE: Too short ID/Request Data (num_prop=%u)",
2543ff40c12SJohn Marino 			   num_prop);
255*a1157835SDaniel Fojt 		return eap_eke_build_fail(data, ret, id,
2563ff40c12SJohn Marino 					  EAP_EKE_FAIL_PROTO_ERROR);
2573ff40c12SJohn Marino 	}
2583ff40c12SJohn Marino 
2593ff40c12SJohn Marino 	for (i = 0; i < num_prop; i++) {
2603ff40c12SJohn Marino 		const u8 *tmp = pos;
2613ff40c12SJohn Marino 
2623ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "EAP-EKE: Proposal #%u: dh=%u encr=%u prf=%u mac=%u",
2633ff40c12SJohn Marino 			   i, pos[0], pos[1], pos[2], pos[3]);
2643ff40c12SJohn Marino 		pos += 4;
2653ff40c12SJohn Marino 
2663ff40c12SJohn Marino 		if ((data->dhgroup && data->dhgroup != *tmp) ||
2673ff40c12SJohn Marino 		    !eap_eke_supp_dhgroup(*tmp))
2683ff40c12SJohn Marino 			continue;
2693ff40c12SJohn Marino 		tmp++;
2703ff40c12SJohn Marino 		if ((data->encr && data->encr != *tmp) ||
2713ff40c12SJohn Marino 		    !eap_eke_supp_encr(*tmp))
2723ff40c12SJohn Marino 			continue;
2733ff40c12SJohn Marino 		tmp++;
2743ff40c12SJohn Marino 		if ((data->prf && data->prf != *tmp) ||
2753ff40c12SJohn Marino 		    !eap_eke_supp_prf(*tmp))
2763ff40c12SJohn Marino 			continue;
2773ff40c12SJohn Marino 		tmp++;
2783ff40c12SJohn Marino 		if ((data->mac && data->mac != *tmp) ||
2793ff40c12SJohn Marino 		    !eap_eke_supp_mac(*tmp))
2803ff40c12SJohn Marino 			continue;
2813ff40c12SJohn Marino 
2823ff40c12SJohn Marino 		prop = tmp - 3;
2833ff40c12SJohn Marino 		if (eap_eke_session_init(&data->sess, prop[0], prop[1], prop[2],
2843ff40c12SJohn Marino 					 prop[3]) < 0) {
2853ff40c12SJohn Marino 			prop = NULL;
2863ff40c12SJohn Marino 			continue;
2873ff40c12SJohn Marino 		}
2883ff40c12SJohn Marino 
2893ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "EAP-EKE: Selected proposal");
2903ff40c12SJohn Marino 		break;
2913ff40c12SJohn Marino 	}
2923ff40c12SJohn Marino 
2933ff40c12SJohn Marino 	if (prop == NULL) {
2943ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "EAP-EKE: No acceptable proposal found");
295*a1157835SDaniel Fojt 		return eap_eke_build_fail(data, ret, id,
2963ff40c12SJohn Marino 					  EAP_EKE_FAIL_NO_PROPOSAL_CHOSEN);
2973ff40c12SJohn Marino 	}
2983ff40c12SJohn Marino 
2993ff40c12SJohn Marino 	pos += (num_prop - i - 1) * 4;
3003ff40c12SJohn Marino 
3013ff40c12SJohn Marino 	if (pos == end) {
3023ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "EAP-EKE: Too short ID/Request Data to include IDType/Identity");
303*a1157835SDaniel Fojt 		return eap_eke_build_fail(data, ret, id,
3043ff40c12SJohn Marino 					  EAP_EKE_FAIL_PROTO_ERROR);
3053ff40c12SJohn Marino 	}
3063ff40c12SJohn Marino 
3073ff40c12SJohn Marino 	idtype = *pos++;
3083ff40c12SJohn Marino 	wpa_printf(MSG_DEBUG, "EAP-EKE: Server IDType %u", idtype);
3093ff40c12SJohn Marino 	wpa_hexdump_ascii(MSG_DEBUG, "EAP-EKE: Server Identity",
3103ff40c12SJohn Marino 			  pos, end - pos);
3113ff40c12SJohn Marino 	os_free(data->serverid);
312*a1157835SDaniel Fojt 	data->serverid = os_memdup(pos, end - pos);
3133ff40c12SJohn Marino 	if (data->serverid == NULL) {
314*a1157835SDaniel Fojt 		return eap_eke_build_fail(data, ret, id,
3153ff40c12SJohn Marino 					  EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
3163ff40c12SJohn Marino 	}
3173ff40c12SJohn Marino 	data->serverid_len = end - pos;
3183ff40c12SJohn Marino 
3193ff40c12SJohn Marino 	wpa_printf(MSG_DEBUG, "EAP-EKE: Sending EAP-EKE-ID/Response");
3203ff40c12SJohn Marino 
321*a1157835SDaniel Fojt 	resp = eap_eke_build_msg(data, id,
3223ff40c12SJohn Marino 				 2 + 4 + 1 + data->peerid_len,
3233ff40c12SJohn Marino 				 EAP_EKE_ID);
3243ff40c12SJohn Marino 	if (resp == NULL) {
325*a1157835SDaniel Fojt 		return eap_eke_build_fail(data, ret, id,
3263ff40c12SJohn Marino 					  EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
3273ff40c12SJohn Marino 	}
3283ff40c12SJohn Marino 
3293ff40c12SJohn Marino 	wpabuf_put_u8(resp, 1); /* NumProposals */
3303ff40c12SJohn Marino 	wpabuf_put_u8(resp, 0); /* Reserved */
3313ff40c12SJohn Marino 	wpabuf_put_data(resp, prop, 4); /* Selected Proposal */
3323ff40c12SJohn Marino 	wpabuf_put_u8(resp, EAP_EKE_ID_NAI);
3333ff40c12SJohn Marino 	if (data->peerid)
3343ff40c12SJohn Marino 		wpabuf_put_data(resp, data->peerid, data->peerid_len);
3353ff40c12SJohn Marino 
3363ff40c12SJohn Marino 	wpabuf_free(data->msgs);
3373ff40c12SJohn Marino 	data->msgs = wpabuf_alloc(wpabuf_len(reqData) + wpabuf_len(resp));
3383ff40c12SJohn Marino 	if (data->msgs == NULL) {
3393ff40c12SJohn Marino 		wpabuf_free(resp);
340*a1157835SDaniel Fojt 		return eap_eke_build_fail(data, ret, id,
3413ff40c12SJohn Marino 					  EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
3423ff40c12SJohn Marino 	}
3433ff40c12SJohn Marino 	wpabuf_put_buf(data->msgs, reqData);
3443ff40c12SJohn Marino 	wpabuf_put_buf(data->msgs, resp);
3453ff40c12SJohn Marino 
3463ff40c12SJohn Marino 	eap_eke_state(data, COMMIT);
3473ff40c12SJohn Marino 
3483ff40c12SJohn Marino 	return resp;
3493ff40c12SJohn Marino }
3503ff40c12SJohn Marino 
3513ff40c12SJohn Marino 
eap_eke_process_commit(struct eap_sm * sm,struct eap_eke_data * data,struct eap_method_ret * ret,const struct wpabuf * reqData,const u8 * payload,size_t payload_len)3523ff40c12SJohn Marino static struct wpabuf * eap_eke_process_commit(struct eap_sm *sm,
3533ff40c12SJohn Marino 					      struct eap_eke_data *data,
3543ff40c12SJohn Marino 					      struct eap_method_ret *ret,
3553ff40c12SJohn Marino 					      const struct wpabuf *reqData,
3563ff40c12SJohn Marino 					      const u8 *payload,
3573ff40c12SJohn Marino 					      size_t payload_len)
3583ff40c12SJohn Marino {
3593ff40c12SJohn Marino 	struct wpabuf *resp;
3603ff40c12SJohn Marino 	const u8 *pos, *end, *dhcomp;
3613ff40c12SJohn Marino 	size_t prot_len;
3623ff40c12SJohn Marino 	u8 *rpos;
3633ff40c12SJohn Marino 	u8 key[EAP_EKE_MAX_KEY_LEN];
3643ff40c12SJohn Marino 	u8 pub[EAP_EKE_MAX_DH_LEN];
3653ff40c12SJohn Marino 	const u8 *password;
3663ff40c12SJohn Marino 	size_t password_len;
367*a1157835SDaniel Fojt 	u8 id = eap_get_id(reqData);
3683ff40c12SJohn Marino 
3693ff40c12SJohn Marino 	if (data->state != COMMIT) {
3703ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "EAP-EKE: EAP-EKE-Commit/Request received in unexpected state (%d)", data->state);
371*a1157835SDaniel Fojt 		return eap_eke_build_fail(data, ret, id,
3723ff40c12SJohn Marino 					  EAP_EKE_FAIL_PROTO_ERROR);
3733ff40c12SJohn Marino 	}
3743ff40c12SJohn Marino 
3753ff40c12SJohn Marino 	wpa_printf(MSG_DEBUG, "EAP-EKE: Received EAP-EKE-Commit/Request");
3763ff40c12SJohn Marino 
3773ff40c12SJohn Marino 	password = eap_get_config_password(sm, &password_len);
3783ff40c12SJohn Marino 	if (password == NULL) {
3793ff40c12SJohn Marino 		wpa_printf(MSG_INFO, "EAP-EKE: No password configured!");
380*a1157835SDaniel Fojt 		return eap_eke_build_fail(data, ret, id,
3813ff40c12SJohn Marino 					  EAP_EKE_FAIL_PASSWD_NOT_FOUND);
3823ff40c12SJohn Marino 	}
3833ff40c12SJohn Marino 
3843ff40c12SJohn Marino 	pos = payload;
3853ff40c12SJohn Marino 	end = payload + payload_len;
3863ff40c12SJohn Marino 
3873ff40c12SJohn Marino 	if (pos + data->sess.dhcomp_len > end) {
3883ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "EAP-EKE: Too short EAP-EKE-Commit");
389*a1157835SDaniel Fojt 		return eap_eke_build_fail(data, ret, id,
3903ff40c12SJohn Marino 					  EAP_EKE_FAIL_PROTO_ERROR);
3913ff40c12SJohn Marino 	}
3923ff40c12SJohn Marino 
3933ff40c12SJohn Marino 	wpa_hexdump(MSG_DEBUG, "EAP-EKE: DHComponent_S",
3943ff40c12SJohn Marino 		    pos, data->sess.dhcomp_len);
3953ff40c12SJohn Marino 	dhcomp = pos;
3963ff40c12SJohn Marino 	pos += data->sess.dhcomp_len;
3973ff40c12SJohn Marino 	wpa_hexdump(MSG_DEBUG, "EAP-EKE: CBValue", pos, end - pos);
3983ff40c12SJohn Marino 
3993ff40c12SJohn Marino 	/*
4003ff40c12SJohn Marino 	 * temp = prf(0+, password)
4013ff40c12SJohn Marino 	 * key = prf+(temp, ID_S | ID_P)
4023ff40c12SJohn Marino 	 */
4033ff40c12SJohn Marino 	if (eap_eke_derive_key(&data->sess, password, password_len,
4043ff40c12SJohn Marino 			       data->serverid, data->serverid_len,
4053ff40c12SJohn Marino 			       data->peerid, data->peerid_len, key) < 0) {
4063ff40c12SJohn Marino 		wpa_printf(MSG_INFO, "EAP-EKE: Failed to derive key");
407*a1157835SDaniel Fojt 		return eap_eke_build_fail(data, ret, id,
4083ff40c12SJohn Marino 					  EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
4093ff40c12SJohn Marino 	}
4103ff40c12SJohn Marino 
4113ff40c12SJohn Marino 	/*
4123ff40c12SJohn Marino 	 * y_p = g ^ x_p (mod p)
4133ff40c12SJohn Marino 	 * x_p = random number 2 .. p-1
4143ff40c12SJohn Marino 	 */
4153ff40c12SJohn Marino 	if (eap_eke_dh_init(data->sess.dhgroup, data->dh_priv, pub) < 0) {
4163ff40c12SJohn Marino 		wpa_printf(MSG_INFO, "EAP-EKE: Failed to initialize DH");
417*a1157835SDaniel Fojt 		forced_memzero(key, sizeof(key));
418*a1157835SDaniel Fojt 		return eap_eke_build_fail(data, ret, id,
4193ff40c12SJohn Marino 					  EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
4203ff40c12SJohn Marino 	}
4213ff40c12SJohn Marino 
4223ff40c12SJohn Marino 	if (eap_eke_shared_secret(&data->sess, key, data->dh_priv, dhcomp) < 0)
4233ff40c12SJohn Marino 	{
4243ff40c12SJohn Marino 		wpa_printf(MSG_INFO, "EAP-EKE: Failed to derive shared secret");
425*a1157835SDaniel Fojt 		forced_memzero(key, sizeof(key));
426*a1157835SDaniel Fojt 		return eap_eke_build_fail(data, ret, id,
4273ff40c12SJohn Marino 					  EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
4283ff40c12SJohn Marino 	}
4293ff40c12SJohn Marino 
4303ff40c12SJohn Marino 	if (eap_eke_derive_ke_ki(&data->sess,
4313ff40c12SJohn Marino 				 data->serverid, data->serverid_len,
4323ff40c12SJohn Marino 				 data->peerid, data->peerid_len) < 0) {
4333ff40c12SJohn Marino 		wpa_printf(MSG_INFO, "EAP-EKE: Failed to derive Ke/Ki");
434*a1157835SDaniel Fojt 		forced_memzero(key, sizeof(key));
435*a1157835SDaniel Fojt 		return eap_eke_build_fail(data, ret, id,
4363ff40c12SJohn Marino 					  EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
4373ff40c12SJohn Marino 	}
4383ff40c12SJohn Marino 
4393ff40c12SJohn Marino 	wpa_printf(MSG_DEBUG, "EAP-EKE: Sending EAP-EKE-Commit/Response");
4403ff40c12SJohn Marino 
441*a1157835SDaniel Fojt 	resp = eap_eke_build_msg(data, id,
4423ff40c12SJohn Marino 				 data->sess.dhcomp_len + data->sess.pnonce_len,
4433ff40c12SJohn Marino 				 EAP_EKE_COMMIT);
4443ff40c12SJohn Marino 	if (resp == NULL) {
445*a1157835SDaniel Fojt 		forced_memzero(key, sizeof(key));
446*a1157835SDaniel Fojt 		return eap_eke_build_fail(data, ret, id,
4473ff40c12SJohn Marino 					  EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
4483ff40c12SJohn Marino 	}
4493ff40c12SJohn Marino 
4503ff40c12SJohn Marino 	/* DHComponent_P = Encr(key, y_p) */
4513ff40c12SJohn Marino 	rpos = wpabuf_put(resp, data->sess.dhcomp_len);
4523ff40c12SJohn Marino 	if (eap_eke_dhcomp(&data->sess, key, pub, rpos) < 0) {
453*a1157835SDaniel Fojt 		wpabuf_free(resp);
454*a1157835SDaniel Fojt 		wpa_printf(MSG_INFO, "EAP-EKE: Failed to build DHComponent_P");
455*a1157835SDaniel Fojt 		forced_memzero(key, sizeof(key));
456*a1157835SDaniel Fojt 		return eap_eke_build_fail(data, ret, id,
4573ff40c12SJohn Marino 					  EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
4583ff40c12SJohn Marino 	}
459*a1157835SDaniel Fojt 	forced_memzero(key, sizeof(key));
4603ff40c12SJohn Marino 
4613ff40c12SJohn Marino 	wpa_hexdump(MSG_DEBUG, "EAP-EKE: DHComponent_P",
4623ff40c12SJohn Marino 		    rpos, data->sess.dhcomp_len);
4633ff40c12SJohn Marino 
4643ff40c12SJohn Marino 	if (random_get_bytes(data->nonce_p, data->sess.nonce_len)) {
4653ff40c12SJohn Marino 		wpabuf_free(resp);
466*a1157835SDaniel Fojt 		return eap_eke_build_fail(data, ret, id,
4673ff40c12SJohn Marino 					  EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
4683ff40c12SJohn Marino 	}
4693ff40c12SJohn Marino 	wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: Nonce_P",
4703ff40c12SJohn Marino 			data->nonce_p, data->sess.nonce_len);
4713ff40c12SJohn Marino 	prot_len = wpabuf_tailroom(resp);
4723ff40c12SJohn Marino 	if (eap_eke_prot(&data->sess, data->nonce_p, data->sess.nonce_len,
4733ff40c12SJohn Marino 			 wpabuf_put(resp, 0), &prot_len) < 0) {
4743ff40c12SJohn Marino 		wpabuf_free(resp);
475*a1157835SDaniel Fojt 		return eap_eke_build_fail(data, ret, id,
4763ff40c12SJohn Marino 					  EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
4773ff40c12SJohn Marino 	}
4783ff40c12SJohn Marino 	wpa_hexdump(MSG_DEBUG, "EAP-EKE: PNonce_P",
4793ff40c12SJohn Marino 		    wpabuf_put(resp, 0), prot_len);
4803ff40c12SJohn Marino 	wpabuf_put(resp, prot_len);
4813ff40c12SJohn Marino 
4823ff40c12SJohn Marino 	/* TODO: CBValue */
4833ff40c12SJohn Marino 
4843ff40c12SJohn Marino 	if (wpabuf_resize(&data->msgs, wpabuf_len(reqData) + wpabuf_len(resp))
4853ff40c12SJohn Marino 	    < 0) {
4863ff40c12SJohn Marino 		wpabuf_free(resp);
487*a1157835SDaniel Fojt 		return eap_eke_build_fail(data, ret, id,
4883ff40c12SJohn Marino 					  EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
4893ff40c12SJohn Marino 	}
4903ff40c12SJohn Marino 	wpabuf_put_buf(data->msgs, reqData);
4913ff40c12SJohn Marino 	wpabuf_put_buf(data->msgs, resp);
4923ff40c12SJohn Marino 
4933ff40c12SJohn Marino 	eap_eke_state(data, CONFIRM);
4943ff40c12SJohn Marino 
4953ff40c12SJohn Marino 	return resp;
4963ff40c12SJohn Marino }
4973ff40c12SJohn Marino 
4983ff40c12SJohn Marino 
eap_eke_process_confirm(struct eap_eke_data * data,struct eap_method_ret * ret,const struct wpabuf * reqData,const u8 * payload,size_t payload_len)4993ff40c12SJohn Marino static struct wpabuf * eap_eke_process_confirm(struct eap_eke_data *data,
5003ff40c12SJohn Marino 					       struct eap_method_ret *ret,
5013ff40c12SJohn Marino 					       const struct wpabuf *reqData,
5023ff40c12SJohn Marino 					       const u8 *payload,
5033ff40c12SJohn Marino 					       size_t payload_len)
5043ff40c12SJohn Marino {
5053ff40c12SJohn Marino 	struct wpabuf *resp;
5063ff40c12SJohn Marino 	const u8 *pos, *end;
5073ff40c12SJohn Marino 	size_t prot_len;
5083ff40c12SJohn Marino 	u8 nonces[2 * EAP_EKE_MAX_NONCE_LEN];
5093ff40c12SJohn Marino 	u8 auth_s[EAP_EKE_MAX_HASH_LEN];
5103ff40c12SJohn Marino 	size_t decrypt_len;
5113ff40c12SJohn Marino 	u8 *auth;
512*a1157835SDaniel Fojt 	u8 id = eap_get_id(reqData);
5133ff40c12SJohn Marino 
5143ff40c12SJohn Marino 	if (data->state != CONFIRM) {
5153ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "EAP-EKE: EAP-EKE-Confirm/Request received in unexpected state (%d)",
5163ff40c12SJohn Marino 			   data->state);
517*a1157835SDaniel Fojt 		return eap_eke_build_fail(data, ret, id,
5183ff40c12SJohn Marino 					  EAP_EKE_FAIL_PROTO_ERROR);
5193ff40c12SJohn Marino 	}
5203ff40c12SJohn Marino 
5213ff40c12SJohn Marino 	wpa_printf(MSG_DEBUG, "EAP-EKE: Received EAP-EKE-Confirm/Request");
5223ff40c12SJohn Marino 
5233ff40c12SJohn Marino 	pos = payload;
5243ff40c12SJohn Marino 	end = payload + payload_len;
5253ff40c12SJohn Marino 
5263ff40c12SJohn Marino 	if (pos + data->sess.pnonce_ps_len + data->sess.prf_len > end) {
527*a1157835SDaniel Fojt 		wpa_printf(MSG_DEBUG, "EAP-EKE: Too short EAP-EKE-Confirm");
528*a1157835SDaniel Fojt 		return eap_eke_build_fail(data, ret, id,
5293ff40c12SJohn Marino 					  EAP_EKE_FAIL_PROTO_ERROR);
5303ff40c12SJohn Marino 	}
5313ff40c12SJohn Marino 
5323ff40c12SJohn Marino 	decrypt_len = sizeof(nonces);
5333ff40c12SJohn Marino 	if (eap_eke_decrypt_prot(&data->sess, pos, data->sess.pnonce_ps_len,
5343ff40c12SJohn Marino 				 nonces, &decrypt_len) < 0) {
5353ff40c12SJohn Marino 		wpa_printf(MSG_INFO, "EAP-EKE: Failed to decrypt PNonce_PS");
536*a1157835SDaniel Fojt 		return eap_eke_build_fail(data, ret, id,
5373ff40c12SJohn Marino 					  EAP_EKE_FAIL_AUTHENTICATION_FAIL);
5383ff40c12SJohn Marino 	}
5393ff40c12SJohn Marino 	if (decrypt_len != (size_t) 2 * data->sess.nonce_len) {
5403ff40c12SJohn Marino 		wpa_printf(MSG_INFO, "EAP-EKE: PNonce_PS protected data length does not match length of Nonce_P and Nonce_S");
541*a1157835SDaniel Fojt 		return eap_eke_build_fail(data, ret, id,
5423ff40c12SJohn Marino 					  EAP_EKE_FAIL_AUTHENTICATION_FAIL);
5433ff40c12SJohn Marino 	}
5443ff40c12SJohn Marino 	wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: Received Nonce_P | Nonce_S",
5453ff40c12SJohn Marino 			nonces, 2 * data->sess.nonce_len);
5463ff40c12SJohn Marino 	if (os_memcmp(data->nonce_p, nonces, data->sess.nonce_len) != 0) {
547*a1157835SDaniel Fojt 		wpa_printf(MSG_INFO, "EAP-EKE: Received Nonce_P does not match transmitted Nonce_P");
548*a1157835SDaniel Fojt 		return eap_eke_build_fail(data, ret, id,
5493ff40c12SJohn Marino 					  EAP_EKE_FAIL_AUTHENTICATION_FAIL);
5503ff40c12SJohn Marino 	}
5513ff40c12SJohn Marino 
5523ff40c12SJohn Marino 	os_memcpy(data->nonce_s, nonces + data->sess.nonce_len,
5533ff40c12SJohn Marino 		  data->sess.nonce_len);
5543ff40c12SJohn Marino 	wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: Nonce_S",
5553ff40c12SJohn Marino 			data->nonce_s, data->sess.nonce_len);
5563ff40c12SJohn Marino 
5573ff40c12SJohn Marino 	if (eap_eke_derive_ka(&data->sess, data->serverid, data->serverid_len,
5583ff40c12SJohn Marino 			      data->peerid, data->peerid_len,
5593ff40c12SJohn Marino 			      data->nonce_p, data->nonce_s) < 0) {
560*a1157835SDaniel Fojt 		return eap_eke_build_fail(data, ret, id,
5613ff40c12SJohn Marino 					  EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
5623ff40c12SJohn Marino 	}
5633ff40c12SJohn Marino 
5643ff40c12SJohn Marino 	if (eap_eke_auth(&data->sess, "EAP-EKE server", data->msgs, auth_s) < 0)
5653ff40c12SJohn Marino 	{
566*a1157835SDaniel Fojt 		return eap_eke_build_fail(data, ret, id,
5673ff40c12SJohn Marino 					  EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
5683ff40c12SJohn Marino 	}
5693ff40c12SJohn Marino 	wpa_hexdump(MSG_DEBUG, "EAP-EKE: Auth_S", auth_s, data->sess.prf_len);
570*a1157835SDaniel Fojt 	if (os_memcmp_const(auth_s, pos + data->sess.pnonce_ps_len,
5713ff40c12SJohn Marino 			    data->sess.prf_len) != 0) {
5723ff40c12SJohn Marino 		wpa_printf(MSG_INFO, "EAP-EKE: Auth_S does not match");
573*a1157835SDaniel Fojt 		return eap_eke_build_fail(data, ret, id,
5743ff40c12SJohn Marino 					  EAP_EKE_FAIL_AUTHENTICATION_FAIL);
5753ff40c12SJohn Marino 	}
5763ff40c12SJohn Marino 
5773ff40c12SJohn Marino 	wpa_printf(MSG_DEBUG, "EAP-EKE: Sending EAP-EKE-Confirm/Response");
5783ff40c12SJohn Marino 
579*a1157835SDaniel Fojt 	resp = eap_eke_build_msg(data, id,
5803ff40c12SJohn Marino 				 data->sess.pnonce_len + data->sess.prf_len,
5813ff40c12SJohn Marino 				 EAP_EKE_CONFIRM);
5823ff40c12SJohn Marino 	if (resp == NULL) {
583*a1157835SDaniel Fojt 		return eap_eke_build_fail(data, ret, id,
5843ff40c12SJohn Marino 					  EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
5853ff40c12SJohn Marino 	}
5863ff40c12SJohn Marino 
5873ff40c12SJohn Marino 	prot_len = wpabuf_tailroom(resp);
5883ff40c12SJohn Marino 	if (eap_eke_prot(&data->sess, data->nonce_s, data->sess.nonce_len,
5893ff40c12SJohn Marino 			 wpabuf_put(resp, 0), &prot_len) < 0) {
5903ff40c12SJohn Marino 		wpabuf_free(resp);
591*a1157835SDaniel Fojt 		return eap_eke_build_fail(data, ret, id,
5923ff40c12SJohn Marino 					  EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
5933ff40c12SJohn Marino 	}
5943ff40c12SJohn Marino 	wpabuf_put(resp, prot_len);
5953ff40c12SJohn Marino 
5963ff40c12SJohn Marino 	auth = wpabuf_put(resp, data->sess.prf_len);
5973ff40c12SJohn Marino 	if (eap_eke_auth(&data->sess, "EAP-EKE peer", data->msgs, auth) < 0) {
5983ff40c12SJohn Marino 		wpabuf_free(resp);
599*a1157835SDaniel Fojt 		return eap_eke_build_fail(data, ret, id,
6003ff40c12SJohn Marino 					  EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
6013ff40c12SJohn Marino 	}
6023ff40c12SJohn Marino 	wpa_hexdump(MSG_DEBUG, "EAP-EKE: Auth_P", auth, data->sess.prf_len);
6033ff40c12SJohn Marino 
6043ff40c12SJohn Marino 	if (eap_eke_derive_msk(&data->sess, data->serverid, data->serverid_len,
6053ff40c12SJohn Marino 			       data->peerid, data->peerid_len,
6063ff40c12SJohn Marino 			       data->nonce_s, data->nonce_p,
6073ff40c12SJohn Marino 			       data->msk, data->emsk) < 0) {
6083ff40c12SJohn Marino 		wpa_printf(MSG_INFO, "EAP-EKE: Failed to derive MSK/EMSK");
6093ff40c12SJohn Marino 		wpabuf_free(resp);
610*a1157835SDaniel Fojt 		return eap_eke_build_fail(data, ret, id,
6113ff40c12SJohn Marino 					  EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
6123ff40c12SJohn Marino 	}
6133ff40c12SJohn Marino 
6143ff40c12SJohn Marino 	os_memset(data->dh_priv, 0, sizeof(data->dh_priv));
6153ff40c12SJohn Marino 	eap_eke_session_clean(&data->sess);
6163ff40c12SJohn Marino 
6173ff40c12SJohn Marino 	eap_eke_state(data, SUCCESS);
6183ff40c12SJohn Marino 	ret->methodState = METHOD_MAY_CONT;
6193ff40c12SJohn Marino 	ret->decision = DECISION_COND_SUCC;
6203ff40c12SJohn Marino 	ret->allowNotifications = FALSE;
6213ff40c12SJohn Marino 
6223ff40c12SJohn Marino 	return resp;
6233ff40c12SJohn Marino }
6243ff40c12SJohn Marino 
6253ff40c12SJohn Marino 
eap_eke_process_failure(struct eap_eke_data * data,struct eap_method_ret * ret,const struct wpabuf * reqData,const u8 * payload,size_t payload_len)6263ff40c12SJohn Marino static struct wpabuf * eap_eke_process_failure(struct eap_eke_data *data,
6273ff40c12SJohn Marino 					       struct eap_method_ret *ret,
6283ff40c12SJohn Marino 					       const struct wpabuf *reqData,
6293ff40c12SJohn Marino 					       const u8 *payload,
6303ff40c12SJohn Marino 					       size_t payload_len)
6313ff40c12SJohn Marino {
6323ff40c12SJohn Marino 	wpa_printf(MSG_DEBUG, "EAP-EKE: Received EAP-EKE-Failure/Request");
6333ff40c12SJohn Marino 
6343ff40c12SJohn Marino 	if (payload_len < 4) {
6353ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "EAP-EKE: Too short EAP-EKE-Failure");
6363ff40c12SJohn Marino 	} else {
6373ff40c12SJohn Marino 		u32 code;
6383ff40c12SJohn Marino 		code = WPA_GET_BE32(payload);
6393ff40c12SJohn Marino 		wpa_printf(MSG_INFO, "EAP-EKE: Failure-Code 0x%x", code);
6403ff40c12SJohn Marino 	}
6413ff40c12SJohn Marino 
642*a1157835SDaniel Fojt 	return eap_eke_build_fail(data, ret, eap_get_id(reqData),
643*a1157835SDaniel Fojt 				  EAP_EKE_FAIL_NO_ERROR);
6443ff40c12SJohn Marino }
6453ff40c12SJohn Marino 
6463ff40c12SJohn Marino 
eap_eke_process(struct eap_sm * sm,void * priv,struct eap_method_ret * ret,const struct wpabuf * reqData)6473ff40c12SJohn Marino static struct wpabuf * eap_eke_process(struct eap_sm *sm, void *priv,
6483ff40c12SJohn Marino 				       struct eap_method_ret *ret,
6493ff40c12SJohn Marino 				       const struct wpabuf *reqData)
6503ff40c12SJohn Marino {
6513ff40c12SJohn Marino 	struct eap_eke_data *data = priv;
6523ff40c12SJohn Marino 	struct wpabuf *resp;
6533ff40c12SJohn Marino 	const u8 *pos, *end;
6543ff40c12SJohn Marino 	size_t len;
6553ff40c12SJohn Marino 	u8 eke_exch;
6563ff40c12SJohn Marino 
6573ff40c12SJohn Marino 	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_EKE, reqData, &len);
6583ff40c12SJohn Marino 	if (pos == NULL || len < 1) {
6593ff40c12SJohn Marino 		ret->ignore = TRUE;
6603ff40c12SJohn Marino 		return NULL;
6613ff40c12SJohn Marino 	}
6623ff40c12SJohn Marino 
6633ff40c12SJohn Marino 	end = pos + len;
6643ff40c12SJohn Marino 	eke_exch = *pos++;
6653ff40c12SJohn Marino 
6663ff40c12SJohn Marino 	wpa_printf(MSG_DEBUG, "EAP-EKE: Received frame: exch %d", eke_exch);
6673ff40c12SJohn Marino 	wpa_hexdump(MSG_DEBUG, "EAP-EKE: Received Data", pos, end - pos);
6683ff40c12SJohn Marino 
6693ff40c12SJohn Marino 	ret->ignore = FALSE;
6703ff40c12SJohn Marino 	ret->methodState = METHOD_MAY_CONT;
6713ff40c12SJohn Marino 	ret->decision = DECISION_FAIL;
6723ff40c12SJohn Marino 	ret->allowNotifications = TRUE;
6733ff40c12SJohn Marino 
6743ff40c12SJohn Marino 	switch (eke_exch) {
6753ff40c12SJohn Marino 	case EAP_EKE_ID:
6763ff40c12SJohn Marino 		resp = eap_eke_process_id(data, ret, reqData, pos, end - pos);
6773ff40c12SJohn Marino 		break;
6783ff40c12SJohn Marino 	case EAP_EKE_COMMIT:
6793ff40c12SJohn Marino 		resp = eap_eke_process_commit(sm, data, ret, reqData,
6803ff40c12SJohn Marino 					      pos, end - pos);
6813ff40c12SJohn Marino 		break;
6823ff40c12SJohn Marino 	case EAP_EKE_CONFIRM:
6833ff40c12SJohn Marino 		resp = eap_eke_process_confirm(data, ret, reqData,
6843ff40c12SJohn Marino 					       pos, end - pos);
6853ff40c12SJohn Marino 		break;
6863ff40c12SJohn Marino 	case EAP_EKE_FAILURE:
6873ff40c12SJohn Marino 		resp = eap_eke_process_failure(data, ret, reqData,
6883ff40c12SJohn Marino 					       pos, end - pos);
6893ff40c12SJohn Marino 		break;
6903ff40c12SJohn Marino 	default:
6913ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "EAP-EKE: Ignoring message with unknown EKE-Exch %d", eke_exch);
6923ff40c12SJohn Marino 		ret->ignore = TRUE;
6933ff40c12SJohn Marino 		return NULL;
6943ff40c12SJohn Marino 	}
6953ff40c12SJohn Marino 
6963ff40c12SJohn Marino 	if (ret->methodState == METHOD_DONE)
6973ff40c12SJohn Marino 		ret->allowNotifications = FALSE;
6983ff40c12SJohn Marino 
6993ff40c12SJohn Marino 	return resp;
7003ff40c12SJohn Marino }
7013ff40c12SJohn Marino 
7023ff40c12SJohn Marino 
eap_eke_isKeyAvailable(struct eap_sm * sm,void * priv)7033ff40c12SJohn Marino static Boolean eap_eke_isKeyAvailable(struct eap_sm *sm, void *priv)
7043ff40c12SJohn Marino {
7053ff40c12SJohn Marino 	struct eap_eke_data *data = priv;
7063ff40c12SJohn Marino 	return data->state == SUCCESS;
7073ff40c12SJohn Marino }
7083ff40c12SJohn Marino 
7093ff40c12SJohn Marino 
eap_eke_getKey(struct eap_sm * sm,void * priv,size_t * len)7103ff40c12SJohn Marino static u8 * eap_eke_getKey(struct eap_sm *sm, void *priv, size_t *len)
7113ff40c12SJohn Marino {
7123ff40c12SJohn Marino 	struct eap_eke_data *data = priv;
7133ff40c12SJohn Marino 	u8 *key;
7143ff40c12SJohn Marino 
7153ff40c12SJohn Marino 	if (data->state != SUCCESS)
7163ff40c12SJohn Marino 		return NULL;
7173ff40c12SJohn Marino 
718*a1157835SDaniel Fojt 	key = os_memdup(data->msk, EAP_MSK_LEN);
7193ff40c12SJohn Marino 	if (key == NULL)
7203ff40c12SJohn Marino 		return NULL;
7213ff40c12SJohn Marino 	*len = EAP_MSK_LEN;
7223ff40c12SJohn Marino 
7233ff40c12SJohn Marino 	return key;
7243ff40c12SJohn Marino }
7253ff40c12SJohn Marino 
7263ff40c12SJohn Marino 
eap_eke_get_emsk(struct eap_sm * sm,void * priv,size_t * len)7273ff40c12SJohn Marino static u8 * eap_eke_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
7283ff40c12SJohn Marino {
7293ff40c12SJohn Marino 	struct eap_eke_data *data = priv;
7303ff40c12SJohn Marino 	u8 *key;
7313ff40c12SJohn Marino 
7323ff40c12SJohn Marino 	if (data->state != SUCCESS)
7333ff40c12SJohn Marino 		return NULL;
7343ff40c12SJohn Marino 
735*a1157835SDaniel Fojt 	key = os_memdup(data->emsk, EAP_EMSK_LEN);
7363ff40c12SJohn Marino 	if (key == NULL)
7373ff40c12SJohn Marino 		return NULL;
7383ff40c12SJohn Marino 	*len = EAP_EMSK_LEN;
7393ff40c12SJohn Marino 
7403ff40c12SJohn Marino 	return key;
7413ff40c12SJohn Marino }
7423ff40c12SJohn Marino 
7433ff40c12SJohn Marino 
eap_eke_get_session_id(struct eap_sm * sm,void * priv,size_t * len)744*a1157835SDaniel Fojt static u8 * eap_eke_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
745*a1157835SDaniel Fojt {
746*a1157835SDaniel Fojt 	struct eap_eke_data *data = priv;
747*a1157835SDaniel Fojt 	u8 *sid;
748*a1157835SDaniel Fojt 	size_t sid_len;
749*a1157835SDaniel Fojt 
750*a1157835SDaniel Fojt 	if (data->state != SUCCESS)
751*a1157835SDaniel Fojt 		return NULL;
752*a1157835SDaniel Fojt 
753*a1157835SDaniel Fojt 	sid_len = 1 + 2 * data->sess.nonce_len;
754*a1157835SDaniel Fojt 	sid = os_malloc(sid_len);
755*a1157835SDaniel Fojt 	if (sid == NULL)
756*a1157835SDaniel Fojt 		return NULL;
757*a1157835SDaniel Fojt 	sid[0] = EAP_TYPE_EKE;
758*a1157835SDaniel Fojt 	os_memcpy(sid + 1, data->nonce_p, data->sess.nonce_len);
759*a1157835SDaniel Fojt 	os_memcpy(sid + 1 + data->sess.nonce_len, data->nonce_s,
760*a1157835SDaniel Fojt 		  data->sess.nonce_len);
761*a1157835SDaniel Fojt 	*len = sid_len;
762*a1157835SDaniel Fojt 
763*a1157835SDaniel Fojt 	return sid;
764*a1157835SDaniel Fojt }
765*a1157835SDaniel Fojt 
766*a1157835SDaniel Fojt 
eap_peer_eke_register(void)7673ff40c12SJohn Marino int eap_peer_eke_register(void)
7683ff40c12SJohn Marino {
7693ff40c12SJohn Marino 	struct eap_method *eap;
7703ff40c12SJohn Marino 
7713ff40c12SJohn Marino 	eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
7723ff40c12SJohn Marino 				    EAP_VENDOR_IETF, EAP_TYPE_EKE, "EKE");
7733ff40c12SJohn Marino 	if (eap == NULL)
7743ff40c12SJohn Marino 		return -1;
7753ff40c12SJohn Marino 
7763ff40c12SJohn Marino 	eap->init = eap_eke_init;
7773ff40c12SJohn Marino 	eap->deinit = eap_eke_deinit;
7783ff40c12SJohn Marino 	eap->process = eap_eke_process;
7793ff40c12SJohn Marino 	eap->isKeyAvailable = eap_eke_isKeyAvailable;
7803ff40c12SJohn Marino 	eap->getKey = eap_eke_getKey;
7813ff40c12SJohn Marino 	eap->get_emsk = eap_eke_get_emsk;
782*a1157835SDaniel Fojt 	eap->getSessionId = eap_eke_get_session_id;
7833ff40c12SJohn Marino 
784*a1157835SDaniel Fojt 	return eap_peer_method_register(eap);
7853ff40c12SJohn Marino }
786