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
= "client EAP encryption KM";
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
,
203 if (data
->key_data
) {
204 wpa_hexdump_key(MSG_DEBUG
, "EAP-TLS: Derived key",
205 data
->key_data
, EAP_TLS_KEY_LEN
);
206 wpa_hexdump_key(MSG_DEBUG
, "EAP-TLS: Derived EMSK",
207 data
->key_data
+ EAP_TLS_KEY_LEN
,
210 wpa_printf(MSG_INFO
, "EAP-TLS: Failed to derive key");
213 os_free(data
->session_id
);
214 data
->session_id
= eap_peer_tls_derive_session_id(sm
, &data
->ssl
,
217 if (data
->session_id
) {
218 wpa_hexdump(MSG_DEBUG
, "EAP-TLS: Derived Session-Id",
219 data
->session_id
, data
->id_len
);
221 wpa_printf(MSG_ERROR
, "EAP-TLS: Failed to derive Session-Id");
226 static struct wpabuf
* eap_tls_process(struct eap_sm
*sm
, void *priv
,
227 struct eap_method_ret
*ret
,
228 const struct wpabuf
*reqData
)
235 struct eap_tls_data
*data
= priv
;
238 if (sm
->waiting_ext_cert_check
&& data
->pending_resp
) {
239 struct eap_peer_config
*config
= eap_get_config(sm
);
241 if (config
->pending_ext_cert_check
== EXT_CERT_CHECK_GOOD
) {
242 wpa_printf(MSG_DEBUG
,
243 "EAP-TLS: External certificate check succeeded - continue handshake");
244 resp
= data
->pending_resp
;
245 data
->pending_resp
= NULL
;
246 sm
->waiting_ext_cert_check
= 0;
250 if (config
->pending_ext_cert_check
== EXT_CERT_CHECK_BAD
) {
251 wpa_printf(MSG_DEBUG
,
252 "EAP-TLS: External certificate check failed - force authentication failure");
253 ret
->methodState
= METHOD_DONE
;
254 ret
->decision
= DECISION_FAIL
;
255 sm
->waiting_ext_cert_check
= 0;
259 wpa_printf(MSG_DEBUG
,
260 "EAP-TLS: Continuing to wait external server certificate validation");
264 pos
= eap_peer_tls_process_init(sm
, &data
->ssl
, data
->eap_type
, ret
,
265 reqData
, &left
, &flags
);
268 id
= eap_get_id(reqData
);
270 if (flags
& EAP_TLS_FLAGS_START
) {
271 wpa_printf(MSG_DEBUG
, "EAP-TLS: Start");
272 left
= 0; /* make sure that this frame is empty, even though it
273 * should always be, anyway */
277 wpabuf_set(&msg
, pos
, left
);
278 res
= eap_peer_tls_process_helper(sm
, &data
->ssl
, data
->eap_type
, 0,
282 return eap_tls_failure(sm
, data
, ret
, res
, resp
, id
);
285 if (sm
->waiting_ext_cert_check
) {
286 wpa_printf(MSG_DEBUG
,
287 "EAP-TLS: Waiting external server certificate validation");
288 wpabuf_free(data
->pending_resp
);
289 data
->pending_resp
= resp
;
293 if (tls_connection_established(data
->ssl_ctx
, data
->ssl
.conn
))
294 eap_tls_success(sm
, data
, ret
);
298 return eap_peer_tls_build_ack(id
, data
->eap_type
, 0);
305 static Boolean
eap_tls_has_reauth_data(struct eap_sm
*sm
, void *priv
)
307 struct eap_tls_data
*data
= priv
;
308 return tls_connection_established(data
->ssl_ctx
, data
->ssl
.conn
);
312 static void eap_tls_deinit_for_reauth(struct eap_sm
*sm
, void *priv
)
314 struct eap_tls_data
*data
= priv
;
316 wpabuf_free(data
->pending_resp
);
317 data
->pending_resp
= NULL
;
321 static void * eap_tls_init_for_reauth(struct eap_sm
*sm
, void *priv
)
323 struct eap_tls_data
*data
= priv
;
324 eap_tls_free_key(data
);
325 os_free(data
->session_id
);
326 data
->session_id
= NULL
;
327 if (eap_peer_tls_reauth_init(sm
, &data
->ssl
)) {
335 static int eap_tls_get_status(struct eap_sm
*sm
, void *priv
, char *buf
,
336 size_t buflen
, int verbose
)
338 struct eap_tls_data
*data
= priv
;
339 return eap_peer_tls_status(sm
, &data
->ssl
, buf
, buflen
, verbose
);
343 static Boolean
eap_tls_isKeyAvailable(struct eap_sm
*sm
, void *priv
)
345 struct eap_tls_data
*data
= priv
;
346 return data
->key_data
!= NULL
;
350 static u8
* eap_tls_getKey(struct eap_sm
*sm
, void *priv
, size_t *len
)
352 struct eap_tls_data
*data
= priv
;
355 if (data
->key_data
== NULL
)
358 key
= os_memdup(data
->key_data
, EAP_TLS_KEY_LEN
);
362 *len
= EAP_TLS_KEY_LEN
;
368 static u8
* eap_tls_get_emsk(struct eap_sm
*sm
, void *priv
, size_t *len
)
370 struct eap_tls_data
*data
= priv
;
373 if (data
->key_data
== NULL
)
376 key
= os_memdup(data
->key_data
+ EAP_TLS_KEY_LEN
, EAP_EMSK_LEN
);
386 static u8
* eap_tls_get_session_id(struct eap_sm
*sm
, void *priv
, size_t *len
)
388 struct eap_tls_data
*data
= priv
;
391 if (data
->session_id
== NULL
)
394 id
= os_memdup(data
->session_id
, data
->id_len
);
404 int eap_peer_tls_register(void)
406 struct eap_method
*eap
;
408 eap
= eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION
,
409 EAP_VENDOR_IETF
, EAP_TYPE_TLS
, "TLS");
413 eap
->init
= eap_tls_init
;
414 eap
->deinit
= eap_tls_deinit
;
415 eap
->process
= eap_tls_process
;
416 eap
->isKeyAvailable
= eap_tls_isKeyAvailable
;
417 eap
->getKey
= eap_tls_getKey
;
418 eap
->getSessionId
= eap_tls_get_session_id
;
419 eap
->get_status
= eap_tls_get_status
;
420 eap
->has_reauth_data
= eap_tls_has_reauth_data
;
421 eap
->deinit_for_reauth
= eap_tls_deinit_for_reauth
;
422 eap
->init_for_reauth
= eap_tls_init_for_reauth
;
423 eap
->get_emsk
= eap_tls_get_emsk
;
425 return eap_peer_method_register(eap
);
429 #ifdef EAP_UNAUTH_TLS
430 int eap_peer_unauth_tls_register(void)
432 struct eap_method
*eap
;
434 eap
= eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION
,
435 EAP_VENDOR_UNAUTH_TLS
,
436 EAP_VENDOR_TYPE_UNAUTH_TLS
, "UNAUTH-TLS");
440 eap
->init
= eap_unauth_tls_init
;
441 eap
->deinit
= eap_tls_deinit
;
442 eap
->process
= eap_tls_process
;
443 eap
->isKeyAvailable
= eap_tls_isKeyAvailable
;
444 eap
->getKey
= eap_tls_getKey
;
445 eap
->get_status
= eap_tls_get_status
;
446 eap
->has_reauth_data
= eap_tls_has_reauth_data
;
447 eap
->deinit_for_reauth
= eap_tls_deinit_for_reauth
;
448 eap
->init_for_reauth
= eap_tls_init_for_reauth
;
449 eap
->get_emsk
= eap_tls_get_emsk
;
451 return eap_peer_method_register(eap
);
453 #endif /* EAP_UNAUTH_TLS */
457 int eap_peer_wfa_unauth_tls_register(void)
459 struct eap_method
*eap
;
461 eap
= eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION
,
463 EAP_VENDOR_WFA_UNAUTH_TLS
,
468 eap
->init
= eap_wfa_unauth_tls_init
;
469 eap
->deinit
= eap_tls_deinit
;
470 eap
->process
= eap_tls_process
;
471 eap
->isKeyAvailable
= eap_tls_isKeyAvailable
;
472 eap
->getKey
= eap_tls_getKey
;
473 eap
->get_status
= eap_tls_get_status
;
474 eap
->has_reauth_data
= eap_tls_has_reauth_data
;
475 eap
->deinit_for_reauth
= eap_tls_deinit_for_reauth
;
476 eap
->init_for_reauth
= eap_tls_init_for_reauth
;
477 eap
->get_emsk
= eap_tls_get_emsk
;
479 return eap_peer_method_register(eap
);
481 #endif /* CONFIG_HS20 */