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