Add crypto hash SM3.
[libgcrypt.git] / cipher / pubkey.c
index aabcf94..8ec15fd 100644 (file)
@@ -1,6 +1,7 @@
 /* pubkey.c  - pubkey dispatcher
- * Copyright (C) 1998, 1999, 2000, 2002, 2003, 2005, 
- *               2007, 2008 Free Software Foundation, Inc.
+ * Copyright (C) 1998, 1999, 2000, 2002, 2003, 2005,
+ *               2007, 2008, 2011 Free Software Foundation, Inc.
+ * Copyright (C) 2013 g10 Code GmbH
  *
  * This file is part of Libgcrypt.
  *
 #include "g10lib.h"
 #include "mpi.h"
 #include "cipher.h"
-#include "ath.h"
+#include "context.h"
+#include "pubkey-internal.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[] =
+/* This is the list of the public-key algorithms included in
+   Libgcrypt.  */
+static gcry_pk_spec_t *pubkey_list[] =
   {
-#if USE_RSA
-    { &_gcry_pubkey_spec_rsa,
-      &_gcry_pubkey_extraspec_rsa,   GCRY_PK_RSA, 1},
+#if USE_ECC
+    &_gcry_pubkey_spec_ecc,
 #endif
-#if USE_ELGAMAL
-    { &_gcry_pubkey_spec_elg,
-      &dummy_extra_spec,             GCRY_PK_ELG   },
-    { &_gcry_pubkey_spec_elg,
-      &dummy_extra_spec,             GCRY_PK_ELG_E },
+#if USE_RSA
+    &_gcry_pubkey_spec_rsa,
 #endif
 #if USE_DSA
-    { &_gcry_pubkey_spec_dsa,
-      &_gcry_pubkey_extraspec_dsa,   GCRY_PK_DSA, 1   },
+    &_gcry_pubkey_spec_dsa,
 #endif
-#if USE_ECC
-    { &_gcry_pubkey_spec_ecdsa,
-      &_gcry_pubkey_extraspec_ecdsa, GCRY_PK_ECDSA, 0 },
+#if USE_ELGAMAL
+    &_gcry_pubkey_spec_elg,
 #endif
-    { NULL, 0 },
+    NULL
   };
 
-/* List of registered ciphers.  */
-static gcry_module_t pubkeys_registered;
-
-/* This is the lock protecting PUBKEYS_REGISTERED.  */
-static ath_mutex_t pubkeys_registered_lock = ATH_MUTEX_INITIALIZER;;
-
-/* Flag to check wether the default pubkeys have already been
-   registered.  */
-static int default_pubkeys_registered;
-
-/* Convenient macro for registering the default digests.  */
-#define REGISTER_DEFAULT_PUBKEYS                   \
-  do                                               \
-    {                                              \
-      ath_mutex_lock (&pubkeys_registered_lock);   \
-      if (! default_pubkeys_registered)            \
-        {                                          \
-          pk_register_default ();                  \
-          default_pubkeys_registered = 1;          \
-        }                                          \
-      ath_mutex_unlock (&pubkeys_registered_lock); \
-    }                                              \
-  while (0)
-
-/* These dummy functions are used in case a cipher implementation
-   refuses to provide it's own functions.  */
 
-static gcry_err_code_t
-dummy_generate (int algorithm, unsigned int nbits, unsigned long dummy,
-                gcry_mpi_t *skey, gcry_mpi_t **retfactors)
+static int
+map_algo (int algo)
 {
-  (void)algorithm;
-  (void)nbits;
-  (void)dummy;
-  (void)skey;
-  (void)retfactors;
-  fips_signal_error ("using dummy public key function");
-  return GPG_ERR_NOT_IMPLEMENTED;
+ switch (algo)
+   {
+   case GCRY_PK_RSA_E: return GCRY_PK_RSA;
+   case GCRY_PK_RSA_S: return GCRY_PK_RSA;
+   case GCRY_PK_ELG_E: return GCRY_PK_ELG;
+   case GCRY_PK_ECDSA: return GCRY_PK_ECC;
+   case GCRY_PK_ECDH:  return GCRY_PK_ECC;
+   default:            return algo;
+   }
 }
 
-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)
+/* Return the spec structure for the public key algorithm ALGO.  For
+   an unknown algorithm NULL is returned.  */
+static gcry_pk_spec_t *
+spec_from_algo (int algo)
 {
-  (void)algorithm;
-  (void)resarr;
-  (void)data;
-  (void)pkey;
-  (void)flags;
-  fips_signal_error ("using dummy public key function");
-  return GPG_ERR_NOT_IMPLEMENTED;
-}
+  int idx;
+  gcry_pk_spec_t *spec;
 
-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;
-}
+  algo = map_algo (algo);
 
-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;
+  for (idx = 0; (spec = pubkey_list[idx]); idx++)
+    if (algo == spec->algo)
+      return spec;
+  return NULL;
 }
 
-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)
+/* Return the spec structure for the public key algorithm with NAME.
+   For an unknown name NULL is returned.  */
+static gcry_pk_spec_t *
+spec_from_name (const char *name)
 {
-  (void)algorithm;
-  (void)pkey;
-  fips_signal_error ("using dummy public key function");
-  return 0;
-}
+  gcry_pk_spec_t *spec;
+  int idx;
+  const char **aliases;
 
-/* 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++)
+  for (idx=0; (spec = pubkey_list[idx]); idx++)
     {
-#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 (!stricmp (name, spec->name))
+        return spec;
+      for (aliases = spec->aliases; *aliases; aliases++)
+        if (!stricmp (name, *aliases))
+          return spec;
     }
 
-  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;
+  return NULL;
 }
 
-/* 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)
+/* Given the s-expression SEXP with the first element be either
+ * "private-key" or "public-key" return the spec structure for it.  We
+ * look through the list to find a list beginning with "private-key"
+ * or "public-key" - the first one found is used.  If WANT_PRIVATE is
+ * set the function will only succeed if a private key has been given.
+ * On success the spec is stored at R_SPEC.  On error NULL is stored
+ * at R_SPEC and an error code returned.  If R_PARMS is not NULL and
+ * the function returns success, the parameter list below
+ * "private-key" or "public-key" is stored there and the caller must
+ * call gcry_sexp_release on it.
+ */
+static gcry_err_code_t
+spec_from_sexp (gcry_sexp_t sexp, int want_private,
+                gcry_pk_spec_t **r_spec, gcry_sexp_t *r_parms)
 {
-  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);
+  gcry_sexp_t list, l2;
+  char *name;
+  gcry_pk_spec_t *spec;
 
-  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);
+  *r_spec = NULL;
+  if (r_parms)
+    *r_parms = NULL;
+
+  /* Check that the first element is valid.  If we are looking for a
+     public key but a private key was supplied, we allow the use of
+     the private key anyway.  The rationale for this is that the
+     private key is a superset of the public key.  */
+  list = sexp_find_token (sexp, want_private? "private-key":"public-key", 0);
+  if (!list && !want_private)
+    list = sexp_find_token (sexp, "private-key", 0);
+  if (!list)
+    return GPG_ERR_INV_OBJ; /* Does not contain a key object.  */
 
-  if (! err)
+  l2 = sexp_cadr (list);
+  sexp_release (list);
+  list = l2;
+  name = sexp_nth_string (list, 0);
+  if (!name)
     {
-      *module = mod;
-      *algorithm_id = mod->mod_id;
+      sexp_release ( list );
+      return GPG_ERR_INV_OBJ;      /* Invalid structure of object. */
     }
-
-  return err;
+  spec = spec_from_name (name);
+  xfree (name);
+  if (!spec)
+    {
+      sexp_release (list);
+      return GPG_ERR_PUBKEY_ALGO; /* Unknown algorithm. */
+    }
+  *r_spec = spec;
+  if (r_parms)
+    *r_parms = list;
+  else
+    sexp_release (list);
+  return 0;
 }
 
-/* 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);
-}
 
+
+/* Disable the use of the algorithm ALGO.  This is not thread safe and
+   should thus be called early.  */
 static void
-release_mpi_array (gcry_mpi_t *array)
+disable_pubkey_algo (int algo)
 {
-  for (; *array; array++)
-    {
-      mpi_free(*array);
-      *array = NULL;
-    }
+  gcry_pk_spec_t *spec = spec_from_algo (algo);
+
+  if (spec)
+    spec->flags.disabled = 1;
 }
 
-/****************
+
+\f
+/*
  * Map a string to the pubkey algo
  */
 int
-gcry_pk_map_name (const char *string)
+_gcry_pk_map_name (const char *string)
 {
-  gcry_module_t pubkey;
-  int algorithm = 0;
+  gcry_pk_spec_t *spec;
 
   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;
+  spec = spec_from_name (string);
+  if (!spec)
+    return 0;
+  if (spec->flags.disabled)
+    return 0;
+  return spec->algo;
 }
 
 
@@ -334,70 +202,14 @@ gcry_pk_map_name (const char *string)
    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_pk_algo_name (int algo)
 {
-  gcry_module_t pubkey;
+  gcry_pk_spec_t *spec;
 
-  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);
+  spec = spec_from_algo (algo);
+  if (spec)
+    return spec->name;
+  return "?";
 }
 
 
@@ -405,32 +217,22 @@ disable_pubkey_algo (int algorithm)
  * A USE of 0 means: don't care.
  */
 static gcry_err_code_t
