~noskcaj/ubuntu/vivid/gnome-keyring/3.15.90

« back to all changes in this revision

Viewing changes to gcr/gcr-certificate-chain.c

  • Committer: Package Import Robot
  • Author(s): Jordi Mallach
  • Date: 2012-05-14 22:13:02 UTC
  • mfrom: (1.3.1)
  • mto: (80.2.8 experimental) (1.1.77)
  • mto: This revision was merged to the branch mainline in revision 148.
  • Revision ID: package-import@ubuntu.com-20120514221302-0l3gjmqpe6xopond
ImportĀ upstreamĀ versionĀ 3.4.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 * gnome-keyring
3
 
 *
4
 
 * Copyright (C) 2010 Collabora Ltd
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, write to the Free Software
18
 
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
19
 
 * 02111-1307, USA.
20
 
 *
21
 
 * Author: Stef Walter <stefw@collabora.co.uk>
22
 
 */
23
 
 
24
 
#include "config.h"
25
 
 
26
 
#include "gcr-certificate-chain.h"
27
 
 
28
 
#include "gcr-certificate.h"
29
 
#include "gcr-pkcs11-certificate.h"
30
 
#include "gcr-simple-certificate.h"
31
 
 
32
 
#include "gcr-trust.h"
33
 
 
34
 
/**
35
 
 * SECTION:gcr-certificate-chain
36
 
 * @title: GcrCertificateChain
37
 
 * @short_description: A certificate chain
38
 
 *
39
 
 * #GcrCertificateChain represents a chain of certificates, normally used to
40
 
 * validate the trust in a certificate. An X.509 certificate chain has one
41
 
 * endpoint certificate (the one for which trust is being verified) and then
42
 
 * in turn the certificate that issued each previous certificate in the chain.
43
 
 *
44
 
 * This functionality is for building of certificate chains not for validating
45
 
 * them. Use your favorite crypto library to validate trust in a certificate
46
 
 * chain once its built.
47
 
 *
48
 
 * The order of certificates in the chain should be first the endpoint
49
 
 * certificates and then the signing certificates.
50
 
 *
51
 
 * Create a new certificate chain with gcr_certificate_chain_new() and then
52
 
 * add the certificates with gcr_certificate_chain_add().
53
 
 *
54
 
 * You can then use gcr_certificate_chain_build() to build the remainder of
55
 
 * the chain. This will lookup missing certificates in PKCS\#11 modules and
56
 
 * also check that each certificate in the chain is the signer of the previous
57
 
 * one. If a trust anchor, pinned certificate, or self-signed certificate is
58
 
 * found, then the chain is considered built. Any extra certificates are
59
 
 * removed from the chain.
60
 
 *
61
 
 * Once the certificate chain has been built, you can access its status
62
 
 * through gcr_certificate_chain_get_status(). The status signifies whether
63
 
 * the chain is anchored on a trust root, self-signed, incomplete etc. See
64
 
 * #GcrCertificateChainStatus for information on the various statuses.
65
 
 *
66
 
 * It's important to understand that the building of a certificate chain is
67
 
 * merely the first step towards verifying trust in a certificate.
68
 
 */
69
 
 
70
 
enum {
71
 
        PROP_0,
72
 
        PROP_STATUS,
73
 
        PROP_LENGTH,
74
 
};
75
 
 
76
 
struct _GcrCertificateChainPrivate {
77
 
        GPtrArray *certificates;
78
 
        GcrCertificateChainStatus status;
79
 
 
80
 
        /* Used in build operation */
81
 
        gchar *purpose;
82
 
        gchar *peer;
83
 
        guint flags;
84
 
};
85
 
 
86
 
static GQuark Q_ORIGINAL_CERT = 0;
87
 
static GQuark Q_OPERATION_DATA = 0;
88
 
 
89
 
G_DEFINE_TYPE (GcrCertificateChain, gcr_certificate_chain, G_TYPE_OBJECT);
90
 
 
91
 
/* -----------------------------------------------------------------------------
92
 
 * INTERNAL
93
 
 */
94
 
 
95
 
static void
96
 
free_chain_private (gpointer data)
97
 
{
98
 
        GcrCertificateChainPrivate *pv = data;
99
 
        g_ptr_array_unref (pv->certificates);
100
 
        g_free (pv->purpose);
101
 
        g_free (pv->peer);
102
 
        g_slice_free (GcrCertificateChainPrivate, pv);
103
 
}
104
 
 
105
 
static GcrCertificateChainPrivate*
106
 
new_chain_private (void)
107
 
