[glib-networking/wip/ocsp: 1/2] Revert "openssl: drop half-baked OCSP support"




commit b58273865250edf3716ed304394b1646f8641caa
Author: Patrick Griffis <pgriffis igalia com>
Date:   Thu Jun 17 10:59:42 2021 -0500

    Revert "openssl: drop half-baked OCSP support"
    
    This reverts commit f21a57a04b55e2239a5df4b6aa47b3f7625c5c61.

 tls/base/gtlsconnection-base.c             |  4 ++
 tls/base/gtlsconnection-base.h             |  3 +
 tls/openssl/gtlsclientconnection-openssl.c | 65 +++++++++++++++++++++
 tls/openssl/gtlsdatabase-openssl.c         | 93 ++++++++++++++++++++++++++++++
 tls/openssl/gtlsdatabase-openssl.h         |  4 ++
 tls/openssl/openssl-include.h              |  3 +
 6 files changed, 172 insertions(+)
---
diff --git a/tls/base/gtlsconnection-base.c b/tls/base/gtlsconnection-base.c
index 72551dc..6ed4326 100644
--- a/tls/base/gtlsconnection-base.c
+++ b/tls/base/gtlsconnection-base.c
@@ -1239,6 +1239,7 @@ static GTlsCertificateFlags
 verify_peer_certificate (GTlsConnectionBase *tls,
                          GTlsCertificate    *peer_certificate)
 {
+  GTlsConnectionBaseClass *tls_class = G_TLS_CONNECTION_BASE_GET_CLASS (tls);
   GSocketConnectable *peer_identity = NULL;
   GTlsDatabase *database;
   GTlsCertificateFlags errors = 0;
@@ -1283,6 +1284,9 @@ verify_peer_certificate (GTlsConnectionBase *tls,
         }
     }
 
+  if (tls_class->verify_peer_certificate)
+    errors |= tls_class->verify_peer_certificate (tls, peer_certificate, errors);
+
   return errors;
 }
 
diff --git a/tls/base/gtlsconnection-base.h b/tls/base/gtlsconnection-base.h
index a89122e..d6247b6 100644
--- a/tls/base/gtlsconnection-base.h
+++ b/tls/base/gtlsconnection-base.h
@@ -72,6 +72,9 @@ struct _GTlsConnectionBaseClass
                                                              GCancellable         *cancellable,
                                                              GError              **error);
   GTlsCertificate            *(*retrieve_peer_certificate)  (GTlsConnectionBase   *tls);