-check_pubkey_algo (int algorithm, unsigned use)
+check_pubkey_algo (int algo, unsigned use)
 {
-  gcry_err_code_t err = GPG_ERR_NO_ERROR;
-  gcry_pk_spec_t *pubkey;
-  gcry_module_t module;
-
-  REGISTER_DEFAULT_PUBKEYS;
+  gcry_err_code_t err = 0;
+  gcry_pk_spec_t *spec;
 
-  ath_mutex_lock (&pubkeys_registered_lock);
-  module = _gcry_module_lookup_id (pubkeys_registered, algorithm);
-  if (module)
+  spec = spec_from_algo (algo);
+  if (spec)
     {
-      pubkey = (gcry_pk_spec_t *) module->spec;
-
       if (((use & GCRY_PK_USAGE_SIGN)
-          && (! (pubkey->use & GCRY_PK_USAGE_SIGN)))
+          && (! (spec->use & GCRY_PK_USAGE_SIGN)))
          || ((use & GCRY_PK_USAGE_ENCR)
-             && (! (pubkey->use & GCRY_PK_USAGE_ENCR))))
+             && (! (spec->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;
 }
@@ -440,1158 +242,63 @@ check_pubkey_algo (int algorithm, unsigned use)
  * Return the number of public key material numbers
  */
 static int
-pubkey_get_npkey (int algorithm)
+pubkey_get_npkey (int algo)
 {
-  gcry_module_t pubkey;
-  int npkey = 0;
+  gcry_pk_spec_t *spec = spec_from_algo (algo);
 
-  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 spec? strlen (spec->elements_pkey) : 0;
 }
 
+
 /****************
  * Return the number of secret key material numbers
  */
 static int
-pubkey_get_nskey (int algorithm)
+pubkey_get_nskey (int algo)
 {
-  gcry_module_t pubkey;
-  int nskey = 0;
-
-  REGISTER_DEFAULT_PUBKEYS;
+  gcry_pk_spec_t *spec = spec_from_algo (algo);
 
-  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 spec? strlen (spec->elements_skey) : 0;
 }
 
+
 /****************
  * Return the number of signature material numbers
  */
 static int
-pubkey_get_nsig (int algorithm)
+pubkey_get_nsig (int algo)
 {
-  gcry_module_t pubkey;
-  int nsig = 0;
+  gcry_pk_spec_t *spec = spec_from_algo (algo);
 
-  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 spec? strlen (spec->elements_sig) : 0;
 }
 
 /****************
  * Return the number of encryption material numbers
  */
 static int
-pubkey_get_nenc (int algorithm)
+pubkey_get_nenc (int algo)
 {
-  gcry_module_t pubkey;
-  int nenc = 0;
-
-  REGISTER_DEFAULT_PUBKEYS;
+  gcry_pk_spec_t *spec = spec_from_algo (algo);
 
-  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. The use of the arguments QBITS, USE_E,
-   XVALUE and CURVE_NAME depend on the ALGORITHM.  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 int qbits,
-                 unsigned long use_e, gcry_mpi_t xvalue,
-                 const char *curve_name, unsigned int keygen_flags,
-                 gcry_mpi_t *skey, gcry_mpi_t **retfactors)
-{
-  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 (keygen_flags && (!extraspec || !extraspec->ext_generate))
-        {
-          /* A keygen flag has been given but the module does not
-             provide an ext_generate function.  We don't want to
-             ignore such a condition as it might eventually be
-             security sensitive..  */
-          ec = GPG_ERR_INV_FLAG;
-        }
-      else if (qbits && pubkey->spec == &_gcry_pubkey_spec_dsa)
-        {
-          /* Hack to pass QBITS to the DSA generation.  fixme: We
-             should merge this into an ext_generate fucntion. */
-          ec = _gcry_dsa_generate2
-            (algorithm, nbits, qbits, 0, skey, retfactors);
-        }
-#ifdef USE_ELGAMAL
-      else if (xvalue && pubkey->spec == &_gcry_pubkey_spec_elg)
-        {
-          /* Fixme: Merge this into an ext_generate fucntion.  */
-          ec = _gcry_elg_generate_using_x
-            (algorithm, nbits, xvalue, skey, retfactors);
-        }
-#endif /*USE_ELGAMAL*/
-#ifdef USE_ECC
-      else if (curve_name && pubkey->spec == &_gcry_pubkey_spec_ecdsa)
-        {
-          /* Fixme: Merge this into an ext_generate fucntion.  */
-          ec = _gcry_ecc_generate
-            (algorithm, nbits, curve_name, skey, retfactors);
-        }
-#endif /*USE_ECC*/
-      else if (extraspec && extraspec->ext_generate)
-        {
-          /* Use the extended generate function if available.  */
-          ec = extraspec->ext_generate (algorithm, nbits, use_e,
-                                        keygen_flags,
-                                        skey, retfactors);
-        }
-      else
-        {
-          /* Use the standard generate function.  */
-          ec = ((gcry_pk_spec_t *) pubkey->spec)->generate 
-            (algorithm, nbits, use_e, skey, retfactors);
-        }
-      _gcry_module_release (pubkey);
-    }
-  ath_mutex_unlock (&pubkeys_registered_lock);
-
-  return ec;
-}
-
-static gcry_err_code_t
-pubkey_check_secret_key (int algorithm, gcry_mpi_t *skey)
-{
-  gcry_err_code_t err = GPG_ERR_PUBKEY_ALGO;
-  gcry_module_t pubkey;
-
-  REGISTER_DEFAULT_PUBKEYS;
-
-  ath_mutex_lock (&pubkeys_registered_lock);
-  pubkey = _gcry_module_lookup_id (pubkeys_registered, algorithm);
-  if (pubkey)
-    {
-      err = ((gcry_pk_spec_t *) pubkey->spec)->check_secret_key
-        (algorithm, skey);
-      _gcry_module_release (pubkey);
-    }
-  ath_mutex_unlock (&pubkeys_registered_lock);
-
-  return err;
-}
-
-
-/****************
- * This is the interface to the public key encryption.  Encrypt DATA
- * with PKEY and put it into RESARR which should be an array of MPIs
- * of size PUBKEY_MAX_NENC (or less if the algorithm allows this -
- * check with pubkey_get_nenc() )
- */
-static gcry_err_code_t
-pubkey_encrypt (int algorithm, gcry_mpi_t *resarr, gcry_mpi_t data,
-                gcry_mpi_t *pkey, int flags)
-{
-  gcry_pk_spec_t *pubkey;
-  gcry_module_t module;
-  gcry_err_code_t rc;
-  int i;
-
-  /* Note: In fips mode DBG_CIPHER will enver evaluate to true but as
-     an extra failsafe protection we explicitly test for fips mode
-     here. */ 
-  if (DBG_CIPHER && !fips_mode ())
-    {
-      log_debug ("pubkey_encrypt: algo=%d\n", algorithm);
-      for(i = 0; i < pubkey_get_npkey (algorithm); i++)
-       log_mpidump ("  pkey:", pkey[i]);
-      log_mpidump ("  data:", data);
-    }
-
-  ath_mutex_lock (&pubkeys_registered_lock);
-  module = _gcry_module_lookup_id (pubkeys_registered, algorithm);
-  if (module)
-    {
-      pubkey = (gcry_pk_spec_t *) module->spec;
-      rc = pubkey->encrypt (algorithm, resarr, data, pkey, flags);
-      _gcry_module_release (module);
-      goto ready;
-    }
-  rc = GPG_ERR_PUBKEY_ALGO;
-
- ready:
-  ath_mutex_unlock (&pubkeys_registered_lock);
-
-  if (!rc && DBG_CIPHER && !fips_mode ())
-    {
-      for(i = 0; i < pubkey_get_nenc (algorithm); i++)
-       log_mpidump("  encr:", resarr[i] );
-    }
-  return rc;
-}
-
-
-/****************
- * This is the interface to the public key decryption.
- * ALGO gives the algorithm to use and this implicitly determines
- * the size of the arrays.
- * result is a pointer to a mpi variable which will receive a
- * newly allocated mpi or NULL in case of an error.
- */
-static gcry_err_code_t
-pubkey_decrypt (int algorithm, gcry_mpi_t *result, gcry_mpi_t *data,
-                gcry_mpi_t *skey, int flags)
-{
-  gcry_pk_spec_t *pubkey;
-  gcry_module_t module;
-  gcry_err_code_t rc;
-  int i;
-
-  *result = NULL; /* so the caller can always do a mpi_free */
-  if (DBG_CIPHER && !fips_mode ())
-    {
-      log_debug ("pubkey_decrypt: algo=%d\n", algorithm);
-      for(i = 0; i < pubkey_get_nskey (algorithm); i++)
-       log_mpidump ("  skey:", skey[i]);
-      for(i = 0; i < pubkey_get_nenc (algorithm); i++)
-       log_mpidump ("  data:", data[i]);
-    }
-
-  ath_mutex_lock (&pubkeys_registered_lock);
-  module = _gcry_module_lookup_id (pubkeys_registered, algorithm);
-  if (module)
-    {
-      pubkey = (gcry_pk_spec_t *) module->spec;
-      rc = pubkey->decrypt (algorithm, result, data, skey, flags);
-      _gcry_module_release (module);
-      goto ready;
-    }
-
-  rc = GPG_ERR_PUBKEY_ALGO;
-  
- ready:
-  ath_mutex_unlock (&pubkeys_registered_lock);
-
-  if (!rc && DBG_CIPHER && !fips_mode ())
-    log_mpidump (" plain:", *result);
-
-  return rc;
-}
-
-
-/****************
- * This is the interface to the public key signing.
- * Sign data with skey and put the result into resarr which
- * should be an array of MPIs of size PUBKEY_MAX_NSIG (or less if the
- * algorithm allows this - check with pubkey_get_nsig() )
- */
-static gcry_err_code_t
-pubkey_sign (int algorithm, gcry_mpi_t *resarr, gcry_mpi_t data,
-             gcry_mpi_t *skey)
-{
-  gcry_pk_spec_t *pubkey;
-  gcry_module_t module;
-  gcry_err_code_t rc;
-  int i;
-
-  if (DBG_CIPHER && !fips_mode ())
-    {
-      log_debug ("pubkey_sign: algo=%d\n", algorithm);
-      for(i = 0; i < pubkey_get_nskey (algorithm); i++)
-       log_mpidump ("  skey:", skey[i]);
-      log_mpidump("  data:", data );
-    }
-
-  ath_mutex_lock (&pubkeys_registered_lock);
-  module = _gcry_module_lookup_id (pubkeys_registered, algorithm);
-  if (module)
-    {
-      pubkey = (gcry_pk_spec_t *) module->spec;
-      rc = pubkey->sign (algorithm, resarr, data, skey);
-      _gcry_module_release (module);
-      goto ready;
-    }
-
-  rc = GPG_ERR_PUBKEY_ALGO;
-
- ready:
-  ath_mutex_unlock (&pubkeys_registered_lock);
-
-  if (!rc && DBG_CIPHER && !fips_mode ())
-    for (i = 0; i < pubkey_get_nsig (algorithm); i++)
-      log_mpidump ("   sig:", resarr[i]);
-
-  return rc;
-}
-
-/****************
- * Verify a public key signature.
- * Return 0 if the signature is good
- */
-static gcry_err_code_t
-pubkey_verify (int algorithm, gcry_mpi_t hash, gcry_mpi_t *data,
-               gcry_mpi_t *pkey,
-              int (*cmp)(void *, gcry_mpi_t), void *opaquev)
-{
-  gcry_pk_spec_t *pubkey;
-  gcry_module_t module;
-  gcry_err_code_t rc;
-  int i;
-
-  if (DBG_CIPHER && !fips_mode ())
-    {
-      log_debug ("pubkey_verify: algo=%d\n", algorithm);
-      for (i = 0; i < pubkey_get_npkey (algorithm); i++)
-       log_mpidump ("  pkey:", pkey[i]);
-      for (i = 0; i < pubkey_get_nsig (algorithm); i++)
-       log_mpidump ("   sig:", data[i]);
-      log_mpidump ("  hash:", hash);
-    }
-
-  ath_mutex_lock (&pubkeys_registered_lock);
-  module = _gcry_module_lookup_id (pubkeys_registered, algorithm);
-  if (module)
-    {
-      pubkey = (gcry_pk_spec_t *) module->spec;
-      rc = pubkey->verify (algorithm, hash, data, pkey, cmp, opaquev);
-      _gcry_module_release (module);
-      goto ready;
-    }
-
-  rc = GPG_ERR_PUBKEY_ALGO;
-
- ready:
-  ath_mutex_unlock (&pubkeys_registered_lock);
-  return rc;
-}
-
-
-/* Internal function.   */
-static gcry_err_code_t
-sexp_elements_extract (gcry_sexp_t key_sexp, const char *element_names,
-                      gcry_mpi_t *elements, const char *algo_name)
-{
-  gcry_err_code_t err = 0;
-  int i, idx;
-  const char *name;
-  gcry_sexp_t list;
-
-  for (name = element_names, idx = 0; *name && !err; name++, idx++)
-    {
-      list = gcry_sexp_find_token (key_sexp, name, 1);
-      if (!list)
-       elements[idx] = NULL;
-      else
-       {
-         elements[idx] = gcry_sexp_nth_mpi (list, 1, GCRYMPI_FMT_USG);
-         gcry_sexp_release (list);
-         if (!elements[idx])
-           err = GPG_ERR_INV_OBJ;
-       }
-    }
-
-  if (!err)
-    {
-      /* Check that all elements are available.  */
-      for (name = element_names, idx = 0; *name; name++, idx++)
-        if (!elements[idx])
-          break;
-      if (*name)
-        {
-          err = GPG_ERR_NO_OBJ;
-          /* Some are missing.  Before bailing out we test for
-             optional parameters.  */
-          if (algo_name && !strcmp (algo_name, "RSA")
-              && !strcmp (element_names, "nedpqu") )
-            {
-              /* This is RSA.  Test whether we got N, E and D and that
-                 the optional P, Q and U are all missing.  */
-              if (elements[0] && elements[1] && elements[2]
-                  && !elements[3] && !elements[4] && !elements[5])
-                err = 0;
-            }
-        }
-    }
-
-
-  if (err)
-    {
-      for (i = 0; i < idx; i++)
-        if (elements[i])
-          gcry_free (elements[i]);
-    }
-  return err;
-}
-
-/* Internal function used for ecc.  Note, that this function makes use
-   of its intimate knowledge about the ECC parameters from ecc.c. */
-static gcry_err_code_t
-sexp_elements_extract_ecc (gcry_sexp_t key_sexp, const char *element_names,
-                           gcry_mpi_t *elements)
-{
-  gcry_err_code_t err = 0;
-  int idx;
-  const char *name;
-  gcry_sexp_t list;
-
-  /* Clear the array for easier error cleanup. */
-  for (name = element_names, idx = 0; *name; name++, idx++)
-    elements[idx] = NULL;
-  gcry_assert (idx >= 6); /* We know that ECC has at least 6 elements.  */
-
-  /* Init the array with the available curve parameters. */
-  for (name = element_names, idx = 0; *name && !err; name++, idx++)
-    {
-      list = gcry_sexp_find_token (key_sexp, name, 1);
-      if (!list)
-       elements[idx] = NULL;
-      else
-       {
-         elements[idx] = gcry_sexp_nth_mpi (list, 1, GCRYMPI_FMT_USG);
-         gcry_sexp_release (list);
-         if (!elements[idx])
-            {
-              err = GPG_ERR_INV_OBJ;
-              goto leave;
-            }
-       }
-    }
-
-  /* Check whether a curve parameter has been given and then fill any
-     missing elements.  */
-  list = gcry_sexp_find_token (key_sexp, "curve", 5);
-  if (list)
-    {
-#if USE_ECC
-      char *curve;
-      gcry_mpi_t params[6];
-
-      for (idx = 0; idx < DIM(params); idx++)
-        params[idx] = NULL;
-
-      curve = _gcry_sexp_nth_string (list, 1);
-      if (!curve)
-        {
-          err = GPG_ERR_INV_OBJ; /* No curve name given (or out of core). */
-          goto leave;
-        }
-      err = _gcry_ecc_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 /* !USE_ECC */
-      err = GPG_ERR_INV_OBJ; /* "curve" given but ECC not supported. */
-      goto leave;
-#endif /* !USE_ECC */
-    }
-
-  /* Check that all parameters are known.  */
-  for (name = element_names, idx = 0; *name; name++, idx++)
-    if (!elements[idx])
-      {
-        err = GPG_ERR_NO_OBJ;
-        goto leave;
-      }
-  
- leave:
-  if (err)
-    {
-      for (name = element_names, idx = 0; *name; name++, idx++)
-        if (elements[idx])
-          gcry_free (elements[idx]);
-    }
-  return err;
-}
-
-
-
-/****************
- * Convert a S-Exp with either a private or a public key to our
- * internal format. Currently we do only support the following
- * algorithms:
- *    dsa
- *    rsa
- *    openpgp-dsa
- *    openpgp-rsa
- *    openpgp-elg
- *    openpgp-elg-sig
- *    ecdsa
- * Provide a SE with the first element be either "private-key" or
- * or "public-key". It is followed by a list with its first element
- * be one of the above algorithm identifiers and the remaning
- * elements are pairs with parameter-id and value.
- * NOTE: we look through the list to find a list beginning with
- * "private-key" or "public-key" - the first one found is used.
- *
- * Returns: A pointer to an allocated array of MPIs if the return value is
- *         zero; the caller has to release this array.
- *
- * Example of a DSA public key:
- *  (private-key
- *    (dsa
- *     (p <mpi>)
- *     (g <mpi>)
- *     (y <mpi>)
- *     (x <mpi>)
- *    )
- *  )
- * The <mpi> are expected to be in GCRYMPI_FMT_USG
- */
-static gcry_err_code_t
-sexp_to_key (gcry_sexp_t sexp, int want_private, gcry_mpi_t **retarray,
-             gcry_module_t *retalgo)
-{
-  gcry_err_code_t err = 0;
-  gcry_sexp_t list, l2;
-  char *name;
-  const char *elems;
-  gcry_mpi_t *array;
-  gcry_module_t module;
-  gcry_pk_spec_t *pubkey;
-  int is_ecc;
-
-  /* Check that the first element is valid.  */
-  list = gcry_sexp_find_token (sexp, 
-                               want_private? "private-key":"public-key", 0);
-  if (!list)
-    return GPG_ERR_INV_OBJ; /* Does not contain a key object.  */
-
-  l2 = gcry_sexp_cadr( list );
-  gcry_sexp_release ( list );
-  list = l2;
-  name = _gcry_sexp_nth_string (list, 0);
-  if (!name)
-    {
-      gcry_sexp_release ( list );
-      return GPG_ERR_INV_OBJ;      /* Invalid structure of object. */
-    }
-
-  ath_mutex_lock (&pubkeys_registered_lock);
-  module = gcry_pk_lookup_name (name);
-  ath_mutex_unlock (&pubkeys_registered_lock);
-  
-  /* Fixme: We should make sure that an ECC key is always named "ecc"
-     and not "ecdsa".  "ecdsa" should be used for the signature
-     itself.  We need a function to test whether an algorithm given
-     with a key is compatible with an application of the key (signing,
-     encryption).  For RSA this is easy, but ECC is the first
-     algorithm which has many flavours. */
-  is_ecc = ( !strcmp (name, "ecdsa") || !strcmp (name, "ecc") );
-  gcry_free (name);
-  
-  if (!module)
-    {
-      gcry_sexp_release (list);
-      return GPG_ERR_PUBKEY_ALGO; /* Unknown algorithm. */
-    }
-  else
-    pubkey = (gcry_pk_spec_t *) module->spec;
-
-  elems = want_private ? pubkey->elements_skey : pubkey->elements_pkey;
-  array = gcry_calloc (strlen (elems) + 1, sizeof (*array));
-  if (!array)
-    err = gpg_err_code_from_errno (errno);
-  if (!err)
-    {
-      if (is_ecc)
-        err = sexp_elements_extract_ecc (list, elems, array);
-      else
-        err = sexp_elements_extract (list, elems, array, pubkey->name);
-    }
-  
-  gcry_sexp_release (list);
-  
-  if (err)
-    {
-      gcry_free (array);
-
-      ath_mutex_lock (&pubkeys_registered_lock);
-      _gcry_module_release (module);
-      ath_mutex_unlock (&pubkeys_registered_lock);
-    }
-  else
-    {
-      *retarray = array;
-      *retalgo = module;
-    }
-  
-  return err;
-}
-
-
-static gcry_err_code_t
-sexp_to_sig (gcry_sexp_t sexp, gcry_mpi_t **retarray,
-            gcry_module_t *retalgo)
-{
-  gcry_err_code_t err = 0;
-  gcry_sexp_t list, l2;
-  char *name;
-  const char *elems;
-  gcry_mpi_t *array;
-  gcry_module_t module;
-  gcry_pk_spec_t *pubkey;
-  
-  /* Check that the first element is valid.  */
-  list = gcry_sexp_find_token( sexp, "sig-val" , 0 );
-  if (!list)
-    return GPG_ERR_INV_OBJ; /* Does not contain a signature value object.  */
-
-  l2 = gcry_sexp_nth (list, 1);
-  if (!l2)
-    {
-      gcry_sexp_release (list);
-      return GPG_ERR_NO_OBJ;   /* No cadr for the sig object.  */
-    }
-  name = _gcry_sexp_nth_string (l2, 0);
-  if (!name)
-    {
-      gcry_sexp_release (list);
-      gcry_sexp_release (l2);
-      return GPG_ERR_INV_OBJ;  /* Invalid structure of object.  */
-    }
-  else if (!strcmp (name, "flags")) 
-    {
-      /* Skip flags, since they are not used but here just for the
-        sake of consistent S-expressions.  */
-      gcry_free (name);
-      gcry_sexp_release (l2);
-      l2 = gcry_sexp_nth (list, 2);
-      if (!l2)
-       {
-         gcry_sexp_release (list);
-         return GPG_ERR_INV_OBJ;
-       }
-      name = _gcry_sexp_nth_string (l2, 0);
-    }
-      
-  ath_mutex_lock (&pubkeys_registered_lock);
-  module = gcry_pk_lookup_name (name);
-  ath_mutex_unlock (&pubkeys_registered_lock);
-  gcry_free (name);
-  name = NULL;
-
-  if (!module)
-    {
-      gcry_sexp_release (l2);
-      gcry_sexp_release (list);
-      return GPG_ERR_PUBKEY_ALGO;  /* Unknown algorithm. */
-    }
-  else
-    pubkey = (gcry_pk_spec_t *) module->spec;
-
-  elems = pubkey->elements_sig;
-  array = gcry_calloc (strlen (elems) + 1 , sizeof *array );
-  if (!array)
-    err = gpg_err_code_from_errno (errno);
-
-  if (!err)
-    err = sexp_elements_extract (list, elems, array, NULL);
-
-  gcry_sexp_release (l2);
-  gcry_sexp_release (list);
-
-  if (err)
-    {
-      ath_mutex_lock (&pubkeys_registered_lock);
-      _gcry_module_release (module);
-      ath_mutex_unlock (&pubkeys_registered_lock);
-      
-      gcry_free (array);
-    }
-  else
-    {
-      *retarray = array;
-      *retalgo = module;
-    }
-  
-  return err;
-}
-
-
-/****************
- * Take sexp and return an array of MPI as used for our internal decrypt
- * function.
- * s_data = (enc-val
- *           [(flags [pkcs1])]
- *           (<algo>
- *             (<param_name1> <mpi>)
- *             ...
- *             (<param_namen> <mpi>)
- *           ))
- * RET_MODERN is set to true when at least an empty flags list has been found.
- */
-static gcry_err_code_t
-sexp_to_enc (gcry_sexp_t sexp, gcry_mpi_t **retarray, gcry_module_t *retalgo,
-             int *ret_modern, int *ret_want_pkcs1, int *flags)
-{
-  gcry_err_code_t err = 0;
-  gcry_sexp_t list = NULL, l2 = NULL;
-  gcry_pk_spec_t *pubkey = NULL;
-  gcry_module_t module = NULL;
-  char *name = NULL;
-  size_t n;
-  int parsed_flags = 0;
-  const char *elems;
-  gcry_mpi_t *array = NULL;
-
-  *ret_want_pkcs1 = 0;
-  *ret_modern = 0;
-
-  /* Check that the first element is valid.  */
-  list = gcry_sexp_find_token (sexp, "enc-val" , 0);
-  if (!list)
-    {
-      err = GPG_ERR_INV_OBJ; /* Does not contain an encrypted value object.  */
-      goto leave;
-    }
-
-  l2 = gcry_sexp_nth (list, 1);
-  if (!l2)
-    {
-      err = GPG_ERR_NO_OBJ; /* No cdr for the data object.  */
-      goto leave;
-    }
-
-  /* Extract identifier of sublist.  */
-  name = _gcry_sexp_nth_string (l2, 0);
-  if (!name)
-    {
-      err = GPG_ERR_INV_OBJ; /* Invalid structure of object.  */
-      goto leave;
-    }
-  
-  if (!strcmp (name, "flags"))
-    {
-      /* There is a flags element - process it.  */
-      const char *s;
-      int i;
-      
-      *ret_modern = 1;
-      for (i = gcry_sexp_length (l2) - 1; i > 0; i--)
-        {
-          s = gcry_sexp_nth_data (l2, i, &n);
-          if (! s)
-            ; /* Not a data element - ignore.  */
-          else if (n == 3 && !memcmp (s, "raw", 3))
-            ; /* This is just a dummy as it is the default.  */
-          else if (n == 5 && !memcmp (s, "pkcs1", 5))
-            *ret_want_pkcs1 = 1;
-          else if (n == 11 && ! memcmp (s, "no-blinding", 11))
-            parsed_flags |= PUBKEY_FLAG_NO_BLINDING;
-          else
-            {
-              err = GPG_ERR_INV_FLAG;
-              goto leave;
-            }
-        }
-      
-      /* Get the next which has the actual data. */
-      gcry_sexp_release (l2);
-      l2 = gcry_sexp_nth (list, 2);
-      if (!l2)
-        {
-          err = GPG_ERR_NO_OBJ; /* No cdr for the data object. */
-          goto leave;
-        }
-
-      /* Extract sublist identifier.  */
-      gcry_free (name);
-      name = _gcry_sexp_nth_string (l2, 0);
-      if (!name)
-        {
-          err = GPG_ERR_INV_OBJ; /* Invalid structure of object. */
-          goto leave;
-        }
-
-      gcry_sexp_release (list);
-      list = l2;
-      l2 = NULL;
-    }
-
-  ath_mutex_lock (&pubkeys_registered_lock);
-  module = gcry_pk_lookup_name (name);
-  ath_mutex_unlock (&pubkeys_registered_lock);
-  
-  if (!module)
-    {
-      err = GPG_ERR_PUBKEY_ALGO; /* Unknown algorithm.  */
-      goto leave;
-    }
-  pubkey = (gcry_pk_spec_t *) module->spec;
-
-  elems = pubkey->elements_enc;
-  array = gcry_calloc (strlen (elems) + 1, sizeof (*array));
-  if (!array)
-    {
-      err = gpg_err_code_from_errno (errno);
-      goto leave;
-    }
-
-  err = sexp_elements_extract (list, elems, array, NULL);
-
- leave:
-  gcry_sexp_release (list);
-  gcry_sexp_release (l2);
-  gcry_free (name);
-
-  if (err)
-    {
-      ath_mutex_lock (&pubkeys_registered_lock);
-      _gcry_module_release (module);
-      ath_mutex_unlock (&pubkeys_registered_lock);
-      gcry_free (array);
-    }
-  else
-    {
-      *retarray = array;
-      *retalgo = module;
-      *flags = parsed_flags;
-    }
-
-  return err;
-}
-
-/* Take the hash value and convert into an MPI, suitable for
-   passing to the low level functions.  We currently support the
-   old style way of passing just a MPI and the modern interface which
-   allows to pass flags so that we can choose between raw and pkcs1
-   padding - may be more padding options later. 
-
-   (<mpi>)
-   or
-   (data
-    [(flags [pkcs1])]
-    [(hash <algo> <value>)]
-    [(value <text>)]
-   )
-   
-   Either the VALUE or the HASH element must be present for use
-   with signatures.  VALUE is used for encryption.
-
-   NBITS is the length of the key in bits. 
-
-*/
-static gcry_err_code_t
-sexp_data_to_mpi (gcry_sexp_t input, unsigned int nbits, gcry_mpi_t *ret_mpi,
-                  int for_encryption, int *flags)
-{
-  gcry_err_code_t rc = 0;
-  gcry_sexp_t ldata, lhash, lvalue;
-  int i;
-  size_t n;
-  const char *s;
-  int is_raw = 0, is_pkcs1 = 0, unknown_flag=0; 
-  int parsed_flags = 0, dummy_flags;
-
-  if (! flags)
-    flags = &dummy_flags;
-  
-  *ret_mpi = NULL;
-  ldata = gcry_sexp_find_token (input, "data", 0);
-  if (!ldata)
-    { /* assume old style */
-      *ret_mpi = gcry_sexp_nth_mpi (input, 0, 0);
-      return *ret_mpi ? GPG_ERR_NO_ERROR : GPG_ERR_INV_OBJ;
-    }
-
-  /* see whether there is a flags object */
-  {
-    gcry_sexp_t lflags = gcry_sexp_find_token (ldata, "flags", 0);
-    if (lflags)
-      { /* parse the flags list. */
-        for (i=gcry_sexp_length (lflags)-1; i > 0; i--)
-          {
-            s = gcry_sexp_nth_data (lflags, i, &n);
-            if (!s)
-              ; /* not a data element*/
-            else if ( n == 3 && !memcmp (s, "raw", 3))
-              is_raw = 1;
-            else if ( n == 5 && !memcmp (s, "pkcs1", 5))
-              is_pkcs1 = 1;
-           else if (n == 11 && ! memcmp (s, "no-blinding", 11))
-             parsed_flags |= PUBKEY_FLAG_NO_BLINDING;
-            else
-              unknown_flag = 1;
-          }
-        gcry_sexp_release (lflags);
-      }
-  }
-
-  if (!is_pkcs1 && !is_raw)
-    is_raw = 1; /* default to raw */
-
-  /* Get HASH or MPI */
-  lhash = gcry_sexp_find_token (ldata, "hash", 0);
-  lvalue = lhash? NULL : gcry_sexp_find_token (ldata, "value", 0);
-
-  if (!(!lhash ^ !lvalue))
-    rc = GPG_ERR_INV_OBJ; /* none or both given */
-  else if (unknown_flag)
-    rc = GPG_ERR_INV_FLAG;
-  else if (is_raw && is_pkcs1 && !for_encryption)
-    rc = GPG_ERR_CONFLICT;
-  else if (is_raw && lvalue)
-    {
-      *ret_mpi = gcry_sexp_nth_mpi (lvalue, 1, 0);
-      if (!*ret_mpi)
-        rc = GPG_ERR_INV_OBJ;
-    }
-  else if (is_pkcs1 && lvalue && for_encryption)
-    { 
-      /* Create pkcs#1 block type 2 padding. */
-      unsigned char *frame = NULL;
-      size_t nframe = (nbits+7) / 8;
-      const void * value;
-      size_t valuelen;
-      unsigned char *p;
-
-      if ( !(value=gcry_sexp_nth_data (lvalue, 1, &valuelen)) || !valuelen )
-        rc = GPG_ERR_INV_OBJ;
-      else if (valuelen + 7 > nframe || !nframe)
-        {
-          /* Can't encode a VALUELEN value in a NFRAME bytes frame. */
-          rc = GPG_ERR_TOO_SHORT; /* the key is too short */
-        }
-      else if ( !(frame = gcry_malloc_secure (nframe)))
-        rc = gpg_err_code_from_errno (errno);
-      else
-        {
-          n = 0;
-          frame[n++] = 0;
-          frame[n++] = 2; /* block type */
-          i = nframe - 3 - valuelen;
-          gcry_assert (i > 0);
-          p = gcry_random_bytes_secure (i, GCRY_STRONG_RANDOM);
-          /* Replace zero bytes by new values. */
-          for (;;)
-            {
-              int j, k;
-              unsigned char *pp;
-              
-              /* Count the zero bytes. */
-              for (j=k=0; j < i; j++)
-                {
-                  if (!p[j])
-                    k++;
-                }
-              if (!k)
-                break; /* Okay: no (more) zero bytes. */
-              
-              k += k/128 + 3; /* Better get some more. */
-              pp = gcry_random_bytes_secure (k, GCRY_STRONG_RANDOM);
-              for (j=0; j < i && k; )
-                {
-                  if (!p[j])
-                    p[j] = pp[--k];
-                  if (p[j])
-                    j++;
-                }
-              gcry_free (pp);
-            }
-          memcpy (frame+n, p, i);
-          n += i;
-          gcry_free (p);
-          
-          frame[n++] = 0;
-          memcpy (frame+n, value, valuelen);
-          n += valuelen;
-          gcry_assert (n == nframe);
-
-         /* FIXME, error checking?  */
-          gcry_mpi_scan (ret_mpi, GCRYMPI_FMT_USG, frame, n, &nframe);
-        }
-
-      gcry_free(frame);
-    }
-  else if (is_pkcs1 && lhash && !for_encryption)
-    { 
-      /* Create pkcs#1 block type 1 padding. */
-      if (gcry_sexp_length (lhash) != 3)
-        rc = GPG_ERR_INV_OBJ;
-      else if ( !(s=gcry_sexp_nth_data (lhash, 1, &n)) || !n )
-        rc = GPG_ERR_INV_OBJ;
-      else
-        {
-          static struct { const char *name; int algo; } hashnames[] = 
-          { { "sha1",   GCRY_MD_SHA1 },
-            { "md5",    GCRY_MD_MD5 },
-            { "sha256", GCRY_MD_SHA256 },
-            { "ripemd160", GCRY_MD_RMD160 },
-            { "rmd160", GCRY_MD_RMD160 },
-            { "sha384", GCRY_MD_SHA384 },
-            { "sha512", GCRY_MD_SHA512 },
-            { "sha224", GCRY_MD_SHA224 },
-            { "md2",    GCRY_MD_MD2 },
-            { "md4",    GCRY_MD_MD4 },
-            { "tiger",  GCRY_MD_TIGER },
-            { "haval",  GCRY_MD_HAVAL },
-            { NULL, 0 }
-          };
-          int algo;
-          byte asn[100];
-          byte *frame = NULL;
-          size_t nframe = (nbits+7) / 8;
-          const void * value;
-          size_t valuelen;
-          size_t asnlen, dlen;
-            
-          for (i=0; hashnames[i].name; i++)
-            {
-              if ( strlen (hashnames[i].name) == n
-                   && !memcmp (hashnames[i].name, s, n))
-                break;
-            }
-          if (hashnames[i].name)
-            algo = hashnames[i].algo;
-          else
-            {
-              /* In case of not listed or dynamically allocated hash
-                 algorithm we fall back to this somewhat slower
-                 method.  Further, it also allows to use OIDs as
-                 algorithm names. */
-              char *tmpname;
-
-              tmpname = gcry_malloc (n+1);
-              if (!tmpname)
-                algo = 0;  /* Out of core - silently give up.  */
-              else
-                {
-                  memcpy (tmpname, s, n);
-                  tmpname[n] = 0;
-                  algo = gcry_md_map_name (tmpname);
-                  gcry_free (tmpname);
-                }
-            }
-
-          asnlen = DIM(asn);
-          dlen = gcry_md_get_algo_dlen (algo);
-
-          if (!algo)
-            rc = GPG_ERR_DIGEST_ALGO;
-          else if ( !(value=gcry_sexp_nth_data (lhash, 2, &valuelen))
-                    || !valuelen )
-            rc = GPG_ERR_INV_OBJ;
-          else if (gcry_md_algo_info (algo, GCRYCTL_GET_ASNOID, asn, &asnlen))
-            {
-              /* We don't have yet all of the above algorithms.  */
-              rc = GPG_ERR_NOT_IMPLEMENTED;
-            }
-          else if ( valuelen != dlen )
-            {
-              /* Hash value does not match the length of digest for
-                 the given algorithm. */
-              rc = GPG_ERR_CONFLICT;
-            }
-          else if( !dlen || dlen + asnlen + 4 > nframe)
-            {
-              /* Can't encode an DLEN byte digest MD into a NFRAME
-                 byte frame. */
-              rc = GPG_ERR_TOO_SHORT;
-            }
-          else if ( !(frame = gcry_malloc (nframe)) )
-            rc = gpg_err_code_from_errno (errno);
-          else
-            { /* Assemble the pkcs#1 block type 1. */
-              n = 0;
-              frame[n++] = 0;
-              frame[n++] = 1; /* block type */
-              i = nframe - valuelen - asnlen - 3 ;
-              gcry_assert (i > 1);
-              memset (frame+n, 0xff, i );
-              n += i;
-              frame[n++] = 0;
-              memcpy (frame+n, asn, asnlen);
-              n += asnlen;
-              memcpy (frame+n, value, valuelen );
-              n += valuelen;
-              gcry_assert (n == nframe);
-      
-              /* Convert it into an MPI.  FIXME: error checking?  */
-              gcry_mpi_scan (ret_mpi, GCRYMPI_FMT_USG, frame, n, &nframe);
-            }
-          
-          gcry_free (frame);
-        }
-    }
-  else
-    rc = GPG_ERR_CONFLICT;
-   
-  gcry_sexp_release (ldata);
-  gcry_sexp_release (lhash);
-  gcry_sexp_release (lvalue);
-
-  if (!rc)
-    *flags = parsed_flags;
-
-  return rc;
+  return spec? strlen (spec->elements_enc) : 0;
 }
 
 
+\f
 /*
    Do a PK encrypt operation
-  
+
    Caller has to provide a public key as the SEXP pkey and data as a
-   SEXP with just one MPI in it. Alternativly S_DATA might be a
+   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
+   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_data = See comment for _gcry_pk_util_data_to_mpi
    s_pkey = <key-as-defined-in-sexp_to_key>
    r_ciph = (enc-val
                (<algo>
@@ -1601,141 +308,44 @@ sexp_data_to_mpi (gcry_sexp_t input, unsigned int nbits, gcry_mpi_t *ret_mpi,
                ))
 
 */
-gcry_error_t
-gcry_pk_encrypt (gcry_sexp_t *r_ciph, gcry_sexp_t s_data, gcry_sexp_t s_pkey)
+gcry_err_code_t
+_gcry_pk_encrypt (gcry_sexp_t *r_ciph, gcry_sexp_t s_data, gcry_sexp_t s_pkey)
 {
-  gcry_mpi_t *pkey = NULL, data = NULL, *ciph = NULL;
-  const char *algo_name, *algo_elems;
-  int flags;
   gcry_err_code_t rc;
-  gcry_pk_spec_t *pubkey = NULL;
-  gcry_module_t module = NULL;
+  gcry_pk_spec_t *spec;
+  gcry_sexp_t keyparms;
 
   *r_ciph = NULL;
 
-  REGISTER_DEFAULT_PUBKEYS;
-
-  /* Get the key. */
-  rc = sexp_to_key (s_pkey, 0, &pkey, &module);
+  rc = spec_from_sexp (s_pkey, 0, &spec, &keyparms);
   if (rc)
     goto leave;
 
-  gcry_assert (module);
-  pubkey = (gcry_pk_spec_t *) module->spec;
-
-  /* If aliases for the algorithm name exists, take the first one
-     instead of the regular name to adhere to SPKI conventions.  We
-     assume that the first alias name is the lowercase version of the
-     regular one.  This change is required for compatibility with
-     1.1.12 generated S-expressions. */
-  algo_name = pubkey->aliases? *pubkey->aliases : NULL;
-  if (!algo_name || !*algo_name)
-    algo_name = pubkey->name;
-  
-  algo_elems = pubkey->elements_enc;
-  
-  /* Get the stuff we want to encrypt. */
-  rc = sexp_data_to_mpi (s_data, gcry_pk_get_nbits (s_pkey), &data, 1,
-                         &flags);
-  if (rc)
-    goto leave;
-
-  /* Now we can encrypt DATA to CIPH. */
-  ciph = gcry_calloc (strlen (algo_elems) + 1, sizeof (*ciph));
-  if (!ciph)
-    {
-      rc = gpg_err_code_from_errno (errno);
-      goto leave;
-    }
-  rc = pubkey_encrypt (module->mod_id, ciph, data, pkey, flags);
-  mpi_free (data);
-  data = NULL;
-  if (rc)
-    goto leave;
-
-  /* We did it.  Now build the return list */
-  {
-    char *string, *p;
-    int i;
-    size_t nelem = strlen (algo_elems);
-    size_t needed = 19 + strlen (algo_name) + (nelem * 5);
-    void **arg_list;
-    
-    /* Build the string.  */
-    string = p = gcry_malloc (needed);
-    if (!string)
-      {
-        rc = gpg_err_code_from_errno (errno);
-        goto leave;
-      }
-    p = stpcpy ( p, "(enc-val(" );
-    p = stpcpy ( p, algo_name );
-    for (i=0; algo_elems[i]; i++ )
-      {
-        *p++ = '(';
-        *p++ = algo_elems[i];
-        p = stpcpy ( p, "%m)" );
-      }
-    strcpy ( p, "))" );
-    
-    /* And now the ugly part: We don't have a function to pass an
-     * array to a format string, so we have to do it this way :-(.  */
-    /* FIXME: There is now such a format specifier, so we can
-       change the code to be more clear. */
-    arg_list = malloc (nelem * sizeof *arg_list);
-    if (!arg_list)
-      {
-        rc = gpg_err_code_from_errno (errno);
-        goto leave;
-      }
-
-    for (i = 0; i < nelem; i++)
-      arg_list[i] = ciph + i;
-    
-    rc = gcry_sexp_build_array (r_ciph, NULL, string, arg_list);
-    free (arg_list);
-    if (rc)
-      BUG ();
-    gcry_free (string);
-  }
+  if (spec->encrypt)
+    rc = spec->encrypt (r_ciph, s_data, keyparms);
+  else
+    rc = GPG_ERR_NOT_IMPLEMENTED;
 
  leave:
-  if (pkey)
-    {
-      release_mpi_array (pkey);
-      gcry_free (pkey);
-    }
-
-  if (ciph)
-    {
-      release_mpi_array (ciph);
-      gcry_free (ciph);
-    }
-
-  if (module)
-    {
-      ath_mutex_lock (&pubkeys_registered_lock);
-      _gcry_module_release (module);
-      ath_mutex_unlock (&pubkeys_registered_lock);
-    }
-
-  return gcry_error (rc);
+  sexp_release (keyparms);
+  return 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)]
+              [(flags [raw, pkcs1, oaep])]
               (<algo>
                 (<param_name1> <mpi>)
                 ...
@@ -1744,207 +354,86 @@ gcry_pk_encrypt (gcry_sexp_t *r_ciph, gcry_sexp_t s_data, gcry_sexp_t s_pkey)
    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). 