{
108
 
        GcrCertificateChainPrivate *pv = g_slice_new0 (GcrCertificateChainPrivate);
109
 
        pv->certificates = g_ptr_array_new_with_free_func (g_object_unref);
110
 
        return pv;
111
 
}
112
 
 
113
 
static GcrCertificateChainPrivate*
114
 
prep_chain_private (GcrCertificateChainPrivate *orig, const gchar *purpose,
115
 
                    const gchar *peer, guint flags)
116
 
{
117
 
        GcrCertificateChainPrivate *pv;
118
 
        GcrCertificate *certificate;
119
 
        guint i;
120
 
 
121
 
        g_assert (orig);
122
 
        g_assert (purpose);
123
 
 
124
 
        pv = new_chain_private ();
125
 
        for (i = 0; i < orig->certificates->len; ++i) {
126
 
                certificate = g_ptr_array_index (orig->certificates, i);
127
 
                g_ptr_array_add (pv->certificates, g_object_ref (certificate));
128
 
        }
129
 
 
130
 
        pv->status = orig->status;
131
 
        pv->purpose = g_strdup (purpose);
132
 
        pv->peer = g_strdup (peer);
133
 
        pv->flags = flags;
134
 
        return pv;
135
 
}
136
 
 
137
 
static GcrCertificateChainPrivate*
138
 
prep_chain_private_thread_safe (GcrCertificateChainPrivate *orig, const gchar *purpose,
139
 
                                const gchar *peer, guint flags)
140
 
{
141
 
        GcrCertificateChainPrivate *pv;
142
 
        GcrCertificate *certificate, *safe;
143
 
        gconstpointer der;
144
 
        gsize n_der;
145
 
        guint i;
146
 
 
147
 
        g_assert (orig);
148
 
 
149
 
        pv = prep_chain_private (orig, purpose, peer, flags);
150
 
 
151
 
        for (i = 0; i < pv->certificates->len; ++i) {
152
 
                certificate = g_ptr_array_index (pv->certificates, i);
153
 
 
154
 
                /* We regard these types as thread safe */
155
 
                if (GCR_IS_SIMPLE_CERTIFICATE (certificate) ||
156
 
                    GCR_IS_PKCS11_CERTIFICATE (certificate)) {
157
 
                        safe = g_object_ref (certificate);
158
 
 
159
 
                /* Otherwise copy the certificate data */
160
 
                } else {
161
 
                        der = gcr_certificate_get_der_data (certificate, &n_der);
162
 
                        g_return_val_if_fail (der, NULL);
163
 
                        safe = gcr_simple_certificate_new (der, n_der);
164
 
 
165
 
                        /* Always set the original certificate onto the safe one */
166
 
                        g_object_set_qdata_full (G_OBJECT (safe), Q_ORIGINAL_CERT,
167
 
                                                 g_object_ref (certificate), g_object_unref);
168
 
                }
169
 
 
170
 
                g_ptr_array_index (pv->certificates, i) = safe;
171
 
                g_object_unref (certificate);
172
 
        }
173
 
 
174
 
        return pv;
175
 
}
176
 
 
177
 
static GcrCertificateChainPrivate*
178
 
cleanup_chain_private (GcrCertificateChainPrivate *pv)
179
 
{
180
 
        GcrCertificate *certificate, *orig;
181
 
        guint i;
182
 
 
183
 
        for (i = 0; i < pv->certificates->len; ++i) {
184
 
                certificate = g_ptr_array_index (pv->certificates, i);
185
 
 
186
 
                /* If there's an original certificate set, then replace it back */
187
 
                orig = g_object_get_qdata (G_OBJECT (certificate), Q_ORIGINAL_CERT);
188
 
                if (orig != NULL) {
189
 
                        g_ptr_array_index (pv->certificates, i) = g_object_ref (orig);
190
 
                        g_object_unref (certificate);
191
 
                }
192
 
        }
193
 
 
194
 
        return pv;
195
 
}
196
 
 
197
 
static gboolean
198
 
perform_build_chain (GcrCertificateChainPrivate *pv, GCancellable *cancellable,
199
 
                     GError **rerror)
200
 
