[glib-networking] gnutls: Update for GTlsCertificate changes, implement verify
- From: Dan Winship <danw src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [glib-networking] gnutls: Update for GTlsCertificate changes, implement verify
- Date: Tue, 7 Dec 2010 10:17:36 +0000 (UTC)
commit 4264b02ac1e2e30aacb8511ccc2a99a60be14062
Author: Dan Winship <danw gnome org>
Date: Tue Nov 30 19:45:39 2010 -0500
gnutls: Update for GTlsCertificate changes, implement verify
tls/gnutls/gtlscertificate-gnutls.c | 196 ++++++++++++++++++++++++------
tls/gnutls/gtlscertificate-gnutls.h | 18 ++-
tls/gnutls/gtlsclientconnection-gnutls.c | 42 +++----
tls/gnutls/gtlsconnection-gnutls.c | 39 +------
4 files changed, 189 insertions(+), 106 deletions(-)
---
diff --git a/tls/gnutls/gtlscertificate-gnutls.c b/tls/gnutls/gtlscertificate-gnutls.c
index 93580c2..29e992f 100644
--- a/tls/gnutls/gtlscertificate-gnutls.c
+++ b/tls/gnutls/gtlscertificate-gnutls.c
@@ -27,20 +27,7 @@
#include "gtlscertificate-gnutls.h"
#include <glib/gi18n-lib.h>
-static void g_tls_certificate_gnutls_get_property (GObject *object,
- guint prop_id,
- GValue *value,
- GParamSpec *pspec);
-static void g_tls_certificate_gnutls_set_property (GObject *object,
- guint prop_id,
- const GValue *value,
- GParamSpec *pspec);
-static void g_tls_certificate_gnutls_finalize (GObject *object);
-
static void g_tls_certificate_gnutls_initable_iface_init (GInitableIface *iface);
-static gboolean g_tls_certificate_gnutls_initable_init (GInitable *initable,
- GCancellable *cancellable,
- GError **error);
G_DEFINE_TYPE_WITH_CODE (GTlsCertificateGnutls, g_tls_certificate_gnutls, G_TYPE_TLS_CERTIFICATE,
G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE,
@@ -53,7 +40,8 @@ enum
PROP_CERTIFICATE,
PROP_CERTIFICATE_PEM,
PROP_PRIVATE_KEY,
- PROP_PRIVATE_KEY_PEM
+ PROP_PRIVATE_KEY_PEM,
+ PROP_ISSUER
};
struct _GTlsCertificateGnutlsPrivate
@@ -61,6 +49,8 @@ struct _GTlsCertificateGnutlsPrivate
gnutls_x509_crt_t cert;
gnutls_x509_privkey_t key;
+ GTlsCertificateGnutls *issuer;
+
GError *construct_error;
guint have_cert : 1;
@@ -68,23 +58,6 @@ struct _GTlsCertificateGnutlsPrivate
};
static void
-g_tls_certificate_gnutls_class_init (GTlsCertificateGnutlsClass *klass)
-{
- GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
-
- g_type_class_add_private (klass, sizeof (GTlsCertificateGnutlsPrivate));
-
- gobject_class->get_property = g_tls_certificate_gnutls_get_property;
- gobject_class->set_property = g_tls_certificate_gnutls_set_property;
- gobject_class->finalize = g_tls_certificate_gnutls_finalize;
-
- g_object_class_override_property (gobject_class, PROP_CERTIFICATE, "certificate");
- g_object_class_override_property (gobject_class, PROP_CERTIFICATE_PEM, "certificate-pem");
- g_object_class_override_property (gobject_class, PROP_PRIVATE_KEY, "private-key");
- g_object_class_override_property (gobject_class, PROP_PRIVATE_KEY_PEM, "private-key-pem");
-}
-
-static void
g_tls_certificate_gnutls_finalize (GObject *object)
{
GTlsCertificateGnutls *gnutls = G_TLS_CERTIFICATE_GNUTLS (object);
@@ -92,6 +65,9 @@ g_tls_certificate_gnutls_finalize (GObject *object)
gnutls_x509_crt_deinit (gnutls->priv->cert);
gnutls_x509_privkey_deinit (gnutls->priv->key);
+ if (gnutls->priv->issuer)
+ g_object_unref (gnutls->priv->issuer);
+
g_clear_error (&gnutls->priv->construct_error);
G_OBJECT_CLASS (g_tls_certificate_gnutls_parent_class)->finalize (object);
@@ -156,6 +132,10 @@ g_tls_certificate_gnutls_get_property (GObject *object,
g_value_take_string (value, certificate_pem);
break;
+ case PROP_ISSUER:
+ g_value_set_object (value, gnutls->priv->issuer);
+ break;
+
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
@@ -256,6 +236,10 @@ g_tls_certificate_gnutls_set_property (GObject *object,
}
break;
+ case PROP_ISSUER:
+ gnutls->priv->issuer = g_value_dup_object (value);
+ break;
+
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
@@ -272,12 +256,6 @@ g_tls_certificate_gnutls_init (GTlsCertificateGnutls *gnutls)
gnutls_x509_privkey_init (&gnutls->priv->key);
}
-static void
-g_tls_certificate_gnutls_initable_iface_init (GInitableIface *iface)
-{
- iface->init = g_tls_certificate_gnutls_initable_init;
-}
-
static gboolean
g_tls_certificate_gnutls_initable_init (GInitable *initable,
GCancellable *cancellable,
@@ -301,6 +279,82 @@ g_tls_certificate_gnutls_initable_init (GInitable *initable,
return TRUE;
}
+static GTlsCertificateFlags
+g_tls_certificate_gnutls_verify (GTlsCertificate *cert,
+ GSocketConnectable *identity,
+ GTlsCertificate *trusted_ca)
+{
+ GTlsCertificateGnutls *cert_gnutls;
+ int status;
+ guint gnutls_flags, num_certs, i, num_cas;
+ gnutls_x509_crt_t *chain, ca;
+ GTlsCertificateFlags gtls_flags;
+
+ cert_gnutls = G_TLS_CERTIFICATE_GNUTLS (cert);
+ for (num_certs = 0; cert_gnutls; cert_gnutls = cert_gnutls->priv->issuer)
+ num_certs++;
+ chain = g_new (gnutls_x509_crt_t, num_certs);
+ cert_gnutls = G_TLS_CERTIFICATE_GNUTLS (cert);
+ for (i = 0; cert_gnutls; cert_gnutls = cert_gnutls->priv->issuer, i++)
+ chain[i] = cert_gnutls->priv->cert;
+
+ if (trusted_ca)
+ {
+ cert_gnutls = G_TLS_CERTIFICATE_GNUTLS (trusted_ca);
+ ca = cert_gnutls->priv->cert;
+ num_cas = 1;
+ }
+ else
+ {
+ ca = NULL;
+ num_cas = 0;
+ }
+
+ status = gnutls_x509_crt_list_verify (chain, num_certs,
+ &ca, num_cas,
+ NULL, 0,
+ GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT,
+ &gnutls_flags);
+ g_free (chain);
+
+ if (status != 0)
+ return G_TLS_CERTIFICATE_GENERIC_ERROR;
+
+ gtls_flags = g_tls_certificate_gnutls_convert_flags (gnutls_flags);
+
+ if (identity)
+ gtls_flags |= g_tls_certificate_gnutls_verify_identity (G_TLS_CERTIFICATE_GNUTLS (cert), identity);
+
+ return gtls_flags;
+}
+
+static void
+g_tls_certificate_gnutls_class_init (GTlsCertificateGnutlsClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+ GTlsCertificateClass *certificate_class = G_TLS_CERTIFICATE_CLASS (klass);
+
+ g_type_class_add_private (klass, sizeof (GTlsCertificateGnutlsPrivate));
+
+ gobject_class->get_property = g_tls_certificate_gnutls_get_property;
+ gobject_class->set_property = g_tls_certificate_gnutls_set_property;
+ gobject_class->finalize = g_tls_certificate_gnutls_finalize;
+
+ certificate_class->verify = g_tls_certificate_gnutls_verify;
+
+ g_object_class_override_property (gobject_class, PROP_CERTIFICATE, "certificate");
+ g_object_class_override_property (gobject_class, PROP_CERTIFICATE_PEM, "certificate-pem");
+ g_object_class_override_property (gobject_class, PROP_PRIVATE_KEY, "private-key");
+ g_object_class_override_property (gobject_class, PROP_PRIVATE_KEY_PEM, "private-key-pem");
+ g_object_class_override_property (gobject_class, PROP_ISSUER, "issuer");
+}
+
+static void
+g_tls_certificate_gnutls_initable_iface_init (GInitableIface *iface)
+{
+ iface->init = g_tls_certificate_gnutls_initable_init;
+}
+
GTlsCertificate *
g_tls_certificate_gnutls_new (const gnutls_datum *datum,
GTlsCertificate *issuer)
@@ -360,3 +414,71 @@ g_tls_certificate_gnutls_copy_key (GTlsCertificateGnutls *gnutls)
gnutls_x509_privkey_cpy (key, gnutls->priv->key);
return key;
}
+
+static const struct {
+ int gnutls_flag;
+ GTlsCertificateFlags gtls_flag;
+} flags_map[] = {
+ { GNUTLS_CERT_SIGNER_NOT_FOUND | GNUTLS_CERT_SIGNER_NOT_CA, G_TLS_CERTIFICATE_UNKNOWN_CA },
+ { GNUTLS_CERT_NOT_ACTIVATED, G_TLS_CERTIFICATE_NOT_ACTIVATED },
+ { GNUTLS_CERT_EXPIRED, G_TLS_CERTIFICATE_EXPIRED },
+ { GNUTLS_CERT_REVOKED, G_TLS_CERTIFICATE_REVOKED },
+ { GNUTLS_CERT_INSECURE_ALGORITHM, G_TLS_CERTIFICATE_INSECURE }
+};
+static const int flags_map_size = G_N_ELEMENTS (flags_map);
+
+GTlsCertificateFlags
+g_tls_certificate_gnutls_convert_flags (guint gnutls_flags)
+{
+ int i;
+ GTlsCertificateFlags gtls_flags;
+
+ /* Convert GNUTLS status to GTlsCertificateFlags. GNUTLS sets
+ * GNUTLS_CERT_INVALID if it sets any other flag, so we want to
+ * strip that out unless it's the only flag set. Then we convert
+ * specific flags we recognize, and if there are any flags left over
+ * at the end, we add G_TLS_CERTIFICATE_GENERIC_ERROR.
+ */
+ gtls_flags = 0;
+
+ if (gnutls_flags != GNUTLS_CERT_INVALID)
+ gnutls_flags = gnutls_flags & ~GNUTLS_CERT_INVALID;
+ for (i = 0; i < flags_map_size && gnutls_flags != 0; i++)
+ {
+ if (gnutls_flags & flags_map[i].gnutls_flag)
+ {
+ gnutls_flags &= ~flags_map[i].gnutls_flag;
+ gtls_flags |= flags_map[i].gtls_flag;
+ }
+ }
+ if (gnutls_flags)
+ gtls_flags |= G_TLS_CERTIFICATE_GENERIC_ERROR;
+
+ return gtls_flags;
+}
+
+GTlsCertificateFlags
+g_tls_certificate_gnutls_verify_identity (GTlsCertificateGnutls *gnutls,
+ GSocketConnectable *identity)
+{
+ const char *hostname;
+
+ 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
+ hostname = NULL;
+
+ if (hostname)
+ {
+ if (gnutls_x509_crt_check_hostname (gnutls->priv->cert, hostname))
+ return 0;
+ }
+
+ /* FIXME: check sRVName and uniformResourceIdentifier
+ * subjectAltNames, if appropriate for @identity.
+ */
+
+ return G_TLS_CERTIFICATE_BAD_IDENTITY;
+}
diff --git a/tls/gnutls/gtlscertificate-gnutls.h b/tls/gnutls/gtlscertificate-gnutls.h
index 32f9058..5e2cc70 100644
--- a/tls/gnutls/gtlscertificate-gnutls.h
+++ b/tls/gnutls/gtlscertificate-gnutls.h
@@ -41,14 +41,20 @@ struct _GTlsCertificateGnutls
GType g_tls_certificate_gnutls_get_type (void) G_GNUC_CONST;
-GTlsCertificate * g_tls_certificate_gnutls_new (const gnutls_datum *datum,
- GTlsCertificate *issuer);
+GTlsCertificate * g_tls_certificate_gnutls_new (const gnutls_datum *datum,
+ GTlsCertificate *issuer);
-const gnutls_x509_crt_t g_tls_certificate_gnutls_get_cert (GTlsCertificateGnutls *gnutls);
-const gnutls_x509_privkey_t g_tls_certificate_gnutls_get_key (GTlsCertificateGnutls *gnutls);
+const gnutls_x509_crt_t g_tls_certificate_gnutls_get_cert (GTlsCertificateGnutls *gnutls);
+const gnutls_x509_privkey_t g_tls_certificate_gnutls_get_key (GTlsCertificateGnutls *gnutls);
+
+gnutls_x509_crt_t g_tls_certificate_gnutls_copy_cert (GTlsCertificateGnutls *gnutls);
+gnutls_x509_privkey_t g_tls_certificate_gnutls_copy_key (GTlsCertificateGnutls *gnutls);
+
+GTlsCertificateFlags g_tls_certificate_gnutls_verify_identity (GTlsCertificateGnutls *gnutls,
+ GSocketConnectable *identity);
+
+GTlsCertificateFlags g_tls_certificate_gnutls_convert_flags (guint gnutls_flags);
-gnutls_x509_crt_t g_tls_certificate_gnutls_copy_cert (GTlsCertificateGnutls *gnutls);
-gnutls_x509_privkey_t g_tls_certificate_gnutls_copy_key (GTlsCertificateGnutls *gnutls);
G_END_DECLS
diff --git a/tls/gnutls/gtlsclientconnection-gnutls.c b/tls/gnutls/gtlsclientconnection-gnutls.c
index ebe871f..b4f1b38 100644
--- a/tls/gnutls/gtlsclientconnection-gnutls.c
+++ b/tls/gnutls/gtlsclientconnection-gnutls.c
@@ -27,6 +27,7 @@
#include <string.h>
#include "gtlsclientconnection-gnutls.h"
+#include "gtlscertificate-gnutls.h"
#include <glib/gi18n-lib.h>
enum
@@ -164,6 +165,7 @@ g_tls_client_connection_gnutls_set_property (GObject *object,
GParamSpec *pspec)
{
GTlsClientConnectionGnutls *gnutls = G_TLS_CLIENT_CONNECTION_GNUTLS (object);
+ const char *hostname;
switch (prop_id)
{
@@ -177,11 +179,16 @@ g_tls_client_connection_gnutls_set_property (GObject *object,
gnutls->priv->server_identity = g_value_dup_object (value);
if (G_IS_NETWORK_ADDRESS (gnutls->priv->server_identity))
+ hostname = g_network_address_get_hostname (G_NETWORK_ADDRESS (gnutls->priv->server_identity));
+ else if (G_IS_NETWORK_SERVICE (gnutls->priv->server_identity))
+ hostname = g_network_service_get_domain (G_NETWORK_SERVICE (gnutls->priv->server_identity));
+ else
+ hostname = NULL;
+
+ if (hostname)
{
- const char *hostname;
gnutls_session_t session = g_tls_connection_gnutls_get_session (G_TLS_CONNECTION_GNUTLS (gnutls));
- hostname = g_network_address_get_hostname (G_NETWORK_ADDRESS (gnutls->priv->server_identity));
gnutls_server_name_set (session, GNUTLS_NAME_DNS,
hostname, strlen (hostname));
}
@@ -233,41 +240,24 @@ g_tls_client_connection_gnutls_retrieve_function (gnutls_session_t s
static gboolean
validate_handshake (GTlsClientConnectionGnutls *gnutls)
{
+ GTlsCertificate *peer;
GTlsCertificateFlags errors;
gboolean accepted;
+ peer = g_tls_connection_get_peer_certificate (G_TLS_CONNECTION (gnutls));
+
errors = g_tls_connection_gnutls_validate_peer (G_TLS_CONNECTION_GNUTLS (gnutls));
- /* FIXME: implement the full hostname/servicename/URI check
- * according to draft-saintandre-tls-server-id-check
- */
if ((gnutls->priv->validation_flags & G_TLS_CERTIFICATE_BAD_IDENTITY) &&
- gnutls->priv->server_identity &&
- G_IS_NETWORK_ADDRESS (gnutls->priv->server_identity))
+ gnutls->priv->server_identity)
{
- gnutls_session session;
- gnutls_x509_crt x509_cert;
- const gnutls_datum_t *certs;
- const char *hostname;
- unsigned int num_certs;
-
- session = g_tls_connection_gnutls_get_session (G_TLS_CONNECTION_GNUTLS (gnutls));
- hostname = g_network_address_get_hostname (G_NETWORK_ADDRESS (gnutls->priv->server_identity));
-
- gnutls_x509_crt_init (&x509_cert);
- certs = gnutls_certificate_get_peers (session, &num_certs);
- gnutls_x509_crt_import (x509_cert, &certs[0], GNUTLS_X509_FMT_DER);
- if (!gnutls_x509_crt_check_hostname (x509_cert, hostname))
- errors |= G_TLS_CERTIFICATE_BAD_IDENTITY;
- gnutls_x509_crt_deinit (x509_cert);
+ errors |= g_tls_certificate_gnutls_verify_identity (G_TLS_CERTIFICATE_GNUTLS (peer),
+ gnutls->priv->server_identity);
}
errors &= gnutls->priv->validation_flags;
if (errors)
- {
- GTlsCertificate *peer = g_tls_connection_get_peer_certificate (G_TLS_CONNECTION (gnutls));
- accepted = g_tls_connection_emit_accept_certificate (G_TLS_CONNECTION (gnutls), peer, errors);
- }
+ accepted = g_tls_connection_emit_accept_certificate (G_TLS_CONNECTION (gnutls), peer, errors);
else
accepted = TRUE;
diff --git a/tls/gnutls/gtlsconnection-gnutls.c b/tls/gnutls/gtlsconnection-gnutls.c
index 22bf34c..75685f8 100644
--- a/tls/gnutls/gtlsconnection-gnutls.c
+++ b/tls/gnutls/gtlsconnection-gnutls.c
@@ -397,48 +397,13 @@ g_tls_connection_gnutls_get_certificate (GTlsConnectionGnutls *gnutls,
st->ncerts = 0;
}
-static const struct {
- int gnutls_flag;
- GTlsCertificateFlags gtls_flag;
-} flags_map[] = {
- { GNUTLS_CERT_SIGNER_NOT_FOUND | GNUTLS_CERT_SIGNER_NOT_CA, G_TLS_CERTIFICATE_UNKNOWN_CA },
- { GNUTLS_CERT_NOT_ACTIVATED, G_TLS_CERTIFICATE_NOT_ACTIVATED },
- { GNUTLS_CERT_EXPIRED, G_TLS_CERTIFICATE_EXPIRED },
- { GNUTLS_CERT_REVOKED, G_TLS_CERTIFICATE_REVOKED },
- { GNUTLS_CERT_INSECURE_ALGORITHM, G_TLS_CERTIFICATE_INSECURE }
-};
-static const int flags_map_size = G_N_ELEMENTS (flags_map);
-
GTlsCertificateFlags
g_tls_connection_gnutls_validate_peer (GTlsConnectionGnutls *gnutls)
{
- int status, i;
- GTlsCertificateFlags gtls_errors;
+ int status;
status = gnutls_certificate_verify_peers (gnutls->priv->session);
-
- /* Convert GNUTLS status to GTlsCertificateFlags. GNUTLS sets
- * GNUTLS_CERT_INVALID if it sets any other flag, so we want to
- * strip that out unless it's the only flag set. Then we convert
- * specific flags we recognize, and if there are any flags left over
- * at the end, we add G_TLS_CERTIFICATE_GENERIC_ERROR.
- */
- gtls_errors = 0;
-
- if (status != GNUTLS_CERT_INVALID)
- status = status & ~GNUTLS_CERT_INVALID;
- for (i = 0; i < flags_map_size && status != 0; i++)
- {
- if (status & flags_map[i].gnutls_flag)
- {
- status &= ~flags_map[i].gnutls_flag;
- gtls_errors |= flags_map[i].gtls_flag;
- }
- }
- if (status)
- gtls_errors |= G_TLS_CERTIFICATE_GENERIC_ERROR;
-
- return gtls_errors;
+ return g_tls_certificate_gnutls_convert_flags (status);
}
static void
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]