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