2 * GnuTLS PKCS#11 support
3 * Copyright (C) 2010-2012 Free Software Foundation, Inc.
5 * Authors: Nikos Mavrogiannopoulos, Stef Walter
7 * The GnuTLS is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public License
9 * as published by the Free Software Foundation; either version 3 of
10 * the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>
21 #include <gnutls_int.h>
22 #include <gnutls/pkcs11.h>
25 #include <gnutls_errors.h>
26 #include <gnutls_datum.h>
27 #include <pkcs11_int.h>
28 #include <gnutls_sig.h>
29 #include <p11-kit/uri.h>
31 struct gnutls_pkcs11_privkey_st
33 gnutls_pk_algorithm_t pk_algorithm
;
35 struct p11_kit_uri
*info
;
37 struct pkcs11_session_info sinfo
;
38 ck_object_handle_t obj
; /* the key in the session */
40 struct pin_info_st pin
;
44 * gnutls_pkcs11_privkey_init:
45 * @key: The structure to be initialized
47 * This function will initialize an private key structure.
49 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
50 * negative error value.
53 gnutls_pkcs11_privkey_init (gnutls_pkcs11_privkey_t
* key
)
55 *key
= gnutls_calloc (1, sizeof (struct gnutls_pkcs11_privkey_st
));
59 return GNUTLS_E_MEMORY_ERROR
;
62 (*key
)->info
= p11_kit_uri_new ();
63 if ((*key
)->info
== NULL
)
67 return GNUTLS_E_MEMORY_ERROR
;
74 * gnutls_pkcs11_privkey_deinit:
75 * @key: The structure to be initialized
77 * This function will deinitialize a private key structure.
80 gnutls_pkcs11_privkey_deinit (gnutls_pkcs11_privkey_t key
)
82 p11_kit_uri_free (key
->info
);
83 if (key
->sinfo
.init
!= 0)
84 pkcs11_close_session (&key
->sinfo
);
89 * gnutls_pkcs11_privkey_get_pk_algorithm:
90 * @key: should contain a #gnutls_pkcs11_privkey_t structure
91 * @bits: if bits is non null it will hold the size of the parameters' in bits
93 * This function will return the public key algorithm of a private
96 * Returns: a member of the #gnutls_pk_algorithm_t enumeration on
97 * success, or a negative error code on error.
100 gnutls_pkcs11_privkey_get_pk_algorithm (gnutls_pkcs11_privkey_t key
,
104 *bits
= 0; /* FIXME */
105 return key
->pk_algorithm
;
109 * gnutls_pkcs11_privkey_get_info:
110 * @pkey: should contain a #gnutls_pkcs11_privkey_t structure
111 * @itype: Denotes the type of information requested
112 * @output: where output will be stored
113 * @output_size: contains the maximum size of the output and will be overwritten with actual
115 * This function will return information about the PKCS 11 private key such
116 * as the label, id as well as token information where the key is stored. When
117 * output is text it returns null terminated string although #output_size contains
118 * the size of the actual data only.
120 * Returns: %GNUTLS_E_SUCCESS (0) on success or a negative error code on error.
123 gnutls_pkcs11_privkey_get_info (gnutls_pkcs11_privkey_t pkey
,
124 gnutls_pkcs11_obj_info_t itype
,
125 void *output
, size_t * output_size
)
127 return pkcs11_get_info (pkey
->info
, itype
, output
, output_size
);
131 #define FIND_OBJECT(sinfo, pin_info, obj, key) \
135 ret = pkcs11_find_object (sinfo, pin_info, &obj, key->info, \
137 if (ret == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) { \
138 if (_gnutls_token_func) \
140 rret = pkcs11_call_token_func (key->info, retries++); \
141 if (rret == 0) continue; \
143 return gnutls_assert_val(ret); \
144 } else if (ret < 0) { \
145 return gnutls_assert_val(ret); \
150 * _gnutls_pkcs11_privkey_sign_hash:
151 * @key: Holds the key
152 * @hash: holds the data to be signed (should be output of a hash)
153 * @signature: will contain the signature allocated with gnutls_malloc()
155 * This function will sign the given data using a signature algorithm
156 * supported by the private key. It is assumed that the given data
157 * are the output of a hash function.
159 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
160 * negative error value.
163 _gnutls_pkcs11_privkey_sign_hash (gnutls_pkcs11_privkey_t key
,
164 const gnutls_datum_t
* hash
,
165 gnutls_datum_t
* signature
)
169 struct ck_mechanism mech
;
170 unsigned long siglen
;
171 struct pkcs11_session_info _sinfo
;
172 struct pkcs11_session_info
*sinfo
;
173 ck_object_handle_t obj
;
175 if (key
->sinfo
.init
!= 0)
183 memset(sinfo
, 0, sizeof(*sinfo
));
184 FIND_OBJECT (sinfo
, &key
->pin
, obj
, key
);
187 mech
.mechanism
= pk_to_mech(key
->pk_algorithm
);
188 mech
.parameter
= NULL
;
189 mech
.parameter_len
= 0;
191 /* Initialize signing operation; using the private key discovered
193 rv
= pkcs11_sign_init (sinfo
->module
, sinfo
->pks
, &mech
, obj
);
197 ret
= pkcs11_rv_to_err (rv
);
201 /* Work out how long the signature must be: */
202 rv
= pkcs11_sign (sinfo
->module
, sinfo
->pks
, hash
->data
, hash
->size
, NULL
, &siglen
);
206 ret
= pkcs11_rv_to_err (rv
);
210 signature
->data
= gnutls_malloc (siglen
);
211 signature
->size
= siglen
;
213 rv
= pkcs11_sign (sinfo
->module
, sinfo
->pks
, hash
->data
, hash
->size
, signature
->data
, &siglen
);
216 gnutls_free (signature
->data
);
218 ret
= pkcs11_rv_to_err (rv
);
222 signature
->size
= siglen
;
227 if (sinfo
!= &key
->sinfo
)
228 pkcs11_close_session (sinfo
);
234 * gnutls_pkcs11_privkey_import_url:
235 * @pkey: The structure to store the parsed key
236 * @url: a PKCS 11 url identifying the key
237 * @flags: sequence of GNUTLS_PKCS_PRIVKEY_*
239 * This function will "import" a PKCS 11 URL identifying a private
240 * key to the #gnutls_pkcs11_privkey_t structure. In reality since
241 * in most cases keys cannot be exported, the private key structure
242 * is being associated with the available operations on the token.
244 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
245 * negative error value.
248 gnutls_pkcs11_privkey_import_url (gnutls_pkcs11_privkey_t pkey
,
249 const char *url
, unsigned int flags
)
252 struct ck_attribute
*attr
;
253 ck_object_handle_t obj
;
254 struct ck_attribute a
[4];
255 ck_key_type_t key_type
;
256 struct pkcs11_session_info sinfo
;
258 memset(&sinfo
, 0, sizeof(sinfo
));
260 ret
= pkcs11_url_to_info (url
, &pkey
->info
);
269 attr
= p11_kit_uri_get_attribute (pkey
->info
, CKA_CLASS
);
270 if (!attr
|| attr
->value_len
!= sizeof (ck_object_class_t
) ||
271 *(ck_object_class_t
*)attr
->value
!= CKO_PRIVATE_KEY
)
274 return GNUTLS_E_INVALID_REQUEST
;
277 attr
= p11_kit_uri_get_attribute (pkey
->info
, CKA_ID
);
278 if (!attr
|| !attr
->value_len
)
280 attr
= p11_kit_uri_get_attribute (pkey
->info
, CKA_LABEL
);
281 if (!attr
|| !attr
->value_len
)
284 return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE
;
288 FIND_OBJECT (&sinfo
, &pkey
->pin
, obj
, pkey
);
290 a
[0].type
= CKA_KEY_TYPE
;
291 a
[0].value
= &key_type
;
292 a
[0].value_len
= sizeof (key_type
);
294 if (pkcs11_get_attribute_value (sinfo
.module
, sinfo
.pks
, obj
, a
, 1) == CKR_OK
)
296 pkey
->pk_algorithm
= mech_to_pk(key_type
);
297 if (pkey
->pk_algorithm
== GNUTLS_PK_UNKNOWN
)
299 _gnutls_debug_log("Cannot determine PKCS #11 key algorithm\n");
300 ret
= GNUTLS_E_UNKNOWN_ALGORITHM
;
307 if (pkey
->sinfo
.init
)
308 pkcs11_close_session (&pkey
->sinfo
);
310 if (sinfo
.tinfo
.max_session_count
!= 1)
312 /* We do not keep the session open in tokens that can
313 * only support a single session.
315 memcpy(&pkey
->sinfo
, &sinfo
, sizeof(pkey
->sinfo
));
321 pkcs11_close_session (&sinfo
);
327 * _gnutls_pkcs11_privkey_decrypt_data:
328 * @key: Holds the key
329 * @flags: should be 0 for now
330 * @ciphertext: holds the data to be signed
331 * @plaintext: will contain the plaintext, allocated with gnutls_malloc()
333 * This function will decrypt the given data using the public key algorithm
334 * supported by the private key.
336 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
337 * negative error value.
340 _gnutls_pkcs11_privkey_decrypt_data (gnutls_pkcs11_privkey_t key
,
342 const gnutls_datum_t
* ciphertext
,
343 gnutls_datum_t
* plaintext
)
347 struct ck_mechanism mech
;
348 unsigned long siglen
;
349 ck_object_handle_t obj
;
350 struct pkcs11_session_info _sinfo
;
351 struct pkcs11_session_info
*sinfo
;
353 if (key
->sinfo
.init
!= 0)
361 memset(sinfo
, 0, sizeof(*sinfo
));
362 FIND_OBJECT (sinfo
, &key
->pin
, obj
, key
);
365 if (key
->pk_algorithm
!= GNUTLS_PK_RSA
)
366 return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST
);
368 mech
.mechanism
= CKM_RSA_PKCS
;
369 mech
.parameter
= NULL
;
370 mech
.parameter_len
= 0;
372 /* Initialize signing operation; using the private key discovered
374 rv
= pkcs11_decrypt_init (sinfo
->module
, sinfo
->pks
, &mech
, obj
);
378 ret
= pkcs11_rv_to_err (rv
);
382 /* Work out how long the plaintext must be: */
383 rv
= pkcs11_decrypt (sinfo
->module
, sinfo
->pks
, ciphertext
->data
, ciphertext
->size
,
388 ret
= pkcs11_rv_to_err (rv
);
392 plaintext
->data
= gnutls_malloc (siglen
);
393 plaintext
->size
= siglen
;
395 rv
= pkcs11_decrypt (sinfo
->module
, sinfo
->pks
, ciphertext
->data
, ciphertext
->size
,
396 plaintext
->data
, &siglen
);
399 gnutls_free (plaintext
->data
);
401 ret
= pkcs11_rv_to_err (rv
);
405 plaintext
->size
= siglen
;
410 if (key
->sinfo
.init
== 0)
411 pkcs11_close_session (sinfo
);
417 * gnutls_pkcs11_privkey_export_url:
418 * @key: Holds the PKCS 11 key
419 * @detailed: non zero if a detailed URL is required
420 * @url: will contain an allocated url
422 * This function will export a URL identifying the given key.
424 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
425 * negative error value.
428 gnutls_pkcs11_privkey_export_url (gnutls_pkcs11_privkey_t key
,
429 gnutls_pkcs11_url_type_t detailed
,
434 ret
= pkcs11_info_to_url (key
->info
, detailed
, url
);
446 * gnutls_pkcs11_privkey_generate:
448 * @pk: the public key algorithm
449 * @bits: the security bits
451 * @flags: should be zero
453 * This function will generate a private key in the specified
454 * by the @url token. The private key will be generate within
455 * the token and will not be exportable.
457 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
458 * negative error value.
463 gnutls_pkcs11_privkey_generate (const char* url
, gnutls_pk_algorithm_t pk
,
464 unsigned int bits
, const char* label
,
468 const ck_bool_t tval
= 1;
469 const ck_bool_t fval
= 0;
470 struct pkcs11_session_info sinfo
;
471 struct p11_kit_uri
*info
= NULL
;
473 struct ck_attribute a
[10], p
[10];
474 ck_object_handle_t pub
, priv
;
475 unsigned long _bits
= bits
;
477 struct ck_mechanism mech
;
479 memset(&sinfo
, 0, sizeof(sinfo
));
481 ret
= pkcs11_url_to_info (url
, &info
);
489 pkcs11_open_session (&sinfo
, NULL
, info
,
490 SESSION_WRITE
| pkcs11_obj_flags_to_int (flags
));
491 p11_kit_uri_free (info
);
499 /* a holds the public key template
500 * and p the private key */
502 mech
.parameter
= NULL
;
503 mech
.parameter_len
= 0;
504 mech
.mechanism
= pk_to_genmech(pk
);
509 p
[p_val
].type
= CKA_DECRYPT
;
510 p
[p_val
].value
= (void*)&tval
;
511 p
[p_val
].value_len
= sizeof (tval
);
514 p
[p_val
].type
= CKA_SIGN
;
515 p
[p_val
].value
= (void*)&tval
;
516 p
[p_val
].value_len
= sizeof (tval
);
519 a
[a_val
].type
= CKA_ENCRYPT
;
520 a
[a_val
].value
= (void*)&tval
;
521 a
[a_val
].value_len
= sizeof (tval
);
524 a
[a_val
].type
= CKA_VERIFY
;
525 a
[a_val
].value
= (void*)&tval
;
526 a
[a_val
].value_len
= sizeof (tval
);
529 a
[a_val
].type
= CKA_MODULUS_BITS
;
530 a
[a_val
].value
= &_bits
;
531 a
[a_val
].value_len
= sizeof (_bits
);
535 p
[p_val
].type
= CKA_SIGN
;
536 p
[p_val
].value
= (void*)&tval
;
537 p
[p_val
].value_len
= sizeof (tval
);
540 a
[a_val
].type
= CKA_VERIFY
;
541 a
[a_val
].value
= (void*)&tval
;
542 a
[a_val
].value_len
= sizeof (tval
);
545 a
[a_val
].type
= CKA_MODULUS_BITS
;
546 a
[a_val
].value
= &_bits
;
547 a
[a_val
].value_len
= sizeof (_bits
);
551 p
[p_val
].type
= CKA_SIGN
;
552 p
[p_val
].value
= (void*)&tval
;
553 p
[p_val
].value_len
= sizeof (tval
);
556 a
[a_val
].type
= CKA_VERIFY
;
557 a
[a_val
].value
= (void*)&tval
;
558 a
[a_val
].value_len
= sizeof (tval
);
561 a
[a_val
].type
= CKA_MODULUS_BITS
;
562 a
[a_val
].value
= &_bits
;
563 a
[a_val
].value_len
= sizeof (_bits
);
567 ret
= gnutls_assert_val(GNUTLS_E_INVALID_REQUEST
);
571 /* a private key is set always as private unless
572 * requested otherwise
574 if (flags
& GNUTLS_PKCS11_OBJ_FLAG_MARK_NOT_PRIVATE
)
576 p
[p_val
].type
= CKA_PRIVATE
;
577 p
[p_val
].value
= (void*)&fval
;
578 p
[p_val
].value_len
= sizeof(fval
);
583 p
[p_val
].type
= CKA_PRIVATE
;
584 p
[p_val
].value
= (void*)&tval
;
585 p
[p_val
].value_len
= sizeof (tval
);
589 p
[p_val
].type
= CKA_TOKEN
;
590 p
[p_val
].value
= (void *)&tval
;
591 p
[p_val
].value_len
= sizeof (tval
);
596 p
[p_val
].type
= CKA_LABEL
;
597 p
[p_val
].value
= (void*)label
;
598 p
[p_val
].value_len
= strlen (label
);
601 a
[a_val
].type
= CKA_LABEL
;
602 a
[a_val
].value
= (void*)label
;
603 a
[a_val
].value_len
= strlen (label
);
607 if (flags
& GNUTLS_PKCS11_OBJ_FLAG_MARK_SENSITIVE
)
609 p
[p_val
].type
= CKA_SENSITIVE
;
610 p
[p_val
].value
= (void*)&tval
;
611 p
[p_val
].value_len
= sizeof (tval
);
616 p
[p_val
].type
= CKA_SENSITIVE
;
617 p
[p_val
].value
= (void*)&fval
;
618 p
[p_val
].value_len
= sizeof (fval
);
622 rv
= pkcs11_generate_key_pair( sinfo
.module
, sinfo
.pks
, &mech
, a
, a_val
, p
, p_val
, &pub
, &priv
);
626 _gnutls_debug_log ("pkcs11: %s\n", pkcs11_strerror (rv
));
627 ret
= pkcs11_rv_to_err (rv
);
634 pkcs11_close_session (&sinfo
);
640 * gnutls_pkcs11_privkey_set_pin_function:
641 * @obj: The object structure
643 * @userdata: data associated with the callback
645 * This function will set a callback function to be used when
646 * required to access the object. This function overrides the global
647 * set using gnutls_pkcs11_set_pin_function().
652 void gnutls_pkcs11_privkey_set_pin_function (gnutls_pkcs11_privkey_t key
,
653 gnutls_pin_callback_t fn
, void *userdata
)
656 key
->pin
.data
= userdata
;