[glib-networking] gnutls: Fix up GTlsCertificateFlags handling



commit dc8510f338b74315387bbbfdd07f2661196d1ef1
Author: Dan Winship <danw gnome org>
Date:   Tue Dec 7 23:10:23 2010 +0100

    gnutls: Fix up GTlsCertificateFlags handling
    
    If a certificate isn't signed by a known CA, gnutls won't bother
    checking some of the other things (eg, expiration). But callers
    might be planning to do the CA check themselves, in which case we
    need to do the other checks anyway. So do that.

 tls/gnutls/gtlscertificate-gnutls.c      |   52 +++++++++++++++++++-----------
 tls/gnutls/gtlsclientconnection-gnutls.c |    2 -
 tls/gnutls/gtlsconnection-gnutls.c       |   23 ++++++++-----
 tls/gnutls/gtlsconnection-gnutls.h       |    1 -
 tls/gnutls/gtlsserverconnection-gnutls.c |    2 -
 5 files changed, 47 insertions(+), 33 deletions(-)
---
diff --git a/tls/gnutls/gtlscertificate-gnutls.c b/tls/gnutls/gtlscertificate-gnutls.c
index 29e992f..68b6e2d 100644
--- a/tls/gnutls/gtlscertificate-gnutls.c
+++ b/tls/gnutls/gtlscertificate-gnutls.c
@@ -285,10 +285,10 @@ g_tls_certificate_gnutls_verify (GTlsCertificate     *cert,
 				 GTlsCertificate     *trusted_ca)
 {
   GTlsCertificateGnutls *cert_gnutls;
-  int status;
-  guint gnutls_flags, num_certs, i, num_cas;
-  gnutls_x509_crt_t *chain, ca;
+  guint num_certs, i;
+  gnutls_x509_crt_t *chain;
   GTlsCertificateFlags gtls_flags;
+  time_t t, now;
   
   cert_gnutls = G_TLS_CERTIFICATE_GNUTLS (cert);
   for (num_certs = 0; cert_gnutls; cert_gnutls = cert_gnutls->priv->issuer)
@@ -300,28 +300,42 @@ g_tls_certificate_gnutls_verify (GTlsCertificate     *cert,
 
   if (trusted_ca)
     {
-      cert_gnutls = G_TLS_CERTIFICATE_GNUTLS (trusted_ca);
-      ca = cert_gnutls->priv->cert;
-      num_cas = 1;
+      gnutls_x509_crt_t ca;
+      guint gnutls_flags;
+      int status;
+
+      ca = G_TLS_CERTIFICATE_GNUTLS (trusted_ca)->priv->cert;
+      status = gnutls_x509_crt_list_verify (chain, num_certs,
+					    &ca, 1,
+					    NULL, 0,
+					    GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT,
+					    &gnutls_flags);
+      if (status != 0)
+	{
+	  g_free (chain);
+	  return G_TLS_CERTIFICATE_GENERIC_ERROR;
+	}
+
+      gtls_flags = g_tls_certificate_gnutls_convert_flags (gnutls_flags);
     }
-  else
+
+  /* We have to check these ourselves since gnutls_x509_crt_list_verify
+   * won't bother if it gets an UNKNOWN_CA.
+   */
+  now = time (NULL);
+  for (i = 0; i < num_certs; i++)
     {
-      ca = NULL;
-      num_cas = 0;
+      t = gnutls_x509_crt_get_activation_time (chain[i]);
+      if (t == (time_t) -1 || t > now)
+	gtls_flags |= G_TLS_CERTIFICATE_NOT_ACTIVATED;
+
+      t = gnutls_x509_crt_get_expiration_time (chain[i]);
+      if (t == (time_t) -1 || t < now)
+	gtls_flags |= G_TLS_CERTIFICATE_EXPIRED;
     }
 
-  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);
 
diff --git a/tls/gnutls/gtlsclientconnection-gnutls.c b/tls/gnutls/gtlsclientconnection-gnutls.c
index 476a60b..5b2fb95 100644
--- a/tls/gnutls/gtlsclientconnection-gnutls.c
+++ b/tls/gnutls/gtlsclientconnection-gnutls.c
@@ -256,8 +256,6 @@ g_tls_client_connection_gnutls_verify_peer (GTlsConnectionGnutls  *conn_gnutls,
   GTlsClientConnectionGnutls *gnutls = G_TLS_CLIENT_CONNECTION_GNUTLS (conn_gnutls);
   gboolean accepted;
 
-  *errors = g_tls_connection_gnutls_validate_peer (conn_gnutls);
-
   if (gnutls->priv->server_identity)
     {
       *errors |= g_tls_certificate_gnutls_verify_identity (G_TLS_CERTIFICATE_GNUTLS (peer_certificate),
diff --git a/tls/gnutls/gtlsconnection-gnutls.c b/tls/gnutls/gtlsconnection-gnutls.c
index de25e4d..6239890 100644
--- a/tls/gnutls/gtlsconnection-gnutls.c
+++ b/tls/gnutls/gtlsconnection-gnutls.c
@@ -442,15 +442,6 @@ g_tls_connection_gnutls_get_certificate (GTlsConnectionGnutls *gnutls,
     st->ncerts = 0;
 }
 
-GTlsCertificateFlags
-g_tls_connection_gnutls_validate_peer (GTlsConnectionGnutls *gnutls)
-{
-  int status;
-
-  status = gnutls_certificate_verify_peers (gnutls->priv->session);
-  return g_tls_certificate_gnutls_convert_flags (status);
-}
-
 static void
 begin_gnutls_io (GTlsConnectionGnutls  *gnutls,
 		 gboolean               blocking,
@@ -865,6 +856,20 @@ handshake_internal (GTlsConnectionGnutls  *gnutls,
 
   if (peer_certificate)
     {
+      int status;
+
+      status = gnutls_certificate_verify_peers (gnutls->priv->session);
+      peer_certificate_errors = g_tls_certificate_gnutls_convert_flags (status);
+      if (peer_certificate_errors)
+	{
+	  /* gnutls_certificate_verify_peers() bails out on the first
+	   * error, which may be G_TLS_CERTIFICATE_UNKNOWN_CA, but the
+	   * caller may be planning to check that part themselves. So
+	   * call g_tls_certificate_verify() to get any other errors.
+	   */
+	  peer_certificate_errors |= g_tls_certificate_verify (peer_certificate, NULL, NULL);
+	}
+
       if (!G_TLS_CONNECTION_GNUTLS_GET_CLASS (gnutls)->verify_peer (gnutls, peer_certificate, &peer_certificate_errors))
 	{
 	  g_object_unref (peer_certificate);
diff --git a/tls/gnutls/gtlsconnection-gnutls.h b/tls/gnutls/gtlsconnection-gnutls.h
index 0e54df8..fff49af 100644
--- a/tls/gnutls/gtlsconnection-gnutls.h
+++ b/tls/gnutls/gtlsconnection-gnutls.h
@@ -53,7 +53,6 @@ gnutls_certificate_credentials g_tls_connection_gnutls_get_credentials (GTlsConn
 gnutls_session                 g_tls_connection_gnutls_get_session     (GTlsConnectionGnutls *connection);
 void                           g_tls_connection_gnutls_get_certificate (GTlsConnectionGnutls *gnutls,
 									 gnutls_retr_st       *st);
-GTlsCertificateFlags           g_tls_connection_gnutls_validate_peer   (GTlsConnectionGnutls *gnutls);
 
 gssize   g_tls_connection_gnutls_read          (GTlsConnectionGnutls  *gnutls,
 						void                  *buffer,
diff --git a/tls/gnutls/gtlsserverconnection-gnutls.c b/tls/gnutls/gtlsserverconnection-gnutls.c
index 6e9a8bd..e374b63 100644
--- a/tls/gnutls/gtlsserverconnection-gnutls.c
+++ b/tls/gnutls/gtlsserverconnection-gnutls.c
@@ -174,8 +174,6 @@ g_tls_server_connection_gnutls_verify_peer (GTlsConnectionGnutls  *gnutls,
 					    GTlsCertificate       *peer_certificate,
 					    GTlsCertificateFlags  *errors)
 {
-  *errors = g_tls_connection_gnutls_validate_peer (G_TLS_CONNECTION_GNUTLS (gnutls));
-
   return g_tls_connection_emit_accept_certificate (G_TLS_CONNECTION (gnutls),
 						   peer_certificate, *errors);
 }



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]