MFC corrected printing of the slice number when adding a GPT partition.
[dragonfly.git] / contrib / wpa_supplicant-0.5.8 / eap_sake.c
blob85ca4a41d88a85007335f6bea24bd860b5f43390
1 /*
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
10 * license.
12 * See README and COPYING for more details.
15 #include "includes.h"
17 #include "common.h"
18 #include "eap_i.h"
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];
28 struct {
29 u8 auth[EAP_SAKE_TEK_AUTH_LEN];
30 u8 cipher[EAP_SAKE_TEK_CIPHER_LEN];
31 } tek;
32 u8 msk[EAP_MSK_LEN];
33 u8 emsk[EAP_EMSK_LEN];
34 u8 session_id;
35 int session_id_set;
36 u8 *peerid;
37 size_t peerid_len;
38 u8 *serverid;
39 size_t serverid_len;
43 static const char * eap_sake_state_txt(int state)
45 switch (state) {
46 case IDENTITY:
47 return "IDENTITY";
48 case CHALLENGE:
49 return "CHALLENGE";
50 case CONFIRM:
51 return "CONFIRM";
52 case SUCCESS:
53 return "SUCCESS";
54 case FAILURE:
55 return "FAILURE";
56 default:
57 return "?";
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));
67 data->state = 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;
79 if (config == NULL) {
80 wpa_printf(MSG_INFO, "EAP-SAKE: No configuration found");
81 return NULL;
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 "
87 "length configured");
88 return NULL;
91 data = os_zalloc(sizeof(*data));
92 if (data == NULL)
93 return NULL;
94 data->state = IDENTITY;
96 if (config->nai) {
97 data->peerid = os_malloc(config->nai_len);
98 if (data->peerid == NULL) {
99 eap_sake_deinit(sm, data);
100 return NULL;
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);
112 return data;
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);
121 os_free(data);
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;
129 u8 *msg;
131 *length += sizeof(struct eap_sake_hdr);
133 msg = os_zalloc(*length);
134 if (msg == NULL) {
135 wpa_printf(MSG_ERROR, "EAP-SAKE: Failed to allocate memory "
136 "request");
137 return NULL;
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);
150 return msg;
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,
159 size_t *respDataLen)
161 struct eap_sake_parse_attr attr;
162 u8 *resp, *rpos;
163 const struct eap_hdr *hdr = (const struct eap_hdr *) reqData;
165 if (data->state != IDENTITY) {
166 ret->ignore = TRUE;
167 return NULL;
170 wpa_printf(MSG_DEBUG, "EAP-SAKE: Received Request/Identity");
172 if (eap_sake_parse_attributes(payload, payload_len, &attr))
173 return NULL;
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");
178 return NULL;
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);
186 if (resp == NULL)
187 return NULL;
189 wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_PEERID");
190 *rpos++ = EAP_SAKE_AT_PEERID;
191 *rpos++ = 2 + data->peerid_len;
192 if (data->peerid)
193 os_memcpy(rpos, data->peerid, data->peerid_len);
195 eap_sake_state(data, CHALLENGE);
197 return resp;
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,
206 size_t *respDataLen)
208 struct eap_sake_parse_attr attr;
209 u8 *resp, *rpos;
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);
215 ret->ignore = TRUE;
216 return NULL;
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))
224 return NULL;
226 if (!attr.rand_s) {
227 wpa_printf(MSG_INFO, "EAP-SAKE: Request/Challenge did not "
228 "include AT_RAND_S");
229 return NULL;
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");
238 return NULL;
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;
246 if (attr.serverid) {
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)
251 return 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;
263 if (data->peerid)
264 *respDataLen += 2 + data->peerid_len;
265 resp = eap_sake_build_msg(data, &rpos, hdr->identifier, respDataLen,
266 EAP_SAKE_SUBTYPE_CHALLENGE);
267 if (resp == NULL)
268 return NULL;
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;
276 if (data->peerid) {
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");
292 os_free(resp);
293 return NULL;
296 eap_sake_state(data, CONFIRM);
298 return resp;
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,
307 size_t *respDataLen)
309 struct eap_sake_parse_attr attr;
310 u8 mic_s[EAP_SAKE_MIC_LEN];
311 u8 *resp, *rpos;
312 const struct eap_hdr *hdr = (const struct eap_hdr *) reqData;
314 if (data->state != CONFIRM) {
315 ret->ignore = TRUE;
316 return NULL;
319 wpa_printf(MSG_DEBUG, "EAP-SAKE: Received Request/Confirm");
321 if (eap_sake_parse_attributes(payload, payload_len, &attr))
322 return NULL;
324 if (!attr.mic_s) {
325 wpa_printf(MSG_INFO, "EAP-SAKE: Request/Confirm did not "
326 "include AT_MIC_S");
327 return NULL;
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;
340 *respDataLen = 0;
341 wpa_printf(MSG_DEBUG, "EAP-SAKE: Sending "
342 "Response/Auth-Reject");
343 return eap_sake_build_msg(data, &rpos, hdr->identifier,
344 respDataLen,
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);
353 if (resp == NULL)
354 return NULL;
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");
364 os_free(resp);
365 return NULL;
368 eap_sake_state(data, SUCCESS);
369 ret->methodState = METHOD_DONE;
370 ret->decision = DECISION_UNCOND_SUCC;
371 ret->allowNotifications = FALSE;
373 return resp;
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,
380 size_t *respDataLen)
382 struct eap_sake_data *data = priv;
383 const struct eap_sake_hdr *req;
384 u8 *resp;
385 const u8 *pos, *end;
386 size_t len;
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) {
392 ret->ignore = TRUE;
393 return NULL;
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",
405 pos, end - pos);
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);
410 ret->ignore = TRUE;
411 return NULL;
413 data->session_id = session_id;
414 data->session_id_set = 1;
416 ret->ignore = FALSE;
417 ret->methodState = METHOD_MAY_CONT;
418 ret->decision = DECISION_FAIL;
419 ret->allowNotifications = TRUE;
421 switch (subtype) {
422 case EAP_SAKE_SUBTYPE_IDENTITY:
423 resp = eap_sake_process_identity(sm, data, ret, reqData,
424 reqDataLen, pos, end - pos,
425 respDataLen);
426 break;
427 case EAP_SAKE_SUBTYPE_CHALLENGE:
428 resp = eap_sake_process_challenge(sm, data, ret, reqData,
429 reqDataLen, pos, end - pos,
430 respDataLen);
431 break;
432 case EAP_SAKE_SUBTYPE_CONFIRM:
433 resp = eap_sake_process_confirm(sm, data, ret, reqData,
434 reqDataLen, pos, end - pos,
435 respDataLen);
436 break;
437 default:
438 wpa_printf(MSG_DEBUG, "EAP-SAKE: Ignoring message with "
439 "unknown subtype %d", subtype);
440 ret->ignore = TRUE;
441 return NULL;
444 if (ret->methodState == METHOD_DONE)
445 ret->allowNotifications = FALSE;
447 return resp;
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;
461 u8 *key;
463 if (data->state != SUCCESS)
464 return NULL;
466 key = os_malloc(EAP_MSK_LEN);
467 if (key == NULL)
468 return NULL;
469 os_memcpy(key, data->msk, EAP_MSK_LEN);
470 *len = EAP_MSK_LEN;
472 return key;
476 static u8 * eap_sake_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
478 struct eap_sake_data *data = priv;
479 u8 *key;
481 if (data->state != SUCCESS)
482 return NULL;
484 key = os_malloc(EAP_EMSK_LEN);
485 if (key == NULL)
486 return NULL;
487 os_memcpy(key, data->emsk, EAP_EMSK_LEN);
488 *len = EAP_EMSK_LEN;
490 return key;
494 int eap_peer_sake_register(void)
496 struct eap_method *eap;
497 int ret;
499 eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
500 EAP_VENDOR_IETF, EAP_TYPE_SAKE, "SAKE");
501 if (eap == NULL)
502 return -1;
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);
512 if (ret)
513 eap_peer_method_free(eap);
514 return ret;