[glib-networking/mcatanzaro/gnutls-creds] WIP: rewrite gnutls certificate verification
- From: Michael Catanzaro <mcatanzaro src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [glib-networking/mcatanzaro/gnutls-creds] WIP: rewrite gnutls certificate verification
- Date: Wed, 23 Jun 2021 00:23:36 +0000 (UTC)
commit 12e593855cc95a2a6189953da30298e53b67a04e
Author: Michael Catanzaro <mcatanzaro redhat com>
Date: Tue Jun 22 19:22:42 2021 -0500
WIP: rewrite gnutls certificate verification
/* 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().
*/
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 72551dc..541e2a4 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]