See ChangeLog: Fri Jul 14 19:38:23 CEST 2000 Werner Koch
authorWerner Koch <wk@gnupg.org>
Fri, 14 Jul 2000 17:34:53 +0000 (17:34 +0000)
committerWerner Koch <wk@gnupg.org>
Fri, 14 Jul 2000 17:34:53 +0000 (17:34 +0000)
104 files changed:
ChangeLog
acconfig.h
acinclude.m4
cipher/ChangeLog
cipher/Makefile.am
cipher/blowfish.c
cipher/cast5.c
cipher/des.c
cipher/dsa.c
cipher/elgamal.c
cipher/md.c
cipher/md5.c
cipher/primegen.c
cipher/pubkey.c
cipher/random.c
cipher/rmd160.c
cipher/rndegd.c
cipher/rndunix.c
cipher/rndw32.c
cipher/rsa.c [new file with mode: 0644]
cipher/rsa.h [new file with mode: 0644]
cipher/sha1.c
cipher/tiger.c
cipher/twofish.c
configure.in
g10/ChangeLog
g10/Makefile.am
g10/armor.c
g10/build-packet.c
g10/cipher.c
g10/comment.c
g10/compress.c
g10/dearmor.c
g10/decrypt.c
g10/delkey.c
g10/encode.c
g10/encr-data.c
g10/export.c
g10/filter.h
g10/free-packet.c
g10/getkey.c
g10/gpg.c
g10/gpgd.c
g10/helptext.c
g10/hkp.c
g10/hkp.h
g10/import.c
g10/kbnode.c
g10/kbxblob.c
g10/kbxfile.c
g10/keydb.h
g10/keyedit.c
g10/keygen.c
g10/keyid.c
g10/keylist.c
g10/ks-proto.h
g10/main.h
g10/mainproc.c
g10/mdfilter.c
g10/misc.c
g10/openfile.c
g10/options.h
g10/packet.h
g10/parse-packet.c
g10/passphrase.c
g10/pkclist.c
g10/plaintext.c
g10/pubkey-enc.c
g10/revoke.c
g10/ringedit.c
g10/seckey-cert.c
g10/seskey.c
g10/sig-check.c
g10/sign.c
g10/signal.c
g10/skclist.c
g10/status.c
g10/status.h
g10/tdbdump.c
g10/tdbio.c
g10/tdbio.h
g10/textfilter.c
g10/trustdb.c
g10/trustdb.h
g10/verify.c
include/ChangeLog
include/errors.h
include/http.h
include/iobuf.h
include/types.h
include/util.h
jnlib/ChangeLog
jnlib/argparse.c
jnlib/dotlock.c
jnlib/dotlock.h
util/ChangeLog
util/Makefile.am
util/http.c
util/iobuf.c
util/logger.c
util/miscutil.c
util/simple-gettext.c
util/strgutil.c
util/ttyio.c

index e0091e2..d33da81 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,6 +1,69 @@
+Fri Jul 14 19:38:23 CEST 2000  Werner Koch  <wk@>
+
+  The big merge between this one and the stable branch 1.0.  Still need
+  to merge TNANKS, AUTHORS and such.  It probaly does not compile yet.
+
+  * acinclude.m4 (GNUPG_CHECK_MLOCK): Fixed syntax error in C code.
+
+  * configure.in: Add check for termio.h, wait unctiosn and sigaction.
+
+  * acinclude.m4, configure.in (GNUPG_CHECK_GNUMAKE): New.
+
+  * acinclude.m4 (MKDIR_TAKES_ONE_ARG): Check some headers. By Gaël Quéri.
+
+  * configure.in (AM_INIT_AUTOMAKE): Use this now. By Gaël.
+
+  * acinclude.m4 (GNUPG_CHECK_EXPORTDYNAMIC): Replacement for
+  GNUPG_CHECK_RDYNAMIC which should handle gcc with non GNU ld nicer.
+  Contributed by Dave Dykstra.
+  * configure.in (GNYPG_CHECK_RDYNAMIC): Replaced by the new check.
+
+  * configure.in: Add a test for unisgned long long.
+
+  * configure.in (DYNLINK_MOD_CFLAGS): Set different for NetBSD.
+
+  * configure.in: Add check for clock_gettime
+
+  * configure.in (ALL_LINGUAS): Add nl.
+  * configure.in (ALL_LINGUAS): Add Esperanto.
+  * configure.in (ALL_LINGUAS): Add sv and ja.
+
+  * configure.in: Use /usr/local for CFLAGS and LDFLAGS when
+  target is freebsd.  By Rémi.
+
+  * configure.in: Do not set development version when the version has
+  a dash in it.  Suggested by Dave Dykstra.
+
+  * configure.in: Removed substitution for doc/gph/Makefile.
+  Do all the gcc warning only in maintainer mode.
+
+  * configure.in (dlopen): Use CHECK_FUNC for a test of dlopen in libc.
+  Suggested by Alexandre Oliva.
+  (-Wall): Moved the settting of gcc warning options near to the end
+  so that tests don't get confused.  Suggested by Paul D. Smith.
+
+  * acinclude.m4 (GNUPG_SYS_NM_PARSE): Added BSDI support.
+  (GNUPG_CHECK_RDYNAMIC): Ditto.
+
+  * acinclude.m4 (GNUPG_CHECK_MLOCK): Changed the way to test for
+  librt.  Test suggested by Jeff Long.
+
+  * acinclude.m4 (GNUPG_CHECK_MLOCK): Do librt check only when
+  we can't link a test program.  This way GNU systems don't need
+  to link against linrt.
+  (GNUPG_CHECK_IPC): Fixed use of TRY_COMPILE macro.  From Tim Mooney.
+
+  * acinclude.m4 (GNUPG_SYS_SYMBOL_UNDERSCORE): Add support for
+  DJGPP.
+  (GNUPG_CHECK_MLOCK): Check whether mlock sits in librt.
+
+  * acinclude.m4 (GNUPG_CHECK_RDYNAMIC): Add NetBSD. By Thomas Klausner.
+
+  * acconfig.h (HAVE_MLOCK): Added
+
 Mon Mar 13 19:22:46 CET 2000  Werner Koch  <wk@openit.de>
 
-       * configure.in: Now uses the Docbook M$s from GPH.
+       * configure.in: Now uses the Docbook M4s from GPH.
 
 Mon Jan 31 17:46:35 CET 2000  Werner Koch  <wk@>
 
index d364c7b..a2c9128 100644 (file)
@@ -53,6 +53,8 @@
 
 #undef HAVE_STPCPY
 
+#undef HAVE_MLOCK
+
 
 #undef BIG_ENDIAN_HOST
 #undef LITTLE_ENDIAN_HOST
index 20c92be..9f8bfd0 100644 (file)
@@ -50,6 +50,25 @@ AC_DEFUN(GNUPG_FIX_HDR_VERSION,
   ])
 
 
+dnl GNUPG_CHECK_GNUMAKE
+dnl
+AC_DEFUN(GNUPG_CHECK_GNUMAKE,
+  [
+    if ${MAKE-make} --version 2>/dev/null | grep '^GNU ' >/dev/null 2>&1; then
+        :
+    else
+        AC_MSG_WARN([[
+***
+*** It seems that you are not using GNU make.  Some make tools have serious
+*** flaws and you may not be able to build this software at all. Before you
+*** complain, please try GNU make:  GNU make is easy to build and available
+*** at all GNU archives.  It is always available from ftp.gnu.org:/gnu/make.
+***]])
+    fi
+  ])
+
+
+
 dnl GNUPG_LINK_FILES( SRC, DEST )
 dnl same as AC_LINK_FILES, but collect the files to link in
 dnl some special variables and do the link
@@ -212,39 +231,38 @@ define(GNUPG_CHECK_PIC,
 
 
 ######################################################################
-# Check for rdynamic flag
-# This sets CFLAGS_RDYNAMIC to the required flags
+# Check for export-dynamic flag
+# This sets CFLAGS_EXPORTDYNAMIC to the required flags
 ######################################################################
-dnl GNUPG_CHECK_RDYNAMIC
+dnl GNUPG_CHECK_EXPORTDYNAMIC
 dnl
-define(GNUPG_CHECK_RDYNAMIC,
-  [ AC_MSG_CHECKING(how to specify -rdynamic)
-    CFLAGS_RDYNAMIC=
+define(GNUPG_CHECK_EXPORTDYNAMIC,
+  [ AC_MSG_CHECKING(how to specify -export-dynamic)
     if test "$cross_compiling" = yes; then
-        AC_MSG_RESULT(assume none)
+      AC_MSG_RESULT(assume none)
+      CFLAGS_EXPORTDYNAMIC=""
     else
-        case "$host_os" in
-          solaris* )
-            CFLAGS_RDYNAMIC="-Wl,-dy"
-            ;;
-
-          hpux* )
-            CFLAGS_RDYNAMIC="-Wl,-E"
-            ;;
-
-          openbsd* | freebsd2* | osf4* | irix* )
-            CFLAGS_RDYNAMIC=""
-            ;;
-
-          * )
-            CFLAGS_RDYNAMIC="-Wl,-export-dynamic"
-            ;;
-        esac
-        AC_MSG_RESULT($CFLAGS_RDYNAMIC)
+      AC_CACHE_VAL(gnupg_cv_export_dynamic,[
+      if AC_TRY_COMMAND([${CC-cc} $CFLAGS -Wl,--version 2>&1 |
+                                          grep "GNU ld" >/dev/null]); then
+          # using gnu's linker
+          gnupg_cv_export_dynamic="-Wl,-export-dynamic"
+      else
+          case "$host_os" in
+            hpux* )
+              gnupg_cv_export_dynamic="-Wl,-E"
+              ;;
+            * )
+              gnupg_cv_export_dynamic=""
+              ;;
+          esac
+      fi
+      ])
+      AC_MSG_RESULT($gnupg_cv_export_dynamic)
+      CFLAGS_EXPORTDYNAMIC="$gnupg_cv_export_dynamic"
     fi
   ])
 
-
 #####################################################################
 # Check for SysV IPC  (from GIMP)
 #   And see whether we have a SHM_LOCK (FreeBSD does not have it).
