1206b73d0SCy Schubert /* 2206b73d0SCy Schubert * EAP peer method: EAP-TEAP (RFC 7170) 3206b73d0SCy Schubert * Copyright (c) 2004-2019, Jouni Malinen <j@w1.fi> 4206b73d0SCy Schubert * 5206b73d0SCy Schubert * This software may be distributed under the terms of the BSD license. 6206b73d0SCy Schubert * See README for more details. 7206b73d0SCy Schubert */ 8206b73d0SCy Schubert 9206b73d0SCy Schubert #include "includes.h" 10206b73d0SCy Schubert 11206b73d0SCy Schubert #include "common.h" 12206b73d0SCy Schubert #include "crypto/tls.h" 13206b73d0SCy Schubert #include "eap_common/eap_teap_common.h" 14206b73d0SCy Schubert #include "eap_i.h" 15206b73d0SCy Schubert #include "eap_tls_common.h" 16206b73d0SCy Schubert #include "eap_config.h" 17206b73d0SCy Schubert #include "eap_teap_pac.h" 18206b73d0SCy Schubert 19206b73d0SCy Schubert #ifdef EAP_TEAP_DYNAMIC 20206b73d0SCy Schubert #include "eap_teap_pac.c" 21206b73d0SCy Schubert #endif /* EAP_TEAP_DYNAMIC */ 22206b73d0SCy Schubert 23206b73d0SCy Schubert 24206b73d0SCy Schubert static void eap_teap_deinit(struct eap_sm *sm, void *priv); 25206b73d0SCy Schubert 26206b73d0SCy Schubert 27206b73d0SCy Schubert struct eap_teap_data { 28206b73d0SCy Schubert struct eap_ssl_data ssl; 29206b73d0SCy Schubert 30206b73d0SCy Schubert u8 teap_version; /* Negotiated version */ 31206b73d0SCy Schubert u8 received_version; /* Version number received during negotiation */ 32206b73d0SCy Schubert u16 tls_cs; 33206b73d0SCy Schubert 34206b73d0SCy Schubert const struct eap_method *phase2_method; 35206b73d0SCy Schubert void *phase2_priv; 36206b73d0SCy Schubert int phase2_success; 37206b73d0SCy Schubert int inner_method_done; 38c1d255d3SCy Schubert int iresult_verified; 39206b73d0SCy Schubert int result_success_done; 40206b73d0SCy Schubert int on_tx_completion; 41206b73d0SCy Schubert 42206b73d0SCy Schubert struct eap_method_type phase2_type; 43206b73d0SCy Schubert struct eap_method_type *phase2_types; 44206b73d0SCy Schubert size_t num_phase2_types; 45206b73d0SCy Schubert int resuming; /* starting a resumed session */ 46206b73d0SCy Schubert #define EAP_TEAP_PROV_UNAUTH 1 47206b73d0SCy Schubert #define EAP_TEAP_PROV_AUTH 2 48206b73d0SCy Schubert int provisioning_allowed; /* Allowed PAC provisioning modes */ 49206b73d0SCy Schubert int provisioning; /* doing PAC provisioning (not the normal auth) */ 50206b73d0SCy Schubert int anon_provisioning; /* doing anonymous (unauthenticated) 51206b73d0SCy Schubert * provisioning */ 52206b73d0SCy Schubert int session_ticket_used; 53206b73d0SCy Schubert int test_outer_tlvs; 54206b73d0SCy Schubert 55206b73d0SCy Schubert u8 key_data[EAP_TEAP_KEY_LEN]; 56206b73d0SCy Schubert u8 *session_id; 57206b73d0SCy Schubert size_t id_len; 58206b73d0SCy Schubert u8 emsk[EAP_EMSK_LEN]; 59206b73d0SCy Schubert int success; 60206b73d0SCy Schubert 61206b73d0SCy Schubert struct eap_teap_pac *pac; 62206b73d0SCy Schubert struct eap_teap_pac *current_pac; 63206b73d0SCy Schubert size_t max_pac_list_len; 64206b73d0SCy Schubert int use_pac_binary_format; 65206b73d0SCy Schubert 66206b73d0SCy Schubert u8 simck_msk[EAP_TEAP_SIMCK_LEN]; 67206b73d0SCy Schubert u8 simck_emsk[EAP_TEAP_SIMCK_LEN]; 68206b73d0SCy Schubert int simck_idx; 69206b73d0SCy Schubert int cmk_emsk_available; 70206b73d0SCy Schubert 71206b73d0SCy Schubert struct wpabuf *pending_phase2_req; 72206b73d0SCy Schubert struct wpabuf *pending_resp; 73206b73d0SCy Schubert struct wpabuf *server_outer_tlvs; 74206b73d0SCy Schubert struct wpabuf *peer_outer_tlvs; 75206b73d0SCy Schubert }; 76206b73d0SCy Schubert 77206b73d0SCy Schubert 78206b73d0SCy Schubert static int eap_teap_session_ticket_cb(void *ctx, const u8 *ticket, size_t len, 79206b73d0SCy Schubert const u8 *client_random, 80206b73d0SCy Schubert const u8 *server_random, 81206b73d0SCy Schubert u8 *master_secret) 82206b73d0SCy Schubert { 83206b73d0SCy Schubert struct eap_teap_data *data = ctx; 84206b73d0SCy Schubert 85206b73d0SCy Schubert wpa_printf(MSG_DEBUG, "EAP-TEAP: SessionTicket callback"); 86206b73d0SCy Schubert 87206b73d0SCy Schubert if (!master_secret) { 88206b73d0SCy Schubert wpa_printf(MSG_DEBUG, 89206b73d0SCy Schubert "EAP-TEAP: SessionTicket failed - fall back to full TLS handshake"); 90206b73d0SCy Schubert data->session_ticket_used = 0; 91206b73d0SCy Schubert if (data->provisioning_allowed) { 92206b73d0SCy Schubert wpa_printf(MSG_DEBUG, 93206b73d0SCy Schubert "EAP-TEAP: Try to provision a new PAC-Key"); 94206b73d0SCy Schubert data->provisioning = 1; 95206b73d0SCy Schubert data->current_pac = NULL; 96206b73d0SCy Schubert } 97206b73d0SCy Schubert return 0; 98206b73d0SCy Schubert } 99206b73d0SCy Schubert 100206b73d0SCy Schubert wpa_hexdump(MSG_DEBUG, "EAP-TEAP: SessionTicket", ticket, len); 101206b73d0SCy Schubert 102206b73d0SCy Schubert if (!data->current_pac) { 103206b73d0SCy Schubert wpa_printf(MSG_DEBUG, 104206b73d0SCy Schubert "EAP-TEAP: No PAC-Key available for using SessionTicket"); 105206b73d0SCy Schubert data->session_ticket_used = 0; 106206b73d0SCy Schubert return 0; 107206b73d0SCy Schubert } 108206b73d0SCy Schubert 109206b73d0SCy Schubert /* EAP-TEAP uses PAC-Key as the TLS master_secret */ 110206b73d0SCy Schubert os_memcpy(master_secret, data->current_pac->pac_key, 111206b73d0SCy Schubert EAP_TEAP_PAC_KEY_LEN); 112206b73d0SCy Schubert 113206b73d0SCy Schubert data->session_ticket_used = 1; 114206b73d0SCy Schubert 115206b73d0SCy Schubert return 1; 116206b73d0SCy Schubert } 117206b73d0SCy Schubert 118206b73d0SCy Schubert 119206b73d0SCy Schubert static void eap_teap_parse_phase1(struct eap_teap_data *data, 120206b73d0SCy Schubert const char *phase1) 121206b73d0SCy Schubert { 122206b73d0SCy Schubert const char *pos; 123206b73d0SCy Schubert 124206b73d0SCy Schubert pos = os_strstr(phase1, "teap_provisioning="); 125206b73d0SCy Schubert if (pos) { 126206b73d0SCy Schubert data->provisioning_allowed = atoi(pos + 18); 127206b73d0SCy Schubert wpa_printf(MSG_DEBUG, 128206b73d0SCy Schubert "EAP-TEAP: Automatic PAC provisioning mode: %d", 129206b73d0SCy Schubert data->provisioning_allowed); 130206b73d0SCy Schubert } 131206b73d0SCy Schubert 132206b73d0SCy Schubert pos = os_strstr(phase1, "teap_max_pac_list_len="); 133206b73d0SCy Schubert if (pos) { 134206b73d0SCy Schubert data->max_pac_list_len = atoi(pos + 22); 135206b73d0SCy Schubert if (data->max_pac_list_len == 0) 136206b73d0SCy Schubert data->max_pac_list_len = 1; 137206b73d0SCy Schubert wpa_printf(MSG_DEBUG, "EAP-TEAP: Maximum PAC list length: %lu", 138206b73d0SCy Schubert (unsigned long) data->max_pac_list_len); 139206b73d0SCy Schubert } 140206b73d0SCy Schubert 141206b73d0SCy Schubert if (os_strstr(phase1, "teap_pac_format=binary")) { 142206b73d0SCy Schubert data->use_pac_binary_format = 1; 143206b73d0SCy Schubert wpa_printf(MSG_DEBUG, 144206b73d0SCy Schubert "EAP-TEAP: Using binary format for PAC list"); 145206b73d0SCy Schubert } 146206b73d0SCy Schubert 147206b73d0SCy Schubert #ifdef CONFIG_TESTING_OPTIONS 148206b73d0SCy Schubert if (os_strstr(phase1, "teap_test_outer_tlvs=1")) 149206b73d0SCy Schubert data->test_outer_tlvs = 1; 150206b73d0SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */ 151206b73d0SCy Schubert } 152206b73d0SCy Schubert 153206b73d0SCy Schubert 154206b73d0SCy Schubert static void * eap_teap_init(struct eap_sm *sm) 155206b73d0SCy Schubert { 156206b73d0SCy Schubert struct eap_teap_data *data; 157206b73d0SCy Schubert struct eap_peer_config *config = eap_get_config(sm); 158206b73d0SCy Schubert 159206b73d0SCy Schubert if (!config) 160206b73d0SCy Schubert return NULL; 161206b73d0SCy Schubert 162206b73d0SCy Schubert data = os_zalloc(sizeof(*data)); 163206b73d0SCy Schubert if (!data) 164206b73d0SCy Schubert return NULL; 165206b73d0SCy Schubert data->teap_version = EAP_TEAP_VERSION; 166206b73d0SCy Schubert data->max_pac_list_len = 10; 167206b73d0SCy Schubert 168206b73d0SCy Schubert if (config->phase1) 169206b73d0SCy Schubert eap_teap_parse_phase1(data, config->phase1); 170206b73d0SCy Schubert 171206b73d0SCy Schubert if ((data->provisioning_allowed & EAP_TEAP_PROV_AUTH) && 172c1d255d3SCy Schubert !config->cert.ca_cert && !config->cert.ca_path) { 173206b73d0SCy Schubert /* Prevent PAC provisioning without mutual authentication 174206b73d0SCy Schubert * (either by validating server certificate or by suitable 175206b73d0SCy Schubert * inner EAP method). */ 176206b73d0SCy Schubert wpa_printf(MSG_INFO, 177206b73d0SCy Schubert "EAP-TEAP: Disable authenticated provisioning due to no ca_cert/ca_path"); 178206b73d0SCy Schubert data->provisioning_allowed &= ~EAP_TEAP_PROV_AUTH; 179206b73d0SCy Schubert } 180206b73d0SCy Schubert 181206b73d0SCy Schubert if (eap_peer_select_phase2_methods(config, "auth=", 182206b73d0SCy Schubert &data->phase2_types, 183c1d255d3SCy Schubert &data->num_phase2_types, 0) < 0) { 184206b73d0SCy Schubert eap_teap_deinit(sm, data); 185206b73d0SCy Schubert return NULL; 186206b73d0SCy Schubert } 187206b73d0SCy Schubert 188206b73d0SCy Schubert data->phase2_type.vendor = EAP_VENDOR_IETF; 189206b73d0SCy Schubert data->phase2_type.method = EAP_TYPE_NONE; 190206b73d0SCy Schubert 191206b73d0SCy Schubert config->teap_anon_dh = !!(data->provisioning_allowed & 192206b73d0SCy Schubert EAP_TEAP_PROV_UNAUTH); 193206b73d0SCy Schubert if (eap_peer_tls_ssl_init(sm, &data->ssl, config, EAP_TYPE_TEAP)) { 194206b73d0SCy Schubert wpa_printf(MSG_INFO, "EAP-TEAP: Failed to initialize SSL"); 195206b73d0SCy Schubert eap_teap_deinit(sm, data); 196206b73d0SCy Schubert return NULL; 197206b73d0SCy Schubert } 198206b73d0SCy Schubert 199206b73d0SCy Schubert if (tls_connection_set_session_ticket_cb(sm->ssl_ctx, data->ssl.conn, 200206b73d0SCy Schubert eap_teap_session_ticket_cb, 201206b73d0SCy Schubert data) < 0) { 202206b73d0SCy Schubert wpa_printf(MSG_INFO, 203206b73d0SCy Schubert "EAP-TEAP: Failed to set SessionTicket callback"); 204206b73d0SCy Schubert eap_teap_deinit(sm, data); 205206b73d0SCy Schubert return NULL; 206206b73d0SCy Schubert } 207206b73d0SCy Schubert 208206b73d0SCy Schubert if (!config->pac_file) { 209206b73d0SCy Schubert wpa_printf(MSG_INFO, "EAP-TEAP: No PAC file configured"); 210206b73d0SCy Schubert eap_teap_deinit(sm, data); 211206b73d0SCy Schubert return NULL; 212206b73d0SCy Schubert } 213206b73d0SCy Schubert 214206b73d0SCy Schubert if (data->use_pac_binary_format && 215206b73d0SCy Schubert eap_teap_load_pac_bin(sm, &data->pac, config->pac_file) < 0) { 216206b73d0SCy Schubert wpa_printf(MSG_INFO, "EAP-TEAP: Failed to load PAC file"); 217206b73d0SCy Schubert eap_teap_deinit(sm, data); 218206b73d0SCy Schubert return NULL; 219206b73d0SCy Schubert } 220206b73d0SCy Schubert 221206b73d0SCy Schubert if (!data->use_pac_binary_format && 222206b73d0SCy Schubert eap_teap_load_pac(sm, &data->pac, config->pac_file) < 0) { 223206b73d0SCy Schubert wpa_printf(MSG_INFO, "EAP-TEAP: Failed to load PAC file"); 224206b73d0SCy Schubert eap_teap_deinit(sm, data); 225206b73d0SCy Schubert return NULL; 226206b73d0SCy Schubert } 227206b73d0SCy Schubert eap_teap_pac_list_truncate(data->pac, data->max_pac_list_len); 228206b73d0SCy Schubert 229206b73d0SCy Schubert return data; 230206b73d0SCy Schubert } 231206b73d0SCy Schubert 232206b73d0SCy Schubert 233206b73d0SCy Schubert static void eap_teap_clear(struct eap_teap_data *data) 234206b73d0SCy Schubert { 235206b73d0SCy Schubert forced_memzero(data->key_data, EAP_TEAP_KEY_LEN); 236206b73d0SCy Schubert forced_memzero(data->emsk, EAP_EMSK_LEN); 237206b73d0SCy Schubert os_free(data->session_id); 238206b73d0SCy Schubert data->session_id = NULL; 239206b73d0SCy Schubert wpabuf_free(data->pending_phase2_req); 240206b73d0SCy Schubert data->pending_phase2_req = NULL; 241206b73d0SCy Schubert wpabuf_free(data->pending_resp); 242206b73d0SCy Schubert data->pending_resp = NULL; 243206b73d0SCy Schubert wpabuf_free(data->server_outer_tlvs); 244206b73d0SCy Schubert data->server_outer_tlvs = NULL; 245206b73d0SCy Schubert wpabuf_free(data->peer_outer_tlvs); 246206b73d0SCy Schubert data->peer_outer_tlvs = NULL; 247206b73d0SCy Schubert forced_memzero(data->simck_msk, EAP_TEAP_SIMCK_LEN); 248206b73d0SCy Schubert forced_memzero(data->simck_emsk, EAP_TEAP_SIMCK_LEN); 249206b73d0SCy Schubert } 250206b73d0SCy Schubert 251206b73d0SCy Schubert 252206b73d0SCy Schubert static void eap_teap_deinit(struct eap_sm *sm, void *priv) 253206b73d0SCy Schubert { 254206b73d0SCy Schubert struct eap_teap_data *data = priv; 255206b73d0SCy Schubert struct eap_teap_pac *pac, *prev; 256206b73d0SCy Schubert 257206b73d0SCy Schubert if (!data) 258206b73d0SCy Schubert return; 259206b73d0SCy Schubert if (data->phase2_priv && data->phase2_method) 260206b73d0SCy Schubert data->phase2_method->deinit(sm, data->phase2_priv); 261206b73d0SCy Schubert eap_teap_clear(data); 262206b73d0SCy Schubert os_free(data->phase2_types); 263206b73d0SCy Schubert eap_peer_tls_ssl_deinit(sm, &data->ssl); 264206b73d0SCy Schubert 265206b73d0SCy Schubert pac = data->pac; 266206b73d0SCy Schubert prev = NULL; 267206b73d0SCy Schubert while (pac) { 268206b73d0SCy Schubert prev = pac; 269206b73d0SCy Schubert pac = pac->next; 270206b73d0SCy Schubert eap_teap_free_pac(prev); 271206b73d0SCy Schubert } 272206b73d0SCy Schubert 273206b73d0SCy Schubert os_free(data); 274206b73d0SCy Schubert } 275206b73d0SCy Schubert 276206b73d0SCy Schubert 277206b73d0SCy Schubert static int eap_teap_derive_msk(struct eap_teap_data *data) 278206b73d0SCy Schubert { 279206b73d0SCy Schubert /* FIX: RFC 7170 does not describe whether MSK or EMSK based S-IMCK[j] 280206b73d0SCy Schubert * is used in this derivation */ 281c1d255d3SCy Schubert if (eap_teap_derive_eap_msk(data->tls_cs, data->simck_msk, 282c1d255d3SCy Schubert data->key_data) < 0 || 283c1d255d3SCy Schubert eap_teap_derive_eap_emsk(data->tls_cs, data->simck_msk, 284c1d255d3SCy Schubert data->emsk) < 0) 285206b73d0SCy Schubert return -1; 286206b73d0SCy Schubert data->success = 1; 287206b73d0SCy Schubert return 0; 288206b73d0SCy Schubert } 289206b73d0SCy Schubert 290206b73d0SCy Schubert 291206b73d0SCy Schubert static int eap_teap_derive_key_auth(struct eap_sm *sm, 292206b73d0SCy Schubert struct eap_teap_data *data) 293206b73d0SCy Schubert { 294206b73d0SCy Schubert int res; 295206b73d0SCy Schubert 296206b73d0SCy Schubert /* RFC 7170, Section 5.1 */ 297206b73d0SCy Schubert res = tls_connection_export_key(sm->ssl_ctx, data->ssl.conn, 298206b73d0SCy Schubert TEAP_TLS_EXPORTER_LABEL_SKS, NULL, 0, 299206b73d0SCy Schubert data->simck_msk, EAP_TEAP_SIMCK_LEN); 300206b73d0SCy Schubert if (res) 301206b73d0SCy Schubert return res; 302206b73d0SCy Schubert wpa_hexdump_key(MSG_DEBUG, 303206b73d0SCy Schubert "EAP-TEAP: session_key_seed (S-IMCK[0])", 304206b73d0SCy Schubert data->simck_msk, EAP_TEAP_SIMCK_LEN); 305206b73d0SCy Schubert os_memcpy(data->simck_emsk, data->simck_msk, EAP_TEAP_SIMCK_LEN); 306206b73d0SCy Schubert data->simck_idx = 0; 307206b73d0SCy Schubert return 0; 308206b73d0SCy Schubert } 309206b73d0SCy Schubert 310206b73d0SCy Schubert 311206b73d0SCy Schubert static int eap_teap_init_phase2_method(struct eap_sm *sm, 312206b73d0SCy Schubert struct eap_teap_data *data) 313206b73d0SCy Schubert { 314206b73d0SCy Schubert data->inner_method_done = 0; 315c1d255d3SCy Schubert data->iresult_verified = 0; 316206b73d0SCy Schubert data->phase2_method = 317206b73d0SCy Schubert eap_peer_get_eap_method(data->phase2_type.vendor, 318206b73d0SCy Schubert data->phase2_type.method); 319206b73d0SCy Schubert if (!data->phase2_method) 320206b73d0SCy Schubert return -1; 321206b73d0SCy Schubert 322*a90b9d01SCy Schubert /* While RFC 7170 does not describe this, EAP-TEAP has been deployed 323*a90b9d01SCy Schubert * with implementations that use the EAP-FAST-MSCHAPv2, instead of the 324*a90b9d01SCy Schubert * EAP-MSCHAPv2, way of deriving the MSK for IMSK. Use that design here 325*a90b9d01SCy Schubert * to interoperate. 326*a90b9d01SCy Schubert */ 327*a90b9d01SCy Schubert sm->eap_fast_mschapv2 = true; 328*a90b9d01SCy Schubert 329206b73d0SCy Schubert sm->init_phase2 = 1; 330206b73d0SCy Schubert data->phase2_priv = data->phase2_method->init(sm); 331206b73d0SCy Schubert sm->init_phase2 = 0; 332206b73d0SCy Schubert 333206b73d0SCy Schubert return data->phase2_priv == NULL ? -1 : 0; 334206b73d0SCy Schubert } 335206b73d0SCy Schubert 336206b73d0SCy Schubert 337c1d255d3SCy Schubert static int eap_teap_select_phase2_method(struct eap_teap_data *data, 338c1d255d3SCy Schubert int vendor, enum eap_type type) 339206b73d0SCy Schubert { 340206b73d0SCy Schubert size_t i; 341206b73d0SCy Schubert 342206b73d0SCy Schubert /* TODO: TNC with anonymous provisioning; need to require both 343206b73d0SCy Schubert * completed inner EAP authentication (EAP-pwd or EAP-EKE) and TNC */ 344206b73d0SCy Schubert 345206b73d0SCy Schubert if (data->anon_provisioning && 346c1d255d3SCy Schubert !eap_teap_allowed_anon_prov_phase2_method(vendor, type)) { 347206b73d0SCy Schubert wpa_printf(MSG_INFO, 348c1d255d3SCy Schubert "EAP-TEAP: EAP type %u:%u not allowed during unauthenticated provisioning", 349c1d255d3SCy Schubert vendor, type); 350206b73d0SCy Schubert return -1; 351206b73d0SCy Schubert } 352206b73d0SCy Schubert 353206b73d0SCy Schubert #ifdef EAP_TNC 354c1d255d3SCy Schubert if (vendor == EAP_VENDOR_IETF && type == EAP_TYPE_TNC) { 355206b73d0SCy Schubert data->phase2_type.vendor = EAP_VENDOR_IETF; 356206b73d0SCy Schubert data->phase2_type.method = EAP_TYPE_TNC; 357206b73d0SCy Schubert wpa_printf(MSG_DEBUG, 358206b73d0SCy Schubert "EAP-TEAP: Selected Phase 2 EAP vendor %d method %d for TNC", 359206b73d0SCy Schubert data->phase2_type.vendor, 360206b73d0SCy Schubert data->phase2_type.method); 361206b73d0SCy Schubert return 0; 362206b73d0SCy Schubert } 363206b73d0SCy Schubert #endif /* EAP_TNC */ 364206b73d0SCy Schubert 365206b73d0SCy Schubert for (i = 0; i < data->num_phase2_types; i++) { 366c1d255d3SCy Schubert if (data->phase2_types[i].vendor != vendor || 367206b73d0SCy Schubert data->phase2_types[i].method != type) 368206b73d0SCy Schubert continue; 369206b73d0SCy Schubert 370206b73d0SCy Schubert data->phase2_type.vendor = data->phase2_types[i].vendor; 371206b73d0SCy Schubert data->phase2_type.method = data->phase2_types[i].method; 372206b73d0SCy Schubert wpa_printf(MSG_DEBUG, 373206b73d0SCy Schubert "EAP-TEAP: Selected Phase 2 EAP vendor %d method %d", 374206b73d0SCy Schubert data->phase2_type.vendor, 375206b73d0SCy Schubert data->phase2_type.method); 376206b73d0SCy Schubert break; 377206b73d0SCy Schubert } 378206b73d0SCy Schubert 379c1d255d3SCy Schubert if (vendor != data->phase2_type.vendor || 380c1d255d3SCy Schubert type != data->phase2_type.method || 381c1d255d3SCy Schubert (vendor == EAP_VENDOR_IETF && type == EAP_TYPE_NONE)) 382206b73d0SCy Schubert return -1; 383206b73d0SCy Schubert 384206b73d0SCy Schubert return 0; 385206b73d0SCy Schubert } 386206b73d0SCy Schubert 387206b73d0SCy Schubert 388c1d255d3SCy Schubert static void eap_teap_deinit_inner_eap(struct eap_sm *sm, 389c1d255d3SCy Schubert struct eap_teap_data *data) 390c1d255d3SCy Schubert { 391c1d255d3SCy Schubert if (!data->phase2_priv || !data->phase2_method) 392c1d255d3SCy Schubert return; 393c1d255d3SCy Schubert 394c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, 395c1d255d3SCy Schubert "EAP-TEAP: Phase 2 EAP sequence - deinitialize previous method"); 396c1d255d3SCy Schubert data->phase2_method->deinit(sm, data->phase2_priv); 397c1d255d3SCy Schubert data->phase2_method = NULL; 398c1d255d3SCy Schubert data->phase2_priv = NULL; 399c1d255d3SCy Schubert data->phase2_type.vendor = EAP_VENDOR_IETF; 400c1d255d3SCy Schubert data->phase2_type.method = EAP_TYPE_NONE; 401c1d255d3SCy Schubert } 402c1d255d3SCy Schubert 403c1d255d3SCy Schubert 404206b73d0SCy Schubert static int eap_teap_phase2_request(struct eap_sm *sm, 405206b73d0SCy Schubert struct eap_teap_data *data, 406206b73d0SCy Schubert struct eap_method_ret *ret, 407206b73d0SCy Schubert struct eap_hdr *hdr, 408206b73d0SCy Schubert struct wpabuf **resp) 409206b73d0SCy Schubert { 410206b73d0SCy Schubert size_t len = be_to_host16(hdr->length); 411206b73d0SCy Schubert u8 *pos; 412206b73d0SCy Schubert struct eap_method_ret iret; 413206b73d0SCy Schubert struct eap_peer_config *config = eap_get_config(sm); 414206b73d0SCy Schubert struct wpabuf msg; 415c1d255d3SCy Schubert int vendor = EAP_VENDOR_IETF; 416c1d255d3SCy Schubert enum eap_type method; 417206b73d0SCy Schubert 418206b73d0SCy Schubert if (len <= sizeof(struct eap_hdr)) { 419206b73d0SCy Schubert wpa_printf(MSG_INFO, 420206b73d0SCy Schubert "EAP-TEAP: too short Phase 2 request (len=%lu)", 421206b73d0SCy Schubert (unsigned long) len); 422206b73d0SCy Schubert return -1; 423206b73d0SCy Schubert } 424206b73d0SCy Schubert pos = (u8 *) (hdr + 1); 425c1d255d3SCy Schubert method = *pos; 426c1d255d3SCy Schubert if (method == EAP_TYPE_EXPANDED) { 427c1d255d3SCy Schubert if (len < sizeof(struct eap_hdr) + 8) { 428c1d255d3SCy Schubert wpa_printf(MSG_INFO, 429c1d255d3SCy Schubert "EAP-TEAP: Too short Phase 2 request (expanded header) (len=%lu)", 430c1d255d3SCy Schubert (unsigned long) len); 431c1d255d3SCy Schubert return -1; 432c1d255d3SCy Schubert } 433c1d255d3SCy Schubert vendor = WPA_GET_BE24(pos + 1); 434c1d255d3SCy Schubert method = WPA_GET_BE32(pos + 4); 435c1d255d3SCy Schubert } 436c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "EAP-TEAP: Phase 2 Request: type=%u:%u", 437c1d255d3SCy Schubert vendor, method); 438c1d255d3SCy Schubert if (vendor == EAP_VENDOR_IETF && method == EAP_TYPE_IDENTITY) { 439c1d255d3SCy Schubert eap_teap_deinit_inner_eap(sm, data); 440206b73d0SCy Schubert *resp = eap_sm_buildIdentity(sm, hdr->identifier, 1); 441206b73d0SCy Schubert return 0; 442206b73d0SCy Schubert } 443206b73d0SCy Schubert 444206b73d0SCy Schubert if (data->phase2_priv && data->phase2_method && 445c1d255d3SCy Schubert (vendor != data->phase2_type.vendor || 446c1d255d3SCy Schubert method != data->phase2_type.method)) 447c1d255d3SCy Schubert eap_teap_deinit_inner_eap(sm, data); 448206b73d0SCy Schubert 449206b73d0SCy Schubert if (data->phase2_type.vendor == EAP_VENDOR_IETF && 450206b73d0SCy Schubert data->phase2_type.method == EAP_TYPE_NONE && 451c1d255d3SCy Schubert eap_teap_select_phase2_method(data, vendor, method) < 0) { 452206b73d0SCy Schubert if (eap_peer_tls_phase2_nak(data->phase2_types, 453206b73d0SCy Schubert data->num_phase2_types, 454206b73d0SCy Schubert hdr, resp)) 455206b73d0SCy Schubert return -1; 456206b73d0SCy Schubert return 0; 457206b73d0SCy Schubert } 458206b73d0SCy Schubert 459206b73d0SCy Schubert if ((!data->phase2_priv && eap_teap_init_phase2_method(sm, data) < 0) || 460206b73d0SCy Schubert !data->phase2_method) { 461206b73d0SCy Schubert wpa_printf(MSG_INFO, 462c1d255d3SCy Schubert "EAP-TEAP: Failed to initialize Phase 2 EAP method %u:%u", 463c1d255d3SCy Schubert vendor, method); 464206b73d0SCy Schubert ret->methodState = METHOD_DONE; 465206b73d0SCy Schubert ret->decision = DECISION_FAIL; 466206b73d0SCy Schubert return -1; 467206b73d0SCy Schubert } 468206b73d0SCy Schubert 469206b73d0SCy Schubert os_memset(&iret, 0, sizeof(iret)); 470206b73d0SCy Schubert wpabuf_set(&msg, hdr, len); 471206b73d0SCy Schubert *resp = data->phase2_method->process(sm, data->phase2_priv, &iret, 472206b73d0SCy Schubert &msg); 473206b73d0SCy Schubert if (iret.methodState == METHOD_DONE) 474206b73d0SCy Schubert data->inner_method_done = 1; 475206b73d0SCy Schubert if (!(*resp) || 476206b73d0SCy Schubert (iret.methodState == METHOD_DONE && 477206b73d0SCy Schubert iret.decision == DECISION_FAIL)) { 478c1d255d3SCy Schubert /* Wait for protected indication of failure */ 479c1d255d3SCy Schubert ret->methodState = METHOD_MAY_CONT; 480206b73d0SCy Schubert ret->decision = DECISION_FAIL; 481206b73d0SCy Schubert } else if ((iret.methodState == METHOD_DONE || 482206b73d0SCy Schubert iret.methodState == METHOD_MAY_CONT) && 483206b73d0SCy Schubert (iret.decision == DECISION_UNCOND_SUCC || 484206b73d0SCy Schubert iret.decision == DECISION_COND_SUCC)) { 485206b73d0SCy Schubert data->phase2_success = 1; 486206b73d0SCy Schubert } 487206b73d0SCy Schubert 488206b73d0SCy Schubert if (!(*resp) && config && 489206b73d0SCy Schubert (config->pending_req_identity || config->pending_req_password || 490206b73d0SCy Schubert config->pending_req_otp || config->pending_req_new_password || 491206b73d0SCy Schubert config->pending_req_sim)) { 492206b73d0SCy Schubert wpabuf_free(data->pending_phase2_req); 493206b73d0SCy Schubert data->pending_phase2_req = wpabuf_alloc_copy(hdr, len); 494206b73d0SCy Schubert } else if (!(*resp)) 495206b73d0SCy Schubert return -1; 496206b73d0SCy Schubert 497206b73d0SCy Schubert return 0; 498206b73d0SCy Schubert } 499206b73d0SCy Schubert 500206b73d0SCy Schubert 501206b73d0SCy Schubert static struct wpabuf * eap_teap_tlv_nak(int vendor_id, int tlv_type) 502206b73d0SCy Schubert { 503206b73d0SCy Schubert struct wpabuf *buf; 504206b73d0SCy Schubert struct teap_tlv_nak *nak; 505206b73d0SCy Schubert 506206b73d0SCy Schubert wpa_printf(MSG_DEBUG, 507206b73d0SCy Schubert "EAP-TEAP: Add NAK TLV (Vendor-Id %u NAK-Type %u)", 508206b73d0SCy Schubert vendor_id, tlv_type); 509206b73d0SCy Schubert buf = wpabuf_alloc(sizeof(*nak)); 510206b73d0SCy Schubert if (!buf) 511206b73d0SCy Schubert return NULL; 512206b73d0SCy Schubert nak = wpabuf_put(buf, sizeof(*nak)); 513206b73d0SCy Schubert nak->tlv_type = host_to_be16(TEAP_TLV_MANDATORY | TEAP_TLV_NAK); 514206b73d0SCy Schubert nak->length = host_to_be16(6); 515206b73d0SCy Schubert nak->vendor_id = host_to_be32(vendor_id); 516206b73d0SCy Schubert nak->nak_type = host_to_be16(tlv_type); 517206b73d0SCy Schubert return buf; 518206b73d0SCy Schubert } 519206b73d0SCy Schubert 520206b73d0SCy Schubert 521206b73d0SCy Schubert static struct wpabuf * eap_teap_tlv_pac_ack(void) 522206b73d0SCy Schubert { 523206b73d0SCy Schubert struct wpabuf *buf; 524206b73d0SCy Schubert struct teap_tlv_result *res; 525206b73d0SCy Schubert struct teap_tlv_pac_ack *ack; 526206b73d0SCy Schubert 527206b73d0SCy Schubert buf = wpabuf_alloc(sizeof(*res) + sizeof(*ack)); 528206b73d0SCy Schubert if (!buf) 529206b73d0SCy Schubert return NULL; 530206b73d0SCy Schubert 531206b73d0SCy Schubert wpa_printf(MSG_DEBUG, "EAP-TEAP: Add PAC TLV (ack)"); 532206b73d0SCy Schubert ack = wpabuf_put(buf, sizeof(*ack)); 533206b73d0SCy Schubert ack->tlv_type = host_to_be16(TEAP_TLV_PAC | TEAP_TLV_MANDATORY); 534206b73d0SCy Schubert ack->length = host_to_be16(sizeof(*ack) - sizeof(struct teap_tlv_hdr)); 535206b73d0SCy Schubert ack->pac_type = host_to_be16(PAC_TYPE_PAC_ACKNOWLEDGEMENT); 536206b73d0SCy Schubert ack->pac_len = host_to_be16(2); 537206b73d0SCy Schubert ack->result = host_to_be16(TEAP_STATUS_SUCCESS); 538206b73d0SCy Schubert 539206b73d0SCy Schubert return buf; 540206b73d0SCy Schubert } 541206b73d0SCy Schubert 542206b73d0SCy Schubert 543c1d255d3SCy Schubert static struct wpabuf * eap_teap_add_identity_type(struct eap_sm *sm, 544c1d255d3SCy Schubert struct wpabuf *msg) 545c1d255d3SCy Schubert { 546c1d255d3SCy Schubert struct wpabuf *tlv; 547c1d255d3SCy Schubert 548c1d255d3SCy Schubert tlv = eap_teap_tlv_identity_type(sm->use_machine_cred ? 549c1d255d3SCy Schubert TEAP_IDENTITY_TYPE_MACHINE : 550c1d255d3SCy Schubert TEAP_IDENTITY_TYPE_USER); 551c1d255d3SCy Schubert return wpabuf_concat(msg, tlv); 552c1d255d3SCy Schubert } 553c1d255d3SCy Schubert 554c1d255d3SCy Schubert 555206b73d0SCy Schubert static struct wpabuf * eap_teap_process_eap_payload_tlv( 556206b73d0SCy Schubert struct eap_sm *sm, struct eap_teap_data *data, 557206b73d0SCy Schubert struct eap_method_ret *ret, 558c1d255d3SCy Schubert u8 *eap_payload_tlv, size_t eap_payload_tlv_len, 559c1d255d3SCy Schubert enum teap_identity_types req_id_type) 560206b73d0SCy Schubert { 561206b73d0SCy Schubert struct eap_hdr *hdr; 562206b73d0SCy Schubert struct wpabuf *resp = NULL; 563206b73d0SCy Schubert 564206b73d0SCy Schubert if (eap_payload_tlv_len < sizeof(*hdr)) { 565206b73d0SCy Schubert wpa_printf(MSG_DEBUG, 566206b73d0SCy Schubert "EAP-TEAP: too short EAP Payload TLV (len=%lu)", 567206b73d0SCy Schubert (unsigned long) eap_payload_tlv_len); 568206b73d0SCy Schubert return NULL; 569206b73d0SCy Schubert } 570206b73d0SCy Schubert 571206b73d0SCy Schubert hdr = (struct eap_hdr *) eap_payload_tlv; 572206b73d0SCy Schubert if (be_to_host16(hdr->length) > eap_payload_tlv_len) { 573206b73d0SCy Schubert wpa_printf(MSG_DEBUG, 574206b73d0SCy Schubert "EAP-TEAP: EAP packet overflow in EAP Payload TLV"); 575206b73d0SCy Schubert return NULL; 576206b73d0SCy Schubert } 577206b73d0SCy Schubert 578206b73d0SCy Schubert if (hdr->code != EAP_CODE_REQUEST) { 579206b73d0SCy Schubert wpa_printf(MSG_INFO, 580206b73d0SCy Schubert "EAP-TEAP: Unexpected code=%d in Phase 2 EAP header", 581206b73d0SCy Schubert hdr->code); 582206b73d0SCy Schubert return NULL; 583206b73d0SCy Schubert } 584206b73d0SCy Schubert 585206b73d0SCy Schubert if (eap_teap_phase2_request(sm, data, ret, hdr, &resp)) { 586206b73d0SCy Schubert wpa_printf(MSG_INFO, 587206b73d0SCy Schubert "EAP-TEAP: Phase 2 Request processing failed"); 588206b73d0SCy Schubert return NULL; 589206b73d0SCy Schubert } 590206b73d0SCy Schubert 591c1d255d3SCy Schubert resp = eap_teap_tlv_eap_payload(resp); 592c1d255d3SCy Schubert if (req_id_type) 593c1d255d3SCy Schubert resp = eap_teap_add_identity_type(sm, resp); 594c1d255d3SCy Schubert 595c1d255d3SCy Schubert return resp; 596206b73d0SCy Schubert } 597206b73d0SCy Schubert 598206b73d0SCy Schubert 599206b73d0SCy Schubert static struct wpabuf * eap_teap_process_basic_auth_req( 600206b73d0SCy Schubert struct eap_sm *sm, struct eap_teap_data *data, 601c1d255d3SCy Schubert u8 *basic_auth_req, size_t basic_auth_req_len, 602c1d255d3SCy Schubert enum teap_identity_types req_id_type) 603206b73d0SCy Schubert { 604206b73d0SCy Schubert const u8 *identity, *password; 605206b73d0SCy Schubert size_t identity_len, password_len, plen; 606206b73d0SCy Schubert struct wpabuf *resp; 607206b73d0SCy Schubert 608206b73d0SCy Schubert wpa_hexdump_ascii(MSG_DEBUG, "EAP-TEAP: Basic-Password-Auth-Req prompt", 609206b73d0SCy Schubert basic_auth_req, basic_auth_req_len); 610206b73d0SCy Schubert /* TODO: send over control interface */ 611206b73d0SCy Schubert 612206b73d0SCy Schubert identity = eap_get_config_identity(sm, &identity_len); 613206b73d0SCy Schubert password = eap_get_config_password(sm, &password_len); 614206b73d0SCy Schubert if (!identity || !password || 615206b73d0SCy Schubert identity_len > 255 || password_len > 255) { 616206b73d0SCy Schubert wpa_printf(MSG_DEBUG, 617206b73d0SCy Schubert "EAP-TEAP: No username/password suitable for Basic-Password-Auth"); 618206b73d0SCy Schubert return eap_teap_tlv_nak(0, TEAP_TLV_BASIC_PASSWORD_AUTH_REQ); 619206b73d0SCy Schubert } 620206b73d0SCy Schubert 621206b73d0SCy Schubert plen = 1 + identity_len + 1 + password_len; 622206b73d0SCy Schubert resp = wpabuf_alloc(sizeof(struct teap_tlv_hdr) + plen); 623206b73d0SCy Schubert if (!resp) 624206b73d0SCy Schubert return NULL; 625206b73d0SCy Schubert eap_teap_put_tlv_hdr(resp, TEAP_TLV_BASIC_PASSWORD_AUTH_RESP, plen); 626206b73d0SCy Schubert wpabuf_put_u8(resp, identity_len); 627206b73d0SCy Schubert wpabuf_put_data(resp, identity, identity_len); 628206b73d0SCy Schubert wpabuf_put_u8(resp, password_len); 629206b73d0SCy Schubert wpabuf_put_data(resp, password, password_len); 630206b73d0SCy Schubert wpa_hexdump_buf_key(MSG_DEBUG, "EAP-TEAP: Basic-Password-Auth-Resp", 631206b73d0SCy Schubert resp); 632c1d255d3SCy Schubert if (req_id_type) 633c1d255d3SCy Schubert resp = eap_teap_add_identity_type(sm, resp); 634206b73d0SCy Schubert 635206b73d0SCy Schubert /* Assume this succeeds so that Result TLV(Success) from the server can 636206b73d0SCy Schubert * be used to terminate TEAP. */ 637206b73d0SCy Schubert data->phase2_success = 1; 638206b73d0SCy Schubert 639206b73d0SCy Schubert return resp; 640206b73d0SCy Schubert } 641206b73d0SCy Schubert 642206b73d0SCy Schubert 643206b73d0SCy Schubert static int 644206b73d0SCy Schubert eap_teap_validate_crypto_binding(struct eap_teap_data *data, 645206b73d0SCy Schubert const struct teap_tlv_crypto_binding *cb) 646206b73d0SCy Schubert { 647206b73d0SCy Schubert u8 flags, subtype; 648206b73d0SCy Schubert 649206b73d0SCy Schubert subtype = cb->subtype & 0x0f; 650206b73d0SCy Schubert flags = cb->subtype >> 4; 651206b73d0SCy Schubert 652206b73d0SCy Schubert wpa_printf(MSG_DEBUG, 653206b73d0SCy Schubert "EAP-TEAP: Crypto-Binding TLV: Version %u Received Version %u Flags %u Sub-Type %u", 654206b73d0SCy Schubert cb->version, cb->received_version, flags, subtype); 655206b73d0SCy Schubert wpa_hexdump(MSG_MSGDUMP, "EAP-TEAP: Nonce", 656206b73d0SCy Schubert cb->nonce, sizeof(cb->nonce)); 657206b73d0SCy Schubert wpa_hexdump(MSG_MSGDUMP, "EAP-TEAP: EMSK Compound MAC", 658206b73d0SCy Schubert cb->emsk_compound_mac, sizeof(cb->emsk_compound_mac)); 659206b73d0SCy Schubert wpa_hexdump(MSG_MSGDUMP, "EAP-TEAP: MSK Compound MAC", 660206b73d0SCy Schubert cb->msk_compound_mac, sizeof(cb->msk_compound_mac)); 661206b73d0SCy Schubert 662206b73d0SCy Schubert if (cb->version != EAP_TEAP_VERSION || 663206b73d0SCy Schubert cb->received_version != data->received_version || 664206b73d0SCy Schubert subtype != TEAP_CRYPTO_BINDING_SUBTYPE_REQUEST || 665206b73d0SCy Schubert flags < 1 || flags > 3) { 666206b73d0SCy Schubert wpa_printf(MSG_INFO, 667206b73d0SCy Schubert "EAP-TEAP: Invalid Version/Flags/Sub-Type in Crypto-Binding TLV: Version %u Received Version %u Flags %u Sub-Type %u", 668206b73d0SCy Schubert cb->version, cb->received_version, flags, subtype); 669206b73d0SCy Schubert return -1; 670206b73d0SCy Schubert } 671206b73d0SCy Schubert 672206b73d0SCy Schubert if (cb->nonce[EAP_TEAP_NONCE_LEN - 1] & 0x01) { 673206b73d0SCy Schubert wpa_printf(MSG_INFO, 674206b73d0SCy Schubert "EAP-TEAP: Invalid Crypto-Binding TLV Nonce in request"); 675206b73d0SCy Schubert return -1; 676206b73d0SCy Schubert } 677206b73d0SCy Schubert 678206b73d0SCy Schubert return 0; 679206b73d0SCy Schubert } 680206b73d0SCy Schubert 681206b73d0SCy Schubert 682206b73d0SCy Schubert static int eap_teap_write_crypto_binding( 683206b73d0SCy Schubert struct eap_teap_data *data, 684206b73d0SCy Schubert struct teap_tlv_crypto_binding *rbind, 685206b73d0SCy Schubert const struct teap_tlv_crypto_binding *cb, 686206b73d0SCy Schubert const u8 *cmk_msk, const u8 *cmk_emsk) 687206b73d0SCy Schubert { 688206b73d0SCy Schubert u8 subtype, flags; 689206b73d0SCy Schubert 690206b73d0SCy Schubert rbind->tlv_type = host_to_be16(TEAP_TLV_MANDATORY | 691206b73d0SCy Schubert TEAP_TLV_CRYPTO_BINDING); 692206b73d0SCy Schubert rbind->length = host_to_be16(sizeof(*rbind) - 693206b73d0SCy Schubert sizeof(struct teap_tlv_hdr)); 694206b73d0SCy Schubert rbind->version = EAP_TEAP_VERSION; 695206b73d0SCy Schubert rbind->received_version = data->received_version; 696206b73d0SCy Schubert /* FIX: RFC 7170 is not clear on which Flags value to use when 697206b73d0SCy Schubert * Crypto-Binding TLV is used with Basic-Password-Auth */ 698206b73d0SCy Schubert flags = cmk_emsk ? TEAP_CRYPTO_BINDING_EMSK_AND_MSK_CMAC : 699206b73d0SCy Schubert TEAP_CRYPTO_BINDING_MSK_CMAC; 700206b73d0SCy Schubert subtype = TEAP_CRYPTO_BINDING_SUBTYPE_RESPONSE; 701206b73d0SCy Schubert rbind->subtype = (flags << 4) | subtype; 702206b73d0SCy Schubert os_memcpy(rbind->nonce, cb->nonce, sizeof(cb->nonce)); 703206b73d0SCy Schubert inc_byte_array(rbind->nonce, sizeof(rbind->nonce)); 704206b73d0SCy Schubert os_memset(rbind->emsk_compound_mac, 0, EAP_TEAP_COMPOUND_MAC_LEN); 705206b73d0SCy Schubert os_memset(rbind->msk_compound_mac, 0, EAP_TEAP_COMPOUND_MAC_LEN); 706206b73d0SCy Schubert 707206b73d0SCy Schubert if (eap_teap_compound_mac(data->tls_cs, rbind, data->server_outer_tlvs, 708206b73d0SCy Schubert data->peer_outer_tlvs, cmk_msk, 709206b73d0SCy Schubert rbind->msk_compound_mac) < 0) 710206b73d0SCy Schubert return -1; 711206b73d0SCy Schubert if (cmk_emsk && 712206b73d0SCy Schubert eap_teap_compound_mac(data->tls_cs, rbind, data->server_outer_tlvs, 713206b73d0SCy Schubert data->peer_outer_tlvs, cmk_emsk, 714206b73d0SCy Schubert rbind->emsk_compound_mac) < 0) 715206b73d0SCy Schubert return -1; 716206b73d0SCy Schubert 717206b73d0SCy Schubert wpa_printf(MSG_DEBUG, 718206b73d0SCy Schubert "EAP-TEAP: Reply Crypto-Binding TLV: Version %u Received Version %u Flags %u SubType %u", 719206b73d0SCy Schubert rbind->version, rbind->received_version, flags, subtype); 720206b73d0SCy Schubert wpa_hexdump(MSG_MSGDUMP, "EAP-TEAP: Nonce", 721206b73d0SCy Schubert rbind->nonce, sizeof(rbind->nonce)); 722206b73d0SCy Schubert wpa_hexdump(MSG_MSGDUMP, "EAP-TEAP: EMSK Compound MAC", 723206b73d0SCy Schubert rbind->emsk_compound_mac, sizeof(rbind->emsk_compound_mac)); 724206b73d0SCy Schubert wpa_hexdump(MSG_MSGDUMP, "EAP-TEAP: MSK Compound MAC", 725206b73d0SCy Schubert rbind->msk_compound_mac, sizeof(rbind->msk_compound_mac)); 726206b73d0SCy Schubert 727206b73d0SCy Schubert return 0; 728206b73d0SCy Schubert } 729206b73d0SCy Schubert 730206b73d0SCy Schubert 731206b73d0SCy Schubert static int eap_teap_get_cmk(struct eap_sm *sm, struct eap_teap_data *data, 732206b73d0SCy Schubert u8 *cmk_msk, u8 *cmk_emsk) 733206b73d0SCy Schubert { 734206b73d0SCy Schubert u8 *msk = NULL, *emsk = NULL; 735206b73d0SCy Schubert size_t msk_len = 0, emsk_len = 0; 736206b73d0SCy Schubert int res; 737206b73d0SCy Schubert 738206b73d0SCy Schubert wpa_printf(MSG_DEBUG, 739206b73d0SCy Schubert "EAP-TEAP: Determining CMK[%d] for Compound MAC calculation", 740206b73d0SCy Schubert data->simck_idx + 1); 741206b73d0SCy Schubert 742206b73d0SCy Schubert if (!data->phase2_method) 743c1d255d3SCy Schubert return eap_teap_derive_cmk_basic_pw_auth(data->tls_cs, 744c1d255d3SCy Schubert data->simck_msk, 745206b73d0SCy Schubert cmk_msk); 746206b73d0SCy Schubert 747206b73d0SCy Schubert if (!data->phase2_method || !data->phase2_priv) { 748206b73d0SCy Schubert wpa_printf(MSG_INFO, "EAP-TEAP: Phase 2 method not available"); 749206b73d0SCy Schubert return -1; 750206b73d0SCy Schubert } 751206b73d0SCy Schubert 752206b73d0SCy Schubert if (data->phase2_method->isKeyAvailable && 753206b73d0SCy Schubert !data->phase2_method->isKeyAvailable(sm, data->phase2_priv)) { 754206b73d0SCy Schubert wpa_printf(MSG_INFO, 755206b73d0SCy Schubert "EAP-TEAP: Phase 2 key material not available"); 756206b73d0SCy Schubert return -1; 757206b73d0SCy Schubert } 758206b73d0SCy Schubert 759206b73d0SCy Schubert if (data->phase2_method->isKeyAvailable && 760206b73d0SCy Schubert data->phase2_method->getKey) { 761206b73d0SCy Schubert msk = data->phase2_method->getKey(sm, data->phase2_priv, 762206b73d0SCy Schubert &msk_len); 763206b73d0SCy Schubert if (!msk) { 764206b73d0SCy Schubert wpa_printf(MSG_INFO, 765206b73d0SCy Schubert "EAP-TEAP: Could not fetch Phase 2 MSK"); 766206b73d0SCy Schubert return -1; 767206b73d0SCy Schubert } 768206b73d0SCy Schubert } 769206b73d0SCy Schubert 770206b73d0SCy Schubert if (data->phase2_method->isKeyAvailable && 771206b73d0SCy Schubert data->phase2_method->get_emsk) { 772206b73d0SCy Schubert emsk = data->phase2_method->get_emsk(sm, data->phase2_priv, 773206b73d0SCy Schubert &emsk_len); 774206b73d0SCy Schubert } 775206b73d0SCy Schubert 776c1d255d3SCy Schubert res = eap_teap_derive_imck(data->tls_cs, 777c1d255d3SCy Schubert data->simck_msk, data->simck_emsk, 778206b73d0SCy Schubert msk, msk_len, emsk, emsk_len, 779206b73d0SCy Schubert data->simck_msk, cmk_msk, 780206b73d0SCy Schubert data->simck_emsk, cmk_emsk); 781206b73d0SCy Schubert bin_clear_free(msk, msk_len); 782206b73d0SCy Schubert bin_clear_free(emsk, emsk_len); 783206b73d0SCy Schubert if (res == 0) { 784206b73d0SCy Schubert data->simck_idx++; 785206b73d0SCy Schubert if (emsk) 786206b73d0SCy Schubert data->cmk_emsk_available = 1; 787206b73d0SCy Schubert } 788206b73d0SCy Schubert return res; 789206b73d0SCy Schubert } 790206b73d0SCy Schubert 791206b73d0SCy Schubert 792206b73d0SCy Schubert static int eap_teap_session_id(struct eap_teap_data *data) 793206b73d0SCy Schubert { 794206b73d0SCy Schubert const size_t max_id_len = 100; 795206b73d0SCy Schubert int res; 796206b73d0SCy Schubert 797206b73d0SCy Schubert os_free(data->session_id); 798206b73d0SCy Schubert data->session_id = os_malloc(max_id_len); 799206b73d0SCy Schubert if (!data->session_id) 800206b73d0SCy Schubert return -1; 801206b73d0SCy Schubert 802206b73d0SCy Schubert data->session_id[0] = EAP_TYPE_TEAP; 803206b73d0SCy Schubert res = tls_get_tls_unique(data->ssl.conn, data->session_id + 1, 804206b73d0SCy Schubert max_id_len - 1); 805206b73d0SCy Schubert if (res < 0) { 806206b73d0SCy Schubert os_free(data->session_id); 807206b73d0SCy Schubert data->session_id = NULL; 808206b73d0SCy Schubert wpa_printf(MSG_ERROR, "EAP-TEAP: Failed to derive Session-Id"); 809206b73d0SCy Schubert return -1; 810206b73d0SCy Schubert } 811206b73d0SCy Schubert 812206b73d0SCy Schubert data->id_len = 1 + res; 813206b73d0SCy Schubert wpa_hexdump(MSG_DEBUG, "EAP-TEAP: Derived Session-Id", 814206b73d0SCy Schubert data->session_id, data->id_len); 815206b73d0SCy Schubert return 0; 816206b73d0SCy Schubert } 817206b73d0SCy Schubert 818206b73d0SCy Schubert 819206b73d0SCy Schubert static struct wpabuf * eap_teap_process_crypto_binding( 820206b73d0SCy Schubert struct eap_sm *sm, struct eap_teap_data *data, 821206b73d0SCy Schubert struct eap_method_ret *ret, 822206b73d0SCy Schubert const struct teap_tlv_crypto_binding *cb, size_t bind_len) 823206b73d0SCy Schubert { 824206b73d0SCy Schubert struct wpabuf *resp; 825206b73d0SCy Schubert u8 *pos; 826206b73d0SCy Schubert u8 cmk_msk[EAP_TEAP_CMK_LEN]; 827206b73d0SCy Schubert u8 cmk_emsk[EAP_TEAP_CMK_LEN]; 828206b73d0SCy Schubert const u8 *cmk_emsk_ptr = NULL; 829206b73d0SCy Schubert int res; 830206b73d0SCy Schubert size_t len; 831206b73d0SCy Schubert u8 flags; 832206b73d0SCy Schubert 833206b73d0SCy Schubert if (eap_teap_validate_crypto_binding(data, cb) < 0 || 834206b73d0SCy Schubert eap_teap_get_cmk(sm, data, cmk_msk, cmk_emsk) < 0) 835206b73d0SCy Schubert return NULL; 836206b73d0SCy Schubert 837206b73d0SCy Schubert /* Validate received MSK/EMSK Compound MAC */ 838206b73d0SCy Schubert flags = cb->subtype >> 4; 839206b73d0SCy Schubert 840206b73d0SCy Schubert if (flags == TEAP_CRYPTO_BINDING_MSK_CMAC || 841206b73d0SCy Schubert flags == TEAP_CRYPTO_BINDING_EMSK_AND_MSK_CMAC) { 842206b73d0SCy Schubert u8 msk_compound_mac[EAP_TEAP_COMPOUND_MAC_LEN]; 843206b73d0SCy Schubert 844206b73d0SCy Schubert if (eap_teap_compound_mac(data->tls_cs, cb, 845206b73d0SCy Schubert data->server_outer_tlvs, 846206b73d0SCy Schubert data->peer_outer_tlvs, cmk_msk, 847206b73d0SCy Schubert msk_compound_mac) < 0) 848206b73d0SCy Schubert return NULL; 849206b73d0SCy Schubert res = os_memcmp_const(msk_compound_mac, cb->msk_compound_mac, 850206b73d0SCy Schubert EAP_TEAP_COMPOUND_MAC_LEN); 851206b73d0SCy Schubert wpa_hexdump(MSG_MSGDUMP, "EAP-TEAP: Received MSK Compound MAC", 852206b73d0SCy Schubert cb->msk_compound_mac, EAP_TEAP_COMPOUND_MAC_LEN); 853206b73d0SCy Schubert wpa_hexdump(MSG_MSGDUMP, 854206b73d0SCy Schubert "EAP-TEAP: Calculated MSK Compound MAC", 855206b73d0SCy Schubert msk_compound_mac, EAP_TEAP_COMPOUND_MAC_LEN); 856206b73d0SCy Schubert if (res != 0) { 857206b73d0SCy Schubert wpa_printf(MSG_INFO, 858206b73d0SCy Schubert "EAP-TEAP: MSK Compound MAC did not match"); 859206b73d0SCy Schubert return NULL; 860206b73d0SCy Schubert } 861206b73d0SCy Schubert } 862206b73d0SCy Schubert 863206b73d0SCy Schubert if ((flags == TEAP_CRYPTO_BINDING_EMSK_CMAC || 864206b73d0SCy Schubert flags == TEAP_CRYPTO_BINDING_EMSK_AND_MSK_CMAC) && 865206b73d0SCy Schubert data->cmk_emsk_available) { 866206b73d0SCy Schubert u8 emsk_compound_mac[EAP_TEAP_COMPOUND_MAC_LEN]; 867206b73d0SCy Schubert 868206b73d0SCy Schubert if (eap_teap_compound_mac(data->tls_cs, cb, 869206b73d0SCy Schubert data->server_outer_tlvs, 870206b73d0SCy Schubert data->peer_outer_tlvs, cmk_emsk, 871206b73d0SCy Schubert emsk_compound_mac) < 0) 872206b73d0SCy Schubert return NULL; 873206b73d0SCy Schubert res = os_memcmp_const(emsk_compound_mac, cb->emsk_compound_mac, 874206b73d0SCy Schubert EAP_TEAP_COMPOUND_MAC_LEN); 875206b73d0SCy Schubert wpa_hexdump(MSG_MSGDUMP, "EAP-TEAP: Received EMSK Compound MAC", 876206b73d0SCy Schubert cb->emsk_compound_mac, EAP_TEAP_COMPOUND_MAC_LEN); 877206b73d0SCy Schubert wpa_hexdump(MSG_MSGDUMP, 878206b73d0SCy Schubert "EAP-TEAP: Calculated EMSK Compound MAC", 879206b73d0SCy Schubert emsk_compound_mac, EAP_TEAP_COMPOUND_MAC_LEN); 880206b73d0SCy Schubert if (res != 0) { 881206b73d0SCy Schubert wpa_printf(MSG_INFO, 882206b73d0SCy Schubert "EAP-TEAP: EMSK Compound MAC did not match"); 883206b73d0SCy Schubert return NULL; 884206b73d0SCy Schubert } 885206b73d0SCy Schubert 886206b73d0SCy Schubert cmk_emsk_ptr = cmk_emsk; 887206b73d0SCy Schubert } 888206b73d0SCy Schubert 889206b73d0SCy Schubert if (flags == TEAP_CRYPTO_BINDING_EMSK_CMAC && 890206b73d0SCy Schubert !data->cmk_emsk_available) { 891206b73d0SCy Schubert wpa_printf(MSG_INFO, 892206b73d0SCy Schubert "EAP-TEAP: Server included only EMSK Compound MAC, but no locally generated inner EAP EMSK to validate this"); 893206b73d0SCy Schubert return NULL; 894206b73d0SCy Schubert } 895206b73d0SCy Schubert 896206b73d0SCy Schubert /* 897206b73d0SCy Schubert * Compound MAC was valid, so authentication succeeded. Reply with 898206b73d0SCy Schubert * crypto binding to allow server to complete authentication. 899206b73d0SCy Schubert */ 900206b73d0SCy Schubert 901206b73d0SCy Schubert len = sizeof(struct teap_tlv_crypto_binding); 902206b73d0SCy Schubert resp = wpabuf_alloc(len); 903206b73d0SCy Schubert if (!resp) 904206b73d0SCy Schubert return NULL; 905206b73d0SCy Schubert 906206b73d0SCy Schubert if (data->phase2_success && eap_teap_derive_msk(data) < 0) { 907206b73d0SCy Schubert wpa_printf(MSG_INFO, "EAP-TEAP: Failed to generate MSK"); 908206b73d0SCy Schubert ret->methodState = METHOD_DONE; 909206b73d0SCy Schubert ret->decision = DECISION_FAIL; 910206b73d0SCy Schubert data->phase2_success = 0; 911206b73d0SCy Schubert wpabuf_free(resp); 912206b73d0SCy Schubert return NULL; 913206b73d0SCy Schubert } 914206b73d0SCy Schubert 915206b73d0SCy Schubert if (data->phase2_success && eap_teap_session_id(data) < 0) { 916206b73d0SCy Schubert wpabuf_free(resp); 917206b73d0SCy Schubert return NULL; 918206b73d0SCy Schubert } 919206b73d0SCy Schubert 920206b73d0SCy Schubert pos = wpabuf_put(resp, sizeof(struct teap_tlv_crypto_binding)); 921206b73d0SCy Schubert if (eap_teap_write_crypto_binding( 922206b73d0SCy Schubert data, (struct teap_tlv_crypto_binding *) pos, 923206b73d0SCy Schubert cb, cmk_msk, cmk_emsk_ptr) < 0) { 924206b73d0SCy Schubert wpabuf_free(resp); 925206b73d0SCy Schubert return NULL; 926206b73d0SCy Schubert } 927206b73d0SCy Schubert 928206b73d0SCy Schubert return resp; 929206b73d0SCy Schubert } 930206b73d0SCy Schubert 931206b73d0SCy Schubert 932206b73d0SCy Schubert static void eap_teap_parse_pac_tlv(struct eap_teap_pac *entry, int type, 933206b73d0SCy Schubert u8 *pos, size_t len, int *pac_key_found) 934206b73d0SCy Schubert { 935206b73d0SCy Schubert switch (type & 0x7fff) { 936206b73d0SCy Schubert case PAC_TYPE_PAC_KEY: 937206b73d0SCy Schubert wpa_hexdump_key(MSG_DEBUG, "EAP-TEAP: PAC-Key", pos, len); 938206b73d0SCy Schubert if (len != EAP_TEAP_PAC_KEY_LEN) { 939206b73d0SCy Schubert wpa_printf(MSG_DEBUG, 940206b73d0SCy Schubert "EAP-TEAP: Invalid PAC-Key length %lu", 941206b73d0SCy Schubert (unsigned long) len); 942206b73d0SCy Schubert break; 943206b73d0SCy Schubert } 944206b73d0SCy Schubert *pac_key_found = 1; 945206b73d0SCy Schubert os_memcpy(entry->pac_key, pos, len); 946206b73d0SCy Schubert break; 947206b73d0SCy Schubert case PAC_TYPE_PAC_OPAQUE: 948206b73d0SCy Schubert wpa_hexdump(MSG_DEBUG, "EAP-TEAP: PAC-Opaque", pos, len); 949206b73d0SCy Schubert entry->pac_opaque = pos; 950206b73d0SCy Schubert entry->pac_opaque_len = len; 951206b73d0SCy Schubert break; 952206b73d0SCy Schubert case PAC_TYPE_PAC_INFO: 953206b73d0SCy Schubert wpa_hexdump(MSG_DEBUG, "EAP-TEAP: PAC-Info", pos, len); 954206b73d0SCy Schubert entry->pac_info = pos; 955206b73d0SCy Schubert entry->pac_info_len = len; 956206b73d0SCy Schubert break; 957206b73d0SCy Schubert default: 958206b73d0SCy Schubert wpa_printf(MSG_DEBUG, "EAP-TEAP: Ignored unknown PAC type %d", 959206b73d0SCy Schubert type); 960206b73d0SCy Schubert break; 961206b73d0SCy Schubert } 962206b73d0SCy Schubert } 963206b73d0SCy Schubert 964206b73d0SCy Schubert 965206b73d0SCy Schubert static int eap_teap_process_pac_tlv(struct eap_teap_pac *entry, 966206b73d0SCy Schubert u8 *pac, size_t pac_len) 967206b73d0SCy Schubert { 968206b73d0SCy Schubert struct pac_attr_hdr *hdr; 969206b73d0SCy Schubert u8 *pos; 970206b73d0SCy Schubert size_t left, len; 971206b73d0SCy Schubert int type, pac_key_found = 0; 972206b73d0SCy Schubert 973206b73d0SCy Schubert pos = pac; 974206b73d0SCy Schubert left = pac_len; 975206b73d0SCy Schubert 976206b73d0SCy Schubert while (left > sizeof(*hdr)) { 977206b73d0SCy Schubert hdr = (struct pac_attr_hdr *) pos; 978206b73d0SCy Schubert type = be_to_host16(hdr->type); 979206b73d0SCy Schubert len = be_to_host16(hdr->len); 980206b73d0SCy Schubert pos += sizeof(*hdr); 981206b73d0SCy Schubert left -= sizeof(*hdr); 982206b73d0SCy Schubert if (len > left) { 983206b73d0SCy Schubert wpa_printf(MSG_DEBUG, 984206b73d0SCy Schubert "EAP-TEAP: PAC TLV overrun (type=%d len=%lu left=%lu)", 985206b73d0SCy Schubert type, (unsigned long) len, 986206b73d0SCy Schubert (unsigned long) left); 987206b73d0SCy Schubert return -1; 988206b73d0SCy Schubert } 989206b73d0SCy Schubert 990206b73d0SCy Schubert eap_teap_parse_pac_tlv(entry, type, pos, len, &pac_key_found); 991206b73d0SCy Schubert 992206b73d0SCy Schubert pos += len; 993206b73d0SCy Schubert left -= len; 994206b73d0SCy Schubert } 995206b73d0SCy Schubert 996206b73d0SCy Schubert if (!pac_key_found || !entry->pac_opaque || !entry->pac_info) { 997206b73d0SCy Schubert wpa_printf(MSG_DEBUG, 998206b73d0SCy Schubert "EAP-TEAP: PAC TLV does not include all the required fields"); 999206b73d0SCy Schubert return -1; 1000206b73d0SCy Schubert } 1001206b73d0SCy Schubert 1002206b73d0SCy Schubert return 0; 1003206b73d0SCy Schubert } 1004206b73d0SCy Schubert 1005206b73d0SCy Schubert 1006206b73d0SCy Schubert static int eap_teap_parse_pac_info(struct eap_teap_pac *entry, int type, 1007206b73d0SCy Schubert u8 *pos, size_t len) 1008206b73d0SCy Schubert { 1009206b73d0SCy Schubert u16 pac_type; 1010206b73d0SCy Schubert u32 lifetime; 1011206b73d0SCy Schubert struct os_time now; 1012206b73d0SCy Schubert 1013206b73d0SCy Schubert switch (type & 0x7fff) { 1014206b73d0SCy Schubert case PAC_TYPE_CRED_LIFETIME: 1015206b73d0SCy Schubert if (len != 4) { 1016206b73d0SCy Schubert wpa_hexdump(MSG_DEBUG, 1017206b73d0SCy Schubert "EAP-TEAP: PAC-Info - Invalid CRED_LIFETIME length - ignored", 1018206b73d0SCy Schubert pos, len); 1019206b73d0SCy Schubert return 0; 1020206b73d0SCy Schubert } 1021206b73d0SCy Schubert 1022206b73d0SCy Schubert /* 1023206b73d0SCy Schubert * This is not currently saved separately in PAC files since 1024206b73d0SCy Schubert * the server can automatically initiate PAC update when 1025206b73d0SCy Schubert * needed. Anyway, the information is available from PAC-Info 1026206b73d0SCy Schubert * dump if it is needed for something in the future. 1027206b73d0SCy Schubert */ 1028206b73d0SCy Schubert lifetime = WPA_GET_BE32(pos); 1029206b73d0SCy Schubert os_get_time(&now); 1030206b73d0SCy Schubert wpa_printf(MSG_DEBUG, 1031206b73d0SCy Schubert "EAP-TEAP: PAC-Info - CRED_LIFETIME %d (%d days)", 1032206b73d0SCy Schubert lifetime, (lifetime - (u32) now.sec) / 86400); 1033206b73d0SCy Schubert break; 1034206b73d0SCy Schubert case PAC_TYPE_A_ID: 1035206b73d0SCy Schubert wpa_hexdump_ascii(MSG_DEBUG, "EAP-TEAP: PAC-Info - A-ID", 1036206b73d0SCy Schubert pos, len); 1037206b73d0SCy Schubert entry->a_id = pos; 1038206b73d0SCy Schubert entry->a_id_len = len; 1039206b73d0SCy Schubert break; 1040206b73d0SCy Schubert case PAC_TYPE_I_ID: 1041206b73d0SCy Schubert wpa_hexdump_ascii(MSG_DEBUG, "EAP-TEAP: PAC-Info - I-ID", 1042206b73d0SCy Schubert pos, len); 1043206b73d0SCy Schubert entry->i_id = pos; 1044206b73d0SCy Schubert entry->i_id_len = len; 1045206b73d0SCy Schubert break; 1046206b73d0SCy Schubert case PAC_TYPE_A_ID_INFO: 1047206b73d0SCy Schubert wpa_hexdump_ascii(MSG_DEBUG, "EAP-TEAP: PAC-Info - A-ID-Info", 1048206b73d0SCy Schubert pos, len); 1049206b73d0SCy Schubert entry->a_id_info = pos; 1050206b73d0SCy Schubert entry->a_id_info_len = len; 1051206b73d0SCy Schubert break; 1052206b73d0SCy Schubert case PAC_TYPE_PAC_TYPE: 1053206b73d0SCy Schubert /* RFC 7170, Section 4.2.12.6 - PAC-Type TLV */ 1054206b73d0SCy Schubert if (len != 2) { 1055206b73d0SCy Schubert wpa_printf(MSG_INFO, 1056206b73d0SCy Schubert "EAP-TEAP: Invalid PAC-Type length %lu (expected 2)", 1057206b73d0SCy Schubert (unsigned long) len); 1058206b73d0SCy Schubert wpa_hexdump_ascii(MSG_DEBUG, 1059206b73d0SCy Schubert "EAP-TEAP: PAC-Info - PAC-Type", 1060206b73d0SCy Schubert pos, len); 1061206b73d0SCy Schubert return -1; 1062206b73d0SCy Schubert } 1063206b73d0SCy Schubert pac_type = WPA_GET_BE16(pos); 1064206b73d0SCy Schubert if (pac_type != PAC_TYPE_TUNNEL_PAC) { 1065206b73d0SCy Schubert wpa_printf(MSG_INFO, 1066206b73d0SCy Schubert "EAP-TEAP: Unsupported PAC Type %d", 1067206b73d0SCy Schubert pac_type); 1068206b73d0SCy Schubert return -1; 1069206b73d0SCy Schubert } 1070206b73d0SCy Schubert 1071206b73d0SCy Schubert wpa_printf(MSG_DEBUG, "EAP-TEAP: PAC-Info - PAC-Type %d", 1072206b73d0SCy Schubert pac_type); 1073206b73d0SCy Schubert entry->pac_type = pac_type; 1074206b73d0SCy Schubert break; 1075206b73d0SCy Schubert default: 1076206b73d0SCy Schubert wpa_printf(MSG_DEBUG, 1077206b73d0SCy Schubert "EAP-TEAP: Ignored unknown PAC-Info type %d", type); 1078206b73d0SCy Schubert break; 1079206b73d0SCy Schubert } 1080206b73d0SCy Schubert 1081206b73d0SCy Schubert return 0; 1082206b73d0SCy Schubert } 1083206b73d0SCy Schubert 1084206b73d0SCy Schubert 1085206b73d0SCy Schubert static int eap_teap_process_pac_info(struct eap_teap_pac *entry) 1086206b73d0SCy Schubert { 1087206b73d0SCy Schubert struct pac_attr_hdr *hdr; 1088206b73d0SCy Schubert u8 *pos; 1089206b73d0SCy Schubert size_t left, len; 1090206b73d0SCy Schubert int type; 1091206b73d0SCy Schubert 1092206b73d0SCy Schubert /* RFC 7170, Section 4.2.12.4 */ 1093206b73d0SCy Schubert 1094206b73d0SCy Schubert /* PAC-Type defaults to Tunnel PAC (Type 1) */ 1095206b73d0SCy Schubert entry->pac_type = PAC_TYPE_TUNNEL_PAC; 1096206b73d0SCy Schubert 1097206b73d0SCy Schubert pos = entry->pac_info; 1098206b73d0SCy Schubert left = entry->pac_info_len; 1099206b73d0SCy Schubert while (left > sizeof(*hdr)) { 1100206b73d0SCy Schubert hdr = (struct pac_attr_hdr *) pos; 1101206b73d0SCy Schubert type = be_to_host16(hdr->type); 1102206b73d0SCy Schubert len = be_to_host16(hdr->len); 1103206b73d0SCy Schubert pos += sizeof(*hdr); 1104206b73d0SCy Schubert left -= sizeof(*hdr); 1105206b73d0SCy Schubert if (len > left) { 1106206b73d0SCy Schubert wpa_printf(MSG_DEBUG, 1107206b73d0SCy Schubert "EAP-TEAP: PAC-Info overrun (type=%d len=%lu left=%lu)", 1108206b73d0SCy Schubert type, (unsigned long) len, 1109206b73d0SCy Schubert (unsigned long) left); 1110206b73d0SCy Schubert return -1; 1111206b73d0SCy Schubert } 1112206b73d0SCy Schubert 1113206b73d0SCy Schubert if (eap_teap_parse_pac_info(entry, type, pos, len) < 0) 1114206b73d0SCy Schubert return -1; 1115206b73d0SCy Schubert 1116206b73d0SCy Schubert pos += len; 1117206b73d0SCy Schubert left -= len; 1118206b73d0SCy Schubert } 1119206b73d0SCy Schubert 1120206b73d0SCy Schubert if (!entry->a_id || !entry->a_id_info) { 1121206b73d0SCy Schubert wpa_printf(MSG_DEBUG, 1122206b73d0SCy Schubert "EAP-TEAP: PAC-Info does not include all the required fields"); 1123206b73d0SCy Schubert return -1; 1124206b73d0SCy Schubert } 1125206b73d0SCy Schubert 1126206b73d0SCy Schubert return 0; 1127206b73d0SCy Schubert } 1128206b73d0SCy Schubert 1129206b73d0SCy Schubert 1130206b73d0SCy Schubert static struct wpabuf * eap_teap_process_pac(struct eap_sm *sm, 1131206b73d0SCy Schubert struct eap_teap_data *data, 1132206b73d0SCy Schubert struct eap_method_ret *ret, 1133206b73d0SCy Schubert u8 *pac, size_t pac_len) 1134206b73d0SCy Schubert { 1135206b73d0SCy Schubert struct eap_peer_config *config = eap_get_config(sm); 1136206b73d0SCy Schubert struct eap_teap_pac entry; 1137206b73d0SCy Schubert 1138206b73d0SCy Schubert os_memset(&entry, 0, sizeof(entry)); 1139206b73d0SCy Schubert if (eap_teap_process_pac_tlv(&entry, pac, pac_len) || 1140206b73d0SCy Schubert eap_teap_process_pac_info(&entry)) 1141206b73d0SCy Schubert return NULL; 1142206b73d0SCy Schubert 1143206b73d0SCy Schubert eap_teap_add_pac(&data->pac, &data->current_pac, &entry); 1144206b73d0SCy Schubert eap_teap_pac_list_truncate(data->pac, data->max_pac_list_len); 1145206b73d0SCy Schubert if (data->use_pac_binary_format) 1146206b73d0SCy Schubert eap_teap_save_pac_bin(sm, data->pac, config->pac_file); 1147206b73d0SCy Schubert else 1148206b73d0SCy Schubert eap_teap_save_pac(sm, data->pac, config->pac_file); 1149206b73d0SCy Schubert 1150206b73d0SCy Schubert wpa_printf(MSG_DEBUG, 1151206b73d0SCy Schubert "EAP-TEAP: Send PAC-Acknowledgement - %s initiated provisioning completed successfully", 1152206b73d0SCy Schubert data->provisioning ? "peer" : "server"); 1153206b73d0SCy Schubert return eap_teap_tlv_pac_ack(); 1154206b73d0SCy Schubert } 1155206b73d0SCy Schubert 1156206b73d0SCy Schubert 1157206b73d0SCy Schubert static int eap_teap_parse_decrypted(struct wpabuf *decrypted, 1158206b73d0SCy Schubert struct eap_teap_tlv_parse *tlv, 1159206b73d0SCy Schubert struct wpabuf **resp) 1160206b73d0SCy Schubert { 1161206b73d0SCy Schubert u16 tlv_type; 1162206b73d0SCy Schubert int mandatory, res; 1163206b73d0SCy Schubert size_t len; 1164206b73d0SCy Schubert u8 *pos, *end; 1165206b73d0SCy Schubert 1166206b73d0SCy Schubert os_memset(tlv, 0, sizeof(*tlv)); 1167206b73d0SCy Schubert 1168206b73d0SCy Schubert /* Parse TLVs from the decrypted Phase 2 data */ 1169206b73d0SCy Schubert pos = wpabuf_mhead(decrypted); 1170206b73d0SCy Schubert end = pos + wpabuf_len(decrypted); 1171206b73d0SCy Schubert while (end - pos >= 4) { 1172206b73d0SCy Schubert mandatory = pos[0] & 0x80; 1173206b73d0SCy Schubert tlv_type = WPA_GET_BE16(pos) & 0x3fff; 1174206b73d0SCy Schubert pos += 2; 1175206b73d0SCy Schubert len = WPA_GET_BE16(pos); 1176206b73d0SCy Schubert pos += 2; 1177206b73d0SCy Schubert if (len > (size_t) (end - pos)) { 1178206b73d0SCy Schubert wpa_printf(MSG_INFO, "EAP-TEAP: TLV overflow"); 1179206b73d0SCy Schubert return -1; 1180206b73d0SCy Schubert } 1181206b73d0SCy Schubert wpa_printf(MSG_DEBUG, 1182206b73d0SCy Schubert "EAP-TEAP: Received Phase 2: TLV type %u (%s) length %u%s", 1183206b73d0SCy Schubert tlv_type, eap_teap_tlv_type_str(tlv_type), 1184206b73d0SCy Schubert (unsigned int) len, 1185206b73d0SCy Schubert mandatory ? " (mandatory)" : ""); 1186206b73d0SCy Schubert 1187206b73d0SCy Schubert res = eap_teap_parse_tlv(tlv, tlv_type, pos, len); 1188206b73d0SCy Schubert if (res == -2) 1189206b73d0SCy Schubert break; 1190206b73d0SCy Schubert if (res < 0) { 1191206b73d0SCy Schubert if (mandatory) { 1192206b73d0SCy Schubert wpa_printf(MSG_DEBUG, 1193206b73d0SCy Schubert "EAP-TEAP: NAK unknown mandatory TLV type %u", 1194206b73d0SCy Schubert tlv_type); 1195206b73d0SCy Schubert *resp = eap_teap_tlv_nak(0, tlv_type); 1196206b73d0SCy Schubert break; 1197206b73d0SCy Schubert } 1198206b73d0SCy Schubert 1199206b73d0SCy Schubert wpa_printf(MSG_DEBUG, 1200206b73d0SCy Schubert "EAP-TEAP: Ignore unknown optional TLV type %u", 1201206b73d0SCy Schubert tlv_type); 1202206b73d0SCy Schubert } 1203206b73d0SCy Schubert 1204206b73d0SCy Schubert pos += len; 1205206b73d0SCy Schubert } 1206206b73d0SCy Schubert 1207206b73d0SCy Schubert return 0; 1208206b73d0SCy Schubert } 1209206b73d0SCy Schubert 1210206b73d0SCy Schubert 1211206b73d0SCy Schubert static struct wpabuf * eap_teap_pac_request(void) 1212206b73d0SCy Schubert { 1213206b73d0SCy Schubert struct wpabuf *req; 1214206b73d0SCy Schubert struct teap_tlv_request_action *act; 1215206b73d0SCy Schubert struct teap_tlv_hdr *pac; 1216206b73d0SCy Schubert struct teap_attr_pac_type *type; 1217206b73d0SCy Schubert 1218206b73d0SCy Schubert req = wpabuf_alloc(sizeof(*act) + sizeof(*pac) + sizeof(*type)); 1219206b73d0SCy Schubert if (!req) 1220206b73d0SCy Schubert return NULL; 1221206b73d0SCy Schubert 1222206b73d0SCy Schubert wpa_printf(MSG_DEBUG, "EAP-TEAP: Add Request Action TLV (Process TLV)"); 1223206b73d0SCy Schubert act = wpabuf_put(req, sizeof(*act)); 1224206b73d0SCy Schubert act->tlv_type = host_to_be16(TEAP_TLV_REQUEST_ACTION); 1225206b73d0SCy Schubert act->length = host_to_be16(2); 1226206b73d0SCy Schubert act->status = TEAP_STATUS_SUCCESS; 1227206b73d0SCy Schubert act->action = TEAP_REQUEST_ACTION_PROCESS_TLV; 1228206b73d0SCy Schubert 1229206b73d0SCy Schubert wpa_printf(MSG_DEBUG, "EAP-TEAP: Add PAC TLV (PAC-Type = Tunnel)"); 1230206b73d0SCy Schubert pac = wpabuf_put(req, sizeof(*pac)); 1231206b73d0SCy Schubert pac->tlv_type = host_to_be16(TEAP_TLV_PAC); 1232206b73d0SCy Schubert pac->length = host_to_be16(sizeof(*type)); 1233206b73d0SCy Schubert 1234206b73d0SCy Schubert type = wpabuf_put(req, sizeof(*type)); 1235206b73d0SCy Schubert type->type = host_to_be16(PAC_TYPE_PAC_TYPE); 1236206b73d0SCy Schubert type->length = host_to_be16(2); 1237206b73d0SCy Schubert type->pac_type = host_to_be16(PAC_TYPE_TUNNEL_PAC); 1238206b73d0SCy Schubert 1239206b73d0SCy Schubert return req; 1240206b73d0SCy Schubert } 1241206b73d0SCy Schubert 1242206b73d0SCy Schubert 1243206b73d0SCy Schubert static int eap_teap_process_decrypted(struct eap_sm *sm, 1244206b73d0SCy Schubert struct eap_teap_data *data, 1245206b73d0SCy Schubert struct eap_method_ret *ret, 1246206b73d0SCy Schubert u8 identifier, 1247206b73d0SCy Schubert struct wpabuf *decrypted, 1248206b73d0SCy Schubert struct wpabuf **out_data) 1249206b73d0SCy Schubert { 1250206b73d0SCy Schubert struct wpabuf *resp = NULL, *tmp; 1251206b73d0SCy Schubert struct eap_teap_tlv_parse tlv; 1252206b73d0SCy Schubert int failed = 0; 1253206b73d0SCy Schubert enum teap_error_codes error = 0; 1254c1d255d3SCy Schubert int iresult_added = 0; 1255206b73d0SCy Schubert 1256206b73d0SCy Schubert if (eap_teap_parse_decrypted(decrypted, &tlv, &resp) < 0) { 1257206b73d0SCy Schubert /* Parsing failed - no response available */ 1258206b73d0SCy Schubert return 0; 1259206b73d0SCy Schubert } 1260206b73d0SCy Schubert 1261206b73d0SCy Schubert if (resp) { 1262206b73d0SCy Schubert /* Parsing rejected the message - send out an error response */ 1263206b73d0SCy Schubert goto send_resp; 1264206b73d0SCy Schubert } 1265206b73d0SCy Schubert 1266206b73d0SCy Schubert if (tlv.result == TEAP_STATUS_FAILURE) { 1267206b73d0SCy Schubert /* Server indicated failure - respond similarly per 1268206b73d0SCy Schubert * RFC 7170, 3.6.3. This authentication exchange cannot succeed 1269206b73d0SCy Schubert * and will be terminated with a cleartext EAP Failure. */ 1270206b73d0SCy Schubert wpa_printf(MSG_DEBUG, 1271206b73d0SCy Schubert "EAP-TEAP: Server rejected authentication"); 1272206b73d0SCy Schubert resp = eap_teap_tlv_result(TEAP_STATUS_FAILURE, 0); 1273206b73d0SCy Schubert ret->methodState = METHOD_DONE; 1274206b73d0SCy Schubert ret->decision = DECISION_FAIL; 1275206b73d0SCy Schubert goto send_resp; 1276206b73d0SCy Schubert } 1277206b73d0SCy Schubert 1278c1d255d3SCy Schubert if (tlv.iresult == TEAP_STATUS_SUCCESS && !tlv.crypto_binding) { 1279c1d255d3SCy Schubert /* Intermediate-Result TLV indicating success, but no 1280c1d255d3SCy Schubert * Crypto-Binding TLV */ 1281206b73d0SCy Schubert wpa_printf(MSG_DEBUG, 1282c1d255d3SCy Schubert "EAP-TEAP: Intermediate-Result TLV indicating success, but no Crypto-Binding TLV"); 1283c1d255d3SCy Schubert failed = 1; 1284c1d255d3SCy Schubert error = TEAP_ERROR_TUNNEL_COMPROMISE_ERROR; 1285c1d255d3SCy Schubert goto done; 1286c1d255d3SCy Schubert } 1287c1d255d3SCy Schubert 1288c1d255d3SCy Schubert if (!data->iresult_verified && !data->result_success_done && 1289c1d255d3SCy Schubert tlv.result == TEAP_STATUS_SUCCESS && !tlv.crypto_binding) { 1290c1d255d3SCy Schubert /* Result TLV indicating success, but no Crypto-Binding TLV */ 1291c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, 1292c1d255d3SCy Schubert "EAP-TEAP: Result TLV indicating success, but no Crypto-Binding TLV"); 1293206b73d0SCy Schubert failed = 1; 1294206b73d0SCy Schubert error = TEAP_ERROR_TUNNEL_COMPROMISE_ERROR; 1295206b73d0SCy Schubert goto done; 1296206b73d0SCy Schubert } 1297206b73d0SCy Schubert 1298206b73d0SCy Schubert if (tlv.iresult != TEAP_STATUS_SUCCESS && 1299206b73d0SCy Schubert tlv.iresult != TEAP_STATUS_FAILURE && 1300206b73d0SCy Schubert data->inner_method_done) { 1301206b73d0SCy Schubert wpa_printf(MSG_DEBUG, 1302206b73d0SCy Schubert "EAP-TEAP: Inner EAP method exchange completed, but no Intermediate-Result TLV included"); 1303206b73d0SCy Schubert failed = 1; 1304206b73d0SCy Schubert error = TEAP_ERROR_TUNNEL_COMPROMISE_ERROR; 1305206b73d0SCy Schubert goto done; 1306206b73d0SCy Schubert } 1307206b73d0SCy Schubert 1308*a90b9d01SCy Schubert if (tlv.crypto_binding) { 1309*a90b9d01SCy Schubert if (tlv.iresult != TEAP_STATUS_SUCCESS && 1310*a90b9d01SCy Schubert tlv.result != TEAP_STATUS_SUCCESS) { 1311*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG, 1312*a90b9d01SCy Schubert "EAP-TEAP: Unexpected Crypto-Binding TLV without Result TLV or Intermediate-Result TLV indicating success"); 1313*a90b9d01SCy Schubert failed = 1; 1314*a90b9d01SCy Schubert error = TEAP_ERROR_UNEXPECTED_TLVS_EXCHANGED; 1315*a90b9d01SCy Schubert goto done; 1316*a90b9d01SCy Schubert } 1317*a90b9d01SCy Schubert 1318*a90b9d01SCy Schubert tmp = eap_teap_process_crypto_binding(sm, data, ret, 1319*a90b9d01SCy Schubert tlv.crypto_binding, 1320*a90b9d01SCy Schubert tlv.crypto_binding_len); 1321*a90b9d01SCy Schubert if (!tmp) { 1322*a90b9d01SCy Schubert failed = 1; 1323*a90b9d01SCy Schubert error = TEAP_ERROR_TUNNEL_COMPROMISE_ERROR; 1324*a90b9d01SCy Schubert } else { 1325*a90b9d01SCy Schubert resp = wpabuf_concat(resp, tmp); 1326*a90b9d01SCy Schubert if (tlv.result == TEAP_STATUS_SUCCESS && !failed) 1327*a90b9d01SCy Schubert data->result_success_done = 1; 1328*a90b9d01SCy Schubert if (tlv.iresult == TEAP_STATUS_SUCCESS && !failed) { 1329*a90b9d01SCy Schubert data->inner_method_done = 0; 1330*a90b9d01SCy Schubert data->iresult_verified = 1; 1331*a90b9d01SCy Schubert } 1332*a90b9d01SCy Schubert } 1333*a90b9d01SCy Schubert } 1334*a90b9d01SCy Schubert 1335c1d255d3SCy Schubert if (tlv.identity_type == TEAP_IDENTITY_TYPE_MACHINE) { 1336c1d255d3SCy Schubert struct eap_peer_config *config = eap_get_config(sm); 1337c1d255d3SCy Schubert 1338c1d255d3SCy Schubert sm->use_machine_cred = config && config->machine_identity && 1339c1d255d3SCy Schubert config->machine_identity_len; 1340c1d255d3SCy Schubert } else if (tlv.identity_type) { 1341c1d255d3SCy Schubert sm->use_machine_cred = 0; 1342c1d255d3SCy Schubert } 1343c1d255d3SCy Schubert if (tlv.identity_type) { 1344c1d255d3SCy Schubert struct eap_peer_config *config = eap_get_config(sm); 1345c1d255d3SCy Schubert 1346c1d255d3SCy Schubert os_free(data->phase2_types); 1347c1d255d3SCy Schubert data->phase2_types = NULL; 1348c1d255d3SCy Schubert data->num_phase2_types = 0; 1349c1d255d3SCy Schubert if (config && 1350c1d255d3SCy Schubert eap_peer_select_phase2_methods(config, "auth=", 1351c1d255d3SCy Schubert &data->phase2_types, 1352c1d255d3SCy Schubert &data->num_phase2_types, 1353c1d255d3SCy Schubert sm->use_machine_cred) < 0) { 1354c1d255d3SCy Schubert wpa_printf(MSG_INFO, 1355c1d255d3SCy Schubert "EAP-TEAP: Failed to update Phase 2 EAP types"); 1356c1d255d3SCy Schubert failed = 1; 1357c1d255d3SCy Schubert goto done; 1358c1d255d3SCy Schubert } 1359c1d255d3SCy Schubert } 1360c1d255d3SCy Schubert 1361206b73d0SCy Schubert if (tlv.basic_auth_req) { 1362206b73d0SCy Schubert tmp = eap_teap_process_basic_auth_req(sm, data, 1363206b73d0SCy Schubert tlv.basic_auth_req, 1364c1d255d3SCy Schubert tlv.basic_auth_req_len, 1365c1d255d3SCy Schubert tlv.identity_type); 1366206b73d0SCy Schubert if (!tmp) 1367206b73d0SCy Schubert failed = 1; 1368206b73d0SCy Schubert resp = wpabuf_concat(resp, tmp); 1369206b73d0SCy Schubert } else if (tlv.eap_payload_tlv) { 1370206b73d0SCy Schubert tmp = eap_teap_process_eap_payload_tlv(sm, data, ret, 1371206b73d0SCy Schubert tlv.eap_payload_tlv, 1372c1d255d3SCy Schubert tlv.eap_payload_tlv_len, 1373c1d255d3SCy Schubert tlv.identity_type); 1374206b73d0SCy Schubert if (!tmp) 1375206b73d0SCy Schubert failed = 1; 1376206b73d0SCy Schubert resp = wpabuf_concat(resp, tmp); 1377206b73d0SCy Schubert 1378206b73d0SCy Schubert if (tlv.iresult == TEAP_STATUS_SUCCESS || 1379206b73d0SCy Schubert tlv.iresult == TEAP_STATUS_FAILURE) { 1380206b73d0SCy Schubert tmp = eap_teap_tlv_result(failed ? 1381206b73d0SCy Schubert TEAP_STATUS_FAILURE : 1382206b73d0SCy Schubert TEAP_STATUS_SUCCESS, 1); 1383206b73d0SCy Schubert resp = wpabuf_concat(resp, tmp); 1384206b73d0SCy Schubert if (tlv.iresult == TEAP_STATUS_FAILURE) 1385206b73d0SCy Schubert failed = 1; 1386c1d255d3SCy Schubert iresult_added = 1; 1387206b73d0SCy Schubert } 1388206b73d0SCy Schubert } 1389206b73d0SCy Schubert 1390206b73d0SCy Schubert if (data->result_success_done && data->session_ticket_used && 1391206b73d0SCy Schubert eap_teap_derive_msk(data) == 0) { 1392206b73d0SCy Schubert /* Assume the server might accept authentication without going 1393206b73d0SCy Schubert * through inner authentication. */ 1394206b73d0SCy Schubert wpa_printf(MSG_DEBUG, 1395206b73d0SCy Schubert "EAP-TEAP: PAC used - server may decide to skip inner authentication"); 1396206b73d0SCy Schubert ret->methodState = METHOD_MAY_CONT; 1397206b73d0SCy Schubert ret->decision = DECISION_COND_SUCC; 1398c1d255d3SCy Schubert } else if (data->result_success_done && 1399c1d255d3SCy Schubert tls_connection_get_own_cert_used(data->ssl.conn) && 1400c1d255d3SCy Schubert eap_teap_derive_msk(data) == 0) { 1401c1d255d3SCy Schubert /* Assume the server might accept authentication without going 1402c1d255d3SCy Schubert * through inner authentication. */ 1403c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, 1404c1d255d3SCy Schubert "EAP-TEAP: Client certificate used - server may decide to skip inner authentication"); 1405c1d255d3SCy Schubert ret->methodState = METHOD_MAY_CONT; 1406c1d255d3SCy Schubert ret->decision = DECISION_COND_SUCC; 1407206b73d0SCy Schubert } 1408206b73d0SCy Schubert 1409206b73d0SCy Schubert if (tlv.pac) { 1410206b73d0SCy Schubert if (tlv.result == TEAP_STATUS_SUCCESS) { 1411206b73d0SCy Schubert tmp = eap_teap_process_pac(sm, data, ret, 1412206b73d0SCy Schubert tlv.pac, tlv.pac_len); 1413206b73d0SCy Schubert resp = wpabuf_concat(resp, tmp); 1414206b73d0SCy Schubert } else { 1415206b73d0SCy Schubert wpa_printf(MSG_DEBUG, 1416206b73d0SCy Schubert "EAP-TEAP: PAC TLV without Result TLV acknowledging success"); 1417206b73d0SCy Schubert failed = 1; 1418206b73d0SCy Schubert error = TEAP_ERROR_UNEXPECTED_TLVS_EXCHANGED; 1419206b73d0SCy Schubert } 1420206b73d0SCy Schubert } 1421206b73d0SCy Schubert 1422206b73d0SCy Schubert if (!data->current_pac && data->provisioning && !failed && !tlv.pac && 1423206b73d0SCy Schubert tlv.crypto_binding && 1424206b73d0SCy Schubert (!data->anon_provisioning || 1425206b73d0SCy Schubert (data->phase2_success && data->phase2_method && 1426206b73d0SCy Schubert data->phase2_method->vendor == 0 && 1427206b73d0SCy Schubert eap_teap_allowed_anon_prov_cipher_suite(data->tls_cs) && 1428206b73d0SCy Schubert eap_teap_allowed_anon_prov_phase2_method( 1429c1d255d3SCy Schubert data->phase2_method->vendor, 1430206b73d0SCy Schubert data->phase2_method->method))) && 1431206b73d0SCy Schubert (tlv.iresult == TEAP_STATUS_SUCCESS || 1432206b73d0SCy Schubert tlv.result == TEAP_STATUS_SUCCESS)) { 1433206b73d0SCy Schubert /* 1434206b73d0SCy Schubert * Need to request Tunnel PAC when using authenticated 1435206b73d0SCy Schubert * provisioning. 1436206b73d0SCy Schubert */ 1437206b73d0SCy Schubert wpa_printf(MSG_DEBUG, "EAP-TEAP: Request Tunnel PAC"); 1438206b73d0SCy Schubert tmp = eap_teap_pac_request(); 1439206b73d0SCy Schubert resp = wpabuf_concat(resp, tmp); 1440206b73d0SCy Schubert } 1441206b73d0SCy Schubert 1442206b73d0SCy Schubert done: 1443206b73d0SCy Schubert if (failed) { 1444206b73d0SCy Schubert tmp = eap_teap_tlv_result(TEAP_STATUS_FAILURE, 0); 1445206b73d0SCy Schubert resp = wpabuf_concat(tmp, resp); 1446206b73d0SCy Schubert 1447206b73d0SCy Schubert if (error != 0) { 1448206b73d0SCy Schubert tmp = eap_teap_tlv_error(error); 1449206b73d0SCy Schubert resp = wpabuf_concat(tmp, resp); 1450206b73d0SCy Schubert } 1451206b73d0SCy Schubert 1452206b73d0SCy Schubert ret->methodState = METHOD_DONE; 1453206b73d0SCy Schubert ret->decision = DECISION_FAIL; 1454206b73d0SCy Schubert } else if (tlv.result == TEAP_STATUS_SUCCESS) { 1455206b73d0SCy Schubert tmp = eap_teap_tlv_result(TEAP_STATUS_SUCCESS, 0); 1456206b73d0SCy Schubert resp = wpabuf_concat(tmp, resp); 1457206b73d0SCy Schubert } 1458c1d255d3SCy Schubert if ((tlv.iresult == TEAP_STATUS_SUCCESS || 1459c1d255d3SCy Schubert tlv.iresult == TEAP_STATUS_FAILURE) && !iresult_added) { 1460c1d255d3SCy Schubert tmp = eap_teap_tlv_result((!failed && data->phase2_success) ? 1461c1d255d3SCy Schubert TEAP_STATUS_SUCCESS : 1462c1d255d3SCy Schubert TEAP_STATUS_FAILURE, 1); 1463c1d255d3SCy Schubert resp = wpabuf_concat(tmp, resp); 1464c1d255d3SCy Schubert } 1465206b73d0SCy Schubert 1466206b73d0SCy Schubert if (resp && tlv.result == TEAP_STATUS_SUCCESS && !failed && 1467c1d255d3SCy Schubert (tlv.crypto_binding || data->iresult_verified) && 1468c1d255d3SCy Schubert data->phase2_success) { 1469206b73d0SCy Schubert /* Successfully completed Phase 2 */ 1470206b73d0SCy Schubert wpa_printf(MSG_DEBUG, 1471206b73d0SCy Schubert "EAP-TEAP: Authentication completed successfully"); 1472206b73d0SCy Schubert ret->methodState = METHOD_MAY_CONT; 1473206b73d0SCy Schubert data->on_tx_completion = data->provisioning ? 1474206b73d0SCy Schubert METHOD_MAY_CONT : METHOD_DONE; 1475206b73d0SCy Schubert ret->decision = DECISION_UNCOND_SUCC; 1476206b73d0SCy Schubert } 1477206b73d0SCy Schubert 1478206b73d0SCy Schubert if (!resp) { 1479206b73d0SCy Schubert wpa_printf(MSG_DEBUG, 1480206b73d0SCy Schubert "EAP-TEAP: No recognized TLVs - send empty response packet"); 1481206b73d0SCy Schubert resp = wpabuf_alloc(1); 1482206b73d0SCy Schubert } 1483206b73d0SCy Schubert 1484206b73d0SCy Schubert send_resp: 1485206b73d0SCy Schubert if (!resp) 1486206b73d0SCy Schubert return 0; 1487206b73d0SCy Schubert 1488206b73d0SCy Schubert wpa_hexdump_buf(MSG_DEBUG, "EAP-TEAP: Encrypting Phase 2 data", resp); 1489206b73d0SCy Schubert if (eap_peer_tls_encrypt(sm, &data->ssl, EAP_TYPE_TEAP, 1490206b73d0SCy Schubert data->teap_version, identifier, 1491206b73d0SCy Schubert resp, out_data)) { 1492206b73d0SCy Schubert wpa_printf(MSG_INFO, 1493206b73d0SCy Schubert "EAP-TEAP: Failed to encrypt a Phase 2 frame"); 1494206b73d0SCy Schubert } 1495206b73d0SCy Schubert wpabuf_free(resp); 1496206b73d0SCy Schubert 1497206b73d0SCy Schubert return 0; 1498206b73d0SCy Schubert } 1499206b73d0SCy Schubert 1500206b73d0SCy Schubert 1501206b73d0SCy Schubert static int eap_teap_decrypt(struct eap_sm *sm, struct eap_teap_data *data, 1502206b73d0SCy Schubert struct eap_method_ret *ret, u8 identifier, 1503206b73d0SCy Schubert const struct wpabuf *in_data, 1504206b73d0SCy Schubert struct wpabuf **out_data) 1505206b73d0SCy Schubert { 1506206b73d0SCy Schubert struct wpabuf *in_decrypted; 1507206b73d0SCy Schubert int res; 1508206b73d0SCy Schubert 1509206b73d0SCy Schubert wpa_printf(MSG_DEBUG, 1510206b73d0SCy Schubert "EAP-TEAP: Received %lu bytes encrypted data for Phase 2", 1511206b73d0SCy Schubert (unsigned long) wpabuf_len(in_data)); 1512206b73d0SCy Schubert 1513206b73d0SCy Schubert if (data->pending_phase2_req) { 1514206b73d0SCy Schubert wpa_printf(MSG_DEBUG, 1515206b73d0SCy Schubert "EAP-TEAP: Pending Phase 2 request - skip decryption and use old data"); 1516206b73d0SCy Schubert /* Clear TLS reassembly state. */ 1517206b73d0SCy Schubert eap_peer_tls_reset_input(&data->ssl); 1518206b73d0SCy Schubert 1519206b73d0SCy Schubert in_decrypted = data->pending_phase2_req; 1520206b73d0SCy Schubert data->pending_phase2_req = NULL; 1521206b73d0SCy Schubert goto continue_req; 1522206b73d0SCy Schubert } 1523206b73d0SCy Schubert 1524206b73d0SCy Schubert if (wpabuf_len(in_data) == 0) { 1525206b73d0SCy Schubert /* Received TLS ACK - requesting more fragments */ 1526206b73d0SCy Schubert res = eap_peer_tls_encrypt(sm, &data->ssl, EAP_TYPE_TEAP, 1527206b73d0SCy Schubert data->teap_version, 1528206b73d0SCy Schubert identifier, NULL, out_data); 1529206b73d0SCy Schubert if (res == 0 && !data->ssl.tls_out && 1530206b73d0SCy Schubert data->on_tx_completion) { 1531206b73d0SCy Schubert wpa_printf(MSG_DEBUG, 1532206b73d0SCy Schubert "EAP-TEAP: Mark authentication completed at full TX of fragments"); 1533206b73d0SCy Schubert ret->methodState = data->on_tx_completion; 1534206b73d0SCy Schubert data->on_tx_completion = 0; 1535206b73d0SCy Schubert ret->decision = DECISION_UNCOND_SUCC; 1536206b73d0SCy Schubert } 1537206b73d0SCy Schubert return res; 1538206b73d0SCy Schubert } 1539206b73d0SCy Schubert 1540206b73d0SCy Schubert res = eap_peer_tls_decrypt(sm, &data->ssl, in_data, &in_decrypted); 1541206b73d0SCy Schubert if (res) 1542206b73d0SCy Schubert return res; 1543206b73d0SCy Schubert 1544206b73d0SCy Schubert continue_req: 1545206b73d0SCy Schubert wpa_hexdump_buf(MSG_MSGDUMP, "EAP-TEAP: Decrypted Phase 2 TLV(s)", 1546206b73d0SCy Schubert in_decrypted); 1547206b73d0SCy Schubert 1548206b73d0SCy Schubert if (wpabuf_len(in_decrypted) < 4) { 1549206b73d0SCy Schubert wpa_printf(MSG_INFO, 1550206b73d0SCy Schubert "EAP-TEAP: Too short Phase 2 TLV frame (len=%lu)", 1551206b73d0SCy Schubert (unsigned long) wpabuf_len(in_decrypted)); 1552206b73d0SCy Schubert wpabuf_free(in_decrypted); 1553206b73d0SCy Schubert return -1; 1554206b73d0SCy Schubert } 1555206b73d0SCy Schubert 1556206b73d0SCy Schubert res = eap_teap_process_decrypted(sm, data, ret, identifier, 1557206b73d0SCy Schubert in_decrypted, out_data); 1558206b73d0SCy Schubert 1559206b73d0SCy Schubert wpabuf_free(in_decrypted); 1560206b73d0SCy Schubert 1561206b73d0SCy Schubert return res; 1562206b73d0SCy Schubert } 1563206b73d0SCy Schubert 1564206b73d0SCy Schubert 1565206b73d0SCy Schubert static void eap_teap_select_pac(struct eap_teap_data *data, 1566206b73d0SCy Schubert const u8 *a_id, size_t a_id_len) 1567206b73d0SCy Schubert { 1568206b73d0SCy Schubert if (!a_id) 1569206b73d0SCy Schubert return; 1570206b73d0SCy Schubert data->current_pac = eap_teap_get_pac(data->pac, a_id, a_id_len, 1571206b73d0SCy Schubert PAC_TYPE_TUNNEL_PAC); 1572206b73d0SCy Schubert if (data->current_pac) { 1573206b73d0SCy Schubert wpa_printf(MSG_DEBUG, 1574206b73d0SCy Schubert "EAP-TEAP: PAC found for this A-ID (PAC-Type %d)", 1575206b73d0SCy Schubert data->current_pac->pac_type); 1576206b73d0SCy Schubert wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-TEAP: A-ID-Info", 1577206b73d0SCy Schubert data->current_pac->a_id_info, 1578206b73d0SCy Schubert data->current_pac->a_id_info_len); 1579206b73d0SCy Schubert } 1580206b73d0SCy Schubert } 1581206b73d0SCy Schubert 1582206b73d0SCy Schubert 1583206b73d0SCy Schubert static int eap_teap_use_pac_opaque(struct eap_sm *sm, 1584206b73d0SCy Schubert struct eap_teap_data *data, 1585206b73d0SCy Schubert struct eap_teap_pac *pac) 1586206b73d0SCy Schubert { 1587206b73d0SCy Schubert u8 *tlv; 1588206b73d0SCy Schubert size_t tlv_len, olen; 1589206b73d0SCy Schubert struct teap_tlv_hdr *ehdr; 1590206b73d0SCy Schubert 1591206b73d0SCy Schubert wpa_printf(MSG_DEBUG, "EAP-TEAP: Add PAC-Opaque TLS extension"); 1592206b73d0SCy Schubert olen = pac->pac_opaque_len; 1593206b73d0SCy Schubert tlv_len = sizeof(*ehdr) + olen; 1594206b73d0SCy Schubert tlv = os_malloc(tlv_len); 1595206b73d0SCy Schubert if (tlv) { 1596206b73d0SCy Schubert ehdr = (struct teap_tlv_hdr *) tlv; 1597206b73d0SCy Schubert ehdr->tlv_type = host_to_be16(PAC_TYPE_PAC_OPAQUE); 1598206b73d0SCy Schubert ehdr->length = host_to_be16(olen); 1599206b73d0SCy Schubert os_memcpy(ehdr + 1, pac->pac_opaque, olen); 1600206b73d0SCy Schubert } 1601206b73d0SCy Schubert if (!tlv || 1602206b73d0SCy Schubert tls_connection_client_hello_ext(sm->ssl_ctx, data->ssl.conn, 1603206b73d0SCy Schubert TLS_EXT_PAC_OPAQUE, 1604206b73d0SCy Schubert tlv, tlv_len) < 0) { 1605206b73d0SCy Schubert wpa_printf(MSG_DEBUG, 1606206b73d0SCy Schubert "EAP-TEAP: Failed to add PAC-Opaque TLS extension"); 1607206b73d0SCy Schubert os_free(tlv); 1608206b73d0SCy Schubert return -1; 1609206b73d0SCy Schubert } 1610206b73d0SCy Schubert os_free(tlv); 1611206b73d0SCy Schubert 1612206b73d0SCy Schubert return 0; 1613206b73d0SCy Schubert } 1614206b73d0SCy Schubert 1615206b73d0SCy Schubert 1616206b73d0SCy Schubert static int eap_teap_clear_pac_opaque_ext(struct eap_sm *sm, 1617206b73d0SCy Schubert struct eap_teap_data *data) 1618206b73d0SCy Schubert { 1619206b73d0SCy Schubert if (tls_connection_client_hello_ext(sm->ssl_ctx, data->ssl.conn, 1620206b73d0SCy Schubert TLS_EXT_PAC_OPAQUE, NULL, 0) < 0) { 1621206b73d0SCy Schubert wpa_printf(MSG_DEBUG, 1622206b73d0SCy Schubert "EAP-TEAP: Failed to remove PAC-Opaque TLS extension"); 1623206b73d0SCy Schubert return -1; 1624206b73d0SCy Schubert } 1625206b73d0SCy Schubert return 0; 1626206b73d0SCy Schubert } 1627206b73d0SCy Schubert 1628206b73d0SCy Schubert 1629206b73d0SCy Schubert static int eap_teap_process_start(struct eap_sm *sm, 1630206b73d0SCy Schubert struct eap_teap_data *data, u8 flags, 1631206b73d0SCy Schubert const u8 *pos, size_t left) 1632206b73d0SCy Schubert { 1633206b73d0SCy Schubert const u8 *a_id = NULL; 1634206b73d0SCy Schubert size_t a_id_len = 0; 1635206b73d0SCy Schubert 1636206b73d0SCy Schubert /* TODO: Support (mostly theoretical) case of TEAP/Start request being 1637206b73d0SCy Schubert * fragmented */ 1638206b73d0SCy Schubert 1639206b73d0SCy Schubert /* EAP-TEAP version negotiation (RFC 7170, Section 3.2) */ 1640206b73d0SCy Schubert data->received_version = flags & EAP_TLS_VERSION_MASK; 1641206b73d0SCy Schubert wpa_printf(MSG_DEBUG, "EAP-TEAP: Start (server ver=%u, own ver=%u)", 1642206b73d0SCy Schubert data->received_version, data->teap_version); 1643206b73d0SCy Schubert if (data->received_version < 1) { 1644206b73d0SCy Schubert /* Version 1 was the first defined version, so reject 0 */ 1645206b73d0SCy Schubert wpa_printf(MSG_INFO, 1646206b73d0SCy Schubert "EAP-TEAP: Server used unknown TEAP version %u", 1647206b73d0SCy Schubert data->received_version); 1648206b73d0SCy Schubert return -1; 1649206b73d0SCy Schubert } 1650206b73d0SCy Schubert if (data->received_version < data->teap_version) 1651206b73d0SCy Schubert data->teap_version = data->received_version; 1652206b73d0SCy Schubert wpa_printf(MSG_DEBUG, "EAP-TEAP: Using TEAP version %d", 1653206b73d0SCy Schubert data->teap_version); 1654206b73d0SCy Schubert wpa_hexdump(MSG_MSGDUMP, "EAP-TEAP: Start message payload", pos, left); 1655206b73d0SCy Schubert 1656206b73d0SCy Schubert /* Parse Authority-ID TLV from Outer TLVs, if present */ 1657206b73d0SCy Schubert if (flags & EAP_TEAP_FLAGS_OUTER_TLV_LEN) { 1658206b73d0SCy Schubert const u8 *outer_pos, *outer_end; 1659206b73d0SCy Schubert u32 outer_tlv_len; 1660206b73d0SCy Schubert 1661206b73d0SCy Schubert if (left < 4) { 1662206b73d0SCy Schubert wpa_printf(MSG_INFO, 1663206b73d0SCy Schubert "EAP-TEAP: Not enough room for the Outer TLV Length field"); 1664206b73d0SCy Schubert return -1; 1665206b73d0SCy Schubert } 1666206b73d0SCy Schubert 1667206b73d0SCy Schubert outer_tlv_len = WPA_GET_BE32(pos); 1668206b73d0SCy Schubert pos += 4; 1669206b73d0SCy Schubert left -= 4; 1670206b73d0SCy Schubert 1671206b73d0SCy Schubert if (outer_tlv_len > left) { 1672206b73d0SCy Schubert wpa_printf(MSG_INFO, 1673206b73d0SCy Schubert "EAP-TEAP: Truncated Outer TLVs field (Outer TLV Length: %u; remaining buffer: %u)", 1674206b73d0SCy Schubert outer_tlv_len, (unsigned int) left); 1675206b73d0SCy Schubert return -1; 1676206b73d0SCy Schubert } 1677206b73d0SCy Schubert 1678206b73d0SCy Schubert outer_pos = pos + left - outer_tlv_len; 1679206b73d0SCy Schubert outer_end = outer_pos + outer_tlv_len; 1680206b73d0SCy Schubert wpa_hexdump(MSG_MSGDUMP, "EAP-TEAP: Start message Outer TLVs", 1681206b73d0SCy Schubert outer_pos, outer_tlv_len); 1682206b73d0SCy Schubert wpabuf_free(data->server_outer_tlvs); 1683206b73d0SCy Schubert data->server_outer_tlvs = wpabuf_alloc_copy(outer_pos, 1684206b73d0SCy Schubert outer_tlv_len); 1685206b73d0SCy Schubert if (!data->server_outer_tlvs) 1686206b73d0SCy Schubert return -1; 1687206b73d0SCy Schubert left -= outer_tlv_len; 1688206b73d0SCy Schubert if (left > 0) { 1689206b73d0SCy Schubert wpa_hexdump(MSG_INFO, 1690206b73d0SCy Schubert "EAP-TEAP: Unexpected TLS Data in Start message", 1691206b73d0SCy Schubert pos, left); 1692206b73d0SCy Schubert return -1; 1693206b73d0SCy Schubert } 1694206b73d0SCy Schubert 1695206b73d0SCy Schubert while (outer_pos < outer_end) { 1696206b73d0SCy Schubert u16 tlv_type, tlv_len; 1697206b73d0SCy Schubert 1698206b73d0SCy Schubert if (outer_end - outer_pos < 4) { 1699206b73d0SCy Schubert wpa_printf(MSG_INFO, 1700206b73d0SCy Schubert "EAP-TEAP: Truncated Outer TLV header"); 1701206b73d0SCy Schubert return -1; 1702206b73d0SCy Schubert } 1703206b73d0SCy Schubert tlv_type = WPA_GET_BE16(outer_pos); 1704206b73d0SCy Schubert outer_pos += 2; 1705206b73d0SCy Schubert tlv_len = WPA_GET_BE16(outer_pos); 1706206b73d0SCy Schubert outer_pos += 2; 1707206b73d0SCy Schubert /* Outer TLVs are required to be optional, so no need to 1708206b73d0SCy Schubert * check the M flag */ 1709206b73d0SCy Schubert tlv_type &= TEAP_TLV_TYPE_MASK; 1710206b73d0SCy Schubert wpa_printf(MSG_DEBUG, 1711206b73d0SCy Schubert "EAP-TEAP: Outer TLV: Type=%u Length=%u", 1712206b73d0SCy Schubert tlv_type, tlv_len); 1713206b73d0SCy Schubert if (outer_end - outer_pos < tlv_len) { 1714206b73d0SCy Schubert wpa_printf(MSG_INFO, 1715206b73d0SCy Schubert "EAP-TEAP: Truncated Outer TLV (Type %u)", 1716206b73d0SCy Schubert tlv_type); 1717206b73d0SCy Schubert return -1; 1718206b73d0SCy Schubert } 1719206b73d0SCy Schubert if (tlv_type == TEAP_TLV_AUTHORITY_ID) { 1720206b73d0SCy Schubert wpa_hexdump(MSG_DEBUG, "EAP-TEAP: Authority-ID", 1721206b73d0SCy Schubert outer_pos, tlv_len); 1722206b73d0SCy Schubert if (a_id) { 1723206b73d0SCy Schubert wpa_printf(MSG_INFO, 1724206b73d0SCy Schubert "EAP-TEAP: Multiple Authority-ID TLVs in TEAP/Start"); 1725206b73d0SCy Schubert return -1; 1726206b73d0SCy Schubert } 1727206b73d0SCy Schubert a_id = outer_pos; 1728206b73d0SCy Schubert a_id_len = tlv_len; 1729206b73d0SCy Schubert } else { 1730206b73d0SCy Schubert wpa_printf(MSG_DEBUG, 1731206b73d0SCy Schubert "EAP-TEAP: Ignore unknown Outer TLV (Type %u)", 1732206b73d0SCy Schubert tlv_type); 1733206b73d0SCy Schubert } 1734206b73d0SCy Schubert outer_pos += tlv_len; 1735206b73d0SCy Schubert } 1736206b73d0SCy Schubert } else if (left > 0) { 1737206b73d0SCy Schubert wpa_hexdump(MSG_INFO, 1738206b73d0SCy Schubert "EAP-TEAP: Unexpected TLS Data in Start message", 1739206b73d0SCy Schubert pos, left); 1740206b73d0SCy Schubert return -1; 1741206b73d0SCy Schubert } 1742206b73d0SCy Schubert 1743206b73d0SCy Schubert eap_teap_select_pac(data, a_id, a_id_len); 1744206b73d0SCy Schubert 1745206b73d0SCy Schubert if (data->resuming && data->current_pac) { 1746206b73d0SCy Schubert wpa_printf(MSG_DEBUG, 1747206b73d0SCy Schubert "EAP-TEAP: Trying to resume session - do not add PAC-Opaque to TLS ClientHello"); 1748206b73d0SCy Schubert if (eap_teap_clear_pac_opaque_ext(sm, data) < 0) 1749206b73d0SCy Schubert return -1; 1750206b73d0SCy Schubert } else if (data->current_pac) { 1751206b73d0SCy Schubert /* 1752206b73d0SCy Schubert * PAC found for the A-ID and we are not resuming an old 1753206b73d0SCy Schubert * session, so add PAC-Opaque extension to ClientHello. 1754206b73d0SCy Schubert */ 1755206b73d0SCy Schubert if (eap_teap_use_pac_opaque(sm, data, data->current_pac) < 0) 1756206b73d0SCy Schubert return -1; 1757206b73d0SCy Schubert } else if (data->provisioning_allowed) { 1758206b73d0SCy Schubert wpa_printf(MSG_DEBUG, 1759206b73d0SCy Schubert "EAP-TEAP: No PAC found - starting provisioning"); 1760206b73d0SCy Schubert if (eap_teap_clear_pac_opaque_ext(sm, data) < 0) 1761206b73d0SCy Schubert return -1; 1762206b73d0SCy Schubert data->provisioning = 1; 1763206b73d0SCy Schubert } 1764206b73d0SCy Schubert 1765206b73d0SCy Schubert return 0; 1766206b73d0SCy Schubert } 1767206b73d0SCy Schubert 1768206b73d0SCy Schubert 1769206b73d0SCy Schubert #ifdef CONFIG_TESTING_OPTIONS 17704b72b91aSCy Schubert static struct wpabuf * eap_teap_add_stub_outer_tlvs(struct eap_teap_data *data, 1771206b73d0SCy Schubert struct wpabuf *resp) 1772206b73d0SCy Schubert { 1773206b73d0SCy Schubert struct wpabuf *resp2; 1774206b73d0SCy Schubert u16 len; 1775206b73d0SCy Schubert const u8 *pos; 1776206b73d0SCy Schubert u8 flags; 1777206b73d0SCy Schubert 1778206b73d0SCy Schubert wpabuf_free(data->peer_outer_tlvs); 1779206b73d0SCy Schubert data->peer_outer_tlvs = wpabuf_alloc(4 + 4); 1780206b73d0SCy Schubert if (!data->peer_outer_tlvs) { 1781206b73d0SCy Schubert wpabuf_free(resp); 1782206b73d0SCy Schubert return NULL; 1783206b73d0SCy Schubert } 1784206b73d0SCy Schubert 17854b72b91aSCy Schubert /* Outer TLVs (stub Vendor-Specific TLV for testing) */ 1786206b73d0SCy Schubert wpabuf_put_be16(data->peer_outer_tlvs, TEAP_TLV_VENDOR_SPECIFIC); 1787206b73d0SCy Schubert wpabuf_put_be16(data->peer_outer_tlvs, 4); 1788206b73d0SCy Schubert wpabuf_put_be32(data->peer_outer_tlvs, EAP_VENDOR_HOSTAP); 17894b72b91aSCy Schubert wpa_hexdump_buf(MSG_DEBUG, "EAP-TEAP: TESTING - Add stub Outer TLVs", 1790206b73d0SCy Schubert data->peer_outer_tlvs); 1791206b73d0SCy Schubert 1792206b73d0SCy Schubert wpa_hexdump_buf(MSG_DEBUG, 1793206b73d0SCy Schubert "EAP-TEAP: TEAP/Start response before modification", 1794206b73d0SCy Schubert resp); 1795206b73d0SCy Schubert resp2 = wpabuf_alloc(wpabuf_len(resp) + 4 + 1796206b73d0SCy Schubert wpabuf_len(data->peer_outer_tlvs)); 1797206b73d0SCy Schubert if (!resp2) { 1798206b73d0SCy Schubert wpabuf_free(resp); 1799206b73d0SCy Schubert return NULL; 1800206b73d0SCy Schubert } 1801206b73d0SCy Schubert 1802206b73d0SCy Schubert pos = wpabuf_head(resp); 1803206b73d0SCy Schubert wpabuf_put_u8(resp2, *pos++); /* Code */ 1804206b73d0SCy Schubert wpabuf_put_u8(resp2, *pos++); /* Identifier */ 1805206b73d0SCy Schubert len = WPA_GET_BE16(pos); 1806206b73d0SCy Schubert pos += 2; 1807206b73d0SCy Schubert wpabuf_put_be16(resp2, len + 4 + wpabuf_len(data->peer_outer_tlvs)); 1808206b73d0SCy Schubert wpabuf_put_u8(resp2, *pos++); /* Type */ 1809206b73d0SCy Schubert /* Flags | Ver (with Outer TLV length included flag set to 1) */ 1810206b73d0SCy Schubert flags = *pos++; 1811206b73d0SCy Schubert if (flags & (EAP_TEAP_FLAGS_OUTER_TLV_LEN | 1812206b73d0SCy Schubert EAP_TLS_FLAGS_LENGTH_INCLUDED)) { 1813206b73d0SCy Schubert wpa_printf(MSG_INFO, 1814206b73d0SCy Schubert "EAP-TEAP: Cannot add Outer TLVs for testing"); 1815206b73d0SCy Schubert wpabuf_free(resp); 1816206b73d0SCy Schubert wpabuf_free(resp2); 1817206b73d0SCy Schubert return NULL; 1818206b73d0SCy Schubert } 1819206b73d0SCy Schubert flags |= EAP_TEAP_FLAGS_OUTER_TLV_LEN; 1820206b73d0SCy Schubert wpabuf_put_u8(resp2, flags); 1821206b73d0SCy Schubert /* Outer TLV Length */ 1822206b73d0SCy Schubert wpabuf_put_be32(resp2, wpabuf_len(data->peer_outer_tlvs)); 1823206b73d0SCy Schubert /* TLS Data */ 1824206b73d0SCy Schubert wpabuf_put_data(resp2, pos, wpabuf_len(resp) - 6); 1825206b73d0SCy Schubert wpabuf_put_buf(resp2, data->peer_outer_tlvs); /* Outer TLVs */ 1826206b73d0SCy Schubert 1827206b73d0SCy Schubert wpabuf_free(resp); 1828206b73d0SCy Schubert wpa_hexdump_buf(MSG_DEBUG, 1829206b73d0SCy Schubert "EAP-TEAP: TEAP/Start response after modification", 1830206b73d0SCy Schubert resp2); 1831206b73d0SCy Schubert return resp2; 1832206b73d0SCy Schubert } 1833206b73d0SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */ 1834206b73d0SCy Schubert 1835206b73d0SCy Schubert 1836206b73d0SCy Schubert static struct wpabuf * eap_teap_process(struct eap_sm *sm, void *priv, 1837206b73d0SCy Schubert struct eap_method_ret *ret, 1838206b73d0SCy Schubert const struct wpabuf *reqData) 1839206b73d0SCy Schubert { 1840206b73d0SCy Schubert const struct eap_hdr *req; 1841206b73d0SCy Schubert size_t left; 1842206b73d0SCy Schubert int res; 1843206b73d0SCy Schubert u8 flags, id; 1844206b73d0SCy Schubert struct wpabuf *resp; 1845206b73d0SCy Schubert const u8 *pos; 1846206b73d0SCy Schubert struct eap_teap_data *data = priv; 1847206b73d0SCy Schubert struct wpabuf msg; 1848206b73d0SCy Schubert 1849206b73d0SCy Schubert pos = eap_peer_tls_process_init(sm, &data->ssl, EAP_TYPE_TEAP, ret, 1850206b73d0SCy Schubert reqData, &left, &flags); 1851206b73d0SCy Schubert if (!pos) 1852206b73d0SCy Schubert return NULL; 1853206b73d0SCy Schubert 1854206b73d0SCy Schubert req = wpabuf_head(reqData); 1855206b73d0SCy Schubert id = req->identifier; 1856206b73d0SCy Schubert 1857206b73d0SCy Schubert if (flags & EAP_TLS_FLAGS_START) { 1858206b73d0SCy Schubert if (eap_teap_process_start(sm, data, flags, pos, left) < 0) 1859206b73d0SCy Schubert return NULL; 1860206b73d0SCy Schubert 1861206b73d0SCy Schubert /* Outer TLVs are not used in further packet processing and 1862206b73d0SCy Schubert * there cannot be TLS Data in this TEAP/Start message, so 1863206b73d0SCy Schubert * enforce that by ignoring whatever data might remain in the 1864206b73d0SCy Schubert * buffer. */ 1865206b73d0SCy Schubert left = 0; 1866206b73d0SCy Schubert } else if (flags & EAP_TEAP_FLAGS_OUTER_TLV_LEN) { 1867206b73d0SCy Schubert /* TODO: RFC 7170, Section 4.3.1 indicates that the unexpected 1868206b73d0SCy Schubert * Outer TLVs MUST be ignored instead of ignoring the full 1869206b73d0SCy Schubert * message. */ 1870206b73d0SCy Schubert wpa_printf(MSG_INFO, 1871206b73d0SCy Schubert "EAP-TEAP: Outer TLVs present in non-Start message -> ignore message"); 1872206b73d0SCy Schubert return NULL; 1873206b73d0SCy Schubert } 1874206b73d0SCy Schubert 1875206b73d0SCy Schubert wpabuf_set(&msg, pos, left); 1876206b73d0SCy Schubert 1877206b73d0SCy Schubert resp = NULL; 1878206b73d0SCy Schubert if (tls_connection_established(sm->ssl_ctx, data->ssl.conn) && 1879206b73d0SCy Schubert !data->resuming) { 1880206b73d0SCy Schubert /* Process tunneled (encrypted) phase 2 data. */ 1881206b73d0SCy Schubert res = eap_teap_decrypt(sm, data, ret, id, &msg, &resp); 1882206b73d0SCy Schubert if (res < 0) { 1883206b73d0SCy Schubert ret->methodState = METHOD_DONE; 1884206b73d0SCy Schubert ret->decision = DECISION_FAIL; 1885206b73d0SCy Schubert /* 1886206b73d0SCy Schubert * Ack possible Alert that may have caused failure in 1887206b73d0SCy Schubert * decryption. 1888206b73d0SCy Schubert */ 1889206b73d0SCy Schubert res = 1; 1890206b73d0SCy Schubert } 1891206b73d0SCy Schubert } else { 1892206b73d0SCy Schubert if (sm->waiting_ext_cert_check && data->pending_resp) { 1893206b73d0SCy Schubert struct eap_peer_config *config = eap_get_config(sm); 1894206b73d0SCy Schubert 1895206b73d0SCy Schubert if (config->pending_ext_cert_check == 1896206b73d0SCy Schubert EXT_CERT_CHECK_GOOD) { 1897206b73d0SCy Schubert wpa_printf(MSG_DEBUG, 1898206b73d0SCy Schubert "EAP-TEAP: External certificate check succeeded - continue handshake"); 1899206b73d0SCy Schubert resp = data->pending_resp; 1900206b73d0SCy Schubert data->pending_resp = NULL; 1901206b73d0SCy Schubert sm->waiting_ext_cert_check = 0; 1902206b73d0SCy Schubert return resp; 1903206b73d0SCy Schubert } 1904206b73d0SCy Schubert 1905206b73d0SCy Schubert if (config->pending_ext_cert_check == 1906206b73d0SCy Schubert EXT_CERT_CHECK_BAD) { 1907206b73d0SCy Schubert wpa_printf(MSG_DEBUG, 1908206b73d0SCy Schubert "EAP-TEAP: External certificate check failed - force authentication failure"); 1909206b73d0SCy Schubert ret->methodState = METHOD_DONE; 1910206b73d0SCy Schubert ret->decision = DECISION_FAIL; 1911206b73d0SCy Schubert sm->waiting_ext_cert_check = 0; 1912206b73d0SCy Schubert return NULL; 1913206b73d0SCy Schubert } 1914206b73d0SCy Schubert 1915206b73d0SCy Schubert wpa_printf(MSG_DEBUG, 1916206b73d0SCy Schubert "EAP-TEAP: Continuing to wait external server certificate validation"); 1917206b73d0SCy Schubert return NULL; 1918206b73d0SCy Schubert } 1919206b73d0SCy Schubert 1920206b73d0SCy Schubert /* Continue processing TLS handshake (phase 1). */ 1921206b73d0SCy Schubert res = eap_peer_tls_process_helper(sm, &data->ssl, 1922206b73d0SCy Schubert EAP_TYPE_TEAP, 1923206b73d0SCy Schubert data->teap_version, id, &msg, 1924206b73d0SCy Schubert &resp); 1925206b73d0SCy Schubert if (res < 0) { 1926206b73d0SCy Schubert wpa_printf(MSG_DEBUG, 1927206b73d0SCy Schubert "EAP-TEAP: TLS processing failed"); 1928206b73d0SCy Schubert ret->methodState = METHOD_DONE; 1929206b73d0SCy Schubert ret->decision = DECISION_FAIL; 1930206b73d0SCy Schubert return resp; 1931206b73d0SCy Schubert } 1932206b73d0SCy Schubert 1933206b73d0SCy Schubert if (sm->waiting_ext_cert_check) { 1934206b73d0SCy Schubert wpa_printf(MSG_DEBUG, 1935206b73d0SCy Schubert "EAP-TEAP: Waiting external server certificate validation"); 1936206b73d0SCy Schubert wpabuf_free(data->pending_resp); 1937206b73d0SCy Schubert data->pending_resp = resp; 1938206b73d0SCy Schubert return NULL; 1939206b73d0SCy Schubert } 1940206b73d0SCy Schubert 1941206b73d0SCy Schubert if (tls_connection_established(sm->ssl_ctx, data->ssl.conn)) { 1942206b73d0SCy Schubert char cipher[80]; 1943206b73d0SCy Schubert 1944206b73d0SCy Schubert wpa_printf(MSG_DEBUG, 1945206b73d0SCy Schubert "EAP-TEAP: TLS done, proceed to Phase 2"); 1946206b73d0SCy Schubert data->tls_cs = 1947206b73d0SCy Schubert tls_connection_get_cipher_suite(data->ssl.conn); 1948206b73d0SCy Schubert wpa_printf(MSG_DEBUG, 1949206b73d0SCy Schubert "EAP-TEAP: TLS cipher suite 0x%04x", 1950206b73d0SCy Schubert data->tls_cs); 1951206b73d0SCy Schubert 1952206b73d0SCy Schubert if (data->provisioning && 1953206b73d0SCy Schubert (!(data->provisioning_allowed & 1954206b73d0SCy Schubert EAP_TEAP_PROV_AUTH) || 1955206b73d0SCy Schubert tls_get_cipher(sm->ssl_ctx, data->ssl.conn, 1956206b73d0SCy Schubert cipher, sizeof(cipher)) < 0 || 1957206b73d0SCy Schubert os_strstr(cipher, "ADH-") || 1958206b73d0SCy Schubert os_strstr(cipher, "anon"))) { 1959206b73d0SCy Schubert wpa_printf(MSG_DEBUG, 1960206b73d0SCy Schubert "EAP-TEAP: Using anonymous (unauthenticated) provisioning"); 1961206b73d0SCy Schubert data->anon_provisioning = 1; 1962206b73d0SCy Schubert } else { 1963206b73d0SCy Schubert data->anon_provisioning = 0; 1964206b73d0SCy Schubert } 1965206b73d0SCy Schubert data->resuming = 0; 1966206b73d0SCy Schubert if (eap_teap_derive_key_auth(sm, data) < 0) { 1967206b73d0SCy Schubert wpa_printf(MSG_DEBUG, 1968206b73d0SCy Schubert "EAP-TEAP: Could not derive keys"); 1969206b73d0SCy Schubert ret->methodState = METHOD_DONE; 1970206b73d0SCy Schubert ret->decision = DECISION_FAIL; 1971206b73d0SCy Schubert wpabuf_free(resp); 1972206b73d0SCy Schubert return NULL; 1973206b73d0SCy Schubert } 1974206b73d0SCy Schubert } 1975206b73d0SCy Schubert 1976206b73d0SCy Schubert if (res == 2) { 1977206b73d0SCy Schubert /* 1978206b73d0SCy Schubert * Application data included in the handshake message. 1979206b73d0SCy Schubert */ 1980206b73d0SCy Schubert wpabuf_free(data->pending_phase2_req); 1981206b73d0SCy Schubert data->pending_phase2_req = resp; 1982206b73d0SCy Schubert resp = NULL; 1983206b73d0SCy Schubert res = eap_teap_decrypt(sm, data, ret, id, &msg, &resp); 1984206b73d0SCy Schubert } 1985206b73d0SCy Schubert } 1986206b73d0SCy Schubert 1987206b73d0SCy Schubert if (res == 1) { 1988206b73d0SCy Schubert wpabuf_free(resp); 1989206b73d0SCy Schubert return eap_peer_tls_build_ack(id, EAP_TYPE_TEAP, 1990206b73d0SCy Schubert data->teap_version); 1991206b73d0SCy Schubert } 1992206b73d0SCy Schubert 1993206b73d0SCy Schubert #ifdef CONFIG_TESTING_OPTIONS 1994206b73d0SCy Schubert if (data->test_outer_tlvs && res == 0 && resp && 1995206b73d0SCy Schubert (flags & EAP_TLS_FLAGS_START) && wpabuf_len(resp) >= 6) 19964b72b91aSCy Schubert resp = eap_teap_add_stub_outer_tlvs(data, resp); 1997206b73d0SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */ 1998206b73d0SCy Schubert 1999206b73d0SCy Schubert return resp; 2000206b73d0SCy Schubert } 2001206b73d0SCy Schubert 2002206b73d0SCy Schubert 2003206b73d0SCy Schubert #if 0 /* TODO */ 2004c1d255d3SCy Schubert static bool eap_teap_has_reauth_data(struct eap_sm *sm, void *priv) 2005206b73d0SCy Schubert { 2006206b73d0SCy Schubert struct eap_teap_data *data = priv; 2007206b73d0SCy Schubert 2008206b73d0SCy Schubert return tls_connection_established(sm->ssl_ctx, data->ssl.conn); 2009206b73d0SCy Schubert } 2010206b73d0SCy Schubert 2011206b73d0SCy Schubert 2012206b73d0SCy Schubert static void eap_teap_deinit_for_reauth(struct eap_sm *sm, void *priv) 2013206b73d0SCy Schubert { 2014206b73d0SCy Schubert struct eap_teap_data *data = priv; 2015206b73d0SCy Schubert 2016206b73d0SCy Schubert if (data->phase2_priv && data->phase2_method && 2017206b73d0SCy Schubert data->phase2_method->deinit_for_reauth) 2018206b73d0SCy Schubert data->phase2_method->deinit_for_reauth(sm, data->phase2_priv); 2019206b73d0SCy Schubert eap_teap_clear(data); 2020206b73d0SCy Schubert } 2021206b73d0SCy Schubert 2022206b73d0SCy Schubert 2023206b73d0SCy Schubert static void * eap_teap_init_for_reauth(struct eap_sm *sm, void *priv) 2024206b73d0SCy Schubert { 2025206b73d0SCy Schubert struct eap_teap_data *data = priv; 2026206b73d0SCy Schubert 2027206b73d0SCy Schubert if (eap_peer_tls_reauth_init(sm, &data->ssl)) { 2028206b73d0SCy Schubert eap_teap_deinit(sm, data); 2029206b73d0SCy Schubert return NULL; 2030206b73d0SCy Schubert } 2031206b73d0SCy Schubert if (data->phase2_priv && data->phase2_method && 2032206b73d0SCy Schubert data->phase2_method->init_for_reauth) 2033206b73d0SCy Schubert data->phase2_method->init_for_reauth(sm, data->phase2_priv); 2034206b73d0SCy Schubert data->phase2_success = 0; 2035206b73d0SCy Schubert data->inner_method_done = 0; 2036206b73d0SCy Schubert data->result_success_done = 0; 2037c1d255d3SCy Schubert data->iresult_verified = 0; 2038206b73d0SCy Schubert data->done_on_tx_completion = 0; 2039206b73d0SCy Schubert data->resuming = 1; 2040206b73d0SCy Schubert data->provisioning = 0; 2041206b73d0SCy Schubert data->anon_provisioning = 0; 2042206b73d0SCy Schubert data->simck_idx = 0; 2043206b73d0SCy Schubert return priv; 2044206b73d0SCy Schubert } 2045206b73d0SCy Schubert #endif 2046206b73d0SCy Schubert 2047206b73d0SCy Schubert 2048206b73d0SCy Schubert static int eap_teap_get_status(struct eap_sm *sm, void *priv, char *buf, 2049206b73d0SCy Schubert size_t buflen, int verbose) 2050206b73d0SCy Schubert { 2051206b73d0SCy Schubert struct eap_teap_data *data = priv; 2052206b73d0SCy Schubert int len, ret; 2053206b73d0SCy Schubert 2054206b73d0SCy Schubert len = eap_peer_tls_status(sm, &data->ssl, buf, buflen, verbose); 2055206b73d0SCy Schubert if (data->phase2_method) { 2056206b73d0SCy Schubert ret = os_snprintf(buf + len, buflen - len, 2057206b73d0SCy Schubert "EAP-TEAP Phase 2 method=%s\n", 2058206b73d0SCy Schubert data->phase2_method->name); 2059206b73d0SCy Schubert if (os_snprintf_error(buflen - len, ret)) 2060206b73d0SCy Schubert return len; 2061206b73d0SCy Schubert len += ret; 2062206b73d0SCy Schubert } 2063206b73d0SCy Schubert return len; 2064206b73d0SCy Schubert } 2065206b73d0SCy Schubert 2066206b73d0SCy Schubert 2067c1d255d3SCy Schubert static bool eap_teap_isKeyAvailable(struct eap_sm *sm, void *priv) 2068206b73d0SCy Schubert { 2069206b73d0SCy Schubert struct eap_teap_data *data = priv; 2070206b73d0SCy Schubert 2071206b73d0SCy Schubert return data->success; 2072206b73d0SCy Schubert } 2073206b73d0SCy Schubert 2074206b73d0SCy Schubert 2075206b73d0SCy Schubert static u8 * eap_teap_getKey(struct eap_sm *sm, void *priv, size_t *len) 2076206b73d0SCy Schubert { 2077206b73d0SCy Schubert struct eap_teap_data *data = priv; 2078206b73d0SCy Schubert u8 *key; 2079206b73d0SCy Schubert 2080206b73d0SCy Schubert if (!data->success) 2081206b73d0SCy Schubert return NULL; 2082206b73d0SCy Schubert 2083206b73d0SCy Schubert key = os_memdup(data->key_data, EAP_TEAP_KEY_LEN); 2084206b73d0SCy Schubert if (!key) 2085206b73d0SCy Schubert return NULL; 2086206b73d0SCy Schubert 2087206b73d0SCy Schubert *len = EAP_TEAP_KEY_LEN; 2088206b73d0SCy Schubert 2089206b73d0SCy Schubert return key; 2090206b73d0SCy Schubert } 2091206b73d0SCy Schubert 2092206b73d0SCy Schubert 2093206b73d0SCy Schubert static u8 * eap_teap_get_session_id(struct eap_sm *sm, void *priv, size_t *len) 2094206b73d0SCy Schubert { 2095206b73d0SCy Schubert struct eap_teap_data *data = priv; 2096206b73d0SCy Schubert u8 *id; 2097206b73d0SCy Schubert 2098206b73d0SCy Schubert if (!data->success || !data->session_id) 2099206b73d0SCy Schubert return NULL; 2100206b73d0SCy Schubert 2101206b73d0SCy Schubert id = os_memdup(data->session_id, data->id_len); 2102206b73d0SCy Schubert if (!id) 2103206b73d0SCy Schubert return NULL; 2104206b73d0SCy Schubert 2105206b73d0SCy Schubert *len = data->id_len; 2106206b73d0SCy Schubert 2107206b73d0SCy Schubert return id; 2108206b73d0SCy Schubert } 2109206b73d0SCy Schubert 2110206b73d0SCy Schubert 2111206b73d0SCy Schubert static u8 * eap_teap_get_emsk(struct eap_sm *sm, void *priv, size_t *len) 2112206b73d0SCy Schubert { 2113206b73d0SCy Schubert struct eap_teap_data *data = priv; 2114206b73d0SCy Schubert u8 *key; 2115206b73d0SCy Schubert 2116206b73d0SCy Schubert if (!data->success) 2117206b73d0SCy Schubert return NULL; 2118206b73d0SCy Schubert 2119206b73d0SCy Schubert key = os_memdup(data->emsk, EAP_EMSK_LEN); 2120206b73d0SCy Schubert if (!key) 2121206b73d0SCy Schubert return NULL; 2122206b73d0SCy Schubert 2123206b73d0SCy Schubert *len = EAP_EMSK_LEN; 2124206b73d0SCy Schubert 2125206b73d0SCy Schubert return key; 2126206b73d0SCy Schubert } 2127206b73d0SCy Schubert 2128206b73d0SCy Schubert 2129206b73d0SCy Schubert int eap_peer_teap_register(void) 2130206b73d0SCy Schubert { 2131206b73d0SCy Schubert struct eap_method *eap; 2132206b73d0SCy Schubert 2133206b73d0SCy Schubert eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION, 2134206b73d0SCy Schubert EAP_VENDOR_IETF, EAP_TYPE_TEAP, "TEAP"); 2135206b73d0SCy Schubert if (!eap) 2136206b73d0SCy Schubert return -1; 2137206b73d0SCy Schubert 2138206b73d0SCy Schubert eap->init = eap_teap_init; 2139206b73d0SCy Schubert eap->deinit = eap_teap_deinit; 2140206b73d0SCy Schubert eap->process = eap_teap_process; 2141206b73d0SCy Schubert eap->isKeyAvailable = eap_teap_isKeyAvailable; 2142206b73d0SCy Schubert eap->getKey = eap_teap_getKey; 2143206b73d0SCy Schubert eap->getSessionId = eap_teap_get_session_id; 2144206b73d0SCy Schubert eap->get_status = eap_teap_get_status; 2145206b73d0SCy Schubert #if 0 /* TODO */ 2146206b73d0SCy Schubert eap->has_reauth_data = eap_teap_has_reauth_data; 2147206b73d0SCy Schubert eap->deinit_for_reauth = eap_teap_deinit_for_reauth; 2148206b73d0SCy Schubert eap->init_for_reauth = eap_teap_init_for_reauth; 2149206b73d0SCy Schubert #endif 2150206b73d0SCy Schubert eap->get_emsk = eap_teap_get_emsk; 2151206b73d0SCy Schubert 2152206b73d0SCy Schubert return eap_peer_method_register(eap); 2153206b73d0SCy Schubert } 2154