* random.c: Fix prototype of the fast random gatherer. Noted by Joe
[gnupg.git] / cipher / pubkey.c
index 4def6f6..d6d1ff1 100644 (file)
@@ -1,5 +1,6 @@
 /* pubkey.c  - pubkey dispatcher
- *     Copyright (C) 1998, 1999 Free Software Foundation, Inc.
+ * Copyright (C) 1998, 1999, 2000, 2001, 2003,
+ *               2004 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
@@ -15,7 +16,8 @@
  *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ * USA.
  */
 
 #include <config.h>
 #include <string.h>
 #include <errno.h>
 #include <assert.h>
-
-#include "g10lib.h"
+#include "util.h"
+#include "errors.h"
 #include "mpi.h"
 #include "cipher.h"
 #include "elgamal.h"
 #include "dsa.h"
-#include "dynload.h"
-
-/* FIXME: use set_lasterr() */
+#include "rsa.h"
 
 #define TABLE_SIZE 10
 
@@ -49,86 +49,45 @@ struct pubkey_table_s {
     int (*encrypt)( int algo, MPI *resarr, MPI data, MPI *pkey );
     int (*decrypt)( int algo, MPI *result, MPI *data, MPI *skey );
     int (*sign)( int algo, MPI *resarr, MPI data, MPI *skey );
-    int (*verify)( int algo, MPI hash, MPI *data, MPI *pkey,
-                  int (*cmp)(void *, MPI), void *opaquev );
+    int (*verify)( int algo, MPI hash, MPI *data, MPI *pkey );
     unsigned (*get_nbits)( int algo, MPI *pkey );
 };
 
 static struct pubkey_table_s pubkey_table[TABLE_SIZE];
 static int disabled_algos[TABLE_SIZE];
 
-static struct { const char* name; int algo;
-               const char* common_elements;
-               const char* public_elements;
-               const char* secret_elements;
-} algo_info_table[] = {
-       {  "dsa"            , PUBKEY_ALGO_DSA       , "pqgy", "", "x"    },
-       {  "rsa"            , PUBKEY_ALGO_RSA       , "ne",   "", "dpqu" },
-       {  "elg"            , PUBKEY_ALGO_ELGAMAL   , "pgy",  "", "x"    },
-       {  "openpgp-dsa"    , PUBKEY_ALGO_DSA       , "pqgy", "", "x"    },
-       {  "openpgp-rsa"    , PUBKEY_ALGO_RSA       , "pqgy", "", "x"    },
-       {  "openpgp-elg"    , PUBKEY_ALGO_ELGAMAL_E , "pgy",  "", "x"    },
-       {  "openpgp-elg-sig", PUBKEY_ALGO_ELGAMAL   , "pgy",  "", "x"    },
-       {  NULL }};
-
-static struct {
-    const char* name; int algo;
-    const char* elements;
-} sig_info_table[] = {
-       {  "dsa"            , PUBKEY_ALGO_DSA       , "rs" },
-       {  "rsa"            , PUBKEY_ALGO_RSA       , "s"  },
-       {  "elg"            , PUBKEY_ALGO_ELGAMAL   , "rs" },
-       {  "openpgp-dsa"    , PUBKEY_ALGO_DSA       , "rs" },
-       {  "openpgp-rsa"    , PUBKEY_ALGO_RSA       , "s"  },
-       {  "openpgp-elg-sig", PUBKEY_ALGO_ELGAMAL   , "rs" },
-       {  NULL }};
-
-static struct {
-    const char* name; int algo;
-    const char* elements;
-} enc_info_table[] = {
-       {  "elg"            , PUBKEY_ALGO_ELGAMAL   , "ab" },
-       {  "rsa"            , PUBKEY_ALGO_RSA       , "a"  },
-       {  "openpgp-rsa"    , PUBKEY_ALGO_RSA       , "a"  },
-       {  "openpgp-elg"    , PUBKEY_ALGO_ELGAMAL_E , "ab" },
-       {  "openpgp-elg-sig", PUBKEY_ALGO_ELGAMAL   , "ab" },
-       {  NULL }};
-
-
-static int pubkey_decrypt( int algo, MPI *result, MPI *data, MPI *skey );
-static int pubkey_sign( int algo, MPI *resarr, MPI hash, MPI *skey );
-static int pubkey_verify( int algo, MPI hash, MPI *data, MPI *pkey,
-                     int (*cmp)(void *, MPI), void *opaque );
 
+#if 0
 static int
 dummy_generate( int algo, unsigned nbits, MPI *skey, MPI **retfactors )
-{ log_bug("no generate() for %d\n", algo ); return GCRYERR_INV_PK_ALGO; }
+{ log_bug("no generate() for %d\n", algo ); return G10ERR_PUBKEY_ALGO; }
 
 static int
 dummy_check_secret_key( int algo, MPI *skey )
-{ log_bug("no check_secret_key() for %d\n", algo ); return GCRYERR_INV_PK_ALGO; }
+{ log_bug("no check_secret_key() for %d\n", algo ); return G10ERR_PUBKEY_ALGO; }
+#endif
 
 static int
 dummy_encrypt( int algo, MPI *resarr, MPI data, MPI *pkey )
-{ log_bug("no encrypt() for %d\n", algo ); return GCRYERR_INV_PK_ALGO; }
+{ log_bug("no encrypt() for %d\n", algo ); return G10ERR_PUBKEY_ALGO; }
 
 static int
 dummy_decrypt( int algo, MPI *result, MPI *data, MPI *skey )
-{ log_bug("no decrypt() for %d\n", algo ); return GCRYERR_INV_PK_ALGO; }
+{ log_bug("no decrypt() for %d\n", algo ); return G10ERR_PUBKEY_ALGO; }
 
 static int
 dummy_sign( int algo, MPI *resarr, MPI data, MPI *skey )