@@ -299,7 +317,8 @@ define(GNUPG_CHECK_IPC,
           AC_TRY_COMPILE([#include <sys/types.h>
              #include <sys/ipc.h>
              #include <sys/shm.h>],[
-             int foo( int shm_id ) {  shmctl(shm_id, SHM_LOCK, 0); }
+             int shm_id;
+             shmctl(shm_id, SHM_LOCK, 0);
              ],
              gnupg_cv_ipc_have_shm_lock="yes",
              gnupg_cv_ipc_have_shm_lock="no"
@@ -318,11 +337,46 @@ define(GNUPG_CHECK_IPC,
 ######################################################################
 # Check whether mlock is broken (hpux 10.20 raises a SIGBUS if mlock
 # is not called from uid 0 (not tested whether uid 0 works)
+# For DECs Tru64 we have also to check whether mlock is in librt
+# mlock is there a macro using memlk()
 ######################################################################
 dnl GNUPG_CHECK_MLOCK
 dnl
 define(GNUPG_CHECK_MLOCK,
   [ AC_CHECK_FUNCS(mlock)
+    if test "$ac_cv_func_mlock" = "no"; then
+        AC_CHECK_HEADERS(sys/mman.h)
+        if test "$ac_cv_header_sys_mman_h" = "yes"; then
+            # Add librt to LIBS:
+            AC_CHECK_LIB(rt, memlk)
+            AC_CACHE_CHECK([whether mlock is in sys/mman.h],
+                            gnupg_cv_mlock_is_in_sys_mman,
+                [AC_TRY_LINK([
+                    #include <assert.h>
+                    #ifdef HAVE_SYS_MMAN_H
+                    #include <sys/mman.h>
+                    #endif
+                ], [
+                    int i;
+                    mkdir ("foo", 0);
+                    /* glibc defines this for functions which it implements
+                     * to always fail with ENOSYS.  Some functions are actually
+                     * named something starting with __ and the normal name
+                     * is an alias.  */
+                    #if defined (__stub_mlock) || defined (__stub___mlock)
+                    choke me
+                    #else
+                    mlock(&i, 4);
+                    #endif
+                    ; return 0;
+                ],
+                gnupg_cv_mlock_is_in_sys_mman=yes,
+                gnupg_cv_mlock_is_in_sys_mman=no)])
+            if test "$gnupg_cv_mlock_is_in_sys_mman" = "yes"; then
+                AC_DEFINE(HAVE_MLOCK)
+            fi
+        fi
+    fi
     if test "$ac_cv_func_mlock" = "yes"; then
         AC_MSG_CHECKING(whether mlock is broken)
           AC_CACHE_VAL(gnupg_cv_have_broken_mlock,
@@ -372,9 +426,10 @@ define(GNUPG_CHECK_MLOCK,
   ])
 
 
-################################################################
 
+################################################################
 # GNUPG_PROG_NM - find the path to a BSD-compatible name lister
+################################################################
 AC_DEFUN(GNUPG_PROG_NM,
 [AC_MSG_CHECKING([for BSD-compatible nm])
 AC_CACHE_VAL(ac_cv_path_NM,
@@ -433,7 +488,7 @@ case "$host_os" in
 aix*)
   ac_symcode='[BCDTU]'
   ;;
-freebsd* | netbsd* | openbsd* | sunos* | cygwin32* | mingw32*)
+freebsd* | netbsd* | openbsd* | bsdi* | sunos* | cygwin32* | mingw32*)
   ac_sympat='_\([_A-Za-z][_A-Za-z0-9]*\)'
   ac_symxfrm='_\1 \1'
   ;;
@@ -586,7 +641,7 @@ AC_CHECK_TOOL(AS, as, false)
 AC_DEFUN(GNUPG_SYS_SYMBOL_UNDERSCORE,
 [tmp_do_check="no"
 case "${target}" in
-    i386-emx-os2 | i[3456]86-pc-os2*emx )
+    i386-emx-os2 | i[3456]86-pc-os2*emx | i386-pc-msdosdjgpp)
         ac_cv_sys_symbol_underscore=yes
         ;;
     *)
@@ -645,7 +700,8 @@ dnl Stolen from gcc
 dnl Define MKDIR_TAKES_ONE_ARG if mkdir accepts only one argument instead
 dnl of the usual 2.
 AC_DEFUN(GNUPG_FUNC_MKDIR_TAKES_ONE_ARG,
-[AC_CACHE_CHECK([if mkdir takes one argument], gnupg_cv_mkdir_takes_one_arg,
+[AC_CHECK_HEADERS(sys/stat.h unistd.h direct.h)
+AC_CACHE_CHECK([if mkdir takes one argument], gnupg_cv_mkdir_takes_one_arg,
 [AC_TRY_COMPILE([
 #include <sys/types.h>
 #ifdef HAVE_SYS_STAT_H
@@ -663,7 +719,6 @@ if test $gnupg_cv_mkdir_takes_one_arg = yes ; then
 fi
 ])
 
-
 dnl GPH_PROG_DOCBOOK()
 dnl Check whether we have the needed Docbook environment
 dnl and issue a warning if this is not the case.
index 49595a9..877a2ad 100644 (file)
@@ -1,3 +1,85 @@
+Fri Jul 14 19:38:23 CEST 2000  Werner Koch  <wk@>
+
+  * md.c (gcry_md_ctl): Support GCRYCTL_{START,STOP}_DUMP.
+
+  * Makefile.am: Never compile mingw32 as module.
+
+  * Makefile.am: Tweaked module build and removed libtool
+
+  * Makefile.am:  Replaced -O1 by -O. Suggested by Alec Habig.
+
+  * elgamal.c (sign): Removed inactive code.
+
+  * rsa.c, rsa.h: New based on the old module version (only in CVS for now).
+  * pubkey.c (setup_pubkey_table): Added commented support for RSA.
+
+  * rndunix.c (waitpid): New. For UTS 2.1.  All by Dave Dykstra.
+  (my_popen): Do the FD_CLOEXEC only if it is available
+  (start_gatherer): Cope with missing _SC_OPEN_MAX
+
+  * rndunix.c: Add some more headers for QNX. By Sam Roberts.
+
+  * rndegd.c (gather_random): Shortcut level 0.
+  * rndunix.c (gather_random): Ditto.
+  * rndw32.c (gather_random): Ditto.
+
+  * rndw32.c: Replaced with code from Cryptlib and commented the old stuff.
+  * rndw32.c: Add some debuging code enabled by an environment variable.
+
+  * random.c (read_seed_file): Binary open for DOSish system
+  (update_random_seed_file): Ditto.
+  * random.c [MINGW32]: Include process.h for getpid.
+  * random.c (fast_random_poll): Add clock_gettime() as fallback for
+  system which support this POSIX.4 fucntion. By Sam Roberts.
+
+  * random.c (read_seed_file): Removed the S_ISLNK test becuase it
+  is already covered by !S_ISREG and is not defined in Unixware.
+  Reported by Dave Dykstra.
+  (update_random_seed_file): Silently ignore update request when pool
+  is not filled.
+
+  * random.c (read_seed_file): New.
+  (set_random_seed_file): New.
+  (read_pool): Try to read the seeding file.
+  (update_random_seed_file): New.
+
+  (read_pool): Do an initial extra seeding when level 2 quality random
+  is requested the first time. This requestes at least POOLSIZE/2 bytes
+  of entropy.  Compined with the seeding file this should make normal
+  random bytes cheaper and increase the quality of the random bytes
+  used for key generation.
+
+  * random.c (read_pool): Print a more friendly error message in
+  cases when too much random is requested in one call.
+
+  * random.c (fast_random_poll): Check whether RUSAGE_SELF is defined;
+  this is not the case for some ESIX and Unixware, although they have
+  getrusage().
+
+  * primegen.c (generate_elg_prime): All primes are now generated with
+  the lowest random quality level.  Because they are public anyway we
+  don't need stronger random and by this we do not drain the systems
+  entropy so much.
+
+  * primegen.c (register_primegen_progress): New.
+  * dsa.c (register_pk_dsa_progress): New.
+  * elgamal.c (register_pk_elg_progress): New.
+
+  * elgamal.c (wiener_map): New.
+  (gen_k): Use a much smaller k.
+  (generate): Calculate the qbits using the wiener map and
+  choose an x at a size comparable to the one choosen in gen_k
+
+  * rmd160.c (rmd160_get_info): Moved casting to the left side due to a
+  problem with UTS4.3. Suggested by Dave Dykstra.
+  * sha1.c (sha1_get_info): Ditto.
+  * tiger.c (tiger_get_info): Ditto.
+  * md5.c (md5_get_info): Ditto
+  * des.c (des_get_info): Ditto.
+  * blowfish.c (blowfish_get_info): Ditto.
+  * cast5.c (cast5_get_info): Ditto.
+  * twofish.c (twofish_get_info): Ditto.
+
 Fri Mar 24 11:25:45 CET 2000  Werner Koch  <wk@openit.de>
 
        * md.c (md_open): Add hmac arg and allocate space for the pads.
index aa766bb..9792419 100644 (file)
@@ -5,15 +5,8 @@ INCLUDES = -I$(top_srcdir)/gcrypt
 
 noinst_LTLIBRARIES = libcipher.la
 
-# The configure script greps the module names from the following lines.
-# You must also add all these names to EXTRA_PROGRAMS some lines below
-# and EXTRA_foo_SOURCES entries.
-# Hmmm is there a more easy way to do this?  (EXTRA_PROGRAMS
-# might also list programs which are not modules)
-# MODULES: rndunix rndlinux rndegd rndw32
-# MODULES: sha1 rmd160 md5 tiger
-EXTRA_PROGRAMS = rndunix rndlinux rndegd rndw32 \
-                sha1 rmd160 md5 tiger
+# The configure script greps the module names from the EXTRA_PROGRAMS line
+EXTRA_PROGRAMS = rndlinux rndunix rndegd rndw32 sha1 rmd160 md5 tiger
 
 EXTRA_rndlinux_SOURCES = rndlinux.c
 EXTRA_rndunix_SOURCES = rndunix.c
@@ -73,7 +66,7 @@ libcipher_la_LIBADD =     @STATIC_CIPHER_OBJS@
 
 tiger: $(srcdir)/tiger.c
        `echo $(COMPILE) $(DYNLINK_MOD_CFLAGS) -o tiger $(srcdir)/tiger.c | \
-           sed -e 's/-O[2-9s]*/-O1/g' `
+           sed -e 's/-O[2-9s]*/-O/g' `
 
 tiger.o: $(srcdir)/tiger.c
        `echo $(COMPILE) -c $(srcdir)/tiger.c | sed -e 's/-O[2-9s]*/-O1/g' `
@@ -98,9 +91,3 @@ rndlinux: $(srcdir)/rndlinux.c
 rndegd: $(srcdir)/rndegd.c
        $(COMPILE) $(DYNLINK_MOD_CFLAGS) -o rndegd $(srcdir)/rndegd.c
 
-# We need to have a better system for selection which modules
-# to compile.  For now this works.
-rndw32: $(srcdir)/rndw32.c
-       echo "#!/bin/sh" >rndw32
-       echo "Not usable as a module" >>rndw32
-
index e7f047f..2bdb3b5 100644 (file)
@@ -584,9 +584,12 @@ blowfish_get_info( int algo, size_t *keylen,
     *keylen = 128;
     *blocksize = BLOWFISH_BLOCKSIZE;
     *contextsize = sizeof(BLOWFISH_context);
-    *r_setkey = FNCCAST_SETKEY(bf_setkey);
-    *r_encrypt= FNCCAST_CRYPT(encrypt_block);
-    *r_decrypt= FNCCAST_CRYPT(decrypt_block);
+    *(int  (**)(BLOWFISH_context*, byte*, unsigned))r_setkey
+                                                       = bf_setkey;
+    *(void (**)(BLOWFISH_context*, byte*, byte*))r_encrypt
+                                                       = encrypt_block;
+    *(void (**)(BLOWFISH_context*, byte*, byte*))r_decrypt
+                                                       = decrypt_block;
 
     if( algo == CIPHER_ALGO_BLOWFISH )
        return "BLOWFISH";
index aaa0a42..64f6bb0 100644 (file)
@@ -610,9 +610,13 @@ cast5_get_info( int algo, size_t *keylen,
     *keylen = 128;
     *blocksize = CAST5_BLOCKSIZE;
     *contextsize = sizeof(CAST5_context);
-    *r_setkey = FNCCAST_SETKEY(cast_setkey);
-    *r_encrypt= FNCCAST_CRYPT(encrypt_block);
-    *r_decrypt= FNCCAST_CRYPT(decrypt_block);
+    *(int  (**)(CAST5_context*, byte*, unsigned))r_setkey
+                                                       = cast_setkey;
+    *(void (**)(CAST5_context*, byte*, byte*))r_encrypt
+                                                       = encrypt_block;
+    *(void (**)(CAST5_context*, byte*, byte*))r_decrypt
+                                                       = decrypt_block;
+
 
     if( algo == CIPHER_ALGO_CAST5 )
        return "CAST5";
index af5b584..9c3c541 100644 (file)
@@ -1001,9 +1001,12 @@ des_get_info( int algo, size_t *keylen,
        *keylen = 192;
        *blocksize = 8;
        *contextsize = sizeof(struct _tripledes_ctx);
-       *r_setkey = FNCCAST_SETKEY(do_tripledes_setkey);
-       *r_encrypt= FNCCAST_CRYPT(do_tripledes_encrypt);
-       *r_decrypt= FNCCAST_CRYPT(do_tripledes_decrypt);
+       *(int  (**)(struct _tripledes_ctx*, byte*, unsigned))r_setkey
+                                                       = do_tripledes_setkey;
+       *(void (**)(struct _tripledes_ctx*, byte*, byte*))r_encrypt
+                                                       = do_tripledes_encrypt;
+       *(void (**)(struct _tripledes_ctx*, byte*, byte*))r_decrypt
+                                                       = do_tripledes_decrypt;
        return "3DES";
     }
     return NULL;
index 1f132ae..255fa37 100644 (file)
@@ -1,5 +1,5 @@
 /* dsa.c  -  DSA signature scheme
- *     Copyright (C) 1998 Free Software Foundation, Inc.
+ *     Copyright (C) 1998, 2000 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
@@ -52,13 +52,28 @@ static void generate( DSA_secret_key *sk, unsigned nbits, MPI **ret_factors );
 static void sign(MPI r, MPI s, MPI input, DSA_secret_key *skey);
 static int  verify(MPI r, MPI s, MPI input, DSA_public_key *pkey);
 
+static void (*progress_cb) ( void *, int );
+static void *progress_cb_data;
+
+void
+register_pk_dsa_progress ( void (*cb)( void *, int), void *cb_data )
+{
+    progress_cb = cb;
+    progress_cb_data = cb_data;
+}
+
+
 static void
 progress( int c )
 {
-    fputc( c, stderr );
+    if ( progress_cb )
+       progress_cb ( progress_cb_data, c );
+    else
+       fputc( c, stderr );
 }
 
 
+
 /****************
  * Generate a random secret exponent k less than q
  */
index 02995e0..f2c029b 100644 (file)
@@ -1,5 +1,5 @@
 /* elgamal.c  -  ElGamal Public Key encryption
- *     Copyright (C) 1998 Free Software Foundation, Inc.
+ *     Copyright (C) 1998, 2000 Free Software Foundation, Inc.
  *
  * For a description of the algorithm, see:
  *   Bruce Schneier: Applied Cryptography. John Wiley & Sons, 1996.
@@ -56,13 +56,67 @@ static void sign(MPI a, MPI b, MPI input, ELG_secret_key *skey);
 static int  verify(MPI a, MPI b, MPI input, ELG_public_key *pkey);
 
 
+static void (*progress_cb) ( void *, int );
+static void *progress_cb_data;
+
+void
+register_pk_elg_progress ( void (*cb)( void *, int), void *cb_data )
+{
+    progress_cb = cb;
+    progress_cb_data = cb_data;
+}
+
+
 static void
 progress( int c )
 {
-    fputc( c, stderr );
+    if ( progress_cb )
+       progress_cb ( progress_cb_data, c );
+    else
+       fputc( c, stderr );
 }
 
 
+/****************
+ * Michael Wiener's table on subgroup sizes to match field sizes
+ * (floating around somewhere - Fixme: need a reference)
+ */
+static unsigned int
+wiener_map( unsigned int n )
+{
+    static struct { unsigned int p_n, q_n; } t[] =
+    {  /*   p    q      attack cost */
+       {  512, 119 },  /* 9 x 10^17 */
+       {  768, 145 },  /* 6 x 10^21 */
+       { 1024, 165 },  /* 7 x 10^24 */
+       { 1280, 183 },  /* 3 x 10^27 */
+       { 1536, 198 },  /* 7 x 10^29 */
+       { 1792, 212 },  /* 9 x 10^31 */
+       { 2048, 225 },  /* 8 x 10^33 */
+       { 2304, 237 },  /* 5 x 10^35 */
+       { 2560, 249 },  /* 3 x 10^37 */
+       { 2816, 259 },  /* 1 x 10^39 */
+       { 3072, 269 },  /* 3 x 10^40 */
+       { 3328, 279 },  /* 8 x 10^41 */
+       { 3584, 288 },  /* 2 x 10^43 */
+       { 3840, 296 },  /* 4 x 10^44 */
+       { 4096, 305 },  /* 7 x 10^45 */
+       { 4352, 313 },  /* 1 x 10^47 */
+       { 4608, 320 },  /* 2 x 10^48 */
+       { 4864, 328 },  /* 2 x 10^49 */
+       { 5120, 335 },  /* 3 x 10^50 */
+       { 0, 0 }
+    };
+    int i;
+
+    for(i=0; t[i].p_n; i++ )  {
+       if( n <= t[i].p_n )
+           return t[i].q_n;
+    }
+    /* not in table - use some arbitrary high number ;-) */
+    return  n / 8 + 200;
+}
+
 static void
 test_keys( ELG_secret_key *sk, unsigned nbits )
 {
@@ -104,38 +158,44 @@ gen_k( MPI p )
     MPI k = mpi_alloc_secure( 0 );
     MPI temp = mpi_alloc( mpi_get_nlimbs(p) );
     MPI p_1 = mpi_copy(p);
-    unsigned int nbits = mpi_get_nbits(p);
-    unsigned int nbytes = (nbits+7)/8;
+    unsigned int orig_nbits = mpi_get_nbits(p);
+    unsigned int nbits, nbytes;
     char *rndbuf = NULL;
 
+    /* IMO using a k much lesser than p is sufficient and it greatly
+     * improves the encryption performance.  We use Wiener's table
+     * and add a large safety margin.
+     */
+    nbits = wiener_map( orig_nbits ) * 3 / 2;
+    if( nbits >= orig_nbits )
+       BUG();
+
+    nbytes = (nbits+7)/8;
     if( DBG_CIPHER )
        log_debug("choosing a random k ");
     mpi_sub_ui( p_1, p, 1);
     for(;;) {
-       if( DBG_CIPHER )
-           progress('.');
        if( !rndbuf || nbits < 32 ) {
            g10_free(rndbuf);
            rndbuf = gcry_random_bytes_secure( nbytes, GCRY_STRONG_RANDOM );
        }
        else { /* change only some of the higher bits */
-           /* we could imporove this by directly requesting more memory
+           /* we could improve this by directly requesting more memory
             * at the first call to get_random_bytes() and use this the here
-            * maybe it is easier to do this directly in random.c */
+            * maybe it is easier to do this directly in random.c
+            * Anyway, it is highly inlikely that we will ever reach this code
+            */
            char *pp = gcry_random_bytes_secure( 4, GCRY_STRONG_RANDOM );
            memcpy( rndbuf, pp, 4 );
            g10_free(pp);
+           log_debug("gen_k: tsss, never expected to reach this\n");
        }
        mpi_set_buffer( k, rndbuf, nbytes, 0 );
 
        for(;;) {
-           /* make sure that the number is of the exact lenght */
-           if( mpi_test_bit( k, nbits-1 ) )
-               mpi_set_highbit( k, nbits-1 );
-           else {
-               mpi_set_highbit( k, nbits-1 );
-               mpi_clear_bit( k, nbits-1 );
-           }
+           /* Hmm, actually we don't need this step here
+            * because we use k much smaller than p - we do it anyway
+            * just in case the keep on adding a one to k ;) */
            if( !(mpi_cmp( k, p_1 ) < 0) ) {  /* check: k < (p-1) */
                if( DBG_CIPHER )
                    progress('+');
@@ -149,6 +209,8 @@ gen_k( MPI p )
            if( mpi_gcd( temp, k, p_1 ) )
                goto found;  /* okay, k is relatively prime to (p-1) */
            mpi_add_ui( k, k, 1 );
+           if( DBG_CIPHER )
+               progress('.');
        }
     }
   found:
@@ -167,7 +229,7 @@ gen_k( MPI p )
  *         and an array with n-1 factors of (p-1)
  */
 static void
-generate(  ELG_secret_key *sk, unsigned nbits, MPI **ret_factors )
+generate(  ELG_secret_key *sk, unsigned int nbits, MPI **ret_factors )
 {
     MPI p;    /* the prime */
     MPI p_min1;
@@ -175,19 +237,15 @@ generate(  ELG_secret_key *sk, unsigned nbits, MPI **ret_factors )
     MPI x;    /* the secret exponent */
     MPI y;
     MPI temp;
-    unsigned qbits;
+    unsigned int qbits;
+    unsigned int xbits;
     byte *rndbuf;
 
     p_min1 = mpi_alloc( (nbits+BITS_PER_MPI_LIMB-1)/BITS_PER_MPI_LIMB );
     temp   = mpi_alloc( (nbits+BITS_PER_MPI_LIMB-1)/BITS_PER_MPI_LIMB );
-    if( nbits < 512 )
-       qbits = 120;
-    else if( nbits <= 1024 )
-       qbits = 160;
-    else if( nbits <= 2048 )
-       qbits = 200;
-    else
-       qbits = 240;
+    qbits = wiener_map( nbits );
+    if( qbits & 1 ) /* better have a even one */
+       qbits++;
     g = mpi_alloc(1);
     p = generate_elg_prime( 0, nbits, qbits, g, ret_factors );
     mpi_sub_ui(p_min1, p, 1);
@@ -198,18 +256,26 @@ generate(  ELG_secret_key *sk, unsigned nbits, MPI **ret_factors )
      * This must be a very good random number because this is the
      * secret part.  The prime is public and may be shared anyway,
      * so a random generator level of 1 is used for the prime.
+     *
+     * I don't see a reason to have a x of about the same size
+     * as the p.  It should be sufficient to have one about the size
+     * of q or the later used k plus a large safety margin. Decryption
+     * will be much faster with such an x.
      */
-    x = mpi_alloc_secure( nbits/BITS_PER_MPI_LIMB );
+    xbits = qbits * 3 / 2;
+    if( xbits >= nbits )
+       BUG();
+    x = mpi_alloc_secure( xbits/BITS_PER_MPI_LIMB );
     if( DBG_CIPHER )
-       log_debug("choosing a random x ");
+       log_debug("choosing a random x of size %u", xbits );
     rndbuf = NULL;
     do {
        if( DBG_CIPHER )
            progress('.');
        if( rndbuf ) { /* change only some of the higher bits */
-           if( nbits < 16 ) {/* should never happen ... */
+           if( xbits < 16 ) {/* should never happen ... */
                g10_free(rndbuf);
-               rndbuf = gcry_random_bytes_secure( (nbits+7)/8,
+               rndbuf = gcry_random_bytes_secure( (xbits+7)/8,
                                                   GCRY_VERY_STRONG_RANDOM );
            }
            else {
@@ -220,11 +286,11 @@ generate(  ELG_secret_key *sk, unsigned nbits, MPI **ret_factors )
            }
        }
        else {
-           rndbuf = gcry_random_bytes_secure( (nbits+7)/8,
+           rndbuf = gcry_random_bytes_secure( (xbits+7)/8,
                                               GCRY_VERY_STRONG_RANDOM );
        }
-       mpi_set_buffer( x, rndbuf, (nbits+7)/8, 0 );
-       mpi_clear_highbit( x, nbits+1 );
+       mpi_set_buffer( x, rndbuf, (xbits+7)/8, 0 );
+       mpi_clear_highbit( x, xbits+1 );
     } while( !( mpi_cmp_ui( x, 0 )>0 && mpi_cmp( x, p_min1 )<0 ) );
     g10_free(rndbuf);
 
@@ -311,7 +377,6 @@ decrypt(MPI output, MPI a, MPI b, ELG_secret_key *skey )
     MPI t1 = mpi_alloc_secure( mpi_get_nlimbs( skey->p ) );
 
     /* output = b/(a^x) mod p */
-
     gcry_mpi_powm( t1, a, skey->x, skey->p );
     mpi_invm( t1, t1, skey->p );
     mpi_mulm( output, b, t1, skey->p );
@@ -351,10 +416,6 @@ sign(MPI a, MPI b, MPI input, ELG_secret_key *skey )
     gcry_mpi_powm( a, skey->g, k, skey->p );
     mpi_mul(t, skey->x, a );
     mpi_subm(t, input, t, p_1 );
-    while( mpi_is_neg(t) ) {
-       BUG();  /* That is nonsense code - left over from a very early test?*/
-       mpi_add(t, t, p_1);
-    }
     mpi_invm(inv, k, p_1 );
     mpi_mulm(b, t, inv, p_1 );
 
@@ -557,7 +618,7 @@ elg_verify( int algo, MPI hash, MPI *data, MPI *pkey,
 
 
 
-unsigned
+unsigned int
 elg_get_nbits( int algo, MPI *pkey )
 {
     if( !is_ELGAMAL(algo) )
@@ -587,10 +648,10 @@ elg_get_info( int algo, int *npkey, int *nskey, int *nenc, int *nsig,
     *nsig = 2;
 
     switch( algo ) {
-      case PUBKEY_ALGO_ELGAMAL:
+      case GCRY_PK_ELG:
        *use = GCRY_PK_USAGE_SIGN|GCRY_PK_USAGE_ENCR;
        return "ELG";
-      case PUBKEY_ALGO_ELGAMAL_E:
+      case GCRY_PK_ELG_E:
        *use = GCRY_PK_USAGE_SIGN|GCRY_PK_USAGE_ENCR;
        return "ELG-E";
       default: *use = 0; return NULL;
index 9879520..e8ac8ac 100644 (file)
@@ -562,6 +562,12 @@ gcry_md_ctl( GCRY_MD_HD hd, int cmd, byte *buffer, size_t buflen)
        else if ( !(rc = prepare_macpads( hd, buffer, buflen )) )
            gcry_md_reset( hd );
     }
+    else if( cmd == GCRYCTL_START_DUMP ) {
+       md_start_debug( hd, buffer );
+    }
+    else if( cmd == GCRYCTL_STOP_DUMP ) {
+       md_stop_debug( hd );
+    }
     else
        rc = GCRYERR_INV_OP;
     return set_lasterr( rc );
@@ -834,7 +840,7 @@ gcry_md_algo_info( int algo, int what, void *buffer, size_t *nbytes)
 
 
 
-void
+static void
 md_start_debug( GCRY_MD_HD md, const char *suffix )
 {
     static int idx=0;
@@ -851,7 +857,7 @@ md_start_debug( GCRY_MD_HD md, const char *suffix )
        log_debug("md debug: can't open %s\n", buf );
 }
 
-void
+static void
 md_stop_debug( GCRY_MD_HD md )
 {
     if( md->ctx->debug ) {
index 161d443..c4351f1 100644 (file)
@@ -344,10 +344,10 @@ md5_get_info( int algo, size_t *contextsize,
     *r_asnoid = asn;
     *r_asnlen = DIM(asn);
     *r_mdlen = 16;
-    *r_init  = (void (*)(void *))md5_init;
-    *r_write = (void (*)(void *, byte*, size_t))md5_write;
-    *r_final = (void (*)(void *))md5_final;
-    *r_read  = (byte *(*)(void *))md5_read;
+    *(void  (**)(MD5_CONTEXT *))r_init                = md5_init;
+    *(void  (**)(MD5_CONTEXT *, byte*, size_t))r_write = md5_write;
+    *(void  (**)(MD5_CONTEXT *))r_final               = md5_final;
+    *(byte *(**)(MD5_CONTEXT *))r_read                = md5_read;
 
     return "MD5";
 }
index 2f16b08..f5dca85 100644 (file)
@@ -1,5 +1,5 @@
 /* primegen.c - prime number generator
- *     Copyright (C) 1998 Free Software Foundation, Inc.
+ *     Copyright (C) 1998, 2000 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
@@ -38,11 +38,24 @@ static int check_prime( MPI prime, MPI val_2 );
 static int is_prime( MPI n, int steps, int *count );
 static void m_out_of_n( char *array, int m, int n );
 
+static void (*progress_cb) ( void *, int );
+static void *progress_cb_data;
+
+void
+register_primegen_progress ( void (*cb)( void *, int), void *cb_data )
+{
+    progress_cb = cb;
+    progress_cb_data = cb_data;
+}
+
 
 static void
 progress( int c )
 {
-    fputc( c, stderr );
+    if ( progress_cb )
+       progress_cb ( progress_cb_data, c );
+    else
+       fputc( c, stderr );
 }
 
 
@@ -117,8 +130,8 @@ generate_elg_prime( int mode, unsigned pbits, unsigned qbits,
        log_debug("gen prime: pbits=%u qbits=%u fbits=%u/%u n=%d\n",
                    pbits, req_qbits, qbits, fbits, n  );
     prime = mpi_alloc( (pbits + BITS_PER_MPI_LIMB - 1) /  BITS_PER_MPI_LIMB );
-    q = gen_prime( qbits, 0, 1 );
-    q_factor = mode==1? gen_prime( req_qbits, 0, 1 ) : NULL;
+    q = gen_prime( qbits, 0, 0 );
+    q_factor = mode==1? gen_prime( req_qbits, 0, 0 ) : NULL;
 
     /* allocate an array to hold the factors + 2 for later usage */
     factors = g10_xcalloc( n+2, sizeof *factors );
@@ -177,7 +190,7 @@ generate_elg_prime( int mode, unsigned pbits, unsigned qbits,
                count1 = 0;
                qbits++;
                progress('>');
-               q = gen_prime( qbits, 0, 1 );
+               q = gen_prime( qbits, 0, 0 );
                goto next_try;
            }
        }
@@ -188,7 +201,7 @@ generate_elg_prime( int mode, unsigned pbits, unsigned qbits,
                count2 = 0;
                qbits--;
                progress('<');
-               q = gen_prime( qbits, 0, 1 );
+               q = gen_prime( qbits, 0, 0 );
                goto next_try;
            }
        }
index 3ace1d8..b139720 100644 (file)
@@ -1,5 +1,5 @@
 /* pubkey.c  - pubkey dispatcher
- *     Copyright (C) 1998, 1999 Free Software Foundation, Inc.
+ *     Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
@@ -30,6 +30,9 @@
 #include "cipher.h"
 #include "elgamal.h"
 #include "dsa.h"
+#if 0
+#include "rsa.h"
+#endif
 #include "dynload.h"
 
 /* FIXME: use set_lasterr() */
@@ -193,6 +196,60 @@ setup_pubkey_table(void)
        BUG();
     i++;
 
+  #if 0
+    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
+
     for( ; i < TABLE_SIZE; i++ )
        pubkey_table[i].name = NULL;
 }
index 38991a1..f8faeeb 100644 (file)
@@ -1,5 +1,5 @@
 /* random.c  - random number generator
- *     Copyright (C) 1998 Free Software Foundation, Inc.
+ *     Copyright (C) 1998, 2000 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <unistd.h>
+#include <fcntl.h>
 #ifdef HAVE_GETHRTIME
   #include <sys/times.h>
 #endif
 #ifdef HAVE_GETTIMEOFDAY
   #include <sys/times.h>
 #endif
+#ifdef HAVE_CLOCK_GETTIME
+  #include <time.h>
+#endif
 #ifdef HAVE_GETRUSAGE
   #include <sys/resource.h>
 #endif
+#ifdef __MINGW32__
+  #include <process.h>
+#endif
 #include "g10lib.h"
 #include "rmd.h"
 #include "random.h"
@@ -89,6 +96,9 @@ static size_t pool_writepos;
 static int pool_filled;
 static int pool_balance;
 static int just_mixed;
+static int did_initial_extra_seeding;
+static char *seed_file_name;
+static int allow_seed_file_update;
 
 static int secure_alloc;
 static int quick_test;
@@ -274,6 +284,139 @@ mix_pool(byte *pool)
     }
 }
 
+void
+set_random_seed_file( const char *name )
+{
+    if( seed_file_name )
+       BUG();
+    seed_file_name = g10_xstrdup( name );
+}
+
+/****************
+ * Read in a seed form the random_seed file
+ * and return true if this was successful
+ */
+static int
+read_seed_file()
+{
+    int fd;
+    struct stat sb;
+    unsigned char buffer[POOLSIZE];
+    int n;
+
+    if( !seed_file_name )
+       return 0;
+
+  #ifdef HAVE_DOSISH_SYSTEM
+    fd = open( seed_file_name, O_RDONLY | O_BINARY );
+  #else
+    fd = open( seed_file_name, O_RDONLY );
+  #endif
+    if( fd == -1 && errno == ENOENT) {
+       allow_seed_file_update = 1;
+       return 0;
+    }
+
+    if( fd == -1 ) {
+       log_info(_("can't open `%s': %s\n"), seed_file_name, strerror(errno) );
+       return 0;
+    }
+    if( fstat( fd, &sb ) ) {
+       log_info(_("can't stat `%s': %s\n"), seed_file_name, strerror(errno) );
+       close(fd);
+       return 0;
+    }
+    if( !S_ISREG(sb.st_mode) ) {
+       log_info(_("`%s' is not a regular file - ignored\n"), seed_file_name );
+       close(fd);
+       return 0;
+    }
+    if( !sb.st_size ) {
+       log_info(_("note: random_seed file is empty\n") );
+       close(fd);
+       allow_seed_file_update = 1;
+       return 0;
+    }
+    if( sb.st_size != POOLSIZE ) {
+       log_info(_("warning: invalid size of random_seed file - not used\n") );
+       close(fd);
+       return 0;
+    }
+    do {
+       n = read( fd, buffer, POOLSIZE );
+    } while( n == -1 && errno == EINTR );
+    if( n != POOLSIZE ) {
+       log_fatal(_("can't read `%s': %s\n"), seed_file_name,strerror(errno) );
+       close(fd);
+       return 0;
+    }
+
+    close(fd);
+
+    add_randomness( buffer, POOLSIZE, 0 );
+    /* add some minor entropy to the pool now (this will also force a mixing) */
+    {  pid_t x = getpid();
+       add_randomness( &x, sizeof(x), 0 );
+    }
+    {  time_t x = time(NULL);
+       add_randomness( &x, sizeof(x), 0 );
+    }
+    {  clock_t x = clock();
+       add_randomness( &x, sizeof(x), 0 );
+    }
+    /* And read a few bytes from our entropy source.  By using
+     * a level of 0 this will not block and might not return anything
+     * with some entropy drivers, however the rndlinux driver will use
+     * /dev/urandom and return some stuff - Do not read to much as we
+     * want to be friendly to the scare system entropy resource. */
+    read_random_source( 0, 16, 0 );
+
+    allow_seed_file_update = 1;
+    return 1;
+}
+
+void
+update_random_seed_file()
+{
+    ulong *sp, *dp;
+    int fd, i;
+
+    if( !seed_file_name || !is_initialized || !pool_filled )
+       return;
+    if( !allow_seed_file_update ) {
+       log_info(_("note: random_seed file not updated\n"));
+       return;
+    }
+
+
+    /* copy the entropy pool to a scratch pool and mix both of them */
+    for(i=0,dp=(ulong*)keypool, sp=(ulong*)rndpool;
+                                   i < POOLWORDS; i++, dp++, sp++ ) {
+       *dp = *sp + ADD_VALUE;
+    }
+    mix_pool(rndpool); rndstats.mixrnd++;
+    mix_pool(keypool); rndstats.mixkey++;
+
+  #ifdef HAVE_DOSISH_SYSTEM
+    fd = open( seed_file_name, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY,
+                                                       S_IRUSR|S_IWUSR );
+  #else
+    fd = open( seed_file_name, O_WRONLY|O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR );
+  #endif
+    if( fd == -1 ) {
+       log_info(_("can't create `%s': %s\n"), seed_file_name, strerror(errno) );
+       return;
+    }
+    do {
+       i = write( fd, keypool, POOLSIZE );
+    } while( i == -1 && errno == EINTR );
+    if( i != POOLSIZE ) {
+       log_info(_("can't write `%s': %s\n"), seed_file_name, strerror(errno) );
+    }
+    if( close(fd) )
+       log_info(_("can't close `%s': %s\n"), seed_file_name, strerror(errno) );
+}
+
 
 static void
 read_pool( byte *buffer, size_t length, int level )
@@ -281,8 +424,31 @@ read_pool( byte *buffer, size_t length, int level )
     int i;
     ulong *sp, *dp;
 
-    if( length >= POOLSIZE )
-       BUG(); /* not allowed */
+    if( length >= POOLSIZE ) {
+       log_fatal(_("too many random bits requested; the limit is %d\n"),
+                 POOLSIZE*8-1 );
+    }
+
+    if( !pool_filled ) {
+       if( read_seed_file() )
+           pool_filled = 1;
+    }
+
+    /* For level 2 quality (key generation) we alwas make
+     * sure that the pool has been seeded enough initially */
+    if( level == 2 && !did_initial_extra_seeding ) {
+       size_t needed;
+
+       pool_balance = 0;
+       needed = length - pool_balance;
+       if( needed < POOLSIZE/2 )
+           needed = POOLSIZE/2;
+       else if( needed > POOLSIZE )
+           BUG();
+       read_random_source( 3, needed, 2 );
+       pool_balance += needed;
+       did_initial_extra_seeding=1;
+    }
 
     /* for level 2 make sure that there is enough random in the pool */
     if( level == 2 && pool_balance < length ) {
@@ -347,6 +513,12 @@ read_pool( byte *buffer, size_t length, int level )
 /****************
  * Add LENGTH bytes of randomness from buffer to the pool.
  * source may be used to specify the randomness source.
+ * Source is:
+ *     0 - used ony for initialization
+ *     1 - fast random poll function
+ *     2 - normal poll function
+ *     3 - used when level 2 random quality has been requested
+ *         to do an extra pool seed.
  */
 static void
 add_randomness( const void *buffer, size_t length, int source )
@@ -410,6 +582,13 @@ fast_random_poll()
        add_randomness( &tv.tv_sec, sizeof(tv.tv_sec), 1 );
        add_randomness( &tv.tv_usec, sizeof(tv.tv_usec), 1 );
     }
+  #elif HAVE_CLOCK_GETTIME
+    {  struct timespec tv;
+       if( clock_gettime( CLOCK_REALTIME, &tv ) == -1 )
+           BUG();
+       add_randomness( &tv.tv_sec, sizeof(tv.tv_sec), 1 );
+       add_randomness( &tv.tv_nsec, sizeof(tv.tv_nsec), 1 );
+    }
   #else /* use times */
     #ifndef HAVE_DOSISH_SYSTEM
     {  struct tms buf;
@@ -419,13 +598,28 @@ fast_random_poll()
     #endif
   #endif
   #ifdef HAVE_GETRUSAGE
+    #ifndef RUSAGE_SELF
+      #ifdef __GCC__
+       #warning There is no RUSAGE_SELF on this system
+      #endif
+    #else
     {  struct rusage buf;
        if( getrusage( RUSAGE_SELF, &buf ) )
            BUG();
        add_randomness( &buf, sizeof buf, 1 );
        memset( &buf, 0, sizeof buf );
     }
+    #endif
   #endif
+    /* time and clock are availabe on all systems - so
+     * we better do it just in case one of the above functions
+     * didn't work */
+    {  time_t x = time(NULL);
+       add_randomness( &x, sizeof(x), 1 );
+    }
+    {  clock_t x = clock();
+       add_randomness( &x, sizeof(x), 1 );
+    }
 }
 
 
@@ -472,9 +666,9 @@ gather_faked( void (*add)(const void*, size_t, int), int requester,
       #endif
        initialized=1;
       #ifdef HAVE_RAND
-       srand( time(NULL) * getpid());
+       srand(make_timestamp()*getpid());
       #else
-       srandom( time(NULL) * getpid());
+       srandom(make_timestamp()*getpid());
       #endif
     }
 
index 7b23008..fb9d6fa 100644 (file)
@@ -562,10 +562,10 @@ rmd160_get_info( int algo, size_t *contextsize,
     *r_asnoid = asn;
     *r_asnlen = DIM(asn);
     *r_mdlen = 20;
-    *r_init  = (void (*)(void *))rmd160_init;
-    *r_write = (void (*)(void *, byte*, size_t))rmd160_write;
-    *r_final = (void (*)(void *))rmd160_final;
-    *r_read  = (byte *(*)(void *))rmd160_read;
+    *(void  (**)(RMD160_CONTEXT *))r_init                = rmd160_init;
+    *(void  (**)(RMD160_CONTEXT *, byte*, size_t))r_write = rmd160_write;
+    *(void  (**)(RMD160_CONTEXT *))r_final               = rmd160_final;
+    *(byte *(**)(RMD160_CONTEXT *))r_read                = rmd160_read;
 
     return "RIPEMD160";
 }
index 4d5f0ef..f6870cd 100644 (file)
@@ -1,5 +1,5 @@
 /* rndegd.c  - interface to the EGD
- *     Copyright (C) 1999 Free Software Foundation, Inc.
+ *     Copyright (C) 1999, 2000 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
@@ -117,9 +117,13 @@ do_read( int fd, void *buf, size_t nbytes )
 
 
 
-/* Note: we always use the highest level.
+/****************
+ * Note: we always use the highest level.
  * TO boost the performance we may want to add some
  * additional code for level 1
+ *
+ * Using a level of 0 should never block and better add nothing
+ * to the pool.  So this is just a dummy for EGD.
  */
 static int
 gather_random( void (*add)(const void*, size_t, int), int requester,
@@ -133,7 +137,8 @@ gather_random( void (*add)(const void*, size_t, int), int requester,
 
     if( !length )
        return 0;
-
+    if( !level )
+       return 0;
 
   restart:
     if( do_restart ) {
index 4ab9f65..99a416e 100644 (file)
@@ -77,7 +77,7 @@
 #ifndef __QNX__
 #include <sys/resource.h>
 #endif                         /* __QNX__ */
-#ifdef _AIX
+#if defined( _AIX ) || defined( __QNX__ )
 #include <sys/select.h>
 #endif                         /* _AIX */
 #ifndef __QNX__
 #endif                         /* __hpux 9.x, after that it's in unistd.h */
 #include <sys/wait.h>
 /* #include <kitchensink.h> */
+#ifdef __QNX__
+#include <signal.h>
+#include <process.h>
+#endif               /* __QNX__ */
 #include <errno.h>
 
 #include "types.h"  /* for byte and u32 typedefs */
 #include "g10lib.h"
 
 #ifndef EAGAIN
-  #define EAGAIN  EWOULDBLOCK
+#define EAGAIN EWOULDBLOCK
+#endif
+#ifndef STDIN_FILENO
+#define STDIN_FILENO 0
+#endif
+#ifndef STDOUT_FILENO
+#define STDOUT_FILENO 1
 #endif
 
 #define GATHER_BUFSIZE         49152   /* Usually about 25K are filled */
@@ -306,6 +316,32 @@ typedef struct {
     char data[500];    /* gathered data */
 } GATHER_MSG;
 
+#ifndef HAVE_WAITPID
+pid_t
+waitpid(pid_t pid, int *statptr, int options)
+{
+     #ifdef HAVE_WAIT4
+       return wait4(pid, statptr, options, NULL);
+     #else
+       /* If wait4 is also not available, try wait3 for SVR3 variants */
+       /* Less ideal because can't actually request a specific pid */
+       /* For that reason, first check to see if pid is for an */
+       /*   existing process. */
+       int tmp_pid, dummystat;;
+       if (kill(pid, 0) == -1) {
+               errno = ECHILD;
+               return -1;
+       }
+       if (statptr == NULL)
+               statptr = &dummystat;
+       while (((tmp_pid = wait3(statptr, options, 0)) != pid) &&
+                   (tmp_pid != -1) && (tmp_pid != 0) && (pid != -1))
+           ;
+       return tmp_pid;
+     #endif
+}
+#endif
+
 /* Under SunOS popen() doesn't record the pid of the child process.  When
  * pclose() is called, instead of calling waitpid() for the correct child, it
  * calls wait() repeatedly until the right child is reaped.  The problem is
@@ -376,7 +412,9 @@ my_popen(struct RI *entry)
      * close on exec, so new children won't see it */
     close(pipedes[STDOUT_FILENO]);
 
+#ifdef FD_CLOEXEC
     fcntl(pipedes[STDIN_FILENO], F_SETFD, FD_CLOEXEC);
+#endif
 
     stream = fdopen(pipedes[STDIN_FILENO], "r");
 
@@ -616,6 +654,7 @@ start_gatherer( int pipefd )
     }
     /* close all files but the ones we need */
     {  int nmax, n1, n2, i;
+      #ifdef _SC_OPEN_MAX
        if( (nmax=sysconf( _SC_OPEN_MAX )) < 0 ) {
          #ifdef _POSIX_OPEN_MAX
            nmax = _POSIX_OPEN_MAX;
@@ -623,6 +662,9 @@ start_gatherer( int pipefd )
            nmax = 20; /* assume a reasonable value */
          #endif
        }
+      #else
+       nmax = 20; /* assume a reasonable value */
+      #endif
        n1 = fileno( stderr );
        n2 = dbgfp? fileno( dbgfp ) : -1;
        for(i=0; i < nmax; i++ ) {
@@ -718,6 +760,10 @@ read_a_msg( int fd, GATHER_MSG *msg )
 }
 
 
+/****************
+ * Using a level of 0 should never block and better add nothing
+ * to the pool.  So this is just a dummy for this gatherer.
+ */
 static int
 gather_random( void (*add)(const void*, size_t, int), int requester,
               size_t length, int level )
@@ -727,6 +773,9 @@ gather_random( void (*add)(const void*, size_t, int), int requester,
     GATHER_MSG msg;
     size_t n;
 
+    if( !level )
+       return 0;
+
     if( !gatherer_pid ) {
        /* make sure we are not setuid */
        if( getuid() != geteuid() )
index c104585..2583069 100644 (file)
@@ -1,5 +1,6 @@
-/* rndw32.c  - interface to the Winseed DLL
- *     Copyright (C) 1999 Free Software Foundation, Inc.
+/* rndw32.c  - W32 entropy gatherer
+ *     Copyright (C) 1999, 2000 Free Software Foundation, Inc.
+ *     Copyright Peter Gutmann, Matt Thomlinson and Blake Coverett 1996-1999
  *
  * This file is part of GnuPG.
  *
  * 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
+ *
+ *************************************************************************
+ * The code here is based on code from Cryptlib 3.0 beta by Peter Gutmann.
+ * Source file misc/rndwin32.c "Win32 Randomness-Gathering Code" with this
+ * copyright notice:
+ *
+ * This module is part of the cryptlib continuously seeded pseudorandom
+ * number generator.  For usage conditions, see lib_rand.c
+ *
+ * [Here is the notice from lib_rand.c, which is now called dev_sys.c]
+ *
+ * This module and the misc/rnd*.c modules represent the cryptlib
+ * continuously seeded pseudorandom number generator (CSPRNG) as described in
+ * my 1998 Usenix Security Symposium paper "The generation of random numbers
+ * for cryptographic purposes".
+ *
+ * The CSPRNG code is copyright Peter Gutmann (and various others) 1996,
+ * 1997, 1998, 1999, all rights reserved.  Redistribution of the CSPRNG
+ * modules and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice
+ *    and this permission notice in its entirety.
+ *
+ * 2. Redistributions in binary form must reproduce the copyright notice in
+ *    the documentation and/or other materials provided with the distribution.
+ *
+ * 3. A copy of any bugfixes or enhancements made must be provided to the
+ *    author, <pgut001@cs.auckland.ac.nz> to allow them to be added to the
+ *    baseline version of the code.
+ *
+ * ALTERNATIVELY, the code may be distributed under the terms of the GNU
+ * General Public License, version 2 or any later version published by the
+ * Free Software Foundation, in which case the provisions of the GNU GPL are
+ * required INSTEAD OF the above restrictions.
+ *
+ * Although not required under the terms of the GPL, it would still be nice if
+ * you could make any changes available to the author to allow a consistent
+ * code base to be maintained
+ *************************************************************************
  */
 
 #include <config.h>
 
 #include <windows.h>
 
+
 #include "types.h"
 #include "g10lib.h"
 #include "dynload.h"
 
+/* We do not use the netropy DLL anymore because a standalone program is
+ * easier to maintain and */
+/*#define USE_ENTROPY_DLL*/
+
+
 
 #ifdef IS_MODULE
   #define _(a) (a)
 #endif
 
 
+static int debug_me;
+
+#ifdef USE_ENTROPY_DLL
+
 #define WIN32_SLOW_SEEDER      0
 #define WIN32_FAST_SEEDER      1
 
 #define PCP_DLL_FUNC           8
 #define PCP_UNKNOWN_SEEDER_TYPE 9
 
+
+/****************
+ * We sometimes get a SEEDER_TOO_SMALL error, in which case we increment
+ * the internal buffer by SEEDER_INC_CHUNK until we reach MAX_SEEDER_SIZE
+ * MAX_SEEDER_SIZE is used as an arbitrary limit to protect against
+ * bugs in Winseed.
+ */
+#define MAX_SEEDER_SIZE  500000
+#define SEEDER_INC_CHUNK  50000
+
+
 typedef void *WIN32_SEEDER;
 
 static WIN32_SEEDER (WINAPI *create_instance)( byte type, unsigned int *reason);
@@ -68,8 +130,6 @@ static WIN32_SEEDER slow_seeder, fast_seeder;
 static byte *entropy_buffer;
 static size_t entropy_buffer_size;
 
-static char *entropy_dll;
-
 /****************
  * Load and initialize the winseed DLL
  * NOTE: winseed is not part of the GnuPG distribution.  It should be available
@@ -80,11 +140,17 @@ static char *entropy_dll;
 static void
 load_and_init_winseed( void )
 {
-    int hInstance;
+    HANDLE hInstance;
     void *addr;
     unsigned int reason = 0;
     unsigned int n1, n2;
-    const char *dllname = entropy_dll? entropy_dll : "c:/gnupg/entropy.dll";
+    const char *dllname;
+
+    dllname = read_w32_registry_string( "HKEY_LOCAL_MACHINE",
+                                       "Software\\GNU\\GnuPG",
+                                       "EntropyDLL" );
+    if( !dllname )
+       dllname = "c:/gnupg/entropy.dll";
 
     hInstance = LoadLibrary( dllname );
     if( !hInstance )
@@ -119,15 +185,14 @@ load_and_init_winseed( void )
        g10_log_fatal("error creating winseed fast seeder: rc=%u\n", reason );
        goto failure;
     }
-    g10_log_info("slow and fast seeders created.\n");
     n1 = get_internal_seed_size( slow_seeder );
-    g10_log_info("slow buffer size=%u\n", n1);
+    /*g10_log_info("slow buffer size=%u\n", n1);*/
     n2 = get_internal_seed_size( fast_seeder );
-    g10_log_info("fast buffer size=%u\n", n2);
+    /*g10_log_info("fast buffer size=%u\n", n2);*/
 
     entropy_buffer_size =  n1 > n2? n1: n2;
-    entropy_buffer = g10_xmalloc( entropy_buffer_size );
-    g10_log_info("using a buffer of size=%u\n", entropy_buffer_size );
+    entropy_buffer = m_alloc( entropy_buffer_size );
+    /*g10_log_info("using a buffer of size=%u\n", entropy_buffer_size );*/
 
     return;
 
@@ -150,13 +215,16 @@ gather_random( void (*add)(const void*, size_t, int), int requester,
     unsigned int result;
     unsigned int nbytes;
 
+    if( !level )
+       return 0;
+
     if( !slow_seeder )
        load_and_init_winseed();
 
     /* Our estimation on how much entropy we should use is very vague.
      * Winseed delivers some amount of entropy on each slow poll and
      * we add it to our random pool.  Depending on the required quality
-     * level we adjust the requested length so that for higer quality
+     * level we adjust the requested length so that for higher quality
      * we make sure to add more entropy to our pool.  However, as we don't
      * like to waste any entropy collected by winseed, we always add
      * at least everything we got from winseed.
@@ -169,17 +237,35 @@ gather_random( void (*add)(const void*, size_t, int), int requester,
     for(;;) {
        nbytes = entropy_buffer_size;
        result = get_seed( slow_seeder, entropy_buffer, &nbytes);
+       if( result == PCP_SEEDER_TOO_SMALL ) {
+           unsigned int n1 = get_internal_seed_size( slow_seeder );
+
+           if( n1 > MAX_SEEDER_SIZE ) {
+               g10_log_fatal("rndw32: internal seeder problem (size=%u)\n",
+                                                                         n1);
+               return -1; /* actually never reached */
+           }
+           n1 += SEEDER_INC_CHUNK;
+           set_internal_seed_size( slow_seeder, n1 );
+           if( n1 > entropy_buffer_size ) {
+               entropy_buffer_size =  n1;
+               entropy_buffer = m_realloc( entropy_buffer,
+                                           entropy_buffer_size );
+           }
+           continue;
+       }
+
+
        if( result ) {
            g10_log_fatal("rndw32: get_seed(slow) failed: rc=%u\n", result);
            return -1; /* actually never reached */
        }
-       g10_log_info("rndw32: slow poll level %d, need %u, got %u\n",
-                     level, (unsigned int)length, (unsigned int)nbytes );
+       /*g10_log_info("rndw32: slow poll level %d, need %u, got %u\n",
+                     level, (unsigned int)length, (unsigned int)nbytes );*/
        (*add)( entropy_buffer, nbytes, requester );
        if( length <= nbytes )
            return 0; /* okay */
        length -= nbytes;
-       g10_log_info("rndw32: need more\n");
     }
 }
 
@@ -206,6 +292,619 @@ gather_random_fast( void (*add)(const void*, size_t, int), int requester )
     return 0;
 }
 
+#else /* !USE_ENTROPY_DLL */
+/* This is the new code which does not require the entropy.dll */
+
+/*
+ * Definitions which are missing from the current GNU Windows32Api
+ */
+
+#define TH32CS_SNAPHEAPLIST 1
+#define TH32CS_SNAPPROCESS  2
+#define TH32CS_SNAPTHREAD   4
+#define TH32CS_SNAPMODULE   8
+#define TH32CS_SNAPALL     (1|2|4|8)
+#define TH32CS_INHERIT     0x80000000
+
+#define IOCTL_DISK_PERFORMANCE 0x00070020
+#define VER_PLATFORM_WIN32_WINDOWS 1
+
+
+typedef struct {
+    DWORD dwSize;
+    DWORD th32ProcessID;
+    DWORD th32HeapID;
+    DWORD dwFlags;
+} HEAPLIST32;
+
+typedef struct {
+    DWORD dwSize;
+    HANDLE hHandle;
+    DWORD dwAddress;
+    DWORD dwBlockSize;
+    DWORD dwFlags;
+    DWORD dwLockCount;
+    DWORD dwResvd;
+    DWORD th32ProcessID;
+    DWORD th32HeapID;
+} HEAPENTRY32;
+
+typedef struct {
+    DWORD dwSize;
+    DWORD cntUsage;
+    DWORD th32ProcessID;
+    DWORD th32DefaultHeapID;
+    DWORD th32ModuleID;
+    DWORD cntThreads;
+    DWORD th32ParentProcessID;
+    LONG  pcPriClassBase;
+    DWORD dwFlags;
+    char  szExeFile[260];
+} PROCESSENTRY32;
+
+typedef struct {
+    DWORD dwSize;
+    DWORD cntUsage;
+    DWORD th32ThreadID;
+    DWORD th32OwnerProcessID;
+    LONG  tpBasePri;
+    LONG  tpDeltaPri;
+    DWORD dwFlags;
+} THREADENTRY32;
+
+typedef struct {
+    DWORD dwSize;
+    DWORD th32ModuleID;
+    DWORD th32ProcessID;
+    DWORD GlblcntUsage;
+    DWORD ProccntUsage;
+    BYTE  *modBaseAddr;
+    DWORD modBaseSize;
+    HMODULE hModule;
+    char  szModule[256];
+    char  szExePath[260];
+} MODULEENTRY32;
+
+
+
+/* Type definitions for function pointers to call Toolhelp32 functions
+ * used with the windows95 gatherer */
+typedef BOOL (WINAPI * MODULEWALK) (HANDLE hSnapshot, MODULEENTRY32 *lpme);
+typedef BOOL (WINAPI * THREADWALK) (HANDLE hSnapshot, THREADENTRY32 *lpte);
+typedef BOOL (WINAPI * PROCESSWALK) (HANDLE hSnapshot, PROCESSENTRY32 *lppe);
+typedef BOOL (WINAPI * HEAPLISTWALK) (HANDLE hSnapshot, HEAPLIST32 *lphl);
+typedef BOOL (WINAPI * HEAPFIRST) (HEAPENTRY32 *lphe, DWORD th32ProcessID,
+                                  DWORD th32HeapID);
+typedef BOOL (WINAPI * HEAPNEXT) (HEAPENTRY32 *lphe);
+typedef HANDLE (WINAPI * CREATESNAPSHOT) (DWORD dwFlags, DWORD th32ProcessID);
+
+/* Type definitions for function pointers to call NetAPI32 functions */
+typedef DWORD (WINAPI * NETSTATISTICSGET) (LPWSTR szServer, LPWSTR szService,
+                                          DWORD dwLevel, DWORD dwOptions,
+                                          LPBYTE * lpBuffer);
+typedef DWORD (WINAPI * NETAPIBUFFERSIZE) (LPVOID lpBuffer, LPDWORD cbBuffer);
+typedef DWORD (WINAPI * NETAPIBUFFERFREE) (LPVOID lpBuffer);
+
+
+/* When we query the performance counters, we allocate an initial buffer and
+ * then reallocate it as required until RegQueryValueEx() stops returning
+ * ERROR_MORE_DATA.  The following values define the initial buffer size and
+ * step size by which the buffer is increased
+ */
+#define PERFORMANCE_BUFFER_SIZE        65536   /* Start at 64K */
+#define PERFORMANCE_BUFFER_STEP        16384   /* Step by 16K */
+
+
+static void
+slow_gatherer_windows95( void (*add)(const void*, size_t, int), int requester )
+{
+    static CREATESNAPSHOT pCreateToolhelp32Snapshot = NULL;
+    static MODULEWALK pModule32First = NULL;
+    static MODULEWALK pModule32Next = NULL;
+    static PROCESSWALK pProcess32First = NULL;
+    static PROCESSWALK pProcess32Next = NULL;
+    static THREADWALK pThread32First = NULL;
+    static THREADWALK pThread32Next = NULL;
+    static HEAPLISTWALK pHeap32ListFirst = NULL;
+    static HEAPLISTWALK pHeap32ListNext = NULL;
+    static HEAPFIRST pHeap32First = NULL;
+    static HEAPNEXT pHeap32Next = NULL;
+    HANDLE hSnapshot;
+
+
+    /* initialize the Toolhelp32 function pointers */
+    if ( !pCreateToolhelp32Snapshot ) {
+       HANDLE hKernel;
+
+       if ( debug_me )
+           log_debug ("rndw32#slow_gatherer_95: init toolkit\n" );
+
+       /* Obtain the module handle of the kernel to retrieve the addresses
+        * of the Toolhelp32 functions */
+       if ( ( !(hKernel = GetModuleHandle ("KERNEL32.DLL"))) ) {
+           g10_log_fatal ( "rndw32: can't get module handle\n" );
+       }
+
+       /* Now get pointers to the functions */
+       pCreateToolhelp32Snapshot = (CREATESNAPSHOT) GetProcAddress (hKernel,
+                                                 "CreateToolhelp32Snapshot");
+       pModule32First = (MODULEWALK) GetProcAddress (hKernel, "Module32First");
+       pModule32Next = (MODULEWALK) GetProcAddress (hKernel, "Module32Next");
+       pProcess32First = (PROCESSWALK) GetProcAddress (hKernel,
+                                                       "Process32First");
+       pProcess32Next = (PROCESSWALK) GetProcAddress (hKernel,
+                                                      "Process32Next");
+       pThread32First = (THREADWALK) GetProcAddress (hKernel, "Thread32First");
+       pThread32Next = (THREADWALK) GetProcAddress (hKernel, "Thread32Next");
+       pHeap32ListFirst = (HEAPLISTWALK) GetProcAddress (hKernel,
+                                                         "Heap32ListFirst");
+       pHeap32ListNext = (HEAPLISTWALK) GetProcAddress (hKernel,
+                                                        "Heap32ListNext");
+       pHeap32First = (HEAPFIRST) GetProcAddress (hKernel, "Heap32First");
+       pHeap32Next = (HEAPNEXT) GetProcAddress (hKernel, "Heap32Next");
+
+       if (    !pCreateToolhelp32Snapshot
+            || !pModule32First || !pModule32Next
+            || !pProcess32First || !pProcess32Next
+            || !pThread32First  || !pThread32Next
+            || !pHeap32ListFirst || !pHeap32ListNext
+            || !pHeap32First     || !pHeap32Next  ) {
+           g10_log_fatal ( "rndw32: failed to get a toolhep function\n" );
+       }
+    }
+
+    /* Take a snapshot of everything we can get to which is currently
+     * in the system */
+    if ( !(hSnapshot = pCreateToolhelp32Snapshot (TH32CS_SNAPALL, 0)) ) {
+       g10_log_fatal ( "rndw32: failed to take a toolhelp snapshot\n" );
+    }
+
+    /* Walk through the local heap */
+    {  HEAPLIST32 hl32;
+       hl32.dwSize = sizeof (HEAPLIST32);
+       if (pHeap32ListFirst (hSnapshot, &hl32)) {
+           if ( debug_me )
+               log_debug ("rndw32#slow_gatherer_95: walk heap\n" );
+           do {
+               HEAPENTRY32 he32;
+
+               /* First add the information from the basic Heaplist32 struct */
+               (*add) ( &hl32, sizeof (hl32), requester );
+
+               /* Now walk through the heap blocks getting information
+                * on each of them */
+               he32.dwSize = sizeof (HEAPENTRY32);
+               if (pHeap32First (&he32, hl32.th32ProcessID, hl32.th32HeapID)){
+                   do {
+                       (*add) ( &he32, sizeof (he32), requester );
+                   } while (pHeap32Next (&he32));
+               }
+           } while (pHeap32ListNext (hSnapshot, &hl32));
+       }
+    }
+
+
+    /* Walk through all processes */
+    {  PROCESSENTRY32 pe32;
+       pe32.dwSize = sizeof (PROCESSENTRY32);
+       if (pProcess32First (hSnapshot, &pe32)) {
+           if ( debug_me )
+               log_debug ("rndw32#slow_gatherer_95: walk processes\n" );
+           do {
+               (*add) ( &pe32, sizeof (pe32), requester );
+           } while (pProcess32Next (hSnapshot, &pe32));
+       }
+    }
+
+    /* Walk through all threads */
+    {  THREADENTRY32 te32;
+       te32.dwSize = sizeof (THREADENTRY32);
+       if (pThread32First (hSnapshot, &te32)) {
+           if ( debug_me )
+               log_debug ("rndw32#slow_gatherer_95: walk threads\n" );
+           do {
+               (*add) ( &te32, sizeof (te32), requester );
+           } while (pThread32Next (hSnapshot, &te32));
+       }
+    }
+
+    /* Walk through all modules associated with the process */
+    {  MODULEENTRY32 me32;
+       me32.dwSize = sizeof (MODULEENTRY32);
+       if (pModule32First (hSnapshot, &me32)) {
+           if ( debug_me )
+               log_debug ("rndw32#slow_gatherer_95: walk modules\n" );
+           do {
+               (*add) ( &me32, sizeof (me32), requester );
+           } while (pModule32Next (hSnapshot, &me32));
+       }
+    }
+
+    CloseHandle (hSnapshot);
+}
+
+
+
+static void
+slow_gatherer_windowsNT( void (*add)(const void*, size_t, int), int requester )
+{
+    static int is_initialized = 0;
+    static NETSTATISTICSGET pNetStatisticsGet = NULL;
+    static NETAPIBUFFERSIZE pNetApiBufferSize = NULL;
+    static NETAPIBUFFERFREE pNetApiBufferFree = NULL;
+    static int is_workstation = 1;
+
+    static int cbPerfData = PERFORMANCE_BUFFER_SIZE;
+    PERF_DATA_BLOCK *pPerfData;
+    HANDLE hDevice, hNetAPI32 = NULL;
+    DWORD dwSize, status;
+    int nDrive;
+
+    if ( !is_initialized ) {
+       HKEY hKey;
+
+       if ( debug_me )
+           log_debug ("rndw32#slow_gatherer_nt: init toolkit\n" );
+       /* Find out whether this is an NT server or workstation if necessary */
+       if (RegOpenKeyEx (HKEY_LOCAL_MACHINE,
+                         "SYSTEM\\CurrentControlSet\\Control\\ProductOptions",
+                         0, KEY_READ, &hKey) == ERROR_SUCCESS) {
+           BYTE szValue[32];
+           dwSize = sizeof (szValue);
+
+           if ( debug_me )
+               log_debug ("rndw32#slow_gatherer_nt: check product options\n" );
+           status = RegQueryValueEx (hKey, "ProductType", 0, NULL,
+                                     szValue, &dwSize);
+           if (status == ERROR_SUCCESS && stricmp (szValue, "WinNT")) {
+               /* Note: There are (at least) three cases for ProductType:
+                * WinNT = NT Workstation, ServerNT = NT Server, LanmanNT =
+                * NT Server acting as a Domain Controller */
+               is_workstation = 0;
+               if ( debug_me )
+                   log_debug ("rndw32: this is a NT server\n");
+           }
+           RegCloseKey (hKey);
+       }
+
+       /* Initialize the NetAPI32 function pointers if necessary */
+       if ( (hNetAPI32 = LoadLibrary ("NETAPI32.DLL")) ) {
+           if ( debug_me )
+               log_debug ("rndw32#slow_gatherer_nt: netapi32 loaded\n" );
+           pNetStatisticsGet = (NETSTATISTICSGET) GetProcAddress (hNetAPI32,
+                                                      "NetStatisticsGet");
+           pNetApiBufferSize = (NETAPIBUFFERSIZE) GetProcAddress (hNetAPI32,
+                                                      "NetApiBufferSize");
+           pNetApiBufferFree = (NETAPIBUFFERFREE) GetProcAddress (hNetAPI32,
+                                                      "NetApiBufferFree");
+
+           if ( !pNetStatisticsGet
+                || !pNetApiBufferSize || !pNetApiBufferFree ) {
+               FreeLibrary (hNetAPI32);
+               hNetAPI32 = NULL;
+               g10_log_debug ("rndw32: No NETAPI found\n" );
+           }
+       }
+
+       is_initialized = 1;
+    }
+
+    /* Get network statistics. Note: Both NT Workstation and NT Server by
+     * default will be running both the workstation and server services.  The
+     * heuristic below is probably useful though on the assumption that the
+     * majority of the network traffic will be via the appropriate service.
+     * In any case the network statistics return almost no randomness */
+    {  LPBYTE lpBuffer;
+       if (hNetAPI32 && !pNetStatisticsGet (NULL,
+                          is_workstation ? L"LanmanWorkstation" :
+                          L"LanmanServer", 0, 0, &lpBuffer) ) {
+           if ( debug_me )
+               log_debug ("rndw32#slow_gatherer_nt: get netstats\n" );
+           pNetApiBufferSize (lpBuffer, &dwSize);
+           (*add) ( lpBuffer, dwSize,requester );
+           pNetApiBufferFree (lpBuffer);
+       }
+    }
+
+    /* Get disk I/O statistics for all the hard drives */
+    for (nDrive = 0;; nDrive++) {
+       DISK_PERFORMANCE diskPerformance;
+       char szDevice[50];
+
+       /* Check whether we can access this device */
+       sprintf (szDevice, "\\\\.\\PhysicalDrive%d", nDrive);
+       hDevice = CreateFile (szDevice, 0, FILE_SHARE_READ | FILE_SHARE_WRITE,
+                             NULL, OPEN_EXISTING, 0, NULL);
+       if (hDevice == INVALID_HANDLE_VALUE)
+           break;
+
+       /* Note: This only works if you have turned on the disk performance
+        * counters with 'diskperf -y'.  These counters are off by default */
+       if (DeviceIoControl (hDevice, IOCTL_DISK_PERFORMANCE, NULL, 0,
+                            &diskPerformance, sizeof (DISK_PERFORMANCE),
+                            &dwSize, NULL))
+       {
+           if ( debug_me )
+               log_debug ("rndw32#slow_gatherer_nt: iostats drive %d\n",
+                                                                 nDrive );
+           (*add) ( &diskPerformance, dwSize, requester );
+       }
+       else {
+           log_info ("NOTE: you should run 'diskperf -y' "
+                     "to enable the disk statistics\n");
+       }
+       CloseHandle (hDevice);
+    }
+
+  #if 0 /* we don't need this in GnuPG  */
+    /* Wait for any async keyset driver binding to complete.  You may be
+     * wondering what this call is doing here... the reason it's necessary is
+     * because RegQueryValueEx() will hang indefinitely if the async driver
+     * bind is in progress.  The problem occurs in the dynamic loading and
+     * linking of driver DLL's, which work as follows:
+     *
+     * hDriver = LoadLibrary( DRIVERNAME );
+     * pFunction1 = ( TYPE_FUNC1 ) GetProcAddress( hDriver, NAME_FUNC1 );
+     * pFunction2 = ( TYPE_FUNC1 ) GetProcAddress( hDriver, NAME_FUNC2 );
+     *
+     * If RegQueryValueEx() is called while the GetProcAddress()'s are in
+     * progress, it will hang indefinitely.  This is probably due to some
+     * synchronisation problem in the NT kernel where the GetProcAddress()
+     * calls affect something like a module reference count or function
+     * reference count while RegQueryValueEx() is trying to take a snapshot
+     * of the statistics, which include the reference counts.  Because of
+     * this, we have to wait until any async driver bind has completed
+     * before we can call RegQueryValueEx() */
+    waitSemaphore (SEMAPHORE_DRIVERBIND);
+  #endif
+
+    /* Get information from the system performance counters.  This can take
+     * a few seconds to do.  In some environments the call to
+     * RegQueryValueEx() can produce an access violation at some random time
+     * in the future, adding a short delay after the following code block
+     * makes the problem go away.  This problem is extremely difficult to
+     * reproduce, I haven't been able to get it to occur despite running it
+     * on a number of machines.  The best explanation for the problem is that
+     * on the machine where it did occur, it was caused by an external driver
+     * or other program which adds its own values under the
+     * HKEY_PERFORMANCE_DATA key.  The NT kernel calls the required external
+     * modules to map in the data, if there's a synchronisation problem the
+     * external module would write its data at an inappropriate moment,
+     * causing the access violation.  A low-level memory checker indicated
+     * that ExpandEnvironmentStrings() in KERNEL32.DLL, called an
+     * interminable number of calls down inside RegQueryValueEx(), was
+     * overwriting memory (it wrote twice the allocated size of a buffer to a
+     * buffer allocated by the NT kernel).  This may be what's causing the
+     * problem, but since it's in the kernel there isn't much which can be
+     * done.
+     *
+     * In addition to these problems the code in RegQueryValueEx() which
+     * estimates the amount of memory required to return the performance
+     * counter information isn't very accurate, since it always returns a
+     * worst-case estimate which is usually nowhere near the actual amount
+     * required.  For example it may report that 128K of memory is required,
+     * but only return 64K of data */
+    {  pPerfData =  m_alloc (cbPerfData);
+       for (;;) {
+           dwSize = cbPerfData;
+           if ( debug_me )
+               log_debug ("rndw32#slow_gatherer_nt: get perf data\n" );
+           status = RegQueryValueEx (HKEY_PERFORMANCE_DATA, "Global", NULL,
+                                     NULL, (LPBYTE) pPerfData, &dwSize);
+           if (status == ERROR_SUCCESS) {
+               if (!memcmp (pPerfData->Signature, L"PERF", 8)) {
+                   (*add) ( pPerfData, dwSize, requester );
+               }
+               else
+                   g10_log_debug ( "rndw32: no PERF signature\n");
+               break;
+           }
+           else if (status == ERROR_MORE_DATA) {
+               cbPerfData += PERFORMANCE_BUFFER_STEP;
+               pPerfData = m_realloc (pPerfData, cbPerfData);
+           }
+           else {
+               g10_log_debug ( "rndw32: get performance data problem\n");
+               break;
+           }
+       }
+       m_free (pPerfData);
+    }
+    /* Although this isn't documented in the Win32 API docs, it's necessary
+       to explicitly close the HKEY_PERFORMANCE_DATA key after use (it's
+       implicitly opened on the first call to RegQueryValueEx()).  If this
+       isn't done then any system components which provide performance data
+       can't be removed or changed while the handle remains active */
+    RegCloseKey (HKEY_PERFORMANCE_DATA);
+}
+
+
+static int
+gather_random( void (*add)(const void*, size_t, int), int requester,
+                                         size_t length, int level )
+{
+    static int is_initialized;
+    static int is_windows95;
+
+
+    if( !level )
+       return 0;
+    /* We don't differentiate between level 1 and 2 here because
+     * there is no nternal entropy pool as a scary resource.  It may
+     * all work slower, but because our entropy source will never
+     * block but deliver some not easy to measure entropy, we assume level 2
+     */
+
+
+    if ( !is_initialized ) {
+       OSVERSIONINFO osvi = { sizeof( osvi ) };
+       DWORD platform;
+
+       GetVersionEx( &osvi );
+       platform = osvi.dwPlatformId;
+       is_windows95 = platform == VER_PLATFORM_WIN32_WINDOWS;
+
+       if ( platform == VER_PLATFORM_WIN32s ) {
+           g10_log_fatal("can't run on a W32s platform\n" );
+       }
+       is_initialized = 1;
+       if ( debug_me )
+           log_debug ("rndw32#gather_random: platform=%d\n", (int)platform );
+    }
+
+
+    if ( debug_me )
+       log_debug ("rndw32#gather_random: req=%d len=%u lvl=%d\n",
+                          requester, (unsigned int)length, level );
+
+    if (is_windows95 ) {
+       slow_gatherer_windows95( add, requester );
+    }
+    else {
+       slow_gatherer_windowsNT( add, requester );
+    }
+
+    return 0;
+}
+
+
+
+static int
+gather_random_fast( void (*add)(const void*, size_t, int), int requester )
+{
+    static int addedFixedItems = 0;
+
+    if ( debug_me )
+       log_debug ("rndw32#gather_random_fast: req=%d\n", requester );
+
+    /* Get various basic pieces of system information: Handle of active
+     * window, handle of window with mouse capture, handle of clipboard owner
+     * handle of start of clpboard viewer list, pseudohandle of current
+     * process, current process ID, pseudohandle of current thread, current
+     * thread ID, handle of desktop window, handle  of window with keyboard
+     * focus, whether system queue has any events, cursor position for last
+     * message, 1 ms time for last message, handle of window with clipboard
+     * open, handle of process heap, handle of procs window station, types of
+     * events in input queue, and milliseconds since Windows was started */
+    {  byte buffer[20*sizeof(ulong)], *bufptr;
+       bufptr = buffer;
+      #define ADD(f)  do { ulong along = (ulong)(f);                 \
+                          memcpy (bufptr, &along, sizeof (along) );  \
+                          bufptr += sizeof (along); } while (0)
+       ADD ( GetActiveWindow ());
+       ADD ( GetCapture ());
+       ADD ( GetClipboardOwner ());
+       ADD ( GetClipboardViewer ());
+       ADD ( GetCurrentProcess ());
+       ADD ( GetCurrentProcessId ());
+       ADD ( GetCurrentThread ());
+       ADD ( GetCurrentThreadId ());
+       ADD ( GetDesktopWindow ());
+       ADD ( GetFocus ());
+       ADD ( GetInputState ());
+       ADD ( GetMessagePos ());
+       ADD ( GetMessageTime ());
+       ADD ( GetOpenClipboardWindow ());
+       ADD ( GetProcessHeap ());
+       ADD ( GetProcessWindowStation ());
+       ADD ( GetQueueStatus (QS_ALLEVENTS));
+       ADD ( GetTickCount ());
+
+       assert ( bufptr-buffer < sizeof (buffer) );
+       (*add) ( buffer, bufptr-buffer, requester );
+      #undef ADD
+    }
+
+    /* Get multiword system information: Current caret position, current
+     * mouse cursor position */
+    {  POINT point;
+       GetCaretPos (&point);
+       (*add) ( &point, sizeof (point), requester );
+       GetCursorPos (&point);
+       (*add) ( &point, sizeof (point), requester );
+    }
+
+    /* Get percent of memory in use, bytes of physical memory, bytes of free
+     * physical memory, bytes in paging file, free bytes in paging file, user
+     * bytes of address space, and free user bytes */
+    {  MEMORYSTATUS memoryStatus;
+       memoryStatus.dwLength = sizeof (MEMORYSTATUS);
+       GlobalMemoryStatus (&memoryStatus);
+       (*add) ( &memoryStatus, sizeof (memoryStatus), requester );
+    }
+
+    /* Get thread and process creation time, exit time, time in kernel mode,
+       and time in user mode in 100ns intervals */
+    {  HANDLE handle;
+       FILETIME creationTime, exitTime, kernelTime, userTime;
+       DWORD minimumWorkingSetSize, maximumWorkingSetSize;
+
+       handle = GetCurrentThread ();
+       GetThreadTimes (handle, &creationTime, &exitTime,
+                                              &kernelTime, &userTime);
+       (*add) ( &creationTime, sizeof (creationTime), requester );
+       (*add) ( &exitTime, sizeof (exitTime), requester );
+       (*add) ( &kernelTime, sizeof (kernelTime), requester );
+       (*add) ( &userTime, sizeof (userTime), requester );
+
+       handle = GetCurrentProcess ();
+       GetProcessTimes (handle, &creationTime, &exitTime,
+                                               &kernelTime, &userTime);
+       (*add) ( &creationTime, sizeof (creationTime), requester );
+       (*add) ( &exitTime, sizeof (exitTime), requester );
+       (*add) ( &kernelTime, sizeof (kernelTime), requester );
+       (*add) ( &userTime, sizeof (userTime), requester );
+
+       /* Get the minimum and maximum working set size for the current process */
+       GetProcessWorkingSetSize (handle, &minimumWorkingSetSize,
+                                         &maximumWorkingSetSize);
+       (*add) ( &minimumWorkingSetSize,
+                                  sizeof (&minimumWorkingSetSize), requester );
+       (*add) ( &maximumWorkingSetSize,
+                                  sizeof (&maximumWorkingSetSize), requester );
+    }
+
+
+    /* The following are fixed for the lifetime of the process so we only
+     * add them once */
+    if (!addedFixedItems) {
+       STARTUPINFO startupInfo;
+
+       /* Get name of desktop, console window title, new window position and
+        * size, window flags, and handles for stdin, stdout, and stderr */
+       startupInfo.cb = sizeof (STARTUPINFO);
+       GetStartupInfo (&startupInfo);
+       (*add) ( &startupInfo, sizeof (STARTUPINFO), requester );
+       addedFixedItems = 1;
+    }
+
+    /* The performance of QPC varies depending on the architecture it's
+     * running on and on the OS.  Under NT it reads the CPU's 64-bit timestamp
+     * counter (at least on a Pentium and newer '486's, it hasn't been tested
+     * on anything without a TSC), under Win95 it reads the 1.193180 MHz PIC
+     * timer.  There are vague mumblings in the docs that it may fail if the
+     * appropriate hardware isn't available (possibly '386's or MIPS machines
+     * running NT), but who's going to run NT on a '386? */
+    {  LARGE_INTEGER performanceCount;
+       if (QueryPerformanceCounter (&performanceCount)) {
+           if ( debug_me )
+               log_debug ("rndw32#gather_random_fast: perf data\n");
+           (*add) (&performanceCount, sizeof (&performanceCount), requester);
+       }
+       else { /* Millisecond accuracy at best... */
+           DWORD aword = GetTickCount ();
+           (*add) (&aword, sizeof (aword), requester );
+       }
+    }
+
+    return 0;
+}
+
+
+
+
+
+#endif /* !USE_ENTROPY_DLL */
 
 
 #ifndef IS_MODULE
@@ -232,6 +931,8 @@ gnupgext_enum_func( int what, int *sequence, int *class, int *vers )
     void *ret;
     int i = *sequence;
 
+    debug_me = !!getenv("DEBUG_RNDW32");
+
     do {
        if ( i >= DIM(func_table) || i < 0 ) {
            return NULL;
@@ -246,14 +947,6 @@ gnupgext_enum_func( int what, int *sequence, int *class, int *vers )
     return ret;
 }
 
-#ifdef USE_STATIC_RNDW32
-void
-rndw32_set_dll_name( const char *name )
-{
-    entropy_dll = m_strdup( name );
-}
-#endif
-
 #ifndef IS_MODULE
 void
 rndw32_constructor(void)
diff --git a/cipher/rsa.c b/cipher/rsa.c
new file mode 100644 (file)
index 0000000..5d852cd
--- /dev/null
@@ -0,0 +1,375 @@
+/* rsa.c  -  RSA function
+ *     Copyright (C) 1997, 1998, 1999 by Werner Koch (dd9jn)
+ *     Copyright (C) 2000 Free Software Foundation, Inc.
+ ***********************************************************************
+ * ATTENTION: This code should not be used in the United States
+ * before the U.S. Patent #4,405,829 expires on September 20, 2000!
+ ***********************************************************************
+ *
+ * This file is part of GnuPG.
+ *
+ * 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,
+ * 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
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "util.h"
+#include "mpi.h"
+#include "cipher.h"
+#include "rsa.h"
+
+
+typedef struct {
+    MPI n;         /* modulus */
+    MPI e;         /* exponent */
+} RSA_public_key;
+
+
+typedef struct {
+    MPI n;         /* public modulus */
+    MPI e;         /* public exponent */
+    MPI d;         /* exponent */
+    MPI p;         /* prime  p. */
+    MPI q;         /* prime  q. */
+    MPI u;         /* inverse of p mod q. */
+} RSA_secret_key;
+
+
+static void test_keys( RSA_secret_key *sk, unsigned nbits );
+static void generate( RSA_secret_key *sk, unsigned nbits );
+static int  check_secret_key( RSA_secret_key *sk );
+static void public(MPI output, MPI input, RSA_public_key *skey );
+static void secret(MPI output, MPI input, RSA_secret_key *skey );
+
+
+static void
+test_keys( RSA_secret_key *sk, unsigned nbits )
+{
+    RSA_public_key pk;
+    MPI test = mpi_alloc( (nbits+BITS_PER_MPI_LIMB-1)/BITS_PER_MPI_LIMB );
+    MPI out1 = mpi_alloc( (nbits+BITS_PER_MPI_LIMB-1)/BITS_PER_MPI_LIMB );
+    MPI out2 = mpi_alloc( (nbits+BITS_PER_MPI_LIMB-1)/BITS_PER_MPI_LIMB );
+
+    pk.n = sk->n;
+    pk.e = sk->e;
+    {  char *p = get_random_bits( nbits, 0, 0 );
+       mpi_set_buffer( test, p, (nbits+7)/8, 0 );
+       m_free(p);
+    }
+
+    public( out1, test, &pk );
+    secret( out2, out1, sk );
+    if( mpi_cmp( test, out2 ) )
+       log_fatal("RSA operation: public, secret failed\n");
+    secret( out1, test, sk );
+    public( out2, out1, &pk );
+    if( mpi_cmp( test, out2 ) )
+       log_fatal("RSA operation: secret, public failed\n");
+    mpi_free( test );
+    mpi_free( out1 );
+    mpi_free( out2 );
+}
+
+/****************
+ * Generate a key pair with a key of size NBITS
+ * Returns: 2 structures filles with all needed values
+ */
+static void
+generate( RSA_secret_key *sk, unsigned nbits )
+{
+    MPI p, q; /* the two primes */
+    MPI d;    /* the private key */
+    MPI u;
+    MPI t1, t2;
+    MPI n;    /* the public key */
+    MPI e;    /* the exponent */
+    MPI phi;  /* helper: (p-a)(q-1) */
+    MPI g;
+    MPI f;
+
+    /* select two (very secret) primes */
+    p = generate_secret_prime( nbits / 2 );
+    q = generate_secret_prime( nbits / 2 );
+    if( mpi_cmp( p, q ) > 0 ) /* p shall be smaller than q (for calc of u)*/
+       mpi_swap(p,q);
+    /* calculate Euler totient: phi = (p-1)(q-1) */
+    t1 = mpi_alloc_secure( mpi_get_nlimbs(p) );
+    t2 = mpi_alloc_secure( mpi_get_nlimbs(p) );
+    phi = mpi_alloc_secure( (nbits+BITS_PER_MPI_LIMB-1)/BITS_PER_MPI_LIMB );
+    g  = mpi_alloc_secure( (nbits+BITS_PER_MPI_LIMB-1)/BITS_PER_MPI_LIMB  );
+    f  = mpi_alloc_secure( (nbits+BITS_PER_MPI_LIMB-1)/BITS_PER_MPI_LIMB  );
+    mpi_sub_ui( t1, p, 1 );
+    mpi_sub_ui( t2, q, 1 );
+    mpi_mul( phi, t1, t2 );
+    mpi_gcd(g, t1, t2);
+    mpi_fdiv_q(f, phi, g);
+    /* multiply them to make the private key */
+    n = mpi_alloc( (nbits+BITS_PER_MPI_LIMB-1)/BITS_PER_MPI_LIMB );
+    mpi_mul( n, p, q );
+    /* find a public exponent  */
+    e = mpi_alloc( (6+BITS_PER_MPI_LIMB-1)/BITS_PER_MPI_LIMB );
+    mpi_set_ui( e, 17); /* start with 17 */
+    while( !mpi_gcd(t1, e, phi) ) /* (while gcd is not 1) */
+       mpi_add_ui( e, e, 2);
+    /* calculate the secret key d = e^1 mod phi */
+    d = mpi_alloc( (nbits+BITS_PER_MPI_LIMB-1)/BITS_PER_MPI_LIMB );
+    mpi_invm(d, e, f );
+    /* calculate the inverse of p and q (used for chinese remainder theorem)*/
+    u = mpi_alloc( (nbits+BITS_PER_MPI_LIMB-1)/BITS_PER_MPI_LIMB );
+    mpi_invm(u, p, q );
+
+    if( DBG_CIPHER ) {
+       log_mpidump("  p= ", p );
+       log_mpidump("  q= ", q );
+       log_mpidump("phi= ", phi );
+       log_mpidump("  g= ", g );
+       log_mpidump("  f= ", f );
+       log_mpidump("  n= ", n );
+       log_mpidump("  e= ", e );
+       log_mpidump("  d= ", d );
+       log_mpidump("  u= ", u );
+    }
+
+    mpi_free(t1);
+    mpi_free(t2);
+    mpi_free(phi);
+    mpi_free(f);
+    mpi_free(g);
+
+    sk->n = n;
+    sk->e = e;
+    sk->p = p;
+    sk->q = q;
+    sk->d = d;
+    sk->u = u;
+
+    /* now we can test our keys (this should never fail!) */
+    test_keys( sk, nbits - 64 );
+}
+
+
+/****************
+ * Test wether the secret key is valid.
+ * Returns: true if this is a valid key.
+ */
+static int
+check_secret_key( RSA_secret_key *sk )
+{
+    int rc;
+    MPI temp = mpi_alloc( mpi_get_nlimbs(sk->p)*2 );
+
+    mpi_mul(temp, sk->p, sk->q );
+    rc = mpi_cmp( temp, sk->n );
+    mpi_free(temp);
+    return !rc;
+}
+
+
+
+/****************
+ * Public key operation. Encrypt INPUT with PKEY and put result into OUTPUT.
+ *
+ *     c = m^e mod n
+ *
+ * Where c is OUTPUT, m is INPUT and e,n are elements of PKEY.
+ */
+static void
+public(MPI output, MPI input, RSA_public_key *pkey )
+{
+    if( output == input ) { /* powm doesn't like output and input the same */
+       MPI x = mpi_alloc( mpi_get_nlimbs(input)*2 );
+       mpi_powm( x, input, pkey->e, pkey->n );
+       mpi_set(output, x);
+       mpi_free(x);
+    }
+    else
+       mpi_powm( output, input, pkey->e, pkey->n );
+}
+
+/****************
+ * Secret key operation. Encrypt INPUT with SKEY and put result into OUTPUT.
+ *
+ *     m = c^d mod n
+ *
+ * Where m is OUTPUT, c is INPUT and d,n are elements of PKEY.
+ *
+ * FIXME: We should better use the Chinese Remainder Theorem
+ */
+static void
+secret(MPI output, MPI input, RSA_secret_key *skey )
+{
+    mpi_powm( output, input, skey->d, skey->n );
+}
+
+
+/*********************************************
+ **************  interface  ******************
+ *********************************************/
+
+int
+rsa_generate( int algo, unsigned nbits, MPI *skey, MPI **retfactors )
+{
+    RSA_secret_key sk;
+
+    if( !is_RSA(algo) )
+       return G10ERR_PUBKEY_ALGO;
+
+    generate( &sk, nbits );
+    skey[0] = sk.n;
+    skey[1] = sk.e;
+    skey[2] = sk.d;
+    skey[3] = sk.p;
+    skey[4] = sk.q;
+    skey[5] = sk.u;
+    /* make an empty list of factors */
+    *retfactors = m_alloc_clear( 1 * sizeof **retfactors );
+    return 0;
+}
+
+
+int
+rsa_check_secret_key( int algo, MPI *skey )
+{
+    RSA_secret_key sk;
+
+    if( !is_RSA(algo) )
+       return G10ERR_PUBKEY_ALGO;
+
+    sk.n = skey[0];
+    sk.e = skey[1];
+    sk.d = skey[2];
+    sk.p = skey[3];
+    sk.q = skey[4];
+    sk.u = skey[5];
+    if( !check_secret_key( &sk ) )
+       return G10ERR_BAD_SECKEY;
+
+    return 0;
+}
+
+
+
+int
+rsa_encrypt( int algo, MPI *resarr, MPI data, MPI *pkey )
+{
+    RSA_public_key pk;
+
+    if( algo != 1 && algo != 2 )
+       return G10ERR_PUBKEY_ALGO;
+
+    pk.n = pkey[0];
+    pk.e = pkey[1];
+    resarr[0] = mpi_alloc( mpi_get_nlimbs( pk.n ) );
+    public( resarr[0], data, &pk );
+    return 0;
+}
+
+int
+rsa_decrypt( int algo, MPI *result, MPI *data, MPI *skey )
+{
+    RSA_secret_key sk;
+
+    if( algo != 1 && algo != 2 )
+       return G10ERR_PUBKEY_ALGO;
+
+    sk.n = skey[0];
+    sk.e = skey[1];
+    sk.d = skey[2];
+    sk.p = skey[3];
+    sk.q = skey[4];
+    sk.u = skey[5];
+    *result = mpi_alloc_secure( mpi_get_nlimbs( sk.n ) );
+    secret( *result, data[0], &sk );
+    return 0;
+}
+
+int
+rsa_sign( int algo, MPI *resarr, MPI data, MPI *skey )
+{
+    RSA_secret_key sk;
+
+    if( algo != 1 && algo != 3 )
+       return G10ERR_PUBKEY_ALGO;
+
+    sk.n = skey[0];
+    sk.e = skey[1];
+    sk.d = skey[2];
+    sk.p = skey[3];
+    sk.q = skey[4];
+    sk.u = skey[5];
+    resarr[0] = mpi_alloc( mpi_get_nlimbs( sk.n ) );
+    secret( resarr[0], data, &sk );
+
+    return 0;
+}
+
+int
+rsa_verify( int algo, MPI hash, MPI *data, MPI *pkey,
+          int (*cmp)(void *opaque, MPI tmp), void *opaquev )
+{
+    RSA_public_key pk;
+    MPI result;
+    int rc;
+
+    if( algo != 1 && algo != 3 )
+       return G10ERR_PUBKEY_ALGO;
+    pk.n = pkey[0];
+    pk.e = pkey[1];
+    result = mpi_alloc( (160+BITS_PER_MPI_LIMB-1)/BITS_PER_MPI_LIMB);
+    public( result, data[0], &pk );
+    /*rc = (*cmp)( opaquev, result );*/
+    rc = mpi_cmp( result, hash )? G10ERR_BAD_SIGN:0;
+    mpi_free(result);
+
+    return rc;
+}
+
+
+unsigned int
+rsa_get_nbits( int algo, MPI *pkey )
+{
+    if( !is_RSA(algo) )
+       return 0;
+    return mpi_get_nbits( pkey[0] );
+}
+
+
+/****************
+ * Return some information about the algorithm.  We need algo here to
+ * distinguish different flavors of the algorithm.
+ * Returns: A pointer to string describing the algorithm or NULL if
+ *         the ALGO is invalid.
+ * Usage: Bit 0 set : allows signing
+ *           1 set : allows encryption
+ */
+const char *
+rsa_get_info( int algo,
+             int *npkey, int *nskey, int *nenc, int *nsig, int *usage )
+{
+    *npkey = 2;
+    *nskey = 6;
+    *nenc = 1;
+    *nsig = 1;
+
+    switch( algo ) {
+      case 1: *usage = PUBKEY_USAGE_SIG | PUBKEY_USAGE_ENC; return "RSA";
+      case 2: *usage = PUBKEY_USAGE_ENC; return "RSA-E";
+      case 3: *usage = PUBKEY_USAGE_SIG; return "RSA-S";
+      default:*usage = 0; return NULL;
+    }
+}
+
diff --git a/cipher/rsa.h b/cipher/rsa.h
new file mode 100644 (file)
index 0000000..8b60ecb
--- /dev/null
@@ -0,0 +1,36 @@
+/* rsa.h
+ *     Copyright (C) 1997,1998 by Werner Koch (dd9jn)
+ *     Copyright (C) 2000 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * 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,
+ * 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
+ */
+#ifndef G10_RSA_H
+#define G10_RSA_H
+
+int rsa_generate( int algo, unsigned nbits, MPI *skey, MPI **retfactors );
+int rsa_check_secret_key( int algo, MPI *skey );
+int rsa_encrypt( int algo, MPI *resarr, MPI data, MPI *pkey );
+int rsa_decrypt( int algo, MPI *result, MPI *data, MPI *skey );
+int rsa_sign( int algo, MPI *resarr, MPI data, MPI *skey );
+int rsa_verify( int algo, MPI hash, MPI *data, MPI *pkey,
+                   int (*cmp)(void *, MPI), void *opaquev );
+unsigned rsa_get_nbits( int algo, MPI *pkey );
+const char *rsa_get_info( int algo, int *npkey, int *nskey,
+                                   int *nenc, int *nsig, int *use );
+
+
+#endif /*G10_RSA_H*/
index f231e37..aa3ac09 100644 (file)
@@ -337,10 +337,10 @@ sha1_get_info( int algo, size_t *contextsize,
     *r_asnoid = asn;
     *r_asnlen = DIM(asn);
     *r_mdlen = 20;
-    *r_init  = (void (*)(void *))sha1_init;
-    *r_write = (void (*)(void *, byte*, size_t))sha1_write;
-    *r_final = (void (*)(void *))sha1_final;
-    *r_read  = (byte *(*)(void *))sha1_read;
+    *(void  (**)(SHA1_CONTEXT *))r_init                = sha1_init;
+    *(void  (**)(SHA1_CONTEXT *, byte*, size_t))r_write = sha1_write;
+    *(void  (**)(SHA1_CONTEXT *))r_final               = sha1_final;
+    *(byte *(**)(SHA1_CONTEXT *))r_read                = sha1_read;
 
     return "SHA1";
 }
index 0e42160..abe449a 100644 (file)
@@ -899,10 +899,10 @@ tiger_get_info( int algo, size_t *contextsize,
     *r_asnoid = asn;
     *r_asnlen = DIM(asn);
     *r_mdlen = 24;
-    *r_init  = (void (*)(void *))tiger_init;
-    *r_write = (void (*)(void *, byte*, size_t))tiger_write;
-    *r_final = (void (*)(void *))tiger_final;
-    *r_read  = (byte *(*)(void *))tiger_read;
+    *(void  (**)(TIGER_CONTEXT *))r_init                = tiger_init;
+    *(void  (**)(TIGER_CONTEXT *, byte*, size_t))r_write = tiger_write;
+    *(void  (**)(TIGER_CONTEXT *))r_final               = tiger_final;
+    *(byte *(**)(TIGER_CONTEXT *))r_read                = tiger_read;
 
     return "TIGER";
 }
index 1eea4b8..5766021 100644 (file)
 /* Prototype for the self-test function. */
 static const char *selftest(void);
 
-/* Macros used by the info function. */
-#define FNCCAST_SETKEY(f)  ((int(*)(void*, byte*, unsigned))(f))
-#define FNCCAST_CRYPT(f)   ((void(*)(void*, byte*, byte*))(f))
-
 /* Structure for an expanded Twofish key.  s contains the key-dependent
  * S-boxes composed with the MDS matrix; w contains the eight "whitening"
  * subkeys, K[0] through K[7]. k holds the remaining, "round" subkeys.  Note
@@ -990,16 +986,20 @@ twofish_get_info (int algo, size_t *keylen,
     *keylen = algo==10? 256 : 128;
     *blocksize = 16;
     *contextsize = sizeof (TWOFISH_context);
-    *r_setkey = FNCCAST_SETKEY (twofish_setkey);
-    *r_encrypt= FNCCAST_CRYPT (twofish_encrypt);
-    *r_decrypt= FNCCAST_CRYPT (twofish_decrypt);
-
-   if( algo == 10 )
-     return "TWOFISH";
-   if (algo == 102) /* This algorithm number is assigned for
-                    * experiments, so we can use it */
-     return "TWOFISH128";
-   return NULL;
+
+    *(int  (**)(TWOFISH_context*, const byte*, const unsigned))r_setkey
+                                                       = twofish_setkey;
+    *(void (**)(const TWOFISH_context*, byte*, const byte*))r_encrypt
+                                                       = twofish_encrypt;
+    *(void (**)(const TWOFISH_context*, byte*, const byte*))r_decrypt
+                                                       = twofish_decrypt;
+
+    if( algo == 10 )
+       return "TWOFISH";
+    if (algo == 102) /* This algorithm number is assigned for
+                     * experiments, so we can use it */
+       return "TWOFISH128";
+    return NULL;
 }
 
 
index fddb93d..b3e44ec 100644 (file)
@@ -11,19 +11,17 @@ AC_PREREQ(2.13)
 AC_INIT(g10/gpg.c)
 AC_CONFIG_AUX_DIR(scripts)
 AM_CONFIG_HEADER(config.h)
+AC_CANONICAL_SYSTEM
+AM_INIT_AUTOMAKE(gnupg,`cat $srcdir/VERSION`)
 
-
-VERSION=`cat $srcdir/VERSION`
-PACKAGE=gnupg
-ALL_LINGUAS="de es_ES fr it pl pt_BR pt_PT ru"
+ALL_LINGUAS="da de eo es_ES fr id it ja nl pl pt_BR pt_PT ru sv"
 static_modules="sha1 md5 rmd160"
-AC_SUBST(VERSION)
-AC_SUBST(PACKAGE)
-AC_DEFINE_UNQUOTED(VERSION, "$VERSION")
-AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE")
+static_random_module=""
+
+AC_PROG_AWK
 
-MODULES_IN_CIPHER=`awk '/# MODULES: / { for(i=3;i<=NF;i++) print $i}' \
-                                                $srcdir/cipher/Makefile.am`
+MODULES_IN_CIPHER=`$AWK '/^EXTRA_PROGRAMS/ { for(i=3;i<=NF;i++) print $i}' \
+                                              $srcdir/cipher/Makefile.am`
 
 dnl
 dnl  Check for random module options
@@ -132,7 +130,6 @@ AM_MAINTAINER_MODE
 
 dnl Checks for programs.
 
-AC_CANONICAL_SYSTEM
 dnl
 dnl Setup some stuff depending on host/target.
 dnl
@@ -145,8 +142,10 @@ case "${target}" in
         CC="${target}-gcc"
         CPP="${target}-gcc -E"
         RANLIB="${target}-ranlib"
+        disallowed_modules="rndunix rndlinux rndegd"
         ;;
     *)
+        disallowed_modules="rndw32"
        ;;
 esac
 
@@ -177,9 +176,6 @@ AM_PROG_LIBTOOL
 
 
 MPI_OPT_FLAGS=""
-if test "$GCC" = yes; then
-    CFLAGS="$CFLAGS -Wall -Wcast-align -Wshadow -Wstrict-prototypes"
-fi
 
 
 try_gettext=yes
@@ -213,6 +209,12 @@ case "${target}" in
         try_gdbm="no"
         ;;
 
+    *-*-freebsd*)
+       # FreeBSD
+       CPPFLAGS="$CPPFLAGS -I/usr/local/include"
+       LDFLAGS="$LDFLAGS -L/usr/local/lib"
+       ;;
+
     *-*-hpux*)
         if test -z "$GCC" ; then
             CFLAGS="$CFLAGS -Ae -D_HPUX_SOURCE"
@@ -234,7 +236,7 @@ esac
 AC_SUBST(MPI_OPT_FLAGS)
 GNUPG_SYS_SYMBOL_UNDERSCORE
 GNUPG_CHECK_PIC
-GNUPG_CHECK_RDYNAMIC
+GNUPG_CHECK_EXPORTDYNAMIC
 if test "$NO_PIC" = yes; then
     try_dynload=no
 fi
@@ -272,6 +274,13 @@ case "${target}" in
         NAME_OF_DEV_URANDOM="/dev/urandom"
         DYNLINK_MOD_CFLAGS="-shared -rdynamic -fpic -Wl,-Bshareable -Wl,-x"
         ;;
+
+    *-netbsd*)
+        NAME_OF_DEV_RANDOM="/dev/random"
+        NAME_OF_DEV_URANDOM="/dev/urandom"
+        DYNLINK_MOD_CFLAGS="-shared -rdynamic -fpic -Wl,-Bshareable -Wl,-x"
+        ;;
+
     *)
         NAME_OF_DEV_RANDOM="/dev/random"
         NAME_OF_DEV_URANDOM="/dev/urandom"
@@ -327,21 +336,21 @@ if test "$try_dynload" = yes ; then
   if test "$ac_cv_lib_dl_dlopen" = "yes"; then
     AC_DEFINE(USE_DYNAMIC_LINKING)
     AC_DEFINE(HAVE_DL_DLOPEN)
-    DYNLINK_LDFLAGS="$CFLAGS_RDYNAMIC"
+    DYNLINK_LDFLAGS="$CFLAGS_EXPORTDYNAMIC"
     use_gnupg_extensions=yes
   else
-    AC_CHECK_LIB(c,dlopen)
-    if test "$ac_cv_lib_c_dlopen" = "yes"; then
+    AC_CHECK_FUNCS(dlopen)
+    if test "$ac_cv_func_dlopen" = "yes"; then
       AC_DEFINE(USE_DYNAMIC_LINKING)
       AC_DEFINE(HAVE_DL_DLOPEN)
-      DYNLINK_LDFLAGS="$CFLAGS_RDYNAMIC"
+      DYNLINK_LDFLAGS="$CFLAGS_EXPORTDYNAMIC"
       use_gnupg_extensions=yes
     else
       AC_CHECK_LIB(dld,shl_load)
       if test "$ac_cv_lib_dld_shl_load" = "yes"; then
         AC_DEFINE(USE_DYNAMIC_LINKING)
         AC_DEFINE(HAVE_DL_SHL_LOAD)
-        DYNLINK_LDFLAGS="$CFLAGS_RDYNAMIC"
+        DYNLINK_LDFLAGS="$CFLAGS_EXPORTDYNAMIC"
         use_gnupg_extensions=yes
 dnl -----------------
 dnl  DLD is not ready for use. So I better disable this test
@@ -350,7 +359,7 @@ dnl    AC_CHECK_LIB(dld,dld_link)
 dnl    if test "$ac_cv_lib_dld_dld_link" = "yes"; then
 dnl      AC_DEFINE(USE_DYNAMIC_LINKING)
 dnl      AC_DEFINE(HAVE_DLD_DLD_LINK)
-dnl      DYNLINK_LDFLAGS="$CFLAGS_RDYNAMIC"
+dnl      DYNLINK_LDFLAGS="$CFLAGS_EXPORTDYNAMIC"
 dnl      use_gnupg_extensions=yes
 dnl ---------------
       fi
@@ -371,7 +380,7 @@ AC_SUBST(DYNLINK_MOD_CFLAGS)
 
 dnl Checks for header files.
 AC_HEADER_STDC
-AC_CHECK_HEADERS(unistd.h langinfo.h)
+AC_CHECK_HEADERS(unistd.h langinfo.h termio.h)
 
 
 dnl Checks for typedefs, structures, and compiler characteristics.
@@ -393,6 +402,7 @@ GNUPG_CHECK_TYPEDEF(u32, HAVE_U32_TYPEDEF)
 AC_CHECK_SIZEOF(unsigned short, 2)
 AC_CHECK_SIZEOF(unsigned int, 4)
 AC_CHECK_SIZEOF(unsigned long, 4)
+AC_CHECK_SIZEOF(unsigned long long, 0)
 
 if test "$ac_cv_sizeof_unsigned_short" = "0" \
    || test "$ac_cv_sizeof_unsigned_int" = "0" \
@@ -405,8 +415,9 @@ fi
 dnl Checks for library functions.
 AC_FUNC_VPRINTF
 AC_CHECK_FUNCS(strerror stpcpy strlwr stricmp tcgetattr rand strtoul mmap)
-AC_CHECK_FUNCS(memmove gettimeofday getrusage gethrtime setrlimit)
+AC_CHECK_FUNCS(memmove gettimeofday getrusage gethrtime setrlimit clock_gettime)
 AC_CHECK_FUNCS(memicmp atexit raise getpagesize strftime nl_langinfo)
+AC_CHECK_FUNCS(waitpid wait4 sigaction sigprocmask)
 
 GNUPG_CHECK_MLOCK
 GNUPG_FUNC_MKDIR_TAKES_ONE_ARG
@@ -483,29 +494,27 @@ fi
 dnl
 dnl Figure out the default linkage mode for cipher modules
 dnl
-dnl (We always need a static rmd160)
 print_egd_notice=no
-static_modules="$static_modules rmd160"
 if test "$use_static_rnd" = default; then
   if test "$ac_cv_have_dev_random" = yes; then
-      static_modules="$static_modules rndlinux"
+      static_random_module="rndlinux"
   else
       case "${target}" in
           *-*-mingw32)
-              static_modules="$static_modules rndw32"
+              static_random_module="rndw32"
               AC_DEFINE(USE_STATIC_RNDW32)
               ;;
           i?86-emx-os2|i?86-*-os2*emx)
