minimal build
[platform/upstream/gcr.git] / gcr / gcr-pkcs11-certificate.c
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-pkcs11-certificate.h"
27
28 #include "gcr-certificate.h"
29 #include "gcr-internal.h"
30 #include "gcr-library.h"
31
32 #include <gck/gck.h>
33
34 #include <string.h>
35
36 /**
37  * SECTION:gcr-pkcs11-certificate
38  * @title: GcrPkcs11Certificate
39  * @short_description: A certificate loaded from PKCS\#11 storage
40  *
41  * A #GcrPkcs11Certificate is a certificate loaded from a PKCS\#11 storage.
42  * It is also a valid #GckObject and can be used as such.
43  *
44  * Use gcr_pkcs11_certificate_lookup_issuer() to lookup the issuer of a given
45  * certificate in the PKCS\#11 store.
46  *
47  * Various common PKCS\#11 certificate attributes are automatically loaded and
48  * are available via gcr_pkcs11_certificate_get_attributes().
49  */
50
51 /**
52  * GcrPkcs11Certificate:
53  *
54  * A certificate loaded from PKCS\#11 storage.
55  */
56
57 /**
58  * GcrPkcs11CertificateClass:
59  *
60  * The class for #GcrPkcs11Certificate.
61  */
62
63 enum {
64         PROP_0,
65         PROP_ATTRIBUTES
66 };
67
68 struct _GcrPkcs11CertificatePrivate {
69         GckAttributes *attrs;
70 };
71
72 static void gcr_certificate_iface (GcrCertificateIface *iface);
73 G_DEFINE_TYPE_WITH_CODE (GcrPkcs11Certificate, gcr_pkcs11_certificate, GCK_TYPE_OBJECT,
74         GCR_CERTIFICATE_MIXIN_IMPLEMENT_COMPARABLE ();
75         G_IMPLEMENT_INTERFACE (GCR_TYPE_CERTIFICATE, gcr_certificate_iface);
76 );
77
78 typedef struct {
79         GckAttributes *search;
80         GcrCertificate *result;
81 } lookup_issuer_closure;
82
83 static void
84 lookup_issuer_free (gpointer data)
85 {
86         lookup_issuer_closure *closure = data;
87         gck_attributes_unref (closure->search);
88         g_clear_object (&closure->result);
89         g_free (closure);
90 }
91
92 static GckAttributes *
93 prepare_lookup_certificate_issuer (GcrCertificate *cert)
94 {
95         GckBuilder builder = GCK_BUILDER_INIT;
96         gpointer data;
97         gsize n_data;
98
99         gck_builder_add_ulong (&builder, CKA_CLASS, CKO_CERTIFICATE);
100         gck_builder_add_ulong (&builder, CKA_CERTIFICATE_TYPE, CKC_X_509);
101
102         data = gcr_certificate_get_issuer_raw (cert, &n_data);
103         gck_builder_add_data (&builder, CKA_SUBJECT, data, n_data);
104         g_free (data);
105
106         return gck_attributes_ref_sink (gck_builder_end (&builder));
107 }
108
109 static GcrCertificate*
110 perform_lookup_certificate (GckAttributes *search,
111                             GCancellable *cancellable,
112                             GError **error)
113 {
114         GcrCertificate *cert;
115         GckObject *object;
116         GckAttributes *attrs;
117         GckModule *module;
118         GckSession *session;
119         GckEnumerator *en;
120         GList *modules;
121
122         if (!gcr_pkcs11_initialize (cancellable, error))
123                 return NULL;
124
125         modules = gcr_pkcs11_get_modules ();
126         en = gck_modules_enumerate_objects (modules, search, 0);
127         gck_list_unref_free (modules);
128
129         object = gck_enumerator_next (en, cancellable, error);
130         g_object_unref (en);
131
132         if (object == NULL)
133                 return NULL;
134
135         /*
136          * Only the CKA_VALUE, CKA_CLASS and CKA_CERTIFICATE_TYPE
137          * is strictly necessary here, but we get more attrs.
138          */
139         attrs = gck_object_get (object, cancellable, error,
140                                 CKA_VALUE, CKA_LABEL,
141                                 CKA_ID, CKA_CLASS,
142                                 CKA_CERTIFICATE_TYPE,
143                                 CKA_ISSUER,
144                                 CKA_SERIAL_NUMBER,
145                                 GCK_INVALID);
146
147         if (attrs == NULL) {
148                 g_object_unref (object);
149                 return NULL;
150         }
151
152         module = gck_object_get_module (object);
153         session = gck_object_get_session (object);
154
155         cert = g_object_new (GCR_TYPE_PKCS11_CERTIFICATE,
156                              "module", module,
157                              "handle", gck_object_get_handle (object),
158                              "session", session,
159                              "attributes", attrs,
160                              NULL);
161
162         g_object_unref (module);
163         g_object_unref (session);
164         g_object_unref (object);
165
166         gck_attributes_unref (attrs);
167
168         return cert;
169 }
170
171 static void
172 thread_lookup_certificate (GSimpleAsyncResult *res, GObject *object, GCancellable *cancel)
173 {
174         lookup_issuer_closure *closure;
175         GError *error = NULL;
176
177         closure = g_simple_async_result_get_op_res_gpointer (res);
178         closure->result = perform_lookup_certificate (closure->search, cancel, &error);
179
180         if (error != NULL) {
181                 g_simple_async_result_set_from_error (res, error);
182                 g_clear_error (&error);
183         }
184 }
185
186 /* ----------------------------------------------------------------------------
187  * OBJECT
188  */
189
190 static GObject*
191 gcr_pkcs11_certificate_constructor (GType type, guint n_props, GObjectConstructParam *props)
192 {
193         gpointer obj = G_OBJECT_CLASS (gcr_pkcs11_certificate_parent_class)->constructor (type, n_props, props);
194         GckAttributes *attrs;
195         const GckAttribute *attr;
196         gulong value;
197
198         attrs = gcr_pkcs11_certificate_get_attributes (obj);
199         g_return_val_if_fail (attrs, NULL);
200
201         if (!gck_attributes_find_ulong (attrs, CKA_CLASS, &value) ||
202             value != CKO_CERTIFICATE) {
203                 g_warning ("attributes don't contain a certificate with: %s",
204                            "CKA_CLASS == CKO_CERTIFICATE");
205                 return NULL;
206         }
207
208         if (!gck_attributes_find_ulong (attrs, CKA_CERTIFICATE_TYPE, &value) ||
209             value != CKC_X_509) {
210                 g_warning ("attributes don't contain a certificate with: %s",
211                            "CKA_CERTIFICATE_TYPE == CKC_X_509");
212                 return NULL;
213         }
214
215         attr = gck_attributes_find (attrs, CKA_VALUE);
216         if (!attr || !attr->value || attr->length == 0 || attr->length == G_MAXULONG) {
217                 g_warning ("attributes don't contain a valid: CKA_VALUE");
218                 return NULL;
219         }
220
221         return obj;
222 }
223
224 static void
225 gcr_pkcs11_certificate_init (GcrPkcs11Certificate *self)
226 {
227         self->pv = G_TYPE_INSTANCE_GET_PRIVATE (self, GCR_TYPE_PKCS11_CERTIFICATE, GcrPkcs11CertificatePrivate);
228 }
229
230 static void
231 gcr_pkcs11_certificate_set_property (GObject *obj, guint prop_id, const GValue *value,
232                                      GParamSpec *pspec)
233 {
234         GcrPkcs11Certificate *self = GCR_PKCS11_CERTIFICATE (obj);
235
236         switch (prop_id) {
237         case PROP_ATTRIBUTES:
238                 g_return_if_fail (self->pv->attrs == NULL);
239                 self->pv->attrs = g_value_dup_boxed (value);
240                 g_return_if_fail (self->pv->attrs != NULL);
241                 break;
242         default:
243                 G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
244                 break;
245         }
246 }
247
248 static void
249 gcr_pkcs11_certificate_get_property (GObject *obj, guint prop_id, GValue *value,
250                                      GParamSpec *pspec)
251 {
252         GcrPkcs11Certificate *self = GCR_PKCS11_CERTIFICATE (obj);
253
254         switch (prop_id) {
255         case PROP_ATTRIBUTES:
256                 g_value_set_boxed (value, gcr_pkcs11_certificate_get_attributes (self));
257                 break;
258         default:
259                 gcr_certificate_mixin_get_property (obj, prop_id, value, pspec);
260                 break;
261         }
262 }
263
264 static void
265 gcr_pkcs11_certificate_finalize (GObject *obj)
266 {
267         GcrPkcs11Certificate *self = GCR_PKCS11_CERTIFICATE (obj);
268
269         gck_attributes_unref (self->pv->attrs);
270
271         G_OBJECT_CLASS (gcr_pkcs11_certificate_parent_class)->finalize (obj);
272 }
273
274 static void
275 gcr_pkcs11_certificate_class_init (GcrPkcs11CertificateClass *klass)
276 {
277         GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
278
279         gobject_class->constructor = gcr_pkcs11_certificate_constructor;
280         gobject_class->get_property = gcr_pkcs11_certificate_get_property;
281         gobject_class->set_property = gcr_pkcs11_certificate_set_property;
282         gobject_class->finalize = gcr_pkcs11_certificate_finalize;
283
284         /**
285          * GcrPkcs11Certificate:attributes:
286          *
287          * Automatically loaded attributes for this certificate.
288          */
289         g_object_class_install_property (gobject_class, PROP_ATTRIBUTES,
290                  g_param_spec_boxed ("attributes", "Attributes", "The data displayed in the renderer",
291                                      GCK_TYPE_ATTRIBUTES, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
292
293         g_type_class_add_private (gobject_class, sizeof (GcrPkcs11CertificatePrivate));
294
295         gcr_certificate_mixin_class_init (gobject_class);
296         _gcr_initialize_library ();
297 }
298
299 static const guchar *
300 gcr_pkcs11_certificate_get_der_data (GcrCertificate *cert,
301                                      gsize *n_data)
302 {
303         GcrPkcs11Certificate *self = GCR_PKCS11_CERTIFICATE (cert);
304         const GckAttribute *attr;
305
306         g_return_val_if_fail (GCR_IS_CERTIFICATE (self), NULL);
307         g_return_val_if_fail (n_data, NULL);
308         g_return_val_if_fail (self->pv->attrs, NULL);
309
310         attr = gck_attributes_find (self->pv->attrs, CKA_VALUE);
311         g_return_val_if_fail (attr && attr->length != 0 && attr->length != G_MAXULONG, NULL);
312         *n_data = attr->length;
313         return attr->value;
314 }
315
316 static void
317 gcr_certificate_iface (GcrCertificateIface *iface)
318 {
319         iface->get_der_data = gcr_pkcs11_certificate_get_der_data;
320 }
321
322 /* -----------------------------------------------------------------------------
323  * PUBLIC
324  */
325
326 /**
327  * gcr_pkcs11_certificate_get_attributes:
328  * @self: A #GcrPkcs11Certificate
329  *
330  * Access the automatically loaded attributes for this certificate.
331  *
332  * Returns: (transfer none): the certificate attributes
333  */
334 GckAttributes *
335 gcr_pkcs11_certificate_get_attributes (GcrPkcs11Certificate *self)
336 {
337         g_return_val_if_fail (GCR_IS_PKCS11_CERTIFICATE (self), NULL);
338         return self->pv->attrs;
339 }
340
341 /**
342  * gcr_pkcs11_certificate_lookup_issuer:
343  * @certificate: a #GcrCertificate
344  * @cancellable: a #GCancellable
345  * @error: a #GError, or NULL
346  *
347  * Lookup a the issuer of a @certificate in the PKCS\#11 storage. The
348  * lookup is done using the issuer DN of the certificate. No certificate chain
349  * verification is done. Use a crypto library to make trust decisions.
350  *
351  * This call may block, see gcr_pkcs11_certificate_lookup_issuer() for the
352  * non-blocking version.
353  *
354  * Will return %NULL if no issuer certificate is found. Use @error to determine
355  * if an error occurred.
356  *
357  * Returns: (transfer full): a new #GcrPkcs11Certificate, or %NULL
358  */
359 GcrCertificate *
360 gcr_pkcs11_certificate_lookup_issuer (GcrCertificate *certificate, GCancellable *cancellable,
361                                       GError **error)
362 {
363         GckAttributes *search;
364         GcrCertificate *issuer;
365
366         g_return_val_if_fail (GCR_IS_CERTIFICATE (certificate), NULL);
367
368         if (!gcr_pkcs11_initialize (cancellable, error))
369                 return NULL;
370
371         search = prepare_lookup_certificate_issuer (certificate);
372         g_return_val_if_fail (search, FALSE);
373
374         issuer = perform_lookup_certificate (search, cancellable, error);
375         gck_attributes_unref (search);
376
377         return issuer;
378 }
379
380 /**
381  * gcr_pkcs11_certificate_lookup_issuer_async:
382  * @certificate: a #GcrCertificate
383  * @cancellable: a #GCancellable
384  * @callback: a #GAsyncReadyCallback to call when the operation completes
385  * @user_data: the data to pass to callback function
386  *
387  * Lookup a the issuer of a @certificate in the PKCS\#11 storage. The
388  * lookup is done using the issuer DN of the certificate. No certificate chain
389  * verification is done. Use a crypto library to make trust decisions.
390  *
391  * When the operation is finished, callback will be called. You can then call
392  * gcr_pkcs11_certificate_lookup_issuer_finish() to get the result of the
393  * operation.
394  */
395 void
396 gcr_pkcs11_certificate_lookup_issuer_async (GcrCertificate *certificate, GCancellable *cancellable,
397                                             GAsyncReadyCallback callback, gpointer user_data)
398 {
399         GSimpleAsyncResult *async;
400         lookup_issuer_closure *closure;
401
402         g_return_if_fail (GCR_IS_CERTIFICATE (certificate));
403
404         async = g_simple_async_result_new (G_OBJECT (certificate), callback, user_data,
405                                            gcr_pkcs11_certificate_lookup_issuer_async);
406         closure = g_new0 (lookup_issuer_closure, 1);
407         closure->search = prepare_lookup_certificate_issuer (certificate);
408         g_return_if_fail (closure->search);
409         g_simple_async_result_set_op_res_gpointer (async, closure, lookup_issuer_free);
410
411         g_simple_async_result_run_in_thread (async, thread_lookup_certificate,
412                                              G_PRIORITY_DEFAULT, cancellable);
413
414         g_object_unref (async);
415 }
416
417 /**
418  * gcr_pkcs11_certificate_lookup_issuer_finish:
419  * @result: the #GAsyncResult passed to the callback
420  * @error: a #GError, or NULL
421  *
422  * Finishes an asynchronous operation started by
423  * gcr_pkcs11_certificate_lookup_issuer_async().
424  *
425  * Will return %NULL if no issuer certificate is found. Use @error to determine
426  * if an error occurred.
427  *
428  * Returns: (transfer full): a new #GcrPkcs11Certificate, or %NULL
429  */
430 GcrCertificate *
431 gcr_pkcs11_certificate_lookup_issuer_finish (GAsyncResult *result, GError **error)
432 {
433         lookup_issuer_closure *closure;
434         GObject *source;
435
436         g_return_val_if_fail (G_IS_ASYNC_RESULT (result), NULL);
437
438         source = g_async_result_get_source_object (result);
439         g_return_val_if_fail (g_simple_async_result_is_valid (result, source,
440                               gcr_pkcs11_certificate_lookup_issuer_async), NULL);
441         g_object_unref (source);
442
443         if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error))
444                 return NULL;
445
446         closure = g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (result));
447         if (closure->result != NULL)
448                 g_object_ref (closure->result);
449         return closure->result;
450 }