* random.c: Fix prototype of the fast random gatherer. Noted by Joe
[gnupg.git] / cipher / pubkey.c
index b18f1c3..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 "cipher.h"
 #include "elgamal.h"
 #include "dsa.h"
-#include "dynload.h"
+#include "rsa.h"
 
-
-#define TABLE_SIZE 20
+#define TABLE_SIZE 10
 
 struct pubkey_table_s {
     const char *name;
@@ -42,21 +43,21 @@ struct pubkey_table_s {
     int nskey;
     int nenc;
     int nsig;
-    int usage;
+    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,
-                  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];
 
 
-
+#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; }
@@ -64,6 +65,7 @@ dummy_generate( int algo, unsigned nbits, MPI *skey, MPI **retfactors )
 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 )
@@ -78,59 +80,38 @@ 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,
-               int (*cmp)(void *, MPI), void *opaquev )
+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()
+setup_pubkey_table(void)
 {
+    int i=0;
 
-    static int initialized = 0;
-    int i;
-
-    if( initialized )
-       return;
-
-    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].usage );
-    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,
                                         &pubkey_table[i].nskey,
                                         &pubkey_table[i].nenc,
                                         &pubkey_table[i].nsig,
-                                        &pubkey_table[i].usage );
+                                        &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].sign            = dummy_sign;
+    pubkey_table[i].verify          = dummy_verify;
     pubkey_table[i].get_nbits       = elg_get_nbits;
     if( !pubkey_table[i].name )
        BUG();
@@ -141,7 +122,7 @@ setup_pubkey_table()
                                         &pubkey_table[i].nskey,
                                         &pubkey_table[i].nenc,
                                         &pubkey_table[i].nsig,
-                                        &pubkey_table[i].usage );
+                                        &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;
@@ -153,9 +134,62 @@ setup_pubkey_table()
        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;
-    initialized = 1;
 }
 
 
@@ -163,68 +197,16 @@ setup_pubkey_table()
  * Try to load all modules and return true if new modules are available
  */
 static int
-load_pubkey_modules()
+load_pubkey_modules(void)
 {
-    static int done = 0;
-    void *context = NULL;
-    struct pubkey_table_s *ct;
-    int ct_idx;
-    int i;
-    const char *name;
-    int any = 0;
-
-    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->usage,
-                               &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;
-       }
+    static int initialized = 0;
 
-       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_opt_verbose > 1 )
-           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;
-       }
+    if( !initialized ) {
+       setup_pubkey_table();
+       initialized = 1;
+       return 1;
     }
-    enum_gnupgext_pubkeys( &context, NULL, NULL, NULL, NULL, NULL, NULL,
-                              NULL, NULL, NULL, NULL, NULL, NULL, NULL );
-    return any;
+    return 0;
 }
 
 
@@ -237,10 +219,9 @@ string_to_pubkey_algo( const char *string )
     int i;
     const char *s;
 
-    setup_pubkey_table();
     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;
@@ -255,7 +236,6 @@ pubkey_algo_to_string( int algo )
 {
     int i;
 
-    setup_pubkey_table();
     do {
        for(i=0; pubkey_table[i].name; i++ )
            if( pubkey_table[i].algo == algo )
@@ -265,6 +245,20 @@ pubkey_algo_to_string( int algo )
 }
 
 
+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 )
@@ -273,21 +267,27 @@ check_pubkey_algo( int algo )
 }
 
 /****************
- * a usage of 0 means: don't care
+ * a use of 0 means: don't care
  */
 int
-check_pubkey_algo2( int algo, unsigned usage )
+check_pubkey_algo2( int algo, unsigned use )
 {
     int i;
 
-    setup_pubkey_table();
     do {
        for(i=0; pubkey_table[i].name; i++ )
            if( pubkey_table[i].algo == algo ) {
-               if( (usage & 1) && !(pubkey_table[i].usage & 1) )
+               if( (use & PUBKEY_USAGE_SIG)
+                   && !(pubkey_table[i].use & PUBKEY_USAGE_SIG) )
                    return G10ERR_WR_PUBKEY_ALGO;
-               if( (usage & 2) && !(pubkey_table[i].usage & 2) )
+               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() );
@@ -304,12 +304,20 @@ int
 pubkey_get_npkey( int algo )
 {
     int i;
-    setup_pubkey_table();
     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;
 }
 
@@ -320,12 +328,20 @@ int
 pubkey_get_nskey( int algo )
 {
     int i;
-    setup_pubkey_table();
     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;
 }
 
@@ -336,12 +352,20 @@ int
 pubkey_get_nsig( int algo )
 {
     int i;
-    setup_pubkey_table();
     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;
 }
 
@@ -352,12 +376,20 @@ int
 pubkey_get_nenc( int algo )
 {
     int i;
-    setup_pubkey_table();
     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;
 }
 
@@ -369,12 +401,20 @@ pubkey_nbits( int algo, MPI *pkey )
 {
     int i;
 
-    setup_pubkey_table();
     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;
 }
 
@@ -384,7 +424,6 @@ pubkey_generate( int algo, unsigned nbits, MPI *skey, MPI **retfactors )
 {
     int i;
 
-    setup_pubkey_table();
     do {
        for(i=0; pubkey_table[i].name; i++ )
            if( pubkey_table[i].algo == algo )
@@ -400,7 +439,6 @@ pubkey_check_secret_key( int algo, MPI *skey )
 {
     int i;
 
-    setup_pubkey_table();
     do {
        for(i=0; pubkey_table[i].name; i++ )
            if( pubkey_table[i].algo == algo )
@@ -421,9 +459,6 @@ pubkey_encrypt( int algo, MPI *resarr, MPI data, MPI *pkey )
 {
     int i, rc;
 
-    /* FIXME: check that data fits into the key (in xxx_encrypt)*/
-
-    setup_pubkey_table();
     if( DBG_CIPHER ) {
        log_debug("pubkey_encrypt: algo=%d\n", algo );
        for(i=0; i < pubkey_get_npkey(algo); i++ )
@@ -461,7 +496,6 @@ pubkey_decrypt( int algo, MPI *result, MPI *data, MPI *skey )
 {
     int i, rc;
 
-    setup_pubkey_table();
     *result = NULL; /* so the caller can always do an mpi_free */
     if( DBG_CIPHER ) {
        log_debug("pubkey_decrypt: algo=%d\n", algo );
@@ -489,7 +523,7 @@ pubkey_decrypt( int algo, MPI *result, MPI *data, MPI *skey )
 
 /****************
  * 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() )
  */
@@ -498,7 +532,6 @@ pubkey_sign( int algo, MPI *resarr, MPI data, MPI *skey )
 {
     int i, rc;
 
-    setup_pubkey_table();
     if( DBG_CIPHER ) {
        log_debug("pubkey_sign: algo=%d\n", algo );
        for(i=0; i < pubkey_get_nskey(algo); i++ )
@@ -527,17 +560,14 @@ pubkey_sign( int algo, MPI *resarr, MPI data, MPI *skey )
  * Return 0 if the signature is good
  */
 int
-pubkey_verify( int algo, MPI hash, MPI *data, MPI *pkey,
-                   int (*cmp)(void *, MPI), void *opaquev )
+pubkey_verify( int algo, MPI hash, MPI *data, MPI *pkey )
 {
     int i, rc;
 
-    setup_pubkey_table();
     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() );
@@ -545,4 +575,3 @@ pubkey_verify( int algo, MPI hash, MPI *data, MPI *pkey,
   ready:
     return rc;
 }
-