-              static_modules="$static_modules rndos2"
+              static_random_module="rndos2"
               ;;
           m68k-atari-mint)
-              static_modules="$static_modules rndatari"
+              static_random_module="rndatari"
               ;;
           i?86-*-msdosdjgpp*)
-              static_modules="$static_modules"
+              :
               ;;
           *)
-              static_modules="$static_modules rndunix"
+              static_random_module="rndunix"
               print_egd_notice=yes
              ;;
       esac
@@ -514,7 +523,7 @@ else
   if test "$use_static_rnd" = none; then
     :
   else
-    static_modules="$static_modules rnd$use_static_rnd"
+    static_random_module="rnd$use_static_rnd"
     if test "$use_static_rnd" = "unix"; then
         print_egd_notice=yes
     fi
@@ -547,23 +556,31 @@ dnl
 dnl Parse the modules list and build the list
 dnl of static and dymically linked modules
 dnl
+dnl (We always need a static rmd160)
+static_modules="$static_modules rmd160 $static_random_module"
 STATIC_CIPHER_NAMES=""
 STATIC_CIPHER_OBJS=""
 DYNAMIC_CIPHER_MODS=""
 GNUPG_MSG_PRINT([dynamically linked cipher modules:])
 for name in $MODULES_IN_CIPHER; do
