2
* EAP peer method: EAP-SAKE (RFC 4763)
3
* Copyright (c) 2006, Jouni Malinen <j@w1.fi>
5
* This program is free software; you can redistribute it and/or modify
6
* it under the terms of the GNU General Public License version 2 as
7
* published by the Free Software Foundation.
9
* Alternatively, this software may be distributed under the terms of BSD
12
* See README and COPYING for more details.
19
#include "config_ssid.h"
20
#include "eap_sake_common.h"
22
struct eap_sake_data {
23
enum { IDENTITY, CHALLENGE, CONFIRM, SUCCESS, FAILURE } state;
24
u8 root_secret_a[EAP_SAKE_ROOT_SECRET_LEN];
25
u8 root_secret_b[EAP_SAKE_ROOT_SECRET_LEN];
26
u8 rand_s[EAP_SAKE_RAND_LEN];
27
u8 rand_p[EAP_SAKE_RAND_LEN];
29
u8 auth[EAP_SAKE_TEK_AUTH_LEN];
30
u8 cipher[EAP_SAKE_TEK_CIPHER_LEN];
33
u8 emsk[EAP_EMSK_LEN];
43
static const char * eap_sake_state_txt(int state)
62
static void eap_sake_state(struct eap_sake_data *data, int state)
64
wpa_printf(MSG_DEBUG, "EAP-SAKE: %s -> %s",
65
eap_sake_state_txt(data->state),
66
eap_sake_state_txt(state));
71
static void eap_sake_deinit(struct eap_sm *sm, void *priv);
74
static void * eap_sake_init(struct eap_sm *sm)
76
struct wpa_ssid *config = eap_get_config(sm);
77
struct eap_sake_data *data;
80
wpa_printf(MSG_INFO, "EAP-SAKE: No configuration found");
84
if (!config->eappsk ||
85
config->eappsk_len != 2 * EAP_SAKE_ROOT_SECRET_LEN) {
86
wpa_printf(MSG_INFO, "EAP-SAKE: No key (eappsk) of correct "
91
data = os_zalloc(sizeof(*data));
94
data->state = IDENTITY;
97
data->peerid = os_malloc(config->nai_len);
98
if (data->peerid == NULL) {
99
eap_sake_deinit(sm, data);
102
os_memcpy(data->peerid, config->nai, config->nai_len);
103
data->peerid_len = config->nai_len;
106
os_memcpy(data->root_secret_a, config->eappsk,
107
EAP_SAKE_ROOT_SECRET_LEN);
108
os_memcpy(data->root_secret_b,
109
config->eappsk + EAP_SAKE_ROOT_SECRET_LEN,
110
EAP_SAKE_ROOT_SECRET_LEN);
116
static void eap_sake_deinit(struct eap_sm *sm, void *priv)
118
struct eap_sake_data *data = priv;
119
os_free(data->serverid);
120
os_free(data->peerid);
125
static u8 * eap_sake_build_msg(struct eap_sake_data *data, u8 **payload,
126
int id, size_t *length, u8 subtype)
128
struct eap_sake_hdr *req;
131
*length += sizeof(struct eap_sake_hdr);
133
msg = os_zalloc(*length);
135
wpa_printf(MSG_ERROR, "EAP-SAKE: Failed to allocate memory "
140
req = (struct eap_sake_hdr *) msg;
141
req->code = EAP_CODE_RESPONSE;
142
req->identifier = id;
143
req->length = htons((u16) *length);
144
req->type = EAP_TYPE_SAKE;
145
req->version = EAP_SAKE_VERSION;
146
req->session_id = data->session_id;
147
req->subtype = subtype;
148
*payload = (u8 *) (req + 1);
154
static u8 * eap_sake_process_identity(struct eap_sm *sm,
155
struct eap_sake_data *data,
156
struct eap_method_ret *ret,
157
const u8 *reqData, size_t reqDataLen,
158
const u8 *payload, size_t payload_len,
161
struct eap_sake_parse_attr attr;
163
const struct eap_hdr *hdr = (const struct eap_hdr *) reqData;
165
if (data->state != IDENTITY) {
170
wpa_printf(MSG_DEBUG, "EAP-SAKE: Received Request/Identity");
172
if (eap_sake_parse_attributes(payload, payload_len, &attr))
175
if (!attr.perm_id_req && !attr.any_id_req) {
176
wpa_printf(MSG_INFO, "EAP-SAKE: No AT_PERM_ID_REQ or "
177
"AT_ANY_ID_REQ in Request/Identity");
181
wpa_printf(MSG_DEBUG, "EAP-SAKE: Sending Response/Identity");
183
*respDataLen = 2 + data->peerid_len;
184
resp = eap_sake_build_msg(data, &rpos, hdr->identifier, respDataLen,
185
EAP_SAKE_SUBTYPE_IDENTITY);
189
wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_PEERID");
190
*rpos++ = EAP_SAKE_AT_PEERID;
191
*rpos++ = 2 + data->peerid_len;
193
os_memcpy(rpos, data->peerid, data->peerid_len);
195
eap_sake_state(data, CHALLENGE);
201
static u8 * eap_sake_process_challenge(struct eap_sm *sm,
202
struct eap_sake_data *data,
203
struct eap_method_ret *ret,
204
const u8 *reqData, size_t reqDataLen,
205
const u8 *payload, size_t payload_len,
208
struct eap_sake_parse_attr attr;
210
const struct eap_hdr *hdr = (const struct eap_hdr *) reqData;
212
if (data->state != IDENTITY && data->state != CHALLENGE) {
213
wpa_printf(MSG_DEBUG, "EAP-SAKE: Request/Challenge received "
214
"in unexpected state (%d)", data->state);
218
if (data->state == IDENTITY)
219
eap_sake_state(data, CHALLENGE);
221
wpa_printf(MSG_DEBUG, "EAP-SAKE: Received Request/Challenge");
223
if (eap_sake_parse_attributes(payload, payload_len, &attr))
227
wpa_printf(MSG_INFO, "EAP-SAKE: Request/Challenge did not "
228
"include AT_RAND_S");
232
os_memcpy(data->rand_s, attr.rand_s, EAP_SAKE_RAND_LEN);
233
wpa_hexdump(MSG_MSGDUMP, "EAP-SAKE: RAND_S (server rand)",
234
data->rand_s, EAP_SAKE_RAND_LEN);
236
if (hostapd_get_rand(data->rand_p, EAP_SAKE_RAND_LEN)) {
237
wpa_printf(MSG_ERROR, "EAP-SAKE: Failed to get random data");
240
wpa_hexdump(MSG_MSGDUMP, "EAP-SAKE: RAND_P (peer rand)",
241
data->rand_p, EAP_SAKE_RAND_LEN);
243
os_free(data->serverid);
244
data->serverid = NULL;
245
data->serverid_len = 0;
247
wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-SAKE: SERVERID",
248
attr.serverid, attr.serverid_len);
249
data->serverid = os_malloc(attr.serverid_len);
250
if (data->serverid == NULL)
252
os_memcpy(data->serverid, attr.serverid, attr.serverid_len);
253
data->serverid_len = attr.serverid_len;
256
eap_sake_derive_keys(data->root_secret_a, data->root_secret_b,
257
data->rand_s, data->rand_p,
258
(u8 *) &data->tek, data->msk, data->emsk);
260
wpa_printf(MSG_DEBUG, "EAP-SAKE: Sending Response/Challenge");
262
*respDataLen = 2 + EAP_SAKE_RAND_LEN + 2 + EAP_SAKE_MIC_LEN;
264
*respDataLen += 2 + data->peerid_len;
265
resp = eap_sake_build_msg(data, &rpos, hdr->identifier, respDataLen,
266
EAP_SAKE_SUBTYPE_CHALLENGE);
270
wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_RAND_P");
271
*rpos++ = EAP_SAKE_AT_RAND_P;
272
*rpos++ = 2 + EAP_SAKE_RAND_LEN;
273
os_memcpy(rpos, data->rand_p, EAP_SAKE_RAND_LEN);
274
rpos += EAP_SAKE_RAND_LEN;
277
wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_PEERID");
278
*rpos++ = EAP_SAKE_AT_PEERID;
279
*rpos++ = 2 + data->peerid_len;
280
os_memcpy(rpos, data->peerid, data->peerid_len);
281
rpos += data->peerid_len;
284
wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_MIC_P");
285
*rpos++ = EAP_SAKE_AT_MIC_P;
286
*rpos++ = 2 + EAP_SAKE_MIC_LEN;
287
if (eap_sake_compute_mic(data->tek.auth, data->rand_s, data->rand_p,
288
data->serverid, data->serverid_len,
289
data->peerid, data->peerid_len, 1,
290
resp, *respDataLen, rpos, rpos)) {
291
wpa_printf(MSG_INFO, "EAP-SAKE: Failed to compute MIC");
296
eap_sake_state(data, CONFIRM);
302
static u8 * eap_sake_process_confirm(struct eap_sm *sm,
303
struct eap_sake_data *data,
304
struct eap_method_ret *ret,
305
const u8 *reqData, size_t reqDataLen,
306
const u8 *payload, size_t payload_len,
309
struct eap_sake_parse_attr attr;
310
u8 mic_s[EAP_SAKE_MIC_LEN];
312
const struct eap_hdr *hdr = (const struct eap_hdr *) reqData;
314
if (data->state != CONFIRM) {
319
wpa_printf(MSG_DEBUG, "EAP-SAKE: Received Request/Confirm");
321
if (eap_sake_parse_attributes(payload, payload_len, &attr))
325
wpa_printf(MSG_INFO, "EAP-SAKE: Request/Confirm did not "
330
eap_sake_compute_mic(data->tek.auth, data->rand_s, data->rand_p,
331
data->serverid, data->serverid_len,
332
data->peerid, data->peerid_len, 0,
333
reqData, reqDataLen, attr.mic_s, mic_s);
334
if (os_memcmp(attr.mic_s, mic_s, EAP_SAKE_MIC_LEN) != 0) {
335
wpa_printf(MSG_INFO, "EAP-SAKE: Incorrect AT_MIC_S");
336
eap_sake_state(data, FAILURE);
337
ret->methodState = METHOD_DONE;
338
ret->decision = DECISION_FAIL;
339
ret->allowNotifications = FALSE;
341
wpa_printf(MSG_DEBUG, "EAP-SAKE: Sending "
342
"Response/Auth-Reject");
343
return eap_sake_build_msg(data, &rpos, hdr->identifier,
345
EAP_SAKE_SUBTYPE_AUTH_REJECT);
348
wpa_printf(MSG_DEBUG, "EAP-SAKE: Sending Response/Confirm");
350
*respDataLen = 2 + EAP_SAKE_MIC_LEN;
351
resp = eap_sake_build_msg(data, &rpos, hdr->identifier, respDataLen,
352
EAP_SAKE_SUBTYPE_CONFIRM);
356
wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_MIC_P");
357
*rpos++ = EAP_SAKE_AT_MIC_P;
358
*rpos++ = 2 + EAP_SAKE_MIC_LEN;
359
if (eap_sake_compute_mic(data->tek.auth, data->rand_s, data->rand_p,
360
data->serverid, data->serverid_len,
361
data->peerid, data->peerid_len, 1,
362
resp, *respDataLen, rpos, rpos)) {
363
wpa_printf(MSG_INFO, "EAP-SAKE: Failed to compute MIC");
368
eap_sake_state(data, SUCCESS);
369
ret->methodState = METHOD_DONE;
370
ret->decision = DECISION_UNCOND_SUCC;
371
ret->allowNotifications = FALSE;
377
static u8 * eap_sake_process(struct eap_sm *sm, void *priv,
378
struct eap_method_ret *ret,
379
const u8 *reqData, size_t reqDataLen,
382
struct eap_sake_data *data = priv;
383
const struct eap_sake_hdr *req;
387
u8 subtype, session_id;
389
pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_SAKE,
390
reqData, reqDataLen, &len);
391
if (pos == NULL || len < 3) {
396
req = (const struct eap_sake_hdr *) reqData;
397
subtype = req->subtype;
398
session_id = req->session_id;
399
pos = (const u8 *) (req + 1);
400
end = reqData + be_to_host16(req->length);
402
wpa_printf(MSG_DEBUG, "EAP-SAKE: Received frame: subtype %d "
403
"session_id %d", subtype, session_id);
404
wpa_hexdump(MSG_DEBUG, "EAP-SAKE: Received attributes",
407
if (data->session_id_set && data->session_id != session_id) {
408
wpa_printf(MSG_INFO, "EAP-SAKE: Session ID mismatch (%d,%d)",
409
session_id, data->session_id);
413
data->session_id = session_id;
414
data->session_id_set = 1;
417
ret->methodState = METHOD_MAY_CONT;
418
ret->decision = DECISION_FAIL;
419
ret->allowNotifications = TRUE;
422
case EAP_SAKE_SUBTYPE_IDENTITY:
423
resp = eap_sake_process_identity(sm, data, ret, reqData,
424
reqDataLen, pos, end - pos,
427
case EAP_SAKE_SUBTYPE_CHALLENGE:
428
resp = eap_sake_process_challenge(sm, data, ret, reqData,
429
reqDataLen, pos, end - pos,
432
case EAP_SAKE_SUBTYPE_CONFIRM:
433
resp = eap_sake_process_confirm(sm, data, ret, reqData,
434
reqDataLen, pos, end - pos,
438
wpa_printf(MSG_DEBUG, "EAP-SAKE: Ignoring message with "
439
"unknown subtype %d", subtype);
444
if (ret->methodState == METHOD_DONE)
445
ret->allowNotifications = FALSE;
451
static Boolean eap_sake_isKeyAvailable(struct eap_sm *sm, void *priv)
453
struct eap_sake_data *data = priv;
454
return data->state == SUCCESS;
458
static u8 * eap_sake_getKey(struct eap_sm *sm, void *priv, size_t *len)
460
struct eap_sake_data *data = priv;
463
if (data->state != SUCCESS)
466
key = os_malloc(EAP_MSK_LEN);
469
os_memcpy(key, data->msk, EAP_MSK_LEN);
476
static u8 * eap_sake_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
478
struct eap_sake_data *data = priv;
481
if (data->state != SUCCESS)
484
key = os_malloc(EAP_EMSK_LEN);
487
os_memcpy(key, data->emsk, EAP_EMSK_LEN);
494
int eap_peer_sake_register(void)
496
struct eap_method *eap;
499
eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
500
EAP_VENDOR_IETF, EAP_TYPE_SAKE, "SAKE");
504
eap->init = eap_sake_init;
505
eap->deinit = eap_sake_deinit;
506
eap->process = eap_sake_process;
507
eap->isKeyAvailable = eap_sake_isKeyAvailable;
508
eap->getKey = eap_sake_getKey;
509
eap->get_emsk = eap_sake_get_emsk;
511
ret = eap_peer_method_register(eap);
513
eap_peer_method_free(eap);