[glib-networking/wip/openssl] Move database code to the subclass
- From: Ignacio Casal Quinteiro <icq src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [glib-networking/wip/openssl] Move database code to the subclass
- Date: Mon, 8 Feb 2016 14:12:28 +0000 (UTC)
commit 811f137210dc91dae6935bd3c9e0357a2ba80aed
Author: Ignacio Casal Quinteiro <icq gnome org>
Date: Mon Feb 8 15:11:58 2016 +0100
Move database code to the subclass
tls/openssl/gtlsdatabase-openssl.c | 334 ---------------------------
tls/openssl/gtlsdatabase-openssl.h | 16 --
tls/openssl/gtlsfiledatabase-openssl.c | 391 ++++++++++++++++++++++++++++----
3 files changed, 346 insertions(+), 395 deletions(-)
---
diff --git a/tls/openssl/gtlsdatabase-openssl.c b/tls/openssl/gtlsdatabase-openssl.c
index 1942d82..93461a2 100644
--- a/tls/openssl/gtlsdatabase-openssl.c
+++ b/tls/openssl/gtlsdatabase-openssl.c
@@ -25,349 +25,15 @@
#include "config.h"
#include "gtlsdatabase-openssl.h"
-#include "gtlscertificate-openssl.h"
-
-#include <openssl/ssl.h>
-#include <glib/gi18n-lib.h>
G_DEFINE_ABSTRACT_TYPE (GTlsDatabaseOpenssl, g_tls_database_openssl, G_TYPE_TLS_DATABASE)
-enum {
- STATUS_FAILURE,
- STATUS_INCOMPLETE,
- STATUS_SELFSIGNED,
- STATUS_PINNED,
- STATUS_ANCHORED,
-};
-
-static gboolean
-is_self_signed (GTlsCertificateOpenssl *certificate)
-{
- X509 *cert;
- X509_STORE *store;
- X509_STORE_CTX csc;
- STACK_OF(X509) *trusted;
- gboolean ret = FALSE;
-
- store = X509_STORE_new ();
- cert = g_tls_certificate_openssl_get_cert (certificate);
-
- if (!X509_STORE_CTX_init(&csc, store, cert, NULL))
- goto end;
-
- trusted = sk_X509_new_null ();
- sk_X509_push (trusted, cert);
-
- X509_STORE_CTX_trusted_stack (&csc, trusted);
- X509_STORE_CTX_set_flags (&csc, X509_V_FLAG_CHECK_SS_SIGNATURE);
-
- ret = X509_verify_cert (&csc) > 0;
-
-end:
- X509_STORE_CTX_cleanup (&csc);
- X509_STORE_free (store);
-
- return ret;
-}
-
-static gint
-build_certificate_chain (GTlsDatabaseOpenssl *openssl,
- GTlsCertificateOpenssl *chain,
- const gchar *purpose,
- GSocketConnectable *identity,
- GTlsInteraction *interaction,
- GTlsDatabaseVerifyFlags flags,
- GCancellable *cancellable,
- GTlsCertificateOpenssl **anchor,
- GError **error)
-{
-
- GTlsCertificateOpenssl *certificate;
- GTlsCertificateOpenssl *previous;
- GTlsCertificate *issuer;
- gboolean certificate_is_from_db;
-
- g_assert (anchor);
- g_assert (chain);
- g_assert (purpose);
- g_assert (error);
- g_assert (!*error);
-
- /*
- * Remember that the first certificate never changes in the chain.
- * When we find a self-signed, pinned or anchored certificate, all
- * issuers are truncated from the chain.
- */
-
- *anchor = NULL;
- previous = NULL;
- certificate = chain;
- certificate_is_from_db = FALSE;
-
- /* First check for pinned certificate */
- if (g_tls_database_openssl_lookup_assertion (openssl, certificate,
- G_TLS_DATABASE_OPENSSL_PINNED_CERTIFICATE,
- purpose, identity, cancellable, error))
- {
- g_tls_certificate_openssl_set_issuer (certificate, NULL);
- return STATUS_PINNED;
- }
- else if (*error)
- {
- return STATUS_FAILURE;
- }
-
- for (;;)
- {
- if (g_cancellable_set_error_if_cancelled (cancellable, error))
- return STATUS_FAILURE;
-
- /* Look up whether this certificate is an anchor */
- if (g_tls_database_openssl_lookup_assertion (openssl, certificate,
- G_TLS_DATABASE_OPENSSL_ANCHORED_CERTIFICATE,
- purpose, identity, cancellable, error))
- {
- g_tls_certificate_openssl_set_issuer (certificate, NULL);
- *anchor = certificate;
- return STATUS_ANCHORED;
- }
- else if (*error)
- {
- return STATUS_FAILURE;
- }
-
- /* Is it self-signed? */
- if (is_self_signed (certificate))
- {
- /*
- * Since at this point we would fail with 'self-signed', can we replace
- * this certificate with one from the database and do better?
- */
- if (previous && !certificate_is_from_db)
- {
- issuer = g_tls_database_lookup_certificate_issuer (G_TLS_DATABASE (openssl),
- G_TLS_CERTIFICATE (previous),
- interaction,
- G_TLS_DATABASE_LOOKUP_NONE,
- cancellable, error);
- if (*error)
- {
- return STATUS_FAILURE;
- }
- else if (issuer)
- {
- /* Replaced with certificate in the db, restart step again with this certificate */
- g_return_val_if_fail (G_IS_TLS_CERTIFICATE_OPENSSL (issuer), STATUS_FAILURE);
- g_tls_certificate_openssl_set_issuer (previous, G_TLS_CERTIFICATE_OPENSSL (issuer));
- certificate = G_TLS_CERTIFICATE_OPENSSL (issuer);
- certificate_is_from_db = TRUE;
- g_object_unref (issuer);
- continue;
- }
- }
-
- g_tls_certificate_openssl_set_issuer (certificate, NULL);
- return STATUS_SELFSIGNED;
- }
-
- previous = certificate;
-
- /* Bring over the next certificate in the chain */
- issuer = g_tls_certificate_get_issuer (G_TLS_CERTIFICATE (certificate));
- if (issuer)
- {
- g_return_val_if_fail (G_IS_TLS_CERTIFICATE_OPENSSL (issuer), STATUS_FAILURE);
- certificate = G_TLS_CERTIFICATE_OPENSSL (issuer);
- certificate_is_from_db = FALSE;
- }
-
- /* Search for the next certificate in chain */
- else
- {
- issuer = g_tls_database_lookup_certificate_issuer (G_TLS_DATABASE (openssl),
- G_TLS_CERTIFICATE (certificate),
- interaction,
- G_TLS_DATABASE_LOOKUP_NONE,
- cancellable, error);
- if (*error)
- return STATUS_FAILURE;
- else if (!issuer)
- return STATUS_INCOMPLETE;
-
- /* Found a certificate in chain, use for next step */
- g_return_val_if_fail (G_IS_TLS_CERTIFICATE_OPENSSL (issuer), STATUS_FAILURE);
- g_tls_certificate_openssl_set_issuer (certificate, G_TLS_CERTIFICATE_OPENSSL (issuer));
- certificate = G_TLS_CERTIFICATE_OPENSSL (issuer);
- certificate_is_from_db = TRUE;
- g_object_unref (issuer);
- }
- }
-
- g_assert_not_reached ();
-}
-
-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 *openssl;
- GTlsCertificateOpenssl *anchor;
- STACK_OF(X509) *certs, *anchors;
- X509_STORE *store;
- X509_STORE_CTX csc;
- X509 *x;
- gint status;
- GTlsCertificateFlags result = 0;
- GError *err = NULL;
-
- g_return_val_if_fail (G_IS_TLS_CERTIFICATE_OPENSSL (chain),
- G_TLS_CERTIFICATE_GENERIC_ERROR);
-
- openssl = G_TLS_DATABASE_OPENSSL (database);
- anchor = NULL;
-
- status = build_certificate_chain (openssl, G_TLS_CERTIFICATE_OPENSSL (chain), purpose,
- identity, interaction, flags, cancellable, &anchor, &err);
- if (status == STATUS_FAILURE)
- {
- g_propagate_error (error, err);
- return G_TLS_CERTIFICATE_GENERIC_ERROR;
- }
-
- /*
- * A pinned certificate is verified on its own, without any further
- * verification.
- */
- if (status == STATUS_PINNED)
- return 0;
-
- 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 ();
-
- x = g_tls_certificate_openssl_get_cert (G_TLS_CERTIFICATE_OPENSSL (chain));
- if (!X509_STORE_CTX_init(&csc, store, x, certs))
- {
- X509_STORE_CTX_cleanup (&csc);
- X509_STORE_free (store);
- return G_TLS_CERTIFICATE_GENERIC_ERROR;
- }
-
- if (anchor)
- {
- g_assert (g_tls_certificate_get_issuer (G_TLS_CERTIFICATE (anchor)) == NULL);
- anchors = convert_certificate_chain_to_openssl (G_TLS_CERTIFICATE_OPENSSL (anchor));
- X509_STORE_CTX_trusted_stack (&csc, anchors);
- }
- else
- anchors = NULL;
-
- if (X509_verify_cert (&csc) <= 0)
- result = g_tls_certificate_openssl_convert_error (X509_STORE_CTX_get_error (&csc));
-
- X509_STORE_CTX_cleanup (&csc);
- X509_STORE_free (store);
-
- 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 void
g_tls_database_openssl_class_init (GTlsDatabaseOpensslClass *klass)
{
- GTlsDatabaseClass *database_class = G_TLS_DATABASE_CLASS (klass);
-
- database_class->verify_chain = g_tls_database_openssl_verify_chain;
}
static void
g_tls_database_openssl_init (GTlsDatabaseOpenssl *openssl)
{
}
-
-gboolean
-g_tls_database_openssl_lookup_assertion (GTlsDatabaseOpenssl *openssl,
- GTlsCertificateOpenssl *certificate,
- GTlsDatabaseOpensslAssertion assertion,
- const gchar *purpose,
- GSocketConnectable *identity,
- GCancellable *cancellable,
- GError **error)
-{
- g_return_val_if_fail (G_IS_TLS_DATABASE_OPENSSL (openssl), FALSE);
- g_return_val_if_fail (G_IS_TLS_CERTIFICATE_OPENSSL (certificate), FALSE);
- g_return_val_if_fail (purpose, FALSE);
- g_return_val_if_fail (!identity || G_IS_SOCKET_CONNECTABLE (identity), FALSE);
- g_return_val_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable), FALSE);
- g_return_val_if_fail (!error || !*error, FALSE);
- g_return_val_if_fail (G_TLS_DATABASE_OPENSSL_GET_CLASS (openssl)->lookup_assertion, FALSE);
- return G_TLS_DATABASE_OPENSSL_GET_CLASS (openssl)->lookup_assertion (openssl,
- certificate,
- assertion,
- purpose,
- identity,
- cancellable,
- error);
-}
diff --git a/tls/openssl/gtlsdatabase-openssl.h b/tls/openssl/gtlsdatabase-openssl.h
index c07a4b9..fd31352 100644
--- a/tls/openssl/gtlsdatabase-openssl.h
+++ b/tls/openssl/gtlsdatabase-openssl.h
@@ -49,14 +49,6 @@ typedef struct _GTlsDatabaseOpenssl GTlsDatabaseOpenssl;
struct _GTlsDatabaseOpensslClass
{
GTlsDatabaseClass parent_class;
-
- gboolean (*lookup_assertion) (GTlsDatabaseOpenssl *openssl,
- GTlsCertificateOpenssl *certificate,
- GTlsDatabaseOpensslAssertion assertion,
- const gchar *purpose,
- GSocketConnectable *identity,
- GCancellable *cancellable,
- GError **error);
};
struct _GTlsDatabaseOpenssl
@@ -66,14 +58,6 @@ struct _GTlsDatabaseOpenssl
GType g_tls_database_openssl_get_type (void) G_GNUC_CONST;
-gboolean g_tls_database_openssl_lookup_assertion (GTlsDatabaseOpenssl *openssl,
- GTlsCertificateOpenssl *certificate,
- GTlsDatabaseOpensslAssertion assertion,
- const gchar *purpose,
- GSocketConnectable *identity,
- GCancellable *cancellable,
- GError **error);
-
G_END_DECLS
#endif /* __G_TLS_DATABASE_OPENSSL_H___ */
diff --git a/tls/openssl/gtlsfiledatabase-openssl.c b/tls/openssl/gtlsfiledatabase-openssl.c
index 71f629b..e2659b0 100644
--- a/tls/openssl/gtlsfiledatabase-openssl.c
+++ b/tls/openssl/gtlsfiledatabase-openssl.c
@@ -58,6 +58,14 @@ typedef struct _GTlsFileDatabaseOpensslPrivate
GHashTable *certs_by_handle;
} GTlsFileDatabaseOpensslPrivate;
+enum {
+ STATUS_FAILURE,
+ STATUS_INCOMPLETE,
+ STATUS_SELFSIGNED,
+ STATUS_PINNED,
+ STATUS_ANCHORED,
+};
+
enum
{
PROP_0,
@@ -369,49 +377,6 @@ g_tls_file_database_openssl_lookup_certificate_for_handle (GTlsDatabase
return cert ? g_object_ref (cert) : NULL;
}
-static gboolean
-g_tls_file_database_openssl_lookup_assertion (GTlsDatabaseOpenssl *database,
- GTlsCertificateOpenssl *certificate,
- GTlsDatabaseOpensslAssertion assertion,
- const gchar *purpose,
- GSocketConnectable *identity,
- GCancellable *cancellable,
- GError **error)
-{
- GTlsFileDatabaseOpenssl *file_database = G_TLS_FILE_DATABASE_OPENSSL (database);
- GTlsFileDatabaseOpensslPrivate *priv;
- GBytes *der = NULL;
- gboolean contains;
-
- priv = g_tls_file_database_openssl_get_instance_private (file_database);
-
- if (g_cancellable_set_error_if_cancelled (cancellable, error))
- return FALSE;
-
- /* We only have anchored certificate assertions here */
- if (assertion != G_TLS_DATABASE_OPENSSL_ANCHORED_CERTIFICATE)
- return FALSE;
-
- /*
- * TODO: We should be parsing any Extended Key Usage attributes and
- * comparing them to the purpose.
- */
-
- der = g_tls_certificate_openssl_get_bytes (certificate);
-
- g_mutex_lock (&priv->mutex);
- contains = g_hash_table_lookup (priv->complete, der) ? TRUE : FALSE;
- g_mutex_unlock (&priv->mutex);
-
- g_bytes_unref (der);
-
- if (g_cancellable_set_error_if_cancelled (cancellable, error))
- return FALSE;
-
- /* All certificates in our file are anchored certificates */
- return contains;
-}
-
static GTlsCertificate *
g_tls_file_database_openssl_lookup_certificate_issuer (GTlsDatabase *database,
GTlsCertificate *certificate,
@@ -513,12 +478,348 @@ g_tls_file_database_openssl_lookup_certificates_issued_by (GTlsDatabase
return issued;
}
+static gboolean
+lookup_assertion (GTlsDatabaseOpenssl *database,
+ GTlsCertificateOpenssl *certificate,
+ GTlsDatabaseOpensslAssertion assertion,
+ const gchar *purpose,
+ GSocketConnectable *identity,
+ GCancellable *cancellable,
+ GError **error)
+{
+ GTlsFileDatabaseOpenssl *file_database = G_TLS_FILE_DATABASE_OPENSSL (database);
+ GTlsFileDatabaseOpensslPrivate *priv;
+ GBytes *der = NULL;
+ gboolean contains;
+
+ priv = g_tls_file_database_openssl_get_instance_private (file_database);
+
+ if (g_cancellable_set_error_if_cancelled (cancellable, error))
+ return FALSE;
+
+ /* We only have anchored certificate assertions here */
+ if (assertion != G_TLS_DATABASE_OPENSSL_ANCHORED_CERTIFICATE)
+ return FALSE;
+
+ /*
+ * TODO: We should be parsing any Extended Key Usage attributes and
+ * comparing them to the purpose.
+ */
+
+ der = g_tls_certificate_openssl_get_bytes (certificate);
+
+ g_mutex_lock (&priv->mutex);
+ contains = g_hash_table_lookup (priv->complete, der) ? TRUE : FALSE;
+ g_mutex_unlock (&priv->mutex);
+
+ g_bytes_unref (der);
+
+ if (g_cancellable_set_error_if_cancelled (cancellable, error))
+ return FALSE;
+
+ /* All certificates in our file are anchored certificates */
+ return contains;
+}
+
+static gboolean
+is_self_signed (GTlsCertificateOpenssl *certificate)
+{
+ X509 *cert;
+ X509_STORE *store;
+ X509_STORE_CTX csc;
+ STACK_OF(X509) *trusted;
+ gboolean ret = FALSE;
+
+ store = X509_STORE_new ();
+ cert = g_tls_certificate_openssl_get_cert (certificate);
+
+ if (!X509_STORE_CTX_init(&csc, store, cert, NULL))
+ goto end;
+
+ trusted = sk_X509_new_null ();
+ sk_X509_push (trusted, cert);
+
+ X509_STORE_CTX_trusted_stack (&csc, trusted);
+ X509_STORE_CTX_set_flags (&csc, X509_V_FLAG_CHECK_SS_SIGNATURE);
+
+ ret = X509_verify_cert (&csc) > 0;
+
+end:
+ X509_STORE_CTX_cleanup (&csc);
+ X509_STORE_free (store);
+
+ return ret;
+}
+
+static gint
+build_certificate_chain (GTlsDatabaseOpenssl *openssl,
+ GTlsCertificateOpenssl *chain,
+ const gchar *purpose,
+ GSocketConnectable *identity,
+ GTlsInteraction *interaction,
+ GTlsDatabaseVerifyFlags flags,
+ GCancellable *cancellable,
+ GTlsCertificateOpenssl **anchor,
+ GError **error)
+{
+
+ GTlsCertificateOpenssl *certificate;
+ GTlsCertificateOpenssl *previous;
+ GTlsCertificate *issuer;
+ gboolean certificate_is_from_db;
+
+ g_assert (anchor);
+ g_assert (chain);
+ g_assert (purpose);
+ g_assert (error);
+ g_assert (!*error);
+
+ /*
+ * Remember that the first certificate never changes in the chain.
+ * When we find a self-signed, pinned or anchored certificate, all
+ * issuers are truncated from the chain.
+ */
+
+ *anchor = NULL;
+ previous = NULL;
+ certificate = chain;
+ certificate_is_from_db = FALSE;
+
+ /* First check for pinned certificate */
+ if (lookup_assertion (openssl, certificate,
+ G_TLS_DATABASE_OPENSSL_PINNED_CERTIFICATE,
+ purpose, identity, cancellable, error))
+ {
+ g_tls_certificate_openssl_set_issuer (certificate, NULL);
+ return STATUS_PINNED;
+ }
+ else if (*error)
+ {
+ return STATUS_FAILURE;
+ }
+
+ for (;;)
+ {
+ if (g_cancellable_set_error_if_cancelled (cancellable, error))
+ return STATUS_FAILURE;
+
+ /* Look up whether this certificate is an anchor */
+ if (lookup_assertion (openssl, certificate,
+ G_TLS_DATABASE_OPENSSL_ANCHORED_CERTIFICATE,
+ purpose, identity, cancellable, error))
+ {
+ g_tls_certificate_openssl_set_issuer (certificate, NULL);
+ *anchor = certificate;
+ return STATUS_ANCHORED;
+ }
+ else if (*error)
+ {
+ return STATUS_FAILURE;
+ }
+
+ /* Is it self-signed? */
+ if (is_self_signed (certificate))
+ {
+ /*
+ * Since at this point we would fail with 'self-signed', can we replace
+ * this certificate with one from the database and do better?
+ */
+ if (previous && !certificate_is_from_db)
+ {
+ issuer = g_tls_database_lookup_certificate_issuer (G_TLS_DATABASE (openssl),
+ G_TLS_CERTIFICATE (previous),
+ interaction,
+ G_TLS_DATABASE_LOOKUP_NONE,
+ cancellable, error);
+ if (*error)
+ {
+ return STATUS_FAILURE;
+ }
+ else if (issuer)
+ {
+ /* Replaced with certificate in the db, restart step again with this certificate */
+ g_return_val_if_fail (G_IS_TLS_CERTIFICATE_OPENSSL (issuer), STATUS_FAILURE);
+ g_tls_certificate_openssl_set_issuer (previous, G_TLS_CERTIFICATE_OPENSSL (issuer));
+ certificate = G_TLS_CERTIFICATE_OPENSSL (issuer);
+ certificate_is_from_db = TRUE;
+ g_object_unref (issuer);
+ continue;
+ }
+ }
+
+ g_tls_certificate_openssl_set_issuer (certificate, NULL);
+ return STATUS_SELFSIGNED;
+ }
+
+ previous = certificate;
+
+ /* Bring over the next certificate in the chain */
+ issuer = g_tls_certificate_get_issuer (G_TLS_CERTIFICATE (certificate));
+ if (issuer)
+ {
+ g_return_val_if_fail (G_IS_TLS_CERTIFICATE_OPENSSL (issuer), STATUS_FAILURE);
+ certificate = G_TLS_CERTIFICATE_OPENSSL (issuer);
+ certificate_is_from_db = FALSE;
+ }
+
+ /* Search for the next certificate in chain */
+ else
+ {
+ issuer = g_tls_database_lookup_certificate_issuer (G_TLS_DATABASE (openssl),
+ G_TLS_CERTIFICATE (certificate),
+ interaction,
+ G_TLS_DATABASE_LOOKUP_NONE,
+ cancellable, error);
+ if (*error)
+ return STATUS_FAILURE;
+ else if (!issuer)
+ return STATUS_INCOMPLETE;
+
+ /* Found a certificate in chain, use for next step */
+ g_return_val_if_fail (G_IS_TLS_CERTIFICATE_OPENSSL (issuer), STATUS_FAILURE);
+ g_tls_certificate_openssl_set_issuer (certificate, G_TLS_CERTIFICATE_OPENSSL (issuer));
+ certificate = G_TLS_CERTIFICATE_OPENSSL (issuer);
+ certificate_is_from_db = TRUE;
+ g_object_unref (issuer);
+ }
+ }
+
+ g_assert_not_reached ();
+}
+
+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_file_database_openssl_verify_chain (GTlsDatabase *database,
+ GTlsCertificate *chain,
+ const gchar *purpose,
+ GSocketConnectable *identity,
+ GTlsInteraction *interaction,
+ GTlsDatabaseVerifyFlags flags,
+ GCancellable *cancellable,
+ GError **error)
+{
+ GTlsDatabaseOpenssl *openssl;
+ GTlsCertificateOpenssl *anchor;
+ STACK_OF(X509) *certs, *anchors;
+ X509_STORE *store;
+ X509_STORE_CTX csc;
+ X509 *x;
+ gint status;
+ GTlsCertificateFlags result = 0;
+ GError *err = NULL;
+
+ g_return_val_if_fail (G_IS_TLS_CERTIFICATE_OPENSSL (chain),
+ G_TLS_CERTIFICATE_GENERIC_ERROR);
+
+ openssl = G_TLS_DATABASE_OPENSSL (database);
+ anchor = NULL;
+
+ status = build_certificate_chain (openssl, G_TLS_CERTIFICATE_OPENSSL (chain), purpose,
+ identity, interaction, flags, cancellable, &anchor, &err);
+ if (status == STATUS_FAILURE)
+ {
+ g_propagate_error (error, err);
+ return G_TLS_CERTIFICATE_GENERIC_ERROR;
+ }
+
+ /*
+ * A pinned certificate is verified on its own, without any further
+ * verification.
+ */
+ if (status == STATUS_PINNED)
+ return 0;
+
+ 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 ();
+
+ x = g_tls_certificate_openssl_get_cert (G_TLS_CERTIFICATE_OPENSSL (chain));
+ if (!X509_STORE_CTX_init(&csc, store, x, certs))
+ {
+ X509_STORE_CTX_cleanup (&csc);
+ X509_STORE_free (store);
+ return G_TLS_CERTIFICATE_GENERIC_ERROR;
+ }
+
+ if (anchor)
+ {
+ g_assert (g_tls_certificate_get_issuer (G_TLS_CERTIFICATE (anchor)) == NULL);
+ anchors = convert_certificate_chain_to_openssl (G_TLS_CERTIFICATE_OPENSSL (anchor));
+ X509_STORE_CTX_trusted_stack (&csc, anchors);
+ }
+ else
+ anchors = NULL;
+
+ if (X509_verify_cert (&csc) <= 0)
+ result = g_tls_certificate_openssl_convert_error (X509_STORE_CTX_get_error (&csc));
+
+ X509_STORE_CTX_cleanup (&csc);
+ X509_STORE_free (store);
+
+ 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 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_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;
@@ -528,7 +829,7 @@ g_tls_file_database_openssl_class_init (GTlsFileDatabaseOpensslClass *klass)
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;
- openssl_class->lookup_assertion = g_tls_file_database_openssl_lookup_assertion;
+ database_class->verify_chain = g_tls_file_database_openssl_verify_chain;
g_object_class_override_property (gobject_class, PROP_ANCHORS, "anchors");
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]