139beb93cSSam Leffler /* 239beb93cSSam Leffler * EAP peer method: EAP-TLS (RFC 2716) 3*f05cddf9SRui Paulo * Copyright (c) 2004-2008, 2012, Jouni Malinen <j@w1.fi> 439beb93cSSam Leffler * 5*f05cddf9SRui Paulo * This software may be distributed under the terms of the BSD license. 6*f05cddf9SRui Paulo * See README for more details. 739beb93cSSam Leffler */ 839beb93cSSam Leffler 939beb93cSSam Leffler #include "includes.h" 1039beb93cSSam Leffler 1139beb93cSSam Leffler #include "common.h" 12e28a4053SRui Paulo #include "crypto/tls.h" 1339beb93cSSam Leffler #include "eap_i.h" 1439beb93cSSam Leffler #include "eap_tls_common.h" 1539beb93cSSam Leffler #include "eap_config.h" 1639beb93cSSam Leffler 1739beb93cSSam Leffler 1839beb93cSSam Leffler static void eap_tls_deinit(struct eap_sm *sm, void *priv); 1939beb93cSSam Leffler 2039beb93cSSam Leffler 2139beb93cSSam Leffler struct eap_tls_data { 2239beb93cSSam Leffler struct eap_ssl_data ssl; 2339beb93cSSam Leffler u8 *key_data; 24*f05cddf9SRui Paulo void *ssl_ctx; 25*f05cddf9SRui Paulo u8 eap_type; 2639beb93cSSam Leffler }; 2739beb93cSSam Leffler 2839beb93cSSam Leffler 2939beb93cSSam Leffler static void * eap_tls_init(struct eap_sm *sm) 3039beb93cSSam Leffler { 3139beb93cSSam Leffler struct eap_tls_data *data; 3239beb93cSSam Leffler struct eap_peer_config *config = eap_get_config(sm); 3339beb93cSSam Leffler if (config == NULL || 3439beb93cSSam Leffler ((sm->init_phase2 ? config->private_key2 : config->private_key) 3539beb93cSSam Leffler == NULL && 3639beb93cSSam Leffler (sm->init_phase2 ? config->engine2 : config->engine) == 0)) { 3739beb93cSSam Leffler wpa_printf(MSG_INFO, "EAP-TLS: Private key not configured"); 3839beb93cSSam Leffler return NULL; 3939beb93cSSam Leffler } 4039beb93cSSam Leffler 4139beb93cSSam Leffler data = os_zalloc(sizeof(*data)); 4239beb93cSSam Leffler if (data == NULL) 4339beb93cSSam Leffler return NULL; 4439beb93cSSam Leffler 45*f05cddf9SRui Paulo data->ssl_ctx = sm->init_phase2 && sm->ssl_ctx2 ? sm->ssl_ctx2 : 46*f05cddf9SRui Paulo sm->ssl_ctx; 47*f05cddf9SRui Paulo 48*f05cddf9SRui Paulo if (eap_peer_tls_ssl_init(sm, &data->ssl, config, EAP_TYPE_TLS)) { 4939beb93cSSam Leffler wpa_printf(MSG_INFO, "EAP-TLS: Failed to initialize SSL."); 5039beb93cSSam Leffler eap_tls_deinit(sm, data); 5139beb93cSSam Leffler if (config->engine) { 5239beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-TLS: Requesting Smartcard " 5339beb93cSSam Leffler "PIN"); 5439beb93cSSam Leffler eap_sm_request_pin(sm); 5539beb93cSSam Leffler sm->ignore = TRUE; 5639beb93cSSam Leffler } else if (config->private_key && !config->private_key_passwd) 5739beb93cSSam Leffler { 5839beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-TLS: Requesting private " 5939beb93cSSam Leffler "key passphrase"); 6039beb93cSSam Leffler eap_sm_request_passphrase(sm); 6139beb93cSSam Leffler sm->ignore = TRUE; 6239beb93cSSam Leffler } 6339beb93cSSam Leffler return NULL; 6439beb93cSSam Leffler } 6539beb93cSSam Leffler 66*f05cddf9SRui Paulo data->eap_type = EAP_TYPE_TLS; 67*f05cddf9SRui Paulo 6839beb93cSSam Leffler return data; 6939beb93cSSam Leffler } 7039beb93cSSam Leffler 7139beb93cSSam Leffler 72*f05cddf9SRui Paulo #ifdef EAP_UNAUTH_TLS 73*f05cddf9SRui Paulo static void * eap_unauth_tls_init(struct eap_sm *sm) 74*f05cddf9SRui Paulo { 75*f05cddf9SRui Paulo struct eap_tls_data *data; 76*f05cddf9SRui Paulo struct eap_peer_config *config = eap_get_config(sm); 77*f05cddf9SRui Paulo 78*f05cddf9SRui Paulo data = os_zalloc(sizeof(*data)); 79*f05cddf9SRui Paulo if (data == NULL) 80*f05cddf9SRui Paulo return NULL; 81*f05cddf9SRui Paulo 82*f05cddf9SRui Paulo data->ssl_ctx = sm->init_phase2 && sm->ssl_ctx2 ? sm->ssl_ctx2 : 83*f05cddf9SRui Paulo sm->ssl_ctx; 84*f05cddf9SRui Paulo 85*f05cddf9SRui Paulo if (eap_peer_tls_ssl_init(sm, &data->ssl, config, 86*f05cddf9SRui Paulo EAP_UNAUTH_TLS_TYPE)) { 87*f05cddf9SRui Paulo wpa_printf(MSG_INFO, "EAP-TLS: Failed to initialize SSL."); 88*f05cddf9SRui Paulo eap_tls_deinit(sm, data); 89*f05cddf9SRui Paulo return NULL; 90*f05cddf9SRui Paulo } 91*f05cddf9SRui Paulo 92*f05cddf9SRui Paulo data->eap_type = EAP_UNAUTH_TLS_TYPE; 93*f05cddf9SRui Paulo 94*f05cddf9SRui Paulo return data; 95*f05cddf9SRui Paulo } 96*f05cddf9SRui Paulo #endif /* EAP_UNAUTH_TLS */ 97*f05cddf9SRui Paulo 98*f05cddf9SRui Paulo 9939beb93cSSam Leffler static void eap_tls_deinit(struct eap_sm *sm, void *priv) 10039beb93cSSam Leffler { 10139beb93cSSam Leffler struct eap_tls_data *data = priv; 10239beb93cSSam Leffler if (data == NULL) 10339beb93cSSam Leffler return; 10439beb93cSSam Leffler eap_peer_tls_ssl_deinit(sm, &data->ssl); 10539beb93cSSam Leffler os_free(data->key_data); 10639beb93cSSam Leffler os_free(data); 10739beb93cSSam Leffler } 10839beb93cSSam Leffler 10939beb93cSSam Leffler 11039beb93cSSam Leffler static struct wpabuf * eap_tls_failure(struct eap_sm *sm, 11139beb93cSSam Leffler struct eap_tls_data *data, 11239beb93cSSam Leffler struct eap_method_ret *ret, int res, 11339beb93cSSam Leffler struct wpabuf *resp, u8 id) 11439beb93cSSam Leffler { 11539beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-TLS: TLS processing failed"); 11639beb93cSSam Leffler 11739beb93cSSam Leffler ret->methodState = METHOD_DONE; 11839beb93cSSam Leffler ret->decision = DECISION_FAIL; 11939beb93cSSam Leffler 12039beb93cSSam Leffler if (res == -1) { 12139beb93cSSam Leffler struct eap_peer_config *config = eap_get_config(sm); 12239beb93cSSam Leffler if (config) { 12339beb93cSSam Leffler /* 12439beb93cSSam Leffler * The TLS handshake failed. So better forget the old 12539beb93cSSam Leffler * PIN. It may be wrong, we cannot be sure but trying 12639beb93cSSam Leffler * the wrong one again might block it on the card--so 12739beb93cSSam Leffler * better ask the user again. 12839beb93cSSam Leffler */ 12939beb93cSSam Leffler os_free(config->pin); 13039beb93cSSam Leffler config->pin = NULL; 13139beb93cSSam Leffler } 13239beb93cSSam Leffler } 13339beb93cSSam Leffler 13439beb93cSSam Leffler if (resp) { 13539beb93cSSam Leffler /* 13639beb93cSSam Leffler * This is likely an alert message, so send it instead of just 13739beb93cSSam Leffler * ACKing the error. 13839beb93cSSam Leffler */ 13939beb93cSSam Leffler return resp; 14039beb93cSSam Leffler } 14139beb93cSSam Leffler 142*f05cddf9SRui Paulo return eap_peer_tls_build_ack(id, data->eap_type, 0); 14339beb93cSSam Leffler } 14439beb93cSSam Leffler 14539beb93cSSam Leffler 14639beb93cSSam Leffler static void eap_tls_success(struct eap_sm *sm, struct eap_tls_data *data, 14739beb93cSSam Leffler struct eap_method_ret *ret) 14839beb93cSSam Leffler { 14939beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-TLS: Done"); 15039beb93cSSam Leffler 15139beb93cSSam Leffler ret->methodState = METHOD_DONE; 15239beb93cSSam Leffler ret->decision = DECISION_UNCOND_SUCC; 15339beb93cSSam Leffler 15439beb93cSSam Leffler os_free(data->key_data); 15539beb93cSSam Leffler data->key_data = eap_peer_tls_derive_key(sm, &data->ssl, 15639beb93cSSam Leffler "client EAP encryption", 15739beb93cSSam Leffler EAP_TLS_KEY_LEN + 15839beb93cSSam Leffler EAP_EMSK_LEN); 15939beb93cSSam Leffler if (data->key_data) { 16039beb93cSSam Leffler wpa_hexdump_key(MSG_DEBUG, "EAP-TLS: Derived key", 16139beb93cSSam Leffler data->key_data, EAP_TLS_KEY_LEN); 16239beb93cSSam Leffler wpa_hexdump_key(MSG_DEBUG, "EAP-TLS: Derived EMSK", 16339beb93cSSam Leffler data->key_data + EAP_TLS_KEY_LEN, 16439beb93cSSam Leffler EAP_EMSK_LEN); 16539beb93cSSam Leffler } else { 16639beb93cSSam Leffler wpa_printf(MSG_INFO, "EAP-TLS: Failed to derive key"); 16739beb93cSSam Leffler } 16839beb93cSSam Leffler } 16939beb93cSSam Leffler 17039beb93cSSam Leffler 17139beb93cSSam Leffler static struct wpabuf * eap_tls_process(struct eap_sm *sm, void *priv, 17239beb93cSSam Leffler struct eap_method_ret *ret, 17339beb93cSSam Leffler const struct wpabuf *reqData) 17439beb93cSSam Leffler { 17539beb93cSSam Leffler size_t left; 17639beb93cSSam Leffler int res; 17739beb93cSSam Leffler struct wpabuf *resp; 17839beb93cSSam Leffler u8 flags, id; 17939beb93cSSam Leffler const u8 *pos; 18039beb93cSSam Leffler struct eap_tls_data *data = priv; 18139beb93cSSam Leffler 182*f05cddf9SRui Paulo pos = eap_peer_tls_process_init(sm, &data->ssl, data->eap_type, ret, 18339beb93cSSam Leffler reqData, &left, &flags); 18439beb93cSSam Leffler if (pos == NULL) 18539beb93cSSam Leffler return NULL; 18639beb93cSSam Leffler id = eap_get_id(reqData); 18739beb93cSSam Leffler 18839beb93cSSam Leffler if (flags & EAP_TLS_FLAGS_START) { 18939beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-TLS: Start"); 19039beb93cSSam Leffler left = 0; /* make sure that this frame is empty, even though it 19139beb93cSSam Leffler * should always be, anyway */ 19239beb93cSSam Leffler } 19339beb93cSSam Leffler 19439beb93cSSam Leffler resp = NULL; 195*f05cddf9SRui Paulo res = eap_peer_tls_process_helper(sm, &data->ssl, data->eap_type, 0, 196*f05cddf9SRui Paulo id, pos, left, &resp); 19739beb93cSSam Leffler 19839beb93cSSam Leffler if (res < 0) { 19939beb93cSSam Leffler return eap_tls_failure(sm, data, ret, res, resp, id); 20039beb93cSSam Leffler } 20139beb93cSSam Leffler 202*f05cddf9SRui Paulo if (tls_connection_established(data->ssl_ctx, data->ssl.conn)) 20339beb93cSSam Leffler eap_tls_success(sm, data, ret); 20439beb93cSSam Leffler 20539beb93cSSam Leffler if (res == 1) { 20639beb93cSSam Leffler wpabuf_free(resp); 207*f05cddf9SRui Paulo return eap_peer_tls_build_ack(id, data->eap_type, 0); 20839beb93cSSam Leffler } 20939beb93cSSam Leffler 21039beb93cSSam Leffler return resp; 21139beb93cSSam Leffler } 21239beb93cSSam Leffler 21339beb93cSSam Leffler 21439beb93cSSam Leffler static Boolean eap_tls_has_reauth_data(struct eap_sm *sm, void *priv) 21539beb93cSSam Leffler { 21639beb93cSSam Leffler struct eap_tls_data *data = priv; 217*f05cddf9SRui Paulo return tls_connection_established(data->ssl_ctx, data->ssl.conn); 21839beb93cSSam Leffler } 21939beb93cSSam Leffler 22039beb93cSSam Leffler 22139beb93cSSam Leffler static void eap_tls_deinit_for_reauth(struct eap_sm *sm, void *priv) 22239beb93cSSam Leffler { 22339beb93cSSam Leffler } 22439beb93cSSam Leffler 22539beb93cSSam Leffler 22639beb93cSSam Leffler static void * eap_tls_init_for_reauth(struct eap_sm *sm, void *priv) 22739beb93cSSam Leffler { 22839beb93cSSam Leffler struct eap_tls_data *data = priv; 22939beb93cSSam Leffler os_free(data->key_data); 23039beb93cSSam Leffler data->key_data = NULL; 23139beb93cSSam Leffler if (eap_peer_tls_reauth_init(sm, &data->ssl)) { 23239beb93cSSam Leffler os_free(data); 23339beb93cSSam Leffler return NULL; 23439beb93cSSam Leffler } 23539beb93cSSam Leffler return priv; 23639beb93cSSam Leffler } 23739beb93cSSam Leffler 23839beb93cSSam Leffler 23939beb93cSSam Leffler static int eap_tls_get_status(struct eap_sm *sm, void *priv, char *buf, 24039beb93cSSam Leffler size_t buflen, int verbose) 24139beb93cSSam Leffler { 24239beb93cSSam Leffler struct eap_tls_data *data = priv; 24339beb93cSSam Leffler return eap_peer_tls_status(sm, &data->ssl, buf, buflen, verbose); 24439beb93cSSam Leffler } 24539beb93cSSam Leffler 24639beb93cSSam Leffler 24739beb93cSSam Leffler static Boolean eap_tls_isKeyAvailable(struct eap_sm *sm, void *priv) 24839beb93cSSam Leffler { 24939beb93cSSam Leffler struct eap_tls_data *data = priv; 25039beb93cSSam Leffler return data->key_data != NULL; 25139beb93cSSam Leffler } 25239beb93cSSam Leffler 25339beb93cSSam Leffler 25439beb93cSSam Leffler static u8 * eap_tls_getKey(struct eap_sm *sm, void *priv, size_t *len) 25539beb93cSSam Leffler { 25639beb93cSSam Leffler struct eap_tls_data *data = priv; 25739beb93cSSam Leffler u8 *key; 25839beb93cSSam Leffler 25939beb93cSSam Leffler if (data->key_data == NULL) 26039beb93cSSam Leffler return NULL; 26139beb93cSSam Leffler 26239beb93cSSam Leffler key = os_malloc(EAP_TLS_KEY_LEN); 26339beb93cSSam Leffler if (key == NULL) 26439beb93cSSam Leffler return NULL; 26539beb93cSSam Leffler 26639beb93cSSam Leffler *len = EAP_TLS_KEY_LEN; 26739beb93cSSam Leffler os_memcpy(key, data->key_data, EAP_TLS_KEY_LEN); 26839beb93cSSam Leffler 26939beb93cSSam Leffler return key; 27039beb93cSSam Leffler } 27139beb93cSSam Leffler 27239beb93cSSam Leffler 27339beb93cSSam Leffler static u8 * eap_tls_get_emsk(struct eap_sm *sm, void *priv, size_t *len) 27439beb93cSSam Leffler { 27539beb93cSSam Leffler struct eap_tls_data *data = priv; 27639beb93cSSam Leffler u8 *key; 27739beb93cSSam Leffler 27839beb93cSSam Leffler if (data->key_data == NULL) 27939beb93cSSam Leffler return NULL; 28039beb93cSSam Leffler 28139beb93cSSam Leffler key = os_malloc(EAP_EMSK_LEN); 28239beb93cSSam Leffler if (key == NULL) 28339beb93cSSam Leffler return NULL; 28439beb93cSSam Leffler 28539beb93cSSam Leffler *len = EAP_EMSK_LEN; 28639beb93cSSam Leffler os_memcpy(key, data->key_data + EAP_TLS_KEY_LEN, EAP_EMSK_LEN); 28739beb93cSSam Leffler 28839beb93cSSam Leffler return key; 28939beb93cSSam Leffler } 29039beb93cSSam Leffler 29139beb93cSSam Leffler 29239beb93cSSam Leffler int eap_peer_tls_register(void) 29339beb93cSSam Leffler { 29439beb93cSSam Leffler struct eap_method *eap; 29539beb93cSSam Leffler int ret; 29639beb93cSSam Leffler 29739beb93cSSam Leffler eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION, 29839beb93cSSam Leffler EAP_VENDOR_IETF, EAP_TYPE_TLS, "TLS"); 29939beb93cSSam Leffler if (eap == NULL) 30039beb93cSSam Leffler return -1; 30139beb93cSSam Leffler 30239beb93cSSam Leffler eap->init = eap_tls_init; 30339beb93cSSam Leffler eap->deinit = eap_tls_deinit; 30439beb93cSSam Leffler eap->process = eap_tls_process; 30539beb93cSSam Leffler eap->isKeyAvailable = eap_tls_isKeyAvailable; 30639beb93cSSam Leffler eap->getKey = eap_tls_getKey; 30739beb93cSSam Leffler eap->get_status = eap_tls_get_status; 30839beb93cSSam Leffler eap->has_reauth_data = eap_tls_has_reauth_data; 30939beb93cSSam Leffler eap->deinit_for_reauth = eap_tls_deinit_for_reauth; 31039beb93cSSam Leffler eap->init_for_reauth = eap_tls_init_for_reauth; 31139beb93cSSam Leffler eap->get_emsk = eap_tls_get_emsk; 31239beb93cSSam Leffler 31339beb93cSSam Leffler ret = eap_peer_method_register(eap); 31439beb93cSSam Leffler if (ret) 31539beb93cSSam Leffler eap_peer_method_free(eap); 31639beb93cSSam Leffler return ret; 31739beb93cSSam Leffler } 318*f05cddf9SRui Paulo 319*f05cddf9SRui Paulo 320*f05cddf9SRui Paulo #ifdef EAP_UNAUTH_TLS 321*f05cddf9SRui Paulo int eap_peer_unauth_tls_register(void) 322*f05cddf9SRui Paulo { 323*f05cddf9SRui Paulo struct eap_method *eap; 324*f05cddf9SRui Paulo int ret; 325*f05cddf9SRui Paulo 326*f05cddf9SRui Paulo eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION, 327*f05cddf9SRui Paulo EAP_VENDOR_UNAUTH_TLS, 328*f05cddf9SRui Paulo EAP_VENDOR_TYPE_UNAUTH_TLS, "UNAUTH-TLS"); 329*f05cddf9SRui Paulo if (eap == NULL) 330*f05cddf9SRui Paulo return -1; 331*f05cddf9SRui Paulo 332*f05cddf9SRui Paulo eap->init = eap_unauth_tls_init; 333*f05cddf9SRui Paulo eap->deinit = eap_tls_deinit; 334*f05cddf9SRui Paulo eap->process = eap_tls_process; 335*f05cddf9SRui Paulo eap->isKeyAvailable = eap_tls_isKeyAvailable; 336*f05cddf9SRui Paulo eap->getKey = eap_tls_getKey; 337*f05cddf9SRui Paulo eap->get_status = eap_tls_get_status; 338*f05cddf9SRui Paulo eap->has_reauth_data = eap_tls_has_reauth_data; 339*f05cddf9SRui Paulo eap->deinit_for_reauth = eap_tls_deinit_for_reauth; 340*f05cddf9SRui Paulo eap->init_for_reauth = eap_tls_init_for_reauth; 341*f05cddf9SRui Paulo eap->get_emsk = eap_tls_get_emsk; 342*f05cddf9SRui Paulo 343*f05cddf9SRui Paulo ret = eap_peer_method_register(eap); 344*f05cddf9SRui Paulo if (ret) 345*f05cddf9SRui Paulo eap_peer_method_free(eap); 346*f05cddf9SRui Paulo return ret; 347*f05cddf9SRui Paulo } 348*f05cddf9SRui Paulo #endif /* EAP_UNAUTH_TLS */ 349