xref: /freebsd/contrib/wpa/src/eap_peer/eap_sake.c (revision c1d255d3ffdbe447de3ab875bf4e7d7accc5bfc5)
139beb93cSSam Leffler /*
239beb93cSSam Leffler  * EAP peer method: EAP-SAKE (RFC 4763)
34bc52338SCy Schubert  * Copyright (c) 2006-2019, Jouni Malinen <j@w1.fi>
439beb93cSSam Leffler  *
5f05cddf9SRui Paulo  * This software may be distributed under the terms of the BSD license.
6f05cddf9SRui Paulo  * See README for more details.
739beb93cSSam Leffler  */
839beb93cSSam Leffler 
939beb93cSSam Leffler #include "includes.h"
1039beb93cSSam Leffler 
1139beb93cSSam Leffler #include "common.h"
12f05cddf9SRui Paulo #include "crypto/random.h"
1339beb93cSSam Leffler #include "eap_peer/eap_i.h"
1439beb93cSSam Leffler #include "eap_common/eap_sake_common.h"
1539beb93cSSam Leffler 
1639beb93cSSam Leffler struct eap_sake_data {
1739beb93cSSam Leffler 	enum { IDENTITY, CHALLENGE, CONFIRM, SUCCESS, FAILURE } state;
1839beb93cSSam Leffler 	u8 root_secret_a[EAP_SAKE_ROOT_SECRET_LEN];
1939beb93cSSam Leffler 	u8 root_secret_b[EAP_SAKE_ROOT_SECRET_LEN];
2039beb93cSSam Leffler 	u8 rand_s[EAP_SAKE_RAND_LEN];
2139beb93cSSam Leffler 	u8 rand_p[EAP_SAKE_RAND_LEN];
2239beb93cSSam Leffler 	struct {
2339beb93cSSam Leffler 		u8 auth[EAP_SAKE_TEK_AUTH_LEN];
2439beb93cSSam Leffler 		u8 cipher[EAP_SAKE_TEK_CIPHER_LEN];
2539beb93cSSam Leffler 	} tek;
2639beb93cSSam Leffler 	u8 msk[EAP_MSK_LEN];
2739beb93cSSam Leffler 	u8 emsk[EAP_EMSK_LEN];
2839beb93cSSam Leffler 	u8 session_id;
2939beb93cSSam Leffler 	int session_id_set;
3039beb93cSSam Leffler 	u8 *peerid;
3139beb93cSSam Leffler 	size_t peerid_len;
3239beb93cSSam Leffler 	u8 *serverid;
3339beb93cSSam Leffler 	size_t serverid_len;
3439beb93cSSam Leffler };
3539beb93cSSam Leffler 
3639beb93cSSam Leffler 
eap_sake_state_txt(int state)3739beb93cSSam Leffler static const char * eap_sake_state_txt(int state)
3839beb93cSSam Leffler {
3939beb93cSSam Leffler 	switch (state) {
4039beb93cSSam Leffler 	case IDENTITY:
4139beb93cSSam Leffler 		return "IDENTITY";
4239beb93cSSam Leffler 	case CHALLENGE:
4339beb93cSSam Leffler 		return "CHALLENGE";
4439beb93cSSam Leffler 	case CONFIRM:
4539beb93cSSam Leffler 		return "CONFIRM";
4639beb93cSSam Leffler 	case SUCCESS:
4739beb93cSSam Leffler 		return "SUCCESS";
4839beb93cSSam Leffler 	case FAILURE:
4939beb93cSSam Leffler 		return "FAILURE";
5039beb93cSSam Leffler 	default:
5139beb93cSSam Leffler 		return "?";
5239beb93cSSam Leffler 	}
5339beb93cSSam Leffler }
5439beb93cSSam Leffler 
5539beb93cSSam Leffler 
eap_sake_state(struct eap_sake_data * data,int state)5639beb93cSSam Leffler static void eap_sake_state(struct eap_sake_data *data, int state)
5739beb93cSSam Leffler {
5839beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "EAP-SAKE: %s -> %s",
5939beb93cSSam Leffler 		   eap_sake_state_txt(data->state),
6039beb93cSSam Leffler 		   eap_sake_state_txt(state));
6139beb93cSSam Leffler 	data->state = state;
6239beb93cSSam Leffler }
6339beb93cSSam Leffler 
6439beb93cSSam Leffler 
6539beb93cSSam Leffler static void eap_sake_deinit(struct eap_sm *sm, void *priv);
6639beb93cSSam Leffler 
6739beb93cSSam Leffler 
eap_sake_init(struct eap_sm * sm)6839beb93cSSam Leffler static void * eap_sake_init(struct eap_sm *sm)
6939beb93cSSam Leffler {
7039beb93cSSam Leffler 	struct eap_sake_data *data;
7139beb93cSSam Leffler 	const u8 *identity, *password;
7239beb93cSSam Leffler 	size_t identity_len, password_len;
7339beb93cSSam Leffler 
7439beb93cSSam Leffler 	password = eap_get_config_password(sm, &password_len);
7539beb93cSSam Leffler 	if (!password || password_len != 2 * EAP_SAKE_ROOT_SECRET_LEN) {
7639beb93cSSam Leffler 		wpa_printf(MSG_INFO, "EAP-SAKE: No key of correct length "
7739beb93cSSam Leffler 			   "configured");
7839beb93cSSam Leffler 		return NULL;
7939beb93cSSam Leffler 	}
8039beb93cSSam Leffler 
8139beb93cSSam Leffler 	data = os_zalloc(sizeof(*data));
8239beb93cSSam Leffler 	if (data == NULL)
8339beb93cSSam Leffler 		return NULL;
8439beb93cSSam Leffler 	data->state = IDENTITY;
8539beb93cSSam Leffler 
8639beb93cSSam Leffler 	identity = eap_get_config_identity(sm, &identity_len);
8739beb93cSSam Leffler 	if (identity) {
8885732ac8SCy Schubert 		data->peerid = os_memdup(identity, identity_len);
8939beb93cSSam Leffler 		if (data->peerid == NULL) {
9039beb93cSSam Leffler 			eap_sake_deinit(sm, data);
9139beb93cSSam Leffler 			return NULL;
9239beb93cSSam Leffler 		}
9339beb93cSSam Leffler 		data->peerid_len = identity_len;
9439beb93cSSam Leffler 	}
9539beb93cSSam Leffler 
9639beb93cSSam Leffler 	os_memcpy(data->root_secret_a, password, EAP_SAKE_ROOT_SECRET_LEN);
9739beb93cSSam Leffler 	os_memcpy(data->root_secret_b,
9839beb93cSSam Leffler 		  password + EAP_SAKE_ROOT_SECRET_LEN,
9939beb93cSSam Leffler 		  EAP_SAKE_ROOT_SECRET_LEN);
10039beb93cSSam Leffler 
10139beb93cSSam Leffler 	return data;
10239beb93cSSam Leffler }
10339beb93cSSam Leffler 
10439beb93cSSam Leffler 
eap_sake_deinit(struct eap_sm * sm,void * priv)10539beb93cSSam Leffler static void eap_sake_deinit(struct eap_sm *sm, void *priv)
10639beb93cSSam Leffler {
10739beb93cSSam Leffler 	struct eap_sake_data *data = priv;
10839beb93cSSam Leffler 	os_free(data->serverid);
10939beb93cSSam Leffler 	os_free(data->peerid);
1105b9c547cSRui Paulo 	bin_clear_free(data, sizeof(*data));
11139beb93cSSam Leffler }
11239beb93cSSam Leffler 
11339beb93cSSam Leffler 
eap_sake_build_msg(struct eap_sake_data * data,int id,size_t length,u8 subtype)11439beb93cSSam Leffler static struct wpabuf * eap_sake_build_msg(struct eap_sake_data *data,
11539beb93cSSam Leffler 					  int id, size_t length, u8 subtype)
11639beb93cSSam Leffler {
11739beb93cSSam Leffler 	struct eap_sake_hdr *sake;
11839beb93cSSam Leffler 	struct wpabuf *msg;
11939beb93cSSam Leffler 	size_t plen;
12039beb93cSSam Leffler 
12139beb93cSSam Leffler 	plen = length + sizeof(struct eap_sake_hdr);
12239beb93cSSam Leffler 
12339beb93cSSam Leffler 	msg = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_SAKE, plen,
12439beb93cSSam Leffler 			    EAP_CODE_RESPONSE, id);
12539beb93cSSam Leffler 	if (msg == NULL) {
12639beb93cSSam Leffler 		wpa_printf(MSG_ERROR, "EAP-SAKE: Failed to allocate memory "
12739beb93cSSam Leffler 			   "request");
12839beb93cSSam Leffler 		return NULL;
12939beb93cSSam Leffler 	}
13039beb93cSSam Leffler 
13139beb93cSSam Leffler 	sake = wpabuf_put(msg, sizeof(*sake));
13239beb93cSSam Leffler 	sake->version = EAP_SAKE_VERSION;
13339beb93cSSam Leffler 	sake->session_id = data->session_id;
13439beb93cSSam Leffler 	sake->subtype = subtype;
13539beb93cSSam Leffler 
13639beb93cSSam Leffler 	return msg;
13739beb93cSSam Leffler }
13839beb93cSSam Leffler 
13939beb93cSSam Leffler 
eap_sake_process_identity(struct eap_sm * sm,struct eap_sake_data * data,struct eap_method_ret * ret,u8 id,const u8 * payload,size_t payload_len)14039beb93cSSam Leffler static struct wpabuf * eap_sake_process_identity(struct eap_sm *sm,
14139beb93cSSam Leffler 						 struct eap_sake_data *data,
14239beb93cSSam Leffler 						 struct eap_method_ret *ret,
143325151a3SRui Paulo 						 u8 id,
14439beb93cSSam Leffler 						 const u8 *payload,
14539beb93cSSam Leffler 						 size_t payload_len)
14639beb93cSSam Leffler {
14739beb93cSSam Leffler 	struct eap_sake_parse_attr attr;
14839beb93cSSam Leffler 	struct wpabuf *resp;
14939beb93cSSam Leffler 
15039beb93cSSam Leffler 	if (data->state != IDENTITY) {
151*c1d255d3SCy Schubert 		ret->ignore = true;
15239beb93cSSam Leffler 		return NULL;
15339beb93cSSam Leffler 	}
15439beb93cSSam Leffler 
15539beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "EAP-SAKE: Received Request/Identity");
15639beb93cSSam Leffler 
15739beb93cSSam Leffler 	if (eap_sake_parse_attributes(payload, payload_len, &attr))
15839beb93cSSam Leffler 		return NULL;
15939beb93cSSam Leffler 
16039beb93cSSam Leffler 	if (!attr.perm_id_req && !attr.any_id_req) {
16139beb93cSSam Leffler 		wpa_printf(MSG_INFO, "EAP-SAKE: No AT_PERM_ID_REQ or "
16239beb93cSSam Leffler 			   "AT_ANY_ID_REQ in Request/Identity");
16339beb93cSSam Leffler 		return NULL;
16439beb93cSSam Leffler 	}
16539beb93cSSam Leffler 
16639beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "EAP-SAKE: Sending Response/Identity");
16739beb93cSSam Leffler 
168325151a3SRui Paulo 	resp = eap_sake_build_msg(data, id, 2 + data->peerid_len,
16939beb93cSSam Leffler 				  EAP_SAKE_SUBTYPE_IDENTITY);
17039beb93cSSam Leffler 	if (resp == NULL)
17139beb93cSSam Leffler 		return NULL;
17239beb93cSSam Leffler 
17339beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_PEERID");
17439beb93cSSam Leffler 	eap_sake_add_attr(resp, EAP_SAKE_AT_PEERID,
17539beb93cSSam Leffler 			  data->peerid, data->peerid_len);
17639beb93cSSam Leffler 
17739beb93cSSam Leffler 	eap_sake_state(data, CHALLENGE);
17839beb93cSSam Leffler 
17939beb93cSSam Leffler 	return resp;
18039beb93cSSam Leffler }
18139beb93cSSam Leffler 
18239beb93cSSam Leffler 
eap_sake_process_challenge(struct eap_sm * sm,struct eap_sake_data * data,struct eap_method_ret * ret,u8 id,const u8 * payload,size_t payload_len)18339beb93cSSam Leffler static struct wpabuf * eap_sake_process_challenge(struct eap_sm *sm,
18439beb93cSSam Leffler 						  struct eap_sake_data *data,
18539beb93cSSam Leffler 						  struct eap_method_ret *ret,
186325151a3SRui Paulo 						  u8 id,
18739beb93cSSam Leffler 						  const u8 *payload,
18839beb93cSSam Leffler 						  size_t payload_len)
18939beb93cSSam Leffler {
19039beb93cSSam Leffler 	struct eap_sake_parse_attr attr;
19139beb93cSSam Leffler 	struct wpabuf *resp;
19239beb93cSSam Leffler 	u8 *rpos;
19339beb93cSSam Leffler 	size_t rlen;
19439beb93cSSam Leffler 
19539beb93cSSam Leffler 	if (data->state != IDENTITY && data->state != CHALLENGE) {
19639beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "EAP-SAKE: Request/Challenge received "
19739beb93cSSam Leffler 			   "in unexpected state (%d)", data->state);
198*c1d255d3SCy Schubert 		ret->ignore = true;
19939beb93cSSam Leffler 		return NULL;
20039beb93cSSam Leffler 	}
20139beb93cSSam Leffler 	if (data->state == IDENTITY)
20239beb93cSSam Leffler 		eap_sake_state(data, CHALLENGE);
20339beb93cSSam Leffler 
20439beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "EAP-SAKE: Received Request/Challenge");
20539beb93cSSam Leffler 
20639beb93cSSam Leffler 	if (eap_sake_parse_attributes(payload, payload_len, &attr))
20739beb93cSSam Leffler 		return NULL;
20839beb93cSSam Leffler 
20939beb93cSSam Leffler 	if (!attr.rand_s) {
21039beb93cSSam Leffler 		wpa_printf(MSG_INFO, "EAP-SAKE: Request/Challenge did not "
21139beb93cSSam Leffler 			   "include AT_RAND_S");
21239beb93cSSam Leffler 		return NULL;
21339beb93cSSam Leffler 	}
21439beb93cSSam Leffler 
21539beb93cSSam Leffler 	os_memcpy(data->rand_s, attr.rand_s, EAP_SAKE_RAND_LEN);
21639beb93cSSam Leffler 	wpa_hexdump(MSG_MSGDUMP, "EAP-SAKE: RAND_S (server rand)",
21739beb93cSSam Leffler 		    data->rand_s, EAP_SAKE_RAND_LEN);
21839beb93cSSam Leffler 
219f05cddf9SRui Paulo 	if (random_get_bytes(data->rand_p, EAP_SAKE_RAND_LEN)) {
22039beb93cSSam Leffler 		wpa_printf(MSG_ERROR, "EAP-SAKE: Failed to get random data");
22139beb93cSSam Leffler 		return NULL;
22239beb93cSSam Leffler 	}
22339beb93cSSam Leffler 	wpa_hexdump(MSG_MSGDUMP, "EAP-SAKE: RAND_P (peer rand)",
22439beb93cSSam Leffler 		    data->rand_p, EAP_SAKE_RAND_LEN);
22539beb93cSSam Leffler 
22639beb93cSSam Leffler 	os_free(data->serverid);
22739beb93cSSam Leffler 	data->serverid = NULL;
22839beb93cSSam Leffler 	data->serverid_len = 0;
22939beb93cSSam Leffler 	if (attr.serverid) {
23039beb93cSSam Leffler 		wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-SAKE: SERVERID",
23139beb93cSSam Leffler 				  attr.serverid, attr.serverid_len);
23285732ac8SCy Schubert 		data->serverid = os_memdup(attr.serverid, attr.serverid_len);
23339beb93cSSam Leffler 		if (data->serverid == NULL)
23439beb93cSSam Leffler 			return NULL;
23539beb93cSSam Leffler 		data->serverid_len = attr.serverid_len;
23639beb93cSSam Leffler 	}
23739beb93cSSam Leffler 
2384bc52338SCy Schubert 	if (eap_sake_derive_keys(data->root_secret_a, data->root_secret_b,
23939beb93cSSam Leffler 				 data->rand_s, data->rand_p,
2404bc52338SCy Schubert 				 (u8 *) &data->tek, data->msk,
2414bc52338SCy Schubert 				 data->emsk) < 0) {
2424bc52338SCy Schubert 		wpa_printf(MSG_INFO, "EAP-SAKE: Failed to derive keys");
2434bc52338SCy Schubert 		return NULL;
2444bc52338SCy Schubert 	}
24539beb93cSSam Leffler 
24639beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "EAP-SAKE: Sending Response/Challenge");
24739beb93cSSam Leffler 
24839beb93cSSam Leffler 	rlen = 2 + EAP_SAKE_RAND_LEN + 2 + EAP_SAKE_MIC_LEN;
24939beb93cSSam Leffler 	if (data->peerid)
25039beb93cSSam Leffler 		rlen += 2 + data->peerid_len;
251325151a3SRui Paulo 	resp = eap_sake_build_msg(data, id, rlen, EAP_SAKE_SUBTYPE_CHALLENGE);
25239beb93cSSam Leffler 	if (resp == NULL)
25339beb93cSSam Leffler 		return NULL;
25439beb93cSSam Leffler 
25539beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_RAND_P");
25639beb93cSSam Leffler 	eap_sake_add_attr(resp, EAP_SAKE_AT_RAND_P,
25739beb93cSSam Leffler 			  data->rand_p, EAP_SAKE_RAND_LEN);
25839beb93cSSam Leffler 
25939beb93cSSam Leffler 	if (data->peerid) {
26039beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_PEERID");
26139beb93cSSam Leffler 		eap_sake_add_attr(resp, EAP_SAKE_AT_PEERID,
26239beb93cSSam Leffler 				  data->peerid, data->peerid_len);
26339beb93cSSam Leffler 	}
26439beb93cSSam Leffler 
26539beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_MIC_P");
26639beb93cSSam Leffler 	wpabuf_put_u8(resp, EAP_SAKE_AT_MIC_P);
26739beb93cSSam Leffler 	wpabuf_put_u8(resp, 2 + EAP_SAKE_MIC_LEN);
26839beb93cSSam Leffler 	rpos = wpabuf_put(resp, EAP_SAKE_MIC_LEN);
26939beb93cSSam Leffler 	if (eap_sake_compute_mic(data->tek.auth, data->rand_s, data->rand_p,
27039beb93cSSam Leffler 				 data->serverid, data->serverid_len,
27139beb93cSSam Leffler 				 data->peerid, data->peerid_len, 1,
27239beb93cSSam Leffler 				 wpabuf_head(resp), wpabuf_len(resp), rpos,
27339beb93cSSam Leffler 				 rpos)) {
27439beb93cSSam Leffler 		wpa_printf(MSG_INFO, "EAP-SAKE: Failed to compute MIC");
27539beb93cSSam Leffler 		wpabuf_free(resp);
27639beb93cSSam Leffler 		return NULL;
27739beb93cSSam Leffler 	}
27839beb93cSSam Leffler 
27939beb93cSSam Leffler 	eap_sake_state(data, CONFIRM);
28039beb93cSSam Leffler 
28139beb93cSSam Leffler 	return resp;
28239beb93cSSam Leffler }
28339beb93cSSam Leffler 
28439beb93cSSam Leffler 
eap_sake_process_confirm(struct eap_sm * sm,struct eap_sake_data * data,struct eap_method_ret * ret,u8 id,const struct wpabuf * reqData,const u8 * payload,size_t payload_len)28539beb93cSSam Leffler static struct wpabuf * eap_sake_process_confirm(struct eap_sm *sm,
28639beb93cSSam Leffler 						struct eap_sake_data *data,
28739beb93cSSam Leffler 						struct eap_method_ret *ret,
288325151a3SRui Paulo 						u8 id,
28939beb93cSSam Leffler 						const struct wpabuf *reqData,
29039beb93cSSam Leffler 						const u8 *payload,
29139beb93cSSam Leffler 						size_t payload_len)
29239beb93cSSam Leffler {
29339beb93cSSam Leffler 	struct eap_sake_parse_attr attr;
29439beb93cSSam Leffler 	u8 mic_s[EAP_SAKE_MIC_LEN];
29539beb93cSSam Leffler 	struct wpabuf *resp;
29639beb93cSSam Leffler 	u8 *rpos;
29739beb93cSSam Leffler 
29839beb93cSSam Leffler 	if (data->state != CONFIRM) {
299*c1d255d3SCy Schubert 		ret->ignore = true;
30039beb93cSSam Leffler 		return NULL;
30139beb93cSSam Leffler 	}
30239beb93cSSam Leffler 
30339beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "EAP-SAKE: Received Request/Confirm");
30439beb93cSSam Leffler 
30539beb93cSSam Leffler 	if (eap_sake_parse_attributes(payload, payload_len, &attr))
30639beb93cSSam Leffler 		return NULL;
30739beb93cSSam Leffler 
30839beb93cSSam Leffler 	if (!attr.mic_s) {
30939beb93cSSam Leffler 		wpa_printf(MSG_INFO, "EAP-SAKE: Request/Confirm did not "
31039beb93cSSam Leffler 			   "include AT_MIC_S");
31139beb93cSSam Leffler 		return NULL;
31239beb93cSSam Leffler 	}
31339beb93cSSam Leffler 
314780fb4a2SCy Schubert 	if (eap_sake_compute_mic(data->tek.auth, data->rand_s, data->rand_p,
31539beb93cSSam Leffler 				 data->serverid, data->serverid_len,
31639beb93cSSam Leffler 				 data->peerid, data->peerid_len, 0,
31739beb93cSSam Leffler 				 wpabuf_head(reqData), wpabuf_len(reqData),
318780fb4a2SCy Schubert 				 attr.mic_s, mic_s)) {
319780fb4a2SCy Schubert 		wpa_printf(MSG_INFO, "EAP-SAKE: Failed to compute MIC");
320780fb4a2SCy Schubert 		eap_sake_state(data, FAILURE);
321780fb4a2SCy Schubert 		ret->methodState = METHOD_DONE;
322780fb4a2SCy Schubert 		ret->decision = DECISION_FAIL;
323*c1d255d3SCy Schubert 		ret->allowNotifications = false;
324780fb4a2SCy Schubert 		wpa_printf(MSG_DEBUG, "EAP-SAKE: Sending Response/Auth-Reject");
325780fb4a2SCy Schubert 		return eap_sake_build_msg(data, id, 0,
326780fb4a2SCy Schubert 					  EAP_SAKE_SUBTYPE_AUTH_REJECT);
327780fb4a2SCy Schubert 	}
3285b9c547cSRui Paulo 	if (os_memcmp_const(attr.mic_s, mic_s, EAP_SAKE_MIC_LEN) != 0) {
32939beb93cSSam Leffler 		wpa_printf(MSG_INFO, "EAP-SAKE: Incorrect AT_MIC_S");
33039beb93cSSam Leffler 		eap_sake_state(data, FAILURE);
33139beb93cSSam Leffler 		ret->methodState = METHOD_DONE;
33239beb93cSSam Leffler 		ret->decision = DECISION_FAIL;
333*c1d255d3SCy Schubert 		ret->allowNotifications = false;
33439beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "EAP-SAKE: Sending "
33539beb93cSSam Leffler 			   "Response/Auth-Reject");
336325151a3SRui Paulo 		return eap_sake_build_msg(data, id, 0,
33739beb93cSSam Leffler 					  EAP_SAKE_SUBTYPE_AUTH_REJECT);
33839beb93cSSam Leffler 	}
33939beb93cSSam Leffler 
34039beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "EAP-SAKE: Sending Response/Confirm");
34139beb93cSSam Leffler 
342325151a3SRui Paulo 	resp = eap_sake_build_msg(data, id, 2 + EAP_SAKE_MIC_LEN,
34339beb93cSSam Leffler 				  EAP_SAKE_SUBTYPE_CONFIRM);
34439beb93cSSam Leffler 	if (resp == NULL)
34539beb93cSSam Leffler 		return NULL;
34639beb93cSSam Leffler 
34739beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_MIC_P");
34839beb93cSSam Leffler 	wpabuf_put_u8(resp, EAP_SAKE_AT_MIC_P);
34939beb93cSSam Leffler 	wpabuf_put_u8(resp, 2 + EAP_SAKE_MIC_LEN);
35039beb93cSSam Leffler 	rpos = wpabuf_put(resp, EAP_SAKE_MIC_LEN);
35139beb93cSSam Leffler 	if (eap_sake_compute_mic(data->tek.auth, data->rand_s, data->rand_p,
35239beb93cSSam Leffler 				 data->serverid, data->serverid_len,
35339beb93cSSam Leffler 				 data->peerid, data->peerid_len, 1,
35439beb93cSSam Leffler 				 wpabuf_head(resp), wpabuf_len(resp), rpos,
35539beb93cSSam Leffler 				 rpos)) {
35639beb93cSSam Leffler 		wpa_printf(MSG_INFO, "EAP-SAKE: Failed to compute MIC");
35739beb93cSSam Leffler 		wpabuf_free(resp);
35839beb93cSSam Leffler 		return NULL;
35939beb93cSSam Leffler 	}
36039beb93cSSam Leffler 
36139beb93cSSam Leffler 	eap_sake_state(data, SUCCESS);
36239beb93cSSam Leffler 	ret->methodState = METHOD_DONE;
36339beb93cSSam Leffler 	ret->decision = DECISION_UNCOND_SUCC;
364*c1d255d3SCy Schubert 	ret->allowNotifications = false;
36539beb93cSSam Leffler 
36639beb93cSSam Leffler 	return resp;
36739beb93cSSam Leffler }
36839beb93cSSam Leffler 
36939beb93cSSam Leffler 
eap_sake_process(struct eap_sm * sm,void * priv,struct eap_method_ret * ret,const struct wpabuf * reqData)37039beb93cSSam Leffler static struct wpabuf * eap_sake_process(struct eap_sm *sm, void *priv,
37139beb93cSSam Leffler 					struct eap_method_ret *ret,
37239beb93cSSam Leffler 					const struct wpabuf *reqData)
37339beb93cSSam Leffler {
37439beb93cSSam Leffler 	struct eap_sake_data *data = priv;
37539beb93cSSam Leffler 	const struct eap_sake_hdr *req;
37639beb93cSSam Leffler 	struct wpabuf *resp;
37739beb93cSSam Leffler 	const u8 *pos, *end;
37839beb93cSSam Leffler 	size_t len;
379325151a3SRui Paulo 	u8 subtype, session_id, id;
38039beb93cSSam Leffler 
38139beb93cSSam Leffler 	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_SAKE, reqData, &len);
38239beb93cSSam Leffler 	if (pos == NULL || len < sizeof(struct eap_sake_hdr)) {
383*c1d255d3SCy Schubert 		ret->ignore = true;
38439beb93cSSam Leffler 		return NULL;
38539beb93cSSam Leffler 	}
38639beb93cSSam Leffler 
38739beb93cSSam Leffler 	req = (const struct eap_sake_hdr *) pos;
38839beb93cSSam Leffler 	end = pos + len;
389325151a3SRui Paulo 	id = eap_get_id(reqData);
39039beb93cSSam Leffler 	subtype = req->subtype;
39139beb93cSSam Leffler 	session_id = req->session_id;
39239beb93cSSam Leffler 	pos = (const u8 *) (req + 1);
39339beb93cSSam Leffler 
39439beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "EAP-SAKE: Received frame: subtype %d "
39539beb93cSSam Leffler 		   "session_id %d", subtype, session_id);
39639beb93cSSam Leffler 	wpa_hexdump(MSG_DEBUG, "EAP-SAKE: Received attributes",
39739beb93cSSam Leffler 		    pos, end - pos);
39839beb93cSSam Leffler 
39939beb93cSSam Leffler 	if (data->session_id_set && data->session_id != session_id) {
40039beb93cSSam Leffler 		wpa_printf(MSG_INFO, "EAP-SAKE: Session ID mismatch (%d,%d)",
40139beb93cSSam Leffler 			   session_id, data->session_id);
402*c1d255d3SCy Schubert 		ret->ignore = true;
40339beb93cSSam Leffler 		return NULL;
40439beb93cSSam Leffler 	}
40539beb93cSSam Leffler 	data->session_id = session_id;
40639beb93cSSam Leffler 	data->session_id_set = 1;
40739beb93cSSam Leffler 
408*c1d255d3SCy Schubert 	ret->ignore = false;
40939beb93cSSam Leffler 	ret->methodState = METHOD_MAY_CONT;
41039beb93cSSam Leffler 	ret->decision = DECISION_FAIL;
411*c1d255d3SCy Schubert 	ret->allowNotifications = true;
41239beb93cSSam Leffler 
41339beb93cSSam Leffler 	switch (subtype) {
41439beb93cSSam Leffler 	case EAP_SAKE_SUBTYPE_IDENTITY:
415325151a3SRui Paulo 		resp = eap_sake_process_identity(sm, data, ret, id,
41639beb93cSSam Leffler 						 pos, end - pos);
41739beb93cSSam Leffler 		break;
41839beb93cSSam Leffler 	case EAP_SAKE_SUBTYPE_CHALLENGE:
419325151a3SRui Paulo 		resp = eap_sake_process_challenge(sm, data, ret, id,
42039beb93cSSam Leffler 						  pos, end - pos);
42139beb93cSSam Leffler 		break;
42239beb93cSSam Leffler 	case EAP_SAKE_SUBTYPE_CONFIRM:
423325151a3SRui Paulo 		resp = eap_sake_process_confirm(sm, data, ret, id, reqData,
42439beb93cSSam Leffler 						pos, end - pos);
42539beb93cSSam Leffler 		break;
42639beb93cSSam Leffler 	default:
42739beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "EAP-SAKE: Ignoring message with "
42839beb93cSSam Leffler 			   "unknown subtype %d", subtype);
429*c1d255d3SCy Schubert 		ret->ignore = true;
43039beb93cSSam Leffler 		return NULL;
43139beb93cSSam Leffler 	}
43239beb93cSSam Leffler 
43339beb93cSSam Leffler 	if (ret->methodState == METHOD_DONE)
434*c1d255d3SCy Schubert 		ret->allowNotifications = false;
43539beb93cSSam Leffler 
43639beb93cSSam Leffler 	return resp;
43739beb93cSSam Leffler }
43839beb93cSSam Leffler 
43939beb93cSSam Leffler 
eap_sake_isKeyAvailable(struct eap_sm * sm,void * priv)440*c1d255d3SCy Schubert static bool eap_sake_isKeyAvailable(struct eap_sm *sm, void *priv)
44139beb93cSSam Leffler {
44239beb93cSSam Leffler 	struct eap_sake_data *data = priv;
44339beb93cSSam Leffler 	return data->state == SUCCESS;
44439beb93cSSam Leffler }
44539beb93cSSam Leffler 
44639beb93cSSam Leffler 
eap_sake_getKey(struct eap_sm * sm,void * priv,size_t * len)44739beb93cSSam Leffler static u8 * eap_sake_getKey(struct eap_sm *sm, void *priv, size_t *len)
44839beb93cSSam Leffler {
44939beb93cSSam Leffler 	struct eap_sake_data *data = priv;
45039beb93cSSam Leffler 	u8 *key;
45139beb93cSSam Leffler 
45239beb93cSSam Leffler 	if (data->state != SUCCESS)
45339beb93cSSam Leffler 		return NULL;
45439beb93cSSam Leffler 
45585732ac8SCy Schubert 	key = os_memdup(data->msk, EAP_MSK_LEN);
45639beb93cSSam Leffler 	if (key == NULL)
45739beb93cSSam Leffler 		return NULL;
45839beb93cSSam Leffler 	*len = EAP_MSK_LEN;
45939beb93cSSam Leffler 
46039beb93cSSam Leffler 	return key;
46139beb93cSSam Leffler }
46239beb93cSSam Leffler 
46339beb93cSSam Leffler 
eap_sake_get_session_id(struct eap_sm * sm,void * priv,size_t * len)4645b9c547cSRui Paulo static u8 * eap_sake_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
4655b9c547cSRui Paulo {
4665b9c547cSRui Paulo 	struct eap_sake_data *data = priv;
4675b9c547cSRui Paulo 	u8 *id;
4685b9c547cSRui Paulo 
4695b9c547cSRui Paulo 	if (data->state != SUCCESS)
4705b9c547cSRui Paulo 		return NULL;
4715b9c547cSRui Paulo 
4725b9c547cSRui Paulo 	*len = 1 + 2 * EAP_SAKE_RAND_LEN;
4735b9c547cSRui Paulo 	id = os_malloc(*len);
4745b9c547cSRui Paulo 	if (id == NULL)
4755b9c547cSRui Paulo 		return NULL;
4765b9c547cSRui Paulo 
4775b9c547cSRui Paulo 	id[0] = EAP_TYPE_SAKE;
4785b9c547cSRui Paulo 	os_memcpy(id + 1, data->rand_s, EAP_SAKE_RAND_LEN);
4795b9c547cSRui Paulo 	os_memcpy(id + 1 + EAP_SAKE_RAND_LEN, data->rand_s, EAP_SAKE_RAND_LEN);
4805b9c547cSRui Paulo 	wpa_hexdump(MSG_DEBUG, "EAP-SAKE: Derived Session-Id", id, *len);
4815b9c547cSRui Paulo 
4825b9c547cSRui Paulo 	return id;
4835b9c547cSRui Paulo }
4845b9c547cSRui Paulo 
4855b9c547cSRui Paulo 
eap_sake_get_emsk(struct eap_sm * sm,void * priv,size_t * len)48639beb93cSSam Leffler static u8 * eap_sake_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
48739beb93cSSam Leffler {
48839beb93cSSam Leffler 	struct eap_sake_data *data = priv;
48939beb93cSSam Leffler 	u8 *key;
49039beb93cSSam Leffler 
49139beb93cSSam Leffler 	if (data->state != SUCCESS)
49239beb93cSSam Leffler 		return NULL;
49339beb93cSSam Leffler 
49485732ac8SCy Schubert 	key = os_memdup(data->emsk, EAP_EMSK_LEN);
49539beb93cSSam Leffler 	if (key == NULL)
49639beb93cSSam Leffler 		return NULL;
49739beb93cSSam Leffler 	*len = EAP_EMSK_LEN;
49839beb93cSSam Leffler 
49939beb93cSSam Leffler 	return key;
50039beb93cSSam Leffler }
50139beb93cSSam Leffler 
50239beb93cSSam Leffler 
eap_peer_sake_register(void)50339beb93cSSam Leffler int eap_peer_sake_register(void)
50439beb93cSSam Leffler {
50539beb93cSSam Leffler 	struct eap_method *eap;
50639beb93cSSam Leffler 
50739beb93cSSam Leffler 	eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
50839beb93cSSam Leffler 				    EAP_VENDOR_IETF, EAP_TYPE_SAKE, "SAKE");
50939beb93cSSam Leffler 	if (eap == NULL)
51039beb93cSSam Leffler 		return -1;
51139beb93cSSam Leffler 
51239beb93cSSam Leffler 	eap->init = eap_sake_init;
51339beb93cSSam Leffler 	eap->deinit = eap_sake_deinit;
51439beb93cSSam Leffler 	eap->process = eap_sake_process;
51539beb93cSSam Leffler 	eap->isKeyAvailable = eap_sake_isKeyAvailable;
51639beb93cSSam Leffler 	eap->getKey = eap_sake_getKey;
5175b9c547cSRui Paulo 	eap->getSessionId = eap_sake_get_session_id;
51839beb93cSSam Leffler 	eap->get_emsk = eap_sake_get_emsk;
51939beb93cSSam Leffler 
520780fb4a2SCy Schubert 	return eap_peer_method_register(eap);
52139beb93cSSam Leffler }
522