{
201
 
        GError *error = NULL;
202
 
        GcrCertificate *certificate;
203
 
        gboolean lookups;
204
 
        gboolean ret;
205
 
        guint length;
206
 
 
207
 
        g_assert (pv);
208
 
        g_assert (pv->certificates);
209
 
 
210
 
        pv->status = GCR_CERTIFICATE_CHAIN_UNKNOWN;
211
 
        lookups = !((pv->flags & GCR_CERTIFICATE_CHAIN_FLAG_NO_LOOKUPS) == GCR_CERTIFICATE_CHAIN_FLAG_NO_LOOKUPS);
212
 
 
213
 
        /* This chain is built */
214
 
        if (!pv->certificates->len)
215
 
                return TRUE;
216
 
 
217
 
        /* First check for pinned certificates */
218
 
        certificate = g_ptr_array_index (pv->certificates, 0);
219
 
        if (lookups && pv->peer) {
220
 
                ret = gcr_trust_is_certificate_pinned (certificate, pv->purpose,
221
 
                                                       pv->peer, cancellable, &error);
222
 
                if (!ret && error) {
223
 
                        g_propagate_error (rerror, error);
224
 
                        return FALSE;
225
 
                }
226
 
 
227
 
                /*
228
 
                 * This is a pinned certificate and the rest of the chain
229
 
                 * is irrelevant, so truncate chain and consider built.
230
 
                 */
231
 
                if (ret) {
232
 
                        g_ptr_array_set_size (pv->certificates, 1);
233
 
                        pv->status = GCR_CERTIFICATE_CHAIN_PINNED;
234
 
                        return TRUE;
235
 
                }
236
 
        }
237
 
 
238
 
        length = 1;
239
 
 
240
 
        /* The first certificate is always unconditionally in the chain */
241
 
        while (pv->status == GCR_CERTIFICATE_CHAIN_UNKNOWN) {
242
 
 
243
 
                /* Stop the chain if previous was self-signed */
244
 
                if (gcr_certificate_is_issuer (certificate, certificate)) {
245
 
                        pv->status = GCR_CERTIFICATE_CHAIN_SELFSIGNED;
246
 
                        break;
247
 
                }
248
 
 
249
 
                /* Try the next certificate in the chain */
250
 
                if (length < pv->certificates->len) {
251
 
                        certificate = g_ptr_array_index (pv->certificates, length);
252
 
 
253
 
                /* No more in chain, try to lookup */
254
 
                } else if (lookups) {
255
 
                        certificate = gcr_pkcs11_certificate_lookup_issuer (certificate,
256
 
                                                                            cancellable, &error);
257
 
                        if (error != NULL) {
258
 
                                g_propagate_error (rerror, error);
259
 
                                return FALSE;
260
 
                        } else if (certificate) {
261
 
                                g_ptr_array_add (pv->certificates, certificate);
262
 
                        }
263
 
 
264
 
                /* No more in chain, and can't lookup */
265
 
                } else {
266
 
                        certificate = NULL;
267
 
                }
268
 
 
269
 
                /* Stop the chain if nothing found */
270
 
                if (certificate == NULL) {
271
 
                        pv->status = GCR_CERTIFICATE_CHAIN_INCOMPLETE;
272
 
                        break;
273
 
                }
274
 
 
275
 
                ++length;
276
 
 
277
 
                /* See if this certificate is an anchor */
278
 
                if (lookups) {
279
 
                        ret = gcr_trust_is_certificate_anchored (certificate, pv->purpose,
280
 
                                                                 cancellable, &error);
281
 
 
282
 
                        if (!ret && error) {
283
 
                                g_propagate_error (rerror, error);
284
 
                                return FALSE;
285
 
 
286
 
                        /* Stop the chain at the first anchor */
287
 
                        } else if (ret) {
288
 
                                pv->status = GCR_CERTIFICATE_CHAIN_ANCHORED;
289
 
                                break;
290
 
                        }
291
 
                }
292
 
        }
293
 
 
294
 
        /* TODO: Need to check each certificate in the chain for distrusted */
295
 
 
296
 
        /* Truncate to the appropriate length */
297
 
        g_assert (length <= pv->certificates->len);
298
 
        g_ptr_array_set_size (pv->certificates, length);
299
 
        return TRUE;
300
 
}
301
 
 
302
 
static void
303
 
thread_build_chain (GSimpleAsyncResult *result, GObject *object,
304
 
                    GCancellable *cancellable)
305
 
{
306
 
        GcrCertificateChainPrivate *pv;
307
 
        GError *error = NULL;
308
 
 
309
 
        pv = g_object_get_qdata (G_OBJECT (result), Q_OPERATION_DATA);
310
 
        g_assert (pv);
311
 
 
312
 
        if (!perform_build_chain (pv, cancellable, &error)) {
313
 
                g_simple_async_result_set_from_error (result, error);
314
 
                g_clear_error (&error);
315
 
        }
316
 
}
317
 
 
318
 
/* -----------------------------------------------------------------------------
319
 
 * OBJECT
320
 
 */
321
 
 
322
 
static void
323
 
gcr_certificate_chain_init (GcrCertificateChain *self)
324
 
