1206b73d0SCy Schubert /* 2206b73d0SCy Schubert * EAP-TEAP server (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/aes_wrap.h" 13206b73d0SCy Schubert #include "crypto/tls.h" 14206b73d0SCy Schubert #include "crypto/random.h" 15206b73d0SCy Schubert #include "eap_common/eap_teap_common.h" 16206b73d0SCy Schubert #include "eap_i.h" 17206b73d0SCy Schubert #include "eap_tls_common.h" 18206b73d0SCy Schubert 19206b73d0SCy Schubert 20206b73d0SCy Schubert static void eap_teap_reset(struct eap_sm *sm, void *priv); 21206b73d0SCy Schubert 22206b73d0SCy Schubert 23206b73d0SCy Schubert /* Private PAC-Opaque TLV types */ 24206b73d0SCy Schubert #define PAC_OPAQUE_TYPE_PAD 0 25206b73d0SCy Schubert #define PAC_OPAQUE_TYPE_KEY 1 26206b73d0SCy Schubert #define PAC_OPAQUE_TYPE_LIFETIME 2 27206b73d0SCy Schubert #define PAC_OPAQUE_TYPE_IDENTITY 3 28206b73d0SCy Schubert 29206b73d0SCy Schubert struct eap_teap_data { 30206b73d0SCy Schubert struct eap_ssl_data ssl; 31206b73d0SCy Schubert enum { 32206b73d0SCy Schubert START, PHASE1, PHASE1B, PHASE2_START, PHASE2_ID, 33206b73d0SCy Schubert PHASE2_BASIC_AUTH, PHASE2_METHOD, CRYPTO_BINDING, REQUEST_PAC, 34c1d255d3SCy Schubert FAILURE_SEND_RESULT, SUCCESS_SEND_RESULT, SUCCESS, FAILURE 35206b73d0SCy Schubert } state; 36206b73d0SCy Schubert 37206b73d0SCy Schubert u8 teap_version; 38206b73d0SCy Schubert u8 peer_version; 39206b73d0SCy Schubert u16 tls_cs; 40206b73d0SCy Schubert 41206b73d0SCy Schubert const struct eap_method *phase2_method; 42206b73d0SCy Schubert void *phase2_priv; 43206b73d0SCy Schubert 44206b73d0SCy Schubert u8 crypto_binding_nonce[32]; 45206b73d0SCy Schubert int final_result; 46206b73d0SCy Schubert 47206b73d0SCy Schubert u8 simck_msk[EAP_TEAP_SIMCK_LEN]; 48206b73d0SCy Schubert u8 cmk_msk[EAP_TEAP_CMK_LEN]; 49206b73d0SCy Schubert u8 simck_emsk[EAP_TEAP_SIMCK_LEN]; 50206b73d0SCy Schubert u8 cmk_emsk[EAP_TEAP_CMK_LEN]; 51206b73d0SCy Schubert int simck_idx; 52206b73d0SCy Schubert int cmk_emsk_available; 53206b73d0SCy Schubert 54206b73d0SCy Schubert u8 pac_opaque_encr[16]; 55206b73d0SCy Schubert u8 *srv_id; 56206b73d0SCy Schubert size_t srv_id_len; 57206b73d0SCy Schubert char *srv_id_info; 58206b73d0SCy Schubert 59c1d255d3SCy Schubert unsigned int basic_auth_not_done:1; 60c1d255d3SCy Schubert unsigned int inner_eap_not_done:1; 61206b73d0SCy Schubert int anon_provisioning; 62c1d255d3SCy Schubert int skipped_inner_auth; 63206b73d0SCy Schubert int send_new_pac; /* server triggered re-keying of Tunnel PAC */ 64206b73d0SCy Schubert struct wpabuf *pending_phase2_resp; 65206b73d0SCy Schubert struct wpabuf *server_outer_tlvs; 66206b73d0SCy Schubert struct wpabuf *peer_outer_tlvs; 67c1d255d3SCy Schubert u8 *identity; /* from PAC-Opaque or client certificate */ 68206b73d0SCy Schubert size_t identity_len; 69206b73d0SCy Schubert int eap_seq; 70206b73d0SCy Schubert int tnc_started; 71206b73d0SCy Schubert 72206b73d0SCy Schubert int pac_key_lifetime; 73206b73d0SCy Schubert int pac_key_refresh_time; 74206b73d0SCy Schubert 75206b73d0SCy Schubert enum teap_error_codes error_code; 76c1d255d3SCy Schubert enum teap_identity_types cur_id_type; 77*a90b9d01SCy Schubert 78*a90b9d01SCy Schubert bool check_crypto_binding; 79206b73d0SCy Schubert }; 80206b73d0SCy Schubert 81206b73d0SCy Schubert 82206b73d0SCy Schubert static int eap_teap_process_phase2_start(struct eap_sm *sm, 83206b73d0SCy Schubert struct eap_teap_data *data); 84*a90b9d01SCy Schubert static int eap_teap_phase2_init(struct eap_sm *sm, struct eap_teap_data *data, 85*a90b9d01SCy Schubert int vendor, enum eap_type eap_type); 86206b73d0SCy Schubert 87206b73d0SCy Schubert 88206b73d0SCy Schubert static const char * eap_teap_state_txt(int state) 89206b73d0SCy Schubert { 90206b73d0SCy Schubert switch (state) { 91206b73d0SCy Schubert case START: 92206b73d0SCy Schubert return "START"; 93206b73d0SCy Schubert case PHASE1: 94206b73d0SCy Schubert return "PHASE1"; 95206b73d0SCy Schubert case PHASE1B: 96206b73d0SCy Schubert return "PHASE1B"; 97206b73d0SCy Schubert case PHASE2_START: 98206b73d0SCy Schubert return "PHASE2_START"; 99206b73d0SCy Schubert case PHASE2_ID: 100206b73d0SCy Schubert return "PHASE2_ID"; 101206b73d0SCy Schubert case PHASE2_BASIC_AUTH: 102206b73d0SCy Schubert return "PHASE2_BASIC_AUTH"; 103206b73d0SCy Schubert case PHASE2_METHOD: 104206b73d0SCy Schubert return "PHASE2_METHOD"; 105206b73d0SCy Schubert case CRYPTO_BINDING: 106206b73d0SCy Schubert return "CRYPTO_BINDING"; 107206b73d0SCy Schubert case REQUEST_PAC: 108206b73d0SCy Schubert return "REQUEST_PAC"; 109206b73d0SCy Schubert case FAILURE_SEND_RESULT: 110206b73d0SCy Schubert return "FAILURE_SEND_RESULT"; 111c1d255d3SCy Schubert case SUCCESS_SEND_RESULT: 112c1d255d3SCy Schubert return "SUCCESS_SEND_RESULT"; 113206b73d0SCy Schubert case SUCCESS: 114206b73d0SCy Schubert return "SUCCESS"; 115206b73d0SCy Schubert case FAILURE: 116206b73d0SCy Schubert return "FAILURE"; 117206b73d0SCy Schubert default: 118206b73d0SCy Schubert return "Unknown?!"; 119206b73d0SCy Schubert } 120206b73d0SCy Schubert } 121206b73d0SCy Schubert 122206b73d0SCy Schubert 123206b73d0SCy Schubert static void eap_teap_state(struct eap_teap_data *data, int state) 124206b73d0SCy Schubert { 125206b73d0SCy Schubert wpa_printf(MSG_DEBUG, "EAP-TEAP: %s -> %s", 126206b73d0SCy Schubert eap_teap_state_txt(data->state), 127206b73d0SCy Schubert eap_teap_state_txt(state)); 128206b73d0SCy Schubert data->state = state; 129206b73d0SCy Schubert } 130206b73d0SCy Schubert 131206b73d0SCy Schubert 132c1d255d3SCy Schubert static enum eap_type eap_teap_req_failure(struct eap_teap_data *data, 133206b73d0SCy Schubert enum teap_error_codes error) 134206b73d0SCy Schubert { 135206b73d0SCy Schubert eap_teap_state(data, FAILURE_SEND_RESULT); 136206b73d0SCy Schubert return EAP_TYPE_NONE; 137206b73d0SCy Schubert } 138206b73d0SCy Schubert 139206b73d0SCy Schubert 140206b73d0SCy Schubert static int eap_teap_session_ticket_cb(void *ctx, const u8 *ticket, size_t len, 141206b73d0SCy Schubert const u8 *client_random, 142206b73d0SCy Schubert const u8 *server_random, 143206b73d0SCy Schubert u8 *master_secret) 144206b73d0SCy Schubert { 145206b73d0SCy Schubert struct eap_teap_data *data = ctx; 146206b73d0SCy Schubert const u8 *pac_opaque; 147206b73d0SCy Schubert size_t pac_opaque_len; 148206b73d0SCy Schubert u8 *buf, *pos, *end, *pac_key = NULL; 149206b73d0SCy Schubert os_time_t lifetime = 0; 150206b73d0SCy Schubert struct os_time now; 151206b73d0SCy Schubert u8 *identity = NULL; 152206b73d0SCy Schubert size_t identity_len = 0; 153206b73d0SCy Schubert 154206b73d0SCy Schubert wpa_printf(MSG_DEBUG, "EAP-TEAP: SessionTicket callback"); 155206b73d0SCy Schubert wpa_hexdump(MSG_DEBUG, "EAP-TEAP: SessionTicket (PAC-Opaque)", 156206b73d0SCy Schubert ticket, len); 157206b73d0SCy Schubert 158206b73d0SCy Schubert if (len < 4 || WPA_GET_BE16(ticket) != PAC_TYPE_PAC_OPAQUE) { 159206b73d0SCy Schubert wpa_printf(MSG_DEBUG, "EAP-TEAP: Ignore invalid SessionTicket"); 160206b73d0SCy Schubert return 0; 161206b73d0SCy Schubert } 162206b73d0SCy Schubert 163206b73d0SCy Schubert pac_opaque_len = WPA_GET_BE16(ticket + 2); 164206b73d0SCy Schubert pac_opaque = ticket + 4; 165206b73d0SCy Schubert if (pac_opaque_len < 8 || pac_opaque_len % 8 || 166206b73d0SCy Schubert pac_opaque_len > len - 4) { 167206b73d0SCy Schubert wpa_printf(MSG_DEBUG, 168206b73d0SCy Schubert "EAP-TEAP: Ignore invalid PAC-Opaque (len=%lu left=%lu)", 169206b73d0SCy Schubert (unsigned long) pac_opaque_len, 170206b73d0SCy Schubert (unsigned long) len); 171206b73d0SCy Schubert return 0; 172206b73d0SCy Schubert } 173206b73d0SCy Schubert wpa_hexdump(MSG_DEBUG, "EAP-TEAP: Received PAC-Opaque", 174206b73d0SCy Schubert pac_opaque, pac_opaque_len); 175206b73d0SCy Schubert 176206b73d0SCy Schubert buf = os_malloc(pac_opaque_len - 8); 177206b73d0SCy Schubert if (!buf) { 178206b73d0SCy Schubert wpa_printf(MSG_DEBUG, 179206b73d0SCy Schubert "EAP-TEAP: Failed to allocate memory for decrypting PAC-Opaque"); 180206b73d0SCy Schubert return 0; 181206b73d0SCy Schubert } 182206b73d0SCy Schubert 183206b73d0SCy Schubert if (aes_unwrap(data->pac_opaque_encr, sizeof(data->pac_opaque_encr), 184206b73d0SCy Schubert (pac_opaque_len - 8) / 8, pac_opaque, buf) < 0) { 185206b73d0SCy Schubert wpa_printf(MSG_DEBUG, "EAP-TEAP: Failed to decrypt PAC-Opaque"); 186206b73d0SCy Schubert os_free(buf); 187206b73d0SCy Schubert /* 188206b73d0SCy Schubert * This may have been caused by server changing the PAC-Opaque 189206b73d0SCy Schubert * encryption key, so just ignore this PAC-Opaque instead of 190206b73d0SCy Schubert * failing the authentication completely. Provisioning can now 191206b73d0SCy Schubert * be used to provision a new PAC. 192206b73d0SCy Schubert */ 193206b73d0SCy Schubert return 0; 194206b73d0SCy Schubert } 195206b73d0SCy Schubert 196206b73d0SCy Schubert end = buf + pac_opaque_len - 8; 197206b73d0SCy Schubert wpa_hexdump_key(MSG_DEBUG, "EAP-TEAP: Decrypted PAC-Opaque", 198206b73d0SCy Schubert buf, end - buf); 199206b73d0SCy Schubert 200206b73d0SCy Schubert pos = buf; 201206b73d0SCy Schubert while (end - pos > 1) { 202206b73d0SCy Schubert u8 id, elen; 203206b73d0SCy Schubert 204206b73d0SCy Schubert id = *pos++; 205206b73d0SCy Schubert elen = *pos++; 206206b73d0SCy Schubert if (elen > end - pos) 207206b73d0SCy Schubert break; 208206b73d0SCy Schubert 209206b73d0SCy Schubert switch (id) { 210206b73d0SCy Schubert case PAC_OPAQUE_TYPE_PAD: 211206b73d0SCy Schubert goto done; 212206b73d0SCy Schubert case PAC_OPAQUE_TYPE_KEY: 213206b73d0SCy Schubert if (elen != EAP_TEAP_PAC_KEY_LEN) { 214206b73d0SCy Schubert wpa_printf(MSG_DEBUG, 215206b73d0SCy Schubert "EAP-TEAP: Invalid PAC-Key length %d", 216206b73d0SCy Schubert elen); 217206b73d0SCy Schubert os_free(buf); 218206b73d0SCy Schubert return -1; 219206b73d0SCy Schubert } 220206b73d0SCy Schubert pac_key = pos; 221206b73d0SCy Schubert wpa_hexdump_key(MSG_DEBUG, 222206b73d0SCy Schubert "EAP-TEAP: PAC-Key from decrypted PAC-Opaque", 223206b73d0SCy Schubert pac_key, EAP_TEAP_PAC_KEY_LEN); 224206b73d0SCy Schubert break; 225206b73d0SCy Schubert case PAC_OPAQUE_TYPE_LIFETIME: 226206b73d0SCy Schubert if (elen != 4) { 227206b73d0SCy Schubert wpa_printf(MSG_DEBUG, 228206b73d0SCy Schubert "EAP-TEAP: Invalid PAC-Key lifetime length %d", 229206b73d0SCy Schubert elen); 230206b73d0SCy Schubert os_free(buf); 231206b73d0SCy Schubert return -1; 232206b73d0SCy Schubert } 233206b73d0SCy Schubert lifetime = WPA_GET_BE32(pos); 234206b73d0SCy Schubert break; 235206b73d0SCy Schubert case PAC_OPAQUE_TYPE_IDENTITY: 236206b73d0SCy Schubert identity = pos; 237206b73d0SCy Schubert identity_len = elen; 238206b73d0SCy Schubert break; 239206b73d0SCy Schubert } 240206b73d0SCy Schubert 241206b73d0SCy Schubert pos += elen; 242206b73d0SCy Schubert } 243206b73d0SCy Schubert done: 244206b73d0SCy Schubert 245206b73d0SCy Schubert if (!pac_key) { 246206b73d0SCy Schubert wpa_printf(MSG_DEBUG, 247206b73d0SCy Schubert "EAP-TEAP: No PAC-Key included in PAC-Opaque"); 248206b73d0SCy Schubert os_free(buf); 249206b73d0SCy Schubert return -1; 250206b73d0SCy Schubert } 251206b73d0SCy Schubert 252206b73d0SCy Schubert if (identity) { 253206b73d0SCy Schubert wpa_hexdump_ascii(MSG_DEBUG, 254206b73d0SCy Schubert "EAP-TEAP: Identity from PAC-Opaque", 255206b73d0SCy Schubert identity, identity_len); 256206b73d0SCy Schubert os_free(data->identity); 257206b73d0SCy Schubert data->identity = os_malloc(identity_len); 258206b73d0SCy Schubert if (data->identity) { 259206b73d0SCy Schubert os_memcpy(data->identity, identity, identity_len); 260206b73d0SCy Schubert data->identity_len = identity_len; 261206b73d0SCy Schubert } 262206b73d0SCy Schubert } 263206b73d0SCy Schubert 264206b73d0SCy Schubert if (os_get_time(&now) < 0 || lifetime <= 0 || now.sec > lifetime) { 265206b73d0SCy Schubert wpa_printf(MSG_DEBUG, 266206b73d0SCy Schubert "EAP-TEAP: PAC-Key not valid anymore (lifetime=%ld now=%ld)", 267206b73d0SCy Schubert lifetime, now.sec); 268206b73d0SCy Schubert data->send_new_pac = 2; 269206b73d0SCy Schubert /* 270206b73d0SCy Schubert * Allow PAC to be used to allow a PAC update with some level 271206b73d0SCy Schubert * of server authentication (i.e., do not fall back to full TLS 272206b73d0SCy Schubert * handshake since we cannot be sure that the peer would be 273206b73d0SCy Schubert * able to validate server certificate now). However, reject 274206b73d0SCy Schubert * the authentication since the PAC was not valid anymore. Peer 275206b73d0SCy Schubert * can connect again with the newly provisioned PAC after this. 276206b73d0SCy Schubert */ 277206b73d0SCy Schubert } else if (lifetime - now.sec < data->pac_key_refresh_time) { 278206b73d0SCy Schubert wpa_printf(MSG_DEBUG, 279206b73d0SCy Schubert "EAP-TEAP: PAC-Key soft timeout; send an update if authentication succeeds"); 280206b73d0SCy Schubert data->send_new_pac = 1; 281206b73d0SCy Schubert } 282206b73d0SCy Schubert 283206b73d0SCy Schubert /* EAP-TEAP uses PAC-Key as the TLS master_secret */ 284206b73d0SCy Schubert os_memcpy(master_secret, pac_key, EAP_TEAP_PAC_KEY_LEN); 285206b73d0SCy Schubert 286206b73d0SCy Schubert os_free(buf); 287206b73d0SCy Schubert 288206b73d0SCy Schubert return 1; 289206b73d0SCy Schubert } 290206b73d0SCy Schubert 291206b73d0SCy Schubert 292206b73d0SCy Schubert static int eap_teap_derive_key_auth(struct eap_sm *sm, 293206b73d0SCy Schubert struct eap_teap_data *data) 294206b73d0SCy Schubert { 295206b73d0SCy Schubert int res; 296206b73d0SCy Schubert 297206b73d0SCy Schubert /* RFC 7170, Section 5.1 */ 298c1d255d3SCy Schubert res = tls_connection_export_key(sm->cfg->ssl_ctx, data->ssl.conn, 299206b73d0SCy Schubert TEAP_TLS_EXPORTER_LABEL_SKS, NULL, 0, 300206b73d0SCy Schubert data->simck_msk, EAP_TEAP_SIMCK_LEN); 301206b73d0SCy Schubert if (res) 302206b73d0SCy Schubert return res; 303206b73d0SCy Schubert wpa_hexdump_key(MSG_DEBUG, 304206b73d0SCy Schubert "EAP-TEAP: session_key_seed (S-IMCK[0])", 305206b73d0SCy Schubert data->simck_msk, EAP_TEAP_SIMCK_LEN); 306206b73d0SCy Schubert os_memcpy(data->simck_emsk, data->simck_msk, EAP_TEAP_SIMCK_LEN); 307206b73d0SCy Schubert data->simck_idx = 0; 308206b73d0SCy Schubert return 0; 309206b73d0SCy Schubert } 310206b73d0SCy Schubert 311206b73d0SCy Schubert 312206b73d0SCy Schubert static int eap_teap_update_icmk(struct eap_sm *sm, struct eap_teap_data *data) 313206b73d0SCy Schubert { 314206b73d0SCy Schubert u8 *msk = NULL, *emsk = NULL; 315206b73d0SCy Schubert size_t msk_len = 0, emsk_len = 0; 316206b73d0SCy Schubert int res; 317206b73d0SCy Schubert 318206b73d0SCy Schubert wpa_printf(MSG_DEBUG, "EAP-TEAP: Deriving ICMK[%d] (S-IMCK and CMK)", 319206b73d0SCy Schubert data->simck_idx + 1); 320206b73d0SCy Schubert 321c1d255d3SCy Schubert if (sm->cfg->eap_teap_auth == 1) 322c1d255d3SCy Schubert return eap_teap_derive_cmk_basic_pw_auth(data->tls_cs, 323c1d255d3SCy Schubert data->simck_msk, 324206b73d0SCy Schubert data->cmk_msk); 325206b73d0SCy Schubert 326206b73d0SCy Schubert if (!data->phase2_method || !data->phase2_priv) { 327206b73d0SCy Schubert wpa_printf(MSG_INFO, "EAP-TEAP: Phase 2 method not available"); 328206b73d0SCy Schubert return -1; 329206b73d0SCy Schubert } 330206b73d0SCy Schubert 331206b73d0SCy Schubert if (data->phase2_method->getKey) { 332206b73d0SCy Schubert msk = data->phase2_method->getKey(sm, data->phase2_priv, 333206b73d0SCy Schubert &msk_len); 334206b73d0SCy Schubert if (!msk) { 335206b73d0SCy Schubert wpa_printf(MSG_INFO, 336206b73d0SCy Schubert "EAP-TEAP: Could not fetch Phase 2 MSK"); 337206b73d0SCy Schubert return -1; 338206b73d0SCy Schubert } 339206b73d0SCy Schubert } 340206b73d0SCy Schubert 341206b73d0SCy Schubert if (data->phase2_method->get_emsk) { 342206b73d0SCy Schubert emsk = data->phase2_method->get_emsk(sm, data->phase2_priv, 343206b73d0SCy Schubert &emsk_len); 344206b73d0SCy Schubert } 345206b73d0SCy Schubert 346c1d255d3SCy Schubert res = eap_teap_derive_imck(data->tls_cs, 347c1d255d3SCy Schubert data->simck_msk, data->simck_emsk, 348206b73d0SCy Schubert msk, msk_len, emsk, emsk_len, 349206b73d0SCy Schubert data->simck_msk, data->cmk_msk, 350206b73d0SCy Schubert data->simck_emsk, data->cmk_emsk); 351206b73d0SCy Schubert bin_clear_free(msk, msk_len); 352206b73d0SCy Schubert bin_clear_free(emsk, emsk_len); 353206b73d0SCy Schubert if (res == 0) { 354206b73d0SCy Schubert data->simck_idx++; 355206b73d0SCy Schubert if (emsk) 356206b73d0SCy Schubert data->cmk_emsk_available = 1; 357206b73d0SCy Schubert } 358206b73d0SCy Schubert return 0; 359206b73d0SCy Schubert } 360206b73d0SCy Schubert 361206b73d0SCy Schubert 362206b73d0SCy Schubert static void * eap_teap_init(struct eap_sm *sm) 363206b73d0SCy Schubert { 364206b73d0SCy Schubert struct eap_teap_data *data; 365206b73d0SCy Schubert 366206b73d0SCy Schubert data = os_zalloc(sizeof(*data)); 367206b73d0SCy Schubert if (!data) 368206b73d0SCy Schubert return NULL; 369206b73d0SCy Schubert data->teap_version = EAP_TEAP_VERSION; 370206b73d0SCy Schubert data->state = START; 371206b73d0SCy Schubert 372c1d255d3SCy Schubert if (eap_server_tls_ssl_init(sm, &data->ssl, 373c1d255d3SCy Schubert sm->cfg->eap_teap_auth == 2 ? 2 : 0, 374c1d255d3SCy Schubert EAP_TYPE_TEAP)) { 375206b73d0SCy Schubert wpa_printf(MSG_INFO, "EAP-TEAP: Failed to initialize SSL."); 376206b73d0SCy Schubert eap_teap_reset(sm, data); 377206b73d0SCy Schubert return NULL; 378206b73d0SCy Schubert } 379206b73d0SCy Schubert 380206b73d0SCy Schubert /* TODO: Add anon-DH TLS cipher suites (and if one is negotiated, 381206b73d0SCy Schubert * enforce inner EAP with mutual authentication to be used) */ 382206b73d0SCy Schubert 383c1d255d3SCy Schubert if (tls_connection_set_session_ticket_cb(sm->cfg->ssl_ctx, 384c1d255d3SCy Schubert data->ssl.conn, 385206b73d0SCy Schubert eap_teap_session_ticket_cb, 386206b73d0SCy Schubert data) < 0) { 387206b73d0SCy Schubert wpa_printf(MSG_INFO, 388206b73d0SCy Schubert "EAP-TEAP: Failed to set SessionTicket callback"); 389206b73d0SCy Schubert eap_teap_reset(sm, data); 390206b73d0SCy Schubert return NULL; 391206b73d0SCy Schubert } 392206b73d0SCy Schubert 393c1d255d3SCy Schubert if (!sm->cfg->pac_opaque_encr_key) { 394206b73d0SCy Schubert wpa_printf(MSG_INFO, 395206b73d0SCy Schubert "EAP-TEAP: No PAC-Opaque encryption key configured"); 396206b73d0SCy Schubert eap_teap_reset(sm, data); 397206b73d0SCy Schubert return NULL; 398206b73d0SCy Schubert } 399c1d255d3SCy Schubert os_memcpy(data->pac_opaque_encr, sm->cfg->pac_opaque_encr_key, 400206b73d0SCy Schubert sizeof(data->pac_opaque_encr)); 401206b73d0SCy Schubert 402c1d255d3SCy Schubert if (!sm->cfg->eap_fast_a_id) { 403206b73d0SCy Schubert wpa_printf(MSG_INFO, "EAP-TEAP: No A-ID configured"); 404206b73d0SCy Schubert eap_teap_reset(sm, data); 405206b73d0SCy Schubert return NULL; 406206b73d0SCy Schubert } 407c1d255d3SCy Schubert data->srv_id = os_malloc(sm->cfg->eap_fast_a_id_len); 408206b73d0SCy Schubert if (!data->srv_id) { 409206b73d0SCy Schubert eap_teap_reset(sm, data); 410206b73d0SCy Schubert return NULL; 411206b73d0SCy Schubert } 412c1d255d3SCy Schubert os_memcpy(data->srv_id, sm->cfg->eap_fast_a_id, 413c1d255d3SCy Schubert sm->cfg->eap_fast_a_id_len); 414c1d255d3SCy Schubert data->srv_id_len = sm->cfg->eap_fast_a_id_len; 415206b73d0SCy Schubert 416c1d255d3SCy Schubert if (!sm->cfg->eap_fast_a_id_info) { 417206b73d0SCy Schubert wpa_printf(MSG_INFO, "EAP-TEAP: No A-ID-Info configured"); 418206b73d0SCy Schubert eap_teap_reset(sm, data); 419206b73d0SCy Schubert return NULL; 420206b73d0SCy Schubert } 421c1d255d3SCy Schubert data->srv_id_info = os_strdup(sm->cfg->eap_fast_a_id_info); 422206b73d0SCy Schubert if (!data->srv_id_info) { 423206b73d0SCy Schubert eap_teap_reset(sm, data); 424206b73d0SCy Schubert return NULL; 425206b73d0SCy Schubert } 426206b73d0SCy Schubert 427206b73d0SCy Schubert /* PAC-Key lifetime in seconds (hard limit) */ 428c1d255d3SCy Schubert data->pac_key_lifetime = sm->cfg->pac_key_lifetime; 429206b73d0SCy Schubert 430206b73d0SCy Schubert /* 431206b73d0SCy Schubert * PAC-Key refresh time in seconds (soft limit on remaining hard 432206b73d0SCy Schubert * limit). The server will generate a new PAC-Key when this number of 433206b73d0SCy Schubert * seconds (or fewer) of the lifetime remains. 434206b73d0SCy Schubert */ 435c1d255d3SCy Schubert data->pac_key_refresh_time = sm->cfg->pac_key_refresh_time; 436206b73d0SCy Schubert 437206b73d0SCy Schubert return data; 438206b73d0SCy Schubert } 439206b73d0SCy Schubert 440206b73d0SCy Schubert 441206b73d0SCy Schubert static void eap_teap_reset(struct eap_sm *sm, void *priv) 442206b73d0SCy Schubert { 443206b73d0SCy Schubert struct eap_teap_data *data = priv; 444206b73d0SCy Schubert 445206b73d0SCy Schubert if (!data) 446206b73d0SCy Schubert return; 447206b73d0SCy Schubert if (data->phase2_priv && data->phase2_method) 448206b73d0SCy Schubert data->phase2_method->reset(sm, data->phase2_priv); 449206b73d0SCy Schubert eap_server_tls_ssl_deinit(sm, &data->ssl); 450206b73d0SCy Schubert os_free(data->srv_id); 451206b73d0SCy Schubert os_free(data->srv_id_info); 452206b73d0SCy Schubert wpabuf_free(data->pending_phase2_resp); 453206b73d0SCy Schubert wpabuf_free(data->server_outer_tlvs); 454206b73d0SCy Schubert wpabuf_free(data->peer_outer_tlvs); 455206b73d0SCy Schubert os_free(data->identity); 456206b73d0SCy Schubert forced_memzero(data->simck_msk, EAP_TEAP_SIMCK_LEN); 457206b73d0SCy Schubert forced_memzero(data->simck_emsk, EAP_TEAP_SIMCK_LEN); 458206b73d0SCy Schubert forced_memzero(data->cmk_msk, EAP_TEAP_CMK_LEN); 459206b73d0SCy Schubert forced_memzero(data->cmk_emsk, EAP_TEAP_CMK_LEN); 460206b73d0SCy Schubert forced_memzero(data->pac_opaque_encr, sizeof(data->pac_opaque_encr)); 461206b73d0SCy Schubert bin_clear_free(data, sizeof(*data)); 462206b73d0SCy Schubert } 463206b73d0SCy Schubert 464206b73d0SCy Schubert 465206b73d0SCy Schubert static struct wpabuf * eap_teap_build_start(struct eap_sm *sm, 466206b73d0SCy Schubert struct eap_teap_data *data, u8 id) 467206b73d0SCy Schubert { 468206b73d0SCy Schubert struct wpabuf *req; 469206b73d0SCy Schubert size_t outer_tlv_len = sizeof(struct teap_tlv_hdr) + data->srv_id_len; 470206b73d0SCy Schubert const u8 *start, *end; 471206b73d0SCy Schubert 472206b73d0SCy Schubert req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TEAP, 473206b73d0SCy Schubert 1 + 4 + outer_tlv_len, EAP_CODE_REQUEST, id); 474206b73d0SCy Schubert if (!req) { 475206b73d0SCy Schubert wpa_printf(MSG_ERROR, 476206b73d0SCy Schubert "EAP-TEAP: Failed to allocate memory for request"); 477206b73d0SCy Schubert eap_teap_state(data, FAILURE); 478206b73d0SCy Schubert return NULL; 479206b73d0SCy Schubert } 480206b73d0SCy Schubert 481206b73d0SCy Schubert wpabuf_put_u8(req, EAP_TLS_FLAGS_START | EAP_TEAP_FLAGS_OUTER_TLV_LEN | 482206b73d0SCy Schubert data->teap_version); 483206b73d0SCy Schubert wpabuf_put_be32(req, outer_tlv_len); 484206b73d0SCy Schubert 485206b73d0SCy Schubert start = wpabuf_put(req, 0); 486206b73d0SCy Schubert 487206b73d0SCy Schubert /* RFC 7170, Section 4.2.2: Authority-ID TLV */ 488206b73d0SCy Schubert eap_teap_put_tlv(req, TEAP_TLV_AUTHORITY_ID, 489206b73d0SCy Schubert data->srv_id, data->srv_id_len); 490206b73d0SCy Schubert 491206b73d0SCy Schubert end = wpabuf_put(req, 0); 492206b73d0SCy Schubert wpabuf_free(data->server_outer_tlvs); 493206b73d0SCy Schubert data->server_outer_tlvs = wpabuf_alloc_copy(start, end - start); 494206b73d0SCy Schubert if (!data->server_outer_tlvs) { 495206b73d0SCy Schubert eap_teap_state(data, FAILURE); 496206b73d0SCy Schubert return NULL; 497206b73d0SCy Schubert } 498206b73d0SCy Schubert 499206b73d0SCy Schubert eap_teap_state(data, PHASE1); 500206b73d0SCy Schubert 501206b73d0SCy Schubert return req; 502206b73d0SCy Schubert } 503206b73d0SCy Schubert 504206b73d0SCy Schubert 505206b73d0SCy Schubert static int eap_teap_phase1_done(struct eap_sm *sm, struct eap_teap_data *data) 506206b73d0SCy Schubert { 507206b73d0SCy Schubert char cipher[64]; 508206b73d0SCy Schubert 509206b73d0SCy Schubert wpa_printf(MSG_DEBUG, "EAP-TEAP: Phase 1 done, starting Phase 2"); 510206b73d0SCy Schubert 511c1d255d3SCy Schubert if (!data->identity && sm->cfg->eap_teap_auth == 2) { 512c1d255d3SCy Schubert const char *subject; 513c1d255d3SCy Schubert 514c1d255d3SCy Schubert subject = tls_connection_get_peer_subject(data->ssl.conn); 515c1d255d3SCy Schubert if (subject) { 516c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, 517c1d255d3SCy Schubert "EAP-TEAP: Peer subject from Phase 1 client certificate: '%s'", 518c1d255d3SCy Schubert subject); 519c1d255d3SCy Schubert data->identity = (u8 *) os_strdup(subject); 520c1d255d3SCy Schubert data->identity_len = os_strlen(subject); 521c1d255d3SCy Schubert } 522c1d255d3SCy Schubert } 523c1d255d3SCy Schubert 524206b73d0SCy Schubert data->tls_cs = tls_connection_get_cipher_suite(data->ssl.conn); 525206b73d0SCy Schubert wpa_printf(MSG_DEBUG, "EAP-TEAP: TLS cipher suite 0x%04x", 526206b73d0SCy Schubert data->tls_cs); 527206b73d0SCy Schubert 528c1d255d3SCy Schubert if (tls_get_cipher(sm->cfg->ssl_ctx, data->ssl.conn, 529c1d255d3SCy Schubert cipher, sizeof(cipher)) < 0) { 530206b73d0SCy Schubert wpa_printf(MSG_DEBUG, 531206b73d0SCy Schubert "EAP-TEAP: Failed to get cipher information"); 532206b73d0SCy Schubert eap_teap_state(data, FAILURE); 533206b73d0SCy Schubert return -1; 534206b73d0SCy Schubert } 535206b73d0SCy Schubert data->anon_provisioning = os_strstr(cipher, "ADH") != NULL; 536206b73d0SCy Schubert 537206b73d0SCy Schubert if (data->anon_provisioning) 538206b73d0SCy Schubert wpa_printf(MSG_DEBUG, "EAP-TEAP: Anonymous provisioning"); 539206b73d0SCy Schubert 540206b73d0SCy Schubert if (eap_teap_derive_key_auth(sm, data) < 0) { 541206b73d0SCy Schubert eap_teap_state(data, FAILURE); 542206b73d0SCy Schubert return -1; 543206b73d0SCy Schubert } 544206b73d0SCy Schubert 545206b73d0SCy Schubert eap_teap_state(data, PHASE2_START); 546206b73d0SCy Schubert 547206b73d0SCy Schubert return 0; 548206b73d0SCy Schubert } 549206b73d0SCy Schubert 550206b73d0SCy Schubert 551206b73d0SCy Schubert static struct wpabuf * eap_teap_build_phase2_req(struct eap_sm *sm, 552206b73d0SCy Schubert struct eap_teap_data *data, 553206b73d0SCy Schubert u8 id) 554206b73d0SCy Schubert { 555c1d255d3SCy Schubert struct wpabuf *req, *id_tlv = NULL; 556206b73d0SCy Schubert 557c1d255d3SCy Schubert if (sm->cfg->eap_teap_auth == 1 || 558c1d255d3SCy Schubert (data->phase2_priv && data->phase2_method && 559c1d255d3SCy Schubert data->phase2_method->vendor == EAP_VENDOR_IETF && 560c1d255d3SCy Schubert data->phase2_method->method == EAP_TYPE_IDENTITY)) { 561c1d255d3SCy Schubert switch (sm->cfg->eap_teap_id) { 562c1d255d3SCy Schubert case EAP_TEAP_ID_ALLOW_ANY: 563c1d255d3SCy Schubert break; 564c1d255d3SCy Schubert case EAP_TEAP_ID_REQUIRE_USER: 565c1d255d3SCy Schubert case EAP_TEAP_ID_REQUEST_USER_ACCEPT_MACHINE: 566c1d255d3SCy Schubert data->cur_id_type = TEAP_IDENTITY_TYPE_USER; 567c1d255d3SCy Schubert id_tlv = eap_teap_tlv_identity_type(data->cur_id_type); 568c1d255d3SCy Schubert break; 569c1d255d3SCy Schubert case EAP_TEAP_ID_REQUIRE_MACHINE: 570c1d255d3SCy Schubert case EAP_TEAP_ID_REQUEST_MACHINE_ACCEPT_USER: 571c1d255d3SCy Schubert data->cur_id_type = TEAP_IDENTITY_TYPE_MACHINE; 572c1d255d3SCy Schubert id_tlv = eap_teap_tlv_identity_type(data->cur_id_type); 573c1d255d3SCy Schubert break; 574c1d255d3SCy Schubert case EAP_TEAP_ID_REQUIRE_USER_AND_MACHINE: 575c1d255d3SCy Schubert if (data->cur_id_type == TEAP_IDENTITY_TYPE_USER) 576c1d255d3SCy Schubert data->cur_id_type = TEAP_IDENTITY_TYPE_MACHINE; 577c1d255d3SCy Schubert else 578c1d255d3SCy Schubert data->cur_id_type = TEAP_IDENTITY_TYPE_USER; 579c1d255d3SCy Schubert id_tlv = eap_teap_tlv_identity_type(data->cur_id_type); 580c1d255d3SCy Schubert break; 581c1d255d3SCy Schubert } 582c1d255d3SCy Schubert } 583c1d255d3SCy Schubert 584c1d255d3SCy Schubert if (sm->cfg->eap_teap_auth == 1) { 585206b73d0SCy Schubert wpa_printf(MSG_DEBUG, "EAP-TEAP: Initiate Basic-Password-Auth"); 586c1d255d3SCy Schubert data->basic_auth_not_done = 1; 587206b73d0SCy Schubert req = wpabuf_alloc(sizeof(struct teap_tlv_hdr)); 588c1d255d3SCy Schubert if (!req) { 589c1d255d3SCy Schubert wpabuf_free(id_tlv); 590206b73d0SCy Schubert return NULL; 591c1d255d3SCy Schubert } 592206b73d0SCy Schubert eap_teap_put_tlv_hdr(req, TEAP_TLV_BASIC_PASSWORD_AUTH_REQ, 0); 593c1d255d3SCy Schubert return wpabuf_concat(req, id_tlv); 594206b73d0SCy Schubert } 595206b73d0SCy Schubert 596206b73d0SCy Schubert wpa_printf(MSG_DEBUG, "EAP-TEAP: Initiate inner EAP method"); 597c1d255d3SCy Schubert data->inner_eap_not_done = 1; 598206b73d0SCy Schubert if (!data->phase2_priv) { 599206b73d0SCy Schubert wpa_printf(MSG_DEBUG, 600206b73d0SCy Schubert "EAP-TEAP: Phase 2 method not initialized"); 601c1d255d3SCy Schubert wpabuf_free(id_tlv); 602206b73d0SCy Schubert return NULL; 603206b73d0SCy Schubert } 604206b73d0SCy Schubert 605206b73d0SCy Schubert req = data->phase2_method->buildReq(sm, data->phase2_priv, id); 606c1d255d3SCy Schubert if (!req) { 607c1d255d3SCy Schubert wpabuf_free(id_tlv); 608206b73d0SCy Schubert return NULL; 609c1d255d3SCy Schubert } 610206b73d0SCy Schubert 611206b73d0SCy Schubert wpa_hexdump_buf_key(MSG_MSGDUMP, "EAP-TEAP: Phase 2 EAP-Request", req); 612c1d255d3SCy Schubert 613c1d255d3SCy Schubert return wpabuf_concat(eap_teap_tlv_eap_payload(req), id_tlv); 614206b73d0SCy Schubert } 615206b73d0SCy Schubert 616206b73d0SCy Schubert 617206b73d0SCy Schubert static struct wpabuf * eap_teap_build_crypto_binding( 618206b73d0SCy Schubert struct eap_sm *sm, struct eap_teap_data *data) 619206b73d0SCy Schubert { 620206b73d0SCy Schubert struct wpabuf *buf; 621206b73d0SCy Schubert struct teap_tlv_result *result; 622206b73d0SCy Schubert struct teap_tlv_crypto_binding *cb; 623206b73d0SCy Schubert u8 subtype, flags; 624206b73d0SCy Schubert 625206b73d0SCy Schubert buf = wpabuf_alloc(2 * sizeof(*result) + sizeof(*cb)); 626206b73d0SCy Schubert if (!buf) 627206b73d0SCy Schubert return NULL; 628206b73d0SCy Schubert 629206b73d0SCy Schubert if (data->send_new_pac || data->anon_provisioning || 630c1d255d3SCy Schubert data->basic_auth_not_done || data->inner_eap_not_done || 631c1d255d3SCy Schubert data->phase2_method || sm->cfg->eap_teap_separate_result) 632206b73d0SCy Schubert data->final_result = 0; 633206b73d0SCy Schubert else 634206b73d0SCy Schubert data->final_result = 1; 635206b73d0SCy Schubert 636c1d255d3SCy Schubert if (!data->final_result || data->eap_seq > 0 || 637c1d255d3SCy Schubert sm->cfg->eap_teap_auth == 1) { 638206b73d0SCy Schubert /* Intermediate-Result */ 639206b73d0SCy Schubert wpa_printf(MSG_DEBUG, 640206b73d0SCy Schubert "EAP-TEAP: Add Intermediate-Result TLV (status=SUCCESS)"); 641206b73d0SCy Schubert result = wpabuf_put(buf, sizeof(*result)); 642206b73d0SCy Schubert result->tlv_type = host_to_be16(TEAP_TLV_MANDATORY | 643206b73d0SCy Schubert TEAP_TLV_INTERMEDIATE_RESULT); 644206b73d0SCy Schubert result->length = host_to_be16(2); 645206b73d0SCy Schubert result->status = host_to_be16(TEAP_STATUS_SUCCESS); 646206b73d0SCy Schubert } 647206b73d0SCy Schubert 648206b73d0SCy Schubert if (data->final_result) { 649206b73d0SCy Schubert /* Result TLV */ 650206b73d0SCy Schubert wpa_printf(MSG_DEBUG, 651206b73d0SCy Schubert "EAP-TEAP: Add Result TLV (status=SUCCESS)"); 652206b73d0SCy Schubert result = wpabuf_put(buf, sizeof(*result)); 653206b73d0SCy Schubert result->tlv_type = host_to_be16(TEAP_TLV_MANDATORY | 654206b73d0SCy Schubert TEAP_TLV_RESULT); 655206b73d0SCy Schubert result->length = host_to_be16(2); 656206b73d0SCy Schubert result->status = host_to_be16(TEAP_STATUS_SUCCESS); 657206b73d0SCy Schubert } 658206b73d0SCy Schubert 659206b73d0SCy Schubert /* Crypto-Binding TLV */ 660206b73d0SCy Schubert cb = wpabuf_put(buf, sizeof(*cb)); 661206b73d0SCy Schubert cb->tlv_type = host_to_be16(TEAP_TLV_MANDATORY | 662206b73d0SCy Schubert TEAP_TLV_CRYPTO_BINDING); 663206b73d0SCy Schubert cb->length = host_to_be16(sizeof(*cb) - sizeof(struct teap_tlv_hdr)); 664206b73d0SCy Schubert cb->version = EAP_TEAP_VERSION; 665206b73d0SCy Schubert cb->received_version = data->peer_version; 666206b73d0SCy Schubert /* FIX: RFC 7170 is not clear on which Flags value to use when 667206b73d0SCy Schubert * Crypto-Binding TLV is used with Basic-Password-Auth */ 668206b73d0SCy Schubert flags = data->cmk_emsk_available ? 669206b73d0SCy Schubert TEAP_CRYPTO_BINDING_EMSK_AND_MSK_CMAC : 670206b73d0SCy Schubert TEAP_CRYPTO_BINDING_MSK_CMAC; 671206b73d0SCy Schubert subtype = TEAP_CRYPTO_BINDING_SUBTYPE_REQUEST; 672206b73d0SCy Schubert cb->subtype = (flags << 4) | subtype; 673206b73d0SCy Schubert if (random_get_bytes(cb->nonce, sizeof(cb->nonce)) < 0) { 674206b73d0SCy Schubert wpabuf_free(buf); 675206b73d0SCy Schubert return NULL; 676206b73d0SCy Schubert } 677206b73d0SCy Schubert 678206b73d0SCy Schubert /* 679206b73d0SCy Schubert * RFC 7170, Section 4.2.13: 680206b73d0SCy Schubert * The nonce in a request MUST have its least significant bit set to 0. 681206b73d0SCy Schubert */ 682206b73d0SCy Schubert cb->nonce[sizeof(cb->nonce) - 1] &= ~0x01; 683206b73d0SCy Schubert 684206b73d0SCy Schubert os_memcpy(data->crypto_binding_nonce, cb->nonce, sizeof(cb->nonce)); 685206b73d0SCy Schubert 686206b73d0SCy Schubert if (eap_teap_compound_mac(data->tls_cs, cb, data->server_outer_tlvs, 687206b73d0SCy Schubert data->peer_outer_tlvs, data->cmk_msk, 688206b73d0SCy Schubert cb->msk_compound_mac) < 0) { 689206b73d0SCy Schubert wpabuf_free(buf); 690206b73d0SCy Schubert return NULL; 691206b73d0SCy Schubert } 692206b73d0SCy Schubert 693206b73d0SCy Schubert if (data->cmk_emsk_available && 694206b73d0SCy Schubert eap_teap_compound_mac(data->tls_cs, cb, data->server_outer_tlvs, 695206b73d0SCy Schubert data->peer_outer_tlvs, data->cmk_emsk, 696206b73d0SCy Schubert cb->emsk_compound_mac) < 0) { 697206b73d0SCy Schubert wpabuf_free(buf); 698206b73d0SCy Schubert return NULL; 699206b73d0SCy Schubert } 700206b73d0SCy Schubert 701206b73d0SCy Schubert wpa_printf(MSG_DEBUG, 702206b73d0SCy Schubert "EAP-TEAP: Add Crypto-Binding TLV: Version %u Received Version %u Flags %u Sub-Type %u", 703206b73d0SCy Schubert cb->version, cb->received_version, flags, subtype); 704206b73d0SCy Schubert wpa_hexdump(MSG_MSGDUMP, "EAP-TEAP: Nonce", 705206b73d0SCy Schubert cb->nonce, sizeof(cb->nonce)); 706206b73d0SCy Schubert wpa_hexdump(MSG_MSGDUMP, "EAP-TEAP: EMSK Compound MAC", 707206b73d0SCy Schubert cb->emsk_compound_mac, sizeof(cb->emsk_compound_mac)); 708206b73d0SCy Schubert wpa_hexdump(MSG_MSGDUMP, "EAP-TEAP: MSK Compound MAC", 709206b73d0SCy Schubert cb->msk_compound_mac, sizeof(cb->msk_compound_mac)); 710206b73d0SCy Schubert 711*a90b9d01SCy Schubert data->check_crypto_binding = true; 712*a90b9d01SCy Schubert 713206b73d0SCy Schubert return buf; 714206b73d0SCy Schubert } 715206b73d0SCy Schubert 716206b73d0SCy Schubert 717206b73d0SCy Schubert static struct wpabuf * eap_teap_build_pac(struct eap_sm *sm, 718206b73d0SCy Schubert struct eap_teap_data *data) 719206b73d0SCy Schubert { 720206b73d0SCy Schubert u8 pac_key[EAP_TEAP_PAC_KEY_LEN]; 721206b73d0SCy Schubert u8 *pac_buf, *pac_opaque; 722206b73d0SCy Schubert struct wpabuf *buf; 723206b73d0SCy Schubert u8 *pos; 724206b73d0SCy Schubert size_t buf_len, srv_id_info_len, pac_len; 725206b73d0SCy Schubert struct teap_tlv_hdr *pac_tlv; 726206b73d0SCy Schubert struct pac_attr_hdr *pac_info; 727206b73d0SCy Schubert struct teap_tlv_result *result; 728206b73d0SCy Schubert struct os_time now; 729206b73d0SCy Schubert 730206b73d0SCy Schubert wpa_printf(MSG_DEBUG, "EAP-TEAP: Build a new PAC"); 731206b73d0SCy Schubert 732206b73d0SCy Schubert if (random_get_bytes(pac_key, EAP_TEAP_PAC_KEY_LEN) < 0 || 733206b73d0SCy Schubert os_get_time(&now) < 0) 734206b73d0SCy Schubert return NULL; 735206b73d0SCy Schubert wpa_hexdump_key(MSG_DEBUG, "EAP-TEAP: Generated PAC-Key", 736206b73d0SCy Schubert pac_key, EAP_TEAP_PAC_KEY_LEN); 737206b73d0SCy Schubert 738206b73d0SCy Schubert pac_len = (2 + EAP_TEAP_PAC_KEY_LEN) + (2 + 4) + 739206b73d0SCy Schubert (2 + sm->identity_len) + 8; 740206b73d0SCy Schubert pac_buf = os_malloc(pac_len); 741206b73d0SCy Schubert if (!pac_buf) 742206b73d0SCy Schubert return NULL; 743206b73d0SCy Schubert 744206b73d0SCy Schubert srv_id_info_len = os_strlen(data->srv_id_info); 745206b73d0SCy Schubert 746206b73d0SCy Schubert pos = pac_buf; 747206b73d0SCy Schubert *pos++ = PAC_OPAQUE_TYPE_KEY; 748206b73d0SCy Schubert *pos++ = EAP_TEAP_PAC_KEY_LEN; 749206b73d0SCy Schubert os_memcpy(pos, pac_key, EAP_TEAP_PAC_KEY_LEN); 750206b73d0SCy Schubert pos += EAP_TEAP_PAC_KEY_LEN; 751206b73d0SCy Schubert 752206b73d0SCy Schubert wpa_printf(MSG_DEBUG, "EAP-TEAP: PAC-Key lifetime: %u seconds", 753206b73d0SCy Schubert data->pac_key_lifetime); 754206b73d0SCy Schubert *pos++ = PAC_OPAQUE_TYPE_LIFETIME; 755206b73d0SCy Schubert *pos++ = 4; 756206b73d0SCy Schubert WPA_PUT_BE32(pos, now.sec + data->pac_key_lifetime); 757206b73d0SCy Schubert pos += 4; 758206b73d0SCy Schubert 759206b73d0SCy Schubert if (sm->identity) { 760206b73d0SCy Schubert wpa_hexdump_ascii(MSG_DEBUG, "EAP-TEAP: PAC-Opaque Identity", 761206b73d0SCy Schubert sm->identity, sm->identity_len); 762206b73d0SCy Schubert *pos++ = PAC_OPAQUE_TYPE_IDENTITY; 763206b73d0SCy Schubert *pos++ = sm->identity_len; 764206b73d0SCy Schubert os_memcpy(pos, sm->identity, sm->identity_len); 765206b73d0SCy Schubert pos += sm->identity_len; 766206b73d0SCy Schubert } 767206b73d0SCy Schubert 768206b73d0SCy Schubert pac_len = pos - pac_buf; 769206b73d0SCy Schubert while (pac_len % 8) { 770206b73d0SCy Schubert *pos++ = PAC_OPAQUE_TYPE_PAD; 771206b73d0SCy Schubert pac_len++; 772206b73d0SCy Schubert } 773206b73d0SCy Schubert 774206b73d0SCy Schubert pac_opaque = os_malloc(pac_len + 8); 775206b73d0SCy Schubert if (!pac_opaque) { 776206b73d0SCy Schubert os_free(pac_buf); 777206b73d0SCy Schubert return NULL; 778206b73d0SCy Schubert } 779206b73d0SCy Schubert if (aes_wrap(data->pac_opaque_encr, sizeof(data->pac_opaque_encr), 780206b73d0SCy Schubert pac_len / 8, pac_buf, pac_opaque) < 0) { 781206b73d0SCy Schubert os_free(pac_buf); 782206b73d0SCy Schubert os_free(pac_opaque); 783206b73d0SCy Schubert return NULL; 784206b73d0SCy Schubert } 785206b73d0SCy Schubert os_free(pac_buf); 786206b73d0SCy Schubert 787206b73d0SCy Schubert pac_len += 8; 788206b73d0SCy Schubert wpa_hexdump(MSG_DEBUG, "EAP-TEAP: PAC-Opaque", pac_opaque, pac_len); 789206b73d0SCy Schubert 790206b73d0SCy Schubert buf_len = sizeof(*pac_tlv) + 791206b73d0SCy Schubert sizeof(struct pac_attr_hdr) + EAP_TEAP_PAC_KEY_LEN + 792206b73d0SCy Schubert sizeof(struct pac_attr_hdr) + pac_len + 793206b73d0SCy Schubert data->srv_id_len + srv_id_info_len + 100 + sizeof(*result); 794206b73d0SCy Schubert buf = wpabuf_alloc(buf_len); 795206b73d0SCy Schubert if (!buf) { 796206b73d0SCy Schubert os_free(pac_opaque); 797206b73d0SCy Schubert return NULL; 798206b73d0SCy Schubert } 799206b73d0SCy Schubert 800206b73d0SCy Schubert /* Result TLV */ 801206b73d0SCy Schubert wpa_printf(MSG_DEBUG, "EAP-TEAP: Add Result TLV (status=SUCCESS)"); 802206b73d0SCy Schubert result = wpabuf_put(buf, sizeof(*result)); 803206b73d0SCy Schubert WPA_PUT_BE16((u8 *) &result->tlv_type, 804206b73d0SCy Schubert TEAP_TLV_MANDATORY | TEAP_TLV_RESULT); 805206b73d0SCy Schubert WPA_PUT_BE16((u8 *) &result->length, 2); 806206b73d0SCy Schubert WPA_PUT_BE16((u8 *) &result->status, TEAP_STATUS_SUCCESS); 807206b73d0SCy Schubert 808206b73d0SCy Schubert /* PAC TLV */ 809206b73d0SCy Schubert wpa_printf(MSG_DEBUG, "EAP-TEAP: Add PAC TLV"); 810206b73d0SCy Schubert pac_tlv = wpabuf_put(buf, sizeof(*pac_tlv)); 811206b73d0SCy Schubert pac_tlv->tlv_type = host_to_be16(TEAP_TLV_MANDATORY | TEAP_TLV_PAC); 812206b73d0SCy Schubert 813206b73d0SCy Schubert /* PAC-Key */ 814206b73d0SCy Schubert eap_teap_put_tlv(buf, PAC_TYPE_PAC_KEY, pac_key, EAP_TEAP_PAC_KEY_LEN); 815206b73d0SCy Schubert 816206b73d0SCy Schubert /* PAC-Opaque */ 817206b73d0SCy Schubert eap_teap_put_tlv(buf, PAC_TYPE_PAC_OPAQUE, pac_opaque, pac_len); 818206b73d0SCy Schubert os_free(pac_opaque); 819206b73d0SCy Schubert 820206b73d0SCy Schubert /* PAC-Info */ 821206b73d0SCy Schubert pac_info = wpabuf_put(buf, sizeof(*pac_info)); 822206b73d0SCy Schubert pac_info->type = host_to_be16(PAC_TYPE_PAC_INFO); 823206b73d0SCy Schubert 824206b73d0SCy Schubert /* PAC-Lifetime (inside PAC-Info) */ 825206b73d0SCy Schubert eap_teap_put_tlv_hdr(buf, PAC_TYPE_CRED_LIFETIME, 4); 826206b73d0SCy Schubert wpabuf_put_be32(buf, now.sec + data->pac_key_lifetime); 827206b73d0SCy Schubert 828206b73d0SCy Schubert /* A-ID (inside PAC-Info) */ 829206b73d0SCy Schubert eap_teap_put_tlv(buf, PAC_TYPE_A_ID, data->srv_id, data->srv_id_len); 830206b73d0SCy Schubert 831206b73d0SCy Schubert /* Note: headers may be misaligned after A-ID */ 832206b73d0SCy Schubert 833206b73d0SCy Schubert if (sm->identity) { 834206b73d0SCy Schubert eap_teap_put_tlv(buf, PAC_TYPE_I_ID, sm->identity, 835206b73d0SCy Schubert sm->identity_len); 836206b73d0SCy Schubert } 837206b73d0SCy Schubert 838206b73d0SCy Schubert /* A-ID-Info (inside PAC-Info) */ 839206b73d0SCy Schubert eap_teap_put_tlv(buf, PAC_TYPE_A_ID_INFO, data->srv_id_info, 840206b73d0SCy Schubert srv_id_info_len); 841206b73d0SCy Schubert 842206b73d0SCy Schubert /* PAC-Type (inside PAC-Info) */ 843206b73d0SCy Schubert eap_teap_put_tlv_hdr(buf, PAC_TYPE_PAC_TYPE, 2); 844206b73d0SCy Schubert wpabuf_put_be16(buf, PAC_TYPE_TUNNEL_PAC); 845206b73d0SCy Schubert 846206b73d0SCy Schubert /* Update PAC-Info and PAC TLV Length fields */ 847206b73d0SCy Schubert pos = wpabuf_put(buf, 0); 848206b73d0SCy Schubert pac_info->len = host_to_be16(pos - (u8 *) (pac_info + 1)); 849206b73d0SCy Schubert pac_tlv->length = host_to_be16(pos - (u8 *) (pac_tlv + 1)); 850206b73d0SCy Schubert 851206b73d0SCy Schubert return buf; 852206b73d0SCy Schubert } 853206b73d0SCy Schubert 854206b73d0SCy Schubert 855206b73d0SCy Schubert static int eap_teap_encrypt_phase2(struct eap_sm *sm, 856206b73d0SCy Schubert struct eap_teap_data *data, 857206b73d0SCy Schubert struct wpabuf *plain, int piggyback) 858206b73d0SCy Schubert { 859206b73d0SCy Schubert struct wpabuf *encr; 860206b73d0SCy Schubert 861206b73d0SCy Schubert wpa_hexdump_buf_key(MSG_DEBUG, "EAP-TEAP: Encrypting Phase 2 TLVs", 862206b73d0SCy Schubert plain); 863206b73d0SCy Schubert encr = eap_server_tls_encrypt(sm, &data->ssl, plain); 864206b73d0SCy Schubert wpabuf_free(plain); 865206b73d0SCy Schubert 866206b73d0SCy Schubert if (!encr) 867206b73d0SCy Schubert return -1; 868206b73d0SCy Schubert 869206b73d0SCy Schubert if (data->ssl.tls_out && piggyback) { 870206b73d0SCy Schubert wpa_printf(MSG_DEBUG, 871206b73d0SCy Schubert "EAP-TEAP: Piggyback Phase 2 data (len=%d) with last Phase 1 Message (len=%d used=%d)", 872206b73d0SCy Schubert (int) wpabuf_len(encr), 873206b73d0SCy Schubert (int) wpabuf_len(data->ssl.tls_out), 874206b73d0SCy Schubert (int) data->ssl.tls_out_pos); 875206b73d0SCy Schubert if (wpabuf_resize(&data->ssl.tls_out, wpabuf_len(encr)) < 0) { 876206b73d0SCy Schubert wpa_printf(MSG_WARNING, 877206b73d0SCy Schubert "EAP-TEAP: Failed to resize output buffer"); 878206b73d0SCy Schubert wpabuf_free(encr); 879206b73d0SCy Schubert return -1; 880206b73d0SCy Schubert } 881206b73d0SCy Schubert wpabuf_put_buf(data->ssl.tls_out, encr); 882206b73d0SCy Schubert wpabuf_free(encr); 883206b73d0SCy Schubert } else { 884206b73d0SCy Schubert wpabuf_free(data->ssl.tls_out); 885206b73d0SCy Schubert data->ssl.tls_out_pos = 0; 886206b73d0SCy Schubert data->ssl.tls_out = encr; 887206b73d0SCy Schubert } 888206b73d0SCy Schubert 889206b73d0SCy Schubert return 0; 890206b73d0SCy Schubert } 891206b73d0SCy Schubert 892206b73d0SCy Schubert 893206b73d0SCy Schubert static struct wpabuf * eap_teap_buildReq(struct eap_sm *sm, void *priv, u8 id) 894206b73d0SCy Schubert { 895206b73d0SCy Schubert struct eap_teap_data *data = priv; 896206b73d0SCy Schubert struct wpabuf *req = NULL; 897206b73d0SCy Schubert int piggyback = 0; 898*a90b9d01SCy Schubert bool move_to_method = true; 899206b73d0SCy Schubert 900206b73d0SCy Schubert if (data->ssl.state == FRAG_ACK) { 901206b73d0SCy Schubert return eap_server_tls_build_ack(id, EAP_TYPE_TEAP, 902206b73d0SCy Schubert data->teap_version); 903206b73d0SCy Schubert } 904206b73d0SCy Schubert 905206b73d0SCy Schubert if (data->ssl.state == WAIT_FRAG_ACK) { 906206b73d0SCy Schubert return eap_server_tls_build_msg(&data->ssl, EAP_TYPE_TEAP, 907206b73d0SCy Schubert data->teap_version, id); 908206b73d0SCy Schubert } 909206b73d0SCy Schubert 910206b73d0SCy Schubert switch (data->state) { 911206b73d0SCy Schubert case START: 912206b73d0SCy Schubert return eap_teap_build_start(sm, data, id); 913206b73d0SCy Schubert case PHASE1B: 914c1d255d3SCy Schubert if (tls_connection_established(sm->cfg->ssl_ctx, 915c1d255d3SCy Schubert data->ssl.conn)) { 916206b73d0SCy Schubert if (eap_teap_phase1_done(sm, data) < 0) 917206b73d0SCy Schubert return NULL; 918206b73d0SCy Schubert if (data->state == PHASE2_START) { 919206b73d0SCy Schubert int res; 920206b73d0SCy Schubert 921206b73d0SCy Schubert /* 922206b73d0SCy Schubert * Try to generate Phase 2 data to piggyback 923206b73d0SCy Schubert * with the end of Phase 1 to avoid extra 924206b73d0SCy Schubert * roundtrip. 925206b73d0SCy Schubert */ 926206b73d0SCy Schubert wpa_printf(MSG_DEBUG, 927206b73d0SCy Schubert "EAP-TEAP: Try to start Phase 2"); 928206b73d0SCy Schubert res = eap_teap_process_phase2_start(sm, data); 929206b73d0SCy Schubert if (res == 1) { 930206b73d0SCy Schubert req = eap_teap_build_crypto_binding( 931206b73d0SCy Schubert sm, data); 932206b73d0SCy Schubert piggyback = 1; 933206b73d0SCy Schubert break; 934206b73d0SCy Schubert } 935206b73d0SCy Schubert 936206b73d0SCy Schubert if (res) 937206b73d0SCy Schubert break; 938206b73d0SCy Schubert req = eap_teap_build_phase2_req(sm, data, id); 939206b73d0SCy Schubert piggyback = 1; 940206b73d0SCy Schubert } 941206b73d0SCy Schubert } 942206b73d0SCy Schubert break; 943206b73d0SCy Schubert case PHASE2_ID: 944206b73d0SCy Schubert case PHASE2_BASIC_AUTH: 945206b73d0SCy Schubert case PHASE2_METHOD: 946206b73d0SCy Schubert req = eap_teap_build_phase2_req(sm, data, id); 947206b73d0SCy Schubert break; 948206b73d0SCy Schubert case CRYPTO_BINDING: 949206b73d0SCy Schubert req = eap_teap_build_crypto_binding(sm, data); 950*a90b9d01SCy Schubert if (req && sm->cfg->eap_teap_auth == 0 && 951*a90b9d01SCy Schubert data->inner_eap_not_done && 952*a90b9d01SCy Schubert !data->phase2_method && 953*a90b9d01SCy Schubert sm->cfg->eap_teap_method_sequence == 0) { 954*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG, 955*a90b9d01SCy Schubert "EAP-TEAP: Continue with inner EAP authentication for second credential (optimized)"); 956*a90b9d01SCy Schubert eap_teap_state(data, PHASE2_ID); 957*a90b9d01SCy Schubert if (eap_teap_phase2_init(sm, data, EAP_VENDOR_IETF, 958*a90b9d01SCy Schubert EAP_TYPE_IDENTITY) < 0) { 959*a90b9d01SCy Schubert eap_teap_state(data, FAILURE); 960*a90b9d01SCy Schubert wpabuf_free(req); 961*a90b9d01SCy Schubert return NULL; 962*a90b9d01SCy Schubert } 963*a90b9d01SCy Schubert move_to_method = false; 964*a90b9d01SCy Schubert } 965206b73d0SCy Schubert if (data->phase2_method) { 966206b73d0SCy Schubert /* 967206b73d0SCy Schubert * Include the start of the next EAP method in the 968206b73d0SCy Schubert * sequence in the same message with Crypto-Binding to 969206b73d0SCy Schubert * save a round-trip. 970206b73d0SCy Schubert */ 971206b73d0SCy Schubert struct wpabuf *eap; 972206b73d0SCy Schubert 973206b73d0SCy Schubert eap = eap_teap_build_phase2_req(sm, data, id); 974206b73d0SCy Schubert req = wpabuf_concat(req, eap); 975*a90b9d01SCy Schubert if (move_to_method) 976206b73d0SCy Schubert eap_teap_state(data, PHASE2_METHOD); 977206b73d0SCy Schubert } 978206b73d0SCy Schubert break; 979206b73d0SCy Schubert case REQUEST_PAC: 980206b73d0SCy Schubert req = eap_teap_build_pac(sm, data); 981206b73d0SCy Schubert break; 982206b73d0SCy Schubert case FAILURE_SEND_RESULT: 983206b73d0SCy Schubert req = eap_teap_tlv_result(TEAP_STATUS_FAILURE, 0); 984206b73d0SCy Schubert if (data->error_code) 985206b73d0SCy Schubert req = wpabuf_concat( 986206b73d0SCy Schubert req, eap_teap_tlv_error(data->error_code)); 987206b73d0SCy Schubert break; 988c1d255d3SCy Schubert case SUCCESS_SEND_RESULT: 989c1d255d3SCy Schubert req = eap_teap_tlv_result(TEAP_STATUS_SUCCESS, 0); 990c1d255d3SCy Schubert data->final_result = 1; 991c1d255d3SCy Schubert break; 992206b73d0SCy Schubert default: 993206b73d0SCy Schubert wpa_printf(MSG_DEBUG, "EAP-TEAP: %s - unexpected state %d", 994206b73d0SCy Schubert __func__, data->state); 995206b73d0SCy Schubert return NULL; 996206b73d0SCy Schubert } 997206b73d0SCy Schubert 998206b73d0SCy Schubert if (req && eap_teap_encrypt_phase2(sm, data, req, piggyback) < 0) 999206b73d0SCy Schubert return NULL; 1000206b73d0SCy Schubert 1001206b73d0SCy Schubert return eap_server_tls_build_msg(&data->ssl, EAP_TYPE_TEAP, 1002206b73d0SCy Schubert data->teap_version, id); 1003206b73d0SCy Schubert } 1004206b73d0SCy Schubert 1005206b73d0SCy Schubert 1006c1d255d3SCy Schubert static bool eap_teap_check(struct eap_sm *sm, void *priv, 1007206b73d0SCy Schubert struct wpabuf *respData) 1008206b73d0SCy Schubert { 1009206b73d0SCy Schubert const u8 *pos; 1010206b73d0SCy Schubert size_t len; 1011206b73d0SCy Schubert 1012206b73d0SCy Schubert pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_TEAP, respData, &len); 1013206b73d0SCy Schubert if (!pos || len < 1) { 1014206b73d0SCy Schubert wpa_printf(MSG_INFO, "EAP-TEAP: Invalid frame"); 1015c1d255d3SCy Schubert return true; 1016206b73d0SCy Schubert } 1017206b73d0SCy Schubert 1018c1d255d3SCy Schubert return false; 1019206b73d0SCy Schubert } 1020206b73d0SCy Schubert 1021206b73d0SCy Schubert 1022206b73d0SCy Schubert static int eap_teap_phase2_init(struct eap_sm *sm, struct eap_teap_data *data, 1023c1d255d3SCy Schubert int vendor, enum eap_type eap_type) 1024206b73d0SCy Schubert { 1025206b73d0SCy Schubert if (data->phase2_priv && data->phase2_method) { 1026206b73d0SCy Schubert data->phase2_method->reset(sm, data->phase2_priv); 1027206b73d0SCy Schubert data->phase2_method = NULL; 1028206b73d0SCy Schubert data->phase2_priv = NULL; 1029206b73d0SCy Schubert } 1030c1d255d3SCy Schubert data->phase2_method = eap_server_get_eap_method(vendor, eap_type); 1031206b73d0SCy Schubert if (!data->phase2_method) 1032206b73d0SCy Schubert return -1; 1033206b73d0SCy Schubert 1034*a90b9d01SCy Schubert /* While RFC 7170 does not describe this, EAP-TEAP has been deployed 1035*a90b9d01SCy Schubert * with implementations that use the EAP-FAST-MSCHAPv2, instead of the 1036*a90b9d01SCy Schubert * EAP-MSCHAPv2, way of deriving the MSK for IMSK. Use that design here 1037*a90b9d01SCy Schubert * to interoperate. 1038*a90b9d01SCy Schubert */ 1039*a90b9d01SCy Schubert sm->eap_fast_mschapv2 = true; 1040*a90b9d01SCy Schubert 1041206b73d0SCy Schubert sm->init_phase2 = 1; 1042206b73d0SCy Schubert data->phase2_priv = data->phase2_method->init(sm); 1043206b73d0SCy Schubert sm->init_phase2 = 0; 1044206b73d0SCy Schubert 1045206b73d0SCy Schubert return data->phase2_priv ? 0 : -1; 1046206b73d0SCy Schubert } 1047206b73d0SCy Schubert 1048206b73d0SCy Schubert 1049c1d255d3SCy Schubert static int eap_teap_valid_id_type(struct eap_sm *sm, struct eap_teap_data *data, 1050c1d255d3SCy Schubert enum teap_identity_types id_type) 1051c1d255d3SCy Schubert { 1052c1d255d3SCy Schubert if (sm->cfg->eap_teap_id == EAP_TEAP_ID_REQUIRE_USER && 1053c1d255d3SCy Schubert id_type != TEAP_IDENTITY_TYPE_USER) 1054c1d255d3SCy Schubert return 0; 1055c1d255d3SCy Schubert if (sm->cfg->eap_teap_id == EAP_TEAP_ID_REQUIRE_MACHINE && 1056c1d255d3SCy Schubert id_type != TEAP_IDENTITY_TYPE_MACHINE) 1057c1d255d3SCy Schubert return 0; 1058c1d255d3SCy Schubert if (sm->cfg->eap_teap_id == EAP_TEAP_ID_REQUIRE_USER_AND_MACHINE && 1059c1d255d3SCy Schubert id_type != data->cur_id_type) 1060c1d255d3SCy Schubert return 0; 1061c1d255d3SCy Schubert if (sm->cfg->eap_teap_id != EAP_TEAP_ID_ALLOW_ANY && 1062c1d255d3SCy Schubert id_type != TEAP_IDENTITY_TYPE_USER && 1063c1d255d3SCy Schubert id_type != TEAP_IDENTITY_TYPE_MACHINE) 1064c1d255d3SCy Schubert return 0; 1065c1d255d3SCy Schubert return 1; 1066c1d255d3SCy Schubert } 1067c1d255d3SCy Schubert 1068c1d255d3SCy Schubert 1069206b73d0SCy Schubert static void eap_teap_process_phase2_response(struct eap_sm *sm, 1070206b73d0SCy Schubert struct eap_teap_data *data, 1071c1d255d3SCy Schubert u8 *in_data, size_t in_len, 1072c1d255d3SCy Schubert enum teap_identity_types id_type) 1073206b73d0SCy Schubert { 1074c1d255d3SCy Schubert int next_vendor = EAP_VENDOR_IETF; 1075c1d255d3SCy Schubert enum eap_type next_type = EAP_TYPE_NONE; 1076206b73d0SCy Schubert struct eap_hdr *hdr; 1077206b73d0SCy Schubert u8 *pos; 1078206b73d0SCy Schubert size_t left; 1079206b73d0SCy Schubert struct wpabuf buf; 1080206b73d0SCy Schubert const struct eap_method *m = data->phase2_method; 1081206b73d0SCy Schubert void *priv = data->phase2_priv; 1082206b73d0SCy Schubert 1083206b73d0SCy Schubert if (!priv) { 1084206b73d0SCy Schubert wpa_printf(MSG_DEBUG, 1085206b73d0SCy Schubert "EAP-TEAP: %s - Phase 2 not initialized?!", 1086206b73d0SCy Schubert __func__); 1087206b73d0SCy Schubert return; 1088206b73d0SCy Schubert } 1089206b73d0SCy Schubert 1090206b73d0SCy Schubert hdr = (struct eap_hdr *) in_data; 1091206b73d0SCy Schubert pos = (u8 *) (hdr + 1); 1092206b73d0SCy Schubert 1093206b73d0SCy Schubert if (in_len > sizeof(*hdr) && *pos == EAP_TYPE_NAK) { 1094206b73d0SCy Schubert left = in_len - sizeof(*hdr); 1095206b73d0SCy Schubert wpa_hexdump(MSG_DEBUG, 1096206b73d0SCy Schubert "EAP-TEAP: Phase 2 type Nak'ed; allowed types", 1097206b73d0SCy Schubert pos + 1, left - 1); 1098206b73d0SCy Schubert #ifdef EAP_SERVER_TNC 1099206b73d0SCy Schubert if (m && m->vendor == EAP_VENDOR_IETF && 1100206b73d0SCy Schubert m->method == EAP_TYPE_TNC) { 1101206b73d0SCy Schubert wpa_printf(MSG_DEBUG, 1102206b73d0SCy Schubert "EAP-TEAP: Peer Nak'ed required TNC negotiation"); 1103c1d255d3SCy Schubert next_vendor = EAP_VENDOR_IETF; 1104206b73d0SCy Schubert next_type = eap_teap_req_failure(data, 0); 1105c1d255d3SCy Schubert eap_teap_phase2_init(sm, data, next_vendor, next_type); 1106206b73d0SCy Schubert return; 1107206b73d0SCy Schubert } 1108206b73d0SCy Schubert #endif /* EAP_SERVER_TNC */ 1109206b73d0SCy Schubert eap_sm_process_nak(sm, pos + 1, left - 1); 1110206b73d0SCy Schubert if (sm->user && sm->user_eap_method_index < EAP_MAX_METHODS && 1111206b73d0SCy Schubert sm->user->methods[sm->user_eap_method_index].method != 1112206b73d0SCy Schubert EAP_TYPE_NONE) { 1113c1d255d3SCy Schubert next_vendor = sm->user->methods[ 1114c1d255d3SCy Schubert sm->user_eap_method_index].vendor; 1115206b73d0SCy Schubert next_type = sm->user->methods[ 1116206b73d0SCy Schubert sm->user_eap_method_index++].method; 1117c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "EAP-TEAP: try EAP type %u:%u", 1118c1d255d3SCy Schubert next_vendor, next_type); 1119206b73d0SCy Schubert } else { 1120c1d255d3SCy Schubert next_vendor = EAP_VENDOR_IETF; 1121206b73d0SCy Schubert next_type = eap_teap_req_failure(data, 0); 1122206b73d0SCy Schubert } 1123c1d255d3SCy Schubert eap_teap_phase2_init(sm, data, next_vendor, next_type); 1124206b73d0SCy Schubert return; 1125206b73d0SCy Schubert } 1126206b73d0SCy Schubert 1127206b73d0SCy Schubert wpabuf_set(&buf, in_data, in_len); 1128206b73d0SCy Schubert 1129206b73d0SCy Schubert if (m->check(sm, priv, &buf)) { 1130206b73d0SCy Schubert wpa_printf(MSG_DEBUG, 1131206b73d0SCy Schubert "EAP-TEAP: Phase 2 check() asked to ignore the packet"); 1132206b73d0SCy Schubert eap_teap_req_failure(data, TEAP_ERROR_INNER_METHOD); 1133206b73d0SCy Schubert return; 1134206b73d0SCy Schubert } 1135206b73d0SCy Schubert 1136206b73d0SCy Schubert m->process(sm, priv, &buf); 1137206b73d0SCy Schubert 1138206b73d0SCy Schubert if (!m->isDone(sm, priv)) 1139206b73d0SCy Schubert return; 1140206b73d0SCy Schubert 1141206b73d0SCy Schubert if (!m->isSuccess(sm, priv)) { 1142206b73d0SCy Schubert wpa_printf(MSG_DEBUG, "EAP-TEAP: Phase 2 method failed"); 1143c1d255d3SCy Schubert next_vendor = EAP_VENDOR_IETF; 1144206b73d0SCy Schubert next_type = eap_teap_req_failure(data, TEAP_ERROR_INNER_METHOD); 1145c1d255d3SCy Schubert eap_teap_phase2_init(sm, data, next_vendor, next_type); 1146206b73d0SCy Schubert return; 1147206b73d0SCy Schubert } 1148206b73d0SCy Schubert 1149206b73d0SCy Schubert switch (data->state) { 1150206b73d0SCy Schubert case PHASE2_ID: 1151c1d255d3SCy Schubert if (!eap_teap_valid_id_type(sm, data, id_type)) { 1152c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, 1153c1d255d3SCy Schubert "EAP-TEAP: Provided Identity-Type %u not allowed", 1154c1d255d3SCy Schubert id_type); 1155c1d255d3SCy Schubert eap_teap_req_failure(data, TEAP_ERROR_INNER_METHOD); 1156c1d255d3SCy Schubert break; 1157c1d255d3SCy Schubert } 1158206b73d0SCy Schubert if (eap_user_get(sm, sm->identity, sm->identity_len, 1) != 0) { 1159206b73d0SCy Schubert wpa_hexdump_ascii(MSG_DEBUG, 1160206b73d0SCy Schubert "EAP-TEAP: Phase 2 Identity not found in the user database", 1161206b73d0SCy Schubert sm->identity, sm->identity_len); 1162c1d255d3SCy Schubert next_vendor = EAP_VENDOR_IETF; 1163206b73d0SCy Schubert next_type = eap_teap_req_failure( 1164206b73d0SCy Schubert data, TEAP_ERROR_INNER_METHOD); 1165206b73d0SCy Schubert break; 1166206b73d0SCy Schubert } 1167206b73d0SCy Schubert 1168206b73d0SCy Schubert eap_teap_state(data, PHASE2_METHOD); 1169206b73d0SCy Schubert if (data->anon_provisioning) { 1170206b73d0SCy Schubert /* TODO: Allow any inner EAP method that provides 1171206b73d0SCy Schubert * mutual authentication and EMSK derivation (i.e., 1172206b73d0SCy Schubert * EAP-pwd or EAP-EKE). */ 1173c1d255d3SCy Schubert next_vendor = EAP_VENDOR_IETF; 1174206b73d0SCy Schubert next_type = EAP_TYPE_PWD; 1175206b73d0SCy Schubert sm->user_eap_method_index = 0; 1176206b73d0SCy Schubert } else { 1177c1d255d3SCy Schubert next_vendor = sm->user->methods[0].vendor; 1178206b73d0SCy Schubert next_type = sm->user->methods[0].method; 1179206b73d0SCy Schubert sm->user_eap_method_index = 1; 1180206b73d0SCy Schubert } 1181c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "EAP-TEAP: Try EAP type %u:%u", 1182c1d255d3SCy Schubert next_vendor, next_type); 1183206b73d0SCy Schubert break; 1184206b73d0SCy Schubert case PHASE2_METHOD: 1185206b73d0SCy Schubert case CRYPTO_BINDING: 1186206b73d0SCy Schubert eap_teap_update_icmk(sm, data); 1187c1d255d3SCy Schubert if (data->state == PHASE2_METHOD && 1188c1d255d3SCy Schubert (sm->cfg->eap_teap_id != 1189c1d255d3SCy Schubert EAP_TEAP_ID_REQUIRE_USER_AND_MACHINE || 1190c1d255d3SCy Schubert data->cur_id_type == TEAP_IDENTITY_TYPE_MACHINE)) 1191c1d255d3SCy Schubert data->inner_eap_not_done = 0; 1192206b73d0SCy Schubert eap_teap_state(data, CRYPTO_BINDING); 1193206b73d0SCy Schubert data->eap_seq++; 1194c1d255d3SCy Schubert next_vendor = EAP_VENDOR_IETF; 1195206b73d0SCy Schubert next_type = EAP_TYPE_NONE; 1196206b73d0SCy Schubert #ifdef EAP_SERVER_TNC 1197c1d255d3SCy Schubert if (sm->cfg->tnc && !data->tnc_started) { 1198206b73d0SCy Schubert wpa_printf(MSG_DEBUG, "EAP-TEAP: Initialize TNC"); 1199c1d255d3SCy Schubert next_vendor = EAP_VENDOR_IETF; 1200206b73d0SCy Schubert next_type = EAP_TYPE_TNC; 1201206b73d0SCy Schubert data->tnc_started = 1; 1202206b73d0SCy Schubert } 1203206b73d0SCy Schubert #endif /* EAP_SERVER_TNC */ 1204206b73d0SCy Schubert break; 1205206b73d0SCy Schubert case FAILURE: 1206206b73d0SCy Schubert break; 1207206b73d0SCy Schubert default: 1208206b73d0SCy Schubert wpa_printf(MSG_DEBUG, "EAP-TEAP: %s - unexpected state %d", 1209206b73d0SCy Schubert __func__, data->state); 1210206b73d0SCy Schubert break; 1211206b73d0SCy Schubert } 1212206b73d0SCy Schubert 1213c1d255d3SCy Schubert eap_teap_phase2_init(sm, data, next_vendor, next_type); 1214206b73d0SCy Schubert } 1215206b73d0SCy Schubert 1216206b73d0SCy Schubert 1217206b73d0SCy Schubert static void eap_teap_process_phase2_eap(struct eap_sm *sm, 1218206b73d0SCy Schubert struct eap_teap_data *data, 1219c1d255d3SCy Schubert u8 *in_data, size_t in_len, 1220c1d255d3SCy Schubert enum teap_identity_types id_type) 1221206b73d0SCy Schubert { 1222206b73d0SCy Schubert struct eap_hdr *hdr; 1223206b73d0SCy Schubert size_t len; 1224206b73d0SCy Schubert 1225206b73d0SCy Schubert hdr = (struct eap_hdr *) in_data; 1226206b73d0SCy Schubert if (in_len < (int) sizeof(*hdr)) { 1227206b73d0SCy Schubert wpa_printf(MSG_INFO, 1228206b73d0SCy Schubert "EAP-TEAP: Too short Phase 2 EAP frame (len=%lu)", 1229206b73d0SCy Schubert (unsigned long) in_len); 1230206b73d0SCy Schubert eap_teap_req_failure(data, TEAP_ERROR_INNER_METHOD); 1231206b73d0SCy Schubert return; 1232206b73d0SCy Schubert } 1233206b73d0SCy Schubert len = be_to_host16(hdr->length); 1234206b73d0SCy Schubert if (len > in_len) { 1235206b73d0SCy Schubert wpa_printf(MSG_INFO, 1236206b73d0SCy Schubert "EAP-TEAP: Length mismatch in Phase 2 EAP frame (len=%lu hdr->length=%lu)", 1237206b73d0SCy Schubert (unsigned long) in_len, (unsigned long) len); 1238206b73d0SCy Schubert eap_teap_req_failure(data, TEAP_ERROR_INNER_METHOD); 1239206b73d0SCy Schubert return; 1240206b73d0SCy Schubert } 1241206b73d0SCy Schubert wpa_printf(MSG_DEBUG, 1242206b73d0SCy Schubert "EAP-TEAP: Received Phase 2: code=%d identifier=%d length=%lu", 1243206b73d0SCy Schubert hdr->code, hdr->identifier, 1244206b73d0SCy Schubert (unsigned long) len); 1245206b73d0SCy Schubert switch (hdr->code) { 1246206b73d0SCy Schubert case EAP_CODE_RESPONSE: 1247c1d255d3SCy Schubert eap_teap_process_phase2_response(sm, data, (u8 *) hdr, len, 1248c1d255d3SCy Schubert id_type); 1249206b73d0SCy Schubert break; 1250206b73d0SCy Schubert default: 1251206b73d0SCy Schubert wpa_printf(MSG_INFO, 1252206b73d0SCy Schubert "EAP-TEAP: Unexpected code=%d in Phase 2 EAP header", 1253206b73d0SCy Schubert hdr->code); 1254206b73d0SCy Schubert break; 1255206b73d0SCy Schubert } 1256206b73d0SCy Schubert } 1257206b73d0SCy Schubert 1258206b73d0SCy Schubert 1259206b73d0SCy Schubert static void eap_teap_process_basic_auth_resp(struct eap_sm *sm, 1260206b73d0SCy Schubert struct eap_teap_data *data, 1261c1d255d3SCy Schubert u8 *in_data, size_t in_len, 1262c1d255d3SCy Schubert enum teap_identity_types id_type) 1263206b73d0SCy Schubert { 1264206b73d0SCy Schubert u8 *pos, *end, *username, *password, *new_id; 1265206b73d0SCy Schubert u8 userlen, passlen; 1266206b73d0SCy Schubert 1267c1d255d3SCy Schubert if (!eap_teap_valid_id_type(sm, data, id_type)) { 1268c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, 1269c1d255d3SCy Schubert "EAP-TEAP: Provided Identity-Type %u not allowed", 1270c1d255d3SCy Schubert id_type); 1271c1d255d3SCy Schubert eap_teap_req_failure(data, 0); 1272c1d255d3SCy Schubert return; 1273c1d255d3SCy Schubert } 1274c1d255d3SCy Schubert 1275206b73d0SCy Schubert pos = in_data; 1276206b73d0SCy Schubert end = pos + in_len; 1277206b73d0SCy Schubert 1278206b73d0SCy Schubert if (end - pos < 1) { 1279206b73d0SCy Schubert wpa_printf(MSG_DEBUG, 1280206b73d0SCy Schubert "EAP-TEAP: No room for Basic-Password-Auth-Resp Userlen field"); 1281206b73d0SCy Schubert eap_teap_req_failure(data, 0); 1282206b73d0SCy Schubert return; 1283206b73d0SCy Schubert } 1284206b73d0SCy Schubert userlen = *pos++; 1285206b73d0SCy Schubert if (end - pos < userlen) { 1286206b73d0SCy Schubert wpa_printf(MSG_DEBUG, 1287206b73d0SCy Schubert "EAP-TEAP: Truncated Basic-Password-Auth-Resp Username field"); 1288206b73d0SCy Schubert eap_teap_req_failure(data, 0); 1289206b73d0SCy Schubert return; 1290206b73d0SCy Schubert } 1291206b73d0SCy Schubert username = pos; 1292206b73d0SCy Schubert pos += userlen; 1293206b73d0SCy Schubert wpa_hexdump_ascii(MSG_DEBUG, 1294206b73d0SCy Schubert "EAP-TEAP: Basic-Password-Auth-Resp Username", 1295206b73d0SCy Schubert username, userlen); 1296206b73d0SCy Schubert 1297206b73d0SCy Schubert if (end - pos < 1) { 1298206b73d0SCy Schubert wpa_printf(MSG_DEBUG, 1299206b73d0SCy Schubert "EAP-TEAP: No room for Basic-Password-Auth-Resp Passlen field"); 1300206b73d0SCy Schubert eap_teap_req_failure(data, 0); 1301206b73d0SCy Schubert return; 1302206b73d0SCy Schubert } 1303206b73d0SCy Schubert passlen = *pos++; 1304206b73d0SCy Schubert if (end - pos < passlen) { 1305206b73d0SCy Schubert wpa_printf(MSG_DEBUG, 1306206b73d0SCy Schubert "EAP-TEAP: Truncated Basic-Password-Auth-Resp Password field"); 1307206b73d0SCy Schubert eap_teap_req_failure(data, 0); 1308206b73d0SCy Schubert return; 1309206b73d0SCy Schubert } 1310206b73d0SCy Schubert password = pos; 1311206b73d0SCy Schubert pos += passlen; 1312206b73d0SCy Schubert wpa_hexdump_ascii_key(MSG_DEBUG, 1313206b73d0SCy Schubert "EAP-TEAP: Basic-Password-Auth-Resp Password", 1314206b73d0SCy Schubert password, passlen); 1315206b73d0SCy Schubert 1316206b73d0SCy Schubert if (end > pos) { 1317206b73d0SCy Schubert wpa_printf(MSG_DEBUG, 1318206b73d0SCy Schubert "EAP-TEAP: Unexpected %d extra octet(s) at the end of Basic-Password-Auth-Resp TLV", 1319206b73d0SCy Schubert (int) (end - pos)); 1320206b73d0SCy Schubert eap_teap_req_failure(data, 0); 1321206b73d0SCy Schubert return; 1322206b73d0SCy Schubert } 1323206b73d0SCy Schubert 1324206b73d0SCy Schubert if (eap_user_get(sm, username, userlen, 1) != 0) { 1325206b73d0SCy Schubert wpa_printf(MSG_DEBUG, 1326206b73d0SCy Schubert "EAP-TEAP: Username not found in the user database"); 1327206b73d0SCy Schubert eap_teap_req_failure(data, 0); 1328206b73d0SCy Schubert return; 1329206b73d0SCy Schubert } 1330206b73d0SCy Schubert 1331206b73d0SCy Schubert if (!sm->user || !sm->user->password || sm->user->password_hash) { 1332206b73d0SCy Schubert wpa_printf(MSG_DEBUG, 1333206b73d0SCy Schubert "EAP-TEAP: No plaintext user password configured"); 1334206b73d0SCy Schubert eap_teap_req_failure(data, 0); 1335206b73d0SCy Schubert return; 1336206b73d0SCy Schubert } 1337206b73d0SCy Schubert 1338206b73d0SCy Schubert if (sm->user->password_len != passlen || 1339206b73d0SCy Schubert os_memcmp_const(sm->user->password, password, passlen) != 0) { 1340206b73d0SCy Schubert wpa_printf(MSG_DEBUG, "EAP-TEAP: Invalid password"); 1341206b73d0SCy Schubert eap_teap_req_failure(data, 0); 1342206b73d0SCy Schubert return; 1343206b73d0SCy Schubert } 1344206b73d0SCy Schubert 1345206b73d0SCy Schubert wpa_printf(MSG_DEBUG, "EAP-TEAP: Correct password"); 1346206b73d0SCy Schubert new_id = os_memdup(username, userlen); 1347206b73d0SCy Schubert if (new_id) { 1348206b73d0SCy Schubert os_free(sm->identity); 1349206b73d0SCy Schubert sm->identity = new_id; 1350206b73d0SCy Schubert sm->identity_len = userlen; 1351206b73d0SCy Schubert } 1352c1d255d3SCy Schubert if (sm->cfg->eap_teap_id != EAP_TEAP_ID_REQUIRE_USER_AND_MACHINE || 1353c1d255d3SCy Schubert data->cur_id_type == TEAP_IDENTITY_TYPE_MACHINE) 1354c1d255d3SCy Schubert data->basic_auth_not_done = 0; 1355206b73d0SCy Schubert eap_teap_state(data, CRYPTO_BINDING); 1356206b73d0SCy Schubert eap_teap_update_icmk(sm, data); 1357206b73d0SCy Schubert } 1358206b73d0SCy Schubert 1359206b73d0SCy Schubert 1360206b73d0SCy Schubert static int eap_teap_parse_tlvs(struct wpabuf *data, 1361206b73d0SCy Schubert struct eap_teap_tlv_parse *tlv) 1362206b73d0SCy Schubert { 1363206b73d0SCy Schubert u16 tlv_type; 1364206b73d0SCy Schubert int mandatory, res; 1365206b73d0SCy Schubert size_t len; 1366206b73d0SCy Schubert u8 *pos, *end; 1367206b73d0SCy Schubert 1368206b73d0SCy Schubert os_memset(tlv, 0, sizeof(*tlv)); 1369206b73d0SCy Schubert 1370206b73d0SCy Schubert pos = wpabuf_mhead(data); 1371206b73d0SCy Schubert end = pos + wpabuf_len(data); 1372206b73d0SCy Schubert while (end - pos > 4) { 1373206b73d0SCy Schubert mandatory = pos[0] & 0x80; 1374206b73d0SCy Schubert tlv_type = WPA_GET_BE16(pos) & 0x3fff; 1375206b73d0SCy Schubert pos += 2; 1376206b73d0SCy Schubert len = WPA_GET_BE16(pos); 1377206b73d0SCy Schubert pos += 2; 1378206b73d0SCy Schubert if (len > (size_t) (end - pos)) { 1379206b73d0SCy Schubert wpa_printf(MSG_INFO, "EAP-TEAP: TLV overflow"); 1380206b73d0SCy Schubert return -1; 1381206b73d0SCy Schubert } 1382206b73d0SCy Schubert wpa_printf(MSG_DEBUG, 1383206b73d0SCy Schubert "EAP-TEAP: Received Phase 2: TLV type %u (%s) length %u%s", 1384206b73d0SCy Schubert tlv_type, eap_teap_tlv_type_str(tlv_type), 1385206b73d0SCy Schubert (unsigned int) len, 1386206b73d0SCy Schubert mandatory ? " (mandatory)" : ""); 1387206b73d0SCy Schubert 1388206b73d0SCy Schubert res = eap_teap_parse_tlv(tlv, tlv_type, pos, len); 1389206b73d0SCy Schubert if (res == -2) 1390206b73d0SCy Schubert break; 1391206b73d0SCy Schubert if (res < 0) { 1392206b73d0SCy Schubert if (mandatory) { 1393206b73d0SCy Schubert wpa_printf(MSG_DEBUG, 1394206b73d0SCy Schubert "EAP-TEAP: NAK unknown mandatory TLV type %u", 1395206b73d0SCy Schubert tlv_type); 1396206b73d0SCy Schubert /* TODO: generate NAK TLV */ 1397206b73d0SCy Schubert break; 1398206b73d0SCy Schubert } 1399206b73d0SCy Schubert 1400206b73d0SCy Schubert wpa_printf(MSG_DEBUG, 1401206b73d0SCy Schubert "EAP-TEAP: Ignore unknown optional TLV type %u", 1402206b73d0SCy Schubert tlv_type); 1403206b73d0SCy Schubert } 1404206b73d0SCy Schubert 1405206b73d0SCy Schubert pos += len; 1406206b73d0SCy Schubert } 1407206b73d0SCy Schubert 1408206b73d0SCy Schubert return 0; 1409206b73d0SCy Schubert } 1410206b73d0SCy Schubert 1411206b73d0SCy Schubert 1412206b73d0SCy Schubert static int eap_teap_validate_crypto_binding( 1413206b73d0SCy Schubert struct eap_teap_data *data, const struct teap_tlv_crypto_binding *cb, 1414206b73d0SCy Schubert size_t bind_len) 1415206b73d0SCy Schubert { 1416206b73d0SCy Schubert u8 flags, subtype; 1417206b73d0SCy Schubert 1418206b73d0SCy Schubert subtype = cb->subtype & 0x0f; 1419206b73d0SCy Schubert flags = cb->subtype >> 4; 1420206b73d0SCy Schubert 1421206b73d0SCy Schubert wpa_printf(MSG_DEBUG, 1422206b73d0SCy Schubert "EAP-TEAP: Reply Crypto-Binding TLV: Version %u Received Version %u Flags %u Sub-Type %u", 1423206b73d0SCy Schubert cb->version, cb->received_version, flags, subtype); 1424206b73d0SCy Schubert wpa_hexdump(MSG_MSGDUMP, "EAP-TEAP: Nonce", 1425206b73d0SCy Schubert cb->nonce, sizeof(cb->nonce)); 1426206b73d0SCy Schubert wpa_hexdump(MSG_MSGDUMP, "EAP-TEAP: EMSK Compound MAC", 1427206b73d0SCy Schubert cb->emsk_compound_mac, sizeof(cb->emsk_compound_mac)); 1428206b73d0SCy Schubert wpa_hexdump(MSG_MSGDUMP, "EAP-TEAP: MSK Compound MAC", 1429206b73d0SCy Schubert cb->msk_compound_mac, sizeof(cb->msk_compound_mac)); 1430206b73d0SCy Schubert 1431206b73d0SCy Schubert if (cb->version != EAP_TEAP_VERSION || 1432206b73d0SCy Schubert cb->received_version != data->peer_version) { 1433206b73d0SCy Schubert wpa_printf(MSG_DEBUG, 1434206b73d0SCy Schubert "EAP-TEAP: Unexpected version in Crypto-Binding: Version %u Received Version %u", 1435206b73d0SCy Schubert cb->version, cb->received_version); 1436206b73d0SCy Schubert return -1; 1437206b73d0SCy Schubert } 1438206b73d0SCy Schubert 1439206b73d0SCy Schubert if (flags < 1 || flags > 3) { 1440206b73d0SCy Schubert wpa_printf(MSG_DEBUG, 1441206b73d0SCy Schubert "EAP-TEAP: Unexpected Flags in Crypto-Binding: %u", 1442206b73d0SCy Schubert flags); 1443206b73d0SCy Schubert return -1; 1444206b73d0SCy Schubert } 1445206b73d0SCy Schubert 1446206b73d0SCy Schubert if (subtype != TEAP_CRYPTO_BINDING_SUBTYPE_RESPONSE) { 1447206b73d0SCy Schubert wpa_printf(MSG_DEBUG, 1448206b73d0SCy Schubert "EAP-TEAP: Unexpected Sub-Type in Crypto-Binding: %u", 1449206b73d0SCy Schubert subtype); 1450206b73d0SCy Schubert return -1; 1451206b73d0SCy Schubert } 1452206b73d0SCy Schubert 1453206b73d0SCy Schubert if (os_memcmp_const(data->crypto_binding_nonce, cb->nonce, 1454206b73d0SCy Schubert EAP_TEAP_NONCE_LEN - 1) != 0 || 1455206b73d0SCy Schubert (data->crypto_binding_nonce[EAP_TEAP_NONCE_LEN - 1] | 1) != 1456206b73d0SCy Schubert cb->nonce[EAP_TEAP_NONCE_LEN - 1]) { 1457206b73d0SCy Schubert wpa_printf(MSG_DEBUG, 1458206b73d0SCy Schubert "EAP-TEAP: Invalid Nonce in Crypto-Binding"); 1459206b73d0SCy Schubert return -1; 1460206b73d0SCy Schubert } 1461206b73d0SCy Schubert 1462206b73d0SCy Schubert if (flags == TEAP_CRYPTO_BINDING_MSK_CMAC || 1463206b73d0SCy Schubert flags == TEAP_CRYPTO_BINDING_EMSK_AND_MSK_CMAC) { 1464206b73d0SCy Schubert u8 msk_compound_mac[EAP_TEAP_COMPOUND_MAC_LEN]; 1465206b73d0SCy Schubert 1466206b73d0SCy Schubert if (eap_teap_compound_mac(data->tls_cs, cb, 1467206b73d0SCy Schubert data->server_outer_tlvs, 1468206b73d0SCy Schubert data->peer_outer_tlvs, data->cmk_msk, 1469206b73d0SCy Schubert msk_compound_mac) < 0) 1470206b73d0SCy Schubert return -1; 1471206b73d0SCy Schubert if (os_memcmp_const(msk_compound_mac, cb->msk_compound_mac, 1472206b73d0SCy Schubert EAP_TEAP_COMPOUND_MAC_LEN) != 0) { 1473206b73d0SCy Schubert wpa_hexdump(MSG_DEBUG, 1474206b73d0SCy Schubert "EAP-TEAP: Calculated MSK Compound MAC", 1475206b73d0SCy Schubert msk_compound_mac, 1476206b73d0SCy Schubert EAP_TEAP_COMPOUND_MAC_LEN); 1477206b73d0SCy Schubert wpa_printf(MSG_INFO, 1478206b73d0SCy Schubert "EAP-TEAP: MSK Compound MAC did not match"); 1479206b73d0SCy Schubert return -1; 1480206b73d0SCy Schubert } 1481206b73d0SCy Schubert } 1482206b73d0SCy Schubert 1483206b73d0SCy Schubert if ((flags == TEAP_CRYPTO_BINDING_EMSK_CMAC || 1484206b73d0SCy Schubert flags == TEAP_CRYPTO_BINDING_EMSK_AND_MSK_CMAC) && 1485206b73d0SCy Schubert data->cmk_emsk_available) { 1486206b73d0SCy Schubert u8 emsk_compound_mac[EAP_TEAP_COMPOUND_MAC_LEN]; 1487206b73d0SCy Schubert 1488206b73d0SCy Schubert if (eap_teap_compound_mac(data->tls_cs, cb, 1489206b73d0SCy Schubert data->server_outer_tlvs, 1490206b73d0SCy Schubert data->peer_outer_tlvs, data->cmk_emsk, 1491206b73d0SCy Schubert emsk_compound_mac) < 0) 1492206b73d0SCy Schubert return -1; 1493206b73d0SCy Schubert if (os_memcmp_const(emsk_compound_mac, cb->emsk_compound_mac, 1494206b73d0SCy Schubert EAP_TEAP_COMPOUND_MAC_LEN) != 0) { 1495206b73d0SCy Schubert wpa_hexdump(MSG_DEBUG, 1496206b73d0SCy Schubert "EAP-TEAP: Calculated EMSK Compound MAC", 1497206b73d0SCy Schubert emsk_compound_mac, 1498206b73d0SCy Schubert EAP_TEAP_COMPOUND_MAC_LEN); 1499206b73d0SCy Schubert wpa_printf(MSG_INFO, 1500206b73d0SCy Schubert "EAP-TEAP: EMSK Compound MAC did not match"); 1501206b73d0SCy Schubert return -1; 1502206b73d0SCy Schubert } 1503206b73d0SCy Schubert } 1504206b73d0SCy Schubert 1505206b73d0SCy Schubert if (flags == TEAP_CRYPTO_BINDING_EMSK_CMAC && 1506206b73d0SCy Schubert !data->cmk_emsk_available) { 1507206b73d0SCy Schubert wpa_printf(MSG_INFO, 1508206b73d0SCy Schubert "EAP-TEAP: Peer included only EMSK Compound MAC, but no locally generated inner EAP EMSK to validate this"); 1509206b73d0SCy Schubert return -1; 1510206b73d0SCy Schubert } 1511206b73d0SCy Schubert 1512206b73d0SCy Schubert return 0; 1513206b73d0SCy Schubert } 1514206b73d0SCy Schubert 1515206b73d0SCy Schubert 1516206b73d0SCy Schubert static int eap_teap_pac_type(u8 *pac, size_t len, u16 type) 1517206b73d0SCy Schubert { 1518206b73d0SCy Schubert struct teap_attr_pac_type *tlv; 1519206b73d0SCy Schubert 1520206b73d0SCy Schubert if (!pac || len != sizeof(*tlv)) 1521206b73d0SCy Schubert return 0; 1522206b73d0SCy Schubert 1523206b73d0SCy Schubert tlv = (struct teap_attr_pac_type *) pac; 1524206b73d0SCy Schubert 1525206b73d0SCy Schubert return be_to_host16(tlv->type) == PAC_TYPE_PAC_TYPE && 1526206b73d0SCy Schubert be_to_host16(tlv->length) == 2 && 1527206b73d0SCy Schubert be_to_host16(tlv->pac_type) == type; 1528206b73d0SCy Schubert } 1529206b73d0SCy Schubert 1530206b73d0SCy Schubert 1531206b73d0SCy Schubert static void eap_teap_process_phase2_tlvs(struct eap_sm *sm, 1532206b73d0SCy Schubert struct eap_teap_data *data, 1533206b73d0SCy Schubert struct wpabuf *in_data) 1534206b73d0SCy Schubert { 1535206b73d0SCy Schubert struct eap_teap_tlv_parse tlv; 1536*a90b9d01SCy Schubert bool check_crypto_binding = data->state == CRYPTO_BINDING || 1537*a90b9d01SCy Schubert data->check_crypto_binding; 1538206b73d0SCy Schubert 1539206b73d0SCy Schubert if (eap_teap_parse_tlvs(in_data, &tlv) < 0) { 1540206b73d0SCy Schubert wpa_printf(MSG_DEBUG, 1541206b73d0SCy Schubert "EAP-TEAP: Failed to parse received Phase 2 TLVs"); 1542206b73d0SCy Schubert return; 1543206b73d0SCy Schubert } 1544206b73d0SCy Schubert 1545206b73d0SCy Schubert if (tlv.result == TEAP_STATUS_FAILURE) { 1546206b73d0SCy Schubert wpa_printf(MSG_DEBUG, "EAP-TEAP: Result TLV indicated failure"); 1547206b73d0SCy Schubert eap_teap_state(data, FAILURE); 1548206b73d0SCy Schubert return; 1549206b73d0SCy Schubert } 1550206b73d0SCy Schubert 1551206b73d0SCy Schubert if (tlv.nak) { 1552206b73d0SCy Schubert wpa_printf(MSG_DEBUG, 1553206b73d0SCy Schubert "EAP-TEAP: Peer NAK'ed Vendor-Id %u NAK-Type %u", 1554206b73d0SCy Schubert WPA_GET_BE32(tlv.nak), WPA_GET_BE16(tlv.nak + 4)); 1555206b73d0SCy Schubert eap_teap_state(data, FAILURE_SEND_RESULT); 1556206b73d0SCy Schubert return; 1557206b73d0SCy Schubert } 1558206b73d0SCy Schubert 1559206b73d0SCy Schubert if (data->state == REQUEST_PAC) { 1560206b73d0SCy Schubert u16 type, len, res; 1561206b73d0SCy Schubert 1562206b73d0SCy Schubert if (!tlv.pac || tlv.pac_len < 6) { 1563206b73d0SCy Schubert wpa_printf(MSG_DEBUG, 1564206b73d0SCy Schubert "EAP-TEAP: No PAC Acknowledgement received"); 1565206b73d0SCy Schubert eap_teap_state(data, FAILURE); 1566206b73d0SCy Schubert return; 1567206b73d0SCy Schubert } 1568206b73d0SCy Schubert 1569206b73d0SCy Schubert type = WPA_GET_BE16(tlv.pac); 1570206b73d0SCy Schubert len = WPA_GET_BE16(tlv.pac + 2); 1571206b73d0SCy Schubert res = WPA_GET_BE16(tlv.pac + 4); 1572206b73d0SCy Schubert 1573206b73d0SCy Schubert if (type != PAC_TYPE_PAC_ACKNOWLEDGEMENT || len != 2 || 1574206b73d0SCy Schubert res != TEAP_STATUS_SUCCESS) { 1575206b73d0SCy Schubert wpa_printf(MSG_DEBUG, 1576206b73d0SCy Schubert "EAP-TEAP: PAC TLV did not contain acknowledgement"); 1577206b73d0SCy Schubert eap_teap_state(data, FAILURE); 1578206b73d0SCy Schubert return; 1579206b73d0SCy Schubert } 1580206b73d0SCy Schubert 1581206b73d0SCy Schubert wpa_printf(MSG_DEBUG, 1582206b73d0SCy Schubert "EAP-TEAP: PAC-Acknowledgement received - PAC provisioning succeeded"); 1583206b73d0SCy Schubert eap_teap_state(data, SUCCESS); 1584206b73d0SCy Schubert return; 1585206b73d0SCy Schubert } 1586206b73d0SCy Schubert 1587206b73d0SCy Schubert if (check_crypto_binding) { 1588206b73d0SCy Schubert if (!tlv.crypto_binding) { 1589206b73d0SCy Schubert wpa_printf(MSG_DEBUG, 1590206b73d0SCy Schubert "EAP-TEAP: No Crypto-Binding TLV received"); 1591206b73d0SCy Schubert eap_teap_state(data, FAILURE); 1592206b73d0SCy Schubert return; 1593206b73d0SCy Schubert } 1594206b73d0SCy Schubert 1595206b73d0SCy Schubert if (data->final_result && 1596206b73d0SCy Schubert tlv.result != TEAP_STATUS_SUCCESS) { 1597206b73d0SCy Schubert wpa_printf(MSG_DEBUG, 1598206b73d0SCy Schubert "EAP-TEAP: Crypto-Binding TLV without Success Result"); 1599206b73d0SCy Schubert eap_teap_state(data, FAILURE); 1600206b73d0SCy Schubert return; 1601206b73d0SCy Schubert } 1602206b73d0SCy Schubert 1603c1d255d3SCy Schubert if (sm->cfg->eap_teap_auth != 1 && 1604c1d255d3SCy Schubert !data->skipped_inner_auth && 1605206b73d0SCy Schubert tlv.iresult != TEAP_STATUS_SUCCESS) { 1606206b73d0SCy Schubert wpa_printf(MSG_DEBUG, 1607206b73d0SCy Schubert "EAP-TEAP: Crypto-Binding TLV without intermediate Success Result"); 1608206b73d0SCy Schubert eap_teap_state(data, FAILURE); 1609206b73d0SCy Schubert return; 1610206b73d0SCy Schubert } 1611206b73d0SCy Schubert 1612206b73d0SCy Schubert if (eap_teap_validate_crypto_binding(data, tlv.crypto_binding, 1613206b73d0SCy Schubert tlv.crypto_binding_len)) { 1614206b73d0SCy Schubert eap_teap_state(data, FAILURE); 1615206b73d0SCy Schubert return; 1616206b73d0SCy Schubert } 1617206b73d0SCy Schubert 1618206b73d0SCy Schubert wpa_printf(MSG_DEBUG, 1619206b73d0SCy Schubert "EAP-TEAP: Valid Crypto-Binding TLV received"); 1620*a90b9d01SCy Schubert data->check_crypto_binding = false; 1621206b73d0SCy Schubert if (data->final_result) { 1622206b73d0SCy Schubert wpa_printf(MSG_DEBUG, 1623206b73d0SCy Schubert "EAP-TEAP: Authentication completed successfully"); 1624206b73d0SCy Schubert } 1625206b73d0SCy Schubert 1626206b73d0SCy Schubert if (data->anon_provisioning && 1627c1d255d3SCy Schubert sm->cfg->eap_fast_prov != ANON_PROV && 1628c1d255d3SCy Schubert sm->cfg->eap_fast_prov != BOTH_PROV) { 1629206b73d0SCy Schubert wpa_printf(MSG_DEBUG, 1630206b73d0SCy Schubert "EAP-TEAP: Client is trying to use unauthenticated provisioning which is disabled"); 1631206b73d0SCy Schubert eap_teap_state(data, FAILURE); 1632206b73d0SCy Schubert return; 1633206b73d0SCy Schubert } 1634206b73d0SCy Schubert 1635c1d255d3SCy Schubert if (sm->cfg->eap_fast_prov != AUTH_PROV && 1636c1d255d3SCy Schubert sm->cfg->eap_fast_prov != BOTH_PROV && 1637206b73d0SCy Schubert tlv.request_action == TEAP_REQUEST_ACTION_PROCESS_TLV && 1638206b73d0SCy Schubert eap_teap_pac_type(tlv.pac, tlv.pac_len, 1639206b73d0SCy Schubert PAC_TYPE_TUNNEL_PAC)) { 1640206b73d0SCy Schubert wpa_printf(MSG_DEBUG, 1641206b73d0SCy Schubert "EAP-TEAP: Client is trying to use authenticated provisioning which is disabled"); 1642206b73d0SCy Schubert eap_teap_state(data, FAILURE); 1643206b73d0SCy Schubert return; 1644206b73d0SCy Schubert } 1645206b73d0SCy Schubert 1646206b73d0SCy Schubert if (data->anon_provisioning || 1647206b73d0SCy Schubert (tlv.request_action == TEAP_REQUEST_ACTION_PROCESS_TLV && 1648206b73d0SCy Schubert eap_teap_pac_type(tlv.pac, tlv.pac_len, 1649206b73d0SCy Schubert PAC_TYPE_TUNNEL_PAC))) { 1650206b73d0SCy Schubert wpa_printf(MSG_DEBUG, 1651206b73d0SCy Schubert "EAP-TEAP: Requested a new Tunnel PAC"); 1652206b73d0SCy Schubert eap_teap_state(data, REQUEST_PAC); 1653206b73d0SCy Schubert } else if (data->send_new_pac) { 1654206b73d0SCy Schubert wpa_printf(MSG_DEBUG, 1655206b73d0SCy Schubert "EAP-TEAP: Server triggered re-keying of Tunnel PAC"); 1656206b73d0SCy Schubert eap_teap_state(data, REQUEST_PAC); 1657c1d255d3SCy Schubert } else if (data->final_result) { 1658206b73d0SCy Schubert eap_teap_state(data, SUCCESS); 1659c1d255d3SCy Schubert } else if (sm->cfg->eap_teap_separate_result) { 1660c1d255d3SCy Schubert eap_teap_state(data, SUCCESS_SEND_RESULT); 1661c1d255d3SCy Schubert } 1662206b73d0SCy Schubert } 1663206b73d0SCy Schubert 1664206b73d0SCy Schubert if (tlv.basic_auth_resp) { 1665c1d255d3SCy Schubert if (sm->cfg->eap_teap_auth != 1) { 1666206b73d0SCy Schubert wpa_printf(MSG_DEBUG, 1667206b73d0SCy Schubert "EAP-TEAP: Unexpected Basic-Password-Auth-Resp when trying to use inner EAP"); 1668206b73d0SCy Schubert eap_teap_state(data, FAILURE); 1669206b73d0SCy Schubert return; 1670206b73d0SCy Schubert } 1671206b73d0SCy Schubert eap_teap_process_basic_auth_resp(sm, data, tlv.basic_auth_resp, 1672c1d255d3SCy Schubert tlv.basic_auth_resp_len, 1673c1d255d3SCy Schubert tlv.identity_type); 1674206b73d0SCy Schubert } 1675206b73d0SCy Schubert 1676206b73d0SCy Schubert if (tlv.eap_payload_tlv) { 1677c1d255d3SCy Schubert if (sm->cfg->eap_teap_auth == 1) { 1678206b73d0SCy Schubert wpa_printf(MSG_DEBUG, 1679206b73d0SCy Schubert "EAP-TEAP: Unexpected EAP Payload TLV when trying to use Basic-Password-Auth"); 1680206b73d0SCy Schubert eap_teap_state(data, FAILURE); 1681206b73d0SCy Schubert return; 1682206b73d0SCy Schubert } 1683206b73d0SCy Schubert eap_teap_process_phase2_eap(sm, data, tlv.eap_payload_tlv, 1684c1d255d3SCy Schubert tlv.eap_payload_tlv_len, 1685c1d255d3SCy Schubert tlv.identity_type); 1686c1d255d3SCy Schubert } 1687c1d255d3SCy Schubert 1688c1d255d3SCy Schubert if (data->state == SUCCESS_SEND_RESULT && 1689c1d255d3SCy Schubert tlv.result == TEAP_STATUS_SUCCESS) { 1690c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, 1691c1d255d3SCy Schubert "EAP-TEAP: Peer agreed with final success - authentication completed"); 1692c1d255d3SCy Schubert eap_teap_state(data, SUCCESS); 1693c1d255d3SCy Schubert } else if (check_crypto_binding && data->state == CRYPTO_BINDING && 1694c1d255d3SCy Schubert sm->cfg->eap_teap_auth == 1 && data->basic_auth_not_done) { 1695c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, 1696c1d255d3SCy Schubert "EAP-TEAP: Continue with basic password authentication for second credential"); 1697c1d255d3SCy Schubert eap_teap_state(data, PHASE2_BASIC_AUTH); 1698c1d255d3SCy Schubert } else if (check_crypto_binding && data->state == CRYPTO_BINDING && 1699*a90b9d01SCy Schubert sm->cfg->eap_teap_auth == 0 && data->inner_eap_not_done && 1700*a90b9d01SCy Schubert sm->cfg->eap_teap_method_sequence == 1) { 1701c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, 1702c1d255d3SCy Schubert "EAP-TEAP: Continue with inner EAP authentication for second credential"); 1703c1d255d3SCy Schubert eap_teap_state(data, PHASE2_ID); 1704c1d255d3SCy Schubert if (eap_teap_phase2_init(sm, data, EAP_VENDOR_IETF, 1705c1d255d3SCy Schubert EAP_TYPE_IDENTITY) < 0) 1706c1d255d3SCy Schubert eap_teap_state(data, FAILURE); 1707206b73d0SCy Schubert } 1708206b73d0SCy Schubert } 1709206b73d0SCy Schubert 1710206b73d0SCy Schubert 1711206b73d0SCy Schubert static void eap_teap_process_phase2(struct eap_sm *sm, 1712206b73d0SCy Schubert struct eap_teap_data *data, 1713206b73d0SCy Schubert struct wpabuf *in_buf) 1714206b73d0SCy Schubert { 1715206b73d0SCy Schubert struct wpabuf *in_decrypted; 1716206b73d0SCy Schubert 1717206b73d0SCy Schubert wpa_printf(MSG_DEBUG, 1718206b73d0SCy Schubert "EAP-TEAP: Received %lu bytes encrypted data for Phase 2", 1719206b73d0SCy Schubert (unsigned long) wpabuf_len(in_buf)); 1720206b73d0SCy Schubert 1721206b73d0SCy Schubert if (data->pending_phase2_resp) { 1722206b73d0SCy Schubert wpa_printf(MSG_DEBUG, 1723206b73d0SCy Schubert "EAP-TEAP: Pending Phase 2 response - skip decryption and use old data"); 1724206b73d0SCy Schubert eap_teap_process_phase2_tlvs(sm, data, 1725206b73d0SCy Schubert data->pending_phase2_resp); 1726206b73d0SCy Schubert wpabuf_free(data->pending_phase2_resp); 1727206b73d0SCy Schubert data->pending_phase2_resp = NULL; 1728206b73d0SCy Schubert return; 1729206b73d0SCy Schubert } 1730206b73d0SCy Schubert 1731c1d255d3SCy Schubert in_decrypted = tls_connection_decrypt(sm->cfg->ssl_ctx, data->ssl.conn, 1732206b73d0SCy Schubert in_buf); 1733206b73d0SCy Schubert if (!in_decrypted) { 1734206b73d0SCy Schubert wpa_printf(MSG_INFO, 1735206b73d0SCy Schubert "EAP-TEAP: Failed to decrypt Phase 2 data"); 1736206b73d0SCy Schubert eap_teap_state(data, FAILURE); 1737206b73d0SCy Schubert return; 1738206b73d0SCy Schubert } 1739206b73d0SCy Schubert 1740206b73d0SCy Schubert wpa_hexdump_buf_key(MSG_DEBUG, "EAP-TEAP: Decrypted Phase 2 TLVs", 1741206b73d0SCy Schubert in_decrypted); 1742206b73d0SCy Schubert 1743206b73d0SCy Schubert eap_teap_process_phase2_tlvs(sm, data, in_decrypted); 1744206b73d0SCy Schubert 1745206b73d0SCy Schubert if (sm->method_pending == METHOD_PENDING_WAIT) { 1746206b73d0SCy Schubert wpa_printf(MSG_DEBUG, 1747206b73d0SCy Schubert "EAP-TEAP: Phase 2 method is in pending wait state - save decrypted response"); 1748206b73d0SCy Schubert wpabuf_free(data->pending_phase2_resp); 1749206b73d0SCy Schubert data->pending_phase2_resp = in_decrypted; 1750206b73d0SCy Schubert return; 1751206b73d0SCy Schubert } 1752206b73d0SCy Schubert 1753206b73d0SCy Schubert wpabuf_free(in_decrypted); 1754206b73d0SCy Schubert } 1755206b73d0SCy Schubert 1756206b73d0SCy Schubert 1757206b73d0SCy Schubert static int eap_teap_process_version(struct eap_sm *sm, void *priv, 1758206b73d0SCy Schubert int peer_version) 1759206b73d0SCy Schubert { 1760206b73d0SCy Schubert struct eap_teap_data *data = priv; 1761206b73d0SCy Schubert 1762206b73d0SCy Schubert if (peer_version < 1) { 1763206b73d0SCy Schubert /* Version 1 was the first defined version, so reject 0 */ 1764206b73d0SCy Schubert wpa_printf(MSG_INFO, 1765206b73d0SCy Schubert "EAP-TEAP: Peer used unknown TEAP version %u", 1766206b73d0SCy Schubert peer_version); 1767206b73d0SCy Schubert return -1; 1768206b73d0SCy Schubert } 1769206b73d0SCy Schubert 1770206b73d0SCy Schubert if (peer_version < data->teap_version) { 1771206b73d0SCy Schubert wpa_printf(MSG_DEBUG, "EAP-TEAP: peer ver=%u, own ver=%u; " 1772206b73d0SCy Schubert "use version %u", 1773206b73d0SCy Schubert peer_version, data->teap_version, peer_version); 1774206b73d0SCy Schubert data->teap_version = peer_version; 1775206b73d0SCy Schubert } 1776206b73d0SCy Schubert 1777206b73d0SCy Schubert data->peer_version = peer_version; 1778206b73d0SCy Schubert 1779206b73d0SCy Schubert return 0; 1780206b73d0SCy Schubert } 1781206b73d0SCy Schubert 1782206b73d0SCy Schubert 1783206b73d0SCy Schubert static int eap_teap_process_phase1(struct eap_sm *sm, 1784206b73d0SCy Schubert struct eap_teap_data *data) 1785206b73d0SCy Schubert { 1786206b73d0SCy Schubert if (eap_server_tls_phase1(sm, &data->ssl) < 0) { 1787206b73d0SCy Schubert wpa_printf(MSG_INFO, "EAP-TEAP: TLS processing failed"); 1788206b73d0SCy Schubert eap_teap_state(data, FAILURE); 1789206b73d0SCy Schubert return -1; 1790206b73d0SCy Schubert } 1791206b73d0SCy Schubert 1792c1d255d3SCy Schubert if (!tls_connection_established(sm->cfg->ssl_ctx, data->ssl.conn) || 1793206b73d0SCy Schubert wpabuf_len(data->ssl.tls_out) > 0) 1794206b73d0SCy Schubert return 1; 1795206b73d0SCy Schubert 1796206b73d0SCy Schubert /* 1797206b73d0SCy Schubert * Phase 1 was completed with the received message (e.g., when using 1798206b73d0SCy Schubert * abbreviated handshake), so Phase 2 can be started immediately 1799206b73d0SCy Schubert * without having to send through an empty message to the peer. 1800206b73d0SCy Schubert */ 1801206b73d0SCy Schubert 1802206b73d0SCy Schubert return eap_teap_phase1_done(sm, data); 1803206b73d0SCy Schubert } 1804206b73d0SCy Schubert 1805206b73d0SCy Schubert 1806206b73d0SCy Schubert static int eap_teap_process_phase2_start(struct eap_sm *sm, 1807206b73d0SCy Schubert struct eap_teap_data *data) 1808206b73d0SCy Schubert { 1809c1d255d3SCy Schubert int next_vendor; 1810c1d255d3SCy Schubert enum eap_type next_type; 1811206b73d0SCy Schubert 1812206b73d0SCy Schubert if (data->identity) { 1813206b73d0SCy Schubert /* Used PAC and identity is from PAC-Opaque */ 1814206b73d0SCy Schubert os_free(sm->identity); 1815206b73d0SCy Schubert sm->identity = data->identity; 1816206b73d0SCy Schubert data->identity = NULL; 1817206b73d0SCy Schubert sm->identity_len = data->identity_len; 1818206b73d0SCy Schubert data->identity_len = 0; 1819206b73d0SCy Schubert if (eap_user_get(sm, sm->identity, sm->identity_len, 1) != 0) { 1820206b73d0SCy Schubert wpa_hexdump_ascii(MSG_DEBUG, 1821206b73d0SCy Schubert "EAP-TEAP: Phase 2 Identity not found in the user database", 1822206b73d0SCy Schubert sm->identity, sm->identity_len); 1823c1d255d3SCy Schubert next_vendor = EAP_VENDOR_IETF; 1824206b73d0SCy Schubert next_type = EAP_TYPE_NONE; 1825206b73d0SCy Schubert eap_teap_state(data, PHASE2_METHOD); 1826c1d255d3SCy Schubert } else if (sm->cfg->eap_teap_pac_no_inner || 1827c1d255d3SCy Schubert sm->cfg->eap_teap_auth == 2) { 1828206b73d0SCy Schubert wpa_printf(MSG_DEBUG, 1829c1d255d3SCy Schubert "EAP-TEAP: Used PAC or client certificate and identity already known - skip inner auth"); 1830c1d255d3SCy Schubert data->skipped_inner_auth = 1; 1831206b73d0SCy Schubert /* FIX: Need to derive CMK here. However, how is that 1832206b73d0SCy Schubert * supposed to be done? RFC 7170 does not tell that for 1833206b73d0SCy Schubert * the no-inner-auth case. */ 1834c1d255d3SCy Schubert eap_teap_derive_cmk_basic_pw_auth(data->tls_cs, 1835c1d255d3SCy Schubert data->simck_msk, 1836206b73d0SCy Schubert data->cmk_msk); 1837206b73d0SCy Schubert eap_teap_state(data, CRYPTO_BINDING); 1838206b73d0SCy Schubert return 1; 1839c1d255d3SCy Schubert } else if (sm->cfg->eap_teap_auth == 1) { 1840206b73d0SCy Schubert eap_teap_state(data, PHASE2_BASIC_AUTH); 1841206b73d0SCy Schubert return 1; 1842206b73d0SCy Schubert } else { 1843206b73d0SCy Schubert wpa_printf(MSG_DEBUG, 1844206b73d0SCy Schubert "EAP-TEAP: Identity already known - skip Phase 2 Identity Request"); 1845c1d255d3SCy Schubert next_vendor = sm->user->methods[0].vendor; 1846206b73d0SCy Schubert next_type = sm->user->methods[0].method; 1847206b73d0SCy Schubert sm->user_eap_method_index = 1; 1848206b73d0SCy Schubert eap_teap_state(data, PHASE2_METHOD); 1849206b73d0SCy Schubert } 1850206b73d0SCy Schubert 1851c1d255d3SCy Schubert } else if (sm->cfg->eap_teap_auth == 1) { 1852206b73d0SCy Schubert eap_teap_state(data, PHASE2_BASIC_AUTH); 1853206b73d0SCy Schubert return 0; 1854206b73d0SCy Schubert } else { 1855206b73d0SCy Schubert eap_teap_state(data, PHASE2_ID); 1856c1d255d3SCy Schubert next_vendor = EAP_VENDOR_IETF; 1857206b73d0SCy Schubert next_type = EAP_TYPE_IDENTITY; 1858206b73d0SCy Schubert } 1859206b73d0SCy Schubert 1860c1d255d3SCy Schubert return eap_teap_phase2_init(sm, data, next_vendor, next_type); 1861206b73d0SCy Schubert } 1862206b73d0SCy Schubert 1863206b73d0SCy Schubert 1864206b73d0SCy Schubert static void eap_teap_process_msg(struct eap_sm *sm, void *priv, 1865206b73d0SCy Schubert const struct wpabuf *respData) 1866206b73d0SCy Schubert { 1867206b73d0SCy Schubert struct eap_teap_data *data = priv; 1868206b73d0SCy Schubert 1869206b73d0SCy Schubert switch (data->state) { 1870206b73d0SCy Schubert case PHASE1: 1871206b73d0SCy Schubert case PHASE1B: 1872206b73d0SCy Schubert if (eap_teap_process_phase1(sm, data)) 1873206b73d0SCy Schubert break; 1874206b73d0SCy Schubert 1875206b73d0SCy Schubert /* fall through */ 1876206b73d0SCy Schubert case PHASE2_START: 1877206b73d0SCy Schubert eap_teap_process_phase2_start(sm, data); 1878206b73d0SCy Schubert break; 1879206b73d0SCy Schubert case PHASE2_ID: 1880206b73d0SCy Schubert case PHASE2_BASIC_AUTH: 1881206b73d0SCy Schubert case PHASE2_METHOD: 1882206b73d0SCy Schubert case CRYPTO_BINDING: 1883206b73d0SCy Schubert case REQUEST_PAC: 1884c1d255d3SCy Schubert case SUCCESS_SEND_RESULT: 1885206b73d0SCy Schubert eap_teap_process_phase2(sm, data, data->ssl.tls_in); 1886206b73d0SCy Schubert break; 1887206b73d0SCy Schubert case FAILURE_SEND_RESULT: 1888206b73d0SCy Schubert /* Protected failure result indication completed. Ignore the 1889206b73d0SCy Schubert * received message (which is supposed to include Result TLV 1890206b73d0SCy Schubert * indicating failure) and terminate exchange with cleartext 1891206b73d0SCy Schubert * EAP-Failure. */ 1892206b73d0SCy Schubert eap_teap_state(data, FAILURE); 1893206b73d0SCy Schubert break; 1894206b73d0SCy Schubert default: 1895206b73d0SCy Schubert wpa_printf(MSG_DEBUG, "EAP-TEAP: Unexpected state %d in %s", 1896206b73d0SCy Schubert data->state, __func__); 1897206b73d0SCy Schubert break; 1898206b73d0SCy Schubert } 1899206b73d0SCy Schubert } 1900206b73d0SCy Schubert 1901206b73d0SCy Schubert 1902206b73d0SCy Schubert static void eap_teap_process(struct eap_sm *sm, void *priv, 1903206b73d0SCy Schubert struct wpabuf *respData) 1904206b73d0SCy Schubert { 1905206b73d0SCy Schubert struct eap_teap_data *data = priv; 1906206b73d0SCy Schubert const u8 *pos; 1907206b73d0SCy Schubert size_t len; 1908206b73d0SCy Schubert struct wpabuf *resp = respData; 1909206b73d0SCy Schubert u8 flags; 1910206b73d0SCy Schubert 1911206b73d0SCy Schubert pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_TEAP, respData, &len); 1912206b73d0SCy Schubert if (!pos || len < 1) 1913206b73d0SCy Schubert return; 1914206b73d0SCy Schubert 1915206b73d0SCy Schubert flags = *pos++; 1916206b73d0SCy Schubert len--; 1917206b73d0SCy Schubert 1918206b73d0SCy Schubert if (flags & EAP_TEAP_FLAGS_OUTER_TLV_LEN) { 1919206b73d0SCy Schubert /* Extract Outer TLVs from the message before common TLS 1920206b73d0SCy Schubert * processing */ 1921206b73d0SCy Schubert u32 message_len = 0, outer_tlv_len; 1922206b73d0SCy Schubert const u8 *hdr; 1923206b73d0SCy Schubert 1924206b73d0SCy Schubert if (data->state != PHASE1) { 1925206b73d0SCy Schubert wpa_printf(MSG_INFO, 1926206b73d0SCy Schubert "EAP-TEAP: Unexpected Outer TLVs in a message that is not the first message from the peer"); 1927206b73d0SCy Schubert return; 1928206b73d0SCy Schubert } 1929206b73d0SCy Schubert 1930206b73d0SCy Schubert if (flags & EAP_TLS_FLAGS_LENGTH_INCLUDED) { 1931206b73d0SCy Schubert if (len < 4) { 1932206b73d0SCy Schubert wpa_printf(MSG_INFO, 1933206b73d0SCy Schubert "EAP-TEAP: Too short message to include Message Length field"); 1934206b73d0SCy Schubert return; 1935206b73d0SCy Schubert } 1936206b73d0SCy Schubert 1937206b73d0SCy Schubert message_len = WPA_GET_BE32(pos); 1938206b73d0SCy Schubert pos += 4; 1939206b73d0SCy Schubert len -= 4; 1940206b73d0SCy Schubert if (message_len < 4) { 1941206b73d0SCy Schubert wpa_printf(MSG_INFO, 1942206b73d0SCy Schubert "EAP-TEAP: Message Length field has too msall value to include Outer TLV Length field"); 1943206b73d0SCy Schubert return; 1944206b73d0SCy Schubert } 1945206b73d0SCy Schubert } 1946206b73d0SCy Schubert 1947206b73d0SCy Schubert if (len < 4) { 1948206b73d0SCy Schubert wpa_printf(MSG_INFO, 1949206b73d0SCy Schubert "EAP-TEAP: Too short message to include Outer TLVs Length field"); 1950206b73d0SCy Schubert return; 1951206b73d0SCy Schubert } 1952206b73d0SCy Schubert 1953206b73d0SCy Schubert outer_tlv_len = WPA_GET_BE32(pos); 1954206b73d0SCy Schubert pos += 4; 1955206b73d0SCy Schubert len -= 4; 1956206b73d0SCy Schubert 1957206b73d0SCy Schubert wpa_printf(MSG_DEBUG, 1958206b73d0SCy Schubert "EAP-TEAP: Message Length %u Outer TLV Length %u", 1959206b73d0SCy Schubert message_len, outer_tlv_len); 1960206b73d0SCy Schubert if (len < outer_tlv_len) { 1961206b73d0SCy Schubert wpa_printf(MSG_INFO, 1962206b73d0SCy Schubert "EAP-TEAP: Too short message to include Outer TLVs field"); 1963206b73d0SCy Schubert return; 1964206b73d0SCy Schubert } 1965206b73d0SCy Schubert 1966206b73d0SCy Schubert if (message_len && 1967206b73d0SCy Schubert (message_len < outer_tlv_len || 1968206b73d0SCy Schubert message_len < 4 + outer_tlv_len)) { 1969206b73d0SCy Schubert wpa_printf(MSG_INFO, 1970206b73d0SCy Schubert "EAP-TEAP: Message Length field has too small value to include Outer TLVs"); 1971206b73d0SCy Schubert return; 1972206b73d0SCy Schubert } 1973206b73d0SCy Schubert 1974206b73d0SCy Schubert if (wpabuf_len(respData) < 4 + outer_tlv_len || 1975206b73d0SCy Schubert len < outer_tlv_len) 1976206b73d0SCy Schubert return; 1977206b73d0SCy Schubert resp = wpabuf_alloc(wpabuf_len(respData) - 4 - outer_tlv_len); 1978206b73d0SCy Schubert if (!resp) 1979206b73d0SCy Schubert return; 1980206b73d0SCy Schubert hdr = wpabuf_head(respData); 1981206b73d0SCy Schubert wpabuf_put_u8(resp, *hdr++); /* Code */ 1982206b73d0SCy Schubert wpabuf_put_u8(resp, *hdr++); /* Identifier */ 1983206b73d0SCy Schubert wpabuf_put_be16(resp, WPA_GET_BE16(hdr) - 4 - outer_tlv_len); 1984206b73d0SCy Schubert hdr += 2; 1985206b73d0SCy Schubert wpabuf_put_u8(resp, *hdr++); /* Type */ 1986206b73d0SCy Schubert /* Flags | Ver */ 1987206b73d0SCy Schubert wpabuf_put_u8(resp, flags & ~EAP_TEAP_FLAGS_OUTER_TLV_LEN); 1988206b73d0SCy Schubert 1989206b73d0SCy Schubert if (flags & EAP_TLS_FLAGS_LENGTH_INCLUDED) 1990206b73d0SCy Schubert wpabuf_put_be32(resp, message_len - 4 - outer_tlv_len); 1991206b73d0SCy Schubert 1992206b73d0SCy Schubert wpabuf_put_data(resp, pos, len - outer_tlv_len); 1993206b73d0SCy Schubert pos += len - outer_tlv_len; 1994206b73d0SCy Schubert wpabuf_free(data->peer_outer_tlvs); 1995206b73d0SCy Schubert data->peer_outer_tlvs = wpabuf_alloc_copy(pos, outer_tlv_len); 1996206b73d0SCy Schubert if (!data->peer_outer_tlvs) 1997206b73d0SCy Schubert return; 1998206b73d0SCy Schubert wpa_hexdump_buf(MSG_DEBUG, "EAP-TEAP: Outer TLVs", 1999206b73d0SCy Schubert data->peer_outer_tlvs); 2000206b73d0SCy Schubert 2001206b73d0SCy Schubert wpa_hexdump_buf(MSG_DEBUG, 2002206b73d0SCy Schubert "EAP-TEAP: TLS Data message after Outer TLV removal", 2003206b73d0SCy Schubert resp); 2004206b73d0SCy Schubert pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_TEAP, resp, 2005206b73d0SCy Schubert &len); 2006206b73d0SCy Schubert if (!pos || len < 1) { 2007206b73d0SCy Schubert wpa_printf(MSG_INFO, 2008206b73d0SCy Schubert "EAP-TEAP: Invalid frame after Outer TLV removal"); 2009206b73d0SCy Schubert return; 2010206b73d0SCy Schubert } 2011206b73d0SCy Schubert } 2012206b73d0SCy Schubert 2013206b73d0SCy Schubert if (data->state == PHASE1) 2014206b73d0SCy Schubert eap_teap_state(data, PHASE1B); 2015206b73d0SCy Schubert 2016206b73d0SCy Schubert if (eap_server_tls_process(sm, &data->ssl, resp, data, 2017206b73d0SCy Schubert EAP_TYPE_TEAP, eap_teap_process_version, 2018206b73d0SCy Schubert eap_teap_process_msg) < 0) 2019206b73d0SCy Schubert eap_teap_state(data, FAILURE); 2020206b73d0SCy Schubert 2021206b73d0SCy Schubert if (resp != respData) 2022206b73d0SCy Schubert wpabuf_free(resp); 2023206b73d0SCy Schubert } 2024206b73d0SCy Schubert 2025206b73d0SCy Schubert 2026c1d255d3SCy Schubert static bool eap_teap_isDone(struct eap_sm *sm, void *priv) 2027206b73d0SCy Schubert { 2028206b73d0SCy Schubert struct eap_teap_data *data = priv; 2029206b73d0SCy Schubert 2030206b73d0SCy Schubert return data->state == SUCCESS || data->state == FAILURE; 2031206b73d0SCy Schubert } 2032206b73d0SCy Schubert 2033206b73d0SCy Schubert 2034206b73d0SCy Schubert static u8 * eap_teap_getKey(struct eap_sm *sm, void *priv, size_t *len) 2035206b73d0SCy Schubert { 2036206b73d0SCy Schubert struct eap_teap_data *data = priv; 2037206b73d0SCy Schubert u8 *eapKeyData; 2038206b73d0SCy Schubert 2039206b73d0SCy Schubert if (data->state != SUCCESS) 2040206b73d0SCy Schubert return NULL; 2041206b73d0SCy Schubert 2042206b73d0SCy Schubert eapKeyData = os_malloc(EAP_TEAP_KEY_LEN); 2043206b73d0SCy Schubert if (!eapKeyData) 2044206b73d0SCy Schubert return NULL; 2045206b73d0SCy Schubert 2046206b73d0SCy Schubert /* FIX: RFC 7170 does not describe whether MSK or EMSK based S-IMCK[j] 2047206b73d0SCy Schubert * is used in this derivation */ 2048c1d255d3SCy Schubert if (eap_teap_derive_eap_msk(data->tls_cs, data->simck_msk, 2049c1d255d3SCy Schubert eapKeyData) < 0) { 2050206b73d0SCy Schubert os_free(eapKeyData); 2051206b73d0SCy Schubert return NULL; 2052206b73d0SCy Schubert } 2053206b73d0SCy Schubert *len = EAP_TEAP_KEY_LEN; 2054206b73d0SCy Schubert 2055206b73d0SCy Schubert return eapKeyData; 2056206b73d0SCy Schubert } 2057206b73d0SCy Schubert 2058206b73d0SCy Schubert 2059206b73d0SCy Schubert static u8 * eap_teap_get_emsk(struct eap_sm *sm, void *priv, size_t *len) 2060206b73d0SCy Schubert { 2061206b73d0SCy Schubert struct eap_teap_data *data = priv; 2062206b73d0SCy Schubert u8 *eapKeyData; 2063206b73d0SCy Schubert 2064206b73d0SCy Schubert if (data->state != SUCCESS) 2065206b73d0SCy Schubert return NULL; 2066206b73d0SCy Schubert 2067206b73d0SCy Schubert eapKeyData = os_malloc(EAP_EMSK_LEN); 2068206b73d0SCy Schubert if (!eapKeyData) 2069206b73d0SCy Schubert return NULL; 2070206b73d0SCy Schubert 2071206b73d0SCy Schubert /* FIX: RFC 7170 does not describe whether MSK or EMSK based S-IMCK[j] 2072206b73d0SCy Schubert * is used in this derivation */ 2073c1d255d3SCy Schubert if (eap_teap_derive_eap_emsk(data->tls_cs, data->simck_msk, 2074c1d255d3SCy Schubert eapKeyData) < 0) { 2075206b73d0SCy Schubert os_free(eapKeyData); 2076206b73d0SCy Schubert return NULL; 2077206b73d0SCy Schubert } 2078206b73d0SCy Schubert *len = EAP_EMSK_LEN; 2079206b73d0SCy Schubert 2080206b73d0SCy Schubert return eapKeyData; 2081206b73d0SCy Schubert } 2082206b73d0SCy Schubert 2083206b73d0SCy Schubert 2084c1d255d3SCy Schubert static bool eap_teap_isSuccess(struct eap_sm *sm, void *priv) 2085206b73d0SCy Schubert { 2086206b73d0SCy Schubert struct eap_teap_data *data = priv; 2087206b73d0SCy Schubert 2088206b73d0SCy Schubert return data->state == SUCCESS; 2089206b73d0SCy Schubert } 2090206b73d0SCy Schubert 2091206b73d0SCy Schubert 2092206b73d0SCy Schubert static u8 * eap_teap_get_session_id(struct eap_sm *sm, void *priv, size_t *len) 2093206b73d0SCy Schubert { 2094206b73d0SCy Schubert struct eap_teap_data *data = priv; 2095206b73d0SCy Schubert const size_t max_id_len = 100; 2096206b73d0SCy Schubert int res; 2097206b73d0SCy Schubert u8 *id; 2098206b73d0SCy Schubert 2099206b73d0SCy Schubert if (data->state != SUCCESS) 2100206b73d0SCy Schubert return NULL; 2101206b73d0SCy Schubert 2102206b73d0SCy Schubert id = os_malloc(max_id_len); 2103206b73d0SCy Schubert if (!id) 2104206b73d0SCy Schubert return NULL; 2105206b73d0SCy Schubert 2106206b73d0SCy Schubert id[0] = EAP_TYPE_TEAP; 2107206b73d0SCy Schubert res = tls_get_tls_unique(data->ssl.conn, id + 1, max_id_len - 1); 2108206b73d0SCy Schubert if (res < 0) { 2109206b73d0SCy Schubert os_free(id); 2110206b73d0SCy Schubert wpa_printf(MSG_ERROR, "EAP-TEAP: Failed to derive Session-Id"); 2111206b73d0SCy Schubert return NULL; 2112206b73d0SCy Schubert } 2113206b73d0SCy Schubert 2114206b73d0SCy Schubert *len = 1 + res; 2115206b73d0SCy Schubert wpa_hexdump(MSG_DEBUG, "EAP-TEAP: Derived Session-Id", id, *len); 2116206b73d0SCy Schubert return id; 2117206b73d0SCy Schubert } 2118206b73d0SCy Schubert 2119206b73d0SCy Schubert 2120206b73d0SCy Schubert int eap_server_teap_register(void) 2121206b73d0SCy Schubert { 2122206b73d0SCy Schubert struct eap_method *eap; 2123206b73d0SCy Schubert 2124206b73d0SCy Schubert eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION, 2125206b73d0SCy Schubert EAP_VENDOR_IETF, EAP_TYPE_TEAP, "TEAP"); 2126206b73d0SCy Schubert if (!eap) 2127206b73d0SCy Schubert return -1; 2128206b73d0SCy Schubert 2129206b73d0SCy Schubert eap->init = eap_teap_init; 2130206b73d0SCy Schubert eap->reset = eap_teap_reset; 2131206b73d0SCy Schubert eap->buildReq = eap_teap_buildReq; 2132206b73d0SCy Schubert eap->check = eap_teap_check; 2133206b73d0SCy Schubert eap->process = eap_teap_process; 2134206b73d0SCy Schubert eap->isDone = eap_teap_isDone; 2135206b73d0SCy Schubert eap->getKey = eap_teap_getKey; 2136206b73d0SCy Schubert eap->get_emsk = eap_teap_get_emsk; 2137206b73d0SCy Schubert eap->isSuccess = eap_teap_isSuccess; 2138206b73d0SCy Schubert eap->getSessionId = eap_teap_get_session_id; 2139206b73d0SCy Schubert 2140206b73d0SCy Schubert return eap_server_method_register(eap); 2141206b73d0SCy Schubert } 2142