+  GTlsCertificateFlags        (*verify_peer_certificate)    (GTlsConnectionBase   *tls,
+                                                             GTlsCertificate      *certificate,
+                                                             GTlsCertificateFlags  flags);
   void                        (*complete_handshake)         (GTlsConnectionBase   *tls,
                                                              gboolean              handshake_succeeded,
                                                              gchar               **negotiated_protocol,
diff --git a/tls/openssl/gtlsclientconnection-openssl.c b/tls/openssl/gtlsclientconnection-openssl.c
index 0e83b03..4249bbe 100644
--- a/tls/openssl/gtlsclientconnection-openssl.c
+++ b/tls/openssl/gtlsclientconnection-openssl.c
@@ -34,6 +34,7 @@
 #include "gtlsclientconnection-openssl.h"
 #include "gtlsbackend-openssl.h"
 #include "gtlscertificate-openssl.h"
+#include "gtlsdatabase-openssl.h"
 #include <glib/gi18n-lib.h>
 
 struct _GTlsClientConnectionOpenssl
@@ -201,6 +202,56 @@ g_tls_client_connection_openssl_complete_handshake (GTlsConnectionBase  *tls,
   g_object_notify (G_OBJECT (client), "accepted-cas");
 }
 
+static GTlsCertificateFlags
+verify_ocsp_response (GTlsClientConnectionOpenssl *openssl,
+                      GTlsCertificate             *peer_certificate)
+{
+#if (OPENSSL_VERSION_NUMBER >= 0x0090808fL) && !defined(OPENSSL_NO_TLSEXT) && !defined(OPENSSL_NO_OCSP)
+  SSL *ssl = NULL;
+  OCSP_RESPONSE *resp = NULL;
+  GTlsDatabase *database;
+  long len = 0;
+  unsigned char *p = NULL;
+
+  ssl = g_tls_connection_openssl_get_ssl (G_TLS_CONNECTION_OPENSSL (openssl));
+  len = SSL_get_tlsext_status_ocsp_resp (ssl, &p);
+  /* Soft fail in case of no response is the best we can do
+   * FIXME: this makes it security theater, why bother with OCSP at all? */
+  if (!p)
+    return 0;
+
+  resp = d2i_OCSP_RESPONSE (NULL, (const unsigned char **)&p, len);
+  if (!resp)
+    return G_TLS_CERTIFICATE_GENERIC_ERROR;
+
+  database = g_tls_connection_get_database (G_TLS_CONNECTION (openssl));
+
+  /* If there's no database, then G_TLS_CERTIFICATE_UNKNOWN_CA must be flagged,
+   * and this function is only called if there are no flags.
+   */
+  g_assert (database);
+
+  return g_tls_database_openssl_verify_ocsp_response (G_TLS_DATABASE_OPENSSL (database),
+                                                      peer_certificate,
+                                                      resp);
+#else
+  return 0;
+#endif
+}
+
+static GTlsCertificateFlags
+g_tls_client_connection_openssl_verify_peer_certificate (GTlsConnectionBase   *tls,
+                                                         GTlsCertificate      *certificate,
+                                                         GTlsCertificateFlags  flags)
+{
+  GTlsClientConnectionOpenssl *openssl = G_TLS_CLIENT_CONNECTION_OPENSSL (tls);
+
+  if (flags == 0)
+    flags = verify_ocsp_response (openssl, certificate);
+
+  return flags;
+}
+
 static SSL *
 g_tls_client_connection_openssl_get_ssl (GTlsConnectionOpenssl *connection)
 {
@@ -219,6 +270,7 @@ g_tls_client_connection_openssl_class_init (GTlsClientConnectionOpensslClass *kl
   gobject_class->set_property         = g_tls_client_connection_openssl_set_property;
 
   base_class->complete_handshake      = g_tls_client_connection_openssl_complete_handshake;
+  base_class->verify_peer_certificate = g_tls_client_connection_openssl_verify_peer_certificate;
 
   openssl_class->get_ssl              = g_tls_client_connection_openssl_get_ssl;
 
@@ -233,6 +285,7 @@ g_tls_client_connection_openssl_init (GTlsClientConnectionOpenssl *openssl)
 {
 }
 
+
 static void
 g_tls_client_connection_openssl_copy_session_state (GTlsClientConnection *conn,
                                                     GTlsClientConnection *source)
@@ -372,6 +425,12 @@ set_curve_list (GTlsClientConnectionOpenssl *client)
 }
 #endif
 
+static gboolean
+use_ocsp (void)
+{
+  return g_getenv ("G_TLS_OPENSSL_OCSP_ENABLED") != NULL;
+}
+
 static gboolean
 g_tls_client_connection_openssl_initable_init (GInitable       *initable,
                                                GCancellable    *cancellable,
@@ -465,6 +524,12 @@ g_tls_client_connection_openssl_initable_init (GInitable       *initable,
 
   SSL_set_connect_state (client->ssl);
 
+#if (OPENSSL_VERSION_NUMBER >= 0x0090808fL) && !defined(OPENSSL_NO_TLSEXT) && \
+    !defined(OPENSSL_NO_OCSP)
+  if (use_ocsp())
+    SSL_set_tlsext_status_type (client->ssl, TLSEXT_STATUSTYPE_ocsp);
+#endif
+
   if (!g_tls_client_connection_openssl_parent_initable_iface->
       init (initable, cancellable, error))
     return FALSE;
diff --git a/tls/openssl/gtlsdatabase-openssl.c b/tls/openssl/gtlsdatabase-openssl.c
index 6cf2f49..65b5ff4 100644
--- a/tls/openssl/gtlsdatabase-openssl.c
+++ b/tls/openssl/gtlsdatabase-openssl.c
@@ -312,3 +312,96 @@ g_tls_database_openssl_new (GError **error)
 
   return g_initable_new (G_TYPE_TLS_DATABASE_OPENSSL, NULL, error, NULL);
 }
+
+GTlsCertificateFlags
+g_tls_database_openssl_verify_ocsp_response (GTlsDatabaseOpenssl *self,
+                                             GTlsCertificate     *chain,
+                                             OCSP_RESPONSE       *resp)
+{
+  GTlsCertificateFlags errors = 0;
+#if (OPENSSL_VERSION_NUMBER >= 0x0090808fL) && !defined(OPENSSL_NO_TLSEXT) && \
+  !defined(OPENSSL_NO_OCSP)
+  GTlsDatabaseOpensslPrivate *priv;
+  STACK_OF(X509) *chain_openssl = NULL;
+  OCSP_BASICRESP *basic_resp = NULL;
+  int ocsp_status = 0;
+  int i;
+
+  ocsp_status = OCSP_response_status (resp);
+  if (ocsp_status != OCSP_RESPONSE_STATUS_SUCCESSFUL)
+    {
+      errors = G_TLS_CERTIFICATE_GENERIC_ERROR;
+      goto end;
+    }
+
+  basic_resp = OCSP_response_get1_basic (resp);
+  if (basic_resp == NULL)
+    {
+      errors = G_TLS_CERTIFICATE_GENERIC_ERROR;
+      goto end;
+    }
+
+  chain_openssl = convert_certificate_chain_to_openssl (G_TLS_CERTIFICATE_OPENSSL (chain));
+  priv = g_tls_database_openssl_get_instance_private (self);
+  if ((chain_openssl == NULL) ||
+      (priv->store == NULL))
+    {
+      errors = G_TLS_CERTIFICATE_GENERIC_ERROR;
+      goto end;
+    }
+
+  if (OCSP_basic_verify (basic_resp, chain_openssl, priv->store, 0) <= 0)
+    {
+      errors = G_TLS_CERTIFICATE_GENERIC_ERROR;
+      goto end;
+    }
+
+  for (i = 0; i < OCSP_resp_count (basic_resp); i++)
+    {
+      OCSP_SINGLERESP *single_resp = OCSP_resp_get0 (basic_resp, i);
+      ASN1_GENERALIZEDTIME *revocation_time = NULL;
+      ASN1_GENERALIZEDTIME *this_update_time = NULL;
+      ASN1_GENERALIZEDTIME *next_update_time = NULL;
+      int crl_reason = 0;
+      int cert_status = 0;
+
+      if (single_resp == NULL)
+        continue;
+
+      cert_status = OCSP_single_get0_status (single_resp,
+                                             &crl_reason,
+                                             &revocation_time,
+                                             &this_update_time,
+                                             &next_update_time);
+      if (!OCSP_check_validity (this_update_time,
+                                next_update_time,
+                                300L,
+                                -1L))
+        {
+          errors = G_TLS_CERTIFICATE_GENERIC_ERROR;
+          goto end;
+        }
+
+      switch (cert_status)
+        {
+        case V_OCSP_CERTSTATUS_GOOD:
+          break;
+        case V_OCSP_CERTSTATUS_REVOKED:
+          errors = G_TLS_CERTIFICATE_REVOKED;
+          goto end;
+        case V_OCSP_CERTSTATUS_UNKNOWN:
+          errors = G_TLS_CERTIFICATE_GENERIC_ERROR;
+          goto end;
+        }
+    }
+
+end:
+  if (basic_resp)
+    OCSP_BASICRESP_free (basic_resp);
+
+  if (resp)
+    OCSP_RESPONSE_free (resp);
+
+#endif
+  return errors;
+}
diff --git a/tls/openssl/gtlsdatabase-openssl.h b/tls/openssl/gtlsdatabase-openssl.h
index 092fdee..f3203c0 100644
--- a/tls/openssl/gtlsdatabase-openssl.h
+++ b/tls/openssl/gtlsdatabase-openssl.h
@@ -46,4 +46,8 @@ struct _GTlsDatabaseOpensslClass
 
 GTlsDatabaseOpenssl      *g_tls_database_openssl_new                      (GError **error);
 
+GTlsCertificateFlags      g_tls_database_openssl_verify_ocsp_response     (GTlsDatabaseOpenssl *self,
+                                                                           GTlsCertificate     *chain,
+                                                                           OCSP_RESPONSE       *resp);
+
 G_END_DECLS
diff --git a/tls/openssl/openssl-include.h b/tls/openssl/openssl-include.h
index 7d394d5..408d9dd 100644
--- a/tls/openssl/openssl-include.h
+++ b/tls/openssl/openssl-include.h
@@ -51,3 +51,6 @@
 #include <openssl/x509_vfy.h>
 #include <openssl/x509v3.h>
 #include <openssl/crypto.h>
+#if (OPENSSL_VERSION_NUMBER >= 0x0090808fL) && !defined(OPENSSL_NO_OCSP)
+#include <openssl/ocsp.h>
+#endif


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