[glib-networking/use-default-verify-paths: 1/2] wip
- From: Ignacio Casal Quinteiro <icq src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [glib-networking/use-default-verify-paths: 1/2] wip
- Date: Thu, 14 Feb 2019 10:35:58 +0000 (UTC)
commit 33df709b0222a37c510faf9eec0441c79c1d4a8f
Author: Ignacio Casal Quinteiro <qignacio amazon com>
Date: Tue Feb 12 09:25:18 2019 +0100
wip
tls/openssl/gtlsbackend-openssl.c | 80 +---
tls/openssl/gtlsbackend-openssl.h | 12 +-
tls/openssl/gtlsconnection-openssl.c | 6 +-
tls/openssl/gtlsdatabase-openssl.c | 764 ++++++++++++++++++++++++++++++++-
tls/openssl/gtlsdatabase-openssl.h | 28 +-
tls/openssl/gtlsfiledatabase-openssl.c | 762 ++------------------------------
tls/openssl/gtlsfiledatabase-openssl.h | 28 +-
7 files changed, 843 insertions(+), 837 deletions(-)
---
diff --git a/tls/openssl/gtlsbackend-openssl.c b/tls/openssl/gtlsbackend-openssl.c
index 96428ac..67971c1 100644
--- a/tls/openssl/gtlsbackend-openssl.c
+++ b/tls/openssl/gtlsbackend-openssl.c
@@ -36,16 +36,17 @@
#include "gtlsclientconnection-openssl.h"
#include "gtlsfiledatabase-openssl.h"
-typedef struct _GTlsBackendOpensslPrivate
+struct _GTlsBackendOpenssl
{
+ GObject parent_instance;
+
GMutex mutex;
GTlsDatabase *default_database;
-} GTlsBackendOpensslPrivate;
+};
static void g_tls_backend_openssl_interface_init (GTlsBackendInterface *iface);
G_DEFINE_DYNAMIC_TYPE_EXTENDED (GTlsBackendOpenssl, g_tls_backend_openssl, G_TYPE_OBJECT, 0,
- G_ADD_PRIVATE_DYNAMIC (GTlsBackendOpenssl)
G_IMPLEMENT_INTERFACE_DYNAMIC (G_TYPE_TLS_BACKEND,
g_tls_backend_openssl_interface_init))
@@ -144,12 +145,8 @@ gtls_openssl_init (gpointer data)
static GOnce openssl_inited = G_ONCE_INIT;
static void
-g_tls_backend_openssl_init (GTlsBackendOpenssl *backend)
+g_tls_backend_openssl_init (GTlsBackendOpenssl *self)
{
- GTlsBackendOpensslPrivate *priv;
-
- priv = g_tls_backend_openssl_get_instance_private (backend);
-
/* Once we call gtls_openssl_init(), we can't allow the module to be
* unloaded (since if openssl gets unloaded but gcrypt doesn't, then
* gcrypt will have dangling pointers to openssl's mutex functions).
@@ -159,21 +156,17 @@ g_tls_backend_openssl_init (GTlsBackendOpenssl *backend)
*/
g_once (&openssl_inited, gtls_openssl_init, NULL);
- g_mutex_init (&priv->mutex);
+ g_mutex_init (&self->mutex);
}
static void
g_tls_backend_openssl_finalize (GObject *object)
{
+ GTlsBackendOpenssl *self = G_TLS_BACKEND_OPENSSL (object);
int i;
- GTlsBackendOpenssl *backend = G_TLS_BACKEND_OPENSSL (object);
- GTlsBackendOpensslPrivate *priv;
-
- priv = g_tls_backend_openssl_get_instance_private (backend);
-
- g_clear_object (&priv->default_database);
- g_mutex_clear (&priv->mutex);
+ g_clear_object (&self->default_database);
+ g_mutex_clear (&self->mutex);
CRYPTO_set_id_callback (NULL);
CRYPTO_set_locking_callback (NULL);
@@ -187,49 +180,12 @@ g_tls_backend_openssl_finalize (GObject *object)
G_OBJECT_CLASS (g_tls_backend_openssl_parent_class)->finalize (object);
}
-static GTlsDatabase *
-g_tls_backend_openssl_real_create_database (GTlsBackendOpenssl *self,
- GError **error)
-{
- gchar *anchor_file = NULL;
- GTlsDatabase *database;
-
-#ifdef G_OS_WIN32
- if (g_getenv ("G_TLS_OPENSSL_HANDLE_CERT_RELOCATABLE") != NULL)
- {
- gchar *module_dir;
-
- module_dir = g_win32_get_package_installation_directory_of_module (NULL);
- anchor_file = g_build_filename (module_dir, "bin", "cert.pem", NULL);
- g_free (module_dir);
- }
-#endif
-
- if (anchor_file == NULL)
- {
- const gchar *openssl_cert_file;
-
- openssl_cert_file = g_getenv (X509_get_default_cert_file_env ());
- if (openssl_cert_file == NULL)
- openssl_cert_file = X509_get_default_cert_file ();
-
- anchor_file = g_strdup (openssl_cert_file);
- }
-
- database = g_tls_file_database_new (anchor_file, error);
- g_free (anchor_file);
-
- return database;
-}
-
static void
g_tls_backend_openssl_class_init (GTlsBackendOpensslClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
gobject_class->finalize = g_tls_backend_openssl_finalize;
-
- klass->create_database = g_tls_backend_openssl_real_create_database;
}
static void
@@ -240,23 +196,19 @@ g_tls_backend_openssl_class_finalize (GTlsBackendOpensslClass *backend_class)
static GTlsDatabase*
g_tls_backend_openssl_get_default_database (GTlsBackend *backend)
{
- GTlsBackendOpenssl *openssl_backend = G_TLS_BACKEND_OPENSSL (backend);
- GTlsBackendOpensslPrivate *priv;
+ GTlsBackendOpenssl *self = G_TLS_BACKEND_OPENSSL (backend);
GTlsDatabase *result;
GError *error = NULL;
- priv = g_tls_backend_openssl_get_instance_private (openssl_backend);
-
- g_mutex_lock (&priv->mutex);
+ g_mutex_lock (&self->mutex);
- if (priv->default_database)
+ if (self->default_database)
{
- result = g_object_ref (priv->default_database);
+ result = g_object_ref (self->default_database);
}
else
{
- g_assert (G_TLS_BACKEND_OPENSSL_GET_CLASS (openssl_backend)->create_database);
- result = G_TLS_BACKEND_OPENSSL_GET_CLASS (openssl_backend)->create_database (openssl_backend, &error);
+ result = G_TLS_DATABASE (g_tls_database_openssl_new (&error));
if (error)
{
g_warning ("Couldn't load TLS file database: %s",
@@ -266,11 +218,11 @@ g_tls_backend_openssl_get_default_database (GTlsBackend *backend)
else
{
g_assert (result);
- priv->default_database = g_object_ref (result);
+ self->default_database = g_object_ref (result);
}
}
- g_mutex_unlock (&priv->mutex);
+ g_mutex_unlock (&self->mutex);
return result;
}
diff --git a/tls/openssl/gtlsbackend-openssl.h b/tls/openssl/gtlsbackend-openssl.h
index 410b0fb..3ee4c7d 100644
--- a/tls/openssl/gtlsbackend-openssl.h
+++ b/tls/openssl/gtlsbackend-openssl.h
@@ -30,16 +30,8 @@
G_BEGIN_DECLS
#define G_TYPE_TLS_BACKEND_OPENSSL (g_tls_backend_openssl_get_type ())
-G_DECLARE_DERIVABLE_TYPE (GTlsBackendOpenssl, g_tls_backend_openssl,
- G, TLS_BACKEND_OPENSSL, GObject)
-
-struct _GTlsBackendOpensslClass
-{
- GObjectClass parent_class;
-
- GTlsDatabase* (*create_database) (GTlsBackendOpenssl *backend,
- GError **error);
-};
+G_DECLARE_FINAL_TYPE (GTlsBackendOpenssl, g_tls_backend_openssl,
+ G, TLS_BACKEND_OPENSSL, GObject)
void g_tls_backend_openssl_register (GIOModule *module);
diff --git a/tls/openssl/gtlsconnection-openssl.c b/tls/openssl/gtlsconnection-openssl.c
index 9b4b9b4..4b363fa 100644
--- a/tls/openssl/gtlsconnection-openssl.c
+++ b/tls/openssl/gtlsconnection-openssl.c
@@ -300,9 +300,9 @@ verify_ocsp_response (GTlsConnectionOpenssl *openssl,
if (resp == NULL)
return G_TLS_CERTIFICATE_GENERIC_ERROR;
- return g_tls_file_database_openssl_verify_ocsp_response (database,
- peer_certificate,
- resp);
+ return g_tls_database_openssl_verify_ocsp_response (G_TLS_DATABASE_OPENSSL (database),
+ peer_certificate,
+ resp);
#else
return 0;
#endif
diff --git a/tls/openssl/gtlsdatabase-openssl.c b/tls/openssl/gtlsdatabase-openssl.c
index 93461a2..b6a725a 100644
--- a/tls/openssl/gtlsdatabase-openssl.c
+++ b/tls/openssl/gtlsdatabase-openssl.c
@@ -1,5 +1,5 @@
/*
- * gtlsdatabase-openssl.c
+ * gtlsfiledatabase-openssl.c
*
* Copyright (C) 2015 NICE s.r.l.
*
@@ -26,14 +26,772 @@
#include "gtlsdatabase-openssl.h"
-G_DEFINE_ABSTRACT_TYPE (GTlsDatabaseOpenssl, g_tls_database_openssl, G_TYPE_TLS_DATABASE)
+#include <gio/gio.h>
+#include <glib/gi18n-lib.h>
+#include "openssl-include.h"
+
+typedef struct _GTlsDatabaseOpensslPrivate
+{
+ /*
+ * This class is protected by mutex because the default GTlsDatabase
+ * is a global singleton, accessible via the default GTlsBackend.
+ */
+ GMutex mutex;
+
+ /* read-only after construct */
+ X509_STORE *store;
+
+ /*
+ * These are hash tables of gulong -> GPtrArray<GBytes>. The values of
+ * the ptr array are full DER encoded certificate values. The keys are byte
+ * arrays containing either subject DNs, issuer DNs, or full DER encoded certs
+ */
+ GHashTable *subjects;
+ GHashTable *issuers;
+
+ /*
+ * This is a table of GBytes -> GBytes. The values and keys are
+ * DER encoded certificate values.
+ */
+ GHashTable *complete;
+
+ /*
+ * This is a table of gchar * -> GPtrArray<GBytes>. The values of
+ * the ptr array are full DER encoded certificate values. The keys are the
+ * string handles. This array is populated on demand.
+ */
+ GHashTable *handles;
+} GTlsDatabaseOpensslPrivate;
+
+static void g_tls_database_openssl_initable_interface_init (GInitableIface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (GTlsDatabaseOpenssl, g_tls_database_openssl, G_TYPE_TLS_DATABASE,
+ G_ADD_PRIVATE (GTlsDatabaseOpenssl)
+ G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE,
+ g_tls_database_openssl_initable_interface_init))
+
+static GHashTable *
+bytes_multi_table_new (void)
+{
+ return g_hash_table_new_full (g_int_hash, g_int_equal,
+ (GDestroyNotify)g_free,
+ (GDestroyNotify)g_ptr_array_unref);
+}
+
+static void
+bytes_multi_table_insert (GHashTable *table,
+ gulong key,
+ GBytes *value)
+{
+ GPtrArray *multi;
+
+ multi = g_hash_table_lookup (table, &key);
+ if (multi == NULL)
+ {
+ int *key_ptr;
+
+ key_ptr = g_new (int, 1);
+ *key_ptr = (int)key;
+ multi = g_ptr_array_new_with_free_func ((GDestroyNotify)g_bytes_unref);
+ g_hash_table_insert (table, key_ptr, multi);
+ }
+ g_ptr_array_add (multi, g_bytes_ref (value));
+}
+
+static GBytes *
+bytes_multi_table_lookup_ref_one (GHashTable *table,
+ gulong key)
+{
+ GPtrArray *multi;
+
+ multi = g_hash_table_lookup (table, &key);
+ if (multi == NULL)
+ return NULL;
+
+ g_assert (multi->len > 0);
+ return g_bytes_ref (multi->pdata[0]);
+}
+
+static GList *
+bytes_multi_table_lookup_ref_all (GHashTable *table,
+ gulong key)
+{
+ GPtrArray *multi;
+ GList *list = NULL;
+ guint i;
+
+ multi = g_hash_table_lookup (table, &key);
+ if (multi == NULL)
+ return NULL;
+
+ for (i = 0; i < multi->len; i++)
+ list = g_list_prepend (list, g_bytes_ref (multi->pdata[i]));
+
+ return g_list_reverse (list);
+}
+
+static GHashTable *
+create_handles_array_unlocked (GTlsDatabaseOpenssl *self,
+ GHashTable *complete)
+{
+ GHashTable *handles;
+ GHashTableIter iter;
+ GBytes *der;
+ gchar *handle;
+
+ handles = g_hash_table_new_full (g_str_hash, g_str_equal, g_free,
+ (GDestroyNotify)g_bytes_unref);
+
+ g_hash_table_iter_init (&iter, complete);
+ while (g_hash_table_iter_next (&iter, NULL, (gpointer *)&der))
+ {
+ g_assert (G_TLS_DATABASE_OPENSSL_GET_CLASS (self)->create_handle_for_certificate);
+ handle = G_TLS_DATABASE_OPENSSL_GET_CLASS (self)->create_handle_for_certificate (self, der);
+ if (handle != NULL)
+ g_hash_table_insert (handles, handle, g_bytes_ref (der));
+ }
+
+ return handles;
+}
+
+static gboolean
+initialize_tables (X509_STORE *store,
+ GHashTable *subjects,
+ GHashTable *issuers,
+ GHashTable *complete)
+{
+ X509_STORE_CTX *store_ctx;
+ STACK_OF(X509) *chain = NULL;
+ gboolean ret = FALSE;
+ int i;
+
+ store_ctx = X509_STORE_CTX_new ();
+ if (store_ctx == NULL)
+ return FALSE;
+
+ if (!X509_STORE_CTX_init (store_ctx, store, NULL, NULL))
+ goto out;
+
+ chain = X509_STORE_CTX_get1_chain (store_ctx);
+
+ for (i = 0; i < sk_X509_num (chain); i++)
+ {
+ X509 *x;
+ unsigned long subject;
+ unsigned long issuer;
+ guint8 *data;
+ int size;
+ GBytes *der;
+
+ x = sk_X509_value (chain, i);
+ subject = X509_subject_name_hash (x);
+ issuer = X509_issuer_name_hash (x);
+
+ size = i2d_X509 (x, &data);
+ der = g_bytes_new_take (der, size);
+
+ g_hash_table_insert (complete, g_bytes_ref (der),
+ g_bytes_ref (der));
+
+ bytes_multi_table_insert (subjects, subject, der);
+ bytes_multi_table_insert (issuers, issuer, der);
+
+ g_bytes_unref (der);
+ }
+
+ ret = TRUE;
+
+out:
+ X509_STORE_CTX_free (store_ctx);
+
+ if (chain)
+ sk_X509_pop_free (chain, X509_free);
+
+ return ret;
+}
+
+static void
+g_tls_database_openssl_finalize (GObject *object)
+{
+ GTlsDatabaseOpenssl *self = G_TLS_DATABASE_OPENSSL (object);
+ GTlsDatabaseOpensslPrivate *priv;
+
+ priv = g_tls_database_openssl_get_instance_private (self);
+
+ g_clear_pointer (&priv->subjects, g_hash_table_destroy);
+ g_clear_pointer (&priv->issuers, g_hash_table_destroy);
+ g_clear_pointer (&priv->complete, g_hash_table_destroy);
+ g_clear_pointer (&priv->handles, g_hash_table_destroy);
+
+ if (priv->store != NULL)
+ X509_STORE_free (priv->store);
+
+ g_mutex_clear (&priv->mutex);
+
+ G_OBJECT_CLASS (g_tls_database_openssl_parent_class)->finalize (object);
+}
+
+static void
+g_tls_database_openssl_init (GTlsDatabaseOpenssl *self)
+{
+ GTlsDatabaseOpensslPrivate *priv;
+
+ priv = g_tls_database_openssl_get_instance_private (self);
+
+ g_mutex_init (&priv->mutex);
+}
+
+static gchar *
+g_tls_database_openssl_create_certificate_handle (GTlsDatabase *database,
+ GTlsCertificate *certificate)
+{
+ GTlsDatabaseOpenssl *self = G_TLS_DATABASE_OPENSSL (database);
+ GTlsDatabaseOpensslPrivate *priv;
+ GBytes *der;
+ gboolean contains;
+ gchar *handle = NULL;
+
+ priv = g_tls_database_openssl_get_instance_private (self);
+
+ der = g_tls_certificate_openssl_get_bytes (G_TLS_CERTIFICATE_OPENSSL (certificate));
+ g_return_val_if_fail (der != NULL, FALSE);
+
+ g_mutex_lock (&priv->mutex);
+
+ /* At the same time look up whether this certificate is in list */
+ contains = g_hash_table_lookup (priv->complete, der) ? TRUE : FALSE;
+
+ g_mutex_unlock (&priv->mutex);
+
+ /* Certificate is in the database */
+ if (contains)
+ {
+ g_assert (G_TLS_DATABASE_OPENSSL_GET_CLASS (self)->create_handle_for_certificate);
+ handle = G_TLS_DATABASE_OPENSSL_GET_CLASS (self)->create_handle_for_certificate (self, der);
+ }
+
+ g_bytes_unref (der);
+ return handle;
+}
+
+static GTlsCertificate *
+g_tls_database_openssl_lookup_certificate_for_handle (GTlsDatabase *database,
+ const gchar *handle,
+ GTlsInteraction *interaction,
+ GTlsDatabaseLookupFlags flags,
+ GCancellable *cancellable,
+ GError **error)
+{
+ GTlsDatabaseOpenssl *self = G_TLS_DATABASE_OPENSSL (database);
+ GTlsDatabaseOpensslPrivate *priv;
+ GTlsCertificate *cert;
+ GBytes *der;
+
+ priv = g_tls_database_openssl_get_instance_private (self);
+
+ if (g_cancellable_set_error_if_cancelled (cancellable, error))
+ return NULL;
+
+ if (!handle)
+ return NULL;
+
+
+ /* Create the handles table if not already done */
+ if (!priv->handles)
+ priv->handles = create_handles_array_unlocked (self, priv->complete);
+
+ der = g_hash_table_lookup (priv->handles, handle);
+ if (der != NULL)
+ g_bytes_ref (der);
+
+ g_mutex_unlock (&priv->mutex);
+
+ if (der == NULL)
+ return NULL;
+
+ if (g_cancellable_set_error_if_cancelled (cancellable, error))
+ cert = NULL;
+ else
+ cert = g_tls_certificate_openssl_new (der, NULL);
+
+ g_bytes_unref (der);
+ return cert;
+}
+
+static GTlsCertificate *
+g_tls_database_openssl_lookup_certificate_issuer (GTlsDatabase *database,
+ GTlsCertificate *certificate,
+ GTlsInteraction *interaction,
+ GTlsDatabaseLookupFlags flags,
+ GCancellable *cancellable,
+ GError **error)
+{
+ GTlsDatabaseOpenssl *self = G_TLS_DATABASE_OPENSSL (database);
+ GTlsDatabaseOpensslPrivate *priv;
+ X509 *x;
+ unsigned long issuer_hash;
+ GBytes *der;
+ GTlsCertificate *issuer = NULL;
+
+ priv = g_tls_database_openssl_get_instance_private (self);
+
+ g_return_val_if_fail (G_IS_TLS_CERTIFICATE_OPENSSL (certificate), NULL);
+
+ if (g_cancellable_set_error_if_cancelled (cancellable, error))
+ return NULL;
+
+ if (flags & G_TLS_DATABASE_LOOKUP_KEYPAIR)
+ return NULL;
+
+ /* Dig out the issuer of this certificate */
+ x = g_tls_certificate_openssl_get_cert (G_TLS_CERTIFICATE_OPENSSL (certificate));
+ issuer_hash = X509_issuer_name_hash (x);
+
+ g_mutex_lock (&priv->mutex);
+ der = bytes_multi_table_lookup_ref_one (priv->subjects, issuer_hash);
+ g_mutex_unlock (&priv->mutex);
+
+ if (g_cancellable_set_error_if_cancelled (cancellable, error))
+ issuer = NULL;
+ else if (der != NULL)
+ issuer = g_tls_certificate_openssl_new (der, NULL);
+
+ if (der != NULL)
+ g_bytes_unref (der);
+ return issuer;
+
+ return NULL;
+}
+
+static GList *
+g_tls_database_openssl_lookup_certificates_issued_by (GTlsDatabase *database,
+ GByteArray *issuer_raw_dn,
+ GTlsInteraction *interaction,
+ GTlsDatabaseLookupFlags flags,
+ GCancellable *cancellable,
+ GError **error)
+{
+ GTlsDatabaseOpenssl *self = G_TLS_DATABASE_OPENSSL (database);
+ GTlsDatabaseOpensslPrivate *priv;
+ X509_NAME *x_name;
+ const unsigned char *in;
+ GList *issued = NULL;
+
+ priv = g_tls_database_openssl_get_instance_private (self);
+
+ if (g_cancellable_set_error_if_cancelled (cancellable, error))
+ return NULL;
+
+ /* We don't have any private keys here */
+ if (flags & G_TLS_DATABASE_LOOKUP_KEYPAIR)
+ return NULL;
+
+ in = issuer_raw_dn->data;
+ x_name = d2i_X509_NAME (NULL, &in, issuer_raw_dn->len);
+ if (x_name != NULL)
+ {
+ unsigned long issuer_hash;
+ GList *ders, *l;
+
+ issuer_hash = X509_NAME_hash (x_name);
+
+ /* Find the full DER value of the certificate */
+ g_mutex_lock (&priv->mutex);
+ ders = bytes_multi_table_lookup_ref_all (priv->issuers, issuer_hash);
+ g_mutex_unlock (&priv->mutex);
+
+ for (l = ders; l != NULL; l = g_list_next (l))
+ {
+ if (g_cancellable_set_error_if_cancelled (cancellable, error))
+ {
+ g_list_free_full (issued, g_object_unref);
+ issued = NULL;
+ break;
+ }
+
+ issued = g_list_prepend (issued, g_tls_certificate_openssl_new (l->data, NULL));
+ }
+
+ g_list_free_full (ders, (GDestroyNotify)g_bytes_unref);
+ X509_NAME_free (x_name);
+ }
+
+ return issued;
+}
+
+static GTlsCertificateFlags
+double_check_before_after_dates (GTlsCertificateOpenssl *chain)
+{
+ GTlsCertificateFlags gtls_flags = 0;
+ X509 *cert;
+
+ while (chain)
+ {
+ ASN1_TIME *not_before;
+ ASN1_TIME *not_after;
+
+ cert = g_tls_certificate_openssl_get_cert (chain);
+ not_before = X509_get_notBefore (cert);
+ not_after = X509_get_notAfter (cert);
+
+ if (X509_cmp_current_time (not_before) > 0)
+ gtls_flags |= G_TLS_CERTIFICATE_NOT_ACTIVATED;
+
+ if (X509_cmp_current_time (not_after) < 0)
+ gtls_flags |= G_TLS_CERTIFICATE_EXPIRED;
+
+ chain = G_TLS_CERTIFICATE_OPENSSL (g_tls_certificate_get_issuer
+ (G_TLS_CERTIFICATE (chain)));
+ }
+
+ return gtls_flags;
+}
+
+static STACK_OF(X509) *
+convert_certificate_chain_to_openssl (GTlsCertificateOpenssl *chain)
+{
+ GTlsCertificate *cert;
+ STACK_OF(X509) *openssl_chain;
+
+ openssl_chain = sk_X509_new_null ();
+
+ for (cert = G_TLS_CERTIFICATE (chain); cert; cert = g_tls_certificate_get_issuer (cert))
+ sk_X509_push (openssl_chain, g_tls_certificate_openssl_get_cert (G_TLS_CERTIFICATE_OPENSSL (cert)));
+
+ return openssl_chain;
+}
+
+static GTlsCertificateFlags
+g_tls_database_openssl_verify_chain (GTlsDatabase *database,
+ GTlsCertificate *chain,
+ const gchar *purpose,
+ GSocketConnectable *identity,
+ GTlsInteraction *interaction,
+ GTlsDatabaseVerifyFlags flags,
+ GCancellable *cancellable,
+ GError **error)
+{
+ GTlsDatabaseOpenssl *self = G_TLS_DATABASE_OPENSSL (database);
+ GTlsDatabaseOpensslPrivate *priv;
+ STACK_OF(X509) *certs;
+ X509_STORE_CTX *csc;
+ X509 *x;
+ GTlsCertificateFlags result = 0;
+
+ g_return_val_if_fail (G_IS_TLS_CERTIFICATE_OPENSSL (chain),
+ G_TLS_CERTIFICATE_GENERIC_ERROR);
+
+ priv = g_tls_database_openssl_get_instance_private (self);
+
+ if (g_cancellable_set_error_if_cancelled (cancellable, error))
+ return G_TLS_CERTIFICATE_GENERIC_ERROR;
+
+ certs = convert_certificate_chain_to_openssl (G_TLS_CERTIFICATE_OPENSSL (chain));
+
+ csc = X509_STORE_CTX_new ();
+
+ x = g_tls_certificate_openssl_get_cert (G_TLS_CERTIFICATE_OPENSSL (chain));
+ if (!X509_STORE_CTX_init (csc, priv->store, x, certs))
+ {
+ X509_STORE_CTX_free (csc);
+ sk_X509_free (certs);
+ return G_TLS_CERTIFICATE_GENERIC_ERROR;
+ }
+
+ if (X509_verify_cert (csc) <= 0)
+ result = g_tls_certificate_openssl_convert_error (X509_STORE_CTX_get_error (csc));
+
+ X509_STORE_CTX_free (csc);
+ sk_X509_free (certs);
+
+ if (g_cancellable_set_error_if_cancelled (cancellable, error))
+ return G_TLS_CERTIFICATE_GENERIC_ERROR;
+
+ /* We have to check these ourselves since openssl
+ * does not give us flags and UNKNOWN_CA will take priority.
+ */
+ result |= double_check_before_after_dates (G_TLS_CERTIFICATE_OPENSSL (chain));
+
+ if (identity)
+ result |= g_tls_certificate_openssl_verify_identity (G_TLS_CERTIFICATE_OPENSSL (chain),
+ identity);
+
+ return result;
+}
+
+static gchar *
+g_tls_database_openssl_create_handle_for_certificate (GTlsDatabaseOpenssl *self,
+ GBytes *der)
+{
+ gchar *bookmark;
+ gchar *uri;
+
+ /*
+ * Here we create a URI that looks like
+ * system-trust:#11b2641821252596420e468c275771f5e51022c121a17bd7a89a2f37b6336c8f.
+ *
+ * system-trust is a meaningless URI scheme, and the handle does not
+ * even need to be a URI; this is just a nice stable way to uniquely
+ * identify a certificate.
+ */
+
+ bookmark = g_compute_checksum_for_bytes (G_CHECKSUM_SHA256, der);
+ uri = g_strconcat ("system-trust:#", bookmark, NULL);
+
+ g_free (bookmark);
+
+ return uri;
+}
+
+static gboolean
+g_tls_database_openssl_populate_trust_list (GTlsDatabaseOpenssl *self,
+ X509_STORE *store,
+ GError **error)
+{
+ X509_LOOKUP *lookup;
+
+ lookup = X509_STORE_add_lookup (store, X509_LOOKUP_file ());
+ if (lookup == NULL)
+ {
+ g_set_error (error, G_TLS_ERROR, G_TLS_ERROR_MISC,
+ _("Failed to load system trust store file: %s"),
+ ERR_error_string (ERR_get_error (), NULL));
+ return FALSE;
+ }
+
+ X509_LOOKUP_load_file (lookup, NULL, X509_FILETYPE_DEFAULT);
+
+ lookup = X509_STORE_add_lookup (store, X509_LOOKUP_hash_dir ());
+ if (lookup == NULL)
+ {
+ g_set_error (error, G_TLS_ERROR, G_TLS_ERROR_MISC,
+ _("Failed to load system trust store: %s"),
+ ERR_error_string (ERR_get_error (), NULL));
+ return FALSE;
+ }
+
+ X509_LOOKUP_add_dir (lookup, NULL, X509_FILETYPE_DEFAULT);
+
+ /* clear any errors */
+ ERR_clear_error ();
+
+ return TRUE;
+}
static void
g_tls_database_openssl_class_init (GTlsDatabaseOpensslClass *klass)
{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+ GTlsDatabaseClass *database_class = G_TLS_DATABASE_CLASS (klass);
+
+ gobject_class->finalize = g_tls_database_openssl_finalize;
+
+ database_class->create_certificate_handle = g_tls_database_openssl_create_certificate_handle;
+ database_class->lookup_certificate_for_handle = g_tls_database_openssl_lookup_certificate_for_handle;
+ database_class->lookup_certificate_issuer = g_tls_database_openssl_lookup_certificate_issuer;
+ database_class->lookup_certificates_issued_by = g_tls_database_openssl_lookup_certificates_issued_by;
+ database_class->verify_chain = g_tls_database_openssl_verify_chain;
+
+ klass->create_handle_for_certificate = g_tls_database_openssl_create_handle_for_certificate;
+ klass->populate_trust_list = g_tls_database_openssl_populate_trust_list;
+}
+
+static gboolean
+g_tls_database_openssl_initable_init (GInitable *initable,
+ GCancellable *cancellable,
+ GError **error)
+{
+ GTlsDatabaseOpenssl *self = G_TLS_DATABASE_OPENSSL (initable);
+ GTlsDatabaseOpensslPrivate *priv;
+ X509_STORE *store;
+ GHashTable *subjects, *issuers, *complete;
+ gboolean result;
+
+ priv = g_tls_database_openssl_get_instance_private (self);
+
+ if (g_cancellable_set_error_if_cancelled (cancellable, error))
+ return FALSE;
+
+ store = X509_STORE_new ();
+ if (store == NULL)
+ {
+ g_set_error_literal (error, G_TLS_ERROR, G_TLS_ERROR_MISC,
+ _("Could not create CA store"));
+ result = FALSE;
+ goto out;
+ }
+
+ g_assert (G_TLS_DATABASE_OPENSSL_GET_CLASS (self)->populate_trust_list);
+ if (!G_TLS_DATABASE_OPENSSL_GET_CLASS (self)->populate_trust_list (self, store, error))
+ {
+ result = FALSE;
+ goto out;
+ }
+
+ subjects = bytes_multi_table_new ();
+ issuers = bytes_multi_table_new ();
+
+ complete = g_hash_table_new_full (g_bytes_hash, g_bytes_equal,
+ (GDestroyNotify)g_bytes_unref,
+ (GDestroyNotify)g_bytes_unref);
+
+ if (!initialize_tables (store, subjects, issuers, complete))
+ {
+ g_set_error_literal (error, G_TLS_ERROR, G_TLS_ERROR_MISC,
+ _("Could not initialize certificate chain data"));
+ result = FALSE;
+ goto out;
+ }
+
+ if (g_cancellable_set_error_if_cancelled (cancellable, error))
+ result = FALSE;
+
+ if (result)
+ {
+ g_mutex_lock (&priv->mutex);
+ if (!priv->store)
+ {
+ priv->store = store;
+ store = NULL;
+ }
+
+ if (!priv->subjects)
+ {
+ priv->subjects = subjects;
+ subjects = NULL;
+ }
+
+ if (!priv->issuers)
+ {
+ priv->issuers = issuers;
+ issuers = NULL;
+ }
+
+ if (!priv->complete)
+ {
+ priv->complete = complete;
+ complete = NULL;
+ }
+
+ g_mutex_unlock (&priv->mutex);
+ }
+
+out:
+ if (store != NULL)
+ X509_STORE_free (store);
+ if (subjects != NULL)
+ g_hash_table_unref (subjects);
+ if (issuers != NULL)
+ g_hash_table_unref (issuers);
+ if (complete != NULL)
+ g_hash_table_unref (complete);
+
+ return result;
}
static void
-g_tls_database_openssl_init (GTlsDatabaseOpenssl *openssl)
+g_tls_database_openssl_initable_interface_init (GInitableIface *iface)
+{
+ iface->init = g_tls_database_openssl_initable_init;
+}
+
+GTlsDatabaseOpenssl *
+g_tls_database_openssl_new (GError **error)
+{
+ g_return_val_if_fail (!error || !*error, NULL);
+
+ return g_initable_new (G_TYPE_TLS_DATABASE_OPENSSL, NULL, error, NULL);
+}
+
+GTlsCertificateFlags
+g_tls_database_openssl_verify_ocsp_response (GTlsDatabaseOpenssl *self,
+ GTlsCertificate *chain,
+ OCSP_RESPONSE *resp)
{
+ GTlsCertificateFlags errors = 0;
+#if (OPENSSL_VERSION_NUMBER >= 0x0090808fL) && !defined(OPENSSL_NO_TLSEXT) && \
+ !defined(OPENSSL_NO_OCSP)
+ GTlsDatabaseOpensslPrivate *priv;
+ STACK_OF(X509) *chain_openssl = NULL;
+ OCSP_BASICRESP *basic_resp = NULL;
+ int ocsp_status = 0;
+ int i;
+
+ ocsp_status = OCSP_response_status (resp);
+ if (ocsp_status != OCSP_RESPONSE_STATUS_SUCCESSFUL)
+ {
+ errors = G_TLS_CERTIFICATE_GENERIC_ERROR;
+ goto end;
+ }
+
+ basic_resp = OCSP_response_get1_basic (resp);
+ if (basic_resp == NULL)
+ {
+ errors = G_TLS_CERTIFICATE_GENERIC_ERROR;
+ goto end;
+ }
+
+ chain_openssl = convert_certificate_chain_to_openssl (G_TLS_CERTIFICATE_OPENSSL (chain));
+ priv = g_tls_database_openssl_get_instance_private (self);
+ if ((chain_openssl == NULL) ||
+ (priv->store == NULL))
+ {
+ errors = G_TLS_CERTIFICATE_GENERIC_ERROR;
+ goto end;
+ }
+
+ if (OCSP_basic_verify (basic_resp, chain_openssl, priv->store, 0) <= 0)
+ {
+ errors = G_TLS_CERTIFICATE_GENERIC_ERROR;
+ goto end;
+ }
+
+ for (i = 0; i < OCSP_resp_count (basic_resp); i++)
+ {
+ OCSP_SINGLERESP *single_resp = OCSP_resp_get0 (basic_resp, i);
+ ASN1_GENERALIZEDTIME *revocation_time = NULL;
+ ASN1_GENERALIZEDTIME *this_update_time = NULL;
+ ASN1_GENERALIZEDTIME *next_update_time = NULL;
+ int crl_reason = 0;
+ int cert_status = 0;
+
+ if (single_resp == NULL)
+ continue;
+
+ cert_status = OCSP_single_get0_status (single_resp,
+ &crl_reason,
+ &revocation_time,
+ &this_update_time,
+ &next_update_time);
+ if (!OCSP_check_validity (this_update_time,
+ next_update_time,
+ 300L,
+ -1L))
+ {
+ errors = G_TLS_CERTIFICATE_GENERIC_ERROR;
+ goto end;
+ }
+
+ switch (cert_status)
+ {
+ case V_OCSP_CERTSTATUS_GOOD:
+ break;
+ case V_OCSP_CERTSTATUS_REVOKED:
+ errors = G_TLS_CERTIFICATE_REVOKED;
+ goto end;
+ case V_OCSP_CERTSTATUS_UNKNOWN:
+ errors = G_TLS_CERTIFICATE_GENERIC_ERROR;
+ goto end;
+ }
+ }
+
+end:
+ if (basic_resp != NULL)
+ OCSP_BASICRESP_free (basic_resp);
+
+ if (resp != NULL)
+ OCSP_RESPONSE_free (resp);
+
+#endif
+ return errors;
}
diff --git a/tls/openssl/gtlsdatabase-openssl.h b/tls/openssl/gtlsdatabase-openssl.h
index fd31352..b22b0b2 100644
--- a/tls/openssl/gtlsdatabase-openssl.h
+++ b/tls/openssl/gtlsdatabase-openssl.h
@@ -31,32 +31,26 @@
G_BEGIN_DECLS
-typedef enum {
- G_TLS_DATABASE_OPENSSL_PINNED_CERTIFICATE = 1,
- G_TLS_DATABASE_OPENSSL_ANCHORED_CERTIFICATE = 2,
-} GTlsDatabaseOpensslAssertion;
-
#define G_TYPE_TLS_DATABASE_OPENSSL (g_tls_database_openssl_get_type ())
-#define G_TLS_DATABASE_OPENSSL(inst) (G_TYPE_CHECK_INSTANCE_CAST ((inst),
G_TYPE_TLS_DATABASE_OPENSSL, GTlsDatabaseOpenssl))
-#define G_TLS_DATABASE_OPENSSL_CLASS(class) (G_TYPE_CHECK_CLASS_CAST ((class),
G_TYPE_TLS_DATABASE_OPENSSL, GTlsDatabaseOpensslClass))
-#define G_IS_TLS_DATABASE_OPENSSL(inst) (G_TYPE_CHECK_INSTANCE_TYPE ((inst),
G_TYPE_TLS_DATABASE_OPENSSL))
-#define G_IS_TLS_DATABASE_OPENSSL_CLASS(class) (G_TYPE_CHECK_CLASS_TYPE ((class),
G_TYPE_TLS_DATABASE_OPENSSL))
-#define G_TLS_DATABASE_OPENSSL_GET_CLASS(inst) (G_TYPE_INSTANCE_GET_CLASS ((inst),
G_TYPE_TLS_DATABASE_OPENSSL, GTlsDatabaseOpensslClass))
-typedef struct _GTlsDatabaseOpensslClass GTlsDatabaseOpensslClass;
-typedef struct _GTlsDatabaseOpenssl GTlsDatabaseOpenssl;
+G_DECLARE_DERIVABLE_TYPE (GTlsDatabaseOpenssl, g_tls_database_openssl, G, TLS_DATABASE_OPENSSL, GTlsDatabase)
struct _GTlsDatabaseOpensslClass
{
GTlsDatabaseClass parent_class;
-};
-struct _GTlsDatabaseOpenssl
-{
- GTlsDatabase parent_instance;
+ gchar *(*create_handle_for_certificate) (GTlsDatabaseOpenssl *self,
+ GBytes *der);
+ gboolean (*populate_trust_list) (GTlsDatabaseOpenssl *self,
+ X509_STORE *store,
+ GError **error);
};
-GType g_tls_database_openssl_get_type (void) G_GNUC_CONST;
+GTlsDatabaseOpenssl *g_tls_database_openssl_new (GError **error);
+
+GTlsCertificateFlags g_tls_database_openssl_verify_ocsp_response (GTlsDatabaseOpenssl *self,
+ GTlsCertificate *chain,
+ OCSP_RESPONSE *resp);
G_END_DECLS
diff --git a/tls/openssl/gtlsfiledatabase-openssl.c b/tls/openssl/gtlsfiledatabase-openssl.c
index e45a619..dd18c52 100644
--- a/tls/openssl/gtlsfiledatabase-openssl.c
+++ b/tls/openssl/gtlsfiledatabase-openssl.c
@@ -30,41 +30,12 @@
#include <glib/gi18n-lib.h>
#include "openssl-include.h"
-typedef struct _GTlsFileDatabaseOpensslPrivate
+struct _GTlsFileDatabaseOpenssl
{
+ GTlsDatabaseOpenssl parent_instance;
+
/* read-only after construct */
gchar *anchor_filename;
- STACK_OF(X509) *trusted;
-
- /* protected by mutex */
- GMutex mutex;
-
- /*
- * These are hash tables of gulong -> GPtrArray<GBytes>. The values of
- * the ptr array are full DER encoded certificate values. The keys are byte
- * arrays containing either subject DNs, issuer DNs, or full DER encoded certs
- */
- GHashTable *subjects;
- GHashTable *issuers;
-
- /*
- * This is a table of GBytes -> GBytes. The values and keys are
- * DER encoded certificate values.
- */
- GHashTable *complete;
-
- /*
- * This is a table of gchar * -> GTlsCertificate.
- */
- GHashTable *certs_by_handle;
-} GTlsFileDatabaseOpensslPrivate;
-
-enum {
- STATUS_FAILURE,
- STATUS_INCOMPLETE,
- STATUS_SELFSIGNED,
- STATUS_PINNED,
- STATUS_ANCHORED,
};
enum
@@ -75,177 +46,16 @@ enum
static void g_tls_file_database_openssl_file_database_interface_init (GTlsFileDatabaseInterface *iface);
-static void g_tls_file_database_openssl_initable_interface_init (GInitableIface *iface);
-
G_DEFINE_TYPE_WITH_CODE (GTlsFileDatabaseOpenssl, g_tls_file_database_openssl, G_TYPE_TLS_DATABASE_OPENSSL,
- G_ADD_PRIVATE (GTlsFileDatabaseOpenssl)
G_IMPLEMENT_INTERFACE (G_TYPE_TLS_FILE_DATABASE,
- g_tls_file_database_openssl_file_database_interface_init)
- G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE,
- g_tls_file_database_openssl_initable_interface_init))
-
-static GHashTable *
-bytes_multi_table_new (void)
-{
- return g_hash_table_new_full (g_int_hash, g_int_equal,
- (GDestroyNotify)g_free,
- (GDestroyNotify)g_ptr_array_unref);
-}
-
-static void
-bytes_multi_table_insert (GHashTable *table,
- gulong key,
- GBytes *value)
-{
- GPtrArray *multi;
-
- multi = g_hash_table_lookup (table, &key);
- if (multi == NULL)
- {
- int *key_ptr;
-
- key_ptr = g_new (int, 1);
- *key_ptr = (int)key;
- multi = g_ptr_array_new_with_free_func ((GDestroyNotify)g_bytes_unref);
- g_hash_table_insert (table, key_ptr, multi);
- }
- g_ptr_array_add (multi, g_bytes_ref (value));
-}
-
-static GBytes *
-bytes_multi_table_lookup_ref_one (GHashTable *table,
- gulong key)
-{
- GPtrArray *multi;
-
- multi = g_hash_table_lookup (table, &key);
- if (multi == NULL)
- return NULL;
-
- g_assert (multi->len > 0);
- return g_bytes_ref (multi->pdata[0]);
-}
-
-static GList *
-bytes_multi_table_lookup_ref_all (GHashTable *table,
- gulong key)
-{
- GPtrArray *multi;
- GList *list = NULL;
- guint i;
-
- multi = g_hash_table_lookup (table, &key);
- if (multi == NULL)
- return NULL;
-
- for (i = 0; i < multi->len; i++)
- list = g_list_prepend (list, g_bytes_ref (multi->pdata[i]));
-
- return g_list_reverse (list);
-}
-
-static gchar *
-create_handle_for_certificate (const gchar *filename,
- GBytes *der)
-{
- gchar *bookmark;
- gchar *uri_part;
- gchar *uri;
-
- /*
- * Here we create a URI that looks like:
- *
file:///etc/ssl/certs/ca-certificates.crt#11b2641821252596420e468c275771f5e51022c121a17bd7a89a2f37b6336c8f
- */
-
- uri_part = g_filename_to_uri (filename, NULL, NULL);
- if (!uri_part)
- return NULL;
-
- bookmark = g_compute_checksum_for_bytes (G_CHECKSUM_SHA256, der);
- uri = g_strconcat (uri_part, "#", bookmark, NULL);
-
- g_free (bookmark);
- g_free (uri_part);
-
- return uri;
-}
-
-static gboolean
-load_anchor_file (GTlsFileDatabaseOpenssl *file_database,
- const gchar *filename,
- GHashTable *subjects,
- GHashTable *issuers,
- GHashTable *complete,
- GHashTable *certs_by_handle,
- GError **error)
-{
- GTlsFileDatabaseOpensslPrivate *priv;
- GList *list;
- GList *l;
- GBytes *der;
- gchar *handle;
- GError *my_error = NULL;
-
- priv = g_tls_file_database_openssl_get_instance_private (file_database);
-
- list = g_tls_certificate_list_new_from_file (filename, &my_error);
- if (my_error)
- {
- g_propagate_error (error, my_error);
- return FALSE;
- }
-
- for (l = list; l; l = l->next)
- {
- X509 *x;
- unsigned long subject;
- unsigned long issuer;
-
- x = g_tls_certificate_openssl_get_cert (l->data);
- subject = X509_subject_name_hash (x);
- issuer = X509_issuer_name_hash (x);
-
- der = g_tls_certificate_openssl_get_bytes (l->data);
- g_return_val_if_fail (der != NULL, FALSE);
-
- g_hash_table_insert (complete, g_bytes_ref (der),
- g_bytes_ref (der));
-
- bytes_multi_table_insert (subjects, subject, der);
- bytes_multi_table_insert (issuers, issuer, der);
-
- handle = create_handle_for_certificate (priv->anchor_filename, der);
- g_hash_table_insert (certs_by_handle, handle, g_object_ref (l->data));
-
- g_bytes_unref (der);
-
- g_object_unref (l->data);
- }
- g_list_free (list);
-
- return TRUE;
-}
+ g_tls_file_database_openssl_file_database_interface_init))
static void
g_tls_file_database_openssl_finalize (GObject *object)
{
- GTlsFileDatabaseOpenssl *file_database = G_TLS_FILE_DATABASE_OPENSSL (object);
- GTlsFileDatabaseOpensslPrivate *priv;
-
- priv = g_tls_file_database_openssl_get_instance_private (file_database);
-
- g_clear_pointer (&priv->subjects, g_hash_table_destroy);
- g_clear_pointer (&priv->issuers, g_hash_table_destroy);
- g_clear_pointer (&priv->complete, g_hash_table_destroy);
- g_clear_pointer (&priv->certs_by_handle, g_hash_table_destroy);
-
- g_free (priv->anchor_filename);
- priv->anchor_filename = NULL;
+ GTlsFileDatabaseOpenssl *self = G_TLS_FILE_DATABASE_OPENSSL (object);
- if (priv->trusted != NULL)
- sk_X509_pop_free (priv->trusted, X509_free);
-
- g_mutex_clear (&priv->mutex);
+ g_free (self->anchor_filename);
G_OBJECT_CLASS (g_tls_file_database_openssl_parent_class)->finalize (object);
}
@@ -256,81 +66,27 @@ g_tls_file_database_openssl_get_property (GObject *object,
GValue *value,
GParamSpec *pspec)
{
- GTlsFileDatabaseOpenssl *file_database = G_TLS_FILE_DATABASE_OPENSSL (object);
- GTlsFileDatabaseOpensslPrivate *priv;
-
- priv = g_tls_file_database_openssl_get_instance_private (file_database);
+ GTlsFileDatabaseOpenssl *self = G_TLS_FILE_DATABASE_OPENSSL (object);
switch (prop_id)
{
case PROP_ANCHORS:
- g_value_set_string (value, priv->anchor_filename);
+ g_value_set_string (value, self->anchor_filename);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
-static STACK_OF(X509) *
-load_certs (const gchar *file_name)
-{
- BIO *bio;
- STACK_OF(X509) *certs;
- STACK_OF(X509_INFO) *xis = NULL;
- gint i;
-
- if (file_name == NULL)
- return NULL;
-
- bio = BIO_new_file (file_name, "rb");
- if (bio == NULL)
- return NULL;
-
- xis = PEM_X509_INFO_read_bio (bio, NULL, NULL, NULL);
-
- BIO_free (bio);
-
- certs = sk_X509_new_null ();
- if (certs == NULL)
- goto end;
-
- for (i = 0; i < sk_X509_INFO_num (xis); i++)
- {
- X509_INFO *xi;
-
- xi = sk_X509_INFO_value (xis, i);
- if (xi->x509 != NULL)
- {
- if (!sk_X509_push (certs, xi->x509))
- goto end;
- xi->x509 = NULL;
- }
- }
-
-end:
- sk_X509_INFO_pop_free (xis, X509_INFO_free);
-
- if (sk_X509_num (certs) == 0)
- {
- sk_X509_pop_free (certs, X509_free);
- certs = NULL;
- }
-
- return certs;
-}
-
static void
g_tls_file_database_openssl_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
- GTlsFileDatabaseOpenssl *file_database = G_TLS_FILE_DATABASE_OPENSSL (object);
- GTlsFileDatabaseOpensslPrivate *priv;
+ GTlsFileDatabaseOpenssl *self = G_TLS_FILE_DATABASE_OPENSSL (object);
const gchar *anchor_path;
- priv = g_tls_file_database_openssl_get_instance_private (file_database);
-
switch (prop_id)
{
case PROP_ANCHORS:
@@ -342,317 +98,75 @@ g_tls_file_database_openssl_set_property (GObject *object,
return;
}
- if (priv->anchor_filename)
- {
- g_free (priv->anchor_filename);
- if (priv->trusted != NULL)
- sk_X509_pop_free (priv->trusted, X509_free);
- }
-
- priv->anchor_filename = g_strdup (anchor_path);
- priv->trusted = load_certs (anchor_path);
+ g_free (self->anchor_filename);
+ self->anchor_filename = g_strdup (anchor_path);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
-static void
-g_tls_file_database_openssl_init (GTlsFileDatabaseOpenssl *file_database)
-{
- GTlsFileDatabaseOpensslPrivate *priv;
-
- priv = g_tls_file_database_openssl_get_instance_private (file_database);
-
- g_mutex_init (&priv->mutex);
-}
-
static gchar *
-g_tls_file_database_openssl_create_certificate_handle (GTlsDatabase *database,
- GTlsCertificate *certificate)
-{
- GTlsFileDatabaseOpenssl *file_database = G_TLS_FILE_DATABASE_OPENSSL (database);
- GTlsFileDatabaseOpensslPrivate *priv;
- GBytes *der;
- gboolean contains;
- gchar *handle = NULL;
-
- priv = g_tls_file_database_openssl_get_instance_private (file_database);
-
- der = g_tls_certificate_openssl_get_bytes (G_TLS_CERTIFICATE_OPENSSL (certificate));
- g_return_val_if_fail (der != NULL, FALSE);
-
- g_mutex_lock (&priv->mutex);
-
- /* At the same time look up whether this certificate is in list */
- contains = g_hash_table_lookup (priv->complete, der) ? TRUE : FALSE;
-
- g_mutex_unlock (&priv->mutex);
-
- /* Certificate is in the database */
- if (contains)
- handle = create_handle_for_certificate (priv->anchor_filename, der);
-
- g_bytes_unref (der);
- return handle;
-}
-
-static GTlsCertificate *
-g_tls_file_database_openssl_lookup_certificate_for_handle (GTlsDatabase *database,
- const gchar *handle,
- GTlsInteraction *interaction,
- GTlsDatabaseLookupFlags flags,
- GCancellable *cancellable,
- GError **error)
-{
- GTlsFileDatabaseOpenssl *file_database = G_TLS_FILE_DATABASE_OPENSSL (database);
- GTlsFileDatabaseOpensslPrivate *priv;
- GTlsCertificate *cert;
-
- priv = g_tls_file_database_openssl_get_instance_private (file_database);
-
- if (g_cancellable_set_error_if_cancelled (cancellable, error))
- return NULL;
-
- if (!handle)
- return NULL;
-
- g_mutex_lock (&priv->mutex);
-
- cert = g_hash_table_lookup (priv->certs_by_handle, handle);
-
- g_mutex_unlock (&priv->mutex);
-
- return cert ? g_object_ref (cert) : NULL;
-}
-
-static GTlsCertificate *
-g_tls_file_database_openssl_lookup_certificate_issuer (GTlsDatabase *database,
- GTlsCertificate *certificate,
- GTlsInteraction *interaction,
- GTlsDatabaseLookupFlags flags,
- GCancellable *cancellable,
- GError **error)
+g_tls_file_database_openssl_create_handle_for_certificate (GTlsDatabaseOpenssl *self,
+ GBytes *der)
{
- GTlsFileDatabaseOpenssl *file_database = G_TLS_FILE_DATABASE_OPENSSL (database);
- GTlsFileDatabaseOpensslPrivate *priv;
- X509 *x;
- unsigned long issuer_hash;
- GBytes *der;
- GTlsCertificate *issuer = NULL;
-
- priv = g_tls_file_database_openssl_get_instance_private (file_database);
-
- g_return_val_if_fail (G_IS_TLS_CERTIFICATE_OPENSSL (certificate), NULL);
-
- if (g_cancellable_set_error_if_cancelled (cancellable, error))
- return NULL;
-
- if (flags & G_TLS_DATABASE_LOOKUP_KEYPAIR)
- return NULL;
-
- /* Dig out the issuer of this certificate */
- x = g_tls_certificate_openssl_get_cert (G_TLS_CERTIFICATE_OPENSSL (certificate));
- issuer_hash = X509_issuer_name_hash (x);
-
- g_mutex_lock (&priv->mutex);
- der = bytes_multi_table_lookup_ref_one (priv->subjects, issuer_hash);
- g_mutex_unlock (&priv->mutex);
-
- if (g_cancellable_set_error_if_cancelled (cancellable, error))
- issuer = NULL;
- else if (der != NULL)
- issuer = g_tls_certificate_openssl_new (der, NULL);
-
- if (der != NULL)
- g_bytes_unref (der);
- return issuer;
-
- return NULL;
-}
-
-static GList *
-g_tls_file_database_openssl_lookup_certificates_issued_by (GTlsDatabase *database,
- GByteArray *issuer_raw_dn,
- GTlsInteraction *interaction,
- GTlsDatabaseLookupFlags flags,
- GCancellable *cancellable,
- GError **error)
-{
- GTlsFileDatabaseOpenssl *file_database = G_TLS_FILE_DATABASE_OPENSSL (database);
- GTlsFileDatabaseOpensslPrivate *priv;
- X509_NAME *x_name;
- const unsigned char *in;
- GList *issued = NULL;
-
- priv = g_tls_file_database_openssl_get_instance_private (file_database);
+ gchar *bookmark;
+ gchar *uri_part;
+ gchar *uri;
- if (g_cancellable_set_error_if_cancelled (cancellable, error))
- return NULL;
+ /*
+ * Here we create a URI that looks like:
+ *
file:///etc/ssl/certs/ca-certificates.crt#11b2641821252596420e468c275771f5e51022c121a17bd7a89a2f37b6336c8f
+ */
- /* We don't have any private keys here */
- if (flags & G_TLS_DATABASE_LOOKUP_KEYPAIR)
+ uri_part = g_filename_to_uri (G_TLS_FILE_DATABASE_OPENSSL (self)->anchor_filename,
+ NULL, NULL);
+ if (!uri_part)
return NULL;
- in = issuer_raw_dn->data;
- x_name = d2i_X509_NAME (NULL, &in, issuer_raw_dn->len);
- if (x_name != NULL)
- {
- unsigned long issuer_hash;
- GList *ders, *l;
-
- issuer_hash = X509_NAME_hash (x_name);
-
- /* Find the full DER value of the certificate */
- g_mutex_lock (&priv->mutex);
- ders = bytes_multi_table_lookup_ref_all (priv->issuers, issuer_hash);
- g_mutex_unlock (&priv->mutex);
-
- for (l = ders; l != NULL; l = g_list_next (l))
- {
- if (g_cancellable_set_error_if_cancelled (cancellable, error))
- {
- g_list_free_full (issued, g_object_unref);
- issued = NULL;
- break;
- }
-
- issued = g_list_prepend (issued, g_tls_certificate_openssl_new (l->data, NULL));
- }
+ bookmark = g_compute_checksum_for_bytes (G_CHECKSUM_SHA256, der);
+ uri = g_strconcat (uri_part, "#", bookmark, NULL);
- g_list_free_full (ders, (GDestroyNotify)g_bytes_unref);
- X509_NAME_free (x_name);
- }
+ g_free (bookmark);
+ g_free (uri_part);
- return issued;
+ return uri;
}
-static GTlsCertificateFlags
-double_check_before_after_dates (GTlsCertificateOpenssl *chain)
+static gboolean
+g_tls_file_database_openssl_populate_trust_list (GTlsDatabaseOpenssl *database,
+ X509_STORE *store,
+ GError **error)
{
- GTlsCertificateFlags gtls_flags = 0;
- X509 *cert;
+ GTlsFileDatabaseOpenssl *self = G_TLS_FILE_DATABASE_OPENSSL (database);
+ X509_LOOKUP *lookup;
- while (chain)
+ lookup = X509_STORE_add_lookup (store, X509_LOOKUP_file ());
+ if (lookup == NULL)
{
- ASN1_TIME *not_before;
- ASN1_TIME *not_after;
-
- cert = g_tls_certificate_openssl_get_cert (chain);
- not_before = X509_get_notBefore (cert);
- not_after = X509_get_notAfter (cert);
-
- if (X509_cmp_current_time (not_before) > 0)
- gtls_flags |= G_TLS_CERTIFICATE_NOT_ACTIVATED;
-
- if (X509_cmp_current_time (not_after) < 0)
- gtls_flags |= G_TLS_CERTIFICATE_EXPIRED;
-
- chain = G_TLS_CERTIFICATE_OPENSSL (g_tls_certificate_get_issuer
- (G_TLS_CERTIFICATE (chain)));
- }
-
- return gtls_flags;
-}
-
-static STACK_OF(X509) *
-convert_certificate_chain_to_openssl (GTlsCertificateOpenssl *chain)
-{
- GTlsCertificate *cert;
- STACK_OF(X509) *openssl_chain;
-
- openssl_chain = sk_X509_new_null ();
-
- for (cert = G_TLS_CERTIFICATE (chain); cert; cert = g_tls_certificate_get_issuer (cert))
- sk_X509_push (openssl_chain, g_tls_certificate_openssl_get_cert (G_TLS_CERTIFICATE_OPENSSL (cert)));
-
- return openssl_chain;
-}
-
-static GTlsCertificateFlags
-g_tls_file_database_openssl_verify_chain (GTlsDatabase *database,
- GTlsCertificate *chain,
- const gchar *purpose,
- GSocketConnectable *identity,
- GTlsInteraction *interaction,
- GTlsDatabaseVerifyFlags flags,
- GCancellable *cancellable,
- GError **error)
-{
- GTlsFileDatabaseOpenssl *file_database;
- GTlsFileDatabaseOpensslPrivate *priv;
- STACK_OF(X509) *certs;
- X509_STORE *store;
- X509_STORE_CTX *csc;
- X509 *x;
- GTlsCertificateFlags result = 0;
-
- g_return_val_if_fail (G_IS_TLS_CERTIFICATE_OPENSSL (chain),
- G_TLS_CERTIFICATE_GENERIC_ERROR);
-
- file_database = G_TLS_FILE_DATABASE_OPENSSL (database);
-
- priv = g_tls_file_database_openssl_get_instance_private (file_database);
-
- if (g_cancellable_set_error_if_cancelled (cancellable, error))
- return G_TLS_CERTIFICATE_GENERIC_ERROR;
-
- certs = convert_certificate_chain_to_openssl (G_TLS_CERTIFICATE_OPENSSL (chain));
-
- store = X509_STORE_new ();
- csc = X509_STORE_CTX_new ();
-
- x = g_tls_certificate_openssl_get_cert (G_TLS_CERTIFICATE_OPENSSL (chain));
- if (!X509_STORE_CTX_init (csc, store, x, certs))
- {
- X509_STORE_CTX_free (csc);
- X509_STORE_free (store);
- sk_X509_free (certs);
- return G_TLS_CERTIFICATE_GENERIC_ERROR;
- }
-
- if (priv->trusted)
- {
- X509_STORE_CTX_trusted_stack (csc, priv->trusted);
+ g_set_error (error, G_TLS_ERROR, G_TLS_ERROR_MISC,
+ _("Failed to load system trust store file: %s"),
+ ERR_error_string (ERR_get_error (), NULL));
+ return FALSE;
}
- if (X509_verify_cert (csc) <= 0)
- result = g_tls_certificate_openssl_convert_error (X509_STORE_CTX_get_error (csc));
-
- X509_STORE_CTX_free (csc);
- X509_STORE_free (store);
- sk_X509_free (certs);
+ X509_LOOKUP_load_file (lookup, self->anchor_filename, X509_FILETYPE_PEM);
- if (g_cancellable_set_error_if_cancelled (cancellable, error))
- return G_TLS_CERTIFICATE_GENERIC_ERROR;
-
- /* We have to check these ourselves since openssl
- * does not give us flags and UNKNOWN_CA will take priority.
- */
- result |= double_check_before_after_dates (G_TLS_CERTIFICATE_OPENSSL (chain));
-
- if (identity)
- result |= g_tls_certificate_openssl_verify_identity (G_TLS_CERTIFICATE_OPENSSL (chain),
- identity);
-
- return result;
+ return TRUE;
}
static void
g_tls_file_database_openssl_class_init (GTlsFileDatabaseOpensslClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
- GTlsDatabaseClass *database_class = G_TLS_DATABASE_CLASS (klass);
+ GTlsDatabaseOpensslClass *openssl_database_class = G_TLS_DATABASE_OPENSSL_CLASS (klass);
gobject_class->get_property = g_tls_file_database_openssl_get_property;
gobject_class->set_property = g_tls_file_database_openssl_set_property;
gobject_class->finalize = g_tls_file_database_openssl_finalize;
- database_class->create_certificate_handle = g_tls_file_database_openssl_create_certificate_handle;
- database_class->lookup_certificate_for_handle = g_tls_file_database_openssl_lookup_certificate_for_handle;
- database_class->lookup_certificate_issuer = g_tls_file_database_openssl_lookup_certificate_issuer;
- database_class->lookup_certificates_issued_by = g_tls_file_database_openssl_lookup_certificates_issued_by;
- database_class->verify_chain = g_tls_file_database_openssl_verify_chain;
+ openssl_database_class->create_handle_for_certificate =
g_tls_file_database_openssl_create_handle_for_certificate;
+ openssl_database_class->populate_trust_list = g_tls_file_database_openssl_populate_trust_list;
g_object_class_override_property (gobject_class, PROP_ANCHORS, "anchors");
}
@@ -662,191 +176,7 @@ g_tls_file_database_openssl_file_database_interface_init (GTlsFileDatabaseInterf
{
}
-static gboolean
-g_tls_file_database_openssl_initable_init (GInitable *initable,
- GCancellable *cancellable,
- GError **error)
-{
- GTlsFileDatabaseOpenssl *file_database = G_TLS_FILE_DATABASE_OPENSSL (initable);
- GTlsFileDatabaseOpensslPrivate *priv;
- GHashTable *subjects, *issuers, *complete, *certs_by_handle;
- gboolean result;
-
- priv = g_tls_file_database_openssl_get_instance_private (file_database);
-
- if (g_cancellable_set_error_if_cancelled (cancellable, error))
- return FALSE;
-
- subjects = bytes_multi_table_new ();
- issuers = bytes_multi_table_new ();
-
- complete = g_hash_table_new_full (g_bytes_hash, g_bytes_equal,
- (GDestroyNotify)g_bytes_unref,
- (GDestroyNotify)g_bytes_unref);
-
- certs_by_handle = g_hash_table_new_full (g_str_hash, g_str_equal,
- (GDestroyNotify)g_free,
- (GDestroyNotify)g_object_unref);
-
- if (priv->anchor_filename)
- result = load_anchor_file (file_database,
- priv->anchor_filename,
- subjects, issuers, complete,
- certs_by_handle,
- error);
- else
- result = TRUE;
-
- if (g_cancellable_set_error_if_cancelled (cancellable, error))
- result = FALSE;
-
- if (result)
- {
- g_mutex_lock (&priv->mutex);
- if (!priv->subjects)
- {
- priv->subjects = subjects;
- subjects = NULL;
- }
- if (!priv->issuers)
- {
- priv->issuers = issuers;
- issuers = NULL;
- }
- if (!priv->complete)
- {
- priv->complete = complete;
- complete = NULL;
- }
- if (!priv->certs_by_handle)
- {
- priv->certs_by_handle = certs_by_handle;
- certs_by_handle = NULL;
- }
- g_mutex_unlock (&priv->mutex);
- }
-
- if (subjects != NULL)
- g_hash_table_unref (subjects);
- if (issuers != NULL)
- g_hash_table_unref (issuers);
- if (complete != NULL)
- g_hash_table_unref (complete);
- if (certs_by_handle != NULL)
- g_hash_table_unref (certs_by_handle);
- return result;
-}
-
static void
-g_tls_file_database_openssl_initable_interface_init (GInitableIface *iface)
-{
- iface->init = g_tls_file_database_openssl_initable_init;
-}
-
-GTlsCertificateFlags
-g_tls_file_database_openssl_verify_ocsp_response (GTlsDatabase *database,
- GTlsCertificate *chain,
- OCSP_RESPONSE *resp)
+g_tls_file_database_openssl_init (GTlsFileDatabaseOpenssl *file_database)
{
- GTlsCertificateFlags errors = 0;
-#if (OPENSSL_VERSION_NUMBER >= 0x0090808fL) && !defined(OPENSSL_NO_TLSEXT) && \
- !defined(OPENSSL_NO_OCSP)
- GTlsFileDatabaseOpenssl *file_database;
- GTlsFileDatabaseOpensslPrivate *priv;
- STACK_OF(X509) *chain_openssl = NULL;
- X509_STORE *store = NULL;
- OCSP_BASICRESP *basic_resp = NULL;
- int ocsp_status = 0;
- int i;
-
- ocsp_status = OCSP_response_status (resp);
- if (ocsp_status != OCSP_RESPONSE_STATUS_SUCCESSFUL)
- {
- errors = G_TLS_CERTIFICATE_GENERIC_ERROR;
- goto end;
- }
-
- basic_resp = OCSP_response_get1_basic (resp);
- if (basic_resp == NULL)
- {
- errors = G_TLS_CERTIFICATE_GENERIC_ERROR;
- goto end;
- }
-
- chain_openssl = convert_certificate_chain_to_openssl (G_TLS_CERTIFICATE_OPENSSL (chain));
- file_database = G_TLS_FILE_DATABASE_OPENSSL (database);
- priv = g_tls_file_database_openssl_get_instance_private (file_database);
- store = X509_STORE_new ();
- if ((chain_openssl == NULL) ||
- (file_database == NULL) ||
- (priv == NULL) ||
- (priv->trusted == NULL) ||
- (store == NULL))
- {
- errors = G_TLS_CERTIFICATE_GENERIC_ERROR;
- goto end;
- }
-
- for (i = 0; i < sk_X509_num (priv->trusted); i++)
- {
- X509_STORE_add_cert (store, sk_X509_value (priv->trusted, i));
- }
-
- if (OCSP_basic_verify (basic_resp, chain_openssl, store, 0) <= 0)
- {
- errors = G_TLS_CERTIFICATE_GENERIC_ERROR;
- goto end;
- }
-
- for (i = 0; i < OCSP_resp_count (basic_resp); i++)
- {
- OCSP_SINGLERESP *single_resp = OCSP_resp_get0 (basic_resp, i);
- ASN1_GENERALIZEDTIME *revocation_time = NULL;
- ASN1_GENERALIZEDTIME *this_update_time = NULL;
- ASN1_GENERALIZEDTIME *next_update_time = NULL;
- int crl_reason = 0;
- int cert_status = 0;
-
- if (single_resp == NULL)
- continue;
-
- cert_status = OCSP_single_get0_status (single_resp,
- &crl_reason,
- &revocation_time,
- &this_update_time,
- &next_update_time);
- if (!OCSP_check_validity (this_update_time,
- next_update_time,
- 300L,
- -1L))
- {
- errors = G_TLS_CERTIFICATE_GENERIC_ERROR;
- goto end;
- }
-
- switch (cert_status)
- {
- case V_OCSP_CERTSTATUS_GOOD:
- break;
- case V_OCSP_CERTSTATUS_REVOKED:
- errors = G_TLS_CERTIFICATE_REVOKED;
- goto end;
- case V_OCSP_CERTSTATUS_UNKNOWN:
- errors = G_TLS_CERTIFICATE_GENERIC_ERROR;
- goto end;
- }
- }
-
-end:
- if (store != NULL)
- X509_STORE_free (store);
-
- if (basic_resp != NULL)
- OCSP_BASICRESP_free (basic_resp);
-
- if (resp != NULL)
- OCSP_RESPONSE_free (resp);
-
-#endif
- return errors;
}
diff --git a/tls/openssl/gtlsfiledatabase-openssl.h b/tls/openssl/gtlsfiledatabase-openssl.h
index 67086db..9efd769 100644
--- a/tls/openssl/gtlsfiledatabase-openssl.h
+++ b/tls/openssl/gtlsfiledatabase-openssl.h
@@ -32,30 +32,10 @@
G_BEGIN_DECLS
#define G_TYPE_TLS_FILE_DATABASE_OPENSSL (g_tls_file_database_openssl_get_type ())
-#define G_TLS_FILE_DATABASE_OPENSSL(inst) (G_TYPE_CHECK_INSTANCE_CAST ((inst),
G_TYPE_TLS_FILE_DATABASE_OPENSSL, GTlsFileDatabaseOpenssl))
-#define G_TLS_FILE_DATABASE_OPENSSL_CLASS(class) (G_TYPE_CHECK_CLASS_CAST ((class),
G_TYPE_TLS_FILE_DATABASE_OPENSSL, GTlsFileDatabaseOpensslClass))
-#define G_IS_TLS_FILE_DATABASE_OPENSSL(inst) (G_TYPE_CHECK_INSTANCE_TYPE ((inst),
G_TYPE_TLS_FILE_DATABASE_OPENSSL))
-#define G_IS_TLS_FILE_DATABASE_OPENSSL_CLASS(class) (G_TYPE_CHECK_CLASS_TYPE ((class),
G_TYPE_TLS_FILE_DATABASE_OPENSSL))
-#define G_TLS_FILE_DATABASE_OPENSSL_GET_CLASS(inst) (G_TYPE_INSTANCE_GET_CLASS ((inst),
G_TYPE_TLS_FILE_DATABASE_OPENSSL, GTlsFileDatabaseOpensslClass))
-
-typedef struct _GTlsFileDatabaseOpensslClass GTlsFileDatabaseOpensslClass;
-typedef struct _GTlsFileDatabaseOpenssl GTlsFileDatabaseOpenssl;
-
-struct _GTlsFileDatabaseOpensslClass
-{
- GTlsDatabaseOpensslClass parent_class;
-};
-
-struct _GTlsFileDatabaseOpenssl
-{
- GTlsDatabaseOpenssl parent_instance;
-};
-
-GType g_tls_file_database_openssl_get_type (void) G_GNUC_CONST;
-
-GTlsCertificateFlags g_tls_file_database_openssl_verify_ocsp_response (GTlsDatabase *database,
- GTlsCertificate *chain,
- OCSP_RESPONSE *resp);
+
+G_DECLARE_FINAL_TYPE (GTlsFileDatabaseOpenssl, g_tls_file_database_openssl, G, TLS_FILE_DATABASE_OPENSSL,
GTlsDatabaseOpenssl)
+
+GTlsDatabase *g_tls_file_database_openssl_new (const gchar *anchor_file);
G_END_DECLS
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]