Line data Source code
1 : /*
2 : * gnome-keyring
3 : *
4 : * Copyright (C) 2008 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 "gkd-dbus.h"
24 : #include "gkd-secret-dispatch.h"
25 : #include "gkd-secret-error.h"
26 : #include "gkd-secret-secret.h"
27 : #include "gkd-secret-service.h"
28 : #include "gkd-secret-session.h"
29 : #include "gkd-secret-types.h"
30 : #include "gkd-secret-util.h"
31 : #include "gkd-secrets-generated.h"
32 :
33 : #include "egg/egg-dh.h"
34 : #include "egg/egg-error.h"
35 :
36 : #include "pkcs11/pkcs11i.h"
37 :
38 : #include <string.h>
39 :
40 : enum {
41 : PROP_0,
42 : PROP_CALLER,
43 : PROP_OBJECT_PATH,
44 : PROP_SERVICE
45 : };
46 :
47 : struct _GkdSecretSession {
48 : GObject parent;
49 :
50 : /* Information about this object */
51 : gchar *object_path;
52 : GkdSecretService *service;
53 : GkdExportedSession *skeleton;
54 : gchar *caller;
55 :
56 : /* While negotiating with a prompt, set to private key */
57 : GckObject *private;
58 :
59 : /* Once negotiated set to key and mechanism */
60 : GckObject *key;
61 : CK_MECHANISM_TYPE mech_type;
62 : };
63 :
64 : static void gkd_secret_dispatch_iface (GkdSecretDispatchIface *iface);
65 209 : G_DEFINE_TYPE_WITH_CODE (GkdSecretSession, gkd_secret_session, G_TYPE_OBJECT,
66 : G_IMPLEMENT_INTERFACE (GKD_SECRET_TYPE_DISPATCH, gkd_secret_dispatch_iface));
67 :
68 : static guint unique_session_number = 0;
69 :
70 : /* -----------------------------------------------------------------------------
71 : * INTERNAL
72 : */
73 :
74 : static void
75 16 : take_session_key (GkdSecretSession *self, GckObject *key, CK_MECHANISM_TYPE mech)
76 : {
77 16 : g_return_if_fail (!self->key);
78 16 : self->key = key;
79 16 : self->mech_type = mech;
80 : }
81 :
82 : static gboolean
83 1 : aes_create_dh_keys (GckSession *session, const gchar *group,
84 : GckObject **pub_key, GckObject **priv_key)
85 : {
86 1 : GckBuilder builder = GCK_BUILDER_INIT;
87 : GckAttributes *attrs;
88 : gconstpointer prime, base;
89 : gsize n_prime, n_base;
90 1 : GError *error = NULL;
91 : gboolean ret;
92 :
93 1 : if (!egg_dh_default_params_raw (group, &prime, &n_prime, &base, &n_base)) {
94 0 : g_warning ("couldn't load dh parameter group: %s", group);
95 0 : return FALSE;
96 : }
97 :
98 1 : gck_builder_add_data (&builder, CKA_PRIME, prime, n_prime);
99 1 : gck_builder_add_data (&builder, CKA_BASE, base, n_base);
100 1 : attrs = gck_attributes_ref_sink (gck_builder_end (&builder));
101 :
102 : /* Perform the DH key generation */
103 1 : ret = gck_session_generate_key_pair (session, CKM_DH_PKCS_KEY_PAIR_GEN, attrs, attrs,
104 : pub_key, priv_key, NULL, &error);
105 :
106 1 : gck_attributes_unref (attrs);
107 :
108 1 : if (ret == FALSE) {
109 0 : g_warning ("couldn't generate dh key pair: %s", egg_error_message (error));
110 0 : g_clear_error (&error);
111 0 : return FALSE;
112 : }
113 :
114 1 : return TRUE;
115 : }
116 :
117 : static gboolean
118 1 : aes_derive_key (GckSession *session, GckObject *priv_key,
119 : gconstpointer input, gsize n_input, GckObject **aes_key)
120 : {
121 1 : GckBuilder builder = GCK_BUILDER_INIT;
122 1 : GError *error = NULL;
123 : GckMechanism mech;
124 : GckObject *dh_key;
125 :
126 : /*
127 : * First we have to generate a secret key from the DH key. The
128 : * length of this key depends on the size of our DH prime
129 : */
130 :
131 1 : mech.type = CKM_DH_PKCS_DERIVE;
132 1 : mech.parameter = input;
133 1 : mech.n_parameter = n_input;
134 :
135 1 : gck_builder_add_ulong (&builder, CKA_CLASS, CKO_SECRET_KEY);
136 1 : gck_builder_add_ulong (&builder, CKA_KEY_TYPE, CKK_GENERIC_SECRET);
137 1 : dh_key = gck_session_derive_key_full (session, priv_key, &mech, gck_builder_end (&builder), NULL, &error);
138 :
139 1 : if (!dh_key) {
140 0 : g_warning ("couldn't derive key from dh key pair: %s", egg_error_message (error));
141 0 : g_clear_error (&error);
142 0 : return FALSE;
143 : }
144 :
145 : /*
146 : * Now use HKDF to generate our AES key.
147 : */
148 :
149 1 : mech.type = CKM_G_HKDF_SHA256_DERIVE;
150 1 : mech.parameter = NULL;
151 1 : mech.n_parameter = 0;
152 :
153 1 : gck_builder_add_ulong (&builder, CKA_VALUE_LEN, 16UL);
154 1 : gck_builder_add_ulong (&builder, CKA_CLASS, CKO_SECRET_KEY);
155 1 : gck_builder_add_ulong (&builder, CKA_KEY_TYPE, CKK_AES);
156 :
157 1 : *aes_key = gck_session_derive_key_full (session, dh_key, &mech, gck_builder_end (&builder), NULL, &error);
158 1 : g_object_unref (dh_key);
159 :
160 1 : if (!*aes_key) {
161 0 : g_warning ("couldn't derive aes key from dh key: %s", egg_error_message (error));
162 0 : g_clear_error (&error);
163 0 : return FALSE;
164 : }
165 :
166 1 : return TRUE;
167 : }
168 :
169 : static gboolean
170 0 : aes_negotiate (GkdSecretSession *self,
171 : GVariant *input_variant,
172 : GVariant **output_variant,
173 : gchar **result,
174 : GError **error_out)
175 : {
176 : GckSession *session;
177 : GckObject *pub, *priv, *key;
178 0 : GError *error = NULL;
179 : gpointer output;
180 : gsize n_output;
181 : const gchar *input;
182 : gsize n_input;
183 : gboolean ret;
184 :
185 0 : session = gkd_secret_service_get_pkcs11_session (self->service, self->caller);
186 0 : g_return_val_if_fail (session, FALSE);
187 :
188 0 : if (!aes_create_dh_keys (session, "ietf-ike-grp-modp-1024", &pub, &priv)) {
189 0 : g_set_error_literal (error_out, G_DBUS_ERROR,
190 : G_DBUS_ERROR_FAILED,
191 : "Failed to create necessary crypto keys.");
192 0 : return FALSE;
193 : }
194 :
195 : /* Get the output data */
196 0 : output = gck_object_get_data (pub, CKA_VALUE, NULL, &n_output, &error);
197 0 : gck_object_destroy (pub, NULL, NULL);
198 0 : g_object_unref (pub);
199 :
200 0 : if (output == NULL) {
201 0 : g_warning ("couldn't get public key DH value: %s", egg_error_message (error));
202 0 : g_clear_error (&error);
203 0 : g_object_unref (priv);
204 0 : g_set_error_literal (error_out, G_DBUS_ERROR,
205 : G_DBUS_ERROR_FAILED,
206 : "Failed to retrieve necessary crypto keys.");
207 0 : return FALSE;
208 : }
209 :
210 0 : input = g_variant_get_fixed_array (input_variant, &n_input, sizeof (guchar));
211 0 : ret = aes_derive_key (session, priv, input, n_input, &key);
212 :
213 0 : gck_object_destroy (priv, NULL, NULL);
214 0 : g_object_unref (priv);
215 :
216 0 : if (ret == FALSE) {
217 0 : g_free (output);
218 0 : g_set_error_literal (error_out, G_DBUS_ERROR,
219 : G_DBUS_ERROR_FAILED,
220 : "Failed to create necessary crypto key.");
221 0 : return FALSE;
222 : }
223 :
224 0 : take_session_key (self, key, CKM_AES_CBC_PAD);
225 :
226 0 : if (output_variant != NULL) {
227 0 : *output_variant = g_variant_new_variant (g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE,
228 : output, n_output,
229 : sizeof (guchar)));
230 : }
231 :
232 0 : if (result != NULL) {
233 0 : *result = g_strdup (self->object_path);
234 : }
235 :
236 0 : g_free (output);
237 :
238 0 : return TRUE;
239 : }
240 :
241 : static gboolean
242 16 : plain_negotiate (GkdSecretSession *self,
243 : GVariant **output,
244 : gchar **result,
245 : GError **error_out)
246 : {
247 16 : GckBuilder builder = GCK_BUILDER_INIT;
248 16 : GError *error = NULL;
249 : GckObject *key;
250 : GckSession *session;
251 :
252 16 : session = gkd_secret_service_get_pkcs11_session (self->service, self->caller);
253 16 : g_return_val_if_fail (session, FALSE);
254 :
255 16 : gck_builder_add_ulong (&builder, CKA_CLASS, CKO_SECRET_KEY);
256 16 : gck_builder_add_ulong (&builder, CKA_KEY_TYPE, CKK_G_NULL);
257 :
258 16 : key = gck_session_create_object (session, gck_builder_end (&builder), NULL, &error);
259 :
260 16 : if (key == NULL) {
261 0 : g_warning ("couldn't create null key: %s", egg_error_message (error));
262 0 : g_clear_error (&error);
263 0 : g_set_error_literal (error_out, G_DBUS_ERROR,
264 : G_DBUS_ERROR_FAILED,
265 : "Failed to create necessary plain keys.");
266 0 : return FALSE;
267 : }
268 :
269 16 : take_session_key (self, key, CKM_G_NULL);
270 :
271 16 : if (output != NULL) {
272 16 : *output = g_variant_new_variant (g_variant_new_string (""));
273 : }
274 :
275 16 : if (result != NULL) {
276 32 : *result = g_strdup (self->object_path);
277 : }
278 :
279 16 : return TRUE;
280 : }
281 :
282 : /* -----------------------------------------------------------------------------
283 : * DBUS
284 : */
285 : static gboolean
286 0 : session_method_close (GkdExportedSession *skeleton,
287 : GDBusMethodInvocation *invocation,
288 : GkdSecretSession *self)
289 : {
290 0 : if (!gkd_dbus_invocation_matches_caller (invocation, self->caller))
291 0 : return FALSE;
292 :
293 0 : gkd_secret_service_close_session (self->service, self);
294 0 : gkd_exported_session_complete_close (skeleton, invocation);
295 :
296 0 : return TRUE;
297 : }
298 :
299 : /* -----------------------------------------------------------------------------
300 : * OBJECT
301 : */
302 : static GObject*
303 17 : gkd_secret_session_constructor (GType type, guint n_props, GObjectConstructParam *props)
304 : {
305 17 : GkdSecretSession *self = GKD_SECRET_SESSION (G_OBJECT_CLASS (gkd_secret_session_parent_class)->constructor(type, n_props, props));
306 17 : GError *error = NULL;
307 :
308 17 : g_return_val_if_fail (self, NULL);
309 17 : g_return_val_if_fail (self->caller, NULL);
310 17 : g_return_val_if_fail (self->service, NULL);
311 :
312 : /* Setup the path for the object */
313 17 : self->object_path = g_strdup_printf (SECRET_SESSION_PREFIX "/s%d", ++unique_session_number);
314 :
315 17 : self->skeleton = gkd_exported_session_skeleton_new ();
316 17 : g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (self->skeleton),
317 : gkd_secret_service_get_connection (self->service),
318 17 : self->object_path, &error);
319 :
320 17 : if (error != NULL) {
321 0 : g_warning ("could not register secret session on session bus: %s", error->message);
322 0 : g_error_free (error);
323 : }
324 :
325 17 : g_signal_connect (self->skeleton, "handle-close",
326 : G_CALLBACK (session_method_close), self);
327 :
328 17 : return G_OBJECT (self);
329 : }
330 :
331 : static void
332 17 : gkd_secret_session_init (GkdSecretSession *self)
333 : {
334 :
335 17 : }
336 :
337 : static void
338 32 : gkd_secret_session_dispose (GObject *obj)
339 : {
340 32 : GkdSecretSession *self = GKD_SECRET_SESSION (obj);
341 :
342 32 : g_free (self->object_path);
343 32 : self->object_path = NULL;
344 :
345 32 : if (self->skeleton) {
346 16 : g_dbus_interface_skeleton_unexport (G_DBUS_INTERFACE_SKELETON (self->skeleton));
347 16 : g_clear_object (&self->skeleton);
348 : }
349 :
350 32 : if (self->service) {
351 16 : g_object_remove_weak_pointer (G_OBJECT (self->service),
352 16 : (gpointer*)&(self->service));
353 16 : self->service = NULL;
354 : }
355 :
356 32 : if (self->key) {
357 16 : g_object_unref (self->key);
358 16 : self->key = NULL;
359 : }
360 :
361 32 : G_OBJECT_CLASS (gkd_secret_session_parent_class)->dispose (obj);
362 32 : }
363 :
364 : static void
365 16 : gkd_secret_session_finalize (GObject *obj)
366 : {
367 16 : GkdSecretSession *self = GKD_SECRET_SESSION (obj);
368 :
369 16 : g_assert (!self->object_path);
370 16 : g_assert (!self->service);
371 16 : g_assert (!self->key);
372 :
373 16 : g_free (self->caller);
374 16 : self->caller = NULL;
375 :
376 16 : G_OBJECT_CLASS (gkd_secret_session_parent_class)->finalize (obj);
377 16 : }
378 :
379 : static void
380 34 : gkd_secret_session_set_property (GObject *obj, guint prop_id, const GValue *value,
381 : GParamSpec *pspec)
382 : {
383 34 : GkdSecretSession *self = GKD_SECRET_SESSION (obj);
384 :
385 34 : switch (prop_id) {
386 17 : case PROP_CALLER:
387 17 : g_return_if_fail (!self->caller);
388 17 : self->caller = g_value_dup_string (value);
389 17 : break;
390 17 : case PROP_SERVICE:
391 17 : g_return_if_fail (!self->service);
392 17 : self->service = g_value_get_object (value);
393 17 : g_return_if_fail (self->service);
394 17 : g_object_add_weak_pointer (G_OBJECT (self->service),
395 17 : (gpointer*)&(self->service));
396 17 : break;
397 0 : default:
398 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
399 0 : break;
400 : }
401 : }
402 :
403 : static void
404 16 : gkd_secret_session_get_property (GObject *obj, guint prop_id, GValue *value,
405 : GParamSpec *pspec)
406 : {
407 16 : GkdSecretSession *self = GKD_SECRET_SESSION (obj);
408 :
409 16 : switch (prop_id) {
410 0 : case PROP_CALLER:
411 0 : g_value_set_string (value, gkd_secret_session_get_caller (self));
412 0 : break;
413 16 : case PROP_OBJECT_PATH:
414 16 : g_value_set_pointer (value, self->object_path);
415 16 : break;
416 0 : case PROP_SERVICE:
417 0 : g_value_set_object (value, self->service);
418 0 : break;
419 0 : default:
420 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
421 0 : break;
422 : }
423 16 : }
424 :
425 : static void
426 16 : gkd_secret_session_class_init (GkdSecretSessionClass *klass)
427 : {
428 16 : GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
429 :
430 16 : gobject_class->constructor = gkd_secret_session_constructor;
431 16 : gobject_class->dispose = gkd_secret_session_dispose;
432 16 : gobject_class->finalize = gkd_secret_session_finalize;
433 16 : gobject_class->set_property = gkd_secret_session_set_property;
434 16 : gobject_class->get_property = gkd_secret_session_get_property;
435 :
436 16 : g_object_class_install_property (gobject_class, PROP_CALLER,
437 : g_param_spec_string ("caller", "Caller", "DBus caller name",
438 : NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY ));
439 :
440 16 : g_object_class_install_property (gobject_class, PROP_OBJECT_PATH,
441 : g_param_spec_pointer ("object-path", "Object Path", "DBus Object Path",
442 : G_PARAM_READABLE));
443 :
444 16 : g_object_class_install_property (gobject_class, PROP_SERVICE,
445 : g_param_spec_object ("service", "Service", "Service which owns this session",
446 : GKD_SECRET_TYPE_SERVICE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
447 16 : }
448 :
449 : static void
450 16 : gkd_secret_dispatch_iface (GkdSecretDispatchIface *iface)
451 : {
452 16 : }
453 :
454 : /* -----------------------------------------------------------------------------
455 : * PUBLIC
456 : */
457 :
458 : GkdSecretSession*
459 17 : gkd_secret_session_new (GkdSecretService *service, const gchar *caller)
460 : {
461 17 : g_return_val_if_fail (GKD_SECRET_IS_SERVICE (service), NULL);
462 17 : g_return_val_if_fail (caller, NULL);
463 17 : return g_object_new (GKD_SECRET_TYPE_SESSION,
464 : "caller", caller, "service", service, NULL);
465 : }
466 :
467 : gpointer
468 1 : gkd_secret_session_begin (GkdSecretSession *self, const gchar *group,
469 : gsize *n_output)
470 : {
471 1 : GError *error = NULL;
472 : GckSession *session;
473 : GckObject *public;
474 : gpointer output;
475 :
476 1 : g_return_val_if_fail (GKD_SECRET_IS_SESSION (self), NULL);
477 1 : g_return_val_if_fail (group, NULL);
478 1 : g_return_val_if_fail (n_output, NULL);
479 1 : g_return_val_if_fail (self->private == NULL, NULL);
480 :
481 1 : session = gkd_secret_session_get_pkcs11_session (self);
482 1 : g_return_val_if_fail (session, NULL);
483 :
484 1 : if (!aes_create_dh_keys (session, group, &public, &self->private))
485 0 : return NULL;
486 :
487 : /* Get the output data */
488 1 : output = gck_object_get_data (public, CKA_VALUE, NULL, n_output, &error);
489 1 : gck_object_destroy (public, NULL, NULL);
490 1 : g_object_unref (public);
491 :
492 1 : if (output == NULL) {
493 0 : g_warning ("couldn't get public key DH value: %s", egg_error_message (error));
494 0 : g_clear_error (&error);
495 0 : return NULL;
496 : }
497 :
498 1 : return output;
499 : }
500 :
501 : gboolean
502 1 : gkd_secret_session_complete (GkdSecretSession *self, gconstpointer peer,
503 : gsize n_peer)
504 : {
505 : GckSession *session;
506 :
507 1 : g_return_val_if_fail (GKD_SECRET_IS_SESSION (self), FALSE);
508 1 : g_return_val_if_fail (self->key == NULL, FALSE);
509 :
510 1 : session = gkd_secret_session_get_pkcs11_session (self);
511 1 : g_return_val_if_fail (session, FALSE);
512 :
513 1 : if (!aes_derive_key (session, self->private, peer, n_peer, &self->key))
514 0 : return FALSE;
515 :
516 1 : self->mech_type = CKM_AES_CBC_PAD;
517 1 : return TRUE;
518 : }
519 :
520 : gboolean
521 16 : gkd_secret_session_handle_open (GkdSecretSession *self,
522 : const gchar *algorithm,
523 : GVariant *input,
524 : GVariant **output,
525 : gchar **result,
526 : GError **error)
527 : {
528 : const GVariantType *variant_type;
529 :
530 16 : variant_type = g_variant_get_type (input);
531 :
532 : /* Plain transfers? just remove our session key */
533 16 : if (g_str_equal (algorithm, "plain")) {
534 16 : if (!g_variant_type_equal (variant_type, G_VARIANT_TYPE_STRING)) {
535 0 : g_set_error (error, G_DBUS_ERROR,
536 : G_DBUS_ERROR_INVALID_ARGS,
537 : "The session algorithm input argument (%s) was invalid",
538 : algorithm);
539 0 : return FALSE;
540 : }
541 :
542 16 : return plain_negotiate (self, output, result, error);
543 :
544 0 : } else if (g_str_equal (algorithm, "dh-ietf1024-sha256-aes128-cbc-pkcs7")) {
545 0 : if (!g_variant_type_equal (variant_type, G_VARIANT_TYPE_BYTESTRING)) {
546 0 : g_set_error (error, G_DBUS_ERROR,
547 : G_DBUS_ERROR_INVALID_ARGS,
548 : "The session algorithm input argument (%s) was invalid",
549 : algorithm);
550 0 : return FALSE;
551 : }
552 :
553 0 : return aes_negotiate (self, input, output, result, error);
554 :
555 : } else {
556 0 : g_set_error (error, G_DBUS_ERROR,
557 : G_DBUS_ERROR_NOT_SUPPORTED,
558 : "The algorithm '%s' is not supported", algorithm);
559 0 : return FALSE;
560 : }
561 :
562 : g_assert_not_reached ();
563 : }
564 :
565 :
566 : const gchar*
567 0 : gkd_secret_session_get_caller (GkdSecretSession *self)
568 : {
569 0 : g_return_val_if_fail (GKD_SECRET_IS_SESSION (self), NULL);
570 0 : return self->caller;
571 : }
572 :
573 : GckSession*
574 4 : gkd_secret_session_get_pkcs11_session (GkdSecretSession *self)
575 : {
576 4 : g_return_val_if_fail (GKD_SECRET_IS_SESSION (self), NULL);
577 4 : return gkd_secret_service_get_pkcs11_session (self->service, self->caller);
578 : }
579 :
580 : GkdSecretSecret*
581 0 : gkd_secret_session_get_item_secret (GkdSecretSession *self, GckObject *item,
582 : GError **error_out)
583 : {
584 0 : GckMechanism mech = { 0UL, NULL, 0 };
585 : GckSession *session;
586 : gpointer value, iv;
587 : gsize n_value, n_iv;
588 0 : GError *error = NULL;
589 :
590 0 : g_assert (GCK_IS_OBJECT (self->key));
591 :
592 0 : session = gck_object_get_session (item);
593 0 : g_return_val_if_fail (session, NULL);
594 :
595 0 : if (self->mech_type == CKM_AES_CBC_PAD) {
596 0 : n_iv = 16;
597 0 : iv = g_malloc (n_iv);
598 0 : gcry_create_nonce (iv, n_iv);
599 : } else {
600 0 : n_iv = 0;
601 0 : iv = NULL;
602 : }
603 :
604 0 : mech.type = self->mech_type;
605 0 : mech.parameter = iv;
606 0 : mech.n_parameter = n_iv;
607 :
608 0 : value = gck_session_wrap_key_full (session, self->key, &mech, item, &n_value,
609 : NULL, &error);
610 :
611 0 : if (error != NULL) {
612 0 : if (g_error_matches (error, GCK_ERROR, CKR_USER_NOT_LOGGED_IN)) {
613 0 : g_set_error_literal (error_out, GKD_SECRET_ERROR,
614 : GKD_SECRET_ERROR_IS_LOCKED,
615 : "Cannot get secret of a locked object");
616 : } else {
617 0 : g_message ("couldn't wrap item secret: %s", egg_error_message (error));
618 0 : g_set_error_literal (error_out, G_DBUS_ERROR,
619 : G_DBUS_ERROR_FAILED,
620 : "Couldn't get item secret");
621 : }
622 0 : g_clear_error (&error);
623 0 : g_free (iv);
624 0 : return NULL;
625 : }
626 :
627 0 : return gkd_secret_secret_new_take_memory (self, iv, n_iv, value, n_value);
628 : }
629 :
630 : gboolean
631 2 : gkd_secret_session_set_item_secret (GkdSecretSession *self, GckObject *item,
632 : GkdSecretSecret *secret, GError **error_out)
633 : {
634 2 : GckBuilder builder = GCK_BUILDER_INIT;
635 : GckMechanism mech;
636 : GckObject *object;
637 : GckSession *session;
638 2 : GError *error = NULL;
639 : GckAttributes *attrs;
640 :
641 2 : g_return_val_if_fail (GKD_SECRET_IS_SESSION (self), FALSE);
642 2 : g_return_val_if_fail (GCK_IS_OBJECT (item), FALSE);
643 2 : g_return_val_if_fail (secret, FALSE);
644 :
645 2 : g_assert (GCK_IS_OBJECT (self->key));
646 :
647 : /*
648 : * By getting these attributes, and then using them in the unwrap,
649 : * the unwrap won't generate a new object, but merely set the secret.
650 : */
651 :
652 2 : attrs = gck_object_get (item, NULL, &error, CKA_ID, CKA_G_COLLECTION, GCK_INVALID);
653 2 : if (attrs == NULL) {
654 0 : g_set_error_literal (error_out, G_DBUS_ERROR,
655 : G_DBUS_ERROR_FAILED,
656 : "Couldn't set item secret");
657 0 : g_clear_error (&error);
658 0 : return FALSE;
659 : }
660 2 : gck_builder_add_all (&builder, attrs);
661 2 : gck_attributes_unref (attrs);
662 2 : gck_builder_add_ulong (&builder, CKA_CLASS, CKO_SECRET_KEY);
663 :
664 2 : session = gkd_secret_service_get_pkcs11_session (self->service, self->caller);
665 2 : g_return_val_if_fail (session, FALSE);
666 :
667 2 : mech.type = self->mech_type;
668 2 : mech.parameter = secret->parameter;
669 2 : mech.n_parameter = secret->n_parameter;
670 :
671 2 : object = gck_session_unwrap_key_full (session, self->key, &mech, secret->value,
672 : secret->n_value, gck_builder_end (&builder), NULL, &error);
673 :
674 2 : if (object == NULL) {
675 0 : if (g_error_matches (error, GCK_ERROR, CKR_USER_NOT_LOGGED_IN)) {
676 0 : g_set_error_literal (error_out, GKD_SECRET_ERROR,
677 : GKD_SECRET_ERROR_IS_LOCKED,
678 : "Cannot set secret of a locked item");
679 0 : } else if (g_error_matches (error, GCK_ERROR, CKR_WRAPPED_KEY_INVALID) ||
680 0 : g_error_matches (error, GCK_ERROR, CKR_WRAPPED_KEY_LEN_RANGE) ||
681 0 : g_error_matches (error, GCK_ERROR, CKR_MECHANISM_PARAM_INVALID)) {
682 0 : g_set_error_literal (error_out, G_DBUS_ERROR,
683 : G_DBUS_ERROR_INVALID_ARGS,
684 : "The secret was transferred or encrypted in an invalid way.");
685 : } else {
686 0 : g_message ("couldn't unwrap item secret: %s", egg_error_message (error));
687 0 : g_set_error_literal (error_out, G_DBUS_ERROR,
688 : G_DBUS_ERROR_FAILED,
689 : "Couldn't set item secret");
690 : }
691 0 : g_clear_error (&error);
692 0 : return FALSE;
693 : }
694 :
695 2 : if (!gck_object_equal (object, item)) {
696 0 : g_warning ("unwrapped secret went to new object, instead of item");
697 0 : g_set_error_literal (error_out, G_DBUS_ERROR,
698 : G_DBUS_ERROR_FAILED,
699 : "Couldn't set item secret");
700 0 : g_object_unref (object);
701 0 : return FALSE;
702 : }
703 :
704 2 : g_object_unref (object);
705 2 : return TRUE;
706 : }
707 :
708 : GckObject*
709 17 : gkd_secret_session_create_credential (GkdSecretSession *self,
710 : GckSession *session,
711 : GckAttributes *attrs,
712 : GkdSecretSecret *secret,
713 : GError **error)
714 : {
715 17 : GckBuilder builder = GCK_BUILDER_INIT;
716 17 : GckAttributes *alloc = NULL;
717 : GckMechanism mech;
718 : GckObject *object;
719 :
720 17 : g_assert (GCK_IS_OBJECT (self->key));
721 17 : g_assert (attrs != NULL);
722 :
723 17 : if (session == NULL)
724 15 : session = gkd_secret_service_get_pkcs11_session (self->service, self->caller);
725 17 : g_return_val_if_fail (session, NULL);
726 :
727 17 : if (attrs == NULL) {
728 0 : gck_builder_add_ulong (&builder, CKA_CLASS, CKO_G_CREDENTIAL);
729 0 : gck_builder_add_boolean (&builder, CKA_TOKEN, FALSE);
730 0 : alloc = attrs = gck_attributes_ref_sink (gck_builder_end (&builder));
731 : }
732 :
733 17 : mech.type = self->mech_type;
734 17 : mech.parameter = secret->parameter;
735 17 : mech.n_parameter = secret->n_parameter;
736 :
737 17 : object = gck_session_unwrap_key_full (session, self->key, &mech, secret->value,
738 : secret->n_value, attrs, NULL, error);
739 :
740 17 : gck_attributes_unref (alloc);
741 :
742 17 : return object;
743 : }
|