[glib/wip/tingping/pkcs11] gtlscertificate: Add support for PKCS #11 backed certificates



commit 4d4c0cfaf83851dd289f9328a75dc19cfde31558
Author: Patrick Griffis <pgriffis igalia com>
Date:   Wed Jun 19 09:10:52 2019 -0700

    gtlscertificate: Add support for PKCS #11 backed certificates
    
    This adds properties to allow backends to expose PKCS #11 support.

 docs/reference/gio/gio-sections-common.txt |   1 +
 gio/gtlscertificate.c                      | 132 ++++++++++++++++++++++++++++-
 gio/gtlscertificate.h                      |   5 ++
 gio/tests/gtesttlsbackend.c                |  15 +++-
 gio/tests/tls-certificate.c                |  35 ++++++++
 5 files changed, 184 insertions(+), 4 deletions(-)
---
diff --git a/docs/reference/gio/gio-sections-common.txt b/docs/reference/gio/gio-sections-common.txt
index bb483b0ce..373ae5777 100644
--- a/docs/reference/gio/gio-sections-common.txt
+++ b/docs/reference/gio/gio-sections-common.txt
@@ -3697,6 +3697,7 @@ GTlsCertificate
 g_tls_certificate_new_from_pem
 g_tls_certificate_new_from_file
 g_tls_certificate_new_from_files
+g_tls_certificate_new_from_pkcs11_uris
 g_tls_certificate_list_new_from_file
 g_tls_certificate_get_issuer
 g_tls_certificate_verify
diff --git a/gio/gtlscertificate.c b/gio/gtlscertificate.c
index 72de5eb1f..ca9c9b67b 100644
--- a/gio/gtlscertificate.c
+++ b/gio/gtlscertificate.c
@@ -60,7 +60,9 @@ enum
   PROP_CERTIFICATE_PEM,
   PROP_PRIVATE_KEY,
   PROP_PRIVATE_KEY_PEM,
-  PROP_ISSUER
+  PROP_ISSUER,
+  PROP_PKCS11_URI,
+  PROP_PRIVATE_KEY_PKCS11_URI,
 };
 
 static void
@@ -74,7 +76,16 @@ g_tls_certificate_get_property (GObject    *object,
                                GValue     *value,
                                GParamSpec *pspec)
 {
-  G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+  switch (prop_id)
+    {
+      case PROP_PKCS11_URI:
+      case PROP_PRIVATE_KEY_PKCS11_URI:
+        /* Subclasses must override this property but this allows older backends to not fatally error */
+        g_value_set_static_string (value, NULL);
+        break;
+      default:
+        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+    }
 }
 
 static void
@@ -83,7 +94,15 @@ g_tls_certificate_set_property (GObject      *object,
                                const GValue *value,
                                GParamSpec   *pspec)
 {
-  G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+  switch (prop_id)
+    {
+      case PROP_PKCS11_URI:
+      case PROP_PRIVATE_KEY_PKCS11_URI:
+        /* Subclasses must override this property but this allows older backends to not fatally error */
+        break;
+      default:
+        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+    }
 }
 
 static void
@@ -193,6 +212,42 @@ g_tls_certificate_class_init (GTlsCertificateClass *class)
                                                        G_PARAM_READWRITE |
                                                        G_PARAM_CONSTRUCT_ONLY |
                                                        G_PARAM_STATIC_STRINGS));
+
+  /**
+   * GTlsCertificate:pkcs11-uri: (nullable)
+   *
+   * A URI referencing the PKCS \#11 objects containing an X.509 certificate
+   * and optionally a private key.
+   *
+   * If %NULL the certificate is either not backed by PKCS \#11 or the
+   * #GTlsBackend does not support PKCS \#11.
+   *
+   * Since: 2.64
+   */
+  g_object_class_install_property (gobject_class, PROP_PKCS11_URI,
+                                   g_param_spec_string ("pkcs11-uri",
+                                                        P_("PKCS #11 URI"),
+                                                        P_("The PKCS #11 URI"),
+                                                        NULL,
+                                                        G_PARAM_READWRITE |
+                                                        G_PARAM_CONSTRUCT_ONLY |
+                                                        G_PARAM_STATIC_STRINGS));
+
+  /**
+   * GTlsCertificate:private-key-pkcs11-uri: (nullable)
+   *
+   * A URI referencing a PKCS \#11 object containing a private key.
+   *
+   * Since: 2.64
+   */
+  g_object_class_install_property (gobject_class, PROP_PRIVATE_KEY_PKCS11_URI,
+                                   g_param_spec_string ("private-key-pkcs11-uri",
+                                                        P_("PKCS #11 URI"),
+                                                        P_("The PKCS #11 URI for a private key"),
+                                                        NULL,
+                                                        G_PARAM_READWRITE |
+                                                        G_PARAM_CONSTRUCT_ONLY |
+                                                        G_PARAM_STATIC_STRINGS));
 }
 
 static GTlsCertificate *