+            (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_err_code_t
+_gcry_pk_decrypt (gcry_sexp_t *r_plain, gcry_sexp_t s_data, gcry_sexp_t s_skey)
 {
-  gcry_mpi_t *skey = NULL, *data = NULL, plain = NULL;
-  int modern, want_pkcs1, flags;
   gcry_err_code_t rc;
-  gcry_module_t module_enc = NULL, module_key = NULL;
-  gcry_pk_spec_t *pubkey = NULL;
-
-  *r_plain = NULL;
-
-  REGISTER_DEFAULT_PUBKEYS;
-
-  rc = sexp_to_key (s_skey, 1, &skey, &module_key);
-  if (rc)
-    goto leave;
-
-  rc = sexp_to_enc (s_data, &data, &module_enc, &modern, &want_pkcs1, &flags);
-  if (rc)
-    goto leave;
-  
-  if (module_key->mod_id != module_enc->mod_id)
-    {
-      rc = GPG_ERR_CONFLICT; /* Key algo does not match data algo. */
-      goto leave;
-    }
+  gcry_pk_spec_t *spec;
+  gcry_sexp_t keyparms;
 
-  pubkey = (gcry_pk_spec_t *) module_key->spec;
+  *r_plain = NULL;
 
-  rc = pubkey_decrypt (module_key->mod_id, &plain, data, skey, flags);
+  rc = spec_from_sexp (s_skey, 1, &spec, &keyparms);
   if (rc)
     goto leave;
 
-  if (gcry_sexp_build (r_plain, NULL, modern? "(value %m)" : "%m", plain))
-    BUG ();
-  
- leave:
-  if (skey)
-    {
-      release_mpi_array (skey);
-      gcry_free (skey);
-    }
-
-  if (plain)
-    mpi_free (plain);
-
-  if (data)
-    {
-      release_mpi_array (data);
-      gcry_free (data);
-    }
-
-  if (module_key || module_enc)
-    {
-      ath_mutex_lock (&pubkeys_registered_lock);
-      if (module_key)
-       _gcry_module_release (module_key);
-      if (module_enc)
-       _gcry_module_release (module_enc);
-      ath_mutex_unlock (&pubkeys_registered_lock);
-    }
+  if (spec->decrypt)
+    rc = spec->decrypt (r_plain, s_data, keyparms);
+  else
+    rc = GPG_ERR_NOT_IMPLEMENTED;
 
-  return gcry_error (rc);
+ leave:
+  sexp_release (keyparms);
+  return rc;
 }
 
 
 
 /*
    Create a signature.
-  
+
    Caller has to provide a secret key as the SEXP skey and data
    expressed as a SEXP list hash with only one element which should
    instantly be available as a MPI. Alternatively the structure given
    below may be used for S_HASH, it provides the abiliy to pass flags
-   to the operation; the only flag defined by now is "pkcs1" which
-   does PKCS#1 block type 1 style padding.
-  
+   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_hash = See comment for _gcry-pk_util_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)]) 
+             [(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_err_code_t
+_gcry_pk_sign (gcry_sexp_t *r_sig, gcry_sexp_t s_hash, gcry_sexp_t s_skey)
 {
-  gcry_mpi_t *skey = NULL, hash = NULL, *result = NULL;
-  gcry_pk_spec_t *pubkey = NULL;
-  gcry_module_t module = NULL;
-  const char *algo_name, *algo_elems;
-  int i;
   gcry_err_code_t rc;
+  gcry_pk_spec_t *spec;
+  gcry_sexp_t keyparms;
 
   *r_sig = NULL;
 
-  REGISTER_DEFAULT_PUBKEYS;
-
-  rc = sexp_to_key (s_skey, 1, &skey, &module);
-  if (rc)
-    goto leave;
-
-  gcry_assert (module);
-  pubkey = (gcry_pk_spec_t *) module->spec;
-  algo_name = pubkey->aliases? *pubkey->aliases : NULL;
-  if (!algo_name || !*algo_name)
-    algo_name = pubkey->name;
-  
-  algo_elems = pubkey->elements_sig;
-
-  /* Get the stuff we want to sign.  Note that pk_get_nbits does also
-      work on a private key. */
-  rc = sexp_data_to_mpi (s_hash, gcry_pk_get_nbits (s_skey),
-                             &hash, 0, NULL);
-  if (rc)
-    goto leave;
-
-  result = gcry_calloc (strlen (algo_elems) + 1, sizeof (*result));
-  if (!result)
-    {
-      rc = gpg_err_code_from_errno (errno);
-      goto leave;
-    }
-  rc = pubkey_sign (module->mod_id, result, hash, skey);
+  rc = spec_from_sexp (s_skey, 1, &spec, &keyparms);
   if (rc)
     goto leave;
 
-  {
-    char *string, *p;
-    size_t nelem, needed = strlen (algo_name) + 20;
-    void **arg_list;
-
-    nelem = strlen (algo_elems);
-    
-    /* Count elements, so that we can allocate enough space. */
-    needed += 10 * nelem;
-
-    /* Build the string. */
-    string = p = gcry_malloc (needed);
-    if (!string)
-      {
-        rc = gpg_err_code_from_errno (errno);
-        goto leave;
-      }
-    p = stpcpy (p, "(sig-val(");
-    p = stpcpy (p, algo_name);
-    for (i = 0; algo_elems[i]; i++)
-      {
-        *p++ = '(';
-        *p++ = algo_elems[i];
-        p = stpcpy (p, "%m)");
-      }
-    strcpy (p, "))");
-
-    arg_list = malloc (nelem * sizeof *arg_list);
-    if (!arg_list)
-      {
-        rc = gpg_err_code_from_errno (errno);
-        goto leave;
-      }
-
-    for (i = 0; i < nelem; i++)
-      arg_list[i] = result + i;
-
-    rc = gcry_sexp_build_array (r_sig, NULL, string, arg_list);
-    free (arg_list);
-    if (rc)
-      BUG ();
-    gcry_free (string);
-  }
+  if (spec->sign)
+    rc = spec->sign (r_sig, s_hash, keyparms);
+  else
+    rc = GPG_ERR_NOT_IMPLEMENTED;
 
  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);
