* random.c: Fix prototype of the fast random gatherer. Noted by Joe
[gnupg.git] / cipher / pubkey.c
index 0a4b343..d6d1ff1 100644 (file)
@@ -1,21 +1,23 @@
 /* pubkey.c  - pubkey dispatcher
- *     Copyright (C) 1998 Free Software Foundation, Inc.
+ * Copyright (C) 1998, 1999, 2000, 2001, 2003,
+ *               2004 Free Software Foundation, Inc.
  *
- * This file is part of GNUPG.
+ * This file is part of GnuPG.
  *
- * GNUPG is free software; you can redistribute it and/or modify
+ * GnuPG is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
  * (at your option) any later version.
  *
- * GNUPG is distributed in the hope that it will be useful,
+ * GnuPG is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
  *
  * 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 "errors.h"
 #include "mpi.h"
 #include "cipher.h"
-#include "dynload.h"
+#include "elgamal.h"
+#include "dsa.h"
+#include "rsa.h"
+
+#define TABLE_SIZE 10
+
+struct pubkey_table_s {
+    const char *name;
+    int algo;
+    int npkey;
+    int nskey;
+    int nenc;
+    int nsig;
+    int use;
+    int (*generate)( int algo, unsigned nbits, MPI *skey, MPI **retfactors );
+    int (*check_secret_key)( int algo, MPI *skey );
+    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 );
+    unsigned (*get_nbits)( int algo, MPI *pkey );
+};
+
+static struct pubkey_table_s pubkey_table[TABLE_SIZE];
+static int disabled_algos[TABLE_SIZE];
+
+
+#if 0
+static int
+dummy_generate( int algo, unsigned nbits, MPI *skey, MPI **retfactors )
+{ 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 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 G10ERR_PUBKEY_ALGO; }
+
+static int
+dummy_decrypt( int algo, MPI *result, MPI *data, MPI *skey )
+{ 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 G10ERR_PUBKEY_ALGO; }
+
+static int
+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.
+ * This is out constructor function which fill the table
+ * of algorithms with the one we have statically linked.
+ */
+static void
+setup_pubkey_table(void)
+{
+    int i=0;
+
+    pubkey_table[i].algo = PUBKEY_ALGO_ELGAMAL_E;
+    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            = dummy_sign;
+    pubkey_table[i].verify          = dummy_verify;
+    pubkey_table[i].get_nbits       = elg_get_nbits;
+    if( !pubkey_table[i].name )
+       BUG();
+    i++;
+    pubkey_table[i].algo = PUBKEY_ALGO_DSA;
+    pubkey_table[i].name = dsa_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        = dsa_generate;
+    pubkey_table[i].check_secret_key = dsa_check_secret_key;
+    pubkey_table[i].encrypt         = dummy_encrypt;
+    pubkey_table[i].decrypt         = dummy_decrypt;
+    pubkey_table[i].sign            = dsa_sign;
+    pubkey_table[i].verify          = dsa_verify;
+    pubkey_table[i].get_nbits       = dsa_get_nbits;
+    if( !pubkey_table[i].name )
+       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;
+}
+
+
+/****************
+ * Try to load all modules and return true if new modules are available
+ */
+static int
+load_pubkey_modules(void)
+{
+    static int initialized = 0;
+
+    if( !initialized ) {
+       setup_pubkey_table();
+       initialized = 1;
+       return 1;
+    }
+    return 0;
+}
+
+
+/****************
+ * Map a string to the pubkey algo
+ */
+int
+string_to_pubkey_algo( const char *string )
+{
+    int i;
+    const char *s;
+
+    do {
+       for(i=0; (s=pubkey_table[i].name); i++ )
+           if( !ascii_strcasecmp( s, string ) )
+               return pubkey_table[i].algo;
+    } while( load_pubkey_modules() );
+    return 0;
+}
+
+
+/****************
+ * Map a pubkey algo to a string
+ */
+const char *
+pubkey_algo_to_string( int algo )
+{
+    int i;
+
+    do {
+       for(i=0; pubkey_table[i].name; i++ )
+           if( pubkey_table[i].algo == algo )
+               return pubkey_table[i].name;
+    } while( load_pubkey_modules() );
+    return NULL;
+}
+
+
+void
+disable_pubkey_algo( int algo )
+{
+    int i;
+
+    for(i=0; i < DIM(disabled_algos); i++ ) {
+       if( !disabled_algos[i] || disabled_algos[i] == algo ) {
+           disabled_algos[i] = algo;
+           return;
+       }
+    }
+    log_fatal("can't disable pubkey algo %d: table full\n", algo );
+}
+
+
+int
+check_pubkey_algo( int algo )
+{
+    return check_pubkey_algo2( algo, 0 );
+}
+
+/****************
+ * a use of 0 means: don't care
+ */
+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 & 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 G10ERR_PUBKEY_ALGO;
+               }
+               return 0; /* okay */
+           }
+    } while( load_pubkey_modules() );
+    return G10ERR_PUBKEY_ALGO;
+}
+
+
+
 
 /****************
  * Return the number of public key material numbers
 int
 pubkey_get_npkey( int algo )
 {
-    if( is_ELGAMAL(algo) )
-       return 3;
-    if( is_RSA(algo) )
-       return 2;
-    if( algo == PUBKEY_ALGO_DSA )
-       return 4;
+    int i;
+    do {
+       for(i=0; pubkey_table[i].name; i++ )
+           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;
 }
 
@@ -51,12 +327,21 @@ pubkey_get_npkey( int algo )
 int
 pubkey_get_nskey( int algo )
 {
-    if( is_ELGAMAL(algo) )
-       return 4;
-    if( is_RSA(algo) )
-       return 6;
-    if( algo == PUBKEY_ALGO_DSA )
-       return 5;
+    int i;
+    do {
+       for(i=0; pubkey_table[i].name; i++ )
+           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;
 }
 
@@ -66,12 +351,21 @@ pubkey_get_nskey( int algo )
 int
 pubkey_get_nsig( int algo )
 {
-    if( is_ELGAMAL(algo) )
-       return 2;
-    if( is_RSA(algo) )
-       return 1;
-    if( algo == PUBKEY_ALGO_DSA )
-       return 2;
+    int i;
+    do {
+       for(i=0; pubkey_table[i].name; i++ )
+           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;
 }
 
@@ -81,10 +375,21 @@ pubkey_get_nsig( int algo )
 int
 pubkey_get_nenc( int algo )
 {
-    if( is_ELGAMAL(algo) )
-       return 2;
-    if( is_RSA(algo) )
-       return 1;
+    int i;
+    do {
+       for(i=0; pubkey_table[i].name; i++ )
+           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;
 }
 
@@ -94,61 +399,52 @@ pubkey_get_nenc( int algo )
 unsigned
 pubkey_nbits( int algo, MPI *pkey )
 {
-    if( is_ELGAMAL( algo ) )
-       return mpi_get_nbits( pkey[0] );
+    int i;
 
-    if( algo == PUBKEY_ALGO_DSA )
-       return mpi_get_nbits( pkey[0] );
+    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() );
 
-    if( is_RSA( algo) )
+#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;
+
+    do {
+       for(i=0; pubkey_table[i].name; i++ )
+           if( pubkey_table[i].algo == algo )
+               return (*pubkey_table[i].generate)( algo, nbits,
+                                                   skey, retfactors );
+    } while( load_pubkey_modules() );
+    return G10ERR_PUBKEY_ALGO;
+}
+
+
+int
 pubkey_check_secret_key( int algo, MPI *skey )
 {
-    int rc = 0;
-
-    if( is_ELGAMAL(algo) ) {
-       ELG_secret_key sk;
-       sk.p = skey[0];
-       sk.g = skey[1];
-       sk.y = skey[2];
-       sk.x = skey[3];
-       if( !elg_check_secret_key( &sk ) )
-           rc = G10ERR_BAD_SECKEY;
-    }
-    else if( algo == PUBKEY_ALGO_DSA ) {
-       DSA_secret_key sk;
-       sk.p = skey[0];
-       sk.q = skey[1];
-       sk.g = skey[2];
-       sk.y = skey[3];
-       sk.x = skey[4];
-       if( !dsa_check_secret_key( &sk ) )
-           rc = G10ERR_BAD_SECKEY;
-    }
- #ifdef HAVE_RSA_CIPHER
-    else if( is_RSA(k->pubkey_algo) ) {
-       /* FIXME */
-       RSA_secret_key sk;
-       assert( ndata == 1 && nskey == 6 );
-       sk.n = skey[0];
-       sk.e = skey[1];
-       sk.d = skey[2];
-       sk.p = skey[3];
-       sk.q = skey[4];
-       sk.u = skey[5];
-       plain = mpi_alloc_secure( mpi_get_nlimbs(sk.n) );
-       rsa_secret( plain, data[0], &sk );
-    }
-  #endif
-    else
-       rc = G10ERR_PUBKEY_ALGO;
-    return rc;
+    int i;
+
+    do {
+       for(i=0; pubkey_table[i].name; i++ )
+           if( pubkey_table[i].algo == algo )
+               return (*pubkey_table[i].check_secret_key)( algo, skey );
+    } while( load_pubkey_modules() );
+    return G10ERR_PUBKEY_ALGO;
 }
 
 
