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