1214501Srpaulo/*
2214501Srpaulo * hostapd / EAP-SAKE (RFC 4763) server
3214501Srpaulo * Copyright (c) 2006-2007, Jouni Malinen <j@w1.fi>
4214501Srpaulo *
5252726Srpaulo * This software may be distributed under the terms of the BSD license.
6252726Srpaulo * See README for more details.
7214501Srpaulo */
8214501Srpaulo
9214501Srpaulo#include "includes.h"
10214501Srpaulo
11214501Srpaulo#include "common.h"
12252726Srpaulo#include "crypto/random.h"
13214501Srpaulo#include "eap_server/eap_i.h"
14214501Srpaulo#include "eap_common/eap_sake_common.h"
15214501Srpaulo
16214501Srpaulo
17214501Srpaulostruct eap_sake_data {
18214501Srpaulo	enum { IDENTITY, CHALLENGE, CONFIRM, SUCCESS, FAILURE } state;
19214501Srpaulo	u8 rand_s[EAP_SAKE_RAND_LEN];
20214501Srpaulo	u8 rand_p[EAP_SAKE_RAND_LEN];
21214501Srpaulo	struct {
22214501Srpaulo		u8 auth[EAP_SAKE_TEK_AUTH_LEN];
23214501Srpaulo		u8 cipher[EAP_SAKE_TEK_CIPHER_LEN];
24214501Srpaulo	} tek;
25214501Srpaulo	u8 msk[EAP_MSK_LEN];
26214501Srpaulo	u8 emsk[EAP_EMSK_LEN];
27214501Srpaulo	u8 session_id;
28214501Srpaulo	u8 *peerid;
29214501Srpaulo	size_t peerid_len;
30214501Srpaulo	u8 *serverid;
31214501Srpaulo	size_t serverid_len;
32214501Srpaulo};
33214501Srpaulo
34214501Srpaulo
35214501Srpaulostatic const char * eap_sake_state_txt(int state)
36214501Srpaulo{
37214501Srpaulo	switch (state) {
38214501Srpaulo	case IDENTITY:
39214501Srpaulo		return "IDENTITY";
40214501Srpaulo	case CHALLENGE:
41214501Srpaulo		return "CHALLENGE";
42214501Srpaulo	case CONFIRM:
43214501Srpaulo		return "CONFIRM";
44214501Srpaulo	case SUCCESS:
45214501Srpaulo		return "SUCCESS";
46214501Srpaulo	case FAILURE:
47214501Srpaulo		return "FAILURE";
48214501Srpaulo	default:
49214501Srpaulo		return "?";
50214501Srpaulo	}
51214501Srpaulo}
52214501Srpaulo
53214501Srpaulo
54214501Srpaulostatic void eap_sake_state(struct eap_sake_data *data, int state)
55214501Srpaulo{
56214501Srpaulo	wpa_printf(MSG_DEBUG, "EAP-SAKE: %s -> %s",
57214501Srpaulo		   eap_sake_state_txt(data->state),
58214501Srpaulo		   eap_sake_state_txt(state));
59214501Srpaulo	data->state = state;
60214501Srpaulo}
61214501Srpaulo
62214501Srpaulo
63214501Srpaulostatic void * eap_sake_init(struct eap_sm *sm)
64214501Srpaulo{
65214501Srpaulo	struct eap_sake_data *data;
66214501Srpaulo
67214501Srpaulo	data = os_zalloc(sizeof(*data));
68214501Srpaulo	if (data == NULL)
69214501Srpaulo		return NULL;
70214501Srpaulo	data->state = CHALLENGE;
71214501Srpaulo
72214501Srpaulo	if (os_get_random(&data->session_id, 1)) {
73214501Srpaulo		wpa_printf(MSG_ERROR, "EAP-SAKE: Failed to get random data");
74214501Srpaulo		os_free(data);
75214501Srpaulo		return NULL;
76214501Srpaulo	}
77214501Srpaulo	wpa_printf(MSG_DEBUG, "EAP-SAKE: Initialized Session ID %d",
78214501Srpaulo		   data->session_id);
79214501Srpaulo
80214501Srpaulo	/* TODO: add support for configuring SERVERID */
81214501Srpaulo	data->serverid = (u8 *) os_strdup("hostapd");
82214501Srpaulo	if (data->serverid)
83214501Srpaulo		data->serverid_len = os_strlen((char *) data->serverid);
84214501Srpaulo
85214501Srpaulo	return data;
86214501Srpaulo}
87214501Srpaulo
88214501Srpaulo
89214501Srpaulostatic void eap_sake_reset(struct eap_sm *sm, void *priv)
90214501Srpaulo{
91214501Srpaulo	struct eap_sake_data *data = priv;
92214501Srpaulo	os_free(data->serverid);
93214501Srpaulo	os_free(data->peerid);
94214501Srpaulo	os_free(data);
95214501Srpaulo}
96214501Srpaulo
97214501Srpaulo
98214501Srpaulostatic struct wpabuf * eap_sake_build_msg(struct eap_sake_data *data,
99214501Srpaulo					  u8 id, size_t length, u8 subtype)
100214501Srpaulo{
101214501Srpaulo	struct eap_sake_hdr *sake;
102214501Srpaulo	struct wpabuf *msg;
103214501Srpaulo	size_t plen;
104214501Srpaulo
105214501Srpaulo	plen = sizeof(struct eap_sake_hdr) + length;
106214501Srpaulo
107214501Srpaulo	msg = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_SAKE, plen,
108214501Srpaulo			    EAP_CODE_REQUEST, id);
109214501Srpaulo	if (msg == NULL) {
110214501Srpaulo		wpa_printf(MSG_ERROR, "EAP-SAKE: Failed to allocate memory "
111214501Srpaulo			   "request");
112214501Srpaulo		return NULL;
113214501Srpaulo	}
114214501Srpaulo
115214501Srpaulo	sake = wpabuf_put(msg, sizeof(*sake));
116214501Srpaulo	sake->version = EAP_SAKE_VERSION;
117214501Srpaulo	sake->session_id = data->session_id;
118214501Srpaulo	sake->subtype = subtype;
119214501Srpaulo
120214501Srpaulo	return msg;
121214501Srpaulo}
122214501Srpaulo
123214501Srpaulo
124214501Srpaulostatic struct wpabuf * eap_sake_build_identity(struct eap_sm *sm,
125214501Srpaulo					       struct eap_sake_data *data,
126214501Srpaulo					       u8 id)
127214501Srpaulo{
128214501Srpaulo	struct wpabuf *msg;
129214501Srpaulo	size_t plen;
130214501Srpaulo
131214501Srpaulo	wpa_printf(MSG_DEBUG, "EAP-SAKE: Request/Identity");
132214501Srpaulo
133214501Srpaulo	plen = 4;
134214501Srpaulo	if (data->serverid)
135214501Srpaulo		plen += 2 + data->serverid_len;
136214501Srpaulo	msg = eap_sake_build_msg(data, id, plen, EAP_SAKE_SUBTYPE_IDENTITY);
137214501Srpaulo	if (msg == NULL) {
138214501Srpaulo		data->state = FAILURE;
139214501Srpaulo		return NULL;
140214501Srpaulo	}
141214501Srpaulo
142214501Srpaulo	wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_PERM_ID_REQ");
143214501Srpaulo	eap_sake_add_attr(msg, EAP_SAKE_AT_PERM_ID_REQ, NULL, 2);
144214501Srpaulo
145214501Srpaulo	if (data->serverid) {
146214501Srpaulo		wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_SERVERID");
147214501Srpaulo		eap_sake_add_attr(msg, EAP_SAKE_AT_SERVERID,
148214501Srpaulo				  data->serverid, data->serverid_len);
149214501Srpaulo	}
150214501Srpaulo
151214501Srpaulo	return msg;
152214501Srpaulo}
153214501Srpaulo
154214501Srpaulo
155214501Srpaulostatic struct wpabuf * eap_sake_build_challenge(struct eap_sm *sm,
156214501Srpaulo						struct eap_sake_data *data,
157214501Srpaulo						u8 id)
158214501Srpaulo{
159214501Srpaulo	struct wpabuf *msg;
160214501Srpaulo	size_t plen;
161214501Srpaulo
162214501Srpaulo	wpa_printf(MSG_DEBUG, "EAP-SAKE: Request/Challenge");
163214501Srpaulo
164252726Srpaulo	if (random_get_bytes(data->rand_s, EAP_SAKE_RAND_LEN)) {
165214501Srpaulo		wpa_printf(MSG_ERROR, "EAP-SAKE: Failed to get random data");
166214501Srpaulo		data->state = FAILURE;
167214501Srpaulo		return NULL;
168214501Srpaulo	}
169214501Srpaulo	wpa_hexdump(MSG_MSGDUMP, "EAP-SAKE: RAND_S (server rand)",
170214501Srpaulo		    data->rand_s, EAP_SAKE_RAND_LEN);
171214501Srpaulo
172214501Srpaulo	plen = 2 + EAP_SAKE_RAND_LEN;
173214501Srpaulo	if (data->serverid)
174214501Srpaulo		plen += 2 + data->serverid_len;
175214501Srpaulo	msg = eap_sake_build_msg(data, id, plen, EAP_SAKE_SUBTYPE_CHALLENGE);
176214501Srpaulo	if (msg == NULL) {
177214501Srpaulo		data->state = FAILURE;
178214501Srpaulo		return NULL;
179214501Srpaulo	}
180214501Srpaulo
181214501Srpaulo	wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_RAND_S");
182214501Srpaulo	eap_sake_add_attr(msg, EAP_SAKE_AT_RAND_S,
183214501Srpaulo			  data->rand_s, EAP_SAKE_RAND_LEN);
184214501Srpaulo
185214501Srpaulo	if (data->serverid) {
186214501Srpaulo		wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_SERVERID");
187214501Srpaulo		eap_sake_add_attr(msg, EAP_SAKE_AT_SERVERID,
188214501Srpaulo				  data->serverid, data->serverid_len);
189214501Srpaulo	}
190214501Srpaulo
191214501Srpaulo	return msg;
192214501Srpaulo}
193214501Srpaulo
194214501Srpaulo
195214501Srpaulostatic struct wpabuf * eap_sake_build_confirm(struct eap_sm *sm,
196214501Srpaulo					      struct eap_sake_data *data,
197214501Srpaulo					      u8 id)
198214501Srpaulo{
199214501Srpaulo	struct wpabuf *msg;
200214501Srpaulo	u8 *mic;
201214501Srpaulo
202214501Srpaulo	wpa_printf(MSG_DEBUG, "EAP-SAKE: Request/Confirm");
203214501Srpaulo
204214501Srpaulo	msg = eap_sake_build_msg(data, id, 2 + EAP_SAKE_MIC_LEN,
205214501Srpaulo				 EAP_SAKE_SUBTYPE_CONFIRM);
206214501Srpaulo	if (msg == NULL) {
207214501Srpaulo		data->state = FAILURE;
208214501Srpaulo		return NULL;
209214501Srpaulo	}
210214501Srpaulo
211214501Srpaulo	wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_MIC_S");
212214501Srpaulo	wpabuf_put_u8(msg, EAP_SAKE_AT_MIC_S);
213214501Srpaulo	wpabuf_put_u8(msg, 2 + EAP_SAKE_MIC_LEN);
214214501Srpaulo	mic = wpabuf_put(msg, EAP_SAKE_MIC_LEN);
215214501Srpaulo	if (eap_sake_compute_mic(data->tek.auth, data->rand_s, data->rand_p,
216214501Srpaulo				 data->serverid, data->serverid_len,
217214501Srpaulo				 data->peerid, data->peerid_len, 0,
218214501Srpaulo				 wpabuf_head(msg), wpabuf_len(msg), mic, mic))
219214501Srpaulo	{
220214501Srpaulo		wpa_printf(MSG_INFO, "EAP-SAKE: Failed to compute MIC");
221214501Srpaulo		data->state = FAILURE;
222214501Srpaulo		os_free(msg);
223214501Srpaulo		return NULL;
224214501Srpaulo	}
225214501Srpaulo
226214501Srpaulo	return msg;
227214501Srpaulo}
228214501Srpaulo
229214501Srpaulo
230214501Srpaulostatic struct wpabuf * eap_sake_buildReq(struct eap_sm *sm, void *priv, u8 id)
231214501Srpaulo{
232214501Srpaulo	struct eap_sake_data *data = priv;
233214501Srpaulo
234214501Srpaulo	switch (data->state) {
235214501Srpaulo	case IDENTITY:
236214501Srpaulo		return eap_sake_build_identity(sm, data, id);
237214501Srpaulo	case CHALLENGE:
238214501Srpaulo		return eap_sake_build_challenge(sm, data, id);
239214501Srpaulo	case CONFIRM:
240214501Srpaulo		return eap_sake_build_confirm(sm, data, id);
241214501Srpaulo	default:
242214501Srpaulo		wpa_printf(MSG_DEBUG, "EAP-SAKE: Unknown state %d in buildReq",
243214501Srpaulo			   data->state);
244214501Srpaulo		break;
245214501Srpaulo	}
246214501Srpaulo	return NULL;
247214501Srpaulo}
248214501Srpaulo
249214501Srpaulo
250214501Srpaulostatic Boolean eap_sake_check(struct eap_sm *sm, void *priv,
251214501Srpaulo			      struct wpabuf *respData)
252214501Srpaulo{
253214501Srpaulo	struct eap_sake_data *data = priv;
254214501Srpaulo	struct eap_sake_hdr *resp;
255214501Srpaulo	size_t len;
256214501Srpaulo	u8 version, session_id, subtype;
257214501Srpaulo	const u8 *pos;
258214501Srpaulo
259214501Srpaulo	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_SAKE, respData, &len);
260214501Srpaulo	if (pos == NULL || len < sizeof(struct eap_sake_hdr)) {
261214501Srpaulo		wpa_printf(MSG_INFO, "EAP-SAKE: Invalid frame");
262214501Srpaulo		return TRUE;
263214501Srpaulo	}
264214501Srpaulo
265214501Srpaulo	resp = (struct eap_sake_hdr *) pos;
266214501Srpaulo	version = resp->version;
267214501Srpaulo	session_id = resp->session_id;
268214501Srpaulo	subtype = resp->subtype;
269214501Srpaulo
270214501Srpaulo	if (version != EAP_SAKE_VERSION) {
271214501Srpaulo		wpa_printf(MSG_INFO, "EAP-SAKE: Unknown version %d", version);
272214501Srpaulo		return TRUE;
273214501Srpaulo	}
274214501Srpaulo
275214501Srpaulo	if (session_id != data->session_id) {
276214501Srpaulo		wpa_printf(MSG_INFO, "EAP-SAKE: Session ID mismatch (%d,%d)",
277214501Srpaulo			   session_id, data->session_id);
278214501Srpaulo		return TRUE;
279214501Srpaulo	}
280214501Srpaulo
281214501Srpaulo	wpa_printf(MSG_DEBUG, "EAP-SAKE: Received frame: subtype=%d", subtype);
282214501Srpaulo
283214501Srpaulo	if (data->state == IDENTITY && subtype == EAP_SAKE_SUBTYPE_IDENTITY)
284214501Srpaulo		return FALSE;
285214501Srpaulo
286214501Srpaulo	if (data->state == CHALLENGE && subtype == EAP_SAKE_SUBTYPE_CHALLENGE)
287214501Srpaulo		return FALSE;
288214501Srpaulo
289214501Srpaulo	if (data->state == CONFIRM && subtype == EAP_SAKE_SUBTYPE_CONFIRM)
290214501Srpaulo		return FALSE;
291214501Srpaulo
292214501Srpaulo	if (subtype == EAP_SAKE_SUBTYPE_AUTH_REJECT)
293214501Srpaulo		return FALSE;
294214501Srpaulo
295214501Srpaulo	wpa_printf(MSG_INFO, "EAP-SAKE: Unexpected subtype=%d in state=%d",
296214501Srpaulo		   subtype, data->state);
297214501Srpaulo
298214501Srpaulo	return TRUE;
299214501Srpaulo}
300214501Srpaulo
301214501Srpaulo
302214501Srpaulostatic void eap_sake_process_identity(struct eap_sm *sm,
303214501Srpaulo				      struct eap_sake_data *data,
304214501Srpaulo				      const struct wpabuf *respData,
305214501Srpaulo				      const u8 *payload, size_t payloadlen)
306214501Srpaulo{
307214501Srpaulo	if (data->state != IDENTITY)
308214501Srpaulo		return;
309214501Srpaulo
310214501Srpaulo	wpa_printf(MSG_DEBUG, "EAP-SAKE: Received Response/Identity");
311214501Srpaulo	/* TODO: update identity and select new user data */
312214501Srpaulo	eap_sake_state(data, CHALLENGE);
313214501Srpaulo}
314214501Srpaulo
315214501Srpaulo
316214501Srpaulostatic void eap_sake_process_challenge(struct eap_sm *sm,
317214501Srpaulo				       struct eap_sake_data *data,
318214501Srpaulo				       const struct wpabuf *respData,
319214501Srpaulo				       const u8 *payload, size_t payloadlen)
320214501Srpaulo{
321214501Srpaulo	struct eap_sake_parse_attr attr;
322214501Srpaulo	u8 mic_p[EAP_SAKE_MIC_LEN];
323214501Srpaulo
324214501Srpaulo	if (data->state != CHALLENGE)
325214501Srpaulo		return;
326214501Srpaulo
327214501Srpaulo	wpa_printf(MSG_DEBUG, "EAP-SAKE: Received Response/Challenge");
328214501Srpaulo
329214501Srpaulo	if (eap_sake_parse_attributes(payload, payloadlen, &attr))
330214501Srpaulo		return;
331214501Srpaulo
332214501Srpaulo	if (!attr.rand_p || !attr.mic_p) {
333214501Srpaulo		wpa_printf(MSG_INFO, "EAP-SAKE: Response/Challenge did not "
334214501Srpaulo			   "include AT_RAND_P or AT_MIC_P");
335214501Srpaulo		return;
336214501Srpaulo	}
337214501Srpaulo
338214501Srpaulo	os_memcpy(data->rand_p, attr.rand_p, EAP_SAKE_RAND_LEN);
339214501Srpaulo
340214501Srpaulo	os_free(data->peerid);
341214501Srpaulo	data->peerid = NULL;
342214501Srpaulo	data->peerid_len = 0;
343214501Srpaulo	if (attr.peerid) {
344214501Srpaulo		data->peerid = os_malloc(attr.peerid_len);
345214501Srpaulo		if (data->peerid == NULL)
346214501Srpaulo			return;
347214501Srpaulo		os_memcpy(data->peerid, attr.peerid, attr.peerid_len);
348214501Srpaulo		data->peerid_len = attr.peerid_len;
349214501Srpaulo	}
350214501Srpaulo
351214501Srpaulo	if (sm->user == NULL || sm->user->password == NULL ||
352214501Srpaulo	    sm->user->password_len != 2 * EAP_SAKE_ROOT_SECRET_LEN) {
353214501Srpaulo		wpa_printf(MSG_INFO, "EAP-SAKE: Plaintext password with "
354214501Srpaulo			   "%d-byte key not configured",
355214501Srpaulo			   2 * EAP_SAKE_ROOT_SECRET_LEN);
356214501Srpaulo		data->state = FAILURE;
357214501Srpaulo		return;
358214501Srpaulo	}
359214501Srpaulo	eap_sake_derive_keys(sm->user->password,
360214501Srpaulo			     sm->user->password + EAP_SAKE_ROOT_SECRET_LEN,
361214501Srpaulo			     data->rand_s, data->rand_p,
362214501Srpaulo			     (u8 *) &data->tek, data->msk, data->emsk);
363214501Srpaulo
364214501Srpaulo	eap_sake_compute_mic(data->tek.auth, data->rand_s, data->rand_p,
365214501Srpaulo			     data->serverid, data->serverid_len,
366214501Srpaulo			     data->peerid, data->peerid_len, 1,
367214501Srpaulo			     wpabuf_head(respData), wpabuf_len(respData),
368214501Srpaulo			     attr.mic_p, mic_p);
369214501Srpaulo	if (os_memcmp(attr.mic_p, mic_p, EAP_SAKE_MIC_LEN) != 0) {
370214501Srpaulo		wpa_printf(MSG_INFO, "EAP-SAKE: Incorrect AT_MIC_P");
371214501Srpaulo		eap_sake_state(data, FAILURE);
372214501Srpaulo		return;
373214501Srpaulo	}
374214501Srpaulo
375214501Srpaulo	eap_sake_state(data, CONFIRM);
376214501Srpaulo}
377214501Srpaulo
378214501Srpaulo
379214501Srpaulostatic void eap_sake_process_confirm(struct eap_sm *sm,
380214501Srpaulo				     struct eap_sake_data *data,
381214501Srpaulo				     const struct wpabuf *respData,
382214501Srpaulo				     const u8 *payload, size_t payloadlen)
383214501Srpaulo{
384214501Srpaulo	struct eap_sake_parse_attr attr;
385214501Srpaulo	u8 mic_p[EAP_SAKE_MIC_LEN];
386214501Srpaulo
387214501Srpaulo	if (data->state != CONFIRM)
388214501Srpaulo		return;
389214501Srpaulo
390214501Srpaulo	wpa_printf(MSG_DEBUG, "EAP-SAKE: Received Response/Confirm");
391214501Srpaulo
392214501Srpaulo	if (eap_sake_parse_attributes(payload, payloadlen, &attr))
393214501Srpaulo		return;
394214501Srpaulo
395214501Srpaulo	if (!attr.mic_p) {
396214501Srpaulo		wpa_printf(MSG_INFO, "EAP-SAKE: Response/Confirm did not "
397214501Srpaulo			   "include AT_MIC_P");
398214501Srpaulo		return;
399214501Srpaulo	}
400214501Srpaulo
401214501Srpaulo	eap_sake_compute_mic(data->tek.auth, data->rand_s, data->rand_p,
402214501Srpaulo			     data->serverid, data->serverid_len,
403214501Srpaulo			     data->peerid, data->peerid_len, 1,
404214501Srpaulo			     wpabuf_head(respData), wpabuf_len(respData),
405214501Srpaulo			     attr.mic_p, mic_p);
406214501Srpaulo	if (os_memcmp(attr.mic_p, mic_p, EAP_SAKE_MIC_LEN) != 0) {
407214501Srpaulo		wpa_printf(MSG_INFO, "EAP-SAKE: Incorrect AT_MIC_P");
408214501Srpaulo		eap_sake_state(data, FAILURE);
409214501Srpaulo	} else
410214501Srpaulo		eap_sake_state(data, SUCCESS);
411214501Srpaulo}
412214501Srpaulo
413214501Srpaulo
414214501Srpaulostatic void eap_sake_process_auth_reject(struct eap_sm *sm,
415214501Srpaulo					 struct eap_sake_data *data,
416214501Srpaulo					 const struct wpabuf *respData,
417214501Srpaulo					 const u8 *payload, size_t payloadlen)
418214501Srpaulo{
419214501Srpaulo	wpa_printf(MSG_DEBUG, "EAP-SAKE: Received Response/Auth-Reject");
420214501Srpaulo	eap_sake_state(data, FAILURE);
421214501Srpaulo}
422214501Srpaulo
423214501Srpaulo
424214501Srpaulostatic void eap_sake_process(struct eap_sm *sm, void *priv,
425214501Srpaulo			     struct wpabuf *respData)
426214501Srpaulo{
427214501Srpaulo	struct eap_sake_data *data = priv;
428214501Srpaulo	struct eap_sake_hdr *resp;
429214501Srpaulo	u8 subtype;
430214501Srpaulo	size_t len;
431214501Srpaulo	const u8 *pos, *end;
432214501Srpaulo
433214501Srpaulo	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_SAKE, respData, &len);
434214501Srpaulo	if (pos == NULL || len < sizeof(struct eap_sake_hdr))
435214501Srpaulo		return;
436214501Srpaulo
437214501Srpaulo	resp = (struct eap_sake_hdr *) pos;
438214501Srpaulo	end = pos + len;
439214501Srpaulo	subtype = resp->subtype;
440214501Srpaulo	pos = (u8 *) (resp + 1);
441214501Srpaulo
442214501Srpaulo	wpa_hexdump(MSG_DEBUG, "EAP-SAKE: Received attributes",
443214501Srpaulo		    pos, end - pos);
444214501Srpaulo
445214501Srpaulo	switch (subtype) {
446214501Srpaulo	case EAP_SAKE_SUBTYPE_IDENTITY:
447214501Srpaulo		eap_sake_process_identity(sm, data, respData, pos, end - pos);
448214501Srpaulo		break;
449214501Srpaulo	case EAP_SAKE_SUBTYPE_CHALLENGE:
450214501Srpaulo		eap_sake_process_challenge(sm, data, respData, pos, end - pos);
451214501Srpaulo		break;
452214501Srpaulo	case EAP_SAKE_SUBTYPE_CONFIRM:
453214501Srpaulo		eap_sake_process_confirm(sm, data, respData, pos, end - pos);
454214501Srpaulo		break;
455214501Srpaulo	case EAP_SAKE_SUBTYPE_AUTH_REJECT:
456214501Srpaulo		eap_sake_process_auth_reject(sm, data, respData, pos,
457214501Srpaulo					     end - pos);
458214501Srpaulo		break;
459214501Srpaulo	}
460214501Srpaulo}
461214501Srpaulo
462214501Srpaulo
463214501Srpaulostatic Boolean eap_sake_isDone(struct eap_sm *sm, void *priv)
464214501Srpaulo{
465214501Srpaulo	struct eap_sake_data *data = priv;
466214501Srpaulo	return data->state == SUCCESS || data->state == FAILURE;
467214501Srpaulo}
468214501Srpaulo
469214501Srpaulo
470214501Srpaulostatic u8 * eap_sake_getKey(struct eap_sm *sm, void *priv, size_t *len)
471214501Srpaulo{
472214501Srpaulo	struct eap_sake_data *data = priv;
473214501Srpaulo	u8 *key;
474214501Srpaulo
475214501Srpaulo	if (data->state != SUCCESS)
476214501Srpaulo		return NULL;
477214501Srpaulo
478214501Srpaulo	key = os_malloc(EAP_MSK_LEN);
479214501Srpaulo	if (key == NULL)
480214501Srpaulo		return NULL;
481214501Srpaulo	os_memcpy(key, data->msk, EAP_MSK_LEN);
482214501Srpaulo	*len = EAP_MSK_LEN;
483214501Srpaulo
484214501Srpaulo	return key;
485214501Srpaulo}
486214501Srpaulo
487214501Srpaulo
488214501Srpaulostatic u8 * eap_sake_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
489214501Srpaulo{
490214501Srpaulo	struct eap_sake_data *data = priv;
491214501Srpaulo	u8 *key;
492214501Srpaulo
493214501Srpaulo	if (data->state != SUCCESS)
494214501Srpaulo		return NULL;
495214501Srpaulo
496214501Srpaulo	key = os_malloc(EAP_EMSK_LEN);
497214501Srpaulo	if (key == NULL)
498214501Srpaulo		return NULL;
499214501Srpaulo	os_memcpy(key, data->emsk, EAP_EMSK_LEN);
500214501Srpaulo	*len = EAP_EMSK_LEN;
501214501Srpaulo
502214501Srpaulo	return key;
503214501Srpaulo}
504214501Srpaulo
505214501Srpaulo
506214501Srpaulostatic Boolean eap_sake_isSuccess(struct eap_sm *sm, void *priv)
507214501Srpaulo{
508214501Srpaulo	struct eap_sake_data *data = priv;
509214501Srpaulo	return data->state == SUCCESS;
510214501Srpaulo}
511214501Srpaulo
512214501Srpaulo
513214501Srpauloint eap_server_sake_register(void)
514214501Srpaulo{
515214501Srpaulo	struct eap_method *eap;
516214501Srpaulo	int ret;
517214501Srpaulo
518214501Srpaulo	eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
519214501Srpaulo				      EAP_VENDOR_IETF, EAP_TYPE_SAKE, "SAKE");
520214501Srpaulo	if (eap == NULL)
521214501Srpaulo		return -1;
522214501Srpaulo
523214501Srpaulo	eap->init = eap_sake_init;
524214501Srpaulo	eap->reset = eap_sake_reset;
525214501Srpaulo	eap->buildReq = eap_sake_buildReq;
526214501Srpaulo	eap->check = eap_sake_check;
527214501Srpaulo	eap->process = eap_sake_process;
528214501Srpaulo	eap->isDone = eap_sake_isDone;
529214501Srpaulo	eap->getKey = eap_sake_getKey;
530214501Srpaulo	eap->isSuccess = eap_sake_isSuccess;
531214501Srpaulo	eap->get_emsk = eap_sake_get_emsk;
532214501Srpaulo
533214501Srpaulo	ret = eap_server_method_register(eap);
534214501Srpaulo	if (ret)
535214501Srpaulo		eap_server_method_free(eap);
536214501Srpaulo	return ret;
537214501Srpaulo}
538