eap_server_psk.c revision 1f69aa52ea2e0a73ac502565df8c666ee49cab6a
1/*
2 * hostapd / EAP-PSK (RFC 4764) server
3 * Copyright (c) 2005-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 * Note: EAP-PSK is an EAP authentication method and as such, completely
15 * different from WPA-PSK. This file is not needed for WPA-PSK functionality.
16 */
17
18#include "includes.h"
19
20#include "common.h"
21#include "crypto/aes_wrap.h"
22#include "crypto/random.h"
23#include "eap_common/eap_psk_common.h"
24#include "eap_server/eap_i.h"
25
26
27struct eap_psk_data {
28	enum { PSK_1, PSK_3, SUCCESS, FAILURE } state;
29	u8 rand_s[EAP_PSK_RAND_LEN];
30	u8 rand_p[EAP_PSK_RAND_LEN];
31	u8 *id_p, *id_s;
32	size_t id_p_len, id_s_len;
33	u8 ak[EAP_PSK_AK_LEN], kdk[EAP_PSK_KDK_LEN], tek[EAP_PSK_TEK_LEN];
34	u8 msk[EAP_MSK_LEN];
35	u8 emsk[EAP_EMSK_LEN];
36};
37
38
39static void * eap_psk_init(struct eap_sm *sm)
40{
41	struct eap_psk_data *data;
42
43	data = os_zalloc(sizeof(*data));
44	if (data == NULL)
45		return NULL;
46	data->state = PSK_1;
47	data->id_s = (u8 *) "hostapd";
48	data->id_s_len = 7;
49
50	return data;
51}
52
53
54static void eap_psk_reset(struct eap_sm *sm, void *priv)
55{
56	struct eap_psk_data *data = priv;
57	os_free(data->id_p);
58	os_free(data);
59}
60
61
62static struct wpabuf * eap_psk_build_1(struct eap_sm *sm,
63				       struct eap_psk_data *data, u8 id)
64{
65	struct wpabuf *req;
66	struct eap_psk_hdr_1 *psk;
67
68	wpa_printf(MSG_DEBUG, "EAP-PSK: PSK-1 (sending)");
69
70	if (random_get_bytes(data->rand_s, EAP_PSK_RAND_LEN)) {
71		wpa_printf(MSG_ERROR, "EAP-PSK: Failed to get random data");
72		data->state = FAILURE;
73		return NULL;
74	}
75	wpa_hexdump(MSG_MSGDUMP, "EAP-PSK: RAND_S (server rand)",
76		    data->rand_s, EAP_PSK_RAND_LEN);
77
78	req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PSK,
79			    sizeof(*psk) + data->id_s_len,
80			    EAP_CODE_REQUEST, id);
81	if (req == NULL) {
82		wpa_printf(MSG_ERROR, "EAP-PSK: Failed to allocate memory "
83			   "request");
84		data->state = FAILURE;
85		return NULL;
86	}
87
88	psk = wpabuf_put(req, sizeof(*psk));
89	psk->flags = EAP_PSK_FLAGS_SET_T(0); /* T=0 */
90	os_memcpy(psk->rand_s, data->rand_s, EAP_PSK_RAND_LEN);
91	wpabuf_put_data(req, data->id_s, data->id_s_len);
92
93	return req;
94}
95
96
97static struct wpabuf * eap_psk_build_3(struct eap_sm *sm,
98				       struct eap_psk_data *data, u8 id)
99{
100	struct wpabuf *req;
101	struct eap_psk_hdr_3 *psk;
102	u8 *buf, *pchannel, nonce[16];
103	size_t buflen;
104
105	wpa_printf(MSG_DEBUG, "EAP-PSK: PSK-3 (sending)");
106
107	req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PSK,
108			    sizeof(*psk) + 4 + 16 + 1, EAP_CODE_REQUEST, id);
109	if (req == NULL) {
110		wpa_printf(MSG_ERROR, "EAP-PSK: Failed to allocate memory "
111			   "request");
112		data->state = FAILURE;
113		return NULL;
114	}
115
116	psk = wpabuf_put(req, sizeof(*psk));
117	psk->flags = EAP_PSK_FLAGS_SET_T(2); /* T=2 */
118	os_memcpy(psk->rand_s, data->rand_s, EAP_PSK_RAND_LEN);
119
120	/* MAC_S = OMAC1-AES-128(AK, ID_S||RAND_P) */
121	buflen = data->id_s_len + EAP_PSK_RAND_LEN;
122	buf = os_malloc(buflen);
123	if (buf == NULL)
124		goto fail;
125
126	os_memcpy(buf, data->id_s, data->id_s_len);
127	os_memcpy(buf + data->id_s_len, data->rand_p, EAP_PSK_RAND_LEN);
128	if (omac1_aes_128(data->ak, buf, buflen, psk->mac_s)) {
129		os_free(buf);
130		goto fail;
131	}
132	os_free(buf);
133
134	if (eap_psk_derive_keys(data->kdk, data->rand_p, data->tek, data->msk,
135				data->emsk))
136		goto fail;
137	wpa_hexdump_key(MSG_DEBUG, "EAP-PSK: TEK", data->tek, EAP_PSK_TEK_LEN);
138	wpa_hexdump_key(MSG_DEBUG, "EAP-PSK: MSK", data->msk, EAP_MSK_LEN);
139	wpa_hexdump_key(MSG_DEBUG, "EAP-PSK: EMSK", data->emsk, EAP_EMSK_LEN);
140
141	os_memset(nonce, 0, sizeof(nonce));
142	pchannel = wpabuf_put(req, 4 + 16 + 1);
143	os_memcpy(pchannel, nonce + 12, 4);
144	os_memset(pchannel + 4, 0, 16); /* Tag */
145	pchannel[4 + 16] = EAP_PSK_R_FLAG_DONE_SUCCESS << 6;
146	wpa_hexdump(MSG_DEBUG, "EAP-PSK: PCHANNEL (plaintext)",
147		    pchannel, 4 + 16 + 1);
148	if (aes_128_eax_encrypt(data->tek, nonce, sizeof(nonce),
149				wpabuf_head(req), 22,
150				pchannel + 4 + 16, 1, pchannel + 4))
151		goto fail;
152	wpa_hexdump(MSG_DEBUG, "EAP-PSK: PCHANNEL (encrypted)",
153		    pchannel, 4 + 16 + 1);
154
155	return req;
156
157fail:
158	wpabuf_free(req);
159	data->state = FAILURE;
160	return NULL;
161}
162
163
164static struct wpabuf * eap_psk_buildReq(struct eap_sm *sm, void *priv, u8 id)
165{
166	struct eap_psk_data *data = priv;
167
168	switch (data->state) {
169	case PSK_1:
170		return eap_psk_build_1(sm, data, id);
171	case PSK_3:
172		return eap_psk_build_3(sm, data, id);
173	default:
174		wpa_printf(MSG_DEBUG, "EAP-PSK: Unknown state %d in buildReq",
175			   data->state);
176		break;
177	}
178	return NULL;
179}
180
181
182static Boolean eap_psk_check(struct eap_sm *sm, void *priv,
183			     struct wpabuf *respData)
184{
185	struct eap_psk_data *data = priv;
186	size_t len;
187	u8 t;
188	const u8 *pos;
189
190	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PSK, respData, &len);
191	if (pos == NULL || len < 1) {
192		wpa_printf(MSG_INFO, "EAP-PSK: Invalid frame");
193		return TRUE;
194	}
195	t = EAP_PSK_FLAGS_GET_T(*pos);
196
197	wpa_printf(MSG_DEBUG, "EAP-PSK: received frame: T=%d", t);
198
199	if (data->state == PSK_1 && t != 1) {
200		wpa_printf(MSG_DEBUG, "EAP-PSK: Expected PSK-2 - "
201			   "ignore T=%d", t);
202		return TRUE;
203	}
204
205	if (data->state == PSK_3 && t != 3) {
206		wpa_printf(MSG_DEBUG, "EAP-PSK: Expected PSK-4 - "
207			   "ignore T=%d", t);
208		return TRUE;
209	}
210
211	if ((t == 1 && len < sizeof(struct eap_psk_hdr_2)) ||
212	    (t == 3 && len < sizeof(struct eap_psk_hdr_4))) {
213		wpa_printf(MSG_DEBUG, "EAP-PSK: Too short frame");
214		return TRUE;
215	}
216
217	return FALSE;
218}
219
220
221static void eap_psk_process_2(struct eap_sm *sm,
222			      struct eap_psk_data *data,
223			      struct wpabuf *respData)
224{
225	const struct eap_psk_hdr_2 *resp;
226	u8 *pos, mac[EAP_PSK_MAC_LEN], *buf;
227	size_t left, buflen;
228	int i;
229	const u8 *cpos;
230
231	if (data->state != PSK_1)
232		return;
233
234	wpa_printf(MSG_DEBUG, "EAP-PSK: Received PSK-2");
235
236	cpos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PSK, respData,
237				&left);
238	if (cpos == NULL || left < sizeof(*resp)) {
239		wpa_printf(MSG_INFO, "EAP-PSK: Invalid frame");
240		return;
241	}
242	resp = (const struct eap_psk_hdr_2 *) cpos;
243	cpos = (const u8 *) (resp + 1);
244	left -= sizeof(*resp);
245
246	os_free(data->id_p);
247	data->id_p = os_malloc(left);
248	if (data->id_p == NULL) {
249		wpa_printf(MSG_INFO, "EAP-PSK: Failed to allocate memory for "
250			   "ID_P");
251		return;
252	}
253	os_memcpy(data->id_p, cpos, left);
254	data->id_p_len = left;
255	wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-PSK: ID_P",
256			  data->id_p, data->id_p_len);
257
258	if (eap_user_get(sm, data->id_p, data->id_p_len, 0) < 0) {
259		wpa_hexdump_ascii(MSG_DEBUG, "EAP-PSK: unknown ID_P",
260				  data->id_p, data->id_p_len);
261		data->state = FAILURE;
262		return;
263	}
264
265	for (i = 0;
266	     i < EAP_MAX_METHODS &&
267		     (sm->user->methods[i].vendor != EAP_VENDOR_IETF ||
268		      sm->user->methods[i].method != EAP_TYPE_NONE);
269	     i++) {
270		if (sm->user->methods[i].vendor == EAP_VENDOR_IETF &&
271		    sm->user->methods[i].method == EAP_TYPE_PSK)
272			break;
273	}
274
275	if (i >= EAP_MAX_METHODS ||
276	    sm->user->methods[i].vendor != EAP_VENDOR_IETF ||
277	    sm->user->methods[i].method != EAP_TYPE_PSK) {
278		wpa_hexdump_ascii(MSG_DEBUG,
279				  "EAP-PSK: EAP-PSK not enabled for ID_P",
280				  data->id_p, data->id_p_len);
281		data->state = FAILURE;
282		return;
283	}
284
285	if (sm->user->password == NULL ||
286	    sm->user->password_len != EAP_PSK_PSK_LEN) {
287		wpa_hexdump_ascii(MSG_DEBUG, "EAP-PSK: invalid password in "
288				  "user database for ID_P",
289				  data->id_p, data->id_p_len);
290		data->state = FAILURE;
291		return;
292	}
293	if (eap_psk_key_setup(sm->user->password, data->ak, data->kdk)) {
294		data->state = FAILURE;
295		return;
296	}
297	wpa_hexdump_key(MSG_DEBUG, "EAP-PSK: AK", data->ak, EAP_PSK_AK_LEN);
298	wpa_hexdump_key(MSG_DEBUG, "EAP-PSK: KDK", data->kdk, EAP_PSK_KDK_LEN);
299
300	wpa_hexdump(MSG_MSGDUMP, "EAP-PSK: RAND_P (client rand)",
301		    resp->rand_p, EAP_PSK_RAND_LEN);
302	os_memcpy(data->rand_p, resp->rand_p, EAP_PSK_RAND_LEN);
303
304	/* MAC_P = OMAC1-AES-128(AK, ID_P||ID_S||RAND_S||RAND_P) */
305	buflen = data->id_p_len + data->id_s_len + 2 * EAP_PSK_RAND_LEN;
306	buf = os_malloc(buflen);
307	if (buf == NULL) {
308		data->state = FAILURE;
309		return;
310	}
311	os_memcpy(buf, data->id_p, data->id_p_len);
312	pos = buf + data->id_p_len;
313	os_memcpy(pos, data->id_s, data->id_s_len);
314	pos += data->id_s_len;
315	os_memcpy(pos, data->rand_s, EAP_PSK_RAND_LEN);
316	pos += EAP_PSK_RAND_LEN;
317	os_memcpy(pos, data->rand_p, EAP_PSK_RAND_LEN);
318	if (omac1_aes_128(data->ak, buf, buflen, mac)) {
319		os_free(buf);
320		data->state = FAILURE;
321		return;
322	}
323	os_free(buf);
324	wpa_hexdump(MSG_DEBUG, "EAP-PSK: MAC_P", resp->mac_p, EAP_PSK_MAC_LEN);
325	if (os_memcmp(mac, resp->mac_p, EAP_PSK_MAC_LEN) != 0) {
326		wpa_printf(MSG_INFO, "EAP-PSK: Invalid MAC_P");
327		wpa_hexdump(MSG_MSGDUMP, "EAP-PSK: Expected MAC_P",
328			    mac, EAP_PSK_MAC_LEN);
329		data->state = FAILURE;
330		return;
331	}
332
333	data->state = PSK_3;
334}
335
336
337static void eap_psk_process_4(struct eap_sm *sm,
338			      struct eap_psk_data *data,
339			      struct wpabuf *respData)
340{
341	const struct eap_psk_hdr_4 *resp;
342	u8 *decrypted, nonce[16];
343	size_t left;
344	const u8 *pos, *tag;
345
346	if (data->state != PSK_3)
347		return;
348
349	wpa_printf(MSG_DEBUG, "EAP-PSK: Received PSK-4");
350
351	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PSK, respData, &left);
352	if (pos == NULL || left < sizeof(*resp)) {
353		wpa_printf(MSG_INFO, "EAP-PSK: Invalid frame");
354		return;
355	}
356	resp = (const struct eap_psk_hdr_4 *) pos;
357	pos = (const u8 *) (resp + 1);
358	left -= sizeof(*resp);
359
360	wpa_hexdump(MSG_MSGDUMP, "EAP-PSK: Encrypted PCHANNEL", pos, left);
361
362	if (left < 4 + 16 + 1) {
363		wpa_printf(MSG_INFO, "EAP-PSK: Too short PCHANNEL data in "
364			   "PSK-4 (len=%lu, expected 21)",
365			   (unsigned long) left);
366		return;
367	}
368
369	if (pos[0] == 0 && pos[1] == 0 && pos[2] == 0 && pos[3] == 0) {
370		wpa_printf(MSG_DEBUG, "EAP-PSK: Nonce did not increase");
371		return;
372	}
373
374	os_memset(nonce, 0, 12);
375	os_memcpy(nonce + 12, pos, 4);
376	pos += 4;
377	left -= 4;
378	tag = pos;
379	pos += 16;
380	left -= 16;
381
382	decrypted = os_malloc(left);
383	if (decrypted == NULL)
384		return;
385	os_memcpy(decrypted, pos, left);
386
387	if (aes_128_eax_decrypt(data->tek, nonce, sizeof(nonce),
388				wpabuf_head(respData), 22, decrypted, left,
389				tag)) {
390		wpa_printf(MSG_WARNING, "EAP-PSK: PCHANNEL decryption failed");
391		os_free(decrypted);
392		data->state = FAILURE;
393		return;
394	}
395	wpa_hexdump(MSG_DEBUG, "EAP-PSK: Decrypted PCHANNEL message",
396		    decrypted, left);
397
398	/* Verify R flag */
399	switch (decrypted[0] >> 6) {
400	case EAP_PSK_R_FLAG_CONT:
401		wpa_printf(MSG_DEBUG, "EAP-PSK: R flag - CONT - unsupported");
402		data->state = FAILURE;
403		break;
404	case EAP_PSK_R_FLAG_DONE_SUCCESS:
405		wpa_printf(MSG_DEBUG, "EAP-PSK: R flag - DONE_SUCCESS");
406		data->state = SUCCESS;
407		break;
408	case EAP_PSK_R_FLAG_DONE_FAILURE:
409		wpa_printf(MSG_DEBUG, "EAP-PSK: R flag - DONE_FAILURE");
410		data->state = FAILURE;
411		break;
412	}
413	os_free(decrypted);
414}
415
416
417static void eap_psk_process(struct eap_sm *sm, void *priv,
418			    struct wpabuf *respData)
419{
420	struct eap_psk_data *data = priv;
421	const u8 *pos;
422	size_t len;
423
424	if (sm->user == NULL || sm->user->password == NULL) {
425		wpa_printf(MSG_INFO, "EAP-PSK: Plaintext password not "
426			   "configured");
427		data->state = FAILURE;
428		return;
429	}
430
431	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PSK, respData, &len);
432	if (pos == NULL || len < 1)
433		return;
434
435	switch (EAP_PSK_FLAGS_GET_T(*pos)) {
436	case 1:
437		eap_psk_process_2(sm, data, respData);
438		break;
439	case 3:
440		eap_psk_process_4(sm, data, respData);
441		break;
442	}
443}
444
445
446static Boolean eap_psk_isDone(struct eap_sm *sm, void *priv)
447{
448	struct eap_psk_data *data = priv;
449	return data->state == SUCCESS || data->state == FAILURE;
450}
451
452
453static u8 * eap_psk_getKey(struct eap_sm *sm, void *priv, size_t *len)
454{
455	struct eap_psk_data *data = priv;
456	u8 *key;
457
458	if (data->state != SUCCESS)
459		return NULL;
460
461	key = os_malloc(EAP_MSK_LEN);
462	if (key == NULL)
463		return NULL;
464	os_memcpy(key, data->msk, EAP_MSK_LEN);
465	*len = EAP_MSK_LEN;
466
467	return key;
468}
469
470
471static u8 * eap_psk_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
472{
473	struct eap_psk_data *data = priv;
474	u8 *key;
475
476	if (data->state != SUCCESS)
477		return NULL;
478
479	key = os_malloc(EAP_EMSK_LEN);
480	if (key == NULL)
481		return NULL;
482	os_memcpy(key, data->emsk, EAP_EMSK_LEN);
483	*len = EAP_EMSK_LEN;
484
485	return key;
486}
487
488
489static Boolean eap_psk_isSuccess(struct eap_sm *sm, void *priv)
490{
491	struct eap_psk_data *data = priv;
492	return data->state == SUCCESS;
493}
494
495
496int eap_server_psk_register(void)
497{
498	struct eap_method *eap;
499	int ret;
500
501	eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
502				      EAP_VENDOR_IETF, EAP_TYPE_PSK, "PSK");
503	if (eap == NULL)
504		return -1;
505
506	eap->init = eap_psk_init;
507	eap->reset = eap_psk_reset;
508	eap->buildReq = eap_psk_buildReq;
509	eap->check = eap_psk_check;
510	eap->process = eap_psk_process;
511	eap->isDone = eap_psk_isDone;
512	eap->getKey = eap_psk_getKey;
513	eap->isSuccess = eap_psk_isSuccess;
514	eap->get_emsk = eap_psk_get_emsk;
515
516	ret = eap_server_method_register(eap);
517	if (ret)
518		eap_server_method_free(eap);
519	return ret;
520}
521