diff options
author | Nikos Mavrogiannopoulos <nmav@gnutls.org> | 2015-08-23 19:19:45 +0200 |
---|---|---|
committer | Nikos Mavrogiannopoulos <nmav@gnutls.org> | 2015-08-23 19:27:01 +0200 |
commit | f84d8c0d536a1b6a160ddceadf7fade8d7b2edaa (patch) | |
tree | ea8ded214d074604f4bbfbd9ed31a07beb48f21d /lib/privkey.c | |
parent | 172ae7efd99ce30d3bdfc2a35e0335687ef70a0f (diff) | |
download | gnutls-f84d8c0d536a1b6a160ddceadf7fade8d7b2edaa.tar.gz |
Removed the 'gnutls_' prefix from files to simplify file naming
Diffstat (limited to 'lib/privkey.c')
-rw-r--r-- | lib/privkey.c | 1404 |
1 files changed, 1404 insertions, 0 deletions
diff --git a/lib/privkey.c b/lib/privkey.c new file mode 100644 index 0000000000..6394a9000e --- /dev/null +++ b/lib/privkey.c @@ -0,0 +1,1404 @@ +/* + * GnuTLS PKCS#11 support + * Copyright (C) 2010-2014 Free Software Foundation, Inc. + * Copyright (C) 2012-2014 Nikos Mavrogiannopoulos + * + * Author: Nikos Mavrogiannopoulos + * + * The GnuTLS is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/> + */ + +#include "gnutls_int.h" +#include <gnutls/pkcs11.h> +#include <stdio.h> +#include <string.h> +#include "errors.h" +#include <datum.h> +#include <pkcs11_int.h> +#include <gnutls/abstract.h> +#include <pk.h> +#include <x509_int.h> +#include <openpgp/openpgp_int.h> +#include <openpgp/openpgp.h> +#include <tls-sig.h> +#include <algorithms.h> +#include <fips.h> +#include <system-keys.h> +#include "urls.h" +#include <abstract_int.h> + +static int +_gnutls_privkey_sign_raw_data(gnutls_privkey_t key, + unsigned flags, + const gnutls_datum_t * data, + gnutls_datum_t * signature); + +/** + * gnutls_privkey_get_type: + * @key: should contain a #gnutls_privkey_t type + * + * This function will return the type of the private key. This is + * actually the type of the subsystem used to set this private key. + * + * Returns: a member of the #gnutls_privkey_type_t enumeration on + * success, or a negative error code on error. + * + * Since: 2.12.0 + **/ +gnutls_privkey_type_t gnutls_privkey_get_type(gnutls_privkey_t key) +{ + return key->type; +} + +/** + * gnutls_privkey_get_pk_algorithm: + * @key: should contain a #gnutls_privkey_t type + * @bits: If set will return the number of bits of the parameters (may be NULL) + * + * This function will return the public key algorithm of a private + * key and if possible will return a number of bits that indicates + * the security parameter of the key. + * + * Returns: a member of the #gnutls_pk_algorithm_t enumeration on + * success, or a negative error code on error. + * + * Since: 2.12.0 + **/ +int gnutls_privkey_get_pk_algorithm(gnutls_privkey_t key, unsigned int *bits) +{ + switch (key->type) { +#ifdef ENABLE_OPENPGP + case GNUTLS_PRIVKEY_OPENPGP: + return gnutls_openpgp_privkey_get_pk_algorithm(key->key.openpgp, + bits); +#endif +#ifdef ENABLE_PKCS11 + case GNUTLS_PRIVKEY_PKCS11: + return gnutls_pkcs11_privkey_get_pk_algorithm(key->key.pkcs11, + bits); +#endif + case GNUTLS_PRIVKEY_X509: + if (bits) + *bits = + _gnutls_mpi_get_nbits(key->key.x509-> + params.params[0]); + return gnutls_x509_privkey_get_pk_algorithm(key->key.x509); + case GNUTLS_PRIVKEY_EXT: + if (bits) + *bits = 0; + return key->pk_algorithm; + default: + gnutls_assert(); + return GNUTLS_E_INVALID_REQUEST; + } + +} + +static int +privkey_to_pubkey(gnutls_pk_algorithm_t pk, + const gnutls_pk_params_st * priv, gnutls_pk_params_st * pub) +{ + int ret; + + pub->algo = priv->algo; + pub->flags = priv->flags; + + switch (pk) { + case GNUTLS_PK_RSA: + pub->params[0] = _gnutls_mpi_copy(priv->params[0]); + pub->params[1] = _gnutls_mpi_copy(priv->params[1]); + + pub->params_nr = RSA_PUBLIC_PARAMS; + + if (pub->params[0] == NULL || pub->params[1] == NULL) { + gnutls_assert(); + ret = GNUTLS_E_MEMORY_ERROR; + goto cleanup; + } + + break; + case GNUTLS_PK_DSA: + pub->params[0] = _gnutls_mpi_copy(priv->params[0]); + pub->params[1] = _gnutls_mpi_copy(priv->params[1]); + pub->params[2] = _gnutls_mpi_copy(priv->params[2]); + pub->params[3] = _gnutls_mpi_copy(priv->params[3]); + + pub->params_nr = DSA_PUBLIC_PARAMS; + + if (pub->params[0] == NULL || pub->params[1] == NULL || + pub->params[2] == NULL || pub->params[3] == NULL) { + gnutls_assert(); + ret = GNUTLS_E_MEMORY_ERROR; + goto cleanup; + } + + break; + case GNUTLS_PK_EC: + pub->params[ECC_X] = _gnutls_mpi_copy(priv->params[ECC_X]); + pub->params[ECC_Y] = _gnutls_mpi_copy(priv->params[ECC_Y]); + + pub->params_nr = ECC_PUBLIC_PARAMS; + + if (pub->params[ECC_X] == NULL || pub->params[ECC_Y] == NULL) { + gnutls_assert(); + ret = GNUTLS_E_MEMORY_ERROR; + goto cleanup; + } + + break; + default: + gnutls_assert(); + return GNUTLS_E_INVALID_REQUEST; + } + + return 0; + cleanup: + gnutls_pk_params_release(pub); + return ret; +} + +/* Returns the public key of the private key (if possible) + */ +int +_gnutls_privkey_get_mpis(gnutls_privkey_t key, gnutls_pk_params_st * params) +{ + int ret; + + switch (key->type) { +#ifdef ENABLE_OPENPGP + case GNUTLS_PRIVKEY_OPENPGP: + { + uint32_t kid[2]; + uint8_t keyid[GNUTLS_OPENPGP_KEYID_SIZE]; + + ret = + gnutls_openpgp_privkey_get_preferred_key_id + (key->key.openpgp, keyid); + if (ret == 0) { + KEYID_IMPORT(kid, keyid); + ret = + _gnutls_openpgp_privkey_get_mpis + (key->key.openpgp, kid, params); + } else + ret = + _gnutls_openpgp_privkey_get_mpis + (key->key.openpgp, NULL, params); + + if (ret < 0) { + gnutls_assert(); + return ret; + } + } + + break; +#endif + case GNUTLS_PRIVKEY_X509: + ret = _gnutls_pk_params_copy(params, &key->key.x509->params); + break; +#ifdef ENABLE_PKCS11 + case GNUTLS_PRIVKEY_PKCS11: { + gnutls_pubkey_t pubkey; + + ret = _pkcs11_privkey_get_pubkey(key->key.pkcs11, &pubkey, 0); + if (ret < 0) + return gnutls_assert_val(ret); + + ret = _gnutls_pubkey_get_mpis(pubkey, params); + gnutls_pubkey_deinit(pubkey); + + break; + } +#endif + default: + gnutls_assert(); + return GNUTLS_E_INVALID_REQUEST; + } + + return ret; +} + +int +_gnutls_privkey_get_public_mpis(gnutls_privkey_t key, + gnutls_pk_params_st * params) +{ + int ret; + gnutls_pk_params_st tmp1; + + gnutls_pk_params_init(&tmp1); + + ret = _gnutls_privkey_get_mpis(key, &tmp1); + if (ret < 0) + return gnutls_assert_val(ret); + + ret = privkey_to_pubkey(key->pk_algorithm, &tmp1, params); + + gnutls_pk_params_release(&tmp1); + + if (ret < 0) + gnutls_assert(); + + return ret; +} + +/** + * gnutls_privkey_init: + * @key: A pointer to the type to be initialized + * + * This function will initialize a private key. + * + * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a + * negative error value. + * + * Since: 2.12.0 + **/ +int gnutls_privkey_init(gnutls_privkey_t * key) +{ + FAIL_IF_LIB_ERROR; + + *key = gnutls_calloc(1, sizeof(struct gnutls_privkey_st)); + if (*key == NULL) { + gnutls_assert(); + return GNUTLS_E_MEMORY_ERROR; + } + + return 0; +} + +/** + * gnutls_privkey_deinit: + * @key: The key to be deinitialized + * + * This function will deinitialize a private key structure. + * + * Since: 2.12.0 + **/ +void gnutls_privkey_deinit(gnutls_privkey_t key) +{ + if (key == NULL) + return; + + if (key->flags & GNUTLS_PRIVKEY_IMPORT_AUTO_RELEASE + || key->flags & GNUTLS_PRIVKEY_IMPORT_COPY) + switch (key->type) { +#ifdef ENABLE_OPENPGP + case GNUTLS_PRIVKEY_OPENPGP: + gnutls_openpgp_privkey_deinit(key->key.openpgp); + break; +#endif +#ifdef ENABLE_PKCS11 + case GNUTLS_PRIVKEY_PKCS11: + gnutls_pkcs11_privkey_deinit(key->key.pkcs11); + break; +#endif + case GNUTLS_PRIVKEY_X509: + gnutls_x509_privkey_deinit(key->key.x509); + break; + case GNUTLS_PRIVKEY_EXT: + if (key->key.ext.deinit_func != NULL) + key->key.ext.deinit_func(key, + key->key.ext.userdata); + break; + default: + break; + } + gnutls_free(key); +} + +/* will fail if the private key contains an actual key. + */ +static int check_if_clean(gnutls_privkey_t key) +{ + if (key->type != 0) + return GNUTLS_E_INVALID_REQUEST; + + return 0; +} + +#ifdef ENABLE_PKCS11 + +/** + * gnutls_privkey_import_pkcs11: + * @pkey: The private key + * @key: The private key to be imported + * @flags: Flags for the import + * + * This function will import the given private key to the abstract + * #gnutls_privkey_t type. + * + * The #gnutls_pkcs11_privkey_t object must not be deallocated + * during the lifetime of this structure. + * + * @flags might be zero or one of %GNUTLS_PRIVKEY_IMPORT_AUTO_RELEASE + * and %GNUTLS_PRIVKEY_IMPORT_COPY. + * + * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a + * negative error value. + * + * Since: 2.12.0 + **/ +int +gnutls_privkey_import_pkcs11(gnutls_privkey_t pkey, + gnutls_pkcs11_privkey_t key, unsigned int flags) +{ + int ret; + + ret = check_if_clean(pkey); + if (ret < 0) { + gnutls_assert(); + return ret; + } + + if (flags & GNUTLS_PRIVKEY_IMPORT_COPY) + return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); + + pkey->key.pkcs11 = key; + pkey->type = GNUTLS_PRIVKEY_PKCS11; + pkey->pk_algorithm = gnutls_pkcs11_privkey_get_pk_algorithm(key, NULL); + pkey->flags = flags; + + if (pkey->pin.data) + gnutls_pkcs11_privkey_set_pin_function(key, pkey->pin.cb, + pkey->pin.data); + + return 0; +} + +#if 0 +/** + * gnutls_privkey_import_pkcs11_url: + * @key: A key of type #gnutls_pubkey_t + * @url: A PKCS 11 url + * + * This function will import a PKCS 11 private key to a #gnutls_private_key_t + * type. + * + * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a + * negative error value. + * + * Since: 3.1.0 + **/ + +int gnutls_privkey_import_pkcs11_url(gnutls_privkey_t key, const char *url) +{ + int x; +} +#endif + +static +int _gnutls_privkey_import_pkcs11_url(gnutls_privkey_t key, const char *url, unsigned flags) +{ + gnutls_pkcs11_privkey_t pkey; + int ret; + + ret = gnutls_pkcs11_privkey_init(&pkey); + if (ret < 0) { + gnutls_assert(); + return ret; + } + + if (key->pin.cb) + gnutls_pkcs11_privkey_set_pin_function(pkey, key->pin.cb, + key->pin.data); + + ret = gnutls_pkcs11_privkey_import_url(pkey, url, flags); + if (ret < 0) { + gnutls_assert(); + goto cleanup; + } + + ret = + gnutls_privkey_import_pkcs11(key, pkey, + GNUTLS_PRIVKEY_IMPORT_AUTO_RELEASE); + if (ret < 0) { + gnutls_assert(); + goto cleanup; + } + + return 0; + + cleanup: + gnutls_pkcs11_privkey_deinit(pkey); + + return ret; +} + +/** + * gnutls_privkey_export_pkcs11: + * @pkey: The private key + * @key: Location for the key to be exported. + * + * Converts the given abstract private key to a #gnutls_pkcs11_privkey_t + * type. The key must be of type %GNUTLS_PRIVKEY_PKCS11. The key + * returned in @key must be deinitialized with + * gnutls_pkcs11_privkey_deinit(). + * + * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a + * negative error value. + * + * Since: 3.4.0 + */ +int +gnutls_privkey_export_pkcs11(gnutls_privkey_t pkey, + gnutls_pkcs11_privkey_t *key) +{ + int ret; + + if (pkey->type != GNUTLS_PRIVKEY_PKCS11) { + gnutls_assert(); + return GNUTLS_E_INVALID_REQUEST; + } + + ret = gnutls_pkcs11_privkey_init(key); + if (ret < 0) + return gnutls_assert_val(ret); + + ret = gnutls_pkcs11_privkey_cpy(*key, pkey->key.pkcs11); + if (ret < 0) { + gnutls_pkcs11_privkey_deinit(*key); + *key = NULL; + + return gnutls_assert_val(ret); + } + + return 0; +} +#endif /* ENABLE_PKCS11 */ + +/** + * gnutls_privkey_import_ext: + * @pkey: The private key + * @pk: The public key algorithm + * @userdata: private data to be provided to the callbacks + * @sign_func: callback for signature operations + * @decrypt_func: callback for decryption operations + * @flags: Flags for the import + * + * This function will associate the given callbacks with the + * #gnutls_privkey_t type. At least one of the two callbacks + * must be non-null. + * + * See also gnutls_privkey_import_ext3(). + * + * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a + * negative error value. + * + * Since: 3.0 + **/ +int +gnutls_privkey_import_ext(gnutls_privkey_t pkey, + gnutls_pk_algorithm_t pk, + void *userdata, + gnutls_privkey_sign_func sign_func, + gnutls_privkey_decrypt_func decrypt_func, + unsigned int flags) +{ + return gnutls_privkey_import_ext2(pkey, pk, userdata, sign_func, + decrypt_func, NULL, flags); +} + +/** + * gnutls_privkey_import_ext2: + * @pkey: The private key + * @pk: The public key algorithm + * @userdata: private data to be provided to the callbacks + * @sign_fn: callback for signature operations + * @decrypt_fn: callback for decryption operations + * @deinit_fn: a deinitialization function + * @flags: Flags for the import + * + * This function will associate the given callbacks with the + * #gnutls_privkey_t type. At least one of the two callbacks + * must be non-null. If a deinitialization function is provided + * then flags is assumed to contain %GNUTLS_PRIVKEY_IMPORT_AUTO_RELEASE. + * + * Note that the signing function is supposed to "raw" sign data, i.e., + * without any hashing or preprocessing. In case of RSA the DigestInfo + * will be provided, and the signing function is expected to do the PKCS #1 + * 1.5 padding and the exponentiation. + * + * See also gnutls_privkey_import_ext3(). + * + * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a + * negative error value. + * + * Since: 3.1 + **/ +int +gnutls_privkey_import_ext2(gnutls_privkey_t pkey, + gnutls_pk_algorithm_t pk, + void *userdata, + gnutls_privkey_sign_func sign_fn, + gnutls_privkey_decrypt_func decrypt_fn, + gnutls_privkey_deinit_func deinit_fn, + unsigned int flags) +{ + int ret; + + ret = check_if_clean(pkey); + if (ret < 0) { + gnutls_assert(); + return ret; + } + + if (sign_fn == NULL && decrypt_fn == NULL) + return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); + + pkey->key.ext.sign_func = sign_fn; + pkey->key.ext.decrypt_func = decrypt_fn; + pkey->key.ext.deinit_func = deinit_fn; + pkey->key.ext.userdata = userdata; + pkey->type = GNUTLS_PRIVKEY_EXT; + pkey->pk_algorithm = pk; + pkey->flags = flags; + + /* Ensure gnutls_privkey_deinit() calls the deinit_func */ + if (deinit_fn) + pkey->flags |= GNUTLS_PRIVKEY_IMPORT_AUTO_RELEASE; + + return 0; +} + +/** + * gnutls_privkey_import_ext3: + * @pkey: The private key + * @userdata: private data to be provided to the callbacks + * @sign_fn: callback for signature operations + * @decrypt_fn: callback for decryption operations + * @deinit_fn: a deinitialization function + * @info_fn: returns info about the public key algorithm (should not be %NULL) + * @flags: Flags for the import + * + * This function will associate the given callbacks with the + * #gnutls_privkey_t type. At least one of the two callbacks + * must be non-null. If a deinitialization function is provided + * then flags is assumed to contain %GNUTLS_PRIVKEY_IMPORT_AUTO_RELEASE. + * + * Note that the signing function is supposed to "raw" sign data, i.e., + * without any hashing or preprocessing. In case of RSA the DigestInfo + * will be provided, and the signing function is expected to do the PKCS #1 + * 1.5 padding and the exponentiation. + * + * The @info_fn must provide information on the algorithms supported by + * this private key, and should support the flags %GNUTLS_PRIVKEY_INFO_PK_ALGO and + * %GNUTLS_PRIVKEY_INFO_SIGN_ALGO. It must return -1 on unknown flags. + * + * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a + * negative error value. + * + * Since: 3.4.0 + **/ +int +gnutls_privkey_import_ext3(gnutls_privkey_t pkey, + void *userdata, + gnutls_privkey_sign_func sign_fn, + gnutls_privkey_decrypt_func decrypt_fn, + gnutls_privkey_deinit_func deinit_fn, + gnutls_privkey_info_func info_fn, + unsigned int flags) +{ + int ret; + + ret = check_if_clean(pkey); + if (ret < 0) { + gnutls_assert(); + return ret; + } + + if (sign_fn == NULL && decrypt_fn == NULL) + return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); + + if (info_fn == NULL) + return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); + + pkey->key.ext.sign_func = sign_fn; + pkey->key.ext.decrypt_func = decrypt_fn; + pkey->key.ext.deinit_func = deinit_fn; + pkey->key.ext.info_func = info_fn; + pkey->key.ext.userdata = userdata; + pkey->type = GNUTLS_PRIVKEY_EXT; + pkey->flags = flags; + + pkey->pk_algorithm = pkey->key.ext.info_func(pkey, GNUTLS_PRIVKEY_INFO_PK_ALGO, pkey->key.ext.userdata); + + /* Ensure gnutls_privkey_deinit() calls the deinit_func */ + if (deinit_fn) + pkey->flags |= GNUTLS_PRIVKEY_IMPORT_AUTO_RELEASE; + + return 0; +} + +/** + * gnutls_privkey_import_x509: + * @pkey: The private key + * @key: The private key to be imported + * @flags: Flags for the import + * + * This function will import the given private key to the abstract + * #gnutls_privkey_t type. + * + * The #gnutls_x509_privkey_t object must not be deallocated + * during the lifetime of this structure. + * + * @flags might be zero or one of %GNUTLS_PRIVKEY_IMPORT_AUTO_RELEASE + * and %GNUTLS_PRIVKEY_IMPORT_COPY. + * + * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a + * negative error value. + * + * Since: 2.12.0 + **/ +int +gnutls_privkey_import_x509(gnutls_privkey_t pkey, + gnutls_x509_privkey_t key, unsigned int flags) +{ + int ret; + + ret = check_if_clean(pkey); + if (ret < 0) { + gnutls_assert(); + return ret; + } + + if (flags & GNUTLS_PRIVKEY_IMPORT_COPY) { + ret = gnutls_x509_privkey_init(&pkey->key.x509); + if (ret < 0) + return gnutls_assert_val(ret); + + ret = gnutls_x509_privkey_cpy(pkey->key.x509, key); + if (ret < 0) { + gnutls_x509_privkey_deinit(pkey->key.x509); + return gnutls_assert_val(ret); + } + } else + pkey->key.x509 = key; + + pkey->type = GNUTLS_PRIVKEY_X509; + pkey->pk_algorithm = gnutls_x509_privkey_get_pk_algorithm(key); + pkey->flags = flags; + + return 0; +} + +/** + * gnutls_privkey_export_x509: + * @pkey: The private key + * @key: Location for the key to be exported. + * + * Converts the given abstract private key to a #gnutls_x509_privkey_t + * type. The key must be of type %GNUTLS_PRIVKEY_X509. The key returned + * in @key must be deinitialized with gnutls_x509_privkey_deinit(). + * + * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a + * negative error value. + * + * Since: 3.4.0 + */ +int +gnutls_privkey_export_x509(gnutls_privkey_t pkey, + gnutls_x509_privkey_t *key) +{ + int ret; + + if (pkey->type != GNUTLS_PRIVKEY_X509) { + gnutls_assert(); + return GNUTLS_E_INVALID_REQUEST; + } + + ret = gnutls_x509_privkey_init(key); + if (ret < 0) + return gnutls_assert_val(ret); + + ret = gnutls_x509_privkey_cpy(*key, pkey->key.x509); + if (ret < 0) { + gnutls_x509_privkey_deinit(*key); + *key = NULL; + + return gnutls_assert_val(ret); + } + + return 0; +} + +/** + * gnutls_privkey_generate: + * @pkey: The private key + * @algo: is one of the algorithms in #gnutls_pk_algorithm_t. + * @bits: the size of the modulus + * @flags: unused for now. Must be 0. + * + * This function will generate a random private key. Note that this + * function must be called on an empty private key. + * + * Note that when generating an elliptic curve key, the curve + * can be substituted in the place of the bits parameter using the + * GNUTLS_CURVE_TO_BITS() macro. + * + * Do not set the number of bits directly, use gnutls_sec_param_to_pk_bits(). + * + * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a + * negative error value. + * + * Since: 3.3.0 + **/ +int +gnutls_privkey_generate(gnutls_privkey_t pkey, + gnutls_pk_algorithm_t algo, unsigned int bits, + unsigned int flags) +{ + int ret; + + ret = gnutls_x509_privkey_init(&pkey->key.x509); + if (ret < 0) + return gnutls_assert_val(ret); + + ret = gnutls_x509_privkey_generate(pkey->key.x509, algo, bits, flags); + if (ret < 0) { + gnutls_x509_privkey_deinit(pkey->key.x509); + pkey->key.x509 = NULL; + return gnutls_assert_val(ret); + } + + pkey->type = GNUTLS_PRIVKEY_X509; + pkey->pk_algorithm = algo; + pkey->flags = flags | GNUTLS_PRIVKEY_IMPORT_AUTO_RELEASE; + + return 0; +} + +#ifdef ENABLE_OPENPGP +/** + * gnutls_privkey_import_openpgp: + * @pkey: The private key + * @key: The private key to be imported + * @flags: Flags for the import + * + * This function will import the given private key to the abstract + * #gnutls_privkey_t type. + * + * The #gnutls_openpgp_privkey_t object must not be deallocated + * during the lifetime of this structure. The subkey set as + * preferred will be used, or the master key otherwise. + * + * @flags might be zero or one of %GNUTLS_PRIVKEY_IMPORT_AUTO_RELEASE + * and %GNUTLS_PRIVKEY_IMPORT_COPY. + * + * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a + * negative error value. + * + * Since: 2.12.0 + **/ +int +gnutls_privkey_import_openpgp(gnutls_privkey_t pkey, + gnutls_openpgp_privkey_t key, unsigned int flags) +{ + int ret, idx; + uint8_t keyid[GNUTLS_OPENPGP_KEYID_SIZE]; + + ret = check_if_clean(pkey); + if (ret < 0) { + gnutls_assert(); + return ret; + } + + if (flags & GNUTLS_PRIVKEY_IMPORT_COPY) { + ret = gnutls_openpgp_privkey_init(&pkey->key.openpgp); + if (ret < 0) + return gnutls_assert_val(ret); + + ret = _gnutls_openpgp_privkey_cpy(pkey->key.openpgp, key); + if (ret < 0) { + gnutls_openpgp_privkey_deinit(pkey->key.openpgp); + return gnutls_assert_val(ret); + } + } else + pkey->key.openpgp = key; + + pkey->type = GNUTLS_PRIVKEY_OPENPGP; + + ret = gnutls_openpgp_privkey_get_preferred_key_id(key, keyid); + if (ret == GNUTLS_E_OPENPGP_PREFERRED_KEY_ERROR) { + pkey->pk_algorithm = + gnutls_openpgp_privkey_get_pk_algorithm(key, NULL); + } else { + if (ret < 0) + return gnutls_assert_val(ret); + + idx = gnutls_openpgp_privkey_get_subkey_idx(key, keyid); + + pkey->pk_algorithm = + gnutls_openpgp_privkey_get_subkey_pk_algorithm(key, + idx, NULL); + } + + pkey->flags = flags; + + return 0; +} + +/** + * gnutls_privkey_import_openpgp_raw: + * @pkey: The private key + * @data: The private key data to be imported + * @format: The format of the private key + * @keyid: The key id to use (optional) + * @password: A password (optional) + * + * This function will import the given private key to the abstract + * #gnutls_privkey_t type. + * + * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a + * negative error value. + * + * Since: 3.1.0 + **/ +int gnutls_privkey_import_openpgp_raw(gnutls_privkey_t pkey, + const gnutls_datum_t * data, + gnutls_openpgp_crt_fmt_t format, + const gnutls_openpgp_keyid_t keyid, + const char *password) +{ + gnutls_openpgp_privkey_t xpriv; + int ret; + + ret = gnutls_openpgp_privkey_init(&xpriv); + if (ret < 0) + return gnutls_assert_val(ret); + + ret = gnutls_openpgp_privkey_import(xpriv, data, format, password, 0); + if (ret < 0) { + gnutls_assert(); + goto cleanup; + } + + if (keyid) { + ret = gnutls_openpgp_privkey_set_preferred_key_id(xpriv, keyid); + if (ret < 0) { + gnutls_assert(); + goto cleanup; + } + } + + ret = + gnutls_privkey_import_openpgp(pkey, xpriv, + GNUTLS_PRIVKEY_IMPORT_AUTO_RELEASE); + if (ret < 0) { + gnutls_assert(); + goto cleanup; + } + + return 0; + + cleanup: + gnutls_openpgp_privkey_deinit(xpriv); + + return ret; +} + +/** + * gnutls_privkey_export_openpgp: + * @pkey: The private key + * @key: Location for the key to be exported. + * + * Converts the given abstract private key to a #gnutls_openpgp_privkey_t + * type. The key must be of type %GNUTLS_PRIVKEY_OPENPGP. The key + * returned in @key must be deinitialized with + * gnutls_openpgp_privkey_deinit(). + * + * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a + * negative error value. + * + * Since: 3.4.0 + */ +int +gnutls_privkey_export_openpgp(gnutls_privkey_t pkey, + gnutls_openpgp_privkey_t *key) +{ + int ret; + + if (pkey->type != GNUTLS_PRIVKEY_OPENPGP) { + gnutls_assert(); + return GNUTLS_E_INVALID_REQUEST; + } + + ret = gnutls_openpgp_privkey_init(key); + if (ret < 0) + return gnutls_assert_val(ret); + + ret = _gnutls_openpgp_privkey_cpy(*key, pkey->key.openpgp); + if (ret < 0) { + gnutls_openpgp_privkey_deinit(*key); + *key = NULL; + + return gnutls_assert_val(ret); + } + + return 0; +} +#endif + +/** + * gnutls_privkey_sign_data: + * @signer: Holds the key + * @hash: should be a digest algorithm + * @flags: Zero or one of %gnutls_privkey_flags_t + * @data: holds the data to be signed + * @signature: will contain the signature allocated with gnutls_malloc() + * + * This function will sign the given data using a signature algorithm + * supported by the private key. Signature algorithms are always used + * together with a hash functions. Different hash functions may be + * used for the RSA algorithm, but only the SHA family for the DSA keys. + * + * You may use gnutls_pubkey_get_preferred_hash_algorithm() to determine + * the hash algorithm. + * + * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a + * negative error value. + * + * Since: 2.12.0 + **/ +int +gnutls_privkey_sign_data(gnutls_privkey_t signer, + gnutls_digest_algorithm_t hash, + unsigned int flags, + const gnutls_datum_t * data, + gnutls_datum_t * signature) +{ + int ret; + gnutls_datum_t digest; + const mac_entry_st *me = hash_to_entry(hash); + + if (flags & GNUTLS_PRIVKEY_SIGN_FLAG_TLS1_RSA) + return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); + + ret = pk_hash_data(signer->pk_algorithm, me, NULL, data, &digest); + if (ret < 0) { + gnutls_assert(); + return ret; + } + + ret = pk_prepare_hash(signer->pk_algorithm, me, &digest); + if (ret < 0) { + gnutls_assert(); + goto cleanup; + } + + ret = _gnutls_privkey_sign_raw_data(signer, flags, &digest, signature); + _gnutls_free_datum(&digest); + + if (ret < 0) { + gnutls_assert(); + return ret; + } + + return 0; + + cleanup: + _gnutls_free_datum(&digest); + return ret; +} + +/** + * gnutls_privkey_sign_hash: + * @signer: Holds the signer's key + * @hash_algo: The hash algorithm used + * @flags: Zero or one of %gnutls_privkey_flags_t + * @hash_data: holds the data to be signed + * @signature: will contain newly allocated signature + * + * This function will sign the given hashed data using a signature algorithm + * supported by the private key. Signature algorithms are always used + * together with a hash functions. Different hash functions may be + * used for the RSA algorithm, but only SHA-XXX for the DSA keys. + * + * You may use gnutls_pubkey_get_preferred_hash_algorithm() to determine + * the hash algorithm. + * + * Note that if %GNUTLS_PRIVKEY_SIGN_FLAG_TLS1_RSA flag is specified this function + * will ignore @hash_algo and perform a raw PKCS1 signature. + * + * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a + * negative error value. + * + * Since: 2.12.0 + **/ +int +gnutls_privkey_sign_hash(gnutls_privkey_t signer, + gnutls_digest_algorithm_t hash_algo, + unsigned int flags, + const gnutls_datum_t * hash_data, + gnutls_datum_t * signature) +{ + int ret; + gnutls_datum_t digest; + + if (flags & GNUTLS_PRIVKEY_SIGN_FLAG_TLS1_RSA) + return _gnutls_privkey_sign_raw_data(signer, flags, + hash_data, signature); + + digest.data = gnutls_malloc(hash_data->size); + if (digest.data == NULL) { + gnutls_assert(); + return GNUTLS_E_MEMORY_ERROR; + } + digest.size = hash_data->size; + memcpy(digest.data, hash_data->data, digest.size); + + ret = + pk_prepare_hash(signer->pk_algorithm, hash_to_entry(hash_algo), + &digest); + if (ret < 0) { + gnutls_assert(); + goto cleanup; + } + + ret = _gnutls_privkey_sign_raw_data(signer, flags, &digest, signature); + if (ret < 0) { + gnutls_assert(); + goto cleanup; + } + + ret = 0; + + cleanup: + _gnutls_free_datum(&digest); + return ret; +} + +/*- + * gnutls_privkey_sign_raw_data: + * @key: Holds the key + * @flags: should be zero + * @data: holds the data to be signed + * @signature: will contain the signature allocated with gnutls_malloc() + * + * This function will sign the given data using a signature algorithm + * supported by the private key. Note that this is a low-level function + * and does not apply any preprocessing or hash on the signed data. + * For example on an RSA key the input @data should be of the DigestInfo + * PKCS #1 1.5 format. Use it only if you know what are you doing. + * + * Note this function is equivalent to using the %GNUTLS_PRIVKEY_SIGN_FLAG_TLS1_RSA + * flag with gnutls_privkey_sign_hash(). + * + * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a + * negative error value. + * + * Since: 3.1.10 + -*/ +static int +_gnutls_privkey_sign_raw_data(gnutls_privkey_t key, + unsigned flags, + const gnutls_datum_t * data, + gnutls_datum_t * signature) +{ + switch (key->type) { +#ifdef ENABLE_OPENPGP + case GNUTLS_PRIVKEY_OPENPGP: + return gnutls_openpgp_privkey_sign_hash(key->key.openpgp, + data, signature); +#endif +#ifdef ENABLE_PKCS11 + case GNUTLS_PRIVKEY_PKCS11: + return _gnutls_pkcs11_privkey_sign_hash(key->key.pkcs11, + data, signature); +#endif + case GNUTLS_PRIVKEY_X509: + return _gnutls_pk_sign(key->key.x509->pk_algorithm, + signature, data, &key->key.x509->params); + case GNUTLS_PRIVKEY_EXT: + if (key->key.ext.sign_func == NULL) + return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); + return key->key.ext.sign_func(key, key->key.ext.userdata, + data, signature); + default: + gnutls_assert(); + return GNUTLS_E_INVALID_REQUEST; + } +} + +/** + * gnutls_privkey_decrypt_data: + * @key: Holds the key + * @flags: zero for now + * @ciphertext: holds the data to be decrypted + * @plaintext: will contain the decrypted data, allocated with gnutls_malloc() + * + * This function will decrypt the given data using the algorithm + * supported by the private key. + * + * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a + * negative error value. + * + * Since: 2.12.0 + **/ +int +gnutls_privkey_decrypt_data(gnutls_privkey_t key, + unsigned int flags, + const gnutls_datum_t * ciphertext, + gnutls_datum_t * plaintext) +{ + switch (key->type) { +#ifdef ENABLE_OPENPGP + case GNUTLS_PRIVKEY_OPENPGP: + return _gnutls_openpgp_privkey_decrypt_data(key->key.openpgp, + flags, ciphertext, + plaintext); +#endif + case GNUTLS_PRIVKEY_X509: + return _gnutls_pk_decrypt(key->pk_algorithm, plaintext, + ciphertext, &key->key.x509->params); +#ifdef ENABLE_PKCS11 + case GNUTLS_PRIVKEY_PKCS11: + return _gnutls_pkcs11_privkey_decrypt_data(key->key.pkcs11, + flags, + ciphertext, + plaintext); +#endif + case GNUTLS_PRIVKEY_EXT: + if (key->key.ext.decrypt_func == NULL) + return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); + + return key->key.ext.decrypt_func(key, + key->key.ext.userdata, + ciphertext, plaintext); + default: + gnutls_assert(); + return GNUTLS_E_INVALID_REQUEST; + } +} + +/** + * gnutls_privkey_import_x509_raw: + * @pkey: The private key + * @data: The private key data to be imported + * @format: The format of the private key + * @password: A password (optional) + * @flags: an ORed sequence of gnutls_pkcs_encrypt_flags_t + * + * This function will import the given private key to the abstract + * #gnutls_privkey_t type. + * + * The supported formats are basic unencrypted key, PKCS8, PKCS12, + * and the openssl format. + * + * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a + * negative error value. + * + * Since: 3.1.0 + **/ +int gnutls_privkey_import_x509_raw(gnutls_privkey_t pkey, + const gnutls_datum_t * data, + gnutls_x509_crt_fmt_t format, + const char *password, unsigned int flags) +{ + gnutls_x509_privkey_t xpriv; + int ret; + + ret = gnutls_x509_privkey_init(&xpriv); + if (ret < 0) + return gnutls_assert_val(ret); + + if (pkey->pin.cb) { + gnutls_x509_privkey_set_pin_function(xpriv, pkey->pin.cb, + pkey->pin.data); + } + + ret = gnutls_x509_privkey_import2(xpriv, data, format, password, flags); + if (ret < 0) { + gnutls_assert(); + goto cleanup; + } + + ret = + gnutls_privkey_import_x509(pkey, xpriv, + GNUTLS_PRIVKEY_IMPORT_AUTO_RELEASE); + if (ret < 0) { + gnutls_assert(); + goto cleanup; + } + + return 0; + + cleanup: + gnutls_x509_privkey_deinit(xpriv); + + return ret; +} + +/** + * gnutls_privkey_import_url: + * @key: A key of type #gnutls_privkey_t + * @url: A PKCS 11 url + * @flags: should be zero + * + * This function will import a PKCS11 or TPM URL as a + * private key. The supported URL types can be checked + * using gnutls_url_is_supported(). + * + * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a + * negative error value. + * + * Since: 3.1.0 + **/ +int +gnutls_privkey_import_url(gnutls_privkey_t key, const char *url, + unsigned int flags) +{ + unsigned i; + int ret; + + if (strncmp(url, PKCS11_URL, PKCS11_URL_SIZE) == 0) { +#ifdef ENABLE_PKCS11 + ret = _gnutls_privkey_import_pkcs11_url(key, url, flags); +#else + ret = gnutls_assert_val(GNUTLS_E_UNIMPLEMENTED_FEATURE); +#endif + goto cleanup; + } + + if (strncmp(url, TPMKEY_URL, TPMKEY_URL_SIZE) == 0) { +#ifdef HAVE_TROUSERS + ret = gnutls_privkey_import_tpm_url(key, url, NULL, NULL, 0); +#else + ret = gnutls_assert_val(GNUTLS_E_UNIMPLEMENTED_FEATURE); +#endif + goto cleanup; + } + + if (strncmp(url, SYSTEM_URL, SYSTEM_URL_SIZE) == 0) { + ret = _gnutls_privkey_import_system_url(key, url); + goto cleanup; + } + + for (i=0;i<_gnutls_custom_urls_size;i++) { + if (strncmp(url, _gnutls_custom_urls[i].name, _gnutls_custom_urls[i].name_size) == 0) { + if (_gnutls_custom_urls[i].import_key) { + ret = _gnutls_custom_urls[i].import_key(key, url, flags); + goto cleanup; + } + break; + } + } + + ret = gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); + cleanup: + return ret; +} + +/** + * gnutls_privkey_set_pin_function: + * @key: A key of type #gnutls_privkey_t + * @fn: the callback + * @userdata: data associated with the callback + * + * This function will set a callback function to be used when + * required to access the object. This function overrides any other + * global PIN functions. + * + * Note that this function must be called right after initialization + * to have effect. + * + * Since: 3.1.0 + * + **/ +void gnutls_privkey_set_pin_function(gnutls_privkey_t key, + gnutls_pin_callback_t fn, void *userdata) +{ + key->pin.cb = fn; + key->pin.data = userdata; +} + +/** + * gnutls_privkey_status: + * @key: Holds the key + * + * Checks the status of the private key token. This function + * is an actual wrapper over gnutls_pkcs11_privkey_status(), and + * if the private key is a PKCS #11 token it will check whether + * it is inserted or not. + * + * Returns: this function will return non-zero if the token + * holding the private key is still available (inserted), and zero otherwise. + * + * Since: 3.1.10 + * + **/ +int gnutls_privkey_status(gnutls_privkey_t key) +{ + switch (key->type) { +#ifdef ENABLE_PKCS11 + case GNUTLS_PRIVKEY_PKCS11: + return gnutls_pkcs11_privkey_status(key->key.pkcs11); +#endif + default: + return 1; + } +} + +/** + * gnutls_privkey_verify_params: + * @key: should contain a #gnutls_privkey_t type + * + * This function will verify the private key parameters. + * + * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a + * negative error value. + * + * Since: 3.3.0 + **/ +int gnutls_privkey_verify_params(gnutls_privkey_t key) +{ + gnutls_pk_params_st params; + int ret; + + gnutls_pk_params_init(¶ms); + + ret = _gnutls_privkey_get_mpis(key, ¶ms); + if (ret < 0) + return gnutls_assert_val(ret); + + ret = _gnutls_pk_verify_priv_params(key->pk_algorithm, ¶ms); + + gnutls_pk_params_release(¶ms); + + if (ret < 0) { + gnutls_assert(); + return ret; + } + + return 0; +} + +/*- + * _gnutls_privkey_get_preferred_sign_algo: + * @key: should contain a #gnutls_privkey_t type + * + * This function returns the preferred signature algorithm for this + * private key. + * + * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a + * negative error value. + * + * Since: 3.4.0 + -*/ +gnutls_sign_algorithm_t +_gnutls_privkey_get_preferred_sign_algo(gnutls_privkey_t key) +{ + if (key->type == GNUTLS_PRIVKEY_EXT) { + if (key->key.ext.info_func) + return key->key.ext.info_func(key, GNUTLS_PRIVKEY_INFO_SIGN_ALGO, key->key.ext.userdata); + } + return key->preferred_sign_algo; +} |