Add syscall.9 adapted from OpenBSD.
[dragonfly.git] / contrib / wpa_supplicant-0.5.8 / eap_fast.c
blobd9347a986d9db7eaaf33b1c16b1ff3e366fab270
1 /*
2 * EAP peer method: EAP-FAST (draft-cam-winget-eap-fast-03.txt)
3 * Copyright (c) 2004-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 "eap_tls_common.h"
20 #include "config_ssid.h"
21 #include "tls.h"
22 #include "eap_tlv.h"
23 #include "sha1.h"
24 #include "config.h"
26 /* TODO:
27 * - encrypt PAC-Key in the PAC file
28 * - test session resumption and enable it if it interoperates
29 * - password change (pending mschapv2 packet; replay decrypted packet)
32 #define EAP_FAST_VERSION 1
33 #define EAP_FAST_KEY_LEN 64
34 #define EAP_FAST_PAC_KEY_LEN 32
35 #define EAP_FAST_SIMCK_LEN 40
36 #define EAP_FAST_SKS_LEN 40
38 #define TLS_EXT_PAC_OPAQUE 35
40 static const char *pac_file_hdr =
41 "wpa_supplicant EAP-FAST PAC file - version 1";
44 static void eap_fast_deinit(struct eap_sm *sm, void *priv);
47 #define PAC_TYPE_PAC_KEY 1
48 #define PAC_TYPE_PAC_OPAQUE 2
49 #define PAC_TYPE_CRED_LIFETIME 3
50 #define PAC_TYPE_A_ID 4
51 #define PAC_TYPE_I_ID 5
52 #define PAC_TYPE_SERVER_PROTECTED_DATA 6
53 #define PAC_TYPE_A_ID_INFO 7
54 #define PAC_TYPE_PAC_ACKNOWLEDGEMENT 8
55 #define PAC_TYPE_PAC_INFO 9
57 struct pac_tlv_hdr {
58 u16 type;
59 u16 len;
63 /* draft-cam-winget-eap-fast-provisioning-01.txt:
64 * 3.4 Key Derivations Used in the EAP-FAST Provisioning Exchange */
65 struct eap_fast_key_block_provisioning {
66 /* Extra key material after TLS key_block */
67 u8 session_key_seed[EAP_FAST_SKS_LEN];
68 u8 server_challenge[16];
69 u8 client_challenge[16];
73 struct eap_fast_pac {
74 struct eap_fast_pac *next;
76 u8 pac_key[EAP_FAST_PAC_KEY_LEN];
77 u8 *pac_opaque;
78 size_t pac_opaque_len;
79 u8 *pac_info;
80 size_t pac_info_len;
81 u8 *a_id;
82 size_t a_id_len;
83 u8 *i_id;
84 size_t i_id_len;
85 u8 *a_id_info;
86 size_t a_id_info_len;
90 struct eap_fast_data {
91 struct eap_ssl_data ssl;
93 int fast_version;
95 const struct eap_method *phase2_method;
96 void *phase2_priv;
97 int phase2_success;
99 struct eap_method_type phase2_type;
100 struct eap_method_type *phase2_types;
101 size_t num_phase2_types;
102 int resuming; /* starting a resumed session */
103 struct eap_fast_key_block_provisioning *key_block_p;
104 int provisioning_allowed; /* is PAC provisioning allowed */
105 int provisioning; /* doing PAC provisioning (not the normal auth) */
107 u8 key_data[EAP_FAST_KEY_LEN];
108 u8 emsk[EAP_EMSK_LEN];
109 int success;
111 struct eap_fast_pac *pac;
112 struct eap_fast_pac *current_pac;
114 int tls_master_secret_set;
116 u8 simck[EAP_FAST_SIMCK_LEN];
117 int simck_idx;
121 static void eap_fast_free_pac(struct eap_fast_pac *pac)
123 os_free(pac->pac_opaque);
124 os_free(pac->pac_info);
125 os_free(pac->a_id);
126 os_free(pac->i_id);
127 os_free(pac->a_id_info);
128 os_free(pac);
132 static struct eap_fast_pac * eap_fast_get_pac(struct eap_fast_data *data,
133 const u8 *a_id, size_t a_id_len)
135 struct eap_fast_pac *pac = data->pac;
137 while (pac) {
138 if (pac->a_id_len == a_id_len &&
139 os_memcmp(pac->a_id, a_id, a_id_len) == 0) {
140 return pac;
142 pac = pac->next;
144 return NULL;
148 static int eap_fast_add_pac(struct eap_fast_data *data,
149 struct eap_fast_pac *entry)
151 struct eap_fast_pac *pac, *prev;
153 if (entry == NULL || entry->a_id == NULL)
154 return -1;
156 /* Remove a possible old entry for the matching A-ID. */
157 pac = data->pac;
158 prev = NULL;
159 while (pac) {
160 if (pac->a_id_len == entry->a_id_len &&
161 os_memcmp(pac->a_id, entry->a_id, pac->a_id_len) == 0) {
162 if (prev == NULL) {
163 data->pac = pac->next;
164 } else {
165 prev->next = pac->next;
167 if (data->current_pac == pac)
168 data->current_pac = NULL;
169 eap_fast_free_pac(pac);
170 break;
172 prev = pac;
173 pac = pac->next;
176 /* Allocate a new entry and add it to the list of PACs. */
177 pac = os_zalloc(sizeof(*pac));
178 if (pac == NULL)
179 return -1;
181 os_memcpy(pac->pac_key, entry->pac_key, EAP_FAST_PAC_KEY_LEN);
182 if (entry->pac_opaque) {
183 pac->pac_opaque = os_malloc(entry->pac_opaque_len);
184 if (pac->pac_opaque == NULL) {
185 eap_fast_free_pac(pac);
186 return -1;
188 os_memcpy(pac->pac_opaque, entry->pac_opaque,
189 entry->pac_opaque_len);
190 pac->pac_opaque_len = entry->pac_opaque_len;
192 if (entry->pac_info) {
193 pac->pac_info = os_malloc(entry->pac_info_len);
194 if (pac->pac_info == NULL) {
195 eap_fast_free_pac(pac);
196 return -1;
198 os_memcpy(pac->pac_info, entry->pac_info,
199 entry->pac_info_len);
200 pac->pac_info_len = entry->pac_info_len;
202 if (entry->a_id) {
203 pac->a_id = os_malloc(entry->a_id_len);
204 if (pac->a_id == NULL) {
205 eap_fast_free_pac(pac);
206 return -1;
208 os_memcpy(pac->a_id, entry->a_id,
209 entry->a_id_len);
210 pac->a_id_len = entry->a_id_len;
212 if (entry->i_id) {
213 pac->i_id = os_malloc(entry->i_id_len);
214 if (pac->i_id == NULL) {
215 eap_fast_free_pac(pac);
216 return -1;
218 os_memcpy(pac->i_id, entry->i_id,
219 entry->i_id_len);
220 pac->i_id_len = entry->i_id_len;
222 if (entry->a_id_info) {
223 pac->a_id_info = os_malloc(entry->a_id_info_len);
224 if (pac->a_id_info == NULL) {
225 eap_fast_free_pac(pac);
226 return -1;
228 os_memcpy(pac->a_id_info, entry->a_id_info,
229 entry->a_id_info_len);
230 pac->a_id_info_len = entry->a_id_info_len;
232 pac->next = data->pac;
233 data->pac = pac;
234 return 0;
238 struct eap_fast_read_ctx {
239 FILE *f;
240 const char *pos;
241 const char *end;
244 static int eap_fast_read_line(struct eap_fast_read_ctx *rc, char *buf,
245 size_t buf_len)
247 char *pos;
249 if (rc->f) {
250 if (fgets(buf, buf_len, rc->f) == NULL)
251 return -1;
252 } else {
253 const char *l_end;
254 size_t len;
255 if (rc->pos >= rc->end)
256 return -1;
257 l_end = rc->pos;
258 while (l_end < rc->end && *l_end != '\n')
259 l_end++;
260 len = l_end - rc->pos;
261 if (len >= buf_len)
262 len = buf_len - 1;
263 os_memcpy(buf, rc->pos, len);
264 buf[len] = '\0';
265 rc->pos = l_end + 1;
268 buf[buf_len - 1] = '\0';
269 pos = buf;
270 while (*pos != '\0') {
271 if (*pos == '\n' || *pos == '\r') {
272 *pos = '\0';
273 break;
275 pos++;
278 return 0;
282 static u8 * eap_fast_parse_hex(const char *value, size_t *len)
284 int hlen;
285 u8 *buf;
287 if (value == NULL)
288 return NULL;
289 hlen = os_strlen(value);
290 if (hlen & 1)
291 return NULL;
292 *len = hlen / 2;
293 buf = os_malloc(*len);
294 if (buf == NULL)
295 return NULL;
296 if (hexstr2bin(value, buf, *len)) {
297 os_free(buf);
298 return NULL;
300 return buf;
304 static int eap_fast_load_pac(struct eap_sm *sm, struct eap_fast_data *data,
305 const char *pac_file)
307 struct eap_fast_read_ctx rc;
308 struct eap_fast_pac *pac = NULL;
309 int count = 0;
310 char *buf, *pos;
311 const int buf_len = 2048;
312 int ret = 0, line = 0;
314 if (pac_file == NULL)
315 return -1;
317 os_memset(&rc, 0, sizeof(rc));
319 if (os_strncmp(pac_file, "blob://", 7) == 0) {
320 const struct wpa_config_blob *blob;
321 blob = eap_get_config_blob(sm, pac_file + 7);
322 if (blob == NULL) {
323 wpa_printf(MSG_INFO, "EAP-FAST: No PAC blob '%s' - "
324 "assume no PAC entries have been "
325 "provisioned", pac_file + 7);
326 return 0;
328 rc.pos = (char *) blob->data;
329 rc.end = (char *) blob->data + blob->len;
330 } else {
331 rc.f = fopen(pac_file, "r");
332 if (rc.f == NULL) {
333 wpa_printf(MSG_INFO, "EAP-FAST: No PAC file '%s' - "
334 "assume no PAC entries have been "
335 "provisioned", pac_file);
336 return 0;
340 buf = os_malloc(buf_len);
341 if (buf == NULL) {
342 return -1;
345 line++;
346 if (eap_fast_read_line(&rc, buf, buf_len) < 0 ||
347 os_strcmp(pac_file_hdr, buf) != 0) {
348 wpa_printf(MSG_INFO, "EAP-FAST: Unrecognized header line in "
349 "PAC file '%s'", pac_file);
350 os_free(buf);
351 if (rc.f)
352 fclose(rc.f);
353 return -1;
356 while (eap_fast_read_line(&rc, buf, buf_len) == 0) {
357 line++;
358 pos = os_strchr(buf, '=');
359 if (pos) {
360 *pos++ = '\0';
363 if (os_strcmp(buf, "START") == 0) {
364 if (pac) {
365 wpa_printf(MSG_INFO, "EAP-FAST: START line "
366 "without END in '%s:%d'",
367 pac_file, line);
368 ret = -1;
369 break;
371 pac = os_zalloc(sizeof(*pac));
372 if (pac == NULL) {
373 wpa_printf(MSG_INFO, "EAP-FAST: No memory for "
374 "PAC entry");
375 ret = -1;
376 break;
378 } else if (os_strcmp(buf, "END") == 0) {
379 if (pac == NULL) {
380 wpa_printf(MSG_INFO, "EAP-FAST: END line "
381 "without START in '%s:%d'",
382 pac_file, line);
383 ret = -1;
384 break;
386 pac->next = data->pac;
387 data->pac = pac;
388 pac = NULL;
389 count++;
390 } else if (pac && os_strcmp(buf, "PAC-Key") == 0) {
391 u8 *key;
392 size_t key_len;
393 key = eap_fast_parse_hex(pos, &key_len);
394 if (key == NULL || key_len != EAP_FAST_PAC_KEY_LEN) {
395 wpa_printf(MSG_INFO, "EAP-FAST: Invalid "
396 "PAC-Key '%s:%d'", pac_file, line);
397 ret = -1;
398 os_free(key);
399 break;
402 os_memcpy(pac->pac_key, key, EAP_FAST_PAC_KEY_LEN);
403 os_free(key);
404 } else if (pac && os_strcmp(buf, "PAC-Opaque") == 0) {
405 os_free(pac->pac_opaque);
406 pac->pac_opaque =
407 eap_fast_parse_hex(pos, &pac->pac_opaque_len);
408 if (pac->pac_opaque == NULL) {
409 wpa_printf(MSG_INFO, "EAP-FAST: Invalid "
410 "PAC-Opaque '%s:%d'",
411 pac_file, line);
412 ret = -1;
413 break;
415 } else if (pac && os_strcmp(buf, "A-ID") == 0) {
416 os_free(pac->a_id);
417 pac->a_id = eap_fast_parse_hex(pos, &pac->a_id_len);
418 if (pac->a_id == NULL) {
419 wpa_printf(MSG_INFO, "EAP-FAST: Invalid "
420 "A-ID '%s:%d'", pac_file, line);
421 ret = -1;
422 break;
424 } else if (pac && os_strcmp(buf, "I-ID") == 0) {
425 os_free(pac->i_id);
426 pac->i_id = eap_fast_parse_hex(pos, &pac->i_id_len);
427 if (pac->i_id == NULL) {
428 wpa_printf(MSG_INFO, "EAP-FAST: Invalid "
429 "I-ID '%s:%d'", pac_file, line);
430 ret = -1;
431 break;
433 } else if (pac && os_strcmp(buf, "A-ID-Info") == 0) {
434 os_free(pac->a_id_info);
435 pac->a_id_info =
436 eap_fast_parse_hex(pos, &pac->a_id_info_len);
437 if (pac->a_id_info == NULL) {
438 wpa_printf(MSG_INFO, "EAP-FAST: Invalid "
439 "A-ID-Info '%s:%d'",
440 pac_file, line);
441 ret = -1;
442 break;
447 if (pac) {
448 wpa_printf(MSG_INFO, "EAP-FAST: PAC block not terminated with "
449 "END in '%s'", pac_file);
450 eap_fast_free_pac(pac);
451 ret = -1;
454 os_free(buf);
455 if (rc.f)
456 fclose(rc.f);
458 if (ret == 0) {
459 wpa_printf(MSG_DEBUG, "EAP-FAST: read %d PAC entries from "
460 "'%s'", count, pac_file);
463 return ret;
467 static void eap_fast_write(char **buf, char **pos, size_t *buf_len,
468 const char *field, const u8 *data,
469 size_t len, int txt)
471 size_t i, need;
472 int ret;
474 if (data == NULL || *buf == NULL)
475 return;
477 need = os_strlen(field) + len * 2 + 30;
478 if (txt)
479 need += os_strlen(field) + len + 20;
481 if (*pos - *buf + need > *buf_len) {
482 char *nbuf = os_realloc(*buf, *buf_len + need);
483 if (nbuf == NULL) {
484 os_free(*buf);
485 *buf = NULL;
486 return;
488 *buf = nbuf;
489 *buf_len += need;
492 ret = os_snprintf(*pos, *buf + *buf_len - *pos, "%s=", field);
493 if (ret < 0 || ret >= *buf + *buf_len - *pos)
494 return;
495 *pos += ret;
496 *pos += wpa_snprintf_hex(*pos, *buf + *buf_len - *pos, data, len);
497 ret = os_snprintf(*pos, *buf + *buf_len - *pos, "\n");
498 if (ret < 0 || ret >= *buf + *buf_len - *pos)
499 return;
500 *pos += ret;
502 if (txt) {
503 ret = os_snprintf(*pos, *buf + *buf_len - *pos,
504 "%s-txt=", field);
505 if (ret < 0 || ret >= *buf + *buf_len - *pos)
506 return;
507 *pos += ret;
508 for (i = 0; i < len; i++) {
509 ret = os_snprintf(*pos, *buf + *buf_len - *pos,
510 "%c", data[i]);
511 if (ret < 0 || ret >= *buf + *buf_len - *pos)
512 return;
513 *pos += ret;
515 ret = os_snprintf(*pos, *buf + *buf_len - *pos, "\n");
516 if (ret < 0 || ret >= *buf + *buf_len - *pos)
517 return;
518 *pos += ret;
523 static int eap_fast_save_pac(struct eap_sm *sm, struct eap_fast_data *data,
524 const char *pac_file)
526 FILE *f;
527 struct eap_fast_pac *pac;
528 int count = 0, ret;
529 char *buf, *pos;
530 size_t buf_len;
532 if (pac_file == NULL)
533 return -1;
535 buf_len = 1024;
536 pos = buf = os_malloc(buf_len);
537 if (buf == NULL)
538 return -1;
540 ret = os_snprintf(pos, buf + buf_len - pos, "%s\n", pac_file_hdr);
541 if (ret < 0 || ret >= buf + buf_len - pos) {
542 os_free(buf);
543 return -1;
545 pos += ret;
547 pac = data->pac;
548 while (pac) {
549 ret = os_snprintf(pos, buf + buf_len - pos, "START\n");
550 if (ret < 0 || ret >= buf + buf_len - pos) {
551 os_free(buf);
552 return -1;
554 pos += ret;
555 eap_fast_write(&buf, &pos, &buf_len, "PAC-Key", pac->pac_key,
556 EAP_FAST_PAC_KEY_LEN, 0);
557 eap_fast_write(&buf, &pos, &buf_len, "PAC-Opaque",
558 pac->pac_opaque, pac->pac_opaque_len, 0);
559 eap_fast_write(&buf, &pos, &buf_len, "PAC-Info", pac->pac_info,
560 pac->pac_info_len, 0);
561 eap_fast_write(&buf, &pos, &buf_len, "A-ID", pac->a_id,
562 pac->a_id_len, 0);
563 eap_fast_write(&buf, &pos, &buf_len, "I-ID", pac->i_id,
564 pac->i_id_len, 1);
565 eap_fast_write(&buf, &pos, &buf_len, "A-ID-Info",
566 pac->a_id_info, pac->a_id_info_len, 1);
567 if (buf == NULL) {
568 wpa_printf(MSG_DEBUG, "EAP-FAST: No memory for PAC "
569 "data");
570 return -1;
572 ret = os_snprintf(pos, buf + buf_len - pos, "END\n");
573 if (ret < 0 || ret >= buf + buf_len - pos) {
574 os_free(buf);
575 return -1;
577 pos += ret;
578 count++;
579 pac = pac->next;
582 if (os_strncmp(pac_file, "blob://", 7) == 0) {
583 struct wpa_config_blob *blob;
584 blob = os_zalloc(sizeof(*blob));
585 if (blob == NULL) {
586 os_free(buf);
587 return -1;
589 blob->data = (u8 *) buf;
590 blob->len = pos - buf;
591 buf = NULL;
592 blob->name = os_strdup(pac_file + 7);
593 if (blob->name == NULL) {
594 os_free(blob->data);
595 os_free(blob);
596 return -1;
598 eap_set_config_blob(sm, blob);
599 } else {
600 f = fopen(pac_file, "w");
601 if (f == NULL) {
602 wpa_printf(MSG_INFO, "EAP-FAST: Failed to open PAC "
603 "file '%s' for writing", pac_file);
604 os_free(buf);
605 return -1;
607 fprintf(f, "%s", buf);
608 os_free(buf);
609 fclose(f);
612 wpa_printf(MSG_DEBUG, "EAP-FAST: wrote %d PAC entries into '%s'",
613 count, pac_file);
615 return 0;
619 static void * eap_fast_init(struct eap_sm *sm)
621 struct eap_fast_data *data;
622 struct wpa_ssid *config = eap_get_config(sm);
624 data = os_zalloc(sizeof(*data));
625 if (data == NULL)
626 return NULL;
627 data->fast_version = EAP_FAST_VERSION;
629 if (config && config->phase1) {
630 if (os_strstr(config->phase1, "fast_provisioning=1")) {
631 data->provisioning_allowed = 1;
632 wpa_printf(MSG_DEBUG, "EAP-FAST: Automatic PAC "
633 "provisioning is allowed");
637 if (config && config->phase2) {
638 char *start, *pos, *buf;
639 struct eap_method_type *methods = NULL, *_methods;
640 u8 method;
641 size_t num_methods = 0;
642 start = buf = os_strdup(config->phase2);
643 if (buf == NULL) {
644 eap_fast_deinit(sm, data);
645 return NULL;
647 while (start && *start != '\0') {
648 int vendor;
649 pos = os_strstr(start, "auth=");
650 if (pos == NULL)
651 break;
652 if (start != pos && *(pos - 1) != ' ') {
653 start = pos + 5;
654 continue;
657 start = pos + 5;
658 pos = os_strchr(start, ' ');
659 if (pos)
660 *pos++ = '\0';
661 method = eap_get_phase2_type(start, &vendor);
662 if (vendor == EAP_VENDOR_IETF &&
663 method == EAP_TYPE_NONE) {
664 wpa_printf(MSG_ERROR, "EAP-FAST: Unsupported "
665 "Phase2 method '%s'", start);
666 } else {
667 num_methods++;
668 _methods = os_realloc(
669 methods,
670 num_methods * sizeof(*methods));
671 if (_methods == NULL) {
672 os_free(methods);
673 os_free(buf);
674 eap_fast_deinit(sm, data);
675 return NULL;
677 methods = _methods;
678 methods[num_methods - 1].vendor = vendor;
679 methods[num_methods - 1].method = method;
682 start = pos;
684 os_free(buf);
685 data->phase2_types = methods;
686 data->num_phase2_types = num_methods;
688 if (data->phase2_types == NULL) {
689 data->phase2_types =
690 eap_get_phase2_types(config, &data->num_phase2_types);
692 if (data->phase2_types == NULL) {
693 wpa_printf(MSG_ERROR, "EAP-FAST: No Phase2 method available");
694 eap_fast_deinit(sm, data);
695 return NULL;
697 wpa_hexdump(MSG_DEBUG, "EAP-FAST: Phase2 EAP types",
698 (u8 *) data->phase2_types,
699 data->num_phase2_types * sizeof(struct eap_method_type));
700 data->phase2_type.vendor = EAP_VENDOR_IETF;
701 data->phase2_type.method = EAP_TYPE_NONE;
703 if (eap_tls_ssl_init(sm, &data->ssl, config)) {
704 wpa_printf(MSG_INFO, "EAP-FAST: Failed to initialize SSL.");
705 eap_fast_deinit(sm, data);
706 return NULL;
709 /* The local RADIUS server in a Cisco AP does not seem to like empty
710 * fragments before data, so disable that workaround for CBC.
711 * TODO: consider making this configurable */
712 tls_connection_enable_workaround(sm->ssl_ctx, data->ssl.conn);
714 if (eap_fast_load_pac(sm, data, config->pac_file) < 0) {
715 eap_fast_deinit(sm, data);
716 return NULL;
719 if (data->pac == NULL && !data->provisioning_allowed) {
720 wpa_printf(MSG_INFO, "EAP-FAST: No PAC configured and "
721 "provisioning disabled");
722 eap_fast_deinit(sm, data);
723 return NULL;
726 return data;
730 static void eap_fast_deinit(struct eap_sm *sm, void *priv)
732 struct eap_fast_data *data = priv;
733 struct eap_fast_pac *pac, *prev;
735 if (data == NULL)
736 return;
737 if (data->phase2_priv && data->phase2_method)
738 data->phase2_method->deinit(sm, data->phase2_priv);
739 os_free(data->phase2_types);
740 os_free(data->key_block_p);
741 eap_tls_ssl_deinit(sm, &data->ssl);
743 pac = data->pac;
744 prev = NULL;
745 while (pac) {
746 prev = pac;
747 pac = pac->next;
748 eap_fast_free_pac(prev);
750 os_free(data);
754 static int eap_fast_encrypt(struct eap_sm *sm, struct eap_fast_data *data,
755 int id, const u8 *plain, size_t plain_len,
756 u8 **out_data, size_t *out_len)
758 int res;
759 u8 *pos;
760 struct eap_hdr *resp;
762 /* TODO: add support for fragmentation, if needed. This will need to
763 * add TLS Message Length field, if the frame is fragmented. */
764 resp = os_malloc(sizeof(struct eap_hdr) + 2 + data->ssl.tls_out_limit);
765 if (resp == NULL)
766 return 0;
768 resp->code = EAP_CODE_RESPONSE;
769 resp->identifier = id;
771 pos = (u8 *) (resp + 1);
772 *pos++ = EAP_TYPE_FAST;
773 *pos++ = data->fast_version;
775 res = tls_connection_encrypt(sm->ssl_ctx, data->ssl.conn,
776 plain, plain_len,
777 pos, data->ssl.tls_out_limit);
778 if (res < 0) {
779 wpa_printf(MSG_INFO, "EAP-FAST: Failed to encrypt Phase 2 "
780 "data");
781 os_free(resp);
782 return 0;
785 *out_len = sizeof(struct eap_hdr) + 2 + res;
786 resp->length = host_to_be16(*out_len);
787 *out_data = (u8 *) resp;
788 return 0;
792 static int eap_fast_phase2_nak(struct eap_fast_data *data,
793 struct eap_hdr *hdr,
794 u8 **resp, size_t *resp_len)
796 struct eap_hdr *resp_hdr;
797 u8 *pos = (u8 *) (hdr + 1);
798 size_t i;
800 /* TODO: add support for expanded Nak */
801 wpa_printf(MSG_DEBUG, "EAP-FAST: Phase 2 Request: Nak type=%d", *pos);
802 wpa_hexdump(MSG_DEBUG, "EAP-FAST: Allowed Phase2 EAP types",
803 (u8 *) data->phase2_types,
804 data->num_phase2_types * sizeof(struct eap_method_type));
805 *resp_len = sizeof(struct eap_hdr) + 1;
806 *resp = os_malloc(*resp_len + data->num_phase2_types);
807 if (*resp == NULL)
808 return -1;
810 resp_hdr = (struct eap_hdr *) (*resp);
811 resp_hdr->code = EAP_CODE_RESPONSE;
812 resp_hdr->identifier = hdr->identifier;
813 pos = (u8 *) (resp_hdr + 1);
814 *pos++ = EAP_TYPE_NAK;
815 for (i = 0; i < data->num_phase2_types; i++) {
816 if (data->phase2_types[i].vendor == EAP_VENDOR_IETF &&
817 data->phase2_types[i].method < 256) {
818 (*resp_len)++;
819 *pos++ = data->phase2_types[i].method;
822 resp_hdr->length = host_to_be16(*resp_len);
824 return 0;
828 static int eap_fast_derive_msk(struct eap_fast_data *data)
830 /* Derive EAP Master Session Keys (section 5.4) */
831 sha1_t_prf(data->simck, EAP_FAST_SIMCK_LEN,
832 "Session Key Generating Function", (u8 *) "", 0,
833 data->key_data, EAP_FAST_KEY_LEN);
834 wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: Derived key (MSK)",
835 data->key_data, EAP_FAST_KEY_LEN);
837 sha1_t_prf(data->simck, EAP_FAST_SIMCK_LEN,
838 "Extended Session Key Generating Function",
839 (u8 *) "", 0, data->emsk, EAP_EMSK_LEN);
840 wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: Derived key (EMSK)",
841 data->emsk, EAP_EMSK_LEN);
843 data->success = 1;
845 return 0;
849 static int eap_fast_set_tls_master_secret(struct eap_sm *sm,
850 struct eap_fast_data *data,
851 const u8 *tls, size_t tls_len)
853 struct tls_keys keys;
854 u8 master_secret[48], *seed;
855 const u8 *server_random;
856 size_t seed_len, server_random_len;
858 if (data->tls_master_secret_set || !data->current_pac ||
859 tls_connection_get_keys(sm->ssl_ctx, data->ssl.conn, &keys) ||
860 keys.client_random == NULL) {
861 return 0;
864 wpa_hexdump(MSG_DEBUG, "EAP-FAST: client_random",
865 keys.client_random, keys.client_random_len);
867 /* TLS master secret is needed before TLS library has processed this
868 * message which includes both ServerHello and an encrypted handshake
869 * message, so we need to parse server_random from this message before
870 * passing it to TLS library.
872 * Example TLS packet header:
873 * (16 03 01 00 2a 02 00 00 26 03 01 <32 bytes server_random>)
874 * Content Type: Handshake: 0x16
875 * Version: TLS 1.0 (0x0301)
876 * Lenghth: 42 (0x002a)
877 * Handshake Type: Server Hello: 0x02
878 * Length: 38 (0x000026)
879 * Version TLS 1.0 (0x0301)
880 * Random: 32 bytes
882 if (tls_len < 43 || tls[0] != 0x16 ||
883 tls[1] != 0x03 || tls[2] != 0x01 ||
884 tls[5] != 0x02 || tls[9] != 0x03 || tls[10] != 0x01) {
885 wpa_hexdump(MSG_DEBUG, "EAP-FAST: unrecognized TLS "
886 "ServerHello", tls, tls_len);
887 return -1;
889 server_random = tls + 11;
890 server_random_len = 32;
891 wpa_hexdump(MSG_DEBUG, "EAP-FAST: server_random",
892 server_random, server_random_len);
894 seed_len = keys.client_random_len + server_random_len;
895 seed = os_malloc(seed_len);
896 if (seed == NULL)
897 return -1;
898 os_memcpy(seed, server_random, server_random_len);
899 os_memcpy(seed + server_random_len,
900 keys.client_random, keys.client_random_len);
902 wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: T-PRF seed", seed, seed_len);
903 wpa_hexdump_key(MSG_MSGDUMP, "EAP-FAST: PAC-Key",
904 data->current_pac->pac_key, EAP_FAST_PAC_KEY_LEN);
905 /* master_secret = T-PRF(PAC-Key, "PAC to master secret label hash",
906 * server_random + client_random, 48) */
907 sha1_t_prf(data->current_pac->pac_key, EAP_FAST_PAC_KEY_LEN,
908 "PAC to master secret label hash",
909 seed, seed_len, master_secret, sizeof(master_secret));
910 os_free(seed);
911 wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: TLS pre-master-secret",
912 master_secret, sizeof(master_secret));
914 data->tls_master_secret_set = 1;
916 return tls_connection_set_master_key(sm->ssl_ctx, data->ssl.conn,
917 master_secret,
918 sizeof(master_secret));
922 static u8 * eap_fast_derive_key(struct eap_sm *sm, struct eap_ssl_data *data,
923 char *label, size_t len)
925 struct tls_keys keys;
926 u8 *rnd = NULL, *out;
927 int block_size;
929 block_size = tls_connection_get_keyblock_size(sm->ssl_ctx, data->conn);
930 if (block_size < 0)
931 return NULL;
933 out = os_malloc(block_size + len);
934 if (out == NULL)
935 return NULL;
937 if (tls_connection_prf(sm->ssl_ctx, data->conn, label, 1, out,
938 block_size + len) == 0) {
939 os_memmove(out, out + block_size, len);
940 return out;
943 if (tls_connection_get_keys(sm->ssl_ctx, data->conn, &keys))
944 goto fail;
946 rnd = os_malloc(keys.client_random_len + keys.server_random_len);
947 if (rnd == NULL)
948 goto fail;
950 os_memcpy(rnd, keys.server_random, keys.server_random_len);
951 os_memcpy(rnd + keys.server_random_len, keys.client_random,
952 keys.client_random_len);
954 wpa_hexdump_key(MSG_MSGDUMP, "EAP-FAST: master_secret for key "
955 "expansion", keys.master_key, keys.master_key_len);
956 if (tls_prf(keys.master_key, keys.master_key_len,
957 label, rnd, keys.client_random_len +
958 keys.server_random_len, out, block_size + len))
959 goto fail;
960 os_free(rnd);
961 os_memmove(out, out + block_size, len);
962 return out;
964 fail:
965 os_free(rnd);
966 os_free(out);
967 return NULL;
971 static void eap_fast_derive_key_auth(struct eap_sm *sm,
972 struct eap_fast_data *data)
974 u8 *sks;
976 /* draft-cam-winget-eap-fast-05.txt:
977 * 5.1 EAP-FAST Authentication Phase 1: Key Derivations
978 * Extra key material after TLS key_block: session_ket_seed[40]
981 sks = eap_fast_derive_key(sm, &data->ssl, "key expansion",
982 EAP_FAST_SKS_LEN);
983 if (sks == NULL) {
984 wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to derive "
985 "session_key_seed");
986 return;
990 * draft-cam-winget-eap-fast-05.txt, 5.2:
991 * S-IMCK[0] = session_key_seed
993 wpa_hexdump_key(MSG_DEBUG,
994 "EAP-FAST: session_key_seed (SKS = S-IMCK[0])",
995 sks, EAP_FAST_SKS_LEN);
996 data->simck_idx = 0;
997 os_memcpy(data->simck, sks, EAP_FAST_SIMCK_LEN);
998 os_free(sks);
1002 static void eap_fast_derive_key_provisioning(struct eap_sm *sm,
1003 struct eap_fast_data *data)
1005 os_free(data->key_block_p);
1006 data->key_block_p = (struct eap_fast_key_block_provisioning *)
1007 eap_fast_derive_key(sm, &data->ssl, "key expansion",
1008 sizeof(*data->key_block_p));
1009 if (data->key_block_p == NULL) {
1010 wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to derive key block");
1011 return;
1014 * draft-cam-winget-eap-fast-05.txt, 5.2:
1015 * S-IMCK[0] = session_key_seed
1017 wpa_hexdump_key(MSG_DEBUG,
1018 "EAP-FAST: session_key_seed (SKS = S-IMCK[0])",
1019 data->key_block_p->session_key_seed,
1020 sizeof(data->key_block_p->session_key_seed));
1021 data->simck_idx = 0;
1022 os_memcpy(data->simck, data->key_block_p->session_key_seed,
1023 EAP_FAST_SIMCK_LEN);
1024 wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: server_challenge",
1025 data->key_block_p->server_challenge,
1026 sizeof(data->key_block_p->server_challenge));
1027 wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: client_challenge",
1028 data->key_block_p->client_challenge,
1029 sizeof(data->key_block_p->client_challenge));
1033 static void eap_fast_derive_keys(struct eap_sm *sm, struct eap_fast_data *data)
1035 if (data->current_pac) {
1036 eap_fast_derive_key_auth(sm, data);
1037 } else {
1038 eap_fast_derive_key_provisioning(sm, data);
1043 static int eap_fast_phase2_request(struct eap_sm *sm,
1044 struct eap_fast_data *data,
1045 struct eap_method_ret *ret,
1046 struct eap_hdr *hdr,
1047 u8 **resp, size_t *resp_len)
1049 size_t len = be_to_host16(hdr->length);
1050 u8 *pos;
1051 struct eap_method_ret iret;
1053 if (len <= sizeof(struct eap_hdr)) {
1054 wpa_printf(MSG_INFO, "EAP-FAST: too short "
1055 "Phase 2 request (len=%lu)", (unsigned long) len);
1056 return -1;
1058 pos = (u8 *) (hdr + 1);
1059 wpa_printf(MSG_DEBUG, "EAP-FAST: Phase 2 Request: type=%d", *pos);
1060 switch (*pos) {
1061 case EAP_TYPE_IDENTITY:
1062 *resp = eap_sm_buildIdentity(sm, hdr->identifier, resp_len, 1);
1063 break;
1064 default:
1065 if (data->phase2_type.vendor == EAP_VENDOR_IETF &&
1066 data->phase2_type.method == EAP_TYPE_NONE) {
1067 size_t i;
1068 for (i = 0; i < data->num_phase2_types; i++) {
1069 if (data->phase2_types[i].vendor !=
1070 EAP_VENDOR_IETF ||
1071 data->phase2_types[i].method != *pos)
1072 continue;
1074 data->phase2_type.vendor =
1075 data->phase2_types[i].vendor;
1076 data->phase2_type.method =
1077 data->phase2_types[i].method;
1078 wpa_printf(MSG_DEBUG, "EAP-FAST: Selected "
1079 "Phase 2 EAP vendor %d method %d",
1080 data->phase2_type.vendor,
1081 data->phase2_type.method);
1082 break;
1085 if (*pos != data->phase2_type.method ||
1086 *pos == EAP_TYPE_NONE) {
1087 if (eap_fast_phase2_nak(data, hdr, resp, resp_len))
1088 return -1;
1089 return 0;
1092 if (data->phase2_priv == NULL) {
1093 data->phase2_method = eap_sm_get_eap_methods(
1094 data->phase2_type.vendor,
1095 data->phase2_type.method);
1096 if (data->phase2_method) {
1097 if (data->key_block_p) {
1098 sm->auth_challenge =
1099 data->key_block_p->
1100 server_challenge;
1101 sm->peer_challenge =
1102 data->key_block_p->
1103 client_challenge;
1105 sm->init_phase2 = 1;
1106 sm->mschapv2_full_key = 1;
1107 data->phase2_priv =
1108 data->phase2_method->init(sm);
1109 sm->init_phase2 = 0;
1110 sm->mschapv2_full_key = 0;
1111 sm->auth_challenge = NULL;
1112 sm->peer_challenge = NULL;
1115 if (data->phase2_priv == NULL || data->phase2_method == NULL) {
1116 wpa_printf(MSG_INFO, "EAP-FAST: failed to initialize "
1117 "Phase 2 EAP method %d", *pos);
1118 ret->methodState = METHOD_DONE;
1119 ret->decision = DECISION_FAIL;
1120 return -1;
1122 os_memset(&iret, 0, sizeof(iret));
1123 *resp = data->phase2_method->process(sm, data->phase2_priv,
1124 &iret, (u8 *) hdr, len,
1125 resp_len);
1126 if (*resp == NULL ||
1127 (iret.methodState == METHOD_DONE &&
1128 iret.decision == DECISION_FAIL)) {
1129 ret->methodState = METHOD_DONE;
1130 ret->decision = DECISION_FAIL;
1131 } else if ((iret.methodState == METHOD_DONE ||
1132 iret.methodState == METHOD_MAY_CONT) &&
1133 (iret.decision == DECISION_UNCOND_SUCC ||
1134 iret.decision == DECISION_COND_SUCC)) {
1135 data->phase2_success = 1;
1137 if (*resp == NULL)
1138 return -1;
1139 break;
1141 return 0;
1145 static u8 * eap_fast_tlv_nak(int vendor_id, int tlv_type, size_t *len)
1147 struct eap_tlv_nak_tlv *nak;
1148 *len = sizeof(*nak);
1149 nak = os_malloc(*len);
1150 if (nak == NULL)
1151 return NULL;
1152 nak->tlv_type = host_to_be16(EAP_TLV_TYPE_MANDATORY | EAP_TLV_NAK_TLV);
1153 nak->length = host_to_be16(6);
1154 nak->vendor_id = host_to_be32(vendor_id);
1155 nak->nak_type = host_to_be16(tlv_type);
1156 return (u8 *) nak;
1160 static u8 * eap_fast_tlv_result(int status, int intermediate, size_t *len)
1162 struct eap_tlv_intermediate_result_tlv *result;
1163 *len = sizeof(*result);
1164 result = os_malloc(*len);
1165 if (result == NULL)
1166 return NULL;
1167 result->tlv_type = host_to_be16(EAP_TLV_TYPE_MANDATORY |
1168 (intermediate ?
1169 EAP_TLV_INTERMEDIATE_RESULT_TLV :
1170 EAP_TLV_RESULT_TLV));
1171 result->length = host_to_be16(2);
1172 result->status = host_to_be16(status);
1173 return (u8 *) result;
1177 static u8 * eap_fast_tlv_pac_ack(size_t *len)
1179 struct eap_tlv_result_tlv *res;
1180 struct eap_tlv_pac_ack_tlv *ack;
1182 *len = sizeof(*res) + sizeof(*ack);
1183 res = os_zalloc(*len);
1184 if (res == NULL)
1185 return NULL;
1187 res->tlv_type = host_to_be16(EAP_TLV_RESULT_TLV |
1188 EAP_TLV_TYPE_MANDATORY);
1189 res->length = host_to_be16(sizeof(*res) - sizeof(struct eap_tlv_hdr));
1190 res->status = host_to_be16(EAP_TLV_RESULT_SUCCESS);
1192 ack = (struct eap_tlv_pac_ack_tlv *) (res + 1);
1193 ack->tlv_type = host_to_be16(EAP_TLV_PAC_TLV |
1194 EAP_TLV_TYPE_MANDATORY);
1195 ack->length = host_to_be16(sizeof(*ack) - sizeof(struct eap_tlv_hdr));
1196 ack->pac_type = host_to_be16(PAC_TYPE_PAC_ACKNOWLEDGEMENT);
1197 ack->pac_len = host_to_be16(2);
1198 ack->result = host_to_be16(EAP_TLV_RESULT_SUCCESS);
1200 return (u8 *) res;
1204 static u8 * eap_fast_tlv_eap_payload(u8 *buf, size_t *len)
1206 struct eap_tlv_hdr *tlv;
1208 /* Encapsulate EAP packet in EAP Payload TLV */
1209 tlv = os_malloc(sizeof(*tlv) + *len);
1210 if (tlv == NULL) {
1211 wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to "
1212 "allocate memory for TLV "
1213 "encapsulation");
1214 os_free(buf);
1215 return NULL;
1217 tlv->tlv_type = host_to_be16(EAP_TLV_TYPE_MANDATORY |
1218 EAP_TLV_EAP_PAYLOAD_TLV);
1219 tlv->length = host_to_be16(*len);
1220 os_memcpy(tlv + 1, buf, *len);
1221 os_free(buf);
1222 *len += sizeof(*tlv);
1223 return (u8 *) tlv;
1227 static u8 * eap_fast_process_crypto_binding(
1228 struct eap_sm *sm, struct eap_fast_data *data,
1229 struct eap_method_ret *ret,
1230 struct eap_tlv_crypto_binding__tlv *_bind, size_t bind_len,
1231 size_t *resp_len, int final)
1233 u8 *resp;
1234 struct eap_tlv_intermediate_result_tlv *rresult;
1235 struct eap_tlv_crypto_binding__tlv *rbind;
1236 u8 isk[32], imck[60], *cmk, cmac[20], *key;
1237 size_t key_len;
1238 int res;
1240 wpa_printf(MSG_DEBUG, "EAP-FAST: Crypto-Binding TLV: Version %d "
1241 "Received Version %d SubType %d",
1242 _bind->version, _bind->received_version, _bind->subtype);
1243 wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: NONCE",
1244 _bind->nonce, sizeof(_bind->nonce));
1245 wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Compound MAC",
1246 _bind->compound_mac, sizeof(_bind->compound_mac));
1248 if (_bind->version != EAP_FAST_VERSION ||
1249 _bind->received_version != EAP_FAST_VERSION ||
1250 _bind->subtype != EAP_TLV_CRYPTO_BINDING_SUBTYPE_REQUEST) {
1251 wpa_printf(MSG_INFO, "EAP-FAST: Invalid version/subtype in "
1252 "Crypto-Binding TLV: Version %d "
1253 "Received Version %d SubType %d",
1254 _bind->version, _bind->received_version,
1255 _bind->subtype);
1256 resp = eap_fast_tlv_result(EAP_TLV_RESULT_FAILURE, 1,
1257 resp_len);
1258 return resp;
1261 wpa_printf(MSG_DEBUG, "EAP-FAST: Determining CMK[%d] for Compound MIC "
1262 "calculation", data->simck_idx + 1);
1265 * draft-cam-winget-eap-fast-05.txt, 5.2:
1266 * IMCK[j] = T-PRF(S-IMCK[j-1], "Inner Methods Compound Keys",
1267 * MSK[j], 60)
1268 * S-IMCK[j] = first 40 octets of IMCK[j]
1269 * CMK[j] = last 20 octets of IMCK[j]
1272 os_memset(isk, 0, sizeof(isk));
1273 if (data->phase2_method == NULL || data->phase2_priv == NULL) {
1274 wpa_printf(MSG_DEBUG, "EAP-FAST: Phase 2 method not "
1275 "available");
1276 return NULL;
1278 if (data->phase2_method->isKeyAvailable && data->phase2_method->getKey)
1280 if (!data->phase2_method->isKeyAvailable(sm, data->phase2_priv)
1282 (key = data->phase2_method->getKey(sm, data->phase2_priv,
1283 &key_len)) == NULL) {
1284 wpa_printf(MSG_DEBUG, "EAP-FAST: Could not get key "
1285 "material from Phase 2");
1286 return NULL;
1288 if (key_len > sizeof(isk))
1289 key_len = sizeof(isk);
1290 os_memcpy(isk, key, key_len);
1291 os_free(key);
1293 wpa_hexdump_key(MSG_MSGDUMP, "EAP-FAST: ISK[j]", isk, sizeof(isk));
1294 sha1_t_prf(data->simck, EAP_FAST_SIMCK_LEN,
1295 "Inner Methods Compound Keys",
1296 isk, sizeof(isk), imck, sizeof(imck));
1297 data->simck_idx++;
1298 os_memcpy(data->simck, imck, EAP_FAST_SIMCK_LEN);
1299 wpa_hexdump_key(MSG_MSGDUMP, "EAP-FAST: S-IMCK[j]",
1300 data->simck, EAP_FAST_SIMCK_LEN);
1301 cmk = imck + EAP_FAST_SIMCK_LEN;
1302 wpa_hexdump_key(MSG_MSGDUMP, "EAP-FAST: CMK[j]", cmk, 20);
1304 os_memcpy(cmac, _bind->compound_mac, sizeof(cmac));
1305 os_memset(_bind->compound_mac, 0, sizeof(cmac));
1306 wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Crypto-Binding TLV for Compound "
1307 "MAC calculation", (u8 *) _bind, bind_len);
1308 hmac_sha1(cmk, 20, (u8 *) _bind, bind_len, _bind->compound_mac);
1309 res = os_memcmp(cmac, _bind->compound_mac, sizeof(cmac));
1310 wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Received Compound MAC",
1311 cmac, sizeof(cmac));
1312 wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Calculated Compound MAC",
1313 _bind->compound_mac, sizeof(cmac));
1314 if (res != 0) {
1315 wpa_printf(MSG_INFO, "EAP-FAST: Compound MAC did not match");
1316 resp = eap_fast_tlv_result(EAP_TLV_RESULT_FAILURE, 1,
1317 resp_len);
1318 os_memcpy(_bind->compound_mac, cmac, sizeof(cmac));
1319 return resp;
1322 *resp_len = sizeof(*rresult) + sizeof(*rbind);
1323 resp = os_zalloc(*resp_len);
1324 if (resp == NULL)
1325 return NULL;
1327 /* Both intermediate and final Result TLVs are identical, so ok to use
1328 * the same structure definition for them. */
1329 rresult = (struct eap_tlv_intermediate_result_tlv *) resp;
1330 rresult->tlv_type = host_to_be16(EAP_TLV_TYPE_MANDATORY |
1331 (final ? EAP_TLV_RESULT_TLV :
1332 EAP_TLV_INTERMEDIATE_RESULT_TLV));
1333 rresult->length = host_to_be16(2);
1334 rresult->status = host_to_be16(EAP_TLV_RESULT_SUCCESS);
1336 if (!data->provisioning && data->phase2_success &&
1337 eap_fast_derive_msk(data) < 0) {
1338 wpa_printf(MSG_INFO, "EAP-FAST: Failed to generate MSK");
1339 ret->methodState = METHOD_DONE;
1340 ret->decision = DECISION_FAIL;
1341 rresult->status = host_to_be16(EAP_TLV_RESULT_FAILURE);
1342 data->phase2_success = 0;
1345 rbind = (struct eap_tlv_crypto_binding__tlv *) (rresult + 1);
1346 rbind->tlv_type = host_to_be16(EAP_TLV_TYPE_MANDATORY |
1347 EAP_TLV_CRYPTO_BINDING_TLV_);
1348 rbind->length = host_to_be16(sizeof(*rbind) -
1349 sizeof(struct eap_tlv_hdr));
1350 rbind->version = EAP_FAST_VERSION;
1351 rbind->received_version = _bind->version;
1352 rbind->subtype = EAP_TLV_CRYPTO_BINDING_SUBTYPE_RESPONSE;
1353 os_memcpy(rbind->nonce, _bind->nonce, sizeof(_bind->nonce));
1354 inc_byte_array(rbind->nonce, sizeof(rbind->nonce));
1355 hmac_sha1(cmk, 20, (u8 *) rbind, sizeof(*rbind), rbind->compound_mac);
1357 wpa_printf(MSG_DEBUG, "EAP-FAST: Reply Crypto-Binding TLV: Version %d "
1358 "Received Version %d SubType %d",
1359 rbind->version, rbind->received_version, rbind->subtype);
1360 wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: NONCE",
1361 rbind->nonce, sizeof(rbind->nonce));
1362 wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Compound MAC",
1363 rbind->compound_mac, sizeof(rbind->compound_mac));
1365 if (final && data->phase2_success) {
1366 wpa_printf(MSG_DEBUG, "EAP-FAST: Authentication completed "
1367 "successfully.");
1368 ret->methodState = METHOD_DONE;
1369 ret->decision = DECISION_UNCOND_SUCC;
1372 return resp;
1376 static u8 * eap_fast_process_pac(struct eap_sm *sm, struct eap_fast_data *data,
1377 struct eap_method_ret *ret,
1378 u8 *pac, size_t pac_len, size_t *resp_len)
1380 struct wpa_ssid *config = eap_get_config(sm);
1381 struct pac_tlv_hdr *hdr;
1382 u8 *pos;
1383 size_t left, len;
1384 int type, pac_key_found = 0;
1385 struct eap_fast_pac entry;
1387 os_memset(&entry, 0, sizeof(entry));
1388 pos = pac;
1389 left = pac_len;
1390 while (left > sizeof(*hdr)) {
1391 hdr = (struct pac_tlv_hdr *) pos;
1392 type = be_to_host16(hdr->type);
1393 len = be_to_host16(hdr->len);
1394 pos += sizeof(*hdr);
1395 left -= sizeof(*hdr);
1396 if (len > left) {
1397 wpa_printf(MSG_DEBUG, "EAP-FAST: PAC TLV overrun "
1398 "(type=%d len=%lu left=%lu)",
1399 type, (unsigned long) len,
1400 (unsigned long) left);
1401 return eap_fast_tlv_result(EAP_TLV_RESULT_FAILURE, 0,
1402 resp_len);
1404 switch (type) {
1405 case PAC_TYPE_PAC_KEY:
1406 wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: PAC-Key",
1407 pos, len);
1408 if (len != EAP_FAST_PAC_KEY_LEN) {
1409 wpa_printf(MSG_DEBUG, "EAP-FAST: Invalid "
1410 "PAC-Key length %lu",
1411 (unsigned long) len);
1412 break;
1414 pac_key_found = 1;
1415 os_memcpy(entry.pac_key, pos, len);
1416 break;
1417 case PAC_TYPE_PAC_OPAQUE:
1418 wpa_hexdump(MSG_DEBUG, "EAP-FAST: PAC-Opaque",
1419 pos, len);
1420 entry.pac_opaque = pos;
1421 entry.pac_opaque_len = len;
1422 break;
1423 case PAC_TYPE_PAC_INFO:
1424 wpa_hexdump(MSG_DEBUG, "EAP-FAST: PAC-Info",
1425 pos, len);
1426 entry.pac_info = pos;
1427 entry.pac_info_len = len;
1428 break;
1429 default:
1430 wpa_printf(MSG_DEBUG, "EAP-FAST: Ignored unknown PAC "
1431 "type %d", type);
1432 break;
1435 pos += len;
1436 left -= len;
1439 if (!pac_key_found || !entry.pac_opaque || !entry.pac_info) {
1440 wpa_printf(MSG_DEBUG, "EAP-FAST: PAC TLV does not include "
1441 "all the required fields");
1442 return eap_fast_tlv_result(EAP_TLV_RESULT_FAILURE, 0,
1443 resp_len);
1446 pos = entry.pac_info;
1447 left = entry.pac_info_len;
1448 while (left > sizeof(*hdr)) {
1449 hdr = (struct pac_tlv_hdr *) pos;
1450 type = be_to_host16(hdr->type);
1451 len = be_to_host16(hdr->len);
1452 pos += sizeof(*hdr);
1453 left -= sizeof(*hdr);
1454 if (len > left) {
1455 wpa_printf(MSG_DEBUG, "EAP-FAST: PAC-Info overrun "
1456 "(type=%d len=%lu left=%lu)",
1457 type, (unsigned long) len,
1458 (unsigned long) left);
1459 return eap_fast_tlv_result(EAP_TLV_RESULT_FAILURE, 0,
1460 resp_len);
1462 switch (type) {
1463 case PAC_TYPE_A_ID:
1464 wpa_hexdump_ascii(MSG_DEBUG, "EAP-FAST: PAC-Info - "
1465 "A-ID", pos, len);
1466 entry.a_id = pos;
1467 entry.a_id_len = len;
1468 break;
1469 case PAC_TYPE_I_ID:
1470 wpa_hexdump_ascii(MSG_DEBUG, "EAP-FAST: PAC-Info - "
1471 "I-ID", pos, len);
1472 entry.i_id = pos;
1473 entry.i_id_len = len;
1474 break;
1475 case PAC_TYPE_A_ID_INFO:
1476 wpa_hexdump_ascii(MSG_DEBUG, "EAP-FAST: PAC-Info - "
1477 "A-ID-Info", pos, len);
1478 entry.a_id_info = pos;
1479 entry.a_id_info_len = len;
1480 break;
1481 default:
1482 wpa_printf(MSG_DEBUG, "EAP-FAST: Ignored unknown "
1483 "PAC-Info type %d", type);
1484 break;
1487 pos += len;
1488 left -= len;
1491 if (entry.a_id == NULL || entry.a_id_info == NULL) {
1492 wpa_printf(MSG_DEBUG, "EAP-FAST: PAC-Info does not include "
1493 "all the required fields");
1494 return eap_fast_tlv_result(EAP_TLV_RESULT_FAILURE, 0,
1495 resp_len);
1498 eap_fast_add_pac(data, &entry);
1499 eap_fast_save_pac(sm, data, config->pac_file);
1501 if (data->provisioning) {
1502 /* EAP-FAST provisioning does not provide keying material and
1503 * must end with an EAP-Failure. Authentication will be done
1504 * separately after this. */
1505 data->success = 0;
1506 ret->decision = DECISION_FAIL;
1507 wpa_printf(MSG_DEBUG, "EAP-FAST: Send PAC-Acknowledgement TLV "
1508 "- Provisioning completed successfully");
1509 } else {
1510 /* This is PAC refreshing, i.e., normal authentication that is
1511 * expected to be completed with an EAP-Success. */
1512 wpa_printf(MSG_DEBUG, "EAP-FAST: Send PAC-Acknowledgement TLV "
1513 "- PAC refreshing completed successfully");
1514 ret->decision = DECISION_UNCOND_SUCC;
1516 ret->methodState = METHOD_DONE;
1517 return eap_fast_tlv_pac_ack(resp_len);
1521 static int eap_fast_decrypt(struct eap_sm *sm, struct eap_fast_data *data,
1522 struct eap_method_ret *ret,
1523 const struct eap_hdr *req,
1524 const u8 *in_data, size_t in_len,
1525 u8 **out_data, size_t *out_len)
1527 u8 *in_decrypted, *pos, *end;
1528 int len_decrypted, len;
1529 struct eap_hdr *hdr;
1530 u8 *resp = NULL;
1531 size_t buf_len, resp_len;
1532 int mandatory, tlv_type;
1533 u8 *eap_payload_tlv = NULL, *pac = NULL;
1534 size_t eap_payload_tlv_len = 0, pac_len = 0;
1535 int iresult = 0, result = 0;
1536 struct eap_tlv_crypto_binding__tlv *crypto_binding = NULL;
1537 size_t crypto_binding_len = 0;
1538 const u8 *msg;
1539 size_t msg_len;
1540 int need_more_input, stop;
1542 wpa_printf(MSG_DEBUG, "EAP-FAST: received %lu bytes encrypted data for"
1543 " Phase 2", (unsigned long) in_len);
1545 msg = eap_tls_data_reassemble(sm, &data->ssl, in_data, in_len,
1546 &msg_len, &need_more_input);
1547 if (msg == NULL)
1548 return need_more_input ? 1 : -1;
1550 buf_len = in_len;
1551 if (data->ssl.tls_in_total > buf_len)
1552 buf_len = data->ssl.tls_in_total;
1553 in_decrypted = os_malloc(buf_len);
1554 if (in_decrypted == NULL) {
1555 os_free(data->ssl.tls_in);
1556 data->ssl.tls_in = NULL;
1557 data->ssl.tls_in_len = 0;
1558 wpa_printf(MSG_WARNING, "EAP-FAST: failed to allocate memory "
1559 "for decryption");
1560 return -1;
1563 len_decrypted = tls_connection_decrypt(sm->ssl_ctx, data->ssl.conn,
1564 msg, msg_len,
1565 in_decrypted, buf_len);
1566 os_free(data->ssl.tls_in);
1567 data->ssl.tls_in = NULL;
1568 data->ssl.tls_in_len = 0;
1569 if (len_decrypted < 0) {
1570 wpa_printf(MSG_INFO, "EAP-FAST: Failed to decrypt Phase 2 "
1571 "data");
1572 os_free(in_decrypted);
1573 return -1;
1576 wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Decrypted Phase 2 TLV(s)",
1577 in_decrypted, len_decrypted);
1579 if (len_decrypted < 4) {
1580 os_free(in_decrypted);
1581 wpa_printf(MSG_INFO, "EAP-FAST: Too short Phase 2 "
1582 "TLV frame (len=%d)", len_decrypted);
1583 return -1;
1586 pos = in_decrypted;
1587 end = in_decrypted + len_decrypted;
1588 stop = 0;
1589 while (pos + 4 < end && !stop) {
1590 mandatory = pos[0] & 0x80;
1591 tlv_type = WPA_GET_BE16(pos) & 0x3fff;
1592 pos += 2;
1593 len = WPA_GET_BE16(pos);
1594 pos += 2;
1595 if (pos + len > end) {
1596 os_free(in_decrypted);
1597 wpa_printf(MSG_INFO, "EAP-FAST: TLV overflow");
1598 return 0;
1600 wpa_printf(MSG_DEBUG, "EAP-FAST: received Phase 2: "
1601 "TLV type %d length %d%s",
1602 tlv_type, len, mandatory ? " (mandatory)" : "");
1604 switch (tlv_type) {
1605 case EAP_TLV_EAP_PAYLOAD_TLV:
1606 wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: EAP Payload TLV",
1607 pos, len);
1608 eap_payload_tlv = pos;
1609 eap_payload_tlv_len = len;
1610 break;
1611 case EAP_TLV_RESULT_TLV:
1612 wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Result TLV",
1613 pos, len);
1614 if (len < 2) {
1615 wpa_printf(MSG_DEBUG, "EAP-FAST: Too short "
1616 "Result TLV");
1617 result = EAP_TLV_RESULT_FAILURE;
1618 break;
1620 result = WPA_GET_BE16(pos);
1621 if (result != EAP_TLV_RESULT_SUCCESS &&
1622 result != EAP_TLV_RESULT_FAILURE) {
1623 wpa_printf(MSG_DEBUG, "EAP-FAST: Unknown "
1624 "Result %d", result);
1625 result = EAP_TLV_RESULT_FAILURE;
1627 wpa_printf(MSG_DEBUG, "EAP-FAST: Result: %s",
1628 result == EAP_TLV_RESULT_SUCCESS ?
1629 "Success" : "Failure");
1630 break;
1631 case EAP_TLV_INTERMEDIATE_RESULT_TLV:
1632 wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Intermediate "
1633 "Result TLV", pos, len);
1634 if (len < 2) {
1635 wpa_printf(MSG_DEBUG, "EAP-FAST: Too short "
1636 "Intermediate Result TLV");
1637 iresult = EAP_TLV_RESULT_FAILURE;
1638 break;
1640 iresult = WPA_GET_BE16(pos);
1641 if (iresult != EAP_TLV_RESULT_SUCCESS &&
1642 iresult != EAP_TLV_RESULT_FAILURE) {
1643 wpa_printf(MSG_DEBUG, "EAP-FAST: Unknown "
1644 "Intermediate Result %d", iresult);
1645 iresult = EAP_TLV_RESULT_FAILURE;
1647 wpa_printf(MSG_DEBUG,
1648 "EAP-FAST: Intermediate Result: %s",
1649 iresult == EAP_TLV_RESULT_SUCCESS ?
1650 "Success" : "Failure");
1651 break;
1652 case EAP_TLV_CRYPTO_BINDING_TLV_:
1653 wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Crypto-Binding "
1654 "TLV", pos, len);
1655 crypto_binding_len = sizeof(struct eap_tlv_hdr) + len;
1656 if (crypto_binding_len < sizeof(*crypto_binding)) {
1657 wpa_printf(MSG_DEBUG, "EAP-FAST: Too short "
1658 "Crypto-Binding TLV");
1659 iresult = EAP_TLV_RESULT_FAILURE;
1660 pos = end;
1661 break;
1663 crypto_binding =
1664 (struct eap_tlv_crypto_binding__tlv *)
1665 (pos - sizeof(struct eap_tlv_hdr));
1666 break;
1667 case EAP_TLV_PAC_TLV:
1668 wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: PAC TLV",
1669 pos, len);
1670 pac = pos;
1671 pac_len = len;
1672 break;
1673 default:
1674 if (mandatory) {
1675 wpa_printf(MSG_DEBUG, "EAP-FAST: Nak unknown "
1676 "mandatory TLV type %d", tlv_type);
1677 resp = eap_fast_tlv_nak(0, tlv_type,
1678 &resp_len);
1679 stop = 1;
1680 } else {
1681 wpa_printf(MSG_DEBUG, "EAP-FAST: ignored "
1682 "unknown optional TLV type %d",
1683 tlv_type);
1685 break;
1688 pos += len;
1691 if (!resp && result == EAP_TLV_RESULT_FAILURE) {
1692 resp = eap_fast_tlv_result(EAP_TLV_RESULT_FAILURE, 0,
1693 &resp_len);
1694 if (!resp) {
1695 os_free(in_decrypted);
1696 return 0;
1700 if (!resp && iresult == EAP_TLV_RESULT_FAILURE) {
1701 resp = eap_fast_tlv_result(EAP_TLV_RESULT_FAILURE, 1,
1702 &resp_len);
1703 if (!resp) {
1704 os_free(in_decrypted);
1705 return 0;
1709 if (!resp && eap_payload_tlv) {
1710 if (eap_payload_tlv_len < sizeof(*hdr)) {
1711 wpa_printf(MSG_DEBUG, "EAP-FAST: too short EAP "
1712 "Payload TLV (len=%lu)",
1713 (unsigned long) eap_payload_tlv_len);
1714 os_free(in_decrypted);
1715 return 0;
1717 hdr = (struct eap_hdr *) eap_payload_tlv;
1718 if (be_to_host16(hdr->length) > eap_payload_tlv_len) {
1719 wpa_printf(MSG_DEBUG, "EAP-FAST: EAP packet overflow "
1720 "in EAP Payload TLV");
1721 os_free(in_decrypted);
1722 return 0;
1724 if (hdr->code == EAP_CODE_REQUEST) {
1725 if (eap_fast_phase2_request(sm, data, ret, hdr,
1726 &resp, &resp_len)) {
1727 os_free(in_decrypted);
1728 wpa_printf(MSG_INFO, "EAP-FAST: Phase2 "
1729 "Request processing failed");
1730 return 0;
1732 resp = eap_fast_tlv_eap_payload(resp, &resp_len);
1733 if (resp == NULL) {
1734 os_free(in_decrypted);
1735 return 0;
1737 } else {
1738 wpa_printf(MSG_INFO, "EAP-FAST: Unexpected code=%d in "
1739 "Phase 2 EAP header", hdr->code);
1740 os_free(in_decrypted);
1741 return 0;
1745 if (!resp && crypto_binding) {
1746 int final = result == EAP_TLV_RESULT_SUCCESS;
1747 resp = eap_fast_process_crypto_binding(sm, data, ret,
1748 crypto_binding,
1749 crypto_binding_len,
1750 &resp_len, final);
1751 if (!resp) {
1752 os_free(in_decrypted);
1753 return 0;
1757 if (!resp && pac && result != EAP_TLV_RESULT_SUCCESS) {
1758 wpa_printf(MSG_DEBUG, "EAP-FAST: PAC TLV without Result TLV "
1759 "acknowledging success");
1760 resp = eap_fast_tlv_result(EAP_TLV_RESULT_FAILURE, 0,
1761 &resp_len);
1762 if (!resp) {
1763 os_free(in_decrypted);
1764 return 0;
1768 if (!resp && pac && result == EAP_TLV_RESULT_SUCCESS) {
1769 resp = eap_fast_process_pac(sm, data, ret, pac, pac_len,
1770 &resp_len);
1771 if (!resp) {
1772 os_free(in_decrypted);
1773 return 0;
1777 os_free(in_decrypted);
1779 if (resp == NULL) {
1780 wpa_printf(MSG_DEBUG, "EAP-FAST: No recognized TLVs - send "
1781 "empty response packet");
1782 resp = os_malloc(1);
1783 if (resp == NULL)
1784 return 0;
1785 resp_len = 0;
1788 wpa_hexdump(MSG_DEBUG, "EAP-FAST: Encrypting Phase 2 data",
1789 resp, resp_len);
1790 if (eap_fast_encrypt(sm, data, req->identifier, resp, resp_len,
1791 out_data, out_len)) {
1792 wpa_printf(MSG_INFO, "EAP-FAST: Failed to encrypt a Phase 2 "
1793 "frame");
1795 os_free(resp);
1797 return 0;
1801 static u8 * eap_fast_process(struct eap_sm *sm, void *priv,
1802 struct eap_method_ret *ret,
1803 const u8 *reqData, size_t reqDataLen,
1804 size_t *respDataLen)
1806 const struct eap_hdr *req;
1807 size_t left;
1808 int res;
1809 u8 flags, *resp, id;
1810 const u8 *pos;
1811 struct eap_fast_data *data = priv;
1813 pos = eap_tls_process_init(sm, &data->ssl, EAP_TYPE_FAST, ret,
1814 reqData, reqDataLen, &left, &flags);
1815 if (pos == NULL)
1816 return NULL;
1817 req = (const struct eap_hdr *) reqData;
1818 id = req->identifier;
1820 if (flags & EAP_TLS_FLAGS_START) {
1821 const u8 *a_id;
1822 size_t a_id_len;
1823 struct pac_tlv_hdr *hdr;
1825 wpa_printf(MSG_DEBUG, "EAP-FAST: Start (server ver=%d, own "
1826 "ver=%d)", flags & EAP_PEAP_VERSION_MASK,
1827 data->fast_version);
1828 if ((flags & EAP_PEAP_VERSION_MASK) < data->fast_version)
1829 data->fast_version = flags & EAP_PEAP_VERSION_MASK;
1830 wpa_printf(MSG_DEBUG, "EAP-FAST: Using FAST version %d",
1831 data->fast_version);
1833 a_id = pos;
1834 a_id_len = left;
1835 if (left > sizeof(*hdr)) {
1836 int tlen;
1837 hdr = (struct pac_tlv_hdr *) pos;
1838 tlen = be_to_host16(hdr->len);
1839 if (be_to_host16(hdr->type) == PAC_TYPE_A_ID &&
1840 sizeof(*hdr) + tlen <= left) {
1841 a_id = (u8 *) (hdr + 1);
1842 a_id_len = tlen;
1845 wpa_hexdump_ascii(MSG_DEBUG, "EAP-FAST: A-ID", a_id, a_id_len);
1847 data->current_pac = eap_fast_get_pac(data, a_id, a_id_len);
1848 if (data->current_pac) {
1849 wpa_printf(MSG_DEBUG, "EAP-FAST: PAC found for this "
1850 "A-ID");
1851 wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-FAST: A-ID-Info",
1852 data->current_pac->a_id_info,
1853 data->current_pac->a_id_info_len);
1856 if (data->resuming && data->current_pac) {
1857 wpa_printf(MSG_DEBUG, "EAP-FAST: Trying to resume "
1858 "session - do not add PAC-Opaque to TLS "
1859 "ClientHello");
1860 if (tls_connection_client_hello_ext(
1861 sm->ssl_ctx, data->ssl.conn,
1862 TLS_EXT_PAC_OPAQUE, NULL, 0) < 0) {
1863 wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to "
1864 "remove PAC-Opaque TLS extension");
1865 return NULL;
1868 } else if (data->current_pac) {
1869 u8 *tlv;
1870 size_t tlv_len, olen;
1871 struct eap_tlv_hdr *ehdr;
1872 olen = data->current_pac->pac_opaque_len;
1873 tlv_len = sizeof(*ehdr) + olen;
1874 tlv = os_malloc(tlv_len);
1875 if (tlv) {
1876 ehdr = (struct eap_tlv_hdr *) tlv;
1877 ehdr->tlv_type =
1878 host_to_be16(PAC_TYPE_PAC_OPAQUE);
1879 ehdr->length = host_to_be16(olen);
1880 os_memcpy(ehdr + 1,
1881 data->current_pac->pac_opaque, olen);
1883 if (tlv == NULL ||
1884 tls_connection_client_hello_ext(
1885 sm->ssl_ctx, data->ssl.conn,
1886 TLS_EXT_PAC_OPAQUE, tlv, tlv_len) < 0) {
1887 wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to "
1888 "add PAC-Opaque TLS extension");
1889 os_free(tlv);
1890 return NULL;
1892 os_free(tlv);
1893 } else {
1894 u8 ciphers[2];
1895 if (!data->provisioning_allowed) {
1896 wpa_printf(MSG_DEBUG, "EAP-FAST: No PAC found "
1897 "and provisioning disabled");
1898 return NULL;
1900 wpa_printf(MSG_DEBUG, "EAP-FAST: No PAC found - "
1901 "starting provisioning");
1902 ciphers[0] = TLS_CIPHER_ANON_DH_AES128_SHA;
1903 ciphers[1] = TLS_CIPHER_NONE;
1904 if (tls_connection_set_cipher_list(sm->ssl_ctx,
1905 data->ssl.conn,
1906 ciphers)) {
1907 wpa_printf(MSG_INFO, "EAP-FAST: Could not "
1908 "configure anonymous DH for TLS "
1909 "connection");
1910 return NULL;
1912 if (tls_connection_client_hello_ext(
1913 sm->ssl_ctx, data->ssl.conn,
1914 TLS_EXT_PAC_OPAQUE, NULL, 0) < 0) {
1915 wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to "
1916 "remove PAC-Opaque TLS extension");
1917 return NULL;
1919 data->provisioning = 1;
1922 left = 0; /* A-ID is not used in further packet processing */
1925 resp = NULL;
1926 if (tls_connection_established(sm->ssl_ctx, data->ssl.conn) &&
1927 !data->resuming) {
1928 res = eap_fast_decrypt(sm, data, ret, req, pos, left,
1929 &resp, respDataLen);
1930 if (res < 0) {
1931 ret->methodState = METHOD_DONE;
1932 ret->decision = DECISION_FAIL;
1933 /* Ack possible Alert that may have caused failure in
1934 * decryption */
1935 res = 1;
1937 } else {
1938 if (eap_fast_set_tls_master_secret(sm, data, pos, left) < 0) {
1939 wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to configure "
1940 "TLS master secret");
1941 ret->methodState = METHOD_DONE;
1942 ret->decision = DECISION_FAIL;
1943 return NULL;
1946 res = eap_tls_process_helper(sm, &data->ssl, EAP_TYPE_FAST,
1947 data->fast_version, id, pos, left,
1948 &resp, respDataLen);
1950 if (tls_connection_established(sm->ssl_ctx, data->ssl.conn)) {
1951 wpa_printf(MSG_DEBUG,
1952 "EAP-FAST: TLS done, proceed to Phase 2");
1953 data->resuming = 0;
1954 eap_fast_derive_keys(sm, data);
1958 if (res == 1)
1959 return eap_tls_build_ack(&data->ssl, respDataLen, id,
1960 EAP_TYPE_FAST, data->fast_version);
1961 return resp;
1965 #if 0 /* FIX */
1966 static Boolean eap_fast_has_reauth_data(struct eap_sm *sm, void *priv)
1968 struct eap_fast_data *data = priv;
1969 return tls_connection_established(sm->ssl_ctx, data->ssl.conn);
1973 static void eap_fast_deinit_for_reauth(struct eap_sm *sm, void *priv)
1975 struct eap_fast_data *data = priv;
1976 os_free(data->key_block_p);
1977 data->key_block_p = NULL;
1981 static void * eap_fast_init_for_reauth(struct eap_sm *sm, void *priv)
1983 struct eap_fast_data *data = priv;
1984 if (eap_tls_reauth_init(sm, &data->ssl)) {
1985 os_free(data);
1986 return NULL;
1988 if (data->phase2_priv && data->phase2_method &&
1989 data->phase2_method->init_for_reauth)
1990 data->phase2_method->init_for_reauth(sm, data->phase2_priv);
1991 data->phase2_success = 0;
1992 data->resuming = 1;
1993 data->provisioning = 0;
1994 data->simck_idx = 0;
1995 return priv;
1997 #endif
2000 static int eap_fast_get_status(struct eap_sm *sm, void *priv, char *buf,
2001 size_t buflen, int verbose)
2003 struct eap_fast_data *data = priv;
2004 int len, ret;
2006 len = eap_tls_status(sm, &data->ssl, buf, buflen, verbose);
2007 if (data->phase2_method) {
2008 ret = os_snprintf(buf + len, buflen - len,
2009 "EAP-FAST Phase2 method=%s\n",
2010 data->phase2_method->name);
2011 if (ret < 0 || (size_t) ret >= buflen - len)
2012 return len;
2013 len += ret;
2015 return len;
2019 static Boolean eap_fast_isKeyAvailable(struct eap_sm *sm, void *priv)
2021 struct eap_fast_data *data = priv;
2022 return data->success;
2026 static u8 * eap_fast_getKey(struct eap_sm *sm, void *priv, size_t *len)
2028 struct eap_fast_data *data = priv;
2029 u8 *key;
2031 if (!data->success)
2032 return NULL;
2034 key = os_malloc(EAP_FAST_KEY_LEN);
2035 if (key == NULL)
2036 return NULL;
2038 *len = EAP_FAST_KEY_LEN;
2039 os_memcpy(key, data->key_data, EAP_FAST_KEY_LEN);
2041 return key;
2045 static u8 * eap_fast_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
2047 struct eap_fast_data *data = priv;
2048 u8 *key;
2050 if (!data->success)
2051 return NULL;
2053 key = os_malloc(EAP_EMSK_LEN);
2054 if (key == NULL)
2055 return NULL;
2057 *len = EAP_EMSK_LEN;
2058 os_memcpy(key, data->emsk, EAP_EMSK_LEN);
2060 return key;
2064 int eap_peer_fast_register(void)
2066 struct eap_method *eap;
2067 int ret;
2069 eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
2070 EAP_VENDOR_IETF, EAP_TYPE_FAST, "FAST");
2071 if (eap == NULL)
2072 return -1;
2074 eap->init = eap_fast_init;
2075 eap->deinit = eap_fast_deinit;
2076 eap->process = eap_fast_process;
2077 eap->isKeyAvailable = eap_fast_isKeyAvailable;
2078 eap->getKey = eap_fast_getKey;
2079 eap->get_status = eap_fast_get_status;
2080 #if 0
2081 eap->has_reauth_data = eap_fast_has_reauth_data;
2082 eap->deinit_for_reauth = eap_fast_deinit_for_reauth;
2083 eap->init_for_reauth = eap_fast_init_for_reauth;
2084 #endif
2085 eap->get_emsk = eap_fast_get_emsk;
2087 ret = eap_peer_method_register(eap);
2088 if (ret)
2089 eap_peer_method_free(eap);
2090 return ret;