2 * GnuTLS PKCS#11 support
3 * Copyright (C) 2010 Free Software Foundation
4 * Copyright (C) 2008, Joe Orton <joe@manyfish.co.uk>
6 * Author: Nikos Mavrogiannopoulos
8 * Inspired and some parts (pkcs11_login) based on neon PKCS #11 support
9 * by Joe Orton. More ideas came from the pkcs11-helper library by
12 * This library is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU Library General Public
14 * License as published by the Free Software Foundation; either
15 * version 2 of the License, or (at your option) any later version.
17 * This library is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * Library General Public License for more details.
22 * You should have received a copy of the GNU Library General Public
23 * License along with this library; if not, write to the Free
24 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
28 #include <gnutls_int.h>
29 #include <gnutls/pkcs11.h>
32 #include <gnutls_errors.h>
33 #include <gnutls_datum.h>
34 #include <pkcs11_int.h>
36 #define MAX_PROVIDERS 16
38 static void terminate_string (unsigned char *str
, size_t len
);
40 /* XXX: try to eliminate this */
41 #define MAX_CERT_SIZE 8*1024
43 struct gnutls_pkcs11_provider_s
45 pakchois_module_t
*module
;
51 struct flags_find_data_st
53 struct pkcs11_url_info info
;
54 unsigned int slot_flags
;
57 struct url_find_data_st
59 gnutls_pkcs11_obj_t crt
;
62 struct crt_find_data_st
64 gnutls_pkcs11_obj_t
*p_list
;
67 gnutls_pkcs11_obj_attr_t flags
;
68 struct pkcs11_url_info info
;
72 static struct gnutls_pkcs11_provider_s providers
[MAX_PROVIDERS
];
73 static int active_providers
= 0;
75 static gnutls_pkcs11_pin_callback_t pin_func
;
76 static void *pin_data
;
78 gnutls_pkcs11_token_callback_t token_func
;
82 pkcs11_rv_to_err (ck_rv_t rv
)
89 return GNUTLS_E_MEMORY_ERROR
;
90 case CKR_SLOT_ID_INVALID
:
91 return GNUTLS_E_PKCS11_SLOT_ERROR
;
92 case CKR_ARGUMENTS_BAD
:
93 case CKR_MECHANISM_PARAM_INVALID
:
94 return GNUTLS_E_INVALID_REQUEST
;
95 case CKR_NEED_TO_CREATE_THREADS
:
97 case CKR_FUNCTION_NOT_PARALLEL
:
99 case CKR_MUTEX_NOT_LOCKED
:
100 return GNUTLS_E_LOCKING_ERROR
;
101 case CKR_ATTRIBUTE_READ_ONLY
:
102 case CKR_ATTRIBUTE_SENSITIVE
:
103 case CKR_ATTRIBUTE_TYPE_INVALID
:
104 case CKR_ATTRIBUTE_VALUE_INVALID
:
105 return GNUTLS_E_PKCS11_ATTRIBUTE_ERROR
;
106 case CKR_DEVICE_ERROR
:
107 case CKR_DEVICE_MEMORY
:
108 case CKR_DEVICE_REMOVED
:
109 return GNUTLS_E_PKCS11_DEVICE_ERROR
;
110 case CKR_DATA_INVALID
:
111 case CKR_DATA_LEN_RANGE
:
112 case CKR_ENCRYPTED_DATA_INVALID
:
113 case CKR_ENCRYPTED_DATA_LEN_RANGE
:
114 case CKR_OBJECT_HANDLE_INVALID
:
115 return GNUTLS_E_PKCS11_DATA_ERROR
;
116 case CKR_FUNCTION_NOT_SUPPORTED
:
117 case CKR_MECHANISM_INVALID
:
118 return GNUTLS_E_PKCS11_UNSUPPORTED_FEATURE_ERROR
;
119 case CKR_KEY_HANDLE_INVALID
:
120 case CKR_KEY_SIZE_RANGE
:
121 case CKR_KEY_TYPE_INCONSISTENT
:
122 case CKR_KEY_NOT_NEEDED
:
123 case CKR_KEY_CHANGED
:
125 case CKR_KEY_INDIGESTIBLE
:
126 case CKR_KEY_FUNCTION_NOT_PERMITTED
:
127 case CKR_KEY_NOT_WRAPPABLE
:
128 case CKR_KEY_UNEXTRACTABLE
:
129 return GNUTLS_E_PKCS11_KEY_ERROR
;
130 case CKR_PIN_INCORRECT
:
131 case CKR_PIN_INVALID
:
132 case CKR_PIN_LEN_RANGE
:
133 return GNUTLS_E_PKCS11_PIN_ERROR
;
134 case CKR_PIN_EXPIRED
:
135 return GNUTLS_E_PKCS11_PIN_EXPIRED
;
137 return GNUTLS_E_PKCS11_PIN_LOCKED
;
138 case CKR_SESSION_CLOSED
:
139 case CKR_SESSION_COUNT
:
140 case CKR_SESSION_HANDLE_INVALID
:
141 case CKR_SESSION_PARALLEL_NOT_SUPPORTED
:
142 case CKR_SESSION_READ_ONLY
:
143 case CKR_SESSION_EXISTS
:
144 case CKR_SESSION_READ_ONLY_EXISTS
:
145 case CKR_SESSION_READ_WRITE_SO_EXISTS
:
146 return GNUTLS_E_PKCS11_SESSION_ERROR
;
147 case CKR_SIGNATURE_INVALID
:
148 case CKR_SIGNATURE_LEN_RANGE
:
149 return GNUTLS_E_PKCS11_SIGNATURE_ERROR
;
150 case CKR_TOKEN_NOT_PRESENT
:
151 case CKR_TOKEN_NOT_RECOGNIZED
:
152 case CKR_TOKEN_WRITE_PROTECTED
:
153 return GNUTLS_E_PKCS11_TOKEN_ERROR
;
154 case CKR_USER_ALREADY_LOGGED_IN
:
155 case CKR_USER_NOT_LOGGED_IN
:
156 case CKR_USER_PIN_NOT_INITIALIZED
:
157 case CKR_USER_TYPE_INVALID
:
158 case CKR_USER_ANOTHER_ALREADY_LOGGED_IN
:
159 case CKR_USER_TOO_MANY_TYPES
:
160 return GNUTLS_E_PKCS11_USER_ERROR
;
161 case CKR_BUFFER_TOO_SMALL
:
162 return GNUTLS_E_SHORT_MEMORY_BUFFER
;
164 return GNUTLS_E_PKCS11_ERROR
;
170 pkcs11_rescan_slots (void)
174 pakchois_get_slot_list (providers
[active_providers
- 1].module
, 0,
179 * gnutls_pkcs11_add_provider:
180 * @name: The filename of the module
181 * @params: should be NULL
183 * This function will load and add a PKCS 11 module to the module
184 * list used in gnutls. After this function is called the module will
185 * be used for PKCS 11 operations.
187 * Returns: On success, %GNUTLS_E_SUCCESS is returned, otherwise a
188 * negative error value.
191 gnutls_pkcs11_add_provider (const char *name
, const char *params
)
194 if (active_providers
>= MAX_PROVIDERS
)
197 return GNUTLS_E_CONSTRAINT_ERROR
;
201 if (pakchois_module_load_abs
202 (&providers
[active_providers
- 1].module
, name
) != CKR_OK
)
205 _gnutls_debug_log ("p11: Cannot load provider %s\n", name
);
207 return GNUTLS_E_PKCS11_LOAD_ERROR
;
210 /* cache the number of slots in this module */
211 if (pakchois_get_slot_list
212 (providers
[active_providers
- 1].module
, 0, NULL
,
213 &providers
[active_providers
- 1].nslots
) != CKR_OK
)
219 providers
[active_providers
- 1].slots
=
220 gnutls_malloc (sizeof (*providers
[active_providers
- 1].slots
) *
221 providers
[active_providers
- 1].nslots
);
222 if (providers
[active_providers
- 1].slots
== NULL
)
228 if (pakchois_get_slot_list
229 (providers
[active_providers
- 1].module
, 0,
230 providers
[active_providers
- 1].slots
,
231 &providers
[active_providers
- 1].nslots
) != CKR_OK
)
234 gnutls_free (providers
[active_providers
- 1].slots
);
238 memset (&providers
[active_providers
- 1].info
, 0,
239 sizeof (providers
[active_providers
- 1].info
));
240 pakchois_get_info (providers
[active_providers
- 1].module
,
241 &providers
[active_providers
- 1].info
);
243 terminate_string (providers
[active_providers
- 1].info
.manufacturer_id
,
244 sizeof (providers
[active_providers
- 1].
245 info
.manufacturer_id
));
246 terminate_string (providers
[active_providers
- 1].info
.library_description
,
247 sizeof (providers
[active_providers
- 1].
248 info
.library_description
));
250 _gnutls_debug_log ("p11: loaded provider '%s' with %d slots\n",
251 name
, (int) providers
[active_providers
- 1].nslots
);
256 pakchois_module_destroy (providers
[active_providers
- 1].module
);
258 return GNUTLS_E_PKCS11_LOAD_ERROR
;
264 * gnutls_pkcs11_obj_get_info:
265 * @crt: should contain a #gnutls_pkcs11_obj_t structure
266 * @itype: Denotes the type of information requested
267 * @output: where output will be stored
268 * @output_size: contains the maximum size of the output and will be overwritten with actual
270 * This function will return information about the PKCS 11 certificatesuch
271 * as the label, id as well as token information where the key is stored. When
272 * output is text it returns null terminated string although %output_size contains
273 * the size of the actual data only.
275 * Returns: zero on success or a negative value on error.
278 gnutls_pkcs11_obj_get_info (gnutls_pkcs11_obj_t crt
,
279 gnutls_pkcs11_obj_info_t itype
,
280 void *output
, size_t * output_size
)
282 return pkcs11_get_info (&crt
->info
, itype
, output
, output_size
);
286 pkcs11_get_info (struct pkcs11_url_info
*info
,
287 gnutls_pkcs11_obj_info_t itype
, void *output
,
288 size_t * output_size
)
290 const char *str
= NULL
;
295 case GNUTLS_PKCS11_OBJ_ID
:
296 if (*output_size
< info
->certid_raw_size
)
298 *output_size
= info
->certid_raw_size
;
299 return GNUTLS_E_SHORT_MEMORY_BUFFER
;
302 memcpy (output
, info
->certid_raw
, info
->certid_raw_size
);
303 *output_size
= info
->certid_raw_size
;
306 case GNUTLS_PKCS11_OBJ_ID_HEX
:
309 case GNUTLS_PKCS11_OBJ_LABEL
:
312 case GNUTLS_PKCS11_OBJ_TOKEN_LABEL
:
315 case GNUTLS_PKCS11_OBJ_TOKEN_SERIAL
:
318 case GNUTLS_PKCS11_OBJ_TOKEN_MANUFACTURER
:
319 str
= info
->manufacturer
;
321 case GNUTLS_PKCS11_OBJ_TOKEN_MODEL
:
324 case GNUTLS_PKCS11_OBJ_LIBRARY_DESCRIPTION
:
325 str
= info
->lib_desc
;
327 case GNUTLS_PKCS11_OBJ_LIBRARY_VERSION
:
328 str
= info
->lib_version
;
330 case GNUTLS_PKCS11_OBJ_LIBRARY_MANUFACTURER
:
331 str
= info
->lib_manufacturer
;
335 return GNUTLS_E_INVALID_REQUEST
;
340 if (len
+ 1 > *output_size
)
342 *output_size
= len
+ 1;
343 return GNUTLS_E_SHORT_MEMORY_BUFFER
;
346 strcpy (output
, str
);
357 * gnutls_pkcs11_init:
358 * @flags: %GNUTLS_PKCS11_FLAG_MANUAL or %GNUTLS_PKCS11_FLAG_AUTO
359 * @configfile: either NULL or the location of a configuration file
361 * This function will initialize the PKCS 11 subsystem in gnutls. It will
362 * read a configuration file if %GNUTLS_PKCS11_FLAG_AUTO is used or allow
363 * you to independently load PKCS 11 modules using gnutls_pkcs11_add_provider()
364 * if %GNUTLS_PKCS11_FLAG_MANUAL is specified.
366 * Normally you don't need to call this function since it is being called
367 * by gnutls_global_init() using the %GNUTLS_PKCS11_FLAG_AUTO. If other option
368 * is required then it must be called before it.
370 * Returns: On success, %GNUTLS_E_SUCCESS is returned, otherwise a
371 * negative error value.
374 gnutls_pkcs11_init (unsigned int flags
, const char *configfile
)
385 if (flags
== GNUTLS_PKCS11_FLAG_MANUAL
)
393 if (configfile
== NULL
)
394 configfile
= "/etc/gnutls/pkcs11.conf";
396 fp
= fopen (configfile
, "r");
400 _gnutls_debug_log ("Cannot load %s\n", configfile
);
401 return GNUTLS_E_FILE_ERROR
;
404 while (fgets (line
, sizeof (line
), fp
) != NULL
)
406 if (strncmp (line
, "load", sizeof ("load") - 1) == 0)
409 p
= strchr (line
, '=');
415 p
= strchr (line
, '\n');
421 ret
= gnutls_pkcs11_add_provider (library
, NULL
);
425 _gnutls_debug_log ("Cannot load provider: %s\n", library
);
437 * gnutls_pkcs11_deinit:
439 * This function will deinitialize the PKCS 11 subsystem in gnutls.
443 gnutls_pkcs11_deinit (void)
456 for (i
= 0; i
< active_providers
; i
++)
458 pakchois_module_destroy (providers
[i
].module
);
460 active_providers
= 0;
461 pakchois_destructor();
465 * gnutls_pkcs11_set_pin_function:
466 * @fn: The PIN callback
467 * @userdata: data to be supplied to callback
469 * This function will set a callback function to be used when a PIN
470 * is required for PKCS 11 operations.
472 * Callback for PKCS#11 PIN entry. The callback provides the PIN code
473 * to unlock the token with label 'token_label', specified by the URL
476 * The PIN code, as a NUL-terminated ASCII string, should be copied
477 * into the 'pin' buffer (of maximum size pin_max), and
478 * return 0 to indicate success. Alternatively, the callback may
479 * return a negative gnutls error code to indicate failure and cancel
480 * PIN entry (in which case, the contents of the 'pin' parameter are ignored).
482 * When a PIN is required, the callback will be invoked repeatedly
483 * (and indefinitely) until either the returned PIN code is correct,
484 * the callback returns failure, or the token refuses login (e.g. when
485 * the token is locked due to too many incorrect PINs!). For the
486 * first such invocation, the 'attempt' counter will have value zero;
487 * it will increase by one for each subsequent attempt.
489 * Returns: On success, %GNUTLS_E_SUCCESS is returned, otherwise a
490 * negative error value.
493 gnutls_pkcs11_set_pin_function (gnutls_pkcs11_pin_callback_t fn
,
501 * gnutls_pkcs11_set_token_function:
502 * @fn: The token callback
503 * @userdata: data to be supplied to callback
505 * This function will set a callback function to be used when a token
506 * needs to be inserted to continue PKCS 11 operations.
508 * Returns: On success, %GNUTLS_E_SUCCESS is returned, otherwise a
509 * negative error value.
512 gnutls_pkcs11_set_token_function (gnutls_pkcs11_token_callback_t fn
,
516 token_data
= userdata
;
520 unescape_string (char *output
, const char *input
, size_t * size
,
523 gnutls_buffer_st str
;
528 _gnutls_buffer_init (&str
);
530 /* find terminator */
531 p
= strchr (input
, terminator
);
535 len
= strlen (input
);
537 ret
= _gnutls_buffer_append_data (&str
, input
, len
);
544 ret
= _gnutls_buffer_unescape (&str
);
551 ret
= _gnutls_buffer_append_data (&str
, "", 1);
558 _gnutls_buffer_pop_data (&str
, output
, size
);
560 _gnutls_buffer_clear (&str
);
566 pkcs11_url_to_info (const char *url
, struct pkcs11_url_info
*info
)
572 memset (info
, 0, sizeof (*info
));
574 if (strstr (url
, "pkcs11:") == NULL
)
576 ret
= GNUTLS_E_PARSING_ERROR
;
580 if ((p1
= strstr (url
, "library-manufacturer=")) != NULL
)
582 p1
+= sizeof ("library-manufacturer=") - 1;
583 l
= sizeof (info
->lib_manufacturer
);
585 ret
= unescape_string (info
->lib_manufacturer
, p1
, &l
, ';');
592 if ((p1
= strstr (url
, "library-description=")) != NULL
)
594 p1
+= sizeof ("library-description=") - 1;
595 l
= sizeof (info
->lib_desc
);
597 ret
= unescape_string (info
->lib_desc
, p1
, &l
, ';');
604 if ((p1
= strstr (url
, "library-version=")) != NULL
)
606 p1
+= sizeof ("library-version=") - 1;
607 l
= sizeof (info
->lib_version
);
609 ret
= unescape_string (info
->lib_version
, p1
, &l
, ';');
616 if ((p1
= strstr (url
, ";manufacturer=")) != NULL
||
617 (p1
= strstr (url
, ":manufacturer=")) != NULL
)
620 p1
+= sizeof (";manufacturer=") - 1;
621 l
= sizeof (info
->manufacturer
);
623 ret
= unescape_string (info
->manufacturer
, p1
, &l
, ';');
630 if ((p1
= strstr (url
, "token=")) != NULL
)
632 p1
+= sizeof ("token=") - 1;
633 l
= sizeof (info
->token
);
635 ret
= unescape_string (info
->token
, p1
, &l
, ';');
642 if ((p1
= strstr (url
, "object=")) != NULL
)
644 p1
+= sizeof ("object=") - 1;
645 l
= sizeof (info
->label
);
647 ret
= unescape_string (info
->label
, p1
, &l
, ';');
654 if ((p1
= strstr (url
, "serial=")) != NULL
)
656 p1
+= sizeof ("serial=") - 1;
657 l
= sizeof (info
->serial
);
659 ret
= unescape_string (info
->serial
, p1
, &l
, ';');
666 if ((p1
= strstr (url
, "model=")) != NULL
)
668 p1
+= sizeof ("model=") - 1;
669 l
= sizeof (info
->model
);
671 ret
= unescape_string (info
->model
, p1
, &l
, ';');
678 if ((p1
= strstr (url
, "objecttype=")) != NULL
)
680 p1
+= sizeof ("objecttype=") - 1;
681 l
= sizeof (info
->type
);
683 ret
= unescape_string (info
->type
, p1
, &l
, ';');
690 if (((p1
= strstr (url
, ";id=")) != NULL
)
691 || ((p1
= strstr (url
, ":id=")) != NULL
))
693 p1
+= sizeof (";id=") - 1;
694 l
= sizeof (info
->certid_raw
);
696 ret
= unescape_string (info
->certid_raw
, p1
, &l
, ';');
701 /* not null terminated */
702 info
->certid_raw_size
= l
-1;
704 p2
= _gnutls_bin2hex(info
->certid_raw
, info
->certid_raw_size
,
705 info
->id
, sizeof(info
->id
), ":");
708 ret
= GNUTLS_E_PARSING_ERROR
;
721 #define INVALID_CHARS "\\/\"'%&#@!?$* <>{}[]()`|:;,.+-"
723 /* Appends @tname to @dest under the name @p11name.
724 * init indicates whether it is the initial addition to buffer.
727 append (gnutls_buffer_st
* dest
, const void *tname
, int tname_size
,
728 const char *p11name
, int all
, int init
)
730 gnutls_buffer_st tmpstr
;
733 _gnutls_buffer_init (&tmpstr
);
734 if ((ret
= _gnutls_buffer_append_data (&tmpstr
, tname
, tname_size
)) < 0)
740 ret
= _gnutls_buffer_escape (&tmpstr
, all
, INVALID_CHARS
);
747 if ((ret
= _gnutls_buffer_append_data (&tmpstr
, "", 1)) < 0)
754 _gnutls_buffer_append_printf (dest
, "%s%s=%s",
755 (init
!= 0) ? ";" : "", p11name
,
765 _gnutls_buffer_clear (&tmpstr
);
773 pkcs11_info_to_url (const struct pkcs11_url_info
*info
,
774 gnutls_pkcs11_url_type_t detailed
, char **url
)
776 gnutls_buffer_st str
;
780 _gnutls_buffer_init (&str
);
782 _gnutls_buffer_append_str (&str
, "pkcs11:");
786 ret
= append (&str
, info
->token
, strlen(info
->token
), "token", 0, init
);
797 ret
= append (&str
, info
->serial
, strlen(info
->serial
), "serial", 0, init
);
808 ret
= append (&str
, info
->model
, strlen(info
->model
), "model", 0, init
);
818 if (info
->manufacturer
[0])
820 ret
= append (&str
, info
->manufacturer
, strlen(info
->manufacturer
), "manufacturer", 0, init
);
831 ret
= append (&str
, info
->label
, strlen(info
->label
), "object", 0, init
);
842 ret
= append (&str
, info
->type
, strlen(info
->type
), "objecttype", 0, init
);
851 if (detailed
> GNUTLS_PKCS11_URL_GENERIC
)
853 if (info
->lib_manufacturer
[0])
856 append (&str
, info
->lib_manufacturer
, strlen(info
->lib_manufacturer
), "library-manufacturer",
866 if (info
->lib_desc
[0])
868 ret
= append (&str
, info
->lib_desc
, strlen(info
->lib_desc
), "library-description", 0, init
);
878 if (detailed
> GNUTLS_PKCS11_URL_LIB
)
880 if (info
->lib_version
[0])
882 ret
= append (&str
, info
->lib_version
, strlen(info
->lib_version
), "library-version", 0, init
);
892 if (info
->certid_raw_size
> 0)
894 ret
= append (&str
, info
->certid_raw
, info
->certid_raw_size
, "id", 1, init
);
902 _gnutls_buffer_append_data (&str
, "", 1);
909 _gnutls_buffer_clear (&str
);
914 * gnutls_pkcs11_obj_init:
915 * @obj: The structure to be initialized
917 * This function will initialize a pkcs11 certificate structure.
919 * Returns: On success, %GNUTLS_E_SUCCESS is returned, otherwise a
920 * negative error value.
923 gnutls_pkcs11_obj_init (gnutls_pkcs11_obj_t
* obj
)
925 *obj
= gnutls_calloc (1, sizeof (struct gnutls_pkcs11_obj_st
));
929 return GNUTLS_E_MEMORY_ERROR
;
936 * gnutls_pkcs11_obj_deinit:
937 * @obj: The structure to be initialized
939 * This function will deinitialize a certificate structure.
942 gnutls_pkcs11_obj_deinit (gnutls_pkcs11_obj_t obj
)
944 _gnutls_free_datum (&obj
->raw
);
949 * gnutls_pkcs11_obj_export:
950 * @obj: Holds the object
951 * @output_data: will contain a certificate PEM or DER encoded
952 * @output_data_size: holds the size of output_data (and will be
953 * replaced by the actual size of parameters)
955 * This function will export the pkcs11 object data. It is normal
956 * for PKCS #11 data to be inaccesible and in that case %GNUTLS_E_INVALID_REQUEST
959 * If the buffer provided is not long enough to hold the output, then
960 * *output_data_size is updated and GNUTLS_E_SHORT_MEMORY_BUFFER will
963 * If the structure is PEM encoded, it will have a header
964 * of "BEGIN CERTIFICATE".
966 * Return value: In case of failure a negative value will be
967 * returned, and 0 on success.
970 gnutls_pkcs11_obj_export (gnutls_pkcs11_obj_t obj
,
971 void *output_data
, size_t * output_data_size
)
973 if (obj
== NULL
|| obj
->raw
.data
== NULL
)
976 return GNUTLS_E_INVALID_REQUEST
;
979 if (output_data
== NULL
|| *output_data_size
< obj
->raw
.size
)
981 *output_data_size
= obj
->raw
.size
;
983 return GNUTLS_E_SHORT_MEMORY_BUFFER
;
985 *output_data_size
= obj
->raw
.size
;
987 memcpy (output_data
, obj
->raw
.data
, obj
->raw
.size
);
992 terminate_string (unsigned char *str
, size_t len
)
994 unsigned char *ptr
= str
+ len
- 1;
996 while ((*ptr
== ' ' || *ptr
== '\t' || *ptr
== '\0') && ptr
>= str
)
1001 else if (ptr
== str
+ len
- 1)
1002 str
[len
- 1] = '\0';
1008 pkcs11_find_object (pakchois_session_t
** _pks
,
1009 ck_object_handle_t
* _obj
,
1010 struct pkcs11_url_info
*info
, unsigned int flags
)
1013 pakchois_session_t
*pks
;
1014 ck_object_handle_t obj
;
1015 ck_object_class_t
class;
1016 struct ck_attribute a
[4];
1018 unsigned long count
;
1021 class = pkcs11_strtype_to_class (info
->type
);
1025 return GNUTLS_E_INVALID_REQUEST
;
1028 ret
= pkcs11_open_session (&pks
, info
, flags
& SESSION_LOGIN
);
1035 a
[a_vals
].type
= CKA_CLASS
;
1036 a
[a_vals
].value
= &class;
1037 a
[a_vals
].value_len
= sizeof class;
1040 if (info
->certid_raw_size
> 0)
1042 a
[a_vals
].type
= CKA_ID
;
1043 a
[a_vals
].value
= info
->certid_raw
;
1044 a
[a_vals
].value_len
= info
->certid_raw_size
;
1048 rv
= pakchois_find_objects_init (pks
, a
, a_vals
);
1052 _gnutls_debug_log ("pk11: FindObjectsInit failed.\n");
1053 ret
= pkcs11_rv_to_err (rv
);
1057 if (pakchois_find_objects (pks
, &obj
, 1, &count
) == CKR_OK
&& count
== 1)
1061 pakchois_find_objects_final (pks
);
1065 ret
= GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE
;
1066 pakchois_find_objects_final (pks
);
1068 pakchois_close_session (pks
);
1074 fix_strings (struct token_info
*info
)
1076 terminate_string (info
->tinfo
.manufacturer_id
,
1077 sizeof info
->tinfo
.manufacturer_id
);
1078 terminate_string (info
->tinfo
.label
, sizeof info
->tinfo
.label
);
1079 terminate_string (info
->tinfo
.model
, sizeof info
->tinfo
.model
);
1080 terminate_string (info
->tinfo
.serial_number
,
1081 sizeof info
->tinfo
.serial_number
);
1082 terminate_string (info
->sinfo
.slot_description
,
1083 sizeof info
->sinfo
.slot_description
);
1087 pkcs11_find_slot (pakchois_module_t
** module
, ck_slot_id_t
* slot
,
1088 struct pkcs11_url_info
*info
, struct token_info
*_tinfo
)
1092 for (x
= 0; x
< active_providers
; x
++)
1094 for (z
= 0; z
< providers
[x
].nslots
; z
++)
1096 struct token_info tinfo
;
1098 if (pakchois_get_token_info
1099 (providers
[x
].module
, providers
[x
].slots
[z
],
1100 &tinfo
.tinfo
) != CKR_OK
)
1104 tinfo
.sid
= providers
[x
].slots
[z
];
1105 tinfo
.prov
= &providers
[x
];
1107 if (pakchois_get_slot_info
1108 (providers
[x
].module
, providers
[x
].slots
[z
],
1109 &tinfo
.sinfo
) != CKR_OK
)
1114 /* XXX make wrapper for token_info? */
1115 fix_strings (&tinfo
);
1117 if (pkcs11_token_matches_info (info
, &tinfo
.tinfo
,
1118 &providers
[x
].info
) < 0)
1124 *module
= providers
[x
].module
;
1125 *slot
= providers
[x
].slots
[z
];
1128 memcpy (_tinfo
, &tinfo
, sizeof (tinfo
));
1135 return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE
;
1139 pkcs11_open_session (pakchois_session_t
** _pks
,
1140 struct pkcs11_url_info
*info
, unsigned int flags
)
1144 pakchois_session_t
*pks
= NULL
;
1145 pakchois_module_t
*module
;
1147 struct token_info tinfo
;
1149 ret
= pkcs11_find_slot (&module
, &slot
, info
, &tinfo
);
1156 rv
= pakchois_open_session (module
,
1158 ((flags
& SESSION_WRITE
)
1159 ? CKF_RW_SESSION
: 0) |
1160 CKF_SERIAL_SESSION
, NULL
, NULL
, &pks
);
1164 return pkcs11_rv_to_err (rv
);
1167 if (flags
& SESSION_LOGIN
)
1169 ret
= pkcs11_login (pks
, &tinfo
, (flags
& SESSION_SO
) ? 1 : 0);
1173 pakchois_close_session (pks
);
1185 _pkcs11_traverse_tokens (find_func_t find_func
, void *input
,
1189 int found
= 0, x
, z
, ret
;
1190 pakchois_session_t
*pks
= NULL
;
1192 for (x
= 0; x
< active_providers
; x
++)
1194 for (z
= 0; z
< providers
[x
].nslots
; z
++)
1196 struct token_info info
;
1198 ret
= GNUTLS_E_PKCS11_ERROR
;
1200 if (pakchois_get_token_info
1201 (providers
[x
].module
, providers
[x
].slots
[z
],
1202 &info
.tinfo
) != CKR_OK
)
1206 info
.sid
= providers
[x
].slots
[z
];
1207 info
.prov
= &providers
[x
];
1209 if (pakchois_get_slot_info
1210 (providers
[x
].module
, providers
[x
].slots
[z
],
1211 &info
.sinfo
) != CKR_OK
)
1216 /* XXX make wrapper for token_info? */
1217 fix_strings (&info
);
1219 rv
= pakchois_open_session (providers
[x
].module
,
1220 providers
[x
].slots
[z
],
1221 ((flags
& SESSION_WRITE
)
1222 ? CKF_RW_SESSION
: 0) |
1223 CKF_SERIAL_SESSION
, NULL
, NULL
, &pks
);
1229 if (flags
& SESSION_LOGIN
)
1231 ret
= pkcs11_login (pks
, &info
, (flags
& SESSION_SO
) ? 1 : 0);
1239 ret
= find_func (pks
, &info
, &providers
[x
].info
, input
);
1248 pakchois_close_session (pks
);
1259 ret
= find_func (pks
, NULL
, NULL
, input
);
1268 pakchois_close_session (pks
);
1275 pkcs11_obj_type_to_str (gnutls_pkcs11_obj_type_t type
)
1279 case GNUTLS_PKCS11_OBJ_X509_CRT
:
1281 case GNUTLS_PKCS11_OBJ_PUBKEY
:
1283 case GNUTLS_PKCS11_OBJ_PRIVKEY
:
1285 case GNUTLS_PKCS11_OBJ_SECRET_KEY
:
1287 case GNUTLS_PKCS11_OBJ_DATA
:
1289 case GNUTLS_PKCS11_OBJ_UNKNOWN
:
1295 /* imports a raw certificate from a token to a pkcs11_obj_t structure.
1298 pkcs11_obj_import (unsigned int class, gnutls_pkcs11_obj_t obj
,
1299 const gnutls_datum_t
* data
,
1300 const gnutls_datum_t
* id
,
1301 const gnutls_datum_t
* label
,
1302 struct ck_token_info
*tinfo
, struct ck_info
*lib_info
)
1309 case CKO_CERTIFICATE
:
1310 obj
->type
= GNUTLS_PKCS11_OBJ_X509_CRT
;
1312 case CKO_PUBLIC_KEY
:
1313 obj
->type
= GNUTLS_PKCS11_OBJ_PUBKEY
;
1315 case CKO_PRIVATE_KEY
:
1316 obj
->type
= GNUTLS_PKCS11_OBJ_PRIVKEY
;
1318 case CKO_SECRET_KEY
:
1319 obj
->type
= GNUTLS_PKCS11_OBJ_SECRET_KEY
;
1322 obj
->type
= GNUTLS_PKCS11_OBJ_DATA
;
1325 obj
->type
= GNUTLS_PKCS11_OBJ_UNKNOWN
;
1328 if (obj
->type
!= GNUTLS_PKCS11_OBJ_UNKNOWN
)
1329 strcpy (obj
->info
.type
, pkcs11_obj_type_to_str (obj
->type
));
1331 if (data
&& data
->data
)
1333 ret
= _gnutls_set_datum (&obj
->raw
, data
->data
, data
->size
);
1341 terminate_string (tinfo
->manufacturer_id
, sizeof tinfo
->manufacturer_id
);
1342 terminate_string (tinfo
->label
, sizeof tinfo
->label
);
1343 terminate_string (tinfo
->model
, sizeof tinfo
->model
);
1344 terminate_string (tinfo
->serial_number
, sizeof tinfo
->serial_number
);
1347 snprintf (obj
->info
.manufacturer
, sizeof (obj
->info
.manufacturer
),
1348 "%s", tinfo
->manufacturer_id
);
1349 snprintf (obj
->info
.token
, sizeof (obj
->info
.token
), "%s", tinfo
->label
);
1350 snprintf (obj
->info
.model
, sizeof (obj
->info
.model
), "%s", tinfo
->model
);
1351 snprintf (obj
->info
.serial
, sizeof (obj
->info
.serial
), "%s",
1352 tinfo
->serial_number
);
1354 snprintf (obj
->info
.lib_manufacturer
, sizeof (obj
->info
.lib_manufacturer
),
1355 "%s", lib_info
->manufacturer_id
);
1356 snprintf (obj
->info
.lib_desc
, sizeof (obj
->info
.lib_desc
), "%s",
1357 lib_info
->library_description
);
1358 snprintf (obj
->info
.lib_version
, sizeof (obj
->info
.lib_version
), "%u.%u",
1359 (unsigned int) lib_info
->library_version
.major
,
1360 (unsigned int) lib_info
->library_version
.minor
);
1364 if (label
&& label
->data
)
1366 memcpy (obj
->info
.label
, label
->data
, label
->size
);
1367 obj
->info
.label
[label
->size
] = 0;
1372 s
= _gnutls_bin2hex (id
->data
, id
->size
, obj
->info
.id
,
1373 sizeof (obj
->info
.id
), ":");
1377 return GNUTLS_E_PKCS11_ERROR
;
1380 memmove (obj
->info
.certid_raw
, id
->data
, id
->size
);
1381 obj
->info
.certid_raw_size
= id
->size
;
1388 pkcs11_obj_import_pubkey (pakchois_session_t
* pks
,
1389 ck_object_handle_t obj
,
1390 gnutls_pkcs11_obj_t crt
,
1391 const gnutls_datum_t
* id
,
1392 const gnutls_datum_t
* label
,
1393 struct ck_token_info
*tinfo
,
1394 struct ck_info
*lib_info
)
1397 struct ck_attribute a
[4];
1398 ck_key_type_t key_type
;
1404 a
[0].type
= CKA_KEY_TYPE
;
1405 a
[0].value
= &key_type
;
1406 a
[0].value_len
= sizeof (key_type
);
1408 if (pakchois_get_attribute_value (pks
, obj
, a
, 1) == CKR_OK
)
1413 a
[0].type
= CKA_MODULUS
;
1415 a
[0].value_len
= sizeof (tmp1
);
1416 a
[1].type
= CKA_PUBLIC_EXPONENT
;
1418 a
[1].value_len
= sizeof (tmp2
);
1420 if (pakchois_get_attribute_value (pks
, obj
, a
, 2) == CKR_OK
)
1424 _gnutls_set_datum (&crt
->pubkey
[0],
1425 a
[0].value
, a
[0].value_len
);
1429 _gnutls_set_datum (&crt
->pubkey
1430 [1], a
[1].value
, a
[1].value_len
);
1435 _gnutls_free_datum (&crt
->pubkey
[1]);
1436 _gnutls_free_datum (&crt
->pubkey
[0]);
1437 return GNUTLS_E_MEMORY_ERROR
;
1443 return GNUTLS_E_PKCS11_ERROR
;
1445 crt
->pk_algorithm
= GNUTLS_PK_RSA
;
1448 a
[0].type
= CKA_PRIME
;
1450 a
[0].value_len
= sizeof (tmp1
);
1451 a
[1].type
= CKA_SUBPRIME
;
1453 a
[1].value_len
= sizeof (tmp2
);
1455 if (pakchois_get_attribute_value (pks
, obj
, a
, 2) == CKR_OK
)
1458 _gnutls_set_datum (&crt
->pubkey
[0],
1459 a
[0].value
, a
[0].value_len
);
1463 _gnutls_set_datum (&crt
->pubkey
1464 [1], a
[1].value
, a
[1].value_len
);
1469 _gnutls_free_datum (&crt
->pubkey
[1]);
1470 _gnutls_free_datum (&crt
->pubkey
[0]);
1471 return GNUTLS_E_MEMORY_ERROR
;
1477 return GNUTLS_E_PKCS11_ERROR
;
1480 a
[0].type
= CKA_BASE
;
1482 a
[0].value_len
= sizeof (tmp1
);
1483 a
[1].type
= CKA_VALUE
;
1485 a
[1].value_len
= sizeof (tmp2
);
1487 if (pakchois_get_attribute_value (pks
, obj
, a
, 2) == CKR_OK
)
1490 _gnutls_set_datum (&crt
->pubkey
[2],
1491 a
[0].value
, a
[0].value_len
);
1495 _gnutls_set_datum (&crt
->pubkey
1496 [3], a
[1].value
, a
[1].value_len
);
1501 _gnutls_free_datum (&crt
->pubkey
[0]);
1502 _gnutls_free_datum (&crt
->pubkey
[1]);
1503 _gnutls_free_datum (&crt
->pubkey
[2]);
1504 _gnutls_free_datum (&crt
->pubkey
[3]);
1505 return GNUTLS_E_MEMORY_ERROR
;
1511 return GNUTLS_E_PKCS11_ERROR
;
1513 crt
->pk_algorithm
= GNUTLS_PK_RSA
;
1517 return GNUTLS_E_UNIMPLEMENTED_FEATURE
;
1521 /* read key usage flags */
1522 a
[0].type
= CKA_ENCRYPT
;
1524 a
[0].value_len
= sizeof (tval
);
1526 if (pakchois_get_attribute_value (pks
, obj
, a
, 1) == CKR_OK
)
1530 crt
->key_usage
|= GNUTLS_KEY_DATA_ENCIPHERMENT
;
1534 a
[0].type
= CKA_VERIFY
;
1536 a
[0].value_len
= sizeof (tval
);
1538 if (pakchois_get_attribute_value (pks
, obj
, a
, 1) == CKR_OK
)
1542 crt
->key_usage
|= GNUTLS_KEY_DIGITAL_SIGNATURE
|
1543 GNUTLS_KEY_KEY_CERT_SIGN
| GNUTLS_KEY_CRL_SIGN
1544 | GNUTLS_KEY_NON_REPUDIATION
;
1548 a
[0].type
= CKA_VERIFY_RECOVER
;
1550 a
[0].value_len
= sizeof (tval
);
1552 if (pakchois_get_attribute_value (pks
, obj
, a
, 1) == CKR_OK
)
1556 crt
->key_usage
|= GNUTLS_KEY_DIGITAL_SIGNATURE
|
1557 GNUTLS_KEY_KEY_CERT_SIGN
| GNUTLS_KEY_CRL_SIGN
1558 | GNUTLS_KEY_NON_REPUDIATION
;
1562 a
[0].type
= CKA_DERIVE
;
1564 a
[0].value_len
= sizeof (tval
);
1566 if (pakchois_get_attribute_value (pks
, obj
, a
, 1) == CKR_OK
)
1570 crt
->key_usage
|= GNUTLS_KEY_KEY_AGREEMENT
;
1574 a
[0].type
= CKA_WRAP
;
1576 a
[0].value_len
= sizeof (tval
);
1578 if (pakchois_get_attribute_value (pks
, obj
, a
, 1) == CKR_OK
)
1582 crt
->key_usage
|= GNUTLS_KEY_KEY_ENCIPHERMENT
;
1586 return pkcs11_obj_import (CKO_PUBLIC_KEY
, crt
, NULL
, id
, label
,
1591 pkcs11_strtype_to_class (const char *type
)
1593 ck_object_class_t
class;
1595 if (strcmp (type
, "cert") == 0)
1597 class = CKO_CERTIFICATE
;
1599 else if (strcmp (type
, "public") == 0)
1601 class = CKO_PUBLIC_KEY
;
1603 else if (strcmp (type
, "private") == 0)
1605 class = CKO_PRIVATE_KEY
;
1607 else if (strcmp (type
, "secretkey") == 0)
1609 class = CKO_SECRET_KEY
;
1611 else if (strcmp (type
, "data") == 0)
1625 find_obj_url (pakchois_session_t
* pks
, struct token_info
*info
,
1626 struct ck_info
*lib_info
, void *input
)
1628 struct url_find_data_st
*find_data
= input
;
1629 struct ck_attribute a
[4];
1630 ck_object_class_t
class = -1;
1631 ck_certificate_type_t type
= -1;
1633 ck_object_handle_t obj
;
1634 unsigned long count
, a_vals
;
1636 opaque
*cert_data
= NULL
;
1637 char label_tmp
[PKCS11_LABEL_SIZE
];
1640 { /* we don't support multiple calls */
1642 return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE
;
1645 /* do not bother reading the token if basic fields do not match
1647 if (pkcs11_token_matches_info
1648 (&find_data
->crt
->info
, &info
->tinfo
, lib_info
) < 0)
1651 return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE
;
1654 if (find_data
->crt
->info
.type
[0] != 0)
1656 class = pkcs11_strtype_to_class (find_data
->crt
->info
.type
);
1657 if (class == CKO_CERTIFICATE
)
1663 return GNUTLS_E_INVALID_REQUEST
;
1667 /* search the token for the id */
1669 cert_data
= gnutls_malloc (MAX_CERT_SIZE
);
1670 if (cert_data
== NULL
)
1673 return GNUTLS_E_MEMORY_ERROR
;
1676 /* Find objects with given class and type */
1679 a
[0].value
= find_data
->crt
->info
.certid_raw
;
1680 a
[0].value_len
= find_data
->crt
->info
.certid_raw_size
;
1686 a
[a_vals
].type
= CKA_CLASS
;
1687 a
[a_vals
].value
= &class;
1688 a
[a_vals
].value_len
= sizeof class;
1694 a
[a_vals
].type
= CKA_CERTIFICATE_TYPE
;
1695 a
[a_vals
].value
= &type
;
1696 a
[a_vals
].value_len
= sizeof type
;
1700 rv
= pakchois_find_objects_init (pks
, a
, a_vals
);
1704 _gnutls_debug_log ("pk11: FindObjectsInit failed.\n");
1705 ret
= pkcs11_rv_to_err (rv
);
1709 while (pakchois_find_objects (pks
, &obj
, 1, &count
) == CKR_OK
&& count
== 1)
1712 a
[0].type
= CKA_VALUE
;
1713 a
[0].value
= cert_data
;
1714 a
[0].value_len
= MAX_CERT_SIZE
;
1715 a
[1].type
= CKA_LABEL
;
1716 a
[1].value
= label_tmp
;
1717 a
[1].value_len
= sizeof (label_tmp
);
1719 if (pakchois_get_attribute_value (pks
, obj
, a
, 2) == CKR_OK
)
1721 gnutls_datum_t id
= { find_data
->crt
->info
.certid_raw
,
1722 find_data
->crt
->info
.certid_raw_size
1724 gnutls_datum_t data
= { a
[0].value
, a
[0].value_len
};
1725 gnutls_datum_t label
= { a
[1].value
, a
[1].value_len
};
1727 if (class == CKO_PUBLIC_KEY
)
1730 pkcs11_obj_import_pubkey (pks
, obj
,
1733 &info
->tinfo
, lib_info
);
1738 pkcs11_obj_import (class,
1741 &info
->tinfo
, lib_info
);
1754 _gnutls_debug_log ("pk11: Skipped cert, missing attrs.\n");
1761 ret
= GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE
;
1769 gnutls_free (cert_data
);
1770 pakchois_find_objects_final (pks
);
1776 pkcs11_obj_flags_to_int (unsigned int flags
)
1778 unsigned int ret_flags
= 0;
1780 if (flags
& GNUTLS_PKCS11_OBJ_FLAG_LOGIN
)
1781 ret_flags
|= SESSION_LOGIN
;
1782 if (flags
& GNUTLS_PKCS11_OBJ_FLAG_LOGIN_SO
)
1783 ret_flags
|= SESSION_LOGIN
|SESSION_SO
;
1789 * gnutls_pkcs11_privkey_import_url:
1790 * @cert: The structure to store the parsed certificate
1791 * @url: a PKCS 11 url identifying the key
1792 * @flags: One of GNUTLS_PKCS11_OBJ_* flags
1794 * This function will "import" a PKCS 11 URL identifying a certificate
1795 * key to the #gnutls_pkcs11_obj_t structure. This does not involve any
1796 * parsing (such as X.509 or OpenPGP) since the #gnutls_pkcs11_obj_t is
1797 * format agnostic. Only data are transferred.
1799 * Returns: On success, %GNUTLS_E_SUCCESS is returned, otherwise a
1800 * negative error value.
1803 gnutls_pkcs11_obj_import_url (gnutls_pkcs11_obj_t cert
, const char *url
,
1807 struct url_find_data_st find_data
;
1809 /* fill in the find data structure */
1810 find_data
.crt
= cert
;
1812 ret
= pkcs11_url_to_info (url
, &cert
->info
);
1820 _pkcs11_traverse_tokens (find_obj_url
, &find_data
,
1821 pkcs11_obj_flags_to_int (flags
));
1834 struct pkcs11_url_info info
;
1835 unsigned int seq
; /* which one we are looking for */
1836 unsigned int current
; /* which one are we now */
1840 find_token_num (pakchois_session_t
* pks
,
1841 struct token_info
*tinfo
,
1842 struct ck_info
*lib_info
, void *input
)
1844 struct token_num
*find_data
= input
;
1847 { /* we don't support multiple calls */
1849 return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE
;
1852 if (find_data
->current
== find_data
->seq
)
1854 strcpy (find_data
->info
.manufacturer
, tinfo
->tinfo
.manufacturer_id
);
1855 strcpy (find_data
->info
.token
, tinfo
->tinfo
.label
);
1856 strcpy (find_data
->info
.model
, tinfo
->tinfo
.model
);
1857 strcpy (find_data
->info
.serial
, tinfo
->tinfo
.serial_number
);
1859 strcpy (find_data
->info
.lib_manufacturer
, lib_info
->manufacturer_id
);
1860 strcpy (find_data
->info
.lib_desc
, lib_info
->library_description
);
1861 snprintf (find_data
->info
.lib_version
,
1862 sizeof (find_data
->info
.lib_version
), "%u.%u",
1863 (unsigned int) lib_info
->library_version
.major
,
1864 (unsigned int) lib_info
->library_version
.minor
);
1869 find_data
->current
++;
1870 /* search the token for the id */
1873 return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE
; /* non zero is enough */
1877 * gnutls_pkcs11_token_get_url:
1878 * @seq: sequence number starting from 0
1879 * @detailed: non zero if a detailed URL is required
1880 * @url: will contain an allocated url
1882 * This function will return the URL for each token available
1883 * in system. The url has to be released using gnutls_free()
1885 * Returns: On success, %GNUTLS_E_SUCCESS is returned, %GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE
1886 * if the sequence number exceeds the available tokens, otherwise a negative error value.
1890 gnutls_pkcs11_token_get_url (unsigned int seq
,
1891 gnutls_pkcs11_url_type_t detailed
, char **url
)
1894 struct token_num tn
;
1896 memset (&tn
, 0, sizeof (tn
));
1899 ret
= _pkcs11_traverse_tokens (find_token_num
, &tn
, 0);
1906 ret
= pkcs11_info_to_url (&tn
.info
, detailed
, url
);
1918 * gnutls_pkcs11_token_get_info:
1919 * @url: should contain a PKCS 11 URL
1920 * @ttype: Denotes the type of information requested
1921 * @output: where output will be stored
1922 * @output_size: contains the maximum size of the output and will be overwritten with actual
1924 * This function will return information about the PKCS 11 token such
1925 * as the label, id as well as token information where the key is stored.
1927 * Returns: zero on success or a negative value on error.
1930 gnutls_pkcs11_token_get_info (const char *url
,
1931 gnutls_pkcs11_token_info_t ttype
,
1932 void *output
, size_t * output_size
)
1936 struct pkcs11_url_info info
;
1939 ret
= pkcs11_url_to_info (url
, &info
);
1948 case GNUTLS_PKCS11_TOKEN_LABEL
:
1951 case GNUTLS_PKCS11_TOKEN_SERIAL
:
1954 case GNUTLS_PKCS11_TOKEN_MANUFACTURER
:
1955 str
= info
.manufacturer
;
1957 case GNUTLS_PKCS11_TOKEN_MODEL
:
1962 return GNUTLS_E_INVALID_REQUEST
;
1967 if (len
+ 1 > *output_size
)
1969 *output_size
= len
+ 1;
1970 return GNUTLS_E_SHORT_MEMORY_BUFFER
;
1973 strcpy (output
, str
);
1981 * gnutls_pkcs11_obj_export_url:
1982 * @obj: Holds the PKCS 11 certificate
1983 * @detailed: non zero if a detailed URL is required
1984 * @url: will contain an allocated url
1986 * This function will export a URL identifying the given certificate.
1988 * Returns: On success, %GNUTLS_E_SUCCESS is returned, otherwise a
1989 * negative error value.
1992 gnutls_pkcs11_obj_export_url (gnutls_pkcs11_obj_t obj
,
1993 gnutls_pkcs11_url_type_t detailed
, char **url
)
1997 ret
= pkcs11_info_to_url (&obj
->info
, detailed
, url
);
2008 * gnutls_pkcs11_obj_get_type:
2009 * @certificate: Holds the PKCS 11 certificate
2011 * This function will return the type of the certificate being
2012 * stored in the structure.
2014 * Returns: The type of the certificate.
2016 gnutls_pkcs11_obj_type_t
2017 gnutls_pkcs11_obj_get_type (gnutls_pkcs11_obj_t obj
)
2024 gnutls_buffer_st
*key_ids
;
2025 size_t key_ids_size
;
2029 pkcs11_login (pakchois_session_t
* pks
, const struct token_info
*info
, int so
)
2031 int attempt
= 0, ret
;
2035 struct pkcs11_url_info uinfo
;
2038 if (so
== 0 && (info
->tinfo
.flags
& CKF_LOGIN_REQUIRED
) == 0)
2041 _gnutls_debug_log ("pk11: No login required.\n");
2045 memset (&uinfo
, 0, sizeof (uinfo
));
2046 strcpy (uinfo
.manufacturer
, info
->tinfo
.manufacturer_id
);
2047 strcpy (uinfo
.token
, info
->tinfo
.label
);
2048 strcpy (uinfo
.model
, info
->tinfo
.model
);
2049 strcpy (uinfo
.serial
, info
->tinfo
.serial_number
);
2050 ret
= pkcs11_info_to_url (&uinfo
, 1, &token_url
);
2057 /* For a token with a "protected" (out-of-band) authentication
2058 * path, calling login with a NULL username is all that is
2060 if (info
->tinfo
.flags
& CKF_PROTECTED_AUTHENTICATION_PATH
)
2062 rv
= pakchois_login (pks
, (so
== 0) ? CKU_USER
: CKU_SO
, NULL
, 0);
2063 if (rv
== CKR_OK
|| rv
== CKR_USER_ALREADY_LOGGED_IN
)
2070 _gnutls_debug_log ("pk11: Protected login failed.\n");
2071 ret
= GNUTLS_E_PKCS11_ERROR
;
2076 /* Otherwise, PIN entry is necessary for login, so fail if there's
2081 _gnutls_debug_log ("pk11: No pin callback but login required.\n");
2082 ret
= GNUTLS_E_PKCS11_ERROR
;
2088 struct ck_token_info tinfo
;
2089 char pin
[GNUTLS_PKCS11_MAX_PIN_LEN
];
2092 memcpy(&tinfo
, &info
->tinfo
, sizeof(tinfo
));
2094 /* If login has been attempted once already, check the token
2095 * status again, the flags might change. */
2098 if (pakchois_get_token_info
2099 (info
->prov
->module
, info
->sid
, &tinfo
) != CKR_OK
)
2102 _gnutls_debug_log ("pk11: GetTokenInfo failed\n");
2103 ret
= GNUTLS_E_PKCS11_ERROR
;
2111 flags
|= GNUTLS_PKCS11_PIN_USER
;
2112 if (tinfo
.flags
& CKF_USER_PIN_COUNT_LOW
)
2113 flags
|= GNUTLS_PKCS11_PIN_COUNT_LOW
;
2114 if (tinfo
.flags
& CKF_USER_PIN_FINAL_TRY
)
2115 flags
|= GNUTLS_PKCS11_PIN_FINAL_TRY
;
2119 flags
|= GNUTLS_PKCS11_PIN_SO
;
2120 if (tinfo
.flags
& CKF_SO_PIN_COUNT_LOW
)
2121 flags
|= GNUTLS_PKCS11_PIN_COUNT_LOW
;
2122 if (tinfo
.flags
& CKF_SO_PIN_FINAL_TRY
)
2123 flags
|= GNUTLS_PKCS11_PIN_FINAL_TRY
;
2126 ret
= pin_func (pin_data
, attempt
++,
2128 (char *) info
->tinfo
.label
, flags
, pin
, sizeof (pin
));
2132 ret
= GNUTLS_E_PKCS11_PIN_ERROR
;
2135 pin_len
= strlen (pin
);
2137 rv
= pakchois_login (pks
, (so
== 0) ? CKU_USER
: CKU_SO
,
2138 (unsigned char *) pin
, pin_len
);
2140 /* Try to scrub the pin off the stack. Clever compilers will
2141 * probably optimize this away, oh well. */
2142 memset (pin
, 0, sizeof pin
);
2144 while (rv
== CKR_PIN_INCORRECT
);
2146 _gnutls_debug_log ("pk11: Login result = %lu\n", rv
);
2150 || rv
== CKR_USER_ALREADY_LOGGED_IN
) ? 0 : pkcs11_rv_to_err (rv
);
2153 gnutls_free (token_url
);
2158 find_privkeys (pakchois_session_t
* pks
, struct token_info
*info
,
2159 struct pkey_list
*list
)
2161 struct ck_attribute a
[3];
2162 ck_object_class_t
class;
2164 ck_object_handle_t obj
;
2165 unsigned long count
, current
;
2166 char certid_tmp
[PKCS11_ID_SIZE
];
2168 class = CKO_PRIVATE_KEY
;
2170 /* Find an object with private key class and a certificate ID
2171 * which matches the certificate. */
2172 /* FIXME: also match the cert subject. */
2173 a
[0].type
= CKA_CLASS
;
2174 a
[0].value
= &class;
2175 a
[0].value_len
= sizeof class;
2177 rv
= pakchois_find_objects_init (pks
, a
, 1);
2181 return pkcs11_rv_to_err (rv
);
2184 list
->key_ids_size
= 0;
2185 while (pakchois_find_objects (pks
, &obj
, 1, &count
) == CKR_OK
&& count
== 1)
2187 list
->key_ids_size
++;
2190 pakchois_find_objects_final (pks
);
2192 if (list
->key_ids_size
== 0)
2195 return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE
;
2199 gnutls_malloc (sizeof (gnutls_buffer_st
) * list
->key_ids_size
);
2200 if (list
->key_ids
== NULL
)
2203 return GNUTLS_E_MEMORY_ERROR
;
2207 a
[0].type
= CKA_CLASS
;
2208 a
[0].value
= &class;
2209 a
[0].value_len
= sizeof class;
2211 rv
= pakchois_find_objects_init (pks
, a
, 1);
2215 return pkcs11_rv_to_err (rv
);
2219 while (pakchois_find_objects (pks
, &obj
, 1, &count
) == CKR_OK
&& count
== 1)
2223 a
[0].value
= certid_tmp
;
2224 a
[0].value_len
= sizeof (certid_tmp
);
2226 _gnutls_buffer_init (&list
->key_ids
[current
]);
2228 if (pakchois_get_attribute_value (pks
, obj
, a
, 1) == CKR_OK
)
2230 _gnutls_buffer_append_data (&list
->key_ids
[current
],
2231 a
[0].value
, a
[0].value_len
);
2235 if (current
> list
->key_ids_size
)
2239 pakchois_find_objects_final (pks
);
2241 list
->key_ids_size
= current
- 1;
2246 /* Recover certificate list from tokens */
2250 find_objs (pakchois_session_t
* pks
, struct token_info
*info
,
2251 struct ck_info
*lib_info
, void *input
)
2253 struct crt_find_data_st
*find_data
= input
;
2254 struct ck_attribute a
[4];
2255 ck_object_class_t
class = -1;
2256 ck_certificate_type_t type
= -1;
2257 unsigned int trusted
;
2259 ck_object_handle_t obj
;
2260 unsigned long count
;
2262 char certid_tmp
[PKCS11_ID_SIZE
];
2263 char label_tmp
[PKCS11_LABEL_SIZE
];
2265 struct pkey_list plist
; /* private key holder */
2270 if (find_data
->current
<= *find_data
->n_list
)
2273 ret
= GNUTLS_E_SHORT_MEMORY_BUFFER
;
2275 *find_data
->n_list
= find_data
->current
;
2280 /* do not bother reading the token if basic fields do not match
2282 if (pkcs11_token_matches_info (&find_data
->info
, &info
->tinfo
, lib_info
) <
2286 return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE
;
2289 if (find_data
->info
.type
[0] != 0)
2291 class = pkcs11_strtype_to_class (find_data
->info
.type
);
2292 if (class == CKO_CERTIFICATE
)
2300 return GNUTLS_E_INVALID_REQUEST
;
2305 memset (&plist
, 0, sizeof (plist
));
2307 if (find_data
->flags
== GNUTLS_PKCS11_OBJ_ATTR_CRT_WITH_PRIVKEY
)
2309 ret
= find_privkeys (pks
, info
, &plist
);
2316 if (plist
.key_ids_size
== 0)
2319 return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE
;
2323 cert_data
= gnutls_malloc (MAX_CERT_SIZE
);
2324 if (cert_data
== NULL
)
2327 return GNUTLS_E_MEMORY_ERROR
;
2330 /* Find objects with cert class and X.509 cert type. */
2334 if (find_data
->flags
== GNUTLS_PKCS11_OBJ_ATTR_CRT_ALL
2335 || find_data
->flags
== GNUTLS_PKCS11_OBJ_ATTR_CRT_WITH_PRIVKEY
)
2337 class = CKO_CERTIFICATE
;
2341 a
[tot_values
].type
= CKA_CLASS
;
2342 a
[tot_values
].value
= &class;
2343 a
[tot_values
].value_len
= sizeof class;
2346 a
[tot_values
].type
= CKA_CERTIFICATE_TYPE
;
2347 a
[tot_values
].value
= &type
;
2348 a
[tot_values
].value_len
= sizeof type
;
2352 else if (find_data
->flags
== GNUTLS_PKCS11_OBJ_ATTR_CRT_TRUSTED
)
2354 class = CKO_CERTIFICATE
;
2358 a
[tot_values
].type
= CKA_CLASS
;
2359 a
[tot_values
].value
= &class;
2360 a
[tot_values
].value_len
= sizeof class;
2363 a
[tot_values
].type
= CKA_TRUSTED
;
2364 a
[tot_values
].value
= &trusted
;
2365 a
[tot_values
].value_len
= sizeof trusted
;
2369 else if (find_data
->flags
== GNUTLS_PKCS11_OBJ_ATTR_PUBKEY
)
2371 class = CKO_PUBLIC_KEY
;
2373 a
[tot_values
].type
= CKA_CLASS
;
2374 a
[tot_values
].value
= &class;
2375 a
[tot_values
].value_len
= sizeof class;
2378 else if (find_data
->flags
== GNUTLS_PKCS11_OBJ_ATTR_PRIVKEY
)
2380 class = CKO_PRIVATE_KEY
;
2382 a
[tot_values
].type
= CKA_CLASS
;
2383 a
[tot_values
].value
= &class;
2384 a
[tot_values
].value_len
= sizeof class;
2387 else if (find_data
->flags
== GNUTLS_PKCS11_OBJ_ATTR_ALL
)
2391 a
[tot_values
].type
= CKA_CLASS
;
2392 a
[tot_values
].value
= &class;
2393 a
[tot_values
].value_len
= sizeof class;
2398 a
[tot_values
].type
= CKA_CERTIFICATE_TYPE
;
2399 a
[tot_values
].value
= &type
;
2400 a
[tot_values
].value_len
= sizeof type
;
2407 ret
= GNUTLS_E_INVALID_REQUEST
;
2411 if (find_data
->info
.certid_raw_size
!= 0)
2413 a
[tot_values
].type
= CKA_ID
;
2414 a
[tot_values
].value
= find_data
->info
.certid_raw
;
2415 a
[tot_values
].value_len
= find_data
->info
.certid_raw_size
;
2419 rv
= pakchois_find_objects_init (pks
, a
, tot_values
);
2423 _gnutls_debug_log ("pk11: FindObjectsInit failed.\n");
2424 return pkcs11_rv_to_err (rv
);
2427 while (pakchois_find_objects (pks
, &obj
, 1, &count
) == CKR_OK
&& count
== 1)
2429 gnutls_datum_t label
, id
, value
;
2431 a
[0].type
= CKA_LABEL
;
2432 a
[0].value
= label_tmp
;
2433 a
[0].value_len
= sizeof label_tmp
;
2435 if (pakchois_get_attribute_value (pks
, obj
, a
, 1) == CKR_OK
)
2437 label
.data
= a
[0].value
;
2438 label
.size
= a
[0].value_len
;
2447 a
[0].value
= certid_tmp
;
2448 a
[0].value_len
= sizeof certid_tmp
;
2450 if (pakchois_get_attribute_value (pks
, obj
, a
, 1) == CKR_OK
)
2452 id
.data
= a
[0].value
;
2453 id
.size
= a
[0].value_len
;
2461 a
[0].type
= CKA_VALUE
;
2462 a
[0].value
= cert_data
;
2463 a
[0].value_len
= MAX_CERT_SIZE
;
2464 if (pakchois_get_attribute_value (pks
, obj
, a
, 1) == CKR_OK
)
2466 value
.data
= a
[0].value
;
2467 value
.size
= a
[0].value_len
;
2475 if (find_data
->flags
== GNUTLS_PKCS11_OBJ_ATTR_ALL
)
2477 a
[0].type
= CKA_CLASS
;
2478 a
[0].value
= &class;
2479 a
[0].value_len
= sizeof class;
2481 pakchois_get_attribute_value (pks
, obj
, a
, 1);
2484 if (find_data
->flags
== GNUTLS_PKCS11_OBJ_ATTR_CRT_WITH_PRIVKEY
)
2486 for (i
= 0; i
< plist
.key_ids_size
; i
++)
2488 if (plist
.key_ids
[i
].length
!=
2490 || memcmp (plist
.key_ids
[i
].data
,
2491 a
[1].value
, a
[1].value_len
) != 0)
2499 if (find_data
->current
< *find_data
->n_list
)
2502 gnutls_pkcs11_obj_init (&find_data
->p_list
[find_data
->current
]);
2509 if (class == CKO_PUBLIC_KEY
)
2512 pkcs11_obj_import_pubkey (pks
, obj
,
2514 [find_data
->current
],
2516 &info
->tinfo
, lib_info
);
2521 pkcs11_obj_import (class,
2523 [find_data
->current
],
2524 &value
, &id
, &label
,
2525 &info
->tinfo
, lib_info
);
2534 find_data
->current
++;
2538 gnutls_free (cert_data
);
2539 pakchois_find_objects_final (pks
);
2541 return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE
; /* continue until all tokens have been checked */
2544 gnutls_free (cert_data
);
2545 pakchois_find_objects_final (pks
);
2546 if (plist
.key_ids
!= NULL
)
2548 for (i
= 0; i
< plist
.key_ids_size
; i
++)
2550 _gnutls_buffer_clear (&plist
.key_ids
[i
]);
2552 gnutls_free (plist
.key_ids
);
2554 for (i
= 0; i
< find_data
->current
; i
++)
2556 gnutls_pkcs11_obj_deinit (find_data
->p_list
[i
]);
2558 find_data
->current
= 0;
2564 * gnutls_pkcs11_obj_list_import_url:
2565 * @p_list: An uninitialized object list (may be NULL)
2566 * @n_list: initially should hold the maximum size of the list. Will contain the actual size.
2567 * @url: A PKCS 11 url identifying a set of objects
2568 * @attrs: Attributes of type #gnutls_pkcs11_obj_attr_t that can be used to limit output
2569 * @flags: One of GNUTLS_PKCS11_OBJ_* flags
2571 * This function will initialize and set values to an object list
2572 * by using all objects identified by a PKCS 11 URL.
2574 * Returns: On success, %GNUTLS_E_SUCCESS is returned, otherwise a
2575 * negative error value.
2578 gnutls_pkcs11_obj_list_import_url (gnutls_pkcs11_obj_t
* p_list
,
2579 unsigned int *n_list
,
2581 gnutls_pkcs11_obj_attr_t attrs
,
2585 struct crt_find_data_st find_data
;
2587 /* fill in the find data structure */
2588 find_data
.p_list
= p_list
;
2589 find_data
.n_list
= n_list
;
2590 find_data
.flags
= attrs
;
2591 find_data
.current
= 0;
2593 if (url
== NULL
|| url
[0] == 0)
2598 ret
= pkcs11_url_to_info (url
, &find_data
.info
);
2606 _pkcs11_traverse_tokens (find_objs
, &find_data
,
2607 pkcs11_obj_flags_to_int (flags
));
2618 * gnutls_x509_crt_import_pkcs11_url:
2619 * @crt: A certificate of type #gnutls_x509_crt_t
2620 * @url: A PKCS 11 url
2621 * @flags: One of GNUTLS_PKCS11_OBJ_* flags
2623 * This function will import a PKCS 11 certificate directly from a token
2624 * without involving the #gnutls_pkcs11_obj_t structure. This function will
2625 * fail if the certificate stored is not of X.509 type.
2627 * Returns: On success, %GNUTLS_E_SUCCESS is returned, otherwise a
2628 * negative error value.
2631 gnutls_x509_crt_import_pkcs11_url (gnutls_x509_crt_t crt
,
2632 const char *url
, unsigned int flags
)
2634 gnutls_pkcs11_obj_t pcrt
;
2637 ret
= gnutls_pkcs11_obj_init (&pcrt
);
2644 ret
= gnutls_pkcs11_obj_import_url (pcrt
, url
, flags
);
2651 ret
= gnutls_x509_crt_import (crt
, &pcrt
->raw
, GNUTLS_X509_FMT_DER
);
2661 gnutls_pkcs11_obj_deinit (pcrt
);
2668 * gnutls_x509_crt_import_pkcs11:
2669 * @crt: A certificate of type #gnutls_x509_crt_t
2670 * @pkcs11_crt: A PKCS 11 object that contains a certificate
2672 * This function will import a PKCS 11 certificate to a #gnutls_x509_crt_t
2675 * Returns: On success, %GNUTLS_E_SUCCESS is returned, otherwise a
2676 * negative error value.
2679 gnutls_x509_crt_import_pkcs11 (gnutls_x509_crt_t crt
,
2680 gnutls_pkcs11_obj_t pkcs11_crt
)
2682 return gnutls_x509_crt_import (crt
, &pkcs11_crt
->raw
, GNUTLS_X509_FMT_DER
);
2686 * gnutls_x509_crt_list_import_pkcs11:
2687 * @certs: A list of certificates of type #gnutls_x509_crt_t
2688 * @cert_max: The maximum size of the list
2689 * @objs: A list of PKCS 11 objects
2692 * This function will import a PKCS 11 certificate list to a list of
2693 * #gnutls_x509_crt_t structure. These must not be initialized.
2695 * Returns: On success, %GNUTLS_E_SUCCESS is returned, otherwise a
2696 * negative error value.
2699 gnutls_x509_crt_list_import_pkcs11 (gnutls_x509_crt_t
* certs
,
2700 unsigned int cert_max
,
2701 gnutls_pkcs11_obj_t
* const objs
,
2707 for (i
= 0; i
< cert_max
; i
++)
2709 ret
= gnutls_x509_crt_init (&certs
[i
]);
2716 ret
= gnutls_x509_crt_import_pkcs11 (certs
[i
], objs
[i
]);
2727 for (j
= 0; j
< i
; j
++)
2729 gnutls_x509_crt_deinit (certs
[j
]);
2736 find_flags (pakchois_session_t
* pks
, struct token_info
*info
,
2737 struct ck_info
*lib_info
, void *input
)
2739 struct flags_find_data_st
*find_data
= input
;
2742 { /* we don't support multiple calls */
2744 return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE
;
2747 /* do not bother reading the token if basic fields do not match
2749 if (pkcs11_token_matches_info (&find_data
->info
, &info
->tinfo
, lib_info
) <
2753 return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE
;
2758 find_data
->slot_flags
= info
->sinfo
.flags
;
2764 * gnutls_pkcs11_token_get_flags:
2765 * @url: should contain a PKCS 11 URL
2766 * @flags: The output flags (GNUTLS_PKCS11_TOKEN_*)
2768 * This function will return information about the PKCS 11 token flags.
2770 * Returns: zero on success or a negative value on error.
2773 gnutls_pkcs11_token_get_flags (const char *url
, unsigned int *flags
)
2775 struct flags_find_data_st find_data
;
2778 ret
= pkcs11_url_to_info (url
, &find_data
.info
);
2785 ret
= _pkcs11_traverse_tokens (find_flags
, &find_data
, 0);
2793 if (find_data
.slot_flags
& CKF_HW_SLOT
)
2794 *flags
|= GNUTLS_PKCS11_TOKEN_HW
;
2802 * gnutls_pkcs11_token_get_mechanism:
2803 * @url: should contain a PKCS 11 URL
2804 * @idx: The index of the mechanism
2805 * @mechanism: The PKCS #11 mechanism ID
2807 * This function will return the names of the supported mechanisms
2808 * by the token. It should be called with an increasing index until
2809 * it return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE.
2811 * Returns: zero on success or a negative value on error.
2814 gnutls_pkcs11_token_get_mechanism (const char *url
, int idx
,
2815 unsigned long *mechanism
)
2819 pakchois_module_t
*module
;
2821 struct token_info tinfo
;
2822 struct pkcs11_url_info info
;
2823 unsigned long count
;
2824 ck_mechanism_type_t mlist
[400];
2826 ret
= pkcs11_url_to_info (url
, &info
);
2834 ret
= pkcs11_find_slot (&module
, &slot
, &info
, &tinfo
);
2841 count
= sizeof (mlist
) / sizeof (mlist
[0]);
2842 rv
= pakchois_get_mechanism_list (module
, slot
, mlist
, &count
);
2846 return pkcs11_rv_to_err (rv
);
2852 return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE
;
2855 *mechanism
= mlist
[idx
];
2863 gnutls_pkcs11_type_get_name (gnutls_pkcs11_obj_type_t type
)
2867 case GNUTLS_PKCS11_OBJ_X509_CRT
:
2868 return "X.509 Certificate";
2869 case GNUTLS_PKCS11_OBJ_PUBKEY
:
2870 return "Public key";
2871 case GNUTLS_PKCS11_OBJ_PRIVKEY
:
2872 return "Private key";
2873 case GNUTLS_PKCS11_OBJ_SECRET_KEY
:
2874 return "Secret key";
2875 case GNUTLS_PKCS11_OBJ_DATA
:
2877 case GNUTLS_PKCS11_OBJ_UNKNOWN
:
2884 pkcs11_token_matches_info (struct pkcs11_url_info
*info
,
2885 struct ck_token_info
*tinfo
,
2886 struct ck_info
*lib_info
)
2888 if (info
->manufacturer
[0] != 0)
2890 if (strcmp (info
->manufacturer
, tinfo
->manufacturer_id
) != 0)
2891 return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE
;
2894 if (info
->token
[0] != 0)
2896 if (strcmp (info
->token
, tinfo
->label
) != 0)
2897 return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE
;
2900 if (info
->model
[0] != 0)
2902 if (strcmp (info
->model
, tinfo
->model
) != 0)
2903 return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE
;
2906 if (info
->serial
[0] != 0)
2908 if (strcmp (info
->serial
, tinfo
->serial_number
) != 0)
2909 return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE
;
2912 if (info
->lib_manufacturer
[0] != 0)
2914 if (strcmp (info
->lib_manufacturer
, lib_info
->manufacturer_id
) != 0)
2915 return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE
;
2918 if (info
->lib_desc
[0] != 0)
2920 if (strcmp (info
->lib_desc
, lib_info
->library_description
) != 0)
2921 return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE
;
2924 if (info
->lib_version
[0] != 0)
2928 snprintf (version
, sizeof (version
), "%u.%u",
2929 (unsigned int) lib_info
->library_version
.major
,
2930 (unsigned int) lib_info
->library_version
.minor
);
2931 if (strcmp (info
->lib_version
, version
) != 0)
2932 return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE
;