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 "pkcs11/pkcs11.h"
24 #include "pkcs11/pkcs11i.h"
25
26 #include "gkm-attributes.h"
27 #include "gkm-credential.h"
28 #include "gkm-crypto.h"
29 #include "gkm-factory.h"
30 #include "gkm-manager.h"
31 #include "gkm-memory-store.h"
32 #include "gkm-session.h"
33 #include "gkm-sexp.h"
34 #include "gkm-sexp-key.h"
35 #include "gkm-transaction.h"
36 #include "gkm-util.h"
37
38 enum {
39 PROP_0,
40 PROP_MODULE,
41 PROP_SLOT_ID,
42 PROP_APARTMENT,
43 PROP_HANDLE,
44 PROP_FLAGS,
45 PROP_MANAGER,
46 PROP_LOGGED_IN
47 };
48
49 struct _GkmSessionPrivate {
50
51 CK_SESSION_HANDLE handle;
52 CK_SLOT_ID slot_id;
53 CK_ULONG apartment;
54
55 GkmModule *module;
56 GkmManager *manager;
57 GkmStore *store;
58
59 CK_USER_TYPE logged_in;
60 CK_ULONG flags;
61
62 CK_NOTIFY notify_callback;
63 CK_VOID_PTR application_ptr;
64
65 /* Objects owned by this session */
66 GHashTable *objects;
67
68 /* Used for operations */
69 void (*current_operation) (GkmSession *self);
70 GkmObject *current_object;
71 GkmCredential *credential;
72
73 /* Used for find operations */
74 GArray *found_objects;
75
76 /* Used for crypto operations */
77 gpointer crypto_state;
78 GDestroyNotify crypto_destroy;
79 CK_MECHANISM_TYPE crypto_mechanism;
80 CK_ATTRIBUTE_TYPE crypto_method;
81 };
82
83 G_DEFINE_TYPE_WITH_PRIVATE (GkmSession, gkm_session, G_TYPE_OBJECT);
84
85 static void add_object (GkmSession *self, GkmTransaction *transaction, GkmObject *object);
86 static void remove_object (GkmSession *self, GkmTransaction *transaction, GkmObject *object);
87
88 /* -----------------------------------------------------------------------------
89 * INTERNAL
90 */
91
92 static void
cleanup_crypto(GkmSession * self)93 cleanup_crypto (GkmSession *self)
94 {
95 g_assert (self->pv->current_operation == cleanup_crypto);
96
97 if (self->pv->crypto_state && self->pv->crypto_destroy)
98 (self->pv->crypto_destroy) (self->pv->crypto_state);
99 self->pv->crypto_state = NULL;
100 self->pv->crypto_destroy = NULL;
101 self->pv->crypto_mechanism = 0;
102 self->pv->crypto_method = 0;
103
104 g_assert (GKM_IS_OBJECT (self->pv->current_object));
105 if (self->pv->current_object)
106 g_object_unref (self->pv->current_object);
107 self->pv->current_object = NULL;
108
109 if (self->pv->credential) {
110 g_object_set_data (G_OBJECT (self->pv->credential), "owned-by-session", NULL);
111 g_object_unref (self->pv->credential);
112 self->pv->credential = NULL;
113 }
114
115 self->pv->current_operation = NULL;
116 }
117
118 static CK_RV
prepare_crypto(GkmSession * self,CK_MECHANISM_PTR mech,CK_ATTRIBUTE_TYPE method,CK_OBJECT_HANDLE handle)119 prepare_crypto (GkmSession *self, CK_MECHANISM_PTR mech,
120 CK_ATTRIBUTE_TYPE method, CK_OBJECT_HANDLE handle)
121 {
122 GkmObject *object;
123 CK_MECHANISM_TYPE_PTR mechanisms;
124 CK_ULONG n_mechanisms, i;
125 gsize n_data;
126 gboolean have;
127 gulong key_type;
128 CK_RV rv;
129
130 g_assert (GKM_IS_SESSION (self));
131
132 /* Cancel any current operation */
133 if (self->pv->current_operation) {
134 (self->pv->current_operation) (self);
135 g_assert (!self->pv->current_operation);
136 }
137
138 g_assert (!self->pv->crypto_state);
139
140 /* First find the object */
141 rv = gkm_session_lookup_readable_object (self, handle, &object);
142 if (rv != CKR_OK)
143 return rv;
144
145 /* Make sure it's a key */
146 if (!gkm_object_get_attribute_ulong (object, self, CKA_KEY_TYPE, &key_type))
147 return CKR_KEY_HANDLE_INVALID;
148
149 /* Lookup the mechanisms this object can do */
150 mechanisms = gkm_object_get_attribute_data (object, self, CKA_ALLOWED_MECHANISMS, &n_data);
151 if (mechanisms)
152 n_mechanisms = n_data / sizeof (CK_MECHANISM_TYPE);
153 else
154 n_mechanisms = 0;
155
156 /* See if ours is represented */
157 have = FALSE;
158 for (i = 0; !have && i < n_mechanisms; ++i) {
159 if (mechanisms[i] == mech->mechanism)
160 have = TRUE;
161 }
162
163 g_free (mechanisms);
164
165 if (have == FALSE)
166 return CKR_KEY_TYPE_INCONSISTENT;
167
168 /* Check that the object can do this method */
169 if (!gkm_object_get_attribute_boolean (object, self, method, &have) || !have)
170 return CKR_KEY_FUNCTION_NOT_PERMITTED;
171
172 /* Track the cyrpto object */
173 self->pv->current_object = object;
174 g_object_ref (object);
175
176 /* And note what we're setup for */
177 self->pv->current_operation = cleanup_crypto;
178 self->pv->crypto_mechanism = mech->mechanism;
179 self->pv->crypto_method = method;
180
181 return CKR_OK;
182 }
183
184 static CK_RV
process_crypto(GkmSession * self,CK_ATTRIBUTE_TYPE method,CK_BYTE_PTR bufone,CK_ULONG n_bufone,CK_BYTE_PTR buftwo,CK_ULONG_PTR n_buftwo)185 process_crypto (GkmSession *self, CK_ATTRIBUTE_TYPE method, CK_BYTE_PTR bufone,
186 CK_ULONG n_bufone, CK_BYTE_PTR buftwo, CK_ULONG_PTR n_buftwo)
187 {
188 CK_RV rv = CKR_OK;
189
190 g_assert (GKM_IS_SESSION (self));
191
192 if (self->pv->current_operation != cleanup_crypto)
193 return CKR_OPERATION_NOT_INITIALIZED;
194 if (method != self->pv->crypto_method)
195 return CKR_OPERATION_NOT_INITIALIZED;
196
197 if (!bufone || !n_buftwo)
198 rv = CKR_ARGUMENTS_BAD;
199
200 if (rv == CKR_OK) {
201 /* Load up the actual sexp we're going to use */
202 if (!self->pv->crypto_state) {
203 g_return_val_if_fail (GKM_IS_OBJECT (self->pv->current_object), CKR_GENERAL_ERROR);
204 rv = gkm_crypto_prepare (self, self->pv->crypto_mechanism, self->pv->current_object);
205 }
206 }
207
208 if (rv == CKR_OK) {
209 g_assert (self->pv->crypto_mechanism);
210 rv = gkm_crypto_perform (self, self->pv->crypto_mechanism, method,
211 bufone, n_bufone, buftwo, n_buftwo);
212 }
213
214 /* Under these conditions the operation isn't complete */
215 if (rv == CKR_BUFFER_TOO_SMALL || rv == CKR_USER_NOT_LOGGED_IN ||
216 (rv == CKR_OK && buftwo == NULL))
217 return rv;
218
219 cleanup_crypto (self);
220 return rv;
221 }
222
223 static void
cleanup_found(GkmSession * self)224 cleanup_found (GkmSession *self)
225 {
226 g_assert (GKM_IS_SESSION (self));
227
228 g_assert (self->pv->found_objects);
229 g_array_free (self->pv->found_objects, TRUE);
230 self->pv->found_objects = NULL;
231
232 self->pv->current_operation = NULL;
233 }
234
235 static CK_RV
lookup_object_from_handle(GkmSession * self,CK_OBJECT_HANDLE handle,gboolean writable,GkmObject ** result)236 lookup_object_from_handle (GkmSession *self, CK_OBJECT_HANDLE handle,
237 gboolean writable, GkmObject **result)
238 {
239 GkmManager *manager;
240 GkmObject *object;
241 gboolean is_private;
242 gboolean is_token;
243
244 g_return_val_if_fail (result, CKR_GENERAL_ERROR);
245 g_return_val_if_fail (GKM_IS_SESSION (self), CKR_GENERAL_ERROR);
246
247 if (handle == 0)
248 return CKR_OBJECT_HANDLE_INVALID;
249
250 /* Try looking up in the token manager */
251 manager = gkm_module_get_manager (self->pv->module);
252 object = gkm_manager_find_by_handle (manager, handle);
253 is_token = TRUE;
254
255 /* Try looking up in the session manager */
256 if (object == NULL) {
257 manager = gkm_session_get_manager (self);
258 object = gkm_manager_find_by_handle (manager, handle);
259 is_token = FALSE;
260 }
261
262 if (object == NULL)
263 return CKR_OBJECT_HANDLE_INVALID;
264
265 g_return_val_if_fail (manager, CKR_GENERAL_ERROR);
266
267 /*
268 * Check that we're not accessing private objects on a
269 * non-logged in session
270 */
271 if (self->pv->logged_in != CKU_USER) {
272 if (!gkm_object_get_attribute_boolean (object, self, CKA_PRIVATE, &is_private))
273 is_private = FALSE;
274 if (is_private)
275 return CKR_USER_NOT_LOGGED_IN;
276 }
277
278 /*
279 * If we're going to write to this object check that we're in a
280 * writable session and object is modifiable.
281 */
282 if (writable) {
283 if (is_token) {
284 if (!gkm_object_is_transient (object))
285 if (gkm_module_get_write_protected (self->pv->module))
286 return CKR_TOKEN_WRITE_PROTECTED;
287 if (gkm_session_is_read_only (self))
288 return CKR_SESSION_READ_ONLY;
289 }
290 }
291
292 *result = object;
293 return CKR_OK;
294 }
295
296
297 static gboolean
complete_remove(GkmTransaction * transaction,GkmSession * self,GkmObject * object)298 complete_remove (GkmTransaction *transaction, GkmSession *self, GkmObject *object)
299 {
300 if (gkm_transaction_get_failed (transaction))
301 add_object (self, NULL, object);
302 g_object_unref (object);
303 return TRUE;
304 }
305
306 static void
remove_object(GkmSession * self,GkmTransaction * transaction,GkmObject * object)307 remove_object (GkmSession *self, GkmTransaction *transaction, GkmObject *object)
308 {
309 g_assert (GKM_IS_SESSION (self));
310 g_assert (GKM_IS_OBJECT (object));
311
312 g_object_ref (object);
313
314 gkm_object_expose_full (object, transaction, FALSE);
315 g_hash_table_remove (self->pv->objects, object);
316 g_object_set (object, "store", NULL, NULL);
317
318 if (transaction)
319 gkm_transaction_add (transaction, self, (GkmTransactionFunc)complete_remove,
320 g_object_ref (object));
321
322 g_object_unref (object);
323 }
324
325 static gboolean
complete_add(GkmTransaction * transaction,GkmSession * self,GkmObject * object)326 complete_add (GkmTransaction *transaction, GkmSession *self, GkmObject *object)
327 {
328 if (gkm_transaction_get_failed (transaction))
329 remove_object (self, NULL, object);
330 g_object_unref (object);
331 return TRUE;
332 }
333
334 static void
add_object(GkmSession * self,GkmTransaction * transaction,GkmObject * object)335 add_object (GkmSession *self, GkmTransaction *transaction, GkmObject *object)
336 {
337 g_assert (GKM_IS_SESSION (self));
338 g_assert (GKM_IS_OBJECT (object));
339
340 /* Must not already be associated with a session or manager */
341 g_return_if_fail (gkm_object_get_manager (object) == self->pv->manager);
342 g_return_if_fail (g_object_get_data (G_OBJECT (object), "owned-by-session") == NULL);
343 g_return_if_fail (g_hash_table_lookup (self->pv->objects, object) == NULL);
344
345 g_hash_table_insert (self->pv->objects, object, g_object_ref (object));
346 g_object_set_data (G_OBJECT (object), "owned-by-session", self);
347 g_object_set (object, "store", self->pv->store, NULL);
348 gkm_object_expose_full (object, transaction, TRUE);
349
350 if (transaction)
351 gkm_transaction_add (transaction, self, (GkmTransactionFunc)complete_add,
352 g_object_ref (object));
353 }
354
355 /* -----------------------------------------------------------------------------
356 * OBJECT
357 */
358
359
360 static GObject*
gkm_session_constructor(GType type,guint n_props,GObjectConstructParam * props)361 gkm_session_constructor (GType type, guint n_props, GObjectConstructParam *props)
362 {
363 GkmSession *self = GKM_SESSION (G_OBJECT_CLASS (gkm_session_parent_class)->constructor(type, n_props, props));
364 CK_ATTRIBUTE attr;
365
366 g_return_val_if_fail (self, NULL);
367
368 /* Register store attributes */
369 attr.type = CKA_LABEL;
370 attr.pValue = "";
371 attr.ulValueLen = 0;
372 gkm_store_register_schema (self->pv->store, &attr, NULL, 0);
373
374 return G_OBJECT (self);
375 }
376
377 static void
gkm_session_init(GkmSession * self)378 gkm_session_init (GkmSession *self)
379 {
380 self->pv = gkm_session_get_instance_private (self);
381 self->pv->objects = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, gkm_util_dispose_unref);
382 self->pv->flags = 0;
383
384 /* Create the store and register attributes */
385 self->pv->store = GKM_STORE (gkm_memory_store_new ());
386 }
387
388 static void
gkm_session_dispose(GObject * obj)389 gkm_session_dispose (GObject *obj)
390 {
391 GkmSession *self = GKM_SESSION (obj);
392
393 /* Cleanup any current operation */
394 if (self->pv->current_operation)
395 (self->pv->current_operation) (self);
396 g_assert (!self->pv->current_operation);
397
398 if (self->pv->module)
399 g_object_unref (self->pv->module);
400 self->pv->module = NULL;
401
402 if (self->pv->credential) {
403 g_object_set_data (G_OBJECT (self->pv->credential), "owned-by-session", NULL);
404 g_object_unref (self->pv->credential);
405 self->pv->credential = NULL;
406 }
407
408 g_hash_table_remove_all (self->pv->objects);
409
410 if (self->pv->manager)
411 g_object_unref (self->pv->manager);
412 self->pv->manager = NULL;
413
414 G_OBJECT_CLASS (gkm_session_parent_class)->dispose (obj);
415 }
416
417 static void
gkm_session_finalize(GObject * obj)418 gkm_session_finalize (GObject *obj)
419 {
420 GkmSession *self = GKM_SESSION (obj);
421
422 g_assert (self->pv->module == NULL);
423 g_assert (self->pv->manager == NULL);
424
425 g_hash_table_destroy (self->pv->objects);
426 self->pv->objects = NULL;
427
428 g_object_unref (self->pv->store);
429 self->pv->store = NULL;
430
431 G_OBJECT_CLASS (gkm_session_parent_class)->finalize (obj);
432 }
433
434 static void
gkm_session_set_property(GObject * obj,guint prop_id,const GValue * value,GParamSpec * pspec)435 gkm_session_set_property (GObject *obj, guint prop_id, const GValue *value,
436 GParamSpec *pspec)
437 {
438 GkmSession *self = GKM_SESSION (obj);
439
440 switch (prop_id) {
441 case PROP_MODULE:
442 g_return_if_fail (!self->pv->module);
443 self->pv->module = g_value_get_object (value);
444 g_return_if_fail (self->pv->module);
445 g_object_ref (self->pv->module);
446 break;
447 case PROP_MANAGER:
448 g_return_if_fail (!self->pv->manager);
449 self->pv->manager = g_value_get_object (value);
450 g_return_if_fail (self->pv->manager);
451 g_object_ref (self->pv->manager);
452 break;
453 case PROP_SLOT_ID:
454 self->pv->slot_id = g_value_get_ulong (value);
455 break;
456 case PROP_APARTMENT:
457 self->pv->apartment = g_value_get_ulong (value);
458 break;
459 case PROP_HANDLE:
460 self->pv->handle = g_value_get_ulong (value);
461 g_return_if_fail (self->pv->handle != 0);
462 break;
463 case PROP_FLAGS:
464 self->pv->flags = g_value_get_ulong (value);
465 break;
466 case PROP_LOGGED_IN:
467 gkm_session_set_logged_in (self, g_value_get_ulong (value));
468 break;
469 default:
470 G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
471 break;
472 }
473 }
474
475 static void
gkm_session_get_property(GObject * obj,guint prop_id,GValue * value,GParamSpec * pspec)476 gkm_session_get_property (GObject *obj, guint prop_id, GValue *value,
477 GParamSpec *pspec)
478 {
479 GkmSession *self = GKM_SESSION (obj);
480
481 switch (prop_id) {
482 case PROP_MODULE:
483 g_value_set_object (value, gkm_session_get_module (self));
484 break;
485 case PROP_MANAGER:
486 g_value_set_object (value, gkm_session_get_manager (self));
487 break;
488 case PROP_SLOT_ID:
489 g_value_set_ulong (value, gkm_session_get_slot_id (self));
490 break;
491 case PROP_APARTMENT:
492 g_value_set_ulong (value, gkm_session_get_apartment (self));
493 break;
494 case PROP_HANDLE:
495 g_value_set_ulong (value, gkm_session_get_handle (self));
496 break;
497 case PROP_FLAGS:
498 g_value_set_ulong (value, self->pv->flags);
499 break;
500 case PROP_LOGGED_IN:
501 g_value_set_ulong (value, gkm_session_get_logged_in (self));
502 break;
503 default:
504 G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
505 break;
506 }
507 }
508
509 static void
gkm_session_class_init(GkmSessionClass * klass)510 gkm_session_class_init (GkmSessionClass *klass)
511 {
512 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
513
514 gobject_class->constructor = gkm_session_constructor;
515 gobject_class->dispose = gkm_session_dispose;
516 gobject_class->finalize = gkm_session_finalize;
517 gobject_class->set_property = gkm_session_set_property;
518 gobject_class->get_property = gkm_session_get_property;
519
520 g_object_class_install_property (gobject_class, PROP_MODULE,
521 g_param_spec_object ("module", "Module", "Module this session belongs to",
522 GKM_TYPE_MODULE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
523
524 g_object_class_install_property (gobject_class, PROP_MANAGER,
525 g_param_spec_object ("manager", "Manager", "Object manager for this session",
526 GKM_TYPE_MANAGER, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
527
528 g_object_class_install_property (gobject_class, PROP_HANDLE,
529 g_param_spec_ulong ("handle", "Handle", "PKCS#11 session handle",
530 0, G_MAXULONG, 0, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
531
532 g_object_class_install_property (gobject_class, PROP_SLOT_ID,
533 g_param_spec_ulong ("slot-id", "Slot ID", "Slot ID this session is opened on",
534 0, G_MAXULONG, 0, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
535
536 g_object_class_install_property (gobject_class, PROP_APARTMENT,
537 g_param_spec_ulong ("apartment", "Apartment", "Apartment this session is opened on",
538 0, G_MAXULONG, 0, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
539
540 g_object_class_install_property(gobject_class, PROP_FLAGS,
541 g_param_spec_ulong ("flags", "Flags", "Flags for the session",
542 0, G_MAXULONG, 0, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
543
544 g_object_class_install_property (gobject_class, PROP_LOGGED_IN,
545 g_param_spec_ulong ("logged-in", "Logged in", "Whether this session is logged in or not",
546 0, G_MAXULONG, CKU_NONE, G_PARAM_READWRITE));
547 }
548
549 /* -----------------------------------------------------------------------------
550 * PUBLIC
551 */
552
553 GkmSession*
gkm_session_for_session_object(GkmObject * obj)554 gkm_session_for_session_object (GkmObject *obj)
555 {
556 g_return_val_if_fail (GKM_IS_OBJECT (obj), NULL);
557 return GKM_SESSION (g_object_get_data (G_OBJECT (obj), "owned-by-session"));
558 }
559
560 CK_SESSION_HANDLE
gkm_session_get_handle(GkmSession * self)561 gkm_session_get_handle (GkmSession *self)
562 {
563 g_return_val_if_fail (GKM_IS_SESSION (self), 0);
564 return self->pv->handle;
565 }
566
567 CK_SLOT_ID
gkm_session_get_slot_id(GkmSession * self)568 gkm_session_get_slot_id (GkmSession *self)
569 {
570 g_return_val_if_fail (GKM_IS_SESSION (self), 0);
571 return self->pv->slot_id;
572 }
573
574 CK_ULONG
gkm_session_get_apartment(GkmSession * self)575 gkm_session_get_apartment (GkmSession *self)
576 {
577 g_return_val_if_fail (GKM_IS_SESSION (self), 0);
578 return self->pv->apartment;
579 }
580
581 GkmModule*
gkm_session_get_module(GkmSession * self)582 gkm_session_get_module (GkmSession *self)
583 {
584 g_return_val_if_fail (GKM_IS_SESSION (self), NULL);
585 g_return_val_if_fail (GKM_IS_MODULE (self->pv->module), NULL);
586 return self->pv->module;
587 }
588
589 GkmManager*
gkm_session_get_manager(GkmSession * self)590 gkm_session_get_manager (GkmSession *self)
591 {
592 g_return_val_if_fail (GKM_IS_SESSION (self), NULL);
593 g_return_val_if_fail (GKM_IS_MANAGER (self->pv->manager), NULL);
594 return self->pv->manager;
595 }
596
597 gulong
gkm_session_get_logged_in(GkmSession * self)598 gkm_session_get_logged_in (GkmSession *self)
599 {
600 g_return_val_if_fail (GKM_IS_SESSION (self), FALSE);
601 return self->pv->logged_in;
602 }
603
604 void
gkm_session_set_logged_in(GkmSession * self,gulong logged_in)605 gkm_session_set_logged_in (GkmSession *self, gulong logged_in)
606 {
607 g_return_if_fail (GKM_IS_SESSION (self));
608 self->pv->logged_in = logged_in;
609 g_object_notify (G_OBJECT (self), "logged-in");
610 }
611
612 gpointer
gkm_session_get_crypto_state(GkmSession * self)613 gkm_session_get_crypto_state (GkmSession *self)
614 {
615 g_return_val_if_fail (GKM_IS_SESSION (self), NULL);
616 return self->pv->crypto_state;
617 }
618
619 void
gkm_session_set_crypto_state(GkmSession * self,gpointer state,GDestroyNotify destroy)620 gkm_session_set_crypto_state (GkmSession *self, gpointer state,
621 GDestroyNotify destroy)
622 {
623 g_return_if_fail (GKM_IS_SESSION (self));
624 if (self->pv->crypto_state != state) {
625 if (self->pv->crypto_state && self->pv->crypto_destroy)
626 (self->pv->crypto_destroy) (self->pv->crypto_state);
627 }
628 self->pv->crypto_state = state;
629 self->pv->crypto_destroy = destroy;
630 }
631
632 gboolean
gkm_session_is_read_only(GkmSession * self)633 gkm_session_is_read_only (GkmSession *self)
634 {
635 g_return_val_if_fail (GKM_IS_SESSION (self), TRUE);
636 return (self->pv->flags & CKF_RW_SESSION) ? FALSE : TRUE;
637 }
638
639 gboolean
gkm_session_is_for_application(GkmSession * self)640 gkm_session_is_for_application (GkmSession *self)
641 {
642 g_return_val_if_fail (GKM_IS_SESSION (self), TRUE);
643 return (self->pv->flags & CKF_G_APPLICATION_SESSION) ? TRUE : FALSE;
644 }
645
646 CK_RV
gkm_session_lookup_readable_object(GkmSession * self,CK_OBJECT_HANDLE handle,GkmObject ** result)647 gkm_session_lookup_readable_object (GkmSession *self, CK_OBJECT_HANDLE handle,
648 GkmObject **result)
649 {
650 return lookup_object_from_handle (self, handle, FALSE, result);
651 }
652
653 CK_RV
gkm_session_lookup_writable_object(GkmSession * self,CK_OBJECT_HANDLE handle,GkmObject ** result)654 gkm_session_lookup_writable_object (GkmSession *self, CK_OBJECT_HANDLE handle,
655 GkmObject **result)
656 {
657 return lookup_object_from_handle (self, handle, TRUE, result);
658 }
659
660 CK_RV
gkm_session_login_context_specific(GkmSession * self,CK_UTF8CHAR_PTR pin,CK_ULONG n_pin)661 gkm_session_login_context_specific (GkmSession *self, CK_UTF8CHAR_PTR pin, CK_ULONG n_pin)
662 {
663 GkmCredential *cred;
664 gboolean always_auth;
665 gboolean is_private;
666 GkmObject *object;
667 CK_RV rv;
668
669 g_return_val_if_fail (GKM_IS_SESSION (self), CKR_GENERAL_ERROR);
670
671 if (!self->pv->current_object)
672 return CKR_OPERATION_NOT_INITIALIZED;
673
674 object = self->pv->current_object;
675 g_return_val_if_fail (GKM_IS_OBJECT (object), CKR_GENERAL_ERROR);
676
677 if (!gkm_object_get_attribute_boolean (object, self, CKA_ALWAYS_AUTHENTICATE, &always_auth))
678 always_auth = FALSE;
679 if (!gkm_object_get_attribute_boolean (object, self, CKA_PRIVATE, &is_private))
680 is_private = FALSE;
681
682 /* A strange code, but that's what the spec says */
683 if (always_auth == FALSE)
684 return CKR_OPERATION_NOT_INITIALIZED;
685
686 /* Double check that the object has what it takes */
687 g_return_val_if_fail (is_private == TRUE, CKR_GENERAL_ERROR);
688
689 /* Now create the strange object */
690 rv = gkm_credential_create (self->pv->module, self->pv->manager,
691 self->pv->current_object, pin, n_pin, &cred);
692 if (rv != CKR_OK)
693 return rv;
694
695 if (self->pv->credential)
696 g_object_unref (self->pv->credential);
697 g_object_set_data (G_OBJECT (cred), "owned-by-session", self);
698 self->pv->credential = cred;
699
700 return CKR_OK;
701 }
702
703 void
gkm_session_add_session_object(GkmSession * self,GkmTransaction * transaction,GkmObject * obj)704 gkm_session_add_session_object (GkmSession *self, GkmTransaction *transaction,
705 GkmObject *obj)
706 {
707 g_return_if_fail (GKM_IS_SESSION (self));
708 g_return_if_fail (gkm_session_for_session_object (obj) == NULL);
709
710 if (transaction) {
711 g_return_if_fail (GKM_IS_TRANSACTION (transaction));
712 g_return_if_fail (!gkm_transaction_get_failed (transaction));
713 }
714
715 add_object (self, transaction, obj);
716 }
717
718 void
gkm_session_destroy_session_object(GkmSession * self,GkmTransaction * transaction,GkmObject * obj)719 gkm_session_destroy_session_object (GkmSession *self, GkmTransaction *transaction,
720 GkmObject *obj)
721 {
722 g_return_if_fail (GKM_IS_SESSION (self));
723 g_return_if_fail (gkm_session_for_session_object (obj) == self);
724
725 if (transaction) {
726 g_return_if_fail (GKM_IS_TRANSACTION (transaction));
727 g_return_if_fail (!gkm_transaction_get_failed (transaction));
728 }
729
730 /* Don't actually destroy the credential */
731 if (self->pv->credential && GKM_OBJECT (self->pv->credential) == obj)
732 return;
733
734 remove_object (self, transaction, obj);
735 }
736
737 GkmCredential*
gkm_session_get_credential(GkmSession * self)738 gkm_session_get_credential (GkmSession *self)
739 {
740 g_return_val_if_fail (GKM_IS_SESSION (self), NULL);
741 return self->pv->credential;
742 }
743
744 GkmObject*
gkm_session_create_object_for_factory(GkmSession * self,GkmFactory * factory,GkmTransaction * transaction,CK_ATTRIBUTE_PTR template,CK_ULONG count)745 gkm_session_create_object_for_factory (GkmSession *self, GkmFactory *factory,
746 GkmTransaction *transaction,
747 CK_ATTRIBUTE_PTR template, CK_ULONG count)
748 {
749 GkmTransaction *owned = NULL;
750 GkmObject *object;
751 gboolean token;
752
753 g_return_val_if_fail (GKM_IS_SESSION (self), NULL);
754 g_return_val_if_fail (factory && factory->func, NULL);
755 g_return_val_if_fail (template || !count, NULL);
756
757 /* The transaction for this whole dealio */
758 if (!transaction)
759 owned = transaction = gkm_transaction_new ();
760
761 g_return_val_if_fail (GKM_IS_TRANSACTION (transaction), NULL);
762
763 /* Refresh the module if storing on the token */
764 if (gkm_attributes_find_boolean (template, count, CKA_TOKEN, &token) && token)
765 gkm_module_refresh_token (self->pv->module);
766
767 /*
768 * Duplicate the memory for the attributes (but not values) so we
769 * can 'consume' in the factory function
770 */
771 template = g_memdup (template, count * sizeof (CK_ATTRIBUTE));
772
773 /* Actually create the object */
774 object = (factory->func) (self, transaction, template, count);
775
776 /* A NULL result without a failure code, bad */
777 if (object == NULL && !gkm_transaction_get_failed (transaction)) {
778 g_warn_if_reached ();
779 gkm_transaction_fail (transaction, CKR_GENERAL_ERROR);
780 }
781
782 g_free (template);
783
784 if (owned)
785 gkm_transaction_complete (transaction);
786
787 /* Object is owned by module or session */
788 if (gkm_transaction_get_failed (transaction)) {
789 if (object)
790 g_object_unref (object);
791 object = NULL;
792 }
793
794 if (owned)
795 g_object_unref (owned);
796
797 return object;
798 }
799
800 GkmObject*
gkm_session_create_object_for_attributes(GkmSession * self,GkmTransaction * transaction,CK_ATTRIBUTE_PTR attrs,CK_ULONG n_attrs)801 gkm_session_create_object_for_attributes (GkmSession *self, GkmTransaction *transaction,
802 CK_ATTRIBUTE_PTR attrs, CK_ULONG n_attrs)
803 {
804 GkmFactory *factory;
805
806 g_return_val_if_fail (GKM_IS_SESSION (self), NULL);
807
808 /* Find out if we can create such an object */
809 factory = gkm_module_find_factory (gkm_session_get_module (self), attrs, n_attrs);
810 if (factory == NULL) {
811 if (transaction)
812 gkm_transaction_fail (transaction, CKR_TEMPLATE_INCOMPLETE);
813 return NULL;
814 }
815
816 return gkm_session_create_object_for_factory (self, factory, transaction, attrs, n_attrs);
817 }
818
819 void
gkm_session_complete_object_creation(GkmSession * self,GkmTransaction * transaction,GkmObject * object,gboolean add,CK_ATTRIBUTE_PTR attrs,CK_ULONG n_attrs)820 gkm_session_complete_object_creation (GkmSession *self, GkmTransaction *transaction, GkmObject *object,
821 gboolean add, CK_ATTRIBUTE_PTR attrs, CK_ULONG n_attrs)
822 {
823 gboolean is_private;
824 gulong i;
825
826 g_return_if_fail (GKM_IS_SESSION (self));
827 g_return_if_fail (GKM_IS_OBJECT (object));
828 g_return_if_fail (GKM_IS_TRANSACTION (transaction));
829 g_return_if_fail (!gkm_transaction_get_failed (transaction));
830
831 gkm_object_create_attributes (object, self, transaction, attrs, n_attrs);
832 if (gkm_transaction_get_failed (transaction))
833 return;
834
835 /* See if we can create due to read-only */
836 if (gkm_object_is_token (object)) {
837 if (!gkm_object_is_transient (object) &&
838 gkm_module_get_write_protected (self->pv->module)) {
839 gkm_transaction_fail (transaction, CKR_TOKEN_WRITE_PROTECTED);
840 return;
841 }
842 else if (gkm_session_is_read_only (self)) {
843 gkm_transaction_fail (transaction, CKR_SESSION_READ_ONLY);
844 return;
845 }
846 }
847
848 /* Can only create public objects unless logged in */
849 if (gkm_session_get_logged_in (self) != CKU_USER &&
850 gkm_object_get_attribute_boolean (object, self, CKA_PRIVATE, &is_private) &&
851 is_private == TRUE) {
852 gkm_transaction_fail (transaction, CKR_USER_NOT_LOGGED_IN);
853 return;
854 }
855
856 /* Add the object to session or token */
857 if (add && !gkm_transaction_get_failed (transaction)) {
858 if (gkm_object_is_token (object))
859 gkm_module_add_token_object (self->pv->module, transaction, object);
860 else
861 add_object (self, transaction, object);
862 }
863
864 /* Next go through and set all attributes that weren't used initially */
865 gkm_attributes_consume (attrs, n_attrs, CKA_TOKEN, G_MAXULONG);
866 for (i = 0; i < n_attrs && !gkm_transaction_get_failed (transaction); ++i) {
867 if (!gkm_attribute_consumed (&attrs[i]))
868 gkm_object_set_attribute (object, self, transaction, &attrs[i]);
869 }
870
871 /* Store the object */
872 if (!gkm_transaction_get_failed (transaction)) {
873 if (gkm_object_is_token (object))
874 gkm_module_store_token_object (self->pv->module, transaction, object);
875 }
876 }
877
878 /* -----------------------------------------------------------------------------
879 * PKCS#11
880 */
881
882 CK_RV
gkm_session_C_GetFunctionStatus(GkmSession * self)883 gkm_session_C_GetFunctionStatus (GkmSession *self)
884 {
885 g_return_val_if_fail (GKM_IS_SESSION (self), CKR_SESSION_HANDLE_INVALID);
886 return CKR_FUNCTION_NOT_PARALLEL;
887 }
888
889 CK_RV
gkm_session_C_CancelFunction(GkmSession * self)890 gkm_session_C_CancelFunction (GkmSession *self)
891 {
892 g_return_val_if_fail (GKM_IS_SESSION (self), CKR_SESSION_HANDLE_INVALID);
893 return CKR_FUNCTION_NOT_PARALLEL;
894 }
895
896 CK_RV
gkm_session_C_GetSessionInfo(GkmSession * self,CK_SESSION_INFO_PTR info)897 gkm_session_C_GetSessionInfo(GkmSession* self, CK_SESSION_INFO_PTR info)
898 {
899 g_return_val_if_fail (GKM_IS_SESSION (self), CKR_SESSION_HANDLE_INVALID);
900 if (!info)
901 return CKR_ARGUMENTS_BAD;
902
903 info->slotID = self->pv->slot_id;
904 if (self->pv->logged_in == CKU_USER)
905 info->state = gkm_session_is_read_only (self) ? CKS_RO_USER_FUNCTIONS : CKS_RW_USER_FUNCTIONS;
906 else if (self->pv->logged_in == CKU_SO)
907 info->state = CKS_RW_SO_FUNCTIONS;
908 else
909 info->state = gkm_session_is_read_only (self) ? CKS_RO_PUBLIC_SESSION : CKS_RW_PUBLIC_SESSION;
910 info->flags = CKF_SERIAL_SESSION | self->pv->flags;
911 info->ulDeviceError = 0;
912
913 return CKR_OK;
914 }
915
916 CK_RV
gkm_session_C_GetOperationState(GkmSession * self,CK_BYTE_PTR operation_state,CK_ULONG_PTR operation_state_len)917 gkm_session_C_GetOperationState (GkmSession* self, CK_BYTE_PTR operation_state,
918 CK_ULONG_PTR operation_state_len)
919 {
920 /* Nope, We don't bend that way */
921 return CKR_FUNCTION_NOT_SUPPORTED;
922 }
923
924 CK_RV
gkm_session_C_SetOperationState(GkmSession * self,CK_BYTE_PTR operation_state,CK_ULONG operation_state_len,CK_OBJECT_HANDLE encryption_key,CK_OBJECT_HANDLE authentication_key)925 gkm_session_C_SetOperationState (GkmSession* self, CK_BYTE_PTR operation_state,
926 CK_ULONG operation_state_len, CK_OBJECT_HANDLE encryption_key,
927 CK_OBJECT_HANDLE authentication_key)
928 {
929 /* Nope. We don't bend that way */
930 return CKR_FUNCTION_NOT_SUPPORTED;
931 }
932
933 CK_RV
gkm_session_C_CreateObject(GkmSession * self,CK_ATTRIBUTE_PTR template,CK_ULONG count,CK_OBJECT_HANDLE_PTR new_object)934 gkm_session_C_CreateObject (GkmSession* self, CK_ATTRIBUTE_PTR template,
935 CK_ULONG count, CK_OBJECT_HANDLE_PTR new_object)
936 {
937 GkmObject *object = NULL;
938 CK_OBJECT_HANDLE handle;
939 GkmTransaction *transaction;
940 CK_RV rv;
941
942 g_return_val_if_fail (GKM_IS_SESSION (self), CKR_SESSION_HANDLE_INVALID);
943 if (!new_object)
944 return CKR_ARGUMENTS_BAD;
945 if (!(!count || template))
946 return CKR_ARGUMENTS_BAD;
947
948 transaction = gkm_transaction_new ();
949
950 object = gkm_session_create_object_for_attributes (self, transaction, template, count);
951
952 rv = gkm_transaction_complete_and_unref (transaction);
953
954 if (rv == CKR_OK) {
955 g_assert (object);
956 handle = gkm_object_get_handle (object);
957 if (handle == 0) {
958 g_warning ("an object was not properly exposed its owner");
959 rv = CKR_GENERAL_ERROR;
960 } else {
961 *new_object = handle;
962 }
963 g_object_unref (object);
964 }
965
966 return rv;
967 }
968
969 CK_RV
gkm_session_C_CopyObject(GkmSession * self,CK_OBJECT_HANDLE object,CK_ATTRIBUTE_PTR template,CK_ULONG count,CK_OBJECT_HANDLE_PTR new_object)970 gkm_session_C_CopyObject (GkmSession* self, CK_OBJECT_HANDLE object,
971 CK_ATTRIBUTE_PTR template, CK_ULONG count,
972 CK_OBJECT_HANDLE_PTR new_object)
973 {
974 /*
975 * TODO: We need to implement this, initially perhaps only
976 * only for session objects.
977 */
978 return CKR_FUNCTION_NOT_SUPPORTED;
979 }
980
981 CK_RV
gkm_session_C_GetObjectSize(GkmSession * self,CK_OBJECT_HANDLE object,CK_ULONG_PTR size)982 gkm_session_C_GetObjectSize (GkmSession* self, CK_OBJECT_HANDLE object, CK_ULONG_PTR size)
983 {
984 /* TODO: Do we need to implement this? */
985 return CKR_FUNCTION_NOT_SUPPORTED;
986 }
987
988 CK_RV
gkm_session_C_GetAttributeValue(GkmSession * self,CK_OBJECT_HANDLE handle,CK_ATTRIBUTE_PTR template,CK_ULONG count)989 gkm_session_C_GetAttributeValue (GkmSession* self, CK_OBJECT_HANDLE handle,
990 CK_ATTRIBUTE_PTR template, CK_ULONG count)
991 {
992 GkmObject *object;
993 CK_ULONG i;
994 CK_RV code, rv;
995
996 g_return_val_if_fail (GKM_IS_SESSION (self), CKR_SESSION_HANDLE_INVALID);
997 if (!(!count || template))
998 return CKR_ARGUMENTS_BAD;
999
1000 rv = gkm_session_lookup_readable_object (self, handle, &object);
1001 if (rv != CKR_OK)
1002 return rv;
1003
1004 rv = CKR_OK;
1005
1006 for (i = 0; i < count; ++i) {
1007 code = gkm_object_get_attribute (object, self, &template[i]);
1008
1009 /* Not a true error, keep going */
1010 if (code == CKR_ATTRIBUTE_SENSITIVE ||
1011 code == CKR_ATTRIBUTE_TYPE_INVALID) {
1012 template[i].ulValueLen = (CK_ULONG)-1;
1013 rv = code;
1014
1015 } else if(code == CKR_BUFFER_TOO_SMALL) {
1016 rv = code;
1017
1018 /* Any other error aborts */
1019 } else if (code != CKR_OK) {
1020 rv = code;
1021 break;
1022 }
1023 }
1024
1025 return rv;
1026 }
1027
1028 CK_RV
gkm_session_C_SetAttributeValue(GkmSession * self,CK_OBJECT_HANDLE handle,CK_ATTRIBUTE_PTR template,CK_ULONG count)1029 gkm_session_C_SetAttributeValue (GkmSession* self, CK_OBJECT_HANDLE handle,
1030 CK_ATTRIBUTE_PTR template, CK_ULONG count)
1031 {
1032 GkmObject *object = NULL;
1033 GkmTransaction *transaction;
1034 CK_ULONG i;
1035 CK_RV rv;
1036
1037 g_return_val_if_fail (GKM_IS_SESSION (self), CKR_SESSION_HANDLE_INVALID);
1038 if (!(!count || template))
1039 return CKR_ARGUMENTS_BAD;
1040
1041 rv = gkm_session_lookup_writable_object (self, handle, &object);
1042 if (rv != CKR_OK)
1043 return rv;
1044
1045 /* The transaction for this whole dealio */
1046 transaction = gkm_transaction_new ();
1047
1048 for (i = 0; i < count && !gkm_transaction_get_failed (transaction); ++i)
1049 gkm_object_set_attribute (object, self, transaction, &template[i]);
1050
1051 /* Store the object */
1052 if (!gkm_transaction_get_failed (transaction) && gkm_object_is_token (object))
1053 gkm_module_store_token_object (self->pv->module, transaction, object);
1054
1055 gkm_transaction_complete (transaction);
1056 rv = gkm_transaction_get_result (transaction);
1057 g_object_unref (transaction);
1058
1059 return rv;
1060 }
1061
1062 CK_RV
gkm_session_C_DestroyObject(GkmSession * self,CK_OBJECT_HANDLE handle)1063 gkm_session_C_DestroyObject (GkmSession* self, CK_OBJECT_HANDLE handle)
1064 {
1065 GkmObject *object;
1066 GkmSession *session;
1067 GkmTransaction *transaction;
1068 CK_RV rv;
1069
1070 g_return_val_if_fail (GKM_IS_SESSION (self), CKR_SESSION_HANDLE_INVALID);
1071
1072 rv = gkm_session_lookup_writable_object (self, handle, &object);
1073 if (rv != CKR_OK)
1074 return rv;
1075
1076 transaction = gkm_transaction_new ();
1077
1078 /* Lookup the actual session that owns this object, if no session, then a token object */
1079 session = gkm_session_for_session_object (object);
1080 if (session != NULL)
1081 remove_object (session, transaction, object);
1082 else
1083 gkm_module_remove_token_object (self->pv->module, transaction, object);
1084
1085 gkm_transaction_complete (transaction);
1086 rv = gkm_transaction_get_result (transaction);
1087 g_object_unref (transaction);
1088
1089 if (rv == CKR_OK) {
1090 /* Check that it's really gone */
1091 g_return_val_if_fail (gkm_session_lookup_readable_object (self, handle, &object) ==
1092 CKR_OBJECT_HANDLE_INVALID, CKR_GENERAL_ERROR);
1093 }
1094
1095 return rv;
1096 }
1097
1098 CK_RV
gkm_session_C_FindObjectsInit(GkmSession * self,CK_ATTRIBUTE_PTR template,CK_ULONG count)1099 gkm_session_C_FindObjectsInit (GkmSession* self, CK_ATTRIBUTE_PTR template,
1100 CK_ULONG count)
1101 {
1102 gboolean token = FALSE;
1103 gboolean also_private;
1104 CK_RV rv = CKR_OK;
1105 GArray *found;
1106 gboolean all;
1107
1108 g_return_val_if_fail (GKM_IS_SESSION (self), CKR_SESSION_HANDLE_INVALID);
1109 if (!(template || !count))
1110 return CKR_ARGUMENTS_BAD;
1111
1112 /* Cancel any current operation */
1113 if (self->pv->current_operation) {
1114 (self->pv->current_operation) (self);
1115 g_assert (!self->pv->current_operation);
1116 }
1117
1118 /* See whether this is token or not */
1119 all = !gkm_attributes_find_boolean (template, count, CKA_TOKEN, &token);
1120
1121 /* An array of object handles */
1122 found = g_array_new (FALSE, TRUE, sizeof (CK_OBJECT_HANDLE));
1123
1124 /* If not logged in, then skip private objects */
1125 also_private = gkm_session_get_logged_in (self) == CKU_USER;
1126
1127 if (all || token) {
1128 rv = gkm_module_refresh_token (self->pv->module);
1129 if (rv == CKR_OK)
1130 rv = gkm_manager_find_handles (gkm_module_get_manager (self->pv->module),
1131 self, also_private, template, count, found);
1132 }
1133
1134 if (rv == CKR_OK && (all || !token)) {
1135 rv = gkm_manager_find_handles (self->pv->manager, self, also_private,
1136 template, count, found);
1137 }
1138
1139 if (rv != CKR_OK) {
1140 g_array_free (found, TRUE);
1141 return rv;
1142 }
1143
1144 g_assert (!self->pv->current_operation);
1145 g_assert (!self->pv->found_objects);
1146
1147 self->pv->found_objects = found;
1148 self->pv->current_operation = cleanup_found;
1149
1150 return CKR_OK;
1151 }
1152
1153 CK_RV
gkm_session_C_FindObjects(GkmSession * self,CK_OBJECT_HANDLE_PTR objects,CK_ULONG max_count,CK_ULONG_PTR count)1154 gkm_session_C_FindObjects (GkmSession* self, CK_OBJECT_HANDLE_PTR objects,
1155 CK_ULONG max_count, CK_ULONG_PTR count)
1156 {
1157 CK_ULONG n_objects, i;
1158 GArray *found;
1159
1160 g_return_val_if_fail (GKM_IS_SESSION (self), CKR_SESSION_HANDLE_INVALID);
1161 if (!(objects || !max_count))
1162 return CKR_ARGUMENTS_BAD;
1163 if (!count)
1164 return CKR_ARGUMENTS_BAD;
1165
1166 if (self->pv->current_operation != cleanup_found)
1167 return CKR_OPERATION_NOT_INITIALIZED;
1168
1169 g_assert (self->pv->found_objects);
1170 found = self->pv->found_objects;
1171
1172 n_objects = MIN (max_count, found->len);
1173 if (n_objects > 0) {
1174 for (i = 0; i < n_objects; ++i)
1175 objects[i] = g_array_index (found, CK_OBJECT_HANDLE, i);
1176 g_array_remove_range (found, 0, n_objects);
1177 }
1178
1179 *count = n_objects;
1180 return CKR_OK;
1181
1182 }
1183
1184 CK_RV
gkm_session_C_FindObjectsFinal(GkmSession * self)1185 gkm_session_C_FindObjectsFinal (GkmSession* self)
1186 {
1187 g_return_val_if_fail (GKM_IS_SESSION (self), CKR_SESSION_HANDLE_INVALID);
1188
1189 if (self->pv->current_operation != cleanup_found)
1190 return CKR_OPERATION_NOT_INITIALIZED;
1191
1192 cleanup_found (self);
1193 return CKR_OK;
1194 }
1195
1196 CK_RV
gkm_session_C_EncryptInit(GkmSession * self,CK_MECHANISM_PTR mechanism,CK_OBJECT_HANDLE key)1197 gkm_session_C_EncryptInit (GkmSession *self, CK_MECHANISM_PTR mechanism,
1198 CK_OBJECT_HANDLE key)
1199 {
1200 g_return_val_if_fail (GKM_IS_SESSION (self), CKR_SESSION_HANDLE_INVALID);
1201 if (!mechanism)
1202 return CKR_ARGUMENTS_BAD;
1203 return prepare_crypto (self, mechanism, CKA_ENCRYPT, key);
1204 }
1205
1206 CK_RV
gkm_session_C_Encrypt(GkmSession * self,CK_BYTE_PTR data,CK_ULONG data_len,CK_BYTE_PTR encrypted_data,CK_ULONG_PTR encrypted_data_len)1207 gkm_session_C_Encrypt (GkmSession *self, CK_BYTE_PTR data, CK_ULONG data_len,
1208 CK_BYTE_PTR encrypted_data, CK_ULONG_PTR encrypted_data_len)
1209 {
1210 g_return_val_if_fail (GKM_IS_SESSION (self), CKR_SESSION_HANDLE_INVALID);
1211 return process_crypto (self, CKA_ENCRYPT, data, data_len, encrypted_data, encrypted_data_len);
1212 }
1213
1214 CK_RV
gkm_session_C_EncryptUpdate(GkmSession * self,CK_BYTE_PTR part,CK_ULONG part_len,CK_BYTE_PTR encrypted_part,CK_ULONG_PTR encrypted_part_len)1215 gkm_session_C_EncryptUpdate (GkmSession *self, CK_BYTE_PTR part,
1216 CK_ULONG part_len, CK_BYTE_PTR encrypted_part,
1217 CK_ULONG_PTR encrypted_part_len)
1218 {
1219 /* Our keys don't support this incremental encryption */
1220 return CKR_FUNCTION_NOT_SUPPORTED;
1221 }
1222
1223 CK_RV
gkm_session_C_EncryptFinal(GkmSession * self,CK_BYTE_PTR last_part,CK_ULONG_PTR last_part_len)1224 gkm_session_C_EncryptFinal (GkmSession *self, CK_BYTE_PTR last_part,
1225 CK_ULONG_PTR last_part_len)
1226 {
1227 /* Our keys don't support this incremental encryption */
1228 return CKR_FUNCTION_NOT_SUPPORTED;
1229 }
1230
1231 CK_RV
gkm_session_C_DecryptInit(GkmSession * self,CK_MECHANISM_PTR mechanism,CK_OBJECT_HANDLE key)1232 gkm_session_C_DecryptInit (GkmSession *self, CK_MECHANISM_PTR mechanism,
1233 CK_OBJECT_HANDLE key)
1234 {
1235 g_return_val_if_fail (GKM_IS_SESSION (self), CKR_SESSION_HANDLE_INVALID);
1236 if (!mechanism)
1237 return CKR_ARGUMENTS_BAD;
1238 return prepare_crypto (self, mechanism, CKA_DECRYPT, key);
1239 }
1240
1241 CK_RV
gkm_session_C_Decrypt(GkmSession * self,CK_BYTE_PTR enc_data,CK_ULONG enc_data_len,CK_BYTE_PTR data,CK_ULONG_PTR data_len)1242 gkm_session_C_Decrypt (GkmSession *self, CK_BYTE_PTR enc_data,
1243 CK_ULONG enc_data_len, CK_BYTE_PTR data, CK_ULONG_PTR data_len)
1244 {
1245 g_return_val_if_fail (GKM_IS_SESSION (self), CKR_SESSION_HANDLE_INVALID);
1246 return process_crypto (self, CKA_DECRYPT, enc_data, enc_data_len, data, data_len);
1247 }
1248
1249 CK_RV
gkm_session_C_DecryptUpdate(GkmSession * self,CK_BYTE_PTR enc_part,CK_ULONG enc_part_len,CK_BYTE_PTR part,CK_ULONG_PTR part_len)1250 gkm_session_C_DecryptUpdate (GkmSession *self, CK_BYTE_PTR enc_part,
1251 CK_ULONG enc_part_len, CK_BYTE_PTR part, CK_ULONG_PTR part_len)
1252 {
1253 /* Our keys don't support this incremental decryption */
1254 return CKR_FUNCTION_NOT_SUPPORTED;
1255 }
1256
1257 CK_RV
gkm_session_C_DecryptFinal(GkmSession * self,CK_BYTE_PTR last_part,CK_ULONG_PTR last_part_len)1258 gkm_session_C_DecryptFinal (GkmSession *self, CK_BYTE_PTR last_part,
1259 CK_ULONG_PTR last_part_len)
1260 {
1261 /* Our keys don't support this incremental decryption */
1262 return CKR_FUNCTION_NOT_SUPPORTED;
1263 }
1264
1265 CK_RV
gkm_session_C_DigestInit(GkmSession * self,CK_MECHANISM_PTR mechanism)1266 gkm_session_C_DigestInit (GkmSession *self, CK_MECHANISM_PTR mechanism)
1267 {
1268 /* We don't do digests */
1269 return CKR_FUNCTION_NOT_SUPPORTED;
1270 }
1271
1272 CK_RV
gkm_session_C_Digest(GkmSession * self,CK_BYTE_PTR data,CK_ULONG data_len,CK_BYTE_PTR digest,CK_ULONG_PTR digest_len)1273 gkm_session_C_Digest (GkmSession *self, CK_BYTE_PTR data, CK_ULONG data_len,
1274 CK_BYTE_PTR digest, CK_ULONG_PTR digest_len)
1275 {
1276 /* We don't do digests */
1277 return CKR_FUNCTION_NOT_SUPPORTED;
1278 }
1279
1280 CK_RV
gkm_session_C_DigestUpdate(GkmSession * self,CK_BYTE_PTR part,CK_ULONG part_len)1281 gkm_session_C_DigestUpdate (GkmSession *self, CK_BYTE_PTR part, CK_ULONG part_len)
1282 {
1283 /* We don't do digests */
1284 return CKR_FUNCTION_NOT_SUPPORTED;
1285 }
1286
1287 CK_RV
gkm_session_C_DigestKey(GkmSession * self,CK_OBJECT_HANDLE key)1288 gkm_session_C_DigestKey (GkmSession *self, CK_OBJECT_HANDLE key)
1289 {
1290 /* We don't do digests */
1291 return CKR_FUNCTION_NOT_SUPPORTED;
1292 }
1293
1294 CK_RV
gkm_session_C_DigestFinal(GkmSession * self,CK_BYTE_PTR digest,CK_ULONG_PTR digest_len)1295 gkm_session_C_DigestFinal (GkmSession *self, CK_BYTE_PTR digest,
1296 CK_ULONG_PTR digest_len)
1297 {
1298 /* We don't do digests */
1299 return CKR_FUNCTION_NOT_SUPPORTED;
1300 }
1301
1302 CK_RV
gkm_session_C_SignInit(GkmSession * self,CK_MECHANISM_PTR mechanism,CK_OBJECT_HANDLE key)1303 gkm_session_C_SignInit (GkmSession *self, CK_MECHANISM_PTR mechanism,
1304 CK_OBJECT_HANDLE key)
1305 {
1306 g_return_val_if_fail (GKM_IS_SESSION (self), CKR_SESSION_HANDLE_INVALID);
1307 if (!mechanism)
1308 return CKR_ARGUMENTS_BAD;
1309 return prepare_crypto (self, mechanism, CKA_SIGN, key);
1310 }
1311
1312 CK_RV
gkm_session_C_Sign(GkmSession * self,CK_BYTE_PTR data,CK_ULONG data_len,CK_BYTE_PTR signature,CK_ULONG_PTR signature_len)1313 gkm_session_C_Sign (GkmSession *self, CK_BYTE_PTR data, CK_ULONG data_len,
1314 CK_BYTE_PTR signature, CK_ULONG_PTR signature_len)
1315 {
1316 g_return_val_if_fail (GKM_IS_SESSION (self), CKR_SESSION_HANDLE_INVALID);
1317 return process_crypto (self, CKA_SIGN, data, data_len, signature, signature_len);
1318 }
1319
1320 CK_RV
gkm_session_C_SignUpdate(GkmSession * self,CK_BYTE_PTR part,CK_ULONG part_len)1321 gkm_session_C_SignUpdate (GkmSession *self, CK_BYTE_PTR part, CK_ULONG part_len)
1322 {
1323 /* Our keys don't support incremental operations */
1324 return CKR_FUNCTION_NOT_SUPPORTED;
1325 }
1326
1327 CK_RV
gkm_session_C_SignFinal(GkmSession * self,CK_BYTE_PTR signature,CK_ULONG_PTR signature_len)1328 gkm_session_C_SignFinal (GkmSession *self, CK_BYTE_PTR signature,
1329 CK_ULONG_PTR signature_len)
1330 {
1331 /* Our keys don't support incremental operations */
1332 return CKR_FUNCTION_NOT_SUPPORTED;
1333 }
1334
1335 CK_RV
gkm_session_C_SignRecoverInit(GkmSession * self,CK_MECHANISM_PTR mechanism,CK_OBJECT_HANDLE key)1336 gkm_session_C_SignRecoverInit (GkmSession *self, CK_MECHANISM_PTR mechanism,
1337 CK_OBJECT_HANDLE key)
1338 {
1339 /* TODO: Need to implement */
1340 return CKR_FUNCTION_NOT_SUPPORTED;
1341 }
1342
1343 CK_RV
gkm_session_C_SignRecover(GkmSession * self,CK_BYTE_PTR data,CK_ULONG data_len,CK_BYTE_PTR signature,CK_ULONG_PTR signature_len)1344 gkm_session_C_SignRecover (GkmSession *self, CK_BYTE_PTR data, CK_ULONG data_len,
1345 CK_BYTE_PTR signature, CK_ULONG_PTR signature_len)
1346 {
1347 /* TODO: Need to implement */
1348 return CKR_FUNCTION_NOT_SUPPORTED;
1349 }
1350
1351 CK_RV
gkm_session_C_VerifyInit(GkmSession * self,CK_MECHANISM_PTR mechanism,CK_OBJECT_HANDLE key)1352 gkm_session_C_VerifyInit (GkmSession *self, CK_MECHANISM_PTR mechanism,
1353 CK_OBJECT_HANDLE key)
1354 {
1355 g_return_val_if_fail (GKM_IS_SESSION (self), CKR_SESSION_HANDLE_INVALID);
1356 if (!mechanism)
1357 return CKR_ARGUMENTS_BAD;
1358 return prepare_crypto (self, mechanism, CKA_VERIFY, key);
1359 }
1360
1361 CK_RV
gkm_session_C_Verify(GkmSession * self,CK_BYTE_PTR data,CK_ULONG data_len,CK_BYTE_PTR signature,CK_ULONG signature_len)1362 gkm_session_C_Verify (GkmSession *self, CK_BYTE_PTR data, CK_ULONG data_len,
1363 CK_BYTE_PTR signature, CK_ULONG signature_len)
1364 {
1365 g_return_val_if_fail (GKM_IS_SESSION (self), CKR_SESSION_HANDLE_INVALID);
1366 return process_crypto (self, CKA_VERIFY, data, data_len, signature, &signature_len);
1367 }
1368
1369 CK_RV
gkm_session_C_VerifyUpdate(GkmSession * self,CK_BYTE_PTR part,CK_ULONG part_len)1370 gkm_session_C_VerifyUpdate (GkmSession *self, CK_BYTE_PTR part, CK_ULONG part_len)
1371 {
1372 /* Our keys don't support incremental operations */
1373 return CKR_FUNCTION_NOT_SUPPORTED;
1374 }
1375
1376 CK_RV
gkm_session_C_VerifyFinal(GkmSession * self,CK_BYTE_PTR signature,CK_ULONG signature_len)1377 gkm_session_C_VerifyFinal (GkmSession *self, CK_BYTE_PTR signature,
1378 CK_ULONG signature_len)
1379 {
1380 /* Our keys don't support incremental operations */
1381 return CKR_FUNCTION_NOT_SUPPORTED;
1382 }
1383
1384 CK_RV
gkm_session_C_VerifyRecoverInit(GkmSession * self,CK_MECHANISM_PTR mechanism,CK_OBJECT_HANDLE key)1385 gkm_session_C_VerifyRecoverInit (GkmSession *self, CK_MECHANISM_PTR mechanism,
1386 CK_OBJECT_HANDLE key)
1387 {
1388 /* TODO: Need to implement */
1389 return CKR_FUNCTION_NOT_SUPPORTED;
1390 }
1391
1392 CK_RV
gkm_session_C_VerifyRecover(GkmSession * self,CK_BYTE_PTR signature,CK_ULONG signature_len,CK_BYTE_PTR data,CK_ULONG_PTR data_len)1393 gkm_session_C_VerifyRecover (GkmSession *self, CK_BYTE_PTR signature,
1394 CK_ULONG signature_len, CK_BYTE_PTR data,
1395 CK_ULONG_PTR data_len)
1396 {
1397 /* TODO: Need to implement */
1398 return CKR_FUNCTION_NOT_SUPPORTED;
1399 }
1400
1401 CK_RV
gkm_session_C_DigestEncryptUpdate(GkmSession * self,CK_BYTE_PTR part,CK_ULONG part_len,CK_BYTE_PTR enc_part,CK_ULONG_PTR enc_part_len)1402 gkm_session_C_DigestEncryptUpdate (GkmSession *self, CK_BYTE_PTR part,
1403 CK_ULONG part_len, CK_BYTE_PTR enc_part,
1404 CK_ULONG_PTR enc_part_len)
1405 {
1406 /* We don't support double operations */
1407 return CKR_FUNCTION_NOT_SUPPORTED;
1408 }
1409
1410 CK_RV
gkm_session_C_DecryptDigestUpdate(GkmSession * self,CK_BYTE_PTR enc_part,CK_ULONG enc_part_len,CK_BYTE_PTR part,CK_ULONG_PTR part_len)1411 gkm_session_C_DecryptDigestUpdate (GkmSession *self, CK_BYTE_PTR enc_part,
1412 CK_ULONG enc_part_len, CK_BYTE_PTR part,
1413 CK_ULONG_PTR part_len)
1414 {
1415 /* We don't support double operations */
1416 return CKR_FUNCTION_NOT_SUPPORTED;
1417 }
1418
1419 CK_RV
gkm_session_C_SignEncryptUpdate(GkmSession * self,CK_BYTE_PTR part,CK_ULONG part_len,CK_BYTE_PTR enc_part,CK_ULONG_PTR enc_part_len)1420 gkm_session_C_SignEncryptUpdate (GkmSession *self, CK_BYTE_PTR part,
1421 CK_ULONG part_len, CK_BYTE_PTR enc_part,
1422 CK_ULONG_PTR enc_part_len)
1423 {
1424 /* We don't support double operations */
1425 return CKR_FUNCTION_NOT_SUPPORTED;
1426 }
1427
1428 CK_RV
gkm_session_C_DecryptVerifyUpdate(GkmSession * self,CK_BYTE_PTR enc_part,CK_ULONG enc_part_len,CK_BYTE_PTR part,CK_ULONG_PTR part_len)1429 gkm_session_C_DecryptVerifyUpdate (GkmSession *self, CK_BYTE_PTR enc_part,
1430 CK_ULONG enc_part_len, CK_BYTE_PTR part,
1431 CK_ULONG_PTR part_len)
1432 {
1433 /* We don't support double operations */
1434 return CKR_FUNCTION_NOT_SUPPORTED;
1435 }
1436
1437 CK_RV
gkm_session_C_GenerateKey(GkmSession * self,CK_MECHANISM_PTR mechanism,CK_ATTRIBUTE_PTR template,CK_ULONG count,CK_OBJECT_HANDLE_PTR key)1438 gkm_session_C_GenerateKey (GkmSession* self, CK_MECHANISM_PTR mechanism,
1439 CK_ATTRIBUTE_PTR template, CK_ULONG count,
1440 CK_OBJECT_HANDLE_PTR key)
1441 {
1442 /* TODO: We need to implement this */
1443 return CKR_FUNCTION_NOT_SUPPORTED;
1444 }
1445
1446 CK_RV
gkm_session_C_GenerateKeyPair(GkmSession * self,CK_MECHANISM_PTR mechanism,CK_ATTRIBUTE_PTR pub_template,CK_ULONG pub_count,CK_ATTRIBUTE_PTR priv_template,CK_ULONG priv_count,CK_OBJECT_HANDLE_PTR pub_key,CK_OBJECT_HANDLE_PTR priv_key)1447 gkm_session_C_GenerateKeyPair (GkmSession* self, CK_MECHANISM_PTR mechanism,
1448 CK_ATTRIBUTE_PTR pub_template, CK_ULONG pub_count,
1449 CK_ATTRIBUTE_PTR priv_template, CK_ULONG priv_count,
1450 CK_OBJECT_HANDLE_PTR pub_key, CK_OBJECT_HANDLE_PTR priv_key)
1451 {
1452 GkmObject *pub = NULL;
1453 GkmObject *priv = NULL;
1454 GkmTransaction *transaction;
1455 CK_RV rv;
1456
1457 g_return_val_if_fail (GKM_IS_SESSION (self), CKR_SESSION_HANDLE_INVALID);
1458 if (!mechanism)
1459 return CKR_ARGUMENTS_BAD;
1460 if (!(!pub_count || pub_template))
1461 return CKR_ARGUMENTS_BAD;
1462 if (!(!priv_count || priv_template))
1463 return CKR_ARGUMENTS_BAD;
1464 if (!pub_key || !priv_key)
1465 return CKR_ARGUMENTS_BAD;
1466
1467 /*
1468 * Duplicate the memory for the attributes (but not values) so we
1469 * can 'consume' in the generator and create object functions.
1470 */
1471 pub_template = g_memdup (pub_template, pub_count * sizeof (CK_ATTRIBUTE));
1472 priv_template = g_memdup (priv_template, priv_count * sizeof (CK_ATTRIBUTE));
1473 transaction = gkm_transaction_new ();
1474
1475 /* Actually do the object creation */
1476 rv = gkm_crypto_generate_key_pair (self, mechanism->mechanism, pub_template, pub_count,
1477 priv_template, priv_count, &pub, &priv);
1478 if (rv != CKR_OK)
1479 gkm_transaction_fail (transaction, rv);
1480
1481 g_free (pub_template);
1482 g_free (priv_template);
1483
1484 gkm_transaction_complete (transaction);
1485 rv = gkm_transaction_get_result (transaction);
1486 g_object_unref (transaction);
1487
1488 if (rv == CKR_OK) {
1489 *pub_key = gkm_object_get_handle (pub);
1490 *priv_key = gkm_object_get_handle (priv);
1491 }
1492
1493 /* Objects are owned by storage */
1494 if (pub != NULL)
1495 g_object_unref (pub);
1496 if (priv != NULL)
1497 g_object_unref (priv);
1498
1499 return rv;
1500 }
1501
1502 CK_RV
gkm_session_C_WrapKey(GkmSession * self,CK_MECHANISM_PTR mechanism,CK_OBJECT_HANDLE wrapping_key,CK_OBJECT_HANDLE key,CK_BYTE_PTR wrapped_key,CK_ULONG_PTR wrapped_key_len)1503 gkm_session_C_WrapKey (GkmSession* self, CK_MECHANISM_PTR mechanism,
1504 CK_OBJECT_HANDLE wrapping_key, CK_OBJECT_HANDLE key,
1505 CK_BYTE_PTR wrapped_key, CK_ULONG_PTR wrapped_key_len)
1506 {
1507 GkmObject *wrapper = NULL;
1508 GkmObject *wrapped = NULL;
1509 CK_RV rv;
1510
1511 g_return_val_if_fail (GKM_IS_SESSION (self), CKR_SESSION_HANDLE_INVALID);
1512 if (!mechanism)
1513 return CKR_ARGUMENTS_BAD;
1514 if (!wrapped_key_len)
1515 return CKR_ARGUMENTS_BAD;
1516
1517 rv = gkm_session_lookup_readable_object (self, wrapping_key, &wrapper);
1518 if (rv == CKR_OBJECT_HANDLE_INVALID)
1519 return CKR_WRAPPING_KEY_HANDLE_INVALID;
1520 else if (rv != CKR_OK)
1521 return rv;
1522
1523 rv = gkm_session_lookup_readable_object (self, key, &wrapped);
1524 if (rv == CKR_OBJECT_HANDLE_INVALID)
1525 return CKR_KEY_HANDLE_INVALID;
1526 else if (rv != CKR_OK)
1527 return rv;
1528
1529 return gkm_crypto_wrap_key (self, mechanism, wrapper, wrapped,
1530 wrapped_key, wrapped_key_len);
1531 }
1532
1533 CK_RV
gkm_session_C_UnwrapKey(GkmSession * self,CK_MECHANISM_PTR mechanism,CK_OBJECT_HANDLE unwrapping_key,CK_BYTE_PTR wrapped_key,CK_ULONG wrapped_key_len,CK_ATTRIBUTE_PTR template,CK_ULONG count,CK_OBJECT_HANDLE_PTR key)1534 gkm_session_C_UnwrapKey (GkmSession* self, CK_MECHANISM_PTR mechanism,
1535 CK_OBJECT_HANDLE unwrapping_key, CK_BYTE_PTR wrapped_key,
1536 CK_ULONG wrapped_key_len, CK_ATTRIBUTE_PTR template,
1537 CK_ULONG count, CK_OBJECT_HANDLE_PTR key)
1538 {
1539 GkmObject *wrapper = NULL;
1540 GkmObject *unwrapped = NULL;
1541 CK_RV rv;
1542
1543 g_return_val_if_fail (GKM_IS_SESSION (self), CKR_SESSION_HANDLE_INVALID);
1544 if (!mechanism)
1545 return CKR_ARGUMENTS_BAD;
1546 if (!(!count || template))
1547 return CKR_ARGUMENTS_BAD;
1548 if (!key)
1549 return CKR_ARGUMENTS_BAD;
1550
1551 rv = gkm_session_lookup_readable_object (self, unwrapping_key, &wrapper);
1552 if (rv == CKR_OBJECT_HANDLE_INVALID)
1553 return CKR_WRAPPING_KEY_HANDLE_INVALID;
1554 else if (rv != CKR_OK)
1555 return rv;
1556
1557 /*
1558 * Duplicate the memory for the attributes (but not values) so we
1559 * can 'consume' in the generator and create object functions.
1560 */
1561 template = g_memdup (template, count * sizeof (CK_ATTRIBUTE));
1562
1563 rv = gkm_crypto_unwrap_key (self, mechanism, wrapper, wrapped_key,
1564 wrapped_key_len, template, count, &unwrapped);
1565
1566 g_free (template);
1567
1568 if (rv == CKR_OK) {
1569 *key = gkm_object_get_handle (unwrapped);
1570 g_object_unref (unwrapped);
1571 }
1572
1573 return rv;
1574 }
1575
1576 CK_RV
gkm_session_C_DeriveKey(GkmSession * self,CK_MECHANISM_PTR mechanism,CK_OBJECT_HANDLE base_key,CK_ATTRIBUTE_PTR template,CK_ULONG count,CK_OBJECT_HANDLE_PTR key)1577 gkm_session_C_DeriveKey (GkmSession* self, CK_MECHANISM_PTR mechanism,
1578 CK_OBJECT_HANDLE base_key, CK_ATTRIBUTE_PTR template,
1579 CK_ULONG count, CK_OBJECT_HANDLE_PTR key)
1580 {
1581 GkmObject *base = NULL;
1582 GkmObject *derived = NULL;
1583 CK_RV rv;
1584
1585 g_return_val_if_fail (GKM_IS_SESSION (self), CKR_SESSION_HANDLE_INVALID);
1586 if (!mechanism)
1587 return CKR_ARGUMENTS_BAD;
1588 if (!(!count || template))
1589 return CKR_ARGUMENTS_BAD;
1590 if (!key)
1591 return CKR_ARGUMENTS_BAD;
1592
1593 rv = gkm_session_lookup_readable_object (self, base_key, &base);
1594 if (rv != CKR_OK)
1595 return rv;
1596
1597 /*
1598 * Duplicate the memory for the attributes (but not values) so we
1599 * can 'consume' in the generator and create object functions.
1600 */
1601 template = g_memdup (template, count * sizeof (CK_ATTRIBUTE));
1602
1603 /* Actually do the object creation */
1604 rv = gkm_crypto_derive_key (self, mechanism, base, template, count, &derived);
1605
1606 g_free (template);
1607
1608 if (rv == CKR_OK) {
1609 *key = gkm_object_get_handle (derived);
1610 g_object_unref (derived);
1611 }
1612
1613 return rv;
1614 }
1615
1616 CK_RV
gkm_session_C_SeedRandom(GkmSession * self,CK_BYTE_PTR seed,CK_ULONG seed_len)1617 gkm_session_C_SeedRandom (GkmSession* self, CK_BYTE_PTR seed, CK_ULONG seed_len)
1618 {
1619 /* We don't have a RNG */
1620 return CKR_RANDOM_NO_RNG;
1621 }
1622
1623 CK_RV
gkm_session_C_GenerateRandom(GkmSession * self,CK_BYTE_PTR random_data,CK_ULONG random_len)1624 gkm_session_C_GenerateRandom (GkmSession* self, CK_BYTE_PTR random_data,
1625 CK_ULONG random_len)
1626 {
1627 /* We don't have a RNG */
1628 return CKR_RANDOM_NO_RNG;
1629 }
1630