18d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/*
28d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * hostapd / EAP-pwd (RFC 5931) server
38d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Copyright (c) 2010, Dan Harkins <dharkins@lounge.org>
48d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *
5c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt * This software may be distributed under the terms of the BSD license.
6c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt * See README for more details.
78d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
88d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
98d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "includes.h"
108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "common.h"
1204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt#include "crypto/sha256.h"
138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "eap_server/eap_i.h"
148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "eap_common/eap_pwd_common.h"
158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct eap_pwd_data {
188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	enum {
198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		PWD_ID_Req, PWD_Commit_Req, PWD_Confirm_Req, SUCCESS, FAILURE
208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	} state;
218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 *id_peer;
228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	size_t id_peer_len;
238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 *id_server;
248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	size_t id_server_len;
258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 *password;
268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	size_t password_len;
278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u32 token;
288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u16 group_num;
298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	EAP_PWD_group *grp;
308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
31c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	struct wpabuf *inbuf;
32c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	size_t in_frag_pos;
33c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	struct wpabuf *outbuf;
34c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	size_t out_frag_pos;
35c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	size_t mtu;
36c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt
378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	BIGNUM *k;
388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	BIGNUM *private_value;
398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	BIGNUM *peer_scalar;
408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	BIGNUM *my_scalar;
418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	EC_POINT *my_element;
428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	EC_POINT *peer_element;
438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	u8 my_confirm[SHA256_MAC_LEN];
458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 msk[EAP_MSK_LEN];
478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 emsk[EAP_EMSK_LEN];
488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	BN_CTX *bnctx;
508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt};
518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic const char * eap_pwd_state_txt(int state)
548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	switch (state) {
568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        case PWD_ID_Req:
578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return "PWD-ID-Req";
588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        case PWD_Commit_Req:
598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return "PWD-Commit-Req";
608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        case PWD_Confirm_Req:
618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return "PWD-Confirm-Req";
628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        case SUCCESS:
638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return "SUCCESS";
648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        case FAILURE:
658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return "FAILURE";
668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        default:
678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return "PWD-Unk";
688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void eap_pwd_state(struct eap_pwd_data *data, int state)
738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "EAP-pwd: %s -> %s",
758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   eap_pwd_state_txt(data->state), eap_pwd_state_txt(state));
768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	data->state = state;
778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void * eap_pwd_init(struct eap_sm *sm)
818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct eap_pwd_data *data;
838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (sm->user == NULL || sm->user->password == NULL ||
858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    sm->user->password_len == 0) {
868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_INFO, "EAP-PWD (server): Password is not "
878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "configured");
888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	data = os_zalloc(sizeof(*data));
928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (data == NULL)
938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	data->group_num = sm->pwd_group;
968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "EAP-pwd: Selected group number %d",
978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   data->group_num);
988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	data->state = PWD_ID_Req;
998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	data->id_server = (u8 *) os_strdup("server");
1018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (data->id_server)
1028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		data->id_server_len = os_strlen((char *) data->id_server);
1038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	data->password = os_malloc(sm->user->password_len);
1058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (data->password == NULL) {
1068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_INFO, "EAP-PWD: Memory allocation password "
1078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "fail");
1088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_free(data->id_server);
1098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_free(data);
1108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
1118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
1128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	data->password_len = sm->user->password_len;
1138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(data->password, sm->user->password, data->password_len);
1148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	data->bnctx = BN_CTX_new();
1168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (data->bnctx == NULL) {
1178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_INFO, "EAP-PWD: bn context allocation fail");
1188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_free(data->password);
1198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_free(data->id_server);
1208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_free(data);
1218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
1228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
1238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
124c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	data->in_frag_pos = data->out_frag_pos = 0;
125c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	data->inbuf = data->outbuf = NULL;
126c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	data->mtu = 1020; /* default from RFC 5931, make it configurable! */
127c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt
1288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return data;
1298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
1308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void eap_pwd_reset(struct eap_sm *sm, void *priv)
1338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
1348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct eap_pwd_data *data = priv;
1358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	BN_free(data->private_value);
1378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	BN_free(data->peer_scalar);
1388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	BN_free(data->my_scalar);
1398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	BN_free(data->k);
1408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	BN_CTX_free(data->bnctx);
1418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	EC_POINT_free(data->my_element);
1428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	EC_POINT_free(data->peer_element);
1438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(data->id_peer);
1448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(data->id_server);
1458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(data->password);
1468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (data->grp) {
1478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		EC_GROUP_free(data->grp->group);
1488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		EC_POINT_free(data->grp->pwe);
1498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		BN_free(data->grp->order);
1508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		BN_free(data->grp->prime);
1518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_free(data->grp);
1528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
1538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(data);
1548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
1558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
157c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidtstatic void eap_pwd_build_id_req(struct eap_sm *sm, struct eap_pwd_data *data,
158c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt				 u8 id)
1598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
1608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "EAP-pwd: ID/Request");
161c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	/*
162c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	 * if we're fragmenting then we already have an id request, just return
163c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	 */
164c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	if (data->out_frag_pos)
165c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt		return;
166c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt
167c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	data->outbuf = wpabuf_alloc(sizeof(struct eap_pwd_id) +
168c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt				    data->id_server_len);
169c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	if (data->outbuf == NULL) {
1708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		eap_pwd_state(data, FAILURE);
171c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt		return;
1728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
1738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* an lfsr is good enough to generate unpredictable tokens */
1758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	data->token = os_random();
176c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	wpabuf_put_be16(data->outbuf, data->group_num);
177c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	wpabuf_put_u8(data->outbuf, EAP_PWD_DEFAULT_RAND_FUNC);
178c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	wpabuf_put_u8(data->outbuf, EAP_PWD_DEFAULT_PRF);
179c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	wpabuf_put_data(data->outbuf, &data->token, sizeof(data->token));
180c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	wpabuf_put_u8(data->outbuf, EAP_PWD_PREP_NONE);
181c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	wpabuf_put_data(data->outbuf, data->id_server, data->id_server_len);
1828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
1838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
185c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidtstatic void eap_pwd_build_commit_req(struct eap_sm *sm,
186c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt				     struct eap_pwd_data *data, u8 id)
1878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
1888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	BIGNUM *mask = NULL, *x = NULL, *y = NULL;
1898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 *scalar = NULL, *element = NULL;
1908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u16 offset;
1918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "EAP-pwd: Commit/Request");
193c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	/*
194c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	 * if we're fragmenting then we already have an commit request, just
195c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	 * return
196c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	 */
197c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	if (data->out_frag_pos)
198c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt		return;
1998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (((data->private_value = BN_new()) == NULL) ||
2018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    ((data->my_element = EC_POINT_new(data->grp->group)) == NULL) ||
2028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    ((data->my_scalar = BN_new()) == NULL) ||
2038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    ((mask = BN_new()) == NULL)) {
2048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_INFO, "EAP-PWD (server): scalar allocation "
2058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "fail");
2068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		goto fin;
2078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
2088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	BN_rand_range(data->private_value, data->grp->order);
2108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	BN_rand_range(mask, data->grp->order);
2118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	BN_add(data->my_scalar, data->private_value, mask);
2128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	BN_mod(data->my_scalar, data->my_scalar, data->grp->order,
2138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	       data->bnctx);
2148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!EC_POINT_mul(data->grp->group, data->my_element, NULL,
2168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			  data->grp->pwe, mask, data->bnctx)) {
2178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_INFO, "EAP-PWD (server): element allocation "
2188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "fail");
2198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		eap_pwd_state(data, FAILURE);
2208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		goto fin;
2218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
2228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!EC_POINT_invert(data->grp->group, data->my_element, data->bnctx))
2248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	{
2258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_INFO, "EAP-PWD (server): element inversion "
2268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "fail");
2278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		goto fin;
2288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
2298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	BN_free(mask);
2308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (((x = BN_new()) == NULL) ||
2328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    ((y = BN_new()) == NULL)) {
2338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_INFO, "EAP-PWD (server): point allocation "
2348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "fail");
2358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		goto fin;
2368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
2378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group,
2388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt						 data->my_element, x, y,
2398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt						 data->bnctx)) {
2408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_INFO, "EAP-PWD (server): point assignment "
2418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "fail");
2428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		goto fin;
2438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
2448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (((scalar = os_malloc(BN_num_bytes(data->grp->order))) == NULL) ||
2468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    ((element = os_malloc(BN_num_bytes(data->grp->prime) * 2)) ==
2478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	     NULL)) {
2488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_INFO, "EAP-PWD (server): data allocation fail");
2498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		goto fin;
2508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
2518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/*
2538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * bignums occupy as little memory as possible so one that is
2548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * sufficiently smaller than the prime or order might need pre-pending
2558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * with zeros.
2568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 */
2578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memset(scalar, 0, BN_num_bytes(data->grp->order));
2588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memset(element, 0, BN_num_bytes(data->grp->prime) * 2);
2598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	offset = BN_num_bytes(data->grp->order) -
2608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		BN_num_bytes(data->my_scalar);
2618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	BN_bn2bin(data->my_scalar, scalar + offset);
2628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(x);
2648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	BN_bn2bin(x, element + offset);
2658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(y);
2668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	BN_bn2bin(y, element + BN_num_bytes(data->grp->prime) + offset);
2678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
268c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	data->outbuf = wpabuf_alloc(2 * BN_num_bytes(data->grp->prime) +
269c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt				    BN_num_bytes(data->grp->order));
270c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	if (data->outbuf == NULL)
2718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		goto fin;
2728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* We send the element as (x,y) followed by the scalar */
274c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	wpabuf_put_data(data->outbuf, element,
275c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt			2 * BN_num_bytes(data->grp->prime));
276c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	wpabuf_put_data(data->outbuf, scalar, BN_num_bytes(data->grp->order));
2778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtfin:
2798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(scalar);
2808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(element);
2818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	BN_free(x);
2828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	BN_free(y);
283c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	if (data->outbuf == NULL)
2848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		eap_pwd_state(data, FAILURE);
2858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
2868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
288c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidtstatic void eap_pwd_build_confirm_req(struct eap_sm *sm,
289c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt				      struct eap_pwd_data *data, u8 id)
2908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
2918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	BIGNUM *x = NULL, *y = NULL;
29204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	struct crypto_hash *hash;
29304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	u8 conf[SHA256_MAC_LEN], *cruft = NULL, *ptr;
2948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u16 grp;
2951f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	int offset;
2968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "EAP-pwd: Confirm/Request");
298c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	/*
299c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	 * if we're fragmenting then we already have an confirm request, just
300c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	 * return
301c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	 */
302c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	if (data->out_frag_pos)
303c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt		return;
3048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* Each component of the cruft will be at most as big as the prime */
3068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (((cruft = os_malloc(BN_num_bytes(data->grp->prime))) == NULL) ||
3078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    ((x = BN_new()) == NULL) || ((y = BN_new()) == NULL)) {
3088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_INFO, "EAP-PWD (server): debug allocation "
3098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "fail");
3108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		goto fin;
3118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
3128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/*
3148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * commit is H(k | server_element | server_scalar | peer_element |
3158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 *	       peer_scalar | ciphersuite)
3168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 */
31704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	hash = eap_pwd_h_init();
31804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	if (hash == NULL)
31904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		goto fin;
3208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/*
3228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * Zero the memory each time because this is mod prime math and some
3238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * value may start with a few zeros and the previous one did not.
3248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 *
3258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * First is k
3268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 */
3278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
3281f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(data->k);
3291f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	BN_bn2bin(data->k, cruft + offset);
33004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
3318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* server element: x, y */
3338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group,
3348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt						 data->my_element, x, y,
3358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt						 data->bnctx)) {
3368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_INFO, "EAP-PWD (server): confirm point "
3378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "assignment fail");
3388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		goto fin;
3398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
3408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
3421f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(x);
3431f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	BN_bn2bin(x, cruft + offset);
34404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
3458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
3461f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(y);
3471f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	BN_bn2bin(y, cruft + offset);
34804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
3498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* server scalar */
3518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
3521f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	offset = BN_num_bytes(data->grp->order) -
3531f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		BN_num_bytes(data->my_scalar);
3541f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	BN_bn2bin(data->my_scalar, cruft + offset);
35504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->order));
3568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* peer element: x, y */
3588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group,
3598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt						 data->peer_element, x, y,
3608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt						 data->bnctx)) {
3618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_INFO, "EAP-PWD (server): confirm point "
3628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "assignment fail");
3638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		goto fin;
3648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
3658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
3671f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(x);
3681f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	BN_bn2bin(x, cruft + offset);
36904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
3708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
3711f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(y);
3721f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	BN_bn2bin(y, cruft + offset);
37304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
3748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* peer scalar */
3768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
3771f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	offset = BN_num_bytes(data->grp->order) -
3781f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		BN_num_bytes(data->peer_scalar);
3791f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	BN_bn2bin(data->peer_scalar, cruft + offset);
38004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->order));
3818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* ciphersuite */
3838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	grp = htons(data->group_num);
3848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
3858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ptr = cruft;
3868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(ptr, &grp, sizeof(u16));
3878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ptr += sizeof(u16);
3888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	*ptr = EAP_PWD_DEFAULT_RAND_FUNC;
3898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ptr += sizeof(u8);
3908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	*ptr = EAP_PWD_DEFAULT_PRF;
3918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ptr += sizeof(u8);
39204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	eap_pwd_h_update(hash, cruft, ptr - cruft);
3938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* all done with the random function */
39504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	eap_pwd_h_final(hash, conf);
39604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	os_memcpy(data->my_confirm, conf, SHA256_MAC_LEN);
3978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
39804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	data->outbuf = wpabuf_alloc(SHA256_MAC_LEN);
399c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	if (data->outbuf == NULL)
4008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		goto fin;
4018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
40204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	wpabuf_put_data(data->outbuf, conf, SHA256_MAC_LEN);
4038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtfin:
4058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(cruft);
4068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	BN_free(x);
4078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	BN_free(y);
408c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	if (data->outbuf == NULL)
4098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		eap_pwd_state(data, FAILURE);
4108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
4118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic struct wpabuf *
4148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidteap_pwd_build_req(struct eap_sm *sm, void *priv, u8 id)
4158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
4168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct eap_pwd_data *data = priv;
417c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	struct wpabuf *req;
418c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	u8 lm_exch;
419c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	const u8 *buf;
420c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	u16 totlen = 0;
421c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	size_t len;
422c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt
423c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	/*
424c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	 * if we're buffering response fragments then just ACK
425c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	 */
426c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	if (data->in_frag_pos) {
427c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt		wpa_printf(MSG_DEBUG, "EAP-pwd: ACKing a fragment!!");
428c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt		req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PWD,
429c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt				    EAP_PWD_HDR_SIZE, EAP_CODE_REQUEST, id);
430c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt		if (req == NULL) {
431c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt			eap_pwd_state(data, FAILURE);
432c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt			return NULL;
433c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt		}
434c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt		switch (data->state) {
435c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt		case PWD_ID_Req:
436c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt			wpabuf_put_u8(req, EAP_PWD_OPCODE_ID_EXCH);
437c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt			break;
438c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt		case PWD_Commit_Req:
439c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt			wpabuf_put_u8(req, EAP_PWD_OPCODE_COMMIT_EXCH);
440c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt			break;
441c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt		case PWD_Confirm_Req:
442c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt			wpabuf_put_u8(req, EAP_PWD_OPCODE_CONFIRM_EXCH);
443c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt			break;
444c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt		default:
445c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt			eap_pwd_state(data, FAILURE);   /* just to be sure */
446c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt			wpabuf_free(req);
447c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt			return NULL;
448c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt		}
449c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt		return req;
450c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	}
4518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
452c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	/*
453c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	 * build the data portion of a request
454c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	 */
4558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	switch (data->state) {
456c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	case PWD_ID_Req:
457c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt		eap_pwd_build_id_req(sm, data, id);
458c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt		lm_exch = EAP_PWD_OPCODE_ID_EXCH;
459c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt		break;
460c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	case PWD_Commit_Req:
461c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt		eap_pwd_build_commit_req(sm, data, id);
462c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt		lm_exch = EAP_PWD_OPCODE_COMMIT_EXCH;
463c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt		break;
464c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	case PWD_Confirm_Req:
465c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt		eap_pwd_build_confirm_req(sm, data, id);
466c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt		lm_exch = EAP_PWD_OPCODE_CONFIRM_EXCH;
467c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt		break;
468c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	default:
4698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_INFO, "EAP-pwd: Unknown state %d in build_req",
4708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   data->state);
471c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt		eap_pwd_state(data, FAILURE);
472c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt		lm_exch = 0;    /* hush now, sweet compiler */
4738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
4748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
4758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
476c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	if (data->state == FAILURE)
477c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt		return NULL;
478c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt
479c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	/*
480c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	 * determine whether that data needs to be fragmented
481c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	 */
482c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	len = wpabuf_len(data->outbuf) - data->out_frag_pos;
483c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	if ((len + EAP_PWD_HDR_SIZE) > data->mtu) {
484c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt		len = data->mtu - EAP_PWD_HDR_SIZE;
485c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt		EAP_PWD_SET_MORE_BIT(lm_exch);
486c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt		/*
487c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt		 * if this is the first fragment, need to set the M bit
488c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt		 * and add the total length to the eap_pwd_hdr
489c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt		 */
490c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt		if (data->out_frag_pos == 0) {
491c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt			EAP_PWD_SET_LENGTH_BIT(lm_exch);
492c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt			totlen = wpabuf_len(data->outbuf) +
493c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt				EAP_PWD_HDR_SIZE + sizeof(u16);
494c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt			len -= sizeof(u16);
495c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt			wpa_printf(MSG_DEBUG, "EAP-pwd: Fragmenting output, "
496c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt				   "total length = %d", totlen);
497c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt		}
498c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt		wpa_printf(MSG_DEBUG, "EAP-pwd: Send a %d byte fragment",
499c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt			   (int) len);
500c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	}
501c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt
502c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	/*
503c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	 * alloc an eap request and populate it with the data
504c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	 */
505c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PWD,
506c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt			    EAP_PWD_HDR_SIZE + len +
507c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt			    (totlen ? sizeof(u16) : 0),
508c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt			    EAP_CODE_REQUEST, id);
509c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	if (req == NULL) {
510c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt		eap_pwd_state(data, FAILURE);
511c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt		return NULL;
512c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	}
513c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt
514c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	wpabuf_put_u8(req, lm_exch);
515c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	if (EAP_PWD_GET_LENGTH_BIT(lm_exch))
516c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt		wpabuf_put_be16(req, totlen);
517c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt
518c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	buf = wpabuf_head_u8(data->outbuf);
519c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	wpabuf_put_data(req, buf + data->out_frag_pos, len);
520c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	data->out_frag_pos += len;
521c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	/*
522c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	 * either not fragged or last fragment, either way free up the data
523c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	 */
524c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	if (data->out_frag_pos >= wpabuf_len(data->outbuf)) {
525c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt		wpabuf_free(data->outbuf);
526c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt		data->out_frag_pos = 0;
527c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	}
528c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt
529c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	return req;
5308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
5318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic Boolean eap_pwd_check(struct eap_sm *sm, void *priv,
5348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			     struct wpabuf *respData)
5358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
5368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct eap_pwd_data *data = priv;
5378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const u8 *pos;
5388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	size_t len;
5398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PWD, respData, &len);
5418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (pos == NULL || len < 1) {
5428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_INFO, "EAP-pwd: Invalid frame");
5438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return TRUE;
5448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
5458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
546c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	wpa_printf(MSG_DEBUG, "EAP-pwd: Received frame: exch = %d, len = %d",
547c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt		   EAP_PWD_GET_EXCHANGE(*pos), (int) len);
5488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
549c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	if (data->state == PWD_ID_Req &&
550c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	    ((EAP_PWD_GET_EXCHANGE(*pos)) == EAP_PWD_OPCODE_ID_EXCH))
5518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return FALSE;
5528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (data->state == PWD_Commit_Req &&
554c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	    ((EAP_PWD_GET_EXCHANGE(*pos)) == EAP_PWD_OPCODE_COMMIT_EXCH))
5558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return FALSE;
5568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (data->state == PWD_Confirm_Req &&
558c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	    ((EAP_PWD_GET_EXCHANGE(*pos)) == EAP_PWD_OPCODE_CONFIRM_EXCH))
5598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return FALSE;
5608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_INFO, "EAP-pwd: Unexpected opcode=%d in state=%d",
5628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   *pos, data->state);
5638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return TRUE;
5658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
5668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void eap_pwd_process_id_resp(struct eap_sm *sm,
5698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				    struct eap_pwd_data *data,
5708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				    const u8 *payload, size_t payload_len)
5718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
5728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct eap_pwd_id *id;
5738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (payload_len < sizeof(struct eap_pwd_id)) {
5758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_INFO, "EAP-pwd: Invalid ID response");
5768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
5778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
5788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	id = (struct eap_pwd_id *) payload;
5808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if ((data->group_num != be_to_host16(id->group_num)) ||
5818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    (id->random_function != EAP_PWD_DEFAULT_RAND_FUNC) ||
5828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    (os_memcmp(id->token, (u8 *)&data->token, sizeof(data->token))) ||
5838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    (id->prf != EAP_PWD_DEFAULT_PRF)) {
5848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_INFO, "EAP-pwd: peer changed parameters");
5858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		eap_pwd_state(data, FAILURE);
5868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
5878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
5888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	data->id_peer = os_malloc(payload_len - sizeof(struct eap_pwd_id));
5898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (data->id_peer == NULL) {
5908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_INFO, "EAP-PWD: memory allocation id fail");
5918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
5928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
5938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	data->id_peer_len = payload_len - sizeof(struct eap_pwd_id);
5948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(data->id_peer, id->identity, data->id_peer_len);
5958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_hexdump_ascii(MSG_DEBUG, "EAP-PWD (server): peer sent id of",
5968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			  data->id_peer, data->id_peer_len);
5978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if ((data->grp = os_malloc(sizeof(EAP_PWD_group))) == NULL) {
5998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_INFO, "EAP-PWD: failed to allocate memory for "
6008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "group");
6018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
6028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
6038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (compute_password_element(data->grp, data->group_num,
6048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				     data->password, data->password_len,
6058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				     data->id_server, data->id_server_len,
6068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				     data->id_peer, data->id_peer_len,
6078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				     (u8 *) &data->token)) {
6088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_INFO, "EAP-PWD (server): unable to compute "
6098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "PWE");
6108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
6118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
6128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "EAP-PWD (server): computed %d bit PWE...",
6138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   BN_num_bits(data->grp->prime));
6148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eap_pwd_state(data, PWD_Commit_Req);
6168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
6178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void
6208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidteap_pwd_process_commit_resp(struct eap_sm *sm, struct eap_pwd_data *data,
6218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			    const u8 *payload, size_t payload_len)
6228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
6238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 *ptr;
6248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	BIGNUM *x = NULL, *y = NULL, *cofactor = NULL;
6258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	EC_POINT *K = NULL, *point = NULL;
6268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int res = 0;
6278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "EAP-pwd: Received commit response");
6298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (((data->peer_scalar = BN_new()) == NULL) ||
6318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    ((data->k = BN_new()) == NULL) ||
6328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    ((cofactor = BN_new()) == NULL) ||
6338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    ((x = BN_new()) == NULL) ||
6348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    ((y = BN_new()) == NULL) ||
6358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    ((point = EC_POINT_new(data->grp->group)) == NULL) ||
6368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    ((K = EC_POINT_new(data->grp->group)) == NULL) ||
6378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    ((data->peer_element = EC_POINT_new(data->grp->group)) == NULL)) {
6388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_INFO, "EAP-PWD (server): peer data allocation "
6398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "fail");
6408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		goto fin;
6418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
6428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!EC_GROUP_get_cofactor(data->grp->group, cofactor, NULL)) {
6448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_INFO, "EAP-PWD (server): unable to get "
6458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "cofactor for curve");
6468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		goto fin;
6478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
6488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* element, x then y, followed by scalar */
6508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ptr = (u8 *) payload;
6518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	BN_bin2bn(ptr, BN_num_bytes(data->grp->prime), x);
6528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ptr += BN_num_bytes(data->grp->prime);
6538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	BN_bin2bn(ptr, BN_num_bytes(data->grp->prime), y);
6548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ptr += BN_num_bytes(data->grp->prime);
6558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	BN_bin2bn(ptr, BN_num_bytes(data->grp->order), data->peer_scalar);
6568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!EC_POINT_set_affine_coordinates_GFp(data->grp->group,
6578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt						 data->peer_element, x, y,
6588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt						 data->bnctx)) {
6598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_INFO, "EAP-PWD (server): setting peer element "
6608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "fail");
6618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		goto fin;
6628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
6638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* check to ensure peer's element is not in a small sub-group */
6658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (BN_cmp(cofactor, BN_value_one())) {
6668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (!EC_POINT_mul(data->grp->group, point, NULL,
6678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				  data->peer_element, cofactor, NULL)) {
6688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_INFO, "EAP-PWD (server): cannot "
6698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "multiply peer element by order");
6708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			goto fin;
6718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
6728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (EC_POINT_is_at_infinity(data->grp->group, point)) {
6738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_INFO, "EAP-PWD (server): peer element "
6748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "is at infinity!\n");
6758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			goto fin;
6768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
6778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
6788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* compute the shared key, k */
6808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if ((!EC_POINT_mul(data->grp->group, K, NULL, data->grp->pwe,
6818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   data->peer_scalar, data->bnctx)) ||
6828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    (!EC_POINT_add(data->grp->group, K, K, data->peer_element,
6838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   data->bnctx)) ||
6848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    (!EC_POINT_mul(data->grp->group, K, NULL, K, data->private_value,
6858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   data->bnctx))) {
6868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_INFO, "EAP-PWD (server): computing shared key "
6878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "fail");
6888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		goto fin;
6898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
6908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* ensure that the shared key isn't in a small sub-group */
6928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (BN_cmp(cofactor, BN_value_one())) {
6938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (!EC_POINT_mul(data->grp->group, K, NULL, K, cofactor,
6948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				  NULL)) {
6958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_INFO, "EAP-PWD (server): cannot "
6968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "multiply shared key point by order!\n");
6978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			goto fin;
6988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
6998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
7008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/*
7028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * This check is strictly speaking just for the case above where
7038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * co-factor > 1 but it was suggested that even though this is probably
7048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * never going to happen it is a simple and safe check "just to be
7058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * sure" so let's be safe.
7068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 */
7078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (EC_POINT_is_at_infinity(data->grp->group, K)) {
7088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_INFO, "EAP-PWD (server): shared key point is "
7098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "at infinity");
7108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		goto fin;
7118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
7128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group, K, data->k,
7138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt						 NULL, data->bnctx)) {
7148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_INFO, "EAP-PWD (server): unable to extract "
7158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "shared secret from secret point");
7168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		goto fin;
7178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
7188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	res = 1;
7198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtfin:
7218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	EC_POINT_free(K);
7228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	EC_POINT_free(point);
7238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	BN_free(cofactor);
7248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	BN_free(x);
7258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	BN_free(y);
7268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (res)
7288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		eap_pwd_state(data, PWD_Confirm_Req);
7298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	else
7308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		eap_pwd_state(data, FAILURE);
7318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
7328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void
7358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidteap_pwd_process_confirm_resp(struct eap_sm *sm, struct eap_pwd_data *data,
7368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			     const u8 *payload, size_t payload_len)
7378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
7388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	BIGNUM *x = NULL, *y = NULL;
73904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	struct crypto_hash *hash;
7408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u32 cs;
7418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u16 grp;
74204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	u8 conf[SHA256_MAC_LEN], *cruft = NULL, *ptr;
7431f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	int offset;
7448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* build up the ciphersuite: group | random_function | prf */
7468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	grp = htons(data->group_num);
7478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ptr = (u8 *) &cs;
7488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(ptr, &grp, sizeof(u16));
7498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ptr += sizeof(u16);
7508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	*ptr = EAP_PWD_DEFAULT_RAND_FUNC;
7518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ptr += sizeof(u8);
7528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	*ptr = EAP_PWD_DEFAULT_PRF;
7538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* each component of the cruft will be at most as big as the prime */
7558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (((cruft = os_malloc(BN_num_bytes(data->grp->prime))) == NULL) ||
7568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    ((x = BN_new()) == NULL) || ((y = BN_new()) == NULL)) {
7578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_INFO, "EAP-PWD (peer): allocation fail");
7588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		goto fin;
7598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
7608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/*
7628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * commit is H(k | peer_element | peer_scalar | server_element |
7638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 *	       server_scalar | ciphersuite)
7648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 */
76504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	hash = eap_pwd_h_init();
76604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	if (hash == NULL)
76704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		goto fin;
7688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* k */
7708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
7711f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(data->k);
7721f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	BN_bn2bin(data->k, cruft + offset);
77304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
7748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* peer element: x, y */
7768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group,
7778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt						 data->peer_element, x, y,
7788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt						 data->bnctx)) {
7798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_INFO, "EAP-PWD (server): confirm point "
7808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "assignment fail");
7818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		goto fin;
7828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
7838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
7841f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(x);
7851f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	BN_bn2bin(x, cruft + offset);
78604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
7878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
7881f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(y);
7891f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	BN_bn2bin(y, cruft + offset);
79004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
7918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* peer scalar */
7938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
7941f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	offset = BN_num_bytes(data->grp->order) -
7951f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		BN_num_bytes(data->peer_scalar);
7961f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	BN_bn2bin(data->peer_scalar, cruft + offset);
79704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->order));
7988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* server element: x, y */
8008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group,
8018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt						 data->my_element, x, y,
8028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt						 data->bnctx)) {
8038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_INFO, "EAP-PWD (server): confirm point "
8048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "assignment fail");
8058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		goto fin;
8068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
8078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
8091f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(x);
8101f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	BN_bn2bin(x, cruft + offset);
81104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
8128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
8131f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(y);
8141f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	BN_bn2bin(y, cruft + offset);
81504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
8168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* server scalar */
8188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
8191f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	offset = BN_num_bytes(data->grp->order) -
8201f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		BN_num_bytes(data->my_scalar);
8211f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	BN_bn2bin(data->my_scalar, cruft + offset);
82204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->order));
8238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* ciphersuite */
8258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
82604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	eap_pwd_h_update(hash, (u8 *) &cs, sizeof(u32));
8278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* all done */
82904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	eap_pwd_h_final(hash, conf);
8308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ptr = (u8 *) payload;
83204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	if (os_memcmp(conf, ptr, SHA256_MAC_LEN)) {
8338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_INFO, "EAP-PWD (server): confirm did not "
8348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "verify");
8358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		goto fin;
8368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
8378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "EAP-pwd (server): confirm verified");
8398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (compute_keys(data->grp, data->bnctx, data->k,
8408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			 data->peer_scalar, data->my_scalar, conf,
8418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			 data->my_confirm, &cs, data->msk, data->emsk) < 0)
8428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		eap_pwd_state(data, FAILURE);
8438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	else
8448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		eap_pwd_state(data, SUCCESS);
8458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtfin:
8478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(cruft);
8488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	BN_free(x);
8498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	BN_free(y);
8508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
8518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void eap_pwd_process(struct eap_sm *sm, void *priv,
8548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			    struct wpabuf *respData)
8558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
8568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct eap_pwd_data *data = priv;
8578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const u8 *pos;
8588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	size_t len;
859c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	u8 lm_exch;
860c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	u16 tot_len;
8618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PWD, respData, &len);
8638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if ((pos == NULL) || (len < 1)) {
8648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_INFO, "Bad EAP header! pos %s and len = %d",
8658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   (pos == NULL) ? "is NULL" : "is not NULL",
8668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   (int) len);
8678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
8688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
8698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
870c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	lm_exch = *pos;
871c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	pos++;            /* skip over the bits and the exch */
872c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	len--;
873c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt
874c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	/*
875c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	 * if we're fragmenting then this should be an ACK with no data,
876c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	 * just return and continue fragmenting in the "build" section above
877c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	 */
878c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	if (data->out_frag_pos) {
879c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt		if (len > 1)
880c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt			wpa_printf(MSG_INFO, "EAP-pwd: Bad response! "
881c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt				   "Fragmenting but not an ACK");
882c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt		else
883c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt			wpa_printf(MSG_DEBUG, "EAP-pwd: received ACK from "
884c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt				   "peer");
885c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt		return;
886c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	}
887c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	/*
888c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	 * if we're receiving fragmented packets then we need to buffer...
889c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	 *
890c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	 * the first fragment has a total length
891c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	 */
892c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	if (EAP_PWD_GET_LENGTH_BIT(lm_exch)) {
893c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt		tot_len = WPA_GET_BE16(pos);
894c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt		wpa_printf(MSG_DEBUG, "EAP-pwd: Incoming fragments, total "
895c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt			   "length = %d", tot_len);
896c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt		data->inbuf = wpabuf_alloc(tot_len);
897c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt		if (data->inbuf == NULL) {
898c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt			wpa_printf(MSG_INFO, "EAP-pwd: Out of memory to "
899c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt				   "buffer fragments!");
900c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt			return;
901c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt		}
902c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt		pos += sizeof(u16);
903c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt		len -= sizeof(u16);
904c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	}
905c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	/*
906c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	 * the first and all intermediate fragments have the M bit set
907c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	 */
908c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	if (EAP_PWD_GET_MORE_BIT(lm_exch)) {
909c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt		if ((data->in_frag_pos + len) > wpabuf_size(data->inbuf)) {
910c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt			wpa_printf(MSG_DEBUG, "EAP-pwd: Buffer overflow "
911c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt				   "attack detected! (%d+%d > %d)",
912c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt				   (int) data->in_frag_pos, (int) len,
913c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt				   (int) wpabuf_size(data->inbuf));
914c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt			eap_pwd_state(data, FAILURE);
915c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt			return;
916c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt		}
917c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt		wpabuf_put_data(data->inbuf, pos, len);
918c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt		data->in_frag_pos += len;
919c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt		wpa_printf(MSG_DEBUG, "EAP-pwd: Got a %d byte fragment",
920c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt			   (int) len);
921c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt		return;
922c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	}
923c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	/*
924c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	 * last fragment won't have the M bit set (but we're obviously
925c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	 * buffering fragments so that's how we know it's the last)
926c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	 */
927c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	if (data->in_frag_pos) {
928c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt		wpabuf_put_data(data->inbuf, pos, len);
929c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt		data->in_frag_pos += len;
930c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt		pos = wpabuf_head_u8(data->inbuf);
931c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt		len = data->in_frag_pos;
932c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt		wpa_printf(MSG_DEBUG, "EAP-pwd: Last fragment, %d bytes",
933c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt			   (int) len);
934c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	}
935c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	switch (EAP_PWD_GET_EXCHANGE(lm_exch)) {
9368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case EAP_PWD_OPCODE_ID_EXCH:
937c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt		eap_pwd_process_id_resp(sm, data, pos, len);
9388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
9398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case EAP_PWD_OPCODE_COMMIT_EXCH:
940c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt		eap_pwd_process_commit_resp(sm, data, pos, len);
9418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
942c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	case EAP_PWD_OPCODE_CONFIRM_EXCH:
943c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt		eap_pwd_process_confirm_resp(sm, data, pos, len);
9448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
9458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
946c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	/*
947c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	 * if we had been buffering fragments, here's a great place
948c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	 * to clean up
949c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	 */
950c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	if (data->in_frag_pos) {
951c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt		wpabuf_free(data->inbuf);
952c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt		data->in_frag_pos = 0;
953c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	}
9548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
9558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic u8 * eap_pwd_getkey(struct eap_sm *sm, void *priv, size_t *len)
9588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
9598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct eap_pwd_data *data = priv;
9608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 *key;
9618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (data->state != SUCCESS)
9638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
9648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	key = os_malloc(EAP_MSK_LEN);
9668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (key == NULL)
9678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
9688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(key, data->msk, EAP_MSK_LEN);
9708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	*len = EAP_MSK_LEN;
9718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return key;
9738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
9748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic u8 * eap_pwd_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
9778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
9788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct eap_pwd_data *data = priv;
9798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 *key;
9808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (data->state != SUCCESS)
9828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
9838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	key = os_malloc(EAP_EMSK_LEN);
9858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (key == NULL)
9868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
9878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(key, data->emsk, EAP_EMSK_LEN);
9898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	*len = EAP_EMSK_LEN;
9908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return key;
9928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
9938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic Boolean eap_pwd_is_success(struct eap_sm *sm, void *priv)
9968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
9978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct eap_pwd_data *data = priv;
9988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return data->state == SUCCESS;
9998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
10008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic Boolean eap_pwd_is_done(struct eap_sm *sm, void *priv)
10038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
10048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct eap_pwd_data *data = priv;
10058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return (data->state == SUCCESS) || (data->state == FAILURE);
10068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
10078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint eap_server_pwd_register(void)
10108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
10118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct eap_method *eap;
10128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int ret;
10138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct timeval tp;
10148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct timezone tz;
10158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u32 sr;
10168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	EVP_add_digest(EVP_sha256());
10188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	sr = 0xdeaddada;
10208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	(void) gettimeofday(&tp, &tz);
10218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	sr ^= (tp.tv_sec ^ tp.tv_usec);
10228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	srandom(sr);
10238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
10258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				      EAP_VENDOR_IETF, EAP_TYPE_PWD,
10268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				      "PWD");
10278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (eap == NULL)
10288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
10298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eap->init = eap_pwd_init;
10318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eap->reset = eap_pwd_reset;
10328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eap->buildReq = eap_pwd_build_req;
10338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eap->check = eap_pwd_check;
10348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eap->process = eap_pwd_process;
10358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eap->isDone = eap_pwd_is_done;
10368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eap->getKey = eap_pwd_getkey;
10378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eap->get_emsk = eap_pwd_get_emsk;
10388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eap->isSuccess = eap_pwd_is_success;
10398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ret = eap_server_method_register(eap);
10418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ret)
10428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		eap_server_method_free(eap);
10438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return ret;
10448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
10458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1046