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