1845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project/*
2845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project * EAP peer method: EAP-PSK (RFC 4764)
3845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project * Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi>
4845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project *
5845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project * This program is free software; you can redistribute it and/or modify
6845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project * it under the terms of the GNU General Public License version 2 as
7845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project * published by the Free Software Foundation.
8845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project *
9845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project * Alternatively, this software may be distributed under the terms of BSD
10845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project * license.
11845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project *
12845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project * See README and COPYING for more details.
13845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project *
14845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project * Note: EAP-PSK is an EAP authentication method and as such, completely
15845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project * different from WPA-PSK. This file is not needed for WPA-PSK functionality.
16845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project */
17845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project
18845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project#include "includes.h"
19845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project
20845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project#include "common.h"
21845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project#include "eap_i.h"
22845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project#include "config_ssid.h"
23845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project#include "md5.h"
24845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project#include "aes_wrap.h"
25845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project#include "eap_psk_common.h"
26845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project
27845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project
28845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Projectstruct eap_psk_data {
29845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	enum { PSK_INIT, PSK_MAC_SENT, PSK_DONE } state;
30845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	u8 rand_p[EAP_PSK_RAND_LEN];
31845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	u8 ak[EAP_PSK_AK_LEN], kdk[EAP_PSK_KDK_LEN], tek[EAP_PSK_TEK_LEN];
32845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	u8 *id_s, *id_p;
33845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	size_t id_s_len, id_p_len;
34845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	u8 msk[EAP_MSK_LEN];
35845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	u8 emsk[EAP_EMSK_LEN];
36845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project};
37845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project
38845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project
39845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Projectstatic void * eap_psk_init(struct eap_sm *sm)
40845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project{
41845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	struct wpa_ssid *config = eap_get_config(sm);
42845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	struct eap_psk_data *data;
43845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project
44845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	if (config == NULL || !config->eappsk) {
45845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project		wpa_printf(MSG_INFO, "EAP-PSK: pre-shared key not configured");
46845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project		return NULL;
47845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	}
48845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project
49845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	data = os_zalloc(sizeof(*data));
50845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	if (data == NULL)
51845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project		return NULL;
52845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	eap_psk_key_setup(config->eappsk, data->ak, data->kdk);
53845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	wpa_hexdump_key(MSG_DEBUG, "EAP-PSK: AK", data->ak, EAP_PSK_AK_LEN);
54845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	wpa_hexdump_key(MSG_DEBUG, "EAP-PSK: KDK", data->kdk, EAP_PSK_KDK_LEN);
55845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	data->state = PSK_INIT;
56845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project
57845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	if (config->nai) {
58845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project		data->id_p = os_malloc(config->nai_len);
59845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project		if (data->id_p)
60845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project			os_memcpy(data->id_p, config->nai, config->nai_len);
61845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project		data->id_p_len = config->nai_len;
62845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	}
63845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	if (data->id_p == NULL) {
64845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project		wpa_printf(MSG_INFO, "EAP-PSK: could not get own identity");
65845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project		os_free(data);
66845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project		return NULL;
67845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	}
68845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project
69845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	return data;
70845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project}
71845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project
72845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project
73845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Projectstatic void eap_psk_deinit(struct eap_sm *sm, void *priv)
74845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project{
75845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	struct eap_psk_data *data = priv;
76845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	os_free(data->id_s);
77845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	os_free(data->id_p);
78845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	os_free(data);
79845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project}
80845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project
81845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project
82845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Projectstatic u8 * eap_psk_process_1(struct eap_psk_data *data,
83845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project			      struct eap_method_ret *ret,
84845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project			      const u8 *reqData, size_t reqDataLen,
85845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project			      size_t *respDataLen)
86845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project{
87845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	const struct eap_psk_hdr_1 *hdr1;
88845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	struct eap_psk_hdr_2 *hdr2;
89845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	u8 *resp, *buf, *pos;
90845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	size_t buflen;
91845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project
92845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	wpa_printf(MSG_DEBUG, "EAP-PSK: in INIT state");
93845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project
94845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	hdr1 = (const struct eap_psk_hdr_1 *) reqData;
95845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	if (reqDataLen < sizeof(*hdr1) ||
96845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	    be_to_host16(hdr1->length) < sizeof(*hdr1) ||
97845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	    be_to_host16(hdr1->length) > reqDataLen) {
98845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project		wpa_printf(MSG_INFO, "EAP-PSK: Invalid first message "
99845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project			   "length (%lu %d; expected %lu or more)",
100845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project			   (unsigned long) reqDataLen,
101845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project			   be_to_host16(hdr1->length),
102845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project			   (unsigned long) sizeof(*hdr1));
103845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project		ret->ignore = TRUE;
104845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project		return NULL;
105845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	}
106845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	wpa_printf(MSG_DEBUG, "EAP-PSK: Flags=0x%x", hdr1->flags);
107845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	if (EAP_PSK_FLAGS_GET_T(hdr1->flags) != 0) {
108845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project		wpa_printf(MSG_INFO, "EAP-PSK: Unexpected T=%d (expected 0)",
109845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project			   EAP_PSK_FLAGS_GET_T(hdr1->flags));
110845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project		ret->methodState = METHOD_DONE;
111845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project		ret->decision = DECISION_FAIL;
112845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project		return NULL;
113845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	}
114845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	wpa_hexdump(MSG_DEBUG, "EAP-PSK: RAND_S", hdr1->rand_s,
115845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project		    EAP_PSK_RAND_LEN);
116845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	os_free(data->id_s);
117845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	data->id_s_len = be_to_host16(hdr1->length) - sizeof(*hdr1);
118845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	data->id_s = os_malloc(data->id_s_len);
119845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	if (data->id_s == NULL) {
120845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project		wpa_printf(MSG_ERROR, "EAP-PSK: Failed to allocate memory for "
121845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project			   "ID_S (len=%lu)", (unsigned long) data->id_s_len);
122845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project		ret->ignore = TRUE;
123845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project		return NULL;
124845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	}
125845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	os_memcpy(data->id_s, (u8 *) (hdr1 + 1), data->id_s_len);
126845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	wpa_hexdump_ascii(MSG_DEBUG, "EAP-PSK: ID_S",
127845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project			  data->id_s, data->id_s_len);
128845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project
129845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	if (hostapd_get_rand(data->rand_p, EAP_PSK_RAND_LEN)) {
130845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project		wpa_printf(MSG_ERROR, "EAP-PSK: Failed to get random data");
131845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project		ret->ignore = TRUE;
132845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project		return NULL;
133845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	}
134845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project
135845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	*respDataLen = sizeof(*hdr2) + data->id_p_len;
136845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	resp = os_malloc(*respDataLen);
137845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	if (resp == NULL)
138845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project		return NULL;
139845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	hdr2 = (struct eap_psk_hdr_2 *) resp;
140845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	hdr2->code = EAP_CODE_RESPONSE;
141845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	hdr2->identifier = hdr1->identifier;
142845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	hdr2->length = host_to_be16(*respDataLen);
143845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	hdr2->type = EAP_TYPE_PSK;
144845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	hdr2->flags = EAP_PSK_FLAGS_SET_T(1); /* T=1 */
145845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	os_memcpy(hdr2->rand_s, hdr1->rand_s, EAP_PSK_RAND_LEN);
146845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	os_memcpy(hdr2->rand_p, data->rand_p, EAP_PSK_RAND_LEN);
147845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	os_memcpy((u8 *) (hdr2 + 1), data->id_p, data->id_p_len);
148845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	/* MAC_P = OMAC1-AES-128(AK, ID_P||ID_S||RAND_S||RAND_P) */
149845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	buflen = data->id_p_len + data->id_s_len + 2 * EAP_PSK_RAND_LEN;
150845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	buf = os_malloc(buflen);
151845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	if (buf == NULL) {
152845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project		os_free(resp);
153845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project		return NULL;
154845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	}
155845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	os_memcpy(buf, data->id_p, data->id_p_len);
156845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	pos = buf + data->id_p_len;
157845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	os_memcpy(pos, data->id_s, data->id_s_len);
158845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	pos += data->id_s_len;
159845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	os_memcpy(pos, hdr1->rand_s, EAP_PSK_RAND_LEN);
160845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	pos += EAP_PSK_RAND_LEN;
161845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	os_memcpy(pos, data->rand_p, EAP_PSK_RAND_LEN);
162845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	omac1_aes_128(data->ak, buf, buflen, hdr2->mac_p);
163845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	os_free(buf);
164845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	wpa_hexdump(MSG_DEBUG, "EAP-PSK: RAND_P", hdr2->rand_p,
165845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project		    EAP_PSK_RAND_LEN);
166845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	wpa_hexdump(MSG_DEBUG, "EAP-PSK: MAC_P", hdr2->mac_p, EAP_PSK_MAC_LEN);
167845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	wpa_hexdump_ascii(MSG_DEBUG, "EAP-PSK: ID_P",
168845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project			  (u8 *) (hdr2 + 1), data->id_p_len);
169845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project
170845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	data->state = PSK_MAC_SENT;
171845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project
172845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	return resp;
173845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project}
174845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project
175845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project
176845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Projectstatic u8 * eap_psk_process_3(struct eap_psk_data *data,
177845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project			      struct eap_method_ret *ret,
178845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project			      const u8 *reqData, size_t reqDataLen,
179845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project			      size_t *respDataLen)
180845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project{
181845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	const struct eap_psk_hdr_3 *hdr3;
182845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	struct eap_psk_hdr_4 *hdr4;
183845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	u8 *resp, *buf, *rpchannel, nonce[16], *decrypted;
184845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	const u8 *pchannel, *tag, *msg;
185845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	u8 mac[EAP_PSK_MAC_LEN];
186845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	size_t buflen, left, data_len;
187845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	int failed = 0;
188845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project
189845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	wpa_printf(MSG_DEBUG, "EAP-PSK: in MAC_SENT state");
190845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project
191845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	hdr3 = (const struct eap_psk_hdr_3 *) reqData;
192845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	left = be_to_host16(hdr3->length);
193845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	if (left < sizeof(*hdr3) || reqDataLen < left) {
194845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project		wpa_printf(MSG_INFO, "EAP-PSK: Invalid third message "
195845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project			   "length (%lu %d; expected %lu)",
196845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project			   (unsigned long) reqDataLen,
197845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project			   be_to_host16(hdr3->length),
198845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project			   (unsigned long) sizeof(*hdr3));
199845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project		ret->ignore = TRUE;
200845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project		return NULL;
201845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	}
202845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	left -= sizeof(*hdr3);
203845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	pchannel = (const u8 *) (hdr3 + 1);
204845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	wpa_printf(MSG_DEBUG, "EAP-PSK: Flags=0x%x", hdr3->flags);
205845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	if (EAP_PSK_FLAGS_GET_T(hdr3->flags) != 2) {
206845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project		wpa_printf(MSG_INFO, "EAP-PSK: Unexpected T=%d (expected 2)",
207845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project			   EAP_PSK_FLAGS_GET_T(hdr3->flags));
208845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project		ret->methodState = METHOD_DONE;
209845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project		ret->decision = DECISION_FAIL;
210845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project		return NULL;
211845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	}
212845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	wpa_hexdump(MSG_DEBUG, "EAP-PSK: RAND_S", hdr3->rand_s,
213845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project		    EAP_PSK_RAND_LEN);
214845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	wpa_hexdump(MSG_DEBUG, "EAP-PSK: MAC_S", hdr3->mac_s, EAP_PSK_MAC_LEN);
215845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	wpa_hexdump(MSG_DEBUG, "EAP-PSK: PCHANNEL", pchannel, left);
216845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project
217845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	if (left < 4 + 16 + 1) {
218845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project		wpa_printf(MSG_INFO, "EAP-PSK: Too short PCHANNEL data in "
219845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project			   "third message (len=%lu, expected 21)",
220845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project			   (unsigned long) left);
221845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project		ret->ignore = TRUE;
222845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project		return NULL;
223845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	}
224845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project
225845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	/* MAC_S = OMAC1-AES-128(AK, ID_S||RAND_P) */
226845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	buflen = data->id_s_len + EAP_PSK_RAND_LEN;
227845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	buf = os_malloc(buflen);
228845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	if (buf == NULL)
229845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project		return NULL;
230845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	os_memcpy(buf, data->id_s, data->id_s_len);
231845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	os_memcpy(buf + data->id_s_len, data->rand_p, EAP_PSK_RAND_LEN);
232845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	omac1_aes_128(data->ak, buf, buflen, mac);
233845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	os_free(buf);
234845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	if (os_memcmp(mac, hdr3->mac_s, EAP_PSK_MAC_LEN) != 0) {
235845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project		wpa_printf(MSG_WARNING, "EAP-PSK: Invalid MAC_S in third "
236845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project			   "message");
237845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project		ret->methodState = METHOD_DONE;
238845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project		ret->decision = DECISION_FAIL;
239845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project		return NULL;
240845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	}
241845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	wpa_printf(MSG_DEBUG, "EAP-PSK: MAC_S verified successfully");
242845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project
243845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	eap_psk_derive_keys(data->kdk, data->rand_p, data->tek,
244845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project			    data->msk, data->emsk);
245845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	wpa_hexdump_key(MSG_DEBUG, "EAP-PSK: TEK", data->tek, EAP_PSK_TEK_LEN);
246845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	wpa_hexdump_key(MSG_DEBUG, "EAP-PSK: MSK", data->msk, EAP_MSK_LEN);
247845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	wpa_hexdump_key(MSG_DEBUG, "EAP-PSK: EMSK", data->emsk, EAP_EMSK_LEN);
248845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project
249845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	os_memset(nonce, 0, 12);
250845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	os_memcpy(nonce + 12, pchannel, 4);
251845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	pchannel += 4;
252845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	left -= 4;
253845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project
254845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	tag = pchannel;
255845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	pchannel += 16;
256845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	left -= 16;
257845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project
258845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	msg = pchannel;
259845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project
260845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	wpa_hexdump(MSG_MSGDUMP, "EAP-PSK: PCHANNEL - nonce",
261845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project		    nonce, sizeof(nonce));
262845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	wpa_hexdump(MSG_MSGDUMP, "EAP-PSK: PCHANNEL - hdr", reqData, 5);
263845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	wpa_hexdump(MSG_MSGDUMP, "EAP-PSK: PCHANNEL - cipher msg", msg, left);
264845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project
265845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	decrypted = os_malloc(left);
266845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	if (decrypted == NULL) {
267845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project		ret->methodState = METHOD_DONE;
268845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project		ret->decision = DECISION_FAIL;
269845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project		return NULL;
270845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	}
271845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	os_memcpy(decrypted, msg, left);
272845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project
273845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	if (aes_128_eax_decrypt(data->tek, nonce, sizeof(nonce),
274845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project				reqData, 22, decrypted, left, tag)) {
275845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project		wpa_printf(MSG_WARNING, "EAP-PSK: PCHANNEL decryption failed");
276845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project		os_free(decrypted);
277845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project		return NULL;
278845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	}
279845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	wpa_hexdump(MSG_DEBUG, "EAP-PSK: Decrypted PCHANNEL message",
280845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project		    decrypted, left);
281845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project
282845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	/* Verify R flag */
283845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	switch (decrypted[0] >> 6) {
284845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	case EAP_PSK_R_FLAG_CONT:
285845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project		wpa_printf(MSG_DEBUG, "EAP-PSK: R flag - CONT - unsupported");
286845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project		failed = 1;
287845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project		break;
288845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	case EAP_PSK_R_FLAG_DONE_SUCCESS:
289845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project		wpa_printf(MSG_DEBUG, "EAP-PSK: R flag - DONE_SUCCESS");
290845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project		break;
291845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	case EAP_PSK_R_FLAG_DONE_FAILURE:
292845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project		wpa_printf(MSG_DEBUG, "EAP-PSK: R flag - DONE_FAILURE");
293845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project		wpa_printf(MSG_INFO, "EAP-PSK: Authentication server rejected "
294845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project			   "authentication");
295845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project		failed = 1;
296845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project		break;
297845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	}
298845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project
299845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	*respDataLen = sizeof(*hdr4) + 4 + 16 + 1;
300845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	resp = os_malloc(*respDataLen + 1);
301845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	if (resp == NULL) {
302845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project		os_free(decrypted);
303845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project		return NULL;
304845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	}
305845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	hdr4 = (struct eap_psk_hdr_4 *) resp;
306845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	hdr4->code = EAP_CODE_RESPONSE;
307845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	hdr4->identifier = hdr3->identifier;
308845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	hdr4->length = host_to_be16(*respDataLen);
309845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	hdr4->type = EAP_TYPE_PSK;
310845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	hdr4->flags = EAP_PSK_FLAGS_SET_T(3); /* T=3 */
311845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	os_memcpy(hdr4->rand_s, hdr3->rand_s, EAP_PSK_RAND_LEN);
312845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	rpchannel = (u8 *) (hdr4 + 1);
313845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project
314845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	/* nonce++ */
315845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	inc_byte_array(nonce, sizeof(nonce));
316845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	os_memcpy(rpchannel, nonce + 12, 4);
317845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project
318845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	data_len = 1;
319845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	if (decrypted[0] & EAP_PSK_E_FLAG) {
320845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project		wpa_printf(MSG_DEBUG, "EAP-PSK: Unsupported E (Ext) flag");
321845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project		failed = 1;
322845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project		rpchannel[4 + 16] = (EAP_PSK_R_FLAG_DONE_FAILURE << 6) |
323845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project			EAP_PSK_E_FLAG;
324845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project		if (left > 1) {
325845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project			/* Add empty EXT_Payload with same EXT_Type */
326845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project			(*respDataLen)++;
327845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project			hdr4->length = host_to_be16(*respDataLen);
328845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project			rpchannel[4 + 16 + 1] = decrypted[1];
329845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project			data_len++;
330845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project		}
331845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	} else if (failed)
332845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project		rpchannel[4 + 16] = EAP_PSK_R_FLAG_DONE_FAILURE << 6;
333845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	else
334845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project		rpchannel[4 + 16] = EAP_PSK_R_FLAG_DONE_SUCCESS << 6;
335845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project
336845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	wpa_hexdump(MSG_DEBUG, "EAP-PSK: reply message (plaintext)",
337845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project		    rpchannel + 4 + 16, data_len);
338845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	aes_128_eax_encrypt(data->tek, nonce, sizeof(nonce), resp, 22,
339845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project			    rpchannel + 4 + 16, data_len, rpchannel + 4);
340845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	wpa_hexdump(MSG_DEBUG, "EAP-PSK: reply message (PCHANNEL)",
341845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project		    rpchannel, 4 + 16 + data_len);
342845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project
343845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	wpa_printf(MSG_DEBUG, "EAP-PSK: Completed %ssuccessfully",
344845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project		   failed ? "un" : "");
345845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	data->state = PSK_DONE;
346845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	ret->methodState = METHOD_DONE;
347845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	ret->decision = failed ? DECISION_FAIL : DECISION_UNCOND_SUCC;
348845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project
349845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	os_free(decrypted);
350845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project
351845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	return resp;
352845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project}
353845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project
354845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project
355845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Projectstatic u8 * eap_psk_process(struct eap_sm *sm, void *priv,
356845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project			    struct eap_method_ret *ret,
357845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project			    const u8 *reqData, size_t reqDataLen,
358845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project			    size_t *respDataLen)
359845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project{
360845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	struct eap_psk_data *data = priv;
361845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	const u8 *pos;
362845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	u8 *resp = NULL;
363845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	size_t len;
364845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project
365845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PSK,
366845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project			       reqData, reqDataLen, &len);
367845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	if (pos == NULL) {
368845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project		ret->ignore = TRUE;
369845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project		return NULL;
370845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	}
371845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	len += sizeof(struct eap_hdr) + 1;
372845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project
373845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	ret->ignore = FALSE;
374845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	ret->methodState = METHOD_MAY_CONT;
375845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	ret->decision = DECISION_FAIL;
376845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	ret->allowNotifications = TRUE;
377845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project
378845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	switch (data->state) {
379845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	case PSK_INIT:
380845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project		resp = eap_psk_process_1(data, ret, reqData, len,
381845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project					 respDataLen);
382845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project		break;
383845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	case PSK_MAC_SENT:
384845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project		resp = eap_psk_process_3(data, ret, reqData, len,
385845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project					 respDataLen);
386845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project		break;
387845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	case PSK_DONE:
388845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project		wpa_printf(MSG_DEBUG, "EAP-PSK: in DONE state - ignore "
389845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project			   "unexpected message");
390845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project		ret->ignore = TRUE;
391845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project		return NULL;
392845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	}
393845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project
394845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	if (ret->methodState == METHOD_DONE) {
395845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project		ret->allowNotifications = FALSE;
396845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	}
397845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project
398845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	return resp;
399845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project}
400845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project
401845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project
402845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Projectstatic Boolean eap_psk_isKeyAvailable(struct eap_sm *sm, void *priv)
403845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project{
404845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	struct eap_psk_data *data = priv;
405845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	return data->state == PSK_DONE;
406845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project}
407845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project
408845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project
409845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Projectstatic u8 * eap_psk_getKey(struct eap_sm *sm, void *priv, size_t *len)
410845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project{
411845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	struct eap_psk_data *data = priv;
412845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	u8 *key;
413845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project
414845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	if (data->state != PSK_DONE)
415845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project		return NULL;
416845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project
417845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	key = os_malloc(EAP_MSK_LEN);
418845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	if (key == NULL)
419845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project		return NULL;
420845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project
421845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	*len = EAP_MSK_LEN;
422845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	os_memcpy(key, data->msk, EAP_MSK_LEN);
423845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project
424845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	return key;
425845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project}
426845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project
427845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project
428845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Projectstatic u8 * eap_psk_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
429845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project{
430845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	struct eap_psk_data *data = priv;
431845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	u8 *key;
432845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project
433845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	if (data->state != PSK_DONE)
434845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project		return NULL;
435845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project
436845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	key = os_malloc(EAP_EMSK_LEN);
437845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	if (key == NULL)
438845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project		return NULL;
439845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project
440845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	*len = EAP_EMSK_LEN;
441845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	os_memcpy(key, data->emsk, EAP_EMSK_LEN);
442845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project
443845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	return key;
444845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project}
445845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project
446845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project
447845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Projectint eap_peer_psk_register(void)
448845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project{
449845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	struct eap_method *eap;
450845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	int ret;
451845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project
452845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
453845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project				    EAP_VENDOR_IETF, EAP_TYPE_PSK, "PSK");
454845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	if (eap == NULL)
455845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project		return -1;
456845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project
457845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	eap->init = eap_psk_init;
458845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	eap->deinit = eap_psk_deinit;
459845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	eap->process = eap_psk_process;
460845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	eap->isKeyAvailable = eap_psk_isKeyAvailable;
461845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	eap->getKey = eap_psk_getKey;
462845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	eap->get_emsk = eap_psk_get_emsk;
463845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project
464845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	ret = eap_peer_method_register(eap);
465845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	if (ret)
466845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project		eap_peer_method_free(eap);
467845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project	return ret;
468845e0124d42b67ef926fbae32a7f61d2e5109ebdThe Android Open Source Project}
469