{
325
 
        self->pv = new_chain_private ();
326
 
}
327
 
 
328
 
static void
329
 
gcr_certificate_chain_dispose (GObject *obj)
330
 
{
331
 
        GcrCertificateChain *self = GCR_CERTIFICATE_CHAIN (obj);
332
 
 
333
 
        g_ptr_array_set_size (self->pv->certificates, 0);
334
 
        self->pv->status = GCR_CERTIFICATE_CHAIN_UNKNOWN;
335
 
 
336
 
        G_OBJECT_CLASS (gcr_certificate_chain_parent_class)->dispose (obj);
337
 
}
338
 
 
339
 
static void
340
 
gcr_certificate_chain_finalize (GObject *obj)
341
 
{
342
 
        GcrCertificateChain *self = GCR_CERTIFICATE_CHAIN (obj);
343
 
 
344
 
        free_chain_private (self->pv);
345
 
        self->pv = NULL;
346
 
 
347
 
        G_OBJECT_CLASS (gcr_certificate_chain_parent_class)->finalize (obj);
348
 
}
349
 
 
350
 
static void
351
 
gcr_certificate_chain_get_property (GObject *obj, guint prop_id, GValue *value,
352
 
                                    GParamSpec *pspec)
353
 
{
354
 
        GcrCertificateChain *self = GCR_CERTIFICATE_CHAIN (obj);
355
 
 
356
 
        switch (prop_id) {
357
 
        case PROP_STATUS:
358
 
                g_value_set_enum (value, gcr_certificate_chain_get_status (self));
359
 
                break;
360
 
        case PROP_LENGTH:
361
 
                g_value_set_uint (value, gcr_certificate_chain_get_length (self));
362
 
                break;
363
 
        default:
364
 
                G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
365
 
                break;
366
 
        }
367
 
}
368
 
 
369
 
static void
370
 
gcr_certificate_chain_class_init (GcrCertificateChainClass *klass)
371
 
{
372
 
        GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
373
 
 
374
 
        gcr_certificate_chain_parent_class = g_type_class_peek_parent (klass);
375
 
 
376
 
        gobject_class->dispose = gcr_certificate_chain_dispose;
377
 
        gobject_class->finalize = gcr_certificate_chain_finalize;
378
 
        gobject_class->get_property = gcr_certificate_chain_get_property;
379
 
 
380
 
        /**
381
 
         * GcrCertificateChain:status:
382
 
         *
383
 
         * The certificate chain status. See #GcrCertificateChainStatus
384
 
         */
385
 
        g_object_class_install_property (gobject_class, PROP_STATUS,
386
 
                   g_param_spec_enum ("status", "Status", "Status of certificate chain",
387
 
                                      GCR_TYPE_CERTIFICATE_CHAIN_STATUS,
388
 
                                      GCR_CERTIFICATE_CHAIN_UNKNOWN, G_PARAM_READABLE));
389
 
 
390
 
        /**
391
 
         * GcrCertificateChain:length:
392
 
         *
393
 
         * The length of the certificate chain.
394
 
         */
395
 
        g_object_class_install_property (gobject_class, PROP_LENGTH,
396
 
                   g_param_spec_uint ("length", "Length", "Length of certificate chain",
397
 
                                      0, G_MAXUINT, 0, G_PARAM_READABLE));
398
 
 
399
 
        Q_ORIGINAL_CERT = g_quark_from_static_string ("gcr-certificate-chain-original-cert");
400
 
        Q_OPERATION_DATA = g_quark_from_static_string ("gcr-certificate-chain-operation-data");
401
 
}
402
 
 
403
 
/* -----------------------------------------------------------------------------
404
 
 * PUBLIC
405
 
 */
406
 
 
407
 
/**
408
 
 * GcrCertificateChainStatus:
409
 
 * @GCR_CERTIFICATE_CHAIN_UNKNOWN: The certificate chain's status is unknown.
410
 
 * When a chain is not yet built it has this status. If a chain is modified after
411
 
 * being built, it has this status.
412
 
 * @GCR_CERTIFICATE_CHAIN_INCOMPLETE: A full chain could not be loaded. The
413
 
 * chain does not end with a self-signed certificate, a trusted anchor, or a
414
 
 * pinned certificate.
415
 
 * @GCR_CERTIFICATE_CHAIN_SELFSIGNED: The chain ends with a self-signed
416
 
 * certificate. No trust anchor was found.
417
 
 * @GCR_CERTIFICATE_CHAIN_DISTRUSTED: The certificate chain contains a revoked
418
 
 * or otherwise explicitly distrusted certificate. The entire chain should
419
 
 * be distrusted.
420
 
 * @GCR_CERTIFICATE_CHAIN_ANCHORED: The chain ends with an anchored
421
 
 * certificate. The anchored certificate is not necessarily self-signed.
422
 
 * @GCR_CERTIFICATE_CHAIN_PINNED: The chain represents a pinned certificate. A
423
 
 * pinned certificate is an exception which trusts a given certificate
424
 
 * explicitly for a purpose and communication with a certain peer.
425
 
 *
426
 
 * The status of a built certificate chain. Will be set to
427
 
 * %GCR_CERTIFICATE_CHAIN_UNKNOWN for certificate chains that have not been
428
 
 * built.
429
 
 */
