eap_pwd.c revision 351611
1/*
2 * EAP peer method: EAP-pwd (RFC 5931)
3 * Copyright (c) 2010, Dan Harkins <dharkins@lounge.org>
4 *
5 * This software may be distributed under the terms of the BSD license.
6 * See README for more details.
7 */
8
9#include "includes.h"
10
11#include "common.h"
12#include "crypto/sha1.h"
13#include "crypto/sha256.h"
14#include "crypto/sha512.h"
15#include "crypto/ms_funcs.h"
16#include "crypto/crypto.h"
17#include "eap_peer/eap_i.h"
18#include "eap_common/eap_pwd_common.h"
19
20
21struct eap_pwd_data {
22	enum {
23		PWD_ID_Req, PWD_Commit_Req, PWD_Confirm_Req,
24		SUCCESS_ON_FRAG_COMPLETION, SUCCESS, FAILURE
25	} state;
26	u8 *id_peer;
27	size_t id_peer_len;
28	u8 *id_server;
29	size_t id_server_len;
30	u8 *password;
31	size_t password_len;
32	int password_hash;
33	struct wpa_freq_range_list allowed_groups;
34	u16 group_num;
35	u8 prep;
36	u8 token[4];
37	EAP_PWD_group *grp;
38
39	struct wpabuf *inbuf;
40	size_t in_frag_pos;
41	struct wpabuf *outbuf;
42	size_t out_frag_pos;
43	size_t mtu;
44
45	struct crypto_bignum *k;
46	struct crypto_bignum *private_value;
47	struct crypto_bignum *server_scalar;
48	struct crypto_bignum *my_scalar;
49	struct crypto_ec_point *my_element;
50	struct crypto_ec_point *server_element;
51
52	u8 msk[EAP_MSK_LEN];
53	u8 emsk[EAP_EMSK_LEN];
54	u8 session_id[1 + SHA256_MAC_LEN];
55};
56
57
58static void eap_pwd_deinit(struct eap_sm *sm, void *priv);
59
60
61#ifndef CONFIG_NO_STDOUT_DEBUG
62static const char * eap_pwd_state_txt(int state)
63{
64	switch (state) {
65        case PWD_ID_Req:
66		return "PWD-ID-Req";
67        case PWD_Commit_Req:
68		return "PWD-Commit-Req";
69        case PWD_Confirm_Req:
70		return "PWD-Confirm-Req";
71	case SUCCESS_ON_FRAG_COMPLETION:
72		return "SUCCESS_ON_FRAG_COMPLETION";
73        case SUCCESS:
74		return "SUCCESS";
75        case FAILURE:
76		return "FAILURE";
77        default:
78		return "PWD-UNK";
79	}
80}
81#endif  /* CONFIG_NO_STDOUT_DEBUG */
82
83
84static void eap_pwd_state(struct eap_pwd_data *data, int state)
85{
86	wpa_printf(MSG_DEBUG, "EAP-PWD: %s -> %s",
87		   eap_pwd_state_txt(data->state), eap_pwd_state_txt(state));
88	data->state = state;
89}
90
91
92static void * eap_pwd_init(struct eap_sm *sm)
93{
94	struct eap_pwd_data *data;
95	const u8 *identity, *password;
96	size_t identity_len, password_len;
97	int fragment_size;
98	int pwhash;
99	const char *phase1;
100
101	password = eap_get_config_password2(sm, &password_len, &pwhash);
102	if (password == NULL) {
103		wpa_printf(MSG_INFO, "EAP-PWD: No password configured!");
104		return NULL;
105	}
106
107	identity = eap_get_config_identity(sm, &identity_len);
108	if (identity == NULL) {
109		wpa_printf(MSG_INFO, "EAP-PWD: No identity configured!");
110		return NULL;
111	}
112
113	if ((data = os_zalloc(sizeof(*data))) == NULL) {
114		wpa_printf(MSG_INFO, "EAP-PWD: memory allocation data fail");
115		return NULL;
116	}
117
118	if ((data->id_peer = os_malloc(identity_len)) == NULL) {
119		wpa_printf(MSG_INFO, "EAP-PWD: memory allocation id fail");
120		os_free(data);
121		return NULL;
122	}
123
124	os_memcpy(data->id_peer, identity, identity_len);
125	data->id_peer_len = identity_len;
126
127	if ((data->password = os_malloc(password_len)) == NULL) {
128		wpa_printf(MSG_INFO, "EAP-PWD: memory allocation psk fail");
129		bin_clear_free(data->id_peer, data->id_peer_len);
130		os_free(data);
131		return NULL;
132	}
133	os_memcpy(data->password, password, password_len);
134	data->password_len = password_len;
135	data->password_hash = pwhash;
136
137	phase1 = eap_get_config_phase1(sm);
138	if (phase1) {
139		const char *pos, *end;
140		char *copy = NULL;
141		int res;
142
143		pos = os_strstr(phase1, "eap_pwd_groups=");
144		if (pos) {
145			pos += 15;
146			end = os_strchr(pos, ' ');
147			if (end) {
148				copy = os_zalloc(end - pos + 1);
149				if (!copy)
150					goto fail;
151				os_memcpy(copy, pos, end - pos);
152				pos = copy;
153			}
154			res = freq_range_list_parse(&data->allowed_groups, pos);
155			os_free(copy);
156			if (res)
157				goto fail;
158		}
159	}
160
161	data->out_frag_pos = data->in_frag_pos = 0;
162	data->inbuf = data->outbuf = NULL;
163	fragment_size = eap_get_config_fragment_size(sm);
164	if (fragment_size <= 0)
165		data->mtu = 1020; /* default from RFC 5931 */
166	else
167		data->mtu = fragment_size;
168
169	data->state = PWD_ID_Req;
170
171	return data;
172fail:
173	eap_pwd_deinit(sm, data);
174	return NULL;
175}
176
177
178static void eap_pwd_deinit(struct eap_sm *sm, void *priv)
179{
180	struct eap_pwd_data *data = priv;
181
182	crypto_bignum_deinit(data->private_value, 1);
183	crypto_bignum_deinit(data->server_scalar, 1);
184	crypto_bignum_deinit(data->my_scalar, 1);
185	crypto_bignum_deinit(data->k, 1);
186	crypto_ec_point_deinit(data->my_element, 1);
187	crypto_ec_point_deinit(data->server_element, 1);
188	bin_clear_free(data->id_peer, data->id_peer_len);
189	bin_clear_free(data->id_server, data->id_server_len);
190	bin_clear_free(data->password, data->password_len);
191	if (data->grp) {
192		crypto_ec_deinit(data->grp->group);
193		crypto_ec_point_deinit(data->grp->pwe, 1);
194		os_free(data->grp);
195	}
196	wpabuf_free(data->inbuf);
197	wpabuf_free(data->outbuf);
198	os_free(data->allowed_groups.range);
199	bin_clear_free(data, sizeof(*data));
200}
201
202
203static u8 * eap_pwd_getkey(struct eap_sm *sm, void *priv, size_t *len)
204{
205	struct eap_pwd_data *data = priv;
206	u8 *key;
207
208	if (data->state != SUCCESS)
209		return NULL;
210
211	key = os_memdup(data->msk, EAP_MSK_LEN);
212	if (key == NULL)
213		return NULL;
214
215	*len = EAP_MSK_LEN;
216
217	return key;
218}
219
220
221static u8 * eap_pwd_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
222{
223	struct eap_pwd_data *data = priv;
224	u8 *id;
225
226	if (data->state != SUCCESS)
227		return NULL;
228
229	id = os_memdup(data->session_id, 1 + SHA256_MAC_LEN);
230	if (id == NULL)
231		return NULL;
232
233	*len = 1 + SHA256_MAC_LEN;
234
235	return id;
236}
237
238
239static int eap_pwd_allowed_group(struct eap_pwd_data *data, u16 group)
240{
241	if (!data->allowed_groups.range) {
242		/* By default, allow the groups using NIST curves P-256, P-384,
243		 * and P-521. */
244		return group == 19 || group == 20 || group == 21;
245	}
246
247	return freq_range_list_includes(&data->allowed_groups, group);
248}
249
250
251static void
252eap_pwd_perform_id_exchange(struct eap_sm *sm, struct eap_pwd_data *data,
253			    struct eap_method_ret *ret,
254			    const struct wpabuf *reqData,
255			    const u8 *payload, size_t payload_len)
256{
257	struct eap_pwd_id *id;
258
259	if (data->state != PWD_ID_Req) {
260		ret->ignore = TRUE;
261		eap_pwd_state(data, FAILURE);
262		return;
263	}
264
265	if (payload_len < sizeof(struct eap_pwd_id)) {
266		ret->ignore = TRUE;
267		eap_pwd_state(data, FAILURE);
268		return;
269	}
270
271	id = (struct eap_pwd_id *) payload;
272	data->group_num = be_to_host16(id->group_num);
273	wpa_printf(MSG_DEBUG,
274		   "EAP-PWD: Server EAP-pwd-ID proposal: group=%u random=%u prf=%u prep=%u",
275		   data->group_num, id->random_function, id->prf, id->prep);
276	if (id->random_function != EAP_PWD_DEFAULT_RAND_FUNC ||
277	    id->prf != EAP_PWD_DEFAULT_PRF ||
278	    !eap_pwd_allowed_group(data, data->group_num)) {
279		wpa_printf(MSG_INFO,
280			   "EAP-pwd: Unsupported or disabled proposal");
281		eap_pwd_state(data, FAILURE);
282		return;
283	}
284
285	if (id->prep != EAP_PWD_PREP_NONE &&
286	    id->prep != EAP_PWD_PREP_MS &&
287	    id->prep != EAP_PWD_PREP_SSHA1 &&
288	    id->prep != EAP_PWD_PREP_SSHA256 &&
289	    id->prep != EAP_PWD_PREP_SSHA512) {
290		wpa_printf(MSG_DEBUG,
291			   "EAP-PWD: Unsupported password pre-processing technique (Prep=%u)",
292			   id->prep);
293		eap_pwd_state(data, FAILURE);
294		return;
295	}
296
297	if (id->prep == EAP_PWD_PREP_NONE && data->password_hash) {
298		wpa_printf(MSG_DEBUG,
299			   "EAP-PWD: Unhashed password not available");
300		eap_pwd_state(data, FAILURE);
301		return;
302	}
303
304	wpa_printf(MSG_DEBUG, "EAP-PWD (peer): using group %d",
305		   data->group_num);
306
307	data->prep = id->prep;
308	os_memcpy(data->token, id->token, sizeof(id->token));
309
310	if (data->id_server || data->grp) {
311		wpa_printf(MSG_INFO, "EAP-pwd: data was already allocated");
312		eap_pwd_state(data, FAILURE);
313		return;
314	}
315
316	data->id_server = os_malloc(payload_len - sizeof(struct eap_pwd_id));
317	if (data->id_server == NULL) {
318		wpa_printf(MSG_INFO, "EAP-PWD: memory allocation id fail");
319		eap_pwd_state(data, FAILURE);
320		return;
321	}
322	data->id_server_len = payload_len - sizeof(struct eap_pwd_id);
323	os_memcpy(data->id_server, id->identity, data->id_server_len);
324	wpa_hexdump_ascii(MSG_INFO, "EAP-PWD (peer): server sent id of",
325			  data->id_server, data->id_server_len);
326
327	data->grp = get_eap_pwd_group(data->group_num);
328	if (data->grp == NULL) {
329		wpa_printf(MSG_INFO, "EAP-PWD: failed to allocate memory for "
330			   "group");
331		eap_pwd_state(data, FAILURE);
332		return;
333	}
334
335	data->outbuf = wpabuf_alloc(sizeof(struct eap_pwd_id) +
336				    data->id_peer_len);
337	if (data->outbuf == NULL) {
338		eap_pwd_state(data, FAILURE);
339		return;
340	}
341	wpabuf_put_be16(data->outbuf, data->group_num);
342	wpabuf_put_u8(data->outbuf, EAP_PWD_DEFAULT_RAND_FUNC);
343	wpabuf_put_u8(data->outbuf, EAP_PWD_DEFAULT_PRF);
344	wpabuf_put_data(data->outbuf, id->token, sizeof(id->token));
345	wpabuf_put_u8(data->outbuf, id->prep);
346	wpabuf_put_data(data->outbuf, data->id_peer, data->id_peer_len);
347
348	eap_pwd_state(data, PWD_Commit_Req);
349}
350
351
352static void
353eap_pwd_perform_commit_exchange(struct eap_sm *sm, struct eap_pwd_data *data,
354				struct eap_method_ret *ret,
355				const struct wpabuf *reqData,
356				const u8 *payload, size_t payload_len)
357{
358	struct crypto_ec_point *K = NULL;
359	struct crypto_bignum *mask = NULL;
360	const u8 *ptr = payload;
361	u8 *scalar, *element;
362	size_t prime_len, order_len;
363	const u8 *password;
364	size_t password_len;
365	u8 pwhashhash[16];
366	const u8 *salt_pwd[2];
367	size_t salt_pwd_len[2], exp_len;
368	u8 salt_len, salthashpwd[64]; /* 64 = SHA512_DIGEST_LENGTH */
369	int res;
370
371	if (data->state != PWD_Commit_Req) {
372		ret->ignore = TRUE;
373		goto fin;
374	}
375
376	if (!data->grp) {
377		wpa_printf(MSG_DEBUG,
378			   "EAP-PWD (client): uninitialized EAP-pwd group");
379		ret->ignore = TRUE;
380		goto fin;
381	}
382
383	prime_len = crypto_ec_prime_len(data->grp->group);
384	order_len = crypto_ec_order_len(data->grp->group);
385
386	switch (data->prep) {
387	case EAP_PWD_PREP_MS:
388		wpa_printf(MSG_DEBUG,
389			   "EAP-pwd commit request, password prep is MS");
390#ifdef CONFIG_FIPS
391		wpa_printf(MSG_ERROR,
392			   "EAP-PWD (peer): MS password hash not supported in FIPS mode");
393		eap_pwd_state(data, FAILURE);
394		return;
395#else /* CONFIG_FIPS */
396		if (payload_len != 2 * prime_len + order_len) {
397			wpa_printf(MSG_INFO,
398				   "EAP-pwd: Unexpected Commit payload length %u (expected %u)",
399				   (unsigned int) payload_len,
400				   (unsigned int) (2 * prime_len + order_len));
401			goto fin;
402		}
403		if (data->password_hash) {
404			res = hash_nt_password_hash(data->password, pwhashhash);
405		} else {
406			u8 pwhash[16];
407
408			res = nt_password_hash(data->password,
409					       data->password_len, pwhash);
410			if (res == 0)
411				res = hash_nt_password_hash(pwhash, pwhashhash);
412			forced_memzero(pwhash, sizeof(pwhash));
413		}
414
415		if (res) {
416			eap_pwd_state(data, FAILURE);
417			return;
418		}
419
420		password = pwhashhash;
421		password_len = sizeof(pwhashhash);
422#endif /* CONFIG_FIPS */
423		break;
424	case EAP_PWD_PREP_SSHA1:
425		wpa_printf(MSG_DEBUG,
426			   "EAP-pwd commit request, password prep is salted sha1");
427		if (payload_len < 1 || *ptr == 0) {
428			wpa_printf(MSG_DEBUG, "EAP-pwd: Invalid Salt-len");
429			goto fin;
430		}
431		salt_len = *ptr++;
432		exp_len = 1 + salt_len + 2 * prime_len + order_len;
433		if (payload_len != exp_len) {
434			wpa_printf(MSG_INFO,
435				   "EAP-pwd: Unexpected Commit payload length %u (expected %u)",
436				   (unsigned int) payload_len,
437				   (unsigned int) exp_len);
438			goto fin;
439		}
440
441		/* salted-password = Hash(password | salt) */
442		wpa_hexdump_key(MSG_DEBUG, "EAP-pwd: Unsalted password",
443				data->password, data->password_len);
444		wpa_hexdump(MSG_DEBUG, "EAP-pwd: Salt", ptr, salt_len);
445		salt_pwd[0] = data->password;
446		salt_pwd[1] = ptr;
447		salt_pwd_len[0] = data->password_len;
448		salt_pwd_len[1] = salt_len;
449		if (sha1_vector(2, salt_pwd, salt_pwd_len, salthashpwd) < 0)
450			goto fin;
451
452		wpa_printf(MSG_DEBUG,
453			   "EAP-pwd: sha1 hashed %d byte salt with password",
454			   (int) salt_len);
455		ptr += salt_len;
456		password = salthashpwd;
457		password_len = SHA1_MAC_LEN;
458		wpa_hexdump_key(MSG_DEBUG, "EAP-pwd: Salted password",
459				password, password_len);
460		break;
461	case EAP_PWD_PREP_SSHA256:
462		wpa_printf(MSG_DEBUG,
463			   "EAP-pwd commit request, password prep is salted sha256");
464		if (payload_len < 1 || *ptr == 0) {
465			wpa_printf(MSG_DEBUG, "EAP-pwd: Invalid Salt-len");
466			goto fin;
467		}
468		salt_len = *ptr++;
469		exp_len = 1 + salt_len + 2 * prime_len + order_len;
470		if (payload_len != exp_len) {
471			wpa_printf(MSG_INFO,
472				   "EAP-pwd: Unexpected Commit payload length %u (expected %u)",
473				   (unsigned int) payload_len,
474				   (unsigned int) exp_len);
475			goto fin;
476		}
477
478		/* salted-password = Hash(password | salt) */
479		wpa_hexdump_key(MSG_DEBUG, "EAP-pwd: Unsalted password",
480				data->password, data->password_len);
481		wpa_hexdump(MSG_DEBUG, "EAP-pwd: Salt", ptr, salt_len);
482		salt_pwd[0] = data->password;
483		salt_pwd[1] = ptr;
484		salt_pwd_len[0] = data->password_len;
485		salt_pwd_len[1] = salt_len;
486		if (sha256_vector(2, salt_pwd, salt_pwd_len, salthashpwd) < 0)
487			goto fin;
488
489		ptr += salt_len;
490		password = salthashpwd;
491		password_len = SHA256_MAC_LEN;
492		wpa_hexdump_key(MSG_DEBUG, "EAP-pwd: Salted password",
493				password, password_len);
494		break;
495#ifdef CONFIG_SHA512
496	case EAP_PWD_PREP_SSHA512:
497		wpa_printf(MSG_DEBUG,
498			   "EAP-pwd commit request, password prep is salted sha512");
499		if (payload_len < 1 || *ptr == 0) {
500			wpa_printf(MSG_DEBUG, "EAP-pwd: Invalid Salt-len");
501			goto fin;
502		}
503		salt_len = *ptr++;
504		exp_len = 1 + salt_len + 2 * prime_len + order_len;
505		if (payload_len != exp_len) {
506			wpa_printf(MSG_INFO,
507				   "EAP-pwd: Unexpected Commit payload length %u (expected %u)",
508				   (unsigned int) payload_len,
509				   (unsigned int) exp_len);
510			goto fin;
511		}
512
513		/* salted-password = Hash(password | salt) */
514		wpa_hexdump_key(MSG_DEBUG, "EAP-pwd: Unsalted password",
515				data->password, data->password_len);
516		wpa_hexdump(MSG_DEBUG, "EAP-pwd: Salt", ptr, salt_len);
517		salt_pwd[0] = data->password;
518		salt_pwd[1] = ptr;
519		salt_pwd_len[0] = data->password_len;
520		salt_pwd_len[1] = salt_len;
521		if (sha512_vector(2, salt_pwd, salt_pwd_len, salthashpwd) < 0)
522			goto fin;
523
524		ptr += salt_len;
525		password = salthashpwd;
526		password_len = SHA512_MAC_LEN;
527		wpa_hexdump_key(MSG_DEBUG, "EAP-pwd: Salted password",
528				password, password_len);
529		break;
530#endif /* CONFIG_SHA512 */
531	case EAP_PWD_PREP_NONE:
532		wpa_printf(MSG_DEBUG,
533			   "EAP-pwd commit request, password prep is NONE");
534		if (data->password_hash) {
535			wpa_printf(MSG_DEBUG,
536				   "EAP-PWD: Unhashed password not available");
537			eap_pwd_state(data, FAILURE);
538			return;
539		}
540		if (payload_len != 2 * prime_len + order_len) {
541			wpa_printf(MSG_INFO,
542				   "EAP-pwd: Unexpected Commit payload length %u (expected %u)",
543				   (unsigned int) payload_len,
544				   (unsigned int) (2 * prime_len + order_len));
545			goto fin;
546		}
547		password = data->password;
548		password_len = data->password_len;
549		break;
550	default:
551		wpa_printf(MSG_DEBUG,
552			   "EAP-pwd: Unsupported password pre-processing technique (Prep=%u)",
553			   data->prep);
554		eap_pwd_state(data, FAILURE);
555		return;
556	}
557
558	/* compute PWE */
559	res = compute_password_element(data->grp, data->group_num,
560				       password, password_len,
561				       data->id_server, data->id_server_len,
562				       data->id_peer, data->id_peer_len,
563				       data->token);
564	forced_memzero(pwhashhash, sizeof(pwhashhash));
565	forced_memzero(salthashpwd, sizeof(salthashpwd));
566	if (res) {
567		wpa_printf(MSG_INFO, "EAP-PWD (peer): unable to compute PWE");
568		eap_pwd_state(data, FAILURE);
569		return;
570	}
571
572	wpa_printf(MSG_DEBUG, "EAP-PWD (peer): computed %d bit PWE...",
573		   (int) crypto_ec_prime_len_bits(data->grp->group));
574
575	data->private_value = crypto_bignum_init();
576	data->my_element = crypto_ec_point_init(data->grp->group);
577	data->my_scalar = crypto_bignum_init();
578	mask = crypto_bignum_init();
579	if (!data->private_value || !data->my_element ||
580	    !data->my_scalar || !mask) {
581		wpa_printf(MSG_INFO, "EAP-PWD (peer): scalar allocation fail");
582		goto fin;
583	}
584
585	if (eap_pwd_get_rand_mask(data->grp, data->private_value, mask,
586				  data->my_scalar) < 0)
587		goto fin;
588
589	if (crypto_ec_point_mul(data->grp->group, data->grp->pwe, mask,
590				data->my_element) < 0) {
591		wpa_printf(MSG_INFO, "EAP-PWD (peer): element allocation "
592			   "fail");
593		eap_pwd_state(data, FAILURE);
594		goto fin;
595	}
596
597	if (crypto_ec_point_invert(data->grp->group, data->my_element) < 0) {
598		wpa_printf(MSG_INFO, "EAP-PWD (peer): element inversion fail");
599		goto fin;
600	}
601
602	/* process the request */
603	data->k = crypto_bignum_init();
604	K = crypto_ec_point_init(data->grp->group);
605	if (!data->k || !K) {
606		wpa_printf(MSG_INFO, "EAP-PWD (peer): peer data allocation "
607			   "fail");
608		goto fin;
609	}
610
611	/* element, x then y, followed by scalar */
612	data->server_element = eap_pwd_get_element(data->grp, ptr);
613	if (!data->server_element) {
614		wpa_printf(MSG_INFO, "EAP-PWD (peer): setting peer element "
615			   "fail");
616		goto fin;
617	}
618	ptr += prime_len * 2;
619	data->server_scalar = eap_pwd_get_scalar(data->grp, ptr);
620	if (!data->server_scalar) {
621		wpa_printf(MSG_INFO,
622			   "EAP-PWD (peer): setting peer scalar fail");
623		goto fin;
624	}
625
626	/* compute the shared key, k */
627	if (crypto_ec_point_mul(data->grp->group, data->grp->pwe,
628				data->server_scalar, K) < 0 ||
629	    crypto_ec_point_add(data->grp->group, K, data->server_element,
630				K) < 0 ||
631	    crypto_ec_point_mul(data->grp->group, K, data->private_value,
632				K) < 0) {
633		wpa_printf(MSG_INFO, "EAP-PWD (peer): computing shared key "
634			   "fail");
635		goto fin;
636	}
637
638	/*
639	 * This check is strictly speaking just for the case where
640	 * co-factor > 1 but it was suggested that even though this is probably
641	 * never going to happen it is a simple and safe check "just to be
642	 * sure" so let's be safe.
643	 */
644	if (crypto_ec_point_is_at_infinity(data->grp->group, K)) {
645		wpa_printf(MSG_INFO, "EAP-PWD (peer): shared key point is at "
646			   "infinity!\n");
647		goto fin;
648	}
649
650	if (crypto_ec_point_x(data->grp->group, K, data->k) < 0) {
651		wpa_printf(MSG_INFO, "EAP-PWD (peer): unable to extract "
652			   "shared secret from point");
653		goto fin;
654	}
655
656	/* now do the response */
657	data->outbuf = wpabuf_alloc(2 * prime_len + order_len);
658	if (data->outbuf == NULL)
659		goto fin;
660	/* We send the element as (x,y) followed by the scalar */
661	element = wpabuf_put(data->outbuf, 2 * prime_len);
662	scalar = wpabuf_put(data->outbuf, order_len);
663
664	/*
665	 * bignums occupy as little memory as possible so one that is
666	 * sufficiently smaller than the prime or order might need pre-pending
667	 * with zeros.
668	 */
669	crypto_bignum_to_bin(data->my_scalar, scalar, order_len, order_len);
670	if (crypto_ec_point_to_bin(data->grp->group, data->my_element, element,
671				   element + prime_len) != 0) {
672		wpa_printf(MSG_INFO, "EAP-PWD (peer): point assignment fail");
673		goto fin;
674	}
675
676fin:
677	crypto_bignum_deinit(mask, 1);
678	crypto_ec_point_deinit(K, 1);
679	if (data->outbuf == NULL)
680		eap_pwd_state(data, FAILURE);
681	else
682		eap_pwd_state(data, PWD_Confirm_Req);
683}
684
685
686static void
687eap_pwd_perform_confirm_exchange(struct eap_sm *sm, struct eap_pwd_data *data,
688				 struct eap_method_ret *ret,
689				 const struct wpabuf *reqData,
690				 const u8 *payload, size_t payload_len)
691{
692	struct crypto_hash *hash = NULL;
693	u32 cs;
694	u16 grp;
695	u8 conf[SHA256_MAC_LEN], *cruft = NULL, *ptr;
696	size_t prime_len = 0, order_len = 0;
697
698	if (data->state != PWD_Confirm_Req) {
699		ret->ignore = TRUE;
700		goto fin;
701	}
702
703	if (payload_len != SHA256_MAC_LEN) {
704		wpa_printf(MSG_INFO,
705			   "EAP-pwd: Unexpected Confirm payload length %u (expected %u)",
706			   (unsigned int) payload_len, SHA256_MAC_LEN);
707		goto fin;
708	}
709
710	prime_len = crypto_ec_prime_len(data->grp->group);
711	order_len = crypto_ec_order_len(data->grp->group);
712
713	/*
714	 * first build up the ciphersuite which is group | random_function |
715	 *	prf
716	 */
717	grp = htons(data->group_num);
718	ptr = (u8 *) &cs;
719	os_memcpy(ptr, &grp, sizeof(u16));
720	ptr += sizeof(u16);
721	*ptr = EAP_PWD_DEFAULT_RAND_FUNC;
722	ptr += sizeof(u8);
723	*ptr = EAP_PWD_DEFAULT_PRF;
724
725	/* each component of the point will be at most as big as the prime */
726	cruft = os_malloc(prime_len * 2);
727	if (!cruft) {
728		wpa_printf(MSG_INFO, "EAP-PWD (server): confirm allocation "
729			   "fail");
730		goto fin;
731	}
732
733	/*
734	 * server's commit is H(k | server_element | server_scalar |
735	 *			peer_element | peer_scalar | ciphersuite)
736	 */
737	hash = eap_pwd_h_init();
738	if (hash == NULL)
739		goto fin;
740
741	/*
742	 * zero the memory each time because this is mod prime math and some
743	 * value may start with a few zeros and the previous one did not.
744	 */
745	crypto_bignum_to_bin(data->k, cruft, prime_len, prime_len);
746	eap_pwd_h_update(hash, cruft, prime_len);
747
748	/* server element: x, y */
749	if (crypto_ec_point_to_bin(data->grp->group, data->server_element,
750				   cruft, cruft + prime_len) != 0) {
751		wpa_printf(MSG_INFO, "EAP-PWD (server): confirm point "
752			   "assignment fail");
753		goto fin;
754	}
755	eap_pwd_h_update(hash, cruft, prime_len * 2);
756
757	/* server scalar */
758	crypto_bignum_to_bin(data->server_scalar, cruft, order_len, order_len);
759	eap_pwd_h_update(hash, cruft, order_len);
760
761	/* my element: x, y */
762	if (crypto_ec_point_to_bin(data->grp->group, data->my_element, cruft,
763				   cruft + prime_len) != 0) {
764		wpa_printf(MSG_INFO, "EAP-PWD (server): confirm point "
765			   "assignment fail");
766		goto fin;
767	}
768	eap_pwd_h_update(hash, cruft, prime_len * 2);
769
770	/* my scalar */
771	crypto_bignum_to_bin(data->my_scalar, cruft, order_len, order_len);
772	eap_pwd_h_update(hash, cruft, order_len);
773
774	/* the ciphersuite */
775	eap_pwd_h_update(hash, (u8 *) &cs, sizeof(u32));
776
777	/* random function fin */
778	eap_pwd_h_final(hash, conf);
779	hash = NULL;
780
781	ptr = (u8 *) payload;
782	if (os_memcmp_const(conf, ptr, SHA256_MAC_LEN)) {
783		wpa_printf(MSG_INFO, "EAP-PWD (peer): confirm did not verify");
784		goto fin;
785	}
786
787	wpa_printf(MSG_DEBUG, "EAP-pwd (peer): confirm verified");
788
789	/*
790	 * compute confirm:
791	 *  H(k | peer_element | peer_scalar | server_element | server_scalar |
792	 *    ciphersuite)
793	 */
794	hash = eap_pwd_h_init();
795	if (hash == NULL)
796		goto fin;
797
798	/* k */
799	crypto_bignum_to_bin(data->k, cruft, prime_len, prime_len);
800	eap_pwd_h_update(hash, cruft, prime_len);
801
802	/* my element */
803	if (crypto_ec_point_to_bin(data->grp->group, data->my_element, cruft,
804				   cruft + prime_len) != 0) {
805		wpa_printf(MSG_INFO, "EAP-PWD (peer): confirm point "
806			   "assignment fail");
807		goto fin;
808	}
809	eap_pwd_h_update(hash, cruft, prime_len * 2);
810
811	/* my scalar */
812	crypto_bignum_to_bin(data->my_scalar, cruft, order_len, order_len);
813	eap_pwd_h_update(hash, cruft, order_len);
814
815	/* server element: x, y */
816	if (crypto_ec_point_to_bin(data->grp->group, data->server_element,
817				   cruft, cruft + prime_len) != 0) {
818		wpa_printf(MSG_INFO, "EAP-PWD (peer): confirm point "
819			   "assignment fail");
820		goto fin;
821	}
822	eap_pwd_h_update(hash, cruft, prime_len * 2);
823
824	/* server scalar */
825	crypto_bignum_to_bin(data->server_scalar, cruft, order_len, order_len);
826	eap_pwd_h_update(hash, cruft, order_len);
827
828	/* the ciphersuite */
829	eap_pwd_h_update(hash, (u8 *) &cs, sizeof(u32));
830
831	/* all done */
832	eap_pwd_h_final(hash, conf);
833	hash = NULL;
834
835	if (compute_keys(data->grp, data->k,
836			 data->my_scalar, data->server_scalar, conf, ptr,
837			 &cs, data->msk, data->emsk, data->session_id) < 0) {
838		wpa_printf(MSG_INFO, "EAP-PWD (peer): unable to compute MSK | "
839			   "EMSK");
840		goto fin;
841	}
842
843	data->outbuf = wpabuf_alloc(SHA256_MAC_LEN);
844	if (data->outbuf == NULL)
845		goto fin;
846
847	wpabuf_put_data(data->outbuf, conf, SHA256_MAC_LEN);
848
849fin:
850	bin_clear_free(cruft, prime_len * 2);
851	if (data->outbuf == NULL) {
852		ret->methodState = METHOD_DONE;
853		ret->decision = DECISION_FAIL;
854		eap_pwd_state(data, FAILURE);
855	} else {
856		eap_pwd_state(data, SUCCESS_ON_FRAG_COMPLETION);
857	}
858
859	/* clean allocated memory */
860	if (hash)
861		eap_pwd_h_final(hash, conf);
862}
863
864
865static struct wpabuf *
866eap_pwd_process(struct eap_sm *sm, void *priv, struct eap_method_ret *ret,
867		const struct wpabuf *reqData)
868{
869	struct eap_pwd_data *data = priv;
870	struct wpabuf *resp = NULL;
871	const u8 *pos, *buf;
872	size_t len;
873	u16 tot_len = 0;
874	u8 lm_exch;
875
876	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PWD, reqData, &len);
877	if ((pos == NULL) || (len < 1)) {
878		wpa_printf(MSG_DEBUG, "EAP-pwd: Got a frame but pos is %s and "
879			   "len is %d",
880			   pos == NULL ? "NULL" : "not NULL", (int) len);
881		ret->ignore = TRUE;
882		return NULL;
883	}
884
885	ret->ignore = FALSE;
886	ret->methodState = METHOD_MAY_CONT;
887	ret->decision = DECISION_FAIL;
888	ret->allowNotifications = FALSE;
889
890	lm_exch = *pos;
891	pos++;                  /* skip over the bits and the exch */
892	len--;
893
894	/*
895	 * we're fragmenting so send out the next fragment
896	 */
897	if (data->out_frag_pos) {
898		/*
899		 * this should be an ACK
900		 */
901		if (len)
902			wpa_printf(MSG_INFO, "Bad Response! Fragmenting but "
903				   "not an ACK");
904
905		wpa_printf(MSG_DEBUG, "EAP-pwd: Got an ACK for a fragment");
906		/*
907		 * check if there are going to be more fragments
908		 */
909		len = wpabuf_len(data->outbuf) - data->out_frag_pos;
910		if ((len + EAP_PWD_HDR_SIZE) > data->mtu) {
911			len = data->mtu - EAP_PWD_HDR_SIZE;
912			EAP_PWD_SET_MORE_BIT(lm_exch);
913		}
914		resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PWD,
915				     EAP_PWD_HDR_SIZE + len,
916				     EAP_CODE_RESPONSE, eap_get_id(reqData));
917		if (resp == NULL) {
918			wpa_printf(MSG_INFO, "Unable to allocate memory for "
919				   "next fragment!");
920			return NULL;
921		}
922		wpabuf_put_u8(resp, lm_exch);
923		buf = wpabuf_head_u8(data->outbuf);
924		wpabuf_put_data(resp, buf + data->out_frag_pos, len);
925		data->out_frag_pos += len;
926		/*
927		 * this is the last fragment so get rid of the out buffer
928		 */
929		if (data->out_frag_pos >= wpabuf_len(data->outbuf)) {
930			wpabuf_free(data->outbuf);
931			data->outbuf = NULL;
932			data->out_frag_pos = 0;
933		}
934		wpa_printf(MSG_DEBUG, "EAP-pwd: Send %s fragment of %d bytes",
935			   data->out_frag_pos == 0 ? "last" : "next",
936			   (int) len);
937		if (data->state == SUCCESS_ON_FRAG_COMPLETION) {
938			ret->methodState = METHOD_DONE;
939			ret->decision = DECISION_UNCOND_SUCC;
940			eap_pwd_state(data, SUCCESS);
941		}
942		return resp;
943	}
944
945	/*
946	 * see if this is a fragment that needs buffering
947	 *
948	 * if it's the first fragment there'll be a length field
949	 */
950	if (EAP_PWD_GET_LENGTH_BIT(lm_exch)) {
951		if (len < 2) {
952			wpa_printf(MSG_DEBUG,
953				   "EAP-pwd: Frame too short to contain Total-Length field");
954			ret->ignore = TRUE;
955			return NULL;
956		}
957		tot_len = WPA_GET_BE16(pos);
958		wpa_printf(MSG_DEBUG, "EAP-pwd: Incoming fragments whose "
959			   "total length = %d", tot_len);
960		if (tot_len > 15000)
961			return NULL;
962		if (data->inbuf) {
963			wpa_printf(MSG_DEBUG,
964				   "EAP-pwd: Unexpected new fragment start when previous fragment is still in use");
965			ret->ignore = TRUE;
966			return NULL;
967		}
968		data->inbuf = wpabuf_alloc(tot_len);
969		if (data->inbuf == NULL) {
970			wpa_printf(MSG_INFO, "Out of memory to buffer "
971				   "fragments!");
972			return NULL;
973		}
974		data->in_frag_pos = 0;
975		pos += sizeof(u16);
976		len -= sizeof(u16);
977	}
978	/*
979	 * buffer and ACK the fragment
980	 */
981	if (EAP_PWD_GET_MORE_BIT(lm_exch) || data->in_frag_pos) {
982		if (!data->inbuf) {
983			wpa_printf(MSG_DEBUG,
984				   "EAP-pwd: No buffer for reassembly");
985			ret->methodState = METHOD_DONE;
986			ret->decision = DECISION_FAIL;
987			return NULL;
988		}
989		data->in_frag_pos += len;
990		if (data->in_frag_pos > wpabuf_size(data->inbuf)) {
991			wpa_printf(MSG_INFO, "EAP-pwd: Buffer overflow attack "
992				   "detected (%d vs. %d)!",
993				   (int) data->in_frag_pos,
994				   (int) wpabuf_len(data->inbuf));
995			wpabuf_free(data->inbuf);
996			data->inbuf = NULL;
997			data->in_frag_pos = 0;
998			return NULL;
999		}
1000		wpabuf_put_data(data->inbuf, pos, len);
1001	}
1002	if (EAP_PWD_GET_MORE_BIT(lm_exch)) {
1003		resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PWD,
1004				     EAP_PWD_HDR_SIZE,
1005				     EAP_CODE_RESPONSE, eap_get_id(reqData));
1006		if (resp != NULL)
1007			wpabuf_put_u8(resp, (EAP_PWD_GET_EXCHANGE(lm_exch)));
1008		wpa_printf(MSG_DEBUG, "EAP-pwd: ACKing a %d byte fragment",
1009			   (int) len);
1010		return resp;
1011	}
1012	/*
1013	 * we're buffering and this is the last fragment
1014	 */
1015	if (data->in_frag_pos && data->inbuf) {
1016		wpa_printf(MSG_DEBUG, "EAP-pwd: Last fragment, %d bytes",
1017			   (int) len);
1018		pos = wpabuf_head_u8(data->inbuf);
1019		len = data->in_frag_pos;
1020	}
1021	wpa_printf(MSG_DEBUG, "EAP-pwd: processing frame: exch %d, len %d",
1022		   EAP_PWD_GET_EXCHANGE(lm_exch), (int) len);
1023
1024	switch (EAP_PWD_GET_EXCHANGE(lm_exch)) {
1025	case EAP_PWD_OPCODE_ID_EXCH:
1026		eap_pwd_perform_id_exchange(sm, data, ret, reqData,
1027					    pos, len);
1028		break;
1029	case EAP_PWD_OPCODE_COMMIT_EXCH:
1030		eap_pwd_perform_commit_exchange(sm, data, ret, reqData,
1031						pos, len);
1032		break;
1033	case EAP_PWD_OPCODE_CONFIRM_EXCH:
1034		eap_pwd_perform_confirm_exchange(sm, data, ret, reqData,
1035						 pos, len);
1036		break;
1037	default:
1038		wpa_printf(MSG_INFO, "EAP-pwd: Ignoring message with unknown "
1039			   "opcode %d", lm_exch);
1040		break;
1041	}
1042	/*
1043	 * if we buffered the just processed input now's the time to free it
1044	 */
1045	if (data->in_frag_pos) {
1046		wpabuf_free(data->inbuf);
1047		data->inbuf = NULL;
1048		data->in_frag_pos = 0;
1049	}
1050
1051	if (data->outbuf == NULL) {
1052		ret->methodState = METHOD_DONE;
1053		ret->decision = DECISION_FAIL;
1054		return NULL;        /* generic failure */
1055	}
1056
1057	/*
1058	 * we have output! Do we need to fragment it?
1059	 */
1060	lm_exch = EAP_PWD_GET_EXCHANGE(lm_exch);
1061	len = wpabuf_len(data->outbuf);
1062	if ((len + EAP_PWD_HDR_SIZE) > data->mtu) {
1063		resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PWD, data->mtu,
1064				     EAP_CODE_RESPONSE, eap_get_id(reqData));
1065		/*
1066		 * if so it's the first so include a length field
1067		 */
1068		EAP_PWD_SET_LENGTH_BIT(lm_exch);
1069		EAP_PWD_SET_MORE_BIT(lm_exch);
1070		tot_len = len;
1071		/*
1072		 * keep the packet at the MTU
1073		 */
1074		len = data->mtu - EAP_PWD_HDR_SIZE - sizeof(u16);
1075		wpa_printf(MSG_DEBUG, "EAP-pwd: Fragmenting output, total "
1076			   "length = %d", tot_len);
1077	} else {
1078		resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PWD,
1079				     EAP_PWD_HDR_SIZE + len,
1080				     EAP_CODE_RESPONSE, eap_get_id(reqData));
1081	}
1082	if (resp == NULL)
1083		return NULL;
1084
1085	wpabuf_put_u8(resp, lm_exch);
1086	if (EAP_PWD_GET_LENGTH_BIT(lm_exch)) {
1087		wpabuf_put_be16(resp, tot_len);
1088		data->out_frag_pos += len;
1089	}
1090	buf = wpabuf_head_u8(data->outbuf);
1091	wpabuf_put_data(resp, buf, len);
1092	/*
1093	 * if we're not fragmenting then there's no need to carry this around
1094	 */
1095	if (data->out_frag_pos == 0) {
1096		wpabuf_free(data->outbuf);
1097		data->outbuf = NULL;
1098		data->out_frag_pos = 0;
1099		if (data->state == SUCCESS_ON_FRAG_COMPLETION) {
1100			ret->methodState = METHOD_DONE;
1101			ret->decision = DECISION_UNCOND_SUCC;
1102			eap_pwd_state(data, SUCCESS);
1103		}
1104	}
1105
1106	return resp;
1107}
1108
1109
1110static Boolean eap_pwd_key_available(struct eap_sm *sm, void *priv)
1111{
1112	struct eap_pwd_data *data = priv;
1113	return data->state == SUCCESS;
1114}
1115
1116
1117static u8 * eap_pwd_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
1118{
1119	struct eap_pwd_data *data = priv;
1120	u8 *key;
1121
1122	if (data->state != SUCCESS)
1123		return NULL;
1124
1125	if ((key = os_malloc(EAP_EMSK_LEN)) == NULL)
1126		return NULL;
1127
1128	os_memcpy(key, data->emsk, EAP_EMSK_LEN);
1129	*len = EAP_EMSK_LEN;
1130
1131	return key;
1132}
1133
1134
1135int eap_peer_pwd_register(void)
1136{
1137	struct eap_method *eap;
1138
1139	eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
1140				    EAP_VENDOR_IETF, EAP_TYPE_PWD, "PWD");
1141	if (eap == NULL)
1142		return -1;
1143
1144	eap->init = eap_pwd_init;
1145	eap->deinit = eap_pwd_deinit;
1146	eap->process = eap_pwd_process;
1147	eap->isKeyAvailable = eap_pwd_key_available;
1148	eap->getKey = eap_pwd_getkey;
1149	eap->getSessionId = eap_pwd_get_session_id;
1150	eap->get_emsk = eap_pwd_get_emsk;
1151
1152	return eap_peer_method_register(eap);
1153}
1154