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 <gnutls_pk.h>
30 #include <p11-kit/uri.h>
32 struct gnutls_pkcs11_privkey_st
34 gnutls_pk_algorithm_t pk_algorithm
;
36 struct p11_kit_uri
*info
;
38 struct pkcs11_session_info sinfo
;
39 ck_object_handle_t obj
; /* the key in the session */
41 struct pin_info_st pin
;
45 * gnutls_pkcs11_privkey_init:
46 * @key: The structure to be initialized
48 * This function will initialize an private key structure.
50 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
51 * negative error value.
54 gnutls_pkcs11_privkey_init (gnutls_pkcs11_privkey_t
* key
)
56 *key
= gnutls_calloc (1, sizeof (struct gnutls_pkcs11_privkey_st
));
60 return GNUTLS_E_MEMORY_ERROR
;
63 (*key
)->info
= p11_kit_uri_new ();
64 if ((*key
)->info
== NULL
)
68 return GNUTLS_E_MEMORY_ERROR
;
75 * gnutls_pkcs11_privkey_deinit:
76 * @key: The structure to be initialized
78 * This function will deinitialize a private key structure.
81 gnutls_pkcs11_privkey_deinit (gnutls_pkcs11_privkey_t key
)
83 p11_kit_uri_free (key
->info
);
84 if (key
->sinfo
.init
!= 0)
85 pkcs11_close_session (&key
->sinfo
);
90 * gnutls_pkcs11_privkey_get_pk_algorithm:
91 * @key: should contain a #gnutls_pkcs11_privkey_t structure
92 * @bits: if bits is non null it will hold the size of the parameters' in bits
94 * This function will return the public key algorithm of a private
97 * Returns: a member of the #gnutls_pk_algorithm_t enumeration on
98 * success, or a negative error code on error.
101 gnutls_pkcs11_privkey_get_pk_algorithm (gnutls_pkcs11_privkey_t key
,
105 *bits
= 0; /* FIXME */
106 return key
->pk_algorithm
;
110 * gnutls_pkcs11_privkey_get_info:
111 * @pkey: should contain a #gnutls_pkcs11_privkey_t structure
112 * @itype: Denotes the type of information requested
113 * @output: where output will be stored
114 * @output_size: contains the maximum size of the output and will be overwritten with actual
116 * This function will return information about the PKCS 11 private key such
117 * as the label, id as well as token information where the key is stored. When
118 * output is text it returns null terminated string although #output_size contains
119 * the size of the actual data only.
121 * Returns: %GNUTLS_E_SUCCESS (0) on success or a negative error code on error.
124 gnutls_pkcs11_privkey_get_info (gnutls_pkcs11_privkey_t pkey
,
125 gnutls_pkcs11_obj_info_t itype
,
126 void *output
, size_t * output_size
)
128 return pkcs11_get_info (pkey
->info
, itype
, output
, output_size
);
132 find_object (struct pkcs11_session_info
* sinfo
,
133 struct pin_info_st
* pin_info
,
134 ck_object_handle_t
* _obj
,
135 struct p11_kit_uri
*info
, unsigned int flags
)
138 ck_object_handle_t obj
;
139 struct ck_attribute
*attrs
;
140 unsigned long attr_count
;
144 ret
= pkcs11_open_session (sinfo
, pin_info
, info
, flags
& SESSION_LOGIN
);
151 attrs
= p11_kit_uri_get_attributes (info
, &attr_count
);
152 rv
= pkcs11_find_objects_init (sinfo
->module
, sinfo
->pks
, attrs
, attr_count
);
156 _gnutls_debug_log ("pk11: FindObjectsInit failed.\n");
157 ret
= pkcs11_rv_to_err (rv
);
161 if (pkcs11_find_objects (sinfo
->module
, sinfo
->pks
, &obj
, 1, &count
) == CKR_OK
&& count
== 1)
164 pkcs11_find_objects_final (sinfo
);
168 ret
= GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE
;
169 pkcs11_find_objects_final (sinfo
);
171 pkcs11_close_session (sinfo
);
176 #define FIND_OBJECT(sinfo, pin_info, obj, key) \
180 ret = find_object (sinfo, pin_info, &obj, key->info, \
182 if (ret == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) { \
183 if (_gnutls_token_func) \
185 rret = pkcs11_call_token_func (key->info, retries++); \
186 if (rret == 0) continue; \
188 return gnutls_assert_val(ret); \
189 } else if (ret < 0) { \
190 return gnutls_assert_val(ret); \
196 * _gnutls_pkcs11_privkey_sign_hash:
197 * @key: Holds the key
198 * @hash: holds the data to be signed (should be output of a hash)
199 * @signature: will contain the signature allocated with gnutls_malloc()
201 * This function will sign the given data using a signature algorithm
202 * supported by the private key. It is assumed that the given data
203 * are the output of a hash function.
205 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
206 * negative error value.
209 _gnutls_pkcs11_privkey_sign_hash (gnutls_pkcs11_privkey_t key
,
210 const gnutls_datum_t
* hash
,
211 gnutls_datum_t
* signature
)
215 struct ck_mechanism mech
;
216 gnutls_datum_t tmp
= {NULL
, 0};
217 unsigned long siglen
;
218 struct pkcs11_session_info _sinfo
;
219 struct pkcs11_session_info
*sinfo
;
220 ck_object_handle_t obj
;
222 if (key
->sinfo
.init
!= 0)
230 memset(sinfo
, 0, sizeof(*sinfo
));
231 FIND_OBJECT (sinfo
, &key
->pin
, obj
, key
);
234 mech
.mechanism
= pk_to_mech(key
->pk_algorithm
);
235 mech
.parameter
= NULL
;
236 mech
.parameter_len
= 0;
238 /* Initialize signing operation; using the private key discovered
240 rv
= pkcs11_sign_init (sinfo
->module
, sinfo
->pks
, &mech
, obj
);
244 ret
= pkcs11_rv_to_err (rv
);
248 /* Work out how long the signature must be: */
249 rv
= pkcs11_sign (sinfo
->module
, sinfo
->pks
, hash
->data
, hash
->size
, NULL
, &siglen
);
253 ret
= pkcs11_rv_to_err (rv
);
257 tmp
.data
= gnutls_malloc (siglen
);
260 rv
= pkcs11_sign (sinfo
->module
, sinfo
->pks
, hash
->data
, hash
->size
, tmp
.data
, &siglen
);
264 ret
= pkcs11_rv_to_err (rv
);
269 if (key
->pk_algorithm
== GNUTLS_PK_EC
|| key
->pk_algorithm
== GNUTLS_PK_DSA
)
271 unsigned int hlen
= siglen
/ 2;
277 ret
= GNUTLS_E_PK_SIGN_FAILED
;
284 s
.data
= &tmp
.data
[hlen
];
287 ret
= _gnutls_encode_ber_rs_raw (signature
, &r
, &s
);
294 gnutls_free(tmp
.data
);
299 signature
->size
= siglen
;
300 signature
->data
= tmp
.data
;
306 if (sinfo
!= &key
->sinfo
)
307 pkcs11_close_session (sinfo
);
309 gnutls_free(tmp
.data
);
315 * gnutls_pkcs11_privkey_import_url:
316 * @pkey: The structure to store the parsed key
317 * @url: a PKCS 11 url identifying the key
318 * @flags: sequence of GNUTLS_PKCS_PRIVKEY_*
320 * This function will "import" a PKCS 11 URL identifying a private
321 * key to the #gnutls_pkcs11_privkey_t structure. In reality since
322 * in most cases keys cannot be exported, the private key structure
323 * is being associated with the available operations on the token.
325 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
326 * negative error value.
329 gnutls_pkcs11_privkey_import_url (gnutls_pkcs11_privkey_t pkey
,
330 const char *url
, unsigned int flags
)
333 struct ck_attribute
*attr
;
334 ck_object_handle_t obj
;
335 struct ck_attribute a
[4];
336 ck_key_type_t key_type
;
337 struct pkcs11_session_info sinfo
;
339 memset(&sinfo
, 0, sizeof(sinfo
));
341 ret
= pkcs11_url_to_info (url
, &pkey
->info
);
350 attr
= p11_kit_uri_get_attribute (pkey
->info
, CKA_CLASS
);
351 if (!attr
|| attr
->value_len
!= sizeof (ck_object_class_t
) ||
352 *(ck_object_class_t
*)attr
->value
!= CKO_PRIVATE_KEY
)
355 return GNUTLS_E_INVALID_REQUEST
;
358 attr
= p11_kit_uri_get_attribute (pkey
->info
, CKA_ID
);
359 if (!attr
|| !attr
->value_len
)
361 attr
= p11_kit_uri_get_attribute (pkey
->info
, CKA_LABEL
);
362 if (!attr
|| !attr
->value_len
)
365 return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE
;
369 FIND_OBJECT (&sinfo
, &pkey
->pin
, obj
, pkey
);
371 a
[0].type
= CKA_KEY_TYPE
;
372 a
[0].value
= &key_type
;
373 a
[0].value_len
= sizeof (key_type
);
375 if (pkcs11_get_attribute_value (sinfo
.module
, sinfo
.pks
, obj
, a
, 1) == CKR_OK
)
377 pkey
->pk_algorithm
= mech_to_pk(key_type
);
378 if (pkey
->pk_algorithm
== GNUTLS_PK_UNKNOWN
)
380 _gnutls_debug_log("Cannot determine PKCS #11 key algorithm\n");
381 ret
= GNUTLS_E_UNKNOWN_ALGORITHM
;
388 if (pkey
->sinfo
.init
)
389 pkcs11_close_session (&pkey
->sinfo
);
391 if (sinfo
.tinfo
.max_session_count
!= 1)
393 /* We do not keep the session open in tokens that can
394 * only support a single session.
396 memcpy(&pkey
->sinfo
, &sinfo
, sizeof(pkey
->sinfo
));
402 pkcs11_close_session (&sinfo
);
408 * _gnutls_pkcs11_privkey_decrypt_data:
409 * @key: Holds the key
410 * @flags: should be 0 for now
411 * @ciphertext: holds the data to be signed
412 * @plaintext: will contain the plaintext, allocated with gnutls_malloc()
414 * This function will decrypt the given data using the public key algorithm
415 * supported by the private key.
417 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
418 * negative error value.
421 _gnutls_pkcs11_privkey_decrypt_data (gnutls_pkcs11_privkey_t key
,
423 const gnutls_datum_t
* ciphertext
,
424 gnutls_datum_t
* plaintext
)
428 struct ck_mechanism mech
;
429 unsigned long siglen
;
430 ck_object_handle_t obj
;
431 struct pkcs11_session_info _sinfo
;
432 struct pkcs11_session_info
*sinfo
;
434 if (key
->sinfo
.init
!= 0)
442 memset(sinfo
, 0, sizeof(*sinfo
));
443 FIND_OBJECT (sinfo
, &key
->pin
, obj
, key
);
446 if (key
->pk_algorithm
!= GNUTLS_PK_RSA
)
447 return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST
);
449 mech
.mechanism
= CKM_RSA_PKCS
;
450 mech
.parameter
= NULL
;
451 mech
.parameter_len
= 0;
453 /* Initialize signing operation; using the private key discovered
455 rv
= pkcs11_decrypt_init (sinfo
->module
, sinfo
->pks
, &mech
, obj
);
459 ret
= pkcs11_rv_to_err (rv
);
463 /* Work out how long the plaintext must be: */
464 rv
= pkcs11_decrypt (sinfo
->module
, sinfo
->pks
, ciphertext
->data
, ciphertext
->size
,
469 ret
= pkcs11_rv_to_err (rv
);
473 plaintext
->data
= gnutls_malloc (siglen
);
474 plaintext
->size
= siglen
;
476 rv
= pkcs11_decrypt (sinfo
->module
, sinfo
->pks
, ciphertext
->data
, ciphertext
->size
,
477 plaintext
->data
, &siglen
);
480 gnutls_free (plaintext
->data
);
482 ret
= pkcs11_rv_to_err (rv
);
486 plaintext
->size
= siglen
;
491 if (key
->sinfo
.init
== 0)
492 pkcs11_close_session (sinfo
);
498 * gnutls_pkcs11_privkey_export_url:
499 * @key: Holds the PKCS 11 key
500 * @detailed: non zero if a detailed URL is required
501 * @url: will contain an allocated url
503 * This function will export a URL identifying the given key.
505 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
506 * negative error value.
509 gnutls_pkcs11_privkey_export_url (gnutls_pkcs11_privkey_t key
,
510 gnutls_pkcs11_url_type_t detailed
,
515 ret
= pkcs11_info_to_url (key
->info
, detailed
, url
);
527 * gnutls_pkcs11_privkey_generate:
529 * @pk: the public key algorithm
530 * @bits: the security bits
532 * @flags: should be zero
534 * This function will generate a private key in the specified
535 * by the @url token. The private key will be generate within
536 * the token and will not be exportable.
538 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
539 * negative error value.
544 gnutls_pkcs11_privkey_generate (const char* url
, gnutls_pk_algorithm_t pk
,
545 unsigned int bits
, const char* label
,
548 return gnutls_pkcs11_privkey_generate2( url
, pk
, bits
, label
, 0, NULL
, flags
);
552 * gnutls_pkcs11_privkey_generate2:
554 * @pk: the public key algorithm
555 * @bits: the security bits
557 * @fmt: the format of output params. PEM or DER.
558 * @pubkey: will hold the public key (may be %NULL)
559 * @flags: should be zero
561 * This function will generate a private key in the specified
562 * by the @url token. The private key will be generate within
563 * the token and will not be exportable. This function will
564 * store the DER-encoded public key in the SubjectPublicKeyInfo format
565 * in @pubkey. The @pubkey should be deinitialized using gnutls_free().
567 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
568 * negative error value.
573 gnutls_pkcs11_privkey_generate2 (const char* url
, gnutls_pk_algorithm_t pk
,
574 unsigned int bits
, const char* label
,
575 gnutls_x509_crt_fmt_t fmt
,
576 gnutls_datum_t
* pubkey
,
580 const ck_bool_t tval
= 1;
581 const ck_bool_t fval
= 0;
582 struct pkcs11_session_info sinfo
;
583 struct p11_kit_uri
*info
= NULL
;
585 struct ck_attribute a
[10], p
[10];
586 ck_object_handle_t pub
, priv
;
587 unsigned long _bits
= bits
;
589 struct ck_mechanism mech
;
590 gnutls_pubkey_t pkey
= NULL
;
591 gnutls_pkcs11_obj_t obj
= NULL
;
593 memset(&sinfo
, 0, sizeof(sinfo
));
595 ret
= pkcs11_url_to_info (url
, &info
);
603 pkcs11_open_session (&sinfo
, NULL
, info
,
604 SESSION_WRITE
| pkcs11_obj_flags_to_int (flags
));
605 p11_kit_uri_free (info
);
613 /* a holds the public key template
614 * and p the private key */
616 mech
.parameter
= NULL
;
617 mech
.parameter_len
= 0;
618 mech
.mechanism
= pk_to_genmech(pk
);
623 p
[p_val
].type
= CKA_DECRYPT
;
624 p
[p_val
].value
= (void*)&tval
;
625 p
[p_val
].value_len
= sizeof (tval
);
628 p
[p_val
].type
= CKA_SIGN
;
629 p
[p_val
].value
= (void*)&tval
;
630 p
[p_val
].value_len
= sizeof (tval
);
633 a
[a_val
].type
= CKA_ENCRYPT
;
634 a
[a_val
].value
= (void*)&tval
;
635 a
[a_val
].value_len
= sizeof (tval
);
638 a
[a_val
].type
= CKA_VERIFY
;
639 a
[a_val
].value
= (void*)&tval
;
640 a
[a_val
].value_len
= sizeof (tval
);
643 a
[a_val
].type
= CKA_MODULUS_BITS
;
644 a
[a_val
].value
= &_bits
;
645 a
[a_val
].value_len
= sizeof (_bits
);
649 p
[p_val
].type
= CKA_SIGN
;
650 p
[p_val
].value
= (void*)&tval
;
651 p
[p_val
].value_len
= sizeof (tval
);
654 a
[a_val
].type
= CKA_VERIFY
;
655 a
[a_val
].value
= (void*)&tval
;
656 a
[a_val
].value_len
= sizeof (tval
);
659 a
[a_val
].type
= CKA_MODULUS_BITS
;
660 a
[a_val
].value
= &_bits
;
661 a
[a_val
].value_len
= sizeof (_bits
);
665 p
[p_val
].type
= CKA_SIGN
;
666 p
[p_val
].value
= (void*)&tval
;
667 p
[p_val
].value_len
= sizeof (tval
);
670 a
[a_val
].type
= CKA_VERIFY
;
671 a
[a_val
].value
= (void*)&tval
;
672 a
[a_val
].value_len
= sizeof (tval
);
675 a
[a_val
].type
= CKA_MODULUS_BITS
;
676 a
[a_val
].value
= &_bits
;
677 a
[a_val
].value_len
= sizeof (_bits
);
681 ret
= gnutls_assert_val(GNUTLS_E_INVALID_REQUEST
);
685 /* a private key is set always as private unless
686 * requested otherwise
688 if (flags
& GNUTLS_PKCS11_OBJ_FLAG_MARK_NOT_PRIVATE
)
690 p
[p_val
].type
= CKA_PRIVATE
;
691 p
[p_val
].value
= (void*)&fval
;
692 p
[p_val
].value_len
= sizeof(fval
);
697 p
[p_val
].type
= CKA_PRIVATE
;
698 p
[p_val
].value
= (void*)&tval
;
699 p
[p_val
].value_len
= sizeof (tval
);
703 p
[p_val
].type
= CKA_TOKEN
;
704 p
[p_val
].value
= (void *)&tval
;
705 p
[p_val
].value_len
= sizeof (tval
);
710 p
[p_val
].type
= CKA_LABEL
;
711 p
[p_val
].value
= (void*)label
;
712 p
[p_val
].value_len
= strlen (label
);
715 a
[a_val
].type
= CKA_LABEL
;
716 a
[a_val
].value
= (void*)label
;
717 a
[a_val
].value_len
= strlen (label
);
721 if (flags
& GNUTLS_PKCS11_OBJ_FLAG_MARK_SENSITIVE
)
723 p
[p_val
].type
= CKA_SENSITIVE
;
724 p
[p_val
].value
= (void*)&tval
;
725 p
[p_val
].value_len
= sizeof (tval
);
730 p
[p_val
].type
= CKA_SENSITIVE
;
731 p
[p_val
].value
= (void*)&fval
;
732 p
[p_val
].value_len
= sizeof (fval
);
736 rv
= pkcs11_generate_key_pair( sinfo
.module
, sinfo
.pks
, &mech
, a
, a_val
, p
, p_val
, &pub
, &priv
);
740 _gnutls_debug_log ("pkcs11: %s\n", pkcs11_strerror (rv
));
741 ret
= pkcs11_rv_to_err (rv
);
745 /* extract the public key */
748 ret
= gnutls_pubkey_init(&pkey
);
755 ret
= gnutls_pkcs11_obj_init(&obj
);
762 obj
->pk_algorithm
= pk
;
763 obj
->type
= GNUTLS_PKCS11_OBJ_PUBKEY
;
764 ret
= pkcs11_read_pubkey(sinfo
.module
, sinfo
.pks
, pub
, mech
.mechanism
, obj
->pubkey
);
771 ret
= gnutls_pubkey_import_pkcs11 (pkey
, obj
, 0);
778 ret
= gnutls_pubkey_export2 (pkey
, fmt
, pubkey
);
789 gnutls_pkcs11_obj_deinit(obj
);
791 gnutls_pubkey_deinit(pkey
);
793 pkcs11_close_session (&sinfo
);
799 * gnutls_pkcs11_privkey_set_pin_function:
800 * @key: The private key
802 * @userdata: data associated with the callback
804 * This function will set a callback function to be used when
805 * required to access the object. This function overrides the global
806 * set using gnutls_pkcs11_set_pin_function().
812 gnutls_pkcs11_privkey_set_pin_function (gnutls_pkcs11_privkey_t key
,
813 gnutls_pin_callback_t fn
,
817 key
->pin
.data
= userdata
;