/* * Copyright (C) 2010 Stefan Walter * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this program; if not, see . */ #include "config.h" #include "gcr/gcr-certificate.h" #include "gcr/gcr-certificate-extensions.h" #include "gcr/gcr-fingerprint.h" #include "gcr/gcr-icons.h" #include "gcr/gcr-oids.h" #include "gcr/gcr-simple-certificate.h" #include "gcr-certificate-exporter.h" #include "gcr-certificate-renderer.h" #include "gcr-certificate-renderer-private.h" #include "gcr-deprecated.h" #include "gcr-display-view.h" #include "gcr-renderer.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" #include "gck/gck.h" #include #include /** * GcrCertificateRenderer: * * An implementation of #GcrRenderer which renders certificates. */ /** * GcrCertificateRendererClass: * @parent_class: The parent class. * * The class for #GcrCertificateRenderer. */ enum { PROP_0, PROP_CERTIFICATE, PROP_LABEL, PROP_ATTRIBUTES }; struct _GcrCertificateRendererPrivate { GcrCertificate *opt_cert; GckAttributes *opt_attrs; guint key_size; gchar *label; }; static void gcr_renderer_iface_init (GcrRendererIface *iface); static void gcr_renderer_certificate_iface_init (GcrCertificateIface *iface); G_DEFINE_TYPE_WITH_CODE (GcrCertificateRenderer, gcr_certificate_renderer, G_TYPE_OBJECT, G_IMPLEMENT_INTERFACE (GCR_TYPE_RENDERER, gcr_renderer_iface_init); GCR_CERTIFICATE_MIXIN_IMPLEMENT_COMPARABLE (); G_IMPLEMENT_INTERFACE (GCR_TYPE_CERTIFICATE, gcr_renderer_certificate_iface_init); ); /* ----------------------------------------------------------------------------- * INTERNAL */ static gchar* calculate_label (GcrCertificateRenderer *self) { gchar *label; if (self->pv->label) return g_strdup (self->pv->label); if (self->pv->opt_attrs) { if (gck_attributes_find_string (self->pv->opt_attrs, CKA_LABEL, &label)) return label; } label = gcr_certificate_get_subject_cn (GCR_CERTIFICATE (self)); if (label != NULL) return label; return g_strdup (_("Certificate")); } static gboolean append_extension_basic_constraints (GcrRenderer *renderer, GcrDisplayView *view, GBytes *data) { gboolean is_ca = FALSE; gint path_len = -1; gchar *number; if (!_gcr_certificate_extension_basic_constraints (data, &is_ca, &path_len)) return FALSE; _gcr_display_view_append_heading (view, renderer, _("Basic Constraints")); _gcr_display_view_append_value (view, renderer, _("Certificate Authority"), is_ca ? _("Yes") : _("No"), FALSE); number = g_strdup_printf ("%d", path_len); _gcr_display_view_append_value (view, renderer, _("Max Path Length"), path_len < 0 ? _("Unlimited") : number, FALSE); g_free (number); return TRUE; } static gboolean append_extension_extended_key_usage (GcrRenderer *renderer, GcrDisplayView *view, GBytes *data) { GQuark *oids; GString *text; guint i; oids = _gcr_certificate_extension_extended_key_usage (data); if (oids == NULL) return FALSE; _gcr_display_view_append_heading (view, renderer, _("Extended Key Usage")); text = g_string_new (""); for (i = 0; oids[i] != 0; i++) { if (i > 0) g_string_append_unichar (text, GCR_DISPLAY_VIEW_LINE_BREAK); g_string_append (text, egg_oid_get_description (oids[i])); } g_free (oids); _gcr_display_view_append_value (view, renderer, _("Allowed Purposes"), text->str, FALSE); g_string_free (text, TRUE); return TRUE; } static gboolean append_extension_subject_key_identifier (GcrRenderer *renderer, GcrDisplayView *view, GBytes *data) { gpointer keyid; gsize n_keyid; keyid = _gcr_certificate_extension_subject_key_identifier (data, &n_keyid); if (keyid == NULL) return FALSE; _gcr_display_view_append_heading (view, renderer, _("Subject Key Identifier")); _gcr_display_view_append_hex (view, renderer, _("Key Identifier"), keyid, n_keyid); g_free (keyid); return TRUE; } static const struct { guint usage; const gchar *description; } usage_descriptions[] = { { GCR_KEY_USAGE_DIGITAL_SIGNATURE, N_("Digital signature") }, { 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") } }; static gboolean append_extension_key_usage (GcrRenderer *renderer, GcrDisplayView *view, GBytes *data) { gulong key_usage; GString *text; guint i; if (!_gcr_certificate_extension_key_usage (data, &key_usage)) return FALSE; 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, GCR_DISPLAY_VIEW_LINE_BREAK); g_string_append (text, _(usage_descriptions[i].description)); } } _gcr_display_view_append_heading (view, renderer, _("Key Usage")); _gcr_display_view_append_value (view, renderer, _("Usages"), text->str, FALSE); g_string_free (text, TRUE); return TRUE; } static gboolean append_extension_subject_alt_name (GcrRenderer *renderer, GcrDisplayView *view, GBytes *data) { GArray *general_names; GcrGeneralName *general; guint i; general_names = _gcr_certificate_extension_subject_alt_name (data); if (general_names == NULL) return FALSE; _gcr_display_view_append_heading (view, renderer, _("Subject Alternative Names")); for (i = 0; i < general_names->len; i++) { general = &g_array_index (general_names, GcrGeneralName, i); if (general->display == NULL) _gcr_display_view_append_hex (view, renderer, general->description, g_bytes_get_data (general->raw, NULL), g_bytes_get_size (general->raw)); else _gcr_display_view_append_value (view, renderer, general->description, general->display, FALSE); } _gcr_general_names_free (general_names); return TRUE; } static gboolean append_extension_hex (GcrRenderer *renderer, GcrDisplayView *view, GQuark oid, gconstpointer data, gsize n_data) { const gchar *text; _gcr_display_view_append_heading (view, renderer, _("Extension")); /* Extension type */ text = egg_oid_get_description (oid); _gcr_display_view_append_value (view, renderer, _("Identifier"), text, FALSE); _gcr_display_view_append_hex (view, renderer, _("Value"), data, n_data); return TRUE; } static void on_export_completed (GObject *source, GAsyncResult *result, gpointer user_data) { GtkWindow *parent = GTK_WINDOW (user_data); GcrCertificateExporter *exporter = GCR_CERTIFICATE_EXPORTER (source); GError *error = NULL; GtkWidget *dialog; if (!_gcr_certificate_exporter_export_finish (exporter, result, &error)) { if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) { dialog = gtk_message_dialog_new_with_markup (parent, GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, "%s\n\n%s", _("Couldn’t export the certificate."), error->message); gtk_widget_show (dialog); g_signal_connect (dialog, "delete-event", G_CALLBACK (gtk_widget_destroy), dialog); g_signal_connect_swapped(dialog, "response", G_CALLBACK (gtk_widget_destroy), dialog); } } /* Matches ref in on_certificate_export */ if (parent) g_object_unref (parent); } static void on_certificate_export (GtkMenuItem *menuitem, gpointer user_data) { GcrCertificateRenderer *self = GCR_CERTIFICATE_RENDERER (user_data); GcrCertificateExporter *exporter; gchar *label; GtkWidget *parent; label = calculate_label (self); parent = gtk_widget_get_toplevel (GTK_WIDGET (menuitem)); if (parent && !GTK_IS_WINDOW (parent)) parent = NULL; exporter = _gcr_certificate_exporter_new (GCR_CERTIFICATE (self), label, GTK_WINDOW (parent)); g_free (label); _gcr_certificate_exporter_export_async (exporter, NULL, on_export_completed, parent ? g_object_ref (parent) : NULL); } /* ----------------------------------------------------------------------------- * OBJECT */ static void gcr_certificate_renderer_init (GcrCertificateRenderer *self) { self->pv = (G_TYPE_INSTANCE_GET_PRIVATE (self, GCR_TYPE_CERTIFICATE_RENDERER, GcrCertificateRendererPrivate)); } static void gcr_certificate_renderer_dispose (GObject *obj) { GcrCertificateRenderer *self = GCR_CERTIFICATE_RENDERER (obj); if (self->pv->opt_cert) g_object_unref (self->pv->opt_cert); self->pv->opt_cert = NULL; G_OBJECT_CLASS (gcr_certificate_renderer_parent_class)->dispose (obj); } static void gcr_certificate_renderer_finalize (GObject *obj) { GcrCertificateRenderer *self = GCR_CERTIFICATE_RENDERER (obj); g_assert (!self->pv->opt_cert); if (self->pv->opt_attrs) gck_attributes_unref (self->pv->opt_attrs); self->pv->opt_attrs = NULL; g_free (self->pv->label); self->pv->label = NULL; G_OBJECT_CLASS (gcr_certificate_renderer_parent_class)->finalize (obj); } static void gcr_certificate_renderer_set_property (GObject *obj, guint prop_id, const GValue *value, GParamSpec *pspec) { GcrCertificateRenderer *self = GCR_CERTIFICATE_RENDERER (obj); switch (prop_id) { case PROP_CERTIFICATE: gcr_certificate_renderer_set_certificate (self, g_value_get_object (value)); break; case PROP_LABEL: g_free (self->pv->label); self->pv->label = g_value_dup_string (value); g_object_notify (obj, "label"); gcr_renderer_emit_data_changed (GCR_RENDERER (self)); break; case PROP_ATTRIBUTES: gck_attributes_unref (self->pv->opt_attrs); self->pv->opt_attrs = g_value_get_boxed (value); if (self->pv->opt_attrs) gck_attributes_ref (self->pv->opt_attrs); if (self->pv->opt_cert) { g_object_unref (self->pv->opt_cert); g_object_notify (G_OBJECT (self), "certificate"); self->pv->opt_cert = NULL; } gcr_renderer_emit_data_changed (GCR_RENDERER (self)); g_object_notify (G_OBJECT (self), "attributes"); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec); break; } } static void gcr_certificate_renderer_get_property (GObject *obj, guint prop_id, GValue *value, GParamSpec *pspec) { GcrCertificateRenderer *self = GCR_CERTIFICATE_RENDERER (obj); switch (prop_id) { case PROP_CERTIFICATE: g_value_set_object (value, self->pv->opt_cert); break; case PROP_LABEL: g_value_take_string (value, calculate_label (self)); break; case PROP_ATTRIBUTES: g_value_set_boxed (value, self->pv->opt_attrs); break; default: gcr_certificate_mixin_get_property (obj, prop_id, value, pspec); break; } } static void gcr_certificate_renderer_class_init (GcrCertificateRendererClass *klass) { GObjectClass *gobject_class = G_OBJECT_CLASS (klass); GckBuilder builder = GCK_BUILDER_INIT; gcr_certificate_renderer_parent_class = g_type_class_peek_parent (klass); g_type_class_add_private (klass, sizeof (GcrCertificateRendererPrivate)); gobject_class->dispose = gcr_certificate_renderer_dispose; gobject_class->finalize = gcr_certificate_renderer_finalize; gobject_class->set_property = gcr_certificate_renderer_set_property; gobject_class->get_property = gcr_certificate_renderer_get_property; /** * GcrCertificateRenderer:certificate: * * The certificate to display. May be %NULL. */ g_object_class_install_property (gobject_class, PROP_CERTIFICATE, g_param_spec_object ("certificate", "Certificate", "Certificate to display.", GCR_TYPE_CERTIFICATE, G_PARAM_READWRITE)); /** * GcrCertificateRenderer:attributes: * * The certificate attributes to display. One of the attributes must be * a CKA_VALUE type attribute which contains a DER encoded certificate. */ g_object_class_install_property (gobject_class, PROP_ATTRIBUTES, g_param_spec_boxed ("attributes", "Attributes", "Certificate pkcs11 attributes", GCK_TYPE_ATTRIBUTES, G_PARAM_READWRITE)); /** * GcrCertificateRenderer:label: * * The label to display. */ g_object_class_install_property (gobject_class, PROP_LABEL, g_param_spec_string ("label", "Label", "Certificate Label", "", G_PARAM_READWRITE)); gcr_certificate_mixin_class_init (gobject_class); /* Register this as a renderer which can be loaded */ gck_builder_add_ulong (&builder, CKA_CLASS, CKO_CERTIFICATE); gcr_renderer_register (GCR_TYPE_CERTIFICATE_RENDERER, gck_builder_end (&builder)); } static void gcr_certificate_renderer_render (GcrRenderer *renderer, GcrViewer *viewer) { GcrCertificateRenderer *self; GNode *extension; gconstpointer data; gsize n_data; GcrDisplayView *view; GcrCertificate *cert; GBytes *number; gulong version; guint bits, index; gchar *display; GBytes *bytes; GNode *asn; GDate date; GIcon *icon; self = GCR_CERTIFICATE_RENDERER (renderer); if (GCR_IS_DISPLAY_VIEW (viewer)) { view = GCR_DISPLAY_VIEW (viewer); } else { g_warning ("GcrCertificateRenderer only works with internal specific " "GcrViewer returned by gcr_viewer_new()."); return; } _gcr_display_view_begin (view, renderer); cert = GCR_CERTIFICATE (self); data = gcr_certificate_get_der_data (cert, &n_data); if (!data) { _gcr_display_view_end (view, renderer); return; } icon = gcr_certificate_get_icon (cert); _gcr_display_view_set_icon (view, GCR_RENDERER (self), icon); g_object_unref (icon); bytes = g_bytes_new_static (data, n_data); asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "Certificate", bytes); g_return_if_fail (asn != NULL); g_bytes_unref (bytes); display = calculate_label (self); _gcr_display_view_append_title (view, renderer, display); g_free (display); display = egg_dn_read_part (egg_asn1x_node (asn, "tbsCertificate", "subject", "rdnSequence", NULL), "CN"); _gcr_display_view_append_content (view, renderer, _("Identity"), display); g_free (display); display = egg_dn_read_part (egg_asn1x_node (asn, "tbsCertificate", "issuer", "rdnSequence", NULL), "CN"); _gcr_display_view_append_content (view, renderer, _("Verified by"), display); g_free (display); if (egg_asn1x_get_time_as_date (egg_asn1x_node (asn, "tbsCertificate", "validity", "notAfter", NULL), &date)) { display = g_malloc0 (128); if (!g_date_strftime (display, 128, "%x", &date)) g_return_if_reached (); _gcr_display_view_append_content (view, renderer, _("Expires"), display); g_free (display); } _gcr_display_view_start_details (view, renderer); /* The subject */ _gcr_display_view_append_heading (view, renderer, _("Subject Name")); _gcr_certificate_renderer_append_distinguished_name (renderer, view, egg_asn1x_node (asn, "tbsCertificate", "subject", "rdnSequence", NULL)); /* The Issuer */ _gcr_display_view_append_heading (view, renderer, _("Issuer Name")); _gcr_certificate_renderer_append_distinguished_name (renderer, view, egg_asn1x_node (asn, "tbsCertificate", "issuer", "rdnSequence", NULL)); /* The Issued Parameters */ _gcr_display_view_append_heading (view, renderer, _("Issued Certificate")); if (!egg_asn1x_get_integer_as_ulong (egg_asn1x_node (asn, "tbsCertificate", "version", NULL), &version)) g_return_if_reached (); display = g_strdup_printf ("%lu", version + 1); _gcr_display_view_append_value (view, renderer, _("Version"), display, FALSE); g_free (display); number = egg_asn1x_get_integer_as_raw (egg_asn1x_node (asn, "tbsCertificate", "serialNumber", NULL)); g_return_if_fail (number != NULL); _gcr_display_view_append_hex (view, renderer, _("Serial Number"), g_bytes_get_data (number, NULL), g_bytes_get_size (number)); g_bytes_unref (number); display = g_malloc0 (128); if (egg_asn1x_get_time_as_date (egg_asn1x_node (asn, "tbsCertificate", "validity", "notBefore", NULL), &date)) { if (!g_date_strftime (display, 128, "%Y-%m-%d", &date)) g_return_if_reached (); _gcr_display_view_append_value (view, renderer, _("Not Valid Before"), display, FALSE); } if (egg_asn1x_get_time_as_date (egg_asn1x_node (asn, "tbsCertificate", "validity", "notAfter", NULL), &date)) { if (!g_date_strftime (display, 128, "%Y-%m-%d", &date)) g_return_if_reached (); _gcr_display_view_append_value (view, renderer, _("Not Valid After"), display, FALSE); } g_free (display); /* Fingerprints */ _gcr_display_view_append_heading (view, renderer, _("Certificate Fingerprints")); _gcr_display_view_append_fingerprint (view, renderer, data, n_data, "SHA1", G_CHECKSUM_SHA1); _gcr_display_view_append_fingerprint (view, renderer, data, n_data, "MD5", G_CHECKSUM_MD5); /* Public Key Info */ _gcr_display_view_append_heading (view, renderer, _("Public Key Info")); bits = gcr_certificate_get_key_size (cert); _gcr_certificate_renderer_append_subject_public_key (renderer, view, bits, egg_asn1x_node (asn, "tbsCertificate", "subjectPublicKeyInfo", NULL)); /* Extensions */ for (index = 1; TRUE; ++index) { extension = egg_asn1x_node (asn, "tbsCertificate", "extensions", index, NULL); if (extension == NULL) break; _gcr_certificate_renderer_append_extension (renderer, view, extension); } /* Signature */ _gcr_display_view_append_heading (view, renderer, _("Signature")); _gcr_certificate_renderer_append_signature (renderer, view, asn); egg_asn1x_destroy (asn); _gcr_display_view_end (view, renderer); } static void gcr_certificate_renderer_populate_popup (GcrRenderer *self, GcrViewer *viewer, GtkMenu *menu) { GtkWidget *item; item = gtk_separator_menu_item_new (); gtk_widget_show (item); gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), item); item = gtk_menu_item_new_with_label (_("Export Certificate\xE2\x80\xA6")); gtk_widget_show (item); g_signal_connect_data (item, "activate", G_CALLBACK (on_certificate_export), g_object_ref (self), (GClosureNotify)g_object_unref, 0); gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), item); } static void gcr_renderer_iface_init (GcrRendererIface *iface) { iface->populate_popup = gcr_certificate_renderer_populate_popup; iface->render_view = gcr_certificate_renderer_render; } static const guchar * gcr_certificate_renderer_get_der_data (GcrCertificate *cert, gsize *n_data) { GcrCertificateRenderer *self = GCR_CERTIFICATE_RENDERER (cert); const GckAttribute *attr; g_assert (n_data); if (self->pv->opt_cert) return gcr_certificate_get_der_data (self->pv->opt_cert, n_data); if (self->pv->opt_attrs) { attr = gck_attributes_find (self->pv->opt_attrs, CKA_VALUE); g_return_val_if_fail (attr, NULL); *n_data = attr->length; return attr->value; } return NULL; } static void gcr_renderer_certificate_iface_init (GcrCertificateIface *iface) { iface->get_der_data = gcr_certificate_renderer_get_der_data; } /* ----------------------------------------------------------------------------- * PUBLIC */ /** * gcr_certificate_renderer_new: * @certificate: The certificate to display * * Create a new certificate renderer to display the certificate. * * Returns: (transfer full): a newly allocated #GcrCertificateRenderer, which * should be released with g_object_unref() */ GcrCertificateRenderer * gcr_certificate_renderer_new (GcrCertificate *certificate) { return g_object_new (GCR_TYPE_CERTIFICATE_RENDERER, "certificate", certificate, NULL); } /** * gcr_certificate_renderer_new_for_attributes: * @label: (allow-none): the label to display * @attrs: The attributes to display * * Create a new certificate renderer to display the label and attributes. One * of the attributes should be a CKA_VALUE type attribute containing a DER * encoded certificate. * * Returns: (transfer full): a newly allocated #GcrCertificateRenderer, which * should be released with g_object_unref() */ GcrCertificateRenderer * gcr_certificate_renderer_new_for_attributes (const gchar *label, struct _GckAttributes *attrs) { return g_object_new (GCR_TYPE_CERTIFICATE_RENDERER, "label", label, "attributes", attrs, NULL); } /** * gcr_certificate_renderer_get_certificate: * @self: The renderer * * Get the certificate displayed in the renderer. If no certificate was * explicitly set, then the renderer will return itself since it acts as * a valid certificate. * * Returns: (transfer none): The certificate, owned by the renderer. */ GcrCertificate * gcr_certificate_renderer_get_certificate (GcrCertificateRenderer *self) { g_return_val_if_fail (GCR_IS_CERTIFICATE_RENDERER (self), NULL); if (self->pv->opt_cert) return self->pv->opt_cert; return GCR_CERTIFICATE (self); } /** * gcr_certificate_renderer_set_certificate: * @self: The renderer * @certificate: (allow-none): the certificate to display * * Set a certificate to display in the renderer. */ void gcr_certificate_renderer_set_certificate (GcrCertificateRenderer *self, GcrCertificate *certificate) { g_return_if_fail (GCR_IS_CERTIFICATE_RENDERER (self)); if (self->pv->opt_cert) g_object_unref (self->pv->opt_cert); self->pv->opt_cert = certificate; if (self->pv->opt_cert) g_object_ref (self->pv->opt_cert); if (self->pv->opt_attrs) { gck_attributes_unref (self->pv->opt_attrs); self->pv->opt_attrs = NULL; } gcr_renderer_emit_data_changed (GCR_RENDERER (self)); g_object_notify (G_OBJECT (self), "certificate"); } /** * gcr_certificate_renderer_get_attributes: * @self: The renderer * * Get the PKCS\#11 attributes, if any, set for this renderer to display. * * Returns: (allow-none) (transfer none): the attributes, owned by the renderer * * Deprecated: 3.6: Use gcr_renderer_get_attributes() instead */ GckAttributes * gcr_certificate_renderer_get_attributes (GcrCertificateRenderer *self) { g_return_val_if_fail (GCR_IS_CERTIFICATE_RENDERER (self), NULL); return gcr_renderer_get_attributes (GCR_RENDERER (self)); } /** * gcr_certificate_renderer_set_attributes: * @self: The renderer * @attrs: (allow-none): attributes to set * * Set the PKCS\#11 attributes for this renderer to display. One of the attributes * should be a CKA_VALUE type attribute containing a DER encoded certificate. * * Deprecated: 3.6: Use gcr_renderer_set_attributes() instead */ void gcr_certificate_renderer_set_attributes (GcrCertificateRenderer *self, GckAttributes *attrs) { g_return_if_fail (GCR_IS_CERTIFICATE_RENDERER (self)); gcr_renderer_set_attributes (GCR_RENDERER (self), attrs); } typedef struct { GcrRenderer *renderer; GcrDisplayView *view; } AppendDnClosure; static void on_parsed_dn_part (guint index, GQuark oid, GNode *value, gpointer user_data) { GcrRenderer *renderer = ((AppendDnClosure *)user_data)->renderer; GcrDisplayView *view = ((AppendDnClosure *)user_data)->view; 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_display_view_append_value (view, renderer, field, display, FALSE); g_free (field); g_free (display); } void _gcr_certificate_renderer_append_distinguished_name (GcrRenderer *renderer, GcrDisplayView *view, GNode *dn) { AppendDnClosure closure; g_return_if_fail (GCR_IS_RENDERER (renderer)); g_return_if_fail (GCR_IS_DISPLAY_VIEW (view)); g_return_if_fail (dn != NULL); closure.renderer = renderer; closure.view = view; egg_dn_parse (dn, on_parsed_dn_part, &closure); } void _gcr_certificate_renderer_append_subject_public_key (GcrRenderer *renderer, GcrDisplayView *view, guint key_nbits, GNode *subject_public_key) { const gchar *text; gchar *display; GBytes *value; guchar *raw; gsize n_raw; GQuark oid; guint bits; oid = egg_asn1x_get_oid_as_quark (egg_asn1x_node (subject_public_key, "algorithm", "algorithm", NULL)); text = egg_oid_get_description (oid); _gcr_display_view_append_value (view, renderer, _("Key Algorithm"), text, FALSE); value = egg_asn1x_get_element_raw (egg_asn1x_node (subject_public_key, "algorithm", "parameters", NULL)); if (value) { _gcr_display_view_append_hex (view, renderer, _("Key Parameters"), g_bytes_get_data (value, NULL), g_bytes_get_size (value)); g_bytes_unref (value); } if (key_nbits > 0) { display = g_strdup_printf ("%u", key_nbits); _gcr_display_view_append_value (view, renderer, _("Key Size"), display, FALSE); g_free (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); _gcr_display_view_append_hex (view, renderer, _("Key SHA1 Fingerprint"), raw, n_raw); g_bytes_unref (value); g_free (raw); value = egg_asn1x_get_bits_as_raw (egg_asn1x_node (subject_public_key, "subjectPublicKey", NULL), &bits); _gcr_display_view_append_hex (view, renderer, _("Public Key"), g_bytes_get_data (value, NULL), bits / 8); g_bytes_unref (value); } void _gcr_certificate_renderer_append_signature (GcrRenderer *renderer, GcrDisplayView *view, GNode *asn) { const gchar *text; GBytes *value; GQuark oid; guint bits; oid = egg_asn1x_get_oid_as_quark (egg_asn1x_node (asn, "signatureAlgorithm", "algorithm", NULL)); text = egg_oid_get_description (oid); _gcr_display_view_append_value (view, renderer, _("Signature Algorithm"), text, FALSE); value = egg_asn1x_get_element_raw (egg_asn1x_node (asn, "signatureAlgorithm", "parameters", NULL)); if (value) { _gcr_display_view_append_hex (view, renderer, _("Signature Parameters"), g_bytes_get_data (value, NULL), g_bytes_get_size (value)); g_bytes_unref (value); } value = egg_asn1x_get_bits_as_raw (egg_asn1x_node (asn, "signature", NULL), &bits); _gcr_display_view_append_hex (view, renderer, _("Signature"), g_bytes_get_data (value, NULL), bits / 8); g_bytes_unref (value); } void _gcr_certificate_renderer_append_extension (GcrRenderer *renderer, GcrDisplayView *view, GNode *node) { GQuark oid; GBytes *value; gboolean critical; gboolean ret = FALSE; /* 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) ret = append_extension_basic_constraints (renderer, view, value); else if (oid == GCR_OID_EXTENDED_KEY_USAGE) ret = append_extension_extended_key_usage (renderer, view, value); else if (oid == GCR_OID_SUBJECT_KEY_IDENTIFIER) ret = append_extension_subject_key_identifier (renderer, view, value); else if (oid == GCR_OID_KEY_USAGE) ret = append_extension_key_usage (renderer, view, value); else if (oid == GCR_OID_SUBJECT_ALT_NAME) ret = append_extension_subject_alt_name (renderer, view, value); /* Otherwise the default raw display */ if (ret == FALSE) ret = append_extension_hex (renderer, view, oid, g_bytes_get_data (value, NULL), g_bytes_get_size (value)); /* Critical */ if (ret == TRUE && egg_asn1x_get_boolean (egg_asn1x_node (node, "critical", NULL), &critical)) { _gcr_display_view_append_value (view, renderer, _("Critical"), critical ? _("Yes") : _("No"), FALSE); } }