1 /* 2 * hostapd / EAP-TLS (RFC 2716) 3 * Copyright (c) 2004-2008, Jouni Malinen <j (at) w1.fi> 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License version 2 as 7 * published by the Free Software Foundation. 8 * 9 * Alternatively, this software may be distributed under the terms of BSD 10 * license. 11 * 12 * See README and COPYING for more details. 13 */ 14 15 #include "includes.h" 16 17 #include "common.h" 18 #include "eap_i.h" 19 #include "eap_tls_common.h" 20 #include "tls.h" 21 22 23 static void eap_tls_reset(struct eap_sm *sm, void *priv); 24 25 26 struct eap_tls_data { 27 struct eap_ssl_data ssl; 28 enum { START, CONTINUE, SUCCESS, FAILURE } state; 29 int established; 30 }; 31 32 33 static const char * eap_tls_state_txt(int state) 34 { 35 switch (state) { 36 case START: 37 return "START"; 38 case CONTINUE: 39 return "CONTINUE"; 40 case SUCCESS: 41 return "SUCCESS"; 42 case FAILURE: 43 return "FAILURE"; 44 default: 45 return "Unknown?!"; 46 } 47 } 48 49 50 static void eap_tls_state(struct eap_tls_data *data, int state) 51 { 52 wpa_printf(MSG_DEBUG, "EAP-TLS: %s -> %s", 53 eap_tls_state_txt(data->state), 54 eap_tls_state_txt(state)); 55 data->state = state; 56 } 57 58 59 static void * eap_tls_init(struct eap_sm *sm) 60 { 61 struct eap_tls_data *data; 62 63 data = os_zalloc(sizeof(*data)); 64 if (data == NULL) 65 return NULL; 66 data->state = START; 67 68 if (eap_server_tls_ssl_init(sm, &data->ssl, 1)) { 69 wpa_printf(MSG_INFO, "EAP-TLS: Failed to initialize SSL."); 70 eap_tls_reset(sm, data); 71 return NULL; 72 } 73 74 return data; 75 } 76 77 78 static void eap_tls_reset(struct eap_sm *sm, void *priv) 79 { 80 struct eap_tls_data *data = priv; 81 if (data == NULL) 82 return; 83 eap_server_tls_ssl_deinit(sm, &data->ssl); 84 os_free(data); 85 } 86 87 88 static struct wpabuf * eap_tls_build_start(struct eap_sm *sm, 89 struct eap_tls_data *data, u8 id) 90 { 91 struct wpabuf *req; 92 93 req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TLS, 1, EAP_CODE_REQUEST, 94 id); 95 if (req == NULL) { 96 wpa_printf(MSG_ERROR, "EAP-TLS: Failed to allocate memory for " 97 "request"); 98 eap_tls_state(data, FAILURE); 99 return NULL; 100 } 101 102 wpabuf_put_u8(req, EAP_TLS_FLAGS_START); 103 104 eap_tls_state(data, CONTINUE); 105 106 return req; 107 } 108 109 110 static struct wpabuf * eap_tls_buildReq(struct eap_sm *sm, void *priv, u8 id) 111 { 112 struct eap_tls_data *data = priv; 113 struct wpabuf *res; 114 115 if (data->ssl.state == FRAG_ACK) { 116 return eap_server_tls_build_ack(id, EAP_TYPE_TLS, 0); 117 } 118 119 if (data->ssl.state == WAIT_FRAG_ACK) { 120 res = eap_server_tls_build_msg(&data->ssl, EAP_TYPE_TLS, 0, 121 id); 122 goto check_established; 123 } 124 125 switch (data->state) { 126 case START: 127 return eap_tls_build_start(sm, data, id); 128 case CONTINUE: 129 if (tls_connection_established(sm->ssl_ctx, data->ssl.conn)) 130 data->established = 1; 131 break; 132 default: 133 wpa_printf(MSG_DEBUG, "EAP-TLS: %s - unexpected state %d", 134 __func__, data->state); 135 return NULL; 136 } 137 138 res = eap_server_tls_build_msg(&data->ssl, EAP_TYPE_TLS, 0, id); 139 140 check_established: 141 if (data->established && data->ssl.state != WAIT_FRAG_ACK) { 142 /* TLS handshake has been completed and there are no more 143 * fragments waiting to be sent out. */ 144 wpa_printf(MSG_DEBUG, "EAP-TLS: Done"); 145 eap_tls_state(data, SUCCESS); 146 } 147 148 return res; 149 } 150 151 152 static Boolean eap_tls_check(struct eap_sm *sm, void *priv, 153 struct wpabuf *respData) 154 { 155 const u8 *pos; 156 size_t len; 157 158 pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_TLS, respData, &len); 159 if (pos == NULL || len < 1) { 160 wpa_printf(MSG_INFO, "EAP-TLS: Invalid frame"); 161 return TRUE; 162 } 163 164 return FALSE; 165 } 166 167 168 static void eap_tls_process_msg(struct eap_sm *sm, void *priv, 169 const struct wpabuf *respData) 170 { 171 struct eap_tls_data *data = priv; 172 if (data->state == SUCCESS && wpabuf_len(data->ssl.in_buf) == 0) { 173 wpa_printf(MSG_DEBUG, "EAP-TLS: Client acknowledged final TLS " 174 "handshake message"); 175 return; 176 } 177 if (eap_server_tls_phase1(sm, &data->ssl) < 0) 178 eap_tls_state(data, FAILURE); 179 } 180 181 182 static void eap_tls_process(struct eap_sm *sm, void *priv, 183 struct wpabuf *respData) 184 { 185 struct eap_tls_data *data = priv; 186 if (eap_server_tls_process(sm, &data->ssl, respData, data, 187 EAP_TYPE_TLS, NULL, eap_tls_process_msg) < 188 0) 189 eap_tls_state(data, FAILURE); 190 } 191 192 193 static Boolean eap_tls_isDone(struct eap_sm *sm, void *priv) 194 { 195 struct eap_tls_data *data = priv; 196 return data->state == SUCCESS || data->state == FAILURE; 197 } 198 199 200 static u8 * eap_tls_getKey(struct eap_sm *sm, void *priv, size_t *len) 201 { 202 struct eap_tls_data *data = priv; 203 u8 *eapKeyData; 204 205 if (data->state != SUCCESS) 206 return NULL; 207 208 eapKeyData = eap_server_tls_derive_key(sm, &data->ssl, 209 "client EAP encryption", 210 EAP_TLS_KEY_LEN); 211 if (eapKeyData) { 212 *len = EAP_TLS_KEY_LEN; 213 wpa_hexdump(MSG_DEBUG, "EAP-TLS: Derived key", 214 eapKeyData, EAP_TLS_KEY_LEN); 215 } else { 216 wpa_printf(MSG_DEBUG, "EAP-TLS: Failed to derive key"); 217 } 218 219 return eapKeyData; 220 } 221 222 223 static u8 * eap_tls_get_emsk(struct eap_sm *sm, void *priv, size_t *len) 224 { 225 struct eap_tls_data *data = priv; 226 u8 *eapKeyData, *emsk; 227 228 if (data->state != SUCCESS) 229 return NULL; 230 231 eapKeyData = eap_server_tls_derive_key(sm, &data->ssl, 232 "client EAP encryption", 233 EAP_TLS_KEY_LEN + EAP_EMSK_LEN); 234 if (eapKeyData) { 235 emsk = os_malloc(EAP_EMSK_LEN); 236 if (emsk) 237 os_memcpy(emsk, eapKeyData + EAP_TLS_KEY_LEN, 238 EAP_EMSK_LEN); 239 os_free(eapKeyData); 240 } else 241 emsk = NULL; 242 243 if (emsk) { 244 *len = EAP_EMSK_LEN; 245 wpa_hexdump(MSG_DEBUG, "EAP-TLS: Derived EMSK", 246 emsk, EAP_EMSK_LEN); 247 } else { 248 wpa_printf(MSG_DEBUG, "EAP-TLS: Failed to derive EMSK"); 249 } 250 251 return emsk; 252 } 253 254 255 static Boolean eap_tls_isSuccess(struct eap_sm *sm, void *priv) 256 { 257 struct eap_tls_data *data = priv; 258 return data->state == SUCCESS; 259 } 260 261 262 int eap_server_tls_register(void) 263 { 264 struct eap_method *eap; 265 int ret; 266 267 eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION, 268 EAP_VENDOR_IETF, EAP_TYPE_TLS, "TLS"); 269 if (eap == NULL) 270 return -1; 271 272 eap->init = eap_tls_init; 273 eap->reset = eap_tls_reset; 274 eap->buildReq = eap_tls_buildReq; 275 eap->check = eap_tls_check; 276 eap->process = eap_tls_process; 277 eap->isDone = eap_tls_isDone; 278 eap->getKey = eap_tls_getKey; 279 eap->isSuccess = eap_tls_isSuccess; 280 eap->get_emsk = eap_tls_get_emsk; 281 282 ret = eap_server_method_register(eap); 283 if (ret) 284 eap_server_method_free(eap); 285 return ret; 286 } 287