2 * SSL/TLS interface functions for GnuTLS
3 * Copyright (c) 2004-2011, Jouni Malinen <j@w1.fi>
5 * This software may be distributed under the terms of the BSD license.
6 * See README for more details.
10 #include <gnutls/gnutls.h>
11 #include <gnutls/x509.h>
13 #include <gnutls/pkcs12.h>
14 #endif /* PKCS12_FUNCS */
15 #if GNUTLS_VERSION_NUMBER >= 0x030103
16 #include <gnutls/ocsp.h>
20 #include "crypto/crypto.h"
24 static int tls_gnutls_ref_count = 0;
27 /* Data for session resumption */
29 size_t session_data_size;
34 gnutls_certificate_credentials_t xcred;
36 void (*event_cb)(void *ctx, enum tls_event ev,
37 union tls_event_data *data);
41 char *ocsp_stapling_response;
44 struct tls_connection {
45 struct tls_global *global;
46 gnutls_session_t session;
47 int read_alerts, write_alerts, failed;
49 u8 *pre_shared_secret;
50 size_t pre_shared_secret_len;
53 unsigned int disable_time_checks:1;
55 struct wpabuf *push_buf;
56 struct wpabuf *pull_buf;
57 const u8 *pull_buf_offset;
60 gnutls_certificate_credentials_t xcred;
68 static int tls_connection_verify_peer(gnutls_session_t session);
71 static void tls_log_func(int level, const char *msg)
74 if (level == 6 || level == 7) {
75 /* These levels seem to be mostly I/O debug and msg dumps */
84 while (*pos != '\0') {
91 wpa_printf(level > 3 ? MSG_MSGDUMP : MSG_DEBUG,
92 "gnutls<%d> %s", level, s);
97 void * tls_init(const struct tls_config *conf)
99 struct tls_global *global;
101 if (tls_gnutls_ref_count == 0) {
102 wpa_printf(MSG_DEBUG,
103 "GnuTLS: Library version %s (runtime) - %s (build)",
104 gnutls_check_version(NULL), GNUTLS_VERSION);
107 global = os_zalloc(sizeof(*global));
111 if (tls_gnutls_ref_count == 0 && gnutls_global_init() < 0) {
115 tls_gnutls_ref_count++;
117 gnutls_global_set_log_function(tls_log_func);
118 if (wpa_debug_show_keys)
119 gnutls_global_set_log_level(11);
122 global->event_cb = conf->event_cb;
123 global->cb_ctx = conf->cb_ctx;
124 global->cert_in_cb = conf->cert_in_cb;
131 void tls_deinit(void *ssl_ctx)
133 struct tls_global *global = ssl_ctx;
135 if (global->params_set)
136 gnutls_certificate_free_credentials(global->xcred);
137 os_free(global->session_data);
138 os_free(global->ocsp_stapling_response);
142 tls_gnutls_ref_count--;
143 if (tls_gnutls_ref_count == 0)
144 gnutls_global_deinit();
148 int tls_get_errors(void *ssl_ctx)
154 static ssize_t tls_pull_func(gnutls_transport_ptr_t ptr, void *buf,
157 struct tls_connection *conn = (struct tls_connection *) ptr;
159 if (conn->pull_buf == NULL) {
164 end = wpabuf_head_u8(conn->pull_buf) + wpabuf_len(conn->pull_buf);
165 if ((size_t) (end - conn->pull_buf_offset) < len)
166 len = end - conn->pull_buf_offset;
167 os_memcpy(buf, conn->pull_buf_offset, len);
168 conn->pull_buf_offset += len;
169 if (conn->pull_buf_offset == end) {
170 wpa_printf(MSG_DEBUG, "%s - pull_buf consumed", __func__);
171 wpabuf_free(conn->pull_buf);
172 conn->pull_buf = NULL;
173 conn->pull_buf_offset = NULL;
175 wpa_printf(MSG_DEBUG, "%s - %lu bytes remaining in pull_buf",
177 (unsigned long) (end - conn->pull_buf_offset));
183 static ssize_t tls_push_func(gnutls_transport_ptr_t ptr, const void *buf,
186 struct tls_connection *conn = (struct tls_connection *) ptr;
188 if (wpabuf_resize(&conn->push_buf, len) < 0) {
192 wpabuf_put_data(conn->push_buf, buf, len);
198 static int tls_gnutls_init_session(struct tls_global *global,
199 struct tls_connection *conn)
204 ret = gnutls_init(&conn->session,
205 global->server ? GNUTLS_SERVER : GNUTLS_CLIENT);
207 wpa_printf(MSG_INFO, "TLS: Failed to initialize new TLS "
208 "connection: %s", gnutls_strerror(ret));
212 ret = gnutls_set_default_priority(conn->session);
216 ret = gnutls_priority_set_direct(conn->session, "NORMAL:-VERS-SSL3.0",
219 wpa_printf(MSG_ERROR, "GnuTLS: Priority string failure at "
224 gnutls_transport_set_pull_function(conn->session, tls_pull_func);
225 gnutls_transport_set_push_function(conn->session, tls_push_func);
226 gnutls_transport_set_ptr(conn->session, (gnutls_transport_ptr_t) conn);
227 gnutls_session_set_ptr(conn->session, conn);
232 wpa_printf(MSG_INFO, "TLS: Failed to setup new TLS connection: %s",
233 gnutls_strerror(ret));
234 gnutls_deinit(conn->session);
239 struct tls_connection * tls_connection_init(void *ssl_ctx)
241 struct tls_global *global = ssl_ctx;
242 struct tls_connection *conn;
245 conn = os_zalloc(sizeof(*conn));
248 conn->global = global;
250 if (tls_gnutls_init_session(global, conn)) {
255 if (global->params_set) {
256 ret = gnutls_credentials_set(conn->session,
257 GNUTLS_CRD_CERTIFICATE,
260 wpa_printf(MSG_INFO, "Failed to configure "
261 "credentials: %s", gnutls_strerror(ret));
267 if (gnutls_certificate_allocate_credentials(&conn->xcred)) {
276 void tls_connection_deinit(void *ssl_ctx, struct tls_connection *conn)
281 gnutls_certificate_free_credentials(conn->xcred);
282 gnutls_deinit(conn->session);
283 os_free(conn->pre_shared_secret);
284 wpabuf_free(conn->push_buf);
285 wpabuf_free(conn->pull_buf);
286 os_free(conn->suffix_match);
287 os_free(conn->domain_match);
292 int tls_connection_established(void *ssl_ctx, struct tls_connection *conn)
294 return conn ? conn->established : 0;
298 int tls_connection_shutdown(void *ssl_ctx, struct tls_connection *conn)
300 struct tls_global *global = ssl_ctx;
306 /* Shutdown previous TLS connection without notifying the peer
307 * because the connection was already terminated in practice
308 * and "close notify" shutdown alert would confuse AS. */
309 gnutls_bye(conn->session, GNUTLS_SHUT_RDWR);
310 wpabuf_free(conn->push_buf);
311 conn->push_buf = NULL;
312 conn->established = 0;
314 gnutls_deinit(conn->session);
315 if (tls_gnutls_init_session(global, conn)) {
316 wpa_printf(MSG_INFO, "GnuTLS: Failed to preparare new session "
317 "for session resumption use");
321 ret = gnutls_credentials_set(conn->session, GNUTLS_CRD_CERTIFICATE,
322 conn->params_set ? conn->xcred :
325 wpa_printf(MSG_INFO, "GnuTLS: Failed to configure credentials "
326 "for session resumption: %s", gnutls_strerror(ret));
330 if (global->session_data) {
331 ret = gnutls_session_set_data(conn->session,
332 global->session_data,
333 global->session_data_size);
335 wpa_printf(MSG_INFO, "GnuTLS: Failed to set session "
336 "data: %s", gnutls_strerror(ret));
345 int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
346 const struct tls_connection_params *params)
350 if (conn == NULL || params == NULL)
353 if (params->flags & TLS_CONN_REQUIRE_OCSP_ALL) {
355 "GnuTLS: ocsp=3 not supported");
359 if (params->flags & TLS_CONN_EXT_CERT_CHECK) {
361 "GnuTLS: tls_ext_cert_check=1 not supported");
365 if (params->subject_match) {
366 wpa_printf(MSG_INFO, "GnuTLS: subject_match not supported");
370 if (params->altsubject_match) {
371 wpa_printf(MSG_INFO, "GnuTLS: altsubject_match not supported");
375 os_free(conn->suffix_match);
376 conn->suffix_match = NULL;
377 if (params->suffix_match) {
378 conn->suffix_match = os_strdup(params->suffix_match);
379 if (conn->suffix_match == NULL)
383 #if GNUTLS_VERSION_NUMBER >= 0x030300
384 os_free(conn->domain_match);
385 conn->domain_match = NULL;
386 if (params->domain_match) {
387 conn->domain_match = os_strdup(params->domain_match);
388 if (conn->domain_match == NULL)
392 if (params->domain_match) {
393 wpa_printf(MSG_INFO, "GnuTLS: domain_match not supported");
396 #endif /* >= 3.3.0 */
398 conn->flags = params->flags;
400 if (params->openssl_ciphers) {
401 wpa_printf(MSG_INFO, "GnuTLS: openssl_ciphers not supported");
405 /* TODO: gnutls_certificate_set_verify_flags(xcred, flags);
406 * to force peer validation(?) */
408 if (params->ca_cert) {
409 wpa_printf(MSG_DEBUG, "GnuTLS: Try to parse %s in DER format",
411 ret = gnutls_certificate_set_x509_trust_file(
412 conn->xcred, params->ca_cert, GNUTLS_X509_FMT_DER);
414 wpa_printf(MSG_DEBUG,
415 "GnuTLS: Failed to read CA cert '%s' in DER format (%s) - try in PEM format",
417 gnutls_strerror(ret));
418 ret = gnutls_certificate_set_x509_trust_file(
419 conn->xcred, params->ca_cert,
420 GNUTLS_X509_FMT_PEM);
422 wpa_printf(MSG_DEBUG,
423 "Failed to read CA cert '%s' in PEM format: %s",
425 gnutls_strerror(ret));
429 } else if (params->ca_cert_blob) {
432 ca.data = (unsigned char *) params->ca_cert_blob;
433 ca.size = params->ca_cert_blob_len;
435 ret = gnutls_certificate_set_x509_trust_mem(
436 conn->xcred, &ca, GNUTLS_X509_FMT_DER);
438 wpa_printf(MSG_DEBUG,
439 "Failed to parse CA cert in DER format: %s",
440 gnutls_strerror(ret));
441 ret = gnutls_certificate_set_x509_trust_mem(
442 conn->xcred, &ca, GNUTLS_X509_FMT_PEM);
444 wpa_printf(MSG_DEBUG,
445 "Failed to parse CA cert in PEM format: %s",
446 gnutls_strerror(ret));
450 } else if (params->ca_path) {
451 wpa_printf(MSG_INFO, "GnuTLS: ca_path not supported");
455 conn->disable_time_checks = 0;
456 if (params->ca_cert || params->ca_cert_blob) {
457 conn->verify_peer = 1;
458 gnutls_certificate_set_verify_function(
459 conn->xcred, tls_connection_verify_peer);
461 if (params->flags & TLS_CONN_ALLOW_SIGN_RSA_MD5) {
462 gnutls_certificate_set_verify_flags(
463 conn->xcred, GNUTLS_VERIFY_ALLOW_SIGN_RSA_MD5);
466 if (params->flags & TLS_CONN_DISABLE_TIME_CHECKS) {
467 conn->disable_time_checks = 1;
468 gnutls_certificate_set_verify_flags(
470 GNUTLS_VERIFY_DISABLE_TIME_CHECKS);
474 if (params->client_cert && params->private_key) {
475 #if GNUTLS_VERSION_NUMBER >= 0x03010b
476 ret = gnutls_certificate_set_x509_key_file2(
477 conn->xcred, params->client_cert, params->private_key,
478 GNUTLS_X509_FMT_DER, params->private_key_passwd, 0);
480 /* private_key_passwd not (easily) supported here */
481 ret = gnutls_certificate_set_x509_key_file(
482 conn->xcred, params->client_cert, params->private_key,
483 GNUTLS_X509_FMT_DER);
486 wpa_printf(MSG_DEBUG, "Failed to read client cert/key "
487 "in DER format: %s", gnutls_strerror(ret));
488 #if GNUTLS_VERSION_NUMBER >= 0x03010b
489 ret = gnutls_certificate_set_x509_key_file2(
490 conn->xcred, params->client_cert,
491 params->private_key, GNUTLS_X509_FMT_PEM,
492 params->private_key_passwd, 0);
494 ret = gnutls_certificate_set_x509_key_file(
495 conn->xcred, params->client_cert,
496 params->private_key, GNUTLS_X509_FMT_PEM);
499 wpa_printf(MSG_DEBUG, "Failed to read client "
500 "cert/key in PEM format: %s",
501 gnutls_strerror(ret));
505 } else if (params->private_key) {
508 /* Try to load in PKCS#12 format */
509 ret = gnutls_certificate_set_x509_simple_pkcs12_file(
510 conn->xcred, params->private_key, GNUTLS_X509_FMT_DER,
511 params->private_key_passwd);
513 wpa_printf(MSG_DEBUG, "Failed to load private_key in "
514 "PKCS#12 format: %s", gnutls_strerror(ret));
518 #endif /* PKCS12_FUNCS */
521 wpa_printf(MSG_DEBUG, "GnuTLS: PKCS#12 support not "
525 } else if (params->client_cert_blob && params->private_key_blob) {
526 gnutls_datum_t cert, key;
528 cert.data = (unsigned char *) params->client_cert_blob;
529 cert.size = params->client_cert_blob_len;
530 key.data = (unsigned char *) params->private_key_blob;
531 key.size = params->private_key_blob_len;
533 #if GNUTLS_VERSION_NUMBER >= 0x03010b
534 ret = gnutls_certificate_set_x509_key_mem2(
535 conn->xcred, &cert, &key, GNUTLS_X509_FMT_DER,
536 params->private_key_passwd, 0);
538 /* private_key_passwd not (easily) supported here */
539 ret = gnutls_certificate_set_x509_key_mem(
540 conn->xcred, &cert, &key, GNUTLS_X509_FMT_DER);
543 wpa_printf(MSG_DEBUG, "Failed to read client cert/key "
544 "in DER format: %s", gnutls_strerror(ret));
545 #if GNUTLS_VERSION_NUMBER >= 0x03010b
546 ret = gnutls_certificate_set_x509_key_mem2(
547 conn->xcred, &cert, &key, GNUTLS_X509_FMT_PEM,
548 params->private_key_passwd, 0);
550 /* private_key_passwd not (easily) supported here */
551 ret = gnutls_certificate_set_x509_key_mem(
552 conn->xcred, &cert, &key, GNUTLS_X509_FMT_PEM);
555 wpa_printf(MSG_DEBUG, "Failed to read client "
556 "cert/key in PEM format: %s",
557 gnutls_strerror(ret));
561 } else if (params->private_key_blob) {
565 key.data = (unsigned char *) params->private_key_blob;
566 key.size = params->private_key_blob_len;
568 /* Try to load in PKCS#12 format */
569 ret = gnutls_certificate_set_x509_simple_pkcs12_mem(
570 conn->xcred, &key, GNUTLS_X509_FMT_DER,
571 params->private_key_passwd);
573 wpa_printf(MSG_DEBUG, "Failed to load private_key in "
574 "PKCS#12 format: %s", gnutls_strerror(ret));
577 #else /* PKCS12_FUNCS */
578 wpa_printf(MSG_DEBUG, "GnuTLS: PKCS#12 support not included");
580 #endif /* PKCS12_FUNCS */
583 #if GNUTLS_VERSION_NUMBER >= 0x030103
584 if (params->flags & (TLS_CONN_REQUEST_OCSP | TLS_CONN_REQUIRE_OCSP)) {
585 ret = gnutls_ocsp_status_request_enable_client(conn->session,
587 if (ret != GNUTLS_E_SUCCESS) {
589 "GnuTLS: Failed to enable OCSP client");
594 if (params->flags & TLS_CONN_REQUIRE_OCSP) {
596 "GnuTLS: OCSP not supported by this version of GnuTLS");
601 conn->params_set = 1;
603 ret = gnutls_credentials_set(conn->session, GNUTLS_CRD_CERTIFICATE,
606 wpa_printf(MSG_INFO, "Failed to configure credentials: %s",
607 gnutls_strerror(ret));
614 #if GNUTLS_VERSION_NUMBER >= 0x030103
615 static int server_ocsp_status_req(gnutls_session_t session, void *ptr,
616 gnutls_datum_t *resp)
618 struct tls_global *global = ptr;
622 if (!global->ocsp_stapling_response) {
623 wpa_printf(MSG_DEBUG, "GnuTLS: OCSP status callback - no response configured");
624 return GNUTLS_E_NO_CERTIFICATE_STATUS;
627 cached = os_readfile(global->ocsp_stapling_response, &len);
629 wpa_printf(MSG_DEBUG,
630 "GnuTLS: OCSP status callback - could not read response file (%s)",
631 global->ocsp_stapling_response);
632 return GNUTLS_E_NO_CERTIFICATE_STATUS;
635 wpa_printf(MSG_DEBUG,
636 "GnuTLS: OCSP status callback - send cached response");
637 resp->data = gnutls_malloc(len);
640 return GNUTLS_E_MEMORY_ERROR;
643 os_memcpy(resp->data, cached, len);
647 return GNUTLS_E_SUCCESS;
652 int tls_global_set_params(void *tls_ctx,
653 const struct tls_connection_params *params)
655 struct tls_global *global = tls_ctx;
658 /* Currently, global parameters are only set when running in server
662 if (global->params_set) {
663 gnutls_certificate_free_credentials(global->xcred);
664 global->params_set = 0;
667 ret = gnutls_certificate_allocate_credentials(&global->xcred);
669 wpa_printf(MSG_DEBUG, "Failed to allocate global credentials "
670 "%s", gnutls_strerror(ret));
674 if (params->ca_cert) {
675 ret = gnutls_certificate_set_x509_trust_file(
676 global->xcred, params->ca_cert, GNUTLS_X509_FMT_DER);
678 wpa_printf(MSG_DEBUG, "Failed to read CA cert '%s' "
679 "in DER format: %s", params->ca_cert,
680 gnutls_strerror(ret));
681 ret = gnutls_certificate_set_x509_trust_file(
682 global->xcred, params->ca_cert,
683 GNUTLS_X509_FMT_PEM);
685 wpa_printf(MSG_DEBUG, "Failed to read CA cert "
686 "'%s' in PEM format: %s",
688 gnutls_strerror(ret));
693 if (params->flags & TLS_CONN_ALLOW_SIGN_RSA_MD5) {
694 gnutls_certificate_set_verify_flags(
696 GNUTLS_VERIFY_ALLOW_SIGN_RSA_MD5);
699 if (params->flags & TLS_CONN_DISABLE_TIME_CHECKS) {
700 gnutls_certificate_set_verify_flags(
702 GNUTLS_VERIFY_DISABLE_TIME_CHECKS);
706 if (params->client_cert && params->private_key) {
707 /* TODO: private_key_passwd? */
708 ret = gnutls_certificate_set_x509_key_file(
709 global->xcred, params->client_cert,
710 params->private_key, GNUTLS_X509_FMT_DER);
712 wpa_printf(MSG_DEBUG, "Failed to read client cert/key "
713 "in DER format: %s", gnutls_strerror(ret));
714 ret = gnutls_certificate_set_x509_key_file(
715 global->xcred, params->client_cert,
716 params->private_key, GNUTLS_X509_FMT_PEM);
718 wpa_printf(MSG_DEBUG, "Failed to read client "
719 "cert/key in PEM format: %s",
720 gnutls_strerror(ret));
724 } else if (params->private_key) {
727 /* Try to load in PKCS#12 format */
728 ret = gnutls_certificate_set_x509_simple_pkcs12_file(
729 global->xcred, params->private_key,
730 GNUTLS_X509_FMT_DER, params->private_key_passwd);
732 wpa_printf(MSG_DEBUG, "Failed to load private_key in "
733 "PKCS#12 format: %s", gnutls_strerror(ret));
737 #endif /* PKCS12_FUNCS */
740 wpa_printf(MSG_DEBUG, "GnuTLS: PKCS#12 support not "
746 #if GNUTLS_VERSION_NUMBER >= 0x030103
747 os_free(global->ocsp_stapling_response);
748 if (params->ocsp_stapling_response)
749 global->ocsp_stapling_response =
750 os_strdup(params->ocsp_stapling_response);
752 global->ocsp_stapling_response = NULL;
753 gnutls_certificate_set_ocsp_status_request_function(
754 global->xcred, server_ocsp_status_req, global);
757 global->params_set = 1;
762 gnutls_certificate_free_credentials(global->xcred);
767 int tls_global_set_verify(void *ssl_ctx, int check_crl)
774 int tls_connection_set_verify(void *ssl_ctx, struct tls_connection *conn,
775 int verify_peer, unsigned int flags,
776 const u8 *session_ctx, size_t session_ctx_len)
778 if (conn == NULL || conn->session == NULL)
781 conn->verify_peer = verify_peer;
782 gnutls_certificate_server_set_request(conn->session,
783 verify_peer ? GNUTLS_CERT_REQUIRE
784 : GNUTLS_CERT_REQUEST);
790 int tls_connection_get_random(void *ssl_ctx, struct tls_connection *conn,
791 struct tls_random *keys)
793 #if GNUTLS_VERSION_NUMBER >= 0x030012
794 gnutls_datum_t client, server;
796 if (conn == NULL || conn->session == NULL || keys == NULL)
799 os_memset(keys, 0, sizeof(*keys));
800 gnutls_session_get_random(conn->session, &client, &server);
801 keys->client_random = client.data;
802 keys->server_random = server.data;
803 keys->client_random_len = client.size;
804 keys->server_random_len = client.size;
813 int tls_connection_export_key(void *tls_ctx, struct tls_connection *conn,
814 const char *label, u8 *out, size_t out_len)
816 if (conn == NULL || conn->session == NULL)
819 return gnutls_prf(conn->session, os_strlen(label), label,
820 0 /* client_random first */, 0, NULL, out_len,
825 int tls_connection_get_eap_fast_key(void *tls_ctx, struct tls_connection *conn,
826 u8 *out, size_t out_len)
832 static void gnutls_tls_fail_event(struct tls_connection *conn,
833 const gnutls_datum_t *cert, int depth,
834 const char *subject, const char *err_str,
835 enum tls_fail_reason reason)
837 union tls_event_data ev;
838 struct tls_global *global = conn->global;
839 struct wpabuf *cert_buf = NULL;
841 if (global->event_cb == NULL)
844 os_memset(&ev, 0, sizeof(ev));
845 ev.cert_fail.depth = depth;
846 ev.cert_fail.subject = subject ? subject : "";
847 ev.cert_fail.reason = reason;
848 ev.cert_fail.reason_txt = err_str;
850 cert_buf = wpabuf_alloc_copy(cert->data, cert->size);
851 ev.cert_fail.cert = cert_buf;
853 global->event_cb(global->cb_ctx, TLS_CERT_CHAIN_FAILURE, &ev);
854 wpabuf_free(cert_buf);
858 #if GNUTLS_VERSION_NUMBER < 0x030300
859 static int server_eku_purpose(gnutls_x509_crt_t cert)
865 size_t oid_size = sizeof(oid);
868 res = gnutls_x509_crt_get_key_purpose_oid(cert, i, oid,
870 if (res == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) {
872 /* No EKU - assume any use allowed */
879 wpa_printf(MSG_INFO, "GnuTLS: Failed to get EKU");
883 wpa_printf(MSG_DEBUG, "GnuTLS: Certificate purpose: %s", oid);
884 if (os_strcmp(oid, GNUTLS_KP_TLS_WWW_SERVER) == 0 ||
885 os_strcmp(oid, GNUTLS_KP_ANY) == 0)
894 static int check_ocsp(struct tls_connection *conn, gnutls_session_t session,
895 gnutls_alert_description_t *err)
897 #if GNUTLS_VERSION_NUMBER >= 0x030103
898 gnutls_datum_t response, buf;
899 gnutls_ocsp_resp_t resp;
900 unsigned int cert_status;
903 if (!(conn->flags & (TLS_CONN_REQUEST_OCSP | TLS_CONN_REQUIRE_OCSP)))
906 if (!gnutls_ocsp_status_request_is_checked(session, 0)) {
907 if (conn->flags & TLS_CONN_REQUIRE_OCSP) {
909 "GnuTLS: No valid OCSP response received");
913 wpa_printf(MSG_DEBUG,
914 "GnuTLS: Valid OCSP response was not received - continue since OCSP was not required");
919 * GnuTLS has already verified the OCSP response in
920 * check_ocsp_response() and rejected handshake if the certificate was
921 * found to be revoked. However, if the response indicates that the
922 * status is unknown, handshake continues and reaches here. We need to
923 * re-import the OCSP response to check for unknown certificate status,
924 * but we do not need to repeat gnutls_ocsp_resp_check_crt() and
925 * gnutls_ocsp_resp_verify_direct() calls.
928 res = gnutls_ocsp_status_request_get(session, &response);
929 if (res != GNUTLS_E_SUCCESS) {
931 "GnuTLS: OCSP response was received, but it was not valid");
935 if (gnutls_ocsp_resp_init(&resp) != GNUTLS_E_SUCCESS)
938 res = gnutls_ocsp_resp_import(resp, &response);
939 if (res != GNUTLS_E_SUCCESS) {
941 "GnuTLS: Could not parse received OCSP response: %s",
942 gnutls_strerror(res));
943 gnutls_ocsp_resp_deinit(resp);
947 res = gnutls_ocsp_resp_print(resp, GNUTLS_OCSP_PRINT_FULL, &buf);
948 if (res == GNUTLS_E_SUCCESS) {
949 wpa_printf(MSG_DEBUG, "GnuTLS: %s", buf.data);
950 gnutls_free(buf.data);
953 res = gnutls_ocsp_resp_get_single(resp, 0, NULL, NULL, NULL,
954 NULL, &cert_status, NULL,
956 gnutls_ocsp_resp_deinit(resp);
957 if (res != GNUTLS_E_SUCCESS) {
959 "GnuTLS: Failed to extract OCSP information: %s",
960 gnutls_strerror(res));
964 if (cert_status == GNUTLS_OCSP_CERT_GOOD) {
965 wpa_printf(MSG_DEBUG, "GnuTLS: OCSP cert status: good");
966 } else if (cert_status == GNUTLS_OCSP_CERT_REVOKED) {
967 wpa_printf(MSG_DEBUG,
968 "GnuTLS: OCSP cert status: revoked");
971 wpa_printf(MSG_DEBUG,
972 "GnuTLS: OCSP cert status: unknown");
973 if (conn->flags & TLS_CONN_REQUIRE_OCSP)
975 wpa_printf(MSG_DEBUG,
976 "GnuTLS: OCSP was not required, so allow connection to continue");
982 gnutls_tls_fail_event(conn, NULL, 0, NULL,
983 "bad certificate status response",
985 *err = GNUTLS_A_CERTIFICATE_REVOKED;
987 #else /* GnuTLS 3.1.3 or newer */
989 #endif /* GnuTLS 3.1.3 or newer */
993 static int tls_connection_verify_peer(gnutls_session_t session)
995 struct tls_connection *conn;
996 unsigned int status, num_certs, i;
998 const gnutls_datum_t *certs;
999 gnutls_x509_crt_t cert;
1000 gnutls_alert_description_t err;
1003 conn = gnutls_session_get_ptr(session);
1004 if (!conn->verify_peer) {
1005 wpa_printf(MSG_DEBUG,
1006 "GnuTLS: No peer certificate verification enabled");
1010 wpa_printf(MSG_DEBUG, "GnuTSL: Verifying peer certificate");
1012 #if GNUTLS_VERSION_NUMBER >= 0x030300
1014 gnutls_typed_vdata_st data[1];
1015 unsigned int elements = 0;
1017 os_memset(data, 0, sizeof(data));
1018 if (!conn->global->server) {
1019 data[elements].type = GNUTLS_DT_KEY_PURPOSE_OID;
1020 data[elements].data = (void *) GNUTLS_KP_TLS_WWW_SERVER;
1023 res = gnutls_certificate_verify_peers(session, data, 1,
1027 res = gnutls_certificate_verify_peers2(session, &status);
1030 wpa_printf(MSG_INFO, "TLS: Failed to verify peer "
1031 "certificate chain");
1032 err = GNUTLS_A_INTERNAL_ERROR;
1036 #if GNUTLS_VERSION_NUMBER >= 0x030104
1038 gnutls_datum_t info;
1041 type = gnutls_certificate_type_get(session);
1042 ret = gnutls_certificate_verification_status_print(status, type,
1045 wpa_printf(MSG_DEBUG,
1046 "GnuTLS: Failed to print verification status");
1047 err = GNUTLS_A_INTERNAL_ERROR;
1050 wpa_printf(MSG_DEBUG, "GnuTLS: %s", info.data);
1051 gnutls_free(info.data);
1053 #endif /* GnuTLS 3.1.4 or newer */
1055 certs = gnutls_certificate_get_peers(session, &num_certs);
1056 if (certs == NULL || num_certs == 0) {
1057 wpa_printf(MSG_INFO, "TLS: No peer certificate chain received");
1058 err = GNUTLS_A_UNKNOWN_CA;
1062 if (conn->verify_peer && (status & GNUTLS_CERT_INVALID)) {
1063 wpa_printf(MSG_INFO, "TLS: Peer certificate not trusted");
1064 if (status & GNUTLS_CERT_INSECURE_ALGORITHM) {
1065 wpa_printf(MSG_INFO, "TLS: Certificate uses insecure "
1067 gnutls_tls_fail_event(conn, NULL, 0, NULL,
1068 "certificate uses insecure algorithm",
1069 TLS_FAIL_BAD_CERTIFICATE);
1070 err = GNUTLS_A_INSUFFICIENT_SECURITY;
1073 if (status & GNUTLS_CERT_NOT_ACTIVATED) {
1074 wpa_printf(MSG_INFO, "TLS: Certificate not yet "
1076 gnutls_tls_fail_event(conn, NULL, 0, NULL,
1077 "certificate not yet valid",
1078 TLS_FAIL_NOT_YET_VALID);
1079 err = GNUTLS_A_CERTIFICATE_EXPIRED;
1082 if (status & GNUTLS_CERT_EXPIRED) {
1083 wpa_printf(MSG_INFO, "TLS: Certificate expired");
1084 gnutls_tls_fail_event(conn, NULL, 0, NULL,
1085 "certificate has expired",
1087 err = GNUTLS_A_CERTIFICATE_EXPIRED;
1090 gnutls_tls_fail_event(conn, NULL, 0, NULL,
1091 "untrusted certificate",
1092 TLS_FAIL_UNTRUSTED);
1093 err = GNUTLS_A_INTERNAL_ERROR;
1097 if (status & GNUTLS_CERT_SIGNER_NOT_FOUND) {
1098 wpa_printf(MSG_INFO, "TLS: Peer certificate does not have a "
1100 gnutls_tls_fail_event(conn, NULL, 0, NULL, "signed not found",
1101 TLS_FAIL_UNTRUSTED);
1102 err = GNUTLS_A_UNKNOWN_CA;
1106 if (status & GNUTLS_CERT_REVOKED) {
1107 wpa_printf(MSG_INFO, "TLS: Peer certificate has been revoked");
1108 gnutls_tls_fail_event(conn, NULL, 0, NULL,
1109 "certificate revoked",
1111 err = GNUTLS_A_CERTIFICATE_REVOKED;
1116 wpa_printf(MSG_INFO, "TLS: Unknown verification status: %d",
1118 err = GNUTLS_A_INTERNAL_ERROR;
1122 if (check_ocsp(conn, session, &err))
1127 for (i = 0; i < num_certs; i++) {
1130 if (gnutls_x509_crt_init(&cert) < 0) {
1131 wpa_printf(MSG_INFO, "TLS: Certificate initialization "
1133 err = GNUTLS_A_BAD_CERTIFICATE;
1137 if (gnutls_x509_crt_import(cert, &certs[i],
1138 GNUTLS_X509_FMT_DER) < 0) {
1139 wpa_printf(MSG_INFO, "TLS: Could not parse peer "
1140 "certificate %d/%d", i + 1, num_certs);
1141 gnutls_x509_crt_deinit(cert);
1142 err = GNUTLS_A_BAD_CERTIFICATE;
1146 gnutls_x509_crt_get_dn(cert, NULL, &len);
1148 buf = os_malloc(len + 1);
1150 buf[0] = buf[len] = '\0';
1151 gnutls_x509_crt_get_dn(cert, buf, &len);
1153 wpa_printf(MSG_DEBUG, "TLS: Peer cert chain %d/%d: %s",
1154 i + 1, num_certs, buf);
1156 if (conn->global->event_cb) {
1157 struct wpabuf *cert_buf = NULL;
1158 union tls_event_data ev;
1159 #ifdef CONFIG_SHA256
1163 #endif /* CONFIG_SHA256 */
1165 os_memset(&ev, 0, sizeof(ev));
1166 if (conn->global->cert_in_cb) {
1167 cert_buf = wpabuf_alloc_copy(certs[i].data,
1169 ev.peer_cert.cert = cert_buf;
1171 #ifdef CONFIG_SHA256
1172 _addr[0] = certs[i].data;
1173 _len[0] = certs[i].size;
1174 if (sha256_vector(1, _addr, _len, hash) == 0) {
1175 ev.peer_cert.hash = hash;
1176 ev.peer_cert.hash_len = sizeof(hash);
1178 #endif /* CONFIG_SHA256 */
1179 ev.peer_cert.depth = i;
1180 ev.peer_cert.subject = buf;
1181 conn->global->event_cb(conn->global->cb_ctx,
1182 TLS_PEER_CERTIFICATE, &ev);
1183 wpabuf_free(cert_buf);
1187 if (conn->suffix_match &&
1188 !gnutls_x509_crt_check_hostname(
1189 cert, conn->suffix_match)) {
1190 wpa_printf(MSG_WARNING,
1191 "TLS: Domain suffix match '%s' not found",
1192 conn->suffix_match);
1193 gnutls_tls_fail_event(
1194 conn, &certs[i], i, buf,
1195 "Domain suffix mismatch",
1196 TLS_FAIL_DOMAIN_SUFFIX_MISMATCH);
1197 err = GNUTLS_A_BAD_CERTIFICATE;
1198 gnutls_x509_crt_deinit(cert);
1203 #if GNUTLS_VERSION_NUMBER >= 0x030300
1204 if (conn->domain_match &&
1205 !gnutls_x509_crt_check_hostname2(
1206 cert, conn->domain_match,
1207 GNUTLS_VERIFY_DO_NOT_ALLOW_WILDCARDS)) {
1208 wpa_printf(MSG_WARNING,
1209 "TLS: Domain match '%s' not found",
1210 conn->domain_match);
1211 gnutls_tls_fail_event(
1212 conn, &certs[i], i, buf,
1214 TLS_FAIL_DOMAIN_MISMATCH);
1215 err = GNUTLS_A_BAD_CERTIFICATE;
1216 gnutls_x509_crt_deinit(cert);
1220 #endif /* >= 3.3.0 */
1222 /* TODO: validate altsubject_match.
1223 * For now, any such configuration is rejected in
1224 * tls_connection_set_params() */
1226 #if GNUTLS_VERSION_NUMBER < 0x030300
1228 * gnutls_certificate_verify_peers() not available, so
1229 * need to check EKU separately.
1231 if (!conn->global->server &&
1232 !server_eku_purpose(cert)) {
1233 wpa_printf(MSG_WARNING,
1234 "GnuTLS: No server EKU");
1235 gnutls_tls_fail_event(
1236 conn, &certs[i], i, buf,
1238 TLS_FAIL_BAD_CERTIFICATE);
1239 err = GNUTLS_A_BAD_CERTIFICATE;
1240 gnutls_x509_crt_deinit(cert);
1244 #endif /* < 3.3.0 */
1247 if (!conn->disable_time_checks &&
1248 (gnutls_x509_crt_get_expiration_time(cert) < now.sec ||
1249 gnutls_x509_crt_get_activation_time(cert) > now.sec)) {
1250 wpa_printf(MSG_INFO, "TLS: Peer certificate %d/%d is "
1251 "not valid at this time",
1253 gnutls_tls_fail_event(
1254 conn, &certs[i], i, buf,
1255 "Certificate is not valid at this time",
1257 gnutls_x509_crt_deinit(cert);
1259 err = GNUTLS_A_CERTIFICATE_EXPIRED;
1265 gnutls_x509_crt_deinit(cert);
1268 if (conn->global->event_cb != NULL)
1269 conn->global->event_cb(conn->global->cb_ctx,
1270 TLS_CERT_CHAIN_SUCCESS, NULL);
1276 gnutls_alert_send(session, GNUTLS_AL_FATAL, err);
1277 return GNUTLS_E_CERTIFICATE_ERROR;
1281 static struct wpabuf * gnutls_get_appl_data(struct tls_connection *conn)
1285 wpa_printf(MSG_DEBUG, "GnuTLS: Check for possible Application Data");
1286 ad = wpabuf_alloc((wpabuf_len(conn->pull_buf) + 500) * 3);
1290 res = gnutls_record_recv(conn->session, wpabuf_mhead(ad),
1292 wpa_printf(MSG_DEBUG, "GnuTLS: gnutls_record_recv: %d", res);
1294 wpa_printf(MSG_DEBUG, "%s - gnutls_record_recv failed: %d "
1295 "(%s)", __func__, (int) res,
1296 gnutls_strerror(res));
1301 wpabuf_put(ad, res);
1302 wpa_printf(MSG_DEBUG, "GnuTLS: Received %d bytes of Application Data",
1308 struct wpabuf * tls_connection_handshake(void *tls_ctx,
1309 struct tls_connection *conn,
1310 const struct wpabuf *in_data,
1311 struct wpabuf **appl_data)
1313 struct tls_global *global = tls_ctx;
1314 struct wpabuf *out_data;
1320 if (in_data && wpabuf_len(in_data) > 0) {
1321 if (conn->pull_buf) {
1322 wpa_printf(MSG_DEBUG, "%s - %lu bytes remaining in "
1323 "pull_buf", __func__,
1324 (unsigned long) wpabuf_len(conn->pull_buf));
1325 wpabuf_free(conn->pull_buf);
1327 conn->pull_buf = wpabuf_dup(in_data);
1328 if (conn->pull_buf == NULL)
1330 conn->pull_buf_offset = wpabuf_head(conn->pull_buf);
1333 ret = gnutls_handshake(conn->session);
1335 gnutls_alert_description_t alert;
1338 case GNUTLS_E_AGAIN:
1339 if (global->server && conn->established &&
1340 conn->push_buf == NULL) {
1341 /* Need to return something to trigger
1342 * completion of EAP-TLS. */
1343 conn->push_buf = wpabuf_alloc(0);
1346 case GNUTLS_E_FATAL_ALERT_RECEIVED:
1347 alert = gnutls_alert_get(conn->session);
1348 wpa_printf(MSG_DEBUG, "%s - received fatal '%s' alert",
1349 __func__, gnutls_alert_get_name(alert));
1350 conn->read_alerts++;
1351 if (conn->global->event_cb != NULL) {
1352 union tls_event_data ev;
1354 os_memset(&ev, 0, sizeof(ev));
1355 ev.alert.is_local = 0;
1356 ev.alert.type = gnutls_alert_get_name(alert);
1357 ev.alert.description = ev.alert.type;
1358 conn->global->event_cb(conn->global->cb_ctx,
1363 wpa_printf(MSG_DEBUG, "%s - gnutls_handshake failed "
1364 "-> %s", __func__, gnutls_strerror(ret));
1370 wpa_printf(MSG_DEBUG, "TLS: Handshake completed successfully");
1372 #if GNUTLS_VERSION_NUMBER >= 0x03010a
1376 desc = gnutls_session_get_desc(conn->session);
1378 wpa_printf(MSG_DEBUG, "GnuTLS: %s", desc);
1382 #endif /* GnuTLS 3.1.10 or newer */
1384 conn->established = 1;
1385 if (conn->push_buf == NULL) {
1386 /* Need to return something to get final TLS ACK. */
1387 conn->push_buf = wpabuf_alloc(0);
1390 gnutls_session_get_data(conn->session, NULL, &size);
1391 if (global->session_data == NULL ||
1392 global->session_data_size < size) {
1393 os_free(global->session_data);
1394 global->session_data = os_malloc(size);
1396 if (global->session_data) {
1397 global->session_data_size = size;
1398 gnutls_session_get_data(conn->session,
1399 global->session_data,
1400 &global->session_data_size);
1403 if (conn->pull_buf && appl_data)
1404 *appl_data = gnutls_get_appl_data(conn);
1407 out_data = conn->push_buf;
1408 conn->push_buf = NULL;
1413 struct wpabuf * tls_connection_server_handshake(void *tls_ctx,
1414 struct tls_connection *conn,
1415 const struct wpabuf *in_data,
1416 struct wpabuf **appl_data)
1418 return tls_connection_handshake(tls_ctx, conn, in_data, appl_data);
1422 struct wpabuf * tls_connection_encrypt(void *tls_ctx,
1423 struct tls_connection *conn,
1424 const struct wpabuf *in_data)
1429 res = gnutls_record_send(conn->session, wpabuf_head(in_data),
1430 wpabuf_len(in_data));
1432 wpa_printf(MSG_INFO, "%s: Encryption failed: %s",
1433 __func__, gnutls_strerror(res));
1437 buf = conn->push_buf;
1438 conn->push_buf = NULL;
1443 struct wpabuf * tls_connection_decrypt(void *tls_ctx,
1444 struct tls_connection *conn,
1445 const struct wpabuf *in_data)
1450 if (conn->pull_buf) {
1451 wpa_printf(MSG_DEBUG, "%s - %lu bytes remaining in "
1452 "pull_buf", __func__,
1453 (unsigned long) wpabuf_len(conn->pull_buf));
1454 wpabuf_free(conn->pull_buf);
1456 conn->pull_buf = wpabuf_dup(in_data);
1457 if (conn->pull_buf == NULL)
1459 conn->pull_buf_offset = wpabuf_head(conn->pull_buf);
1462 * Even though we try to disable TLS compression, it is possible that
1463 * this cannot be done with all TLS libraries. Add extra buffer space
1464 * to handle the possibility of the decrypted data being longer than
1467 out = wpabuf_alloc((wpabuf_len(in_data) + 500) * 3);
1471 res = gnutls_record_recv(conn->session, wpabuf_mhead(out),
1474 wpa_printf(MSG_DEBUG, "%s - gnutls_record_recv failed: %d "
1475 "(%s)", __func__, (int) res, gnutls_strerror(res));
1479 wpabuf_put(out, res);
1485 int tls_connection_resumed(void *ssl_ctx, struct tls_connection *conn)
1489 return gnutls_session_is_resumed(conn->session);
1493 int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn,
1501 int tls_get_version(void *ssl_ctx, struct tls_connection *conn,
1502 char *buf, size_t buflen)
1509 int tls_get_cipher(void *ssl_ctx, struct tls_connection *conn,
1510 char *buf, size_t buflen)
1518 int tls_connection_enable_workaround(void *ssl_ctx,
1519 struct tls_connection *conn)
1521 gnutls_record_disable_padding(conn->session);
1526 int tls_connection_client_hello_ext(void *ssl_ctx, struct tls_connection *conn,
1527 int ext_type, const u8 *data,
1535 int tls_connection_get_failed(void *ssl_ctx, struct tls_connection *conn)
1539 return conn->failed;
1543 int tls_connection_get_read_alerts(void *ssl_ctx, struct tls_connection *conn)
1547 return conn->read_alerts;
1551 int tls_connection_get_write_alerts(void *ssl_ctx, struct tls_connection *conn)
1555 return conn->write_alerts;
1559 int tls_connection_set_session_ticket_cb(void *tls_ctx,
1560 struct tls_connection *conn,
1561 tls_session_ticket_cb cb, void *ctx)
1567 int tls_get_library_version(char *buf, size_t buf_len)
1569 return os_snprintf(buf, buf_len, "GnuTLS build=%s run=%s",
1570 GNUTLS_VERSION, gnutls_check_version(NULL));
1574 void tls_connection_set_success_data(struct tls_connection *conn,
1575 struct wpabuf *data)
1580 void tls_connection_set_success_data_resumed(struct tls_connection *conn)
1585 const struct wpabuf *
1586 tls_connection_get_success_data(struct tls_connection *conn)
1592 void tls_connection_remove_session(struct tls_connection *conn)