mirror of
				https://git.proxmox.com/git/grub2
				synced 2025-10-31 03:50:11 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			4213 lines
		
	
	
		
			112 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			4213 lines
		
	
	
		
			112 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /* pubkey.c  -	pubkey dispatcher
 | ||
|  * Copyright (C) 1998, 1999, 2000, 2002, 2003, 2005,
 | ||
|  *               2007, 2008, 2011 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 },
 | ||
|     { &_gcry_pubkey_spec_ecdh,
 | ||
|       &_gcry_pubkey_extraspec_ecdsa, GCRY_PK_ECDH, 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 whether 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;
 | ||
| }
 | ||
| 
 | ||
| 
 | ||
| /* Turn VALUE into an octet string and store it in an allocated buffer
 | ||
|    at R_FRAME or - if R_RAME is NULL - copy it into the caller
 | ||
|    provided buffer SPACE; either SPACE or R_FRAME may be used.  If
 | ||
|    SPACE if not NULL, the caller must provide a buffer of at least
 | ||
|    NBYTES.  If the resulting octet string is shorter than NBYTES pad
 | ||
|    it to the left with zeroes.  If VALUE does not fit into NBYTES
 | ||
|    return an error code.  */
 | ||
| static gpg_err_code_t
 | ||
| octet_string_from_mpi (unsigned char **r_frame, void *space,
 | ||
|                        gcry_mpi_t value, size_t nbytes)
 | ||
| {
 | ||
|   gpg_err_code_t rc;
 | ||
|   size_t nframe, noff, n;
 | ||
|   unsigned char *frame;
 | ||
| 
 | ||
|   if (!r_frame == !space)
 | ||
|     return GPG_ERR_INV_ARG;  /* Only one may be used.  */
 | ||
| 
 | ||
|   if (r_frame)
 | ||
|     *r_frame = NULL;
 | ||
| 
 | ||
|   rc = gcry_err_code (gcry_mpi_print (GCRYMPI_FMT_USG,
 | ||
|                                       NULL, 0, &nframe, value));
 | ||
|   if (rc)
 | ||
|     return rc;
 | ||
|   if (nframe > nbytes)
 | ||
|     return GPG_ERR_TOO_LARGE; /* Value too long to fit into NBYTES.  */
 | ||
| 
 | ||
|   noff = (nframe < nbytes)? nbytes - nframe : 0;
 | ||
|   n = nframe + noff;
 | ||
|   if (space)
 | ||
|     frame = space;
 | ||
|   else
 | ||
|     {
 | ||
|       frame = mpi_is_secure (value)? gcry_malloc_secure (n) : gcry_malloc (n);
 | ||
|       if (!frame)
 | ||
|         {
 | ||
|           rc = gpg_err_code_from_syserror ();
 | ||
|           return rc;
 | ||
|         }
 | ||
|     }
 | ||
|   if (noff)
 | ||
|     memset (frame, 0, noff);
 | ||
|   nframe += noff;
 | ||
|   rc = gcry_err_code (gcry_mpi_print (GCRYMPI_FMT_USG,
 | ||
|                                       frame+noff, nframe-noff, NULL, value));
 | ||
|   if (rc)
 | ||
|     {
 | ||
|       gcry_free (frame);
 | ||
|       return rc;
 | ||
|     }
 | ||
| 
 | ||
|   if (r_frame)
 | ||
|     *r_frame = frame;
 | ||
|   return 0;
 | ||
| }
 | ||
| 
 | ||
| 
 | ||
| /* Encode {VALUE,VALUELEN} for an NBITS keys using the pkcs#1 block
 | ||
|    type 2 padding.  On sucess the result is stored as a new MPI at
 | ||
|    R_RESULT.  On error the value at R_RESULT is undefined.
 | ||
| 
 | ||
|    If {RANDOM_OVERRIDE, RANDOM_OVERRIDE_LEN} is given it is used as
 | ||
|    the seed instead of using a random string for it.  This feature is
 | ||
|    only useful for regression tests.  Note that this value may not
 | ||
|    contain zero bytes.
 | ||
| 
 | ||
|    We encode the value in this way:
 | ||
| 
 | ||
|      0  2  RND(n bytes)  0  VALUE
 | ||
| 
 | ||
|    0   is a marker we unfortunately can't encode because we return an
 | ||
|        MPI which strips all leading zeroes.
 | ||
|    2   is the block type.
 | ||
|    RND are non-zero random bytes.
 | ||
| 
 | ||
|    (Note that OpenPGP includes the cipher algorithm and a checksum in
 | ||
|    VALUE; the caller needs to prepare the value accordingly.)
 | ||
|   */
 | ||
| static gcry_err_code_t
 | ||
| pkcs1_encode_for_encryption (gcry_mpi_t *r_result, unsigned int nbits,
 | ||
| 			     const unsigned char *value, size_t valuelen,
 | ||
|                              const unsigned char *random_override,
 | ||
|                              size_t random_override_len)
 | ||
| {
 | ||
|   gcry_err_code_t rc = 0;
 | ||
|   gcry_error_t err;
 | ||
|   unsigned char *frame = NULL;
 | ||
|   size_t nframe = (nbits+7) / 8;
 | ||
|   int i;
 | ||
|   size_t n;
 | ||
|   unsigned char *p;
 | ||
| 
 | ||
|   if (valuelen + 7 > nframe || !nframe)
 | ||
|     {
 | ||
|       /* Can't encode a VALUELEN value in a NFRAME bytes frame.  */
 | ||
|       return GPG_ERR_TOO_SHORT; /* The key is too short.  */
 | ||
|     }
 | ||
| 
 | ||
|   if ( !(frame = gcry_malloc_secure (nframe)))
 | ||
|     return gpg_err_code_from_syserror ();
 | ||
| 
 | ||
|   n = 0;
 | ||
|   frame[n++] = 0;
 | ||
|   frame[n++] = 2; /* block type */
 | ||
|   i = nframe - 3 - valuelen;
 | ||
|   gcry_assert (i > 0);
 | ||
| 
 | ||
|   if (random_override)
 | ||
|     {
 | ||
|       int j;
 | ||
| 
 | ||
|       if (random_override_len != i)
 | ||
|         {
 | ||
|           gcry_free (frame);
 | ||
|           return GPG_ERR_INV_ARG;
 | ||
|         }
 | ||
|       /* Check that random does not include a zero byte.  */
 | ||
|       for (j=0; j < random_override_len; j++)
 | ||
|         if (!random_override[j])
 | ||
|           {
 | ||
|             gcry_free (frame);
 | ||
|             return GPG_ERR_INV_ARG;
 | ||
|           }
 | ||
|       memcpy (frame + n, random_override, random_override_len);
 | ||
|       n += random_override_len;
 | ||
|     }
 | ||
|   else
 | ||
|     {
 | ||
|       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);
 | ||
| 
 | ||
|   err = gcry_mpi_scan (r_result, GCRYMPI_FMT_USG, frame, n, &nframe);
 | ||
|   if (err)
 | ||
|     rc = gcry_err_code (err);
 | ||
|   else if (DBG_CIPHER)
 | ||
|     log_mpidump ("PKCS#1 block type 2 encoded data", *r_result);
 | ||
|   gcry_free (frame);
 | ||
| 
 | ||
|   return rc;
 | ||
| }
 | ||
| 
 | ||
| 
 | ||
| /* Decode a plaintext in VALUE assuming pkcs#1 block type 2 padding.
 | ||
|    NBITS is the size of the secret key.  On success the result is
 | ||
|    stored as a newly allocated buffer at R_RESULT and its valid length at
 | ||
|    R_RESULTLEN.  On error NULL is stored at R_RESULT.  */
 | ||
| static gcry_err_code_t
 | ||
| pkcs1_decode_for_encryption (unsigned char **r_result, size_t *r_resultlen,
 | ||
|                              unsigned int nbits, gcry_mpi_t value)
 | ||
| {
 | ||
|   gcry_error_t err;
 | ||
|   unsigned char *frame = NULL;
 | ||
|   size_t nframe = (nbits+7) / 8;
 | ||
|   size_t n;
 | ||
| 
 | ||
|   *r_result = NULL;
 | ||
| 
 | ||
|   if ( !(frame = gcry_malloc_secure (nframe)))
 | ||
|     return gpg_err_code_from_syserror ();
 | ||
| 
 | ||
|   err = gcry_mpi_print (GCRYMPI_FMT_USG, frame, nframe, &n, value);
 | ||
|   if (err)
 | ||
|     {
 | ||
|       gcry_free (frame);
 | ||
|       return gcry_err_code (err);
 | ||
|     }
 | ||
| 
 | ||
|   nframe = n; /* Set NFRAME to the actual length.  */
 | ||
| 
 | ||
|   /* FRAME = 0x00 || 0x02 || PS || 0x00 || M
 | ||
| 
 | ||
|      pkcs#1 requires that the first byte is zero.  Our MPIs usually
 | ||
|      strip leading zero bytes; thus we are not able to detect them.
 | ||
|      However due to the way gcry_mpi_print is implemented we may see
 | ||
|      leading zero bytes nevertheless.  We handle this by making the
 | ||
|      first zero byte optional.  */
 | ||
|   if (nframe < 4)
 | ||
|     {
 | ||
|       gcry_free (frame);
 | ||
|       return GPG_ERR_ENCODING_PROBLEM;  /* Too short.  */
 | ||
|     }
 | ||
|   n = 0;
 | ||
|   if (!frame[0])
 | ||
|     n++;
 | ||
|   if (frame[n++] != 0x02)
 | ||
|     {
 | ||
|       gcry_free (frame);
 | ||
|       return GPG_ERR_ENCODING_PROBLEM;  /* Wrong block type.  */
 | ||
|     }
 | ||
| 
 | ||
|   /* Skip the non-zero random bytes and the terminating zero byte.  */
 | ||
|   for (; n < nframe && frame[n] != 0x00; n++)
 | ||
|     ;
 | ||
|   if (n+1 >= nframe)
 | ||
|     {
 | ||
|       gcry_free (frame);
 | ||
|       return GPG_ERR_ENCODING_PROBLEM; /* No zero byte.  */
 | ||
|     }
 | ||
|   n++; /* Skip the zero byte.  */
 | ||
| 
 | ||
|   /* To avoid an extra allocation we reuse the frame buffer.  The only
 | ||
|      caller of this function will anyway free the result soon.  */
 | ||
|   memmove (frame, frame + n, nframe - n);
 | ||
|   *r_result = frame;
 | ||
|   *r_resultlen = nframe - n;
 | ||
| 
 | ||
|   if (DBG_CIPHER)
 | ||
|     log_printhex ("value extracted from PKCS#1 block type 2 encoded data:",
 | ||
|                   *r_result, *r_resultlen);
 | ||
| 
 | ||
|   return 0;
 | ||
| }
 | ||
| 
 | ||
| 
 | ||
