xref: /freebsd/contrib/wpa/src/eap_server/eap_server_pwd.c (revision 93e779a26c651610ac6e7986d67ecc9ed2cadcbf)
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 
18 struct 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 
56 static 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 
75 static 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 
83 static 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 
137 static 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 
164 static 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 
193 static 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 
290 fin:
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 
300 static 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 
416 fin:
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 
425 static struct wpabuf *
426 eap_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 
546 static 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 
581 static 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 
651 static void
652 eap_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 
764 fin:
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 
778 static void
779 eap_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 
898 fin:
899 	bin_clear_free(cruft, BN_num_bytes(data->grp->prime));
900 	BN_clear_free(x);
901 	BN_clear_free(y);
902 }
903 
904 
905 static 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 
1023 static 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 
1042 static 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 
1061 static 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 
1068 static 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 
1075 static 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 
1094 int 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