Use GBytes instead of our own EggBytes
[platform/upstream/gcr.git] / gcr / gcr-certificate-renderer.c
1 /*
2  * Copyright (C) 2010 Stefan Walter
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU Lesser General Public License as
6  * published by the Free Software Foundation; either version 2.1 of
7  * the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this program; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
17  * 02111-1307, USA.
18  */
19
20 #include "config.h"
21
22 #include "gcr-certificate.h"
23 #include "gcr-certificate-exporter.h"
24 #include "gcr-certificate-extensions.h"
25 #include "gcr-certificate-renderer.h"
26 #include "gcr-certificate-renderer-private.h"
27 #include "gcr-display-view.h"
28 #include "gcr-fingerprint.h"
29 #include "gcr-icons.h"
30 #include "gcr-oids.h"
31 #include "gcr-simple-certificate.h"
32 #include "gcr-renderer.h"
33
34 #include "egg/egg-asn1x.h"
35 #include "egg/egg-asn1-defs.h"
36 #include "egg/egg-dn.h"
37 #include "egg/egg-oid.h"
38 #include "egg/egg-hex.h"
39
40 #include "gck/gck.h"
41
42 #include <gdk/gdk.h>
43 #include <glib/gi18n-lib.h>
44
45 /**
46  * GcrCertificateRenderer:
47  *
48  * An implementation of #GcrRenderer which renders certificates.
49  */
50
51 /**
52  * GcrCertificateRendererClass:
53  * @parent_class: The parent class.
54  *
55  * The class for #GcrCertificateRenderer.
56  */
57
58 enum {
59         PROP_0,
60         PROP_CERTIFICATE,
61         PROP_LABEL,
62         PROP_ATTRIBUTES
63 };
64
65 struct _GcrCertificateRendererPrivate {
66         GcrCertificate *opt_cert;
67         GckAttributes *opt_attrs;
68         guint key_size;
69         gchar *label;
70 };
71
72 static void gcr_renderer_iface_init (GcrRendererIface *iface);
73 static void gcr_renderer_certificate_iface_init (GcrCertificateIface *iface);
74
75 G_DEFINE_TYPE_WITH_CODE (GcrCertificateRenderer, gcr_certificate_renderer, G_TYPE_OBJECT,
76         G_IMPLEMENT_INTERFACE (GCR_TYPE_RENDERER, gcr_renderer_iface_init);
77         GCR_CERTIFICATE_MIXIN_IMPLEMENT_COMPARABLE ();
78         G_IMPLEMENT_INTERFACE (GCR_TYPE_CERTIFICATE, gcr_renderer_certificate_iface_init);
79 );
80
81 /* -----------------------------------------------------------------------------
82  * INTERNAL
83  */
84
85 static gchar*
86 calculate_label (GcrCertificateRenderer *self)
87 {
88         gchar *label;
89
90         if (self->pv->label)
91                 return g_strdup (self->pv->label);
92
93         if (self->pv->opt_attrs) {
94                 if (gck_attributes_find_string (self->pv->opt_attrs, CKA_LABEL, &label))
95                         return label;
96         }
97
98         label = gcr_certificate_get_subject_cn (GCR_CERTIFICATE (self));
99         if (label != NULL)
100                 return label;
101
102         return g_strdup (_("Certificate"));
103 }
104
105 static gboolean
106 append_extension_basic_constraints (GcrRenderer *renderer,
107                                     GcrDisplayView *view,
108                                     GBytes *data)
109 {
110         gboolean is_ca = FALSE;
111         gint path_len = -1;
112         gchar *number;
113
114         if (!_gcr_certificate_extension_basic_constraints (data, &is_ca, &path_len))
115                 return FALSE;
116
117         _gcr_display_view_append_heading (view, renderer, _("Basic Constraints"));
118
119         _gcr_display_view_append_value (view, renderer, _("Certificate Authority"),
120                                         is_ca ? _("Yes") : _("No"), FALSE);
121
122         number = g_strdup_printf ("%d", path_len);
123         _gcr_display_view_append_value (view, renderer, _("Max Path Length"),
124                                         path_len < 0 ? _("Unlimited") : number, FALSE);
125         g_free (number);
126
127         return TRUE;
128 }
129
130 static gboolean
131 append_extension_extended_key_usage (GcrRenderer *renderer,
132                                      GcrDisplayView *view,
133                                      GBytes *data)
134 {
135         GQuark *oids;
136         GString *text;
137         guint i;
138
139         oids = _gcr_certificate_extension_extended_key_usage (data);
140         if (oids == NULL)
141                 return FALSE;
142
143         _gcr_display_view_append_heading (view, renderer, _("Extended Key Usage"));
144
145         text = g_string_new ("");
146         for (i = 0; oids[i] != 0; i++) {
147                 if (i > 0)
148                         g_string_append_unichar (text, GCR_DISPLAY_VIEW_LINE_BREAK);
149                 g_string_append (text, egg_oid_get_description (oids[i]));
150         }
151
152         g_free (oids);
153
154         _gcr_display_view_append_value (view, renderer, _("Allowed Purposes"),
155                                         text->str, FALSE);
156
157         g_string_free (text, TRUE);
158
159         return TRUE;
160 }
161
162 static gboolean
163 append_extension_subject_key_identifier (GcrRenderer *renderer,
164                                          GcrDisplayView *view,
165                                          GBytes *data)
166 {
167         gpointer keyid;
168         gsize n_keyid;
169
170         keyid = _gcr_certificate_extension_subject_key_identifier (data, &n_keyid);
171         if (keyid == NULL)
172                 return FALSE;
173
174         _gcr_display_view_append_heading (view, renderer, _("Subject Key Identifier"));
175         _gcr_display_view_append_hex (view, renderer, _("Key Identifier"), keyid, n_keyid);
176
177         g_free (keyid);
178
179         return TRUE;
180 }
181
182 static const struct {
183         guint usage;
184         const gchar *description;
185 } usage_descriptions[] = {
186         { GCR_KEY_USAGE_DIGITAL_SIGNATURE, N_("Digital signature") },
187         { GCR_KEY_USAGE_KEY_ENCIPHERMENT, N_("Key encipherment") },
188         { GCR_KEY_USAGE_DATA_ENCIPHERMENT, N_("Data encipherment") },
189         { GCR_KEY_USAGE_KEY_AGREEMENT, N_("Key agreement") },
190         { GCR_KEY_USAGE_KEY_CERT_SIGN, N_("Certificate signature") },
191         { GCR_KEY_USAGE_CRL_SIGN, N_("Revocation list signature") }
192 };
193
194 static gboolean
195 append_extension_key_usage (GcrRenderer *renderer,
196                             GcrDisplayView *view,
197                             GBytes *data)
198 {
199         gulong key_usage;
200         GString *text;
201         guint i;
202
203         if (!_gcr_certificate_extension_key_usage (data, &key_usage))
204                 return FALSE;
205
206         text = g_string_new ("");
207
208         for (i = 0; i < G_N_ELEMENTS (usage_descriptions); i++) {
209                 if (key_usage & usage_descriptions[i].usage) {
210                         if (text->len > 0)
211                                 g_string_append_unichar (text, GCR_DISPLAY_VIEW_LINE_BREAK);
212                         g_string_append (text, gettext (usage_descriptions[i].description));
213                 }
214         }
215
216         _gcr_display_view_append_heading (view, renderer, _("Key Usage"));
217         _gcr_display_view_append_value (view, renderer, _("Usages"), text->str, FALSE);
218
219         g_string_free (text, TRUE);
220
221         return TRUE;
222 }
223
224 static gboolean
225 append_extension_subject_alt_name (GcrRenderer *renderer,
226                                    GcrDisplayView *view,
227                                    GBytes *data)
228 {
229         GArray *general_names;
230         GcrGeneralName *general;
231         guint i;
232
233         general_names = _gcr_certificate_extension_subject_alt_name (data);
234         if (general_names == NULL)
235                 return FALSE;
236
237         _gcr_display_view_append_heading (view, renderer, _("Subject Alternative Names"));
238
239         for (i = 0; i < general_names->len; i++) {
240                 general = &g_array_index (general_names, GcrGeneralName, i);
241                 if (general->display == NULL)
242                         _gcr_display_view_append_hex (view, renderer, general->description,
243                                                       g_bytes_get_data (general->raw, NULL),
244                                                       g_bytes_get_size (general->raw));
245                 else
246                         _gcr_display_view_append_value (view, renderer, general->description,
247                                                         general->display, FALSE);
248         }
249
250         _gcr_general_names_free (general_names);
251
252         return TRUE;
253 }
254
255 static gboolean
256 append_extension_hex (GcrRenderer *renderer,
257                       GcrDisplayView *view,
258                       GQuark oid,
259                       gconstpointer data,
260                       gsize n_data)
261 {
262         const gchar *text;
263
264         _gcr_display_view_append_heading (view, renderer, _("Extension"));
265
266         /* Extension type */
267         text = egg_oid_get_description (oid);
268         _gcr_display_view_append_value (view, renderer, _("Identifier"), text, FALSE);
269         _gcr_display_view_append_hex (view, renderer, _("Value"), data, n_data);
270
271         return TRUE;
272 }
273
274 static gboolean
275 on_delete_unref_dialog (GtkWidget *widget, GdkEvent *event, gpointer data)
276 {
277         g_object_unref (widget);
278         return FALSE;
279 }
280
281 static void
282 on_export_completed (GObject *source, GAsyncResult *result, gpointer user_data)
283 {
284         GtkWindow *parent = GTK_WINDOW (user_data);
285         GcrCertificateExporter *exporter = GCR_CERTIFICATE_EXPORTER (source);
286         GError *error = NULL;
287         GtkWidget *dialog;
288
289         if (!_gcr_certificate_exporter_export_finish (exporter, result, &error)) {
290                 if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
291                         dialog = gtk_message_dialog_new_with_markup (parent,
292                                   GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR,
293                                   GTK_BUTTONS_OK, "<big>%s</big>\n\n%s",
294                                   _("Couldn't export the certificate."),
295                                   error->message);
296                         gtk_widget_show (dialog);
297                         g_signal_connect (dialog, "delete-event",
298                                           G_CALLBACK (on_delete_unref_dialog), NULL);
299                 }
300         }
301
302         /* Matches ref in on_certificate_export */
303         if (parent)
304                 g_object_unref (parent);
305 }
306
307 static void
308 on_certificate_export (GtkMenuItem *menuitem, gpointer user_data)
309 {
310         GcrCertificateRenderer *self = GCR_CERTIFICATE_RENDERER (user_data);
311         GcrCertificateExporter *exporter;
312         gchar *label;
313         GtkWidget *parent;
314
315         label = calculate_label (self);
316
317         parent = gtk_widget_get_toplevel (GTK_WIDGET (menuitem));
318         if (parent && !GTK_IS_WINDOW (parent))
319                 parent = NULL;
320
321         exporter = _gcr_certificate_exporter_new (GCR_CERTIFICATE (self), label,
322                                                   GTK_WINDOW (parent));
323
324         g_free (label);
325
326         _gcr_certificate_exporter_export_async (exporter, NULL, on_export_completed,
327                                                 parent ? g_object_ref (parent) : NULL);
328 }
329
330 /* -----------------------------------------------------------------------------
331  * OBJECT
332  */
333
334 static void
335 gcr_certificate_renderer_init (GcrCertificateRenderer *self)
336 {
337         self->pv = (G_TYPE_INSTANCE_GET_PRIVATE (self, GCR_TYPE_CERTIFICATE_RENDERER, GcrCertificateRendererPrivate));
338 }
339
340 static void
341 gcr_certificate_renderer_dispose (GObject *obj)
342 {
343         GcrCertificateRenderer *self = GCR_CERTIFICATE_RENDERER (obj);
344
345         if (self->pv->opt_cert)
346                 g_object_unref (self->pv->opt_cert);
347         self->pv->opt_cert = NULL;
348
349         G_OBJECT_CLASS (gcr_certificate_renderer_parent_class)->dispose (obj);
350 }
351
352 static void
353 gcr_certificate_renderer_finalize (GObject *obj)
354 {
355         GcrCertificateRenderer *self = GCR_CERTIFICATE_RENDERER (obj);
356
357         g_assert (!self->pv->opt_cert);
358
359         if (self->pv->opt_attrs)
360                 gck_attributes_unref (self->pv->opt_attrs);
361         self->pv->opt_attrs = NULL;
362
363         g_free (self->pv->label);
364         self->pv->label = NULL;
365
366         G_OBJECT_CLASS (gcr_certificate_renderer_parent_class)->finalize (obj);
367 }
368
369 static void
370 gcr_certificate_renderer_set_property (GObject *obj, guint prop_id, const GValue *value,
371                                      GParamSpec *pspec)
372 {
373         GcrCertificateRenderer *self = GCR_CERTIFICATE_RENDERER (obj);
374
375         switch (prop_id) {
376         case PROP_CERTIFICATE:
377                 gcr_certificate_renderer_set_certificate (self, g_value_get_object (value));
378                 break;
379         case PROP_LABEL:
380                 g_free (self->pv->label);
381                 self->pv->label = g_value_dup_string (value);
382                 g_object_notify (obj, "label");
383                 gcr_renderer_emit_data_changed (GCR_RENDERER (self));
384                 break;
385         case PROP_ATTRIBUTES:
386                 gcr_certificate_renderer_set_attributes (self, g_value_get_boxed (value));
387                 break;
388         default:
389                 G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
390                 break;
391         }
392 }
393
394 static void
395 gcr_certificate_renderer_get_property (GObject *obj, guint prop_id, GValue *value,
396                                      GParamSpec *pspec)
397 {
398         GcrCertificateRenderer *self = GCR_CERTIFICATE_RENDERER (obj);
399
400         switch (prop_id) {
401         case PROP_CERTIFICATE:
402                 g_value_set_object (value, self->pv->opt_cert);
403                 break;
404         case PROP_LABEL:
405                 g_value_take_string (value, calculate_label (self));
406                 break;
407         case PROP_ATTRIBUTES:
408                 g_value_set_boxed (value, self->pv->opt_attrs);
409                 break;
410         default:
411                 gcr_certificate_mixin_get_property (obj, prop_id, value, pspec);
412                 break;
413         }
414 }
415
416 static void
417 gcr_certificate_renderer_class_init (GcrCertificateRendererClass *klass)
418 {
419         GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
420         GckBuilder builder = GCK_BUILDER_INIT;
421
422         _gcr_oids_init ();
423
424         gcr_certificate_renderer_parent_class = g_type_class_peek_parent (klass);
425         g_type_class_add_private (klass, sizeof (GcrCertificateRendererPrivate));
426
427         gobject_class->dispose = gcr_certificate_renderer_dispose;
428         gobject_class->finalize = gcr_certificate_renderer_finalize;
429         gobject_class->set_property = gcr_certificate_renderer_set_property;
430         gobject_class->get_property = gcr_certificate_renderer_get_property;
431
432         /**
433          * GcrCertificateRenderer:certificate:
434          *
435          * The certificate to display. May be %NULL.
436          */
437         g_object_class_install_property (gobject_class, PROP_CERTIFICATE,
438                    g_param_spec_object ("certificate", "Certificate", "Certificate to display.",
439                                         GCR_TYPE_CERTIFICATE, G_PARAM_READWRITE));
440
441         /**
442          * GcrCertificateRenderer:attributes:
443          *
444          * The certificate attributes to display. One of the attributes must be
445          * a CKA_VALUE type attribute which contains a DER encoded certificate.
446          */
447         g_object_class_install_property (gobject_class, PROP_ATTRIBUTES,
448                    g_param_spec_boxed ("attributes", "Attributes", "Certificate pkcs11 attributes",
449                                        GCK_TYPE_ATTRIBUTES, G_PARAM_READWRITE));
450
451         /**
452          * GcrCertificateRenderer:label:
453          *
454          * The label to display.
455          */
456         g_object_class_install_property (gobject_class, PROP_LABEL,
457                    g_param_spec_string ("label", "Label", "Certificate Label",
458                                         "", G_PARAM_READWRITE));
459
460         gcr_certificate_mixin_class_init (gobject_class);
461
462         /* Register this as a renderer which can be loaded */
463         gck_builder_add_ulong (&builder, CKA_CLASS, CKO_CERTIFICATE);
464         gcr_renderer_register (GCR_TYPE_CERTIFICATE_RENDERER, gck_builder_end (&builder));
465 }
466
467 static void
468 gcr_certificate_renderer_render (GcrRenderer *renderer, GcrViewer *viewer)
469 {
470         GcrCertificateRenderer *self;
471         GNode *extension;
472         gconstpointer data;
473         gsize n_data;
474         GcrDisplayView *view;
475         GcrCertificate *cert;
476         GBytes *number;
477         gulong version;
478         guint bits, index;
479         gchar *display;
480         GBytes *bytes;
481         GNode *asn;
482         GDate date;
483         GIcon *icon;
484
485         self = GCR_CERTIFICATE_RENDERER (renderer);
486
487         if (GCR_IS_DISPLAY_VIEW (viewer)) {
488                 view = GCR_DISPLAY_VIEW (viewer);
489
490         } else {
491                 g_warning ("GcrCertificateRenderer only works with internal specific "
492                            "GcrViewer returned by gcr_viewer_new().");
493                 return;
494         }
495
496         _gcr_display_view_begin (view, renderer);
497         cert = GCR_CERTIFICATE (self);
498
499         data = gcr_certificate_get_der_data (cert, &n_data);
500         if (!data) {
501                 _gcr_display_view_end (view, renderer);
502                 return;
503         }
504
505         icon = gcr_certificate_get_icon (cert);
506         _gcr_display_view_set_icon (view, GCR_RENDERER (self), icon);
507         g_object_unref (icon);
508
509         bytes = g_bytes_new_static (data, n_data);
510         asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "Certificate", bytes);
511         g_return_if_fail (asn != NULL);
512         g_bytes_unref (bytes);
513
514         display = calculate_label (self);
515         _gcr_display_view_append_title (view, renderer, display);
516         g_free (display);
517
518         display = egg_dn_read_part (egg_asn1x_node (asn, "tbsCertificate", "subject", "rdnSequence", NULL), "CN");
519         _gcr_display_view_append_content (view, renderer, _("Identity"), display);
520         g_free (display);
521
522         display = egg_dn_read_part (egg_asn1x_node (asn, "tbsCertificate", "issuer", "rdnSequence", NULL), "CN");
523         _gcr_display_view_append_content (view, renderer, _("Verified by"), display);
524         g_free (display);
525
526         if (egg_asn1x_get_time_as_date (egg_asn1x_node (asn, "tbsCertificate", "validity", "notAfter", NULL), &date)) {
527                 display = g_malloc0 (128);
528                 if (!g_date_strftime (display, 128, "%x", &date))
529                         g_return_if_reached ();
530                 _gcr_display_view_append_content (view, renderer, _("Expires"), display);
531                 g_free (display);
532         }
533
534         _gcr_display_view_start_details (view, renderer);
535
536         /* The subject */
537         _gcr_display_view_append_heading (view, renderer, _("Subject Name"));
538         _gcr_certificate_renderer_append_distinguished_name (renderer, view,
539                                                              egg_asn1x_node (asn, "tbsCertificate", "subject", "rdnSequence", NULL));
540
541         /* The Issuer */
542         _gcr_display_view_append_heading (view, renderer, _("Issuer Name"));
543         _gcr_certificate_renderer_append_distinguished_name (renderer, view,
544                                                              egg_asn1x_node (asn, "tbsCertificate", "issuer", "rdnSequence", NULL));
545
546         /* The Issued Parameters */
547         _gcr_display_view_append_heading (view, renderer, _("Issued Certificate"));
548
549         if (!egg_asn1x_get_integer_as_ulong (egg_asn1x_node (asn, "tbsCertificate", "version", NULL), &version))
550                 g_return_if_reached ();
551         display = g_strdup_printf ("%lu", version + 1);
552         _gcr_display_view_append_value (view, renderer, _("Version"), display, FALSE);
553         g_free (display);
554
555         number = egg_asn1x_get_integer_as_raw (egg_asn1x_node (asn, "tbsCertificate", "serialNumber", NULL));
556         g_return_if_fail (number != NULL);
557         _gcr_display_view_append_hex (view, renderer, _("Serial Number"),
558                                       g_bytes_get_data (number, NULL),
559                                       g_bytes_get_size (number));
560         g_bytes_unref (number);
561
562         display = g_malloc0 (128);
563         if (egg_asn1x_get_time_as_date (egg_asn1x_node (asn, "tbsCertificate", "validity", "notBefore", NULL), &date)) {
564                 if (!g_date_strftime (display, 128, "%Y-%m-%d", &date))
565                         g_return_if_reached ();
566                 _gcr_display_view_append_value (view, renderer, _("Not Valid Before"), display, FALSE);
567         }
568         if (egg_asn1x_get_time_as_date (egg_asn1x_node (asn, "tbsCertificate", "validity", "notAfter", NULL), &date)) {
569                 if (!g_date_strftime (display, 128, "%Y-%m-%d", &date))
570                         g_return_if_reached ();
571                 _gcr_display_view_append_value (view, renderer, _("Not Valid After"), display, FALSE);
572         }
573         g_free (display);
574
575         /* Fingerprints */
576         _gcr_display_view_append_heading (view, renderer, _("Certificate Fingerprints"));
577
578         _gcr_display_view_append_fingerprint (view, renderer, data, n_data, "SHA1", G_CHECKSUM_SHA1);
579         _gcr_display_view_append_fingerprint (view, renderer, data, n_data, "MD5", G_CHECKSUM_MD5);
580
581         /* Public Key Info */
582         _gcr_display_view_append_heading (view, renderer, _("Public Key Info"));
583         bits = gcr_certificate_get_key_size (cert);
584         _gcr_certificate_renderer_append_subject_public_key (renderer, view, bits,
585                                                              egg_asn1x_node (asn, "tbsCertificate",
586                                                                              "subjectPublicKeyInfo", NULL));
587
588         /* Extensions */
589         for (index = 1; TRUE; ++index) {
590                 extension = egg_asn1x_node (asn, "tbsCertificate", "extensions", index, NULL);
591                 if (extension == NULL)
592                         break;
593                 _gcr_certificate_renderer_append_extension (renderer, view, extension);
594         }
595
596         /* Signature */
597         _gcr_display_view_append_heading (view, renderer, _("Signature"));
598         _gcr_certificate_renderer_append_signature (renderer, view, asn);
599
600         egg_asn1x_destroy (asn);
601         _gcr_display_view_end (view, renderer);
602 }
603
604 static void
605 gcr_certificate_renderer_populate_popup (GcrRenderer *self, GcrViewer *viewer,
606                                          GtkMenu *menu)
607 {
608         GtkWidget *item;
609
610         item = gtk_separator_menu_item_new ();
611         gtk_widget_show (item);
612         gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), item);
613
614         item = gtk_menu_item_new_with_label ("Export Certificate...");
615         gtk_widget_show (item);
616         g_signal_connect_data (item, "activate", G_CALLBACK (on_certificate_export),
617                                g_object_ref (self), (GClosureNotify)g_object_unref, 0);
618         gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), item);
619 }
620
621 static void
622 gcr_renderer_iface_init (GcrRendererIface *iface)
623 {
624         iface->populate_popup = gcr_certificate_renderer_populate_popup;
625         iface->render_view = gcr_certificate_renderer_render;
626 }
627
628 static const guchar *
629 gcr_certificate_renderer_get_der_data (GcrCertificate *cert,
630                                        gsize *n_data)
631 {
632         GcrCertificateRenderer *self = GCR_CERTIFICATE_RENDERER (cert);
633         const GckAttribute *attr;
634
635         g_assert (n_data);
636
637         if (self->pv->opt_cert)
638                 return gcr_certificate_get_der_data (self->pv->opt_cert, n_data);
639
640         if (self->pv->opt_attrs) {
641                 attr = gck_attributes_find (self->pv->opt_attrs, CKA_VALUE);
642                 g_return_val_if_fail (attr, NULL);
643                 *n_data = attr->length;
644                 return attr->value;
645         }
646
647         return NULL;
648 }
649
650 static void
651 gcr_renderer_certificate_iface_init (GcrCertificateIface *iface)
652 {
653         iface->get_der_data = gcr_certificate_renderer_get_der_data;
654 }
655
656 /* -----------------------------------------------------------------------------
657  * PUBLIC
658  */
659
660 /**
661  * gcr_certificate_renderer_new:
662  * @certificate: The certificate to display
663  *
664  * Create a new certificate renderer to display the certificate.
665  *
666  * Returns: (transfer full): a newly allocated #GcrCertificateRenderer, which
667  *          should be released with g_object_unref()
668  */
669 GcrCertificateRenderer *
670 gcr_certificate_renderer_new (GcrCertificate *certificate)
671 {
672         return g_object_new (GCR_TYPE_CERTIFICATE_RENDERER, "certificate", certificate, NULL);
673 }
674
675 /**
676  * gcr_certificate_renderer_new_for_attributes:
677  * @label: (allow-none): the label to display
678  * @attrs: The attributes to display
679  *
680  * Create a new certificate renderer to display the label and attributes. One
681  * of the attributes should be a CKA_VALUE type attribute containing a DER
682  * encoded certificate.
683  *
684  * Returns: (transfer full): a newly allocated #GcrCertificateRenderer, which
685  *          should be released with g_object_unref()
686  */
687 GcrCertificateRenderer *
688 gcr_certificate_renderer_new_for_attributes (const gchar *label, struct _GckAttributes *attrs)
689 {
690         return g_object_new (GCR_TYPE_CERTIFICATE_RENDERER, "label", label, "attributes", attrs, NULL);
691 }
692
693 /**
694  * gcr_certificate_renderer_get_certificate:
695  * @self: The renderer
696  *
697  * Get the certificate displayed in the renderer. If no certificate was
698  * explicitly set, then the renderer will return itself since it acts as
699  * a valid certificate.
700  *
701  * Returns: (transfer none): The certificate, owned by the renderer.
702  */
703 GcrCertificate *
704 gcr_certificate_renderer_get_certificate (GcrCertificateRenderer *self)
705 {
706         g_return_val_if_fail (GCR_IS_CERTIFICATE_RENDERER (self), NULL);
707         if (self->pv->opt_cert)
708                 return self->pv->opt_cert;
709         return GCR_CERTIFICATE (self);
710 }
711
712 /**
713  * gcr_certificate_renderer_set_certificate:
714  * @self: The renderer
715  * @certificate: (allow-none): the certificate to display
716  *
717  * Set a certificate to display in the renderer.
718  */
719 void
720 gcr_certificate_renderer_set_certificate (GcrCertificateRenderer *self, GcrCertificate *certificate)
721 {
722         g_return_if_fail (GCR_IS_CERTIFICATE_RENDERER (self));
723
724         if (self->pv->opt_cert)
725                 g_object_unref (self->pv->opt_cert);
726         self->pv->opt_cert = certificate;
727         if (self->pv->opt_cert)
728                 g_object_ref (self->pv->opt_cert);
729
730         if (self->pv->opt_attrs) {
731                 gck_attributes_unref (self->pv->opt_attrs);
732                 self->pv->opt_attrs = NULL;
733         }
734
735         gcr_renderer_emit_data_changed (GCR_RENDERER (self));
736         g_object_notify (G_OBJECT (self), "certificate");
737 }
738
739 /**
740  * gcr_certificate_renderer_get_attributes:
741  * @self: The renderer
742  *
743  * Get the PKCS\#11 attributes, if any, set for this renderer to display.
744  *
745  * Returns: (allow-none) (transfer none): the attributes, owned by the renderer
746  */
747 GckAttributes *
748 gcr_certificate_renderer_get_attributes (GcrCertificateRenderer *self)
749 {
750         g_return_val_if_fail (GCR_IS_CERTIFICATE_RENDERER (self), NULL);
751         return self->pv->opt_attrs;
752 }
753
754 /**
755  * gcr_certificate_renderer_set_attributes:
756  * @self: The renderer
757  * @attrs: (allow-none): attributes to set
758  *
759  * Set the PKCS\#11 attributes for this renderer to display. One of the attributes
760  * should be a CKA_VALUE type attribute containing a DER encoded certificate.
761  */
762 void
763 gcr_certificate_renderer_set_attributes (GcrCertificateRenderer *self, GckAttributes *attrs)
764 {
765         g_return_if_fail (GCR_IS_CERTIFICATE_RENDERER (self));
766
767         gck_attributes_unref (self->pv->opt_attrs);
768         self->pv->opt_attrs = attrs;
769
770         if (self->pv->opt_attrs)
771                 gck_attributes_ref (self->pv->opt_attrs);
772
773         if (self->pv->opt_cert) {
774                 g_object_unref (self->pv->opt_cert);
775                 g_object_notify (G_OBJECT (self), "certificate");
776                 self->pv->opt_cert = NULL;
777         }
778
779         gcr_renderer_emit_data_changed (GCR_RENDERER (self));
780         g_object_notify (G_OBJECT (self), "attributes");
781
782 }
783
784 typedef struct {
785         GcrRenderer *renderer;
786         GcrDisplayView *view;
787 } AppendDnClosure;
788
789 static void
790 on_parsed_dn_part (guint index,
791                    GQuark oid,
792                    GBytes *value,
793                    gpointer user_data)
794 {
795         GcrRenderer *renderer = ((AppendDnClosure *)user_data)->renderer;
796         GcrDisplayView *view = ((AppendDnClosure *)user_data)->view;
797         const gchar *attr;
798         const gchar *desc;
799         gchar *field = NULL;
800         gchar *display;
801
802         attr = egg_oid_get_name (oid);
803         desc = egg_oid_get_description (oid);
804
805         /* Combine them into something sane */
806         if (attr && desc) {
807                 if (strcmp (attr, desc) == 0)
808                         field = g_strdup (attr);
809                 else
810                         field = g_strdup_printf ("%s (%s)", attr, desc);
811         } else if (!attr && !desc) {
812                 field = g_strdup ("");
813         } else if (attr) {
814                 field = g_strdup (attr);
815         } else if (desc) {
816                 field = g_strdup (desc);
817         } else {
818                 g_assert_not_reached ();
819         }
820
821         display = egg_dn_print_value (oid, value);
822         if (display == NULL)
823                 display = g_strdup ("");
824
825         _gcr_display_view_append_value (view, renderer, field, display, FALSE);
826         g_free (field);
827         g_free (display);
828 }
829
830
831 void
832 _gcr_certificate_renderer_append_distinguished_name (GcrRenderer *renderer,
833                                                      GcrDisplayView *view,
834                                                      GNode *dn)
835 {
836         AppendDnClosure closure;
837
838         g_return_if_fail (GCR_IS_RENDERER (renderer));
839         g_return_if_fail (GCR_IS_DISPLAY_VIEW (view));
840         g_return_if_fail (dn != NULL);
841
842         closure.renderer = renderer;
843         closure.view = view;
844         egg_dn_parse (dn, on_parsed_dn_part, &closure);
845 }
846
847 void
848 _gcr_certificate_renderer_append_subject_public_key (GcrRenderer *renderer,
849                                                      GcrDisplayView *view,
850                                                      guint key_nbits,
851                                                      GNode *subject_public_key)
852 {
853         const gchar *text;
854         gchar *display;
855         GBytes *value;
856         guchar *raw;
857         gsize n_raw;
858         GQuark oid;
859         guint bits;
860
861         oid = egg_asn1x_get_oid_as_quark (egg_asn1x_node (subject_public_key,
862                                                           "algorithm", "algorithm", NULL));
863         text = egg_oid_get_description (oid);
864         _gcr_display_view_append_value (view, renderer, _("Key Algorithm"), text, FALSE);
865
866         value = egg_asn1x_get_element_raw (egg_asn1x_node (subject_public_key,
867                                                            "algorithm", "parameters", NULL));
868         if (value) {
869                 _gcr_display_view_append_hex (view, renderer, _("Key Parameters"),
870                                               g_bytes_get_data (value, NULL),
871                                               g_bytes_get_size (value));
872                 g_bytes_unref (value);
873         }
874
875         if (key_nbits > 0) {
876                 display = g_strdup_printf ("%u", key_nbits);
877                 _gcr_display_view_append_value (view, renderer, _("Key Size"), display, FALSE);
878                 g_free (display);
879         }
880
881         value = egg_asn1x_get_element_raw (subject_public_key);
882         raw = gcr_fingerprint_from_subject_public_key_info (g_bytes_get_data (value, NULL),
883                                                             g_bytes_get_size (value),
884                                                             G_CHECKSUM_SHA1, &n_raw);
885         _gcr_display_view_append_hex (view, renderer, _("Key SHA1 Fingerprint"), raw, n_raw);
886         g_bytes_unref (value);
887         g_free (raw);
888
889         value = egg_asn1x_get_bits_as_raw (egg_asn1x_node (subject_public_key, "subjectPublicKey", NULL), &bits);
890         _gcr_display_view_append_hex (view, renderer, _("Public Key"),
891                                       g_bytes_get_data (value, NULL), bits / 8);
892         g_bytes_unref (value);
893 }
894
895 void
896 _gcr_certificate_renderer_append_signature (GcrRenderer *renderer,
897                                             GcrDisplayView *view,
898                                             GNode *asn)
899 {
900         const gchar *text;
901         GBytes *value;
902         GQuark oid;
903         guint bits;
904
905         oid = egg_asn1x_get_oid_as_quark (egg_asn1x_node (asn, "signatureAlgorithm", "algorithm", NULL));
906         text = egg_oid_get_description (oid);
907         _gcr_display_view_append_value (view, renderer, _("Signature Algorithm"), text, FALSE);
908
909         value = egg_asn1x_get_element_raw (egg_asn1x_node (asn, "signatureAlgorithm", "parameters", NULL));
910         if (value) {
911                 _gcr_display_view_append_hex (view, renderer, _("Signature Parameters"),
912                                               g_bytes_get_data (value, NULL),
913                                               g_bytes_get_size (value));
914                 g_bytes_unref (value);
915         }
916
917         value = egg_asn1x_get_bits_as_raw (egg_asn1x_node (asn, "signature", NULL), &bits);
918         _gcr_display_view_append_hex (view, renderer, _("Signature"),
919                                       g_bytes_get_data (value, NULL), bits / 8);
920         g_bytes_unref (value);
921 }
922
923 void
924 _gcr_certificate_renderer_append_extension (GcrRenderer *renderer,
925                                             GcrDisplayView *view,
926                                             GNode *node)
927 {
928         GQuark oid;
929         GBytes *value;
930         gboolean critical;
931         gboolean ret = FALSE;
932
933         /* Dig out the OID */
934         oid = egg_asn1x_get_oid_as_quark (egg_asn1x_node (node, "extnID", NULL));
935         g_return_if_fail (oid);
936
937         /* Extension value */
938         value = egg_asn1x_get_raw_value (egg_asn1x_node (node, "extnValue", NULL));
939
940         /* The custom parsers */
941         if (oid == GCR_OID_BASIC_CONSTRAINTS)
942                 ret = append_extension_basic_constraints (renderer, view, value);
943         else if (oid == GCR_OID_EXTENDED_KEY_USAGE)
944                 ret = append_extension_extended_key_usage (renderer, view, value);
945         else if (oid == GCR_OID_SUBJECT_KEY_IDENTIFIER)
946                 ret = append_extension_subject_key_identifier (renderer, view, value);
947         else if (oid == GCR_OID_KEY_USAGE)
948                 ret = append_extension_key_usage (renderer, view, value);
949         else if (oid == GCR_OID_SUBJECT_ALT_NAME)
950                 ret = append_extension_subject_alt_name (renderer, view, value);
951
952         /* Otherwise the default raw display */
953         if (ret == FALSE)
954                 ret = append_extension_hex (renderer, view, oid,
955                                             g_bytes_get_data (value, NULL),
956                                             g_bytes_get_size (value));
957
958         /* Critical */
959         if (ret == TRUE && egg_asn1x_get_boolean (egg_asn1x_node (node, "critical", NULL), &critical)) {
960                 _gcr_display_view_append_value (view, renderer, _("Critical"),
961                                                 critical ? _("Yes") : _("No"), FALSE);
962         }
963 }