diff options
author | Werner Koch <wk@gnupg.org> | 2000-07-14 17:34:52 +0000 |
---|---|---|
committer | Werner Koch <wk@gnupg.org> | 2000-07-14 17:34:52 +0000 |
commit | 74386120dad6b3da62db37f7044267c8ef34689b (patch) | |
tree | 16fc58b6817d55a9556192a064d573ea8a174a93 | |
parent | eef468f4897c6d46fe46c2a9635151e2257e3dd1 (diff) | |
download | libgcrypt-74386120dad6b3da62db37f7044267c8ef34689b.tar.gz |
See ChangeLog: Fri Jul 14 19:38:23 CEST 2000 Werner Koch
-rw-r--r-- | ChangeLog | 65 | ||||
-rw-r--r-- | acconfig.h | 2 | ||||
-rw-r--r-- | acinclude.m4 | 119 | ||||
-rw-r--r-- | cipher/ChangeLog | 82 | ||||
-rw-r--r-- | cipher/Makefile.am | 19 | ||||
-rw-r--r-- | cipher/blowfish.c | 9 | ||||
-rw-r--r-- | cipher/cast5.c | 10 | ||||
-rw-r--r-- | cipher/des.c | 9 | ||||
-rw-r--r-- | cipher/dsa.c | 19 | ||||
-rw-r--r-- | cipher/elgamal.c | 141 | ||||
-rw-r--r-- | cipher/md.c | 10 | ||||
-rw-r--r-- | cipher/md5.c | 8 | ||||
-rw-r--r-- | cipher/primegen.c | 25 | ||||
-rw-r--r-- | cipher/pubkey.c | 59 | ||||
-rw-r--r-- | cipher/random.c | 204 | ||||
-rw-r--r-- | cipher/rmd160.c | 8 | ||||
-rw-r--r-- | cipher/rndegd.c | 11 | ||||
-rw-r--r-- | cipher/rndunix.c | 53 | ||||
-rw-r--r-- | cipher/rndw32.c | 739 | ||||
-rw-r--r-- | cipher/rsa.c | 375 | ||||
-rw-r--r-- | cipher/rsa.h | 36 | ||||
-rw-r--r-- | cipher/sha1.c | 8 | ||||
-rw-r--r-- | cipher/tiger.c | 8 | ||||
-rw-r--r-- | cipher/twofish.c | 28 | ||||
-rw-r--r-- | configure.in | 118 | ||||
-rw-r--r-- | jnlib/ChangeLog | 6 | ||||
-rw-r--r-- | jnlib/argparse.c | 4 | ||||
-rw-r--r-- | jnlib/dotlock.c | 40 | ||||
-rw-r--r-- | jnlib/dotlock.h | 1 | ||||
-rw-r--r-- | src/ChangeLog | 12 | ||||
-rw-r--r-- | src/Makefile.am | 6 | ||||
-rw-r--r-- | src/gcrypt-config.in | 6 | ||||
-rw-r--r-- | src/gcrypt.h | 8 | ||||
-rw-r--r-- | src/secmem.c | 16 | ||||
-rw-r--r-- | src/sexp.c | 91 |
35 files changed, 2113 insertions, 242 deletions
@@ -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@> @@ -53,6 +53,8 @@ #undef HAVE_STPCPY +#undef HAVE_MLOCK + #undef BIG_ENDIAN_HOST #undef LITTLE_ENDIAN_HOST diff --git a/acinclude.m4 b/acinclude.m4 index 20c92be5..9f8bfd01 100644 --- a/acinclude.m4 +++ b/acinclude.m4 @@ -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. diff --git a/cipher/ChangeLog b/cipher/ChangeLog index 49595a93..877a2ad2 100644 --- a/cipher/ChangeLog +++ b/cipher/ChangeLog @@ -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. diff --git a/cipher/Makefile.am b/cipher/Makefile.am index aa766bbc..9792419f 100644 --- a/cipher/Makefile.am +++ b/cipher/Makefile.am @@ -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 - diff --git a/cipher/blowfish.c b/cipher/blowfish.c index e7f047ff..2bdb3b5e 100644 --- a/cipher/blowfish.c +++ b/cipher/blowfish.c @@ -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"; diff --git a/cipher/cast5.c b/cipher/cast5.c index aaa0a42e..64f6bb0e 100644 --- a/cipher/cast5.c +++ b/cipher/cast5.c @@ -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"; diff --git a/cipher/des.c b/cipher/des.c index af5b5845..9c3c5419 100644 --- a/cipher/des.c +++ b/cipher/des.c @@ -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; diff --git a/cipher/dsa.c b/cipher/dsa.c index 1f132ae0..255fa372 100644 --- a/cipher/dsa.c +++ b/cipher/dsa.c @@ -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 */ diff --git a/cipher/elgamal.c b/cipher/elgamal.c index 02995e02..f2c029b3 100644 --- a/cipher/elgamal.c +++ b/cipher/elgamal.c @@ -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; diff --git a/cipher/md.c b/cipher/md.c index 98795206..e8ac8ac2 100644 --- a/cipher/md.c +++ b/cipher/md.c @@ -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 ) { diff --git a/cipher/md5.c b/cipher/md5.c index 161d4430..c4351f1f 100644 --- a/cipher/md5.c +++ b/cipher/md5.c @@ -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"; } diff --git a/cipher/primegen.c b/cipher/primegen.c index 2f16b083..f5dca859 100644 --- a/cipher/primegen.c +++ b/cipher/primegen.c @@ -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; } } diff --git a/cipher/pubkey.c b/cipher/pubkey.c index 3ace1d83..b139720d 100644 --- a/cipher/pubkey.c +++ b/cipher/pubkey.c @@ -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; } diff --git a/cipher/random.c b/cipher/random.c index 38991a18..f8faeebf 100644 --- a/cipher/random.c +++ b/cipher/random.c @@ -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. * @@ -36,15 +36,22 @@ #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 } diff --git a/cipher/rmd160.c b/cipher/rmd160.c index 7b230087..fb9d6fa5 100644 --- a/cipher/rmd160.c +++ b/cipher/rmd160.c @@ -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"; } diff --git a/cipher/rndegd.c b/cipher/rndegd.c index 4d5f0ef3..f6870cdd 100644 --- a/cipher/rndegd.c +++ b/cipher/rndegd.c @@ -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 ) { diff --git a/cipher/rndunix.c b/cipher/rndunix.c index 4ab9f65f..99a416ea 100644 --- a/cipher/rndunix.c +++ b/cipher/rndunix.c @@ -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__ @@ -91,6 +91,10 @@ #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 */ @@ -100,7 +104,13 @@ #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() ) diff --git a/cipher/rndw32.c b/cipher/rndw32.c index c1045851..25830693 100644 --- a/cipher/rndw32.c +++ b/cipher/rndw32.c @@ -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. * @@ -16,6 +17,46 @@ * 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> @@ -27,10 +68,16 @@ #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) @@ -39,6 +86,10 @@ #endif +static int debug_me; + +#ifdef USE_ENTROPY_DLL + #define WIN32_SLOW_SEEDER 0 #define WIN32_FAST_SEEDER 1 @@ -53,6 +104,17 @@ #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 index 00000000..5d852cd8 --- /dev/null +++ b/cipher/rsa.c @@ -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 index 00000000..8b60ecbb --- /dev/null +++ b/cipher/rsa.h @@ -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*/ diff --git a/cipher/sha1.c b/cipher/sha1.c index f231e37b..aa3ac092 100644 --- a/cipher/sha1.c +++ b/cipher/sha1.c @@ -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"; } diff --git a/cipher/tiger.c b/cipher/tiger.c index 0e42160a..abe449ab 100644 --- a/cipher/tiger.c +++ b/cipher/tiger.c @@ -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"; } diff --git a/cipher/twofish.c b/cipher/twofish.c index 1eea4b8e..5766021c 100644 --- a/cipher/twofish.c +++ b/cipher/twofish.c @@ -34,10 +34,6 @@ /* 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; } diff --git a/configure.in b/configure.in index fddb93d2..b3e44ec7 100644 --- a/configure.in +++ b/configure.in @@ -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 diff --git a/jnlib/ChangeLog b/jnlib/ChangeLog index a41901bf..5bb8faf3 100644 --- a/jnlib/ChangeLog +++ b/jnlib/ChangeLog @@ -1,3 +1,9 @@ +Fri Jul 14 19:38:23 CEST 2000 Werner Koch <wk@> + + * argparse.c (default_strusage): Changed year of default copyright. + + * dotlock.c (disable_dotlock): New. + Mon Jan 24 13:04:28 CET 2000 Werner Koch <wk@gnupg.de> * README: New. diff --git a/jnlib/argparse.c b/jnlib/argparse.c index 3f778053..6293d3eb 100644 --- a/jnlib/argparse.c +++ b/jnlib/argparse.c @@ -1,5 +1,5 @@ /* [argparse.c wk 17.06.97] Argument Parser for option handling - * Copyright (C) 1998,1999 Free Software Foundation, Inc. + * Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc. * This file is part of GnuPG. * * GnuPG is free software; you can redistribute it and/or modify @@ -899,7 +899,7 @@ strusage( int level ) switch( level ) { case 11: p = "foo"; break; case 13: p = "0.0"; break; - case 14: p = "Copyright (C) 1999 Free Software Foundation, Inc."; break; + case 14: p = "Copyright (C) 2000 Free Software Foundation, Inc."; break; case 15: p = "This program comes with ABSOLUTELY NO WARRANTY.\n" "This is free software, and you are welcome to redistribute it\n" diff --git a/jnlib/dotlock.c b/jnlib/dotlock.c index 8e61f7a0..29ab65df 100644 --- a/jnlib/dotlock.c +++ b/jnlib/dotlock.c @@ -1,5 +1,5 @@ /* dotlock.c - dotfile locking - * Copyright (C) 1998,2000 Free Software Foundation, Inc. + * Copyright (C) 1998, 2000 Free Software Foundation, Inc. * * This file is part of GnuPG. * @@ -42,14 +42,22 @@ struct dotlock_handle { char *tname; /* name of lockfile template */ char *lockname; /* name of the real lockfile */ int locked; /* lock status */ + int disable; /* locking */ }; static DOTLOCK all_lockfiles; +static int never_lock; static int read_lockfile( const char *name ); static void remove_lockfiles(void); +void +disable_dotlock(void) +{ + never_lock = 1; +} + /**************** * Create a lockfile with the given name and return an object of * type DOTLOCK which may be used later to actually do the lock. @@ -88,6 +96,16 @@ create_dotlock( const char *file_to_lock ) return NULL; h = jnlib_xcalloc( 1, sizeof *h ); + if( never_lock ) { + h->disable = 1; + #ifdef _REENTRANT + /* fixme: aquire mutex on all_lockfiles */ + #endif + h->next = all_lockfiles; + all_lockfiles = h; + return h; + } + #ifndef HAVE_DOSISH_SYSTEM sprintf( pidstr, "%10d\n", (int)getpid() ); /* fixme: add the hostname to the second line (FQDN or IP addr?) */ @@ -191,6 +209,10 @@ make_dotlock( DOTLOCK h, long timeout ) const char *maybe_dead=""; int backoff=0; + if( h->disable ) { + return 0; + } + if( h->locked ) { log_debug("oops, `%s' is already locked\n", h->lockname ); return 0; @@ -259,6 +281,10 @@ release_dotlock( DOTLOCK h ) #else int pid; + if( h->disable ) { + return 0; + } + if( !h->locked ) { log_debug("oops, `%s' is not locked\n", h->lockname ); return 0; @@ -333,11 +359,13 @@ remove_lockfiles() while( h ) { h2 = h->next; - if( h->locked ) - unlink( h->lockname ); - unlink(h->tname); - jnlib_free(h->tname); - jnlib_free(h->lockname); + if( !h->disable ) { + if( h->locked ) + unlink( h->lockname ); + unlink(h->tname); + jnlib_free(h->tname); + jnlib_free(h->lockname); + } jnlib_free(h); h = h2; } diff --git a/jnlib/dotlock.h b/jnlib/dotlock.h index d54219e2..74ac876f 100644 --- a/jnlib/dotlock.h +++ b/jnlib/dotlock.h @@ -24,6 +24,7 @@ struct dotlock_handle; typedef struct dotlock_handle *DOTLOCK; +void disable_dotlock(void); DOTLOCK create_dotlock( const char *file_to_lock ); int make_dotlock( DOTLOCK h, long timeout ); int release_dotlock( DOTLOCK h ); diff --git a/src/ChangeLog b/src/ChangeLog index dda6d393..83d1517c 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,15 @@ +Fri Jul 14 19:38:23 CEST 2000 Werner Koch <wk@> + + * gcrypt.h (gcry_md_start_debug, gcry_md_stop_debug): New. + (gcry_ctl_cmds): New control values + + * sexp.c (gcry_sexp_sscan): Add hex format parsing. + + * secmem.c (lock_pool): Check for ENOSYS return my mlock() on old SCOs. + (pool_is_mmapped): Made volatile. + (lock_pool): No more warning for QNX. By Sam Roberts. + (lock_pool,secmem_init): Additional check for dropped privs. + 2000-03-21 09:18:48 Werner Koch (wk@habibti.gnupg.de) * gcrypt.h (gcry_md_setkey): New. diff --git a/src/Makefile.am b/src/Makefile.am index 0681e918..359bc1cf 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -12,9 +12,9 @@ bin_SCRIPTS = gcrypt-config m4datadir = $(datadir)/aclocal m4data_DATA = gcrypt.m4 -noinst_PROGRAMS = testapi -#sexp_SOURCES = sexp.c mpiapi.c -#sexp_LDADD = ../cipher/libcipher.la ../mpi/libmpi.la ../util/libutil.la ./libgcrypt.la @INTLLIBS@ +noinst_PROGRAMS = testapi sexp +sexp_SOURCES = sexp.c +sexp_LDADD = libgcrypt.la testapi_SOURCES = testapi.c testapi_LDADD = libgcrypt.la diff --git a/src/gcrypt-config.in b/src/gcrypt-config.in index ab577a91..0f7fffdd 100644 --- a/src/gcrypt-config.in +++ b/src/gcrypt-config.in @@ -1,12 +1,12 @@ #!/bin/sh +prefix=@prefix@ +exec_prefix=@exec_prefix@ +exec_prefix_set=no gcrypt_libs="@GCRYPT_LIBS@" gcrypt_cflags="@GCRYPT_CFLAGS@" -prefix=@prefix@ -exec_prefix=@exec_prefix@ -exec_prefix_set=no usage() { diff --git a/src/gcrypt.h b/src/gcrypt.h index 416505df..aaeb95b1 100644 --- a/src/gcrypt.h +++ b/src/gcrypt.h @@ -128,6 +128,8 @@ enum gcry_ctl_cmds { GCRYCTL_RESUME_SECMEM_WARN = 29, GCRYCTL_DROP_PRIVS = 30, GCRYCTL_ENABLE_M_GUARD = 31, + GCRYCTL_START_DUMP = 32, + GCRYCTL_STOP_DUMP = 33, }; int gcry_control( enum gcry_ctl_cmds, ... ); @@ -411,6 +413,12 @@ int gcry_md_map_name( const char* name ); #define gcry_md_test_algo(a) \ gcry_md_algo_info( (a), GCRYCTL_TEST_ALGO, NULL, NULL ) +#define gcry_md_start_debug(a,b) \ + gcry_md_ctl( (a), GCRYCTL_START_DUMP, (b), 0 ) +#define gcry_md_stop_debug(a,b) \ + gcry_md_ctl( (a), GCRYCTL_STOP_DUMP, (b), 0 ) + + /********************************************* ******* random generating functions ******* *********************************************/ diff --git a/src/secmem.c b/src/secmem.c index 388fa91d..56df4f8f 100644 --- a/src/secmem.c +++ b/src/secmem.c @@ -1,5 +1,5 @@ /* secmem.c - memory allocation from a secure heap - * Copyright (C) 1998,1999 Free Software Foundation, Inc. + * Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc. * * This file is part of GnuPG. * @@ -56,7 +56,7 @@ struct memblock_struct { static void *pool; static volatile int pool_okay; /* may be checked in an atexit function */ -static int pool_is_mmapped; +static volatile int pool_is_mmapped; static size_t poolsize; /* allocated length */ static size_t poollen; /* used length */ static MEMBLOCK *unused_blocks; @@ -126,7 +126,9 @@ lock_pool( void *p, size_t n ) #endif if( uid && !geteuid() ) { - if( setuid( uid ) || getuid() != geteuid() ) + /* check that we really dropped the privs. + * Note: setuid(0) should always fail */ + if( setuid( uid ) || getuid() != geteuid() || !setuid(0) ) log_fatal("failed to reset uid: %s\n", strerror(errno)); } @@ -143,6 +145,12 @@ lock_pool( void *p, size_t n ) show_warning = 1; } + #elif defined ( __QNX__ ) + /* QNX does not page at all, so the whole secure memory stuff does + * not make much sense. However it is still of use because it + * wipes out the memory on a free(). + * Therefore it is sufficient to suppress the warning + */ #else log_info("Please note that you don't have secure memory on this system\n"); #endif @@ -252,7 +260,7 @@ secmem_init( size_t n ) disable_secmem=1; uid = getuid(); if( uid != geteuid() ) { - if( setuid( uid ) || getuid() != geteuid() ) + if( setuid( uid ) || getuid() != geteuid() || !setuid(0) ) log_fatal("failed to drop setuid\n" ); } #endif @@ -1,5 +1,5 @@ /* sexp.c - S-Expression handling - * Copyright (C) 1999 Free Software Foundation, Inc. + * Copyright (C) 1999, 2000 Free Software Foundation, Inc. * * This file is part of GnuPG. * @@ -571,6 +571,34 @@ gcry_sexp_cdr_mpi( GCRY_SEXP list, int mpifmt ) } + + + +static int +hextobyte( const byte *s ) +{ + int c=0; + + if( *s >= '0' && *s <= '9' ) + c = 16 * (*s - '0'); + else if( *s >= 'A' && *s <= 'F' ) + c = 16 * (10 + *s - 'A'); + else if( *s >= 'a' && *s <= 'f' ) { + c = 16 * (10 + *s - 'a'); + } + s++; + if( *s >= '0' && *s <= '9' ) + c += *s - '0'; + else if( *s >= 'A' && *s <= 'F' ) + c += 10 + *s - 'A'; + else if( *s >= 'a' && *s <= 'f' ) { + c += 10 + *s - 'a'; + } + return c; +} + + + /**************** * Scan the provided buffer and return the S expression in our internal * format. Returns a newly allocated expression. If erroff is not NULL and @@ -592,6 +620,7 @@ gcry_sexp_sscan( GCRY_SEXP *retsexp, const char *buffer, const char *hexfmt=NULL; const char *base64=NULL; const char *disphint=NULL; + int hexcount=0; int quoted_esc=0; int datalen=0; int first; @@ -603,7 +632,7 @@ gcry_sexp_sscan( GCRY_SEXP *retsexp, const char *buffer, tail = head = NULL; first = 0; for(p=buffer,n=length; n; p++, n-- ) { - if( tokenp ) { + if( tokenp && !hexfmt ) { if( strchr( tokenchars, *p ) ) continue; } @@ -657,8 +686,46 @@ gcry_sexp_sscan( GCRY_SEXP *retsexp, const char *buffer, } } else if( hexfmt ) { - if( *p == '#' ) - hexfmt = NULL; + if( isxdigit( *p ) ) + hexcount++; + else if( *p == '#' ) { + int i; + + if( (hexcount & 1) ) { + *erroff = p - buffer; + return -12; /* odd number of hex digits */ + } + + /* make a new list entry */ + datalen = hexcount/2; + node = g10_xcalloc( 1, sizeof *node + datalen ); + if( first ) { /* stuff it into the first node */ + first = 0; + node->up = tail; + tail->u.list = node; + } + else { + node->up = tail->up; + tail->next = node; + } + tail = node; + /* and fill in the value (we store the value in the node)*/ + node->type = ntDATA; + node->u.data.len = datalen; + for(i=0, hexfmt++; hexfmt < p; hexfmt++ ) { + if( isspace( *hexfmt ) ) + continue; + node->u.data.d[i++] = hextobyte( hexfmt ); + hexfmt++; + } + assert( hexfmt == p ); + assert( i == datalen ); + hexfmt = NULL; + } + else if( !isspace( *p ) ) { + *erroff = p - buffer; + return -11; /* invalid hex character */ + } } else if( base64 ) { if( *p == '|' ) @@ -706,6 +773,7 @@ gcry_sexp_sscan( GCRY_SEXP *retsexp, const char *buffer, else if( *p == '#' ) { digptr = NULL; /* we ignore the optional length */ hexfmt = p; + hexcount = 0; } else if( *p == '|' ) { digptr = NULL; /* we ignore the optional length */ @@ -751,8 +819,10 @@ gcry_sexp_sscan( GCRY_SEXP *retsexp, const char *buffer, quoted = p; quoted_esc = 0; } - else if( *p == '#' ) + else if( *p == '#' ) { hexfmt = p; + hexcount = 0; + } else if( *p == '|' ) base64 = p; else if( *p == '[' ) { @@ -821,16 +891,17 @@ gcry_sexp_sprint( GCRY_SEXP sexp, int mode, char *buffer, size_t maxlength ) -#if 0 +#if 1 /***********************************************************/ const char * strusage( int level ) { - return default_strusage(level); + return "?"; } +#if 0 static int sexp_to_pk( GCRY_SEXP sexp, int want_private, MPI **retarray, int *retalgo) { @@ -909,7 +980,7 @@ sexp_to_pk( GCRY_SEXP sexp, int want_private, MPI **retarray, int *retalgo) return 0; } - +#endif int @@ -921,7 +992,7 @@ main(int argc, char **argv) FILE *fp; GCRY_SEXP s_pk, s_dsa, s_p, s_q, s_g, s_y, sexp; - #if 0 + #if 1 fp = stdin; n = fread(buffer, 1, 5000, fp ); rc = gcry_sexp_sscan( &sexp, buffer, n, &erroff ); @@ -969,7 +1040,7 @@ main(int argc, char **argv) dump_sexp( s1 ); } - #if 1 + #if 0 { int i,rc, algo; GCRY_MPI *array; |