See ChangeLog: Mon Sep 18 16:35:45 CEST 2000 Werner Koch
authorWerner Koch <wk@gnupg.org>
Mon, 18 Sep 2000 14:35:34 +0000 (14:35 +0000)
committerWerner Koch <wk@gnupg.org>
Mon, 18 Sep 2000 14:35:34 +0000 (14:35 +0000)
46 files changed:
ChangeLog
NEWS
VERSION
acconfig.h
acinclude.m4
cipher/ChangeLog
cipher/Makefile.am
cipher/pubkey.c
cipher/random.c
cipher/rndlinux.c
cipher/rndunix.c
cipher/rsa.c
configure.in
g10/ChangeLog
g10/build-packet.c
g10/encode.c
g10/free-packet.c
g10/getkey.c
g10/gpg.c
g10/import.c
g10/keydb.h
g10/keyedit.c
g10/keygen.c
g10/keyid.c
g10/main.h
g10/misc.c
g10/openfile.c
g10/options.h
g10/packet.h
g10/parse-packet.c
g10/passphrase.c
g10/pkclist.c
g10/pubkey-enc.c
g10/ringedit.c
g10/seckey-cert.c
g10/sig-check.c
g10/sign.c
g10/skclist.c
g10/trustdb.c
include/iobuf.h
tools/ChangeLog
tools/ring-a-party
util/ChangeLog
util/iobuf.c
util/miscutil.c
util/strgutil.c

index 96c1e81..f3fbca8 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,20 @@
+Mon Sep 18 16:35:45 CEST 2000  Werner Koch  <wk@openit.de>
+
+        * acinclude.m4 (GNUPG_CHECK_MLOCK):  Removed that silly mkdir().
+
+        * configure.in:  Changes to allow for Solaris random device.
+        By Nils Ellmenreich.
+        (--with-egd-socket): New.
+
+        * configure.in (GNUPG_HOMEDIR): New.
+
+        * configure.in: Check for fstat64 and fopen64
+
+        * acinclude.m4 (GNUPG_CHECK_FAQPROG): New.
+        * configure.in: Test for this.
+
+        * configure.in (DYNLINK_MOD_CFLAGS): Fix by David Champion.
+
 Tue Aug 22 14:31:15 CEST 2000  Werner Koch  <wk@openit.de>
 
         Version 1.1.1
diff --git a/NEWS b/NEWS
index 60180fc..d5367ae 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -1,8 +1,38 @@
-Noteworthy changes in version 1.1.1
------------------------------------
+Noteworthy changes in the current CVS HEAD
+------------------------------------------
 
     THIS IS A DEVELOPMENT VERSION; see README-alpha
 
+    * Fixed problems with piping to/from other MS-Windows software
+
+    * Expiration time of the primary key can be changed again.
+
+    * Revoked user IDs are now marked in the output of --list-key
+
+    * New options --merge-only and --try-all-secrets.
+
+    * New configuration option --with-egd-socket.
+
+    * The --trusted-key option is back after it left us with 0.9.5
+     
+    * RSA is supported. Key generation does not yet work but will come
+      soon.
+    
+    * CAST5 and SHA-1 are now the default algorithms to protect the key
+      and for symmetric-only encryption. This should solve a couple
+      of compatibility problems because the old algorithms are optional
+      according to RFC2440
+
+    * Twofish and MDC enhanced encryption is now used.  PGP 7 supports 
+      this.  Older versions of GnuPG don't support it, so they should be
+      upgraded to at least 1.0.2
+      
+      
+    
+
+Noteworthy changes in version 1.1.1
+-----------------------------------
+
     * Add gpg-agent.
 
     * Removed option --emulate-checksum-bug
diff --git a/VERSION b/VERSION
index 8cfbc90..bff94dd 100644 (file)
--- a/VERSION
+++ b/VERSION
@@ -1 +1,2 @@
-1.1.1
\ No newline at end of file
+1.1.1a
+
index a2c9128..3c1d32e 100644 (file)
@@ -74,6 +74,8 @@
 #undef NAME_OF_DEV_URANDOM
 /* Linux has an ioctl */
 #undef HAVE_DEV_RANDOM_IOCTL
+/* see cipher/rndegd.c */
+#undef EGD_SOCKET_NAME
 
 
 #undef USE_DYNAMIC_LINKING
index 9f8bfd0..7291c1d 100644 (file)
@@ -67,6 +67,32 @@ AC_DEFUN(GNUPG_CHECK_GNUMAKE,
     fi
   ])
 
+dnl GNUPG_CHECK_FAQPROG
+dnl
+AC_DEFUN(GNUPG_CHECK_FAQPROG,
+  [ AC_MSG_CHECKING(for faqprog.pl)
+    if faqprog.pl -V 2>/dev/null | grep '^faqprog.pl ' >/dev/null 2>&1; then
+        working_faqprog=yes
+        FAQPROG="faqprog.pl"
+    else 
+       working_faqprog=no
+        FAQPROG=": "
+    fi
+    AC_MSG_RESULT($working_faqprog)
+    AC_SUBST(FAQPROG)
+    AM_CONDITIONAL(WORKING_FAQPROG, test "$working_faqprog" = "yes" )
+
+    if test $working_faqprog = no; then
+       AC_MSG_WARN([[
+***
+*** It seems that the faqprog.pl program is not installed.
+*** Unless you do not change the source of the FAQs it is not required.
+*** The working version of this utility should be available at:
+***   ftp://ftp.gnupg.org/pub/gcrypt/contrib/faqprog.pl
+***]])
+    fi
+  ])       
+
 
 
 dnl GNUPG_LINK_FILES( SRC, DEST )
@@ -358,7 +384,7 @@ define(GNUPG_CHECK_MLOCK,
                     #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
index e37e3c3..2e4ebe5 100644 (file)
@@ -1,3 +1,21 @@
+Mon Sep 18 16:35:45 CEST 2000  Werner Koch  <wk@openit.de>
+
+        * rndlinux.c (open_device): Loose random device checking.
+        By Nils Ellmenreich.
+
+        * random.c (fast_random_poll): Check ENOSYS for getrusage.
+        * rndunix.c:  Add 2 sources for QNX. By Sam Roberts.
+
+        * pubkey.c (gcry_pk_algo_info): Add GCRYCTL_GET_ALGO_USAGE.
+
+        * rsa.c: Changed the comment about the patent.
+        (secret): Speed up by using the CRT.  For a 2k keys this
+        is about 3 times faster.
+        (stronger_key_check): New but unused code to check the secret key.
+        * Makefile.am: Included rsa.[ch].
+        * pubkey.c: Enabled RSA support.
+        (pubkey_get_npkey): Removed RSA workaround.
+
 Mon Jul 31 10:04:47 CEST 2000  Werner Koch  <wk@openit.de>
 
   * pubkey.c: Replaced all gcry_sexp_{car,cdr}_{data,mpi} by the new
index 2ed370f..26de925 100644 (file)
@@ -50,6 +50,7 @@ libcipher_la_SOURCES = cipher.c  \
                 rmd.h          \
                 dsa.h          \
                 dsa.c          \
+                rsa.c rsa.h    \
                 smallprime.c   \
                 construct.c
 
index bbf592b..3dab336 100644 (file)
@@ -30,9 +30,7 @@
 #include "cipher.h"
 #include "elgamal.h"
 #include "dsa.h"
-#if 0
 #include "rsa.h"
-#endif
 #include "dynload.h"
 
 /* FIXME: use set_lasterr() */
@@ -196,7 +194,6 @@ 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,
@@ -248,7 +245,6 @@ setup_pubkey_table(void)
     if( !pubkey_table[i].name )
        BUG();
     i++;
-  #endif
 
     for( ; i < TABLE_SIZE; i++ )
        pubkey_table[i].name = NULL;
@@ -433,8 +429,6 @@ pubkey_get_npkey( int algo )
            if( pubkey_table[i].algo == algo )
                return pubkey_table[i].npkey;
     } while( load_pubkey_modules() );
-    if( is_RSA(algo) )   /* special hack, so that we are able to */
-       return 2;         /* see the RSA keyids */
     return 0;
 }
 
@@ -450,8 +444,6 @@ pubkey_get_nskey( int algo )
            if( pubkey_table[i].algo == algo )
                return pubkey_table[i].nskey;
     } while( load_pubkey_modules() );
-    if( is_RSA(algo) )   /* special hack, so that we are able to */
-       return 6;         /* see the RSA keyids */
     return 0;
 }
 
@@ -467,8 +459,6 @@ pubkey_get_nsig( int algo )
            if( pubkey_table[i].algo == algo )
                return pubkey_table[i].nsig;
     } while( load_pubkey_modules() );
-    if( is_RSA(algo) )   /* special hack, so that we are able to */
-       return 1;         /* see the RSA keyids */
     return 0;
 }
 
@@ -484,8 +474,6 @@ pubkey_get_nenc( int algo )
            if( pubkey_table[i].algo == algo )
                return pubkey_table[i].nenc;
     } while( load_pubkey_modules() );
-    if( is_RSA(algo) )   /* special hack, so that we are able to */
-       return 1;         /* see the RSA keyids */
     return 0;
 }
 
@@ -1509,6 +1497,11 @@ gcry_pk_ctl( int cmd, void *buffer, size_t buflen)
  *     Buffer must be NULL, nbytes  may have the address of a variable
  *     with the required usage of the algorithm. It may be 0 for don't
  *     care or a combination of the GCRY_PK_USAGE_xxx flags;
+ *  GCRYCTL_GET_ALGO_USAGE:
+ *      Return the usage glafs for the give algo.  An invalid alog
+ *      does return 0.  Disabled algos are ignored here becuase we
+ *      only want to know whether the algo is at all capable of
+ *      the usage.
  *
  * On error the value -1 is returned and the error reason may be
  * retrieved by gcry_errno().
@@ -1535,6 +1528,15 @@ gcry_pk_algo_info( int algo, int what, void *buffer, size_t *nbytes)
        }
        break;
 
+      case GCRYCTL_GET_ALGO_USAGE: 
+          do {
+              int i;
+              for(i=0; pubkey_table[i].name; i++ )
+                  if( pubkey_table[i].algo == algo ) 
+                      return pubkey_table[i].use;
+          } while( load_pubkey_modules() );
+          return 0;
+         
       case GCRYCTL_GET_ALGO_NPKEY: return pubkey_get_npkey( algo );
       case GCRYCTL_GET_ALGO_NSKEY: return pubkey_get_nskey( algo );
       case GCRYCTL_GET_ALGO_NSIGN: return pubkey_get_nsig( algo );
index 0258f5d..6f31b56 100644 (file)
@@ -604,7 +604,9 @@ fast_random_poll()
       #endif
     #else
     {  struct rusage buf;
-       if( getrusage( RUSAGE_SELF, &buf ) )
+        /* QNX/Neutrino does return ENOSYS - so we just ignore it and
+         * add whatever is in buf */
+        if( getrusage( RUSAGE_SELF, &buf ) && errno != ENOSYS )
            BUG();
        add_randomness( &buf, sizeof buf, 1 );
        memset( &buf, 0, sizeof buf );
index bca596f..c232696 100644 (file)
@@ -63,7 +63,7 @@ get_entropy_count( int fd )
 #endif
 
 /****************
- * Used to open the Linux and xBSD /dev/random devices
+ * Used to open the /dev/random devices (Linux, xBSD, Solaris (if it exists), ...)
  */
 static int
 open_device( const char *name, int minor )
@@ -76,8 +76,9 @@ open_device( const char *name, int minor )
        g10_log_fatal("can't open %s: %s\n", name, strerror(errno) );
     if( fstat( fd, &sb ) )
        g10_log_fatal("stat() off %s failed: %s\n", name, strerror(errno) );
-    if( !S_ISCHR(sb.st_mode) )
-       g10_log_fatal("invalid random device!\n" );
+    /* Don't check device type for better portability */
+    /*  if( (!S_ISCHR(sb.st_mode)) && (!S_ISFIFO(sb.st_mode)) )
+         g10_log_fatal("invalid random device!\n" ); */
     return fd;
 }
 
index 99a416e..6c8e680 100644 (file)
@@ -244,6 +244,7 @@ static struct RI {
     {  "/usr/ucb/ps", "aux", SC(0.3), NULL, 0, 0, 0, 1       },
     {  "/usr/bin/ps", "aux", SC(0.3), NULL, 0, 0, 0, 1       },
     {  "/bin/ps", "aux", SC(0.3), NULL, 0, 0, 0, 0          },
+    {   "/bin/ps", "-A", SC(0.3), NULL, 0, 0, 0, 0           }, /*QNX*/
     {  "/usr/bin/ipcs", "-a", SC(0.5), NULL, 0, 0, 0, 1      },
     {  "/bin/ipcs", "-a", SC(0.5), NULL, 0, 0, 0, 0         },
     /* Unreliable source, depends on system usage */
@@ -292,6 +293,10 @@ static struct RI {
     /* This is a complex and screwball program.  Some systems have things
      * like rX_dmn, x = integer, for RAID systems, but the statistics are
      * pretty dodgy */
+#ifdef __QNXNTO__                                                             
+    { "/bin/pidin", "-F%A%B%c%d%E%I%J%K%m%M%n%N%p%P%S%s%T", SC(0.3),
+             NULL, 0, 0, 0, 0       },
+#endif     
 #if 0
     /* The following aren't enabled since they're somewhat slow and not very
      * unpredictable, however they give an indication of the sort of sources
index 5d852cd..2bb4510 100644 (file)
@@ -1,10 +1,6 @@
 /* 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.
  *
  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
  */
 
+/* This code uses an algorithm protected by U.S. Patent #4,405,829
+   which expires on September 20, 2000.  The patent holder placed that
+   patent into the public domain on Sep 6th, 2000.
+*/
+
 #include <config.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include "util.h"
+#include "g10lib.h"
 #include "mpi.h"
 #include "cipher.h"
 #include "rsa.h"
@@ -68,7 +69,7 @@ test_keys( RSA_secret_key *sk, unsigned nbits )
     pk.e = sk->e;
     {  char *p = get_random_bits( nbits, 0, 0 );
        mpi_set_buffer( test, p, (nbits+7)/8, 0 );
-       m_free(p);
+       g10_free(p);
     }
 
     public( out1, test, &pk );
@@ -200,22 +201,111 @@ public(MPI output, MPI input, RSA_public_key *pkey )
        mpi_powm( output, input, pkey->e, pkey->n );
 }
 
+#if 0
+static void
+stronger_key_check ( RSA_secret_key *skey )
+{
+    MPI t = mpi_alloc_secure ( 0 );
+    MPI t1 = mpi_alloc_secure ( 0 );
+    MPI t2 = mpi_alloc_secure ( 0 );
+    MPI phi = mpi_alloc_secure ( 0 );
+
+    /* check that n == p * q */
+    mpi_mul( t, skey->p, skey->q);
+    if (mpi_cmp( t, skey->n) )
+        log_info ( "RSA Oops: n != p * q\n" );
+
+    /* check that p is less than q */
+    if( mpi_cmp( skey->p, skey->q ) > 0 )
+       log_info ("RSA Oops: p >= q\n");
+
+
+    /* check that e divides neither p-1 nor q-1 */
+    mpi_sub_ui(t, skey->p, 1 );
+    mpi_fdiv_r(t, t, skey->e );
+    if ( !mpi_cmp_ui( t, 0) )
+        log_info ( "RSA Oops: e divides p-1\n" );
+    mpi_sub_ui(t, skey->q, 1 );
+    mpi_fdiv_r(t, t, skey->e );
+    if ( !mpi_cmp_ui( t, 0) )
+        log_info ( "RSA Oops: e divides q-1\n" );
+
+    /* check that d is correct */
+    mpi_sub_ui( t1, skey->p, 1 );
+    mpi_sub_ui( t2, skey->q, 1 );
+    mpi_mul( phi, t1, t2 );
+    mpi_gcd(t, t1, t2);
+    mpi_fdiv_q(t, phi, t);
+    mpi_invm(t, skey->e, t );
+    if ( mpi_cmp(t, skey->d ) )
+        log_info ( "RSA Oops: d is wrong\n");
+
+    /* check for crrectness of u */
+    mpi_invm(t, skey->p, skey->q );
+    if ( mpi_cmp(t, skey->u ) )
+        log_info ( "RSA Oops: u is wrong\n");
+   
+    log_info ( "RSA secret key check finished\n");
+
+    mpi_free (t);
+    mpi_free (t1);
+    mpi_free (t2);
+    mpi_free (phi);
+}
+#endif
+
+
+
 /****************
  * 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.
+ * Or faster:
  *
- * FIXME: We should better use the Chinese Remainder Theorem
+ *      m1 = c ^ (d mod (p-1)) mod p 
+ *      m2 = c ^ (d mod (q-1)) mod q 
+ *      h = u * (m2 - m1) mod q 
+ *      m = m1 + h * p
+ *
+ * Where m is OUTPUT, c is INPUT and d,n,p,q,u are elements of SKEY.
  */
 static void
 secret(MPI output, MPI input, RSA_secret_key *skey )
 {
+  #if 0
     mpi_powm( output, input, skey->d, skey->n );
+  #else
+    MPI m1   = mpi_alloc_secure( mpi_get_nlimbs(skey->n)+1 );
+    MPI m2   = mpi_alloc_secure( mpi_get_nlimbs(skey->n)+1 );
+    MPI h    = mpi_alloc_secure( mpi_get_nlimbs(skey->n)+1 );
+
+    /* m1 = c ^ (d mod (p-1)) mod p */
+    mpi_sub_ui( h, skey->p, 1  );
+    mpi_fdiv_r( h, skey->d, h );   
+    mpi_powm( m1, input, h, skey->p );
+    /* m2 = c ^ (d mod (q-1)) mod q */
+    mpi_sub_ui( h, skey->q, 1  );
+    mpi_fdiv_r( h, skey->d, h );
+    mpi_powm( m2, input, h, skey->q );
+    /* h = u * ( m2 - m1 ) mod q */
+    mpi_sub( h, m2, m1 );
+    if ( mpi_is_neg( h ) ) 
+        mpi_add ( h, h, skey->q );
+    mpi_mulm( h, skey->u, h, skey->q ); 
+    /* m = m2 + h * p */
+    mpi_mul ( h, h, skey->p );
+    mpi_add ( output, m1, h );
+    /* ready */
+    
+    mpi_free ( h );
+    mpi_free ( m1 );
+    mpi_free ( m2 );
+  #endif
 }
 
 
+
 /*********************************************
  **************  interface  ******************
  *********************************************/
@@ -226,7 +316,7 @@ rsa_generate( int algo, unsigned nbits, MPI *skey, MPI **retfactors )
     RSA_secret_key sk;
 
     if( !is_RSA(algo) )
-       return G10ERR_PUBKEY_ALGO;
+       return GCRYERR_INV_PK_ALGO;
 
     generate( &sk, nbits );
     skey[0] = sk.n;
@@ -236,7 +326,7 @@ rsa_generate( int algo, unsigned nbits, MPI *skey, MPI **retfactors )
     skey[4] = sk.q;
     skey[5] = sk.u;
     /* make an empty list of factors */
-    *retfactors = m_alloc_clear( 1 * sizeof **retfactors );
+    *retfactors = g10_xcalloc( 1, sizeof **retfactors );
     return 0;
 }
 
@@ -247,7 +337,7 @@ rsa_check_secret_key( int algo, MPI *skey )
     RSA_secret_key sk;
 
     if( !is_RSA(algo) )
-       return G10ERR_PUBKEY_ALGO;
+       return GCRYERR_INV_PK_ALGO;
 
     sk.n = skey[0];
     sk.e = skey[1];
@@ -256,7 +346,7 @@ rsa_check_secret_key( int algo, MPI *skey )
     sk.q = skey[4];
     sk.u = skey[5];
     if( !check_secret_key( &sk ) )
-       return G10ERR_BAD_SECKEY;
+       return GCRYERR_INV_PK_ALGO;
 
     return 0;
 }
@@ -269,7 +359,7 @@ rsa_encrypt( int algo, MPI *resarr, MPI data, MPI *pkey )
     RSA_public_key pk;
 
     if( algo != 1 && algo != 2 )
-       return G10ERR_PUBKEY_ALGO;
+       return GCRYERR_INV_PK_ALGO;
 
     pk.n = pkey[0];
     pk.e = pkey[1];
@@ -284,7 +374,7 @@ rsa_decrypt( int algo, MPI *result, MPI *data, MPI *skey )
     RSA_secret_key sk;
 
     if( algo != 1 && algo != 2 )
-       return G10ERR_PUBKEY_ALGO;
+       return GCRYERR_INV_PK_ALGO;
 
     sk.n = skey[0];
     sk.e = skey[1];
