Merge branch 'gnome-3-0'
[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-renderer.h"
25 #include "gcr-display-view.h"
26 #include "gcr-icons.h"
27 #include "gcr-simple-certificate.h"
28 #include "gcr-renderer.h"
29
30 #include "egg/egg-asn1x.h"
31 #include "egg/egg-asn1-defs.h"
32 #include "egg/egg-dn.h"
33 #include "egg/egg-oid.h"
34 #include "egg/egg-hex.h"
35
36 #include "gck/gck.h"
37
38 #include <gdk/gdk.h>
39 #include <glib/gi18n-lib.h>
40
41 enum {
42         PROP_0,
43         PROP_CERTIFICATE,
44         PROP_LABEL,
45         PROP_ATTRIBUTES
46 };
47
48 struct _GcrCertificateRendererPrivate {
49         GcrCertificate *opt_cert;
50         GckAttributes *opt_attrs;
51         guint key_size;
52         gchar *label;
53 };
54
55 static void gcr_renderer_iface_init (GcrRendererIface *iface);
56 static void gcr_renderer_certificate_iface_init (GcrCertificateIface *iface);
57
58 G_DEFINE_TYPE_WITH_CODE (GcrCertificateRenderer, gcr_certificate_renderer, G_TYPE_OBJECT,
59         G_IMPLEMENT_INTERFACE (GCR_TYPE_RENDERER, gcr_renderer_iface_init);
60         GCR_CERTIFICATE_MIXIN_IMPLEMENT_COMPARABLE ();
61         G_IMPLEMENT_INTERFACE (GCR_TYPE_CERTIFICATE, gcr_renderer_certificate_iface_init);
62 );
63
64 /* -----------------------------------------------------------------------------
65  * INTERNAL
66  */
67
68 static gchar*
69 calculate_label (GcrCertificateRenderer *self)
70 {
71         gchar *label;
72
73         if (self->pv->label)
74                 return g_strdup (self->pv->label);
75
76         if (self->pv->opt_attrs) {
77                 if (gck_attributes_find_string (self->pv->opt_attrs, CKA_LABEL, &label))
78                         return label;
79         }
80
81         label = gcr_certificate_get_subject_cn (GCR_CERTIFICATE (self));
82         if (label != NULL)
83                 return label;
84
85         return g_strdup (_("Certificate"));
86 }
87
88 static gboolean
89 append_extension (GcrCertificateRenderer *self, GcrDisplayView *view,
90                   GNode *asn, const guchar *data, gsize n_data, gint index)
91 {
92         GcrRenderer *renderer = GCR_RENDERER (self);
93         GNode *node;
94         GQuark oid;
95         gchar *display;
96         gsize n_value;
97         const guchar *value;
98         const gchar *text;
99         gboolean critical;
100
101         /* Make sure it is present */
102         node = egg_asn1x_node (asn, "tbsCertificate", "extensions", index, NULL);
103         if (node == NULL)
104                 return FALSE;
105
106         /* Dig out the OID */
107         oid = egg_asn1x_get_oid_as_quark (egg_asn1x_node (node, "extnID", NULL));
108         g_return_val_if_fail (oid, FALSE);
109
110         _gcr_display_view_append_heading (view, renderer, _("Extension"));
111
112
113         /* Extension type */
114         text = egg_oid_get_description (oid);
115         _gcr_display_view_append_value (view, renderer, _("Identifier"), text, FALSE);
116
117
118         /* Extension value */
119         value = egg_asn1x_get_raw_value (egg_asn1x_node (node, "extnValue", NULL), &n_value);
120
121         /* TODO: Parsing of extensions that we understand */
122         display = egg_hex_encode_full (value, n_value, TRUE, ' ', 1);
123         _gcr_display_view_append_value (view, renderer, _("Value"), display, TRUE);
124         g_free (display);
125
126
127         /* Critical */
128         if (egg_asn1x_get_boolean (egg_asn1x_node (node, "critical", NULL), &critical))
129                 _gcr_display_view_append_value (view, renderer, _("Critical"), critical ? _("Yes") : _("No"), FALSE);
130
131         return TRUE;
132 }
133
134 typedef struct _on_parsed_dn_args {
135         GcrCertificateRenderer *renderer;
136         GcrDisplayView *view;
137 } on_parsed_dn_args;
138
139 static void
140 on_parsed_dn_part (guint index, GQuark oid, const guchar *value,
141                    gsize n_value, gpointer user_data)
142 {
143         GcrCertificateRenderer *self = ((on_parsed_dn_args*)user_data)->renderer;
144         GcrDisplayView *view = ((on_parsed_dn_args*)user_data)->view;
145         const gchar *attr;
146         const gchar *desc;
147         gchar *field;
148         gchar *display;
149
150         g_return_if_fail (GCR_IS_CERTIFICATE_RENDERER (self));
151
152         attr = egg_oid_get_name (oid);
153         desc = egg_oid_get_description (oid);
154
155         /* Combine them into something sane */
156         if (attr && desc) {
157                 if (strcmp (attr, desc) == 0)
158                         field = g_strdup (attr);
159                 else
160                         field = g_strdup_printf ("%s (%s)", attr, desc);
161         } else if (!attr && !desc) {
162                 field = g_strdup ("");
163         } else if (attr) {
164                 field = g_strdup (attr);
165         } else if (desc) {
166                 field = g_strdup (desc);
167         } else {
168                 g_assert_not_reached ();
169         }
170
171         display = egg_dn_print_value (oid, value, n_value);
172         if (display == NULL)
173                 display = g_strdup ("");
174
175         _gcr_display_view_append_value (view, GCR_RENDERER (self), field, display, FALSE);
176         g_free (field);
177         g_free (display);
178 }
179
180 static gboolean
181 on_delete_unref_dialog (GtkWidget *widget, GdkEvent *event, gpointer data)
182 {
183         g_object_unref (widget);
184         return FALSE;
185 }
186
187 static void
188 on_export_completed (GObject *source, GAsyncResult *result, gpointer user_data)
189 {
190         GtkWindow *parent = GTK_WINDOW (user_data);
191         GcrCertificateExporter *exporter = GCR_CERTIFICATE_EXPORTER (source);
192         GError *error = NULL;
193         GtkWidget *dialog;
194
195         if (!_gcr_certificate_exporter_export_finish (exporter, result, &error)) {
196                 if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
197                         dialog = gtk_message_dialog_new_with_markup (parent,
198                                   GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR,
199                                   GTK_BUTTONS_OK, "<big>%s</big>\n\n%s",
200                                   _("Couldn't export the certificate."),
201                                   error->message);
202                         gtk_widget_show (dialog);
203                         g_signal_connect (dialog, "delete-event",
204                                           G_CALLBACK (on_delete_unref_dialog), NULL);
205                 }
206         }
207
208         /* Matches ref in on_certificate_export */
209         if (parent)
210                 g_object_unref (parent);
211 }
212
213 static void
214 on_certificate_export (GtkMenuItem *menuitem, gpointer user_data)
215 {
216         GcrCertificateRenderer *self = GCR_CERTIFICATE_RENDERER (user_data);
217         GcrCertificateExporter *exporter;
218         gchar *label;
219         GtkWidget *parent;
220
221         label = calculate_label (self);
222
223         parent = gtk_widget_get_toplevel (GTK_WIDGET (menuitem));
224         if (parent && !GTK_IS_WINDOW (parent))
225                 parent = NULL;
226
227         exporter = _gcr_certificate_exporter_new (GCR_CERTIFICATE (self), label,
228                                                   GTK_WINDOW (parent));
229
230         g_free (label);
231
232         _gcr_certificate_exporter_export_async (exporter, NULL, on_export_completed,
233                                                 parent ? g_object_ref (parent) : NULL);
234 }
235
236 /* -----------------------------------------------------------------------------
237  * OBJECT
238  */
239
240 static void
241 gcr_certificate_renderer_init (GcrCertificateRenderer *self)
242 {
243         self->pv = (G_TYPE_INSTANCE_GET_PRIVATE (self, GCR_TYPE_CERTIFICATE_RENDERER, GcrCertificateRendererPrivate));
244 }
245
246 static void
247 gcr_certificate_renderer_dispose (GObject *obj)
248 {
249         GcrCertificateRenderer *self = GCR_CERTIFICATE_RENDERER (obj);
250
251         if (self->pv->opt_cert)
252                 g_object_unref (self->pv->opt_cert);
253         self->pv->opt_cert = NULL;
254
255         G_OBJECT_CLASS (gcr_certificate_renderer_parent_class)->dispose (obj);
256 }
257
258 static void
259 gcr_certificate_renderer_finalize (GObject *obj)
260 {
261         GcrCertificateRenderer *self = GCR_CERTIFICATE_RENDERER (obj);
262
263         g_assert (!self->pv->opt_cert);
264
265         if (self->pv->opt_attrs)
266                 gck_attributes_unref (self->pv->opt_attrs);
267         self->pv->opt_attrs = NULL;
268
269         g_free (self->pv->label);
270         self->pv->label = NULL;
271
272         G_OBJECT_CLASS (gcr_certificate_renderer_parent_class)->finalize (obj);
273 }
274
275 static void
276 gcr_certificate_renderer_set_property (GObject *obj, guint prop_id, const GValue *value,
277                                      GParamSpec *pspec)
278 {
279         GcrCertificateRenderer *self = GCR_CERTIFICATE_RENDERER (obj);
280
281         switch (prop_id) {
282         case PROP_CERTIFICATE:
283                 gcr_certificate_renderer_set_certificate (self, g_value_get_object (value));
284                 break;
285         case PROP_LABEL:
286                 g_free (self->pv->label);
287                 self->pv->label = g_value_dup_string (value);
288                 g_object_notify (obj, "label");
289                 gcr_renderer_emit_data_changed (GCR_RENDERER (self));
290                 break;
291         case PROP_ATTRIBUTES:
292                 gcr_certificate_renderer_set_attributes (self, g_value_get_boxed (value));
293                 break;
294         default:
295                 G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
296                 break;
297         }
298 }
299
300 static void
301 gcr_certificate_renderer_get_property (GObject *obj, guint prop_id, GValue *value,
302                                      GParamSpec *pspec)
303 {
304         GcrCertificateRenderer *self = GCR_CERTIFICATE_RENDERER (obj);
305
306         switch (prop_id) {
307         case PROP_CERTIFICATE:
308                 g_value_set_object (value, self->pv->opt_cert);
309                 break;
310         case PROP_LABEL:
311                 g_value_take_string (value, calculate_label (self));
312                 break;
313         case PROP_ATTRIBUTES:
314                 g_value_set_boxed (value, self->pv->opt_attrs);
315                 break;
316         default:
317                 gcr_certificate_mixin_get_property (obj, prop_id, value, pspec);
318                 break;
319         }
320 }
321
322 static void
323 gcr_certificate_renderer_class_init (GcrCertificateRendererClass *klass)
324 {
325         GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
326         GckAttributes *registered;
327
328         gcr_certificate_renderer_parent_class = g_type_class_peek_parent (klass);
329         g_type_class_add_private (klass, sizeof (GcrCertificateRendererPrivate));
330
331         gobject_class->dispose = gcr_certificate_renderer_dispose;
332         gobject_class->finalize = gcr_certificate_renderer_finalize;
333         gobject_class->set_property = gcr_certificate_renderer_set_property;
334         gobject_class->get_property = gcr_certificate_renderer_get_property;
335
336         g_object_class_install_property (gobject_class, PROP_CERTIFICATE,
337                    g_param_spec_object ("certificate", "Certificate", "Certificate to display.",
338                                         GCR_TYPE_CERTIFICATE, G_PARAM_READWRITE));
339
340         g_object_class_install_property (gobject_class, PROP_ATTRIBUTES,
341                    g_param_spec_boxed ("attributes", "Attributes", "Certificate pkcs11 attributes",
342                                        GCK_TYPE_ATTRIBUTES, G_PARAM_READWRITE));
343
344         g_object_class_install_property (gobject_class, PROP_LABEL,
345                    g_param_spec_string ("label", "Label", "Certificate Label",
346                                         "", G_PARAM_READWRITE));
347
348         _gcr_icons_register ();
349         gcr_certificate_mixin_class_init (gobject_class);
350
351         /* Register this as a renderer which can be loaded */
352         registered = gck_attributes_new ();
353         gck_attributes_add_ulong (registered, CKA_CLASS, CKO_CERTIFICATE);
354         gcr_renderer_register (GCR_TYPE_CERTIFICATE_RENDERER, registered);
355         gck_attributes_unref (registered);
356 }
357
358 static void
359 gcr_certificate_renderer_render (GcrRenderer *renderer, GcrViewer *viewer)
360 {
361         GcrCertificateRenderer *self;
362         gconstpointer data, value;
363         gsize n_data, n_value, n_raw;
364         GcrDisplayView *view;
365         on_parsed_dn_args args;
366         const gchar *text;
367         GcrCertificate *cert;
368         gpointer raw;
369         gulong version;
370         guint bits, index;
371         gchar *display;
372         GNode *asn;
373         GQuark oid;
374         GDate date;
375         GIcon *icon;
376
377         self = GCR_CERTIFICATE_RENDERER (renderer);
378
379         if (GCR_IS_DISPLAY_VIEW (viewer)) {
380                 view = GCR_DISPLAY_VIEW (viewer);
381
382         } else {
383                 g_warning ("GcrCertificateRenderer only works with internal specific "
384                            "GcrViewer returned by gcr_viewer_new().");
385                 return;
386         }
387
388         _gcr_display_view_clear (view, renderer);
389         cert = GCR_CERTIFICATE (self);
390
391         data = gcr_certificate_get_der_data (cert, &n_data);
392         if (!data)
393                 return;
394
395         icon = gcr_certificate_get_icon (cert);
396         _gcr_display_view_set_icon (view, GCR_RENDERER (self), icon);
397         g_object_unref (icon);
398
399         asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "Certificate", data, n_data);
400         g_return_if_fail (asn);
401
402         display = calculate_label (self);
403         _gcr_display_view_append_title (view, renderer, display);
404         g_free (display);
405
406         display = egg_dn_read_part (egg_asn1x_node (asn, "tbsCertificate", "subject", "rdnSequence", NULL), "CN");
407         _gcr_display_view_append_content (view, renderer, _("Identity"), display);
408         g_free (display);
409
410         display = egg_dn_read_part (egg_asn1x_node (asn, "tbsCertificate", "issuer", "rdnSequence", NULL), "CN");
411         _gcr_display_view_append_content (view, renderer, _("Verified by"), display);
412         g_free (display);
413
414         if (egg_asn1x_get_time_as_date (egg_asn1x_node (asn, "tbsCertificate", "validity", "notAfter", NULL), &date)) {
415                 display = g_malloc0 (128);
416                 if (!g_date_strftime (display, 128, "%x", &date))
417                         g_return_if_reached ();
418                 _gcr_display_view_append_content (view, renderer, _("Expires"), display);
419                 g_free (display);
420         }
421
422         _gcr_display_view_start_details (view, renderer);
423
424         args.renderer = self;
425         args.view = view;
426
427         /* The subject */
428         _gcr_display_view_append_heading (view, renderer, _("Subject Name"));
429         egg_dn_parse (egg_asn1x_node (asn, "tbsCertificate", "subject", "rdnSequence", NULL), on_parsed_dn_part, &args);
430
431         /* The Issuer */
432         _gcr_display_view_append_heading (view, renderer, _("Issuer Name"));
433         egg_dn_parse (egg_asn1x_node (asn, "tbsCertificate", "issuer", "rdnSequence", NULL), on_parsed_dn_part, &args);
434
435         /* The Issued Parameters */
436         _gcr_display_view_append_heading (view, renderer, _("Issued Certificate"));
437
438         if (!egg_asn1x_get_integer_as_ulong (egg_asn1x_node (asn, "tbsCertificate", "version", NULL), &version))
439                 g_return_if_reached ();
440         display = g_strdup_printf ("%lu", version + 1);
441         _gcr_display_view_append_value (view, renderer, _("Version"), display, FALSE);
442         g_free (display);
443
444         raw = egg_asn1x_get_integer_as_raw (egg_asn1x_node (asn, "tbsCertificate", "serialNumber", NULL), NULL, &n_raw);
445         g_return_if_fail (raw);
446         display = egg_hex_encode_full (raw, n_raw, TRUE, ' ', 1);
447         _gcr_display_view_append_value (view, renderer, _("Serial Number"), display, TRUE);
448         g_free (display);
449         g_free (raw);
450
451         display = g_malloc0 (128);
452         if (egg_asn1x_get_time_as_date (egg_asn1x_node (asn, "tbsCertificate", "validity", "notBefore", NULL), &date)) {
453                 if (!g_date_strftime (display, 128, "%Y-%m-%d", &date))
454                         g_return_if_reached ();
455                 _gcr_display_view_append_value (view, renderer, _("Not Valid Before"), display, FALSE);
456         }
457         if (egg_asn1x_get_time_as_date (egg_asn1x_node (asn, "tbsCertificate", "validity", "notAfter", NULL), &date)) {
458                 if (!g_date_strftime (display, 128, "%Y-%m-%d", &date))
459                         g_return_if_reached ();
460                 _gcr_display_view_append_value (view, renderer, _("Not Valid After"), display, FALSE);
461         }
462         g_free (display);
463
464         /* Signature */
465         _gcr_display_view_append_heading (view, renderer, _("Signature"));
466
467         oid = egg_asn1x_get_oid_as_quark (egg_asn1x_node (asn, "signatureAlgorithm", "algorithm", NULL));
468         text = egg_oid_get_description (oid);
469         _gcr_display_view_append_value (view, renderer, _("Signature Algorithm"), text, FALSE);
470
471         value = egg_asn1x_get_raw_element (egg_asn1x_node (asn, "signatureAlgorithm", "parameters", NULL), &n_value);
472         if (value && n_value) {
473                 display = egg_hex_encode_full (value, n_value, TRUE, ' ', 1);
474                 _gcr_display_view_append_value (view, renderer, _("Signature Parameters"), display, TRUE);
475                 g_free (display);
476         }
477
478         raw = egg_asn1x_get_bits_as_raw (egg_asn1x_node (asn, "signature", NULL), NULL, &bits);
479         g_return_if_fail (raw);
480         display = egg_hex_encode_full (raw, bits / 8, TRUE, ' ', 1);
481         _gcr_display_view_append_value (view, renderer, _("Signature"), display, TRUE);
482         g_free (display);
483         g_free (raw);
484
485         /* Public Key Info */
486         _gcr_display_view_append_heading (view, renderer, _("Public Key Info"));
487
488         oid = egg_asn1x_get_oid_as_quark (egg_asn1x_node (asn, "tbsCertificate", "subjectPublicKeyInfo",
489                                                           "algorithm", "algorithm", NULL));
490         text = egg_oid_get_description (oid);
491         _gcr_display_view_append_value (view, renderer, _("Key Algorithm"), text, FALSE);
492
493         value = egg_asn1x_get_raw_element (egg_asn1x_node (asn, "tbsCertificate", "subjectPublicKeyInfo",
494                                                            "algorithm", "parameters", NULL), &n_value);
495         if (value && n_value) {
496                 display = egg_hex_encode_full (value, n_value, TRUE, ' ', 1);
497                 _gcr_display_view_append_value (view, renderer, _("Key Parameters"), display, TRUE);
498                 g_free (display);
499         }
500
501         bits = gcr_certificate_get_key_size (cert);
502         if (bits > 0) {
503                 display = g_strdup_printf ("%u", bits);
504                 _gcr_display_view_append_value (view, renderer, _("Key Size"), display, FALSE);
505                 g_free (display);
506         }
507
508         raw = egg_asn1x_get_bits_as_raw (egg_asn1x_node (asn, "tbsCertificate", "subjectPublicKeyInfo",
509                                                          "subjectPublicKey", NULL), NULL, &bits);
510         g_return_if_fail (raw);
511         display = egg_hex_encode_full (raw, bits / 8, TRUE, ' ', 1);
512         _gcr_display_view_append_value (view, renderer, _("Public Key"), display, TRUE);
513         g_free (display);
514         g_free (raw);
515
516         /* Fingerprints */
517         _gcr_display_view_append_heading (view, renderer, _("Fingerprints"));
518
519         _gcr_display_view_append_fingerprint (view, renderer, data, n_data, "SHA1", G_CHECKSUM_SHA1);
520         _gcr_display_view_append_fingerprint (view, renderer, data, n_data, "MD5", G_CHECKSUM_MD5);
521
522         /* Extensions */
523         for (index = 1; TRUE; ++index) {
524                 if (!append_extension (self, view, asn, data, n_data, index))
525                         break;
526         }
527
528         egg_asn1x_destroy (asn);
529 }
530
531 static void
532 gcr_certificate_renderer_populate_popup (GcrRenderer *self, GcrViewer *viewer,
533                                          GtkMenu *menu)
534 {
535         GtkWidget *item;
536
537         item = gtk_separator_menu_item_new ();
538         gtk_widget_show (item);
539         gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), item);
540
541         item = gtk_menu_item_new_with_label ("Export Certificate...");
542         gtk_widget_show (item);
543         g_signal_connect_data (item, "activate", G_CALLBACK (on_certificate_export),
544                                g_object_ref (self), (GClosureNotify)g_object_unref, 0);
545         gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), item);
546 }
547
548 static void
549 gcr_renderer_iface_init (GcrRendererIface *iface)
550 {
551         iface->populate_popup = gcr_certificate_renderer_populate_popup;
552         iface->render_view = gcr_certificate_renderer_render;
553 }
554
555 static gconstpointer
556 gcr_certificate_renderer_get_der_data (GcrCertificate *cert, gsize *n_data)
557 {
558         GcrCertificateRenderer *self = GCR_CERTIFICATE_RENDERER (cert);
559         GckAttribute *attr;
560
561         g_assert (n_data);
562
563         if (self->pv->opt_cert)
564                 return gcr_certificate_get_der_data (self->pv->opt_cert, n_data);
565
566         if (self->pv->opt_attrs) {
567                 attr = gck_attributes_find (self->pv->opt_attrs, CKA_VALUE);
568                 g_return_val_if_fail (attr, NULL);
569                 *n_data = attr->length;
570                 return attr->value;
571         }
572
573         return NULL;
574 }
575
576 static void
577 gcr_renderer_certificate_iface_init (GcrCertificateIface *iface)
578 {
579         iface->get_der_data = gcr_certificate_renderer_get_der_data;
580 }
581
582 /* -----------------------------------------------------------------------------
583  * PUBLIC
584  */
585
586 GcrCertificateRenderer*
587 gcr_certificate_renderer_new (GcrCertificate *certificate)
588 {
589         return g_object_new (GCR_TYPE_CERTIFICATE_RENDERER, "certificate", certificate, NULL);
590 }
591
592 GcrCertificateRenderer*
593 gcr_certificate_renderer_new_for_attributes (const gchar *label, struct _GckAttributes *attrs)
594 {
595         return g_object_new (GCR_TYPE_CERTIFICATE_RENDERER, "label", label, "attributes", attrs, NULL);
596 }
597
598 GcrCertificate*
599 gcr_certificate_renderer_get_certificate (GcrCertificateRenderer *self)
600 {
601         g_return_val_if_fail (GCR_IS_CERTIFICATE_RENDERER (self), NULL);
602         if (self->pv->opt_cert)
603                 return self->pv->opt_cert;
604         return GCR_CERTIFICATE (self);
605 }
606
607 void
608 gcr_certificate_renderer_set_certificate (GcrCertificateRenderer *self, GcrCertificate *cert)
609 {
610         g_return_if_fail (GCR_IS_CERTIFICATE_RENDERER (self));
611
612         if (self->pv->opt_cert)
613                 g_object_unref (self->pv->opt_cert);
614         self->pv->opt_cert = cert;
615         if (self->pv->opt_cert)
616                 g_object_ref (self->pv->opt_cert);
617
618         if (self->pv->opt_attrs) {
619                 gck_attributes_unref (self->pv->opt_attrs);
620                 self->pv->opt_attrs = NULL;
621         }
622
623         gcr_renderer_emit_data_changed (GCR_RENDERER (self));
624         g_object_notify (G_OBJECT (self), "certificate");
625 }
626
627 GckAttributes*
628 gcr_certificate_renderer_get_attributes (GcrCertificateRenderer *self)
629 {
630         g_return_val_if_fail (GCR_IS_CERTIFICATE_RENDERER (self), NULL);
631         return self->pv->opt_attrs;
632 }
633
634 void
635 gcr_certificate_renderer_set_attributes (GcrCertificateRenderer *self, GckAttributes *attrs)
636 {
637         g_return_if_fail (GCR_IS_CERTIFICATE_RENDERER (self));
638
639         gck_attributes_unref (self->pv->opt_attrs);
640         self->pv->opt_attrs = attrs;
641
642         if (self->pv->opt_attrs)
643                 gck_attributes_ref (self->pv->opt_attrs);
644
645         if (self->pv->opt_cert) {
646                 g_object_unref (self->pv->opt_cert);
647                 g_object_notify (G_OBJECT (self), "certificate");
648                 self->pv->opt_cert = NULL;
649         }
650
651         gcr_renderer_emit_data_changed (GCR_RENDERER (self));
652         g_object_notify (G_OBJECT (self), "attributes");
653
654 }