430
 
 
431
 
GType
432
 
gcr_certificate_chain_status_get_type (void)
433
 
{
434
 
        static volatile gsize initialized = 0;
435
 
        static GType type = 0;
436
 
        static const GEnumValue values[] = {
437
 
                { GCR_CERTIFICATE_CHAIN_UNKNOWN, "GCR_CERTIFICATE_CHAIN_UNKNOWN", "unknown" },
438
 
                { GCR_CERTIFICATE_CHAIN_INCOMPLETE, "GCR_CERTIFICATE_CHAIN_INCOMPLETE", "incomplete" },
439
 
                { GCR_CERTIFICATE_CHAIN_DISTRUSTED, "GCR_CERTIFICATE_CHAIN_DISTRUSTED", "distrusted" },
440
 
                { GCR_CERTIFICATE_CHAIN_SELFSIGNED, "GCR_CERTIFICATE_CHAIN_SELFSIGNED", "self-signed" },
441
 
                { GCR_CERTIFICATE_CHAIN_PINNED, "GCR_CERTIFICATE_CHAIN_PINNED", "pinned" },
442
 
                { GCR_CERTIFICATE_CHAIN_ANCHORED, "GCR_CERTIFICATE_CHAIN_ANCHORED", "anchored" },
443
 
                { 0, NULL, NULL }
444
 
        };
445
 
 
446
 
        if (g_once_init_enter (&initialized)) {
447
 
                type = g_enum_register_static ("GcrCertificateChainStatus", values);
448
 
                g_once_init_leave (&initialized, 1);
449
 
        }
450
 
 
451
 
        return type;
452
 
}
453
 
 
454
 
/**
455
 
 * GcrCertificateChainFlags:
456
 
 * @GCR_CERTIFICATE_CHAIN_FLAG_NO_LOOKUPS: If this flag is specified then no
457
 
 * lookups for anchors or pinned certificates are done, and the resulting chain
458
 
 * will be neither anchored or pinned. Additionally no missing certificate
459
 
 * authorities are looked up in PKCS\#11.
460
 
 *
461
 
 * Flags to be used with the gcr_certificate_chain_build() operation.
462
 
 */
463
 
 
464
 
GType
465
 
gcr_certificate_chain_flags_get_type (void)
466
 
{
467
 
        static volatile gsize initialized = 0;
468
 
        static GType type = 0;
469
 
        static const GFlagsValue values[] = {
470
 
                { GCR_CERTIFICATE_CHAIN_FLAG_NO_LOOKUPS, "GCR_CERTIFICATE_CHAIN_FLAG_NO_LOOKUPS", "no-lookups" },
471
 
                { 0, NULL, NULL }
472
 
        };
473
 
 
474
 
        if (g_once_init_enter (&initialized)) {
475
 
                type = g_flags_register_static ("GcrCertificateChainFlags", values);
476
 
                g_once_init_leave (&initialized, 1);
477
 
        }
478
 
 
479
 
        return type;
480
 
}
481
 
 
482
 
/**
483
 
 * gcr_certificate_chain_new:
484
 
 *
485
 
 * Create a new #GcrCertificateChain.
486
 
 *
487
 
 * Returns: A newly allocated #GcrCertificateChain
488
 
 */
489
 
GcrCertificateChain*
490
 
gcr_certificate_chain_new (void)
491
 
{
492
 
        return g_object_new (GCR_TYPE_CERTIFICATE_CHAIN, NULL);
493
 
}
494
 
 
495
 
/**
496
 
 * gcr_certificate_chain_add:
497
 
 * @self: the #GcrCertificateChain
498
 
 * @certificate: a #GcrCertificate to add to the chain
499
 
 *
500
 
 * Add @certificate to the chain. The order of certificates in the chain are
501
 
 * important. The first certificate should be the endpoint certificate, and
502
 
 * then come the signers (certificate authorities) each in turn. If a root
503
 
 * certificate authority is present, it should come last.
504
 
 *
505
 
 * Adding a certificate an already built chain (see
506
 
 * gcr_certificate_chain_build()) resets the type of the certificate chain
507
 
 * to %GCR_CERTIFICATE_CHAIN_UNKNOWN
508
 
 */
