1 /*
2  * hostapd / EAP-SAKE (RFC 4763) server
3  * Copyright (c) 2006-2007, Jouni Malinen <j@w1.fi>
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License version 2 as
7  * published by the Free Software Foundation.
8  *
9  * Alternatively, this software may be distributed under the terms of BSD
10  * license.
11  *
12  * See README and COPYING for more details.
13  */
14 
15 #include "includes.h"
16 
17 #include "common.h"
18 #include "eap_server/eap_i.h"
19 #include "eap_common/eap_sake_common.h"
20 
21 
22 struct eap_sake_data {
23 	enum { IDENTITY, CHALLENGE, CONFIRM, SUCCESS, FAILURE } state;
24 	u8 rand_s[EAP_SAKE_RAND_LEN];
25 	u8 rand_p[EAP_SAKE_RAND_LEN];
26 	struct {
27 		u8 auth[EAP_SAKE_TEK_AUTH_LEN];
28 		u8 cipher[EAP_SAKE_TEK_CIPHER_LEN];
29 	} tek;
30 	u8 msk[EAP_MSK_LEN];
31 	u8 emsk[EAP_EMSK_LEN];
32 	u8 session_id;
33 	u8 *peerid;
34 	size_t peerid_len;
35 	u8 *serverid;
36 	size_t serverid_len;
37 };
38 
39 
40 static const char * eap_sake_state_txt(int state)
41 {
42 	switch (state) {
43 	case IDENTITY:
44 		return "IDENTITY";
45 	case CHALLENGE:
46 		return "CHALLENGE";
47 	case CONFIRM:
48 		return "CONFIRM";
49 	case SUCCESS:
50 		return "SUCCESS";
51 	case FAILURE:
52 		return "FAILURE";
53 	default:
54 		return "?";
55 	}
56 }
57 
58 
59 static void eap_sake_state(struct eap_sake_data *data, int state)
60 {
61 	wpa_printf(MSG_DEBUG, "EAP-SAKE: %s -> %s",
62 		   eap_sake_state_txt(data->state),
63 		   eap_sake_state_txt(state));
64 	data->state = state;
65 }
66 
67 
68 static void * eap_sake_init(struct eap_sm *sm)
69 {
70 	struct eap_sake_data *data;
71 
72 	data = os_zalloc(sizeof(*data));
73 	if (data == NULL)
74 		return NULL;
75 	data->state = CHALLENGE;
76 
77 	if (os_get_random(&data->session_id, 1)) {
78 		wpa_printf(MSG_ERROR, "EAP-SAKE: Failed to get random data");
79 		os_free(data);
80 		return NULL;
81 	}
82 	wpa_printf(MSG_DEBUG, "EAP-SAKE: Initialized Session ID %d",
83 		   data->session_id);
84 
85 	/* TODO: add support for configuring SERVERID */
86 	data->serverid = (u8 *) os_strdup("hostapd");
87 	if (data->serverid)
88 		data->serverid_len = os_strlen((char *) data->serverid);
89 
90 	return data;
91 }
92 
93 
94 static void eap_sake_reset(struct eap_sm *sm, void *priv)
95 {
96 	struct eap_sake_data *data = priv;
97 	os_free(data->serverid);
98 	os_free(data->peerid);
99 	os_free(data);
100 }
101 
102 
103 static struct wpabuf * eap_sake_build_msg(struct eap_sake_data *data,
104 					  u8 id, size_t length, u8 subtype)
105 {
106 	struct eap_sake_hdr *sake;
107 	struct wpabuf *msg;
108 	size_t plen;
109 
110 	plen = sizeof(struct eap_sake_hdr) + length;
111 
112 	msg = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_SAKE, plen,
113 			    EAP_CODE_REQUEST, id);
114 	if (msg == NULL) {
115 		wpa_printf(MSG_ERROR, "EAP-SAKE: Failed to allocate memory "
116 			   "request");
117 		return NULL;
118 	}
119 
120 	sake = wpabuf_put(msg, sizeof(*sake));
121 	sake->version = EAP_SAKE_VERSION;
122 	sake->session_id = data->session_id;
123 	sake->subtype = subtype;
124 
125 	return msg;
126 }
127 
128 
129 static struct wpabuf * eap_sake_build_identity(struct eap_sm *sm,
130 					       struct eap_sake_data *data,
131 					       u8 id)
132 {
133 	struct wpabuf *msg;
134 	size_t plen;
135 
136 	wpa_printf(MSG_DEBUG, "EAP-SAKE: Request/Identity");
137 
138 	plen = 4;
139 	if (data->serverid)
140 		plen += 2 + data->serverid_len;
141 	msg = eap_sake_build_msg(data, id, plen, EAP_SAKE_SUBTYPE_IDENTITY);
142 	if (msg == NULL) {
143 		data->state = FAILURE;
144 		return NULL;
145 	}
146 
147 	wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_PERM_ID_REQ");
148 	eap_sake_add_attr(msg, EAP_SAKE_AT_PERM_ID_REQ, NULL, 2);
149 
150 	if (data->serverid) {
151 		wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_SERVERID");
152 		eap_sake_add_attr(msg, EAP_SAKE_AT_SERVERID,
153 				  data->serverid, data->serverid_len);
154 	}
155 
156 	return msg;
157 }
158 
159 
160 static struct wpabuf * eap_sake_build_challenge(struct eap_sm *sm,
161 						struct eap_sake_data *data,
162 						u8 id)
163 {
164 	struct wpabuf *msg;
165 	size_t plen;
166 
167 	wpa_printf(MSG_DEBUG, "EAP-SAKE: Request/Challenge");
168 
169 	if (os_get_random(data->rand_s, EAP_SAKE_RAND_LEN)) {
170 		wpa_printf(MSG_ERROR, "EAP-SAKE: Failed to get random data");
171 		data->state = FAILURE;
172 		return NULL;
173 	}
174 	wpa_hexdump(MSG_MSGDUMP, "EAP-SAKE: RAND_S (server rand)",
175 		    data->rand_s, EAP_SAKE_RAND_LEN);
176 
177 	plen = 2 + EAP_SAKE_RAND_LEN;
178 	if (data->serverid)
179 		plen += 2 + data->serverid_len;
180 	msg = eap_sake_build_msg(data, id, plen, EAP_SAKE_SUBTYPE_CHALLENGE);
181 	if (msg == NULL) {
182 		data->state = FAILURE;
183 		return NULL;
184 	}
185 
186 	wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_RAND_S");
187 	eap_sake_add_attr(msg, EAP_SAKE_AT_RAND_S,
188 			  data->rand_s, EAP_SAKE_RAND_LEN);
189 
190 	if (data->serverid) {
191 		wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_SERVERID");
192 		eap_sake_add_attr(msg, EAP_SAKE_AT_SERVERID,
193 				  data->serverid, data->serverid_len);
194 	}
195 
196 	return msg;
197 }
198 
199 
200 static struct wpabuf * eap_sake_build_confirm(struct eap_sm *sm,
201 					      struct eap_sake_data *data,
202 					      u8 id)
203 {
204 	struct wpabuf *msg;
205 	u8 *mic;
206 
207 	wpa_printf(MSG_DEBUG, "EAP-SAKE: Request/Confirm");
208 
209 	msg = eap_sake_build_msg(data, id, 2 + EAP_SAKE_MIC_LEN,
210 				 EAP_SAKE_SUBTYPE_CONFIRM);
211 	if (msg == NULL) {
212 		data->state = FAILURE;
213 		return NULL;
214 	}
215 
216 	wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_MIC_S");
217 	wpabuf_put_u8(msg, EAP_SAKE_AT_MIC_S);
218 	wpabuf_put_u8(msg, 2 + EAP_SAKE_MIC_LEN);
219 	mic = wpabuf_put(msg, EAP_SAKE_MIC_LEN);
220 	if (eap_sake_compute_mic(data->tek.auth, data->rand_s, data->rand_p,
221 				 data->serverid, data->serverid_len,
222 				 data->peerid, data->peerid_len, 0,
223 				 wpabuf_head(msg), wpabuf_len(msg), mic, mic))
224 	{
225 		wpa_printf(MSG_INFO, "EAP-SAKE: Failed to compute MIC");
226 		data->state = FAILURE;
227 		os_free(msg);
228 		return NULL;
229 	}
230 
231 	return msg;
232 }
233 
234 
235 static struct wpabuf * eap_sake_buildReq(struct eap_sm *sm, void *priv, u8 id)
236 {
237 	struct eap_sake_data *data = priv;
238 
239 	switch (data->state) {
240 	case IDENTITY:
241 		return eap_sake_build_identity(sm, data, id);
242 	case CHALLENGE:
243 		return eap_sake_build_challenge(sm, data, id);
244 	case CONFIRM:
245 		return eap_sake_build_confirm(sm, data, id);
246 	default:
247 		wpa_printf(MSG_DEBUG, "EAP-SAKE: Unknown state %d in buildReq",
248 			   data->state);
249 		break;
250 	}
251 	return NULL;
252 }
253 
254 
255 static Boolean eap_sake_check(struct eap_sm *sm, void *priv,
256 			      struct wpabuf *respData)
257 {
258 	struct eap_sake_data *data = priv;
259 	struct eap_sake_hdr *resp;
260 	size_t len;
261 	u8 version, session_id, subtype;
262 	const u8 *pos;
263 
264 	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_SAKE, respData, &len);
265 	if (pos == NULL || len < sizeof(struct eap_sake_hdr)) {
266 		wpa_printf(MSG_INFO, "EAP-SAKE: Invalid frame");
267 		return TRUE;
268 	}
269 
270 	resp = (struct eap_sake_hdr *) pos;
271 	version = resp->version;
272 	session_id = resp->session_id;
273 	subtype = resp->subtype;
274 
275 	if (version != EAP_SAKE_VERSION) {
276 		wpa_printf(MSG_INFO, "EAP-SAKE: Unknown version %d", version);
277 		return TRUE;
278 	}
279 
280 	if (session_id != data->session_id) {
281 		wpa_printf(MSG_INFO, "EAP-SAKE: Session ID mismatch (%d,%d)",
282 			   session_id, data->session_id);
283 		return TRUE;
284 	}
285 
286 	wpa_printf(MSG_DEBUG, "EAP-SAKE: Received frame: subtype=%d", subtype);
287 
288 	if (data->state == IDENTITY && subtype == EAP_SAKE_SUBTYPE_IDENTITY)
289 		return FALSE;
290 
291 	if (data->state == CHALLENGE && subtype == EAP_SAKE_SUBTYPE_CHALLENGE)
292 		return FALSE;
293 
294 	if (data->state == CONFIRM && subtype == EAP_SAKE_SUBTYPE_CONFIRM)
295 		return FALSE;
296 
297 	if (subtype == EAP_SAKE_SUBTYPE_AUTH_REJECT)
298 		return FALSE;
299 
300 	wpa_printf(MSG_INFO, "EAP-SAKE: Unexpected subtype=%d in state=%d",
301 		   subtype, data->state);
302 
303 	return TRUE;
304 }
305 
306 
307 static void eap_sake_process_identity(struct eap_sm *sm,
308 				      struct eap_sake_data *data,
309 				      const struct wpabuf *respData,
310 				      const u8 *payload, size_t payloadlen)
311 {
312 	if (data->state != IDENTITY)
313 		return;
314 
315 	wpa_printf(MSG_DEBUG, "EAP-SAKE: Received Response/Identity");
316 	/* TODO: update identity and select new user data */
317 	eap_sake_state(data, CHALLENGE);
318 }
319 
320 
321 static void eap_sake_process_challenge(struct eap_sm *sm,
322 				       struct eap_sake_data *data,
323 				       const struct wpabuf *respData,
324 				       const u8 *payload, size_t payloadlen)
325 {
326 	struct eap_sake_parse_attr attr;
327 	u8 mic_p[EAP_SAKE_MIC_LEN];
328 
329 	if (data->state != CHALLENGE)
330 		return;
331 
332 	wpa_printf(MSG_DEBUG, "EAP-SAKE: Received Response/Challenge");
333 
334 	if (eap_sake_parse_attributes(payload, payloadlen, &attr))
335 		return;
336 
337 	if (!attr.rand_p || !attr.mic_p) {
338 		wpa_printf(MSG_INFO, "EAP-SAKE: Response/Challenge did not "
339 			   "include AT_RAND_P or AT_MIC_P");
340 		return;
341 	}
342 
343 	os_memcpy(data->rand_p, attr.rand_p, EAP_SAKE_RAND_LEN);
344 
345 	os_free(data->peerid);
346 	data->peerid = NULL;
347 	data->peerid_len = 0;
348 	if (attr.peerid) {
349 		data->peerid = os_malloc(attr.peerid_len);
350 		if (data->peerid == NULL)
351 			return;
352 		os_memcpy(data->peerid, attr.peerid, attr.peerid_len);
353 		data->peerid_len = attr.peerid_len;
354 	}
355 
356 	if (sm->user == NULL || sm->user->password == NULL ||
357 	    sm->user->password_len != 2 * EAP_SAKE_ROOT_SECRET_LEN) {
358 		wpa_printf(MSG_INFO, "EAP-SAKE: Plaintext password with "
359 			   "%d-byte key not configured",
360 			   2 * EAP_SAKE_ROOT_SECRET_LEN);
361 		data->state = FAILURE;
362 		return;
363 	}
364 	eap_sake_derive_keys(sm->user->password,
365 			     sm->user->password + EAP_SAKE_ROOT_SECRET_LEN,
366 			     data->rand_s, data->rand_p,
367 			     (u8 *) &data->tek, data->msk, data->emsk);
368 
369 	eap_sake_compute_mic(data->tek.auth, data->rand_s, data->rand_p,
370 			     data->serverid, data->serverid_len,
371 			     data->peerid, data->peerid_len, 1,
372 			     wpabuf_head(respData), wpabuf_len(respData),
373 			     attr.mic_p, mic_p);
374 	if (os_memcmp(attr.mic_p, mic_p, EAP_SAKE_MIC_LEN) != 0) {
375 		wpa_printf(MSG_INFO, "EAP-SAKE: Incorrect AT_MIC_P");
376 		eap_sake_state(data, FAILURE);
377 		return;
378 	}
379 
380 	eap_sake_state(data, CONFIRM);
381 }
382 
383 
384 static void eap_sake_process_confirm(struct eap_sm *sm,
385 				     struct eap_sake_data *data,
386 				     const struct wpabuf *respData,
387 				     const u8 *payload, size_t payloadlen)
388 {
389 	struct eap_sake_parse_attr attr;
390 	u8 mic_p[EAP_SAKE_MIC_LEN];
391 
392 	if (data->state != CONFIRM)
393 		return;
394 
395 	wpa_printf(MSG_DEBUG, "EAP-SAKE: Received Response/Confirm");
396 
397 	if (eap_sake_parse_attributes(payload, payloadlen, &attr))
398 		return;
399 
400 	if (!attr.mic_p) {
401 		wpa_printf(MSG_INFO, "EAP-SAKE: Response/Confirm did not "
402 			   "include AT_MIC_P");
403 		return;
404 	}
405 
406 	eap_sake_compute_mic(data->tek.auth, data->rand_s, data->rand_p,
407 			     data->serverid, data->serverid_len,
408 			     data->peerid, data->peerid_len, 1,
409 			     wpabuf_head(respData), wpabuf_len(respData),
410 			     attr.mic_p, mic_p);
411 	if (os_memcmp(attr.mic_p, mic_p, EAP_SAKE_MIC_LEN) != 0) {
412 		wpa_printf(MSG_INFO, "EAP-SAKE: Incorrect AT_MIC_P");
413 		eap_sake_state(data, FAILURE);
414 	} else
415 		eap_sake_state(data, SUCCESS);
416 }
417 
418 
419 static void eap_sake_process_auth_reject(struct eap_sm *sm,
420 					 struct eap_sake_data *data,
421 					 const struct wpabuf *respData,
422 					 const u8 *payload, size_t payloadlen)
423 {
424 	wpa_printf(MSG_DEBUG, "EAP-SAKE: Received Response/Auth-Reject");
425 	eap_sake_state(data, FAILURE);
426 }
427 
428 
429 static void eap_sake_process(struct eap_sm *sm, void *priv,
430 			     struct wpabuf *respData)
431 {
432 	struct eap_sake_data *data = priv;
433 	struct eap_sake_hdr *resp;
434 	u8 subtype;
435 	size_t len;
436 	const u8 *pos, *end;
437 
438 	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_SAKE, respData, &len);
439 	if (pos == NULL || len < sizeof(struct eap_sake_hdr))
440 		return;
441 
442 	resp = (struct eap_sake_hdr *) pos;
443 	end = pos + len;
444 	subtype = resp->subtype;
445 	pos = (u8 *) (resp + 1);
446 
447 	wpa_hexdump(MSG_DEBUG, "EAP-SAKE: Received attributes",
448 		    pos, end - pos);
449 
450 	switch (subtype) {
451 	case EAP_SAKE_SUBTYPE_IDENTITY:
452 		eap_sake_process_identity(sm, data, respData, pos, end - pos);
453 		break;
454 	case EAP_SAKE_SUBTYPE_CHALLENGE:
455 		eap_sake_process_challenge(sm, data, respData, pos, end - pos);
456 		break;
457 	case EAP_SAKE_SUBTYPE_CONFIRM:
458 		eap_sake_process_confirm(sm, data, respData, pos, end - pos);
459 		break;
460 	case EAP_SAKE_SUBTYPE_AUTH_REJECT:
461 		eap_sake_process_auth_reject(sm, data, respData, pos,
462 					     end - pos);
463 		break;
464 	}
465 }
466 
467 
468 static Boolean eap_sake_isDone(struct eap_sm *sm, void *priv)
469 {
470 	struct eap_sake_data *data = priv;
471 	return data->state == SUCCESS || data->state == FAILURE;
472 }
473 
474 
475 static u8 * eap_sake_getKey(struct eap_sm *sm, void *priv, size_t *len)
476 {
477 	struct eap_sake_data *data = priv;
478 	u8 *key;
479 
480 	if (data->state != SUCCESS)
481 		return NULL;
482 
483 	key = os_malloc(EAP_MSK_LEN);
484 	if (key == NULL)
485 		return NULL;
486 	os_memcpy(key, data->msk, EAP_MSK_LEN);
487 	*len = EAP_MSK_LEN;
488 
489 	return key;
490 }
491 
492 
493 static u8 * eap_sake_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
494 {
495 	struct eap_sake_data *data = priv;
496 	u8 *key;
497 
498 	if (data->state != SUCCESS)
499 		return NULL;
500 
501 	key = os_malloc(EAP_EMSK_LEN);
502 	if (key == NULL)
503 		return NULL;
504 	os_memcpy(key, data->emsk, EAP_EMSK_LEN);
505 	*len = EAP_EMSK_LEN;
506 
507 	return key;
508 }
509 
510 
511 static Boolean eap_sake_isSuccess(struct eap_sm *sm, void *priv)
512 {
513 	struct eap_sake_data *data = priv;
514 	return data->state == SUCCESS;
515 }
516 
517 
518 int eap_server_sake_register(void)
519 {
520 	struct eap_method *eap;
521 	int ret;
522 
523 	eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
524 				      EAP_VENDOR_IETF, EAP_TYPE_SAKE, "SAKE");
525 	if (eap == NULL)
526 		return -1;
527 
528 	eap->init = eap_sake_init;
529 	eap->reset = eap_sake_reset;
530 	eap->buildReq = eap_sake_buildReq;
531 	eap->check = eap_sake_check;
532 	eap->process = eap_sake_process;
533 	eap->isDone = eap_sake_isDone;
534 	eap->getKey = eap_sake_getKey;
535 	eap->isSuccess = eap_sake_isSuccess;
536 	eap->get_emsk = eap_sake_get_emsk;
537 
538 	ret = eap_server_method_register(eap);
539 	if (ret)
540 		eap_server_method_free(eap);
541 	return ret;
542 }
543