1 /* 2 * hostapd / EAP-TLS (RFC 2716) 3 * Copyright (c) 2004-2008, 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 "eap_i.h" 13 #include "eap_tls_common.h" 14 #include "crypto/tls.h" 15 16 17 static void eap_tls_reset(struct eap_sm *sm, void *priv); 18 19 20 struct eap_tls_data { 21 struct eap_ssl_data ssl; 22 enum { START, CONTINUE, SUCCESS, FAILURE } state; 23 int established; 24 u8 eap_type; 25 }; 26 27 28 static const char * eap_tls_state_txt(int state) 29 { 30 switch (state) { 31 case START: 32 return "START"; 33 case CONTINUE: 34 return "CONTINUE"; 35 case SUCCESS: 36 return "SUCCESS"; 37 case FAILURE: 38 return "FAILURE"; 39 default: 40 return "Unknown?!"; 41 } 42 } 43 44 45 static void eap_tls_state(struct eap_tls_data *data, int state) 46 { 47 wpa_printf(MSG_DEBUG, "EAP-TLS: %s -> %s", 48 eap_tls_state_txt(data->state), 49 eap_tls_state_txt(state)); 50 data->state = state; 51 if (state == FAILURE) 52 tls_connection_remove_session(data->ssl.conn); 53 } 54 55 56 static void eap_tls_valid_session(struct eap_sm *sm, struct eap_tls_data *data) 57 { 58 struct wpabuf *buf; 59 60 if (!sm->tls_session_lifetime) 61 return; 62 63 buf = wpabuf_alloc(1); 64 if (!buf) 65 return; 66 wpabuf_put_u8(buf, data->eap_type); 67 tls_connection_set_success_data(data->ssl.conn, buf); 68 } 69 70 71 static void * eap_tls_init(struct eap_sm *sm) 72 { 73 struct eap_tls_data *data; 74 75 data = os_zalloc(sizeof(*data)); 76 if (data == NULL) 77 return NULL; 78 data->state = START; 79 80 if (eap_server_tls_ssl_init(sm, &data->ssl, 1, EAP_TYPE_TLS)) { 81 wpa_printf(MSG_INFO, "EAP-TLS: Failed to initialize SSL."); 82 eap_tls_reset(sm, data); 83 return NULL; 84 } 85 86 data->eap_type = EAP_TYPE_TLS; 87 88 return data; 89 } 90 91 92 #ifdef EAP_SERVER_UNAUTH_TLS 93 static void * eap_unauth_tls_init(struct eap_sm *sm) 94 { 95 struct eap_tls_data *data; 96 97 data = os_zalloc(sizeof(*data)); 98 if (data == NULL) 99 return NULL; 100 data->state = START; 101 102 if (eap_server_tls_ssl_init(sm, &data->ssl, 0, EAP_UNAUTH_TLS_TYPE)) { 103 wpa_printf(MSG_INFO, "EAP-TLS: Failed to initialize SSL."); 104 eap_tls_reset(sm, data); 105 return NULL; 106 } 107 108 data->eap_type = EAP_UNAUTH_TLS_TYPE; 109 return data; 110 } 111 #endif /* EAP_SERVER_UNAUTH_TLS */ 112 113 114 #ifdef CONFIG_HS20 115 static void * eap_wfa_unauth_tls_init(struct eap_sm *sm) 116 { 117 struct eap_tls_data *data; 118 119 data = os_zalloc(sizeof(*data)); 120 if (data == NULL) 121 return NULL; 122 data->state = START; 123 124 if (eap_server_tls_ssl_init(sm, &data->ssl, 0, 125 EAP_WFA_UNAUTH_TLS_TYPE)) { 126 wpa_printf(MSG_INFO, "EAP-TLS: Failed to initialize SSL."); 127 eap_tls_reset(sm, data); 128 return NULL; 129 } 130 131 data->eap_type = EAP_WFA_UNAUTH_TLS_TYPE; 132 return data; 133 } 134 #endif /* CONFIG_HS20 */ 135 136 137 static void eap_tls_reset(struct eap_sm *sm, void *priv) 138 { 139 struct eap_tls_data *data = priv; 140 if (data == NULL) 141 return; 142 eap_server_tls_ssl_deinit(sm, &data->ssl); 143 os_free(data); 144 } 145 146 147 static struct wpabuf * eap_tls_build_start(struct eap_sm *sm, 148 struct eap_tls_data *data, u8 id) 149 { 150 struct wpabuf *req; 151 152 req = eap_tls_msg_alloc(data->eap_type, 1, EAP_CODE_REQUEST, id); 153 if (req == NULL) { 154 wpa_printf(MSG_ERROR, "EAP-TLS: Failed to allocate memory for " 155 "request"); 156 eap_tls_state(data, FAILURE); 157 return NULL; 158 } 159 160 wpabuf_put_u8(req, EAP_TLS_FLAGS_START); 161 162 eap_tls_state(data, CONTINUE); 163 164 return req; 165 } 166 167 168 static struct wpabuf * eap_tls_buildReq(struct eap_sm *sm, void *priv, u8 id) 169 { 170 struct eap_tls_data *data = priv; 171 struct wpabuf *res; 172 173 if (data->ssl.state == FRAG_ACK) { 174 return eap_server_tls_build_ack(id, data->eap_type, 0); 175 } 176 177 if (data->ssl.state == WAIT_FRAG_ACK) { 178 res = eap_server_tls_build_msg(&data->ssl, data->eap_type, 0, 179 id); 180 goto check_established; 181 } 182 183 switch (data->state) { 184 case START: 185 return eap_tls_build_start(sm, data, id); 186 case CONTINUE: 187 if (tls_connection_established(sm->ssl_ctx, data->ssl.conn)) 188 data->established = 1; 189 break; 190 default: 191 wpa_printf(MSG_DEBUG, "EAP-TLS: %s - unexpected state %d", 192 __func__, data->state); 193 return NULL; 194 } 195 196 res = eap_server_tls_build_msg(&data->ssl, data->eap_type, 0, id); 197 198 check_established: 199 if (data->established && data->ssl.state != WAIT_FRAG_ACK) { 200 /* TLS handshake has been completed and there are no more 201 * fragments waiting to be sent out. */ 202 wpa_printf(MSG_DEBUG, "EAP-TLS: Done"); 203 eap_tls_state(data, SUCCESS); 204 eap_tls_valid_session(sm, data); 205 } 206 207 return res; 208 } 209 210 211 static Boolean eap_tls_check(struct eap_sm *sm, void *priv, 212 struct wpabuf *respData) 213 { 214 struct eap_tls_data *data = priv; 215 const u8 *pos; 216 size_t len; 217 218 if (data->eap_type == EAP_UNAUTH_TLS_TYPE) 219 pos = eap_hdr_validate(EAP_VENDOR_UNAUTH_TLS, 220 EAP_VENDOR_TYPE_UNAUTH_TLS, respData, 221 &len); 222 else if (data->eap_type == EAP_WFA_UNAUTH_TLS_TYPE) 223 pos = eap_hdr_validate(EAP_VENDOR_WFA_NEW, 224 EAP_VENDOR_WFA_UNAUTH_TLS, respData, 225 &len); 226 else 227 pos = eap_hdr_validate(EAP_VENDOR_IETF, data->eap_type, 228 respData, &len); 229 if (pos == NULL || len < 1) { 230 wpa_printf(MSG_INFO, "EAP-TLS: Invalid frame"); 231 return TRUE; 232 } 233 234 return FALSE; 235 } 236 237 238 static void eap_tls_process_msg(struct eap_sm *sm, void *priv, 239 const struct wpabuf *respData) 240 { 241 struct eap_tls_data *data = priv; 242 if (data->state == SUCCESS && wpabuf_len(data->ssl.tls_in) == 0) { 243 wpa_printf(MSG_DEBUG, "EAP-TLS: Client acknowledged final TLS " 244 "handshake message"); 245 return; 246 } 247 if (eap_server_tls_phase1(sm, &data->ssl) < 0) 248 eap_tls_state(data, FAILURE); 249 } 250 251 252 static void eap_tls_process(struct eap_sm *sm, void *priv, 253 struct wpabuf *respData) 254 { 255 struct eap_tls_data *data = priv; 256 const struct wpabuf *buf; 257 const u8 *pos; 258 259 if (eap_server_tls_process(sm, &data->ssl, respData, data, 260 data->eap_type, NULL, eap_tls_process_msg) < 261 0) { 262 eap_tls_state(data, FAILURE); 263 return; 264 } 265 266 if (!tls_connection_established(sm->ssl_ctx, data->ssl.conn) || 267 !tls_connection_resumed(sm->ssl_ctx, data->ssl.conn)) 268 return; 269 270 buf = tls_connection_get_success_data(data->ssl.conn); 271 if (!buf || wpabuf_len(buf) < 1) { 272 wpa_printf(MSG_DEBUG, 273 "EAP-TLS: No success data in resumed session - reject attempt"); 274 eap_tls_state(data, FAILURE); 275 return; 276 } 277 278 pos = wpabuf_head(buf); 279 if (*pos != data->eap_type) { 280 wpa_printf(MSG_DEBUG, 281 "EAP-TLS: Resumed session for another EAP type (%u) - reject attempt", 282 *pos); 283 eap_tls_state(data, FAILURE); 284 return; 285 } 286 287 wpa_printf(MSG_DEBUG, 288 "EAP-TLS: Resuming previous session"); 289 eap_tls_state(data, SUCCESS); 290 tls_connection_set_success_data_resumed(data->ssl.conn); 291 } 292 293 294 static Boolean eap_tls_isDone(struct eap_sm *sm, void *priv) 295 { 296 struct eap_tls_data *data = priv; 297 return data->state == SUCCESS || data->state == FAILURE; 298 } 299 300 301 static u8 * eap_tls_getKey(struct eap_sm *sm, void *priv, size_t *len) 302 { 303 struct eap_tls_data *data = priv; 304 u8 *eapKeyData; 305 const char *label; 306 307 if (data->state != SUCCESS) 308 return NULL; 309 310 if (data->ssl.tls_v13) 311 label = "EXPORTER_EAP_TLS_Key_Material"; 312 else 313 label = "client EAP encryption"; 314 eapKeyData = eap_server_tls_derive_key(sm, &data->ssl, label, 315 EAP_TLS_KEY_LEN + EAP_EMSK_LEN); 316 if (eapKeyData) { 317 *len = EAP_TLS_KEY_LEN; 318 wpa_hexdump(MSG_DEBUG, "EAP-TLS: Derived key", 319 eapKeyData, EAP_TLS_KEY_LEN); 320 os_memset(eapKeyData + EAP_TLS_KEY_LEN, 0, EAP_EMSK_LEN); 321 } else { 322 wpa_printf(MSG_DEBUG, "EAP-TLS: Failed to derive key"); 323 } 324 325 return eapKeyData; 326 } 327 328 329 static u8 * eap_tls_get_emsk(struct eap_sm *sm, void *priv, size_t *len) 330 { 331 struct eap_tls_data *data = priv; 332 u8 *eapKeyData, *emsk; 333 const char *label; 334 335 if (data->state != SUCCESS) 336 return NULL; 337 338 if (data->ssl.tls_v13) 339 label = "EXPORTER_EAP_TLS_Key_Material"; 340 else 341 label = "client EAP encryption"; 342 eapKeyData = eap_server_tls_derive_key(sm, &data->ssl, label, 343 EAP_TLS_KEY_LEN + EAP_EMSK_LEN); 344 if (eapKeyData) { 345 emsk = os_malloc(EAP_EMSK_LEN); 346 if (emsk) 347 os_memcpy(emsk, eapKeyData + EAP_TLS_KEY_LEN, 348 EAP_EMSK_LEN); 349 bin_clear_free(eapKeyData, EAP_TLS_KEY_LEN + EAP_EMSK_LEN); 350 } else 351 emsk = NULL; 352 353 if (emsk) { 354 *len = EAP_EMSK_LEN; 355 wpa_hexdump(MSG_DEBUG, "EAP-TLS: Derived EMSK", 356 emsk, EAP_EMSK_LEN); 357 } else { 358 wpa_printf(MSG_DEBUG, "EAP-TLS: Failed to derive EMSK"); 359 } 360 361 return emsk; 362 } 363 364 365 static Boolean eap_tls_isSuccess(struct eap_sm *sm, void *priv) 366 { 367 struct eap_tls_data *data = priv; 368 return data->state == SUCCESS; 369 } 370 371 372 static u8 * eap_tls_get_session_id(struct eap_sm *sm, void *priv, size_t *len) 373 { 374 struct eap_tls_data *data = priv; 375 376 if (data->state != SUCCESS) 377 return NULL; 378 379 return eap_server_tls_derive_session_id(sm, &data->ssl, EAP_TYPE_TLS, 380 len); 381 } 382 383 384 int eap_server_tls_register(void) 385 { 386 struct eap_method *eap; 387 388 eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION, 389 EAP_VENDOR_IETF, EAP_TYPE_TLS, "TLS"); 390 if (eap == NULL) 391 return -1; 392 393 eap->init = eap_tls_init; 394 eap->reset = eap_tls_reset; 395 eap->buildReq = eap_tls_buildReq; 396 eap->check = eap_tls_check; 397 eap->process = eap_tls_process; 398 eap->isDone = eap_tls_isDone; 399 eap->getKey = eap_tls_getKey; 400 eap->isSuccess = eap_tls_isSuccess; 401 eap->get_emsk = eap_tls_get_emsk; 402 eap->getSessionId = eap_tls_get_session_id; 403 404 return eap_server_method_register(eap); 405 } 406 407 408 #ifdef EAP_SERVER_UNAUTH_TLS 409 int eap_server_unauth_tls_register(void) 410 { 411 struct eap_method *eap; 412 413 eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION, 414 EAP_VENDOR_UNAUTH_TLS, 415 EAP_VENDOR_TYPE_UNAUTH_TLS, 416 "UNAUTH-TLS"); 417 if (eap == NULL) 418 return -1; 419 420 eap->init = eap_unauth_tls_init; 421 eap->reset = eap_tls_reset; 422 eap->buildReq = eap_tls_buildReq; 423 eap->check = eap_tls_check; 424 eap->process = eap_tls_process; 425 eap->isDone = eap_tls_isDone; 426 eap->getKey = eap_tls_getKey; 427 eap->isSuccess = eap_tls_isSuccess; 428 eap->get_emsk = eap_tls_get_emsk; 429 430 return eap_server_method_register(eap); 431 } 432 #endif /* EAP_SERVER_UNAUTH_TLS */ 433 434 435 #ifdef CONFIG_HS20 436 int eap_server_wfa_unauth_tls_register(void) 437 { 438 struct eap_method *eap; 439 440 eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION, 441 EAP_VENDOR_WFA_NEW, 442 EAP_VENDOR_WFA_UNAUTH_TLS, 443 "WFA-UNAUTH-TLS"); 444 if (eap == NULL) 445 return -1; 446 447 eap->init = eap_wfa_unauth_tls_init; 448 eap->reset = eap_tls_reset; 449 eap->buildReq = eap_tls_buildReq; 450 eap->check = eap_tls_check; 451 eap->process = eap_tls_process; 452 eap->isDone = eap_tls_isDone; 453 eap->getKey = eap_tls_getKey; 454 eap->isSuccess = eap_tls_isSuccess; 455 eap->get_emsk = eap_tls_get_emsk; 456 457 return eap_server_method_register(eap); 458 } 459 #endif /* CONFIG_HS20 */ 460