/* * 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-fingerprint.h" #include "gcr/gcr-icons.h" #include "gcr/gcr-subject-public-key.h" #include "gcr-key-renderer.h" #include "gcr-display-view.h" #include "gcr-renderer.h" #include "gcr-viewer.h" #include "gck/gck.h" #include "egg/egg-asn1x.h" #include #include /** * GcrKeyRenderer: * * An implementation of #GcrRenderer which renders keys. */ /** * GcrKeyRendererClass: * @parent_class: The parent class. * * The class for #GcrKeyRenderer. */ enum { PROP_0, PROP_LABEL, PROP_ATTRIBUTES, PROP_OBJECT }; struct _GcrKeyRendererPrivate { guint key_size; gchar *label; GckAttributes *attributes; GckObject *object; GIcon *icon; gulong notify_sig; GBytes *spk; }; static void gcr_key_renderer_renderer_iface (GcrRendererIface *iface); G_DEFINE_TYPE_WITH_CODE (GcrKeyRenderer, gcr_key_renderer, G_TYPE_OBJECT, G_IMPLEMENT_INTERFACE (GCR_TYPE_RENDERER, gcr_key_renderer_renderer_iface)); /* ----------------------------------------------------------------------------- * INTERNAL */ static gchar* calculate_label (GcrKeyRenderer *self) { gchar *label; if (self->pv->label) return g_strdup (self->pv->label); if (self->pv->attributes) { if (gck_attributes_find_string (self->pv->attributes, CKA_LABEL, &label)) return label; } return g_strdup (_("Key")); } static GckAttributes * calculate_attrs (GcrKeyRenderer *self) { if (self->pv->attributes) return gck_attributes_ref (self->pv->attributes); if (GCK_IS_OBJECT_CACHE (self->pv->object)) return gck_object_cache_get_attributes (GCK_OBJECT_CACHE (self->pv->object)); return NULL; } static guchar * calculate_fingerprint (GcrKeyRenderer *self, GckAttributes *attrs, GChecksumType algorithm, gsize *n_fingerprint) { if (self->pv->spk) return gcr_fingerprint_from_subject_public_key_info (g_bytes_get_data (self->pv->spk, NULL), g_bytes_get_size (self->pv->spk), algorithm, n_fingerprint); return gcr_fingerprint_from_attributes (attrs, algorithm, n_fingerprint); } static void on_subject_public_key (GObject *source, GAsyncResult *result, gpointer user_data) { GcrKeyRenderer *self = GCR_KEY_RENDERER (user_data); GError *error = NULL; GNode *node; node = _gcr_subject_public_key_load_finish (result, &error); if (error != NULL) { g_message ("couldn't load key information: %s", error->message); g_clear_error (&error); } else { if (self->pv->spk) g_bytes_unref (self->pv->spk); self->pv->spk = NULL; self->pv->spk = egg_asn1x_encode (node, NULL); if (self->pv->spk == NULL) g_warning ("invalid subjectPublicKey loaded: %s", egg_asn1x_message (node)); egg_asn1x_destroy (node); gcr_renderer_emit_data_changed (GCR_RENDERER (self)); } g_object_unref (self); } static void update_subject_public_key (GcrKeyRenderer *self) { if (self->pv->spk) g_bytes_unref (self->pv->spk); self->pv->spk = NULL; if (!self->pv->object) return; _gcr_subject_public_key_load_async (self->pv->object, NULL, on_subject_public_key, g_object_ref (self)); } static void on_object_cache_attributes (GObject *obj, GParamSpec *spec, gpointer user_data) { GcrKeyRenderer *self = GCR_KEY_RENDERER (user_data); update_subject_public_key (self); gcr_renderer_emit_data_changed (GCR_RENDERER (self)); } static void gcr_key_renderer_init (GcrKeyRenderer *self) { self->pv = (G_TYPE_INSTANCE_GET_PRIVATE (self, GCR_TYPE_KEY_RENDERER, GcrKeyRendererPrivate)); self->pv->icon = g_themed_icon_new (GCR_ICON_KEY); } static void gcr_key_renderer_dispose (GObject *obj) { GcrKeyRenderer *self = GCR_KEY_RENDERER (obj); if (self->pv->spk) g_bytes_unref (self->pv->spk); self->pv->spk = NULL; if (self->pv->object && self->pv->notify_sig) { g_signal_handler_disconnect (self->pv->object, self->pv->notify_sig); self->pv->notify_sig = 0; } g_clear_object (&self->pv->object); G_OBJECT_CLASS (gcr_key_renderer_parent_class)->dispose (obj); } static void gcr_key_renderer_finalize (GObject *obj) { GcrKeyRenderer *self = GCR_KEY_RENDERER (obj); if (self->pv->attributes) gck_attributes_unref (self->pv->attributes); self->pv->attributes = NULL; g_free (self->pv->label); self->pv->label = NULL; if (self->pv->icon) g_object_unref (self->pv->icon); self->pv->icon = NULL; G_OBJECT_CLASS (gcr_key_renderer_parent_class)->finalize (obj); } static void gcr_key_renderer_set_property (GObject *obj, guint prop_id, const GValue *value, GParamSpec *pspec) { GcrKeyRenderer *self = GCR_KEY_RENDERER (obj); switch (prop_id) { 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->attributes); self->pv->attributes = g_value_dup_boxed (value); gcr_renderer_emit_data_changed (GCR_RENDERER (self)); break; case PROP_OBJECT: g_clear_object (&self->pv->object); self->pv->object = g_value_dup_object (value); if (self->pv->object) { gck_attributes_unref (self->pv->attributes); self->pv->attributes = NULL; } if (GCK_IS_OBJECT_CACHE (self->pv->object)) { self->pv->notify_sig = g_signal_connect (self->pv->object, "notify::attributes", G_CALLBACK (on_object_cache_attributes), self); on_object_cache_attributes (G_OBJECT (self->pv->object), NULL, self); } g_object_notify (obj, "attributes"); g_object_notify (obj, "object"); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec); break; } } static void gcr_key_renderer_get_property (GObject *obj, guint prop_id, GValue *value, GParamSpec *pspec) { GcrKeyRenderer *self = GCR_KEY_RENDERER (obj); switch (prop_id) { case PROP_LABEL: g_value_take_string (value, calculate_label (self)); break; case PROP_ATTRIBUTES: g_value_take_boxed (value, calculate_attrs (self)); break; case PROP_OBJECT: g_value_set_object (value, self->pv->object); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec); break; } } static void gcr_key_renderer_class_init (GcrKeyRendererClass *klass) { GObjectClass *gobject_class = G_OBJECT_CLASS (klass); GckBuilder builder = GCK_BUILDER_INIT; gcr_key_renderer_parent_class = g_type_class_peek_parent (klass); g_type_class_add_private (klass, sizeof (GcrKeyRendererPrivate)); gobject_class->dispose = gcr_key_renderer_dispose; gobject_class->finalize = gcr_key_renderer_finalize; gobject_class->set_property = gcr_key_renderer_set_property; gobject_class->get_property = gcr_key_renderer_get_property; g_object_class_override_property (gobject_class, PROP_LABEL, "label"); g_object_class_override_property (gobject_class, PROP_ATTRIBUTES, "attributes"); g_object_class_install_property (gobject_class, PROP_OBJECT, g_param_spec_object ("object", "Object", "Key Object", GCK_TYPE_OBJECT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); /* Register this as a view which can be loaded */ gck_builder_add_ulong (&builder, CKA_CLASS, CKO_PRIVATE_KEY); gcr_renderer_register (GCR_TYPE_KEY_RENDERER, gck_builder_end (&builder)); } static void gcr_key_renderer_real_render (GcrRenderer *renderer, GcrViewer *viewer) { GcrKeyRenderer *self; GcrDisplayView *view; const gchar *text = ""; GckAttributes *attrs; gpointer fingerprint; gsize n_fingerprint; gchar *display; gulong klass; gulong key_type; guint size; self = GCR_KEY_RENDERER (renderer); if (GCR_IS_DISPLAY_VIEW (viewer)) { view = GCR_DISPLAY_VIEW (viewer); } else { g_warning ("GcrKeyRenderer only works with internal specific " "GcrViewer returned by gcr_viewer_new()."); return; } _gcr_display_view_begin (view, renderer); attrs = calculate_attrs (self); if (attrs == NULL) { _gcr_display_view_end (view, renderer); return; } if (!gck_attributes_find_ulong (attrs, CKA_CLASS, &klass) || !gck_attributes_find_ulong (attrs, CKA_KEY_TYPE, &key_type)) { g_warning ("private key does not have the CKA_CLASS and CKA_KEY_TYPE attributes"); _gcr_display_view_end (view, renderer); gck_attributes_unref (attrs); return; } _gcr_display_view_set_icon (view, renderer, self->pv->icon); display = calculate_label (self); _gcr_display_view_append_title (view, renderer, display); g_free (display); if (klass == CKO_PRIVATE_KEY) { if (key_type == CKK_RSA) text = _("Private RSA Key"); else if (key_type == CKK_DSA) text = _("Private DSA Key"); else if (key_type == CKK_EC) text = _("Private Elliptic Curve Key"); else text = _("Private Key"); } else if (klass == CKO_PUBLIC_KEY) { if (key_type == CKK_RSA) text = _("Public DSA Key"); else if (key_type == CKK_DSA) text = _("Public DSA Key"); else if (key_type == CKK_EC) text = _("Public Elliptic Curve Key"); else text = _("Public Key"); } _gcr_display_view_append_content (view, renderer, text, NULL); size = _gcr_subject_public_key_attributes_size (attrs); if (size > 0) { display = g_strdup_printf (g_dngettext (GETTEXT_PACKAGE, "%u bit", "%u bits", size), size); _gcr_display_view_append_content (view, renderer, _("Strength"), display); g_free (display); } _gcr_display_view_start_details (view, renderer); if (key_type == CKK_RSA) text = _("RSA"); else if (key_type == CKK_DSA) text = _("DSA"); else if (key_type == CKK_EC) text = _("Elliptic Curve"); else text = _("Unknown"); _gcr_display_view_append_value (view, renderer, _("Algorithm"), text, FALSE); if (size == 0) display = g_strdup (_("Unknown")); else display = g_strdup_printf ("%u", size); _gcr_display_view_append_value (view, renderer, _("Size"), display, FALSE); g_free (display); /* Fingerprints */ _gcr_display_view_append_heading (view, renderer, _("Fingerprints")); fingerprint = calculate_fingerprint (self, attrs, G_CHECKSUM_SHA1, &n_fingerprint); if (fingerprint) { _gcr_display_view_append_hex (view, renderer, _("SHA1"), fingerprint, n_fingerprint); g_free (fingerprint); } fingerprint = calculate_fingerprint (self, attrs, G_CHECKSUM_SHA256, &n_fingerprint); if (fingerprint) { _gcr_display_view_append_hex (view, renderer, _("SHA256"), fingerprint, n_fingerprint); g_free (fingerprint); } _gcr_display_view_end (view, renderer); gck_attributes_unref (attrs); } static void gcr_key_renderer_renderer_iface (GcrRendererIface *iface) { iface->render_view = gcr_key_renderer_real_render; } /* ----------------------------------------------------------------------------- * PUBLIC */ /** * gcr_key_renderer_new: * @label: (allow-none): label describing the key * @attrs: (allow-none): key to display, or %NULL * * Create a new key renderer which renders a given key in the attributes. * * Returns: (transfer full): a newly allocated #GcrKeyRenderer, which should be * freed with g_object_unref() */ GcrKeyRenderer* gcr_key_renderer_new (const gchar *label, GckAttributes *attrs) { return g_object_new (GCR_TYPE_KEY_RENDERER, "label", label, "attributes", attrs, NULL); } /** * gcr_key_renderer_set_attributes: * @self: The key renderer * @attrs: (allow-none): the attributes to display * * Get the attributes displayed in the renderer. The attributes should represent * either an RSA, DSA, or EC key in PKCS\#11 style. */ void gcr_key_renderer_set_attributes (GcrKeyRenderer *self, GckAttributes *attrs) { g_return_if_fail (GCR_IS_KEY_RENDERER (self)); if (self->pv->attributes) gck_attributes_unref (self->pv->attributes); self->pv->attributes = attrs; if (self->pv->attributes) gck_attributes_ref (self->pv->attributes); g_object_notify (G_OBJECT (self), "attributes"); gcr_renderer_emit_data_changed (GCR_RENDERER (self)); } /** * gcr_key_renderer_get_attributes: * @self: The key renderer * * Get the attributes displayed in the renderer. * * Returns: (transfer none) (allow-none): the attributes, owned by the renderer */ GckAttributes* gcr_key_renderer_get_attributes (GcrKeyRenderer *self) { g_return_val_if_fail (GCR_IS_KEY_RENDERER (self), NULL); return self->pv->attributes; }