@@ -161,41 +457,29 @@ pubkey_check_secret_key( int algo, MPI *skey )
 int
 pubkey_encrypt( int algo, MPI *resarr, MPI data, MPI *pkey )
 {
+    int i, rc;
+
     if( DBG_CIPHER ) {
-       int i;
        log_debug("pubkey_encrypt: algo=%d\n", algo );
        for(i=0; i < pubkey_get_npkey(algo); i++ )
            log_mpidump("  pkey:", pkey[i] );
        log_mpidump("  data:", data );
     }
-    /* FIXME: check that data fits into the key */
-    if( is_ELGAMAL(algo) ) {
-       ELG_public_key pk;
-       pk.p = pkey[0];
-       pk.g = pkey[1];
-       pk.y = pkey[2];
-       resarr[0] = mpi_alloc( mpi_get_nlimbs( pk.p ) );
-       resarr[1] = mpi_alloc( mpi_get_nlimbs( pk.p ) );
-       elg_encrypt( resarr[0], resarr[1], data, &pk );
-    }
- #ifdef HAVE_RSA_CIPHER
-    else if( algo == PUBKEY_ALGO_RSA || algo == PUBKEY_ALGO_RSA_E ) {
-       RSA_public_key pk;
-       pk.n = pkey[0];
-       pk.e = pkey[1];
-       resarr[0] = mpi_alloc( mpi_get_nlimbs( pk.p ) );
-       rsa_public( resarr[0], data, &pk );
-    }
-  #endif
-    else
-       return G10ERR_PUBKEY_ALGO;
 
-    if( DBG_CIPHER ) {
-       int i;
+    do {
+       for(i=0; pubkey_table[i].name; i++ )
+           if( pubkey_table[i].algo == algo ) {
+               rc = (*pubkey_table[i].encrypt)( algo, resarr, data, pkey );
+               goto ready;
+           }
+    } while( load_pubkey_modules() );
+    rc = G10ERR_PUBKEY_ALGO;
+  ready:
+    if( !rc && DBG_CIPHER ) {
        for(i=0; i < pubkey_get_nenc(algo); i++ )
            log_mpidump("  encr:", resarr[i] );
     }
-    return 0;
+    return rc;
 }
 
 
@@ -210,108 +494,65 @@ pubkey_encrypt( int algo, MPI *resarr, MPI data, MPI *pkey )
 int
 pubkey_decrypt( int algo, MPI *result, MPI *data, MPI *skey )
 {
-    MPI plain = NULL;
+    int i, rc;
 
     *result = NULL; /* so the caller can always do an mpi_free */
     if( DBG_CIPHER ) {
-       int i;
        log_debug("pubkey_decrypt: algo=%d\n", algo );
        for(i=0; i < pubkey_get_nskey(algo); i++ )
            log_mpidump("  skey:", skey[i] );
        for(i=0; i < pubkey_get_nenc(algo); i++ )
            log_mpidump("  data:", data[i] );
     }
-    if( is_ELGAMAL(algo) ) {
-       ELG_secret_key sk;
-       sk.p = skey[0];
-       sk.g = skey[1];
-       sk.y = skey[2];
-       sk.x = skey[3];
-       plain = mpi_alloc_secure( mpi_get_nlimbs( sk.p ) );
-       elg_decrypt( plain, data[0], data[1], &sk );
-    }
- #ifdef HAVE_RSA_CIPHER
-    else if( algo == PUBKEY_ALGO_RSA || algo == PUBKEY_ALGO_RSA_E ) {
-       RSA_secret_key sk;
-       sk.n = skey[0];
-       sk.e = skey[1];
-       sk.d = skey[2];
-       sk.p = skey[3];
-       sk.q = skey[4];
-       sk.u = skey[5];
-       plain = mpi_alloc_secure( mpi_get_nlimbs(sk.n) );
-       rsa_secret( plain, data[0], &sk );
-    }
-  #endif
-    else
-       return G10ERR_PUBKEY_ALGO;
 
-    *result = plain;
-    return 0;
+    do {
+       for(i=0; pubkey_table[i].name; i++ )
+           if( pubkey_table[i].algo == algo ) {
+               rc = (*pubkey_table[i].decrypt)( algo, result, data, skey );
+               goto ready;
+           }
+    } while( load_pubkey_modules() );
+    rc = G10ERR_PUBKEY_ALGO;
+  ready:
+    if( !rc && DBG_CIPHER ) {
+       log_mpidump(" plain:", *result );
+    }
+    return rc;
 }
 
 
 /****************
  * This is the interface to the public key signing.
- * Sign hash with skey and put the result into resarr which
+ * 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() )
  */
 int
 pubkey_sign( int algo, MPI *resarr, MPI data, MPI *skey )
 {
+    int i, rc;
+
     if( DBG_CIPHER ) {
-       int i;
        log_debug("pubkey_sign: algo=%d\n", algo );
        for(i=0; i < pubkey_get_nskey(algo); i++ )
            log_mpidump("  skey:", skey[i] );
        log_mpidump("  data:", data );
     }
 
-    if( is_ELGAMAL(algo) ) {
-       ELG_secret_key sk;
-       sk.p = skey[0];
-       sk.g = skey[1];
-       sk.y = skey[2];
-       sk.x = skey[3];
-       resarr[0] = mpi_alloc( mpi_get_nlimbs( sk.p ) );
-       resarr[1] = mpi_alloc( mpi_get_nlimbs( sk.p ) );
-       elg_sign( resarr[0], resarr[1], data, &sk );
-    }
-    else if( algo == PUBKEY_ALGO_DSA ) {
-       DSA_secret_key sk;
-       sk.p = skey[0];
-       sk.q = skey[1];
-       sk.g = skey[2];
-       sk.y = skey[3];
-       sk.x = skey[4];
-       resarr[0] = mpi_alloc( mpi_get_nlimbs( sk.p ) );
-       resarr[1] = mpi_alloc( mpi_get_nlimbs( sk.p ) );
-       dsa_sign( resarr[0], resarr[1], data, &sk );
-    }
- #ifdef HAVE_RSA_CIPHER
-    else if( algo == PUBKEY_ALGO_RSA || algo == PUBKEY_ALGO_RSA_S ) {
-       RSA_secret_key sk;
-       sk.n = skey[0];
-       sk.e = skey[1];
-       sk.d = skey[2];
-       sk.p = skey[3];
-       sk.q = skey[4];
-       sk.u = skey[5];
-       plain = mpi_alloc_secure( mpi_get_nlimbs(sk.n) );
-       rsa_sign( plain, data[0], &sk );
-    }
-  #endif
-    else
-       return G10ERR_PUBKEY_ALGO;
-
-    if( DBG_CIPHER ) {
-       int i;
+    do {
+       for(i=0; pubkey_table[i].name; i++ )
+           if( pubkey_table[i].algo == algo ) {
+               rc = (*pubkey_table[i].sign)( algo, resarr, data, skey );
+               goto ready;
+           }
+    } while( load_pubkey_modules() );
+    rc = G10ERR_PUBKEY_ALGO;
+  ready:
+    if( !rc && DBG_CIPHER ) {
        for(i=0; i < pubkey_get_nsig(algo); i++ )
            log_mpidump("   sig:", resarr[i] );
     }
-
-    return 0;
+    return rc;
 }
 
 /****************
@@ -321,113 +562,16 @@ pubkey_sign( int algo, MPI *resarr, MPI data, MPI *skey )
 int
 pubkey_verify( int algo, MPI hash, MPI *data, MPI *pkey )
 {
-    int rc = 0;
-
-    if( is_ELGAMAL( algo ) ) {
-       ELG_public_key pk;
-       pk.p = pkey[0];
-       pk.g = pkey[1];
-       pk.y = pkey[2];
-       if( !elg_verify( data[0], data[1], hash, &pk ) )
-           rc = G10ERR_BAD_SIGN;
-    }
-    else if( algo == PUBKEY_ALGO_DSA ) {
-       DSA_public_key pk;
-       pk.p = pkey[0];
-       pk.q = pkey[1];
-       pk.g = pkey[2];
-       pk.y = pkey[3];
-       if( !dsa_verify( data[0], data[1], hash, &pk ) )
-           rc = G10ERR_BAD_SIGN;
-    }
- #ifdef HAVE_RSA_CIPHER
-    else if( algo == PUBKEY_ALGO_RSA || algo == PUBKEY_ALGO_RSA_S ) {
-       RSA_public_key pk;
-       int i, j, c, old_enc;
-       byte *dp;
-       const byte *asn;
-       size_t mdlen, asnlen;
-
-       pk.e = pkey[0];
-       pk.n = pkey[1];
-       result = mpi_alloc(40);
-       rsa_public( result, data[0], &pk );
-
-       old_enc = 0;
-       for(i=j=0; (c=mpi_getbyte(result, i)) != -1; i++ ) {
-           if( !j ) {
-               if( !i && c != 1 )
-                   break;
-               else if( i && c == 0xff )
-                   ; /* skip the padding */
-               else if( i && !c )
-                   j++;
-               else
-                   break;
-           }
-           else if( ++j == 18 && c != 1 )
-               break;
-           else if( j == 19 && c == 0 ) {
-               old_enc++;
-               break;
-           }
-       }
-       if( old_enc ) {
-           log_error("old encoding scheme is not supported\n");
-           rc = G10ERR_GENERAL;
-           goto leave;
-       }
-
-       if( (rc=check_digest_algo(sig->digest_algo)) )
-           goto leave; /* unsupported algo */
-       md_enable( digest, sig->digest_algo );
-       asn = md_asn_oid( sig->digest_algo, &asnlen, &mdlen );
-
-       for(i=mdlen,j=asnlen-1; (c=mpi_getbyte(result, i)) != -1 && j >= 0;
-                                                              i++, j-- )
-           if( asn[j] != c )
-               break;
-       if( j != -1 || mpi_getbyte(result, i) ) { /* ASN is wrong */
-           rc = G10ERR_BAD_PUBKEY;
-           goto leave;
-       }
-       for(i++; (c=mpi_getbyte(result, i)) != -1; i++ )
-           if( c != 0xff  )
-               break;
-       i++;
-       if( c != sig->digest_algo || mpi_getbyte(result, i) ) {
-           /* Padding or leading bytes in signature is wrong */
-           rc = G10ERR_BAD_PUBKEY;
-           goto leave;
-       }
-       if( mpi_getbyte(result, mdlen-1) != sig->digest_start[0]
-           || mpi_getbyte(result, mdlen-2) != sig->digest_start[1] ) {
-           /* Wrong key used to check the signature */
-           rc = G10ERR_BAD_PUBKEY;
-           goto leave;
-       }
+    int i, rc;
 
-       /* complete the digest */
-       md_putc( digest, sig->sig_class );
-       {   u32 a = sig->timestamp;
-           md_putc( digest, (a >> 24) & 0xff );
-           md_putc( digest, (a >> 16) & 0xff );
-           md_putc( digest, (a >>  8) & 0xff );
-           md_putc( digest,  a        & 0xff );
-       }
-       md_final( digest );
-       dp = md_read( digest, sig->digest_algo );
-       for(i=mdlen-1; i >= 0; i--, dp++ ) {
-           if( mpi_getbyte( result, i ) != *dp ) {
-               rc = G10ERR_BAD_SIGN;
-               break;
+    do {
+       for(i=0; pubkey_table[i].name; i++ )
+           if( pubkey_table[i].algo == algo ) {
+               rc = (*pubkey_table[i].verify)( algo, hash, data, pkey );
+               goto ready;
            }
-       }
-    }
-  #endif
-    else
-       rc = G10ERR_PUBKEY_ALGO;
-
+    } while( load_pubkey_modules() );
+    rc = G10ERR_PUBKEY_ALGO;
+  ready:
     return rc;
 }
-