[gcr/tintou/section-field] gcr: Add GcrCertificateSection/Field
- From: Corentin Noël <corentinnoel src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gcr/tintou/section-field] gcr: Add GcrCertificateSection/Field
- Date: Sun, 7 Aug 2022 08:06:03 +0000 (UTC)
commit 052dbecf474ff1853a3a617e0f1780a72715c26a
Author: Corentin Noël <corentin noel collabora com>
Date: Tue May 10 16:08:39 2022 +0200
gcr: Add GcrCertificateSection/Field
Allows to use the same code-path for both GTK3 and GTK4.
Also allow any library-user to reimplement it with the toolkit of its choice or
to adapt it when a different styling is required (e.g. with libadwaita).
egg/egg-hex.c | 27 ++
egg/egg-hex.h | 7 +
gcr-gtk3/gcr-certificate-widget.c | 531 ++---------------------------------
gcr-gtk3/gcr-section.c | 207 +++++++++-----
gcr-gtk3/gcr-section.h | 7 +-
gcr-gtk4/gcr-certificate-widget.c | 532 ++----------------------------------
gcr-gtk4/gcr-section.c | 205 +++++++++-----
gcr-gtk4/gcr-section.h | 7 +-
gcr/gcr-certificate-field-private.h | 75 +++++
gcr/gcr-certificate-field.c | 261 ++++++++++++++++++
gcr/gcr-certificate-field.h | 33 +++
gcr/gcr-certificate-section.c | 211 ++++++++++++++
gcr/gcr-certificate-section.h | 35 +++
gcr/gcr-certificate.c | 436 +++++++++++++++++++++++++++++
gcr/gcr-certificate.h | 2 +
gcr/gcr.h | 2 +
gcr/meson.build | 4 +
gcr/test-certificate.c | 33 +++
meson.build | 2 +-
19 files changed, 1458 insertions(+), 1159 deletions(-)
---
diff --git a/egg/egg-hex.c b/egg/egg-hex.c
index d7d05fce..193468f3 100644
--- a/egg/egg-hex.c
+++ b/egg/egg-hex.c
@@ -153,3 +153,30 @@ egg_hex_encode_full (gconstpointer data,
return g_string_free (result, FALSE);
}
+
+gchar*
+egg_hex_encode_bytes (GBytes *bytes)
+{
+ gsize size;
+ gconstpointer data;
+
+ g_return_val_if_fail (bytes != NULL, NULL);
+
+ data = g_bytes_get_data (bytes, &size);
+ return egg_hex_encode (data, size);
+}
+
+gchar*
+egg_hex_encode_bytes_full (GBytes *bytes,
+ gboolean upper_case,
+ const gchar *delim,
+ guint group)
+{
+ gsize size;
+ gconstpointer data;
+
+ g_return_val_if_fail (bytes != NULL, NULL);
+
+ data = g_bytes_get_data (bytes, &size);
+ return egg_hex_encode_full (data, size, upper_case, delim, group);
+}
diff --git a/egg/egg-hex.h b/egg/egg-hex.h
index d5baea64..b1a8c1a4 100644
--- a/egg/egg-hex.h
+++ b/egg/egg-hex.h
@@ -41,4 +41,11 @@ gchar* egg_hex_encode_full (gconstpointer data
const gchar *delim,
guint group);
+gchar* egg_hex_encode_bytes (GBytes *bytes);
+
+gchar* egg_hex_encode_bytes_full (GBytes *bytes,
+ gboolean upper_case,
+ const gchar *delim,
+ guint group);
+
#endif /* EGG_HEX_H_ */
diff --git a/gcr-gtk3/gcr-certificate-widget.c b/gcr-gtk3/gcr-certificate-widget.c
index cf995d58..0ea05f8f 100644
--- a/gcr-gtk3/gcr-certificate-widget.c
+++ b/gcr-gtk3/gcr-certificate-widget.c
@@ -6,21 +6,9 @@
#include "config.h"
-#include <glib/gi18n-lib.h>
-
-#include <gcr-gtk3/gcr-certificate-widget.h>
-#include "gcr/gcr-certificate-extensions.h"
-#include "gcr/gcr-fingerprint.h"
-#include "gcr/gcr-oids.h"
-
+#include "gcr-certificate-widget.h"
#include "gcr-section.h"
-#include "egg/egg-asn1x.h"
-#include "egg/egg-asn1-defs.h"
-#include "egg/egg-dn.h"
-#include "egg/egg-oid.h"
-#include "egg/egg-hex.h"
-
struct _GcrCertificateWidget
{
GtkBox parent_instance;
@@ -28,6 +16,7 @@ struct _GcrCertificateWidget
GcrCertificate *certificate;
GtkWidget *reveal_button;
GtkWidget *revealer;
+ GtkWidget *primary_info;
GtkWidget *secondary_info;
GtkSizeGroup *size_group;
};
@@ -124,374 +113,19 @@ gcr_certificate_widget_init (GcrCertificateWidget *self)
gtk_orientable_set_orientation (GTK_ORIENTABLE (self), GTK_ORIENTATION_VERTICAL);
self->reveal_button = gtk_button_new_with_label ("…");
gtk_widget_set_halign (self->reveal_button, GTK_ALIGN_CENTER);
- gtk_box_pack_end (GTK_BOX (self), self->reveal_button, FALSE, TRUE, 0);
+ gtk_box_pack_end (GTK_BOX (self), self->reveal_button, FALSE, TRUE, 0);
+ self->primary_info = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
self->secondary_info = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
+ gtk_box_pack_start (GTK_BOX (self), self->primary_info, FALSE, TRUE, 0);
self->revealer = g_object_new (GTK_TYPE_REVEALER,
- "child", self->secondary_info,
- "transition-type", GTK_REVEALER_TRANSITION_TYPE_SLIDE_DOWN,
- NULL);
- gtk_box_pack_end (GTK_BOX (self), self->revealer, FALSE, TRUE, 0);
+ "child", self->secondary_info,
+ "transition-type", GTK_REVEALER_TRANSITION_TYPE_SLIDE_DOWN,
+ NULL);
+ gtk_box_pack_end (GTK_BOX (self), self->revealer, FALSE, TRUE, 0);
g_signal_connect (self->reveal_button, "clicked", G_CALLBACK (on_reveal_button_clicked), self);
self->size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
}
-static GtkWidget*
-_gcr_certificate_widget_add_section (GcrCertificateWidget *self,
- const gchar *title,
- gboolean important)
-{
- GtkWidget *widget;
-
- g_assert (GCR_IS_CERTIFICATE_WIDGET (self));
-
- widget = gcr_section_new (title);
-
- gtk_size_group_add_widget (self->size_group, widget);
- if (important)
- gtk_box_pack_start (GTK_BOX (self), widget, FALSE, TRUE, 0);
- else
- gtk_container_add (GTK_CONTAINER (self->secondary_info), widget);
-
- return widget;
-}
-
-static GtkWidget*
-create_value_label (const gchar *label)
-{
- return g_object_new (GTK_TYPE_LABEL,
- "label", label,
- "xalign", 1.0,
- "halign", GTK_ALIGN_END,
- "hexpand", TRUE,
- "selectable", TRUE,
- "wrap", TRUE,
- NULL);
-}
-
-static gchar*
-calculate_label (GcrCertificateWidget *self)
-{
- gchar *label;
-
- label = gcr_certificate_get_subject_cn (self->certificate);
- if (label != NULL)
- return label;
-
- return g_strdup (_("Certificate"));
-}
-
-static void
-on_parsed_dn_part (guint index,
- GQuark oid,
- GNode *value,
- gpointer user_data)
-{
- GtkWidget *section = user_data;
- const gchar *attr;
- const gchar *desc;
- gchar *field = NULL;
- gchar *display;
-
- attr = egg_oid_get_name (oid);
- desc = egg_oid_get_description (oid);
-
- /* Combine them into something sane */
- if (attr && desc) {
- if (strcmp (attr, desc) == 0)
- field = g_strdup (attr);
- else
- field = g_strdup_printf ("%s (%s)", attr, desc);
- } else if (!attr && !desc) {
- field = g_strdup ("");
- } else if (attr) {
- field = g_strdup (attr);
- } else if (desc) {
- field = g_strdup (desc);
- } else {
- g_assert_not_reached ();
- }
-
- display = egg_dn_print_value (oid, value);
- if (display == NULL)
- display = g_strdup ("");
-
- gcr_section_add_child (GCR_SECTION (section), field, create_value_label (display));
-
- g_free (field);
- g_free (display);
-}
-
-static inline gchar *
-hex_encode_bytes (GBytes *bytes)
-{
- gsize size;
- gconstpointer data = g_bytes_get_data (bytes, &size);
- return egg_hex_encode_full (data, size, TRUE, " ", 1);
-}
-
-static void
-append_subject_public_key (GcrCertificateWidget *self,
- GcrSection *section,
- GNode *subject_public_key)
-{
- guint key_nbits;
- const gchar *text;
- gchar *display;
- GBytes *value;
- guchar *raw;
- gsize n_raw;
- GQuark oid;
- guint bits;
-
- key_nbits = gcr_certificate_get_key_size (self->certificate);
-
- oid = egg_asn1x_get_oid_as_quark (egg_asn1x_node (subject_public_key,
- "algorithm", "algorithm", NULL));
- text = egg_oid_get_description (oid);
- gcr_section_add_child (section, _("Key Algorithm"), create_value_label (text));
-
- value = egg_asn1x_get_element_raw (egg_asn1x_node (subject_public_key,
- "algorithm", "parameters", NULL));
- if (value) {
- display = hex_encode_bytes (value);
- gcr_section_add_child (section, _("Key Parameters"), create_value_label (display));
- g_clear_pointer (&display, g_free);
- g_bytes_unref (value);
- }
-
- if (key_nbits > 0) {
- display = g_strdup_printf ("%u", key_nbits);
- gcr_section_add_child (section, _("Key Size"), create_value_label (display));
- g_clear_pointer (&display, g_free);
- }
-
- value = egg_asn1x_get_element_raw (subject_public_key);
- raw = gcr_fingerprint_from_subject_public_key_info (g_bytes_get_data (value, NULL),
- g_bytes_get_size (value),
- G_CHECKSUM_SHA1, &n_raw);
- g_bytes_unref (value);
- display = egg_hex_encode_full (raw, n_raw, TRUE, " ", 1);
- g_free (raw);
- gcr_section_add_child (section, _("Key SHA1 Fingerprint"), create_value_label (text));
- g_clear_pointer (&display, g_free);
-
- value = egg_asn1x_get_bits_as_raw (egg_asn1x_node (subject_public_key, "subjectPublicKey", NULL),
&bits);
- display = egg_hex_encode_full (g_bytes_get_data (value, NULL), bits / 8, TRUE, " ", 1);
- gcr_section_add_child (section, _("Public Key"), create_value_label (text));
- g_clear_pointer (&display, g_free);
- g_bytes_unref (value);
-}
-
-static GcrSection *
-append_extension_basic_constraints (GcrCertificateWidget *self,
- GBytes *data)
-{
- GcrSection *section;
- gboolean is_ca = FALSE;
- gint path_len = -1;
- gchar *number;
-
- if (!_gcr_certificate_extension_basic_constraints (data, &is_ca, &path_len))
- return NULL;
-
- section = GCR_SECTION (_gcr_certificate_widget_add_section (self, _("Basic Constraints"), FALSE));
- gcr_section_add_child (section, _("Certificate Authority"), create_value_label (is_ca ? _("Yes") :
_("No")));
-
- number = g_strdup_printf ("%d", path_len);
- gcr_section_add_child (section, _("Max Path Length"), create_value_label (path_len < 0 ?
_("Unlimited") : number));
- g_free (number);
-
- return section;
-}
-
-static GcrSection *
-append_extension_extended_key_usage (GcrCertificateWidget *self,
- GBytes *data)
-{
- GcrSection *section;
- GQuark *oids;
- GString *text;
- guint i;
-
- oids = _gcr_certificate_extension_extended_key_usage (data);
- if (oids == NULL)
- return NULL;
-
- text = g_string_new ("");
- for (i = 0; oids[i] != 0; i++) {
- if (i > 0)
- g_string_append_unichar (text, '\n');
- g_string_append (text, egg_oid_get_description (oids[i]));
- }
-
- g_free (oids);
-
- section = GCR_SECTION (_gcr_certificate_widget_add_section (self, _("Extended Key Usage"), FALSE));
- gcr_section_add_child (section, _("Allowed Purposes"), create_value_label (text->str));
-
- g_string_free (text, TRUE);
-
- return section;
-}
-
-static GcrSection *
-append_extension_subject_key_identifier (GcrCertificateWidget *self,
- GBytes *data)
-{
- GcrSection *section;
- gpointer keyid;
- gsize n_keyid;
-
- keyid = _gcr_certificate_extension_subject_key_identifier (data, &n_keyid);
- if (keyid == NULL)
- return NULL;
-
- section = GCR_SECTION (_gcr_certificate_widget_add_section (self, _("Subject Key Identifier"),
FALSE));
- gchar *display = egg_hex_encode_full (keyid, n_keyid, TRUE, " ", 1);
- g_free (keyid);
- gcr_section_add_child (section, _("Key Identifier"), create_value_label (display));
- g_free (display);
-
- return section;
-}
-
-static const struct {
- guint usage;
- const gchar *description;
-} usage_descriptions[] = {
- { GCR_KEY_USAGE_DIGITAL_SIGNATURE, N_("Digital signature") },
- { GCR_KEY_USAGE_NON_REPUDIATION, N_("Non repudiation") },
- { GCR_KEY_USAGE_KEY_ENCIPHERMENT, N_("Key encipherment") },
- { GCR_KEY_USAGE_DATA_ENCIPHERMENT, N_("Data encipherment") },
- { GCR_KEY_USAGE_KEY_AGREEMENT, N_("Key agreement") },
- { GCR_KEY_USAGE_KEY_CERT_SIGN, N_("Certificate signature") },
- { GCR_KEY_USAGE_CRL_SIGN, N_("Revocation list signature") },
- { GCR_KEY_USAGE_ENCIPHER_ONLY, N_("Encipher only") },
- { GCR_KEY_USAGE_DECIPHER_ONLY, N_("Decipher only") }
-};
-
-static GcrSection *
-append_extension_key_usage (GcrCertificateWidget *self,
- GBytes *data)
-{
- GcrSection *section;
- gulong key_usage;
- GString *text;
- guint i;
-
- if (!_gcr_certificate_extension_key_usage (data, &key_usage))
- return NULL;
-
- text = g_string_new ("");
-
- for (i = 0; i < G_N_ELEMENTS (usage_descriptions); i++) {
- if (key_usage & usage_descriptions[i].usage) {
- if (text->len > 0)
- g_string_append_unichar (text, '\n');
- g_string_append (text, _(usage_descriptions[i].description));
- }
- }
-
- section = GCR_SECTION (_gcr_certificate_widget_add_section (self, _("Key Usage"), FALSE));
- gcr_section_add_child (section, _("Usages"), create_value_label (text->str));
-
- g_string_free (text, TRUE);
-
- return section;
-}
-
-static GcrSection *
-append_extension_subject_alt_name (GcrCertificateWidget *self,
- GBytes *data)
-{
- GcrSection *section;
- GArray *general_names;
- GcrGeneralName *general;
- guint i;
-
- general_names = _gcr_certificate_extension_subject_alt_name (data);
- if (general_names == NULL)
- return FALSE;
-
- section = GCR_SECTION (_gcr_certificate_widget_add_section (self, _("Subject Alternative Names"),
FALSE));
-
- for (i = 0; i < general_names->len; i++) {
- general = &g_array_index (general_names, GcrGeneralName, i);
- if (general->display == NULL) {
- gchar *display = hex_encode_bytes (general->raw);
- gcr_section_add_child (section, general->description, create_value_label (display));
- g_free (display);
- } else
- gcr_section_add_child (section, general->description, create_value_label
(general->display));
- }
-
- _gcr_general_names_free (general_names);
-
- return section;
-}
-
-static GcrSection *
-append_extension_hex (GcrCertificateWidget *self,
- GQuark oid,
- GBytes *value)
-{
- GcrSection *section;
- const gchar *text;
- gchar *display;
-
- section = GCR_SECTION (_gcr_certificate_widget_add_section (self, _("Extension"), FALSE));
-
- /* Extension type */
- text = egg_oid_get_description (oid);
- gcr_section_add_child (section, _("Identifier"), create_value_label (text));
- display = hex_encode_bytes (value);
- gcr_section_add_child (section, _("Value"), create_value_label (display));
- g_free (display);
-
- return section;
-}
-
-static void
-append_extension (GcrCertificateWidget *self,
- GNode *node)
-{
- GQuark oid;
- GBytes *value;
- gboolean critical;
- GcrSection *section = NULL;
-
- /* Dig out the OID */
- oid = egg_asn1x_get_oid_as_quark (egg_asn1x_node (node, "extnID", NULL));
- g_return_if_fail (oid);
-
- /* Extension value */
- value = egg_asn1x_get_string_as_bytes (egg_asn1x_node (node, "extnValue", NULL));
-
- /* The custom parsers */
- if (oid == GCR_OID_BASIC_CONSTRAINTS)
- section = append_extension_basic_constraints (self, value);
- else if (oid == GCR_OID_EXTENDED_KEY_USAGE)
- section = append_extension_extended_key_usage (self, value);
- else if (oid == GCR_OID_SUBJECT_KEY_IDENTIFIER)
- section = append_extension_subject_key_identifier (self, value);
- else if (oid == GCR_OID_KEY_USAGE)
- section = append_extension_key_usage (self, value);
- else if (oid == GCR_OID_SUBJECT_ALT_NAME)
- section = append_extension_subject_alt_name (self, value);
-
- /* Otherwise the default raw display */
- if (!section) {
- section = append_extension_hex (self, oid, value);
- }
-
- /* Critical */
- if (section && egg_asn1x_get_boolean (egg_asn1x_node (node, "critical", NULL), &critical)) {
- gcr_section_add_child (section, _("Critical"), create_value_label (critical ? _("Yes") :
_("No")));
- }
-
- g_bytes_unref (value);
-}
-
/**
* gcr_certificate_widget_new:
* @certificate: (nullable): certificate to display, or %NULL
@@ -532,144 +166,35 @@ gcr_certificate_widget_get_certificate (GcrCertificateWidget *self)
void
gcr_certificate_widget_set_certificate (GcrCertificateWidget *self, GcrCertificate *certificate)
{
- GtkWidget *section, *label;
- PangoAttrList *attributes;
- gchar *display;
- GBytes *bytes, *number;
- GNode *asn, *subject_public_key;
- GQuark oid;
- gconstpointer data;
- gsize n_data;
- GDateTime *datetime;
- gulong version;
- guint bits, index;
+ GList* elements, *l, *children;
g_return_if_fail (GCR_IS_CERTIFICATE_WIDGET (self));
- g_set_object (&self->certificate, certificate);
-
- data = gcr_certificate_get_der_data (self->certificate, &n_data);
- if (!data) {
- g_set_object (&self->certificate, NULL);
- }
-
- display = calculate_label (self);
- section = _gcr_certificate_widget_add_section (self, display, TRUE);
- g_clear_pointer (&display, g_free);
-
- bytes = g_bytes_new_static (data, n_data);
- asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "Certificate", bytes);
- g_bytes_unref (bytes);
-
- display = egg_dn_read_part (egg_asn1x_node (asn, "tbsCertificate", "subject", "rdnSequence", NULL),
"CN");
- gcr_section_add_child (GCR_SECTION (section), _("Identity"), create_value_label (display));
- g_clear_pointer (&display, g_free);
-
- display = egg_dn_read_part (egg_asn1x_node (asn, "tbsCertificate", "issuer", "rdnSequence", NULL),
"CN");
- gcr_section_add_child (GCR_SECTION (section), _("Verified by"), create_value_label (display));
- g_clear_pointer (&display, g_free);
-
- datetime = egg_asn1x_get_time_as_date_time (egg_asn1x_node (asn, "tbsCertificate", "validity",
"notAfter", NULL));
- if (datetime) {
- display = g_date_time_format (datetime, "%x");
- g_return_if_fail (display != NULL);
- gcr_section_add_child (GCR_SECTION (section), _("Expires"), create_value_label (display));
- g_clear_pointer (&display, g_free);
- g_clear_pointer (&datetime, g_date_time_unref);
- }
-
- /* The subject */
- section = _gcr_certificate_widget_add_section (self, _("Subject Name"), FALSE);
- egg_dn_parse (egg_asn1x_node (asn, "tbsCertificate", "subject", "rdnSequence", NULL),
on_parsed_dn_part, section);
-
- /* The Issuer */
- section = _gcr_certificate_widget_add_section (self, _("Issuer Name"), FALSE);
- egg_dn_parse (egg_asn1x_node (asn, "tbsCertificate", "issuer", "rdnSequence", NULL),
on_parsed_dn_part, section);
-
- /* The Issued Parameters */
- section = _gcr_certificate_widget_add_section (self, _("Issued Certificate"), FALSE);
-
- if (!egg_asn1x_get_integer_as_ulong (egg_asn1x_node (asn, "tbsCertificate", "version", NULL),
&version)) {
- g_critical ("Unable to parse certificate version");
- } else {
- display = g_strdup_printf ("%lu", version + 1);
- gcr_section_add_child (GCR_SECTION (section), _("Version"), create_value_label (display));
- g_clear_pointer (&display, g_free);
- }
-
- number = egg_asn1x_get_integer_as_raw (egg_asn1x_node (asn, "tbsCertificate", "serialNumber", NULL));
- if (!number) {
- g_critical ("Unable to parse certificate serial number");
- } else {
- display = hex_encode_bytes (number);
- gcr_section_add_child (GCR_SECTION (section), _("Serial Number"), create_value_label
(display));
- g_clear_pointer (&display, g_free);
- g_bytes_unref (number);
- }
-
- datetime = egg_asn1x_get_time_as_date_time (egg_asn1x_node (asn, "tbsCertificate", "validity",
"notBefore", NULL));
- if (datetime) {
- display = g_date_time_format (datetime, "%x");
- g_return_if_fail (display != NULL);
- gcr_section_add_child (GCR_SECTION (section), _("Not Valid Before"), create_value_label
(display));
- g_clear_pointer (&display, g_free);
- g_clear_pointer (&datetime, g_date_time_unref);
- }
- datetime = egg_asn1x_get_time_as_date_time (egg_asn1x_node (asn, "tbsCertificate", "validity",
"notAfter", NULL));
- if (datetime) {
- display = g_date_time_format (datetime, "%x");
- g_return_if_fail (display != NULL);
- gcr_section_add_child (GCR_SECTION (section), _("Not Valid After"), create_value_label
(display));
- g_clear_pointer (&display, g_free);
- g_clear_pointer (&datetime, g_date_time_unref);
+ children = gtk_container_get_children (GTK_CONTAINER (self->secondary_info));
+ for (l = children; l != NULL; l = l->next) {
+ gtk_widget_destroy (GTK_WIDGET (l->data));
}
- /* Fingerprints */
- section = _gcr_certificate_widget_add_section (self, _("Certificate Fingerprints"), FALSE);
- display = g_compute_checksum_for_bytes (G_CHECKSUM_SHA1, bytes);
- gcr_section_add_child (GCR_SECTION (section), "SHA1", create_value_label (display));
- g_clear_pointer (&display, g_free);
- display = g_compute_checksum_for_bytes (G_CHECKSUM_MD5, bytes);
- gcr_section_add_child (GCR_SECTION (section), "MD5", create_value_label (display));
- g_clear_pointer (&display, g_free);
+ g_list_free (children);
- /* Public Key Info */
- section = _gcr_certificate_widget_add_section (self, _("Public Key Info"), FALSE);
- subject_public_key = egg_asn1x_node (asn, "tbsCertificate", "subjectPublicKeyInfo", NULL);
- append_subject_public_key (self, GCR_SECTION (section), subject_public_key);
-
- /* Extensions */
- for (index = 1; TRUE; ++index) {
- GNode *extension = egg_asn1x_node (asn, "tbsCertificate", "extensions", index, NULL);
- if (extension == NULL)
- break;
- append_extension (self, extension);
+ g_set_object (&self->certificate, certificate);
+ if (!certificate) {
+ return;
}
- /* Signature */
- section = _gcr_certificate_widget_add_section (self, _("Signature"), FALSE);
+ elements = gcr_certificate_get_interface_elements (certificate);
+ for (l = elements; l != NULL; l = l->next) {
+ GcrCertificateSection *section = l->data;
+ GtkWidget *widget;
- oid = egg_asn1x_get_oid_as_quark (egg_asn1x_node (asn, "signatureAlgorithm", "algorithm", NULL));
- gcr_section_add_child (GCR_SECTION (section), _("Signature Algorithm"), create_value_label
(egg_oid_get_description (oid)));
+ widget = gcr_section_new (section);
- bytes = egg_asn1x_get_element_raw (egg_asn1x_node (asn, "signatureAlgorithm", "parameters", NULL));
- if (bytes) {
- display = hex_encode_bytes (bytes);
- gcr_section_add_child (GCR_SECTION (section), _("Signature Parameters"), create_value_label
(display));
- g_clear_pointer (&display, g_free);
- g_bytes_unref (bytes);
+ gtk_size_group_add_widget (self->size_group, widget);
+ if (gcr_certificate_section_get_flags (section) & GCR_CERTIFICATE_SECTION_IMPORTANT)
+ gtk_box_pack_start (GTK_BOX (self->primary_info), widget, FALSE, FALSE, 0);
+ else
+ gtk_box_pack_start (GTK_BOX (self->secondary_info), widget, FALSE, FALSE, 0);
}
- bytes = egg_asn1x_get_bits_as_raw (egg_asn1x_node (asn, "signature", NULL), &bits);
- display = egg_hex_encode_full (g_bytes_get_data (bytes, NULL), bits / 8, TRUE, " ", 1);
- g_bytes_unref (bytes);
- label = create_value_label (display);
- attributes = pango_attr_list_new ();
- pango_attr_list_insert (attributes, pango_attr_family_new ("Monospace"));
- gtk_label_set_attributes (GTK_LABEL (label), attributes);
- pango_attr_list_unref (attributes);
- gcr_section_add_child (GCR_SECTION (section), _("Signature"), label);
- g_clear_pointer (&display, g_free);
-
- egg_asn1x_destroy (asn);
+ g_list_free_full (elements, (GDestroyNotify) g_object_unref);
}
diff --git a/gcr-gtk3/gcr-section.c b/gcr-gtk3/gcr-section.c
index bc6373ef..6b2ce0fb 100644
--- a/gcr-gtk3/gcr-section.c
+++ b/gcr-gtk3/gcr-section.c
@@ -10,9 +10,8 @@ struct _GcrSection
{
GtkGrid parent_instance;
- GtkWidget *frame;
+ GcrCertificateSection *section;
GtkWidget *label;
- GtkWidget *image;
GtkWidget *listbox;
GtkSizeGroup *size_group;
};
@@ -20,21 +19,118 @@ struct _GcrSection
G_DEFINE_TYPE (GcrSection, gcr_section, GTK_TYPE_GRID)
enum {
- PROP_TITLE = 1,
+ PROP_SECTION = 1,
N_PROPERTIES
};
static GParamSpec *obj_properties[N_PROPERTIES] = { NULL, };
+static char*
+bytes_to_display (GBytes *bytes)
+{
+ const char *hexc = "0123456789ABCDEF";
+ GString *result;
+ const char *input;
+ gsize read_bytes;
+ gsize remaining_bytes;
+ guchar j;
+
+ g_return_val_if_fail (bytes != NULL, NULL);
+
+ input = g_bytes_get_data (bytes, &remaining_bytes);
+ result = g_string_sized_new (g_bytes_get_size (bytes) * 2 + 1);
+
+ for (read_bytes = 0; read_bytes < remaining_bytes; read_bytes++) {
+ if (read_bytes && (read_bytes % 1) == 0)
+ g_string_append_c (result, ' ');
+
+ j = *(input) >> 4 & 0xf;
+ g_string_append_c (result, hexc[j]);
+
+ j = *(input++) & 0xf;
+ g_string_append_c (result, hexc[j]);
+ }
+
+ return g_string_free (result, FALSE);
+}
+
+GtkWidget *
+gcr_section_create_row (GObject *item,
+ gpointer user_data)
+{
+ GcrCertificateField *field = (GcrCertificateField *) item;
+ GtkSizeGroup *size_group = user_data;
+ GtkWidget *row, *box, *label, *value;
+ GValue val = G_VALUE_INIT;
+ GType value_type;
+
+ g_return_val_if_fail (GCR_IS_CERTIFICATE_FIELD (field), NULL);
+
+ row = gtk_list_box_row_new ();
+ gtk_list_box_row_set_selectable (GTK_LIST_BOX_ROW (row), FALSE);
+ box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12);
+ gtk_container_add (GTK_CONTAINER (row), box);
+ label = gtk_label_new (gcr_certificate_field_get_label (field));
+ gtk_label_set_xalign (GTK_LABEL (label), 0.0);
+ g_object_set (label,
+ "margin-start", 12,
+ "margin-end", 12,
+ "margin-top", 8,
+ "margin-bottom", 8,
+ "xalign", 0.0,
+ "halign", GTK_ALIGN_START,
+ NULL);
+ gtk_style_context_add_class (gtk_widget_get_style_context (label), "caption");
+ value = g_object_new (GTK_TYPE_LABEL,
+ "xalign", 1.0,
+ "halign", GTK_ALIGN_END,
+ "hexpand", TRUE,
+ "selectable", TRUE,
+ "wrap", TRUE,
+ NULL);
+
+ value_type = gcr_certificate_field_get_value_type (field);
+ g_value_init (&val, value_type);
+ gcr_certificate_field_get_value (field, &val);
+ if (g_type_is_a (value_type, G_TYPE_STRING)) {
+ g_object_set (G_OBJECT (value), "label", g_value_get_string (&val), NULL);
+ } else if (g_type_is_a (value_type, G_TYPE_STRV)) {
+ char *lbl = g_strjoinv ("\n", (GStrv) g_value_get_boxed (&val));
+ g_object_set (G_OBJECT (value), "label", lbl, NULL);
+ g_free (lbl);
+ } else if (g_type_is_a (value_type, G_TYPE_BYTES)) {
+ PangoAttrList *attributes;
+ GBytes *bytes = g_value_get_boxed (&val);
+ char *lbl = bytes_to_display (bytes);
+ g_object_set (G_OBJECT (value), "label", lbl, NULL);
+ g_free (lbl);
+ attributes = pango_attr_list_new ();
+ pango_attr_list_insert (attributes, pango_attr_family_new ("Monospace"));
+ gtk_label_set_attributes (GTK_LABEL (value), attributes);
+ pango_attr_list_unref (attributes);
+ }
+ g_value_unset (&val);
+
+ g_object_set (value,
+ "margin-start", 12,
+ "margin-end", 12,
+ "margin-top", 8,
+ "margin-bottom", 8,
+ "halign", GTK_ALIGN_END,
+ NULL);
+ gtk_size_group_add_widget (size_group, label);
+ gtk_container_add (GTK_CONTAINER (box), label);
+ gtk_container_add (GTK_CONTAINER (box), value);
+ return row;
+}
+
static void
gcr_section_dispose (GObject *object)
{
GcrSection *self = (GcrSection *)object;
g_clear_object (&self->size_group);
- /* g_clear_pointer (&self->label, gtk_widget_unparent); */
- /* g_clear_pointer (&self->image, gtk_widget_unparent); */
- /* g_clear_pointer (&self->frame, gtk_widget_unparent); */
+ g_clear_object (&self->section);
G_OBJECT_CLASS (gcr_section_parent_class)->dispose (object);
}
@@ -47,10 +143,9 @@ gcr_section_get_property (GObject *object,
{
GcrSection *self = GCR_SECTION (object);
- switch (prop_id)
- {
- case PROP_TITLE:
- g_value_set_string (value, gtk_label_get_label (GTK_LABEL (self->label)));
+ switch (prop_id) {
+ case PROP_SECTION:
+ g_value_set_object (value, self->section);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -65,10 +160,15 @@ gcr_section_set_property (GObject *object,
{
GcrSection *self = GCR_SECTION (object);
- switch (prop_id)
- {
- case PROP_TITLE:
- gtk_label_set_label (GTK_LABEL (self->label), g_value_get_string (value));
+ switch (prop_id) {
+ case PROP_SECTION:
+ g_assert (!self->section);
+ self->section = g_value_dup_object (value);
+ gtk_label_set_label (GTK_LABEL (self->label), gcr_certificate_section_get_label
(self->section));
+ gtk_list_box_bind_model (GTK_LIST_BOX (self->listbox),
+ gcr_certificate_section_get_fields (self->section),
+ (GtkListBoxCreateWidgetFunc) gcr_section_create_row,
+ self->size_group, NULL);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -83,11 +183,11 @@ gcr_section_class_init (GcrSectionClass *klass)
object_class->dispose = gcr_section_dispose;
object_class->get_property = gcr_section_get_property;
object_class->set_property = gcr_section_set_property;
- obj_properties[PROP_TITLE] =
- g_param_spec_string ("title",
- "Title",
- "The title of the section",
- NULL,
+ obj_properties[PROP_SECTION] =
+ g_param_spec_object ("section",
+ "Section",
+ "The section object",
+ GCR_TYPE_CERTIFICATE_SECTION,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS);
g_object_class_install_properties (object_class,
@@ -101,72 +201,33 @@ gcr_section_init (GcrSection *self)
gtk_orientable_set_orientation (GTK_ORIENTABLE (self), GTK_ORIENTATION_VERTICAL);
self->label = gtk_label_new (NULL);
g_object_set (G_OBJECT (self->label),
- "margin-start", 12,
- "margin-end", 12,
- "margin-top", 8,
- "margin-bottom", 8,
+ "margin-start", 12,
+ "margin-end", 12,
+ "margin-top", 8,
+ "margin-bottom", 8,
"xalign", 0.0,
- "halign", GTK_ALIGN_START,
- "hexpand", TRUE,
+ "halign", GTK_ALIGN_START,
+ "hexpand", TRUE,
NULL);
gtk_style_context_add_class (gtk_widget_get_style_context (self->label), "heading");
gtk_style_context_add_class (gtk_widget_get_style_context (self->label), "h4");
self->listbox = gtk_list_box_new ();
gtk_list_box_set_selection_mode (GTK_LIST_BOX (self->listbox), GTK_SELECTION_NONE);
- self->frame = gtk_frame_new (NULL);
- g_object_set (G_OBJECT (self->frame),
- "child", self->listbox,
- "hexpand", TRUE,
- NULL);
self->size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
- gtk_container_add (GTK_CONTAINER (self), self->label);
- gtk_container_add (GTK_CONTAINER (self), self->frame);
+ gtk_style_context_add_class (gtk_widget_get_style_context (self->listbox), "frame");
+ gtk_container_add (GTK_CONTAINER (self), self->label);
+ gtk_container_add (GTK_CONTAINER (self), self->listbox);
g_object_set (self,
- "margin-start", 12,
- "margin-end", 12,
- "margin-top", 8,
- "margin-bottom", 8,
+ "margin-start", 12,
+ "margin-end", 12,
+ "margin-top", 8,
+ "margin-bottom", 8,
NULL);
}
GtkWidget *
-gcr_section_new (const gchar *title)
+gcr_section_new (GcrCertificateSection *section)
{
- return g_object_new (GCR_TYPE_SECTION, "title", title, NULL);
-}
-
-void
-gcr_section_add_child (GcrSection *self,
- const gchar *description,
- GtkWidget *child)
-{
- GtkWidget *row, *box, *label;
- g_return_if_fail (GCR_IS_SECTION (self));
-
- row = gtk_list_box_row_new ();
- box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12);
- gtk_container_add (GTK_CONTAINER (row), box);
- label = gtk_label_new (description);
- gtk_label_set_xalign (GTK_LABEL (label), 0.0);
- g_object_set (label,
- "margin-start", 12,
- "margin-end", 12,
- "margin-top", 8,
- "margin-bottom", 8,
- "xalign", 0.0,
- "halign", GTK_ALIGN_START,
- NULL);
- gtk_style_context_add_class (gtk_widget_get_style_context (label), "caption");
- g_object_set (child,
- "margin-start", 12,
- "margin-end", 12,
- "margin-top", 8,
- "margin-bottom", 8,
- "halign", GTK_ALIGN_END,
- NULL);
- gtk_size_group_add_widget (self->size_group, label);
- gtk_container_add (GTK_CONTAINER (box), label);
- gtk_container_add (GTK_CONTAINER (box), child);
- gtk_container_add (GTK_CONTAINER (self->listbox), row);
+ return g_object_new (GCR_TYPE_SECTION, "section", section, NULL);
}
diff --git a/gcr-gtk3/gcr-section.h b/gcr-gtk3/gcr-section.h
index 359716d5..55443ccc 100644
--- a/gcr-gtk3/gcr-section.h
+++ b/gcr-gtk3/gcr-section.h
@@ -10,17 +10,14 @@
#include <glib.h>
#include <glib-object.h>
#include <gtk/gtk.h>
+#include <gcr/gcr.h>
G_BEGIN_DECLS
#define GCR_TYPE_SECTION gcr_section_get_type()
G_DECLARE_FINAL_TYPE (GcrSection, gcr_section, GCR, SECTION, GtkGrid)
-GtkWidget *gcr_section_new (const gchar *title);
-
-void gcr_section_add_child (GcrSection *self,
- const gchar *description,
- GtkWidget *child);
+GtkWidget *gcr_section_new (GcrCertificateSection *section);
G_END_DECLS
diff --git a/gcr-gtk4/gcr-certificate-widget.c b/gcr-gtk4/gcr-certificate-widget.c
index 0acdc7b2..ce9e9490 100644
--- a/gcr-gtk4/gcr-certificate-widget.c
+++ b/gcr-gtk4/gcr-certificate-widget.c
@@ -6,26 +6,15 @@
#include "config.h"
-#include <glib/gi18n-lib.h>
-
-#include <gcr-gtk4/gcr-certificate-widget.h>
-#include "gcr/gcr-certificate-extensions.h"
-#include "gcr/gcr-fingerprint.h"
-#include "gcr/gcr-oids.h"
-
+#include "gcr-certificate-widget.h"
#include "gcr-section.h"
-#include "egg/egg-asn1x.h"
-#include "egg/egg-asn1-defs.h"
-#include "egg/egg-dn.h"
-#include "egg/egg-oid.h"
-#include "egg/egg-hex.h"
-
struct _GcrCertificateWidget
{
GtkWidget parent_instance;
GcrCertificate *certificate;
+ GtkWidget *primary_info;
GtkWidget *reveal_button;
GtkWidget *revealer;
GtkWidget *secondary_info;
@@ -63,8 +52,7 @@ gcr_certificate_widget_get_property (GObject *object,
{
GcrCertificateWidget *self = GCR_CERTIFICATE_WIDGET (object);
- switch (prop_id)
- {
+ switch (prop_id) {
case PROP_CERTIFICATE:
g_value_set_object (value, gcr_certificate_widget_get_certificate (self));
break;
@@ -82,8 +70,7 @@ gcr_certificate_widget_set_property (GObject *object,
{
GcrCertificateWidget *self = GCR_CERTIFICATE_WIDGET (object);
- switch (prop_id)
- {
+ switch (prop_id) {
case PROP_CERTIFICATE:
gcr_certificate_widget_set_certificate (self, g_value_get_object (value));
break;
@@ -132,373 +119,18 @@ gcr_certificate_widget_init (GcrCertificateWidget *self)
self->reveal_button = gtk_button_new_with_label ("…");
gtk_widget_set_halign (self->reveal_button, GTK_ALIGN_CENTER);
gtk_widget_insert_before (self->reveal_button, GTK_WIDGET (self), NULL);
+ self->primary_info = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
self->secondary_info = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
self->revealer = g_object_new (GTK_TYPE_REVEALER,
- "child", self->secondary_info,
- "transition-type", GTK_REVEALER_TRANSITION_TYPE_SLIDE_DOWN,
- NULL);
+ "child", self->secondary_info,
+ "transition-type", GTK_REVEALER_TRANSITION_TYPE_SLIDE_DOWN,
+ NULL);
+ gtk_widget_insert_after (self->primary_info, GTK_WIDGET (self), NULL);
gtk_widget_insert_after (self->revealer, GTK_WIDGET (self), self->reveal_button);
g_signal_connect (self->reveal_button, "clicked", G_CALLBACK (on_reveal_button_clicked), self);
self->size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
}
-static GtkWidget*
-_gcr_certificate_widget_add_section (GcrCertificateWidget *self,
- const gchar *title,
- gboolean important)
-{
- GtkWidget *widget;
-
- g_assert (GCR_IS_CERTIFICATE_WIDGET (self));
-
- widget = gcr_section_new (title);
-
- gtk_size_group_add_widget (self->size_group, widget);
- if (important)
- gtk_widget_insert_before (widget, GTK_WIDGET (self), self->reveal_button);
- else
- gtk_box_append (GTK_BOX (self->secondary_info), widget);
-
- return widget;
-}
-
-static GtkWidget*
-create_value_label (const gchar *label)
-{
- return g_object_new (GTK_TYPE_LABEL,
- "label", label,
- "xalign", 1.0,
- "halign", GTK_ALIGN_END,
- "hexpand", TRUE,
- "selectable", TRUE,
- "wrap", TRUE,
- NULL);
-}
-
-static gchar*
-calculate_label (GcrCertificateWidget *self)
-{
- gchar *label;
-
- label = gcr_certificate_get_subject_cn (self->certificate);
- if (label != NULL)
- return label;
-
- return g_strdup (_("Certificate"));
-}
-
-static void
-on_parsed_dn_part (guint index,
- GQuark oid,
- GNode *value,
- gpointer user_data)
-{
- GtkWidget *section = user_data;
- const gchar *attr;
- const gchar *desc;
- gchar *field = NULL;
- gchar *display;
-
- attr = egg_oid_get_name (oid);
- desc = egg_oid_get_description (oid);
-
- /* Combine them into something sane */
- if (attr && desc) {
- if (strcmp (attr, desc) == 0)
- field = g_strdup (attr);
- else
- field = g_strdup_printf ("%s (%s)", attr, desc);
- } else if (!attr && !desc) {
- field = g_strdup ("");
- } else if (attr) {
- field = g_strdup (attr);
- } else if (desc) {
- field = g_strdup (desc);
- } else {
- g_assert_not_reached ();
- }
-
- display = egg_dn_print_value (oid, value);
- if (display == NULL)
- display = g_strdup ("");
-
- gcr_section_add_child (GCR_SECTION (section), field, create_value_label (display));
-
- g_free (field);
- g_free (display);
-}
-
-static inline gchar *
-hex_encode_bytes (GBytes *bytes)
-{
- gsize size;
- gconstpointer data = g_bytes_get_data (bytes, &size);
- return egg_hex_encode_full (data, size, TRUE, " ", 1);
-}
-
-static void
-append_subject_public_key (GcrCertificateWidget *self,
- GcrSection *section,
- GNode *subject_public_key)
-{
- guint key_nbits;
- const gchar *text;
- gchar *display;
- GBytes *value;
- guchar *raw;
- gsize n_raw;
- GQuark oid;
- guint bits;
-
- key_nbits = gcr_certificate_get_key_size (self->certificate);
-
- oid = egg_asn1x_get_oid_as_quark (egg_asn1x_node (subject_public_key,
- "algorithm", "algorithm", NULL));
- text = egg_oid_get_description (oid);
- gcr_section_add_child (section, _("Key Algorithm"), create_value_label (text));
-
- value = egg_asn1x_get_element_raw (egg_asn1x_node (subject_public_key,
- "algorithm", "parameters", NULL));
- if (value) {
- display = hex_encode_bytes (value);
- gcr_section_add_child (section, _("Key Parameters"), create_value_label (display));
- g_clear_pointer (&display, g_free);
- g_bytes_unref (value);
- }
-
- if (key_nbits > 0) {
- display = g_strdup_printf ("%u", key_nbits);
- gcr_section_add_child (section, _("Key Size"), create_value_label (display));
- g_clear_pointer (&display, g_free);
- }
-
- value = egg_asn1x_get_element_raw (subject_public_key);
- raw = gcr_fingerprint_from_subject_public_key_info (g_bytes_get_data (value, NULL),
- g_bytes_get_size (value),
- G_CHECKSUM_SHA1, &n_raw);
- g_bytes_unref (value);
- display = egg_hex_encode_full (raw, n_raw, TRUE, " ", 1);
- g_free (raw);
- gcr_section_add_child (section, _("Key SHA1 Fingerprint"), create_value_label (text));
- g_clear_pointer (&display, g_free);
-
- value = egg_asn1x_get_bits_as_raw (egg_asn1x_node (subject_public_key, "subjectPublicKey", NULL),
&bits);
- display = egg_hex_encode_full (g_bytes_get_data (value, NULL), bits / 8, TRUE, " ", 1);
- gcr_section_add_child (section, _("Public Key"), create_value_label (text));
- g_clear_pointer (&display, g_free);
- g_bytes_unref (value);
-}
-
-static GcrSection *
-append_extension_basic_constraints (GcrCertificateWidget *self,
- GBytes *data)
-{
- GcrSection *section;
- gboolean is_ca = FALSE;
- gint path_len = -1;
- gchar *number;
-
- if (!_gcr_certificate_extension_basic_constraints (data, &is_ca, &path_len))
- return NULL;
-
- section = GCR_SECTION (_gcr_certificate_widget_add_section (self, _("Basic Constraints"), FALSE));
- gcr_section_add_child (section, _("Certificate Authority"), create_value_label (is_ca ? _("Yes") :
_("No")));
-
- number = g_strdup_printf ("%d", path_len);
- gcr_section_add_child (section, _("Max Path Length"), create_value_label (path_len < 0 ?
_("Unlimited") : number));
- g_free (number);
-
- return section;
-}
-
-static GcrSection *
-append_extension_extended_key_usage (GcrCertificateWidget *self,
- GBytes *data)
-{
- GcrSection *section;
- GQuark *oids;
- GString *text;
- guint i;
-
- oids = _gcr_certificate_extension_extended_key_usage (data);
- if (oids == NULL)
- return NULL;
-
- text = g_string_new ("");
- for (i = 0; oids[i] != 0; i++) {
- if (i > 0)
- g_string_append_unichar (text, '\n');
- g_string_append (text, egg_oid_get_description (oids[i]));
- }
-
- g_free (oids);
-
- section = GCR_SECTION (_gcr_certificate_widget_add_section (self, _("Extended Key Usage"), FALSE));
- gcr_section_add_child (section, _("Allowed Purposes"), create_value_label (text->str));
-
- g_string_free (text, TRUE);
-
- return section;
-}
-
-static GcrSection *
-append_extension_subject_key_identifier (GcrCertificateWidget *self,
- GBytes *data)
-{
- GcrSection *section;
- gpointer keyid;
- gsize n_keyid;
-
- keyid = _gcr_certificate_extension_subject_key_identifier (data, &n_keyid);
- if (keyid == NULL)
- return NULL;
-
- section = GCR_SECTION (_gcr_certificate_widget_add_section (self, _("Subject Key Identifier"),
FALSE));
- gchar *display = egg_hex_encode_full (keyid, n_keyid, TRUE, " ", 1);
- g_free (keyid);
- gcr_section_add_child (section, _("Key Identifier"), create_value_label (display));
- g_free (display);
-
- return section;
-}
-
-static const struct {
- guint usage;
- const gchar *description;
-} usage_descriptions[] = {
- { GCR_KEY_USAGE_DIGITAL_SIGNATURE, N_("Digital signature") },
- { GCR_KEY_USAGE_NON_REPUDIATION, N_("Non repudiation") },
- { GCR_KEY_USAGE_KEY_ENCIPHERMENT, N_("Key encipherment") },
- { GCR_KEY_USAGE_DATA_ENCIPHERMENT, N_("Data encipherment") },
- { GCR_KEY_USAGE_KEY_AGREEMENT, N_("Key agreement") },
- { GCR_KEY_USAGE_KEY_CERT_SIGN, N_("Certificate signature") },
- { GCR_KEY_USAGE_CRL_SIGN, N_("Revocation list signature") },
- { GCR_KEY_USAGE_ENCIPHER_ONLY, N_("Encipher only") },
- { GCR_KEY_USAGE_DECIPHER_ONLY, N_("Decipher only") }
-};
-
-static GcrSection *
-append_extension_key_usage (GcrCertificateWidget *self,
- GBytes *data)
-{
- GcrSection *section;
- gulong key_usage;
- GString *text;
- guint i;
-
- if (!_gcr_certificate_extension_key_usage (data, &key_usage))
- return NULL;
-
- text = g_string_new ("");
-
- for (i = 0; i < G_N_ELEMENTS (usage_descriptions); i++) {
- if (key_usage & usage_descriptions[i].usage) {
- if (text->len > 0)
- g_string_append_unichar (text, '\n');
- g_string_append (text, _(usage_descriptions[i].description));
- }
- }
-
- section = GCR_SECTION (_gcr_certificate_widget_add_section (self, _("Key Usage"), FALSE));
- gcr_section_add_child (section, _("Usages"), create_value_label (text->str));
-
- g_string_free (text, TRUE);
-
- return section;
-}
-
-static GcrSection *
-append_extension_subject_alt_name (GcrCertificateWidget *self,
- GBytes *data)
-{
- GcrSection *section;
- GArray *general_names;
- GcrGeneralName *general;
- guint i;
-
- general_names = _gcr_certificate_extension_subject_alt_name (data);
- if (general_names == NULL)
- return FALSE;
-
- section = GCR_SECTION (_gcr_certificate_widget_add_section (self, _("Subject Alternative Names"),
FALSE));
-
- for (i = 0; i < general_names->len; i++) {
- general = &g_array_index (general_names, GcrGeneralName, i);
- if (general->display == NULL) {
- gchar *display = hex_encode_bytes (general->raw);
- gcr_section_add_child (section, general->description, create_value_label (display));
- g_free (display);
- } else
- gcr_section_add_child (section, general->description, create_value_label
(general->display));
- }
-
- _gcr_general_names_free (general_names);
-
- return section;
-}
-
-static GcrSection *
-append_extension_hex (GcrCertificateWidget *self,
- GQuark oid,
- GBytes *value)
-{
- GcrSection *section;
- const gchar *text;
- gchar *display;
-
- section = GCR_SECTION (_gcr_certificate_widget_add_section (self, _("Extension"), FALSE));
-
- /* Extension type */
- text = egg_oid_get_description (oid);
- gcr_section_add_child (section, _("Identifier"), create_value_label (text));
- display = hex_encode_bytes (value);
- gcr_section_add_child (section, _("Value"), create_value_label (display));
- g_free (display);
-
- return section;
-}
-
-static void
-append_extension (GcrCertificateWidget *self,
- GNode *node)
-{
- GQuark oid;
- GBytes *value;
- gboolean critical;
- GcrSection *section = NULL;
-
- /* Dig out the OID */
- oid = egg_asn1x_get_oid_as_quark (egg_asn1x_node (node, "extnID", NULL));
- g_return_if_fail (oid);
-
- /* Extension value */
- value = egg_asn1x_get_string_as_bytes (egg_asn1x_node (node, "extnValue", NULL));
-
- /* The custom parsers */
- if (oid == GCR_OID_BASIC_CONSTRAINTS)
- section = append_extension_basic_constraints (self, value);
- else if (oid == GCR_OID_EXTENDED_KEY_USAGE)
- section = append_extension_extended_key_usage (self, value);
- else if (oid == GCR_OID_SUBJECT_KEY_IDENTIFIER)
- section = append_extension_subject_key_identifier (self, value);
- else if (oid == GCR_OID_KEY_USAGE)
- section = append_extension_key_usage (self, value);
- else if (oid == GCR_OID_SUBJECT_ALT_NAME)
- section = append_extension_subject_alt_name (self, value);
-
- /* Otherwise the default raw display */
- if (!section) {
- section = append_extension_hex (self, oid, value);
- }
-
- /* Critical */
- if (section && egg_asn1x_get_boolean (egg_asn1x_node (node, "critical", NULL), &critical)) {
- gcr_section_add_child (section, _("Critical"), create_value_label (critical ? _("Yes") :
_("No")));
- }
-
- g_bytes_unref (value);
-}
-
/**
* gcr_certificate_widget_new:
* @certificate: (nullable): certificate to display, or %NULL
@@ -539,144 +171,38 @@ gcr_certificate_widget_get_certificate (GcrCertificateWidget *self)
void
gcr_certificate_widget_set_certificate (GcrCertificateWidget *self, GcrCertificate *certificate)
{
- GtkWidget *section, *label;
- PangoAttrList *attributes;
- gchar *display;
- GBytes *bytes, *number;
- GNode *asn, *subject_public_key;
- GQuark oid;
- gconstpointer data;
- gsize n_data;
- GDateTime *datetime;
- gulong version;
- guint bits, index;
+ GtkWidget *child;
+ GList* elements;
g_return_if_fail (GCR_IS_CERTIFICATE_WIDGET (self));
- g_set_object (&self->certificate, certificate);
-
- data = gcr_certificate_get_der_data (self->certificate, &n_data);
- if (!data) {
- g_set_object (&self->certificate, NULL);
+ if (!g_set_object (&self->certificate, certificate)) {
+ return;
}
- display = calculate_label (self);
- section = _gcr_certificate_widget_add_section (self, display, TRUE);
- g_clear_pointer (&display, g_free);
-
- bytes = g_bytes_new_static (data, n_data);
- asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "Certificate", bytes);
- g_bytes_unref (bytes);
-
- display = egg_dn_read_part (egg_asn1x_node (asn, "tbsCertificate", "subject", "rdnSequence", NULL),
"CN");
- gcr_section_add_child (GCR_SECTION (section), _("Identity"), create_value_label (display));
- g_clear_pointer (&display, g_free);
-
- display = egg_dn_read_part (egg_asn1x_node (asn, "tbsCertificate", "issuer", "rdnSequence", NULL),
"CN");
- gcr_section_add_child (GCR_SECTION (section), _("Verified by"), create_value_label (display));
- g_clear_pointer (&display, g_free);
-
- datetime = egg_asn1x_get_time_as_date_time (egg_asn1x_node (asn, "tbsCertificate", "validity",
"notAfter", NULL));
- if (datetime) {
- display = g_date_time_format (datetime, "%x");
- g_return_if_fail (display != NULL);
- gcr_section_add_child (GCR_SECTION (section), _("Expires"), create_value_label (display));
- g_clear_pointer (&display, g_free);
- g_clear_pointer (&datetime, g_date_time_unref);
- }
-
- /* The subject */
- section = _gcr_certificate_widget_add_section (self, _("Subject Name"), FALSE);
- egg_dn_parse (egg_asn1x_node (asn, "tbsCertificate", "subject", "rdnSequence", NULL),
on_parsed_dn_part, section);
-
- /* The Issuer */
- section = _gcr_certificate_widget_add_section (self, _("Issuer Name"), FALSE);
- egg_dn_parse (egg_asn1x_node (asn, "tbsCertificate", "issuer", "rdnSequence", NULL),
on_parsed_dn_part, section);
-
- /* The Issued Parameters */
- section = _gcr_certificate_widget_add_section (self, _("Issued Certificate"), FALSE);
-
- if (!egg_asn1x_get_integer_as_ulong (egg_asn1x_node (asn, "tbsCertificate", "version", NULL),
&version)) {
- g_critical ("Unable to parse certificate version");
- } else {
- display = g_strdup_printf ("%lu", version + 1);
- gcr_section_add_child (GCR_SECTION (section), _("Version"), create_value_label (display));
- g_clear_pointer (&display, g_free);
- }
-
- number = egg_asn1x_get_integer_as_raw (egg_asn1x_node (asn, "tbsCertificate", "serialNumber", NULL));
- if (!number) {
- g_critical ("Unable to parse certificate serial number");
- } else {
- display = hex_encode_bytes (number);
- gcr_section_add_child (GCR_SECTION (section), _("Serial Number"), create_value_label
(display));
- g_clear_pointer (&display, g_free);
- g_bytes_unref (number);
+ while ((child = gtk_widget_get_first_child (GTK_WIDGET (self->secondary_info)))) {
+ gtk_widget_unparent (child);
}
- datetime = egg_asn1x_get_time_as_date_time (egg_asn1x_node (asn, "tbsCertificate", "validity",
"notBefore", NULL));
- if (datetime) {
- display = g_date_time_format (datetime, "%x");
- g_return_if_fail (display != NULL);
- gcr_section_add_child (GCR_SECTION (section), _("Not Valid Before"), create_value_label
(display));
- g_clear_pointer (&display, g_free);
- g_clear_pointer (&datetime, g_date_time_unref);
- }
- datetime = egg_asn1x_get_time_as_date_time (egg_asn1x_node (asn, "tbsCertificate", "validity",
"notAfter", NULL));
- if (datetime) {
- display = g_date_time_format (datetime, "%x");
- g_return_if_fail (display != NULL);
- gcr_section_add_child (GCR_SECTION (section), _("Not Valid After"), create_value_label
(display));
- g_clear_pointer (&display, g_free);
- g_clear_pointer (&datetime, g_date_time_unref);
+ while ((child = gtk_widget_get_first_child (GTK_WIDGET (self->primary_info)))) {
+ gtk_widget_unparent (child);
}
- /* Fingerprints */
- section = _gcr_certificate_widget_add_section (self, _("Certificate Fingerprints"), FALSE);
- display = g_compute_checksum_for_bytes (G_CHECKSUM_SHA1, bytes);
- gcr_section_add_child (GCR_SECTION (section), "SHA1", create_value_label (display));
- g_clear_pointer (&display, g_free);
- display = g_compute_checksum_for_bytes (G_CHECKSUM_MD5, bytes);
- gcr_section_add_child (GCR_SECTION (section), "MD5", create_value_label (display));
- g_clear_pointer (&display, g_free);
-
- /* Public Key Info */
- section = _gcr_certificate_widget_add_section (self, _("Public Key Info"), FALSE);
- subject_public_key = egg_asn1x_node (asn, "tbsCertificate", "subjectPublicKeyInfo", NULL);
- append_subject_public_key (self, GCR_SECTION (section), subject_public_key);
-
- /* Extensions */
- for (index = 1; TRUE; ++index) {
- GNode *extension = egg_asn1x_node (asn, "tbsCertificate", "extensions", index, NULL);
- if (extension == NULL)
- break;
- append_extension (self, extension);
+ if (!certificate) {
+ return;
}
- /* Signature */
- section = _gcr_certificate_widget_add_section (self, _("Signature"), FALSE);
-
- oid = egg_asn1x_get_oid_as_quark (egg_asn1x_node (asn, "signatureAlgorithm", "algorithm", NULL));
- gcr_section_add_child (GCR_SECTION (section), _("Signature Algorithm"), create_value_label
(egg_oid_get_description (oid)));
+ elements = gcr_certificate_get_interface_elements (certificate);
+ for (GList *l = elements; l != NULL; l = l->next) {
+ GcrCertificateSection *section = l->data;
+ GtkWidget *widget = gcr_section_new (section);
- bytes = egg_asn1x_get_element_raw (egg_asn1x_node (asn, "signatureAlgorithm", "parameters", NULL));
- if (bytes) {
- display = hex_encode_bytes (bytes);
- gcr_section_add_child (GCR_SECTION (section), _("Signature Parameters"), create_value_label
(display));
- g_clear_pointer (&display, g_free);
- g_bytes_unref (bytes);
+ gtk_size_group_add_widget (self->size_group, widget);
+ if (gcr_certificate_section_get_flags (section) & GCR_CERTIFICATE_SECTION_IMPORTANT)
+ gtk_box_append (GTK_BOX (self->primary_info), widget);
+ else
+ gtk_box_append (GTK_BOX (self->secondary_info), widget);
}
- bytes = egg_asn1x_get_bits_as_raw (egg_asn1x_node (asn, "signature", NULL), &bits);
- display = egg_hex_encode_full (g_bytes_get_data (bytes, NULL), bits / 8, TRUE, " ", 1);
- g_bytes_unref (bytes);
- label = create_value_label (display);
- attributes = pango_attr_list_new ();
- pango_attr_list_insert (attributes, pango_attr_family_new ("Monospace"));
- gtk_label_set_attributes (GTK_LABEL (label), attributes);
- pango_attr_list_unref (attributes);
- gcr_section_add_child (GCR_SECTION (section), _("Signature"), label);
- g_clear_pointer (&display, g_free);
-
- egg_asn1x_destroy (asn);
+ g_list_free_full (elements, (GDestroyNotify) g_object_unref);
}
diff --git a/gcr-gtk4/gcr-section.c b/gcr-gtk4/gcr-section.c
index ecd8a9cc..52d83263 100644
--- a/gcr-gtk4/gcr-section.c
+++ b/gcr-gtk4/gcr-section.c
@@ -10,9 +10,8 @@ struct _GcrSection
{
GtkWidget parent_instance;
- GtkWidget *frame;
+ GcrCertificateSection *section;
GtkWidget *label;
- GtkWidget *image;
GtkWidget *listbox;
GtkSizeGroup *size_group;
};
@@ -20,21 +19,120 @@ struct _GcrSection
G_DEFINE_TYPE (GcrSection, gcr_section, GTK_TYPE_WIDGET)
enum {
- PROP_TITLE = 1,
+ PROP_SECTION = 1,
N_PROPERTIES
};
static GParamSpec *obj_properties[N_PROPERTIES] = { NULL, };
+static char*
+bytes_to_display (GBytes *bytes)
+{
+ const char *hexc = "0123456789ABCDEF";
+ GString *result;
+ const char *input;
+ gsize read_bytes;
+ gsize remaining_bytes;
+ guchar j;
+
+ g_return_val_if_fail (bytes != NULL, NULL);
+
+ input = g_bytes_get_data (bytes, &remaining_bytes);
+ result = g_string_sized_new (g_bytes_get_size (bytes) * 2 + 1);
+
+ for (read_bytes = 0; read_bytes < remaining_bytes; read_bytes++) {
+ if (read_bytes && (read_bytes % 1) == 0)
+ g_string_append_c (result, ' ');
+
+ j = *(input) >> 4 & 0xf;
+ g_string_append_c (result, hexc[j]);
+
+ j = *(input++) & 0xf;
+ g_string_append_c (result, hexc[j]);
+ }
+
+ return g_string_free (result, FALSE);
+}
+
+GtkWidget *
+gcr_section_create_row (GObject *item,
+ gpointer user_data)
+{
+ GcrCertificateField *field = (GcrCertificateField *) item;
+ GtkSizeGroup *size_group = user_data;
+ GtkWidget *row, *box, *label, *value;
+ GValue val = G_VALUE_INIT;
+ GType value_type;
+
+ g_return_val_if_fail (GCR_IS_CERTIFICATE_FIELD (field), NULL);
+
+ row = gtk_list_box_row_new ();
+ gtk_list_box_row_set_selectable (GTK_LIST_BOX_ROW (row), FALSE);
+ gtk_widget_set_focusable (row, FALSE);
+ box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12);
+ gtk_list_box_row_set_child (GTK_LIST_BOX_ROW (row), box);
+ label = gtk_label_new (gcr_certificate_field_get_label (field));
+ gtk_label_set_xalign (GTK_LABEL (label), 0.0);
+ g_object_set (label,
+ "margin-start", 12,
+ "margin-end", 12,
+ "margin-top", 8,
+ "margin-bottom", 8,
+ "xalign", 0.0,
+ "halign", GTK_ALIGN_START,
+ NULL);
+ gtk_style_context_add_class (gtk_widget_get_style_context (label), "caption");
+ value = g_object_new (GTK_TYPE_LABEL,
+ "xalign", 1.0,
+ "halign", GTK_ALIGN_END,
+ "hexpand", TRUE,
+ "selectable", TRUE,
+ "wrap", TRUE,
+ NULL);
+ value_type = gcr_certificate_field_get_value_type (field);
+ g_value_init (&val, value_type);
+ gcr_certificate_field_get_value (field, &val);
+ if (g_type_is_a (value_type, G_TYPE_STRING)) {
+ g_object_set (G_OBJECT (value), "label", g_value_get_string (&val), NULL);
+ } else if (g_type_is_a (value_type, G_TYPE_STRV)) {
+ char *lbl = g_strjoinv ("\n", (GStrv) g_value_get_boxed (&val));
+ g_object_set (G_OBJECT (value), "label", lbl, NULL);
+ g_free (lbl);
+ } else if (g_type_is_a (value_type, G_TYPE_BYTES)) {
+ PangoAttrList *attributes;
+ GBytes *bytes = g_value_get_boxed (&val);
+ char *lbl = bytes_to_display (bytes);
+ g_object_set (G_OBJECT (value), "label", lbl, NULL);
+ g_free (lbl);
+ attributes = pango_attr_list_new ();
+ pango_attr_list_insert (attributes, pango_attr_family_new ("Monospace"));
+ gtk_label_set_attributes (GTK_LABEL (value), attributes);
+ pango_attr_list_unref (attributes);
+ }
+ g_value_unset (&val);
+
+ g_object_set (value,
+ "margin-start", 12,
+ "margin-end", 12,
+ "margin-top", 8,
+ "margin-bottom", 8,
+ "halign", GTK_ALIGN_END,
+ NULL);
+ gtk_size_group_add_widget (size_group, label);
+ gtk_box_append (GTK_BOX (box), label);
+ gtk_box_append (GTK_BOX (box), value);
+ return row;
+}
+
static void
gcr_section_dispose (GObject *object)
{
GcrSection *self = (GcrSection *)object;
- g_clear_object (&self->size_group);
g_clear_pointer (&self->label, gtk_widget_unparent);
- g_clear_pointer (&self->image, gtk_widget_unparent);
- g_clear_pointer (&self->frame, gtk_widget_unparent);
+ g_clear_pointer (&self->listbox, gtk_widget_unparent);
+ g_clear_object (&self->size_group);
+ g_clear_object (&self->section);
G_OBJECT_CLASS (gcr_section_parent_class)->dispose (object);
}
@@ -49,8 +147,8 @@ gcr_section_get_property (GObject *object,
switch (prop_id)
{
- case PROP_TITLE:
- g_value_set_string (value, gtk_label_get_label (GTK_LABEL (self->label)));
+ case PROP_SECTION:
+ g_value_set_object (value, self->section);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -67,8 +165,14 @@ gcr_section_set_property (GObject *object,
switch (prop_id)
{
- case PROP_TITLE:
- gtk_label_set_label (GTK_LABEL (self->label), g_value_get_string (value));
+ case PROP_SECTION:
+ g_assert (!self->section);
+ self->section = g_value_dup_object (value);
+ gtk_label_set_label (GTK_LABEL (self->label), gcr_certificate_section_get_label
(self->section));
+ gtk_list_box_bind_model (GTK_LIST_BOX (self->listbox),
+ gcr_certificate_section_get_fields (self->section),
+ (GtkListBoxCreateWidgetFunc) gcr_section_create_row,
+ self->size_group, NULL);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -84,11 +188,11 @@ gcr_section_class_init (GcrSectionClass *klass)
object_class->dispose = gcr_section_dispose;
object_class->get_property = gcr_section_get_property;
object_class->set_property = gcr_section_set_property;
- obj_properties[PROP_TITLE] =
- g_param_spec_string ("title",
- "Title",
- "The title of the section",
- NULL,
+ obj_properties[PROP_SECTION] =
+ g_param_spec_object ("section",
+ "Section",
+ "The section object",
+ GCR_TYPE_CERTIFICATE_SECTION,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS);
g_object_class_install_properties (object_class,
@@ -106,76 +210,39 @@ gcr_section_init (GcrSection *self)
self->label = gtk_label_new (NULL);
g_object_set (G_OBJECT (self->label),
- "margin-start", 12,
- "margin-end", 12,
- "margin-top", 8,
- "margin-bottom", 8,
+ "margin-start", 12,
+ "margin-end", 12,
+ "margin-top", 8,
+ "margin-bottom", 8,
"xalign", 0.0,
- "halign", GTK_ALIGN_START,
- "hexpand", TRUE,
+ "halign", GTK_ALIGN_START,
+ "hexpand", TRUE,
NULL);
+ gtk_style_context_add_class (gtk_widget_get_style_context (self->label), "title");
gtk_style_context_add_class (gtk_widget_get_style_context (self->label), "caption-heading");
self->listbox = gtk_list_box_new ();
+ gtk_style_context_add_class (gtk_widget_get_style_context (self->listbox), "frame");
+ gtk_style_context_add_class (gtk_widget_get_style_context (self->listbox), "rich-list");
gtk_list_box_set_selection_mode (GTK_LIST_BOX (self->listbox), GTK_SELECTION_NONE);
- self->frame = gtk_frame_new (NULL);
- g_object_set (G_OBJECT (self->frame),
- "child", self->listbox,
- "hexpand", TRUE,
- NULL);
self->size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
gtk_widget_insert_after (self->label, GTK_WIDGET (self), NULL);
- gtk_widget_insert_after (self->frame, GTK_WIDGET (self), self->label);
+ gtk_widget_insert_after (self->listbox, GTK_WIDGET (self), self->label);
layout_manager = gtk_widget_get_layout_manager (GTK_WIDGET (self));
- child = gtk_layout_manager_get_layout_child (layout_manager, self->frame);
+ child = gtk_layout_manager_get_layout_child (layout_manager, self->listbox);
g_object_set (G_OBJECT (child),
"row", 1,
NULL);
g_object_set (self,
- "margin-start", 12,
- "margin-end", 12,
- "margin-top", 8,
- "margin-bottom", 8,
+ "margin-start", 12,
+ "margin-end", 12,
+ "margin-top", 8,
+ "margin-bottom", 8,
NULL);
}
GtkWidget *
-gcr_section_new (const gchar *title)
-{
- return g_object_new (GCR_TYPE_SECTION, "title", title, NULL);
-}
-
-void
-gcr_section_add_child (GcrSection *self,
- const gchar *description,
- GtkWidget *child)
+gcr_section_new (GcrCertificateSection *section)
{
- GtkWidget *row, *box, *label;
- g_return_if_fail (GCR_IS_SECTION (self));
-
- row = gtk_list_box_row_new ();
- box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12);
- gtk_list_box_row_set_child (GTK_LIST_BOX_ROW (row), box);
- label = gtk_label_new (description);
- gtk_label_set_xalign (GTK_LABEL (label), 0.0);
- g_object_set (label,
- "margin-start", 12,
- "margin-end", 12,
- "margin-top", 8,
- "margin-bottom", 8,
- "xalign", 0.0,
- "halign", GTK_ALIGN_START,
- NULL);
- gtk_style_context_add_class (gtk_widget_get_style_context (label), "caption");
- g_object_set (child,
- "margin-start", 12,
- "margin-end", 12,
- "margin-top", 8,
- "margin-bottom", 8,
- "halign", GTK_ALIGN_END,
- NULL);
- gtk_size_group_add_widget (self->size_group, label);
- gtk_box_append (GTK_BOX (box), label);
- gtk_box_append (GTK_BOX (box), child);
- gtk_list_box_insert (GTK_LIST_BOX (self->listbox), row, -1);
+ return g_object_new (GCR_TYPE_SECTION, "section", section, NULL);
}
diff --git a/gcr-gtk4/gcr-section.h b/gcr-gtk4/gcr-section.h
index 0bc7c270..c341ae94 100644
--- a/gcr-gtk4/gcr-section.h
+++ b/gcr-gtk4/gcr-section.h
@@ -10,6 +10,7 @@
#include <glib.h>
#include <glib-object.h>
#include <gtk/gtk.h>
+#include <gcr/gcr.h>
G_BEGIN_DECLS
@@ -17,11 +18,7 @@ G_BEGIN_DECLS
G_DECLARE_FINAL_TYPE (GcrSection, gcr_section, GCR, SECTION, GtkWidget)
-GtkWidget *gcr_section_new (const gchar *title);
-
-void gcr_section_add_child (GcrSection *self,
- const gchar *description,
- GtkWidget *child);
+GtkWidget *gcr_section_new (GcrCertificateSection *section);
G_END_DECLS
diff --git a/gcr/gcr-certificate-field-private.h b/gcr/gcr-certificate-field-private.h
new file mode 100644
index 00000000..bfd5bcf6
--- /dev/null
+++ b/gcr/gcr-certificate-field-private.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2021 Collabora Ltd.
+ * Copyright Corentin Noël <corentin noel collabora com>
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+
+#ifndef __GCR_CERTIFICATE_FIELD_PRIVATE_H__
+#define __GCR_CERTIFICATE_FIELD_PRIVATE_H__
+
+#if !defined (__GCR_INSIDE_HEADER__) && !defined (GCR_COMPILATION)
+#error "Only <gcr/gcr.h> can be included directly."
+#endif
+
+#include "gcr-types.h"
+#include "gcr-certificate-field.h"
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+GcrCertificateSection *_gcr_certificate_section_new (const char *label,
+ gboolean important);
+void _gcr_certificate_section_append_field (GcrCertificateSection *section,
+ GcrCertificateField *field);
+GcrCertificateField *_gcr_certificate_field_new_take_value (GcrCertificateSection *section,
+ const char *label,
+ char *value);
+GcrCertificateField *_gcr_certificate_field_new_take_values (GcrCertificateSection *section,
+ const char *label,
+ GStrv value);
+GcrCertificateField *_gcr_certificate_field_new_take_bytes (GcrCertificateSection *section,
+ const char *label,
+ GBytes *bytes);
+
+static inline void
+_gcr_certificate_section_new_field_take_value (GcrCertificateSection *section,
+ const char *label,
+ char *value)
+{
+ GcrCertificateField *field = _gcr_certificate_field_new_take_value (section, label, value);
+ _gcr_certificate_section_append_field (section, field);
+ g_object_unref (field);
+}
+
+static inline void
+_gcr_certificate_section_new_field_take_values (GcrCertificateSection *section,
+ const char *label,
+ GStrv values)
+{
+ GcrCertificateField *field = _gcr_certificate_field_new_take_values (section, label, values);
+ _gcr_certificate_section_append_field (section, field);
+ g_object_unref (field);
+}
+
+static inline void
+_gcr_certificate_section_new_field_take_bytes (GcrCertificateSection *section,
+ const char *label,
+ GBytes *bytes)
+{
+ GcrCertificateField *field = _gcr_certificate_field_new_take_bytes (section, label, bytes);
+ _gcr_certificate_section_append_field (section, field);
+ g_object_unref (field);
+}
+
+static inline void
+_gcr_certificate_section_new_field (GcrCertificateSection *section,
+ const char *label,
+ const char *value)
+{
+ _gcr_certificate_section_new_field_take_value (section, label, g_strdup (value));
+}
+
+G_END_DECLS
+
+#endif /* __GCR_CERTIFICATE_FIELD_PRIVATE_H__ */
diff --git a/gcr/gcr-certificate-field.c b/gcr/gcr-certificate-field.c
new file mode 100644
index 00000000..3869e199
--- /dev/null
+++ b/gcr/gcr-certificate-field.c
@@ -0,0 +1,261 @@
+/*
+ * Copyright 2021 Collabora Ltd.
+ * Copyright Corentin Noël <corentin noel collabora com>
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+
+#include "gcr-certificate-field.h"
+#include "gcr-certificate-field-private.h"
+#include "gcr-enum-types.h"
+
+struct _GcrCertificateField
+{
+ GObject parent_instance;
+
+ char *label;
+ GValue value;
+ GcrCertificateSection *section;
+};
+
+G_DEFINE_FINAL_TYPE (GcrCertificateField, gcr_certificate_field, G_TYPE_OBJECT)
+
+enum {
+ PROP_LABEL = 1,
+ PROP_VALUE,
+ PROP_SECTION,
+ N_PROPERTIES
+};
+
+static GParamSpec *obj_properties [N_PROPERTIES];
+
+static void
+gcr_certificate_field_finalize (GObject *object)
+{
+ GcrCertificateField *self = (GcrCertificateField *)object;
+
+ g_clear_pointer (&self->label, g_free);
+ g_value_unset (&self->value);
+
+ G_OBJECT_CLASS (gcr_certificate_field_parent_class)->finalize (object);
+}
+
+static void
+gcr_certificate_field_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GcrCertificateField *self = GCR_CERTIFICATE_FIELD (object);
+
+ switch (prop_id) {
+ case PROP_LABEL:
+ g_value_set_string (value, self->label);
+ break;
+ case PROP_VALUE:
+ g_value_set_boxed (value, &self->value);
+ break;
+ case PROP_SECTION:
+ g_value_set_object (value, self->section);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static void
+gcr_certificate_field_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GcrCertificateField *self = GCR_CERTIFICATE_FIELD (object);
+
+ switch (prop_id) {
+ case PROP_LABEL:
+ self->label = g_value_dup_string (value);
+ break;
+ case PROP_SECTION:
+ self->section = g_value_get_object (value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static void
+gcr_certificate_field_class_init (GcrCertificateFieldClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->finalize = gcr_certificate_field_finalize;
+ object_class->get_property = gcr_certificate_field_get_property;
+ object_class->set_property = gcr_certificate_field_set_property;
+
+ obj_properties[PROP_LABEL] =
+ g_param_spec_string ("label",
+ "Label",
+ "Display name of the field.",
+ NULL,
+ G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
+
+ obj_properties[PROP_VALUE] =
+ g_param_spec_boxed ("value",
+ "Value",
+ "Display name of the value.",
+ G_TYPE_VALUE,
+ G_PARAM_STATIC_STRINGS | G_PARAM_READABLE);
+
+ obj_properties[PROP_SECTION] =
+ g_param_spec_object ("section",
+ "Section",
+ "The section it is included.",
+ GCR_TYPE_CERTIFICATE_SECTION,
+ G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
+
+ g_object_class_install_properties (object_class,
+ N_PROPERTIES,
+ obj_properties);
+}
+
+static void
+gcr_certificate_field_init (GcrCertificateField *self)
+{
+}
+
+/**
+ * gcr_certificate_field_get_label:
+ * @self: the #GcrCertificateField
+ *
+ * Get the display label of the field.
+ *
+ * Returns: the display label of the field
+ */
+const char *
+gcr_certificate_field_get_label (GcrCertificateField *self)
+{
+ g_return_val_if_fail (GCR_IS_CERTIFICATE_FIELD (self), NULL);
+
+ return self->label;
+}
+
+/**
+ * gcr_certificate_field_get_value:
+ * @self: the #GcrCertificateField
+ * @value: (out caller-allocates): the `GValue` to fill
+ *
+ * Get the value of the field.
+ *
+ * The @value will have been initialized to the `GType` the value should be
+ * provided in.
+ *
+ * Returns: %TRUE if the value was set successfully.
+ */
+gboolean
+gcr_certificate_field_get_value (GcrCertificateField *self,
+ GValue *value)
+{
+ g_return_val_if_fail (GCR_IS_CERTIFICATE_FIELD (self), FALSE);
+ g_return_val_if_fail (G_IS_VALUE (value), FALSE);
+
+ if (G_VALUE_HOLDS (&self->value, G_VALUE_TYPE (value))) {
+ g_value_copy (&self->value, value);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/**
+ * gcr_certificate_field_get_value_type:
+ * @self: the #GcrCertificateField
+ *
+ * Get the type associated with the value.
+ *
+ * Returns: The `GType` of the value
+ */
+GType
+gcr_certificate_field_get_value_type (GcrCertificateField *self)
+{
+ g_return_val_if_fail (GCR_IS_CERTIFICATE_FIELD (self), FALSE);
+
+ return G_VALUE_TYPE (&self->value);
+}
+
+/**
+ * gcr_certificate_field_get_section:
+ * @self: the #GcrCertificateField
+ *
+ * Get the parent #GcrCertificateSection.
+ *
+ * Returns: (transfer none): the parent #GcrCertificateSection
+ */
+GcrCertificateSection *
+gcr_certificate_field_get_section (GcrCertificateField *self)
+{
+ g_return_val_if_fail (GCR_IS_CERTIFICATE_FIELD (self), NULL);
+
+ return self->section;
+}
+
+GcrCertificateField *
+_gcr_certificate_field_new_take_value (GcrCertificateSection *section,
+ const char *label,
+ char *value)
+{
+ GcrCertificateField *self;
+
+ g_return_val_if_fail (GCR_IS_CERTIFICATE_SECTION (section), NULL);
+ g_return_val_if_fail (label != NULL, NULL);
+ g_return_val_if_fail (value != NULL, NULL);
+
+ self = g_object_new (GCR_TYPE_CERTIFICATE_FIELD,
+ "section", section,
+ "label", label,
+ NULL);
+ g_value_init (&self->value, G_TYPE_STRING);
+ g_value_take_string (&self->value, value);
+
+ return self;
+}
+
+GcrCertificateField *
+_gcr_certificate_field_new_take_values (GcrCertificateSection *section,
+ const char *label,
+ GStrv values)
+{
+ GcrCertificateField *self;
+
+ g_return_val_if_fail (GCR_IS_CERTIFICATE_SECTION (section), NULL);
+ g_return_val_if_fail (label != NULL, NULL);
+ g_return_val_if_fail (values != NULL, NULL);
+
+ self = g_object_new (GCR_TYPE_CERTIFICATE_FIELD,
+ "section", section,
+ "label", label,
+ NULL);
+ g_value_init (&self->value, G_TYPE_STRV);
+ g_value_take_boxed (&self->value, values);
+
+ return self;
+}
+
+GcrCertificateField *
+_gcr_certificate_field_new_take_bytes (GcrCertificateSection *section,
+ const char *label,
+ GBytes *bytes)
+{
+ GcrCertificateField *self;
+
+ g_return_val_if_fail (GCR_IS_CERTIFICATE_SECTION (section), NULL);
+ g_return_val_if_fail (label != NULL, NULL);
+ g_return_val_if_fail (bytes != NULL, NULL);
+
+ self = g_object_new (GCR_TYPE_CERTIFICATE_FIELD,
+ "section", section,
+ "label", label,
+ NULL);
+ g_value_init (&self->value, G_TYPE_BYTES);
+ g_value_take_boxed (&self->value, bytes);
+
+ return self;
+}
diff --git a/gcr/gcr-certificate-field.h b/gcr/gcr-certificate-field.h
new file mode 100644
index 00000000..946ccdc5
--- /dev/null
+++ b/gcr/gcr-certificate-field.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2022 Collabora Ltd.
+ * Copyright Corentin Noël <corentin noel collabora com>
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+
+#ifndef __GCR_CERTIFICATE_FIELD_H__
+#define __GCR_CERTIFICATE_FIELD_H__
+
+#if !defined (__GCR_INSIDE_HEADER__) && !defined (GCR_COMPILATION)
+#error "Only <gcr/gcr.h> can be included directly."
+#endif
+
+#include "gcr-types.h"
+#include <gcr/gcr-certificate-section.h>
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define GCR_TYPE_CERTIFICATE_FIELD (gcr_certificate_field_get_type ())
+
+G_DECLARE_FINAL_TYPE (GcrCertificateField, gcr_certificate_field, GCR, CERTIFICATE_FIELD, GObject)
+
+const char *gcr_certificate_field_get_label (GcrCertificateField *self);
+gboolean gcr_certificate_field_get_value (GcrCertificateField *self,
+ GValue *value);
+GType gcr_certificate_field_get_value_type (GcrCertificateField *self);
+GcrCertificateSection *gcr_certificate_field_get_section (GcrCertificateField *self);
+
+G_END_DECLS
+
+#endif /* __GCR_CERTIFICATE_FIELD_H__ */
diff --git a/gcr/gcr-certificate-section.c b/gcr/gcr-certificate-section.c
new file mode 100644
index 00000000..4741ca67
--- /dev/null
+++ b/gcr/gcr-certificate-section.c
@@ -0,0 +1,211 @@
+/*
+ * Copyright 2021 Collabora Ltd.
+ * Copyright Corentin Noël <corentin noel collabora com>
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+
+#include "gcr-certificate-field.h"
+#include "gcr-certificate-section.h"
+#include "gcr-enum-types.h"
+
+struct _GcrCertificateSection {
+ GObject parent_instance;
+
+ char *label;
+ GcrCertificateSectionFlags flags;
+ GListStore *fields;
+};
+
+G_DEFINE_FINAL_TYPE (GcrCertificateSection, gcr_certificate_section, G_TYPE_OBJECT)
+
+enum {
+ PROP_LABEL = 1,
+ PROP_FIELDS,
+ PROP_FLAGS,
+ N_PROPERTIES
+};
+
+static GParamSpec *obj_properties [N_PROPERTIES];
+
+
+/**
+ * _gcr_certificate_section_new:
+ * @label: the user-displayable label of the section
+ * @important: whether this section should be visible by default
+ *
+ * Create a new certificate section usable in user interfaces.
+ *
+ * Returns: (transfer full): a new #GcrCertificateSection
+ */
+GcrCertificateSection *
+_gcr_certificate_section_new (const char *label,
+ gboolean important)
+{
+ return g_object_new (GCR_TYPE_CERTIFICATE_SECTION,
+ "label", label,
+ "flags", important ? GCR_CERTIFICATE_SECTION_IMPORTANT :
GCR_CERTIFICATE_SECTION_NONE,
+ NULL);
+}
+
+static void
+gcr_certificate_section_finalize (GObject *object)
+{
+ GcrCertificateSection *self = (GcrCertificateSection *)object;
+ g_clear_pointer (&self->label, g_free);
+
+ G_OBJECT_CLASS (gcr_certificate_section_parent_class)->finalize (object);
+}
+
+static void
+gcr_certificate_section_dispose (GObject *object)
+{
+ GcrCertificateSection *self = (GcrCertificateSection *)object;
+ g_clear_object (&self->fields);
+
+ G_OBJECT_CLASS (gcr_certificate_section_parent_class)->dispose (object);
+}
+
+static void
+gcr_certificate_section_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GcrCertificateSection *self = GCR_CERTIFICATE_SECTION (object);
+
+ switch (prop_id) {
+ case PROP_LABEL:
+ g_value_set_string (value, self->label);
+ break;
+ case PROP_FIELDS:
+ g_value_set_object (value, &self->fields);
+ break;
+ case PROP_FLAGS:
+ g_value_set_flags (value, self->flags);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static void
+gcr_certificate_section_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GcrCertificateSection *self = GCR_CERTIFICATE_SECTION (object);
+
+ switch (prop_id) {
+ case PROP_LABEL:
+ self->label = g_value_dup_string (value);
+ break;
+ case PROP_FLAGS:
+ self->flags = g_value_get_flags (value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static void
+gcr_certificate_section_class_init (GcrCertificateSectionClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->finalize = gcr_certificate_section_finalize;
+ object_class->dispose = gcr_certificate_section_dispose;
+ object_class->get_property = gcr_certificate_section_get_property;
+ object_class->set_property = gcr_certificate_section_set_property;
+
+ obj_properties[PROP_LABEL] =
+ g_param_spec_string ("label",
+ "Label",
+ "Display name of the field.",
+ NULL,
+ G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
+
+ obj_properties[PROP_FIELDS] =
+ g_param_spec_object ("fields",
+ "Fields",
+ "The list of fields.",
+ G_TYPE_LIST_MODEL,
+ G_PARAM_STATIC_STRINGS | G_PARAM_READABLE);
+
+ obj_properties[PROP_FLAGS] =
+ g_param_spec_flags ("flags",
+ "Flags",
+ "Flags defined for the section.",
+ GCR_TYPE_CERTIFICATE_SECTION_FLAGS,
+ GCR_CERTIFICATE_SECTION_NONE,
+ G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
+
+ g_object_class_install_properties (object_class,
+ N_PROPERTIES,
+ obj_properties);
+}
+
+static void
+gcr_certificate_section_init (GcrCertificateSection *self)
+{
+ self->fields = g_list_store_new (GCR_TYPE_CERTIFICATE_FIELD);
+}
+
+/**
+ * gcr_certificate_section_get_label:
+ * @self: the #GcrCertificateSection
+ *
+ * Get the displayable label of the section.
+ *
+ * Returns: the displayable label of the section
+ */
+const char *
+gcr_certificate_section_get_label (GcrCertificateSection *self)
+{
+ g_return_val_if_fail (self != NULL, NULL);
+
+ return self->label;
+}
+
+/**
+ * gcr_certificate_section_get_flags:
+ * @self: the #GcrCertificateSection
+ *
+ * Get the flags.
+ *
+ * Returns: the `GcrCertificateSectionFlags`
+ */
+GcrCertificateSectionFlags
+gcr_certificate_section_get_flags (GcrCertificateSection *self)
+{
+ g_return_val_if_fail (self != NULL, FALSE);
+
+ return self->flags;
+}
+
+/**
+ * gcr_certificate_section_get_fields:
+ * @self: the #GcrCertificateSection
+ *
+ * Get the list of all the fields in this section.
+ *
+ * Returns: (transfer none): a #GListModel of #GcrCertificateField
+ */
+GListModel *
+gcr_certificate_section_get_fields (GcrCertificateSection *self)
+{
+ g_return_val_if_fail (self != NULL, NULL);
+
+ return G_LIST_MODEL (self->fields);
+}
+
+void
+_gcr_certificate_section_append_field (GcrCertificateSection *section,
+ GcrCertificateField *field)
+{
+ g_return_if_fail (GCR_IS_CERTIFICATE_SECTION (section));
+ g_return_if_fail (GCR_IS_CERTIFICATE_FIELD (field));
+
+ g_list_store_append (section->fields, field);
+}
+
diff --git a/gcr/gcr-certificate-section.h b/gcr/gcr-certificate-section.h
new file mode 100644
index 00000000..85068970
--- /dev/null
+++ b/gcr/gcr-certificate-section.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2022 Collabora Ltd.
+ * Copyright Corentin Noël <corentin noel collabora com>
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+
+#ifndef __GCR_CERTIFICATE_SECTION_H__
+#define __GCR_CERTIFICATE_SECTION_H__
+
+#if !defined (__GCR_INSIDE_HEADER__) && !defined (GCR_COMPILATION)
+#error "Only <gcr/gcr.h> can be included directly."
+#endif
+
+#include "gcr-types.h"
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define GCR_TYPE_CERTIFICATE_SECTION (gcr_certificate_section_get_type())
+
+G_DECLARE_FINAL_TYPE (GcrCertificateSection, gcr_certificate_section, GCR, CERTIFICATE_SECTION, GObject)
+
+typedef enum {
+ GCR_CERTIFICATE_SECTION_NONE = 0,
+ GCR_CERTIFICATE_SECTION_IMPORTANT = 1 << 0,
+} GcrCertificateSectionFlags;
+
+const char *gcr_certificate_section_get_label (GcrCertificateSection *self);
+GListModel *gcr_certificate_section_get_fields (GcrCertificateSection *self);
+GcrCertificateSectionFlags gcr_certificate_section_get_flags (GcrCertificateSection *self);
+
+G_END_DECLS
+
+#endif /* __GCR_CERTIFICATE_SECTION_H__ */
diff --git a/gcr/gcr-certificate.c b/gcr/gcr-certificate.c
index fc2d9e09..97740c2f 100644
--- a/gcr/gcr-certificate.c
+++ b/gcr/gcr-certificate.c
@@ -21,6 +21,9 @@
#include "gcr-certificate.h"
#include "gcr-certificate-extensions.h"
+#include "gcr-certificate-field.h"
+#include "gcr-certificate-field-private.h"
+#include "gcr-fingerprint.h"
#include "gcr-internal.h"
#include "gcr-subject-public-key.h"
@@ -30,6 +33,7 @@
#include "egg/egg-asn1-defs.h"
#include "egg/egg-dn.h"
#include "egg/egg-hex.h"
+#include "egg/egg-oid.h"
#include <string.h>
#include <glib/gi18n-lib.h>
@@ -856,6 +860,438 @@ gcr_certificate_get_basic_constraints (GcrCertificate *self,
return TRUE;
}
+static void
+append_subject_public_key (GcrCertificate *self,
+ GcrCertificateSection *section,
+ GNode *subject_public_key)
+{
+ guint key_nbits;
+ const gchar *text;
+ gchar *display;
+ GBytes *value;
+ guchar *raw;
+ gsize n_raw;
+ GQuark oid;
+ guint bits;
+
+ key_nbits = gcr_certificate_get_key_size (self);
+
+ oid = egg_asn1x_get_oid_as_quark (egg_asn1x_node (subject_public_key,
+ "algorithm", "algorithm", NULL));
+ text = egg_oid_get_description (oid);
+ _gcr_certificate_section_new_field (section, _("Key Algorithm"), text);
+
+ value = egg_asn1x_get_element_raw (egg_asn1x_node (subject_public_key,
+ "algorithm", "parameters", NULL));
+ if (value) {
+ _gcr_certificate_section_new_field_take_bytes (section,
+ _("Key Parameters"),
+ g_steal_pointer (&value));
+ }
+
+ if (key_nbits > 0) {
+ display = g_strdup_printf ("%u", key_nbits);
+ _gcr_certificate_section_new_field_take_value (section,
+ _("Key Size"),
+ g_steal_pointer (&display));
+ }
+
+ value = egg_asn1x_get_element_raw (subject_public_key);
+ raw = gcr_fingerprint_from_subject_public_key_info (g_bytes_get_data (value, NULL),
+ g_bytes_get_size (value),
+ G_CHECKSUM_SHA1, &n_raw);
+ g_clear_pointer (&value, g_bytes_unref);
+ _gcr_certificate_section_new_field_take_bytes (section,
+ _("Key SHA1 Fingerprint"),
+ g_bytes_new_take (raw, n_raw));
+
+ value = egg_asn1x_get_bits_as_raw (egg_asn1x_node (subject_public_key, "subjectPublicKey", NULL),
&bits);
+ _gcr_certificate_section_new_field_take_bytes (section, _("Public Key"), g_steal_pointer (&value));
+}
+
+static GcrCertificateSection *
+append_extension_basic_constraints (GBytes *data)
+{
+ GcrCertificateSection *section;
+ gboolean is_ca = FALSE;
+ gint path_len = -1;
+ gchar *number;
+
+ if (!_gcr_certificate_extension_basic_constraints (data, &is_ca, &path_len))
+ return NULL;
+
+ section = _gcr_certificate_section_new (_("Basic Constraints"), FALSE);
+ _gcr_certificate_section_new_field (section, _("Certificate Authority"), is_ca ? _("Yes") : _("No"));
+
+ if (path_len < 0)
+ number = g_strdup (_("Unlimited"));
+ else
+ number = g_strdup_printf ("%d", path_len);
+
+ _gcr_certificate_section_new_field_take_value (section, _("Max Path Length"), g_steal_pointer
(&number));
+
+ return section;
+}
+
+static GcrCertificateSection *
+append_extension_extended_key_usage (GBytes *data)
+{
+ GcrCertificateSection *section;
+ GQuark *oids;
+ GStrvBuilder *text;
+ guint i;
+
+ oids = _gcr_certificate_extension_extended_key_usage (data);
+ if (!oids)
+ return NULL;
+
+ text = g_strv_builder_new ();
+ for (i = 0; oids[i] != 0; i++) {
+ g_strv_builder_add (text, egg_oid_get_description (oids[i]));
+ }
+
+ g_free (oids);
+
+ section = _gcr_certificate_section_new (_("Extended Key Usage"), FALSE);
+ _gcr_certificate_section_new_field_take_values (section, _("Allowed Purposes"), g_strv_builder_end
(text));
+ g_strv_builder_unref (text);
+
+ return section;
+}
+
+static GcrCertificateSection *
+append_extension_subject_key_identifier (GBytes *data)
+{
+ GcrCertificateSection *section;
+ gpointer keyid;
+ gsize n_keyid;
+
+ keyid = _gcr_certificate_extension_subject_key_identifier (data, &n_keyid);
+ if (!keyid)
+ return NULL;
+
+ section = _gcr_certificate_section_new (_("Subject Key Identifier"), FALSE);
+ gchar *display = egg_hex_encode_full (keyid, n_keyid, TRUE, " ", 1);
+ g_free (keyid);
+ _gcr_certificate_section_new_field_take_value (section, _("Key Identifier"), g_steal_pointer
(&display));
+
+ return section;
+}
+
+static const struct {
+ guint usage;
+ const gchar *description;
+} usage_descriptions[] = {
+ { GCR_KEY_USAGE_DIGITAL_SIGNATURE, N_("Digital signature") },
+ { GCR_KEY_USAGE_NON_REPUDIATION, N_("Non repudiation") },
+ { GCR_KEY_USAGE_KEY_ENCIPHERMENT, N_("Key encipherment") },
+ { GCR_KEY_USAGE_DATA_ENCIPHERMENT, N_("Data encipherment") },
+ { GCR_KEY_USAGE_KEY_AGREEMENT, N_("Key agreement") },
+ { GCR_KEY_USAGE_KEY_CERT_SIGN, N_("Certificate signature") },
+ { GCR_KEY_USAGE_CRL_SIGN, N_("Revocation list signature") },
+ { GCR_KEY_USAGE_ENCIPHER_ONLY, N_("Encipher only") },
+ { GCR_KEY_USAGE_DECIPHER_ONLY, N_("Decipher only") }
+};
+
+static GcrCertificateSection *
+append_extension_key_usage (GBytes *data)
+{
+ GcrCertificateSection *section;
+ gulong key_usage;
+ GStrvBuilder *values;
+ guint i;
+
+ if (!_gcr_certificate_extension_key_usage (data, &key_usage))
+ return NULL;
+
+ values = g_strv_builder_new ();
+ for (i = 0; i < G_N_ELEMENTS (usage_descriptions); i++) {
+ if (key_usage & usage_descriptions[i].usage) {
+ g_strv_builder_add (values, _(usage_descriptions[i].description));
+ }
+ }
+
+ section = _gcr_certificate_section_new (_("Key Usage"), FALSE);
+ _gcr_certificate_section_new_field_take_values (section, _("Usages"), g_strv_builder_end (values));
+ g_strv_builder_unref (values);
+
+ return section;
+}
+
+static GcrCertificateSection *
+append_extension_subject_alt_name (GBytes *data)
+{
+ GcrCertificateSection *section;
+ GArray *general_names;
+ GcrGeneralName *general;
+ guint i;
+
+ general_names = _gcr_certificate_extension_subject_alt_name (data);
+ if (general_names == NULL)
+ return FALSE;
+
+ section = _gcr_certificate_section_new (_("Subject Alternative Names"), FALSE);
+
+ for (i = 0; i < general_names->len; i++) {
+ general = &g_array_index (general_names, GcrGeneralName, i);
+ if (general->display == NULL) {
+ gchar *display = egg_hex_encode_bytes_full (general->raw, TRUE, " ", 1);
+ _gcr_certificate_section_new_field_take_value (section, general->description,
g_steal_pointer (&display));
+ } else
+ _gcr_certificate_section_new_field (section, general->description, general->display);
+ }
+
+ _gcr_general_names_free (general_names);
+
+ return section;
+}
+
+static GcrCertificateSection *
+append_extension_hex (GQuark oid,
+ GBytes *value)
+{
+ GcrCertificateSection *section;
+ const gchar *text;
+
+ section = _gcr_certificate_section_new (_("Extension"), FALSE);
+
+ /* Extension type */
+ text = egg_oid_get_description (oid);
+ _gcr_certificate_section_new_field (section, _("Identifier"), g_strdup (text));
+ _gcr_certificate_section_new_field_take_bytes (section, _("Value"), g_steal_pointer (&value));
+
+ return section;
+}
+
+static GcrCertificateSection *
+append_extension (GcrCertificate *self,
+ GNode *node)
+{
+ GQuark oid;
+ GBytes *value;
+ gboolean critical;
+ GcrCertificateSection *section = NULL;
+
+ /* Dig out the OID */
+ oid = egg_asn1x_get_oid_as_quark (egg_asn1x_node (node, "extnID", NULL));
+ g_return_val_if_fail (oid, NULL);
+
+ /* Extension value */
+ value = egg_asn1x_get_string_as_bytes (egg_asn1x_node (node, "extnValue", NULL));
+
+ /* The custom parsers */
+ if (oid == GCR_OID_BASIC_CONSTRAINTS)
+ section = append_extension_basic_constraints (value);
+ else if (oid == GCR_OID_EXTENDED_KEY_USAGE)
+ section = append_extension_extended_key_usage (value);
+ else if (oid == GCR_OID_SUBJECT_KEY_IDENTIFIER)
+ section = append_extension_subject_key_identifier (value);
+ else if (oid == GCR_OID_KEY_USAGE)
+ section = append_extension_key_usage (value);
+ else if (oid == GCR_OID_SUBJECT_ALT_NAME)
+ section = append_extension_subject_alt_name (value);
+
+ /* Otherwise the default raw display */
+ if (!section) {
+ section = append_extension_hex (oid, g_steal_pointer (&value));
+ }
+
+ /* Critical */
+ if (section && egg_asn1x_get_boolean (egg_asn1x_node (node, "critical", NULL), &critical)) {
+ _gcr_certificate_section_new_field (section, _("Critical"), critical ? _("Yes") : _("No"));
+ }
+
+ g_clear_pointer (&value, g_bytes_unref);
+ return section;
+}
+
+static void
+on_parsed_dn_part (guint index,
+ GQuark oid,
+ GNode *value,
+ gpointer user_data)
+{
+ GcrCertificateSection *section = user_data;
+ const gchar *attr;
+ const gchar *desc;
+ gchar *label, *display;
+
+ attr = egg_oid_get_name (oid);
+ desc = egg_oid_get_description (oid);
+
+ /* Combine them into something sane */
+ if (attr && desc) {
+ if (strcmp (attr, desc) == 0)
+ label = g_strdup (attr);
+ else
+ label = g_strdup_printf ("%s (%s)", attr, desc);
+ } else if (!attr && !desc) {
+ label = g_strdup ("");
+ } else if (attr) {
+ label = g_strdup (attr);
+ } else if (desc) {
+ label = g_strdup (desc);
+ } else {
+ g_assert_not_reached ();
+ }
+
+ display = egg_dn_print_value (oid, value);
+ if (!display)
+ display = g_strdup ("");
+
+ _gcr_certificate_section_new_field_take_value (section, label, g_steal_pointer (&display));
+ g_clear_pointer (&label, g_free);
+}
+
+/**
+ * gcr_certificate_get_interface_elements:
+ * @self: the #GcrCertificate
+ *
+ * Get the list of sections from the certificate that can be shown to the user
+ * interface.
+ *
+ * Returns: (element-type GcrCertificateSection) (transfer full): A #GList of
+ * #GcrCertificateSection
+ */
+GList *
+gcr_certificate_get_interface_elements (GcrCertificate *self)
+{
+ GcrCertificateSection *section;
+ GcrCertificateInfo *info;
+ GList *list = NULL;
+ gchar *display;
+ GBytes *bytes, *number;
+ GNode *subject_public_key;
+ GQuark oid;
+ GDateTime *datetime;
+ gulong version;
+ guint bits;
+
+ g_return_val_if_fail (GCR_IS_CERTIFICATE (self), NULL);
+
+ info = certificate_info_load (self);
+ g_return_val_if_fail (info != NULL, NULL);
+
+ display = gcr_certificate_get_subject_name (self);
+ if (!display)
+ display = g_strdup (_("Certificate"));
+
+ section = _gcr_certificate_section_new (display, TRUE);
+ g_clear_pointer (&display, g_free);
+
+ display = gcr_certificate_get_subject_cn (self);
+ _gcr_certificate_section_new_field_take_value (section, _("Identity"), g_steal_pointer (&display));
+
+ display = gcr_certificate_get_issuer_cn (self);
+ _gcr_certificate_section_new_field_take_value (section, _("Verified by"), g_steal_pointer (&display));
+
+ datetime = gcr_certificate_get_expiry_date (self);
+ if (datetime) {
+ display = g_date_time_format (datetime, "%x");
+ if (display)
+ _gcr_certificate_section_new_field_take_value (section, _("Expires"), g_steal_pointer
(&display));
+
+ g_clear_pointer (&datetime, g_date_time_unref);
+ }
+
+ list = g_list_prepend (list, g_steal_pointer (§ion));
+
+ /* The subject */
+ section = _gcr_certificate_section_new (_("Subject Name"), FALSE);
+ egg_dn_parse (egg_asn1x_node (info->asn1, "tbsCertificate", "subject", "rdnSequence", NULL),
on_parsed_dn_part, section);
+
+ list = g_list_prepend (list, g_steal_pointer (§ion));
+
+ /* The Issuer */
+ section = _gcr_certificate_section_new (_("Issuer Name"), FALSE);
+ egg_dn_parse (egg_asn1x_node (info->asn1, "tbsCertificate", "issuer", "rdnSequence", NULL),
on_parsed_dn_part, section);
+
+ list = g_list_prepend (list, g_steal_pointer (§ion));
+
+ /* The Issued Parameters */
+ section = _gcr_certificate_section_new (_("Issued Certificate"), FALSE);
+
+ if (!egg_asn1x_get_integer_as_ulong (egg_asn1x_node (info->asn1, "tbsCertificate", "version", NULL),
&version)) {
+ g_critical ("Unable to parse certificate version");
+ } else {
+ display = g_strdup_printf ("%lu", version + 1);
+ _gcr_certificate_section_new_field_take_value (section, _("Version"), g_steal_pointer
(&display));
+ }
+
+ number = egg_asn1x_get_integer_as_raw (egg_asn1x_node (info->asn1, "tbsCertificate", "serialNumber",
NULL));
+ if (!number) {
+ g_critical ("Unable to parse certificate serial number");
+ } else {
+ _gcr_certificate_section_new_field_take_bytes (section, _("Serial Number"), g_steal_pointer
(&number));
+ }
+
+ datetime = gcr_certificate_get_issued_date (self);
+ if (datetime) {
+ display = g_date_time_format (datetime, "%x");
+ if (display)
+ _gcr_certificate_section_new_field_take_value (section, _("Not Valid Before"),
g_steal_pointer (&display));
+
+ g_clear_pointer (&datetime, g_date_time_unref);
+ }
+
+ datetime = gcr_certificate_get_expiry_date (self);
+ if (datetime) {
+ display = g_date_time_format (datetime, "%x");
+ if (display)
+ _gcr_certificate_section_new_field_take_value (section, _("Not Valid After"),
g_steal_pointer (&display));
+
+ g_clear_pointer (&datetime, g_date_time_unref);
+ }
+
+ list = g_list_prepend (list, g_steal_pointer (§ion));
+
+ /* Fingerprints */
+ bytes = g_bytes_new_static (info->der, info->n_der);
+ section = _gcr_certificate_section_new (_("Certificate Fingerprints"), FALSE);
+ display = g_compute_checksum_for_bytes (G_CHECKSUM_SHA1, bytes);
+ _gcr_certificate_section_new_field_take_value (section, "SHA1", g_steal_pointer (&display));
+ display = g_compute_checksum_for_bytes (G_CHECKSUM_MD5, bytes);
+ _gcr_certificate_section_new_field_take_value (section, "MD5", g_steal_pointer (&display));
+ g_clear_pointer (&bytes, g_bytes_unref);
+
+ list = g_list_prepend (list, g_steal_pointer (§ion));
+
+ /* Public Key Info */
+ section = _gcr_certificate_section_new (_("Public Key Info"), FALSE);
+ subject_public_key = egg_asn1x_node (info->asn1, "tbsCertificate", "subjectPublicKeyInfo", NULL);
+ append_subject_public_key (self, section, subject_public_key);
+
+ list = g_list_prepend (list, g_steal_pointer (§ion));
+
+ /* Extensions */
+ for (guint extension_num = 1; TRUE; ++extension_num) {
+ GNode *extension = egg_asn1x_node (info->asn1, "tbsCertificate", "extensions", extension_num,
NULL);
+ if (extension == NULL)
+ break;
+ section = append_extension (self, extension);
+ if (section)
+ list = g_list_prepend (list, g_steal_pointer (§ion));
+ }
+
+ /* Signature */
+ section = _gcr_certificate_section_new (_("Signature"), FALSE);
+
+ oid = egg_asn1x_get_oid_as_quark (egg_asn1x_node (info->asn1, "signatureAlgorithm", "algorithm",
NULL));
+ _gcr_certificate_section_new_field (section, _("Signature Algorithm"), egg_oid_get_description (oid));
+
+ bytes = egg_asn1x_get_element_raw (egg_asn1x_node (info->asn1, "signatureAlgorithm", "parameters",
NULL));
+ if (bytes) {
+ _gcr_certificate_section_new_field_take_bytes (section, _("Signature Parameters"),
g_steal_pointer (&bytes));
+ }
+
+ bytes = egg_asn1x_get_bits_as_raw (egg_asn1x_node (info->asn1, "signature", NULL), &bits);
+ _gcr_certificate_section_new_field_take_bytes (section, _("Signature"), g_steal_pointer (&bytes));
+
+ list = g_list_prepend (list, g_steal_pointer (§ion));
+
+ return g_list_reverse (list);
+}
+
/* -----------------------------------------------------------------------------
* MIXIN
*/
diff --git a/gcr/gcr-certificate.h b/gcr/gcr-certificate.h
index f0df3726..a764d124 100644
--- a/gcr/gcr-certificate.h
+++ b/gcr/gcr-certificate.h
@@ -120,6 +120,8 @@ gboolean gcr_certificate_get_basic_constraints (GcrCertificate *self
gboolean *is_ca,
gint *path_len);
+GList* gcr_certificate_get_interface_elements (GcrCertificate *self);
+
void gcr_certificate_mixin_emit_notify (GcrCertificate *self);
void gcr_certificate_mixin_class_init (GObjectClass *object_class);
diff --git a/gcr/gcr.h b/gcr/gcr.h
index 17b4da02..b9705a8c 100644
--- a/gcr/gcr.h
+++ b/gcr/gcr.h
@@ -34,7 +34,9 @@
#include <gcr/gcr-certificate.h>
#include <gcr/gcr-certificate-chain.h>
+#include <gcr/gcr-certificate-field.h>
#include <gcr/gcr-certificate-request.h>
+#include <gcr/gcr-certificate-section.h>
#include <gcr/gcr-enum-types.h>
#include <gcr/gcr-fingerprint.h>
#include <gcr/gcr-importer.h>
diff --git a/gcr/meson.build b/gcr/meson.build
index 6a1dd747..e67606e9 100644
--- a/gcr/meson.build
+++ b/gcr/meson.build
@@ -4,7 +4,9 @@ gcr_headers_install_dir = gcr_headers_subdir / 'gcr'
gcr_public_sources = files(
'gcr-certificate.c',
'gcr-certificate-chain.c',
+ 'gcr-certificate-field.c',
'gcr-certificate-request.c',
+ 'gcr-certificate-section.c',
'gcr-fingerprint.c',
'gcr-importer.c',
'gcr-import-interaction.c',
@@ -43,7 +45,9 @@ gcr_headers = files(
'gcr.h',
'gcr-certificate.h',
'gcr-certificate-chain.h',
+ 'gcr-certificate-field.h',
'gcr-certificate-request.h',
+ 'gcr-certificate-section.h',
'gcr-fingerprint.h',
'gcr-importer.h',
'gcr-import-interaction.h',
diff --git a/gcr/test-certificate.c b/gcr/test-certificate.c
index 8bca0343..cdaafe81 100644
--- a/gcr/test-certificate.c
+++ b/gcr/test-certificate.c
@@ -266,6 +266,38 @@ test_basic_constraints (Test *test,
g_assert (path_len == -1);
}
+
+static void
+test_interface_elements (Test *test,
+ gconstpointer unused)
+{
+ GList* sections = gcr_certificate_get_interface_elements (test->dsa_cert);
+ for (GList *l = sections; l != NULL; l = l->next) {
+ GcrCertificateSection *section = l->data;
+ GListModel *fields;
+
+ gcr_certificate_section_get_flags (section);
+ g_assert (gcr_certificate_section_get_label (section) != NULL);
+ fields = gcr_certificate_section_get_fields (section);
+ g_assert (fields != NULL);
+ g_assert (g_list_model_get_item_type (fields) == GCR_TYPE_CERTIFICATE_FIELD);
+ for (guint i = 0; i < g_list_model_get_n_items (fields); i++) {
+ GValue val = G_VALUE_INIT;
+ GType value_type;
+ GcrCertificateField *field = g_list_model_get_item (fields, i);
+ g_assert (gcr_certificate_field_get_label (field) != NULL);
+ value_type = gcr_certificate_field_get_value_type (field);
+ g_value_init (&val, value_type);
+ g_assert (gcr_certificate_field_get_value (field, &val));
+ g_value_unset (&val);
+ g_assert (gcr_certificate_field_get_section (field) == section);
+ g_object_unref (field);
+ }
+ }
+
+ g_list_free_full (sections, (GDestroyNotify) g_object_unref);
+}
+
static void
test_subject_alt_name (void)
{
@@ -346,6 +378,7 @@ main (int argc, char **argv)
g_test_add ("/gcr/certificate/key_size", Test, NULL, setup, test_certificate_key_size, teardown);
g_test_add ("/gcr/certificate/is_issuer", Test, NULL, setup, test_certificate_is_issuer, teardown);
g_test_add ("/gcr/certificate/basic_constraints", Test, NULL, setup, test_basic_constraints,
teardown);
+ g_test_add ("/gcr/certificate/interface_elements", Test, NULL, setup, test_interface_elements,
teardown);
g_test_add_func ("/gcr/certificate/subject_alt_name", test_subject_alt_name);
g_test_add_func ("/gcr/certificate/key_usage", test_key_usage);
diff --git a/meson.build b/meson.build
index 1c6db2aa..f66d0cc2 100644
--- a/meson.build
+++ b/meson.build
@@ -41,7 +41,7 @@ gcr_gtk3_basename = 'gcr-@0@-gtk3'.format(gcr_api_version)
gcr_gtk4_basename = 'gcr-@0@-gtk4'.format(gcr_api_version)
# Dependencies
-min_glib_version = '2.64'
+min_glib_version = '2.68'
glib_dep = dependency('glib-2.0', version: '>=' + min_glib_version)
gmodule_dep = dependency('gmodule-no-export-2.0', version: '>=' + min_glib_version)
gthread_dep = dependency('gthread-2.0', version: '>=' + min_glib_version)
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]