1/* 2 * EAP peer method: EAP-TLS (RFC 2716) 3 * Copyright (c) 2004-2008, 2012-2015, Jouni Malinen <j@w1.fi> 4 * 5 * This software may be distributed under the terms of the BSD license. 6 * See README for more details. 7 */ 8 9#include "includes.h" 10 11#include "common.h" 12#include "crypto/tls.h" 13#include "eap_i.h" 14#include "eap_tls_common.h" 15#include "eap_config.h" 16 17 18static void eap_tls_deinit(struct eap_sm *sm, void *priv); 19 20 21struct eap_tls_data { 22 struct eap_ssl_data ssl; 23 u8 *key_data; 24 u8 *session_id; 25 size_t id_len; 26 void *ssl_ctx; 27 u8 eap_type; 28 struct wpabuf *pending_resp; 29}; 30 31 32static void * eap_tls_init(struct eap_sm *sm) 33{ 34 struct eap_tls_data *data; 35 struct eap_peer_config *config = eap_get_config(sm); 36 if (config == NULL || 37 ((sm->init_phase2 ? config->private_key2 : config->private_key) 38 == NULL && 39 (sm->init_phase2 ? config->engine2 : config->engine) == 0)) { 40 wpa_printf(MSG_INFO, "EAP-TLS: Private key not configured"); 41 return NULL; 42 } 43 44 data = os_zalloc(sizeof(*data)); 45 if (data == NULL) 46 return NULL; 47 48 data->ssl_ctx = sm->init_phase2 && sm->ssl_ctx2 ? sm->ssl_ctx2 : 49 sm->ssl_ctx; 50 51 if (eap_peer_tls_ssl_init(sm, &data->ssl, config, EAP_TYPE_TLS)) { 52 wpa_printf(MSG_INFO, "EAP-TLS: Failed to initialize SSL."); 53 eap_tls_deinit(sm, data); 54 if (config->engine) { 55 wpa_printf(MSG_DEBUG, "EAP-TLS: Requesting Smartcard " 56 "PIN"); 57 eap_sm_request_pin(sm); 58 sm->ignore = TRUE; 59 } else if (config->private_key && !config->private_key_passwd) 60 { 61 wpa_printf(MSG_DEBUG, "EAP-TLS: Requesting private " 62 "key passphrase"); 63 eap_sm_request_passphrase(sm); 64 sm->ignore = TRUE; 65 } 66 return NULL; 67 } 68 69 data->eap_type = EAP_TYPE_TLS; 70 71 return data; 72} 73 74 75#ifdef EAP_UNAUTH_TLS 76static void * eap_unauth_tls_init(struct eap_sm *sm) 77{ 78 struct eap_tls_data *data; 79 struct eap_peer_config *config = eap_get_config(sm); 80 81 data = os_zalloc(sizeof(*data)); 82 if (data == NULL) 83 return NULL; 84 85 data->ssl_ctx = sm->init_phase2 && sm->ssl_ctx2 ? sm->ssl_ctx2 : 86 sm->ssl_ctx; 87 88 if (eap_peer_tls_ssl_init(sm, &data->ssl, config, 89 EAP_UNAUTH_TLS_TYPE)) { 90 wpa_printf(MSG_INFO, "EAP-TLS: Failed to initialize SSL."); 91 eap_tls_deinit(sm, data); 92 return NULL; 93 } 94 95 data->eap_type = EAP_UNAUTH_TLS_TYPE; 96 97 return data; 98} 99#endif /* EAP_UNAUTH_TLS */ 100 101 102#ifdef CONFIG_HS20 103static void * eap_wfa_unauth_tls_init(struct eap_sm *sm) 104{ 105 struct eap_tls_data *data; 106 struct eap_peer_config *config = eap_get_config(sm); 107 108 data = os_zalloc(sizeof(*data)); 109 if (data == NULL) 110 return NULL; 111 112 data->ssl_ctx = sm->init_phase2 && sm->ssl_ctx2 ? sm->ssl_ctx2 : 113 sm->ssl_ctx; 114 115 if (eap_peer_tls_ssl_init(sm, &data->ssl, config, 116 EAP_WFA_UNAUTH_TLS_TYPE)) { 117 wpa_printf(MSG_INFO, "EAP-TLS: Failed to initialize SSL."); 118 eap_tls_deinit(sm, data); 119 return NULL; 120 } 121 122 data->eap_type = EAP_WFA_UNAUTH_TLS_TYPE; 123 124 return data; 125} 126#endif /* CONFIG_HS20 */ 127 128 129static void eap_tls_free_key(struct eap_tls_data *data) 130{ 131 if (data->key_data) { 132 bin_clear_free(data->key_data, EAP_TLS_KEY_LEN + EAP_EMSK_LEN); 133 data->key_data = NULL; 134 } 135} 136 137 138static void eap_tls_deinit(struct eap_sm *sm, void *priv) 139{ 140 struct eap_tls_data *data = priv; 141 if (data == NULL) 142 return; 143 eap_peer_tls_ssl_deinit(sm, &data->ssl); 144 eap_tls_free_key(data); 145 os_free(data->session_id); 146 wpabuf_free(data->pending_resp); 147 os_free(data); 148} 149 150 151static struct wpabuf * eap_tls_failure(struct eap_sm *sm, 152 struct eap_tls_data *data, 153 struct eap_method_ret *ret, int res, 154 struct wpabuf *resp, u8 id) 155{ 156 wpa_printf(MSG_DEBUG, "EAP-TLS: TLS processing failed"); 157 158 ret->methodState = METHOD_DONE; 159 ret->decision = DECISION_FAIL; 160 161 if (resp) { 162 /* 163 * This is likely an alert message, so send it instead of just 164 * ACKing the error. 165 */ 166 return resp; 167 } 168 169 return eap_peer_tls_build_ack(id, data->eap_type, 0); 170} 171 172 173static void eap_tls_success(struct eap_sm *sm, struct eap_tls_data *data, 174 struct eap_method_ret *ret) 175{ 176 wpa_printf(MSG_DEBUG, "EAP-TLS: Done"); 177 178 ret->methodState = METHOD_DONE; 179 ret->decision = DECISION_UNCOND_SUCC; 180 181 eap_tls_free_key(data); 182 data->key_data = eap_peer_tls_derive_key(sm, &data->ssl, 183 "client EAP encryption", 184 EAP_TLS_KEY_LEN + 185 EAP_EMSK_LEN); 186 if (data->key_data) { 187 wpa_hexdump_key(MSG_DEBUG, "EAP-TLS: Derived key", 188 data->key_data, EAP_TLS_KEY_LEN); 189 wpa_hexdump_key(MSG_DEBUG, "EAP-TLS: Derived EMSK", 190 data->key_data + EAP_TLS_KEY_LEN, 191 EAP_EMSK_LEN); 192 } else { 193 wpa_printf(MSG_INFO, "EAP-TLS: Failed to derive key"); 194 } 195 196 os_free(data->session_id); 197 data->session_id = eap_peer_tls_derive_session_id(sm, &data->ssl, 198 EAP_TYPE_TLS, 199 &data->id_len); 200 if (data->session_id) { 201 wpa_hexdump(MSG_DEBUG, "EAP-TLS: Derived Session-Id", 202 data->session_id, data->id_len); 203 } else { 204 wpa_printf(MSG_ERROR, "EAP-TLS: Failed to derive Session-Id"); 205 } 206} 207 208 209static struct wpabuf * eap_tls_process(struct eap_sm *sm, void *priv, 210 struct eap_method_ret *ret, 211 const struct wpabuf *reqData) 212{ 213 size_t left; 214 int res; 215 struct wpabuf *resp; 216 u8 flags, id; 217 const u8 *pos; 218 struct eap_tls_data *data = priv; 219 struct wpabuf msg; 220 221 if (sm->waiting_ext_cert_check && data->pending_resp) { 222 struct eap_peer_config *config = eap_get_config(sm); 223 224 if (config->pending_ext_cert_check == EXT_CERT_CHECK_GOOD) { 225 wpa_printf(MSG_DEBUG, 226 "EAP-TLS: External certificate check succeeded - continue handshake"); 227 resp = data->pending_resp; 228 data->pending_resp = NULL; 229 sm->waiting_ext_cert_check = 0; 230 return resp; 231 } 232 233 if (config->pending_ext_cert_check == EXT_CERT_CHECK_BAD) { 234 wpa_printf(MSG_DEBUG, 235 "EAP-TLS: External certificate check failed - force authentication failure"); 236 ret->methodState = METHOD_DONE; 237 ret->decision = DECISION_FAIL; 238 sm->waiting_ext_cert_check = 0; 239 return NULL; 240 } 241 242 wpa_printf(MSG_DEBUG, 243 "EAP-TLS: Continuing to wait external server certificate validation"); 244 return NULL; 245 } 246 247 pos = eap_peer_tls_process_init(sm, &data->ssl, data->eap_type, ret, 248 reqData, &left, &flags); 249 if (pos == NULL) 250 return NULL; 251 id = eap_get_id(reqData); 252 253 if (flags & EAP_TLS_FLAGS_START) { 254 wpa_printf(MSG_DEBUG, "EAP-TLS: Start"); 255 left = 0; /* make sure that this frame is empty, even though it 256 * should always be, anyway */ 257 } 258 259 resp = NULL; 260 wpabuf_set(&msg, pos, left); 261 res = eap_peer_tls_process_helper(sm, &data->ssl, data->eap_type, 0, 262 id, &msg, &resp); 263 264 if (res < 0) { 265 return eap_tls_failure(sm, data, ret, res, resp, id); 266 } 267 268 if (sm->waiting_ext_cert_check) { 269 wpa_printf(MSG_DEBUG, 270 "EAP-TLS: Waiting external server certificate validation"); 271 wpabuf_free(data->pending_resp); 272 data->pending_resp = resp; 273 return NULL; 274 } 275 276 if (tls_connection_established(data->ssl_ctx, data->ssl.conn)) 277 eap_tls_success(sm, data, ret); 278 279 if (res == 1) { 280 wpabuf_free(resp); 281 return eap_peer_tls_build_ack(id, data->eap_type, 0); 282 } 283 284 return resp; 285} 286 287 288static Boolean eap_tls_has_reauth_data(struct eap_sm *sm, void *priv) 289{ 290 struct eap_tls_data *data = priv; 291 return tls_connection_established(data->ssl_ctx, data->ssl.conn); 292} 293 294 295static void eap_tls_deinit_for_reauth(struct eap_sm *sm, void *priv) 296{ 297 struct eap_tls_data *data = priv; 298 299 wpabuf_free(data->pending_resp); 300 data->pending_resp = NULL; 301} 302 303 304static void * eap_tls_init_for_reauth(struct eap_sm *sm, void *priv) 305{ 306 struct eap_tls_data *data = priv; 307 eap_tls_free_key(data); 308 os_free(data->session_id); 309 data->session_id = NULL; 310 if (eap_peer_tls_reauth_init(sm, &data->ssl)) { 311 os_free(data); 312 return NULL; 313 } 314 return priv; 315} 316 317 318static int eap_tls_get_status(struct eap_sm *sm, void *priv, char *buf, 319 size_t buflen, int verbose) 320{ 321 struct eap_tls_data *data = priv; 322 return eap_peer_tls_status(sm, &data->ssl, buf, buflen, verbose); 323} 324 325 326static Boolean eap_tls_isKeyAvailable(struct eap_sm *sm, void *priv) 327{ 328 struct eap_tls_data *data = priv; 329 return data->key_data != NULL; 330} 331 332 333static u8 * eap_tls_getKey(struct eap_sm *sm, void *priv, size_t *len) 334{ 335 struct eap_tls_data *data = priv; 336 u8 *key; 337 338 if (data->key_data == NULL) 339 return NULL; 340 341 key = os_malloc(EAP_TLS_KEY_LEN); 342 if (key == NULL) 343 return NULL; 344 345 *len = EAP_TLS_KEY_LEN; 346 os_memcpy(key, data->key_data, EAP_TLS_KEY_LEN); 347 348 return key; 349} 350 351 352static u8 * eap_tls_get_emsk(struct eap_sm *sm, void *priv, size_t *len) 353{ 354 struct eap_tls_data *data = priv; 355 u8 *key; 356 357 if (data->key_data == NULL) 358 return NULL; 359 360 key = os_malloc(EAP_EMSK_LEN); 361 if (key == NULL) 362 return NULL; 363 364 *len = EAP_EMSK_LEN; 365 os_memcpy(key, data->key_data + EAP_TLS_KEY_LEN, EAP_EMSK_LEN); 366 367 return key; 368} 369 370 371static u8 * eap_tls_get_session_id(struct eap_sm *sm, void *priv, size_t *len) 372{ 373 struct eap_tls_data *data = priv; 374 u8 *id; 375 376 if (data->session_id == NULL) 377 return NULL; 378 379 id = os_malloc(data->id_len); 380 if (id == NULL) 381 return NULL; 382 383 *len = data->id_len; 384 os_memcpy(id, data->session_id, data->id_len); 385 386 return id; 387} 388 389 390int eap_peer_tls_register(void) 391{ 392 struct eap_method *eap; 393 394 eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION, 395 EAP_VENDOR_IETF, EAP_TYPE_TLS, "TLS"); 396 if (eap == NULL) 397 return -1; 398 399 eap->init = eap_tls_init; 400 eap->deinit = eap_tls_deinit; 401 eap->process = eap_tls_process; 402 eap->isKeyAvailable = eap_tls_isKeyAvailable; 403 eap->getKey = eap_tls_getKey; 404 eap->getSessionId = eap_tls_get_session_id; 405 eap->get_status = eap_tls_get_status; 406 eap->has_reauth_data = eap_tls_has_reauth_data; 407 eap->deinit_for_reauth = eap_tls_deinit_for_reauth; 408 eap->init_for_reauth = eap_tls_init_for_reauth; 409 eap->get_emsk = eap_tls_get_emsk; 410 411 return eap_peer_method_register(eap); 412} 413 414 415#ifdef EAP_UNAUTH_TLS 416int eap_peer_unauth_tls_register(void) 417{ 418 struct eap_method *eap; 419 420 eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION, 421 EAP_VENDOR_UNAUTH_TLS, 422 EAP_VENDOR_TYPE_UNAUTH_TLS, "UNAUTH-TLS"); 423 if (eap == NULL) 424 return -1; 425 426 eap->init = eap_unauth_tls_init; 427 eap->deinit = eap_tls_deinit; 428 eap->process = eap_tls_process; 429 eap->isKeyAvailable = eap_tls_isKeyAvailable; 430 eap->getKey = eap_tls_getKey; 431 eap->get_status = eap_tls_get_status; 432 eap->has_reauth_data = eap_tls_has_reauth_data; 433 eap->deinit_for_reauth = eap_tls_deinit_for_reauth; 434 eap->init_for_reauth = eap_tls_init_for_reauth; 435 eap->get_emsk = eap_tls_get_emsk; 436 437 return eap_peer_method_register(eap); 438} 439#endif /* EAP_UNAUTH_TLS */ 440 441 442#ifdef CONFIG_HS20 443int eap_peer_wfa_unauth_tls_register(void) 444{ 445 struct eap_method *eap; 446 447 eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION, 448 EAP_VENDOR_WFA_NEW, 449 EAP_VENDOR_WFA_UNAUTH_TLS, 450 "WFA-UNAUTH-TLS"); 451 if (eap == NULL) 452 return -1; 453 454 eap->init = eap_wfa_unauth_tls_init; 455 eap->deinit = eap_tls_deinit; 456 eap->process = eap_tls_process; 457 eap->isKeyAvailable = eap_tls_isKeyAvailable; 458 eap->getKey = eap_tls_getKey; 459 eap->get_status = eap_tls_get_status; 460 eap->has_reauth_data = eap_tls_has_reauth_data; 461 eap->deinit_for_reauth = eap_tls_deinit_for_reauth; 462 eap->init_for_reauth = eap_tls_init_for_reauth; 463 eap->get_emsk = eap_tls_get_emsk; 464 465 return eap_peer_method_register(eap); 466} 467#endif /* CONFIG_HS20 */ 468