-{ log_bug("no sign() for %d\n", algo ); return GCRYERR_INV_PK_ALGO; }
+{ log_bug("no sign() for %d\n", algo ); return G10ERR_PUBKEY_ALGO; }
 
 static int
-dummy_verify( int algo, MPI hash, MPI *data, MPI *pkey,
-               int (*cmp)(void *, MPI), void *opaquev )
-{ log_bug("no verify() for %d\n", algo ); return GCRYERR_INV_PK_ALGO; }
+dummy_verify( int algo, MPI hash, MPI *data, MPI *pkey )
+{ log_bug("no verify() for %d\n", algo ); return G10ERR_PUBKEY_ALGO; }
 
+#if 0
 static unsigned
 dummy_get_nbits( int algo, MPI *pkey )
 { log_bug("no get_nbits() for %d\n", algo ); return 0; }
-
+#endif
 
 /****************
  * Put the static entries into the table.
@@ -138,26 +97,8 @@ dummy_get_nbits( int algo, MPI *pkey )
 static void
 setup_pubkey_table(void)
 {
-    int i;
+    int i=0;
 
-    i = 0;
-    pubkey_table[i].algo = PUBKEY_ALGO_ELGAMAL;
-    pubkey_table[i].name = elg_get_info( pubkey_table[i].algo,
-                                        &pubkey_table[i].npkey,
-                                        &pubkey_table[i].nskey,
-                                        &pubkey_table[i].nenc,
-                                        &pubkey_table[i].nsig,
-                                        &pubkey_table[i].use );
-    pubkey_table[i].generate        = elg_generate;
-    pubkey_table[i].check_secret_key = elg_check_secret_key;
-    pubkey_table[i].encrypt         = elg_encrypt;
-    pubkey_table[i].decrypt         = elg_decrypt;
-    pubkey_table[i].sign            = elg_sign;
-    pubkey_table[i].verify          = elg_verify;
-    pubkey_table[i].get_nbits       = elg_get_nbits;
-    if( !pubkey_table[i].name )
-       BUG();
-    i++;
     pubkey_table[i].algo = PUBKEY_ALGO_ELGAMAL_E;
     pubkey_table[i].name = elg_get_info( pubkey_table[i].algo,
                                         &pubkey_table[i].npkey,
@@ -169,8 +110,8 @@ setup_pubkey_table(void)
     pubkey_table[i].check_secret_key = elg_check_secret_key;
     pubkey_table[i].encrypt         = elg_encrypt;
     pubkey_table[i].decrypt         = elg_decrypt;
-    pubkey_table[i].sign            = elg_sign;
-    pubkey_table[i].verify          = elg_verify;
+    pubkey_table[i].sign            = dummy_sign;
+    pubkey_table[i].verify          = dummy_verify;
     pubkey_table[i].get_nbits       = elg_get_nbits;
     if( !pubkey_table[i].name )
        BUG();
@@ -193,18 +134,64 @@ setup_pubkey_table(void)
        BUG();
     i++;
 
+#ifdef USE_RSA
+    pubkey_table[i].algo = PUBKEY_ALGO_RSA;
+    pubkey_table[i].name = rsa_get_info( pubkey_table[i].algo,
+                                        &pubkey_table[i].npkey,
+                                        &pubkey_table[i].nskey,
+                                        &pubkey_table[i].nenc,
+                                        &pubkey_table[i].nsig,
+                                        &pubkey_table[i].use );
+    pubkey_table[i].generate        = rsa_generate;
+    pubkey_table[i].check_secret_key = rsa_check_secret_key;
+    pubkey_table[i].encrypt         = rsa_encrypt;
+    pubkey_table[i].decrypt         = rsa_decrypt;
+    pubkey_table[i].sign            = rsa_sign;
+    pubkey_table[i].verify          = rsa_verify;
+    pubkey_table[i].get_nbits       = rsa_get_nbits;
+    if( !pubkey_table[i].name )
+       BUG();
+    i++;
+    pubkey_table[i].algo = PUBKEY_ALGO_RSA_E;
+    pubkey_table[i].name = rsa_get_info( pubkey_table[i].algo,
+                                        &pubkey_table[i].npkey,
+                                        &pubkey_table[i].nskey,
+                                        &pubkey_table[i].nenc,
+                                        &pubkey_table[i].nsig,
+                                        &pubkey_table[i].use );
+    pubkey_table[i].generate        = rsa_generate;
+    pubkey_table[i].check_secret_key = rsa_check_secret_key;
+    pubkey_table[i].encrypt         = rsa_encrypt;
+    pubkey_table[i].decrypt         = rsa_decrypt;
+    pubkey_table[i].sign            = dummy_sign;
+    pubkey_table[i].verify          = dummy_verify;
+    pubkey_table[i].get_nbits       = rsa_get_nbits;
+    if( !pubkey_table[i].name )
+       BUG();
+    i++;
+    pubkey_table[i].algo = PUBKEY_ALGO_RSA_S;
+    pubkey_table[i].name = rsa_get_info( pubkey_table[i].algo,
+                                        &pubkey_table[i].npkey,
+                                        &pubkey_table[i].nskey,
+                                        &pubkey_table[i].nenc,
+                                        &pubkey_table[i].nsig,
+                                        &pubkey_table[i].use );
+    pubkey_table[i].generate        = rsa_generate;
+    pubkey_table[i].check_secret_key = rsa_check_secret_key;
+    pubkey_table[i].encrypt         = dummy_encrypt;
+    pubkey_table[i].decrypt         = dummy_decrypt;
+    pubkey_table[i].sign            = rsa_sign;
+    pubkey_table[i].verify          = rsa_verify;
+    pubkey_table[i].get_nbits       = rsa_get_nbits;
+    if( !pubkey_table[i].name )
+       BUG();
+    i++;
+#endif /* USE_RSA */
+
     for( ; i < TABLE_SIZE; i++ )
        pubkey_table[i].name = NULL;
 }
 
