2
* EAP peer method: EAP-SAKE (draft-vanderveen-eap-sake-01.txt)
3
* Copyright (c) 2006, Jouni Malinen <jkmaline@cc.hut.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 "wpa_supplicant.h"
20
#include "config_ssid.h"
21
#include "eap_sake_common.h"
23
struct eap_sake_data {
24
enum { IDENTITY, CHALLENGE, CONFIRM, SUCCESS, FAILURE } state;
25
u8 root_secret_a[EAP_SAKE_ROOT_SECRET_LEN];
26
u8 root_secret_b[EAP_SAKE_ROOT_SECRET_LEN];
27
u8 rand_s[EAP_SAKE_RAND_LEN];
28
u8 rand_p[EAP_SAKE_RAND_LEN];
30
u8 auth[EAP_SAKE_TEK_AUTH_LEN];
31
u8 cipher[EAP_SAKE_TEK_CIPHER_LEN];
44
static const char * eap_sake_state_txt(int state)
63
static void eap_sake_state(struct eap_sake_data *data, int state)
65
wpa_printf(MSG_DEBUG, "EAP-SAKE: %s -> %s",
66
eap_sake_state_txt(data->state),
67
eap_sake_state_txt(state));
72
static void eap_sake_deinit(struct eap_sm *sm, void *priv);
75
static void * eap_sake_init(struct eap_sm *sm)
77
struct wpa_ssid *config = eap_get_config(sm);
78
struct eap_sake_data *data;
81
wpa_printf(MSG_INFO, "EAP-SAKE: No configuration found");
85
if (!config->eappsk ||
86
config->eappsk_len != 2 * EAP_SAKE_ROOT_SECRET_LEN) {
87
wpa_printf(MSG_INFO, "EAP-SAKE: No key (eappsk) of correct "
92
data = wpa_zalloc(sizeof(*data));
95
data->state = IDENTITY;
98
data->peerid = malloc(config->nai_len);
99
if (data->peerid == NULL) {
100
eap_sake_deinit(sm, data);
103
memcpy(data->peerid, config->nai, config->nai_len);
104
data->peerid_len = config->nai_len;
107
memcpy(data->root_secret_a, config->eappsk, EAP_SAKE_ROOT_SECRET_LEN);
108
memcpy(data->root_secret_b, config->eappsk + EAP_SAKE_ROOT_SECRET_LEN,
109
EAP_SAKE_ROOT_SECRET_LEN);
115
static void eap_sake_deinit(struct eap_sm *sm, void *priv)
117
struct eap_sake_data *data = priv;
118
free(data->serverid);
124
static u8 * eap_sake_build_msg(struct eap_sake_data *data, u8 **payload,
125
int id, size_t *length, u8 subtype)
127
struct eap_sake_hdr *req;
128
struct eap_sake_exp_hdr *ereq;
132
*length += data->expanded_eap ? sizeof(struct eap_sake_exp_hdr) :
133
sizeof(struct eap_sake_hdr);
135
/* Pad to 32-bit boundary; minimum pad length is 2. */
153
msg = wpa_zalloc(*length);
155
wpa_printf(MSG_ERROR, "EAP-SAKE: Failed to allocate memory "
160
if (data->expanded_eap) {
161
ereq = (struct eap_sake_exp_hdr *) msg;
162
ereq->code = EAP_CODE_RESPONSE;
163
ereq->identifier = id;
164
ereq->length = htons((u16) *length);
165
ereq->type = EAP_TYPE_EXPANDED;
166
WPA_PUT_BE24(ereq->vendor_id, EAP_VENDOR_IETF);
167
WPA_PUT_BE32(ereq->vendor_type, EAP_TYPE_SAKE);
169
ereq->version = EAP_SAKE_VERSION;
170
ereq->session_id = data->session_id;
171
ereq->subtype = subtype;
172
*payload = (u8 *) (ereq + 1);
174
req = (struct eap_sake_hdr *) msg;
175
req->code = EAP_CODE_RESPONSE;
176
req->identifier = id;
177
req->length = htons((u16) *length);
178
req->type = EAP_TYPE_SAKE;
179
req->version = EAP_SAKE_VERSION;
180
req->session_id = data->session_id;
181
req->subtype = subtype;
182
*payload = (u8 *) (req + 1);
186
u8 *pos = &msg[*length - pad];
187
*pos++ = EAP_SAKE_AT_PADDING;
195
static u8 * eap_sake_process_identity(struct eap_sm *sm,
196
struct eap_sake_data *data,
197
struct eap_method_ret *ret,
198
const u8 *reqData, size_t reqDataLen,
199
const u8 *payload, size_t payload_len,
202
struct eap_sake_parse_attr attr;
204
const struct eap_hdr *hdr = (const struct eap_hdr *) reqData;
206
if (data->state != IDENTITY) {
211
wpa_printf(MSG_DEBUG, "EAP-SAKE: Received Request/Identity");
213
if (eap_sake_parse_attributes(payload, payload_len, &attr))
216
if (!attr.perm_id_req && !attr.any_id_req) {
217
wpa_printf(MSG_INFO, "EAP-SAKE: No AT_PERM_ID_REQ or "
218
"AT_ANY_ID_REQ in Request/Identity");
222
wpa_printf(MSG_DEBUG, "EAP-SAKE: Sending Response/Identity");
224
*respDataLen = 2 + data->peerid_len;
225
resp = eap_sake_build_msg(data, &rpos, hdr->identifier, respDataLen,
226
EAP_SAKE_SUBTYPE_IDENTITY);
230
wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_PEERID");
231
*rpos++ = EAP_SAKE_AT_PEERID;
232
*rpos++ = 2 + data->peerid_len;
234
memcpy(rpos, data->peerid, data->peerid_len);
236
eap_sake_state(data, CHALLENGE);
242
static u8 * eap_sake_process_challenge(struct eap_sm *sm,
243
struct eap_sake_data *data,
244
struct eap_method_ret *ret,
245
const u8 *reqData, size_t reqDataLen,
246
const u8 *payload, size_t payload_len,
249
struct eap_sake_parse_attr attr;
251
const struct eap_hdr *hdr = (const struct eap_hdr *) reqData;
253
if (data->state != IDENTITY && data->state != CHALLENGE) {
254
wpa_printf(MSG_DEBUG, "EAP-SAKE: Request/Challenge received "
255
"in unexpected state (%d)", data->state);
259
if (data->state == IDENTITY)
260
eap_sake_state(data, CHALLENGE);
262
wpa_printf(MSG_DEBUG, "EAP-SAKE: Received Request/Challenge");
264
if (eap_sake_parse_attributes(payload, payload_len, &attr))
268
wpa_printf(MSG_INFO, "EAP-SAKE: Request/Challenge did not "
269
"include AT_RAND_S");
273
memcpy(data->rand_s, attr.rand_s, EAP_SAKE_RAND_LEN);
274
wpa_hexdump(MSG_MSGDUMP, "EAP-SAKE: RAND_S (server rand)",
275
data->rand_s, EAP_SAKE_RAND_LEN);
277
if (hostapd_get_rand(data->rand_p, EAP_SAKE_RAND_LEN)) {
278
wpa_printf(MSG_ERROR, "EAP-SAKE: Failed to get random data");
281
wpa_hexdump(MSG_MSGDUMP, "EAP-SAKE: RAND_P (peer rand)",
282
data->rand_p, EAP_SAKE_RAND_LEN);
284
free(data->serverid);
285
data->serverid = NULL;
286
data->serverid_len = 0;
288
wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-SAKE: SERVERID",
289
attr.serverid, attr.serverid_len);
290
data->serverid = malloc(attr.serverid_len);
291
if (data->serverid == NULL)
293
memcpy(data->serverid, attr.serverid, attr.serverid_len);
294
data->serverid_len = attr.serverid_len;
297
eap_sake_derive_keys(data->root_secret_a, data->root_secret_b,
298
data->rand_s, data->rand_p,
299
(u8 *) &data->tek, data->msk);
301
wpa_printf(MSG_DEBUG, "EAP-SAKE: Sending Response/Challenge");
303
*respDataLen = 2 + EAP_SAKE_RAND_LEN + 2 + EAP_SAKE_MIC_LEN;
305
*respDataLen += 2 + data->peerid_len;
306
resp = eap_sake_build_msg(data, &rpos, hdr->identifier, respDataLen,
307
EAP_SAKE_SUBTYPE_CHALLENGE);
311
wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_RAND_P");
312
*rpos++ = EAP_SAKE_AT_RAND_P;
313
*rpos++ = 2 + EAP_SAKE_RAND_LEN;
314
memcpy(rpos, data->rand_p, EAP_SAKE_RAND_LEN);
315
rpos += EAP_SAKE_RAND_LEN;
318
wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_PEERID");
319
*rpos++ = EAP_SAKE_AT_PEERID;
320
*rpos++ = 2 + data->peerid_len;
321
memcpy(rpos, data->peerid, data->peerid_len);
322
rpos += data->peerid_len;
325
wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_MIC_P");
326
*rpos++ = EAP_SAKE_AT_MIC_P;
327
*rpos++ = 2 + EAP_SAKE_MIC_LEN;
328
if (eap_sake_compute_mic(data->tek.auth, data->rand_s, data->rand_p,
329
data->serverid, data->serverid_len,
330
data->peerid, data->peerid_len, 1,
331
resp, *respDataLen, rpos, rpos)) {
332
wpa_printf(MSG_INFO, "EAP-SAKE: Failed to compute MIC");
337
eap_sake_state(data, CONFIRM);
343
static u8 * eap_sake_process_confirm(struct eap_sm *sm,
344
struct eap_sake_data *data,
345
struct eap_method_ret *ret,
346
const u8 *reqData, size_t reqDataLen,
347
const u8 *payload, size_t payload_len,
350
struct eap_sake_parse_attr attr;
351
u8 mic_s[EAP_SAKE_MIC_LEN];
353
const struct eap_hdr *hdr = (const struct eap_hdr *) reqData;
355
if (data->state != CONFIRM) {
360
wpa_printf(MSG_DEBUG, "EAP-SAKE: Received Request/Confirm");
362
if (eap_sake_parse_attributes(payload, payload_len, &attr))
366
wpa_printf(MSG_INFO, "EAP-SAKE: Request/Confirm did not "
371
eap_sake_compute_mic(data->tek.auth, data->rand_s, data->rand_p,
372
data->serverid, data->serverid_len,
373
data->peerid, data->peerid_len, 0,
374
reqData, reqDataLen, attr.mic_s, mic_s);
375
if (memcmp(attr.mic_s, mic_s, EAP_SAKE_MIC_LEN) != 0) {
376
wpa_printf(MSG_INFO, "EAP-SAKE: Incorrect AT_MIC_S");
377
eap_sake_state(data, FAILURE);
378
ret->methodState = METHOD_DONE;
379
ret->decision = DECISION_FAIL;
380
ret->allowNotifications = FALSE;
382
wpa_printf(MSG_DEBUG, "EAP-SAKE: Sending "
383
"Response/Auth-Reject");
384
return eap_sake_build_msg(data, &rpos, hdr->identifier,
386
EAP_SAKE_SUBTYPE_AUTH_REJECT);
389
wpa_printf(MSG_DEBUG, "EAP-SAKE: Sending Response/Confirm");
391
*respDataLen = 2 + EAP_SAKE_MIC_LEN;
392
resp = eap_sake_build_msg(data, &rpos, hdr->identifier, respDataLen,
393
EAP_SAKE_SUBTYPE_CONFIRM);
397
wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_MIC_P");
398
*rpos++ = EAP_SAKE_AT_MIC_P;
399
*rpos++ = 2 + EAP_SAKE_MIC_LEN;
400
if (eap_sake_compute_mic(data->tek.auth, data->rand_s, data->rand_p,
401
data->serverid, data->serverid_len,
402
data->peerid, data->peerid_len, 1,
403
resp, *respDataLen, rpos, rpos)) {
404
wpa_printf(MSG_INFO, "EAP-SAKE: Failed to compute MIC");
409
eap_sake_state(data, SUCCESS);
410
ret->methodState = METHOD_DONE;
411
ret->decision = DECISION_UNCOND_SUCC;
412
ret->allowNotifications = FALSE;
418
static u8 * eap_sake_process(struct eap_sm *sm, void *priv,
419
struct eap_method_ret *ret,
420
const u8 *reqData, size_t reqDataLen,
423
struct eap_sake_data *data = priv;
424
const struct eap_sake_hdr *req;
425
const struct eap_sake_exp_hdr *ereq;
429
u8 subtype, session_id;
431
pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_SAKE,
432
reqData, reqDataLen, &len);
433
if (pos == NULL || len < (data->expanded_eap ? 4 : 3)) {
438
if (data->expanded_eap) {
439
ereq = (const struct eap_sake_exp_hdr *) reqData;
440
subtype = ereq->subtype;
441
session_id = ereq->session_id;
442
pos = (const u8 *) (ereq + 1);
443
end = reqData + be_to_host16(ereq->length);
445
req = (const struct eap_sake_hdr *) reqData;
446
subtype = req->subtype;
447
session_id = req->session_id;
448
pos = (const u8 *) (req + 1);
449
end = reqData + be_to_host16(req->length);
452
wpa_printf(MSG_DEBUG, "EAP-SAKE: Received frame: subtype %d "
453
"session_id %d", subtype, session_id);
454
wpa_hexdump(MSG_DEBUG, "EAP-SAKE: Received attributes",
457
if (data->session_id_set && data->session_id != session_id) {
458
wpa_printf(MSG_INFO, "EAP-SAKE: Session ID mismatch (%d,%d)",
459
session_id, data->session_id);
463
data->session_id = session_id;
464
data->session_id_set = 1;
467
ret->methodState = METHOD_MAY_CONT;
468
ret->decision = DECISION_FAIL;
469
ret->allowNotifications = TRUE;
472
case EAP_SAKE_SUBTYPE_IDENTITY:
473
resp = eap_sake_process_identity(sm, data, ret, reqData,
474
reqDataLen, pos, end - pos,
477
case EAP_SAKE_SUBTYPE_CHALLENGE:
478
resp = eap_sake_process_challenge(sm, data, ret, reqData,
479
reqDataLen, pos, end - pos,
482
case EAP_SAKE_SUBTYPE_CONFIRM:
483
resp = eap_sake_process_confirm(sm, data, ret, reqData,
484
reqDataLen, pos, end - pos,
488
wpa_printf(MSG_DEBUG, "EAP-SAKE: Ignoring message with "
489
"unknown subtype %d", subtype);
494
if (ret->methodState == METHOD_DONE)
495
ret->allowNotifications = FALSE;
501
static Boolean eap_sake_isKeyAvailable(struct eap_sm *sm, void *priv)
503
struct eap_sake_data *data = priv;
504
return data->state == SUCCESS;
508
static u8 * eap_sake_getKey(struct eap_sm *sm, void *priv, size_t *len)
510
struct eap_sake_data *data = priv;
513
if (data->state != SUCCESS)
516
key = malloc(EAP_MSK_LEN);
519
memcpy(key, data->msk, EAP_MSK_LEN);
526
int eap_peer_sake_register(void)
528
struct eap_method *eap;
531
eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
532
EAP_VENDOR_IETF, EAP_TYPE_SAKE, "SAKE");
536
eap->init = eap_sake_init;
537
eap->deinit = eap_sake_deinit;
538
eap->process = eap_sake_process;
539
eap->isKeyAvailable = eap_sake_isKeyAvailable;
540
eap->getKey = eap_sake_getKey;
542
ret = eap_peer_method_register(eap);
544
eap_peer_method_free(eap);