@@ -591,6 +646,77 @@ g_tls_certificate_new_from_files (const gchar  *cert_file,
   return cert;
 }
 
+/**
+ * g_tls_certificate_new_from_pkcs11_uris:
+ * @pkcs11_uri: A PKCS \#11 URI
+ * @private_key_pkcs11_uri: (nullable): A PKCS \#11 URI
+ * @error: #GError for error reporting, or %NULL to ignore.
+ *
+ * Creates a #GTlsCertificate from a PKCS \#11 URI.
+ *
+ * An example @pkcs11_uri would be 
`pkcs11:model=Model;manufacturer=Manufacture;serial=1;token=My%20Client%20Certificate;id=%01`
+ *
+ * Where the token’s layout is:
+ *
+ * ```
+ * Object 0:
+ *   URL: 
pkcs11:model=Model;manufacturer=Manufacture;serial=1;token=My%20Client%20Certificate;id=%01;object=private%20key;type=private
+ *   Type: Private key (RSA-2048)
+ *   ID: 01
+ *
+ * Object 1:
+ *   URL: 
pkcs11:model=Model;manufacturer=Manufacture;serial=1;token=My%20Client%20Certificate;id=%01;object=Certificate%20for%20Authentication;type=cert
+ *   Type: X.509 Certificate (RSA-2048)
+ *   ID: 01
+ * ```
+ *
+ * In this case the certificate and private key would both be detected and used as expected.
+ * @pkcs_uri may also just reference an X.509 certificate object and then optionally
+ * @private_key_pkcs11_uri allows using a private key exposed under a different URI.
+ *
+ * Note that the private key is not accessed until usage and may fail or require a PIN later.
+ *
+ * Returns: (transfer full): the new certificate, or %NULL on error
+ *
+ * Since: 2.64
+ */
+GTlsCertificate *
+g_tls_certificate_new_from_pkcs11_uris (const gchar  *pkcs11_uri,
+                                        const gchar  *private_key_pkcs11_uri,
+                                        GError      **error)
+{
+  GObject *cert;
+  GTlsBackend *backend;
+
+  g_return_val_if_fail (error == NULL || *error == NULL, NULL);
+  g_return_val_if_fail (pkcs11_uri, NULL);
+
+  backend = g_tls_backend_get_default ();
+
+  cert = g_initable_new (g_tls_backend_get_certificate_type (backend),
+                         NULL, error,
+                         "pkcs11-uri", pkcs11_uri,
+                         "private-key-pkcs11-uri", private_key_pkcs11_uri,
+                         NULL);
+
+  if (cert != NULL)
+    {
+      gchar *objects_uri;
+
+      /* Old implementations might not override this property */
+      g_object_get (cert, "pkcs11-uri", &objects_uri, NULL);
+      if (objects_uri == NULL)
+        {
+          g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, _("This GTlsBackend does not 
support creating PKCS #11 certificates"));
+          g_object_unref (cert);
+          return NULL;
+        }
+      g_free (objects_uri);
+    }
+
+  return G_TLS_CERTIFICATE (cert);
+}
+
 /**
  * g_tls_certificate_list_new_from_file:
  * @file: (type filename): file containing PEM-encoded certificates to import
diff --git a/gio/gtlscertificate.h b/gio/gtlscertificate.h
index a064543c4..66fe59a03 100644
--- a/gio/gtlscertificate.h
+++ b/gio/gtlscertificate.h
@@ -71,6 +71,11 @@ GLIB_AVAILABLE_IN_ALL
 GTlsCertificate      *g_tls_certificate_new_from_files     (const gchar         *cert_file,
                                                            const gchar         *key_file,
                                                            GError             **error);
+GLIB_AVAILABLE_IN_2_64
+GTlsCertificate      *g_tls_certificate_new_from_pkcs11_uris (const gchar       *pkcs11_uri,
+                                                              const gchar       *private_key_pkcs11_uri,
+                                                              GError           **error);
+
 GLIB_AVAILABLE_IN_ALL
 GList                *g_tls_certificate_list_new_from_file (const gchar         *file,
                                                            GError             **error);
diff --git a/gio/tests/gtesttlsbackend.c b/gio/tests/gtesttlsbackend.c
index 157a4a3f3..3460753df 100644
--- a/gio/tests/gtesttlsbackend.c
+++ b/gio/tests/gtesttlsbackend.c
@@ -91,6 +91,7 @@ struct _GTestTlsCertificate {
   gchar *key_pem;
   gchar *cert_pem;
   GTlsCertificate *issuer;
+  gchar *pkcs11_uri;
 };
 
 struct _GTestTlsCertificateClass {
@@ -103,7 +104,8 @@ enum
   PROP_CERT_CERTIFICATE_PEM,
   PROP_CERT_PRIVATE_KEY,
   PROP_CERT_PRIVATE_KEY_PEM,
-  PROP_CERT_ISSUER
+  PROP_CERT_ISSUER,
+  PROP_CERT_PKCS11_URI,
 };
 
 static void g_test_tls_certificate_initable_iface_init (GInitableIface *iface);
@@ -141,6 +143,12 @@ g_test_tls_certificate_get_property (GObject    *object,
     case PROP_CERT_ISSUER:
       g_value_set_object (value, cert->issuer);
       break;
+    case PROP_CERT_PKCS11_URI:
+      /* This test value simulates a backend that ignores the value
+         because it is unsupported */
+      if (g_strcmp0 (cert->pkcs11_uri, "unsupported") != 0)
+        g_value_set_string (value, cert->pkcs11_uri);
+      break;
     default:
       g_assert_not_reached ();
       break;
@@ -166,6 +174,9 @@ g_test_tls_certificate_set_property (GObject      *object,
     case PROP_CERT_ISSUER:
       cert->issuer = g_value_dup_object (value);
       break;
+    case PROP_CERT_PKCS11_URI:
+      cert->pkcs11_uri = g_value_dup_string (value);
+      break;
     case PROP_CERT_CERTIFICATE:
     case PROP_CERT_PRIVATE_KEY:
       /* ignore */
@@ -183,6 +194,7 @@ g_test_tls_certificate_finalize (GObject *object)
 
   g_free (cert->cert_pem);
   g_free (cert->key_pem);
+  g_free (cert->pkcs11_uri);
   g_clear_object (&cert->issuer);
 
   G_OBJECT_CLASS (g_test_tls_certificate_parent_class)->finalize (object);
@@ -205,6 +217,7 @@ g_test_tls_certificate_class_init (GTestTlsCertificateClass *test_class)
   g_object_class_override_property (gobject_class, PROP_CERT_PRIVATE_KEY, "private-key");
   g_object_class_override_property (gobject_class, PROP_CERT_PRIVATE_KEY_PEM, "private-key-pem");
   g_object_class_override_property (gobject_class, PROP_CERT_ISSUER, "issuer");
+  g_object_class_override_property (gobject_class, PROP_CERT_PKCS11_URI, "pkcs11-uri");
 }
 
 static void
diff --git a/gio/tests/tls-certificate.c b/gio/tests/tls-certificate.c
index e1ba23737..8f125b0a0 100644
--- a/gio/tests/tls-certificate.c
+++ b/gio/tests/tls-certificate.c
@@ -398,6 +398,36 @@ list_from_file (const Reference *ref)
   g_assert_cmpint (g_list_length (list), ==, 0);
 }
 
