[glib-networking/mcatanzaro/gnutls-creds: 24/24] 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: 24/24] gnutls: perform certificate verification in TLS session context
- Date: Thu, 24 Jun 2021 16:42:08 +0000 (UTC)
commit d94c33138ecb12905fde400b1db41a3829ce7be9
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 | 14 ++-
tls/gnutls/gtlsclientconnection-gnutls.c | 10 ++
tls/gnutls/gtlsconnection-gnutls.c | 168 +++++++++++++++++++++++++++----
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 | 36 +++++++
9 files changed, 316 insertions(+), 68 deletions(-)
---
diff --git a/tls/base/gtlsconnection-base.c b/tls/base/gtlsconnection-base.c
index dd23c46..6608b9b 100644
--- a/tls/base/gtlsconnection-base.c
+++ b/tls/base/gtlsconnection-base.c
@@ -1258,6 +1258,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;
@@ -1285,14 +1286,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 4541f54..a8c9b93 100644
--- a/tls/base/gtlsconnection-base.h
+++ b/tls/base/gtlsconnection-base.h
@@ -58,10 +58,10 @@ 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,
@@ -72,6 +72,14 @@ struct _GTlsConnectionBaseClass
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,
diff --git a/tls/gnutls/gtlsclientconnection-gnutls.c b/tls/gnutls/gtlsclientconnection-gnutls.c
index 7df0488..bd67fc1 100644
--- a/tls/gnutls/gtlsclientconnection-gnutls.c
+++ b/tls/gnutls/gtlsclientconnection-gnutls.c
@@ -573,11 +573,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;
@@ -586,6 +594,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 cc07c1f..c072a1d 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,45 @@ 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;
+ }
}
+ 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 +248,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
@@ -907,6 +974,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 GTlsProtocolVersion
glib_protocol_version_from_gnutls (gnutls_protocol_t protocol_version)
{
@@ -949,7 +1079,6 @@ get_ciphersuite_name (gnutls_session_t session)
return g_strdup_printf ("TLS_%s_%s",
gnutls_cipher_get_name (gnutls_cipher_get (session)),
gnutls_digest_get_name (gnutls_prf_hash_get (session)));
-
}
static void
@@ -1427,6 +1556,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 648645c..4c49c56 100644
--- a/tls/openssl/gtlsconnection-openssl.c
+++ b/tls/openssl/gtlsconnection-openssl.c
@@ -484,6 +484,41 @@ g_tls_connection_openssl_prepare_handshake (GTlsConnectionBase *tls,
}
#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;
+}
+
static GTlsProtocolVersion
glib_protocol_version_from_openssl (int protocol_version)
{
@@ -1039,6 +1074,7 @@ 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;
base_class->complete_handshake = g_tls_connection_openssl_complete_handshake;
base_class->handshake_thread_safe_renegotiation_status =
g_tls_connection_openssl_handshake_thread_safe_renegotiation_status;
base_class->handshake_thread_request_rehandshake =
g_tls_connection_openssl_handshake_thread_request_rehandshake;
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]