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