@@ -303,7 +393,7 @@ rsa_sign( int algo, MPI *resarr, MPI data, MPI *skey )
     RSA_secret_key sk;
 
     if( algo != 1 && algo != 3 )
-       return G10ERR_PUBKEY_ALGO;
+       return GCRYERR_INV_PK_ALGO;
 
     sk.n = skey[0];
     sk.e = skey[1];
@@ -326,13 +416,13 @@ rsa_verify( int algo, MPI hash, MPI *data, MPI *pkey,
     int rc;
 
     if( algo != 1 && algo != 3 )
-       return G10ERR_PUBKEY_ALGO;
+       return GCRYERR_INV_PK_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;
+    rc = mpi_cmp( result, hash )? GCRYERR_BAD_SIGNATURE:0;
     mpi_free(result);
 
     return rc;
@@ -366,10 +456,16 @@ rsa_get_info( int algo,
     *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";
+      case 1: *usage = GCRY_PK_USAGE_SIGN | GCRY_PK_USAGE_ENCR; return "RSA";
+      case 2: *usage = GCRY_PK_USAGE_ENCR; return "RSA-E";
+      case 3: *usage = GCRY_PK_USAGE_SIGN; return "RSA-S";
       default:*usage = 0; return NULL;
     }
 }
 
+
+
+
+
+
+
index 65b6c84..38d2c94 100644 (file)
@@ -48,6 +48,11 @@ case "$use_static_rnd" in
       ;;
 esac
 
+AC_ARG_WITH(egd-socket,
+    [  --with-egd-socket=NAME  Use NAME for the EGD socket)],
+            egd_socket_name="$withval", egd_socket_name="" )
+AC_DEFINE_UNQUOTED(EGD_SOCKET_NAME, "$egd_socket_name")
+
 
 
 dnl
@@ -164,6 +169,7 @@ AC_ISC_POSIX
 AC_PROG_INSTALL
 AC_PROG_AWK
 GPH_PROG_DOCBOOK
+GNUPG_CHECK_FAQPROG
 
 
 dnl
@@ -271,19 +277,30 @@ case "${target}" in
     *-openbsd*)
         NAME_OF_DEV_RANDOM="/dev/srandom"
         NAME_OF_DEV_URANDOM="/dev/urandom"
-        DYNLINK_MOD_CFLAGS="-shared -rdynamic -fpic -Wl,-Bshareable -Wl,-x"
+        DYNLINK_MOD_CFLAGS="-shared -rdynamic $CFLAGS_PIC -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"
+        DYNLINK_MOD_CFLAGS="-shared -rdynamic $CFLAGS_PIC -Wl,-Bshareable -Wl,-x"
+        ;;
+
+    *-solaris*)
+        NAME_OF_DEV_RANDOM="/dev/random"
+        NAME_OF_DEV_URANDOM="/dev/random"
+        DYNLINK_MOD_CFLAGS="-shared $CFLAGS_PIC"
         ;;
 
     *)
         NAME_OF_DEV_RANDOM="/dev/random"
         NAME_OF_DEV_URANDOM="/dev/urandom"
-        DYNLINK_MOD_CFLAGS="-shared $CFLAGS_PIC"
+        # -shared is a gcc-ism.  Find pic flags from GNUPG_CHECK_PIC.
+        if test -n "$GCC" ; then
+           DYNLINK_MOD_CFLAGS="-shared $CFLAGS_PIC"                            
+        else
+           DYNLINK_MOD_CFLAGS="$CFLAGS_PIC"
+        fi
         ;;
 esac
 AC_DEFINE_UNQUOTED(NAME_OF_DEV_RANDOM, "$NAME_OF_DEV_RANDOM")
@@ -429,7 +446,7 @@ AC_FUNC_VPRINTF
 AC_CHECK_FUNCS(strerror stpcpy strlwr stricmp tcgetattr rand strtoul mmap)
 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)
+AC_CHECK_FUNCS(waitpid wait4 sigaction sigprocmask fopen64 fstat64)
 
 GNUPG_CHECK_MLOCK
 GNUPG_FUNC_MKDIR_TAKES_ONE_ARG
@@ -473,7 +490,7 @@ dnl check whether we have a random device
 dnl
 if test "$try_dev_random" = yes ; then
     AC_CACHE_CHECK(for random device, ac_cv_have_dev_random,
-    [if test -c "$NAME_OF_DEV_RANDOM" && test -c "$NAME_OF_DEV_URANDOM" ; then
+    [if test -r "$NAME_OF_DEV_RANDOM" && test -r "$NAME_OF_DEV_URANDOM" ; then
       ac_cv_have_dev_random=yes; else ac_cv_have_dev_random=no; fi])
     if test "$ac_cv_have_dev_random" = yes; then
         AC_DEFINE(HAVE_DEV_RANDOM)
@@ -740,10 +757,16 @@ cat >gnupg-defs.tmp <<G10EOF
   #define GNUPG_LOCALEDIR "c:/lib/gnupg/locale"
   #define GNUPG_LIBDIR  "c:/lib/gnupg"
   #define GNUPG_DATADIR "c:/lib/gnupg"
+  #define GNUPG_HOMEDIR "c:/gnupg-test"
 #else
   #define GNUPG_LOCALEDIR "${prefix}/${DATADIRNAME}/locale"
   #define GNUPG_LIBDIR  "${libdir}/gnupg"
   #define GNUPG_DATADIR "${datadir}/gnupg"
+  #ifdef __VMS
+    #define GNUPG_HOMEDIR "/SYS\$LOGIN/gnupg" 
+  #else
+    #define GNUPG_HOMEDIR "~/.gnupg-test" 
+  #endif
 #endif
 G10EOF
 if cmp -s gnupg-defs.h gnupg-defs.tmp 2>/dev/null; then
index 74cf0d4..7cb0f17 100644 (file)
@@ -1,3 +1,81 @@
+Mon Sep 18 16:35:45 CEST 2000  Werner Koch  <wk@openit.de>
+
+        * parse-packet.c (dump_sig_subpkt): Dump key flags.
+        (parse_one_sig_subpkt,can_handle_critical): Add KeyFlags support.
+        * build-packet.c (build_sig_subpkt): Ditto.
+
+        * g10.c: New option --allow-freeform-uid. By Jeroen C. van Gelderen.
+        * keygen.c (ask_user_id): Implemented here.
+
+        * parse-packet.c (dump_sig_subpkt): Print info about the ARR.
+
+        * openfile.c (overwrite_filep): Always return okay if the file is
+        called /dev/null. 
+        (make_outfile_name): Add ".sign" to the list of know extensions.
+        (open_sigfile): Ditto.
+
+        * getkey.c: Large parts rewritten to have a better sub key selection
+        and handle some meta information from signatures more correctly.
+        (get_primary_seckey): Removed.
+        * seckey_cert.c (do_check): Set main keyid from the data in the sk.
+        * free-packet.c (copy_public_parts_to_secret_key): New.
+        * sig-check.c (check_key_signature2): Enabled shortcut for already
+        checked signatures.
+        * keydb.h: New macros IS_xxx_SIG, IS_xxx_REV.
+        * misc.c (openpgp_pk_algo_usage): New.
+        * packet.h: New field req_uage and do not use pubkey_usage anymore
+        to request a specific usage.  Changed at all places.
+        * keyid.c (keyid_from_sk): Cache the keyid in the sk
+
+        * passphrase.c (hash_passphrase): Removed funny assert.  Reported by
+        David Mathog.
+
+        * keyedit.c (keyedit_menu): Allow "debug" on secret keys.
+
+        * keygen.c (keygen_add_std_prefs): Changed order of preferences to
+        twofish, cast5, blowfish.
+
+        * gpg.c: The --trusted-key option is back.
+        * trustdb.c (verify_own_key): Handle this option.
+        (add_ultimate_key): Moved stuff from verify_own_key to this new func.
+        (register_trusted_key): New.
+
+        * openfile.c (try_make_homedir): Changes for non-Posix systems.
+        * gpg.c (main): Take the default homedir from macro.
+
+        * encode.c (encode_simple, encode_crypt): Fix for large files.
+        * sign.c (sign_file): Ditto.
+
+        * gpg.c (main): Don't set --quite along with --no-tty.  By Frank Tobin.
+
+        * misc.c (disable_core_dump): Don't display a warning here but a return
+        a status value and ...
+        * gpg.c (main): ...print warning here. Suggested by Sam Roberts.
+
+        * misc.c (print_pubkey_algo_note): Do not print the RSA notice.
+        * sig-check.c (do_signature_check): Do not emit the RSA status message.
+        * pubkey-enc.c (get_session_key): Ditto.
+
+        * ringedit.c (cmp_seckey): Fix for v4 RSA keys.
+        * seckey-cert.c (do_check): Workaround for PGP 7 bug.
+
+        * pkclist.c (algo_available): Removed hack to disable Twofish.
+
+        * gpg.c (main): Default S2K algorithms are now SHA1 and CAST5 - this
+        should solve a lot of compatibility problems with other OpenPGP
+        apps because those algorithms are SHOULD and not optional.  The old
+        way to force it was by using the --openpgp option whith the drawback 
+        that this would disable a couple of workarounds for PGP.
+
+        * gpg.c: New option --merge-only.  Suggested by Brendan O'Dea.
+        * import.c (import_one): Implemented it here.
+        (import_secret_one): Ditto.
+        (print_stats): and give some stats.
+
+        * gpg.c: New option --try-all-secrets on suggestion from
+        Matthias Urlichs.
+        * pubkey-enc.c (get_session_key): Quite easy to implement here.
+
 Mon Aug 21 17:59:17 CEST 2000  Werner Koch  <wk@openit.de>
 
         * gpg.c: New option --use-agent
index 8781589..7291f74 100644 (file)
@@ -701,6 +701,7 @@ build_sig_subpkt( PKT_signature *sig, sigsubpkttype_t type,
       case SIGSUBPKT_NOTATION:
       case SIGSUBPKT_POLICY:
       case SIGSUBPKT_REVOC_REASON:
+      case SIGSUBPKT_KEY_FLAGS:
               hashed = 1; break;
       default: hashed = 0; break;
     }
index a004837..a817f90 100644 (file)
@@ -220,6 +220,10 @@ encode_simple( const char *filename, int mode )
     if( filename && !opt.textmode && !mode ) {
        if( !(filesize = iobuf_get_filelength(inp)) )
            log_info(_("%s: WARNING: empty file\n"), filename );
+        /* we can't yet encode the length of very large files,
+         * so we switch to partial length encoding in this case */
+        if ( filesize >= IOBUF_FILELENGTH_LIMIT )
+            filesize = 0;
     }
     else
        filesize = opt.set_filesize ? opt.set_filesize : 0; /* stdin */
@@ -368,6 +372,10 @@ encode_crypt( const char *filename, STRLIST remusr )
     if( filename && !opt.textmode ) {
        if( !(filesize = iobuf_get_filelength(inp)) )
            log_info(_("%s: WARNING: empty file\n"), filename );
+        /* we can't yet encode the length of very large files,
+         * so we switch to partial lengthn encoding in this case */
+        if ( filesize >= IOBUF_FILELENGTH_LIMIT )
+            filesize = 0;
     }
     else
        filesize = opt.set_filesize ? opt.set_filesize : 0; /* stdin */
index 1d9aacf..2cc4e25 100644 (file)
@@ -139,6 +139,32 @@ copy_public_key( PKT_public_key *d, PKT_public_key *s )
    return copy_public_key_new_namehash( d, s, NULL );
 }
 
+
+/****************
+ * Replace all common parts of a sk by the one from the public key.
+ * This is a hack and a better solution will be to just store the real secret
+ * parts somewhere and don't duplicate all the other stuff.
+ */
+void
+copy_public_parts_to_secret_key( PKT_public_key *pk, PKT_secret_key *sk )
+{
+    sk->expiredate  = pk->expiredate;     
+    sk->pubkey_algo = pk->pubkey_algo;    
+    sk->pubkey_usage= pk->pubkey_usage;
+    sk->created     = pk->created;        
+    sk->req_usage   = pk->req_usage;
+    sk->req_algo    = pk->req_algo;
+    sk->has_expired = pk->has_expired;    
+    sk->is_revoked  = pk->is_revoked;     
+    sk->is_valid    = pk->is_valid;    
+    sk->main_keyid[0]= pk->main_keyid[0];
+    sk->main_keyid[1]= pk->main_keyid[1];
+    sk->keyid[0]    = pk->keyid[0];
+    sk->keyid[1]    = pk->keyid[1];
+}
+
+
+
 PKT_signature *
 copy_signature( PKT_signature *d, PKT_signature *s )
 {
@@ -450,3 +476,7 @@ cmp_user_ids( PKT_user_id *a, PKT_user_id *b )
 }
 
 
+
+
+
+
index e9b4a23..17dc6fa 100644 (file)
 #include "trustdb.h"
 #include "i18n.h"
 
+
+#if 0
 #define MAX_UNK_CACHE_ENTRIES 1000   /* we use a linked list - so I guess
                                      * this is a reasonable limit */
 #define MAX_PK_CACHE_ENTRIES   50
+#endif
 #define MAX_UID_CACHE_ENTRIES  50
 
 /* A map of the all characters valid used for word_match()
@@ -99,7 +102,10 @@ struct getkey_ctx_s {
     int primary;
     KBNODE keyblock;
     KBPOS kbpos;
+    KBNODE found_key; /* pointer into some keyblock */
     int last_rc;
+    int req_usage;
+    int req_algo;
     ulong count;
     int not_allocated;
     int nitems;
@@ -119,13 +125,13 @@ static struct {
 } lkup_stats[21];
 #endif
 
+typedef struct keyid_list {
+    struct keyid_list *next;
+    u32 keyid[2];
+} *keyid_list_t;
 
 
 #if MAX_UNK_CACHE_ENTRIES
-  typedef struct keyid_list {
-      struct keyid_list *next;
-      u32 keyid[2];
-  } *keyid_list_t;
   static keyid_list_t unknown_keyids;
   static int unk_cache_entries;   /* number of entries in unknown keys cache */
   static int unk_cache_disabled;
@@ -147,7 +153,7 @@ static struct {
 #endif
 typedef struct user_id_db {
     struct user_id_db *next;
-    u32 keyid[2];
+    keyid_list_t keyids;
     int len;
     char name[1];
 } *user_id_db_t;
@@ -157,9 +163,7 @@ static int uid_cache_entries;       /* number of entries in uid cache */
 
 
 static char* prepare_word_match( const byte *name );
-static int lookup_pk( GETKEY_CTX ctx, PKT_public_key *pk, KBNODE *ret_kb );
-static int lookup_sk( GETKEY_CTX ctx, PKT_secret_key *sk, KBNODE *ret_kb );
-static u32 subkeys_expiretime( KBNODE node, u32 *mainkid );
+static int lookup( GETKEY_CTX ctx, KBNODE *ret_kb, int secmode );
 
 
 #if 0
@@ -222,34 +226,96 @@ cache_public_key( PKT_public_key *pk )
   #endif
 }
 
+/*
+ * Return the user ID from the given keyblock.
+ * We use the primary uid flag which has been set by the merge_selfsigs
+ * function.  The returned value is only valid as long as then given
+ * keyblock is not changed
+ */
+static const char *
+get_primary_uid ( KBNODE keyblock, size_t *uidlen )
+{
+    KBNODE k;
+
+    for (k=keyblock; k; k=k->next ) {
+        if ( k->pkt->pkttype == PKT_USER_ID
+             && k->pkt->pkt.user_id->is_primary ) {
+            *uidlen = k->pkt->pkt.user_id->len;
+            return k->pkt->pkt.user_id->name;
+        }
+    } 
+    *uidlen = 12;
+    return "[No user ID]";
+}
+
+
+static void
+release_keyid_list ( keyid_list_t k )
+{
+    while (  k ) {
+        keyid_list_t k2 = k->next;
+        gcry_free (k);
+        k = k2;
+    }
+}
 
 /****************
  * Store the association of keyid and userid
+ * Feed only public keys to this function.
  */
 void
-cache_user_id( PKT_user_id *uid, u32 *keyid )
+cache_user_id( KBNODE keyblock )
 {
     user_id_db_t r;
+    const char *uid;
+    size_t uidlen;
+    keyid_list_t keyids = NULL;
+    KBNODE k;
 
-    for(r=user_id_db; r; r = r->next )
-       if( r->keyid[0] == keyid[0] && r->keyid[1] == keyid[1] ) {
-           if( DBG_CACHE )
-              log_debug("cache_user_id: already in cache\n");
-           return;
-       }
+    for (k=keyblock; k; k = k->next ) {
+        if ( k->pkt->pkttype == PKT_PUBLIC_KEY
+             || k->pkt->pkttype == PKT_PUBLIC_SUBKEY ) {
+            keyid_list_t a = gcry_xcalloc ( 1, sizeof *a );
+            /* Hmmm: For a long list of keyids it might be an advantage
+             * to append the keys */
+            keyid_from_pk( k->pkt->pkt.public_key, a->keyid );
+            /* first check for duplicates */
+            for(r=user_id_db; r; r = r->next ) {
+                keyid_list_t b = r->keyids;
+                for ( b = r->keyids; b; b = b->next ) {
+                    if( b->keyid[0] == a->keyid[0]
+                        && b->keyid[1] == a->keyid[1] ) {
+                        if( DBG_CACHE )
+                            log_debug("cache_user_id: already in cache\n");
+                        release_keyid_list ( keyids );
+                        gcry_free ( a );
+                        return;
+                    }
+                }
+            }
+            /* now put it into the cache */
+            a->next = keyids;
+            keyids = a;
+        }
+    }
+    if ( !keyids )
+        BUG (); /* No key no fun */
+
+
+    uid = get_primary_uid ( keyblock, &uidlen );
 
     if( uid_cache_entries >= MAX_UID_CACHE_ENTRIES ) {
        /* fixme: use another algorithm to free some cache slots */
        r = user_id_db;
        user_id_db = r->next;
+        release_keyid_list ( r->keyids );
        gcry_free(r);
        uid_cache_entries--;
     }
-    r = gcry_xmalloc( sizeof *r + uid->len-1 );
-    r->keyid[0] = keyid[0];
-    r->keyid[1] = keyid[1];
-    r->len = uid->len;
-    memcpy(r->name, uid->name, r->len);
+    r = gcry_xmalloc( sizeof *r + uidlen-1 );
+    r->keyids = keyids;
+    r->len = uidlen;
+    memcpy(r->name, uid, r->len);
     r->next = user_id_db;
     user_id_db = r;
     uid_cache_entries++;
@@ -288,6 +354,31 @@ getkey_disable_caches()
 }
 
 
+static void
+pk_from_block ( GETKEY_CTX ctx,
+                PKT_public_key *pk, KBNODE keyblock, const char *namehash )
+{
+    KBNODE a = ctx->found_key ? ctx->found_key : keyblock;
+
+    assert ( a->pkt->pkttype == PKT_PUBLIC_KEY
+             ||  a->pkt->pkttype == PKT_PUBLIC_SUBKEY );
+     
+    copy_public_key_new_namehash( pk, a->pkt->pkt.public_key, namehash);
+}
+
+static void
+sk_from_block ( GETKEY_CTX ctx,
+                PKT_secret_key *sk, KBNODE keyblock )
+{
+    KBNODE a = ctx->found_key ? ctx->found_key : keyblock;
+
+    assert ( a->pkt->pkttype == PKT_SECRET_KEY
+             ||  a->pkt->pkttype == PKT_SECRET_SUBKEY );
+     
+    copy_secret_key( sk, a->pkt->pkt.secret_key);
+}
+
+
 /****************
  * Get a public key and store it into the allocated pk
  * can be called with PK set to NULL to just read it into some
@@ -329,14 +420,21 @@ get_pubkey( PKT_public_key *pk, u32 *keyid )
 
     /* do a lookup */
     {  struct getkey_ctx_s ctx;
+        KBNODE kb = NULL;
        memset( &ctx, 0, sizeof ctx );
        ctx.not_allocated = 1;
        ctx.nitems = 1;
        ctx.items[0].mode = 11;
        ctx.items[0].keyid[0] = keyid[0];
        ctx.items[0].keyid[1] = keyid[1];
-       rc = lookup_pk( &ctx, pk, NULL );
+        ctx.req_algo  = pk->req_algo;
+        ctx.req_usage = pk->req_usage;
+       rc = lookup( &ctx, &kb, 0 );
+        if ( !rc ) {
+            pk_from_block ( &ctx, pk, kb, NULL );
+        }
        get_pubkey_end( &ctx );
+        release_kbnode ( kb );
     }
     if( !rc )
        goto leave;
