[glib-networking/mcatanzaro/gnutls-creds: 2/2] gnutls: perform certificate verification in TLS session context
- From: Michael Catanzaro <mcatanzaro src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [glib-networking/mcatanzaro/gnutls-creds: 2/2] gnutls: perform certificate verification in TLS session context
- Date: Wed, 23 Jun 2021 01:34:14 +0000 (UTC)
commit ec544f715fa5ee2a8f55d7c00ae2019b602e9653
Author: Michael Catanzaro <mcatanzaro redhat com>
Date: Tue Jun 22 19:22:42 2021 -0500
gnutls: perform certificate verification in TLS session context
There are several different ways to perform certificate verification
with GnuTLS, but they all fall into one of two categories:
(a) outside the context of a TLS session
(b) within the context of a TLS session
(a) is done by g_tls_database_verify_chain() and implemented using one
of several different functions of gnutls_x509_trust_list_t, e.g.
gnutls_x509_trust_list_verify_crt2() or one of the related functions.
This is what we have historically always done.
(b) is what we're now doing here. The recommended way is to use
gnutls_session_set_verify_cert(), but we can't do that because that
would leave no way to implement the accept-certificate signal. The other
way is to use gnutls_certificate_verify_peers3() or one of the related
functions. This adds additional smarts that are not possible when using
GTlsDatabase directly. For example, it checks name constraints, key
usage, and basic constraints. It also checks for stapled OCSP responses.
Verification will fail if the OCSP response indicates the certificate
has been revoked. Verification will also fail if the Must-Staple flag is
set but the OCSP response is missing. Nice!
Incidentally fixes #32
tls/base/gtlsconnection-base.c | 18 ++--
tls/base/gtlsconnection-base.h | 40 +++++---
tls/gnutls/gtlsclientconnection-gnutls.c | 10 ++
tls/gnutls/gtlsconnection-gnutls.c | 169 +++++++++++++++++++++++++++----
tls/gnutls/gtlsconnection-gnutls.h | 3 +
tls/gnutls/gtlsdatabase-gnutls.c | 112 ++++++++++++++------
tls/gnutls/gtlsdatabase-gnutls.h | 13 ++-
tls/gnutls/gtlsserverconnection-gnutls.c | 10 ++
tls/openssl/gtlsconnection-openssl.c | 40 ++++++++
9 files changed, 335 insertions(+), 80 deletions(-)
---
diff --git a/tls/base/gtlsconnection-base.c b/tls/base/gtlsconnection-base.c
index f6b2460..ebef3df 100644
--- a/tls/base/gtlsconnection-base.c
+++ b/tls/base/gtlsconnection-base.c
@@ -1240,6 +1240,7 @@ verify_peer_certificate (GTlsConnectionBase *tls,
GTlsCertificate *peer_certificate)
{
GSocketConnectable *peer_identity = NULL;
+ GTlsConnectionBaseClass *tls_class = G_TLS_CONNECTION_BASE_GET_CLASS (tls);
GTlsDatabase *database;
GTlsCertificateFlags errors = 0;
gboolean is_client;
@@ -1267,14 +1268,15 @@ verify_peer_certificate (GTlsConnectionBase *tls,
{
GError *error = NULL;
- errors |= g_tls_database_verify_chain (database, peer_certificate,
- is_client ?
- G_TLS_DATABASE_PURPOSE_AUTHENTICATE_SERVER :
- G_TLS_DATABASE_PURPOSE_AUTHENTICATE_CLIENT,
- peer_identity,
- g_tls_connection_get_interaction (G_TLS_CONNECTION (tls)),
- G_TLS_DATABASE_VERIFY_NONE,
- NULL, &error);
+ g_assert (tls_class->verify_chain);
+ errors |= tls_class->verify_chain (tls,
+ peer_certificate,
+ is_client ? G_TLS_DATABASE_PURPOSE_AUTHENTICATE_SERVER :
G_TLS_DATABASE_PURPOSE_AUTHENTICATE_CLIENT,
+ peer_identity,
+ g_tls_connection_get_interaction (G_TLS_CONNECTION (tls)),
+ G_TLS_DATABASE_VERIFY_NONE,
+ NULL,
+ &error);
if (error)
{
g_tls_log_debug (tls, "failure verifying certificate chain: %s", error->message);
diff --git a/tls/base/gtlsconnection-base.h b/tls/base/gtlsconnection-base.h
index a89122e..e9f3242 100644
--- a/tls/base/gtlsconnection-base.h
+++ b/tls/base/gtlsconnection-base.h
@@ -58,24 +58,32 @@ struct _GTlsConnectionBaseClass
{
GTlsConnectionClass parent_class;
- void (*prepare_handshake) (GTlsConnectionBase *tls,
- gchar **advertised_protocols);
+ void (*prepare_handshake) (GTlsConnectionBase *tls,
+ gchar **advertised_protocols);
GTlsSafeRenegotiationStatus (*handshake_thread_safe_renegotiation_status)
- (GTlsConnectionBase *tls);
+ (GTlsConnectionBase *tls);
GTlsConnectionBaseStatus (*handshake_thread_request_rehandshake)
- (GTlsConnectionBase *tls,
- gint64 timeout,
- GCancellable *cancellable,
- GError **error);
- GTlsConnectionBaseStatus (*handshake_thread_handshake) (GTlsConnectionBase *tls,
- gint64 timeout,
- GCancellable *cancellable,
- GError **error);
- GTlsCertificate *(*retrieve_peer_certificate) (GTlsConnectionBase *tls);
- void (*complete_handshake) (GTlsConnectionBase *tls,
- gboolean handshake_succeeded,
- gchar **negotiated_protocol,
- GError **error);
+ (GTlsConnectionBase *tls,
+ gint64 timeout,
+ GCancellable *cancellable,
+ GError **error);
+ GTlsConnectionBaseStatus (*handshake_thread_handshake) (GTlsConnectionBase *tls,
+ gint64 timeout,
+ GCancellable *cancellable,
+ GError **error);
+ GTlsCertificate *(*retrieve_peer_certificate) (GTlsConnectionBase *tls);
+ GTlsCertificateFlags (*verify_chain) (GTlsConnectionBase *tls,
+ GTlsCertificate *chain,
+ const gchar *purpose,
+ GSocketConnectable *identity,
+ GTlsInteraction *interaction,
+ GTlsDatabaseVerifyFlags flags,
+ GCancellable *cancellable,
+ GError **error);
+ void (*complete_handshake) (GTlsConnectionBase *tls,
+ gboolean handshake_succeeded,
+ gchar **negotiated_protocol,
+ GError **error);
gboolean (*is_session_resumed) (GTlsConnectionBase *tls);
diff --git a/tls/gnutls/gtlsclientconnection-gnutls.c b/tls/gnutls/gtlsclientconnection-gnutls.c
index 6f4cd23..3c432da 100644
--- a/tls/gnutls/gtlsclientconnection-gnutls.c
+++ b/tls/gnutls/gtlsclientconnection-gnutls.c
@@ -566,11 +566,19 @@ g_tls_client_connection_gnutls_copy_session_state (GTlsClientConnection *conn,
gnutls->session_data_override = !!gnutls->session_data;
}
+static void
+g_tls_client_connection_gnutls_update_credentials (GTlsConnectionGnutls *gnutls,
+ gnutls_certificate_credentials_t credentials)
+{
+ gnutls_certificate_set_retrieve_function2 (credentials,
g_tls_client_connection_gnutls_handshake_thread_retrieve_function);
+}
+
static void
g_tls_client_connection_gnutls_class_init (GTlsClientConnectionGnutlsClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
GTlsConnectionBaseClass *base_class = G_TLS_CONNECTION_BASE_CLASS (klass);
+ GTlsConnectionGnutlsClass *gnutls_class = G_TLS_CONNECTION_GNUTLS_CLASS (klass);
gobject_class->get_property = g_tls_client_connection_gnutls_get_property;
gobject_class->set_property = g_tls_client_connection_gnutls_set_property;
@@ -579,6 +587,8 @@ g_tls_client_connection_gnutls_class_init (GTlsClientConnectionGnutlsClass *klas
base_class->prepare_handshake = g_tls_client_connection_gnutls_prepare_handshake;
base_class->complete_handshake = g_tls_client_connection_gnutls_complete_handshake;
+ gnutls_class->update_credentials = g_tls_client_connection_gnutls_update_credentials;
+
g_object_class_override_property (gobject_class, PROP_VALIDATION_FLAGS, "validation-flags");
g_object_class_override_property (gobject_class, PROP_SERVER_IDENTITY, "server-identity");
g_object_class_override_property (gobject_class, PROP_USE_SSL3, "use-ssl3");
diff --git a/tls/gnutls/gtlsconnection-gnutls.c b/tls/gnutls/gtlsconnection-gnutls.c
index f99ba40..c4f5b1d 100644
--- a/tls/gnutls/gtlsconnection-gnutls.c
+++ b/tls/gnutls/gtlsconnection-gnutls.c
@@ -36,6 +36,7 @@
#include "gtlsbackend-gnutls.h"
#include "gtlscertificate-gnutls.h"
#include "gtlsclientconnection-gnutls.h"
+#include "gtlsdatabase-gnutls.h"
#include "gtlslog.h"
#ifdef G_OS_WIN32
@@ -111,6 +112,55 @@ g_tls_connection_gnutls_set_handshake_priority (GTlsConnectionGnutls *gnutls)
g_warning ("Failed to set GnuTLS session priority: %s", gnutls_strerror (ret));
}
+static void
+update_credentials_cb (GObject *gobject,
+ GParamSpec *pspec,
+ gpointer user_data)
+{
+ GTlsConnectionGnutls *gnutls = G_TLS_CONNECTION_GNUTLS (gobject);
+ GTlsConnectionGnutlsPrivate *priv = g_tls_connection_gnutls_get_instance_private (gnutls);
+ GTlsConnectionGnutlsClass *connection_class = G_TLS_CONNECTION_GNUTLS_GET_CLASS (gnutls);
+ gnutls_certificate_credentials_t credentials;
+ GTlsDatabase *database;
+ GError *error = NULL;
+ int ret;
+
+ database = g_tls_connection_get_database (G_TLS_CONNECTION (gnutls));
+ if (database)
+ {
+ credentials = g_tls_database_gnutls_get_credentials (G_TLS_DATABASE_GNUTLS (database), &error);
+ if (!credentials)
+ {
+ g_warning ("Failed to update credentials: %s", error->message);
+ g_error_free (error);
+ return;
+ }
+ }
+ else
+ {
+ ret = gnutls_certificate_allocate_credentials (&credentials);
+ if (ret != 0)
+ {
+ g_warning ("Failed to update credentials: %s", gnutls_strerror (ret));
+ return;
+ }
+ }
+
+ ret = gnutls_credentials_set (priv->session, GNUTLS_CRD_CERTIFICATE, credentials);
+ if (ret != 0)
+ {
+ g_warning ("Failed to update credentials: %s", gnutls_strerror (ret));
+ gnutls_certificate_free_credentials (credentials);
+ return;
+ }
+
+ gnutls_certificate_free_credentials (priv->creds);
+ priv->creds = credentials;
+
+ g_assert (connection_class->update_credentials);
+ connection_class->update_credentials (gnutls, credentials);
+}
+
static gboolean
g_tls_connection_gnutls_initable_init (GInitable *initable,
GCancellable *cancellable,
@@ -118,11 +168,13 @@ g_tls_connection_gnutls_initable_init (GInitable *initable,
{
GTlsConnectionGnutls *gnutls = G_TLS_CONNECTION_GNUTLS (initable);
GTlsConnectionGnutlsPrivate *priv = g_tls_connection_gnutls_get_instance_private (gnutls);
+ GTlsDatabase *database;
GIOStream *base_io_stream = NULL;
GDatagramBased *base_socket = NULL;
gboolean client = G_IS_TLS_CLIENT_CONNECTION (gnutls);
guint flags = client ? GNUTLS_CLIENT : GNUTLS_SERVER;
- int status;
+ GError *my_error = NULL;
+ gboolean success = FALSE;
int ret;
g_object_get (gnutls,
@@ -136,33 +188,47 @@ g_tls_connection_gnutls_initable_init (GInitable *initable,
if (base_socket)
flags |= GNUTLS_DATAGRAM;
- ret = gnutls_certificate_allocate_credentials (&priv->creds);
- if (ret != GNUTLS_E_SUCCESS)
+ database = g_tls_connection_get_database (G_TLS_CONNECTION (gnutls));
+ if (database)
{
- g_set_error (error, G_TLS_ERROR, G_TLS_ERROR_MISC,
- _("Could not create TLS connection: %s"),
- gnutls_strerror (ret));
- g_clear_object (&base_io_stream);
- g_clear_object (&base_socket);
- return FALSE;
+ priv->creds = g_tls_database_gnutls_get_credentials (G_TLS_DATABASE_GNUTLS (database), &my_error);
+ if (!priv->creds)
+ {
+ g_propagate_prefixed_error (error, my_error, ("Could not create TLS connection:"));
+ goto out;
+ }
+ }
+ else
+ {
+ ret = gnutls_certificate_allocate_credentials (&priv->creds);
+ if (ret != 0)
+ {
+ g_set_error (error, G_TLS_ERROR, G_TLS_ERROR_MISC,
+ _("Could not create TLS connection: %s"),
+ gnutls_strerror (ret));
+ goto out;
+ }
}
+ if (!client)
+ g_signal_connect (gnutls, "notify::authentication-mode", G_CALLBACK (update_credentials_cb), NULL);
+ g_signal_connect (gnutls, "notify::database", G_CALLBACK (update_credentials_cb), NULL);
+ g_signal_connect (gnutls, "notify::use-system-certdb", G_CALLBACK (update_credentials_cb), NULL);
+
gnutls_init (&priv->session, flags);
gnutls_session_set_ptr (priv->session, gnutls);
gnutls_session_set_verify_function (priv->session, verify_certificate_cb);
- status = gnutls_credentials_set (priv->session,
- GNUTLS_CRD_CERTIFICATE,
- priv->creds);
- if (status != 0)
+ ret = gnutls_credentials_set (priv->session,
+ GNUTLS_CRD_CERTIFICATE,
+ priv->creds);
+ if (ret != 0)
{
g_set_error (error, G_TLS_ERROR, G_TLS_ERROR_MISC,
_("Could not create TLS connection: %s"),
- gnutls_strerror (status));
- g_clear_object (&base_io_stream);
- g_clear_object (&base_socket);
- return FALSE;
+ gnutls_strerror (ret));
+ goto out;
}
gnutls_transport_set_push_function (priv->session,
@@ -184,10 +250,13 @@ g_tls_connection_gnutls_initable_init (GInitable *initable,
if (flags & GNUTLS_DATAGRAM)
gnutls_dtls_set_mtu (priv->session, 1400);
+ success = TRUE;
+
+out:
g_clear_object (&base_io_stream);
g_clear_object (&base_socket);
- return TRUE;
+ return success;
}
static void
@@ -900,6 +969,69 @@ g_tls_connection_gnutls_handshake_thread_handshake (GTlsConnectionBase *tls,
return status;
}
+static GTlsCertificateFlags
+g_tls_connection_gnutls_verify_chain (GTlsConnectionBase *tls,
+ GTlsCertificate *chain,
+ const gchar *purpose,
+ GSocketConnectable *identity,
+ GTlsInteraction *interaction,
+ GTlsDatabaseVerifyFlags flags,
+ GCancellable *cancellable,
+ GError **error)
+{
+ GTlsConnectionGnutls *gnutls = G_TLS_CONNECTION_GNUTLS (tls);
+ GTlsConnectionGnutlsPrivate *priv = g_tls_connection_gnutls_get_instance_private (gnutls);
+ GTlsCertificateFlags errors = 0;
+ const char *hostname = NULL;
+ char *free_hostname = NULL;
+ guint gnutls_result;
+ int ret;
+
+ /* There are several different ways to perform certificate verification with
+ * GnuTLS, but they all fall into one of two categories:
+ *
+ * (a) outside the context of a TLS session
+ * (b) within the context of a TLS session
+ *
+ * (a) is done by g_tls_database_verify_chain() and implemented using one of
+ * several different functions of gnutls_x509_trust_list_t, e.g.
+ * gnutls_x509_trust_list_verify_crt2() or one of the related functions.
+ *
+ * (b) is what we're doing here. The recommended way is to use
+ * gnutls_session_set_verify_cert(), but we can't do that because that would
+ * leave no way to implement the accept-certificate signal. The other way is
+ * to use gnutls_certificate_verify_peers3() or one of the related functions.
+ * This adds additional smarts that are not possible when using GTlsDatabase
+ * directly. For example, it checks name constraints, key usage, and basic
+ * constraints. It also checks for stapled OCSP responses. Verification will
+ * fail if the OCSP response indicates the certificate has been revoked.
+ * Verification will also fail if the Must-Staple flag is set but the OCSP
+ * response is missing. Nice! This uses the gnutls_certificate_credentials_t
+ * set on the gnutls_session_t by gnutls_credentials_set().
+ */
+
+ if (G_IS_NETWORK_ADDRESS (identity))
+ hostname = g_network_address_get_hostname (G_NETWORK_ADDRESS (identity));
+ else if (G_IS_NETWORK_SERVICE (identity))
+ hostname = g_network_service_get_domain (G_NETWORK_SERVICE (identity));
+ else if (G_IS_INET_SOCKET_ADDRESS (identity))
+ {
+ GInetAddress *addr;
+
+ addr = g_inet_socket_address_get_address (G_INET_SOCKET_ADDRESS (identity));
+ hostname = free_hostname = g_inet_address_to_string (addr);
+ }
+
+ ret = gnutls_certificate_verify_peers3 (priv->session, hostname, &gnutls_result);
+ if (ret != 0)
+ errors = G_TLS_CERTIFICATE_GENERIC_ERROR;
+ else
+ errors = g_tls_certificate_gnutls_convert_flags (gnutls_result);
+
+ g_free (free_hostname);
+ return errors;
+}
+
static void
g_tls_connection_gnutls_complete_handshake (GTlsConnectionBase *tls,
gboolean handshake_succeeded,
@@ -1348,6 +1480,7 @@ g_tls_connection_gnutls_class_init (GTlsConnectionGnutlsClass *klass)
base_class->handshake_thread_request_rehandshake =
g_tls_connection_gnutls_handshake_thread_request_rehandshake;
base_class->handshake_thread_handshake =
g_tls_connection_gnutls_handshake_thread_handshake;
base_class->retrieve_peer_certificate = g_tls_connection_gnutls_retrieve_peer_certificate;
+ base_class->verify_chain = g_tls_connection_gnutls_verify_chain;
base_class->complete_handshake = g_tls_connection_gnutls_complete_handshake;
base_class->is_session_resumed = g_tls_connection_gnutls_is_session_resumed;
base_class->get_channel_binding_data = g_tls_connection_gnutls_get_channel_binding_data;
diff --git a/tls/gnutls/gtlsconnection-gnutls.h b/tls/gnutls/gtlsconnection-gnutls.h
index 55ae5ee..16ec747 100644
--- a/tls/gnutls/gtlsconnection-gnutls.h
+++ b/tls/gnutls/gtlsconnection-gnutls.h
@@ -39,6 +39,9 @@ G_DECLARE_DERIVABLE_TYPE (GTlsConnectionGnutls, g_tls_connection_gnutls, G, TLS_
struct _GTlsConnectionGnutlsClass
{
GTlsConnectionBaseClass parent_class;
+
+ void (*update_credentials) (GTlsConnectionGnutls *gnutls,
+ gnutls_certificate_credentials_t credentials);
};
gnutls_certificate_credentials_t g_tls_connection_gnutls_get_credentials (GTlsConnectionGnutls *connection);
diff --git a/tls/gnutls/gtlsdatabase-gnutls.c b/tls/gnutls/gtlsdatabase-gnutls.c
index 4354d48..5499ae5 100644
--- a/tls/gnutls/gtlsdatabase-gnutls.c
+++ b/tls/gnutls/gtlsdatabase-gnutls.c
@@ -566,26 +566,6 @@ g_tls_database_gnutls_create_handle_for_certificate (GTlsDatabaseGnutls *self,
return uri;
}
-static gboolean
-g_tls_database_gnutls_populate_trust_list (GTlsDatabaseGnutls *self,
- gnutls_x509_trust_list_t trust_list,
- GError **error)
-{
- int gerr = gnutls_x509_trust_list_add_system_trust (trust_list, 0, 0);
- if (gerr == GNUTLS_E_UNIMPLEMENTED_FEATURE)
- {
- g_set_error_literal (error, G_TLS_ERROR, G_TLS_ERROR_MISC,
- _("Failed to load system trust store: GnuTLS was not configured with a system
trust"));
- }
- else if (gerr < 0)
- {
- g_set_error (error, G_TLS_ERROR, G_TLS_ERROR_MISC,
- _("Failed to load system trust store: %s"),
- gnutls_strerror (gerr));
- }
- return gerr >= 0;
-}
-
#if GNUTLS_VERSION_MAJOR > 3 || GNUTLS_VERSION_MAJOR == 3 && GNUTLS_VERSION_MINOR >= 7
static int
issuer_missing_cb (gnutls_x509_trust_list_t tlist,
@@ -710,6 +690,82 @@ out:
}
#endif
+static gboolean
+g_tls_database_gnutls_populate_trust_list (GTlsDatabaseGnutls *self,
+ gnutls_x509_trust_list_t trust_list,
+ GError **error)
+{
+ int gerr = gnutls_x509_trust_list_add_system_trust (trust_list, 0, 0);
+ if (gerr == GNUTLS_E_UNIMPLEMENTED_FEATURE)
+ {
+ g_set_error_literal (error, G_TLS_ERROR, G_TLS_ERROR_MISC,
+ _("Failed to load system trust store: GnuTLS was not configured with a system
trust"));
+ }
+ else if (gerr < 0)
+ {
+ g_set_error (error, G_TLS_ERROR, G_TLS_ERROR_MISC,
+ _("Failed to load system trust store: %s"),
+ gnutls_strerror (gerr));
+ }
+ return gerr >= 0;
+}
+
+static gnutls_x509_trust_list_t
+create_trust_list (GTlsDatabaseGnutls *self,
+ GError **error)
+{
+ GTlsDatabaseGnutlsClass *database_class = G_TLS_DATABASE_GNUTLS_GET_CLASS (self);
+ gnutls_x509_trust_list_t trust_list;
+ int ret;
+
+ ret = gnutls_x509_trust_list_init (&trust_list, 0);
+ if (ret != 0)
+ {
+ g_set_error (error, G_TLS_ERROR, G_TLS_ERROR_MISC, "Failed to initialize trust list: %s",
gnutls_strerror (ret));
+ return NULL;
+ }
+
+#if GNUTLS_VERSION_MAJOR > 3 || GNUTLS_VERSION_MAJOR == 3 && GNUTLS_VERSION_MINOR >= 7
+ gnutls_x509_trust_list_set_getissuer_function (trust_list, issuer_missing_cb);
+ gnutls_x509_trust_list_set_ptr (trust_list, self);
+#endif
+
+ g_assert (database_class->populate_trust_list);
+ if (!database_class->populate_trust_list (self, trust_list, error))
+ {
+ gnutls_x509_trust_list_deinit (trust_list, TRUE);
+ return NULL;
+ }
+
+ return trust_list;
+}
+
+gnutls_certificate_credentials_t
+g_tls_database_gnutls_get_credentials (GTlsDatabaseGnutls *self,
+ GError **error)
+{
+ gnutls_certificate_credentials_t credentials;
+ gnutls_x509_trust_list_t trust_list = NULL;
+ int ret;
+
+ ret = gnutls_certificate_allocate_credentials (&credentials);
+ if (ret != 0)
+ {
+ g_set_error (error, G_TLS_ERROR, G_TLS_ERROR_MISC, "Failed to allocate credentials: %s",
gnutls_strerror (ret));
+ return NULL;
+ }
+
+ trust_list = create_trust_list (self, error);
+ if (!trust_list)
+ {
+ gnutls_certificate_free_credentials (credentials);
+ return NULL;
+ }
+
+ gnutls_certificate_set_trust_list (credentials, trust_list, 0);
+ return credentials;
+}
+
static void
g_tls_database_gnutls_class_init (GTlsDatabaseGnutlsClass *klass)
{
@@ -744,18 +800,9 @@ g_tls_database_gnutls_initable_init (GInitable *initable,
if (g_cancellable_set_error_if_cancelled (cancellable, error))
return FALSE;
- gnutls_x509_trust_list_init (&trust_list, 0);
-#if GNUTLS_VERSION_MAJOR > 3 || GNUTLS_VERSION_MAJOR == 3 && GNUTLS_VERSION_MINOR >= 7
- gnutls_x509_trust_list_set_getissuer_function (trust_list, issuer_missing_cb);
- gnutls_x509_trust_list_set_ptr (trust_list, self);
-#endif
-
- g_assert (G_TLS_DATABASE_GNUTLS_GET_CLASS (self)->populate_trust_list);
- if (!G_TLS_DATABASE_GNUTLS_GET_CLASS (self)->populate_trust_list (self, trust_list, error))
- {
- result = FALSE;
- goto out;
- }
+ trust_list = create_trust_list (self, error);
+ if (!trust_list)
+ return FALSE;
subjects = bytes_multi_table_new ();
issuers = bytes_multi_table_new ();
@@ -795,7 +842,6 @@ g_tls_database_gnutls_initable_init (GInitable *initable,
g_mutex_unlock (&priv->mutex);
}
-out:
if (trust_list)
gnutls_x509_trust_list_deinit (trust_list, 1);
if (subjects)
diff --git a/tls/gnutls/gtlsdatabase-gnutls.h b/tls/gnutls/gtlsdatabase-gnutls.h
index 0a31dd5..0f9cd93 100644
--- a/tls/gnutls/gtlsdatabase-gnutls.h
+++ b/tls/gnutls/gtlsdatabase-gnutls.h
@@ -41,13 +41,16 @@ struct _GTlsDatabaseGnutlsClass
{
GTlsDatabaseClass parent_class;
- gchar *(*create_handle_for_certificate) (GTlsDatabaseGnutls *self,
- GBytes *der);
- gboolean (*populate_trust_list) (GTlsDatabaseGnutls *self,
- gnutls_x509_trust_list_t trust_list,
- GError **error);
+ gchar *(*create_handle_for_certificate) (GTlsDatabaseGnutls *self,
+ GBytes *der);
+ gboolean (*populate_trust_list) (GTlsDatabaseGnutls *self,
+ gnutls_x509_trust_list_t trust_list,
+ GError **error);
};
GTlsDatabaseGnutls *g_tls_database_gnutls_new (GError **error);
+gnutls_certificate_credentials_t g_tls_database_gnutls_get_credentials (GTlsDatabaseGnutls *self,
+ GError **error);
+
G_END_DECLS
diff --git a/tls/gnutls/gtlsserverconnection-gnutls.c b/tls/gnutls/gtlsserverconnection-gnutls.c
index 090b57d..2530376 100644
--- a/tls/gnutls/gtlsserverconnection-gnutls.c
+++ b/tls/gnutls/gtlsserverconnection-gnutls.c
@@ -218,11 +218,19 @@ g_tls_server_connection_gnutls_prepare_handshake (GTlsConnectionBase *tls,
G_TLS_CONNECTION_BASE_CLASS (g_tls_server_connection_gnutls_parent_class)->prepare_handshake (tls,
advertised_protocols);
}
+static void
+g_tls_server_connection_gnutls_update_credentials (GTlsConnectionGnutls *gnutls,
+ gnutls_certificate_credentials_t credentials)
+{
+ gnutls_certificate_set_retrieve_function2 (credentials,
g_tls_server_connection_gnutls_handshake_thread_retrieve_function);
+}
+
static void
g_tls_server_connection_gnutls_class_init (GTlsServerConnectionGnutlsClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
GTlsConnectionBaseClass *base_class = G_TLS_CONNECTION_BASE_CLASS (klass);
+ GTlsConnectionGnutlsClass *gnutls_class = G_TLS_CONNECTION_GNUTLS_CLASS (klass);
gobject_class->finalize = g_tls_server_connection_gnutls_finalize;
gobject_class->get_property = g_tls_server_connection_gnutls_get_property;
@@ -230,6 +238,8 @@ g_tls_server_connection_gnutls_class_init (GTlsServerConnectionGnutlsClass *klas
base_class->prepare_handshake = g_tls_server_connection_gnutls_prepare_handshake;
+ gnutls_class->update_credentials = g_tls_server_connection_gnutls_update_credentials;
+
g_object_class_override_property (gobject_class, PROP_AUTHENTICATION_MODE, "authentication-mode");
}
diff --git a/tls/openssl/gtlsconnection-openssl.c b/tls/openssl/gtlsconnection-openssl.c
index e756fa7..8829d28 100644
--- a/tls/openssl/gtlsconnection-openssl.c
+++ b/tls/openssl/gtlsconnection-openssl.c
@@ -482,7 +482,44 @@ g_tls_connection_openssl_prepare_handshake (GTlsConnectionBase *tls,
g_byte_array_unref (protocols);
}
}
+#endif
+
+static GTlsCertificateFlags
+g_tls_connection_openssl_verify_chain (GTlsConnectionBase *tls,
+ GTlsCertificate *chain,
+ const gchar *purpose,
+ GSocketConnectable *identity,
+ GTlsInteraction *interaction,
+ GTlsDatabaseVerifyFlags flags,
+ GCancellable *cancellable,
+ GError **error)
+{
+ GTlsDatabase *database;
+ GTlsCertificateFlags errors = 0;
+ gboolean is_client = G_IS_TLS_CLIENT_CONNECTION (tls);
+ database = g_tls_connection_get_database (G_TLS_CONNECTION (tls));
+ if (database)
+ {
+ errors |= g_tls_database_verify_chain (database,
+ chain,
+ is_client ? G_TLS_DATABASE_PURPOSE_AUTHENTICATE_SERVER :
G_TLS_DATABASE_PURPOSE_AUTHENTICATE_CLIENT,
+ identity,
+ g_tls_connection_get_interaction (G_TLS_CONNECTION (tls)),
+ G_TLS_DATABASE_VERIFY_NONE,
+ NULL,
+ error);
+ }
+ else
+ {
+ errors |= G_TLS_CERTIFICATE_UNKNOWN_CA;
+ errors |= g_tls_certificate_verify (chain, identity, NULL);
+ }
+
+ return errors;
+}
+
+#if OPENSSL_VERSION_NUMBER >= 0x10002000L || defined (LIBRESSL_VERSION_NUMBER)
static void
g_tls_connection_openssl_complete_handshake (GTlsConnectionBase *tls,
gboolean handshake_succeeded,
@@ -1005,6 +1042,9 @@ g_tls_connection_openssl_class_init (GTlsConnectionOpensslClass *klass)
#if OPENSSL_VERSION_NUMBER >= 0x10002000L || defined (LIBRESSL_VERSION_NUMBER)
base_class->prepare_handshake = g_tls_connection_openssl_prepare_handshake;
+#endif
+ base_class->verify_chain = g_tls_connection_openssl_verify_chain;
+#if OPENSSL_VERSION_NUMBER >= 0x10002000L || defined (LIBRESSL_VERSION_NUMBER)
base_class->complete_handshake = g_tls_connection_openssl_complete_handshake;
#endif
base_class->handshake_thread_safe_renegotiation_status =
g_tls_connection_openssl_handshake_thread_safe_renegotiation_status;
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]