18d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/*
28d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * EAP peer method: EAP-SAKE (RFC 4763)
38d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Copyright (c) 2006-2008, Jouni Malinen <j@w1.fi>
48d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *
5c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt * This software may be distributed under the terms of the BSD license.
6c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt * See README for more details.
78d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
88d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
98d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "includes.h"
108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "common.h"
128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "crypto/random.h"
138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "eap_peer/eap_i.h"
148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "eap_common/eap_sake_common.h"
158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct eap_sake_data {
178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	enum { IDENTITY, CHALLENGE, CONFIRM, SUCCESS, FAILURE } state;
188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 root_secret_a[EAP_SAKE_ROOT_SECRET_LEN];
198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 root_secret_b[EAP_SAKE_ROOT_SECRET_LEN];
208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 rand_s[EAP_SAKE_RAND_LEN];
218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 rand_p[EAP_SAKE_RAND_LEN];
228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct {
238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		u8 auth[EAP_SAKE_TEK_AUTH_LEN];
248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		u8 cipher[EAP_SAKE_TEK_CIPHER_LEN];
258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	} tek;
268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 msk[EAP_MSK_LEN];
278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 emsk[EAP_EMSK_LEN];
288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 session_id;
298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int session_id_set;
308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 *peerid;
318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	size_t peerid_len;
328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 *serverid;
338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	size_t serverid_len;
348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt};
358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic const char * eap_sake_state_txt(int state)
388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	switch (state) {
408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case IDENTITY:
418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return "IDENTITY";
428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case CHALLENGE:
438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return "CHALLENGE";
448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case CONFIRM:
458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return "CONFIRM";
468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case SUCCESS:
478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return "SUCCESS";
488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case FAILURE:
498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return "FAILURE";
508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	default:
518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return "?";
528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void eap_sake_state(struct eap_sake_data *data, int state)
578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "EAP-SAKE: %s -> %s",
598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   eap_sake_state_txt(data->state),
608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   eap_sake_state_txt(state));
618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	data->state = state;
628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void eap_sake_deinit(struct eap_sm *sm, void *priv);
668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void * eap_sake_init(struct eap_sm *sm)
698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct eap_sake_data *data;
718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const u8 *identity, *password;
728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	size_t identity_len, password_len;
738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	password = eap_get_config_password(sm, &password_len);
758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!password || password_len != 2 * EAP_SAKE_ROOT_SECRET_LEN) {
768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_INFO, "EAP-SAKE: No key of correct length "
778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "configured");
788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	data = os_zalloc(sizeof(*data));
828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (data == NULL)
838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	data->state = IDENTITY;
858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	identity = eap_get_config_identity(sm, &identity_len);
878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (identity) {
888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		data->peerid = os_malloc(identity_len);
898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (data->peerid == NULL) {
908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			eap_sake_deinit(sm, data);
918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return NULL;
928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_memcpy(data->peerid, identity, identity_len);
948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		data->peerid_len = identity_len;
958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(data->root_secret_a, password, EAP_SAKE_ROOT_SECRET_LEN);
988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(data->root_secret_b,
998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		  password + EAP_SAKE_ROOT_SECRET_LEN,
1008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		  EAP_SAKE_ROOT_SECRET_LEN);
1018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return data;
1038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
1048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void eap_sake_deinit(struct eap_sm *sm, void *priv)
1078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
1088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct eap_sake_data *data = priv;
1098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(data->serverid);
1108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(data->peerid);
111c28170251eb54dbf64a9074a07fee377587425b2Dmitry Shmidt	bin_clear_free(data, sizeof(*data));
1128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
1138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic struct wpabuf * eap_sake_build_msg(struct eap_sake_data *data,
1168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					  int id, size_t length, u8 subtype)
1178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
1188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct eap_sake_hdr *sake;
1198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpabuf *msg;
1208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	size_t plen;
1218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	plen = length + sizeof(struct eap_sake_hdr);
1238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	msg = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_SAKE, plen,
1258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			    EAP_CODE_RESPONSE, id);
1268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (msg == NULL) {
1278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_ERROR, "EAP-SAKE: Failed to allocate memory "
1288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "request");
1298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
1308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
1318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	sake = wpabuf_put(msg, sizeof(*sake));
1338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	sake->version = EAP_SAKE_VERSION;
1348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	sake->session_id = data->session_id;
1358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	sake->subtype = subtype;
1368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return msg;
1388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
1398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic struct wpabuf * eap_sake_process_identity(struct eap_sm *sm,
1428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt						 struct eap_sake_data *data,
1438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt						 struct eap_method_ret *ret,
144cc00d5dc8483e32158b2ba61ea44b0c38d790ed7Dmitry Shmidt						 u8 id,
1458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt						 const u8 *payload,
1468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt						 size_t payload_len)
1478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
1488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct eap_sake_parse_attr attr;
1498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpabuf *resp;
1508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (data->state != IDENTITY) {
1528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		ret->ignore = TRUE;
1538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
1548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
1558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "EAP-SAKE: Received Request/Identity");
1578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (eap_sake_parse_attributes(payload, payload_len, &attr))
1598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
1608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!attr.perm_id_req && !attr.any_id_req) {
1628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_INFO, "EAP-SAKE: No AT_PERM_ID_REQ or "
1638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "AT_ANY_ID_REQ in Request/Identity");
1648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
1658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
1668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "EAP-SAKE: Sending Response/Identity");
1688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
169cc00d5dc8483e32158b2ba61ea44b0c38d790ed7Dmitry Shmidt	resp = eap_sake_build_msg(data, id, 2 + data->peerid_len,
1708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				  EAP_SAKE_SUBTYPE_IDENTITY);
1718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (resp == NULL)
1728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
1738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_PEERID");
1758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eap_sake_add_attr(resp, EAP_SAKE_AT_PEERID,
1768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			  data->peerid, data->peerid_len);
1778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eap_sake_state(data, CHALLENGE);
1798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return resp;
1818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
1828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic struct wpabuf * eap_sake_process_challenge(struct eap_sm *sm,
1858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt						  struct eap_sake_data *data,
1868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt						  struct eap_method_ret *ret,
187cc00d5dc8483e32158b2ba61ea44b0c38d790ed7Dmitry Shmidt						  u8 id,
1888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt						  const u8 *payload,
1898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt						  size_t payload_len)
1908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
1918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct eap_sake_parse_attr attr;
1928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpabuf *resp;
1938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 *rpos;
1948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	size_t rlen;
1958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (data->state != IDENTITY && data->state != CHALLENGE) {
1978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "EAP-SAKE: Request/Challenge received "
1988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "in unexpected state (%d)", data->state);
1998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		ret->ignore = TRUE;
2008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
2018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
2028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (data->state == IDENTITY)
2038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		eap_sake_state(data, CHALLENGE);
2048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "EAP-SAKE: Received Request/Challenge");
2068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (eap_sake_parse_attributes(payload, payload_len, &attr))
2088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
2098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!attr.rand_s) {
2118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_INFO, "EAP-SAKE: Request/Challenge did not "
2128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "include AT_RAND_S");
2138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
2148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
2158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(data->rand_s, attr.rand_s, EAP_SAKE_RAND_LEN);
2178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_hexdump(MSG_MSGDUMP, "EAP-SAKE: RAND_S (server rand)",
2188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    data->rand_s, EAP_SAKE_RAND_LEN);
2198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (random_get_bytes(data->rand_p, EAP_SAKE_RAND_LEN)) {
2218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_ERROR, "EAP-SAKE: Failed to get random data");
2228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
2238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
2248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_hexdump(MSG_MSGDUMP, "EAP-SAKE: RAND_P (peer rand)",
2258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    data->rand_p, EAP_SAKE_RAND_LEN);
2268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(data->serverid);
2288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	data->serverid = NULL;
2298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	data->serverid_len = 0;
2308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (attr.serverid) {
2318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-SAKE: SERVERID",
2328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				  attr.serverid, attr.serverid_len);
2338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		data->serverid = os_malloc(attr.serverid_len);
2348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (data->serverid == NULL)
2358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return NULL;
2368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_memcpy(data->serverid, attr.serverid, attr.serverid_len);
2378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		data->serverid_len = attr.serverid_len;
2388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
2398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eap_sake_derive_keys(data->root_secret_a, data->root_secret_b,
2418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			     data->rand_s, data->rand_p,
2428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			     (u8 *) &data->tek, data->msk, data->emsk);
2438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "EAP-SAKE: Sending Response/Challenge");
2458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	rlen = 2 + EAP_SAKE_RAND_LEN + 2 + EAP_SAKE_MIC_LEN;
2478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (data->peerid)
2488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		rlen += 2 + data->peerid_len;
249cc00d5dc8483e32158b2ba61ea44b0c38d790ed7Dmitry Shmidt	resp = eap_sake_build_msg(data, id, rlen, EAP_SAKE_SUBTYPE_CHALLENGE);
2508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (resp == NULL)
2518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
2528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_RAND_P");
2548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eap_sake_add_attr(resp, EAP_SAKE_AT_RAND_P,
2558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			  data->rand_p, EAP_SAKE_RAND_LEN);
2568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (data->peerid) {
2588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_PEERID");
2598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		eap_sake_add_attr(resp, EAP_SAKE_AT_PEERID,
2608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				  data->peerid, data->peerid_len);
2618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
2628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_MIC_P");
2648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_u8(resp, EAP_SAKE_AT_MIC_P);
2658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_u8(resp, 2 + EAP_SAKE_MIC_LEN);
2668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	rpos = wpabuf_put(resp, EAP_SAKE_MIC_LEN);
2678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (eap_sake_compute_mic(data->tek.auth, data->rand_s, data->rand_p,
2688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				 data->serverid, data->serverid_len,
2698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				 data->peerid, data->peerid_len, 1,
2708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				 wpabuf_head(resp), wpabuf_len(resp), rpos,
2718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				 rpos)) {
2728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_INFO, "EAP-SAKE: Failed to compute MIC");
2738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpabuf_free(resp);
2748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
2758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
2768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eap_sake_state(data, CONFIRM);
2788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return resp;
2808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
2818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic struct wpabuf * eap_sake_process_confirm(struct eap_sm *sm,
2848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt						struct eap_sake_data *data,
2858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt						struct eap_method_ret *ret,
286cc00d5dc8483e32158b2ba61ea44b0c38d790ed7Dmitry Shmidt						u8 id,
2878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt						const struct wpabuf *reqData,
2888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt						const u8 *payload,
2898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt						size_t payload_len)
2908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
2918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct eap_sake_parse_attr attr;
2928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 mic_s[EAP_SAKE_MIC_LEN];
2938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpabuf *resp;
2948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 *rpos;
2958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (data->state != CONFIRM) {
2978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		ret->ignore = TRUE;
2988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
2998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
3008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "EAP-SAKE: Received Request/Confirm");
3028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (eap_sake_parse_attributes(payload, payload_len, &attr))
3048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
3058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!attr.mic_s) {
3078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_INFO, "EAP-SAKE: Request/Confirm did not "
3088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "include AT_MIC_S");
3098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
3108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
3118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
312849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt	if (eap_sake_compute_mic(data->tek.auth, data->rand_s, data->rand_p,
313849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt				 data->serverid, data->serverid_len,
314849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt				 data->peerid, data->peerid_len, 0,
315849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt				 wpabuf_head(reqData), wpabuf_len(reqData),
316849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt				 attr.mic_s, mic_s)) {
317849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt		wpa_printf(MSG_INFO, "EAP-SAKE: Failed to compute MIC");
318849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt		eap_sake_state(data, FAILURE);
319849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt		ret->methodState = METHOD_DONE;
320849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt		ret->decision = DECISION_FAIL;
321849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt		ret->allowNotifications = FALSE;
322849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt		wpa_printf(MSG_DEBUG, "EAP-SAKE: Sending Response/Auth-Reject");
323849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt		return eap_sake_build_msg(data, id, 0,
324849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt					  EAP_SAKE_SUBTYPE_AUTH_REJECT);
325849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt	}
326c28170251eb54dbf64a9074a07fee377587425b2Dmitry Shmidt	if (os_memcmp_const(attr.mic_s, mic_s, EAP_SAKE_MIC_LEN) != 0) {
3278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_INFO, "EAP-SAKE: Incorrect AT_MIC_S");
3288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		eap_sake_state(data, FAILURE);
3298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		ret->methodState = METHOD_DONE;
3308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		ret->decision = DECISION_FAIL;
3318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		ret->allowNotifications = FALSE;
3328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "EAP-SAKE: Sending "
3338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "Response/Auth-Reject");
334cc00d5dc8483e32158b2ba61ea44b0c38d790ed7Dmitry Shmidt		return eap_sake_build_msg(data, id, 0,
3358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					  EAP_SAKE_SUBTYPE_AUTH_REJECT);
3368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
3378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "EAP-SAKE: Sending Response/Confirm");
3398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
340cc00d5dc8483e32158b2ba61ea44b0c38d790ed7Dmitry Shmidt	resp = eap_sake_build_msg(data, id, 2 + EAP_SAKE_MIC_LEN,
3418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				  EAP_SAKE_SUBTYPE_CONFIRM);
3428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (resp == NULL)
3438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
3448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_MIC_P");
3468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_u8(resp, EAP_SAKE_AT_MIC_P);
3478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_u8(resp, 2 + EAP_SAKE_MIC_LEN);
3488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	rpos = wpabuf_put(resp, EAP_SAKE_MIC_LEN);
3498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (eap_sake_compute_mic(data->tek.auth, data->rand_s, data->rand_p,
3508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				 data->serverid, data->serverid_len,
3518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				 data->peerid, data->peerid_len, 1,
3528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				 wpabuf_head(resp), wpabuf_len(resp), rpos,
3538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				 rpos)) {
3548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_INFO, "EAP-SAKE: Failed to compute MIC");
3558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpabuf_free(resp);
3568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
3578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
3588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eap_sake_state(data, SUCCESS);
3608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ret->methodState = METHOD_DONE;
3618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ret->decision = DECISION_UNCOND_SUCC;
3628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ret->allowNotifications = FALSE;
3638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return resp;
3658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
3668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic struct wpabuf * eap_sake_process(struct eap_sm *sm, void *priv,
3698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					struct eap_method_ret *ret,
3708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					const struct wpabuf *reqData)
3718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
3728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct eap_sake_data *data = priv;
3738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const struct eap_sake_hdr *req;
3748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpabuf *resp;
3758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const u8 *pos, *end;
3768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	size_t len;
377cc00d5dc8483e32158b2ba61ea44b0c38d790ed7Dmitry Shmidt	u8 subtype, session_id, id;
3788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_SAKE, reqData, &len);
3808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (pos == NULL || len < sizeof(struct eap_sake_hdr)) {
3818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		ret->ignore = TRUE;
3828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
3838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
3848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	req = (const struct eap_sake_hdr *) pos;
3868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	end = pos + len;
387cc00d5dc8483e32158b2ba61ea44b0c38d790ed7Dmitry Shmidt	id = eap_get_id(reqData);
3888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	subtype = req->subtype;
3898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	session_id = req->session_id;
3908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos = (const u8 *) (req + 1);
3918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "EAP-SAKE: Received frame: subtype %d "
3938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   "session_id %d", subtype, session_id);
3948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_hexdump(MSG_DEBUG, "EAP-SAKE: Received attributes",
3958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    pos, end - pos);
3968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (data->session_id_set && data->session_id != session_id) {
3988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_INFO, "EAP-SAKE: Session ID mismatch (%d,%d)",
3998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   session_id, data->session_id);
4008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		ret->ignore = TRUE;
4018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
4028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
4038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	data->session_id = session_id;
4048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	data->session_id_set = 1;
4058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ret->ignore = FALSE;
4078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ret->methodState = METHOD_MAY_CONT;
4088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ret->decision = DECISION_FAIL;
4098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ret->allowNotifications = TRUE;
4108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	switch (subtype) {
4128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case EAP_SAKE_SUBTYPE_IDENTITY:
413cc00d5dc8483e32158b2ba61ea44b0c38d790ed7Dmitry Shmidt		resp = eap_sake_process_identity(sm, data, ret, id,
4148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt						 pos, end - pos);
4158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
4168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case EAP_SAKE_SUBTYPE_CHALLENGE:
417cc00d5dc8483e32158b2ba61ea44b0c38d790ed7Dmitry Shmidt		resp = eap_sake_process_challenge(sm, data, ret, id,
4188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt						  pos, end - pos);
4198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
4208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case EAP_SAKE_SUBTYPE_CONFIRM:
421cc00d5dc8483e32158b2ba61ea44b0c38d790ed7Dmitry Shmidt		resp = eap_sake_process_confirm(sm, data, ret, id, reqData,
4228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt						pos, end - pos);
4238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
4248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	default:
4258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "EAP-SAKE: Ignoring message with "
4268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "unknown subtype %d", subtype);
4278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		ret->ignore = TRUE;
4288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
4298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
4308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ret->methodState == METHOD_DONE)
4328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		ret->allowNotifications = FALSE;
4338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return resp;
4358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
4368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic Boolean eap_sake_isKeyAvailable(struct eap_sm *sm, void *priv)
4398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
4408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct eap_sake_data *data = priv;
4418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return data->state == SUCCESS;
4428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
4438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic u8 * eap_sake_getKey(struct eap_sm *sm, void *priv, size_t *len)
4468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
4478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct eap_sake_data *data = priv;
4488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 *key;
4498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (data->state != SUCCESS)
4518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
4528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	key = os_malloc(EAP_MSK_LEN);
4548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (key == NULL)
4558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
4568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(key, data->msk, EAP_MSK_LEN);
4578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	*len = EAP_MSK_LEN;
4588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return key;
4608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
4618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
463f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidtstatic u8 * eap_sake_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
464f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt{
465f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt	struct eap_sake_data *data = priv;
466f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt	u8 *id;
467f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt
468f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt	if (data->state != SUCCESS)
469f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt		return NULL;
470f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt
471f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt	*len = 1 + 2 * EAP_SAKE_RAND_LEN;
472f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt	id = os_malloc(*len);
473f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt	if (id == NULL)
474f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt		return NULL;
475f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt
476f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt	id[0] = EAP_TYPE_SAKE;
477f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt	os_memcpy(id + 1, data->rand_s, EAP_SAKE_RAND_LEN);
478f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt	os_memcpy(id + 1 + EAP_SAKE_RAND_LEN, data->rand_s, EAP_SAKE_RAND_LEN);
479f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt	wpa_hexdump(MSG_DEBUG, "EAP-SAKE: Derived Session-Id", id, *len);
480f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt
481f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt	return id;
482f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt}
483f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt
484f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt
4858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic u8 * eap_sake_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
4868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
4878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct eap_sake_data *data = priv;
4888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 *key;
4898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (data->state != SUCCESS)
4918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
4928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	key = os_malloc(EAP_EMSK_LEN);
4948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (key == NULL)
4958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
4968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(key, data->emsk, EAP_EMSK_LEN);
4978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	*len = EAP_EMSK_LEN;
4988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return key;
5008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
5018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint eap_peer_sake_register(void)
5048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
5058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct eap_method *eap;
5068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
5088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				    EAP_VENDOR_IETF, EAP_TYPE_SAKE, "SAKE");
5098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (eap == NULL)
5108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
5118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eap->init = eap_sake_init;
5138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eap->deinit = eap_sake_deinit;
5148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eap->process = eap_sake_process;
5158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eap->isKeyAvailable = eap_sake_isKeyAvailable;
5168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eap->getKey = eap_sake_getKey;
517f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt	eap->getSessionId = eap_sake_get_session_id;
5188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eap->get_emsk = eap_sake_get_emsk;
5198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5201d6bf427f4769edb60865a3999d01eeb8f8fcb19Dmitry Shmidt	return eap_peer_method_register(eap);
5218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
522