| /* Encode {VALUE,VALUELEN} for an NBITS keys and hash algorith ALGO
 | ||
|    using the pkcs#1 block type 1 padding.  On success the result is
 | ||
|    stored as a new MPI at R_RESULT.  On error the value at R_RESULT is
 | ||
|    undefined.
 | ||
| 
 | ||
|    We encode the value in this way:
 | ||
| 
 | ||
|      0  1  PAD(n bytes)  0  ASN(asnlen bytes) VALUE(valuelen bytes)
 | ||
| 
 | ||
|    0   is a marker we unfortunately can't encode because we return an
 | ||
|        MPI which strips all leading zeroes.
 | ||
|    1   is the block type.
 | ||
|    PAD consists of 0xff bytes.
 | ||
|    0   marks the end of the padding.
 | ||
|    ASN is the DER encoding of the hash algorithm; along with the VALUE
 | ||
|        it yields a valid DER encoding.
 | ||
| 
 | ||
|    (Note that PGP prior to version 2.3 encoded the message digest as:
 | ||
|       0   1   MD(16 bytes)   0   PAD(n bytes)   1
 | ||
|     The MD is always 16 bytes here because it's always MD5.  GnuPG
 | ||
|     does not not support pre-v2.3 signatures, but I'm including this
 | ||
|     comment so the information is easily found if needed.)
 | ||
| */
 | ||
| static gcry_err_code_t
 | ||
| pkcs1_encode_for_signature (gcry_mpi_t *r_result, unsigned int nbits,
 | ||
| 			    const unsigned char *value, size_t valuelen,
 | ||
| 			    int algo)
 | ||
| {
 | ||
|   gcry_err_code_t rc = 0;
 | ||
|   gcry_error_t err;
 | ||
|   byte asn[100];
 | ||
|   byte *frame = NULL;
 | ||
|   size_t nframe = (nbits+7) / 8;
 | ||
|   int i;
 | ||
|   size_t n;
 | ||
|   size_t asnlen, dlen;
 | ||
| 
 | ||
|   asnlen = DIM(asn);
 | ||
|   dlen = gcry_md_get_algo_dlen (algo);
 | ||
| 
 | ||
|   if (gcry_md_algo_info (algo, GCRYCTL_GET_ASNOID, asn, &asnlen))
 | ||
|     {
 | ||
|       /* We don't have yet all of the above algorithms.  */
 | ||
|       return GPG_ERR_NOT_IMPLEMENTED;
 | ||
|     }
 | ||
| 
 | ||
|   if ( valuelen != dlen )
 | ||
|     {
 | ||
|       /* Hash value does not match the length of digest for
 | ||
|          the given algorithm.  */
 | ||
|       return GPG_ERR_CONFLICT;
 | ||
|     }
 | ||
| 
 | ||
|   if ( !dlen || dlen + asnlen + 4 > nframe)
 | ||
|     {
 | ||
|       /* Can't encode an DLEN byte digest MD into an NFRAME byte
 | ||
|          frame.  */
 | ||
|       return GPG_ERR_TOO_SHORT;
 | ||
|     }
 | ||
| 
 | ||
|   if ( !(frame = gcry_malloc (nframe)) )
 | ||
|     return gpg_err_code_from_syserror ();
 | ||
| 
 | ||
|   /* 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. */
 | ||
|   err = gcry_mpi_scan (r_result, GCRYMPI_FMT_USG, frame, n, &nframe);
 | ||
|   if (err)
 | ||
|     rc = gcry_err_code (err);
 | ||
|   else if (DBG_CIPHER)
 | ||
|     log_mpidump ("PKCS#1 block type 1 encoded data", *r_result);
 | ||
|   gcry_free (frame);
 | ||
| 
 | ||
|   return rc;
 | ||
| }
 | ||
| 
 | ||
| 
 | ||
| /* Mask generation function for OAEP.  See RFC-3447 B.2.1.  */
 | ||
| static gcry_err_code_t
 | ||
| mgf1 (unsigned char *output, size_t outlen, unsigned char *seed, size_t seedlen,
 | ||
|       int algo)
 | ||
| {
 | ||
|   size_t dlen, nbytes, n;
 | ||
|   int idx;
 | ||
|   gcry_md_hd_t hd;
 | ||
|   gcry_error_t err;
 | ||
| 
 | ||
|   err = gcry_md_open (&hd, algo, 0);
 | ||
|   if (err)
 | ||
|     return gpg_err_code (err);
 | ||
| 
 | ||
|   dlen = gcry_md_get_algo_dlen (algo);
 | ||
| 
 | ||
|   /* We skip step 1 which would be assert(OUTLEN <= 2^32).  The loop
 | ||
|      in step 3 is merged with step 4 by concatenating no more octets
 | ||
|      than what would fit into OUTPUT.  The ceiling for the counter IDX
 | ||
|      is implemented indirectly.  */
 | ||
|   nbytes = 0;  /* Step 2.  */
 | ||
|   idx = 0;
 | ||
|   while ( nbytes < outlen )
 | ||
|     {
 | ||
|       unsigned char c[4], *digest;
 | ||
| 
 | ||
|       if (idx)
 | ||
|         gcry_md_reset (hd);
 | ||
| 
 | ||
|       c[0] = (idx >> 24) & 0xFF;
 | ||
|       c[1] = (idx >> 16) & 0xFF;
 | ||
|       c[2] = (idx >> 8) & 0xFF;
 | ||
|       c[3] = idx & 0xFF;
 | ||
|       idx++;
 | ||
| 
 | ||
|       gcry_md_write (hd, seed, seedlen);
 | ||
|       gcry_md_write (hd, c, 4);
 | ||
|       digest = gcry_md_read (hd, 0);
 | ||
| 
 | ||
|       n = (outlen - nbytes < dlen)? (outlen - nbytes) : dlen;
 | ||
|       memcpy (output+nbytes, digest, n);
 | ||
|       nbytes += n;
 | ||
|     }
 | ||
| 
 | ||
|   gcry_md_close (hd);
 | ||
|   return GPG_ERR_NO_ERROR;
 | ||
| }
 | ||
| 
 | ||
| 
 | ||
| /* RFC-3447 (pkcs#1 v2.1) OAEP encoding.  NBITS is the length of the
 | ||
|    key measured in bits.  ALGO is the hash function; it must be a
 | ||
|    valid and usable algorithm.  {VALUE,VALUELEN} is the message to
 | ||
|    encrypt.  {LABEL,LABELLEN} is the optional label to be associated
 | ||
|    with the message, if LABEL is NULL the default is to use the empty
 | ||
|    string as label.  On success the encoded ciphertext is returned at
 | ||
|    R_RESULT.
 | ||
| 
 | ||
|    If {RANDOM_OVERRIDE, RANDOM_OVERRIDE_LEN} is given it is used as
 | ||
|    the seed instead of using a random string for it.  This feature is
 | ||
|    only useful for regression tests.
 | ||
| 
 | ||
|    Here is figure 1 from the RFC depicting the process:
 | ||
| 
 | ||
|                              +----------+---------+-------+
 | ||
|                         DB = |  lHash   |    PS   |   M   |
 | ||
|                              +----------+---------+-------+
 | ||
|                                             |
 | ||
|                   +----------+              V
 | ||
|                   |   seed   |--> MGF ---> xor
 | ||
|                   +----------+              |
 | ||
|                         |                   |
 | ||
|                +--+     V                   |
 | ||
|                |00|    xor <----- MGF <-----|
 | ||
|                +--+     |                   |
 | ||
|                  |      |                   |
 | ||
|                  V      V                   V
 | ||
|                +--+----------+----------------------------+
 | ||
|          EM =  |00|maskedSeed|          maskedDB          |
 | ||
|                +--+----------+----------------------------+
 | ||
|   */
 | ||
| static gcry_err_code_t
 | ||
| oaep_encode (gcry_mpi_t *r_result, unsigned int nbits, int algo,
 | ||
|              const unsigned char *value, size_t valuelen,
 | ||
|              const unsigned char *label, size_t labellen,
 | ||
|              const void *random_override, size_t random_override_len)
 | ||
| {
 | ||
|   gcry_err_code_t rc = 0;
 | ||
|   gcry_error_t err;
 | ||
|   unsigned char *frame = NULL;
 | ||
|   size_t nframe = (nbits+7) / 8;
 | ||
|   unsigned char *p;
 | ||
|   size_t hlen;
 | ||
|   size_t n;
 | ||
| 
 | ||
|   *r_result = NULL;
 | ||
| 
 | ||
|   /* Set defaults for LABEL.  */
 | ||
|   if (!label || !labellen)
 | ||
|     {
 | ||
|       label = (const unsigned char*)"";
 | ||
|       labellen = 0;
 | ||
|     }
 | ||
| 
 | ||
|   hlen = gcry_md_get_algo_dlen (algo);
 | ||
| 
 | ||
|   /* We skip step 1a which would be to check that LABELLEN is not
 | ||
|      greater than 2^61-1.  See rfc-3447 7.1.1. */
 | ||
| 
 | ||
|   /* Step 1b.  Note that the obsolete rfc-2437 uses the check:
 | ||
|      valuelen > nframe - 2 * hlen - 1 .  */
 | ||
|   if (valuelen > nframe - 2 * hlen - 2 || !nframe)
 | ||
|     {
 | ||
|       /* Can't encode a VALUELEN value in a NFRAME bytes frame. */
 | ||
|       return GPG_ERR_TOO_SHORT; /* The key is too short.  */
 | ||
|     }
 | ||
| 
 | ||
|   /* Allocate the frame.  */
 | ||
|   frame = gcry_calloc_secure (1, nframe);
 | ||
|   if (!frame)
 | ||
|     return gpg_err_code_from_syserror ();
 | ||
| 
 | ||
|   /* Step 2a: Compute the hash of the label.  We store it in the frame
 | ||
|      where later the maskedDB will commence.  */
 | ||
|   gcry_md_hash_buffer (algo, frame + 1 + hlen, label, labellen);
 | ||
| 
 | ||
|   /* Step 2b: Set octet string to zero.  */
 | ||
|   /* This has already been done while allocating FRAME.  */
 | ||
| 
 | ||
|   /* Step 2c: Create DB by concatenating lHash, PS, 0x01 and M.  */
 | ||
|   n = nframe - valuelen - 1;
 | ||
|   frame[n] = 0x01;
 | ||
|   memcpy (frame + n + 1, value, valuelen);
 | ||
| 
 | ||
|   /* Step 3d: Generate seed.  We store it where the maskedSeed will go
 | ||
|      later. */
 | ||
|   if (random_override)
 | ||
|     {
 | ||
|       if (random_override_len != hlen)
 | ||
|         {
 | ||
|           gcry_free (frame);
 | ||
|           return GPG_ERR_INV_ARG;
 | ||
|         }
 | ||
|       memcpy (frame + 1, random_override, hlen);
 | ||
|     }
 | ||
|   else
 | ||
|     gcry_randomize (frame + 1, hlen, GCRY_STRONG_RANDOM);
 | ||
| 
 | ||
|   /* Step 2e and 2f: Create maskedDB.  */
 | ||
|   {
 | ||
|     unsigned char *dmask;
 | ||
| 
 | ||
|     dmask = gcry_malloc_secure (nframe - hlen - 1);
 | ||
|     if (!dmask)
 | ||
|       {
 | ||
|         rc = gpg_err_code_from_syserror ();
 | ||
|         gcry_free (frame);
 | ||
|         return rc;
 | ||
|       }
 | ||
|     rc = mgf1 (dmask, nframe - hlen - 1, frame+1, hlen, algo);
 | ||
|     if (rc)
 | ||
|       {
 | ||
|         gcry_free (dmask);
 | ||
|         gcry_free (frame);
 | ||
|         return rc;
 | ||
|       }
 | ||
|     for (n = 1 + hlen, p = dmask; n < nframe; n++)
 | ||
|       frame[n] ^= *p++;
 | ||
|     gcry_free (dmask);
 | ||
|   }
 | ||
| 
 | ||
|   /* Step 2g and 2h: Create maskedSeed.  */
 | ||
|   {
 | ||
|     unsigned char *smask;
 | ||
| 
 | ||
|     smask = gcry_malloc_secure (hlen);
 | ||
|     if (!smask)
 | ||
|       {
 | ||
|         rc = gpg_err_code_from_syserror ();
 | ||
|         gcry_free (frame);
 | ||
|         return rc;
 | ||
|       }
 | ||
|     rc = mgf1 (smask, hlen, frame + 1 + hlen, nframe - hlen - 1, algo);
 | ||
|     if (rc)
 | ||
|       {
 | ||
|         gcry_free (smask);
 | ||
|         gcry_free (frame);
 | ||
|         return rc;
 | ||
|       }
 | ||
|     for (n = 1, p = smask; n < 1 + hlen; n++)
 | ||
|       frame[n] ^= *p++;
 | ||
|     gcry_free (smask);
 | ||
|   }
 | ||
| 
 | ||
|   /* Step 2i: Concatenate 0x00, maskedSeed and maskedDB.  */
 | ||
|   /* This has already been done by using in-place operations.  */
 | ||
| 
 | ||
|   /* Convert the stuff into an MPI as expected by the caller.  */
 | ||
|   err = gcry_mpi_scan (r_result, GCRYMPI_FMT_USG, frame, nframe, NULL);
 | ||
|   if (err)
 | ||
|     rc = gcry_err_code (err);
 | ||
|   else if (DBG_CIPHER)
 | ||
|     log_mpidump ("OAEP encoded data", *r_result);
 | ||
|   gcry_free (frame);
 | ||
| 
 | ||
|   return rc;
 | ||
| }
 | ||
