2 * EAP peer method: EAP-pwd (RFC 5931)
3 * Copyright (c) 2010, Dan Harkins <dharkins@lounge.org>
5 * This software may be distributed under the terms of the BSD license.
6 * See README for more details.
12 #include "eap_peer/eap_i.h"
13 #include "eap_common/eap_pwd_common.h"
18 PWD_ID_Req
, PWD_Commit_Req
, PWD_Confirm_Req
, SUCCESS
, FAILURE
31 struct wpabuf
*outbuf
;
36 BIGNUM
*private_value
;
37 BIGNUM
*server_scalar
;
40 EC_POINT
*server_element
;
43 u8 emsk
[EAP_EMSK_LEN
];
49 #ifndef CONFIG_NO_STDOUT_DEBUG
50 static const char * eap_pwd_state_txt(int state
)
56 return "PWD-Commit-Req";
58 return "PWD-Confirm-Req";
67 #endif /* CONFIG_NO_STDOUT_DEBUG */
70 static void eap_pwd_state(struct eap_pwd_data
*data
, int state
)
72 wpa_printf(MSG_DEBUG
, "EAP-PWD: %s -> %s",
73 eap_pwd_state_txt(data
->state
), eap_pwd_state_txt(state
));
78 static void * eap_pwd_init(struct eap_sm
*sm
)
80 struct eap_pwd_data
*data
;
81 const u8
*identity
, *password
;
82 size_t identity_len
, password_len
;
84 password
= eap_get_config_password(sm
, &password_len
);
85 if (password
== NULL
) {
86 wpa_printf(MSG_INFO
, "EAP-PWD: No password configured!");
90 identity
= eap_get_config_identity(sm
, &identity_len
);
91 if (identity
== NULL
) {
92 wpa_printf(MSG_INFO
, "EAP-PWD: No identity configured!");
96 if ((data
= os_zalloc(sizeof(*data
))) == NULL
) {
97 wpa_printf(MSG_INFO
, "EAP-PWD: memory allocation data fail");
101 if ((data
->bnctx
= BN_CTX_new()) == NULL
) {
102 wpa_printf(MSG_INFO
, "EAP-PWD: bn context allocation fail");
107 if ((data
->id_peer
= os_malloc(identity_len
)) == NULL
) {
108 wpa_printf(MSG_INFO
, "EAP-PWD: memory allocation id fail");
109 BN_CTX_free(data
->bnctx
);
114 os_memcpy(data
->id_peer
, identity
, identity_len
);
115 data
->id_peer_len
= identity_len
;
117 if ((data
->password
= os_malloc(password_len
)) == NULL
) {
118 wpa_printf(MSG_INFO
, "EAP-PWD: memory allocation psk fail");
119 BN_CTX_free(data
->bnctx
);
120 os_free(data
->id_peer
);
124 os_memcpy(data
->password
, password
, password_len
);
125 data
->password_len
= password_len
;
127 data
->out_frag_pos
= data
->in_frag_pos
= 0;
128 data
->inbuf
= data
->outbuf
= NULL
;
129 data
->mtu
= 1020; /* default from RFC 5931, make it configurable! */
131 data
->state
= PWD_ID_Req
;
137 static void eap_pwd_deinit(struct eap_sm
*sm
, void *priv
)
139 struct eap_pwd_data
*data
= priv
;
141 BN_free(data
->private_value
);
142 BN_free(data
->server_scalar
);
143 BN_free(data
->my_scalar
);
145 BN_CTX_free(data
->bnctx
);
146 EC_POINT_free(data
->my_element
);
147 EC_POINT_free(data
->server_element
);
148 os_free(data
->id_peer
);
149 os_free(data
->id_server
);
150 os_free(data
->password
);
152 EC_GROUP_free(data
->grp
->group
);
153 EC_POINT_free(data
->grp
->pwe
);
154 BN_free(data
->grp
->order
);
155 BN_free(data
->grp
->prime
);
162 static u8
* eap_pwd_getkey(struct eap_sm
*sm
, void *priv
, size_t *len
)
164 struct eap_pwd_data
*data
= priv
;
167 if (data
->state
!= SUCCESS
)
170 key
= os_malloc(EAP_MSK_LEN
);
174 os_memcpy(key
, data
->msk
, EAP_MSK_LEN
);
182 eap_pwd_perform_id_exchange(struct eap_sm
*sm
, struct eap_pwd_data
*data
,
183 struct eap_method_ret
*ret
,
184 const struct wpabuf
*reqData
,
185 const u8
*payload
, size_t payload_len
)
187 struct eap_pwd_id
*id
;
189 if (data
->state
!= PWD_ID_Req
) {
191 eap_pwd_state(data
, FAILURE
);
195 if (payload_len
< sizeof(struct eap_pwd_id
)) {
197 eap_pwd_state(data
, FAILURE
);
201 id
= (struct eap_pwd_id
*) payload
;
202 data
->group_num
= be_to_host16(id
->group_num
);
203 if ((id
->random_function
!= EAP_PWD_DEFAULT_RAND_FUNC
) ||
204 (id
->prf
!= EAP_PWD_DEFAULT_PRF
)) {
206 eap_pwd_state(data
, FAILURE
);
210 wpa_printf(MSG_DEBUG
, "EAP-PWD (peer): using group %d",
213 data
->id_server
= os_malloc(payload_len
- sizeof(struct eap_pwd_id
));
214 if (data
->id_server
== NULL
) {
215 wpa_printf(MSG_INFO
, "EAP-PWD: memory allocation id fail");
216 eap_pwd_state(data
, FAILURE
);
219 data
->id_server_len
= payload_len
- sizeof(struct eap_pwd_id
);
220 os_memcpy(data
->id_server
, id
->identity
, data
->id_server_len
);
221 wpa_hexdump_ascii(MSG_INFO
, "EAP-PWD (peer): server sent id of",
222 data
->id_server
, data
->id_server_len
);
224 if ((data
->grp
= (EAP_PWD_group
*) os_malloc(sizeof(EAP_PWD_group
))) ==
226 wpa_printf(MSG_INFO
, "EAP-PWD: failed to allocate memory for "
228 eap_pwd_state(data
, FAILURE
);
233 if (compute_password_element(data
->grp
, data
->group_num
,
234 data
->password
, data
->password_len
,
235 data
->id_server
, data
->id_server_len
,
236 data
->id_peer
, data
->id_peer_len
,
238 wpa_printf(MSG_INFO
, "EAP-PWD (peer): unable to compute PWE");
239 eap_pwd_state(data
, FAILURE
);
243 wpa_printf(MSG_DEBUG
, "EAP-PWD (peer): computed %d bit PWE...",
244 BN_num_bits(data
->grp
->prime
));
246 data
->outbuf
= wpabuf_alloc(sizeof(struct eap_pwd_id
) +
248 if (data
->outbuf
== NULL
) {
249 eap_pwd_state(data
, FAILURE
);
252 wpabuf_put_be16(data
->outbuf
, data
->group_num
);
253 wpabuf_put_u8(data
->outbuf
, EAP_PWD_DEFAULT_RAND_FUNC
);
254 wpabuf_put_u8(data
->outbuf
, EAP_PWD_DEFAULT_PRF
);
255 wpabuf_put_data(data
->outbuf
, id
->token
, sizeof(id
->token
));
256 wpabuf_put_u8(data
->outbuf
, EAP_PWD_PREP_NONE
);
257 wpabuf_put_data(data
->outbuf
, data
->id_peer
, data
->id_peer_len
);
259 eap_pwd_state(data
, PWD_Commit_Req
);
264 eap_pwd_perform_commit_exchange(struct eap_sm
*sm
, struct eap_pwd_data
*data
,
265 struct eap_method_ret
*ret
,
266 const struct wpabuf
*reqData
,
267 const u8
*payload
, size_t payload_len
)
269 EC_POINT
*K
= NULL
, *point
= NULL
;
270 BIGNUM
*mask
= NULL
, *x
= NULL
, *y
= NULL
, *cofactor
= NULL
;
272 u8
*ptr
, *scalar
= NULL
, *element
= NULL
;
274 if (((data
->private_value
= BN_new()) == NULL
) ||
275 ((data
->my_element
= EC_POINT_new(data
->grp
->group
)) == NULL
) ||
276 ((cofactor
= BN_new()) == NULL
) ||
277 ((data
->my_scalar
= BN_new()) == NULL
) ||
278 ((mask
= BN_new()) == NULL
)) {
279 wpa_printf(MSG_INFO
, "EAP-PWD (peer): scalar allocation fail");
283 if (!EC_GROUP_get_cofactor(data
->grp
->group
, cofactor
, NULL
)) {
284 wpa_printf(MSG_INFO
, "EAP-pwd (peer): unable to get cofactor "
289 BN_rand_range(data
->private_value
, data
->grp
->order
);
290 BN_rand_range(mask
, data
->grp
->order
);
291 BN_add(data
->my_scalar
, data
->private_value
, mask
);
292 BN_mod(data
->my_scalar
, data
->my_scalar
, data
->grp
->order
,
295 if (!EC_POINT_mul(data
->grp
->group
, data
->my_element
, NULL
,
296 data
->grp
->pwe
, mask
, data
->bnctx
)) {
297 wpa_printf(MSG_INFO
, "EAP-PWD (peer): element allocation "
299 eap_pwd_state(data
, FAILURE
);
303 if (!EC_POINT_invert(data
->grp
->group
, data
->my_element
, data
->bnctx
))
305 wpa_printf(MSG_INFO
, "EAP-PWD (peer): element inversion fail");
310 if (((x
= BN_new()) == NULL
) ||
311 ((y
= BN_new()) == NULL
)) {
312 wpa_printf(MSG_INFO
, "EAP-PWD (peer): point allocation fail");
316 /* process the request */
317 if (((data
->server_scalar
= BN_new()) == NULL
) ||
318 ((data
->k
= BN_new()) == NULL
) ||
319 ((K
= EC_POINT_new(data
->grp
->group
)) == NULL
) ||
320 ((point
= EC_POINT_new(data
->grp
->group
)) == NULL
) ||
321 ((data
->server_element
= EC_POINT_new(data
->grp
->group
)) == NULL
))
323 wpa_printf(MSG_INFO
, "EAP-PWD (peer): peer data allocation "
328 /* element, x then y, followed by scalar */
329 ptr
= (u8
*) payload
;
330 BN_bin2bn(ptr
, BN_num_bytes(data
->grp
->prime
), x
);
331 ptr
+= BN_num_bytes(data
->grp
->prime
);
332 BN_bin2bn(ptr
, BN_num_bytes(data
->grp
->prime
), y
);
333 ptr
+= BN_num_bytes(data
->grp
->prime
);
334 BN_bin2bn(ptr
, BN_num_bytes(data
->grp
->order
), data
->server_scalar
);
335 if (!EC_POINT_set_affine_coordinates_GFp(data
->grp
->group
,
336 data
->server_element
, x
, y
,
338 wpa_printf(MSG_INFO
, "EAP-PWD (peer): setting peer element "
343 /* check to ensure server's element is not in a small sub-group */
344 if (BN_cmp(cofactor
, BN_value_one())) {
345 if (!EC_POINT_mul(data
->grp
->group
, point
, NULL
,
346 data
->server_element
, cofactor
, NULL
)) {
347 wpa_printf(MSG_INFO
, "EAP-PWD (peer): cannot multiply "
348 "server element by order!\n");
351 if (EC_POINT_is_at_infinity(data
->grp
->group
, point
)) {
352 wpa_printf(MSG_INFO
, "EAP-PWD (peer): server element "
353 "is at infinity!\n");
358 /* compute the shared key, k */
359 if ((!EC_POINT_mul(data
->grp
->group
, K
, NULL
, data
->grp
->pwe
,
360 data
->server_scalar
, data
->bnctx
)) ||
361 (!EC_POINT_add(data
->grp
->group
, K
, K
, data
->server_element
,
363 (!EC_POINT_mul(data
->grp
->group
, K
, NULL
, K
, data
->private_value
,
365 wpa_printf(MSG_INFO
, "EAP-PWD (peer): computing shared key "
370 /* ensure that the shared key isn't in a small sub-group */
371 if (BN_cmp(cofactor
, BN_value_one())) {
372 if (!EC_POINT_mul(data
->grp
->group
, K
, NULL
, K
, cofactor
,
374 wpa_printf(MSG_INFO
, "EAP-PWD (peer): cannot multiply "
375 "shared key point by order");
381 * This check is strictly speaking just for the case above where
382 * co-factor > 1 but it was suggested that even though this is probably
383 * never going to happen it is a simple and safe check "just to be
384 * sure" so let's be safe.
386 if (EC_POINT_is_at_infinity(data
->grp
->group
, K
)) {
387 wpa_printf(MSG_INFO
, "EAP-PWD (peer): shared key point is at "
392 if (!EC_POINT_get_affine_coordinates_GFp(data
->grp
->group
, K
, data
->k
,
393 NULL
, data
->bnctx
)) {
394 wpa_printf(MSG_INFO
, "EAP-PWD (peer): unable to extract "
395 "shared secret from point");
399 /* now do the response */
400 if (!EC_POINT_get_affine_coordinates_GFp(data
->grp
->group
,
401 data
->my_element
, x
, y
,
403 wpa_printf(MSG_INFO
, "EAP-PWD (peer): point assignment fail");
407 if (((scalar
= os_malloc(BN_num_bytes(data
->grp
->order
))) == NULL
) ||
408 ((element
= os_malloc(BN_num_bytes(data
->grp
->prime
) * 2)) ==
410 wpa_printf(MSG_INFO
, "EAP-PWD (peer): data allocation fail");
415 * bignums occupy as little memory as possible so one that is
416 * sufficiently smaller than the prime or order might need pre-pending
419 os_memset(scalar
, 0, BN_num_bytes(data
->grp
->order
));
420 os_memset(element
, 0, BN_num_bytes(data
->grp
->prime
) * 2);
421 offset
= BN_num_bytes(data
->grp
->order
) -
422 BN_num_bytes(data
->my_scalar
);
423 BN_bn2bin(data
->my_scalar
, scalar
+ offset
);
425 offset
= BN_num_bytes(data
->grp
->prime
) - BN_num_bytes(x
);
426 BN_bn2bin(x
, element
+ offset
);
427 offset
= BN_num_bytes(data
->grp
->prime
) - BN_num_bytes(y
);
428 BN_bn2bin(y
, element
+ BN_num_bytes(data
->grp
->prime
) + offset
);
430 data
->outbuf
= wpabuf_alloc(BN_num_bytes(data
->grp
->order
) +
431 2 * BN_num_bytes(data
->grp
->prime
));
432 if (data
->outbuf
== NULL
)
435 /* we send the element as (x,y) follwed by the scalar */
436 wpabuf_put_data(data
->outbuf
, element
,
437 2 * BN_num_bytes(data
->grp
->prime
));
438 wpabuf_put_data(data
->outbuf
, scalar
, BN_num_bytes(data
->grp
->order
));
447 EC_POINT_free(point
);
448 if (data
->outbuf
== NULL
)
449 eap_pwd_state(data
, FAILURE
);
451 eap_pwd_state(data
, PWD_Confirm_Req
);
456 eap_pwd_perform_confirm_exchange(struct eap_sm
*sm
, struct eap_pwd_data
*data
,
457 struct eap_method_ret
*ret
,
458 const struct wpabuf
*reqData
,
459 const u8
*payload
, size_t payload_len
)
461 BIGNUM
*x
= NULL
, *y
= NULL
;
465 u8 conf
[SHA256_DIGEST_LENGTH
], *cruft
= NULL
, *ptr
;
469 * first build up the ciphersuite which is group | random_function |
472 grp
= htons(data
->group_num
);
474 os_memcpy(ptr
, &grp
, sizeof(u16
));
476 *ptr
= EAP_PWD_DEFAULT_RAND_FUNC
;
478 *ptr
= EAP_PWD_DEFAULT_PRF
;
480 /* each component of the cruft will be at most as big as the prime */
481 if (((cruft
= os_malloc(BN_num_bytes(data
->grp
->prime
))) == NULL
) ||
482 ((x
= BN_new()) == NULL
) || ((y
= BN_new()) == NULL
)) {
483 wpa_printf(MSG_INFO
, "EAP-PWD (server): confirm allocation "
489 * server's commit is H(k | server_element | server_scalar |
490 * peer_element | peer_scalar | ciphersuite)
495 * zero the memory each time because this is mod prime math and some
496 * value may start with a few zeros and the previous one did not.
498 os_memset(cruft
, 0, BN_num_bytes(data
->grp
->prime
));
499 offset
= BN_num_bytes(data
->grp
->prime
) - BN_num_bytes(data
->k
);
500 BN_bn2bin(data
->k
, cruft
+ offset
);
501 H_Update(&ctx
, cruft
, BN_num_bytes(data
->grp
->prime
));
503 /* server element: x, y */
504 if (!EC_POINT_get_affine_coordinates_GFp(data
->grp
->group
,
505 data
->server_element
, x
, y
,
507 wpa_printf(MSG_INFO
, "EAP-PWD (server): confirm point "
511 os_memset(cruft
, 0, BN_num_bytes(data
->grp
->prime
));
512 offset
= BN_num_bytes(data
->grp
->prime
) - BN_num_bytes(x
);
513 BN_bn2bin(x
, cruft
+ offset
);
514 H_Update(&ctx
, cruft
, BN_num_bytes(data
->grp
->prime
));
515 os_memset(cruft
, 0, BN_num_bytes(data
->grp
->prime
));
516 offset
= BN_num_bytes(data
->grp
->prime
) - BN_num_bytes(y
);
517 BN_bn2bin(y
, cruft
+ offset
);
518 H_Update(&ctx
, cruft
, BN_num_bytes(data
->grp
->prime
));
521 os_memset(cruft
, 0, BN_num_bytes(data
->grp
->prime
));
522 offset
= BN_num_bytes(data
->grp
->order
) -
523 BN_num_bytes(data
->server_scalar
);
524 BN_bn2bin(data
->server_scalar
, cruft
+ offset
);
525 H_Update(&ctx
, cruft
, BN_num_bytes(data
->grp
->order
));
527 /* my element: x, y */
528 if (!EC_POINT_get_affine_coordinates_GFp(data
->grp
->group
,
529 data
->my_element
, x
, y
,
531 wpa_printf(MSG_INFO
, "EAP-PWD (server): confirm point "
536 os_memset(cruft
, 0, BN_num_bytes(data
->grp
->prime
));
537 offset
= BN_num_bytes(data
->grp
->prime
) - BN_num_bytes(x
);
538 BN_bn2bin(x
, cruft
+ offset
);
539 H_Update(&ctx
, cruft
, BN_num_bytes(data
->grp
->prime
));
540 os_memset(cruft
, 0, BN_num_bytes(data
->grp
->prime
));
541 offset
= BN_num_bytes(data
->grp
->prime
) - BN_num_bytes(y
);
542 BN_bn2bin(y
, cruft
+ offset
);
543 H_Update(&ctx
, cruft
, BN_num_bytes(data
->grp
->prime
));
546 os_memset(cruft
, 0, BN_num_bytes(data
->grp
->prime
));
547 offset
= BN_num_bytes(data
->grp
->order
) -
548 BN_num_bytes(data
->my_scalar
);
549 BN_bn2bin(data
->my_scalar
, cruft
+ offset
);
550 H_Update(&ctx
, cruft
, BN_num_bytes(data
->grp
->order
));
552 /* the ciphersuite */
553 H_Update(&ctx
, (u8
*) &cs
, sizeof(u32
));
555 /* random function fin */
558 ptr
= (u8
*) payload
;
559 if (os_memcmp(conf
, ptr
, SHA256_DIGEST_LENGTH
)) {
560 wpa_printf(MSG_INFO
, "EAP-PWD (peer): confirm did not verify");
564 wpa_printf(MSG_DEBUG
, "EAP-pwd (peer): confirm verified");
568 * H(k | peer_element | peer_scalar | server_element | server_scalar |
574 os_memset(cruft
, 0, BN_num_bytes(data
->grp
->prime
));
575 offset
= BN_num_bytes(data
->grp
->prime
) - BN_num_bytes(data
->k
);
576 BN_bn2bin(data
->k
, cruft
+ offset
);
577 H_Update(&ctx
, cruft
, BN_num_bytes(data
->grp
->prime
));
580 if (!EC_POINT_get_affine_coordinates_GFp(data
->grp
->group
,
581 data
->my_element
, x
, y
,
583 wpa_printf(MSG_INFO
, "EAP-PWD (peer): confirm point "
587 os_memset(cruft
, 0, BN_num_bytes(data
->grp
->prime
));
588 offset
= BN_num_bytes(data
->grp
->prime
) - BN_num_bytes(x
);
589 BN_bn2bin(x
, cruft
+ offset
);
590 H_Update(&ctx
, cruft
, BN_num_bytes(data
->grp
->prime
));
591 os_memset(cruft
, 0, BN_num_bytes(data
->grp
->prime
));
592 offset
= BN_num_bytes(data
->grp
->prime
) - BN_num_bytes(y
);
593 BN_bn2bin(y
, cruft
+ offset
);
594 H_Update(&ctx
, cruft
, BN_num_bytes(data
->grp
->prime
));
597 os_memset(cruft
, 0, BN_num_bytes(data
->grp
->prime
));
598 offset
= BN_num_bytes(data
->grp
->order
) -
599 BN_num_bytes(data
->my_scalar
);
600 BN_bn2bin(data
->my_scalar
, cruft
+ offset
);
601 H_Update(&ctx
, cruft
, BN_num_bytes(data
->grp
->order
));
603 /* server element: x, y */
604 if (!EC_POINT_get_affine_coordinates_GFp(data
->grp
->group
,
605 data
->server_element
, x
, y
,
607 wpa_printf(MSG_INFO
, "EAP-PWD (peer): confirm point "
611 os_memset(cruft
, 0, BN_num_bytes(data
->grp
->prime
));
612 offset
= BN_num_bytes(data
->grp
->prime
) - BN_num_bytes(x
);
613 BN_bn2bin(x
, cruft
+ offset
);
614 H_Update(&ctx
, cruft
, BN_num_bytes(data
->grp
->prime
));
615 os_memset(cruft
, 0, BN_num_bytes(data
->grp
->prime
));
616 offset
= BN_num_bytes(data
->grp
->prime
) - BN_num_bytes(y
);
617 BN_bn2bin(y
, cruft
+ offset
);
618 H_Update(&ctx
, cruft
, BN_num_bytes(data
->grp
->prime
));
621 os_memset(cruft
, 0, BN_num_bytes(data
->grp
->prime
));
622 offset
= BN_num_bytes(data
->grp
->order
) -
623 BN_num_bytes(data
->server_scalar
);
624 BN_bn2bin(data
->server_scalar
, cruft
+ offset
);
625 H_Update(&ctx
, cruft
, BN_num_bytes(data
->grp
->order
));
627 /* the ciphersuite */
628 H_Update(&ctx
, (u8
*) &cs
, sizeof(u32
));
633 if (compute_keys(data
->grp
, data
->bnctx
, data
->k
,
634 data
->my_scalar
, data
->server_scalar
, conf
, ptr
,
635 &cs
, data
->msk
, data
->emsk
) < 0) {
636 wpa_printf(MSG_INFO
, "EAP-PWD (peer): unable to compute MSK | "
641 data
->outbuf
= wpabuf_alloc(SHA256_DIGEST_LENGTH
);
642 if (data
->outbuf
== NULL
)
645 wpabuf_put_data(data
->outbuf
, conf
, SHA256_DIGEST_LENGTH
);
651 ret
->methodState
= METHOD_DONE
;
652 if (data
->outbuf
== NULL
) {
653 ret
->decision
= DECISION_FAIL
;
654 eap_pwd_state(data
, FAILURE
);
656 ret
->decision
= DECISION_UNCOND_SUCC
;
657 eap_pwd_state(data
, SUCCESS
);
662 static struct wpabuf
*
663 eap_pwd_process(struct eap_sm
*sm
, void *priv
, struct eap_method_ret
*ret
,
664 const struct wpabuf
*reqData
)
666 struct eap_pwd_data
*data
= priv
;
667 struct wpabuf
*resp
= NULL
;
673 pos
= eap_hdr_validate(EAP_VENDOR_IETF
, EAP_TYPE_PWD
, reqData
, &len
);
674 if ((pos
== NULL
) || (len
< 1)) {
675 wpa_printf(MSG_DEBUG
, "EAP-pwd: Got a frame but pos is %s and "
677 pos
== NULL
? "NULL" : "not NULL", (int) len
);
683 ret
->methodState
= METHOD_MAY_CONT
;
684 ret
->decision
= DECISION_FAIL
;
685 ret
->allowNotifications
= FALSE
;
688 pos
++; /* skip over the bits and the exch */
692 * we're fragmenting so send out the next fragment
694 if (data
->out_frag_pos
) {
696 * this should be an ACK
699 wpa_printf(MSG_INFO
, "Bad Response! Fragmenting but "
702 wpa_printf(MSG_DEBUG
, "EAP-pwd: Got an ACK for a fragment");
704 * check if there are going to be more fragments
706 len
= wpabuf_len(data
->outbuf
) - data
->out_frag_pos
;
707 if ((len
+ EAP_PWD_HDR_SIZE
) > data
->mtu
) {
708 len
= data
->mtu
- EAP_PWD_HDR_SIZE
;
709 EAP_PWD_SET_MORE_BIT(lm_exch
);
711 resp
= eap_msg_alloc(EAP_VENDOR_IETF
, EAP_TYPE_PWD
,
712 EAP_PWD_HDR_SIZE
+ len
,
713 EAP_CODE_RESPONSE
, eap_get_id(reqData
));
715 wpa_printf(MSG_INFO
, "Unable to allocate memory for "
719 wpabuf_put_u8(resp
, lm_exch
);
720 buf
= wpabuf_head_u8(data
->outbuf
);
721 wpabuf_put_data(resp
, buf
+ data
->out_frag_pos
, len
);
722 data
->out_frag_pos
+= len
;
724 * this is the last fragment so get rid of the out buffer
726 if (data
->out_frag_pos
>= wpabuf_len(data
->outbuf
)) {
727 wpabuf_free(data
->outbuf
);
729 data
->out_frag_pos
= 0;
731 wpa_printf(MSG_DEBUG
, "EAP-pwd: Send %s fragment of %d bytes",
732 data
->out_frag_pos
== 0 ? "last" : "next",
738 * see if this is a fragment that needs buffering
740 * if it's the first fragment there'll be a length field
742 if (EAP_PWD_GET_LENGTH_BIT(lm_exch
)) {
743 tot_len
= WPA_GET_BE16(pos
);
744 wpa_printf(MSG_DEBUG
, "EAP-pwd: Incoming fragments whose "
745 "total length = %d", tot_len
);
746 data
->inbuf
= wpabuf_alloc(tot_len
);
747 if (data
->inbuf
== NULL
) {
748 wpa_printf(MSG_INFO
, "Out of memory to buffer "
756 * buffer and ACK the fragment
758 if (EAP_PWD_GET_MORE_BIT(lm_exch
)) {
759 data
->in_frag_pos
+= len
;
760 if (data
->in_frag_pos
> wpabuf_size(data
->inbuf
)) {
761 wpa_printf(MSG_INFO
, "EAP-pwd: Buffer overflow attack "
762 "detected (%d vs. %d)!",
763 (int) data
->in_frag_pos
,
764 (int) wpabuf_len(data
->inbuf
));
765 wpabuf_free(data
->inbuf
);
766 data
->in_frag_pos
= 0;
769 wpabuf_put_data(data
->inbuf
, pos
, len
);
771 resp
= eap_msg_alloc(EAP_VENDOR_IETF
, EAP_TYPE_PWD
,
773 EAP_CODE_RESPONSE
, eap_get_id(reqData
));
775 wpabuf_put_u8(resp
, (EAP_PWD_GET_EXCHANGE(lm_exch
)));
776 wpa_printf(MSG_DEBUG
, "EAP-pwd: ACKing a %d byte fragment",
781 * we're buffering and this is the last fragment
783 if (data
->in_frag_pos
) {
784 wpabuf_put_data(data
->inbuf
, pos
, len
);
785 wpa_printf(MSG_DEBUG
, "EAP-pwd: Last fragment, %d bytes",
787 data
->in_frag_pos
+= len
;
788 pos
= wpabuf_head_u8(data
->inbuf
);
789 len
= data
->in_frag_pos
;
791 wpa_printf(MSG_DEBUG
, "EAP-pwd: processing frame: exch %d, len %d",
792 EAP_PWD_GET_EXCHANGE(lm_exch
), (int) len
);
794 switch (EAP_PWD_GET_EXCHANGE(lm_exch
)) {
795 case EAP_PWD_OPCODE_ID_EXCH
:
796 eap_pwd_perform_id_exchange(sm
, data
, ret
, reqData
,
799 case EAP_PWD_OPCODE_COMMIT_EXCH
:
800 eap_pwd_perform_commit_exchange(sm
, data
, ret
, reqData
,
803 case EAP_PWD_OPCODE_CONFIRM_EXCH
:
804 eap_pwd_perform_confirm_exchange(sm
, data
, ret
, reqData
,
808 wpa_printf(MSG_INFO
, "EAP-pwd: Ignoring message with unknown "
809 "opcode %d", lm_exch
);
813 * if we buffered the just processed input now's the time to free it
815 if (data
->in_frag_pos
) {
816 wpabuf_free(data
->inbuf
);
817 data
->in_frag_pos
= 0;
820 if (data
->outbuf
== NULL
)
821 return NULL
; /* generic failure */
824 * we have output! Do we need to fragment it?
826 len
= wpabuf_len(data
->outbuf
);
827 if ((len
+ EAP_PWD_HDR_SIZE
) > data
->mtu
) {
828 resp
= eap_msg_alloc(EAP_VENDOR_IETF
, EAP_TYPE_PWD
, data
->mtu
,
829 EAP_CODE_RESPONSE
, eap_get_id(reqData
));
831 * if so it's the first so include a length field
833 EAP_PWD_SET_LENGTH_BIT(lm_exch
);
834 EAP_PWD_SET_MORE_BIT(lm_exch
);
837 * keep the packet at the MTU
839 len
= data
->mtu
- EAP_PWD_HDR_SIZE
- sizeof(u16
);
840 wpa_printf(MSG_DEBUG
, "EAP-pwd: Fragmenting output, total "
841 "length = %d", tot_len
);
843 resp
= eap_msg_alloc(EAP_VENDOR_IETF
, EAP_TYPE_PWD
,
844 EAP_PWD_HDR_SIZE
+ len
,
845 EAP_CODE_RESPONSE
, eap_get_id(reqData
));
850 wpabuf_put_u8(resp
, lm_exch
);
851 if (EAP_PWD_GET_LENGTH_BIT(lm_exch
)) {
852 wpabuf_put_be16(resp
, tot_len
);
853 data
->out_frag_pos
+= len
;
855 buf
= wpabuf_head_u8(data
->outbuf
);
856 wpabuf_put_data(resp
, buf
, len
);
858 * if we're not fragmenting then there's no need to carry this around
860 if (data
->out_frag_pos
== 0) {
861 wpabuf_free(data
->outbuf
);
863 data
->out_frag_pos
= 0;
870 static Boolean
eap_pwd_key_available(struct eap_sm
*sm
, void *priv
)
872 struct eap_pwd_data
*data
= priv
;
873 return data
->state
== SUCCESS
;
877 static u8
* eap_pwd_get_emsk(struct eap_sm
*sm
, void *priv
, size_t *len
)
879 struct eap_pwd_data
*data
= priv
;
882 if (data
->state
!= SUCCESS
)
885 if ((key
= os_malloc(EAP_EMSK_LEN
)) == NULL
)
888 os_memcpy(key
, data
->emsk
, EAP_EMSK_LEN
);
895 int eap_peer_pwd_register(void)
897 struct eap_method
*eap
;
900 EVP_add_digest(EVP_sha256());
901 eap
= eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION
,
902 EAP_VENDOR_IETF
, EAP_TYPE_PWD
, "PWD");
906 eap
->init
= eap_pwd_init
;
907 eap
->deinit
= eap_pwd_deinit
;
908 eap
->process
= eap_pwd_process
;
909 eap
->isKeyAvailable
= eap_pwd_key_available
;
910 eap
->getKey
= eap_pwd_getkey
;
911 eap
->get_emsk
= eap_pwd_get_emsk
;
913 ret
= eap_peer_method_register(eap
);
915 eap_peer_method_free(eap
);