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