| 
 | ||
| 
 | ||
| /* RFC-3447 (pkcs#1 v2.1) OAEP decoding.  NBITS is the length of the
 | ||
|    key measured in bits.  ALGO is the hash function; it must be a
 | ||
|    valid and usable algorithm.  VALUE is the raw decrypted message
 | ||
|    {LABEL,LABELLEN} is the optional label to be associated with the
 | ||
|    message, if LABEL is NULL the default is to use the empty string as
 | ||
|    label.  On success the plaintext is returned as a newly allocated
 | ||
|    buffer at R_RESULT; its valid length is stored at R_RESULTLEN.  On
 | ||
|    error NULL is stored at R_RESULT.  */
 | ||
| static gcry_err_code_t
 | ||
| oaep_decode (unsigned char **r_result, size_t *r_resultlen,
 | ||
|              unsigned int nbits, int algo,
 | ||
|              gcry_mpi_t value, const unsigned char *label, size_t labellen)
 | ||
| {
 | ||
|   gcry_err_code_t rc;
 | ||
|   unsigned char *frame = NULL; /* Encoded messages (EM).  */
 | ||
|   unsigned char *masked_seed;  /* Points into FRAME.  */
 | ||
|   unsigned char *masked_db;    /* Points into FRAME.  */
 | ||
|   unsigned char *seed = NULL;  /* Allocated space for the seed and DB.  */
 | ||
|   unsigned char *db;           /* Points into SEED.  */
 | ||
|   unsigned char *lhash = NULL; /* Hash of the label.  */
 | ||
|   size_t nframe;               /* Length of the ciphertext (EM).  */
 | ||
|   size_t hlen;                 /* Length of the hash digest.  */
 | ||
|   size_t db_len;               /* Length of DB and masked_db.  */
 | ||
|   size_t nkey = (nbits+7)/8;   /* Length of the key in bytes.  */
 | ||
|   int failed = 0;              /* Error indicator.  */
 | ||
|   size_t n;
 | ||
| 
 | ||
|   *r_result = NULL;
 | ||
| 
 | ||
|   /* This code is implemented as described by rfc-3447 7.1.2.  */
 | ||
| 
 | ||
|   /* Set defaults for LABEL.  */
 | ||
|   if (!label || !labellen)
 | ||
|     {
 | ||
|       label = (const unsigned char*)"";
 | ||
|       labellen = 0;
 | ||
|     }
 | ||
| 
 | ||
|   /* Get the length of the digest.  */
 | ||
|   hlen = gcry_md_get_algo_dlen (algo);
 | ||
| 
 | ||
|   /* Hash the label right away.  */
 | ||
|   lhash = gcry_malloc (hlen);
 | ||
|   if (!lhash)
 | ||
|     return gpg_err_code_from_syserror ();
 | ||
|   gcry_md_hash_buffer (algo, lhash, label, labellen);
 | ||
| 
 | ||
|   /* Turn the MPI into an octet string.  If the octet string is
 | ||
|      shorter than the key we pad it to the left with zeroes.  This may
 | ||
|      happen due to the leading zero in OAEP frames and due to the
 | ||
|      following random octets (seed^mask) which may have leading zero
 | ||
|      bytes.  This all is needed to cope with our leading zeroes
 | ||
|      suppressing MPI implementation.  The code implictly implements
 | ||
|      Step 1b (bail out if NFRAME != N).  */
 | ||
|   rc = octet_string_from_mpi (&frame, NULL, value, nkey);
 | ||
|   if (rc)
 | ||
|     {
 | ||
|       gcry_free (lhash);
 | ||
|       return GPG_ERR_ENCODING_PROBLEM;
 | ||
|     }
 | ||
|   nframe = nkey;
 | ||
| 
 | ||
|   /* Step 1c: Check that the key is long enough.  */
 | ||
|   if ( nframe < 2 * hlen + 2 )
 | ||
|     {
 | ||
|       gcry_free (frame);
 | ||
|       gcry_free (lhash);
 | ||
|       return GPG_ERR_ENCODING_PROBLEM;
 | ||
|     }
 | ||
| 
 | ||
|   /* Step 2 has already been done by the caller and the
 | ||
|      gcry_mpi_aprint above.  */
 | ||
| 
 | ||
|   /* Allocate space for SEED and DB.  */
 | ||
|   seed = gcry_malloc_secure (nframe - 1);
 | ||
|   if (!seed)
 | ||
|     {
 | ||
|       rc = gpg_err_code_from_syserror ();
 | ||
|       gcry_free (frame);
 | ||
|       gcry_free (lhash);
 | ||
|       return rc;
 | ||
|     }
 | ||
|   db = seed + hlen;
 | ||
| 
 | ||
|   /* To avoid choosen ciphertext attacks from now on we make sure to
 | ||
|      run all code even in the error case; this avoids possible timing
 | ||
|      attacks as described by Manger.  */
 | ||
| 
 | ||
|   /* Step 3a: Hash the label.  */
 | ||
|   /* This has already been done.  */
 | ||
| 
 | ||
|   /* Step 3b: Separate the encoded message.  */
 | ||
|   masked_seed = frame + 1;
 | ||
|   masked_db   = frame + 1 + hlen;
 | ||
|   db_len      = nframe - 1 - hlen;
 | ||
| 
 | ||
|   /* Step 3c and 3d: seed = maskedSeed ^ mgf(maskedDB, hlen).  */
 | ||
|   if (mgf1 (seed, hlen, masked_db, db_len, algo))
 | ||
|     failed = 1;
 | ||
|   for (n = 0; n < hlen; n++)
 | ||
|     seed[n] ^= masked_seed[n];
 | ||
| 
 | ||
|   /* Step 3e and 3f: db = maskedDB ^ mgf(seed, db_len).  */
 | ||
|   if (mgf1 (db, db_len, seed, hlen, algo))
 | ||
|     failed = 1;
 | ||
|   for (n = 0; n < db_len; n++)
 | ||
|     db[n] ^= masked_db[n];
 | ||
| 
 | ||
|   /* Step 3g: Check lhash, an possible empty padding string terminated
 | ||
|      by 0x01 and the first byte of EM being 0.  */
 | ||
|   if (memcmp (lhash, db, hlen))
 | ||
|     failed = 1;
 | ||
|   for (n = hlen; n < db_len; n++)
 | ||
|     if (db[n] == 0x01)
 | ||
|       break;
 | ||
|   if (n == db_len)
 | ||
|     failed = 1;
 | ||
|   if (frame[0])
 | ||
|     failed = 1;
 | ||
| 
 | ||
|   gcry_free (lhash);
 | ||
|   gcry_free (frame);
 | ||
|   if (failed)
 | ||
|     {
 | ||
|       gcry_free (seed);
 | ||
|       return GPG_ERR_ENCODING_PROBLEM;
 | ||
|     }
 | ||
| 
 | ||
|   /* Step 4: Output M.  */
 | ||
|   /* To avoid an extra allocation we reuse the seed buffer.  The only
 | ||
|      caller of this function will anyway free the result soon.  */
 | ||
|   n++;
 | ||
|   memmove (seed, db + n, db_len - n);
 | ||
|   *r_result = seed;
 | ||
|   *r_resultlen = db_len - n;
 | ||
|   seed = NULL;
 | ||
| 
 | ||
|   if (DBG_CIPHER)
 | ||
|     log_printhex ("value extracted from OAEP encoded data:",
 | ||
|                   *r_result, *r_resultlen);
 | ||
| 
 | ||
|   return 0;
 | ||
| }
 | ||
| 
 | ||
| 
 | ||
