xref: /dflybsd-src/contrib/wpa_supplicant/src/eap_server/eap_server_pwd.c (revision 3a84a4273475ed07d0ab1c2dfeffdfedef35d9cd)
13ff40c12SJohn Marino /*
23ff40c12SJohn Marino  * hostapd / EAP-pwd (RFC 5931) server
33ff40c12SJohn Marino  * Copyright (c) 2010, Dan Harkins <dharkins@lounge.org>
43ff40c12SJohn Marino  *
53ff40c12SJohn Marino  * This software may be distributed under the terms of the BSD license.
63ff40c12SJohn Marino  * See README for more details.
73ff40c12SJohn Marino  */
83ff40c12SJohn Marino 
93ff40c12SJohn Marino #include "includes.h"
103ff40c12SJohn Marino 
113ff40c12SJohn Marino #include "common.h"
123ff40c12SJohn Marino #include "crypto/sha256.h"
13*a1157835SDaniel Fojt #include "crypto/ms_funcs.h"
14*a1157835SDaniel Fojt #include "crypto/crypto.h"
153ff40c12SJohn Marino #include "eap_server/eap_i.h"
163ff40c12SJohn Marino #include "eap_common/eap_pwd_common.h"
173ff40c12SJohn Marino 
183ff40c12SJohn Marino 
193ff40c12SJohn Marino struct eap_pwd_data {
203ff40c12SJohn Marino 	enum {
213ff40c12SJohn Marino 		PWD_ID_Req, PWD_Commit_Req, PWD_Confirm_Req, SUCCESS, FAILURE
223ff40c12SJohn Marino 	} state;
233ff40c12SJohn Marino 	u8 *id_peer;
243ff40c12SJohn Marino 	size_t id_peer_len;
253ff40c12SJohn Marino 	u8 *id_server;
263ff40c12SJohn Marino 	size_t id_server_len;
273ff40c12SJohn Marino 	u8 *password;
283ff40c12SJohn Marino 	size_t password_len;
29*a1157835SDaniel Fojt 	int password_hash;
30*a1157835SDaniel Fojt 	u8 *salt;
31*a1157835SDaniel Fojt 	size_t salt_len;
323ff40c12SJohn Marino 	u32 token;
333ff40c12SJohn Marino 	u16 group_num;
34*a1157835SDaniel Fojt 	u8 password_prep;
353ff40c12SJohn Marino 	EAP_PWD_group *grp;
363ff40c12SJohn Marino 
373ff40c12SJohn Marino 	struct wpabuf *inbuf;
383ff40c12SJohn Marino 	size_t in_frag_pos;
393ff40c12SJohn Marino 	struct wpabuf *outbuf;
403ff40c12SJohn Marino 	size_t out_frag_pos;
413ff40c12SJohn Marino 	size_t mtu;
423ff40c12SJohn Marino 
43*a1157835SDaniel Fojt 	struct crypto_bignum *k;
44*a1157835SDaniel Fojt 	struct crypto_bignum *private_value;
45*a1157835SDaniel Fojt 	struct crypto_bignum *peer_scalar;
46*a1157835SDaniel Fojt 	struct crypto_bignum *my_scalar;
47*a1157835SDaniel Fojt 	struct crypto_ec_point *my_element;
48*a1157835SDaniel Fojt 	struct crypto_ec_point *peer_element;
493ff40c12SJohn Marino 
503ff40c12SJohn Marino 	u8 my_confirm[SHA256_MAC_LEN];
513ff40c12SJohn Marino 
523ff40c12SJohn Marino 	u8 msk[EAP_MSK_LEN];
533ff40c12SJohn Marino 	u8 emsk[EAP_EMSK_LEN];
54*a1157835SDaniel Fojt 	u8 session_id[1 + SHA256_MAC_LEN];
553ff40c12SJohn Marino };
563ff40c12SJohn Marino 
573ff40c12SJohn Marino 
eap_pwd_state_txt(int state)583ff40c12SJohn Marino static const char * eap_pwd_state_txt(int state)
593ff40c12SJohn Marino {
603ff40c12SJohn Marino 	switch (state) {
613ff40c12SJohn Marino         case PWD_ID_Req:
623ff40c12SJohn Marino 		return "PWD-ID-Req";
633ff40c12SJohn Marino         case PWD_Commit_Req:
643ff40c12SJohn Marino 		return "PWD-Commit-Req";
653ff40c12SJohn Marino         case PWD_Confirm_Req:
663ff40c12SJohn Marino 		return "PWD-Confirm-Req";
673ff40c12SJohn Marino         case SUCCESS:
683ff40c12SJohn Marino 		return "SUCCESS";
693ff40c12SJohn Marino         case FAILURE:
703ff40c12SJohn Marino 		return "FAILURE";
713ff40c12SJohn Marino         default:
723ff40c12SJohn Marino 		return "PWD-Unk";
733ff40c12SJohn Marino 	}
743ff40c12SJohn Marino }
753ff40c12SJohn Marino 
763ff40c12SJohn Marino 
eap_pwd_state(struct eap_pwd_data * data,int state)773ff40c12SJohn Marino static void eap_pwd_state(struct eap_pwd_data *data, int state)
783ff40c12SJohn Marino {
793ff40c12SJohn Marino 	wpa_printf(MSG_DEBUG, "EAP-pwd: %s -> %s",
803ff40c12SJohn Marino 		   eap_pwd_state_txt(data->state), eap_pwd_state_txt(state));
813ff40c12SJohn Marino 	data->state = state;
823ff40c12SJohn Marino }
833ff40c12SJohn Marino 
843ff40c12SJohn Marino 
eap_pwd_init(struct eap_sm * sm)853ff40c12SJohn Marino static void * eap_pwd_init(struct eap_sm *sm)
863ff40c12SJohn Marino {
873ff40c12SJohn Marino 	struct eap_pwd_data *data;
883ff40c12SJohn Marino 
893ff40c12SJohn Marino 	if (sm->user == NULL || sm->user->password == NULL ||
903ff40c12SJohn Marino 	    sm->user->password_len == 0) {
913ff40c12SJohn Marino 		wpa_printf(MSG_INFO, "EAP-PWD (server): Password is not "
923ff40c12SJohn Marino 			   "configured");
933ff40c12SJohn Marino 		return NULL;
943ff40c12SJohn Marino 	}
953ff40c12SJohn Marino 
963ff40c12SJohn Marino 	data = os_zalloc(sizeof(*data));
973ff40c12SJohn Marino 	if (data == NULL)
983ff40c12SJohn Marino 		return NULL;
993ff40c12SJohn Marino 
1003ff40c12SJohn Marino 	data->group_num = sm->pwd_group;
1013ff40c12SJohn Marino 	wpa_printf(MSG_DEBUG, "EAP-pwd: Selected group number %d",
1023ff40c12SJohn Marino 		   data->group_num);
1033ff40c12SJohn Marino 	data->state = PWD_ID_Req;
1043ff40c12SJohn Marino 
1053ff40c12SJohn Marino 	data->id_server = (u8 *) os_strdup("server");
1063ff40c12SJohn Marino 	if (data->id_server)
1073ff40c12SJohn Marino 		data->id_server_len = os_strlen((char *) data->id_server);
1083ff40c12SJohn Marino 
1093ff40c12SJohn Marino 	data->password = os_malloc(sm->user->password_len);
1103ff40c12SJohn Marino 	if (data->password == NULL) {
1113ff40c12SJohn Marino 		wpa_printf(MSG_INFO, "EAP-PWD: Memory allocation password "
1123ff40c12SJohn Marino 			   "fail");
113*a1157835SDaniel Fojt 		bin_clear_free(data->id_server, data->id_server_len);
1143ff40c12SJohn Marino 		os_free(data);
1153ff40c12SJohn Marino 		return NULL;
1163ff40c12SJohn Marino 	}
1173ff40c12SJohn Marino 	data->password_len = sm->user->password_len;
1183ff40c12SJohn Marino 	os_memcpy(data->password, sm->user->password, data->password_len);
119*a1157835SDaniel Fojt 	data->password_hash = sm->user->password_hash;
1203ff40c12SJohn Marino 
121*a1157835SDaniel Fojt 	data->salt_len = sm->user->salt_len;
122*a1157835SDaniel Fojt 	if (data->salt_len) {
123*a1157835SDaniel Fojt 		data->salt = os_memdup(sm->user->salt, sm->user->salt_len);
124*a1157835SDaniel Fojt 		if (!data->salt) {
125*a1157835SDaniel Fojt 			wpa_printf(MSG_INFO,
126*a1157835SDaniel Fojt 				   "EAP-pwd: Memory allocation of salt failed");
127*a1157835SDaniel Fojt 			bin_clear_free(data->id_server, data->id_server_len);
128*a1157835SDaniel Fojt 			bin_clear_free(data->password, data->password_len);
1293ff40c12SJohn Marino 			os_free(data);
1303ff40c12SJohn Marino 			return NULL;
1313ff40c12SJohn Marino 		}
132*a1157835SDaniel Fojt 	}
1333ff40c12SJohn Marino 
1343ff40c12SJohn Marino 	data->in_frag_pos = data->out_frag_pos = 0;
1353ff40c12SJohn Marino 	data->inbuf = data->outbuf = NULL;
136*a1157835SDaniel Fojt 	/* use default MTU from RFC 5931 if not configured otherwise */
137*a1157835SDaniel Fojt 	data->mtu = sm->fragment_size > 0 ? sm->fragment_size : 1020;
1383ff40c12SJohn Marino 
1393ff40c12SJohn Marino 	return data;
1403ff40c12SJohn Marino }
1413ff40c12SJohn Marino 
1423ff40c12SJohn Marino 
eap_pwd_reset(struct eap_sm * sm,void * priv)1433ff40c12SJohn Marino static void eap_pwd_reset(struct eap_sm *sm, void *priv)
1443ff40c12SJohn Marino {
1453ff40c12SJohn Marino 	struct eap_pwd_data *data = priv;
1463ff40c12SJohn Marino 
147*a1157835SDaniel Fojt 	crypto_bignum_deinit(data->private_value, 1);
148*a1157835SDaniel Fojt 	crypto_bignum_deinit(data->peer_scalar, 1);
149*a1157835SDaniel Fojt 	crypto_bignum_deinit(data->my_scalar, 1);
150*a1157835SDaniel Fojt 	crypto_bignum_deinit(data->k, 1);
151*a1157835SDaniel Fojt 	crypto_ec_point_deinit(data->my_element, 1);
152*a1157835SDaniel Fojt 	crypto_ec_point_deinit(data->peer_element, 1);
153*a1157835SDaniel Fojt 	bin_clear_free(data->id_peer, data->id_peer_len);
154*a1157835SDaniel Fojt 	bin_clear_free(data->id_server, data->id_server_len);
155*a1157835SDaniel Fojt 	bin_clear_free(data->password, data->password_len);
156*a1157835SDaniel Fojt 	bin_clear_free(data->salt, data->salt_len);
1573ff40c12SJohn Marino 	if (data->grp) {
158*a1157835SDaniel Fojt 		crypto_ec_deinit(data->grp->group);
159*a1157835SDaniel Fojt 		crypto_ec_point_deinit(data->grp->pwe, 1);
1603ff40c12SJohn Marino 		os_free(data->grp);
1613ff40c12SJohn Marino 	}
162*a1157835SDaniel Fojt 	wpabuf_free(data->inbuf);
163*a1157835SDaniel Fojt 	wpabuf_free(data->outbuf);
164*a1157835SDaniel Fojt 	bin_clear_free(data, sizeof(*data));
1653ff40c12SJohn Marino }
1663ff40c12SJohn Marino 
1673ff40c12SJohn Marino 
eap_pwd_build_id_req(struct eap_sm * sm,struct eap_pwd_data * data,u8 id)1683ff40c12SJohn Marino static void eap_pwd_build_id_req(struct eap_sm *sm, struct eap_pwd_data *data,
1693ff40c12SJohn Marino 				 u8 id)
1703ff40c12SJohn Marino {
1713ff40c12SJohn Marino 	wpa_printf(MSG_DEBUG, "EAP-pwd: ID/Request");
1723ff40c12SJohn Marino 	/*
1733ff40c12SJohn Marino 	 * if we're fragmenting then we already have an id request, just return
1743ff40c12SJohn Marino 	 */
1753ff40c12SJohn Marino 	if (data->out_frag_pos)
1763ff40c12SJohn Marino 		return;
1773ff40c12SJohn Marino 
1783ff40c12SJohn Marino 	data->outbuf = wpabuf_alloc(sizeof(struct eap_pwd_id) +
1793ff40c12SJohn Marino 				    data->id_server_len);
1803ff40c12SJohn Marino 	if (data->outbuf == NULL) {
1813ff40c12SJohn Marino 		eap_pwd_state(data, FAILURE);
1823ff40c12SJohn Marino 		return;
1833ff40c12SJohn Marino 	}
1843ff40c12SJohn Marino 
185*a1157835SDaniel Fojt 	if (os_get_random((u8 *) &data->token, sizeof(data->token)) < 0) {
186*a1157835SDaniel Fojt 		wpabuf_free(data->outbuf);
187*a1157835SDaniel Fojt 		data->outbuf = NULL;
188*a1157835SDaniel Fojt 		eap_pwd_state(data, FAILURE);
189*a1157835SDaniel Fojt 		return;
190*a1157835SDaniel Fojt 	}
191*a1157835SDaniel Fojt 
192*a1157835SDaniel Fojt 	wpa_hexdump_key(MSG_DEBUG, "EAP-pwd (server): password",
193*a1157835SDaniel Fojt 			data->password, data->password_len);
194*a1157835SDaniel Fojt 	if (data->salt_len)
195*a1157835SDaniel Fojt 		wpa_hexdump(MSG_DEBUG, "EAP-pwd (server): salt",
196*a1157835SDaniel Fojt 			    data->salt, data->salt_len);
197*a1157835SDaniel Fojt 
198*a1157835SDaniel Fojt 	/*
199*a1157835SDaniel Fojt 	 * If this is a salted password then figure out how it was hashed
200*a1157835SDaniel Fojt 	 * based on the length.
201*a1157835SDaniel Fojt 	 */
202*a1157835SDaniel Fojt 	if (data->salt_len) {
203*a1157835SDaniel Fojt 		switch (data->password_len) {
204*a1157835SDaniel Fojt 		case 20:
205*a1157835SDaniel Fojt 			data->password_prep = EAP_PWD_PREP_SSHA1;
206*a1157835SDaniel Fojt 			break;
207*a1157835SDaniel Fojt 		case 32:
208*a1157835SDaniel Fojt 			data->password_prep = EAP_PWD_PREP_SSHA256;
209*a1157835SDaniel Fojt 			break;
210*a1157835SDaniel Fojt 		case 64:
211*a1157835SDaniel Fojt 			data->password_prep = EAP_PWD_PREP_SSHA512;
212*a1157835SDaniel Fojt 			break;
213*a1157835SDaniel Fojt 		default:
214*a1157835SDaniel Fojt 			wpa_printf(MSG_INFO,
215*a1157835SDaniel Fojt 				   "EAP-pwd (server): bad size %d for salted password",
216*a1157835SDaniel Fojt 				   (int) data->password_len);
217*a1157835SDaniel Fojt 			eap_pwd_state(data, FAILURE);
218*a1157835SDaniel Fojt 			return;
219*a1157835SDaniel Fojt 		}
220*a1157835SDaniel Fojt 	} else {
221*a1157835SDaniel Fojt 		/* Otherwise, figure out whether it's MS hashed or plain */
222*a1157835SDaniel Fojt 		data->password_prep = data->password_hash ? EAP_PWD_PREP_MS :
223*a1157835SDaniel Fojt 			EAP_PWD_PREP_NONE;
224*a1157835SDaniel Fojt 	}
225*a1157835SDaniel Fojt 
2263ff40c12SJohn Marino 	wpabuf_put_be16(data->outbuf, data->group_num);
2273ff40c12SJohn Marino 	wpabuf_put_u8(data->outbuf, EAP_PWD_DEFAULT_RAND_FUNC);
2283ff40c12SJohn Marino 	wpabuf_put_u8(data->outbuf, EAP_PWD_DEFAULT_PRF);
2293ff40c12SJohn Marino 	wpabuf_put_data(data->outbuf, &data->token, sizeof(data->token));
230*a1157835SDaniel Fojt 	wpabuf_put_u8(data->outbuf, data->password_prep);
2313ff40c12SJohn Marino 	wpabuf_put_data(data->outbuf, data->id_server, data->id_server_len);
2323ff40c12SJohn Marino }
2333ff40c12SJohn Marino 
2343ff40c12SJohn Marino 
eap_pwd_build_commit_req(struct eap_sm * sm,struct eap_pwd_data * data,u8 id)2353ff40c12SJohn Marino static void eap_pwd_build_commit_req(struct eap_sm *sm,
2363ff40c12SJohn Marino 				     struct eap_pwd_data *data, u8 id)
2373ff40c12SJohn Marino {
238*a1157835SDaniel Fojt 	struct crypto_bignum *mask = NULL;
239*a1157835SDaniel Fojt 	u8 *scalar, *element;
240*a1157835SDaniel Fojt 	size_t prime_len, order_len;
2413ff40c12SJohn Marino 
2423ff40c12SJohn Marino 	wpa_printf(MSG_DEBUG, "EAP-pwd: Commit/Request");
2433ff40c12SJohn Marino 	/*
2443ff40c12SJohn Marino 	 * if we're fragmenting then we already have an commit request, just
2453ff40c12SJohn Marino 	 * return
2463ff40c12SJohn Marino 	 */
2473ff40c12SJohn Marino 	if (data->out_frag_pos)
2483ff40c12SJohn Marino 		return;
2493ff40c12SJohn Marino 
250*a1157835SDaniel Fojt 	prime_len = crypto_ec_prime_len(data->grp->group);
251*a1157835SDaniel Fojt 	order_len = crypto_ec_order_len(data->grp->group);
252*a1157835SDaniel Fojt 
253*a1157835SDaniel Fojt 	data->private_value = crypto_bignum_init();
254*a1157835SDaniel Fojt 	data->my_element = crypto_ec_point_init(data->grp->group);
255*a1157835SDaniel Fojt 	data->my_scalar = crypto_bignum_init();
256*a1157835SDaniel Fojt 	mask = crypto_bignum_init();
257*a1157835SDaniel Fojt 	if (!data->private_value || !data->my_element || !data->my_scalar ||
258*a1157835SDaniel Fojt 	    !mask) {
2593ff40c12SJohn Marino 		wpa_printf(MSG_INFO, "EAP-PWD (server): scalar allocation "
2603ff40c12SJohn Marino 			   "fail");
2613ff40c12SJohn Marino 		goto fin;
2623ff40c12SJohn Marino 	}
2633ff40c12SJohn Marino 
264*a1157835SDaniel Fojt 	if (eap_pwd_get_rand_mask(data->grp, data->private_value, mask,
265*a1157835SDaniel Fojt 				  data->my_scalar) < 0)
266*a1157835SDaniel Fojt 		goto fin;
2673ff40c12SJohn Marino 
268*a1157835SDaniel Fojt 	if (crypto_ec_point_mul(data->grp->group, data->grp->pwe, mask,
269*a1157835SDaniel Fojt 				data->my_element) < 0) {
2703ff40c12SJohn Marino 		wpa_printf(MSG_INFO, "EAP-PWD (server): element allocation "
2713ff40c12SJohn Marino 			   "fail");
2723ff40c12SJohn Marino 		eap_pwd_state(data, FAILURE);
2733ff40c12SJohn Marino 		goto fin;
2743ff40c12SJohn Marino 	}
2753ff40c12SJohn Marino 
276*a1157835SDaniel Fojt 	if (crypto_ec_point_invert(data->grp->group, data->my_element) < 0) {
2773ff40c12SJohn Marino 		wpa_printf(MSG_INFO, "EAP-PWD (server): element inversion "
2783ff40c12SJohn Marino 			   "fail");
2793ff40c12SJohn Marino 		goto fin;
2803ff40c12SJohn Marino 	}
2813ff40c12SJohn Marino 
282*a1157835SDaniel Fojt 	data->outbuf = wpabuf_alloc(2 * prime_len + order_len +
283*a1157835SDaniel Fojt 				    (data->salt ? 1 + data->salt_len : 0));
284*a1157835SDaniel Fojt 	if (data->outbuf == NULL)
2853ff40c12SJohn Marino 		goto fin;
286*a1157835SDaniel Fojt 
287*a1157835SDaniel Fojt 	/* If we're doing salted password prep, add the salt */
288*a1157835SDaniel Fojt 	if (data->salt_len) {
289*a1157835SDaniel Fojt 		wpabuf_put_u8(data->outbuf, data->salt_len);
290*a1157835SDaniel Fojt 		wpabuf_put_data(data->outbuf, data->salt, data->salt_len);
2913ff40c12SJohn Marino 	}
292*a1157835SDaniel Fojt 
293*a1157835SDaniel Fojt 	/* We send the element as (x,y) followed by the scalar */
294*a1157835SDaniel Fojt 	element = wpabuf_put(data->outbuf, 2 * prime_len);
295*a1157835SDaniel Fojt 	scalar = wpabuf_put(data->outbuf, order_len);
296*a1157835SDaniel Fojt 	crypto_bignum_to_bin(data->my_scalar, scalar, order_len, order_len);
297*a1157835SDaniel Fojt 	if (crypto_ec_point_to_bin(data->grp->group, data->my_element, element,
298*a1157835SDaniel Fojt 				   element + prime_len) < 0) {
2993ff40c12SJohn Marino 		wpa_printf(MSG_INFO, "EAP-PWD (server): point assignment "
3003ff40c12SJohn Marino 			   "fail");
3013ff40c12SJohn Marino 		goto fin;
3023ff40c12SJohn Marino 	}
3033ff40c12SJohn Marino 
3043ff40c12SJohn Marino fin:
305*a1157835SDaniel Fojt 	crypto_bignum_deinit(mask, 1);
3063ff40c12SJohn Marino 	if (data->outbuf == NULL)
3073ff40c12SJohn Marino 		eap_pwd_state(data, FAILURE);
3083ff40c12SJohn Marino }
3093ff40c12SJohn Marino 
3103ff40c12SJohn Marino 
eap_pwd_build_confirm_req(struct eap_sm * sm,struct eap_pwd_data * data,u8 id)3113ff40c12SJohn Marino static void eap_pwd_build_confirm_req(struct eap_sm *sm,
3123ff40c12SJohn Marino 				      struct eap_pwd_data *data, u8 id)
3133ff40c12SJohn Marino {
314*a1157835SDaniel Fojt 	struct crypto_hash *hash = NULL;
3153ff40c12SJohn Marino 	u8 conf[SHA256_MAC_LEN], *cruft = NULL, *ptr;
3163ff40c12SJohn Marino 	u16 grp;
317*a1157835SDaniel Fojt 	size_t prime_len, order_len;
3183ff40c12SJohn Marino 
3193ff40c12SJohn Marino 	wpa_printf(MSG_DEBUG, "EAP-pwd: Confirm/Request");
3203ff40c12SJohn Marino 	/*
3213ff40c12SJohn Marino 	 * if we're fragmenting then we already have an confirm request, just
3223ff40c12SJohn Marino 	 * return
3233ff40c12SJohn Marino 	 */
3243ff40c12SJohn Marino 	if (data->out_frag_pos)
3253ff40c12SJohn Marino 		return;
3263ff40c12SJohn Marino 
327*a1157835SDaniel Fojt 	prime_len = crypto_ec_prime_len(data->grp->group);
328*a1157835SDaniel Fojt 	order_len = crypto_ec_order_len(data->grp->group);
329*a1157835SDaniel Fojt 
3303ff40c12SJohn Marino 	/* Each component of the cruft will be at most as big as the prime */
331*a1157835SDaniel Fojt 	cruft = os_malloc(prime_len * 2);
332*a1157835SDaniel Fojt 	if (!cruft) {
3333ff40c12SJohn Marino 		wpa_printf(MSG_INFO, "EAP-PWD (server): debug allocation "
3343ff40c12SJohn Marino 			   "fail");
3353ff40c12SJohn Marino 		goto fin;
3363ff40c12SJohn Marino 	}
3373ff40c12SJohn Marino 
3383ff40c12SJohn Marino 	/*
3393ff40c12SJohn Marino 	 * commit is H(k | server_element | server_scalar | peer_element |
3403ff40c12SJohn Marino 	 *	       peer_scalar | ciphersuite)
3413ff40c12SJohn Marino 	 */
3423ff40c12SJohn Marino 	hash = eap_pwd_h_init();
3433ff40c12SJohn Marino 	if (hash == NULL)
3443ff40c12SJohn Marino 		goto fin;
3453ff40c12SJohn Marino 
3463ff40c12SJohn Marino 	/*
3473ff40c12SJohn Marino 	 * Zero the memory each time because this is mod prime math and some
3483ff40c12SJohn Marino 	 * value may start with a few zeros and the previous one did not.
3493ff40c12SJohn Marino 	 *
3503ff40c12SJohn Marino 	 * First is k
3513ff40c12SJohn Marino 	 */
352*a1157835SDaniel Fojt 	crypto_bignum_to_bin(data->k, cruft, prime_len, prime_len);
353*a1157835SDaniel Fojt 	eap_pwd_h_update(hash, cruft, prime_len);
3543ff40c12SJohn Marino 
3553ff40c12SJohn Marino 	/* server element: x, y */
356*a1157835SDaniel Fojt 	if (crypto_ec_point_to_bin(data->grp->group, data->my_element, cruft,
357*a1157835SDaniel Fojt 				   cruft + prime_len) < 0) {
3583ff40c12SJohn Marino 		wpa_printf(MSG_INFO, "EAP-PWD (server): confirm point "
3593ff40c12SJohn Marino 			   "assignment fail");
3603ff40c12SJohn Marino 		goto fin;
3613ff40c12SJohn Marino 	}
362*a1157835SDaniel Fojt 	eap_pwd_h_update(hash, cruft, prime_len * 2);
3633ff40c12SJohn Marino 
3643ff40c12SJohn Marino 	/* server scalar */
365*a1157835SDaniel Fojt 	crypto_bignum_to_bin(data->my_scalar, cruft, order_len, order_len);
366*a1157835SDaniel Fojt 	eap_pwd_h_update(hash, cruft, order_len);
3673ff40c12SJohn Marino 
3683ff40c12SJohn Marino 	/* peer element: x, y */
369*a1157835SDaniel Fojt 	if (crypto_ec_point_to_bin(data->grp->group, data->peer_element, cruft,
370*a1157835SDaniel Fojt 				   cruft + prime_len) < 0) {
3713ff40c12SJohn Marino 		wpa_printf(MSG_INFO, "EAP-PWD (server): confirm point "
3723ff40c12SJohn Marino 			   "assignment fail");
3733ff40c12SJohn Marino 		goto fin;
3743ff40c12SJohn Marino 	}
375*a1157835SDaniel Fojt 	eap_pwd_h_update(hash, cruft, prime_len * 2);
3763ff40c12SJohn Marino 
3773ff40c12SJohn Marino 	/* peer scalar */
378*a1157835SDaniel Fojt 	crypto_bignum_to_bin(data->peer_scalar, cruft, order_len, order_len);
379*a1157835SDaniel Fojt 	eap_pwd_h_update(hash, cruft, order_len);
3803ff40c12SJohn Marino 
3813ff40c12SJohn Marino 	/* ciphersuite */
3823ff40c12SJohn Marino 	grp = htons(data->group_num);
383*a1157835SDaniel Fojt 	os_memset(cruft, 0, prime_len);
3843ff40c12SJohn Marino 	ptr = cruft;
3853ff40c12SJohn Marino 	os_memcpy(ptr, &grp, sizeof(u16));
3863ff40c12SJohn Marino 	ptr += sizeof(u16);
3873ff40c12SJohn Marino 	*ptr = EAP_PWD_DEFAULT_RAND_FUNC;
3883ff40c12SJohn Marino 	ptr += sizeof(u8);
3893ff40c12SJohn Marino 	*ptr = EAP_PWD_DEFAULT_PRF;
3903ff40c12SJohn Marino 	ptr += sizeof(u8);
3913ff40c12SJohn Marino 	eap_pwd_h_update(hash, cruft, ptr - cruft);
3923ff40c12SJohn Marino 
3933ff40c12SJohn Marino 	/* all done with the random function */
3943ff40c12SJohn Marino 	eap_pwd_h_final(hash, conf);
395*a1157835SDaniel Fojt 	hash = NULL;
3963ff40c12SJohn Marino 	os_memcpy(data->my_confirm, conf, SHA256_MAC_LEN);
3973ff40c12SJohn Marino 
3983ff40c12SJohn Marino 	data->outbuf = wpabuf_alloc(SHA256_MAC_LEN);
3993ff40c12SJohn Marino 	if (data->outbuf == NULL)
4003ff40c12SJohn Marino 		goto fin;
4013ff40c12SJohn Marino 
4023ff40c12SJohn Marino 	wpabuf_put_data(data->outbuf, conf, SHA256_MAC_LEN);
4033ff40c12SJohn Marino 
4043ff40c12SJohn Marino fin:
405*a1157835SDaniel Fojt 	bin_clear_free(cruft, prime_len * 2);
4063ff40c12SJohn Marino 	if (data->outbuf == NULL)
4073ff40c12SJohn Marino 		eap_pwd_state(data, FAILURE);
408*a1157835SDaniel Fojt 	eap_pwd_h_final(hash, NULL);
4093ff40c12SJohn Marino }
4103ff40c12SJohn Marino 
4113ff40c12SJohn Marino 
4123ff40c12SJohn Marino static struct wpabuf *
eap_pwd_build_req(struct eap_sm * sm,void * priv,u8 id)4133ff40c12SJohn Marino eap_pwd_build_req(struct eap_sm *sm, void *priv, u8 id)
4143ff40c12SJohn Marino {
4153ff40c12SJohn Marino 	struct eap_pwd_data *data = priv;
4163ff40c12SJohn Marino 	struct wpabuf *req;
4173ff40c12SJohn Marino 	u8 lm_exch;
4183ff40c12SJohn Marino 	const u8 *buf;
4193ff40c12SJohn Marino 	u16 totlen = 0;
4203ff40c12SJohn Marino 	size_t len;
4213ff40c12SJohn Marino 
4223ff40c12SJohn Marino 	/*
4233ff40c12SJohn Marino 	 * if we're buffering response fragments then just ACK
4243ff40c12SJohn Marino 	 */
4253ff40c12SJohn Marino 	if (data->in_frag_pos) {
4263ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "EAP-pwd: ACKing a fragment!!");
4273ff40c12SJohn Marino 		req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PWD,
4283ff40c12SJohn Marino 				    EAP_PWD_HDR_SIZE, EAP_CODE_REQUEST, id);
4293ff40c12SJohn Marino 		if (req == NULL) {
4303ff40c12SJohn Marino 			eap_pwd_state(data, FAILURE);
4313ff40c12SJohn Marino 			return NULL;
4323ff40c12SJohn Marino 		}
4333ff40c12SJohn Marino 		switch (data->state) {
4343ff40c12SJohn Marino 		case PWD_ID_Req:
4353ff40c12SJohn Marino 			wpabuf_put_u8(req, EAP_PWD_OPCODE_ID_EXCH);
4363ff40c12SJohn Marino 			break;
4373ff40c12SJohn Marino 		case PWD_Commit_Req:
4383ff40c12SJohn Marino 			wpabuf_put_u8(req, EAP_PWD_OPCODE_COMMIT_EXCH);
4393ff40c12SJohn Marino 			break;
4403ff40c12SJohn Marino 		case PWD_Confirm_Req:
4413ff40c12SJohn Marino 			wpabuf_put_u8(req, EAP_PWD_OPCODE_CONFIRM_EXCH);
4423ff40c12SJohn Marino 			break;
4433ff40c12SJohn Marino 		default:
4443ff40c12SJohn Marino 			eap_pwd_state(data, FAILURE);   /* just to be sure */
4453ff40c12SJohn Marino 			wpabuf_free(req);
4463ff40c12SJohn Marino 			return NULL;
4473ff40c12SJohn Marino 		}
4483ff40c12SJohn Marino 		return req;
4493ff40c12SJohn Marino 	}
4503ff40c12SJohn Marino 
4513ff40c12SJohn Marino 	/*
4523ff40c12SJohn Marino 	 * build the data portion of a request
4533ff40c12SJohn Marino 	 */
4543ff40c12SJohn Marino 	switch (data->state) {
4553ff40c12SJohn Marino 	case PWD_ID_Req:
4563ff40c12SJohn Marino 		eap_pwd_build_id_req(sm, data, id);
4573ff40c12SJohn Marino 		lm_exch = EAP_PWD_OPCODE_ID_EXCH;
4583ff40c12SJohn Marino 		break;
4593ff40c12SJohn Marino 	case PWD_Commit_Req:
4603ff40c12SJohn Marino 		eap_pwd_build_commit_req(sm, data, id);
4613ff40c12SJohn Marino 		lm_exch = EAP_PWD_OPCODE_COMMIT_EXCH;
4623ff40c12SJohn Marino 		break;
4633ff40c12SJohn Marino 	case PWD_Confirm_Req:
4643ff40c12SJohn Marino 		eap_pwd_build_confirm_req(sm, data, id);
4653ff40c12SJohn Marino 		lm_exch = EAP_PWD_OPCODE_CONFIRM_EXCH;
4663ff40c12SJohn Marino 		break;
4673ff40c12SJohn Marino 	default:
4683ff40c12SJohn Marino 		wpa_printf(MSG_INFO, "EAP-pwd: Unknown state %d in build_req",
4693ff40c12SJohn Marino 			   data->state);
4703ff40c12SJohn Marino 		eap_pwd_state(data, FAILURE);
4713ff40c12SJohn Marino 		lm_exch = 0;    /* hush now, sweet compiler */
4723ff40c12SJohn Marino 		break;
4733ff40c12SJohn Marino 	}
4743ff40c12SJohn Marino 
4753ff40c12SJohn Marino 	if (data->state == FAILURE)
4763ff40c12SJohn Marino 		return NULL;
4773ff40c12SJohn Marino 
4783ff40c12SJohn Marino 	/*
4793ff40c12SJohn Marino 	 * determine whether that data needs to be fragmented
4803ff40c12SJohn Marino 	 */
4813ff40c12SJohn Marino 	len = wpabuf_len(data->outbuf) - data->out_frag_pos;
4823ff40c12SJohn Marino 	if ((len + EAP_PWD_HDR_SIZE) > data->mtu) {
4833ff40c12SJohn Marino 		len = data->mtu - EAP_PWD_HDR_SIZE;
4843ff40c12SJohn Marino 		EAP_PWD_SET_MORE_BIT(lm_exch);
4853ff40c12SJohn Marino 		/*
4863ff40c12SJohn Marino 		 * if this is the first fragment, need to set the M bit
4873ff40c12SJohn Marino 		 * and add the total length to the eap_pwd_hdr
4883ff40c12SJohn Marino 		 */
4893ff40c12SJohn Marino 		if (data->out_frag_pos == 0) {
4903ff40c12SJohn Marino 			EAP_PWD_SET_LENGTH_BIT(lm_exch);
4913ff40c12SJohn Marino 			totlen = wpabuf_len(data->outbuf) +
4923ff40c12SJohn Marino 				EAP_PWD_HDR_SIZE + sizeof(u16);
4933ff40c12SJohn Marino 			len -= sizeof(u16);
4943ff40c12SJohn Marino 			wpa_printf(MSG_DEBUG, "EAP-pwd: Fragmenting output, "
4953ff40c12SJohn Marino 				   "total length = %d", totlen);
4963ff40c12SJohn Marino 		}
4973ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "EAP-pwd: Send a %d byte fragment",
4983ff40c12SJohn Marino 			   (int) len);
4993ff40c12SJohn Marino 	}
5003ff40c12SJohn Marino 
5013ff40c12SJohn Marino 	/*
5023ff40c12SJohn Marino 	 * alloc an eap request and populate it with the data
5033ff40c12SJohn Marino 	 */
5043ff40c12SJohn Marino 	req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PWD,
5053ff40c12SJohn Marino 			    EAP_PWD_HDR_SIZE + len +
5063ff40c12SJohn Marino 			    (totlen ? sizeof(u16) : 0),
5073ff40c12SJohn Marino 			    EAP_CODE_REQUEST, id);
5083ff40c12SJohn Marino 	if (req == NULL) {
5093ff40c12SJohn Marino 		eap_pwd_state(data, FAILURE);
5103ff40c12SJohn Marino 		return NULL;
5113ff40c12SJohn Marino 	}
5123ff40c12SJohn Marino 
5133ff40c12SJohn Marino 	wpabuf_put_u8(req, lm_exch);
5143ff40c12SJohn Marino 	if (EAP_PWD_GET_LENGTH_BIT(lm_exch))
5153ff40c12SJohn Marino 		wpabuf_put_be16(req, totlen);
5163ff40c12SJohn Marino 
5173ff40c12SJohn Marino 	buf = wpabuf_head_u8(data->outbuf);
5183ff40c12SJohn Marino 	wpabuf_put_data(req, buf + data->out_frag_pos, len);
5193ff40c12SJohn Marino 	data->out_frag_pos += len;
5203ff40c12SJohn Marino 	/*
5213ff40c12SJohn Marino 	 * either not fragged or last fragment, either way free up the data
5223ff40c12SJohn Marino 	 */
5233ff40c12SJohn Marino 	if (data->out_frag_pos >= wpabuf_len(data->outbuf)) {
5243ff40c12SJohn Marino 		wpabuf_free(data->outbuf);
525*a1157835SDaniel Fojt 		data->outbuf = NULL;
5263ff40c12SJohn Marino 		data->out_frag_pos = 0;
5273ff40c12SJohn Marino 	}
5283ff40c12SJohn Marino 
5293ff40c12SJohn Marino 	return req;
5303ff40c12SJohn Marino }
5313ff40c12SJohn Marino 
5323ff40c12SJohn Marino 
eap_pwd_check(struct eap_sm * sm,void * priv,struct wpabuf * respData)5333ff40c12SJohn Marino static Boolean eap_pwd_check(struct eap_sm *sm, void *priv,
5343ff40c12SJohn Marino 			     struct wpabuf *respData)
5353ff40c12SJohn Marino {
5363ff40c12SJohn Marino 	struct eap_pwd_data *data = priv;
5373ff40c12SJohn Marino 	const u8 *pos;
5383ff40c12SJohn Marino 	size_t len;
5393ff40c12SJohn Marino 
5403ff40c12SJohn Marino 	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PWD, respData, &len);
5413ff40c12SJohn Marino 	if (pos == NULL || len < 1) {
5423ff40c12SJohn Marino 		wpa_printf(MSG_INFO, "EAP-pwd: Invalid frame");
5433ff40c12SJohn Marino 		return TRUE;
5443ff40c12SJohn Marino 	}
5453ff40c12SJohn Marino 
5463ff40c12SJohn Marino 	wpa_printf(MSG_DEBUG, "EAP-pwd: Received frame: exch = %d, len = %d",
5473ff40c12SJohn Marino 		   EAP_PWD_GET_EXCHANGE(*pos), (int) len);
5483ff40c12SJohn Marino 
5493ff40c12SJohn Marino 	if (data->state == PWD_ID_Req &&
5503ff40c12SJohn Marino 	    ((EAP_PWD_GET_EXCHANGE(*pos)) == EAP_PWD_OPCODE_ID_EXCH))
5513ff40c12SJohn Marino 		return FALSE;
5523ff40c12SJohn Marino 
5533ff40c12SJohn Marino 	if (data->state == PWD_Commit_Req &&
5543ff40c12SJohn Marino 	    ((EAP_PWD_GET_EXCHANGE(*pos)) == EAP_PWD_OPCODE_COMMIT_EXCH))
5553ff40c12SJohn Marino 		return FALSE;
5563ff40c12SJohn Marino 
5573ff40c12SJohn Marino 	if (data->state == PWD_Confirm_Req &&
5583ff40c12SJohn Marino 	    ((EAP_PWD_GET_EXCHANGE(*pos)) == EAP_PWD_OPCODE_CONFIRM_EXCH))
5593ff40c12SJohn Marino 		return FALSE;
5603ff40c12SJohn Marino 
5613ff40c12SJohn Marino 	wpa_printf(MSG_INFO, "EAP-pwd: Unexpected opcode=%d in state=%d",
5623ff40c12SJohn Marino 		   *pos, data->state);
5633ff40c12SJohn Marino 
5643ff40c12SJohn Marino 	return TRUE;
5653ff40c12SJohn Marino }
5663ff40c12SJohn Marino 
5673ff40c12SJohn Marino 
eap_pwd_process_id_resp(struct eap_sm * sm,struct eap_pwd_data * data,const u8 * payload,size_t payload_len)5683ff40c12SJohn Marino static void eap_pwd_process_id_resp(struct eap_sm *sm,
5693ff40c12SJohn Marino 				    struct eap_pwd_data *data,
5703ff40c12SJohn Marino 				    const u8 *payload, size_t payload_len)
5713ff40c12SJohn Marino {
5723ff40c12SJohn Marino 	struct eap_pwd_id *id;
573*a1157835SDaniel Fojt 	const u8 *password;
574*a1157835SDaniel Fojt 	size_t password_len;
575*a1157835SDaniel Fojt 	u8 pwhashhash[16];
576*a1157835SDaniel Fojt 	int res;
5773ff40c12SJohn Marino 
5783ff40c12SJohn Marino 	if (payload_len < sizeof(struct eap_pwd_id)) {
5793ff40c12SJohn Marino 		wpa_printf(MSG_INFO, "EAP-pwd: Invalid ID response");
5803ff40c12SJohn Marino 		return;
5813ff40c12SJohn Marino 	}
5823ff40c12SJohn Marino 
5833ff40c12SJohn Marino 	id = (struct eap_pwd_id *) payload;
5843ff40c12SJohn Marino 	if ((data->group_num != be_to_host16(id->group_num)) ||
5853ff40c12SJohn Marino 	    (id->random_function != EAP_PWD_DEFAULT_RAND_FUNC) ||
5863ff40c12SJohn Marino 	    (os_memcmp(id->token, (u8 *)&data->token, sizeof(data->token))) ||
587*a1157835SDaniel Fojt 	    (id->prf != EAP_PWD_DEFAULT_PRF) ||
588*a1157835SDaniel Fojt 	    (id->prep != data->password_prep)) {
5893ff40c12SJohn Marino 		wpa_printf(MSG_INFO, "EAP-pwd: peer changed parameters");
5903ff40c12SJohn Marino 		eap_pwd_state(data, FAILURE);
5913ff40c12SJohn Marino 		return;
5923ff40c12SJohn Marino 	}
593*a1157835SDaniel Fojt 	if (data->id_peer || data->grp) {
594*a1157835SDaniel Fojt 		wpa_printf(MSG_INFO, "EAP-pwd: data was already allocated");
595*a1157835SDaniel Fojt 		return;
596*a1157835SDaniel Fojt 	}
5973ff40c12SJohn Marino 	data->id_peer = os_malloc(payload_len - sizeof(struct eap_pwd_id));
5983ff40c12SJohn Marino 	if (data->id_peer == NULL) {
5993ff40c12SJohn Marino 		wpa_printf(MSG_INFO, "EAP-PWD: memory allocation id fail");
6003ff40c12SJohn Marino 		return;
6013ff40c12SJohn Marino 	}
6023ff40c12SJohn Marino 	data->id_peer_len = payload_len - sizeof(struct eap_pwd_id);
6033ff40c12SJohn Marino 	os_memcpy(data->id_peer, id->identity, data->id_peer_len);
6043ff40c12SJohn Marino 	wpa_hexdump_ascii(MSG_DEBUG, "EAP-PWD (server): peer sent id of",
6053ff40c12SJohn Marino 			  data->id_peer, data->id_peer_len);
6063ff40c12SJohn Marino 
607*a1157835SDaniel Fojt 	data->grp = get_eap_pwd_group(data->group_num);
608*a1157835SDaniel Fojt 	if (data->grp == NULL) {
6093ff40c12SJohn Marino 		wpa_printf(MSG_INFO, "EAP-PWD: failed to allocate memory for "
6103ff40c12SJohn Marino 			   "group");
6113ff40c12SJohn Marino 		return;
6123ff40c12SJohn Marino 	}
613*a1157835SDaniel Fojt 
614*a1157835SDaniel Fojt 	/*
615*a1157835SDaniel Fojt 	 * If it's PREP_MS then hash the password again, otherwise regardless
616*a1157835SDaniel Fojt 	 * of the prep the client is doing, the password we have is the one to
617*a1157835SDaniel Fojt 	 * use to generate the password element.
618*a1157835SDaniel Fojt 	 */
619*a1157835SDaniel Fojt 	if (data->password_prep == EAP_PWD_PREP_MS) {
620*a1157835SDaniel Fojt 		res = hash_nt_password_hash(data->password, pwhashhash);
621*a1157835SDaniel Fojt 		if (res)
622*a1157835SDaniel Fojt 			return;
623*a1157835SDaniel Fojt 		password = pwhashhash;
624*a1157835SDaniel Fojt 		password_len = sizeof(pwhashhash);
625*a1157835SDaniel Fojt 	} else {
626*a1157835SDaniel Fojt 		password = data->password;
627*a1157835SDaniel Fojt 		password_len = data->password_len;
628*a1157835SDaniel Fojt 	}
629*a1157835SDaniel Fojt 
630*a1157835SDaniel Fojt 	res = compute_password_element(data->grp, data->group_num,
631*a1157835SDaniel Fojt 				       password, password_len,
6323ff40c12SJohn Marino 				       data->id_server, data->id_server_len,
6333ff40c12SJohn Marino 				       data->id_peer, data->id_peer_len,
634*a1157835SDaniel Fojt 				       (u8 *) &data->token);
635*a1157835SDaniel Fojt 	forced_memzero(pwhashhash, sizeof(pwhashhash));
636*a1157835SDaniel Fojt 	if (res) {
6373ff40c12SJohn Marino 		wpa_printf(MSG_INFO, "EAP-PWD (server): unable to compute "
6383ff40c12SJohn Marino 			   "PWE");
6393ff40c12SJohn Marino 		return;
6403ff40c12SJohn Marino 	}
6413ff40c12SJohn Marino 	wpa_printf(MSG_DEBUG, "EAP-PWD (server): computed %d bit PWE...",
642*a1157835SDaniel Fojt 		   (int) crypto_ec_prime_len_bits(data->grp->group));
6433ff40c12SJohn Marino 
6443ff40c12SJohn Marino 	eap_pwd_state(data, PWD_Commit_Req);
6453ff40c12SJohn Marino }
6463ff40c12SJohn Marino 
6473ff40c12SJohn Marino 
6483ff40c12SJohn Marino static void
eap_pwd_process_commit_resp(struct eap_sm * sm,struct eap_pwd_data * data,const u8 * payload,size_t payload_len)6493ff40c12SJohn Marino eap_pwd_process_commit_resp(struct eap_sm *sm, struct eap_pwd_data *data,
6503ff40c12SJohn Marino 			    const u8 *payload, size_t payload_len)
6513ff40c12SJohn Marino {
652*a1157835SDaniel Fojt 	const u8 *ptr;
653*a1157835SDaniel Fojt 	struct crypto_ec_point *K = NULL;
6543ff40c12SJohn Marino 	int res = 0;
655*a1157835SDaniel Fojt 	size_t prime_len, order_len;
6563ff40c12SJohn Marino 
6573ff40c12SJohn Marino 	wpa_printf(MSG_DEBUG, "EAP-pwd: Received commit response");
6583ff40c12SJohn Marino 
659*a1157835SDaniel Fojt 	prime_len = crypto_ec_prime_len(data->grp->group);
660*a1157835SDaniel Fojt 	order_len = crypto_ec_order_len(data->grp->group);
661*a1157835SDaniel Fojt 
662*a1157835SDaniel Fojt 	if (payload_len != 2 * prime_len + order_len) {
663*a1157835SDaniel Fojt 		wpa_printf(MSG_INFO,
664*a1157835SDaniel Fojt 			   "EAP-pwd: Unexpected Commit payload length %u (expected %u)",
665*a1157835SDaniel Fojt 			   (unsigned int) payload_len,
666*a1157835SDaniel Fojt 			   (unsigned int) (2 * prime_len + order_len));
667*a1157835SDaniel Fojt 		goto fin;
668*a1157835SDaniel Fojt 	}
669*a1157835SDaniel Fojt 
670*a1157835SDaniel Fojt 	data->k = crypto_bignum_init();
671*a1157835SDaniel Fojt 	K = crypto_ec_point_init(data->grp->group);
672*a1157835SDaniel Fojt 	if (!data->k || !K) {
6733ff40c12SJohn Marino 		wpa_printf(MSG_INFO, "EAP-PWD (server): peer data allocation "
6743ff40c12SJohn Marino 			   "fail");
6753ff40c12SJohn Marino 		goto fin;
6763ff40c12SJohn Marino 	}
6773ff40c12SJohn Marino 
6783ff40c12SJohn Marino 	/* element, x then y, followed by scalar */
679*a1157835SDaniel Fojt 	ptr = payload;
680*a1157835SDaniel Fojt 	data->peer_element = eap_pwd_get_element(data->grp, ptr);
681*a1157835SDaniel Fojt 	if (!data->peer_element) {
6823ff40c12SJohn Marino 		wpa_printf(MSG_INFO, "EAP-PWD (server): setting peer element "
6833ff40c12SJohn Marino 			   "fail");
6843ff40c12SJohn Marino 		goto fin;
6853ff40c12SJohn Marino 	}
686*a1157835SDaniel Fojt 	ptr += prime_len * 2;
687*a1157835SDaniel Fojt 	data->peer_scalar = eap_pwd_get_scalar(data->grp, ptr);
688*a1157835SDaniel Fojt 	if (!data->peer_scalar) {
689*a1157835SDaniel Fojt 		wpa_printf(MSG_INFO, "EAP-PWD (server): peer data allocation "
690*a1157835SDaniel Fojt 			   "fail");
691*a1157835SDaniel Fojt 		goto fin;
692*a1157835SDaniel Fojt 	}
6933ff40c12SJohn Marino 
694*a1157835SDaniel Fojt 	/* detect reflection attacks */
695*a1157835SDaniel Fojt 	if (crypto_bignum_cmp(data->my_scalar, data->peer_scalar) == 0 ||
696*a1157835SDaniel Fojt 	    crypto_ec_point_cmp(data->grp->group, data->my_element,
697*a1157835SDaniel Fojt 				data->peer_element) == 0) {
698*a1157835SDaniel Fojt 		wpa_printf(MSG_INFO,
699*a1157835SDaniel Fojt 			   "EAP-PWD (server): detected reflection attack!");
7003ff40c12SJohn Marino 		goto fin;
7013ff40c12SJohn Marino 	}
7023ff40c12SJohn Marino 
7033ff40c12SJohn Marino 	/* compute the shared key, k */
704*a1157835SDaniel Fojt 	if ((crypto_ec_point_mul(data->grp->group, data->grp->pwe,
705*a1157835SDaniel Fojt 				 data->peer_scalar, K) < 0) ||
706*a1157835SDaniel Fojt 	    (crypto_ec_point_add(data->grp->group, K, data->peer_element,
707*a1157835SDaniel Fojt 				 K) < 0) ||
708*a1157835SDaniel Fojt 	    (crypto_ec_point_mul(data->grp->group, K, data->private_value,
709*a1157835SDaniel Fojt 				 K) < 0)) {
7103ff40c12SJohn Marino 		wpa_printf(MSG_INFO, "EAP-PWD (server): computing shared key "
7113ff40c12SJohn Marino 			   "fail");
7123ff40c12SJohn Marino 		goto fin;
7133ff40c12SJohn Marino 	}
7143ff40c12SJohn Marino 
7153ff40c12SJohn Marino 	/*
716*a1157835SDaniel Fojt 	 * This check is strictly speaking just for the case where
7173ff40c12SJohn Marino 	 * co-factor > 1 but it was suggested that even though this is probably
7183ff40c12SJohn Marino 	 * never going to happen it is a simple and safe check "just to be
7193ff40c12SJohn Marino 	 * sure" so let's be safe.
7203ff40c12SJohn Marino 	 */
721*a1157835SDaniel Fojt 	if (crypto_ec_point_is_at_infinity(data->grp->group, K)) {
7223ff40c12SJohn Marino 		wpa_printf(MSG_INFO, "EAP-PWD (server): shared key point is "
7233ff40c12SJohn Marino 			   "at infinity");
7243ff40c12SJohn Marino 		goto fin;
7253ff40c12SJohn Marino 	}
726*a1157835SDaniel Fojt 	if (crypto_ec_point_x(data->grp->group, K, data->k)) {
7273ff40c12SJohn Marino 		wpa_printf(MSG_INFO, "EAP-PWD (server): unable to extract "
7283ff40c12SJohn Marino 			   "shared secret from secret point");
7293ff40c12SJohn Marino 		goto fin;
7303ff40c12SJohn Marino 	}
7313ff40c12SJohn Marino 	res = 1;
7323ff40c12SJohn Marino 
7333ff40c12SJohn Marino fin:
734*a1157835SDaniel Fojt 	crypto_ec_point_deinit(K, 1);
7353ff40c12SJohn Marino 
7363ff40c12SJohn Marino 	if (res)
7373ff40c12SJohn Marino 		eap_pwd_state(data, PWD_Confirm_Req);
7383ff40c12SJohn Marino 	else
7393ff40c12SJohn Marino 		eap_pwd_state(data, FAILURE);
7403ff40c12SJohn Marino }
7413ff40c12SJohn Marino 
7423ff40c12SJohn Marino 
7433ff40c12SJohn Marino static void
eap_pwd_process_confirm_resp(struct eap_sm * sm,struct eap_pwd_data * data,const u8 * payload,size_t payload_len)7443ff40c12SJohn Marino eap_pwd_process_confirm_resp(struct eap_sm *sm, struct eap_pwd_data *data,
7453ff40c12SJohn Marino 			     const u8 *payload, size_t payload_len)
7463ff40c12SJohn Marino {
747*a1157835SDaniel Fojt 	struct crypto_hash *hash = NULL;
7483ff40c12SJohn Marino 	u32 cs;
7493ff40c12SJohn Marino 	u16 grp;
7503ff40c12SJohn Marino 	u8 conf[SHA256_MAC_LEN], *cruft = NULL, *ptr;
751*a1157835SDaniel Fojt 	size_t prime_len, order_len;
752*a1157835SDaniel Fojt 
753*a1157835SDaniel Fojt 	prime_len = crypto_ec_prime_len(data->grp->group);
754*a1157835SDaniel Fojt 	order_len = crypto_ec_order_len(data->grp->group);
755*a1157835SDaniel Fojt 
756*a1157835SDaniel Fojt 	if (payload_len != SHA256_MAC_LEN) {
757*a1157835SDaniel Fojt 		wpa_printf(MSG_INFO,
758*a1157835SDaniel Fojt 			   "EAP-pwd: Unexpected Confirm payload length %u (expected %u)",
759*a1157835SDaniel Fojt 			   (unsigned int) payload_len, SHA256_MAC_LEN);
760*a1157835SDaniel Fojt 		goto fin;
761*a1157835SDaniel Fojt 	}
7623ff40c12SJohn Marino 
7633ff40c12SJohn Marino 	/* build up the ciphersuite: group | random_function | prf */
7643ff40c12SJohn Marino 	grp = htons(data->group_num);
7653ff40c12SJohn Marino 	ptr = (u8 *) &cs;
7663ff40c12SJohn Marino 	os_memcpy(ptr, &grp, sizeof(u16));
7673ff40c12SJohn Marino 	ptr += sizeof(u16);
7683ff40c12SJohn Marino 	*ptr = EAP_PWD_DEFAULT_RAND_FUNC;
7693ff40c12SJohn Marino 	ptr += sizeof(u8);
7703ff40c12SJohn Marino 	*ptr = EAP_PWD_DEFAULT_PRF;
7713ff40c12SJohn Marino 
7723ff40c12SJohn Marino 	/* each component of the cruft will be at most as big as the prime */
773*a1157835SDaniel Fojt 	cruft = os_malloc(prime_len * 2);
774*a1157835SDaniel Fojt 	if (!cruft) {
7753ff40c12SJohn Marino 		wpa_printf(MSG_INFO, "EAP-PWD (peer): allocation fail");
7763ff40c12SJohn Marino 		goto fin;
7773ff40c12SJohn Marino 	}
7783ff40c12SJohn Marino 
7793ff40c12SJohn Marino 	/*
7803ff40c12SJohn Marino 	 * commit is H(k | peer_element | peer_scalar | server_element |
7813ff40c12SJohn Marino 	 *	       server_scalar | ciphersuite)
7823ff40c12SJohn Marino 	 */
7833ff40c12SJohn Marino 	hash = eap_pwd_h_init();
7843ff40c12SJohn Marino 	if (hash == NULL)
7853ff40c12SJohn Marino 		goto fin;
7863ff40c12SJohn Marino 
7873ff40c12SJohn Marino 	/* k */
788*a1157835SDaniel Fojt 	crypto_bignum_to_bin(data->k, cruft, prime_len, prime_len);
789*a1157835SDaniel Fojt 	eap_pwd_h_update(hash, cruft, prime_len);
7903ff40c12SJohn Marino 
7913ff40c12SJohn Marino 	/* peer element: x, y */
792*a1157835SDaniel Fojt 	if (crypto_ec_point_to_bin(data->grp->group, data->peer_element, cruft,
793*a1157835SDaniel Fojt 				   cruft + prime_len) < 0) {
7943ff40c12SJohn Marino 		wpa_printf(MSG_INFO, "EAP-PWD (server): confirm point "
7953ff40c12SJohn Marino 			   "assignment fail");
7963ff40c12SJohn Marino 		goto fin;
7973ff40c12SJohn Marino 	}
798*a1157835SDaniel Fojt 	eap_pwd_h_update(hash, cruft, prime_len * 2);
7993ff40c12SJohn Marino 
8003ff40c12SJohn Marino 	/* peer scalar */
801*a1157835SDaniel Fojt 	crypto_bignum_to_bin(data->peer_scalar, cruft, order_len, order_len);
802*a1157835SDaniel Fojt 	eap_pwd_h_update(hash, cruft, order_len);
8033ff40c12SJohn Marino 
8043ff40c12SJohn Marino 	/* server element: x, y */
805*a1157835SDaniel Fojt 	if (crypto_ec_point_to_bin(data->grp->group, data->my_element, cruft,
806*a1157835SDaniel Fojt 				   cruft + prime_len) < 0) {
8073ff40c12SJohn Marino 		wpa_printf(MSG_INFO, "EAP-PWD (server): confirm point "
8083ff40c12SJohn Marino 			   "assignment fail");
8093ff40c12SJohn Marino 		goto fin;
8103ff40c12SJohn Marino 	}
811*a1157835SDaniel Fojt 	eap_pwd_h_update(hash, cruft, prime_len * 2);
8123ff40c12SJohn Marino 
8133ff40c12SJohn Marino 	/* server scalar */
814*a1157835SDaniel Fojt 	crypto_bignum_to_bin(data->my_scalar, cruft, order_len, order_len);
815*a1157835SDaniel Fojt 	eap_pwd_h_update(hash, cruft, order_len);
8163ff40c12SJohn Marino 
8173ff40c12SJohn Marino 	/* ciphersuite */
8183ff40c12SJohn Marino 	eap_pwd_h_update(hash, (u8 *) &cs, sizeof(u32));
8193ff40c12SJohn Marino 
8203ff40c12SJohn Marino 	/* all done */
8213ff40c12SJohn Marino 	eap_pwd_h_final(hash, conf);
822*a1157835SDaniel Fojt 	hash = NULL;
8233ff40c12SJohn Marino 
8243ff40c12SJohn Marino 	ptr = (u8 *) payload;
825*a1157835SDaniel Fojt 	if (os_memcmp_const(conf, ptr, SHA256_MAC_LEN)) {
8263ff40c12SJohn Marino 		wpa_printf(MSG_INFO, "EAP-PWD (server): confirm did not "
8273ff40c12SJohn Marino 			   "verify");
8283ff40c12SJohn Marino 		goto fin;
8293ff40c12SJohn Marino 	}
8303ff40c12SJohn Marino 
8313ff40c12SJohn Marino 	wpa_printf(MSG_DEBUG, "EAP-pwd (server): confirm verified");
832*a1157835SDaniel Fojt 	if (compute_keys(data->grp, data->k,
8333ff40c12SJohn Marino 			 data->peer_scalar, data->my_scalar, conf,
834*a1157835SDaniel Fojt 			 data->my_confirm, &cs, data->msk, data->emsk,
835*a1157835SDaniel Fojt 			 data->session_id) < 0)
8363ff40c12SJohn Marino 		eap_pwd_state(data, FAILURE);
8373ff40c12SJohn Marino 	else
8383ff40c12SJohn Marino 		eap_pwd_state(data, SUCCESS);
8393ff40c12SJohn Marino 
8403ff40c12SJohn Marino fin:
841*a1157835SDaniel Fojt 	bin_clear_free(cruft, prime_len * 2);
842*a1157835SDaniel Fojt 	eap_pwd_h_final(hash, NULL);
8433ff40c12SJohn Marino }
8443ff40c12SJohn Marino 
8453ff40c12SJohn Marino 
eap_pwd_process(struct eap_sm * sm,void * priv,struct wpabuf * respData)8463ff40c12SJohn Marino static void eap_pwd_process(struct eap_sm *sm, void *priv,
8473ff40c12SJohn Marino 			    struct wpabuf *respData)
8483ff40c12SJohn Marino {
8493ff40c12SJohn Marino 	struct eap_pwd_data *data = priv;
8503ff40c12SJohn Marino 	const u8 *pos;
8513ff40c12SJohn Marino 	size_t len;
8523ff40c12SJohn Marino 	u8 lm_exch;
8533ff40c12SJohn Marino 	u16 tot_len;
8543ff40c12SJohn Marino 
8553ff40c12SJohn Marino 	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PWD, respData, &len);
8563ff40c12SJohn Marino 	if ((pos == NULL) || (len < 1)) {
8573ff40c12SJohn Marino 		wpa_printf(MSG_INFO, "Bad EAP header! pos %s and len = %d",
8583ff40c12SJohn Marino 			   (pos == NULL) ? "is NULL" : "is not NULL",
8593ff40c12SJohn Marino 			   (int) len);
8603ff40c12SJohn Marino 		return;
8613ff40c12SJohn Marino 	}
8623ff40c12SJohn Marino 
8633ff40c12SJohn Marino 	lm_exch = *pos;
8643ff40c12SJohn Marino 	pos++;            /* skip over the bits and the exch */
8653ff40c12SJohn Marino 	len--;
8663ff40c12SJohn Marino 
8673ff40c12SJohn Marino 	/*
8683ff40c12SJohn Marino 	 * if we're fragmenting then this should be an ACK with no data,
8693ff40c12SJohn Marino 	 * just return and continue fragmenting in the "build" section above
8703ff40c12SJohn Marino 	 */
8713ff40c12SJohn Marino 	if (data->out_frag_pos) {
8723ff40c12SJohn Marino 		if (len > 1)
8733ff40c12SJohn Marino 			wpa_printf(MSG_INFO, "EAP-pwd: Bad response! "
8743ff40c12SJohn Marino 				   "Fragmenting but not an ACK");
8753ff40c12SJohn Marino 		else
8763ff40c12SJohn Marino 			wpa_printf(MSG_DEBUG, "EAP-pwd: received ACK from "
8773ff40c12SJohn Marino 				   "peer");
8783ff40c12SJohn Marino 		return;
8793ff40c12SJohn Marino 	}
8803ff40c12SJohn Marino 	/*
8813ff40c12SJohn Marino 	 * if we're receiving fragmented packets then we need to buffer...
8823ff40c12SJohn Marino 	 *
8833ff40c12SJohn Marino 	 * the first fragment has a total length
8843ff40c12SJohn Marino 	 */
8853ff40c12SJohn Marino 	if (EAP_PWD_GET_LENGTH_BIT(lm_exch)) {
886*a1157835SDaniel Fojt 		if (len < 2) {
887*a1157835SDaniel Fojt 			wpa_printf(MSG_DEBUG,
888*a1157835SDaniel Fojt 				   "EAP-pwd: Frame too short to contain Total-Length field");
889*a1157835SDaniel Fojt 			return;
890*a1157835SDaniel Fojt 		}
8913ff40c12SJohn Marino 		tot_len = WPA_GET_BE16(pos);
8923ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "EAP-pwd: Incoming fragments, total "
8933ff40c12SJohn Marino 			   "length = %d", tot_len);
894*a1157835SDaniel Fojt 		if (tot_len > 15000)
895*a1157835SDaniel Fojt 			return;
896*a1157835SDaniel Fojt 		if (data->inbuf) {
897*a1157835SDaniel Fojt 			wpa_printf(MSG_DEBUG,
898*a1157835SDaniel Fojt 				   "EAP-pwd: Unexpected new fragment start when previous fragment is still in use");
899*a1157835SDaniel Fojt 			return;
900*a1157835SDaniel Fojt 		}
9013ff40c12SJohn Marino 		data->inbuf = wpabuf_alloc(tot_len);
9023ff40c12SJohn Marino 		if (data->inbuf == NULL) {
9033ff40c12SJohn Marino 			wpa_printf(MSG_INFO, "EAP-pwd: Out of memory to "
9043ff40c12SJohn Marino 				   "buffer fragments!");
9053ff40c12SJohn Marino 			return;
9063ff40c12SJohn Marino 		}
907*a1157835SDaniel Fojt 		data->in_frag_pos = 0;
9083ff40c12SJohn Marino 		pos += sizeof(u16);
9093ff40c12SJohn Marino 		len -= sizeof(u16);
9103ff40c12SJohn Marino 	}
9113ff40c12SJohn Marino 	/*
9123ff40c12SJohn Marino 	 * the first and all intermediate fragments have the M bit set
9133ff40c12SJohn Marino 	 */
914*a1157835SDaniel Fojt 	if (EAP_PWD_GET_MORE_BIT(lm_exch) || data->in_frag_pos) {
915*a1157835SDaniel Fojt 		if (!data->inbuf) {
916*a1157835SDaniel Fojt 			wpa_printf(MSG_DEBUG,
917*a1157835SDaniel Fojt 				   "EAP-pwd: No buffer for reassembly");
918*a1157835SDaniel Fojt 			eap_pwd_state(data, FAILURE);
919*a1157835SDaniel Fojt 			return;
920*a1157835SDaniel Fojt 		}
9213ff40c12SJohn Marino 		if ((data->in_frag_pos + len) > wpabuf_size(data->inbuf)) {
9223ff40c12SJohn Marino 			wpa_printf(MSG_DEBUG, "EAP-pwd: Buffer overflow "
9233ff40c12SJohn Marino 				   "attack detected! (%d+%d > %d)",
9243ff40c12SJohn Marino 				   (int) data->in_frag_pos, (int) len,
9253ff40c12SJohn Marino 				   (int) wpabuf_size(data->inbuf));
9263ff40c12SJohn Marino 			eap_pwd_state(data, FAILURE);
9273ff40c12SJohn Marino 			return;
9283ff40c12SJohn Marino 		}
9293ff40c12SJohn Marino 		wpabuf_put_data(data->inbuf, pos, len);
9303ff40c12SJohn Marino 		data->in_frag_pos += len;
931*a1157835SDaniel Fojt 	}
932*a1157835SDaniel Fojt 	if (EAP_PWD_GET_MORE_BIT(lm_exch)) {
9333ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "EAP-pwd: Got a %d byte fragment",
9343ff40c12SJohn Marino 			   (int) len);
9353ff40c12SJohn Marino 		return;
9363ff40c12SJohn Marino 	}
9373ff40c12SJohn Marino 	/*
9383ff40c12SJohn Marino 	 * last fragment won't have the M bit set (but we're obviously
9393ff40c12SJohn Marino 	 * buffering fragments so that's how we know it's the last)
9403ff40c12SJohn Marino 	 */
941*a1157835SDaniel Fojt 	if (data->in_frag_pos && data->inbuf) {
9423ff40c12SJohn Marino 		pos = wpabuf_head_u8(data->inbuf);
9433ff40c12SJohn Marino 		len = data->in_frag_pos;
9443ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "EAP-pwd: Last fragment, %d bytes",
9453ff40c12SJohn Marino 			   (int) len);
9463ff40c12SJohn Marino 	}
9473ff40c12SJohn Marino 	switch (EAP_PWD_GET_EXCHANGE(lm_exch)) {
9483ff40c12SJohn Marino 	case EAP_PWD_OPCODE_ID_EXCH:
9493ff40c12SJohn Marino 		eap_pwd_process_id_resp(sm, data, pos, len);
9503ff40c12SJohn Marino 		break;
9513ff40c12SJohn Marino 	case EAP_PWD_OPCODE_COMMIT_EXCH:
9523ff40c12SJohn Marino 		eap_pwd_process_commit_resp(sm, data, pos, len);
9533ff40c12SJohn Marino 		break;
9543ff40c12SJohn Marino 	case EAP_PWD_OPCODE_CONFIRM_EXCH:
9553ff40c12SJohn Marino 		eap_pwd_process_confirm_resp(sm, data, pos, len);
9563ff40c12SJohn Marino 		break;
9573ff40c12SJohn Marino 	}
9583ff40c12SJohn Marino 	/*
9593ff40c12SJohn Marino 	 * if we had been buffering fragments, here's a great place
9603ff40c12SJohn Marino 	 * to clean up
9613ff40c12SJohn Marino 	 */
9623ff40c12SJohn Marino 	if (data->in_frag_pos) {
9633ff40c12SJohn Marino 		wpabuf_free(data->inbuf);
964*a1157835SDaniel Fojt 		data->inbuf = NULL;
9653ff40c12SJohn Marino 		data->in_frag_pos = 0;
9663ff40c12SJohn Marino 	}
9673ff40c12SJohn Marino }
9683ff40c12SJohn Marino 
9693ff40c12SJohn Marino 
eap_pwd_getkey(struct eap_sm * sm,void * priv,size_t * len)9703ff40c12SJohn Marino static u8 * eap_pwd_getkey(struct eap_sm *sm, void *priv, size_t *len)
9713ff40c12SJohn Marino {
9723ff40c12SJohn Marino 	struct eap_pwd_data *data = priv;
9733ff40c12SJohn Marino 	u8 *key;
9743ff40c12SJohn Marino 
9753ff40c12SJohn Marino 	if (data->state != SUCCESS)
9763ff40c12SJohn Marino 		return NULL;
9773ff40c12SJohn Marino 
978*a1157835SDaniel Fojt 	key = os_memdup(data->msk, EAP_MSK_LEN);
9793ff40c12SJohn Marino 	if (key == NULL)
9803ff40c12SJohn Marino 		return NULL;
9813ff40c12SJohn Marino 
9823ff40c12SJohn Marino 	*len = EAP_MSK_LEN;
9833ff40c12SJohn Marino 
9843ff40c12SJohn Marino 	return key;
9853ff40c12SJohn Marino }
9863ff40c12SJohn Marino 
9873ff40c12SJohn Marino 
eap_pwd_get_emsk(struct eap_sm * sm,void * priv,size_t * len)9883ff40c12SJohn Marino static u8 * eap_pwd_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
9893ff40c12SJohn Marino {
9903ff40c12SJohn Marino 	struct eap_pwd_data *data = priv;
9913ff40c12SJohn Marino 	u8 *key;
9923ff40c12SJohn Marino 
9933ff40c12SJohn Marino 	if (data->state != SUCCESS)
9943ff40c12SJohn Marino 		return NULL;
9953ff40c12SJohn Marino 
996*a1157835SDaniel Fojt 	key = os_memdup(data->emsk, EAP_EMSK_LEN);
9973ff40c12SJohn Marino 	if (key == NULL)
9983ff40c12SJohn Marino 		return NULL;
9993ff40c12SJohn Marino 
10003ff40c12SJohn Marino 	*len = EAP_EMSK_LEN;
10013ff40c12SJohn Marino 
10023ff40c12SJohn Marino 	return key;
10033ff40c12SJohn Marino }
10043ff40c12SJohn Marino 
10053ff40c12SJohn Marino 
eap_pwd_is_success(struct eap_sm * sm,void * priv)10063ff40c12SJohn Marino static Boolean eap_pwd_is_success(struct eap_sm *sm, void *priv)
10073ff40c12SJohn Marino {
10083ff40c12SJohn Marino 	struct eap_pwd_data *data = priv;
10093ff40c12SJohn Marino 	return data->state == SUCCESS;
10103ff40c12SJohn Marino }
10113ff40c12SJohn Marino 
10123ff40c12SJohn Marino 
eap_pwd_is_done(struct eap_sm * sm,void * priv)10133ff40c12SJohn Marino static Boolean eap_pwd_is_done(struct eap_sm *sm, void *priv)
10143ff40c12SJohn Marino {
10153ff40c12SJohn Marino 	struct eap_pwd_data *data = priv;
10163ff40c12SJohn Marino 	return (data->state == SUCCESS) || (data->state == FAILURE);
10173ff40c12SJohn Marino }
10183ff40c12SJohn Marino 
10193ff40c12SJohn Marino 
eap_pwd_get_session_id(struct eap_sm * sm,void * priv,size_t * len)1020*a1157835SDaniel Fojt static u8 * eap_pwd_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
1021*a1157835SDaniel Fojt {
1022*a1157835SDaniel Fojt 	struct eap_pwd_data *data = priv;
1023*a1157835SDaniel Fojt 	u8 *id;
1024*a1157835SDaniel Fojt 
1025*a1157835SDaniel Fojt 	if (data->state != SUCCESS)
1026*a1157835SDaniel Fojt 		return NULL;
1027*a1157835SDaniel Fojt 
1028*a1157835SDaniel Fojt 	id = os_memdup(data->session_id, 1 + SHA256_MAC_LEN);
1029*a1157835SDaniel Fojt 	if (id == NULL)
1030*a1157835SDaniel Fojt 		return NULL;
1031*a1157835SDaniel Fojt 
1032*a1157835SDaniel Fojt 	*len = 1 + SHA256_MAC_LEN;
1033*a1157835SDaniel Fojt 
1034*a1157835SDaniel Fojt 	return id;
1035*a1157835SDaniel Fojt }
1036*a1157835SDaniel Fojt 
1037*a1157835SDaniel Fojt 
eap_server_pwd_register(void)10383ff40c12SJohn Marino int eap_server_pwd_register(void)
10393ff40c12SJohn Marino {
10403ff40c12SJohn Marino 	struct eap_method *eap;
10413ff40c12SJohn Marino 
10423ff40c12SJohn Marino 	eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
10433ff40c12SJohn Marino 				      EAP_VENDOR_IETF, EAP_TYPE_PWD,
10443ff40c12SJohn Marino 				      "PWD");
10453ff40c12SJohn Marino 	if (eap == NULL)
10463ff40c12SJohn Marino 		return -1;
10473ff40c12SJohn Marino 
10483ff40c12SJohn Marino 	eap->init = eap_pwd_init;
10493ff40c12SJohn Marino 	eap->reset = eap_pwd_reset;
10503ff40c12SJohn Marino 	eap->buildReq = eap_pwd_build_req;
10513ff40c12SJohn Marino 	eap->check = eap_pwd_check;
10523ff40c12SJohn Marino 	eap->process = eap_pwd_process;
10533ff40c12SJohn Marino 	eap->isDone = eap_pwd_is_done;
10543ff40c12SJohn Marino 	eap->getKey = eap_pwd_getkey;
10553ff40c12SJohn Marino 	eap->get_emsk = eap_pwd_get_emsk;
10563ff40c12SJohn Marino 	eap->isSuccess = eap_pwd_is_success;
1057*a1157835SDaniel Fojt 	eap->getSessionId = eap_pwd_get_session_id;
10583ff40c12SJohn Marino 
1059*a1157835SDaniel Fojt 	return eap_server_method_register(eap);
10603ff40c12SJohn Marino }
1061