509
 
void
510
 
gcr_certificate_chain_add (GcrCertificateChain *self, GcrCertificate *certificate)
511
 
{
512
 
        g_return_if_fail (GCR_IS_CERTIFICATE_CHAIN (self));
513
 
        g_return_if_fail (GCR_IS_CERTIFICATE (certificate));
514
 
        g_ptr_array_add (self->pv->certificates, g_object_ref (certificate));
515
 
        self->pv->status = GCR_CERTIFICATE_CHAIN_UNKNOWN;
516
 
        g_object_notify (G_OBJECT (self), "status");
517
 
        g_object_notify (G_OBJECT (self), "length");
518
 
}
519
 
 
520
 
/**
521
 
 * gcr_certificate_chain_get_status:
522
 
 * @self: the #GcrCertificateChain
523
 
 *
524
 
 * Get the status of a certificate chain. If the certificate chain has not
525
 
 * been built, then the status will be %GCR_CERTIFICATE_CHAIN_UNKNOWN.
526
 
 *
527
 
 * A status of %GCR_CERTIFICATE_CHAIN_ANCHORED does not mean that the
528
 
 * certificate chain has been verified, but merely that an anchor has been
529
 
 * found.
530
 
 *
531
 
 * Returns: the status of the certificate chain.
532
 
 */
533
 
GcrCertificateChainStatus
534
 
gcr_certificate_chain_get_status (GcrCertificateChain *self)
535
 
{
536
 
        g_return_val_if_fail (GCR_IS_CERTIFICATE_CHAIN (self), GCR_CERTIFICATE_CHAIN_UNKNOWN);
537
 
        return self->pv->status;
538
 
}
539
 
 
540
 
/**
541
 
 * gcr_certificate_chain_get_anchor:
542
 
 * @self: the #GcrCertificateChain
543
 
 *
544
 
 * If the certificate chain has been built and is of status
545
 
 * %GCR_CERTIFICATE_CHAIN_ANCHORED, then this will return the anchor
546
 
 * certificate that was found. This is not necessarily a root certificate
547
 
 * authority. If an intermediate certificate authority in the chain was
548
 
 * found to be anchored, then that certificate will be returned.
549
 
 *
550
 
 * If an anchor is returned it does not mean that the certificate chain has
551
 
 * been verified, but merely that an anchor has been found.
552
 
 *
553
 
 * Returns: the anchor certificate, or NULL if not anchored.
554
 
 */
555
 
GcrCertificate*
556
 
gcr_certificate_chain_get_anchor (GcrCertificateChain *self)
557
 
{
558
 
        g_return_val_if_fail (GCR_IS_CERTIFICATE_CHAIN (self), NULL);
559
 
        if (self->pv->status != GCR_CERTIFICATE_CHAIN_ANCHORED)
560
 
                return NULL;
561
 
        g_assert (self->pv->certificates->len > 0);
562
 
        return GCR_CERTIFICATE (g_ptr_array_index (self->pv->certificates,
563
 
                                                   self->pv->certificates->len - 1));
564
 
}
565
 
 
566
 
/**
567
 
 * gcr_certificate_chain_get_endpoint:
568
 
 * @self: the #GcrCertificateChain
569
 
 *
570
 
 * Get the endpoint certificate in the chain. This is always the first
571
 
 * certificate in the chain. The endpoint certificate cannot be anchored.
572
 
 *
573
 
 * Returns: the endpoint certificate, or NULL if the chain is empty.
574
 
 */
575
 
GcrCertificate*
576
 
gcr_certificate_chain_get_endpoint (GcrCertificateChain *self)
577
 
{
578
 
        g_return_val_if_fail (GCR_IS_CERTIFICATE_CHAIN (self), NULL);
579
 
        if (!self->pv->certificates->len)
580
 
                return NULL;
581
 
        return GCR_CERTIFICATE (g_ptr_array_index (self->pv->certificates, 0));
582
 
}
583
 
 
584
 
/**
585
 
 * gcr_certificate_chain_get_length:
586
 
 * @self: the #GcrCertificateChain
587
 
 *
588
 
 * Get the length of the certificate chain.
589
 
 *
590
 
 * Returns: the length of the certificate chain
591
 
 */
592
 
guint
593
 
gcr_certificate_chain_get_length (GcrCertificateChain *self)
594
 