| /* RFC-3447 (pkcs#1 v2.1) PSS encoding.  Encode {VALUE,VALUELEN} for
 | ||
|    an NBITS key.  Note that VALUE is already the mHash from the
 | ||
|    picture below.  ALGO is a valid hash algorithm and SALTLEN is the
 | ||
|    length of salt to be used.  On success the result is stored as a
 | ||
|    new MPI at R_RESULT.  On error the value at R_RESULT is undefined.
 | ||
| 
 | ||
|    If {RANDOM_OVERRIDE, RANDOM_OVERRIDE_LEN} is given it is used as
 | ||
|    the salt instead of using a random string for the salt.  This
 | ||
|    feature is only useful for regression tests.
 | ||
| 
 | ||
|    Here is figure 2 from the RFC (errata 595 applied) depicting the
 | ||
|    process:
 | ||
| 
 | ||
|                                   +-----------+
 | ||
|                                   |     M     |
 | ||
|                                   +-----------+
 | ||
|                                         |
 | ||
|                                         V
 | ||
|                                       Hash
 | ||
|                                         |
 | ||
|                                         V
 | ||
|                           +--------+----------+----------+
 | ||
|                      M' = |Padding1|  mHash   |   salt   |
 | ||
|                           +--------+----------+----------+
 | ||
|                                          |
 | ||
|                +--------+----------+     V
 | ||
|          DB =  |Padding2| salt     |   Hash
 | ||
|                +--------+----------+     |
 | ||
|                          |               |
 | ||
|                          V               |    +----+
 | ||
|                         xor <--- MGF <---|    |0xbc|
 | ||
|                          |               |    +----+
 | ||
|                          |               |      |
 | ||
|                          V               V      V
 | ||
|                +-------------------+----------+----+
 | ||
|          EM =  |    maskedDB       |     H    |0xbc|
 | ||
|                +-------------------+----------+----+
 | ||
| 
 | ||
|   */
 | ||
| static gcry_err_code_t
 | ||
| pss_encode (gcry_mpi_t *r_result, unsigned int nbits, int algo,
 | ||
| 	    const unsigned char *value, size_t valuelen, int saltlen,
 | ||
|             const void *random_override, size_t random_override_len)
 | ||
| {
 | ||
|   gcry_err_code_t rc = 0;
 | ||
|   gcry_error_t err;
 | ||
|   size_t hlen;                 /* Length of the hash digest.  */
 | ||
|   unsigned char *em = NULL;    /* Encoded message.  */
 | ||
|   size_t emlen = (nbits+7)/8;  /* Length in bytes of EM.  */
 | ||
|   unsigned char *h;            /* Points into EM.  */
 | ||
|   unsigned char *buf = NULL;   /* Help buffer.  */
 | ||
|   size_t buflen;               /* Length of BUF.  */
 | ||
|   unsigned char *mhash;        /* Points into BUF.  */
 | ||
|   unsigned char *salt;         /* Points into BUF.  */
 | ||
|   unsigned char *dbmask;       /* Points into BUF.  */
 | ||
|   unsigned char *p;
 | ||
|   size_t n;
 | ||
| 
 | ||
|   /* This code is implemented as described by rfc-3447 9.1.1.  */
 | ||
| 
 | ||
|   /* Get the length of the digest.  */
 | ||
|   hlen = gcry_md_get_algo_dlen (algo);
 | ||
|   gcry_assert (hlen);  /* We expect a valid ALGO here.  */
 | ||
| 
 | ||
|   /* Allocate a help buffer and setup some pointers.  */
 | ||
|   buflen = 8 + hlen + saltlen + (emlen - hlen - 1);
 | ||
|   buf = gcry_malloc (buflen);
 | ||
|   if (!buf)
 | ||
|     {
 | ||
|       rc = gpg_err_code_from_syserror ();
 | ||
|       goto leave;
 | ||
|     }
 | ||
|   mhash = buf + 8;
 | ||
|   salt  = mhash + hlen;
 | ||
|   dbmask= salt + saltlen;
 | ||
| 
 | ||
|   /* Step 2: That would be: mHash = Hash(M) but our input is already
 | ||
|      mHash thus we do only a consistency check and copy to MHASH.  */
 | ||
|   if (valuelen != hlen)
 | ||
|     {
 | ||
|       rc = GPG_ERR_INV_LENGTH;
 | ||
|       goto leave;
 | ||
|     }
 | ||
|   memcpy (mhash, value, hlen);
 | ||
| 
 | ||
|   /* Step 3: Check length constraints.  */
 | ||
|   if (emlen < hlen + saltlen + 2)
 | ||
|     {
 | ||
|       rc = GPG_ERR_TOO_SHORT;
 | ||
|       goto leave;
 | ||
|     }
 | ||
| 
 | ||
|   /* Allocate space for EM.  */
 | ||
|   em = gcry_malloc (emlen);
 | ||
|   if (!em)
 | ||
|     {
 | ||
|       rc = gpg_err_code_from_syserror ();
 | ||
|       goto leave;
 | ||
|     }
 | ||
|   h = em + emlen - 1 - hlen;
 | ||
| 
 | ||
|   /* Step 4: Create a salt.  */
 | ||
|   if (saltlen)
 | ||
|     {
 | ||
|       if (random_override)
 | ||
|         {
 | ||
|           if (random_override_len != saltlen)
 | ||
|             {
 | ||
|               rc = GPG_ERR_INV_ARG;
 | ||
|               goto leave;
 | ||
|             }
 | ||
|           memcpy (salt, random_override, saltlen);
 | ||
|         }
 | ||
|       else
 | ||
|         gcry_randomize (salt, saltlen, GCRY_STRONG_RANDOM);
 | ||
|     }
 | ||
| 
 | ||
|   /* Step 5 and 6: M' = Hash(Padding1 || mHash || salt).  */
 | ||
|   memset (buf, 0, 8);  /* Padding.  */
 | ||
|   gcry_md_hash_buffer (algo, h, buf, 8 + hlen + saltlen);
 | ||
| 
 | ||
|   /* Step 7 and 8: DB = PS || 0x01 || salt.  */
 | ||
|   /* Note that we use EM to store DB and later Xor in-place.  */
 | ||
|   p = em + emlen - 1 - hlen - saltlen - 1;
 | ||
|   memset (em, 0, p - em);
 | ||
|   *p++ = 0x01;
 | ||
|   memcpy (p, salt, saltlen);
 | ||
| 
 | ||
|   /* Step 9: dbmask = MGF(H, emlen - hlen - 1).  */
 | ||
|   mgf1 (dbmask, emlen - hlen - 1, h, hlen, algo);
 | ||
| 
 | ||
|   /* Step 10: maskedDB = DB ^ dbMask */
 | ||
|   for (n = 0, p = dbmask; n < emlen - hlen - 1; n++, p++)
 | ||
|     em[n] ^= *p;
 | ||
| 
 | ||
|   /* Step 11: Set the leftmost bits to zero.  */
 | ||
|   em[0] &= 0xFF >> (8 * emlen - nbits);
 | ||
| 
 | ||
|   /* Step 12: EM = maskedDB || H || 0xbc.  */
 | ||
|   em[emlen-1] = 0xbc;
 | ||
| 
 | ||
|   /* Convert EM into an MPI.  */
 | ||
|   err = gcry_mpi_scan (r_result, GCRYMPI_FMT_USG, em, emlen, NULL);
 | ||
|   if (err)
 | ||
|     rc = gcry_err_code (err);
 | ||
|   else if (DBG_CIPHER)
 | ||
|     log_mpidump ("PSS encoded data", *r_result);
 | ||
| 
 | ||
|  leave:
 | ||
|   if (em)
 | ||
|     {
 | ||
|       wipememory (em, emlen);
 | ||
|       gcry_free (em);
 | ||
|     }
 | ||
|   if (buf)
 | ||
|     {
 | ||
|       wipememory (buf, buflen);
 | ||
|       gcry_free (buf);
 | ||
|     }
 | ||
|   return rc;
 | ||
| }
 | ||
| 
 | ||
| 
 | ||
| /* Verify a signature assuming PSS padding.  VALUE is the hash of the
 | ||
|    message (mHash) encoded as an MPI; its length must match the digest
 | ||
|    length of ALGO.  ENCODED is the output of the RSA public key
 | ||
|    function (EM).  NBITS is the size of the public key.  ALGO is the
 | ||
|    hash algorithm and SALTLEN is the length of the used salt.  The
 | ||
|    function returns 0 on success or on error code.  */
 | ||
| static gcry_err_code_t
 | ||
| pss_verify (gcry_mpi_t value, gcry_mpi_t encoded, unsigned int nbits, int algo,
 | ||
|             size_t saltlen)
 | ||
