eap_tls.c revision 04949598a23f501be6eec21697465fd46a28840a
1/* 2 * EAP peer method: EAP-TLS (RFC 2716) 3 * Copyright (c) 2004-2008, 2012, Jouni Malinen <j@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 "crypto/tls.h" 13#include "eap_i.h" 14#include "eap_tls_common.h" 15#include "eap_config.h" 16 17 18static void eap_tls_deinit(struct eap_sm *sm, void *priv); 19 20 21struct eap_tls_data { 22 struct eap_ssl_data ssl; 23 u8 *key_data; 24 void *ssl_ctx; 25}; 26 27 28static void * eap_tls_init(struct eap_sm *sm) 29{ 30 struct eap_tls_data *data; 31 struct eap_peer_config *config = eap_get_config(sm); 32 if (config == NULL || 33 ((sm->init_phase2 ? config->private_key2 : config->private_key) 34 == NULL && 35 (sm->init_phase2 ? config->engine2 : config->engine) == 0)) { 36 wpa_printf(MSG_INFO, "EAP-TLS: Private key not configured"); 37 return NULL; 38 } 39 40 data = os_zalloc(sizeof(*data)); 41 if (data == NULL) 42 return NULL; 43 44 data->ssl_ctx = sm->init_phase2 && sm->ssl_ctx2 ? sm->ssl_ctx2 : 45 sm->ssl_ctx; 46 47 if (eap_peer_tls_ssl_init(sm, &data->ssl, config)) { 48 wpa_printf(MSG_INFO, "EAP-TLS: Failed to initialize SSL."); 49 eap_tls_deinit(sm, data); 50 if (config->engine) { 51 wpa_printf(MSG_DEBUG, "EAP-TLS: Requesting Smartcard " 52 "PIN"); 53 eap_sm_request_pin(sm); 54 sm->ignore = TRUE; 55 } else if (config->private_key && !config->private_key_passwd) 56 { 57 wpa_printf(MSG_DEBUG, "EAP-TLS: Requesting private " 58 "key passphrase"); 59 eap_sm_request_passphrase(sm); 60 sm->ignore = TRUE; 61 } 62 return NULL; 63 } 64 65 return data; 66} 67 68 69static void eap_tls_deinit(struct eap_sm *sm, void *priv) 70{ 71 struct eap_tls_data *data = priv; 72 if (data == NULL) 73 return; 74 eap_peer_tls_ssl_deinit(sm, &data->ssl); 75 os_free(data->key_data); 76 os_free(data); 77} 78 79 80static struct wpabuf * eap_tls_failure(struct eap_sm *sm, 81 struct eap_tls_data *data, 82 struct eap_method_ret *ret, int res, 83 struct wpabuf *resp, u8 id) 84{ 85 wpa_printf(MSG_DEBUG, "EAP-TLS: TLS processing failed"); 86 87 ret->methodState = METHOD_DONE; 88 ret->decision = DECISION_FAIL; 89 90 if (res == -1) { 91 struct eap_peer_config *config = eap_get_config(sm); 92 if (config) { 93 /* 94 * The TLS handshake failed. So better forget the old 95 * PIN. It may be wrong, we cannot be sure but trying 96 * the wrong one again might block it on the card--so 97 * better ask the user again. 98 */ 99 os_free(config->pin); 100 config->pin = NULL; 101 } 102 } 103 104 if (resp) { 105 /* 106 * This is likely an alert message, so send it instead of just 107 * ACKing the error. 108 */ 109 return resp; 110 } 111 112 return eap_peer_tls_build_ack(id, EAP_TYPE_TLS, 0); 113} 114 115 116static void eap_tls_success(struct eap_sm *sm, struct eap_tls_data *data, 117 struct eap_method_ret *ret) 118{ 119 wpa_printf(MSG_DEBUG, "EAP-TLS: Done"); 120 121 ret->methodState = METHOD_DONE; 122 ret->decision = DECISION_UNCOND_SUCC; 123 124 os_free(data->key_data); 125 data->key_data = eap_peer_tls_derive_key(sm, &data->ssl, 126 "client EAP encryption", 127 EAP_TLS_KEY_LEN + 128 EAP_EMSK_LEN); 129 if (data->key_data) { 130 wpa_hexdump_key(MSG_DEBUG, "EAP-TLS: Derived key", 131 data->key_data, EAP_TLS_KEY_LEN); 132 wpa_hexdump_key(MSG_DEBUG, "EAP-TLS: Derived EMSK", 133 data->key_data + EAP_TLS_KEY_LEN, 134 EAP_EMSK_LEN); 135 } else { 136 wpa_printf(MSG_INFO, "EAP-TLS: Failed to derive key"); 137 } 138} 139 140 141static struct wpabuf * eap_tls_process(struct eap_sm *sm, void *priv, 142 struct eap_method_ret *ret, 143 const struct wpabuf *reqData) 144{ 145 size_t left; 146 int res; 147 struct wpabuf *resp; 148 u8 flags, id; 149 const u8 *pos; 150 struct eap_tls_data *data = priv; 151 152 pos = eap_peer_tls_process_init(sm, &data->ssl, EAP_TYPE_TLS, ret, 153 reqData, &left, &flags); 154 if (pos == NULL) 155 return NULL; 156 id = eap_get_id(reqData); 157 158 if (flags & EAP_TLS_FLAGS_START) { 159 wpa_printf(MSG_DEBUG, "EAP-TLS: Start"); 160 left = 0; /* make sure that this frame is empty, even though it 161 * should always be, anyway */ 162 } 163 164 resp = NULL; 165 res = eap_peer_tls_process_helper(sm, &data->ssl, EAP_TYPE_TLS, 0, id, 166 pos, left, &resp); 167 168 if (res < 0) { 169 return eap_tls_failure(sm, data, ret, res, resp, id); 170 } 171 172 if (tls_connection_established(data->ssl_ctx, data->ssl.conn)) 173 eap_tls_success(sm, data, ret); 174 175 if (res == 1) { 176 wpabuf_free(resp); 177 return eap_peer_tls_build_ack(id, EAP_TYPE_TLS, 0); 178 } 179 180 return resp; 181} 182 183 184static Boolean eap_tls_has_reauth_data(struct eap_sm *sm, void *priv) 185{ 186 struct eap_tls_data *data = priv; 187 return tls_connection_established(data->ssl_ctx, data->ssl.conn); 188} 189 190 191static void eap_tls_deinit_for_reauth(struct eap_sm *sm, void *priv) 192{ 193} 194 195 196static void * eap_tls_init_for_reauth(struct eap_sm *sm, void *priv) 197{ 198 struct eap_tls_data *data = priv; 199 os_free(data->key_data); 200 data->key_data = NULL; 201 if (eap_peer_tls_reauth_init(sm, &data->ssl)) { 202 os_free(data); 203 return NULL; 204 } 205 return priv; 206} 207 208 209static int eap_tls_get_status(struct eap_sm *sm, void *priv, char *buf, 210 size_t buflen, int verbose) 211{ 212 struct eap_tls_data *data = priv; 213 return eap_peer_tls_status(sm, &data->ssl, buf, buflen, verbose); 214} 215 216 217static Boolean eap_tls_isKeyAvailable(struct eap_sm *sm, void *priv) 218{ 219 struct eap_tls_data *data = priv; 220 return data->key_data != NULL; 221} 222 223 224static u8 * eap_tls_getKey(struct eap_sm *sm, void *priv, size_t *len) 225{ 226 struct eap_tls_data *data = priv; 227 u8 *key; 228 229 if (data->key_data == NULL) 230 return NULL; 231 232 key = os_malloc(EAP_TLS_KEY_LEN); 233 if (key == NULL) 234 return NULL; 235 236 *len = EAP_TLS_KEY_LEN; 237 os_memcpy(key, data->key_data, EAP_TLS_KEY_LEN); 238 239 return key; 240} 241 242 243static u8 * eap_tls_get_emsk(struct eap_sm *sm, void *priv, size_t *len) 244{ 245 struct eap_tls_data *data = priv; 246 u8 *key; 247 248 if (data->key_data == NULL) 249 return NULL; 250 251 key = os_malloc(EAP_EMSK_LEN); 252 if (key == NULL) 253 return NULL; 254 255 *len = EAP_EMSK_LEN; 256 os_memcpy(key, data->key_data + EAP_TLS_KEY_LEN, EAP_EMSK_LEN); 257 258 return key; 259} 260 261 262int eap_peer_tls_register(void) 263{ 264 struct eap_method *eap; 265 int ret; 266 267 eap = eap_peer_method_alloc(EAP_PEER_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->deinit = eap_tls_deinit; 274 eap->process = eap_tls_process; 275 eap->isKeyAvailable = eap_tls_isKeyAvailable; 276 eap->getKey = eap_tls_getKey; 277 eap->get_status = eap_tls_get_status; 278 eap->has_reauth_data = eap_tls_has_reauth_data; 279 eap->deinit_for_reauth = eap_tls_deinit_for_reauth; 280 eap->init_for_reauth = eap_tls_init_for_reauth; 281 eap->get_emsk = eap_tls_get_emsk; 282 283 ret = eap_peer_method_register(eap); 284 if (ret) 285 eap_peer_method_free(eap); 286 return ret; 287} 288