partial DSA support
authorWerner Koch <wk@gnupg.org>
Mon, 9 Mar 1998 21:44:06 +0000 (21:44 +0000)
committerWerner Koch <wk@gnupg.org>
Mon, 9 Mar 1998 21:44:06 +0000 (21:44 +0000)
62 files changed:
ChangeLog
NEWS
README
THANKS
TODO
VERSION
cipher/ChangeLog
cipher/Makefile.am
cipher/Makefile.in
cipher/blowfish.c
cipher/dsa.c
cipher/dsa.h
cipher/md.c
cipher/misc.c
cipher/random.c
cipher/random.h [new file with mode: 0644]
cipher/rmd.h
cipher/rmd160.c
config.h.in
configure.in
doc/gpg.1pod
g10/ChangeLog
g10/Makefile.am
g10/Makefile.in
g10/armor.c
g10/build-packet.c
g10/compress.c
g10/decrypt.c [new file with mode: 0644]
g10/dsa.c [new file with mode: 0644]
g10/elg.c
g10/free-packet.c
g10/g10.c
g10/getkey.c
g10/import.c
g10/kbnode.c
g10/keyid.c
g10/keylist.c
g10/main.h
g10/mainproc.c
g10/openfile.c
g10/options.h
g10/packet.h
g10/parse-packet.c
g10/plaintext.c
g10/ringedit.c
g10/rsa.c
g10/seckey-cert.c
g10/sig-check.c
g10/sign.c
g10/status.c
g10/status.h
g10/trustdb.c
g10/verify.c [new file with mode: 0644]
include/ChangeLog
include/cipher.h
include/errors.h
include/util.h
util/ChangeLog
util/errors.c
util/fileutil.c
util/iobuf.c
util/miscutil.c

index e9b12dd..2bd404e 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,7 @@
+Wed Mar  4 10:32:40 1998  Werner Koch  (wk@isil.d.shuttle.de)
+
+       * configure.in (getrusage,gettimeofday): New tests.
+
 Fri Feb 27 13:14:17 1998  Werner Koch  (wk@isil.d.shuttle.de)
 
        * configure.in (--disable-m-guard): New.
diff --git a/NEWS b/NEWS
index 4ad308d..609c163 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,17 @@
+Noteworthy changes in version 0.2.12
+------------------------------------
+
+    * --delete-key checks that there is no secret key. The new
+      option --delete-secret-key maybe used to delete a secret key.
+
+    * "-kv" now works as expected. Options "--list-{keys,sigs]"
+      and "--check-sigs" are now working.
+
+    * New options "--verify" and "--decrypt" to better support integration
+      into MUAs (partly done for Mutt).
+
+    * New option "--with-colons" to make parsing of key lists easier.
+
 Noteworthy changes in version 0.2.11
 ------------------------------------
 
diff --git a/README b/README
index 5815fc1..664c8a3 100644 (file)
--- a/README
+++ b/README
@@ -3,8 +3,6 @@
                 -------------------------------
 
     THIS IS ALPHA SOFTWARE, EXPECT BUGS AND UNIMPLEMENTED STUFF.
-    IT MAY HAPPEN THAT SOME DATA FORMATS OR PROGRAMM OPTIONS
-    CHANGE WITH THE NEXT VERSION.
 
     On a Linux box (version 2.x.x, alpha or x86 CPU) it should
     work reliable. You may create your key on such a machine and
     8) Continue with step 4 if we did not find a prime in step 7.
     9) Find a generator for that prime.
 
-    You should make a revocation certificate in cases someone gets
+    You should make a revocation certificate in case someone gets
     knowledge of your secret key or you forgot your passphrase:
 
        gpg --gen-revoke your_user_id
        "234567C4"
        "0F34E556E"
        "01347A56A"
+       "0xAB123456
 
     * By a complete keyid:
 
        "234AABBCC34567C4"
        "0F323456784E56EAB"
        "01AB3FED1347A5612"
+       "0x234AABBCC34567C4"
 
     * By a fingerprint (not yet implemented):
 
     you are asked for the passphrase, so that GNUPG is able to look at the
     inner structure of a encrypted packet.
 
-       gpgm --quick-random
-
-    Do not use the stroing random generator but a faster one.  This can be
-    used to generate keys for tests; those are marked as insecure.
-
        gpgm --list-trustdb
 
     List the contents of the trustdb in a human readable format
diff --git a/THANKS b/THANKS
index eb5a62c..4d04365 100644 (file)
--- a/THANKS
+++ b/THANKS
@@ -1,4 +1,4 @@
-G10 has originally been written by Werner Koch.  Other people contributed
+GNUPG has originally been written by Werner Koch.  Other people contributed
 by reporting problems, suggesting various improvements or submitting actual
 code.  Here is a list of these people. Help me keeping it complete and
 exempt of errors.
diff --git a/TODO b/TODO
index 6edd5d5..e8fabe5 100644 (file)
--- a/TODO
+++ b/TODO
@@ -13,9 +13,7 @@
     * complete cipher/cast.c
     * complete cipher/dsa.c
 
-    * add g10 stuff to Mutt's pgpinvoke.c
-
-    * Burn the buffers used by fopen().
+    * Burn the buffers used by fopen(), or use read(2).
 
     * bug: g10/trustdb.c#build_sigrecs called to often by do_list_path
       and remove the bad kludge. Maybe we should put all sigs into the trustdb
       them to your key and because the user id which is signed by others has
       also be signed by you, all user-ids are bound together.
 
+    * add an option to re-create a public key from a secret key
+
+    * should we have a simple menu for all the key management options?
+
+    * cleanup mainproc.c, much stuff is duplicated.
+
+    * remove key management stuff from sign.c.
 
diff --git a/VERSION b/VERSION
index d3b5ba4..c7ea8e0 100644 (file)
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-0.2.11
+0.2.12a
index 152d234..0a316d1 100644 (file)
@@ -1,3 +1,18 @@
+Mon Mar  9 12:59:08 1998  Werner Koch  (wk@isil.d.shuttle.de)
+
+       * dsa.c, dsa.h: Removed some unused code.
+
+Wed Mar  4 10:39:22 1998  Werner Koch  (wk@isil.d.shuttle.de)
+
+       * md.c (md_open): Add call to fast_random_poll.
+       blowfish.c (blowfish_setkey): Ditto.
+
+Tue Mar  3 13:32:54 1998  Werner Koch  (wk@isil.d.shuttle.de)
+
+       * rmd160.c (rmd160_mixblock): New.
+       * random.c: Restructured to start with a new RNG implementation.
+       * random.h: New.
+
 Mon Mar  2 19:21:46 1998  Werner Koch  (wk@isil.d.shuttle.de)
 
        * gost.c, gost.h: Removed because they did only conatin trash.
index 48478a2..c0b3c8a 100644 (file)
@@ -13,6 +13,7 @@ libcipher_a_SOURCES = blowfish.c     \
                 md5.c          \
                 md5.h          \
                 primegen.c     \
+                random.h       \
                 random.c       \
                 rmd.h          \
                 rmd160.c       \
index 958b7d1..579d4a3 100644 (file)
@@ -104,6 +104,7 @@ libcipher_a_SOURCES = blowfish.c     \
                 md5.c          \
                 md5.h          \
                 primegen.c     \
+                random.h       \
                 random.c       \
                 rmd.h          \
                 rmd160.c       \
index c0979b8..55b9902 100644 (file)
@@ -37,6 +37,7 @@
 #include "util.h"
 #include "types.h"
 #include "blowfish.h"
+#include "random.h"
 
 /* precomputed S boxes */
 static const u32 ks0[256] = {
@@ -421,6 +422,8 @@ blowfish_setkey( BLOWFISH_context *c, byte *key, unsigned keylen )
        selftest();
     }
 
+    fast_random_poll();
+
     for(i=0; i < BLOWFISH_ROUNDS+2; i++ )
        c->p[i] = ps[i];
     for(i=0; i < 256; i++ ) {
index 07f9e70..8024ac0 100644 (file)
@@ -32,6 +32,7 @@ void
 dsa_free_public_key( DSA_public_key *pk )
 {
     mpi_free( pk->p ); pk->p = NULL;
+    mpi_free( pk->q ); pk->q = NULL;
     mpi_free( pk->g ); pk->g = NULL;
     mpi_free( pk->y ); pk->y = NULL;
 }
@@ -40,121 +41,13 @@ void
 dsa_free_secret_key( DSA_secret_key *sk )
 {
     mpi_free( sk->p ); sk->p = NULL;
+    mpi_free( sk->q ); sk->q = NULL;
     mpi_free( sk->g ); sk->g = NULL;
     mpi_free( sk->y ); sk->y = NULL;
     mpi_free( sk->x ); sk->x = NULL;
 }
 
 
-static void
-test_keys( DSA_public_key *pk, DSA_secret_key *sk, unsigned nbits )
-{
-    MPI test = mpi_alloc( nbits / BITS_PER_MPI_LIMB );
-    MPI out1_a = mpi_alloc( nbits / BITS_PER_MPI_LIMB );
-    MPI out1_b = mpi_alloc( nbits / BITS_PER_MPI_LIMB );
-    MPI out2 = mpi_alloc( nbits / BITS_PER_MPI_LIMB );
-
-    mpi_set_bytes( test, nbits, get_random_byte, 0 );
-
-    dsa_sign( out1_a, out1_b, test, sk );
-    if( !dsa_verify( out1_a, out1_b, test, pk ) )
-       log_fatal("DSA operation: sign, verify failed\n");
-
-    mpi_free( test );
-    mpi_free( out1_a );
-    mpi_free( out1_b );
-    mpi_free( out2 );
-}
-
-
-/****************
- * generate a random secret exponent k from prime p, so
- * that k is relatively prime to p-1
- */
-static MPI
-gen_k( MPI p )
-{
-    MPI k = mpi_alloc_secure( mpi_get_nlimbs(p) );
-    MPI temp = mpi_alloc( mpi_get_nlimbs(p) );
-    MPI p_1 = mpi_copy(p);
-    unsigned nbits = mpi_get_nbits(p);
-
-    if( DBG_CIPHER )
-       log_debug("choosing a random k ");
-    mpi_sub_ui( p_1, p, 1);
-    for(;;) {
-       if( DBG_CIPHER )
-           fputc('.', stderr);
-       mpi_set_bytes( k, nbits, get_random_byte, 1 );
-       mpi_set_highbit( k, nbits-1 ); /* make sure it's high (really needed?) */
-       if( mpi_cmp( k, p_1 ) >= 0 )
-           continue; /* is not smaller than (p-1) */
-       if( mpi_gcd( temp, k, p_1 ) )
-           break;  /* okay, k is relatively prime to (p-1) */
-    }
-    if( DBG_CIPHER )
-       fputc('\n', stderr);
-    mpi_free(p_1);
-    mpi_free(temp);
-
-    return k;
-}
-
-/****************
- * Generate a key pair with a key of size NBITS
- * Returns: 2 structures filles with all needed values
- */
-void
-dsa_generate( DSA_public_key *pk, DSA_secret_key *sk, unsigned nbits )
-{
-    MPI p;    /* the prime */
-    MPI g;
-    MPI x;    /* the secret exponent */
-    MPI y;
-
-    p = generate_public_prime( nbits );
-    /* FIXME: check wether we shall assert that (p-1)/2 is also prime
-     *       Schneier votes against it
-     */
-    g = mpi_alloc_set_ui(3);
-
-    /* select a random number */
-    x = mpi_alloc_secure( nbits/BITS_PER_MPI_LIMB );
-    if( DBG_CIPHER )
-       log_debug("choosing a random x ");
-    do {
-       if( DBG_CIPHER )
-           fputc('.', stderr);
-       mpi_set_bytes( x, nbits, get_random_byte, 1 ); /* fixme: should be 2 */
-       mpi_set_highbit( x, nbits-1 ); /* make sure it's high (needed?) */
-    } while( mpi_cmp( x, p ) >= 0 );  /* x must be smaller than p */
-
-    y = mpi_alloc(nbits/BITS_PER_MPI_LIMB);
-    mpi_powm( y, g, x, p );
-
-    if( DBG_CIPHER ) {
-       fputc('\n', stderr);
-       log_mpidump("dsa  p= ", p );
-       log_mpidump("dsa  g= ", g );
-       log_mpidump("dsa  y= ", y );
-       log_mpidump("dsa  x= ", x );
-    }
-
-
-    /* copy the stuff to the key structures */
-    pk->p = mpi_copy(p);
-    pk->g = mpi_copy(g);
-    pk->y = mpi_copy(y);
-    sk->p = p;
-    sk->g = g;
-    sk->y = y;
-    sk->x = x;
-
-    /* now we can test our keys (this should never fail!) */
-    test_keys( pk, sk, nbits - 64 );
-}
-
-
 /****************
  * Test wether the secret key is valid.
  * Returns: if this is a valid key.
@@ -174,72 +67,58 @@ dsa_check_secret_key( DSA_secret_key *sk )
 
 
 /****************
- * Make an Elgamal signature out of INPUT
+ * Make a DSA signature out of INPUT
  */
 
 void
-dsa_sign(MPI a, MPI b, MPI input, DSA_secret_key *skey )
+dsa_sign(MPI r, MPI s, MPI input, DSA_secret_key *skey )
 {
-    MPI k;
-    MPI t   = mpi_alloc( mpi_get_nlimbs(a) );
-    MPI inv = mpi_alloc( mpi_get_nlimbs(a) );
-    MPI p_1 = mpi_copy(skey->p);
-
-   /*
-    * b = (t * inv) mod (p-1)
-    * b = (t * inv(k,(p-1),(p-1)) mod (p-1)
-    * b = (((M-x*a) mod (p-1)) * inv(k,(p-1),(p-1))) mod (p-1)
-    *
-    */
-    mpi_sub_ui(p_1, p_1, 1);
-    k = gen_k( skey->p );
-    mpi_powm( a, skey->g, k, skey->p );
-    mpi_mul(t, skey->x, a );
-    mpi_subm(t, input, t, p_1 );
-    while( mpi_is_neg(t) )
-       mpi_add(t, t, p_1);
-    mpi_invm(inv, k, p_1 );
-    mpi_mulm(b, t, inv, p_1 );
-
-  #if 0
-    if( DBG_CIPHER ) {
-       log_mpidump("dsa sign p= ", skey->p);
-       log_mpidump("dsa sign g= ", skey->g);
-       log_mpidump("dsa sign y= ", skey->y);
-       log_mpidump("dsa sign x= ", skey->x);
-       log_mpidump("dsa sign k= ", k);
-       log_mpidump("dsa sign M= ", input);
-       log_mpidump("dsa sign a= ", a);
-       log_mpidump("dsa sign b= ", b);
-    }
-  #endif
-    mpi_free(k);
-    mpi_free(t);
-    mpi_free(inv);
-    mpi_free(p_1);
 }
 
 
 /****************
- * Returns true if the signature composed from A and B is valid.
+ * Returns true if the signature composed from R and S is valid.
  */
 int
-dsa_verify(MPI a, MPI b, MPI input, DSA_public_key *pkey )
+dsa_verify(MPI r, MPI s, MPI input, DSA_public_key *pkey )
 {
     int rc;
-    MPI t1 = mpi_alloc( mpi_get_nlimbs(a) );
-    MPI t2 = mpi_alloc( mpi_get_nlimbs(a) );
-
-    mpi_powm( t1, pkey->y, a, pkey->p );
-    mpi_powm( t2, a, b, pkey->p );
-    mpi_mulm( t1, t1, t2, pkey->p );
-
-    mpi_powm( t2, pkey->g, input, pkey->p );
-
-    rc = !mpi_cmp( t1, t2 );
-
-    mpi_free(t1);
-    mpi_free(t2);
+    MPI w, u1, u2, v;
+    MPI base[3];
+    MPI exp[3];
+
+    if( !(mpi_cmp_ui( r, 0 ) > 0 && mpi_cmp( r, pkey->q ) < 0) )
+       return 0; /* assertion  0 < r < q  failed */
+    if( !(mpi_cmp_ui( s, 0 ) > 0 && mpi_cmp( s, pkey->q ) < 0) )
+       return 0; /* assertion  0 < s < q  failed */
+
+    w  = mpi_alloc( mpi_get_nlimbs(pkey->q) );
+    u1 = mpi_alloc( mpi_get_nlimbs(pkey->q) );
+    u2 = mpi_alloc( mpi_get_nlimbs(pkey->q) );
+    v  = mpi_alloc( mpi_get_nlimbs(pkey->p) );
+
+    /* w = s^(-1) mod q */
+    mpi_invm( w, s, pkey->q );
+
+    /* u1 = (input * w) mod q */
+    mpi_mulm( u1, input, w, pkey->q );
+
+    /* u2 = r * w mod q  */
+    mpi_mulm( u2, r, w, pkey->q );
+
+    /* v =  g^u1 * y^u2 mod p mod q */
+    base[0] = pkey->g; exp[0] = u1;
+    base[1] = pkey->y; exp[1] = u2;
+    base[2] = NULL;    exp[2] = NULL;
+    mpi_mulpowm( v, base, exp, pkey->p );
+    mpi_fdiv_r( v, v, pkey->q );
+
+    rc = !mpi_cmp( v, r );
+
+    mpi_free(w);
+    mpi_free(u1);
+    mpi_free(u2);
+    mpi_free(v);
     return rc;
 }
 
index 1574560..07a41ae 100644 (file)
@@ -43,7 +43,7 @@ void dsa_free_public_key( DSA_public_key *pk );
 void dsa_free_secret_key( DSA_secret_key *sk );
 void dsa_generate( DSA_public_key *pk, DSA_secret_key *sk, unsigned nbits );
 int  dsa_check_secret_key( DSA_secret_key *sk );
-void dsa_sign(MPI a, MPI b, MPI input, DSA_secret_key *skey);
-int  dsa_verify(MPI a, MPI b, MPI input, DSA_public_key *pkey);
+void dsa_sign(MPI r, MPI s, MPI input, DSA_secret_key *skey);
+int  dsa_verify(MPI r, MPI s, MPI input, DSA_public_key *pkey);
 
 #endif /*G10_DSA_H*/
index a9a5666..b193996 100644 (file)
@@ -42,6 +42,7 @@ md_open( int algo, int secure )
     hd->secure = secure;
     if( algo )
        md_enable( hd, algo );
+    fast_random_poll();
     return hd;
 }
 