+static void
+from_pkcs11_uri (void)
+{
+  GError *error = NULL;
+  GTlsCertificate *cert;
+  gchar *pkcs11_uri = NULL;
+
+  cert = g_tls_certificate_new_from_pkcs11_uris 
("pkcs11:model=p11-kit-trust;manufacturer=PKCS%2311%20Kit;serial=1;token=ca-bundle.crt", NULL, &error);
+  g_assert_no_error (error);
+  g_assert_nonnull (cert);
+
+  g_object_get (cert, "pkcs11-uri", &pkcs11_uri, NULL);
+  g_assert_cmpstr ("pkcs11:model=p11-kit-trust;manufacturer=PKCS%2311%20Kit;serial=1;token=ca-bundle.crt", 
==, pkcs11_uri);
+  g_free (pkcs11_uri);
+
+  g_object_unref (cert);
+}
+
+static void
+from_unsupported_pkcs11_uri (void)
+{
+  GError *error = NULL;
+  GTlsCertificate *cert;
+
+  /* This is a magic value in gtesttlsbackend.c simulating an unsupported backend */
+  cert = g_tls_certificate_new_from_pkcs11_uris ("unsupported", NULL, &error);
+  g_assert_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED);
+  g_assert_null (cert);
+}
+
 int
 main (int   argc,
       char *argv[])
@@ -464,6 +494,11 @@ main (int   argc,
                         &ref, (GTestDataFunc)from_files_pkcs8enc);
   g_test_add_data_func ("/tls-certificate/list_from_file",
                         &ref, (GTestDataFunc)list_from_file);
+  g_test_add_func ("/tls-certificate/pkcs11-uri",
+                   from_pkcs11_uri);
+  g_test_add_func ("/tls-certificate/pkcs11-uri-unsupported",
+                   from_unsupported_pkcs11_uri);
+
 
   rtv = g_test_run();
 


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