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-types.h"
25 : : #include "gcr-internal.h"
26 : : #include "gcr-library.h"
27 : : #include "gcr-trust.h"
28 : :
29 : : #include "gck/gck.h"
30 : : #include "gck/pkcs11n.h"
31 : : #include "gck/pkcs11i.h"
32 : : #include "gck/pkcs11x.h"
33 : :
34 : : #include <glib/gi18n-lib.h>
35 : :
36 : : /**
37 : : * GCR_PURPOSE_SERVER_AUTH:
38 : : *
39 : : * The purpose used to verify the server certificate in a TLS connection. This
40 : : * is the most common purpose in use.
41 : : */
42 : :
43 : : /**
44 : : * GCR_PURPOSE_CLIENT_AUTH:
45 : : *
46 : : * The purpose used to verify the client certificate in a TLS connection.
47 : : */
48 : :
49 : : /**
50 : : * GCR_PURPOSE_CODE_SIGNING:
51 : : *
52 : : * The purpose used to verify certificate used for the signature on signed code.
53 : : */
54 : :
55 : : /**
56 : : * GCR_PURPOSE_EMAIL:
57 : : *
58 : : * The purpose used to verify certificates that are used in email communication
59 : : * such as S/MIME.
60 : : */
61 : :
62 : : /* ----------------------------------------------------------------------------------
63 : : * HELPERS
64 : : */
65 : :
66 : : static void
67 : 25 : prepare_trust_attrs (GcrCertificate *certificate,
68 : : CK_X_ASSERTION_TYPE type,
69 : : GckBuilder *builder)
70 : : {
71 : : gconstpointer data;
72 : : gsize n_data;
73 : :
74 : 25 : gck_builder_add_ulong (builder, CKA_CLASS, CKO_X_TRUST_ASSERTION);
75 : 25 : gck_builder_add_ulong (builder, CKA_X_ASSERTION_TYPE, type);
76 : :
77 : 25 : data = gcr_certificate_get_der_data (certificate, &n_data);
78 [ - + ]: 25 : g_return_if_fail (data);
79 : 25 : gck_builder_add_data (builder, CKA_X_CERTIFICATE_VALUE, data, n_data);
80 : : }
81 : :
82 : : /* ----------------------------------------------------------------------------------
83 : : * GET PINNED CERTIFICATE
84 : : */
85 : :
86 : : static GckAttributes *
87 : 10 : prepare_is_certificate_pinned (GcrCertificate *certificate, const gchar *purpose, const gchar *peer)
88 : : {
89 : 10 : GckBuilder builder = GCK_BUILDER_INIT;
90 : :
91 : 10 : prepare_trust_attrs (certificate, CKT_X_PINNED_CERTIFICATE, &builder);
92 : :
93 : 10 : gck_builder_add_string (&builder, CKA_X_PURPOSE, purpose);
94 : 10 : gck_builder_add_string (&builder, CKA_X_PEER, peer);
95 : :
96 : 10 : return gck_builder_end (&builder);
97 : : }
98 : :
99 : : static gboolean
100 : 10 : perform_is_certificate_pinned (GckAttributes *search,
101 : : GCancellable *cancellable,
102 : : GError **error)
103 : : {
104 : : GckEnumerator *en;
105 : : GList *slots;
106 : : GckObject *object;
107 : :
108 [ - + ]: 10 : if (!gcr_pkcs11_initialize (cancellable, error))
109 : 0 : return FALSE;
110 : :
111 : 10 : slots = gcr_pkcs11_get_trust_lookup_slots ();
112 : 10 : g_debug ("searching for pinned certificate in %d slots",
113 : : g_list_length (slots));
114 : 10 : en = gck_slots_enumerate_objects (slots, search, 0);
115 [ + - + - ]: 10 : g_clear_list (&slots, g_object_unref);
116 : :
117 : 10 : object = gck_enumerator_next (en, cancellable, error);
118 : 10 : g_object_unref (en);
119 : :
120 [ + + ]: 10 : if (object)
121 : 5 : g_object_unref (object);
122 : :
123 [ + + ]: 10 : g_debug ("%s certificate anchor", object ? "found" : "did not find");
124 : 10 : return (object != NULL);
125 : : }
126 : :
127 : : /**
128 : : * gcr_trust_is_certificate_pinned:
129 : : * @certificate: a #GcrCertificate to check
130 : : * @purpose: the purpose string
131 : : * @peer: the peer for this pinned
132 : : * @cancellable: a #GCancellable
133 : : * @error: a #GError, or %NULL
134 : : *
135 : : * Check if @certificate is pinned for @purpose to communicate with @peer.
136 : : * A pinned certificate overrides all other certificate verification.
137 : : *
138 : : * This call may block, see gcr_trust_is_certificate_pinned_async() for the
139 : : * non-blocking version.
140 : : *
141 : : * In the case of an error, %FALSE is also returned. Check @error to detect
142 : : * if an error occurred.
143 : : *
144 : : * Returns: %TRUE if the certificate is pinned for the host and purpose
145 : : */
146 : : gboolean
147 : 6 : gcr_trust_is_certificate_pinned (GcrCertificate *certificate, const gchar *purpose,
148 : : const gchar *peer, GCancellable *cancellable, GError **error)
149 : : {
150 : : GckAttributes *search;
151 : : gboolean ret;
152 : :
153 [ - + + - : 6 : g_return_val_if_fail (GCR_IS_CERTIFICATE (certificate), FALSE);
- + - + ]
154 [ - + ]: 6 : g_return_val_if_fail (purpose, FALSE);
155 [ - + ]: 6 : g_return_val_if_fail (peer, FALSE);
156 : :
157 : 6 : search = prepare_is_certificate_pinned (certificate, purpose, peer);
158 [ - + ]: 6 : g_return_val_if_fail (search, FALSE);
159 : :
160 : 6 : ret = perform_is_certificate_pinned (search, cancellable, error);
161 : 6 : gck_attributes_unref (search);
162 : :
163 : 6 : return ret;
164 : : }
165 : :
166 : : static void
167 : 4 : thread_is_certificate_pinned (GTask *task, gpointer object,
168 : : gpointer task_data, GCancellable *cancellable)
169 : : {
170 : 4 : GckAttributes *attrs = task_data;
171 : 4 : GError *error = NULL;
172 : : gboolean found;
173 : :
174 : 4 : found = perform_is_certificate_pinned (attrs, cancellable, &error);
175 [ + - ]: 4 : if (error == NULL)
176 : 4 : g_task_return_boolean (task, found);
177 : : else
178 : 0 : g_task_return_error (task, g_steal_pointer (&error));
179 : 4 : }
180 : :
181 : : /**
182 : : * gcr_trust_is_certificate_pinned_async:
183 : : * @certificate: a #GcrCertificate to check
184 : : * @purpose: the purpose string
185 : : * @peer: the peer for this pinned
186 : : * @cancellable: a #GCancellable
187 : : * @callback: a #GAsyncReadyCallback to call when the operation completes
188 : : * @user_data: the data to pass to callback function
189 : : *
190 : : * Check if @certificate is pinned for @purpose to communicate with @peer. A
191 : : * pinned certificate overrides all other certificate verification.
192 : : *
193 : : * When the operation is finished, callback will be called. You can then call
194 : : * [func@Gcr.trust_is_certificate_pinned_finish] to get the result of the
195 : : * operation.
196 : : */
197 : : void
198 : 4 : gcr_trust_is_certificate_pinned_async (GcrCertificate *certificate, const gchar *purpose,
199 : : const gchar *peer, GCancellable *cancellable,
200 : : GAsyncReadyCallback callback, gpointer user_data)
201 : : {
202 : : GTask *task;
203 : : GckAttributes *attrs;
204 : :
205 [ - + + - : 4 : g_return_if_fail (GCR_IS_CERTIFICATE (certificate));
- + - + ]
206 [ - + ]: 4 : g_return_if_fail (purpose);
207 [ - + ]: 4 : g_return_if_fail (peer);
208 : :
209 : 4 : task = g_task_new (NULL, cancellable, callback, user_data);
210 [ + - ]: 4 : g_task_set_source_tag (task, gcr_trust_is_certificate_pinned_async);
211 : :
212 : 4 : attrs = prepare_is_certificate_pinned (certificate, purpose, peer);
213 [ - + ]: 4 : g_return_if_fail (attrs);
214 : 4 : g_task_set_task_data (task, attrs, gck_attributes_unref);
215 : :
216 : 4 : g_task_run_in_thread (task, thread_is_certificate_pinned);
217 : :
218 [ + - ]: 4 : g_clear_object (&task);
219 : : }
220 : :
221 : : /**
222 : : * gcr_trust_is_certificate_pinned_finish:
223 : : * @result: the #GAsyncResult passed to the callback
224 : : * @error: a #GError, or %NULL
225 : : *
226 : : * Finishes an asynchronous operation started by
227 : : * gcr_trust_is_certificate_pinned_async().
228 : : *
229 : : * In the case of an error, %FALSE is also returned. Check @error to detect
230 : : * if an error occurred.
231 : : *
232 : : * Returns: %TRUE if the certificate is pinned.
233 : : */
234 : : gboolean
235 : 4 : gcr_trust_is_certificate_pinned_finish (GAsyncResult *result, GError **error)
236 : : {
237 [ + - - + ]: 4 : g_return_val_if_fail (!error || !*error, FALSE);
238 [ - + ]: 4 : g_return_val_if_fail (g_task_is_valid (result, NULL), FALSE);
239 : :
240 : 4 : return g_task_propagate_boolean (G_TASK (result), error);
241 : : }
242 : :
243 : : /* ----------------------------------------------------------------------------------
244 : : * ADD PINNED CERTIFICATE
245 : : */
246 : :
247 : : static GckAttributes *
248 : 5 : prepare_add_pinned_certificate (GcrCertificate *certificate, const gchar *purpose, const gchar *peer)
249 : : {
250 : 5 : GckBuilder builder = GCK_BUILDER_INIT;
251 : :
252 : 5 : prepare_trust_attrs (certificate, CKT_X_PINNED_CERTIFICATE, &builder);
253 : :
254 : 5 : gck_builder_add_string (&builder, CKA_X_PURPOSE, purpose);
255 : 5 : gck_builder_add_string (&builder, CKA_X_PEER, peer);
256 : 5 : gck_builder_add_boolean (&builder, CKA_TOKEN, TRUE);
257 : :
258 : 5 : return gck_builder_end (&builder);
259 : : }
260 : :
261 : : static gboolean
262 : 5 : perform_add_pinned_certificate (GckAttributes *search,
263 : : GCancellable *cancellable,
264 : : GError **error)
265 : : {
266 : 5 : GckBuilder builder = GCK_BUILDER_INIT;
267 : 5 : gboolean ret = FALSE;
268 : 5 : GError *lerr = NULL;
269 : : GckObject *object;
270 : : GckSession *session;
271 : : GckSlot *slot;
272 : : GckEnumerator *en;
273 : : GList *slots;
274 : :
275 [ - + ]: 5 : if (!gcr_pkcs11_initialize (cancellable, error))
276 : 0 : return FALSE;
277 : :
278 : 5 : slots = gcr_pkcs11_get_trust_lookup_slots ();
279 : 5 : en = gck_slots_enumerate_objects (slots, search, CKF_RW_SESSION);
280 [ + - ]: 5 : g_clear_list (&slots, g_object_unref);
281 : :
282 : 5 : object = gck_enumerator_next (en, cancellable, &lerr);
283 : 5 : g_object_unref (en);
284 : :
285 [ - + ]: 5 : if (lerr != NULL) {
286 : 0 : g_propagate_error (error, lerr);
287 : 0 : return FALSE;
288 : : }
289 : :
290 : : /* It already exists */
291 [ - + ]: 5 : if (object) {
292 : 0 : g_object_unref (object);
293 : 0 : return TRUE;
294 : : }
295 : :
296 : 5 : gck_builder_add_all (&builder, search);
297 : :
298 : : /* TODO: Add relevant label */
299 : :
300 : : /* Find an appropriate token */
301 : 5 : slot = gcr_pkcs11_get_trust_store_slot ();
302 [ - + ]: 5 : if (slot == NULL) {
303 : 0 : g_set_error (&lerr, GCK_ERROR, CKR_FUNCTION_FAILED,
304 : : /* Translators: A pinned certificate is an exception which
305 : : trusts a given certificate explicitly for a purpose and
306 : : communication with a certain peer. */
307 : : _("Couldn’t find a place to store the pinned certificate"));
308 : 0 : ret = FALSE;
309 : : } else {
310 : 5 : session = gck_slot_open_session (slot, CKF_RW_SESSION, NULL, NULL, &lerr);
311 [ + - ]: 5 : if (session != NULL) {
312 : 5 : GckAttributes *attrs = gck_builder_end (&builder);
313 : 5 : object = gck_session_create_object (session, attrs,
314 : : cancellable, &lerr);
315 [ + + ]: 5 : if (object != NULL) {
316 : 4 : g_object_unref (object);
317 : 4 : ret = TRUE;
318 : : }
319 : :
320 : 5 : g_object_unref (session);
321 : 5 : gck_attributes_unref (attrs);
322 : : }
323 : :
324 : 5 : g_object_unref (slot);
325 : : }
326 : :
327 : 5 : gck_builder_clear (&builder);
328 : :
329 [ + + ]: 5 : if (!ret)
330 : 1 : g_propagate_error (error, lerr);
331 : :
332 : 5 : return ret;
333 : : }
334 : :
335 : : /**
336 : : * gcr_trust_add_pinned_certificate:
337 : : * @certificate: a #GcrCertificate
338 : : * @purpose: the purpose string
339 : : * @peer: the peer for this pinned certificate
340 : : * @cancellable: a #GCancellable
341 : : * @error: a #GError, or %NULL
342 : : *
343 : : * Add a pinned @certificate for connections to @peer for @purpose. A pinned
344 : : * certificate overrides all other certificate verification and should be
345 : : * used with care.
346 : : *
347 : : * If the same pinned certificate already exists, then this operation
348 : : * does not add another, and succeeds without error.
349 : : *
350 : : * This call may block, see gcr_trust_add_pinned_certificate_async() for the
351 : : * non-blocking version.
352 : : *
353 : : * Returns: %TRUE if the pinned certificate is recorded successfully
354 : : */
355 : : gboolean
356 : 3 : gcr_trust_add_pinned_certificate (GcrCertificate *certificate, const gchar *purpose, const gchar *peer,
357 : : GCancellable *cancellable, GError **error)
358 : : {
359 : : GckAttributes *search;
360 : : gboolean ret;
361 : :
362 [ - + + - : 3 : g_return_val_if_fail (GCR_IS_CERTIFICATE (certificate), FALSE);
- + - + ]
363 [ - + ]: 3 : g_return_val_if_fail (purpose, FALSE);
364 [ - + ]: 3 : g_return_val_if_fail (peer, FALSE);
365 : :
366 : 3 : search = prepare_add_pinned_certificate (certificate, purpose, peer);
367 [ - + ]: 3 : g_return_val_if_fail (search, FALSE);
368 : :
369 : 3 : ret = perform_add_pinned_certificate (search, cancellable, error);
370 : 3 : gck_attributes_unref (search);
371 : :
372 : 3 : return ret;
373 : : }
374 : :
375 : : static void
376 : 2 : thread_add_pinned_certificate (GTask *task, gpointer object,
377 : : gpointer task_data, GCancellable *cancellable)
378 : : {
379 : 2 : GckAttributes *attrs = task_data;
380 : 2 : GError *error = NULL;
381 : :
382 : 2 : perform_add_pinned_certificate (attrs, cancellable, &error);
383 [ + - ]: 2 : if (error == NULL)
384 : 2 : g_task_return_boolean (task, TRUE);
385 : : else
386 : 0 : g_task_return_error (task, g_steal_pointer (&error));
387 : 2 : }
388 : :
389 : : /**
390 : : * gcr_trust_add_pinned_certificate_async:
391 : : * @certificate: a #GcrCertificate
392 : : * @purpose: the purpose string
393 : : * @peer: the peer for this pinned certificate
394 : : * @cancellable: a #GCancellable
395 : : * @callback: a #GAsyncReadyCallback to call when the operation completes
396 : : * @user_data: the data to pass to callback function
397 : : *
398 : : * Add a pinned certificate for communication with @peer for @purpose. A pinned
399 : : * certificate overrides all other certificate verification and should be used
400 : : * with care.
401 : : *
402 : : * If the same pinned certificate already exists, then this operation
403 : : * does not add another, and succeeds without error.
404 : : *
405 : : * When the operation is finished, callback will be called. You can then call
406 : : * [func@Gcr.trust_add_pinned_certificate_finish] to get the result of the
407 : : * operation.
408 : : */
409 : : void
410 : 2 : gcr_trust_add_pinned_certificate_async (GcrCertificate *certificate, const gchar *purpose,
411 : : const gchar *peer, GCancellable *cancellable,
412 : : GAsyncReadyCallback callback, gpointer user_data)
413 : : {
414 : : GTask *task;
415 : : GckAttributes *attrs;
416 : :
417 [ - + + - : 2 : g_return_if_fail (GCR_IS_CERTIFICATE (certificate));
- + - + ]
418 [ - + ]: 2 : g_return_if_fail (purpose);
419 [ - + ]: 2 : g_return_if_fail (peer);
420 : :
421 : 2 : task = g_task_new (NULL, cancellable, callback, user_data);
422 [ + - ]: 2 : g_task_set_source_tag (task, gcr_trust_add_pinned_certificate_async);
423 : :
424 : 2 : attrs = prepare_add_pinned_certificate (certificate, purpose, peer);
425 [ - + ]: 2 : g_return_if_fail (attrs);
426 : 2 : g_task_set_task_data (task, attrs, gck_attributes_unref);
427 : :
428 : 2 : g_task_run_in_thread (task, thread_add_pinned_certificate);
429 : :
430 [ + - ]: 2 : g_clear_object (&task);
431 : : }
432 : :
433 : : /**
434 : : * gcr_trust_add_pinned_certificate_finish:
435 : : * @result: the #GAsyncResult passed to the callback
436 : : * @error: a #GError, or %NULL
437 : : *
438 : : * Finishes an asynchronous operation started by
439 : : * gcr_trust_add_pinned_certificate_async().
440 : : *
441 : : * Returns: %TRUE if the pinned certificate is recorded successfully
442 : : */
443 : : gboolean
444 : 2 : gcr_trust_add_pinned_certificate_finish (GAsyncResult *result, GError **error)
445 : : {
446 [ + - - + ]: 2 : g_return_val_if_fail (!error || !*error, FALSE);
447 [ - + ]: 2 : g_return_val_if_fail (g_task_is_valid (result, NULL), FALSE);
448 : :
449 : 2 : return g_task_propagate_boolean (G_TASK (result), error);
450 : : }
451 : :
452 : : /* -----------------------------------------------------------------------
453 : : * REMOVE PINNED CERTIFICATE
454 : : */
455 : :
456 : : static GckAttributes *
457 : 2 : prepare_remove_pinned_certificate (GcrCertificate *certificate, const gchar *purpose,
458 : : const gchar *peer)
459 : : {
460 : 2 : GckBuilder builder = GCK_BUILDER_INIT;
461 : :
462 : 2 : prepare_trust_attrs (certificate, CKT_X_PINNED_CERTIFICATE, &builder);
463 : 2 : gck_builder_add_string (&builder, CKA_X_PURPOSE, purpose);
464 : 2 : gck_builder_add_string (&builder, CKA_X_PEER, peer);
465 : :
466 : 2 : return gck_builder_end (&builder);
467 : : }
468 : :
469 : : static gboolean
470 : 2 : perform_remove_pinned_certificate (GckAttributes *attrs,
471 : : GCancellable *cancellable,
472 : : GError **error)
473 : : {
474 : : GList *objects, *l;
475 : 2 : GError *lerr = NULL;
476 : : GckEnumerator *en;
477 : : GList *slots;
478 : :
479 [ - + ]: 2 : if (!gcr_pkcs11_initialize (cancellable, error))
480 : 0 : return FALSE;
481 : :
482 : 2 : slots = gcr_pkcs11_get_trust_lookup_slots ();
483 : 2 : en = gck_slots_enumerate_objects (slots, attrs, CKF_RW_SESSION);
484 [ + - ]: 2 : g_clear_list (&slots, g_object_unref);
485 : :
486 : : /* We need an error below */
487 [ + - + - ]: 2 : if (error && !*error)
488 : 2 : *error = lerr;
489 : :
490 : 2 : objects = gck_enumerator_next_n (en, -1, cancellable, error);
491 : 2 : g_object_unref (en);
492 : :
493 [ - + ]: 2 : if (*error)
494 : 0 : return FALSE;
495 : :
496 [ + - + + ]: 4 : for (l = objects; l; l = g_list_next (l)) {
497 [ - + ]: 2 : if (!gck_object_destroy (l->data, cancellable, error)) {
498 : :
499 : : /* In case there's a race condition */
500 [ # # ]: 0 : if (g_error_matches (*error, GCK_ERROR, CKR_OBJECT_HANDLE_INVALID)) {
501 : 0 : g_clear_error (error);
502 : 0 : continue;
503 : : }
504 : :
505 [ # # ]: 0 : g_clear_list (&objects, g_object_unref);
506 : 0 : return FALSE;
507 : : }
508 : : }
509 : :
510 [ + - ]: 2 : g_clear_list (&objects, g_object_unref);
511 : 2 : return TRUE;
512 : : }
513 : :
514 : : /**
515 : : * gcr_trust_remove_pinned_certificate:
516 : : * @certificate: a #GcrCertificate
517 : : * @purpose: the purpose string
518 : : * @peer: the peer for this pinned certificate
519 : : * @cancellable: a #GCancellable
520 : : * @error: a #GError, or %NULL
521 : : *
522 : : * Remove a pinned certificate for communication with @peer for @purpose.
523 : : *
524 : : * If the same pinned certificate does not exist, or was already removed,
525 : : * then this operation succeeds without error.
526 : : *
527 : : * This call may block, see gcr_trust_remove_pinned_certificate_async() for the
528 : : * non-blocking version.
529 : : *
530 : : * Returns: %TRUE if the pinned certificate no longer exists
531 : : */
532 : : gboolean
533 : 1 : gcr_trust_remove_pinned_certificate (GcrCertificate *certificate, const gchar *purpose, const gchar *peer,
534 : : GCancellable *cancellable, GError **error)
535 : : {
536 : : GckAttributes *search;
537 : : gboolean ret;
538 : :
539 [ - + + - : 1 : g_return_val_if_fail (GCR_IS_CERTIFICATE (certificate), FALSE);
- + - + ]
540 [ - + ]: 1 : g_return_val_if_fail (purpose, FALSE);
541 [ - + ]: 1 : g_return_val_if_fail (peer, FALSE);
542 : :
543 : 1 : search = prepare_remove_pinned_certificate (certificate, purpose, peer);
544 [ - + ]: 1 : g_return_val_if_fail (search, FALSE);
545 : :
546 : 1 : ret = perform_remove_pinned_certificate (search, cancellable, error);
547 : 1 : gck_attributes_unref (search);
548 : :
549 : 1 : return ret;
550 : : }
551 : :
552 : : static void
553 : 1 : thread_remove_pinned_certificate (GTask *task, gpointer object,
554 : : gpointer task_data, GCancellable *cancellable)
555 : : {
556 : 1 : GckAttributes *attrs = task_data;
557 : 1 : GError *error = NULL;
558 : :
559 : 1 : perform_remove_pinned_certificate (attrs, cancellable, &error);
560 : :
561 [ + - ]: 1 : if (error == NULL)
562 : 1 : g_task_return_boolean (task, TRUE);
563 : : else
564 : 0 : g_task_return_error (task, g_steal_pointer (&error));
565 : 1 : }
566 : :
567 : : /**
568 : : * gcr_trust_remove_pinned_certificate_async:
569 : : * @certificate: a #GcrCertificate
570 : : * @purpose: the purpose string
571 : : * @peer: the peer for this pinned certificate
572 : : * @cancellable: a #GCancellable
573 : : * @callback: a #GAsyncReadyCallback to call when the operation completes
574 : : * @user_data: the data to pass to callback function
575 : : *
576 : : * Remove a pinned certificate for communication with @peer for @purpose.
577 : : *
578 : : * If the same pinned certificate does not exist, or was already removed,
579 : : * then this operation succeeds without error.
580 : : *
581 : : * When the operation is finished, callback will be called. You can then call
582 : : * gcr_trust_remove_pinned_certificate_finish() to get the result of the
583 : : * operation.
584 : : */
585 : : void
586 : 1 : gcr_trust_remove_pinned_certificate_async (GcrCertificate *certificate,
587 : : const gchar *purpose,
588 : : const gchar *peer,
589 : : GCancellable *cancellable,
590 : : GAsyncReadyCallback callback,
591 : : gpointer user_data)
592 : : {
593 : : GTask *task;
594 : : GckAttributes *attrs;
595 : :
596 [ - + + - : 1 : g_return_if_fail (GCR_IS_CERTIFICATE (certificate));
- + - + ]
597 [ - + ]: 1 : g_return_if_fail (purpose);
598 [ - + ]: 1 : g_return_if_fail (peer);
599 : :
600 : 1 : task = g_task_new (NULL, cancellable, callback, user_data);
601 [ + - ]: 1 : g_task_set_source_tag (task, gcr_trust_remove_pinned_certificate_async);
602 : :
603 : 1 : attrs = prepare_remove_pinned_certificate (certificate, purpose, peer);
604 [ - + ]: 1 : g_return_if_fail (attrs);
605 : 1 : g_task_set_task_data (task, attrs, gck_attributes_unref);
606 : :
607 : 1 : g_task_run_in_thread (task, thread_remove_pinned_certificate);
608 : :
609 [ + - ]: 1 : g_clear_object (&task);
610 : : }
611 : :
612 : : /**
613 : : * gcr_trust_remove_pinned_certificate_finish:
614 : : * @result: the #GAsyncResult passed to the callback
615 : : * @error: a #GError, or %NULL
616 : : *
617 : : * Finishes an asynchronous operation started by
618 : : * gcr_trust_remove_pinned_certificate_async().
619 : : *
620 : : * Returns: %TRUE if the pinned certificate no longer exists
621 : : */
622 : : gboolean
623 : 1 : gcr_trust_remove_pinned_certificate_finish (GAsyncResult *result, GError **error)
624 : : {
625 [ + - - + ]: 1 : g_return_val_if_fail (!error || !*error, FALSE);
626 [ - + ]: 1 : g_return_val_if_fail (g_task_is_valid (result, NULL), FALSE);
627 : :
628 : 1 : return g_task_propagate_boolean (G_TASK (result), error);
629 : : }
630 : :
631 : : /* ----------------------------------------------------------------------------------
632 : : * CERTIFICATE ROOT
633 : : */
634 : :
635 : : static GckAttributes *
636 : 8 : prepare_is_certificate_anchored (GcrCertificate *certificate, const gchar *purpose)
637 : : {
638 : 8 : GckBuilder builder = GCK_BUILDER_INIT;
639 : :
640 : 8 : prepare_trust_attrs (certificate, CKT_X_ANCHORED_CERTIFICATE, &builder);
641 : 8 : gck_builder_add_string (&builder, CKA_X_PURPOSE, purpose);
642 : :
643 : 8 : return gck_builder_end (&builder);
644 : : }
645 : :
646 : : static gboolean
647 : 8 : perform_is_certificate_anchored (GckAttributes *attrs,
648 : : GCancellable *cancellable,
649 : : GError **error)
650 : : {
651 : : GckEnumerator *en;
652 : : GList *slots;
653 : : GckObject *object;
654 : :
655 [ - + ]: 8 : if (!gcr_pkcs11_initialize (cancellable, error))
656 : 0 : return FALSE;
657 : :
658 : 8 : slots = gcr_pkcs11_get_trust_lookup_slots ();
659 : 8 : g_debug ("searching for certificate anchor in %d slots",
660 : : g_list_length (slots));
661 : 8 : en = gck_slots_enumerate_objects (slots, attrs, 0);
662 [ + - ]: 8 : g_clear_list (&slots, g_object_unref);
663 : :
664 : 8 : object = gck_enumerator_next (en, cancellable, error);
665 : 8 : g_object_unref (en);
666 : :
667 [ + + ]: 8 : if (object != NULL)
668 : 4 : g_object_unref (object);
669 : :
670 [ + + ]: 8 : g_debug ("%s certificate anchor", object ? "found" : "did not find");
671 : 8 : return (object != NULL);
672 : : }
673 : :
674 : : /**
675 : : * gcr_trust_is_certificate_anchored:
676 : : * @certificate: a #GcrCertificate to check
677 : : * @purpose: the purpose string
678 : : * @cancellable: a #GCancellable
679 : : * @error: a #GError, or %NULL
680 : : *
681 : : * Check if the @certificate is a trust anchor for the given @purpose. A trust
682 : : * anchor is used to verify the signatures on other certificates when verifying
683 : : * a certificate chain. Also known as a trusted certificate authority.
684 : : *
685 : : * This call may block, see [func@Gcr.trust_is_certificate_anchored_async] for
686 : : * the non-blocking version.
687 : : *
688 : : * In the case of an error, %FALSE is also returned. Check @error to detect
689 : : * if an error occurred.
690 : : *
691 : : * Returns: %TRUE if the certificate is a trust anchor
692 : : */
693 : : gboolean
694 : 7 : gcr_trust_is_certificate_anchored (GcrCertificate *certificate, const gchar *purpose,
695 : : GCancellable *cancellable, GError **error)
696 : : {
697 : : GckAttributes *search;
698 : : gboolean ret;
699 : :
700 [ - + + - : 7 : g_return_val_if_fail (GCR_IS_CERTIFICATE (certificate), FALSE);
- + - + ]
701 [ - + ]: 7 : g_return_val_if_fail (purpose, FALSE);
702 : :
703 : 7 : search = prepare_is_certificate_anchored (certificate, purpose);
704 [ - + ]: 7 : g_return_val_if_fail (search, FALSE);
705 : :
706 : 7 : ret = perform_is_certificate_anchored (search, cancellable, error);
707 : 7 : gck_attributes_unref (search);
708 : :
709 : 7 : return ret;
710 : : }
711 : :
712 : : static void
713 : 1 : thread_is_certificate_anchored (GTask *task, gpointer object,
714 : : gpointer task_data, GCancellable *cancellable)
715 : : {
716 : 1 : GckAttributes *attrs = task_data;
717 : 1 : GError *error = NULL;
718 : : gboolean found;
719 : :
720 : 1 : found = perform_is_certificate_anchored (attrs, cancellable, &error);
721 [ + - ]: 1 : if (error == NULL)
722 : 1 : g_task_return_boolean (task, found);
723 : : else
724 : 0 : g_task_return_error (task, g_steal_pointer (&error));
725 : 1 : }
726 : :
727 : : /**
728 : : * gcr_trust_is_certificate_anchored_async:
729 : : * @certificate: a #GcrCertificate to check
730 : : * @purpose: the purpose string
731 : : * @cancellable: a #GCancellable
732 : : * @callback: a #GAsyncReadyCallback to call when the operation completes
733 : : * @user_data: the data to pass to callback function
734 : : *
735 : : * Check if the @certificate is a trust anchor for the given @purpose. A trust
736 : : * anchor is used to verify the signatures on other certificates when verifying
737 : : * a certificate chain. Also known as a trusted certificate authority.
738 : : *
739 : : * When the operation is finished, callback will be called. You can then call
740 : : * gcr_trust_is_certificate_anchored_finish() to get the result of the operation.
741 : : */
742 : : void
743 : 1 : gcr_trust_is_certificate_anchored_async (GcrCertificate *certificate, const gchar *purpose,
744 : : GCancellable *cancellable, GAsyncReadyCallback callback,
745 : : gpointer user_data)
746 : : {
747 : : GTask *task;
748 : : GckAttributes *attrs;
749 : :
750 [ - + + - : 1 : g_return_if_fail (GCR_IS_CERTIFICATE (certificate));
- + - + ]
751 [ - + ]: 1 : g_return_if_fail (purpose);
752 : :
753 : 1 : task = g_task_new (NULL, cancellable, callback, user_data);
754 [ + - ]: 1 : g_task_set_source_tag (task, gcr_trust_is_certificate_anchored_async);
755 : :
756 : 1 : attrs = prepare_is_certificate_anchored (certificate, purpose);
757 [ - + ]: 1 : g_return_if_fail (attrs);
758 : 1 : g_task_set_task_data (task, attrs, gck_attributes_unref);
759 : :
760 : 1 : g_task_run_in_thread (task, thread_is_certificate_anchored);
761 : :
762 [ + - ]: 1 : g_clear_object (&task);
763 : : }
764 : :
765 : : /**
766 : : * gcr_trust_is_certificate_anchored_finish:
767 : : * @result: the #GAsyncResult passed to the callback
768 : : * @error: a #GError, or %NULL
769 : : *
770 : : * Finishes an asynchronous operation started by
771 : : * gcr_trust_is_certificate_anchored_async().
772 : : *
773 : : * In the case of an error, %FALSE is also returned. Check @error to detect
774 : : * if an error occurred.
775 : : *
776 : : * Returns: %TRUE if the certificate is a trust anchor
777 : : */
778 : : gboolean
779 : 1 : gcr_trust_is_certificate_anchored_finish (GAsyncResult *result, GError **error)
780 : : {
781 [ + - - + ]: 1 : g_return_val_if_fail (!error || !*error, FALSE);
782 [ - + ]: 1 : g_return_val_if_fail (g_task_is_valid (result, NULL), FALSE);
783 : :
784 : 1 : return g_task_propagate_boolean (G_TASK (result), error);
785 : : }
786 : :
787 : : /* ----------------------------------------------------------------------------------
788 : : * DISTRUSTED CERTIFICATE
789 : : */
790 : :
791 : : static GckAttributes *
792 : 3 : prepare_is_certificate_distrusted (unsigned char *serial_nr,
793 : : size_t serial_nr_len,
794 : : unsigned char *issuer,
795 : : size_t issuer_len)
796 : : {
797 : 3 : GckBuilder builder = GCK_BUILDER_INIT;
798 : :
799 : 3 : gck_builder_add_ulong (&builder, CKA_CLASS, CKO_X_TRUST_ASSERTION);
800 : 3 : gck_builder_add_ulong (&builder, CKA_X_ASSERTION_TYPE, CKT_X_DISTRUSTED_CERTIFICATE);
801 : 3 : gck_builder_add_data (&builder, CKA_SERIAL_NUMBER, serial_nr, serial_nr_len);
802 : 3 : gck_builder_add_data (&builder, CKA_ISSUER, issuer, issuer_len);
803 : :
804 : 3 : return gck_builder_end (&builder);
805 : : }
806 : :
807 : : static gboolean
808 : 3 : perform_is_certificate_distrusted (GckAttributes *attrs,
809 : : GCancellable *cancellable,
810 : : GError **error)
811 : : {
812 : : GckEnumerator *en;
813 : : GList *slots;
814 : : GckObject *object;
815 : :
816 [ - + ]: 3 : if (!gcr_pkcs11_initialize (cancellable, error))
817 : 0 : return FALSE;
818 : :
819 : 3 : slots = gcr_pkcs11_get_trust_lookup_slots ();
820 : 3 : g_debug ("searching for certificate distrust assertion in %d slots",
821 : : g_list_length (slots));
822 : 3 : en = gck_slots_enumerate_objects (slots, attrs, 0);
823 [ + - ]: 3 : g_clear_list (&slots, g_object_unref);
824 : :
825 : 3 : object = gck_enumerator_next (en, cancellable, error);
826 : 3 : g_object_unref (en);
827 : :
828 [ + + ]: 3 : if (object != NULL)
829 : 1 : g_object_unref (object);
830 : :
831 [ + + ]: 3 : g_debug ("%s certificate distrust", object ? "found" : "did not find");
832 : 3 : return (object != NULL);
833 : : }
834 : :
835 : : /**
836 : : * gcr_trust_is_certificate_distrusted:
837 : : * @serial_nr: (array length=serial_nr_len): The serial number of the certificate
838 : : * @serial_nr_len: The nr of bytes in @serial_nr
839 : : * @issuer: (array length=issuer_len): The raw issuer
840 : : * @issuer_len: The nr of bytes in @issuer
841 : : * @cancellable: (nullable): a #GCancellable or %NULL
842 : : * @error: a #GError, or %NULL
843 : : *
844 : : * Checks whether the certificate that can be uniquely identified with the
845 : : * given @serial_nr and @issuer is marked as distrusted (for example by the
846 : : * user, or because it's part of a CRL).
847 : : *
848 : : * Since we can't directly use [iface@Certificate] to fetch these values, you
849 : : * need to call these with the raw serial number and issuer as provided by the
850 : : * PKCS#11 fields `CKA_SERIAL_NR` and `CKA_ISSUER`.
851 : : *
852 : : * Returns: %TRUE if the certificate is marked as distrusted
853 : : */
854 : : gboolean
855 : 2 : gcr_trust_is_certificate_distrusted (unsigned char *serial_nr,
856 : : size_t serial_nr_len,
857 : : unsigned char *issuer,
858 : : size_t issuer_len,
859 : : GCancellable *cancellable,
860 : : GError **error)
861 : : {
862 : : GckAttributes *search;
863 : : gboolean ret;
864 : :
865 [ - + ]: 2 : g_return_val_if_fail (serial_nr, FALSE);
866 [ - + ]: 2 : g_return_val_if_fail (serial_nr_len > 0, FALSE);
867 [ - + ]: 2 : g_return_val_if_fail (issuer, FALSE);
868 [ - + ]: 2 : g_return_val_if_fail (issuer_len > 0, FALSE);
869 [ + - - - : 2 : g_return_val_if_fail (G_IS_CANCELLABLE (cancellable) || !cancellable, FALSE);
- - + - -
+ ]
870 [ + - - + ]: 2 : g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
871 : :
872 : 2 : search = prepare_is_certificate_distrusted (serial_nr, serial_nr_len, issuer, issuer_len);
873 [ - + ]: 2 : g_return_val_if_fail (search, FALSE);
874 : :
875 : 2 : ret = perform_is_certificate_distrusted (search, cancellable, error);
876 : 2 : gck_attributes_unref (search);
877 : :
878 : 2 : return ret;
879 : : }
880 : :
881 : : static void
882 : 1 : thread_is_certificate_distrusted (GTask *task,
883 : : void *object,
884 : : void *task_data,
885 : : GCancellable *cancellable)
886 : : {
887 : 1 : GckAttributes *attrs = task_data;
888 : 1 : GError *error = NULL;
889 : : gboolean found;
890 : :
891 : 1 : found = perform_is_certificate_distrusted (attrs, cancellable, &error);
892 [ + - ]: 1 : if (error == NULL)
893 : 1 : g_task_return_boolean (task, found);
894 : : else
895 : 0 : g_task_return_error (task, g_steal_pointer (&error));
896 : 1 : }
897 : :
898 : : /**
899 : : * gcr_trust_is_certificate_distrusted_async:
900 : : * @serial_nr: (array length=serial_nr_len): The serial number of the certificate
901 : : * @serial_nr_len: The nr of bytes in @serial_nr
902 : : * @issuer: (array length=issuer_len): The raw issuer
903 : : * @issuer_len: The number of bytes in @issuer
904 : : * @cancellable: (nullable): a #GCancellable or %NULL
905 : : * @callback: a #GAsyncReadyCallback to call when the operation completes
906 : : * @user_data: the data to pass to callback function
907 : : *
908 : : * Asynchronously checks whether the certificate that can be uniquely
909 : : * identified with the given @serial_nr and @issuer is marked as distrusted
910 : : * (for example by the user, or because it's part of a CRL).
911 : : *
912 : : * Since we can't directly use [iface@Certificate] to fetch these values, you
913 : : * need to call these with the raw serial number and issuer as provided by the
914 : : * PKCS#11 fields `CKA_SERIAL_NR` and `CKA_ISSUER`.
915 : : *
916 : : * When the operation is finished, @callback will be called. You can then call
917 : : * [func@trust_is_certificate_distrusted_finish] to get the result of the
918 : : * operation.
919 : : */
920 : : void
921 : 1 : gcr_trust_is_certificate_distrusted_async (unsigned char *serial_nr,
922 : : size_t serial_nr_len,
923 : : unsigned char *issuer,
924 : : size_t issuer_len,
925 : : GCancellable *cancellable,
926 : : GAsyncReadyCallback callback,
927 : : void *user_data)
928 : : {
929 : : GTask *task;
930 : : GckAttributes *attrs;
931 : :
932 [ - + ]: 1 : g_return_if_fail (serial_nr);
933 [ - + ]: 1 : g_return_if_fail (serial_nr_len > 0);
934 [ - + ]: 1 : g_return_if_fail (issuer);
935 [ - + ]: 1 : g_return_if_fail (issuer_len > 0);
936 [ + - - - : 1 : g_return_if_fail (G_IS_CANCELLABLE (cancellable) || !cancellable);
- - + - -
+ ]
937 : :
938 : 1 : task = g_task_new (NULL, cancellable, callback, user_data);
939 [ + - ]: 1 : g_task_set_source_tag (task, gcr_trust_is_certificate_distrusted_async);
940 : :
941 : 1 : attrs = prepare_is_certificate_distrusted (serial_nr, serial_nr_len, issuer, issuer_len);
942 [ - + ]: 1 : g_return_if_fail (attrs);
943 : 1 : g_task_set_task_data (task, attrs, gck_attributes_unref);
944 : :
945 : 1 : g_task_run_in_thread (task, thread_is_certificate_distrusted);
946 : :
947 [ + - ]: 1 : g_clear_object (&task);
948 : : }
949 : :
950 : : /**
951 : : * gcr_trust_is_certificate_distrusted_finish:
952 : : * @result: the #GAsyncResult passed to the callback
953 : : * @error: a #GError, or %NULL
954 : : *
955 : : * Finishes an asynchronous operation started by
956 : : * [func@trust_is_certificate_distrusted_async].
957 : : *
958 : : * In the case of an error, %FALSE is also returned. Check @error to detect
959 : : * if an error occurred.
960 : : *
961 : : * Returns: %TRUE if the certificate is a trust anchor
962 : : */
963 : : gboolean
964 : 1 : gcr_trust_is_certificate_distrusted_finish (GAsyncResult *result,
965 : : GError **error)
966 : : {
967 [ + - - + ]: 1 : g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
968 [ - + ]: 1 : g_return_val_if_fail (g_task_is_valid (result, NULL), FALSE);
969 : :
970 : 1 : return g_task_propagate_boolean (G_TASK (result), error);
971 : : }
|