+  sexp_release (keyparms);
+  return rc;
 }
 
 
@@ -1955,63 +444,25 @@ gcry_pk_sign (gcry_sexp_t *r_sig, gcry_sexp_t s_hash, gcry_sexp_t s_skey)
    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_err_code_t
+_gcry_pk_verify (gcry_sexp_t s_sig, gcry_sexp_t s_hash, gcry_sexp_t s_pkey)
 {
-  gcry_module_t module_key = NULL, module_sig = NULL;
-  gcry_mpi_t *pkey = NULL, hash = NULL, *sig = NULL;
   gcry_err_code_t rc;
+  gcry_pk_spec_t *spec;
+  gcry_sexp_t keyparms;
 
-  REGISTER_DEFAULT_PUBKEYS;
-  rc = sexp_to_key (s_pkey, 0, &pkey, &module_key);
-  if (rc)
-    goto leave;
-
-  rc = sexp_to_sig (s_sig, &sig, &module_sig);
-  if (rc)
-    goto leave;
-
-  /* Fixme: Check that the algorithm of S_SIG is compatible to the one
-     of S_PKEY.  */
-
-  if (module_key->mod_id != module_sig->mod_id)
-    {
-      rc = GPG_ERR_CONFLICT;
-      goto leave;
-    }
-
-  rc = sexp_data_to_mpi (s_hash, gcry_pk_get_nbits (s_pkey), &hash, 0, 0);
+  rc = spec_from_sexp (s_pkey, 0, &spec, &keyparms);
   if (rc)
     goto leave;
 
-  rc = pubkey_verify (module_key->mod_id, hash, sig, pkey, NULL, NULL);
+  if (spec->verify)
+    rc = spec->verify (s_sig, s_hash, keyparms);
+  else
+    rc = GPG_ERR_NOT_IMPLEMENTED;
 
  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);
