[glib-networking] gnutls: reorganize certificate handling
- From: Dan Winship <danw src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [glib-networking] gnutls: reorganize certificate handling
- Date: Wed, 18 Jul 2012 21:47:54 +0000 (UTC)
commit e4e47d270eaeacef010a9ee41c8a3f1c0aabdad6
Author: Dan Winship <danw gnome org>
Date: Tue Jul 17 18:47:26 2012 -0400
gnutls: reorganize certificate handling
Move some of the code in handshake_internal() out into helper
functions, and move the code from the client and server verify_peer()
implementations into a helper function in gtlsconnection-gnutls.c as
well, to reduce duplication between them.
tls/gnutls/gtlsclientconnection-gnutls.c | 49 +--------
tls/gnutls/gtlsconnection-gnutls.c | 179 ++++++++++++++++++++++--------
tls/gnutls/gtlsconnection-gnutls.h | 4 -
tls/gnutls/gtlsserverconnection-gnutls.c | 35 ------
4 files changed, 136 insertions(+), 131 deletions(-)
---
diff --git a/tls/gnutls/gtlsclientconnection-gnutls.c b/tls/gnutls/gtlsclientconnection-gnutls.c
index 6ff6383..478be2b 100644
--- a/tls/gnutls/gtlsclientconnection-gnutls.c
+++ b/tls/gnutls/gtlsclientconnection-gnutls.c
@@ -293,55 +293,15 @@ g_tls_client_connection_gnutls_begin_handshake (GTlsConnectionGnutls *conn)
gnutls->priv->cert_requested = FALSE;
}
-static gboolean
-g_tls_client_connection_gnutls_verify_peer (GTlsConnectionGnutls *conn_gnutls,
- GTlsCertificate *peer_certificate,
- GTlsCertificateFlags *errors)
-{
- GTlsClientConnectionGnutls *gnutls = G_TLS_CLIENT_CONNECTION_GNUTLS (conn_gnutls);
- GTlsDatabase *database;
- gboolean accepted;
- GError *error = NULL;
-
- database = g_tls_connection_get_database (G_TLS_CONNECTION (conn_gnutls));
- if (database == NULL)
- {
- *errors |= G_TLS_CERTIFICATE_UNKNOWN_CA;
- *errors |= g_tls_certificate_verify (peer_certificate, gnutls->priv->server_identity, NULL);
- }
- else
- {
- *errors |= g_tls_database_verify_chain (database, peer_certificate,
- G_TLS_DATABASE_PURPOSE_AUTHENTICATE_SERVER,
- gnutls->priv->server_identity,
- g_tls_connection_get_interaction (G_TLS_CONNECTION (gnutls)),
- G_TLS_DATABASE_VERIFY_NONE,
- NULL, &error);
- if (error)
- {
- g_warning ("failure verifying certificate chain: %s",
- error->message);
- g_clear_error (&error);
- }
- }
-
- if (*errors & gnutls->priv->validation_flags)
- accepted = g_tls_connection_emit_accept_certificate (G_TLS_CONNECTION (gnutls), peer_certificate, *errors);
- else
- accepted = TRUE;
-
- return accepted;
-}
-
static void
g_tls_client_connection_gnutls_finish_handshake (GTlsConnectionGnutls *conn,
- gboolean success,
GError **inout_error)
{
GTlsClientConnectionGnutls *gnutls = G_TLS_CLIENT_CONNECTION_GNUTLS (conn);
- if (inout_error &&
- g_error_matches (*inout_error, G_TLS_ERROR, G_TLS_ERROR_NOT_TLS) &&
+ g_assert (inout_error != NULL);
+
+ if (g_error_matches (*inout_error, G_TLS_ERROR, G_TLS_ERROR_NOT_TLS) &&
gnutls->priv->cert_requested)
{
g_clear_error (inout_error);
@@ -353,7 +313,7 @@ g_tls_client_connection_gnutls_finish_handshake (GTlsConnectionGnutls *conn,
{
gnutls_datum session_datum;
- if (success &&
+ if (!*inout_error &&
gnutls_session_get_data2 (g_tls_connection_gnutls_get_session (conn),
&session_datum) == 0)
{
@@ -384,7 +344,6 @@ g_tls_client_connection_gnutls_class_init (GTlsClientConnectionGnutlsClass *klas
connection_gnutls_class->failed = g_tls_client_connection_gnutls_failed;
connection_gnutls_class->begin_handshake = g_tls_client_connection_gnutls_begin_handshake;
- connection_gnutls_class->verify_peer = g_tls_client_connection_gnutls_verify_peer;
connection_gnutls_class->finish_handshake = g_tls_client_connection_gnutls_finish_handshake;
g_object_class_override_property (gobject_class, PROP_VALIDATION_FLAGS, "validation-flags");
diff --git a/tls/gnutls/gtlsconnection-gnutls.c b/tls/gnutls/gtlsconnection-gnutls.c
index 65658e3..46db1c7 100644
--- a/tls/gnutls/gtlsconnection-gnutls.c
+++ b/tls/gnutls/gtlsconnection-gnutls.c
@@ -769,6 +769,110 @@ g_tls_connection_gnutls_push_func (gnutls_transport_ptr_t transport_data,
return ret;
}
+
+static GTlsCertificate *
+get_peer_certificate_from_session (GTlsConnectionGnutls *gnutls)
+{
+ GTlsCertificate *chain, *cert;
+ const gnutls_datum_t *certs;
+ unsigned int num_certs;
+ int i;
+
+ certs = gnutls_certificate_get_peers (gnutls->priv->session, &num_certs);
+ if (!certs || !num_certs)
+ return NULL;
+
+ chain = NULL;
+ for (i = num_certs - 1; i >= 0; i--)
+ {
+ cert = g_tls_certificate_gnutls_new (&certs[i], chain);
+ if (chain)
+ g_object_unref (chain);
+ chain = cert;
+ }
+
+ return chain;
+}
+
+static GTlsCertificateFlags
+verify_peer_certificate (GTlsConnectionGnutls *gnutls,
+ GTlsCertificate *peer_certificate)
+{
+ GTlsConnection *conn = G_TLS_CONNECTION (gnutls);
+ GSocketConnectable *peer_identity;
+ GTlsDatabase *database;
+ GTlsCertificateFlags errors;
+ gboolean is_client;
+
+ is_client = G_IS_TLS_CLIENT_CONNECTION (gnutls);
+ if (is_client)
+ peer_identity = g_tls_client_connection_get_server_identity (G_TLS_CLIENT_CONNECTION (gnutls));
+ else
+ peer_identity = NULL;
+
+ errors = 0;
+
+ database = g_tls_connection_get_database (conn);
+ if (database == NULL)
+ {
+ errors |= G_TLS_CERTIFICATE_UNKNOWN_CA;
+ errors |= g_tls_certificate_verify (peer_certificate, peer_identity, NULL);
+ }
+ else
+ {
+ GError *error = NULL;
+
+ errors |= g_tls_database_verify_chain (database, peer_certificate,
+ is_client ?
+ G_TLS_DATABASE_PURPOSE_AUTHENTICATE_SERVER :
+ G_TLS_DATABASE_PURPOSE_AUTHENTICATE_CLIENT,
+ peer_identity,
+ g_tls_connection_get_interaction (conn),
+ G_TLS_DATABASE_VERIFY_NONE,
+ NULL, &error);
+ if (error)
+ {
+ g_warning ("failure verifying certificate chain: %s",
+ error->message);
+ g_assert (errors != 0);
+ g_clear_error (&error);
+ }
+ }
+
+ return errors;
+}
+
+static gboolean
+accept_peer_certificate (GTlsConnectionGnutls *gnutls,
+ GTlsCertificate *peer_certificate,
+ GTlsCertificateFlags peer_certificate_errors)
+{
+ gboolean accepted;
+
+ if (G_IS_TLS_CLIENT_CONNECTION (gnutls))
+ {
+ GTlsCertificateFlags validation_flags =
+ g_tls_client_connection_get_validation_flags (G_TLS_CLIENT_CONNECTION (gnutls));
+
+ if ((peer_certificate_errors & validation_flags) == 0)
+ accepted = TRUE;
+ else
+ {
+ accepted = g_tls_connection_emit_accept_certificate (G_TLS_CONNECTION (gnutls),
+ peer_certificate,
+ peer_certificate_errors);
+ }
+ }
+ else
+ {
+ accepted = g_tls_connection_emit_accept_certificate (G_TLS_CONNECTION (gnutls),
+ peer_certificate,
+ peer_certificate_errors);
+ }
+
+ return accepted;
+}
+
static gboolean
handshake_internal (GTlsConnectionGnutls *gnutls,
gboolean blocking,
@@ -797,14 +901,8 @@ handshake_internal (GTlsConnectionGnutls *gnutls,
{
gnutls->priv->handshaking = TRUE;
- if (gnutls->priv->peer_certificate)
- {
- g_clear_object (&gnutls->priv->peer_certificate);
- gnutls->priv->peer_certificate_errors = 0;
-
- g_object_notify (G_OBJECT (gnutls), "peer-certificate");
- g_object_notify (G_OBJECT (gnutls), "peer-certificate-errors");
- }
+ g_clear_object (&gnutls->priv->peer_certificate);
+ gnutls->priv->peer_certificate_errors = 0;
g_tls_connection_gnutls_set_handshake_priority (gnutls);
G_TLS_CONNECTION_GNUTLS_GET_CLASS (gnutls)->begin_handshake (gnutls);
@@ -828,57 +926,44 @@ handshake_internal (GTlsConnectionGnutls *gnutls,
if (ret == 0 &&
gnutls_certificate_type_get (gnutls->priv->session) == GNUTLS_CRT_X509)
- {
- GTlsCertificate *chain, *cert;
- const gnutls_datum_t *certs;
- unsigned int num_certs;
- int i;
-
- certs = gnutls_certificate_get_peers (gnutls->priv->session, &num_certs);
- chain = NULL;
- if (certs)
- {
- for (i = num_certs - 1; i >= 0; i--)
- {
- cert = g_tls_certificate_gnutls_new (&certs[i], chain);
- if (chain)
- g_object_unref (chain);
- chain = cert;
- }
- }
-
- peer_certificate = chain;
- }
+ peer_certificate = get_peer_certificate_from_session (gnutls);
+ else
+ peer_certificate = NULL;
if (peer_certificate)
{
- gboolean accepted;
-
- accepted = G_TLS_CONNECTION_GNUTLS_GET_CLASS (gnutls)->verify_peer (gnutls, peer_certificate, &peer_certificate_errors);
-
- gnutls->priv->peer_certificate = peer_certificate;
- gnutls->priv->peer_certificate_errors = peer_certificate_errors;
-
- g_object_notify (G_OBJECT (gnutls), "peer-certificate");
- g_object_notify (G_OBJECT (gnutls), "peer-certificate-errors");
-
- if (!accepted)
+ peer_certificate_errors = verify_peer_certificate (gnutls, peer_certificate);
+ if (!accept_peer_certificate (gnutls, peer_certificate,
+ peer_certificate_errors))
{
g_set_error_literal (&gnutls->priv->handshake_error,
G_TLS_ERROR, G_TLS_ERROR_BAD_CERTIFICATE,
_("Unacceptable TLS certificate"));
- if (error)
- *error = g_error_copy (gnutls->priv->handshake_error);
- return FALSE;
}
+
+ gnutls->priv->peer_certificate = peer_certificate;
+ gnutls->priv->peer_certificate_errors = peer_certificate_errors;
+ g_object_notify (G_OBJECT (gnutls), "peer-certificate");
+ g_object_notify (G_OBJECT (gnutls), "peer-certificate-errors");
+ }
+ else if (G_IS_TLS_CLIENT_CONNECTION (gnutls))
+ {
+ g_set_error_literal (&gnutls->priv->handshake_error,
+ G_TLS_ERROR, G_TLS_ERROR_BAD_CERTIFICATE,
+ _("Server did not return a valid TLS certificate"));
}
G_TLS_CONNECTION_GNUTLS_GET_CLASS (gnutls)->
- finish_handshake (gnutls, ret == 0, &gnutls->priv->handshake_error);
+ finish_handshake (gnutls, &gnutls->priv->handshake_error);
- if (gnutls->priv->handshake_error && error)
- *error = g_error_copy (gnutls->priv->handshake_error);
- return (ret == 0);
+ if (gnutls->priv->handshake_error)
+ {
+ if (error)
+ *error = g_error_copy (gnutls->priv->handshake_error);
+ return FALSE;
+ }
+ else
+ return TRUE;
}
static gboolean
diff --git a/tls/gnutls/gtlsconnection-gnutls.h b/tls/gnutls/gtlsconnection-gnutls.h
index b69eca1..b217f97 100644
--- a/tls/gnutls/gtlsconnection-gnutls.h
+++ b/tls/gnutls/gtlsconnection-gnutls.h
@@ -36,11 +36,7 @@ struct _GTlsConnectionGnutlsClass
void (*failed) (GTlsConnectionGnutls *gnutls);
void (*begin_handshake) (GTlsConnectionGnutls *gnutls);
- gboolean (*verify_peer) (GTlsConnectionGnutls *gnutls,
- GTlsCertificate *peer_certificate,
- GTlsCertificateFlags *errors);
void (*finish_handshake) (GTlsConnectionGnutls *gnutls,
- gboolean success,
GError **inout_error);
};
diff --git a/tls/gnutls/gtlsserverconnection-gnutls.c b/tls/gnutls/gtlsserverconnection-gnutls.c
index 2f05ecf..566b922 100644
--- a/tls/gnutls/gtlsserverconnection-gnutls.c
+++ b/tls/gnutls/gtlsserverconnection-gnutls.c
@@ -187,42 +187,8 @@ g_tls_server_connection_gnutls_begin_handshake (GTlsConnectionGnutls *conn)
gnutls_certificate_server_set_request (session, req_mode);
}
-static gboolean
-g_tls_server_connection_gnutls_verify_peer (GTlsConnectionGnutls *gnutls,
- GTlsCertificate *peer_certificate,
- GTlsCertificateFlags *errors)
-{
- GTlsDatabase *database;
- GError *error = NULL;
-
- database = g_tls_connection_get_database (G_TLS_CONNECTION (gnutls));
- if (database == NULL)
- {
- *errors |= G_TLS_CERTIFICATE_UNKNOWN_CA;
- *errors |= g_tls_certificate_verify (peer_certificate, NULL, NULL);
- }
- else
- {
- *errors |= g_tls_database_verify_chain (database, peer_certificate,
- G_TLS_DATABASE_PURPOSE_AUTHENTICATE_CLIENT, NULL,
- g_tls_connection_get_interaction (G_TLS_CONNECTION (gnutls)),
- G_TLS_DATABASE_VERIFY_NONE,
- NULL, &error);
- if (error)
- {
- g_warning ("failure verifying certificate chain: %s",
- error->message);
- g_clear_error (&error);
- }
- }
-
- return g_tls_connection_emit_accept_certificate (G_TLS_CONNECTION (gnutls),
- peer_certificate, *errors);
-}
-
static void
g_tls_server_connection_gnutls_finish_handshake (GTlsConnectionGnutls *gnutls,
- gboolean success,
GError **inout_error)
{
}
@@ -298,7 +264,6 @@ g_tls_server_connection_gnutls_class_init (GTlsServerConnectionGnutlsClass *klas
connection_gnutls_class->failed = g_tls_server_connection_gnutls_failed;
connection_gnutls_class->begin_handshake = g_tls_server_connection_gnutls_begin_handshake;
- connection_gnutls_class->verify_peer = g_tls_server_connection_gnutls_verify_peer;
connection_gnutls_class->finish_handshake = g_tls_server_connection_gnutls_finish_handshake;
g_object_class_override_property (gobject_class, PROP_AUTHENTICATION_MODE, "authentication-mode");
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]