-static void
-release_mpi_array( MPI *array )
-{
-    for( ; *array; array++ ) {
-       mpi_free(*array);
-       *array = NULL;
-    }
-}
 
 /****************
  * Try to load all modules and return true if new modules are available
@@ -213,73 +200,13 @@ static int
 load_pubkey_modules(void)
 {
     static int initialized = 0;
-    static int done = 0;
-    void *context = NULL;
-    struct pubkey_table_s *ct;
-    int ct_idx;
-    int i;
-    const char *name;
-    int any = 0;
-
 
     if( !initialized ) {
-       cipher_modules_constructor();
        setup_pubkey_table();
        initialized = 1;
        return 1;
     }
-    if( done )
-       return 0;
-    done = 1;
-    for(ct_idx=0, ct = pubkey_table; ct_idx < TABLE_SIZE; ct_idx++,ct++ ) {
-       if( !ct->name )
-           break;
-    }
-    if( ct_idx >= TABLE_SIZE-1 )
-       BUG(); /* table already full */
-    /* now load all extensions */
-    while( (name = enum_gnupgext_pubkeys( &context, &ct->algo,
-                               &ct->npkey, &ct->nskey, &ct->nenc,
-                               &ct->nsig,  &ct->use,
-                               &ct->generate,
-                               &ct->check_secret_key,
-                               &ct->encrypt,
-                               &ct->decrypt,
-                               &ct->sign,
-                               &ct->verify,
-                               &ct->get_nbits )) ) {
-       for(i=0; pubkey_table[i].name; i++ )
-           if( pubkey_table[i].algo == ct->algo )
-               break;
-       if( pubkey_table[i].name ) {
-           log_info("skipping pubkey %d: already loaded\n", ct->algo );
-           continue;
-       }
-
-       if( !ct->generate  )  ct->generate = dummy_generate;
-       if( !ct->check_secret_key )  ct->check_secret_key =
-                                                   dummy_check_secret_key;
-       if( !ct->encrypt   )  ct->encrypt  = dummy_encrypt;
-       if( !ct->decrypt   )  ct->decrypt  = dummy_decrypt;
-       if( !ct->sign      )  ct->sign     = dummy_sign;
-       if( !ct->verify    )  ct->verify   = dummy_verify;
-       if( !ct->get_nbits )  ct->get_nbits= dummy_get_nbits;
-       /* put it into the table */
-       if( g10_log_verbosity( 2 ) )
-           log_info("loaded pubkey %d (%s)\n", ct->algo, name);
-       ct->name = name;
-       ct_idx++;
-       ct++;
-       any = 1;
-       /* check whether there are more available table slots */
-       if( ct_idx >= TABLE_SIZE-1 ) {
-           log_info("pubkey table full; ignoring other extensions\n");
-           break;
-       }
-    }
-    enum_gnupgext_pubkeys( &context, NULL, NULL, NULL, NULL, NULL, NULL,
-                              NULL, NULL, NULL, NULL, NULL, NULL, NULL );
-    return any;
+    return 0;
 }
 
 
@@ -287,14 +214,14 @@ load_pubkey_modules(void)
  * Map a string to the pubkey algo
  */
 int
-gcry_pk_map_name( const char *string )
+string_to_pubkey_algo( const char *string )
 {
     int i;
     const char *s;
 
     do {
        for(i=0; (s=pubkey_table[i].name); i++ )
-           if( !stricmp( s, string ) )
+           if( !ascii_strcasecmp( s, string ) )
                return pubkey_table[i].algo;
     } while( load_pubkey_modules() );
     return 0;
@@ -305,7 +232,7 @@ gcry_pk_map_name( const char *string )
  * Map a pubkey algo to a string
  */
 const char *
-gcry_pk_algo_name( int algo )
+pubkey_algo_to_string( int algo )
 {
     int i;
 
@@ -318,7 +245,7 @@ gcry_pk_algo_name( int algo )
 }
 
 
-static void
+void
 disable_pubkey_algo( int algo )
 {
     int i;
@@ -333,32 +260,38 @@ disable_pubkey_algo( int algo )
 }
 
 
+int
+check_pubkey_algo( int algo )
+{
+    return check_pubkey_algo2( algo, 0 );
+}
+
 /****************
  * a use of 0 means: don't care
  */
-static int
-check_pubkey_algo( int algo, unsigned use )
+int
+check_pubkey_algo2( int algo, unsigned use )
 {
     int i;
 
     do {
        for(i=0; pubkey_table[i].name; i++ )
            if( pubkey_table[i].algo == algo ) {
-               if( (use & GCRY_PK_USAGE_SIGN)
-                   && !(pubkey_table[i].use & GCRY_PK_USAGE_SIGN) )
-                   return GCRYERR_WRONG_PK_ALGO;
-               if( (use & GCRY_PK_USAGE_ENCR)
-                   && !(pubkey_table[i].use & GCRY_PK_USAGE_ENCR) )
-                   return GCRYERR_WRONG_PK_ALGO;
+               if( (use & PUBKEY_USAGE_SIG)
+                   && !(pubkey_table[i].use & PUBKEY_USAGE_SIG) )
+                   return G10ERR_WR_PUBKEY_ALGO;
+               if( (use & PUBKEY_USAGE_ENC)
+                   && !(pubkey_table[i].use & PUBKEY_USAGE_ENC) )
+                   return G10ERR_WR_PUBKEY_ALGO;
 
                for(i=0; i < DIM(disabled_algos); i++ ) {
                    if( disabled_algos[i] == algo )
-                       return GCRYERR_INV_PK_ALGO;
+                       return G10ERR_PUBKEY_ALGO;
                }
                return 0; /* okay */
            }
     } while( load_pubkey_modules() );
-    return GCRYERR_INV_PK_ALGO;
+    return G10ERR_PUBKEY_ALGO;
 }
 
 
@@ -367,7 +300,7 @@ check_pubkey_algo( int algo, unsigned use )
 /****************
  * Return the number of public key material numbers
  */
-static int
+int
 pubkey_get_npkey( int algo )
 {
     int i;
@@ -376,15 +309,22 @@ pubkey_get_npkey( int algo )
            if( pubkey_table[i].algo == algo )
                return pubkey_table[i].npkey;
     } while( load_pubkey_modules() );
+
+#ifndef USE_RSA
     if( is_RSA(algo) )   /* special hack, so that we are able to */
        return 2;         /* see the RSA keyids */
+#endif /* USE_RSA */
+
+    if(algo==PUBKEY_ALGO_ELGAMAL)
+      return 3;
+
     return 0;
 }
 
 /****************
  * Return the number of secret key material numbers
  */
