eap_server_tls.c revision 214501
1214501Srpaulo/* 2214501Srpaulo * hostapd / EAP-TLS (RFC 2716) 3214501Srpaulo * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi> 4214501Srpaulo * 5214501Srpaulo * This program is free software; you can redistribute it and/or modify 6214501Srpaulo * it under the terms of the GNU General Public License version 2 as 7214501Srpaulo * published by the Free Software Foundation. 8214501Srpaulo * 9214501Srpaulo * Alternatively, this software may be distributed under the terms of BSD 10214501Srpaulo * license. 11214501Srpaulo * 12214501Srpaulo * See README and COPYING for more details. 13214501Srpaulo */ 14214501Srpaulo 15214501Srpaulo#include "includes.h" 16214501Srpaulo 17214501Srpaulo#include "common.h" 18214501Srpaulo#include "eap_i.h" 19214501Srpaulo#include "eap_tls_common.h" 20214501Srpaulo#include "crypto/tls.h" 21214501Srpaulo 22214501Srpaulo 23214501Srpaulostatic void eap_tls_reset(struct eap_sm *sm, void *priv); 24214501Srpaulo 25214501Srpaulo 26214501Srpaulostruct eap_tls_data { 27214501Srpaulo struct eap_ssl_data ssl; 28214501Srpaulo enum { START, CONTINUE, SUCCESS, FAILURE } state; 29214501Srpaulo int established; 30214501Srpaulo}; 31214501Srpaulo 32214501Srpaulo 33214501Srpaulostatic const char * eap_tls_state_txt(int state) 34214501Srpaulo{ 35214501Srpaulo switch (state) { 36214501Srpaulo case START: 37214501Srpaulo return "START"; 38214501Srpaulo case CONTINUE: 39214501Srpaulo return "CONTINUE"; 40214501Srpaulo case SUCCESS: 41214501Srpaulo return "SUCCESS"; 42214501Srpaulo case FAILURE: 43214501Srpaulo return "FAILURE"; 44214501Srpaulo default: 45214501Srpaulo return "Unknown?!"; 46214501Srpaulo } 47214501Srpaulo} 48214501Srpaulo 49214501Srpaulo 50214501Srpaulostatic void eap_tls_state(struct eap_tls_data *data, int state) 51214501Srpaulo{ 52214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-TLS: %s -> %s", 53214501Srpaulo eap_tls_state_txt(data->state), 54214501Srpaulo eap_tls_state_txt(state)); 55214501Srpaulo data->state = state; 56214501Srpaulo} 57214501Srpaulo 58214501Srpaulo 59214501Srpaulostatic void * eap_tls_init(struct eap_sm *sm) 60214501Srpaulo{ 61214501Srpaulo struct eap_tls_data *data; 62214501Srpaulo 63214501Srpaulo data = os_zalloc(sizeof(*data)); 64214501Srpaulo if (data == NULL) 65214501Srpaulo return NULL; 66214501Srpaulo data->state = START; 67214501Srpaulo 68214501Srpaulo if (eap_server_tls_ssl_init(sm, &data->ssl, 1)) { 69214501Srpaulo wpa_printf(MSG_INFO, "EAP-TLS: Failed to initialize SSL."); 70214501Srpaulo eap_tls_reset(sm, data); 71214501Srpaulo return NULL; 72214501Srpaulo } 73214501Srpaulo 74214501Srpaulo return data; 75214501Srpaulo} 76214501Srpaulo 77214501Srpaulo 78214501Srpaulostatic void eap_tls_reset(struct eap_sm *sm, void *priv) 79214501Srpaulo{ 80214501Srpaulo struct eap_tls_data *data = priv; 81214501Srpaulo if (data == NULL) 82214501Srpaulo return; 83214501Srpaulo eap_server_tls_ssl_deinit(sm, &data->ssl); 84214501Srpaulo os_free(data); 85214501Srpaulo} 86214501Srpaulo 87214501Srpaulo 88214501Srpaulostatic struct wpabuf * eap_tls_build_start(struct eap_sm *sm, 89214501Srpaulo struct eap_tls_data *data, u8 id) 90214501Srpaulo{ 91214501Srpaulo struct wpabuf *req; 92214501Srpaulo 93214501Srpaulo req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TLS, 1, EAP_CODE_REQUEST, 94214501Srpaulo id); 95214501Srpaulo if (req == NULL) { 96214501Srpaulo wpa_printf(MSG_ERROR, "EAP-TLS: Failed to allocate memory for " 97214501Srpaulo "request"); 98214501Srpaulo eap_tls_state(data, FAILURE); 99214501Srpaulo return NULL; 100214501Srpaulo } 101214501Srpaulo 102214501Srpaulo wpabuf_put_u8(req, EAP_TLS_FLAGS_START); 103214501Srpaulo 104214501Srpaulo eap_tls_state(data, CONTINUE); 105214501Srpaulo 106214501Srpaulo return req; 107214501Srpaulo} 108214501Srpaulo 109214501Srpaulo 110214501Srpaulostatic struct wpabuf * eap_tls_buildReq(struct eap_sm *sm, void *priv, u8 id) 111214501Srpaulo{ 112214501Srpaulo struct eap_tls_data *data = priv; 113214501Srpaulo struct wpabuf *res; 114214501Srpaulo 115214501Srpaulo if (data->ssl.state == FRAG_ACK) { 116214501Srpaulo return eap_server_tls_build_ack(id, EAP_TYPE_TLS, 0); 117214501Srpaulo } 118214501Srpaulo 119214501Srpaulo if (data->ssl.state == WAIT_FRAG_ACK) { 120214501Srpaulo res = eap_server_tls_build_msg(&data->ssl, EAP_TYPE_TLS, 0, 121214501Srpaulo id); 122214501Srpaulo goto check_established; 123214501Srpaulo } 124214501Srpaulo 125214501Srpaulo switch (data->state) { 126214501Srpaulo case START: 127214501Srpaulo return eap_tls_build_start(sm, data, id); 128214501Srpaulo case CONTINUE: 129214501Srpaulo if (tls_connection_established(sm->ssl_ctx, data->ssl.conn)) 130214501Srpaulo data->established = 1; 131214501Srpaulo break; 132214501Srpaulo default: 133214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-TLS: %s - unexpected state %d", 134214501Srpaulo __func__, data->state); 135214501Srpaulo return NULL; 136214501Srpaulo } 137214501Srpaulo 138214501Srpaulo res = eap_server_tls_build_msg(&data->ssl, EAP_TYPE_TLS, 0, id); 139214501Srpaulo 140214501Srpaulocheck_established: 141214501Srpaulo if (data->established && data->ssl.state != WAIT_FRAG_ACK) { 142214501Srpaulo /* TLS handshake has been completed and there are no more 143214501Srpaulo * fragments waiting to be sent out. */ 144214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-TLS: Done"); 145214501Srpaulo eap_tls_state(data, SUCCESS); 146214501Srpaulo } 147214501Srpaulo 148214501Srpaulo return res; 149214501Srpaulo} 150214501Srpaulo 151214501Srpaulo 152214501Srpaulostatic Boolean eap_tls_check(struct eap_sm *sm, void *priv, 153214501Srpaulo struct wpabuf *respData) 154214501Srpaulo{ 155214501Srpaulo const u8 *pos; 156214501Srpaulo size_t len; 157214501Srpaulo 158214501Srpaulo pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_TLS, respData, &len); 159214501Srpaulo if (pos == NULL || len < 1) { 160214501Srpaulo wpa_printf(MSG_INFO, "EAP-TLS: Invalid frame"); 161214501Srpaulo return TRUE; 162214501Srpaulo } 163214501Srpaulo 164214501Srpaulo return FALSE; 165214501Srpaulo} 166214501Srpaulo 167214501Srpaulo 168214501Srpaulostatic void eap_tls_process_msg(struct eap_sm *sm, void *priv, 169214501Srpaulo const struct wpabuf *respData) 170214501Srpaulo{ 171214501Srpaulo struct eap_tls_data *data = priv; 172214501Srpaulo if (data->state == SUCCESS && wpabuf_len(data->ssl.tls_in) == 0) { 173214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-TLS: Client acknowledged final TLS " 174214501Srpaulo "handshake message"); 175214501Srpaulo return; 176214501Srpaulo } 177214501Srpaulo if (eap_server_tls_phase1(sm, &data->ssl) < 0) 178214501Srpaulo eap_tls_state(data, FAILURE); 179214501Srpaulo} 180214501Srpaulo 181214501Srpaulo 182214501Srpaulostatic void eap_tls_process(struct eap_sm *sm, void *priv, 183214501Srpaulo struct wpabuf *respData) 184214501Srpaulo{ 185214501Srpaulo struct eap_tls_data *data = priv; 186214501Srpaulo if (eap_server_tls_process(sm, &data->ssl, respData, data, 187214501Srpaulo EAP_TYPE_TLS, NULL, eap_tls_process_msg) < 188214501Srpaulo 0) 189214501Srpaulo eap_tls_state(data, FAILURE); 190214501Srpaulo} 191214501Srpaulo 192214501Srpaulo 193214501Srpaulostatic Boolean eap_tls_isDone(struct eap_sm *sm, void *priv) 194214501Srpaulo{ 195214501Srpaulo struct eap_tls_data *data = priv; 196214501Srpaulo return data->state == SUCCESS || data->state == FAILURE; 197214501Srpaulo} 198214501Srpaulo 199214501Srpaulo 200214501Srpaulostatic u8 * eap_tls_getKey(struct eap_sm *sm, void *priv, size_t *len) 201214501Srpaulo{ 202214501Srpaulo struct eap_tls_data *data = priv; 203214501Srpaulo u8 *eapKeyData; 204214501Srpaulo 205214501Srpaulo if (data->state != SUCCESS) 206214501Srpaulo return NULL; 207214501Srpaulo 208214501Srpaulo eapKeyData = eap_server_tls_derive_key(sm, &data->ssl, 209214501Srpaulo "client EAP encryption", 210214501Srpaulo EAP_TLS_KEY_LEN); 211214501Srpaulo if (eapKeyData) { 212214501Srpaulo *len = EAP_TLS_KEY_LEN; 213214501Srpaulo wpa_hexdump(MSG_DEBUG, "EAP-TLS: Derived key", 214214501Srpaulo eapKeyData, EAP_TLS_KEY_LEN); 215214501Srpaulo } else { 216214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-TLS: Failed to derive key"); 217214501Srpaulo } 218214501Srpaulo 219214501Srpaulo return eapKeyData; 220214501Srpaulo} 221214501Srpaulo 222214501Srpaulo 223214501Srpaulostatic u8 * eap_tls_get_emsk(struct eap_sm *sm, void *priv, size_t *len) 224214501Srpaulo{ 225214501Srpaulo struct eap_tls_data *data = priv; 226214501Srpaulo u8 *eapKeyData, *emsk; 227214501Srpaulo 228214501Srpaulo if (data->state != SUCCESS) 229214501Srpaulo return NULL; 230214501Srpaulo 231214501Srpaulo eapKeyData = eap_server_tls_derive_key(sm, &data->ssl, 232214501Srpaulo "client EAP encryption", 233214501Srpaulo EAP_TLS_KEY_LEN + EAP_EMSK_LEN); 234214501Srpaulo if (eapKeyData) { 235214501Srpaulo emsk = os_malloc(EAP_EMSK_LEN); 236214501Srpaulo if (emsk) 237214501Srpaulo os_memcpy(emsk, eapKeyData + EAP_TLS_KEY_LEN, 238214501Srpaulo EAP_EMSK_LEN); 239214501Srpaulo os_free(eapKeyData); 240214501Srpaulo } else 241214501Srpaulo emsk = NULL; 242214501Srpaulo 243214501Srpaulo if (emsk) { 244214501Srpaulo *len = EAP_EMSK_LEN; 245214501Srpaulo wpa_hexdump(MSG_DEBUG, "EAP-TLS: Derived EMSK", 246214501Srpaulo emsk, EAP_EMSK_LEN); 247214501Srpaulo } else { 248214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-TLS: Failed to derive EMSK"); 249214501Srpaulo } 250214501Srpaulo 251214501Srpaulo return emsk; 252214501Srpaulo} 253214501Srpaulo 254214501Srpaulo 255214501Srpaulostatic Boolean eap_tls_isSuccess(struct eap_sm *sm, void *priv) 256214501Srpaulo{ 257214501Srpaulo struct eap_tls_data *data = priv; 258214501Srpaulo return data->state == SUCCESS; 259214501Srpaulo} 260214501Srpaulo 261214501Srpaulo 262214501Srpauloint eap_server_tls_register(void) 263214501Srpaulo{ 264214501Srpaulo struct eap_method *eap; 265214501Srpaulo int ret; 266214501Srpaulo 267214501Srpaulo eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION, 268214501Srpaulo EAP_VENDOR_IETF, EAP_TYPE_TLS, "TLS"); 269214501Srpaulo if (eap == NULL) 270214501Srpaulo return -1; 271214501Srpaulo 272214501Srpaulo eap->init = eap_tls_init; 273214501Srpaulo eap->reset = eap_tls_reset; 274214501Srpaulo eap->buildReq = eap_tls_buildReq; 275214501Srpaulo eap->check = eap_tls_check; 276214501Srpaulo eap->process = eap_tls_process; 277214501Srpaulo eap->isDone = eap_tls_isDone; 278214501Srpaulo eap->getKey = eap_tls_getKey; 279214501Srpaulo eap->isSuccess = eap_tls_isSuccess; 280214501Srpaulo eap->get_emsk = eap_tls_get_emsk; 281214501Srpaulo 282214501Srpaulo ret = eap_server_method_register(eap); 283214501Srpaulo if (ret) 284214501Srpaulo eap_server_method_free(eap); 285214501Srpaulo return ret; 286214501Srpaulo} 287