| {
 | ||
|   gcry_err_code_t rc = 0;
 | ||
|   size_t hlen;                 /* Length of the hash digest.  */
 | ||
|   unsigned char *em = NULL;    /* Encoded message.  */
 | ||
|   size_t emlen = (nbits+7)/8;  /* Length in bytes of EM.  */
 | ||
|   unsigned char *salt;         /* Points into EM.  */
 | ||
|   unsigned char *h;            /* Points into EM.  */
 | ||
|   unsigned char *buf = NULL;   /* Help buffer.  */
 | ||
|   size_t buflen;               /* Length of BUF.  */
 | ||
|   unsigned char *dbmask;       /* Points into BUF.  */
 | ||
|   unsigned char *mhash;        /* Points into BUF.  */
 | ||
|   unsigned char *p;
 | ||
|   size_t n;
 | ||
| 
 | ||
|   /* This code is implemented as described by rfc-3447 9.1.2.  */
 | ||
| 
 | ||
|   /* Get the length of the digest.  */
 | ||
|   hlen = gcry_md_get_algo_dlen (algo);
 | ||
|   gcry_assert (hlen);  /* We expect a valid ALGO here.  */
 | ||
| 
 | ||
|   /* Allocate a help buffer and setup some pointers.
 | ||
|      This buffer is used for two purposes:
 | ||
|         +------------------------------+-------+
 | ||
|      1. | dbmask                       | mHash |
 | ||
|         +------------------------------+-------+
 | ||
|            emlen - hlen - 1              hlen
 | ||
| 
 | ||
|         +----------+-------+---------+-+-------+
 | ||
|      2. | padding1 | mHash | salt    | | mHash |
 | ||
|         +----------+-------+---------+-+-------+
 | ||
|              8       hlen    saltlen     hlen
 | ||
|   */
 | ||
|   buflen = 8 + hlen + saltlen;
 | ||
|   if (buflen < emlen - hlen - 1)
 | ||
|     buflen = emlen - hlen - 1;
 | ||
|   buflen += hlen;
 | ||
|   buf = gcry_malloc (buflen);
 | ||
|   if (!buf)
 | ||
|     {
 | ||
|       rc = gpg_err_code_from_syserror ();
 | ||
|       goto leave;
 | ||
|     }
 | ||
|   dbmask = buf;
 | ||
|   mhash = buf + buflen - hlen;
 | ||
| 
 | ||
|   /* Step 2: That would be: mHash = Hash(M) but our input is already
 | ||
|      mHash thus we only need to convert VALUE into MHASH.  */
 | ||
|   rc = octet_string_from_mpi (NULL, mhash, value, hlen);
 | ||
|   if (rc)
 | ||
|     goto leave;
 | ||
| 
 | ||
|   /* Convert the signature into an octet string.  */
 | ||
|   rc = octet_string_from_mpi (&em, NULL, encoded, emlen);
 | ||
|   if (rc)
 | ||
|     goto leave;
 | ||
| 
 | ||
|   /* Step 3: Check length of EM.  Because we internally use MPI
 | ||
|      functions we can't do this properly; EMLEN is always the length
 | ||
|      of the key because octet_string_from_mpi needs to left pad the
 | ||
|      result with zero to cope with the fact that our MPIs suppress all
 | ||
|      leading zeroes.  Thus what we test here are merely the digest and
 | ||
|      salt lengths to the key.  */
 | ||
|   if (emlen < hlen + saltlen + 2)
 | ||
|     {
 | ||
|       rc = GPG_ERR_TOO_SHORT; /* For the hash and saltlen.  */
 | ||
|       goto leave;
 | ||
|     }
 | ||
| 
 | ||
|   /* Step 4: Check last octet.  */
 | ||
|   if (em[emlen - 1] != 0xbc)
 | ||
|     {
 | ||
|       rc = GPG_ERR_BAD_SIGNATURE;
 | ||
|       goto leave;
 | ||
|     }
 | ||
| 
 | ||
|   /* Step 5: Split EM.  */
 | ||
|   h = em + emlen - 1 - hlen;
 | ||
| 
 | ||
|   /* Step 6: Check the leftmost bits.  */
 | ||
|   if ((em[0] & ~(0xFF >> (8 * emlen - nbits))))
 | ||
|     {
 | ||
|       rc = GPG_ERR_BAD_SIGNATURE;
 | ||
|       goto leave;
 | ||
|     }
 | ||
| 
 | ||
|   /* Step 7: dbmask = MGF(H, emlen - hlen - 1).  */
 | ||
|   mgf1 (dbmask, emlen - hlen - 1, h, hlen, algo);
 | ||
| 
 | ||
|   /* Step 8: maskedDB = DB ^ dbMask.  */
 | ||
|   for (n = 0, p = dbmask; n < emlen - hlen - 1; n++, p++)
 | ||
|     em[n] ^= *p;
 | ||
| 
 | ||
|   /* Step 9: Set leftmost bits in DB to zero.  */
 | ||
|   em[0] &= 0xFF >> (8 * emlen - nbits);
 | ||
| 
 | ||
|   /* Step 10: Check the padding of DB.  */
 | ||
|   for (n = 0; n < emlen - hlen - saltlen - 2 && !em[n]; n++)
 | ||
|     ;
 | ||
|   if (n != emlen - hlen - saltlen - 2 || em[n++] != 1)
 | ||
|     {
 | ||
|       rc = GPG_ERR_BAD_SIGNATURE;
 | ||
|       goto leave;
 | ||
|     }
 | ||
| 
 | ||
|   /* Step 11: Extract salt from DB.  */
 | ||
|   salt = em + n;
 | ||
| 
 | ||
|   /* Step 12:  M' = (0x)00 00 00 00 00 00 00 00 || mHash || salt */
 | ||
|   memset (buf, 0, 8);
 | ||
|   memcpy (buf+8, mhash, hlen);
 | ||
|   memcpy (buf+8+hlen, salt, saltlen);
 | ||
| 
 | ||
|   /* Step 13:  H' = Hash(M').  */
 | ||
|   gcry_md_hash_buffer (algo, buf, buf, 8 + hlen + saltlen);
 | ||
| 
 | ||
|   /* Step 14:  Check H == H'.   */
 | ||
|   rc = memcmp (h, buf, hlen) ? GPG_ERR_BAD_SIGNATURE : GPG_ERR_NO_ERROR;
 | ||
| 
 | ||
|  leave:
 | ||
|   if (em)
 | ||
|     {
 | ||
|       wipememory (em, emlen);
 | ||
|       gcry_free (em);
 | ||
|     }
 | ||
|   if (buf)
 | ||
|     {
 | ||
|       wipememory (buf, buflen);
 | ||
|       gcry_free (buf);
 | ||
|     }
 | ||
|   return rc;
 | ||
| }
 | ||
| 
 | ||
| 
 | ||
| /* Callback for the pubkey algorithm code to verify PSS signatures.
 | ||
|    OPAQUE is the data provided by the actual caller.  The meaning of
 | ||
|    TMP depends on the actual algorithm (but there is only RSA); now
 | ||
|    for RSA it is the output of running the public key function on the
 | ||
|    input.  */
 | ||
| static int
 | ||
| pss_verify_cmp (void *opaque, gcry_mpi_t tmp)
 | ||
| {
 | ||
|   struct pk_encoding_ctx *ctx = opaque;
 | ||
|   gcry_mpi_t hash = ctx->verify_arg;
 | ||
| 
 | ||
|   return pss_verify (hash, tmp, ctx->nbits - 1, ctx->hash_algo, ctx->saltlen);
 | ||
| }
 | ||
| 
 | ||
| 
 | ||
| /* 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 >= 5); /* We know that ECC has at least 5 elements
 | ||
|                              (params only) or 6 (full public key).  */
 | ||
|   if (idx == 5)
 | ||
|     elements[5] = NULL;   /* Extra clear for the params only case.  */
 | ||
| 
 | ||
| 
 | ||
|   /* 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
 | ||
|  *    ecdh
 | ||
|  * 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.
 | ||
|  *
 | ||
|  * If OVERRIDE_ELEMS is not NULL those elems override the parameter
 | ||
|  * specification taken from the module.  This ise used by
 | ||
|  * gcry_pk_get_curve.
 | ||
|  *
 | ||
|  * 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, const char *override_elems,
 | ||
|              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, "ecdh")
 | ||
|              || !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;
 | ||
|     }
 | ||
| 
 | ||
|   if (override_elems)
 | ||
|     elems = override_elems;
 | ||
|   else if (want_private)
 | ||
|     elems = pubkey->elements_skey;
 | ||
|   else
 | ||
|     elems = pubkey->elements_pkey;
 | ||
|   array = gcry_calloc (strlen (elems) + 1, sizeof (*array));
 | ||
|   if (!array)
 | ||
|     err = gpg_err_code_from_syserror ();
 | ||
|   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_syserror ();
 | ||
| 
 | ||
|   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;
 | ||
| }
 | ||
| 
 | ||
| static inline int
 | ||
| get_hash_algo (const char *s, size_t n)
 | ||
| {
 | ||
|   static const 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;
 | ||
|   int i;
 | ||
| 
 | ||
|   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);
 | ||
| 	}
 | ||
|     }
 | ||
|   return algo;
 | ||
| }
 | ||
| 
 | ||
| 
 | ||
| /****************
 | ||
|  * Take sexp and return an array of MPI as used for our internal decrypt
 | ||
|  * function.
 | ||
|  * s_data = (enc-val
 | ||
|  *           [(flags [raw, pkcs1, oaep, no-blinding])]
 | ||
|  *           [(hash-algo <algo>)]
 | ||
|  *           [(label <label>)]
 | ||
|  *	      (<algo>
 | ||
|  *		(<param_name1> <mpi>)
 | ||
|  *		...
 | ||
|  *		(<param_namen> <mpi>)
 | ||
|  *	      ))
 | ||
|  * HASH-ALGO and LABEL are specific to OAEP.
 | ||
|  * RET_MODERN is set to true when at least an empty flags list has been found.
 | ||
|  * CTX is used to return encoding information; it may be NULL in which
 | ||
|  * case raw encoding is used.
 | ||
|  */
 | ||
| static gcry_err_code_t
 | ||
| sexp_to_enc (gcry_sexp_t sexp, gcry_mpi_t **retarray, gcry_module_t *retalgo,
 | ||
|              int *ret_modern, int *flags, struct pk_encoding_ctx *ctx)
 | ||
| {
 | ||
|   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_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)
 | ||
|                    && ctx->encoding == PUBKEY_ENC_UNKNOWN)
 | ||
|             ctx->encoding = PUBKEY_ENC_RAW;
 | ||
|           else if (n == 5 && !memcmp (s, "pkcs1", 5)
 | ||
|                    && ctx->encoding == PUBKEY_ENC_UNKNOWN)
 | ||
| 	    ctx->encoding = PUBKEY_ENC_PKCS1;
 | ||
|           else if (n == 4 && !memcmp (s, "oaep", 4)
 | ||
|                    && ctx->encoding == PUBKEY_ENC_UNKNOWN)
 | ||
| 	    ctx->encoding = PUBKEY_ENC_OAEP;
 | ||
|           else if (n == 3 && !memcmp (s, "pss", 3)
 | ||
|                    && ctx->encoding == PUBKEY_ENC_UNKNOWN)
 | ||
| 	    {
 | ||
| 	      err = GPG_ERR_CONFLICT;
 | ||
| 	      goto leave;
 | ||
| 	    }
 | ||
|           else if (n == 11 && ! memcmp (s, "no-blinding", 11))
 | ||
|             parsed_flags |= PUBKEY_FLAG_NO_BLINDING;
 | ||
|           else
 | ||
|             {
 | ||
|               err = GPG_ERR_INV_FLAG;
 | ||
|               goto leave;
 | ||
|             }
 | ||
|         }
 | ||
|       gcry_sexp_release (l2);
 | ||
| 
 | ||
|       /* Get the OAEP parameters HASH-ALGO and LABEL, if any. */
 | ||
|       if (ctx->encoding == PUBKEY_ENC_OAEP)
 | ||
| 	{
 | ||
| 	  /* Get HASH-ALGO. */
 | ||
| 	  l2 = gcry_sexp_find_token (list, "hash-algo", 0);
 | ||
| 	  if (l2)
 | ||
| 	    {
 | ||
| 	      s = gcry_sexp_nth_data (l2, 1, &n);
 | ||
| 	      if (!s)
 | ||
| 		err = GPG_ERR_NO_OBJ;
 | ||
| 	      else
 | ||
| 		{
 | ||
| 		  ctx->hash_algo = get_hash_algo (s, n);
 | ||
| 		  if (!ctx->hash_algo)
 | ||
| 		    err = GPG_ERR_DIGEST_ALGO;
 | ||
| 		}
 | ||
| 	      gcry_sexp_release (l2);
 | ||
| 	      if (err)
 | ||
| 		goto leave;
 | ||
| 	    }
 | ||
| 
 | ||
| 	  /* Get LABEL. */
 | ||
| 	  l2 = gcry_sexp_find_token (list, "label", 0);
 | ||
| 	  if (l2)
 | ||
| 	    {
 | ||
| 	      s = gcry_sexp_nth_data (l2, 1, &n);
 | ||
| 	      if (!s)
 | ||
| 		err = GPG_ERR_NO_OBJ;
 | ||
| 	      else if (n > 0)
 | ||
| 		{
 | ||
| 		  ctx->label = gcry_malloc (n);
 | ||
| 		  if (!ctx->label)
 | ||
| 		    err = gpg_err_code_from_syserror ();
 | ||
| 		  else
 | ||
| 		    {
 | ||
| 		      memcpy (ctx->label, s, n);
 | ||
| 		      ctx->labellen = n;
 | ||
| 		    }
 | ||
| 		}
 | ||
| 	      gcry_sexp_release (l2);
 | ||
| 	      if (err)
 | ||
| 		goto leave;
 | ||
| 	    }
 | ||
| 	}
 | ||
| 
 | ||
|       /* Get the next which has the actual data - skip HASH-ALGO and LABEL. */
 | ||
