16d49e1aeSJan Lentfer /*
26d49e1aeSJan Lentfer * EAP peer method: EAP-FAST (RFC 4851)
3*a1157835SDaniel Fojt * Copyright (c) 2004-2015, Jouni Malinen <j@w1.fi>
46d49e1aeSJan Lentfer *
53ff40c12SJohn Marino * This software may be distributed under the terms of the BSD license.
63ff40c12SJohn Marino * See README for more details.
76d49e1aeSJan Lentfer */
86d49e1aeSJan Lentfer
96d49e1aeSJan Lentfer #include "includes.h"
106d49e1aeSJan Lentfer
116d49e1aeSJan Lentfer #include "common.h"
123ff40c12SJohn Marino #include "crypto/tls.h"
133ff40c12SJohn Marino #include "crypto/sha1.h"
143ff40c12SJohn Marino #include "eap_common/eap_tlv_common.h"
156d49e1aeSJan Lentfer #include "eap_i.h"
166d49e1aeSJan Lentfer #include "eap_tls_common.h"
176d49e1aeSJan Lentfer #include "eap_config.h"
186d49e1aeSJan Lentfer #include "eap_fast_pac.h"
196d49e1aeSJan Lentfer
206d49e1aeSJan Lentfer #ifdef EAP_FAST_DYNAMIC
216d49e1aeSJan Lentfer #include "eap_fast_pac.c"
226d49e1aeSJan Lentfer #endif /* EAP_FAST_DYNAMIC */
236d49e1aeSJan Lentfer
246d49e1aeSJan Lentfer /* TODO:
256d49e1aeSJan Lentfer * - test session resumption and enable it if it interoperates
266d49e1aeSJan Lentfer * - password change (pending mschapv2 packet; replay decrypted packet)
276d49e1aeSJan Lentfer */
286d49e1aeSJan Lentfer
296d49e1aeSJan Lentfer
306d49e1aeSJan Lentfer static void eap_fast_deinit(struct eap_sm *sm, void *priv);
316d49e1aeSJan Lentfer
326d49e1aeSJan Lentfer
336d49e1aeSJan Lentfer struct eap_fast_data {
346d49e1aeSJan Lentfer struct eap_ssl_data ssl;
356d49e1aeSJan Lentfer
366d49e1aeSJan Lentfer int fast_version;
376d49e1aeSJan Lentfer
386d49e1aeSJan Lentfer const struct eap_method *phase2_method;
396d49e1aeSJan Lentfer void *phase2_priv;
406d49e1aeSJan Lentfer int phase2_success;
416d49e1aeSJan Lentfer
426d49e1aeSJan Lentfer struct eap_method_type phase2_type;
436d49e1aeSJan Lentfer struct eap_method_type *phase2_types;
446d49e1aeSJan Lentfer size_t num_phase2_types;
456d49e1aeSJan Lentfer int resuming; /* starting a resumed session */
466d49e1aeSJan Lentfer struct eap_fast_key_block_provisioning *key_block_p;
476d49e1aeSJan Lentfer #define EAP_FAST_PROV_UNAUTH 1
486d49e1aeSJan Lentfer #define EAP_FAST_PROV_AUTH 2
496d49e1aeSJan Lentfer int provisioning_allowed; /* Allowed PAC provisioning modes */
506d49e1aeSJan Lentfer int provisioning; /* doing PAC provisioning (not the normal auth) */
516d49e1aeSJan Lentfer int anon_provisioning; /* doing anonymous (unauthenticated)
526d49e1aeSJan Lentfer * provisioning */
536d49e1aeSJan Lentfer int session_ticket_used;
546d49e1aeSJan Lentfer
556d49e1aeSJan Lentfer u8 key_data[EAP_FAST_KEY_LEN];
563ff40c12SJohn Marino u8 *session_id;
573ff40c12SJohn Marino size_t id_len;
586d49e1aeSJan Lentfer u8 emsk[EAP_EMSK_LEN];
596d49e1aeSJan Lentfer int success;
606d49e1aeSJan Lentfer
616d49e1aeSJan Lentfer struct eap_fast_pac *pac;
626d49e1aeSJan Lentfer struct eap_fast_pac *current_pac;
636d49e1aeSJan Lentfer size_t max_pac_list_len;
646d49e1aeSJan Lentfer int use_pac_binary_format;
656d49e1aeSJan Lentfer
666d49e1aeSJan Lentfer u8 simck[EAP_FAST_SIMCK_LEN];
676d49e1aeSJan Lentfer int simck_idx;
686d49e1aeSJan Lentfer
696d49e1aeSJan Lentfer struct wpabuf *pending_phase2_req;
70*a1157835SDaniel Fojt struct wpabuf *pending_resp;
716d49e1aeSJan Lentfer };
726d49e1aeSJan Lentfer
736d49e1aeSJan Lentfer
eap_fast_session_ticket_cb(void * ctx,const u8 * ticket,size_t len,const u8 * client_random,const u8 * server_random,u8 * master_secret)746d49e1aeSJan Lentfer static int eap_fast_session_ticket_cb(void *ctx, const u8 *ticket, size_t len,
756d49e1aeSJan Lentfer const u8 *client_random,
766d49e1aeSJan Lentfer const u8 *server_random,
776d49e1aeSJan Lentfer u8 *master_secret)
786d49e1aeSJan Lentfer {
796d49e1aeSJan Lentfer struct eap_fast_data *data = ctx;
806d49e1aeSJan Lentfer
816d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-FAST: SessionTicket callback");
826d49e1aeSJan Lentfer
836d49e1aeSJan Lentfer if (client_random == NULL || server_random == NULL ||
846d49e1aeSJan Lentfer master_secret == NULL) {
856d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-FAST: SessionTicket failed - fall "
866d49e1aeSJan Lentfer "back to full TLS handshake");
876d49e1aeSJan Lentfer data->session_ticket_used = 0;
886d49e1aeSJan Lentfer if (data->provisioning_allowed) {
896d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-FAST: Try to provision a "
906d49e1aeSJan Lentfer "new PAC-Key");
916d49e1aeSJan Lentfer data->provisioning = 1;
926d49e1aeSJan Lentfer data->current_pac = NULL;
936d49e1aeSJan Lentfer }
946d49e1aeSJan Lentfer return 0;
956d49e1aeSJan Lentfer }
966d49e1aeSJan Lentfer
976d49e1aeSJan Lentfer wpa_hexdump(MSG_DEBUG, "EAP-FAST: SessionTicket", ticket, len);
986d49e1aeSJan Lentfer
996d49e1aeSJan Lentfer if (data->current_pac == NULL) {
1006d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-FAST: No PAC-Key available for "
1016d49e1aeSJan Lentfer "using SessionTicket");
1026d49e1aeSJan Lentfer data->session_ticket_used = 0;
1036d49e1aeSJan Lentfer return 0;
1046d49e1aeSJan Lentfer }
1056d49e1aeSJan Lentfer
1066d49e1aeSJan Lentfer eap_fast_derive_master_secret(data->current_pac->pac_key,
1076d49e1aeSJan Lentfer server_random, client_random,
1086d49e1aeSJan Lentfer master_secret);
1096d49e1aeSJan Lentfer
1106d49e1aeSJan Lentfer data->session_ticket_used = 1;
1116d49e1aeSJan Lentfer
1126d49e1aeSJan Lentfer return 1;
1136d49e1aeSJan Lentfer }
1146d49e1aeSJan Lentfer
1156d49e1aeSJan Lentfer
eap_fast_parse_phase1(struct eap_fast_data * data,const char * phase1)116*a1157835SDaniel Fojt static void eap_fast_parse_phase1(struct eap_fast_data *data,
1176d49e1aeSJan Lentfer const char *phase1)
1186d49e1aeSJan Lentfer {
1196d49e1aeSJan Lentfer const char *pos;
1206d49e1aeSJan Lentfer
1216d49e1aeSJan Lentfer pos = os_strstr(phase1, "fast_provisioning=");
1226d49e1aeSJan Lentfer if (pos) {
1236d49e1aeSJan Lentfer data->provisioning_allowed = atoi(pos + 18);
1246d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-FAST: Automatic PAC provisioning "
1256d49e1aeSJan Lentfer "mode: %d", data->provisioning_allowed);
1266d49e1aeSJan Lentfer }
1276d49e1aeSJan Lentfer
1286d49e1aeSJan Lentfer pos = os_strstr(phase1, "fast_max_pac_list_len=");
1296d49e1aeSJan Lentfer if (pos) {
1306d49e1aeSJan Lentfer data->max_pac_list_len = atoi(pos + 22);
1316d49e1aeSJan Lentfer if (data->max_pac_list_len == 0)
1326d49e1aeSJan Lentfer data->max_pac_list_len = 1;
1336d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-FAST: Maximum PAC list length: %lu",
1346d49e1aeSJan Lentfer (unsigned long) data->max_pac_list_len);
1356d49e1aeSJan Lentfer }
1366d49e1aeSJan Lentfer
1376d49e1aeSJan Lentfer pos = os_strstr(phase1, "fast_pac_format=binary");
1386d49e1aeSJan Lentfer if (pos) {
1396d49e1aeSJan Lentfer data->use_pac_binary_format = 1;
1406d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-FAST: Using binary format for PAC "
1416d49e1aeSJan Lentfer "list");
1426d49e1aeSJan Lentfer }
1436d49e1aeSJan Lentfer }
1446d49e1aeSJan Lentfer
1456d49e1aeSJan Lentfer
eap_fast_init(struct eap_sm * sm)1466d49e1aeSJan Lentfer static void * eap_fast_init(struct eap_sm *sm)
1476d49e1aeSJan Lentfer {
1486d49e1aeSJan Lentfer struct eap_fast_data *data;
1496d49e1aeSJan Lentfer struct eap_peer_config *config = eap_get_config(sm);
1506d49e1aeSJan Lentfer
151*a1157835SDaniel Fojt if (config == NULL)
152*a1157835SDaniel Fojt return NULL;
153*a1157835SDaniel Fojt
1546d49e1aeSJan Lentfer data = os_zalloc(sizeof(*data));
1556d49e1aeSJan Lentfer if (data == NULL)
1566d49e1aeSJan Lentfer return NULL;
1576d49e1aeSJan Lentfer data->fast_version = EAP_FAST_VERSION;
1586d49e1aeSJan Lentfer data->max_pac_list_len = 10;
1596d49e1aeSJan Lentfer
160*a1157835SDaniel Fojt if (config->phase1)
161*a1157835SDaniel Fojt eap_fast_parse_phase1(data, config->phase1);
1626d49e1aeSJan Lentfer
1636d49e1aeSJan Lentfer if (eap_peer_select_phase2_methods(config, "auth=",
1646d49e1aeSJan Lentfer &data->phase2_types,
1656d49e1aeSJan Lentfer &data->num_phase2_types) < 0) {
1666d49e1aeSJan Lentfer eap_fast_deinit(sm, data);
1676d49e1aeSJan Lentfer return NULL;
1686d49e1aeSJan Lentfer }
1696d49e1aeSJan Lentfer
1706d49e1aeSJan Lentfer data->phase2_type.vendor = EAP_VENDOR_IETF;
1716d49e1aeSJan Lentfer data->phase2_type.method = EAP_TYPE_NONE;
1726d49e1aeSJan Lentfer
1733ff40c12SJohn Marino if (eap_peer_tls_ssl_init(sm, &data->ssl, config, EAP_TYPE_FAST)) {
1746d49e1aeSJan Lentfer wpa_printf(MSG_INFO, "EAP-FAST: Failed to initialize SSL.");
1756d49e1aeSJan Lentfer eap_fast_deinit(sm, data);
1766d49e1aeSJan Lentfer return NULL;
1776d49e1aeSJan Lentfer }
1786d49e1aeSJan Lentfer
1796d49e1aeSJan Lentfer if (tls_connection_set_session_ticket_cb(sm->ssl_ctx, data->ssl.conn,
1806d49e1aeSJan Lentfer eap_fast_session_ticket_cb,
1816d49e1aeSJan Lentfer data) < 0) {
1826d49e1aeSJan Lentfer wpa_printf(MSG_INFO, "EAP-FAST: Failed to set SessionTicket "
1836d49e1aeSJan Lentfer "callback");
1846d49e1aeSJan Lentfer eap_fast_deinit(sm, data);
1856d49e1aeSJan Lentfer return NULL;
1866d49e1aeSJan Lentfer }
1876d49e1aeSJan Lentfer
1886d49e1aeSJan Lentfer /*
1896d49e1aeSJan Lentfer * The local RADIUS server in a Cisco AP does not seem to like empty
1906d49e1aeSJan Lentfer * fragments before data, so disable that workaround for CBC.
1916d49e1aeSJan Lentfer * TODO: consider making this configurable
1926d49e1aeSJan Lentfer */
1936d49e1aeSJan Lentfer if (tls_connection_enable_workaround(sm->ssl_ctx, data->ssl.conn)) {
1946d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to enable TLS "
1956d49e1aeSJan Lentfer "workarounds");
1966d49e1aeSJan Lentfer }
1976d49e1aeSJan Lentfer
1983ff40c12SJohn Marino if (!config->pac_file) {
1993ff40c12SJohn Marino wpa_printf(MSG_INFO, "EAP-FAST: No PAC file configured");
2003ff40c12SJohn Marino eap_fast_deinit(sm, data);
2013ff40c12SJohn Marino return NULL;
2023ff40c12SJohn Marino }
2033ff40c12SJohn Marino
2046d49e1aeSJan Lentfer if (data->use_pac_binary_format &&
2056d49e1aeSJan Lentfer eap_fast_load_pac_bin(sm, &data->pac, config->pac_file) < 0) {
2063ff40c12SJohn Marino wpa_printf(MSG_INFO, "EAP-FAST: Failed to load PAC file");
2076d49e1aeSJan Lentfer eap_fast_deinit(sm, data);
2086d49e1aeSJan Lentfer return NULL;
2096d49e1aeSJan Lentfer }
2106d49e1aeSJan Lentfer
2116d49e1aeSJan Lentfer if (!data->use_pac_binary_format &&
2126d49e1aeSJan Lentfer eap_fast_load_pac(sm, &data->pac, config->pac_file) < 0) {
2133ff40c12SJohn Marino wpa_printf(MSG_INFO, "EAP-FAST: Failed to load PAC file");
2146d49e1aeSJan Lentfer eap_fast_deinit(sm, data);
2156d49e1aeSJan Lentfer return NULL;
2166d49e1aeSJan Lentfer }
2176d49e1aeSJan Lentfer eap_fast_pac_list_truncate(data->pac, data->max_pac_list_len);
2186d49e1aeSJan Lentfer
2196d49e1aeSJan Lentfer if (data->pac == NULL && !data->provisioning_allowed) {
2206d49e1aeSJan Lentfer wpa_printf(MSG_INFO, "EAP-FAST: No PAC configured and "
2216d49e1aeSJan Lentfer "provisioning disabled");
2226d49e1aeSJan Lentfer eap_fast_deinit(sm, data);
2236d49e1aeSJan Lentfer return NULL;
2246d49e1aeSJan Lentfer }
2256d49e1aeSJan Lentfer
2266d49e1aeSJan Lentfer return data;
2276d49e1aeSJan Lentfer }
2286d49e1aeSJan Lentfer
2296d49e1aeSJan Lentfer
eap_fast_deinit(struct eap_sm * sm,void * priv)2306d49e1aeSJan Lentfer static void eap_fast_deinit(struct eap_sm *sm, void *priv)
2316d49e1aeSJan Lentfer {
2326d49e1aeSJan Lentfer struct eap_fast_data *data = priv;
2336d49e1aeSJan Lentfer struct eap_fast_pac *pac, *prev;
2346d49e1aeSJan Lentfer
2356d49e1aeSJan Lentfer if (data == NULL)
2366d49e1aeSJan Lentfer return;
2376d49e1aeSJan Lentfer if (data->phase2_priv && data->phase2_method)
2386d49e1aeSJan Lentfer data->phase2_method->deinit(sm, data->phase2_priv);
2396d49e1aeSJan Lentfer os_free(data->phase2_types);
2406d49e1aeSJan Lentfer os_free(data->key_block_p);
2416d49e1aeSJan Lentfer eap_peer_tls_ssl_deinit(sm, &data->ssl);
2426d49e1aeSJan Lentfer
2436d49e1aeSJan Lentfer pac = data->pac;
2446d49e1aeSJan Lentfer prev = NULL;
2456d49e1aeSJan Lentfer while (pac) {
2466d49e1aeSJan Lentfer prev = pac;
2476d49e1aeSJan Lentfer pac = pac->next;
2486d49e1aeSJan Lentfer eap_fast_free_pac(prev);
2496d49e1aeSJan Lentfer }
250*a1157835SDaniel Fojt os_memset(data->key_data, 0, EAP_FAST_KEY_LEN);
251*a1157835SDaniel Fojt os_memset(data->emsk, 0, EAP_EMSK_LEN);
2523ff40c12SJohn Marino os_free(data->session_id);
253*a1157835SDaniel Fojt wpabuf_clear_free(data->pending_phase2_req);
254*a1157835SDaniel Fojt wpabuf_clear_free(data->pending_resp);
2556d49e1aeSJan Lentfer os_free(data);
2566d49e1aeSJan Lentfer }
2576d49e1aeSJan Lentfer
2586d49e1aeSJan Lentfer
eap_fast_derive_msk(struct eap_fast_data * data)2596d49e1aeSJan Lentfer static int eap_fast_derive_msk(struct eap_fast_data *data)
2606d49e1aeSJan Lentfer {
261*a1157835SDaniel Fojt if (eap_fast_derive_eap_msk(data->simck, data->key_data) < 0 ||
262*a1157835SDaniel Fojt eap_fast_derive_eap_emsk(data->simck, data->emsk) < 0)
263*a1157835SDaniel Fojt return -1;
2646d49e1aeSJan Lentfer data->success = 1;
2656d49e1aeSJan Lentfer return 0;
2666d49e1aeSJan Lentfer }
2676d49e1aeSJan Lentfer
2686d49e1aeSJan Lentfer
eap_fast_derive_key_auth(struct eap_sm * sm,struct eap_fast_data * data)269*a1157835SDaniel Fojt static int eap_fast_derive_key_auth(struct eap_sm *sm,
2706d49e1aeSJan Lentfer struct eap_fast_data *data)
2716d49e1aeSJan Lentfer {
2726d49e1aeSJan Lentfer u8 *sks;
2736d49e1aeSJan Lentfer
2746d49e1aeSJan Lentfer /* RFC 4851, Section 5.1:
2756d49e1aeSJan Lentfer * Extra key material after TLS key_block: session_key_seed[40]
2766d49e1aeSJan Lentfer */
2776d49e1aeSJan Lentfer
278*a1157835SDaniel Fojt sks = eap_fast_derive_key(sm->ssl_ctx, data->ssl.conn,
2796d49e1aeSJan Lentfer EAP_FAST_SKS_LEN);
2806d49e1aeSJan Lentfer if (sks == NULL) {
2816d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to derive "
2826d49e1aeSJan Lentfer "session_key_seed");
283*a1157835SDaniel Fojt return -1;
2846d49e1aeSJan Lentfer }
2856d49e1aeSJan Lentfer
2866d49e1aeSJan Lentfer /*
2876d49e1aeSJan Lentfer * RFC 4851, Section 5.2:
2886d49e1aeSJan Lentfer * S-IMCK[0] = session_key_seed
2896d49e1aeSJan Lentfer */
2906d49e1aeSJan Lentfer wpa_hexdump_key(MSG_DEBUG,
2916d49e1aeSJan Lentfer "EAP-FAST: session_key_seed (SKS = S-IMCK[0])",
2926d49e1aeSJan Lentfer sks, EAP_FAST_SKS_LEN);
2936d49e1aeSJan Lentfer data->simck_idx = 0;
2946d49e1aeSJan Lentfer os_memcpy(data->simck, sks, EAP_FAST_SIMCK_LEN);
2956d49e1aeSJan Lentfer os_free(sks);
296*a1157835SDaniel Fojt return 0;
2976d49e1aeSJan Lentfer }
2986d49e1aeSJan Lentfer
2996d49e1aeSJan Lentfer
eap_fast_derive_key_provisioning(struct eap_sm * sm,struct eap_fast_data * data)300*a1157835SDaniel Fojt static int eap_fast_derive_key_provisioning(struct eap_sm *sm,
3016d49e1aeSJan Lentfer struct eap_fast_data *data)
3026d49e1aeSJan Lentfer {
3036d49e1aeSJan Lentfer os_free(data->key_block_p);
3046d49e1aeSJan Lentfer data->key_block_p = (struct eap_fast_key_block_provisioning *)
3056d49e1aeSJan Lentfer eap_fast_derive_key(sm->ssl_ctx, data->ssl.conn,
3066d49e1aeSJan Lentfer sizeof(*data->key_block_p));
3076d49e1aeSJan Lentfer if (data->key_block_p == NULL) {
3086d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to derive key block");
309*a1157835SDaniel Fojt return -1;
3106d49e1aeSJan Lentfer }
3116d49e1aeSJan Lentfer /*
3126d49e1aeSJan Lentfer * RFC 4851, Section 5.2:
3136d49e1aeSJan Lentfer * S-IMCK[0] = session_key_seed
3146d49e1aeSJan Lentfer */
3156d49e1aeSJan Lentfer wpa_hexdump_key(MSG_DEBUG,
3166d49e1aeSJan Lentfer "EAP-FAST: session_key_seed (SKS = S-IMCK[0])",
3176d49e1aeSJan Lentfer data->key_block_p->session_key_seed,
3186d49e1aeSJan Lentfer sizeof(data->key_block_p->session_key_seed));
3196d49e1aeSJan Lentfer data->simck_idx = 0;
3206d49e1aeSJan Lentfer os_memcpy(data->simck, data->key_block_p->session_key_seed,
3216d49e1aeSJan Lentfer EAP_FAST_SIMCK_LEN);
3226d49e1aeSJan Lentfer wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: server_challenge",
3236d49e1aeSJan Lentfer data->key_block_p->server_challenge,
3246d49e1aeSJan Lentfer sizeof(data->key_block_p->server_challenge));
3256d49e1aeSJan Lentfer wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: client_challenge",
3266d49e1aeSJan Lentfer data->key_block_p->client_challenge,
3276d49e1aeSJan Lentfer sizeof(data->key_block_p->client_challenge));
328*a1157835SDaniel Fojt return 0;
3296d49e1aeSJan Lentfer }
3306d49e1aeSJan Lentfer
3316d49e1aeSJan Lentfer
eap_fast_derive_keys(struct eap_sm * sm,struct eap_fast_data * data)332*a1157835SDaniel Fojt static int eap_fast_derive_keys(struct eap_sm *sm, struct eap_fast_data *data)
3336d49e1aeSJan Lentfer {
334*a1157835SDaniel Fojt int res;
335*a1157835SDaniel Fojt
3366d49e1aeSJan Lentfer if (data->anon_provisioning)
337*a1157835SDaniel Fojt res = eap_fast_derive_key_provisioning(sm, data);
3386d49e1aeSJan Lentfer else
339*a1157835SDaniel Fojt res = eap_fast_derive_key_auth(sm, data);
340*a1157835SDaniel Fojt return res;
3416d49e1aeSJan Lentfer }
3426d49e1aeSJan Lentfer
3436d49e1aeSJan Lentfer
eap_fast_init_phase2_method(struct eap_sm * sm,struct eap_fast_data * data)3446d49e1aeSJan Lentfer static int eap_fast_init_phase2_method(struct eap_sm *sm,
3456d49e1aeSJan Lentfer struct eap_fast_data *data)
3466d49e1aeSJan Lentfer {
3476d49e1aeSJan Lentfer data->phase2_method =
3486d49e1aeSJan Lentfer eap_peer_get_eap_method(data->phase2_type.vendor,
3496d49e1aeSJan Lentfer data->phase2_type.method);
3506d49e1aeSJan Lentfer if (data->phase2_method == NULL)
3516d49e1aeSJan Lentfer return -1;
3526d49e1aeSJan Lentfer
3536d49e1aeSJan Lentfer if (data->key_block_p) {
3546d49e1aeSJan Lentfer sm->auth_challenge = data->key_block_p->server_challenge;
3556d49e1aeSJan Lentfer sm->peer_challenge = data->key_block_p->client_challenge;
3566d49e1aeSJan Lentfer }
3576d49e1aeSJan Lentfer sm->init_phase2 = 1;
3586d49e1aeSJan Lentfer data->phase2_priv = data->phase2_method->init(sm);
3596d49e1aeSJan Lentfer sm->init_phase2 = 0;
3606d49e1aeSJan Lentfer sm->auth_challenge = NULL;
3616d49e1aeSJan Lentfer sm->peer_challenge = NULL;
3626d49e1aeSJan Lentfer
3636d49e1aeSJan Lentfer return data->phase2_priv == NULL ? -1 : 0;
3646d49e1aeSJan Lentfer }
3656d49e1aeSJan Lentfer
3666d49e1aeSJan Lentfer
eap_fast_select_phase2_method(struct eap_fast_data * data,u8 type)3676d49e1aeSJan Lentfer static int eap_fast_select_phase2_method(struct eap_fast_data *data, u8 type)
3686d49e1aeSJan Lentfer {
3696d49e1aeSJan Lentfer size_t i;
3706d49e1aeSJan Lentfer
3716d49e1aeSJan Lentfer /* TODO: TNC with anonymous provisioning; need to require both
3726d49e1aeSJan Lentfer * completed MSCHAPv2 and TNC */
3736d49e1aeSJan Lentfer
3746d49e1aeSJan Lentfer if (data->anon_provisioning && type != EAP_TYPE_MSCHAPV2) {
3756d49e1aeSJan Lentfer wpa_printf(MSG_INFO, "EAP-FAST: Only EAP-MSCHAPv2 is allowed "
3766d49e1aeSJan Lentfer "during unauthenticated provisioning; reject phase2"
3776d49e1aeSJan Lentfer " type %d", type);
3786d49e1aeSJan Lentfer return -1;
3796d49e1aeSJan Lentfer }
3806d49e1aeSJan Lentfer
3816d49e1aeSJan Lentfer #ifdef EAP_TNC
3826d49e1aeSJan Lentfer if (type == EAP_TYPE_TNC) {
3836d49e1aeSJan Lentfer data->phase2_type.vendor = EAP_VENDOR_IETF;
3846d49e1aeSJan Lentfer data->phase2_type.method = EAP_TYPE_TNC;
3856d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-FAST: Selected Phase 2 EAP "
3866d49e1aeSJan Lentfer "vendor %d method %d for TNC",
3876d49e1aeSJan Lentfer data->phase2_type.vendor,
3886d49e1aeSJan Lentfer data->phase2_type.method);
3896d49e1aeSJan Lentfer return 0;
3906d49e1aeSJan Lentfer }
3916d49e1aeSJan Lentfer #endif /* EAP_TNC */
3926d49e1aeSJan Lentfer
3936d49e1aeSJan Lentfer for (i = 0; i < data->num_phase2_types; i++) {
3946d49e1aeSJan Lentfer if (data->phase2_types[i].vendor != EAP_VENDOR_IETF ||
3956d49e1aeSJan Lentfer data->phase2_types[i].method != type)
3966d49e1aeSJan Lentfer continue;
3976d49e1aeSJan Lentfer
3986d49e1aeSJan Lentfer data->phase2_type.vendor = data->phase2_types[i].vendor;
3996d49e1aeSJan Lentfer data->phase2_type.method = data->phase2_types[i].method;
4006d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-FAST: Selected Phase 2 EAP "
4016d49e1aeSJan Lentfer "vendor %d method %d",
4026d49e1aeSJan Lentfer data->phase2_type.vendor,
4036d49e1aeSJan Lentfer data->phase2_type.method);
4046d49e1aeSJan Lentfer break;
4056d49e1aeSJan Lentfer }
4066d49e1aeSJan Lentfer
4076d49e1aeSJan Lentfer if (type != data->phase2_type.method || type == EAP_TYPE_NONE)
4086d49e1aeSJan Lentfer return -1;
4096d49e1aeSJan Lentfer
4106d49e1aeSJan Lentfer return 0;
4116d49e1aeSJan Lentfer }
4126d49e1aeSJan Lentfer
4136d49e1aeSJan Lentfer
eap_fast_phase2_request(struct eap_sm * sm,struct eap_fast_data * data,struct eap_method_ret * ret,struct eap_hdr * hdr,struct wpabuf ** resp)4146d49e1aeSJan Lentfer static int eap_fast_phase2_request(struct eap_sm *sm,
4156d49e1aeSJan Lentfer struct eap_fast_data *data,
4166d49e1aeSJan Lentfer struct eap_method_ret *ret,
4176d49e1aeSJan Lentfer struct eap_hdr *hdr,
4186d49e1aeSJan Lentfer struct wpabuf **resp)
4196d49e1aeSJan Lentfer {
4206d49e1aeSJan Lentfer size_t len = be_to_host16(hdr->length);
4216d49e1aeSJan Lentfer u8 *pos;
4226d49e1aeSJan Lentfer struct eap_method_ret iret;
4236d49e1aeSJan Lentfer struct eap_peer_config *config = eap_get_config(sm);
4246d49e1aeSJan Lentfer struct wpabuf msg;
4256d49e1aeSJan Lentfer
4266d49e1aeSJan Lentfer if (len <= sizeof(struct eap_hdr)) {
4276d49e1aeSJan Lentfer wpa_printf(MSG_INFO, "EAP-FAST: too short "
4286d49e1aeSJan Lentfer "Phase 2 request (len=%lu)", (unsigned long) len);
4296d49e1aeSJan Lentfer return -1;
4306d49e1aeSJan Lentfer }
4316d49e1aeSJan Lentfer pos = (u8 *) (hdr + 1);
4326d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-FAST: Phase 2 Request: type=%d", *pos);
4336d49e1aeSJan Lentfer if (*pos == EAP_TYPE_IDENTITY) {
4346d49e1aeSJan Lentfer *resp = eap_sm_buildIdentity(sm, hdr->identifier, 1);
4356d49e1aeSJan Lentfer return 0;
4366d49e1aeSJan Lentfer }
4376d49e1aeSJan Lentfer
4386d49e1aeSJan Lentfer if (data->phase2_priv && data->phase2_method &&
4396d49e1aeSJan Lentfer *pos != data->phase2_type.method) {
4406d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-FAST: Phase 2 EAP sequence - "
4416d49e1aeSJan Lentfer "deinitialize previous method");
4426d49e1aeSJan Lentfer data->phase2_method->deinit(sm, data->phase2_priv);
4436d49e1aeSJan Lentfer data->phase2_method = NULL;
4446d49e1aeSJan Lentfer data->phase2_priv = NULL;
4456d49e1aeSJan Lentfer data->phase2_type.vendor = EAP_VENDOR_IETF;
4466d49e1aeSJan Lentfer data->phase2_type.method = EAP_TYPE_NONE;
4476d49e1aeSJan Lentfer }
4486d49e1aeSJan Lentfer
4496d49e1aeSJan Lentfer if (data->phase2_type.vendor == EAP_VENDOR_IETF &&
4506d49e1aeSJan Lentfer data->phase2_type.method == EAP_TYPE_NONE &&
4516d49e1aeSJan Lentfer eap_fast_select_phase2_method(data, *pos) < 0) {
4526d49e1aeSJan Lentfer if (eap_peer_tls_phase2_nak(data->phase2_types,
4536d49e1aeSJan Lentfer data->num_phase2_types,
4546d49e1aeSJan Lentfer hdr, resp))
4556d49e1aeSJan Lentfer return -1;
4566d49e1aeSJan Lentfer return 0;
4576d49e1aeSJan Lentfer }
4586d49e1aeSJan Lentfer
4593ff40c12SJohn Marino if ((data->phase2_priv == NULL &&
4603ff40c12SJohn Marino eap_fast_init_phase2_method(sm, data) < 0) ||
4613ff40c12SJohn Marino data->phase2_method == NULL) {
4626d49e1aeSJan Lentfer wpa_printf(MSG_INFO, "EAP-FAST: Failed to initialize "
4636d49e1aeSJan Lentfer "Phase 2 EAP method %d", *pos);
4646d49e1aeSJan Lentfer ret->methodState = METHOD_DONE;
4656d49e1aeSJan Lentfer ret->decision = DECISION_FAIL;
4666d49e1aeSJan Lentfer return -1;
4676d49e1aeSJan Lentfer }
4686d49e1aeSJan Lentfer
4696d49e1aeSJan Lentfer os_memset(&iret, 0, sizeof(iret));
4706d49e1aeSJan Lentfer wpabuf_set(&msg, hdr, len);
4716d49e1aeSJan Lentfer *resp = data->phase2_method->process(sm, data->phase2_priv, &iret,
4726d49e1aeSJan Lentfer &msg);
4736d49e1aeSJan Lentfer if (*resp == NULL ||
4746d49e1aeSJan Lentfer (iret.methodState == METHOD_DONE &&
4756d49e1aeSJan Lentfer iret.decision == DECISION_FAIL)) {
4766d49e1aeSJan Lentfer ret->methodState = METHOD_DONE;
4776d49e1aeSJan Lentfer ret->decision = DECISION_FAIL;
4786d49e1aeSJan Lentfer } else if ((iret.methodState == METHOD_DONE ||
4796d49e1aeSJan Lentfer iret.methodState == METHOD_MAY_CONT) &&
4806d49e1aeSJan Lentfer (iret.decision == DECISION_UNCOND_SUCC ||
4816d49e1aeSJan Lentfer iret.decision == DECISION_COND_SUCC)) {
4826d49e1aeSJan Lentfer data->phase2_success = 1;
4836d49e1aeSJan Lentfer }
4846d49e1aeSJan Lentfer
4856d49e1aeSJan Lentfer if (*resp == NULL && config &&
4866d49e1aeSJan Lentfer (config->pending_req_identity || config->pending_req_password ||
487*a1157835SDaniel Fojt config->pending_req_otp || config->pending_req_new_password ||
488*a1157835SDaniel Fojt config->pending_req_sim)) {
489*a1157835SDaniel Fojt wpabuf_clear_free(data->pending_phase2_req);
4906d49e1aeSJan Lentfer data->pending_phase2_req = wpabuf_alloc_copy(hdr, len);
4916d49e1aeSJan Lentfer } else if (*resp == NULL)
4926d49e1aeSJan Lentfer return -1;
4936d49e1aeSJan Lentfer
4946d49e1aeSJan Lentfer return 0;
4956d49e1aeSJan Lentfer }
4966d49e1aeSJan Lentfer
4976d49e1aeSJan Lentfer
eap_fast_tlv_nak(int vendor_id,int tlv_type)4986d49e1aeSJan Lentfer static struct wpabuf * eap_fast_tlv_nak(int vendor_id, int tlv_type)
4996d49e1aeSJan Lentfer {
5006d49e1aeSJan Lentfer struct wpabuf *buf;
5016d49e1aeSJan Lentfer struct eap_tlv_nak_tlv *nak;
5026d49e1aeSJan Lentfer buf = wpabuf_alloc(sizeof(*nak));
5036d49e1aeSJan Lentfer if (buf == NULL)
5046d49e1aeSJan Lentfer return NULL;
5056d49e1aeSJan Lentfer nak = wpabuf_put(buf, sizeof(*nak));
5066d49e1aeSJan Lentfer nak->tlv_type = host_to_be16(EAP_TLV_TYPE_MANDATORY | EAP_TLV_NAK_TLV);
5076d49e1aeSJan Lentfer nak->length = host_to_be16(6);
5086d49e1aeSJan Lentfer nak->vendor_id = host_to_be32(vendor_id);
5096d49e1aeSJan Lentfer nak->nak_type = host_to_be16(tlv_type);
5106d49e1aeSJan Lentfer return buf;
5116d49e1aeSJan Lentfer }
5126d49e1aeSJan Lentfer
5136d49e1aeSJan Lentfer
eap_fast_tlv_result(int status,int intermediate)5146d49e1aeSJan Lentfer static struct wpabuf * eap_fast_tlv_result(int status, int intermediate)
5156d49e1aeSJan Lentfer {
5166d49e1aeSJan Lentfer struct wpabuf *buf;
5176d49e1aeSJan Lentfer struct eap_tlv_intermediate_result_tlv *result;
5186d49e1aeSJan Lentfer buf = wpabuf_alloc(sizeof(*result));
5196d49e1aeSJan Lentfer if (buf == NULL)
5206d49e1aeSJan Lentfer return NULL;
5216d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-FAST: Add %sResult TLV(status=%d)",
5226d49e1aeSJan Lentfer intermediate ? "Intermediate " : "", status);
5236d49e1aeSJan Lentfer result = wpabuf_put(buf, sizeof(*result));
5246d49e1aeSJan Lentfer result->tlv_type = host_to_be16(EAP_TLV_TYPE_MANDATORY |
5256d49e1aeSJan Lentfer (intermediate ?
5266d49e1aeSJan Lentfer EAP_TLV_INTERMEDIATE_RESULT_TLV :
5276d49e1aeSJan Lentfer EAP_TLV_RESULT_TLV));
5286d49e1aeSJan Lentfer result->length = host_to_be16(2);
5296d49e1aeSJan Lentfer result->status = host_to_be16(status);
5306d49e1aeSJan Lentfer return buf;
5316d49e1aeSJan Lentfer }
5326d49e1aeSJan Lentfer
5336d49e1aeSJan Lentfer
eap_fast_tlv_pac_ack(void)5346d49e1aeSJan Lentfer static struct wpabuf * eap_fast_tlv_pac_ack(void)
5356d49e1aeSJan Lentfer {
5366d49e1aeSJan Lentfer struct wpabuf *buf;
5376d49e1aeSJan Lentfer struct eap_tlv_result_tlv *res;
5386d49e1aeSJan Lentfer struct eap_tlv_pac_ack_tlv *ack;
5396d49e1aeSJan Lentfer
5406d49e1aeSJan Lentfer buf = wpabuf_alloc(sizeof(*res) + sizeof(*ack));
5416d49e1aeSJan Lentfer if (buf == NULL)
5426d49e1aeSJan Lentfer return NULL;
5436d49e1aeSJan Lentfer
5446d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-FAST: Add PAC TLV (ack)");
5456d49e1aeSJan Lentfer ack = wpabuf_put(buf, sizeof(*ack));
5466d49e1aeSJan Lentfer ack->tlv_type = host_to_be16(EAP_TLV_PAC_TLV |
5476d49e1aeSJan Lentfer EAP_TLV_TYPE_MANDATORY);
5486d49e1aeSJan Lentfer ack->length = host_to_be16(sizeof(*ack) - sizeof(struct eap_tlv_hdr));
5496d49e1aeSJan Lentfer ack->pac_type = host_to_be16(PAC_TYPE_PAC_ACKNOWLEDGEMENT);
5506d49e1aeSJan Lentfer ack->pac_len = host_to_be16(2);
5516d49e1aeSJan Lentfer ack->result = host_to_be16(EAP_TLV_RESULT_SUCCESS);
5526d49e1aeSJan Lentfer
5536d49e1aeSJan Lentfer return buf;
5546d49e1aeSJan Lentfer }
5556d49e1aeSJan Lentfer
5566d49e1aeSJan Lentfer
eap_fast_process_eap_payload_tlv(struct eap_sm * sm,struct eap_fast_data * data,struct eap_method_ret * ret,u8 * eap_payload_tlv,size_t eap_payload_tlv_len)5576d49e1aeSJan Lentfer static struct wpabuf * eap_fast_process_eap_payload_tlv(
5586d49e1aeSJan Lentfer struct eap_sm *sm, struct eap_fast_data *data,
5593ff40c12SJohn Marino struct eap_method_ret *ret,
5606d49e1aeSJan Lentfer u8 *eap_payload_tlv, size_t eap_payload_tlv_len)
5616d49e1aeSJan Lentfer {
5626d49e1aeSJan Lentfer struct eap_hdr *hdr;
5636d49e1aeSJan Lentfer struct wpabuf *resp = NULL;
5646d49e1aeSJan Lentfer
5656d49e1aeSJan Lentfer if (eap_payload_tlv_len < sizeof(*hdr)) {
5666d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-FAST: too short EAP "
5676d49e1aeSJan Lentfer "Payload TLV (len=%lu)",
5686d49e1aeSJan Lentfer (unsigned long) eap_payload_tlv_len);
5696d49e1aeSJan Lentfer return NULL;
5706d49e1aeSJan Lentfer }
5716d49e1aeSJan Lentfer
5726d49e1aeSJan Lentfer hdr = (struct eap_hdr *) eap_payload_tlv;
5736d49e1aeSJan Lentfer if (be_to_host16(hdr->length) > eap_payload_tlv_len) {
5746d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-FAST: EAP packet overflow in "
5756d49e1aeSJan Lentfer "EAP Payload TLV");
5766d49e1aeSJan Lentfer return NULL;
5776d49e1aeSJan Lentfer }
5786d49e1aeSJan Lentfer
5796d49e1aeSJan Lentfer if (hdr->code != EAP_CODE_REQUEST) {
5806d49e1aeSJan Lentfer wpa_printf(MSG_INFO, "EAP-FAST: Unexpected code=%d in "
5816d49e1aeSJan Lentfer "Phase 2 EAP header", hdr->code);
5826d49e1aeSJan Lentfer return NULL;
5836d49e1aeSJan Lentfer }
5846d49e1aeSJan Lentfer
5856d49e1aeSJan Lentfer if (eap_fast_phase2_request(sm, data, ret, hdr, &resp)) {
5866d49e1aeSJan Lentfer wpa_printf(MSG_INFO, "EAP-FAST: Phase2 Request processing "
5876d49e1aeSJan Lentfer "failed");
5886d49e1aeSJan Lentfer return NULL;
5896d49e1aeSJan Lentfer }
5906d49e1aeSJan Lentfer
5916d49e1aeSJan Lentfer return eap_fast_tlv_eap_payload(resp);
5926d49e1aeSJan Lentfer }
5936d49e1aeSJan Lentfer
5946d49e1aeSJan Lentfer
eap_fast_validate_crypto_binding(struct eap_tlv_crypto_binding_tlv * _bind)5956d49e1aeSJan Lentfer static int eap_fast_validate_crypto_binding(
5966d49e1aeSJan Lentfer struct eap_tlv_crypto_binding_tlv *_bind)
5976d49e1aeSJan Lentfer {
5986d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-FAST: Crypto-Binding TLV: Version %d "
5996d49e1aeSJan Lentfer "Received Version %d SubType %d",
6006d49e1aeSJan Lentfer _bind->version, _bind->received_version, _bind->subtype);
6016d49e1aeSJan Lentfer wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: NONCE",
6026d49e1aeSJan Lentfer _bind->nonce, sizeof(_bind->nonce));
6036d49e1aeSJan Lentfer wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Compound MAC",
6046d49e1aeSJan Lentfer _bind->compound_mac, sizeof(_bind->compound_mac));
6056d49e1aeSJan Lentfer
6066d49e1aeSJan Lentfer if (_bind->version != EAP_FAST_VERSION ||
6076d49e1aeSJan Lentfer _bind->received_version != EAP_FAST_VERSION ||
6086d49e1aeSJan Lentfer _bind->subtype != EAP_TLV_CRYPTO_BINDING_SUBTYPE_REQUEST) {
6096d49e1aeSJan Lentfer wpa_printf(MSG_INFO, "EAP-FAST: Invalid version/subtype in "
6106d49e1aeSJan Lentfer "Crypto-Binding TLV: Version %d "
6116d49e1aeSJan Lentfer "Received Version %d SubType %d",
6126d49e1aeSJan Lentfer _bind->version, _bind->received_version,
6136d49e1aeSJan Lentfer _bind->subtype);
6146d49e1aeSJan Lentfer return -1;
6156d49e1aeSJan Lentfer }
6166d49e1aeSJan Lentfer
6176d49e1aeSJan Lentfer return 0;
6186d49e1aeSJan Lentfer }
6196d49e1aeSJan Lentfer
6206d49e1aeSJan Lentfer
eap_fast_write_crypto_binding(struct eap_tlv_crypto_binding_tlv * rbind,struct eap_tlv_crypto_binding_tlv * _bind,const u8 * cmk)6216d49e1aeSJan Lentfer static void eap_fast_write_crypto_binding(
6226d49e1aeSJan Lentfer struct eap_tlv_crypto_binding_tlv *rbind,
6236d49e1aeSJan Lentfer struct eap_tlv_crypto_binding_tlv *_bind, const u8 *cmk)
6246d49e1aeSJan Lentfer {
6256d49e1aeSJan Lentfer rbind->tlv_type = host_to_be16(EAP_TLV_TYPE_MANDATORY |
6266d49e1aeSJan Lentfer EAP_TLV_CRYPTO_BINDING_TLV);
6276d49e1aeSJan Lentfer rbind->length = host_to_be16(sizeof(*rbind) -
6286d49e1aeSJan Lentfer sizeof(struct eap_tlv_hdr));
6296d49e1aeSJan Lentfer rbind->version = EAP_FAST_VERSION;
6306d49e1aeSJan Lentfer rbind->received_version = _bind->version;
6316d49e1aeSJan Lentfer rbind->subtype = EAP_TLV_CRYPTO_BINDING_SUBTYPE_RESPONSE;
6326d49e1aeSJan Lentfer os_memcpy(rbind->nonce, _bind->nonce, sizeof(_bind->nonce));
6336d49e1aeSJan Lentfer inc_byte_array(rbind->nonce, sizeof(rbind->nonce));
6346d49e1aeSJan Lentfer hmac_sha1(cmk, EAP_FAST_CMK_LEN, (u8 *) rbind, sizeof(*rbind),
6356d49e1aeSJan Lentfer rbind->compound_mac);
6366d49e1aeSJan Lentfer
6376d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-FAST: Reply Crypto-Binding TLV: Version %d "
6386d49e1aeSJan Lentfer "Received Version %d SubType %d",
6396d49e1aeSJan Lentfer rbind->version, rbind->received_version, rbind->subtype);
6406d49e1aeSJan Lentfer wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: NONCE",
6416d49e1aeSJan Lentfer rbind->nonce, sizeof(rbind->nonce));
6426d49e1aeSJan Lentfer wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Compound MAC",
6436d49e1aeSJan Lentfer rbind->compound_mac, sizeof(rbind->compound_mac));
6446d49e1aeSJan Lentfer }
6456d49e1aeSJan Lentfer
6466d49e1aeSJan Lentfer
eap_fast_get_phase2_key(struct eap_sm * sm,struct eap_fast_data * data,u8 * isk,size_t isk_len)6476d49e1aeSJan Lentfer static int eap_fast_get_phase2_key(struct eap_sm *sm,
6486d49e1aeSJan Lentfer struct eap_fast_data *data,
6496d49e1aeSJan Lentfer u8 *isk, size_t isk_len)
6506d49e1aeSJan Lentfer {
6516d49e1aeSJan Lentfer u8 *key;
6526d49e1aeSJan Lentfer size_t key_len;
6536d49e1aeSJan Lentfer
6546d49e1aeSJan Lentfer os_memset(isk, 0, isk_len);
6556d49e1aeSJan Lentfer
6566d49e1aeSJan Lentfer if (data->phase2_method == NULL || data->phase2_priv == NULL) {
6576d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-FAST: Phase 2 method not "
6586d49e1aeSJan Lentfer "available");
6596d49e1aeSJan Lentfer return -1;
6606d49e1aeSJan Lentfer }
6616d49e1aeSJan Lentfer
6626d49e1aeSJan Lentfer if (data->phase2_method->isKeyAvailable == NULL ||
6636d49e1aeSJan Lentfer data->phase2_method->getKey == NULL)
6646d49e1aeSJan Lentfer return 0;
6656d49e1aeSJan Lentfer
6666d49e1aeSJan Lentfer if (!data->phase2_method->isKeyAvailable(sm, data->phase2_priv) ||
6676d49e1aeSJan Lentfer (key = data->phase2_method->getKey(sm, data->phase2_priv,
6686d49e1aeSJan Lentfer &key_len)) == NULL) {
6696d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-FAST: Could not get key material "
6706d49e1aeSJan Lentfer "from Phase 2");
6716d49e1aeSJan Lentfer return -1;
6726d49e1aeSJan Lentfer }
6736d49e1aeSJan Lentfer
6746d49e1aeSJan Lentfer if (key_len > isk_len)
6756d49e1aeSJan Lentfer key_len = isk_len;
6766d49e1aeSJan Lentfer if (key_len == 32 &&
6776d49e1aeSJan Lentfer data->phase2_method->vendor == EAP_VENDOR_IETF &&
6786d49e1aeSJan Lentfer data->phase2_method->method == EAP_TYPE_MSCHAPV2) {
6796d49e1aeSJan Lentfer /*
6806d49e1aeSJan Lentfer * EAP-FAST uses reverse order for MS-MPPE keys when deriving
6816d49e1aeSJan Lentfer * MSK from EAP-MSCHAPv2. Swap the keys here to get the correct
6826d49e1aeSJan Lentfer * ISK for EAP-FAST cryptobinding.
6836d49e1aeSJan Lentfer */
6846d49e1aeSJan Lentfer os_memcpy(isk, key + 16, 16);
6856d49e1aeSJan Lentfer os_memcpy(isk + 16, key, 16);
6866d49e1aeSJan Lentfer } else
6876d49e1aeSJan Lentfer os_memcpy(isk, key, key_len);
6886d49e1aeSJan Lentfer os_free(key);
6896d49e1aeSJan Lentfer
6906d49e1aeSJan Lentfer return 0;
6916d49e1aeSJan Lentfer }
6926d49e1aeSJan Lentfer
6936d49e1aeSJan Lentfer
eap_fast_get_cmk(struct eap_sm * sm,struct eap_fast_data * data,u8 * cmk)6946d49e1aeSJan Lentfer static int eap_fast_get_cmk(struct eap_sm *sm, struct eap_fast_data *data,
6956d49e1aeSJan Lentfer u8 *cmk)
6966d49e1aeSJan Lentfer {
6976d49e1aeSJan Lentfer u8 isk[32], imck[60];
6986d49e1aeSJan Lentfer
6996d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-FAST: Determining CMK[%d] for Compound MIC "
7006d49e1aeSJan Lentfer "calculation", data->simck_idx + 1);
7016d49e1aeSJan Lentfer
7026d49e1aeSJan Lentfer /*
7036d49e1aeSJan Lentfer * RFC 4851, Section 5.2:
7046d49e1aeSJan Lentfer * IMCK[j] = T-PRF(S-IMCK[j-1], "Inner Methods Compound Keys",
7056d49e1aeSJan Lentfer * MSK[j], 60)
7066d49e1aeSJan Lentfer * S-IMCK[j] = first 40 octets of IMCK[j]
7076d49e1aeSJan Lentfer * CMK[j] = last 20 octets of IMCK[j]
7086d49e1aeSJan Lentfer */
7096d49e1aeSJan Lentfer
7106d49e1aeSJan Lentfer if (eap_fast_get_phase2_key(sm, data, isk, sizeof(isk)) < 0)
7116d49e1aeSJan Lentfer return -1;
7126d49e1aeSJan Lentfer wpa_hexdump_key(MSG_MSGDUMP, "EAP-FAST: ISK[j]", isk, sizeof(isk));
713*a1157835SDaniel Fojt if (sha1_t_prf(data->simck, EAP_FAST_SIMCK_LEN,
7146d49e1aeSJan Lentfer "Inner Methods Compound Keys",
715*a1157835SDaniel Fojt isk, sizeof(isk), imck, sizeof(imck)) < 0)
716*a1157835SDaniel Fojt return -1;
7176d49e1aeSJan Lentfer data->simck_idx++;
7186d49e1aeSJan Lentfer os_memcpy(data->simck, imck, EAP_FAST_SIMCK_LEN);
7196d49e1aeSJan Lentfer wpa_hexdump_key(MSG_MSGDUMP, "EAP-FAST: S-IMCK[j]",
7206d49e1aeSJan Lentfer data->simck, EAP_FAST_SIMCK_LEN);
7216d49e1aeSJan Lentfer os_memcpy(cmk, imck + EAP_FAST_SIMCK_LEN, EAP_FAST_CMK_LEN);
7226d49e1aeSJan Lentfer wpa_hexdump_key(MSG_MSGDUMP, "EAP-FAST: CMK[j]",
7236d49e1aeSJan Lentfer cmk, EAP_FAST_CMK_LEN);
7246d49e1aeSJan Lentfer
7256d49e1aeSJan Lentfer return 0;
7266d49e1aeSJan Lentfer }
7276d49e1aeSJan Lentfer
7286d49e1aeSJan Lentfer
eap_fast_write_pac_request(u8 * pos,u16 pac_type)7296d49e1aeSJan Lentfer static u8 * eap_fast_write_pac_request(u8 *pos, u16 pac_type)
7306d49e1aeSJan Lentfer {
7316d49e1aeSJan Lentfer struct eap_tlv_hdr *pac;
7326d49e1aeSJan Lentfer struct eap_tlv_request_action_tlv *act;
7336d49e1aeSJan Lentfer struct eap_tlv_pac_type_tlv *type;
7346d49e1aeSJan Lentfer
7356d49e1aeSJan Lentfer act = (struct eap_tlv_request_action_tlv *) pos;
7366d49e1aeSJan Lentfer act->tlv_type = host_to_be16(EAP_TLV_REQUEST_ACTION_TLV);
7376d49e1aeSJan Lentfer act->length = host_to_be16(2);
7386d49e1aeSJan Lentfer act->action = host_to_be16(EAP_TLV_ACTION_PROCESS_TLV);
7396d49e1aeSJan Lentfer
7406d49e1aeSJan Lentfer pac = (struct eap_tlv_hdr *) (act + 1);
7416d49e1aeSJan Lentfer pac->tlv_type = host_to_be16(EAP_TLV_PAC_TLV);
7426d49e1aeSJan Lentfer pac->length = host_to_be16(sizeof(*type));
7436d49e1aeSJan Lentfer
7446d49e1aeSJan Lentfer type = (struct eap_tlv_pac_type_tlv *) (pac + 1);
7456d49e1aeSJan Lentfer type->tlv_type = host_to_be16(PAC_TYPE_PAC_TYPE);
7466d49e1aeSJan Lentfer type->length = host_to_be16(2);
7476d49e1aeSJan Lentfer type->pac_type = host_to_be16(pac_type);
7486d49e1aeSJan Lentfer
7496d49e1aeSJan Lentfer return (u8 *) (type + 1);
7506d49e1aeSJan Lentfer }
7516d49e1aeSJan Lentfer
7526d49e1aeSJan Lentfer
eap_fast_process_crypto_binding(struct eap_sm * sm,struct eap_fast_data * data,struct eap_method_ret * ret,struct eap_tlv_crypto_binding_tlv * _bind,size_t bind_len)7536d49e1aeSJan Lentfer static struct wpabuf * eap_fast_process_crypto_binding(
7546d49e1aeSJan Lentfer struct eap_sm *sm, struct eap_fast_data *data,
7556d49e1aeSJan Lentfer struct eap_method_ret *ret,
7566d49e1aeSJan Lentfer struct eap_tlv_crypto_binding_tlv *_bind, size_t bind_len)
7576d49e1aeSJan Lentfer {
7586d49e1aeSJan Lentfer struct wpabuf *resp;
7596d49e1aeSJan Lentfer u8 *pos;
7606d49e1aeSJan Lentfer u8 cmk[EAP_FAST_CMK_LEN], cmac[SHA1_MAC_LEN];
7616d49e1aeSJan Lentfer int res;
7626d49e1aeSJan Lentfer size_t len;
7636d49e1aeSJan Lentfer
7646d49e1aeSJan Lentfer if (eap_fast_validate_crypto_binding(_bind) < 0)
7656d49e1aeSJan Lentfer return NULL;
7666d49e1aeSJan Lentfer
7676d49e1aeSJan Lentfer if (eap_fast_get_cmk(sm, data, cmk) < 0)
7686d49e1aeSJan Lentfer return NULL;
7696d49e1aeSJan Lentfer
7706d49e1aeSJan Lentfer /* Validate received Compound MAC */
7716d49e1aeSJan Lentfer os_memcpy(cmac, _bind->compound_mac, sizeof(cmac));
7726d49e1aeSJan Lentfer os_memset(_bind->compound_mac, 0, sizeof(cmac));
7736d49e1aeSJan Lentfer wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Crypto-Binding TLV for Compound "
7746d49e1aeSJan Lentfer "MAC calculation", (u8 *) _bind, bind_len);
7756d49e1aeSJan Lentfer hmac_sha1(cmk, EAP_FAST_CMK_LEN, (u8 *) _bind, bind_len,
7766d49e1aeSJan Lentfer _bind->compound_mac);
777*a1157835SDaniel Fojt res = os_memcmp_const(cmac, _bind->compound_mac, sizeof(cmac));
7786d49e1aeSJan Lentfer wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Received Compound MAC",
7796d49e1aeSJan Lentfer cmac, sizeof(cmac));
7806d49e1aeSJan Lentfer wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Calculated Compound MAC",
7816d49e1aeSJan Lentfer _bind->compound_mac, sizeof(cmac));
7826d49e1aeSJan Lentfer if (res != 0) {
7836d49e1aeSJan Lentfer wpa_printf(MSG_INFO, "EAP-FAST: Compound MAC did not match");
7846d49e1aeSJan Lentfer os_memcpy(_bind->compound_mac, cmac, sizeof(cmac));
7856d49e1aeSJan Lentfer return NULL;
7866d49e1aeSJan Lentfer }
7876d49e1aeSJan Lentfer
7886d49e1aeSJan Lentfer /*
7896d49e1aeSJan Lentfer * Compound MAC was valid, so authentication succeeded. Reply with
7906d49e1aeSJan Lentfer * crypto binding to allow server to complete authentication.
7916d49e1aeSJan Lentfer */
7926d49e1aeSJan Lentfer
7936d49e1aeSJan Lentfer len = sizeof(struct eap_tlv_crypto_binding_tlv);
7946d49e1aeSJan Lentfer resp = wpabuf_alloc(len);
7956d49e1aeSJan Lentfer if (resp == NULL)
7966d49e1aeSJan Lentfer return NULL;
7976d49e1aeSJan Lentfer
7986d49e1aeSJan Lentfer if (!data->anon_provisioning && data->phase2_success &&
7996d49e1aeSJan Lentfer eap_fast_derive_msk(data) < 0) {
8006d49e1aeSJan Lentfer wpa_printf(MSG_INFO, "EAP-FAST: Failed to generate MSK");
8016d49e1aeSJan Lentfer ret->methodState = METHOD_DONE;
8026d49e1aeSJan Lentfer ret->decision = DECISION_FAIL;
8036d49e1aeSJan Lentfer data->phase2_success = 0;
804*a1157835SDaniel Fojt wpabuf_clear_free(resp);
8056d49e1aeSJan Lentfer return NULL;
8066d49e1aeSJan Lentfer }
8076d49e1aeSJan Lentfer
8083ff40c12SJohn Marino if (!data->anon_provisioning && data->phase2_success) {
8093ff40c12SJohn Marino os_free(data->session_id);
8103ff40c12SJohn Marino data->session_id = eap_peer_tls_derive_session_id(
8113ff40c12SJohn Marino sm, &data->ssl, EAP_TYPE_FAST, &data->id_len);
8123ff40c12SJohn Marino if (data->session_id) {
8133ff40c12SJohn Marino wpa_hexdump(MSG_DEBUG, "EAP-FAST: Derived Session-Id",
8143ff40c12SJohn Marino data->session_id, data->id_len);
8153ff40c12SJohn Marino } else {
8163ff40c12SJohn Marino wpa_printf(MSG_ERROR, "EAP-FAST: Failed to derive "
8173ff40c12SJohn Marino "Session-Id");
818*a1157835SDaniel Fojt wpabuf_clear_free(resp);
8193ff40c12SJohn Marino return NULL;
8203ff40c12SJohn Marino }
8213ff40c12SJohn Marino }
8223ff40c12SJohn Marino
8236d49e1aeSJan Lentfer pos = wpabuf_put(resp, sizeof(struct eap_tlv_crypto_binding_tlv));
8246d49e1aeSJan Lentfer eap_fast_write_crypto_binding((struct eap_tlv_crypto_binding_tlv *)
8256d49e1aeSJan Lentfer pos, _bind, cmk);
8266d49e1aeSJan Lentfer
8276d49e1aeSJan Lentfer return resp;
8286d49e1aeSJan Lentfer }
8296d49e1aeSJan Lentfer
8306d49e1aeSJan Lentfer
eap_fast_parse_pac_tlv(struct eap_fast_pac * entry,int type,u8 * pos,size_t len,int * pac_key_found)8316d49e1aeSJan Lentfer static void eap_fast_parse_pac_tlv(struct eap_fast_pac *entry, int type,
8326d49e1aeSJan Lentfer u8 *pos, size_t len, int *pac_key_found)
8336d49e1aeSJan Lentfer {
8346d49e1aeSJan Lentfer switch (type & 0x7fff) {
8356d49e1aeSJan Lentfer case PAC_TYPE_PAC_KEY:
8366d49e1aeSJan Lentfer wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: PAC-Key", pos, len);
8376d49e1aeSJan Lentfer if (len != EAP_FAST_PAC_KEY_LEN) {
8386d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-FAST: Invalid PAC-Key "
8396d49e1aeSJan Lentfer "length %lu", (unsigned long) len);
8406d49e1aeSJan Lentfer break;
8416d49e1aeSJan Lentfer }
8426d49e1aeSJan Lentfer *pac_key_found = 1;
8436d49e1aeSJan Lentfer os_memcpy(entry->pac_key, pos, len);
8446d49e1aeSJan Lentfer break;
8456d49e1aeSJan Lentfer case PAC_TYPE_PAC_OPAQUE:
8466d49e1aeSJan Lentfer wpa_hexdump(MSG_DEBUG, "EAP-FAST: PAC-Opaque", pos, len);
8476d49e1aeSJan Lentfer entry->pac_opaque = pos;
8486d49e1aeSJan Lentfer entry->pac_opaque_len = len;
8496d49e1aeSJan Lentfer break;
8506d49e1aeSJan Lentfer case PAC_TYPE_PAC_INFO:
8516d49e1aeSJan Lentfer wpa_hexdump(MSG_DEBUG, "EAP-FAST: PAC-Info", pos, len);
8526d49e1aeSJan Lentfer entry->pac_info = pos;
8536d49e1aeSJan Lentfer entry->pac_info_len = len;
8546d49e1aeSJan Lentfer break;
8556d49e1aeSJan Lentfer default:
8566d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-FAST: Ignored unknown PAC type %d",
8576d49e1aeSJan Lentfer type);
8586d49e1aeSJan Lentfer break;
8596d49e1aeSJan Lentfer }
8606d49e1aeSJan Lentfer }
8616d49e1aeSJan Lentfer
8626d49e1aeSJan Lentfer
eap_fast_process_pac_tlv(struct eap_fast_pac * entry,u8 * pac,size_t pac_len)8636d49e1aeSJan Lentfer static int eap_fast_process_pac_tlv(struct eap_fast_pac *entry,
8646d49e1aeSJan Lentfer u8 *pac, size_t pac_len)
8656d49e1aeSJan Lentfer {
8666d49e1aeSJan Lentfer struct pac_tlv_hdr *hdr;
8676d49e1aeSJan Lentfer u8 *pos;
8686d49e1aeSJan Lentfer size_t left, len;
8696d49e1aeSJan Lentfer int type, pac_key_found = 0;
8706d49e1aeSJan Lentfer
8716d49e1aeSJan Lentfer pos = pac;
8726d49e1aeSJan Lentfer left = pac_len;
8736d49e1aeSJan Lentfer
8746d49e1aeSJan Lentfer while (left > sizeof(*hdr)) {
8756d49e1aeSJan Lentfer hdr = (struct pac_tlv_hdr *) pos;
8766d49e1aeSJan Lentfer type = be_to_host16(hdr->type);
8776d49e1aeSJan Lentfer len = be_to_host16(hdr->len);
8786d49e1aeSJan Lentfer pos += sizeof(*hdr);
8796d49e1aeSJan Lentfer left -= sizeof(*hdr);
8806d49e1aeSJan Lentfer if (len > left) {
8816d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-FAST: PAC TLV overrun "
8826d49e1aeSJan Lentfer "(type=%d len=%lu left=%lu)",
8836d49e1aeSJan Lentfer type, (unsigned long) len,
8846d49e1aeSJan Lentfer (unsigned long) left);
8856d49e1aeSJan Lentfer return -1;
8866d49e1aeSJan Lentfer }
8876d49e1aeSJan Lentfer
8886d49e1aeSJan Lentfer eap_fast_parse_pac_tlv(entry, type, pos, len, &pac_key_found);
8896d49e1aeSJan Lentfer
8906d49e1aeSJan Lentfer pos += len;
8916d49e1aeSJan Lentfer left -= len;
8926d49e1aeSJan Lentfer }
8936d49e1aeSJan Lentfer
8946d49e1aeSJan Lentfer if (!pac_key_found || !entry->pac_opaque || !entry->pac_info) {
8956d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-FAST: PAC TLV does not include "
8966d49e1aeSJan Lentfer "all the required fields");
8976d49e1aeSJan Lentfer return -1;
8986d49e1aeSJan Lentfer }
8996d49e1aeSJan Lentfer
9006d49e1aeSJan Lentfer return 0;
9016d49e1aeSJan Lentfer }
9026d49e1aeSJan Lentfer
9036d49e1aeSJan Lentfer
eap_fast_parse_pac_info(struct eap_fast_pac * entry,int type,u8 * pos,size_t len)9046d49e1aeSJan Lentfer static int eap_fast_parse_pac_info(struct eap_fast_pac *entry, int type,
9056d49e1aeSJan Lentfer u8 *pos, size_t len)
9066d49e1aeSJan Lentfer {
9076d49e1aeSJan Lentfer u16 pac_type;
9086d49e1aeSJan Lentfer u32 lifetime;
9096d49e1aeSJan Lentfer struct os_time now;
9106d49e1aeSJan Lentfer
9116d49e1aeSJan Lentfer switch (type & 0x7fff) {
9126d49e1aeSJan Lentfer case PAC_TYPE_CRED_LIFETIME:
9136d49e1aeSJan Lentfer if (len != 4) {
9146d49e1aeSJan Lentfer wpa_hexdump(MSG_DEBUG, "EAP-FAST: PAC-Info - "
9156d49e1aeSJan Lentfer "Invalid CRED_LIFETIME length - ignored",
9166d49e1aeSJan Lentfer pos, len);
9176d49e1aeSJan Lentfer return 0;
9186d49e1aeSJan Lentfer }
9196d49e1aeSJan Lentfer
9206d49e1aeSJan Lentfer /*
9216d49e1aeSJan Lentfer * This is not currently saved separately in PAC files since
9226d49e1aeSJan Lentfer * the server can automatically initiate PAC update when
9236d49e1aeSJan Lentfer * needed. Anyway, the information is available from PAC-Info
9246d49e1aeSJan Lentfer * dump if it is needed for something in the future.
9256d49e1aeSJan Lentfer */
9266d49e1aeSJan Lentfer lifetime = WPA_GET_BE32(pos);
9276d49e1aeSJan Lentfer os_get_time(&now);
9286d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-FAST: PAC-Info - CRED_LIFETIME %d "
9296d49e1aeSJan Lentfer "(%d days)",
9306d49e1aeSJan Lentfer lifetime, (lifetime - (u32) now.sec) / 86400);
9316d49e1aeSJan Lentfer break;
9326d49e1aeSJan Lentfer case PAC_TYPE_A_ID:
9336d49e1aeSJan Lentfer wpa_hexdump_ascii(MSG_DEBUG, "EAP-FAST: PAC-Info - A-ID",
9346d49e1aeSJan Lentfer pos, len);
9356d49e1aeSJan Lentfer entry->a_id = pos;
9366d49e1aeSJan Lentfer entry->a_id_len = len;
9376d49e1aeSJan Lentfer break;
9386d49e1aeSJan Lentfer case PAC_TYPE_I_ID:
9396d49e1aeSJan Lentfer wpa_hexdump_ascii(MSG_DEBUG, "EAP-FAST: PAC-Info - I-ID",
9406d49e1aeSJan Lentfer pos, len);
9416d49e1aeSJan Lentfer entry->i_id = pos;
9426d49e1aeSJan Lentfer entry->i_id_len = len;
9436d49e1aeSJan Lentfer break;
9446d49e1aeSJan Lentfer case PAC_TYPE_A_ID_INFO:
9456d49e1aeSJan Lentfer wpa_hexdump_ascii(MSG_DEBUG, "EAP-FAST: PAC-Info - A-ID-Info",
9466d49e1aeSJan Lentfer pos, len);
9476d49e1aeSJan Lentfer entry->a_id_info = pos;
9486d49e1aeSJan Lentfer entry->a_id_info_len = len;
9496d49e1aeSJan Lentfer break;
9506d49e1aeSJan Lentfer case PAC_TYPE_PAC_TYPE:
9516d49e1aeSJan Lentfer /* RFC 5422, Section 4.2.6 - PAC-Type TLV */
9526d49e1aeSJan Lentfer if (len != 2) {
9536d49e1aeSJan Lentfer wpa_printf(MSG_INFO, "EAP-FAST: Invalid PAC-Type "
9546d49e1aeSJan Lentfer "length %lu (expected 2)",
9556d49e1aeSJan Lentfer (unsigned long) len);
9566d49e1aeSJan Lentfer wpa_hexdump_ascii(MSG_DEBUG,
9576d49e1aeSJan Lentfer "EAP-FAST: PAC-Info - PAC-Type",
9586d49e1aeSJan Lentfer pos, len);
9596d49e1aeSJan Lentfer return -1;
9606d49e1aeSJan Lentfer }
9616d49e1aeSJan Lentfer pac_type = WPA_GET_BE16(pos);
9626d49e1aeSJan Lentfer if (pac_type != PAC_TYPE_TUNNEL_PAC &&
9636d49e1aeSJan Lentfer pac_type != PAC_TYPE_USER_AUTHORIZATION &&
9646d49e1aeSJan Lentfer pac_type != PAC_TYPE_MACHINE_AUTHENTICATION) {
9656d49e1aeSJan Lentfer wpa_printf(MSG_INFO, "EAP-FAST: Unsupported PAC Type "
9666d49e1aeSJan Lentfer "%d", pac_type);
9676d49e1aeSJan Lentfer return -1;
9686d49e1aeSJan Lentfer }
9696d49e1aeSJan Lentfer
9706d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-FAST: PAC-Info - PAC-Type %d",
9716d49e1aeSJan Lentfer pac_type);
9726d49e1aeSJan Lentfer entry->pac_type = pac_type;
9736d49e1aeSJan Lentfer break;
9746d49e1aeSJan Lentfer default:
9756d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-FAST: Ignored unknown PAC-Info "
9766d49e1aeSJan Lentfer "type %d", type);
9776d49e1aeSJan Lentfer break;
9786d49e1aeSJan Lentfer }
9796d49e1aeSJan Lentfer
9806d49e1aeSJan Lentfer return 0;
9816d49e1aeSJan Lentfer }
9826d49e1aeSJan Lentfer
9836d49e1aeSJan Lentfer
eap_fast_process_pac_info(struct eap_fast_pac * entry)9846d49e1aeSJan Lentfer static int eap_fast_process_pac_info(struct eap_fast_pac *entry)
9856d49e1aeSJan Lentfer {
9866d49e1aeSJan Lentfer struct pac_tlv_hdr *hdr;
9876d49e1aeSJan Lentfer u8 *pos;
9886d49e1aeSJan Lentfer size_t left, len;
9896d49e1aeSJan Lentfer int type;
9906d49e1aeSJan Lentfer
9916d49e1aeSJan Lentfer /* RFC 5422, Section 4.2.4 */
9926d49e1aeSJan Lentfer
9936d49e1aeSJan Lentfer /* PAC-Type defaults to Tunnel PAC (Type 1) */
9946d49e1aeSJan Lentfer entry->pac_type = PAC_TYPE_TUNNEL_PAC;
9956d49e1aeSJan Lentfer
9966d49e1aeSJan Lentfer pos = entry->pac_info;
9976d49e1aeSJan Lentfer left = entry->pac_info_len;
9986d49e1aeSJan Lentfer while (left > sizeof(*hdr)) {
9996d49e1aeSJan Lentfer hdr = (struct pac_tlv_hdr *) pos;
10006d49e1aeSJan Lentfer type = be_to_host16(hdr->type);
10016d49e1aeSJan Lentfer len = be_to_host16(hdr->len);
10026d49e1aeSJan Lentfer pos += sizeof(*hdr);
10036d49e1aeSJan Lentfer left -= sizeof(*hdr);
10046d49e1aeSJan Lentfer if (len > left) {
10056d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-FAST: PAC-Info overrun "
10066d49e1aeSJan Lentfer "(type=%d len=%lu left=%lu)",
10076d49e1aeSJan Lentfer type, (unsigned long) len,
10086d49e1aeSJan Lentfer (unsigned long) left);
10096d49e1aeSJan Lentfer return -1;
10106d49e1aeSJan Lentfer }
10116d49e1aeSJan Lentfer
10126d49e1aeSJan Lentfer if (eap_fast_parse_pac_info(entry, type, pos, len) < 0)
10136d49e1aeSJan Lentfer return -1;
10146d49e1aeSJan Lentfer
10156d49e1aeSJan Lentfer pos += len;
10166d49e1aeSJan Lentfer left -= len;
10176d49e1aeSJan Lentfer }
10186d49e1aeSJan Lentfer
10196d49e1aeSJan Lentfer if (entry->a_id == NULL || entry->a_id_info == NULL) {
10206d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-FAST: PAC-Info does not include "
10216d49e1aeSJan Lentfer "all the required fields");
10226d49e1aeSJan Lentfer return -1;
10236d49e1aeSJan Lentfer }
10246d49e1aeSJan Lentfer
10256d49e1aeSJan Lentfer return 0;
10266d49e1aeSJan Lentfer }
10276d49e1aeSJan Lentfer
10286d49e1aeSJan Lentfer
eap_fast_process_pac(struct eap_sm * sm,struct eap_fast_data * data,struct eap_method_ret * ret,u8 * pac,size_t pac_len)10296d49e1aeSJan Lentfer static struct wpabuf * eap_fast_process_pac(struct eap_sm *sm,
10306d49e1aeSJan Lentfer struct eap_fast_data *data,
10316d49e1aeSJan Lentfer struct eap_method_ret *ret,
10326d49e1aeSJan Lentfer u8 *pac, size_t pac_len)
10336d49e1aeSJan Lentfer {
10346d49e1aeSJan Lentfer struct eap_peer_config *config = eap_get_config(sm);
10356d49e1aeSJan Lentfer struct eap_fast_pac entry;
10366d49e1aeSJan Lentfer
10376d49e1aeSJan Lentfer os_memset(&entry, 0, sizeof(entry));
10386d49e1aeSJan Lentfer if (eap_fast_process_pac_tlv(&entry, pac, pac_len) ||
10396d49e1aeSJan Lentfer eap_fast_process_pac_info(&entry))
10406d49e1aeSJan Lentfer return NULL;
10416d49e1aeSJan Lentfer
10426d49e1aeSJan Lentfer eap_fast_add_pac(&data->pac, &data->current_pac, &entry);
10436d49e1aeSJan Lentfer eap_fast_pac_list_truncate(data->pac, data->max_pac_list_len);
10446d49e1aeSJan Lentfer if (data->use_pac_binary_format)
10456d49e1aeSJan Lentfer eap_fast_save_pac_bin(sm, data->pac, config->pac_file);
10466d49e1aeSJan Lentfer else
10476d49e1aeSJan Lentfer eap_fast_save_pac(sm, data->pac, config->pac_file);
10486d49e1aeSJan Lentfer
10496d49e1aeSJan Lentfer if (data->provisioning) {
10506d49e1aeSJan Lentfer if (data->anon_provisioning) {
10516d49e1aeSJan Lentfer /*
10526d49e1aeSJan Lentfer * Unauthenticated provisioning does not provide keying
10536d49e1aeSJan Lentfer * material and must end with an EAP-Failure.
10546d49e1aeSJan Lentfer * Authentication will be done separately after this.
10556d49e1aeSJan Lentfer */
10566d49e1aeSJan Lentfer data->success = 0;
10576d49e1aeSJan Lentfer ret->decision = DECISION_FAIL;
10586d49e1aeSJan Lentfer } else {
10596d49e1aeSJan Lentfer /*
10606d49e1aeSJan Lentfer * Server may or may not allow authenticated
10616d49e1aeSJan Lentfer * provisioning also for key generation.
10626d49e1aeSJan Lentfer */
10636d49e1aeSJan Lentfer ret->decision = DECISION_COND_SUCC;
10646d49e1aeSJan Lentfer }
10656d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-FAST: Send PAC-Acknowledgement TLV "
10666d49e1aeSJan Lentfer "- Provisioning completed successfully");
10673ff40c12SJohn Marino sm->expected_failure = 1;
10686d49e1aeSJan Lentfer } else {
10696d49e1aeSJan Lentfer /*
10706d49e1aeSJan Lentfer * This is PAC refreshing, i.e., normal authentication that is
10713ff40c12SJohn Marino * expected to be completed with an EAP-Success. However,
10723ff40c12SJohn Marino * RFC 5422, Section 3.5 allows EAP-Failure to be sent even
10733ff40c12SJohn Marino * after protected success exchange in case of EAP-Fast
10743ff40c12SJohn Marino * provisioning, so we better use DECISION_COND_SUCC here
10753ff40c12SJohn Marino * instead of DECISION_UNCOND_SUCC.
10766d49e1aeSJan Lentfer */
10776d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-FAST: Send PAC-Acknowledgement TLV "
10786d49e1aeSJan Lentfer "- PAC refreshing completed successfully");
10793ff40c12SJohn Marino ret->decision = DECISION_COND_SUCC;
10806d49e1aeSJan Lentfer }
10816d49e1aeSJan Lentfer ret->methodState = METHOD_DONE;
10826d49e1aeSJan Lentfer return eap_fast_tlv_pac_ack();
10836d49e1aeSJan Lentfer }
10846d49e1aeSJan Lentfer
10856d49e1aeSJan Lentfer
eap_fast_parse_decrypted(struct wpabuf * decrypted,struct eap_fast_tlv_parse * tlv,struct wpabuf ** resp)10866d49e1aeSJan Lentfer static int eap_fast_parse_decrypted(struct wpabuf *decrypted,
10876d49e1aeSJan Lentfer struct eap_fast_tlv_parse *tlv,
10886d49e1aeSJan Lentfer struct wpabuf **resp)
10896d49e1aeSJan Lentfer {
1090*a1157835SDaniel Fojt int mandatory, tlv_type, res;
1091*a1157835SDaniel Fojt size_t len;
10926d49e1aeSJan Lentfer u8 *pos, *end;
10936d49e1aeSJan Lentfer
10946d49e1aeSJan Lentfer os_memset(tlv, 0, sizeof(*tlv));
10956d49e1aeSJan Lentfer
10966d49e1aeSJan Lentfer /* Parse TLVs from the decrypted Phase 2 data */
10976d49e1aeSJan Lentfer pos = wpabuf_mhead(decrypted);
10986d49e1aeSJan Lentfer end = pos + wpabuf_len(decrypted);
1099*a1157835SDaniel Fojt while (end - pos > 4) {
11006d49e1aeSJan Lentfer mandatory = pos[0] & 0x80;
11016d49e1aeSJan Lentfer tlv_type = WPA_GET_BE16(pos) & 0x3fff;
11026d49e1aeSJan Lentfer pos += 2;
11036d49e1aeSJan Lentfer len = WPA_GET_BE16(pos);
11046d49e1aeSJan Lentfer pos += 2;
1105*a1157835SDaniel Fojt if (len > (size_t) (end - pos)) {
11066d49e1aeSJan Lentfer wpa_printf(MSG_INFO, "EAP-FAST: TLV overflow");
11076d49e1aeSJan Lentfer return -1;
11086d49e1aeSJan Lentfer }
11096d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-FAST: Received Phase 2: "
1110*a1157835SDaniel Fojt "TLV type %d length %u%s",
1111*a1157835SDaniel Fojt tlv_type, (unsigned int) len,
1112*a1157835SDaniel Fojt mandatory ? " (mandatory)" : "");
11136d49e1aeSJan Lentfer
11146d49e1aeSJan Lentfer res = eap_fast_parse_tlv(tlv, tlv_type, pos, len);
11156d49e1aeSJan Lentfer if (res == -2)
11166d49e1aeSJan Lentfer break;
11176d49e1aeSJan Lentfer if (res < 0) {
11186d49e1aeSJan Lentfer if (mandatory) {
11196d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-FAST: Nak unknown "
11206d49e1aeSJan Lentfer "mandatory TLV type %d", tlv_type);
11216d49e1aeSJan Lentfer *resp = eap_fast_tlv_nak(0, tlv_type);
11226d49e1aeSJan Lentfer break;
11236d49e1aeSJan Lentfer } else {
11246d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-FAST: ignored "
11256d49e1aeSJan Lentfer "unknown optional TLV type %d",
11266d49e1aeSJan Lentfer tlv_type);
11276d49e1aeSJan Lentfer }
11286d49e1aeSJan Lentfer }
11296d49e1aeSJan Lentfer
11306d49e1aeSJan Lentfer pos += len;
11316d49e1aeSJan Lentfer }
11326d49e1aeSJan Lentfer
11336d49e1aeSJan Lentfer return 0;
11346d49e1aeSJan Lentfer }
11356d49e1aeSJan Lentfer
11366d49e1aeSJan Lentfer
eap_fast_encrypt_response(struct eap_sm * sm,struct eap_fast_data * data,struct wpabuf * resp,u8 identifier,struct wpabuf ** out_data)11376d49e1aeSJan Lentfer static int eap_fast_encrypt_response(struct eap_sm *sm,
11386d49e1aeSJan Lentfer struct eap_fast_data *data,
11396d49e1aeSJan Lentfer struct wpabuf *resp,
11406d49e1aeSJan Lentfer u8 identifier, struct wpabuf **out_data)
11416d49e1aeSJan Lentfer {
11426d49e1aeSJan Lentfer if (resp == NULL)
11436d49e1aeSJan Lentfer return 0;
11446d49e1aeSJan Lentfer
11456d49e1aeSJan Lentfer wpa_hexdump_buf(MSG_DEBUG, "EAP-FAST: Encrypting Phase 2 data",
11466d49e1aeSJan Lentfer resp);
11476d49e1aeSJan Lentfer if (eap_peer_tls_encrypt(sm, &data->ssl, EAP_TYPE_FAST,
11486d49e1aeSJan Lentfer data->fast_version, identifier,
11496d49e1aeSJan Lentfer resp, out_data)) {
11506d49e1aeSJan Lentfer wpa_printf(MSG_INFO, "EAP-FAST: Failed to encrypt a Phase 2 "
11516d49e1aeSJan Lentfer "frame");
11526d49e1aeSJan Lentfer }
1153*a1157835SDaniel Fojt wpabuf_clear_free(resp);
11546d49e1aeSJan Lentfer
11556d49e1aeSJan Lentfer return 0;
11566d49e1aeSJan Lentfer }
11576d49e1aeSJan Lentfer
11586d49e1aeSJan Lentfer
eap_fast_pac_request(void)11596d49e1aeSJan Lentfer static struct wpabuf * eap_fast_pac_request(void)
11606d49e1aeSJan Lentfer {
11616d49e1aeSJan Lentfer struct wpabuf *tmp;
11626d49e1aeSJan Lentfer u8 *pos, *pos2;
11636d49e1aeSJan Lentfer
11646d49e1aeSJan Lentfer tmp = wpabuf_alloc(sizeof(struct eap_tlv_hdr) +
11656d49e1aeSJan Lentfer sizeof(struct eap_tlv_request_action_tlv) +
11666d49e1aeSJan Lentfer sizeof(struct eap_tlv_pac_type_tlv));
11676d49e1aeSJan Lentfer if (tmp == NULL)
11686d49e1aeSJan Lentfer return NULL;
11696d49e1aeSJan Lentfer
11706d49e1aeSJan Lentfer pos = wpabuf_put(tmp, 0);
11716d49e1aeSJan Lentfer pos2 = eap_fast_write_pac_request(pos, PAC_TYPE_TUNNEL_PAC);
11726d49e1aeSJan Lentfer wpabuf_put(tmp, pos2 - pos);
11736d49e1aeSJan Lentfer return tmp;
11746d49e1aeSJan Lentfer }
11756d49e1aeSJan Lentfer
11766d49e1aeSJan Lentfer
eap_fast_process_decrypted(struct eap_sm * sm,struct eap_fast_data * data,struct eap_method_ret * ret,u8 identifier,struct wpabuf * decrypted,struct wpabuf ** out_data)11776d49e1aeSJan Lentfer static int eap_fast_process_decrypted(struct eap_sm *sm,
11786d49e1aeSJan Lentfer struct eap_fast_data *data,
11796d49e1aeSJan Lentfer struct eap_method_ret *ret,
1180*a1157835SDaniel Fojt u8 identifier,
11816d49e1aeSJan Lentfer struct wpabuf *decrypted,
11826d49e1aeSJan Lentfer struct wpabuf **out_data)
11836d49e1aeSJan Lentfer {
11846d49e1aeSJan Lentfer struct wpabuf *resp = NULL, *tmp;
11856d49e1aeSJan Lentfer struct eap_fast_tlv_parse tlv;
11866d49e1aeSJan Lentfer int failed = 0;
11876d49e1aeSJan Lentfer
11886d49e1aeSJan Lentfer if (eap_fast_parse_decrypted(decrypted, &tlv, &resp) < 0)
11896d49e1aeSJan Lentfer return 0;
11906d49e1aeSJan Lentfer if (resp)
11916d49e1aeSJan Lentfer return eap_fast_encrypt_response(sm, data, resp,
1192*a1157835SDaniel Fojt identifier, out_data);
11936d49e1aeSJan Lentfer
11946d49e1aeSJan Lentfer if (tlv.result == EAP_TLV_RESULT_FAILURE) {
11956d49e1aeSJan Lentfer resp = eap_fast_tlv_result(EAP_TLV_RESULT_FAILURE, 0);
11966d49e1aeSJan Lentfer return eap_fast_encrypt_response(sm, data, resp,
1197*a1157835SDaniel Fojt identifier, out_data);
11986d49e1aeSJan Lentfer }
11996d49e1aeSJan Lentfer
12006d49e1aeSJan Lentfer if (tlv.iresult == EAP_TLV_RESULT_FAILURE) {
12016d49e1aeSJan Lentfer resp = eap_fast_tlv_result(EAP_TLV_RESULT_FAILURE, 1);
12026d49e1aeSJan Lentfer return eap_fast_encrypt_response(sm, data, resp,
1203*a1157835SDaniel Fojt identifier, out_data);
12046d49e1aeSJan Lentfer }
12056d49e1aeSJan Lentfer
12066d49e1aeSJan Lentfer if (tlv.crypto_binding) {
12076d49e1aeSJan Lentfer tmp = eap_fast_process_crypto_binding(sm, data, ret,
12086d49e1aeSJan Lentfer tlv.crypto_binding,
12096d49e1aeSJan Lentfer tlv.crypto_binding_len);
12106d49e1aeSJan Lentfer if (tmp == NULL)
12116d49e1aeSJan Lentfer failed = 1;
12126d49e1aeSJan Lentfer else
12136d49e1aeSJan Lentfer resp = wpabuf_concat(resp, tmp);
12146d49e1aeSJan Lentfer }
12156d49e1aeSJan Lentfer
12166d49e1aeSJan Lentfer if (tlv.iresult == EAP_TLV_RESULT_SUCCESS) {
12176d49e1aeSJan Lentfer tmp = eap_fast_tlv_result(failed ? EAP_TLV_RESULT_FAILURE :
12186d49e1aeSJan Lentfer EAP_TLV_RESULT_SUCCESS, 1);
12196d49e1aeSJan Lentfer resp = wpabuf_concat(resp, tmp);
12206d49e1aeSJan Lentfer }
12216d49e1aeSJan Lentfer
12226d49e1aeSJan Lentfer if (tlv.eap_payload_tlv) {
12236d49e1aeSJan Lentfer tmp = eap_fast_process_eap_payload_tlv(
12243ff40c12SJohn Marino sm, data, ret, tlv.eap_payload_tlv,
12256d49e1aeSJan Lentfer tlv.eap_payload_tlv_len);
12266d49e1aeSJan Lentfer resp = wpabuf_concat(resp, tmp);
12276d49e1aeSJan Lentfer }
12286d49e1aeSJan Lentfer
12296d49e1aeSJan Lentfer if (tlv.pac && tlv.result != EAP_TLV_RESULT_SUCCESS) {
12306d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-FAST: PAC TLV without Result TLV "
12316d49e1aeSJan Lentfer "acknowledging success");
12326d49e1aeSJan Lentfer failed = 1;
12336d49e1aeSJan Lentfer } else if (tlv.pac && tlv.result == EAP_TLV_RESULT_SUCCESS) {
12346d49e1aeSJan Lentfer tmp = eap_fast_process_pac(sm, data, ret, tlv.pac,
12356d49e1aeSJan Lentfer tlv.pac_len);
12366d49e1aeSJan Lentfer resp = wpabuf_concat(resp, tmp);
12376d49e1aeSJan Lentfer }
12386d49e1aeSJan Lentfer
12396d49e1aeSJan Lentfer if (data->current_pac == NULL && data->provisioning &&
12406d49e1aeSJan Lentfer !data->anon_provisioning && !tlv.pac &&
12416d49e1aeSJan Lentfer (tlv.iresult == EAP_TLV_RESULT_SUCCESS ||
12426d49e1aeSJan Lentfer tlv.result == EAP_TLV_RESULT_SUCCESS)) {
12436d49e1aeSJan Lentfer /*
12446d49e1aeSJan Lentfer * Need to request Tunnel PAC when using authenticated
12456d49e1aeSJan Lentfer * provisioning.
12466d49e1aeSJan Lentfer */
12476d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-FAST: Request Tunnel PAC");
12486d49e1aeSJan Lentfer tmp = eap_fast_pac_request();
12496d49e1aeSJan Lentfer resp = wpabuf_concat(resp, tmp);
12506d49e1aeSJan Lentfer }
12516d49e1aeSJan Lentfer
12526d49e1aeSJan Lentfer if (tlv.result == EAP_TLV_RESULT_SUCCESS && !failed) {
12536d49e1aeSJan Lentfer tmp = eap_fast_tlv_result(EAP_TLV_RESULT_SUCCESS, 0);
12546d49e1aeSJan Lentfer resp = wpabuf_concat(tmp, resp);
12556d49e1aeSJan Lentfer } else if (failed) {
12566d49e1aeSJan Lentfer tmp = eap_fast_tlv_result(EAP_TLV_RESULT_FAILURE, 0);
12576d49e1aeSJan Lentfer resp = wpabuf_concat(tmp, resp);
12586d49e1aeSJan Lentfer }
12596d49e1aeSJan Lentfer
12606d49e1aeSJan Lentfer if (resp && tlv.result == EAP_TLV_RESULT_SUCCESS && !failed &&
12616d49e1aeSJan Lentfer tlv.crypto_binding && data->phase2_success) {
12626d49e1aeSJan Lentfer if (data->anon_provisioning) {
12636d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-FAST: Unauthenticated "
12646d49e1aeSJan Lentfer "provisioning completed successfully.");
12656d49e1aeSJan Lentfer ret->methodState = METHOD_DONE;
12666d49e1aeSJan Lentfer ret->decision = DECISION_FAIL;
12673ff40c12SJohn Marino sm->expected_failure = 1;
12686d49e1aeSJan Lentfer } else {
12696d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-FAST: Authentication "
12706d49e1aeSJan Lentfer "completed successfully.");
12716d49e1aeSJan Lentfer if (data->provisioning)
12726d49e1aeSJan Lentfer ret->methodState = METHOD_MAY_CONT;
12736d49e1aeSJan Lentfer else
12746d49e1aeSJan Lentfer ret->methodState = METHOD_DONE;
12756d49e1aeSJan Lentfer ret->decision = DECISION_UNCOND_SUCC;
12766d49e1aeSJan Lentfer }
12776d49e1aeSJan Lentfer }
12786d49e1aeSJan Lentfer
12796d49e1aeSJan Lentfer if (resp == NULL) {
12806d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-FAST: No recognized TLVs - send "
12816d49e1aeSJan Lentfer "empty response packet");
12826d49e1aeSJan Lentfer resp = wpabuf_alloc(1);
12836d49e1aeSJan Lentfer }
12846d49e1aeSJan Lentfer
1285*a1157835SDaniel Fojt return eap_fast_encrypt_response(sm, data, resp, identifier,
12866d49e1aeSJan Lentfer out_data);
12876d49e1aeSJan Lentfer }
12886d49e1aeSJan Lentfer
12896d49e1aeSJan Lentfer
eap_fast_decrypt(struct eap_sm * sm,struct eap_fast_data * data,struct eap_method_ret * ret,u8 identifier,const struct wpabuf * in_data,struct wpabuf ** out_data)12906d49e1aeSJan Lentfer static int eap_fast_decrypt(struct eap_sm *sm, struct eap_fast_data *data,
1291*a1157835SDaniel Fojt struct eap_method_ret *ret, u8 identifier,
12926d49e1aeSJan Lentfer const struct wpabuf *in_data,
12936d49e1aeSJan Lentfer struct wpabuf **out_data)
12946d49e1aeSJan Lentfer {
12956d49e1aeSJan Lentfer struct wpabuf *in_decrypted;
12966d49e1aeSJan Lentfer int res;
12976d49e1aeSJan Lentfer
12986d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-FAST: Received %lu bytes encrypted data for"
12996d49e1aeSJan Lentfer " Phase 2", (unsigned long) wpabuf_len(in_data));
13006d49e1aeSJan Lentfer
13016d49e1aeSJan Lentfer if (data->pending_phase2_req) {
13026d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-FAST: Pending Phase 2 request - "
13036d49e1aeSJan Lentfer "skip decryption and use old data");
13046d49e1aeSJan Lentfer /* Clear TLS reassembly state. */
13056d49e1aeSJan Lentfer eap_peer_tls_reset_input(&data->ssl);
13066d49e1aeSJan Lentfer
13076d49e1aeSJan Lentfer in_decrypted = data->pending_phase2_req;
13086d49e1aeSJan Lentfer data->pending_phase2_req = NULL;
13096d49e1aeSJan Lentfer goto continue_req;
13106d49e1aeSJan Lentfer }
13116d49e1aeSJan Lentfer
13126d49e1aeSJan Lentfer if (wpabuf_len(in_data) == 0) {
13136d49e1aeSJan Lentfer /* Received TLS ACK - requesting more fragments */
13146d49e1aeSJan Lentfer return eap_peer_tls_encrypt(sm, &data->ssl, EAP_TYPE_FAST,
13156d49e1aeSJan Lentfer data->fast_version,
1316*a1157835SDaniel Fojt identifier, NULL, out_data);
13176d49e1aeSJan Lentfer }
13186d49e1aeSJan Lentfer
13196d49e1aeSJan Lentfer res = eap_peer_tls_decrypt(sm, &data->ssl, in_data, &in_decrypted);
13206d49e1aeSJan Lentfer if (res)
13216d49e1aeSJan Lentfer return res;
13226d49e1aeSJan Lentfer
13236d49e1aeSJan Lentfer continue_req:
13246d49e1aeSJan Lentfer wpa_hexdump_buf(MSG_MSGDUMP, "EAP-FAST: Decrypted Phase 2 TLV(s)",
13256d49e1aeSJan Lentfer in_decrypted);
13266d49e1aeSJan Lentfer
13276d49e1aeSJan Lentfer if (wpabuf_len(in_decrypted) < 4) {
13286d49e1aeSJan Lentfer wpa_printf(MSG_INFO, "EAP-FAST: Too short Phase 2 "
13296d49e1aeSJan Lentfer "TLV frame (len=%lu)",
13306d49e1aeSJan Lentfer (unsigned long) wpabuf_len(in_decrypted));
1331*a1157835SDaniel Fojt wpabuf_clear_free(in_decrypted);
13326d49e1aeSJan Lentfer return -1;
13336d49e1aeSJan Lentfer }
13346d49e1aeSJan Lentfer
1335*a1157835SDaniel Fojt res = eap_fast_process_decrypted(sm, data, ret, identifier,
13366d49e1aeSJan Lentfer in_decrypted, out_data);
13376d49e1aeSJan Lentfer
1338*a1157835SDaniel Fojt wpabuf_clear_free(in_decrypted);
13396d49e1aeSJan Lentfer
13406d49e1aeSJan Lentfer return res;
13416d49e1aeSJan Lentfer }
13426d49e1aeSJan Lentfer
13436d49e1aeSJan Lentfer
eap_fast_get_a_id(const u8 * buf,size_t len,size_t * id_len)13446d49e1aeSJan Lentfer static const u8 * eap_fast_get_a_id(const u8 *buf, size_t len, size_t *id_len)
13456d49e1aeSJan Lentfer {
13466d49e1aeSJan Lentfer const u8 *a_id;
1347*a1157835SDaniel Fojt const struct pac_tlv_hdr *hdr;
13486d49e1aeSJan Lentfer
13496d49e1aeSJan Lentfer /*
13506d49e1aeSJan Lentfer * Parse authority identity (A-ID) from the EAP-FAST/Start. This
13516d49e1aeSJan Lentfer * supports both raw A-ID and one inside an A-ID TLV.
13526d49e1aeSJan Lentfer */
13536d49e1aeSJan Lentfer a_id = buf;
13546d49e1aeSJan Lentfer *id_len = len;
13556d49e1aeSJan Lentfer if (len > sizeof(*hdr)) {
13566d49e1aeSJan Lentfer int tlen;
1357*a1157835SDaniel Fojt hdr = (const struct pac_tlv_hdr *) buf;
13586d49e1aeSJan Lentfer tlen = be_to_host16(hdr->len);
13596d49e1aeSJan Lentfer if (be_to_host16(hdr->type) == PAC_TYPE_A_ID &&
13606d49e1aeSJan Lentfer sizeof(*hdr) + tlen <= len) {
13616d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-FAST: A-ID was in TLV "
13626d49e1aeSJan Lentfer "(Start)");
1363*a1157835SDaniel Fojt a_id = (const u8 *) (hdr + 1);
13646d49e1aeSJan Lentfer *id_len = tlen;
13656d49e1aeSJan Lentfer }
13666d49e1aeSJan Lentfer }
13676d49e1aeSJan Lentfer wpa_hexdump_ascii(MSG_DEBUG, "EAP-FAST: A-ID", a_id, *id_len);
13686d49e1aeSJan Lentfer
13696d49e1aeSJan Lentfer return a_id;
13706d49e1aeSJan Lentfer }
13716d49e1aeSJan Lentfer
13726d49e1aeSJan Lentfer
eap_fast_select_pac(struct eap_fast_data * data,const u8 * a_id,size_t a_id_len)13736d49e1aeSJan Lentfer static void eap_fast_select_pac(struct eap_fast_data *data,
13746d49e1aeSJan Lentfer const u8 *a_id, size_t a_id_len)
13756d49e1aeSJan Lentfer {
13766d49e1aeSJan Lentfer data->current_pac = eap_fast_get_pac(data->pac, a_id, a_id_len,
13776d49e1aeSJan Lentfer PAC_TYPE_TUNNEL_PAC);
13786d49e1aeSJan Lentfer if (data->current_pac == NULL) {
13796d49e1aeSJan Lentfer /*
13806d49e1aeSJan Lentfer * Tunnel PAC was not available for this A-ID. Try to use
13816d49e1aeSJan Lentfer * Machine Authentication PAC, if one is available.
13826d49e1aeSJan Lentfer */
13836d49e1aeSJan Lentfer data->current_pac = eap_fast_get_pac(
13846d49e1aeSJan Lentfer data->pac, a_id, a_id_len,
13856d49e1aeSJan Lentfer PAC_TYPE_MACHINE_AUTHENTICATION);
13866d49e1aeSJan Lentfer }
13876d49e1aeSJan Lentfer
13886d49e1aeSJan Lentfer if (data->current_pac) {
13896d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-FAST: PAC found for this A-ID "
13906d49e1aeSJan Lentfer "(PAC-Type %d)", data->current_pac->pac_type);
13916d49e1aeSJan Lentfer wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-FAST: A-ID-Info",
13926d49e1aeSJan Lentfer data->current_pac->a_id_info,
13936d49e1aeSJan Lentfer data->current_pac->a_id_info_len);
13946d49e1aeSJan Lentfer }
13956d49e1aeSJan Lentfer }
13966d49e1aeSJan Lentfer
13976d49e1aeSJan Lentfer
eap_fast_use_pac_opaque(struct eap_sm * sm,struct eap_fast_data * data,struct eap_fast_pac * pac)13986d49e1aeSJan Lentfer static int eap_fast_use_pac_opaque(struct eap_sm *sm,
13996d49e1aeSJan Lentfer struct eap_fast_data *data,
14006d49e1aeSJan Lentfer struct eap_fast_pac *pac)
14016d49e1aeSJan Lentfer {
14026d49e1aeSJan Lentfer u8 *tlv;
14036d49e1aeSJan Lentfer size_t tlv_len, olen;
14046d49e1aeSJan Lentfer struct eap_tlv_hdr *ehdr;
14056d49e1aeSJan Lentfer
14066d49e1aeSJan Lentfer olen = pac->pac_opaque_len;
14076d49e1aeSJan Lentfer tlv_len = sizeof(*ehdr) + olen;
14086d49e1aeSJan Lentfer tlv = os_malloc(tlv_len);
14096d49e1aeSJan Lentfer if (tlv) {
14106d49e1aeSJan Lentfer ehdr = (struct eap_tlv_hdr *) tlv;
14116d49e1aeSJan Lentfer ehdr->tlv_type = host_to_be16(PAC_TYPE_PAC_OPAQUE);
14126d49e1aeSJan Lentfer ehdr->length = host_to_be16(olen);
14136d49e1aeSJan Lentfer os_memcpy(ehdr + 1, pac->pac_opaque, olen);
14146d49e1aeSJan Lentfer }
14156d49e1aeSJan Lentfer if (tlv == NULL ||
14166d49e1aeSJan Lentfer tls_connection_client_hello_ext(sm->ssl_ctx, data->ssl.conn,
14176d49e1aeSJan Lentfer TLS_EXT_PAC_OPAQUE,
14186d49e1aeSJan Lentfer tlv, tlv_len) < 0) {
14196d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to add PAC-Opaque TLS "
14206d49e1aeSJan Lentfer "extension");
14216d49e1aeSJan Lentfer os_free(tlv);
14226d49e1aeSJan Lentfer return -1;
14236d49e1aeSJan Lentfer }
14246d49e1aeSJan Lentfer os_free(tlv);
14256d49e1aeSJan Lentfer
14266d49e1aeSJan Lentfer return 0;
14276d49e1aeSJan Lentfer }
14286d49e1aeSJan Lentfer
14296d49e1aeSJan Lentfer
eap_fast_clear_pac_opaque_ext(struct eap_sm * sm,struct eap_fast_data * data)14306d49e1aeSJan Lentfer static int eap_fast_clear_pac_opaque_ext(struct eap_sm *sm,
14316d49e1aeSJan Lentfer struct eap_fast_data *data)
14326d49e1aeSJan Lentfer {
14336d49e1aeSJan Lentfer if (tls_connection_client_hello_ext(sm->ssl_ctx, data->ssl.conn,
14346d49e1aeSJan Lentfer TLS_EXT_PAC_OPAQUE, NULL, 0) < 0) {
14356d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to remove PAC-Opaque "
14366d49e1aeSJan Lentfer "TLS extension");
14376d49e1aeSJan Lentfer return -1;
14386d49e1aeSJan Lentfer }
14396d49e1aeSJan Lentfer return 0;
14406d49e1aeSJan Lentfer }
14416d49e1aeSJan Lentfer
14426d49e1aeSJan Lentfer
eap_fast_set_provisioning_ciphers(struct eap_sm * sm,struct eap_fast_data * data)14436d49e1aeSJan Lentfer static int eap_fast_set_provisioning_ciphers(struct eap_sm *sm,
14446d49e1aeSJan Lentfer struct eap_fast_data *data)
14456d49e1aeSJan Lentfer {
1446*a1157835SDaniel Fojt u8 ciphers[7];
14476d49e1aeSJan Lentfer int count = 0;
14486d49e1aeSJan Lentfer
14496d49e1aeSJan Lentfer if (data->provisioning_allowed & EAP_FAST_PROV_UNAUTH) {
14506d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-FAST: Enabling unauthenticated "
14516d49e1aeSJan Lentfer "provisioning TLS cipher suites");
14526d49e1aeSJan Lentfer ciphers[count++] = TLS_CIPHER_ANON_DH_AES128_SHA;
14536d49e1aeSJan Lentfer }
14546d49e1aeSJan Lentfer
14556d49e1aeSJan Lentfer if (data->provisioning_allowed & EAP_FAST_PROV_AUTH) {
14566d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-FAST: Enabling authenticated "
14576d49e1aeSJan Lentfer "provisioning TLS cipher suites");
1458*a1157835SDaniel Fojt ciphers[count++] = TLS_CIPHER_RSA_DHE_AES256_SHA;
14596d49e1aeSJan Lentfer ciphers[count++] = TLS_CIPHER_RSA_DHE_AES128_SHA;
1460*a1157835SDaniel Fojt ciphers[count++] = TLS_CIPHER_AES256_SHA;
14616d49e1aeSJan Lentfer ciphers[count++] = TLS_CIPHER_AES128_SHA;
14626d49e1aeSJan Lentfer ciphers[count++] = TLS_CIPHER_RC4_SHA;
14636d49e1aeSJan Lentfer }
14646d49e1aeSJan Lentfer
14656d49e1aeSJan Lentfer ciphers[count++] = TLS_CIPHER_NONE;
14666d49e1aeSJan Lentfer
14676d49e1aeSJan Lentfer if (tls_connection_set_cipher_list(sm->ssl_ctx, data->ssl.conn,
14686d49e1aeSJan Lentfer ciphers)) {
14696d49e1aeSJan Lentfer wpa_printf(MSG_INFO, "EAP-FAST: Could not configure TLS "
14706d49e1aeSJan Lentfer "cipher suites for provisioning");
14716d49e1aeSJan Lentfer return -1;
14726d49e1aeSJan Lentfer }
14736d49e1aeSJan Lentfer
14746d49e1aeSJan Lentfer return 0;
14756d49e1aeSJan Lentfer }
14766d49e1aeSJan Lentfer
14776d49e1aeSJan Lentfer
eap_fast_process_start(struct eap_sm * sm,struct eap_fast_data * data,u8 flags,const u8 * pos,size_t left)14786d49e1aeSJan Lentfer static int eap_fast_process_start(struct eap_sm *sm,
14796d49e1aeSJan Lentfer struct eap_fast_data *data, u8 flags,
14806d49e1aeSJan Lentfer const u8 *pos, size_t left)
14816d49e1aeSJan Lentfer {
14826d49e1aeSJan Lentfer const u8 *a_id;
14836d49e1aeSJan Lentfer size_t a_id_len;
14846d49e1aeSJan Lentfer
14856d49e1aeSJan Lentfer /* EAP-FAST Version negotiation (section 3.1) */
14866d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-FAST: Start (server ver=%d, own ver=%d)",
14873ff40c12SJohn Marino flags & EAP_TLS_VERSION_MASK, data->fast_version);
14883ff40c12SJohn Marino if ((flags & EAP_TLS_VERSION_MASK) < data->fast_version)
14893ff40c12SJohn Marino data->fast_version = flags & EAP_TLS_VERSION_MASK;
14906d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-FAST: Using FAST version %d",
14916d49e1aeSJan Lentfer data->fast_version);
14926d49e1aeSJan Lentfer
14936d49e1aeSJan Lentfer a_id = eap_fast_get_a_id(pos, left, &a_id_len);
14946d49e1aeSJan Lentfer eap_fast_select_pac(data, a_id, a_id_len);
14956d49e1aeSJan Lentfer
14966d49e1aeSJan Lentfer if (data->resuming && data->current_pac) {
14976d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-FAST: Trying to resume session - "
14986d49e1aeSJan Lentfer "do not add PAC-Opaque to TLS ClientHello");
14996d49e1aeSJan Lentfer if (eap_fast_clear_pac_opaque_ext(sm, data) < 0)
15006d49e1aeSJan Lentfer return -1;
15016d49e1aeSJan Lentfer } else if (data->current_pac) {
15026d49e1aeSJan Lentfer /*
15036d49e1aeSJan Lentfer * PAC found for the A-ID and we are not resuming an old
15046d49e1aeSJan Lentfer * session, so add PAC-Opaque extension to ClientHello.
15056d49e1aeSJan Lentfer */
15066d49e1aeSJan Lentfer if (eap_fast_use_pac_opaque(sm, data, data->current_pac) < 0)
15076d49e1aeSJan Lentfer return -1;
15086d49e1aeSJan Lentfer } else {
15096d49e1aeSJan Lentfer /* No PAC found, so we must provision one. */
15106d49e1aeSJan Lentfer if (!data->provisioning_allowed) {
15116d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-FAST: No PAC found and "
15126d49e1aeSJan Lentfer "provisioning disabled");
15136d49e1aeSJan Lentfer return -1;
15146d49e1aeSJan Lentfer }
15156d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-FAST: No PAC found - "
15166d49e1aeSJan Lentfer "starting provisioning");
15176d49e1aeSJan Lentfer if (eap_fast_set_provisioning_ciphers(sm, data) < 0 ||
15186d49e1aeSJan Lentfer eap_fast_clear_pac_opaque_ext(sm, data) < 0)
15196d49e1aeSJan Lentfer return -1;
15206d49e1aeSJan Lentfer data->provisioning = 1;
15216d49e1aeSJan Lentfer }
15226d49e1aeSJan Lentfer
15236d49e1aeSJan Lentfer return 0;
15246d49e1aeSJan Lentfer }
15256d49e1aeSJan Lentfer
15266d49e1aeSJan Lentfer
eap_fast_process(struct eap_sm * sm,void * priv,struct eap_method_ret * ret,const struct wpabuf * reqData)15276d49e1aeSJan Lentfer static struct wpabuf * eap_fast_process(struct eap_sm *sm, void *priv,
15286d49e1aeSJan Lentfer struct eap_method_ret *ret,
15296d49e1aeSJan Lentfer const struct wpabuf *reqData)
15306d49e1aeSJan Lentfer {
15316d49e1aeSJan Lentfer const struct eap_hdr *req;
15326d49e1aeSJan Lentfer size_t left;
15336d49e1aeSJan Lentfer int res;
15346d49e1aeSJan Lentfer u8 flags, id;
15356d49e1aeSJan Lentfer struct wpabuf *resp;
15366d49e1aeSJan Lentfer const u8 *pos;
15376d49e1aeSJan Lentfer struct eap_fast_data *data = priv;
1538*a1157835SDaniel Fojt struct wpabuf msg;
15396d49e1aeSJan Lentfer
15406d49e1aeSJan Lentfer pos = eap_peer_tls_process_init(sm, &data->ssl, EAP_TYPE_FAST, ret,
15416d49e1aeSJan Lentfer reqData, &left, &flags);
15426d49e1aeSJan Lentfer if (pos == NULL)
15436d49e1aeSJan Lentfer return NULL;
15446d49e1aeSJan Lentfer
15456d49e1aeSJan Lentfer req = wpabuf_head(reqData);
15466d49e1aeSJan Lentfer id = req->identifier;
15476d49e1aeSJan Lentfer
15486d49e1aeSJan Lentfer if (flags & EAP_TLS_FLAGS_START) {
15496d49e1aeSJan Lentfer if (eap_fast_process_start(sm, data, flags, pos, left) < 0)
15506d49e1aeSJan Lentfer return NULL;
15516d49e1aeSJan Lentfer
15526d49e1aeSJan Lentfer left = 0; /* A-ID is not used in further packet processing */
15536d49e1aeSJan Lentfer }
15546d49e1aeSJan Lentfer
1555*a1157835SDaniel Fojt wpabuf_set(&msg, pos, left);
1556*a1157835SDaniel Fojt
15576d49e1aeSJan Lentfer resp = NULL;
15586d49e1aeSJan Lentfer if (tls_connection_established(sm->ssl_ctx, data->ssl.conn) &&
15596d49e1aeSJan Lentfer !data->resuming) {
15606d49e1aeSJan Lentfer /* Process tunneled (encrypted) phase 2 data. */
1561*a1157835SDaniel Fojt res = eap_fast_decrypt(sm, data, ret, id, &msg, &resp);
15626d49e1aeSJan Lentfer if (res < 0) {
15636d49e1aeSJan Lentfer ret->methodState = METHOD_DONE;
15646d49e1aeSJan Lentfer ret->decision = DECISION_FAIL;
15656d49e1aeSJan Lentfer /*
15666d49e1aeSJan Lentfer * Ack possible Alert that may have caused failure in
15676d49e1aeSJan Lentfer * decryption.
15686d49e1aeSJan Lentfer */
15696d49e1aeSJan Lentfer res = 1;
15706d49e1aeSJan Lentfer }
15716d49e1aeSJan Lentfer } else {
1572*a1157835SDaniel Fojt if (sm->waiting_ext_cert_check && data->pending_resp) {
1573*a1157835SDaniel Fojt struct eap_peer_config *config = eap_get_config(sm);
1574*a1157835SDaniel Fojt
1575*a1157835SDaniel Fojt if (config->pending_ext_cert_check ==
1576*a1157835SDaniel Fojt EXT_CERT_CHECK_GOOD) {
1577*a1157835SDaniel Fojt wpa_printf(MSG_DEBUG,
1578*a1157835SDaniel Fojt "EAP-FAST: External certificate check succeeded - continue handshake");
1579*a1157835SDaniel Fojt resp = data->pending_resp;
1580*a1157835SDaniel Fojt data->pending_resp = NULL;
1581*a1157835SDaniel Fojt sm->waiting_ext_cert_check = 0;
1582*a1157835SDaniel Fojt return resp;
1583*a1157835SDaniel Fojt }
1584*a1157835SDaniel Fojt
1585*a1157835SDaniel Fojt if (config->pending_ext_cert_check ==
1586*a1157835SDaniel Fojt EXT_CERT_CHECK_BAD) {
1587*a1157835SDaniel Fojt wpa_printf(MSG_DEBUG,
1588*a1157835SDaniel Fojt "EAP-FAST: External certificate check failed - force authentication failure");
1589*a1157835SDaniel Fojt ret->methodState = METHOD_DONE;
1590*a1157835SDaniel Fojt ret->decision = DECISION_FAIL;
1591*a1157835SDaniel Fojt sm->waiting_ext_cert_check = 0;
1592*a1157835SDaniel Fojt return NULL;
1593*a1157835SDaniel Fojt }
1594*a1157835SDaniel Fojt
1595*a1157835SDaniel Fojt wpa_printf(MSG_DEBUG,
1596*a1157835SDaniel Fojt "EAP-FAST: Continuing to wait external server certificate validation");
1597*a1157835SDaniel Fojt return NULL;
1598*a1157835SDaniel Fojt }
1599*a1157835SDaniel Fojt
16006d49e1aeSJan Lentfer /* Continue processing TLS handshake (phase 1). */
16016d49e1aeSJan Lentfer res = eap_peer_tls_process_helper(sm, &data->ssl,
16026d49e1aeSJan Lentfer EAP_TYPE_FAST,
1603*a1157835SDaniel Fojt data->fast_version, id, &msg,
1604*a1157835SDaniel Fojt &resp);
1605*a1157835SDaniel Fojt if (res < 0) {
1606*a1157835SDaniel Fojt wpa_printf(MSG_DEBUG,
1607*a1157835SDaniel Fojt "EAP-FAST: TLS processing failed");
1608*a1157835SDaniel Fojt ret->methodState = METHOD_DONE;
1609*a1157835SDaniel Fojt ret->decision = DECISION_FAIL;
1610*a1157835SDaniel Fojt return resp;
1611*a1157835SDaniel Fojt }
1612*a1157835SDaniel Fojt
1613*a1157835SDaniel Fojt if (sm->waiting_ext_cert_check) {
1614*a1157835SDaniel Fojt wpa_printf(MSG_DEBUG,
1615*a1157835SDaniel Fojt "EAP-FAST: Waiting external server certificate validation");
1616*a1157835SDaniel Fojt wpabuf_clear_free(data->pending_resp);
1617*a1157835SDaniel Fojt data->pending_resp = resp;
1618*a1157835SDaniel Fojt return NULL;
1619*a1157835SDaniel Fojt }
16206d49e1aeSJan Lentfer
16216d49e1aeSJan Lentfer if (tls_connection_established(sm->ssl_ctx, data->ssl.conn)) {
16226d49e1aeSJan Lentfer char cipher[80];
16236d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG,
16246d49e1aeSJan Lentfer "EAP-FAST: TLS done, proceed to Phase 2");
16256d49e1aeSJan Lentfer if (data->provisioning &&
16266d49e1aeSJan Lentfer (!(data->provisioning_allowed &
16276d49e1aeSJan Lentfer EAP_FAST_PROV_AUTH) ||
16286d49e1aeSJan Lentfer tls_get_cipher(sm->ssl_ctx, data->ssl.conn,
16296d49e1aeSJan Lentfer cipher, sizeof(cipher)) < 0 ||
16306d49e1aeSJan Lentfer os_strstr(cipher, "ADH-") ||
16316d49e1aeSJan Lentfer os_strstr(cipher, "anon"))) {
16326d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-FAST: Using "
16336d49e1aeSJan Lentfer "anonymous (unauthenticated) "
16346d49e1aeSJan Lentfer "provisioning");
16356d49e1aeSJan Lentfer data->anon_provisioning = 1;
16366d49e1aeSJan Lentfer } else
16376d49e1aeSJan Lentfer data->anon_provisioning = 0;
16386d49e1aeSJan Lentfer data->resuming = 0;
1639*a1157835SDaniel Fojt if (eap_fast_derive_keys(sm, data) < 0) {
1640*a1157835SDaniel Fojt wpa_printf(MSG_DEBUG,
1641*a1157835SDaniel Fojt "EAP-FAST: Could not derive keys");
1642*a1157835SDaniel Fojt ret->methodState = METHOD_DONE;
1643*a1157835SDaniel Fojt ret->decision = DECISION_FAIL;
1644*a1157835SDaniel Fojt wpabuf_clear_free(resp);
1645*a1157835SDaniel Fojt return NULL;
1646*a1157835SDaniel Fojt }
16476d49e1aeSJan Lentfer }
16486d49e1aeSJan Lentfer
16496d49e1aeSJan Lentfer if (res == 2) {
16506d49e1aeSJan Lentfer /*
16516d49e1aeSJan Lentfer * Application data included in the handshake message.
16526d49e1aeSJan Lentfer */
1653*a1157835SDaniel Fojt wpabuf_clear_free(data->pending_phase2_req);
16546d49e1aeSJan Lentfer data->pending_phase2_req = resp;
16556d49e1aeSJan Lentfer resp = NULL;
1656*a1157835SDaniel Fojt res = eap_fast_decrypt(sm, data, ret, id, &msg, &resp);
16576d49e1aeSJan Lentfer }
16586d49e1aeSJan Lentfer }
16596d49e1aeSJan Lentfer
16606d49e1aeSJan Lentfer if (res == 1) {
1661*a1157835SDaniel Fojt wpabuf_clear_free(resp);
16626d49e1aeSJan Lentfer return eap_peer_tls_build_ack(id, EAP_TYPE_FAST,
16636d49e1aeSJan Lentfer data->fast_version);
16646d49e1aeSJan Lentfer }
16656d49e1aeSJan Lentfer
16666d49e1aeSJan Lentfer return resp;
16676d49e1aeSJan Lentfer }
16686d49e1aeSJan Lentfer
16696d49e1aeSJan Lentfer
16706d49e1aeSJan Lentfer #if 0 /* FIX */
16716d49e1aeSJan Lentfer static Boolean eap_fast_has_reauth_data(struct eap_sm *sm, void *priv)
16726d49e1aeSJan Lentfer {
16736d49e1aeSJan Lentfer struct eap_fast_data *data = priv;
16746d49e1aeSJan Lentfer return tls_connection_established(sm->ssl_ctx, data->ssl.conn);
16756d49e1aeSJan Lentfer }
16766d49e1aeSJan Lentfer
16776d49e1aeSJan Lentfer
16786d49e1aeSJan Lentfer static void eap_fast_deinit_for_reauth(struct eap_sm *sm, void *priv)
16796d49e1aeSJan Lentfer {
16806d49e1aeSJan Lentfer struct eap_fast_data *data = priv;
1681*a1157835SDaniel Fojt
1682*a1157835SDaniel Fojt if (data->phase2_priv && data->phase2_method &&
1683*a1157835SDaniel Fojt data->phase2_method->deinit_for_reauth)
1684*a1157835SDaniel Fojt data->phase2_method->deinit_for_reauth(sm, data->phase2_priv);
16856d49e1aeSJan Lentfer os_free(data->key_block_p);
16866d49e1aeSJan Lentfer data->key_block_p = NULL;
1687*a1157835SDaniel Fojt wpabuf_clear_free(data->pending_phase2_req);
16886d49e1aeSJan Lentfer data->pending_phase2_req = NULL;
1689*a1157835SDaniel Fojt wpabuf_clear_free(data->pending_resp);
1690*a1157835SDaniel Fojt data->pending_resp = NULL;
16916d49e1aeSJan Lentfer }
16926d49e1aeSJan Lentfer
16936d49e1aeSJan Lentfer
16946d49e1aeSJan Lentfer static void * eap_fast_init_for_reauth(struct eap_sm *sm, void *priv)
16956d49e1aeSJan Lentfer {
16966d49e1aeSJan Lentfer struct eap_fast_data *data = priv;
16976d49e1aeSJan Lentfer if (eap_peer_tls_reauth_init(sm, &data->ssl)) {
16986d49e1aeSJan Lentfer os_free(data);
16996d49e1aeSJan Lentfer return NULL;
17006d49e1aeSJan Lentfer }
1701*a1157835SDaniel Fojt os_memset(data->key_data, 0, EAP_FAST_KEY_LEN);
1702*a1157835SDaniel Fojt os_memset(data->emsk, 0, EAP_EMSK_LEN);
17033ff40c12SJohn Marino os_free(data->session_id);
17043ff40c12SJohn Marino data->session_id = NULL;
17056d49e1aeSJan Lentfer if (data->phase2_priv && data->phase2_method &&
17066d49e1aeSJan Lentfer data->phase2_method->init_for_reauth)
17076d49e1aeSJan Lentfer data->phase2_method->init_for_reauth(sm, data->phase2_priv);
17086d49e1aeSJan Lentfer data->phase2_success = 0;
17096d49e1aeSJan Lentfer data->resuming = 1;
17106d49e1aeSJan Lentfer data->provisioning = 0;
17116d49e1aeSJan Lentfer data->anon_provisioning = 0;
17126d49e1aeSJan Lentfer data->simck_idx = 0;
17136d49e1aeSJan Lentfer return priv;
17146d49e1aeSJan Lentfer }
17156d49e1aeSJan Lentfer #endif
17166d49e1aeSJan Lentfer
17176d49e1aeSJan Lentfer
eap_fast_get_status(struct eap_sm * sm,void * priv,char * buf,size_t buflen,int verbose)17186d49e1aeSJan Lentfer static int eap_fast_get_status(struct eap_sm *sm, void *priv, char *buf,
17196d49e1aeSJan Lentfer size_t buflen, int verbose)
17206d49e1aeSJan Lentfer {
17216d49e1aeSJan Lentfer struct eap_fast_data *data = priv;
17226d49e1aeSJan Lentfer int len, ret;
17236d49e1aeSJan Lentfer
17246d49e1aeSJan Lentfer len = eap_peer_tls_status(sm, &data->ssl, buf, buflen, verbose);
17256d49e1aeSJan Lentfer if (data->phase2_method) {
17266d49e1aeSJan Lentfer ret = os_snprintf(buf + len, buflen - len,
17276d49e1aeSJan Lentfer "EAP-FAST Phase2 method=%s\n",
17286d49e1aeSJan Lentfer data->phase2_method->name);
1729*a1157835SDaniel Fojt if (os_snprintf_error(buflen - len, ret))
17306d49e1aeSJan Lentfer return len;
17316d49e1aeSJan Lentfer len += ret;
17326d49e1aeSJan Lentfer }
17336d49e1aeSJan Lentfer return len;
17346d49e1aeSJan Lentfer }
17356d49e1aeSJan Lentfer
17366d49e1aeSJan Lentfer
eap_fast_isKeyAvailable(struct eap_sm * sm,void * priv)17376d49e1aeSJan Lentfer static Boolean eap_fast_isKeyAvailable(struct eap_sm *sm, void *priv)
17386d49e1aeSJan Lentfer {
17396d49e1aeSJan Lentfer struct eap_fast_data *data = priv;
17406d49e1aeSJan Lentfer return data->success;
17416d49e1aeSJan Lentfer }
17426d49e1aeSJan Lentfer
17436d49e1aeSJan Lentfer
eap_fast_getKey(struct eap_sm * sm,void * priv,size_t * len)17446d49e1aeSJan Lentfer static u8 * eap_fast_getKey(struct eap_sm *sm, void *priv, size_t *len)
17456d49e1aeSJan Lentfer {
17466d49e1aeSJan Lentfer struct eap_fast_data *data = priv;
17476d49e1aeSJan Lentfer u8 *key;
17486d49e1aeSJan Lentfer
17496d49e1aeSJan Lentfer if (!data->success)
17506d49e1aeSJan Lentfer return NULL;
17516d49e1aeSJan Lentfer
1752*a1157835SDaniel Fojt key = os_memdup(data->key_data, EAP_FAST_KEY_LEN);
17536d49e1aeSJan Lentfer if (key == NULL)
17546d49e1aeSJan Lentfer return NULL;
17556d49e1aeSJan Lentfer
17566d49e1aeSJan Lentfer *len = EAP_FAST_KEY_LEN;
17576d49e1aeSJan Lentfer
17586d49e1aeSJan Lentfer return key;
17596d49e1aeSJan Lentfer }
17606d49e1aeSJan Lentfer
17616d49e1aeSJan Lentfer
eap_fast_get_session_id(struct eap_sm * sm,void * priv,size_t * len)17623ff40c12SJohn Marino static u8 * eap_fast_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
17633ff40c12SJohn Marino {
17643ff40c12SJohn Marino struct eap_fast_data *data = priv;
17653ff40c12SJohn Marino u8 *id;
17663ff40c12SJohn Marino
1767*a1157835SDaniel Fojt if (!data->success || !data->session_id)
17683ff40c12SJohn Marino return NULL;
17693ff40c12SJohn Marino
1770*a1157835SDaniel Fojt id = os_memdup(data->session_id, data->id_len);
17713ff40c12SJohn Marino if (id == NULL)
17723ff40c12SJohn Marino return NULL;
17733ff40c12SJohn Marino
17743ff40c12SJohn Marino *len = data->id_len;
17753ff40c12SJohn Marino
17763ff40c12SJohn Marino return id;
17773ff40c12SJohn Marino }
17783ff40c12SJohn Marino
17793ff40c12SJohn Marino
eap_fast_get_emsk(struct eap_sm * sm,void * priv,size_t * len)17806d49e1aeSJan Lentfer static u8 * eap_fast_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
17816d49e1aeSJan Lentfer {
17826d49e1aeSJan Lentfer struct eap_fast_data *data = priv;
17836d49e1aeSJan Lentfer u8 *key;
17846d49e1aeSJan Lentfer
17856d49e1aeSJan Lentfer if (!data->success)
17866d49e1aeSJan Lentfer return NULL;
17876d49e1aeSJan Lentfer
1788*a1157835SDaniel Fojt key = os_memdup(data->emsk, EAP_EMSK_LEN);
17896d49e1aeSJan Lentfer if (key == NULL)
17906d49e1aeSJan Lentfer return NULL;
17916d49e1aeSJan Lentfer
17926d49e1aeSJan Lentfer *len = EAP_EMSK_LEN;
17936d49e1aeSJan Lentfer
17946d49e1aeSJan Lentfer return key;
17956d49e1aeSJan Lentfer }
17966d49e1aeSJan Lentfer
17976d49e1aeSJan Lentfer
eap_peer_fast_register(void)17986d49e1aeSJan Lentfer int eap_peer_fast_register(void)
17996d49e1aeSJan Lentfer {
18006d49e1aeSJan Lentfer struct eap_method *eap;
18016d49e1aeSJan Lentfer
18026d49e1aeSJan Lentfer eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
18036d49e1aeSJan Lentfer EAP_VENDOR_IETF, EAP_TYPE_FAST, "FAST");
18046d49e1aeSJan Lentfer if (eap == NULL)
18056d49e1aeSJan Lentfer return -1;
18066d49e1aeSJan Lentfer
18076d49e1aeSJan Lentfer eap->init = eap_fast_init;
18086d49e1aeSJan Lentfer eap->deinit = eap_fast_deinit;
18096d49e1aeSJan Lentfer eap->process = eap_fast_process;
18106d49e1aeSJan Lentfer eap->isKeyAvailable = eap_fast_isKeyAvailable;
18116d49e1aeSJan Lentfer eap->getKey = eap_fast_getKey;
18123ff40c12SJohn Marino eap->getSessionId = eap_fast_get_session_id;
18136d49e1aeSJan Lentfer eap->get_status = eap_fast_get_status;
18146d49e1aeSJan Lentfer #if 0
18156d49e1aeSJan Lentfer eap->has_reauth_data = eap_fast_has_reauth_data;
18166d49e1aeSJan Lentfer eap->deinit_for_reauth = eap_fast_deinit_for_reauth;
18176d49e1aeSJan Lentfer eap->init_for_reauth = eap_fast_init_for_reauth;
18186d49e1aeSJan Lentfer #endif
18196d49e1aeSJan Lentfer eap->get_emsk = eap_fast_get_emsk;
18206d49e1aeSJan Lentfer
1821*a1157835SDaniel Fojt return eap_peer_method_register(eap);
18226d49e1aeSJan Lentfer }
1823