-static int
+int
 pubkey_get_nskey( int algo )
 {
     int i;
@@ -393,15 +333,22 @@ pubkey_get_nskey( int algo )
            if( pubkey_table[i].algo == algo )
                return pubkey_table[i].nskey;
     } while( load_pubkey_modules() );
+
+#ifndef USE_RSA
     if( is_RSA(algo) )   /* special hack, so that we are able to */
        return 6;         /* see the RSA keyids */
+#endif /* USE_RSA */
+
+    if(algo==PUBKEY_ALGO_ELGAMAL)
+      return 4;
+
     return 0;
 }
 
 /****************
  * Return the number of signature material numbers
  */
-static int
+int
 pubkey_get_nsig( int algo )
 {
     int i;
@@ -410,15 +357,22 @@ pubkey_get_nsig( int algo )
            if( pubkey_table[i].algo == algo )
                return pubkey_table[i].nsig;
     } while( load_pubkey_modules() );
+
+#ifndef USE_RSA
     if( is_RSA(algo) )   /* special hack, so that we are able to */
        return 1;         /* see the RSA keyids */
+#endif /* USE_RSA */
+
+    if(algo==PUBKEY_ALGO_ELGAMAL)
+      return 2;
+
     return 0;
 }
 
 /****************
  * Return the number of encryption material numbers
  */
-static int
+int
 pubkey_get_nenc( int algo )
 {
     int i;
@@ -427,13 +381,45 @@ pubkey_get_nenc( int algo )
            if( pubkey_table[i].algo == algo )
                return pubkey_table[i].nenc;
     } while( load_pubkey_modules() );
+
+#ifndef USE_RSA
     if( is_RSA(algo) )   /* special hack, so that we are able to */
        return 1;         /* see the RSA keyids */
+#endif /* USE_RSA */
+
+    if(algo==PUBKEY_ALGO_ELGAMAL)
+      return 2;
+
     return 0;
 }
 
+/****************
+ * Get the number of nbits from the public key
+ */
+unsigned
+pubkey_nbits( int algo, MPI *pkey )
+{
+    int i;
 
-static int
+    do {
+       for(i=0; pubkey_table[i].name; i++ )
+           if( pubkey_table[i].algo == algo )
+               return (*pubkey_table[i].get_nbits)( algo, pkey );
+    } while( load_pubkey_modules() );
+
+#ifndef USE_RSA
+    if( is_RSA(algo) ) /* we always wanna see the length of a key :-) */
+       return mpi_get_nbits( pkey[0] );
+#endif /* USE_RSA */
+
+    if(algo==PUBKEY_ALGO_ELGAMAL)
+      return mpi_get_nbits(pkey[0]);
+
+    return 0;
+}
+
+
+int
 pubkey_generate( int algo, unsigned nbits, MPI *skey, MPI **retfactors )
 {
     int i;
@@ -444,11 +430,11 @@ pubkey_generate( int algo, unsigned nbits, MPI *skey, MPI **retfactors )
                return (*pubkey_table[i].generate)( algo, nbits,
                                                    skey, retfactors );
     } while( load_pubkey_modules() );
-    return GCRYERR_INV_PK_ALGO;
+    return G10ERR_PUBKEY_ALGO;
 }
 
 
-static int
+int
 pubkey_check_secret_key( int algo, MPI *skey )
 {
     int i;
@@ -458,7 +444,7 @@ pubkey_check_secret_key( int algo, MPI *skey )
            if( pubkey_table[i].algo == algo )
                return (*pubkey_table[i].check_secret_key)( algo, skey );
     } while( load_pubkey_modules() );
-    return GCRYERR_INV_PK_ALGO;
+    return G10ERR_PUBKEY_ALGO;
 }
 
 
@@ -468,7 +454,7 @@ pubkey_check_secret_key( int algo, MPI *skey )
  * should be an array of MPIs of size PUBKEY_MAX_NENC (or less if the
  * algorithm allows this - check with pubkey_get_nenc() )
  */
-static int
+int
 pubkey_encrypt( int algo, MPI *resarr, MPI data, MPI *pkey )
 {
     int i, rc;
@@ -487,7 +473,7 @@ pubkey_encrypt( int algo, MPI *resarr, MPI data, MPI *pkey )
                goto ready;
            }
     } while( load_pubkey_modules() );
