Use common driver code for Linux hwaddr get/set
[hostap-gosc2009.git] / src / eap_peer / eap_tls.c
blob20b2212e1cdc4fff0e6e9cfe7ef2a95f8c5d3f91
1 /*
2 * EAP peer method: EAP-TLS (RFC 2716)
3 * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi>
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.
9 * Alternatively, this software may be distributed under the terms of BSD
10 * license.
12 * See README and COPYING for more details.
15 #include "includes.h"
17 #include "common.h"
18 #include "crypto/tls.h"
19 #include "eap_i.h"
20 #include "eap_tls_common.h"
21 #include "eap_config.h"
24 static void eap_tls_deinit(struct eap_sm *sm, void *priv);
27 struct eap_tls_data {
28 struct eap_ssl_data ssl;
29 u8 *key_data;
33 static void * eap_tls_init(struct eap_sm *sm)
35 struct eap_tls_data *data;
36 struct eap_peer_config *config = eap_get_config(sm);
37 if (config == NULL ||
38 ((sm->init_phase2 ? config->private_key2 : config->private_key)
39 == NULL &&
40 (sm->init_phase2 ? config->engine2 : config->engine) == 0)) {
41 wpa_printf(MSG_INFO, "EAP-TLS: Private key not configured");
42 return NULL;
45 data = os_zalloc(sizeof(*data));
46 if (data == NULL)
47 return NULL;
49 if (eap_peer_tls_ssl_init(sm, &data->ssl, config)) {
50 wpa_printf(MSG_INFO, "EAP-TLS: Failed to initialize SSL.");
51 eap_tls_deinit(sm, data);
52 if (config->engine) {
53 wpa_printf(MSG_DEBUG, "EAP-TLS: Requesting Smartcard "
54 "PIN");
55 eap_sm_request_pin(sm);
56 sm->ignore = TRUE;
57 } else if (config->private_key && !config->private_key_passwd)
59 wpa_printf(MSG_DEBUG, "EAP-TLS: Requesting private "
60 "key passphrase");
61 eap_sm_request_passphrase(sm);
62 sm->ignore = TRUE;
64 return NULL;
67 return data;
71 static void eap_tls_deinit(struct eap_sm *sm, void *priv)
73 struct eap_tls_data *data = priv;
74 if (data == NULL)
75 return;
76 eap_peer_tls_ssl_deinit(sm, &data->ssl);
77 os_free(data->key_data);
78 os_free(data);
82 static struct wpabuf * eap_tls_failure(struct eap_sm *sm,
83 struct eap_tls_data *data,
84 struct eap_method_ret *ret, int res,
85 struct wpabuf *resp, u8 id)
87 wpa_printf(MSG_DEBUG, "EAP-TLS: TLS processing failed");
89 ret->methodState = METHOD_DONE;
90 ret->decision = DECISION_FAIL;
92 if (res == -1) {
93 struct eap_peer_config *config = eap_get_config(sm);
94 if (config) {
96 * The TLS handshake failed. So better forget the old
97 * PIN. It may be wrong, we cannot be sure but trying
98 * the wrong one again might block it on the card--so
99 * better ask the user again.
101 os_free(config->pin);
102 config->pin = NULL;
106 if (resp) {
108 * This is likely an alert message, so send it instead of just
109 * ACKing the error.
111 return resp;
114 return eap_peer_tls_build_ack(id, EAP_TYPE_TLS, 0);
118 static void eap_tls_success(struct eap_sm *sm, struct eap_tls_data *data,
119 struct eap_method_ret *ret)
121 wpa_printf(MSG_DEBUG, "EAP-TLS: Done");
123 ret->methodState = METHOD_DONE;
124 ret->decision = DECISION_UNCOND_SUCC;
126 os_free(data->key_data);
127 data->key_data = eap_peer_tls_derive_key(sm, &data->ssl,
128 "client EAP encryption",
129 EAP_TLS_KEY_LEN +
130 EAP_EMSK_LEN);
131 if (data->key_data) {
132 wpa_hexdump_key(MSG_DEBUG, "EAP-TLS: Derived key",
133 data->key_data, EAP_TLS_KEY_LEN);
134 wpa_hexdump_key(MSG_DEBUG, "EAP-TLS: Derived EMSK",
135 data->key_data + EAP_TLS_KEY_LEN,
136 EAP_EMSK_LEN);
137 } else {
138 wpa_printf(MSG_INFO, "EAP-TLS: Failed to derive key");
143 static struct wpabuf * eap_tls_process(struct eap_sm *sm, void *priv,
144 struct eap_method_ret *ret,
145 const struct wpabuf *reqData)
147 size_t left;
148 int res;
149 struct wpabuf *resp;
150 u8 flags, id;
151 const u8 *pos;
152 struct eap_tls_data *data = priv;
154 pos = eap_peer_tls_process_init(sm, &data->ssl, EAP_TYPE_TLS, ret,
155 reqData, &left, &flags);
156 if (pos == NULL)
157 return NULL;
158 id = eap_get_id(reqData);
160 if (flags & EAP_TLS_FLAGS_START) {
161 wpa_printf(MSG_DEBUG, "EAP-TLS: Start");
162 left = 0; /* make sure that this frame is empty, even though it
163 * should always be, anyway */
166 resp = NULL;
167 res = eap_peer_tls_process_helper(sm, &data->ssl, EAP_TYPE_TLS, 0, id,
168 pos, left, &resp);
170 if (res < 0) {
171 return eap_tls_failure(sm, data, ret, res, resp, id);
174 if (tls_connection_established(sm->ssl_ctx, data->ssl.conn))
175 eap_tls_success(sm, data, ret);
177 if (res == 1) {
178 wpabuf_free(resp);
179 return eap_peer_tls_build_ack(id, EAP_TYPE_TLS, 0);
182 return resp;
186 static Boolean eap_tls_has_reauth_data(struct eap_sm *sm, void *priv)
188 struct eap_tls_data *data = priv;
189 return tls_connection_established(sm->ssl_ctx, data->ssl.conn);
193 static void eap_tls_deinit_for_reauth(struct eap_sm *sm, void *priv)
198 static void * eap_tls_init_for_reauth(struct eap_sm *sm, void *priv)
200 struct eap_tls_data *data = priv;
201 os_free(data->key_data);
202 data->key_data = NULL;
203 if (eap_peer_tls_reauth_init(sm, &data->ssl)) {
204 os_free(data);
205 return NULL;
207 return priv;
211 static int eap_tls_get_status(struct eap_sm *sm, void *priv, char *buf,
212 size_t buflen, int verbose)
214 struct eap_tls_data *data = priv;
215 return eap_peer_tls_status(sm, &data->ssl, buf, buflen, verbose);
219 static Boolean eap_tls_isKeyAvailable(struct eap_sm *sm, void *priv)
221 struct eap_tls_data *data = priv;
222 return data->key_data != NULL;
226 static u8 * eap_tls_getKey(struct eap_sm *sm, void *priv, size_t *len)
228 struct eap_tls_data *data = priv;
229 u8 *key;
231 if (data->key_data == NULL)
232 return NULL;
234 key = os_malloc(EAP_TLS_KEY_LEN);
235 if (key == NULL)
236 return NULL;
238 *len = EAP_TLS_KEY_LEN;
239 os_memcpy(key, data->key_data, EAP_TLS_KEY_LEN);
241 return key;
245 static u8 * eap_tls_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
247 struct eap_tls_data *data = priv;
248 u8 *key;
250 if (data->key_data == NULL)
251 return NULL;
253 key = os_malloc(EAP_EMSK_LEN);
254 if (key == NULL)
255 return NULL;
257 *len = EAP_EMSK_LEN;
258 os_memcpy(key, data->key_data + EAP_TLS_KEY_LEN, EAP_EMSK_LEN);
260 return key;
264 int eap_peer_tls_register(void)
266 struct eap_method *eap;
267 int ret;
269 eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
270 EAP_VENDOR_IETF, EAP_TYPE_TLS, "TLS");
271 if (eap == NULL)
272 return -1;
274 eap->init = eap_tls_init;
275 eap->deinit = eap_tls_deinit;
276 eap->process = eap_tls_process;
277 eap->isKeyAvailable = eap_tls_isKeyAvailable;
278 eap->getKey = eap_tls_getKey;
279 eap->get_status = eap_tls_get_status;
280 eap->has_reauth_data = eap_tls_has_reauth_data;
281 eap->deinit_for_reauth = eap_tls_deinit_for_reauth;
282 eap->init_for_reauth = eap_tls_init_for_reauth;
283 eap->get_emsk = eap_tls_get_emsk;
285 ret = eap_peer_method_register(eap);
286 if (ret)
287 eap_peer_method_free(eap);
288 return ret;