+  sexp_release (keyparms);
+  return rc;
 }
 
 
@@ -2020,28 +471,29 @@ gcry_pk_verify (gcry_sexp_t s_sig, gcry_sexp_t s_hash, gcry_sexp_t s_pkey)
 
    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)
+
+   NOTE: We currently support only secret key checking. */
+gcry_err_code_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;
+  gcry_pk_spec_t *spec;
+  gcry_sexp_t keyparms;
 
-  /* Note we currently support only secret key checking. */
-  rc = sexp_to_key (s_key, 1, &key, &module);
-  if (! rc)
-    {
-      rc = pubkey_check_secret_key (module->mod_id, key);
-      release_mpi_array (key);
-      gcry_free (key);
-    }
-  return gcry_error (rc);
+  rc = spec_from_sexp (s_key, 1, &spec, &keyparms);
+  if (rc)
+    goto leave;
+
+  if (spec->check_secret_key)
+    rc = spec->check_secret_key (keyparms);
+  else
+    rc = GPG_ERR_NOT_IMPLEMENTED;
+
+ leave:
+  sexp_release (keyparms);
+  return rc;
 }
 
 
@@ -2078,41 +530,26 @@ gcry_pk_testkey (gcry_sexp_t s_key)
       (pm1-factors n1 n2 ... nn)
    ))
  */
