1 /*
2 * gnome-keyring
3 *
4 * Copyright (C) 2008 Stefan Walter
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU Lesser General Public License as
8 * published by the Free Software Foundation; either version 2.1 of
9 * the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this program; if not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include "config.h"
21
22 #include "gcr-certificate.h"
23 #include "gcr-certificate-extensions.h"
24 #include "gcr-comparable.h"
25 #include "gcr-icons.h"
26 #include "gcr-internal.h"
27 #include "gcr-subject-public-key.h"
28
29 #include "gcr/gcr-oids.h"
30
31 #include "egg/egg-asn1x.h"
32 #include "egg/egg-asn1-defs.h"
33 #include "egg/egg-dn.h"
34 #include "egg/egg-hex.h"
35
36 #include <string.h>
37 #include <glib/gi18n-lib.h>
38
39 /**
40 * SECTION:gcr-certificate
41 * @title: GcrCertificate
42 * @short_description: Represents an X.509 certificate
43 *
44 * This is an interface that represents an X.509 certificate. Objects can
45 * implement this interface to make a certificate usable with the GCR
46 * library.
47 *
48 * Various methods are available to parse out relevant bits of the certificate.
49 * However no verification of the validity of a certificate is done here. Use
50 * your favorite crypto library to do this.
51 *
52 * You can use #GcrSimpleCertificate to simply load a certificate for which
53 * you already have the raw certificate data.
54 *
55 * The #GcrCertificate interface has several properties that must be implemented.
56 * You can use a mixin to implement these properties if desired. See the
57 * gcr_certificate_mixin_class_init() and gcr_certificate_mixin_get_property()
58 * functions.
59 *
60 * All certificates are comparable. If implementing a #GcrCertificate, you can
61 * use GCR_CERTIFICATE_MIXIN_IMPLEMENT_COMPARABLE() to implement the #GcrComparable
62 * interface.
63 */
64
65 /**
66 * GcrCertificate:
67 *
68 * An object which holds a certificate.
69 */
70
71 /**
72 * GcrCertificateIface:
73 * @parent: the parent interface type
74 * @get_der_data: a method which returns the RAW der data of the certificate
75 *
76 * The interface that implementors of #GcrCertificate must implement.
77 */
78
79 /**
80 * GCR_CERTIFICATE_COLUMNS:
81 *
82 * The columns that are valid for a certificate. This is to be used with
83 * the #GcrTreeSelector or #GcrCollectionModel.
84 *
85 * This is an array of #GcrColumn, owned by the gcr library.
86 */
87
88 /*
89 * The DER data in this structure is owned by the derived class.
90 * It is only valid for the duration of the current call stack
91 * after we call gcr_certificate_get_der_data(). We shouldn't
92 * save it anywhere else.
93 *
94 * We keep the pointer around and compare it so that if the derived
95 * class returns exactly the same pointer and size, then we can
96 * keep from parsing things over again.
97 */
98
99 typedef struct _GcrCertificateInfo {
100 gconstpointer der;
101 gsize n_der;
102 GNode *asn1;
103 guint key_size;
104 } GcrCertificateInfo;
105
106 /* Forward declarations */
107
108 static GBytes * _gcr_certificate_get_subject_const (GcrCertificate *self);
109 static GBytes * _gcr_certificate_get_issuer_const (GcrCertificate *self);
110
111 enum {
112 PROP_FIRST = 0x0007000,
113 PROP_LABEL,
114 PROP_MARKUP,
115 PROP_DESCRIPTION,
116 PROP_ICON,
117 PROP_SUBJECT,
118 PROP_ISSUER,
119 PROP_EXPIRY
120 };
121
122 /* -----------------------------------------------------------------------------
123 * INTERNAL
124 */
125
126 static GQuark CERTIFICATE_INFO = 0;
127
128 static void
certificate_info_free(gpointer data)129 certificate_info_free (gpointer data)
130 {
131 GcrCertificateInfo *info = data;
132 if (info) {
133 g_assert (info->asn1);
134 egg_asn1x_destroy (info->asn1);
135 g_free (info);
136 }
137 }
138
139 static GcrCertificateInfo*
certificate_info_load(GcrCertificate * cert)140 certificate_info_load (GcrCertificate *cert)
141 {
142 GcrCertificateInfo *info;
143 GBytes *bytes;
144 GNode *asn1;
145 gconstpointer der;
146 gsize n_der;
147
148 g_assert (GCR_IS_CERTIFICATE (cert));
149
150 der = gcr_certificate_get_der_data (cert, &n_der);
151 if (der == NULL)
152 return NULL;
153
154 info = g_object_get_qdata (G_OBJECT (cert), CERTIFICATE_INFO);
155 if (info != NULL) {
156 if (n_der == info->n_der && der == info->der)
157 return info;
158 }
159
160 /* TODO: Once GBytes is public, add to GcrCertificate interface */
161 bytes = g_bytes_new_static (der, n_der);
162
163 /* Cache is invalid or non existent */
164 asn1 = egg_asn1x_create_and_decode (pkix_asn1_tab, "Certificate", bytes);
165
166 g_bytes_unref (bytes);
167
168 if (asn1 == NULL) {
169 g_warning ("a derived class provided an invalid or unparseable X.509 DER certificate data.");
170 return NULL;
171 }
172
173 info = g_new0 (GcrCertificateInfo, 1);
174 info->der = der;
175 info->n_der = n_der;
176 info->asn1 = asn1;
177
178 g_object_set_qdata_full (G_OBJECT (cert), CERTIFICATE_INFO, info, certificate_info_free);
179 return info;
180 }
181
182 static GChecksum*
digest_certificate(GcrCertificate * self,GChecksumType type)183 digest_certificate (GcrCertificate *self, GChecksumType type)
184 {
185 GChecksum *digest;
186 gconstpointer der;
187 gsize n_der;
188
189 g_assert (GCR_IS_CERTIFICATE (self));
190
191 der = gcr_certificate_get_der_data (self, &n_der);
192 if (der == NULL)
193 return NULL;
194
195 digest = g_checksum_new (type);
196 g_return_val_if_fail (digest, NULL);
197
198 g_checksum_update (digest, der, n_der);
199 return digest;
200 }
201
202 /**
203 * gcr_certificate_get_markup_text:
204 * @self: a certificate
205 *
206 * Calculate a GMarkup string for displaying this certificate.
207 *
208 * Returns: (transfer full): the markup string
209 */
210 gchar *
gcr_certificate_get_markup_text(GcrCertificate * self)211 gcr_certificate_get_markup_text (GcrCertificate *self)
212 {
213 gchar *label = NULL;
214 gchar *issuer;
215 gchar *markup;
216
217 g_object_get (self, "label", &label, NULL);
218 issuer = gcr_certificate_get_issuer_name (self);
219
220 if (issuer)
221 markup = g_markup_printf_escaped ("%s\n<small>Issued by: %s</small>", label, issuer);
222 else
223 markup = g_markup_printf_escaped ("%s\n<small>Issued by: <i>No name</i></small>", label);
224
225 g_free (label);
226 g_free (issuer);
227 return markup;
228 }
229
230 static void
on_transform_date_to_string(const GValue * src,GValue * dest)231 on_transform_date_to_string (const GValue *src, GValue *dest)
232 {
233 static const gsize len = 256;
234 GDate *date;
235 gchar *result;
236
237 g_return_if_fail (G_VALUE_TYPE (src) == G_TYPE_DATE);
238
239 date = g_value_get_boxed (src);
240 g_return_if_fail (date);
241
242 result = g_malloc0 (len);
243 if (!g_date_strftime (result, len, "%x", date)) {
244 g_free (result);
245 result = NULL;
246 }
247
248 g_value_take_string (dest, result);
249 }
250
251 /* ---------------------------------------------------------------------------------
252 * INTERFACE
253 */
254
255 static void
gcr_certificate_default_init(GcrCertificateIface * iface)256 gcr_certificate_default_init (GcrCertificateIface *iface)
257 {
258 static volatile gsize initialized = 0;
259
260 if (g_once_init_enter (&initialized)) {
261 CERTIFICATE_INFO = g_quark_from_static_string ("_gcr_certificate_certificate_info");
262
263 /**
264 * GcrCertificate:label:
265 *
266 * A readable label for this certificate.
267 */
268 g_object_interface_install_property (iface,
269 g_param_spec_string ("label", "Label", "Certificate label",
270 "", G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
271
272 /**
273 * GcrCertificate:description:
274 *
275 * A readable description for this certificate
276 */
277 g_object_interface_install_property (iface,
278 g_param_spec_string ("description", "Description", "Description of object being rendered",
279 "", G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
280
281 /**
282 * GcrCertificate:markup:
283 *
284 * GLib markup to describe the certificate
285 */
286 g_object_interface_install_property (iface,
287 g_param_spec_string ("markup", "Markup", "Markup which describes object being rendered",
288 "", G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
289
290 /**
291 * GcrCertificate:icon:
292 *
293 * An icon representing the certificate
294 */
295 g_object_interface_install_property (iface,
296 g_param_spec_object ("icon", "Icon", "Icon for the object being rendered",
297 G_TYPE_ICON, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
298
299 /**
300 * GcrCertificate:subject:
301 *
302 * Common name part of the certificate subject
303 */
304 g_object_interface_install_property (iface,
305 g_param_spec_string ("subject", "Subject", "Common name of subject",
306 "", G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
307
308 /**
309 * GcrCertificate:issuer:
310 *
311 * Common name part of the certificate issuer
312 */
313 g_object_interface_install_property (iface,
314 g_param_spec_string ("issuer", "Issuer", "Common name of issuer",
315 "", G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
316
317 /**
318 * GcrCertificate:expiry:
319 *
320 * The expiry date of the certificate
321 */
322 g_object_interface_install_property (iface,
323 g_param_spec_boxed ("expiry", "Expiry", "Certificate expiry",
324 G_TYPE_DATE, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
325
326 g_once_init_leave (&initialized, 1);
327 }
328 }
329
330 typedef GcrCertificateIface GcrCertificateInterface;
331
332 G_DEFINE_INTERFACE (GcrCertificate, gcr_certificate, GCR_TYPE_COMPARABLE);
333
334 /* -----------------------------------------------------------------------------
335 * PUBLIC
336 */
337
338 /**
339 * gcr_certificate_get_columns: (skip)
340 *
341 * Get the columns appropriate for a certificate
342 *
343 * Returns: (transfer none): the columns
344 */
345 const GcrColumn*
gcr_certificate_get_columns(void)346 gcr_certificate_get_columns (void)
347 {
348 static GcrColumn columns[] = {
349 { "icon", /* later */ 0, /* later */ 0, NULL, 0 },
350 { "label", G_TYPE_STRING, G_TYPE_STRING, NC_("column", "Name"),
351 GCR_COLUMN_SORTABLE },
352 { "issuer", G_TYPE_STRING, G_TYPE_STRING, NC_("column", "Issued By"),
353 GCR_COLUMN_SORTABLE },
354 { "expiry", /* later */ 0, G_TYPE_STRING, NC_("column", "Expires"),
355 GCR_COLUMN_SORTABLE, on_transform_date_to_string },
356 { NULL }
357 };
358
359 columns[0].property_type = columns[0].column_type = G_TYPE_ICON;
360 columns[3].property_type = G_TYPE_DATE;
361 return columns;
362 }
363
364 /**
365 * gcr_certificate_compare:
366 * @first: (nullable): the certificate to compare
367 * @other: (nullable): the certificate to compare against
368 *
369 * Compare one certificate against another. If the certificates are equal
370 * then zero is returned. If one certificate is %NULL or not a certificate,
371 * then a non-zero value is returned.
372 *
373 * The return value is useful in a stable sort, but has no user logical
374 * meaning.
375 *
376 * Returns: zero if the certificates match, non-zero otherwise.
377 */
378 gint
gcr_certificate_compare(GcrComparable * first,GcrComparable * other)379 gcr_certificate_compare (GcrComparable *first, GcrComparable *other)
380 {
381 gconstpointer data1, data2;
382 gsize size1, size2;
383
384 if (!GCR_IS_CERTIFICATE (first))
385 first = NULL;
386 if (!GCR_IS_CERTIFICATE (other))
387 other = NULL;
388
389 if (first == other)
390 return TRUE;
391 if (!first)
392 return 1;
393 if (!other)
394 return -1;
395
396 data1 = gcr_certificate_get_der_data (GCR_CERTIFICATE (first), &size1);
397 data2 = gcr_certificate_get_der_data (GCR_CERTIFICATE (other), &size2);
398
399 return gcr_comparable_memcmp (data1, size1, data2, size2);
400 }
401
402
403 /**
404 * gcr_certificate_get_der_data: (virtual get_der_data)
405 * @self: a #GcrCertificate
406 * @n_data: a pointer to a location to store the size of the resulting DER data.
407 *
408 * Gets the raw DER data for an X.509 certificate.
409 *
410 * Returns: (transfer none) (array length=n_data): raw DER data of the X.509 certificate
411 **/
412 const guint8 *
gcr_certificate_get_der_data(GcrCertificate * self,gsize * n_data)413 gcr_certificate_get_der_data (GcrCertificate *self,
414 gsize *n_data)
415 {
416 g_return_val_if_fail (GCR_IS_CERTIFICATE (self), NULL);
417 g_return_val_if_fail (n_data != NULL, NULL);
418 g_return_val_if_fail (GCR_CERTIFICATE_GET_INTERFACE (self)->get_der_data, NULL);
419 return GCR_CERTIFICATE_GET_INTERFACE (self)->get_der_data (self, n_data);
420 }
421
422 /**
423 * gcr_certificate_get_issuer_name:
424 * @self: a #GcrCertificate
425 *
426 * Get a name to represent the issuer of this certificate.
427 *
428 * This will try to lookup the common name, orianizational unit,
429 * organization in that order.
430 *
431 * Returns: the allocated issuer name, or %NULL if no issuer name
432 */
433 gchar *
gcr_certificate_get_issuer_name(GcrCertificate * self)434 gcr_certificate_get_issuer_name (GcrCertificate *self)
435 {
436 gchar *name;
437
438 name = gcr_certificate_get_issuer_part (self, "cn");
439 if (name == NULL)
440 name = gcr_certificate_get_issuer_part (self, "ou");
441 if (name == NULL)
442 name = gcr_certificate_get_issuer_part (self, "o");
443
444 return name;
445 }
446
447 /**
448 * gcr_certificate_get_issuer_cn:
449 * @self: a #GcrCertificate
450 *
451 * Get the common name of the issuer of this certificate.
452 *
453 * The string returned should be freed by the caller when no longer
454 * required.
455 *
456 * Returns: The allocated issuer CN, or %NULL if no issuer CN present.
457 */
458 gchar*
gcr_certificate_get_issuer_cn(GcrCertificate * self)459 gcr_certificate_get_issuer_cn (GcrCertificate *self)
460 {
461 return gcr_certificate_get_issuer_part (self, "cn");
462 }
463
464 /**
465 * gcr_certificate_get_issuer_part:
466 * @self: a #GcrCertificate
467 * @part: a DN type string or OID.
468 *
469 * Get a part of the DN of the issuer of this certificate.
470 *
471 * Examples of a @part might be the 'OU' (organizational unit)
472 * or the 'CN' (common name). Only the value of that part
473 * of the DN is returned.
474 *
475 * The string returned should be freed by the caller when no longer
476 * required.
477 *
478 * Returns: (nullable): the allocated part of the issuer DN, or %NULL if no
479 * such part is present
480 */
481 gchar *
gcr_certificate_get_issuer_part(GcrCertificate * self,const char * part)482 gcr_certificate_get_issuer_part (GcrCertificate *self, const char *part)
483 {
484 GcrCertificateInfo *info;
485
486 g_return_val_if_fail (GCR_IS_CERTIFICATE (self), NULL);
487 g_return_val_if_fail (part != NULL, NULL);
488
489 info = certificate_info_load (self);
490 if (info == NULL)
491 return NULL;
492
493 return egg_dn_read_part (egg_asn1x_node (info->asn1, "tbsCertificate", "issuer", "rdnSequence", NULL), part);
494 }
495
496 static GBytes *
_gcr_certificate_get_issuer_const(GcrCertificate * self)497 _gcr_certificate_get_issuer_const (GcrCertificate *self)
498 {
499 GcrCertificateInfo *info;
500
501 g_return_val_if_fail (GCR_IS_CERTIFICATE (self), NULL);
502
503 info = certificate_info_load (self);
504 if (info == NULL)
505 return NULL;
506
507 return egg_asn1x_get_element_raw (egg_asn1x_node (info->asn1, "tbsCertificate", "issuer", NULL));
508 }
509
510 /**
511 * gcr_certificate_get_issuer_raw:
512 * @self: a #GcrCertificate
513 * @n_data: The length of the returned data.
514 *
515 * Get the raw DER data for the issuer DN of the certificate.
516 *
517 * The data should be freed by using g_free() when no longer required.
518 *
519 * Returns: (transfer full) (array length=n_data): allocated memory containing
520 * the raw issuer
521 */
522 guchar *
gcr_certificate_get_issuer_raw(GcrCertificate * self,gsize * n_data)523 gcr_certificate_get_issuer_raw (GcrCertificate *self,
524 gsize *n_data)
525 {
526 GBytes *bytes;
527 guchar *result;
528
529 g_return_val_if_fail (GCR_IS_CERTIFICATE (self), NULL);
530 g_return_val_if_fail (n_data != NULL, NULL);
531
532 bytes = _gcr_certificate_get_issuer_const (self);
533 if (bytes == NULL)
534 return NULL;
535
536 *n_data = g_bytes_get_size (bytes);
537 result = g_memdup (g_bytes_get_data (bytes, NULL), *n_data);
538 g_bytes_unref (bytes);
539
540 return result;
541 }
542
543 /**
544 * gcr_certificate_is_issuer:
545 * @self: a #GcrCertificate
546 * @issuer: a possible issuer #GcrCertificate
547 *
548 * Check if @issuer could be the issuer of this certificate. This is done by
549 * comparing the relevant subject and issuer fields. No signature check is
550 * done. Proper verification of certificates must be done via a crypto
551 * library.
552 *
553 * Returns: whether @issuer could be the issuer of the certificate.
554 */
555 gboolean
gcr_certificate_is_issuer(GcrCertificate * self,GcrCertificate * issuer)556 gcr_certificate_is_issuer (GcrCertificate *self, GcrCertificate *issuer)
557 {
558 GBytes *subject_dn;
559 GBytes *issuer_dn;
560 gboolean ret;
561
562 g_return_val_if_fail (GCR_IS_CERTIFICATE (self), FALSE);
563 g_return_val_if_fail (GCR_IS_CERTIFICATE (issuer), FALSE);
564
565 subject_dn = _gcr_certificate_get_subject_const (issuer);
566 if (subject_dn == NULL)
567 return FALSE;
568
569 issuer_dn = _gcr_certificate_get_issuer_const (self);
570 if (issuer_dn == NULL)
571 return FALSE;
572
573 ret = g_bytes_equal (subject_dn, issuer_dn);
574
575 g_bytes_unref (subject_dn);
576 g_bytes_unref (issuer_dn);
577
578 return ret;
579 }
580
581 /**
582 * gcr_certificate_get_issuer_dn:
583 * @self: a #GcrCertificate
584 *
585 * Get the full issuer DN of the certificate as a (mostly)
586 * readable string.
587 *
588 * The string returned should be freed by the caller when no longer
589 * required.
590 *
591 * Returns: The allocated issuer DN of the certificate.
592 */
593 gchar*
gcr_certificate_get_issuer_dn(GcrCertificate * self)594 gcr_certificate_get_issuer_dn (GcrCertificate *self)
595 {
596 GcrCertificateInfo *info;
597
598 g_return_val_if_fail (GCR_IS_CERTIFICATE (self), NULL);
599
600 info = certificate_info_load (self);
601 if (info == NULL)
602 return NULL;
603
604 return egg_dn_read (egg_asn1x_node (info->asn1, "tbsCertificate", "issuer", "rdnSequence", NULL));
605 }
606
607 /**
608 * gcr_certificate_get_subject_cn:
609 * @self: a #GcrCertificate
610 *
611 * Get the common name of the subject of this certificate.
612 *
613 * The string returned should be freed by the caller when no longer
614 * required.
615 *
616 * Returns: The allocated subject CN, or %NULL if no subject CN present.
617 */
618 gchar*
gcr_certificate_get_subject_cn(GcrCertificate * self)619 gcr_certificate_get_subject_cn (GcrCertificate *self)
620 {
621 return gcr_certificate_get_subject_part (self, "cn");
622 }
623
624 /**
625 * gcr_certificate_get_subject_name:
626 * @self: a #GcrCertificate
627 *
628 * Get a name to represent the subject of this certificate.
629 *
630 * This will try to lookup the common name, orianizational unit,
631 * organization in that order.
632 *
633 * Returns: the allocated subject name, or %NULL if no subject name
634 */
635 gchar *
gcr_certificate_get_subject_name(GcrCertificate * self)636 gcr_certificate_get_subject_name (GcrCertificate *self)
637 {
638 gchar *name;
639
640 name = gcr_certificate_get_subject_part (self, "cn");
641 if (name == NULL)
642 name = gcr_certificate_get_subject_part (self, "ou");
643 if (name == NULL)
644 name = gcr_certificate_get_subject_part (self, "o");
645
646 return name;
647 }
648
649 /**
650 * gcr_certificate_get_subject_part:
651 * @self: a #GcrCertificate
652 * @part: a DN type string or OID.
653 *
654 * Get a part of the DN of the subject of this certificate.
655 *
656 * Examples of a @part might be the 'OU' (organizational unit)
657 * or the 'CN' (common name). Only the value of that part
658 * of the DN is returned.
659 *
660 * The string returned should be freed by the caller when no longer
661 * required.
662 *
663 * Returns: (nullable): the allocated part of the subject DN, or %NULL if no
664 * such part is present.
665 */
666 gchar*
gcr_certificate_get_subject_part(GcrCertificate * self,const char * part)667 gcr_certificate_get_subject_part (GcrCertificate *self, const char *part)
668 {
669 GcrCertificateInfo *info;
670
671 g_return_val_if_fail (GCR_IS_CERTIFICATE (self), NULL);
672 g_return_val_if_fail (part != NULL, NULL);
673
674 info = certificate_info_load (self);
675 if (info == NULL)
676 return NULL;
677
678 return egg_dn_read_part (egg_asn1x_node (info->asn1, "tbsCertificate", "subject", "rdnSequence", NULL), part);
679 }
680
681 /**
682 * gcr_certificate_get_subject_dn:
683 * @self: a #GcrCertificate
684 *
685 * Get the full subject DN of the certificate as a (mostly)
686 * readable string.
687 *
688 * The string returned should be freed by the caller when no longer
689 * required.
690 *
691 * Returns: The allocated subject DN of the certificate.
692 */
693 gchar*
gcr_certificate_get_subject_dn(GcrCertificate * self)694 gcr_certificate_get_subject_dn (GcrCertificate *self)
695 {
696 GcrCertificateInfo *info;
697
698 g_return_val_if_fail (GCR_IS_CERTIFICATE (self), NULL);
699
700 info = certificate_info_load (self);
701 if (info == NULL)
702 return NULL;
703
704 return egg_dn_read (egg_asn1x_node (info->asn1, "tbsCertificate", "subject", "rdnSequence", NULL));
705 }
706
707 static GBytes *
_gcr_certificate_get_subject_const(GcrCertificate * self)708 _gcr_certificate_get_subject_const (GcrCertificate *self)
709 {
710 GcrCertificateInfo *info;
711
712 g_return_val_if_fail (GCR_IS_CERTIFICATE (self), NULL);
713
714 info = certificate_info_load (self);
715 if (info == NULL)
716 return NULL;
717
718 return egg_asn1x_get_element_raw (egg_asn1x_node (info->asn1, "tbsCertificate", "subject", NULL));
719 }
720
721 /**
722 * gcr_certificate_get_subject_raw:
723 * @self: a #GcrCertificate
724 * @n_data: The length of the returned data.
725 *
726 * Get the raw DER data for the subject DN of the certificate.
727 *
728 * The data should be freed by using g_free() when no longer required.
729 *
730 * Returns: (transfer full) (array length=n_data): allocated memory containing
731 * the raw subject
732 */
733 guchar *
gcr_certificate_get_subject_raw(GcrCertificate * self,gsize * n_data)734 gcr_certificate_get_subject_raw (GcrCertificate *self, gsize *n_data)
735 {
736 GBytes *bytes;
737 guchar *result;
738
739 g_return_val_if_fail (GCR_IS_CERTIFICATE (self), NULL);
740 g_return_val_if_fail (n_data != NULL, NULL);
741
742 bytes = _gcr_certificate_get_subject_const (self);
743 if (bytes == NULL)
744 return NULL;
745
746 *n_data = g_bytes_get_size (bytes);
747 result = g_memdup (g_bytes_get_data (bytes, NULL), *n_data);
748
749 g_bytes_unref (bytes);
750
751 return result;
752 }
753
754 /**
755 * gcr_certificate_get_issued_date:
756 * @self: a #GcrCertificate
757 *
758 * Get the issued date of this certificate.
759 *
760 * The #GDate returned should be freed by the caller using
761 * g_date_free() when no longer required.
762 *
763 * Returns: An allocated issued date of this certificate.
764 */
765 GDate*
gcr_certificate_get_issued_date(GcrCertificate * self)766 gcr_certificate_get_issued_date (GcrCertificate *self)
767 {
768 GcrCertificateInfo *info;
769 GDate *date;
770
771 g_return_val_if_fail (GCR_IS_CERTIFICATE (self), NULL);
772
773 info = certificate_info_load (self);
774 if (info == NULL)
775 return NULL;
776
777 date = g_date_new ();
778 if (!egg_asn1x_get_time_as_date (egg_asn1x_node (info->asn1, "tbsCertificate", "validity", "notBefore", NULL), date)) {
779 g_date_free (date);
780 return NULL;
781 }
782
783 return date;
784 }
785
786 /**
787 * gcr_certificate_get_expiry_date:
788 * @self: a #GcrCertificate
789 *
790 * Get the expiry date of this certificate.
791 *
792 * The #GDate returned should be freed by the caller using
793 * g_date_free() when no longer required.
794 *
795 * Returns: An allocated expiry date of this certificate.
796 */
797 GDate*
gcr_certificate_get_expiry_date(GcrCertificate * self)798 gcr_certificate_get_expiry_date (GcrCertificate *self)
799 {
800 GcrCertificateInfo *info;
801 GDate *date;
802
803 g_return_val_if_fail (GCR_IS_CERTIFICATE (self), NULL);
804
805 info = certificate_info_load (self);
806 if (info == NULL)
807 return NULL;
808
809 date = g_date_new ();
810 if (!egg_asn1x_get_time_as_date (egg_asn1x_node (info->asn1, "tbsCertificate", "validity", "notAfter", NULL), date)) {
811 g_date_free (date);
812 return NULL;
813 }
814
815 return date;
816 }
817
818 /**
819 * gcr_certificate_get_key_size:
820 * @self: a #GcrCertificate
821 *
822 * Get the key size in bits of the public key represented
823 * by this certificate.
824 *
825 * Returns: The key size of the certificate.
826 */
827 guint
gcr_certificate_get_key_size(GcrCertificate * self)828 gcr_certificate_get_key_size (GcrCertificate *self)
829 {
830 GcrCertificateInfo *info;
831 GNode *subject_public_key;
832
833 g_return_val_if_fail (GCR_IS_CERTIFICATE (self), 0);
834
835 info = certificate_info_load (self);
836 if (info == NULL)
837 return 0;
838
839 if (!info->key_size) {
840 subject_public_key = egg_asn1x_node (info->asn1, "tbsCertificate",
841 "subjectPublicKeyInfo", NULL);
842 info->key_size = _gcr_subject_public_key_calculate_size (subject_public_key);
843 }
844
845 return info->key_size;
846 }
847
848 /**
849 * gcr_certificate_get_fingerprint:
850 * @self: a #GcrCertificate
851 * @type: the type of algorithm for the fingerprint.
852 * @n_length: The length of the resulting fingerprint.
853 *
854 * Calculate the fingerprint for this certificate.
855 *
856 * The caller should free the returned data using g_free() when
857 * it is no longer required.
858 *
859 * Returns: (array length=n_length): the raw binary fingerprint
860 **/
861 guchar *
gcr_certificate_get_fingerprint(GcrCertificate * self,GChecksumType type,gsize * n_length)862 gcr_certificate_get_fingerprint (GcrCertificate *self, GChecksumType type, gsize *n_length)
863 {
864 GChecksum *sum;
865 guchar *digest;
866 gssize length;
867
868 g_return_val_if_fail (GCR_IS_CERTIFICATE (self), NULL);
869 g_return_val_if_fail (n_length != NULL, NULL);
870
871 sum = digest_certificate (self, type);
872 if (sum == NULL)
873 return NULL;
874
875 length = g_checksum_type_get_length (type);
876 g_return_val_if_fail (length > 0, NULL);
877 digest = g_malloc (length);
878 *n_length = length;
879 g_checksum_get_digest (sum, digest, n_length);
880 g_checksum_free (sum);
881
882 return digest;
883 }
884
885 /**
886 * gcr_certificate_get_fingerprint_hex:
887 * @self: a #GcrCertificate
888 * @type: the type of algorithm for the fingerprint.
889 *
890 * Calculate the fingerprint for this certificate, and return it
891 * as a hex string.
892 *
893 * The caller should free the returned data using g_free() when
894 * it is no longer required.
895 *
896 * Returns: an allocated hex string which contains the fingerprint.
897 */
898 gchar*
gcr_certificate_get_fingerprint_hex(GcrCertificate * self,GChecksumType type)899 gcr_certificate_get_fingerprint_hex (GcrCertificate *self, GChecksumType type)
900 {
901 GChecksum *sum;
902 guchar *digest;
903 gsize n_digest;
904 gssize length;
905 gchar *hex;
906
907 g_return_val_if_fail (GCR_IS_CERTIFICATE (self), NULL);
908
909 sum = digest_certificate (self, type);
910 if (sum == NULL)
911 return NULL;
912
913 length = g_checksum_type_get_length (type);
914 g_return_val_if_fail (length > 0, NULL);
915 digest = g_malloc (length);
916 n_digest = length;
917 g_checksum_get_digest (sum, digest, &n_digest);
918 hex = egg_hex_encode_full (digest, n_digest, TRUE, " ", 1);
919 g_checksum_free (sum);
920 g_free (digest);
921 return hex;
922 }
923
924 /**
925 * gcr_certificate_get_serial_number:
926 * @self: a #GcrCertificate
927 * @n_length: the length of the returned data.
928 *
929 * Get the raw binary serial number of the certificate.
930 *
931 * The caller should free the returned data using g_free() when
932 * it is no longer required.
933 *
934 * Returns: (array length=n_length): the raw binary serial number.
935 */
936 guchar *
gcr_certificate_get_serial_number(GcrCertificate * self,gsize * n_length)937 gcr_certificate_get_serial_number (GcrCertificate *self, gsize *n_length)
938 {
939 GcrCertificateInfo *info;
940 GBytes *bytes;
941 guchar *result;
942
943 g_return_val_if_fail (GCR_IS_CERTIFICATE (self), NULL);
944 g_return_val_if_fail (n_length != NULL, NULL);
945
946 info = certificate_info_load (self);
947 if (info == NULL)
948 return NULL;
949
950 bytes = egg_asn1x_get_integer_as_raw (egg_asn1x_node (info->asn1, "tbsCertificate", "serialNumber", NULL));
951 g_return_val_if_fail (bytes != NULL, NULL);
952
953 *n_length = g_bytes_get_size (bytes);
954 result = g_memdup (g_bytes_get_data (bytes, NULL), *n_length);
955
956 g_bytes_unref (bytes);
957 return result;
958 }
959
960 /**
961 * gcr_certificate_get_serial_number_hex:
962 * @self: a #GcrCertificate
963 *
964 * Get the serial number of the certificate as a hex string.
965 *
966 * The caller should free the returned data using g_free() when
967 * it is no longer required.
968 *
969 * Returns: an allocated string containing the serial number as hex.
970 */
971 gchar*
gcr_certificate_get_serial_number_hex(GcrCertificate * self)972 gcr_certificate_get_serial_number_hex (GcrCertificate *self)
973 {
974 guchar *serial;
975 gsize n_serial;
976 gchar *hex;
977
978 g_return_val_if_fail (GCR_IS_CERTIFICATE (self), NULL);
979
980 serial = gcr_certificate_get_serial_number (self, &n_serial);
981 if (serial == NULL)
982 return NULL;
983
984 hex = egg_hex_encode (serial, n_serial);
985 g_free (serial);
986 return hex;
987 }
988
989 /**
990 * gcr_certificate_get_icon: (skip)
991 * @self: The certificate
992 *
993 * Get the icon for a certificate.
994 *
995 * Returns: (transfer full): the icon for this certificate, which should be
996 * released with g_object_unref()
997 */
998 GIcon *
gcr_certificate_get_icon(GcrCertificate * self)999 gcr_certificate_get_icon (GcrCertificate *self)
1000 {
1001 g_return_val_if_fail (GCR_IS_CERTIFICATE (self), FALSE);
1002 return g_themed_icon_new (GCR_ICON_CERTIFICATE);
1003 }
1004
1005 /**
1006 * gcr_certificate_get_basic_constraints:
1007 * @self: the certificate
1008 * @is_ca: (out) (optional): location to place a %TRUE if is an authority
1009 * @path_len: (out) (optional): location to place the max path length
1010 *
1011 * Get the basic constraints for the certificate if present. If %FALSE is
1012 * returned then no basic constraints are present and the @is_ca and
1013 * @path_len arguments are not changed.
1014 *
1015 * Returns: whether basic constraints are present or not
1016 */
1017 gboolean
gcr_certificate_get_basic_constraints(GcrCertificate * self,gboolean * is_ca,gint * path_len)1018 gcr_certificate_get_basic_constraints (GcrCertificate *self,
1019 gboolean *is_ca,
1020 gint *path_len)
1021 {
1022 GcrCertificateInfo *info;
1023 GBytes *value;
1024
1025 g_return_val_if_fail (GCR_IS_CERTIFICATE (self), FALSE);
1026
1027 info = certificate_info_load (self);
1028 if (info == NULL)
1029 return FALSE;
1030
1031 value = _gcr_certificate_extension_find (info->asn1, GCR_OID_BASIC_CONSTRAINTS, NULL);
1032 if (!value)
1033 return FALSE;
1034
1035 if (!_gcr_certificate_extension_basic_constraints (value, is_ca, path_len))
1036 g_return_val_if_reached (FALSE);
1037
1038 g_bytes_unref (value);
1039 return TRUE;
1040 }
1041
1042 /* -----------------------------------------------------------------------------
1043 * MIXIN
1044 */
1045
1046 /**
1047 * GCR_CERTIFICATE_MIXIN_IMPLEMENT_COMPARABLE:
1048 *
1049 * Implement the GcrComparable interface. Use this macro like this:
1050 *
1051 * <informalexample><programlisting>
1052 * G_DEFINE_TYPE_WITH_CODE (MyCertificate, my_certificate, G_TYPE_OBJECT,
1053 * GCR_CERTIFICATE_MIXIN_IMPLEMENT_COMPARABLE ();
1054 * G_IMPLEMENT_INTERFACE (GCR_TYPE_CERTIFICATE, my_certificate_iface_init);
1055 * );
1056 * </programlisting></informalexample>
1057 */
1058
1059 /**
1060 * gcr_certificate_mixin_emit_notify:
1061 * @self: the #GcrCertificate
1062 *
1063 * Implementers of the #GcrCertificate mixin should call this function to notify
1064 * when the certificate has changed to emit notifications on the various
1065 * properties.
1066 */
1067 void
gcr_certificate_mixin_emit_notify(GcrCertificate * self)1068 gcr_certificate_mixin_emit_notify (GcrCertificate *self)
1069 {
1070 GObject *obj;
1071
1072 g_return_if_fail (GCR_IS_CERTIFICATE (self));
1073
1074 obj = G_OBJECT (self);
1075 g_object_notify (obj, "label");
1076 g_object_notify (obj, "markup");
1077 g_object_notify (obj, "subject");
1078 g_object_notify (obj, "issuer");
1079 g_object_notify (obj, "expiry");
1080 }
1081
1082 /**
1083 * gcr_certificate_mixin_comparable_init: (skip)
1084 * @iface: The interface
1085 *
1086 * Initialize a #GcrComparableIface to compare the current certificate.
1087 * In general it's easier to use the GCR_CERTIFICATE_MIXIN_IMPLEMENT_COMPARABLE()
1088 * macro instead of this function.
1089 */
1090 void
gcr_certificate_mixin_comparable_init(GcrComparableIface * iface)1091 gcr_certificate_mixin_comparable_init (GcrComparableIface *iface)
1092 {
1093 iface->compare = gcr_certificate_compare;
1094 }
1095
1096 /**
1097 * gcr_certificate_mixin_class_init: (skip)
1098 * @object_class: The GObjectClass for this class
1099 *
1100 * Initialize the certificate mixin for the class. This mixin implements the
1101 * various required properties for the certificate.
1102 *
1103 * Call this function near the end of your derived class_init function. The
1104 * derived class must implement the #GcrCertificate interface.
1105 */
1106 void
gcr_certificate_mixin_class_init(GObjectClass * object_class)1107 gcr_certificate_mixin_class_init (GObjectClass *object_class)
1108 {
1109 if (!g_object_class_find_property (object_class, "description"))
1110 g_object_class_override_property (object_class, PROP_DESCRIPTION, "description");
1111 if (!g_object_class_find_property (object_class, "markup"))
1112 g_object_class_override_property (object_class, PROP_MARKUP, "markup");
1113 if (!g_object_class_find_property (object_class, "label"))
1114 g_object_class_override_property (object_class, PROP_LABEL, "label");
1115 if (!g_object_class_find_property (object_class, "icon"))
1116 g_object_class_override_property (object_class, PROP_ICON, "icon");
1117 if (!g_object_class_find_property (object_class, "subject"))
1118 g_object_class_override_property (object_class, PROP_SUBJECT, "subject");
1119 if (!g_object_class_find_property (object_class, "issuer"))
1120 g_object_class_override_property (object_class, PROP_ISSUER, "issuer");
1121 if (!g_object_class_find_property (object_class, "expiry"))
1122 g_object_class_override_property (object_class, PROP_EXPIRY, "expiry");
1123
1124 _gcr_initialize_library ();
1125 }
1126
1127 /**
1128 * gcr_certificate_mixin_get_property: (skip)
1129 * @obj: The object
1130 * @prop_id: The property id
1131 * @value: The value to fill in.
1132 * @pspec: The param specification.
1133 *
1134 * Implementation to get various required certificate properties. This should
1135 * be called from your derived class get_property function, or used as a
1136 * get_property virtual function.
1137 *
1138 * Example of use as called from derived class get_property function:
1139 *
1140 * <informalexample><programlisting>
1141 * static void
1142 * my_get_property (GObject *obj, guint prop_id, GValue *value, GParamSpec *pspec)
1143 * {
1144 * switch (prop_id) {
1145 *
1146 * ...
1147 *
1148 * default:
1149 * gcr_certificate_mixin_get_property (obj, prop_id, value, pspec);
1150 * break;
1151 * }
1152 *}
1153 * </programlisting></informalexample>
1154 *
1155 * Example of use as get_property function:
1156 *
1157 * <informalexample><programlisting>
1158 * static void
1159 * my_class_init (MyClass *klass)
1160 * {
1161 * GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
1162 * gobject_class->get_property = gcr_certificate_mixin_get_property;
1163 *
1164 * ...
1165 * }
1166 * </programlisting></informalexample>
1167
1168 */
1169 void
gcr_certificate_mixin_get_property(GObject * obj,guint prop_id,GValue * value,GParamSpec * pspec)1170 gcr_certificate_mixin_get_property (GObject *obj, guint prop_id,
1171 GValue *value, GParamSpec *pspec)
1172 {
1173 GcrCertificate *cert = GCR_CERTIFICATE (obj);
1174
1175 switch (prop_id) {
1176 case PROP_LABEL:
1177 g_value_take_string (value, gcr_certificate_get_subject_name (cert));
1178 break;
1179 case PROP_SUBJECT:
1180 g_value_take_string (value, gcr_certificate_get_subject_name (cert));
1181 break;
1182 case PROP_ICON:
1183 g_value_set_object (value, gcr_certificate_get_icon (cert));
1184 break;
1185 case PROP_DESCRIPTION:
1186 g_value_set_string (value, _("Certificate"));
1187 break;
1188 case PROP_MARKUP:
1189 g_value_take_string (value, gcr_certificate_get_markup_text (cert));
1190 break;
1191 case PROP_ISSUER:
1192 g_value_take_string (value, gcr_certificate_get_issuer_name (cert));
1193 break;
1194 case PROP_EXPIRY:
1195 g_value_take_boxed (value, gcr_certificate_get_expiry_date (cert));
1196 break;
1197 default:
1198 G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
1199 break;
1200 }
1201 }
1202