|       for (i = 2; (l2 = gcry_sexp_nth (list, i)) != NULL; i++)
 | ||
| 	{
 | ||
| 	  s = gcry_sexp_nth_data (l2, 0, &n);
 | ||
| 	  if (!(n == 9 && !memcmp (s, "hash-algo", 9))
 | ||
| 	      && !(n == 5 && !memcmp (s, "label", 5))
 | ||
| 	      && !(n == 15 && !memcmp (s, "random-override", 15)))
 | ||
| 	    break;
 | ||
| 	  gcry_sexp_release (l2);
 | ||
| 	}
 | ||
| 
 | ||
|       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_syserror ();
 | ||
|       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);
 | ||
|       gcry_free (ctx->label);
 | ||
|       ctx->label = NULL;
 | ||
|     }
 | ||
|   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 [raw, pkcs1, oaep, pss, no-blinding])]
 | ||
|     [(hash <algo> <value>)]
 | ||
|     [(value <text>)]
 | ||
|     [(hash-algo <algo>)]
 | ||
|     [(label <label>)]
 | ||
|     [(salt-length <length>)]
 | ||
|     [(random-override <data>)]
 | ||
|    )
 | ||
| 
 | ||
|    Either the VALUE or the HASH element must be present for use
 | ||
|    with signatures.  VALUE is used for encryption.
 | ||
| 
 | ||
|    HASH-ALGO and LABEL are specific to OAEP.
 | ||
| 
 | ||
|    SALT-LENGTH is for PSS.
 | ||
| 
 | ||
|    RANDOM-OVERRIDE is used to replace random nonces for regression
 | ||
|    testing.  */
 | ||
| static gcry_err_code_t
 | ||
| sexp_data_to_mpi (gcry_sexp_t input, gcry_mpi_t *ret_mpi,
 | ||
| 		  struct pk_encoding_ctx *ctx)
 | ||
| {
 | ||
|   gcry_err_code_t rc = 0;
 | ||
|   gcry_sexp_t ldata, lhash, lvalue;
 | ||
|   int i;
 | ||
|   size_t n;
 | ||
|   const char *s;
 | ||
|   int unknown_flag=0;
 | ||
|   int parsed_flags = 0;
 | ||
| 
 | ||
|   *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)
 | ||
|                       && ctx->encoding == PUBKEY_ENC_UNKNOWN)
 | ||
|               ctx->encoding = PUBKEY_ENC_RAW;
 | ||
|             else if ( n == 5 && !memcmp (s, "pkcs1", 5)
 | ||
|                       && ctx->encoding == PUBKEY_ENC_UNKNOWN)
 | ||
|               ctx->encoding = PUBKEY_ENC_PKCS1;
 | ||
|             else if ( n == 4 && !memcmp (s, "oaep", 4)
 | ||
|                       && ctx->encoding == PUBKEY_ENC_UNKNOWN)
 | ||
|               ctx->encoding = PUBKEY_ENC_OAEP;
 | ||
|             else if ( n == 3 && !memcmp (s, "pss", 3)
 | ||
|                       && ctx->encoding == PUBKEY_ENC_UNKNOWN)
 | ||
|               ctx->encoding = PUBKEY_ENC_PSS;
 | ||
| 	    else if (n == 11 && ! memcmp (s, "no-blinding", 11))
 | ||
| 	      parsed_flags |= PUBKEY_FLAG_NO_BLINDING;
 | ||
|             else
 | ||
|               unknown_flag = 1;
 | ||
|           }
 | ||
|         gcry_sexp_release (lflags);
 | ||
|       }
 | ||
|   }
 | ||
| 
 | ||
|   if (ctx->encoding == PUBKEY_ENC_UNKNOWN)
 | ||
|     ctx->encoding = PUBKEY_ENC_RAW; /* 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 (ctx->encoding == PUBKEY_ENC_RAW && lvalue)
 | ||
|     {
 | ||
|       *ret_mpi = gcry_sexp_nth_mpi (lvalue, 1, GCRYMPI_FMT_USG);
 | ||
|       if (!*ret_mpi)
 | ||
|         rc = GPG_ERR_INV_OBJ;
 | ||
|     }
 | ||
|   else if (ctx->encoding == PUBKEY_ENC_PKCS1 && lvalue
 | ||
| 	   && ctx->op == PUBKEY_OP_ENCRYPT)
 | ||
|     {
 | ||
|       const void * value;
 | ||
|       size_t valuelen;
 | ||
|       gcry_sexp_t list;
 | ||
|       void *random_override = NULL;
 | ||
|       size_t random_override_len = 0;
 | ||
| 
 | ||
|       if ( !(value=gcry_sexp_nth_data (lvalue, 1, &valuelen)) || !valuelen )
 | ||
|         rc = GPG_ERR_INV_OBJ;
 | ||
|       else
 | ||
|         {
 | ||
|           /* Get optional RANDOM-OVERRIDE.  */
 | ||
|           list = gcry_sexp_find_token (ldata, "random-override", 0);
 | ||
|           if (list)
 | ||
|             {
 | ||
|               s = gcry_sexp_nth_data (list, 1, &n);
 | ||
|               if (!s)
 | ||
|                 rc = GPG_ERR_NO_OBJ;
 | ||
|               else if (n > 0)
 | ||
|                 {
 | ||
|                   random_override = gcry_malloc (n);
 | ||
|                   if (!random_override)
 | ||
|                     rc = gpg_err_code_from_syserror ();
 | ||
|                   else
 | ||
|                     {
 | ||
|                       memcpy (random_override, s, n);
 | ||
|                       random_override_len = n;
 | ||
|                     }
 | ||
|                 }
 | ||
|               gcry_sexp_release (list);
 | ||
|               if (rc)
 | ||
|                 goto leave;
 | ||
|             }
 | ||
| 
 | ||
|           rc = pkcs1_encode_for_encryption (ret_mpi, ctx->nbits,
 | ||
|                                             value, valuelen,
 | ||
|                                             random_override,
 | ||
|                                             random_override_len);
 | ||
|           gcry_free (random_override);
 | ||
|         }
 | ||
|     }
 | ||
|   else if (ctx->encoding == PUBKEY_ENC_PKCS1 && lhash
 | ||
| 	   && (ctx->op == PUBKEY_OP_SIGN || ctx->op == PUBKEY_OP_VERIFY))
 | ||
|     {
 | ||
|       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
 | ||
|         {
 | ||
|           const void * value;
 | ||
|           size_t valuelen;
 | ||
| 
 | ||
| 	  ctx->hash_algo = get_hash_algo (s, n);
 | ||
| 
 | ||
|           if (!ctx->hash_algo)
 | ||
|             rc = GPG_ERR_DIGEST_ALGO;
 | ||
|           else if ( !(value=gcry_sexp_nth_data (lhash, 2, &valuelen))
 | ||
|                     || !valuelen )
 | ||
|             rc = GPG_ERR_INV_OBJ;
 | ||
|           else
 | ||
| 	    rc = pkcs1_encode_for_signature (ret_mpi, ctx->nbits,
 | ||
| 					     value, valuelen,
 | ||
| 					     ctx->hash_algo);
 | ||
|         }
 | ||
|     }
 | ||
|   else if (ctx->encoding == PUBKEY_ENC_OAEP && lvalue
 | ||
| 	   && ctx->op == PUBKEY_OP_ENCRYPT)
 | ||
|     {
 | ||
|       const void * value;
 | ||
|       size_t valuelen;
 | ||
| 
 | ||
|       if ( !(value=gcry_sexp_nth_data (lvalue, 1, &valuelen)) || !valuelen )
 | ||
| 	rc = GPG_ERR_INV_OBJ;
 | ||
|       else
 | ||
| 	{
 | ||
| 	  gcry_sexp_t list;
 | ||
|           void *random_override = NULL;
 | ||
|           size_t random_override_len = 0;
 | ||
| 
 | ||
| 	  /* Get HASH-ALGO. */
 | ||
| 	  list = gcry_sexp_find_token (ldata, "hash-algo", 0);
 | ||
| 	  if (list)
 | ||
| 	    {
 | ||
| 	      s = gcry_sexp_nth_data (list, 1, &n);
 | ||
| 	      if (!s)
 | ||
| 		rc = GPG_ERR_NO_OBJ;
 | ||
| 	      else
 | ||
| 		{
 | ||
| 		  ctx->hash_algo = get_hash_algo (s, n);
 | ||
| 		  if (!ctx->hash_algo)
 | ||
| 		    rc = GPG_ERR_DIGEST_ALGO;
 | ||
| 		}
 | ||
| 	      gcry_sexp_release (list);
 | ||
| 	      if (rc)
 | ||
| 		goto leave;
 | ||
| 	    }
 | ||
| 
 | ||
| 	  /* Get LABEL. */
 | ||
| 	  list = gcry_sexp_find_token (ldata, "label", 0);
 | ||
| 	  if (list)
 | ||
| 	    {
 | ||
| 	      s = gcry_sexp_nth_data (list, 1, &n);
 | ||
| 	      if (!s)
 | ||
| 		rc = GPG_ERR_NO_OBJ;
 | ||
| 	      else if (n > 0)
 | ||
| 		{
 | ||
| 		  ctx->label = gcry_malloc (n);
 | ||
| 		  if (!ctx->label)
 | ||
| 		    rc = gpg_err_code_from_syserror ();
 | ||
| 		  else
 | ||
| 		    {
 | ||
| 		      memcpy (ctx->label, s, n);
 | ||
| 		      ctx->labellen = n;
 | ||
| 		    }
 | ||
| 		}
 | ||
| 	      gcry_sexp_release (list);
 | ||
| 	      if (rc)
 | ||
| 		goto leave;
 | ||
| 	    }
 | ||
|           /* Get optional RANDOM-OVERRIDE.  */
 | ||
|           list = gcry_sexp_find_token (ldata, "random-override", 0);
 | ||
|           if (list)
 | ||
|             {
 | ||
|               s = gcry_sexp_nth_data (list, 1, &n);
 | ||
|               if (!s)
 | ||
|                 rc = GPG_ERR_NO_OBJ;
 | ||
|               else if (n > 0)
 | ||
|                 {
 | ||
|                   random_override = gcry_malloc (n);
 | ||
|                   if (!random_override)
 | ||
|                     rc = gpg_err_code_from_syserror ();
 | ||
|                   else
 | ||
|                     {
 | ||
|                       memcpy (random_override, s, n);
 | ||
|                       random_override_len = n;
 | ||
|                     }
 | ||
|                 }
 | ||
|               gcry_sexp_release (list);
 | ||
|               if (rc)
 | ||
|                 goto leave;
 | ||
|             }
 | ||
| 
 | ||
| 	  rc = oaep_encode (ret_mpi, ctx->nbits, ctx->hash_algo,
 | ||
| 			    value, valuelen,
 | ||
| 			    ctx->label, ctx->labellen,
 | ||
|                             random_override, random_override_len);
 | ||
| 
 | ||
|           gcry_free (random_override);
 | ||
| 	}
 | ||
|     }
 | ||
