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 17static void eap_tls_reset(struct eap_sm *sm, void *priv); 18 19 20struct 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 28static 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 45static 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 54static 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 76static 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 97static void eap_tls_reset(struct eap_sm *sm, void *priv) 98{ 99 struct eap_tls_data *data = priv; 100 if (data == NULL) 101 return; 102 eap_server_tls_ssl_deinit(sm, &data->ssl); 103 os_free(data); 104} 105 106 107static struct wpabuf * eap_tls_build_start(struct eap_sm *sm, 108 struct eap_tls_data *data, u8 id) 109{ 110 struct wpabuf *req; 111 112 req = eap_tls_msg_alloc(data->eap_type, 1, EAP_CODE_REQUEST, id); 113 if (req == NULL) { 114 wpa_printf(MSG_ERROR, "EAP-TLS: Failed to allocate memory for " 115 "request"); 116 eap_tls_state(data, FAILURE); 117 return NULL; 118 } 119 120 wpabuf_put_u8(req, EAP_TLS_FLAGS_START); 121 122 eap_tls_state(data, CONTINUE); 123 124 return req; 125} 126 127 128static struct wpabuf * eap_tls_buildReq(struct eap_sm *sm, void *priv, u8 id) 129{ 130 struct eap_tls_data *data = priv; 131 struct wpabuf *res; 132 133 if (data->ssl.state == FRAG_ACK) { 134 return eap_server_tls_build_ack(id, data->eap_type, 0); 135 } 136 137 if (data->ssl.state == WAIT_FRAG_ACK) { 138 res = eap_server_tls_build_msg(&data->ssl, data->eap_type, 0, 139 id); 140 goto check_established; 141 } 142 143 switch (data->state) { 144 case START: 145 return eap_tls_build_start(sm, data, id); 146 case CONTINUE: 147 if (tls_connection_established(sm->ssl_ctx, data->ssl.conn)) 148 data->established = 1; 149 break; 150 default: 151 wpa_printf(MSG_DEBUG, "EAP-TLS: %s - unexpected state %d", 152 __func__, data->state); 153 return NULL; 154 } 155 156 res = eap_server_tls_build_msg(&data->ssl, data->eap_type, 0, id); 157 158check_established: 159 if (data->established && data->ssl.state != WAIT_FRAG_ACK) { 160 /* TLS handshake has been completed and there are no more 161 * fragments waiting to be sent out. */ 162 wpa_printf(MSG_DEBUG, "EAP-TLS: Done"); 163 eap_tls_state(data, SUCCESS); 164 } 165 166 return res; 167} 168 169 170static Boolean eap_tls_check(struct eap_sm *sm, void *priv, 171 struct wpabuf *respData) 172{ 173 struct eap_tls_data *data = priv; 174 const u8 *pos; 175 size_t len; 176 177 if (data->eap_type == EAP_UNAUTH_TLS_TYPE) 178 pos = eap_hdr_validate(EAP_VENDOR_UNAUTH_TLS, 179 EAP_VENDOR_TYPE_UNAUTH_TLS, respData, 180 &len); 181 else 182 pos = eap_hdr_validate(EAP_VENDOR_IETF, data->eap_type, 183 respData, &len); 184 if (pos == NULL || len < 1) { 185 wpa_printf(MSG_INFO, "EAP-TLS: Invalid frame"); 186 return TRUE; 187 } 188 189 return FALSE; 190} 191 192 193static void eap_tls_process_msg(struct eap_sm *sm, void *priv, 194 const struct wpabuf *respData) 195{ 196 struct eap_tls_data *data = priv; 197 if (data->state == SUCCESS && wpabuf_len(data->ssl.tls_in) == 0) { 198 wpa_printf(MSG_DEBUG, "EAP-TLS: Client acknowledged final TLS " 199 "handshake message"); 200 return; 201 } 202 if (eap_server_tls_phase1(sm, &data->ssl) < 0) 203 eap_tls_state(data, FAILURE); 204} 205 206 207static void eap_tls_process(struct eap_sm *sm, void *priv, 208 struct wpabuf *respData) 209{ 210 struct eap_tls_data *data = priv; 211 if (eap_server_tls_process(sm, &data->ssl, respData, data, 212 data->eap_type, NULL, eap_tls_process_msg) < 213 0) 214 eap_tls_state(data, FAILURE); 215} 216 217 218static Boolean eap_tls_isDone(struct eap_sm *sm, void *priv) 219{ 220 struct eap_tls_data *data = priv; 221 return data->state == SUCCESS || data->state == FAILURE; 222} 223 224 225static u8 * eap_tls_getKey(struct eap_sm *sm, void *priv, size_t *len) 226{ 227 struct eap_tls_data *data = priv; 228 u8 *eapKeyData; 229 230 if (data->state != SUCCESS) 231 return NULL; 232 233 eapKeyData = eap_server_tls_derive_key(sm, &data->ssl, 234 "client EAP encryption", 235 EAP_TLS_KEY_LEN); 236 if (eapKeyData) { 237 *len = EAP_TLS_KEY_LEN; 238 wpa_hexdump(MSG_DEBUG, "EAP-TLS: Derived key", 239 eapKeyData, EAP_TLS_KEY_LEN); 240 } else { 241 wpa_printf(MSG_DEBUG, "EAP-TLS: Failed to derive key"); 242 } 243 244 return eapKeyData; 245} 246 247 248static u8 * eap_tls_get_emsk(struct eap_sm *sm, void *priv, size_t *len) 249{ 250 struct eap_tls_data *data = priv; 251 u8 *eapKeyData, *emsk; 252 253 if (data->state != SUCCESS) 254 return NULL; 255 256 eapKeyData = eap_server_tls_derive_key(sm, &data->ssl, 257 "client EAP encryption", 258 EAP_TLS_KEY_LEN + EAP_EMSK_LEN); 259 if (eapKeyData) { 260 emsk = os_malloc(EAP_EMSK_LEN); 261 if (emsk) 262 os_memcpy(emsk, eapKeyData + EAP_TLS_KEY_LEN, 263 EAP_EMSK_LEN); 264 os_free(eapKeyData); 265 } else 266 emsk = NULL; 267 268 if (emsk) { 269 *len = EAP_EMSK_LEN; 270 wpa_hexdump(MSG_DEBUG, "EAP-TLS: Derived EMSK", 271 emsk, EAP_EMSK_LEN); 272 } else { 273 wpa_printf(MSG_DEBUG, "EAP-TLS: Failed to derive EMSK"); 274 } 275 276 return emsk; 277} 278 279 280static Boolean eap_tls_isSuccess(struct eap_sm *sm, void *priv) 281{ 282 struct eap_tls_data *data = priv; 283 return data->state == SUCCESS; 284} 285 286 287int eap_server_tls_register(void) 288{ 289 struct eap_method *eap; 290 int ret; 291 292 eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION, 293 EAP_VENDOR_IETF, EAP_TYPE_TLS, "TLS"); 294 if (eap == NULL) 295 return -1; 296 297 eap->init = eap_tls_init; 298 eap->reset = eap_tls_reset; 299 eap->buildReq = eap_tls_buildReq; 300 eap->check = eap_tls_check; 301 eap->process = eap_tls_process; 302 eap->isDone = eap_tls_isDone; 303 eap->getKey = eap_tls_getKey; 304 eap->isSuccess = eap_tls_isSuccess; 305 eap->get_emsk = eap_tls_get_emsk; 306 307 ret = eap_server_method_register(eap); 308 if (ret) 309 eap_server_method_free(eap); 310 return ret; 311} 312 313 314#ifdef EAP_SERVER_UNAUTH_TLS 315int eap_server_unauth_tls_register(void) 316{ 317 struct eap_method *eap; 318 int ret; 319 320 eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION, 321 EAP_VENDOR_UNAUTH_TLS, 322 EAP_VENDOR_TYPE_UNAUTH_TLS, 323 "UNAUTH-TLS"); 324 if (eap == NULL) 325 return -1; 326 327 eap->init = eap_unauth_tls_init; 328 eap->reset = eap_tls_reset; 329 eap->buildReq = eap_tls_buildReq; 330 eap->check = eap_tls_check; 331 eap->process = eap_tls_process; 332 eap->isDone = eap_tls_isDone; 333 eap->getKey = eap_tls_getKey; 334 eap->isSuccess = eap_tls_isSuccess; 335 eap->get_emsk = eap_tls_get_emsk; 336 337 ret = eap_server_method_register(eap); 338 if (ret) 339 eap_server_method_free(eap); 340 return ret; 341} 342#endif /* EAP_SERVER_UNAUTH_TLS */ 343