diff options
author | René Schümann <white06tiger@gmail.com> | 2015-03-14 19:56:55 +0000 |
---|---|---|
committer | René Schümann <white06tiger@gmail.com> | 2015-03-14 19:56:55 +0000 |
commit | c60aed5432e9cda277b9351de51e82dfb8e02475 (patch) | |
tree | 97ccd1ea8e2544f6a9673ee7d04c18b714877a35 /plugins/MirOTR/libgcrypt-1.4.6/cipher/pubkey.c | |
parent | d2b26b1f86326362f56540b5185fa09ab5f2779c (diff) |
MirOTR: part one of many file/folder structure changes
git-svn-id: http://svn.miranda-ng.org/main/trunk@12402 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c
Diffstat (limited to 'plugins/MirOTR/libgcrypt-1.4.6/cipher/pubkey.c')
-rw-r--r-- | plugins/MirOTR/libgcrypt-1.4.6/cipher/pubkey.c | 2749 |
1 files changed, 0 insertions, 2749 deletions
diff --git a/plugins/MirOTR/libgcrypt-1.4.6/cipher/pubkey.c b/plugins/MirOTR/libgcrypt-1.4.6/cipher/pubkey.c deleted file mode 100644 index f163ea1696..0000000000 --- a/plugins/MirOTR/libgcrypt-1.4.6/cipher/pubkey.c +++ /dev/null @@ -1,2749 +0,0 @@ -/* pubkey.c - pubkey dispatcher - * Copyright (C) 1998, 1999, 2000, 2002, 2003, 2005, - * 2007, 2008 Free Software Foundation, Inc. - * - * This file is part of Libgcrypt. - * - * Libgcrypt 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. - * - * Libgcrypt 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 <config.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <errno.h> - -#include "g10lib.h" -#include "mpi.h" -#include "cipher.h" -#include "ath.h" - - -static gcry_err_code_t pubkey_decrypt (int algo, gcry_mpi_t *result, - gcry_mpi_t *data, gcry_mpi_t *skey, - int flags); -static gcry_err_code_t pubkey_sign (int algo, gcry_mpi_t *resarr, - gcry_mpi_t hash, gcry_mpi_t *skey); -static gcry_err_code_t pubkey_verify (int algo, gcry_mpi_t hash, - gcry_mpi_t *data, gcry_mpi_t *pkey, - int (*cmp) (void *, gcry_mpi_t), - void *opaque); - - -/* A dummy extraspec so that we do not need to tests the extraspec - field from the module specification against NULL and instead - directly test the respective fields of extraspecs. */ -static pk_extra_spec_t dummy_extra_spec; - - -/* This is the list of the default public-key ciphers included in - libgcrypt. FIPS_ALLOWED indicated whether the algorithm is used in - FIPS mode. */ -static struct pubkey_table_entry -{ - gcry_pk_spec_t *pubkey; - pk_extra_spec_t *extraspec; - unsigned int algorithm; - int fips_allowed; -} pubkey_table[] = - { -#if USE_RSA - { &_gcry_pubkey_spec_rsa, - &_gcry_pubkey_extraspec_rsa, GCRY_PK_RSA, 1}, -#endif -#if USE_ELGAMAL - { &_gcry_pubkey_spec_elg, - &_gcry_pubkey_extraspec_elg, GCRY_PK_ELG }, - { &_gcry_pubkey_spec_elg, - &_gcry_pubkey_extraspec_elg, GCRY_PK_ELG_E }, -#endif -#if USE_DSA - { &_gcry_pubkey_spec_dsa, - &_gcry_pubkey_extraspec_dsa, GCRY_PK_DSA, 1 }, -#endif -#if USE_ECC - { &_gcry_pubkey_spec_ecdsa, - &_gcry_pubkey_extraspec_ecdsa, GCRY_PK_ECDSA, 0 }, -#endif - { NULL, 0 }, - }; - -/* List of registered ciphers. */ -static gcry_module_t pubkeys_registered; - -/* This is the lock protecting PUBKEYS_REGISTERED. */ -static ath_mutex_t pubkeys_registered_lock = ATH_MUTEX_INITIALIZER;; - -/* Flag to check wether the default pubkeys have already been - registered. */ -static int default_pubkeys_registered; - -/* Convenient macro for registering the default digests. */ -#define REGISTER_DEFAULT_PUBKEYS \ - do \ - { \ - ath_mutex_lock (&pubkeys_registered_lock); \ - if (! default_pubkeys_registered) \ - { \ - pk_register_default (); \ - default_pubkeys_registered = 1; \ - } \ - ath_mutex_unlock (&pubkeys_registered_lock); \ - } \ - while (0) - -/* These dummy functions are used in case a cipher implementation - refuses to provide it's own functions. */ - -static gcry_err_code_t -dummy_generate (int algorithm, unsigned int nbits, unsigned long dummy, - gcry_mpi_t *skey, gcry_mpi_t **retfactors) -{ - (void)algorithm; - (void)nbits; - (void)dummy; - (void)skey; - (void)retfactors; - fips_signal_error ("using dummy public key function"); - return GPG_ERR_NOT_IMPLEMENTED; -} - -static gcry_err_code_t -dummy_check_secret_key (int algorithm, gcry_mpi_t *skey) -{ - (void)algorithm; - (void)skey; - fips_signal_error ("using dummy public key function"); - return GPG_ERR_NOT_IMPLEMENTED; -} - -static gcry_err_code_t -dummy_encrypt (int algorithm, gcry_mpi_t *resarr, gcry_mpi_t data, - gcry_mpi_t *pkey, int flags) -{ - (void)algorithm; - (void)resarr; - (void)data; - (void)pkey; - (void)flags; - fips_signal_error ("using dummy public key function"); - return GPG_ERR_NOT_IMPLEMENTED; -} - -static gcry_err_code_t -dummy_decrypt (int algorithm, gcry_mpi_t *result, gcry_mpi_t *data, - gcry_mpi_t *skey, int flags) -{ - (void)algorithm; - (void)result; - (void)data; - (void)skey; - (void)flags; - fips_signal_error ("using dummy public key function"); - return GPG_ERR_NOT_IMPLEMENTED; -} - -static gcry_err_code_t -dummy_sign (int algorithm, gcry_mpi_t *resarr, gcry_mpi_t data, - gcry_mpi_t *skey) -{ - (void)algorithm; - (void)resarr; - (void)data; - (void)skey; - fips_signal_error ("using dummy public key function"); - return GPG_ERR_NOT_IMPLEMENTED; -} - -static gcry_err_code_t -dummy_verify (int algorithm, gcry_mpi_t hash, gcry_mpi_t *data, - gcry_mpi_t *pkey, - int (*cmp) (void *, gcry_mpi_t), void *opaquev) -{ - (void)algorithm; - (void)hash; - (void)data; - (void)pkey; - (void)cmp; - (void)opaquev; - fips_signal_error ("using dummy public key function"); - return GPG_ERR_NOT_IMPLEMENTED; -} - -static unsigned -dummy_get_nbits (int algorithm, gcry_mpi_t *pkey) -{ - (void)algorithm; - (void)pkey; - fips_signal_error ("using dummy public key function"); - return 0; -} - -/* Internal function. Register all the pubkeys included in - PUBKEY_TABLE. Returns zero on success or an error code. */ -static void -pk_register_default (void) -{ - gcry_err_code_t err = 0; - int i; - - for (i = 0; (! err) && pubkey_table[i].pubkey; i++) - { -#define pubkey_use_dummy(func) \ - if (! pubkey_table[i].pubkey->func) \ - pubkey_table[i].pubkey->func = dummy_##func; - - pubkey_use_dummy (generate); - pubkey_use_dummy (check_secret_key); - pubkey_use_dummy (encrypt); - pubkey_use_dummy (decrypt); - pubkey_use_dummy (sign); - pubkey_use_dummy (verify); - pubkey_use_dummy (get_nbits); -#undef pubkey_use_dummy - - err = _gcry_module_add (&pubkeys_registered, - pubkey_table[i].algorithm, - (void *) pubkey_table[i].pubkey, - (void *) pubkey_table[i].extraspec, - NULL); - } - - if (err) - BUG (); -} - -/* Internal callback function. Used via _gcry_module_lookup. */ -static int -gcry_pk_lookup_func_name (void *spec, void *data) -{ - gcry_pk_spec_t *pubkey = (gcry_pk_spec_t *) spec; - char *name = (char *) data; - const char **aliases = pubkey->aliases; - int ret = _stricmp (name, pubkey->name); - - while (ret && *aliases) - ret = _stricmp (name, *aliases++); - - return ! ret; -} - -/* Internal function. Lookup a pubkey entry by it's name. */ -static gcry_module_t -gcry_pk_lookup_name (const char *name) -{ - gcry_module_t pubkey; - - pubkey = _gcry_module_lookup (pubkeys_registered, (void *) name, - gcry_pk_lookup_func_name); - - return pubkey; -} - -/* Register a new pubkey module whose specification can be found in - PUBKEY. On success, a new algorithm ID is stored in ALGORITHM_ID - and a pointer representhing this module is stored in MODULE. */ -gcry_error_t -_gcry_pk_register (gcry_pk_spec_t *pubkey, - pk_extra_spec_t *extraspec, - unsigned int *algorithm_id, - gcry_module_t *module) -{ - gcry_err_code_t err = GPG_ERR_NO_ERROR; - gcry_module_t mod; - - /* We do not support module loading in fips mode. */ - if (fips_mode ()) - return gpg_error (GPG_ERR_NOT_SUPPORTED); - - ath_mutex_lock (&pubkeys_registered_lock); - err = _gcry_module_add (&pubkeys_registered, 0, - (void *) pubkey, - (void *)(extraspec? extraspec : &dummy_extra_spec), - &mod); - ath_mutex_unlock (&pubkeys_registered_lock); - - if (! err) - { - *module = mod; - *algorithm_id = mod->mod_id; - } - - return err; -} - -/* Unregister the pubkey identified by ID, which must have been - registered with gcry_pk_register. */ -void -gcry_pk_unregister (gcry_module_t module) -{ - ath_mutex_lock (&pubkeys_registered_lock); - _gcry_module_release (module); - ath_mutex_unlock (&pubkeys_registered_lock); -} - -static void -release_mpi_array (gcry_mpi_t *array) -{ - for (; *array; array++) - { - mpi_free(*array); - *array = NULL; - } -} - -/**************** - * Map a string to the pubkey algo - */ -int -gcry_pk_map_name (const char *string) -{ - gcry_module_t pubkey; - int algorithm = 0; - - if (!string) - return 0; - - REGISTER_DEFAULT_PUBKEYS; - - ath_mutex_lock (&pubkeys_registered_lock); - pubkey = gcry_pk_lookup_name (string); - if (pubkey) - { - algorithm = pubkey->mod_id; - _gcry_module_release (pubkey); - } - ath_mutex_unlock (&pubkeys_registered_lock); - - return algorithm; -} - - -/* Map the public key algorithm whose ID is contained in ALGORITHM to - a string representation of the algorithm name. For unknown - algorithm IDs this functions returns "?". */ -const char * -gcry_pk_algo_name (int algorithm) -{ - gcry_module_t pubkey; - const char *name; - - REGISTER_DEFAULT_PUBKEYS; - - ath_mutex_lock (&pubkeys_registered_lock); - pubkey = _gcry_module_lookup_id (pubkeys_registered, algorithm); - if (pubkey) - { - name = ((gcry_pk_spec_t *) pubkey->spec)->name; - _gcry_module_release (pubkey); - } - else - name = "?"; - ath_mutex_unlock (&pubkeys_registered_lock); - - return name; -} - - -/* A special version of gcry_pk_algo name to return the first aliased - name of the algorithm. This is required to adhere to the spki - specs where the algorithm names are lowercase. */ -const char * -_gcry_pk_aliased_algo_name (int algorithm) -{ - const char *name = NULL; - gcry_module_t module; - - REGISTER_DEFAULT_PUBKEYS; - - ath_mutex_lock (&pubkeys_registered_lock); - module = _gcry_module_lookup_id (pubkeys_registered, algorithm); - if (module) - { - gcry_pk_spec_t *pubkey = (gcry_pk_spec_t *) module->spec; - - name = pubkey->aliases? *pubkey->aliases : NULL; - if (!name || !*name) - name = pubkey->name; - _gcry_module_release (module); - } - ath_mutex_unlock (&pubkeys_registered_lock); - - return name; -} - - -static void -disable_pubkey_algo (int algorithm) -{ - gcry_module_t pubkey; - - ath_mutex_lock (&pubkeys_registered_lock); - pubkey = _gcry_module_lookup_id (pubkeys_registered, algorithm); - if (pubkey) - { - if (! (pubkey-> flags & FLAG_MODULE_DISABLED)) - pubkey->flags |= FLAG_MODULE_DISABLED; - _gcry_module_release (pubkey); - } - ath_mutex_unlock (&pubkeys_registered_lock); -} - - -/**************** - * A USE of 0 means: don't care. - */ -static gcry_err_code_t -check_pubkey_algo (int algorithm, unsigned use) -{ - gcry_err_code_t err = GPG_ERR_NO_ERROR; - gcry_pk_spec_t *pubkey; - gcry_module_t module; - - REGISTER_DEFAULT_PUBKEYS; - - ath_mutex_lock (&pubkeys_registered_lock); - module = _gcry_module_lookup_id (pubkeys_registered, algorithm); - if (module) - { - pubkey = (gcry_pk_spec_t *) module->spec; - - if (((use & GCRY_PK_USAGE_SIGN) - && (! (pubkey->use & GCRY_PK_USAGE_SIGN))) - || ((use & GCRY_PK_USAGE_ENCR) - && (! (pubkey->use & GCRY_PK_USAGE_ENCR)))) - err = GPG_ERR_WRONG_PUBKEY_ALGO; - else if (module->flags & FLAG_MODULE_DISABLED) - err = GPG_ERR_PUBKEY_ALGO; - _gcry_module_release (module); - } - else - err = GPG_ERR_PUBKEY_ALGO; - ath_mutex_unlock (&pubkeys_registered_lock); - - return err; -} - - -/**************** - * Return the number of public key material numbers - */ -static int -pubkey_get_npkey (int algorithm) -{ - gcry_module_t pubkey; - int npkey = 0; - - REGISTER_DEFAULT_PUBKEYS; - - ath_mutex_lock (&pubkeys_registered_lock); - pubkey = _gcry_module_lookup_id (pubkeys_registered, algorithm); - if (pubkey) - { - npkey = strlen (((gcry_pk_spec_t *) pubkey->spec)->elements_pkey); - _gcry_module_release (pubkey); - } - ath_mutex_unlock (&pubkeys_registered_lock); - - return npkey; -} - -/**************** - * Return the number of secret key material numbers - */ -static int -pubkey_get_nskey (int algorithm) -{ - gcry_module_t pubkey; - int nskey = 0; - - REGISTER_DEFAULT_PUBKEYS; - - ath_mutex_lock (&pubkeys_registered_lock); - pubkey = _gcry_module_lookup_id (pubkeys_registered, algorithm); - if (pubkey) - { - nskey = strlen (((gcry_pk_spec_t *) pubkey->spec)->elements_skey); - _gcry_module_release (pubkey); - } - ath_mutex_unlock (&pubkeys_registered_lock); - - return nskey; -} - -/**************** - * Return the number of signature material numbers - */ -static int -pubkey_get_nsig (int algorithm) -{ - gcry_module_t pubkey; - int nsig = 0; - - REGISTER_DEFAULT_PUBKEYS; - - ath_mutex_lock (&pubkeys_registered_lock); - pubkey = _gcry_module_lookup_id (pubkeys_registered, algorithm); - if (pubkey) - { - nsig = strlen (((gcry_pk_spec_t *) pubkey->spec)->elements_sig); - _gcry_module_release (pubkey); - } - ath_mutex_unlock (&pubkeys_registered_lock); - - return nsig; -} - -/**************** - * Return the number of encryption material numbers - */ -static int -pubkey_get_nenc (int algorithm) -{ - gcry_module_t pubkey; - int nenc = 0; - - REGISTER_DEFAULT_PUBKEYS; - - ath_mutex_lock (&pubkeys_registered_lock); - pubkey = _gcry_module_lookup_id (pubkeys_registered, algorithm); - if (pubkey) - { - nenc = strlen (((gcry_pk_spec_t *) pubkey->spec)->elements_enc); - _gcry_module_release (pubkey); - } - ath_mutex_unlock (&pubkeys_registered_lock); - - return nenc; -} - - -/* Generate a new public key with algorithm ALGORITHM of size NBITS - and return it at SKEY. USE_E depends on the ALGORITHM. GENPARMS - is passed to the algorithm module if it features an extended - generation function. RETFACTOR is used by some algorithms to - return certain additional information which are in general not - required. - - The function returns the error code number or 0 on success. */ -static gcry_err_code_t -pubkey_generate (int algorithm, - unsigned int nbits, - unsigned long use_e, - gcry_sexp_t genparms, - gcry_mpi_t *skey, gcry_mpi_t **retfactors, - gcry_sexp_t *r_extrainfo) -{ - gcry_err_code_t ec = GPG_ERR_PUBKEY_ALGO; - gcry_module_t pubkey; - - REGISTER_DEFAULT_PUBKEYS; - - ath_mutex_lock (&pubkeys_registered_lock); - pubkey = _gcry_module_lookup_id (pubkeys_registered, algorithm); - if (pubkey) - { - pk_extra_spec_t *extraspec = pubkey->extraspec; - - if (extraspec && extraspec->ext_generate) - { - /* Use the extended generate function. */ - ec = extraspec->ext_generate - (algorithm, nbits, use_e, genparms, skey, retfactors, r_extrainfo); - } - else - { - /* Use the standard generate function. */ - ec = ((gcry_pk_spec_t *) pubkey->spec)->generate - (algorithm, nbits, use_e, skey, retfactors); - } - _gcry_module_release (pubkey); - } - ath_mutex_unlock (&pubkeys_registered_lock); - - return ec; -} - - -static gcry_err_code_t -pubkey_check_secret_key (int algorithm, gcry_mpi_t *skey) -{ - gcry_err_code_t err = GPG_ERR_PUBKEY_ALGO; - gcry_module_t pubkey; - - REGISTER_DEFAULT_PUBKEYS; - - ath_mutex_lock (&pubkeys_registered_lock); - pubkey = _gcry_module_lookup_id (pubkeys_registered, algorithm); - if (pubkey) - { - err = ((gcry_pk_spec_t *) pubkey->spec)->check_secret_key - (algorithm, skey); - _gcry_module_release (pubkey); - } - ath_mutex_unlock (&pubkeys_registered_lock); - - return err; -} - - -/**************** - * This is the interface to the public key encryption. Encrypt DATA - * with PKEY and put it into RESARR which should be an array of MPIs - * of size PUBKEY_MAX_NENC (or less if the algorithm allows this - - * check with pubkey_get_nenc() ) - */ -static gcry_err_code_t -pubkey_encrypt (int algorithm, gcry_mpi_t *resarr, gcry_mpi_t data, - gcry_mpi_t *pkey, int flags) -{ - gcry_pk_spec_t *pubkey; - gcry_module_t module; - gcry_err_code_t rc; - int i; - - /* Note: In fips mode DBG_CIPHER will enver evaluate to true but as - an extra failsafe protection we explicitly test for fips mode - here. */ - if (DBG_CIPHER && !fips_mode ()) - { - log_debug ("pubkey_encrypt: algo=%d\n", algorithm); - for(i = 0; i < pubkey_get_npkey (algorithm); i++) - log_mpidump (" pkey:", pkey[i]); - log_mpidump (" data:", data); - } - - ath_mutex_lock (&pubkeys_registered_lock); - module = _gcry_module_lookup_id (pubkeys_registered, algorithm); - if (module) - { - pubkey = (gcry_pk_spec_t *) module->spec; - rc = pubkey->encrypt (algorithm, resarr, data, pkey, flags); - _gcry_module_release (module); - goto ready; - } - rc = GPG_ERR_PUBKEY_ALGO; - - ready: - ath_mutex_unlock (&pubkeys_registered_lock); - - if (!rc && DBG_CIPHER && !fips_mode ()) - { - for(i = 0; i < pubkey_get_nenc (algorithm); i++) - log_mpidump(" encr:", resarr[i] ); - } - return rc; -} - - -/**************** - * This is the interface to the public key decryption. - * ALGO gives the algorithm to use and this implicitly determines - * the size of the arrays. - * result is a pointer to a mpi variable which will receive a - * newly allocated mpi or NULL in case of an error. - */ -static gcry_err_code_t -pubkey_decrypt (int algorithm, gcry_mpi_t *result, gcry_mpi_t *data, - gcry_mpi_t *skey, int flags) -{ - gcry_pk_spec_t *pubkey; - gcry_module_t module; - gcry_err_code_t rc; - int i; - - *result = NULL; /* so the caller can always do a mpi_free */ - if (DBG_CIPHER && !fips_mode ()) - { - log_debug ("pubkey_decrypt: algo=%d\n", algorithm); - for(i = 0; i < pubkey_get_nskey (algorithm); i++) - log_mpidump (" skey:", skey[i]); - for(i = 0; i < pubkey_get_nenc (algorithm); i++) - log_mpidump (" data:", data[i]); - } - - ath_mutex_lock (&pubkeys_registered_lock); - module = _gcry_module_lookup_id (pubkeys_registered, algorithm); - if (module) - { - pubkey = (gcry_pk_spec_t *) module->spec; - rc = pubkey->decrypt (algorithm, result, data, skey, flags); - _gcry_module_release (module); - goto ready; - } - - rc = GPG_ERR_PUBKEY_ALGO; - - ready: - ath_mutex_unlock (&pubkeys_registered_lock); - - if (!rc && DBG_CIPHER && !fips_mode ()) - log_mpidump (" plain:", *result); - - return rc; -} - - -/**************** - * This is the interface to the public key signing. - * Sign data with skey and put the result into resarr which - * should be an array of MPIs of size PUBKEY_MAX_NSIG (or less if the - * algorithm allows this - check with pubkey_get_nsig() ) - */ -static gcry_err_code_t -pubkey_sign (int algorithm, gcry_mpi_t *resarr, gcry_mpi_t data, - gcry_mpi_t *skey) -{ - gcry_pk_spec_t *pubkey; - gcry_module_t module; - gcry_err_code_t rc; - int i; - - if (DBG_CIPHER && !fips_mode ()) - { - log_debug ("pubkey_sign: algo=%d\n", algorithm); - for(i = 0; i < pubkey_get_nskey (algorithm); i++) - log_mpidump (" skey:", skey[i]); - log_mpidump(" data:", data ); - } - - ath_mutex_lock (&pubkeys_registered_lock); - module = _gcry_module_lookup_id (pubkeys_registered, algorithm); - if (module) - { - pubkey = (gcry_pk_spec_t *) module->spec; - rc = pubkey->sign (algorithm, resarr, data, skey); - _gcry_module_release (module); - goto ready; - } - - rc = GPG_ERR_PUBKEY_ALGO; - - ready: - ath_mutex_unlock (&pubkeys_registered_lock); - - if (!rc && DBG_CIPHER && !fips_mode ()) - for (i = 0; i < pubkey_get_nsig (algorithm); i++) - log_mpidump (" sig:", resarr[i]); - - return rc; -} - -/**************** - * Verify a public key signature. - * Return 0 if the signature is good - */ -static gcry_err_code_t -pubkey_verify (int algorithm, gcry_mpi_t hash, gcry_mpi_t *data, - gcry_mpi_t *pkey, - int (*cmp)(void *, gcry_mpi_t), void *opaquev) -{ - gcry_pk_spec_t *pubkey; - gcry_module_t module; - gcry_err_code_t rc; - int i; - - if (DBG_CIPHER && !fips_mode ()) - { - log_debug ("pubkey_verify: algo=%d\n", algorithm); - for (i = 0; i < pubkey_get_npkey (algorithm); i++) - log_mpidump (" pkey:", pkey[i]); - for (i = 0; i < pubkey_get_nsig (algorithm); i++) - log_mpidump (" sig:", data[i]); - log_mpidump (" hash:", hash); - } - - ath_mutex_lock (&pubkeys_registered_lock); - module = _gcry_module_lookup_id (pubkeys_registered, algorithm); - if (module) - { - pubkey = (gcry_pk_spec_t *) module->spec; - rc = pubkey->verify (algorithm, hash, data, pkey, cmp, opaquev); - _gcry_module_release (module); - goto ready; - } - - rc = GPG_ERR_PUBKEY_ALGO; - - ready: - ath_mutex_unlock (&pubkeys_registered_lock); - return rc; -} - - -/* Internal function. */ -static gcry_err_code_t -sexp_elements_extract (gcry_sexp_t key_sexp, const char *element_names, - gcry_mpi_t *elements, const char *algo_name) -{ - gcry_err_code_t err = 0; - int i, idx; - const char *name; - gcry_sexp_t list; - - for (name = element_names, idx = 0; *name && !err; name++, idx++) - { - list = gcry_sexp_find_token (key_sexp, name, 1); - if (!list) - elements[idx] = NULL; - else - { - elements[idx] = gcry_sexp_nth_mpi (list, 1, GCRYMPI_FMT_USG); - gcry_sexp_release (list); - if (!elements[idx]) - err = GPG_ERR_INV_OBJ; - } - } - - if (!err) - { - /* Check that all elements are available. */ - for (name = element_names, idx = 0; *name; name++, idx++) - if (!elements[idx]) - break; - if (*name) - { - err = GPG_ERR_NO_OBJ; - /* Some are missing. Before bailing out we test for - optional parameters. */ - if (algo_name && !strcmp (algo_name, "RSA") - && !strcmp (element_names, "nedpqu") ) - { - /* This is RSA. Test whether we got N, E and D and that - the optional P, Q and U are all missing. */ - if (elements[0] && elements[1] && elements[2] - && !elements[3] && !elements[4] && !elements[5]) - err = 0; - } - } - } - - - if (err) - { - for (i = 0; i < idx; i++) - if (elements[i]) - gcry_free (elements[i]); - } - return err; -} - - -/* Internal function used for ecc. Note, that this function makes use - of its intimate knowledge about the ECC parameters from ecc.c. */ -static gcry_err_code_t -sexp_elements_extract_ecc (gcry_sexp_t key_sexp, const char *element_names, - gcry_mpi_t *elements, pk_extra_spec_t *extraspec) - -{ - gcry_err_code_t err = 0; - int idx; - const char *name; - gcry_sexp_t list; - - /* Clear the array for easier error cleanup. */ - for (name = element_names, idx = 0; *name; name++, idx++) - elements[idx] = NULL; - gcry_assert (idx >= 6); /* We know that ECC has at least 6 elements. */ - - /* Init the array with the available curve parameters. */ - for (name = element_names, idx = 0; *name && !err; name++, idx++) - { - list = gcry_sexp_find_token (key_sexp, name, 1); - if (!list) - elements[idx] = NULL; - else - { - elements[idx] = gcry_sexp_nth_mpi (list, 1, GCRYMPI_FMT_USG); - gcry_sexp_release (list); - if (!elements[idx]) - { - err = GPG_ERR_INV_OBJ; - goto leave; - } - } - } - - /* Check whether a curve parameter has been given and then fill any - missing elements. */ - list = gcry_sexp_find_token (key_sexp, "curve", 5); - if (list) - { - if (extraspec->get_param) - { - char *curve; - gcry_mpi_t params[6]; - - for (idx = 0; idx < DIM(params); idx++) - params[idx] = NULL; - - curve = _gcry_sexp_nth_string (list, 1); - gcry_sexp_release (list); - if (!curve) - { - /* No curve name given (or out of core). */ - err = GPG_ERR_INV_OBJ; - goto leave; - } - err = extraspec->get_param (curve, params); - gcry_free (curve); - if (err) - goto leave; - - for (idx = 0; idx < DIM(params); idx++) - { - if (!elements[idx]) - elements[idx] = params[idx]; - else - mpi_free (params[idx]); - } - } - else - { - gcry_sexp_release (list); - err = GPG_ERR_INV_OBJ; /* "curve" given but ECC not supported. */ - goto leave; - } - } - - /* Check that all parameters are known. */ - for (name = element_names, idx = 0; *name; name++, idx++) - if (!elements[idx]) - { - err = GPG_ERR_NO_OBJ; - goto leave; - } - - leave: - if (err) - { - for (name = element_names, idx = 0; *name; name++, idx++) - if (elements[idx]) - gcry_free (elements[idx]); - } - return err; -} - - - -/**************** - * Convert a S-Exp with either a private or a public key to our - * internal format. Currently we do only support the following - * algorithms: - * dsa - * rsa - * openpgp-dsa - * openpgp-rsa - * openpgp-elg - * openpgp-elg-sig - * ecdsa - * Provide a SE with the first element be either "private-key" or - * or "public-key". It is followed by a list with its first element - * be one of the above algorithm identifiers and the remaning - * elements are pairs with parameter-id and value. - * NOTE: we look through the list to find a list beginning with - * "private-key" or "public-key" - the first one found is used. - * - * Returns: A pointer to an allocated array of MPIs if the return value is - * zero; the caller has to release this array. - * - * Example of a DSA public key: - * (private-key - * (dsa - * (p <mpi>) - * (g <mpi>) - * (y <mpi>) - * (x <mpi>) - * ) - * ) - * The <mpi> are expected to be in GCRYMPI_FMT_USG - */ -static gcry_err_code_t -sexp_to_key (gcry_sexp_t sexp, int want_private, gcry_mpi_t **retarray, - gcry_module_t *retalgo) -{ - gcry_err_code_t err = 0; - gcry_sexp_t list, l2; - char *name; - const char *elems; - gcry_mpi_t *array; - gcry_module_t module; - gcry_pk_spec_t *pubkey; - pk_extra_spec_t *extraspec; - int is_ecc; - - /* Check that the first element is valid. */ - list = gcry_sexp_find_token (sexp, - want_private? "private-key":"public-key", 0); - if (!list) - return GPG_ERR_INV_OBJ; /* Does not contain a key object. */ - - l2 = gcry_sexp_cadr( list ); - gcry_sexp_release ( list ); - list = l2; - name = _gcry_sexp_nth_string (list, 0); - if (!name) - { - gcry_sexp_release ( list ); - return GPG_ERR_INV_OBJ; /* Invalid structure of object. */ - } - - ath_mutex_lock (&pubkeys_registered_lock); - module = gcry_pk_lookup_name (name); - ath_mutex_unlock (&pubkeys_registered_lock); - - /* Fixme: We should make sure that an ECC key is always named "ecc" - and not "ecdsa". "ecdsa" should be used for the signature - itself. We need a function to test whether an algorithm given - with a key is compatible with an application of the key (signing, - encryption). For RSA this is easy, but ECC is the first - algorithm which has many flavours. */ - is_ecc = ( !strcmp (name, "ecdsa") || !strcmp (name, "ecc") ); - gcry_free (name); - - if (!module) - { - gcry_sexp_release (list); - return GPG_ERR_PUBKEY_ALGO; /* Unknown algorithm. */ - } - else - { - pubkey = (gcry_pk_spec_t *) module->spec; - extraspec = module->extraspec; - } - - elems = want_private ? pubkey->elements_skey : pubkey->elements_pkey; - array = gcry_calloc (strlen (elems) + 1, sizeof (*array)); - if (!array) - err = gpg_err_code_from_errno (errno); - if (!err) - { - if (is_ecc) - err = sexp_elements_extract_ecc (list, elems, array, extraspec); - else - err = sexp_elements_extract (list, elems, array, pubkey->name); - } - - gcry_sexp_release (list); - - if (err) - { - gcry_free (array); - - ath_mutex_lock (&pubkeys_registered_lock); - _gcry_module_release (module); - ath_mutex_unlock (&pubkeys_registered_lock); - } - else - { - *retarray = array; - *retalgo = module; - } - - return err; -} - - -static gcry_err_code_t -sexp_to_sig (gcry_sexp_t sexp, gcry_mpi_t **retarray, - gcry_module_t *retalgo) -{ - gcry_err_code_t err = 0; - gcry_sexp_t list, l2; - char *name; - const char *elems; - gcry_mpi_t *array; - gcry_module_t module; - gcry_pk_spec_t *pubkey; - - /* Check that the first element is valid. */ - list = gcry_sexp_find_token( sexp, "sig-val" , 0 ); - if (!list) - return GPG_ERR_INV_OBJ; /* Does not contain a signature value object. */ - - l2 = gcry_sexp_nth (list, 1); - if (!l2) - { - gcry_sexp_release (list); - return GPG_ERR_NO_OBJ; /* No cadr for the sig object. */ - } - name = _gcry_sexp_nth_string (l2, 0); - if (!name) - { - gcry_sexp_release (list); - gcry_sexp_release (l2); - return GPG_ERR_INV_OBJ; /* Invalid structure of object. */ - } - else if (!strcmp (name, "flags")) - { - /* Skip flags, since they are not used but here just for the - sake of consistent S-expressions. */ - gcry_free (name); - gcry_sexp_release (l2); - l2 = gcry_sexp_nth (list, 2); - if (!l2) - { - gcry_sexp_release (list); - return GPG_ERR_INV_OBJ; - } - name = _gcry_sexp_nth_string (l2, 0); - } - - ath_mutex_lock (&pubkeys_registered_lock); - module = gcry_pk_lookup_name (name); - ath_mutex_unlock (&pubkeys_registered_lock); - gcry_free (name); - name = NULL; - - if (!module) - { - gcry_sexp_release (l2); - gcry_sexp_release (list); - return GPG_ERR_PUBKEY_ALGO; /* Unknown algorithm. */ - } - else - pubkey = (gcry_pk_spec_t *) module->spec; - - elems = pubkey->elements_sig; - array = gcry_calloc (strlen (elems) + 1 , sizeof *array ); - if (!array) - err = gpg_err_code_from_errno (errno); - - if (!err) - err = sexp_elements_extract (list, elems, array, NULL); - - gcry_sexp_release (l2); - gcry_sexp_release (list); - - if (err) - { - ath_mutex_lock (&pubkeys_registered_lock); - _gcry_module_release (module); - ath_mutex_unlock (&pubkeys_registered_lock); - - gcry_free (array); - } - else - { - *retarray = array; - *retalgo = module; - } - - return err; -} - - -/**************** - * Take sexp and return an array of MPI as used for our internal decrypt - * function. - * s_data = (enc-val - * [(flags [pkcs1])] - * (<algo> - * (<param_name1> <mpi>) - * ... - * (<param_namen> <mpi>) - * )) - * RET_MODERN is set to true when at least an empty flags list has been found. - */ -static gcry_err_code_t -sexp_to_enc (gcry_sexp_t sexp, gcry_mpi_t **retarray, gcry_module_t *retalgo, - int *ret_modern, int *ret_want_pkcs1, int *flags) -{ - gcry_err_code_t err = 0; - gcry_sexp_t list = NULL, l2 = NULL; - gcry_pk_spec_t *pubkey = NULL; - gcry_module_t module = NULL; - char *name = NULL; - size_t n; - int parsed_flags = 0; - const char *elems; - gcry_mpi_t *array = NULL; - - *ret_want_pkcs1 = 0; - *ret_modern = 0; - - /* Check that the first element is valid. */ - list = gcry_sexp_find_token (sexp, "enc-val" , 0); - if (!list) - { - err = GPG_ERR_INV_OBJ; /* Does not contain an encrypted value object. */ - goto leave; - } - - l2 = gcry_sexp_nth (list, 1); - if (!l2) - { - err = GPG_ERR_NO_OBJ; /* No cdr for the data object. */ - goto leave; - } - - /* Extract identifier of sublist. */ - name = _gcry_sexp_nth_string (l2, 0); - if (!name) - { - err = GPG_ERR_INV_OBJ; /* Invalid structure of object. */ - goto leave; - } - - if (!strcmp (name, "flags")) - { - /* There is a flags element - process it. */ - const char *s; - int i; - - *ret_modern = 1; - for (i = gcry_sexp_length (l2) - 1; i > 0; i--) - { - s = gcry_sexp_nth_data (l2, i, &n); - if (! s) - ; /* Not a data element - ignore. */ - else if (n == 3 && !memcmp (s, "raw", 3)) - ; /* This is just a dummy as it is the default. */ - else if (n == 5 && !memcmp (s, "pkcs1", 5)) - *ret_want_pkcs1 = 1; - else if (n == 11 && ! memcmp (s, "no-blinding", 11)) - parsed_flags |= PUBKEY_FLAG_NO_BLINDING; - else - { - err = GPG_ERR_INV_FLAG; - goto leave; - } - } - - /* Get the next which has the actual data. */ - gcry_sexp_release (l2); - l2 = gcry_sexp_nth (list, 2); - if (!l2) - { - err = GPG_ERR_NO_OBJ; /* No cdr for the data object. */ - goto leave; - } - - /* Extract sublist identifier. */ - gcry_free (name); - name = _gcry_sexp_nth_string (l2, 0); - if (!name) - { - err = GPG_ERR_INV_OBJ; /* Invalid structure of object. */ - goto leave; - } - - gcry_sexp_release (list); - list = l2; - l2 = NULL; - } - - ath_mutex_lock (&pubkeys_registered_lock); - module = gcry_pk_lookup_name (name); - ath_mutex_unlock (&pubkeys_registered_lock); - - if (!module) - { - err = GPG_ERR_PUBKEY_ALGO; /* Unknown algorithm. */ - goto leave; - } - pubkey = (gcry_pk_spec_t *) module->spec; - - elems = pubkey->elements_enc; - array = gcry_calloc (strlen (elems) + 1, sizeof (*array)); - if (!array) - { - err = gpg_err_code_from_errno (errno); - goto leave; - } - - err = sexp_elements_extract (list, elems, array, NULL); - - leave: - gcry_sexp_release (list); - gcry_sexp_release (l2); - gcry_free (name); - - if (err) - { - ath_mutex_lock (&pubkeys_registered_lock); - _gcry_module_release (module); - ath_mutex_unlock (&pubkeys_registered_lock); - gcry_free (array); - } - else - { - *retarray = array; - *retalgo = module; - *flags = parsed_flags; - } - - return err; -} - -/* Take the hash value and convert into an MPI, suitable for - passing to the low level functions. We currently support the - old style way of passing just a MPI and the modern interface which - allows to pass flags so that we can choose between raw and pkcs1 - padding - may be more padding options later. - - (<mpi>) - or - (data - [(flags [pkcs1])] - [(hash <algo> <value>)] - [(value <text>)] - ) - - Either the VALUE or the HASH element must be present for use - with signatures. VALUE is used for encryption. - - NBITS is the length of the key in bits. - -*/ -static gcry_err_code_t -sexp_data_to_mpi (gcry_sexp_t input, unsigned int nbits, gcry_mpi_t *ret_mpi, - int for_encryption, int *flags) -{ - gcry_err_code_t rc = 0; - gcry_sexp_t ldata, lhash, lvalue; - int i; - size_t n; - const char *s; - int is_raw = 0, is_pkcs1 = 0, unknown_flag=0; - int parsed_flags = 0, dummy_flags; - - if (! flags) - flags = &dummy_flags; - - *ret_mpi = NULL; - ldata = gcry_sexp_find_token (input, "data", 0); - if (!ldata) - { /* assume old style */ - *ret_mpi = gcry_sexp_nth_mpi (input, 0, 0); - return *ret_mpi ? GPG_ERR_NO_ERROR : GPG_ERR_INV_OBJ; - } - - /* see whether there is a flags object */ - { - gcry_sexp_t lflags = gcry_sexp_find_token (ldata, "flags", 0); - if (lflags) - { /* parse the flags list. */ - for (i=gcry_sexp_length (lflags)-1; i > 0; i--) - { - s = gcry_sexp_nth_data (lflags, i, &n); - if (!s) - ; /* not a data element*/ - else if ( n == 3 && !memcmp (s, "raw", 3)) - is_raw = 1; - else if ( n == 5 && !memcmp (s, "pkcs1", 5)) - is_pkcs1 = 1; - else if (n == 11 && ! memcmp (s, "no-blinding", 11)) - parsed_flags |= PUBKEY_FLAG_NO_BLINDING; - else - unknown_flag = 1; - } - gcry_sexp_release (lflags); - } - } - - if (!is_pkcs1 && !is_raw) - is_raw = 1; /* default to raw */ - - /* Get HASH or MPI */ - lhash = gcry_sexp_find_token (ldata, "hash", 0); - lvalue = lhash? NULL : gcry_sexp_find_token (ldata, "value", 0); - - if (!(!lhash ^ !lvalue)) - rc = GPG_ERR_INV_OBJ; /* none or both given */ - else if (unknown_flag) - rc = GPG_ERR_INV_FLAG; - else if (is_raw && is_pkcs1 && !for_encryption) - rc = GPG_ERR_CONFLICT; - else if (is_raw && lvalue) - { - *ret_mpi = gcry_sexp_nth_mpi (lvalue, 1, 0); - if (!*ret_mpi) - rc = GPG_ERR_INV_OBJ; - } - else if (is_pkcs1 && lvalue && for_encryption) - { - /* Create pkcs#1 block type 2 padding. */ - unsigned char *frame = NULL; - size_t nframe = (nbits+7) / 8; - const void * value; - size_t valuelen; - unsigned char *p; - - if ( !(value=gcry_sexp_nth_data (lvalue, 1, &valuelen)) || !valuelen ) - rc = GPG_ERR_INV_OBJ; - else if (valuelen + 7 > nframe || !nframe) - { - /* Can't encode a VALUELEN value in a NFRAME bytes frame. */ - rc = GPG_ERR_TOO_SHORT; /* the key is too short */ - } - else if ( !(frame = gcry_malloc_secure (nframe))) - rc = gpg_err_code_from_errno (errno); - else - { - n = 0; - frame[n++] = 0; - frame[n++] = 2; /* block type */ - i = nframe - 3 - valuelen; - gcry_assert (i > 0); - p = gcry_random_bytes_secure (i, GCRY_STRONG_RANDOM); - /* Replace zero bytes by new values. */ - for (;;) - { - int j, k; - unsigned char *pp; - - /* Count the zero bytes. */ - for (j=k=0; j < i; j++) - { - if (!p[j]) - k++; - } - if (!k) - break; /* Okay: no (more) zero bytes. */ - - k += k/128 + 3; /* Better get some more. */ - pp = gcry_random_bytes_secure (k, GCRY_STRONG_RANDOM); - for (j=0; j < i && k; ) - { - if (!p[j]) - p[j] = pp[--k]; - if (p[j]) - j++; - } - gcry_free (pp); - } - memcpy (frame+n, p, i); - n += i; - gcry_free (p); - - frame[n++] = 0; - memcpy (frame+n, value, valuelen); - n += valuelen; - gcry_assert (n == nframe); - - /* FIXME, error checking? */ - gcry_mpi_scan (ret_mpi, GCRYMPI_FMT_USG, frame, n, &nframe); - } - - gcry_free(frame); - } - else if (is_pkcs1 && lhash && !for_encryption) - { - /* Create pkcs#1 block type 1 padding. */ - if (gcry_sexp_length (lhash) != 3) - rc = GPG_ERR_INV_OBJ; - else if ( !(s=gcry_sexp_nth_data (lhash, 1, &n)) || !n ) - rc = GPG_ERR_INV_OBJ; - else - { - static struct { const char *name; int algo; } hashnames[] = - { { "sha1", GCRY_MD_SHA1 }, - { "md5", GCRY_MD_MD5 }, - { "sha256", GCRY_MD_SHA256 }, - { "ripemd160", GCRY_MD_RMD160 }, - { "rmd160", GCRY_MD_RMD160 }, - { "sha384", GCRY_MD_SHA384 }, - { "sha512", GCRY_MD_SHA512 }, - { "sha224", GCRY_MD_SHA224 }, - { "md2", GCRY_MD_MD2 }, - { "md4", GCRY_MD_MD4 }, - { "tiger", GCRY_MD_TIGER }, - { "haval", GCRY_MD_HAVAL }, - { NULL, 0 } - }; - int algo; - byte asn[100]; - byte *frame = NULL; - size_t nframe = (nbits+7) / 8; - const void * value; - size_t valuelen; - size_t asnlen, dlen; - - for (i=0; hashnames[i].name; i++) - { - if ( strlen (hashnames[i].name) == n - && !memcmp (hashnames[i].name, s, n)) - break; - } - if (hashnames[i].name) - algo = hashnames[i].algo; - else - { - /* In case of not listed or dynamically allocated hash - algorithm we fall back to this somewhat slower - method. Further, it also allows to use OIDs as - algorithm names. */ - char *tmpname; - - tmpname = gcry_malloc (n+1); - if (!tmpname) - algo = 0; /* Out of core - silently give up. */ - else - { - memcpy (tmpname, s, n); - tmpname[n] = 0; - algo = gcry_md_map_name (tmpname); - gcry_free (tmpname); - } - } - - asnlen = DIM(asn); - dlen = gcry_md_get_algo_dlen (algo); - - if (!algo) - rc = GPG_ERR_DIGEST_ALGO; - else if ( !(value=gcry_sexp_nth_data (lhash, 2, &valuelen)) - || !valuelen ) - rc = GPG_ERR_INV_OBJ; - else if (gcry_md_algo_info (algo, GCRYCTL_GET_ASNOID, asn, &asnlen)) - { - /* We don't have yet all of the above algorithms. */ - rc = GPG_ERR_NOT_IMPLEMENTED; - } - else if ( valuelen != dlen ) - { - /* Hash value does not match the length of digest for - the given algorithm. */ - rc = GPG_ERR_CONFLICT; - } - else if( !dlen || dlen + asnlen + 4 > nframe) - { - /* Can't encode an DLEN byte digest MD into a NFRAME - byte frame. */ - rc = GPG_ERR_TOO_SHORT; - } - else if ( !(frame = gcry_malloc (nframe)) ) - rc = gpg_err_code_from_errno (errno); - else - { /* Assemble the pkcs#1 block type 1. */ - n = 0; - frame[n++] = 0; - frame[n++] = 1; /* block type */ - i = nframe - valuelen - asnlen - 3 ; - gcry_assert (i > 1); - memset (frame+n, 0xff, i ); - n += i; - frame[n++] = 0; - memcpy (frame+n, asn, asnlen); - n += asnlen; - memcpy (frame+n, value, valuelen ); - n += valuelen; - gcry_assert (n == nframe); - - /* Convert it into an MPI. FIXME: error checking? */ - gcry_mpi_scan (ret_mpi, GCRYMPI_FMT_USG, frame, n, &nframe); - } - - gcry_free (frame); - } - } - else - rc = GPG_ERR_CONFLICT; - - gcry_sexp_release (ldata); - gcry_sexp_release (lhash); - gcry_sexp_release (lvalue); - - if (!rc) - *flags = parsed_flags; - - return rc; -} - - -/* - Do a PK encrypt operation - - Caller has to provide a public key as the SEXP pkey and data as a - SEXP with just one MPI in it. Alternativly S_DATA might be a - complex S-Expression, similar to the one used for signature - verification. This provides a flag which allows to handle PKCS#1 - block type 2 padding. The function returns a a sexp which may be - passed to to pk_decrypt. - - Returns: 0 or an errorcode. - - s_data = See comment for sexp_data_to_mpi - s_pkey = <key-as-defined-in-sexp_to_key> - r_ciph = (enc-val - (<algo> - (<param_name1> <mpi>) - ... - (<param_namen> <mpi>) - )) - -*/ -gcry_error_t -gcry_pk_encrypt (gcry_sexp_t *r_ciph, gcry_sexp_t s_data, gcry_sexp_t s_pkey) -{ - gcry_mpi_t *pkey = NULL, data = NULL, *ciph = NULL; - const char *algo_name, *algo_elems; - int flags; - gcry_err_code_t rc; - gcry_pk_spec_t *pubkey = NULL; - gcry_module_t module = NULL; - - *r_ciph = NULL; - - REGISTER_DEFAULT_PUBKEYS; - - /* Get the key. */ - rc = sexp_to_key (s_pkey, 0, &pkey, &module); - if (rc) - goto leave; - - gcry_assert (module); - pubkey = (gcry_pk_spec_t *) module->spec; - - /* If aliases for the algorithm name exists, take the first one - instead of the regular name to adhere to SPKI conventions. We - assume that the first alias name is the lowercase version of the - regular one. This change is required for compatibility with - 1.1.12 generated S-expressions. */ - algo_name = pubkey->aliases? *pubkey->aliases : NULL; - if (!algo_name || !*algo_name) - algo_name = pubkey->name; - - algo_elems = pubkey->elements_enc; - - /* Get the stuff we want to encrypt. */ - rc = sexp_data_to_mpi (s_data, gcry_pk_get_nbits (s_pkey), &data, 1, - &flags); - if (rc) - goto leave; - - /* Now we can encrypt DATA to CIPH. */ - ciph = gcry_calloc (strlen (algo_elems) + 1, sizeof (*ciph)); - if (!ciph) - { - rc = gpg_err_code_from_errno (errno); - goto leave; - } - rc = pubkey_encrypt (module->mod_id, ciph, data, pkey, flags); - mpi_free (data); - data = NULL; - if (rc) - goto leave; - - /* We did it. Now build the return list */ - { - char *string, *p; - int i; - size_t nelem = strlen (algo_elems); - size_t needed = 19 + strlen (algo_name) + (nelem * 5); - void **arg_list; - - /* Build the string. */ - string = p = gcry_malloc (needed); - if (!string) - { - rc = gpg_err_code_from_errno (errno); - goto leave; - } - p = stpcpy ( p, "(enc-val(" ); - p = stpcpy ( p, algo_name ); - for (i=0; algo_elems[i]; i++ ) - { - *p++ = '('; - *p++ = algo_elems[i]; - p = stpcpy ( p, "%m)" ); - } - strcpy ( p, "))" ); - - /* And now the ugly part: We don't have a function to pass an - * array to a format string, so we have to do it this way :-(. */ - /* FIXME: There is now such a format specifier, so we can - change the code to be more clear. */ - arg_list = malloc (nelem * sizeof *arg_list); - if (!arg_list) - { - rc = gpg_err_code_from_errno (errno); - goto leave; - } - - for (i = 0; i < nelem; i++) - arg_list[i] = ciph + i; - - rc = gcry_sexp_build_array (r_ciph, NULL, string, arg_list); - free (arg_list); - if (rc) - BUG (); - gcry_free (string); - } - - leave: - if (pkey) - { - release_mpi_array (pkey); - gcry_free (pkey); - } - - if (ciph) - { - release_mpi_array (ciph); - gcry_free (ciph); - } - - if (module) - { - ath_mutex_lock (&pubkeys_registered_lock); - _gcry_module_release (module); - ath_mutex_unlock (&pubkeys_registered_lock); - } - - return gcry_error (rc); -} - -/* - Do a PK decrypt operation - - Caller has to provide a secret key as the SEXP skey and data in a - format as created by gcry_pk_encrypt. For historic reasons the - function returns simply an MPI as an S-expression part; this is - deprecated and the new method should be used which returns a real - S-expressionl this is selected by adding at least an empty flags - list to S_DATA. - - Returns: 0 or an errorcode. - - s_data = (enc-val - [(flags)] - (<algo> - (<param_name1> <mpi>) - ... - (<param_namen> <mpi>) - )) - s_skey = <key-as-defined-in-sexp_to_key> - r_plain= Either an incomplete S-expression without the parentheses - or if the flags list is used (even if empty) a real S-expression: - (value PLAIN). - */ -gcry_error_t -gcry_pk_decrypt (gcry_sexp_t *r_plain, gcry_sexp_t s_data, gcry_sexp_t s_skey) -{ - gcry_mpi_t *skey = NULL, *data = NULL, plain = NULL; - int modern, want_pkcs1, flags; - gcry_err_code_t rc; - gcry_module_t module_enc = NULL, module_key = NULL; - gcry_pk_spec_t *pubkey = NULL; - - *r_plain = NULL; - - REGISTER_DEFAULT_PUBKEYS; - - rc = sexp_to_key (s_skey, 1, &skey, &module_key); - if (rc) - goto leave; - - rc = sexp_to_enc (s_data, &data, &module_enc, &modern, &want_pkcs1, &flags); - if (rc) - goto leave; - - if (module_key->mod_id != module_enc->mod_id) - { - rc = GPG_ERR_CONFLICT; /* Key algo does not match data algo. */ - goto leave; - } - - pubkey = (gcry_pk_spec_t *) module_key->spec; - - rc = pubkey_decrypt (module_key->mod_id, &plain, data, skey, flags); - if (rc) - goto leave; - - if (gcry_sexp_build (r_plain, NULL, modern? "(value %m)" : "%m", plain)) - BUG (); - - leave: - if (skey) - { - release_mpi_array (skey); - gcry_free (skey); - } - - if (plain) - mpi_free (plain); - - if (data) - { - release_mpi_array (data); - gcry_free (data); - } - - if (module_key || module_enc) - { - ath_mutex_lock (&pubkeys_registered_lock); - if (module_key) - _gcry_module_release (module_key); - if (module_enc) - _gcry_module_release (module_enc); - ath_mutex_unlock (&pubkeys_registered_lock); - } - - return gcry_error (rc); -} - - - -/* - Create a signature. - - Caller has to provide a secret key as the SEXP skey and data - expressed as a SEXP list hash with only one element which should - instantly be available as a MPI. Alternatively the structure given - below may be used for S_HASH, it provides the abiliy to pass flags - to the operation; the only flag defined by now is "pkcs1" which - does PKCS#1 block type 1 style padding. - - Returns: 0 or an errorcode. - In case of 0 the function returns a new SEXP with the - signature value; the structure of this signature depends on the - other arguments but is always suitable to be passed to - gcry_pk_verify - - s_hash = See comment for sexp_data_to_mpi - - s_skey = <key-as-defined-in-sexp_to_key> - r_sig = (sig-val - (<algo> - (<param_name1> <mpi>) - ... - (<param_namen> <mpi>)) - [(hash algo)]) - - Note that (hash algo) in R_SIG is not used. -*/ -gcry_error_t -gcry_pk_sign (gcry_sexp_t *r_sig, gcry_sexp_t s_hash, gcry_sexp_t s_skey) -{ - gcry_mpi_t *skey = NULL, hash = NULL, *result = NULL; - gcry_pk_spec_t *pubkey = NULL; - gcry_module_t module = NULL; - const char *algo_name, *algo_elems; - int i; - gcry_err_code_t rc; - - *r_sig = NULL; - - REGISTER_DEFAULT_PUBKEYS; - - rc = sexp_to_key (s_skey, 1, &skey, &module); - if (rc) - goto leave; - - gcry_assert (module); - pubkey = (gcry_pk_spec_t *) module->spec; - algo_name = pubkey->aliases? *pubkey->aliases : NULL; - if (!algo_name || !*algo_name) - algo_name = pubkey->name; - - algo_elems = pubkey->elements_sig; - - /* Get the stuff we want to sign. Note that pk_get_nbits does also - work on a private key. */ - rc = sexp_data_to_mpi (s_hash, gcry_pk_get_nbits (s_skey), - &hash, 0, NULL); - if (rc) - goto leave; - - result = gcry_calloc (strlen (algo_elems) + 1, sizeof (*result)); - if (!result) - { - rc = gpg_err_code_from_errno (errno); - goto leave; - } - rc = pubkey_sign (module->mod_id, result, hash, skey); - if (rc) - goto leave; - - { - char *string, *p; - size_t nelem, needed = strlen (algo_name) + 20; - void **arg_list; - - nelem = strlen (algo_elems); - - /* Count elements, so that we can allocate enough space. */ - needed += 10 * nelem; - - /* Build the string. */ - string = p = gcry_malloc (needed); - if (!string) - { - rc = gpg_err_code_from_errno (errno); - goto leave; - } - p = stpcpy (p, "(sig-val("); - p = stpcpy (p, algo_name); - for (i = 0; algo_elems[i]; i++) - { - *p++ = '('; - *p++ = algo_elems[i]; - p = stpcpy (p, "%m)"); - } - strcpy (p, "))"); - - arg_list = malloc (nelem * sizeof *arg_list); - if (!arg_list) - { - rc = gpg_err_code_from_errno (errno); - goto leave; - } - - for (i = 0; i < nelem; i++) - arg_list[i] = result + i; - - rc = gcry_sexp_build_array (r_sig, NULL, string, arg_list); - free (arg_list); - if (rc) - BUG (); - gcry_free (string); - } - - leave: - if (skey) - { - release_mpi_array (skey); - gcry_free (skey); - } - - if (hash) - mpi_free (hash); - - if (result) - { - release_mpi_array (result); - gcry_free (result); - } - - return gcry_error (rc); -} - - -/* - Verify a signature. - - Caller has to supply the public key pkey, the signature sig and his - hashvalue data. Public key has to be a standard public key given - as an S-Exp, sig is a S-Exp as returned from gcry_pk_sign and data - must be an S-Exp like the one in sign too. */ -gcry_error_t -gcry_pk_verify (gcry_sexp_t s_sig, gcry_sexp_t s_hash, gcry_sexp_t s_pkey) -{ - gcry_module_t module_key = NULL, module_sig = NULL; - gcry_mpi_t *pkey = NULL, hash = NULL, *sig = NULL; - gcry_err_code_t rc; - - REGISTER_DEFAULT_PUBKEYS; - - rc = sexp_to_key (s_pkey, 0, &pkey, &module_key); - if (rc) - goto leave; - - rc = sexp_to_sig (s_sig, &sig, &module_sig); - if (rc) - goto leave; - - /* Fixme: Check that the algorithm of S_SIG is compatible to the one - of S_PKEY. */ - - if (module_key->mod_id != module_sig->mod_id) - { - rc = GPG_ERR_CONFLICT; - goto leave; - } - - rc = sexp_data_to_mpi (s_hash, gcry_pk_get_nbits (s_pkey), &hash, 0, 0); - if (rc) - goto leave; - - rc = pubkey_verify (module_key->mod_id, hash, sig, pkey, NULL, NULL); - - leave: - if (pkey) - { - release_mpi_array (pkey); - gcry_free (pkey); - } - if (sig) - { - release_mpi_array (sig); - gcry_free (sig); - } - if (hash) - mpi_free (hash); - - if (module_key || module_sig) - { - ath_mutex_lock (&pubkeys_registered_lock); - if (module_key) - _gcry_module_release (module_key); - if (module_sig) - _gcry_module_release (module_sig); - ath_mutex_unlock (&pubkeys_registered_lock); - } - - return gcry_error (rc); -} - - -/* - Test a key. - - This may be used either for a public or a secret key to see whether - the internal structure is okay. - - Returns: 0 or an errorcode. - - s_key = <key-as-defined-in-sexp_to_key> */ -gcry_error_t -gcry_pk_testkey (gcry_sexp_t s_key) -{ - gcry_module_t module = NULL; - gcry_mpi_t *key = NULL; - gcry_err_code_t rc; - - REGISTER_DEFAULT_PUBKEYS; - - /* Note we currently support only secret key checking. */ - rc = sexp_to_key (s_key, 1, &key, &module); - if (! rc) - { - rc = pubkey_check_secret_key (module->mod_id, key); - release_mpi_array (key); - gcry_free (key); - } - return gcry_error (rc); -} - - -/* - Create a public key pair and return it in r_key. - How the key is created depends on s_parms: - (genkey - (algo - (parameter_name_1 ....) - .... - (parameter_name_n ....) - )) - The key is returned in a format depending on the - algorithm. Both, private and secret keys are returned - and optionally some additional informatin. - For elgamal we return this structure: - (key-data - (public-key - (elg - (p <mpi>) - (g <mpi>) - (y <mpi>) - ) - ) - (private-key - (elg - (p <mpi>) - (g <mpi>) - (y <mpi>) - (x <mpi>) - ) - ) - (misc-key-info - (pm1-factors n1 n2 ... nn) - )) - */ -gcry_error_t -gcry_pk_genkey (gcry_sexp_t *r_key, gcry_sexp_t s_parms) -{ - gcry_pk_spec_t *pubkey = NULL; - gcry_module_t module = NULL; - gcry_sexp_t list = NULL; - gcry_sexp_t l2 = NULL; - gcry_sexp_t l3 = NULL; - char *name = NULL; - size_t n; - gcry_err_code_t rc = GPG_ERR_NO_ERROR; - int i; - const char *algo_name = NULL; - int algo; - const char *sec_elems = NULL, *pub_elems = NULL; - gcry_mpi_t skey[12]; - gcry_mpi_t *factors = NULL; - gcry_sexp_t extrainfo = NULL; - unsigned int nbits = 0; - unsigned long use_e = 0; - - skey[0] = NULL; - *r_key = NULL; - - REGISTER_DEFAULT_PUBKEYS; - - list = gcry_sexp_find_token (s_parms, "genkey", 0); - if (!list) - { - rc = GPG_ERR_INV_OBJ; /* Does not contain genkey data. */ - goto leave; - } - - l2 = gcry_sexp_cadr (list); - gcry_sexp_release (list); - list = l2; - l2 = NULL; - if (! list) - { - rc = GPG_ERR_NO_OBJ; /* No cdr for the genkey. */ - goto leave; - } - - name = _gcry_sexp_nth_string (list, 0); - if (!name) - { - rc = GPG_ERR_INV_OBJ; /* Algo string missing. */ - goto leave; - } - - ath_mutex_lock (&pubkeys_registered_lock); - module = gcry_pk_lookup_name (name); - ath_mutex_unlock (&pubkeys_registered_lock); - gcry_free (name); - name = NULL; - if (!module) - { - rc = GPG_ERR_PUBKEY_ALGO; /* Unknown algorithm. */ - goto leave; - } - - pubkey = (gcry_pk_spec_t *) module->spec; - algo = module->mod_id; - algo_name = pubkey->aliases? *pubkey->aliases : NULL; - if (!algo_name || !*algo_name) - algo_name = pubkey->name; - pub_elems = pubkey->elements_pkey; - sec_elems = pubkey->elements_skey; - if (strlen (sec_elems) >= DIM(skey)) - BUG (); - - /* Handle the optional rsa-use-e element. Actually this belong into - the algorithm module but we have this parameter in the public - module API, so we need to parse it right here. */ - l2 = gcry_sexp_find_token (list, "rsa-use-e", 0); - if (l2) - { - char buf[50]; - const char *s; - - s = gcry_sexp_nth_data (l2, 1, &n); - if ( !s || n >= DIM (buf) - 1 ) - { - rc = GPG_ERR_INV_OBJ; /* No value or value too large. */ - goto leave; - } - memcpy (buf, s, n); - buf[n] = 0; - use_e = strtoul (buf, NULL, 0); - gcry_sexp_release (l2); - l2 = NULL; - } - else - use_e = 65537; /* Not given, use the value generated by old versions. */ - - - /* Get the "nbits" parameter. */ - l2 = gcry_sexp_find_token (list, "nbits", 0); - if (l2) - { - char buf[50]; - const char *s; - - s = gcry_sexp_nth_data (l2, 1, &n); - if (!s || n >= DIM (buf) - 1 ) - { - rc = GPG_ERR_INV_OBJ; /* NBITS given without a cdr. */ - goto leave; - } - memcpy (buf, s, n); - buf[n] = 0; - nbits = (unsigned int)strtoul (buf, NULL, 0); - gcry_sexp_release (l2); l2 = NULL; - } - else - nbits = 0; - - /* Pass control to the algorithm module. */ - rc = pubkey_generate (module->mod_id, nbits, use_e, list, skey, - &factors, &extrainfo); - gcry_sexp_release (list); list = NULL; - if (rc) - goto leave; - - /* Key generation succeeded: Build an S-expression. */ - { - char *string, *p; - size_t nelem=0, nelem_cp = 0, needed=0; - gcry_mpi_t mpis[30]; - - /* Estimate size of format string. */ - nelem = strlen (pub_elems) + strlen (sec_elems); - if (factors) - { - for (i = 0; factors[i]; i++) - nelem++; - } - nelem_cp = nelem; - - needed += nelem * 10; - /* (+5 is for EXTRAINFO ("%S")). */ - needed += 2 * strlen (algo_name) + 300 + 5; - if (nelem > DIM (mpis)) - BUG (); - - /* Build the string. */ - nelem = 0; - string = p = gcry_malloc (needed); - if (!string) - { - rc = gpg_err_code_from_errno (errno); - goto leave; - } - p = stpcpy (p, "(key-data"); - p = stpcpy (p, "(public-key("); - p = stpcpy (p, algo_name); - for(i = 0; pub_elems[i]; i++) - { - *p++ = '('; - *p++ = pub_elems[i]; - p = stpcpy (p, "%m)"); - mpis[nelem++] = skey[i]; - } - p = stpcpy (p, "))"); - p = stpcpy (p, "(private-key("); - p = stpcpy (p, algo_name); - for (i = 0; sec_elems[i]; i++) - { - *p++ = '('; - *p++ = sec_elems[i]; - p = stpcpy (p, "%m)"); - mpis[nelem++] = skey[i]; - } - p = stpcpy (p, "))"); - - /* Hack to make release_mpi_array() work. */ - skey[i] = NULL; - - if (extrainfo) - { - /* If we have extrainfo we should not have any factors. */ - p = stpcpy (p, "%S"); - } - else if (factors && factors[0]) - { - p = stpcpy (p, "(misc-key-info(pm1-factors"); - for(i = 0; factors[i]; i++) - { - p = stpcpy (p, "%m"); - mpis[nelem++] = factors[i]; - } - p = stpcpy (p, "))"); - } - strcpy (p, ")"); - gcry_assert (p - string < needed); - - while (nelem < DIM (mpis)) - mpis[nelem++] = NULL; - - { - int elem_n = strlen (pub_elems) + strlen (sec_elems); - void **arg_list; - - /* Allocate one extra for EXTRAINFO ("%S"). */ - arg_list = gcry_calloc (nelem_cp+1, sizeof *arg_list); - if (!arg_list) - { - rc = gpg_err_code_from_errno (errno); - goto leave; - } - for (i = 0; i < elem_n; i++) - arg_list[i] = mpis + i; - if (extrainfo) - arg_list[i] = &extrainfo; - else if (factors && factors[0]) - { - for (; i < nelem_cp; i++) - arg_list[i] = factors + i - elem_n; - } - - rc = gcry_sexp_build_array (r_key, NULL, string, arg_list); - gcry_free (arg_list); - if (rc) - BUG (); - gcry_assert (DIM (mpis) == 30); /* Reminder to make sure that - the array gets increased if - new parameters are added. */ - } - gcry_free (string); - } - - leave: - gcry_free (name); - gcry_sexp_release (extrainfo); - release_mpi_array (skey); - /* Don't free SKEY itself, it is an stack allocated array. */ - - if (factors) - { - release_mpi_array ( factors ); - gcry_free (factors); - } - - gcry_sexp_release (l3); - gcry_sexp_release (l2); - gcry_sexp_release (list); - - if (module) - { - ath_mutex_lock (&pubkeys_registered_lock); - _gcry_module_release (module); - ath_mutex_unlock (&pubkeys_registered_lock); - } - - return gcry_error (rc); -} - - -/* - Get the number of nbits from the public key. - - Hmmm: Should we have really this function or is it better to have a - more general function to retrieve different properties of the key? */ -unsigned int -gcry_pk_get_nbits (gcry_sexp_t key) -{ - gcry_module_t module = NULL; - gcry_pk_spec_t *pubkey; - gcry_mpi_t *keyarr = NULL; - unsigned int nbits = 0; - gcry_err_code_t rc; - - REGISTER_DEFAULT_PUBKEYS; - - rc = sexp_to_key (key, 0, &keyarr, &module); - if (rc == GPG_ERR_INV_OBJ) - rc = sexp_to_key (key, 1, &keyarr, &module); - if (rc) - return 0; /* Error - 0 is a suitable indication for that. */ - - pubkey = (gcry_pk_spec_t *) module->spec; - nbits = (*pubkey->get_nbits) (module->mod_id, keyarr); - - ath_mutex_lock (&pubkeys_registered_lock); - _gcry_module_release (module); - ath_mutex_unlock (&pubkeys_registered_lock); - - release_mpi_array (keyarr); - gcry_free (keyarr); - - return nbits; -} - - -/* Return the so called KEYGRIP which is the SHA-1 hash of the public - key parameters expressed in a way depended on the algorithm. - - ARRAY must either be 20 bytes long or NULL; in the latter case a - newly allocated array of that size is returned, otherwise ARRAY or - NULL is returned to indicate an error which is most likely an - unknown algorithm. The function accepts public or secret keys. */ -unsigned char * -gcry_pk_get_keygrip (gcry_sexp_t key, unsigned char *array) -{ - gcry_sexp_t list = NULL, l2 = NULL; - gcry_pk_spec_t *pubkey = NULL; - gcry_module_t module = NULL; - pk_extra_spec_t *extraspec; - const char *s; - char *name = NULL; - int idx; - const char *elems; - gcry_md_hd_t md = NULL; - - REGISTER_DEFAULT_PUBKEYS; - - /* Check that the first element is valid. */ - list = gcry_sexp_find_token (key, "public-key", 0); - if (! list) - list = gcry_sexp_find_token (key, "private-key", 0); - if (! list) - list = gcry_sexp_find_token (key, "protected-private-key", 0); - if (! list) - list = gcry_sexp_find_token (key, "shadowed-private-key", 0); - if (! list) - return NULL; /* No public- or private-key object. */ - - l2 = gcry_sexp_cadr (list); - gcry_sexp_release (list); - list = l2; - l2 = NULL; - - name = _gcry_sexp_nth_string (list, 0); - if (!name) - goto fail; /* Invalid structure of object. */ - - ath_mutex_lock (&pubkeys_registered_lock); - module = gcry_pk_lookup_name (name); - ath_mutex_unlock (&pubkeys_registered_lock); - - if (!module) - goto fail; /* Unknown algorithm. */ - - pubkey = (gcry_pk_spec_t *) module->spec; - extraspec = module->extraspec; - - elems = pubkey->elements_grip; - if (!elems) - goto fail; /* No grip parameter. */ - - if (gcry_md_open (&md, GCRY_MD_SHA1, 0)) - goto fail; - - if (extraspec && extraspec->comp_keygrip) - { - /* Module specific method to compute a keygrip. */ - if (extraspec->comp_keygrip (md, list)) - goto fail; - } - else - { - /* Generic method to compute a keygrip. */ - for (idx = 0, s = elems; *s; s++, idx++) - { - const char *data; - size_t datalen; - char buf[30]; - - l2 = gcry_sexp_find_token (list, s, 1); - if (! l2) - goto fail; - data = gcry_sexp_nth_data (l2, 1, &datalen); - if (! data) - goto fail; - - snprintf (buf, sizeof buf, "(1:%c%u:", *s, (unsigned int)datalen); - gcry_md_write (md, buf, strlen (buf)); - gcry_md_write (md, data, datalen); - gcry_sexp_release (l2); - gcry_md_write (md, ")", 1); - } - } - - if (!array) - { - array = gcry_malloc (20); - if (! array) - goto fail; - } - - memcpy (array, gcry_md_read (md, GCRY_MD_SHA1), 20); - gcry_md_close (md); - gcry_sexp_release (list); - return array; - - fail: - gcry_free (name); - gcry_sexp_release (l2); - gcry_md_close (md); - gcry_sexp_release (list); - return NULL; -} - - -gcry_error_t -gcry_pk_ctl (int cmd, void *buffer, size_t buflen) -{ - gcry_err_code_t err = GPG_ERR_NO_ERROR; - - REGISTER_DEFAULT_PUBKEYS; - - switch (cmd) - { - case GCRYCTL_DISABLE_ALGO: - /* This one expects a buffer pointing to an integer with the - algo number. */ - if ((! buffer) || (buflen != sizeof (int))) - err = GPG_ERR_INV_ARG; - else - disable_pubkey_algo (*((int *) buffer)); - break; - - default: - err = GPG_ERR_INV_OP; - } - - return gcry_error (err); -} - - -/* Return information about the given algorithm - - WHAT selects the kind of information returned: - - GCRYCTL_TEST_ALGO: - Returns 0 when the specified algorithm is available for use. - Buffer must be NULL, nbytes may have the address of a variable - with the required usage of the algorithm. It may be 0 for don't - care or a combination of the GCRY_PK_USAGE_xxx flags; - - GCRYCTL_GET_ALGO_USAGE: - Return the usage glafs for the give algo. An invalid alog - does return 0. Disabled algos are ignored here becuase we - only want to know whether the algo is at all capable of - the usage. - - Note: Because this function is in most cases used to return an - integer value, we can make it easier for the caller to just look at - the return value. The caller will in all cases consult the value - and thereby detecting whether a error occured or not (i.e. while - checking the block size) */ -gcry_error_t -gcry_pk_algo_info (int algorithm, int what, void *buffer, size_t *nbytes) -{ - gcry_err_code_t err = GPG_ERR_NO_ERROR; - - switch (what) - { - case GCRYCTL_TEST_ALGO: - { - int use = nbytes ? *nbytes : 0; - if (buffer) - err = GPG_ERR_INV_ARG; - else if (check_pubkey_algo (algorithm, use)) - err = GPG_ERR_PUBKEY_ALGO; - break; - } - - case GCRYCTL_GET_ALGO_USAGE: - { - gcry_module_t pubkey; - int use = 0; - - REGISTER_DEFAULT_PUBKEYS; - - ath_mutex_lock (&pubkeys_registered_lock); - pubkey = _gcry_module_lookup_id (pubkeys_registered, algorithm); - if (pubkey) - { - use = ((gcry_pk_spec_t *) pubkey->spec)->use; - _gcry_module_release (pubkey); - } - ath_mutex_unlock (&pubkeys_registered_lock); - - /* FIXME? */ - *nbytes = use; - - break; - } - - case GCRYCTL_GET_ALGO_NPKEY: - { - /* FIXME? */ - int npkey = pubkey_get_npkey (algorithm); - *nbytes = npkey; - break; - } - case GCRYCTL_GET_ALGO_NSKEY: - { - /* FIXME? */ - int nskey = pubkey_get_nskey (algorithm); - *nbytes = nskey; - break; - } - case GCRYCTL_GET_ALGO_NSIGN: - { - /* FIXME? */ - int nsign = pubkey_get_nsig (algorithm); - *nbytes = nsign; - break; - } - case GCRYCTL_GET_ALGO_NENCR: - { - /* FIXME? */ - int nencr = pubkey_get_nenc (algorithm); - *nbytes = nencr; - break; - } - - default: - err = GPG_ERR_INV_OP; - } - - return gcry_error (err); -} - - -/* Explicitly initialize this module. */ -gcry_err_code_t -_gcry_pk_init (void) -{ - gcry_err_code_t err = GPG_ERR_NO_ERROR; - - REGISTER_DEFAULT_PUBKEYS; - - return err; -} - - -gcry_err_code_t -_gcry_pk_module_lookup (int algorithm, gcry_module_t *module) -{ - gcry_err_code_t err = GPG_ERR_NO_ERROR; - gcry_module_t pubkey; - - REGISTER_DEFAULT_PUBKEYS; - - ath_mutex_lock (&pubkeys_registered_lock); - pubkey = _gcry_module_lookup_id (pubkeys_registered, algorithm); - if (pubkey) - *module = pubkey; - else - err = GPG_ERR_PUBKEY_ALGO; - ath_mutex_unlock (&pubkeys_registered_lock); - - return err; -} - - -void -_gcry_pk_module_release (gcry_module_t module) -{ - ath_mutex_lock (&pubkeys_registered_lock); - _gcry_module_release (module); - ath_mutex_unlock (&pubkeys_registered_lock); -} - -/* Get a list consisting of the IDs of the loaded pubkey modules. If - LIST is zero, write the number of loaded pubkey modules to - LIST_LENGTH and return. If LIST is non-zero, the first - *LIST_LENGTH algorithm IDs are stored in LIST, which must be of - according size. In case there are less pubkey modules than - *LIST_LENGTH, *LIST_LENGTH is updated to the correct number. */ -gcry_error_t -gcry_pk_list (int *list, int *list_length) -{ - gcry_err_code_t err = GPG_ERR_NO_ERROR; - - ath_mutex_lock (&pubkeys_registered_lock); - err = _gcry_module_list (pubkeys_registered, list, list_length); - ath_mutex_unlock (&pubkeys_registered_lock); - - return err; -} - - -/* Run the selftests for pubkey algorithm ALGO with optional reporting - function REPORT. */ -gpg_error_t -_gcry_pk_selftest (int algo, int extended, selftest_report_func_t report) -{ - gcry_module_t module = NULL; - pk_extra_spec_t *extraspec = NULL; - gcry_err_code_t ec = 0; - - REGISTER_DEFAULT_PUBKEYS; - - ath_mutex_lock (&pubkeys_registered_lock); - module = _gcry_module_lookup_id (pubkeys_registered, algo); - if (module && !(module->flags & FLAG_MODULE_DISABLED)) - extraspec = module->extraspec; - ath_mutex_unlock (&pubkeys_registered_lock); - if (extraspec && extraspec->selftest) - ec = extraspec->selftest (algo, extended, report); - else - { - ec = GPG_ERR_PUBKEY_ALGO; - if (report) - report ("pubkey", algo, "module", - module && !(module->flags & FLAG_MODULE_DISABLED)? - "no selftest available" : - module? "algorithm disabled" : "algorithm not found"); - } - - if (module) - { - ath_mutex_lock (&pubkeys_registered_lock); - _gcry_module_release (module); - ath_mutex_unlock (&pubkeys_registered_lock); - } - return gpg_error (ec); -} - - -/* This function is only used by ac.c! */ -gcry_err_code_t -_gcry_pk_get_elements (int algo, char **enc, char **sig) -{ - gcry_module_t pubkey; - gcry_pk_spec_t *spec; - gcry_err_code_t err; - char *enc_cp; - char *sig_cp; - - REGISTER_DEFAULT_PUBKEYS; - - enc_cp = NULL; - sig_cp = NULL; - spec = NULL; - - pubkey = _gcry_module_lookup_id (pubkeys_registered, algo); - if (! pubkey) - { - err = GPG_ERR_INTERNAL; - goto out; - } - spec = pubkey->spec; - - if (enc) - { - enc_cp = _strdup (spec->elements_enc); - if (! enc_cp) - { - err = gpg_err_code_from_errno (errno); - goto out; - } - } - - if (sig) - { - sig_cp = _strdup (spec->elements_sig); - if (! sig_cp) - { - err = gpg_err_code_from_errno (errno); - goto out; - } - } - - if (enc) - *enc = enc_cp; - if (sig) - *sig = sig_cp; - err = 0; - - out: - - _gcry_module_release (pubkey); - if (err) - { - free (enc_cp); - free (sig_cp); - } - - return err; -} |