{
595
 
        g_return_val_if_fail (GCR_IS_CERTIFICATE_CHAIN (self), 0);
596
 
        return self->pv->certificates->len;
597
 
}
598
 
 
599
 
/**
600
 
 * gcr_certificate_chain_get_certificate:
601
 
 * @self: the #GcrCertificateChain
602
 
 * @index: index of the certificate to get
603
 
 *
604
 
 * Get a certificate in the chain. It is an error to call this function
605
 
 * with an invalid index.
606
 
 *
607
 
 * Returns: the certificate
608
 
 */
609
 
GcrCertificate*
610
 
gcr_certificate_chain_get_certificate (GcrCertificateChain *self, guint index)
611
 
{
612
 
        g_return_val_if_fail (GCR_IS_CERTIFICATE_CHAIN (self), NULL);
613
 
        g_return_val_if_fail (index < self->pv->certificates->len, NULL);
614
 
        return GCR_CERTIFICATE (g_ptr_array_index (self->pv->certificates, index));
615
 
}
616
 
 
617
 
/**
618
 
 * gcr_certificate_chain_build:
619
 
 * @self: the #GcrCertificateChain
620
 
 * @purpose: the purpose the certificate chain will be used for
621
 
 * @peer: the peer the certificate chain will be used with, or NULL
622
 
 * @flags: chain completion flags
623
 
 * @cancellable: a #GCancellable or %NULL
624
 
 * @error: a #GError or %NULL
625
 
 *
626
 
 * Complete a certificate chain. Once a certificate chain has been built
627
 
 * its status can be examined.
628
 
 *
629
 
 * This operation will lookup missing certificates in PKCS\#11
630
 
 * modules and also that each certificate in the chain is the signer of the
631
 
 * previous one. If a trust anchor, pinned certificate, or self-signed certificate
632
 
 * is found, then the chain is considered built. Any extra certificates are
633
 
 * removed from the chain.
634
 
 *
635
 
 * It's important to understand that building of a certificate chain does not
636
 
 * constitute verifying that chain. This is merely the first step towards
637
 
 * trust verification.
638
 
 *
639
 
 * The @purpose is a string like %GCR_PURPOSE_CLIENT_AUTH and is the purpose
640
 
 * for which the certificate chain will be used. Trust anchors are looked up
641
 
 * for this purpose. This argument is required.
642
 
 *
643
 
 * The @peer is usually the host name of the peer whith which this certificate
644
 
 * chain is being used. It is used to look up pinned certificates that have
645
 
 * been stored for this peer. If %NULL then no pinned certificates will
646
 
 * be considered.
647
 
 *
648
 
 * If the %GCR_CERTIFICATE_CHAIN_FLAG_NO_LOOKUPS flag is specified then no
649
 
 * lookups for anchors or pinned certificates are done, and the resulting chain
650
 
 * will be neither anchored or pinned. Additionally no missing certificate
651
 
 * authorities are looked up in PKCS\#11
652
 
 *
653
 
 * This call will block, see gcr_certificate_chain_build_async() for the
654
 
 * asynchronous version.
655
 
 *
656
 
 * Returns: whether the operation completed successfully
657
 
 */
658
 
gboolean
659
 
gcr_certificate_chain_build (GcrCertificateChain *self, const gchar *purpose,
660
 
                             const gchar *peer, guint flags,
661
 
                             GCancellable *cancellable, GError **error)
662
 
{
663
 
        GcrCertificateChainPrivate *pv;
664
 
        gboolean ret;
665
 
 
666
 
        g_return_val_if_fail (GCR_IS_CERTIFICATE_CHAIN (self), FALSE);
667
 
        g_return_val_if_fail (purpose, FALSE);
668
 
 
669
 
        pv = prep_chain_private (self->pv, purpose, peer, flags);
670
 
 
671
 
        ret = perform_build_chain (pv, cancellable, error);
672
 
 
673
 
        if (ret) {
674
 
                free_chain_private (self->pv);
675
 
                self->pv = cleanup_chain_private (pv);
676
 
                g_object_notify (G_OBJECT (self), "status");
677
 
                g_object_notify (G_OBJECT (self), "length");
678
 
        } else {
679
 
                free_chain_private (pv);
680
 
        }
681
 
 
682
 
        return ret;
683
 
}
684
 
 
685
 