-    x="no"
-    for i in $static_modules; do
-        if test "$name" = "$i" ; then
-            x="yes"
-        fi
+    x="yes"
+    for i in $disallowed_modules; do
+        if test "$name" = "$i" ; then x="no" ; fi
     done;
     if test $x = yes; then
-        STATIC_CIPHER_NAMES="$STATIC_CIPHER_NAMES $name"
-        STATIC_CIPHER_OBJS="$STATIC_CIPHER_OBJS $name.lo"
-    else
-        DYNAMIC_CIPHER_MODS="$DYNAMIC_CIPHER_MODS $name"
-        GNUPG_MSG_PRINT([$name])
+        x="no"
+        for i in $static_modules; do
+            if test "$name" = "$i" ; then
+                x="yes"
+            fi
+        done;
+        if test $x = yes; then
+            STATIC_CIPHER_NAMES="$STATIC_CIPHER_NAMES $name"
+            STATIC_CIPHER_OBJS="$STATIC_CIPHER_OBJS $name.o"
+        else
+            DYNAMIC_CIPHER_MODS="$DYNAMIC_CIPHER_MODS $name"
+            GNUPG_MSG_PRINT([$name])
+        fi
     fi
 done
 AC_MSG_RESULT()
@@ -663,6 +680,9 @@ fi
 AC_SUBST(ZLIBS)
 
 
+# Allow users to append something to the version string without
+# flagging it as development version.  The user version parts is
+# considered everything after a dash.
 changequote(,)dnl
 tmp_pat='[a-zA-Z]'
 changequote([,])dnl
@@ -678,12 +698,26 @@ AM_CONDITIONAL(CROSS_COMPILING, test x$cross_compiling = xyes)
 
 GNUPG_DO_LINK_FILES
 
+GNUPG_CHECK_GNUMAKE
+
+if test "$GCC" = yes; then
+    if test "$MAINTAINER_MODE" = "yes"; then
+        CFLAGS="$CFLAGS -Wall -Wcast-align -Wshadow -Wstrict-prototypes"
+    else
+        CFLAGS="$CFLAGS -Wall"
+    fi
+fi
+
 dnl
 dnl Make the version number in gcrypt/gcrypt.h the same as the one here.
 dnl (this is easier than to have a .in file just for one substitution)
 dnl
 GNUPG_FIX_HDR_VERSION(gcrypt/gcrypt.h, GCRYPT_VERSION)
 
