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