2 * GnuTLS PKCS#11 support
3 * Copyright (C) 2010-2012 Free Software Foundation, Inc.
5 * Author: Nikos Mavrogiannopoulos
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/abstract.h>
29 #include <gnutls_pk.h>
31 #include <openpgp/openpgp_int.h>
32 #include <openpgp/gnutls_openpgp.h>
33 #include <gnutls_sig.h>
34 #include <abstract_int.h>
36 struct gnutls_privkey_st
38 gnutls_privkey_type_t type
;
39 gnutls_pk_algorithm_t pk_algorithm
;
43 gnutls_x509_privkey_t x509
;
45 gnutls_pkcs11_privkey_t pkcs11
;
48 gnutls_openpgp_privkey_t openpgp
;
51 gnutls_privkey_sign_func sign_func
;
52 gnutls_privkey_decrypt_func decrypt_func
;
61 * gnutls_privkey_get_type:
62 * @key: should contain a #gnutls_privkey_t structure
64 * This function will return the type of the private key. This is
65 * actually the type of the subsystem used to set this private key.
67 * Returns: a member of the #gnutls_privkey_type_t enumeration on
68 * success, or a negative error code on error.
73 gnutls_privkey_get_type (gnutls_privkey_t key
)
79 * gnutls_privkey_get_pk_algorithm:
80 * @key: should contain a #gnutls_privkey_t structure
81 * @bits: If set will return the number of bits of the parameters (may be NULL)
83 * This function will return the public key algorithm of a private
84 * key and if possible will return a number of bits that indicates
85 * the security parameter of the key.
87 * Returns: a member of the #gnutls_pk_algorithm_t enumeration on
88 * success, or a negative error code on error.
93 gnutls_privkey_get_pk_algorithm (gnutls_privkey_t key
, unsigned int *bits
)
98 case GNUTLS_PRIVKEY_OPENPGP
:
99 return gnutls_openpgp_privkey_get_pk_algorithm (key
->key
.openpgp
, bits
);
102 case GNUTLS_PRIVKEY_PKCS11
:
103 return gnutls_pkcs11_privkey_get_pk_algorithm (key
->key
.pkcs11
, bits
);
105 case GNUTLS_PRIVKEY_X509
:
107 *bits
= _gnutls_mpi_get_nbits (key
->key
.x509
->params
.params
[0]);
108 return gnutls_x509_privkey_get_pk_algorithm (key
->key
.x509
);
109 case GNUTLS_PRIVKEY_EXT
:
112 return key
->pk_algorithm
;
115 return GNUTLS_E_INVALID_REQUEST
;
121 privkey_to_pubkey (gnutls_pk_algorithm_t pk
,
122 const gnutls_pk_params_st
* priv
,
123 gnutls_pk_params_st
* pub
)
130 pub
->params
[0] = _gnutls_mpi_copy (priv
->params
[0]);
131 pub
->params
[1] = _gnutls_mpi_copy (priv
->params
[1]);
133 pub
->params_nr
= RSA_PUBLIC_PARAMS
;
135 if (pub
->params
[0] == NULL
|| pub
->params
[1] == NULL
)
138 ret
= GNUTLS_E_MEMORY_ERROR
;
144 pub
->params
[0] = _gnutls_mpi_copy (priv
->params
[0]);
145 pub
->params
[1] = _gnutls_mpi_copy (priv
->params
[1]);
146 pub
->params
[2] = _gnutls_mpi_copy (priv
->params
[2]);
147 pub
->params
[3] = _gnutls_mpi_copy (priv
->params
[3]);
149 pub
->params_nr
= DSA_PUBLIC_PARAMS
;
151 if (pub
->params
[0] == NULL
|| pub
->params
[1] == NULL
||
152 pub
->params
[2] == NULL
|| pub
->params
[3] == NULL
)
155 ret
= GNUTLS_E_MEMORY_ERROR
;
161 pub
->params
[0] = _gnutls_mpi_copy (priv
->params
[0]);
162 pub
->params
[1] = _gnutls_mpi_copy (priv
->params
[1]);
163 pub
->params
[2] = _gnutls_mpi_copy (priv
->params
[2]);
164 pub
->params
[3] = _gnutls_mpi_copy (priv
->params
[3]);
165 pub
->params
[4] = _gnutls_mpi_copy (priv
->params
[4]);
166 pub
->params
[5] = _gnutls_mpi_copy (priv
->params
[5]);
167 pub
->params
[6] = _gnutls_mpi_copy (priv
->params
[6]);
168 pub
->params
[7] = _gnutls_mpi_copy (priv
->params
[7]);
170 pub
->params_nr
= ECC_PUBLIC_PARAMS
;
171 pub
->flags
= priv
->flags
;
173 if (pub
->params
[0] == NULL
|| pub
->params
[1] == NULL
||
174 pub
->params
[2] == NULL
|| pub
->params
[3] == NULL
||
175 pub
->params
[4] == NULL
|| pub
->params
[5] == NULL
||
176 pub
->params
[6] == NULL
|| pub
->params
[7] == NULL
)
179 ret
= GNUTLS_E_MEMORY_ERROR
;
186 return GNUTLS_E_INVALID_REQUEST
;
191 gnutls_pk_params_release(pub
);
196 /* Returns the public key of the private key (if possible)
199 _gnutls_privkey_get_public_mpis (gnutls_privkey_t key
,
200 gnutls_pk_params_st
* params
)
203 gnutls_pk_algorithm_t pk
= gnutls_privkey_get_pk_algorithm (key
, NULL
);
207 #ifdef ENABLE_OPENPGP
208 case GNUTLS_PRIVKEY_OPENPGP
:
210 gnutls_pk_params_st tmp_params
;
212 uint8_t keyid
[GNUTLS_OPENPGP_KEYID_SIZE
];
215 gnutls_openpgp_privkey_get_preferred_key_id (key
->key
.openpgp
,
219 KEYID_IMPORT (kid
, keyid
);
220 ret
= _gnutls_openpgp_privkey_get_mpis (key
->key
.openpgp
, kid
,
224 ret
= _gnutls_openpgp_privkey_get_mpis (key
->key
.openpgp
, NULL
,
233 ret
= privkey_to_pubkey (pk
,
237 gnutls_pk_params_release(&tmp_params
);
242 case GNUTLS_PRIVKEY_X509
:
243 ret
= privkey_to_pubkey (pk
,
244 &key
->key
.x509
->params
,
249 return GNUTLS_E_INVALID_REQUEST
;
256 * gnutls_privkey_init:
257 * @key: The structure to be initialized
259 * This function will initialize an private key structure.
261 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
262 * negative error value.
267 gnutls_privkey_init (gnutls_privkey_t
* key
)
269 *key
= gnutls_calloc (1, sizeof (struct gnutls_privkey_st
));
273 return GNUTLS_E_MEMORY_ERROR
;
280 * gnutls_privkey_deinit:
281 * @key: The structure to be deinitialized
283 * This function will deinitialize a private key structure.
288 gnutls_privkey_deinit (gnutls_privkey_t key
)
290 if (key
== NULL
) return;
292 if (key
->flags
& GNUTLS_PRIVKEY_IMPORT_AUTO_RELEASE
|| key
->flags
& GNUTLS_PRIVKEY_IMPORT_COPY
)
295 #ifdef ENABLE_OPENPGP
296 case GNUTLS_PRIVKEY_OPENPGP
:
297 gnutls_openpgp_privkey_deinit (key
->key
.openpgp
);
301 case GNUTLS_PRIVKEY_PKCS11
:
302 gnutls_pkcs11_privkey_deinit (key
->key
.pkcs11
);
305 case GNUTLS_PRIVKEY_X509
:
306 gnutls_x509_privkey_deinit (key
->key
.x509
);
314 /* will fail if the private key contains an actual key.
316 static int check_if_clean(gnutls_privkey_t key
)
319 return GNUTLS_E_INVALID_REQUEST
;
327 * gnutls_privkey_import_pkcs11:
328 * @pkey: The private key
329 * @key: The private key to be imported
330 * @flags: Flags for the import
332 * This function will import the given private key to the abstract
333 * #gnutls_privkey_t structure.
335 * The #gnutls_pkcs11_privkey_t object must not be deallocated
336 * during the lifetime of this structure.
338 * @flags might be zero or one of %GNUTLS_PRIVKEY_IMPORT_AUTO_RELEASE
339 * and %GNUTLS_PRIVKEY_IMPORT_COPY.
341 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
342 * negative error value.
347 gnutls_privkey_import_pkcs11 (gnutls_privkey_t pkey
,
348 gnutls_pkcs11_privkey_t key
, unsigned int flags
)
352 ret
= check_if_clean(pkey
);
359 if (flags
& GNUTLS_PRIVKEY_IMPORT_COPY
)
360 return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST
);
362 pkey
->key
.pkcs11
= key
;
363 pkey
->type
= GNUTLS_PRIVKEY_PKCS11
;
364 pkey
->pk_algorithm
= gnutls_pkcs11_privkey_get_pk_algorithm (key
, NULL
);
370 #endif /* ENABLE_PKCS11 */
373 * gnutls_privkey_import_ext:
374 * @pkey: The private key
375 * @pk: The public key algorithm
376 * @userdata: private data to be provided to the callbacks
377 * @sign_func: callback for signature operations
378 * @decrypt_func: callback for decryption operations
379 * @flags: Flags for the import
381 * This function will associate the given callbacks with the
382 * #gnutls_privkey_t structure. At least one of the two callbacks
385 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
386 * negative error value.
391 gnutls_privkey_import_ext (gnutls_privkey_t pkey
,
392 gnutls_pk_algorithm_t pk
,
394 gnutls_privkey_sign_func sign_func
,
395 gnutls_privkey_decrypt_func decrypt_func
,
400 ret
= check_if_clean(pkey
);
407 if (sign_func
== NULL
&& decrypt_func
== NULL
)
408 return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST
);
410 pkey
->key
.ext
.sign_func
= sign_func
;
411 pkey
->key
.ext
.decrypt_func
= decrypt_func
;
412 pkey
->key
.ext
.userdata
= userdata
;
413 pkey
->type
= GNUTLS_PRIVKEY_EXT
;
414 pkey
->pk_algorithm
= pk
;
421 * gnutls_privkey_import_x509:
422 * @pkey: The private key
423 * @key: The private key to be imported
424 * @flags: Flags for the import
426 * This function will import the given private key to the abstract
427 * #gnutls_privkey_t structure.
429 * The #gnutls_x509_privkey_t object must not be deallocated
430 * during the lifetime of this structure.
432 * @flags might be zero or one of %GNUTLS_PRIVKEY_IMPORT_AUTO_RELEASE
433 * and %GNUTLS_PRIVKEY_IMPORT_COPY.
435 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
436 * negative error value.
441 gnutls_privkey_import_x509 (gnutls_privkey_t pkey
,
442 gnutls_x509_privkey_t key
, unsigned int flags
)
446 ret
= check_if_clean(pkey
);
453 if (flags
& GNUTLS_PRIVKEY_IMPORT_COPY
)
455 ret
= gnutls_x509_privkey_init(&pkey
->key
.x509
);
457 return gnutls_assert_val(ret
);
459 ret
= gnutls_x509_privkey_cpy(pkey
->key
.x509
, key
);
462 gnutls_x509_privkey_deinit(pkey
->key
.x509
);
463 return gnutls_assert_val(ret
);
467 pkey
->key
.x509
= key
;
469 pkey
->type
= GNUTLS_PRIVKEY_X509
;
470 pkey
->pk_algorithm
= gnutls_x509_privkey_get_pk_algorithm (key
);
476 #ifdef ENABLE_OPENPGP
478 * gnutls_privkey_import_openpgp:
479 * @pkey: The private key
480 * @key: The private key to be imported
481 * @flags: Flags for the import
483 * This function will import the given private key to the abstract
484 * #gnutls_privkey_t structure.
486 * The #gnutls_openpgp_privkey_t object must not be deallocated
487 * during the lifetime of this structure. The subkey set as
488 * preferred will be used, or the master key otherwise.
490 * @flags might be zero or one of %GNUTLS_PRIVKEY_IMPORT_AUTO_RELEASE
491 * and %GNUTLS_PRIVKEY_IMPORT_COPY.
493 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
494 * negative error value.
499 gnutls_privkey_import_openpgp (gnutls_privkey_t pkey
,
500 gnutls_openpgp_privkey_t key
,
504 uint8_t keyid
[GNUTLS_OPENPGP_KEYID_SIZE
];
506 ret
= check_if_clean(pkey
);
513 if (flags
& GNUTLS_PRIVKEY_IMPORT_COPY
)
515 ret
= gnutls_openpgp_privkey_init(&pkey
->key
.openpgp
);
517 return gnutls_assert_val(ret
);
519 ret
= _gnutls_openpgp_privkey_cpy(pkey
->key
.openpgp
, key
);
522 gnutls_openpgp_privkey_deinit(pkey
->key
.openpgp
);
523 return gnutls_assert_val(ret
);
527 pkey
->key
.openpgp
= key
;
529 pkey
->type
= GNUTLS_PRIVKEY_OPENPGP
;
531 ret
= gnutls_openpgp_privkey_get_preferred_key_id (key
, keyid
);
532 if (ret
== GNUTLS_E_OPENPGP_PREFERRED_KEY_ERROR
)
534 pkey
->pk_algorithm
= gnutls_openpgp_privkey_get_pk_algorithm(key
, NULL
);
539 return gnutls_assert_val(ret
);
541 idx
= gnutls_openpgp_privkey_get_subkey_idx (key
, keyid
);
543 pkey
->pk_algorithm
= gnutls_openpgp_privkey_get_subkey_pk_algorithm (key
, idx
, NULL
);
553 * gnutls_privkey_sign_data:
554 * @signer: Holds the key
555 * @hash: should be a digest algorithm
556 * @flags: should be 0 for now
557 * @data: holds the data to be signed
558 * @signature: will contain the signature allocate with gnutls_malloc()
560 * This function will sign the given data using a signature algorithm
561 * supported by the private key. Signature algorithms are always used
562 * together with a hash functions. Different hash functions may be
563 * used for the RSA algorithm, but only the SHA family for the DSA keys.
565 * Use gnutls_pubkey_get_preferred_hash_algorithm() to determine
566 * the hash algorithm.
568 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
569 * negative error value.
574 gnutls_privkey_sign_data (gnutls_privkey_t signer
,
575 gnutls_digest_algorithm_t hash
,
577 const gnutls_datum_t
* data
,
578 gnutls_datum_t
* signature
)
581 gnutls_datum_t digest
;
583 ret
= pk_hash_data (signer
->pk_algorithm
, hash
, NULL
, data
, &digest
);
590 ret
= pk_prepare_hash (signer
->pk_algorithm
, hash
, &digest
);
597 ret
= _gnutls_privkey_sign_hash (signer
, &digest
, signature
);
598 _gnutls_free_datum (&digest
);
609 _gnutls_free_datum (&digest
);
614 * gnutls_privkey_sign_hash:
615 * @signer: Holds the signer's key
616 * @hash_algo: The hash algorithm used
617 * @flags: zero for now
618 * @hash_data: holds the data to be signed
619 * @signature: will contain newly allocated signature
621 * This function will sign the given hashed data using a signature algorithm
622 * supported by the private key. Signature algorithms are always used
623 * together with a hash functions. Different hash functions may be
624 * used for the RSA algorithm, but only SHA-XXX for the DSA keys.
626 * Use gnutls_pubkey_get_preferred_hash_algorithm() to determine
627 * the hash algorithm.
629 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
630 * negative error value.
635 gnutls_privkey_sign_hash (gnutls_privkey_t signer
,
636 gnutls_digest_algorithm_t hash_algo
,
638 const gnutls_datum_t
* hash_data
,
639 gnutls_datum_t
* signature
)
642 gnutls_datum_t digest
;
644 digest
.data
= gnutls_malloc (hash_data
->size
);
645 if (digest
.data
== NULL
)
648 return GNUTLS_E_MEMORY_ERROR
;
650 digest
.size
= hash_data
->size
;
651 memcpy (digest
.data
, hash_data
->data
, digest
.size
);
653 ret
= pk_prepare_hash (signer
->pk_algorithm
, hash_algo
, &digest
);
660 ret
= _gnutls_privkey_sign_hash (signer
, &digest
, signature
);
670 _gnutls_free_datum (&digest
);
675 * _gnutls_privkey_sign_hash:
676 * @key: Holds the key
677 * @data: holds the data to be signed
678 * @signature: will contain the signature allocate with gnutls_malloc()
680 * This function will sign the given data using a signature algorithm
681 * supported by the private key.
683 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
684 * negative error value.
687 _gnutls_privkey_sign_hash (gnutls_privkey_t key
,
688 const gnutls_datum_t
* hash
,
689 gnutls_datum_t
* signature
)
693 #ifdef ENABLE_OPENPGP
694 case GNUTLS_PRIVKEY_OPENPGP
:
695 return gnutls_openpgp_privkey_sign_hash (key
->key
.openpgp
,
699 case GNUTLS_PRIVKEY_PKCS11
:
700 return _gnutls_pkcs11_privkey_sign_hash (key
->key
.pkcs11
,
703 case GNUTLS_PRIVKEY_X509
:
704 return _gnutls_soft_sign (key
->key
.x509
->pk_algorithm
,
705 &key
->key
.x509
->params
,
707 case GNUTLS_PRIVKEY_EXT
:
708 if (key
->key
.ext
.sign_func
== NULL
)
709 return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST
);
710 return key
->key
.ext
.sign_func(key
, key
->key
.ext
.userdata
, hash
, signature
);
713 return GNUTLS_E_INVALID_REQUEST
;
718 * gnutls_privkey_decrypt_data:
719 * @key: Holds the key
720 * @flags: zero for now
721 * @ciphertext: holds the data to be decrypted
722 * @plaintext: will contain the decrypted data, allocated with gnutls_malloc()
724 * This function will decrypt the given data using the algorithm
725 * supported by the private key.
727 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
728 * negative error value.
733 gnutls_privkey_decrypt_data (gnutls_privkey_t key
,
735 const gnutls_datum_t
* ciphertext
,
736 gnutls_datum_t
* plaintext
)
738 if (key
->pk_algorithm
!= GNUTLS_PK_RSA
)
741 return GNUTLS_E_INVALID_REQUEST
;
746 #ifdef ENABLE_OPENPGP
747 case GNUTLS_PRIVKEY_OPENPGP
:
748 return _gnutls_openpgp_privkey_decrypt_data (key
->key
.openpgp
, flags
,
749 ciphertext
, plaintext
);
751 case GNUTLS_PRIVKEY_X509
:
752 return _gnutls_pkcs1_rsa_decrypt (plaintext
, ciphertext
,
753 &key
->key
.x509
->params
,
756 case GNUTLS_PRIVKEY_PKCS11
:
757 return _gnutls_pkcs11_privkey_decrypt_data (key
->key
.pkcs11
,
759 ciphertext
, plaintext
);
761 case GNUTLS_PRIVKEY_EXT
:
762 if (key
->key
.ext
.decrypt_func
== NULL
)
763 return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST
);
765 return key
->key
.ext
.decrypt_func(key
, key
->key
.ext
.userdata
, ciphertext
, plaintext
);
768 return GNUTLS_E_INVALID_REQUEST
;