/**
686
 
 * gcr_certificate_chain_build_async:
687
 
 * @self: the #GcrCertificateChain
688
 
 * @purpose: the purpose the certificate chain will be used for
689
 
 * @peer: the peer the certificate chain will be used with, or NULL
690
 
 * @flags: chain completion flags
691
 
 * @cancellable: a #GCancellable or %NULL
692
 
 * @callback: this will be called when the operation completes.
693
 
 * @user_data: data to pass to the callback
694
 
 *
695
 
 * Complete a certificate chain. Once a certificate chain has been built
696
 
 * its status can be examined.
697
 
 *
698
 
 * This will lookup missing certificates in PKCS\#11
699
 
 * modules and also that each certificate in the chain is the signer of the
700
 
 * previous one. If a trust anchor, pinned certificate, or self-signed certificate
701
 
 * is found, then the chain is considered built. Any extra certificates are
702
 
 * removed from the chain.
703
 
 *
704
 
 * It's important to understand that building of a certificate chain does not
705
 
 * constitute verifying that chain. This is merely the first step towards
706
 
 * trust verification.
707
 
 *
708
 
 * The @purpose is a string like %GCR_PURPOSE_CLIENT_AUTH and is the purpose
709
 
 * for which the certificate chain will be used. Trust anchors are looked up
710
 
 * for this purpose. This argument is required.
711
 
 *
712
 
 * The @peer is usually the host name of the peer whith which this certificate
713
 
 * chain is being used. It is used to look up pinned certificates that have
714
 
 * been stored for this peer. If %NULL then no pinned certificates will
715
 
 * be considered.
716
 
 *
717
 
 * If the %GCR_CERTIFICATE_CHAIN_FLAG_NO_LOOKUPS flag is specified then no
718
 
 * lookups for anchors or pinned certificates are done, and the resulting chain
719
 
 * will be neither anchored or pinned. Additionally no missing certificate
720
 
 * authorities are looked up in PKCS\#11
721
 
 *
722
 
 * When the operation is finished, @callback will be called. You can then call
723
 
 * gcr_certificate_chain_build_finish() to get the result of the operation.
724
 
 */
725
 
void
726
 
gcr_certificate_chain_build_async (GcrCertificateChain *self, const gchar *purpose,
727
 
                                   const gchar *peer, guint flags,
728
 
                                   GCancellable *cancellable, GAsyncReadyCallback callback,
729
 
                                   gpointer user_data)
730
 
{
731
 
        GcrCertificateChainPrivate *pv;
732
 
        GSimpleAsyncResult *result;
733
 
 
734
 
        g_return_if_fail (GCR_IS_CERTIFICATE_CHAIN (self));
735
 
 
736
 
        g_return_if_fail (GCR_IS_CERTIFICATE_CHAIN (self));
737
 
        g_return_if_fail (purpose);
738
 
 
739
 
        pv = prep_chain_private_thread_safe (self->pv, purpose, peer, flags);
740
 
 
741
 
        result = g_simple_async_result_new (G_OBJECT (self), callback, user_data,
742
 
                                            gcr_certificate_chain_build_async);
743
 
        g_object_set_qdata_full (G_OBJECT (result), Q_OPERATION_DATA, pv, free_chain_private);
744
 
 
745
 
        g_simple_async_result_run_in_thread (result, thread_build_chain,
746
 
                                             G_PRIORITY_DEFAULT, cancellable);
747
 
        g_object_unref (result);
748
 
}
749
 
 
750
 
/**
751
 
 * gcr_certificate_chain_build_finish:
752
 
 * @self: the #GcrCertificateChain
753
 
 * @result: the #GAsyncResult passed to the callback
754
 
 * @error: a #GError, or NULL
755
 
 *
756
 
 * Finishes an asynchronous operation started by
757
 
 * gcr_certificate_chain_build_async().
758
 
 *
759
 
 * Returns: whether the operation succeeded
760
 
 */
761
 
gboolean
762
 
gcr_certificate_chain_build_finish (GcrCertificateChain *self, GAsyncResult *result,
763
 
                                    GError **error)
764
 
{
765
 
        GcrCertificateChainPrivate *pv;
766
 
 
767
 
        g_return_val_if_fail (GCR_IS_CERTIFICATE_CHAIN (self), FALSE);
768
 
        g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE);
769
 
        g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (self),
770
 
                              gcr_certificate_chain_build_async), FALSE);
771
 
 
772
 
        if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error))
773
 
                return FALSE;
774
 
 
775
 
        pv = g_object_steal_qdata (G_OBJECT (result), Q_OPERATION_DATA);
776
 
        g_return_val_if_fail (pv, FALSE);
777
 
 
778
 
        free_chain_private (self->pv);
779
 
        self->pv = cleanup_chain_private (pv);
780
 
 
781
 
        g_object_notify (G_OBJECT (self), "status");
782
 
        g_object_notify (G_OBJECT (self), "length");
783
 
        return TRUE;
784
 
}