-gcry_error_t
-gcry_pk_genkey (gcry_sexp_t *r_key, gcry_sexp_t s_parms)
+gcry_err_code_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, l2 = NULL;
+  gcry_pk_spec_t *spec = NULL;
+  gcry_sexp_t list = NULL;
+  gcry_sexp_t l2 = NULL;
   char *name = NULL;
-  size_t n;
-  gcry_err_code_t rc = GPG_ERR_NO_ERROR;
-  int i;
-  const char *algo_name = NULL;
-  int algo;
-  const char *sec_elems = NULL, *pub_elems = NULL;
-  gcry_mpi_t skey[12], *factors = NULL;
-  unsigned int nbits = 0;
-  unsigned long use_e = 0;
-  unsigned int qbits;
-  gcry_mpi_t xvalue = NULL;
-  char *curve = NULL;
-  unsigned int keygen_flags = 0;
-
-  skey[0] = NULL;
-  *r_key = NULL;
+  gcry_err_code_t rc;
 
-  REGISTER_DEFAULT_PUBKEYS;
+  *r_key = NULL;
 
-  list = gcry_sexp_find_token (s_parms, "genkey", 0);
+  list = 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);
+  l2 = sexp_cadr (list);
+  sexp_release (list);
   list = l2;
   l2 = NULL;
   if (! list)
