#include <gnutls/x509.h>
#include "gtlscertificate-gnutls.h"
+#include "gtlshttp.h"
+#include "gtlsgnutls-version.h"
typedef struct
{
*/
GMutex mutex;
- /* read-only after construct */
+ /* Read-only after construct, but still has to be protected by the mutex. */
gnutls_x509_trust_list_t trust_list;
/*
GPtrArray *multi;
multi = g_hash_table_lookup (table, key);
- if (multi == NULL)
+ if (!multi)
{
multi = g_ptr_array_new_with_free_func ((GDestroyNotify)g_bytes_unref);
g_hash_table_insert (table, g_bytes_ref (key), multi);
GPtrArray *multi;
multi = g_hash_table_lookup (table, key);
- if (multi == NULL)
+ if (!multi)
return NULL;
g_assert (multi->len > 0);
guint i;
multi = g_hash_table_lookup (table, key);
- if (multi == NULL)
+ if (!multi)
return NULL;
for (i = 0; i < multi->len; i++)
{
g_assert (G_TLS_DATABASE_GNUTLS_GET_CLASS (self)->create_handle_for_certificate);
handle = G_TLS_DATABASE_GNUTLS_GET_CLASS (self)->create_handle_for_certificate (self, der);
- if (handle != NULL)
+ if (handle)
g_hash_table_insert (handles, handle, g_bytes_ref (der));
}
GBytes *issuer = NULL;
gint gerr;
- while ((gerr = gnutls_x509_trust_list_iter_get_ca (trust_list, &iter, &cert)) == 0)
+ while (gnutls_x509_trust_list_iter_get_ca (trust_list, &iter, &cert) == 0)
{
gerr = gnutls_x509_crt_get_raw_dn (cert, &dn);
if (gerr < 0)
gchar *handle = NULL;
der = g_tls_certificate_gnutls_get_bytes (G_TLS_CERTIFICATE_GNUTLS (certificate));
- g_return_val_if_fail (der != NULL, FALSE);
+ g_return_val_if_fail (der, FALSE);
g_mutex_lock (&priv->mutex);
priv->handles = create_handles_array_unlocked (self, priv->complete);
der = g_hash_table_lookup (priv->handles, handle);
- if (der != NULL)
+ if (der)
g_bytes_ref (der);
g_mutex_unlock (&priv->mutex);
- if (der == NULL)
+ if (!der)
return NULL;
datum.data = (unsigned char *)g_bytes_get_data (der, &length);
{
issuer = NULL;
}
- else if (der != NULL)
+ else if (der)
{
datum.data = (unsigned char *)g_bytes_get_data (der, &length);
datum.size = length;
issuer = g_tls_certificate_gnutls_new (&datum, NULL);
}
- if (der != NULL)
+ if (der)
g_bytes_unref (der);
return issuer;
}
g_bytes_unref (issuer);
- for (l = ders; l != NULL; l = g_list_next (l))
+ for (l = ders; l; l = g_list_next (l))
{
if (g_cancellable_set_error_if_cancelled (cancellable, error))
{
return issued;
}
+typedef struct {
+ gnutls_x509_crt_t *chain;
+ guint length;
+} CertificateChain;
+
+static CertificateChain *
+certificate_chain_new (void)
+{
+ return g_new0 (CertificateChain, 1);
+}
+
static void
-convert_certificate_chain_to_gnutls (GTlsCertificateGnutls *chain,
- gnutls_x509_crt_t **gnutls_chain,
- guint *gnutls_chain_length)
+certificate_chain_free (CertificateChain *chain)
+{
+ g_free (chain->chain);
+ g_free (chain);
+}
+
+static CertificateChain *
+convert_certificate_chain_to_gnutls (GTlsCertificateGnutls *chain)
{
GTlsCertificate *cert;
- guint i;
+ CertificateChain *gnutls_chain;
+ guint i = 0;
+
+ gnutls_chain = certificate_chain_new ();
- g_assert (gnutls_chain);
- g_assert (gnutls_chain_length);
+ for (cert = G_TLS_CERTIFICATE (chain); cert; cert = g_tls_certificate_get_issuer (cert))
+ gnutls_chain->length++;
- for (*gnutls_chain_length = 0, cert = G_TLS_CERTIFICATE (chain);
- cert; cert = g_tls_certificate_get_issuer (cert))
- ++(*gnutls_chain_length);
+ gnutls_chain->chain = g_new (gnutls_x509_crt_t, gnutls_chain->length);
- *gnutls_chain = g_new0 (gnutls_x509_crt_t, *gnutls_chain_length);
+ for (cert = G_TLS_CERTIFICATE (chain); cert; cert = g_tls_certificate_get_issuer (cert), i++)
+ gnutls_chain->chain[i] = g_tls_certificate_gnutls_get_cert (G_TLS_CERTIFICATE_GNUTLS (cert));
- for (i = 0, cert = G_TLS_CERTIFICATE (chain);
- cert; cert = g_tls_certificate_get_issuer (cert), ++i)
- (*gnutls_chain)[i] = g_tls_certificate_gnutls_get_cert (G_TLS_CERTIFICATE_GNUTLS (cert));
+ g_assert (i == gnutls_chain->length);
- g_assert (i == *gnutls_chain_length);
+ return gnutls_chain;
}
static GTlsCertificateFlags
GTlsDatabaseGnutlsPrivate *priv = g_tls_database_gnutls_get_instance_private (self);
GTlsCertificateFlags result;
guint gnutls_result;
- gnutls_x509_crt_t *certs;
- guint certs_length;
- const char *hostname = NULL;
- char *free_hostname = NULL;
+ CertificateChain *gnutls_chain;
int gerr;
g_return_val_if_fail (G_IS_TLS_CERTIFICATE_GNUTLS (chain),
if (g_cancellable_set_error_if_cancelled (cancellable, error))
return G_TLS_CERTIFICATE_GENERIC_ERROR;
- convert_certificate_chain_to_gnutls (G_TLS_CERTIFICATE_GNUTLS (chain),
- &certs, &certs_length);
+ g_mutex_lock (&priv->mutex);
+ gnutls_chain = convert_certificate_chain_to_gnutls (G_TLS_CERTIFICATE_GNUTLS (chain));
gerr = gnutls_x509_trust_list_verify_crt (priv->trust_list,
- certs, certs_length,
+ gnutls_chain->chain, gnutls_chain->length,
0, &gnutls_result, NULL);
+ g_mutex_unlock (&priv->mutex);
if (gerr != 0 || g_cancellable_set_error_if_cancelled (cancellable, error))
{
- g_free (certs);
+ certificate_chain_free (gnutls_chain);
return G_TLS_CERTIFICATE_GENERIC_ERROR;
}
result = g_tls_certificate_gnutls_convert_flags (gnutls_result);
- 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;
+ if (identity)
+ result |= g_tls_certificate_gnutls_verify_identity (G_TLS_CERTIFICATE_GNUTLS (chain),
+ identity,
+ error);
- addr = g_inet_socket_address_get_address (G_INET_SOCKET_ADDRESS (identity));
- hostname = free_hostname = g_inet_address_to_string (addr);
- }
- if (hostname)
- {
- if (!gnutls_x509_crt_check_hostname (certs[0], hostname))
- result |= G_TLS_CERTIFICATE_BAD_IDENTITY;
- g_free (free_hostname);
- }
-
- g_free (certs);
+ certificate_chain_free (gnutls_chain);
return result;
}
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;
+ }
+
+ 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)
{
if (g_cancellable_set_error_if_cancelled (cancellable, error))
return FALSE;
- gnutls_x509_trust_list_init (&trust_list, 0);
-
- 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 ();
g_mutex_unlock (&priv->mutex);
}
-out:
- if (trust_list != NULL)
+ if (trust_list)
gnutls_x509_trust_list_deinit (trust_list, 1);
- if (subjects != NULL)
+ if (subjects)
g_hash_table_unref (subjects);
- if (issuers != NULL)
+ if (issuers)
g_hash_table_unref (issuers);
- if (complete != NULL)
+ if (complete)
g_hash_table_unref (complete);
return result;
}