2 * hostapd / EAP-SAKE (RFC 4763) server
3 * Copyright (c) 2006-2007, 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 "crypto/random.h"
19 #include "eap_server/eap_i.h"
20 #include "eap_common/eap_sake_common.h"
23 struct eap_sake_data {
24 enum { IDENTITY, CHALLENGE, CONFIRM, SUCCESS, FAILURE } state;
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];
41 static const char * eap_sake_state_txt(int state)
60 static void eap_sake_state(struct eap_sake_data *data, int state)
62 wpa_printf(MSG_DEBUG, "EAP-SAKE: %s -> %s",
63 eap_sake_state_txt(data->state),
64 eap_sake_state_txt(state));
69 static void * eap_sake_init(struct eap_sm *sm)
71 struct eap_sake_data *data;
73 data = os_zalloc(sizeof(*data));
76 data->state = CHALLENGE;
78 if (os_get_random(&data->session_id, 1)) {
79 wpa_printf(MSG_ERROR, "EAP-SAKE: Failed to get random data");
83 wpa_printf(MSG_DEBUG, "EAP-SAKE: Initialized Session ID %d",
86 /* TODO: add support for configuring SERVERID */
87 data->serverid = (u8 *) os_strdup("hostapd");
89 data->serverid_len = os_strlen((char *) data->serverid);
95 static void eap_sake_reset(struct eap_sm *sm, void *priv)
97 struct eap_sake_data *data = priv;
98 os_free(data->serverid);
99 os_free(data->peerid);
104 static struct wpabuf * eap_sake_build_msg(struct eap_sake_data *data,
105 u8 id, size_t length, u8 subtype)
107 struct eap_sake_hdr *sake;
111 plen = sizeof(struct eap_sake_hdr) + length;
113 msg = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_SAKE, plen,
114 EAP_CODE_REQUEST, id);
116 wpa_printf(MSG_ERROR, "EAP-SAKE: Failed to allocate memory "
121 sake = wpabuf_put(msg, sizeof(*sake));
122 sake->version = EAP_SAKE_VERSION;
123 sake->session_id = data->session_id;
124 sake->subtype = subtype;
130 static struct wpabuf * eap_sake_build_identity(struct eap_sm *sm,
131 struct eap_sake_data *data,
137 wpa_printf(MSG_DEBUG, "EAP-SAKE: Request/Identity");
141 plen += 2 + data->serverid_len;
142 msg = eap_sake_build_msg(data, id, plen, EAP_SAKE_SUBTYPE_IDENTITY);
144 data->state = FAILURE;
148 wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_PERM_ID_REQ");
149 eap_sake_add_attr(msg, EAP_SAKE_AT_PERM_ID_REQ, NULL, 2);
151 if (data->serverid) {
152 wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_SERVERID");
153 eap_sake_add_attr(msg, EAP_SAKE_AT_SERVERID,
154 data->serverid, data->serverid_len);
161 static struct wpabuf * eap_sake_build_challenge(struct eap_sm *sm,
162 struct eap_sake_data *data,
168 wpa_printf(MSG_DEBUG, "EAP-SAKE: Request/Challenge");
170 if (random_get_bytes(data->rand_s, EAP_SAKE_RAND_LEN)) {
171 wpa_printf(MSG_ERROR, "EAP-SAKE: Failed to get random data");
172 data->state = FAILURE;
175 wpa_hexdump(MSG_MSGDUMP, "EAP-SAKE: RAND_S (server rand)",
176 data->rand_s, EAP_SAKE_RAND_LEN);
178 plen = 2 + EAP_SAKE_RAND_LEN;
180 plen += 2 + data->serverid_len;
181 msg = eap_sake_build_msg(data, id, plen, EAP_SAKE_SUBTYPE_CHALLENGE);
183 data->state = FAILURE;
187 wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_RAND_S");
188 eap_sake_add_attr(msg, EAP_SAKE_AT_RAND_S,
189 data->rand_s, EAP_SAKE_RAND_LEN);
191 if (data->serverid) {
192 wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_SERVERID");
193 eap_sake_add_attr(msg, EAP_SAKE_AT_SERVERID,
194 data->serverid, data->serverid_len);
201 static struct wpabuf * eap_sake_build_confirm(struct eap_sm *sm,
202 struct eap_sake_data *data,
208 wpa_printf(MSG_DEBUG, "EAP-SAKE: Request/Confirm");
210 msg = eap_sake_build_msg(data, id, 2 + EAP_SAKE_MIC_LEN,
211 EAP_SAKE_SUBTYPE_CONFIRM);
213 data->state = FAILURE;
217 wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_MIC_S");
218 wpabuf_put_u8(msg, EAP_SAKE_AT_MIC_S);
219 wpabuf_put_u8(msg, 2 + EAP_SAKE_MIC_LEN);
220 mic = wpabuf_put(msg, EAP_SAKE_MIC_LEN);
221 if (eap_sake_compute_mic(data->tek.auth, data->rand_s, data->rand_p,
222 data->serverid, data->serverid_len,
223 data->peerid, data->peerid_len, 0,
224 wpabuf_head(msg), wpabuf_len(msg), mic, mic))
226 wpa_printf(MSG_INFO, "EAP-SAKE: Failed to compute MIC");
227 data->state = FAILURE;
236 static struct wpabuf * eap_sake_buildReq(struct eap_sm *sm, void *priv, u8 id)
238 struct eap_sake_data *data = priv;
240 switch (data->state) {
242 return eap_sake_build_identity(sm, data, id);
244 return eap_sake_build_challenge(sm, data, id);
246 return eap_sake_build_confirm(sm, data, id);
248 wpa_printf(MSG_DEBUG, "EAP-SAKE: Unknown state %d in buildReq",
256 static Boolean eap_sake_check(struct eap_sm *sm, void *priv,
257 struct wpabuf *respData)
259 struct eap_sake_data *data = priv;
260 struct eap_sake_hdr *resp;
262 u8 version, session_id, subtype;
265 pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_SAKE, respData, &len);
266 if (pos == NULL || len < sizeof(struct eap_sake_hdr)) {
267 wpa_printf(MSG_INFO, "EAP-SAKE: Invalid frame");
271 resp = (struct eap_sake_hdr *) pos;
272 version = resp->version;
273 session_id = resp->session_id;
274 subtype = resp->subtype;
276 if (version != EAP_SAKE_VERSION) {
277 wpa_printf(MSG_INFO, "EAP-SAKE: Unknown version %d", version);
281 if (session_id != data->session_id) {
282 wpa_printf(MSG_INFO, "EAP-SAKE: Session ID mismatch (%d,%d)",
283 session_id, data->session_id);
287 wpa_printf(MSG_DEBUG, "EAP-SAKE: Received frame: subtype=%d", subtype);
289 if (data->state == IDENTITY && subtype == EAP_SAKE_SUBTYPE_IDENTITY)
292 if (data->state == CHALLENGE && subtype == EAP_SAKE_SUBTYPE_CHALLENGE)
295 if (data->state == CONFIRM && subtype == EAP_SAKE_SUBTYPE_CONFIRM)
298 if (subtype == EAP_SAKE_SUBTYPE_AUTH_REJECT)
301 wpa_printf(MSG_INFO, "EAP-SAKE: Unexpected subtype=%d in state=%d",
302 subtype, data->state);
308 static void eap_sake_process_identity(struct eap_sm *sm,
309 struct eap_sake_data *data,
310 const struct wpabuf *respData,
311 const u8 *payload, size_t payloadlen)
313 if (data->state != IDENTITY)
316 wpa_printf(MSG_DEBUG, "EAP-SAKE: Received Response/Identity");
317 /* TODO: update identity and select new user data */
318 eap_sake_state(data, CHALLENGE);
322 static void eap_sake_process_challenge(struct eap_sm *sm,
323 struct eap_sake_data *data,
324 const struct wpabuf *respData,
325 const u8 *payload, size_t payloadlen)
327 struct eap_sake_parse_attr attr;
328 u8 mic_p[EAP_SAKE_MIC_LEN];
330 if (data->state != CHALLENGE)
333 wpa_printf(MSG_DEBUG, "EAP-SAKE: Received Response/Challenge");
335 if (eap_sake_parse_attributes(payload, payloadlen, &attr))
338 if (!attr.rand_p || !attr.mic_p) {
339 wpa_printf(MSG_INFO, "EAP-SAKE: Response/Challenge did not "
340 "include AT_RAND_P or AT_MIC_P");
344 os_memcpy(data->rand_p, attr.rand_p, EAP_SAKE_RAND_LEN);
346 os_free(data->peerid);
348 data->peerid_len = 0;
350 data->peerid = os_malloc(attr.peerid_len);
351 if (data->peerid == NULL)
353 os_memcpy(data->peerid, attr.peerid, attr.peerid_len);
354 data->peerid_len = attr.peerid_len;
357 if (sm->user == NULL || sm->user->password == NULL ||
358 sm->user->password_len != 2 * EAP_SAKE_ROOT_SECRET_LEN) {
359 wpa_printf(MSG_INFO, "EAP-SAKE: Plaintext password with "
360 "%d-byte key not configured",
361 2 * EAP_SAKE_ROOT_SECRET_LEN);
362 data->state = FAILURE;
365 eap_sake_derive_keys(sm->user->password,
366 sm->user->password + EAP_SAKE_ROOT_SECRET_LEN,
367 data->rand_s, data->rand_p,
368 (u8 *) &data->tek, data->msk, data->emsk);
370 eap_sake_compute_mic(data->tek.auth, data->rand_s, data->rand_p,
371 data->serverid, data->serverid_len,
372 data->peerid, data->peerid_len, 1,
373 wpabuf_head(respData), wpabuf_len(respData),
375 if (os_memcmp(attr.mic_p, mic_p, EAP_SAKE_MIC_LEN) != 0) {
376 wpa_printf(MSG_INFO, "EAP-SAKE: Incorrect AT_MIC_P");
377 eap_sake_state(data, FAILURE);
381 eap_sake_state(data, CONFIRM);
385 static void eap_sake_process_confirm(struct eap_sm *sm,
386 struct eap_sake_data *data,
387 const struct wpabuf *respData,
388 const u8 *payload, size_t payloadlen)
390 struct eap_sake_parse_attr attr;
391 u8 mic_p[EAP_SAKE_MIC_LEN];
393 if (data->state != CONFIRM)
396 wpa_printf(MSG_DEBUG, "EAP-SAKE: Received Response/Confirm");
398 if (eap_sake_parse_attributes(payload, payloadlen, &attr))
402 wpa_printf(MSG_INFO, "EAP-SAKE: Response/Confirm did not "
407 eap_sake_compute_mic(data->tek.auth, data->rand_s, data->rand_p,
408 data->serverid, data->serverid_len,
409 data->peerid, data->peerid_len, 1,
410 wpabuf_head(respData), wpabuf_len(respData),
412 if (os_memcmp(attr.mic_p, mic_p, EAP_SAKE_MIC_LEN) != 0) {
413 wpa_printf(MSG_INFO, "EAP-SAKE: Incorrect AT_MIC_P");
414 eap_sake_state(data, FAILURE);
416 eap_sake_state(data, SUCCESS);
420 static void eap_sake_process_auth_reject(struct eap_sm *sm,
421 struct eap_sake_data *data,
422 const struct wpabuf *respData,
423 const u8 *payload, size_t payloadlen)
425 wpa_printf(MSG_DEBUG, "EAP-SAKE: Received Response/Auth-Reject");
426 eap_sake_state(data, FAILURE);
430 static void eap_sake_process(struct eap_sm *sm, void *priv,
431 struct wpabuf *respData)
433 struct eap_sake_data *data = priv;
434 struct eap_sake_hdr *resp;
439 pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_SAKE, respData, &len);
440 if (pos == NULL || len < sizeof(struct eap_sake_hdr))
443 resp = (struct eap_sake_hdr *) pos;
445 subtype = resp->subtype;
446 pos = (u8 *) (resp + 1);
448 wpa_hexdump(MSG_DEBUG, "EAP-SAKE: Received attributes",
452 case EAP_SAKE_SUBTYPE_IDENTITY:
453 eap_sake_process_identity(sm, data, respData, pos, end - pos);
455 case EAP_SAKE_SUBTYPE_CHALLENGE:
456 eap_sake_process_challenge(sm, data, respData, pos, end - pos);
458 case EAP_SAKE_SUBTYPE_CONFIRM:
459 eap_sake_process_confirm(sm, data, respData, pos, end - pos);
461 case EAP_SAKE_SUBTYPE_AUTH_REJECT:
462 eap_sake_process_auth_reject(sm, data, respData, pos,
469 static Boolean eap_sake_isDone(struct eap_sm *sm, void *priv)
471 struct eap_sake_data *data = priv;
472 return data->state == SUCCESS || data->state == FAILURE;
476 static u8 * eap_sake_getKey(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_MSK_LEN);
487 os_memcpy(key, data->msk, EAP_MSK_LEN);
494 static u8 * eap_sake_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
496 struct eap_sake_data *data = priv;
499 if (data->state != SUCCESS)
502 key = os_malloc(EAP_EMSK_LEN);
505 os_memcpy(key, data->emsk, EAP_EMSK_LEN);
512 static Boolean eap_sake_isSuccess(struct eap_sm *sm, void *priv)
514 struct eap_sake_data *data = priv;
515 return data->state == SUCCESS;
519 int eap_server_sake_register(void)
521 struct eap_method *eap;
524 eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
525 EAP_VENDOR_IETF, EAP_TYPE_SAKE, "SAKE");
529 eap->init = eap_sake_init;
530 eap->reset = eap_sake_reset;
531 eap->buildReq = eap_sake_buildReq;
532 eap->check = eap_sake_check;
533 eap->process = eap_sake_process;
534 eap->isDone = eap_sake_isDone;
535 eap->getKey = eap_sake_getKey;
536 eap->isSuccess = eap_sake_isSuccess;
537 eap->get_emsk = eap_sake_get_emsk;
539 ret = eap_server_method_register(eap);
541 eap_server_method_free(eap);