|   else if (ctx->encoding == PUBKEY_ENC_PSS && lhash
 | ||
| 	   && ctx->op == PUBKEY_OP_SIGN)
 | ||
|     {
 | ||
|       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
 | ||
|         {
 | ||
|           const void * value;
 | ||
|           size_t valuelen;
 | ||
|           void *random_override = NULL;
 | ||
|           size_t random_override_len = 0;
 | ||
| 
 | ||
| 	  ctx->hash_algo = get_hash_algo (s, n);
 | ||
| 
 | ||
|           if (!ctx->hash_algo)
 | ||
|             rc = GPG_ERR_DIGEST_ALGO;
 | ||
|           else if ( !(value=gcry_sexp_nth_data (lhash, 2, &valuelen))
 | ||
|                     || !valuelen )
 | ||
|             rc = GPG_ERR_INV_OBJ;
 | ||
|           else
 | ||
| 	    {
 | ||
| 	      gcry_sexp_t list;
 | ||
| 
 | ||
| 	      /* Get SALT-LENGTH. */
 | ||
| 	      list = gcry_sexp_find_token (ldata, "salt-length", 0);
 | ||
| 	      if (list)
 | ||
| 		{
 | ||
| 		  s = gcry_sexp_nth_data (list, 1, &n);
 | ||
| 		  if (!s)
 | ||
| 		    {
 | ||
| 		      rc = GPG_ERR_NO_OBJ;
 | ||
| 		      goto leave;
 | ||
| 		    }
 | ||
| 		  ctx->saltlen = (unsigned int)strtoul (s, NULL, 10);
 | ||
| 		  gcry_sexp_release (list);
 | ||
| 		}
 | ||
| 
 | ||
|               /* Get optional RANDOM-OVERRIDE.  */
 | ||
|               list = gcry_sexp_find_token (ldata, "random-override", 0);
 | ||
|               if (list)
 | ||
|                 {
 | ||
|                   s = gcry_sexp_nth_data (list, 1, &n);
 | ||
|                   if (!s)
 | ||
|                     rc = GPG_ERR_NO_OBJ;
 | ||
|                   else if (n > 0)
 | ||
|                     {
 | ||
|                       random_override = gcry_malloc (n);
 | ||
|                       if (!random_override)
 | ||
|                         rc = gpg_err_code_from_syserror ();
 | ||
|                       else
 | ||
|                         {
 | ||
|                           memcpy (random_override, s, n);
 | ||
|                           random_override_len = n;
 | ||
|                         }
 | ||
|                     }
 | ||
|                   gcry_sexp_release (list);
 | ||
|                   if (rc)
 | ||
|                     goto leave;
 | ||
|                 }
 | ||
| 
 | ||
|               /* Encode the data.  (NBITS-1 is due to 8.1.1, step 1.) */
 | ||
| 	      rc = pss_encode (ret_mpi, ctx->nbits - 1, ctx->hash_algo,
 | ||
| 			       value, valuelen, ctx->saltlen,
 | ||
|                                random_override, random_override_len);
 | ||
| 
 | ||
|               gcry_free (random_override);
 | ||
| 	    }
 | ||
|         }
 | ||
|     }
 | ||
|   else if (ctx->encoding == PUBKEY_ENC_PSS && lhash
 | ||
| 	   && ctx->op == PUBKEY_OP_VERIFY)
 | ||
|     {
 | ||
|       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
 | ||
|         {
 | ||
| 	  ctx->hash_algo = get_hash_algo (s, n);
 | ||
| 
 | ||
|           if (!ctx->hash_algo)
 | ||
|             rc = GPG_ERR_DIGEST_ALGO;
 | ||
| 	  else
 | ||
| 	    {
 | ||
| 	      *ret_mpi = gcry_sexp_nth_mpi (lhash, 2, GCRYMPI_FMT_USG);
 | ||
| 	      if (!*ret_mpi)
 | ||
| 		rc = GPG_ERR_INV_OBJ;
 | ||
| 	      ctx->verify_cmp = pss_verify_cmp;
 | ||
| 	      ctx->verify_arg = *ret_mpi;
 | ||
| 	    }
 | ||
| 	}
 | ||
|     }
 | ||
|   else
 | ||
|     rc = GPG_ERR_CONFLICT;
 | ||
| 
 | ||
|  leave:
 | ||
|   gcry_sexp_release (ldata);
 | ||
|   gcry_sexp_release (lhash);
 | ||
|   gcry_sexp_release (lvalue);
 | ||
| 
 | ||
|   if (!rc)
 | ||
|     ctx->flags = parsed_flags;
 | ||
|   else
 | ||
|     {
 | ||
|       gcry_free (ctx->label);
 | ||
|       ctx->label = NULL;
 | ||
|     }
 | ||
| 
 | ||
|   return rc;
 | ||
| }
 | ||
| 
 | ||
| static void
 | ||
| init_encoding_ctx (struct pk_encoding_ctx *ctx, enum pk_operation op,
 | ||
| 		   unsigned int nbits)
 | ||
| {
 | ||
|   ctx->op = op;
 | ||
|   ctx->nbits = nbits;
 | ||
|   ctx->encoding = PUBKEY_ENC_UNKNOWN;
 | ||
|   ctx->flags = 0;
 | ||
|   ctx->hash_algo = GCRY_MD_SHA1;
 | ||
|   ctx->label = NULL;
 | ||
|   ctx->labellen = 0;
 | ||
|   ctx->saltlen = 20;
 | ||
|   ctx->verify_cmp = NULL;
 | ||
|   ctx->verify_arg = NULL;
 | ||
| }
 | ||
| 
 | ||
| 
 | ||
| /*
 | ||
|    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. Alternatively 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 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;
 | ||
|   struct pk_encoding_ctx ctx;
 | ||
|   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, NULL, &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. */
 | ||
|   init_encoding_ctx (&ctx, PUBKEY_OP_ENCRYPT, gcry_pk_get_nbits (s_pkey));
 | ||
|   rc = sexp_data_to_mpi (s_data, &data, &ctx);
 | ||
|   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_syserror ();
 | ||
|       goto leave;
 | ||
|     }
 | ||
|   rc = pubkey_encrypt (module->mod_id, ciph, data, pkey, ctx.flags);
 | ||
|   mpi_free (data);
 | ||
|   data = NULL;
 | ||
|   if (rc)
 | ||
|     goto leave;
 | ||
| 
 | ||
|   /* We did it.  Now build the return list */
 | ||
|   if (ctx.encoding == PUBKEY_ENC_OAEP
 | ||
|       || ctx.encoding == PUBKEY_ENC_PKCS1)
 | ||
|     {
 | ||
|       /* We need to make sure to return the correct length to avoid
 | ||
|          problems with missing leading zeroes.  We know that this
 | ||
|          encoding does only make sense with RSA thus we don't need to
 | ||
|          build the S-expression on the fly.  */
 | ||
|       unsigned char *em;
 | ||
|       size_t emlen = (ctx.nbits+7)/8;
 | ||
| 
 | ||
|       rc = octet_string_from_mpi (&em, NULL, ciph[0], emlen);
 | ||
|       if (rc)
 | ||
|         goto leave;
 | ||
|       rc = gcry_err_code (gcry_sexp_build (r_ciph, NULL,
 | ||
|                                            "(enc-val(%s(a%b)))",
 | ||
|                                            algo_name, (int)emlen, em));
 | ||
|       gcry_free (em);
 | ||
|       if (rc)
 | ||
|         goto leave;
 | ||
|     }
 | ||
|   else
 | ||
|     {
 | ||
|       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_syserror ();
 | ||
|           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_syserror ();
 | ||
|           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);
 | ||
|     }
 | ||
| 
 | ||
|   gcry_free (ctx.label);
 | ||
| 
 | ||
|   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 [raw, pkcs1, oaep])]
 | ||
|               (<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).  In raw mode (or no flags given) the returned value
 | ||
|             is to be interpreted as a signed MPI, thus it may have an extra
 | ||
|             leading zero octet even if not included in the original data.
 | ||
|             With pkcs1 or oaep decoding enabled the returned value is a
 | ||
|             verbatim octet string.
 | ||
|  */
 | ||
| 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;
 | ||
|   unsigned char *unpad = NULL;
 | ||
|   size_t unpadlen = 0;
 | ||
|   int modern, flags;
 | ||
|   struct pk_encoding_ctx ctx;
 | ||
|   gcry_err_code_t rc;
 | ||
|   gcry_module_t module_enc = NULL, module_key = NULL;
 | ||
| 
 | ||
|   *r_plain = NULL;
 | ||
|   ctx.label = NULL;
 | ||
| 
 | ||
|   REGISTER_DEFAULT_PUBKEYS;
 | ||
| 
 | ||
|   rc = sexp_to_key (s_skey, 1, NULL, &skey, &module_key);
 | ||
|   if (rc)
 | ||
|     goto leave;
 | ||
| 
 | ||
|   init_encoding_ctx (&ctx, PUBKEY_OP_DECRYPT, gcry_pk_get_nbits (s_skey));
 | ||
|   rc = sexp_to_enc (s_data, &data, &module_enc, &modern, &flags, &ctx);
 | ||
|   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;
 | ||
|     }
 | ||
| 
 | ||
|   rc = pubkey_decrypt (module_key->mod_id, &plain, data, skey, flags);
 | ||
|   if (rc)
 | ||
|     goto leave;
 | ||
| 
 | ||
|   /* Do un-padding if necessary. */
 | ||
|   switch (ctx.encoding)
 | ||
|     {
 | ||
|     case PUBKEY_ENC_PKCS1:
 | ||
|       rc = pkcs1_decode_for_encryption (&unpad, &unpadlen,
 | ||
|                                         gcry_pk_get_nbits (s_skey), plain);
 | ||
|       mpi_free (plain);
 | ||
|       plain = NULL;
 | ||
|       if (!rc)
 | ||
|         rc = gcry_err_code (gcry_sexp_build (r_plain, NULL, "(value %b)",
 | ||
|                                              (int)unpadlen, unpad));
 | ||
|       break;
 | ||
| 
 | ||
|     case PUBKEY_ENC_OAEP:
 | ||
|       rc = oaep_decode (&unpad, &unpadlen,
 | ||
|                         gcry_pk_get_nbits (s_skey), ctx.hash_algo,
 | ||
| 			plain, ctx.label, ctx.labellen);
 | ||
|       mpi_free (plain);
 | ||
|       plain = NULL;
 | ||
|       if (!rc)
 | ||
|         rc = gcry_err_code (gcry_sexp_build (r_plain, NULL, "(value %b)",
 | ||
|                                              (int)unpadlen, unpad));
 | ||
|       break;
 | ||
| 
 | ||
|     default:
 | ||
|       /* Raw format.  For backward compatibility we need to assume a
 | ||
|          signed mpi by using the sexp format string "%m".  */
 | ||
|       rc = gcry_err_code (gcry_sexp_build
 | ||
|                           (r_plain, NULL, modern? "(value %m)" : "%m", plain));
 | ||
|       break;
 | ||
|     }
 | ||