index 937aa61..ad937fc 100644 (file)
@@ -174,6 +174,7 @@ check_pubkey_algo( int algo )
 {
     switch( algo ) {
       case PUBKEY_ALGO_ELGAMAL:
+      case PUBKEY_ALGO_DSA:
     #ifdef HAVE_RSA_CIPHER
       case PUBKEY_ALGO_RSA:
     #endif
index 2f11df7..5a63719 100644 (file)
  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
  */
 
+
+/****************
+ * How it works:
+ *
+ * See Peter Gutmann's Paper: "Software Generation of Practically
+ * Strong Random Numbers"
+ *
+ * fixme!
+ */
+
+
 #include <config.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <sys/time.h>
 #include <sys/types.h>
 #include <sys/stat.h>
+#ifndef HAVE_GETTIMEOFTIME
+  #include <sys/times.h>
+#endif
+#ifdef HAVE_GETRUSAGE
+  #include <sys/resource.h>
+#endif
 #include <string.h>
 #include <unistd.h>
 #include <fcntl.h>
 #include "util.h"
-#include "cipher.h"
+#include "random.h"
+#include "rmd.h"
 #include "ttyio.h"
 #include "i18n.h"
 
+
+#define BLOCKLEN  64   /* hash this amount of bytes */
+#define DIGESTLEN 20   /* into a digest of this length (rmd160) */
+/* poolblocks is the number of digests which make up the pool
+ * and poolsize must be a multiple of the digest length
+ * to make the AND operations faster, the size should also be
+ * a multiple of ulong
+ */
+#define POOLBLOCKS 30
+#define POOLSIZE (POOLBLOCKS*DIGESTLEN)
+#if (POOLSIZE % SIZEOF_UNSIGNED_LONG)
+  #error Please make sure that poolsize is a multiple of ulong
+#endif
+#define POOLWORDS (POOLSIZE / SIZEOF_UNSIGNED_LONG)
+#if SIZEOF_UNSIGNED_LONG == 8
+  #define ADD_VALUE 0xa5a5a5a5a5a5a5a5
+#elif SIZEOF_UNSIGNED_LONG == 4
+  #define ADD_VALUE 0xa5a5a5a5
+#else
+  #error weird size for an unsigned long
+#endif
+
 struct cache {
     int len;
-    byte buffer[100]; /* fixme: should be allocated with m_alloc_secure()*/
+    int size;
+    byte *buffer;
 };
 
+
+static int is_initialized;
 static struct cache cache[3];
 #define MASK_LEVEL(a) do {if( a > 2 ) a = 2; else if( a < 0 ) a = 0; } while(0)
+static char *rndpool;  /* allocated size is POOLSIZE+BLOCKLEN */
+static char *keypool;  /* allocated size is POOLSIZE+BLOCKLEN */
+static size_t pool_readpos;
+static size_t pool_writepos;
+static int pool_filled;
+static int just_mixed;
+
+static int secure_alloc;
+static int quick_test;
 
 
-static void fill_buffer( byte *buffer, size_t length, int level );
-static int quick_test;
+
+static void read_pool( byte *buffer, size_t length, int level );
+static void read_dev_random( byte *buffer, size_t length, int level );
 
 
+static void
+initialize()
+{
+    /* The data buffer is allocated somewhat larger, so that
+     * we can use this extra space (which is allocated in secure memory)
+     * as a temporary hash buffer */
+    rndpool = secure_alloc ? m_alloc_secure_clear(POOLSIZE+BLOCKLEN)
+                          : m_alloc_clear(POOLSIZE+BLOCKLEN);
+    keypool = secure_alloc ? m_alloc_secure_clear(POOLSIZE+BLOCKLEN)
+                          : m_alloc_clear(POOLSIZE+BLOCKLEN);
+    is_initialized = 1;
+}
+
+void
+secure_random_alloc()
+{
+    secure_alloc = 1;
+}
+
 int
 quick_random_gen( int onoff )
 {
@@ -78,14 +150,174 @@ get_random_byte( int level )
 {
     MASK_LEVEL(level);
     if( !cache[level].len ) {
-       fill_buffer(cache[level].buffer, DIM(cache[level].buffer), level );
-       cache[level].len = DIM(cache[level].buffer);
+       if( !is_initialized )
+           initialize();
+       if( !cache[level].buffer ) {
+           cache[level].size = 100;
+           cache[level].buffer = level && secure_alloc?
+                                        m_alloc_secure( cache[level].size )
+                                      : m_alloc( cache[level].size );
+       }
+       read_pool(cache[level].buffer, cache[level].size, level );
+       cache[level].len = cache[level].size;
     }
 
     return cache[level].buffer[--cache[level].len];
 }
 
 
+/****************
+ * Mix the pool
+ */
+static void
+mix_pool(byte *pool)
+{
+    char *hashbuf = pool + POOLSIZE;
+    char *p, *pend;
+    int i, n;
+    RMD160_CONTEXT md;
+
+    rmd160_init( &md );
+ #if DIGESTLEN != 20
+    #error must have a digest length of 20 for ripe-md-160
+ #endif
+    /* loop over the pool */
+    pend = pool + POOLSIZE;
+    memcpy(hashbuf, pend - DIGESTLEN, DIGESTLEN );
+    memcpy(hashbuf+DIGESTLEN, pool, BLOCKLEN-DIGESTLEN);
+    rmd160_mixblock( &md, hashbuf);
+    memcpy(pool, hashbuf, 20 );
+
+    p = pool;
+    for( n=1; n < POOLBLOCKS; n++ ) {
+       memcpy(hashbuf, p, DIGESTLEN );
+
+       p += DIGESTLEN;
+       if( p+DIGESTLEN+BLOCKLEN < pend )
+           memcpy(hashbuf+DIGESTLEN, p+DIGESTLEN, BLOCKLEN-DIGESTLEN);
+       else {
+           char *pp = p+DIGESTLEN;
+           for(i=DIGESTLEN; i < BLOCKLEN; i++ ) {
+               if( pp >= pend )
+                   pp = pool;
+               hashbuf[i] = *pp++;
+           }
+       }
+
+       rmd160_mixblock( &md, hashbuf);
+       memcpy(p, hashbuf, 20 );
+    }
+}
+
+
+static void
+read_pool( byte *buffer, size_t length, int level )
+{
+    int i;
+    ulong *sp, *dp;
+
+    if( length >= POOLSIZE )
+       BUG(); /* not allowed */
+    if( !level ) { /* read simple random bytes */
+       read_dev_random( buffer, length, level );
+       return;
+    }
+
+    /* always do a random poll if we need strong numbers */
+    if( pool_filled && level == 2 )
+       random_poll();
+    /* make sure the pool is filled */
+    while( !pool_filled )
+       random_poll();
+    /* do always a fast random poll */
+    fast_random_poll();
+
+    /* mix the pool (if add_randomness() didn't it) */
+    if( !just_mixed )
+       mix_pool(rndpool);
+
+    /* create a new pool */
+    for(i=0,dp=(ulong*)keypool, sp=(ulong*)rndpool;
+                               i < POOLWORDS; i++, dp++, sp++ )
+       *dp = *sp + ADD_VALUE;
+    /* and mix both pools */
+    mix_pool(rndpool);
+    mix_pool(keypool);
+    /* read the required data
+     * we use a readpoiter to read from a different postion each
+     * time */
+    while( length-- ) {
+       *buffer++ = keypool[pool_readpos++];
+       if( pool_readpos >= POOLSIZE )
+           pool_readpos = 0;
+    }
+    /* and clear the keypool */
+    memset( keypool, 0, POOLSIZE );
+}
+
+
+/****************
+ * Add LENGTH bytes of randomness from buffer to the pool.
+ * source may be used to specify the randomeness source.
+ */
+void
+add_randomness( const void *buffer, size_t length, int source )
+{
+    if( !is_initialized )
+       initialize();
+    while( length-- ) {
+       rndpool[pool_writepos++] = *((byte*)buffer)++;
+       if( pool_writepos >= POOLSIZE ) {
+           pool_filled = 1;
+           pool_writepos = 0;
+           mix_pool(rndpool);
+           just_mixed = !length;
+       }
+    }
+}
+
+
+
+/********************
+ *  FIXME: move these functions to rand_unix.c
+ */
+
+void
+random_poll()
+{
+    char buf[POOLSIZE/5];
+    read_dev_random( buf, POOLSIZE/5, 1 ); /* read /dev/urandom */
+    add_randomness( buf, POOLSIZE/5, 2);
+    memset( buf, 0, POOLSIZE/5);
+}
+
+
+void
+fast_random_poll()
+{
+  #ifdef HAVE_GETTIMEOFTIME
+    {  struct timeval tv;
+       if( gettimeofday( &tv, NULL ) )
+           BUG();
+       add_randomness( &tv.tv_sec, sizeof(tv.tv_sec), 1 );
+       add_randomness( &tv.tv_usec, sizeof(tv.tv_usec), 1 );
+    }
+  #else /* use times */
+    {  struct tms buf;
+       times( &buf );
+       add_randomness( &buf, sizeof buf, 1 );
+    }
+  #endif
+  #ifdef HAVE_GETRUSAGE
+    {  struct rusage buf;
+       if( getrusage( RUSAGE_SELF, &buf ) )
+           BUG();
+       add_randomness( &buf, sizeof buf, 1 );
+       memset( &buf, 0, sizeof buf );
+    }
+  #endif
+}
+
 
 #ifdef HAVE_DEV_RANDOM
 
@@ -111,7 +343,7 @@ open_device( const char *name, int minor )
 
 
 static void
-fill_buffer( byte *buffer, size_t length, int level )
+read_dev_random( byte *buffer, size_t length, int level )
 {
     static int fd_urandom = -1;
     static int fd_random = -1;
@@ -125,6 +357,9 @@ fill_buffer( byte *buffer, size_t length, int level )
        fd = fd_random;
     }
     else {
+       /* fixme: we should use a simpler one for level 0,
+        * because reading from /dev/urandom removes entropy
+        * and the next read on /dev/random may have to wait */
        if( fd_urandom == -1 )
            fd_urandom = open_device( "/dev/urandom", 9 );
        fd = fd_urandom;
@@ -154,7 +389,7 @@ fill_buffer( byte *buffer, size_t length, int level )
            continue;
        }
 
-       assert( length < 200 );
+       assert( length < 500 );
        do {
            n = read(fd, buffer, length );
            if( n >= 0 && n > length ) {
@@ -178,7 +413,7 @@ fill_buffer( byte *buffer, size_t length, int level )
 #endif
 
 static void
-fill_buffer( byte *buffer, size_t length, int level )
+read_dev_random( byte *buffer, size_t length, int level )
 {
     static int initialized=0;
 
diff --git a/cipher/random.h b/cipher/random.h
new file mode 100644 (file)
index 0000000..a8c506d
--- /dev/null
@@ -0,0 +1,39 @@
+/* random.h - random functions
+ *     Copyright (C) 1998 Free Software Foundation, Inc.
+ *
+ * This file is part of GNUPG.
+ *
+ * GNUPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * GNUPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+#ifndef G10_RANDOM_H
+#define G10_RANDOM_H
+
+#include "types.h"
+
+/*-- random.c --*/
+void secure_random_alloc(void);
+int  quick_random_gen( int onoff );
+void randomize_buffer( byte *buffer, size_t length, int level );
+byte get_random_byte( int level );
+void add_randomness( const void *buffer, size_t length, int source );
+
+
+/*-- the next two functions are implemented by all the system
+     specific source files rand_xxxx.s --*/
+void random_poll(void);
+void fast_random_poll(void);
+
+
+#endif /*G10_RANDOM_H*/
index d6bc007..f3a6724 100644 (file)
@@ -33,6 +33,7 @@ typedef struct {
 void rmd160_init( RMD160_CONTEXT *c );
 void rmd160_write( RMD160_CONTEXT *hd, byte *inbuf, size_t inlen);
 void rmd160_final(RMD160_CONTEXT *hd);
+void rmd160_mixblock( RMD160_CONTEXT *hd, char *buffer );
 #define rmd160_read(h) ( (h)->buf )
 
 #endif /*G10_RMD_H*/
index 7b87d42..8d17b28 100644 (file)
@@ -300,6 +300,27 @@ rmd160_write( RMD160_CONTEXT *hd, byte *inbuf, size_t inlen)
 }
 
 
+/****************
+ * Apply the rmd160 transform function on the buffer which must have
+ * a length 64 bytes. Do not use this function together with the
+ * other functions, use rmd160_init to initialize intzernal variables.
+ * Returns: 16 bytes in buffer with the mixed contentes of buffer.
+ */
+void
+rmd160_mixblock( RMD160_CONTEXT *hd, char *buffer )
+{
+    char *p = buffer;
+    transform( hd, buffer );
+  #define X(a) do { *(u32*)p = hd->h##a ; p += 4; } while(0)
+    X(0);
+    X(1);
+    X(2);
+    X(3);
+    X(4);
+  #undef X
+}
+
+
 /* The routine terminates the computation
  */
 
index 95f2175..485605b 100644 (file)
 /* Define if you have the getpagesize function.  */
 #undef HAVE_GETPAGESIZE
 
+/* Define if you have the getrusage function.  */
+#undef HAVE_GETRUSAGE
+
+/* Define if you have the gettimeofday function.  */
+#undef HAVE_GETTIMEOFDAY
+
 /* Define if you have the mlock function.  */
 #undef HAVE_MLOCK
 
index 660f541..43ca5a1 100644 (file)
@@ -133,6 +133,7 @@ fi
 dnl Checks for library functions.
 AC_FUNC_VPRINTF
 AC_CHECK_FUNCS(strerror stpcpy strlwr tcgetattr rand strtoul mlock mmap)
+AC_CHECK_FUNCS(gettimeofday getrusage)
 
 
 
index ecbc391..da75525 100644 (file)
@@ -32,13 +32,30 @@ B<-c>, B<--symmetric>
     This command asks for a passphrase.
 
 B<--store>
-    store only (make a RFC1991 packet).
-
-B<-d>, B<--decrypt>
-    Decrypt data. This is the default operation for data
-    files.
-
-B<-k> [I<keyring>]
+    store only (make a simple RFC1991 packet).
+
+B<--decrypt> [I<file>]
+    Decrypt file (or stdin if no file is specified) and
+    write it to stdout (or the file specified with
+    B<--output>). If the decrypted file is signed, the
+    signature is also verified. This command differs
+    from the default operation, as it never write to the
+    filename which is included in the file and that it
+    rejects files which don't begin with an encrypted
+    message.
+
+B<--verify> [[I<sigfile>] {I<signed-files>}]
+    Assume that I<filename> is a signature and verify it
+    without generating any output.  With no arguments,
+    the signature packet is read from stdin (it may be a
+    detached signature when not used in batch mode). If
+    only a sigfile is given, is maybe a complete signature
+    or a detached signature in which case the signed stuff
+    is expected from stdin. With more than 1 argument, the
+    first should be a detached signature and the remaining
+    files are the signed stuff.
+
+B<-k> [I<username>] [I<keyring>]
     Kludge to be somewhat compatibe to PGP.
     Without arguments, all public key-rings are listed,
     with one argument, only I<keyring> is listed.
@@ -50,15 +67,21 @@ B<-k> [I<keyring>]
     B<-kvc>   List fingerprints
     B<-kvvc>  List fingerprints and signatures
 
-B<--list-keys>
-    List all keys in all public key-rings and check the
-    signatures.
+B<--list-keys> [I<names>]
+    List all keys from the default public keyring or just the ones
+    given on the commandline.
 
-B<--check-keys>
-    Check signatures on a key in the keyring
+B<--list-sigs> [I<names>]
+    Same as B<--list-keys>, but the signatures are listed too.
 
-B<--fingerprint>
-    Show the fingerprints
+B<--check-sigs> [I<names>]
+    Same as B<--list-sigs>, but the signatures are verified.
+
+B<--fingerprint> [I<names>]
+    List all keys with their fingerprints. This is the
+    same output as B<list-keys> but with the additonal output
+    of a line with the fingerprint. May also be combined
+    with B<--list-sigs> or B<--check-sigs>.
 
 B<--list-packets>
     List only the sequence of packets. This is mainly
@@ -84,7 +107,10 @@ B<--sign-key> I<name>
 B<--delete-key>
     Remove key from the public keyring
 
-B<--edit-sig>
+B<--delete-secret-key>
+    Remove key from the secret and public keyring
+
+B<--edit-key>
     Edit/remove a key signature.
 
 B<--change-passphrase>
@@ -124,9 +150,13 @@ B<-o> I<file>, B<--output> I<file>
 
 B<-u> I<name>, B<--local-user> I<name>
     Use I<name> as the user-id to sign.
+    This option is silently ignored for the list commands,
+    so that it can be used in an options file.
 
 B<-r>  I<name>, B<--remote-user>  I<name>
-    Use  I<name> as the user-id for encryption.
+    Use I<name> as the user-id for encryption.
+    This option is silently ignored for the list commands,
+    so that it can be used in an options file.
 
 B<-v>, B<--verbose>
     Give more informations during processing. If used
@@ -181,7 +211,7 @@ B<--options> I<file>
     (see B<--homedir>). This option is ignored when used
     in an options file.
 
-B<no-options>
+B<--no-options>
     Shortcut for B<--options> I</dev/null>.  This option is
     detected before an attempt to open an option file.
 
@@ -227,17 +257,17 @@ B<--passphrase-fd> I<n>
     can only be used if only one passphrase is supplied.
     B<Don't use this option if you can avoid it>
 
-B<no-verbose>
+B<--no-verbose>
     Reset verbose level to 0.
 
-B<no-greeting>
+B<--no-greeting>
     Suppress the initial copyright message but do not
     enter batch mode.
 
-B<no-armor>
+B<--no-armor>
     Assume the input data is not in ASCCI armored format.
 
-B<no-default-keyring>
+B<--no-default-keyring>
     Do not add the default key-rings to the list of
     key-rings.
 
@@ -245,6 +275,9 @@ B<--version>
     Print version information along with a list
     of supported algorithms.
 
+B<--with-colons>
+    Print key listings delimited by colons.
+
 B<--warranty>
     Print warranty information.
 
index c1f6036..c641441 100644 (file)
@@ -1,3 +1,49 @@
+Mon Mar  9 12:43:42 1998  Werner Koch  (wk@isil.d.shuttle.de)
+
+       * dsa.c: New
+       * packet.h, free-packet.c, parse-packet.c : Add support for DSA
+       * sig-check.c, getkey.c, keyid.c, ringedit.c: Ditto.
+       * seckey-cert.c: Ditto.
+
+       * packet.h : Moved .digest_algo of signature packets to outer
+       structure. Changed all references
+
+Sun Mar  8 13:06:42 1998  Werner Koch  (wk@isil.d.shuttle.de)
+
+       * openfile.c : Support for stdout filename "-".
+
+       * mainproc.c (check_sig_and_print): Enhanced status output:
+       * status.c (write_status_text): New.
+
+Fri Mar  6 16:10:54 1998  Werner Koch  (wk@isil.d.shuttle.de)
+
+       * kbnode.c (clone_kbnode): Fixed private_flag.
+
+       * mainproc.c (list_node): Output of string "Revoked" as user-id.
+
+Fri Mar  6 14:26:39 1998  Werner Koch  (wk@isil.d.shuttle.de)
+
+       * g10.c (main): Add userids to "-kv" and cleaned up this stuff.
+
+Fri Mar  6 12:45:58 1998  Werner Koch  (wk@isil.d.shuttle.de)
+
+       * g10.c (main): Changed semantics of the list-... commands
+       and added a new one. Removed option "-d"
+
+       * decrypt.c: New.
+
+       * trustdb.c (init_trustdb): Autocreate directory only if it ends
+       in "/.gnupg".
+
+Thu Mar  5 12:12:11 1998  Werner Koch  (wk@isil.d.shuttle.de)
+
+       * mainproc.c (do_proc_packets): New. Common part of proc_packet.
+       (proc_signature_packets): special version to handle signature data.
+       * verify.c: New.
+       * g10.c (aVerify): New.
+       * plaintext.c (hash_datafiles): New.
+       * compress.c (handle_compressed): Add callback arg, changed caller.
+
 Thu Mar  5 10:20:06 1998  Werner Koch  (wk@isil.d.shuttle.de)
 
        * g10.c: Is nom the common source for gpg and gpgm
index aaed0ff..edfdba4 100644 (file)
@@ -26,6 +26,7 @@ common_source =  \
              textfilter.c      \
              cipher.c          \
              elg.c             \
+             dsa.c             \
              rsa.c             \
              options.h         \
              openfile.c        \
@@ -48,16 +49,18 @@ common_source =  \
              encr-data.c       \
              encode.c          \
              revoke.c          \
+             keylist.c         \
              sig-check.c
 
 gpg_SOURCES  = g10.c           \
              $(common_source)  \
+             verify.c          \
+             decrypt.c         \
              keygen.c
 
 
 gpgm_SOURCES = g10maint.c   \
              dearmor.c     \
-             keylist.c     \
              $(common_source)
 
 LDADD = @INTLLIBS@ $(needed_libs) @ZLIBS@
index caffcd7..cc4b69b 100644 (file)
@@ -118,6 +118,7 @@ common_source =  \
              textfilter.c      \
              cipher.c          \
              elg.c             \
+             dsa.c             \
              rsa.c             \
              options.h         \
              openfile.c        \
@@ -140,15 +141,17 @@ common_source =  \
              encr-data.c       \
              encode.c          \
              revoke.c          \
+             keylist.c         \
              sig-check.c
 
 gpg_SOURCES  = g10.c           \
              $(common_source)  \
+             verify.c          \
+             decrypt.c         \
              keygen.c
 
 gpgm_SOURCES = g10maint.c   \
              dearmor.c     \
-             keylist.c     \
              $(common_source)
 
 LDADD = @INTLLIBS@ $(needed_libs) @ZLIBS@
@@ -164,20 +167,20 @@ LDFLAGS = @LDFLAGS@
 LIBS = @LIBS@
 gpg_OBJECTS =  g10.o build-packet.o compress.o free-packet.o getkey.o \
 pkclist.o skclist.o ringedit.o kbnode.o mainproc.o armor.o mdfilter.o \
-textfilter.o cipher.o elg.o rsa.o openfile.o keyid.o trustdb.o \
+textfilter.o cipher.o elg.o dsa.o rsa.o openfile.o keyid.o trustdb.o \
 parse-packet.o passphrase.o pubkey-enc.o seckey-cert.o seskey.o \
 import.o export.o comment.o status.o sign.o plaintext.o encr-data.o \
-encode.o revoke.o sig-check.o keygen.o
+encode.o revoke.o keylist.o sig-check.o verify.o decrypt.o keygen.o
 gpg_LDADD = $(LDADD)
 gpg_DEPENDENCIES =  ../cipher/libcipher.a ../mpi/libmpi.a \
 ../util/libutil.a
 gpg_LDFLAGS = 
-gpgm_OBJECTS =  g10maint.o dearmor.o keylist.o build-packet.o compress.o \
+gpgm_OBJECTS =  g10maint.o dearmor.o build-packet.o compress.o \
 free-packet.o getkey.o pkclist.o skclist.o ringedit.o kbnode.o \
-mainproc.o armor.o mdfilter.o textfilter.o cipher.o elg.o rsa.o \
+mainproc.o armor.o mdfilter.o textfilter.o cipher.o elg.o dsa.o rsa.o \
 openfile.o keyid.o trustdb.o parse-packet.o passphrase.o pubkey-enc.o \
 seckey-cert.o seskey.o import.o export.o comment.o status.o sign.o \
-plaintext.o encr-data.o encode.o revoke.o sig-check.o
+plaintext.o encr-data.o encode.o revoke.o keylist.o sig-check.o
 gpgm_LDADD = $(LDADD)
 gpgm_DEPENDENCIES =  ../cipher/libcipher.a ../mpi/libmpi.a \
 ../util/libutil.a
@@ -193,16 +196,16 @@ DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST)
 TAR = tar
 GZIP = --best
 DEP_FILES =  .deps/armor.P .deps/build-packet.P .deps/cipher.P \
-.deps/comment.P .deps/compress.P .deps/dearmor.P .deps/elg.P \
-.deps/encode.P .deps/encr-data.P .deps/export.P .deps/free-packet.P \
-.deps/g10.P .deps/g10maint .deps/g10maint.P .deps/getkey.P \
-.deps/import.P .deps/kbnode.P .deps/keygen.P .deps/keyid.P \
-.deps/keylist.P .deps/mainproc.P .deps/mdfilter.P .deps/openfile.P \
-.deps/parse-packet.P .deps/passphrase.P .deps/pkclist.P \
-.deps/plaintext.P .deps/pubkey-enc.P .deps/revoke.P .deps/ringedit.P \
-.deps/rsa.P .deps/seckey-cert.P .deps/seskey.P .deps/sig-check.P \
-.deps/sign.P .deps/skclist.P .deps/status.P .deps/textfilter.P \
-.deps/trustdb.P
+.deps/comment.P .deps/compress.P .deps/dearmor.P .deps/decrypt.P \
+.deps/dsa.P .deps/elg.P .deps/encode.P .deps/encr-data.P .deps/export.P \
+.deps/free-packet.P .deps/g10.P .deps/g10maint .deps/g10maint.P \
+.deps/getkey.P .deps/import.P .deps/kbnode.P .deps/keygen.P \
+.deps/keyid.P .deps/keylist.P .deps/mainproc.P .deps/mdfilter.P \
+.deps/openfile.P .deps/parse-packet.P .deps/passphrase.P \
+.deps/pkclist.P .deps/plaintext.P .deps/pubkey-enc.P .deps/revoke.P \
+.deps/ringedit.P .deps/rsa.P .deps/seckey-cert.P .deps/seskey.P \
+.deps/sig-check.P .deps/sign.P .deps/skclist.P .deps/status.P \
+.deps/textfilter.P .deps/trustdb.P .deps/verify.P
 SOURCES = $(gpg_SOURCES) $(gpgm_SOURCES)
 OBJECTS = $(gpg_OBJECTS) $(gpgm_OBJECTS)
 
index 142e0bd..3192e95 100644 (file)
@@ -322,7 +322,7 @@ find_header( fhdr_state_t state, byte *buf, size_t *r_buflen,
                            buf[--n] = 0;
                        if( opt.verbose ) {
                            log_info("armor header: ");
-                           print_string( stderr, buf, n );
+                           print_string( stderr, buf, n, 0 );
                            putc('\n', stderr);
                        }
                        if( clearsig && !parse_hash_header( buf ) ) {
@@ -348,7 +348,7 @@ find_header( fhdr_state_t state, byte *buf, size_t *r_buflen,
                }
                else {
                    log_error("invalid armor header: ");
-                   print_string( stderr, buf, n );
+                   print_string( stderr, buf, n, 0 );
                    putc('\n', stderr);
                    state = fhdrERROR;
                }
@@ -357,7 +357,7 @@ find_header( fhdr_state_t state, byte *buf, size_t *r_buflen,
                if( strchr( buf, ':') ) { /* buffer to short, but this is okay*/
                    if( opt.verbose ) {
                        log_info("armor header: ");
-                       print_string( stderr, buf, n );
+                       print_string( stderr, buf, n, 0 );
                        fputs("[...]\n", stderr);  /* indicate it is truncated */
                    }
                    state = fhdrSKIPHeader;  /* skip rest of line */
@@ -462,7 +462,7 @@ find_header( fhdr_state_t state, byte *buf, size_t *r_buflen,
            }
            else {
                log_error("invalid dash escaped line: ");
-               print_string( stderr, buf, n );
+               print_string( stderr, buf, n, 0 );
                putc('\n', stderr);
                state = fhdrERROR;
            }
@@ -531,7 +531,7 @@ find_header( fhdr_state_t state, byte *buf, size_t *r_buflen,
 
          case fhdrERRORShow:
            log_error("invalid clear text header: ");
-           print_string( stderr, buf, n );
+           print_string( stderr, buf, n, 0 );
            putc('\n', stderr);
            state = fhdrERROR;
            break;
index ea8a875..793095e 100644 (file)
@@ -175,13 +175,20 @@ do_public_cert( IOBUF out, int ctb, PKT_public_cert *pkc )
     else
        iobuf_put( a, pkc->version );
     write_32(a, pkc->timestamp );
-    write_16(a, pkc->valid_days );
+    if( pkc->version < 4 )
+       write_16(a, pkc->valid_days );
     iobuf_put(a, pkc->pubkey_algo );
     if( pkc->pubkey_algo == PUBKEY_ALGO_ELGAMAL ) {
        mpi_write(a, pkc->d.elg.p );
        mpi_write(a, pkc->d.elg.g );
        mpi_write(a, pkc->d.elg.y );
     }
+    else if( pkc->pubkey_algo == PUBKEY_ALGO_DSA ) {
+       mpi_write(a, pkc->d.dsa.p );
+       mpi_write(a, pkc->d.dsa.q );
+       mpi_write(a, pkc->d.dsa.g );
+       mpi_write(a, pkc->d.dsa.y );
+    }
     else if( pkc->pubkey_algo == PUBKEY_ALGO_RSA ) {
        mpi_write(a, pkc->d.rsa.rsa_n );
        mpi_write(a, pkc->d.rsa.rsa_e );
@@ -253,7 +260,8 @@ do_secret_cert( IOBUF out, int ctb, PKT_secret_cert *skc )
     else
        iobuf_put( a, skc->version );
     write_32(a, skc->timestamp );
-    write_16(a, skc->valid_days );
+    if( skc->version < 4 )
+       write_16(a, skc->valid_days );
     iobuf_put(a, skc->pubkey_algo );
     if( skc->pubkey_algo == PUBKEY_ALGO_ELGAMAL ) {
        mpi_write(a, skc->d.elg.p );
@@ -416,24 +424,35 @@ do_signature( IOBUF out, int ctb, PKT_signature *sig )
     int rc = 0;
     IOBUF a = iobuf_temp();
 
-    write_version( a, ctb );
-    iobuf_put(a, 5 ); /* constant */
+    if( !sig->version )
+       iobuf_put( a, 3 );
+    else
+       iobuf_put( a, sig->version );
+    if( sig->version < 4 )
+       iobuf_put(a, 5 ); /* constant */
     iobuf_put(a, sig->sig_class );
-    write_32(a, sig->timestamp );
-    write_32(a, sig->keyid[0] );
-    write_32(a, sig->keyid[1] );
+    if( sig->version < 4 ) {
+       write_32(a, sig->timestamp );
+       write_32(a, sig->keyid[0] );
+       write_32(a, sig->keyid[1] );
+    }
     iobuf_put(a, sig->pubkey_algo );
+    iobuf_put(a, sig->digest_algo );
+    if( sig->version >= 4 ) {
+       /* fixme: write v4 subpackets here */
+       log_error("WARNING: note writing of v4 subpackets is not implemented\n");
+    }
+    iobuf_put(a, sig->digest_start[0] );
+    iobuf_put(a, sig->digest_start[1] );
     if( sig->pubkey_algo == PUBKEY_ALGO_ELGAMAL ) {
-       iobuf_put(a, sig->d.elg.digest_algo );
-       iobuf_put(a, sig->d.elg.digest_start[0] );
-       iobuf_put(a, sig->d.elg.digest_start[1] );
        mpi_write(a, sig->d.elg.a );
        mpi_write(a, sig->d.elg.b );
     }
+    else if( sig->pubkey_algo == PUBKEY_ALGO_DSA ) {
+       mpi_write(a, sig->d.dsa.r );
+       mpi_write(a, sig->d.dsa.s );
+    }
     else if( sig->pubkey_algo == PUBKEY_ALGO_RSA ) {
-       iobuf_put(a, sig->d.rsa.digest_algo );
-       iobuf_put(a, sig->d.rsa.digest_start[0] );
-       iobuf_put(a, sig->d.rsa.digest_start[1] );
        mpi_write(a, sig->d.rsa.rsa_integer );
     }
     else {
index ebad430..686332b 100644 (file)
@@ -230,9 +230,11 @@ compress_filter( void *opaque, int control,
  * Handle a compressed packet
  */
 int
-handle_compressed( PKT_compressed *cd )
+handle_compressed( PKT_compressed *cd,
+                  int (*callback)(IOBUF, void *), void *passthru )
 {
     compress_filter_context_t cfx;
+    int rc;
 
     memset( &cfx, 0, sizeof cfx );
     if( cd->algorithm == 1 )
@@ -241,7 +243,10 @@ handle_compressed( PKT_compressed *cd )
        return G10ERR_COMPR_ALGO;
 
     iobuf_push_filter( cd->buf, compress_filter, &cfx );
-    proc_packets(cd->buf);
+    if( callback )
+       rc = callback(cd->buf, passthru );
+    else
+       rc = proc_packets(cd->buf);
     iobuf_pop_filter( cd->buf, compress_filter, &cfx );
   #if 0
     if( cd->len )
@@ -250,6 +255,6 @@ handle_compressed( PKT_compressed *cd )
        iobuf_clear_eof( cd->buf );
   #endif
     cd->buf = NULL;
-    return 0;
+    return rc;
 }
 
diff --git a/g10/decrypt.c b/g10/decrypt.c
new file mode 100644 (file)
index 0000000..1a457f2
--- /dev/null
@@ -0,0 +1,82 @@
+/* verify.c - verify signed data
+ *     Copyright (C) 1998 Free Software Foundation, Inc.
+ *
+ * This file is part of GNUPG.
+ *
+ * GNUPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * GNUPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <assert.h>
+
+#include "options.h"
+#include "packet.h"
+#include "errors.h"
+#include "iobuf.h"
+#include "keydb.h"
+#include "memory.h"
+#include "util.h"
+#include "main.h"
+#include "i18n.h"
+
+
+
+/****************
+ * Assume that the input is an encrypted message and decrypt
+ * (and if signed, verify the signature) it.
+ * This command differs from the default operation, as it never
+ * write to the filename which is included in the file and that it
+ * rejects files which don't begin with an encrypted message.
+ */
+
+int
+decrypt_message( const char *filename )
+{
+    IOBUF fp;
+    armor_filter_context_t afx;
+    int rc;
+    int no_out=0;
+
+    /* open the message file */
+    fp = iobuf_open(filename);
+    if( !fp ) {
+       log_error(_("can't open '%s'\n"), print_fname_stdin(filename));
+       return G10ERR_OPEN_FILE;
+    }
+
+    if( !opt.no_armor ) {
+       if( use_armor_filter( fp ) ) {
+           memset( &afx, 0, sizeof afx);
+           iobuf_push_filter( fp, armor_filter, &afx );
+       }
+    }
+
+    if( !opt.outfile ) {
+       no_out = 1;
+       opt.outfile = "-";
+    }
+    rc = proc_encryption_packets( fp );
+    if( no_out )
+       opt.outfile = NULL;
+    iobuf_close(fp);
+    return rc;
+}
+
+
+
diff --git a/g10/dsa.c b/g10/dsa.c
new file mode 100644 (file)
index 0000000..1c4f894
--- /dev/null
+++ b/g10/dsa.c
@@ -0,0 +1,71 @@
+/* dsa.c
+ *     Copyright (C) 1998 Free Software Foundation, Inc.
+ *
+ * This file is part of GNUPG.
+ *
+ * GNUPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * GNUPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <assert.h>
+
+#include "options.h"
+#include "packet.h"
+#include "errors.h"
+#include "iobuf.h"
+#include "keydb.h"
+#include "memory.h"
+#include "util.h"
+#include "main.h"
+
+
+void
+g10_dsa_sign( PKT_secret_cert *skc, PKT_signature *sig,
+             MD_HANDLE md, int digest_algo )
+{
+    DSA_secret_key skey;
+    MPI frame;
+    byte *dp;
+
+    assert( sig->pubkey_algo == PUBKEY_ALGO_DSA );
+    if( !digest_algo )
+       digest_algo = md_get_algo(md);
+
+    dp = md_read( md, digest_algo );
+    keyid_from_skc( skc, sig->keyid );
+    sig->digest_algo = digest_algo;
+    sig->digest_start[0] = dp[0];
+    sig->digest_start[1] = dp[1];
+    sig->d.dsa.r = mpi_alloc( mpi_get_nlimbs(skc->d.dsa.p) );
+    sig->d.dsa.s = mpi_alloc( mpi_get_nlimbs(skc->d.dsa.p) );
+    frame = encode_md_value( md, mpi_get_nbits(skc->d.dsa.p));
+    skey.p = skc->d.elg.p;
+    skey.g = skc->d.elg.g;
+    skey.y = skc->d.elg.y;
+    skey.x = skc->d.elg.x;
+    dsa_sign( sig->d.dsa.r, sig->d.dsa.s, frame, &skey);
+    memset( &skey, 0, sizeof skey );
+    mpi_free(frame);
+    if( opt.verbose ) {
+       char *ustr = get_user_id_string( sig->keyid );
+       log_info("DSA signature from: %s\n", ustr );
+       m_free(ustr);
+    }
+}
+
index 62c5014..329b762 100644 (file)
--- a/g10/elg.c
+++ b/g10/elg.c
@@ -79,9 +79,9 @@ g10_elg_sign( PKT_secret_cert *skc, PKT_signature *sig,
 
     dp = md_read( md, digest_algo );
     keyid_from_skc( skc, sig->keyid );
-    sig->d.elg.digest_algo = digest_algo;
-    sig->d.elg.digest_start[0] = dp[0];
-    sig->d.elg.digest_start[1] = dp[1];
+    sig->digest_algo = digest_algo;
+    sig->digest_start[0] = dp[0];
+    sig->digest_start[1] = dp[1];
     sig->d.elg.a = mpi_alloc( mpi_get_nlimbs(skc->d.elg.p) );
     sig->d.elg.b = mpi_alloc( mpi_get_nlimbs(skc->d.elg.p) );
     frame = encode_md_value( md, mpi_get_nbits(skc->d.elg.p));
index fa1a53c..eb90f51 100644 (file)
@@ -45,31 +45,41 @@ free_pubkey_enc( PKT_pubkey_enc *enc )
 }
 
 void
-free_seckey_enc( PKT_signature *enc )
+free_seckey_enc( PKT_signature *sig )
 {
-    if( enc->pubkey_algo == PUBKEY_ALGO_ELGAMAL ) {
-       mpi_free( enc->d.elg.a );
-       mpi_free( enc->d.elg.b );
+    if( sig->pubkey_algo == PUBKEY_ALGO_ELGAMAL ) {
+       mpi_free( sig->d.elg.a );
+       mpi_free( sig->d.elg.b );
     }
-    else if( enc->pubkey_algo == PUBKEY_ALGO_RSA )
-       mpi_free( enc->d.rsa.rsa_integer );
-    m_free(enc);
+    else if( sig->pubkey_algo == PUBKEY_ALGO_DSA ) {
+       mpi_free( sig->d.dsa.r );
+       mpi_free( sig->d.dsa.s );
+    }
+    else if( sig->pubkey_algo == PUBKEY_ALGO_RSA )
+       mpi_free( sig->d.rsa.rsa_integer );
+    m_free(sig->hashed_data);
+    m_free(sig->unhashed_data);
+    m_free(sig);
 }
 
 
 /****************
- * Return the digest algorith from the signature packet.
+ * Return the digest algorithm from the signature packet.
  * We need this function because the digeste algo depends on the
  * used pubkey algorithm.
  */
 int
 digest_algo_from_sig( PKT_signature *sig )
 {
+  #if 0 /* not used anymore */
     switch( sig->pubkey_algo ) {
       case PUBKEY_ALGO_ELGAMAL: return sig->d.elg.digest_algo;
+      case PUBKEY_ALGO_DSA:    return sig->d.dsa.digest_algo;
       case PUBKEY_ALGO_RSA:    return sig->d.rsa.digest_algo;
       default: return 0;
     }
+  #endif
+    return sig->digest_algo;
 }
 
 
@@ -83,6 +93,12 @@ release_public_cert_parts( PKT_public_cert *cert )
        mpi_free( cert->d.elg.g ); cert->d.elg.g = NULL;
        mpi_free( cert->d.elg.y ); cert->d.elg.y = NULL;
     }
+    else if( cert->pubkey_algo == PUBKEY_ALGO_DSA ) {
+       mpi_free( cert->d.dsa.p ); cert->d.dsa.p = NULL;
+       mpi_free( cert->d.dsa.q ); cert->d.dsa.q = NULL;
+       mpi_free( cert->d.dsa.g ); cert->d.dsa.g = NULL;
+       mpi_free( cert->d.dsa.y ); cert->d.dsa.y = NULL;
+    }
     else if( cert->pubkey_algo == PUBKEY_ALGO_RSA ) {
        mpi_free( cert->d.rsa.rsa_n ); cert->d.rsa.rsa_n = NULL;
        mpi_free( cert->d.rsa.rsa_e ); cert->d.rsa.rsa_e = NULL;
@@ -107,6 +123,12 @@ copy_public_cert( PKT_public_cert *d, PKT_public_cert *s )
        d->d.elg.g = mpi_copy( s->d.elg.g );
        d->d.elg.y = mpi_copy( s->d.elg.y );
     }
+    else if( s->pubkey_algo == PUBKEY_ALGO_DSA ) {
+       d->d.dsa.p = mpi_copy( s->d.dsa.p );
+       d->d.dsa.q = mpi_copy( s->d.dsa.q );
+       d->d.dsa.g = mpi_copy( s->d.dsa.g );
+       d->d.dsa.y = mpi_copy( s->d.dsa.y );
+    }
     else if( s->pubkey_algo == PUBKEY_ALGO_RSA ) {
        d->d.rsa.rsa_n = mpi_copy( s->d.rsa.rsa_n );
        d->d.rsa.rsa_e = mpi_copy( s->d.rsa.rsa_e );
@@ -123,6 +145,13 @@ release_secret_cert_parts( PKT_secret_cert *cert )
        mpi_free( cert->d.elg.y ); cert->d.elg.y = NULL;
        mpi_free( cert->d.elg.x ); cert->d.elg.x = NULL;
     }
+    else if( cert->pubkey_algo == PUBKEY_ALGO_DSA ) {
+       mpi_free( cert->d.dsa.p ); cert->d.dsa.p = NULL;
+       mpi_free( cert->d.dsa.q ); cert->d.dsa.q = NULL;
+       mpi_free( cert->d.dsa.g ); cert->d.dsa.g = NULL;
+       mpi_free( cert->d.dsa.y ); cert->d.dsa.y = NULL;
+       mpi_free( cert->d.dsa.x ); cert->d.dsa.x = NULL;
+    }
     else if( cert->pubkey_algo == PUBKEY_ALGO_RSA ) {
        mpi_free( cert->d.rsa.rsa_n ); cert->d.rsa.rsa_n = NULL;
        mpi_free( cert->d.rsa.rsa_e ); cert->d.rsa.rsa_e = NULL;
@@ -152,6 +181,13 @@ copy_secret_cert( PKT_secret_cert *d, PKT_secret_cert *s )
        d->d.elg.y = mpi_copy( s->d.elg.y );
        d->d.elg.x = mpi_copy( s->d.elg.x );
     }
+    else if( s->pubkey_algo == PUBKEY_ALGO_DSA ) {
+       d->d.dsa.p = mpi_copy( s->d.dsa.p );
+       d->d.dsa.q = mpi_copy( s->d.dsa.q );
+       d->d.dsa.g = mpi_copy( s->d.dsa.g );
+       d->d.dsa.y = mpi_copy( s->d.dsa.y );
+       d->d.dsa.x = mpi_copy( s->d.dsa.x );
+    }
     else if( s->pubkey_algo == PUBKEY_ALGO_RSA ) {
        d->d.rsa.rsa_n = mpi_copy( s->d.rsa.rsa_n );
        d->d.rsa.rsa_e = mpi_copy( s->d.rsa.rsa_e );
@@ -290,6 +326,16 @@ cmp_public_certs( PKT_public_cert *a, PKT_public_cert *b )
        if( mpi_cmp( a->d.elg.y , b->d.elg.y ) )
            return -1;
     }
+    else if( a->pubkey_algo == PUBKEY_ALGO_DSA ) {
+       if( mpi_cmp( a->d.dsa.p , b->d.dsa.p ) )
+           return -1;
+       if( mpi_cmp( a->d.dsa.q , b->d.dsa.q ) )
+           return -1;
+       if( mpi_cmp( a->d.dsa.g , b->d.dsa.g ) )
+           return -1;
+       if( mpi_cmp( a->d.dsa.y , b->d.dsa.y ) )
+           return -1;
+    }
     else if( a->pubkey_algo == PUBKEY_ALGO_RSA ) {
        if( mpi_cmp( a->d.rsa.rsa_n , b->d.rsa.rsa_n ) )
            return -1;
@@ -321,6 +367,16 @@ cmp_public_secret_cert( PKT_public_cert *pkc, PKT_secret_cert *skc )
        if( mpi_cmp( pkc->d.elg.y , skc->d.elg.y ) )
            return -1;
     }
+    else if( pkc->pubkey_algo == PUBKEY_ALGO_DSA ) {
+       if( mpi_cmp( pkc->d.dsa.p , skc->d.dsa.p ) )
+           return -1;
+       if( mpi_cmp( pkc->d.dsa.q , skc->d.dsa.q ) )
+           return -1;
+       if( mpi_cmp( pkc->d.dsa.g , skc->d.dsa.g ) )
+           return -1;
+       if( mpi_cmp( pkc->d.dsa.y , skc->d.dsa.y ) )
+           return -1;
+    }
     else if( pkc->pubkey_algo == PUBKEY_ALGO_RSA ) {
        if( mpi_cmp( pkc->d.rsa.rsa_n , skc->d.rsa.rsa_n ) )
            return -1;
index b5ee4e4..d2683c9 100644 (file)
--- a/g10/g10.c
+++ b/g10/g10.c
@@ -63,9 +63,13 @@ static ARGPARSE_OPTS opts[] = {
     { 'c', "symmetric", 0, N_("encryption only with symmetric cipher")},
     { 507, "store",     0, N_("store only")},
     { 'd', "decrypt",   0, N_("decrypt data (default)")},
-    { 'k', "list-keys", 0, N_("list keys")},
-    { 508, "check-keys",0, N_("check signatures on a key in the keyring")},
-    { 515, "fingerprint", 0, N_("show the fingerprints")},
+    { 550, "verify"   , 0, N_("verify a signature")},
+  #endif
+    { 551, "list-keys", 0, N_("list keys")},
+    { 552, "list-sigs", 0, N_("list keys and signatures")},
+    { 508, "check-sigs",0, N_("check key signatures")},
+    { 515, "fingerprint", 0, N_("list keys and fingerprints")},
+  #ifdef IS_G10
     { 503, "gen-key",   0, N_("generate a new key pair")},
     { 506, "sign-key"  ,0, N_("make a signature on a key in the keyring")},
     { 505, "delete-key",0, N_("remove key from the public keyring")},
@@ -82,7 +86,6 @@ static ARGPARSE_OPTS opts[] = {
     { 516, "print-mds" , 0, N_("print all message digests")},
     { 513, "gen-prime" , 0, "\r" },
     { 548, "gen-random" , 0, "\r" },
-    { 549, "ext-list-keys", 0, "Print a parsable list of keys" },
   #endif
 
     { 301, NULL, 0, N_("\v\nOptions:\n ") },
@@ -132,6 +135,7 @@ static ARGPARSE_OPTS opts[] = {
     { 533, "list-trust-path",0, "\r"},
   #endif
   #ifdef IS_G10
+    { 'k', NULL,        0, "\r"},
     { 504, "delete-secret-key",0, "\r" },
     { 524, "edit-sig"  ,0, "\r"}, /* alias for edit-key */
     { 523, "passphrase-fd",1, "\r" },
@@ -147,6 +151,10 @@ static ARGPARSE_OPTS opts[] = {
     { 543, "no-options", 0, "\r" }, /* shortcut for --options /dev/null */
     { 544, "homedir", 2, "\r" },   /* defaults to "~/.gnupg" */
     { 545, "no-batch", 0, "\r" },
+    { 549, "with-colons", 0, "\r"},
+    { 551, "list-key", 0, "\r" }, /* alias */
+    { 552, "list-sig", 0, "\r" }, /* alias */
+    { 508, "check-sig",0, "\r" }, /* alias */
 
 
 {0} };
@@ -157,8 +165,9 @@ static ARGPARSE_OPTS opts[] = {
 enum cmd_values { aNull = 0,
     aSym, aStore, aEncr, aKeygen, aSign, aSignEncr,
     aSignKey, aClearsign, aListPackets, aEditSig, aDeleteKey, aDeleteSecretKey,
-    aKMode, aKModeC, aChangePass, aImport,
-    aExport, aCheckKeys, aGenRevoke, aPrimegen, aPrintMDs, aExtKeyList,
+    aKMode, aKModeC, aChangePass, aImport, aVerify, aDecrypt, aListKeys,
+    aListSigs,
+    aExport, aCheckKeys, aGenRevoke, aPrimegen, aPrintMDs,
     aListTrustDB, aListTrustPath, aDeArmor, aEnArmor, aGenRandom, aTest,
 aNOP };
 
@@ -358,7 +367,7 @@ main( int argc, char **argv )
     int rc=0;
     int orig_argc;
     char **orig_argv;
-    const char *fname, *fname_print;
+    const char *fname;
     STRLIST sl, remusr= NULL, locusr=NULL;
     int nrings=0, sec_nrings=0;
     armor_filter_context_t afx;
@@ -458,11 +467,10 @@ main( int argc, char **argv )
 
        #ifdef IS_G10
          case 'a': opt.armor = 1; opt.no_armor=0; break;
-         case 'b': detached_sig = 1; /* fall trough */
-         case 'c': set_cmd( &cmd , aSym); break;
-         case 'd': break; /* it is default */
+         case 'b': detached_sig = 1; set_cmd( &cmd, aSign ); break;
+         case 'c': set_cmd( &cmd, aSym); break;
+         case 'd': set_cmd( &cmd, aDecrypt); break;
          case 'e': set_cmd( &cmd, aEncr); break;
-         case 'k': set_cmd( &cmd, aKMode ); break;
          case 'r': /* store the remote users */
            sl = m_alloc( sizeof *sl + strlen(pargs.r.ret_str));
            strcpy(sl->d, pargs.r.ret_str);
@@ -483,9 +491,6 @@ main( int argc, char **argv )
          case 505: set_cmd( &cmd, aDeleteKey); break;
          case 506: set_cmd( &cmd, aSignKey); break;
          case 507: set_cmd( &cmd, aStore); break;
-         case 508: set_cmd( &cmd, aCheckKeys);
-                   opt.check_sigs = 1; opt.list_sigs = 1; break;
-         case 515: opt.fingerprint = 1; break;
          case 523: set_passphrase_fd( pargs.r.ret_int ); break;
          case 524: set_cmd( &cmd, aEditSig); break;
          case 525: set_cmd( &cmd, aChangePass); break;
@@ -501,6 +506,7 @@ main( int argc, char **argv )
          case 539: set_cmd( &cmd, aClearsign); break;
          case 540: secmem_set_flags( secmem_get_flags() | 1 ); break;
          case 542: set_cmd( &cmd, aGenRevoke); break;
+         case 550: set_cmd( &cmd, aVerify); break;
        #endif /* IS_G10 */
 
        #ifdef IS_G10MAINT
@@ -513,19 +519,21 @@ main( int argc, char **argv )
          case 546: set_cmd( &cmd, aDeArmor); break;
          case 547: set_cmd( &cmd, aEnArmor); break;
          case 548: set_cmd( &cmd, aGenRandom); break;
-         case 549: set_cmd( &cmd, aExtKeyList); break;
        #endif /* IS_G10MAINT */
 
          case 'o': opt.outfile = pargs.r.ret_str; break;
          case 'v': opt.verbose++; opt.list_sigs=1; break;
+         case 'k': set_cmd( &cmd, aKMode ); break;
 
          case 500: opt.batch = 1; greeting = 0; break;
          case 501: opt.answer_yes = 1; break;
          case 502: opt.answer_no = 1; break;
+         case 508: set_cmd( &cmd, aCheckKeys); break;
          case 509: add_keyring(pargs.r.ret_str); nrings++; break;
          case 510: opt.debug |= pargs.r.ret_ulong; break;
          case 511: opt.debug = ~0; break;
          case 512: set_status_fd( pargs.r.ret_int ); break;
+         case 515: opt.fingerprint = 1; break;
          case 517: add_secret_keyring(pargs.r.ret_str); sec_nrings++; break;
          case 518:
            /* config files may not be nested (silently ignore them) */
@@ -551,6 +559,9 @@ main( int argc, char **argv )
          case 543: break; /* no-options */
          case 544: opt.homedir = pargs.r.ret_str; break;
          case 545: opt.batch = 0; break;
+         case 549: opt.with_colons=':'; break;
+         case 551: set_cmd( &cmd, aListKeys); break;
+         case 552: set_cmd( &cmd, aListSigs); break;
          default : errors++; pargs.err = configfp? 1:2; break;
        }
     }
@@ -576,9 +587,12 @@ main( int argc, char **argv )
     /* Okay, we are now working under our real uid */
   #endif
 
-    write_status( STATUS_ENTER );
+    /*write_status( STATUS_ENTER );*/
 
     set_debug();
+    if( !cmd && opt.fingerprint )
+       set_cmd( &cmd, aListKeys);
+
     if( cmd == aKMode || cmd == aKModeC ) { /* kludge to be compatible to pgp */
        if( cmd == aKModeC ) {
            opt.fingerprint = 1;
@@ -593,6 +607,7 @@ main( int argc, char **argv )
        opt.verbose = opt.verbose > 1;
     }
 
+
     /* kludge to let -sat generate a clear text signature */
     if( opt.textmode && !detached_sig && opt.armor && cmd == aSign )
        cmd = aClearsign;
@@ -600,23 +615,24 @@ main( int argc, char **argv )
     if( opt.verbose > 1 )
        set_packet_list_mode(1);
 
-    if( cmd != aDeArmor && cmd != aEnArmor ) {
+    /* add the keyrings, but not for some special commands and
+     * not in case of "-kvv userid keyring" */
+    if( cmd != aDeArmor && cmd != aEnArmor
+       && !(cmd == aKMode && argc == 2 ) ) {
        if( !sec_nrings || default_keyring )  /* add default secret rings */
            add_secret_keyring("secring.gpg");
        if( !nrings || default_keyring )  /* add default ring */
            add_keyring("pubring.gpg");
     }
 
-    if( argc ) {
-       fname_print = fname = *argv;
-    }
+    if( argc )
+       fname = *argv;
     else {
-       fname_print = "[stdin]";
        fname = NULL;
        if( get_passphrase_fd() == 0 ) {
            /* reading data and passphrase form stdin:
             * we assume the first line is the passphrase, so
-            * we read it now
+            * we better should read it now.
             */
            /* FIXME: doit */
        }
@@ -629,6 +645,10 @@ main( int argc, char **argv )
       case aDeArmor:
       case aEnArmor:
        break;
+      case aKMode:
+      case aListKeys:
+      case aCheckKeys:
+       break;
       case aListTrustDB: rc = init_trustdb( argc? 1:0, trustdb_name ); break;
       default: rc = init_trustdb(1, trustdb_name ); break;
     }
@@ -642,21 +662,22 @@ main( int argc, char **argv )
            wrong_args(_("--store [filename]"));
        if( (rc = encode_store(fname)) )
            log_error("%s: store failed: %s\n",
-                                   fname_print, g10_errstr(rc) );
+                                print_fname_stdin(fname), g10_errstr(rc) );
        break;
     #ifdef IS_G10
       case aSym: /* encrypt the given file only with the symmetric cipher */
        if( argc > 1 )
            wrong_args(_("--symmetric [filename]"));
        if( (rc = encode_symmetric(fname)) )
-           log_error("%s: symmetric encryption failed: %s\n", fname_print, g10_errstr(rc) );
+           log_error("%s: symmetric encryption failed: %s\n",
+                           print_fname_stdin(fname), g10_errstr(rc) );
        break;
 
       case aEncr: /* encrypt the given file */
        if( argc > 1 )
            wrong_args(_("--encrypt [filename]"));
        if( (rc = encode_crypt(fname,remusr)) )
-           log_error("%s: encryption failed: %s\n", fname_print, g10_errstr(rc) );
+           log_error("%s: encryption failed: %s\n", print_fname_stdin(fname), g10_errstr(rc) );
        break;
 
       case aSign: /* sign the given file */
@@ -688,7 +709,7 @@ main( int argc, char **argv )
        else
            sl = NULL;
        if( (rc = sign_file(sl, detached_sig, locusr, 1, remusr, NULL)) )
-           log_error("%s: sign+encrypt failed: %s\n", fname_print, g10_errstr(rc) );
+           log_error("%s: sign+encrypt failed: %s\n", print_fname_stdin(fname), g10_errstr(rc) );
        free_strlist(sl);
        break;
 
@@ -696,7 +717,19 @@ main( int argc, char **argv )
        if( argc > 1 )
            wrong_args(_("--clearsign [filename]"));
        if( (rc = clearsign_file(fname, locusr, NULL)) )
-           log_error("%s: clearsign failed: %s\n", fname_print, g10_errstr(rc) );
+           log_error("%s: clearsign failed: %s\n", print_fname_stdin(fname), g10_errstr(rc) );
+       break;
+
+      case aVerify:
+       if( (rc = verify_signatures( argc, argv ) ))
+           log_error("verify signatures failed: %s\n", g10_errstr(rc) );
+       break;
+
+      case aDecrypt:
+       if( argc > 1 )
+           wrong_args(_("--decrypt [filename]"));
+       if( (rc = decrypt_message( fname ) ))
+           log_error("decrypt_message failed: %s\n", g10_errstr(rc) );
        break;
 
 
@@ -705,7 +738,7 @@ main( int argc, char **argv )
            wrong_args(_("--sign-key username"));
        /* note: fname is the user id! */
        if( (rc = sign_key(fname, locusr)) )
-           log_error("%s: sign key failed: %s\n", fname_print, g10_errstr(rc) );
+           log_error("%s: sign key failed: %s\n", print_fname_stdin(fname), g10_errstr(rc) );
        break;
 
       case aEditSig: /* Edit a key signature */
@@ -713,7 +746,7 @@ main( int argc, char **argv )
            wrong_args(_("--edit-sig username"));
        /* note: fname is the user id! */
        if( (rc = edit_keysigs(fname)) )
-           log_error("%s: edit signature failed: %s\n", fname_print, g10_errstr(rc) );
+           log_error("%s: edit signature failed: %s\n", print_fname_stdin(fname), g10_errstr(rc) );
        break;
 
       case aDeleteSecretKey:
@@ -724,7 +757,7 @@ main( int argc, char **argv )
            wrong_args(_("--delete-key username"));
        /* note: fname is the user id! */
        if( (rc = delete_key(fname, cmd==aDeleteSecretKey)) )
-           log_error("%s: delete key failed: %s\n", fname_print, g10_errstr(rc) );
+           log_error("%s: delete key failed: %s\n", print_fname_stdin(fname), g10_errstr(rc) );
        break;
 
       case aChangePass: /* Change the passphrase */
@@ -732,51 +765,36 @@ main( int argc, char **argv )
            wrong_args(_("--change-passphrase [username]"));
        /* note: fname is the user id! */
        if( (rc = change_passphrase(fname)) )
-           log_error("%s: change passphrase failed: %s\n", fname_print,
+           log_error("%s: change passphrase failed: %s\n", print_fname_stdin(fname),
                                                       g10_errstr(rc) );
        break;
       #endif /* IS_G10 */
 
       case aCheckKeys:
+       opt.check_sigs = 1;
+      case aListSigs:
+       opt.list_sigs = 1;
+      case aListKeys:
+       std_key_list( argc, argv );
+       break;
+
       case aKMode: /* list keyring */
-       if( !argc ) { /* list the default public keyrings */
-           int i, seq=0;
-           const char *s;
-
-           while( (s=get_keyring(seq++)) ) {
-               if( !(a = iobuf_open(s)) ) {
-                   log_error(_("can't open '%s'\n"), s);
-                   continue;
-               }
-               if( seq > 1 )
-                   putchar('\n');
-               printf("%s\n", s );
-               for(i=strlen(s); i; i-- )
-                   putchar('-');
-               putchar('\n');
-
-               proc_packets( a );
-               iobuf_close(a);
+       if( argc < 2 )  /* -kv [userid] */
+           std_key_list( (argc && **argv)? 1:0, argv );
+       else if( argc == 2 ) { /* -kv userid keyring */
+           if( access( argv[1], R_OK ) ) {
+               log_error(_("can't open %s: %s\n"),
+                              print_fname_stdin(argv[1]), strerror(errno));
            }
-
-       }
-       else if( cmd == aCheckKeys ) {
-           log_error("will be soon: --check-keys user-ids\n");
-       }
-       else if( argc == 1) { /* list the given keyring */
-           if( !(a = iobuf_open(fname)) )
-               log_error(_("can't open '%s'\n"), fname_print);
            else {
-               if( !opt.no_armor ) {
-                   memset( &afx, 0, sizeof afx);
-                   iobuf_push_filter( a, armor_filter, &afx );
-               }
-               proc_packets( a );
-               iobuf_close(a);
+               /* add keyring (default keyrings are not registered in this
+                * special case */
+               add_keyring( argv[1] );
+               std_key_list( **argv?1:0, argv );
            }
        }
        else
-           wrong_args(_("-k[v][v][v][c] [keyring]") );
+           wrong_args(_("-k[v][v][v][c] [userid] [keyring]") );
        break;
 
     #ifdef IS_G10
@@ -901,13 +919,6 @@ main( int argc, char **argv )
        list_trust_path( atoi(*argv), argv[1] );
        break;
 
-      case aExtKeyList:
-       sl = NULL;
-       for( ; argc; argc--, argv++ )
-           add_to_strlist( &sl, *argv );
-       ext_key_list( sl );
-       free_strlist(sl);
-       break;
      #endif /* IS_G10MAINT */
 
 
@@ -921,7 +932,7 @@ main( int argc, char **argv )
        if( argc > 1 )
            wrong_args(_("[filename]"));
        if( !(a = iobuf_open(fname)) )
-           log_error(_("can't open '%s'\n"), fname_print);
+           log_error(_("can't open '%s'\n"), print_fname_stdin(fname));
        else {
            if( !opt.no_armor ) {
                if( use_armor_filter( a ) ) {
@@ -953,7 +964,7 @@ g10_exit( int rc )
        secmem_dump_stats();
     secmem_term();
     rc = rc? rc : log_get_errorcount(0)? 2:0;
-    write_status( STATUS_LEAVE );
+    /*write_status( STATUS_LEAVE );*/
     exit(rc );
 }
 
index b528ed7..300e33b 100644 (file)
@@ -168,6 +168,7 @@ cache_public_cert( PKT_public_cert *pkc )
     u32 keyid[2];
 
     if( pkc->pubkey_algo == PUBKEY_ALGO_ELGAMAL
+       || pkc->pubkey_algo == PUBKEY_ALGO_DSA
        || pkc->pubkey_algo == PUBKEY_ALGO_RSA ) {
        keyid_from_pkc( pkc, keyid );
     }
@@ -545,6 +546,7 @@ scan_keyring( PKT_public_cert *pkc, u32 *keyid,
        else if( keyid && pkt.pkttype == PKT_PUBLIC_CERT ) {
            switch( pkt.pkt.public_cert->pubkey_algo ) {
              case PUBKEY_ALGO_ELGAMAL:
+             case PUBKEY_ALGO_DSA:
              case PUBKEY_ALGO_RSA:
                keyid_from_pkc( pkt.pkt.public_cert, akeyid );
                if( (shortkeyid || akeyid[0] == keyid[0])
@@ -596,6 +598,7 @@ scan_keyring( PKT_public_cert *pkc, u32 *keyid,
                            pkt.pkt.user_id->len, pkt.pkt.user_id->name);
            else {
                if( last_pk->pubkey_algo == PUBKEY_ALGO_ELGAMAL
+                   || last_pk->pubkey_algo == PUBKEY_ALGO_DSA
                    || last_pk->pubkey_algo == PUBKEY_ALGO_RSA ) {
                     keyid_from_pkc( last_pk, akeyid );
                     cache_user_id( pkt.pkt.user_id, akeyid );
@@ -657,6 +660,7 @@ scan_secret_keyring( PKT_secret_cert *skc, u32 *keyid,
        else if( keyid && pkt.pkttype == PKT_SECRET_CERT ) {
            switch( pkt.pkt.secret_cert->pubkey_algo ) {
              case PUBKEY_ALGO_ELGAMAL:
+             case PUBKEY_ALGO_DSA:
              case PUBKEY_ALGO_RSA:
                if( get_first ) {
                    copy_secret_cert( skc, pkt.pkt.secret_cert );
@@ -712,6 +716,7 @@ scan_secret_keyring( PKT_secret_cert *skc, u32 *keyid,
                            pkt.pkt.user_id->len, pkt.pkt.user_id->name);
            else {
                if( last_pk->pubkey_algo == PUBKEY_ALGO_ELGAMAL
+                  || last_pk->pubkey_algo == PUBKEY_ALGO_DSA
                   || last_pk->pubkey_algo == PUBKEY_ALGO_RSA ) {
                    keyid_from_skc( last_pk, akeyid );
                    cache_user_id( pkt.pkt.user_id, akeyid );
index a99b479..3d5cd2a 100644 (file)
@@ -259,7 +259,7 @@ import_one( const char *fname, KBNODE keyblock )
                  (ulong)keyid[1], datestr_from_pkc(pkc) );
        if( uidnode )
            print_string( stderr, uidnode->pkt->pkt.user_id->name,
-                                 uidnode->pkt->pkt.user_id->len );
+                                 uidnode->pkt->pkt.user_id->len, 0 );
        putc('\n', stderr);
     }
     if( !uidnode ) {
@@ -532,7 +532,7 @@ delete_inv_parts( const char *fname, KBNODE keyblock, u32 *keyid )
                    log_info("%s: key %08lX, removed userid '",
                                                  fname, (ulong)keyid[1]);
                    print_string( stderr, node->pkt->pkt.user_id->name,
-                                     node->pkt->pkt.user_id->len );
+                                     node->pkt->pkt.user_id->len, 0 );
                    fputs("'\n", stderr );
                }
                delete_kbnode( node ); /* the user-id */
index 5a6d16a..11b0e46 100644 (file)
@@ -48,8 +48,8 @@ clone_kbnode( KBNODE node )
     KBNODE n = m_alloc( sizeof *n );
     n->next = NULL;
     n->pkt = node->pkt;
-    n->private_flag |= 2; /* mark cloned */
     n->flag = 0;
+    n->private_flag = node->private_flag | 2; /* mark cloned */
     return n;
 }
 
@@ -268,7 +268,7 @@ dump_kbnode( KBNODE node )
        if( node->pkt->pkttype == PKT_USER_ID ) {
            fputs("  \"", stderr);
            print_string( stderr, node->pkt->pkt.user_id->name,
-                                 node->pkt->pkt.user_id->len );
+                                 node->pkt->pkt.user_id->len, 0 );
            fputs("\"\n", stderr);
        }
        else if( node->pkt->pkttype == PKT_SIGNATURE ) {
index 8d3e58d..ef7b1ba 100644 (file)
@@ -105,6 +105,60 @@ v3_elg_fingerprint_md( PKT_public_cert *pkc )
     return md;
 }
 
+static MD_HANDLE
+dsa_fingerprint_md( PKT_public_cert *pkc )
+{
+    MD_HANDLE md;
+    byte *buf1, *buf2, *buf3, *buf4 ;
+    byte *p1, *p2, *p3, *p4;
+    unsigned n1, n2, n3, n4;
+    unsigned nb1, nb2, nb3, nb4;
+    unsigned n;
+
+    nb1 = mpi_get_nbits(pkc->d.dsa.p);
+    p1 = buf1 = mpi_get_buffer( pkc->d.dsa.p, &n1, NULL );
+    for( ; !*p1 && n1; p1++, n1-- )  /* skip leading null bytes */
+       ;
+    nb2 = mpi_get_nbits(pkc->d.dsa.q);
+    p2 = buf2 = mpi_get_buffer( pkc->d.dsa.q, &n2, NULL );
+    for( ; !*p2 && n2; p2++, n2-- )
+       ;
+    nb3 = mpi_get_nbits(pkc->d.dsa.g);
+    p3 = buf3 = mpi_get_buffer( pkc->d.dsa.g, &n3, NULL );
+    for( ; !*p3 && n3; p3++, n3-- )
+       ;
+    nb4 = mpi_get_nbits(pkc->d.dsa.y);
+    p4 = buf4 = mpi_get_buffer( pkc->d.dsa.y, &n4, NULL );
+    for( ; !*p4 && n4; p4++, n4-- )
+       ;
+
+    /* calculate length of packet */
+    n = 14 + n1 + n2 + n3 +n4 ;
+    md = md_open( DIGEST_ALGO_SHA1, 0);
+
+    md_putc( md, 0x99 );     /* ctb */
+    md_putc( md, n >> 8 );   /* 2 byte length header */
+    md_putc( md, n );
+    md_putc( md, 4 );       /* version */
+    {  u32 a = pkc->timestamp;
+       md_putc( md, a >> 24 );
+       md_putc( md, a >> 16 );
+       md_putc( md, a >>  8 );
+       md_putc( md, a       );
+    }
+    md_putc( md, pkc->pubkey_algo );
+    md_putc( md, nb1>>8); md_putc( md, nb1 ); md_write( md, p1, n1 );
+    md_putc( md, nb2>>8); md_putc( md, nb2 ); md_write( md, p2, n2 );
+    md_putc( md, nb3>>8); md_putc( md, nb3 ); md_write( md, p3, n3 );
+    md_putc( md, nb4>>8); md_putc( md, nb4 ); md_write( md, p4, n4 );
+    m_free(buf1);
+    m_free(buf2);
+    m_free(buf3);
+    m_free(buf4);
+    md_final( md );
+
+    return md;
+}
 
 static MD_HANDLE
 v3_elg_fingerprint_md_skc( PKT_secret_cert *skc )
@@ -121,6 +175,21 @@ v3_elg_fingerprint_md_skc( PKT_secret_cert *skc )
     return v3_elg_fingerprint_md( &pkc );
 }
 
+static MD_HANDLE
+dsa_fingerprint_md_skc( PKT_secret_cert *skc )
+{
+    PKT_public_cert pkc;
+
+    pkc.pubkey_algo = skc->pubkey_algo;
+    pkc.timestamp = skc->timestamp;
+    pkc.pubkey_algo = skc->pubkey_algo;
+    pkc.d.dsa.p = skc->d.dsa.p;
+    pkc.d.dsa.q = skc->d.dsa.q;
+    pkc.d.dsa.g = skc->d.dsa.g;
+    pkc.d.dsa.y = skc->d.dsa.y;
+    return dsa_fingerprint_md( &pkc );
+}
+
 
 /****************
  * Get the keyid from the secret key certificate and put it into keyid
@@ -145,6 +214,16 @@ keyid_from_skc( PKT_secret_cert *skc, u32 *keyid )
        lowbits = keyid[1];
        md_close(md);
     }
+    else if( skc->pubkey_algo == PUBKEY_ALGO_DSA ) {
+       const byte *dp;
+       MD_HANDLE md;
+       md = dsa_fingerprint_md_skc(skc);
+       dp = md_read( md, DIGEST_ALGO_SHA1 );
+       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] ;
+       lowbits = keyid[1];
+       md_close(md);
+    }
     else if( skc->pubkey_algo == PUBKEY_ALGO_RSA ) {
        lowbits = mpi_get_keyid( skc->d.rsa.rsa_n, keyid );
     }
@@ -178,6 +257,16 @@ keyid_from_pkc( PKT_public_cert *pkc, u32 *keyid )
        lowbits = keyid[1];
        md_close(md);
     }
+    else if( pkc->pubkey_algo == PUBKEY_ALGO_DSA ) {
+       const byte *dp;
+       MD_HANDLE md;
+       md = dsa_fingerprint_md(pkc);
+       dp = md_read( md, DIGEST_ALGO_SHA1 );
+       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] ;
+       lowbits = keyid[1];
+       md_close(md);
+    }
     else if( pkc->pubkey_algo == PUBKEY_ALGO_RSA ) {
        lowbits = mpi_get_keyid( pkc->d.rsa.rsa_n, keyid );
     }
@@ -208,6 +297,9 @@ nbits_from_pkc( PKT_public_cert *pkc )
     if( pkc->pubkey_algo == PUBKEY_ALGO_ELGAMAL ) {
        return mpi_get_nbits( pkc->d.elg.p );
     }
+    else if( pkc->pubkey_algo == PUBKEY_ALGO_DSA ) {
+       return mpi_get_nbits( pkc->d.dsa.p );
+    }
     else if( pkc->pubkey_algo == PUBKEY_ALGO_RSA ) {
        return mpi_get_nbits( pkc->d.rsa.rsa_n );
     }
@@ -224,6 +316,9 @@ nbits_from_skc( PKT_secret_cert *skc )
     if( skc->pubkey_algo == PUBKEY_ALGO_ELGAMAL ) {
        return mpi_get_nbits( skc->d.elg.p );
     }
+    else if( skc->pubkey_algo == PUBKEY_ALGO_DSA ) {
+       return mpi_get_nbits( skc->d.dsa.p );
+    }
     else if( skc->pubkey_algo == PUBKEY_ALGO_RSA ) {
        return mpi_get_nbits( skc->d.rsa.rsa_n );
     }
@@ -293,6 +388,15 @@ fingerprint_from_skc( PKT_secret_cert *skc, size_t *ret_len )
        pkc.d.elg.g = skc->d.elg.g;
        pkc.d.elg.y = skc->d.elg.y;
     }
+    else if( pkc.pubkey_algo == PUBKEY_ALGO_DSA ) {
+       pkc.timestamp = skc->timestamp;
+       pkc.valid_days = skc->valid_days;
+       pkc.pubkey_algo = skc->pubkey_algo;
+       pkc.d.dsa.p = skc->d.dsa.p;
+       pkc.d.dsa.q = skc->d.dsa.q;
+       pkc.d.dsa.g = skc->d.dsa.g;
+       pkc.d.dsa.y = skc->d.dsa.y;
+    }
     else if( pkc.pubkey_algo == PUBKEY_ALGO_RSA ) {
        pkc.d.rsa.rsa_n = skc->d.rsa.rsa_n;
        pkc.d.rsa.rsa_e = skc->d.rsa.rsa_e;
@@ -322,6 +426,15 @@ fingerprint_from_pkc( PKT_public_cert *pkc, size_t *ret_len )
        memcpy(array, dp, 20 );
        md_close(md);
     }
+    else if( pkc->pubkey_algo == PUBKEY_ALGO_DSA ) {
+       MD_HANDLE md;
+       md = dsa_fingerprint_md(pkc);
+       dp = md_read( md, DIGEST_ALGO_SHA1 );
+       array = m_alloc( 20 );
+       len = 20;
+       memcpy(array, dp, 20 );
+       md_close(md);
+    }
     else if( pkc->pubkey_algo == PUBKEY_ALGO_RSA ) {
        MD_HANDLE md;
 
index 15f3c2f..2557366 100644 (file)
 #include "memory.h"
 #include "util.h"
 #include "trustdb.h"
-#include "ttyio.h"
+#include "main.h"
 #include "i18n.h"
 
+static void list_all(void);
+static void list_one(const char *name);
+static void fingerprint( PKT_public_cert *pkc );
+
 
 /****************
- * List the keys in a special forma which is extensible and easy to parse
- * If NAMES is NULL; the complte keyring is listed
- *
+ * List the keys
+ * If NNAMES is 0; all available keys are listed
  */
 void
-ext_key_list( STRLIST names )
+std_key_list( int nnames, char **names )
 {
+    if( !nnames )
+       list_all();
+    else { /* List by user id */
+       for( ; nnames ; nnames--, names++ )
+           list_one( *names );
+    }
+}
+
+
+static void
+list_all()
+{
+    int i, seq=0;
+    const char *s;
+    IOBUF a;
+
+    while( (s=get_keyring(seq++)) ) {
+       if( !(a = iobuf_open(s)) ) {
+           log_error(_("can't open %s: %s\n"), s, strerror(errno));
+           continue;
+       }
+       if( seq > 1 )
+           putchar('\n');
+       printf("%s\n", s );
+       for(i=strlen(s); i; i-- )
+           putchar('-');
+       putchar('\n');
+
+       proc_packets( a );
+       iobuf_close(a);
+    }
+}
+
+
+static void
+list_one( const char *name )
+{
+    int rc = 0;
+    KBNODE keyblock = NULL;
+    KBNODE kbctx;
+    KBNODE node;
+    KBPOS kbpos;
+    PKT_public_cert *pkc;
+    u32 keyid[2];
+    int any=0;
+
+    /* search the userid */
+    rc = find_keyblock_byname( &kbpos, name );
+    if( rc ) {
+       log_error("%s: user not found\n", name );
+       goto leave;
+    }
+
+    /* read the keyblock */
+    rc = read_keyblock( &kbpos, &keyblock );
+    if( rc ) {
+       log_error("%s: keyblock read problem: %s\n", name, g10_errstr(rc) );
+       goto leave;
+    }
+
+    /* get the keyid from the keyblock */
+    node = find_kbnode( keyblock, PKT_PUBLIC_CERT );
+    if( !node ) {
+       log_error("Oops; public key not found anymore!\n");
+       goto leave;
+    }
+
+    pkc = node->pkt->pkt.public_cert;
+    keyid_from_pkc( pkc, keyid );
+    if( opt.with_colons )
+       printf("pub::%u:%d:%08lX%08lX:%s:::",
+               /* fixme: add trust value here */
+               nbits_from_pkc( pkc ),
+               pkc->pubkey_algo,
+               (ulong)keyid[0],(ulong)keyid[1],
+               datestr_from_pkc( pkc )
+               /* fixme: add LID and ownertrust here */
+                                       );
+    else
+       printf("pub  %4u%c/%08lX %s ", nbits_from_pkc( pkc ),
+                                  pubkey_letter( pkc->pubkey_algo ),
+                                  (ulong)keyid[1],
+                                  datestr_from_pkc( pkc ) );
+
+    for( kbctx=NULL; (node=walk_kbnode( keyblock, &kbctx, 0)) ; ) {
+       if( node->pkt->pkttype == PKT_USER_ID ) {
+           if( any ) {
+               if( opt.with_colons )
+                   printf("uid::::::::");
+               else
+                   printf("uid%*s", 28, "");
+           }
+           print_string( stdout,  node->pkt->pkt.user_id->name,
+                         node->pkt->pkt.user_id->len, opt.with_colons );
+           if( opt.with_colons )
+               putchar(':');
+           putchar('\n');
+           if( !any ) {
+               if( opt.fingerprint )
+                   fingerprint( pkc );
+               any = 1;
+           }
+       }
+       else if( opt.list_sigs && node->pkt->pkttype == PKT_SIGNATURE ) {
+           PKT_signature *sig = node->pkt->pkt.signature;
+           int sigrc;
+
+           if( !any ) { /* no user id, (maybe a revocation follows)*/
+               if( sig->sig_class == 0x20 )
+                   puts("[revoked]");
+               else
+                   putchar('\n');
+               if( opt.fingerprint )
+                   fingerprint( pkc );
+               any=1;
+           }
+
+           if( sig->sig_class == 0x20 || sig->sig_class == 0x30 )
+               fputs("rev", stdout);
+           else if( (sig->sig_class&~3) == 0x10 )
+               fputs("sig", stdout);
+           else {
+               if( opt.with_colons )
+                   printf("sig:::::::::%02x:\n",sig->sig_class );
+               else
+                   printf("sig                              "
+                      "[unexpected signature class 0x%02x]\n",sig->sig_class );
+               continue;
+           }
+           if( opt.check_sigs ) {
+               fflush(stdout);
+               rc = check_key_signature( keyblock, node, NULL );
+               switch( rc ) {
+                 case 0:                  sigrc = '!'; break;
+                 case G10ERR_BAD_SIGN:    sigrc = '-'; break;
+                 case G10ERR_NO_PUBKEY:   sigrc = '?'; break;
+                 default:                 sigrc = '%'; break;
+               }
+           }
+           else {
+               rc = 0;
+               sigrc = ' ';
+           }
+           if( opt.with_colons ) {
+               putchar(':');
+               if( sigrc != ' ' )
+                   putchar(sigrc);
+               printf(":::%08lX%08lX:%s:::", (ulong)sig->keyid[0],
+                          (ulong)sig->keyid[1], datestr_from_sig(sig));
+           }
+           else
+               printf("%c       %08lX %s  ",
+                   sigrc, (ulong)sig->keyid[1], datestr_from_sig(sig));
+           if( sigrc == '%' )
+               printf("[%s] ", g10_errstr(rc) );
+           else if( sigrc == '?' )
+               ;
+           else {
+               size_t n;
+               char *p = get_user_id( sig->keyid, &n );
+               print_string( stdout, p, n, opt.with_colons );
+               m_free(p);
+           }
+           if( opt.with_colons )
+               printf(":%02x:", sig->sig_class );
+           putchar('\n');
+       }
+    }
+    if( !any ) {/* oops, no user id */
+       if( opt.with_colons )
+           putchar(':');
+       putchar('\n');
+    }
+
+
+  leave:
+    release_kbnode( keyblock );
+}
+
+static void
+fingerprint( PKT_public_cert *pkc )
+{
+    byte *array, *p;
+    size_t i, n;
+
+    p = array = fingerprint_from_pkc( pkc, &n );
+    if( opt.with_colons ) {
+       printf("fpr::::::::");
+       for(i=0; i < n ; i++, p++ )
+           printf("%02X", *p );
+       putchar(':');
+    }
+    else {
+       printf("     Key fingerprint =");
+       if( n == 20 ) {
+           for(i=0; i < n ; i++, i++, p += 2 ) {
+               if( i == 10 )
+                   putchar(' ');
+               printf(" %02X%02X", *p, p[1] );
+           }
+       }
+       else {
+           for(i=0; i < n ; i++, p++ ) {
+               if( i && !(i%8) )
+                   putchar(' ');
+               printf(" %02X", *p );
+           }
+       }
+    }
+    putchar('\n');
+    m_free(array);
 }
 
index eef3d73..5078e80 100644 (file)
@@ -81,6 +81,10 @@ void g10_elg_encrypt( PKT_public_cert *pkc, PKT_pubkey_enc *enc, DEK *dek );
 void g10_elg_sign( PKT_secret_cert *skc, PKT_signature *sig,
                                         MD_HANDLE md, int digest_algo );
 
+/*-- dsa.c --*/
+void g10_dsa_sign( PKT_secret_cert *skc, PKT_signature *sig,
+                                        MD_HANDLE md, int digest_algo );
+
 /*-- rsa.c --*/
 void g10_rsa_encrypt( PKT_public_cert *pkc, PKT_pubkey_enc *enc, DEK *dek );
 void g10_rsa_sign( PKT_secret_cert *skc, PKT_signature *sig,
@@ -98,6 +102,15 @@ int enarmor_file( const char *fname );
 int gen_revoke( const char *uname );
 
 /*-- keylist.c --*/
-void ext_key_list( STRLIST names );
+void std_key_list( int nnames, char **names );
+
+/*-- verify.c --*/
+int verify_signatures( int nfiles, char **files );
+
+/*-- decrypt.c --*/
+int decrypt_message( const char *filename );
+
+/*-- plaintext.c --*/
+int hash_datafiles( MD_HANDLE md, STRLIST files, int textmode );
 
 #endif /*G10_MAIN_H*/
index 153496f..3ca23cc 100644 (file)
@@ -21,6 +21,7 @@
 #include <config.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include <string.h>
 #include <assert.h>
 
 #include "packet.h"
@@ -45,6 +46,9 @@ typedef struct {
     PKT_secret_cert *last_seckey;
     PKT_user_id     *last_user_id;
     md_filter_context_t mfx;
+    int sigs_only;   /* process only signatures and reject all other stuff */
+    int encrypt_only; /* process onyl encrytion messages */
+    STRLIST signed_data;
     DEK *dek;
     int last_was_pubkey_enc;
     KBNODE list;   /* the current list of packets */
@@ -53,6 +57,7 @@ typedef struct {
 } *CTX;
 
 
+static int do_proc_packets( CTX c, IOBUF a );
 
 static void list_node( CTX c, KBNODE node );
 static void proc_tree( CTX c, KBNODE node );
@@ -155,6 +160,7 @@ proc_pubkey_enc( CTX c, PACKET *pkt )
     enc = pkt->pkt.pubkey_enc;
     /*printf("enc: encrypted by a pubkey with keyid %08lX\n", enc->keyid[1] );*/
     if( enc->pubkey_algo == PUBKEY_ALGO_ELGAMAL
+       || enc->pubkey_algo == PUBKEY_ALGO_DSA
        || enc->pubkey_algo == PUBKEY_ALGO_RSA  ) {
        m_free(c->dek ); /* paranoid: delete a pending DEK */
        c->dek = m_alloc_secure( sizeof *c->dek );
@@ -234,6 +240,18 @@ proc_plaintext( CTX c, PACKET *pkt )
 }
 
 
+static int
+proc_compressed_cb( IOBUF a, void *info )
+{
+    return proc_signature_packets( a, ((CTX)info)->signed_data );
+}
+
+static int
+proc_encrypt_cb( IOBUF a, void *info )
+{
+    return proc_encryption_packets( a );
+}
+
 static void
 proc_compressed( CTX c, PACKET *pkt )
 {
@@ -241,7 +259,12 @@ proc_compressed( CTX c, PACKET *pkt )
     int rc;
 
     /*printf("zip: compressed data packet\n");*/
-    rc = handle_compressed( zd );
+    if( c->sigs_only )
+       rc = handle_compressed( zd, proc_compressed_cb, c );
+    else if( c->encrypt_only )
+       rc = handle_compressed( zd, proc_encrypt_cb, c );
+    else
+       rc = handle_compressed( zd, NULL, NULL );
     if( rc )
        log_error("uncompressing failed: %s\n", g10_errstr(rc));
     free_packet(pkt);
@@ -337,7 +360,8 @@ print_userid( PACKET *pkt )
        printf("ERROR: unexpected packet type %d", pkt->pkttype );
        return;
     }
-    print_string( stdout,  pkt->pkt.user_id->name, pkt->pkt.user_id->len );
+    print_string( stdout,  pkt->pkt.user_id->name, pkt->pkt.user_id->len,
+                                                       opt.with_colons );
 }
 
 
@@ -349,19 +373,27 @@ print_fingerprint( PKT_public_cert *pkc, PKT_secret_cert *skc )
 
     p = array = skc? fingerprint_from_skc( skc, &n )
                   : fingerprint_from_pkc( pkc, &n );
-    printf("     Key fingerprint =");
-    if( n == 20 ) {
-       for(i=0; i < n ; i++, i++, p += 2 ) {
-           if( i == 10 )
-               putchar(' ');
-           printf(" %02X%02X", *p, p[1] );
-       }
+    if( opt.with_colons ) {
+       printf("fpr::::::::");
+       for(i=0; i < n ; i++, p++ )
+           printf("%02X", *p );
+       putchar(':');
     }
     else {
-       for(i=0; i < n ; i++, p++ ) {
-           if( i && !(i%8) )
-               putchar(' ');
-           printf(" %02X", *p );
+       printf("     Key fingerprint =");
+       if( n == 20 ) {
+           for(i=0; i < n ; i++, i++, p += 2 ) {
+               if( i == 10 )
+                   putchar(' ');
+               printf(" %02X%02X", *p, p[1] );
+           }
+       }
+       else {
+           for(i=0; i < n ; i++, p++ ) {
+               if( i && !(i%8) )
+                   putchar(' ');
+               printf(" %02X", *p );
+           }
        }
     }
     putchar('\n');
@@ -383,24 +415,47 @@ list_node( CTX c, KBNODE node )
     else if( node->pkt->pkttype == PKT_PUBLIC_CERT ) {
        PKT_public_cert *pkc = node->pkt->pkt.public_cert;
 
-       printf("pub  %4u%c/%08lX %s ", nbits_from_pkc( pkc ),
+       if( opt.with_colons ) {
+           u32 keyid[2];
+           keyid_from_pkc( pkc, keyid );
+           printf("pub::%u:%d:%08lX%08lX:%s:::",
+                   /* fixme: add trust value here */
+                   nbits_from_pkc( pkc ),
+                   pkc->pubkey_algo,
+                   (ulong)keyid[0],(ulong)keyid[1],
+                   datestr_from_pkc( pkc )
+                   /* fixme: add LID and ownertrust here */
+                                           );
+       }
+       else
+           printf("pub  %4u%c/%08lX %s ", nbits_from_pkc( pkc ),
                                      pubkey_letter( pkc->pubkey_algo ),
                                      (ulong)keyid_from_pkc( pkc, NULL ),
                                      datestr_from_pkc( pkc )     );
        /* and now list all userids with their signatures */
        for( node = node->next; node; node = node->next ) {
            if( any != 2 && node->pkt->pkttype == PKT_SIGNATURE ) {
-               if( !any )
-                   putchar('\n');
+               if( !any ) {
+                   if( node->pkt->pkt.signature->sig_class == 0x20 )
+                       puts("[revoked]");
+                   else
+                       putchar('\n');
+               }
                list_node(c,  node );
                any = 1;
            }
            else if( node->pkt->pkttype == PKT_USER_ID ) {
                KBNODE n;
 
-               if( any )
-                   printf( "%*s", 31, "" );
+               if( any ) {
+                   if( opt.with_colons )
+                       printf("uid::::::::");
+                   else
+                       printf( "uid%*s", 28, "" );
+               }
                print_userid( node->pkt );
+               if( opt.with_colons )
+                   putchar(':');
                putchar('\n');
                if( opt.fingerprint && !any )
                    print_fingerprint( pkc, NULL );
@@ -457,17 +512,27 @@ list_node( CTX c, KBNODE node )
              default:                 sigrc = '%'; break;
            }
        }
-       printf("%c       %08lX %s   ",
-               sigrc, (ulong)sig->keyid[1], datestr_from_sig(sig));
+       if( opt.with_colons ) {
+           putchar(':');
+           if( sigrc != ' ' )
+               putchar(sigrc);
+           printf(":::%08lX%08lX:%s:::", (ulong)sig->keyid[0],
+                      (ulong)sig->keyid[1], datestr_from_sig(sig));
+       }
+       else
+           printf("%c       %08lX %s   ",
+                   sigrc, (ulong)sig->keyid[1], datestr_from_sig(sig));
        if( sigrc == '%' )
            printf("[%s] ", g10_errstr(rc2) );
        else if( sigrc == '?' )
            ;
        else {
            p = get_user_id( sig->keyid, &n );
-           print_string( stdout, p, n );
+           print_string( stdout, p, n, opt.with_colons );
            m_free(p);
        }
+       if( opt.with_colons )
+           printf(":%02x:", sig->sig_class );
        putchar('\n');
     }
     else
@@ -479,8 +544,40 @@ int
 proc_packets( IOBUF a )
 {
     CTX c = m_alloc_clear( sizeof *c );
-    PACKET *pkt = m_alloc( sizeof *pkt );
+    int rc = do_proc_packets( c, a );
+    m_free( c );
+    return rc;
+}
+
+int
+proc_signature_packets( IOBUF a, STRLIST signedfiles )
+{
+    CTX c = m_alloc_clear( sizeof *c );
     int rc;
+    c->sigs_only = 1;
+    c->signed_data = signedfiles;
+    rc = do_proc_packets( c, a );
+    m_free( c );
+    return rc;
+}
+
+int
+proc_encryption_packets( IOBUF a )
+{
+    CTX c = m_alloc_clear( sizeof *c );
+    int rc;
+    c->encrypt_only = 1;
+    rc = do_proc_packets( c, a );
+    m_free( c );
+    return rc;
+}
+
+
+int
+do_proc_packets( CTX c, IOBUF a )
+{
+    PACKET *pkt = m_alloc( sizeof *pkt );
+    int rc=0;
     int newpkt;
 
     c->iobuf = a;
@@ -507,6 +604,38 @@ proc_packets( IOBUF a )
              default: newpkt = 0; break;
            }
        }
+       else if( c->sigs_only ) {
+           switch( pkt->pkttype ) {
+             case PKT_PUBLIC_CERT:
+             case PKT_SECRET_CERT:
+             case PKT_USER_ID:
+             case PKT_PUBKEY_ENC:
+             case PKT_ENCRYPTED:
+               rc = G10ERR_UNEXPECTED;
+               goto leave;
+             case PKT_SIGNATURE:   newpkt = add_signature( c, pkt ); break;
+             case PKT_PLAINTEXT:   proc_plaintext( c, pkt ); break;
+             case PKT_COMPRESSED:  proc_compressed( c, pkt ); break;
+             case PKT_ONEPASS_SIG: newpkt = add_onepass_sig( c, pkt ); break;
+             default: newpkt = 0; break;
+           }
+       }
+       else if( c->encrypt_only ) {
+           switch( pkt->pkttype ) {
+             case PKT_PUBLIC_CERT:
+             case PKT_SECRET_CERT:
+             case PKT_USER_ID:
+               rc = G10ERR_UNEXPECTED;
+               goto leave;
+             case PKT_SIGNATURE:   newpkt = add_signature( c, pkt ); break;
+             case PKT_PUBKEY_ENC:  proc_pubkey_enc( c, pkt ); break;
+             case PKT_ENCRYPTED:   proc_encrypted( c, pkt ); break;
+             case PKT_PLAINTEXT:   proc_plaintext( c, pkt ); break;
+             case PKT_COMPRESSED:  proc_compressed( c, pkt ); break;
+             case PKT_ONEPASS_SIG: newpkt = add_onepass_sig( c, pkt ); break;
+             default: newpkt = 0; break;
+           }
+       }
        else {
            switch( pkt->pkttype ) {
              case PKT_PUBLIC_CERT: newpkt = add_public_cert( c, pkt ); break;
@@ -533,14 +662,15 @@ proc_packets( IOBUF a )
        else
            free_packet(pkt);
     }
+    rc = 0;
 
+  leave:
     release_list( c );
     m_free(c->dek);
     free_packet( pkt );
     m_free( pkt );
     free_md_filter_context( &c->mfx );
-    m_free( c );
-    return 0;
+    return rc;
 }
 
 
@@ -549,7 +679,7 @@ print_keyid( FILE *fp, u32 *keyid )
 {
     size_t n;
     char *p = get_user_id( keyid, &n );
-    print_string( fp, p, n );
+    print_string( fp, p, n, opt.with_colons );
     m_free(p);
 }
 
@@ -562,15 +692,18 @@ check_sig_and_print( CTX c, KBNODE node )
     int rc;
 
     rc = do_check_sig(c, node );
-    if( !rc ) {
-       write_status( STATUS_GOODSIG );
-       log_info("Good signature from ");
-       print_keyid( stderr, sig->keyid );
-       putc('\n', stderr);
-    }
-    else if( rc == G10ERR_BAD_SIGN ) {
-       write_status( STATUS_BADSIG );
-       log_error("BAD signature from ");
+    if( !rc || rc == G10ERR_BAD_SIGN ) {
+       char *p, *buf;
+
+       p = get_user_id_string( sig->keyid );
+       buf = m_alloc( 20 + strlen(p) );
+       sprintf(buf, "%lu %s", (ulong)sig->timestamp, p );
+       m_free(p);
+       if( (p=strchr(buf,'\n')) )
+           *p = 0; /* just in case ... */
+       write_status_text( rc? STATUS_BADSIG : STATUS_GOODSIG, buf );
+       m_free(buf);
+       log_info("%s signature from ", rc? "BAD":"Good");
        print_keyid( stderr, sig->keyid );
        putc('\n', stderr);
        if( opt.batch )
@@ -607,12 +740,17 @@ proc_tree( CTX c, KBNODE node )
            free_md_filter_context( &c->mfx );
            /* prepare to create all requested message digests */
            c->mfx.md = md_open(0, 0);
+           /* fixme: why looking for the signature packet and not 1passpacket*/
            for( n1 = node; (n1 = find_next_kbnode(n1, PKT_SIGNATURE )); ) {
                md_enable( c->mfx.md,
                           digest_algo_from_sig(n1->pkt->pkt.signature));
            }
            /* ask for file and hash it */
-           rc = ask_for_detached_datafile( &c->mfx,
+           if( c->sigs_only )
+               rc = hash_datafiles( c->mfx.md, c->signed_data,
+                           n1->pkt->pkt.onepass_sig->sig_class == 0x01 );
+           else
+               rc = ask_for_detached_datafile( &c->mfx,
                                            iobuf_get_fname(c->iobuf));
            if( rc ) {
                log_error("can't hash datafile: %s\n", g10_errstr(rc));
@@ -629,7 +767,11 @@ proc_tree( CTX c, KBNODE node )
        if( !c->have_data ) {
            free_md_filter_context( &c->mfx );
            c->mfx.md = md_open(digest_algo_from_sig(sig), 0);
-           rc = ask_for_detached_datafile( &c->mfx,
+           if( c->sigs_only )
+               rc = hash_datafiles( c->mfx.md, c->signed_data,
+                                    sig->sig_class == 0x01 );
+           else
+               rc = ask_for_detached_datafile( &c->mfx,
                                            iobuf_get_fname(c->iobuf));
            if( rc ) {
                log_error("can't hash datafile: %s\n", g10_errstr(rc));
index 249e9c9..f51ee43 100644 (file)
@@ -42,6 +42,8 @@
 int
 overwrite_filep( const char *fname )
 {
+    if( !fname || (*fname == '-' && !fname[1]) )
+       return 0; /* stdout */
     if( !access( fname, F_OK ) ) {
        char *p;
        int okay;
@@ -55,7 +57,6 @@ overwrite_filep( const char *fname )
            okay = 0;
 
        while( !okay ) {
-       if( !okay )
            if( first ) {
                tty_printf("File '%s' exists. ", fname);
                first = 0;
@@ -91,7 +92,7 @@ open_outfile( const char *iname, int mode )
     IOBUF a = NULL;
     int rc;
 
-    if( !iname && !opt.outfile ) {
+    if( (!iname || (*iname=='-' && !iname[1])) && !opt.outfile ) {
        if( !(a = iobuf_create(NULL)) )
            log_error("can't open [stdout]: %s\n", strerror(errno) );
        else if( opt.verbose )
@@ -133,7 +134,7 @@ open_sigfile( const char *iname )
     IOBUF a = NULL;
     size_t len;
 
-    if( iname ) {
+    if( iname && !(*iname == '-' && !iname[1]) ) {
        len = strlen(iname);
        if( len > 4 && ( !strcmp(iname + len - 4, ".sig")
                        || !strcmp(iname + len - 4, ".asc")) ) {
index 0ac0418..0f2a278 100644 (file)
@@ -31,7 +31,7 @@ struct {
     int answer_yes; /* answer yes on most questions */
     int answer_no;  /* answer no on most questions */
     int check_sigs; /* check key signatures */
-    int reserved1;
+    int with_colons;
     int fingerprint; /* list fingerprints */
     int list_sigs;   /* list signatures */
     int no_armor;
index 2013136..53448bd 100644 (file)
@@ -75,18 +75,22 @@ typedef struct {
     u32     keyid[2];      /* 64 bit keyid */
     ulong   local_id;      /* internal use, valid if > 0 */
     u32     timestamp;     /* signature made */
+    byte    version;
     byte    sig_class;     /* sig classification, append for MD calculation*/
     byte    pubkey_algo;    /* algorithm used for public key scheme */
                            /* (PUBKEY_ALGO_xxx) */
+    byte digest_algo;      /* algorithm used for digest (DIGEST_ALGO_xxxx) */
+    byte *hashed_data;     /* all subpackets with hashed  data (v4 only) */
+    byte *unhashed_data;    /* ditto for unhashed data */
+    byte digest_start[2];   /* first 2 bytes of the digest */
     union {
       struct {
-       byte digest_algo;     /* algorithm used for digest (DIGEST_ALGO_xxxx) */
-       byte digest_start[2]; /* first 2 byte of the digest */
        MPI  a, b;            /* integers with the digest */
       } elg;
       struct {
-       byte digest_algo;     /* algorithm used for digest (DIGEST_ALGO_xxxx) */
-       byte digest_start[2]; /* first 2 byte of the digest */
+       MPI  r, s;            /* integers with the digest */
+      } dsa;
+      struct {
        MPI  rsa_integer;     /* the encrypted digest */
       } rsa;
     } d;
@@ -107,6 +111,12 @@ typedef struct {
        MPI y;              /* g^x mod p */
       } elg;
       struct {
+       MPI p;              /* prime */
+       MPI q;              /* group order */
+       MPI g;              /* group generator */
+       MPI y;              /* g^x mod p */
+      } dsa;
+      struct {
        MPI rsa_n;          /* public modulus */
        MPI rsa_e;          /* public exponent */
       } rsa;
@@ -139,6 +149,25 @@ typedef struct {
                             * to plain storage */
       } elg;
       struct {
+       MPI p;              /* prime */
+       MPI q;              /* group order */
+       MPI g;              /* group generator */
+       MPI y;              /* g^x mod p */
+       MPI x;              /* secret exponent */
+       u16 csum;           /* checksum */
+       byte is_protected;  /* The above infos are protected and must */
+                           /* be decrypteded before use. */
+       struct {
+           byte algo;  /* cipher used to protect the secret informations*/
+           byte s2k;
+           byte hash;
+           byte salt[8];
+           byte count;
+           byte iv[8]; /* initialization vector for CFB mode */
+       } protect;          /* when protected, the MPIs above are pointers
+                            * to plain storage */
+      } dsa;
+      struct {
        MPI rsa_n;          /* public modulus */
        MPI rsa_e;          /* public exponent */
        MPI rsa_d;          /* secret descryption exponent */
@@ -215,6 +244,8 @@ struct packet_struct {
 
 /*-- mainproc.c --*/
 int proc_packets( IOBUF a );
+int proc_signature_packets( IOBUF a, STRLIST signedfiles );
+int proc_encryption_packets( IOBUF a );
 int list_packets( IOBUF a );
 
 /*-- parse-packet.c --*/
@@ -260,7 +291,8 @@ int protect_secret_key( PKT_secret_cert *cert, DEK *dek );
 int get_session_key( PKT_pubkey_enc *k, DEK *dek );
 
 /*-- compress.c --*/
-int handle_compressed( PKT_compressed *zd );
+int handle_compressed( PKT_compressed *cd,
+                      int (*callback)(IOBUF, void *), void *passthru );
 
 /*-- encr-data.c --*/
 int decrypt_data( PKT_encrypted *ed, DEK *dek );
index 498dd19..0cc2ece 100644 (file)
@@ -96,6 +96,17 @@ read_32(IOBUF inp)
     return a;
 }
 
+static unsigned long
+buffer_to_u32( const byte *buffer )
+{
+    unsigned long a;
+    a =  *buffer << 24;
+    a |= buffer[1] << 16;
+    a |= buffer[2] << 8;
+    a |= buffer[3];
+    return a;
+}
+
 int
 set_packet_list_mode( int mode )
 {
@@ -466,49 +477,210 @@ parse_publickey( IOBUF inp, int pkttype, unsigned long pktlen, PACKET *packet )
 }
 
 
+static const byte *
+parse_subpkt( const byte *buffer, int reqtype )
+{
+    int buflen = (*buffer << 8) | buffer[1];
+    int type;
+    int critical;
+    size_t n;
+
+    buffer += 2;
+    for(;;) {
+       if( !buflen )
+           return NULL; /* end of packets; not found */
+       n = *buffer++; buflen--;
+       if( n >= 192 ) {
+           if( buflen < 2 )
+               goto too_short;
+           n = (( n - 192 ) << 8) + *buffer + 192;
+           buflen--;
+       }
+       if( buflen < n )
+           goto too_short;
+       type = *buffer;
+       if( type & 0x80 ) {
+           type &= 0x7f;
+           critical = 1;
+       }
+       else
+           critical = 0;
+       if( reqtype < 0 ) { /* list packets */
+           printf("\t%ssubpacket %d of length %u (%s)\n",
+                   reqtype == -1 ? "hashed ":"", type, n,
+                   type == 2 ? "signature creation time"
+                 : type == 3 ? "signature expiration time"
+                 : type == 4 ? "exportable"
+                 : type == 5 ? "trust signature"
+                 : type == 6 ? "regular expression"
+                 : type == 7 ? "revocable"
+                 : type == 9 ? "key expiration time"
+                 : type ==10 ? "additional recipient request"
+                 : type ==11 ? "preferred symmetric algorithms"
+                 : type ==12 ? "revocation key"
+                 : type ==16 ? "issuer key ID"
+                 : type ==20 ? "notation data"
+                 : type ==21 ? "preferred hash algorithms"
+                 : type ==22 ? "preferred compression algorithms"
+                 : type ==23 ? "key server preferences"
+                 : type ==24 ? "preferred key server"
+                             : "?");
+       }
+       else if( type == reqtype )
+           break; /* found */
+       buffer += n; buflen -=n;
+    }
+    buffer++;
+    n--;
+    if( n > buflen )
+       goto too_short;
+    switch( type ) {
+      case 2: /* signature creation time */
+       if( n < 4 )
+           break;
+       return buffer;
+      case 16:/* issuer key ID */
+       if( n < 8 )
+           break;
+       return buffer;
+      case 3: /* signature expiration time */
+      case 4: /* exportable */
+      case 5: /* trust signature */
+      case 6: /* regular expression */
+      case 7: /* revocable */
+      case 9: /* key expiration time */
+      case 10:/* additional recipient request */
+      case 11:/* preferred symmetric algorithms */
+      case 12:/* revocation key */
+      case 20:/* notation data */
+      case 21:/* preferred hash algorithms */
+      case 22:/* preferred compression algorithms */
+      case 23:/* key server preferences */
+      case 24:/* preferred key server */
+      default: BUG(); /* not yet needed */
+    }
+    log_error("subpacket of type %d too short\n", type);
+    return NULL;
+
+  too_short:
+    log_error("buffer shorter than subpacket\n");
+    return NULL;
+}
+
+
 static int
 parse_signature( IOBUF inp, int pkttype, unsigned long pktlen,
                                          PKT_signature *sig )
 {
-    int version, md5_len;
+    int md5_len=0;
     unsigned n;
+    int is_v4=0;
+    int rc=0;
 
     if( pktlen < 16 ) {
        log_error("packet(%d) too short\n", pkttype);
        goto leave;
     }
-    version = iobuf_get_noeof(inp); pktlen--;
-    if( version != 2 && version != 3 ) {
-       log_error("packet(%d) with unknown version %d\n", pkttype, version);
+    sig->version = iobuf_get_noeof(inp); pktlen--;
+    if( sig->version == 4 )
+       is_v4=1;
+    else if( sig->version != 2 && sig->version != 3 ) {
+       log_error("packet(%d) with unknown version %d\n", pkttype, sig->version);
        goto leave;
     }
-    md5_len = iobuf_get_noeof(inp); pktlen--;
+
+    if( !is_v4 ) {
+       md5_len = iobuf_get_noeof(inp); pktlen--;
+    }
     sig->sig_class = iobuf_get_noeof(inp); pktlen--;
-    sig->timestamp = read_32(inp); pktlen -= 4;
-    sig->keyid[0] = read_32(inp); pktlen -= 4;
-    sig->keyid[1] = read_32(inp); pktlen -= 4;
+    if( !is_v4 ) {
+       sig->timestamp = read_32(inp); pktlen -= 4;
+       sig->keyid[0] = read_32(inp); pktlen -= 4;
+       sig->keyid[1] = read_32(inp); pktlen -= 4;
+    }
     sig->pubkey_algo = iobuf_get_noeof(inp); pktlen--;
-    if( list_mode )
+    sig->digest_algo = iobuf_get_noeof(inp); pktlen--;
+    if( is_v4 ) { /* read subpackets */
+       n = read_16(inp); pktlen -= 2; /* length of hashed data */
+       if( n > 10000 ) {
+           log_error("signature packet: hashed data too long\n");
+           rc = G10ERR_INVALID_PACKET;
+           goto leave;
+       }
+       if( n ) {
+           sig->hashed_data = m_alloc( n + 2 );
+           sig->hashed_data[0] = n << 8;
+           sig->hashed_data[1] = n;
+           if( iobuf_read(inp, sig->hashed_data+2, n ) != n ) {
+               log_error("premature eof while reading hashed signature data\n");
+               rc = -1;
+               goto leave;
+           }
+           pktlen -= n;
+       }
+       n = read_16(inp); pktlen -= 2; /* length of unhashed data */
+       if( n > 10000 ) {
+           log_error("signature packet: unhashed data too long\n");
+           rc = G10ERR_INVALID_PACKET;
+           goto leave;
+       }
+       if( n ) {
+           sig->unhashed_data = m_alloc( n + 2 );
+           sig->unhashed_data[0] = n << 8;
+           sig->unhashed_data[1] = n;
+           if( iobuf_read(inp, sig->unhashed_data+2, n ) != n ) {
+               log_error("premature eof while reading unhashed signature data\n");
+               rc = -1;
+               goto leave;
+           }
+           pktlen -= n;
+       }
+    }
+
+    if( pktlen < 5 ) { /* sanity check */
+       log_error("packet(%d) too short\n", pkttype);
+       rc = G10ERR_INVALID_PACKET;
+       goto leave;
+    }
+
+    sig->digest_start[0] = iobuf_get_noeof(inp); pktlen--;
+    sig->digest_start[1] = iobuf_get_noeof(inp); pktlen--;
+
+    if( is_v4 ) { /*extract required informations */
+       const byte *p;
+       p = parse_subpkt( sig->hashed_data, 2 );
+       if( !p )
+           log_error("signature packet without timestamp\n");
+       else
+           sig->timestamp = buffer_to_u32(p);
+       p = parse_subpkt( sig->unhashed_data, 16 );
+       if( !p )
+           log_error("signature packet without keyid\n");
+       else {
+           sig->keyid[0] = buffer_to_u32(p);
+           sig->keyid[1] = buffer_to_u32(p+4);
+       }
+    }
+
+    if( list_mode ) {
        printf(":signature packet: keyid %08lX%08lX\n"
-              "\tversion %d, created %lu, md5len %d, sigclass %02x\n",
+              "\tversion %d, created %lu, md5len %d, sigclass %02x\n"
+              "\tdigest algo %d, begin of digest %02x %02x\n",
                (ulong)sig->keyid[0], (ulong)sig->keyid[1],
-               version, (ulong)sig->timestamp, md5_len, sig->sig_class );
-    if( sig->pubkey_algo == PUBKEY_ALGO_ELGAMAL ) {
-       if( pktlen < 5 ) {
-           log_error("packet(%d) too short\n", pkttype);
-           goto leave;
+               sig->version, (ulong)sig->timestamp, md5_len, sig->sig_class,
+               sig->digest_algo,
+               sig->digest_start[0], sig->digest_start[1] );
+       if( is_v4 ) {
+           parse_subpkt( sig->hashed_data, -1 );
+           parse_subpkt( sig->unhashed_data, -2 );
        }
-       sig->d.elg.digest_algo = iobuf_get_noeof(inp); pktlen--;
-       sig->d.elg.digest_start[0] = iobuf_get_noeof(inp); pktlen--;
-       sig->d.elg.digest_start[1] = iobuf_get_noeof(inp); pktlen--;
+    }
+    if( sig->pubkey_algo == PUBKEY_ALGO_ELGAMAL ) {
        n = pktlen;
        sig->d.elg.a = mpi_read(inp, &n, 0 ); pktlen -=n;
        n = pktlen;
        sig->d.elg.b = mpi_read(inp, &n, 0 ); pktlen -=n;
        if( list_mode ) {
-           printf("\tdigest algo %d, begin of digest %02x %02x\n",
-                   sig->d.elg.digest_algo,
-                   sig->d.elg.digest_start[0], sig->d.elg.digest_start[1] );
            printf("\telg a: ");
            mpi_print(stdout, sig->d.elg.a, mpi_print_mode );
            printf("\n\telg b: ");
@@ -516,20 +688,23 @@ parse_signature( IOBUF inp, int pkttype, unsigned long pktlen,
            putchar('\n');
        }
     }
-    else if( sig->pubkey_algo == PUBKEY_ALGO_RSA ) {
-       if( pktlen < 5 ) {
-           log_error("packet(%d) too short\n", pkttype);
-           goto leave;
+    else if( sig->pubkey_algo == PUBKEY_ALGO_DSA ) {
+       n = pktlen;
+       sig->d.dsa.r = mpi_read(inp, &n, 0 ); pktlen -=n;
+       n = pktlen;
+       sig->d.dsa.s = mpi_read(inp, &n, 0 ); pktlen -=n;
+       if( list_mode ) {
+           printf("\tdsa r: ");
+           mpi_print(stdout, sig->d.elg.a, mpi_print_mode );
+           printf("\n\tdsa s: ");
+           mpi_print(stdout, sig->d.elg.b, mpi_print_mode );
+           putchar('\n');
        }
-       sig->d.rsa.digest_algo = iobuf_get_noeof(inp); pktlen--;
-       sig->d.rsa.digest_start[0] = iobuf_get_noeof(inp); pktlen--;
-       sig->d.rsa.digest_start[1] = iobuf_get_noeof(inp); pktlen--;
+    }
+    else if( sig->pubkey_algo == PUBKEY_ALGO_RSA ) {
        n = pktlen;
        sig->d.rsa.rsa_integer = mpi_read(inp, &n, 0 ); pktlen -=n;
        if( list_mode ) {
-           printf("\tdigest algo %d, begin of digest %02x %02x\n",
-                   sig->d.rsa.digest_algo,
-                   sig->d.rsa.digest_start[0], sig->d.rsa.digest_start[1] );
            printf("\trsa integer: ");
            mpi_print(stdout, sig->d.rsa.rsa_integer, mpi_print_mode );
            putchar('\n');
@@ -541,7 +716,7 @@ parse_signature( IOBUF inp, int pkttype, unsigned long pktlen,
 
   leave:
     skip_rest(inp, pktlen);
-    return 0;
+    return rc;
 }
 
 
@@ -761,6 +936,137 @@ parse_certificate( IOBUF inp, int pkttype, unsigned long pktlen,
            log_mpidump("elg x=", cert->d.elg.x ); */
        }
     }
+    else if( algorithm == PUBKEY_ALGO_DSA ) {
+       MPI dsa_p, dsa_q, dsa_g, dsa_y;
+       n = pktlen; dsa_p = mpi_read(inp, &n, 0 ); pktlen -=n;
+       n = pktlen; dsa_q = mpi_read(inp, &n, 0 ); pktlen -=n;
+       n = pktlen; dsa_g = mpi_read(inp, &n, 0 ); pktlen -=n;
+       n = pktlen; dsa_y = mpi_read(inp, &n, 0 ); pktlen -=n;
+       if( list_mode ) {
+           printf(  "\tdsa p: ");
+           mpi_print(stdout, dsa_p, mpi_print_mode  );
+           printf("\n\tdsa q: ");
+           mpi_print(stdout, dsa_q, mpi_print_mode  );
+           printf("\n\tdsa g: ");
+           mpi_print(stdout, dsa_g, mpi_print_mode  );
+           printf("\n\tdsa y: ");
+           mpi_print(stdout, dsa_y, mpi_print_mode  );
+           putchar('\n');
+       }
+       if( pkttype == PKT_PUBLIC_CERT ) {
+           pkt->pkt.public_cert->d.dsa.p = dsa_p;
+           pkt->pkt.public_cert->d.dsa.q = dsa_q;
+           pkt->pkt.public_cert->d.dsa.g = dsa_g;
+           pkt->pkt.public_cert->d.dsa.y = dsa_y;
+       }
+       else {
+           PKT_secret_cert *cert = pkt->pkt.secret_cert;
+           byte temp[8];
+
+           pkt->pkt.secret_cert->d.dsa.p = dsa_p;
+           pkt->pkt.secret_cert->d.dsa.q = dsa_q;
+           pkt->pkt.secret_cert->d.dsa.g = dsa_g;
+           pkt->pkt.secret_cert->d.dsa.y = dsa_y;
+           cert->d.dsa.protect.algo = iobuf_get_noeof(inp); pktlen--;
+           if( cert->d.dsa.protect.algo ) {
+               cert->d.dsa.is_protected = 1;
+               cert->d.dsa.protect.count = 0;
+               if( cert->d.dsa.protect.algo == 255 ) {
+                   if( pktlen < 3 ) {
+                       rc = G10ERR_INVALID_PACKET;
+                       goto leave;
+                   }
+                   cert->d.dsa.protect.algo = iobuf_get_noeof(inp); pktlen--;
+                   cert->d.dsa.protect.s2k  = iobuf_get_noeof(inp); pktlen--;
+                   cert->d.dsa.protect.hash = iobuf_get_noeof(inp); pktlen--;
+                   switch( cert->d.dsa.protect.s2k ) {
+                     case 1:
+                     case 3:
+                       for(i=0; i < 8 && pktlen; i++, pktlen-- )
+                           temp[i] = iobuf_get_noeof(inp);
+                       memcpy(cert->d.dsa.protect.salt, temp, 8 );
+                       break;
+                   }
+                   switch( cert->d.dsa.protect.s2k ) {
+                     case 0: if( list_mode ) printf(  "\tsimple S2K" );
+                       break;
+                     case 1: if( list_mode ) printf(  "\tsalted S2K" );
+                       break;
+                     case 3: if( list_mode ) printf(  "\titer+salt S2K" );
+                       break;
+                     default:
+                       if( list_mode )
+                           printf(  "\tunknown S2K %d\n",
+                                               cert->d.dsa.protect.s2k );
+                       rc = G10ERR_INVALID_PACKET;
+                       goto leave;
+                   }
+
+                   if( list_mode ) {
+                       printf(", algo: %d, hash: %d",
+                                        cert->d.dsa.protect.algo,
+                                        cert->d.dsa.protect.hash );
+                       if( cert->d.dsa.protect.s2k == 1
+                           || cert->d.dsa.protect.s2k == 3 ) {
+                           printf(", salt: ");
+                           for(i=0; i < 8; i++ )
+                               printf("%02x", cert->d.dsa.protect.salt[i]);
+                       }
+                       putchar('\n');
+                   }
+
+                   if( cert->d.dsa.protect.s2k == 3 ) {
+                       if( !pktlen ) {
+                           rc = G10ERR_INVALID_PACKET;
+                           goto leave;
+                       }
+                       cert->d.dsa.protect.count = iobuf_get_noeof(inp);
+                       pktlen--;
+                   }
+
+               }
+               else {
+                   if( list_mode )
+                       printf(  "\tprotect algo: %d\n",
+                                               cert->d.dsa.protect.algo);
+                   /* old version, we don't have a S2K, so we fake one */
+                   cert->d.dsa.protect.s2k = 0;
+                   cert->d.dsa.protect.hash = DIGEST_ALGO_MD5;
+               }
+               if( pktlen < 8 ) {
+                   rc = G10ERR_INVALID_PACKET;
+                   goto leave;
+               }
+               for(i=0; i < 8 && pktlen; i++, pktlen-- )
+                   temp[i] = iobuf_get_noeof(inp);
+               if( list_mode ) {
+                   printf(  "\tprotect IV: ");
+                   for(i=0; i < 8; i++ )
+                       printf(" %02x", temp[i] );
+                   putchar('\n');
+               }
+               memcpy(cert->d.dsa.protect.iv, temp, 8 );
+           }
+           else
+               cert->d.dsa.is_protected = 0;
+           /* It does not make sense to read it into secure memory.
+            * If the user is so careless, not to protect his secret key,
+            * we can assume, that he operates an open system :=(.
+            * So we put the key into secure memory when we unprotect him. */
+           n = pktlen; cert->d.dsa.x = mpi_read(inp, &n, 0 ); pktlen -=n;
+
+           cert->d.dsa.csum = read_16(inp); pktlen -= 2;
+           if( list_mode ) {
+               printf("\t[secret value x is not shown]\n"
+                      "\tchecksum: %04hx\n", cert->d.dsa.csum);
+           }
+         /*log_mpidump("dsa p=", cert->d.dsa.p );
+           log_mpidump("dsa q=", cert->d.dsa.q );
+           log_mpidump("dsa g=", cert->d.dsa.g );
+           log_mpidump("dsa y=", cert->d.dsa.y );
+           log_mpidump("dsa x=", cert->d.dsa.x ); */
+       }
+    }
     else if( algorithm == PUBKEY_ALGO_RSA ) {
        MPI rsa_pub_mod, rsa_pub_exp;
 
@@ -1023,3 +1329,4 @@ parse_encrypted( IOBUF inp, int pkttype, unsigned long pktlen, PACKET *pkt )
 }
 
 
+
index 284b684..e15a269 100644 (file)
@@ -30,6 +30,7 @@
 #include "ttyio.h"
 #include "filter.h"
 #include "main.h"
+#include "i18n.h"
 
 
 /****************
@@ -58,7 +59,8 @@ handle_plaintext( PKT_plaintext *pt, md_filter_context_t *mfx )
        fname[pt->namelen] = 0;
     }
 
-    if( !*fname ) { /* no filename given; write to stdout */
+    if( !*fname || (*fname=='-' && !fname[1])) {
+       /* no filename or "-" given; write to stdout */
        fp = stdout;
     }
     else if( overwrite_filep( fname ) )
@@ -181,3 +183,44 @@ ask_for_detached_datafile( md_filter_context_t *mfx, const char *inname )
 }
 
 
+/****************
+ * Hash the given files and append the hash to hash context md.
+ * If FILES is NULL, hash stdin.
+ */
+int
+hash_datafiles( MD_HANDLE md, STRLIST files, int textmode )
+{
+    IOBUF fp;
+    STRLIST sl=NULL;
+    text_filter_context_t tfx;
+    int c;
+
+    if( !files )
+       add_to_strlist( &sl, "-");
+    else
+       sl = files;
+
+    for( ; sl; sl = sl->next ) {
+       fp = iobuf_open( sl->d );
+       if( !fp ) {
+           log_error(_("can't open signed data '%s'\n"),
+                                               print_fname_stdin(sl->d));
+           if( !files )
+               free_strlist(sl);
+           return G10ERR_OPEN_FILE;
+       }
+       if( textmode ) {
+           memset( &tfx, 0, sizeof tfx);
+           iobuf_push_filter( fp, text_filter, &tfx );
+       }
+       while( (c = iobuf_get(fp)) != -1 )
+           md_putc(md, c );
+       iobuf_close(fp);
+    }
+
+    if( !files )
+       free_strlist(sl);
+    return 0;
+}
+
+
index ba71f0e..1ec35b8 100644 (file)
@@ -517,6 +517,13 @@ keyring_search( PACKET *req, KBPOS *kbpos, IOBUF iobuf, const char *fname )
                        && !mpi_cmp( req_skc->d.elg.y, skc->d.elg.y )
                        && !mpi_cmp( req_skc->d.elg.x, skc->d.elg.x )
                      )
+                  || ( skc->pubkey_algo == PUBKEY_ALGO_DSA
+                       && !mpi_cmp( req_skc->d.dsa.p, skc->d.dsa.p )
+                       && !mpi_cmp( req_skc->d.dsa.q, skc->d.dsa.q )
+                       && !mpi_cmp( req_skc->d.dsa.g, skc->d.dsa.g )
+                       && !mpi_cmp( req_skc->d.dsa.y, skc->d.dsa.y )
+                       && !mpi_cmp( req_skc->d.dsa.x, skc->d.dsa.x )
+                     )
                   || ( skc->pubkey_algo == PUBKEY_ALGO_RSA
                        && !mpi_cmp( req_skc->d.rsa.rsa_n, skc->d.rsa.rsa_n )
                        && !mpi_cmp( req_skc->d.rsa.rsa_e, skc->d.rsa.rsa_e )
@@ -537,6 +544,12 @@ keyring_search( PACKET *req, KBPOS *kbpos, IOBUF iobuf, const char *fname )
                        && !mpi_cmp( req_pkc->d.elg.g, pkc->d.elg.g )
                        && !mpi_cmp( req_pkc->d.elg.y, pkc->d.elg.y )
                      )
+                  || ( pkc->pubkey_algo == PUBKEY_ALGO_DSA
+                       && !mpi_cmp( req_pkc->d.dsa.p, pkc->d.dsa.p )
+                       && !mpi_cmp( req_pkc->d.dsa.q, pkc->d.dsa.q )
+                       && !mpi_cmp( req_pkc->d.dsa.g, pkc->d.dsa.g )
+                       && !mpi_cmp( req_pkc->d.dsa.y, pkc->d.dsa.y )
+                     )
                   || ( pkc->pubkey_algo == PUBKEY_ALGO_RSA
                        && !mpi_cmp( req_pkc->d.rsa.rsa_n, pkc->d.rsa.rsa_n )
                        && !mpi_cmp( req_pkc->d.rsa.rsa_e, pkc->d.rsa.rsa_e )
index 23df055..f1872b5 100644 (file)
--- a/g10/rsa.c
+++ b/g10/rsa.c
@@ -77,9 +77,9 @@ g10_rsa_sign( PKT_secret_cert *skc, PKT_signature *sig,
 
     dp = md_read( md, digest_algo );
     keyid_from_skc( skc, sig->keyid );
-    sig->d.rsa.digest_algo = digest_algo;
-    sig->d.rsa.digest_start[0] = dp[0];
-    sig->d.rsa.digest_start[1] = dp[1];
+    sig->digest_algo = digest_algo;
+    sig->digest_start[0] = dp[0];
+    sig->digest_start[1] = dp[1];
     sig->d.rsa.rsa_integer =
                   encode_md_value( md, mpi_get_nbits(skc->d.rsa.rsa_n));
     skey.e = skc->d.rsa.rsa_e;
index 85b0ed7..f126ba0 100644 (file)
@@ -141,6 +141,7 @@ check_elg( PKT_secret_cert *cert )
     return 0;
 }
 
+
 static int
 protect_elg( PKT_secret_cert *cert, DEK *dek )
 {
@@ -174,6 +175,126 @@ protect_elg( PKT_secret_cert *cert, DEK *dek )
     return 0;
 }
 
+static int
+check_dsa( PKT_secret_cert *cert )
+{
+    byte *buffer;
+    u16 csum=0;
+    int res;
+    unsigned nbytes;
+    u32 keyid[2];
+    DSA_secret_key skey;
+    char save_iv[8];
+
+    if( cert->d.dsa.is_protected ) { /* remove the protection */
+       DEK *dek = NULL;
+       MPI test_x;
+       BLOWFISH_context *blowfish_ctx=NULL;
+
+       switch( cert->d.dsa.protect.algo ) {
+         case CIPHER_ALGO_NONE: BUG(); break;
+         case CIPHER_ALGO_BLOWFISH:
+           keyid_from_skc( cert, keyid );
+           if( cert->d.dsa.protect.s2k == 1
+               || cert->d.dsa.protect.s2k == 3 )
+               dek = get_passphrase_hash( keyid, NULL,
+                                                cert->d.dsa.protect.salt );
+           else
+               dek = get_passphrase_hash( keyid, NULL, NULL );
+
+           blowfish_ctx = m_alloc_secure( sizeof *blowfish_ctx );
+           blowfish_setkey( blowfish_ctx, dek->key, dek->keylen );
+           m_free(dek); /* pw is in secure memory, so m_free() burns it */
+           blowfish_setiv( blowfish_ctx, NULL );
+           memcpy(save_iv, cert->d.dsa.protect.iv, 8 );
+           blowfish_decode_cfb( blowfish_ctx,
+                                cert->d.dsa.protect.iv,
+                                cert->d.dsa.protect.iv, 8 );
+           mpi_set_secure(cert->d.dsa.x );
+           /*fixme: maybe it is better to set the buffer secure with a
+            * new get_buffer_secure() function */
+           buffer = mpi_get_buffer( cert->d.dsa.x, &nbytes, NULL );
+           csum = checksum_u16( nbytes*8 );
+           blowfish_decode_cfb( blowfish_ctx, buffer, buffer, nbytes );
+           csum += checksum( buffer, nbytes );
+           test_x = mpi_alloc_secure( mpi_get_nlimbs(cert->d.dsa.x) );
+           mpi_set_buffer( test_x, buffer, nbytes, 0 );
+           m_free( buffer );
+           m_free( blowfish_ctx );
+           /* now let's see wether we have used the right passphrase */
+           if( csum != cert->d.dsa.csum ) {
+               mpi_free(test_x);
+               memcpy( cert->d.dsa.protect.iv, save_iv, 8 );
+               return G10ERR_BAD_PASS;
+           }
+
+           skey.p = cert->d.dsa.p;
+           skey.q = cert->d.dsa.q;
+           skey.g = cert->d.dsa.g;
+           skey.y = cert->d.dsa.y;
+           skey.x = test_x;
+           res = dsa_check_secret_key( &skey );
+           memset( &skey, 0, sizeof skey );
+           if( !res ) {
+               mpi_free(test_x);
+               memcpy( cert->d.dsa.protect.iv, save_iv, 8 );
+               return G10ERR_BAD_PASS;
+           }
+           mpi_set(cert->d.dsa.x, test_x);
+           mpi_free(test_x);
+           cert->d.dsa.is_protected = 0;
+           break;
+
+         default:
+           return G10ERR_CIPHER_ALGO; /* unsupport protection algorithm */
+       }
+    }
+    else { /* not protected */
+       buffer = mpi_get_buffer( cert->d.dsa.x, &nbytes, NULL );
+       csum = checksum_u16( nbytes*8 );
+       csum += checksum( buffer, nbytes );
+       m_free( buffer );
+       if( csum != cert->d.dsa.csum )
+           return G10ERR_CHECKSUM;
+    }
+
+    return 0;
+}
+
+
+static int
+protect_dsa( PKT_secret_cert *cert, DEK *dek )
+{
+    byte *buffer;
+    unsigned nbytes;
+
+    if( !cert->d.dsa.is_protected ) { /* add the protection */
+       BLOWFISH_context *blowfish_ctx=NULL;
+
+       switch( cert->d.dsa.protect.algo ) {
+         case CIPHER_ALGO_NONE: BUG(); break;
+         case CIPHER_ALGO_BLOWFISH:
+           blowfish_ctx = m_alloc_secure( sizeof *blowfish_ctx );
+           blowfish_setkey( blowfish_ctx, dek->key, dek->keylen );
+           blowfish_setiv( blowfish_ctx, NULL );
+           blowfish_encode_cfb( blowfish_ctx,
+                                cert->d.dsa.protect.iv,
+                                cert->d.dsa.protect.iv, 8 );
+           buffer = mpi_get_buffer( cert->d.dsa.x, &nbytes, NULL );
+           blowfish_encode_cfb( blowfish_ctx, buffer, buffer, nbytes );
+           mpi_set_buffer( cert->d.dsa.x, buffer, nbytes, 0 );
+           m_free( buffer );
+           m_free( blowfish_ctx );
+           cert->d.dsa.is_protected = 1;
+           break;
+
+         default:
+           return G10ERR_CIPHER_ALGO; /* unsupport protection algorithm */
+       }
+    }
+    return 0;
+}
+
 
 #ifdef HAVE_RSA_CIPHER
 static int
@@ -282,6 +403,8 @@ check_secret_key( PKT_secret_cert *cert )
            log_error("Invalid passphrase; please try again ...\n");
        if( cert->pubkey_algo == PUBKEY_ALGO_ELGAMAL )
            rc = check_elg( cert );
+       else if( cert->pubkey_algo == PUBKEY_ALGO_DSA )
+           rc = check_dsa( cert );
       #ifdef HAVE_RSA_CIPHER
        else if( cert->pubkey_algo == PUBKEY_ALGO_RSA )
            rc = check_rsa( cert );
@@ -303,6 +426,8 @@ is_secret_key_protected( PKT_secret_cert *cert )
 {
     if( cert->pubkey_algo == PUBKEY_ALGO_ELGAMAL )
        return cert->d.elg.is_protected? cert->d.elg.protect.algo : 0;
+    else if( cert->pubkey_algo == PUBKEY_ALGO_DSA )
+       return cert->d.dsa.is_protected? cert->d.dsa.protect.algo : 0;
   #ifdef HAVE_RSA_CIPHER
     else if( cert->pubkey_algo == PUBKEY_ALGO_RSA )
        return cert->d.rsa.is_protected? cert->d.rsa.protect_algo : 0;
@@ -323,6 +448,8 @@ protect_secret_key( PKT_secret_cert *cert, DEK *dek )
 
     if( cert->pubkey_algo == PUBKEY_ALGO_ELGAMAL )
        return protect_elg( cert, dek );
+    else if( cert->pubkey_algo == PUBKEY_ALGO_DSA )
+       return protect_dsa( cert, dek );
     else
        return G10ERR_PUBKEY_ALGO;
 }
index 32371b3..f25f2e1 100644 (file)
@@ -66,11 +66,11 @@ do_check( PKT_public_cert *pkc, PKT_signature *sig, MD_HANDLE digest )
     if( pkc->pubkey_algo == PUBKEY_ALGO_ELGAMAL ) {
        ELG_public_key pkey;
 
-       if( (rc=check_digest_algo(sig->d.elg.digest_algo)) )
+       if( (rc=check_digest_algo(sig->digest_algo)) )
            goto leave;
        /* make sure the digest algo is enabled (in case of a detached
         * signature */
-       md_enable( digest, sig->d.elg.digest_algo );
+       md_enable( digest, sig->digest_algo );
        /* complete the digest */
        md_putc( digest, sig->sig_class );
        {   u32 a = sig->timestamp;
@@ -87,6 +87,59 @@ do_check( PKT_public_cert *pkc, PKT_signature *sig, MD_HANDLE digest )
        if( !elg_verify( sig->d.elg.a, sig->d.elg.b, result, &pkey ) )
            rc = G10ERR_BAD_SIGN;
     }
+    else if( pkc->pubkey_algo == PUBKEY_ALGO_DSA ) {
+       DSA_public_key pkey;
+
+       if( (rc=check_digest_algo(sig->digest_algo)) )
+           goto leave;
+       /* make sure the digest algo is enabled (in case of a detached
+        * signature */
+       md_enable( digest, sig->digest_algo );
+
+       assert( sig->digest_algo == DIGEST_ALGO_SHA1 );
+
+       /* complete the digest */
+       if( sig->version >= 4 )
+           md_putc( digest, sig->version );
+       md_putc( digest, sig->sig_class );
+       if( sig->version < 4 ) {
+           u32 a = sig->timestamp;
+           md_putc( digest, (a >> 24) & 0xff );
+           md_putc( digest, (a >> 16) & 0xff );
+           md_putc( digest, (a >>  8) & 0xff );
+           md_putc( digest,  a        & 0xff );
+       }
+       else {
+           byte buf[6];
+           size_t n;
+           md_putc( digest, sig->pubkey_algo );
+           md_putc( digest, sig->digest_algo );
+           if( sig->hashed_data ) {
+               n = (sig->hashed_data[0] << 8) | sig->hashed_data[1];
+               md_write( digest, sig->hashed_data, n+2 );
+               n += 4;
+           }
+           else
+               n = 4;
+           /* add some magic */
+           buf[0] = sig->version;
+           buf[1] = 0xff;
+           buf[2] = n >> 24;
+           buf[3] = n >> 16;
+           buf[4] = n >>  8;
+           buf[5] = n;
+           md_write( digest, buf, 6 );
+       }
+       md_final( digest );
+       log_hexdump("digest is: ", md_read(digest, DIGEST_ALGO_SHA1), 20);
+       result = encode_md_value( digest, mpi_get_nbits(pkc->d.dsa.p));
+       pkey.p = pkc->d.dsa.p;
+       pkey.q = pkc->d.dsa.q;
+       pkey.g = pkc->d.dsa.g;
+       pkey.y = pkc->d.dsa.y;
+       if( !dsa_verify( sig->d.dsa.r, sig->d.dsa.s, result, &pkey ) )
+           rc = G10ERR_BAD_SIGN;
+    }
  #ifdef HAVE_RSA_CIPHER
     else if( pkc->pubkey_algo == PUBKEY_ALGO_RSA ) {
        int i, j, c, old_enc;
@@ -125,10 +178,10 @@ do_check( PKT_public_cert *pkc, PKT_signature *sig, MD_HANDLE digest )
            goto leave;
        }
 
-       if( (rc=check_digest_algo(sig->d.rsa.digest_algo)) )
+       if( (rc=check_digest_algo(sig->digest_algo)) )
            goto leave; /* unsupported algo */
-       md_enable( digest, sig->d.rsa.digest_algo );
-       asn = md_asn_oid( sig->d.rsa.digest_algo, &asnlen, &mdlen );
+       md_enable( digest, sig->digest_algo );
+       asn = md_asn_oid( sig->digest_algo, &asnlen, &mdlen );
 
        for(i=mdlen,j=asnlen-1; (c=mpi_getbyte(result, i)) != -1 && j >= 0;
                                                               i++, j-- )
@@ -142,7 +195,7 @@ do_check( PKT_public_cert *pkc, PKT_signature *sig, MD_HANDLE digest )
            if( c != 0xff  )
                break;
        i++;
-       if( c != sig->d.rsa.digest_algo || mpi_getbyte(result, i) ) {
+       if( c != sig->digest_algo || mpi_getbyte(result, i) ) {
            /* Padding or leading bytes in signature is wrong */
            rc = G10ERR_BAD_PUBKEY;
            goto leave;
@@ -163,7 +216,7 @@ do_check( PKT_public_cert *pkc, PKT_signature *sig, MD_HANDLE digest )
            md_putc( digest,  a        & 0xff );
        }
        md_final( digest );
-       dp = md_read( digest, sig->d.rsa.digest_algo );
+       dp = md_read( digest, sig->digest_algo );
        for(i=mdlen-1; i >= 0; i--, dp++ ) {
            if( mpi_getbyte( result, i ) != *dp ) {
                rc = G10ERR_BAD_SIGN;
@@ -188,7 +241,7 @@ do_check( PKT_public_cert *pkc, PKT_signature *sig, MD_HANDLE digest )
 
 /****************
  * check the signature pointed to by NODE. This is a key signatures.
- * If the function detects a elf signature, it uses the PKC from
+ * If the function detects a self-signature, it uses the PKC from
  * NODE and does not read the any public key.
  */
 int
@@ -210,9 +263,11 @@ check_key_signature( KBNODE root, KBNODE node, int *is_selfsig )
     sig = node->pkt->pkt.signature;
 
     if( sig->pubkey_algo == PUBKEY_ALGO_ELGAMAL )
-       algo = sig->d.elg.digest_algo;
+       algo = sig->digest_algo;
+    else if( sig->pubkey_algo == PUBKEY_ALGO_DSA )
+       algo = sig->digest_algo;
     else if(sig->pubkey_algo == PUBKEY_ALGO_RSA )
-       algo = sig->d.rsa.digest_algo;
+       algo = sig->digest_algo;
     else
        return G10ERR_PUBKEY_ALGO;
     if( (rc=check_digest_algo(algo)) )
@@ -233,7 +288,18 @@ check_key_signature( KBNODE root, KBNODE node, int *is_selfsig )
 
            keyid_from_pkc( pkc, keyid );
            md = md_open( algo, 0 );
+     if( sig->sig_class== 16 )
+        md->debug = fopen("dsahashsig","w");
            hash_public_cert( md, pkc );
+           if( sig->version >=4 ) {
+               byte buf[5];
+               buf[0] = 0xb4; /* indicates a userid packet */
+               buf[1] = uid->len >> 24;  /* but use 4 length bytes */
+               buf[2] = uid->len >> 16;
+               buf[3] = uid->len >>  8;
+               buf[4] = uid->len;
+               md_write( md, buf, 5 );
+           }
            md_write( md, uid->name, uid->len );
            if( keyid[0] == sig->keyid[0] && keyid[1] == sig->keyid[1] ) {
                if( is_selfsig )
@@ -243,6 +309,8 @@ check_key_signature( KBNODE root, KBNODE node, int *is_selfsig )
            else
                rc = signature_check( sig, md );
            md_close(md);
+     if( sig->sig_class== 16 )
+        fclose(md->debug);
        }
        else {
            log_error("no user id for key signature packet\n");
index 9d82088..4cf7b7b 100644 (file)
@@ -50,6 +50,8 @@ complete_sig( PKT_signature *sig, PKT_secret_cert *skc, MD_HANDLE md )
        ;
     else if( sig->pubkey_algo == PUBKEY_ALGO_ELGAMAL )
        g10_elg_sign( skc, sig, md, 0 );
+    else if( sig->pubkey_algo == PUBKEY_ALGO_DSA )
+       g10_dsa_sign( skc, sig, md, 0 );
     else if( sig->pubkey_algo == PUBKEY_ALGO_RSA )
        g10_rsa_sign( skc, sig, md, 0 );
     else
@@ -274,6 +276,8 @@ sign_file( STRLIST filenames, int detached, STRLIST locusr,
 
        if( sig->pubkey_algo == PUBKEY_ALGO_ELGAMAL )
            g10_elg_sign( skc, sig, md, DIGEST_ALGO_RMD160 );
+       else if( sig->pubkey_algo == PUBKEY_ALGO_DSA )
+           g10_dsa_sign( skc, sig, md, DIGEST_ALGO_SHA1 );
        else if( sig->pubkey_algo == PUBKEY_ALGO_RSA )
            g10_rsa_sign( skc, sig, md, DIGEST_ALGO_RMD160 );
        else
@@ -428,6 +432,8 @@ clearsign_file( const char *fname, STRLIST locusr, const char *outfile )
 
        if( sig->pubkey_algo == PUBKEY_ALGO_ELGAMAL )
            g10_elg_sign( skc, sig, md, DIGEST_ALGO_RMD160 );
+       else if( sig->pubkey_algo == PUBKEY_ALGO_DSA )
+           g10_dsa_sign( skc, sig, md, DIGEST_ALGO_SHA1 );
        else if( sig->pubkey_algo == PUBKEY_ALGO_RSA )
            g10_rsa_sign( skc, sig, md, DIGEST_ALGO_RMD160 );
        else
@@ -1066,6 +1072,7 @@ change_passphrase( const char *username )
                break;
            }
            else { /* okay */
+               /* FIXME: what about dsa */
                skc->d.elg.protect.algo = CIPHER_ALGO_BLOWFISH;
                skc->d.elg.protect.s2k  = 1;
                skc->d.elg.protect.hash = DIGEST_ALGO_RMD160;
index 05f902a..5aa712a 100644 (file)
@@ -37,6 +37,12 @@ set_status_fd( int newfd )
 void
 write_status( int no )
 {
+    write_status_text( no, NULL );
+}
+
+void
+write_status_text( int no, const char *text)
+{
     const char *s;
 
     if( fd == -1 )
@@ -53,7 +59,13 @@ write_status( int no )
       default: s = "?\n"; break;
     }
 
-    write( fd, s, strlen(s) );
-
+    if( text ) {
+       write( fd, s, strlen(s)-1 );
+       write( fd, " ", 1 );
+       write( fd, text, strlen(text) );
+       write( fd, "\n", 1 );
+    }
+    else
+       write( fd, s, strlen(s) );
 }
 
index a3d493b..4182082 100644 (file)
@@ -37,6 +37,7 @@
 /*-- status.c --*/
 void set_status_fd( int fd );
 void write_status( int no );
+void write_status_text( int no, const char *text);
 
 
 #endif /*G10_STATUS_H*/
index 8c9088b..257c372 100644 (file)
@@ -912,7 +912,7 @@ print_user_id( const char *text, u32 *keyid )
        putchar(' ');
     }
     putchar('\"');
-    print_string( stdout, p, n );
+    print_string( stdout, p, n, 0 );
     putchar('\"');
     putchar('\n');
     m_free(p);
@@ -1520,13 +1520,18 @@ init_trustdb( int level, const char *dbname )
                assert(p);
                *p = 0;
                if( access( fname, F_OK ) ) {
-                 #if __MINGW32__
-                   if( mkdir( fname ) )
-                 #else
-                   if( mkdir( fname, S_IRUSR|S_IWUSR|S_IXUSR ) )
-                 #endif
-                       log_fatal("can't create directory '%s': %s\n",
-                                   fname, strerror(errno) );
+                   if( strlen(fname) >= 7
+                       && !strcmp(fname+strlen(fname)-7, "/.gnupg" ) ) {
+                     #if __MINGW32__
+                       if( mkdir( fname ) )
+                     #else
+                       if( mkdir( fname, S_IRUSR|S_IWUSR|S_IXUSR ) )
+                     #endif
+                           log_fatal("can't create directory '%s': %s\n",
+                                       fname, strerror(errno) );
+                   }
+                   else
+                       log_fatal("directory '%s' does not exist!\n", fname );
                }
                *p = '/';
                create_db( fname );
@@ -1539,7 +1544,7 @@ init_trustdb( int level, const char *dbname )
            return 0;
 
        /* we can verify a signature about our local data (secring and trustdb)
-        * in ~/.g10/ here */
+        * in ~/.gnupg/ here */
        rc = verify_private_data();
        if( !rc ) {
            /* verify, that our own certificates are in the trustDB
diff --git a/g10/verify.c b/g10/verify.c
new file mode 100644 (file)
index 0000000..3398c2e
--- /dev/null
@@ -0,0 +1,87 @@
+/* verify.c - verify signed data
+ *     Copyright (C) 1998 Free Software Foundation, Inc.
+ *
+ * This file is part of GNUPG.
+ *
+ * GNUPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * GNUPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <assert.h>
+
+#include "options.h"
+#include "packet.h"
+#include "errors.h"
+#include "iobuf.h"
+#include "keydb.h"
+#include "memory.h"
+#include "util.h"
+#include "main.h"
+#include "filter.h"
+#include "ttyio.h"
+#include "i18n.h"
+
+
+
+/****************
+ * Assume that the input is a signature and verify it without
+ * generating any output.  With no arguments, the sigature packet
+ * is read from stdin (it may be a detached signature when not
+ * used in batch mode). If only a sigfile is given, is maybe a complete
+ * signature or a detached signature in which case the signed stuff
+ * is expected from stdin. With more than 1 argument, the first should
+ * be a detached signature and the remaining files are the signed stuff.
+ */
+
+int
+verify_signatures( int nfiles, char **files )
+{
+    IOBUF fp;
+    armor_filter_context_t afx;
+    const char *sigfile;
+    int i, rc;
+    STRLIST sl;
+
+    sigfile = nfiles? *files : NULL;
+
+    /* open the signature file */
+    fp = iobuf_open(sigfile);
+    if( !fp ) {
+       log_error(_("can't open '%s'\n"), print_fname_stdin(sigfile));
+       return G10ERR_OPEN_FILE;
+    }
+
+    if( !opt.no_armor ) {
+       if( use_armor_filter( fp ) ) {
+           memset( &afx, 0, sizeof afx);
+           iobuf_push_filter( fp, armor_filter, &afx );
+       }
+    }
+
+    sl = NULL;
+    for(i=1 ; i < nfiles; i++ )
+       add_to_strlist( &sl, files[i] );
+    rc = proc_signature_packets( fp, sl );
+    free_strlist(sl);
+    iobuf_close(fp);
+    return rc;
+}
+
+
+
index e69de29..b0dd2b9 100644 (file)
@@ -0,0 +1,9 @@
+Mon Mar  9 12:59:55 1998  Werner Koch  (wk@isil.d.shuttle.de)
+
+       * cipher.h: Included dsa.h.
+
+Tue Mar  3 15:11:21 1998  Werner Koch  (wk@isil.d.shuttle.de)
+
+       * cipher.h (random.h): Add new header and move all relevalt
+       functions to this header.
+
index d7a89ab..9987fde 100644 (file)
@@ -34,6 +34,8 @@
 #endif
 #include "../cipher/blowfish.h"
 #include "../cipher/elgamal.h"
+#include "../cipher/dsa.h"
+#include "../cipher/random.h"
 
 
 #define CIPHER_ALGO_NONE        0
@@ -78,10 +80,6 @@ int check_cipher_algo( int algo );
 int check_pubkey_algo( int algo );
 int check_digest_algo( int algo );
 
-/*-- random.c --*/
-int  quick_random_gen( int onoff );
-void randomize_buffer( byte *buffer, size_t length, int level );
-byte get_random_byte( int level );
 
 /*-- smallprime.c --*/
 extern ushort small_prime_numbers[];
index 36aff5b..b405d2e 100644 (file)
@@ -58,5 +58,6 @@
 #define G10ERR_CLOSE_FILE     36
 #define G10ERR_RENAME_FILE    37
 #define G10ERR_DELETE_FILE    38
+#define G10ERR_UNEXPECTED     39
 
 #endif /*G10_ERRORS_H*/
index e083c53..6204578 100644 (file)
@@ -101,10 +101,13 @@ const char *strusage( int level );
 
 /*-- fileutil.c --*/
 char *make_filename( const char *first_part, ... );
+const char *print_fname_stdin( const char *s );
+const char *print_fname_stdout( const char *s );
+
 
 /*-- miscutil.c --*/
 u32 make_timestamp(void);
-void print_string( FILE *fp, byte *p, size_t n );
+void print_string( FILE *fp, byte *p, size_t n, int delim );
 int answer_is_yes( const char *s );
 
 /*-- strgutil.c --*/
index 169a5b9..561b849 100644 (file)
@@ -1,3 +1,16 @@
+Sat Mar  7 11:54:35 1998  Werner Koch  (wk@isil.d.shuttle.de)
+
+       * miscutil.c (print_string): New arg delim; changed all callers.
+
+Thu Mar  5 12:19:30 1998  Werner Koch  (wk@isil.d.shuttle.de)
+
+       * errors.c: New strings.
+
+Thu Mar  5 12:06:31 1998  Werner Koch  (wk@isil.d.shuttle.de)
+
+       * iobuf.c (iobuf_open): A name of "-" now opens stdin.
+       * fileutil.c (print_fname_stdout, print_fname_stdin): New.
+
 Fri Feb 27 10:20:03 1998  Werner Koch  (wk@isil.d.shuttle.de)
 
        * memory.c (m_is_secure): Removed.
index 28a4185..35b5517 100644 (file)
@@ -64,9 +64,13 @@ g10_errstr( int err )
       X(NI_PUBKEY      ,"Unimplemented pubkey algorithm")
       X(NI_CIPHER      ,"Unimplemented cipher algorithm")
       X(SIG_CLASS      ,"Unknown signature class")
-      X(TRUSTDB        ,"TrustDB error")
+      X(TRUSTDB        ,"Trust database error")
       X(BAD_CERT       ,"Bad certificate")
-      X(INV_USER_ID    ,"malformed user id")
+      X(INV_USER_ID    ,"Malformed user id")
+      X(CLOSE_FILE     ,"File close error")
+      X(RENAME_FILE    ,"File rename error")
+      X(DELETE_FILE    ,"File delete error")
+      X(UNEXPECTED     ,"Unexpected data")
 
       default: p = buf; sprintf(buf, "g10err=%d", err); break;
     }
index e5f9311..f3e00f8 100644 (file)
@@ -64,3 +64,26 @@ make_filename( const char *first_part, ... )
     return name;
 }
 
+
+/****************
+ * A simple function to decide, wether the filename ist stdout
+ * or a real filename.
+ */
+const char *
+print_fname_stdout( const char *s )
+{
+    if( !s || (*s == '-' && !s[1]) )
+       return "[stdout]";
+    return s;
+}
+
+
+const char *
+print_fname_stdin( const char *s )
+{
+    if( !s || (*s == '-' && !s[1]) )
+       return "[stdin]";
+    return s;
+}
+
+
index ca33986..30d6186 100644 (file)
@@ -371,7 +371,7 @@ iobuf_open( const char *fname )
     file_filter_ctx_t *fcx;
     size_t len;
 
-    if( !fname ) {
+    if( !fname || (*fname=='-' && !fname[1])  ) {
        fp = stdin; /* fixme: set binary mode for msdoze */
        fname = "[stdin]";
     }
index 9dbb13a..cad89e8 100644 (file)
@@ -37,13 +37,21 @@ make_timestamp()
  * Print a string to FP, but filter all control characters out.
  */
 void
-print_string( FILE *fp, byte *p, size_t n )
+print_string( FILE *fp, byte *p, size_t n, int delim )
 {
     for( ; n; n--, p++ )
-       if( iscntrl( *p ) ) {
+       if( iscntrl( *p ) || *p == delim ) {
            putc('\\', fp);
            if( *p == '\n' )
                putc('n', fp);
+           else if( *p == '\r' )
+               putc('r', fp);
+           else if( *p == '\f' )
+               putc('f', fp);
+           else if( *p == '\v' )
+               putc('v', fp);
+           else if( *p == '\b' )
+               putc('b', fp);
            else if( !*p )
                putc('0', fp);
            else