From f9fc29f0b701b9c1ed869ad7cd490547d91698cd Mon Sep 17 00:00:00 2001 From: Patrick Griffis Date: Fri, 25 Sep 2020 12:40:14 -0700 Subject: [PATCH] gtlscertificate: Add support for PKCS #11 backed certificates This reverts commit d58e5de9e9c8d93e64d34aa8a7100bdfbc9b8dac. --- docs/reference/gio/gio-sections-common.txt | 1 + gio/gtlscertificate.c | 132 ++++++++++++++++++++- gio/gtlscertificate.h | 5 + gio/tests/gtesttlsbackend.c | 25 +++- gio/tests/tls-certificate.c | 36 ++++++ 5 files changed, 195 insertions(+), 4 deletions(-) diff --git a/docs/reference/gio/gio-sections-common.txt b/docs/reference/gio/gio-sections-common.txt index 314d1009e..4173f7dcf 100644 --- a/docs/reference/gio/gio-sections-common.txt +++ b/docs/reference/gio/gio-sections-common.txt @@ -3705,6 +3705,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..0668d4905 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.68 + */ + 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.68 + */ + 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.68 + */ +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..ead4f015e 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_68 +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 346a20dd9..56d155031 100644 --- a/gio/tests/gtesttlsbackend.c +++ b/gio/tests/gtesttlsbackend.c @@ -93,6 +93,8 @@ struct _GTestTlsCertificate { gchar *key_pem; gchar *cert_pem; GTlsCertificate *issuer; + gchar *pkcs11_uri; + gchar *private_key_pkcs11_uri; }; struct _GTestTlsCertificateClass { @@ -105,7 +107,9 @@ enum PROP_CERT_CERTIFICATE_PEM, PROP_CERT_PRIVATE_KEY, PROP_CERT_PRIVATE_KEY_PEM, - PROP_CERT_ISSUER + PROP_CERT_ISSUER, + PROP_CERT_PKCS11_URI, + PROP_CERT_PRIVATE_KEY_PKCS11_URI, }; static void g_test_tls_certificate_initable_iface_init (GInitableIface *iface); @@ -143,6 +147,15 @@ 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; + case PROP_CERT_PRIVATE_KEY_PKCS11_URI: + g_value_set_string (value, cert->private_key_pkcs11_uri); + break; default: g_assert_not_reached (); break; @@ -168,6 +181,12 @@ 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_PRIVATE_KEY_PKCS11_URI: + cert->private_key_pkcs11_uri = g_value_dup_string (value); + break; case PROP_CERT_CERTIFICATE: case PROP_CERT_PRIVATE_KEY: /* ignore */ @@ -185,6 +204,8 @@ g_test_tls_certificate_finalize (GObject *object) g_free (cert->cert_pem); g_free (cert->key_pem); + g_free (cert->pkcs11_uri); + g_free (cert->private_key_pkcs11_uri); g_clear_object (&cert->issuer); G_OBJECT_CLASS (g_test_tls_certificate_parent_class)->finalize (object); @@ -207,6 +228,8 @@ 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"); + g_object_class_override_property (gobject_class, PROP_CERT_PRIVATE_KEY_PKCS11_URI, "private-key-pkcs11-uri"); } static void diff --git a/gio/tests/tls-certificate.c b/gio/tests/tls-certificate.c index 89e3d1421..c0fc80c4b 100644 --- a/gio/tests/tls-certificate.c +++ b/gio/tests/tls-certificate.c @@ -398,6 +398,38 @@ 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); + + g_clear_error (&error); +} + int main (int argc, char *argv[]) @@ -464,6 +496,10 @@ 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();