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 }
     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 		os_free(eapKeyData);
    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 int eap_server_tls_register(void)
    314 {
    315 	struct eap_method *eap;
    316 	int ret;
    317 
    318 	eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
    319 				      EAP_VENDOR_IETF, EAP_TYPE_TLS, "TLS");
    320 	if (eap == NULL)
    321 		return -1;
    322 
    323 	eap->init = eap_tls_init;
    324 	eap->reset = eap_tls_reset;
    325 	eap->buildReq = eap_tls_buildReq;
    326 	eap->check = eap_tls_check;
    327 	eap->process = eap_tls_process;
    328 	eap->isDone = eap_tls_isDone;
    329 	eap->getKey = eap_tls_getKey;
    330 	eap->isSuccess = eap_tls_isSuccess;
    331 	eap->get_emsk = eap_tls_get_emsk;
    332 
    333 	ret = eap_server_method_register(eap);
    334 	if (ret)
    335 		eap_server_method_free(eap);
    336 	return ret;
    337 }
    338 
    339 
    340 #ifdef EAP_SERVER_UNAUTH_TLS
    341 int eap_server_unauth_tls_register(void)
    342 {
    343 	struct eap_method *eap;
    344 	int ret;
    345 
    346 	eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
    347 				      EAP_VENDOR_UNAUTH_TLS,
    348 				      EAP_VENDOR_TYPE_UNAUTH_TLS,
    349 				      "UNAUTH-TLS");
    350 	if (eap == NULL)
    351 		return -1;
    352 
    353 	eap->init = eap_unauth_tls_init;
    354 	eap->reset = eap_tls_reset;
    355 	eap->buildReq = eap_tls_buildReq;
    356 	eap->check = eap_tls_check;
    357 	eap->process = eap_tls_process;
    358 	eap->isDone = eap_tls_isDone;
    359 	eap->getKey = eap_tls_getKey;
    360 	eap->isSuccess = eap_tls_isSuccess;
    361 	eap->get_emsk = eap_tls_get_emsk;
    362 
    363 	ret = eap_server_method_register(eap);
    364 	if (ret)
    365 		eap_server_method_free(eap);
    366 	return ret;
    367 }
    368 #endif /* EAP_SERVER_UNAUTH_TLS */
    369 
    370 
    371 #ifdef CONFIG_HS20
    372 int eap_server_wfa_unauth_tls_register(void)
    373 {
    374 	struct eap_method *eap;
    375 	int ret;
    376 
    377 	eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
    378 				      EAP_VENDOR_WFA_NEW,
    379 				      EAP_VENDOR_WFA_UNAUTH_TLS,
    380 				      "WFA-UNAUTH-TLS");
    381 	if (eap == NULL)
    382 		return -1;
    383 
    384 	eap->init = eap_wfa_unauth_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 
    394 	ret = eap_server_method_register(eap);
    395 	if (ret)
    396 		eap_server_method_free(eap);
    397 	return ret;
    398 }
    399 #endif /* CONFIG_HS20 */
    400