2
* EAP peer method: EAP-SAKE (RFC 4763)
3
* Copyright (c) 2006-2008, 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.
18
#include "eap_peer/eap_i.h"
19
#include "eap_common/eap_sake_common.h"
21
struct eap_sake_data {
22
enum { IDENTITY, CHALLENGE, CONFIRM, SUCCESS, FAILURE } state;
23
u8 root_secret_a[EAP_SAKE_ROOT_SECRET_LEN];
24
u8 root_secret_b[EAP_SAKE_ROOT_SECRET_LEN];
25
u8 rand_s[EAP_SAKE_RAND_LEN];
26
u8 rand_p[EAP_SAKE_RAND_LEN];
28
u8 auth[EAP_SAKE_TEK_AUTH_LEN];
29
u8 cipher[EAP_SAKE_TEK_CIPHER_LEN];
32
u8 emsk[EAP_EMSK_LEN];
42
static const char * eap_sake_state_txt(int state)
61
static void eap_sake_state(struct eap_sake_data *data, int state)
63
wpa_printf(MSG_DEBUG, "EAP-SAKE: %s -> %s",
64
eap_sake_state_txt(data->state),
65
eap_sake_state_txt(state));
70
static void eap_sake_deinit(struct eap_sm *sm, void *priv);
73
static void * eap_sake_init(struct eap_sm *sm)
75
struct eap_sake_data *data;
76
const u8 *identity, *password;
77
size_t identity_len, password_len;
79
password = eap_get_config_password(sm, &password_len);
80
if (!password || password_len != 2 * EAP_SAKE_ROOT_SECRET_LEN) {
81
wpa_printf(MSG_INFO, "EAP-SAKE: No key of correct length "
86
data = os_zalloc(sizeof(*data));
89
data->state = IDENTITY;
91
identity = eap_get_config_identity(sm, &identity_len);
93
data->peerid = os_malloc(identity_len);
94
if (data->peerid == NULL) {
95
eap_sake_deinit(sm, data);
98
os_memcpy(data->peerid, identity, identity_len);
99
data->peerid_len = identity_len;
102
os_memcpy(data->root_secret_a, password, EAP_SAKE_ROOT_SECRET_LEN);
103
os_memcpy(data->root_secret_b,
104
password + EAP_SAKE_ROOT_SECRET_LEN,
105
EAP_SAKE_ROOT_SECRET_LEN);
111
static void eap_sake_deinit(struct eap_sm *sm, void *priv)
113
struct eap_sake_data *data = priv;
114
os_free(data->serverid);
115
os_free(data->peerid);
120
static struct wpabuf * eap_sake_build_msg(struct eap_sake_data *data,
121
int id, size_t length, u8 subtype)
123
struct eap_sake_hdr *sake;
127
plen = length + sizeof(struct eap_sake_hdr);
129
msg = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_SAKE, plen,
130
EAP_CODE_RESPONSE, id);
132
wpa_printf(MSG_ERROR, "EAP-SAKE: Failed to allocate memory "
137
sake = wpabuf_put(msg, sizeof(*sake));
138
sake->version = EAP_SAKE_VERSION;
139
sake->session_id = data->session_id;
140
sake->subtype = subtype;
146
static struct wpabuf * eap_sake_process_identity(struct eap_sm *sm,
147
struct eap_sake_data *data,
148
struct eap_method_ret *ret,
149
const struct wpabuf *reqData,
153
struct eap_sake_parse_attr attr;
156
if (data->state != IDENTITY) {
161
wpa_printf(MSG_DEBUG, "EAP-SAKE: Received Request/Identity");
163
if (eap_sake_parse_attributes(payload, payload_len, &attr))
166
if (!attr.perm_id_req && !attr.any_id_req) {
167
wpa_printf(MSG_INFO, "EAP-SAKE: No AT_PERM_ID_REQ or "
168
"AT_ANY_ID_REQ in Request/Identity");
172
wpa_printf(MSG_DEBUG, "EAP-SAKE: Sending Response/Identity");
174
resp = eap_sake_build_msg(data, eap_get_id(reqData),
175
2 + data->peerid_len,
176
EAP_SAKE_SUBTYPE_IDENTITY);
180
wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_PEERID");
181
eap_sake_add_attr(resp, EAP_SAKE_AT_PEERID,
182
data->peerid, data->peerid_len);
184
eap_sake_state(data, CHALLENGE);
190
static struct wpabuf * eap_sake_process_challenge(struct eap_sm *sm,
191
struct eap_sake_data *data,
192
struct eap_method_ret *ret,
193
const struct wpabuf *reqData,
197
struct eap_sake_parse_attr attr;
202
if (data->state != IDENTITY && data->state != CHALLENGE) {
203
wpa_printf(MSG_DEBUG, "EAP-SAKE: Request/Challenge received "
204
"in unexpected state (%d)", data->state);
208
if (data->state == IDENTITY)
209
eap_sake_state(data, CHALLENGE);
211
wpa_printf(MSG_DEBUG, "EAP-SAKE: Received Request/Challenge");
213
if (eap_sake_parse_attributes(payload, payload_len, &attr))
217
wpa_printf(MSG_INFO, "EAP-SAKE: Request/Challenge did not "
218
"include AT_RAND_S");
222
os_memcpy(data->rand_s, attr.rand_s, EAP_SAKE_RAND_LEN);
223
wpa_hexdump(MSG_MSGDUMP, "EAP-SAKE: RAND_S (server rand)",
224
data->rand_s, EAP_SAKE_RAND_LEN);
226
if (os_get_random(data->rand_p, EAP_SAKE_RAND_LEN)) {
227
wpa_printf(MSG_ERROR, "EAP-SAKE: Failed to get random data");
230
wpa_hexdump(MSG_MSGDUMP, "EAP-SAKE: RAND_P (peer rand)",
231
data->rand_p, EAP_SAKE_RAND_LEN);
233
os_free(data->serverid);
234
data->serverid = NULL;
235
data->serverid_len = 0;
237
wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-SAKE: SERVERID",
238
attr.serverid, attr.serverid_len);
239
data->serverid = os_malloc(attr.serverid_len);
240
if (data->serverid == NULL)
242
os_memcpy(data->serverid, attr.serverid, attr.serverid_len);
243
data->serverid_len = attr.serverid_len;
246
eap_sake_derive_keys(data->root_secret_a, data->root_secret_b,
247
data->rand_s, data->rand_p,
248
(u8 *) &data->tek, data->msk, data->emsk);
250
wpa_printf(MSG_DEBUG, "EAP-SAKE: Sending Response/Challenge");
252
rlen = 2 + EAP_SAKE_RAND_LEN + 2 + EAP_SAKE_MIC_LEN;
254
rlen += 2 + data->peerid_len;
255
resp = eap_sake_build_msg(data, eap_get_id(reqData), rlen,
256
EAP_SAKE_SUBTYPE_CHALLENGE);
260
wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_RAND_P");
261
eap_sake_add_attr(resp, EAP_SAKE_AT_RAND_P,
262
data->rand_p, EAP_SAKE_RAND_LEN);
265
wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_PEERID");
266
eap_sake_add_attr(resp, EAP_SAKE_AT_PEERID,
267
data->peerid, data->peerid_len);
270
wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_MIC_P");
271
wpabuf_put_u8(resp, EAP_SAKE_AT_MIC_P);
272
wpabuf_put_u8(resp, 2 + EAP_SAKE_MIC_LEN);
273
rpos = wpabuf_put(resp, EAP_SAKE_MIC_LEN);
274
if (eap_sake_compute_mic(data->tek.auth, data->rand_s, data->rand_p,
275
data->serverid, data->serverid_len,
276
data->peerid, data->peerid_len, 1,
277
wpabuf_head(resp), wpabuf_len(resp), rpos,
279
wpa_printf(MSG_INFO, "EAP-SAKE: Failed to compute MIC");
284
eap_sake_state(data, CONFIRM);
290
static struct wpabuf * eap_sake_process_confirm(struct eap_sm *sm,
291
struct eap_sake_data *data,
292
struct eap_method_ret *ret,
293
const struct wpabuf *reqData,
297
struct eap_sake_parse_attr attr;
298
u8 mic_s[EAP_SAKE_MIC_LEN];
302
if (data->state != CONFIRM) {
307
wpa_printf(MSG_DEBUG, "EAP-SAKE: Received Request/Confirm");
309
if (eap_sake_parse_attributes(payload, payload_len, &attr))
313
wpa_printf(MSG_INFO, "EAP-SAKE: Request/Confirm did not "
318
eap_sake_compute_mic(data->tek.auth, data->rand_s, data->rand_p,
319
data->serverid, data->serverid_len,
320
data->peerid, data->peerid_len, 0,
321
wpabuf_head(reqData), wpabuf_len(reqData),
323
if (os_memcmp(attr.mic_s, mic_s, EAP_SAKE_MIC_LEN) != 0) {
324
wpa_printf(MSG_INFO, "EAP-SAKE: Incorrect AT_MIC_S");
325
eap_sake_state(data, FAILURE);
326
ret->methodState = METHOD_DONE;
327
ret->decision = DECISION_FAIL;
328
ret->allowNotifications = FALSE;
329
wpa_printf(MSG_DEBUG, "EAP-SAKE: Sending "
330
"Response/Auth-Reject");
331
return eap_sake_build_msg(data, eap_get_id(reqData), 0,
332
EAP_SAKE_SUBTYPE_AUTH_REJECT);
335
wpa_printf(MSG_DEBUG, "EAP-SAKE: Sending Response/Confirm");
337
resp = eap_sake_build_msg(data, eap_get_id(reqData),
338
2 + EAP_SAKE_MIC_LEN,
339
EAP_SAKE_SUBTYPE_CONFIRM);
343
wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_MIC_P");
344
wpabuf_put_u8(resp, EAP_SAKE_AT_MIC_P);
345
wpabuf_put_u8(resp, 2 + EAP_SAKE_MIC_LEN);
346
rpos = wpabuf_put(resp, EAP_SAKE_MIC_LEN);
347
if (eap_sake_compute_mic(data->tek.auth, data->rand_s, data->rand_p,
348
data->serverid, data->serverid_len,
349
data->peerid, data->peerid_len, 1,
350
wpabuf_head(resp), wpabuf_len(resp), rpos,
352
wpa_printf(MSG_INFO, "EAP-SAKE: Failed to compute MIC");
357
eap_sake_state(data, SUCCESS);
358
ret->methodState = METHOD_DONE;
359
ret->decision = DECISION_UNCOND_SUCC;
360
ret->allowNotifications = FALSE;
366
static struct wpabuf * eap_sake_process(struct eap_sm *sm, void *priv,
367
struct eap_method_ret *ret,
368
const struct wpabuf *reqData)
370
struct eap_sake_data *data = priv;
371
const struct eap_sake_hdr *req;
375
u8 subtype, session_id;
377
pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_SAKE, reqData, &len);
378
if (pos == NULL || len < sizeof(struct eap_sake_hdr)) {
383
req = (const struct eap_sake_hdr *) pos;
385
subtype = req->subtype;
386
session_id = req->session_id;
387
pos = (const u8 *) (req + 1);
389
wpa_printf(MSG_DEBUG, "EAP-SAKE: Received frame: subtype %d "
390
"session_id %d", subtype, session_id);
391
wpa_hexdump(MSG_DEBUG, "EAP-SAKE: Received attributes",
394
if (data->session_id_set && data->session_id != session_id) {
395
wpa_printf(MSG_INFO, "EAP-SAKE: Session ID mismatch (%d,%d)",
396
session_id, data->session_id);
400
data->session_id = session_id;
401
data->session_id_set = 1;
404
ret->methodState = METHOD_MAY_CONT;
405
ret->decision = DECISION_FAIL;
406
ret->allowNotifications = TRUE;
409
case EAP_SAKE_SUBTYPE_IDENTITY:
410
resp = eap_sake_process_identity(sm, data, ret, reqData,
413
case EAP_SAKE_SUBTYPE_CHALLENGE:
414
resp = eap_sake_process_challenge(sm, data, ret, reqData,
417
case EAP_SAKE_SUBTYPE_CONFIRM:
418
resp = eap_sake_process_confirm(sm, data, ret, reqData,
422
wpa_printf(MSG_DEBUG, "EAP-SAKE: Ignoring message with "
423
"unknown subtype %d", subtype);
428
if (ret->methodState == METHOD_DONE)
429
ret->allowNotifications = FALSE;
435
static Boolean eap_sake_isKeyAvailable(struct eap_sm *sm, void *priv)
437
struct eap_sake_data *data = priv;
438
return data->state == SUCCESS;
442
static u8 * eap_sake_getKey(struct eap_sm *sm, void *priv, size_t *len)
444
struct eap_sake_data *data = priv;
447
if (data->state != SUCCESS)
450
key = os_malloc(EAP_MSK_LEN);
453
os_memcpy(key, data->msk, EAP_MSK_LEN);
460
static u8 * eap_sake_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
462
struct eap_sake_data *data = priv;
465
if (data->state != SUCCESS)
468
key = os_malloc(EAP_EMSK_LEN);
471
os_memcpy(key, data->emsk, EAP_EMSK_LEN);
478
int eap_peer_sake_register(void)
480
struct eap_method *eap;
483
eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
484
EAP_VENDOR_IETF, EAP_TYPE_SAKE, "SAKE");
488
eap->init = eap_sake_init;
489
eap->deinit = eap_sake_deinit;
490
eap->process = eap_sake_process;
491
eap->isKeyAvailable = eap_sake_isKeyAvailable;
492
eap->getKey = eap_sake_getKey;
493
eap->get_emsk = eap_sake_get_emsk;
495
ret = eap_peer_method_register(eap);
497
eap_peer_method_free(eap);