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