@@ -374,7 +472,6 @@ get_pubkey( PKT_public_key *pk, u32 *keyid )
 KBNODE
 get_pubkeyblock( u32 *keyid )
 {
-    PKT_public_key *pk = gcry_xcalloc( 1, sizeof *pk );
     struct getkey_ctx_s ctx;
     int rc = 0;
     KBNODE keyblock = NULL;
@@ -385,8 +482,7 @@ get_pubkeyblock( u32 *keyid )
     ctx.items[0].mode = 11;
     ctx.items[0].keyid[0] = keyid[0];
     ctx.items[0].keyid[1] = keyid[1];
-    rc = lookup_pk( &ctx, pk, &keyblock );
-    free_public_key(pk);
+    rc = lookup( &ctx, &keyblock, 0 );
     get_pubkey_end( &ctx );
 
     return rc ? NULL : keyblock;
@@ -403,6 +499,7 @@ get_seckey( PKT_secret_key *sk, u32 *keyid )
 {
     int rc;
     struct getkey_ctx_s ctx;
+    KBNODE kb = NULL;
 
     memset( &ctx, 0, sizeof ctx );
     ctx.not_allocated = 1;
@@ -410,8 +507,15 @@ get_seckey( PKT_secret_key *sk, u32 *keyid )
     ctx.items[0].mode = 11;
     ctx.items[0].keyid[0] = keyid[0];
     ctx.items[0].keyid[1] = keyid[1];
-    rc = lookup_sk( &ctx, sk, NULL );
+    ctx.req_algo  = sk->req_algo;
+    ctx.req_usage = sk->req_usage;
+    rc = lookup( &ctx, &kb, 1 );
+    if ( !rc ) {
+        sk_from_block ( &ctx, sk, kb );
+    }
     get_seckey_end( &ctx );
+    release_kbnode ( kb );
+
     if( !rc ) {
        /* check the secret key (this may prompt for a passprase to
         * unlock the secret key
@@ -424,30 +528,6 @@ get_seckey( PKT_secret_key *sk, u32 *keyid )
 
 
 /****************
- * Get the primary secret key and store it into sk
- * Note: This function does not unprotect the key!
- */
-int
-get_primary_seckey( PKT_secret_key *sk, u32 *keyid )
-{
-    struct getkey_ctx_s ctx;
-    int rc;
-
-    memset( &ctx, 0, sizeof ctx );
-    ctx.not_allocated = 1;
-    ctx.primary = 1;
-    ctx.nitems = 1;
-    ctx.items[0].mode = 11;
-    ctx.items[0].keyid[0] = keyid[0];
-    ctx.items[0].keyid[1] = keyid[1];
-    rc = lookup_sk( &ctx, sk, NULL );
-    get_seckey_end( &ctx );
-    return rc;
-}
-
-
-
-/****************
  * Check whether the secret key is available
  * Returns: 0 := key is available
  *         GPGERR_NO_SECKEY := not availabe
@@ -457,18 +537,17 @@ seckey_available( u32 *keyid )
 {
     int rc;
     struct getkey_ctx_s ctx;
-    PKT_secret_key *sk;
+    KBNODE kb = NULL;
 
-    sk = gcry_xcalloc( 1, sizeof *sk );
     memset( &ctx, 0, sizeof ctx );
     ctx.not_allocated = 1;
     ctx.nitems = 1;
     ctx.items[0].mode = 11;
     ctx.items[0].keyid[0] = keyid[0];
     ctx.items[0].keyid[1] = keyid[1];
-    rc = lookup_sk( &ctx, sk, NULL );
+    rc = lookup( &ctx, &kb, 1 );
     get_seckey_end( &ctx );
-    free_secret_key( sk );
+    release_kbnode ( kb );
     return rc;
 }
 
@@ -612,7 +691,8 @@ classify_user_id( const char *name, u32 *keyid, byte *fprint,
                    hexlength = 0;  /* a hex number, but really were not. */
            }
 
-           if (hexlength == 8 || (!hexprefix && hexlength == 9 && *s == '0')){
+           if (hexlength == 8
+                || (!hexprefix && hexlength == 9 && *s == '0')){
                /* short keyid */
                if (hexlength == 9)
                    s++;
@@ -622,8 +702,8 @@ classify_user_id( const char *name, u32 *keyid, byte *fprint,
                }
                mode = 10;
            }
-           else if (hexlength == 16 || (!hexprefix && hexlength == 17
-                                                         && *s == '0')) {
+           else if (hexlength == 16
+                     || (!hexprefix && hexlength == 17 && *s == '0')) {
                /* complete keyid */
                char buf[9];
                if (hexlength == 17)
@@ -701,10 +781,10 @@ key_byname( GETKEY_CTX *retctx, STRLIST namelist,
     int n;
     STRLIST r;
     GETKEY_CTX ctx;
-
+    KBNODE help_kb = NULL;
+    
     if( retctx ) /* reset the returned context in case of error */
        *retctx = NULL;
-    assert( !pk ^ !sk );
 
     /* build the search context */
     /* Performance hint: Use a static buffer if there is only one name */
@@ -732,10 +812,25 @@ key_byname( GETKEY_CTX *retctx, STRLIST namelist,
 
     /* and call the lookup function */
     ctx->primary = 1; /* we want to look for the primary key only */
-    if( sk )
-       rc = lookup_sk( ctx, sk, ret_kb );
-    else
-       rc = lookup_pk( ctx, pk, ret_kb );
+
+    if ( !ret_kb ) 
+        ret_kb = &help_kb;
+
+    if( sk ) {
+       rc = lookup( ctx, ret_kb, 1 );
+        if ( !rc && sk ) {
+            sk_from_block ( ctx, sk, *ret_kb );
+        }
+    }
+    else {
+       
+       rc = lookup( ctx, ret_kb, 0 );
+        if ( !rc && pk ) {
+            pk_from_block ( ctx, pk, *ret_kb, NULL /* FIXME need to get the namehash*/ );
+        }
+    }
+
+    release_kbnode ( help_kb );
 
     if( retctx ) /* caller wants the context */
        *retctx = ctx;
@@ -758,16 +853,7 @@ get_pubkey_byname( GETKEY_CTX *retctx, PKT_public_key *pk,
     STRLIST namelist = NULL;
 
     add_to_strlist( &namelist, name );
-
-    if( !pk ) {
-       /* Performance Hint: key_byname should not need a pk here */
-       pk = gcry_xcalloc( 1, sizeof *pk );
-       rc = key_byname( retctx, namelist, pk, NULL, ret_keyblock );
-       free_public_key( pk );
-    }
-    else
-       rc = key_byname( retctx, namelist, pk, NULL, ret_keyblock );
-
+    rc = key_byname( retctx, namelist, pk, NULL, ret_keyblock );
     free_strlist( namelist );
     return rc;
 }
@@ -776,18 +862,7 @@ int
 get_pubkey_bynames( GETKEY_CTX *retctx, PKT_public_key *pk,
                    STRLIST names, KBNODE *ret_keyblock )
 {
-    int rc;
-
-    if( !pk ) {
-       /* Performance Hint: key_byname should not need a pk here */
-       pk = gcry_xcalloc( 1, sizeof *pk );
-       rc = key_byname( retctx, names, pk, NULL, ret_keyblock );
-       free_public_key( pk );
-    }
-    else
-       rc = key_byname( retctx, names, pk, NULL, ret_keyblock );
-
-    return rc;
+    return key_byname( retctx, names, pk, NULL, ret_keyblock );
 }
 
 int
@@ -795,14 +870,10 @@ get_pubkey_next( GETKEY_CTX ctx, PKT_public_key *pk, KBNODE *ret_keyblock )
 {
     int rc;
 
-    if( !pk ) {
-       /* Performance Hint: lookup_read should not need a pk in this case */
-       pk = gcry_xcalloc( 1, sizeof *pk );
-       rc = lookup_pk( ctx, pk, ret_keyblock );
-       free_public_key( pk );
-    }
-    else
-       rc = lookup_pk( ctx, pk, ret_keyblock );
+    rc = lookup( ctx, ret_keyblock, 0 );
+    if ( !rc && pk && ret_keyblock )
+        pk_from_block ( ctx, pk, *ret_keyblock, NULL );
+    
     return rc;
 }
 
@@ -824,18 +895,24 @@ get_pubkey_end( GETKEY_CTX ctx )
  * Search for a key with the given fingerprint.
  */
 int
-get_pubkey_byfprint( PKT_public_key *pk, const byte *fprint, size_t fprint_len)
+get_pubkey_byfprint( PKT_public_key *pk,
+                     const byte *fprint, size_t fprint_len)
 {
     int rc;
 
     if( fprint_len == 20 || fprint_len == 16 ) {
        struct getkey_ctx_s ctx;
+        KBNODE kb = NULL;
+
        memset( &ctx, 0, sizeof ctx );
        ctx.not_allocated = 1;
        ctx.nitems = 1;
        ctx.items[0].mode = fprint_len;
        memcpy( ctx.items[0].fprint, fprint, fprint_len );
-       rc = lookup_pk( &ctx, pk, NULL );
+       rc = lookup( &ctx, &kb, 0 );
+        if (!rc && pk )
+            pk_from_block ( &ctx, pk, kb, NULL );
+        release_kbnode ( kb );
        get_pubkey_end( &ctx );
     }
     else
@@ -852,35 +929,33 @@ get_keyblock_byfprint( KBNODE *ret_keyblock, const byte *fprint,
                                                size_t fprint_len )
 {
     int rc;
-    PKT_public_key *pk = gcry_xcalloc( 1, sizeof *pk );
 
     if( fprint_len == 20 || fprint_len == 16 ) {
        struct getkey_ctx_s ctx;
+
        memset( &ctx, 0, sizeof ctx );
        ctx.not_allocated = 1;
        ctx.nitems = 1;
        ctx.items[0].mode = fprint_len;
        memcpy( ctx.items[0].fprint, fprint, fprint_len );
-       rc = lookup_pk( &ctx, pk, ret_keyblock );
+       rc = lookup( &ctx, ret_keyblock, 0 );
        get_pubkey_end( &ctx );
     }
     else
        rc = GPGERR_GENERAL; /* Oops */
 
-    free_public_key( pk );
     return rc;
 }
 
 
 
 /****************
- * Search for a key with the given lid and return the complete keyblock
+ * Search for a key with the given lid and return the entire keyblock
  */
 int
 get_keyblock_bylid( KBNODE *ret_keyblock, ulong lid )
 {
     int rc;
-    PKT_public_key *pk = gcry_xcalloc( 1, sizeof *pk );
     struct getkey_ctx_s ctx;
     u32 kid[2];
 
@@ -892,10 +967,9 @@ get_keyblock_bylid( KBNODE *ret_keyblock, ulong lid )
     ctx.items[0].mode = 12;
     ctx.items[0].keyid[0] = kid[0];
     ctx.items[0].keyid[1] = kid[1];
-    rc = lookup_pk( &ctx, pk, ret_keyblock );
+    rc = lookup( &ctx,  ret_keyblock, 0 );
     get_pubkey_end( &ctx );
 
-    free_public_key( pk );
     return rc;
 }
 
@@ -919,13 +993,17 @@ get_seckey_byname( PKT_secret_key *sk, const char *name, int unprotect )
     }
     else if( !name ) { /* use the first one as default key */
        struct getkey_ctx_s ctx;
+        KBNODE kb = NULL;
 
        memset( &ctx, 0, sizeof ctx );
        ctx.not_allocated = 1;
        ctx.primary = 1;
        ctx.nitems = 1;
        ctx.items[0].mode = 15;
-       rc = lookup_sk( &ctx, sk, NULL );
+       rc = lookup( &ctx, &kb, 1 );
+        if (!rc && sk )
+            sk_from_block ( &ctx, sk, kb );
+        release_kbnode ( kb );
        get_seckey_end( &ctx );
     }
     else {
@@ -945,18 +1023,7 @@ int
 get_seckey_bynames( GETKEY_CTX *retctx, PKT_secret_key *sk,
                    STRLIST names, KBNODE *ret_keyblock )
 {
-    int rc;
-
-    if( !sk ) {
-       /* Performance Hint: key_byname should not need a sk here */
-       sk = gcry_xcalloc_secure( 1, sizeof *sk );
-       rc = key_byname( retctx, names, NULL, sk, ret_keyblock );
-       free_secret_key( sk );
-    }
-    else
-       rc = key_byname( retctx, names, NULL, sk, ret_keyblock );
-
-    return rc;
+    return key_byname( retctx, names, NULL, sk, ret_keyblock );
 }
 
 
@@ -965,32 +1032,24 @@ get_seckey_next( GETKEY_CTX ctx, PKT_secret_key *sk, KBNODE *ret_keyblock )
 {
     int rc;
 
-    if( !sk ) {
-       /* Performance Hint: lookup_read should not need a pk in this case */
-       sk = gcry_xcalloc_secure( 1, sizeof *sk );
-       rc = lookup_sk( ctx, sk, ret_keyblock );
-       free_secret_key( sk );
-    }
-    else
-       rc = lookup_sk( ctx, sk, ret_keyblock );
+    rc = lookup( ctx, ret_keyblock, 1 );
+    if ( !rc && sk && ret_keyblock )
+        sk_from_block ( ctx, sk, *ret_keyblock );
+
     return rc;
 }
 
 void
 get_seckey_end( GETKEY_CTX ctx )
 {
-    if( ctx ) {
-       int n;
-
-       enum_keyblocks( 2, &ctx->kbpos, NULL ); /* close */
-       for(n=0; n < ctx->nitems; n++ )
-           gcry_free( ctx->items[n].namebuf );
-       if( !ctx->not_allocated )
-           gcry_free( ctx );
-    }
+    get_pubkey_end( ctx );
 }
 
 
+\f
+/*******************************************************
+ ************** compare functions **********************
+ *******************************************************/
 
 /****************
  * Do a word match (original user id starts with a '+').
@@ -1130,73 +1189,15 @@ compare_name( const char *uid, size_t uidlen, const char *name, int mode )
 
 
 
-/****************
- * Assume that knode points to a public key packet  and keyblock is
- * the entire keyblock.  This function adds all relevant information from
- * a selfsignature to the public key.
- */
-
-static void
-merge_one_pk_and_selfsig( KBNODE keyblock, KBNODE knode,
-                         PKT_public_key *orig_pk )
-{
-    PKT_public_key *pk = knode->pkt->pkt.public_key;
-    PKT_signature *sig;
-    KBNODE k;
-    u32 kid[2];
-    u32 sigdate = 0;
-
-    assert(    knode->pkt->pkttype == PKT_PUBLIC_KEY
-           || knode->pkt->pkttype == PKT_PUBLIC_SUBKEY );
-
-    if( pk->version < 4 )
-       return; /* this is only needed for version >=4 packets */
-
-
-    /* find the selfsignature */
-    if( knode->pkt->pkttype == PKT_PUBLIC_SUBKEY ) {
-       k = find_kbnode( keyblock, PKT_PUBLIC_KEY );
-       if( !k )
-          BUG(); /* keyblock without primary key!!! */
-       keyid_from_pk( k->pkt->pkt.public_key, kid );
-    }
-    else
-       keyid_from_pk( pk, kid );
-
-    for(k=knode->next; k; k = k->next ) {
-       if( k->pkt->pkttype == PKT_SIGNATURE
-           && (sig=k->pkt->pkt.signature)->sig_class >= 0x10
-           && sig->sig_class <= 0x30
-           && sig->keyid[0] == kid[0]
-           && sig->keyid[1] == kid[1]
-           && sig->version > 3 ) {
-           /* okay this is a self-signature which can be used.
-            * We use the latest self-signature.
-            * FIXME: We should only use this if the signature is valid
-            *        but this is time consuming - we must provide another
-            *        way to handle this
-            */
-           const byte *p;
-           u32 ed;
-
-           p = parse_sig_subpkt( sig->hashed_data, SIGSUBPKT_KEY_EXPIRE, NULL );
-           ed = p? pk->timestamp + buffer_to_u32(p):0;
-           /* use the latest self signature */
-           if( sig->timestamp > sigdate ) {
-               pk->expiredate = ed;
-               orig_pk->expiredate = ed;
-               sigdate = sig->timestamp;
-           }
-           /* fixme: add usage etc. to pk */
-       }
-       else if( k->pkt->pkttype == PKT_PUBLIC_SUBKEY )
-           break; /* stop here */
-    }
-}
-
+\f
+/************************************************
+ ************* Merging stuff ********************
+ ************************************************/
 
 /****************
  * merge all selfsignatures with the keys.
+ * FIXME: replace this at least for the public key parts
+ *        by merge_selfsigs
  */
 void
 merge_keys_and_selfsig( KBNODE keyblock )
@@ -1218,7 +1219,7 @@ merge_keys_and_selfsig( KBNODE keyblock )
                keyid_from_pk( pk, kid );
            else if( !pk->expiredate ) { /* and subkey */
                /* insert the expiration date here */
-               pk->expiredate = subkeys_expiretime( k, kid );
+               /*FIXME!!! pk->expiredate = subkeys_expiretime( k, kid );*/
            }
            sigdate = 0;
        }
@@ -1266,510 +1267,850 @@ merge_keys_and_selfsig( KBNODE keyblock )
 }
 
 
-static KBNODE
-find_by_name( KBNODE keyblock, PKT_public_key *pk, const char *name,
-             int mode, byte *namehash, int *use_namehash )
+static void
+fixup_uidnode ( KBNODE uidnode, KBNODE signode )
 {
-    KBNODE k, kk;
+    PKT_user_id   *uid = uidnode->pkt->pkt.user_id;
+    PKT_signature *sig = signode->pkt->pkt.signature;
+    const byte *p;
+    size_t n;
+
+    uid->created = 0; /* not created == invalid */
+    if ( !signode ) 
+        return; /* no self-signature */
+    if ( IS_UID_REV ( sig ) )
+        return; /* has been revoked */
+
+    uid->created = sig->timestamp; /* this one is okay */    
+        
+    /* store the key flags in the helper variable for later processing */
+    uid->help_key_usage = 0;
+    p = parse_sig_subpkt ( sig->hashed_data, SIGSUBPKT_KEY_FLAGS, &n );
+    if ( p && n ) {
+        /* first octet of the keyflags */   
+        if ( (*p & 3) )
+            uid->help_key_usage |= GCRY_PK_USAGE_SIGN;
+        if ( (*p & 12) )    
+            uid->help_key_usage |= GCRY_PK_USAGE_ENCR;
+    }
 
-    for(k=keyblock; k; k = k->next ) {
-       if( k->pkt->pkttype == PKT_USER_ID
-           && !compare_name( k->pkt->pkt.user_id->name,
-                             k->pkt->pkt.user_id->len, name, mode)) {
-           /* we found a matching name, look for the key */
-           for(kk=keyblock; kk; kk = kk->next ) {
-               if( (    kk->pkt->pkttype == PKT_PUBLIC_KEY
-                     || kk->pkt->pkttype == PKT_PUBLIC_SUBKEY )
-                   && ( !pk->pubkey_algo
-                        || pk->pubkey_algo
-                           == kk->pkt->pkt.public_key->pubkey_algo)
-                   && ( !pk->pubkey_usage
-                        || !openpgp_pk_test_algo(
-                              kk->pkt->pkt.public_key->pubkey_algo,
-                                                  pk->pubkey_usage ))
-                 )
-                   break;
-           }
-           if( kk ) {
-               u32 aki[2];
-               keyid_from_pk( kk->pkt->pkt.public_key, aki );
-               cache_user_id( k->pkt->pkt.user_id, aki );
-               if( k->pkt->pkt.user_id->photo ) {
-                   gcry_md_hash_buffer( GCRY_MD_RMD160, namehash,
-                                       k->pkt->pkt.user_id->photo,
-                                       k->pkt->pkt.user_id->photolen );
-               }
-               else {
-                   gcry_md_hash_buffer( GCRY_MD_RMD160, namehash,
-                                       k->pkt->pkt.user_id->name,
-                                       k->pkt->pkt.user_id->len );
-               }
-               *use_namehash = 1;
-               return kk;
-           }
-           else if( is_RSA(pk->pubkey_algo) )
-               log_error(_("RSA key cannot be used in this version\n"));
-           else
-               log_error(_("No key for user ID\n"));
-       }
+    /* ditto or the key expiration */
+    uid->help_key_expire = 0;
+    p = parse_sig_subpkt ( sig->hashed_data, SIGSUBPKT_KEY_EXPIRE, NULL);
+    if ( p ) {
+        uid->help_key_expire = sig->timestamp + buffer_to_u32(p);
     }
-    return NULL;
+
+    /* Set the primary user ID flag - we will later wipe out some
+     * of them to only have one in out keyblock */
+    uid->is_primary = 0;
+    p = parse_sig_subpkt ( sig->hashed_data, SIGSUBPKT_PRIMARY_UID, NULL );
+    if ( p && *p )
+        uid->is_primary = 1;
+    /* We could also query this from the unhashed area if it is not in
+     * the hased area and then later try to decide which is the better
+     * there should be no security problem with this.
+     * For now we only look at the hashed one. 
+     */
 }
 
-static KBNODE
-find_by_name_sk( KBNODE keyblock, PKT_secret_key *sk, const char *name,
-                int mode )
+static void
+merge_selfsigs_main( KBNODE keyblock, int *r_revoked )
 {
-    KBNODE k, kk;
+    PKT_public_key *pk = NULL;
+    KBNODE k;
+    u32 kid[2];
+    u32 sigdate = 0, uiddate=0, uiddate2;
+    KBNODE signode, uidnode, uidnode2;
+    u32 curtime = make_timestamp ();
+    unsigned int key_usage = 0;
+    u32 key_expire = 0;
+    int key_expire_seen = 0;
+
+    *r_revoked = 0;
+    if ( keyblock->pkt->pkttype != PKT_PUBLIC_KEY )
+        BUG ();
+    pk = keyblock->pkt->pkt.public_key;
+    pk->created = 0;
+    keyid_from_pk( pk, kid );
+    pk->main_keyid[0] = kid[0];
+    pk->main_keyid[1] = kid[1];
+
+    if ( pk->version < 4 ) 
+        return; /* nothing to do for old keys FIXME: This is wrong!!!!*/
+
+    /* first pass: find the latest direct key self-signature.
+     * We assume that the newest one overrides all others
+     */
+    signode = NULL;
+    sigdate = 0; /* helper to find the latest signature */
+    for(k=keyblock; k && k->pkt->pkttype != PKT_PUBLIC_SUBKEY; k = k->next ) {
+        if ( k->pkt->pkttype == PKT_SIGNATURE ) {
+            PKT_signature *sig = k->pkt->pkt.signature;
+            if ( sig->keyid[0] == kid[0] && sig->keyid[1]==kid[1] ) { 
+               if ( check_key_signature( keyblock, k, NULL ) )
+                    ; /* signature did not verify */
+                else if ( IS_KEY_REV (sig) ){
+                    /* key has been revoked - there is no way to override
+                     * such a revocation, so we can stop now.
+                     * we can't cope with expiration times for revocations
+                     * here because we have to assumethat an attacker can
+                     * generate all kinds of signatures.
+                     */ 
+                    *r_revoked = 1;
+                    return;
+                }
+                else if ( IS_KEY_SIG (sig) && sig->timestamp >= sigdate ) {
+                    const byte *p;
+                    
+                    p = parse_sig_subpkt( sig->hashed_data,
+                                          SIGSUBPKT_SIG_EXPIRE, NULL );
+                    if ( p && (sig->timestamp + buffer_to_u32(p)) >= curtime )
+                        ; /* signature has expired - ignore it */
+                    else {
+                        sigdate = sig->timestamp;
+                        signode = k;
+                    }
+                }
+            }
+        }
+    }
 
-    for(k=keyblock; k; k = k->next ) {
-       if( k->pkt->pkttype == PKT_USER_ID
-           && !compare_name( k->pkt->pkt.user_id->name,
-                             k->pkt->pkt.user_id->len, name, mode)) {
-           /* we found a matching name, look for the key */
-           for(kk=keyblock; kk; kk = kk->next ) {
-               if( (    kk->pkt->pkttype == PKT_SECRET_KEY
-                     || kk->pkt->pkttype == PKT_SECRET_SUBKEY )
-                   && ( !sk->pubkey_algo
-                        || sk->pubkey_algo
-                           == kk->pkt->pkt.secret_key->pubkey_algo)
-                   && ( !sk->pubkey_usage
-                        || !openpgp_pk_test_algo(
-                              kk->pkt->pkt.secret_key->pubkey_algo,
-                                                  sk->pubkey_usage ))
-                 )
-                   break;
-           }
-           if( kk ) {
-               u32 aki[2];
-               keyid_from_sk( kk->pkt->pkt.secret_key, aki );
-               cache_user_id( k->pkt->pkt.user_id, aki );
-               return kk;
-           }
-           else if( is_RSA(sk->pubkey_algo) )
-               log_error(_("RSA key cannot be used in this version\n"));
-           else
-               log_error(_("No key for user ID\n"));
-       }
+    if ( signode ) {
+        /* some information from a direct key signature take precedence
+         * over the same information given in UID sigs.
+         */
+        PKT_signature *sig = signode->pkt->pkt.signature;
+        const byte *p;
+        size_t n;
+        
+        p = parse_sig_subpkt ( sig->hashed_data, SIGSUBPKT_KEY_FLAGS, &n );
+        if ( p && n ) {
+            /* first octet of the keyflags */   
+            if ( (*p & 3) )
+                key_usage |= GCRY_PK_USAGE_SIGN;
+            if ( (*p & 12) )    
+                key_usage |= GCRY_PK_USAGE_ENCR;
+        }
+
+        p = parse_sig_subpkt ( sig->hashed_data, SIGSUBPKT_KEY_EXPIRE, NULL);
+        if ( p ) {
+            key_expire = sig->timestamp + buffer_to_u32(p);
+            key_expire_seen = 1;
+        }
+
+        /* and set the created field */
+        pk->created = sigdate;
+        /* and mark that key as valid: one direct key signature should 
+         * render a key as valid */
+        pk->is_valid = 1;
     }
-    return NULL;
+
+
+    /* second pass: look at the self-signature of all user IDs */
+    signode = uidnode = NULL;
+    sigdate = 0; /* helper to find the latest signature in one user ID */
+    uiddate = 0; /* and over of all user IDs */
+    for(k=keyblock; k && k->pkt->pkttype != PKT_PUBLIC_SUBKEY; k = k->next ) {
+       if ( k->pkt->pkttype == PKT_USER_ID
+             || k->pkt->pkttype == PKT_PHOTO_ID ) {
+            if ( uidnode ) 
+                fixup_uidnode ( uidnode, signode );
+            uidnode = k;
+            signode = NULL;
+            if ( sigdate > uiddate )
+                uiddate = sigdate;
+            sigdate = 0;
+       }
+        else if ( k->pkt->pkttype == PKT_SIGNATURE && uidnode ) {
+            PKT_signature *sig = k->pkt->pkt.signature;
+            if ( sig->keyid[0] == kid[0] && sig->keyid[1]==kid[1] ) { 
+                if ( check_key_signature( keyblock, k, NULL ) )
+                    ; /* signature did not verify */
+                else if ( IS_UID_SIG (sig) || IS_UID_REV (sig)) {
+                    /* Note: we allow to invalidated cert revocations
+                     * by a newer signature.  An attacker can't use this
+                     * because a key should be revoced with a key revocation.
+                     * The reason why we have to allow for that is that at
+                     * one time an email address may become invalid but later
+                     * the same email address may become valid again (hired,
+                     * fired, hired again).
+                     */                    
+                    const byte *p;
+                    
+                    p = parse_sig_subpkt( sig->hashed_data,
+                                          SIGSUBPKT_SIG_EXPIRE, NULL );
+                    if ( p && (sig->timestamp + buffer_to_u32(p)) >= curtime )
+                        ; /* signature/revocation has expired - ignore it */
+                    else {
+                        sigdate = sig->timestamp;
+                        signode = k;
+                    }
+                }
+            }
+        }
+    }
+    if ( uidnode ) {
+        fixup_uidnode ( uidnode, signode );
+        pk->is_valid = 1;
+    }
+    if ( sigdate > uiddate )
+        uiddate = sigdate;
+    /* if we do not have a direct key signature, take the key creation date
+     * from the latest user ID.  Hmmm, another possibilty would be to take 
+     * it from the latest primary user ID - but we don't implement it for
+     * now */
+    if ( !pk->created )
+        pk->created = uiddate;
+    if ( !pk->created ) {
+        /* oops, still no creation date: use the timestamp */
+        if (DBG_CACHE)
+            log_debug( "merge_selfsigs_main: "
+                       "using timestamp as creation date\n");    
+        pk->created = pk->timestamp;
+    }
+
+    /* Now that we had a look at all user IDs we can now get some information
+     * from those user IDs.
+     */
+    
+    if ( !key_usage ) {
+        /* find the latest user ID with key flags set */
+        uiddate = 0; /* helper to find the latest user ID */
+        for(k=keyblock; k && k->pkt->pkttype != PKT_PUBLIC_SUBKEY;
+            k = k->next ) {
+            if ( k->pkt->pkttype == PKT_USER_ID
+                 || k->pkt->pkttype == PKT_PHOTO_ID ) {
+                PKT_user_id *uid = k->pkt->pkt.user_id;
+                if ( uid->help_key_usage && uid->created > uiddate ) {
+                    key_usage = uid->help_key_usage;
+                    uiddate = uid->created;
+                }
+            }
+       }
+    }
+    if ( !key_usage ) { /* no key flags at all: get it from the algo */
+        key_usage = openpgp_pk_algo_usage ( pk->pubkey_algo );
+    }
+    else { /* check that the usage matches the usage as given by the algo */
+        int x = openpgp_pk_algo_usage ( pk->pubkey_algo );
+        if ( x ) /* mask it down to the actual allowed usage */
+            key_usage &= x; 
+    }
+    pk->pubkey_usage = key_usage;
+
+
+    if ( !key_expire_seen ) {
+        /* find the latest valid user ID with a key expiration set 
+         * Note, that this may be a diferent one from the above because
+         * some user IDs may have no expiration date set */
+        uiddate = 0; 
+        for(k=keyblock; k && k->pkt->pkttype != PKT_PUBLIC_SUBKEY;
+            k = k->next ) {
+            if ( k->pkt->pkttype == PKT_USER_ID
+                 || k->pkt->pkttype == PKT_PHOTO_ID ) {
+                PKT_user_id *uid = k->pkt->pkt.user_id;
+                if ( uid->help_key_expire && uid->created > uiddate ) {
+                    key_expire = uid->help_key_expire;
+                    uiddate = uid->created;
+                }
+            }
+       }
+    }
+    if ( key_expire >= curtime )
+        pk->has_expired = key_expire;
+    /* FIXME: we should see how to get rid of the expiretime fields */
+
+
+    /* and now find the real primary user ID and delete all others */
+    uiddate = uiddate2 = 0;
+    uidnode = uidnode2 = NULL;
+    for(k=keyblock; k && k->pkt->pkttype != PKT_PUBLIC_SUBKEY; k = k->next ) {
+        if ( k->pkt->pkttype == PKT_USER_ID
+             || k->pkt->pkttype == PKT_PHOTO_ID ) {
+            PKT_user_id *uid = k->pkt->pkt.user_id;
+            if ( uid->is_primary && uid->created > uiddate ) {
+                uiddate = uid->created;
+                uidnode = k;
+            }
+            if ( !uid->is_primary && uid->created > uiddate2 ) {
+                uiddate2 = uid->created;
+                uidnode2 = k;
+            }
+        }
+    }
+    if ( uidnode ) {
+        for(k=keyblock; k && k->pkt->pkttype != PKT_PUBLIC_SUBKEY;
+            k = k->next ) {
+            if ( k->pkt->pkttype == PKT_USER_ID
+                 || k->pkt->pkttype == PKT_PHOTO_ID ) {
+                PKT_user_id *uid = k->pkt->pkt.user_id;
+                if ( k != uidnode ) 
+                    uid->is_primary = 0;
+            }
+        }
+    }
+    else if( uidnode2 ) {
+        /* none is flagged primary - use the latest user ID we have */
+        uidnode2->pkt->pkt.user_id->is_primary = 1;
+    }
+
 }
 
 
-static KBNODE
-find_by_keyid( KBNODE keyblock, PKT_public_key *pk, u32 *keyid, int mode )
+static void
+merge_selfsigs_subkey( KBNODE keyblock, KBNODE subnode )
 {
+    PKT_public_key *mainpk = NULL, *subpk = NULL;
+    PKT_signature *sig;
     KBNODE k;
+    u32 mainkid[2];
+    u32 sigdate = 0;
+    KBNODE signode;
+    u32 curtime = make_timestamp ();
+    unsigned int key_usage = 0;
+    u32 key_expire = 0;
+    const byte *p;
+    size_t n;
+
+    if ( subnode->pkt->pkttype != PKT_PUBLIC_SUBKEY )
+        BUG ();
+    mainpk = keyblock->pkt->pkt.public_key;
+    if ( mainpk->version < 4 )
+        return; /* (actually this should never happen) */
+    keyid_from_pk( mainpk, mainkid );
+    subpk = subnode->pkt->pkt.public_key;
+    subpk->is_valid = 0;
+    subpk->main_keyid[0] = mainpk->main_keyid[0];
+    subpk->main_keyid[1] = mainpk->main_keyid[1];
+    if ( subpk->version < 4 )
+        return; /* there are no v3 subkeys */
+
+    /* find the latest key binding self-signature. */
+    signode = NULL;
+    sigdate = 0; /* helper to find the latest signature */
+    for(k=subnode->next; k && k->pkt->pkttype != PKT_PUBLIC_SUBKEY;
+                                                        k = k->next ) {
+        if ( k->pkt->pkttype == PKT_SIGNATURE ) {
+            sig = k->pkt->pkt.signature;
+            if ( sig->keyid[0] == mainkid[0] && sig->keyid[1]==mainkid[1] ) { 
+               if ( check_key_signature( keyblock, k, NULL ) )
+                    ; /* signature did not verify */
+                else if ( IS_SUBKEY_REV (sig) ) {
+                    /* key has been revoked - given the fact that it is easy
+                     * to create a new subkey, it does not make sense to
+                     * revive a revoked key.  So we can stop here.
+                     */
+                    subpk->is_revoked = 1;
+                    return;
+                }
+                else if ( IS_SUBKEY_SIG (sig) && sig->timestamp >= sigdate ) {
+                    p = parse_sig_subpkt( sig->hashed_data,
+                                          SIGSUBPKT_SIG_EXPIRE, NULL );
+                    if ( p && (sig->timestamp + buffer_to_u32(p)) >= curtime )
+                        ; /* signature has expired - ignore it */
+                    else {
+                        sigdate = sig->timestamp;
+                        signode = k;
+                    }
+                }
+            }
+        }
+    }
 
-    if( DBG_CACHE )
-       log_debug("lookup keyid=%08lx%08lx req_algo=%d mode=%d\n",
-                  (ulong)keyid[0], (ulong)keyid[1], pk->pubkey_algo, mode );
+    if ( !signode ) {
+        subpk->created = subpk->timestamp;
+        return;  /* no valid key binding */
+    }
 
-    for(k=keyblock; k; k = k->next ) {
-       if(    k->pkt->pkttype == PKT_PUBLIC_KEY
-           || k->pkt->pkttype == PKT_PUBLIC_SUBKEY ) {
-           u32 aki[2];
-           keyid_from_pk( k->pkt->pkt.public_key, aki );
-           if( DBG_CACHE )
-               log_debug("         aki=%08lx%08lx algo=%d\n",
-                               (ulong)aki[0], (ulong)aki[1],
-                                k->pkt->pkt.public_key->pubkey_algo    );
-
-           if( aki[1] == keyid[1]
-               && ( mode == 10 || aki[0] == keyid[0] )
-               && ( !pk->pubkey_algo
-                    || pk->pubkey_algo
-                       == k->pkt->pkt.public_key->pubkey_algo) ){
-               KBNODE kk;
-               /* cache the userid */
-               for(kk=keyblock; kk; kk = kk->next )
-                   if( kk->pkt->pkttype == PKT_USER_ID )
-                       break;
-               if( kk )
-                   cache_user_id( kk->pkt->pkt.user_id, aki );
-               else
-                   log_error(_("No user ID for key\n"));
-               return k; /* found */
-           }
-       }
+    subpk->is_valid = 1;
+    subpk->created = sigdate; 
+    sig = signode->pkt->pkt.signature;
+        
+    p = parse_sig_subpkt ( sig->hashed_data, SIGSUBPKT_KEY_FLAGS, &n );
+    if ( p && n ) {
+        /* first octet of the keyflags */   
+        if ( (*p & 3) )
+            key_usage |= GCRY_PK_USAGE_SIGN;
+        if ( (*p & 12) )    
+            key_usage |= GCRY_PK_USAGE_ENCR;
     }
-    return NULL;
+    if ( !key_usage ) { /* no key flags at all: get it from the algo */
+        key_usage = openpgp_pk_algo_usage ( subpk->pubkey_algo );
+    }
+    else { /* check that the usage matches the usage as given by the algo */
+        int x = openpgp_pk_algo_usage ( subpk->pubkey_algo );
+        if ( x ) /* mask it down to the actual allowed usage */
+            key_usage &= x; 
+    }
+    subpk->pubkey_usage = key_usage;
+    
+    p = parse_sig_subpkt ( sig->hashed_data, SIGSUBPKT_KEY_EXPIRE, NULL);
+    if ( p ) 
+        key_expire = sig->timestamp + buffer_to_u32(p);
+    else
+        key_expire = 0;
+    subpk->has_expired = key_expire >= curtime? key_expire : 0;
 }
 
-static KBNODE
-find_by_keyid_sk( KBNODE keyblock, PKT_secret_key *sk, u32 *keyid, int mode )
+
+
+/* 
+ * Merge information from the self-signatures with the key, so that
+ * we can later use them more easy.
+ * The function works by first applying the self signatures to the
+ * primary key and the to each subkey.
+ * Here are the rules we use to decide which inormation from which
+ * self-signature is used:
+ * We check all self signatures or validity and ignore all invalid signatures.
+ * All signatures are then ordered by their creation date ....
+ * For the primary key:
+ *   FIXME the docs    
+ */
+static void
+merge_selfsigs( KBNODE keyblock )
 {
     KBNODE k;
+    int revoked;
+    PKT_public_key *main_pk;
+
+    if ( keyblock->pkt->pkttype != PKT_PUBLIC_KEY )
+        BUG ();
+
+    merge_selfsigs_main ( keyblock, &revoked );
+    main_pk = keyblock->pkt->pkt.public_key;
+    if ( revoked ) {
+        /* if the primary key has been revoked we better set the revoke
+         * flag on that key and all subkeys */
+        for(k=keyblock; k; k = k->next ) {
+            if ( k->pkt->pkttype == PKT_PUBLIC_KEY
+                || k->pkt->pkttype == PKT_PUBLIC_SUBKEY ) {
+                PKT_public_key *pk = k->pkt->pkt.public_key;
+                pk->is_revoked = 1;
+                pk->main_keyid[0] = main_pk->main_keyid[0];
+                pk->main_keyid[1] = main_pk->main_keyid[1];
+            }
+       }
+        return;
+    }
 
-    if( DBG_CACHE )
-       log_debug("lookup_sk keyid=%08lx%08lx req_algo=%d mode=%d\n",
-                  (ulong)keyid[0], (ulong)keyid[1], sk->pubkey_algo, mode );
-
+    /* now merge in the data from each of the subkeys */
     for(k=keyblock; k; k = k->next ) {
-       if(    k->pkt->pkttype == PKT_SECRET_KEY
-           || k->pkt->pkttype == PKT_SECRET_SUBKEY ) {
-           u32 aki[2];
-           keyid_from_sk( k->pkt->pkt.secret_key, aki );
-           if( DBG_CACHE )
-               log_debug("         aki=%08lx%08lx algo=%d\n",
-                               (ulong)aki[0], (ulong)aki[1],
-                                k->pkt->pkt.secret_key->pubkey_algo    );
-
-           if( aki[1] == keyid[1]
-               && ( mode == 10 || aki[0] == keyid[0] )
-               && ( !sk->pubkey_algo
-                    || sk->pubkey_algo
-                       == k->pkt->pkt.secret_key->pubkey_algo) ){
-               KBNODE kk;
-               /* cache the userid */
-               for(kk=keyblock; kk; kk = kk->next )
-                   if( kk->pkt->pkttype == PKT_USER_ID )
-                       break;
-               if( kk )
-                   cache_user_id( kk->pkt->pkt.user_id, aki );
-               else
-                   log_error(_("No user ID for key\n"));
-               return k; /* found */
-           }
-       }
+       if (  k->pkt->pkttype == PKT_PUBLIC_SUBKEY ) {
+            merge_selfsigs_subkey ( keyblock, k );
+        }
     }
-    return NULL;
 }
 
 
-static KBNODE
-find_first( KBNODE keyblock, PKT_public_key *pk )
+/*
+ * Merge the secret keys from secblock into the pubblock thereby
+ * replacing the public (sub)keys with their secret counterparts Hmmm:
+ * It might be better to get away from the concept of entire secret
+ * keys at all and have a way to store just the real secret parts
+ * from the key.
+ */
+static void
+merge_public_with_secret ( KBNODE pubblock, KBNODE secblock )
 {
-    KBNODE k;
+    KBNODE pub;
+    int deleting = 0;
+    int any_deleted = 0;
+
+    assert ( pubblock->pkt->pkttype == PKT_PUBLIC_KEY );
+    assert ( secblock->pkt->pkttype == PKT_SECRET_KEY );
+    
+    for (pub=pubblock; pub; pub = pub->next ) {
+        if ( pub->pkt->pkttype == PKT_PUBLIC_KEY ) {
+             PKT_public_key *pk = pub->pkt->pkt.public_key;
+             PKT_secret_key *sk = secblock->pkt->pkt.secret_key;
+             assert ( pub == pubblock ); /* only in the first node */
+             /* there is nothing to compare in this case, so just replace
+              * some information */
+             copy_public_parts_to_secret_key ( pk, sk );
+             free_public_key ( pk );
+             pub->pkt->pkttype = PKT_SECRET_KEY;
+             pub->pkt->pkt.secret_key = copy_secret_key (NULL, sk);
+        }
+        else if ( pub->pkt->pkttype == PKT_PUBLIC_SUBKEY ) {
+            KBNODE sec;
+            PKT_public_key *pk = pub->pkt->pkt.public_key;
+
+            deleting = 0;
+            /* this is more complicated: it may happen that the sequence
+             * of the subkeys dosn't match, so we have to find the
+             * appropriate secret key */
+            for (sec=secblock->next; sec; sec = sec->next ) {
+                if ( sec->pkt->pkttype == PKT_SECRET_SUBKEY ) {
+                    PKT_secret_key *sk = sec->pkt->pkt.secret_key;
+                    if ( !cmp_public_secret_key ( pk, sk ) ) {
+                        copy_public_parts_to_secret_key ( pk, sk );
+                        free_public_key ( pk );
+                        pub->pkt->pkttype = PKT_SECRET_KEY;
+                        pub->pkt->pkt.secret_key = copy_secret_key (NULL, sk);
+                        break;
+                    }
+                }
+            }
+            if ( !sec ) {
+                log_error ( "no corresponding secret subkey "
+                            "for public subkey - removing\n" );
+                /* better remove the public subkey in this case */
+                delete_kbnode ( pub );
+                deleting = 1;
+                any_deleted = 1;
+            }
+        }
+        else if ( deleting ) {
+            delete_kbnode (pub);
+        }
+    }
 
-    for(k=keyblock; k; k = k->next ) {
-       if(    k->pkt->pkttype == PKT_PUBLIC_KEY
-           || k->pkt->pkttype == PKT_PUBLIC_SUBKEY )
-       {
-           if( !pk->pubkey_algo
-               || pk->pubkey_algo == k->pkt->pkt.public_key->pubkey_algo )
-               return k;
-       }
+    if ( any_deleted ) {
+        /* because we have not deleted the root node, we don't need to
+         * update the pubblock */
+        pub = pubblock;
+        commit_kbnode ( &pubblock );
+        assert ( pub == pubblock );
     }
-    return NULL;
 }
 
-static KBNODE
-find_first_sk( KBNODE keyblock, PKT_secret_key *sk )
+
+
+\f
+/************************************************
+ ************* Find stuff ***********************
+ ************************************************/
+
+static int 
+find_by_name( KBNODE keyblock, const char *name,
+             int mode, byte *namehash )
 {
     KBNODE k;
 
     for(k=keyblock; k; k = k->next ) {
-       if(    k->pkt->pkttype == PKT_SECRET_KEY
-           || k->pkt->pkttype == PKT_SECRET_SUBKEY )
-       {
-           if( !sk->pubkey_algo
-               || sk->pubkey_algo == k->pkt->pkt.secret_key->pubkey_algo )
-               return k;
-       }
+       if( k->pkt->pkttype == PKT_USER_ID
+           && !compare_name( k->pkt->pkt.user_id->name,
+                             k->pkt->pkt.user_id->len, name, mode)) {
+           /* we found a matching name, look for the key */
+            if( k->pkt->pkt.user_id->photo ) {
+                /* oops: this can never happen */
+                gcry_md_hash_buffer( GCRY_MD_RMD160, namehash,
+                                     k->pkt->pkt.user_id->photo,
+                                     k->pkt->pkt.user_id->photolen );
+            }
+            else {
+                gcry_md_hash_buffer( GCRY_MD_RMD160, namehash,
+                                     k->pkt->pkt.user_id->name,
+                                     k->pkt->pkt.user_id->len );
+            }
+            return 1; 
+        }
     }
-    return NULL;
+    
+    return 0;
 }
 
 
+
 static KBNODE
-find_by_fpr( KBNODE keyblock, PKT_public_key *pk, const char *name, int mode )
+find_by_keyid( KBNODE keyblock, u32 *keyid, int mode )
 {
     KBNODE k;
 
     for(k=keyblock; k; k = k->next ) {
        if(    k->pkt->pkttype == PKT_PUBLIC_KEY
            || k->pkt->pkttype == PKT_PUBLIC_SUBKEY ) {
-           byte afp[MAX_FINGERPRINT_LEN];
-           size_t an;
-
-           fingerprint_from_pk(k->pkt->pkt.public_key, afp, &an );
-
-           if( DBG_CACHE ) {
-               u32 aki[2];
-               keyid_from_pk( k->pkt->pkt.public_key, aki );
-               log_debug("         aki=%08lx%08lx algo=%d mode=%d an=%u\n",
-                               (ulong)aki[0], (ulong)aki[1],
-                       k->pkt->pkt.public_key->pubkey_algo, mode,
-                                                           (unsigned)an );
+           u32 aki[2];
+           keyid_from_pk( k->pkt->pkt.public_key, aki );
+           if( aki[1] == keyid[1] && ( mode == 10 || aki[0] == keyid[0] ) ) {
+                return k; /* found */
            }
-
-           if( an == mode
-               && !memcmp( afp, name, an)
-               && ( !pk->pubkey_algo
-                    || pk->pubkey_algo == k->pkt->pkt.public_key->pubkey_algo) )
-               return k;
        }
     }
     return NULL;
 }
 
+
+
 static KBNODE
-find_by_fpr_sk( KBNODE keyblock, PKT_secret_key *sk,
-                                const char *name, int mode )
+find_by_fpr( KBNODE keyblock,  const char *name, int mode )
 {
     KBNODE k;
 
     for(k=keyblock; k; k = k->next ) {
-       if(    k->pkt->pkttype == PKT_SECRET_KEY
-           || k->pkt->pkttype == PKT_SECRET_SUBKEY ) {
+       if(    k->pkt->pkttype == PKT_PUBLIC_KEY
+           || k->pkt->pkttype == PKT_PUBLIC_SUBKEY ) {
            byte afp[MAX_FINGERPRINT_LEN];
            size_t an;
 
-           fingerprint_from_sk(k->pkt->pkt.secret_key, afp, &an );
-
-           if( DBG_CACHE ) {
-               u32 aki[2];
-               keyid_from_sk( k->pkt->pkt.secret_key, aki );
-               log_debug("         aki=%08lx%08lx algo=%d mode=%d an=%u\n",
-                               (ulong)aki[0], (ulong)aki[1],
-                       k->pkt->pkt.secret_key->pubkey_algo, mode,
-                                                       (unsigned)an );
-           }
-
-           if( an == mode
-               && !memcmp( afp, name, an)
-               && ( !sk->pubkey_algo
-                    || sk->pubkey_algo == k->pkt->pkt.secret_key->pubkey_algo) )
-               return k;
+           fingerprint_from_pk(k->pkt->pkt.public_key, afp, &an );
+           if( an == mode && !memcmp( afp, name, an) ) {
+                return k;
+            }
        }
     }
     return NULL;
 }
 
 
-/****************
- * Return the expiretime of a subkey.
- */
-static u32
-subkeys_expiretime( KBNODE node, u32 *mainkid )
-{
-    KBNODE k;
-    PKT_signature *sig;
-    u32 expires = 0, sigdate = 0;
-
-    assert( node->pkt->pkttype == PKT_PUBLIC_SUBKEY );
-    for(k=node->next; k; k = k->next ) {
-       if( k->pkt->pkttype == PKT_SIGNATURE
-           && (sig=k->pkt->pkt.signature)->sig_class == 0x18
-           && sig->keyid[0] == mainkid[0]
-           && sig->keyid[1] == mainkid[1]
-           && sig->version > 3
-           && sig->timestamp > sigdate ) {
-           /* okay this is a key-binding which can be used.
-            * We use the latest self-signature.
-            * FIXME: We should only use this if the binding signature is valid
-            *        but this is time consuming - we must provide another
-            *        way to handle this
-            */
-           const byte *p;
-           u32 ed;
-
-           p = parse_sig_subpkt( sig->hashed_data, SIGSUBPKT_KEY_EXPIRE, NULL );
-           ed = p? node->pkt->pkt.public_key->timestamp + buffer_to_u32(p):0;
-           sigdate = sig->timestamp;
-           expires = ed;
-       }
-       else if( k->pkt->pkttype == PKT_PUBLIC_SUBKEY )
-           break; /* stop at the next subkey */
-    }
-
-    return expires;
-}
 
 
-/****************
- * Check whether the subkey has expired.  Node must point to the subkey
+/* See see whether the key fits
+ * our requirements and in case we do not
+ * request a the primary key, we should select
+ * a suitable subkey.
+ * FIXME: Check against PGP 7 whether we still need a kludge
+ *        to favor type 16 keys over type 20 keys when type 20
+ *        has not been explitely requested.
+ * Returns: True when a suitable key has been found.
+ *
+ * We have to distinguish four cases:
+ *  1. No usage and no primary key requested
+ *     Examples for this case are that we have a keyID to be used
+ *     for decrytion or verification.
+ *  2. No usage but primary key requested
+ *     This is the case for all functions which work on an
+ *     entire keyblock, e.g. for editing or listing
+ *  3. Usage and primary key requested
+ *     FXME
+ *  4. Usage but no primary key requested
+ *     FIXME
+ * FIXME: Tell what is going to happen here and something about the rationale
+ *
  */
+
 static int
-has_expired( KBNODE node, u32 *mainkid, u32 cur_time )
+finish_lookup( GETKEY_CTX ctx,  KBNODE foundk )
 {
-    u32 expires = subkeys_expiretime( node, mainkid );
-    return expires && expires <= cur_time;
-}
+    KBNODE keyblock = ctx->keyblock;
+    KBNODE k;
+  #define USAGE_MASK  (GCRY_PK_USAGE_SIGN|GCRY_PK_USAGE_ENCR)
+    unsigned int req_usage = ( ctx->req_usage & USAGE_MASK );
+    u32 latest_date;
+    KBNODE latest_key;
 
-static void
-finish_lookup( KBNODE keyblock, PKT_public_key *pk, KBNODE k, byte *namehash,
-                                              int use_namehash, int primary )
-{
-    assert(    k->pkt->pkttype == PKT_PUBLIC_KEY
-           || k->pkt->pkttype == PKT_PUBLIC_SUBKEY );
+    assert( !foundk || foundk->pkt->pkttype == PKT_PUBLIC_KEY
+                   || foundk->pkt->pkttype == PKT_PUBLIC_SUBKEY );
     assert( keyblock->pkt->pkttype == PKT_PUBLIC_KEY );
-    if( primary && !pk->pubkey_usage ) {
-       copy_public_key_new_namehash( pk, keyblock->pkt->pkt.public_key,
-                                     use_namehash? namehash:NULL);
-       merge_one_pk_and_selfsig( keyblock, keyblock, pk );
+   
+    ctx->found_key = NULL;
+    
+    if ( DBG_CACHE )
+        log_debug( "finish_lookup: checking %s (req_usage=%x)\n",
+                   foundk? "one key":"all keys", req_usage);
+
+    latest_date = 0;
+    latest_key  = NULL;
+    /* We do check the subkeys only if we either have requested a specific
+     * usage or have not requested to get the primary key. */
+    if ( (req_usage || !ctx->primary)
+         && (!foundk || foundk->pkt->pkttype == PKT_PUBLIC_SUBKEY) ) {
+        KBNODE nextk;
+        /* either start a loop or check just this one subkey */
+        for (k=foundk?foundk:keyblock; k; k = nextk ) {
+            PKT_public_key *pk;
+            nextk = k->next;
+            if ( k->pkt->pkttype != PKT_PUBLIC_SUBKEY )
+                continue;
+            if ( foundk )
+                nextk = NULL;  /* what a hack */
+            pk = k->pkt->pkt.public_key;
+            if ( !pk->is_valid ) {
+                if (DBG_CACHE)
+                    log_debug( "\tsubkey not valid\n");
+                continue;
+            }
+            if ( pk->is_revoked ) {
+                if (DBG_CACHE)
+                    log_debug( "\tsubkey has been revoked\n");
+                continue;
+            }
+            if ( pk->has_expired ) {
+                if (DBG_CACHE)
+                    log_debug( "\tsubkey has expired\n");
+                continue;
+            }
+            
+            if ( req_usage &&
+                 !((pk->pubkey_usage&USAGE_MASK) & req_usage) ) {
+                if (DBG_CACHE)
+                    log_debug( "\tusage does not match: want=%x have=%x\n",
+                               req_usage, pk->pubkey_usage );
+                continue;
+            }
+
+            if (DBG_CACHE)
+                log_debug( "\tconsidering key created %lu\n",
+                           (ulong)pk->created);
+            if ( pk->created > latest_date ) {
+                latest_date = pk->created;
+                latest_key  = k;
+            }
+        }
     }
-    else {
-       if( primary && pk->pubkey_usage
-           && openpgp_pk_test_algo( k->pkt->pkt.public_key->pubkey_algo,
-                      pk->pubkey_usage ) == GPGERR_WR_PUBKEY_ALGO ) {
-           /* if the usage is not correct, try to use a subkey */
-           KBNODE save_k = k;
-           u32 mainkid[2];
-           u32 cur_time = make_timestamp();
-
-           keyid_from_pk( keyblock->pkt->pkt.public_key, mainkid );
-
-           k = NULL;
-           /* kludge for pgp 5: which doesn't accept type 20:
-            * try to use a type 16 subkey instead */
-           if( pk->pubkey_usage == GCRY_PK_USAGE_ENCR ) {
-               for( k = save_k; k; k = k->next ) {
-                   if( k->pkt->pkttype == PKT_PUBLIC_SUBKEY
-                       && k->pkt->pkt.public_key->pubkey_algo
-                           == GCRY_PK_ELG_E
-                       && !openpgp_pk_test_algo(
-                               k->pkt->pkt.public_key->pubkey_algo,
-                                                pk->pubkey_usage )
-                       && !has_expired(k, mainkid, cur_time) )
-                       break;
-               }
-           }
 
-           if( !k ) {
-               for(k = save_k ; k; k = k->next ) {
-                   if( k->pkt->pkttype == PKT_PUBLIC_SUBKEY
-                       && !openpgp_pk_test_algo(
-                               k->pkt->pkt.public_key->pubkey_algo,
-                                                pk->pubkey_usage )
-                       && ( pk->pubkey_usage != GCRY_PK_USAGE_ENCR
-                            || !has_expired( k, mainkid, cur_time ) )
-                     )
-                       break;
-               }
-           }
-           if( !k )
-               k = save_k;
-           else
-               log_info(_("using secondary key %08lX "
-                          "instead of primary key %08lX\n"),
-                     (ulong)keyid_from_pk( k->pkt->pkt.public_key, NULL),
-                     (ulong)keyid_from_pk( save_k->pkt->pkt.public_key, NULL)
-                       );
-       }
-
-       copy_public_key_new_namehash( pk, k->pkt->pkt.public_key,
-                                     use_namehash? namehash:NULL);
-       merge_one_pk_and_selfsig( keyblock, k, pk );
+    if ( !latest_key ) {
+        PKT_public_key *pk;
+        if (DBG_CACHE && !foundk )
+            log_debug( "\tno suitable subkeys found - trying primary\n");
+        pk = keyblock->pkt->pkt.public_key;
+        if ( !pk->is_valid ) {
+            if (DBG_CACHE)
+                log_debug( "\tprimary key not valid\n");
+        }
+        else if ( pk->is_revoked ) {
+            if (DBG_CACHE)
+                log_debug( "\tprimary key has been revoked\n");
+        }
+        else if ( pk->has_expired ) {
+            if (DBG_CACHE)
+                log_debug( "\tprimary key has expired\n");
+        }
+        else  if ( req_usage
+                   && !((pk->pubkey_usage&USAGE_MASK) & req_usage) ) {
+            if (DBG_CACHE)
+                log_debug( "\tusage does not match: want=%x have=%x\n",
+                           req_usage, pk->pubkey_usage );
+        }
+        else { /* okay */
+            if (DBG_CACHE)
+                log_debug( "\tprimary key may be used\n");
+            latest_key = keyblock;
+            latest_date = pk->created;
+        }
     }
-}
-
-static void
-finish_lookup_sk( KBNODE keyblock, PKT_secret_key *sk, KBNODE k, int primary )
-{
-    assert(    k->pkt->pkttype == PKT_SECRET_KEY
-           || k->pkt->pkttype == PKT_SECRET_SUBKEY );
-    assert( keyblock->pkt->pkttype == PKT_SECRET_KEY );
-    if( primary && !sk->pubkey_usage ) {
-       copy_secret_key( sk, keyblock->pkt->pkt.secret_key );
+    
+    if ( !latest_key ) {
+        if (DBG_CACHE)
+            log_debug("\tno suitable key found -  giving up\n");
+        return 0;
     }
-    else {
-       if( primary && sk->pubkey_usage
-           && openpgp_pk_test_algo( k->pkt->pkt.secret_key->pubkey_algo,
-                      sk->pubkey_usage ) == GPGERR_WR_PUBKEY_ALGO ) {
-           /* if the usage is not correct, try to use a subkey */
-           KBNODE save_k = k;
-
-           k = NULL;
-           /* kludge for pgp 5: which doesn't accept type 20:
-            * try to use a type 16 subkey instead */
-           if( sk->pubkey_usage == GCRY_PK_USAGE_ENCR ) {
-               for( k = save_k; k; k = k->next ) {
-                   if( k->pkt->pkttype == PKT_SECRET_SUBKEY
-                       && k->pkt->pkt.secret_key->pubkey_algo
-                           == GCRY_PK_ELG_E
-                       && !openpgp_pk_test_algo(
-                               k->pkt->pkt.secret_key->pubkey_algo,
-                                                sk->pubkey_usage ) )
-                       break;
-               }
-           }
 
-           if( !k ) {
-               for(k = save_k ; k; k = k->next ) {
-                   if( k->pkt->pkttype == PKT_SECRET_SUBKEY
-                       && !openpgp_pk_test_algo(
-                               k->pkt->pkt.secret_key->pubkey_algo,
-                                                sk->pubkey_usage ) )
-                       break;
-               }
-           }
-           if( !k )
-               k = save_k;
-           else
-               log_info(_("using secondary key %08lX "
-                          "instead of primary key %08lX\n"),
-                     (ulong)keyid_from_sk( k->pkt->pkt.secret_key, NULL),
-                     (ulong)keyid_from_sk( save_k->pkt->pkt.secret_key, NULL)
-                       );
-       }
+    if (DBG_CACHE)
+        log_debug( "\tusing key created %lu\n", (ulong)latest_date );
+
+    ctx->found_key = latest_key;
 
-       copy_secret_key( sk, k->pkt->pkt.secret_key );
+    if ( latest_key != keyblock ) {
+        log_info(_("using secondary key %08lX "
+                   "instead of primary key %08lX\n"),
+                 (ulong)keyid_from_pk( latest_key->pkt->pkt.public_key, NULL),
+                 (ulong)keyid_from_pk( keyblock->pkt->pkt.public_key, NULL) );
     }
-}
 
+    cache_user_id( keyblock );
+    
+    return 1; /* found */
+}
 
 static int
-lookup_pk( GETKEY_CTX ctx, PKT_public_key *pk, KBNODE *ret_keyblock )
+lookup( GETKEY_CTX ctx, KBNODE *ret_keyblock, int secmode )
 {
     int rc;
-    KBNODE k;
     int oldmode = set_packet_list_mode(0);
     byte namehash[20];
     int use_namehash=0;
+    KBNODE secblock = NULL; /* helper */
 
     if( !ctx->count ) /* first time */
-       rc = enum_keyblocks( 0, &ctx->kbpos, &ctx->keyblock );
+       rc = enum_keyblocks( secmode?5:0, &ctx->kbpos, &ctx->keyblock );
     else
        rc = 0;
     if( !rc ) {
        while( !(rc = enum_keyblocks( 1, &ctx->kbpos, &ctx->keyblock )) ) {
            int n;
            getkey_item_t *item;
-           /* fixme: we don't enum the complete keyblock, but
-            * use the first match and then continue with the next keyblock
-            */
+
+            if ( secmode ) {
+                /* find the correspondig public key and use this 
+                 * this one for the selection process */
+                u32 aki[2];
+                KBNODE k = ctx->keyblock;
+                
+                if ( k->pkt->pkttype != PKT_SECRET_KEY )
+                    BUG();
+                keyid_from_sk( k->pkt->pkt.secret_key, aki );
+               k = get_pubkeyblock( aki );
+               if( !k ) {
+                   log_info(_("key %08lX: secret key without public key "
+                               "- skipped\n"),  (ulong)aki[1] );
+                    goto skip;
+                }
+                secblock = ctx->keyblock;
+                ctx->keyblock = k;
+            }
+
+
            /* loop over all the user ids we want to look for */
            item = ctx->items;
            for(n=0; n < ctx->nitems; n++, item++ ) {
-               if( item->mode < 10 )
-                   k = find_by_name( ctx->keyblock, pk,
-                                     item->name, item->mode,
-                                     namehash, &use_namehash );
-               else if( item->mode >= 10 && item->mode <= 12 )
-                   k = find_by_keyid( ctx->keyblock, pk,
+                KBNODE k = NULL;
+                int found = 0;
+    
+               if( item->mode < 10 ) {
+                   found = find_by_name( ctx->keyblock,
+                                          item->name, item->mode,
+                                          namehash );
+                    use_namehash = found;
+                }
+               else if( item->mode >= 10 && item->mode <= 12 ) {
+                   k = find_by_keyid( ctx->keyblock, 
                                       item->keyid, item->mode );
-               else if( item->mode == 15 )
-                   k = find_first( ctx->keyblock, pk );
-               else if( item->mode == 16 || item->mode == 20 )
-                   k = find_by_fpr( ctx->keyblock, pk,
+                    found = !!k;
+                }
+               else if( item->mode == 15 ) {
+                   found = 1;
+                }
+               else if( item->mode == 16 || item->mode == 20 ) {
+                   k = find_by_fpr( ctx->keyblock,
                                     item->fprint, item->mode );
+                    found = !!k;
+                }
                else
                    BUG();
-               if( k ) {
-                   finish_lookup( ctx->keyblock, pk, k, namehash,
-                                                use_namehash, ctx->primary );
-                   goto found;
+               if( found ) { 
+                    /* this keyblock looks fine - do further investigation */
+                    merge_selfsigs ( ctx->keyblock );
+                   if ( finish_lookup( ctx, k ) ) {
+                        if ( secmode ) {
+                            merge_public_with_secret ( ctx->keyblock,
+                                                       secblock);
+                            release_kbnode (secblock);
+                            secblock = NULL;
+                        }
+                        goto found;
+                    }
                }
            }
+          skip:
+            /* release resources and try the next keyblock */
+            if ( secmode ) {
+                release_kbnode( secblock );
+                secblock = NULL;
+            }
            release_kbnode( ctx->keyblock );
            ctx->keyblock = NULL;
        }
-      found: ;
+      found:
+        ;
     }
     if( rc && rc != -1 )
        log_error("enum_keyblocks failed: %s\n", gpg_errstr(rc));
 
     if( !rc ) {
-       if( ret_keyblock ) {
-           *ret_keyblock = ctx->keyblock;
-           ctx->keyblock = NULL;
-       }
+        *ret_keyblock = ctx->keyblock; /* return the keyblock */
+        ctx->keyblock = NULL;
     }
     else if( rc == -1 )
-       rc = GPGERR_NO_PUBKEY;
+       rc = secmode ? GPGERR_NO_SECKEY : GPGERR_NO_PUBKEY;
 
+    if ( secmode ) {
+        release_kbnode( secblock );
+        secblock = NULL;
+    }
     release_kbnode( ctx->keyblock );
     ctx->keyblock = NULL;
     set_packet_list_mode(oldmode);
@@ -1786,7 +2127,7 @@ lookup_pk( GETKEY_CTX ctx, PKT_public_key *pk, KBNODE *ret_keyblock )
        lkup_stats[ctx->mode].any = 1;
        if( !rc )
            lkup_stats[ctx->mode].okay_count++;
-       else if ( rc == GPGERR_NO_PUBKEY )
+       else if ( rc == GPGERR_NO_PUBKEY || rc == GPGERR_NO_SECKEY )
            lkup_stats[ctx->mode].nokey_count++;
        else
            lkup_stats[ctx->mode].error_count++;
@@ -1800,75 +2141,14 @@ lookup_pk( GETKEY_CTX ctx, PKT_public_key *pk, KBNODE *ret_keyblock )
 
 
 
-static int
-lookup_sk( GETKEY_CTX ctx, PKT_secret_key *sk, KBNODE *ret_keyblock )
-{
-    int rc;
-    KBNODE k;
-    int oldmode = set_packet_list_mode(0);
-
-    if( !ctx->count ) /* first time */
-       rc = enum_keyblocks( 5, &ctx->kbpos, &ctx->keyblock );
-    else
-       rc = 0;
-    if( !rc ) {
-       while( !(rc = enum_keyblocks( 1, &ctx->kbpos, &ctx->keyblock )) ) {
-           int n;
-           getkey_item_t *item;
-           /* fixme: we don't enum the complete keyblock, but
-            * use the first match and then continue with the next keyblock
-            */
-           /* loop over all the user ids we want to look for */
-           item = ctx->items;
-           for(n=0; n < ctx->nitems; n++, item++ ) {
-               if( item->mode < 10 )
-                   k = find_by_name_sk( ctx->keyblock, sk,
-                                        item->name, item->mode );
-               else if( item->mode >= 10 && item->mode <= 12 )
-                   k = find_by_keyid_sk( ctx->keyblock, sk,
-                                         item->keyid, item->mode );
-               else if( item->mode == 15 )
-                   k = find_first_sk( ctx->keyblock, sk );
-               else if( item->mode == 16 || item->mode == 20 )
-                   k = find_by_fpr_sk( ctx->keyblock, sk,
-                                       item->fprint, item->mode );
-               else
-                   BUG();
-               if( k ) {
-                   finish_lookup_sk( ctx->keyblock, sk, k, ctx->primary );
-                   goto found;
-               }
-           }
-           release_kbnode( ctx->keyblock );
-           ctx->keyblock = NULL;
-       }
-      found: ;
-    }
-    if( rc && rc != -1 )
-       log_error("enum_keyblocks failed: %s\n", gpg_errstr(rc));
-
-    if( !rc ) {
-       if( ret_keyblock ) {
-           *ret_keyblock = ctx->keyblock;
-           ctx->keyblock = NULL;
-       }
-    }
-    else if( rc == -1 )
-       rc = GPGERR_NO_SECKEY;
-
-    release_kbnode( ctx->keyblock );
-    ctx->keyblock = NULL;
-    set_packet_list_mode(oldmode);
-
-    ctx->last_rc = rc;
-    ctx->count++;
-    return rc;
-}
-
 
 
 /****************
- * fixme: replace by the generic function
+ * FIXME: Replace by the generic function 
+ *        It does not work as it is right now - it is used at 
+ *        2 places:  a) to get the key for an anonyous recipient
+ *                   b) to get the ultimately trusted keys.
+ *        The a) usage might have some problems.
  *
  * Enumerate all primary secret keys.  Caller must use these procedure:
  *  1) create a void pointer and initialize it to NULL
@@ -1943,6 +2223,11 @@ enum_secret_keys( void **context, PKT_secret_key *sk, int with_subkeys )
 }
 
 
+\f
+/*********************************************
+ ***********  user ID printing helpers *******
+ *********************************************/
+
 /****************
  * Return a string with a printable representation of the user_id.
  * this string must be freed by m_free.
@@ -1955,12 +2240,17 @@ get_user_id_string( u32 *keyid )
     int pass=0;
     /* try it two times; second pass reads from key resources */
     do {
-       for(r=user_id_db; r; r = r->next )
-           if( r->keyid[0] == keyid[0] && r->keyid[1] == keyid[1] ) {
-               p = gcry_xmalloc( r->len + 10 );
-               sprintf(p, "%08lX %.*s", (ulong)keyid[1], r->len, r->name );
-               return p;
-           }
+       for(r=user_id_db; r; r = r->next ) {
+            keyid_list_t a;
+            for (a=r->keyids; a; a= a->next ) {
+                if( a->keyid[0] == keyid[0] && a->keyid[1] == keyid[1] ) {
+                    p = gcry_xmalloc( r->len + 10 );
+                    sprintf(p, "%08lX %.*s",
+                            (ulong)keyid[1], r->len, r->name );
+                    return p;
+                }
+            }
+        }
     } while( ++pass < 2 && !get_pubkey( NULL, keyid ) );
     p = gcry_xmalloc( 15 );
     sprintf(p, "%08lX [?]", (ulong)keyid[1] );
@@ -1987,13 +2277,18 @@ get_long_user_id_string( u32 *keyid )
     int pass=0;
     /* try it two times; second pass reads from key resources */
     do {
-       for(r=user_id_db; r; r = r->next )
-           if( r->keyid[0] == keyid[0] && r->keyid[1] == keyid[1] ) {
-               p = gcry_xmalloc( r->len + 20 );
-               sprintf(p, "%08lX%08lX %.*s",
-                         (ulong)keyid[0], (ulong)keyid[1], r->len, r->name );
-               return p;
-           }
+       for(r=user_id_db; r; r = r->next ) {
+            keyid_list_t a;
+            for (a=r->keyids; a; a= a->next ) {
+                if( a->keyid[0] == keyid[0] && a->keyid[1] == keyid[1] ) {
+                    p = gcry_xmalloc( r->len + 20 );
+                    sprintf(p, "%08lX%08lX %.*s",
+                            (ulong)keyid[0], (ulong)keyid[1],
+                            r->len, r->name );
+                    return p;
+                }
+            }
+        }
     } while( ++pass < 2 && !get_pubkey( NULL, keyid ) );
     p = gcry_xmalloc( 25 );
     sprintf(p, "%08lX%08lX [?]", (ulong)keyid[0], (ulong)keyid[1] );
@@ -2009,13 +2304,17 @@ get_user_id( u32 *keyid, size_t *rn )
 
     /* try it two times; second pass reads from key resources */
     do {
-       for(r=user_id_db; r; r = r->next )
-           if( r->keyid[0] == keyid[0] && r->keyid[1] == keyid[1] ) {
-               p = gcry_xmalloc( r->len );
-               memcpy(p, r->name, r->len );
-               *rn = r->len;
-               return p;
-           }
+       for(r=user_id_db; r; r = r->next ) {
+            keyid_list_t a;
+            for (a=r->keyids; a; a= a->next ) {
+                if( a->keyid[0] == keyid[0] && a->keyid[1] == keyid[1] ) {
+                    p = gcry_xmalloc( r->len );
+                    memcpy(p, r->name, r->len );
+                    *rn = r->len;
+                    return p;
+                }
+            }
+        }
     } while( ++pass < 2 && !get_pubkey( NULL, keyid ) );
     p = gcry_xstrdup( _("[User id not found]") );
     *rn = strlen(p);
index 73919ae..be4ec98 100644 (file)
--- a/g10/gpg.c
+++ b/g10/gpg.c
@@ -179,6 +179,7 @@ enum cmd_and_opt_values { aNull = 0,
     oDisableCipherAlgo,
     oDisablePubkeyAlgo,
     oAllowNonSelfsignedUID,
+    oAllowFreeformUID,
     oNoLiteral,
     oSetFilesize,
     oHonorHttpProxy,
@@ -188,7 +189,9 @@ enum cmd_and_opt_values { aNull = 0,
     oNoRandomSeedFile,
     oNoAutoKeyRetrieve,
     oUseAgent,
-    oEmu3DESS2KBug,  /* will be removed in 1.1 */
+    oMergeOnly,
+    oTryAllSecrets,
+    oTrustedKey,
     oEmuMDEncodeBug,
 aTest };
 
@@ -290,6 +293,7 @@ static ARGPARSE_OPTS opts[] = {
     { oCompletesNeeded, "completes-needed", 1, "@"},
     { oMarginalsNeeded, "marginals-needed", 1, "@"},
     { oMaxCertDepth,   "max-cert-depth", 1, "@" },
+    { oTrustedKey, "trusted-key", 2, N_("|KEYID|ulimately trust this key")},
     { oLoadExtension, "load-extension" ,2, N_("|FILE|load extension module FILE")},
     { oRFC1991, "rfc1991",   0, N_("emulate the mode described in RFC1991")},
     { oOpenPGP, "openpgp", 0, N_("set all packet, cipher and digest options to OpenPGP behavior")},
@@ -362,6 +366,7 @@ static ARGPARSE_OPTS opts[] = {
     { oDisableCipherAlgo,  "disable-cipher-algo", 2, "@" },
     { oDisablePubkeyAlgo,  "disable-pubkey-algo", 2, "@" },
     { oAllowNonSelfsignedUID, "allow-non-selfsigned-uid", 0, "@" },
+    { oAllowFreeformUID, "allow-freeform-uid", 0, "@" },
     { oNoLiteral, "no-literal", 0, "@" },
     { oSetFilesize, "set-filesize", 20, "@" },
     { oHonorHttpProxy,"honor-http-proxy", 0, "@" },
@@ -370,7 +375,8 @@ static ARGPARSE_OPTS opts[] = {
     { oIgnoreTimeConflict, "ignore-time-conflict", 0, "@" },
     { oNoRandomSeedFile,  "no-random-seed-file", 0, "@" },
     { oNoAutoKeyRetrieve, "no-auto-key-retrieve", 0, "@" },
-    { oEmu3DESS2KBug,  "emulate-3des-s2k-bug", 0, "@"},
+    { oMergeOnly,        "merge-only", 0, "@" },
+    { oTryAllSecrets,  "try-all-secrets", 0, "@" },
     { oEmuMDEncodeBug, "emulate-md-encode-bug", 0, "@"},
 {0} };
 
@@ -601,6 +607,7 @@ main( int argc, char **argv )
     char **orig_argv;
     const char *fname;
     char *username;
+    int may_coredump;
     STRLIST sl, remusr= NULL, locusr=NULL;
     STRLIST nrings=NULL, sec_nrings=NULL;
     armor_filter_context_t afx;
@@ -642,7 +649,7 @@ main( int argc, char **argv )
     }
 
     gcry_control( GCRYCTL_USE_SECURE_RNDPOOL );
-    disable_core_dumps();
+    may_coredump = disable_core_dumps();
     init_signals();
     create_dotlock(NULL); /* register locking cleanup */
     i18n_init();
@@ -653,8 +660,8 @@ main( int argc, char **argv )
     opt.def_digest_algo = 0;
     opt.def_compress_algo = 2;
     opt.s2k_mode = 3; /* iterated+salted */
-    opt.s2k_digest_algo = GCRY_MD_RMD160;
-    opt.s2k_cipher_algo = GCRY_CIPHER_BLOWFISH;
+    opt.s2k_digest_algo = GCRY_MD_SHA1;
+    opt.s2k_cipher_algo = GCRY_CIPHER_CAST5;
     opt.completes_needed = 1;
     opt.marginals_needed = 3;
     opt.max_cert_depth = 5;
@@ -666,11 +673,7 @@ main( int argc, char **argv )
     opt.homedir = getenv("GNUPGHOME");
   #endif
     if( !opt.homedir || !*opt.homedir ) {
-      #ifdef HAVE_DRIVE_LETTERS
-       opt.homedir = "c:/gnupg-test";
-      #else
-       opt.homedir = "~/.gnupg-test";
-      #endif
+       opt.homedir = GNUPG_HOMEDIR;
     }
 
     /* check whether we have a config file on the commandline */
@@ -801,7 +804,7 @@ main( int argc, char **argv )
          case oArmor: opt.armor = 1; opt.no_armor=0; break;
          case oOutput: opt.outfile = pargs.r.ret_str; break;
          case oQuiet: opt.quiet = 1; break;
-         case oNoTTY: opt.quiet = 1; tty_no_terminal(1); break;
+         case oNoTTY: tty_no_terminal(1); break;
          case oDryRun: opt.dry_run = 1; break;
          case oInteractive: opt.interactive = 1; break;
          case oVerbose:
@@ -894,7 +897,6 @@ main( int argc, char **argv )
            opt.s2k_digest_algo = GCRY_MD_SHA1;
            opt.s2k_cipher_algo = GCRY_CIPHER_CAST5;
            break;
-         case oEmu3DESS2KBug:  opt.emulate_bugs |= EMUBUG_3DESS2K; break;
          case oEmuMDEncodeBug: opt.emulate_bugs |= EMUBUG_MDENCODE; break;
          case oCompressSigs: opt.compress_sigs = 1; break;
          case oRunAsShmCP:
@@ -965,6 +967,7 @@ main( int argc, char **argv )
                }
                break;
          case oAllowNonSelfsignedUID: opt.allow_non_selfsigned_uid = 1; break;
+         case oAllowFreeformUID: opt.allow_freeform_uid = 1; break;
          case oNoLiteral: opt.no_literal = 1; break;
          case oSetFilesize: opt.set_filesize = pargs.r.ret_ulong; break;
          case oHonorHttpProxy: opt.honor_http_proxy = 1; break;
@@ -973,6 +976,9 @@ main( int argc, char **argv )
          case oIgnoreTimeConflict: opt.ignore_time_conflict = 1; break;
          case oNoRandomSeedFile: use_random_seed = 0; break;
          case oNoAutoKeyRetrieve: opt.auto_key_retrieve = 0; break;
+         case oMergeOnly: opt.merge_only = 1; break;
+         case oTryAllSecrets: opt.try_all_secrets = 1; break;
+          case oTrustedKey: register_trusted_key( pargs.r.ret_str ); break;
 
          default : pargs.err = configfp? 1:2; break;
        }
@@ -1001,6 +1007,10 @@ main( int argc, char **argv )
        log_info("used in a production environment or with production keys!\n");
     }
   #endif
+
+    if( may_coredump && !opt.quiet )
+       log_info(_("WARNING: program may create a core file!\n"));
+
     if (opt.no_literal) {
        log_info(_("NOTE: %s is not for normal use!\n"), "--no-literal");
        if (opt.textmode)
@@ -1406,9 +1416,13 @@ main( int argc, char **argv )
 
 
       case aPrimegen:
-       {   int mode = argc < 2 ? 0 : atoi(*argv);
+       { 
+          #if 1
+            log_error( "command is currently not implemented\n");
+          #else
+          /* FIXME: disabled until we have an API to create primes */
+            int mode = argc < 2 ? 0 : atoi(*argv);
 
-          #if 0 /* FIXME: disabled until we have an API to create primes */
            if( mode == 1 && argc == 2 ) {
                mpi_print( stdout, generate_public_prime( atoi(argv[1]) ), 1);
            }
@@ -1435,9 +1449,9 @@ main( int argc, char **argv )
                mpi_release(g);
            }
            else
-         #endif
                wrong_args("--gen-prime mode bits [qbits] ");
            putchar('\n');
+          #endif
        }
        break;
 
index 5780825..94b83f0 100644 (file)
@@ -50,6 +50,7 @@ static struct {
     ulong secret_read;
     ulong secret_imported;
     ulong secret_dups;
+    ulong skipped_new_keys;
 } stats;
 
 
@@ -201,6 +202,9 @@ print_stats()
 {
     if( !opt.quiet ) {
        log_info(_("Total number processed: %lu\n"), stats.count );
+       if( stats.skipped_new_keys )
+           log_info(_("      skipped new keys: %lu\n"),
+                                               stats.skipped_new_keys );
        if( stats.no_user_id )
            log_info(_("          w/o user IDs: %lu\n"), stats.no_user_id );
        if( stats.imported || stats.imported_rsa ) {
@@ -413,6 +417,13 @@ import_one( const char *fname, KBNODE keyblock, int fast )
        log_error( _("key %08lX: public key not found: %s\n"),
                                (ulong)keyid[1], gpg_errstr(rc));
     }
+    else if ( rc && opt.merge_only ) {
+       if( opt.verbose )
+           log_info( _("key %08lX: new key - skipped\n"), (ulong)keyid[1] );
+       rc = 0;
+       fast = 1; /* so that we don't get into the trustdb update */
+       stats.skipped_new_keys++;
+    }
     else if( rc ) { /* insert this key */
        /* get default resource */
        if( get_keyblock_handle( NULL, 0, &kbpos ) ) {
@@ -583,7 +594,7 @@ import_secret_one( const char *fname, KBNODE keyblock )
 
     /* do we have this key already in one of our secrings ? */
     rc = seckey_available( keyid );
-    if( rc == GPGERR_NO_SECKEY ) { /* simply insert this key */
+    if( rc == GPGERR_NO_SECKEY && !opt.merge_only ) { /* simply insert this key */
        /* get default resource */
        if( get_keyblock_handle( NULL, 1, &kbpos ) ) {
            log_error("no default secret keyring\n");
index 75cb3d4..830a7db 100644 (file)
 
 #define MAX_FINGERPRINT_LEN 20
 
+#define IS_KEY_SIG(s)    ((s)->sig_class == 0x1f)
+#define IS_UID_SIG(s)    (((s)->sig_class & ~3) == 0x10)
+#define IS_SUBKEY_SIG(s) ((s)->sig_class == 0x18)
+#define IS_KEY_REV(s)    ((s)->sig_class == 0x20)
+#define IS_UID_REV(s)    ((s)->sig_class == 0x30)
+#define IS_SUBKEY_REV(s) ((s)->sig_class == 0x28)
+
+
+
 struct getkey_ctx_s;
 typedef struct getkey_ctx_s *GETKEY_CTX;
 
index daf4fb4..b7e8367 100644 (file)
@@ -592,7 +592,7 @@ keyedit_menu( const char *username, STRLIST locusr, STRLIST commands,
        { N_("sign")    , cmdSIGN      , 0,1,1, N_("sign the key") },
        { N_("s")       , cmdSIGN      , 0,1,1, NULL },
        { N_("lsign")   , cmdLSIGN     , 0,1,1, N_("sign the key locally") },
-       { N_("debug")   , cmdDEBUG     , 0,1,0, NULL },
+       { N_("debug")   , cmdDEBUG     , 0,0,0, NULL },
        { N_("adduid")  , cmdADDUID    , 1,1,0, N_("add a user ID") },
        { N_("deluid")  , cmdDELUID    , 0,1,0, N_("delete user ID") },
        { N_("addkey")  , cmdADDKEY    , 1,1,0, N_("add a secondary key") },
index 8e29090..fc3b2cf 100644 (file)
@@ -136,8 +136,8 @@ keygen_add_std_prefs( PKT_signature *sig, void *opaque )
     keygen_add_key_expire( sig, opaque );
 
     buf[0] = GCRY_CIPHER_TWOFISH;
-    buf[1] = GCRY_CIPHER_BLOWFISH;
-    buf[2] = GCRY_CIPHER_CAST5;
+    buf[1] = GCRY_CIPHER_CAST5;
+    buf[2] = GCRY_CIPHER_BLOWFISH;
     build_sig_subpkt( sig, SIGSUBPKT_PREF_SYM, buf, 3 );
 
     buf[0] = GCRY_MD_RMD160;
@@ -889,7 +889,11 @@ ask_user_id( int mode )
                aname = cpr_get("keygen.name",_("Real name: "));
                trim_spaces(aname);
                cpr_kill_prompt();
-               if( strpbrk( aname, "<([])>" ) )
+
+               if( opt.allow_freeform_uid )
+                   break;
+
+               if( strpbrk( aname, "<>" ) )
                    tty_printf(_("Invalid character in name\n"));
                else if( isdigit(*aname) )
                    tty_printf(_("Name may not start with a digit\n"));
index 14406b6..fb652e7 100644 (file)
@@ -166,11 +166,17 @@ keyid_from_sk( PKT_secret_key *sk, u32 *keyid )
     if( !keyid )
        keyid = dummy_keyid;
 
-    if( sk->version < 4 && is_RSA(sk->pubkey_algo) ) {
+    if( sk->keyid[0] || sk->keyid[1] ) {
+       keyid[0] = sk->keyid[0];
+       keyid[1] = sk->keyid[1];
+    }
+    else if( sk->version < 4 && is_RSA(sk->pubkey_algo) ) {
        if( pubkey_get_npkey(sk->pubkey_algo) )
            v3_keyid( sk->skey[0], keyid ); /* take n */
        else
            keyid[0] = keyid[1] = 0;
+       sk->keyid[0] = keyid[0];
+       sk->keyid[1] = keyid[1];
     }
     else {
        const byte *dp;
@@ -180,6 +186,8 @@ keyid_from_sk( PKT_secret_key *sk, u32 *keyid )
        keyid[0] = dp[12] << 24 | dp[13] << 16 | dp[14] << 8 | dp[15] ;
        keyid[1] = dp[16] << 24 | dp[17] << 16 | dp[18] << 8 | dp[19] ;
        gcry_md_close(md);
+       sk->keyid[0] = keyid[0];
+       sk->keyid[1] = keyid[1];
     }
 
     return keyid[1];
index 8e2436c..d199c54 100644 (file)
@@ -51,7 +51,7 @@ char *make_radix64_string( const byte *data, size_t len );
 
 /*-- misc.c --*/
 void trap_unaligned(void);
-void disable_core_dumps(void);
+int disable_core_dumps(void);
 u16 checksum_u16( unsigned n );
 u16 checksum( byte *p, unsigned n );
 u16 checksum_mpi( MPI a );
@@ -65,6 +65,7 @@ int mpi_print( FILE *fp, MPI a, int mode );
 
 int openpgp_cipher_test_algo( int algo );
 int openpgp_pk_test_algo( int algo, unsigned int usage_flags );
+int openpgp_pk_algo_usage ( int algo );
 int openpgp_md_test_algo( int algo );
 
 int pubkey_get_npkey( int algo );
index 44a6f76..a62a047 100644 (file)
@@ -68,22 +68,24 @@ trap_unaligned(void)
 #endif
 
 
-void
+
+int
 disable_core_dumps()
 {
- #ifndef HAVE_DOSISH_SYSTEM
+ #ifdef HAVE_DOSISH_SYSTEM
+    return 0;
+ #else
   #ifdef HAVE_SETRLIMIT
     struct rlimit limit;
 
     limit.rlim_cur = 0;
     limit.rlim_max = 0;
     if( !setrlimit( RLIMIT_CORE, &limit ) )
-       return;
-    if( errno != EINVAL )
+       return 0;
+    if( errno != EINVAL && errno != ENOSYS )
        log_fatal(_("can't disable core dumps: %s\n"), strerror(errno) );
   #endif
-    if( !opt.quiet )
-       log_info(_("WARNING: program may create a core file!\n"));
+    return 1;
  #endif
 }
 
@@ -318,15 +320,6 @@ print_pubkey_algo_note( int algo )
 {
     if( algo >= 100 && algo <= 110 )
        no_exp_algo();
-    else if( is_RSA( algo ) ) {
-       static int did_note = 0;
-
-       if( !did_note ) {
-           did_note = 1;
-           log_info(_("RSA keys are deprecated; please consider "
-                      "creating a new key and use this key in the future\n"));
-       }
-    }
 }
 
 void
@@ -362,7 +355,7 @@ print_digest_algo_note( int algo )
 
 /****************
  * Wrapper around the libgcrypt function with addional checks on
- * openPGP contrainst for the algo ID.
+ * openPGP contraints for the algo ID.
  */
 int
 openpgp_cipher_test_algo( int algo )
@@ -382,6 +375,40 @@ openpgp_pk_test_algo( int algo, unsigned int usage_flags )
     return gcry_pk_algo_info( algo, GCRYCTL_TEST_ALGO, NULL, &n );
 }
 
+int 
+openpgp_pk_algo_usage ( int algo )
+{
+    int usage = 0; 
+    
+    /* some are hardwired */
+    switch ( algo ) {    
+      case GCRY_PK_RSA:
+          usage = GCRY_PK_USAGE_SIGN | GCRY_PK_USAGE_ENCR;
+          break;
+      case GCRY_PK_RSA_E:
+          usage = GCRY_PK_USAGE_ENCR;
+          break;
+      case GCRY_PK_RSA_S:
+          usage = GCRY_PK_USAGE_SIGN;
+          break;
+      case GCRY_PK_ELG_E:
+          usage = GCRY_PK_USAGE_ENCR;
+          break;
+      case GCRY_PK_DSA:  
+          usage = GCRY_PK_USAGE_SIGN;
+          break;
+      case GCRY_PK_ELG:
+          usage = GCRY_PK_USAGE_SIGN | GCRY_PK_USAGE_ENCR;
+          break;
+      default:
+          usage = gcry_pk_algo_info ( algo, GCRYCTL_GET_ALGO_USAGE,
+                                      NULL, NULL);
+    }
+    return usage;
+
+}
+
+
 
 int
 openpgp_md_test_algo( int algo )
index 47dca0e..340cfd6 100644 (file)
@@ -70,6 +70,11 @@ overwrite_filep( const char *fname )
     if( access( fname, F_OK ) )
        return 1; /* does not exist */
 
+#ifndef HAVE_DOSISH_SYSTEM
+    if ( !strcmp ( fname, "/dev/null" ) )
+        return 1; /* does not do any harm */
+#endif
+
     /* fixme: add some backup stuff in case of overwrite */
     if( opt.answer_yes )
        return 1;
@@ -105,6 +110,12 @@ make_outfile_name( const char *iname )
        buf[n-4] = 0;
        return buf;
     }
+    else if( n > 5 && !CMP_FILENAME(iname+n-5,".sign") ) {
+       char *buf = gcry_xstrdup( iname );
+       buf[n-5] = 0;
+       return buf;
+    }
+
 
     log_info(_("%s: unknown suffix\n"), iname );
     return NULL;
@@ -241,6 +252,7 @@ open_sigfile( const char *iname )
     if( iname && !(*iname == '-' && !iname[1]) ) {
        len = strlen(iname);
        if( len > 4 && ( !strcmp(iname + len - 4, ".sig")
+                        || ( len > 5 && !strcmp(iname + len - 5, ".sign") )
                        || !strcmp(iname + len - 4, ".asc")) ) {
            char *buf;
            buf = gcry_xstrdup(iname);
@@ -305,10 +317,24 @@ copy_options_file( const char *destdir )
 void
 try_make_homedir( const char *fname )
 {
+    const char *defhome = GNUPG_HOMEDIR;
+
+    /* Create the directory only if the supplied directory name
+     * is the same as the default one.  This way we avoid to create
+     * arbitrary directories when a non-default homedirectory is used.
+     * To cope with HOME, we do compare only the suffix if we see that
+     * the default homedir does start with a tilde.
+     */
     if( opt.dry_run )
        return;
-    if( strlen(fname) >= 7
-       && !strcmp(fname+strlen(fname)-7, "/.gnupg" ) ) {
+
+    if ( ( *defhome == '~'
+           && ( strlen(fname) >= strlen (defhome+1)
+                && !strcmp(fname+strlen(defhome+1)-strlen(defhome+1),
+                           defhome+1 ) ))
+         || ( *defhome != '~'
+              && !compare_filenames( fname, defhome ) )
+        ) {
        if( mkdir( fname, S_IRUSR|S_IWUSR|S_IXUSR ) )
            log_fatal( _("%s: can't create directory: %s\n"),
                                        fname,  strerror(errno) );
@@ -321,3 +347,5 @@ try_make_homedir( const char *fname )
     }
 }
 
+
+
index 218e976..b7ef09f 100644 (file)
@@ -84,6 +84,7 @@ struct {
     const char *set_policy_url;
     int use_embedded_filename;
     int allow_non_selfsigned_uid;
+    int allow_freeform_uid;
     int no_literal;
     ulong set_filesize;
     int honor_http_proxy;
@@ -92,6 +93,8 @@ struct {
     int command_fd;
     int auto_key_retrieve;
     int use_agent;
+    int merge_only;
+    int try_all_secrets;
 } opt;
 
 
index f6da15e..03fa2ca 100644 (file)
@@ -128,8 +128,15 @@ typedef struct {
     byte    hdrbytes;      /* number of header bytes */
     byte    version;
     byte    pubkey_algo;    /* algorithm used for public key scheme */
-    byte    pubkey_usage;   /* for now only used to pass it to getkey() */
+    byte    pubkey_usage;   /* the actual allowed usage as set by getkey() */
+    u32     created;        /* according to the self-signature */
+    byte    req_usage;      /* hack to pass a request to getkey() */
+    byte    req_algo;       /* Ditto */
+    u32     has_expired;    /* set to the expiration date if expired */ 
+    int     is_revoked;     /* key has been revoked */
+    int     is_valid;       /* key (especially subkey) is valid */
     ulong   local_id;      /* internal use, valid if > 0 */
+    u32     main_keyid[2];  /* keyid of the primary key */
     u32     keyid[2];      /* calculated by keyid_from_pk() */
     byte    *namehash;     /* if != NULL: found by this name */
     MPI     pkey[GNUPG_MAX_NPKEY];
@@ -142,6 +149,14 @@ typedef struct {
     byte    version;
     byte    pubkey_algo;    /* algorithm used for public key scheme */
     byte    pubkey_usage;
+    u32     created;        /* according to the self-signature */
+    byte    req_usage;
+    byte    req_algo;
+    u32     has_expired;    /* set to the expiration date if expired */ 
+    int     is_revoked;     /* key has been revoked */
+    int     is_valid;       /* key (especially subkey) is valid */
+    u32     main_keyid[2];  /* keyid of the primary key */
+    u32     keyid[2];   
     byte is_primary;
     byte is_protected; /* The secret info is protected and must */
                        /* be decrypted before use, the protected */
@@ -169,6 +184,10 @@ typedef struct {
     int  len;            /* length of the name */
     char *photo;         /* if this is not NULL, the packet is a photo ID */
     int photolen;        /* and the length of the photo */
+    int help_key_usage;
+    u32 help_key_expire;
+    int is_primary;
+    u32 created;          /* according to the self-signature */
     char name[1];
 } PKT_user_id;
 
@@ -322,6 +341,8 @@ PKT_public_key *copy_public_key( PKT_public_key *d, PKT_public_key *s );
 PKT_public_key *copy_public_key_new_namehash( PKT_public_key *d,
                                              PKT_public_key *s,
                                              const byte *namehash );
+void copy_public_parts_to_secret_key( PKT_public_key *pk,
+                                      PKT_secret_key *sk );
 PKT_secret_key *copy_secret_key( PKT_secret_key *d, PKT_secret_key *s );
 PKT_signature *copy_signature( PKT_signature *d, PKT_signature *s );
 PKT_user_id *copy_user_id( PKT_user_id *d, PKT_user_id *s );
index 867f93d..3cabe77 100644 (file)
@@ -700,6 +700,17 @@ dump_sig_subpkt( int hashed, int type, int critical,
     const char *p=NULL;
     int i;
 
+    /* The CERT has warning out with explains how to use GNUPG to
+     * detect the ARRs - we print our old message here when it is a faked
+     * ARR and add an additional notice */
+    if ( type == SIGSUBPKT_ARR && !hashed ) {
+        printf("\tsubpkt %d len %u (additional recipient request)\n"
+               "WARNING: PGP versions > 5.0 and < 6.5.8 will automagically "
+               "encrypt to this key and thereby reveal the plaintext to "
+               "the owner of this ARR key. Detailed info follows:\n",
+               type, (unsigned)length );
+    }
+    
     printf("\t%s%ssubpkt %d len %u (", /*)*/
              critical ? "critical ":"",
              hashed ? "hashed ":"", type, (unsigned)length );
@@ -737,9 +748,6 @@ dump_sig_subpkt( int hashed, int type, int critical,
            printf("key expires after %s",
                                    strtimevalue( buffer_to_u32(buffer) ) );
        break;
-      case SIGSUBPKT_ARR:
-       p = "additional recipient request";
-       break;
       case SIGSUBPKT_PREF_SYM:
        fputs("pref-sym-algos:", stdout );
        for( i=0; i < length; i++ )
@@ -809,8 +817,10 @@ dump_sig_subpkt( int hashed, int type, int critical,
        print_string( stdout, buffer, length, ')' );
        break;
       case SIGSUBPKT_KEY_FLAGS:
-       p = "key flags";
-       break;
+        fputs ( "key flags:", stdout );
+        for( i=0; i < length; i++ )
+            printf(" %02X", buffer[i] );
+        break;
       case SIGSUBPKT_SIGNERS_UID:
        p = "signer's user ID";
        break;
@@ -821,6 +831,16 @@ dump_sig_subpkt( int hashed, int type, int critical,
            p = ")";
        }
        break;
+      case SIGSUBPKT_ARR:
+        fputs("Big Brother's key (ignored): ", stdout );
+       if( length < 22 )
+           p = "[too short]";
+       else {
+           printf("c=%02x a=%d f=", buffer[0], buffer[1] );
+           for( i=2; i < length; i++ )
+               printf("%02X", buffer[i] );
+       }
+        break;
       case SIGSUBPKT_PRIV_ADD_SIG:
        p = "signs additional user ID";
        break;
@@ -846,6 +866,8 @@ parse_one_sig_subpkt( const byte *buffer, size_t n, int type )
        if( n < 4 )
            break;
        return 0;
+      case SIGSUBPKT_KEY_FLAGS:
+          return 0;  
       case SIGSUBPKT_EXPORTABLE:
        if( !n )
            break;
@@ -867,6 +889,10 @@ parse_one_sig_subpkt( const byte *buffer, size_t n, int type )
       case SIGSUBPKT_PREF_COMPR:
       case SIGSUBPKT_POLICY:
        return 0;
+      case SIGSUBPKT_PRIMARY_UID:
+          if ( n != 1 )
+              break;
+          return 0;   
       case SIGSUBPKT_PRIV_ADD_SIG:
        /* because we use private data, we check the GNUPG marker */
        if( n < 24 )
@@ -897,6 +923,7 @@ can_handle_critical( const byte *buffer, size_t n, int type )
       case SIGSUBPKT_PREF_SYM:
       case SIGSUBPKT_PREF_HASH:
       case SIGSUBPKT_PREF_COMPR:
+      case SIGSUBPKT_KEY_FLAGS:
        return 1;
 
       case SIGSUBPKT_POLICY: /* Is it enough to show the policy? */
@@ -1288,7 +1315,8 @@ parse_key( IOBUF inp, int pkttype, unsigned long pktlen,
        sk->version = version;
        sk->is_primary = pkttype == PKT_SECRET_KEY;
        sk->pubkey_algo = algorithm;
-       sk->pubkey_usage = 0; /* not yet used */
+       sk->req_usage = 0; 
+        sk->pubkey_usage = 0; /* will be set by getkey functions */
     }
     else {
        PKT_public_key *pk = pkt->pkt.public_key;
@@ -1298,7 +1326,9 @@ parse_key( IOBUF inp, int pkttype, unsigned long pktlen,
        pk->hdrbytes    = hdrlen;
        pk->version     = version;
        pk->pubkey_algo = algorithm;
-       pk->pubkey_usage = 0; /* not yet used */
+        pk->req_usage = 0;
+       pk->pubkey_usage = 0; /* will be set bey getkey functions */
+        pk->is_revoked = 0;
        pk->keyid[0] = 0;
        pk->keyid[1] = 0;
     }
index 97ed3d1..6b06df7 100644 (file)
@@ -640,7 +640,6 @@ hash_passphrase( DEK *dek, char *pw, STRING2KEY *s2k, int create )
            else {
                gcry_md_write( md, s2k->salt, 8 );
                count -= 8;
-               assert( count >= 0 );
                gcry_md_write( md, pw, count );
            }
        }
index 8e61ffd..d827ce6 100644 (file)
@@ -814,13 +814,12 @@ build_pk_list( STRLIST remusr, PK_LIST *ret_pk_list, unsigned use )
            any_recipients = 1;
        else if( (use & GCRY_PK_USAGE_ENCR) && !opt.no_encrypt_to ) {
            pk = gcry_xcalloc( 1, sizeof *pk );
-           pk->pubkey_usage = use;
+           pk->req_usage = use;
            if( (rc = get_pubkey_byname( NULL, pk, rov->d, NULL )) ) {
                free_public_key( pk ); pk = NULL;
                log_error(_("%s: skipped: %s\n"), rov->d, gpg_errstr(rc) );
            }
            else if( !(rc=openpgp_pk_test_algo(pk->pubkey_algo, use )) ) {
-
                /* Skip the actual key if the key is already present
                 * in the list */
                if (key_present_in_pk_list(pk_list, pk) == 0) {
@@ -871,7 +870,7 @@ build_pk_list( STRLIST remusr, PK_LIST *ret_pk_list, unsigned use )
            if( pk )
                free_public_key( pk );
            pk = gcry_xcalloc( 1, sizeof *pk );
-           pk->pubkey_usage = use;
+           pk->req_usage = use;
            rc = get_pubkey_byname( NULL, pk, answer, NULL );
            if( rc )
                tty_printf(_("No such user ID.\n"));
@@ -937,7 +936,7 @@ build_pk_list( STRLIST remusr, PK_LIST *ret_pk_list, unsigned use )
     }
     else if( !any_recipients && (def_rec = default_recipient()) ) {
        pk = gcry_xcalloc( 1, sizeof *pk );
-       pk->pubkey_usage = use;
+       pk->req_usage = use;
        rc = get_pubkey_byname( NULL, pk, def_rec, NULL );
        if( rc )
            log_error(_("unknown default recipient `%s'\n"), def_rec );
@@ -962,7 +961,7 @@ build_pk_list( STRLIST remusr, PK_LIST *ret_pk_list, unsigned use )
                continue; /* encrypt-to keys are already handled */
 
            pk = gcry_xcalloc( 1, sizeof *pk );
-           pk->pubkey_usage = use;
+           pk->req_usage = use;
            if( (rc = get_pubkey_byname( NULL, pk, remusr->d, NULL )) ) {
                free_public_key( pk ); pk = NULL;
                log_error(_("%s: skipped: %s\n"), remusr->d, gpg_errstr(rc) );
@@ -1033,8 +1032,6 @@ static int
 algo_available( int preftype, int algo )
 {
     if( preftype == PREFTYPE_SYM ) {
-       if( algo == GCRY_CIPHER_TWOFISH )
-           return 0;  /* we don't want to generate Twofish messages for now*/
        return algo && !openpgp_cipher_test_algo( algo );
     }
     else if( preftype == PREFTYPE_HASH ) {
index e6cbec4..646aca0 100644 (file)
@@ -106,14 +106,11 @@ get_session_key( PKT_pubkey_enc *k, DEK *dek )
     PKT_secret_key *sk = NULL;
     int rc;
 
-    if( is_RSA(k->pubkey_algo) ) /* warn about that */
-       write_status(STATUS_RSA_OR_IDEA);
-
     rc = openpgp_pk_test_algo( k->pubkey_algo, 0 );
     if( rc )
        goto leave;
 
-    if( k->keyid[0] || k->keyid[1] ) {
+    if( (k->keyid[0] || k->keyid[1]) && !opt.try_all_secrets ) {
        sk = gcry_xcalloc( 1, sizeof *sk );
        sk->pubkey_algo = k->pubkey_algo; /* we want a pubkey with this algo*/
        if( !(rc = get_seckey( sk, k->keyid )) )
index 3a29654..311cf41 100644 (file)
@@ -1114,7 +1114,13 @@ cmp_seckey( PKT_secret_key *req_sk, PKT_secret_key *sk )
 
     n = pubkey_get_nskey( req_sk->pubkey_algo );
     for(i=0; i < n; i++ ) {
-       if( mpi_cmp( req_sk->skey[i], sk->skey[i] ) )
+        /* Note: because v4 protected keys have nothing in the
+         * mpis except for the first one, we skip all NULL MPIs.
+         * This might not be always correct in cases where the both
+         * keys do not match in their secret parts but we can ignore that
+         * because the need for this function is quite ugly. */
+       if( req_sk->skey[1] && sk->skey[i]
+             && mpi_cmp( req_sk->skey[i], sk->skey[i] ) )
            return -1;
     }
     return 0;
index 342dde0..0be514e 100644 (file)
@@ -100,10 +100,8 @@ do_check( PKT_secret_key *sk )
        keyid_from_sk( sk, keyid );
        keyid[2] = keyid[3] = 0;
        if( !sk->is_primary ) {
-           PKT_secret_key *sk2 = gcry_xcalloc( 1, sizeof *sk2 );
-           if( !get_primary_seckey( sk2, keyid ) )
-               keyid_from_sk( sk2, keyid+2 );
-           free_secret_key( sk2 );
+            keyid[2] = sk->main_keyid[0];
+            keyid[3] = sk->main_keyid[1];
        }
        dek = passphrase_to_dek( keyid, sk->pubkey_algo, sk->protect.algo,
                                 &sk->protect.s2k, 0 );
@@ -128,11 +126,14 @@ do_check( PKT_secret_key *sk )
            size_t ndata;
            unsigned int ndatabits;
            byte *p, *data;
+            u16 csumc = 0;
 
            i = pubkey_get_npkey(sk->pubkey_algo);
            assert( gcry_mpi_get_flag( sk->skey[i], GCRYMPI_FLAG_OPAQUE ) );
            p = gcry_mpi_get_opaque( sk->skey[i], &ndatabits );
            ndata = (ndatabits+7)/8;
+            if ( ndata > 1 )
+                csumc = p[ndata-2] << 8 | p[ndata-1];
            data = gcry_xmalloc_secure( ndata );
            gcry_cipher_decrypt( cipher_hd, data, ndata, p, ndata );
            mpi_release( sk->skey[i] ); sk->skey[i] = NULL ;
@@ -145,6 +146,10 @@ do_check( PKT_secret_key *sk )
            else {
                csum = checksum( data, ndata-2);
                sk->csum = data[ndata-2] << 8 | data[ndata-1];
+                if ( sk->csum != csum ) {
+                    /* This is a PGP 7.0.0 workaround */
+                    sk->csum = csumc; /* take the encrypted one */
+                }
            }
            /* must check it here otherwise the mpi_read_xx would fail
             * because the length may have an arbitrary value */
@@ -321,8 +326,6 @@ protect_secret_key( PKT_secret_key *sk, DEK *dek )
 
            #warning FIXME: replace set/get buffer
            if( sk->version >= 4 ) {
-               /* FIXME: There is a bug in this function for all algorithms
-                * where the secret MPIs are more than 1 */
                byte *bufarr[GNUPG_MAX_NSKEY];
                unsigned narr[GNUPG_MAX_NSKEY];
                unsigned nbits[GNUPG_MAX_NSKEY];
index 85c8bfb..a3946a1 100644 (file)
@@ -134,9 +134,6 @@ do_signature_check( PKT_signature *sig, GCRY_MD_HD digest,
     PKT_public_key *pk = gcry_xcalloc( 1, sizeof *pk );
     int rc=0;
 
-    if( is_RSA(sig->pubkey_algo) )
-       write_status(STATUS_RSA_OR_IDEA);
-
     *r_expiredate = 0;
     if( get_pubkey( pk, sig->keyid ) )
        rc = GPGERR_NO_PUBKEY;
@@ -451,10 +448,18 @@ check_key_signature2( KBNODE root, KBNODE node, int *is_selfsig,
     sig = node->pkt->pkt.signature;
     algo = sig->digest_algo;
 
-  #if 0 /* I am not sure whether this is a good thing to do */
-    if( sig->flags.checked )
+  #if 0
+    if( sig->flags.checked ) {
        log_debug("check_key_signature: already checked: %s\n",
                      sig->flags.valid? "good":"bad" );
+        if ( sig->flags.valid )
+            return 0; /* shortcut already checked signatures */
+        /* FIXME: We should also do this with bad signatures but here we
+         * have to distinguish between several reasons; e.g. for a missing
+         * public key. the key may now be available.
+         * For now we simply don't shortcut bad signatures
+         */
+    }
   #endif
 
     if( (rc=openpgp_md_test_algo(algo)) )
index d52010a..b53444b 100644 (file)
@@ -485,6 +485,10 @@ sign_file( STRLIST filenames, int detached, STRLIST locusr,
        if( fname ) {
            if( !(filesize = iobuf_get_filelength(inp)) )
                log_info(_("WARNING: `%s' is an empty file\n"), fname );
+            /* we can't yet encode the length of very large files,
+             * so we switch to partial length encoding in this case */
+            if ( filesize >= IOBUF_FILELENGTH_LIMIT )
+                filesize = 0;
 
            /* because the text_filter modifies the length of the
             * data, it is not possible to know the used length
index 8fcb22a..5c6d6fb 100644 (file)
@@ -59,7 +59,7 @@ build_sk_list( STRLIST locusr, SK_LIST *ret_sk_list, int unlock,
        PKT_secret_key *sk;
 
        sk = gcry_xcalloc( 1, sizeof *sk );
-       sk->pubkey_usage = use;
+       sk->req_usage = use;
        if( (rc = get_seckey_byname( sk, NULL, unlock )) ) {
            free_secret_key( sk ); sk = NULL;
            log_error("no default secret key: %s\n", gpg_errstr(rc) );
@@ -90,7 +90,7 @@ build_sk_list( STRLIST locusr, SK_LIST *ret_sk_list, int unlock,
            PKT_secret_key *sk;
 
            sk = gcry_xcalloc( 1, sizeof *sk );
-           sk->pubkey_usage = use;
+           sk->req_usage = use;
            if( (rc = get_seckey_byname( sk, locusr->d, unlock )) ) {
                free_secret_key( sk ); sk = NULL;
                log_error(_("skipped `%s': %s\n"), locusr->d, gpg_errstr(rc) );
index f75ccc5..f3fcd46 100644 (file)
@@ -109,6 +109,7 @@ static TN used_tns;
 static int alloced_tns;
 static int max_alloced_tns;
 
+static struct keyid_list *trusted_key_list;
 
 static LOCAL_ID_TABLE new_lid_table(void);
 static int ins_lid_table_item( LOCAL_ID_TABLE tbl, ulong lid, unsigned flag );
@@ -463,6 +464,64 @@ lid_from_keyid_no_sdir( u32 *keyid )
  ************* Initialization  ****************
  ***********************************************/
 
+void
+register_trusted_key( const char *string )
+{
+    u32 keyid[2];
+    struct keyid_list *r;
+
+    if( classify_user_id( string, keyid, NULL, NULL, NULL ) != 11 ) {
+        log_error(_("'%s' is not a valid long keyID\n"), string );
+        return;
+    }
+
+    for( r = trusted_key_list; r; r = r->next )
+        if( r->keyid[0] == keyid[0] && r->keyid[1] == keyid[1] )
+            return;
+    r = gcry_xmalloc( sizeof *r );
+    r->keyid[0] = keyid[0];
+    r->keyid[1] = keyid[1];
+    r->next = trusted_key_list;
+    trusted_key_list = r;
+}
+
+
+
+static void
+add_ultimate_key( PKT_public_key *pk, u32 *keyid )
+{
+    int rc;
+
+    /* first make sure that the pubkey is in the trustdb */
+    rc = query_trust_record( pk );
+    if( rc == -1 && opt.dry_run )
+       return;
+    if( rc == -1 ) { /* put it into the trustdb */
+        rc = insert_trust_record_by_pk( pk );
+        if( rc ) {
+            log_error(_("key %08lX: can't put it into the trustdb\n"),
+                      (ulong)keyid[1] );
+            return;
+        }
+    }
+    else if( rc ) {
+        log_error(_("key %08lX: query record failed\n"), (ulong)keyid[1] );
+        return;
+    }
+
+    if( DBG_TRUST )
+        log_debug("key %08lX.%lu: stored into ultikey_table\n",
+                  (ulong)keyid[1], pk->local_id );
+
+    if( ins_lid_table_item( ultikey_table, pk->local_id, 0 ) )
+        log_error(_("key %08lX: already in trusted key table\n"),
+                  (ulong)keyid[1]);
+    else if( opt.verbose > 1 )
+        log_info(_("key %08lX: accepted as trusted key.\n"),
+                 (ulong)keyid[1]);
+
+}
+
 /****************
  * Verify that all our public keys are in the trustdb.
  */
@@ -474,7 +533,27 @@ verify_own_keys(void)
     PKT_secret_key *sk = gcry_xcalloc( 1, sizeof *sk );
     PKT_public_key *pk = gcry_xcalloc( 1, sizeof *pk );
     u32 keyid[2];
-
+    struct keyid_list *kl;
+
+
+    /* put the trusted keys into the ultikey table */
+    for( kl = trusted_key_list; kl; kl = kl->next ) {
+        keyid[0] = kl->keyid[0];
+        keyid[1] = kl->keyid[1];
+        /* get the public key */
+        memset( pk, 0, sizeof *pk );
+        rc = get_pubkey( pk, keyid );
+        if( rc ) {
+            log_info(_("key %08lX: no public key for trusted key - skipped\n"),
+                                                            (ulong)keyid[1] );
+        }
+        else {
+            add_ultimate_key( pk, keyid );
+            release_public_key_parts( pk );
+        }
+    }
+
+    /* And now add all secret keys to the ultikey table */
     while( !(rc=enum_secret_keys( &enum_context, sk, 0 ) ) ) {
        int have_pk = 0;
 
@@ -487,6 +566,10 @@ verify_own_keys(void)
            log_info(_("NOTE: secret key %08lX is NOT protected.\n"),
                                                            (ulong)keyid[1] );
 
+        for( kl = trusted_key_list; kl; kl = kl->next ) {
+            if( kl->keyid[0] == keyid[0] && kl->keyid[1] == keyid[1] )
+                goto skip; /* already in trusted key table */
+        }
 
        /* see whether we can access the public key of this secret key */
        memset( pk, 0, sizeof *pk );
@@ -504,33 +587,8 @@ verify_own_keys(void)
            goto skip;
        }
 
-       /* make sure that the pubkey is in the trustdb */
-       rc = query_trust_record( pk );
-       if( rc == -1 && opt.dry_run )
-           goto skip;
-       if( rc == -1 ) { /* put it into the trustdb */
-           rc = insert_trust_record_by_pk( pk );
-           if( rc ) {
-               log_error(_("key %08lX: can't put it into the trustdb\n"),
-                                                           (ulong)keyid[1] );
-               goto skip;
-           }
-       }
-       else if( rc ) {
-           log_error(_("key %08lX: query record failed\n"), (ulong)keyid[1] );
-           goto skip;
+       add_ultimate_key( pk, keyid );
 
-       }
-
-       if( DBG_TRUST )
-           log_debug("key %08lX.%lu: stored into ultikey_table\n",
-                                   (ulong)keyid[1], pk->local_id );
-       if( ins_lid_table_item( ultikey_table, pk->local_id, 0 ) )
-           log_error(_("key %08lX: already in trusted key table\n"),
-                                                       (ulong)keyid[1]);
-       else if( opt.verbose > 1 )
-           log_info(_("key %08lX: accepted as trusted key.\n"),
-                                                       (ulong)keyid[1]);
       skip:
        release_secret_key_parts( sk );
        if( have_pk )
@@ -541,6 +599,15 @@ verify_own_keys(void)
     else
        rc = 0;
 
+    /* release the trusted keyid table */
+    {   struct keyid_list *kl2;
+        for( kl = trusted_key_list; kl; kl = kl2 ) {
+            kl2 = kl->next;
+            gcry_free( kl );
+        }
+        trusted_key_list = NULL;
+    }
+
     enum_secret_keys( &enum_context, NULL, 0 ); /* free context */
     free_secret_key( sk );
     free_public_key( pk );
@@ -548,6 +615,8 @@ verify_own_keys(void)
 }
 
 
+
+
 /****************
  * Perform some checks over the trustdb
  *  level 0: only open the db
index 7a7d825..2f35f9a 100644 (file)
@@ -116,6 +116,7 @@ size_t iobuf_temp_to_buffer( IOBUF a, byte *buffer, size_t buflen );
 void iobuf_unget_and_close_temp( IOBUF a, IOBUF temp );
 
 u32 iobuf_get_filelength( IOBUF a );
+#define IOBUF_FILELENGTH_LIMIT 0xffffffff
 const char *iobuf_get_real_fname( IOBUF a );
 const char *iobuf_get_fname( IOBUF a );
 
index 79bba89..136caf5 100644 (file)
@@ -1,3 +1,8 @@
+Mon Sep 18 16:35:45 CEST 2000  Werner Koch  <wk@openit.de>
+
+       * ring-a-party: substr starts at offset 1 not 0.  Many thanks to Mike
+        for finding this bug. Flush the last key.
+
 Mon Jul 17 16:35:47 CEST 2000  Werner Koch  <wk@>
 
   * mail-signed-keys: New.
index 561b513..7cf05d7 100755 (executable)
@@ -31,6 +31,9 @@ BEGIN { FS=":"
        page = 0;
        now = strftime("%b %d %H:%M %Y");
       }
+END { 
+    if (any) myflush(); 
+}
 $1 == "pub" {
              if( any ) myflush();
              uidcount = 0;
@@ -84,7 +87,7 @@ function printfpr16( s )
     printf "f16    Fingerprint16 =";
     for(i=0; i < 16; i++ ) {
        if( i == 8 ) printf " ";
-       printf " %s", substr( s, i*2, 2 );
+       printf " %s", substr( s, i*2+1, 2 );
     }
     printf "\n"
 }
@@ -94,10 +97,13 @@ function printfpr20( s )
     printf "f20    Fingerprint20 =";
     for(i=0; i < 10; i++ ) {
        if( i == 5 ) printf " ";
-       printf " %s", substr( s, i*4, 4 );
+       printf " %s", substr( s, i*4+1, 4 );
     }
     printf "\n"
 }
 
 ' | tee a.pub | gpg --print-mds
 
+
+
+
index 956c208..20e9bda 100644 (file)
@@ -1,3 +1,15 @@
+Mon Sep 18 16:35:45 CEST 2000  Werner Koch  <wk@openit.de>
+
+        * strgutil.c (utf8_to_native): Fixed null ptr problem.  By
+        Giampaolo Tomassoni.
+
+        * iobuf.c: Use fopen64 insead of fopen when available.
+        (iobuf_get_filelength): Use fstat64 when available but return
+        2^32-1 if the file is larger than this value.
+
+        * miscutil.c (answer_is_yes_no_quit): Swapped order of yes/no test
+        so that no is returned for an empty input. By David Champion.
+
 Fri Aug 18 14:27:14 CEST 2000  Werner Koch  <wk@openit.de>
 
         * logger.c (log_set_file): Allow to set the file by name.
index f7035ae..5f70694 100644 (file)
 #include "util.h"
 #include "iobuf.h"
 
+
+#if defined (HAVE_FOPEN64) && defined (HAVE_FSTAT64)
+  #define fopen(a,b)  fopen64 ((a),(b))
+  #define fstat(a,b)  fstat64 ((a),(b))
+#endif
+
+
+
 typedef struct {
     FILE *fp;     /* open file handle */
     int  print_only_name; /* flags indicating that fname is not a real file*/
@@ -1312,25 +1320,40 @@ iobuf_set_limit( IOBUF a, unsigned long nlimit )
 u32
 iobuf_get_filelength( IOBUF a )
 {
+#if defined (HAVE_FOPEN64) && defined (HAVE_FSTAT64)
+    struct stat64 st;
+#else
     struct stat st;
+#endif
 
     if( a->directfp )  {
        FILE *fp = a->directfp;
 
-       if( !fstat(fileno(fp), &st) )
-           return st.st_size;
+       if( !fstat(fileno(fp), &st) ) {
+          #if defined (HAVE_FOPEN64) && defined (HAVE_FSTAT64)
+            if( st.st_size >= IOBUF_FILELENGTH_LIMIT )
+                return IOBUF_FILELENGTH_LIMIT;
+          #endif
+           return (u32)st.st_size;
+        }
        log_error("fstat() failed: %s\n", strerror(errno) );
        return 0;
     }
 
+
     /* Hmmm: file_filter may have already been removed */
     for( ; a; a = a->chain )
        if( !a->chain && a->filter == file_filter ) {
            file_filter_ctx_t *b = a->filter_ov;
            FILE *fp = b->fp;
 
-           if( !fstat(fileno(fp), &st) )
+           if( !fstat(fileno(fp), &st) ) {
+              #if defined (HAVE_FOPEN64) && defined (HAVE_FSTAT64)
+                if( st.st_size >= IOBUF_FILELENGTH_LIMIT )
+                    return IOBUF_FILELENGTH_LIMIT;
+              #endif
                return st.st_size;
+            }
            log_error("fstat() failed: %s\n", strerror(errno) );
            break;
        }
index c1b8fa0..9b4a837 100644 (file)
@@ -311,16 +311,16 @@ answer_is_yes_no_quit( const char *s )
     char *short_no = _("nN");
     char *short_quit = _("qQ");
 
-    if( !stricmp(s, long_yes ) )
-       return 1;
     if( !stricmp(s, long_no ) )
        return 0;
+    if( !stricmp(s, long_yes ) )
+       return 1;
     if( !stricmp(s, long_quit ) )
        return -1;
-    if( strchr( short_yes, *s ) && !s[1] )
-       return 1;
     if( strchr( short_no, *s ) && !s[1] )
        return 0;
+    if( strchr( short_yes, *s ) && !s[1] )
+       return 1;
     if( strchr( short_quit, *s ) && !s[1] )
        return -1;
     if( !stricmp(s, "yes" ) )
index a8abf7b..89722f8 100644 (file)
@@ -389,7 +389,8 @@ utf8_to_native( const char *string, size_t length )
                          case   0 : n++; if( p ) *p++ = '0'; break;
                          default: n += 3;
                                   sprintf( p, "x%02x", *s );
-                                  p += 3;
+                                   if ( p )
+                                       p += 3;
                                   break;
                        }
                    }
@@ -496,3 +497,7 @@ utf8_to_native( const char *string, size_t length )
 }
 
 
+
+
+
+