1526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt/*
2526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * EAP peer method: EAP-PSK (RFC 4764)
3526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi>
4526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt *
5526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * This program is free software; you can redistribute it and/or modify
6526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * it under the terms of the GNU General Public License version 2 as
7526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * published by the Free Software Foundation.
8526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt *
9526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * Alternatively, this software may be distributed under the terms of BSD
10526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * license.
11526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt *
12526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * See README and COPYING for more details.
13526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt *
14526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * Note: EAP-PSK is an EAP authentication method and as such, completely
15526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * different from WPA-PSK. This file is not needed for WPA-PSK functionality.
16526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt */
17526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
18526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#include "includes.h"
19526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
20526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#include "common.h"
21526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#include "eap_peer/eap_i.h"
22b349ef9e9f3f5399bf96b3c1c663cb9e547f50a1Dmitry Shmidt#include "crypto/aes_wrap.h"
23526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#include "eap_common/eap_psk_common.h"
24526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
25526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
26526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstruct eap_psk_data {
27526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	enum { PSK_INIT, PSK_MAC_SENT, PSK_DONE } state;
28526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	u8 rand_p[EAP_PSK_RAND_LEN];
29526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	u8 ak[EAP_PSK_AK_LEN], kdk[EAP_PSK_KDK_LEN], tek[EAP_PSK_TEK_LEN];
30526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	u8 *id_s, *id_p;
31526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	size_t id_s_len, id_p_len;
32526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	u8 msk[EAP_MSK_LEN];
33526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	u8 emsk[EAP_EMSK_LEN];
34526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt};
35526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
36526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
37526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic void * eap_psk_init(struct eap_sm *sm)
38526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{
39526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	struct eap_psk_data *data;
40526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	const u8 *identity, *password;
41526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	size_t identity_len, password_len;
42526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
43526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	password = eap_get_config_password(sm, &password_len);
44526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (!password || password_len != 16) {
45526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_printf(MSG_INFO, "EAP-PSK: 16-octet pre-shared key not "
46526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			   "configured");
47526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return NULL;
48526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
49526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
50526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	data = os_zalloc(sizeof(*data));
51526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (data == NULL)
52526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return NULL;
53526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (eap_psk_key_setup(password, data->ak, data->kdk)) {
54526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		os_free(data);
55526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return NULL;
56526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
57526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	wpa_hexdump_key(MSG_DEBUG, "EAP-PSK: AK", data->ak, EAP_PSK_AK_LEN);
58526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	wpa_hexdump_key(MSG_DEBUG, "EAP-PSK: KDK", data->kdk, EAP_PSK_KDK_LEN);
59526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	data->state = PSK_INIT;
60526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
61526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	identity = eap_get_config_identity(sm, &identity_len);
62526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (identity) {
63526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		data->id_p = os_malloc(identity_len);
64526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		if (data->id_p)
65526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			os_memcpy(data->id_p, identity, identity_len);
66526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		data->id_p_len = identity_len;
67526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
68526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (data->id_p == NULL) {
69526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_printf(MSG_INFO, "EAP-PSK: could not get own identity");
70526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		os_free(data);
71526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return NULL;
72526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
73526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
74526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	return data;
75526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}
76526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
77526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
78526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic void eap_psk_deinit(struct eap_sm *sm, void *priv)
79526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{
80526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	struct eap_psk_data *data = priv;
81526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	os_free(data->id_s);
82526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	os_free(data->id_p);
83526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	os_free(data);
84526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}
85526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
86526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
87526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic struct wpabuf * eap_psk_process_1(struct eap_psk_data *data,
88526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt					 struct eap_method_ret *ret,
89526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt					 const struct wpabuf *reqData)
90526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{
91526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	const struct eap_psk_hdr_1 *hdr1;
92526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	struct eap_psk_hdr_2 *hdr2;
93526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	struct wpabuf *resp;
94526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	u8 *buf, *pos;
95526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	size_t buflen, len;
96526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	const u8 *cpos;
97526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
98526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	wpa_printf(MSG_DEBUG, "EAP-PSK: in INIT state");
99526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
100526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	cpos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PSK, reqData, &len);
101526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	hdr1 = (const struct eap_psk_hdr_1 *) cpos;
102526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (cpos == NULL || len < sizeof(*hdr1)) {
103526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_printf(MSG_INFO, "EAP-PSK: Invalid first message "
104526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			   "length (%lu; expected %lu or more)",
105526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			   (unsigned long) len,
106526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			   (unsigned long) sizeof(*hdr1));
107526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		ret->ignore = TRUE;
108526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return NULL;
109526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
110526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	wpa_printf(MSG_DEBUG, "EAP-PSK: Flags=0x%x", hdr1->flags);
111526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (EAP_PSK_FLAGS_GET_T(hdr1->flags) != 0) {
112526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_printf(MSG_INFO, "EAP-PSK: Unexpected T=%d (expected 0)",
113526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			   EAP_PSK_FLAGS_GET_T(hdr1->flags));
114526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		ret->methodState = METHOD_DONE;
115526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		ret->decision = DECISION_FAIL;
116526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return NULL;
117526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
118526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	wpa_hexdump(MSG_DEBUG, "EAP-PSK: RAND_S", hdr1->rand_s,
119526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		    EAP_PSK_RAND_LEN);
120526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	os_free(data->id_s);
121526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	data->id_s_len = len - sizeof(*hdr1);
122526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	data->id_s = os_malloc(data->id_s_len);
123526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (data->id_s == NULL) {
124526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_printf(MSG_ERROR, "EAP-PSK: Failed to allocate memory for "
125526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			   "ID_S (len=%lu)", (unsigned long) data->id_s_len);
126526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		ret->ignore = TRUE;
127526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return NULL;
128526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
129526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	os_memcpy(data->id_s, (u8 *) (hdr1 + 1), data->id_s_len);
130526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	wpa_hexdump_ascii(MSG_DEBUG, "EAP-PSK: ID_S",
131526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			  data->id_s, data->id_s_len);
132526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
133526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (os_get_random(data->rand_p, EAP_PSK_RAND_LEN)) {
134526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_printf(MSG_ERROR, "EAP-PSK: Failed to get random data");
135526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		ret->ignore = TRUE;
136526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return NULL;
137526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
138526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
139526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PSK,
140526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			     sizeof(*hdr2) + data->id_p_len, EAP_CODE_RESPONSE,
141526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			     eap_get_id(reqData));
142526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (resp == NULL)
143526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return NULL;
144526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	hdr2 = wpabuf_put(resp, sizeof(*hdr2));
145526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	hdr2->flags = EAP_PSK_FLAGS_SET_T(1); /* T=1 */
146526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	os_memcpy(hdr2->rand_s, hdr1->rand_s, EAP_PSK_RAND_LEN);
147526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	os_memcpy(hdr2->rand_p, data->rand_p, EAP_PSK_RAND_LEN);
148526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	wpabuf_put_data(resp, data->id_p, data->id_p_len);
149526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	/* MAC_P = OMAC1-AES-128(AK, ID_P||ID_S||RAND_S||RAND_P) */
150526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	buflen = data->id_p_len + data->id_s_len + 2 * EAP_PSK_RAND_LEN;
151526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	buf = os_malloc(buflen);
152526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (buf == NULL) {
153526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpabuf_free(resp);
154526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return NULL;
155526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
156526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	os_memcpy(buf, data->id_p, data->id_p_len);
157526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	pos = buf + data->id_p_len;
158526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	os_memcpy(pos, data->id_s, data->id_s_len);
159526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	pos += data->id_s_len;
160526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	os_memcpy(pos, hdr1->rand_s, EAP_PSK_RAND_LEN);
161526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	pos += EAP_PSK_RAND_LEN;
162526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	os_memcpy(pos, data->rand_p, EAP_PSK_RAND_LEN);
163526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (omac1_aes_128(data->ak, buf, buflen, hdr2->mac_p)) {
164526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		os_free(buf);
165526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpabuf_free(resp);
166526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return NULL;
167526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
168526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	os_free(buf);
169526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	wpa_hexdump(MSG_DEBUG, "EAP-PSK: RAND_P", hdr2->rand_p,
170526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		    EAP_PSK_RAND_LEN);
171526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	wpa_hexdump(MSG_DEBUG, "EAP-PSK: MAC_P", hdr2->mac_p, EAP_PSK_MAC_LEN);
172526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	wpa_hexdump_ascii(MSG_DEBUG, "EAP-PSK: ID_P",
173526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			  data->id_p, data->id_p_len);
174526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
175526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	data->state = PSK_MAC_SENT;
176526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
177526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	return resp;
178526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}
179526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
180526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
181526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic struct wpabuf * eap_psk_process_3(struct eap_psk_data *data,
182526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt					 struct eap_method_ret *ret,
183526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt					 const struct wpabuf *reqData)
184526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{
185526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	const struct eap_psk_hdr_3 *hdr3;
186526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	struct eap_psk_hdr_4 *hdr4;
187526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	struct wpabuf *resp;
188526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	u8 *buf, *rpchannel, nonce[16], *decrypted;
189526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	const u8 *pchannel, *tag, *msg;
190526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	u8 mac[EAP_PSK_MAC_LEN];
191526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	size_t buflen, left, data_len, len, plen;
192526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	int failed = 0;
193526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	const u8 *pos;
194526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
195526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	wpa_printf(MSG_DEBUG, "EAP-PSK: in MAC_SENT state");
196526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
197526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PSK,
198526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			       reqData, &len);
199526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	hdr3 = (const struct eap_psk_hdr_3 *) pos;
200526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (pos == NULL || len < sizeof(*hdr3)) {
201526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_printf(MSG_INFO, "EAP-PSK: Invalid third message "
202526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			   "length (%lu; expected %lu or more)",
203526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			   (unsigned long) len,
204526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			   (unsigned long) sizeof(*hdr3));
205526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		ret->ignore = TRUE;
206526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return NULL;
207526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
208526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	left = len - sizeof(*hdr3);
209526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	pchannel = (const u8 *) (hdr3 + 1);
210526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	wpa_printf(MSG_DEBUG, "EAP-PSK: Flags=0x%x", hdr3->flags);
211526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (EAP_PSK_FLAGS_GET_T(hdr3->flags) != 2) {
212526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_printf(MSG_INFO, "EAP-PSK: Unexpected T=%d (expected 2)",
213526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			   EAP_PSK_FLAGS_GET_T(hdr3->flags));
214526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		ret->methodState = METHOD_DONE;
215526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		ret->decision = DECISION_FAIL;
216526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return NULL;
217526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
218526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	wpa_hexdump(MSG_DEBUG, "EAP-PSK: RAND_S", hdr3->rand_s,
219526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		    EAP_PSK_RAND_LEN);
220526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	wpa_hexdump(MSG_DEBUG, "EAP-PSK: MAC_S", hdr3->mac_s, EAP_PSK_MAC_LEN);
221526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	wpa_hexdump(MSG_DEBUG, "EAP-PSK: PCHANNEL", pchannel, left);
222526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
223526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (left < 4 + 16 + 1) {
224526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_printf(MSG_INFO, "EAP-PSK: Too short PCHANNEL data in "
225526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			   "third message (len=%lu, expected 21)",
226526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			   (unsigned long) left);
227526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		ret->ignore = TRUE;
228526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return NULL;
229526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
230526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
231526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	/* MAC_S = OMAC1-AES-128(AK, ID_S||RAND_P) */
232526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	buflen = data->id_s_len + EAP_PSK_RAND_LEN;
233526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	buf = os_malloc(buflen);
234526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (buf == NULL)
235526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return NULL;
236526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	os_memcpy(buf, data->id_s, data->id_s_len);
237526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	os_memcpy(buf + data->id_s_len, data->rand_p, EAP_PSK_RAND_LEN);
238526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (omac1_aes_128(data->ak, buf, buflen, mac)) {
239526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		os_free(buf);
240526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return NULL;
241526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
242526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	os_free(buf);
243526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (os_memcmp(mac, hdr3->mac_s, EAP_PSK_MAC_LEN) != 0) {
244526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_printf(MSG_WARNING, "EAP-PSK: Invalid MAC_S in third "
245526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			   "message");
246526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		ret->methodState = METHOD_DONE;
247526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		ret->decision = DECISION_FAIL;
248526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return NULL;
249526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
250526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	wpa_printf(MSG_DEBUG, "EAP-PSK: MAC_S verified successfully");
251526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
252526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (eap_psk_derive_keys(data->kdk, data->rand_p, data->tek,
253526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				data->msk, data->emsk)) {
254526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		ret->methodState = METHOD_DONE;
255526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		ret->decision = DECISION_FAIL;
256526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return NULL;
257526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
258526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	wpa_hexdump_key(MSG_DEBUG, "EAP-PSK: TEK", data->tek, EAP_PSK_TEK_LEN);
259526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	wpa_hexdump_key(MSG_DEBUG, "EAP-PSK: MSK", data->msk, EAP_MSK_LEN);
260526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	wpa_hexdump_key(MSG_DEBUG, "EAP-PSK: EMSK", data->emsk, EAP_EMSK_LEN);
261526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
262526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	os_memset(nonce, 0, 12);
263526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	os_memcpy(nonce + 12, pchannel, 4);
264526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	pchannel += 4;
265526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	left -= 4;
266526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
267526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	tag = pchannel;
268526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	pchannel += 16;
269526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	left -= 16;
270526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
271526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	msg = pchannel;
272526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
273526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	wpa_hexdump(MSG_MSGDUMP, "EAP-PSK: PCHANNEL - nonce",
274526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		    nonce, sizeof(nonce));
275526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	wpa_hexdump(MSG_MSGDUMP, "EAP-PSK: PCHANNEL - hdr",
276526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		    wpabuf_head(reqData), 5);
277526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	wpa_hexdump(MSG_MSGDUMP, "EAP-PSK: PCHANNEL - cipher msg", msg, left);
278526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
279526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	decrypted = os_malloc(left);
280526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (decrypted == NULL) {
281526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		ret->methodState = METHOD_DONE;
282526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		ret->decision = DECISION_FAIL;
283526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return NULL;
284526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
285526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	os_memcpy(decrypted, msg, left);
286526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
287526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (aes_128_eax_decrypt(data->tek, nonce, sizeof(nonce),
288526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				wpabuf_head(reqData),
289526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				sizeof(struct eap_hdr) + 1 +
290526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				sizeof(*hdr3) - EAP_PSK_MAC_LEN, decrypted,
291526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				left, tag)) {
292526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_printf(MSG_WARNING, "EAP-PSK: PCHANNEL decryption failed");
293526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		os_free(decrypted);
294526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return NULL;
295526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
296526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	wpa_hexdump(MSG_DEBUG, "EAP-PSK: Decrypted PCHANNEL message",
297526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		    decrypted, left);
298526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
299526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	/* Verify R flag */
300526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	switch (decrypted[0] >> 6) {
301526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	case EAP_PSK_R_FLAG_CONT:
302526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_printf(MSG_DEBUG, "EAP-PSK: R flag - CONT - unsupported");
303526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		failed = 1;
304526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		break;
305526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	case EAP_PSK_R_FLAG_DONE_SUCCESS:
306526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_printf(MSG_DEBUG, "EAP-PSK: R flag - DONE_SUCCESS");
307526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		break;
308526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	case EAP_PSK_R_FLAG_DONE_FAILURE:
309526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_printf(MSG_DEBUG, "EAP-PSK: R flag - DONE_FAILURE");
310526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_printf(MSG_INFO, "EAP-PSK: Authentication server rejected "
311526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			   "authentication");
312526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		failed = 1;
313526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		break;
314526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
315526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
316526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	data_len = 1;
317526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if ((decrypted[0] & EAP_PSK_E_FLAG) && left > 1)
318526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		data_len++;
319526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	plen = sizeof(*hdr4) + 4 + 16 + data_len;
320526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PSK, plen,
321526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			     EAP_CODE_RESPONSE, eap_get_id(reqData));
322526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (resp == NULL) {
323526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		os_free(decrypted);
324526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return NULL;
325526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
326526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	hdr4 = wpabuf_put(resp, sizeof(*hdr4));
327526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	hdr4->flags = EAP_PSK_FLAGS_SET_T(3); /* T=3 */
328526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	os_memcpy(hdr4->rand_s, hdr3->rand_s, EAP_PSK_RAND_LEN);
329526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	rpchannel = wpabuf_put(resp, 4 + 16 + data_len);
330526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
331526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	/* nonce++ */
332526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	inc_byte_array(nonce, sizeof(nonce));
333526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	os_memcpy(rpchannel, nonce + 12, 4);
334526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
335526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (decrypted[0] & EAP_PSK_E_FLAG) {
336526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_printf(MSG_DEBUG, "EAP-PSK: Unsupported E (Ext) flag");
337526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		failed = 1;
338526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		rpchannel[4 + 16] = (EAP_PSK_R_FLAG_DONE_FAILURE << 6) |
339526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			EAP_PSK_E_FLAG;
340526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		if (left > 1) {
341526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			/* Add empty EXT_Payload with same EXT_Type */
342526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			rpchannel[4 + 16 + 1] = decrypted[1];
343526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		}
344526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	} else if (failed)
345526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		rpchannel[4 + 16] = EAP_PSK_R_FLAG_DONE_FAILURE << 6;
346526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	else
347526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		rpchannel[4 + 16] = EAP_PSK_R_FLAG_DONE_SUCCESS << 6;
348526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
349526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	wpa_hexdump(MSG_DEBUG, "EAP-PSK: reply message (plaintext)",
350526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		    rpchannel + 4 + 16, data_len);
351526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (aes_128_eax_encrypt(data->tek, nonce, sizeof(nonce),
352526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				wpabuf_head(resp),
353526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				sizeof(struct eap_hdr) + 1 + sizeof(*hdr4),
354526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				rpchannel + 4 + 16, data_len, rpchannel + 4)) {
355526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		os_free(decrypted);
356526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpabuf_free(resp);
357526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return NULL;
358526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
359526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	wpa_hexdump(MSG_DEBUG, "EAP-PSK: reply message (PCHANNEL)",
360526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		    rpchannel, 4 + 16 + data_len);
361526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
362526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	wpa_printf(MSG_DEBUG, "EAP-PSK: Completed %ssuccessfully",
363526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		   failed ? "un" : "");
364526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	data->state = PSK_DONE;
365526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	ret->methodState = METHOD_DONE;
366526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	ret->decision = failed ? DECISION_FAIL : DECISION_UNCOND_SUCC;
367526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
368526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	os_free(decrypted);
369526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
370526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	return resp;
371526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}
372526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
373526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
374526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic struct wpabuf * eap_psk_process(struct eap_sm *sm, void *priv,
375526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				       struct eap_method_ret *ret,
376526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				       const struct wpabuf *reqData)
377526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{
378526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	struct eap_psk_data *data = priv;
379526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	const u8 *pos;
380526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	struct wpabuf *resp = NULL;
381526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	size_t len;
382526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
383526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PSK, reqData, &len);
384526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (pos == NULL) {
385526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		ret->ignore = TRUE;
386526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return NULL;
387526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
388526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
389526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	ret->ignore = FALSE;
390526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	ret->methodState = METHOD_MAY_CONT;
391526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	ret->decision = DECISION_FAIL;
392526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	ret->allowNotifications = TRUE;
393526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
394526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	switch (data->state) {
395526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	case PSK_INIT:
396526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		resp = eap_psk_process_1(data, ret, reqData);
397526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		break;
398526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	case PSK_MAC_SENT:
399526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		resp = eap_psk_process_3(data, ret, reqData);
400526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		break;
401526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	case PSK_DONE:
402526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_printf(MSG_DEBUG, "EAP-PSK: in DONE state - ignore "
403526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			   "unexpected message");
404526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		ret->ignore = TRUE;
405526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return NULL;
406526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
407526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
408526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (ret->methodState == METHOD_DONE) {
409526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		ret->allowNotifications = FALSE;
410526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
411526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
412526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	return resp;
413526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}
414526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
415526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
416526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic Boolean eap_psk_isKeyAvailable(struct eap_sm *sm, void *priv)
417526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{
418526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	struct eap_psk_data *data = priv;
419526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	return data->state == PSK_DONE;
420526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}
421526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
422526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
423526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic u8 * eap_psk_getKey(struct eap_sm *sm, void *priv, size_t *len)
424526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{
425526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	struct eap_psk_data *data = priv;
426526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	u8 *key;
427526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
428526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (data->state != PSK_DONE)
429526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return NULL;
430526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
431526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	key = os_malloc(EAP_MSK_LEN);
432526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (key == NULL)
433526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return NULL;
434526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
435526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	*len = EAP_MSK_LEN;
436526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	os_memcpy(key, data->msk, EAP_MSK_LEN);
437526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
438526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	return key;
439526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}
440526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
441526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
442526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic u8 * eap_psk_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
443526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{
444526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	struct eap_psk_data *data = priv;
445526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	u8 *key;
446526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
447526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (data->state != PSK_DONE)
448526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return NULL;
449526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
450526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	key = os_malloc(EAP_EMSK_LEN);
451526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (key == NULL)
452526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return NULL;
453526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
454526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	*len = EAP_EMSK_LEN;
455526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	os_memcpy(key, data->emsk, EAP_EMSK_LEN);
456526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
457526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	return key;
458526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}
459526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
460526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
461526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtint eap_peer_psk_register(void)
462526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{
463526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	struct eap_method *eap;
464526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	int ret;
465526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
466526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
467526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				    EAP_VENDOR_IETF, EAP_TYPE_PSK, "PSK");
468526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (eap == NULL)
469526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return -1;
470526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
471526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	eap->init = eap_psk_init;
472526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	eap->deinit = eap_psk_deinit;
473526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	eap->process = eap_psk_process;
474526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	eap->isKeyAvailable = eap_psk_isKeyAvailable;
475526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	eap->getKey = eap_psk_getKey;
476526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	eap->get_emsk = eap_psk_get_emsk;
477526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
478526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	ret = eap_peer_method_register(eap);
479526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (ret)
480526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		eap_peer_method_free(eap);
481526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	return ret;
482526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}
483