Home | History | Annotate | Download | only in eap_server
      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