Line data Source code
1 : /*
2 : * gnome-keyring
3 : *
4 : * Copyright (C) 2010 Stefan Walter
5 : *
6 : * This program is free software; you can redistribute it and/or modify
7 : * it under the terms of the GNU Lesser General Public License as
8 : * published by the Free Software Foundation; either version 2.1 of
9 : * the License, or (at your option) any later version.
10 : *
11 : * This program is distributed in the hope that it will be useful, but
12 : * WITHOUT ANY WARRANTY; without even the implied warranty of
13 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 : * Lesser General Public License for more details.
15 : *
16 : * You should have received a copy of the GNU Lesser General Public
17 : * License along with this program; if not, see
18 : * <http://www.gnu.org/licenses/>.
19 : */
20 :
21 : #include "config.h"
22 :
23 : #include "gkm-xdg-assertion.h"
24 : #include "gkm-xdg-trust.h"
25 :
26 : #include "egg/egg-asn1x.h"
27 : #include "egg/egg-asn1-defs.h"
28 :
29 : #include "gkm/gkm-assertion.h"
30 : #include "gkm/gkm-attributes.h"
31 : #define DEBUG_FLAG GKM_DEBUG_OBJECT
32 : #include "gkm/gkm-debug.h"
33 : #include "gkm/gkm-object.h"
34 : #include "gkm/gkm-oids.h"
35 : #include "gkm/gkm-serializable.h"
36 : #include "gkm/gkm-session.h"
37 : #include "gkm/gkm-transaction.h"
38 : #include "gkm/gkm-util.h"
39 :
40 : #include "pkcs11/pkcs11i.h"
41 : #include "pkcs11/pkcs11n.h"
42 : #include "pkcs11/pkcs11x.h"
43 :
44 : #include <glib/gi18n.h>
45 :
46 : extern const struct _EggAsn1xDef xdg_asn1_tab[];
47 :
48 : struct _GkmXdgTrustPrivate {
49 : GHashTable *assertions;
50 : GNode *asn;
51 : GBytes *bytes;
52 : };
53 :
54 : static void gkm_xdg_trust_serializable (GkmSerializableIface *iface);
55 :
56 694 : G_DEFINE_TYPE_EXTENDED (GkmXdgTrust, gkm_xdg_trust, GKM_TYPE_TRUST, 0,
57 : G_IMPLEMENT_INTERFACE (GKM_TYPE_SERIALIZABLE, gkm_xdg_trust_serializable)
58 : G_ADD_PRIVATE (GkmXdgTrust));
59 :
60 : static GQuark QDATA_ASSERTION_KEY = 0;
61 :
62 : /* Forward declarations */
63 : static void add_assertion_to_trust (GkmXdgTrust *self, GkmAssertion *assertion,
64 : GkmTransaction *transaction);
65 :
66 : static void remove_assertion_from_trust (GkmXdgTrust *self, GkmAssertion *assertion,
67 : GkmTransaction *transaction);
68 :
69 : /* -----------------------------------------------------------------------------
70 : * QUARKS
71 : */
72 :
73 : static GQuark TRUST_UNKNOWN;
74 : static GQuark TRUST_DISTRUSTED;
75 : static GQuark TRUST_TRUSTED;
76 : static GQuark TRUST_TRUSTED_ANCHOR;
77 :
78 : static void
79 2 : init_quarks (void)
80 : {
81 : static gsize quarks_inited = 0;
82 :
83 2 : if (g_once_init_enter (&quarks_inited)) {
84 :
85 : #define QUARK(name, value) \
86 : name = g_quark_from_static_string(value)
87 :
88 2 : QUARK (TRUST_UNKNOWN, "trustUnknown");
89 2 : QUARK (TRUST_DISTRUSTED, "distrusted");
90 2 : QUARK (TRUST_TRUSTED, "trusted");
91 2 : QUARK (TRUST_TRUSTED_ANCHOR, "trustedAnchor");
92 :
93 : #undef QUARK
94 :
95 2 : g_once_init_leave (&quarks_inited, 1);
96 : }
97 2 : }
98 :
99 : /* -----------------------------------------------------------------------------
100 : * INTERNAL
101 : */
102 :
103 : static CK_RV
104 21 : trust_get_der (GkmXdgTrust *self, const gchar *part, CK_ATTRIBUTE_PTR attr)
105 : {
106 : GNode *node;
107 : GBytes *element;
108 : CK_RV rv;
109 :
110 21 : g_assert (GKM_XDG_IS_TRUST (self));
111 :
112 21 : node = egg_asn1x_node (self->pv->asn, "reference", "certReference", part, NULL);
113 21 : g_return_val_if_fail (node, CKR_GENERAL_ERROR);
114 :
115 : /* If the assertion doesn't contain this info ... */
116 21 : if (!egg_asn1x_have (node)) {
117 10 : gkm_debug ("CKR_ATTRIBUTE_TYPE_INVALID: %s wants %s which is not part of assertion",
118 : gkm_log_attr_type (attr->type), part);
119 10 : return CKR_ATTRIBUTE_TYPE_INVALID;
120 : }
121 :
122 11 : element = egg_asn1x_get_element_raw (node);
123 11 : rv = gkm_attribute_set_bytes (attr, element);
124 11 : g_bytes_unref (element);
125 :
126 11 : return rv;
127 : }
128 :
129 : static CK_RV
130 20 : trust_get_integer (GkmXdgTrust *self, const gchar *part, CK_ATTRIBUTE_PTR attr)
131 : {
132 : GNode *node;
133 : GBytes *integer;
134 : CK_RV rv;
135 :
136 20 : g_assert (GKM_XDG_IS_TRUST (self));
137 :
138 20 : node = egg_asn1x_node (self->pv->asn, "reference", "certReference", part, NULL);
139 20 : g_return_val_if_fail (node, CKR_GENERAL_ERROR);
140 :
141 : /* If the assertion doesn't contain this info ... */
142 20 : if (!egg_asn1x_have (node)) {
143 9 : gkm_debug ("CKR_ATTRIBUTE_TYPE_INVALID: %s wants %s which is not part of assertion",
144 : gkm_log_attr_type (attr->type), part);
145 9 : return CKR_ATTRIBUTE_TYPE_INVALID;
146 : }
147 :
148 11 : integer = egg_asn1x_get_integer_as_raw (node);
149 11 : g_return_val_if_fail (integer, CKR_GENERAL_ERROR);
150 :
151 11 : rv = gkm_attribute_set_bytes (attr, integer);
152 11 : g_bytes_unref (integer);
153 :
154 11 : return rv;
155 : }
156 :
157 : static CK_RV
158 20 : trust_get_hash (GkmXdgTrust *self, GChecksumType ctype, CK_ATTRIBUTE_PTR attr)
159 : {
160 : GNode *cert;
161 : GBytes *element;
162 : CK_RV rv;
163 :
164 20 : cert = egg_asn1x_node (self->pv->asn, "reference", "certComplete", NULL);
165 20 : g_return_val_if_fail (cert, CKR_GENERAL_ERROR);
166 :
167 : /* If it's not stored, then this attribute is not present */
168 20 : if (!egg_asn1x_have (cert)) {
169 2 : gkm_debug ("CKR_ATTRIBUTE_TYPE_INVALID: %s wants certComplete which is not part of assertion",
170 : gkm_log_attr_type (attr->type));
171 2 : return CKR_ATTRIBUTE_TYPE_INVALID;
172 : }
173 :
174 18 : element = egg_asn1x_get_element_raw (cert);
175 18 : g_return_val_if_fail (element != NULL, CKR_GENERAL_ERROR);
176 :
177 18 : rv = gkm_attribute_set_checksum (attr, ctype,
178 : g_bytes_get_data (element, NULL),
179 : g_bytes_get_size (element));
180 :
181 18 : g_bytes_unref (element);
182 18 : return rv;
183 : }
184 :
185 : static CK_RV
186 29 : trust_get_complete (GkmXdgTrust *self, CK_ATTRIBUTE_PTR attr)
187 : {
188 : GNode *cert;
189 : GBytes *element;
190 : CK_RV rv;
191 :
192 29 : cert = egg_asn1x_node (self->pv->asn, "reference", "certComplete", NULL);
193 29 : g_return_val_if_fail (cert, CKR_GENERAL_ERROR);
194 :
195 : /* If it's not stored, then this attribute is not present */
196 29 : if (!egg_asn1x_have (cert)) {
197 7 : gkm_debug ("CKR_ATTRIBUTE_TYPE_INVALID: %s wants certComplete which is not part of assertion",
198 : gkm_log_attr_type (attr->type));
199 7 : return CKR_ATTRIBUTE_TYPE_INVALID;
200 : }
201 :
202 22 : element = egg_asn1x_get_element_raw (cert);
203 22 : g_return_val_if_fail (element != NULL, CKR_GENERAL_ERROR);
204 :
205 22 : rv = gkm_attribute_set_bytes (attr, element);
206 22 : g_bytes_unref (element);
207 :
208 22 : return rv;
209 : }
210 :
211 :
212 : static gboolean
213 26 : validate_der (CK_ATTRIBUTE_PTR attr, const gchar *asn_type)
214 : {
215 : GNode *asn;
216 26 : gboolean valid = TRUE;
217 : GBytes *data;
218 :
219 26 : if (!attr->pValue || attr->ulValueLen == (CK_ULONG)-1)
220 1 : return FALSE;
221 :
222 25 : asn = egg_asn1x_create (pkix_asn1_tab, asn_type);
223 25 : g_return_val_if_fail (asn, FALSE);
224 :
225 25 : data = g_bytes_new_static (attr->pValue, attr->ulValueLen);
226 25 : valid = egg_asn1x_decode (asn, data);
227 25 : g_bytes_unref (data);
228 :
229 25 : if (!valid)
230 1 : g_message ("failed to parse certificate passed to trust assertion: %s",
231 : egg_asn1x_message (asn));
232 :
233 : /* Yes, this is an expensive check, but worthwhile */
234 25 : egg_asn1x_destroy (asn);
235 25 : return valid;
236 : }
237 :
238 : static gboolean
239 11 : validate_integer (CK_ATTRIBUTE_PTR attr)
240 : {
241 22 : return attr->pValue != NULL &&
242 22 : attr->ulValueLen > 0 &&
243 11 : attr->ulValueLen != (CK_ULONG)-1;
244 : }
245 :
246 : static GQuark
247 2 : assertion_type_to_level_enum (CK_X_ASSERTION_TYPE type)
248 : {
249 2 : switch (type) {
250 0 : case CKT_X_DISTRUSTED_CERTIFICATE:
251 0 : return TRUST_DISTRUSTED;
252 0 : case CKT_X_ANCHORED_CERTIFICATE:
253 0 : return TRUST_TRUSTED_ANCHOR;
254 2 : case CKT_X_PINNED_CERTIFICATE:
255 2 : return TRUST_TRUSTED;
256 0 : default:
257 0 : return 0;
258 : };
259 : }
260 :
261 : static gboolean
262 13 : level_enum_to_assertion_type (GQuark level, CK_X_ASSERTION_TYPE *type)
263 : {
264 13 : if (level == TRUST_DISTRUSTED)
265 0 : *type = CKT_X_DISTRUSTED_CERTIFICATE;
266 13 : else if (level == TRUST_TRUSTED_ANCHOR)
267 0 : *type = CKT_X_ANCHORED_CERTIFICATE;
268 13 : else if (level == TRUST_TRUSTED)
269 13 : *type = CKT_X_PINNED_CERTIFICATE;
270 0 : else if (level == TRUST_UNKNOWN)
271 0 : *type = 0;
272 : else
273 0 : return FALSE;
274 13 : return TRUE;
275 : }
276 :
277 : static void
278 36 : check_and_unref_assertion (gpointer data)
279 : {
280 36 : g_assert (GKM_IS_ASSERTION (data));
281 36 : g_assert (g_object_get_qdata (data, QDATA_ASSERTION_KEY) != NULL);
282 36 : g_object_run_dispose (data);
283 36 : g_object_unref (data);
284 36 : }
285 :
286 : static GHashTable*
287 61 : create_assertions (void)
288 : {
289 61 : return g_hash_table_new_full (g_bytes_hash, g_bytes_equal,
290 : (GDestroyNotify)g_bytes_unref,
291 : check_and_unref_assertion);
292 : }
293 :
294 : static GkmAssertion*
295 13 : create_assertion (GkmXdgTrust *self, GNode *asn)
296 : {
297 13 : CK_X_ASSERTION_TYPE type = 0;
298 : GkmAssertion *assertion;
299 : GQuark level;
300 : gchar *purpose;
301 : gchar *peer;
302 : GNode *node;
303 :
304 : /* Get the trust level */
305 13 : level = egg_asn1x_get_enumerated (egg_asn1x_node (asn, "level", NULL));
306 13 : g_return_val_if_fail (level != 0, NULL);
307 13 : if (!level_enum_to_assertion_type (level, &type))
308 0 : g_message ("unsupported trust level %s in trust object", g_quark_to_string (level));
309 13 : else if (type == 0)
310 0 : return NULL;
311 :
312 : /* A purpose */
313 13 : purpose = egg_asn1x_get_string_as_utf8 (egg_asn1x_node (asn, "purpose", NULL), NULL);
314 13 : g_return_val_if_fail (purpose, NULL);
315 :
316 : /* A peer name */
317 13 : node = egg_asn1x_node (asn, "peer", NULL);
318 13 : if (egg_asn1x_have (node))
319 0 : peer = egg_asn1x_get_string_as_utf8 (node, NULL);
320 : else
321 13 : peer = NULL;
322 :
323 26 : assertion = g_object_new (GKM_XDG_TYPE_ASSERTION,
324 13 : "module", gkm_object_get_module (GKM_OBJECT (self)),
325 13 : "manager", gkm_object_get_manager (GKM_OBJECT (self)),
326 : "trust", self,
327 : "type", type,
328 : "purpose", purpose,
329 : "peer", peer,
330 : NULL);
331 :
332 13 : g_free (purpose);
333 13 : g_free (peer);
334 :
335 13 : return assertion;
336 : }
337 :
338 : static GBytes *
339 71 : create_assertion_key (const gchar *purpose,
340 : const gchar *peer)
341 : {
342 : GString *string;
343 : gsize len;
344 :
345 71 : g_return_val_if_fail (purpose, NULL);
346 :
347 71 : string = g_string_sized_new (32);
348 : g_string_append (string, purpose);
349 :
350 71 : if (peer != NULL) {
351 : g_string_append_len (string, "\0", 1);
352 : g_string_append (string, peer);
353 : }
354 :
355 71 : len = string->len;
356 71 : return g_bytes_new_take (g_string_free (string, FALSE), len);
357 : }
358 :
359 : static GBytes *
360 93 : lookup_assertion_key (GkmAssertion *assertion)
361 : {
362 93 : return g_object_get_qdata (G_OBJECT (assertion), QDATA_ASSERTION_KEY);
363 : }
364 :
365 : static GBytes *
366 81 : lookup_or_create_assertion_key (GkmAssertion *assertion)
367 : {
368 : GBytes *key;
369 :
370 81 : key = lookup_assertion_key (assertion);
371 81 : if (key == NULL) {
372 47 : key = create_assertion_key (gkm_assertion_get_purpose (assertion),
373 : gkm_assertion_get_peer (assertion));
374 47 : g_object_set_qdata_full (G_OBJECT (assertion), QDATA_ASSERTION_KEY,
375 : key, (GDestroyNotify)g_bytes_unref);
376 : }
377 :
378 81 : return key;
379 : }
380 :
381 : static gboolean
382 34 : complete_add_assertion (GkmTransaction *transaction, GObject *object, gpointer user_data)
383 : {
384 34 : GkmAssertion *assertion = GKM_ASSERTION (user_data);
385 34 : GkmXdgTrust *self = GKM_XDG_TRUST (object);
386 :
387 34 : if (gkm_transaction_get_failed (transaction))
388 0 : remove_assertion_from_trust (self, assertion, NULL);
389 :
390 34 : g_object_unref (assertion);
391 34 : return TRUE;
392 : }
393 :
394 : static void
395 47 : add_assertion_to_trust (GkmXdgTrust *self, GkmAssertion *assertion,
396 : GkmTransaction *transaction)
397 : {
398 : GBytes *key;
399 :
400 47 : key = lookup_or_create_assertion_key (assertion);
401 47 : g_assert (key != NULL);
402 :
403 47 : g_hash_table_insert (self->pv->assertions, g_bytes_ref (key), g_object_ref (assertion));
404 47 : gkm_object_expose (GKM_OBJECT (assertion), gkm_object_is_exposed (GKM_OBJECT (self)));
405 :
406 47 : if (transaction != NULL)
407 34 : gkm_transaction_add (transaction, self, complete_add_assertion, g_object_ref (assertion));
408 47 : }
409 :
410 : static gboolean
411 11 : complete_remove_assertion (GkmTransaction *transaction, GObject *object, gpointer user_data)
412 : {
413 11 : GkmXdgTrust *self = GKM_XDG_TRUST (object);
414 11 : GkmAssertion *assertion = GKM_ASSERTION (user_data);
415 :
416 11 : if (gkm_transaction_get_failed (transaction))
417 0 : add_assertion_to_trust (self, assertion, NULL);
418 : else
419 11 : g_object_run_dispose (G_OBJECT (assertion));
420 :
421 11 : g_object_unref (assertion);
422 11 : return TRUE;
423 : }
424 :
425 : static void
426 11 : remove_assertion_from_trust (GkmXdgTrust *self, GkmAssertion *assertion,
427 : GkmTransaction *transaction)
428 : {
429 : GBytes *key;
430 :
431 11 : key = lookup_assertion_key (assertion);
432 11 : g_assert (key != NULL);
433 :
434 11 : gkm_object_expose (GKM_OBJECT (assertion), FALSE);
435 :
436 11 : if (transaction == NULL) {
437 0 : if (!g_hash_table_remove (self->pv->assertions, key))
438 0 : g_return_if_reached ();
439 : } else {
440 11 : if (!g_hash_table_steal (self->pv->assertions, key))
441 0 : g_return_if_reached ();
442 11 : gkm_transaction_add (transaction, self, complete_remove_assertion, assertion);
443 11 : g_bytes_unref (key);
444 : }
445 : }
446 :
447 : static gboolean
448 13 : load_assertions (GkmXdgTrust *self, GNode *asn)
449 : {
450 : GHashTable *assertions;
451 : GkmAssertion *assertion;
452 : GBytes *key;
453 : GNode *node;
454 : guint count, i;
455 :
456 13 : g_assert (self);
457 13 : g_assert (asn);
458 :
459 13 : assertions = self->pv->assertions;
460 13 : self->pv->assertions = create_assertions ();
461 :
462 13 : count = egg_asn1x_count (egg_asn1x_node (asn, "assertions", NULL));
463 :
464 26 : for (i = 0; i < count; ++i) {
465 13 : node = egg_asn1x_node (asn, "assertions", i + 1, NULL);
466 13 : g_return_val_if_fail (node != NULL, FALSE);
467 :
468 : /* We use the raw DER encoding as an assertion */
469 13 : key = egg_asn1x_get_element_raw (node);
470 13 : g_return_val_if_fail (key != NULL, FALSE);
471 :
472 : /* Already have this assertion? */
473 13 : assertion = g_hash_table_lookup (assertions, key);
474 13 : if (assertion) {
475 0 : if (!g_hash_table_steal (assertions, key))
476 0 : g_assert_not_reached ();
477 :
478 : /* Create a new assertion */
479 : } else {
480 13 : assertion = create_assertion (self, node);
481 : }
482 :
483 13 : add_assertion_to_trust (self, assertion, NULL);
484 13 : g_bytes_unref (key);
485 13 : g_object_unref (assertion);
486 : }
487 :
488 : /* Override the stored assertions and netscape trust */
489 13 : g_hash_table_remove_all (assertions);
490 13 : g_hash_table_unref (assertions);
491 :
492 13 : return TRUE;
493 : }
494 :
495 : static gboolean
496 2 : save_assertion (GNode *asn, GkmAssertion *assertion)
497 : {
498 : const gchar *purpose;
499 : const gchar *peer;
500 : GQuark level;
501 :
502 2 : level = assertion_type_to_level_enum (gkm_assertion_get_trust_type (assertion));
503 2 : purpose = gkm_assertion_get_purpose (assertion);
504 2 : peer = gkm_assertion_get_peer (assertion);
505 :
506 2 : if (!egg_asn1x_set_string_as_utf8 (egg_asn1x_node (asn, "purpose", NULL),
507 2 : g_strdup (purpose), g_free))
508 0 : g_return_val_if_reached (FALSE);
509 2 : egg_asn1x_set_enumerated (egg_asn1x_node (asn, "level", NULL), level);
510 :
511 2 : if (peer && !egg_asn1x_set_string_as_utf8 (egg_asn1x_node (asn, "peer", NULL),
512 0 : g_strdup (peer), g_free))
513 0 : g_return_val_if_reached (FALSE);
514 :
515 2 : return TRUE;
516 : }
517 :
518 : static gboolean
519 3 : save_assertions (GkmXdgTrust *self, GNode *asn)
520 : {
521 : GHashTableIter iter;
522 : GNode *pair, *node;
523 : gpointer value;
524 :
525 3 : g_assert (GKM_XDG_IS_TRUST (self));
526 3 : g_assert (asn);
527 :
528 3 : node = egg_asn1x_node (asn, "assertions", NULL);
529 3 : egg_asn1x_clear (node);
530 :
531 3 : g_hash_table_iter_init (&iter, self->pv->assertions);
532 5 : while (g_hash_table_iter_next (&iter, NULL, &value)) {
533 2 : pair = egg_asn1x_append (node);
534 2 : g_return_val_if_fail (pair, FALSE);
535 2 : save_assertion (pair, GKM_ASSERTION (value));
536 : }
537 :
538 3 : return TRUE;
539 : }
540 :
541 : static GkmXdgTrust*
542 11 : create_trust_for_reference (GkmModule *module, GkmManager *manager,
543 : CK_ATTRIBUTE_PTR serial, CK_ATTRIBUTE_PTR issuer)
544 : {
545 : GkmXdgTrust *trust;
546 : GNode *asn, *ref, *node;
547 : GBytes *bytes;
548 :
549 11 : asn = egg_asn1x_create (xdg_asn1_tab, "trust-1");
550 11 : g_return_val_if_fail (asn, NULL);
551 :
552 11 : ref = egg_asn1x_node (asn, "reference", NULL);
553 11 : node = egg_asn1x_node (ref, "certReference", NULL);
554 :
555 11 : egg_asn1x_set_choice (ref, node);
556 11 : bytes = g_bytes_new (serial->pValue, serial->ulValueLen);
557 11 : egg_asn1x_set_integer_as_raw (egg_asn1x_node (node, "serialNumber", NULL), bytes);
558 11 : g_bytes_unref (bytes);
559 :
560 11 : bytes = g_bytes_new (issuer->pValue, issuer->ulValueLen);
561 11 : egg_asn1x_set_any_raw (egg_asn1x_node (node, "issuer", NULL), bytes);
562 11 : g_bytes_unref (bytes);
563 :
564 11 : trust = g_object_new (GKM_XDG_TYPE_TRUST, "module", module, "manager", manager, NULL);
565 11 : trust->pv->asn = asn;
566 :
567 : /* Encode it, so we have read access to all the data */
568 11 : trust->pv->bytes = egg_asn1x_encode (asn, NULL);
569 11 : if (!trust->pv->bytes) {
570 0 : g_warning ("created invalid trust object: %s", egg_asn1x_message (asn));
571 0 : return NULL;
572 : }
573 :
574 11 : return trust;
575 : }
576 :
577 : static GkmXdgTrust*
578 13 : create_trust_for_complete (GkmModule *module, GkmManager *manager,
579 : CK_ATTRIBUTE_PTR cert)
580 : {
581 : GkmXdgTrust *trust;
582 : GNode *asn, *ref, *node;
583 : GBytes *bytes;
584 :
585 13 : asn = egg_asn1x_create (xdg_asn1_tab, "trust-1");
586 13 : g_return_val_if_fail (asn, NULL);
587 :
588 13 : ref = egg_asn1x_node (asn, "reference", NULL);
589 13 : node = egg_asn1x_node (ref, "certComplete", NULL);
590 :
591 13 : egg_asn1x_set_choice (ref, node);
592 13 : bytes = g_bytes_new (cert->pValue, cert->ulValueLen);
593 13 : egg_asn1x_set_any_raw (node, bytes);
594 13 : g_bytes_unref (bytes);
595 :
596 13 : trust = g_object_new (GKM_XDG_TYPE_TRUST, "module", module, "manager", manager, NULL);
597 13 : trust->pv->asn = asn;
598 :
599 : /* Encode it, which validates, and so we have read access to all the data */
600 13 : trust->pv->bytes = egg_asn1x_encode (asn, NULL);
601 13 : if (!trust->pv->bytes) {
602 0 : g_warning ("created invalid trust object: %s", egg_asn1x_message (asn));
603 0 : return NULL;
604 : }
605 :
606 13 : return trust;
607 : }
608 :
609 : /* -----------------------------------------------------------------------------
610 : * OBJECT
611 : */
612 :
613 : static CK_RV
614 282 : gkm_xdg_trust_get_attribute (GkmObject *base, GkmSession *session, CK_ATTRIBUTE_PTR attr)
615 : {
616 282 : GkmXdgTrust *self = GKM_XDG_TRUST (base);
617 :
618 282 : switch (attr->type)
619 : {
620 0 : case CKA_PRIVATE:
621 0 : return gkm_attribute_set_bool (attr, CK_FALSE);
622 0 : case CKA_TRUST_STEP_UP_APPROVED:
623 0 : return gkm_attribute_set_bool (attr, CK_FALSE);
624 96 : case CKA_CLASS:
625 96 : return gkm_attribute_set_ulong (attr, CKO_NETSCAPE_TRUST);
626 0 : case CKA_MODIFIABLE:
627 0 : return gkm_attribute_set_bool (attr, CK_FALSE);
628 :
629 : /* Certificate reference values */
630 1 : case CKA_SUBJECT:
631 1 : return trust_get_der (self, "subject", attr);
632 20 : case CKA_SERIAL_NUMBER:
633 20 : return trust_get_integer (self, "serialNumber", attr);
634 20 : case CKA_ISSUER:
635 20 : return trust_get_der (self, "issuer", attr);
636 29 : case CKA_X_CERTIFICATE_VALUE:
637 29 : return trust_get_complete (self, attr);
638 :
639 : /* Certificate hash values */
640 2 : case CKA_CERT_MD5_HASH:
641 2 : return trust_get_hash (self, G_CHECKSUM_MD5, attr);
642 18 : case CKA_CERT_SHA1_HASH:
643 18 : return trust_get_hash (self, G_CHECKSUM_SHA1, attr);
644 :
645 96 : default:
646 96 : break;
647 : };
648 :
649 96 : return GKM_OBJECT_CLASS (gkm_xdg_trust_parent_class)->get_attribute (base, session, attr);
650 : }
651 :
652 : static void
653 72 : gkm_xdg_trust_expose_object (GkmObject *base, gboolean expose)
654 : {
655 : GHashTableIter iter;
656 : gpointer value;
657 :
658 72 : GKM_OBJECT_CLASS (gkm_xdg_trust_parent_class)->expose_object (base, expose);
659 :
660 72 : g_hash_table_iter_init (&iter, GKM_XDG_TRUST (base)->pv->assertions);
661 119 : while (g_hash_table_iter_next (&iter, NULL, &value))
662 47 : gkm_object_expose (value, expose);
663 72 : }
664 :
665 : static GkmTrustLevel
666 24 : gkm_xdg_trust_get_level (GkmTrust *base, const gchar *purpose)
667 : {
668 24 : GkmXdgTrust *self = GKM_XDG_TRUST (base);
669 : GkmAssertion *assertion;
670 : GBytes *key;
671 : gulong type;
672 :
673 24 : key = create_assertion_key (purpose, NULL);
674 24 : assertion = g_hash_table_lookup (self->pv->assertions, key);
675 24 : g_bytes_unref (key);
676 :
677 24 : if (!assertion)
678 0 : return GKM_TRUST_UNKNOWN;
679 :
680 24 : type = gkm_assertion_get_trust_type (assertion);
681 24 : if (type == CKT_X_ANCHORED_CERTIFICATE)
682 8 : return GKM_TRUST_ANCHOR;
683 16 : else if (type == CKT_X_PINNED_CERTIFICATE)
684 8 : return GKM_TRUST_TRUSTED;
685 8 : else if (type == CKT_X_DISTRUSTED_CERTIFICATE)
686 8 : return GKM_TRUST_DISTRUSTED;
687 : else
688 0 : g_return_val_if_reached (GKM_TRUST_UNKNOWN);
689 : }
690 :
691 : static void
692 48 : gkm_xdg_trust_init (GkmXdgTrust *self)
693 : {
694 48 : self->pv = gkm_xdg_trust_get_instance_private (self);
695 48 : self->pv->assertions = create_assertions ();
696 48 : }
697 :
698 : static void
699 48 : gkm_xdg_trust_finalize (GObject *obj)
700 : {
701 48 : GkmXdgTrust *self = GKM_XDG_TRUST (obj);
702 :
703 48 : if (self->pv->asn)
704 36 : egg_asn1x_destroy (self->pv->asn);
705 48 : self->pv->asn = NULL;
706 :
707 48 : if (self->pv->assertions)
708 48 : g_hash_table_destroy (self->pv->assertions);
709 48 : self->pv->assertions = NULL;
710 :
711 48 : if (self->pv->bytes)
712 36 : g_bytes_unref (self->pv->bytes);
713 48 : self->pv->bytes = NULL;
714 :
715 48 : G_OBJECT_CLASS (gkm_xdg_trust_parent_class)->finalize (obj);
716 48 : }
717 :
718 : static void
719 2 : gkm_xdg_trust_class_init (GkmXdgTrustClass *klass)
720 : {
721 2 : GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
722 2 : GkmObjectClass *gkm_class = GKM_OBJECT_CLASS (klass);
723 2 : GkmTrustClass *trust_class = GKM_TRUST_CLASS (klass);
724 :
725 2 : gobject_class->finalize = gkm_xdg_trust_finalize;
726 2 : gkm_class->get_attribute = gkm_xdg_trust_get_attribute;
727 2 : gkm_class->expose_object = gkm_xdg_trust_expose_object;
728 2 : trust_class->get_trust_level = gkm_xdg_trust_get_level;
729 :
730 2 : QDATA_ASSERTION_KEY = g_quark_from_static_string ("gkm-xdg-trust-assertion-key");
731 :
732 2 : init_quarks ();
733 2 : }
734 :
735 : static gboolean
736 26 : gkm_xdg_trust_real_load (GkmSerializable *base,
737 : GkmSecret *login,
738 : GBytes *data)
739 : {
740 26 : GkmXdgTrust *self = GKM_XDG_TRUST (base);
741 26 : GNode *asn = NULL;
742 :
743 26 : if (g_bytes_get_size (data) == 0)
744 13 : return FALSE;
745 :
746 13 : asn = egg_asn1x_create (xdg_asn1_tab, "trust-1");
747 13 : g_return_val_if_fail (asn, FALSE);
748 :
749 13 : if (!egg_asn1x_decode (asn, data)) {
750 0 : g_warning ("couldn't parse trust data: %s", egg_asn1x_message (asn));
751 0 : egg_asn1x_destroy (asn);
752 0 : return FALSE;
753 : }
754 :
755 : /* Next parse out all the pairs */
756 13 : if (!load_assertions (self, asn)) {
757 0 : egg_asn1x_destroy (asn);
758 0 : return FALSE;
759 : }
760 :
761 : /* Take ownership of this new data */
762 13 : if (self->pv->bytes)
763 1 : g_bytes_unref (self->pv->bytes);
764 13 : self->pv->bytes = g_bytes_ref (data);
765 13 : egg_asn1x_destroy (self->pv->asn);
766 13 : self->pv->asn = asn;
767 :
768 13 : return TRUE;
769 : }
770 :
771 : static GBytes *
772 3 : gkm_xdg_trust_real_save (GkmSerializable *base, GkmSecret *login)
773 : {
774 3 : GkmXdgTrust *self = GKM_XDG_TRUST (base);
775 : GBytes *bytes;
776 :
777 3 : g_return_val_if_fail (GKM_XDG_IS_TRUST (self), FALSE);
778 3 : g_return_val_if_fail (self->pv->asn, FALSE);
779 :
780 3 : if (!save_assertions (self, self->pv->asn))
781 0 : return FALSE;
782 :
783 3 : bytes = egg_asn1x_encode (self->pv->asn, NULL);
784 3 : if (bytes == NULL) {
785 0 : g_warning ("encoding trust failed: %s", egg_asn1x_message (self->pv->asn));
786 0 : return FALSE;
787 : }
788 :
789 3 : if (self->pv->bytes)
790 3 : g_bytes_unref (self->pv->bytes);
791 3 : self->pv->bytes = bytes;
792 :
793 3 : return g_bytes_ref (bytes);
794 : }
795 :
796 : static void
797 2 : gkm_xdg_trust_serializable (GkmSerializableIface *iface)
798 : {
799 2 : iface->extension = ".trust";
800 2 : iface->load = gkm_xdg_trust_real_load;
801 2 : iface->save = gkm_xdg_trust_real_save;
802 2 : }
803 :
804 : /* -----------------------------------------------------------------------------
805 : * PUBLIC
806 : */
807 :
808 : GkmXdgTrust*
809 26 : gkm_xdg_trust_create_for_assertion (GkmModule *module, GkmManager *manager,
810 : GkmTransaction *transaction,
811 : CK_ATTRIBUTE_PTR attrs, CK_ULONG n_attrs)
812 : {
813 :
814 : CK_ATTRIBUTE_PTR serial, issuer, cert;
815 : GkmXdgTrust *trust;
816 :
817 26 : g_return_val_if_fail (GKM_IS_MODULE (module), NULL);
818 26 : g_return_val_if_fail (GKM_IS_MANAGER (manager), NULL);
819 26 : g_return_val_if_fail (attrs || !n_attrs, NULL);
820 :
821 26 : serial = gkm_attributes_find (attrs, n_attrs, CKA_SERIAL_NUMBER);
822 26 : issuer = gkm_attributes_find (attrs, n_attrs, CKA_ISSUER);
823 26 : cert = gkm_attributes_find (attrs, n_attrs, CKA_X_CERTIFICATE_VALUE);
824 :
825 : /* A trust object with just serial + issuer */
826 26 : if (serial != NULL && issuer != NULL) {
827 11 : if (cert != NULL) {
828 0 : gkm_transaction_fail (transaction, CKR_TEMPLATE_INCONSISTENT);
829 0 : return NULL;
830 : }
831 11 : if (!validate_der (issuer, "Name") || !validate_integer (serial)) {
832 0 : gkm_transaction_fail (transaction, CKR_ATTRIBUTE_VALUE_INVALID);
833 0 : return NULL;
834 : }
835 :
836 11 : trust = create_trust_for_reference (module, manager, serial, issuer);
837 :
838 : /* A trust object with a full certificate */
839 15 : } else if (cert != NULL) {
840 15 : if (serial != NULL || issuer != NULL) {
841 0 : gkm_transaction_fail (transaction, CKR_TEMPLATE_INCONSISTENT);
842 0 : return NULL;
843 : }
844 15 : if (!validate_der (cert, "Certificate")) {
845 2 : gkm_transaction_fail (transaction, CKR_ATTRIBUTE_VALUE_INVALID);
846 2 : return NULL;
847 : }
848 :
849 13 : trust = create_trust_for_complete (module, manager, cert);
850 :
851 : /* Not sure what this is */
852 : } else {
853 0 : gkm_transaction_fail (transaction, CKR_TEMPLATE_INCOMPLETE);
854 0 : return NULL;
855 : }
856 :
857 24 : gkm_attributes_consume (attrs, n_attrs, CKA_X_CERTIFICATE_VALUE, CKA_ISSUER,
858 : CKA_SERIAL_NUMBER, G_MAXULONG);
859 :
860 24 : return trust;
861 : }
862 :
863 : void
864 34 : gkm_xdg_trust_replace_assertion (GkmXdgTrust *self, GkmAssertion *assertion,
865 : GkmTransaction *transaction)
866 : {
867 : GkmAssertion *previous;
868 : GBytes *key;
869 :
870 34 : g_return_if_fail (GKM_XDG_IS_TRUST (self));
871 34 : g_return_if_fail (GKM_IS_ASSERTION (assertion));
872 34 : g_return_if_fail (!transaction || GKM_IS_TRANSACTION (transaction));
873 :
874 : /* Build up a key if we don't have one */
875 34 : key = lookup_or_create_assertion_key (assertion);
876 :
877 : /* Remove any previous assertion with this key */
878 34 : previous = g_hash_table_lookup (self->pv->assertions, key);
879 34 : if (previous != NULL)
880 10 : remove_assertion_from_trust (self, previous, transaction);
881 34 : add_assertion_to_trust (self, assertion, transaction);
882 :
883 : }
884 :
885 : void
886 1 : gkm_xdg_trust_remove_assertion (GkmXdgTrust *self, GkmAssertion *assertion,
887 : GkmTransaction *transaction)
888 : {
889 : GBytes *key;
890 :
891 1 : g_return_if_fail (GKM_XDG_IS_TRUST (self));
892 1 : g_return_if_fail (GKM_IS_ASSERTION (assertion));
893 1 : g_return_if_fail (!transaction || GKM_IS_TRANSACTION (transaction));
894 :
895 1 : key = lookup_assertion_key (assertion);
896 1 : g_return_if_fail (key);
897 :
898 : /* Assertion needs to be from this trust object */
899 1 : g_return_if_fail (g_hash_table_lookup (self->pv->assertions, key) == assertion);
900 1 : remove_assertion_from_trust (self, assertion, transaction);
901 : }
902 :
903 : gboolean
904 1 : gkm_xdg_trust_have_assertion (GkmXdgTrust *self)
905 : {
906 1 : g_return_val_if_fail (GKM_XDG_IS_TRUST (self), FALSE);
907 1 : return g_hash_table_size (self->pv->assertions);
908 : }
|