From a17c28790ac4111878961f6b0973068deebe9fcc Mon Sep 17 00:00:00 2001 From: "Ross A. Wollman" Date: Wed, 26 May 2021 07:59:37 +0000 Subject: [PATCH] tls: expose cert details on GTlsCertificate This changeset exposes * `not-valid-before` * `not-valid-after` * `subject-name` * `issuer-name` on GTlsCertificate provided by the underlying TLS Backend. In order to make use of these changes, see the related [glib-networking MR][glib-networking]. This change aims to help populate more of the [`Certificate`][wk-cert] info in the WebKit Inspector Protocol on Linux. This changeset stems from work in Microsoft Playwright to [add more info into its HAR capture][pw] generated from the Inspector Protocol events and will bring feature parity across WebKit platforms. [wk-cert]: https://github.com/WebKit/WebKit/blob/8afe31a018b11741abdf9b4d5bb973d7c1d9ff05/Source/JavaScriptCore/inspector/protocol/Security.json [pw]: https://github.com/microsoft/playwright/pull/6631 [glib-networking]: https://gitlab.gnome.org/GNOME/glib-networking/-/merge_requests/156 --- docs/reference/gio/gio-sections-common.txt | 4 + gio/gtlscertificate.c | 156 +++++++++++++++++++++ gio/gtlscertificate.h | 12 ++ gio/tests/gtesttlsbackend.c | 20 +++ gio/tests/tls-certificate.c | 94 +++++++++++++ 5 files changed, 286 insertions(+) diff --git a/docs/reference/gio/gio-sections-common.txt b/docs/reference/gio/gio-sections-common.txt index e38971c12..ece7d5db1 100644 --- a/docs/reference/gio/gio-sections-common.txt +++ b/docs/reference/gio/gio-sections-common.txt @@ -3716,6 +3716,10 @@ 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_get_issuer_name +g_tls_certificate_get_not_valid_before +g_tls_certificate_get_not_valid_after +g_tls_certificate_get_subject_name g_tls_certificate_verify g_tls_certificate_is_same diff --git a/gio/gtlscertificate.c b/gio/gtlscertificate.c index ae9e88016..c46ad107c 100644 --- a/gio/gtlscertificate.c +++ b/gio/gtlscertificate.c @@ -63,6 +63,10 @@ enum PROP_ISSUER, PROP_PKCS11_URI, PROP_PRIVATE_KEY_PKCS11_URI, + PROP_NOT_VALID_BEFORE, + PROP_NOT_VALID_AFTER, + PROP_SUBJECT_NAME, + PROP_ISSUER_NAME, }; static void @@ -248,6 +252,69 @@ g_tls_certificate_class_init (GTlsCertificateClass *class) G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS)); + + /** + * GTlsCertificate:not-valid-before: (nullable) + * + * The time at which this cert is considered to be valid, + * %NULL if unavailable. + * + * Since: 2.70 + */ + g_object_class_install_property (gobject_class, PROP_NOT_VALID_BEFORE, + g_param_spec_boxed ("not-valid-before", + P_("Not Valid Before"), + P_("Cert should not be considered valid before this time."), + G_TYPE_DATE_TIME, + G_PARAM_READABLE | + G_PARAM_STATIC_STRINGS)); + + /** + * GTlsCertificate:not-valid-after: (nullable) + * + * The time at which this cert is no longer valid, + * %NULL if unavailable. + * + * Since: 2.70 + */ + g_object_class_install_property (gobject_class, PROP_NOT_VALID_AFTER, + g_param_spec_boxed ("not-valid-after", + P_("Not Valid after"), + P_("Cert should not be considered valid after this time."), + G_TYPE_DATE_TIME, + G_PARAM_READABLE | + G_PARAM_STATIC_STRINGS)); + + /** + * GTlsCertificate:subject-name: (nullable) + * + * The subject from the cert, + * %NULL if unavailable. + * + * Since: 2.70 + */ + g_object_class_install_property (gobject_class, PROP_SUBJECT_NAME, + g_param_spec_string ("subject-name", + P_("Subject Name"), + P_("The subject name from the certificate."), + NULL, + G_PARAM_READABLE | + G_PARAM_STATIC_STRINGS)); + /** + * GTlsCertificate:issuer-name: (nullable) + * + * The issuer from the certificate, + * %NULL if unavailable. + * + * Since: 2.70 + */ + g_object_class_install_property (gobject_class, PROP_ISSUER_NAME, + g_param_spec_string ("issuer-name", + P_("Issuer Name"), + P_("The issuer from the certificate."), + NULL, + G_PARAM_READABLE | + G_PARAM_STATIC_STRINGS)); } static GTlsCertificate * @@ -876,3 +943,92 @@ g_tls_certificate_is_same (GTlsCertificate *cert_one, return equal; } + + +/** + * g_tls_certificate_get_not_valid_before: + * @cert: a #GTlsCertificate + * + * Returns the time at which the certificate became or will become valid. + * + * Returns: (nullable) (transfer full): The not-valid-before date, or %NULL if it's not available. + * + * Since: 2.70 + */ +GDateTime * +g_tls_certificate_get_not_valid_before (GTlsCertificate *cert) +{ + GDateTime *not_valid_before = NULL; + + g_return_val_if_fail (G_IS_TLS_CERTIFICATE (cert), NULL); + + g_object_get (G_OBJECT (cert), "not-valid-before", ¬_valid_before, NULL); + + return g_steal_pointer (¬_valid_before); +} + +/** + * g_tls_certificate_get_not_valid_after: + * @cert: a #GTlsCertificate + * + * Returns the time at which the certificate became or will become invalid. + * + * Returns: (nullable) (transfer full): The not-valid-after date, or %NULL if it's not available. + * + * Since: 2.70 + */ +GDateTime * +g_tls_certificate_get_not_valid_after (GTlsCertificate *cert) +{ + GDateTime *not_valid_after = NULL; + + g_return_val_if_fail (G_IS_TLS_CERTIFICATE (cert), NULL); + + g_object_get (G_OBJECT (cert), "not-valid-after", ¬_valid_after, NULL); + + return g_steal_pointer (¬_valid_after); +} + +/** + * g_tls_certificate_get_subject_name: + * @cert: a #GTlsCertificate + * + * Returns the subject name from the certificate. + * + * Returns: (nullable) (transfer full): The subject name, or %NULL if it's not available. + * + * Since: 2.70 + */ +gchar * +g_tls_certificate_get_subject_name (GTlsCertificate *cert) +{ + gchar *subject_name = NULL; + + g_return_val_if_fail (G_IS_TLS_CERTIFICATE (cert), NULL); + + g_object_get (G_OBJECT (cert), "subject-name", &subject_name, NULL); + + return g_steal_pointer (&subject_name); +} + +/** + * g_tls_certificate_get_issuer_name: + * @cert: a #GTlsCertificate + * + * Returns the issuer name from the certificate. + * + * Returns: (nullable) (transfer full): The issuer name, or %NULL if it's not available. + * + * Since: 2.70 + */ +gchar * +g_tls_certificate_get_issuer_name (GTlsCertificate *cert) +{ + gchar *issuer_name = NULL; + + g_return_val_if_fail (G_IS_TLS_CERTIFICATE (cert), NULL); + + g_object_get (G_OBJECT (cert), "issuer-name", &issuer_name, NULL); + + return g_steal_pointer (&issuer_name); +} diff --git a/gio/gtlscertificate.h b/gio/gtlscertificate.h index ead4f015e..27307d8a2 100644 --- a/gio/gtlscertificate.h +++ b/gio/gtlscertificate.h @@ -92,6 +92,18 @@ GLIB_AVAILABLE_IN_2_34 gboolean g_tls_certificate_is_same (GTlsCertificate *cert_one, GTlsCertificate *cert_two); +GLIB_AVAILABLE_IN_2_70 +GDateTime *g_tls_certificate_get_not_valid_before (GTlsCertificate *cert); + +GLIB_AVAILABLE_IN_2_70 +GDateTime *g_tls_certificate_get_not_valid_after (GTlsCertificate *cert); + +GLIB_AVAILABLE_IN_2_70 +gchar *g_tls_certificate_get_subject_name (GTlsCertificate *cert); + +GLIB_AVAILABLE_IN_2_70 +gchar *g_tls_certificate_get_issuer_name (GTlsCertificate *cert); + G_END_DECLS #endif /* __G_TLS_CERTIFICATE_H__ */ diff --git a/gio/tests/gtesttlsbackend.c b/gio/tests/gtesttlsbackend.c index 56d155031..869c71673 100644 --- a/gio/tests/gtesttlsbackend.c +++ b/gio/tests/gtesttlsbackend.c @@ -110,6 +110,10 @@ enum PROP_CERT_ISSUER, PROP_CERT_PKCS11_URI, PROP_CERT_PRIVATE_KEY_PKCS11_URI, + PROP_CERT_NOT_VALID_BEFORE, + PROP_CERT_NOT_VALID_AFTER, + PROP_CERT_SUBJECT_NAME, + PROP_CERT_ISSUER_NAME, }; static void g_test_tls_certificate_initable_iface_init (GInitableIface *iface); @@ -156,6 +160,18 @@ g_test_tls_certificate_get_property (GObject *object, case PROP_CERT_PRIVATE_KEY_PKCS11_URI: g_value_set_string (value, cert->private_key_pkcs11_uri); break; + case PROP_CERT_NOT_VALID_BEFORE: + g_value_take_boxed (value, g_date_time_new_from_iso8601 ("2020-10-12T17:49:44Z", NULL)); + break; + case PROP_CERT_NOT_VALID_AFTER: + g_value_take_boxed (value, g_date_time_new_from_iso8601 ("2045-10-06T17:49:44Z", NULL)); + break; + case PROP_CERT_SUBJECT_NAME: + g_value_set_string (value, "DC=COM,DC=EXAMPLE,CN=server.example.com"); + break; + case PROP_CERT_ISSUER_NAME: + g_value_set_string (value, "DC=COM,DC=EXAMPLE,OU=Certificate Authority,CN=ca.example.com,emailAddress=ca@example.com"); + break; default: g_assert_not_reached (); break; @@ -230,6 +246,10 @@ g_test_tls_certificate_class_init (GTestTlsCertificateClass *test_class) 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"); + g_object_class_override_property (gobject_class, PROP_CERT_NOT_VALID_BEFORE, "not-valid-before"); + g_object_class_override_property (gobject_class, PROP_CERT_NOT_VALID_AFTER, "not-valid-after"); + g_object_class_override_property (gobject_class, PROP_CERT_SUBJECT_NAME, "subject-name"); + g_object_class_override_property (gobject_class, PROP_CERT_ISSUER_NAME, "issuer-name"); } static void diff --git a/gio/tests/tls-certificate.c b/gio/tests/tls-certificate.c index c0fc80c4b..cfc349ea1 100644 --- a/gio/tests/tls-certificate.c +++ b/gio/tests/tls-certificate.c @@ -430,6 +430,92 @@ from_unsupported_pkcs11_uri (void) g_clear_error (&error); } +static void +not_valid_before (void) +{ + const gchar *EXPECTED_NOT_VALID_BEFORE = "2020-10-12T17:49:44Z"; + + GTlsCertificate *cert; + GError *error = NULL; + GDateTime *actual; + gchar *actual_str; + + 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); + + actual = g_tls_certificate_get_not_valid_before (cert); + g_assert_nonnull (actual); + actual_str = g_date_time_format_iso8601 (actual); + g_assert_cmpstr (actual_str, ==, EXPECTED_NOT_VALID_BEFORE); + g_free (actual_str); + g_date_time_unref (actual); + g_object_unref (cert); +} + +static void +not_valid_after (void) +{ + const gchar *EXPECTED_NOT_VALID_AFTER = "2045-10-06T17:49:44Z"; + + GTlsCertificate *cert; + GError *error = NULL; + GDateTime *actual; + gchar *actual_str; + + 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); + + actual = g_tls_certificate_get_not_valid_after (cert); + g_assert_nonnull (actual); + actual_str = g_date_time_format_iso8601 (actual); + g_assert_cmpstr (actual_str, ==, EXPECTED_NOT_VALID_AFTER); + g_free (actual_str); + g_date_time_unref (actual); + g_object_unref (cert); +} + +static void +subject_name (void) +{ + const gchar *EXPECTED_SUBJECT_NAME = "DC=COM,DC=EXAMPLE,CN=server.example.com"; + + GTlsCertificate *cert; + GError *error = NULL; + gchar *actual; + + 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); + + actual = g_tls_certificate_get_subject_name (cert); + g_assert_nonnull (actual); + g_assert_cmpstr (actual, ==, EXPECTED_SUBJECT_NAME); + g_free (actual); + g_object_unref (cert); +} + +static void +issuer_name (void) +{ + const gchar *EXPECTED_ISSUER_NAME = "DC=COM,DC=EXAMPLE,OU=Certificate Authority,CN=ca.example.com,emailAddress=ca@example.com"; + + GTlsCertificate *cert; + GError *error = NULL; + gchar *actual; + + 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); + + actual = g_tls_certificate_get_issuer_name (cert); + g_assert_nonnull (actual); + g_assert_cmpstr (actual, ==, EXPECTED_ISSUER_NAME); + g_free (actual); + g_object_unref (cert); +} + int main (int argc, char *argv[]) @@ -500,6 +586,14 @@ main (int argc, from_pkcs11_uri); g_test_add_func ("/tls-certificate/pkcs11-uri-unsupported", from_unsupported_pkcs11_uri); + g_test_add_func ("/tls-certificate/not-valid-before", + not_valid_before); + g_test_add_func ("/tls-certificate/not-valid-after", + not_valid_after); + g_test_add_func ("/tls-certificate/subject-name", + subject_name); + g_test_add_func ("/tls-certificate/issuer-name", + issuer_name); rtv = g_test_run();