+GCRYPT_LIBS="-L${libdir} -lgcrypt"
+GCRYPT_CFLAGS=""
+AC_SUBST(GCRYPT_LIBS)
+AC_SUBST(GCRYPT_CFLAGS)
 
 AC_OUTPUT_COMMANDS([
 chmod +x scripts/db2html
index 64056be..6d3aa7c 100644 (file)
-Thu May 25 18:39:11 CEST 2000  Werner Koch  <wk@openit.de>
+Fri Jul 14 19:38:23 CEST 2000  Werner Koch  <wk@>
 
-  * kbxio.c: New.
+  Replaced everything with the code from the STABLE-BRANCH-1-0 and
+  started to backport the changes from the 1.1 development branch
+  which are dated according to the ChangeLog of the 1.1 from
+  Sat Sep 18 12:16:08 CEST 1999  to  Thu May 25 18:39:11 CEST 2000.
+  Here are those changes, some of them are duplicates because they
+  have been done on both branch simultaneously.
 
-  * kbxfile.c (print_kbxfile): Add a loop
-  (do_print_kbxfile): Fixed passing to kbx_dump_blob.
+  * gpg.c (print_mds): Add arg keys as a kludge to print hmacs
+  (main): New option --print-hmac.
 
-Fri Mar 24 11:25:45 CET 2000  Werner Koch  <wk@openit.de>
+  * trustdb.c (verify_own_keys): Do not print warning about unprotected
+  key when in quiet mode.
 
-       * gpg.c (print_mds): Add arg keys as a kludge to print hmacs
-       (main): New option --print-hmac.
+  * build-paket.c (do_user_id): Save offset where name has been stored.
+
+  * ringedit.c : Add new access method KBXF
+
+  * kbxfile.c: New.
+
+  * kbx.h: New.
+  * kbxblob.c: Started to work on the keybox stuff.
+
+  * keygen.c (gen_dsa): Modified to work with gcry_pk_genkey.
+
+  * Removed dummy-cipher.h from all files.
+
+  * keygen.c (gen_elg): Modified to work with gcry_pk_genkey.
+  (key_from_sexp): New.
+  (factors_from_sexp): New.
+
+  * g10.c : Renamed to ...
+  * gpg.c : ... this
+  * Makefile.am: And fixed it here.
+
+  * Changed all "g10_"/"GPG_" prefixes to "gpg_"/"GPG_".
+
+  * misc.c (mpi_read_opaque): Fixed double counting.
+
+  * seckey-cert.c (do_check): Removed buffer and the unmotivated free
+  on it.
+
+  * pubkey-enc.c (pk_decrypt): New wrapper for the gcry_ function.
+  * seckey-cert.c (pk_check_secret_key): Likewise.
+  * encode.c (pk_encrypt): Likewise.
+
+  * parse-packet.c (parse_key): Fixed case of unencrypted secret keys.
+
+  * misc.c (mpi_print): Use gcry_mpi_aprint.
+  (pubkey_nbits): Kludge to use the gcry_pk_ API.
+
+  * seskey.c (encode_session_key): Replaced mpi_set_buffer by *_scan.
+  (do_encode_md): Ditto.
+  (encode_md_value): Ditto.
+  * seckey-cert.c (protect_secret_key): Ditto.
+  * comment.c (make_mpi_comment_node): Replaced mpi_get_buffer by _print.
+  * pubkey-enc.c (get_it): Ditto.
+  * sig-check.c (do_signature_check): Ditto.
+
+  * keyid.c (do_fingerprint_md): Replaced mpi_get_buffer by gcry_mpi_print.
+  (v3_keyid): New.
+  (keyid_from_sk): And use it here.
+  (keyid_from_pk): Ditto.
+  (fingerprint_from_sk): Ditto.
+  (fingerprint_from_pk): Ditto.
+
+  * misc.c (mpi_print): New.
+
+  * misc.c (checksum_mpi): Now uses gcry_mpi_print to get the data.
+
+  * seckey-cert.c (do_check): Replaced mpi_read_from_buffer.
+
+  * armor.c (armor_filter): Made the "Comment:" header translatable.
+
+  * seckey-cert.c: Removed obsolete mpi_*_protect_flag.
+  * parse-packet.c: Ditto.
+
+  * misc.c (mpi_read): Removed the secure argumet becuase it is
+  never used.  Changed all Callers.
+  (mpi_read_opaque): New.
+  (mpi_write_opaque): New.
+  * parse-packet.c (parse_key): Use the opaque method also for
+  v3 keys.
+  * build-packet.c (do_secret_key): Likewise.
+
+  * g10.c (main): Check libgcrypt version.
+
+  * packet.h: replaced inclusion of mpi.h by a plain typeedef of the
+  gcry_mpi structure and removed all inclusions of "mpi.h" in all
+  sources.
+
+  * g10.c: Add --delete-secret-key to the help page.
+
+  * g10.c (main): Changed the default homedir to "~/.gnupg-test" so
+  that we don't mess up with the stable version.
+
+  * misc.c (mpi_write): New.
+  (mpi_write): New.
+
+  * misc.c (checksum_u16_nobug): Removed.
+  (checksum_mpi_counted_nbits): Renamed to ...
+  (checksum_mpi): ... this to superseed the old one. Changed all
+  callers. This is because we do not emulate the old gpg bug anymore.
+  * g10.c (oEmuChecksumBug): Removed.
+
+  * g10.c (register_extension): New...
+  (main): Use it here instead of register_cipher_extesnion.
+  (strusage): s/strusage/my_strusage/ . Made static.
+  (main): Use set_strusage().
+
+  * tdbdump.c (HEXTOBIN): Changed the name of the argument, so that
+  traditional cpp don't mess up the macros. Suggested by Jos Backus.
+
+  * armor.c (parse_header_line): Stop parsing on a only WS line too.
+  Suggested by Aric Cyr.
+
+  * misc.c (pull_in_libs): Removed.
+
+  * mainproc.c (list_node): Print the PK algo in the --with-colon mode.
+  * keylist.c (list_keyblock): Ditto.
+
+  * misc.c (pull_in_libs): Removed pull in of g10c.
+
+  * misc.c (map_gcry_rc): Removed here and chnaged all users.
+
+  * getkey.c: Replaced check_pubkey_algo by openpgp_pk_test_algo.
+  * import.c (delete_inv_parts): Ditto.
+  * pkclist.c: Ditto.
+  * skclist.c: Ditto.
+  * pubkey-enc.c: Ditto.
+
+  * g10.c (main): Replaced the function to diable PK algos.
+
+  * g10.c (main): Replaced get_random_bits by gcry_random_bytes.
+  * seskey.c (encode_session_key): Likewise.
+  (make_session_key): Renamed randomize_buffer to gcry_randomize
+  and use the GCRY_xxx_RANDOM constants.
+  * cipher.c (write_header): Ditto.
+  * passphrase.c (hash_passphrase): Ditto.
+  * seckey-cert.c (protect_secret_key): Ditto.
+
+  * getkey.c (find_by_name): Replaced rmd160_hash_buffer
+  by gcry_md_hash_buffer.
+  * keyedit.c (show_prefs): Ditto.
+  * keylist.c (list_keyblock): Ditto.
+  * trustdb.c (print_uid_from_keyblock): Ditto.
+  (make_uid_records): Ditto.
+
+  * skclist.c (build_sk_list): Removed the test on faked RNGs.
+  (is_insecure): Removed.
+  * g10.c (--quick-random): Removed this option.
+
+  * Replaced all PUBKEY_ALGO_xxx by GCRY_PK_xxxx.
+
+  * misc.c (pubkey_algo_npkey): New as a wrapper around the gcry fucntion.
+  (pubkey_algo_nskey): Ditto.
+  (pubkey_algo_nsig): Ditto.
+  (pubkey_algo_nenc): Ditto.
+
+  * Makefile.am (basicdefs.h): Added.
+  (install-data-local): Removed the handling for historic gpgm.
+
+  * misc.c (openpgp_cipher_test_algo): New.
+  (openpgp_pk_test_algo): New.
+  (openpgp_md_test_algo): New.
+
+  * g10.c (build_list): Changed to use the new functions from libgcrypt.
+
+  * ringedit.c (enum_keyblocks): Set .rt to 0 on open.
+
+  * encode.c (encode_simple): Use new CTB when we don't have the
+  length of the file.  This is somewhat strange as the comment above
+  indicates that this part is actually fixed for PGP 5 - maybe I simply
+  lost the source line, tsss.
+
+  * sign.c (clearsign_file): Avoid duplicated Entries in the "Hash:"
+  line.  Those headers are now only _not_ printed when there are
+  only old-style keys _and_ all hashs are MD5.
+
+  (clearsign_file): Use gcry_md_test_algo() and gcry_md_algo_name().
+
+  * openfile.c (make_outfile_name): Use case-insenstive compare for
+  DOS systems. Add ".pgp" to the list of know extensions.
+  (open_outfile): For DOS systems try to replace the suffix instead of
+  appending it.
+
+  * encr-data.c (decrypt_data): Reset error on a weak key.
+
+  * cipher.c: Replaced the cipher and digest functions by the gcry_ ones.
+  * seckey-cert.c: Ditto.
+  * seskey.c: Ditto.
+  * g10.c (print_mds): Replaced digst functions with the new gcry_ ones.
+  * keyid.c: Ditto.
+  * mainproc.c: Ditto.
+  * passphrase.c: Ditto.
+  * sig-check.c: Ditto.
+  * sign.c: Ditto.
+
+  * pkclist.c (do_edit_ownertrust): Made the answer string const.
+
+  * basicdefs.h: New.  Move some defs and decl to this header.
+
+  * openfile.c (open_outfile): Fixed the 8dot3 handling.
+
+  * passphrase.c (passphrase_to_dek): Print uid using utf8 func.
+  * delkey.c (delete_key): Ditto.
+  * pkclist.c (show_paths,do_edit_ownertrust,do_we_trust): Ditto
+  (do_we_trust_pre): Ditto.
+  * trustdb.c (print_user_id,check_uidsigs): Ditto.
+  * revoke.c (gen_revoke,ask_revoke_sig): Ditto.
+
+  * filter.h: Changed cipher handle types to the the GCRY_xxx ones.
+  replaces include cipher by system header include gcrypt.h.
+  * cipher.c: replaced the cipher functions by the gcry_ ones.
+  Ditto for the md functions.
+
+  * misc.c (map_gcry_rc): New.
+
+Wed Jun 28 11:54:44 CEST 2000  Werner Koch  <wk@>
+
+  * armor.c (armor_filter): Set sigclass to 0 in case of non-dash-escaped
+  clearsig.  This makes this mode work again.
+
+  * mainproc.c (proc_tree): Fixed handling of one-pass-sig packets in textmode.
+  Disabled the ugly workaround for PGP 5 - let's see whether thi breaks less
+  cases. Found by Ted Cabeen.
+
+  * options.h (DBG_HASHING): New.  All commented md_start_debug are now
+  controlled by this debug option.
+
+  * sign.c (print_status_sig_created): New and called from 2 places.
+
+  * keygen.c (gen_rsa): New, but commented.
+  (ask_algo): Commented support for RSA.
+
+  * seckey-cert.c (protect_secret_key): Started to fix the code for v4 RSA
+  keys - it is not solved yet. However, we have time until, Sep 20th ;)
+
+Wed Jun 14 12:27:09 CEST 2000  Werner Koch  <wk@openit.de>
+
+  * status.c (init_shm_coprocessing): Changed the sequence of the get,attach
+  to cope with the changes in newer Linux kernels.  This bug has been found
+  by <dmitri@advantrix.com> who also proposed this solution.  Hopefully
+  this does not break gpg on to many systems.
+
+  * cipher.c (write_header): Protect the IV with the MDC too.
+  * encr-data.c (decrypt_data): Likewise.
+
+Fri Jun  9 10:09:52 CEST 2000  Werner Koch  <wk@openit.de>
+
+  * g10.c: New options --no-auto-key-retrieve
+  * options.h (auto_key_retrieve): New.
+  * mainproc.c (check_sig_and_print): Implemented that.
+
+Wed Jun  7 19:19:09 CEST 2000  Werner Koch  <wk@openit.de>
+
+  * sig-check.c (do_check): Use EMULATE_MDENCODE also on v4 paclets.
+
+Wed Jun  7 17:25:38 CEST 2000  Werner Koch  <wk@openit.de>
+
+  * cipher.c (write_header): Use plain CFB mode for MDC encrypted packets.
+  * encr-data.c (decrypt_data): Ditto.
+
+Mon Jun  5 23:41:54 CEST 2000  Werner Koch  <wk@openit.de>
+
+  * seskey.c (do_encode_md, encode_md_value): Add new arg v3compathack to work
+  around a bug in old versions.
+  * sig-check.c (do_check): use the aboved workaround when enabled.
+  * g10.c: New option --emulate-md-decode-bug
+
+Mon Jun  5 12:37:43 CEST 2000  Werner Koch  <wk@openit.de>
+
+  * build-packet.c (do_mdc): New.
+  (do_encrypted_mdc): Changed for the new proposal.
+  * parse-packet.c (parse_mdc): New.
+  (parse_encrypted): Fixed for the new proposal.
+  * packet.h (PKT_MDC): New.
+  * cipher.c (cipher_filter): Build the MDC packet here.
+  * g10.c (main): Enable --force-mdc.
+  * encr-data.c (mdc_decode_filter): Fixed for new MDC method
+
+  * options.h(rfc2440): New.
+  * g10.c (main): Changed the selected values for --openpgp to not include
+  optional algorithms.
+
+Thu May 18 11:38:54 CEST 2000  Werner Koch  <wk@openit.de>
+
+       * keyedit.c (keyedit_menu): Add a keyword arg to the prompt.
+
+       * status.c, status.h: Added 3 new status tokens.
+       * status.c (do_get_from_fd): New.
+       (cpr_enabled,cpr_get,cpr_get_hidden,cpr_kill_prompt,
+        cpr_get_answer_is_yes,cpr_get_answer_yes_no_quit): Modified to work
+        with the new function.
+       * g10.c: Add new option --command-fd.
+
+       * status.c (progress_cb): New.
+       (set_status_fd): Register progress functions
+
+Fri May 12 14:01:20 CEST 2000  Werner Koch  <wk@openit.de>
+
+       * delkey.c (delete_key): Add 2 new status messages
+       * status.c, status.h (STATUS_DELETE_PROBLEM): New.
+
+       Fixed years of copyright in all source files.
+
+Mon May  1 17:08:14 CEST 2000  Werner Koch  <wk@openit.de>
+
+       * trustdb.c (propagate_validity): Fixed the bug that only one uid
+       gets fully trusted even when all are signed by an ultimate key.
+
+Mon May  1 15:38:04 CEST 2000  Werner Koch  <wk@openit.de>
+
+       * getkey.c (key_byname): Always returned a defined context.  Fixed
+       a segv for invalid user id specifications. Reported by Walter Koch.
+
+       * getkey.c (get_user_id): I18ned "no user id" string. By Walter.
+
+       * pkclist.c (do_show_revocation_reason): Typo fixes.
+       * helptext.c: Ditto.
+
+       * armor.c (armor_filter): Fixed some CRLF issues.  By Mike McEwan.
+
+Fri Apr 14 19:37:08 CEST 2000  Werner Koch  <wk@openit.de>
+
+       * pkclist.c (do_show_revocation_reason): New.
+       (show_revocation_reason): New and called at various places.
+
+       * g10.c (main): Fixed small typo.
+
+       * pkclist.c (do_we_trust): Act on always_trust but not for revoked
+       keys. Suggested by Chip Salzenberg.
+
+       * g10.c: New option --lock-never.
+
+       * ringedit.c (get_writable_keyblock_file): New.
+       * keygen.c (do_generate_keypair): Use this instead of the hardwired one.
+
+       * keygen.c (ask_user_id): Check that the email address is in the
+       correct field.  Suggested by Christian Kurz.
+
+Mon Apr 10 13:34:19 CEST 2000  Werner Koch  <wk@openit.de>
+
+       * keyedit.c (show_key_with_all_names): s/sbb/ssb/
+
+Tue Mar 28 14:26:58 CEST 2000  Werner Koch  <wk@openit.de>
 
        * trustdb.c (verify_own_keys): Do not print warning about unprotected
        key when in quiet mode.
 
-Mon Mar 13 19:22:46 CET 2000  Werner Koch  <wk@openit.de>
+Wed Mar 22 13:50:24 CET 2000  Werner Koch  <wk@openit.de>
 
-       * build-paket.c (do_user_id): Save offset where name has been stored.
+       * mainproc.c (print_userid): Do UTF8 conversion before printing.
+       * import.c (import_one): Ditto.
+       (import_secret_one): Ditto.
+       (delete_inv_parts): Ditto.
 
-       * ringedit.c : Add new access method KBXF
+Thu Mar 16 16:20:23 CET 2000  Werner Koch  <wk@openit.de>
 
-       * kbxfile.c: New.
+       * keylist.c (print_key_data): Handle a NULL pk gracefully.
 
-Mon Feb 21 22:43:01 CET 2000  Werner Koch  <wk@>
+       * getkey.c (merge_one_pk_and_selfsig): Fixed silly code for
+       getting the primary keys keyID but kept using the one from the
+       subkey.
+       * pubkey-enc.c (get_it): Print a note for expired subkeys.
 
-       * kbx.h: New.
-       * kbxblob.c: Started to work on the keybox stuff.
+       * getkey.c (has_expired): New.
+       (subkeys_expiretime): New.
+       (finish_lookup): Check for expired subkeys needed for encryption.
+       (merge_keys_and_selfsig): Fixed expiration date merging for subkeys.
 
-Mon Jan 31 16:37:34 CET 2000  Werner Koch  <wk@gnupg.de>
+       * keylist.c (list_keyblock): Print expiration time for "sub".
+       (list_one): Add missing merging for public keys.
+       * mainproc.c (list_node): Ditto.
 
-       * keygen.c (gen_dsa): Modified to work with gcry_pk_genkey.
+2000-03-14 13:49:38  Werner Koch  (wk@habibti.openit.de)
 
-       * Removed dummy-cipher.h from all files.
+       * keygen.c (keyedit_menu): Do not allow to use certain commands
+       while the secret key is selected.
 
-Thu Jan 27 18:00:44 CET 2000  Werner Koch  <wk@gnupg.de>
+2000-03-09 12:53:09  Werner Koch  (wk@habibti.openit.de)
 
-       * keygen.c (gen_elg): Modified to work with gcry_pk_genkey.
-       (key_from_sexp): New.
-       (factors_from_sexp): New.
+       * keygen.c (ask_expire_interval): Movede parsig to ...
+       (parse_expire_string): ... this new function. And some new control
+       commands.
+       (proc_parameter_file): Add expire date parsing.
+       (do_generate_keypair): Allow the use of specified output files.
 
-       * g10.c : Renamed to ...
-       * gpg.c : ... this
-       * Makefile.am: And fixed it here.
+2000-03-08 10:38:38  Werner Koch  (wk@habibti.openit.de)
 
-       * Changed all "g10_"/"GPG_" prefixes to "gpg_"/"GPG_".
+       * keygen.c (ask_algo): Removed is_v4 return value and the commented
+       code to create Elg keys in a v3 packet. Removed the rounding
+       of key sizes here.
+       (do_create): Likewise removed arg v4_packet.
+       (gen_elg): Likewise removed arg version. Now rounding keysizes here.
+       (gen_dsa): Rounding keysize now here.
+       (release_parameter_list): New
+       (get_parameter*): New.
+       (proc_parameter_file): New.
+       (read_parameter_file): New.
+       (generate_keypair): Splitted. Now uses read_parameter_file when in
+       batch mode.  Additional argument to specify a parameter file.
+       (do_generate_keypair): Main bulk of above fucntion and uses the
+       parameter list.
+       (do_create): Don't print long notice in batch mode.
+       * g10.c (main): Allow batched key generation.
 
-Mon Jan 24 22:24:38 CET 2000  Werner Koch  <wk@gnupg.de>
+Thu Mar  2 15:37:46 CET 2000  Werner Koch  <wk@gnupg.de>
 
-       * misc.c (mpi_read_opaque): Fixed double counting.
+       * pubkey-enc.c (get_it): Print a note about unknown cipher algos.
 
-       * seckey-cert.c (do_check): Removed buffer and the unmotivated free
-       on it.
+       * g10.c (opts): Add a note to the help listing about the man page
+       and removed some options from the help listing.
 
-       * pubkey-enc.c (pk_decrypt): New wrapper for the gcry_ function.
-       * seckey-cert.c (pk_check_secret_key): Likewise.
-       * encode.c (pk_encrypt): Likewise.
+       * keyedit.c (print_and_check_one_sig): Use a new function to truncate
+       the output of the user ID.  Suggested by Jan-Benedict Glaw.
 
-       * parse-packet.c (parse_key): Fixed case of unencrypted secret keys.
+Wed Feb 23 10:07:57 CET 2000  Werner Koch  <wk@gnupg.de>
 
-Mon Jan 24 13:04:28 CET 2000  Werner Koch  <wk@gnupg.de>
+       * helptext.c: typo fix.
 
-       * misc.c (mpi_print): Use gcry_mpi_aprint.
-       (pubkey_nbits): Kludge to use the gcry_pk_ API.
+Thu Feb 17 13:39:32 CET 2000  Werner Koch  <wk@gnupg.de>
 
-       * seskey.c (encode_session_key): Replaced mpi_set_buffer by *_scan.
-       (do_encode_md): Ditto.
-       (encode_md_value): Ditto.
-       * seckey-cert.c (protect_secret_key): Ditto.
-       * comment.c (make_mpi_comment_node): Replaced mpi_get_buffer by _print.
-       * pubkey-enc.c (get_it): Ditto.
-       * sig-check.c (do_signature_check): Ditto.
+       * revoke.c: Removed a bunch of commented code.
 
-Fri Dec 31 12:48:31 CET 1999  Werner Koch  <wk@gnupg.de>
+       * packet.h (SIGSUBPKT_REVOC_REASON): New.
+       * build-packet.c (build_sig_subpkt): Support new sub packet.
+       * parse-packet.c (parse_one_sig_subpkt): Ditto.
+       (dump_sig_subpkt): Ditto.
+       * revoke.c (ask_revocation_reason): New.
+       (release_revocation_reason_info): New.
+       (revocation_reason_build_cb): New.
+       (gen_revoke): Ask for reason.
+       * main.h (struct revocation_reason_info): Add declaration.
+       * keyedit.c (menu_revsig): Add support for revocation reason.
+       (menu_revkey): Ditto.
+       (sign_uid_mk_attrib): Renamed to ...
+       (sign_mk_attrib): ... this, made static and add support for reasons.
 
-       * keyid.c (do_fingerprint_md): Replaced mpi_get_buffer by gcry_mpi_print.
-       (v3_keyid): New.
-       (keyid_from_sk): And use it here.
-       (keyid_from_pk): Ditto.
-       (fingerprint_from_sk): Ditto.
-       (fingerprint_from_pk): Ditto.
+Tue Feb 15 08:48:13 CET 2000  Werner Koch  <wk@gnupg.de>
+
+       * build-packet.c (build_packet): Fixed fixing of old comment packets.
+
+       * import.c (import_keys): Fixed importing from stdin when called with
+       nnames set to zero as it normally happens.
+
+Mon Feb 14 14:30:20 CET 2000  Werner Koch  <wk@gnupg.de>
+
+       * sig-check.c (check_key_signature2): Add new arg r_expired.
+       (do_signature_check): New arg to pass it down to ...
+       (do_check): New arg r-expire which is set when the signature
+       has expired.
+       * trustdb.c (check_sig_record): Set SIGF_EXPIRED flag and set
+       the expiretime to zero so that thi signature will not be checked
+       anymore.
+
+Fri Feb 11 17:44:40 CET 2000  Werner Koch  <wk@gnupg.de>
 
-       * misc.c (mpi_print): New.
+       * g10.c (g10_exit): Update the random seed_file.
+       (main): Set the random seed file.  New option --no-random-seed-file.
 
-       * misc.c (checksum_mpi): Now uses gcry_mpi_print to get the data.
+Thu Feb 10 17:39:44 CET 2000  Werner Koch  <wk@gnupg.de>
 
-       * seckey-cert.c (do_check): Replaced mpi_read_from_buffer.
+       * keyedit.c (menu_expire): Fixed segv due to unitialized sub_pk.
+       By Rémi.
+
+Thu Feb 10 11:39:41 CET 2000  Werner Koch  <wk@gnupg.de>
+
+       * keylist.c (list_keyblock): Don't print warnings in the middle of
+       regulat output lines.  By Rémi.
+
+       * sig-check.c: Include options.h
+
+Wed Feb  9 15:33:44 CET 2000  Werner Koch  <wk@gnupg.de>
+
+       * gpg.c: New option --ignore-time-conflict
+       * sig-check.c (do_check): Implemented this option.
+       * trustdb.c (check_trust): Ditto.
+       * sign.c (do_sign): Ditto.
+       * keygen.c (generate_subkeypair): Ditto.
+
+       * encode.c (encode_simple): use iobuf_cancel after open failure.
+       Reported by Huy Le.
+
+Fri Jan 14 18:32:01 CET 2000  Werner Koch  <wk@gnupg.de>
+
+       * packet.h (STRING2KEY): Changed mode from byte to int.
+       * parse-packet.c (parse_key): Add the special GNU protection stuff
+       * build-packet.c (so_secret_key): Ditto.
+       * seckey-cert.c (do_check): Ditto.
+       * keyedit.c (change_passphrase): Ditto.
+       * export.c (export_secsubkeys): New.
+       (do_export_stream): Hack to export the primary key using mode 1001.
+       * g10.c: New command --export-secret-subkeys
+
+Thu Jan 13 19:31:58 CET 2000  Werner Koch  <wk@gnupg.de>
+
+       * armor.c (is_armored): Check for 1-pass-sig packets. Reported by
+       David Hallinan <hallinan@rtd.com>.
+       (armor_filter): Replaced one LF by the LF macro.  Reported by
+       Wolfgang Redtenbacher.
+
+Wed Jan  5 11:51:17 CET 2000  Werner Koch  <wk@gnupg.de>
+
+       * g10.c (main): Reset new global flag opt.pgp2_workarounds
+       when --openpgp is used.
+       * mainproc.c (proc_plaintext): Do the PGP2,5 workarounds only
+       when the global flag is set.
+       (proc_tree): Ditto.
+       * textfilter.c (copy_clearsig_text): Ditto.
+       * armor.c (armor_filter): Ditto.
+
+       * g10.c: New option --list-only
+       * mainproc.c (proc_tree): Don't do it if opt.list_only is active.
+       (proc_pubkey_enc): Implement option.
+
+       * status.h, status.c ({BEGIN,END}_{EN,DE}CRYPTION): New.
+       * cipher.c (cipher_filter): New status outputs.
+       * mainproc.c (proc_encrypted): New status outputs.
+
+Fri Dec 31 14:08:15 CET 1999  Werner Koch  <wk@gnupg.de>
 
        * armor.c (armor_filter): Made the "Comment:" header translatable.
 
-Wed Dec  8 21:58:32 CET 1999  Werner Koch  <wk@gnupg.de>
+       * hkp.c (hkp_import): Make sure that the program does not return
+       success when there is a connection problem.  Reported by Phillip Jones.
+
+Sun Dec 19 15:22:26 CET 1999  Werner Koch  <wk@gnupg.de>
+
+       * armor.c (LF): Use this new macro at all places where a line LF
+       is needed.  This way DOSish textfiles should be created when the
+       input data is also in dos mode.
+       * sign.c (LF): Ditto.
+       * textfilter.c (LF): Ditto.
+       (copy_clearsig_text): Disabled the forcing of CR,LF sequences
+       for DOS systems.
+
+       * plaintext.c (handle_plaintext): Fixes for line endings on DOS.
+       and react on a LF in cleartext.
+       * armor.c (fake_packet): Restore the original line ending after
+       removing trailing spaces.
+
+       * signal.c (got_fatal_signal): DOS fix.
 
-       * seckey-cert.c: Removed obsolete mpi_*_protect_flag.
-       * parse-packet.c: Ditto.
+Thu Dec 16 10:07:58 CET 1999  Werner Koch  <wk@gnupg.de>
 
-       * misc.c (mpi_read): Removed the secure argumet becuase it is
-       never used.  Changed all Callers.
-       (mpi_read_opaque): New.
-       (mpi_write_opaque): New.
-       * parse-packet.c (parse_key): Use the opaque method also for
-       v3 keys.
-       * build-packet.c (do_secret_key): Likewise.
+       * mainproc.c (print_failed_pkenc): Fix for unknown algorithm.
+       Found by fygrave@epr0.org.
 
-       * g10.c (main): Check libgcrypt version.
+Thu Dec  9 10:31:05 CET 1999  Werner Koch  <wk@gnupg.de>
 
-       * packet.h: replaced inclusion of mpi.h by a plain typeedef of the
-       gcry_mpi structure and removed all inclusions of "mpi.h" in all
-       sources.
+       * hkp.c: i18n the strings.
+
+Sat Dec  4 15:32:20 CET 1999  Werner Koch  <wk@gnupg.de>
+
+       * trustdb.c (verify_key): Shortcut for ultimately trusted keys.
+
+Sat Dec  4 12:30:28 CET 1999  Werner Koch  <wk@gnupg.de>
+
+       * pkclist.c (build_pk_list): Validate the trust using the namehash
+       if this one has been set by the key lookup.
 
        * g10.c: Add --delete-secret-key to the help page.
 
-       * g10.c (main): Changed the default homedir to "~/.gnupg-test" so
-       that we don't mess up with the stable version.
+       * openfile.c (copy_options_file): Made static.
+       (try_make_homedir): New.
+       * ringedit.c (add_keyblock_resource): Use the try_make_hoemdir logic.
+       * tdbio.c (tdbio_set_dbname): Likewise.
 
-       * misc.c (mpi_write): New.
-       (mpi_write): New.
+       * keygen.c (generate_user_id): Use m_alloc_clear() here. We should
+       better use an allocation function specific to the user_id packet.
 
-       * misc.c (checksum_u16_nobug): Removed.
-       (checksum_mpi_counted_nbits): Renamed to ...
-       (checksum_mpi): ... this to superseed the old one. Changed all
-       callers. This is because we do not emulate the old gpg bug anymore.
-       * g10.c (oEmuChecksumBug): Removed.
+       * keygen.c (keygen_add_std_prefs): Changed symmetric preferences
+       to include Blowfish again.  This is due to it's better speed compared
+       to CAST5.
 
-Fri Nov 19 17:15:20 CET 1999  Werner Koch  <wk@gnupg.de>
+       * g10.c (strusage): Print the home directory.
 
-       * g10.c (register_extension): New...
-       (main): Use it here instead of register_cipher_extesnion.
-       (strusage): s/strusage/my_strusage/ . Made static.
-       (main): Use set_strusage().
+       * armor.c (armor_filter): Take action on the cancel control msg.
+       * filter.h (armor_filter_context_t): Add cancel flag.
 
-       * tdbdump.c (HEXTOBIN): Changed the name of the argument, so that
-       traditional cpp don't mess up the macros. Suggested by Jos Backus.
+Mon Nov 29 21:52:11 CET 1999  Werner Koch  <wk@gnupg.de>
 
-       * armor.c (parse_header_line): Stop parsing on a only WS line too.
-       Suggested by Aric Cyr.
+       * g10.c: New option --fast-list-mode ..
+       * keylist.c (list_keyblock): .. and implemented.
+       * mainproc.c (list_node): Ditto.
 
-Mon Nov 15 21:36:02 CET 1999  Werner Koch  <wk@gnupg.de>
+       * import.c (mark_non_selfsigned_uids_valid): Fixed the case that there
+       is a uid without any packet following.
 
-       * misc.c (pull_in_libs): Removed.
+Mon Nov 22 11:14:53 CET 1999  Werner Koch  <wk@gnupg.de>
+
+       * mainproc.c (proc_plaintext): Never enable the hash processing
+       when skip_verify is active.
+
+       * armor.c (parse_header_line): Stop parsing on a WS line too.
+       Suggested by Aric Cyr.
 
-Sat Nov 13 17:44:23 CET 1999  Werner Koch  <wk@gnupg.de>
+       * tdbdump.c (HEXTOBIN): Changed the name of the argument, so that
+       traditional cpp don't mess up the macros. Suggested by Jos Backus.
 
        * mainproc.c (list_node): Print the PK algo in the --with-colon mode.
        * keylist.c (list_keyblock): Ditto.
 
-       * misc.c (pull_in_libs): Removed pull in of g10c.
+       * signal.c (got_fatal_signal): Found the reason why exit(8) did not
+       work - it is better to set the disposition back to default before
+       raising the signal.  Print the notice on stderr always.
 
-       * misc.c (map_gcry_rc): Removed here and chnaged all users.
+Fri Nov 12 20:33:19 CET 1999  Werner Koch  <wk@gnupg.de>
 
-       * getkey.c: Replaced check_pubkey_algo by openpgp_pk_test_algo.
-       * import.c (delete_inv_parts): Ditto.
-       * pkclist.c: Ditto.
-       * skclist.c: Ditto.
-       * pubkey-enc.c: Ditto.
+       * g10.c (make_username): Swapped the logic.
+       * keylist.c (public_key_list): Now takes a STRLIST as arg and moved
+       the creation ot this list to the caller, so that he can copy with
+       UTF-conversion of user IDs.  Changed all callers.
+       (secret_key_list): Likewise.
 
-       * g10.c (main): Replaced the function to diable PK algos.
+       * getkey.c (get_user_id_string_native): New and ...
+       * encode.c (write_pubkey_enc_from_list): ... use it here.
 
-       * g10.c (main): Replaced get_random_bits by gcry_random_bytes.
-       * seskey.c (encode_session_key): Likewise.
-       (make_session_key): Renamed randomize_buffer to gcry_randomize
-       and use the GCRY_xxx_RANDOM constants.
-       * cipher.c (write_header): Ditto.
-       * passphrase.c (hash_passphrase): Ditto.
-       * seckey-cert.c (protect_secret_key): Ditto.
+       * pubring.asc: Updated.
 
-       * getkey.c (find_by_name): Replaced rmd160_hash_buffer
-       by gcry_md_hash_buffer.
+       * packet.h (PKT_PHOTO_ID): New.
+       * parse-packet.c (parse_photo_id): New.
+       * build-packet.c (do_user_id: Handle photo IDs.
+       (build_packet): Change CTB for photo IDs
+       * free-packet.c (free_user_id): Release memory used for photo IDs
+       * sig-check.c (hash_uid_node): Handle photo IDs too.
+       * trustdb.c (print_uid_from_keyblock): Hash photo ID.
+       (make_uid_records): Ditto.
+       * getkey.c (find_by_name): Ditto.
        * keyedit.c (show_prefs): Ditto.
        * keylist.c (list_keyblock): Ditto.
-       * trustdb.c (print_uid_from_keyblock): Ditto.
-       (make_uid_records): Ditto.
 
-       * skclist.c (build_sk_list): Removed the test on faked RNGs.
-       (is_insecure): Removed.
-       * g10.c (--quick-random): Removed this option.
+Thu Oct 28 16:08:20 CEST 1999  Werner Koch  <wk@gnupg.de>
+
+       * keygen.c (ask_expire_interval): Print a warning for systems
+       with a signed 32 time_t if the exiration time is beyoind 2038.
+
+Fri Oct  8 20:40:50 CEST 1999  Werner Koch  <wk@gnupg.de>
 
-       * Replaced all PUBKEY_ALGO_xxx by GCRY_PK_xxxx.
+       * ringedit.c (enum_keyblocks): The last fix way really stupid;
+       reverted and set rt to Unknown.
 
-       * misc.c (pubkey_algo_npkey): New as a wrapper around the gcry fucntion.
-       (pubkey_algo_nskey): Ditto.
-       (pubkey_algo_nsig): Ditto.
-       (pubkey_algo_nenc): Ditto.
+Fri Oct  8 20:32:01 CEST 1999  Werner Koch  <wk@gnupg.de>
 
-Tue Oct 26 20:03:44 CEST 1999  Werner Koch  <wk@gnupg.de>
+       * ringedit.c (enum_keyblocks): Zero the entire kbpos out on open.
 
-       * Makefile.am (basicdefs.h): Added.
-       (install-data-local): Removed the handling for historic gpgm.
+       * g10.c (oEntropyDLL): Removed option.
+       (main): Made the warning on development versions more verbose.
 
-Tue Oct 26 14:10:21 CEST 1999  Werner Koch  <wk@gnupg.de>
+       * g10.c (oHonorHttpProxy): New option.
+       * hkp.c (hkp_ask_import,hkp_export): Implement this option.
+       * options.skel: Enable this option for new installations
 
-       * misc.c (openpgp_cipher_test_algo): New.
-       (openpgp_pk_test_algo): New.
-       (openpgp_md_test_algo): New.
+Mon Oct  4 21:23:04 CEST 1999  Werner Koch  <wk@gnupg.de>
 
-       * g10.c (build_list): Changed to use the new functions from libgcrypt.
+       * import.c (import_keys): Changed calling interface, adjusted caller.
+       (import): Moved printing of stats out ...
+       (print_stats): New. ... to here.
+       (import_keys_stream): Call stats print here.
+       (import_keys): Print stats as totals for all files.
 
-       * ringedit.c (enum_keyblocks): Set .rt to 0 on open.
+       * tdbio.h (DIRF_NEWKEYS): New
+       * tdbio.c (tdbio_dump_record): Print the new flag.
+       * trustdb.c (check_trust_record): New arg sigs_only.  Adapted all
+       callers.
+       (do_update_trust_record): Removed recheck arg and add a new sigs_only
+       do we can later improve on the performance.  Changed all callers too.
+       (check_trustdb): Evalutate the new flag and add a status output.
+       Do a check when the dir record has not been checked.
+       (build_cert_tree): Evaluate the new flag.
+       (check_trust): Ditto.  Do a trust_record check, when the dir record
+       is not marked as checked.
+       (mark_fresh_keys): New.
+       (clear_lid_table): New.
+       (sync_trustdb): New.
+       * import.c (import_keys): Call sync_trustdb() after processing.
+       (import_keys_stream): Ditto.
+       * tdbdump.c (import_ownertrust): Ditto.
+
+       * import.c (import_revoke_cert): Notify the trust DB.
+       (do_update_trust_record): Use |= to set the REVOKED bit and not &=;
+       shame on me for this bad copy+paste introduced bug.
+       (do_we_trust): Add trustmask to allow revoked key override to work.
+       Chnaged are to allow return of a mofified trustlevel. Adapted the
+       one caller.
+
+       * g10.c: New options --emulate-3des-s2k-bug
+       * passphrase.c (hash_passphrase): Implemented above.
+
+       * mainproc.c (proc_tree): Check for standalone signatures.
+       (do_check_sig): Print a notice for a standalone revocation
+       (check_sig_and_print): Do not print an error for unchecked standalone
+       revocations.
+
+Tue Sep 28 20:54:37 CEST 1999  Werner Koch  <wk@gnupg.de>
 
        * encode.c (encode_simple): Use new CTB when we don't have the
        length of the file.  This is somewhat strange as the comment above
        indicates that this part is actually fixed for PGP 5 - maybe I simply
        lost the source line, tsss.
 
-       * sign.c (clearsign_file): Avoid duplicated Entries in the "Hash:"
-       line.  Those headers are now only _not_ printed when there are
-       only old-style keys _and_ all hashs are MD5.
-
-       (clearsign_file): Use gcry_md_test_algo() and gcry_md_algo_name().
+       * armor.c (armor_filter): Set a flag if no OpenPGP data has been found.
+       * verify.c (verify_signatures): Add an error helptext.
 
-       * openfile.c (make_outfile_name): Use case-insenstive compare for
-       DOS systems.  Add ".pgp" to the list of know extensions.
-       (open_outfile): For DOS systems try to replace the suffix instead of
-       appending it.
-
-       * encr-data.c (decrypt_data): Reset error on a weak key.
-
-       * cipher.c: Replaced the cipher and digest functions by the gcry_ ones.
-       * seckey-cert.c: Ditto.
-       * seskey.c: Ditto.
-       * g10.c (print_mds): Replaced digst functions with the new gcry_ ones.
-       * keyid.c: Ditto.
-       * mainproc.c: Ditto.
-       * passphrase.c: Ditto.
-       * sig-check.c: Ditto.
-       * sign.c: Ditto.
-
-       * pkclist.c (do_edit_ownertrust): Made the answer string const.
-
-       * basicdefs.h: New.  Move some defs and decl to this header.
+Thu Sep 23 19:24:30 CEST 1999  Werner Koch  <wk@isil.d.shuttle.de>
 
        * openfile.c (open_outfile): Fixed the 8dot3 handling.
 
@@ -236,17 +715,33 @@ Tue Oct 26 14:10:21 CEST 1999  Werner Koch  <wk@gnupg.de>
        * trustdb.c (print_user_id,check_uidsigs): Ditto.
        * revoke.c (gen_revoke,ask_revoke_sig): Ditto.
 
-Sat Sep 18 12:16:08 CEST 1999  Werner Koch  <wk@isil.d.shuttle.de>
+Thu Sep 23 09:52:58 CEST 1999  Werner Koch  <wk@isil.d.shuttle.de>
 
-       * filter.h: Changed cipher handle types to the the GCRY_xxx ones.
-       replaces include cipher by system header include gcrypt.h.
-       * cipher.c: replaced the cipher functions by the gcry_ ones.
-       Ditto for the md functions.
+       * verify.c (print_file_status): New.
+       (verify_one_file): Moved status print to th new fnc. Add error status.
+       * status.c, status.h (STATUS_FILE_ERROR): New
 
-       * misc.c (map_gcry_rc): New.
+Wed Sep 22 10:14:17 CEST 1999  Werner Koch  <wk@isil.d.shuttle.de>
 
-Fri Sep 17 12:56:42 CEST 1999  Werner Koch  <wk@isil.d.shuttle.de>
+       * openfile.c (make_outfile_name): Use case-insenstive compare for
+       DOS systems.  Add ".pgp" to the list of know extensions.
+       (open_outfile): For DOS systems try to replace the suffiy instead of
+       appending it.
+
+       * status.c, status.h: Add STATUS_FILE_{START,DONE}.
+       * verify.c (verify_one_file): Emit these new stati.
 
+       * sign.c (clearsign_file): Avoid duplicated Entries in the "Hash:"
+       line.  Those headers are now only _not_ printed when there are
+       only old-style keys _and_ all hashs are MD5.
+
+Mon Sep 20 12:24:41 CEST 1999  Werner Koch  <wk@isil.d.shuttle.de>
+
+
+       * verify.c (verify_files, ferify_one_file): New.
+       * g10.c:  New command --verify-files
+
+Fri Sep 17 12:56:42 CEST 1999  Werner Koch  <wk@isil.d.shuttle.de>
 
        * g10.c: Add UK spelling as alias for armor options ;-)
 
@@ -256,16 +751,13 @@ Fri Sep 17 12:56:42 CEST 1999  Werner Koch  <wk@isil.d.shuttle.de>
 
 Wed Sep 15 16:22:17 CEST 1999  Werner Koch  <wk@isil.d.shuttle.de>
 
-
        * g10.c: New option --entropy-dll-name
 
 Mon Sep 13 10:51:29 CEST 1999  Werner Koch  <wk@isil.d.shuttle.de>
 
-
        * signal.c (got_fatal_signal): Print message using write(2) and
        only for development versions.
 
-
 Mon Sep  6 19:59:08 CEST 1999  Werner Koch  <wk@isil.d.shuttle.de>
 
        * tdbio.c (tdbio_set_dbname): Use mkdir macro
index 55d0ed2..6b95ac3 100644 (file)
@@ -6,10 +6,11 @@ OMIT_DEPENDENCIES = zlib.h zconf.h
 LDFLAGS = -static @LDFLAGS@ @DYNLINK_LDFLAGS@
 # we need to add libutil.la a second time because we have to resolve
 # gpg_log_ in some libjnlib modules. - very ugly - should be removed soon.
-needed_libs = ../util/libutil.la ../gcrypt/libgcrypt.la ../jnlib/libjnlib.la ../util/libutil.la
+needed_libs = ../util/libutil.la ../gcrypt/libgcrypt.la \
+             ../jnlib/libjnlib.la ../util/libutil.la
 
 #noinst_PROGRAMS = gpgd
-bin_PROGRAMS = gpg  kbxutil
+bin_PROGRAMS = gpg kbxutil
 
 common_source =  \
              build-packet.c    \
index 0661d76..819c951 100644 (file)
@@ -1,5 +1,5 @@
 /* armor.c - Armor flter
- *     Copyright (C) 1998, 1999 Free Software Foundation, Inc.
+ *     Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
 #include "status.h"
 #include "i18n.h"
 
+#ifdef HAVE_DOSISH_SYSTEM
+  #define LF "\r\n"
+#else
+  #define LF "\n"
+#endif
 
 #define MAX_LINELEN 20000
 
@@ -162,6 +167,7 @@ is_armored( const byte *buf )
     switch( pkttype ) {
       case PKT_MARKER:
       case PKT_SYMKEY_ENC:
+      case PKT_ONEPASS_SIG:
       case PKT_PUBLIC_KEY:
       case PKT_SECRET_KEY:
       case PKT_PUBKEY_ENC:
@@ -485,13 +491,26 @@ fake_packet( armor_filter_context_t *afx, IOBUF a,
        if( !maxlen )
            afx->truncated++;
        if( !afx->not_dash_escaped ) {
+           int crlf;
+           p = afx->buffer;
+           n = afx->buffer_len;
+           crlf = n > 1 && p[n-2] == '\r' && p[n-1]=='\n';
+
            /* PGP2 does not treat a tab as white space character */
-           afx->buffer_len =
-                   trim_trailing_chars( afx->buffer, afx->buffer_len,
+           afx->buffer_len = trim_trailing_chars( p, n,
                                         afx->pgp2mode ? " \r\n" : " \t\r\n");
            /* the buffer is always allocated with enough space to append
-            * a CR, LF, Nul */
-           afx->buffer[afx->buffer_len++] = '\r';
+            * the removed [CR], LF and a Nul
+            * The reason for this complicated procedure is to keep at least
+            * the original tupe of lineending - handling of the removed
+            * trailing spaces seems to be impossible in our method
+            * of faking a packet; either we have to use a temporary file
+            * or calculate the hash here in this module and somehow find
+            * a way to send the hash down the processing line (well, a special
+            * faked packet could do the job).
+            */
+           if( crlf )
+               afx->buffer[afx->buffer_len++] = '\r';
            afx->buffer[afx->buffer_len++] = '\n';
            afx->buffer[afx->buffer_len] = 0;
        }
@@ -819,7 +838,8 @@ armor_filter( void *opaque, int control,
                hashes &= 1|2|4|8;
                if( !hashes ) {
                    hashes |= 4;  /* default to MD 5 */
-                   afx->pgp2mode = 1;
+                   if( opt.pgp2_workarounds )
+                       afx->pgp2mode = 1;
                }
                n=0;
                do {
@@ -827,7 +847,7 @@ armor_filter( void *opaque, int control,
                    buf[n++] = 0x90; /* old format, type 4, 1 length byte */
                    buf[n++] = 13;   /* length */
                    buf[n++] = 3;    /* version */
-                   buf[n++] = 0x01; /* sigclass 0x01 (canonical text mode)*/
+                   buf[n++] = afx->not_dash_escaped? 0:1; /* sigclass */
                    if( hashes & 1 ) {
                        hashes &= ~1;
                        buf[n++] = GCRY_MD_RMD160;
@@ -874,7 +894,7 @@ armor_filter( void *opaque, int control,
       #endif
        *ret_len = n;
     }
-    else if( control == IOBUFCTRL_FLUSH ) {
+    else if( control == IOBUFCTRL_FLUSH && !afx->cancel ) {
        if( !afx->status ) { /* write the header line */
            const char *s;
 
@@ -882,10 +902,10 @@ armor_filter( void *opaque, int control,
                log_bug("afx->what=%d", afx->what);
            iobuf_writestr(a, "-----");
            iobuf_writestr(a, head_strings[afx->what] );
-           iobuf_writestr(a, "-----\n");
+           iobuf_writestr(a, "-----" LF );
            if( !opt.no_version )
                iobuf_writestr(a, "Version: GnuPG v"  VERSION " ("
-                                             PRINTABLE_OS_NAME ")\n");
+                                             PRINTABLE_OS_NAME ")" LF );
 
            /* write the comment string or a default one */
            s = opt.comment_string ? opt.comment_string
@@ -902,16 +922,17 @@ armor_filter( void *opaque, int control,
                    else
                        iobuf_put(a, *s );
                }
-               iobuf_put(a, '\n' );
+               iobuf_writestr(a, LF );
            }
 
            if( afx->hdrlines )
                iobuf_writestr(a, afx->hdrlines);
-           iobuf_put(a, '\n');
+           iobuf_writestr(a, LF );
            afx->status++;
            afx->idx = 0;
            afx->idx2 = 0;
            afx->crc = CRCINIT;
+
        }
        crc = afx->crc;
        idx = afx->idx;
@@ -936,7 +957,7 @@ armor_filter( void *opaque, int control,
                c = bintoasc[radbuf[2]&077];
                iobuf_put(a, c);
                if( ++idx2 >= (64/4) ) { /* pgp doesn't like 72 here */
-                   iobuf_put(a, '\n');
+                   iobuf_writestr(a, LF );
                    idx2=0;
                }
            }
@@ -951,8 +972,13 @@ armor_filter( void *opaque, int control,
        if( !is_initialized )
            initialize();
     }
+    else if( control == IOBUFCTRL_CANCEL ) {
+       afx->cancel = 1;
+    }
     else if( control == IOBUFCTRL_FREE ) {
-       if( afx->status ) { /* pad, write cecksum, and bottom line */
+       if( afx->cancel )
+           ;
+       else if( afx->status ) { /* pad, write cecksum, and bottom line */
            crc = afx->crc;
            idx = afx->idx;
            idx2 = afx->idx2;
@@ -975,13 +1001,13 @@ armor_filter( void *opaque, int control,
                    iobuf_put(a, '=');
                }
                if( ++idx2 >= (64/4) ) { /* pgp doesn't like 72 here */
-                   iobuf_put(a, '\n');
+                   iobuf_writestr(a, LF );
                    idx2=0;
                }
            }
            /* may need a linefeed */
            if( idx2 )
-               iobuf_put(a, '\n');
+               iobuf_writestr(a, LF );
            /* write the CRC */
            iobuf_put(a, '=');
            radbuf[0] = crc >>16;
@@ -995,16 +1021,17 @@ armor_filter( void *opaque, int control,
            iobuf_put(a, c);
            c = bintoasc[radbuf[2]&077];
            iobuf_put(a, c);
-           iobuf_put(a, '\n');
+           iobuf_writestr(a, LF );
            /* and the the trailer */
            if( afx->what >= DIM(tail_strings) )
                log_bug("afx->what=%d", afx->what);
            iobuf_writestr(a, "-----");
            iobuf_writestr(a, tail_strings[afx->what] );
-           iobuf_writestr(a, "-----\n");
+           iobuf_writestr(a, "-----" LF );
        }
        else if( !afx->any_data && !afx->inp_bypass ) {
            log_error(_("no valid OpenPGP data found.\n"));
+           afx->no_openpgp_data = 1;
            write_status_text( STATUS_NODATA, "1" );
        }
        if( afx->truncated )
index 84912ac..8781589 100644 (file)
@@ -1,5 +1,5 @@
 /* build-packet.c - assemble packets and write them
- *     Copyright (C) 1998 Free Software Foundation, Inc.
+ *     Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
 #include <string.h>
 #include <assert.h>
 
+#include <gcrypt.h>
 #include "packet.h"
 #include "errors.h"
 #include "iobuf.h"
 #include "util.h"
-#include <gcrypt.h>
 #include "options.h"
 #include "main.h"
 
@@ -43,6 +43,7 @@ static u32 calc_plaintext( PKT_plaintext *pt );
 static int do_plaintext( IOBUF out, int ctb, PKT_plaintext *pt );
 static int do_encrypted( IOBUF out, int ctb, PKT_encrypted *ed );
 static int do_encrypted_mdc( IOBUF out, int ctb, PKT_encrypted *ed );
+static int do_mdc( IOBUF out, PKT_mdc *mdc );
 static int do_compressed( IOBUF out, int ctb, PKT_compressed *cd );
 static int do_signature( IOBUF out, int ctb, PKT_signature *sig );
 static int do_onepass_sig( IOBUF out, int ctb, PKT_onepass_sig *ops );
@@ -66,25 +67,31 @@ int
 build_packet( IOBUF out, PACKET *pkt )
 {
     int new_ctb=0, rc=0, ctb;
+    int pkttype;
 
     if( DBG_PACKET )
        log_debug("build_packet() type=%d\n", pkt->pkttype );
     assert( pkt->pkt.generic );
 
-    switch( pkt->pkttype ) {
-      case PKT_OLD_COMMENT: pkt->pkttype = PKT_COMMENT; break;
+    switch( (pkttype = pkt->pkttype) ) {
+      case PKT_OLD_COMMENT: pkttype = pkt->pkttype = PKT_COMMENT; break;
       case PKT_PLAINTEXT: new_ctb = pkt->pkt.plaintext->new_ctb; break;
       case PKT_ENCRYPTED:
       case PKT_ENCRYPTED_MDC: new_ctb = pkt->pkt.encrypted->new_ctb; break;
       case PKT_COMPRESSED:new_ctb = pkt->pkt.compressed->new_ctb; break;
+      case PKT_USER_ID:
+           if( pkt->pkt.user_id->photo )
+               pkttype = PKT_PHOTO_ID;
+           break;
       default: break;
     }
 
-    if( new_ctb || pkt->pkttype > 15 ) /* new format */
-       ctb = 0xc0 | (pkt->pkttype & 0x3f);
+    if( new_ctb || pkttype > 15 ) /* new format */
+       ctb = 0xc0 | (pkttype & 0x3f);
     else
-       ctb = 0x80 | ((pkt->pkttype & 15)<<2);
-    switch( pkt->pkttype ) {
+       ctb = 0x80 | ((pkttype & 15)<<2);
+    switch( pkttype ) {
+      case PKT_PHOTO_ID:
       case PKT_USER_ID:
        rc = do_user_id( out, ctb, pkt->pkt.user_id );
        break;
@@ -114,6 +121,9 @@ build_packet( IOBUF out, PACKET *pkt )
       case PKT_ENCRYPTED_MDC:
        rc = do_encrypted_mdc( out, ctb, pkt->pkt.encrypted );
        break;
+      case PKT_MDC:
+       rc = do_mdc( out, pkt->pkt.mdc );
+       break;
       case PKT_COMPRESSED:
        rc = do_compressed( out, ctb, pkt->pkt.compressed );
        break;
@@ -148,6 +158,7 @@ calc_packet_length( PACKET *pkt )
        n = calc_plaintext( pkt->pkt.plaintext );
        new_ctb = pkt->pkt.plaintext->new_ctb;
        break;
+      case PKT_PHOTO_ID:
       case PKT_USER_ID:
       case PKT_COMMENT:
       case PKT_PUBLIC_KEY:
@@ -172,11 +183,11 @@ static void
 write_fake_data( IOBUF out, MPI a )
 {
     if( a ) {
-       size_t i;
+       int i;
        void *p;
 
-       p = gcry_mpi_get_opaque( a, &i );
-       iobuf_write( out, p, (i+7)/8 );
+       p = mpi_get_opaque( a, &i );
+       iobuf_write( out, p, i );
     }
 }
 
@@ -195,11 +206,20 @@ do_comment( IOBUF out, int ctb, PKT_comment *rem )
 static int
 do_user_id( IOBUF out, int ctb, PKT_user_id *uid )
 {
-    write_header(out, ctb, uid->len);
-    uid->stored_at = iobuf_get_temp_length ( out ); /* what a hack ... */
-       /* ... and it does only work when used with a temp iobuf */
-    if( iobuf_write( out, uid->name, uid->len ) )
-       return GPGERR_WRITE_FILE;
+    if( uid->photo ) {
+       write_header(out, ctb, uid->photolen);
+       uid->stored_at = iobuf_get_temp_length ( out ); /* what a hack ... */
+                 /* ... and it does only work when used with a temp iobuf */
+       if( iobuf_write( out, uid->photo, uid->photolen ) )
+           return GPGERR_WRITE_FILE;
+    }
+    else {
+       write_header(out, ctb, uid->len);
+       uid->stored_at = iobuf_get_temp_length ( out ); /* what a hack ... */
+                 /* ... and it does only work when used with a temp iobuf */
+       if( iobuf_write( out, uid->name, uid->len ) )
+           return GPGERR_WRITE_FILE;
+    }
     return 0;
 }
 
@@ -358,19 +378,30 @@ do_secret_key( IOBUF out, int ctb, PKT_secret_key *sk )
        else {
            iobuf_put(a, 0xff );
            iobuf_put(a, sk->protect.algo );
-           iobuf_put(a, sk->protect.s2k.mode );
-           iobuf_put(a, sk->protect.s2k.hash_algo );
+           if( sk->protect.s2k.mode >= 1000 ) {
+               iobuf_put(a, 101 );
+               iobuf_put(a, sk->protect.s2k.hash_algo );
+               iobuf_write(a, "GNU", 3 );
+               iobuf_put(a, sk->protect.s2k.mode - 1000 );
+           }
+           else {
+               iobuf_put(a, sk->protect.s2k.mode );
+               iobuf_put(a, sk->protect.s2k.hash_algo );
+           }
            if( sk->protect.s2k.mode == 1
                || sk->protect.s2k.mode == 3 )
                iobuf_write(a, sk->protect.s2k.salt, 8 );
            if( sk->protect.s2k.mode == 3 )
                iobuf_put(a, sk->protect.s2k.count );
-           iobuf_write(a, sk->protect.iv, sk->protect.ivlen );
+           if( sk->protect.s2k.mode != 1001 )
+               iobuf_write(a, sk->protect.iv, sk->protect.ivlen );
        }
     }
     else
        iobuf_put(a, 0 );
-    if( sk->is_protected && sk->version >= 4 ) {
+    if( sk->protect.s2k.mode == 1001 )
+       ;
+    else if( sk->is_protected && sk->version >= 4 ) {
        byte *p;
        size_t n;
        assert( gcry_mpi_get_flag( sk->skey[i], GCRYMPI_FLAG_OPAQUE ) );
@@ -379,7 +410,7 @@ do_secret_key( IOBUF out, int ctb, PKT_secret_key *sk )
     }
     else {
        for(   ; i < nskey; i++ )
-           mpi_write_opaque(a, sk->skey[i] );
+           mpi_write(a, sk->skey[i] );
        write_16(a, sk->csum );
     }
 
@@ -527,13 +558,24 @@ do_encrypted_mdc( IOBUF out, int ctb, PKT_encrypted *ed )
     n = ed->len ? (ed->len + 10) : 0;
     write_header(out, ctb, n );
     iobuf_put(out, 1 );  /* version */
-    iobuf_put(out, ed->mdc_method );
 
     /* This is all. The caller has to write the real data */
 
     return rc;
 }
 
+
+static int
+do_mdc( IOBUF out, PKT_mdc *mdc )
+{
+    /* This packet requires a fixed header encoding */
+    iobuf_put( out, 0xd3 ); /* packet ID and 1 byte length */
+    iobuf_put( out, 0x14 ); /* length = 20 */
+    if( iobuf_write( out, mdc->hash, sizeof(mdc->hash) ) )
+       return GPGERR_WRITE_FILE;
+    return 0;
+}
+
 static int
 do_compressed( IOBUF out, int ctb, PKT_compressed *cd )
 {
@@ -623,7 +665,6 @@ void
 build_sig_subpkt( PKT_signature *sig, sigsubpkttype_t type,
                  const byte *buffer, size_t buflen )
 {
-
     byte *data;
     size_t hlen, dlen, nlen;
     int found=0;
@@ -659,6 +700,7 @@ build_sig_subpkt( PKT_signature *sig, sigsubpkttype_t type,
       case SIGSUBPKT_KEY_EXPIRE:
       case SIGSUBPKT_NOTATION:
       case SIGSUBPKT_POLICY:
+      case SIGSUBPKT_REVOC_REASON:
               hashed = 1; break;
       default: hashed = 0; break;
     }
index 8fc0d38..cad6ff6 100644 (file)
@@ -1,5 +1,5 @@
 /* cipher.c - En-/De-ciphering filter
- *     Copyright (C) 1998,1999 Free Software Foundation, Inc.
+ *     Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
@@ -33,6 +33,7 @@
 #include "packet.h"
 #include "options.h"
 #include "main.h"
+#include "status.h"
 
 
 #define MIN_PARTIAL_SIZE 512
@@ -44,10 +45,18 @@ write_header( cipher_filter_context_t *cfx, IOBUF a )
     PACKET pkt;
     PKT_encrypted ed;
     byte temp[18];
-    int blocksize;
-    unsigned nprefix;
-    int use_mdc = opt.force_mdc;
+    unsigned int blocksize;
+    unsigned int nprefix;
     int rc;
+    int use_mdc = opt.force_mdc;
+
+    blocksize = gcry_cipher_get_algo_blklen( cfx->dek->algo );
+    if( blocksize < 8 || blocksize > 16 )
+       log_fatal("unsupported blocksize %u\n", blocksize );
+    if( blocksize != 8 )
+       use_mdc = 1;  /* enable it for all modern ciphers */
+    if( opt.rfc2440 )
+       use_mdc = 0;  /* override - rfc2440 does not know about MDC */
 
     memset( &ed, 0, sizeof ed );
     ed.len = cfx->datalen;
@@ -55,18 +64,16 @@ write_header( cipher_filter_context_t *cfx, IOBUF a )
     if( use_mdc ) {
        ed.mdc_method = GCRY_MD_SHA1;
        cfx->mdc_hash = gcry_md_open( GCRY_MD_SHA1, 0 );
-       /*should we check the function works, or is it better to provide
-         a flag which makes the function die itself ?? FIXME */
-       /*md_start_debug( cfx->mdc_hash, "mdccreat" );*/
+       if( !cfx->mdc_hash )
+           BUG();
+       if ( DBG_HASHING )
+           gcry_md_start_debug( cfx->mdc_hash, "creatmdc" );
     }
     init_packet( &pkt );
     pkt.pkttype = use_mdc? PKT_ENCRYPTED_MDC : PKT_ENCRYPTED;
     pkt.pkt.encrypted = &ed;
     if( build_packet( a, &pkt ))
        log_bug("build_packet(ENCR_DATA) failed\n");
-    blocksize = gcry_cipher_get_algo_blklen( cfx->dek->algo );
-    if( blocksize < 8 || blocksize > 16 )
-       log_fatal("unsupported blocksize %d\n", blocksize );
     nprefix = blocksize;
     gcry_randomize( temp, nprefix, GCRY_STRONG_RANDOM );
     temp[nprefix] = temp[nprefix-2];
@@ -75,7 +82,7 @@ write_header( cipher_filter_context_t *cfx, IOBUF a )
     if( !(cfx->cipher_hd = gcry_cipher_open( cfx->dek->algo,
                                       GCRY_CIPHER_MODE_CFB,
                                       GCRY_CIPHER_SECURE
-                                      | (cfx->dek->algo >= 100 ?
+                                      | ((use_mdc || cfx->dek->algo >= 100) ?
                                             0 : GCRY_CIPHER_ENABLE_SYNC)))
                                     ) {
        /* we should never get an error here cause we already checked, that
@@ -83,6 +90,7 @@ write_header( cipher_filter_context_t *cfx, IOBUF a )
        BUG();
     }
 
+
 /*   log_hexdump( "thekey", cfx->dek->key, cfx->dek->keylen );*/
     rc = gcry_cipher_setkey( cfx->cipher_hd, cfx->dek->key, cfx->dek->keylen );
     if( !rc )
@@ -99,6 +107,7 @@ write_header( cipher_filter_context_t *cfx, IOBUF a )
        log_fatal("encrypt failed: %s\n", gcry_strerror(rc) );
     iobuf_write(a, temp, nprefix+2);
     cfx->header=1;
+
 }
 
 
@@ -120,6 +129,7 @@ cipher_filter( void *opaque, int control,
     else if( control == IOBUFCTRL_FLUSH ) { /* encrypt */
        assert(a);
        if( !cfx->header ) {
+           write_status( STATUS_BEGIN_ENCRYPTION );
            write_header( cfx, a );
        }
        if( cfx->mdc_hash )
@@ -134,15 +144,26 @@ cipher_filter( void *opaque, int control,
        if( cfx->mdc_hash ) {
            byte *hash;
            int hashlen = gcry_md_get_algo_dlen( gcry_md_get_algo( cfx->mdc_hash ) );
+           byte temp[22];
+
+           assert( hashlen == 20 );
+           /* we must hash the prefix of the MDC packet here */
+           temp[0] = 0xd3;
+           temp[1] = 0x14;
+           gcry_md_putc( cfx->mdc_hash, temp[0] );
+           gcry_md_putc( cfx->mdc_hash, temp[1] );
+
            hash = gcry_md_read( cfx->mdc_hash, 0 );
-           rc = gcry_cipher_encrypt( cfx->cipher_hd, hash, hashlen, NULL, 0 );
+           memcpy(temp+2, hash, 20);
+           rc = gcry_cipher_encrypt( cfx->cipher_hd, temp, 22, NULL, 0 );
            if( rc )
                log_fatal("encrypt failed: %s\n", gcry_strerror(rc) );
-           if( iobuf_write( a, hash, hashlen ) )
-               rc = GPGERR_WRITE_FILE;
            gcry_md_close( cfx->mdc_hash ); cfx->mdc_hash = NULL;
+           if( iobuf_write( a, temp, 22 ) )
+               log_error("writing MDC packet failed\n" );
        }
        gcry_cipher_close(cfx->cipher_hd);
+       write_status( STATUS_END_ENCRYPTION );
     }
     else if( control == IOBUFCTRL_DESC ) {
        *(char**)buf = "cipher_filter";
index fe80a1c..f0d8849 100644 (file)
@@ -1,5 +1,5 @@
 /* comment.c - write comment stuff
- *     Copyright (C) 1998 Free Software Foundation, Inc.
+ *     Copyright (C) 1998, 2000 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
index 48335ba..2666e90 100644 (file)
@@ -1,5 +1,5 @@
 /* compress.c - compress filter
- *     Copyright (C) 1998 Free Software Foundation, Inc.
+ *     Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
@@ -27,8 +27,8 @@
 #include <errno.h>
 #include <zlib.h>
 
-#include "util.h"
 #include <gcrypt.h>
+#include "util.h"
 #include "packet.h"
 #include "filter.h"
 #include "options.h"
index 1c0a15b..937961e 100644 (file)
@@ -1,5 +1,5 @@
 /* dearmor.c - Armor utility
- *     Copyright (C) 1998 Free Software Foundation, Inc.
+ *     Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
@@ -25,9 +25,9 @@
 #include <errno.h>
 #include <assert.h>
 
+#include <gcrypt.h>
 #include "errors.h"
 #include "iobuf.h"
-#include <gcrypt.h>
 #include "util.h"
 #include "filter.h"
 #include "packet.h"
index e9f1d2b..9812756 100644 (file)
@@ -1,5 +1,5 @@
 /* decrypt.c - verify signed data
- *     Copyright (C) 1998 Free Software Foundation, Inc.
+ *     Copyright (C) 1998, 2000 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
 #include <errno.h>
 #include <assert.h>
 
+#include <gcrypt.h>
 #include "options.h"
 #include "packet.h"
 #include "errors.h"
 #include "iobuf.h"
 #include "keydb.h"
-#include <gcrypt.h>
 #include "util.h"
 #include "main.h"
 #include "i18n.h"
index c452567..0c64d41 100644 (file)
@@ -1,5 +1,5 @@
 /* delkey.c - delete keys
- *     Copyright (C) 1998 Free Software Foundation, Inc.
+ *     Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
@@ -62,6 +62,7 @@ delete_key( const char *username, int secret )
               : find_keyblock_byname( &kbpos, username );
     if( rc ) {
        log_error(_("%s: user not found\n"), username );
+       write_status_text( STATUS_DELETE_PROBLEM, "1" );
        goto leave;
     }
 
@@ -93,10 +94,12 @@ delete_key( const char *username, int secret )
            "there is a secret key for this public key!\n"));
            log_info(_(
            "use option \"--delete-secret-key\" to delete it first.\n"));
+           write_status_text( STATUS_DELETE_PROBLEM, "2" );
            rc = -1;
        }
-       else if( rc != GPGERR_NO_SECKEY )
+       else if( rc != GPGERR_NO_SECKEY ) {
            log_error("%s: get secret key: %s\n", username, gpg_errstr(rc) );
+       }
        else
            rc = 0;
     }
index ed4b1df..6195b53 100644 (file)
@@ -1,5 +1,5 @@
 /* encode.c - encode data
- *     Copyright (C) 1998 Free Software Foundation, Inc.
+ *     Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
@@ -41,6 +41,7 @@
 static int encode_simple( const char *filename, int mode );
 static int write_pubkey_enc_from_list( PK_LIST pk_list, DEK *dek, IOBUF out );
 
+
 /****************
  * Emulate our old PK interface here - sometime in the future we might
  * change the internal design to directly fit to libgcrypt.
@@ -162,7 +163,7 @@ encode_simple( const char *filename, int mode )
     }
 
     if( (rc = open_outfile( filename, opt.armor? 1:0, &out )) ) {
-       iobuf_close(inp);
+       iobuf_cancel(inp);
        gcry_free(cfx.dek);
        gcry_free(s2k);
        return rc;
@@ -510,7 +511,7 @@ write_pubkey_enc_from_list( PK_LIST pk_list, DEK *dek, IOBUF out )
         * number of bits we have to use.  We then encode the session
         * key in some way and we get it back in the big intger value
         * FRAME.  Then we use FRAME, the public key PK->PKEY and the
-        * algorithm number PK->PUBKEY_ALGO and pass it to pk_encrypt
+        * algorithm number PK->PUBKEY_ALGO and pass it to pubkey_encrypt
         * which returns the encrypted value in the array ENC->DATA.
         * This array has a size which depends on the used algorithm
         * (e.g. 2 for ElGamal).  We don't need frame anymore because we
@@ -525,7 +526,7 @@ write_pubkey_enc_from_list( PK_LIST pk_list, DEK *dek, IOBUF out )
            log_error("pubkey_encrypt failed: %s\n", gpg_errstr(rc) );
        else {
            if( opt.verbose ) {
-               char *ustr = get_user_id_string( enc->keyid );
+               char *ustr = get_user_id_string_native( enc->keyid );
                log_info(_("%s/%s encrypted for: %s\n"),
                    gcry_pk_algo_name(enc->pubkey_algo),
                    gcry_cipher_algo_name(dek->algo), ustr );
index 7c90829..17d43e9 100644 (file)
@@ -1,5 +1,5 @@
 /* encr-data.c -  process an encrypted data packet
- *     Copyright (C) 1998, 1999 Free Software Foundation, Inc.
+ *     Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
@@ -23,6 +23,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <assert.h>
+
 #include <gcrypt.h>
 #include "util.h"
 #include "packet.h"
@@ -30,9 +31,9 @@
 #include "i18n.h"
 
 
-static int decode_filter( void *opaque, int control, IOBUF a,
-                                       byte *buf, size_t *ret_len);
 static int mdc_decode_filter( void *opaque, int control, IOBUF a,
+                                             byte *buf, size_t *ret_len);
+static int decode_filter( void *opaque, int control, IOBUF a,
                                        byte *buf, size_t *ret_len);
 
 typedef struct {
@@ -54,8 +55,8 @@ decrypt_data( void *procctx, PKT_encrypted *ed, DEK *dek )
     byte *p;
     int rc=0, c, i;
     byte temp[32];
-    int blocksize;
-    unsigned nprefix;
+    unsigned int blocksize;
+    unsigned int nprefix;
 
     memset( &dfx, 0, sizeof dfx );
     if( gcry_cipher_test_algo( dek->algo ) ) {
@@ -68,7 +69,7 @@ decrypt_data( void *procctx, PKT_encrypted *ed, DEK *dek )
        log_info(_("%s encrypted data\n"), gcry_cipher_algo_name( dek->algo ) );
 
     blocksize = gcry_cipher_get_algo_blklen( dek->algo );
-    if( blocksize < 1 || blocksize > 16 )
+    if( !blocksize || blocksize > 16 )
        log_fatal("unsupported blocksize %u\n", blocksize );
     nprefix = blocksize;
     if( ed->len && ed->len < (nprefix+2) )
@@ -76,13 +77,13 @@ decrypt_data( void *procctx, PKT_encrypted *ed, DEK *dek )
 
     if( ed->mdc_method ) {
        dfx.mdc_hash = gcry_md_open( ed->mdc_method, 0 );
-       if( !dfx.mdc_hash )
-           BUG();
+       if ( DBG_HASHING )
+           gcry_md_start_debug(dfx.mdc_hash, "checkmdc");
     }
     if( !(dfx.cipher_hd = gcry_cipher_open( dek->algo,
                                      GCRY_CIPHER_MODE_CFB,
                                      GCRY_CIPHER_SECURE
-                                     | (dek->algo >= 100 ?
+                                     | ((ed->mdc_method || dek->algo >= 100)?
                                           0 : GCRY_CIPHER_ENABLE_SYNC) ))
                                    ) {
        /* we should never get an error here cause we already checked, that
@@ -122,8 +123,6 @@ decrypt_data( void *procctx, PKT_encrypted *ed, DEK *dek )
                temp[i] = c;
     }
     gcry_cipher_decrypt( dfx.cipher_hd, temp, nprefix+2, NULL, 0 );
-    if( dfx.mdc_hash )
-       gcry_md_write( dfx.mdc_hash, temp, nprefix+2 );
     gcry_cipher_sync( dfx.cipher_hd );
     p = temp;
 /* log_hexdump( "prefix", temp, nprefix+2 ); */
@@ -131,22 +130,30 @@ decrypt_data( void *procctx, PKT_encrypted *ed, DEK *dek )
        rc = GPGERR_BAD_KEY;
        goto leave;
     }
+
+    if( dfx.mdc_hash )
+       gcry_md_write( dfx.mdc_hash, temp, nprefix+2 );
+
     if( ed->mdc_method )
        iobuf_push_filter( ed->buf, mdc_decode_filter, &dfx );
     else
        iobuf_push_filter( ed->buf, decode_filter, &dfx );
-    proc_packets( procctx, ed->buf);
+
+    proc_packets( procctx, ed->buf );
     ed->buf = NULL;
     if( ed->mdc_method && dfx.eof_seen == 2 )
        rc = GPGERR_INVALID_PACKET;
     else if( ed->mdc_method ) { /* check the mdc */
        int datalen = gcry_md_get_algo_dlen( ed->mdc_method );
+
+       gcry_cipher_decrypt( dfx.cipher_hd, dfx.defer, 20, NULL, 0);
        if( datalen != 20
            || memcmp(gcry_md_read( dfx.mdc_hash, 0 ), dfx.defer, datalen) )
            rc = GPGERR_BAD_SIGN;
-       log_hexdump("MDC calculated:", gcry_md_read( dfx.mdc_hash, 0), datalen);
-       log_hexdump("MDC message   :", dfx.defer, 20);
+       /*log_hexdump("MDC calculated:", md_read( dfx.mdc_hash, 0), datalen);*/
+       /*log_hexdump("MDC message   :", dfx.defer, 20);*/
     }
+
   leave:
     gcry_cipher_close(dfx.cipher_hd);
     gcry_md_close( dfx.mdc_hash );
@@ -154,6 +161,7 @@ decrypt_data( void *procctx, PKT_encrypted *ed, DEK *dek )
 }
 
 
+
 /* I think we should merge this with cipher_filter */
 static int
 mdc_decode_filter( void *opaque, int control, IOBUF a,
@@ -180,11 +188,14 @@ mdc_decode_filter( void *opaque, int control, IOBUF a,
        }
        if( n == 40 ) {
            /* we have enough stuff - flush the deferred stuff */
-           /* (we have asserted that the buffer is large enough */
-           if( !dfx->defer_filled ) /* the first time */
+           /* (we have asserted that the buffer is large enough) */
+           if( !dfx->defer_filled ) /* the first time */
                memcpy(buf, buf+20, 20 );
-           else
+               n = 20;
+           }
+           else {
                memcpy(buf, dfx->defer, 20 );
+           }
            /* now fill up */
            for(; n < size; n++ ) {
                if( (c = iobuf_get(a)) == -1 )
@@ -198,7 +209,7 @@ mdc_decode_filter( void *opaque, int control, IOBUF a,
            dfx->defer_filled = 1;
        }
        else if( !dfx->defer_filled ) { /* eof seen buf empty defer */
-           /* this is very bad because there is an incomplete hash */
+           /* this is bad because there is an incomplete hash */
            n -= 20;
            memcpy(buf, buf+20, n );
            dfx->eof_seen = 2; /* eof with incomplete hash */
@@ -238,7 +249,7 @@ decode_filter( void *opaque, int control, IOBUF a, byte *buf, size_t *ret_len)
        n = iobuf_read( a, buf, size );
        if( n == -1 ) n = 0;
        if( n )
-           gcry_cipher_decrypt( fc->cipher_hd, buf, n, NULL, 0);
+           gcry_cipher_decrypt( fc->cipher_hd, buf, n, NULL, 0 );
        else
            rc = -1; /* eof */
        *ret_len = n;
index df81bab..2de9f91 100644 (file)
@@ -1,5 +1,5 @@
 /* export.c
- *     Copyright (C) 1998 Free Software Foundation, Inc.
+ *     Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
 #include <errno.h>
 #include <assert.h>
 
+#include <gcrypt.h>
 #include "options.h"
 #include "packet.h"
 #include "errors.h"
 #include "keydb.h"
-#include <gcrypt.h>
 #include "util.h"
 #include "main.h"
 #include "i18n.h"
@@ -71,6 +71,12 @@ export_seckeys( STRLIST users )
     return do_export( users, 1, 0 );
 }
 
+int
+export_secsubkeys( STRLIST users )
+{
+    return do_export( users, 2, 0 );
+}
+
 static int
 do_export( STRLIST users, int secret, int onlyrfc )
 {
@@ -168,6 +174,16 @@ do_export_stream( IOBUF out, STRLIST users, int secret, int onlyrfc, int *any )
            }
        }
 
+       /* we can't apply GNU mode 1001 on an unprotected key */
+       if( secret == 2
+           && (node = find_kbnode( keyblock, PKT_SECRET_KEY ))
+           && !node->pkt->pkt.secret_key->is_protected )
+       {
+           log_info(_("key %08lX: not protected - skipped\n"),
+                 (ulong)keyid_from_sk( node->pkt->pkt.secret_key, NULL) );
+           continue;
+       }
+
        /* and write it */
        for( kbctx=NULL; (node = walk_kbnode( keyblock, &kbctx, 0 )); ) {
            /* don't export any comment packets but those in the
@@ -183,7 +199,20 @@ do_export_stream( IOBUF out, STRLIST users, int secret, int onlyrfc, int *any )
                    continue; /* not exportable */
            }
 
-           if( (rc = build_packet( out, node->pkt )) ) {
+           if( secret == 2 && node->pkt->pkttype == PKT_SECRET_KEY ) {
+               /* we don't want to export the secret parts of the
+                * primary key, this is done by using GNU protection mode 1001
+                */
+               int save_mode = node->pkt->pkt.secret_key->protect.s2k.mode;
+               node->pkt->pkt.secret_key->protect.s2k.mode = 1001;
+               rc = build_packet( out, node->pkt );
+               node->pkt->pkt.secret_key->protect.s2k.mode = save_mode;
+           }
+           else {
+               rc = build_packet( out, node->pkt );
+           }
+
+           if( rc ) {
                log_error("build_packet(%d) failed: %s\n",
                            node->pkt->pkttype, gpg_errstr(rc) );
                rc = GPGERR_WRITE_FILE;
index 389026d..a29d2aa 100644 (file)
@@ -1,5 +1,5 @@
 /* filter.h
- *     Copyright (C) 1998 Free Software Foundation, Inc.
+ *     Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
@@ -26,7 +26,6 @@
 #include "iobuf.h"
 
 
-
 typedef struct {
     GCRY_MD_HD md;     /* catch all */
     GCRY_MD_HD md2;    /* if we want to calculate an alternate hash */
@@ -39,6 +38,9 @@ typedef struct {
     int only_keyblocks;     /* skip all headers but ".... key block" */
     const char *hdrlines;   /* write these headerlines */
 
+    /* these fileds must be initialized to zero */
+    int no_openpgp_data;    /* output flag: "No valid OpenPGP data found" */
+
     /* the following fields must be initialized to zero */
     int inp_checked;       /* set if the input has been checked */
     int inp_bypass;        /* set if the input is not armored */
@@ -60,6 +62,7 @@ typedef struct {
     u32 crc;
 
     int status;            /* an internal state flag */
+    int cancel;
     int any_data;          /* any valid armored data seen */
     int pending_lf;        /* used together with faked */
 } armor_filter_context_t;
@@ -83,6 +86,8 @@ typedef struct {
     GCRY_CIPHER_HD cipher_hd;
     int header;
     GCRY_MD_HD mdc_hash;
+    byte enchash[20];
+    int create_mdc; /* flag will be set by the cipher filter */
 } cipher_filter_context_t;
 
 
@@ -93,7 +98,6 @@ typedef struct {
 } encrypt_filter_context_t;
 
 
-
 typedef struct {
     byte *buffer;          /* malloced buffer */
     unsigned buffer_size;   /* and size of this buffer */
@@ -108,8 +112,6 @@ typedef struct {
 } text_filter_context_t;
 
 
-/* encrypt_filter_context_t defined in main.h */
-
 /*-- mdfilter.c --*/
 int md_filter( void *opaque, int control, IOBUF a, byte *buf, size_t *ret_len);
 void free_md_filter_context( md_filter_context_t *mfx );
index 173f8d8..1d9aacf 100644 (file)
@@ -1,5 +1,5 @@
 /* free-packet.c - cleanup stuff for packets
- *     Copyright (C) 1998 Free Software Foundation, Inc.
+ *     Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
 #include <string.h>
 #include <assert.h>
 
+#include <gcrypt.h>
 #include "packet.h"
 #include "iobuf.h"
 #include "util.h"
-#include <gcrypt.h>
 #include "options.h"
 #include "main.h"
 
@@ -219,6 +219,8 @@ free_comment( PKT_comment *rem )
 void
 free_user_id( PKT_user_id *uid )
 {
+    if( uid->photo )
+       gcry_free( uid->photo );
     gcry_free(uid);
 }
 
index d0b9cc1..e9b4a23 100644 (file)
@@ -1,5 +1,5 @@
 /* getkey.c -  Get a key from the database
- *     Copyright (C) 1998, 1999 Free Software Foundation, Inc.
+ *     Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
 #include <string.h>
 #include <assert.h>
 #include <ctype.h>
-#include <gcrypt.h>
+
 #include "util.h"
 #include "packet.h"
+#include <gcrypt.h>
 #include "iobuf.h"
 #include "keydb.h"
 #include "options.h"
  * that they are all valid.
  * Note: We must use numerical values here in case that this program
  * will be converted to those little blue HAL9000s with their strange
- * EBCDIC character set (user ids are UTF-8). */
+ * EBCDIC character set (user ids are UTF-8).
+ * wk 2000-04-13: Hmmm, does this really make sense, given the fact that
+ * we can run gpg now on a S/390 running GNU/Linux, where the code
+ * translation is done by the device drivers?
+ */
 static const byte word_match_chars[256] = {
   /* 00 */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   /* 08 */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -154,6 +159,7 @@ static int uid_cache_entries;       /* number of entries in uid cache */
 static char* prepare_word_match( const byte *name );
 static int lookup_pk( GETKEY_CTX ctx, PKT_public_key *pk, KBNODE *ret_kb );
 static int lookup_sk( GETKEY_CTX ctx, PKT_secret_key *sk, KBNODE *ret_kb );
+static u32 subkeys_expiretime( KBNODE node, u32 *mainkid );
 
 
 #if 0
@@ -696,6 +702,8 @@ key_byname( GETKEY_CTX *retctx, STRLIST namelist,
     STRLIST r;
     GETKEY_CTX ctx;
 
+    if( retctx ) /* reset the returned context in case of error */
+       *retctx = NULL;
     assert( !pk ^ !sk );
 
     /* build the search context */
@@ -941,7 +949,7 @@ get_seckey_bynames( GETKEY_CTX *retctx, PKT_secret_key *sk,
 
     if( !sk ) {
        /* Performance Hint: key_byname should not need a sk here */
-       sk = gcry_xcalloc_secure( 1,  sizeof *sk );
+       sk = gcry_xcalloc_secure( 1, sizeof *sk );
        rc = key_byname( retctx, names, NULL, sk, ret_keyblock );
        free_secret_key( sk );
     }
@@ -959,7 +967,7 @@ get_seckey_next( GETKEY_CTX ctx, PKT_secret_key *sk, KBNODE *ret_keyblock )
 
     if( !sk ) {
        /* Performance Hint: lookup_read should not need a pk in this case */
-       sk = gcry_xcalloc_secure( 1,  sizeof *sk );
+       sk = gcry_xcalloc_secure( 1, sizeof *sk );
        rc = lookup_sk( ctx, sk, ret_keyblock );
        free_secret_key( sk );
     }
@@ -1150,7 +1158,7 @@ merge_one_pk_and_selfsig( KBNODE keyblock, KBNODE knode,
        k = find_kbnode( keyblock, PKT_PUBLIC_KEY );
        if( !k )
           BUG(); /* keyblock without primary key!!! */
-       keyid_from_pk( knode->pkt->pkt.public_key, kid );
+       keyid_from_pk( k->pkt->pkt.public_key, kid );
     }
     else
        keyid_from_pk( pk, kid );
@@ -1208,6 +1216,10 @@ merge_keys_and_selfsig( KBNODE keyblock )
                pk = NULL; /* not needed for old keys */
            else if( k->pkt->pkttype == PKT_PUBLIC_KEY )
                keyid_from_pk( pk, kid );
+           else if( !pk->expiredate ) { /* and subkey */
+               /* insert the expiration date here */
+               pk->expiredate = subkeys_expiretime( k, kid );
+           }
            sigdate = 0;
        }
        else if( k->pkt->pkttype == PKT_SECRET_KEY
@@ -1222,8 +1234,11 @@ merge_keys_and_selfsig( KBNODE keyblock )
        else if( (pk || sk ) && k->pkt->pkttype == PKT_SIGNATURE
                 && (sig=k->pkt->pkt.signature)->sig_class >= 0x10
                 && sig->sig_class <= 0x30 && sig->version > 3
+                && !(sig->sig_class == 0x18 || sig->sig_class == 0x28)
                 && sig->keyid[0] == kid[0] && sig->keyid[1] == kid[1] ) {
            /* okay this is a self-signature which can be used.
+            * This is not used for subkey binding signature, becuase this
+            * is done above.
             * FIXME: We should only use this if the signature is valid
             *        but this is time consuming - we must provide another
             *        way to handle this
@@ -1279,9 +1294,16 @@ find_by_name( KBNODE keyblock, PKT_public_key *pk, const char *name,
                u32 aki[2];
                keyid_from_pk( kk->pkt->pkt.public_key, aki );
                cache_user_id( k->pkt->pkt.user_id, aki );
-               gcry_md_hash_buffer( GCRY_MD_RMD160, namehash,
-                                   k->pkt->pkt.user_id->name,
-                                   k->pkt->pkt.user_id->len );
+               if( k->pkt->pkt.user_id->photo ) {
+                   gcry_md_hash_buffer( GCRY_MD_RMD160, namehash,
+                                       k->pkt->pkt.user_id->photo,
+                                       k->pkt->pkt.user_id->photolen );
+               }
+               else {
+                   gcry_md_hash_buffer( GCRY_MD_RMD160, namehash,
+                                       k->pkt->pkt.user_id->name,
+                                       k->pkt->pkt.user_id->len );
+               }
                *use_namehash = 1;
                return kk;
            }
@@ -1516,6 +1538,56 @@ find_by_fpr_sk( KBNODE keyblock, PKT_secret_key *sk,
 }
 
 
+/****************
+ * Return the expiretime of a subkey.
+ */
+static u32
+subkeys_expiretime( KBNODE node, u32 *mainkid )
+{
+    KBNODE k;
+    PKT_signature *sig;
+    u32 expires = 0, sigdate = 0;
+
+    assert( node->pkt->pkttype == PKT_PUBLIC_SUBKEY );
+    for(k=node->next; k; k = k->next ) {
+       if( k->pkt->pkttype == PKT_SIGNATURE
+           && (sig=k->pkt->pkt.signature)->sig_class == 0x18
+           && sig->keyid[0] == mainkid[0]
+           && sig->keyid[1] == mainkid[1]
+           && sig->version > 3
+           && sig->timestamp > sigdate ) {
+           /* okay this is a key-binding which can be used.
+            * We use the latest self-signature.
+            * FIXME: We should only use this if the binding signature is valid
+            *        but this is time consuming - we must provide another
+            *        way to handle this
+            */
+           const byte *p;
+           u32 ed;
+
+           p = parse_sig_subpkt( sig->hashed_data, SIGSUBPKT_KEY_EXPIRE, NULL );
+           ed = p? node->pkt->pkt.public_key->timestamp + buffer_to_u32(p):0;
+           sigdate = sig->timestamp;
+           expires = ed;
+       }
+       else if( k->pkt->pkttype == PKT_PUBLIC_SUBKEY )
+           break; /* stop at the next subkey */
+    }
+
+    return expires;
+}
+
+
+/****************
+ * Check whether the subkey has expired.  Node must point to the subkey
+ */
+static int
+has_expired( KBNODE node, u32 *mainkid, u32 cur_time )
+{
+    u32 expires = subkeys_expiretime( node, mainkid );
+    return expires && expires <= cur_time;
+}
+
 static void
 finish_lookup( KBNODE keyblock, PKT_public_key *pk, KBNODE k, byte *namehash,
                                               int use_namehash, int primary )
@@ -1534,6 +1606,10 @@ finish_lookup( KBNODE keyblock, PKT_public_key *pk, KBNODE k, byte *namehash,
                       pk->pubkey_usage ) == GPGERR_WR_PUBKEY_ALGO ) {
            /* if the usage is not correct, try to use a subkey */
            KBNODE save_k = k;
+           u32 mainkid[2];
+           u32 cur_time = make_timestamp();
+
+           keyid_from_pk( keyblock->pkt->pkt.public_key, mainkid );
 
            k = NULL;
            /* kludge for pgp 5: which doesn't accept type 20:
@@ -1545,7 +1621,8 @@ finish_lookup( KBNODE keyblock, PKT_public_key *pk, KBNODE k, byte *namehash,
                            == GCRY_PK_ELG_E
                        && !openpgp_pk_test_algo(
                                k->pkt->pkt.public_key->pubkey_algo,
-                                                pk->pubkey_usage ) )
+                                                pk->pubkey_usage )
+                       && !has_expired(k, mainkid, cur_time) )
                        break;
                }
            }
@@ -1555,7 +1632,10 @@ finish_lookup( KBNODE keyblock, PKT_public_key *pk, KBNODE k, byte *namehash,
                    if( k->pkt->pkttype == PKT_PUBLIC_SUBKEY
                        && !openpgp_pk_test_algo(
                                k->pkt->pkt.public_key->pubkey_algo,
-                                                pk->pubkey_usage ) )
+                                                pk->pubkey_usage )
+                       && ( pk->pubkey_usage != GCRY_PK_USAGE_ENCR
+                            || !has_expired( k, mainkid, cur_time ) )
+                     )
                        break;
                }
            }
@@ -1887,6 +1967,18 @@ get_user_id_string( u32 *keyid )
     return p;
 }
 
+
+char*
+get_user_id_string_native( u32 *keyid )
+{
+    char *p = get_user_id_string( keyid );
+    char *p2 = utf8_to_native( p, strlen(p) );
+
+    gcry_free(p);
+    return p2;
+}
+
+
 char*
 get_long_user_id_string( u32 *keyid )
 {
@@ -1914,6 +2006,7 @@ get_user_id( u32 *keyid, size_t *rn )
     user_id_db_t r;
     char *p;
     int pass=0;
+
     /* try it two times; second pass reads from key resources */
     do {
        for(r=user_id_db; r; r = r->next )
@@ -1924,9 +2017,8 @@ get_user_id( u32 *keyid, size_t *rn )
                return p;
            }
     } while( ++pass < 2 && !get_pubkey( NULL, keyid ) );
-    p = gcry_xmalloc( 19 );
-    memcpy(p, "[User id not found]", 19 );
-    *rn = 19;
+    p = gcry_xstrdup( _("[User id not found]") );
+    *rn = strlen(p);
     return p;
 }
 
index 2b66509..fb1be04 100644 (file)
--- a/g10/gpg.c
+++ b/g10/gpg.c
@@ -26,8 +26,8 @@
 #include <ctype.h>
 #include <unistd.h>
 
-#include <gcrypt.h>
 
+#include <gcrypt.h>
 #include "packet.h"
 #include "iobuf.h"
 #include "util.h"
@@ -77,6 +77,7 @@ enum cmd_and_opt_values { aNull = 0,
     aImport,
     aFastImport,
     aVerify,
+    aVerifyFiles,
     aListKeys,
     aListSigs,
     aListSecretKeys,
@@ -85,12 +86,13 @@ enum cmd_and_opt_values { aNull = 0,
     aExport,
     aExportAll,
     aExportSecret,
+    aExportSecretSub,
     aCheckKeys,
     aGenRevoke,
     aPrimegen,
     aPrintMD,
-    aPrintHMAC,
     aPrintMDs,
+    aPrintHMAC,
     aCheckTrustDB,
     aUpdateTrustDB,
     aFixTrustDB,
@@ -130,6 +132,7 @@ enum cmd_and_opt_values { aNull = 0,
     oDigestAlgo,
     oCompressAlgo,
     oPasswdFD,
+    oCommandFD,
     oNoVerbose,
     oTrustDBName,
     oNoSecmemWarn,
@@ -146,7 +149,6 @@ enum cmd_and_opt_values { aNull = 0,
     oCompressKeys,
     oCompressSigs,
     oAlwaysTrust,
-    oEmuChecksumBug,
     oRunAsShmCP,
     oSetFilename,
     oSetPolicyURL,
@@ -164,6 +166,7 @@ enum cmd_and_opt_values { aNull = 0,
     oEscapeFrom,
     oLockOnce,
     oLockMultiple,
+    oLockNever,
     oKeyServer,
     oEncryptTo,
     oNoEncryptTo,
@@ -175,7 +178,14 @@ enum cmd_and_opt_values { aNull = 0,
     oAllowNonSelfsignedUID,
     oNoLiteral,
     oSetFilesize,
-    oEntropyDLLName,
+    oHonorHttpProxy,
+    oFastListMode,
+    oListOnly,
+    oIgnoreTimeConflict,
+    oNoRandomSeedFile,
+    oNoAutoKeyRetrieve,
+    oEmu3DESS2KBug,  /* will be removed in 1.1 */
+    oEmuMDEncodeBug,
 aTest };
 
 
@@ -191,6 +201,7 @@ static ARGPARSE_OPTS opts[] = {
     { aStore, "store",     256, N_("store only")},
     { aDecrypt, "decrypt",   256, N_("decrypt data (default)")},
     { aVerify, "verify"   , 256, N_("verify a signature")},
+    { aVerifyFiles, "verify-files" , 256, "@" },
     { aListKeys, "list-keys", 256, N_("list keys")},
     { aListKeys, "list-public-keys", 256, "@" },
     { aListSigs, "list-sigs", 256, N_("list keys and signatures")},
@@ -210,6 +221,7 @@ static ARGPARSE_OPTS opts[] = {
     { aRecvKeys, "recv-keys"     , 256, N_("import keys from a key server") },
     { aExportAll, "export-all"    , 256, "@" },
     { aExportSecret, "export-secret-keys" , 256, "@" },
+    { aExportSecretSub, "export-secret-subkeys" , 256, "@" },
     { aImport, "import",      256     , N_("import/merge keys")},
     { aFastImport, "fast-import",  256 , "@"},
     { aListPackets, "list-packets",256,N_("list only the sequence of packets")},
@@ -266,12 +278,12 @@ static ARGPARSE_OPTS opts[] = {
     { oCharset, "charset"   , 2, N_("|NAME|set terminal charset to NAME") },
     { oOptions, "options"   , 2, N_("read options from file")},
 
-    { oDebug, "debug"     ,4|16, N_("set debugging flags")},
-    { oDebugAll, "debug-all" ,0, N_("enable full debugging")},
+    { oDebug, "debug"     ,4|16, "@"},
+    { oDebugAll, "debug-all" ,0, "@"},
     { oStatusFD, "status-fd" ,1, N_("|FD|write status info to this FD") },
-    { oNoComment, "no-comment", 0,   N_("do not write comment packets")},
-    { oCompletesNeeded, "completes-needed", 1, N_("(default is 1)")},
-    { oMarginalsNeeded, "marginals-needed", 1, N_("(default is 3)")},
+    { oNoComment, "no-comment", 0,   "@"},
+    { oCompletesNeeded, "completes-needed", 1, "@"},
+    { oMarginalsNeeded, "marginals-needed", 1, "@"},
     { oMaxCertDepth,   "max-cert-depth", 1, "@" },
     { oLoadExtension, "load-extension" ,2, N_("|FILE|load extension module FILE")},
     { oRFC1991, "rfc1991",   0, N_("emulate the mode described in RFC1991")},
@@ -287,7 +299,11 @@ static ARGPARSE_OPTS opts[] = {
     { oThrowKeyid, "throw-keyid", 0, N_("throw keyid field of encrypted packets")},
     { oNotation,   "notation-data", 2, N_("|NAME=VALUE|use this notation data")},
 
-    { 302, NULL, 0, N_("@\nExamples:\n\n"
+    { 302, NULL, 0, N_(
+  "@\n(See the man page for a complete listing of all commands and options)\n"
+                     )},
+
+    { 303, NULL, 0, N_("@\nExamples:\n\n"
     " -se -r Bob [file]          sign and encrypt for user Bob\n"
     " --clearsign [file]         make a clear text signature\n"
     " --detach-sign [file]       make a detached signature\n"
@@ -301,6 +317,7 @@ static ARGPARSE_OPTS opts[] = {
     { aListTrustPath, "list-trust-path",0, "@"},
     { oKOption, NULL,   0, "@"},
     { oPasswdFD, "passphrase-fd",1, "@" },
+    { oCommandFD, "command-fd",1, "@" },
     { oNoVerbose, "no-verbose", 0, "@"},
     { oTrustDBName, "trustdb-name", 2, "@" },
     { oNoSecmemWarn, "no-secmem-warning", 0, "@" }, /* used only by regression tests */
@@ -331,6 +348,7 @@ static ARGPARSE_OPTS opts[] = {
     { oEscapeFrom, "escape-from-lines", 0, "@" },
     { oLockOnce, "lock-once", 0, "@" },
     { oLockMultiple, "lock-multiple", 0, "@" },
+    { oLockNever, "lock-never", 0, "@" },
     { oLoggerFD, "logger-fd",1, "@" },
     { oUseEmbeddedFilename, "use-embedded-filename", 0, "@" },
     { oUtf8Strings, "utf8-strings", 0, "@" },
@@ -341,7 +359,14 @@ static ARGPARSE_OPTS opts[] = {
     { oAllowNonSelfsignedUID, "allow-non-selfsigned-uid", 0, "@" },
     { oNoLiteral, "no-literal", 0, "@" },
     { oSetFilesize, "set-filesize", 20, "@" },
-    { oEntropyDLLName, "entropy-dll-name", 2, "@" },
+    { oHonorHttpProxy,"honor-http-proxy", 0, "@" },
+    { oFastListMode,"fast-list-mode", 0, "@" },
+    { oListOnly, "list-only", 0, "@"},
+    { oIgnoreTimeConflict, "ignore-time-conflict", 0, "@" },
+    { oNoRandomSeedFile,  "no-random-seed-file", 0, "@" },
+    { oNoAutoKeyRetrieve, "no-auto-key-retrieve", 0, "@" },
+    { oEmu3DESS2KBug,  "emulate-3des-s2k-bug", 0, "@"},
+    { oEmuMDEncodeBug, "emulate-md-encode-bug", 0, "@"},
 {0} };
 
 
@@ -351,8 +376,8 @@ int gpg_errors_seen = 0;
 static int utf8_strings = 0;
 static int maybe_setuid = 1;
 
-static char *build_list( const char *text, const char * (*mapf)(int),
-                                                   int (*chkf)(int) );
+static char *build_list( const char *text,
+                        const char *(*mapf)(int), int (*chkf)(int) );
 static void set_cmd( enum cmd_and_opt_values *ret_cmd,
                        enum cmd_and_opt_values new_cmd );
 static void print_hex( byte *p, size_t n );
@@ -360,13 +385,13 @@ static void print_mds( const char *fname, int algo, const char *key );
 static void add_notation_data( const char *string );
 static int  check_policy_url( const char *s );
 
+
 static int
 our_pk_test_algo( int algo )
 {
     return openpgp_pk_test_algo( algo, 0 );
 }
 
-
 static const char *
 my_strusage( int level )
 {
@@ -390,26 +415,29 @@ my_strusage( int level )
              "default operation depends on the input data\n");
        break;
 
-      case 31: p = _("\nSupported algorithms:\n"); break;
-      case 32:
+      case 31: p = "\nHome: "; break;
+      case 32: p = opt.homedir; break;
+      case 33: p = _("\nSupported algorithms:\n"); break;
+      case 34:
        if( !ciphers )
            ciphers = build_list("Cipher: ", gcry_cipher_algo_name,
                                             openpgp_cipher_test_algo );
        p = ciphers;
        break;
-      case 33:
+      case 35:
        if( !pubkeys )
            pubkeys = build_list("Pubkey: ", gcry_pk_algo_name,
                                             our_pk_test_algo );
        p = pubkeys;
        break;
-      case 34:
+      case 36:
        if( !digests )
            digests = build_list("Hash: ", gcry_md_algo_name,
                                           openpgp_md_test_algo );
        p = digests;
        break;
 
+
       default: p = NULL;
     }
     return p;
@@ -465,27 +493,6 @@ i18n_init(void)
   #endif
 }
 
-static void
-wrong_args( const char *text)
-{
-    fputs(_("usage: gpg [options] "),stderr);
-    fputs(text,stderr);
-    putc('\n',stderr);
-    gpg_exit(2);
-}
-
-
-static char *
-make_username( const char *string )
-{
-    char *p;
-    if( utf8_strings )
-       p = native_to_utf8( string );
-    else
-       p = gcry_xstrdup(string);
-    return p;
-}
-
 
 static void
 register_extension( const char *mainpgm, const char *fname )
@@ -510,15 +517,37 @@ register_extension( const char *mainpgm, const char *fname )
 
 
 static void
+wrong_args( const char *text)
+{
+    fputs(_("usage: gpg [options] "),stderr);
+    fputs(text,stderr);
+    putc('\n',stderr);
+    gpg_exit(2);
+}
+
+
+static char *
+make_username( const char *string )
+{
+    char *p;
+    if( utf8_strings )
+       p = gcry_xstrdup(string);
+    else
+       p = native_to_utf8( string );
+    return p;
+}
+
+
+static void
 set_debug(void)
 {
-   #if 0
-     #warning memory debuggig not enabled
+  #if 0
+    #warning memory debugging not enabled
     if( opt.debug & DBG_MEMORY_VALUE )
        memory_debug_mode = 1;
     if( opt.debug & DBG_MEMSTAT_VALUE )
        memory_stat_debug_mode = 1;
-   #endif
+  #endif
 
     if( opt.debug & DBG_MPI_VALUE )
        gcry_control( GCRYCTL_SET_DEBUG_FLAGS, 2 );
@@ -579,6 +608,7 @@ main( int argc, char **argv )
     int default_keyring = 1;
     int greeting = 0;
     int nogreeting = 0;
+    int use_random_seed = 1;
     enum cmd_and_opt_values cmd = 0;
     const char *trustdb_name = NULL;
     char *def_cipher_string = NULL;
@@ -611,6 +641,7 @@ main( int argc, char **argv )
     init_signals();
     create_dotlock(NULL); /* register locking cleanup */
     i18n_init();
+    opt.command_fd = -1; /* no command fd */
     opt.compress = -1; /* defaults to standard compress level */
     /* note: if you change these lines, look at oOpenPGP */
     opt.def_cipher_algo = 0;
@@ -622,7 +653,13 @@ main( int argc, char **argv )
     opt.completes_needed = 1;
     opt.marginals_needed = 3;
     opt.max_cert_depth = 5;
+    opt.pgp2_workarounds = 1;
+    opt.auto_key_retrieve = 1;
+  #ifdef __MINGW32__
+    opt.homedir = read_w32_registry_string( NULL, "Software\\GNU\\GnuPG", "HomeDir" );
+  #else
     opt.homedir = getenv("GNUPGHOME");
+  #endif
     if( !opt.homedir || !*opt.homedir ) {
       #ifdef HAVE_DRIVE_LETTERS
        opt.homedir = "c:/gnupg-test";
@@ -679,7 +716,6 @@ main( int argc, char **argv )
     if( default_config )
        configname = make_filename(opt.homedir, "options", NULL );
 
-
     argc = orig_argc;
     argv = orig_argv;
     pargs.argc = &argc;
@@ -721,13 +757,16 @@ main( int argc, char **argv )
          case aListKeys: set_cmd( &cmd, aListKeys); break;
          case aListSigs: set_cmd( &cmd, aListSigs); break;
          case aExportSecret: set_cmd( &cmd, aExportSecret); break;
+         case aExportSecretSub: set_cmd( &cmd, aExportSecretSub); break;
          case aDeleteSecretKey: set_cmd( &cmd, aDeleteSecretKey);
                                                        greeting=1; break;
          case aDeleteKey: set_cmd( &cmd, aDeleteKey); greeting=1; break;
 
          case aDetachedSign: detached_sig = 1; set_cmd( &cmd, aSign ); break;
          case aSym: set_cmd( &cmd, aSym); break;
+
          case aDecrypt: set_cmd( &cmd, aDecrypt); break;
+
          case aEncr: set_cmd( &cmd, aEncr); break;
          case aSign: set_cmd( &cmd, aSign );  break;
          case aKeygen: set_cmd( &cmd, aKeygen); greeting=1; break;
@@ -738,11 +777,12 @@ main( int argc, char **argv )
          case aClearsign: set_cmd( &cmd, aClearsign); break;
          case aGenRevoke: set_cmd( &cmd, aGenRevoke); break;
          case aVerify: set_cmd( &cmd, aVerify); break;
+         case aVerifyFiles: set_cmd( &cmd, aVerifyFiles); break;
          case aPrimegen: set_cmd( &cmd, aPrimegen); break;
          case aGenRandom: set_cmd( &cmd, aGenRandom); break;
          case aPrintMD: set_cmd( &cmd, aPrintMD); break;
-         case aPrintHMAC: set_cmd( &cmd, aPrintHMAC); break;
          case aPrintMDs: set_cmd( &cmd, aPrintMDs); break;
+         case aPrintHMAC: set_cmd( &cmd, aPrintHMAC); break;
          case aListTrustDB: set_cmd( &cmd, aListTrustDB); break;
          case aCheckTrustDB: set_cmd( &cmd, aCheckTrustDB); break;
          case aUpdateTrustDB: set_cmd( &cmd, aUpdateTrustDB); break;
@@ -828,11 +868,14 @@ main( int argc, char **argv )
            break;
          case oRFC1991:
            opt.rfc1991 = 1;
+           opt.rfc2440 = 0;
            opt.no_comment = 1;
            opt.escape_from = 1;
            break;
          case oOpenPGP:
            opt.rfc1991 = 0;
+           opt.rfc2440 = 1;
+           opt.pgp2_workarounds = 0;
            opt.escape_from = 0;
            opt.force_v3_sigs = 0;
            opt.compress_keys = 0;          /* not mandated  but we do it */
@@ -840,11 +883,13 @@ main( int argc, char **argv )
            opt.not_dash_escaped = 0;
            opt.def_cipher_algo = 0;
            opt.def_digest_algo = 0;
-           opt.def_compress_algo = 2;
+           opt.def_compress_algo = 1;
            opt.s2k_mode = 3; /* iterated+salted */
-           opt.s2k_digest_algo = GCRY_MD_RMD160;
-           opt.s2k_cipher_algo = GCRY_CIPHER_BLOWFISH;
+           opt.s2k_digest_algo = GCRY_MD_SHA1;
+           opt.s2k_cipher_algo = GCRY_CIPHER_CAST5;
            break;
+         case oEmu3DESS2KBug:  opt.emulate_bugs |= EMUBUG_3DESS2K; break;
+         case oEmuMDEncodeBug: opt.emulate_bugs |= EMUBUG_MDENCODE; break;
          case oCompressSigs: opt.compress_sigs = 1; break;
          case oRunAsShmCP:
          #ifndef USE_SHM_COPROCESSING
@@ -880,6 +925,7 @@ main( int argc, char **argv )
            break;
          case oCompress: opt.compress = pargs.r.ret_int; break;
          case oPasswdFD: pwfd = pargs.r.ret_int; break;
+         case oCommandFD: opt.command_fd = pargs.r.ret_int; break;
          case oCipherAlgo: def_cipher_string = gcry_xstrdup(pargs.r.ret_str); break;
          case oDigestAlgo: def_digest_string = gcry_xstrdup(pargs.r.ret_str); break;
          case oNoSecmemWarn: gcry_control( GCRYCTL_DISABLE_SECMEM_WARN ); break;
@@ -891,6 +937,10 @@ main( int argc, char **argv )
          case oNotDashEscaped: opt.not_dash_escaped = 1; break;
          case oEscapeFrom: opt.escape_from = 1; break;
          case oLockOnce: opt.lock_once = 1; break;
+         #if 0
+         #warning no disable_dotlock() yet
+         case oLockNever: disable_dotlock(); break;
+         #endif
          case oLockMultiple: opt.lock_once = 0; break;
          case oKeyServer: opt.keyserver_name = pargs.r.ret_str; break;
          case oNotation: add_notation_data( pargs.r.ret_str ); break;
@@ -908,22 +958,15 @@ main( int argc, char **argv )
                                       &algo, sizeof algo );
                }
                break;
-         case oAllowNonSelfsignedUID:
-               opt.allow_non_selfsigned_uid = 1;
-               break;
-         case oNoLiteral:
-               opt.no_literal = 1;
-               break;
-         case oSetFilesize:
-               opt.set_filesize = pargs.r.ret_ulong;
-               break;
-
-         case oEntropyDLLName:
-             #ifdef USE_STATIC_RNDW32
-               log_info("set dllname to `%s'\n", pargs.r.ret_str );
-               rndw32_set_dll_name( pargs.r.ret_str );
-             #endif
-               break;
+         case oAllowNonSelfsignedUID: opt.allow_non_selfsigned_uid = 1; break;
+         case oNoLiteral: opt.no_literal = 1; break;
+         case oSetFilesize: opt.set_filesize = pargs.r.ret_ulong; break;
+         case oHonorHttpProxy: opt.honor_http_proxy = 1; break;
+         case oFastListMode: opt.fast_list_mode = 1; break;
+         case oListOnly: opt.list_only=1; break;
+         case oIgnoreTimeConflict: opt.ignore_time_conflict = 1; break;
+         case oNoRandomSeedFile: use_random_seed = 0; break;
+         case oNoAutoKeyRetrieve: opt.auto_key_retrieve = 0; break;
 
          default : pargs.err = configfp? 1:2; break;
        }
@@ -946,14 +989,12 @@ main( int argc, char **argv )
        fprintf(stderr, "%s\n", strusage(15) );
     }
   #ifdef IS_DEVELOPMENT_VERSION
-    if( !opt.batch )
-       log_info("NOTE: this is a development version!\n");
-  #endif
-    if( opt.force_mdc ) {
-       log_info("--force-mdc ignored because"
-                " the OpenPGP WG has not yet aggreed on MDCs\n");
-       opt.force_mdc = 0;
+    if( !opt.batch ) {
+       log_info("NOTE: THIS IS A DEVELOPMENT VERSION!\n");
+       log_info("It is only intended for test purposes and should NOT be\n");
+       log_info("used in a production environment or with production keys!\n");
     }
+  #endif
     if (opt.no_literal) {
        log_info(_("NOTE: %s is not for normal use!\n"), "--no-literal");
        if (opt.textmode)
@@ -975,7 +1016,7 @@ main( int argc, char **argv )
      * gpg_opt_homedir = opt.homedir; */
 
     /* must do this after dropping setuid, because string_to...
-     * may try to load a module */
+     * may try to load an module */
     if( def_cipher_string ) {
        opt.def_cipher_algo = gcry_cipher_map_name(def_cipher_string);
        gcry_free(def_cipher_string); def_cipher_string = NULL;
@@ -1025,8 +1066,19 @@ main( int argc, char **argv )
     if( log_get_errorcount(0) )
        gpg_exit(2);
 
-    if( !cmd && opt.fingerprint && !with_fpr )
+    /* set the random seed file */
+    if( use_random_seed ) {
+       char *p = make_filename(opt.homedir, "random_seed", NULL );
+       #if 0
+       #warning set_random_seed_file missing
+       set_random_seed_file(p);
+       #endif
+       gcry_free(p);
+    }
+
+    if( !cmd && opt.fingerprint && !with_fpr ) {
        set_cmd( &cmd, aListKeys);
+    }
 
     if( cmd == aKMode || cmd == aKModeC ) { /* kludge to be compatible to pgp */
        if( cmd == aKModeC ) {
@@ -1077,8 +1129,8 @@ main( int argc, char **argv )
     switch( cmd ) {
       case aPrimegen:
       case aPrintMD:
-      case aPrintHMAC:
       case aPrintMDs:
+      case aPrintHMAC:
       case aGenRandom:
       case aDeArmor:
       case aEnArmor:
@@ -1167,6 +1219,11 @@ main( int argc, char **argv )
            log_error("verify signatures failed: %s\n", gpg_errstr(rc) );
        break;
 
+      case aVerifyFiles:
+       if( (rc = verify_files( argc, argv ) ))
+           log_error("verify files failed: %s\n", gpg_errstr(rc) );
+       break;
+
       case aDecrypt:
        if( argc > 1 )
            wrong_args(_("--decrypt [filename]"));
@@ -1225,16 +1282,28 @@ main( int argc, char **argv )
       case aListSigs:
        opt.list_sigs = 1;
       case aListKeys:
-       /* fixme: we chnaged this in 1.0 */
-       public_key_list( argc, argv );
+       sl = NULL;
+       for( ; argc; argc--, argv++ )
+           add_to_strlist2( &sl, *argv, utf8_strings );
+       public_key_list( sl );
+       free_strlist(sl);
        break;
       case aListSecretKeys:
-       secret_key_list( argc, argv );
+       sl = NULL;
+       for( ; argc; argc--, argv++ )
+           add_to_strlist2( &sl, *argv, utf8_strings );
+       secret_key_list( sl );
+       free_strlist(sl);
        break;
 
       case aKMode: /* list keyring -- NOTE: This will be removed soon */
-       if( argc < 2 )  /* -kv [userid] */
-           public_key_list( (argc && **argv)? 1:0, argv );
+       if( argc < 2 ) { /* -kv [userid] */
+           sl = NULL;
+           if (argc && **argv)
+               add_to_strlist2( &sl, *argv, utf8_strings );
+           public_key_list( sl );
+           free_strlist(sl);
+       }
        else if( argc == 2 ) { /* -kv userid keyring */
            if( access( argv[1], R_OK ) ) {
                log_error(_("can't open %s: %s\n"),
@@ -1244,32 +1313,33 @@ main( int argc, char **argv )
                /* add keyring (default keyrings are not registered in this
                 * special case */
                add_keyblock_resource( argv[1], 0, 0 );
-               public_key_list( **argv?1:0, argv );
+               sl = NULL;
+               if (**argv)
+                   add_to_strlist2( &sl, *argv, utf8_strings );
+               public_key_list( sl );
+               free_strlist(sl);
            }
        }
        else
            wrong_args(_("-k[v][v][v][c] [user-id] [keyring]") );
        break;
 
-      case aKeygen: /* generate a key (interactive) */
-       if( argc )
-           wrong_args("--gen-key");
-       generate_keypair();
+      case aKeygen: /* generate a key */
+       if( opt.batch ) {
+           if( argc > 1 )
+               wrong_args("--gen-key [parameterfile]");
+           generate_keypair( argc? *argv : NULL );
+       }
+       else {
+           if( argc )
+               wrong_args("--gen-key");
+           generate_keypair(NULL);
+       }
        break;
 
       case aFastImport:
       case aImport:
-       if( !argc  ) {
-           rc = import_keys( NULL, (cmd == aFastImport) );
-           if( rc )
-               log_error("import failed: %s\n", gpg_errstr(rc) );
-       }
-       for( ; argc; argc--, argv++ ) {
-           rc = import_keys( *argv, (cmd == aFastImport) );
-           if( rc )
-               log_error("import from `%s' failed: %s\n",
-                                               *argv, gpg_errstr(rc) );
-       }
+       import_keys( argc? argv:NULL, argc, (cmd == aFastImport) );
        break;
 
       case aExport:
@@ -1296,6 +1366,14 @@ main( int argc, char **argv )
        free_strlist(sl);
        break;
 
+      case aExportSecretSub:
+       sl = NULL;
+       for( ; argc; argc--, argv++ )
+           add_to_strlist2( &sl, *argv, utf8_strings );
+       export_secsubkeys( sl );
+       free_strlist(sl);
+       break;
+
       case aGenRevoke:
        if( argc != 1 )
            wrong_args("--gen-revoke user-id");
@@ -1342,7 +1420,7 @@ main( int argc, char **argv )
                mpi_print( stdout, factors[0], 1 ); /* print q */
            }
            else if( mode == 4 && argc == 3 ) {
-               MPI g = mpi_new(8);
+               MPI g = mpi_alloc(1);
                mpi_print( stdout, generate_elg_prime(
                                                 0, atoi(argv[1]),
                                                 atoi(argv[2]), g, NULL ), 1);
@@ -1424,6 +1502,7 @@ main( int argc, char **argv )
        }
        break;
 
+
       case aPrintMDs: /* old option */
        if( !argc )
            print_mds(NULL,0,NULL);
@@ -1461,11 +1540,9 @@ main( int argc, char **argv )
        break;
 
       case aFixTrustDB:
-       log_error("this command is not yet implemented.\"\n");
+       log_error("this command is not yet implemented.\n");
        log_error("A workaround is to use \"--export-ownertrust\", remove\n");
        log_error("the trustdb file and do an \"--import-ownertrust\".\n" );
-       #warning removed the next line
-       export_as_kbxfile();
        break;
 
       case aListTrustPath:
@@ -1533,6 +1610,10 @@ main( int argc, char **argv )
 void
 gpg_exit( int rc )
 {
+  #if 0
+    #warning no update_random_seed_file
+    update_random_seed_file();
+  #endif
     if( opt.debug & DBG_MEMSTAT_VALUE ) {
        gcry_control( GCRYCTL_DUMP_MEMORY_STATS );
        gcry_control( GCRYCTL_DUMP_RANDOM_STATS );
@@ -1629,7 +1710,7 @@ print_mds( const char *fname, int algo, const char *key )
        if( algo ) {
            if( fname )
                fputs( pname, stdout );
-           print_hex( gcry_md_read(md, algo), gcry_md_get_algo_dlen(algo) );
+           print_hex(gcry_md_read(md, algo), gcry_md_get_algo_dlen(algo) );
        }
        else {
            printf(  "%s   MD5 = ", fname?pname:"" );
index 99c91f6..8ca37d3 100644 (file)
@@ -1,4 +1,4 @@
-/* gpg.c - The GnuPG daemon (keyserver)
+/* ggpd.c - The GnuPG daemon (keyserver)
  *     Copyright (C) 1998 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
@@ -38,6 +38,7 @@
 #include <sys/stat.h>
 
 #include "util.h"
+#include "cipher.h"
 #include "options.h"
 #include "main.h"
 
@@ -84,7 +85,7 @@ strusage( int level )
       case 33:
        if( !pubkeys )
            pubkeys = build_list("Supported pubkeys: ", pubkey_algo_to_string,
-                                                       openpgp_pk_test_algo );
+                                                       check_pubkey_algo );
        p = pubkeys;
        break;
       case 34:
@@ -137,7 +138,7 @@ set_debug(void)
     if( opt.debug & DBG_MPI_VALUE )
        mpi_debug_mode = 1;
     if( opt.debug & DBG_CIPHER_VALUE )
-       gpgc_debug_mode = 1;
+       g10c_debug_mode = 1;
     if( opt.debug & DBG_IOBUF_VALUE )
        iobuf_debug_mode = 1;
 }
index e429025..4a7a14f 100644 (file)
@@ -1,5 +1,5 @@
 /* helptext.c  - English help texts
- *     Copyright (C) 1998 Free Software Foundation, Inc.
+ *     Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
@@ -224,6 +224,29 @@ static struct helptexts { const char *key; const char *help; } helptexts[] = {
  "file (which is shown in brackets) will be used."
 )},
 
+/* revoke.c (ask_revocation_reason) */
+{ "ask_revocation_reason.code", N_(
+ "You should specify a reason for the certification.  Depending on the\n"
+ "context you have the ability to choose from this list:\n"
+ "  \"Key has been compromised\"\n"
+ "      Use this if you have a reason to believe that unauthorized persons\n"
+ "      got access to your secret key.\n"
+ "  \"Key is superseeded\"\n"
+ "      Use this if you have replaced this key with a newer one.\n"
+ "  \"Key is no longer used\"\n"
+ "      Use this if you have retired this key.\n"
+ "  \"User ID is no longer valid\"\n"
+ "      Use this to state that the user ID should not longer be used;\n"
+ "      this is normally used to mark an email address invalid.\n"
+)},
+
+/* revoke.c (ask_revocation_reason) */
+{ "ask_revocation_reason.text", N_(
+ "If you like, you can enter a text describing why you issue this\n"
+ "revocation certificate.  Please keep this text concise.\n"
+ "An empty line ends the text.\n"
+)},
+
 /* end of list */
 { NULL, NULL } };
 
index b60b3cc..2f60313 100644 (file)
--- a/g10/hkp.c
+++ b/g10/hkp.c
@@ -30,7 +30,6 @@
 #include "util.h"
 #include "ttyio.h"
 #include "i18n.h"
-#include <gcrypt.h>
 #include "options.h"
 #include "filter.h"
 #include "http.h"
@@ -56,19 +55,24 @@ hkp_ask_import( u32 *keyid )
     struct http_context hd;
     char *request;
     int rc;
+    unsigned int hflags = opt.honor_http_proxy? HTTP_FLAG_TRY_PROXY : 0;
 
     if( !opt.keyserver_name )
        return -1;
-    log_info("requesting key %08lX from %s ...\n", (ulong)keyid[1],
+    log_info(_("requesting key %08lX from %s ...\n"), (ulong)keyid[1],
                                                   opt.keyserver_name );
     request = gcry_xmalloc( strlen( opt.keyserver_name ) + 100 );
     /* hkp does not accept the long keyid - we should really write a
-     * nicer one */
+     * nicer one :-)
+     * FIXME: request binary mode - need to pass no_armor mode
+     * down to the import function.  Marc told that there is such a
+     * binary mode ... how?
+     */
     sprintf( request, "x-hkp://%s:11371/pks/lookup?op=get&search=0x%08lX",
                        opt.keyserver_name, (ulong)keyid[1] );
-    rc = http_open_document( &hd, request, 0 );
+    rc = http_open_document( &hd, request, hflags );
     if( rc ) {
-       log_info("can't get key from keyserver: %s\n",
+       log_info(_("can't get key from keyserver: %s\n"),
                        rc == GPGERR_NETWORK? strerror(errno)
                                            : gpg_errstr(rc) );
     }
@@ -91,7 +95,7 @@ hkp_import( STRLIST users )
     return -1;
   #else
     if( !opt.keyserver_name ) {
-       log_error("no keyserver known (use option --keyserver)\n");
+       log_error(_("no keyserver known (use option --keyserver)\n"));
        return -1;
     }
 
@@ -99,10 +103,15 @@ hkp_import( STRLIST users )
        u32 kid[2];
        int type = classify_user_id( users->d, kid, NULL, NULL, NULL );
        if( type != 10 && type != 11 ) {
-           log_info("%s: not a valid key ID\n", users->d );
+           log_info(_("%s: not a valid key ID\n"), users->d );
            continue;
        }
-       hkp_ask_import( kid );
+       /* because the function may use log_info in some situations, the
+        * errorcounter ist not increaed and the program will return
+        * with success - which is not good when this function is used.
+        */
+       if( hkp_ask_import( kid ) )
+           log_inc_errorcount();
     }
     return 0;
   #endif
@@ -121,9 +130,10 @@ hkp_export( STRLIST users )
     struct http_context hd;
     char *request;
     unsigned int status;
+    unsigned int hflags = opt.honor_http_proxy? HTTP_FLAG_TRY_PROXY : 0;
 
     if( !opt.keyserver_name ) {
-       log_error("no keyserver known (use option --keyserver)\n");
+       log_error(_("no keyserver known (use option --keyserver)\n"));
        return -1;
     }
 
@@ -143,9 +153,9 @@ hkp_export( STRLIST users )
 
     request = gcry_xmalloc( strlen( opt.keyserver_name ) + 100 );
     sprintf( request, "x-hkp://%s:11371/pks/add", opt.keyserver_name );
-    rc = http_open( &hd, HTTP_REQ_POST, request , 0 );
+    rc = http_open( &hd, HTTP_REQ_POST, request , hflags );
     if( rc ) {
-       log_error("can't connect to `%s': %s\n",
+       log_error(_("can't connect to `%s': %s\n"),
                   opt.keyserver_name,
                        rc == GPGERR_NETWORK? strerror(errno)
                                            : gpg_errstr(rc) );
@@ -169,7 +179,7 @@ hkp_export( STRLIST users )
 
     rc = http_wait_response( &hd, &status );
     if( rc ) {
-       log_error("error sending to `%s': %s\n",
+       log_error(_("error sending to `%s': %s\n"),
                   opt.keyserver_name, gpg_errstr(rc) );
     }
     else {
@@ -181,10 +191,10 @@ hkp_export( STRLIST users )
        }
       #endif
        if( (status/100) == 2 )
-           log_info("success sending to `%s' (status=%u)\n",
+           log_info(_("success sending to `%s' (status=%u)\n"),
                                        opt.keyserver_name, status  );
        else
-           log_error("failed sending to `%s': status=%u\n",
+           log_error(_("failed sending to `%s': status=%u\n"),
                                        opt.keyserver_name, status  );
     }
     http_close( &hd );
index a7b78da..64f0497 100644 (file)
--- a/g10/hkp.h
+++ b/g10/hkp.h
@@ -1,5 +1,5 @@
 /* hkp.h  -  Horrowitz Keyserver Protocol
- *     Copyright (C) 1999 Free Software Foundation, Inc.
+ *     Copyright (C) 1999, 2000 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
index 7313512..5780825 100644 (file)
@@ -1,5 +1,5 @@
 /* import.c
- *     Copyright (C) 1998, 1999 Free Software Foundation, Inc.
+ *     Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
@@ -38,6 +38,7 @@
 
 
 static struct {
+    ulong count;
     ulong no_user_id;
     ulong imported;
     ulong imported_rsa;
@@ -53,6 +54,7 @@ static struct {
 
 
 static int import( IOBUF inp, int fast, const char* fname );
+static void print_stats(void);
 static int read_block( IOBUF a, PACKET **pending_pkt, KBNODE *ret_root );
 static int import_one( const char *fname, KBNODE keyblock, int fast );
 static int import_secret_one( const char *fname, KBNODE keyblock );
@@ -105,30 +107,51 @@ static int merge_keysigs( KBNODE dst, KBNODE src, int *n_sigs,
  *  Key revocation certificates have special handling.
  *
  */
-int
-import_keys( const char *fname, int fast )
+void
+import_keys( char **fnames, int nnames, int fast )
 {
-    IOBUF inp = NULL;
-    int rc;
+    int i;
 
-    inp = iobuf_open(fname);
-    if( !fname )
-       fname = "[stdin]";
-    if( !inp ) {
-       log_error(_("can't open `%s': %s\n"), fname, strerror(errno) );
-       return GPGERR_OPEN_FILE;
-    }
+    /* fixme: don't use static variables */
+    memset( &stats, 0, sizeof( stats ) );
 
-    rc = import( inp, fast, fname );
+    if( !fnames && !nnames )
+       nnames = 1;  /* Ohh what a ugly hack to jump into the loop */
 
-    iobuf_close(inp);
-    return rc;
+    for(i=0; i < nnames; i++ ) {
+       const char *fname = fnames? fnames[i] : NULL;
+       IOBUF inp = iobuf_open(fname);
+       if( !fname )
+           fname = "[stdin]";
+       if( !inp )
+           log_error(_("can't open `%s': %s\n"), fname, strerror(errno) );
+       else {
+           int rc = import( inp, fast, fname );
+           iobuf_close(inp);
+           if( rc )
+               log_error("import from `%s' failed: %s\n", fname,
+                                                          gpg_errstr(rc) );
+       }
+       if( !fname )
+           break;
+    }
+    print_stats();
+    if( !fast )
+       sync_trustdb();
 }
 
 int
 import_keys_stream( IOBUF inp, int fast )
 {
-    return import( inp, fast, "[stream]" );
+    int rc = 0;
+
+    /* fixme: don't use static variables */
+    memset( &stats, 0, sizeof( stats ) );
+    rc = import( inp, fast, "[stream]" );
+    print_stats();
+    if( !fast )
+       sync_trustdb();
+    return rc;
 }
 
 static int
@@ -137,10 +160,6 @@ import( IOBUF inp, int fast, const char* fname )
     PACKET *pending_pkt = NULL;
     KBNODE keyblock;
     int rc = 0;
-    ulong count=0;
-
-    /* fixme: don't use static variables */
-    memset( &stats, 0, sizeof( stats ) );
 
     getkey_disable_caches();
 
@@ -165,16 +184,23 @@ import( IOBUF inp, int fast, const char* fname )
        release_kbnode(keyblock);
        if( rc )
            break;
-       if( !(++count % 100) && !opt.quiet )
-           log_info(_("%lu keys so far processed\n"), count );
+       if( !(++stats.count % 100) && !opt.quiet )
+           log_info(_("%lu keys so far processed\n"), stats.count );
     }
     if( rc == -1 )
        rc = 0;
     else if( rc && rc != GPGERR_INV_KEYRING )
        log_error( _("error reading `%s': %s\n"), fname, gpg_errstr(rc));
 
+    return rc;
+}
+
+
+static void
+print_stats()
+{
     if( !opt.quiet ) {
-       log_info(_("Total number processed: %lu\n"), count );
+       log_info(_("Total number processed: %lu\n"), stats.count );
        if( stats.no_user_id )
            log_info(_("          w/o user IDs: %lu\n"), stats.no_user_id );
        if( stats.imported || stats.imported_rsa ) {
@@ -202,9 +228,9 @@ import( IOBUF inp, int fast, const char* fname )
     }
 
     if( is_status_enabled() ) {
-       char buf[12*16];
+       char buf[12*20];
        sprintf(buf, "%lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu",
-               count,
+               stats.count,
                stats.no_user_id,
                stats.imported,
                stats.imported_rsa,
@@ -218,8 +244,6 @@ import( IOBUF inp, int fast, const char* fname )
                stats.secret_dups);
        write_status_text( STATUS_IMPORT_RES, buf );
     }
-
-    return rc;
 }
 
 
@@ -354,8 +378,8 @@ import_one( const char *fname, KBNODE keyblock, int fast )
                  pubkey_letter( pk->pubkey_algo ),
                  (ulong)keyid[1], datestr_from_pk(pk) );
        if( uidnode )
-           print_string( stderr, uidnode->pkt->pkt.user_id->name,
-                                 uidnode->pkt->pkt.user_id->len, 0 );
+           print_utf8_string( stderr, uidnode->pkt->pkt.user_id->name,
+                                      uidnode->pkt->pkt.user_id->len );
        putc('\n', stderr);
     }
     if( !uidnode ) {
@@ -545,8 +569,8 @@ import_secret_one( const char *fname, KBNODE keyblock )
                  pubkey_letter( sk->pubkey_algo ),
                  (ulong)keyid[1], datestr_from_sk(sk) );
        if( uidnode )
-           print_string( stderr, uidnode->pkt->pkt.user_id->name,
-                                 uidnode->pkt->pkt.user_id->len, 0 );
+           print_utf8_string( stderr, uidnode->pkt->pkt.user_id->name,
+                                      uidnode->pkt->pkt.user_id->len );
        putc('\n', stderr);
     }
     stats.secret_read++;
@@ -678,6 +702,15 @@ import_revoke_cert( const char *fname, KBNODE node )
        log_info( _("key %08lX: revocation certificate imported\n"),
                                        (ulong)keyid[1]);
     stats.n_revoc++;
+    if( clear_trust_checked_flag( pk ) ) {
+       /* seems that we have to insert the record first */
+       rc = insert_trust_record( keyblock );
+       if( rc )
+           log_error("key %08lX: trustdb insert failed: %s\n",
+                                       (ulong)keyid[1], gpg_errstr(rc) );
+       else
+           rc = clear_trust_checked_flag( pk );
+    }
 
   leave:
     release_kbnode( keyblock );
@@ -764,7 +797,8 @@ mark_non_selfsigned_uids_valid( KBNODE keyblock, u32 *kid )
     KBNODE node;
     for(node=keyblock->next; node; node = node->next ) {
        if( node->pkt->pkttype == PKT_USER_ID && !(node->flag & 1) ) {
-           if( node->next && node->next->pkt->pkttype == PKT_SIGNATURE ) {
+           if( (node->next && node->next->pkt->pkttype == PKT_SIGNATURE)
+               || !node->next ) {
                node->flag |= 1;
                log_info( _("key %08lX: accepted non self-signed user ID '"),
                                                         (ulong)kid[1]);
@@ -797,8 +831,8 @@ delete_inv_parts( const char *fname, KBNODE keyblock, u32 *keyid )
                if( opt.verbose ) {
                    log_info( _("key %08lX: skipped user ID '"),
                                                         (ulong)keyid[1]);
-                   print_string( stderr, node->pkt->pkt.user_id->name,
-                                     node->pkt->pkt.user_id->len, 0 );
+                   print_utf8_string( stderr, node->pkt->pkt.user_id->name,
+                                      node->pkt->pkt.user_id->len );
                    fputs("'\n", stderr );
                }
                delete_kbnode( node ); /* the user-id */
@@ -831,7 +865,7 @@ delete_inv_parts( const char *fname, KBNODE keyblock, u32 *keyid )
            }
        }
        else if( node->pkt->pkttype == PKT_SIGNATURE
-                && openpgp_pk_test_algo( node->pkt->pkt.signature->pubkey_algo, 0)
+                && openpgp_pk_test_algo( node->pkt->pkt.signature->pubkey_algo, 0 )
                 && node->pkt->pkt.signature->pubkey_algo != GCRY_PK_RSA )
            delete_kbnode( node ); /* build_packet() can't handle this */
        else if( node->pkt->pkttype == PKT_SIGNATURE
index 79c1386..2c1e2ad 100644 (file)
@@ -1,5 +1,5 @@
 /* kbnode.c -  keyblock node utility functions
- *     Copyright (C) 1998 Free Software Foundation, Inc.
+ *     Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
@@ -23,8 +23,9 @@
 #include <stdlib.h>
 #include <string.h>
 #include <assert.h>
-#include "util.h"
+
 #include <gcrypt.h>
+#include "util.h"
 #include "packet.h"
 #include "keydb.h"
 
@@ -165,7 +166,7 @@ find_prev_kbnode( KBNODE root, KBNODE node, int pkttype )
     KBNODE n1;
 
     for(n1=NULL ; root && root != node; root = root->next )
-       if( !pkttype || root->pkt->pkttype == pkttype )
+       if( !pkttype || root->pkt->pkttype == pkttype  )
            n1 = root;
     return n1;
 }
index c298d58..01d0dfe 100644 (file)
@@ -511,7 +511,7 @@ kbx_create_blob ( KBXBLOB *r_blob,  KBNODE keyblock )
     KBXBLOB blob;
 
     *r_blob = NULL;
-    blob = gcry_calloc (1, sizeof *blob );
+    blob = gcry_xcalloc (1, sizeof *blob );
     if( !blob )
        return GCRYERR_NO_MEM;
 
@@ -529,9 +529,9 @@ kbx_create_blob ( KBXBLOB *r_blob,  KBNODE keyblock )
          default: break;
        }
     }
-    blob->keys = gcry_calloc ( blob->nkeys, sizeof ( *blob->keys ) );
-    blob->uids = gcry_calloc ( blob->nuids, sizeof ( *blob->uids ) );
-    blob->sigs = gcry_calloc ( blob->nsigs, sizeof ( *blob->sigs ) );
+    blob->keys = gcry_xcalloc ( blob->nkeys, sizeof ( *blob->keys ) );
+    blob->uids = gcry_xcalloc ( blob->nuids, sizeof ( *blob->uids ) );
+    blob->sigs = gcry_xcalloc ( blob->nsigs, sizeof ( *blob->sigs ) );
     if ( !blob->keys || !blob->uids || !blob->sigs ) {
        rc = GCRYERR_NO_MEM;
        goto leave;
@@ -581,7 +581,7 @@ kbx_new_blob ( KBXBLOB *r_blob,  char *image, size_t imagelen )
     KBXBLOB blob;
 
     *r_blob = NULL;
-    blob = gcry_calloc (1, sizeof *blob );
+    blob = gcry_xcalloc (1, sizeof *blob );
     if( !blob )
        return GCRYERR_NO_MEM;
     blob->blob = image;
index 7bf6150..457fb17 100644 (file)
@@ -321,7 +321,7 @@ print_kbxfile( const char *filename )
     fp = fopen ( filename, "rb" );
     if( !fp ) {
        log_error(_("can't open `%s': %s\n"), filename, strerror(errno) );
-       return 1;
+       return;
     }
 
     while ( !do_print_kbxfile( filename, fp ) )
index 05aac77..e0af39a 100644 (file)
@@ -1,5 +1,5 @@
 /* keydb.h - Key database
- *     Copyright (C) 1998 Free Software Foundation, Inc.
+ *     Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
@@ -25,6 +25,7 @@
   #include <gdbm.h>
 #endif
 
+#include "types.h"
 #include "basicdefs.h"
 #include "packet.h"
 
@@ -156,6 +157,7 @@ void get_seckey_end( GETKEY_CTX ctx );
 int enum_secret_keys( void **context, PKT_secret_key *sk, int with_subkeys );
 void merge_keys_and_selfsig( KBNODE keyblock );
 char*get_user_id_string( u32 *keyid );
+char*get_user_id_string_native( u32 *keyid );
 char*get_long_user_id_string( u32 *keyid );
 char*get_user_id( u32 *keyid, size_t *rn );
 
@@ -197,6 +199,7 @@ const char *enum_keyblock_resources( int *sequence, int secret );
 int add_keyblock_resource( const char *resname, int force, int secret );
 const char *keyblock_resource_name( KBPOS *kbpos );
 int get_keyblock_handle( const char *filename, int secret, KBPOS *kbpos );
+char *get_writable_keyblock_file( int secret );
 int locate_keyblock_by_fpr( KBPOS *kbpos, const byte *fpr,
                                            int fprlen, int secret );
 int locate_keyblock_by_keyid( KBPOS *kbpos, u32 *keyid,
index fdb8bf6..a64c7e8 100644 (file)
@@ -1,5 +1,5 @@
 /* keyedit.c - keyedit stuff
- *     Copyright (C) 1998, 1999 Free Software Foundation, Inc.
+ *     Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
@@ -74,8 +74,9 @@ static int enable_disable_key( KBNODE keyblock, int disable );
 #define NODFLG_SELSIG (1<<10) /* indicate a selected signature */
 
 
-struct sign_uid_attrib {
+struct sign_attrib {
     int non_exportable;
+    struct revocation_reason_info *reason;
 };
 
 
@@ -157,7 +158,7 @@ print_and_check_one_sig( KBNODE keyblock, KBNODE node,
        else {
            size_t n;
            char *p = get_user_id( sig->keyid, &n );
-           tty_print_utf8_string( p, n > 40? 40 : n );
+           tty_print_utf8_string2( p, n, 40 );
            gcry_free(p);
        }
        tty_printf("\n");
@@ -239,16 +240,18 @@ check_all_keysigs( KBNODE keyblock, int only_selected )
 
 
 
-int
-sign_uid_mk_attrib( PKT_signature *sig, void *opaque )
+static int
+sign_mk_attrib( PKT_signature *sig, void *opaque )
 {
-    struct sign_uid_attrib *attrib = opaque;
+    struct sign_attrib *attrib = opaque;
     byte buf[8];
 
     if( attrib->non_exportable ) {
        buf[0] = 0; /* not exportable */
        build_sig_subpkt( sig, SIGSUBPKT_EXPORTABLE, buf, 1 );
     }
+    if( attrib->reason )
+       revocation_reason_build_cb( sig, attrib->reason );
 
     return 0;
 }
@@ -353,7 +356,7 @@ sign_uids( KBNODE keyblock, STRLIST locusr, int *ret_modified, int local )
                     && (node->flag & NODFLG_MARK_A) ) {
                PACKET *pkt;
                PKT_signature *sig;
-               struct sign_uid_attrib attrib;
+               struct sign_attrib attrib;
 
                assert( primary_pk );
                memset( &attrib, 0, sizeof attrib );
@@ -364,7 +367,7 @@ sign_uids( KBNODE keyblock, STRLIST locusr, int *ret_modified, int local )
                                               NULL,
                                               sk,
                                               0x10, 0,
-                                              sign_uid_mk_attrib,
+                                              sign_mk_attrib,
                                               &attrib );
                if( rc ) {
                    log_error(_("signing failed: %s\n"), gpg_errstr(rc));
@@ -407,6 +410,7 @@ change_passphrase( KBNODE keyblock )
     KBNODE node;
     PKT_secret_key *sk;
     char *passphrase = NULL;
+    int no_primary_secrets = 0;
 
     node = find_kbnode( keyblock, PKT_SECRET_KEY );
     if( !node ) {
@@ -423,10 +427,16 @@ change_passphrase( KBNODE keyblock )
        tty_printf(_("This key is not protected.\n"));
        break;
       default:
-       tty_printf(_("Key is protected.\n"));
-       rc = check_secret_key( sk, 0 );
-       if( !rc )
-           passphrase = get_last_passphrase();
+       if( sk->protect.s2k.mode == 1001 ) {
+           tty_printf(_("Secret parts of primary key are not available.\n"));
+           no_primary_secrets = 1;
+       }
+       else {
+           tty_printf(_("Key is protected.\n"));
+           rc = check_secret_key( sk, 0 );
+           if( !rc )
+               passphrase = get_last_passphrase();
+       }
        break;
     }
 
@@ -436,6 +446,8 @@ change_passphrase( KBNODE keyblock )
            PKT_secret_key *subsk = node->pkt->pkt.secret_key;
            set_next_passphrase( passphrase );
            rc = check_secret_key( subsk, 0 );
+           if( !rc && !passphrase )
+               passphrase = get_last_passphrase();
        }
     }
 
@@ -465,9 +477,12 @@ change_passphrase( KBNODE keyblock )
                break;
            }
            else { /* okay */
-               sk->protect.algo = dek->algo;
-               sk->protect.s2k = *s2k;
-               rc = protect_secret_key( sk, dek );
+               rc = 0;
+               if( !no_primary_secrets ) {
+                   sk->protect.algo = dek->algo;
+                   sk->protect.s2k = *s2k;
+                   rc = protect_secret_key( sk, dek );
+               }
                for(node=keyblock; !rc && node; node = node->next ) {
                    if( node->pkt->pkttype == PKT_SECRET_SUBKEY ) {
                        PKT_secret_key *subsk = node->pkt->pkt.secret_key;
@@ -558,41 +573,42 @@ keyedit_menu( const char *username, STRLIST locusr, STRLIST commands,
     static struct { const char *name;
                    enum cmdids id;
                    int need_sk;
+                   int not_with_sk;
                    int signmode;
                    const char *desc;
                  } cmds[] = {
-       { N_("quit")    , cmdQUIT      , 0,1, N_("quit this menu") },
-       { N_("q")       , cmdQUIT      , 0,1, NULL   },
-       { N_("save")    , cmdSAVE      , 0,1, N_("save and quit") },
-       { N_("help")    , cmdHELP      , 0,1, N_("show this help") },
-       {    "?"        , cmdHELP      , 0,1, NULL   },
-       { N_("fpr")     , cmdFPR       , 0,1, N_("show fingerprint") },
-       { N_("list")    , cmdLIST      , 0,1, N_("list key and user IDs") },
-       { N_("l")       , cmdLIST      , 0,1, NULL   },
-       { N_("uid")     , cmdSELUID    , 0,1, N_("select user ID N") },
-       { N_("key")     , cmdSELKEY    , 0,0, N_("select secondary key N") },
-       { N_("check")   , cmdCHECK     , 0,1, N_("list signatures") },
-       { N_("c")       , cmdCHECK     , 0,1, NULL },
-       { N_("sign")    , cmdSIGN      , 0,1, N_("sign the key") },
-       { N_("s")       , cmdSIGN      , 0,1, NULL },
-       { N_("lsign")   , cmdLSIGN     , 0,1, N_("sign the key locally") },
-       { N_("debug")   , cmdDEBUG     , 0,0, NULL },
-       { N_("adduid")  , cmdADDUID    , 1,0, N_("add a user ID") },
-       { N_("deluid")  , cmdDELUID    , 0,0, N_("delete user ID") },
-       { N_("addkey")  , cmdADDKEY    , 1,0, N_("add a secondary key") },
-       { N_("delkey")  , cmdDELKEY    , 0,0, N_("delete a secondary key") },
-       { N_("delsig")  , cmdDELSIG    , 0,0, N_("delete signatures") },
-       { N_("expire")  , cmdEXPIRE    , 1,0, N_("change the expire date") },
-       { N_("toggle")  , cmdTOGGLE    , 1,0, N_("toggle between secret "
-                                                "and public key listing") },
-       { N_("t"     )  , cmdTOGGLE    , 1,0, NULL },
-       { N_("pref")    , cmdPREF      , 0,0,  N_("list preferences") },
-       { N_("passwd")  , cmdPASSWD    , 1,0, N_("change the passphrase") },
-       { N_("trust")   , cmdTRUST     , 0,0,  N_("change the ownertrust") },
-       { N_("revsig")  , cmdREVSIG    , 0,0, N_("revoke signatures") },
-       { N_("revkey")  , cmdREVKEY    , 1,0, N_("revoke a secondary key") },
-       { N_("disable") , cmdDISABLEKEY, 0,0, N_("disable a key") },
-       { N_("enable")  , cmdENABLEKEY , 0,0, N_("enable a key") },
+       { N_("quit")    , cmdQUIT      , 0,0,1, N_("quit this menu") },
+       { N_("q")       , cmdQUIT      , 0,0,1, NULL   },
+       { N_("save")    , cmdSAVE      , 0,0,1, N_("save and quit") },
+       { N_("help")    , cmdHELP      , 0,0,1, N_("show this help") },
+       {    "?"        , cmdHELP      , 0,0,1, NULL   },
+       { N_("fpr")     , cmdFPR       , 0,0,1, N_("show fingerprint") },
+       { N_("list")    , cmdLIST      , 0,0,1, N_("list key and user IDs") },
+       { N_("l")       , cmdLIST      , 0,0,1, NULL   },
+       { N_("uid")     , cmdSELUID    , 0,0,1, N_("select user ID N") },
+       { N_("key")     , cmdSELKEY    , 0,0,0, N_("select secondary key N") },
+       { N_("check")   , cmdCHECK     , 0,0,1, N_("list signatures") },
+       { N_("c")       , cmdCHECK     , 0,0,1, NULL },
+       { N_("sign")    , cmdSIGN      , 0,1,1, N_("sign the key") },
+       { N_("s")       , cmdSIGN      , 0,1,1, NULL },
+       { N_("lsign")   , cmdLSIGN     , 0,1,1, N_("sign the key locally") },
+       { N_("debug")   , cmdDEBUG     , 0,1,0, NULL },
+       { N_("adduid")  , cmdADDUID    , 1,1,0, N_("add a user ID") },
+       { N_("deluid")  , cmdDELUID    , 0,1,0, N_("delete user ID") },
+       { N_("addkey")  , cmdADDKEY    , 1,1,0, N_("add a secondary key") },
+       { N_("delkey")  , cmdDELKEY    , 0,1,0, N_("delete a secondary key") },
+       { N_("delsig")  , cmdDELSIG    , 0,1,0, N_("delete signatures") },
+       { N_("expire")  , cmdEXPIRE    , 1,1,0, N_("change the expire date") },
+       { N_("toggle")  , cmdTOGGLE    , 1,0,0, N_("toggle between secret "
+                                                  "and public key listing") },
+       { N_("t"     )  , cmdTOGGLE    , 1,0,0, NULL },
+       { N_("pref")    , cmdPREF      , 0,1,0, N_("list preferences") },
+       { N_("passwd")  , cmdPASSWD    , 1,1,0, N_("change the passphrase") },
+       { N_("trust")   , cmdTRUST     , 0,1,0, N_("change the ownertrust") },
+       { N_("revsig")  , cmdREVSIG    , 0,1,0, N_("revoke signatures") },
+       { N_("revkey")  , cmdREVKEY    , 1,1,0, N_("revoke a secondary key") },
+       { N_("disable") , cmdDISABLEKEY, 0,1,0, N_("disable a key") },
+       { N_("enable")  , cmdENABLEKEY , 0,1,0, N_("enable a key") },
 
     { NULL, cmdNONE } };
     enum cmdids cmd = 0;
@@ -678,7 +694,7 @@ keyedit_menu( const char *username, STRLIST locusr, STRLIST commands,
                    have_commands = 0;
            }
            if( !have_commands ) {
-               answer = cpr_get("", _("Command> "));
+               answer = cpr_get("keyedit.prompt", _("Command> "));
                cpr_kill_prompt();
            }
            trim_spaces(answer);
@@ -711,6 +727,10 @@ keyedit_menu( const char *username, STRLIST locusr, STRLIST commands,
                tty_printf(_("Need the secret key to do this.\n"));
                cmd = cmdNOP;
            }
+           else if( cmds[i].not_with_sk && sec_keyblock && toggle ) {
+               tty_printf(_("Please use the command \"toggle\" first.\n"));
+               cmd = cmdNOP;
+           }
            else
                cmd = cmds[i].id;
        }
@@ -763,6 +783,11 @@ keyedit_menu( const char *username, STRLIST locusr, STRLIST commands,
            if( !sign_uids( keyblock, locusr, &modified, cmd == cmdLSIGN )
                && sign_mode )
                goto do_cmd_save;
+           /* Actually we should do a update_trust_record() here so that
+            * the trust gets displayed correctly. however this is not possible
+            * because we would have to save the keyblock first - something
+            * we don't want to do without an explicit save command.
+            */
            break;
 
          case cmdDEBUG:
@@ -1005,7 +1030,13 @@ show_prefs( KBNODE keyblock, PKT_user_id *uid )
        return;
     }
 
-    gcry_md_hash_buffer( GCRY_MD_RMD160, namehash, uid->name, uid->len );
+    if( uid->photo ) {
+       gcry_md_hash_buffer( GCRY_MD_RMD160, namehash, uid->photo,
+                                                      uid->photolen );
+    }
+    else {
+       gcry_md_hash_buffer( GCRY_MD_RMD160, namehash, uid->name, uid->len );
+    }
 
     p = get_pref_data( pk->local_id, namehash, &n );
     if( !p )
@@ -1049,7 +1080,7 @@ show_key_with_all_names( KBNODE keyblock, int only_marked,
                otrust = get_ownertrust_info( pk->local_id );
            }
 
-           tty_printf("%s%c %4u%c/%08lX  created: %s expires: %s",
+           tty_printf(_("%s%c %4u%c/%08lX  created: %s expires: %s"),
                          node->pkt->pkttype == PKT_PUBLIC_KEY? "pub":"sub",
                          (node->flag & NODFLG_SELKEY)? '*':' ',
                          nbits_from_pk( pk ),
@@ -1058,7 +1089,7 @@ show_key_with_all_names( KBNODE keyblock, int only_marked,
                          datestr_from_pk(pk),
                          expirestr_from_pk(pk) );
            if( node->pkt->pkttype == PKT_PUBLIC_KEY ) {
-               tty_printf(" trust: %c/%c", otrust, trust );
+               tty_printf(_(" trust: %c/%c"), otrust, trust );
                if( node->pkt->pkttype == PKT_PUBLIC_KEY
                    && (get_ownertrust( pk->local_id )&TRUST_FLAG_DISABLED)) {
                    tty_printf("\n*** ");
@@ -1075,14 +1106,15 @@ show_key_with_all_names( KBNODE keyblock, int only_marked,
        else if( node->pkt->pkttype == PKT_SECRET_KEY
            || (with_subkeys && node->pkt->pkttype == PKT_SECRET_SUBKEY) ) {
            PKT_secret_key *sk = node->pkt->pkt.secret_key;
-           tty_printf("%s%c %4u%c/%08lX  created: %s expires: %s\n",
-                         node->pkt->pkttype == PKT_SECRET_KEY? "sec":"sbb",
+           tty_printf(_("%s%c %4u%c/%08lX  created: %s expires: %s"),
+                         node->pkt->pkttype == PKT_SECRET_KEY? "sec":"ssb",
                          (node->flag & NODFLG_SELKEY)? '*':' ',
                          nbits_from_sk( sk ),
                          pubkey_letter( sk->pubkey_algo ),
                          (ulong)keyid_from_sk(sk,NULL),
                          datestr_from_sk(sk),
                          expirestr_from_sk(sk) );
+           tty_printf("\n");
        }
        else if( with_subkeys && node->pkt->pkttype == PKT_SIGNATURE
                 && node->pkt->pkt.signature->sig_class == 0x28       ) {
@@ -1090,12 +1122,12 @@ show_key_with_all_names( KBNODE keyblock, int only_marked,
 
            rc = check_key_signature( keyblock, node, NULL );
            if( !rc )
-               tty_printf( "rev! subkey has been revoked: %s\n",
+               tty_printf( _("rev! subkey has been revoked: %s\n"),
                            datestr_from_sig( sig ) );
            else if( rc == GPGERR_BAD_SIGN )
-               tty_printf( "rev- faked revocation found\n" );
+               tty_printf( _("rev- faked revocation found\n") );
            else if( rc )
-               tty_printf( "rev? problem checking revocation: %s\n",
+               tty_printf( _("rev? problem checking revocation: %s\n"),
                                                         gpg_errstr(rc) );
        }
     }
@@ -1156,7 +1188,7 @@ show_fingerprint( PKT_public_key *pk )
 
     fingerprint_from_pk( pk, array, &n );
     p = array;
-    tty_printf("             Fingerprint:");
+    tty_printf(_("             Fingerprint:"));
     if( n == 20 ) {
        for(i=0; i < n ; i++, i++, p += 2 ) {
            if( i == 10 )
@@ -1471,7 +1503,8 @@ menu_expire( KBNODE pub_keyblock, KBNODE sec_keyblock )
        }
        else if( node->pkt->pkttype == PKT_USER_ID )
            uid = node->pkt->pkt.user_id;
-       else if( main_pk && node->pkt->pkttype == PKT_SIGNATURE ) {
+       else if( main_pk && node->pkt->pkttype == PKT_SIGNATURE
+                && sub_pk != NULL ) {
            PKT_signature *sig = node->pkt->pkt.signature;
            if( keyid[0] == sig->keyid[0] && keyid[1] == sig->keyid[1]
                && (    (mainkey && uid && (sig->sig_class&~3) == 0x10)
@@ -1535,6 +1568,7 @@ menu_expire( KBNODE pub_keyblock, KBNODE sec_keyblock )
                    gcry_free( sn->pkt );
                    sn->pkt = newpkt;
                }
+               sub_pk = NULL;
            }
        }
     }
@@ -1735,6 +1769,7 @@ menu_revsig( KBNODE keyblock )
     int changed = 0;
     int upd_trust = 0;
     int rc, any;
+    struct revocation_reason_info *reason = NULL;
 
     /* FIXME: detect duplicates here  */
     tty_printf(_("You have signed these user IDs:\n"));
@@ -1797,6 +1832,10 @@ menu_revsig( KBNODE keyblock )
         _("Really create the revocation certificates? (y/N)")) )
        return 0; /* forget it */
 
+    reason = ask_revocation_reason( 0, 1, 0 );
+    if( !reason ) { /* user decided to cancel */
+       return 0;
+    }
 
     /* now we can sign the user ids */
   reloop: /* (must use this, because we are modifing the list) */
@@ -1804,7 +1843,7 @@ menu_revsig( KBNODE keyblock )
     for( node=keyblock; node; node = node->next ) {
        KBNODE unode;
        PACKET *pkt;
-       struct sign_uid_attrib attrib;
+       struct sign_attrib attrib;
        PKT_secret_key *sk;
 
        if( !(node->flag & NODFLG_MARK_A)
@@ -1814,8 +1853,10 @@ menu_revsig( KBNODE keyblock )
        assert( unode ); /* we already checked this */
 
        memset( &attrib, 0, sizeof attrib );
+       attrib.reason = reason;
+
        node->flag &= ~NODFLG_MARK_A;
-       sk = gcry_xcalloc_secure( 1,  sizeof *sk );
+       sk = gcry_xcalloc_secure( 1, sizeof *sk );
        if( get_seckey( sk, node->pkt->pkt.signature->keyid ) ) {
            log_info(_("no secret key\n"));
            continue;
@@ -1825,11 +1866,12 @@ menu_revsig( KBNODE keyblock )
                                       NULL,
                                       sk,
                                       0x30, 0,
-                                      sign_uid_mk_attrib,
+                                      sign_mk_attrib,
                                       &attrib );
        free_secret_key(sk);
        if( rc ) {
            log_error(_("signing failed: %s\n"), gpg_errstr(rc));
+           release_revocation_reason_info( reason );
            return changed;
        }
        changed = 1; /* we changed the keyblock */
@@ -1844,7 +1886,7 @@ menu_revsig( KBNODE keyblock )
 
     if( upd_trust )
        clear_trust_checked_flag( primary_pk );
-
+    release_revocation_reason_info( reason );
     return changed;
 }
 
@@ -1861,6 +1903,13 @@ menu_revkey( KBNODE pub_keyblock, KBNODE sec_keyblock )
     int changed = 0;
     int upd_trust = 0;
     int rc;
+    struct revocation_reason_info *reason = NULL;
+
+    reason = ask_revocation_reason( 1, 0, 0 );
+    if( !reason ) { /* user decided to cancel */
+       return 0;
+    }
+
 
   reloop: /* (better this way because we are modifing the keyring) */
     mainpk = pub_keyblock->pkt->pkt.public_key;
@@ -1871,14 +1920,20 @@ menu_revkey( KBNODE pub_keyblock, KBNODE sec_keyblock )
            PKT_signature *sig;
            PKT_secret_key *sk;
            PKT_public_key *subpk = node->pkt->pkt.public_key;
+           struct sign_attrib attrib;
+
+           memset( &attrib, 0, sizeof attrib );
+           attrib.reason = reason;
 
            node->flag &= ~NODFLG_SELKEY;
            sk = copy_secret_key( NULL, sec_keyblock->pkt->pkt.secret_key );
            rc = make_keysig_packet( &sig, mainpk, NULL, subpk, sk, 0x28, 0,
-                                    NULL, NULL );
+                                      sign_mk_attrib,
+                                      &attrib );
            free_secret_key(sk);
            if( rc ) {
                log_error(_("signing failed: %s\n"), gpg_errstr(rc));
+               release_revocation_reason_info( reason );
                return changed;
            }
            changed = 1; /* we changed the keyblock */
@@ -1897,6 +1952,7 @@ menu_revkey( KBNODE pub_keyblock, KBNODE sec_keyblock )
     if( upd_trust )
        clear_trust_checked_flag( mainpk );
 
+    release_revocation_reason_info( reason );
     return changed;
 }
 
index af288b3..b6c6cc7 100644 (file)
@@ -1,5 +1,5 @@
 /* keygen.c - generate a key pair
- *     Copyright (C) 1998, 1999 Free Software Foundation, Inc.
+ *     Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
 #include "status.h"
 #include "i18n.h"
 
+enum para_name {
+  pKEYTYPE,
+  pKEYLENGTH,
+  pSUBKEYTYPE,
+  pSUBKEYLENGTH,
+  pNAMEREAL,
+  pNAMEEMAIL,
+  pNAMECOMMENT,
+  pUSERID,
+  pEXPIREDATE,
+  pKEYEXPIRE, /* in n seconds */
+  pSUBKEYEXPIRE, /* in n seconds */
+  pPASSPHRASE,
+  pPASSPHRASE_DEK,
+  pPASSPHRASE_S2K
+};
+
+struct para_data_s {
+    struct para_data_s *next;
+    int lnr;
+    enum para_name key;
+    union {
+       DEK *dek;
+       STRING2KEY *s2k;
+       u32 expire;
+       char value[1];
+    } u;
+};
+
+struct output_control_s {
+    int lnr;
+    int dryrun;
+    int use_files;
+    struct {
+       char  *fname;
+       char  *newfname;
+       IOBUF stream;
+       armor_filter_context_t afx;
+    } pub;
+    struct {
+       char  *fname;
+       char  *newfname;
+       IOBUF stream;
+       armor_filter_context_t afx;
+    } sec;
+};
+
+
+static void do_generate_keypair( struct para_data_s *para,
+                                struct output_control_s *outctrl );
+static int  write_keyblock( IOBUF out, KBNODE node );
+
 
 static void
 write_uid( KBNODE root, const char *s )
@@ -43,7 +95,7 @@ write_uid( KBNODE root, const char *s )
     size_t n = strlen(s);
 
     pkt->pkttype = PKT_USER_ID;
-    pkt->pkt.user_id = gcry_xmalloc( sizeof *pkt->pkt.user_id + n - 1 );
+    pkt->pkt.user_id = gcry_xcalloc( 1, sizeof *pkt->pkt.user_id + n - 1 );
     pkt->pkt.user_id->len = n;
     strcpy(pkt->pkt.user_id->name, s);
     add_kbnode( root, new_kbnode( pkt ) );
@@ -84,8 +136,9 @@ keygen_add_std_prefs( PKT_signature *sig, void *opaque )
     keygen_add_key_expire( sig, opaque );
 
     buf[0] = GCRY_CIPHER_TWOFISH;
-    buf[1] = GCRY_CIPHER_CAST5;
-    build_sig_subpkt( sig, SIGSUBPKT_PREF_SYM, buf, 2 );
+    buf[1] = GCRY_CIPHER_BLOWFISH;
+    buf[2] = GCRY_CIPHER_CAST5;
+    build_sig_subpkt( sig, SIGSUBPKT_PREF_SYM, buf, 3 );
 
     buf[0] = GCRY_MD_RMD160;
     buf[1] = GCRY_MD_SHA1;
@@ -189,6 +242,7 @@ write_keybinding( KBNODE root, KBNODE pub_root, PKT_secret_key *sk )
 }
 
 
+
 static int
 key_from_sexp( GCRY_MPI *array,
               GCRY_SEXP sexp, const char *topname, const char *elems )
@@ -252,7 +306,7 @@ factors_from_sexp( MPI **retarray, GCRY_SEXP sexp )
     for( n=0; (l2 = gcry_sexp_enum( list, &ctx, 0 )); n++ )
        ;
 
-    array = gcry_calloc( n, sizeof *array );
+    array = gcry_xcalloc( n, sizeof *array );
     if( !array )
        return GCRYERR_NO_MEM;
 
@@ -275,10 +329,10 @@ factors_from_sexp( MPI **retarray, GCRY_SEXP sexp )
 }
 
 
+
 static int
 gen_elg(int algo, unsigned nbits, KBNODE pub_root, KBNODE sec_root, DEK *dek,
-       STRING2KEY *s2k, PKT_secret_key **ret_sk, u32 expireval,
-                                                       int version )
+       STRING2KEY *s2k, PKT_secret_key **ret_sk, u32 expireval )
 {
     int rc;
     int i;
@@ -289,6 +343,18 @@ gen_elg(int algo, unsigned nbits, KBNODE pub_root, KBNODE sec_root, DEK *dek,
     char buf[100];
     GCRY_SEXP s_parms, s_key;
 
+    assert( is_ELGAMAL(algo) );
+
+    if( nbits < 512 ) {
+       nbits = 1024;
+       log_info(_("keysize invalid; using %u bits\n"), nbits );
+    }
+
+    if( (nbits % 32) ) {
+       nbits = ((nbits + 31) / 32) * 32;
+       log_info(_("keysize rounded up to %u bits\n"), nbits );
+    }
+
     sprintf(buf, "%u", nbits );
     s_parms = SEXP_CONS( SEXP_NEW( "genkey", 0 ),
                 SEXP_CONS( SEXP_NEW(algo == GCRY_PK_ELG_E ? "openpgp-elg" :
@@ -303,10 +369,11 @@ gen_elg(int algo, unsigned nbits, KBNODE pub_root, KBNODE sec_root, DEK *dek,
        return rc;
     }
 
+
     sk = gcry_xcalloc( 1, sizeof *sk );
     pk = gcry_xcalloc( 1, sizeof *pk );
     sk->timestamp = pk->timestamp = make_timestamp();
-    sk->version = pk->version = version;
+    sk->version = pk->version = 4;
     if( expireval ) {
        sk->expiredate = pk->expiredate = sk->timestamp + expireval;
     }
@@ -361,7 +428,6 @@ gen_elg(int algo, unsigned nbits, KBNODE pub_root, KBNODE sec_root, DEK *dek,
     for(i=0; factors[i]; i++ ) {
        add_kbnode( sec_root,
                    make_mpi_comment_node("#:ELG_factor:", factors[i] ));
-       gcry_mpi_release(factors[i]);
     }
 
     return 0;
@@ -372,7 +438,7 @@ gen_elg(int algo, unsigned nbits, KBNODE pub_root, KBNODE sec_root, DEK *dek,
  * Generate a DSA key
  */
 static int
-gen_dsa(unsigned nbits, KBNODE pub_root, KBNODE sec_root, DEK *dek,
+gen_dsa(unsigned int nbits, KBNODE pub_root, KBNODE sec_root, DEK *dek,
            STRING2KEY *s2k, PKT_secret_key **ret_sk, u32 expireval )
 {
     int rc;
@@ -384,8 +450,15 @@ gen_dsa(unsigned nbits, KBNODE pub_root, KBNODE sec_root, DEK *dek,
     char buf[100];
     GCRY_SEXP s_parms, s_key;
 
-    if( nbits > 1024 )
+    if( nbits > 1024 || nbits < 512 ) {
        nbits = 1024;
+       log_info(_("keysize invalid; using %u bits\n"), nbits );
+    }
+
+    if( (nbits % 64) ) {
+       nbits = ((nbits + 63) / 64) * 64;
+       log_info(_("keysize rounded up to %u bits\n"), nbits );
+    }
 
     sprintf(buf, "%u", nbits );
     s_parms = SEXP_CONS( SEXP_NEW( "genkey", 0 ),
@@ -400,6 +473,7 @@ gen_dsa(unsigned nbits, KBNODE pub_root, KBNODE sec_root, DEK *dek,
        return rc;
     }
 
+
     sk = gcry_xcalloc( 1, sizeof *sk );
     pk = gcry_xcalloc( 1, sizeof *pk );
     sk->timestamp = pk->timestamp = make_timestamp();
@@ -464,10 +538,91 @@ gen_dsa(unsigned nbits, KBNODE pub_root, KBNODE sec_root, DEK *dek,
                    make_mpi_comment_node("#:DSA_factor:", factors[i] ));
 
     /* fixme: Merge this with the elg-generate function and release
-     * some more stuff */
+     * some more stuff (memory-leak) */
     return 0;
 }
 
+#if 0
+static int
+gen_rsa(int algo, unsigned nbits, KBNODE pub_root, KBNODE sec_root, DEK *dek,
+       STRING2KEY *s2k, PKT_secret_key **ret_sk, u32 expireval )
+{
+    int rc;
+    PACKET *pkt;
+    PKT_secret_key *sk;
+    PKT_public_key *pk;
+    MPI skey[4];
+    MPI *factors;
+
+    assert( is_RSA(algo) );
+
+    if( nbits < 1024 ) {
+       nbits = 1024;
+       log_info(_("keysize invalid; using %u bits\n"), nbits );
+    }
+
+    if( (nbits % 32) ) {
+       nbits = ((nbits + 31) / 32) * 32;
+       log_info(_("keysize rounded up to %u bits\n"), nbits );
+    }
+
+    rc = pubkey_generate( algo, nbits, skey, &factors );
+    if( rc ) {
+       log_error("pubkey_generate failed: %s\n", gpg_errstr(rc) );
+       return rc;
+    }
+
+    sk = gcry_xcalloc( 1, sizeof *sk );
+    pk = gcry_xcalloc( 1, sizeof *pk );
+    sk->timestamp = pk->timestamp = make_timestamp();
+    sk->version = pk->version = 4;
+    if( expireval ) {
+       sk->expiredate = pk->expiredate = sk->timestamp + expireval;
+    }
+    sk->pubkey_algo = pk->pubkey_algo = algo;
+                      pk->pkey[0] = mpi_copy( skey[0] );
+                      pk->pkey[1] = mpi_copy( skey[1] );
+    sk->skey[0] = skey[0];
+    sk->skey[1] = skey[1];