[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: Wed, 3 Aug 2022 18:52:47 +0000 (UTC)
commit 36eacc2dce9eb53093f9fd69e05ddc6912bc0354
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 | 171 +++++++-----
gcr-gtk3/gcr-section.h | 7 +-
gcr-gtk4/gcr-certificate-widget.c | 532 ++----------------------------------
gcr-gtk4/gcr-section.c | 170 +++++++-----
gcr-gtk4/gcr-section.h | 7 +-
gcr/gcr-certificate-field-private.h | 38 +++
gcr/gcr-certificate-field.c | 405 +++++++++++++++++++++++++++
gcr/gcr-certificate-field.h | 46 ++++
gcr/gcr-certificate.c | 452 ++++++++++++++++++++++++++++++
gcr/gcr-certificate.h | 2 +
gcr/gcr.h | 1 +
gcr/meson.build | 2 +
gcr/test-certificate.c | 31 +++
16 files changed, 1269 insertions(+), 1160 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..977ad3e2 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_important (section))
+ 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) gcr_certificate_section_unref);
}
diff --git a/gcr-gtk3/gcr-section.c b/gcr-gtk3/gcr-section.c
index bc6373ef..8bfd1d43 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,80 @@ 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, };
+GtkWidget *
+gcr_section_create_row (GObject *item,
+ gpointer user_data)
+{
+ GcrCertificateField *field = (GcrCertificateField *) item;
+ GtkSizeGroup *size_group = user_data;
+ GtkWidget *row, *box, *label, *value;
+
+ 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);
+ if (gcr_certificate_field_is_single(field)) {
+ g_object_set (G_OBJECT (value), "label", gcr_certificate_field_get_value (field), NULL);
+ } else {
+ char *val = g_strjoinv ("\n", gcr_certificate_field_get_values (field));
+ g_object_set (G_OBJECT (value), "label", val, NULL);
+ g_free (val);
+ }
+
+ if (gcr_certificate_field_is_bytes (field)) {
+ PangoAttrList *attributes;
+ 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_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_pointer (&self->section, gcr_certificate_section_unref);
G_OBJECT_CLASS (gcr_section_parent_class)->dispose (object);
}
@@ -47,10 +105,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_boxed (value, self->section);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -65,10 +122,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_boxed (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,12 +145,12 @@ 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,
- G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS);
+ obj_properties[PROP_SECTION] =
+ g_param_spec_boxed ("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,
N_PROPERTIES,
@@ -101,72 +163,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..27357a79 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_important (section))
+ 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) gcr_certificate_section_unref);
}
diff --git a/gcr-gtk4/gcr-section.c b/gcr-gtk4/gcr-section.c
index ecd8a9cc..c8e900e7 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,83 @@ 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, };
+GtkWidget *
+gcr_section_create_row (GObject *item,
+ gpointer user_data)
+{
+ GcrCertificateField *field = (GcrCertificateField *) item;
+ GtkSizeGroup *size_group = user_data;
+ GtkWidget *row, *box, *label, *value;
+
+ 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);
+ if (gcr_certificate_field_is_single(field)) {
+ g_object_set (G_OBJECT (value), "label", gcr_certificate_field_get_value (field), NULL);
+ } else {
+ char *val = g_strjoinv ("\n", gcr_certificate_field_get_values (field));
+ g_object_set (G_OBJECT (value), "label", val, NULL);
+ g_free (val);
+ }
+
+ if (gcr_certificate_field_is_bytes (field)) {
+ PangoAttrList *attributes;
+ 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_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_pointer (&self->section, gcr_certificate_section_unref);
G_OBJECT_CLASS (gcr_section_parent_class)->dispose (object);
}
@@ -49,8 +110,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_boxed (value, self->section);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -67,8 +128,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_boxed (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,12 +151,12 @@ 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,
- G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS);
+ obj_properties[PROP_SECTION] =
+ g_param_spec_boxed ("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,
N_PROPERTIES,
@@ -106,76 +173,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..3434ab1c
--- /dev/null
+++ b/gcr/gcr-certificate-field-private.h
@@ -0,0 +1,38 @@
+/*
+ * 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,
+ const char *label,
+ const char *value,
+ gboolean is_bytes);
+void _gcr_certificate_section_append_field_take_value (GcrCertificateSection *section,
+ const char *label,
+ char *value,
+ gboolean is_bytes);
+void _gcr_certificate_section_append_field_take_values (GcrCertificateSection *section,
+ const char *label,
+ GStrv value,
+ gboolean is_bytes);
+
+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..674fdc65
--- /dev/null
+++ b/gcr/gcr-certificate-field.c
@@ -0,0 +1,405 @@
+/*
+ * 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"
+
+struct _GcrCertificateSection {
+ gatomicrefcount ref_count;
+
+ char *label;
+ gboolean important;
+ GListStore *fields;
+};
+
+G_DEFINE_BOXED_TYPE (GcrCertificateSection, gcr_certificate_section, gcr_certificate_section_ref,
gcr_certificate_section_unref)
+
+struct _GcrCertificateField
+{
+ GObject parent_instance;
+
+ char *label;
+ union {
+ char *value;
+ GStrv values;
+ };
+ gboolean is_bytes : 1;
+ gboolean is_single : 1;
+ GcrCertificateSection *section;
+};
+
+G_DEFINE_FINAL_TYPE (GcrCertificateField, gcr_certificate_field, G_TYPE_OBJECT)
+
+enum {
+ PROP_LABEL = 1,
+ PROP_VALUE,
+ PROP_VALUES,
+ PROP_IS_BYTES,
+ PROP_IS_SINGLE,
+ 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);
+ if (self->is_single)
+ g_clear_pointer (&self->value, g_free);
+ else
+ g_clear_pointer (&self->values, g_strfreev);
+
+ 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_string (value, self->value);
+ break;
+ case PROP_VALUES:
+ g_value_set_boxed (value, self->values);
+ break;
+ case PROP_IS_BYTES:
+ g_value_set_boolean (value, self->is_bytes);
+ break;
+ case PROP_IS_SINGLE:
+ g_value_set_boolean (value, self->is_single);
+ break;
+ case PROP_SECTION:
+ g_value_set_boxed (value, self->section);
+ 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;
+
+ obj_properties[PROP_LABEL] =
+ g_param_spec_string ("label",
+ "Label",
+ "Display name of the field.",
+ NULL,
+ G_PARAM_STATIC_STRINGS | G_PARAM_READABLE);
+
+ obj_properties[PROP_VALUE] =
+ g_param_spec_string ("value",
+ "Value",
+ "Display name of the value.",
+ NULL,
+ G_PARAM_STATIC_STRINGS | G_PARAM_READABLE);
+
+ obj_properties[PROP_VALUES] =
+ g_param_spec_boxed ("values",
+ "Values",
+ "Display name of the values.",
+ G_TYPE_STRV,
+ G_PARAM_STATIC_STRINGS | G_PARAM_READABLE);
+
+ obj_properties[PROP_IS_BYTES] =
+ g_param_spec_boolean ("is-bytes",
+ "Is Bytes",
+ "Whether the value is representing bytes.",
+ FALSE,
+ G_PARAM_STATIC_STRINGS | G_PARAM_READABLE);
+
+ obj_properties[PROP_IS_SINGLE] =
+ g_param_spec_boolean ("is-single",
+ "Is Single",
+ "Whether the value is a single value or an array",
+ TRUE,
+ G_PARAM_STATIC_STRINGS | G_PARAM_READABLE);
+
+ obj_properties[PROP_SECTION] =
+ g_param_spec_boxed ("section",
+ "Section",
+ "The section it is included.",
+ GCR_TYPE_CERTIFICATE_SECTION,
+ G_PARAM_STATIC_STRINGS | G_PARAM_READABLE);
+
+ g_object_class_install_properties (object_class,
+ N_PROPERTIES,
+ obj_properties);
+}
+
+static void
+gcr_certificate_field_init (GcrCertificateField *self)
+{
+}
+
+/**
+ * _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)
+{
+ GcrCertificateSection *self = g_new(GcrCertificateSection, 1);
+ g_atomic_ref_count_init (&self->ref_count);
+ self->fields = g_list_store_new (GCR_TYPE_CERTIFICATE_FIELD);
+ self->label = g_strdup (label);
+ self->important = important;
+
+ return self;
+}
+
+GcrCertificateSection *
+gcr_certificate_section_ref (GcrCertificateSection *self)
+{
+ g_return_val_if_fail (self != NULL, NULL);
+
+ g_atomic_ref_count_inc (&self->ref_count);
+
+ return self;
+}
+
+void
+gcr_certificate_section_unref (GcrCertificateSection *self)
+{
+ g_return_if_fail (self != NULL);
+
+ if (g_atomic_ref_count_dec (&self->ref_count)) {
+ g_clear_pointer (&self->label, g_free);
+ g_clear_object (&self->fields);
+ g_free (self);
+ }
+}
+
+/**
+ * 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_important:
+ * @self: the #GcrCertificateSection
+ *
+ * Get whether this section should be visible by default.
+ *
+ * Returns: whether this section should be visible by default
+ */
+gboolean
+gcr_certificate_section_get_important (GcrCertificateSection *self)
+{
+ g_return_val_if_fail (self != NULL, FALSE);
+
+ return self->important;
+}
+
+/**
+ * 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);
+}
+
+/**
+ * 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
+ *
+ * Get the value of the field.
+ *
+ * It is a programming mistake to call this on non single field.
+ *
+ * Returns: the value of the field
+ */
+const char *
+gcr_certificate_field_get_value (GcrCertificateField *self)
+{
+ g_return_val_if_fail (GCR_IS_CERTIFICATE_FIELD (self), NULL);
+ g_return_val_if_fail (self->is_single, NULL);
+
+ return self->value;
+}
+
+/**
+ * gcr_certificate_field_get_values:
+ * @self: the #GcrCertificateField
+ *
+ * Get the values of the field.
+ *
+ * It is a programming mistake to call this on single field.
+ *
+ * Returns: (transfer none): the values of the field
+ */
+const GStrv
+gcr_certificate_field_get_values (GcrCertificateField *self)
+{
+ g_return_val_if_fail (GCR_IS_CERTIFICATE_FIELD (self), NULL);
+ g_return_val_if_fail (!self->is_single, NULL);
+
+ return self->values;
+}
+
+/**
+ * gcr_certificate_field_is_bytes:
+ * @self: the #GcrCertificateField
+ *
+ * Get whether the value is representing a byte sequence.
+ *
+ * Returns: %TRUE if this is representing bytes, %FALSE otherwise
+ */
+gboolean
+gcr_certificate_field_is_bytes (GcrCertificateField *self)
+{
+ g_return_val_if_fail (GCR_IS_CERTIFICATE_FIELD (self), FALSE);
+
+ return self->is_bytes;
+}
+
+/**
+ * gcr_certificate_field_is_single:
+ * @self: the #GcrCertificateField
+ *
+ * Get whether the value is a single value.
+ *
+ * Returns: %TRUE if the value is single, %FALSE otherwise
+ */
+gboolean
+gcr_certificate_field_is_single (GcrCertificateField *self)
+{
+ g_return_val_if_fail (GCR_IS_CERTIFICATE_FIELD (self), FALSE);
+
+ return self->is_single;
+}
+
+/**
+ * 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;
+}
+
+void
+_gcr_certificate_section_append_field (GcrCertificateSection *section,
+ const char *label,
+ const char *value,
+ gboolean is_bytes)
+{
+ g_return_if_fail (section != NULL);
+ g_return_if_fail (label != NULL);
+ g_return_if_fail (value != NULL);
+
+ _gcr_certificate_section_append_field_take_value (section, label, g_strdup (value), is_bytes);
+}
+
+void
+_gcr_certificate_section_append_field_take_value (GcrCertificateSection *section,
+ const char *label,
+ char *value,
+ gboolean is_bytes)
+{
+ GcrCertificateField *self;
+
+ g_return_if_fail (section != NULL);
+ g_return_if_fail (label != NULL);
+ g_return_if_fail (value != NULL);
+
+ self = g_object_new (GCR_TYPE_CERTIFICATE_FIELD, NULL);
+ self->section = section;
+ self->label = g_strdup (label);
+ self->value = value;
+ self->is_bytes = is_bytes;
+ self->is_single = TRUE;
+ g_list_store_append (section->fields, self);
+
+ g_object_unref (self);
+}
+
+void
+_gcr_certificate_section_append_field_take_values (GcrCertificateSection *section,
+ const char *label,
+ GStrv values,
+ gboolean is_bytes)
+{
+ GcrCertificateField *self;
+
+ g_return_if_fail (section != NULL);
+ g_return_if_fail (label != NULL);
+ g_return_if_fail (values != NULL);
+
+ self = g_object_new (GCR_TYPE_CERTIFICATE_FIELD, NULL);
+ self->section = section;
+ self->label = g_strdup (label);
+ self->values = values;
+ self->is_bytes = is_bytes;
+ self->is_single = FALSE;
+ g_list_store_append (section->fields, self);
+
+ g_object_unref (self);
+}
diff --git a/gcr/gcr-certificate-field.h b/gcr/gcr-certificate-field.h
new file mode 100644
index 00000000..3bc2685b
--- /dev/null
+++ b/gcr/gcr-certificate-field.h
@@ -0,0 +1,46 @@
+/*
+ * 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 <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define GCR_TYPE_CERTIFICATE_SECTION (gcr_certificate_section_get_type ())
+
+typedef struct _GcrCertificateSection GcrCertificateSection;
+
+GType gcr_certificate_section_get_type (void) G_GNUC_CONST;
+GcrCertificateSection *gcr_certificate_section_ref (GcrCertificateSection *self);
+void gcr_certificate_section_unref (GcrCertificateSection *self);
+const char *gcr_certificate_section_get_label (GcrCertificateSection *self);
+gboolean gcr_certificate_section_get_important (GcrCertificateSection *self);
+GListModel *gcr_certificate_section_get_fields (GcrCertificateSection *self);
+
+#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);
+const char *gcr_certificate_field_get_value (GcrCertificateField *self);
+const GStrv gcr_certificate_field_get_values (GcrCertificateField *self);
+gboolean gcr_certificate_field_is_bytes (GcrCertificateField *self);
+gboolean gcr_certificate_field_is_single (GcrCertificateField *self);
+GcrCertificateSection *gcr_certificate_field_get_section (GcrCertificateField *self);
+
+G_DEFINE_AUTOPTR_CLEANUP_FUNC(GcrCertificateSection, gcr_certificate_section_unref)
+
+G_END_DECLS
+
+#endif /* __GCR_CERTIFICATE_FIELD_H__ */
diff --git a/gcr/gcr-certificate.c b/gcr/gcr-certificate.c
index fc2d9e09..3a21ed57 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,454 @@ 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_append_field (section, _("Key Algorithm"), text, FALSE);
+
+ value = egg_asn1x_get_element_raw (egg_asn1x_node (subject_public_key,
+ "algorithm", "parameters", NULL));
+ if (value) {
+ display = egg_hex_encode_bytes_full (value, TRUE, " ", 1);
+ _gcr_certificate_section_append_field_take_value (section,
+ _("Key Parameters"),
+ g_steal_pointer (&display),
+ TRUE);
+ }
+
+ g_clear_pointer (&value, g_bytes_unref);
+
+ if (key_nbits > 0) {
+ display = g_strdup_printf ("%u", key_nbits);
+ _gcr_certificate_section_append_field_take_value (section,
+ _("Key Size"),
+ g_steal_pointer (&display),
+ FALSE);
+ }
+
+ 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);
+ display = egg_hex_encode_full (raw, n_raw, TRUE, " ", 1);
+ g_clear_pointer (&raw, g_free);
+ _gcr_certificate_section_append_field_take_value (section,
+ _("Key SHA1 Fingerprint"),
+ g_steal_pointer (&display),
+ TRUE);
+
+ 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_certificate_section_append_field_take_value (section, _("Public Key"), g_steal_pointer
(&display), TRUE);
+ g_clear_pointer (&value, g_bytes_unref);
+}
+
+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_append_field (section, _("Certificate Authority"), is_ca ? _("Yes") :
_("No"), FALSE);
+
+ if (path_len < 0)
+ number = g_strdup (_("Unlimited"));
+ else
+ number = g_strdup_printf ("%d", path_len);
+
+ _gcr_certificate_section_append_field_take_value (section, _("Max Path Length"), g_steal_pointer
(&number), FALSE);
+
+ return section;
+}
+
+static GcrCertificateSection *
+append_extension_extended_key_usage (GBytes *data)
+{
+ GcrCertificateSection *section;
+ GQuark *oids;
+ GString *text;
+ guint i;
+
+ oids = _gcr_certificate_extension_extended_key_usage (data);
+ if (!oids)
+ 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_certificate_section_new (_("Extended Key Usage"), FALSE);
+ _gcr_certificate_section_append_field_take_value (section, _("Allowed Purposes"), g_string_free
(text, FALSE), FALSE);
+
+ 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_append_field_take_value (section, _("Key Identifier"), g_steal_pointer
(&display), FALSE);
+
+ 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;
+ char* values[G_N_ELEMENTS (usage_descriptions) + 1];
+ guint i, index = 0;
+
+ if (!_gcr_certificate_extension_key_usage (data, &key_usage))
+ return NULL;
+
+ for (i = 0; i < G_N_ELEMENTS (usage_descriptions); i++) {
+ if (key_usage & usage_descriptions[i].usage) {
+ values[index++] = _(usage_descriptions[i].description);
+ }
+ }
+
+ values[index] = NULL;
+ section = _gcr_certificate_section_new (_("Key Usage"), FALSE);
+ _gcr_certificate_section_append_field_take_values (section, _("Usages"), g_strdupv (values), FALSE);
+
+ 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_append_field_take_value (section, general->description,
g_steal_pointer (&display), FALSE);
+ } else
+ _gcr_certificate_section_append_field (section, general->description,
general->display, FALSE);
+ }
+
+ _gcr_general_names_free (general_names);
+
+ return section;
+}
+
+static GcrCertificateSection *
+append_extension_hex (GQuark oid,
+ GBytes *value)
+{
+ GcrCertificateSection *section;
+ const gchar *text;
+ gchar *display;
+
+ section = _gcr_certificate_section_new (_("Extension"), FALSE);
+
+ /* Extension type */
+ text = egg_oid_get_description (oid);
+ _gcr_certificate_section_append_field (section, _("Identifier"), g_strdup (text), FALSE);
+ display = egg_hex_encode_bytes_full (value, TRUE, " ", 1);
+ _gcr_certificate_section_append_field_take_value (section, _("Value"), g_steal_pointer (&display),
TRUE);
+
+ 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, value);
+ }
+
+ /* Critical */
+ if (section && egg_asn1x_get_boolean (egg_asn1x_node (node, "critical", NULL), &critical)) {
+ _gcr_certificate_section_append_field (section, _("Critical"), critical ? _("Yes") : _("No"),
FALSE);
+ }
+
+ g_bytes_unref (value);
+ 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_append_field_take_value (section, label, g_steal_pointer (&display), FALSE);
+ 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_append_field_take_value (section, _("Identity"), g_steal_pointer (&display),
FALSE);
+
+ display = gcr_certificate_get_issuer_cn (self);
+ _gcr_certificate_section_append_field_take_value (section, _("Verified by"), g_steal_pointer
(&display), FALSE);
+
+ datetime = gcr_certificate_get_expiry_date (self);
+ if (datetime) {
+ display = g_date_time_format (datetime, "%x");
+ if (display)
+ _gcr_certificate_section_append_field_take_value (section, _("Expires"),
g_steal_pointer (&display), FALSE);
+
+ 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_append_field_take_value (section, _("Version"), g_steal_pointer
(&display), FALSE);
+ }
+
+ 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 {
+ display = egg_hex_encode_bytes_full (number, TRUE, " ", 1);
+ _gcr_certificate_section_append_field_take_value (section, _("Serial Number"),
g_steal_pointer (&display), TRUE);
+ }
+
+ datetime = gcr_certificate_get_issued_date (self);
+ if (datetime) {
+ display = g_date_time_format (datetime, "%x");
+ if (display)
+ _gcr_certificate_section_append_field_take_value (section, _("Not Valid Before"),
g_steal_pointer (&display), FALSE);
+
+ 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_append_field_take_value (section, _("Not Valid After"),
g_steal_pointer (&display), FALSE);
+
+ 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_append_field_take_value (section, "SHA1", g_steal_pointer (&display), FALSE);
+ display = g_compute_checksum_for_bytes (G_CHECKSUM_MD5, bytes);
+ _gcr_certificate_section_append_field_take_value (section, "MD5", g_steal_pointer (&display), FALSE);
+ 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_append_field (section, _("Signature Algorithm"), egg_oid_get_description
(oid), FALSE);
+
+ bytes = egg_asn1x_get_element_raw (egg_asn1x_node (info->asn1, "signatureAlgorithm", "parameters",
NULL));
+ if (bytes) {
+ display = egg_hex_encode_bytes_full (bytes, TRUE, " ", 1);
+ _gcr_certificate_section_append_field_take_value (section, _("Signature Parameters"),
g_steal_pointer (&display), TRUE);
+ }
+
+ bytes = egg_asn1x_get_bits_as_raw (egg_asn1x_node (info->asn1, "signature", NULL), &bits);
+ display = egg_hex_encode_full (g_bytes_get_data (bytes, NULL), bits / 8, TRUE, " ", 1);
+ g_clear_pointer (&bytes, g_bytes_unref);
+ _gcr_certificate_section_append_field_take_value (section, _("Signature"), g_steal_pointer
(&display), TRUE);
+
+ 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..089e880d 100644
--- a/gcr/gcr.h
+++ b/gcr/gcr.h
@@ -34,6 +34,7 @@
#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-enum-types.h>
#include <gcr/gcr-fingerprint.h>
diff --git a/gcr/meson.build b/gcr/meson.build
index 6a1dd747..f3dd2851 100644
--- a/gcr/meson.build
+++ b/gcr/meson.build
@@ -4,6 +4,7 @@ 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-fingerprint.c',
'gcr-importer.c',
@@ -43,6 +44,7 @@ gcr_headers = files(
'gcr.h',
'gcr-certificate.h',
'gcr-certificate-chain.h',
+ 'gcr-certificate-field.h',
'gcr-certificate-request.h',
'gcr-fingerprint.h',
'gcr-importer.h',
diff --git a/gcr/test-certificate.c b/gcr/test-certificate.c
index 8bca0343..b94f1b7b 100644
--- a/gcr/test-certificate.c
+++ b/gcr/test-certificate.c
@@ -266,6 +266,36 @@ 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_important (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++) {
+ GcrCertificateField *field = g_list_model_get_item (fields, i);
+ g_assert (gcr_certificate_field_get_label (field) != NULL);
+ if (gcr_certificate_field_is_single (field))
+ g_assert (gcr_certificate_field_get_value (field) != NULL);
+ else
+ g_assert (gcr_certificate_field_get_values (field) != NULL);
+ gcr_certificate_field_is_bytes (field);
+ g_assert (gcr_certificate_field_get_section (field) == section);
+ }
+ }
+
+ g_list_free_full (sections, (GDestroyNotify) gcr_certificate_section_unref);
+}
+
static void
test_subject_alt_name (void)
{
@@ -346,6 +376,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);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]