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