aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ChangeLog4
-rw-r--r--NEWS14
-rw-r--r--README11
-rw-r--r--THANKS2
-rw-r--r--TODO11
-rw-r--r--VERSION2
-rw-r--r--cipher/ChangeLog15
-rw-r--r--cipher/Makefile.am1
-rw-r--r--cipher/Makefile.in1
-rw-r--r--cipher/blowfish.c3
-rw-r--r--cipher/dsa.c205
-rw-r--r--cipher/dsa.h4
-rw-r--r--cipher/md.c1
-rw-r--r--cipher/misc.c1
-rw-r--r--cipher/random.c253
-rw-r--r--cipher/random.h39
-rw-r--r--cipher/rmd.h1
-rw-r--r--cipher/rmd160.c21
-rw-r--r--config.h.in6
-rw-r--r--configure.in1
-rw-r--r--doc/gpg.1pod75
-rw-r--r--g10/ChangeLog46
-rw-r--r--g10/Makefile.am5
-rw-r--r--g10/Makefile.in35
-rw-r--r--g10/armor.c10
-rw-r--r--g10/build-packet.c45
-rw-r--r--g10/compress.c11
-rw-r--r--g10/decrypt.c82
-rw-r--r--g10/dsa.c71
-rw-r--r--g10/elg.c6
-rw-r--r--g10/free-packet.c72
-rw-r--r--g10/g10.c157
-rw-r--r--g10/getkey.c5
-rw-r--r--g10/import.c4
-rw-r--r--g10/kbnode.c4
-rw-r--r--g10/keyid.c113
-rw-r--r--g10/keylist.c224
-rw-r--r--g10/main.h15
-rw-r--r--g10/mainproc.c214
-rw-r--r--g10/openfile.c7
-rw-r--r--g10/options.h2
-rw-r--r--g10/packet.h42
-rw-r--r--g10/parse-packet.c371
-rw-r--r--g10/plaintext.c45
-rw-r--r--g10/ringedit.c13
-rw-r--r--g10/rsa.c6
-rw-r--r--g10/seckey-cert.c127
-rw-r--r--g10/sig-check.c88
-rw-r--r--g10/sign.c7
-rw-r--r--g10/status.c16
-rw-r--r--g10/status.h1
-rw-r--r--g10/trustdb.c23
-rw-r--r--g10/verify.c87
-rw-r--r--include/ChangeLog9
-rw-r--r--include/cipher.h6
-rw-r--r--include/errors.h1
-rw-r--r--include/util.h5
-rw-r--r--util/ChangeLog13
-rw-r--r--util/errors.c8
-rw-r--r--util/fileutil.c23
-rw-r--r--util/iobuf.c2
-rw-r--r--util/miscutil.c12
62 files changed, 2252 insertions, 452 deletions
diff --git a/ChangeLog b/ChangeLog
index e9b12ddf9..2bd404e99 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,7 @@
+Wed Mar 4 10:32:40 1998 Werner Koch ([email protected])
+
+ * configure.in (getrusage,gettimeofday): New tests.
+
Fri Feb 27 13:14:17 1998 Werner Koch ([email protected])
* configure.in (--disable-m-guard): New.
diff --git a/NEWS b/NEWS
index 4ad308d20..609c16322 100644
--- 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 5815fc1c0..664c8a320 100644
--- 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
@@ -105,7 +103,7 @@
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
@@ -208,12 +206,14 @@
"234567C4"
"0F34E556E"
"01347A56A"
+ "0xAB123456
* By a complete keyid:
"234AABBCC34567C4"
"0F323456784E56EAB"
"01AB3FED1347A5612"
+ "0x234AABBCC34567C4"
* By a fingerprint (not yet implemented):
@@ -280,11 +280,6 @@
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 eb5a62cba..4d0436512 100644
--- 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 6edd5d523..e8fabe51d 100644
--- 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
@@ -34,4 +32,11 @@
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 d3b5ba4bf..c7ea8e05a 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-0.2.11
+0.2.12a
diff --git a/cipher/ChangeLog b/cipher/ChangeLog
index 152d23412..0a316d1bb 100644
--- a/cipher/ChangeLog
+++ b/cipher/ChangeLog
@@ -1,3 +1,18 @@
+Mon Mar 9 12:59:08 1998 Werner Koch ([email protected])
+
+ * dsa.c, dsa.h: Removed some unused code.
+
+Wed Mar 4 10:39:22 1998 Werner Koch ([email protected])
+
+ * md.c (md_open): Add call to fast_random_poll.
+ blowfish.c (blowfish_setkey): Ditto.
+
+Tue Mar 3 13:32:54 1998 Werner Koch ([email protected])
+
+ * 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 ([email protected])
* gost.c, gost.h: Removed because they did only conatin trash.
diff --git a/cipher/Makefile.am b/cipher/Makefile.am
index 48478a21d..c0b3c8a5b 100644
--- a/cipher/Makefile.am
+++ b/cipher/Makefile.am
@@ -13,6 +13,7 @@ libcipher_a_SOURCES = blowfish.c \
md5.c \
md5.h \
primegen.c \
+ random.h \
random.c \
rmd.h \
rmd160.c \
diff --git a/cipher/Makefile.in b/cipher/Makefile.in
index 958b7d167..579d4a355 100644
--- a/cipher/Makefile.in
+++ b/cipher/Makefile.in
@@ -104,6 +104,7 @@ libcipher_a_SOURCES = blowfish.c \
md5.c \
md5.h \
primegen.c \
+ random.h \
random.c \
rmd.h \
rmd160.c \
diff --git a/cipher/blowfish.c b/cipher/blowfish.c
index c0979b8ce..55b99025c 100644
--- a/cipher/blowfish.c
+++ b/cipher/blowfish.c
@@ -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++ ) {
diff --git a/cipher/dsa.c b/cipher/dsa.c
index 07f9e7075..8024ac0a2 100644
--- a/cipher/dsa.c
+++ b/cipher/dsa.c
@@ -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;
}
diff --git a/cipher/dsa.h b/cipher/dsa.h
index 1574560f6..07a41ae6c 100644
--- a/cipher/dsa.h
+++ b/cipher/dsa.h
@@ -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*/
diff --git a/cipher/md.c b/cipher/md.c
index a9a566698..b19399653 100644
--- a/cipher/md.c
+++ b/cipher/md.c
@@ -42,6 +42,7 @@ md_open( int algo, int secure )
hd->secure = secure;
if( algo )
md_enable( hd, algo );
+ fast_random_poll();
return hd;
}
diff --git a/cipher/misc.c b/cipher/misc.c
index 937aa61f5..ad937fcfe 100644
--- a/cipher/misc.c
+++ b/cipher/misc.c
@@ -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
diff --git a/cipher/random.c b/cipher/random.c
index 2f11df7cd..5a6371995 100644
--- a/cipher/random.c
+++ b/cipher/random.c
@@ -18,6 +18,17 @@
* 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>
@@ -26,27 +37,88 @@
#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
index 000000000..a8c506da7
--- /dev/null
+++ b/cipher/random.h
@@ -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*/
diff --git a/cipher/rmd.h b/cipher/rmd.h
index d6bc007d1..f3a67243b 100644
--- a/cipher/rmd.h
+++ b/cipher/rmd.h
@@ -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*/
diff --git a/cipher/rmd160.c b/cipher/rmd160.c
index 7b87d4218..8d17b287f 100644
--- a/cipher/rmd160.c
+++ b/cipher/rmd160.c
@@ -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
*/
diff --git a/config.h.in b/config.h.in
index 95f2175f8..485605b18 100644
--- a/config.h.in
+++ b/config.h.in
@@ -142,6 +142,12 @@
/* 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
diff --git a/configure.in b/configure.in
index 660f54144..43ca5a188 100644
--- a/configure.in
+++ b/configure.in
@@ -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)
diff --git a/doc/gpg.1pod b/doc/gpg.1pod
index ecbc39138..da755256f 100644
--- a/doc/gpg.1pod
+++ b/doc/gpg.1pod
@@ -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.
diff --git a/g10/ChangeLog b/g10/ChangeLog
index c1f6036c4..c64144117 100644
--- a/g10/ChangeLog
+++ b/g10/ChangeLog
@@ -1,3 +1,49 @@
+Mon Mar 9 12:43:42 1998 Werner Koch ([email protected])
+
+ * 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 ([email protected])
+
+ * 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 ([email protected])
+
+ * 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 ([email protected])
+
+ * g10.c (main): Add userids to "-kv" and cleaned up this stuff.
+
+Fri Mar 6 12:45:58 1998 Werner Koch ([email protected])
+
+ * 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 ([email protected])
+
+ * 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 ([email protected])
* g10.c: Is nom the common source for gpg and gpgm
diff --git a/g10/Makefile.am b/g10/Makefile.am
index aaed0ff23..edfdba412 100644
--- a/g10/Makefile.am
+++ b/g10/Makefile.am
@@ -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@
diff --git a/g10/Makefile.in b/g10/Makefile.in
index caffcd7f5..cc4b69b36 100644
--- a/g10/Makefile.in
+++ b/g10/Makefile.in
@@ -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)
diff --git a/g10/armor.c b/g10/armor.c
index 142e0bd82..3192e95b3 100644
--- a/g10/armor.c
+++ b/g10/armor.c
@@ -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;
diff --git a/g10/build-packet.c b/g10/build-packet.c
index ea8a875ad..793095e65 100644
--- a/g10/build-packet.c
+++ b/g10/build-packet.c
@@ -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 {
diff --git a/g10/compress.c b/g10/compress.c
index ebad43045..686332b82 100644
--- a/g10/compress.c
+++ b/g10/compress.c
@@ -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
index 000000000..1a457f2df
--- /dev/null
+++ b/g10/decrypt.c
@@ -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
index 000000000..1c4f8945d
--- /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);
+ }
+}
+
diff --git a/g10/elg.c b/g10/elg.c
index 62c5014c8..329b762fe 100644
--- 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));
diff --git a/g10/free-packet.c b/g10/free-packet.c
index fa1a53ccf..eb90f51ef 100644
--- a/g10/free-packet.c
+++ b/g10/free-packet.c
@@ -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;
diff --git a/g10/g10.c b/g10/g10.c
index b5ee4e4e3..d2683c95c 100644
--- 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 );
}
diff --git a/g10/getkey.c b/g10/getkey.c
index b528ed782..300e33b86 100644
--- a/g10/getkey.c
+++ b/g10/getkey.c
@@ -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 );
diff --git a/g10/import.c b/g10/import.c
index a99b4793b..3d5cd2a17 100644
--- a/g10/import.c
+++ b/g10/import.c
@@ -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 */
diff --git a/g10/kbnode.c b/g10/kbnode.c
index 5a6d16abc..11b0e46be 100644
--- a/g10/kbnode.c
+++ b/g10/kbnode.c
@@ -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 ) {
diff --git a/g10/keyid.c b/g10/keyid.c
index 8d3e58da2..ef7b1ba1b 100644
--- a/g10/keyid.c
+++ b/g10/keyid.c
@@ -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;
diff --git a/g10/keylist.c b/g10/keylist.c
index 15f3c2f19..25573663a 100644
--- a/g10/keylist.c
+++ b/g10/keylist.c
@@ -32,17 +32,231 @@
#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);
}
diff --git a/g10/main.h b/g10/main.h
index eef3d7377..5078e80aa 100644
--- a/g10/main.h
+++ b/g10/main.h
@@ -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*/
diff --git a/g10/mainproc.c b/g10/mainproc.c
index 153496f60..3ca23ccc0 100644
--- a/g10/mainproc.c
+++ b/g10/mainproc.c
@@ -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));
diff --git a/g10/openfile.c b/g10/openfile.c
index 249e9c9a1..f51ee433d 100644
--- a/g10/openfile.c
+++ b/g10/openfile.c
@@ -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")) ) {
diff --git a/g10/options.h b/g10/options.h
index 0ac04184b..0f2a2789f 100644
--- a/g10/options.h
+++ b/g10/options.h
@@ -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;
diff --git a/g10/packet.h b/g10/packet.h
index 201313668..53448bd8e 100644
--- a/g10/packet.h
+++ b/g10/packet.h
@@ -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 );
diff --git a/g10/parse-packet.c b/g10/parse-packet.c
index 498dd1985..0cc2ece01 100644
--- a/g10/parse-packet.c
+++ b/g10/parse-packet.c
@@ -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 )
}
+
diff --git a/g10/plaintext.c b/g10/plaintext.c
index 284b684b5..e15a269e8 100644
--- a/g10/plaintext.c
+++ b/g10/plaintext.c
@@ -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;
+}
+
+
diff --git a/g10/ringedit.c b/g10/ringedit.c
index ba71f0e67..1ec35b811 100644
--- a/g10/ringedit.c
+++ b/g10/ringedit.c
@@ -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 )
diff --git a/g10/rsa.c b/g10/rsa.c
index 23df05575..f1872b53a 100644
--- 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;
diff --git a/g10/seckey-cert.c b/g10/seckey-cert.c
index 85b0ed7af..f126ba01b 100644
--- a/g10/seckey-cert.c
+++ b/g10/seckey-cert.c
@@ -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;
}
diff --git a/g10/sig-check.c b/g10/sig-check.c
index 32371b359..f25f2e19f 100644
--- a/g10/sig-check.c
+++ b/g10/sig-check.c
@@ -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");
diff --git a/g10/sign.c b/g10/sign.c
index 9d8208870..4cf7b7bd6 100644
--- a/g10/sign.c
+++ b/g10/sign.c
@@ -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;
diff --git a/g10/status.c b/g10/status.c
index 05f902a5f..5aa712a30 100644
--- a/g10/status.c
+++ b/g10/status.c
@@ -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) );
}
diff --git a/g10/status.h b/g10/status.h
index a3d493b89..41820825f 100644
--- a/g10/status.h
+++ b/g10/status.h
@@ -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*/
diff --git a/g10/trustdb.c b/g10/trustdb.c
index 8c9088b91..257c37204 100644
--- a/g10/trustdb.c
+++ b/g10/trustdb.c
@@ -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
index 000000000..3398c2ed4
--- /dev/null
+++ b/g10/verify.c
@@ -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;
+}
+
+
+
diff --git a/include/ChangeLog b/include/ChangeLog
index e69de29bb..b0dd2b902 100644
--- a/include/ChangeLog
+++ b/include/ChangeLog
@@ -0,0 +1,9 @@
+Mon Mar 9 12:59:55 1998 Werner Koch ([email protected])
+
+ * cipher.h: Included dsa.h.
+
+Tue Mar 3 15:11:21 1998 Werner Koch ([email protected])
+
+ * cipher.h (random.h): Add new header and move all relevalt
+ functions to this header.
+
diff --git a/include/cipher.h b/include/cipher.h
index d7a89ab46..9987fdec9 100644
--- a/include/cipher.h
+++ b/include/cipher.h
@@ -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[];
diff --git a/include/errors.h b/include/errors.h
index 36aff5bd6..b405d2eee 100644
--- a/include/errors.h
+++ b/include/errors.h
@@ -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*/
diff --git a/include/util.h b/include/util.h
index e083c53c9..620457860 100644
--- a/include/util.h
+++ b/include/util.h
@@ -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 --*/
diff --git a/util/ChangeLog b/util/ChangeLog
index 169a5b96f..561b84905 100644
--- a/util/ChangeLog
+++ b/util/ChangeLog
@@ -1,3 +1,16 @@
+Sat Mar 7 11:54:35 1998 Werner Koch ([email protected])
+
+ * miscutil.c (print_string): New arg delim; changed all callers.
+
+Thu Mar 5 12:19:30 1998 Werner Koch ([email protected])
+
+ * errors.c: New strings.
+
+Thu Mar 5 12:06:31 1998 Werner Koch ([email protected])
+
+ * 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 ([email protected])
* memory.c (m_is_secure): Removed.
diff --git a/util/errors.c b/util/errors.c
index 28a418536..35b55177c 100644
--- a/util/errors.c
+++ b/util/errors.c
@@ -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;
}
diff --git a/util/fileutil.c b/util/fileutil.c
index e5f9311bc..f3e00f8d6 100644
--- a/util/fileutil.c
+++ b/util/fileutil.c
@@ -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;
+}
+
+
diff --git a/util/iobuf.c b/util/iobuf.c
index ca3398674..30d6186fd 100644
--- a/util/iobuf.c
+++ b/util/iobuf.c
@@ -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]";
}
diff --git a/util/miscutil.c b/util/miscutil.c
index 9dbb13ac1..cad89e8ab 100644
--- a/util/miscutil.c
+++ b/util/miscutil.c
@@ -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