-    rc = GCRYERR_INV_PK_ALGO;
+    rc = G10ERR_PUBKEY_ALGO;
   ready:
     if( !rc && DBG_CIPHER ) {
        for(i=0; i < pubkey_get_nenc(algo); i++ )
@@ -505,12 +491,12 @@ pubkey_encrypt( int algo, MPI *resarr, MPI data, MPI *pkey )
  * result is a pointer to a mpi variable which will receive a
  * newly allocated mpi or NULL in case of an error.
  */
-static int
+int
 pubkey_decrypt( int algo, MPI *result, MPI *data, MPI *skey )
 {
     int i, rc;
 
-    *result = NULL; /* so the caller can always do a mpi_free */
+    *result = NULL; /* so the caller can always do an mpi_free */
     if( DBG_CIPHER ) {
        log_debug("pubkey_decrypt: algo=%d\n", algo );
        for(i=0; i < pubkey_get_nskey(algo); i++ )
@@ -526,7 +512,7 @@ pubkey_decrypt( int algo, MPI *result, MPI *data, MPI *skey )
                goto ready;
            }
     } while( load_pubkey_modules() );
-    rc = GCRYERR_INV_PK_ALGO;
+    rc = G10ERR_PUBKEY_ALGO;
   ready:
     if( !rc && DBG_CIPHER ) {
        log_mpidump(" plain:", *result );
@@ -541,7 +527,7 @@ pubkey_decrypt( int algo, MPI *result, MPI *data, MPI *skey )
  * should be an array of MPIs of size PUBKEY_MAX_NSIG (or less if the
  * algorithm allows this - check with pubkey_get_nsig() )
  */
-static int
+int
 pubkey_sign( int algo, MPI *resarr, MPI data, MPI *skey )
 {
     int i, rc;
@@ -560,7 +546,7 @@ pubkey_sign( int algo, MPI *resarr, MPI data, MPI *skey )
                goto ready;
            }
     } while( load_pubkey_modules() );
-    rc = GCRYERR_INV_PK_ALGO;
+    rc = G10ERR_PUBKEY_ALGO;
   ready:
     if( !rc && DBG_CIPHER ) {
        for(i=0; i < pubkey_get_nsig(algo); i++ )
@@ -573,649 +559,19 @@ pubkey_sign( int algo, MPI *resarr, MPI data, MPI *skey )
  * Verify a public key signature.
  * Return 0 if the signature is good
  */
-static int
-pubkey_verify( int algo, MPI hash, MPI *data, MPI *pkey,
-                   int (*cmp)(void *, MPI), void *opaquev )
+int
+pubkey_verify( int algo, MPI hash, MPI *data, MPI *pkey )
 {
     int i, rc;
 
     do {
        for(i=0; pubkey_table[i].name; i++ )
            if( pubkey_table[i].algo == algo ) {
-               rc = (*pubkey_table[i].verify)( algo, hash, data, pkey,
-                                                           cmp, opaquev );
+               rc = (*pubkey_table[i].verify)( algo, hash, data, pkey );
                goto ready;
            }
     } while( load_pubkey_modules() );
-    rc = GCRYERR_INV_PK_ALGO;
+    rc = G10ERR_PUBKEY_ALGO;
   ready:
     return rc;
 }
-
-
-
-/****************
- * 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
- * Provide a SE with the first element be either "private-key" or
- * or "public-key". the followed by a list with its first element
- * be one of the above algorithm identifiers and the following
- * 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.
- *
- * FIXME: Allow for encrypted secret keys here.
- *
- * 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 int
-sexp_to_key( GCRY_SEXP sexp, int want_private, MPI **retarray, int *retalgo)
-{
-    GCRY_SEXP list, l2;
-    const char *name;
-    const char *s;
-    size_t n;
-    int i, idx;
-    int algo;
-    const char *elems1, *elems2;
-    GCRY_MPI *array;
-
-    /* check that the first element is valid */
-    list = gcry_sexp_find_token( sexp, want_private? "private-key"
-                                                   :"public-key", 0 );
-    if( !list )
-       return GCRYERR_INV_OBJ; /* Does not contain a public- or private-key object */
-    list = gcry_sexp_cdr( list );
-    if( !list )
-       return GCRYERR_NO_OBJ; /* no cdr for the key object */
-    name = gcry_sexp_car_data( list, &n );
-    if( !name )
-       return GCRYERR_INV_OBJ; /* invalid structure of object */
-    for(i=0; (s=algo_info_table[i].name); i++ ) {
-       if( strlen(s) == n && !memcmp( s, name, n ) )
-           break;
-    }
-    if( !s )
-       return GCRYERR_INV_PK_ALGO; /* unknown algorithm */
-    algo = algo_info_table[i].algo;
-    elems1 = algo_info_table[i].common_elements;
-    elems2 = want_private? algo_info_table[i].secret_elements
-                        : algo_info_table[i].public_elements;
-    array = g10_calloc( strlen(elems1)+strlen(elems2)+1, sizeof *array );
-    if( !array )
-       return GCRYERR_NO_MEM;
-
-    idx = 0;
-    for(s=elems1; *s; s++, idx++ ) {
-       l2 = gcry_sexp_find_token( list, s, 1 );
-       if( !l2 ) {
-           g10_free( array );
-           return GCRYERR_NO_OBJ; /* required parameter not found */
-       }
-       array[idx] = gcry_sexp_cdr_mpi( l2, GCRYMPI_FMT_USG );
-       if( !array[idx] ) {
-           g10_free( array );
-           return GCRYERR_INV_OBJ; /* required parameter is invalid */
-       }
-    }
-    for(s=elems2; *s; s++, idx++ ) {
-       l2 = gcry_sexp_find_token( list, s, 1 );
-       if( !l2 ) {
-           g10_free( array );
-           return GCRYERR_NO_OBJ; /* required parameter not found */
-       }
-       /* FIXME: put the MPI in secure memory when needed */
-       array[idx] = gcry_sexp_cdr_mpi( l2, GCRYMPI_FMT_USG );
-       if( !array[idx] ) {
-           g10_free( array );
-           return GCRYERR_INV_OBJ; /* required parameter is invalid */
-       }
-    }
-
-    *retarray = array;
-    *retalgo = algo;
-
-    return 0;
-}
-
-static int
-sexp_to_sig( GCRY_SEXP sexp, MPI **retarray, int *retalgo)
-{
-    GCRY_SEXP list, l2;
-    const char *name;
-    const char *s;
-    size_t n;
-    int i, idx;
-    int algo;
-    const char *elems;
-    GCRY_MPI *array;
-
-    /* check that the first element is valid */
-    list = gcry_sexp_find_token( sexp, "sig-val" , 0 );
-    if( !list )
-       return GCRYERR_INV_OBJ; /* Does not contain a signature value object */
-    list = gcry_sexp_cdr( list );
-    if( !list )
-       return GCRYERR_NO_OBJ; /* no cdr for the sig object */
-    name = gcry_sexp_car_data( list, &n );
-    if( !name )
-       return GCRYERR_INV_OBJ; /* invalid structure of object */
-    for(i=0; (s=sig_info_table[i].name); i++ ) {
-       if( strlen(s) == n && !memcmp( s, name, n ) )
-           break;
-    }
-    if( !s )
-       return GCRYERR_INV_PK_ALGO; /* unknown algorithm */
-    algo = sig_info_table[i].algo;
-    elems = sig_info_table[i].elements;
-    array = g10_calloc( (strlen(elems)+1) , sizeof *array );
-    if( !array )
-       return GCRYERR_NO_MEM;
-
-    idx = 0;
-    for(s=elems; *s; s++, idx++ ) {
-       l2 = gcry_sexp_find_token( list, s, 1 );
-       if( !l2 ) {
-           g10_free( array );
-           return GCRYERR_NO_OBJ; /* required parameter not found */
-       }
-       array[idx] = gcry_sexp_cdr_mpi( l2, GCRYMPI_FMT_USG );
-       if( !array[idx] ) {
-           g10_free( array );
-           return GCRYERR_INV_OBJ; /* required parameter is invalid */
-       }
-    }
-
-    *retarray = array;
-    *retalgo = algo;
-
-    return 0;
-}
-
-
-/****************
- * Take sexp and return an array of MPI as used for our internal decrypt
- * function.
- */
-static int
-sexp_to_enc( GCRY_SEXP sexp, MPI **retarray, int *retalgo)
-{
-    GCRY_SEXP list, l2;
-    const char *name;
-    const char *s;
-    size_t n;
-    int i, idx;
-    int algo;
-    const char *elems;
-    GCRY_MPI *array;
-
-    /* check that the first element is valid */
-    list = gcry_sexp_find_token( sexp, "enc-val" , 0 );
-    if( !list )
-       return GCRYERR_INV_OBJ; /* Does not contain a encrypted value object */
-    list = gcry_sexp_cdr( list );
-    if( !list )
-       return GCRYERR_NO_OBJ; /* no cdr for the data object */
-    name = gcry_sexp_car_data( list, &n );
-    if( !name )
-       return GCRYERR_INV_OBJ; /* invalid structure of object */
-    for(i=0; (s=enc_info_table[i].name); i++ ) {
-       if( strlen(s) == n && !memcmp( s, name, n ) )
-           break;
-    }
-    if( !s )
-       return GCRYERR_INV_PK_ALGO; /* unknown algorithm */
-    algo = enc_info_table[i].algo;
-    elems = enc_info_table[i].elements;
-    array = g10_calloc( (strlen(elems)+1) , sizeof *array );
-    if( !array )
-       return GCRYERR_NO_MEM;
-
-    idx = 0;
-    for(s=elems; *s; s++, idx++ ) {
-       l2 = gcry_sexp_find_token( list, s, 1 );
-       if( !l2 ) {
-           g10_free( array );
-           return GCRYERR_NO_OBJ; /* required parameter not found */
-       }
-       array[idx] = gcry_sexp_cdr_mpi( l2, GCRYMPI_FMT_USG );
-       if( !array[idx] ) {
-           g10_free( array );
-           return GCRYERR_INV_OBJ; /* required parameter is invalid */
-       }
-    }
-
-    *retarray = array;
-    *retalgo = algo;
-
-    return 0;
-}
-
-
-/****************
- * 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.  The function returns a a sexp which may
- * be passed tp to pk_decrypt.
- * Later versions of this functions may take more complex input data.
- *
- * Returns: 0 or an errorcode.
- *
- * s_data = (<mpi>)
- * s_pkey = <key-as-defined-in-sexp_to_key>
- * r_ciph = (enc-val
- *           (<algo>
- *             (<param_name1> <mpi>)
- *             ...
- *             (<param_namen> <mpi>)
- *           ))
- */
-int
-gcry_pk_encrypt( GCRY_SEXP *r_ciph, GCRY_SEXP s_data, GCRY_SEXP s_pkey )
-{
-    MPI *pkey, data, *ciph;
-    const char *algo_name, *algo_elems;
-    GCRY_SEXP *s_elems;
-    int i, rc, algo;
-
-    /* get the key */
-    rc = sexp_to_key( s_pkey, 0, &pkey, &algo );
-    if( rc ) {
-       return rc;
-    }
-
-    /* get the name and the required size of the return value */
-    for(i=0; (algo_name = enc_info_table[i].name); i++ ) {
-       if( enc_info_table[i].algo == algo )
-           break;
-    }
-    if( !algo_name ) {
-       release_mpi_array( pkey );
-       return GCRYERR_INV_PK_ALGO;
-    }
-    algo_elems = enc_info_table[i].elements;
-
-    /* get the stuff we want to encrypt */
-    data = gcry_sexp_car_mpi( s_data, 0 );
-    if( !data ) {
-       release_mpi_array( pkey );
-       return GCRYERR_INV_OBJ;
-    }
-
-    /* Now we can encrypt data to ciph */
-    ciph = g10_xcalloc( (strlen(algo_elems)+1) , sizeof *ciph );
-    rc = pubkey_encrypt( algo, ciph, data, pkey );
-    release_mpi_array( pkey );
-    mpi_free( data );
-    if( rc ) {
-       g10_free( ciph );
-       return rc;
-    }
-
-    /* We did it.  Now build the return list */
-    s_elems = g10_xcalloc( (strlen(algo_elems)+2), sizeof *s_elems );
-    s_elems[0] = SEXP_NEW( algo_name, 0 );
-    for(i=0; algo_elems[i]; i++ ) {
-       char tmp[2];
-       tmp[0] = algo_elems[i];
-       tmp[1] = 0;
-       s_elems[i+1] = gcry_sexp_new_name_mpi( tmp, ciph[i] );
-    }
-    release_mpi_array( ciph );
-    g10_free( ciph );
-
-    *r_ciph = SEXP_CONS( SEXP_NEW( "enc-val", 0 ),
-                        gcry_sexp_alist( s_elems ) );
-
-    g10_free( s_elems );
-    return 0;
-}
-
-/****************
- * 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.  Currently the function returns
- * simply a MPI.  Later versions of this functions may return a more
- * complex data structure.
- *
- * Returns: 0 or an errorcode.
- *
- * s_data = (enc-val
- *           (<algo>
- *             (<param_name1> <mpi>)
- *             ...
- *             (<param_namen> <mpi>)
- *           ))
- * s_skey = <key-as-defined-in-sexp_to_key>
- * r_plain= (<mpi>)   FIXME: Return a more structered value
- */
-int
-gcry_pk_decrypt( GCRY_SEXP *r_plain, GCRY_SEXP s_data, GCRY_SEXP s_skey )
-{
-    MPI *skey, *data, plain;
-    int rc, algo, dataalgo;
-
-    rc = sexp_to_key( s_skey, 1, &skey, &algo );
-    if( rc ) {
-       return rc;
-    }
-    rc = sexp_to_enc( s_data, &data, &dataalgo );
-    if( rc ) {
-       release_mpi_array( skey );
-       return rc;
-    }
-    if( algo != dataalgo ) {
-       release_mpi_array( skey );
-       release_mpi_array( data );
-       return -1; /* fixme: add real errornumber - algo does not match */
-    }
-
-    rc = pubkey_decrypt( algo, &plain, data, skey );
-    if( rc ) {
-       release_mpi_array( skey );
-       release_mpi_array( data );
-       return -1; /* fixme: add real errornumber - decryption failed */
-    }
-
-    *r_plain = gcry_sexp_new_mpi( plain );
-    mpi_free( plain );
-    release_mpi_array( data );
-    release_mpi_array( skey );
-    return 0;
-}
-
-
-
-/****************
- * 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. Later versions of this functions may provide padding
- * and other things depending on data.
- *
- * 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 = (<mpi>)
- * s_skey = <key-as-defined-in-sexp_to_key>
- * r_sig  = (sig-val
- *           (<algo>
- *             (<param_name1> <mpi>)
- *             ...
- *             (<param_namen> <mpi>)
- *           ))
- */
-int
-gcry_pk_sign( GCRY_SEXP *r_sig, GCRY_SEXP s_hash, GCRY_SEXP s_skey )
-{
-    MPI *skey, hash;
-    MPI *result;
-    int i, algo, rc;
-    const char *algo_name, *algo_elems;
-    GCRY_SEXP *s_elems;
-
-    rc = sexp_to_key( s_skey, 1, &skey, &algo );
-    if( rc )
-       return rc;
-
-    /* get the name and the required size of the result array */
-    for(i=0; (algo_name = sig_info_table[i].name); i++ ) {
-       if( sig_info_table[i].algo == algo )
-           break;
-    }
-    if( !algo_name ) {
-       release_mpi_array( skey );
-       return -4; /* oops: unknown algorithm */
-    }
-    algo_elems = sig_info_table[i].elements;
-
-    /* get the stuff we want to sign */
-    hash = gcry_sexp_car_mpi( s_hash, 0 );
-    if( !hash ) {
-       release_mpi_array( skey );
-       return -1; /* fixme: get a real errorcode for this */
-    }
-    result = g10_xcalloc( (strlen(algo_elems)+1) , sizeof *result );
-    rc = pubkey_sign( algo, result, hash, skey );
-    release_mpi_array( skey );
-    mpi_free( hash );
-    if( rc ) {
-       g10_free( result );
-       return rc;
-    }
-
-    s_elems = g10_xcalloc( (strlen(algo_elems)+2), sizeof *s_elems );
-    s_elems[0] = SEXP_NEW( algo_name, 0 );
-    for(i=0; algo_elems[i]; i++ ) {
-       char tmp[2];
-       tmp[0] = algo_elems[i];
-       tmp[1] = 0;
-       s_elems[i+1] = gcry_sexp_new_name_mpi( tmp, result[i] );
-    }
-    release_mpi_array( result );
-    g10_free( result );
-
-    *r_sig = SEXP_CONS( SEXP_NEW( "sig-val", 0 ),
-                       gcry_sexp_alist( s_elems ) );
-
-    g10_free( s_elems );
-    return 0;
-}
-
-
-/****************
- * Verify a sgnature.  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.
- */
-int
-gcry_pk_verify( GCRY_SEXP s_sig, GCRY_SEXP s_hash, GCRY_SEXP s_pkey )
-{
-    MPI *pkey, hash, *sig;
-    int algo, sigalgo;
-    int rc;
-
-    rc = sexp_to_key( s_pkey, 0, &pkey, &algo );
-    if( rc )
-       return rc;
-    rc = sexp_to_sig( s_sig, &sig, &sigalgo );
-    if( rc ) {
-       release_mpi_array( pkey );
-       return rc;
-    }
-    if( algo != sigalgo ) {
-       release_mpi_array( pkey );
-       release_mpi_array( sig );
-       return -1; /* fixme: add real errornumber - algo does not match */
-    }
-
-    hash = gcry_sexp_car_mpi( s_hash, 0 );
-    if( !hash ) {
-       release_mpi_array( pkey );
-       release_mpi_array( sig );
-       return -1; /* fixme: get a real errorcode for this */
-    }
-
-    rc = pubkey_verify( algo, hash, sig, pkey, NULL, NULL );
-    release_mpi_array( pkey );
-    release_mpi_array( sig );
-    mpi_free(hash);
-
-    return rc;
-}
-
-
-/****************
- * Test a key. This may be used either for a public or a secret key
- * to see whether internal structre is valid.
- *
- * Returns: 0 or an errorcode.
- *
- * s_key = <key-as-defined-in-sexp_to_key>
- */
-int
-gcry_pk_testkey( GCRY_SEXP s_key )
-{
-    MPI *key;
-    int rc, algo;
-
-    /* Note we currently support only secret key checking */
-    rc = sexp_to_key( s_key, 1, &key, &algo );
-    if( rc ) {
-       return rc;
-    }
-
-    rc = pubkey_check_secret_key( algo, key );
-    release_mpi_array( key );
-    return rc;
-}
-
-
-/****************
- * Create a public key pair and return it in r_key.
- * How the key is created depends on s_parms:
- * (GNU
- *  (genkey
- *   (algo
- *     (parameter_name_1 ....)
- *     ....
- *     (parameter_name_n ....)
- * )))
- * The key is returned in a format depending on the
- * algorithm. Both, private and secret key are returned
- * and optionally some additional informatin.
- */
-int
-gcry_pk_genkey( GCRY_SEXP *r_key, GCRY_SEXP s_parms )
-{
-    return GCRYERR_NOT_IMPL;
-}
-
-/****************
- * 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 propoerties of the key?
- */
-unsigned int
-gcry_pk_get_nbits( GCRY_SEXP key )
-{
-    int rc, i, algo;
-    MPI *keyarr;
-    unsigned int nbits = 0;
-
-    rc = sexp_to_key( key, 0, &keyarr, &algo );
-    if( rc == GCRYERR_INV_OBJ )
-       rc = sexp_to_key( key, 0, &keyarr, &algo );
-    if( rc )
-       return 0;
-
-    do {
-       for(i=0; pubkey_table[i].name; i++ )
-           if( pubkey_table[i].algo == algo ) {
-               nbits = (*pubkey_table[i].get_nbits)( algo, keyarr );
-               goto leave;
-           }
-    } while( load_pubkey_modules() );
-    if( is_RSA(algo) ) /* we always wanna see the length of a key :-) */
-       nbits = mpi_get_nbits( keyarr[0] );
-  leave:
-    release_mpi_array( keyarr );
-    return nbits;
-}
-
-
-
-int
-gcry_pk_ctl( int cmd, void *buffer, size_t buflen)
-{
-    switch( cmd ) {
-      case GCRYCTL_DISABLE_ALGO:
-       /* this one expects a buffer pointing to an
-        * integer with the algo number.
-        */
-       if( !buffer || buflen != sizeof(int) )
-           return set_lasterr( GCRYERR_INV_CIPHER_ALGO );
-       disable_pubkey_algo( *(int*)buffer );
-       break;
-
-      default:
-       return set_lasterr( GCRYERR_INV_OP );
-    }
-    return 0;
-}
-
-
-/****************
- * Return information about the given algorithm
- * WHAT select 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;
- *
- * On error the value -1 is returned and the error reason may be
- * retrieved by gcry_errno().
- * Note:  Because this function is in most caes used to return an
- * integer value, we can make it easier for the caller to just look at
- * the return value.  The caller will in all cases consult the value
- * and thereby detecting whether a error occured or not (i.e. while checking
- * the block size)
- */
-int
-gcry_pk_algo_info( int algo, int what, void *buffer, size_t *nbytes)
-{
-    switch( what ) {
-      case GCRYCTL_TEST_ALGO: {
-           int use = nbytes? *nbytes: 0;
-           if( buffer ) {
-               set_lasterr( GCRYERR_INV_ARG );
-               return -1;
-           }
-           if( check_pubkey_algo( algo, use ) ) {
-               set_lasterr( GCRYERR_INV_PK_ALGO );
-               return -1;
-           }
-       }
-       break;
-
-      case GCRYCTL_GET_ALGO_NPKEY: return pubkey_get_npkey( algo );
-      case GCRYCTL_GET_ALGO_NSKEY: return pubkey_get_nskey( algo );
-      case GCRYCTL_GET_ALGO_NSIGN: return pubkey_get_nsig( algo );
-      case GCRYCTL_GET_ALGO_NENCR: return pubkey_get_nenc( algo );
-
-      default:
-       set_lasterr( GCRYERR_INV_OP );
-       return -1;
-    }
-    return 0;
-}
-
-