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