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