2 * EAP peer method: EAP-TLS (RFC 2716)
3 * Copyright (c) 2004-2008, 2012-2015, Jouni Malinen <j@w1.fi>
5 * This software may be distributed under the terms of the BSD license.
6 * See README for more details.
12 #include "crypto/tls.h"
14 #include "eap_tls_common.h"
15 #include "eap_config.h"
18 static void eap_tls_deinit(struct eap_sm
*sm
, void *priv
);
22 struct eap_ssl_data ssl
;
28 struct wpabuf
*pending_resp
;
32 static void * eap_tls_init(struct eap_sm
*sm
)
34 struct eap_tls_data
*data
;
35 struct eap_peer_config
*config
= eap_get_config(sm
);
37 ((sm
->init_phase2
? config
->private_key2
: config
->private_key
)
39 (sm
->init_phase2
? config
->engine2
: config
->engine
) == 0)) {
40 wpa_printf(MSG_INFO
, "EAP-TLS: Private key not configured");
44 data
= os_zalloc(sizeof(*data
));
48 data
->ssl_ctx
= sm
->init_phase2
&& sm
->ssl_ctx2
? sm
->ssl_ctx2
:
51 if (eap_peer_tls_ssl_init(sm
, &data
->ssl
, config
, EAP_TYPE_TLS
)) {
52 wpa_printf(MSG_INFO
, "EAP-TLS: Failed to initialize SSL.");
53 eap_tls_deinit(sm
, data
);
55 wpa_printf(MSG_DEBUG
, "EAP-TLS: Requesting Smartcard "
57 eap_sm_request_pin(sm
);
59 } else if (config
->private_key
&& !config
->private_key_passwd
)
61 wpa_printf(MSG_DEBUG
, "EAP-TLS: Requesting private "
63 eap_sm_request_passphrase(sm
);
69 data
->eap_type
= EAP_TYPE_TLS
;
76 static void * eap_unauth_tls_init(struct eap_sm
*sm
)
78 struct eap_tls_data
*data
;
79 struct eap_peer_config
*config
= eap_get_config(sm
);
81 data
= os_zalloc(sizeof(*data
));
85 data
->ssl_ctx
= sm
->init_phase2
&& sm
->ssl_ctx2
? sm
->ssl_ctx2
:
88 if (eap_peer_tls_ssl_init(sm
, &data
->ssl
, config
,
89 EAP_UNAUTH_TLS_TYPE
)) {
90 wpa_printf(MSG_INFO
, "EAP-TLS: Failed to initialize SSL.");
91 eap_tls_deinit(sm
, data
);
95 data
->eap_type
= EAP_UNAUTH_TLS_TYPE
;
99 #endif /* EAP_UNAUTH_TLS */
103 static void * eap_wfa_unauth_tls_init(struct eap_sm
*sm
)
105 struct eap_tls_data
*data
;
106 struct eap_peer_config
*config
= eap_get_config(sm
);
108 data
= os_zalloc(sizeof(*data
));
112 data
->ssl_ctx
= sm
->init_phase2
&& sm
->ssl_ctx2
? sm
->ssl_ctx2
:
115 if (eap_peer_tls_ssl_init(sm
, &data
->ssl
, config
,
116 EAP_WFA_UNAUTH_TLS_TYPE
)) {
117 wpa_printf(MSG_INFO
, "EAP-TLS: Failed to initialize SSL.");
118 eap_tls_deinit(sm
, data
);
122 data
->eap_type
= EAP_WFA_UNAUTH_TLS_TYPE
;
126 #endif /* CONFIG_HS20 */
129 static void eap_tls_free_key(struct eap_tls_data
*data
)
131 if (data
->key_data
) {
132 bin_clear_free(data
->key_data
, EAP_TLS_KEY_LEN
+ EAP_EMSK_LEN
);
133 data
->key_data
= NULL
;
138 static void eap_tls_deinit(struct eap_sm
*sm
, void *priv
)
140 struct eap_tls_data
*data
= priv
;
143 eap_peer_tls_ssl_deinit(sm
, &data
->ssl
);
144 eap_tls_free_key(data
);
145 os_free(data
->session_id
);
146 wpabuf_free(data
->pending_resp
);
151 static struct wpabuf
* eap_tls_failure(struct eap_sm
*sm
,
152 struct eap_tls_data
*data
,
153 struct eap_method_ret
*ret
, int res
,
154 struct wpabuf
*resp
, u8 id
)
156 wpa_printf(MSG_DEBUG
, "EAP-TLS: TLS processing failed");
158 ret
->methodState
= METHOD_DONE
;
159 ret
->decision
= DECISION_FAIL
;
163 * This is likely an alert message, so send it instead of just
169 return eap_peer_tls_build_ack(id
, data
->eap_type
, 0);
173 static void eap_tls_success(struct eap_sm
*sm
, struct eap_tls_data
*data
,
174 struct eap_method_ret
*ret
)
178 wpa_printf(MSG_DEBUG
, "EAP-TLS: Done");
180 if (data
->ssl
.tls_out
) {
181 wpa_printf(MSG_DEBUG
, "EAP-TLS: Fragment(s) remaining");
185 if (data
->ssl
.tls_v13
) {
186 label
= "EXPORTER_EAP_TLS_Key_Material";
188 /* A possible NewSessionTicket may be received before
189 * EAP-Success, so need to allow it to be received. */
190 ret
->methodState
= METHOD_MAY_CONT
;
191 ret
->decision
= DECISION_COND_SUCC
;
193 label
= "client EAP encryption";
195 ret
->methodState
= METHOD_DONE
;
196 ret
->decision
= DECISION_UNCOND_SUCC
;
199 eap_tls_free_key(data
);
200 data
->key_data
= eap_peer_tls_derive_key(sm
, &data
->ssl
, label
,
204 if (data
->key_data
) {
205 wpa_hexdump_key(MSG_DEBUG
, "EAP-TLS: Derived key",
206 data
->key_data
, EAP_TLS_KEY_LEN
);
207 wpa_hexdump_key(MSG_DEBUG
, "EAP-TLS: Derived EMSK",
208 data
->key_data
+ EAP_TLS_KEY_LEN
,
211 wpa_printf(MSG_INFO
, "EAP-TLS: Failed to derive key");
214 os_free(data
->session_id
);
215 data
->session_id
= eap_peer_tls_derive_session_id(sm
, &data
->ssl
,
218 if (data
->session_id
) {
219 wpa_hexdump(MSG_DEBUG
, "EAP-TLS: Derived Session-Id",
220 data
->session_id
, data
->id_len
);
222 wpa_printf(MSG_ERROR
, "EAP-TLS: Failed to derive Session-Id");
227 static struct wpabuf
* eap_tls_process(struct eap_sm
*sm
, void *priv
,
228 struct eap_method_ret
*ret
,
229 const struct wpabuf
*reqData
)
236 struct eap_tls_data
*data
= priv
;
239 if (sm
->waiting_ext_cert_check
&& data
->pending_resp
) {
240 struct eap_peer_config
*config
= eap_get_config(sm
);
242 if (config
->pending_ext_cert_check
== EXT_CERT_CHECK_GOOD
) {
243 wpa_printf(MSG_DEBUG
,
244 "EAP-TLS: External certificate check succeeded - continue handshake");
245 resp
= data
->pending_resp
;
246 data
->pending_resp
= NULL
;
247 sm
->waiting_ext_cert_check
= 0;
251 if (config
->pending_ext_cert_check
== EXT_CERT_CHECK_BAD
) {
252 wpa_printf(MSG_DEBUG
,
253 "EAP-TLS: External certificate check failed - force authentication failure");
254 ret
->methodState
= METHOD_DONE
;
255 ret
->decision
= DECISION_FAIL
;
256 sm
->waiting_ext_cert_check
= 0;
260 wpa_printf(MSG_DEBUG
,
261 "EAP-TLS: Continuing to wait external server certificate validation");
265 pos
= eap_peer_tls_process_init(sm
, &data
->ssl
, data
->eap_type
, ret
,
266 reqData
, &left
, &flags
);
269 id
= eap_get_id(reqData
);
271 if (flags
& EAP_TLS_FLAGS_START
) {
272 wpa_printf(MSG_DEBUG
, "EAP-TLS: Start");
273 left
= 0; /* make sure that this frame is empty, even though it
274 * should always be, anyway */
278 wpabuf_set(&msg
, pos
, left
);
279 res
= eap_peer_tls_process_helper(sm
, &data
->ssl
, data
->eap_type
, 0,
283 return eap_tls_failure(sm
, data
, ret
, res
, resp
, id
);
286 if (sm
->waiting_ext_cert_check
) {
287 wpa_printf(MSG_DEBUG
,
288 "EAP-TLS: Waiting external server certificate validation");
289 wpabuf_free(data
->pending_resp
);
290 data
->pending_resp
= resp
;
294 if (tls_connection_established(data
->ssl_ctx
, data
->ssl
.conn
))
295 eap_tls_success(sm
, data
, ret
);
299 return eap_peer_tls_build_ack(id
, data
->eap_type
, 0);
306 static Boolean
eap_tls_has_reauth_data(struct eap_sm
*sm
, void *priv
)
308 struct eap_tls_data
*data
= priv
;
309 return tls_connection_established(data
->ssl_ctx
, data
->ssl
.conn
);
313 static void eap_tls_deinit_for_reauth(struct eap_sm
*sm
, void *priv
)
315 struct eap_tls_data
*data
= priv
;
317 wpabuf_free(data
->pending_resp
);
318 data
->pending_resp
= NULL
;
322 static void * eap_tls_init_for_reauth(struct eap_sm
*sm
, void *priv
)
324 struct eap_tls_data
*data
= priv
;
325 eap_tls_free_key(data
);
326 os_free(data
->session_id
);
327 data
->session_id
= NULL
;
328 if (eap_peer_tls_reauth_init(sm
, &data
->ssl
)) {
336 static int eap_tls_get_status(struct eap_sm
*sm
, void *priv
, char *buf
,
337 size_t buflen
, int verbose
)
339 struct eap_tls_data
*data
= priv
;
340 return eap_peer_tls_status(sm
, &data
->ssl
, buf
, buflen
, verbose
);
344 static Boolean
eap_tls_isKeyAvailable(struct eap_sm
*sm
, void *priv
)
346 struct eap_tls_data
*data
= priv
;
347 return data
->key_data
!= NULL
;
351 static u8
* eap_tls_getKey(struct eap_sm
*sm
, void *priv
, size_t *len
)
353 struct eap_tls_data
*data
= priv
;
356 if (data
->key_data
== NULL
)
359 key
= os_memdup(data
->key_data
, EAP_TLS_KEY_LEN
);
363 *len
= EAP_TLS_KEY_LEN
;
369 static u8
* eap_tls_get_emsk(struct eap_sm
*sm
, void *priv
, size_t *len
)
371 struct eap_tls_data
*data
= priv
;
374 if (data
->key_data
== NULL
)
377 key
= os_memdup(data
->key_data
+ EAP_TLS_KEY_LEN
, EAP_EMSK_LEN
);
387 static u8
* eap_tls_get_session_id(struct eap_sm
*sm
, void *priv
, size_t *len
)
389 struct eap_tls_data
*data
= priv
;
392 if (data
->session_id
== NULL
)
395 id
= os_memdup(data
->session_id
, data
->id_len
);
405 int eap_peer_tls_register(void)
407 struct eap_method
*eap
;
409 eap
= eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION
,
410 EAP_VENDOR_IETF
, EAP_TYPE_TLS
, "TLS");
414 eap
->init
= eap_tls_init
;
415 eap
->deinit
= eap_tls_deinit
;
416 eap
->process
= eap_tls_process
;
417 eap
->isKeyAvailable
= eap_tls_isKeyAvailable
;
418 eap
->getKey
= eap_tls_getKey
;
419 eap
->getSessionId
= eap_tls_get_session_id
;
420 eap
->get_status
= eap_tls_get_status
;
421 eap
->has_reauth_data
= eap_tls_has_reauth_data
;
422 eap
->deinit_for_reauth
= eap_tls_deinit_for_reauth
;
423 eap
->init_for_reauth
= eap_tls_init_for_reauth
;
424 eap
->get_emsk
= eap_tls_get_emsk
;
426 return eap_peer_method_register(eap
);
430 #ifdef EAP_UNAUTH_TLS
431 int eap_peer_unauth_tls_register(void)
433 struct eap_method
*eap
;
435 eap
= eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION
,
436 EAP_VENDOR_UNAUTH_TLS
,
437 EAP_VENDOR_TYPE_UNAUTH_TLS
, "UNAUTH-TLS");
441 eap
->init
= eap_unauth_tls_init
;
442 eap
->deinit
= eap_tls_deinit
;
443 eap
->process
= eap_tls_process
;
444 eap
->isKeyAvailable
= eap_tls_isKeyAvailable
;
445 eap
->getKey
= eap_tls_getKey
;
446 eap
->get_status
= eap_tls_get_status
;
447 eap
->has_reauth_data
= eap_tls_has_reauth_data
;
448 eap
->deinit_for_reauth
= eap_tls_deinit_for_reauth
;
449 eap
->init_for_reauth
= eap_tls_init_for_reauth
;
450 eap
->get_emsk
= eap_tls_get_emsk
;
452 return eap_peer_method_register(eap
);
454 #endif /* EAP_UNAUTH_TLS */
458 int eap_peer_wfa_unauth_tls_register(void)
460 struct eap_method
*eap
;
462 eap
= eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION
,
464 EAP_VENDOR_WFA_UNAUTH_TLS
,
469 eap
->init
= eap_wfa_unauth_tls_init
;
470 eap
->deinit
= eap_tls_deinit
;
471 eap
->process
= eap_tls_process
;
472 eap
->isKeyAvailable
= eap_tls_isKeyAvailable
;
473 eap
->getKey
= eap_tls_getKey
;
474 eap
->get_status
= eap_tls_get_status
;
475 eap
->has_reauth_data
= eap_tls_has_reauth_data
;
476 eap
->deinit_for_reauth
= eap_tls_deinit_for_reauth
;
477 eap
->init_for_reauth
= eap_tls_init_for_reauth
;
478 eap
->get_emsk
= eap_tls_get_emsk
;
480 return eap_peer_method_register(eap
);
482 #endif /* CONFIG_HS20 */