Branch data Line data Source code
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-certificate-field.h"
25 : : #include "gcr-certificate-field-private.h"
26 : : #include "gcr-fingerprint.h"
27 : : #include "gcr-internal.h"
28 : : #include "gcr-subject-public-key.h"
29 : :
30 : : #include "gcr/gcr-oids.h"
31 : :
32 : : #include "egg/egg-asn1x.h"
33 : : #include "egg/egg-asn1-defs.h"
34 : : #include "egg/egg-dn.h"
35 : : #include "egg/egg-hex.h"
36 : : #include "egg/egg-oid.h"
37 : :
38 : : #include <string.h>
39 : : #include <glib/gi18n-lib.h>
40 : :
41 : : /**
42 : : * GcrCertificate:
43 : : *
44 : : * An interface that represents an X.509 certificate.
45 : : *
46 : : * Objects can implement this interface to make a certificate usable with the
47 : : * GCR library.
48 : : *
49 : : * Various methods are available to parse out relevant bits of the certificate.
50 : : * However no verification of the validity of a certificate is done here. Use
51 : : * your favorite crypto library to do this.
52 : : *
53 : : * You can use [class@SimpleCertificate] to simply load a certificate for which
54 : : * you already have the raw certificate data.
55 : : *
56 : : * The #GcrCertificate interface has several properties that must be implemented.
57 : : * You can use a mixin to implement these properties if desired. See the
58 : : * gcr_certificate_mixin_class_init() and gcr_certificate_mixin_get_property()
59 : : * functions.
60 : : */
61 : :
62 : : /**
63 : : * GcrCertificateIface:
64 : : * @parent: the parent interface type
65 : : * @get_der_data: a method which returns the RAW der data of the certificate
66 : : *
67 : : * The interface that implementors of #GcrCertificate must implement.
68 : : */
69 : :
70 : : /*
71 : : * The DER data in this structure is owned by the derived class.
72 : : * It is only valid for the duration of the current call stack
73 : : * after we call gcr_certificate_get_der_data(). We shouldn't
74 : : * save it anywhere else.
75 : : *
76 : : * We keep the pointer around and compare it so that if the derived
77 : : * class returns exactly the same pointer and size, then we can
78 : : * keep from parsing things over again.
79 : : */
80 : :
81 : : typedef struct _GcrCertificateInfo {
82 : : gconstpointer der;
83 : : gsize n_der;
84 : : GNode *asn1;
85 : : guint key_size;
86 : : } GcrCertificateInfo;
87 : :
88 : : /* Forward declarations */
89 : :
90 : : static GBytes * _gcr_certificate_get_subject_const (GcrCertificate *self);
91 : : static GBytes * _gcr_certificate_get_issuer_const (GcrCertificate *self);
92 : :
93 : : enum {
94 : : PROP_FIRST = 0x0007000,
95 : : PROP_LABEL,
96 : : PROP_DESCRIPTION,
97 : : PROP_SUBJECT_NAME,
98 : : PROP_ISSUER_NAME,
99 : : PROP_EXPIRY_DATE
100 : : };
101 : :
102 : : /* -----------------------------------------------------------------------------
103 : : * INTERNAL
104 : : */
105 : :
106 : : static GQuark CERTIFICATE_INFO = 0;
107 : :
108 : : static void
109 : 52 : certificate_info_free (gpointer data)
110 : : {
111 : 52 : GcrCertificateInfo *info = data;
112 [ + - ]: 52 : if (info) {
113 [ - + ]: 52 : g_assert (info->asn1);
114 : 52 : egg_asn1x_destroy (info->asn1);
115 : 52 : g_free (info);
116 : : }
117 : 52 : }
118 : :
119 : : static GcrCertificateInfo*
120 : 105 : certificate_info_load (GcrCertificate *cert)
121 : : {
122 : : GcrCertificateInfo *info;
123 : : GBytes *bytes;
124 : : GNode *asn1;
125 : : gconstpointer der;
126 : : gsize n_der;
127 : :
128 [ - + + - : 105 : g_assert (GCR_IS_CERTIFICATE (cert));
- + - + ]
129 : :
130 : 105 : der = gcr_certificate_get_der_data (cert, &n_der);
131 [ - + ]: 105 : if (der == NULL)
132 : 0 : return NULL;
133 : :
134 : 105 : info = g_object_get_qdata (G_OBJECT (cert), CERTIFICATE_INFO);
135 [ + + ]: 105 : if (info != NULL) {
136 [ + - + - ]: 53 : if (n_der == info->n_der && der == info->der)
137 : 53 : return info;
138 : : }
139 : :
140 : : /* TODO: Once GBytes is public, add to GcrCertificate interface */
141 : 52 : bytes = g_bytes_new_static (der, n_der);
142 : :
143 : : /* Cache is invalid or non existent */
144 : 52 : asn1 = egg_asn1x_create_and_decode (pkix_asn1_tab, "Certificate", bytes);
145 : :
146 : 52 : g_bytes_unref (bytes);
147 : :
148 [ - + ]: 52 : if (asn1 == NULL) {
149 : 0 : g_warning ("a derived class provided an invalid or unparseable X.509 DER certificate data.");
150 : 0 : return NULL;
151 : : }
152 : :
153 : 52 : info = g_new0 (GcrCertificateInfo, 1);
154 : 52 : info->der = der;
155 : 52 : info->n_der = n_der;
156 : 52 : info->asn1 = asn1;
157 : :
158 : 52 : g_object_set_qdata_full (G_OBJECT (cert), CERTIFICATE_INFO, info, certificate_info_free);
159 : 52 : return info;
160 : : }
161 : :
162 : : static GChecksum*
163 : 2 : digest_certificate (GcrCertificate *self, GChecksumType type)
164 : : {
165 : : GChecksum *digest;
166 : : gconstpointer der;
167 : : gsize n_der;
168 : :
169 [ - + + - : 2 : g_assert (GCR_IS_CERTIFICATE (self));
- + - + ]
170 : :
171 : 2 : der = gcr_certificate_get_der_data (self, &n_der);
172 [ - + ]: 2 : if (der == NULL)
173 : 0 : return NULL;
174 : :
175 : 2 : digest = g_checksum_new (type);
176 [ - + ]: 2 : g_return_val_if_fail (digest, NULL);
177 : :
178 : 2 : g_checksum_update (digest, der, n_der);
179 : 2 : return digest;
180 : : }
181 : :
182 : : /* ---------------------------------------------------------------------------------
183 : : * INTERFACE
184 : : */
185 : :
186 : : static void
187 : 5 : gcr_certificate_default_init (GcrCertificateIface *iface)
188 : : {
189 : : static size_t initialized = 0;
190 : :
191 [ + - + - : 5 : if (g_once_init_enter (&initialized)) {
+ - ]
192 : 5 : CERTIFICATE_INFO = g_quark_from_static_string ("_gcr_certificate_certificate_info");
193 : :
194 : : /**
195 : : * GcrCertificate:label:
196 : : *
197 : : * A readable label for this certificate.
198 : : */
199 : 5 : g_object_interface_install_property (iface,
200 : : g_param_spec_string ("label", "Label", "Certificate label",
201 : : "", G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
202 : :
203 : : /**
204 : : * GcrCertificate:description:
205 : : *
206 : : * A readable description for this certificate
207 : : */
208 : 5 : g_object_interface_install_property (iface,
209 : : g_param_spec_string ("description", "Description", "Description of object being rendered",
210 : : "", G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
211 : :
212 : : /**
213 : : * GcrCertificate:subject:
214 : : *
215 : : * Common name part of the certificate subject
216 : : */
217 : 5 : g_object_interface_install_property (iface,
218 : : g_param_spec_string ("subject-name", "Subject name", "Common name of subject",
219 : : "", G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
220 : :
221 : : /**
222 : : * GcrCertificate:issuer-name:
223 : : *
224 : : * Common name part of the certificate issuer
225 : : */
226 : 5 : g_object_interface_install_property (iface,
227 : : g_param_spec_string ("issuer-name", "Issuer name", "Common name of issuer",
228 : : "", G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
229 : :
230 : : /**
231 : : * GcrCertificate:expiry-date:
232 : : *
233 : : * The expiry date of the certificate
234 : : */
235 : 5 : g_object_interface_install_property (iface,
236 : : g_param_spec_boxed ("expiry-date", "Expiry date", "Certificate expiry date",
237 : : G_TYPE_DATE_TIME, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
238 : :
239 : 5 : g_once_init_leave (&initialized, 1);
240 : : }
241 : 5 : }
242 : :
243 : : typedef GcrCertificateIface GcrCertificateInterface;
244 : :
245 [ + + + - : 1046 : G_DEFINE_INTERFACE (GcrCertificate, gcr_certificate, G_TYPE_OBJECT);
+ + ]
246 : :
247 : : /* -----------------------------------------------------------------------------
248 : : * PUBLIC
249 : : */
250 : :
251 : :
252 : : /**
253 : : * gcr_certificate_get_der_data: (virtual get_der_data)
254 : : * @self: a #GcrCertificate
255 : : * @n_data: a pointer to a location to store the size of the resulting DER data.
256 : : *
257 : : * Gets the raw DER data for an X.509 certificate.
258 : : *
259 : : * Returns: (transfer none) (array length=n_data): raw DER data of the X.509 certificate
260 : : **/
261 : : const guint8 *
262 : 149 : gcr_certificate_get_der_data (GcrCertificate *self,
263 : : gsize *n_data)
264 : : {
265 [ - + + - : 149 : g_return_val_if_fail (GCR_IS_CERTIFICATE (self), NULL);
- + - + ]
266 [ - + ]: 149 : g_return_val_if_fail (n_data != NULL, NULL);
267 [ - + ]: 149 : g_return_val_if_fail (GCR_CERTIFICATE_GET_INTERFACE (self)->get_der_data, NULL);
268 : 149 : return GCR_CERTIFICATE_GET_INTERFACE (self)->get_der_data (self, n_data);
269 : : }
270 : :
271 : : /**
272 : : * gcr_certificate_get_issuer_name:
273 : : * @self: a #GcrCertificate
274 : : *
275 : : * Get a name to represent the issuer of this certificate.
276 : : *
277 : : * This will try to lookup the common name, orianizational unit,
278 : : * organization in that order.
279 : : *
280 : : * Returns: (nullable): the allocated issuer name, or %NULL if no issuer name
281 : : */
282 : : gchar *
283 : 0 : gcr_certificate_get_issuer_name (GcrCertificate *self)
284 : : {
285 : : gchar *name;
286 : :
287 : 0 : name = gcr_certificate_get_issuer_part (self, "cn");
288 [ # # ]: 0 : if (name == NULL)
289 : 0 : name = gcr_certificate_get_issuer_part (self, "ou");
290 [ # # ]: 0 : if (name == NULL)
291 : 0 : name = gcr_certificate_get_issuer_part (self, "o");
292 : :
293 : 0 : return name;
294 : : }
295 : :
296 : : /**
297 : : * gcr_certificate_get_issuer_cn:
298 : : * @self: a #GcrCertificate
299 : : *
300 : : * Get the common name of the issuer of this certificate.
301 : : *
302 : : * The string returned should be freed by the caller when no longer
303 : : * required.
304 : : *
305 : : * Returns: (nullable): The allocated issuer CN, or %NULL if no issuer CN present.
306 : : */
307 : : gchar*
308 : 2 : gcr_certificate_get_issuer_cn (GcrCertificate *self)
309 : : {
310 : 2 : return gcr_certificate_get_issuer_part (self, "cn");
311 : : }
312 : :
313 : : /**
314 : : * gcr_certificate_get_issuer_part:
315 : : * @self: a #GcrCertificate
316 : : * @part: a DN type string or OID.
317 : : *
318 : : * Get a part of the DN of the issuer of this certificate.
319 : : *
320 : : * Examples of a @part might be the 'OU' (organizational unit)
321 : : * or the 'CN' (common name). Only the value of that part
322 : : * of the DN is returned.
323 : : *
324 : : * The string returned should be freed by the caller when no longer
325 : : * required.
326 : : *
327 : : * Returns: (nullable): the allocated part of the issuer DN, or %NULL if no
328 : : * such part is present
329 : : */
330 : : gchar *
331 : 3 : gcr_certificate_get_issuer_part (GcrCertificate *self, const char *part)
332 : : {
333 : : GcrCertificateInfo *info;
334 : :
335 [ - + + - : 3 : g_return_val_if_fail (GCR_IS_CERTIFICATE (self), NULL);
- + - + ]
336 [ - + ]: 3 : g_return_val_if_fail (part != NULL, NULL);
337 : :
338 : 3 : info = certificate_info_load (self);
339 [ - + ]: 3 : if (info == NULL)
340 : 0 : return NULL;
341 : :
342 : 3 : return egg_dn_read_part (egg_asn1x_node (info->asn1, "tbsCertificate", "issuer", "rdnSequence", NULL), part);
343 : : }
344 : :
345 : : static GBytes *
346 : 34 : _gcr_certificate_get_issuer_const (GcrCertificate *self)
347 : : {
348 : : GcrCertificateInfo *info;
349 : :
350 [ - + + - : 34 : g_return_val_if_fail (GCR_IS_CERTIFICATE (self), NULL);
- + - + ]
351 : :
352 : 34 : info = certificate_info_load (self);
353 [ - + ]: 34 : if (info == NULL)
354 : 0 : return NULL;
355 : :
356 : 34 : return egg_asn1x_get_element_raw (egg_asn1x_node (info->asn1, "tbsCertificate", "issuer", NULL));
357 : : }
358 : :
359 : : /**
360 : : * gcr_certificate_get_issuer_raw:
361 : : * @self: a #GcrCertificate
362 : : * @n_data: (out): The length of the returned data.
363 : : *
364 : : * Get the raw DER data for the issuer DN of the certificate.
365 : : *
366 : : * The data should be freed by using g_free() when no longer required.
367 : : *
368 : : * Returns: (transfer full) (array length=n_data) (nullable): allocated memory
369 : : * containing the raw issuer
370 : : */
371 : : guchar *
372 : 14 : gcr_certificate_get_issuer_raw (GcrCertificate *self,
373 : : gsize *n_data)
374 : : {
375 : : GBytes *bytes;
376 : : guchar *result;
377 : :
378 [ - + + - : 14 : g_return_val_if_fail (GCR_IS_CERTIFICATE (self), NULL);
- + - + ]
379 [ - + ]: 14 : g_return_val_if_fail (n_data != NULL, NULL);
380 : :
381 : 14 : bytes = _gcr_certificate_get_issuer_const (self);
382 [ - + ]: 14 : if (bytes == NULL) {
383 : 0 : *n_data = 0;
384 : 0 : return NULL;
385 : : }
386 : :
387 : 14 : *n_data = g_bytes_get_size (bytes);
388 : 14 : result = g_memdup2 (g_bytes_get_data (bytes, NULL), *n_data);
389 : 14 : g_bytes_unref (bytes);
390 : :
391 : 14 : return result;
392 : : }
393 : :
394 : : /**
395 : : * gcr_certificate_is_issuer:
396 : : * @self: a #GcrCertificate
397 : : * @issuer: a possible issuer #GcrCertificate
398 : : *
399 : : * Check if @issuer could be the issuer of this certificate. This is done by
400 : : * comparing the relevant subject and issuer fields. No signature check is
401 : : * done. Proper verification of certificates must be done via a crypto
402 : : * library.
403 : : *
404 : : * Returns: whether @issuer could be the issuer of the certificate.
405 : : */
406 : : gboolean
407 : 20 : gcr_certificate_is_issuer (GcrCertificate *self, GcrCertificate *issuer)
408 : : {
409 : : GBytes *subject_dn;
410 : : GBytes *issuer_dn;
411 : : gboolean ret;
412 : :
413 [ - + + - : 20 : g_return_val_if_fail (GCR_IS_CERTIFICATE (self), FALSE);
- + - + ]
414 [ - + + - : 20 : g_return_val_if_fail (GCR_IS_CERTIFICATE (issuer), FALSE);
- + - + ]
415 : :
416 : 20 : subject_dn = _gcr_certificate_get_subject_const (issuer);
417 [ - + ]: 20 : if (subject_dn == NULL)
418 : 0 : return FALSE;
419 : :
420 : 20 : issuer_dn = _gcr_certificate_get_issuer_const (self);
421 [ - + ]: 20 : if (issuer_dn == NULL)
422 : 0 : return FALSE;
423 : :
424 : 20 : ret = g_bytes_equal (subject_dn, issuer_dn);
425 : :
426 : 20 : g_bytes_unref (subject_dn);
427 : 20 : g_bytes_unref (issuer_dn);
428 : :
429 : 20 : return ret;
430 : : }
431 : :
432 : : /**
433 : : * gcr_certificate_get_issuer_dn:
434 : : * @self: a #GcrCertificate
435 : : *
436 : : * Get the full issuer DN of the certificate as a (mostly)
437 : : * readable string.
438 : : *
439 : : * The string returned should be freed by the caller when no longer
440 : : * required.
441 : : *
442 : : * Returns: (nullable): The allocated issuer DN of the certificate.
443 : : */
444 : : gchar*
445 : 1 : gcr_certificate_get_issuer_dn (GcrCertificate *self)
446 : : {
447 : : GcrCertificateInfo *info;
448 : :
449 [ - + + - : 1 : g_return_val_if_fail (GCR_IS_CERTIFICATE (self), NULL);
- + - + ]
450 : :
451 : 1 : info = certificate_info_load (self);
452 [ - + ]: 1 : if (info == NULL)
453 : 0 : return NULL;
454 : :
455 : 1 : return egg_dn_read (egg_asn1x_node (info->asn1, "tbsCertificate", "issuer", "rdnSequence", NULL));
456 : : }
457 : :
458 : : /**
459 : : * gcr_certificate_get_subject_cn:
460 : : * @self: a #GcrCertificate
461 : : *
462 : : * Get the common name of the subject of this certificate.
463 : : *
464 : : * The string returned should be freed by the caller when no longer
465 : : * required.
466 : : *
467 : : * Returns: (nullable): The allocated subject CN, or %NULL if no subject CN present.
468 : : */
469 : : gchar*
470 : 3 : gcr_certificate_get_subject_cn (GcrCertificate *self)
471 : : {
472 : 3 : return gcr_certificate_get_subject_part (self, "cn");
473 : : }
474 : :
475 : : /**
476 : : * gcr_certificate_get_subject_name:
477 : : * @self: a #GcrCertificate
478 : : *
479 : : * Get a name to represent the subject of this certificate.
480 : : *
481 : : * This will try to lookup the common name, orianizational unit,
482 : : * organization in that order.
483 : : *
484 : : * Returns: (nullable): the allocated subject name, or %NULL if no subject name
485 : : */
486 : : gchar *
487 : 1 : gcr_certificate_get_subject_name (GcrCertificate *self)
488 : : {
489 : : gchar *name;
490 : :
491 : 1 : name = gcr_certificate_get_subject_part (self, "cn");
492 [ - + ]: 1 : if (name == NULL)
493 : 0 : name = gcr_certificate_get_subject_part (self, "ou");
494 [ - + ]: 1 : if (name == NULL)
495 : 0 : name = gcr_certificate_get_subject_part (self, "o");
496 : :
497 : 1 : return name;
498 : : }
499 : :
500 : : /**
501 : : * gcr_certificate_get_subject_part:
502 : : * @self: a #GcrCertificate
503 : : * @part: a DN type string or OID.
504 : : *
505 : : * Get a part of the DN of the subject of this certificate.
506 : : *
507 : : * Examples of a @part might be the 'OU' (organizational unit)
508 : : * or the 'CN' (common name). Only the value of that part
509 : : * of the DN is returned.
510 : : *
511 : : * The string returned should be freed by the caller when no longer
512 : : * required.
513 : : *
514 : : * Returns: (nullable): the allocated part of the subject DN, or %NULL if no
515 : : * such part is present.
516 : : */
517 : : gchar*
518 : 6 : gcr_certificate_get_subject_part (GcrCertificate *self, const char *part)
519 : : {
520 : : GcrCertificateInfo *info;
521 : :
522 [ - + + - : 6 : g_return_val_if_fail (GCR_IS_CERTIFICATE (self), NULL);
- + - + ]
523 [ - + ]: 6 : g_return_val_if_fail (part != NULL, NULL);
524 : :
525 : 6 : info = certificate_info_load (self);
526 [ - + ]: 6 : if (info == NULL)
527 : 0 : return NULL;
528 : :
529 : 6 : return egg_dn_read_part (egg_asn1x_node (info->asn1, "tbsCertificate", "subject", "rdnSequence", NULL), part);
530 : : }
531 : :
532 : : /**
533 : : * gcr_certificate_get_subject_dn:
534 : : * @self: a #GcrCertificate
535 : : *
536 : : * Get the full subject DN of the certificate as a (mostly)
537 : : * readable string.
538 : : *
539 : : * The string returned should be freed by the caller when no longer
540 : : * required.
541 : : *
542 : : * Returns: (nullable): The allocated subject DN of the certificate.
543 : : */
544 : : gchar*
545 : 19 : gcr_certificate_get_subject_dn (GcrCertificate *self)
546 : : {
547 : : GcrCertificateInfo *info;
548 : :
549 [ - + + - : 19 : g_return_val_if_fail (GCR_IS_CERTIFICATE (self), NULL);
- + - + ]
550 : :
551 : 19 : info = certificate_info_load (self);
552 [ - + ]: 19 : if (info == NULL)
553 : 0 : return NULL;
554 : :
555 : 19 : return egg_dn_read (egg_asn1x_node (info->asn1, "tbsCertificate", "subject", "rdnSequence", NULL));
556 : : }
557 : :
558 : : static GBytes *
559 : 27 : _gcr_certificate_get_subject_const (GcrCertificate *self)
560 : : {
561 : : GcrCertificateInfo *info;
562 : :
563 [ - + + - : 27 : g_return_val_if_fail (GCR_IS_CERTIFICATE (self), NULL);
- + - + ]
564 : :
565 : 27 : info = certificate_info_load (self);
566 [ - + ]: 27 : if (info == NULL)
567 : 0 : return NULL;
568 : :
569 : 27 : return egg_asn1x_get_element_raw (egg_asn1x_node (info->asn1, "tbsCertificate", "subject", NULL));
570 : : }
571 : :
572 : : /**
573 : : * gcr_certificate_get_subject_raw:
574 : : * @self: a #GcrCertificate
575 : : * @n_data: (out): The length of the returned data.
576 : : *
577 : : * Get the raw DER data for the subject DN of the certificate.
578 : : *
579 : : * The data should be freed by using g_free() when no longer required.
580 : : *
581 : : * Returns: (transfer full) (array length=n_data) (nullable): allocated memory
582 : : * containing the raw subject
583 : : */
584 : : guchar *
585 : 7 : gcr_certificate_get_subject_raw (GcrCertificate *self, gsize *n_data)
586 : : {
587 : : GBytes *bytes;
588 : : guchar *result;
589 : :
590 [ - + + - : 7 : g_return_val_if_fail (GCR_IS_CERTIFICATE (self), NULL);
- + - + ]
591 [ - + ]: 7 : g_return_val_if_fail (n_data != NULL, NULL);
592 : :
593 : 7 : bytes = _gcr_certificate_get_subject_const (self);
594 [ - + ]: 7 : if (bytes == NULL) {
595 : 0 : *n_data = 0;
596 : 0 : return NULL;
597 : : }
598 : :
599 : 7 : *n_data = g_bytes_get_size (bytes);
600 : 7 : result = g_memdup2 (g_bytes_get_data (bytes, NULL), *n_data);
601 : :
602 : 7 : g_bytes_unref (bytes);
603 : :
604 : 7 : return result;
605 : : }
606 : :
607 : : /**
608 : : * gcr_certificate_get_issued_date:
609 : : * @self: a #GcrCertificate
610 : : *
611 : : * Get the issued date of this certificate.
612 : : *
613 : : * Returns: (nullable): A issued date of this certificate.
614 : : */
615 : : GDateTime *
616 : 2 : gcr_certificate_get_issued_date (GcrCertificate *self)
617 : : {
618 : : GcrCertificateInfo *info;
619 : :
620 [ - + + - : 2 : g_return_val_if_fail (GCR_IS_CERTIFICATE (self), NULL);
- + - + ]
621 : :
622 : 2 : info = certificate_info_load (self);
623 [ - + ]: 2 : if (info == NULL)
624 : 0 : return NULL;
625 : :
626 : 2 : return egg_asn1x_get_time_as_date_time (egg_asn1x_node (info->asn1, "tbsCertificate", "validity", "notBefore", NULL));
627 : : }
628 : :
629 : : /**
630 : : * gcr_certificate_get_expiry_date:
631 : : * @self: a #GcrCertificate
632 : : *
633 : : * Get the expiry date of this certificate.
634 : : *
635 : : * Returns: (nullable): An expiry date of this certificate.
636 : : */
637 : : GDateTime *
638 : 3 : gcr_certificate_get_expiry_date (GcrCertificate *self)
639 : : {
640 : : GcrCertificateInfo *info;
641 : :
642 [ - + + - : 3 : g_return_val_if_fail (GCR_IS_CERTIFICATE (self), NULL);
- + - + ]
643 : :
644 : 3 : info = certificate_info_load (self);
645 [ - + ]: 3 : if (info == NULL)
646 : 0 : return NULL;
647 : :
648 : 3 : return egg_asn1x_get_time_as_date_time (egg_asn1x_node (info->asn1, "tbsCertificate", "validity", "notAfter", NULL));
649 : : }
650 : :
651 : : /**
652 : : * gcr_certificate_get_key_size:
653 : : * @self: a #GcrCertificate
654 : : *
655 : : * Get the key size in bits of the public key represented
656 : : * by this certificate.
657 : : *
658 : : * Returns: The key size of the certificate.
659 : : */
660 : : guint
661 : 3 : gcr_certificate_get_key_size (GcrCertificate *self)
662 : : {
663 : : GcrCertificateInfo *info;
664 : : GNode *subject_public_key;
665 : :
666 [ - + + - : 3 : g_return_val_if_fail (GCR_IS_CERTIFICATE (self), 0);
- + - + ]
667 : :
668 : 3 : info = certificate_info_load (self);
669 [ - + ]: 3 : if (info == NULL)
670 : 0 : return 0;
671 : :
672 [ + - ]: 3 : if (!info->key_size) {
673 : 3 : subject_public_key = egg_asn1x_node (info->asn1, "tbsCertificate",
674 : : "subjectPublicKeyInfo", NULL);
675 : 3 : info->key_size = _gcr_subject_public_key_calculate_size (subject_public_key);
676 : : }
677 : :
678 : 3 : return info->key_size;
679 : : }
680 : :
681 : : /**
682 : : * gcr_certificate_get_fingerprint:
683 : : * @self: a #GcrCertificate
684 : : * @type: the type of algorithm for the fingerprint.
685 : : * @n_length: (out): The length of the resulting fingerprint.
686 : : *
687 : : * Calculate the fingerprint for this certificate.
688 : : *
689 : : * The caller should free the returned data using g_free() when
690 : : * it is no longer required.
691 : : *
692 : : * Returns: (array length=n_length) (nullable): the raw binary fingerprint
693 : : **/
694 : : guchar *
695 : 1 : gcr_certificate_get_fingerprint (GcrCertificate *self, GChecksumType type, gsize *n_length)
696 : : {
697 : : GChecksum *sum;
698 : : guchar *digest;
699 : : gssize length;
700 : :
701 [ - + + - : 1 : g_return_val_if_fail (GCR_IS_CERTIFICATE (self), NULL);
- + - + ]
702 [ - + ]: 1 : g_return_val_if_fail (n_length != NULL, NULL);
703 : :
704 : 1 : sum = digest_certificate (self, type);
705 [ - + ]: 1 : if (sum == NULL) {
706 : 0 : *n_length = 0;
707 : 0 : return NULL;
708 : : }
709 : :
710 : 1 : length = g_checksum_type_get_length (type);
711 [ - + ]: 1 : g_return_val_if_fail (length > 0, NULL);
712 : 1 : digest = g_malloc (length);
713 : 1 : *n_length = length;
714 : 1 : g_checksum_get_digest (sum, digest, n_length);
715 : 1 : g_checksum_free (sum);
716 : :
717 : 1 : return digest;
718 : : }
719 : :
720 : : /**
721 : : * gcr_certificate_get_fingerprint_hex:
722 : : * @self: a #GcrCertificate
723 : : * @type: the type of algorithm for the fingerprint.
724 : : *
725 : : * Calculate the fingerprint for this certificate, and return it
726 : : * as a hex string.
727 : : *
728 : : * The caller should free the returned data using g_free() when
729 : : * it is no longer required.
730 : : *
731 : : * Returns: (nullable): an allocated hex string which contains the fingerprint.
732 : : */
733 : : gchar*
734 : 1 : gcr_certificate_get_fingerprint_hex (GcrCertificate *self, GChecksumType type)
735 : : {
736 : : GChecksum *sum;
737 : : guchar *digest;
738 : : gsize n_digest;
739 : : gssize length;
740 : : gchar *hex;
741 : :
742 [ - + + - : 1 : g_return_val_if_fail (GCR_IS_CERTIFICATE (self), NULL);
- + - + ]
743 : :
744 : 1 : sum = digest_certificate (self, type);
745 [ - + ]: 1 : if (sum == NULL)
746 : 0 : return NULL;
747 : :
748 : 1 : length = g_checksum_type_get_length (type);
749 [ - + ]: 1 : g_return_val_if_fail (length > 0, NULL);
750 : 1 : digest = g_malloc (length);
751 : 1 : n_digest = length;
752 : 1 : g_checksum_get_digest (sum, digest, &n_digest);
753 : 1 : hex = egg_hex_encode_full (digest, n_digest, TRUE, " ", 1);
754 : 1 : g_checksum_free (sum);
755 : 1 : g_free (digest);
756 : 1 : return hex;
757 : : }
758 : :
759 : : /**
760 : : * gcr_certificate_get_serial_number:
761 : : * @self: a #GcrCertificate
762 : : * @n_length: (out): the length of the returned data.
763 : : *
764 : : * Get the raw binary serial number of the certificate.
765 : : *
766 : : * The caller should free the returned data using g_free() when
767 : : * it is no longer required.
768 : : *
769 : : * Returns: (array length=n_length) (nullable): the raw binary serial number.
770 : : */
771 : : guchar *
772 : 5 : gcr_certificate_get_serial_number (GcrCertificate *self, gsize *n_length)
773 : : {
774 : : GcrCertificateInfo *info;
775 : : GBytes *bytes;
776 : : guchar *result;
777 : :
778 [ - + + - : 5 : g_return_val_if_fail (GCR_IS_CERTIFICATE (self), NULL);
- + - + ]
779 [ - + ]: 5 : g_return_val_if_fail (n_length != NULL, NULL);
780 : :
781 : 5 : info = certificate_info_load (self);
782 [ - + ]: 5 : if (info == NULL) {
783 : 0 : *n_length = 0;
784 : 0 : return NULL;
785 : : }
786 : :
787 : 5 : bytes = egg_asn1x_get_integer_as_raw (egg_asn1x_node (info->asn1, "tbsCertificate", "serialNumber", NULL));
788 [ - + ]: 5 : g_return_val_if_fail (bytes != NULL, NULL);
789 : :
790 : 5 : *n_length = g_bytes_get_size (bytes);
791 : 5 : result = g_memdup2 (g_bytes_get_data (bytes, NULL), *n_length);
792 : :
793 : 5 : g_bytes_unref (bytes);
794 : 5 : return result;
795 : : }
796 : :
797 : : /**
798 : : * gcr_certificate_get_serial_number_hex:
799 : : * @self: a #GcrCertificate
800 : : *
801 : : * Get the serial number of the certificate as a hex string.
802 : : *
803 : : * The caller should free the returned data using g_free() when
804 : : * it is no longer required.
805 : : *
806 : : * Returns: (nullable): an allocated string containing the serial number as hex.
807 : : */
808 : : gchar*
809 : 1 : gcr_certificate_get_serial_number_hex (GcrCertificate *self)
810 : : {
811 : : guchar *serial;
812 : : gsize n_serial;
813 : : gchar *hex;
814 : :
815 [ - + + - : 1 : g_return_val_if_fail (GCR_IS_CERTIFICATE (self), NULL);
- + - + ]
816 : :
817 : 1 : serial = gcr_certificate_get_serial_number (self, &n_serial);
818 [ - + ]: 1 : if (serial == NULL)
819 : 0 : return NULL;
820 : :
821 : 1 : hex = egg_hex_encode (serial, n_serial);
822 : 1 : g_free (serial);
823 : 1 : return hex;
824 : : }
825 : :
826 : : /**
827 : : * gcr_certificate_get_basic_constraints:
828 : : * @self: the certificate
829 : : * @is_ca: (out) (optional): location to place a %TRUE if is an authority
830 : : * @path_len: (out) (optional): location to place the max path length
831 : : *
832 : : * Get the basic constraints for the certificate if present. If %FALSE is
833 : : * returned then no basic constraints are present and the @is_ca and
834 : : * @path_len arguments are not changed.
835 : : *
836 : : * Returns: whether basic constraints are present or not
837 : : */
838 : : gboolean
839 : 1 : gcr_certificate_get_basic_constraints (GcrCertificate *self,
840 : : gboolean *is_ca,
841 : : gint *path_len)
842 : : {
843 : : GcrCertificateInfo *info;
844 : : GBytes *value;
845 : :
846 [ - + + - : 1 : g_return_val_if_fail (GCR_IS_CERTIFICATE (self), FALSE);
- + - + ]
847 : :
848 : 1 : info = certificate_info_load (self);
849 [ - + ]: 1 : if (info == NULL)
850 : 0 : return FALSE;
851 : :
852 : 1 : value = _gcr_certificate_extension_find (info->asn1, GCR_OID_BASIC_CONSTRAINTS, NULL);
853 [ - + ]: 1 : if (!value)
854 : 0 : return FALSE;
855 : :
856 [ - + ]: 1 : if (!_gcr_certificate_extension_basic_constraints (value, is_ca, path_len))
857 : 0 : g_return_val_if_reached (FALSE);
858 : :
859 : 1 : g_bytes_unref (value);
860 : 1 : return TRUE;
861 : : }
862 : :
863 : : static void
864 : 1 : append_subject_public_key (GcrCertificate *self,
865 : : GcrCertificateSection *section,
866 : : GNode *subject_public_key)
867 : : {
868 : : guint key_nbits;
869 : : const gchar *text;
870 : : gchar *display;
871 : : GBytes *value;
872 : : guchar *raw;
873 : : gsize n_raw;
874 : : GQuark oid;
875 : : guint bits;
876 : :
877 : 1 : key_nbits = gcr_certificate_get_key_size (self);
878 : :
879 : 1 : oid = egg_asn1x_get_oid_as_quark (egg_asn1x_node (subject_public_key,
880 : : "algorithm", "algorithm", NULL));
881 : 1 : text = egg_oid_get_description (oid);
882 : 1 : _gcr_certificate_section_new_field (section, _("Key Algorithm"), text);
883 : :
884 : 1 : value = egg_asn1x_get_element_raw (egg_asn1x_node (subject_public_key,
885 : : "algorithm", "parameters", NULL));
886 [ + - ]: 1 : if (value) {
887 : 1 : _gcr_certificate_section_new_field_take_bytes (section,
888 : 1 : _("Key Parameters"),
889 : 1 : g_steal_pointer (&value));
890 : : }
891 : :
892 [ + - ]: 1 : if (key_nbits > 0) {
893 : 1 : display = g_strdup_printf ("%u", key_nbits);
894 : 1 : _gcr_certificate_section_new_field_take_value (section,
895 : 1 : _("Key Size"),
896 : 1 : g_steal_pointer (&display));
897 : : }
898 : :
899 : 1 : value = egg_asn1x_get_element_raw (subject_public_key);
900 : 1 : raw = gcr_fingerprint_from_subject_public_key_info (g_bytes_get_data (value, NULL),
901 : : g_bytes_get_size (value),
902 : : G_CHECKSUM_SHA1, &n_raw);
903 [ + - ]: 1 : g_clear_pointer (&value, g_bytes_unref);
904 : 2 : _gcr_certificate_section_new_field_take_bytes (section,
905 : 1 : _("Key SHA1 Fingerprint"),
906 : : g_bytes_new_take (raw, n_raw));
907 : :
908 : 1 : value = egg_asn1x_get_bits_as_raw (egg_asn1x_node (subject_public_key, "subjectPublicKey", NULL), &bits);
909 : 1 : _gcr_certificate_section_new_field_take_bytes (section, _("Public Key"), g_steal_pointer (&value));
910 : 1 : }
911 : :
912 : : static GcrCertificateSection *
913 : 1 : append_extension_basic_constraints (GBytes *data)
914 : : {
915 : : GcrCertificateSection *section;
916 : 1 : gboolean is_ca = FALSE;
917 : 1 : gint path_len = -1;
918 : : gchar *number;
919 : :
920 [ - + ]: 1 : if (!_gcr_certificate_extension_basic_constraints (data, &is_ca, &path_len))
921 : 0 : return NULL;
922 : :
923 : 1 : section = _gcr_certificate_section_new (_("Basic Constraints"), FALSE);
924 [ - + ]: 1 : _gcr_certificate_section_new_field (section, _("Certificate Authority"), is_ca ? _("Yes") : _("No"));
925 : :
926 [ + - ]: 1 : if (path_len < 0)
927 : 1 : number = g_strdup (_("Unlimited"));
928 : : else
929 : 0 : number = g_strdup_printf ("%d", path_len);
930 : :
931 : 1 : _gcr_certificate_section_new_field_take_value (section, _("Max Path Length"), g_steal_pointer (&number));
932 : :
933 : 1 : return section;
934 : : }
935 : :
936 : : static GcrCertificateSection *
937 : 1 : append_extension_extended_key_usage (GBytes *data)
938 : : {
939 : : GcrCertificateSection *section;
940 : : GQuark *oids;
941 : : GStrvBuilder *text;
942 : : guint i;
943 : :
944 : 1 : oids = _gcr_certificate_extension_extended_key_usage (data);
945 [ - + ]: 1 : if (!oids)
946 : 0 : return NULL;
947 : :
948 : 1 : text = g_strv_builder_new ();
949 [ + + ]: 3 : for (i = 0; oids[i] != 0; i++) {
950 : 2 : g_strv_builder_add (text, egg_oid_get_description (oids[i]));
951 : : }
952 : :
953 : 1 : g_free (oids);
954 : :
955 : 1 : section = _gcr_certificate_section_new (_("Extended Key Usage"), FALSE);
956 : 1 : _gcr_certificate_section_new_field_take_values (section, _("Allowed Purposes"), g_strv_builder_end (text));
957 : 1 : g_strv_builder_unref (text);
958 : :
959 : 1 : return section;
960 : : }
961 : :
962 : : static GcrCertificateSection *
963 : 1 : append_extension_subject_key_identifier (GBytes *data)
964 : : {
965 : : GcrCertificateSection *section;
966 : : gpointer keyid;
967 : : gsize n_keyid;
968 : :
969 : 1 : keyid = _gcr_certificate_extension_subject_key_identifier (data, &n_keyid);
970 [ - + ]: 1 : if (!keyid)
971 : 0 : return NULL;
972 : :
973 : 1 : section = _gcr_certificate_section_new (_("Subject Key Identifier"), FALSE);
974 : 1 : gchar *display = egg_hex_encode_full (keyid, n_keyid, TRUE, " ", 1);
975 : 1 : g_free (keyid);
976 : 1 : _gcr_certificate_section_new_field_take_value (section, _("Key Identifier"), g_steal_pointer (&display));
977 : :
978 : 1 : return section;
979 : : }
980 : :
981 : : static const struct {
982 : : guint usage;
983 : : const gchar *description;
984 : : } usage_descriptions[] = {
985 : : { GCR_KEY_USAGE_DIGITAL_SIGNATURE, N_("Digital signature") },
986 : : { GCR_KEY_USAGE_NON_REPUDIATION, N_("Non repudiation") },
987 : : { GCR_KEY_USAGE_KEY_ENCIPHERMENT, N_("Key encipherment") },
988 : : { GCR_KEY_USAGE_DATA_ENCIPHERMENT, N_("Data encipherment") },
989 : : { GCR_KEY_USAGE_KEY_AGREEMENT, N_("Key agreement") },
990 : : { GCR_KEY_USAGE_KEY_CERT_SIGN, N_("Certificate signature") },
991 : : { GCR_KEY_USAGE_CRL_SIGN, N_("Revocation list signature") },
992 : : { GCR_KEY_USAGE_ENCIPHER_ONLY, N_("Encipher only") },
993 : : { GCR_KEY_USAGE_DECIPHER_ONLY, N_("Decipher only") }
994 : : };
995 : :
996 : : static GcrCertificateSection *
997 : 1 : append_extension_key_usage (GBytes *data)
998 : : {
999 : : GcrCertificateSection *section;
1000 : : gulong key_usage;
1001 : : GStrvBuilder *values;
1002 : : guint i;
1003 : :
1004 [ - + ]: 1 : if (!_gcr_certificate_extension_key_usage (data, &key_usage))
1005 : 0 : return NULL;
1006 : :
1007 : 1 : values = g_strv_builder_new ();
1008 [ + + ]: 10 : for (i = 0; i < G_N_ELEMENTS (usage_descriptions); i++) {
1009 [ + + ]: 9 : if (key_usage & usage_descriptions[i].usage) {
1010 : 1 : g_strv_builder_add (values, _(usage_descriptions[i].description));
1011 : : }
1012 : : }
1013 : :
1014 : 1 : section = _gcr_certificate_section_new (_("Key Usage"), FALSE);
1015 : 1 : _gcr_certificate_section_new_field_take_values (section, _("Usages"), g_strv_builder_end (values));
1016 : 1 : g_strv_builder_unref (values);
1017 : :
1018 : 1 : return section;
1019 : : }
1020 : :
1021 : : static GcrCertificateSection *
1022 : 0 : append_extension_subject_alt_name (GBytes *data)
1023 : : {
1024 : : GcrCertificateSection *section;
1025 : : GArray *general_names;
1026 : : GcrGeneralName *general;
1027 : : guint i;
1028 : :
1029 : 0 : general_names = _gcr_certificate_extension_subject_alt_name (data);
1030 [ # # ]: 0 : if (general_names == NULL)
1031 : 0 : return FALSE;
1032 : :
1033 : 0 : section = _gcr_certificate_section_new (_("Subject Alternative Names"), FALSE);
1034 : :
1035 [ # # ]: 0 : for (i = 0; i < general_names->len; i++) {
1036 : 0 : general = &g_array_index (general_names, GcrGeneralName, i);
1037 [ # # ]: 0 : if (general->display == NULL) {
1038 : 0 : _gcr_certificate_section_new_field_take_bytes (section, general->description, g_bytes_ref (general->raw));
1039 : : } else
1040 : 0 : _gcr_certificate_section_new_field (section, general->description, general->display);
1041 : : }
1042 : :
1043 : 0 : _gcr_general_names_free (general_names);
1044 : :
1045 : 0 : return section;
1046 : : }
1047 : :
1048 : : static GcrCertificateSection *
1049 : 5 : append_extension_hex (GQuark oid,
1050 : : GBytes *value)
1051 : : {
1052 : : GcrCertificateSection *section;
1053 : : const gchar *text;
1054 : :
1055 : 5 : section = _gcr_certificate_section_new (_("Extension"), FALSE);
1056 : :
1057 : : /* Extension type */
1058 : 5 : text = egg_oid_get_description (oid);
1059 : 5 : _gcr_certificate_section_new_field (section, _("Identifier"), g_strdup (text));
1060 : 5 : _gcr_certificate_section_new_field_take_bytes (section, _("Value"), g_steal_pointer (&value));
1061 : :
1062 : 5 : return section;
1063 : : }
1064 : :
1065 : : static GcrCertificateSection *
1066 : 9 : append_extension (GcrCertificate *self,
1067 : : GNode *node)
1068 : : {
1069 : : GQuark oid;
1070 : : GBytes *value;
1071 : : gboolean critical;
1072 : 9 : GcrCertificateSection *section = NULL;
1073 : :
1074 : : /* Dig out the OID */
1075 : 9 : oid = egg_asn1x_get_oid_as_quark (egg_asn1x_node (node, "extnID", NULL));
1076 [ - + ]: 9 : g_return_val_if_fail (oid, NULL);
1077 : :
1078 : : /* Extension value */
1079 : 9 : value = egg_asn1x_get_string_as_bytes (egg_asn1x_node (node, "extnValue", NULL));
1080 : :
1081 : : /* The custom parsers */
1082 [ + + ]: 9 : if (oid == GCR_OID_BASIC_CONSTRAINTS)
1083 : 1 : section = append_extension_basic_constraints (value);
1084 [ + + ]: 8 : else if (oid == GCR_OID_EXTENDED_KEY_USAGE)
1085 : 1 : section = append_extension_extended_key_usage (value);
1086 [ + + ]: 7 : else if (oid == GCR_OID_SUBJECT_KEY_IDENTIFIER)
1087 : 1 : section = append_extension_subject_key_identifier (value);
1088 [ + + ]: 6 : else if (oid == GCR_OID_KEY_USAGE)
1089 : 1 : section = append_extension_key_usage (value);
1090 [ - + ]: 5 : else if (oid == GCR_OID_SUBJECT_ALT_NAME)
1091 : 0 : section = append_extension_subject_alt_name (value);
1092 : :
1093 : : /* Otherwise the default raw display */
1094 [ + + ]: 9 : if (!section) {
1095 : 5 : section = append_extension_hex (oid, g_steal_pointer (&value));
1096 : : }
1097 : :
1098 : : /* Critical */
1099 [ + - + - ]: 9 : if (section && egg_asn1x_get_boolean (egg_asn1x_node (node, "critical", NULL), &critical)) {
1100 [ + + ]: 9 : _gcr_certificate_section_new_field (section, _("Critical"), critical ? _("Yes") : _("No"));
1101 : : }
1102 : :
1103 [ + + ]: 9 : g_clear_pointer (&value, g_bytes_unref);
1104 : 9 : return section;
1105 : : }
1106 : :
1107 : : static void
1108 : 6 : on_parsed_dn_part (guint index,
1109 : : GQuark oid,
1110 : : GNode *value,
1111 : : gpointer user_data)
1112 : : {
1113 : 6 : GcrCertificateSection *section = user_data;
1114 : : const gchar *attr;
1115 : : const gchar *desc;
1116 : : gchar *label, *display;
1117 : :
1118 : 6 : attr = egg_oid_get_name (oid);
1119 : 6 : desc = egg_oid_get_description (oid);
1120 : :
1121 : : /* Combine them into something sane */
1122 [ + - + - ]: 6 : if (attr && desc) {
1123 [ - + ]: 6 : if (strcmp (attr, desc) == 0)
1124 : 0 : label = g_strdup (attr);
1125 : : else
1126 : 6 : label = g_strdup_printf ("%s (%s)", attr, desc);
1127 [ # # # # ]: 0 : } else if (!attr && !desc) {
1128 : 0 : label = g_strdup ("");
1129 [ # # ]: 0 : } else if (attr) {
1130 : 0 : label = g_strdup (attr);
1131 [ # # ]: 0 : } else if (desc) {
1132 : 0 : label = g_strdup (desc);
1133 : : } else {
1134 : 0 : g_assert_not_reached ();
1135 : : }
1136 : :
1137 : 6 : display = egg_dn_print_value (oid, value);
1138 [ - + ]: 6 : if (!display)
1139 : 0 : display = g_strdup ("");
1140 : :
1141 : 6 : _gcr_certificate_section_new_field_take_value (section, label, g_steal_pointer (&display));
1142 [ + - ]: 6 : g_clear_pointer (&label, g_free);
1143 : 6 : }
1144 : :
1145 : : /**
1146 : : * gcr_certificate_get_interface_elements:
1147 : : * @self: the #GcrCertificate
1148 : : *
1149 : : * Get the list of sections from the certificate that can be shown to the user
1150 : : * interface.
1151 : : *
1152 : : * Returns: (element-type GcrCertificateSection) (transfer full): A #GList of
1153 : : * #GcrCertificateSection
1154 : : */
1155 : : GList *
1156 : 1 : gcr_certificate_get_interface_elements (GcrCertificate *self)
1157 : : {
1158 : : GcrCertificateSection *section;
1159 : : GcrCertificateInfo *info;
1160 : 1 : GList *list = NULL;
1161 : : gchar *display;
1162 : : GBytes *bytes, *number;
1163 : : GNode *subject_public_key;
1164 : : GQuark oid;
1165 : : GDateTime *datetime;
1166 : : gulong version;
1167 : : guint bits;
1168 : :
1169 [ - + + - : 1 : g_return_val_if_fail (GCR_IS_CERTIFICATE (self), NULL);
- + - + ]
1170 : :
1171 : 1 : info = certificate_info_load (self);
1172 [ - + ]: 1 : g_return_val_if_fail (info != NULL, NULL);
1173 : :
1174 : 1 : display = gcr_certificate_get_subject_name (self);
1175 [ - + ]: 1 : if (!display)
1176 : 0 : display = g_strdup (_("Certificate"));
1177 : :
1178 : 1 : section = _gcr_certificate_section_new (display, TRUE);
1179 [ + - ]: 1 : g_clear_pointer (&display, g_free);
1180 : :
1181 : 1 : display = gcr_certificate_get_subject_cn (self);
1182 [ - + ]: 1 : if (display == NULL)
1183 : 0 : display = g_strdup (_("Unknown"));
1184 : 1 : _gcr_certificate_section_new_field_take_value (section, _("Identity"), g_steal_pointer (&display));
1185 : :
1186 : 1 : display = gcr_certificate_get_issuer_cn (self);
1187 [ - + ]: 1 : if (display == NULL)
1188 : 0 : display = g_strdup (_("Unknown"));
1189 : 1 : _gcr_certificate_section_new_field_take_value (section, _("Verified by"), g_steal_pointer (&display));
1190 : :
1191 : 1 : datetime = gcr_certificate_get_expiry_date (self);
1192 [ + - ]: 1 : if (datetime) {
1193 : 1 : display = g_date_time_format (datetime, "%x");
1194 [ + - ]: 1 : if (display)
1195 : 1 : _gcr_certificate_section_new_field_take_value (section, _("Expires"), g_steal_pointer (&display));
1196 : :
1197 [ + - ]: 1 : g_clear_pointer (&datetime, g_date_time_unref);
1198 : : }
1199 : :
1200 : 1 : list = g_list_prepend (list, g_steal_pointer (§ion));
1201 : :
1202 : : /* The subject */
1203 : 1 : section = _gcr_certificate_section_new (_("Subject Name"), FALSE);
1204 : 1 : egg_dn_parse (egg_asn1x_node (info->asn1, "tbsCertificate", "subject", "rdnSequence", NULL), on_parsed_dn_part, section);
1205 : :
1206 : 1 : list = g_list_prepend (list, g_steal_pointer (§ion));
1207 : :
1208 : : /* The Issuer */
1209 : 1 : section = _gcr_certificate_section_new (_("Issuer Name"), FALSE);
1210 : 1 : egg_dn_parse (egg_asn1x_node (info->asn1, "tbsCertificate", "issuer", "rdnSequence", NULL), on_parsed_dn_part, section);
1211 : :
1212 : 1 : list = g_list_prepend (list, g_steal_pointer (§ion));
1213 : :
1214 : : /* The Issued Parameters */
1215 : 1 : section = _gcr_certificate_section_new (_("Issued Certificate"), FALSE);
1216 : :
1217 [ - + ]: 1 : if (!egg_asn1x_get_integer_as_ulong (egg_asn1x_node (info->asn1, "tbsCertificate", "version", NULL), &version)) {
1218 : 0 : g_critical ("Unable to parse certificate version");
1219 : : } else {
1220 : 1 : display = g_strdup_printf ("%lu", version + 1);
1221 : 1 : _gcr_certificate_section_new_field_take_value (section, _("Version"), g_steal_pointer (&display));
1222 : : }
1223 : :
1224 : 1 : number = egg_asn1x_get_integer_as_raw (egg_asn1x_node (info->asn1, "tbsCertificate", "serialNumber", NULL));
1225 [ - + ]: 1 : if (!number) {
1226 : 0 : g_critical ("Unable to parse certificate serial number");
1227 : : } else {
1228 : 1 : _gcr_certificate_section_new_field_take_bytes (section, _("Serial Number"), g_steal_pointer (&number));
1229 : : }
1230 : :
1231 : 1 : datetime = gcr_certificate_get_issued_date (self);
1232 [ + - ]: 1 : if (datetime) {
1233 : 1 : display = g_date_time_format (datetime, "%x");
1234 [ + - ]: 1 : if (display)
1235 : 1 : _gcr_certificate_section_new_field_take_value (section, _("Not Valid Before"), g_steal_pointer (&display));
1236 : :
1237 [ + - ]: 1 : g_clear_pointer (&datetime, g_date_time_unref);
1238 : : }
1239 : :
1240 : 1 : datetime = gcr_certificate_get_expiry_date (self);
1241 [ + - ]: 1 : if (datetime) {
1242 : 1 : display = g_date_time_format (datetime, "%x");
1243 [ + - ]: 1 : if (display)
1244 : 1 : _gcr_certificate_section_new_field_take_value (section, _("Not Valid After"), g_steal_pointer (&display));
1245 : :
1246 [ + - ]: 1 : g_clear_pointer (&datetime, g_date_time_unref);
1247 : : }
1248 : :
1249 : 1 : list = g_list_prepend (list, g_steal_pointer (§ion));
1250 : :
1251 : : /* Fingerprints */
1252 : 1 : bytes = g_bytes_new_static (info->der, info->n_der);
1253 : 1 : section = _gcr_certificate_section_new (_("Certificate Fingerprints"), FALSE);
1254 : 1 : display = g_compute_checksum_for_bytes (G_CHECKSUM_SHA1, bytes);
1255 : 1 : _gcr_certificate_section_new_field_take_value (section, "SHA1", g_steal_pointer (&display));
1256 : 1 : display = g_compute_checksum_for_bytes (G_CHECKSUM_MD5, bytes);
1257 : 1 : _gcr_certificate_section_new_field_take_value (section, "MD5", g_steal_pointer (&display));
1258 [ + - ]: 1 : g_clear_pointer (&bytes, g_bytes_unref);
1259 : :
1260 : 1 : list = g_list_prepend (list, g_steal_pointer (§ion));
1261 : :
1262 : : /* Public Key Info */
1263 : 1 : section = _gcr_certificate_section_new (_("Public Key Info"), FALSE);
1264 : 1 : subject_public_key = egg_asn1x_node (info->asn1, "tbsCertificate", "subjectPublicKeyInfo", NULL);
1265 : 1 : append_subject_public_key (self, section, subject_public_key);
1266 : :
1267 : 1 : list = g_list_prepend (list, g_steal_pointer (§ion));
1268 : :
1269 : : /* Extensions */
1270 : 10 : for (guint extension_num = 1; TRUE; ++extension_num) {
1271 : 10 : GNode *extension = egg_asn1x_node (info->asn1, "tbsCertificate", "extensions", extension_num, NULL);
1272 [ + + ]: 10 : if (extension == NULL)
1273 : 1 : break;
1274 : 9 : section = append_extension (self, extension);
1275 [ + - ]: 9 : if (section)
1276 : 9 : list = g_list_prepend (list, g_steal_pointer (§ion));
1277 : : }
1278 : :
1279 : : /* Signature */
1280 : 1 : section = _gcr_certificate_section_new (_("Signature"), FALSE);
1281 : :
1282 : 1 : oid = egg_asn1x_get_oid_as_quark (egg_asn1x_node (info->asn1, "signatureAlgorithm", "algorithm", NULL));
1283 : 1 : _gcr_certificate_section_new_field (section, _("Signature Algorithm"), egg_oid_get_description (oid));
1284 : :
1285 : 1 : bytes = egg_asn1x_get_element_raw (egg_asn1x_node (info->asn1, "signatureAlgorithm", "parameters", NULL));
1286 [ + - ]: 1 : if (bytes) {
1287 : 1 : _gcr_certificate_section_new_field_take_bytes (section, _("Signature Parameters"), g_steal_pointer (&bytes));
1288 : : }
1289 : :
1290 : 1 : bytes = egg_asn1x_get_bits_as_raw (egg_asn1x_node (info->asn1, "signature", NULL), &bits);
1291 : 1 : _gcr_certificate_section_new_field_take_bytes (section, _("Signature"), g_steal_pointer (&bytes));
1292 : :
1293 : 1 : list = g_list_prepend (list, g_steal_pointer (§ion));
1294 : :
1295 : 1 : return g_list_reverse (list);
1296 : : }
1297 : :
1298 : : /* -----------------------------------------------------------------------------
1299 : : * MIXIN
1300 : : */
1301 : :
1302 : : /**
1303 : : * gcr_certificate_mixin_emit_notify:
1304 : : * @self: the #GcrCertificate
1305 : : *
1306 : : * Implementers of the #GcrCertificate mixin should call this function to notify
1307 : : * when the certificate has changed to emit notifications on the various
1308 : : * properties.
1309 : : */
1310 : : void
1311 : 0 : gcr_certificate_mixin_emit_notify (GcrCertificate *self)
1312 : : {
1313 : : GObject *obj;
1314 : :
1315 [ # # # # : 0 : g_return_if_fail (GCR_IS_CERTIFICATE (self));
# # # # ]
1316 : :
1317 : 0 : obj = G_OBJECT (self);
1318 : 0 : g_object_notify (obj, "label");
1319 : 0 : g_object_notify (obj, "subject-name");
1320 : 0 : g_object_notify (obj, "issuer-name");
1321 : 0 : g_object_notify (obj, "expiry-date");
1322 : : }
1323 : :
1324 : : /**
1325 : : * gcr_certificate_mixin_class_init: (skip)
1326 : : * @object_class: The GObjectClass for this class
1327 : : *
1328 : : * Initialize the certificate mixin for the class. This mixin implements the
1329 : : * various required properties for the certificate.
1330 : : *
1331 : : * Call this function near the end of your derived class_init function. The
1332 : : * derived class must implement the #GcrCertificate interface.
1333 : : */
1334 : : void
1335 : 8 : gcr_certificate_mixin_class_init (GObjectClass *object_class)
1336 : : {
1337 [ + - ]: 8 : if (!g_object_class_find_property (object_class, "description"))
1338 : 8 : g_object_class_override_property (object_class, PROP_DESCRIPTION, "description");
1339 [ + - ]: 8 : if (!g_object_class_find_property (object_class, "label"))
1340 : 8 : g_object_class_override_property (object_class, PROP_LABEL, "label");
1341 [ + - ]: 8 : if (!g_object_class_find_property (object_class, "subject-name"))
1342 : 8 : g_object_class_override_property (object_class, PROP_SUBJECT_NAME, "subject-name");
1343 [ + - ]: 8 : if (!g_object_class_find_property (object_class, "issuer-name"))
1344 : 8 : g_object_class_override_property (object_class, PROP_ISSUER_NAME, "issuer-name");
1345 [ + - ]: 8 : if (!g_object_class_find_property (object_class, "expiry-date"))
1346 : 8 : g_object_class_override_property (object_class, PROP_EXPIRY_DATE, "expiry-date");
1347 : :
1348 : 8 : _gcr_initialize_library ();
1349 : 8 : }
1350 : :
1351 : : /**
1352 : : * gcr_certificate_mixin_get_property: (skip)
1353 : : * @obj: The object
1354 : : * @prop_id: The property id
1355 : : * @value: The value to fill in.
1356 : : * @pspec: The param specification.
1357 : : *
1358 : : * Implementation to get various required certificate properties. This should
1359 : : * be called from your derived class get_property function, or used as a
1360 : : * get_property virtual function.
1361 : : *
1362 : : * Example of use as called from derived class get_property function:
1363 : : *
1364 : : * <informalexample><programlisting>
1365 : : * static void
1366 : : * my_get_property (GObject *obj, guint prop_id, GValue *value, GParamSpec *pspec)
1367 : : * {
1368 : : * switch (prop_id) {
1369 : : *
1370 : : * ...
1371 : : *
1372 : : * default:
1373 : : * gcr_certificate_mixin_get_property (obj, prop_id, value, pspec);
1374 : : * break;
1375 : : * }
1376 : : *}
1377 : : * </programlisting></informalexample>
1378 : : *
1379 : : * Example of use as get_property function:
1380 : : *
1381 : : * <informalexample><programlisting>
1382 : : * static void
1383 : : * my_class_init (MyClass *klass)
1384 : : * {
1385 : : * GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
1386 : : * gobject_class->get_property = gcr_certificate_mixin_get_property;
1387 : : *
1388 : : * ...
1389 : : * }
1390 : : * </programlisting></informalexample>
1391 : :
1392 : : */
1393 : : void
1394 : 0 : gcr_certificate_mixin_get_property (GObject *obj, guint prop_id,
1395 : : GValue *value, GParamSpec *pspec)
1396 : : {
1397 : 0 : GcrCertificate *cert = GCR_CERTIFICATE (obj);
1398 : :
1399 [ # # # # : 0 : switch (prop_id) {
# # ]
1400 : 0 : case PROP_LABEL:
1401 : 0 : g_value_take_string (value, gcr_certificate_get_subject_name (cert));
1402 : 0 : break;
1403 : 0 : case PROP_SUBJECT_NAME:
1404 : 0 : g_value_take_string (value, gcr_certificate_get_subject_name (cert));
1405 : 0 : break;
1406 : 0 : case PROP_DESCRIPTION:
1407 : 0 : g_value_set_string (value, _("Certificate"));
1408 : 0 : break;
1409 : 0 : case PROP_ISSUER_NAME:
1410 : 0 : g_value_take_string (value, gcr_certificate_get_issuer_name (cert));
1411 : 0 : break;
1412 : 0 : case PROP_EXPIRY_DATE:
1413 : 0 : g_value_take_boxed (value, gcr_certificate_get_expiry_date (cert));
1414 : 0 : break;
1415 : 0 : default:
1416 : 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
1417 : 0 : break;
1418 : : }
1419 : 0 : }
|