@@ -2127,333 +564,90 @@ gcry_pk_genkey (gcry_sexp_t *r_key, gcry_sexp_t s_parms)
       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);
+
+  spec = spec_from_name (name);
+  xfree (name);
   name = NULL;
-  if (!module)
+  if (!spec)
     {
       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. */
-  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. */
-
-  /* Handle the optional qbits element. */
-  l2 = gcry_sexp_find_token (list, "qbits", 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;
-      qbits = (unsigned int)strtoul (buf, NULL, 0);
-      gcry_sexp_release (l2);
-      l2 = NULL;
-    }
+  if (spec->generate)
+    rc = spec->generate (list, r_key);
   else
-    qbits = 0;
-
-  /* Parse the optional xvalue element. */
-  l2 = gcry_sexp_find_token (list, "xvalue", 0);
-  if (l2)
-    {
-      xvalue = gcry_sexp_nth_mpi (l2, 1, 0);
-      if (!xvalue)
-        {
-          rc = GPG_ERR_BAD_MPI;
-          goto leave;
-        }
-    }
-
-  /* Parse the optional "curve" parameter. */
-  l2 = gcry_sexp_find_token (list, "curve", 0);
-  if (l2)
-    {
-      curve = _gcry_sexp_nth_string (l2, 1);
-      if (!curve)
-        {
-          rc = GPG_ERR_INV_OBJ; /* No curve name or value too large. */
-          goto leave;
-        }
-      gcry_sexp_release (l2);
-      l2 = NULL;
-    }
-
-  /* Parse the optional "transient-key" flag. */
-  l2 = gcry_sexp_find_token (list, "transient-key", 0);
-  if (l2)
-    {
-      keygen_flags |= PUBKEY_FLAG_TRANSIENT_KEY;
-      gcry_sexp_release (l2);
-      l2 = NULL;
-    }
-
-
-  /* Unless a curve name has been given, the "nbits" parameter is
-     required.  */
-  l2 = gcry_sexp_find_token (list, "nbits", 0);
-  gcry_sexp_release (list);
-  list = l2;
-  l2 = NULL;
-  if (!list && !curve)
-    {
-      rc = GPG_ERR_NO_OBJ; /* No nbits parameter. */
-      goto leave;
-    }
-  if (list)
-    {
-      char buf[50];
-      const char *s;
-
-      s = gcry_sexp_nth_data (list, 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);
-    }
-  else 
-    nbits = 0;
-
-  rc = pubkey_generate (module->mod_id, nbits, qbits, use_e, xvalue,
-                        curve, keygen_flags, skey, &factors);
-  if (rc)
-    goto leave;
-
-  {
-    char *string, *p;
-    size_t nelem=0, nelem_cp = 0, needed=0;
-    gcry_mpi_t mpis[30];
-    
-    nelem = strlen (pub_elems) + strlen (sec_elems);
-    for (i = 0; factors[i]; i++)
-      nelem++;
-    nelem_cp = nelem;
-
-    needed += nelem * 10;
-    needed += 2 * strlen (algo_name) + 300;
-    if (nelem > DIM (mpis))
-      BUG ();
-
-    /* Build the string. */
-    nelem = 0;
-    string = p = gcry_malloc (needed);
-    if (!string)
-      {
-        rc = gpg_err_code_from_errno (errno);
-        goto leave;
-      }
-    p = stpcpy (p, "(key-data");
-    p = stpcpy (p, "(public-key(");
-    p = stpcpy (p, algo_name);
-    for(i = 0; pub_elems[i]; i++)
-      {
-        *p++ = '(';
-        *p++ = pub_elems[i];
-        p = stpcpy (p, "%m)");
-        mpis[nelem++] = skey[i];
-      }
-    p = stpcpy (p, "))");
-    p = stpcpy (p, "(private-key(");
-    p = stpcpy (p, algo_name);
-    for (i = 0; sec_elems[i]; i++)
-      {
-        *p++ = '(';
-        *p++ = sec_elems[i];
-        p = stpcpy (p, "%m)");
-        mpis[nelem++] = skey[i];
-      }
-    p = stpcpy (p, "))");
-
-    /* Very ugly hack to make release_mpi_array() work FIXME */
-    skey[i] = NULL;
-
-    if (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;
-
-      arg_list = malloc (nelem_cp * sizeof *arg_list);
-      if (!arg_list)
-        {
-          rc = gpg_err_code_from_errno (errno);
-          goto leave;
-        }
-      for (i = 0; i < elem_n; i++)
-        arg_list[i] = mpis + i;
-      for (; i < nelem_cp; i++)
-        arg_list[i] = factors + i - elem_n;
-      
-      rc = gcry_sexp_build_array (r_key, NULL, string, arg_list);
-      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);
-  }
+    rc = GPG_ERR_NOT_IMPLEMENTED;
 
  leave:
-  gcry_free (name);
-  gcry_free (curve);
-  release_mpi_array (skey);
-  /* Don't free SKEY itself, it is a static array. */
-
-  gcry_mpi_release (xvalue);
-  
-  if (factors)
-    {
-      release_mpi_array ( factors );
-      gcry_free (factors);
-    }
-  
-  if (l2)
-    gcry_sexp_release (l2);
-  if (list)
-    gcry_sexp_release (list);
-
-  if (module)
-    {
-      ath_mutex_lock (&pubkeys_registered_lock);
-      _gcry_module_release (module);
-      ath_mutex_unlock (&pubkeys_registered_lock);
-    }
+  sexp_release (list);
+  xfree (name);
+  sexp_release (l2);
 
-  return gcry_error (rc);
+  return 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_pk_get_nbits (gcry_sexp_t key)
 {
-  gcry_module_t module = NULL;
-  gcry_pk_spec_t *pubkey;
-  gcry_mpi_t *keyarr = NULL;
-  unsigned int nbits = 0;
-  gcry_err_code_t rc;
-
-  REGISTER_DEFAULT_PUBKEYS;
-
-  rc = sexp_to_key (key, 0, &keyarr, &module);
-  if (rc == GPG_ERR_INV_OBJ)
-    rc = sexp_to_key (key, 1, &keyarr, &module);
-  if (rc)
-    return 0; /* Error - 0 is a suitable indication for that. */
+  gcry_pk_spec_t *spec;
+  gcry_sexp_t parms;
+  unsigned int nbits;
 
-  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);
+  /* Parsing KEY might be considered too much overhead.  For example
+     for RSA we would only need to look at P and stop parsing right
+     away.  However, with ECC things are more complicate in that only
+     a curve name might be specified.  Thus we need to tear the sexp
+     apart. */
 
-  release_mpi_array (keyarr);
-  gcry_free (keyarr);
+  if (spec_from_sexp (key, 0, &spec, &parms))
+    return 0; /* Error - 0 is a suitable indication for that.  */
 
+  nbits = spec->get_nbits (parms);
+  sexp_release (parms);
   return nbits;
 }
 
 
 /* Return the so called KEYGRIP which is the SHA-1 hash of the public
-   key parameters expressed in a way depended on the algorithm.
+   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_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;
+  gcry_sexp_t list = NULL;
+  gcry_sexp_t l2 = NULL;
+  gcry_pk_spec_t *spec = NULL;
   const char *s;
   char *name = NULL;
   int idx;
   const char *elems;
   gcry_md_hd_t md = NULL;
-
-  REGISTER_DEFAULT_PUBKEYS;
+  int okay = 0;
 
   /* Check that the first element is valid. */
-  list = gcry_sexp_find_token (key, "public-key", 0);
+  list = sexp_find_token (key, "public-key", 0);
   if (! list)
-    list = gcry_sexp_find_token (key, "private-key", 0);
+    list = sexp_find_token (key, "private-key", 0);
   if (! list)
-    list = gcry_sexp_find_token (key, "protected-private-key", 0);
+    list = sexp_find_token (key, "protected-private-key", 0);
   if (! list)
-    list = gcry_sexp_find_token (key, "shadowed-private-key", 0);
+    list = 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);
+  l2 = sexp_cadr (list);
+  sexp_release (list);
   list = l2;
   l2 = NULL;
 
@@ -2461,27 +655,21 @@ gcry_pk_get_keygrip (gcry_sexp_t key, unsigned char *array)
   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)
+  spec = spec_from_name (name);
+  if (!spec)
     goto fail; /* Unknown algorithm.  */
 
-  pubkey = (gcry_pk_spec_t *) module->spec;
-  extraspec = module->extraspec;
-
-  elems = pubkey->elements_grip;
+  elems = spec->elements_grip;
   if (!elems)
     goto fail; /* No grip parameter.  */
-    
-  if (gcry_md_open (&md, GCRY_MD_SHA1, 0))
+
+  if (_gcry_md_open (&md, GCRY_MD_SHA1, 0))
     goto fail;
 
-  if (extraspec && extraspec->comp_keygrip)
+  if (spec->comp_keygrip)
     {
       /* Module specific method to compute a keygrip.  */
-      if (extraspec->comp_keygrip (md, list))
+      if (spec->comp_keygrip (md, list))
         goto fail;
     }
   else
@@ -2492,49 +680,102 @@ gcry_pk_get_keygrip (gcry_sexp_t key, unsigned char *array)
           const char *data;
           size_t datalen;
           char buf[30];
-          
-          l2 = gcry_sexp_find_token (list, s, 1);
+
+          l2 = sexp_find_token (list, s, 1);
           if (! l2)
             goto fail;
-          data = gcry_sexp_nth_data (l2, 1, &datalen);
+          data = sexp_nth_data (l2, 1, &datalen);
           if (! data)
             goto fail;
