1 /* 2 * hostapd / EAP-TLS (RFC 2716) 3 * Copyright (c) 2004-2008, Jouni Malinen <j (at) 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 306 if (data->state != SUCCESS) 307 return NULL; 308 309 eapKeyData = eap_server_tls_derive_key(sm, &data->ssl, 310 "client EAP encryption", 311 EAP_TLS_KEY_LEN); 312 if (eapKeyData) { 313 *len = EAP_TLS_KEY_LEN; 314 wpa_hexdump(MSG_DEBUG, "EAP-TLS: Derived key", 315 eapKeyData, EAP_TLS_KEY_LEN); 316 } else { 317 wpa_printf(MSG_DEBUG, "EAP-TLS: Failed to derive key"); 318 } 319 320 return eapKeyData; 321 } 322 323 324 static u8 * eap_tls_get_emsk(struct eap_sm *sm, void *priv, size_t *len) 325 { 326 struct eap_tls_data *data = priv; 327 u8 *eapKeyData, *emsk; 328 329 if (data->state != SUCCESS) 330 return NULL; 331 332 eapKeyData = eap_server_tls_derive_key(sm, &data->ssl, 333 "client EAP encryption", 334 EAP_TLS_KEY_LEN + EAP_EMSK_LEN); 335 if (eapKeyData) { 336 emsk = os_malloc(EAP_EMSK_LEN); 337 if (emsk) 338 os_memcpy(emsk, eapKeyData + EAP_TLS_KEY_LEN, 339 EAP_EMSK_LEN); 340 bin_clear_free(eapKeyData, EAP_TLS_KEY_LEN + EAP_EMSK_LEN); 341 } else 342 emsk = NULL; 343 344 if (emsk) { 345 *len = EAP_EMSK_LEN; 346 wpa_hexdump(MSG_DEBUG, "EAP-TLS: Derived EMSK", 347 emsk, EAP_EMSK_LEN); 348 } else { 349 wpa_printf(MSG_DEBUG, "EAP-TLS: Failed to derive EMSK"); 350 } 351 352 return emsk; 353 } 354 355 356 static Boolean eap_tls_isSuccess(struct eap_sm *sm, void *priv) 357 { 358 struct eap_tls_data *data = priv; 359 return data->state == SUCCESS; 360 } 361 362 363 static u8 * eap_tls_get_session_id(struct eap_sm *sm, void *priv, size_t *len) 364 { 365 struct eap_tls_data *data = priv; 366 367 if (data->state != SUCCESS) 368 return NULL; 369 370 return eap_server_tls_derive_session_id(sm, &data->ssl, EAP_TYPE_TLS, 371 len); 372 } 373 374 375 int eap_server_tls_register(void) 376 { 377 struct eap_method *eap; 378 379 eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION, 380 EAP_VENDOR_IETF, EAP_TYPE_TLS, "TLS"); 381 if (eap == NULL) 382 return -1; 383 384 eap->init = eap_tls_init; 385 eap->reset = eap_tls_reset; 386 eap->buildReq = eap_tls_buildReq; 387 eap->check = eap_tls_check; 388 eap->process = eap_tls_process; 389 eap->isDone = eap_tls_isDone; 390 eap->getKey = eap_tls_getKey; 391 eap->isSuccess = eap_tls_isSuccess; 392 eap->get_emsk = eap_tls_get_emsk; 393 eap->getSessionId = eap_tls_get_session_id; 394 395 return eap_server_method_register(eap); 396 } 397 398 399 #ifdef EAP_SERVER_UNAUTH_TLS 400 int eap_server_unauth_tls_register(void) 401 { 402 struct eap_method *eap; 403 404 eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION, 405 EAP_VENDOR_UNAUTH_TLS, 406 EAP_VENDOR_TYPE_UNAUTH_TLS, 407 "UNAUTH-TLS"); 408 if (eap == NULL) 409 return -1; 410 411 eap->init = eap_unauth_tls_init; 412 eap->reset = eap_tls_reset; 413 eap->buildReq = eap_tls_buildReq; 414 eap->check = eap_tls_check; 415 eap->process = eap_tls_process; 416 eap->isDone = eap_tls_isDone; 417 eap->getKey = eap_tls_getKey; 418 eap->isSuccess = eap_tls_isSuccess; 419 eap->get_emsk = eap_tls_get_emsk; 420 421 return eap_server_method_register(eap); 422 } 423 #endif /* EAP_SERVER_UNAUTH_TLS */ 424 425 426 #ifdef CONFIG_HS20 427 int eap_server_wfa_unauth_tls_register(void) 428 { 429 struct eap_method *eap; 430 431 eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION, 432 EAP_VENDOR_WFA_NEW, 433 EAP_VENDOR_WFA_UNAUTH_TLS, 434 "WFA-UNAUTH-TLS"); 435 if (eap == NULL) 436 return -1; 437 438 eap->init = eap_wfa_unauth_tls_init; 439 eap->reset = eap_tls_reset; 440 eap->buildReq = eap_tls_buildReq; 441 eap->check = eap_tls_check; 442 eap->process = eap_tls_process; 443 eap->isDone = eap_tls_isDone; 444 eap->getKey = eap_tls_getKey; 445 eap->isSuccess = eap_tls_isSuccess; 446 eap->get_emsk = eap_tls_get_emsk; 447 448 return eap_server_method_register(eap); 449 } 450 #endif /* CONFIG_HS20 */ 451