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