-          
+
           snprintf (buf, sizeof buf, "(1:%c%u:", *s, (unsigned int)datalen);
-          gcry_md_write (md, buf, strlen (buf));
-          gcry_md_write (md, data, datalen);
-          gcry_sexp_release (l2);
-          gcry_md_write (md, ")", 1);
+          _gcry_md_write (md, buf, strlen (buf));
+          _gcry_md_write (md, data, datalen);
+          sexp_release (l2);
+          l2 = NULL;
+          _gcry_md_write (md, ")", 1);
         }
     }
-  
+
   if (!array)
     {
-      array = gcry_malloc (20);
+      array = xtrymalloc (20);
       if (! array)
         goto fail;
     }
 
-  memcpy (array, gcry_md_read (md, GCRY_MD_SHA1), 20);
-  gcry_md_close (md);
-  gcry_sexp_release (list);
-  return array;
+  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 NULL;
+  xfree (name);
+  sexp_release (l2);
+  _gcry_md_close (md);
+  sexp_release (list);
+  return okay? array : NULL;
+}
+
+
+\f
+const char *
+_gcry_pk_get_curve (gcry_sexp_t key, int iterator, unsigned int *r_nbits)
+{
+  const char *result = NULL;
+  gcry_pk_spec_t *spec;
+  gcry_sexp_t keyparms = NULL;
+
+  if (r_nbits)
+    *r_nbits = 0;
+
+  if (key)
+    {
+      iterator = 0;
+
+      if (spec_from_sexp (key, 0, &spec, &keyparms))
+        return NULL;
+    }
+  else
+    {
+      spec = spec_from_name ("ecc");
+      if (!spec)
+        return NULL;
+    }
+
+  if (spec->get_curve)
+    result = spec->get_curve (keyparms, iterator, r_nbits);
+
+  sexp_release (keyparms);
+  return result;
 }
 
 
-gcry_error_t
-gcry_pk_ctl (int cmd, void *buffer, size_t buflen)
+\f
+gcry_sexp_t
+_gcry_pk_get_param (int algo, const char *name)
 {
-  gcry_err_code_t err = GPG_ERR_NO_ERROR;
+  gcry_sexp_t result = NULL;
+  gcry_pk_spec_t *spec = NULL;
+
+  algo = map_algo (algo);
+
+  if (algo != GCRY_PK_ECC)
+    return NULL;
+
+  spec = spec_from_name ("ecc");
+  if (spec)
+    {
+      if (spec && spec->get_curve_param)
+        result = spec->get_curve_param (name);
+    }
+  return result;
+}
+
 
-  REGISTER_DEFAULT_PUBKEYS;
+\f
+gcry_err_code_t
+_gcry_pk_ctl (int cmd, void *buffer, size_t buflen)
+{
+  gcry_err_code_t rc = 0;
 
   switch (cmd)
     {
@@ -2542,16 +783,16 @@ gcry_pk_ctl (int cmd, void *buffer, size_t buflen)
       /* This one expects a buffer pointing to an integer with the
          algo number.  */
       if ((! buffer) || (buflen != sizeof (int)))
-       err = GPG_ERR_INV_ARG;
+       rc = GPG_ERR_INV_ARG;
       else
        disable_pubkey_algo (*((int *) buffer));
       break;
 
     default:
-      err = GPG_ERR_INV_OP;
+      rc = GPG_ERR_INV_OP;
     }
 
-  return gcry_error (err);
+  return rc;
 }
 
 
@@ -2566,20 +807,20 @@ gcry_pk_ctl (int cmd, void *buffer, size_t buflen)
         care or a combination of the GCRY_PK_USAGE_xxx flags;
 
     GCRYCTL_GET_ALGO_USAGE:
-        Return the usage glafs for the give algo.  An invalid alog
-        does return 0.  Disabled algos are ignored here becuase we
+        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 occured or not (i.e. while
+   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
+_gcry_pk_algo_info (int algorithm, int what, void *buffer, size_t *nbytes)
 {
-  gcry_err_code_t err = GPG_ERR_NO_ERROR;
+  gcry_err_code_t rc = 0;
 
   switch (what)
     {
@@ -2587,31 +828,18 @@ gcry_pk_algo_info (int algorithm, int what, void *buffer, size_t *nbytes)
       {
        int use = nbytes ? *nbytes : 0;
        if (buffer)
-         err = GPG_ERR_INV_ARG;
+         rc = GPG_ERR_INV_ARG;
        else if (check_pubkey_algo (algorithm, use))
-         err = GPG_ERR_PUBKEY_ALGO;
+         rc = 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;
+       gcry_pk_spec_t *spec;
 
+       spec = spec_from_algo (algorithm);
+        *nbytes = spec? spec->use : 0;
        break;
       }
 
@@ -2645,69 +873,71 @@ gcry_pk_algo_info (int algorithm, int what, void *buffer, size_t *nbytes)
       }
 
     default:
-      err = GPG_ERR_INV_OP;
+      rc = GPG_ERR_INV_OP;
     }
 
-  return gcry_error (err);
+  return rc;
 }
 
 
-/* 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;
-}
-
+/* Return an S-expression representing the context CTX.  Depending on
+   the state of that context, the S-expression may either be a public
+   key, a private key or any other object used with public key
+   operations.  On success a new S-expression is stored at R_SEXP and
+   0 is returned, on error NULL is store there and an error code is
+   returned.  MODE is either 0 or one of the GCRY_PK_GET_xxx values.
 
+   As of now it only support certain ECC operations because a context
+   object is right now only defined for ECC.  Over time this function
+   will be extended to cover more algorithms.  Note also that the name
+   of the function is gcry_pubkey_xxx and not gcry_pk_xxx.  The idea
+   is that we will eventually provide variants of the existing
+   gcry_pk_xxx functions which will take a context parameter.   */
 gcry_err_code_t
-_gcry_pk_module_lookup (int algorithm, gcry_module_t *module)
+_gcry_pubkey_get_sexp (gcry_sexp_t *r_sexp, int mode, gcry_ctx_t ctx)
 {
-  gcry_err_code_t err = GPG_ERR_NO_ERROR;
-  gcry_module_t pubkey;
+  mpi_ec_t ec;
 
-  REGISTER_DEFAULT_PUBKEYS;
+  if (!r_sexp)
+    return GPG_ERR_INV_VALUE;
+  *r_sexp = NULL;
+  switch (mode)
+    {
+    case 0:
+    case GCRY_PK_GET_PUBKEY:
+    case GCRY_PK_GET_SECKEY:
+      break;
+    default:
+      return GPG_ERR_INV_VALUE;
+    }
+  if (!ctx)
+    return GPG_ERR_NO_CRYPT_CTX;
 
-  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);
+  ec = _gcry_ctx_find_pointer (ctx, CONTEXT_TYPE_EC);
+  if (ec)
+    return _gcry_pk_ecc_get_sexp (r_sexp, mode, ec);
 
-  return err;
+  return GPG_ERR_WRONG_CRYPT_CTX;
 }
 
 
-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)
+\f
+/* Explicitly initialize this module.  */
+gcry_err_code_t
+_gcry_pk_init (void)
 {
-  gcry_err_code_t err = GPG_ERR_NO_ERROR;
+  if (fips_mode())
+    {
+      /* disable algorithms that are disallowed in fips */
+      int idx;
+      gcry_pk_spec_t *spec;
 
-  ath_mutex_lock (&pubkeys_registered_lock);
-  err = _gcry_module_list (pubkeys_registered, list, list_length);
-  ath_mutex_unlock (&pubkeys_registered_lock);
+      for (idx = 0; (spec = pubkey_list[idx]); idx++)
+        if (!spec->flags.fips)
+          spec->flags.disabled = 1;
+    }
 
-  return err;
+  return 0;
 }
 
 
@@ -2716,97 +946,25 @@ gcry_pk_list (int *list, int *list_length)
 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);
+  gcry_err_code_t ec;
+  gcry_pk_spec_t *spec;
+
+  algo = map_algo (algo);
+  spec = spec_from_algo (algo);
+  if (spec && !spec->flags.disabled && spec->selftest)
+    ec = spec->selftest (algo, extended, report);
   else
     {
       ec = GPG_ERR_PUBKEY_ALGO;
+      /* Fixme: We need to change the report function to allow passing
+         of an encryption mode (e.g. pkcs1, ecdsa, or ecdh).  */
       if (report)
-        report ("pubkey", algo, "module", 
-                module && !(module->flags & FLAG_MODULE_DISABLED)?
+        report ("pubkey", algo, "module",
+                spec && !spec->flags.disabled?
                 "no selftest available" :
-                module? "algorithm disabled" : "algorithm not found");
+                spec? "algorithm disabled" :
+                "algorithm not found");
     }
 
-  if (module)
-    {
-      ath_mutex_lock (&pubkeys_registered_lock);
-      _gcry_module_release (module);
-      ath_mutex_unlock (&pubkeys_registered_lock);
-    }
   return gpg_error (ec);
 }
-
-
-/* This function is only used by ac.c!  */
-gcry_err_code_t
-_gcry_pk_get_elements (int algo, char **enc, char **sig)
-{
-  gcry_module_t pubkey;
-  gcry_pk_spec_t *spec;
-  gcry_err_code_t err;
-  char *enc_cp;
-  char *sig_cp;
-
-  REGISTER_DEFAULT_PUBKEYS;
-
-  enc_cp = NULL;
-  sig_cp = NULL;
-  spec = NULL;
-
-  pubkey = _gcry_module_lookup_id (pubkeys_registered, algo);
-  if (! pubkey)
-    {
-      err = GPG_ERR_INTERNAL;
-      goto out;
-    }
-  spec = pubkey->spec;
-
-  if (enc)
-    {
-      enc_cp = strdup (spec->elements_enc);
-      if (! enc_cp)
-       {
-         err = gpg_err_code_from_errno (errno);
-         goto out;
-       }
-    }
-  
-  if (sig)
-    {
-      sig_cp = strdup (spec->elements_sig);
-      if (! sig_cp)
-       {
-         err = gpg_err_code_from_errno (errno);
-         goto out;
-       }
-    }
-
-  if (enc)
-    *enc = enc_cp;
-  if (sig)
-    *sig = sig_cp;
-  err = 0;
-
- out:
-
-  _gcry_module_release (pubkey);
-  if (err)
-    {
-      free (enc_cp);
-      free (sig_cp);
-    }
-
-  return err;
-}