1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
2 /* gck-misc.c - the GObject PKCS#11 wrapper library
3
4 Copyright (C) 2008, Stefan Walter
5
6 The Gnome Keyring Library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Library General Public License as
8 published by the Free Software Foundation; either version 2 of the
9 License, or (at your option) any later version.
10
11 The Gnome Keyring Library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Library General Public License for more details.
15
16 You should have received a copy of the GNU Library General Public
17 License along with the Gnome Library; see the file COPYING.LIB. If not,
18 see <http://www.gnu.org/licenses/>.
19
20 Author: Stef Walter <nielsen@memberwebs.com>
21 */
22
23 #include "config.h"
24
25 #include "gck.h"
26 #include "gck-private.h"
27
28 #include "egg/egg-secure-memory.h"
29
30 #include <p11-kit/p11-kit.h>
31
32 #include <glib/gi18n-lib.h>
33
34 #include <string.h>
35
36 EGG_SECURE_DEFINE_GLIB_GLOBALS ();
37
38 /**
39 * SECTION:gck-library
40 * @title: Library Utilities
41 * @short_description: Library utilities such as version checks
42 *
43 * Basic library utilities such as version checks.
44 */
45
46 /**
47 * GCK_CHECK_VERSION:
48 * @major: the major version to check for
49 * @minor: the minor version to check for
50 * @micro: the micro version to check for
51 *
52 * Checks the version of the Gck libarry that is being compiled
53 * against.
54 *
55 * <example>
56 * <title>Checking the version of the Gck library</title>
57 * <programlisting>
58 * #if !GCK_CHECK_VERSION (3, 0, 0)
59 * #warning Old Gck version, disabling functionality
60 * #endif
61 * </programlisting>
62 * </example>
63 *
64 * Returns: %TRUE if the version of the GLib header files
65 * is the same as or newer than the passed-in version.
66 */
67
68 /**
69 * GCK_MAJOR_VERSION:
70 *
71 * The major version number of the Gck library.
72 */
73
74 /**
75 * GCK_MINOR_VERSION:
76 *
77 * The minor version number of the Gck library.
78 */
79
80 /**
81 * GCK_MICRO_VERSION:
82 *
83 * The micro version number of the Gck library.
84 */
85
86 /**
87 * SECTION:gck-error
88 * @title: Errors
89 * @short_description: Gck Errors and error codes.
90 *
91 * Errors are returned as GError structures. The code member of GError
92 * contains the raw PKCS11 CK_RV result value.
93 */
94
95 /**
96 * SECTION:gck-private
97 * @title: Private, not used in docs
98 * @short_description: Should not show up in docs
99 *
100 * Should not show up in the docs
101 */
102
103 /**
104 * GCK_INVALID:
105 *
106 * Used as a terminator at the end of variable argument lists.
107 */
108
109 /**
110 * GCK_VENDOR_CODE:
111 *
112 * Custom PKCS11 errors that originate from the gck library, are
113 * based at this error code.
114 */
115
116 /**
117 * GckError:
118 * @GCK_ERROR_MODULE_PROBLEM: a result code that signifies there was a problem
119 * loading a PKCS\#11 module, usually a shared library
120 *
121 * Various error codes. All the CKR_XXX error codes from PKCS\#11 are also
122 * relevant error codes.
123 */
124
125 /**
126 * GCK_ERROR:
127 *
128 * The error domain for gck library errors.
129 */
130
131 GQuark
gck_get_error_quark(void)132 gck_get_error_quark (void)
133 {
134 /* This is the deprecated version */
135 return gck_error_get_quark ();
136 }
137
138 GQuark
gck_error_get_quark(void)139 gck_error_get_quark (void)
140 {
141 static GQuark domain = 0;
142 static volatile gsize quark_inited = 0;
143
144 if (g_once_init_enter (&quark_inited)) {
145 domain = g_quark_from_static_string ("gck-error");
146 g_once_init_leave (&quark_inited, 1);
147 }
148
149 return domain;
150 }
151
152 /**
153 * gck_message_from_rv:
154 * @rv: The PKCS\#11 return value to get a message for.
155 *
156 * Get a message for a PKCS\#11 return value or error code. Do not
157 * pass CKR_OK or other such non errors to this function.
158 *
159 * Return value: The user readable message.
160 **/
161 const gchar*
gck_message_from_rv(gulong rv)162 gck_message_from_rv (gulong rv)
163 {
164 switch (rv) {
165
166 /* These are not really errors, or not current */
167 case CKR_OK:
168 case CKR_NO_EVENT:
169 case CKR_FUNCTION_NOT_PARALLEL:
170 case CKR_SESSION_PARALLEL_NOT_SUPPORTED:
171 g_return_val_if_reached ("");
172
173 default:
174 return p11_kit_strerror (rv);
175 }
176 }
177
178 const gchar *
_gck_stringize_rv(CK_RV rv)179 _gck_stringize_rv (CK_RV rv)
180 {
181 switch(rv) {
182 #define X(x) case x: return #x;
183 X (CKR_OK)
184 X (CKR_CANCEL)
185 X (CKR_HOST_MEMORY)
186 X (CKR_SLOT_ID_INVALID)
187 X (CKR_GENERAL_ERROR)
188 X (CKR_FUNCTION_FAILED)
189 X (CKR_ARGUMENTS_BAD)
190 X (CKR_NO_EVENT)
191 X (CKR_NEED_TO_CREATE_THREADS)
192 X (CKR_CANT_LOCK)
193 X (CKR_ATTRIBUTE_READ_ONLY)
194 X (CKR_ATTRIBUTE_SENSITIVE)
195 X (CKR_ATTRIBUTE_TYPE_INVALID)
196 X (CKR_ATTRIBUTE_VALUE_INVALID)
197 X (CKR_DATA_INVALID)
198 X (CKR_DATA_LEN_RANGE)
199 X (CKR_DEVICE_ERROR)
200 X (CKR_DEVICE_MEMORY)
201 X (CKR_DEVICE_REMOVED)
202 X (CKR_ENCRYPTED_DATA_INVALID)
203 X (CKR_ENCRYPTED_DATA_LEN_RANGE)
204 X (CKR_FUNCTION_CANCELED)
205 X (CKR_FUNCTION_NOT_PARALLEL)
206 X (CKR_FUNCTION_NOT_SUPPORTED)
207 X (CKR_KEY_HANDLE_INVALID)
208 X (CKR_KEY_SIZE_RANGE)
209 X (CKR_KEY_TYPE_INCONSISTENT)
210 X (CKR_KEY_NOT_NEEDED)
211 X (CKR_KEY_CHANGED)
212 X (CKR_KEY_NEEDED)
213 X (CKR_KEY_INDIGESTIBLE)
214 X (CKR_KEY_FUNCTION_NOT_PERMITTED)
215 X (CKR_KEY_NOT_WRAPPABLE)
216 X (CKR_KEY_UNEXTRACTABLE)
217 X (CKR_MECHANISM_INVALID)
218 X (CKR_MECHANISM_PARAM_INVALID)
219 X (CKR_OBJECT_HANDLE_INVALID)
220 X (CKR_OPERATION_ACTIVE)
221 X (CKR_OPERATION_NOT_INITIALIZED)
222 X (CKR_PIN_INCORRECT)
223 X (CKR_PIN_INVALID)
224 X (CKR_PIN_LEN_RANGE)
225 X (CKR_PIN_EXPIRED)
226 X (CKR_PIN_LOCKED)
227 X (CKR_SESSION_CLOSED)
228 X (CKR_SESSION_COUNT)
229 X (CKR_SESSION_HANDLE_INVALID)
230 X (CKR_SESSION_PARALLEL_NOT_SUPPORTED)
231 X (CKR_SESSION_READ_ONLY)
232 X (CKR_SESSION_EXISTS)
233 X (CKR_SESSION_READ_ONLY_EXISTS)
234 X (CKR_SESSION_READ_WRITE_SO_EXISTS)
235 X (CKR_SIGNATURE_INVALID)
236 X (CKR_SIGNATURE_LEN_RANGE)
237 X (CKR_TEMPLATE_INCOMPLETE)
238 X (CKR_TEMPLATE_INCONSISTENT)
239 X (CKR_TOKEN_NOT_PRESENT)
240 X (CKR_TOKEN_NOT_RECOGNIZED)
241 X (CKR_TOKEN_WRITE_PROTECTED)
242 X (CKR_UNWRAPPING_KEY_HANDLE_INVALID)
243 X (CKR_UNWRAPPING_KEY_SIZE_RANGE)
244 X (CKR_UNWRAPPING_KEY_TYPE_INCONSISTENT)
245 X (CKR_USER_ALREADY_LOGGED_IN)
246 X (CKR_USER_NOT_LOGGED_IN)
247 X (CKR_USER_PIN_NOT_INITIALIZED)
248 X (CKR_USER_TYPE_INVALID)
249 X (CKR_USER_ANOTHER_ALREADY_LOGGED_IN)
250 X (CKR_USER_TOO_MANY_TYPES)
251 X (CKR_WRAPPED_KEY_INVALID)
252 X (CKR_WRAPPED_KEY_LEN_RANGE)
253 X (CKR_WRAPPING_KEY_HANDLE_INVALID)
254 X (CKR_WRAPPING_KEY_SIZE_RANGE)
255 X (CKR_WRAPPING_KEY_TYPE_INCONSISTENT)
256 X (CKR_RANDOM_SEED_NOT_SUPPORTED)
257 X (CKR_RANDOM_NO_RNG)
258 X (CKR_DOMAIN_PARAMS_INVALID)
259 X (CKR_BUFFER_TOO_SMALL)
260 X (CKR_SAVED_STATE_INVALID)
261 X (CKR_INFORMATION_SENSITIVE)
262 X (CKR_STATE_UNSAVEABLE)
263 X (CKR_CRYPTOKI_NOT_INITIALIZED)
264 X (CKR_CRYPTOKI_ALREADY_INITIALIZED)
265 X (CKR_MUTEX_BAD)
266 X (CKR_MUTEX_NOT_LOCKED)
267 X (CKR_FUNCTION_REJECTED)
268 X (CKR_VENDOR_DEFINED)
269 #undef X
270 default:
271 return "CKR_??????";
272 }
273 }
274
275 CK_RV
_gck_rv_from_error(GError * error,CK_RV catch_all_code)276 _gck_rv_from_error (GError *error,
277 CK_RV catch_all_code)
278 {
279 g_return_val_if_fail (error != NULL, CKR_GENERAL_ERROR);
280
281 if (error->domain == GCK_ERROR)
282 return error->code;
283
284 if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
285 return CKR_FUNCTION_CANCELED;
286
287 return catch_all_code;
288 }
289
290 /**
291 * SECTION:gck-misc
292 * @title: Miscellaneous Functions
293 * @short_description: Other miscellaneous functions.
294 *
295 * A few supporting functions that come in handy when dealing with the gck
296 * library or PKCS11 in general.
297 */
298
299 GType
gck_list_get_boxed_type(void)300 gck_list_get_boxed_type (void)
301 {
302 static GType type = 0;
303 if (!type)
304 type = g_boxed_type_register_static ("GckList",
305 (GBoxedCopyFunc)gck_list_ref_copy,
306 (GBoxedFreeFunc)gck_list_unref_free);
307 return type;
308
309 }
310
311 /**
312 * gck_list_unref_free: (skip)
313 * @reflist: (element-type GObject.Object): list of Gobject reference counted pointers
314 *
315 * Free a list of GObject based pointers. All objects in the list
316 * will be unreffed and then the list itself will be freed.
317 **/
318 void
gck_list_unref_free(GList * reflist)319 gck_list_unref_free (GList *reflist)
320 {
321 GList *l;
322 for (l = reflist; l; l = g_list_next (l)) {
323 g_return_if_fail (G_IS_OBJECT (l->data));
324 g_object_unref (l->data);
325 }
326 g_list_free (reflist);
327 }
328
329 /**
330 * gck_list_ref_copy: (skip)
331 * @reflist: (element-type GObject.Object): list of GObject reference counted
332 * objects
333 *
334 * Copy a list of GObject based pointers. All objects
335 * in the list will be reffed and the list will be copied.
336 *
337 * Return value: (transfer full) (element-type GObject.Object): the copied and
338 * reffed list, when done, free it with gck_list_unref_free ()
339 **/
340 GList *
gck_list_ref_copy(GList * reflist)341 gck_list_ref_copy (GList *reflist)
342 {
343 GList *l, *copy = g_list_copy (reflist);
344 for (l = copy; l; l = g_list_next (l)) {
345 g_return_val_if_fail (G_IS_OBJECT (l->data), NULL);
346 g_object_ref (l->data);
347 }
348 return copy;
349 }
350
351 /**
352 * gck_string_from_chars: (skip)
353 * @data: The character data to turn into a null terminated string.
354 * @max: The maximum length of the charater data.
355 *
356 * Create a string from a set of PKCS\#11 characters. This is
357 * similar to g_strndup, except for that it also strips trailing
358 * spaces. These space padded strings are often used in PKCS\#11
359 * structures.
360 *
361 * If the space padded string is filled with null characters then
362 * this function will return %NULL.
363 *
364 * Return value: The null terminated string.
365 */
366 gchar*
gck_string_from_chars(const guchar * data,gsize max)367 gck_string_from_chars (const guchar *data, gsize max)
368 {
369 gchar *string;
370
371 g_return_val_if_fail (data, NULL);
372 g_return_val_if_fail (max, NULL);
373
374 /* Means no value */
375 if (!data[0])
376 return NULL;
377
378 string = g_strndup ((gchar*)data, max);
379 g_strchomp (string);
380 return string;
381 }
382
383 /**
384 * gck_string_to_chars: (skip)
385 * @data: The character buffer to place string into.
386 * @max: The maximum length of the charater buffer.
387 * @string: The string to place in the buffer.
388 *
389 * Create a space padded PKCS\#11 string from a null terminated string.
390 * The string must be shorter than the buffer or %FALSE will be
391 * returned.
392 *
393 * If a %NULL string is passed, then the space padded string will be
394 * set to zero characters.
395 *
396 * Return value: The null terminated string.
397 */
398 gboolean
gck_string_to_chars(guchar * data,gsize max,const gchar * string)399 gck_string_to_chars (guchar *data, gsize max, const gchar *string)
400 {
401 gsize len;
402
403 g_return_val_if_fail (data, FALSE);
404 g_return_val_if_fail (max, FALSE);
405
406 if (!string) {
407 memset (data, 0, max);
408 return TRUE;
409 }
410
411 len = strlen (string);
412 if (len > max)
413 return FALSE;
414
415 memset (data, ' ', max);
416 memcpy (data, string, len);
417 return TRUE;
418 }
419
420 guint
_gck_ulong_hash(gconstpointer v)421 _gck_ulong_hash (gconstpointer v)
422 {
423 const signed char *p = v;
424 guint32 i, h = *p;
425
426 for(i = 0; i < sizeof (gulong); ++i)
427 h = (h << 5) - h + *(p++);
428
429 return h;
430 }
431
432 gboolean
_gck_ulong_equal(gconstpointer v1,gconstpointer v2)433 _gck_ulong_equal (gconstpointer v1, gconstpointer v2)
434 {
435 return memcmp(v1, v2, sizeof (gulong)) == 0;
436 }
437
438 /**
439 * gck_value_to_ulong:
440 * @value: (array length=length): memory to convert
441 * @length: length of memory
442 * @result: A location to store the result
443 *
444 * Convert CK_ULONG type memory to a boolean.
445 *
446 * Returns: Whether the conversion was successful.
447 */
448 gboolean
gck_value_to_ulong(const guchar * value,gsize length,gulong * result)449 gck_value_to_ulong (const guchar *value,
450 gsize length,
451 gulong *result)
452 {
453 if (!value || length != sizeof (CK_ULONG))
454 return FALSE;
455 if (result)
456 memcpy(result, value, sizeof(CK_ULONG));
457 return TRUE;
458 }
459
460 /**
461 * gck_value_to_boolean:
462 * @value: (array length=length): memory to convert
463 * @length: length of memory
464 * @result: A location to store the result
465 *
466 * Convert CK_BBOOL type memory to a boolean.
467 *
468 * Returns: Whether the conversion was successful.
469 */
470 gboolean
gck_value_to_boolean(const guchar * value,gsize length,gboolean * result)471 gck_value_to_boolean (const guchar *value,
472 gsize length,
473 gboolean *result)
474 {
475 CK_BBOOL tempval = CK_FALSE;
476 if (!value || length != sizeof (CK_BBOOL))
477 return FALSE;
478 if (result) {
479 memcpy(&tempval, value, sizeof(CK_BBOOL));
480 *result = tempval ? TRUE : FALSE;
481 }
482 return TRUE;
483 }
484
485 static gboolean
match_info_string(const gchar * match,const gchar * string)486 match_info_string (const gchar *match, const gchar *string)
487 {
488 /* NULL matches anything */
489 if (match == NULL)
490 return TRUE;
491
492 if (string == NULL)
493 return FALSE;
494
495 return g_str_equal (match, string);
496 }
497
498 gboolean
_gck_module_info_match(GckModuleInfo * match,GckModuleInfo * info)499 _gck_module_info_match (GckModuleInfo *match, GckModuleInfo *info)
500 {
501 /* Matches two GckModuleInfo for use in PKCS#11 URI's */
502
503 g_return_val_if_fail (match, FALSE);
504 g_return_val_if_fail (info, FALSE);
505
506 return (match_info_string (match->library_description, info->library_description) &&
507 match_info_string (match->manufacturer_id, info->manufacturer_id));
508 }
509
510 gboolean
_gck_token_info_match(GckTokenInfo * match,GckTokenInfo * info)511 _gck_token_info_match (GckTokenInfo *match, GckTokenInfo *info)
512 {
513 /* Matches two GckTokenInfo for use in PKCS#11 URI's */
514
515 g_return_val_if_fail (match, FALSE);
516 g_return_val_if_fail (info, FALSE);
517
518 return (match_info_string (match->label, info->label) &&
519 match_info_string (match->manufacturer_id, info->manufacturer_id) &&
520 match_info_string (match->model, info->model) &&
521 match_info_string (match->serial_number, info->serial_number));
522 }
523