Imported Upstream version 3.3.5
[platform/upstream/gnutls.git] / lib / pkcs11.c
1 /*
2  * GnuTLS PKCS#11 support
3  * Copyright (C) 2010-2012 Free Software Foundation, Inc.
4  * Copyright (C) 2008 Joe Orton <joe@manyfish.co.uk>
5  * Copyright (C) 2013 Nikos Mavrogiannopoulos
6  * 
7  * Authors: Nikos Mavrogiannopoulos, Stef Walter
8  *
9  * Inspired and some parts (pkcs11_login) based on neon PKCS #11 support 
10  * by Joe Orton. More ideas came from the pkcs11-helper library by 
11  * Alon Bar-Lev.
12  *
13  * GnuTLS is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU Lesser General Public License
15  * as published by the Free Software Foundation; either version 2.1 of
16  * the License, or (at your option) any later version.
17  *
18  * This library is distributed in the hope that it will be useful, but
19  * WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
21  * Lesser General Public License for more details.
22  *
23  * You should have received a copy of the GNU Lesser General Public License
24  * along with this program.  If not, see <http://www.gnu.org/licenses/>
25  */
26
27 #include <gnutls_int.h>
28 #include <gnutls/pkcs11.h>
29 #include <string.h>
30 #include <gnutls_errors.h>
31 #include <gnutls_datum.h>
32 #include <x509/common.h>
33 #include <locks.h>
34
35 #include <pin.h>
36 #include <pkcs11_int.h>
37 #include <p11-kit/p11-kit.h>
38 #include <p11-kit/pin.h>
39 #ifdef HAVE_GETPID
40 # include <unistd.h>
41 #endif
42
43 #define MAX_PROVIDERS 16
44
45 /* XXX: try to eliminate this */
46 #define MAX_CERT_SIZE 32*1024
47 #define MAX_SLOTS 48
48
49 extern void *_gnutls_pkcs11_mutex;
50
51 struct gnutls_pkcs11_provider_st {
52         struct ck_function_list *module;
53         unsigned active;
54         unsigned trusted; /* in the sense of p11-kit trusted:
55                            * it can be used for verification */
56         struct ck_info info;
57 };
58
59 struct find_flags_data_st {
60         struct p11_kit_uri *info;
61         unsigned int slot_flags;
62         unsigned int trusted;
63 };
64
65 struct find_url_data_st {
66         gnutls_pkcs11_obj_t crt;
67 };
68
69 struct find_obj_data_st {
70         gnutls_pkcs11_obj_t *p_list;
71         unsigned int *n_list;
72         unsigned int current;
73         gnutls_pkcs11_obj_attr_t flags;
74         struct p11_kit_uri *info;
75 };
76
77 struct find_token_num {
78         struct p11_kit_uri *info;
79         unsigned int seq;       /* which one we are looking for */
80         unsigned int current;   /* which one are we now */
81 };
82
83 struct find_pkey_list_st {
84         gnutls_buffer_st *key_ids;
85         size_t key_ids_size;
86 };
87
88 struct find_cert_st {
89         gnutls_datum_t dn;
90         gnutls_datum_t issuer_dn;
91         gnutls_datum_t key_id;
92         gnutls_datum_t serial;
93
94         unsigned need_import;
95         gnutls_pkcs11_obj_t obj;
96         gnutls_x509_crt_t crt; /* used when compare flag is specified */
97         unsigned flags;
98 };
99
100
101 static struct gnutls_pkcs11_provider_st providers[MAX_PROVIDERS];
102 static unsigned int active_providers = 0;
103 static unsigned int providers_initialized = 0;
104 #ifdef HAVE_GETPID
105 static pid_t init_pid = -1;
106 #endif
107
108 gnutls_pkcs11_token_callback_t _gnutls_token_func;
109 void *_gnutls_token_data;
110
111 int pkcs11_rv_to_err(ck_rv_t rv)
112 {
113         switch (rv) {
114         case CKR_OK:
115                 return 0;
116         case CKR_HOST_MEMORY:
117                 return GNUTLS_E_MEMORY_ERROR;
118         case CKR_SLOT_ID_INVALID:
119                 return GNUTLS_E_PKCS11_SLOT_ERROR;
120         case CKR_ARGUMENTS_BAD:
121         case CKR_MECHANISM_PARAM_INVALID:
122                 return GNUTLS_E_INVALID_REQUEST;
123         case CKR_NEED_TO_CREATE_THREADS:
124         case CKR_CANT_LOCK:
125         case CKR_FUNCTION_NOT_PARALLEL:
126         case CKR_MUTEX_BAD:
127         case CKR_MUTEX_NOT_LOCKED:
128                 return GNUTLS_E_LOCKING_ERROR;
129         case CKR_ATTRIBUTE_READ_ONLY:
130         case CKR_ATTRIBUTE_SENSITIVE:
131         case CKR_ATTRIBUTE_TYPE_INVALID:
132         case CKR_ATTRIBUTE_VALUE_INVALID:
133                 return GNUTLS_E_PKCS11_ATTRIBUTE_ERROR;
134         case CKR_DEVICE_ERROR:
135         case CKR_DEVICE_MEMORY:
136         case CKR_DEVICE_REMOVED:
137                 return GNUTLS_E_PKCS11_DEVICE_ERROR;
138         case CKR_DATA_INVALID:
139         case CKR_DATA_LEN_RANGE:
140         case CKR_ENCRYPTED_DATA_INVALID:
141         case CKR_ENCRYPTED_DATA_LEN_RANGE:
142         case CKR_OBJECT_HANDLE_INVALID:
143                 return GNUTLS_E_PKCS11_DATA_ERROR;
144         case CKR_FUNCTION_NOT_SUPPORTED:
145         case CKR_MECHANISM_INVALID:
146                 return GNUTLS_E_PKCS11_UNSUPPORTED_FEATURE_ERROR;
147         case CKR_KEY_HANDLE_INVALID:
148         case CKR_KEY_SIZE_RANGE:
149         case CKR_KEY_TYPE_INCONSISTENT:
150         case CKR_KEY_NOT_NEEDED:
151         case CKR_KEY_CHANGED:
152         case CKR_KEY_NEEDED:
153         case CKR_KEY_INDIGESTIBLE:
154         case CKR_KEY_FUNCTION_NOT_PERMITTED:
155         case CKR_KEY_NOT_WRAPPABLE:
156         case CKR_KEY_UNEXTRACTABLE:
157                 return GNUTLS_E_PKCS11_KEY_ERROR;
158         case CKR_PIN_INCORRECT:
159         case CKR_PIN_INVALID:
160         case CKR_PIN_LEN_RANGE:
161                 return GNUTLS_E_PKCS11_PIN_ERROR;
162         case CKR_PIN_EXPIRED:
163                 return GNUTLS_E_PKCS11_PIN_EXPIRED;
164         case CKR_PIN_LOCKED:
165                 return GNUTLS_E_PKCS11_PIN_LOCKED;
166         case CKR_SESSION_CLOSED:
167         case CKR_SESSION_COUNT:
168         case CKR_SESSION_HANDLE_INVALID:
169         case CKR_SESSION_PARALLEL_NOT_SUPPORTED:
170         case CKR_SESSION_READ_ONLY:
171         case CKR_SESSION_EXISTS:
172         case CKR_SESSION_READ_ONLY_EXISTS:
173         case CKR_SESSION_READ_WRITE_SO_EXISTS:
174                 return GNUTLS_E_PKCS11_SESSION_ERROR;
175         case CKR_SIGNATURE_INVALID:
176         case CKR_SIGNATURE_LEN_RANGE:
177                 return GNUTLS_E_PKCS11_SIGNATURE_ERROR;
178         case CKR_TOKEN_NOT_PRESENT:
179         case CKR_TOKEN_NOT_RECOGNIZED:
180         case CKR_TOKEN_WRITE_PROTECTED:
181                 return GNUTLS_E_PKCS11_TOKEN_ERROR;
182         case CKR_USER_ALREADY_LOGGED_IN:
183         case CKR_USER_NOT_LOGGED_IN:
184         case CKR_USER_PIN_NOT_INITIALIZED:
185         case CKR_USER_TYPE_INVALID:
186         case CKR_USER_ANOTHER_ALREADY_LOGGED_IN:
187         case CKR_USER_TOO_MANY_TYPES:
188                 return GNUTLS_E_PKCS11_USER_ERROR;
189         case CKR_BUFFER_TOO_SMALL:
190                 return GNUTLS_E_SHORT_MEMORY_BUFFER;
191         default:
192                 return GNUTLS_E_PKCS11_ERROR;
193         }
194 }
195
196
197 static int scan_slots(struct gnutls_pkcs11_provider_st *p,
198                       ck_slot_id_t * slots, unsigned long *nslots)
199 {
200         ck_rv_t rv;
201
202         rv = pkcs11_get_slot_list(p->module, 1, slots, nslots);
203         if (rv != CKR_OK) {
204                 gnutls_assert();
205                 return pkcs11_rv_to_err(rv);
206         }
207         return 0;
208 }
209
210 static int
211 pkcs11_add_module(const char* name, struct ck_function_list *module, const char *params)
212 {
213         unsigned int i;
214         struct ck_info info;
215
216         if (active_providers >= MAX_PROVIDERS) {
217                 gnutls_assert();
218                 return GNUTLS_E_CONSTRAINT_ERROR;
219         }
220         
221         memset(&info, 0, sizeof(info));
222         pkcs11_get_module_info(module, &info);
223
224         /* initially check if this module is a duplicate */
225         for (i = 0; i < active_providers; i++) {
226                 /* already loaded, skip the rest */
227                 if (module == providers[i].module) {
228                         _gnutls_debug_log("p11: module %s is already loaded.\n", name);
229                         return GNUTLS_E_INT_RET_0;
230                 }
231         }
232
233         active_providers++;
234         providers[active_providers - 1].module = module;
235         providers[active_providers - 1].active = 1;
236
237         if (p11_kit_module_get_flags(module) & P11_KIT_MODULE_TRUSTED ||
238                 (params != NULL && strstr(params, "trusted") != 0))
239                 providers[active_providers - 1].trusted = 1;
240
241         memcpy(&providers[active_providers - 1].info, &info, sizeof(info));
242
243         return 0;
244 }
245
246 int _gnutls_pkcs11_check_init(void)
247 {
248         int ret;
249         
250         ret = gnutls_mutex_lock(&_gnutls_pkcs11_mutex);
251         if (ret != 0)
252                 return gnutls_assert_val(GNUTLS_E_LOCKING_ERROR);
253
254 #ifdef HAVE_GETPID
255         if (init_pid == 0)
256                 init_pid = getpid();
257 #endif
258
259         if (providers_initialized != 0) {
260                 ret = 0;
261 #ifdef HAVE_GETPID
262                 if (init_pid != getpid()) {
263                         /* if we are initialized but a fork is detected */
264                         ret = gnutls_pkcs11_reinit();
265                 }
266 #endif
267
268                 gnutls_mutex_unlock(&_gnutls_pkcs11_mutex);
269                 return ret;
270         }
271
272 #ifdef HAVE_GETPID
273         init_pid = getpid();
274 #endif
275
276         providers_initialized = 1;
277         _gnutls_debug_log("Initializing PKCS #11 modules\n");
278         ret = gnutls_pkcs11_init(GNUTLS_PKCS11_FLAG_AUTO, NULL);
279         
280         gnutls_mutex_unlock(&_gnutls_pkcs11_mutex);
281         
282         if (ret < 0)
283                 return gnutls_assert_val(ret);
284
285         return 0;
286 }
287
288
289 /**
290  * gnutls_pkcs11_add_provider:
291  * @name: The filename of the module
292  * @params: should be NULL
293  *
294  * This function will load and add a PKCS 11 module to the module
295  * list used in gnutls. After this function is called the module will
296  * be used for PKCS 11 operations.
297  *
298  * When loading a module to be used for certificate verification,
299  * use the string 'trusted' as @params.
300  *
301  * Note that this function is not thread safe.
302  *
303  * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
304  *   negative error value.
305  *
306  * Since: 2.12.0
307  **/
308 int gnutls_pkcs11_add_provider(const char *name, const char *params)
309 {
310         struct ck_function_list *module;
311         int ret;
312
313         module = p11_kit_module_load(name, P11_KIT_MODULE_CRITICAL);
314         if (module == NULL) {
315                 gnutls_assert();
316                 _gnutls_debug_log("p11: Cannot load provider %s\n", name);
317                 return GNUTLS_E_PKCS11_LOAD_ERROR;
318         }
319
320         _gnutls_debug_log
321                     ("p11: Initializing module: %s\n", name);
322
323         ret = p11_kit_module_initialize(module);
324         if (ret != CKR_OK) {
325                 p11_kit_module_release(module);
326                 gnutls_assert();
327                 return pkcs11_rv_to_err(ret);
328         }
329
330         ret = pkcs11_add_module(name, module, params);
331         if (ret != 0) {
332                 if (ret == GNUTLS_E_INT_RET_0)
333                         ret = 0;
334                 p11_kit_module_finalize(module);
335                 p11_kit_module_release(module);
336                 gnutls_assert();
337         }
338
339         return ret;
340 }
341
342
343 /**
344  * gnutls_pkcs11_obj_get_info:
345  * @crt: should contain a #gnutls_pkcs11_obj_t structure
346  * @itype: Denotes the type of information requested
347  * @output: where output will be stored
348  * @output_size: contains the maximum size of the output and will be overwritten with actual
349  *
350  * This function will return information about the PKCS11 certificate
351  * such as the label, id as well as token information where the key is
352  * stored. When output is text it returns null terminated string
353  * although @output_size contains the size of the actual data only.
354  *
355  * Returns: %GNUTLS_E_SUCCESS (0) on success or a negative error code on error.
356  *
357  * Since: 2.12.0
358  **/
359 int
360 gnutls_pkcs11_obj_get_info(gnutls_pkcs11_obj_t crt,
361                            gnutls_pkcs11_obj_info_t itype,
362                            void *output, size_t * output_size)
363 {
364         return pkcs11_get_info(crt->info, itype, output, output_size);
365 }
366
367 int
368 pkcs11_get_info(struct p11_kit_uri *info,
369                 gnutls_pkcs11_obj_info_t itype, void *output,
370                 size_t * output_size)
371 {
372         struct ck_attribute *attr = NULL;
373         struct ck_version *version = NULL;
374         const uint8_t *str = NULL;
375         size_t str_max = 0;
376         int terminate = 0;
377         int hexify = 0;
378         size_t length = 0;
379         const char *data = NULL;
380         char buf[32];
381
382         /*
383          * Either attr, str or version is valid by the time switch
384          * finishes
385          */
386
387         switch (itype) {
388         case GNUTLS_PKCS11_OBJ_ID:
389                 attr = p11_kit_uri_get_attribute(info, CKA_ID);
390                 break;
391         case GNUTLS_PKCS11_OBJ_ID_HEX:
392                 attr = p11_kit_uri_get_attribute(info, CKA_ID);
393                 hexify = 1;
394                 terminate = 1;
395                 break;
396         case GNUTLS_PKCS11_OBJ_LABEL:
397                 attr = p11_kit_uri_get_attribute(info, CKA_LABEL);
398                 terminate = 1;
399                 break;
400         case GNUTLS_PKCS11_OBJ_TOKEN_LABEL:
401                 str = p11_kit_uri_get_token_info(info)->label;
402                 str_max = 32;
403                 break;
404         case GNUTLS_PKCS11_OBJ_TOKEN_SERIAL:
405                 str = p11_kit_uri_get_token_info(info)->serial_number;
406                 str_max = 16;
407                 break;
408         case GNUTLS_PKCS11_OBJ_TOKEN_MANUFACTURER:
409                 str = p11_kit_uri_get_token_info(info)->manufacturer_id;
410                 str_max = 32;
411                 break;
412         case GNUTLS_PKCS11_OBJ_TOKEN_MODEL:
413                 str = p11_kit_uri_get_token_info(info)->model;
414                 str_max = 16;
415                 break;
416         case GNUTLS_PKCS11_OBJ_LIBRARY_DESCRIPTION:
417                 str =
418                     p11_kit_uri_get_module_info(info)->library_description;
419                 str_max = 32;
420                 break;
421         case GNUTLS_PKCS11_OBJ_LIBRARY_VERSION:
422                 version =
423                     &p11_kit_uri_get_module_info(info)->library_version;
424                 break;
425         case GNUTLS_PKCS11_OBJ_LIBRARY_MANUFACTURER:
426                 str = p11_kit_uri_get_module_info(info)->manufacturer_id;
427                 str_max = 32;
428                 break;
429         default:
430                 gnutls_assert();
431                 return GNUTLS_E_INVALID_REQUEST;
432         }
433
434         if (attr != NULL) {
435                 data = attr->value;
436                 length = attr->value_len;
437         } else if (str != NULL) {
438                 data = (void *) str;
439                 length = p11_kit_space_strlen(str, str_max);
440                 terminate = 1;
441         } else if (version != NULL) {
442                 data = buf;
443                 length =
444                     snprintf(buf, sizeof(buf), "%d.%d",
445                              (int) version->major, (int) version->minor);
446                 terminate = 1;
447         } else {
448                 *output_size = 0;
449                 if (output)
450                         ((uint8_t *) output)[0] = 0;
451                 return 0;
452         }
453
454         if (hexify) {
455                 /* terminate is assumed with hexify */
456                 if (*output_size < length * 3) {
457                         *output_size = length * 3;
458                         return GNUTLS_E_SHORT_MEMORY_BUFFER;
459                 }
460                 if (output && length > 0)
461                         _gnutls_bin2hex(data, length, output, *output_size,
462                                         ":");
463                 *output_size = length * 3;
464                 return 0;
465         } else {
466                 if (*output_size < length + terminate) {
467                         *output_size = length + terminate;
468                         return GNUTLS_E_SHORT_MEMORY_BUFFER;
469                 }
470                 if (output) {
471                         memcpy(output, data, length);
472                         if (terminate)
473                                 ((unsigned char *) output)[length] = '\0';
474                 }
475                 *output_size = length + terminate;
476         }
477
478         return 0;
479 }
480
481 static int init = 0;
482
483 /* tries to load modules from /etc/gnutls/pkcs11.conf if it exists
484  */
485 static void compat_load(const char *configfile)
486 {
487         FILE *fp;
488         int ret;
489         char line[512];
490         const char *library;
491
492         if (configfile == NULL)
493                 configfile = "/etc/gnutls/pkcs11.conf";
494
495         fp = fopen(configfile, "r");
496         if (fp == NULL) {
497                 gnutls_assert();
498                 return;
499         }
500
501         _gnutls_debug_log("Loading PKCS #11 libraries from %s\n",
502                           configfile);
503         while (fgets(line, sizeof(line), fp) != NULL) {
504                 if (strncmp(line, "load", sizeof("load") - 1) == 0) {
505                         char *p;
506                         p = strchr(line, '=');
507                         if (p == NULL)
508                                 continue;
509
510                         library = ++p;
511                         p = strchr(line, '\n');
512                         if (p != NULL)
513                                 *p = 0;
514
515                         ret = gnutls_pkcs11_add_provider(library, NULL);
516                         if (ret < 0) {
517                                 gnutls_assert();
518                                 _gnutls_debug_log
519                                     ("Cannot load provider: %s\n",
520                                      library);
521                                 continue;
522                         }
523                 }
524         }
525         fclose(fp);
526
527         return;
528 }
529
530 static int auto_load(void)
531 {
532         struct ck_function_list **modules;
533         int i, ret;
534         char* name;
535
536         modules = p11_kit_modules_load_and_initialize(0);
537         if (modules == NULL) {
538                 gnutls_assert();
539                 _gnutls_debug_log
540                     ("Cannot initialize registered modules: %s\n",
541                      p11_kit_message());
542                 return GNUTLS_E_PKCS11_LOAD_ERROR;
543         }
544
545         for (i = 0; modules[i] != NULL; i++) {
546                 name = p11_kit_module_get_name(modules[i]);
547                 _gnutls_debug_log
548                             ("p11: Initializing module: %s\n", name);
549
550                 ret = pkcs11_add_module(name, modules[i], NULL);
551                 if (ret < 0) {
552                         gnutls_assert();
553                         _gnutls_debug_log
554                             ("Cannot load PKCS #11 module: %s\n", name);
555                 }
556                 free(name);
557         }
558
559         /* Shallow free */
560         free(modules);
561         return 0;
562 }
563
564 /**
565  * gnutls_pkcs11_init:
566  * @flags: An ORed sequence of %GNUTLS_PKCS11_FLAG_*
567  * @deprecated_config_file: either NULL or the location of a deprecated
568  *     configuration file
569  *
570  * This function will initialize the PKCS 11 subsystem in gnutls. It will
571  * read configuration files if %GNUTLS_PKCS11_FLAG_AUTO is used or allow
572  * you to independently load PKCS 11 modules using gnutls_pkcs11_add_provider()
573  * if %GNUTLS_PKCS11_FLAG_MANUAL is specified.
574  *
575  * Normally you don't need to call this function since it is being called
576  * when the first PKCS 11 operation is requested using the %GNUTLS_PKCS11_FLAG_AUTO
577  * flag. If another flags are required then it must be called independently
578  * prior to any PKCS 11 operation.
579  *
580  * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
581  *   negative error value.
582  *
583  * Since: 2.12.0
584  **/
585 int
586 gnutls_pkcs11_init(unsigned int flags, const char *deprecated_config_file)
587 {
588         int ret = 0;
589
590         if (init != 0) {
591                 init++;
592                 return 0;
593         }
594         init++;
595
596         p11_kit_pin_register_callback(P11_KIT_PIN_FALLBACK,
597                                       p11_kit_pin_file_callback, NULL,
598                                       NULL);
599
600         if (flags == GNUTLS_PKCS11_FLAG_MANUAL)
601                 return 0;
602         else if (flags & GNUTLS_PKCS11_FLAG_AUTO) {
603                 if (deprecated_config_file == NULL)
604                         ret = auto_load();
605
606                 compat_load(deprecated_config_file);
607
608                 return ret;
609         }
610
611         return 0;
612 }
613
614 /**
615  * gnutls_pkcs11_reinit:
616  *
617  * This function will reinitialize the PKCS 11 subsystem in gnutls. 
618  * This is required by PKCS 11 when an application uses fork(). The
619  * reinitialization function must be called on the child.
620  *
621  * Note that since GnuTLS 3.3.0, the reinitialization of the PKCS #11
622  * subsystem occurs automatically after fork.
623  *
624  * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
625  *   negative error value.
626  *
627  * Since: 3.0
628  **/
629 int gnutls_pkcs11_reinit(void)
630 {
631         unsigned i;
632         ck_rv_t rv;
633
634         /* make sure that we don't call more than once after a fork */
635         if (init_pid == getpid())
636                 return 0;
637
638         for (i = 0; i < active_providers; i++) {
639                 if (providers[i].module != NULL) {
640                         rv = p11_kit_module_initialize(providers
641                                                        [i].module);
642                         if (rv != CKR_OK) {
643                                 providers[i].active = 1;
644                         } else {
645                                 providers[i].active = 0;
646                                 _gnutls_debug_log
647                                     ("Cannot re-initialize registered module '%s': %s\n",
648                                      providers[i].info.library_description,
649                                      p11_kit_strerror(rv));
650                         }
651                 }
652         }
653 #ifdef HAVE_GETPID
654         init_pid = getpid();
655 #endif
656
657         return 0;
658 }
659
660 /**
661  * gnutls_pkcs11_deinit:
662  *
663  * This function will deinitialize the PKCS 11 subsystem in gnutls.
664  * This function is only needed if you need to deinitialize the
665  * subsystem without calling gnutls_global_deinit().
666  *
667  * Since: 2.12.0
668  **/
669 void gnutls_pkcs11_deinit(void)
670 {
671         unsigned int i;
672
673         if (init == 0)
674                 return;
675
676         init--;
677         if (init > 0)
678                 return;
679
680         for (i = 0; i < active_providers; i++) {
681                 if (providers[i].active)
682                         p11_kit_module_finalize(providers[i].module);
683                 p11_kit_module_release(providers[i].module);
684         }
685         active_providers = 0;
686         providers_initialized = 0;
687
688         gnutls_pkcs11_set_pin_function(NULL, NULL);
689         gnutls_pkcs11_set_token_function(NULL, NULL);
690         p11_kit_pin_unregister_callback(P11_KIT_PIN_FALLBACK,
691                                         p11_kit_pin_file_callback, NULL);
692 }
693
694 /**
695  * gnutls_pkcs11_set_token_function:
696  * @fn: The token callback
697  * @userdata: data to be supplied to callback
698  *
699  * This function will set a callback function to be used when a token
700  * needs to be inserted to continue PKCS 11 operations.
701  *
702  * Since: 2.12.0
703  **/
704 void
705 gnutls_pkcs11_set_token_function(gnutls_pkcs11_token_callback_t fn,
706                                  void *userdata)
707 {
708         _gnutls_token_func = fn;
709         _gnutls_token_data = userdata;
710 }
711
712 int pkcs11_url_to_info(const char *url, struct p11_kit_uri **info)
713 {
714         int allocated = 0;
715         int ret;
716
717         if (*info == NULL) {
718                 *info = p11_kit_uri_new();
719                 if (*info == NULL) {
720                         gnutls_assert();
721                         return GNUTLS_E_MEMORY_ERROR;
722                 }
723                 allocated = 1;
724         }
725
726         ret = p11_kit_uri_parse(url, P11_KIT_URI_FOR_ANY, *info);
727         if (ret < 0) {
728                 if (allocated) {
729                         p11_kit_uri_free(*info);
730                         *info = NULL;
731                 }
732                 gnutls_assert();
733                 return ret == P11_KIT_URI_NO_MEMORY ?
734                     GNUTLS_E_MEMORY_ERROR : GNUTLS_E_PARSING_ERROR;
735         }
736
737         return 0;
738 }
739
740 int
741 pkcs11_info_to_url(struct p11_kit_uri *info,
742                    gnutls_pkcs11_url_type_t detailed, char **url)
743 {
744         p11_kit_uri_type_t type = 0;
745         int ret;
746
747         switch (detailed) {
748         case GNUTLS_PKCS11_URL_GENERIC:
749                 type = P11_KIT_URI_FOR_OBJECT_ON_TOKEN;
750                 break;
751         case GNUTLS_PKCS11_URL_LIB:
752                 type = P11_KIT_URI_FOR_OBJECT_ON_TOKEN_AND_MODULE;
753                 break;
754         case GNUTLS_PKCS11_URL_LIB_VERSION:
755                 type =
756                     P11_KIT_URI_FOR_OBJECT_ON_TOKEN_AND_MODULE |
757                     P11_KIT_URI_FOR_MODULE_WITH_VERSION;
758                 break;
759         }
760
761         ret = p11_kit_uri_format(info, type, url);
762         if (ret < 0) {
763                 gnutls_assert();
764                 return ret == P11_KIT_URI_NO_MEMORY ?
765                     GNUTLS_E_MEMORY_ERROR : GNUTLS_E_INTERNAL_ERROR;
766         }
767
768         return 0;
769 }
770
771 /**
772  * gnutls_pkcs11_obj_init:
773  * @obj: The structure to be initialized
774  *
775  * This function will initialize a pkcs11 certificate structure.
776  *
777  * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
778  *   negative error value.
779  *
780  * Since: 2.12.0
781  **/
782 int gnutls_pkcs11_obj_init(gnutls_pkcs11_obj_t * obj)
783 {
784         *obj = gnutls_calloc(1, sizeof(struct gnutls_pkcs11_obj_st));
785         if (*obj == NULL) {
786                 gnutls_assert();
787                 return GNUTLS_E_MEMORY_ERROR;
788         }
789
790         (*obj)->info = p11_kit_uri_new();
791         if ((*obj)->info == NULL) {
792                 gnutls_free(*obj);
793                 *obj = NULL;
794                 gnutls_assert();
795                 return GNUTLS_E_MEMORY_ERROR;
796         }
797
798         return 0;
799 }
800
801 /**
802  * gnutls_pkcs11_obj_set_pin_function:
803  * @obj: The object structure
804  * @fn: the callback
805  * @userdata: data associated with the callback
806  *
807  * This function will set a callback function to be used when
808  * required to access the object. This function overrides the global
809  * set using gnutls_pkcs11_set_pin_function().
810  *
811  * Since: 3.1.0
812  **/
813 void
814 gnutls_pkcs11_obj_set_pin_function(gnutls_pkcs11_obj_t obj,
815                                    gnutls_pin_callback_t fn,
816                                    void *userdata)
817 {
818         obj->pin.cb = fn;
819         obj->pin.data = userdata;
820 }
821
822 /**
823  * gnutls_pkcs11_obj_deinit:
824  * @obj: The structure to be initialized
825  *
826  * This function will deinitialize a certificate structure.
827  *
828  * Since: 2.12.0
829  **/
830 void gnutls_pkcs11_obj_deinit(gnutls_pkcs11_obj_t obj)
831 {
832         _gnutls_free_datum(&obj->raw);
833         p11_kit_uri_free(obj->info);
834         free(obj);
835 }
836
837 /**
838  * gnutls_pkcs11_obj_export:
839  * @obj: Holds the object
840  * @output_data: will contain the object data
841  * @output_data_size: holds the size of output_data (and will be
842  *   replaced by the actual size of parameters)
843  *
844  * This function will export the PKCS11 object data.  It is normal for
845  * data to be inaccesible and in that case %GNUTLS_E_INVALID_REQUEST
846  * will be returned.
847  *
848  * If the buffer provided is not long enough to hold the output, then
849  * *output_data_size is updated and GNUTLS_E_SHORT_MEMORY_BUFFER will
850  * be returned.
851  *
852  * Returns: In case of failure a negative error code will be
853  *   returned, and %GNUTLS_E_SUCCESS (0) on success.
854  *
855  * Since: 2.12.0
856  **/
857 int
858 gnutls_pkcs11_obj_export(gnutls_pkcs11_obj_t obj,
859                          void *output_data, size_t * output_data_size)
860 {
861         if (obj == NULL || obj->raw.data == NULL) {
862                 gnutls_assert();
863                 return GNUTLS_E_INVALID_REQUEST;
864         }
865
866         if (output_data == NULL || *output_data_size < obj->raw.size) {
867                 *output_data_size = obj->raw.size;
868                 gnutls_assert();
869                 return GNUTLS_E_SHORT_MEMORY_BUFFER;
870         }
871         *output_data_size = obj->raw.size;
872
873         memcpy(output_data, obj->raw.data, obj->raw.size);
874         return 0;
875 }
876
877 /**
878  * gnutls_pkcs11_obj_export2:
879  * @obj: Holds the object
880  * @out: will contain the object data
881  *
882  * This function will export the PKCS11 object data.  It is normal for
883  * data to be inaccesible and in that case %GNUTLS_E_INVALID_REQUEST
884  * will be returned.
885  *
886  * The output buffer is allocated using gnutls_malloc().
887  *
888  * Returns: In case of failure a negative error code will be
889  *   returned, and %GNUTLS_E_SUCCESS (0) on success.
890  *
891  * Since: 3.1.3
892  **/
893 int
894 gnutls_pkcs11_obj_export2(gnutls_pkcs11_obj_t obj, gnutls_datum_t * out)
895 {
896         if (obj == NULL || obj->raw.data == NULL) {
897                 gnutls_assert();
898                 return GNUTLS_E_INVALID_REQUEST;
899         }
900
901         return _gnutls_set_datum(out, obj->raw.data, obj->raw.size);
902 }
903
904 /**
905  * gnutls_pkcs11_obj_export3:
906  * @obj: Holds the object
907  * @out: will contain the object data
908  * @fmt: The format of the exported data
909  *
910  * This function will export the PKCS11 object data.  It is normal for
911  * data to be inaccesible and in that case %GNUTLS_E_INVALID_REQUEST
912  * will be returned.
913  *
914  * The output buffer is allocated using gnutls_malloc().
915  *
916  * Returns: In case of failure a negative error code will be
917  *   returned, and %GNUTLS_E_SUCCESS (0) on success.
918  *
919  * Since: 3.2.7
920  **/
921 int
922 gnutls_pkcs11_obj_export3(gnutls_pkcs11_obj_t obj,
923                           gnutls_x509_crt_fmt_t fmt, gnutls_datum_t * out)
924 {
925         int ret;
926
927         if (obj == NULL || obj->raw.data == NULL) {
928                 gnutls_assert();
929                 return GNUTLS_E_INVALID_REQUEST;
930         }
931
932         if (fmt == GNUTLS_X509_FMT_DER)
933                 return _gnutls_set_datum(out, obj->raw.data,
934                                          obj->raw.size);
935         else if (fmt == GNUTLS_X509_FMT_PEM) {
936                 switch (obj->type) {
937                 case GNUTLS_PKCS11_OBJ_X509_CRT:
938                         return
939                             gnutls_pem_base64_encode_alloc(PEM_X509_CERT2,
940                                                            &obj->raw, out);
941                 case GNUTLS_PKCS11_OBJ_PUBKEY:{
942                                 gnutls_pubkey_t pubkey;
943                                 /* more complex */
944                                 ret = gnutls_pubkey_init(&pubkey);
945                                 if (ret < 0)
946                                         return gnutls_assert_val(ret);
947
948                                 ret =
949                                     gnutls_pubkey_import_pkcs11(pubkey,
950                                                                 obj, 0);
951                                 if (ret < 0) {
952                                         gnutls_assert();
953                                         goto pcleanup;
954                                 }
955
956                                 ret =
957                                     gnutls_pubkey_export2(pubkey, fmt,
958                                                           out);
959
960                               pcleanup:
961                                 gnutls_pubkey_deinit(pubkey);
962                                 return ret;
963                         }
964                 default:
965                         return gnutls_pem_base64_encode_alloc("DATA",
966                                                               &obj->raw,
967                                                               out);
968                 }
969         } else
970                 return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
971 }
972
973
974 int
975 pkcs11_find_slot(struct ck_function_list **module, ck_slot_id_t * slot,
976                  struct p11_kit_uri *info, struct token_info *_tinfo)
977 {
978         unsigned int x, z;
979         int ret;
980         unsigned long nslots;
981         ck_slot_id_t slots[MAX_SLOTS];
982         
983         for (x = 0; x < active_providers; x++) {
984                 if (providers[x].active == 0)
985                         continue;
986
987                 nslots = sizeof(slots) / sizeof(slots[0]);
988                 ret = scan_slots(&providers[x], slots, &nslots);
989                 if (ret < 0) {
990                         gnutls_assert();
991                         continue;
992                 }
993
994                 for (z = 0; z < nslots; z++) {
995                         struct token_info tinfo;
996
997                         if (pkcs11_get_token_info
998                             (providers[x].module, slots[z],
999                              &tinfo.tinfo) != CKR_OK) {
1000                                 continue;
1001                         }
1002                         tinfo.sid = slots[z];
1003                         tinfo.prov = &providers[x];
1004
1005                         if (pkcs11_get_slot_info
1006                             (providers[x].module, slots[z],
1007                              &tinfo.sinfo) != CKR_OK) {
1008                                 continue;
1009                         }
1010
1011                         if (!p11_kit_uri_match_token_info
1012                             (info, &tinfo.tinfo)
1013                             || !p11_kit_uri_match_module_info(info,
1014                                                               &providers
1015                                                               [x].info)) {
1016                                 continue;
1017                         }
1018
1019                         /* ok found */
1020                         *module = providers[x].module;
1021                         *slot = slots[z];
1022
1023                         if (_tinfo != NULL)
1024                                 memcpy(_tinfo, &tinfo, sizeof(tinfo));
1025
1026                         return 0;
1027                 }
1028         }
1029
1030         gnutls_assert();
1031         return GNUTLS_E_PKCS11_REQUESTED_OBJECT_NOT_AVAILBLE;
1032 }
1033
1034 int
1035 pkcs11_open_session(struct pkcs11_session_info *sinfo,
1036                     struct pin_info_st *pin_info,
1037                     struct p11_kit_uri *info, unsigned int flags)
1038 {
1039         ck_rv_t rv;
1040         int ret;
1041         ck_session_handle_t pks = 0;
1042         struct ck_function_list *module;
1043         ck_slot_id_t slot;
1044         struct token_info tinfo;
1045         
1046         ret = pkcs11_find_slot(&module, &slot, info, &tinfo);
1047         if (ret < 0) {
1048                 gnutls_assert();
1049                 return ret;
1050         }
1051
1052         rv = (module)->C_OpenSession(slot, ((flags & SESSION_WRITE)
1053                                             ? CKF_RW_SESSION : 0) |
1054                                      CKF_SERIAL_SESSION, NULL, NULL, &pks);
1055         if (rv != CKR_OK) {
1056                 gnutls_assert();
1057                 return pkcs11_rv_to_err(rv);
1058         }
1059
1060         /* ok found */
1061         sinfo->pks = pks;
1062         sinfo->module = module;
1063         sinfo->init = 1;
1064         memcpy(&sinfo->tinfo, &tinfo.tinfo, sizeof(sinfo->tinfo));
1065
1066         if (flags & SESSION_LOGIN) {
1067                 ret =
1068                     pkcs11_login(sinfo, pin_info, &tinfo, info,
1069                                  (flags & SESSION_SO) ? 1 : 0);
1070                 if (ret < 0) {
1071                         gnutls_assert();
1072                         pkcs11_close_session(sinfo);
1073                         return ret;
1074                 }
1075         }
1076
1077         return 0;
1078 }
1079
1080
1081 int
1082 _pkcs11_traverse_tokens(find_func_t find_func, void *input,
1083                         struct p11_kit_uri *info,
1084                         struct pin_info_st *pin_info, unsigned int flags)
1085 {
1086         ck_rv_t rv;
1087         unsigned int found = 0, x, z;
1088         int ret;
1089         ck_session_handle_t pks = 0;
1090         struct pkcs11_session_info sinfo;
1091         struct ck_function_list *module = NULL;
1092         unsigned long nslots;
1093         ck_slot_id_t slots[MAX_SLOTS];
1094
1095         for (x = 0; x < active_providers; x++) {
1096                 if (providers[x].active == 0)
1097                         continue;
1098
1099                 if (flags & SESSION_TRUSTED && providers[x].trusted == 0)
1100                         continue;
1101
1102                 nslots = sizeof(slots) / sizeof(slots[0]);
1103                 ret = scan_slots(&providers[x], slots, &nslots);
1104                 if (ret < 0) {
1105                         gnutls_assert();
1106                         continue;
1107                 }
1108
1109                 module = providers[x].module;
1110                 for (z = 0; z < nslots; z++) {
1111                         struct token_info tinfo;
1112
1113                         if (pkcs11_get_token_info(module, slots[z],
1114                                                   &tinfo.tinfo) != CKR_OK) {
1115                                 continue;
1116                         }
1117                         tinfo.sid = slots[z];
1118                         tinfo.prov = &providers[x];
1119
1120                         if (pkcs11_get_slot_info(module, slots[z],
1121                                                  &tinfo.sinfo) != CKR_OK) {
1122                                 continue;
1123                         }
1124
1125                         if (info != NULL) {
1126                             if (!p11_kit_uri_match_token_info
1127                                 (info, &tinfo.tinfo)
1128                                 || !p11_kit_uri_match_module_info(info,
1129                                                               &providers
1130                                                               [x].info)) {
1131                                 continue;
1132                             }
1133                         }
1134
1135                         rv = (module)->C_OpenSession(slots[z],
1136                                                      ((flags & SESSION_WRITE) ? CKF_RW_SESSION : 0)
1137                                                      | CKF_SERIAL_SESSION,
1138                                                      NULL, NULL, &pks);
1139                         if (rv != CKR_OK) {
1140                                 continue;
1141                         }
1142
1143                         sinfo.module = module;
1144                         sinfo.pks = pks;
1145
1146                         if (flags & SESSION_LOGIN) {
1147                                 ret =
1148                                     pkcs11_login(&sinfo, pin_info, &tinfo,
1149                                                  info, (flags & SESSION_SO) ? 1 :        0);
1150                                 if (ret < 0) {
1151                                         gnutls_assert();
1152                                         return ret;
1153                                 }
1154                         }
1155
1156                         ret =
1157                             find_func(&sinfo, &tinfo, &providers[x].info, input);
1158
1159                         if (ret == 0) {
1160                                 found = 1;
1161                                 goto finish;
1162                         } else {
1163                                 pkcs11_close_session(&sinfo);
1164                                 pks = 0;
1165                         }
1166                 }
1167         }
1168
1169       finish:
1170         /* final call */
1171
1172         if (found == 0) {
1173                 if (module) {
1174                         sinfo.module = module;
1175                         sinfo.pks = pks;
1176                         ret = find_func(&sinfo, NULL, NULL, input);
1177                 } else
1178                         ret =
1179                             gnutls_assert_val
1180                             (GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE);
1181         } else {
1182                 ret = 0;
1183         }
1184
1185         if (pks != 0 && module != NULL) {
1186                 pkcs11_close_session(&sinfo);
1187         }
1188
1189         return ret;
1190 }
1191
1192 /* imports an object from a token to a pkcs11_obj_t structure.
1193  */
1194 static int
1195 pkcs11_obj_import(ck_object_class_t class, gnutls_pkcs11_obj_t obj,
1196                   const gnutls_datum_t * data,
1197                   const gnutls_datum_t * id,
1198                   const gnutls_datum_t * label,
1199                   struct ck_token_info *tinfo, struct ck_info *lib_info)
1200 {
1201         struct ck_attribute attr;
1202         int ret;
1203
1204         switch (class) {
1205         case CKO_CERTIFICATE:
1206                 obj->type = GNUTLS_PKCS11_OBJ_X509_CRT;
1207                 break;
1208         case CKO_PUBLIC_KEY:
1209                 obj->type = GNUTLS_PKCS11_OBJ_PUBKEY;
1210                 break;
1211         case CKO_PRIVATE_KEY:
1212                 obj->type = GNUTLS_PKCS11_OBJ_PRIVKEY;
1213                 break;
1214         case CKO_SECRET_KEY:
1215                 obj->type = GNUTLS_PKCS11_OBJ_SECRET_KEY;
1216                 break;
1217         case CKO_DATA:
1218                 obj->type = GNUTLS_PKCS11_OBJ_DATA;
1219                 break;
1220         default:
1221                 obj->type = GNUTLS_PKCS11_OBJ_UNKNOWN;
1222         }
1223
1224         attr.type = CKA_CLASS;
1225         attr.value = &class;
1226         attr.value_len = sizeof(class);
1227         ret = p11_kit_uri_set_attribute(obj->info, &attr);
1228         if (ret < 0) {
1229                 gnutls_assert();
1230                 return GNUTLS_E_MEMORY_ERROR;
1231         }
1232
1233         if (data && data->data) {
1234                 ret = _gnutls_set_datum(&obj->raw, data->data, data->size);
1235                 if (ret < 0) {
1236                         gnutls_assert();
1237                         return ret;
1238                 }
1239         }
1240
1241         /* copy the token and library info into the uri */
1242         memcpy(p11_kit_uri_get_token_info(obj->info), tinfo,
1243                sizeof(struct ck_token_info));
1244         memcpy(p11_kit_uri_get_module_info(obj->info), lib_info,
1245                sizeof(struct ck_info));
1246
1247         if (label && label->data) {
1248                 attr.type = CKA_LABEL;
1249                 attr.value = label->data;
1250                 attr.value_len = label->size;
1251                 ret = p11_kit_uri_set_attribute(obj->info, &attr);
1252                 if (ret < 0) {
1253                         gnutls_assert();
1254                         return GNUTLS_E_MEMORY_ERROR;
1255                 }
1256         }
1257
1258         if (id && id->data) {
1259                 attr.type = CKA_ID;
1260                 attr.value = id->data;
1261                 attr.value_len = id->size;
1262                 ret = p11_kit_uri_set_attribute(obj->info, &attr);
1263                 if (ret < 0) {
1264                         gnutls_assert();
1265                         return GNUTLS_E_MEMORY_ERROR;
1266                 }
1267         }
1268
1269         return 0;
1270 }
1271
1272 #define MAX_PK_PARAM_SIZE 2048
1273
1274 int pkcs11_read_pubkey(struct ck_function_list *module,
1275                        ck_session_handle_t pks, ck_object_handle_t obj,
1276                        ck_key_type_t key_type, gnutls_datum_t * pubkey)
1277 {
1278         struct ck_attribute a[4];
1279         uint8_t *tmp1;
1280         uint8_t *tmp2 = NULL;
1281         size_t tmp1_size, tmp2_size;
1282         int ret;
1283         
1284         tmp1_size = tmp2_size = MAX_PK_PARAM_SIZE;
1285         tmp1 = gnutls_malloc(tmp1_size);
1286         if (tmp1 == NULL)
1287                 return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
1288
1289         tmp2 = gnutls_malloc(tmp2_size);
1290         if (tmp2 == NULL) {
1291                 ret = gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
1292                 goto cleanup;
1293         }
1294
1295         switch (key_type) {
1296         case CKK_RSA:
1297                 a[0].type = CKA_MODULUS;
1298                 a[0].value = tmp1;
1299                 a[0].value_len = tmp1_size;
1300                 a[1].type = CKA_PUBLIC_EXPONENT;
1301                 a[1].value = tmp2;
1302                 a[1].value_len = tmp2_size;
1303
1304                 if (pkcs11_get_attribute_value(module, pks, obj, a, 2) ==
1305                     CKR_OK) {
1306
1307                         pubkey[0].data = a[0].value;
1308                         pubkey[0].size = a[0].value_len;
1309
1310                         pubkey[1].data = a[1].value;
1311                         pubkey[1].size = a[1].value_len;
1312                 } else {
1313                         gnutls_assert();
1314                         ret = GNUTLS_E_PKCS11_ERROR;
1315                         goto cleanup;
1316                 }
1317                 break;
1318         case CKK_DSA:
1319                 a[0].type = CKA_PRIME;
1320                 a[0].value = tmp1;
1321                 a[0].value_len = tmp1_size;
1322                 a[1].type = CKA_SUBPRIME;
1323                 a[1].value = tmp2;
1324                 a[1].value_len = tmp2_size;
1325
1326                 if (pkcs11_get_attribute_value(module, pks, obj, a, 2) ==
1327                     CKR_OK) {
1328                         ret =
1329                             _gnutls_set_datum(&pubkey[0], a[0].value,
1330                                               a[0].value_len);
1331
1332                         if (ret >= 0)
1333                                 ret =
1334                                     _gnutls_set_datum(&pubkey
1335                                                       [1], a[1].value,
1336                                                       a[1].value_len);
1337
1338                         if (ret < 0) {
1339                                 gnutls_assert();
1340                                 _gnutls_free_datum(&pubkey[1]);
1341                                 _gnutls_free_datum(&pubkey[0]);
1342                                 ret = GNUTLS_E_MEMORY_ERROR;
1343                                 goto cleanup;
1344                         }
1345                 } else {
1346                         gnutls_assert();
1347                         ret = GNUTLS_E_PKCS11_ERROR;
1348                         goto cleanup;
1349                 }
1350
1351                 a[0].type = CKA_BASE;
1352                 a[0].value = tmp1;
1353                 a[0].value_len = tmp1_size;
1354                 a[1].type = CKA_VALUE;
1355                 a[1].value = tmp2;
1356                 a[1].value_len = tmp2_size;
1357
1358                 if (pkcs11_get_attribute_value(module, pks, obj, a, 2) ==
1359                     CKR_OK) {
1360                         pubkey[2].data = a[0].value;
1361                         pubkey[2].size = a[0].value_len;
1362
1363                         pubkey[3].data = a[1].value;
1364                         pubkey[3].size = a[1].value_len;
1365
1366                 } else {
1367                         gnutls_assert();
1368                         ret = GNUTLS_E_PKCS11_ERROR;
1369                         goto cleanup;
1370                 }
1371                 break;
1372         case CKK_ECDSA:
1373                 a[0].type = CKA_EC_PARAMS;
1374                 a[0].value = tmp1;
1375                 a[0].value_len = tmp1_size;
1376                 a[1].type = CKA_EC_POINT;
1377                 a[1].value = tmp2;
1378                 a[1].value_len = tmp2_size;
1379
1380                 if (pkcs11_get_attribute_value(module, pks, obj, a, 2) ==
1381                     CKR_OK) {
1382
1383                         pubkey[0].data = a[0].value;
1384                         pubkey[0].size = a[0].value_len;
1385
1386                         pubkey[1].data = a[1].value;
1387                         pubkey[1].size = a[1].value_len;
1388                 } else {
1389                         gnutls_assert();
1390                         ret = GNUTLS_E_PKCS11_ERROR;
1391                         goto cleanup;
1392                 }
1393
1394                 break;
1395         default:
1396                 ret = gnutls_assert_val(GNUTLS_E_UNIMPLEMENTED_FEATURE);
1397                 goto cleanup;
1398         }
1399
1400         return 0;
1401
1402 cleanup:
1403         gnutls_free(tmp1);
1404         gnutls_free(tmp2);
1405         
1406         return ret;
1407 }
1408
1409 static int
1410 pkcs11_obj_import_pubkey(struct ck_function_list *module,
1411                          ck_session_handle_t pks,
1412                          ck_object_handle_t obj,
1413                          gnutls_pkcs11_obj_t crt,
1414                          const gnutls_datum_t * id,
1415                          const gnutls_datum_t * label,
1416                          struct ck_token_info *tinfo,
1417                          struct ck_info *lib_info)
1418 {
1419         struct ck_attribute a[4];
1420         ck_key_type_t key_type;
1421         int ret;
1422         ck_bool_t tval;
1423
1424         a[0].type = CKA_KEY_TYPE;
1425         a[0].value = &key_type;
1426         a[0].value_len = sizeof(key_type);
1427
1428         if (pkcs11_get_attribute_value(module, pks, obj, a, 1) == CKR_OK) {
1429                 crt->pk_algorithm = mech_to_pk(key_type);
1430
1431                 ret =
1432                     pkcs11_read_pubkey(module, pks, obj, key_type,
1433                                        crt->pubkey);
1434                 if (ret < 0)
1435                         return gnutls_assert_val(ret);
1436         }
1437
1438         /* read key usage flags */
1439         a[0].type = CKA_ENCRYPT;
1440         a[0].value = &tval;
1441         a[0].value_len = sizeof(tval);
1442
1443         if (pkcs11_get_attribute_value(module, pks, obj, a, 1) == CKR_OK) {
1444                 if (tval != 0) {
1445                         crt->key_usage |= GNUTLS_KEY_DATA_ENCIPHERMENT;
1446                 }
1447         }
1448
1449         a[0].type = CKA_VERIFY;
1450         a[0].value = &tval;
1451         a[0].value_len = sizeof(tval);
1452
1453         if (pkcs11_get_attribute_value(module, pks, obj, a, 1) == CKR_OK) {
1454                 if (tval != 0) {
1455                         crt->key_usage |= GNUTLS_KEY_DIGITAL_SIGNATURE |
1456                             GNUTLS_KEY_KEY_CERT_SIGN | GNUTLS_KEY_CRL_SIGN
1457                             | GNUTLS_KEY_NON_REPUDIATION;
1458                 }
1459         }
1460
1461         a[0].type = CKA_VERIFY_RECOVER;
1462         a[0].value = &tval;
1463         a[0].value_len = sizeof(tval);
1464
1465         if (pkcs11_get_attribute_value(module, pks, obj, a, 1) == CKR_OK) {
1466                 if (tval != 0) {
1467                         crt->key_usage |= GNUTLS_KEY_DIGITAL_SIGNATURE |
1468                             GNUTLS_KEY_KEY_CERT_SIGN | GNUTLS_KEY_CRL_SIGN
1469                             | GNUTLS_KEY_NON_REPUDIATION;
1470                 }
1471         }
1472
1473         a[0].type = CKA_DERIVE;
1474         a[0].value = &tval;
1475         a[0].value_len = sizeof(tval);
1476
1477         if (pkcs11_get_attribute_value(module, pks, obj, a, 1) == CKR_OK) {
1478                 if (tval != 0) {
1479                         crt->key_usage |= GNUTLS_KEY_KEY_AGREEMENT;
1480                 }
1481         }
1482
1483         a[0].type = CKA_WRAP;
1484         a[0].value = &tval;
1485         a[0].value_len = sizeof(tval);
1486
1487         if (pkcs11_get_attribute_value(module, pks, obj, a, 1) == CKR_OK) {
1488                 if (tval != 0) {
1489                         crt->key_usage |= GNUTLS_KEY_KEY_ENCIPHERMENT;
1490                 }
1491         }
1492
1493         return pkcs11_obj_import(CKO_PUBLIC_KEY, crt, NULL, id, label,
1494                                  tinfo, lib_info);
1495 }
1496
1497 static int
1498 find_obj_url(struct pkcs11_session_info *sinfo,
1499              struct token_info *info, struct ck_info *lib_info,
1500              void *input)
1501 {
1502         struct find_url_data_st *find_data = input;
1503         struct ck_attribute a[4];
1504         struct ck_attribute *attr;
1505         ck_object_class_t class = -1;
1506         ck_certificate_type_t type = (ck_certificate_type_t) - 1;
1507         ck_rv_t rv;
1508         ck_object_handle_t obj;
1509         unsigned long count, a_vals;
1510         int found = 0, ret;
1511         uint8_t *cert_data = NULL;
1512         char label_tmp[PKCS11_LABEL_SIZE];
1513         char id_tmp[PKCS11_ID_SIZE];
1514
1515         if (info == NULL) {     /* we don't support multiple calls */
1516                 gnutls_assert();
1517                 return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
1518         }
1519
1520         /* do not bother reading the token if basic fields do not match
1521          */
1522         if (!p11_kit_uri_match_token_info
1523             (find_data->crt->info, &info->tinfo)
1524             || !p11_kit_uri_match_module_info(find_data->crt->info,
1525                                               lib_info)) {
1526                 gnutls_assert();
1527                 return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
1528         }
1529
1530         a_vals = 0;
1531         attr = p11_kit_uri_get_attribute(find_data->crt->info, CKA_ID);
1532         if (attr) {
1533                 memcpy(a + a_vals, attr, sizeof(struct ck_attribute));
1534                 a_vals++;
1535         }
1536
1537         attr = p11_kit_uri_get_attribute(find_data->crt->info, CKA_LABEL);
1538         if (attr) {
1539                 memcpy(a + a_vals, attr, sizeof(struct ck_attribute));
1540                 a_vals++;
1541         }
1542
1543         if (!a_vals) {
1544                 gnutls_assert();
1545                 return GNUTLS_E_INVALID_REQUEST;
1546         }
1547
1548         /* search the token for the id */
1549
1550         cert_data = gnutls_malloc(MAX_CERT_SIZE);
1551         if (cert_data == NULL) {
1552                 gnutls_assert();
1553                 return GNUTLS_E_MEMORY_ERROR;
1554         }
1555
1556         /* Find objects with given class and type */
1557         attr = p11_kit_uri_get_attribute(find_data->crt->info, CKA_CLASS);
1558         if (attr) {
1559                 if (attr->value
1560                     && attr->value_len == sizeof(ck_object_class_t))
1561                         class = *((ck_object_class_t *) attr->value);
1562                 if (class == CKO_CERTIFICATE)
1563                         type = CKC_X_509;
1564                 memcpy(a + a_vals, attr, sizeof(struct ck_attribute));
1565                 a_vals++;
1566         }
1567
1568         if (type != (ck_certificate_type_t) - 1) {
1569                 a[a_vals].type = CKA_CERTIFICATE_TYPE;
1570                 a[a_vals].value = &type;
1571                 a[a_vals].value_len = sizeof type;
1572                 a_vals++;
1573         }
1574
1575         rv = pkcs11_find_objects_init(sinfo->module, sinfo->pks, a,
1576                                       a_vals);
1577         if (rv != CKR_OK) {
1578                 gnutls_assert();
1579                 _gnutls_debug_log("p11: FindObjectsInit failed.\n");
1580                 ret = pkcs11_rv_to_err(rv);
1581                 goto cleanup;
1582         }
1583
1584         while (pkcs11_find_objects
1585                (sinfo->module, sinfo->pks, &obj, 1, &count) == CKR_OK
1586                && count == 1) {
1587                 a[0].type = CKA_VALUE;
1588                 a[0].value = cert_data;
1589                 a[0].value_len = MAX_CERT_SIZE;
1590                 a[1].type = CKA_LABEL;
1591                 a[1].value = label_tmp;
1592                 a[1].value_len = sizeof(label_tmp);
1593                 a[2].type = CKA_ID;
1594                 a[2].value = id_tmp;
1595                 a[2].value_len = sizeof(id_tmp);
1596
1597                 if (pkcs11_get_attribute_value
1598                     (sinfo->module, sinfo->pks, obj, a, 3) == CKR_OK) {
1599                         gnutls_datum_t id = { a[2].value, a[2].value_len };
1600                         gnutls_datum_t data =
1601                             { a[0].value, a[0].value_len };
1602                         gnutls_datum_t label =
1603                             { a[1].value, a[1].value_len };
1604
1605                         if (class == CKO_PUBLIC_KEY) {
1606                                 ret =
1607                                     pkcs11_obj_import_pubkey(sinfo->module,
1608                                                              sinfo->pks,
1609                                                              obj,
1610                                                              find_data->crt,
1611                                                              &id, &label,
1612                                                              &info->tinfo,
1613                                                              lib_info);
1614                         } else {
1615                                 ret =
1616                                     pkcs11_obj_import(class,
1617                                                       find_data->crt,
1618                                                       &data, &id, &label,
1619                                                       &info->tinfo,
1620                                                       lib_info);
1621                         }
1622                         if (ret < 0) {
1623                                 gnutls_assert();
1624                                 goto cleanup;
1625                         }
1626
1627                         found = 1;
1628                         break;
1629                 } else {
1630                         _gnutls_debug_log
1631                             ("p11: Skipped cert, missing attrs.\n");
1632                 }
1633         }
1634
1635         if (found == 0) {
1636                 gnutls_assert();
1637                 ret = GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
1638         } else {
1639                 ret = 0;
1640         }
1641
1642       cleanup:
1643         gnutls_free(cert_data);
1644         pkcs11_find_objects_final(sinfo);
1645
1646         return ret;
1647 }
1648
1649 unsigned int pkcs11_obj_flags_to_int(unsigned int flags)
1650 {
1651         unsigned int ret_flags = 0;
1652
1653         if (flags & GNUTLS_PKCS11_OBJ_FLAG_LOGIN)
1654                 ret_flags |= SESSION_LOGIN;
1655         if (flags & GNUTLS_PKCS11_OBJ_FLAG_LOGIN_SO)
1656                 ret_flags |= SESSION_LOGIN | SESSION_SO;
1657         if (flags & GNUTLS_PKCS11_OBJ_FLAG_PRESENT_IN_TRUSTED_MODULE)
1658                 ret_flags |= SESSION_TRUSTED;
1659
1660         return ret_flags;
1661 }
1662
1663 /**
1664  * gnutls_pkcs11_obj_import_url:
1665  * @obj: The structure to store the object
1666  * @url: a PKCS 11 url identifying the key
1667  * @flags: One of GNUTLS_PKCS11_OBJ_* flags
1668  *
1669  * This function will "import" a PKCS 11 URL identifying an object (e.g. certificate)
1670  * to the #gnutls_pkcs11_obj_t structure. This does not involve any
1671  * parsing (such as X.509 or OpenPGP) since the #gnutls_pkcs11_obj_t is
1672  * format agnostic. Only data are transferred.
1673  *
1674  * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
1675  *   negative error value.
1676  *
1677  * Since: 2.12.0
1678  **/
1679 int
1680 gnutls_pkcs11_obj_import_url(gnutls_pkcs11_obj_t obj, const char *url,
1681                              unsigned int flags)
1682 {
1683         int ret;
1684         struct find_url_data_st find_data;
1685
1686         PKCS11_CHECK_INIT;
1687
1688         /* fill in the find data structure */
1689         find_data.crt = obj;
1690
1691         ret = pkcs11_url_to_info(url, &obj->info);
1692         if (ret < 0) {
1693                 gnutls_assert();
1694                 return ret;
1695         }
1696
1697         ret =
1698             _pkcs11_traverse_tokens(find_obj_url, &find_data, obj->info,
1699                                     &obj->pin,
1700                                     pkcs11_obj_flags_to_int(flags));
1701
1702         if (ret < 0) {
1703                 gnutls_assert();
1704                 return ret;
1705         }
1706
1707         return 0;
1708 }
1709
1710 static int
1711 find_token_num(struct pkcs11_session_info *sinfo,
1712                struct token_info *tinfo,
1713                struct ck_info *lib_info, void *input)
1714 {
1715         struct find_token_num *find_data = input;
1716
1717         if (tinfo == NULL) {    /* we don't support multiple calls */
1718                 gnutls_assert();
1719                 return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
1720         }
1721
1722         if (find_data->current == find_data->seq) {
1723                 memcpy(p11_kit_uri_get_token_info(find_data->info),
1724                        &tinfo->tinfo, sizeof(struct ck_token_info));
1725                 memcpy(p11_kit_uri_get_module_info(find_data->info),
1726                        lib_info, sizeof(struct ck_info));
1727                 return 0;
1728         }
1729
1730         find_data->current++;
1731         /* search the token for the id */
1732
1733
1734         return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;   /* non zero is enough */
1735 }
1736
1737 /**
1738  * gnutls_pkcs11_token_get_url:
1739  * @seq: sequence number starting from 0
1740  * @detailed: non zero if a detailed URL is required
1741  * @url: will contain an allocated url
1742  *
1743  * This function will return the URL for each token available
1744  * in system. The url has to be released using gnutls_free()
1745  *
1746  * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned,
1747  * %GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE if the sequence number
1748  * exceeds the available tokens, otherwise a negative error value.
1749  *
1750  * Since: 2.12.0
1751  **/
1752 int
1753 gnutls_pkcs11_token_get_url(unsigned int seq,
1754                             gnutls_pkcs11_url_type_t detailed, char **url)
1755 {
1756         int ret;
1757         struct find_token_num tn;
1758
1759         PKCS11_CHECK_INIT;
1760
1761         memset(&tn, 0, sizeof(tn));
1762         tn.seq = seq;
1763         tn.info = p11_kit_uri_new();
1764
1765         ret = _pkcs11_traverse_tokens(find_token_num, &tn, NULL, NULL, 0);
1766         if (ret < 0) {
1767                 p11_kit_uri_free(tn.info);
1768                 gnutls_assert();
1769                 return ret;
1770         }
1771
1772         ret = pkcs11_info_to_url(tn.info, detailed, url);
1773         p11_kit_uri_free(tn.info);
1774
1775         if (ret < 0) {
1776                 gnutls_assert();
1777                 return ret;
1778         }
1779
1780         return 0;
1781
1782 }
1783
1784 /**
1785  * gnutls_pkcs11_token_get_info:
1786  * @url: should contain a PKCS 11 URL
1787  * @ttype: Denotes the type of information requested
1788  * @output: where output will be stored
1789  * @output_size: contains the maximum size of the output and will be overwritten with actual
1790  *
1791  * This function will return information about the PKCS 11 token such
1792  * as the label, id, etc.
1793  *
1794  * Returns: %GNUTLS_E_SUCCESS (0) on success or a negative error code
1795  * on error.
1796  *
1797  * Since: 2.12.0
1798  **/
1799 int
1800 gnutls_pkcs11_token_get_info(const char *url,
1801                              gnutls_pkcs11_token_info_t ttype,
1802                              void *output, size_t * output_size)
1803 {
1804         struct p11_kit_uri *info = NULL;
1805         const uint8_t *str;
1806         size_t str_max;
1807         size_t len;
1808         int ret;
1809
1810         PKCS11_CHECK_INIT;
1811
1812         ret = pkcs11_url_to_info(url, &info);
1813         if (ret < 0) {
1814                 gnutls_assert();
1815                 return ret;
1816         }
1817
1818         switch (ttype) {
1819         case GNUTLS_PKCS11_TOKEN_LABEL:
1820                 str = p11_kit_uri_get_token_info(info)->label;
1821                 str_max = 32;
1822                 break;
1823         case GNUTLS_PKCS11_TOKEN_SERIAL:
1824                 str = p11_kit_uri_get_token_info(info)->serial_number;
1825                 str_max = 16;
1826                 break;
1827         case GNUTLS_PKCS11_TOKEN_MANUFACTURER:
1828                 str = p11_kit_uri_get_token_info(info)->manufacturer_id;
1829                 str_max = 32;
1830                 break;
1831         case GNUTLS_PKCS11_TOKEN_MODEL:
1832                 str = p11_kit_uri_get_token_info(info)->model;
1833                 str_max = 16;
1834                 break;
1835         default:
1836                 p11_kit_uri_free(info);
1837                 gnutls_assert();
1838                 return GNUTLS_E_INVALID_REQUEST;
1839         }
1840
1841         len = p11_kit_space_strlen(str, str_max);
1842
1843         if (len + 1 > *output_size) {
1844                 *output_size = len + 1;
1845                 return GNUTLS_E_SHORT_MEMORY_BUFFER;
1846         }
1847
1848         memcpy(output, str, len);
1849         ((char *) output)[len] = '\0';
1850
1851         *output_size = len;
1852
1853         ret = 0;
1854
1855         p11_kit_uri_free(info);
1856         return ret;
1857 }
1858
1859 /**
1860  * gnutls_pkcs11_obj_export_url:
1861  * @obj: Holds the PKCS 11 certificate
1862  * @detailed: non zero if a detailed URL is required
1863  * @url: will contain an allocated url
1864  *
1865  * This function will export a URL identifying the given certificate.
1866  *
1867  * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
1868  *   negative error value.
1869  *
1870  * Since: 2.12.0
1871  **/
1872 int
1873 gnutls_pkcs11_obj_export_url(gnutls_pkcs11_obj_t obj,
1874                              gnutls_pkcs11_url_type_t detailed, char **url)
1875 {
1876         int ret;
1877
1878         ret = pkcs11_info_to_url(obj->info, detailed, url);
1879         if (ret < 0) {
1880                 gnutls_assert();
1881                 return ret;
1882         }
1883
1884         return 0;
1885 }
1886
1887 /**
1888  * gnutls_pkcs11_obj_get_type:
1889  * @obj: Holds the PKCS 11 object
1890  *
1891  * This function will return the type of the certificate being
1892  * stored in the structure.
1893  *
1894  * Returns: The type of the certificate.
1895  *
1896  * Since: 2.12.0
1897  **/
1898 gnutls_pkcs11_obj_type_t
1899 gnutls_pkcs11_obj_get_type(gnutls_pkcs11_obj_t obj)
1900 {
1901         return obj->type;
1902 }
1903
1904 static int
1905 retrieve_pin_from_source(const char *pinfile,
1906                          struct ck_token_info *token_info, int attempts,
1907                          ck_user_type_t user_type,
1908                          struct p11_kit_pin **pin)
1909 {
1910         unsigned int flags = 0;
1911         struct p11_kit_uri *token_uri;
1912         struct p11_kit_pin *result;
1913         char *label;
1914
1915         label =
1916             p11_kit_space_strdup(token_info->label,
1917                                  sizeof(token_info->label));
1918         if (label == NULL) {
1919                 gnutls_assert();
1920                 return GNUTLS_E_MEMORY_ERROR;
1921         }
1922
1923         token_uri = p11_kit_uri_new();
1924         if (token_uri == NULL) {
1925                 free(label);
1926                 gnutls_assert();
1927                 return GNUTLS_E_MEMORY_ERROR;
1928         }
1929
1930         memcpy(p11_kit_uri_get_token_info(token_uri), token_info,
1931                sizeof(struct ck_token_info));
1932
1933         if (attempts)
1934                 flags |= P11_KIT_PIN_FLAGS_RETRY;
1935         if (user_type == CKU_USER) {
1936                 flags |= P11_KIT_PIN_FLAGS_USER_LOGIN;
1937                 if (token_info->flags & CKF_USER_PIN_COUNT_LOW)
1938                         flags |= P11_KIT_PIN_FLAGS_MANY_TRIES;
1939                 if (token_info->flags & CKF_USER_PIN_FINAL_TRY)
1940                         flags |= P11_KIT_PIN_FLAGS_FINAL_TRY;
1941         } else if (user_type == CKU_SO) {
1942                 flags |= P11_KIT_PIN_FLAGS_SO_LOGIN;
1943                 if (token_info->flags & CKF_SO_PIN_COUNT_LOW)
1944                         flags |= P11_KIT_PIN_FLAGS_MANY_TRIES;
1945                 if (token_info->flags & CKF_SO_PIN_FINAL_TRY)
1946                         flags |= P11_KIT_PIN_FLAGS_FINAL_TRY;
1947         } else if (user_type == CKU_CONTEXT_SPECIFIC) {
1948                 flags |= P11_KIT_PIN_FLAGS_CONTEXT_LOGIN;
1949         }
1950
1951         result = p11_kit_pin_request(pinfile, token_uri, label, flags);
1952         p11_kit_uri_free(token_uri);
1953         free(label);
1954
1955         if (result == NULL) {
1956                 gnutls_assert();
1957                 return GNUTLS_E_PKCS11_PIN_ERROR;
1958         }
1959
1960         *pin = result;
1961         return 0;
1962 }
1963
1964 static int
1965 retrieve_pin_from_callback(const struct pin_info_st *pin_info,
1966                            struct ck_token_info *token_info,
1967                            int attempts, ck_user_type_t user_type,
1968                            struct p11_kit_pin **pin)
1969 {
1970         char pin_value[GNUTLS_PKCS11_MAX_PIN_LEN];
1971         unsigned int flags = 0;
1972         char *token_str;
1973         char *label;
1974         struct p11_kit_uri *token_uri;
1975         int ret = 0;
1976
1977         label =
1978             p11_kit_space_strdup(token_info->label,
1979                                  sizeof(token_info->label));
1980         if (label == NULL) {
1981                 gnutls_assert();
1982                 return GNUTLS_E_MEMORY_ERROR;
1983         }
1984
1985         token_uri = p11_kit_uri_new();
1986         if (token_uri == NULL) {
1987                 free(label);
1988                 gnutls_assert();
1989                 return GNUTLS_E_MEMORY_ERROR;
1990         }
1991
1992         memcpy(p11_kit_uri_get_token_info(token_uri), token_info,
1993                sizeof(struct ck_token_info));
1994         ret = pkcs11_info_to_url(token_uri, 1, &token_str);
1995         p11_kit_uri_free(token_uri);
1996
1997         if (ret < 0) {
1998                 free(label);
1999                 gnutls_assert();
2000                 return GNUTLS_E_MEMORY_ERROR;
2001         }
2002
2003         if (user_type == CKU_USER) {
2004                 flags |= GNUTLS_PIN_USER;
2005                 if (token_info->flags & CKF_USER_PIN_COUNT_LOW)
2006                         flags |= GNUTLS_PIN_COUNT_LOW;
2007                 if (token_info->flags & CKF_USER_PIN_FINAL_TRY)
2008                         flags |= GNUTLS_PIN_FINAL_TRY;
2009         } else if (user_type == CKU_SO) {
2010                 flags |= GNUTLS_PIN_SO;
2011                 if (token_info->flags & CKF_SO_PIN_COUNT_LOW)
2012                         flags |= GNUTLS_PIN_COUNT_LOW;
2013                 if (token_info->flags & CKF_SO_PIN_FINAL_TRY)
2014                         flags |= GNUTLS_PIN_FINAL_TRY;
2015         }
2016
2017         if (attempts > 0)
2018                 flags |= GNUTLS_PIN_WRONG;
2019
2020         if (pin_info && pin_info->cb)
2021                 ret =
2022                     pin_info->cb(pin_info->data, attempts,
2023                                  (char *) token_str, label, flags,
2024                                  pin_value, GNUTLS_PKCS11_MAX_PIN_LEN);
2025         else if (_gnutls_pin_func)
2026                 ret =
2027                     _gnutls_pin_func(_gnutls_pin_data, attempts,
2028                                      (char *) token_str, label, flags,
2029                                      pin_value, GNUTLS_PKCS11_MAX_PIN_LEN);
2030         else
2031                 ret = gnutls_assert_val(GNUTLS_E_PKCS11_PIN_ERROR);
2032
2033         free(token_str);
2034         free(label);
2035
2036         if (ret < 0)
2037                 return gnutls_assert_val(GNUTLS_E_PKCS11_PIN_ERROR);
2038
2039         *pin = p11_kit_pin_new_for_string(pin_value);
2040
2041         if (*pin == NULL)
2042                 return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
2043
2044         return 0;
2045 }
2046
2047 static int
2048 retrieve_pin(struct pin_info_st *pin_info, struct p11_kit_uri *info,
2049              struct ck_token_info *token_info, int attempts,
2050              ck_user_type_t user_type, struct p11_kit_pin **pin)
2051 {
2052         const char *pinfile;
2053         int ret = GNUTLS_E_PKCS11_PIN_ERROR;
2054
2055         *pin = NULL;
2056
2057         /* Check if a pinfile is specified, and use that if possible */
2058         pinfile = p11_kit_uri_get_pinfile(info);
2059         if (pinfile != NULL) {
2060                 _gnutls_debug_log("p11: Using pinfile to retrieve PIN\n");
2061                 ret =
2062                     retrieve_pin_from_source(pinfile, token_info, attempts,
2063                                              user_type, pin);
2064         }
2065
2066         /* The global gnutls pin callback */
2067         if (ret < 0)
2068                 ret =
2069                     retrieve_pin_from_callback(pin_info, token_info,
2070                                                attempts, user_type, pin);
2071
2072         /* Otherwise, PIN entry is necessary for login, so fail if there's
2073          * no callback. */
2074
2075         if (ret < 0) {
2076                 gnutls_assert();
2077                 _gnutls_debug_log
2078                     ("p11: No suitable pin callback but login required.\n");
2079         }
2080
2081         return ret;
2082 }
2083
2084 int
2085 pkcs11_login(struct pkcs11_session_info *sinfo,
2086              struct pin_info_st *pin_info,
2087              const struct token_info *tokinfo, struct p11_kit_uri *info,
2088              int so)
2089 {
2090         struct ck_session_info session_info;
2091         int attempt = 0, ret;
2092         ck_user_type_t user_type;
2093         ck_rv_t rv;
2094
2095         user_type = (so == 0) ? CKU_USER : CKU_SO;
2096         if (so == 0 && (tokinfo->tinfo.flags & CKF_LOGIN_REQUIRED) == 0) {
2097                 gnutls_assert();
2098                 _gnutls_debug_log("p11: No login required.\n");
2099                 return 0;
2100         }
2101
2102         /* For a token with a "protected" (out-of-band) authentication
2103          * path, calling login with a NULL username is all that is
2104          * required. */
2105         if (tokinfo->tinfo.flags & CKF_PROTECTED_AUTHENTICATION_PATH) {
2106                 rv = (sinfo->module)->C_Login(sinfo->pks,
2107                                               (so ==
2108                                                0) ? CKU_USER : CKU_SO,
2109                                               NULL, 0);
2110                 if (rv == CKR_OK || rv == CKR_USER_ALREADY_LOGGED_IN) {
2111                         return 0;
2112                 } else {
2113                         gnutls_assert();
2114                         _gnutls_debug_log
2115                             ("p11: Protected login failed.\n");
2116                         ret = GNUTLS_E_PKCS11_ERROR;
2117                         goto cleanup;
2118                 }
2119         }
2120
2121         do {
2122                 struct p11_kit_pin *pin;
2123                 struct ck_token_info tinfo;
2124
2125                 memcpy(&tinfo, &tokinfo->tinfo, sizeof(tinfo));
2126
2127                 /* Check whether the session is already logged in, and if so, just skip */
2128                 rv = (sinfo->module)->C_GetSessionInfo(sinfo->pks,
2129                                                        &session_info);
2130                 if (rv == CKR_OK
2131                     && (session_info.state == CKS_RO_USER_FUNCTIONS
2132                         || session_info.state == CKS_RW_USER_FUNCTIONS)) {
2133                         ret = 0;
2134                         goto cleanup;
2135                 }
2136
2137                 /* If login has been attempted once already, check the token
2138                  * status again, the flags might change. */
2139                 if (attempt) {
2140                         if (pkcs11_get_token_info
2141                             (tokinfo->prov->module, tokinfo->sid,
2142                              &tinfo) != CKR_OK) {
2143                                 gnutls_assert();
2144                                 _gnutls_debug_log
2145                                     ("p11: GetTokenInfo failed\n");
2146                                 ret = GNUTLS_E_PKCS11_ERROR;
2147                                 goto cleanup;
2148                         }
2149                 }
2150
2151                 ret =
2152                     retrieve_pin(pin_info, info, &tinfo, attempt++,
2153                                  user_type, &pin);
2154                 if (ret < 0) {
2155                         gnutls_assert();
2156                         goto cleanup;
2157                 }
2158
2159                 rv = (sinfo->module)->C_Login(sinfo->pks, user_type,
2160                                               (unsigned char *)
2161                                               p11_kit_pin_get_value(pin,
2162                                                                     NULL),
2163                                               p11_kit_pin_get_length(pin));
2164
2165                 p11_kit_pin_unref(pin);
2166         }
2167         while (rv == CKR_PIN_INCORRECT);
2168
2169         _gnutls_debug_log("p11: Login result = %lu\n", rv);
2170
2171
2172         ret = (rv == CKR_OK
2173                || rv ==
2174                CKR_USER_ALREADY_LOGGED_IN) ? 0 : pkcs11_rv_to_err(rv);
2175
2176       cleanup:
2177         return ret;
2178 }
2179
2180 int pkcs11_call_token_func(struct p11_kit_uri *info, const unsigned retry)
2181 {
2182         struct ck_token_info *tinfo;
2183         char *label;
2184         int ret = 0;
2185
2186         tinfo = p11_kit_uri_get_token_info(info);
2187         label = p11_kit_space_strdup(tinfo->label, sizeof(tinfo->label));
2188         ret = (_gnutls_token_func) (_gnutls_token_data, label, retry);
2189         free(label);
2190
2191         return ret;
2192 }
2193
2194
2195 static int
2196 find_privkeys(struct pkcs11_session_info *sinfo,
2197               struct token_info *info, struct find_pkey_list_st *list)
2198 {
2199         struct ck_attribute a[3];
2200         ck_object_class_t class;
2201         ck_rv_t rv;
2202         ck_object_handle_t obj;
2203         unsigned long count, current;
2204         char certid_tmp[PKCS11_ID_SIZE];
2205
2206         class = CKO_PRIVATE_KEY;
2207
2208         /* Find an object with private key class and a certificate ID
2209          * which matches the certificate. */
2210         /* FIXME: also match the cert subject. */
2211         a[0].type = CKA_CLASS;
2212         a[0].value = &class;
2213         a[0].value_len = sizeof class;
2214
2215         rv = pkcs11_find_objects_init(sinfo->module, sinfo->pks, a, 1);
2216         if (rv != CKR_OK) {
2217                 gnutls_assert();
2218                 return pkcs11_rv_to_err(rv);
2219         }
2220
2221         list->key_ids_size = 0;
2222         while (pkcs11_find_objects
2223                (sinfo->module, sinfo->pks, &obj, 1, &count) == CKR_OK
2224                && count == 1) {
2225                 list->key_ids_size++;
2226         }
2227
2228         pkcs11_find_objects_final(sinfo);
2229
2230         if (list->key_ids_size == 0) {
2231                 gnutls_assert();
2232                 return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
2233         }
2234
2235         list->key_ids =
2236             gnutls_malloc(sizeof(gnutls_buffer_st) * list->key_ids_size);
2237         if (list->key_ids == NULL) {
2238                 gnutls_assert();
2239                 return GNUTLS_E_MEMORY_ERROR;
2240         }
2241
2242         /* actual search */
2243         a[0].type = CKA_CLASS;
2244         a[0].value = &class;
2245         a[0].value_len = sizeof class;
2246
2247         rv = pkcs11_find_objects_init(sinfo->module, sinfo->pks, a, 1);
2248         if (rv != CKR_OK) {
2249                 gnutls_assert();
2250                 return pkcs11_rv_to_err(rv);
2251         }
2252
2253         current = 0;
2254         while (pkcs11_find_objects
2255                (sinfo->module, sinfo->pks, &obj, 1, &count) == CKR_OK
2256                && count == 1) {
2257
2258                 a[0].type = CKA_ID;
2259                 a[0].value = certid_tmp;
2260                 a[0].value_len = sizeof(certid_tmp);
2261
2262                 _gnutls_buffer_init(&list->key_ids[current]);
2263
2264                 if (pkcs11_get_attribute_value
2265                     (sinfo->module, sinfo->pks, obj, a, 1) == CKR_OK) {
2266                         _gnutls_buffer_append_data(&list->key_ids[current],
2267                                                    a[0].value,
2268                                                    a[0].value_len);
2269                         current++;
2270                 }
2271
2272                 if (current > list->key_ids_size)
2273                         break;
2274         }
2275
2276         pkcs11_find_objects_final(sinfo);
2277
2278         list->key_ids_size = current - 1;
2279
2280         return 0;
2281 }
2282
2283 /* Recover certificate list from tokens */
2284
2285
2286 static int
2287 find_objs(struct pkcs11_session_info *sinfo,
2288           struct token_info *info, struct ck_info *lib_info, void *input)
2289 {
2290         struct find_obj_data_st *find_data = input;
2291         struct ck_attribute a[6];
2292         struct ck_attribute *attr;
2293         ck_object_class_t class = (ck_object_class_t) - 1;
2294         ck_certificate_type_t type = (ck_certificate_type_t) - 1;
2295         ck_bool_t trusted;
2296         unsigned long category;
2297         ck_rv_t rv;
2298         ck_object_handle_t obj;
2299         unsigned long count;
2300         uint8_t *cert_data;
2301         char certid_tmp[PKCS11_ID_SIZE];
2302         char label_tmp[PKCS11_LABEL_SIZE];
2303         int ret;
2304         struct find_pkey_list_st plist; /* private key holder */
2305         unsigned int i, tot_values = 0;
2306
2307         if (info == NULL) {     /* final call */
2308                 if (find_data->current <= *find_data->n_list)
2309                         ret = 0;
2310                 else
2311                         ret = GNUTLS_E_SHORT_MEMORY_BUFFER;
2312
2313                 *find_data->n_list = find_data->current;
2314
2315                 return ret;
2316         }
2317
2318         /* do not bother reading the token if basic fields do not match
2319          */
2320         if (!p11_kit_uri_match_token_info(find_data->info, &info->tinfo) ||
2321             !p11_kit_uri_match_module_info(find_data->info, lib_info)) {
2322                 gnutls_assert();
2323                 return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
2324         }
2325
2326         memset(&plist, 0, sizeof(plist));
2327
2328         if (find_data->flags == GNUTLS_PKCS11_OBJ_ATTR_CRT_WITH_PRIVKEY) {
2329                 ret = find_privkeys(sinfo, info, &plist);
2330                 if (ret < 0) {
2331                         gnutls_assert();
2332                         return ret;
2333                 }
2334
2335                 if (plist.key_ids_size == 0) {
2336                         gnutls_assert();
2337                         return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
2338                 }
2339         }
2340
2341         /* Find objects with given class and type */
2342         attr = p11_kit_uri_get_attribute(find_data->info, CKA_CLASS);
2343         if (attr) {
2344                 if (attr->value
2345                     && attr->value_len == sizeof(ck_object_class_t))
2346                         class = *((ck_object_class_t *) attr->value);
2347                 if (class == CKO_CERTIFICATE)
2348                         type = CKC_X_509;
2349         }
2350
2351         cert_data = gnutls_malloc(MAX_CERT_SIZE);
2352         if (cert_data == NULL) {
2353                 gnutls_assert();
2354                 return GNUTLS_E_MEMORY_ERROR;
2355         }
2356
2357         /* Find objects with cert class and X.509 cert type. */
2358
2359         tot_values = 0;
2360
2361         if (find_data->flags == GNUTLS_PKCS11_OBJ_ATTR_CRT_ALL
2362             || find_data->flags == GNUTLS_PKCS11_OBJ_ATTR_CRT_WITH_PRIVKEY)
2363         {
2364                 class = CKO_CERTIFICATE;
2365                 type = CKC_X_509;
2366                 trusted = 1;
2367
2368                 a[tot_values].type = CKA_CLASS;
2369                 a[tot_values].value = &class;
2370                 a[tot_values].value_len = sizeof class;
2371                 tot_values++;
2372
2373                 a[tot_values].type = CKA_CERTIFICATE_TYPE;
2374                 a[tot_values].value = &type;
2375                 a[tot_values].value_len = sizeof type;
2376                 tot_values++;
2377
2378         } else if (find_data->flags == GNUTLS_PKCS11_OBJ_ATTR_CRT_TRUSTED) {
2379                 class = CKO_CERTIFICATE;
2380                 type = CKC_X_509;
2381                 trusted = 1;
2382
2383                 a[tot_values].type = CKA_CLASS;
2384                 a[tot_values].value = &class;
2385                 a[tot_values].value_len = sizeof class;
2386                 tot_values++;
2387
2388                 a[tot_values].type = CKA_TRUSTED;
2389                 a[tot_values].value = &trusted;
2390                 a[tot_values].value_len = sizeof trusted;
2391                 tot_values++;
2392
2393         } else if (find_data->flags ==
2394                    GNUTLS_PKCS11_OBJ_ATTR_CRT_TRUSTED_CA) {
2395                 class = CKO_CERTIFICATE;
2396                 type = CKC_X_509;
2397                 trusted = 1;
2398
2399                 a[tot_values].type = CKA_CLASS;
2400                 a[tot_values].value = &class;
2401                 a[tot_values].value_len = sizeof class;
2402                 tot_values++;
2403
2404                 a[tot_values].type = CKA_TRUSTED;
2405                 a[tot_values].value = &trusted;
2406                 a[tot_values].value_len = sizeof trusted;
2407                 tot_values++;
2408
2409                 category = 2;
2410                 a[tot_values].type = CKA_CERTIFICATE_CATEGORY;
2411                 a[tot_values].value = &category;
2412                 a[tot_values].value_len = sizeof category;
2413                 tot_values++;
2414         } else if (find_data->flags == GNUTLS_PKCS11_OBJ_ATTR_PUBKEY) {
2415                 class = CKO_PUBLIC_KEY;
2416
2417                 a[tot_values].type = CKA_CLASS;
2418                 a[tot_values].value = &class;
2419                 a[tot_values].value_len = sizeof class;
2420                 tot_values++;
2421         } else if (find_data->flags == GNUTLS_PKCS11_OBJ_ATTR_PRIVKEY) {
2422                 class = CKO_PRIVATE_KEY;
2423
2424                 a[tot_values].type = CKA_CLASS;
2425                 a[tot_values].value = &class;
2426                 a[tot_values].value_len = sizeof class;
2427                 tot_values++;
2428         } else if (find_data->flags == GNUTLS_PKCS11_OBJ_ATTR_ALL) {
2429                 if (class != (ck_object_class_t) - 1) {
2430                         a[tot_values].type = CKA_CLASS;
2431                         a[tot_values].value = &class;
2432                         a[tot_values].value_len = sizeof class;
2433                         tot_values++;
2434                 }
2435                 if (type != (ck_certificate_type_t) - 1) {
2436                         a[tot_values].type = CKA_CERTIFICATE_TYPE;
2437                         a[tot_values].value = &type;
2438                         a[tot_values].value_len = sizeof type;
2439                         tot_values++;
2440                 }
2441         } else {
2442                 gnutls_assert();
2443                 ret = GNUTLS_E_INVALID_REQUEST;
2444                 goto fail;
2445         }
2446
2447         attr = p11_kit_uri_get_attribute(find_data->info, CKA_ID);
2448         if (attr != NULL) {
2449                 memcpy(a + tot_values, attr, sizeof(struct ck_attribute));
2450                 tot_values++;
2451         }
2452
2453         rv = pkcs11_find_objects_init(sinfo->module, sinfo->pks, a,
2454                                       tot_values);
2455         if (rv != CKR_OK) {
2456                 gnutls_assert();
2457                 _gnutls_debug_log("p11: FindObjectsInit failed.\n");
2458                 return pkcs11_rv_to_err(rv);
2459         }
2460
2461         while (pkcs11_find_objects
2462                (sinfo->module, sinfo->pks, &obj, 1, &count) == CKR_OK
2463                && count == 1) {
2464                 gnutls_datum_t label, id, value;
2465
2466                 a[0].type = CKA_LABEL;
2467                 a[0].value = label_tmp;
2468                 a[0].value_len = sizeof label_tmp;
2469
2470                 if (pkcs11_get_attribute_value
2471                     (sinfo->module, sinfo->pks, obj, a, 1) == CKR_OK) {
2472                         label.data = a[0].value;
2473                         label.size = a[0].value_len;
2474                 } else {
2475                         label.data = NULL;
2476                         label.size = 0;
2477                 }
2478
2479                 a[0].type = CKA_ID;
2480                 a[0].value = certid_tmp;
2481                 a[0].value_len = sizeof certid_tmp;
2482
2483                 if (pkcs11_get_attribute_value
2484                     (sinfo->module, sinfo->pks, obj, a, 1) == CKR_OK) {
2485                         id.data = a[0].value;
2486                         id.size = a[0].value_len;
2487                 } else {
2488                         id.data = NULL;
2489                         id.size = 0;
2490                 }
2491
2492                 a[0].type = CKA_VALUE;
2493                 a[0].value = cert_data;
2494                 a[0].value_len = MAX_CERT_SIZE;
2495                 if (pkcs11_get_attribute_value
2496                     (sinfo->module, sinfo->pks, obj, a, 1) == CKR_OK) {
2497                         value.data = a[0].value;
2498                         value.size = a[0].value_len;
2499                 } else {
2500                         value.data = NULL;
2501                         value.size = 0;
2502                 }
2503
2504                 if (find_data->flags == GNUTLS_PKCS11_OBJ_ATTR_ALL) {
2505                         a[0].type = CKA_CLASS;
2506                         a[0].value = &class;
2507                         a[0].value_len = sizeof class;
2508
2509                         rv = pkcs11_get_attribute_value(sinfo->module,
2510                                                    sinfo->pks, obj, a, 1);
2511                         if (rv != CKR_OK) {
2512                                 class = -1;
2513                         }
2514                 }
2515
2516                 if (find_data->flags ==
2517                     GNUTLS_PKCS11_OBJ_ATTR_CRT_WITH_PRIVKEY) {
2518                         for (i = 0; i < plist.key_ids_size; i++) {
2519                                 if (plist.key_ids[i].length !=
2520                                     a[1].value_len
2521                                     || memcmp(plist.key_ids[i].data,
2522                                               a[1].value,
2523                                               a[1].value_len) != 0) {
2524                                         /* not found */
2525                                         continue;
2526                                 }
2527                         }
2528                 }
2529
2530                 if (find_data->current < *find_data->n_list) {
2531                         ret =
2532                             gnutls_pkcs11_obj_init(&find_data->p_list
2533                                                    [find_data->current]);
2534                         if (ret < 0) {
2535                                 gnutls_assert();
2536                                 goto fail;
2537                         }
2538
2539                         if (class == CKO_PUBLIC_KEY) {
2540                                 ret =
2541                                     pkcs11_obj_import_pubkey(sinfo->module,
2542                                                              sinfo->pks,
2543                                                              obj,
2544                                                              find_data->p_list
2545                                                              [find_data->current],
2546                                                              &id, &label,
2547                                                              &info->tinfo,
2548                                                              lib_info);
2549                         } else {
2550                                 ret =
2551                                     pkcs11_obj_import(class,
2552                                                       find_data->p_list
2553                                                       [find_data->current],
2554                                                       &value, &id, &label,
2555                                                       &info->tinfo,
2556                                                       lib_info);
2557                         }
2558                         if (ret < 0) {
2559                                 gnutls_assert();
2560                                 goto fail;
2561                         }
2562                 }
2563
2564                 find_data->current++;
2565
2566         }
2567
2568         gnutls_free(cert_data);
2569         pkcs11_find_objects_final(sinfo);
2570
2571         return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;   /* continue until all tokens have been checked */
2572
2573       fail:
2574         gnutls_free(cert_data);
2575         pkcs11_find_objects_final(sinfo);
2576         if (plist.key_ids != NULL) {
2577                 for (i = 0; i < plist.key_ids_size; i++) {
2578                         _gnutls_buffer_clear(&plist.key_ids[i]);
2579                 }
2580                 gnutls_free(plist.key_ids);
2581         }
2582         for (i = 0; i < find_data->current; i++) {
2583                 gnutls_pkcs11_obj_deinit(find_data->p_list[i]);
2584         }
2585         find_data->current = 0;
2586
2587         return ret;
2588 }
2589
2590 /**
2591  * gnutls_pkcs11_obj_list_import_url:
2592  * @p_list: An uninitialized object list (may be NULL)
2593  * @n_list: initially should hold the maximum size of the list. Will contain the actual size.
2594  * @url: A PKCS 11 url identifying a set of objects
2595  * @attrs: Attributes of type #gnutls_pkcs11_obj_attr_t that can be used to limit output
2596  * @flags: One of GNUTLS_PKCS11_OBJ_* flags
2597  *
2598  * This function will initialize and set values to an object list
2599  * by using all objects identified by a PKCS 11 URL.
2600  *
2601  * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
2602  *   negative error value.
2603  *
2604  * Since: 2.12.0
2605  **/
2606 int
2607 gnutls_pkcs11_obj_list_import_url(gnutls_pkcs11_obj_t * p_list,
2608                                   unsigned int *n_list,
2609                                   const char *url,
2610                                   gnutls_pkcs11_obj_attr_t attrs,
2611                                   unsigned int flags)
2612 {
2613         int ret;
2614         struct find_obj_data_st priv;
2615
2616         PKCS11_CHECK_INIT;
2617
2618         memset(&priv, 0, sizeof(priv));
2619
2620         /* fill in the find data structure */
2621         priv.p_list = p_list;
2622         priv.n_list = n_list;
2623         priv.flags = attrs;
2624         priv.current = 0;
2625
2626         if (url == NULL || url[0] == 0) {
2627                 url = "pkcs11:";
2628         }
2629
2630         ret = pkcs11_url_to_info(url, &priv.info);
2631         if (ret < 0) {
2632                 gnutls_assert();
2633                 return ret;
2634         }
2635
2636         ret =
2637             _pkcs11_traverse_tokens(find_objs, &priv, priv.info,
2638                                     NULL, pkcs11_obj_flags_to_int(flags));
2639         p11_kit_uri_free(priv.info);
2640
2641         if (ret < 0) {
2642                 gnutls_assert();
2643                 if (ret == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) {
2644                         *n_list = 0;
2645                         ret = 0;
2646                 }
2647                 return ret;
2648         }
2649
2650         return 0;
2651 }
2652
2653 /**
2654  * gnutls_pkcs11_obj_list_import_url2:
2655  * @p_list: An uninitialized object list (may be NULL)
2656  * @n_list: It will contain the size of the list.
2657  * @url: A PKCS 11 url identifying a set of objects
2658  * @attrs: Attributes of type #gnutls_pkcs11_obj_attr_t that can be used to limit output
2659  * @flags: One of GNUTLS_PKCS11_OBJ_* flags
2660  *
2661  * This function will initialize and set values to an object list
2662  * by using all objects identified by the PKCS 11 URL. The output
2663  * is stored in @p_list, which will be initialized.
2664  *
2665  * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
2666  *   negative error value.
2667  *
2668  * Since: 3.1.0
2669  **/
2670 int
2671 gnutls_pkcs11_obj_list_import_url2(gnutls_pkcs11_obj_t ** p_list,
2672                                    unsigned int *n_list,
2673                                    const char *url,
2674                                    gnutls_pkcs11_obj_attr_t attrs,
2675                                    unsigned int flags)
2676 {
2677         unsigned int init = 128;
2678         int ret;
2679
2680         *p_list = gnutls_malloc(sizeof(gnutls_pkcs11_obj_t) * init);
2681         if (*p_list == NULL) {
2682                 gnutls_assert();
2683                 return GNUTLS_E_MEMORY_ERROR;
2684         }
2685
2686         ret =
2687             gnutls_pkcs11_obj_list_import_url(*p_list, &init, url, attrs,
2688                                               flags);
2689         if (ret == GNUTLS_E_SHORT_MEMORY_BUFFER) {
2690                 *p_list =
2691                     gnutls_realloc_fast(*p_list,
2692                                         sizeof(gnutls_pkcs11_obj_t) *
2693                                         init);
2694                 if (*p_list == NULL)
2695                         return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
2696
2697                 ret =
2698                     gnutls_pkcs11_obj_list_import_url(*p_list, &init, url,
2699                                                       attrs, flags);
2700         }
2701
2702         if (ret < 0) {
2703                 gnutls_assert();
2704                 gnutls_free(*p_list);
2705                 *p_list = NULL;
2706                 return ret;
2707         }
2708
2709         *n_list = init;
2710         return 0;
2711
2712 }
2713
2714 /**
2715  * gnutls_x509_crt_import_pkcs11_url:
2716  * @crt: A certificate of type #gnutls_x509_crt_t
2717  * @url: A PKCS 11 url
2718  * @flags: One of GNUTLS_PKCS11_OBJ_* flags
2719  *
2720  * This function will import a PKCS 11 certificate directly from a token
2721  * without involving the #gnutls_pkcs11_obj_t structure. This function will
2722  * fail if the certificate stored is not of X.509 type.
2723  *
2724  * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
2725  *   negative error value.
2726  *
2727  * Since: 2.12.0
2728  **/
2729 int
2730 gnutls_x509_crt_import_pkcs11_url(gnutls_x509_crt_t crt,
2731                                   const char *url, unsigned int flags)
2732 {
2733         gnutls_pkcs11_obj_t pcrt;
2734         int ret;
2735
2736         ret = gnutls_pkcs11_obj_init(&pcrt);
2737         if (ret < 0) {
2738                 gnutls_assert();
2739                 return ret;
2740         }
2741
2742         if (crt->pin.cb)
2743                 gnutls_pkcs11_obj_set_pin_function(pcrt, crt->pin.cb,
2744                                                    crt->pin.data);
2745
2746         ret = gnutls_pkcs11_obj_import_url(pcrt, url, flags);
2747         if (ret < 0) {
2748                 gnutls_assert();
2749                 goto cleanup;
2750         }
2751
2752         ret = gnutls_x509_crt_import(crt, &pcrt->raw, GNUTLS_X509_FMT_DER);
2753         if (ret < 0) {
2754                 gnutls_assert();
2755                 goto cleanup;
2756         }
2757
2758         ret = 0;
2759       cleanup:
2760
2761         gnutls_pkcs11_obj_deinit(pcrt);
2762
2763         return ret;
2764 }
2765
2766 /**
2767  * gnutls_x509_crt_import_pkcs11:
2768  * @crt: A certificate of type #gnutls_x509_crt_t
2769  * @pkcs11_crt: A PKCS 11 object that contains a certificate
2770  *
2771  * This function will import a PKCS 11 certificate to a #gnutls_x509_crt_t
2772  * structure.
2773  *
2774  * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
2775  *   negative error value.
2776  *
2777  * Since: 2.12.0
2778  **/
2779 int
2780 gnutls_x509_crt_import_pkcs11(gnutls_x509_crt_t crt,
2781                               gnutls_pkcs11_obj_t pkcs11_crt)
2782 {
2783         return gnutls_x509_crt_import(crt, &pkcs11_crt->raw,
2784                                       GNUTLS_X509_FMT_DER);
2785 }
2786
2787 /**
2788  * gnutls_x509_crt_list_import_pkcs11:
2789  * @certs: A list of certificates of type #gnutls_x509_crt_t
2790  * @cert_max: The maximum size of the list
2791  * @objs: A list of PKCS 11 objects
2792  * @flags: 0 for now
2793  *
2794  * This function will import a PKCS 11 certificate list to a list of 
2795  * #gnutls_x509_crt_t structure. These must not be initialized.
2796  *
2797  * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
2798  *   negative error value.
2799  *
2800  * Since: 2.12.0
2801  **/
2802 int
2803 gnutls_x509_crt_list_import_pkcs11(gnutls_x509_crt_t * certs,
2804                                    unsigned int cert_max,
2805                                    gnutls_pkcs11_obj_t * const objs,
2806                                    unsigned int flags)
2807 {
2808         unsigned int i, j;
2809         int ret;
2810
2811         for (i = 0; i < cert_max; i++) {
2812                 ret = gnutls_x509_crt_init(&certs[i]);
2813                 if (ret < 0) {
2814                         gnutls_assert();
2815                         goto cleanup;
2816                 }
2817
2818                 ret = gnutls_x509_crt_import_pkcs11(certs[i], objs[i]);
2819                 if (ret < 0) {
2820                         gnutls_assert();
2821                         goto cleanup;
2822                 }
2823         }
2824
2825         return 0;
2826
2827       cleanup:
2828         for (j = 0; j < i; j++) {
2829                 gnutls_x509_crt_deinit(certs[j]);
2830         }
2831
2832         return ret;
2833 }
2834
2835 static int
2836 find_flags(struct pkcs11_session_info *sinfo,
2837            struct token_info *info, struct ck_info *lib_info, void *input)
2838 {
2839         struct find_flags_data_st *find_data = input;
2840
2841         if (info == NULL) {     /* we don't support multiple calls */
2842                 gnutls_assert();
2843                 return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
2844         }
2845
2846         /* do not bother reading the token if basic fields do not match
2847          */
2848         if (!p11_kit_uri_match_token_info(find_data->info, &info->tinfo) ||
2849             !p11_kit_uri_match_module_info(find_data->info, lib_info)) {
2850                 gnutls_assert();
2851                 return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
2852         }
2853
2854         /* found token! */
2855         if (p11_kit_module_get_flags(sinfo->module) & P11_KIT_MODULE_TRUSTED)
2856                 find_data->trusted = 1;
2857         else
2858                 find_data->trusted = 0;
2859         find_data->slot_flags = info->sinfo.flags;
2860
2861         return 0;
2862 }
2863
2864 /**
2865  * gnutls_pkcs11_token_get_flags:
2866  * @url: should contain a PKCS 11 URL
2867  * @flags: The output flags (GNUTLS_PKCS11_TOKEN_*)
2868  *
2869  * This function will return information about the PKCS 11 token flags.
2870  *
2871  * The supported flags are: %GNUTLS_PKCS11_TOKEN_HW and %GNUTLS_PKCS11_TOKEN_TRUSTED.
2872  *
2873  * Returns: %GNUTLS_E_SUCCESS (0) on success or a negative error code on error.
2874  *
2875  * Since: 2.12.0
2876  **/
2877 int gnutls_pkcs11_token_get_flags(const char *url, unsigned int *flags)
2878 {
2879         struct find_flags_data_st find_data;
2880         int ret;
2881
2882         PKCS11_CHECK_INIT;
2883
2884         memset(&find_data, 0, sizeof(find_data));
2885         ret = pkcs11_url_to_info(url, &find_data.info);
2886         if (ret < 0) {
2887                 gnutls_assert();
2888                 return ret;
2889         }
2890
2891         ret =
2892             _pkcs11_traverse_tokens(find_flags, &find_data, find_data.info,
2893                                     NULL, 0);
2894         p11_kit_uri_free(find_data.info);
2895
2896         if (ret < 0) {
2897                 gnutls_assert();
2898                 return ret;
2899         }
2900
2901         *flags = 0;
2902         if (find_data.slot_flags & CKF_HW_SLOT)
2903                 *flags |= GNUTLS_PKCS11_TOKEN_HW;
2904
2905         if (find_data.trusted != 0)
2906                 *flags |= GNUTLS_PKCS11_TOKEN_TRUSTED;
2907
2908         return 0;
2909
2910 }
2911
2912 /**
2913  * gnutls_pkcs11_token_get_mechanism:
2914  * @url: should contain a PKCS 11 URL
2915  * @idx: The index of the mechanism
2916  * @mechanism: The PKCS #11 mechanism ID
2917  *
2918  * This function will return the names of the supported mechanisms
2919  * by the token. It should be called with an increasing index until
2920  * it return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE.
2921  *
2922  * Returns: %GNUTLS_E_SUCCESS (0) on success or a negative error code on error.
2923  *
2924  * Since: 2.12.0
2925  **/
2926 int
2927 gnutls_pkcs11_token_get_mechanism(const char *url, unsigned int idx,
2928                                   unsigned long *mechanism)
2929 {
2930         int ret;
2931         ck_rv_t rv;
2932         struct ck_function_list *module;
2933         ck_slot_id_t slot;
2934         struct token_info tinfo;
2935         struct p11_kit_uri *info = NULL;
2936         unsigned long count;
2937         ck_mechanism_type_t mlist[400];
2938         
2939         PKCS11_CHECK_INIT;
2940
2941         ret = pkcs11_url_to_info(url, &info);
2942         if (ret < 0) {
2943                 gnutls_assert();
2944                 return ret;
2945         }
2946
2947         ret = pkcs11_find_slot(&module, &slot, info, &tinfo);
2948         p11_kit_uri_free(info);
2949
2950         if (ret < 0) {
2951                 gnutls_assert();
2952                 return ret;
2953         }
2954
2955         count = sizeof(mlist) / sizeof(mlist[0]);
2956         rv = pkcs11_get_mechanism_list(module, slot, mlist, &count);
2957         if (rv != CKR_OK) {
2958                 gnutls_assert();
2959                 return pkcs11_rv_to_err(rv);
2960         }
2961
2962         if (idx >= count) {
2963                 gnutls_assert();
2964                 return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
2965         }
2966
2967         *mechanism = mlist[idx];
2968
2969         return 0;
2970
2971 }
2972
2973 /**
2974  * gnutls_pkcs11_type_get_name:
2975  * @type: Holds the PKCS 11 object type, a #gnutls_pkcs11_obj_type_t.
2976  *
2977  * This function will return a human readable description of the
2978  * PKCS11 object type @obj.  It will return "Unknown" for unknown
2979  * types.
2980  *
2981  * Returns: human readable string labeling the PKCS11 object type
2982  * @type.
2983  *
2984  * Since: 2.12.0
2985  **/
2986 const char *gnutls_pkcs11_type_get_name(gnutls_pkcs11_obj_type_t type)
2987 {
2988         switch (type) {
2989         case GNUTLS_PKCS11_OBJ_X509_CRT:
2990                 return "X.509 Certificate";
2991         case GNUTLS_PKCS11_OBJ_PUBKEY:
2992                 return "Public key";
2993         case GNUTLS_PKCS11_OBJ_PRIVKEY:
2994                 return "Private key";
2995         case GNUTLS_PKCS11_OBJ_SECRET_KEY:
2996                 return "Secret key";
2997         case GNUTLS_PKCS11_OBJ_DATA:
2998                 return "Data";
2999         case GNUTLS_PKCS11_OBJ_UNKNOWN:
3000         default:
3001                 return "Unknown";
3002         }
3003 }
3004
3005 #ifndef CKA_X_DISTRUSTED
3006 # define CKA_X_VENDOR (CKA_VENDOR_DEFINED | 0x58444700UL)
3007 # define CKA_X_DISTRUSTED (CKA_X_VENDOR + 100)
3008 #endif
3009
3010 static int
3011 find_cert(struct pkcs11_session_info *sinfo,
3012             struct token_info *info, struct ck_info *lib_info, void *input)
3013 {
3014         struct ck_attribute a[10];
3015         ck_object_class_t class = -1;
3016         ck_certificate_type_t type = (ck_certificate_type_t) - 1;
3017         ck_rv_t rv;
3018         ck_object_handle_t obj;
3019         unsigned long count, a_vals;
3020         int found = 0, ret;
3021         uint8_t *cert_data = NULL;
3022         struct find_cert_st *priv = input;
3023         char label_tmp[PKCS11_LABEL_SIZE];
3024         char id_tmp[PKCS11_ID_SIZE];
3025         unsigned tries, i, finalized;
3026         ck_bool_t trusted = 1;
3027
3028         if (info == NULL) {
3029                 gnutls_assert();
3030                 return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
3031         }
3032
3033         /* the DISTRUSTED flag is p11-kit module specific */
3034         if (priv->flags & GNUTLS_PKCS11_OBJ_FLAG_RETRIEVE_DISTRUSTED) {
3035                 if (memcmp(lib_info->manufacturer_id, "PKCS#11 Kit", 11) != 0) {
3036                         gnutls_assert();
3037                         return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
3038                 }
3039         }
3040
3041         if (priv->dn.size == 0 && priv->key_id.size == 0 && priv->issuer_dn.size == 0 &&
3042                 priv->serial.size == 0)
3043                 return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
3044
3045         /* search the token for the key ID */
3046
3047         cert_data = gnutls_malloc(MAX_CERT_SIZE);
3048         if (cert_data == NULL) {
3049                 gnutls_assert();
3050                 return GNUTLS_E_MEMORY_ERROR;
3051         }
3052
3053         /* Find objects with given class and type */
3054
3055         if (priv->key_id.size > 0 && priv->dn.size > 0)
3056                 tries = 2;
3057         else
3058                 tries = 1;
3059
3060         for (i = 0; i < tries; i++) {
3061
3062                 a_vals = 0;
3063                 class = CKO_CERTIFICATE;
3064                 a[a_vals].type = CKA_CLASS;
3065                 a[a_vals].value = &class;
3066                 a[a_vals].value_len = sizeof class;
3067                 a_vals++;
3068
3069                 if (priv->flags & GNUTLS_PKCS11_OBJ_FLAG_RETRIEVE_TRUSTED) {
3070                         a[a_vals].type = CKA_TRUSTED;
3071                         a[a_vals].value = &trusted;
3072                         a[a_vals].value_len = sizeof trusted;
3073                         a_vals++;
3074                 }
3075
3076                 if (priv->flags & GNUTLS_PKCS11_OBJ_FLAG_RETRIEVE_DISTRUSTED) {
3077                         a[a_vals].type = CKA_X_DISTRUSTED;
3078                         a[a_vals].value = &trusted;
3079                         a[a_vals].value_len = sizeof trusted;
3080                         a_vals++;
3081                 }
3082
3083                 if (priv->need_import != 0) {
3084                         type = CKC_X_509;
3085                         a[a_vals].type = CKA_CERTIFICATE_TYPE;
3086                         a[a_vals].value = &type;
3087                         a[a_vals].value_len = sizeof type;
3088                         a_vals++;
3089                 }
3090
3091                 if (i == 0 && priv->key_id.size > 0) {
3092                         a[a_vals].type = CKA_ID;
3093                         a[a_vals].value = priv->key_id.data;
3094                         a[a_vals].value_len = priv->key_id.size;
3095                         a_vals++;
3096                 }
3097
3098                 if (priv->dn.size > 0) {
3099                         a[a_vals].type = CKA_SUBJECT;
3100                         a[a_vals].value = priv->dn.data;
3101                         a[a_vals].value_len = priv->dn.size;
3102                         a_vals++;
3103                 }
3104
3105                 if (priv->serial.size > 0) {
3106                         a[a_vals].type = CKA_SERIAL_NUMBER;
3107                         a[a_vals].value = priv->serial.data;
3108                         a[a_vals].value_len = priv->serial.size;
3109                         a_vals++;
3110                 }
3111
3112                 if (priv->issuer_dn.size > 0) {
3113                         a[a_vals].type = CKA_ISSUER;
3114                         a[a_vals].value = priv->issuer_dn.data;
3115                         a[a_vals].value_len = priv->issuer_dn.size;
3116                         a_vals++;
3117                 }
3118
3119                 finalized = 0;
3120                 rv = pkcs11_find_objects_init(sinfo->module, sinfo->pks, a,
3121                                               a_vals);
3122                 if (rv != CKR_OK) {
3123                         gnutls_assert();
3124                         _gnutls_debug_log
3125                             ("p11: FindObjectsInit failed.\n");
3126                         ret = pkcs11_rv_to_err(rv);
3127                         goto cleanup;
3128                 }
3129
3130                 while (pkcs11_find_objects
3131                        (sinfo->module, sinfo->pks, &obj, 1,
3132                         &count) == CKR_OK && count == 1) {
3133
3134                         if (priv->need_import == 0 && !(priv->flags & GNUTLS_PKCS11_OBJ_FLAG_COMPARE)) {
3135                                 found = 1;
3136                                 break;
3137                         }
3138
3139                         a[0].type = CKA_VALUE;
3140                         a[0].value = cert_data;
3141                         a[0].value_len = MAX_CERT_SIZE;
3142
3143                         a[1].type = CKA_LABEL;
3144                         a[1].value = label_tmp;
3145                         a[1].value_len = sizeof(label_tmp);
3146
3147                         a[2].type = CKA_ID;
3148                         a[2].value = id_tmp;
3149                         a[2].value_len = sizeof(id_tmp);
3150
3151                         if (pkcs11_get_attribute_value
3152                             (sinfo->module, sinfo->pks, obj, a,
3153                              3) == CKR_OK) {
3154                                 gnutls_datum_t id =
3155                                     { a[2].value, a[2].value_len };
3156                                 gnutls_datum_t data =
3157                                     { a[0].value, a[0].value_len };
3158                                 gnutls_datum_t label =
3159                                     { a[1].value, a[1].value_len };
3160
3161                                 if (priv->need_import != 0) {
3162                                         ret =
3163                                             pkcs11_obj_import(class, priv->obj,
3164                                                               &data, &id, &label,
3165                                                               &info->tinfo,
3166                                                               lib_info);
3167                                         if (ret < 0) {
3168                                                 gnutls_assert();
3169                                                 goto cleanup;
3170                                         }
3171                                 }
3172                                 
3173                                 if (priv->flags & GNUTLS_PKCS11_OBJ_FLAG_COMPARE) {
3174                                         if (priv->crt == NULL) {
3175                                                 gnutls_assert();
3176                                                 break;
3177                                         }
3178
3179                                         if (_gnutls_check_if_same_cert2(priv->crt, &data) == 0) {
3180                                                 /* doesn't match */
3181                                                 break;
3182                                         }
3183                                 }
3184
3185                                 found = 1;
3186                                 break;
3187                         } else {
3188                                 _gnutls_debug_log
3189                                     ("p11: Skipped cert, missing attrs.\n");
3190                         }
3191                 }
3192
3193                 pkcs11_find_objects_final(sinfo);
3194                 finalized = 1;
3195
3196                 if (found != 0)
3197                         break;
3198         }
3199
3200         if (found == 0) {
3201                 gnutls_assert();
3202                 ret = GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
3203         } else {
3204                 ret = 0;
3205         }
3206
3207       cleanup:
3208         gnutls_free(cert_data);
3209         if (finalized == 0)
3210                 pkcs11_find_objects_final(sinfo);
3211
3212         return ret;
3213 }
3214
3215 /**
3216  * gnutls_pkcs11_get_raw_issuer:
3217  * @url: A PKCS 11 url identifying a token
3218  * @cert: is the certificate to find issuer for
3219  * @issuer: Will hold the issuer if any in an allocated buffer. 
3220  * @fmt: The format of the exported issuer.
3221  * @flags: Use zero or flags from %GNUTLS_PKCS11_OBJ_FLAG.
3222  *
3223  * This function will return the issuer of a given certificate, if it
3224  * is stored in the token. By default only marked as trusted issuers
3225  * are retuned. If any issuer should be returned specify
3226  * %GNUTLS_PKCS11_OBJ_FLAG_RETRIEVE_ANY in @flags.
3227  *
3228  * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
3229  *   negative error value.
3230  *
3231  * Since: 3.2.7
3232  **/
3233 int gnutls_pkcs11_get_raw_issuer(const char *url, gnutls_x509_crt_t cert,
3234                                  gnutls_datum_t * issuer,
3235                                  gnutls_x509_crt_fmt_t fmt,
3236                                  unsigned int flags)
3237 {
3238         int ret;
3239         struct find_cert_st priv;
3240         uint8_t id[PKCS11_ID_SIZE];
3241         size_t id_size;
3242         struct p11_kit_uri *info = NULL;
3243
3244         PKCS11_CHECK_INIT;
3245
3246         memset(&priv, 0, sizeof(priv));
3247
3248         if (url == NULL || url[0] == 0) {
3249                 url = "pkcs11:";
3250         }
3251
3252         ret = pkcs11_url_to_info(url, &info);
3253         if (ret < 0) {
3254                 gnutls_assert();
3255                 return ret;
3256         }
3257
3258         id_size = sizeof(id);
3259         ret =
3260             gnutls_x509_crt_get_authority_key_id(cert, id, &id_size, NULL);
3261         if (ret >= 0) {
3262                 priv.key_id.data = id;
3263                 priv.key_id.size = id_size;
3264         }
3265
3266         priv.dn.data = cert->raw_issuer_dn.data;
3267         priv.dn.size = cert->raw_issuer_dn.size;
3268
3269         if (!(flags & GNUTLS_PKCS11_OBJ_FLAG_RETRIEVE_ANY))
3270                 flags |= GNUTLS_PKCS11_OBJ_FLAG_RETRIEVE_TRUSTED;
3271
3272         priv.flags = flags;
3273
3274         ret = gnutls_pkcs11_obj_init(&priv.obj);
3275         if (ret < 0) {
3276                 gnutls_assert();
3277                 goto cleanup;
3278         }
3279         priv.need_import = 1;
3280
3281         ret =
3282             _pkcs11_traverse_tokens(find_cert, &priv, info,
3283                                     NULL, pkcs11_obj_flags_to_int(flags));
3284         if (ret < 0) {
3285                 gnutls_assert();
3286                 goto cleanup;
3287         }
3288
3289         ret = gnutls_pkcs11_obj_export3(priv.obj, fmt, issuer);
3290         if (ret < 0) {
3291                 gnutls_assert();
3292                 goto cleanup;
3293         }
3294
3295         ret = 0;
3296
3297       cleanup:
3298         if (priv.obj)
3299                 gnutls_pkcs11_obj_deinit(priv.obj);
3300         if (info)
3301                 p11_kit_uri_free(info);
3302
3303         return ret;
3304 }
3305
3306 /**
3307  * gnutls_pkcs11_crt_is_known:
3308  * @url: A PKCS 11 url identifying a token
3309  * @cert: is the certificate to find issuer for
3310  * @issuer: Will hold the issuer if any in an allocated buffer. 
3311  * @fmt: The format of the exported issuer.
3312  * @flags: Use zero or flags from %GNUTLS_PKCS11_OBJ_FLAG.
3313  *
3314  * This function will check whether the provided certificate is stored
3315  * in the specified token. This is useful in combination with 
3316  * %GNUTLS_PKCS11_OBJ_FLAG_RETRIEVE_TRUSTED or 
3317  * %GNUTLS_PKCS11_OBJ_FLAG_RETRIEVE_DISTRUSTED,
3318  * to check whether a CA is present or a certificate is blacklisted in
3319  * a trust PKCS #11 module.
3320  *
3321  * This function can be used with a @url of "pkcs11:", and in that case all modules
3322  * will be searched. To restrict the modules to the marked as trusted in p11-kit
3323  * use the %GNUTLS_PKCS11_OBJ_FLAG_PRESENT_IN_TRUSTED_MODULE flag.
3324  *
3325  * Note that the flag %GNUTLS_PKCS11_OBJ_FLAG_RETRIEVE_DISTRUSTED is
3326  * specific to p11-kit trust modules.
3327  *
3328  * Returns: If the certificate exists non-zero is returned, otherwise zero.
3329  *
3330  * Since: 3.3.0
3331  **/
3332 int gnutls_pkcs11_crt_is_known(const char *url, gnutls_x509_crt_t cert,
3333                                  unsigned int flags)
3334 {
3335         int ret;
3336         struct find_cert_st priv;
3337         uint8_t serial[ASN1_MAX_TL_SIZE+64];
3338         size_t serial_size;
3339         uint8_t tag[ASN1_MAX_TL_SIZE];
3340         unsigned int tag_size;
3341         struct p11_kit_uri *info = NULL;
3342
3343         PKCS11_CHECK_INIT_RET(0);
3344
3345         memset(&priv, 0, sizeof(priv));
3346
3347         if (url == NULL || url[0] == 0) {
3348                 url = "pkcs11:";
3349         }
3350
3351         ret = pkcs11_url_to_info(url, &info);
3352         if (ret < 0) {
3353                 gnutls_assert();
3354                 return 0;
3355         }
3356
3357         /* Attempt searching using the issuer DN + serial number */
3358         serial_size = sizeof(serial) - sizeof(tag);
3359         ret =
3360             gnutls_x509_crt_get_serial(cert, serial+sizeof(tag), &serial_size);
3361         if (ret < 0) {
3362                 gnutls_assert();
3363                 return 0;
3364         }
3365
3366         /* PKCS#11 requires a DER encoded serial, wtf. $@(*$@ */
3367         tag_size = sizeof(tag);
3368         ret = asn1_encode_simple_der(ASN1_ETYPE_INTEGER, serial+sizeof(tag), serial_size,
3369                 tag, &tag_size);
3370         if (ret != ASN1_SUCCESS) {
3371                 gnutls_assert();
3372                 return 0;
3373         }
3374
3375         memcpy(serial+sizeof(tag)-tag_size, tag, tag_size);
3376         
3377         priv.serial.data = serial+sizeof(tag)-tag_size;
3378         priv.serial.size = serial_size + tag_size;
3379         priv.crt = cert;
3380
3381         priv.issuer_dn.data = cert->raw_issuer_dn.data;
3382         priv.issuer_dn.size = cert->raw_issuer_dn.size;
3383         
3384         /* when looking for a trusted certificate, we always fully compare
3385          * with the given */
3386         if (flags & GNUTLS_PKCS11_OBJ_FLAG_RETRIEVE_TRUSTED)
3387                 flags |= GNUTLS_PKCS11_OBJ_FLAG_COMPARE;
3388
3389         priv.flags = flags;
3390
3391         ret =
3392             _pkcs11_traverse_tokens(find_cert, &priv, info,
3393                                     NULL, pkcs11_obj_flags_to_int(flags));
3394         if (ret == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) {
3395                 /* attempt searching with the subject DN only */
3396                 memset(&priv, 0, sizeof(priv));
3397                 priv.crt = cert;
3398                 priv.flags = flags;
3399
3400                 priv.dn.data = cert->raw_dn.data;
3401                 priv.dn.size = cert->raw_dn.size;
3402                 ret =
3403                     _pkcs11_traverse_tokens(find_cert, &priv, info,
3404                                     NULL, pkcs11_obj_flags_to_int(flags));
3405         }
3406         if (ret < 0) {
3407                 gnutls_assert();
3408                 ret = 0;
3409                 goto cleanup;
3410         }
3411
3412         ret = 1;
3413
3414       cleanup:
3415         if (info)
3416                 p11_kit_uri_free(info);
3417
3418         return ret;
3419 }