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