| 
 | ||
|  leave:
 | ||
|   gcry_free (unpad);
 | ||
| 
 | ||
|   if (skey)
 | ||
|     {
 | ||
|       release_mpi_array (skey);
 | ||
|       gcry_free (skey);
 | ||
|     }
 | ||
| 
 | ||
|   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);
 | ||
|     }
 | ||
| 
 | ||
|   gcry_free (ctx.label);
 | ||
| 
 | ||
|   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 flags defined by now are "pkcs1" which does
 | ||
|    PKCS#1 block type 1 style padding and "pss" for PSS encoding.
 | ||
| 
 | ||
|    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;
 | ||
|   struct pk_encoding_ctx ctx;
 | ||
|   int i;
 | ||
|   gcry_err_code_t rc;
 | ||
| 
 | ||
|   *r_sig = NULL;
 | ||
| 
 | ||
|   REGISTER_DEFAULT_PUBKEYS;
 | ||
| 
 | ||
|   rc = sexp_to_key (s_skey, 1, NULL, &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. */
 | ||
|   init_encoding_ctx (&ctx, PUBKEY_OP_SIGN, gcry_pk_get_nbits (s_skey));
 | ||
|   rc = sexp_data_to_mpi (s_hash, &hash, &ctx);
 | ||
|   if (rc)
 | ||
|     goto leave;
 | ||
| 
 | ||
|   result = gcry_calloc (strlen (algo_elems) + 1, sizeof (*result));
 | ||
|   if (!result)
 | ||
|     {
 | ||
|       rc = gpg_err_code_from_syserror ();
 | ||
|       goto leave;
 | ||
|     }
 | ||
|   rc = pubkey_sign (module->mod_id, result, hash, skey);
 | ||
|   if (rc)
 | ||
|     goto leave;
 | ||
| 
 | ||
|   if (ctx.encoding == PUBKEY_ENC_PSS
 | ||
|       || ctx.encoding == PUBKEY_ENC_PKCS1)
 | ||
|     {
 | ||
|       /* We need to make sure to return the correct length to avoid
 | ||
|          problems with missing leading zeroes.  We know that this
 | ||
|          encoding does only make sense with RSA thus we don't need to
 | ||
|          build the S-expression on the fly.  */
 | ||
|       unsigned char *em;
 | ||
|       size_t emlen = (ctx.nbits+7)/8;
 | ||
| 
 | ||
|       rc = octet_string_from_mpi (&em, NULL, result[0], emlen);
 | ||
|       if (rc)
 | ||
|         goto leave;
 | ||
|       rc = gcry_err_code (gcry_sexp_build (r_sig, NULL,
 | ||
|                                            "(sig-val(%s(s%b)))",
 | ||
|                                            algo_name, (int)emlen, em));
 | ||
|       gcry_free (em);
 | ||
|       if (rc)
 | ||
|         goto leave;
 | ||
|     }
 | ||
|   else
 | ||
|     {
 | ||
|       /* General purpose output encoding.  Do it on the fly.  */
 | ||
|       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_syserror ();
 | ||
|           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_syserror ();
 | ||
|           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;
 | ||
|   struct pk_encoding_ctx ctx;
 | ||
|   gcry_err_code_t rc;
 | ||
| 
 | ||
|   REGISTER_DEFAULT_PUBKEYS;
 | ||
| 
 | ||
|   rc = sexp_to_key (s_pkey, 0, NULL, &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;
 | ||
|     }
 | ||
| 
 | ||
|   /* Get the stuff we want to verify. */
 | ||
|   init_encoding_ctx (&ctx, PUBKEY_OP_VERIFY, gcry_pk_get_nbits (s_pkey));
 | ||
|   rc = sexp_data_to_mpi (s_hash, &hash, &ctx);
 | ||
|   if (rc)
 | ||
|     goto leave;
 | ||
| 
 | ||
|   rc = pubkey_verify (module_key->mod_id, hash, sig, pkey,
 | ||
| 		      ctx.verify_cmp, &ctx);
 | ||
| 
 | ||
|  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, NULL, &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, j;
 | ||
|   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];
 | ||
|     int percent_s_idx = -1;
 | ||
| 
 | ||
|     /* 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_syserror ();
 | ||
|         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];
 | ||
|       }
 | ||
|     if (extrainfo && (algo == GCRY_PK_ECDSA || algo == GCRY_PK_ECDH))
 | ||
|       {
 | ||
|         /* Very ugly hack to insert the used curve parameter into the
 | ||
|            list of public key parameters.  */
 | ||
|         percent_s_idx = nelem;
 | ||
|         p = stpcpy (p, "%S");
 | ||
|       }
 | ||
|     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 && percent_s_idx == -1)
 | ||
|       {
 | ||
|         /* 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_syserror ();
 | ||
|           goto leave;
 | ||
|         }
 | ||
|       for (i = j = 0; i < elem_n; i++)
 | ||
|         {
 | ||
|           if (i == percent_s_idx)
 | ||
|             arg_list[j++] = &extrainfo;
 | ||
|           arg_list[j++] = mpis + i;
 | ||
|         }
 | ||
|       if (extrainfo && percent_s_idx == -1)
 | ||
|         arg_list[j] = &extrainfo;
 | ||
|       else if (factors && factors[0])
 | ||
|         {
 | ||
|           for (; i < nelem_cp; i++)
 | ||
|             arg_list[j++] = 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, NULL, &keyarr, &module);
 | ||
|   if (rc == GPG_ERR_INV_OBJ)
 | ||
|     rc = sexp_to_key (key, 1, NULL, &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 depending 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;
 | ||
|   int okay = 0;
 | ||
| 
 | ||
|   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);
 | ||
|           l2 = NULL;
 | ||
|           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);
 | ||
|   okay = 1;
 | ||
| 
 | ||
|  fail:
 | ||
|   gcry_free (name);
 | ||
|   gcry_sexp_release (l2);
 | ||
|   gcry_md_close (md);
 | ||
|   gcry_sexp_release (list);
 | ||
|   return okay? array : NULL;
 | ||
| }
 | ||
| 
 | ||
| 
 | ||
| 
 | ||
| const char *
 | ||
| gcry_pk_get_curve (gcry_sexp_t key, int iterator, unsigned int *r_nbits)
 | ||
| {
 | ||
|   gcry_mpi_t *pkey = NULL;
 | ||
|   gcry_sexp_t list = NULL;
 | ||
|   gcry_sexp_t l2;
 | ||
|   gcry_module_t module = NULL;
 | ||
|   pk_extra_spec_t *extraspec;
 | ||
|   char *name = NULL;
 | ||
|   const char *result = NULL;
 | ||
|   int want_private = 1;
 | ||
| 
 | ||
|   if (r_nbits)
 | ||
|     *r_nbits = 0;
 | ||
| 
 | ||
|   REGISTER_DEFAULT_PUBKEYS;
 | ||
| 
 | ||
|   if (key)
 | ||
|     {
 | ||
|       iterator = 0;
 | ||
| 
 | ||
|       /* Check that the first element is valid. */
 | ||
|       list = gcry_sexp_find_token (key, "public-key", 0);
 | ||
|       if (list)
 | ||
|         want_private = 0;
 | ||
|       if (!list)
 | ||
|         list = gcry_sexp_find_token (key, "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 leave; /* Invalid structure of object. */
 | ||
| 
 | ||
|       /* Get the key.  We pass the names of the parameters for
 | ||
|          override_elems; this allows to call this function without the
 | ||
|          actual public key parameter.  */
 | ||
|       if (sexp_to_key (key, want_private, "pabgn", &pkey, &module))
 | ||
|         goto leave;
 | ||
|     }
 | ||
|   else
 | ||
|     {
 | ||
|       ath_mutex_lock (&pubkeys_registered_lock);
 | ||
|       module = gcry_pk_lookup_name ("ecc");
 | ||
|       ath_mutex_unlock (&pubkeys_registered_lock);
 | ||
|       if (!module)
 | ||
|         goto leave;
 | ||
|     }
 | ||
| 
 | ||
|   extraspec = module->extraspec;
 | ||
|   if (!extraspec || !extraspec->get_curve)
 | ||
|     goto leave;
 | ||
| 
 | ||
|   result = extraspec->get_curve (pkey, iterator, r_nbits);
 | ||
| 
 | ||
|  leave:
 | ||
|   if (pkey)
 | ||
|     {
 | ||
|       release_mpi_array (pkey);
 | ||
|       gcry_free (pkey);
 | ||
|     }
 | ||
|   if (module)
 | ||
|     {
 | ||
|       ath_mutex_lock (&pubkeys_registered_lock);
 | ||
|       _gcry_module_release (module);
 | ||
|       ath_mutex_unlock (&pubkeys_registered_lock);
 | ||
|     }
 | ||
|   gcry_free (name);
 | ||
|   gcry_sexp_release (list);
 | ||
|   return result;
 | ||
| }
 | ||
| 
 | ||
| 
 | ||
| 
 | ||
| gcry_sexp_t
 | ||
| gcry_pk_get_param (int algo, const char *name)
 | ||
| {
 | ||
|   gcry_module_t module = NULL;
 | ||
|   pk_extra_spec_t *extraspec;
 | ||
|   gcry_sexp_t result = NULL;
 | ||
| 
 | ||
|   if (algo != GCRY_PK_ECDSA && algo != GCRY_PK_ECDH)
 | ||
|     return NULL;
 | ||
| 
 | ||
|   REGISTER_DEFAULT_PUBKEYS;
 | ||
| 
 | ||
|   ath_mutex_lock (&pubkeys_registered_lock);
 | ||
|   module = gcry_pk_lookup_name ("ecc");
 | ||
|   ath_mutex_unlock (&pubkeys_registered_lock);
 | ||
|   if (module)
 | ||
|     {
 | ||
|       extraspec = module->extraspec;
 | ||
|       if (extraspec && extraspec->get_curve_param)
 | ||
|         result = extraspec->get_curve_param (name);
 | ||
| 
 | ||
|       ath_mutex_lock (&pubkeys_registered_lock);
 | ||
|       _gcry_module_release (module);
 | ||
|       ath_mutex_unlock (&pubkeys_registered_lock);
 | ||
|     }
 | ||
|   return result;
 | ||
| }
 | ||
| 
 | ||
| 
 | ||
| 
 | ||
| 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 flags for the given algo.  An invalid algo
 | ||
|         returns 0.  Disabled algos are ignored here because 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 occurred 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_syserror ();
 | ||
| 	  goto out;
 | ||
| 	}
 | ||
|     }
 | ||
| 
 | ||
|   if (sig)
 | ||
|     {
 | ||
|       sig_cp = strdup (spec->elements_sig);
 | ||
|       if (! sig_cp)
 | ||
| 	{
 | ||
| 	  err = gpg_err_code_from_syserror ();
 | ||
| 	  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;
 | ||
| }
 | 
