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