xref: /dflybsd-src/contrib/wpa_supplicant/src/eap_server/eap_server_sake.c (revision 3a84a4273475ed07d0ab1c2dfeffdfedef35d9cd)
13ff40c12SJohn Marino /*
23ff40c12SJohn Marino  * hostapd / EAP-SAKE (RFC 4763) server
33ff40c12SJohn Marino  * Copyright (c) 2006-2007, 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_server/eap_i.h"
143ff40c12SJohn Marino #include "eap_common/eap_sake_common.h"
153ff40c12SJohn Marino 
163ff40c12SJohn Marino 
173ff40c12SJohn Marino struct eap_sake_data {
183ff40c12SJohn Marino 	enum { IDENTITY, CHALLENGE, CONFIRM, SUCCESS, FAILURE } state;
193ff40c12SJohn Marino 	u8 rand_s[EAP_SAKE_RAND_LEN];
203ff40c12SJohn Marino 	u8 rand_p[EAP_SAKE_RAND_LEN];
213ff40c12SJohn Marino 	struct {
223ff40c12SJohn Marino 		u8 auth[EAP_SAKE_TEK_AUTH_LEN];
233ff40c12SJohn Marino 		u8 cipher[EAP_SAKE_TEK_CIPHER_LEN];
243ff40c12SJohn Marino 	} tek;
253ff40c12SJohn Marino 	u8 msk[EAP_MSK_LEN];
263ff40c12SJohn Marino 	u8 emsk[EAP_EMSK_LEN];
273ff40c12SJohn Marino 	u8 session_id;
283ff40c12SJohn Marino 	u8 *peerid;
293ff40c12SJohn Marino 	size_t peerid_len;
303ff40c12SJohn Marino };
313ff40c12SJohn Marino 
323ff40c12SJohn Marino 
eap_sake_state_txt(int state)333ff40c12SJohn Marino static const char * eap_sake_state_txt(int state)
343ff40c12SJohn Marino {
353ff40c12SJohn Marino 	switch (state) {
363ff40c12SJohn Marino 	case IDENTITY:
373ff40c12SJohn Marino 		return "IDENTITY";
383ff40c12SJohn Marino 	case CHALLENGE:
393ff40c12SJohn Marino 		return "CHALLENGE";
403ff40c12SJohn Marino 	case CONFIRM:
413ff40c12SJohn Marino 		return "CONFIRM";
423ff40c12SJohn Marino 	case SUCCESS:
433ff40c12SJohn Marino 		return "SUCCESS";
443ff40c12SJohn Marino 	case FAILURE:
453ff40c12SJohn Marino 		return "FAILURE";
463ff40c12SJohn Marino 	default:
473ff40c12SJohn Marino 		return "?";
483ff40c12SJohn Marino 	}
493ff40c12SJohn Marino }
503ff40c12SJohn Marino 
513ff40c12SJohn Marino 
eap_sake_state(struct eap_sake_data * data,int state)523ff40c12SJohn Marino static void eap_sake_state(struct eap_sake_data *data, int state)
533ff40c12SJohn Marino {
543ff40c12SJohn Marino 	wpa_printf(MSG_DEBUG, "EAP-SAKE: %s -> %s",
553ff40c12SJohn Marino 		   eap_sake_state_txt(data->state),
563ff40c12SJohn Marino 		   eap_sake_state_txt(state));
573ff40c12SJohn Marino 	data->state = state;
583ff40c12SJohn Marino }
593ff40c12SJohn Marino 
603ff40c12SJohn Marino 
eap_sake_init(struct eap_sm * sm)613ff40c12SJohn Marino static void * eap_sake_init(struct eap_sm *sm)
623ff40c12SJohn Marino {
633ff40c12SJohn Marino 	struct eap_sake_data *data;
643ff40c12SJohn Marino 
653ff40c12SJohn Marino 	data = os_zalloc(sizeof(*data));
663ff40c12SJohn Marino 	if (data == NULL)
673ff40c12SJohn Marino 		return NULL;
683ff40c12SJohn Marino 	data->state = CHALLENGE;
693ff40c12SJohn Marino 
703ff40c12SJohn Marino 	if (os_get_random(&data->session_id, 1)) {
713ff40c12SJohn Marino 		wpa_printf(MSG_ERROR, "EAP-SAKE: Failed to get random data");
723ff40c12SJohn Marino 		os_free(data);
733ff40c12SJohn Marino 		return NULL;
743ff40c12SJohn Marino 	}
753ff40c12SJohn Marino 	wpa_printf(MSG_DEBUG, "EAP-SAKE: Initialized Session ID %d",
763ff40c12SJohn Marino 		   data->session_id);
773ff40c12SJohn Marino 
783ff40c12SJohn Marino 	return data;
793ff40c12SJohn Marino }
803ff40c12SJohn Marino 
813ff40c12SJohn Marino 
eap_sake_reset(struct eap_sm * sm,void * priv)823ff40c12SJohn Marino static void eap_sake_reset(struct eap_sm *sm, void *priv)
833ff40c12SJohn Marino {
843ff40c12SJohn Marino 	struct eap_sake_data *data = priv;
853ff40c12SJohn Marino 	os_free(data->peerid);
86*a1157835SDaniel Fojt 	bin_clear_free(data, sizeof(*data));
873ff40c12SJohn Marino }
883ff40c12SJohn Marino 
893ff40c12SJohn Marino 
eap_sake_build_msg(struct eap_sake_data * data,u8 id,size_t length,u8 subtype)903ff40c12SJohn Marino static struct wpabuf * eap_sake_build_msg(struct eap_sake_data *data,
913ff40c12SJohn Marino 					  u8 id, size_t length, u8 subtype)
923ff40c12SJohn Marino {
933ff40c12SJohn Marino 	struct eap_sake_hdr *sake;
943ff40c12SJohn Marino 	struct wpabuf *msg;
953ff40c12SJohn Marino 	size_t plen;
963ff40c12SJohn Marino 
973ff40c12SJohn Marino 	plen = sizeof(struct eap_sake_hdr) + length;
983ff40c12SJohn Marino 
993ff40c12SJohn Marino 	msg = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_SAKE, plen,
1003ff40c12SJohn Marino 			    EAP_CODE_REQUEST, id);
1013ff40c12SJohn Marino 	if (msg == NULL) {
1023ff40c12SJohn Marino 		wpa_printf(MSG_ERROR, "EAP-SAKE: Failed to allocate memory "
1033ff40c12SJohn Marino 			   "request");
1043ff40c12SJohn Marino 		return NULL;
1053ff40c12SJohn Marino 	}
1063ff40c12SJohn Marino 
1073ff40c12SJohn Marino 	sake = wpabuf_put(msg, sizeof(*sake));
1083ff40c12SJohn Marino 	sake->version = EAP_SAKE_VERSION;
1093ff40c12SJohn Marino 	sake->session_id = data->session_id;
1103ff40c12SJohn Marino 	sake->subtype = subtype;
1113ff40c12SJohn Marino 
1123ff40c12SJohn Marino 	return msg;
1133ff40c12SJohn Marino }
1143ff40c12SJohn Marino 
1153ff40c12SJohn Marino 
eap_sake_build_identity(struct eap_sm * sm,struct eap_sake_data * data,u8 id)1163ff40c12SJohn Marino static struct wpabuf * eap_sake_build_identity(struct eap_sm *sm,
1173ff40c12SJohn Marino 					       struct eap_sake_data *data,
1183ff40c12SJohn Marino 					       u8 id)
1193ff40c12SJohn Marino {
1203ff40c12SJohn Marino 	struct wpabuf *msg;
1213ff40c12SJohn Marino 	size_t plen;
1223ff40c12SJohn Marino 
1233ff40c12SJohn Marino 	wpa_printf(MSG_DEBUG, "EAP-SAKE: Request/Identity");
1243ff40c12SJohn Marino 
1253ff40c12SJohn Marino 	plen = 4;
1263ff40c12SJohn Marino 	plen += 2 + sm->server_id_len;
1273ff40c12SJohn Marino 	msg = eap_sake_build_msg(data, id, plen, EAP_SAKE_SUBTYPE_IDENTITY);
1283ff40c12SJohn Marino 	if (msg == NULL) {
1293ff40c12SJohn Marino 		data->state = FAILURE;
1303ff40c12SJohn Marino 		return NULL;
1313ff40c12SJohn Marino 	}
1323ff40c12SJohn Marino 
1333ff40c12SJohn Marino 	wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_PERM_ID_REQ");
1343ff40c12SJohn Marino 	eap_sake_add_attr(msg, EAP_SAKE_AT_PERM_ID_REQ, NULL, 2);
1353ff40c12SJohn Marino 
1363ff40c12SJohn Marino 	wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_SERVERID");
1373ff40c12SJohn Marino 	eap_sake_add_attr(msg, EAP_SAKE_AT_SERVERID,
1383ff40c12SJohn Marino 			  sm->server_id, sm->server_id_len);
1393ff40c12SJohn Marino 
1403ff40c12SJohn Marino 	return msg;
1413ff40c12SJohn Marino }
1423ff40c12SJohn Marino 
1433ff40c12SJohn Marino 
eap_sake_build_challenge(struct eap_sm * sm,struct eap_sake_data * data,u8 id)1443ff40c12SJohn Marino static struct wpabuf * eap_sake_build_challenge(struct eap_sm *sm,
1453ff40c12SJohn Marino 						struct eap_sake_data *data,
1463ff40c12SJohn Marino 						u8 id)
1473ff40c12SJohn Marino {
1483ff40c12SJohn Marino 	struct wpabuf *msg;
1493ff40c12SJohn Marino 	size_t plen;
1503ff40c12SJohn Marino 
1513ff40c12SJohn Marino 	wpa_printf(MSG_DEBUG, "EAP-SAKE: Request/Challenge");
1523ff40c12SJohn Marino 
1533ff40c12SJohn Marino 	if (random_get_bytes(data->rand_s, EAP_SAKE_RAND_LEN)) {
1543ff40c12SJohn Marino 		wpa_printf(MSG_ERROR, "EAP-SAKE: Failed to get random data");
1553ff40c12SJohn Marino 		data->state = FAILURE;
1563ff40c12SJohn Marino 		return NULL;
1573ff40c12SJohn Marino 	}
1583ff40c12SJohn Marino 	wpa_hexdump(MSG_MSGDUMP, "EAP-SAKE: RAND_S (server rand)",
1593ff40c12SJohn Marino 		    data->rand_s, EAP_SAKE_RAND_LEN);
1603ff40c12SJohn Marino 
1613ff40c12SJohn Marino 	plen = 2 + EAP_SAKE_RAND_LEN + 2 + sm->server_id_len;
1623ff40c12SJohn Marino 	msg = eap_sake_build_msg(data, id, plen, EAP_SAKE_SUBTYPE_CHALLENGE);
1633ff40c12SJohn Marino 	if (msg == NULL) {
1643ff40c12SJohn Marino 		data->state = FAILURE;
1653ff40c12SJohn Marino 		return NULL;
1663ff40c12SJohn Marino 	}
1673ff40c12SJohn Marino 
1683ff40c12SJohn Marino 	wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_RAND_S");
1693ff40c12SJohn Marino 	eap_sake_add_attr(msg, EAP_SAKE_AT_RAND_S,
1703ff40c12SJohn Marino 			  data->rand_s, EAP_SAKE_RAND_LEN);
1713ff40c12SJohn Marino 
1723ff40c12SJohn Marino 	wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_SERVERID");
1733ff40c12SJohn Marino 	eap_sake_add_attr(msg, EAP_SAKE_AT_SERVERID,
1743ff40c12SJohn Marino 			  sm->server_id, sm->server_id_len);
1753ff40c12SJohn Marino 
1763ff40c12SJohn Marino 	return msg;
1773ff40c12SJohn Marino }
1783ff40c12SJohn Marino 
1793ff40c12SJohn Marino 
eap_sake_build_confirm(struct eap_sm * sm,struct eap_sake_data * data,u8 id)1803ff40c12SJohn Marino static struct wpabuf * eap_sake_build_confirm(struct eap_sm *sm,
1813ff40c12SJohn Marino 					      struct eap_sake_data *data,
1823ff40c12SJohn Marino 					      u8 id)
1833ff40c12SJohn Marino {
1843ff40c12SJohn Marino 	struct wpabuf *msg;
1853ff40c12SJohn Marino 	u8 *mic;
1863ff40c12SJohn Marino 
1873ff40c12SJohn Marino 	wpa_printf(MSG_DEBUG, "EAP-SAKE: Request/Confirm");
1883ff40c12SJohn Marino 
1893ff40c12SJohn Marino 	msg = eap_sake_build_msg(data, id, 2 + EAP_SAKE_MIC_LEN,
1903ff40c12SJohn Marino 				 EAP_SAKE_SUBTYPE_CONFIRM);
1913ff40c12SJohn Marino 	if (msg == NULL) {
1923ff40c12SJohn Marino 		data->state = FAILURE;
1933ff40c12SJohn Marino 		return NULL;
1943ff40c12SJohn Marino 	}
1953ff40c12SJohn Marino 
1963ff40c12SJohn Marino 	wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_MIC_S");
1973ff40c12SJohn Marino 	wpabuf_put_u8(msg, EAP_SAKE_AT_MIC_S);
1983ff40c12SJohn Marino 	wpabuf_put_u8(msg, 2 + EAP_SAKE_MIC_LEN);
1993ff40c12SJohn Marino 	mic = wpabuf_put(msg, EAP_SAKE_MIC_LEN);
2003ff40c12SJohn Marino 	if (eap_sake_compute_mic(data->tek.auth, data->rand_s, data->rand_p,
2013ff40c12SJohn Marino 				 sm->server_id, sm->server_id_len,
2023ff40c12SJohn Marino 				 data->peerid, data->peerid_len, 0,
2033ff40c12SJohn Marino 				 wpabuf_head(msg), wpabuf_len(msg), mic, mic))
2043ff40c12SJohn Marino 	{
2053ff40c12SJohn Marino 		wpa_printf(MSG_INFO, "EAP-SAKE: Failed to compute MIC");
2063ff40c12SJohn Marino 		data->state = FAILURE;
207*a1157835SDaniel Fojt 		wpabuf_free(msg);
2083ff40c12SJohn Marino 		return NULL;
2093ff40c12SJohn Marino 	}
2103ff40c12SJohn Marino 
2113ff40c12SJohn Marino 	return msg;
2123ff40c12SJohn Marino }
2133ff40c12SJohn Marino 
2143ff40c12SJohn Marino 
eap_sake_buildReq(struct eap_sm * sm,void * priv,u8 id)2153ff40c12SJohn Marino static struct wpabuf * eap_sake_buildReq(struct eap_sm *sm, void *priv, u8 id)
2163ff40c12SJohn Marino {
2173ff40c12SJohn Marino 	struct eap_sake_data *data = priv;
2183ff40c12SJohn Marino 
2193ff40c12SJohn Marino 	switch (data->state) {
2203ff40c12SJohn Marino 	case IDENTITY:
2213ff40c12SJohn Marino 		return eap_sake_build_identity(sm, data, id);
2223ff40c12SJohn Marino 	case CHALLENGE:
2233ff40c12SJohn Marino 		return eap_sake_build_challenge(sm, data, id);
2243ff40c12SJohn Marino 	case CONFIRM:
2253ff40c12SJohn Marino 		return eap_sake_build_confirm(sm, data, id);
2263ff40c12SJohn Marino 	default:
2273ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "EAP-SAKE: Unknown state %d in buildReq",
2283ff40c12SJohn Marino 			   data->state);
2293ff40c12SJohn Marino 		break;
2303ff40c12SJohn Marino 	}
2313ff40c12SJohn Marino 	return NULL;
2323ff40c12SJohn Marino }
2333ff40c12SJohn Marino 
2343ff40c12SJohn Marino 
eap_sake_check(struct eap_sm * sm,void * priv,struct wpabuf * respData)2353ff40c12SJohn Marino static Boolean eap_sake_check(struct eap_sm *sm, void *priv,
2363ff40c12SJohn Marino 			      struct wpabuf *respData)
2373ff40c12SJohn Marino {
2383ff40c12SJohn Marino 	struct eap_sake_data *data = priv;
2393ff40c12SJohn Marino 	struct eap_sake_hdr *resp;
2403ff40c12SJohn Marino 	size_t len;
2413ff40c12SJohn Marino 	u8 version, session_id, subtype;
2423ff40c12SJohn Marino 	const u8 *pos;
2433ff40c12SJohn Marino 
2443ff40c12SJohn Marino 	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_SAKE, respData, &len);
2453ff40c12SJohn Marino 	if (pos == NULL || len < sizeof(struct eap_sake_hdr)) {
2463ff40c12SJohn Marino 		wpa_printf(MSG_INFO, "EAP-SAKE: Invalid frame");
2473ff40c12SJohn Marino 		return TRUE;
2483ff40c12SJohn Marino 	}
2493ff40c12SJohn Marino 
2503ff40c12SJohn Marino 	resp = (struct eap_sake_hdr *) pos;
2513ff40c12SJohn Marino 	version = resp->version;
2523ff40c12SJohn Marino 	session_id = resp->session_id;
2533ff40c12SJohn Marino 	subtype = resp->subtype;
2543ff40c12SJohn Marino 
2553ff40c12SJohn Marino 	if (version != EAP_SAKE_VERSION) {
2563ff40c12SJohn Marino 		wpa_printf(MSG_INFO, "EAP-SAKE: Unknown version %d", version);
2573ff40c12SJohn Marino 		return TRUE;
2583ff40c12SJohn Marino 	}
2593ff40c12SJohn Marino 
2603ff40c12SJohn Marino 	if (session_id != data->session_id) {
2613ff40c12SJohn Marino 		wpa_printf(MSG_INFO, "EAP-SAKE: Session ID mismatch (%d,%d)",
2623ff40c12SJohn Marino 			   session_id, data->session_id);
2633ff40c12SJohn Marino 		return TRUE;
2643ff40c12SJohn Marino 	}
2653ff40c12SJohn Marino 
2663ff40c12SJohn Marino 	wpa_printf(MSG_DEBUG, "EAP-SAKE: Received frame: subtype=%d", subtype);
2673ff40c12SJohn Marino 
2683ff40c12SJohn Marino 	if (data->state == IDENTITY && subtype == EAP_SAKE_SUBTYPE_IDENTITY)
2693ff40c12SJohn Marino 		return FALSE;
2703ff40c12SJohn Marino 
2713ff40c12SJohn Marino 	if (data->state == CHALLENGE && subtype == EAP_SAKE_SUBTYPE_CHALLENGE)
2723ff40c12SJohn Marino 		return FALSE;
2733ff40c12SJohn Marino 
2743ff40c12SJohn Marino 	if (data->state == CONFIRM && subtype == EAP_SAKE_SUBTYPE_CONFIRM)
2753ff40c12SJohn Marino 		return FALSE;
2763ff40c12SJohn Marino 
2773ff40c12SJohn Marino 	if (subtype == EAP_SAKE_SUBTYPE_AUTH_REJECT)
2783ff40c12SJohn Marino 		return FALSE;
2793ff40c12SJohn Marino 
2803ff40c12SJohn Marino 	wpa_printf(MSG_INFO, "EAP-SAKE: Unexpected subtype=%d in state=%d",
2813ff40c12SJohn Marino 		   subtype, data->state);
2823ff40c12SJohn Marino 
2833ff40c12SJohn Marino 	return TRUE;
2843ff40c12SJohn Marino }
2853ff40c12SJohn Marino 
2863ff40c12SJohn Marino 
eap_sake_process_identity(struct eap_sm * sm,struct eap_sake_data * data,const struct wpabuf * respData,const u8 * payload,size_t payloadlen)2873ff40c12SJohn Marino static void eap_sake_process_identity(struct eap_sm *sm,
2883ff40c12SJohn Marino 				      struct eap_sake_data *data,
2893ff40c12SJohn Marino 				      const struct wpabuf *respData,
2903ff40c12SJohn Marino 				      const u8 *payload, size_t payloadlen)
2913ff40c12SJohn Marino {
2923ff40c12SJohn Marino 	if (data->state != IDENTITY)
2933ff40c12SJohn Marino 		return;
2943ff40c12SJohn Marino 
2953ff40c12SJohn Marino 	wpa_printf(MSG_DEBUG, "EAP-SAKE: Received Response/Identity");
2963ff40c12SJohn Marino 	/* TODO: update identity and select new user data */
2973ff40c12SJohn Marino 	eap_sake_state(data, CHALLENGE);
2983ff40c12SJohn Marino }
2993ff40c12SJohn Marino 
3003ff40c12SJohn Marino 
eap_sake_process_challenge(struct eap_sm * sm,struct eap_sake_data * data,const struct wpabuf * respData,const u8 * payload,size_t payloadlen)3013ff40c12SJohn Marino static void eap_sake_process_challenge(struct eap_sm *sm,
3023ff40c12SJohn Marino 				       struct eap_sake_data *data,
3033ff40c12SJohn Marino 				       const struct wpabuf *respData,
3043ff40c12SJohn Marino 				       const u8 *payload, size_t payloadlen)
3053ff40c12SJohn Marino {
3063ff40c12SJohn Marino 	struct eap_sake_parse_attr attr;
3073ff40c12SJohn Marino 	u8 mic_p[EAP_SAKE_MIC_LEN];
3083ff40c12SJohn Marino 
3093ff40c12SJohn Marino 	if (data->state != CHALLENGE)
3103ff40c12SJohn Marino 		return;
3113ff40c12SJohn Marino 
3123ff40c12SJohn Marino 	wpa_printf(MSG_DEBUG, "EAP-SAKE: Received Response/Challenge");
3133ff40c12SJohn Marino 
3143ff40c12SJohn Marino 	if (eap_sake_parse_attributes(payload, payloadlen, &attr))
3153ff40c12SJohn Marino 		return;
3163ff40c12SJohn Marino 
3173ff40c12SJohn Marino 	if (!attr.rand_p || !attr.mic_p) {
3183ff40c12SJohn Marino 		wpa_printf(MSG_INFO, "EAP-SAKE: Response/Challenge did not "
3193ff40c12SJohn Marino 			   "include AT_RAND_P or AT_MIC_P");
3203ff40c12SJohn Marino 		return;
3213ff40c12SJohn Marino 	}
3223ff40c12SJohn Marino 
3233ff40c12SJohn Marino 	os_memcpy(data->rand_p, attr.rand_p, EAP_SAKE_RAND_LEN);
3243ff40c12SJohn Marino 
3253ff40c12SJohn Marino 	os_free(data->peerid);
3263ff40c12SJohn Marino 	data->peerid = NULL;
3273ff40c12SJohn Marino 	data->peerid_len = 0;
3283ff40c12SJohn Marino 	if (attr.peerid) {
329*a1157835SDaniel Fojt 		data->peerid = os_memdup(attr.peerid, attr.peerid_len);
3303ff40c12SJohn Marino 		if (data->peerid == NULL)
3313ff40c12SJohn Marino 			return;
3323ff40c12SJohn Marino 		data->peerid_len = attr.peerid_len;
3333ff40c12SJohn Marino 	}
3343ff40c12SJohn Marino 
3353ff40c12SJohn Marino 	if (sm->user == NULL || sm->user->password == NULL ||
3363ff40c12SJohn Marino 	    sm->user->password_len != 2 * EAP_SAKE_ROOT_SECRET_LEN) {
3373ff40c12SJohn Marino 		wpa_printf(MSG_INFO, "EAP-SAKE: Plaintext password with "
3383ff40c12SJohn Marino 			   "%d-byte key not configured",
3393ff40c12SJohn Marino 			   2 * EAP_SAKE_ROOT_SECRET_LEN);
3403ff40c12SJohn Marino 		data->state = FAILURE;
3413ff40c12SJohn Marino 		return;
3423ff40c12SJohn Marino 	}
343*a1157835SDaniel Fojt 	if (eap_sake_derive_keys(sm->user->password,
3443ff40c12SJohn Marino 				 sm->user->password + EAP_SAKE_ROOT_SECRET_LEN,
3453ff40c12SJohn Marino 				 data->rand_s, data->rand_p,
346*a1157835SDaniel Fojt 				 (u8 *) &data->tek, data->msk,
347*a1157835SDaniel Fojt 				 data->emsk) < 0) {
348*a1157835SDaniel Fojt 		wpa_printf(MSG_INFO, "EAP-SAKE: Failed to derive keys");
349*a1157835SDaniel Fojt 		data->state = FAILURE;
350*a1157835SDaniel Fojt 		return;
351*a1157835SDaniel Fojt 	}
3523ff40c12SJohn Marino 
353*a1157835SDaniel Fojt 	if (eap_sake_compute_mic(data->tek.auth, data->rand_s, data->rand_p,
3543ff40c12SJohn Marino 				 sm->server_id, sm->server_id_len,
3553ff40c12SJohn Marino 				 data->peerid, data->peerid_len, 1,
3563ff40c12SJohn Marino 				 wpabuf_head(respData), wpabuf_len(respData),
357*a1157835SDaniel Fojt 				 attr.mic_p, mic_p) < 0) {
358*a1157835SDaniel Fojt 		wpa_printf(MSG_INFO, "EAP-SAKE: Failed to compute MIC");
359*a1157835SDaniel Fojt 		data->state = FAILURE;
360*a1157835SDaniel Fojt 		return;
361*a1157835SDaniel Fojt 	}
362*a1157835SDaniel Fojt 	if (os_memcmp_const(attr.mic_p, mic_p, EAP_SAKE_MIC_LEN) != 0) {
3633ff40c12SJohn Marino 		wpa_printf(MSG_INFO, "EAP-SAKE: Incorrect AT_MIC_P");
3643ff40c12SJohn Marino 		eap_sake_state(data, FAILURE);
3653ff40c12SJohn Marino 		return;
3663ff40c12SJohn Marino 	}
3673ff40c12SJohn Marino 
3683ff40c12SJohn Marino 	eap_sake_state(data, CONFIRM);
3693ff40c12SJohn Marino }
3703ff40c12SJohn Marino 
3713ff40c12SJohn Marino 
eap_sake_process_confirm(struct eap_sm * sm,struct eap_sake_data * data,const struct wpabuf * respData,const u8 * payload,size_t payloadlen)3723ff40c12SJohn Marino static void eap_sake_process_confirm(struct eap_sm *sm,
3733ff40c12SJohn Marino 				     struct eap_sake_data *data,
3743ff40c12SJohn Marino 				     const struct wpabuf *respData,
3753ff40c12SJohn Marino 				     const u8 *payload, size_t payloadlen)
3763ff40c12SJohn Marino {
3773ff40c12SJohn Marino 	struct eap_sake_parse_attr attr;
3783ff40c12SJohn Marino 	u8 mic_p[EAP_SAKE_MIC_LEN];
3793ff40c12SJohn Marino 
3803ff40c12SJohn Marino 	if (data->state != CONFIRM)
3813ff40c12SJohn Marino 		return;
3823ff40c12SJohn Marino 
3833ff40c12SJohn Marino 	wpa_printf(MSG_DEBUG, "EAP-SAKE: Received Response/Confirm");
3843ff40c12SJohn Marino 
3853ff40c12SJohn Marino 	if (eap_sake_parse_attributes(payload, payloadlen, &attr))
3863ff40c12SJohn Marino 		return;
3873ff40c12SJohn Marino 
3883ff40c12SJohn Marino 	if (!attr.mic_p) {
3893ff40c12SJohn Marino 		wpa_printf(MSG_INFO, "EAP-SAKE: Response/Confirm did not "
3903ff40c12SJohn Marino 			   "include AT_MIC_P");
3913ff40c12SJohn Marino 		return;
3923ff40c12SJohn Marino 	}
3933ff40c12SJohn Marino 
394*a1157835SDaniel Fojt 	if (eap_sake_compute_mic(data->tek.auth, data->rand_s, data->rand_p,
3953ff40c12SJohn Marino 				 sm->server_id, sm->server_id_len,
3963ff40c12SJohn Marino 				 data->peerid, data->peerid_len, 1,
3973ff40c12SJohn Marino 				 wpabuf_head(respData), wpabuf_len(respData),
398*a1157835SDaniel Fojt 				 attr.mic_p, mic_p) < 0) {
399*a1157835SDaniel Fojt 		wpa_printf(MSG_INFO, "EAP-SAKE: Failed to compute MIC");
400*a1157835SDaniel Fojt 		return;
401*a1157835SDaniel Fojt 	}
402*a1157835SDaniel Fojt 	if (os_memcmp_const(attr.mic_p, mic_p, EAP_SAKE_MIC_LEN) != 0) {
4033ff40c12SJohn Marino 		wpa_printf(MSG_INFO, "EAP-SAKE: Incorrect AT_MIC_P");
4043ff40c12SJohn Marino 		eap_sake_state(data, FAILURE);
4053ff40c12SJohn Marino 	} else
4063ff40c12SJohn Marino 		eap_sake_state(data, SUCCESS);
4073ff40c12SJohn Marino }
4083ff40c12SJohn Marino 
4093ff40c12SJohn Marino 
eap_sake_process_auth_reject(struct eap_sm * sm,struct eap_sake_data * data,const struct wpabuf * respData,const u8 * payload,size_t payloadlen)4103ff40c12SJohn Marino static void eap_sake_process_auth_reject(struct eap_sm *sm,
4113ff40c12SJohn Marino 					 struct eap_sake_data *data,
4123ff40c12SJohn Marino 					 const struct wpabuf *respData,
4133ff40c12SJohn Marino 					 const u8 *payload, size_t payloadlen)
4143ff40c12SJohn Marino {
4153ff40c12SJohn Marino 	wpa_printf(MSG_DEBUG, "EAP-SAKE: Received Response/Auth-Reject");
4163ff40c12SJohn Marino 	eap_sake_state(data, FAILURE);
4173ff40c12SJohn Marino }
4183ff40c12SJohn Marino 
4193ff40c12SJohn Marino 
eap_sake_process(struct eap_sm * sm,void * priv,struct wpabuf * respData)4203ff40c12SJohn Marino static void eap_sake_process(struct eap_sm *sm, void *priv,
4213ff40c12SJohn Marino 			     struct wpabuf *respData)
4223ff40c12SJohn Marino {
4233ff40c12SJohn Marino 	struct eap_sake_data *data = priv;
4243ff40c12SJohn Marino 	struct eap_sake_hdr *resp;
4253ff40c12SJohn Marino 	u8 subtype;
4263ff40c12SJohn Marino 	size_t len;
4273ff40c12SJohn Marino 	const u8 *pos, *end;
4283ff40c12SJohn Marino 
4293ff40c12SJohn Marino 	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_SAKE, respData, &len);
4303ff40c12SJohn Marino 	if (pos == NULL || len < sizeof(struct eap_sake_hdr))
4313ff40c12SJohn Marino 		return;
4323ff40c12SJohn Marino 
4333ff40c12SJohn Marino 	resp = (struct eap_sake_hdr *) pos;
4343ff40c12SJohn Marino 	end = pos + len;
4353ff40c12SJohn Marino 	subtype = resp->subtype;
4363ff40c12SJohn Marino 	pos = (u8 *) (resp + 1);
4373ff40c12SJohn Marino 
4383ff40c12SJohn Marino 	wpa_hexdump(MSG_DEBUG, "EAP-SAKE: Received attributes",
4393ff40c12SJohn Marino 		    pos, end - pos);
4403ff40c12SJohn Marino 
4413ff40c12SJohn Marino 	switch (subtype) {
4423ff40c12SJohn Marino 	case EAP_SAKE_SUBTYPE_IDENTITY:
4433ff40c12SJohn Marino 		eap_sake_process_identity(sm, data, respData, pos, end - pos);
4443ff40c12SJohn Marino 		break;
4453ff40c12SJohn Marino 	case EAP_SAKE_SUBTYPE_CHALLENGE:
4463ff40c12SJohn Marino 		eap_sake_process_challenge(sm, data, respData, pos, end - pos);
4473ff40c12SJohn Marino 		break;
4483ff40c12SJohn Marino 	case EAP_SAKE_SUBTYPE_CONFIRM:
4493ff40c12SJohn Marino 		eap_sake_process_confirm(sm, data, respData, pos, end - pos);
4503ff40c12SJohn Marino 		break;
4513ff40c12SJohn Marino 	case EAP_SAKE_SUBTYPE_AUTH_REJECT:
4523ff40c12SJohn Marino 		eap_sake_process_auth_reject(sm, data, respData, pos,
4533ff40c12SJohn Marino 					     end - pos);
4543ff40c12SJohn Marino 		break;
4553ff40c12SJohn Marino 	}
4563ff40c12SJohn Marino }
4573ff40c12SJohn Marino 
4583ff40c12SJohn Marino 
eap_sake_isDone(struct eap_sm * sm,void * priv)4593ff40c12SJohn Marino static Boolean eap_sake_isDone(struct eap_sm *sm, void *priv)
4603ff40c12SJohn Marino {
4613ff40c12SJohn Marino 	struct eap_sake_data *data = priv;
4623ff40c12SJohn Marino 	return data->state == SUCCESS || data->state == FAILURE;
4633ff40c12SJohn Marino }
4643ff40c12SJohn Marino 
4653ff40c12SJohn Marino 
eap_sake_getKey(struct eap_sm * sm,void * priv,size_t * len)4663ff40c12SJohn Marino static u8 * eap_sake_getKey(struct eap_sm *sm, void *priv, size_t *len)
4673ff40c12SJohn Marino {
4683ff40c12SJohn Marino 	struct eap_sake_data *data = priv;
4693ff40c12SJohn Marino 	u8 *key;
4703ff40c12SJohn Marino 
4713ff40c12SJohn Marino 	if (data->state != SUCCESS)
4723ff40c12SJohn Marino 		return NULL;
4733ff40c12SJohn Marino 
474*a1157835SDaniel Fojt 	key = os_memdup(data->msk, EAP_MSK_LEN);
4753ff40c12SJohn Marino 	if (key == NULL)
4763ff40c12SJohn Marino 		return NULL;
4773ff40c12SJohn Marino 	*len = EAP_MSK_LEN;
4783ff40c12SJohn Marino 
4793ff40c12SJohn Marino 	return key;
4803ff40c12SJohn Marino }
4813ff40c12SJohn Marino 
4823ff40c12SJohn Marino 
eap_sake_get_emsk(struct eap_sm * sm,void * priv,size_t * len)4833ff40c12SJohn Marino static u8 * eap_sake_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
4843ff40c12SJohn Marino {
4853ff40c12SJohn Marino 	struct eap_sake_data *data = priv;
4863ff40c12SJohn Marino 	u8 *key;
4873ff40c12SJohn Marino 
4883ff40c12SJohn Marino 	if (data->state != SUCCESS)
4893ff40c12SJohn Marino 		return NULL;
4903ff40c12SJohn Marino 
491*a1157835SDaniel Fojt 	key = os_memdup(data->emsk, EAP_EMSK_LEN);
4923ff40c12SJohn Marino 	if (key == NULL)
4933ff40c12SJohn Marino 		return NULL;
4943ff40c12SJohn Marino 	*len = EAP_EMSK_LEN;
4953ff40c12SJohn Marino 
4963ff40c12SJohn Marino 	return key;
4973ff40c12SJohn Marino }
4983ff40c12SJohn Marino 
4993ff40c12SJohn Marino 
eap_sake_isSuccess(struct eap_sm * sm,void * priv)5003ff40c12SJohn Marino static Boolean eap_sake_isSuccess(struct eap_sm *sm, void *priv)
5013ff40c12SJohn Marino {
5023ff40c12SJohn Marino 	struct eap_sake_data *data = priv;
5033ff40c12SJohn Marino 	return data->state == SUCCESS;
5043ff40c12SJohn Marino }
5053ff40c12SJohn Marino 
5063ff40c12SJohn Marino 
eap_sake_get_session_id(struct eap_sm * sm,void * priv,size_t * len)507*a1157835SDaniel Fojt static u8 * eap_sake_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
508*a1157835SDaniel Fojt {
509*a1157835SDaniel Fojt 	struct eap_sake_data *data = priv;
510*a1157835SDaniel Fojt 	u8 *id;
511*a1157835SDaniel Fojt 
512*a1157835SDaniel Fojt 	if (data->state != SUCCESS)
513*a1157835SDaniel Fojt 		return NULL;
514*a1157835SDaniel Fojt 
515*a1157835SDaniel Fojt 	*len = 1 + 2 * EAP_SAKE_RAND_LEN;
516*a1157835SDaniel Fojt 	id = os_malloc(*len);
517*a1157835SDaniel Fojt 	if (id == NULL)
518*a1157835SDaniel Fojt 		return NULL;
519*a1157835SDaniel Fojt 
520*a1157835SDaniel Fojt 	id[0] = EAP_TYPE_SAKE;
521*a1157835SDaniel Fojt 	os_memcpy(id + 1, data->rand_s, EAP_SAKE_RAND_LEN);
522*a1157835SDaniel Fojt 	os_memcpy(id + 1 + EAP_SAKE_RAND_LEN, data->rand_s, EAP_SAKE_RAND_LEN);
523*a1157835SDaniel Fojt 	wpa_hexdump(MSG_DEBUG, "EAP-SAKE: Derived Session-Id", id, *len);
524*a1157835SDaniel Fojt 
525*a1157835SDaniel Fojt 	return id;
526*a1157835SDaniel Fojt }
527*a1157835SDaniel Fojt 
528*a1157835SDaniel Fojt 
eap_server_sake_register(void)5293ff40c12SJohn Marino int eap_server_sake_register(void)
5303ff40c12SJohn Marino {
5313ff40c12SJohn Marino 	struct eap_method *eap;
5323ff40c12SJohn Marino 
5333ff40c12SJohn Marino 	eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
5343ff40c12SJohn Marino 				      EAP_VENDOR_IETF, EAP_TYPE_SAKE, "SAKE");
5353ff40c12SJohn Marino 	if (eap == NULL)
5363ff40c12SJohn Marino 		return -1;
5373ff40c12SJohn Marino 
5383ff40c12SJohn Marino 	eap->init = eap_sake_init;
5393ff40c12SJohn Marino 	eap->reset = eap_sake_reset;
5403ff40c12SJohn Marino 	eap->buildReq = eap_sake_buildReq;
5413ff40c12SJohn Marino 	eap->check = eap_sake_check;
5423ff40c12SJohn Marino 	eap->process = eap_sake_process;
5433ff40c12SJohn Marino 	eap->isDone = eap_sake_isDone;
5443ff40c12SJohn Marino 	eap->getKey = eap_sake_getKey;
5453ff40c12SJohn Marino 	eap->isSuccess = eap_sake_isSuccess;
5463ff40c12SJohn Marino 	eap->get_emsk = eap_sake_get_emsk;
547*a1157835SDaniel Fojt 	eap->getSessionId = eap_sake_get_session_id;
5483ff40c12SJohn Marino 
549*a1157835SDaniel Fojt 	return eap_server_method_register(eap);
5503ff40c12SJohn Marino }
551