[glib-networking] tls: expose cert details on GTlsCertificate
- From: Michael Catanzaro <mcatanzaro src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [glib-networking] tls: expose cert details on GTlsCertificate
- Date: Wed, 23 Jun 2021 17:38:22 +0000 (UTC)
commit 588d8fb28c176cabaf587a5bb141caed1c31bc65
Author: Ross A. Wollman <ross wollman gmail com>
Date: Wed May 26 08:14:06 2021 +0000
tls: expose cert details on GTlsCertificate
This changeset exposes
* `not-valid-before`
* `not-valid-after`
* `subject-name`
* `issuer-name`
For more information, see related glib MR:
https://gitlab.gnome.org/GNOME/glib/-/merge_requests/2113
tls/gnutls/gtlscertificate-gnutls.c | 49 ++++++++++++++++++++
tls/openssl/gtlscertificate-openssl.c | 53 ++++++++++++++++++++-
tls/tests/certificate.c | 87 +++++++++++++++++++++++++++++++++++
tls/tests/files/create-files.sh | 11 +++++
4 files changed, 199 insertions(+), 1 deletion(-)
---
diff --git a/tls/gnutls/gtlscertificate-gnutls.c b/tls/gnutls/gtlscertificate-gnutls.c
index 62d586a..4c27587 100644
--- a/tls/gnutls/gtlscertificate-gnutls.c
+++ b/tls/gnutls/gtlscertificate-gnutls.c
@@ -42,6 +42,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,
};
struct _GTlsCertificateGnutls
@@ -97,6 +101,9 @@ g_tls_certificate_gnutls_get_property (GObject *object,
char *certificate_pem;
int status;
size_t size;
+ gnutls_x509_dn_t dn;
+ gnutls_datum_t data;
+ time_t time;
switch (prop_id)
{
@@ -157,6 +164,44 @@ g_tls_certificate_gnutls_get_property (GObject *object,
g_value_set_string (value, gnutls->private_key_pkcs11_uri);
break;
+ case PROP_NOT_VALID_BEFORE:
+ time = gnutls_x509_crt_get_activation_time (gnutls->cert);
+ if (time != (time_t)-1)
+ g_value_take_boxed (value, g_date_time_new_from_unix_utc (time));
+ break;
+
+ case PROP_NOT_VALID_AFTER:
+ time = gnutls_x509_crt_get_expiration_time (gnutls->cert);
+ if (time != (time_t)-1)
+ g_value_take_boxed (value, g_date_time_new_from_unix_utc (time));
+ break;
+
+ case PROP_SUBJECT_NAME:
+ status = gnutls_x509_crt_get_subject (gnutls->cert, &dn);
+ if (status != GNUTLS_E_SUCCESS)
+ return;
+
+ status = gnutls_x509_dn_get_str (dn, &data);
+ if (status != GNUTLS_E_SUCCESS)
+ return;
+
+ g_value_take_string (value, g_strndup ((gchar *)data.data, data.size));
+ gnutls_free (data.data);
+ break;
+
+ case PROP_ISSUER_NAME:
+ status = gnutls_x509_crt_get_issuer (gnutls->cert, &dn);
+ if (status != GNUTLS_E_SUCCESS)
+ return;
+
+ status = gnutls_x509_dn_get_str (dn, &data);
+ if (status != GNUTLS_E_SUCCESS)
+ return;
+
+ g_value_take_string (value, g_strndup ((gchar *)data.data, data.size));
+ gnutls_free (data.data);
+ break;
+
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
@@ -411,6 +456,10 @@ g_tls_certificate_gnutls_class_init (GTlsCertificateGnutlsClass *klass)
g_object_class_override_property (gobject_class, PROP_ISSUER, "issuer");
g_object_class_override_property (gobject_class, PROP_PKCS11_URI, "pkcs11-uri");
g_object_class_override_property (gobject_class, PROP_PRIVATE_KEY_PKCS11_URI, "private-key-pkcs11-uri");
+ g_object_class_override_property (gobject_class, PROP_NOT_VALID_BEFORE, "not-valid-before");
+ g_object_class_override_property (gobject_class, PROP_NOT_VALID_AFTER, "not-valid-after");
+ g_object_class_override_property (gobject_class, PROP_SUBJECT_NAME, "subject-name");
+ g_object_class_override_property (gobject_class, PROP_ISSUER_NAME, "issuer-name");
}
static void
diff --git a/tls/openssl/gtlscertificate-openssl.c b/tls/openssl/gtlscertificate-openssl.c
index 2fa9695..dd9664c 100644
--- a/tls/openssl/gtlscertificate-openssl.c
+++ b/tls/openssl/gtlscertificate-openssl.c
@@ -55,7 +55,11 @@ enum
PROP_CERTIFICATE_PEM,
PROP_PRIVATE_KEY,
PROP_PRIVATE_KEY_PEM,
- PROP_ISSUER
+ PROP_ISSUER,
+ PROP_NOT_VALID_BEFORE,
+ PROP_NOT_VALID_AFTER,
+ PROP_SUBJECT_NAME,
+ PROP_ISSUER_NAME,
};
static void g_tls_certificate_openssl_initable_iface_init (GInitableIface *iface);
@@ -94,6 +98,13 @@ g_tls_certificate_openssl_get_property (GObject *object,
char *certificate_pem;
int size;
+ const ASN1_TIME *time_asn1;
+ struct tm time_tm;
+ GDateTime *time;
+ GTimeZone *tz;
+ X509_NAME *name;
+ const char *name_string;
+
switch (prop_id)
{
case PROP_CERTIFICATE:
@@ -134,6 +145,42 @@ g_tls_certificate_openssl_get_property (GObject *object,
g_value_set_object (value, openssl->issuer);
break;
+ case PROP_NOT_VALID_BEFORE:
+ time_asn1 = X509_get0_notBefore (openssl->cert);
+ ASN1_TIME_to_tm (time_asn1, &time_tm);
+ tz = g_time_zone_new_utc ();
+ time = g_date_time_new (tz, time_tm.tm_year + 1900, time_tm.tm_mon + 1, time_tm.tm_mday,
time_tm.tm_hour, time_tm.tm_min, time_tm.tm_sec);
+ g_value_take_boxed (value, time);
+ g_time_zone_unref (tz);
+ break;
+
+ case PROP_NOT_VALID_AFTER:
+ time_asn1 = X509_get0_notAfter (openssl->cert);
+ ASN1_TIME_to_tm (time_asn1, &time_tm);
+ tz = g_time_zone_new_utc ();
+ time = g_date_time_new (tz, time_tm.tm_year + 1900, time_tm.tm_mon + 1, time_tm.tm_mday,
time_tm.tm_hour, time_tm.tm_min, time_tm.tm_sec);
+ g_value_take_boxed (value, time);
+ g_time_zone_unref (tz);
+ break;
+
+ case PROP_SUBJECT_NAME:
+ bio = BIO_new (BIO_s_mem ());
+ name = X509_get_subject_name (openssl->cert);
+ X509_NAME_print_ex (bio, name, 0, XN_FLAG_SEP_COMMA_PLUS);
+ BIO_get_mem_data (bio, (char **)&name_string);
+ g_value_set_string (value, name_string);
+ BIO_free_all (bio);
+ break;
+
+ case PROP_ISSUER_NAME:
+ bio = BIO_new (BIO_s_mem ());
+ name = X509_get_issuer_name (openssl->cert);
+ X509_NAME_print_ex (bio, name, 0, XN_FLAG_SEP_COMMA_PLUS);
+ BIO_get_mem_data (bio, &name_string);
+ g_value_set_string (value, name_string);
+ BIO_free_all (bio);
+ break;
+
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
@@ -359,6 +406,10 @@ g_tls_certificate_openssl_class_init (GTlsCertificateOpensslClass *klass)
g_object_class_override_property (gobject_class, PROP_PRIVATE_KEY, "private-key");
g_object_class_override_property (gobject_class, PROP_PRIVATE_KEY_PEM, "private-key-pem");
g_object_class_override_property (gobject_class, PROP_ISSUER, "issuer");
+ g_object_class_override_property (gobject_class, PROP_NOT_VALID_BEFORE, "not-valid-before");
+ g_object_class_override_property (gobject_class, PROP_NOT_VALID_AFTER, "not-valid-after");
+ g_object_class_override_property (gobject_class, PROP_SUBJECT_NAME, "subject-name");
+ g_object_class_override_property (gobject_class, PROP_ISSUER_NAME, "issuer-name");
}
static void
diff --git a/tls/tests/certificate.c b/tls/tests/certificate.c
index 921f29e..50b7dc3 100644
--- a/tls/tests/certificate.c
+++ b/tls/tests/certificate.c
@@ -576,6 +576,88 @@ test_certificate_is_same (void)
g_object_unref (three);
}
+static void
+test_certificate_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_file (tls_test_file_path ("server.pem"), &error);
+ g_assert_no_error (error);
+
+ 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
+test_certificate_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_file (tls_test_file_path ("server.pem"), &error);
+ g_assert_no_error (error);
+
+ 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
+test_certificate_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_file (tls_test_file_path ("server.pem"), &error);
+ g_assert_no_error (error);
+
+ 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
+test_certificate_issuer_name (void)
+{
+ GTlsCertificate *cert;
+ GError *error = NULL;
+ gchar *actual;
+
+ cert = g_tls_certificate_new_from_file (tls_test_file_path ("server.pem"), &error);
+ g_assert_no_error (error);
+
+ actual = g_tls_certificate_get_issuer_name (cert);
+ g_assert_nonnull (actual);
+ // For GnuTLS the full string includes ",EMAIL=ca example com" at the end while
+ // OpenSSL includes ",emailAddress=ca example com" at the end
+ g_assert (strstr (actual, "DC=COM,DC=EXAMPLE,OU=Certificate Authority,CN=ca.example.com"));
+ g_free (actual);
+ g_object_unref (cert);
+}
+
int
main (int argc,
char *argv[])
@@ -634,5 +716,10 @@ main (int argc,
g_test_add_func ("/tls/" BACKEND "/certificate/is-same", test_certificate_is_same);
+ g_test_add_func ("/tls/" BACKEND "/certificate/not-valid-before", test_certificate_not_valid_before);
+ g_test_add_func ("/tls/" BACKEND "/certificate/not-valid-after", test_certificate_not_valid_after);
+ g_test_add_func ("/tls/" BACKEND "/certificate/subject-name", test_certificate_subject_name);
+ g_test_add_func ("/tls/" BACKEND "/certificate/issuer-name", test_certificate_issuer_name);
+
return g_test_run();
}
diff --git a/tls/tests/files/create-files.sh b/tls/tests/files/create-files.sh
index b4693c8..4eeac0f 100755
--- a/tls/tests/files/create-files.sh
+++ b/tls/tests/files/create-files.sh
@@ -17,6 +17,17 @@ echo " *** IMPORTANT ***"
echo
echo "This script depends on datefudge, openssl, and python3's cryptography module."
echo
+echo "A few manual changes need to be made."
+echo "certificate.c:test_certificate_not_valid_before"
+echo "and certificate.c:test_certificate_not_valid_after have"
+echo "EXPECTED_NOT_VALID_BEFORE and EXPECTED_NOT_VALID_AFTER"
+echo "that needs to be changed to match corresponding validity dates"
+echo "that are part of the new certificate named server.pem."
+echo "One way to obtain the new values is to inspect the output of:"
+echo "$ openssl x509 -inform pem -in ./tls/tests/files/server.pem -noout -text"
+echo
+echo " *** IMPORTANT ***"
+echo
read -p "Press [Enter] key to continue..."
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]