summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWerner Koch <wk@gnupg.org>1998-07-29 21:35:05 +0200
committerWerner Koch <wk@gnupg.org>1998-07-29 21:35:05 +0200
commit5ae562b41d9e3ec965643b902bf8593c8ca5a2d7 (patch)
tree059ed09c380b3f534479add19933dbe9a7a401c9
parentchanged trustdb design (diff)
downloadgnupg2-5ae562b41d9e3ec965643b902bf8593c8ca5a2d7.tar.xz
gnupg2-5ae562b41d9e3ec965643b902bf8593c8ca5a2d7.zip
edit-key is now complete
-rw-r--r--AUTHORS4
-rw-r--r--NEWS25
-rw-r--r--README3
-rw-r--r--THANKS3
-rw-r--r--TODO16
-rwxr-xr-xchecks/defs.inc4
-rw-r--r--cipher/ChangeLog7
-rw-r--r--cipher/Makefile.am8
-rw-r--r--cipher/cipher.c158
-rw-r--r--cipher/tiger.c1
-rw-r--r--doc/DETAILS45
-rw-r--r--doc/gpg.1pod69
-rw-r--r--g10/ChangeLog23
-rw-r--r--g10/Makefile.am2
-rw-r--r--g10/OPTIONS6
-rw-r--r--g10/build-packet.c18
-rw-r--r--g10/cipher.c16
-rw-r--r--g10/encr-data.c16
-rw-r--r--g10/free-packet.c49
-rw-r--r--g10/g10.c69
-rw-r--r--g10/import.c2
-rw-r--r--g10/kbnode.c5
-rw-r--r--g10/keydb.h3
-rw-r--r--g10/keyedit.c1426
-rw-r--r--g10/keygen.c169
-rw-r--r--g10/keyid.c31
-rw-r--r--g10/keylist.c7
-rw-r--r--g10/main.h7
-rw-r--r--g10/mainproc.c4
-rw-r--r--g10/misc.c4
-rw-r--r--g10/options.h4
-rw-r--r--g10/packet.h7
-rw-r--r--g10/parse-packet.c6
-rw-r--r--g10/seckey-cert.c6
-rw-r--r--g10/sign.c108
-rw-r--r--g10/tdbio.c520
-rw-r--r--g10/tdbio.h14
-rw-r--r--g10/trustdb.c95
-rw-r--r--g10/trustdb.h3
-rw-r--r--include/cipher.h2
-rw-r--r--include/ttyio.h1
-rw-r--r--mpi/g10m.c2
-rw-r--r--mpi/mpi-inv.c2
-rw-r--r--po/de.po15
-rw-r--r--util/ChangeLog4
-rw-r--r--util/miscutil.c1
-rw-r--r--util/secmem.c6
-rw-r--r--util/ttyio.c12
48 files changed, 2034 insertions, 974 deletions
diff --git a/AUTHORS b/AUTHORS
index 86dab482b..779b4edac 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -6,3 +6,7 @@ Werner Koch. Designed and implemented gnupg.
TRANSLATIONS Marco d'Itri 1997-02-22
Disclaim
+Twofish Matthew Skala ????????????
+
+
+
diff --git a/NEWS b/NEWS
index 6197de5c3..0a375b1a3 100644
--- a/NEWS
+++ b/NEWS
@@ -1,12 +1,37 @@
Noteworthy changes in version 0.3.3
-----------------------------------
+ * The format of the trust database has changed; you must delete
+ the old one, so gnupg can create a new one.
+ IMPORTANT: Use version 0.3.[12] to save your assigned ownertrusts
+ ("gpgm --list-ownertrust >saved-trust"); then build this new version
+ and restore the ownertrust with this new version
+ ("gpgm --import-ownertrust saved-trust").
+
+ * The command --edit-key now provides a commandline driven menu
+ which can be used vor vaious tasks. --sign-key is only an
+ an alias to --edit-key and maybe removed in future: use the
+ command "sign" of this new menu - you can select which user ids
+ you want to sign.
+
+ * Alternate user ids can now be created an signed.
+
* Removed options --gen-prime and --gen-random.
+ * Removed option --add-key; use --edit-key instead.
+
+ * Removed option --change-passphrase; use --edit-key instead.
+
* Signatures are now checked even if the output file could not
be created. Command "--verify" tries to find the detached data.
* gpg now disables core dumps.
+ * We have added the Twofish as an experimental cipher algorithm.
+ Many thanks to Matthew Skala for doing this work.
+ Twofish is the AES submission from Schneier et al.; see
+ "www.counterpane.com/twofish.html" for more information.
+
+
Noteworthy changes in version 0.3.2
-----------------------------------
diff --git a/README b/README
index c220c00c2..240b319f1 100644
--- a/README
+++ b/README
@@ -135,6 +135,9 @@
Creates a signature of file, but writes the output to the file "out".
+ If you use the option "--rfc1991", gnupg tries to me more compatible
+ to RFC1991 (pgp 2.x).
+
Encrypt
-------
diff --git a/THANKS b/THANKS
index b30466c18..d0c53d505 100644
--- a/THANKS
+++ b/THANKS
@@ -5,6 +5,7 @@ errors.
Anand Kumria wildfire@progsoc.uts.edu.au
Brian Warner warner@lothar.com
+Caskey L. Dickson caskey@technocage.com
Charles Levert charles@comm.polymtl.ca
Christian von Roques roques@pond.sub.org
Daniel Eisenbud eisenbud@cs.swarthmore.edu
@@ -25,8 +26,10 @@ Martin Schulte schulte@thp.uni-koeln.de
Matthew Skala mskala@ansuz.sooke.bc.ca
Max Valianskiy maxcom@maxcom.ml.org
Nicolas Graner Nicolas.Graner@cri.u-psud.fr
+Oskari Jääskeläinen f33003a@cc.hut.fi
Peter Gutmann pgut001@cs.auckland.ac.nz
Ralph Gillen gillen@theochem.uni-duesseldorf.de
+Steffen Ullrich ccrlphr@xensei.com
Thomas Roessler roessler@guug.de
Tom Spindler dogcow@home.merit.edu
Tom Zerucha tzeruch@ceddec.com
diff --git a/TODO b/TODO
index 3c05ad040..9ceeb728f 100644
--- a/TODO
+++ b/TODO
@@ -2,6 +2,16 @@
can also hold the localid and extend the localid to hold information
of the subkey number because two subkeys may have the same keyid.
+ * Fix Oscaris problems with the trustdb.
+
+ * add test cases for invalid data (scrambled armor or other random data)
+
+ * fix the expire stuff for v4 packets.
+
+ * check whether it is valid to pack the signature stuff (onepass, data,
+ sig) into a compressed packet - or should we only compress the data?
+ what does pgp 5 do, what does OpenPGP say=
+
* invalid packets (Marco)
* add some sanity checks to read_keyblock, so that we are sure that
@@ -9,9 +19,7 @@
* what about the CR,LF in cleartext singatures?
- * add option --restore-ownertrust
-
- * always put key signatures before the first subkey.
+ * add option --import-ownertrust
* add a way to delete subkeys (in edit-keys?)
@@ -33,8 +41,6 @@
* add checking of armor trailers
* remove all "Fixmes"
- * add an option to create a new user id.
-
* add an option to re-create a public key from a secret key. Think about
a backup system of only the secret part of the secret key.
diff --git a/checks/defs.inc b/checks/defs.inc
index f3ff66f18..49cbcf292 100755
--- a/checks/defs.inc
+++ b/checks/defs.inc
@@ -61,10 +61,10 @@ chdir () {
set -e
-pgmname=$(basename $0)
+pgmname=`basename $0`
#trap cleanup SIGHUP SIGINT SIGQUIT
-[ -z $srcdir ] && fatal "not called from make"
+[ -z "$srcdir" ] && fatal "not called from make"
cat <<EOF >./options
no-greeting
diff --git a/cipher/ChangeLog b/cipher/ChangeLog
index 010952863..528de20cd 100644
--- a/cipher/ChangeLog
+++ b/cipher/ChangeLog
@@ -1,3 +1,10 @@
+Mon Jul 27 10:30:22 1998 Werner Koch (wk@(none))
+
+ * cipher.c : Support for other blocksizes
+ (cipher_get_blocksize): New.
+ * twofish.c: New.
+ * Makefile.am: Add twofish module.
+
Mon Jul 13 21:30:52 1998 Werner Koch (wk@isil.d.shuttle.de)
* random.c (read_pool): Simple alloc if secure_alloc is not set.
diff --git a/cipher/Makefile.am b/cipher/Makefile.am
index f01bb7844..36dd0c537 100644
--- a/cipher/Makefile.am
+++ b/cipher/Makefile.am
@@ -1,6 +1,6 @@
## Process this file with automake to produce Makefile.in
-gnupg_extensions = tiger
+gnupg_extensions = tiger twofish
INCLUDES = -I$(top_srcdir)/include -I$(top_srcdir)/intl -I../intl
@@ -42,9 +42,13 @@ libcipher_a_SOURCES = cipher.c \
smallprime.c
EXTRA_tiger_SOURCES = tiger.c
+EXTRA_twofish_SOURCES = twofish.c
tiger: tiger.c
- $(COMPILE) -shared -fPIC -o tiger tiger.c
+ $(COMPILE) -shared -fPIC -o tiger tiger.c
+
+twofish: twofish.c
+ $(COMPILE) -shared -fPIC -o twofish twofish.c
install-exec-hook:
@list='$(pkglib_PROGRAMS)'; for p in $$list; do \
diff --git a/cipher/cipher.c b/cipher/cipher.c
index 25b1e8fcd..049207bf1 100644
--- a/cipher/cipher.c
+++ b/cipher/cipher.c
@@ -34,12 +34,13 @@
#include "dynload.h"
-#define STD_BLOCKSIZE 8
+#define MAX_BLOCKSIZE 16
#define TABLE_SIZE 10
struct cipher_table_s {
const char *name;
int algo;
+ size_t blocksize;
size_t keylen;
size_t contextsize; /* allocate this amount of context */
void (*setkey)( void *c, byte *key, unsigned keylen );
@@ -53,8 +54,9 @@ static struct cipher_table_s cipher_table[TABLE_SIZE];
struct cipher_handle_s {
int algo;
int mode;
- byte iv[STD_BLOCKSIZE]; /* (this should be ulong aligned) */
- byte lastiv[STD_BLOCKSIZE];
+ size_t blocksize;
+ byte iv[MAX_BLOCKSIZE]; /* (this should be ulong aligned) */
+ byte lastiv[MAX_BLOCKSIZE];
int unused; /* in IV */
void (*setkey)( void *c, byte *key, unsigned keylen );
void (*encrypt)( void *c, byte *outbuf, byte *inbuf );
@@ -80,44 +82,44 @@ setup_cipher_table()
{
int i;
- size_t blocksize;
i = 0;
cipher_table[i].algo = CIPHER_ALGO_BLOWFISH;
cipher_table[i].name = blowfish_get_info( cipher_table[i].algo,
&cipher_table[i].keylen,
- &blocksize,
+ &cipher_table[i].blocksize,
&cipher_table[i].contextsize,
&cipher_table[i].setkey,
&cipher_table[i].encrypt,
&cipher_table[i].decrypt );
- if( !cipher_table[i].name || blocksize != STD_BLOCKSIZE )
+ if( !cipher_table[i].name )
BUG();
i++;
cipher_table[i].algo = CIPHER_ALGO_CAST5;
cipher_table[i].name = cast5_get_info( cipher_table[i].algo,
&cipher_table[i].keylen,
- &blocksize,
+ &cipher_table[i].blocksize,
&cipher_table[i].contextsize,
&cipher_table[i].setkey,
&cipher_table[i].encrypt,
&cipher_table[i].decrypt );
- if( !cipher_table[i].name || blocksize != STD_BLOCKSIZE )
+ if( !cipher_table[i].name )
BUG();
i++;
cipher_table[i].algo = CIPHER_ALGO_BLOWFISH160;
cipher_table[i].name = blowfish_get_info( cipher_table[i].algo,
&cipher_table[i].keylen,
- &blocksize,
+ &cipher_table[i].blocksize,
&cipher_table[i].contextsize,
&cipher_table[i].setkey,
&cipher_table[i].encrypt,
&cipher_table[i].decrypt );
- if( !cipher_table[i].name || blocksize != STD_BLOCKSIZE )
+ if( !cipher_table[i].name )
BUG();
i++;
cipher_table[i].algo = CIPHER_ALGO_DUMMY;
cipher_table[i].name = "DUMMY";
+ cipher_table[i].blocksize = 8;
cipher_table[i].keylen = 128;
cipher_table[i].contextsize = 0;
cipher_table[i].setkey = dummy_setkey;
@@ -141,7 +143,6 @@ load_cipher_modules()
void *context = NULL;
struct cipher_table_s *ct;
int ct_idx;
- size_t blocksize;
int i;
const char *name;
int any = 0;
@@ -164,9 +165,9 @@ load_cipher_modules()
BUG(); /* table already full */
/* now load all extensions */
while( (name = enum_gnupgext_ciphers( &context, &ct->algo,
- &ct->keylen, &blocksize, &ct->contextsize,
+ &ct->keylen, &ct->blocksize, &ct->contextsize,
&ct->setkey, &ct->encrypt, &ct->decrypt)) ) {
- if( blocksize != STD_BLOCKSIZE ) {
+ if( ct->blocksize != 8 && ct->blocksize != 16 ) {
log_info("skipping cipher %d: unsupported blocksize\n", ct->algo);
continue;
}
@@ -271,6 +272,26 @@ cipher_get_keylen( int algo )
return 0;
}
+unsigned
+cipher_get_blocksize( int algo )
+{
+ int i;
+ unsigned len = 0;
+
+ do {
+ for(i=0; cipher_table[i].name; i++ ) {
+ if( cipher_table[i].algo == algo ) {
+ len = cipher_table[i].blocksize;
+ if( !len )
+ log_bug("cipher %d w/o blocksize\n", algo );
+ return len;
+ }
+ }
+ } while( load_cipher_modules() );
+ log_bug("cipher %d not found\n", algo );
+ return 0;
+}
+
/****************
* Open a cipher handle for use with algorithm ALGO, in mode MODE
@@ -299,6 +320,7 @@ cipher_open( int algo, int mode, int secure )
+ cipher_table[i].contextsize )
: m_alloc_clear( sizeof *hd + cipher_table[i].contextsize );
hd->algo = algo;
+ hd->blocksize = cipher_table[i].blocksize;
hd->setkey = cipher_table[i].setkey;
hd->encrypt = cipher_table[i].encrypt;
hd->decrypt = cipher_table[i].decrypt;
@@ -336,9 +358,9 @@ void
cipher_setiv( CIPHER_HANDLE c, const byte *iv )
{
if( iv )
- memcpy( c->iv, iv, STD_BLOCKSIZE );
+ memcpy( c->iv, iv, c->blocksize );
else
- memset( c->iv, 0, STD_BLOCKSIZE );
+ memset( c->iv, 0, c->blocksize );
c->unused = 0;
}
@@ -351,8 +373,8 @@ do_ecb_encrypt( CIPHER_HANDLE c, byte *outbuf, byte *inbuf, unsigned nblocks )
for(n=0; n < nblocks; n++ ) {
(*c->encrypt)( &c->context, outbuf, inbuf );
- inbuf += STD_BLOCKSIZE;;
- outbuf += STD_BLOCKSIZE;
+ inbuf += c->blocksize;
+ outbuf += c->blocksize;
}
}
@@ -363,8 +385,8 @@ do_ecb_decrypt( CIPHER_HANDLE c, byte *outbuf, byte *inbuf, unsigned nblocks )
for(n=0; n < nblocks; n++ ) {
(*c->decrypt)( &c->context, outbuf, inbuf );
- inbuf += STD_BLOCKSIZE;;
- outbuf += STD_BLOCKSIZE;
+ inbuf += c->blocksize;
+ outbuf += c->blocksize;
}
}
@@ -373,11 +395,12 @@ static void
do_cfb_encrypt( CIPHER_HANDLE c, byte *outbuf, byte *inbuf, unsigned nbytes )
{
byte *ivp;
+ size_t blocksize = c->blocksize;
if( nbytes <= c->unused ) {
/* short enough to be encoded by the remaining XOR mask */
/* XOR the input with the IV and store input into IV */
- for(ivp=c->iv+STD_BLOCKSIZE - c->unused; nbytes; nbytes--, c->unused-- )
+ for(ivp=c->iv+c->blocksize - c->unused; nbytes; nbytes--, c->unused-- )
*outbuf++ = (*ivp++ ^= *inbuf++);
return;
}
@@ -385,26 +408,26 @@ do_cfb_encrypt( CIPHER_HANDLE c, byte *outbuf, byte *inbuf, unsigned nbytes )
if( c->unused ) {
/* XOR the input with the IV and store input into IV */
nbytes -= c->unused;
- for(ivp=c->iv+STD_BLOCKSIZE - c->unused; c->unused; c->unused-- )
+ for(ivp=c->iv+blocksize - c->unused; c->unused; c->unused-- )
*outbuf++ = (*ivp++ ^= *inbuf++);
}
/* now we can process complete blocks */
- while( nbytes >= STD_BLOCKSIZE ) {
+ while( nbytes >= blocksize ) {
int i;
/* encrypt the IV (and save the current one) */
- memcpy( c->lastiv, c->iv, STD_BLOCKSIZE );
+ memcpy( c->lastiv, c->iv, blocksize );
(*c->encrypt)( &c->context, c->iv, c->iv );
/* XOR the input with the IV and store input into IV */
- for(ivp=c->iv,i=0; i < STD_BLOCKSIZE; i++ )
+ for(ivp=c->iv,i=0; i < blocksize; i++ )
*outbuf++ = (*ivp++ ^= *inbuf++);
- nbytes -= STD_BLOCKSIZE;
+ nbytes -= blocksize;
}
if( nbytes ) { /* process the remaining bytes */
/* encrypt the IV (and save the current one) */
- memcpy( c->lastiv, c->iv, STD_BLOCKSIZE );
+ memcpy( c->lastiv, c->iv, blocksize );
(*c->encrypt)( &c->context, c->iv, c->iv );
- c->unused = STD_BLOCKSIZE;
+ c->unused = blocksize;
/* and apply the xor */
c->unused -= nbytes;
for(ivp=c->iv; nbytes; nbytes-- )
@@ -417,11 +440,12 @@ do_cfb_decrypt( CIPHER_HANDLE c, byte *outbuf, byte *inbuf, unsigned nbytes )
{
byte *ivp;
ulong temp;
+ size_t blocksize = c->blocksize;
if( nbytes <= c->unused ) {
/* short enough to be encoded by the remaining XOR mask */
/* XOR the input with the IV and store input into IV */
- for(ivp=c->iv+STD_BLOCKSIZE - c->unused; nbytes; nbytes--,c->unused--){
+ for(ivp=c->iv+blocksize - c->unused; nbytes; nbytes--,c->unused--){
temp = *inbuf++;
*outbuf++ = *ivp ^ temp;
*ivp++ = temp;
@@ -432,7 +456,7 @@ do_cfb_decrypt( CIPHER_HANDLE c, byte *outbuf, byte *inbuf, unsigned nbytes )
if( c->unused ) {
/* XOR the input with the IV and store input into IV */
nbytes -= c->unused;
- for(ivp=c->iv+STD_BLOCKSIZE - c->unused; c->unused; c->unused-- ) {
+ for(ivp=c->iv+blocksize - c->unused; c->unused; c->unused-- ) {
temp = *inbuf++;
*outbuf++ = *ivp ^ temp;
*ivp++ = temp;
@@ -440,70 +464,24 @@ do_cfb_decrypt( CIPHER_HANDLE c, byte *outbuf, byte *inbuf, unsigned nbytes )
}
/* now we can process complete blocks */
- #ifdef BIG_ENDIAN_HOST
- /* This does only make sense for big endian hosts, due to ... ivp = temp*/
- if( !((ulong)inbuf % SIZEOF_UNSIGNED_LONG) ) {
- while( nbytes >= STD_BLOCKSIZE ) {
- /* encrypt the IV (and save the current one) */
- memcpy( c->lastiv, c->iv, STD_BLOCKSIZE );
- (*c->encrypt)( &c->context, c->iv, c->iv );
- ivp = c->iv;
- /* XOR the input with the IV and store input into IV */
- #if SIZEOF_UNSIGNED_LONG == STD_BLOCKSIZE
- temp = *(ulong*)inbuf;
- *(ulong*)outbuf = *(ulong*)c->iv ^ temp;
- *(ulong*)ivp = temp;
- #elif (2*SIZEOF_UNSIGNED_LONG) == STD_BLOCKSIZE
- temp = ((ulong*)inbuf)[0];
- ((ulong*)outbuf)[0] = ((ulong*)c->iv)[0] ^ temp;
- ((ulong*)ivp)[0] = temp;
- temp = ((ulong*)inbuf)[1];
- ((ulong*)outbuf)[1] = ((ulong*)c->iv)[1] ^ temp;
- ((ulong*)ivp)[1] = temp;
- #elif (4*SIZEOF_UNSIGNED_LONG) == STD_BLOCKSIZE
- temp = ((ulong*)inbuf)[0];
- ((ulong*)outbuf)[0] = ((ulong*)c->iv)[0] ^ temp;
- ((ulong*)ivp)[0] = temp;
- temp = ((ulong*)inbuf)[1];
- ((ulong*)outbuf)[1] = ((ulong*)c->iv)[1] ^ temp;
- ((ulong*)ivp)[1] = temp;
- temp = ((ulong*)inbuf)[2];
- ((ulong*)outbuf)[2] = ((ulong*)c->iv)[2] ^ temp;
- ((ulong*)ivp)[2] = temp;
- temp = ((ulong*)inbuf)[3];
- ((ulong*)outbuf)[3] = ((ulong*)c->iv)[3] ^ temp;
- ((ulong*)ivp)[3] = temp;
- #else
- #error Please disable the align test.
- #endif
- nbytes -= STD_BLOCKSIZE;
- inbuf += STD_BLOCKSIZE;
- outbuf += STD_BLOCKSIZE;
- }
- }
- else { /* non aligned version */
- #endif /* BIG_ENDIAN_HOST */
- while( nbytes >= STD_BLOCKSIZE ) {
- int i;
- /* encrypt the IV (and save the current one) */
- memcpy( c->lastiv, c->iv, STD_BLOCKSIZE );
- (*c->encrypt)( &c->context, c->iv, c->iv );
- /* XOR the input with the IV and store input into IV */
- for(ivp=c->iv,i=0; i < STD_BLOCKSIZE; i++ ) {
- temp = *inbuf++;
- *outbuf++ = *ivp ^ temp;
- *ivp++ = temp;
- }
- nbytes -= STD_BLOCKSIZE;
+ while( nbytes >= blocksize ) {
+ int i;
+ /* encrypt the IV (and save the current one) */
+ memcpy( c->lastiv, c->iv, blocksize );
+ (*c->encrypt)( &c->context, c->iv, c->iv );
+ /* XOR the input with the IV and store input into IV */
+ for(ivp=c->iv,i=0; i < blocksize; i++ ) {
+ temp = *inbuf++;
+ *outbuf++ = *ivp ^ temp;
+ *ivp++ = temp;
}
- #ifdef BIG_ENDIAN_HOST
+ nbytes -= blocksize;
}
- #endif
if( nbytes ) { /* process the remaining bytes */
/* encrypt the IV (and save the current one) */
- memcpy( c->lastiv, c->iv, STD_BLOCKSIZE );
+ memcpy( c->lastiv, c->iv, blocksize );
(*c->encrypt)( &c->context, c->iv, c->iv );
- c->unused = STD_BLOCKSIZE;
+ c->unused = blocksize;
/* and apply the xor */
c->unused -= nbytes;
for(ivp=c->iv; nbytes; nbytes-- ) {
@@ -576,8 +554,8 @@ void
cipher_sync( CIPHER_HANDLE c )
{
if( c->mode == CIPHER_MODE_PHILS_CFB && c->unused ) {
- memmove(c->iv + c->unused, c->iv, STD_BLOCKSIZE - c->unused );
- memcpy(c->iv, c->lastiv + STD_BLOCKSIZE - c->unused, c->unused);
+ memmove(c->iv + c->unused, c->iv, c->blocksize - c->unused );
+ memcpy(c->iv, c->lastiv + c->blocksize - c->unused, c->unused);
c->unused = 0;
}
}
diff --git a/cipher/tiger.c b/cipher/tiger.c
index 2560e8ab7..d02f5cb86 100644
--- a/cipher/tiger.c
+++ b/cipher/tiger.c
@@ -939,7 +939,6 @@ gnupgext_enum_func( int what, int *sequence, int *class, int *vers )
void *ret;
int i = *sequence;
- /*log_info("gnupgext_enum_func in rsa+idea called what=%d i=%d: ", what, i);*/
do {
if( i >= DIM(func_table) || i < 0 ) {
/*fprintf(stderr, "failed\n");*/
diff --git a/doc/DETAILS b/doc/DETAILS
index 661a4a1ef..04236b7e9 100644
--- a/doc/DETAILS
+++ b/doc/DETAILS
@@ -56,23 +56,18 @@ Record type 1:
--------------
Version information for this TrustDB. This is always the first
record of the DB and the only one with type 1.
- 1 byte value 2
+ 1 byte value 1
3 bytes 'gpg' magic value
1 byte Version of the TrustDB
3 byte reserved
- 1 u32 locked by (pid) 0 = not locked.
+ 1 u32 locked flags
1 u32 timestamp of trustdb creation
1 u32 timestamp of last modification
1 u32 timestamp of last validation
(Used to keep track of the time, when this TrustDB was checked
against the pubring)
- 1 u32 reserved
- 1 byte marginals needed
- 1 byte completes needed
- 1 byte max. cert depth
- If any of this 3 values are changed, all cache records
- must be invalidated.
- 9 bytes reserved
+ 1 u32 record number of keyhashtable
+ 12 bytes reserved
Record type 2: (directory record)
@@ -183,9 +178,9 @@ Record type 9: (cache record)
Record Type 10 (hash table)
--------------
- Due to the fact that we use the keyid to lookup keys, we can
+ Due to the fact that we use fingerprints to lookup keys, we can
implement quick access by some simple hash methods, and avoid
- the overhead of gdbm. A property of keyids is that they can be
+ the overhead of gdbm. A property of fingerprints is that they can be
used directly as hash values. (They can be considered as strong
random numbers.)
What we use is a dynamic multilevel architecture, which combines
@@ -194,11 +189,11 @@ Record Type 10 (hash table)
This record is a hashtable of 256 entries; a special property
is that all these records are stored consecutively to make one
big table. The hash value is simple the 1st, 2nd, ... byte of
- the keyid (depending on the indirection level).
+ the fingerprint (depending on the indirection level).
1 byte value 10
1 byte reserved
- n u32 recnum; n depends on th record length:
+ n u32 recnum; n depends on the record length:
n = (reclen-2)/4 which yields 9 for the current record length
of 40 bytes.
@@ -206,18 +201,15 @@ Record Type 10 (hash table)
m = (256+n-1) / n
which is 29 for a record length of 40.
- To look up a key we use its lsb to get the recnum from this
- hashtable and look up the addressed record:
- - If this record is another hashtable, we use 2nd lsb
+ To look up a key we use the first byte of the fingerprint to get
+ the recnum from this hashtable and look up the addressed record:
+ - If this record is another hashtable, we use 2nd byte
to index this hast table and so on.
- - if this record is a hashlist, we walk thru the
- reclist records until we found one whose hash field
- matches the MSB of our keyid, and lookup this record
- - if this record is a dir record, we compare the
- keyid and if this is correct, we get the keyrecod and compare
- the fingerprint to decide whether it is the requested key;
- if this is not the correct dir record, we look at the next
- dir record which is linked by the link field.
+ - if this record is a hashlist, we walk all entries
+ until we found one a matching one.
+ - if this record is a key record, we compare the
+ fingerprint and to decide whether it is the requested key;
+
Record type 11 (hash list)
--------------
@@ -226,11 +218,10 @@ Record type 11 (hash list)
1 byte value 11
1 byte reserved
1 u32 next next hash list record
- n times n = (reclen-6)/5
- 1 byte hash
+ n times n = (reclen-5)/5
1 u32 recnum
- For the current record length of 40, n is 6
+ For the current record length of 40, n is 7
diff --git a/doc/gpg.1pod b/doc/gpg.1pod
index 1fde885fa..5be04b6b3 100644
--- a/doc/gpg.1pod
+++ b/doc/gpg.1pod
@@ -5,6 +5,7 @@ gpg - GNU Privacy Guard
=head1 SYNOPSIS
B<gpg> [--homedir name] [--options file] [options] command [args]
+
B<gpgm> [--homedir name] [--options file] [options] command [args]
=head1 DESCRIPTION
@@ -98,23 +99,46 @@ B<--gen-key>
Generate a new key pair. This command can only be
used interactive.
-B<--add-key> I<name>
- Add a subkey to an already existing key. This
- command is similiar to B<--gen-key> but a primary
- key must already exit.
-
-B<--sign-key> I<name>
- Make a signature on key of user I<name>.
- This looks for the key, displays the key and checks
- all existing signatures of this key. If the key is
- not yet signed by the default user (or the users given
- with B<-u>), the program displays the information of
- the key again, together with its fingerprint and
- asks whether it should be signed. This question
- is repeated for all users specified with B<-u>.
- The key is then signed and the keyring which
- contains the key is updated.
+B<--edit-key> I<name>
+ Present a menu which enables you to do all key
+ related tasks:
+ B<sign>
+ Make a signature on key of user I<name>.
+ If the key is not yet signed by the default
+ user (or the users given with B<-u>), the
+ program displays the information of the key
+ again, together with its fingerprint and
+ asks whether it should be signed. This
+ question is repeated for all users specified
+ with B<-u>.
+ B<adduid>
+ Create an alternate user id.
+ B<deluid>
+ Delete an user id.
+ B<addkey>
+ Add a subkey to this key.
+ B<delkey>
+ Remove a subkey.
+ B<passwd>
+ Change the passphrase of the secret key.
+ B<check>
+ Check signatures
+ B<uid> I<n>
+ Toggle selection of user id with index I<n>.
+ Use 0 to deselect all.
+ B<key> I<n>
+ Toggle selection of subkey with index I<n>.
+ Use 0 to deselect all.
+ B<check>
+ Check all selected user ids.
+ B<toggle>
+ Toggle between public and secret key listing.
+ B<save>
+ Save all changes to the key rings and quit.
+ B<quit>
+ Quit the program without updating the
+ key rings.
B<--delete-key>
Remove key from the public keyring
@@ -122,12 +146,6 @@ B<--delete-key>
B<--delete-secret-key>
Remove key from the secret and public keyring
-B<--edit-key>
- Edit/remove a key signature.
-
-B<--change-passphrase>
- Change the passphrase of your secret keyring
-
B<--gen-revoke>
Generate a revocation certificate.
@@ -142,10 +160,15 @@ B<--export> [I<names>]
B<--import>
import/merge keys
-B<--list-ownertrust>
+B<--export-ownertrust>
List the assigned ownertrust values in ascii format for
backup purposes [B<gpgm> only].
+B<--import-ownertrust> [I<filename>]
+ Update the trustdb with the ownertrust values stored in
+ I<filename> (or stdin if not given); existing values will be
+ overwritten. [B<gpgm> only].
+
=head1 OPTIONS
Long options can be put in an options file (default F<~/.gnupg/options>);
diff --git a/g10/ChangeLog b/g10/ChangeLog
index badb5cd32..39e528de0 100644
--- a/g10/ChangeLog
+++ b/g10/ChangeLog
@@ -1,3 +1,26 @@
+Wed Jul 29 12:53:03 1998 Werner Koch (wk@(none))
+
+ * free-packet.c (copy_signature): New.
+
+ * keygen.c (generate_subkeypair): rewritten
+ * g10.c (aKeyadd): Removed option --add-key
+
+Mon Jul 27 10:37:28 1998 Werner Koch (wk@(none))
+
+ * seckey-cert.c (do_check): Additional check on cipher blocksize.
+ (protect_secret_key): Ditto.
+ * encr-data.c: Support for other blocksizes.
+ * cipher.c (write_header): Ditto.
+
+Fri Jul 24 16:47:59 1998 Werner Koch (wk@(none))
+
+ * kbnode.c (insert_kbnode): Changed semantics and all callers.
+ * keyedit.c : More or less a complete rewrite
+
+Wed Jul 22 17:10:04 1998 Werner Koch (wk@(none))
+
+ * build-packet.c (write_sign_packet_header): New.
+
Tue Jul 21 14:37:09 1998 Werner Koch (wk@(none))
* import.c (import_one): Now creates a trustdb record.
diff --git a/g10/Makefile.am b/g10/Makefile.am
index e97fb8cf4..0097ace5f 100644
--- a/g10/Makefile.am
+++ b/g10/Makefile.am
@@ -48,7 +48,6 @@ common_source = \
status.c \
status.h \
sign.c \
- keyedit.c \
plaintext.c \
encr-data.c \
encode.c \
@@ -61,6 +60,7 @@ gpg_SOURCES = g10.c \
$(common_source) \
verify.c \
decrypt.c \
+ keyedit.c \
keygen.c
diff --git a/g10/OPTIONS b/g10/OPTIONS
index aa8b46d6e..4def8e60e 100644
--- a/g10/OPTIONS
+++ b/g10/OPTIONS
@@ -57,3 +57,9 @@ compress-sigs
# Normally, compressing of signatures does not make sense; so this
# is disabled for detached signatures unless this option is used.
+
+emulate-pgp-sign-bug
+# PGP 2.x can only cope with 2 byte length headers of the
+# signature packets, this option forces.
+
+
diff --git a/g10/build-packet.c b/g10/build-packet.c
index ae5e08f15..c7ed8fa2a 100644
--- a/g10/build-packet.c
+++ b/g10/build-packet.c
@@ -51,6 +51,7 @@ static int calc_header_length( u32 len );
static int write_16(IOBUF inp, u16 a);
static int write_32(IOBUF inp, u32 a);
static int write_header( IOBUF out, int ctb, u32 len );
+static int write_sign_packet_header( IOBUF out, int ctb, u32 len );
static int write_header2( IOBUF out, int ctb, u32 len, int hdrlen, int blkmode );
static int write_new_header( IOBUF out, int ctb, u32 len, int hdrlen );
static int write_version( IOBUF out, int ctb );
@@ -669,7 +670,10 @@ do_signature( IOBUF out, int ctb, PKT_signature *sig )
for(i=0; i < n; i++ )
mpi_write(a, sig->data[i] );
- write_header(out, ctb, iobuf_get_temp_length(a) );
+ if( is_RSA(sig->pubkey_algo) && sig->version < 4 )
+ write_sign_packet_header(out, ctb, iobuf_get_temp_length(a) );
+ else
+ write_header(out, ctb, iobuf_get_temp_length(a) );
if( iobuf_write_temp( out, a ) )
rc = G10ERR_WRITE_FILE;
@@ -747,6 +751,18 @@ write_header( IOBUF out, int ctb, u32 len )
return write_header2( out, ctb, len, 0, 1 );
}
+
+static int
+write_sign_packet_header( IOBUF out, int ctb, u32 len )
+{
+ /* work around a bug in the pgp read function for signature packets,
+ * which are not correctly coded and silently assume at some
+ * point 2 byte length headers.*/
+ iobuf_put(out, 0x89 );
+ iobuf_put(out, len >> 8 );
+ return iobuf_put(out, len ) == -1 ? -1:0;
+}
+
/****************
* if HDRLEN is > 0, try to build a header of this length.
* we need this, so that we can hash packets without reading them again.
diff --git a/g10/cipher.c b/g10/cipher.c
index 0891d52fb..4c4e85f78 100644
--- a/g10/cipher.c
+++ b/g10/cipher.c
@@ -42,7 +42,8 @@ write_header( cipher_filter_context_t *cfx, IOBUF a )
{
PACKET pkt;
PKT_encrypted ed;
- byte temp[10];
+ byte temp[18];
+ unsigned blocksize;
memset( &ed, 0, sizeof ed );
ed.len = cfx->datalen;
@@ -52,15 +53,18 @@ write_header( cipher_filter_context_t *cfx, IOBUF a )
pkt.pkt.encrypted = &ed;
if( build_packet( a, &pkt ))
log_bug("build_packet(ENCR_DATA) failed\n");
- randomize_buffer( temp, 8, 1 );
- temp[8] = temp[6];
- temp[9] = temp[7];
+ blocksize = cipher_get_blocksize( cfx->dek->algo );
+ if( blocksize < 8 || blocksize > 16 )
+ log_fatal("unsupported blocksize %u\n", blocksize );
+ randomize_buffer( temp, blocksize, 1 );
+ temp[blocksize] = temp[blocksize-2];
+ temp[blocksize+1] = temp[blocksize-1];
cfx->cipher_hd = cipher_open( cfx->dek->algo, CIPHER_MODE_AUTO_CFB, 1 );
cipher_setkey( cfx->cipher_hd, cfx->dek->key, cfx->dek->keylen );
cipher_setiv( cfx->cipher_hd, NULL );
- cipher_encrypt( cfx->cipher_hd, temp, temp, 10);
+ cipher_encrypt( cfx->cipher_hd, temp, temp, blocksize+2);
cipher_sync( cfx->cipher_hd );
- iobuf_write(a, temp, 10);
+ iobuf_write(a, temp, blocksize+2);
cfx->header=1;
}
diff --git a/g10/encr-data.c b/g10/encr-data.c
index e7e56408a..b5eb0e0ee 100644
--- a/g10/encr-data.c
+++ b/g10/encr-data.c
@@ -49,7 +49,8 @@ decrypt_data( PKT_encrypted *ed, DEK *dek )
decode_filter_ctx_t dfx;
byte *p;
int rc, c, i;
- byte temp[16];
+ byte temp[32];
+ unsigned blocksize;
if( opt.verbose ) {
const char *s = cipher_algo_to_string( dek->algo );
@@ -60,7 +61,10 @@ decrypt_data( PKT_encrypted *ed, DEK *dek )
}
if( (rc=check_cipher_algo(dek->algo)) )
return rc;
- if( ed->len && ed->len < 10 )
+ blocksize = cipher_get_blocksize(dek->algo);
+ if( !blocksize || blocksize > 16 )
+ log_fatal("unsupported blocksize %u\n", blocksize );
+ if( ed->len && ed->len < (blocksize+2) )
log_bug("Nanu\n"); /* oops: found a bug */
dfx.cipher_hd = cipher_open( dek->algo, CIPHER_MODE_AUTO_CFB, 1 );
@@ -70,20 +74,20 @@ decrypt_data( PKT_encrypted *ed, DEK *dek )
if( ed->len ) {
iobuf_set_limit( ed->buf, ed->len );
- for(i=0; i < 10 && ed->len; i++, ed->len-- )
+ for(i=0; i < (blocksize+2) && ed->len; i++, ed->len-- )
temp[i] = iobuf_get(ed->buf);
}
else {
- for(i=0; i < 10; i++ )
+ for(i=0; i < (blocksize+2); i++ )
if( (c=iobuf_get(ed->buf)) == -1 )
break;
else
temp[i] = c;
}
- cipher_decrypt( dfx.cipher_hd, temp, temp, 10);
+ cipher_decrypt( dfx.cipher_hd, temp, temp, blocksize+2);
cipher_sync( dfx.cipher_hd );
p = temp;
- if( p[6] != p[8] || p[7] != p[9] ) {
+ if( p[blocksize-2] != p[blocksize] || p[blocksize-1] != p[blocksize+1] ) {
cipher_close(dfx.cipher_hd);
return G10ERR_BAD_KEY;
}
diff --git a/g10/free-packet.c b/g10/free-packet.c
index 9d623ec30..14a466556 100644
--- a/g10/free-packet.c
+++ b/g10/free-packet.c
@@ -55,7 +55,7 @@ void
free_seckey_enc( PKT_signature *sig )
{
int n, i;
- n = pubkey_get_nenc( sig->pubkey_algo );
+ n = pubkey_get_nsig( sig->pubkey_algo );
if( !n ) {
m_free(sig->data[0]);
sig->data[0] = NULL;
@@ -107,6 +107,20 @@ cp_fake_data( MPI a )
return d;
}
+static void *
+cp_data_block( byte *s )
+{
+ byte *d;
+ u16 len;
+
+ if( !s )
+ return NULL;
+ len = (s[0] << 8) | s[1];
+ d = m_alloc( len+2 );
+ memcpy(d, s, len+2);
+ return d;
+}
+
PKT_public_key *
copy_public_key( PKT_public_key *d, PKT_public_key *s )
@@ -126,6 +140,39 @@ copy_public_key( PKT_public_key *d, PKT_public_key *s )
return d;
}
+
+PKT_signature *
+copy_signature( PKT_signature *d, PKT_signature *s )
+{
+ int n, i;
+
+ if( !d )
+ d = m_alloc(sizeof *d);
+ memcpy( d, s, sizeof *d );
+ n = pubkey_get_nsig( s->pubkey_algo );
+ if( !n )
+ d->data[0] = cp_fake_data(s->data[0]);
+ else {
+ for(i=0; i < n; i++ )
+ d->data[i] = mpi_copy( s->data[i] );
+ }
+ d->hashed_data = cp_data_block(s->hashed_data);
+ d->unhashed_data = cp_data_block(s->unhashed_data);
+ return d;
+}
+
+
+PKT_user_id *
+copy_user_id( PKT_user_id *d, PKT_user_id *s )
+{
+ if( !d )
+ d = m_alloc(sizeof *d + s->len - 1 );
+ memcpy( d, s, sizeof *d + s->len - 1 );
+ return d;
+}
+
+
+
void
release_secret_key_parts( PKT_secret_key *sk )
{
diff --git a/g10/g10.c b/g10/g10.c
index dbd277d63..c7d8dfcc7 100644
--- a/g10/g10.c
+++ b/g10/g10.c
@@ -68,11 +68,8 @@ static ARGPARSE_OPTS opts[] = {
{ 558, "list-secret-keys", 256, N_("list secret keys")},
#ifdef IS_G10
{ 503, "gen-key", 256, N_("generate a new key pair")},
- { 554, "add-key", 256, N_("add a subkey to a key pair")},
- { 506, "sign-key" ,256, N_("make a signature on a key in the keyring")},
{ 505, "delete-key",256, N_("remove key from the public keyring")},
- { 524, "edit-key" ,256, N_("edit a key signature")},
- { 525, "change-passphrase", 256, N_("change the passphrase of your secret keyring")},
+ { 524, "edit-key" ,256, N_("sign or edit a key")},
{ 542, "gen-revoke",256, N_("generate a revocation certificate")},
#endif
{ 537, "export" , 256, N_("export keys") },
@@ -81,7 +78,8 @@ static ARGPARSE_OPTS opts[] = {
{ 530, "import", 256 , N_("import/merge keys")},
{ 521, "list-packets",256,N_("list only the sequence of packets")},
#ifdef IS_G10MAINT
- { 564, "list-ownertrust", 256, N_("list the ownertrust values")},
+ { 564, "export-ownertrust", 256, N_("export the ownertrust values")},
+ { 525, "import-ownertrust", 256 , N_("import ownertrust values")},
{ 567, "check-trustdb",0 , N_("|[NAMES]|check the trust database")},
{ 546, "dearmor", 256, N_("De-Armor a file or stdin") },
{ 547, "enarmor", 256, N_("En-Armor a file or stdin") },
@@ -153,6 +151,7 @@ static ARGPARSE_OPTS opts[] = {
{ 504, "delete-secret-key",0, "@" },
{ 524, "edit-sig" ,0, "@"}, /* alias for edit-key */
{ 523, "passphrase-fd",1, "@" },
+ { 506, "sign-key" ,256, "@" }, /* alias for edit-key */
#endif
{ 532, "quick-random", 0, "@"},
{ 526, "no-verbose", 0, "@"},
@@ -173,18 +172,18 @@ static ARGPARSE_OPTS opts[] = {
{ 566, "compress-sigs",0, "@"},
{ 559, "always-trust", 0, "@"},
{ 562, "emulate-checksum-bug", 0, "@"},
-
+ /*554 is unused */
{0} };
enum cmd_values { aNull = 0,
aSym, aStore, aEncr, aKeygen, aSign, aSignEncr,
aSignKey, aClearsign, aListPackets, aEditKey, aDeleteKey, aDeleteSecretKey,
- aKMode, aKModeC, aChangePass, aImport, aVerify, aDecrypt, aListKeys,
- aListSigs, aKeyadd, aListSecretKeys,
- aExport, aExportSecret,
+ aKMode, aKModeC, aImport, aVerify, aDecrypt, aListKeys,
+ aListSigs, aListSecretKeys, aExport, aExportSecret,
aCheckKeys, aGenRevoke, aPrimegen, aPrintMD, aPrintMDs,
- aCheckTrustDB, aListTrustDB, aListTrustPath, aListOwnerTrust,
+ aCheckTrustDB, aListTrustDB, aListTrustPath,
+ aExportOwnerTrust, aImportOwnerTrust,
aDeArmor, aEnArmor, aGenRandom,
aTest };
@@ -521,7 +520,6 @@ main( int argc, char **argv )
case 507: set_cmd( &cmd, aStore); break;
case 523: set_passphrase_fd( pargs.r.ret_int ); break;
case 524: set_cmd( &cmd, aEditKey); break;
- case 525: set_cmd( &cmd, aChangePass); break;
case 527: def_cipher_string = m_strdup(pargs.r.ret_str); break;
case 529: def_digest_string = m_strdup(pargs.r.ret_str); break;
case 539: set_cmd( &cmd, aClearsign); break;
@@ -548,7 +546,8 @@ main( int argc, char **argv )
case 546: set_cmd( &cmd, aDeArmor); break;
case 547: set_cmd( &cmd, aEnArmor); break;
case 555: set_cmd( &cmd, aPrintMD); break;
- case 564: set_cmd( &cmd, aListOwnerTrust); break;
+ case 564: set_cmd( &cmd, aExportOwnerTrust); break;
+ case 525: set_cmd( &cmd, aImportOwnerTrust); break;
#endif /* IS_G10MAINT */
case 'o': opt.outfile = pargs.r.ret_str; break;
@@ -564,7 +563,7 @@ main( int argc, char **argv )
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 515: opt.fingerprint++; break;
case 517: append_to_strlist( &sec_nrings, pargs.r.ret_str); break;
case 518:
/* config files may not be nested (silently ignore them) */
@@ -595,17 +594,17 @@ main( int argc, char **argv )
case 551: set_cmd( &cmd, aListKeys); break;
case 552: set_cmd( &cmd, aListSigs); break;
case 553: opt.skip_verify=1; break;
- case 554: set_cmd( &cmd, aKeyadd); break;
case 556: opt.def_compress_algo = pargs.r.ret_int; break;
case 557: opt.compress_keys = 1; break;
case 558: set_cmd( &cmd, aListSecretKeys); break;
case 559: opt.always_trust = 1; break;
case 560: register_cipher_extension(pargs.r.ret_str); break;
- case 561: opt.rfc1991 = 1; break;
- case 562: opt.emulate_bugs |= 1; break;
+ case 561: opt.rfc1991 = 1; opt.no_comment = 1; break;
+ case 562: opt.emulate_bugs |= EMUBUG_GPGCHKSUM; break;
case 563: set_cmd( &cmd, aExportSecret); break;
case 565: opt.do_not_export_rsa = 1; break;
case 566: opt.compress_sigs = 1; break;
+ case 554:
default : errors++; pargs.err = configfp? 1:2; break;
}
}
@@ -722,7 +721,7 @@ main( int argc, char **argv )
if( opt.with_colons ) /* need this to list the trust */
rc = init_trustdb(1, trustdb_name );
break;
- case aListOwnerTrust: rc = init_trustdb( 0, trustdb_name ); break;
+ case aExportOwnerTrust: rc = init_trustdb( 0, trustdb_name ); break;
case aListTrustDB: rc = init_trustdb( argc? 1:0, trustdb_name ); break;
default: rc = init_trustdb(1, trustdb_name ); break;
}
@@ -808,19 +807,10 @@ main( int argc, char **argv )
case aSignKey: /* sign the key given as argument */
- if( argc != 1 )
- 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", print_fname_stdin(fname), g10_errstr(rc) );
- break;
-
case aEditKey: /* Edit a key signature */
if( argc != 1 )
wrong_args(_("--edit-key username"));
- /* note: fname is the user id! */
- if( (rc = edit_keysigs(fname)) )
- log_error("%s: edit signature failed: %s\n", print_fname_stdin(fname), g10_errstr(rc) );
+ keyedit_menu(fname, locusr );
break;
case aDeleteSecretKey:
@@ -834,14 +824,6 @@ main( int argc, char **argv )
log_error("%s: delete key failed: %s\n", print_fname_stdin(fname), g10_errstr(rc) );
break;
- case aChangePass: /* Change the passphrase */
- if( argc > 1 ) /* no arg: use default, 1 arg use this one */
- wrong_args(_("--change-passphrase [username]"));
- /* note: fname is the user id! */
- if( (rc = change_passphrase(fname)) )
- log_error("%s: change passphrase failed: %s\n", print_fname_stdin(fname),
- g10_errstr(rc) );
- break;
#endif /* IS_G10 */
case aCheckKeys:
@@ -880,11 +862,6 @@ main( int argc, char **argv )
wrong_args("--gen-key");
generate_keypair();
break;
- case aKeyadd: /* add a subkey (interactive) */
- if( argc != 1 )
- wrong_args("--add-key userid");
- generate_subkeypair(*argv);
- break;
#endif
case aImport:
@@ -1049,10 +1026,16 @@ main( int argc, char **argv )
list_trust_path( atoi(*argv), argv[1] );
break;
- case aListOwnerTrust:
+ case aExportOwnerTrust:
if( argc )
- wrong_args("--list-ownertrust");
- list_ownertrust();
+ wrong_args("--export-ownertrust");
+ export_ownertrust();
+ break;
+
+ case aImportOwnerTrust:
+ if( argc > 1 )
+ wrong_args("--import-ownertrust [file]");
+ import_ownertrust( argc? *argv:NULL );
break;
#endif /* IS_G10MAINT */
diff --git a/g10/import.c b/g10/import.c
index ec143dce2..c5eaf9ba8 100644
--- a/g10/import.c
+++ b/g10/import.c
@@ -851,7 +851,7 @@ merge_sigs( KBNODE dst, KBNODE src, int *n_sigs,
* We add a clone to the original keyblock, because this
* one is released first */
n2 = clone_kbnode(n);
- insert_kbnode( dst, n2, PKT_USER_ID );
+ insert_kbnode( dst, n2, PKT_SIGNATURE );
n2->flag |= 1;
n->flag |= 1;
++*n_sigs;
diff --git a/g10/kbnode.c b/g10/kbnode.c
index 4578f8271..428768105 100644
--- a/g10/kbnode.c
+++ b/g10/kbnode.c
@@ -94,7 +94,8 @@ add_kbnode( KBNODE root, KBNODE node )
}
/****************
- * Insert NODE into the list after root but before a packet with type PKTTYPE
+ * Insert NODE into the list after root but before a packet which is not of
+ * type PKTTYPE
* (only if PKTTYPE != 0)
*/
void
@@ -108,7 +109,7 @@ insert_kbnode( KBNODE root, KBNODE node, int pkttype )
KBNODE n1;
for(n1=root; n1->next; n1 = n1->next)
- if( pkttype == n1->next->pkt->pkttype ) {
+ if( pkttype != n1->next->pkt->pkttype ) {
node->next = n1->next;
n1->next = node;
return;
diff --git a/g10/keydb.h b/g10/keydb.h
index bbd803fbe..85ab88b45 100644
--- a/g10/keydb.h
+++ b/g10/keydb.h
@@ -133,6 +133,8 @@ unsigned nbits_from_sk( PKT_secret_key *sk );
const char *datestr_from_pk( PKT_public_key *pk );
const char *datestr_from_sk( PKT_secret_key *sk );
const char *datestr_from_sig( PKT_signature *sig );
+const char *expirestr_from_pk( PKT_public_key *pk );
+const char *expirestr_from_sk( PKT_secret_key *sk );
byte *fingerprint_from_sk( PKT_secret_key *sk, byte *buf, size_t *ret_len );
byte *fingerprint_from_pk( PKT_public_key *pk, byte *buf, size_t *ret_len );
@@ -149,6 +151,7 @@ KBNODE find_kbnode( KBNODE node, int pkttype );
KBNODE walk_kbnode( KBNODE root, KBNODE *context, int all );
void clear_kbnode_flags( KBNODE n );
int commit_kbnode( KBNODE *root );
+void dump_kbnode( KBNODE node );
/*-- ringedit.c --*/
int add_keyblock_resource( const char *filename, int force, int secret );
diff --git a/g10/keyedit.c b/g10/keyedit.c
index 4369e9a86..73772328b 100644
--- a/g10/keyedit.c
+++ b/g10/keyedit.c
@@ -24,6 +24,7 @@
#include <string.h>
#include <errno.h>
#include <assert.h>
+#include <ctype.h>
#include "options.h"
#include "packet.h"
@@ -37,73 +38,60 @@
#include "ttyio.h"
#include "i18n.h"
+static void show_key_with_all_names( KBNODE keyblock,
+ int only_marked, int with_fpr, int with_subkeys );
+static void show_key_and_fingerprint( KBNODE keyblock );
+static void show_fingerprint( PKT_public_key *pk );
+static int menu_adduid( KBNODE keyblock, KBNODE sec_keyblock );
+static void menu_deluid( KBNODE pub_keyblock, KBNODE sec_keyblock );
+static void menu_delkey( KBNODE pub_keyblock, KBNODE sec_keyblock );
+static int menu_select_uid( KBNODE keyblock, int index );
+static int menu_select_key( KBNODE keyblock, int index );
+static int count_uids( KBNODE keyblock );
+static int count_uids_with_flag( KBNODE keyblock, unsigned flag );
+static int count_keys_with_flag( KBNODE keyblock, unsigned flag );
+static int count_selected_uids( KBNODE keyblock );
+static int count_selected_keys( KBNODE keyblock );
-static void
-show_fingerprint( PKT_public_key *pk )
-{
- byte *array, *p;
- size_t i, n;
- p = array = fingerprint_from_pk( pk, NULL, &n );
- tty_printf(" Fingerprint:");
- if( n == 20 ) {
- for(i=0; i < n ; i++, i++, p += 2 ) {
- if( i == 10 )
- tty_printf(" ");
- tty_printf(" %02X%02X", *p, p[1] );
- }
- }
- else {
- for(i=0; i < n ; i++, p++ ) {
- if( i && !(i%8) )
- tty_printf(" ");
- tty_printf(" %02X", *p );
- }
- }
- tty_printf("\n");
- m_free(array);
-}
+#define NODFLG_BADSIG (1<<0) /* bad signature */
+#define NODFLG_NOKEY (1<<1) /* no public key */
+#define NODFLG_SIGERR (1<<2) /* other sig error */
+
+#define NODFLG_MARK_A (1<<4) /* temporary mark */
+
+#define NODFLG_SELUID (1<<8) /* indicate the selected userid */
+#define NODFLG_SELKEY (1<<9) /* indicate the selected key */
-/****************
- * Ask whether the user is willing to sign the key. Return true if so.
- */
static int
-sign_it_p( PKT_public_key *pk, PKT_user_id *uid )
+get_keyblock_byname( KBNODE *keyblock, KBPOS *kbpos, const char *username )
{
- char *answer;
- int yes;
+ int rc;
- tty_printf("\n");
- tty_printf(_("Are you really sure that you want to sign this key:\n\n"));
- tty_printf("pub %4u%c/%08lX %s ",
- nbits_from_pk( pk ),
- pubkey_letter( pk->pubkey_algo ),
- (ulong)keyid_from_pk( pk, NULL ),
- datestr_from_pk( pk ) );
- tty_print_string( uid->name, uid->len );
- tty_printf("\n");
- show_fingerprint(pk);
- tty_printf("\n");
- answer = tty_get(_("Sign this key? "));
- tty_kill_prompt();
- yes = answer_is_yes(answer);
- m_free(answer);
- return yes;
+ *keyblock = NULL;
+ /* search the userid */
+ rc = find_keyblock_byname( kbpos, username );
+ if( rc ) {
+ log_error(_("%s: user not found\n"), username );
+ return rc;
+ }
+
+ /* read the keyblock */
+ rc = read_keyblock( kbpos, keyblock );
+ if( rc )
+ log_error("%s: keyblock read problem: %s\n", username, g10_errstr(rc));
+ return rc;
}
/****************
* Check the keysigs and set the flags to indicate errors.
- * Usage of nodes flag bits:
- * Bit 0 = bad signature
- * 1 = no public key
- * 2 = other error
* Returns true if error found.
*/
static int
-check_all_keysigs( KBNODE keyblock )
+check_all_keysigs( KBNODE keyblock, int only_selected )
{
KBNODE kbctx;
KBNODE node;
@@ -111,337 +99,217 @@ check_all_keysigs( KBNODE keyblock )
int inv_sigs = 0;
int no_key = 0;
int oth_err = 0;
+ int has_selfsig = 0;
+ int mis_selfsig = 0;
+ int selected = !only_selected;
+ int anyuid = 0;
for( kbctx=NULL; (node=walk_kbnode( keyblock, &kbctx, 0)) ; ) {
- if( node->pkt->pkttype == PKT_SIGNATURE
- && (node->pkt->pkt.signature->sig_class&~3) == 0x10 ) {
- PKT_signature *sig = node->pkt->pkt.signature;
- int sigrc;
-
- tty_printf("sig");
- switch( (rc = check_key_signature( keyblock, node,NULL)) ) {
- case 0: node->flag = 0; sigrc = '!'; break;
- case G10ERR_BAD_SIGN: inv_sigs++; node->flag = 1; sigrc = '-'; break;
- case G10ERR_NO_PUBKEY: no_key++; node->flag = 2; sigrc = '?'; break;
- default: oth_err++; node->flag = 4; sigrc = '%'; break;
- }
- tty_printf("%c %08lX %s ",
- sigrc, sig->keyid[1], datestr_from_sig(sig));
- if( sigrc == '%' )
- tty_printf("[%s] ", g10_errstr(rc) );
- else if( sigrc == '?' )
- ;
- else {
- size_t n;
- char *p = get_user_id( sig->keyid, &n );
- tty_print_string( p, n > 40? 40 : n );
- m_free(p);
+ if( node->pkt->pkttype == PKT_USER_ID ) {
+ PKT_user_id *uid = node->pkt->pkt.user_id;
+
+ if( only_selected )
+ selected = (node->flag & NODFLG_SELUID);
+ if( selected ) {
+ tty_printf("uid ");
+ tty_print_string( uid->name, uid->len );
+ tty_printf("\n");
+ if( anyuid && !has_selfsig )
+ mis_selfsig++;
+ has_selfsig = 0;
+ anyuid = 1;
}
- tty_printf("\n");
- /* FIXME: update the trustdb */
}
- }
- if( inv_sigs )
- tty_printf(_("%d bad signatures\n"), inv_sigs );
- if( no_key )
- tty_printf(_("No public key for %d signatures\n"), no_key );
- if( oth_err )
- tty_printf(_("%d signatures not checked due to errors\n"), oth_err );
- return inv_sigs || no_key || oth_err;
-}
-
-
-/****************
- * Ask and remove invalid signatures that are to be removed.
- */
-static int
-remove_keysigs( KBNODE keyblock, u32 *keyid, int all )
-{
- KBNODE kbctx;
- KBNODE node;
- char *answer;
- int yes;
- int count;
-
- count = 0;
- for( kbctx=NULL; (node=walk_kbnode( keyblock, &kbctx, 0)) ; ) {
- if( ((node->flag & 7) || all )
- && node->pkt->pkttype == PKT_SIGNATURE
- && (node->pkt->pkt.signature->sig_class&~3) == 0x10 ) {
+ else if( selected && node->pkt->pkttype == PKT_SIGNATURE
+ && (node->pkt->pkt.signature->sig_class&~3) == 0x10 ) {
PKT_signature *sig = node->pkt->pkt.signature;
+ int sigrc, selfsig;
- tty_printf("\n \"%08lX %s ",
- sig->keyid[1], datestr_from_sig(sig));
- if( node->flag & 6 )
- tty_printf(_("[User name not available] "));
- else {
- size_t n;
- char *p = get_user_id( sig->keyid, &n );
- tty_print_string( p, n );
- m_free(p);
- }
- tty_printf("\"\n");
- if( node->flag & 1 )
- tty_printf(_("This is a BAD signature!\n"));
- else if( node->flag & 2 )
- tty_printf(_("Public key not available.\n"));
- else if( node->flag & 4 )
- tty_printf(_("The signature could not be checked!\n"));
-
- if( keyid[0] == sig->keyid[0] && keyid[1] == sig->keyid[1] ) {
- tty_printf(_("Skipped self-signature\n"));
- continue; /* do not remove self-signatures */
+ switch( (rc = check_key_signature( keyblock, node, &selfsig)) ) {
+ case 0:
+ node->flag &= ~(NODFLG_BADSIG|NODFLG_NOKEY|NODFLG_SIGERR);
+ sigrc = '!';
+ break;
+ case G10ERR_BAD_SIGN:
+ node->flag = NODFLG_BADSIG;
+ sigrc = '-';
+ inv_sigs++;
+ break;
+ case G10ERR_NO_PUBKEY:
+ node->flag = NODFLG_NOKEY;
+ sigrc = '?';
+ no_key++;
+ break;
+ default:
+ node->flag = NODFLG_SIGERR;
+ sigrc = '%';
+ oth_err++;
+ break;
}
-
- tty_printf("\n");
- answer = tty_get(_("Remove this signature? "));
- tty_kill_prompt();
- if( answer_is_yes(answer) ) {
- node->flag |= 128; /* use bit 7 to mark this node */
- count++;
+ if( sigrc != '?' ) {
+ tty_printf("sig%c %08lX %s ",
+ sigrc, sig->keyid[1], datestr_from_sig(sig));
+ if( sigrc == '%' )
+ tty_printf("[%s] ", g10_errstr(rc) );
+ else if( sigrc == '?' )
+ ;
+ else if( selfsig ) {
+ tty_printf( _("[self-signature]") );
+ if( sigrc == '!' )
+ has_selfsig = 1;
+ }
+ else {
+ size_t n;
+ char *p = get_user_id( sig->keyid, &n );
+ tty_print_string( p, n > 40? 40 : n );
+ m_free(p);
+ }
+ tty_printf("\n");
+ /* fixme: Should we update the trustdb here */
}
- m_free(answer);
}
}
+ if( !has_selfsig )
+ mis_selfsig++;
+ if( inv_sigs == 1 )
+ tty_printf(_("1 bad signature\n"), inv_sigs );
+ else if( inv_sigs )
+ tty_printf(_("%d bad signatures\n"), inv_sigs );
+ if( no_key == 1 )
+ tty_printf(_("1 signature not checked due to a missing key\n") );
+ else if( no_key )
+ tty_printf(_("%d signatures not checked due to missing keys\n"), no_key );
+ if( oth_err == 1 )
+ tty_printf(_("1 signature not checked due to an error\n") );
+ else if( oth_err )
+ tty_printf(_("%d signatures not checked due to errors\n"), oth_err );
+ if( mis_selfsig == 1 )
+ tty_printf(_("1 user id without valid self-signature detected\n"));
+ else if( mis_selfsig )
+ tty_printf(_("%d user ids without valid self-signatures detected\n"),
+ mis_selfsig);
- if( !count )
- return 0; /* nothing to remove */
- answer = tty_get(_("Do you really want to remove the selected signatures? "));
- tty_kill_prompt();
- yes = answer_is_yes(answer);
- m_free(answer);
- if( !yes )
- return 0;
-
- for( kbctx=NULL; (node=walk_kbnode( keyblock, &kbctx, 1)) ; ) {
- if( node->flag & 128)
- delete_kbnode(node );
- }
-
- return 1;
+ return inv_sigs || no_key || oth_err || mis_selfsig;
}
+
/****************
- * This function signs the key of USERNAME with all users listed in
- * LOCUSR. If LOCUSR is NULL the default secret certificate will
- * be used. This works on all keyrings, so there is no armor or
- * compress stuff here.
+ * Loop over all locusr and and sign the uids after asking.
+ * If no user id is marked, all user ids will be signed;
+ * if some user_ids are marked those will be signed.
+ *
+ * fixme: Add support for our proposed sign-all scheme
*/
-int
-sign_key( const char *username, STRLIST locusr )
+static int
+sign_uids( KBNODE keyblock, STRLIST locusr, int *ret_modified )
{
- md_filter_context_t mfx;
int rc = 0;
SK_LIST sk_list = NULL;
SK_LIST sk_rover = NULL;
- KBNODE keyblock = NULL;
- KBNODE kbctx, node;
- KBPOS kbpos;
- PKT_public_key *pk;
- u32 pk_keyid[2];
- char *answer;
-
- memset( &mfx, 0, sizeof mfx);
-
- /* search the userid */
- rc = find_keyblock_byname( &kbpos, username );
- if( rc ) {
- log_error(_("%s: user not found\n"), username );
- goto leave;
- }
+ KBNODE node, uidnode;
+ PKT_public_key *primary_pk;
+ int select_all = !count_selected_uids(keyblock);
/* build a list of all signators */
rc=build_sk_list( locusr, &sk_list, 0, 1 );
if( rc )
goto leave;
-
- /* read the keyblock */
- rc = read_keyblock( &kbpos, &keyblock );
- if( rc ) {
- log_error("error reading the certificate: %s\n", g10_errstr(rc) );
- goto leave;
- }
-
- /* get the keyid from the keyblock */
- node = find_kbnode( keyblock, PKT_PUBLIC_KEY );
- if( !node ) {
- log_error("Oops; public key not found anymore!\n");
- rc = G10ERR_GENERAL;
- goto leave;
- }
-
- pk = node->pkt->pkt.public_key;
- keyid_from_pk( pk, pk_keyid );
- tty_printf(_("Checking signatures of this public key certificate:\n"));
- tty_printf("pub %4u%c/%08lX %s ",
- nbits_from_pk( pk ),
- pubkey_letter( pk->pubkey_algo ),
- pk_keyid[1], datestr_from_pk(pk) );
- {
+ /* loop over all signaturs */
+ for( sk_rover = sk_list; sk_rover; sk_rover = sk_rover->next ) {
+ u32 sk_keyid[2];
size_t n;
- char *p = get_user_id( pk_keyid, &n );
- tty_print_string( p, n > 40? 40 : n );
- m_free(p);
- tty_printf("\n");
- }
+ char *p;
- clear_kbnode_flags( keyblock );
- if( check_all_keysigs( keyblock ) ) {
- if( !opt.batch ) {
- /* ask whether we really should do anything */
- answer = tty_get(
- _("Do you want to remove some of the invalid signatures? "));
- tty_kill_prompt();
- if( answer_is_yes(answer) )
- remove_keysigs( keyblock, pk_keyid, 0 );
- m_free(answer);
+ keyid_from_sk( sk_rover->sk, sk_keyid );
+ /* set mark A for all selected user ids */
+ for( node=keyblock; node; node = node->next ) {
+ if( select_all || (node->flag & NODFLG_SELUID) )
+ node->flag |= NODFLG_MARK_A;
+ else
+ node->flag &= ~NODFLG_MARK_A;
}
- }
-
- /* check whether we it is possible to sign this key */
- for( sk_rover = sk_list; sk_rover; sk_rover = sk_rover->next ) {
- u32 akeyid[2];
-
- keyid_from_sk( sk_rover->sk, akeyid );
- for( kbctx=NULL; (node=walk_kbnode( keyblock, &kbctx, 0)) ; ) {
- if( node->pkt->pkttype == PKT_USER_ID )
- sk_rover->mark = 1;
- else if( node->pkt->pkttype == PKT_SIGNATURE
+ /* reset mark for uids which are already signed */
+ uidnode = NULL;
+ for( node=keyblock; node; node = node->next ) {
+ if( node->pkt->pkttype == PKT_USER_ID ) {
+ uidnode = (node->flag & NODFLG_MARK_A)? node : NULL;
+ }
+ else if( uidnode && node->pkt->pkttype == PKT_SIGNATURE
&& (node->pkt->pkt.signature->sig_class&~3) == 0x10 ) {
- if( akeyid[0] == node->pkt->pkt.signature->keyid[0]
- && akeyid[1] == node->pkt->pkt.signature->keyid[1] ) {
- log_info(_("Already signed by keyid %08lX\n"),
- (ulong)akeyid[1] );
- sk_rover->mark = 0;
+ if( sk_keyid[0] == node->pkt->pkt.signature->keyid[0]
+ && sk_keyid[1] == node->pkt->pkt.signature->keyid[1] ) {
+ tty_printf(_("Already signed by key %08lX\n"),
+ (ulong)sk_keyid[1] );
+ uidnode->flag &= ~NODFLG_MARK_A; /* remove mark */
}
}
}
- }
- for( sk_rover = sk_list; sk_rover; sk_rover = sk_rover->next ) {
- if( sk_rover->mark )
- break;
- }
- if( !sk_rover ) {
- log_info(_("Nothing to sign\n"));
- goto leave;
- }
-
- /* Loop over all signers and all user ids and sign */
- /* FIXME: we have to change it: Present all user-ids and
- * then ask whether all those ids shall be signed if the user
- * answers yes, go and make a 0x14 sign class packet and remove
- * old one-user-id-only-sigs (user should be noted of this
- * condition while presenting the user-ids); if he had answered
- * no, present each user-id in turn and ask which one should be signed
- * (only one) - if there is already a single-user-sig, do nothing.
- * (this is propably already out in the world) */
- for( sk_rover = sk_list; sk_rover; sk_rover = sk_rover->next ) {
- if( !sk_rover->mark )
+ /* check whether any uids are left for signing */
+ if( !count_uids_with_flag(keyblock, NODFLG_MARK_A) ) {
+ tty_printf(_("Nothing to sign with key %08lX\n"),
+ (ulong)sk_keyid[1] );
continue;
- for( kbctx=NULL; (node=walk_kbnode( keyblock, &kbctx, 0)) ; ) {
- if( node->pkt->pkttype == PKT_USER_ID ) {
- if( sign_it_p( pk, node->pkt->pkt.user_id ) ) {
- PACKET *pkt;
- PKT_signature *sig;
-
- rc = make_keysig_packet( &sig, pk,
- node->pkt->pkt.user_id,
- NULL,
- sk_rover->sk,
- 0x10, 0, NULL, NULL );
- if( rc ) {
- log_error("make_keysig_packet failed: %s\n", g10_errstr(rc));
- goto leave;
- }
-
- pkt = m_alloc_clear( sizeof *pkt );
- pkt->pkttype = PKT_SIGNATURE;
- pkt->pkt.signature = sig;
- insert_kbnode( node, new_kbnode(pkt), PKT_USER_ID );
+ }
+ /* Ask whether we realy should sign these user id(s) */
+ tty_printf("\n");
+ show_key_with_all_names( keyblock, 1, 1, 0 );
+ tty_printf("\n");
+ tty_printf(_(
+ "Are you really sure that you want to sign this key\n"
+ "with your key: \""));
+ p = get_user_id( sk_keyid, &n );
+ tty_print_string( p, n );
+ tty_printf("\"\n\n");
+ m_free(p);
+ p = tty_get(_("Really sign? "));
+ tty_kill_prompt();
+ if( !answer_is_yes(p) ) {
+ m_free(p);
+ continue; /* No */
+ }
+ m_free(p);
+ /* now we can sign the user ids */
+ reloop: /* (must use this, because we are modifing the list) */
+ primary_pk = NULL;
+ for( node=keyblock; node; node = node->next ) {
+ if( node->pkt->pkttype == PKT_PUBLIC_KEY )
+ primary_pk = node->pkt->pkt.public_key;
+ else if( node->pkt->pkttype == PKT_USER_ID
+ && (node->flag & NODFLG_MARK_A) ) {
+ PACKET *pkt;
+ PKT_signature *sig;
+
+ assert( primary_pk );
+ node->flag &= ~NODFLG_MARK_A;
+ rc = make_keysig_packet( &sig, primary_pk,
+ node->pkt->pkt.user_id,
+ NULL,
+ sk_rover->sk,
+ 0x10, 0, NULL, NULL );
+ if( rc ) {
+ log_error(_("signing failed: %s\n"), g10_errstr(rc));
+ goto leave;
}
+ *ret_modified = 1; /* we changed the keyblock */
+
+ pkt = m_alloc_clear( sizeof *pkt );
+ pkt->pkttype = PKT_SIGNATURE;
+ pkt->pkt.signature = sig;
+ insert_kbnode( node, new_kbnode(pkt), PKT_SIGNATURE );
+ goto reloop;
}
}
- }
-
- rc = update_keyblock( &kbpos, keyblock );
- if( rc ) {
- log_error("update_keyblock failed: %s\n", g10_errstr(rc) );
- goto leave;
- }
+ } /* end loop over signators */
leave:
- release_kbnode( keyblock );
release_sk_list( sk_list );
- md_close( mfx.md );
return rc;
}
-int
-edit_keysigs( const char *username )
-{
- int rc = 0;
- KBNODE keyblock = NULL;
- KBNODE node;
- KBPOS kbpos;
- PKT_public_key *pk;
- u32 pk_keyid[2];
-
- /* search the userid */
- rc = find_keyblock_byname( &kbpos, username );
- if( rc ) {
- log_error(_("%s: user not found\n"), username );
- goto leave;
- }
-
- /* read the keyblock */
- rc = read_keyblock( &kbpos, &keyblock );
- if( rc ) {
- log_error("%s: certificate read problem: %s\n", username, g10_errstr(rc) );
- goto leave;
- }
-
- /* get the keyid from the keyblock */
- node = find_kbnode( keyblock, PKT_PUBLIC_KEY );
- if( !node ) {
- log_error("Oops; public key not found anymore!\n");
- rc = G10ERR_GENERAL;
- goto leave;
- }
-
- pk = node->pkt->pkt.public_key;
- keyid_from_pk( pk, pk_keyid );
- tty_printf(_("Checking signatures of this public key certificate:\n"));
- tty_printf("pub %4u%c/%08lX %s ",
- nbits_from_pk( pk ),
- pubkey_letter( pk->pubkey_algo ),
- pk_keyid[1], datestr_from_pk(pk) );
- {
- size_t n;
- char *p = get_user_id( pk_keyid, &n );
- tty_print_string( p, n > 40? 40 : n );
- m_free(p);
- tty_printf("\n");
- }
-
- clear_kbnode_flags( keyblock );
- check_all_keysigs( keyblock );
- if( remove_keysigs( keyblock, pk_keyid, 1 ) ) {
- rc = update_keyblock( &kbpos, keyblock );
- if( rc ) {
- log_error("update_keyblock failed: %s\n", g10_errstr(rc) );
- goto leave;
- }
- }
-
- leave:
- release_kbnode( keyblock );
- return rc;
-}
-
/****************
* Delete a public or secret key from a keyring.
@@ -560,66 +428,26 @@ delete_key( const char *username, int secret )
}
-int
-change_passphrase( const char *username )
+/****************
+ * Change the passphrase of the primary and all secondary keys.
+ * We use only one passphrase for all keys.
+ */
+static int
+change_passphrase( KBNODE keyblock )
{
int rc = 0;
- KBNODE keyblock = NULL;
+ int changed=0;
KBNODE node;
- KBPOS kbpos;
PKT_secret_key *sk;
- u32 keyid[2];
- char *answer;
- int changed=0;
char *passphrase = NULL;
- /* find the userid */
- rc = find_secret_keyblock_byname( &kbpos, username );
- if( rc ) {
- log_error("secret key for user '%s' not found\n", username );
- goto leave;
- }
-
- /* read the keyblock */
- rc = read_keyblock( &kbpos, &keyblock );
- if( rc ) {
- log_error("error reading the certificate: %s\n", g10_errstr(rc) );
- goto leave;
- }
-
- /* get the keyid from the keyblock */
node = find_kbnode( keyblock, PKT_SECRET_KEY );
if( !node ) {
log_error("Oops; secret key not found anymore!\n");
- rc = G10ERR_GENERAL;
goto leave;
}
-
sk = node->pkt->pkt.secret_key;
- keyid_from_sk( sk, keyid );
- tty_printf("sec %4u%c/%08lX %s ",
- nbits_from_sk( sk ),
- pubkey_letter( sk->pubkey_algo ),
- keyid[1], datestr_from_sk(sk) );
- {
- size_t n;
- char *p = get_user_id( keyid, &n );
- tty_print_string( p, n );
- m_free(p);
- tty_printf("\n");
- }
- for(node=keyblock; node; node = node->next ) {
- if( node->pkt->pkttype == PKT_SECRET_SUBKEY ) {
- PKT_secret_key *subsk = node->pkt->pkt.secret_key;
- keyid_from_sk( subsk, keyid );
- tty_printf("sub %4u%c/%08lX %s\n",
- nbits_from_sk( subsk ),
- pubkey_letter( subsk->pubkey_algo ),
- keyid[1], datestr_from_sk(subsk) );
- }
- }
- clear_kbnode_flags( keyblock );
switch( is_secret_key_protected( sk ) ) {
case -1:
rc = G10ERR_PUBKEY_ALGO;
@@ -636,13 +464,11 @@ change_passphrase( const char *username )
}
/* unprotect all subkeys (use the supplied passphrase or ask)*/
- for(node=keyblock; node; node = node->next ) {
+ for(node=keyblock; !rc && node; node = node->next ) {
if( node->pkt->pkttype == PKT_SECRET_SUBKEY ) {
PKT_secret_key *subsk = node->pkt->pkt.secret_key;
set_next_passphrase( passphrase );
rc = check_secret_key( subsk );
- if( rc )
- break;
}
}
@@ -666,11 +492,9 @@ change_passphrase( const char *username )
rc = 0;
tty_printf(_( "You don't want a passphrase -"
" this is probably a *bad* idea!\n\n"));
- answer = tty_get(_("Do you really want to do this? "));
- tty_kill_prompt();
- if( answer_is_yes(answer) )
+ if( tty_get_answer_is_yes(_(
+ "Do you really want to do this? ")))
changed++;
- m_free(answer);
break;
}
else { /* okay */
@@ -696,128 +520,746 @@ change_passphrase( const char *username )
m_free(dek);
}
+ leave:
+ m_free( passphrase );
+ set_next_passphrase( NULL );
+ return changed && !rc;
+}
+
+
+
+
+/****************
+ * Menu driven key editor
+ *
+ * Note: to keep track of some selection we use node->mark MARKBIT_xxxx.
+ */
+
+void
+keyedit_menu( const char *username, STRLIST locusr )
+{
+ enum cmdids { cmdNONE = 0,
+ cmdQUIT, cmdHELP, cmdFPR, cmdLIST, cmdSELUID, cmdCHECK, cmdSIGN,
+ cmdDEBUG, cmdSAVE, cmdADDUID, cmdDELUID, cmdADDKEY, cmdDELKEY,
+ cmdTOGGLE, cmdSELKEY, cmdPASSWD,
+ cmdNOP };
+ static struct { const char *name;
+ enum cmdids id;
+ int need_sk;
+ const char *desc;
+ } cmds[] = {
+ { N_("quit") , cmdQUIT , 0, N_("quit this menu") },
+ { N_("q") , cmdQUIT , 0, NULL },
+ { N_("save") , cmdSAVE , 0, N_("save and quit") },
+ { N_("help") , cmdHELP , 0, N_("show this help") },
+ { "?" , cmdHELP , 0, NULL },
+ { N_("fpr") , cmdFPR , 0, N_("show fingerprint") },
+ { N_("list") , cmdLIST , 0, N_("list key and user ids") },
+ { N_("l") , cmdLIST , 0, NULL },
+ { N_("uid") , cmdSELUID , 0, N_("select user id N") },
+ { N_("key") , cmdSELKEY , 0, N_("select secondary key N") },
+ { N_("check") , cmdCHECK , 0, N_("list signatures") },
+ { N_("c") , cmdCHECK , 0, NULL },
+ { N_("sign") , cmdSIGN , 0, N_("sign the key") },
+ { N_("s") , cmdSIGN , 0, NULL },
+ { N_("debug") , cmdDEBUG , 0, NULL },
+ { N_("adduid") , cmdADDUID , 1, N_("add a user id") },
+ { N_("deluid") , cmdDELUID , 0, N_("delete user id") },
+ { N_("addkey") , cmdADDKEY , 1, N_("add a secondary key") },
+ { N_("delkey") , cmdDELKEY , 0, N_("delete a secondary key") },
+ { N_("toggle") , cmdTOGGLE , 1, N_("toggle between secret "
+ "and public key listing") },
+ { N_("t" ) , cmdTOGGLE , 1, NULL },
+ { N_("passwd") , cmdPASSWD , 1, N_("change the passphrase") },
+
+ { NULL, cmdNONE } };
+ enum cmdids cmd;
+ int rc = 0;
+ KBNODE keyblock = NULL;
+ KBPOS keyblockpos;
+ KBNODE sec_keyblock = NULL;
+ KBPOS sec_keyblockpos;
+ KBNODE cur_keyblock;
+ char *answer = NULL;
+ int redisplay = 1;
+ int modified = 0;
+ int sec_modified = 0;
+ int toggle;
+
+
+ if( opt.batch ) {
+ log_error(_("can't do that in batch-mode\n"));
+ goto leave;
+ }
- if( changed ) {
- rc = update_keyblock( &kbpos, keyblock );
+ /* first try to locate it as secret key */
+ rc = find_secret_keyblock_byname( &sec_keyblockpos, username );
+ if( !rc ) {
+ rc = read_keyblock( &sec_keyblockpos, &sec_keyblock );
if( rc ) {
- log_error("update_keyblock failed: %s\n", g10_errstr(rc) );
+ log_error("%s: secret keyblock read problem: %s\n",
+ username, g10_errstr(rc));
goto leave;
}
}
+ /* and now get the public key */
+ rc = get_keyblock_byname( &keyblock, &keyblockpos, username );
+ if( rc )
+ goto leave;
+
+ if( sec_keyblock ) { /* check that they match */
+ /* FIXME: check that they both match */
+ tty_printf(_("Secret key is available.\n"));
+ }
+
+ toggle = 0;
+ cur_keyblock = keyblock;
+ for(;;) { /* main loop */
+ int i, arg_number;
+ char *p;
+
+ tty_printf("\n");
+ if( redisplay ) {
+ show_key_with_all_names( cur_keyblock, 0, 0, 1 );
+ tty_printf("\n");
+ redisplay = 0;
+ }
+ m_free(answer);
+ answer = tty_get(_("Command> "));
+ tty_kill_prompt();
+ trim_spaces(answer);
+
+ arg_number = 0;
+ if( !*answer )
+ cmd = cmdLIST;
+ else if( isdigit( *answer ) ) {
+ cmd = cmdSELUID;
+ arg_number = atoi(answer);
+ }
+ else {
+ if( (p=strchr(answer,' ')) ) {
+ *p++ = 0;
+ trim_spaces(answer);
+ trim_spaces(p);
+ arg_number = atoi(p);
+ }
+
+ for(i=0; cmds[i].name; i++ )
+ if( !stricmp( answer, cmds[i].name ) )
+ break;
+ if( cmds[i].need_sk && !sec_keyblock ) {
+ tty_printf(_("Need the secret key to to this.\n"));
+ cmd = cmdNOP;
+ }
+ else
+ cmd = cmds[i].id;
+ }
+ switch( cmd ) {
+ case cmdHELP:
+ for(i=0; cmds[i].name; i++ ) {
+ if( cmds[i].need_sk && !sec_keyblock )
+ ; /* skip if we do not have the secret key */
+ else if( cmds[i].desc )
+ tty_printf("%-10s %s\n", cmds[i].name, cmds[i].desc );
+ }
+ break;
+
+ case cmdQUIT:
+ if( !modified )
+ goto leave;
+ m_free(answer);
+ answer = tty_get(_("Save changes? "));
+ if( !answer_is_yes(answer) ) {
+ m_free(answer);
+ answer = tty_get(_("Quit without saving? "));
+ if( answer_is_yes(answer) )
+ goto leave;
+ break;
+ }
+ /* fall thru */
+ case cmdSAVE:
+ if( modified ) {
+ rc = update_keyblock( &keyblockpos, keyblock );
+ if( rc ) {
+ log_error(_("update failed: %s\n"), g10_errstr(rc) );
+ break;
+ }
+ if( sec_modified ) {
+ rc = update_keyblock( &sec_keyblockpos, sec_keyblock );
+ if( rc ) {
+ log_error(_("update secret failed: %s\n"),
+ g10_errstr(rc) );
+ break;
+ }
+ }
+ /* FIXME: UPDATE/INVALIDATE trustdb !! */
+ }
+ else
+ tty_printf(_("Key not changed so no update needed.\n"));
+ goto leave;
+
+ case cmdLIST:
+ redisplay = 1;
+ break;
+
+ case cmdFPR:
+ show_key_and_fingerprint( keyblock );
+ break;
+
+ case cmdSELUID:
+ if( menu_select_uid( cur_keyblock, arg_number ) )
+ redisplay = 1;
+ break;
+
+ case cmdSELKEY:
+ if( menu_select_key( cur_keyblock, arg_number ) )
+ redisplay = 1;
+ break;
+
+ case cmdCHECK:
+ /* we can only do this with the public key becuase the
+ * check functions can't cope with secret keys and it
+ * is questionable whether this would make sense at all */
+ check_all_keysigs( keyblock, count_selected_uids(keyblock) );
+ break;
+
+ case cmdSIGN: /* sign (only the public key) */
+ if( count_uids(keyblock) > 1 && !count_selected_uids(keyblock) ) {
+ if( !tty_get_answer_is_yes(_("Really sign all user ids? ")) ) {
+ tty_printf(_("Hint: Select the user ids to sign\n"));
+ break;
+ }
+ }
+ sign_uids( keyblock, locusr, &modified );
+ break;
+
+ case cmdDEBUG:
+ dump_kbnode( cur_keyblock );
+ break;
+
+ case cmdTOGGLE:
+ toggle = !toggle;
+ cur_keyblock = toggle? sec_keyblock : keyblock;
+ redisplay = 1;
+ break;
+
+ case cmdADDUID:
+ if( menu_adduid( keyblock, sec_keyblock ) ) {
+ redisplay = 1;
+ sec_modified = modified = 1;
+ }
+ break;
+
+ case cmdDELUID: {
+ int n1;
+
+ if( !(n1=count_selected_uids(keyblock)) )
+ tty_printf(_("You must select at least one user id.\n"));
+ else if( count_uids(keyblock) - n1 < 1 )
+ tty_printf(_("You can't delete the last user id!\n"));
+ else if( tty_get_answer_is_yes(
+ n1 > 1? _("Really remove all selected user ids? ")
+ : _("Really remove this user id? ")
+ ) ) {
+ menu_deluid( keyblock, sec_keyblock );
+ redisplay = 1;
+ modified = 1;
+ if( sec_keyblock )
+ sec_modified = 1;
+ }
+ }
+ break;
+
+ case cmdADDKEY:
+ if( generate_subkeypair( keyblock, sec_keyblock ) ) {
+ redisplay = 1;
+ sec_modified = modified = 1;
+ }
+ break;
+
+
+ case cmdDELKEY: {
+ int n1;
+
+ if( !(n1=count_selected_keys( keyblock )) )
+ tty_printf(_("You must select at least one key.\n"));
+ else if( sec_keyblock && !tty_get_answer_is_yes(
+ n1 > 1?
+ _("Do you really want to delete the selected keys? "):
+ _("Do you really want to delete this key? ")
+ ))
+ ;
+ else {
+ menu_delkey( keyblock, sec_keyblock );
+ redisplay = 1;
+ modified = 1;
+ if( sec_keyblock )
+ sec_modified = 1;
+ }
+ }
+ break;
+
+ case cmdPASSWD:
+ if( change_passphrase( sec_keyblock ) )
+ sec_modified = 1;
+ break;
+
+ case cmdNOP:
+ break;
+
+ default:
+ tty_printf("\n");
+ tty_printf(_("Invalid command (try \"help\")\n"));
+ break;
+ }
+ } /* end main loop */
+
leave:
- m_free( passphrase );
release_kbnode( keyblock );
- set_next_passphrase( NULL );
- return rc;
+ release_kbnode( sec_keyblock );
+ m_free(answer);
}
+
/****************
- * Create a signature packet for the given public key certificate
- * and the user id and return it in ret_sig. User signature class SIGCLASS
- * user-id is not used (and may be NULL if sigclass is 0x20)
- * If digest_algo is 0 the function selects an appropriate one.
+ * Display the key a the user ids, if only_marked is true, do only
+ * so for user ids with mark A flag set and dont display the index number
*/
-int
-make_keysig_packet( PKT_signature **ret_sig, PKT_public_key *pk,
- PKT_user_id *uid, PKT_public_key *subpk,
- PKT_secret_key *sk,
- int sigclass, int digest_algo,
- int (*mksubpkt)(PKT_signature *, void *), void *opaque
- )
+static void
+show_key_with_all_names( KBNODE keyblock, int only_marked,
+ int with_fpr, int with_subkeys )
{
- PKT_signature *sig;
- int rc=0;
- MD_HANDLE md;
-
- assert( (sigclass >= 0x10 && sigclass <= 0x13)
- || sigclass == 0x20 || sigclass == 0x18 );
- if( !digest_algo ) {
- switch( sk->pubkey_algo ) {
- case PUBKEY_ALGO_DSA: digest_algo = DIGEST_ALGO_SHA1; break;
- case PUBKEY_ALGO_RSA_S:
- case PUBKEY_ALGO_RSA: digest_algo = DIGEST_ALGO_MD5; break;
- default: digest_algo = DIGEST_ALGO_RMD160; break;
- }
- }
- md = md_open( digest_algo, 0 );
-
- /* hash the public key certificate and the user id */
- hash_public_key( md, pk );
- if( sigclass == 0x18 ) { /* subkey binding */
- hash_public_key( md, subpk );
- }
- else if( sigclass != 0x20 ) {
- if( sk->version >=4 ) {
- byte buf[5];
- buf[0] = 0xb4; /* indicates a userid packet */
- buf[1] = uid->len >> 24; /* always 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 );
- }
- /* and make the signature packet */
- sig = m_alloc_clear( sizeof *sig );
- sig->version = sk->version;
- keyid_from_sk( sk, sig->keyid );
- sig->pubkey_algo = sk->pubkey_algo;
- sig->digest_algo = digest_algo;
- sig->timestamp = make_timestamp();
- sig->sig_class = sigclass;
- if( sig->version >= 4 )
- build_sig_subpkt_from_sig( sig );
-
- if( sig->version >= 4 && mksubpkt )
- rc = (*mksubpkt)( sig, opaque );
-
- if( !rc ) {
- if( sig->version >= 4 )
- md_putc( md, sig->version );
- md_putc( md, sig->sig_class );
- if( sig->version < 4 ) {
- u32 a = sig->timestamp;
- md_putc( md, (a >> 24) & 0xff );
- md_putc( md, (a >> 16) & 0xff );
- md_putc( md, (a >> 8) & 0xff );
- md_putc( md, a & 0xff );
+ KBNODE node;
+ int i;
+
+ /* the keys */
+ for( node = keyblock; node; node = node->next ) {
+ if( node->pkt->pkttype == PKT_PUBLIC_KEY
+ || (with_subkeys && node->pkt->pkttype == PKT_PUBLIC_SUBKEY) ) {
+ PKT_public_key *pk = node->pkt->pkt.public_key;
+ tty_printf("%s%c %4u%c/%08lX created: %s expires: %s\n",
+ node->pkt->pkttype == PKT_PUBLIC_KEY? "pub":"sub",
+ (node->flag & NODFLG_SELKEY)? '*':' ',
+ nbits_from_pk( pk ),
+ pubkey_letter( pk->pubkey_algo ),
+ (ulong)keyid_from_pk(pk,NULL),
+ datestr_from_pk(pk),
+ expirestr_from_pk(pk) );
+ if( with_fpr && node->pkt->pkttype == PKT_PUBLIC_KEY )
+ show_fingerprint( pk );
}
- else {
- byte buf[6];
- size_t n;
-
- md_putc( md, sig->pubkey_algo );
- md_putc( md, sig->digest_algo );
- if( sig->hashed_data ) {
- n = (sig->hashed_data[0] << 8) | sig->hashed_data[1];
- md_write( md, sig->hashed_data, n+2 );
- n += 6;
+ else if( node->pkt->pkttype == PKT_SECRET_KEY
+ || (with_subkeys && node->pkt->pkttype == PKT_SECRET_SUBKEY) ) {
+ PKT_secret_key *sk = node->pkt->pkt.secret_key;
+ tty_printf("%s%c %4u%c/%08lX created: %s expires: %s\n",
+ node->pkt->pkttype == PKT_SECRET_KEY? "sec":"sbb",
+ (node->flag & NODFLG_SELKEY)? '*':' ',
+ nbits_from_sk( sk ),
+ pubkey_letter( sk->pubkey_algo ),
+ (ulong)keyid_from_sk(sk,NULL),
+ datestr_from_sk(sk),
+ expirestr_from_sk(sk) );
+ }
+ }
+ /* the user ids */
+ i = 0;
+ for( node = keyblock; node; node = node->next ) {
+ if( node->pkt->pkttype == PKT_USER_ID ) {
+ PKT_user_id *uid = node->pkt->pkt.user_id;
+ ++i;
+ if( !only_marked || (only_marked && (node->flag & NODFLG_MARK_A))){
+ if( only_marked )
+ tty_printf(" ");
+ else if( node->flag & NODFLG_SELUID )
+ tty_printf("(%d)* ", i);
+ else
+ tty_printf("(%d) ", i);
+ tty_print_string( uid->name, uid->len );
+ tty_printf("\n");
}
- else
- n = 6;
- /* add some magic */
- buf[0] = sig->version;
- buf[1] = 0xff;
- buf[2] = n >> 24; /* hmmm, n is only 16 bit, so this is always 0 */
- buf[3] = n >> 16;
- buf[4] = n >> 8;
- buf[5] = n;
- md_write( md, buf, 6 );
+ }
+ }
+}
+
+static void
+show_key_and_fingerprint( KBNODE keyblock )
+{
+ KBNODE node;
+ PKT_public_key *pk = NULL;
+ for( node = keyblock; node; node = node->next ) {
+ if( node->pkt->pkttype == PKT_PUBLIC_KEY ) {
+ pk = node->pkt->pkt.public_key;
+ tty_printf("pub %4u%c/%08lX %s ",
+ nbits_from_pk( pk ),
+ pubkey_letter( pk->pubkey_algo ),
+ (ulong)keyid_from_pk(pk,NULL),
+ datestr_from_pk(pk) );
}
- md_final(md);
+ else if( node->pkt->pkttype == PKT_USER_ID ) {
+ PKT_user_id *uid = node->pkt->pkt.user_id;
+ tty_print_string( uid->name, uid->len );
+ break;
+ }
+ }
+ tty_printf("\n");
+ if( pk )
+ show_fingerprint( pk );
+}
+
- rc = complete_sig( sig, sk, md );
+static void
+show_fingerprint( PKT_public_key *pk )
+{
+ byte *array, *p;
+ size_t i, n;
+
+ p = array = fingerprint_from_pk( pk, NULL, &n );
+ tty_printf(" Fingerprint:");
+ if( n == 20 ) {
+ for(i=0; i < n ; i++, i++, p += 2 ) {
+ if( i == 10 )
+ tty_printf(" ");
+ tty_printf(" %02X%02X", *p, p[1] );
+ }
}
+ else {
+ for(i=0; i < n ; i++, p++ ) {
+ if( i && !(i%8) )
+ tty_printf(" ");
+ tty_printf(" %02X", *p );
+ }
+ }
+ tty_printf("\n");
+ m_free(array);
+}
- md_close( md );
- if( rc )
- free_seckey_enc( sig );
+
+/****************
+ * Ask for a new user id , do the selfsignature and put it into
+ * both keyblocks.
+ * Return true if there is a new user id
+ */
+static int
+menu_adduid( KBNODE pub_keyblock, KBNODE sec_keyblock )
+{
+ PKT_user_id *uid;
+ PKT_public_key *pk=NULL;
+ PKT_secret_key *sk=NULL;
+ PKT_signature *sig=NULL;
+ PACKET *pkt;
+ KBNODE node;
+ KBNODE pub_where=NULL, sec_where=NULL;
+ int rc;
+
+ uid = generate_user_id();
+ if( !uid )
+ return 0;
+
+ for( node = pub_keyblock; node; pub_where = node, node = node->next ) {
+ if( node->pkt->pkttype == PKT_PUBLIC_KEY )
+ pk = node->pkt->pkt.public_key;
+ else if( node->pkt->pkttype == PKT_PUBLIC_SUBKEY )
+ break;
+ }
+ if( !node ) /* no subkey */
+ pub_where = NULL;
+ for( node = sec_keyblock; node; sec_where = node, node = node->next ) {
+ if( node->pkt->pkttype == PKT_SECRET_KEY )
+ sk = node->pkt->pkt.secret_key;
+ else if( node->pkt->pkttype == PKT_SECRET_SUBKEY )
+ break;
+ }
+ if( !node ) /* no subkey */
+ sec_where = NULL;
+ assert(pk && sk );
+
+ rc = make_keysig_packet( &sig, pk, uid, NULL, sk, 0x13, 0,
+ keygen_add_std_prefs, sk );
+ if( rc ) {
+ log_error("signing failed: %s\n", g10_errstr(rc) );
+ free_user_id(uid);
+ return 0;
+ }
+
+ /* insert/append to secret keyblock */
+ pkt = m_alloc_clear( sizeof *pkt );
+ pkt->pkttype = PKT_USER_ID;
+ pkt->pkt.user_id = copy_user_id(NULL, uid);
+ node = new_kbnode(pkt);
+ if( sec_where )
+ insert_kbnode( sec_where, node, 0 );
else
- *ret_sig = sig;
- return rc;
+ add_kbnode( sec_keyblock, node );
+ pkt = m_alloc_clear( sizeof *pkt );
+ pkt->pkttype = PKT_SIGNATURE;
+ pkt->pkt.signature = copy_signature(NULL, sig);
+ if( sec_where )
+ insert_kbnode( node, new_kbnode(pkt), 0 );
+ else
+ add_kbnode( sec_keyblock, new_kbnode(pkt) );
+ /* insert/append to public keyblock */
+ pkt = m_alloc_clear( sizeof *pkt );
+ pkt->pkttype = PKT_USER_ID;
+ pkt->pkt.user_id = uid;
+ node = new_kbnode(pkt);
+ if( pub_where )
+ insert_kbnode( pub_where, node, 0 );
+ else
+ add_kbnode( pub_keyblock, node );
+ pkt = m_alloc_clear( sizeof *pkt );
+ pkt->pkttype = PKT_SIGNATURE;
+ pkt->pkt.signature = copy_signature(NULL, sig);
+ if( pub_where )
+ insert_kbnode( node, new_kbnode(pkt), 0 );
+ else
+ add_kbnode( pub_keyblock, new_kbnode(pkt) );
+ return 1;
+}
+
+
+/****************
+ * Remove all selceted userids from the keyrings
+ */
+static void
+menu_deluid( KBNODE pub_keyblock, KBNODE sec_keyblock )
+{
+ KBNODE node;
+ int selected=0;
+
+ for( node = pub_keyblock; node; node = node->next ) {
+ if( node->pkt->pkttype == PKT_USER_ID ) {
+ selected = node->flag & NODFLG_SELUID;
+ if( selected ) {
+ delete_kbnode( node );
+ if( sec_keyblock ) {
+ KBNODE snode;
+ int s_selected = 0;
+ PKT_user_id *uid = node->pkt->pkt.user_id;
+ for( snode = sec_keyblock; snode; snode = snode->next ) {
+ if( snode->pkt->pkttype == PKT_USER_ID ) {
+ PKT_user_id *suid = snode->pkt->pkt.user_id;
+
+ s_selected =
+ (uid->len == suid->len
+ && !memcmp( uid->name, suid->name, uid->len));
+ if( s_selected )
+ delete_kbnode( snode );
+ }
+ else if( s_selected
+ && snode->pkt->pkttype == PKT_SIGNATURE )
+ delete_kbnode( snode );
+ else if( snode->pkt->pkttype == PKT_SECRET_SUBKEY )
+ s_selected = 0;
+ }
+ }
+ }
+ }
+ else if( selected && node->pkt->pkttype == PKT_SIGNATURE )
+ delete_kbnode( node );
+ else if( node->pkt->pkttype == PKT_PUBLIC_SUBKEY )
+ selected = 0;
+ }
+ commit_kbnode( &pub_keyblock );
+ if( sec_keyblock )
+ commit_kbnode( &sec_keyblock );
+}
+
+
+/****************
+ * Remove some of the secondary keys
+ */
+static void
+menu_delkey( KBNODE pub_keyblock, KBNODE sec_keyblock )
+{
+ KBNODE node;
+ int selected=0;
+
+ for( node = pub_keyblock; node; node = node->next ) {
+ if( node->pkt->pkttype == PKT_PUBLIC_SUBKEY ) {
+ selected = node->flag & NODFLG_SELKEY;
+ if( selected ) {
+ delete_kbnode( node );
+ if( sec_keyblock ) {
+ KBNODE snode;
+ int s_selected = 0;
+ u32 ki[2];
+
+ keyid_from_pk( node->pkt->pkt.public_key, ki );
+ for( snode = sec_keyblock; snode; snode = snode->next ) {
+ if( snode->pkt->pkttype == PKT_SECRET_SUBKEY ) {
+ u32 ki2[2];
+
+ keyid_from_sk( snode->pkt->pkt.secret_key, ki2 );
+ s_selected = (ki[0] == ki2[0] && ki[1] == ki2[1]);
+ if( s_selected )
+ delete_kbnode( snode );
+ }
+ else if( s_selected
+ && snode->pkt->pkttype == PKT_SIGNATURE )
+ delete_kbnode( snode );
+ else
+ s_selected = 0;
+ }
+ }
+ }
+ }
+ else if( selected && node->pkt->pkttype == PKT_SIGNATURE )
+ delete_kbnode( node );
+ else
+ selected = 0;
+ }
+ commit_kbnode( &pub_keyblock );
+ if( sec_keyblock )
+ commit_kbnode( &sec_keyblock );
+}
+
+
+/****************
+ * Select one user id or remove all selection if index is 0.
+ * Returns: True if the selection changed;
+ */
+static int
+menu_select_uid( KBNODE keyblock, int index )
+{
+ KBNODE node;
+ int i;
+
+ /* first check that the index is valid */
+ if( index ) {
+ for( i=0, node = keyblock; node; node = node->next ) {
+ if( node->pkt->pkttype == PKT_USER_ID ) {
+ if( ++i == index )
+ break;
+ }
+ }
+ if( !node ) {
+ tty_printf(_("No user id with index %d\n"), index );
+ return 0;
+ }
+ }
+ else { /* reset all */
+ for( i=0, node = keyblock; node; node = node->next ) {
+ if( node->pkt->pkttype == PKT_USER_ID )
+ node->flag &= ~NODFLG_SELUID;
+ }
+ return 1;
+ }
+ /* and toggle the new index */
+ for( i=0, node = keyblock; node; node = node->next ) {
+ if( node->pkt->pkttype == PKT_USER_ID ) {
+ if( ++i == index )
+ if( (node->flag & NODFLG_SELUID) )
+ node->flag &= ~NODFLG_SELUID;
+ else
+ node->flag |= NODFLG_SELUID;
+ }
+ }
+
+ return 1;
+}
+
+/****************
+ * Select secondary keys
+ * Returns: True if the selection changed;
+ */
+static int
+menu_select_key( KBNODE keyblock, int index )
+{
+ KBNODE node;
+ int i;
+
+ /* first check that the index is valid */
+ if( index ) {
+ for( i=0, node = keyblock; node; node = node->next ) {
+ if( node->pkt->pkttype == PKT_PUBLIC_SUBKEY
+ || node->pkt->pkttype == PKT_SECRET_SUBKEY ) {
+ if( ++i == index )
+ break;
+ }
+ }
+ if( !node ) {
+ tty_printf(_("No secondary key with index %d\n"), index );
+ return 0;
+ }
+ }
+ else { /* reset all */
+ for( i=0, node = keyblock; node; node = node->next ) {
+ if( node->pkt->pkttype == PKT_PUBLIC_SUBKEY
+ || node->pkt->pkttype == PKT_SECRET_SUBKEY )
+ node->flag &= ~NODFLG_SELKEY;
+ }
+ return 1;
+ }
+ /* and set the new index */
+ for( i=0, node = keyblock; node; node = node->next ) {
+ if( node->pkt->pkttype == PKT_PUBLIC_SUBKEY
+ || node->pkt->pkttype == PKT_SECRET_SUBKEY ) {
+ if( ++i == index )
+ if( (node->flag & NODFLG_SELKEY) )
+ node->flag &= ~NODFLG_SELKEY;
+ else
+ node->flag |= NODFLG_SELKEY;
+ }
+ }
+
+ return 1;
+}
+
+
+static int
+count_uids_with_flag( KBNODE keyblock, unsigned flag )
+{
+ KBNODE node;
+ int i=0;
+
+ for( node = keyblock; node; node = node->next )
+ if( node->pkt->pkttype == PKT_USER_ID && (node->flag & flag) )
+ i++;
+ return i;
+}
+
+static int
+count_keys_with_flag( KBNODE keyblock, unsigned flag )
+{
+ KBNODE node;
+ int i=0;
+
+ for( node = keyblock; node; node = node->next )
+ if( ( node->pkt->pkttype == PKT_PUBLIC_SUBKEY
+ || node->pkt->pkttype == PKT_SECRET_SUBKEY)
+ && (node->flag & flag) )
+ i++;
+ return i;
+}
+
+static int
+count_uids( KBNODE keyblock )
+{
+ KBNODE node;
+ int i=0;
+
+ for( node = keyblock; node; node = node->next )
+ if( node->pkt->pkttype == PKT_USER_ID )
+ i++;
+ return i;
+}
+
+
+/****************
+ * Returns true if there is at least one selected user id
+ */
+static int
+count_selected_uids( KBNODE keyblock )
+{
+ return count_uids_with_flag( keyblock, NODFLG_SELUID);
+}
+
+static int
+count_selected_keys( KBNODE keyblock )
+{
+ return count_keys_with_flag( keyblock, NODFLG_SELKEY);
}
diff --git a/g10/keygen.c b/g10/keygen.c
index 0eaeafeae..4ff81b7f5 100644
--- a/g10/keygen.c
+++ b/g10/keygen.c
@@ -74,8 +74,8 @@ add_key_expire( PKT_signature *sig, void *opaque )
* Add preference to the self signature packet.
* This is only called for packets with version > 3.
*/
-static int
-add_prefs( PKT_signature *sig, void *opaque )
+int
+keygen_add_std_prefs( PKT_signature *sig, void *opaque )
{
byte buf[8];
@@ -134,7 +134,7 @@ write_selfsig( KBNODE root, KBNODE pub_root, PKT_secret_key *sk )
/* and make the signature */
rc = make_keysig_packet( &sig, pk, uid, NULL, sk, 0x13, 0,
- add_prefs, sk );
+ keygen_add_std_prefs, sk );
if( rc ) {
log_error("make_keysig_packet failed: %s\n", g10_errstr(rc) );
return rc;
@@ -444,25 +444,18 @@ ask_keysize( int algo )
else if( nbits > 2048 ) {
tty_printf(_("Keysizes larger than 2048 are not suggested because "
"computations take REALLY long!\n"));
- answer = tty_get(_("Are you sure that you want this keysize? "));
- tty_kill_prompt();
- if( answer_is_yes(answer) ) {
- m_free(answer);
+ if( tty_get_answer_is_yes(_(
+ "Are you sure that you want this keysize? ")) ) {
tty_printf(_("Okay, but keep in mind that your monitor "
"and keyboard radiation is also very vulnerable "
"to attacks!\n"));
break;
}
- m_free(answer);
}
else if( nbits > 1536 ) {
- answer = tty_get(_("Do you really need such a large keysize? "));
- tty_kill_prompt();
- if( answer_is_yes(answer) ) {
- m_free(answer);
+ if( tty_get_answer_is_yes(_(
+ "Do you really need such a large keysize? ")) )
break;
- }
- m_free(answer);
}
else
break;
@@ -524,10 +517,7 @@ ask_valid_days()
add_days_to_timestamp( make_timestamp(), valid_days )));
}
- m_free(answer);
- answer = tty_get(_("Is this correct (y/n)? "));
- tty_kill_prompt();
- if( answer_is_yes(answer) )
+ if( tty_get_answer_is_yes(_("Is this correct (y/n)? ")) )
break;
}
m_free(answer);
@@ -549,12 +539,13 @@ has_invalid_email_chars( const char *s )
static char *
-ask_user_id()
+ask_user_id( int mode )
{
char *answer;
char *aname, *acomment, *amail, *uid;
- tty_printf( _("\n"
+ if( !mode )
+ tty_printf( _("\n"
"You need a User-ID to identify your key; the software constructs the user id\n"
"from Real Name, Comment and Email Address in this form:\n"
" \"Heinrich Heine (Der Dichter) <heinrichh@duesseldorf.de>\"\n\n") );
@@ -630,28 +621,37 @@ ask_user_id()
tty_printf(_("You selected this USER-ID:\n \"%s\"\n\n"), uid);
/* fixme: add a warning if this user-id already exists */
for(;;) {
- answer = tty_get(_("Edit (N)ame, (C)omment, (E)mail or (O)kay? "));
+ char *ansstr = N_("NnCcEeOoQq");
+ answer = tty_get(_(
+ "Change (N)ame, (C)omment, (E)mail or (O)kay/(Q)uit? "));
tty_kill_prompt();
if( strlen(answer) > 1 )
;
- else if( *answer == 'N' || *answer == 'n' ) {
+ else if( *answer == ansstr[0] || *answer == ansstr[1] ) {
m_free(aname); aname = NULL;
break;
}
- else if( *answer == 'C' || *answer == 'c' ) {
+ else if( *answer == ansstr[2] || *answer == ansstr[3] ) {
m_free(acomment); acomment = NULL;
break;
}
- else if( *answer == 'E' || *answer == 'e' ) {
+ else if( *answer == ansstr[4] || *answer == ansstr[5] ) {
m_free(amail); amail = NULL;
break;
}
- else if( *answer == 'O' || *answer == 'o' ) {
+ else if( *answer == ansstr[6] || *answer == ansstr[7] ) {
m_free(aname); aname = NULL;
m_free(acomment); acomment = NULL;
m_free(amail); amail = NULL;
break;
}
+ else if( *answer == ansstr[8] || *answer == ansstr[9] ) {
+ m_free(aname); aname = NULL;
+ m_free(acomment); acomment = NULL;
+ m_free(amail); amail = NULL;
+ m_free(uid); uid = NULL;
+ break;
+ }
m_free(answer);
}
m_free(answer);
@@ -685,7 +685,7 @@ ask_passphrase( STRING2KEY **ret_s2k )
tty_printf(_(
"You don't want a passphrase - this is probably a *bad* idea!\n"
"I will do it anyway. You can change your passphrase at any time,\n"
- "using this program with the option \"--change-passphrase\".\n\n"));
+ "using this program with the option \"--edit-key\".\n\n"));
break;
}
else
@@ -729,6 +729,27 @@ do_create( int algo, unsigned nbits, KBNODE pub_root, KBNODE sec_root,
/****************
+ * Generate a new user id packet, or return NULL if cancelled
+ */
+PKT_user_id *
+generate_user_id()
+{
+ PKT_user_id *uid;
+ char *p;
+ size_t n;
+
+ p = ask_user_id( 1 );
+ if( !p )
+ return NULL;
+ n = strlen(p);
+ uid = m_alloc( sizeof *uid + n - 1 );
+ uid->len = n;
+ strcpy(uid->name, p);
+ return uid;
+}
+
+
+/****************
* Generate a keypair
*/
void
@@ -762,7 +783,11 @@ generate_keypair()
}
nbits = ask_keysize( algo );
ndays = ask_valid_days();
- uid = ask_user_id();
+ uid = ask_user_id(0);
+ if( !uid ) {
+ log_error(_("Key generation cancelled.\n"));
+ return;
+ }
dek = ask_passphrase( &s2k );
@@ -879,88 +904,29 @@ generate_keypair()
/****************
* add a new subkey to an existing key.
+ * Returns true if a new key has been generated and put into the keyblocks.
*/
-void
-generate_subkeypair( const char *username )
+int
+generate_subkeypair( KBNODE pub_keyblock, KBNODE sec_keyblock )
{
- int rc=0;
- KBPOS pub_kbpos, sec_kbpos;
- KBNODE pub_keyblock = NULL;
- KBNODE sec_keyblock = NULL;
+ int okay=0, rc=0;
KBNODE node;
PKT_secret_key *sk = NULL; /* this is the primary sk */
- u32 keyid[2];
int v4, algo, ndays;
unsigned nbits;
char *passphrase = NULL;
DEK *dek = NULL;
STRING2KEY *s2k = NULL;
- if( opt.batch || opt.answer_yes || opt.answer_no ) {
- log_error(_("Key generation can only be used in interactive mode\n"));
- return;
- }
-
- /* search the userid */
- rc = find_secret_keyblock_byname( &sec_kbpos, username );
- if( rc ) {
- log_error("user '%s' not found\n", username );
- goto leave;
- }
- rc = read_keyblock( &sec_kbpos, &sec_keyblock );
- if( rc ) {
- log_error("error reading the secret key: %s\n", g10_errstr(rc) );
- goto leave;
- }
- /* and the public key */
- rc = find_keyblock_byname( &pub_kbpos, username );
- if( rc ) {
- log_error("user '%s' not found in public ring\n", username );
- goto leave;
- }
- rc = read_keyblock( &pub_kbpos, &pub_keyblock );
- if( rc ) {
- log_error("error reading the public key: %s\n", g10_errstr(rc) );
- goto leave;
- }
-
- /* break out the primary key */
+ /* break out the primary secret key */
node = find_kbnode( sec_keyblock, PKT_SECRET_KEY );
if( !node ) {
log_error("Oops; secret key not found anymore!\n");
- rc = G10ERR_GENERAL;
goto leave;
}
/* make a copy of the sk to keep the protected one in the keyblock */
sk = copy_secret_key( NULL, node->pkt->pkt.secret_key );
- keyid_from_sk( sk, keyid );
- /* display primary and all secondary keys */
- tty_printf("sec %4u%c/%08lX %s ",
- nbits_from_sk( sk ),
- pubkey_letter( sk->pubkey_algo ),
- keyid[1], datestr_from_sk(sk) );
- {
- size_t n;
- char *p = get_user_id( keyid, &n );
- tty_print_string( p, n );
- m_free(p);
- tty_printf("\n");
- }
- for(node=sec_keyblock; node; node = node->next ) {
- if( node->pkt->pkttype == PKT_SECRET_SUBKEY ) {
- PKT_secret_key *subsk = node->pkt->pkt.secret_key;
- keyid_from_sk( subsk, keyid );
- tty_printf("sub %4u%c/%08lX %s\n",
- nbits_from_sk( subsk ),
- pubkey_letter( subsk->pubkey_algo ),
- keyid[1], datestr_from_sk(subsk) );
- }
- }
- tty_printf("\n");
-
-
-
/* unprotect to get the passphrase */
switch( is_secret_key_protected( sk ) ) {
case -1:
@@ -984,6 +950,8 @@ generate_subkeypair( const char *username )
assert(algo);
nbits = ask_keysize( algo );
ndays = ask_valid_days();
+ if( !tty_get_answer_is_yes( _("Really create? ") ) )
+ goto leave;
if( passphrase ) {
s2k = m_alloc_secure( sizeof *s2k );
@@ -999,31 +967,18 @@ generate_subkeypair( const char *username )
rc = write_keybinding(pub_keyblock, pub_keyblock, sk);
if( !rc )
rc = write_keybinding(sec_keyblock, pub_keyblock, sk);
- /* write back */
- if( !rc ) {
- rc = update_keyblock( &pub_kbpos, pub_keyblock );
- if( rc )
- log_error("update_public_keyblock failed\n" );
- }
- if( !rc ) {
- rc = update_keyblock( &sec_kbpos, sec_keyblock );
- if( rc )
- log_error("update_secret_keyblock failed\n" );
- }
if( !rc )
- tty_printf(_("public and secret subkey created.\n") );
-
+ okay = 1;
leave:
if( rc )
- tty_printf(_("Key generation failed: %s\n"), g10_errstr(rc) );
+ log_error(_("Key generation failed: %s\n"), g10_errstr(rc) );
m_free( passphrase );
m_free( dek );
m_free( s2k );
if( sk ) /* release the copy of the (now unprotected) secret key */
free_secret_key(sk);
- release_kbnode( sec_keyblock );
- release_kbnode( pub_keyblock );
set_next_passphrase( NULL );
+ return okay;
}
diff --git a/g10/keyid.c b/g10/keyid.c
index de0319fe3..349356406 100644
--- a/g10/keyid.c
+++ b/g10/keyid.c
@@ -296,6 +296,37 @@ datestr_from_sig( PKT_signature *sig )
}
+const char *
+expirestr_from_pk( PKT_public_key *pk )
+{
+ static char buffer[11+5];
+ struct tm *tp;
+ time_t atime;
+
+ if( !pk->valid_days )
+ return "never ";
+ atime = add_days_to_timestamp( pk->timestamp, pk->valid_days );
+ tp = gmtime( &atime );
+ sprintf(buffer,"%04d-%02d-%02d", 1900+tp->tm_year, tp->tm_mon+1, tp->tm_mday );
+ return buffer;
+}
+
+const char *
+expirestr_from_sk( PKT_secret_key *sk )
+{
+ static char buffer[11+5];
+ struct tm *tp;
+ time_t atime;
+
+ if( !sk->valid_days )
+ return "never ";
+ atime = add_days_to_timestamp( sk->timestamp, sk->valid_days );
+ tp = gmtime( &atime );
+ sprintf(buffer,"%04d-%02d-%02d", 1900+tp->tm_year, tp->tm_mon+1, tp->tm_mday );
+ return buffer;
+}
+
+
/**************** .
* Return a byte array with the fingerprint for the given PK/SK
* The length of the array is returned in ret_len. Caller must free
diff --git a/g10/keylist.c b/g10/keylist.c
index d23a98f1e..04d79b1ec 100644
--- a/g10/keylist.c
+++ b/g10/keylist.c
@@ -202,6 +202,8 @@ list_one( const char *name, int secret )
any = 1;
}
+
+
keyid_from_pk( pk2, keyid2 );
if( opt.with_colons ) {
printf("sub:%c:%u:%d:%08lX%08lX:%s:%u:",
@@ -224,6 +226,8 @@ list_one( const char *name, int secret )
pubkey_letter( pk2->pubkey_algo ),
(ulong)keyid2[1],
datestr_from_pk( pk2 ) );
+ if( opt.fingerprint > 1 )
+ fingerprint( pk2, NULL );
}
else if( node->pkt->pkttype == PKT_SECRET_SUBKEY ) {
u32 keyid2[2];
@@ -251,6 +255,9 @@ list_one( const char *name, int secret )
pubkey_letter( sk2->pubkey_algo ),
(ulong)keyid2[1],
datestr_from_sk( sk2 ) );
+ if( opt.fingerprint > 1 )
+ fingerprint( NULL, sk2 );
+
}
else if( opt.list_sigs && node->pkt->pkttype == PKT_SIGNATURE ) {
PKT_signature *sig = node->pkt->pkt.signature;
diff --git a/g10/main.h b/g10/main.h
index fdb01343f..573158a73 100644
--- a/g10/main.h
+++ b/g10/main.h
@@ -72,14 +72,13 @@ int clearsign_file( const char *fname, STRLIST locusr, const char *outfile );
int check_key_signature( KBNODE root, KBNODE node, int *is_selfsig );
/*-- keyedit.c --*/
-int sign_key( const char *username, STRLIST locusr );
-int edit_keysigs( const char *username );
int delete_key( const char *username, int secure );
-int change_passphrase( const char *username );
+void keyedit_menu( const char *username, STRLIST locusr );
/*-- keygen.c --*/
void generate_keypair(void);
-void generate_subkeypair(const char *userid);
+int keygen_add_std_prefs( PKT_signature *sig, void *opaque );
+int generate_subkeypair( KBNODE pub_keyblock, KBNODE sec_keyblock );
/*-- openfile.c --*/
int overwrite_filep( const char *fname );
diff --git a/g10/mainproc.c b/g10/mainproc.c
index cd3e85a8b..e7dabf5e9 100644
--- a/g10/mainproc.c
+++ b/g10/mainproc.c
@@ -520,6 +520,8 @@ list_node( CTX c, KBNODE node )
}
if( !any )
putchar('\n');
+ if( !mainkey && opt.fingerprint > 1 )
+ print_fingerprint( pk, NULL );
}
else if( (mainkey = (node->pkt->pkttype == PKT_SECRET_KEY) )
|| node->pkt->pkttype == PKT_SECRET_SUBKEY ) {
@@ -583,6 +585,8 @@ list_node( CTX c, KBNODE node )
}
if( !any )
putchar('\n');
+ if( !mainkey && opt.fingerprint > 1 )
+ print_fingerprint( NULL, sk );
}
else if( node->pkt->pkttype == PKT_SIGNATURE ) {
PKT_signature *sig = node->pkt->pkt.signature;
diff --git a/g10/misc.c b/g10/misc.c
index ec7c40a1a..6ae065a98 100644
--- a/g10/misc.c
+++ b/g10/misc.c
@@ -98,7 +98,7 @@ checksum_u16( unsigned n )
u16 a;
a = (n >> 8) & 0xff;
- if( opt.emulate_bugs & 1 ) {
+ if( opt.emulate_bugs & EMUBUG_GPGCHKSUM ) {
a |= n & 0xff;
log_debug("csum_u16 emulated for n=%u\n", n);
}
@@ -142,7 +142,7 @@ checksum_mpi( MPI a )
* this stored value if it is still available.
*/
- if( opt.emulate_bugs & 1 )
+ if( opt.emulate_bugs & EMUBUG_GPGCHKSUM )
nbits = 0;
else
nbits = mpi_get_nbit_info(a);
diff --git a/g10/options.h b/g10/options.h
index 80a6539ec..0c9e17fc1 100644
--- a/g10/options.h
+++ b/g10/options.h
@@ -50,10 +50,12 @@ struct {
int compress_sigs;
int always_trust;
int rfc1991;
- unsigned emulate_bugs; /* bug emulation flags */
+ unsigned emulate_bugs; /* bug emulation flags EMUBUG_xxxx */
} opt;
+#define EMUBUG_GPGCHKSUM 1
+
#define DBG_PACKET_VALUE 1 /* debug packet reading/writing */
#define DBG_MPI_VALUE 2 /* debug mpi details */
#define DBG_CIPHER_VALUE 4 /* debug cipher handling */
diff --git a/g10/packet.h b/g10/packet.h
index cef9afe5c..6a35cd89e 100644
--- a/g10/packet.h
+++ b/g10/packet.h
@@ -258,7 +258,9 @@ void free_comment( PKT_comment *rem );
void free_packet( PACKET *pkt );
PKT_public_key *copy_public_key( PKT_public_key *d, PKT_public_key *s );
PKT_secret_key *copy_secret_key( PKT_secret_key *d, PKT_secret_key *s );
-int cmp_public_keys( PKT_public_key *a, PKT_public_key *b );
+PKT_signature *copy_signature( PKT_signature *d, PKT_signature *s );
+PKT_user_id *copy_user_id( PKT_user_id *d, PKT_user_id *s );
+int cmp_public_keys( PKT_public_key *d, PKT_public_key *s );
int cmp_public_secret_key( PKT_public_key *pk, PKT_secret_key *sk );
int cmp_user_ids( PKT_user_id *a, PKT_user_id *b );
@@ -298,4 +300,7 @@ int make_keysig_packet( PKT_signature **ret_sig, PKT_public_key *pk,
int (*mksubpkt)(PKT_signature *, void *),
void *opaque );
+/*-- keygen.c --*/
+PKT_user_id *generate_user_id(void);
+
#endif /*G10_PACKET_H*/
diff --git a/g10/parse-packet.c b/g10/parse-packet.c
index 310feae29..60e0042da 100644
--- a/g10/parse-packet.c
+++ b/g10/parse-packet.c
@@ -349,7 +349,7 @@ parse( IOBUF inp, PACKET *pkt, int reqtype, ulong *retpos,
}
leave:
- if( rc == -1 && iobuf_error(inp) )
+ if( !rc && iobuf_error(inp) )
rc = G10ERR_INV_KEYRING;
return rc;
}
@@ -434,7 +434,8 @@ skip_rest( IOBUF inp, unsigned long pktlen )
}
else {
for( ; pktlen; pktlen-- )
- iobuf_get(inp);
+ if( iobuf_get(inp) == -1 )
+ break;
}
}
@@ -1048,6 +1049,7 @@ parse_key( IOBUF inp, int pkttype, unsigned long pktlen,
rc = G10ERR_INVALID_PACKET;
goto leave;
}
+ /* fixme: Add support for other blocksizes */
for(i=0; i < 8 && pktlen; i++, pktlen-- )
temp[i] = iobuf_get_noeof(inp);
if( list_mode ) {
diff --git a/g10/seckey-cert.c b/g10/seckey-cert.c
index 042b90fe8..6bffb7843 100644
--- a/g10/seckey-cert.c
+++ b/g10/seckey-cert.c
@@ -53,6 +53,8 @@ do_check( PKT_secret_key *sk )
BUG();
if( check_cipher_algo( sk->protect.algo ) )
return G10ERR_CIPHER_ALGO; /* unsupported protection algorithm */
+ if( cipher_get_blocksize( sk->protect.algo ) != 8 )
+ return G10ERR_CIPHER_ALGO; /* unsupported protection algorithm */
keyid_from_sk( sk, keyid );
dek = passphrase_to_dek( keyid, sk->protect.algo,
&sk->protect.s2k, 0 );
@@ -76,7 +78,7 @@ do_check( PKT_secret_key *sk )
csum += checksum_mpi( sk->skey[i] );
m_free( buffer );
}
- if( opt.emulate_bugs & 1 ) {
+ if( opt.emulate_bugs & EMUBUG_GPGCHKSUM ) {
csum = sk->csum;
}
cipher_close( cipher_hd );
@@ -180,6 +182,8 @@ protect_secret_key( PKT_secret_key *sk, DEK *dek )
if( check_cipher_algo( sk->protect.algo ) )
rc = G10ERR_CIPHER_ALGO; /* unsupport protection algorithm */
+ else if( cipher_get_blocksize( sk->protect.algo ) != 8 )
+ rc = G10ERR_CIPHER_ALGO; /* unsupport protection algorithm */
else {
cipher_hd = cipher_open( sk->protect.algo,
CIPHER_MODE_AUTO_CFB, 1 );
diff --git a/g10/sign.c b/g10/sign.c
index 6192d5987..2aa9468e9 100644
--- a/g10/sign.c
+++ b/g10/sign.c
@@ -650,4 +650,112 @@ clearsign_file( const char *fname, STRLIST locusr, const char *outfile )
}
+/****************
+ * Create a signature packet for the given public key certificate
+ * and the user id and return it in ret_sig. User signature class SIGCLASS
+ * user-id is not used (and may be NULL if sigclass is 0x20)
+ * If digest_algo is 0 the function selects an appropriate one.
+ */
+int
+make_keysig_packet( PKT_signature **ret_sig, PKT_public_key *pk,
+ PKT_user_id *uid, PKT_public_key *subpk,
+ PKT_secret_key *sk,
+ int sigclass, int digest_algo,
+ int (*mksubpkt)(PKT_signature *, void *), void *opaque
+ )
+{
+ PKT_signature *sig;
+ int rc=0;
+ MD_HANDLE md;
+
+ assert( (sigclass >= 0x10 && sigclass <= 0x13)
+ || sigclass == 0x20 || sigclass == 0x18 );
+ if( !digest_algo ) {
+ switch( sk->pubkey_algo ) {
+ case PUBKEY_ALGO_DSA: digest_algo = DIGEST_ALGO_SHA1; break;
+ case PUBKEY_ALGO_RSA_S:
+ case PUBKEY_ALGO_RSA: digest_algo = DIGEST_ALGO_MD5; break;
+ default: digest_algo = DIGEST_ALGO_RMD160; break;
+ }
+ }
+ md = md_open( digest_algo, 0 );
+
+ /* hash the public key certificate and the user id */
+ hash_public_key( md, pk );
+ if( sigclass == 0x18 ) { /* subkey binding */
+ hash_public_key( md, subpk );
+ }
+ else if( sigclass != 0x20 ) {
+ if( sk->version >=4 ) {
+ byte buf[5];
+ buf[0] = 0xb4; /* indicates a userid packet */
+ buf[1] = uid->len >> 24; /* always 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 );
+ }
+ /* and make the signature packet */
+ sig = m_alloc_clear( sizeof *sig );
+ sig->version = sk->version;
+ keyid_from_sk( sk, sig->keyid );
+ sig->pubkey_algo = sk->pubkey_algo;
+ sig->digest_algo = digest_algo;
+ sig->timestamp = make_timestamp();
+ sig->sig_class = sigclass;
+ if( sig->version >= 4 )
+ build_sig_subpkt_from_sig( sig );
+
+ if( sig->version >= 4 && mksubpkt )
+ rc = (*mksubpkt)( sig, opaque );
+
+ if( !rc ) {
+ if( sig->version >= 4 )
+ md_putc( md, sig->version );
+ md_putc( md, sig->sig_class );
+ if( sig->version < 4 ) {
+ u32 a = sig->timestamp;
+ md_putc( md, (a >> 24) & 0xff );
+ md_putc( md, (a >> 16) & 0xff );
+ md_putc( md, (a >> 8) & 0xff );
+ md_putc( md, a & 0xff );
+ }
+ else {
+ byte buf[6];
+ size_t n;
+
+ md_putc( md, sig->pubkey_algo );
+ md_putc( md, sig->digest_algo );
+ if( sig->hashed_data ) {
+ n = (sig->hashed_data[0] << 8) | sig->hashed_data[1];
+ md_write( md, sig->hashed_data, n+2 );
+ n += 6;
+ }
+ else
+ n = 6;
+ /* add some magic */
+ buf[0] = sig->version;
+ buf[1] = 0xff;
+ buf[2] = n >> 24; /* hmmm, n is only 16 bit, so this is always 0 */
+ buf[3] = n >> 16;
+ buf[4] = n >> 8;
+ buf[5] = n;
+ md_write( md, buf, 6 );
+
+ }
+ md_final(md);
+
+ rc = complete_sig( sig, sk, md );
+ }
+
+ md_close( md );
+ if( rc )
+ free_seckey_enc( sig );
+ else
+ *ret_sig = sig;
+ return rc;
+}
+
diff --git a/g10/tdbio.c b/g10/tdbio.c
index ac1266147..36f0ac503 100644
--- a/g10/tdbio.c
+++ b/g10/tdbio.c
@@ -45,46 +45,8 @@ static char *db_name;
static int db_fd = -1;
-
-static void create_db( const char *fname );
static void open_db(void);
-/**************************************************
- ************** read and write helpers ************
- **************************************************/
-
-static void
-fwrite_8(FILE *fp, byte a)
-{
- if( putc( a & 0xff, fp ) == EOF )
- log_fatal("error writing byte to trustdb: %s\n", strerror(errno) );
-}
-
-
-static void
-fwrite_32( FILE*fp, ulong a)
-{
- putc( (a>>24) & 0xff, fp );
- putc( (a>>16) & 0xff, fp );
- putc( (a>> 8) & 0xff, fp );
- if( putc( a & 0xff, fp ) == EOF )
- log_fatal("error writing ulong to trustdb: %s\n", strerror(errno) );
-}
-
-static void
-fwrite_zeros( FILE *fp, size_t n)
-{
- while( n-- )
- if( putc( 0, fp ) == EOF )
- log_fatal("error writing zeros to trustdb: %s\n", strerror(errno) );
-}
-
-
-
-
-/**************************************************
- ************** read and write stuff **************
- **************************************************/
int
tdbio_set_dbname( const char *new_dbname, int create )
@@ -101,7 +63,11 @@ tdbio_set_dbname( const char *new_dbname, int create )
return G10ERR_TRUSTDB;
}
if( create ) {
+ FILE *fp;
+ TRUSTREC rec;
+ int rc;
char *p = strrchr( fname, '/' );
+
assert(p);
*p = 0;
if( access( fname, F_OK ) ) {
@@ -119,7 +85,30 @@ tdbio_set_dbname( const char *new_dbname, int create )
log_fatal_f(fname, _("directory does not exist!\n") );
}
*p = '/';
- create_db( fname );
+
+ fp =fopen( fname, "w" );
+ if( !fp )
+ log_fatal_f( fname, _("can't create: %s\n"), strerror(errno) );
+ fclose(fp);
+ m_free(db_name);
+ db_name = fname;
+ db_fd = open( db_name, O_RDWR );
+ if( db_fd == -1 )
+ log_fatal_f( db_name, _("can't open: %s\n"), strerror(errno) );
+
+ memset( &rec, 0, sizeof rec );
+ rec.r.ver.version = 2;
+ rec.r.ver.created = make_timestamp();
+ rec.rectype = RECTYPE_VER;
+ rec.recnum = 0;
+ rc = tdbio_write_record( &rec );
+ if( rc )
+ log_fatal_f( fname, _("failed to create version record: %s"),
+ g10_errstr(rc));
+ /* and read again to check that we are okay */
+ if( tdbio_read_record( 0, &rec, RECTYPE_VER ) )
+ log_fatal_f( db_name, "invalid trust-db created\n" );
+ return 0;
}
}
m_free(db_name);
@@ -136,37 +125,6 @@ tdbio_get_dbname()
-/****************
- * Create a new trustdb
- */
-static void
-create_db( const char *fname )
-{
- FILE *fp;
-
- fp =fopen( fname, "w" );
- if( !fp )
- log_fatal_f( fname, _("can't create %s: %s\n"), strerror(errno) );
- fwrite_8( fp, 1 ); /* record type */
- fwrite_8( fp, 'g' );
- fwrite_8( fp, 'p' );
- fwrite_8( fp, 'g' );
- fwrite_8( fp, 2 ); /* version */
- fwrite_zeros( fp, 3 ); /* reserved */
- fwrite_32( fp, 0 ); /* not locked */
- fwrite_32( fp, make_timestamp() ); /* created */
- fwrite_32( fp, 0 ); /* not yet modified */
- fwrite_32( fp, 0 ); /* not yet validated*/
- fwrite_32( fp, 0 ); /* reserved */
- fwrite_8( fp, 3 ); /* marginals needed */
- fwrite_8( fp, 1 ); /* completes needed */
- fwrite_8( fp, 4 ); /* max_cet_depth */
- fwrite_zeros( fp, 9 ); /* filler */
- fclose(fp);
-}
-
-
-
static void
open_db()
{
@@ -182,10 +140,221 @@ open_db()
}
+/****************
+ * Return the record number of the keyhash tbl or create a new one.
+ */
+static ulong
+get_keyhashrec()
+{
+ static ulong keyhashtbl; /* record number of the key hashtable */
+ TRUSTREC vr;
+ int rc;
+
+ if( keyhashtbl )
+ return keyhashtbl;
+
+ rc = tdbio_read_record( 0, &vr, RECTYPE_VER );
+ if( rc )
+ log_fatal_f( db_name, _("error reading version record: %s\n"),
+ g10_errstr(rc) );
+ if( vr.r.ver.keyhashtbl )
+ keyhashtbl = vr.r.ver.keyhashtbl;
+ else {
+ TRUSTREC rec;
+ off_t offset;
+ ulong recnum;
+ int i, n;
+
+ offset = lseek( db_fd, 0, SEEK_END );
+ if( offset == -1 )
+ log_fatal("trustdb: lseek to end failed: %s\n", strerror(errno) );
+ recnum = offset / TRUST_RECORD_LEN;
+ assert(recnum); /* this is will never be the first record */
+
+ keyhashtbl = recnum;
+ /* Now write the records */
+ n = (256+ITEMS_PER_HTBL_RECORD-1) / ITEMS_PER_HTBL_RECORD;
+ for(i=0; i < n; i++, recnum++ ) {
+ memset( &rec, 0, sizeof rec );
+ rec.rectype = RECTYPE_HTBL; /* free record */
+ rec.recnum = recnum;
+ rc = tdbio_write_record( &rec );
+ if( rc )
+ log_fatal_f(db_name,_("failed to create hashtable: %s\n"),
+ g10_errstr(rc));
+ }
+ /* update the version record */
+ vr.r.ver.keyhashtbl = keyhashtbl;
+ rc = tdbio_write_record( &vr );
+ if( rc )
+ log_fatal_f( db_name, _("error updating version record: %s\n"),
+ g10_errstr(rc));
+ }
+ return keyhashtbl;
+}
+
+
+/****************
+ * Update the key hashtbl or create the table if it does not exist
+ */
+static int
+update_keyhashtbl( TRUSTREC *kr )
+{
+ TRUSTREC lastrec, rec;
+ ulong hashrec, item;
+ int msb;
+ int level=0;
+ int rc, i;
+
+ hashrec = get_keyhashrec();
+ next_level:
+ msb = kr->r.key.fingerprint[level];
+ hashrec += msb / ITEMS_PER_HTBL_RECORD;
+ rc = tdbio_read_record( hashrec, &rec, RECTYPE_HTBL );
+ if( rc ) {
+ log_error( db_name, "update_keyhashtbl read failed: %s\n",
+ g10_errstr(rc) );
+ return rc;
+ }
+
+ item = rec.r.htbl.item[msb % ITEMS_PER_HTBL_RECORD];
+ if( !item ) { /* insert new one */
+ rec.r.htbl.item[msb % ITEMS_PER_HTBL_RECORD] = kr->recnum;
+ rc = tdbio_write_record( &rec );
+ if( rc ) {
+ log_error( db_name, "update_keyhashtbl write htbl failed: %s\n",
+ g10_errstr(rc) );
+ return rc;
+ }
+ }
+ else if( item != kr->recnum ) { /* must do an update */
+ lastrec = rec;
+ rc = tdbio_read_record( item, &rec, 0 );
+ if( rc ) {
+ log_error( db_name, "update_keyhashtbl read item failed: %s\n",
+ g10_errstr(rc) );
+ return rc;
+ }
+ if( rec.rectype == RECTYPE_HTBL ) {
+ hashrec = item;
+ level++;
+ if( level >= kr->r.key.fingerprint_len ) {
+ log_error( db_name, "keyhashtbl has invalid indirections\n");
+ return G10ERR_TRUSTDB;
+ }
+ goto next_level;
+ }
+ else if( rec.rectype == RECTYPE_HLST ) { /* extend list */
+ /* see whether the key is already in this list */
+ for(;;) {
+ for(i=0; i < ITEMS_PER_HLST_RECORD; i++ ) {
+ if( rec.r.hlst.rnum[i] == kr->recnum ) {
+ log_debug("HTBL: no update needed for keyrec %lu\n",
+ kr->recnum );
+ return 0;
+ }
+ }
+ if( rec.r.hlst.next ) {
+ rc = tdbio_read_record( rec.r.hlst.next,
+ &rec, RECTYPE_HLST);
+ if( rc ) {
+ log_error( db_name,
+ "scan keyhashtbl read hlst failed: %s\n",
+ g10_errstr(rc) );
+ return rc;
+ }
+ }
+ else
+ break; /* not there */
+ }
+ /* find the next free entry and put it in */
+ for(;;) {
+ for(i=0; i < ITEMS_PER_HLST_RECORD; i++ ) {
+ if( !rec.r.hlst.rnum[i] ) {
+ rec.r.hlst.rnum[i] = kr->recnum;
+ rc = tdbio_write_record( &rec );
+ if( rc )
+ log_error( db_name,
+ "update_keyhashtbl write hlst failed: %s\n",
+ g10_errstr(rc) );
+ return rc; /* ready */
+ }
+ }
+ if( rec.r.hlst.next ) {
+ rc = tdbio_read_record( rec.r.hlst.next,
+ &rec, RECTYPE_HLST );
+ if( rc ) {
+ log_error( db_name,
+ "update_keyhashtbl read hlst failed: %s\n",
+ g10_errstr(rc) );
+ return rc;
+ }
+ }
+ else { /* add a new list record */
+ rec.r.hlst.next = item = tdbio_new_recnum();
+ rc = tdbio_write_record( &rec );
+ if( rc ) {
+ log_error( db_name,
+ "update_keyhashtbl write hlst failed: %s\n",
+ g10_errstr(rc) );
+ return rc;
+ }
+ memset( &rec, 0, sizeof rec );
+ rec.rectype = RECTYPE_HLST;
+ rec.recnum = item;
+ rec.r.hlst.rnum[0] = kr->recnum;
+ if( rc )
+ log_error( db_name,
+ "update_keyhashtbl write ext hlst failed: %s\n",
+ g10_errstr(rc) );
+ return rc; /* ready */
+ }
+ }
+ }
+ else if( rec.rectype == RECTYPE_KEY ) { /* insert a list record */
+ if( rec.recnum == kr->recnum ) {
+ log_debug("HTBL: no update needed for keyrec %lu\n",
+ kr->recnum );
+ return 0;
+ }
+ item = rec.recnum; /* save number of key record */
+ memset( &rec, 0, sizeof rec );
+ rec.rectype = RECTYPE_HLST;
+ rec.recnum = tdbio_new_recnum();
+ rec.r.hlst.rnum[0] = item; /* old keyrecord */
+ rec.r.hlst.rnum[1] = kr->recnum; /* and new one */
+ rc = tdbio_write_record( &rec );
+ if( rc ) {
+ log_error( db_name,
+ "update_keyhashtbl write new hlst failed: %s\n",
+ g10_errstr(rc) );
+ return rc;
+ }
+ /* update the hashtable record */
+ lastrec.r.htbl.item[msb % ITEMS_PER_HTBL_RECORD] = rec.recnum;
+ rc = tdbio_write_record( &lastrec );
+ if( rc )
+ log_error( db_name,
+ "update_keyhashtbl update htbl failed: %s\n",
+ g10_errstr(rc) );
+ return rc; /* ready */
+ }
+ else {
+ log_error( db_name, "keyhashtbl %lu points to an invalid record\n",
+ item);
+ return G10ERR_TRUSTDB;
+ }
+ }
+
+ return 0;
+}
+
+
+
void
tdbio_dump_record( TRUSTREC *rec, FILE *fp )
{
- int i, any;
+ int i;
ulong rnum = rec->recnum;
fprintf(fp, "rec %5lu, ", rnum );
@@ -193,7 +362,8 @@ tdbio_dump_record( TRUSTREC *rec, FILE *fp )
switch( rec->rectype ) {
case 0: fprintf(fp, "free\n");
break;
- case RECTYPE_VER: fprintf(fp, "version\n");
+ case RECTYPE_VER: fprintf(fp, "version, keyhashtbl=%lu\n",
+ rec->r.ver.keyhashtbl );
break;
case RECTYPE_DIR:
fprintf(fp, "dir %lu, keys=%lu, uids=%lu, cach=%lu, ot=%02x",
@@ -213,11 +383,12 @@ tdbio_dump_record( TRUSTREC *rec, FILE *fp )
putc('\n', fp);
break;
case RECTYPE_KEY:
- fprintf(fp, "key %lu, next=%lu, algo=%d, flen=%d",
+ fprintf(fp, "key %lu, next=%lu, algo=%d, ",
rec->r.key.lid,
rec->r.key.next,
- rec->r.key.pubkey_algo,
- rec->r.key.fingerprint_len );
+ rec->r.key.pubkey_algo );
+ for(i=0; i < rec->r.key.fingerprint_len; i++ )
+ fprintf(fp, "%02X", rec->r.key.fingerprint[i] );
if( rec->r.key.keyflags & KEYF_REVOKED )
fputs(", revoked", fp );
putc('\n', fp);
@@ -239,29 +410,29 @@ tdbio_dump_record( TRUSTREC *rec, FILE *fp )
rec->r.uid.next);
break;
case RECTYPE_SIG:
- fprintf(fp, "sig %lu, next=%lu\n",
+ fprintf(fp, "sig %lu, next=%lu,",
rec->r.sig.lid, rec->r.sig.next );
- for(i=any=0; i < SIGS_PER_RECORD; i++ ) {
- if( rec->r.sig.sig[i].lid ) {
- if( !any ) {
- putc('\t', fp);
- any++;
- }
- fprintf(fp, " %lu:%02x", rec->r.sig.sig[i].lid,
+ for(i=0; i < SIGS_PER_RECORD; i++ ) {
+ if( rec->r.sig.sig[i].lid )
+ fprintf(fp, " %lu:%02x", rec->r.sig.sig[i].lid,
rec->r.sig.sig[i].flag );
- }
}
- if( any )
- putc('\n', fp);
+ putc('\n', fp);
break;
case RECTYPE_CACH:
fprintf(fp, "cach\n");
break;
case RECTYPE_HTBL:
- fprintf(fp, "htbl\n");
+ fprintf(fp, "htbl,");
+ for(i=0; i < ITEMS_PER_HTBL_RECORD; i++ )
+ fprintf(fp, " %lu", rec->r.htbl.item[i] );
+ putc('\n', fp);
break;
case RECTYPE_HLST:
- fprintf(fp, "hlst\n");
+ fprintf(fp, "hlst, next=%lu,", rec->r.hlst.next );
+ for(i=0; i < ITEMS_PER_HLST_RECORD; i++ )
+ fprintf(fp, " %lu", rec->r.hlst.rnum[i] );
+ putc('\n', fp);
break;
default:
fprintf(fp, "unknown type %d\n", rec->rectype );
@@ -302,30 +473,29 @@ tdbio_read_record( ulong recnum, TRUSTREC *rec, int expected )
recnum, expected, rec->rectype );
return G10ERR_TRUSTDB;
}
- p++;
+ p++; /* skip reserved byte */
switch( rec->rectype ) {
- case 0: /* unused record */
+ case 0: /* unused (free) record */
break;
case RECTYPE_VER: /* version record */
if( memcmp(buf+1, "gpg", 3 ) ) {
log_error_f( db_name, _("not a trustdb file\n") );
rc = G10ERR_TRUSTDB;
}
- p += 2; /* skip magic */
+ p += 2; /* skip "pgp" */
rec->r.ver.version = *p++;
- rec->r.ver.locked = buftoulong(p); p += 4;
+ p += 3; /* reserved bytes */
+ p += 4; /* lock flags */
rec->r.ver.created = buftoulong(p); p += 4;
rec->r.ver.modified = buftoulong(p); p += 4;
rec->r.ver.validated= buftoulong(p); p += 4;
- rec->r.ver.marginals_needed = *p++;
- rec->r.ver.completes_needed = *p++;
- rec->r.ver.max_cert_depth = *p++;
+ rec->r.ver.keyhashtbl=buftoulong(p); p += 4;
if( recnum ) {
log_error_f( db_name, "version record with recnum %lu\n",
(ulong)recnum );
rc = G10ERR_TRUSTDB;
}
- if( rec->r.ver.version != 2 ) {
+ else if( rec->r.ver.version != 2 ) {
log_error_f( db_name, "invalid file version %d\n",
rec->r.ver.version );
rc = G10ERR_TRUSTDB;
@@ -381,6 +551,17 @@ tdbio_read_record( ulong recnum, TRUSTREC *rec, int expected )
memcpy(rec->r.cache.blockhash, p, 20); p += 20;
rec->r.cache.trustlevel = *p++;
break;
+ case RECTYPE_HTBL:
+ for(i=0; i < ITEMS_PER_HTBL_RECORD; i++ ) {
+ rec->r.htbl.item[i] = buftoulong(p); p += 4;
+ }
+ break;
+ case RECTYPE_HLST:
+ rec->r.hlst.next = buftoulong(p); p += 4;
+ for(i=0; i < ITEMS_PER_HLST_RECORD; i++ ) {
+ rec->r.hlst.rnum[i] = buftoulong(p); p += 4;
+ }
+ break;
default:
log_error_f( db_name, "invalid record type %d at recnum %lu\n",
rec->rectype, (ulong)recnum );
@@ -412,8 +593,16 @@ tdbio_write_record( TRUSTREC *rec )
switch( rec->rectype ) {
case 0: /* unused record */
break;
- case 1: /* version record */
- BUG();
+ case RECTYPE_VER: /* version record */
+ if( recnum )
+ BUG();
+ memcpy(p-1, "gpg", 3 ); p += 2;
+ *p++ = rec->r.ver.version;
+ p += 7; /* skip reserved bytes and lock flags */
+ ulongtobuf(p, rec->r.ver.created); p += 4;
+ ulongtobuf(p, rec->r.ver.modified); p += 4;
+ ulongtobuf(p, rec->r.ver.validated); p += 4;
+ ulongtobuf(p, rec->r.ver.keyhashtbl); p += 4;
break;
case RECTYPE_DIR: /*directory record */
@@ -466,6 +655,19 @@ tdbio_write_record( TRUSTREC *rec )
*p++ = rec->r.cache.trustlevel;
break;
+ case RECTYPE_HTBL:
+ for(i=0; i < ITEMS_PER_HTBL_RECORD; i++ ) {
+ ulongtobuf( p, rec->r.htbl.item[i]); p += 4;
+ }
+ break;
+
+ case RECTYPE_HLST:
+ ulongtobuf( p, rec->r.hlst.next); p += 4;
+ for(i=0; i < ITEMS_PER_HLST_RECORD; i++ ) {
+ ulongtobuf( p, rec->r.hlst.rnum[i]); p += 4;
+ }
+ break;
+
default:
BUG();
}
@@ -479,6 +681,8 @@ tdbio_write_record( TRUSTREC *rec )
log_error(_("trustdb: write failed (n=%d): %s\n"), n, strerror(errno) );
return G10ERR_WRITE_FILE;
}
+ else if( rec->rectype == RECTYPE_KEY )
+ rc = update_keyhashtbl( rec );
return rc;
}
@@ -528,9 +732,6 @@ tdbio_new_recnum()
/****************
* Search the trustdb for a key which matches PK and return the dir record
* The local_id of PK is set to the correct value
- *
- * Note: To increase performance, we could use a index search here.
- * tdbio_write_record shoudl create this index automagically
*/
int
tdbio_search_dir_record( PKT_public_key *pk, TRUSTREC *rec )
@@ -540,32 +741,111 @@ tdbio_search_dir_record( PKT_public_key *pk, TRUSTREC *rec )
byte *fingerprint;
size_t fingerlen;
int rc;
+ ulong hashrec, item;
+ int msb;
+ int level=0;
keyid_from_pk( pk, keyid );
fingerprint = fingerprint_from_pk( pk, NULL, &fingerlen );
assert( fingerlen == 20 || fingerlen == 16 );
- for(recnum=1; !(rc=tdbio_read_record( recnum, rec, 0)); recnum++ ) {
- if( rec->rectype != RECTYPE_KEY )
- continue;
- if( rec->r.key.pubkey_algo == pk->pubkey_algo
- && !memcmp(rec->r.key.fingerprint, fingerprint, fingerlen) ) {
- /* found: read the dir record for this key */
- recnum = rec->r.key.lid;
- rc = tdbio_read_record( recnum, rec, RECTYPE_DIR);
- if( rc )
- break;
- if( pk->local_id && pk->local_id != recnum )
- log_error_f(db_name,
- "found record, but LID from memory does "
- "not match recnum (%lu,%lu)\n",
- pk->local_id, recnum );
- pk->local_id = recnum;
- return 0;
+ /* locate the key using the hash table */
+ hashrec = get_keyhashrec();
+ next_level:
+ msb = fingerprint[level];
+ hashrec += msb / ITEMS_PER_HTBL_RECORD;
+ rc = tdbio_read_record( hashrec, rec, RECTYPE_HTBL );
+ if( rc ) {
+ log_error( db_name, "scan keyhashtbl failed: %s\n", g10_errstr(rc) );
+ return rc;
+ }
+
+ item = rec->r.htbl.item[msb % ITEMS_PER_HTBL_RECORD];
+ if( !item )
+ return -1; /* not found */
+
+ rc = tdbio_read_record( item, rec, 0 );
+ if( rc ) {
+ log_error( db_name, "keyhashtbl read failed: %s\n", g10_errstr(rc) );
+ return rc;
+ }
+ if( rec->rectype == RECTYPE_HTBL ) {
+ hashrec = item;
+ level++;
+ if( level >= fingerlen ) {
+ log_error( db_name, "keyhashtbl has invalid indirections\n");
+ return G10ERR_TRUSTDB;
}
+ goto next_level;
}
- if( rc != -1 )
- log_error_f( db_name, _("search_db failed: %s\n"), g10_errstr(rc) );
+ else if( rec->rectype == RECTYPE_HLST ) {
+ for(;;) {
+ int i;
+
+ for(i=0; i < ITEMS_PER_HLST_RECORD; i++ ) {
+ if( rec->r.hlst.rnum[i] ) {
+ TRUSTREC tmp;
+
+ rc = tdbio_read_record( rec->r.hlst.rnum[i],
+ &tmp, RECTYPE_KEY );
+ if( rc ) {
+ log_error( db_name,
+ "scan keyhashtbl read key failed: %s\n",
+ g10_errstr(rc) );
+ return rc;
+ }
+ if( tmp.r.key.pubkey_algo == pk->pubkey_algo
+ && tmp.r.key.fingerprint_len == fingerlen
+ && !memcmp(tmp.r.key.fingerprint,
+ fingerprint, fingerlen) ) {
+ *rec = tmp;
+ goto found;
+ }
+ }
+ }
+ if( rec->r.hlst.next ) {
+ rc = tdbio_read_record( rec->r.hlst.next, rec, RECTYPE_HLST );
+ if( rc ) {
+ log_error( db_name,
+ "scan keyhashtbl read hlst failed: %s\n",
+ g10_errstr(rc) );
+ return rc;
+ }
+ }
+ else
+ return -1; /* not found */
+ }
+ found:
+ ;
+ }
+ else if( rec->rectype == RECTYPE_KEY ) {
+ /* must check that it is the requested key */
+ if( rec->r.key.pubkey_algo != pk->pubkey_algo
+ || rec->r.key.fingerprint_len != fingerlen
+ || memcmp(rec->r.key.fingerprint, fingerprint, fingerlen) )
+ return -1; /* no: not found */
+ }
+ else {
+ log_error( db_name, "keyhashtbl %lu points to an invalid record\n",
+ item);
+ return G10ERR_TRUSTDB;
+ }
+
+ recnum = rec->r.key.lid;
+
+ if( pk->local_id && pk->local_id != recnum )
+ log_error_f(db_name,
+ "found record, but LID from memory does "
+ "not match recnum (%lu,%lu)\n",
+ pk->local_id, recnum );
+ pk->local_id = recnum;
+
+ /* Now read the dir record */
+ rc = tdbio_read_record( recnum, rec, RECTYPE_DIR);
+ if( rc )
+ log_error_f(db_name, "can't read dirrec %lu: %s\n",
+ recnum, g10_errstr(rc) );
+
return rc;
}
diff --git a/g10/tdbio.h b/g10/tdbio.h
index 8eec40e4a..c37c3ac1f 100644
--- a/g10/tdbio.h
+++ b/g10/tdbio.h
@@ -60,15 +60,12 @@ struct trust_record {
int mark;
ulong recnum;
union {
- struct { /* version record: */
- byte version; /* should be 1 */
- ulong locked; /* pid of process which holds a lock */
+ struct { /* version record: */
+ byte version; /* should be 2 */
ulong created; /* timestamp of trustdb creation */
ulong modified; /* timestamp of last modification */
ulong validated; /* timestamp of last validation */
- byte marginals_needed;
- byte completes_needed;
- byte max_cert_depth;
+ ulong keyhashtbl;
} ver;
struct { /* directory record */
ulong lid;
@@ -117,10 +114,7 @@ struct trust_record {
} htbl;
struct {
ulong next;
- struct {
- byte hash;
- ulong rnum;
- } item[ITEMS_PER_HLST_RECORD];
+ ulong rnum[ITEMS_PER_HLST_RECORD]; /* of a key record */
} hlst;
} r;
};
diff --git a/g10/trustdb.c b/g10/trustdb.c
index b82d26a1e..2bd986c79 100644
--- a/g10/trustdb.c
+++ b/g10/trustdb.c
@@ -23,6 +23,7 @@
#include <stdlib.h>
#include <string.h>
#include <errno.h>
+#include <ctype.h>
#include <assert.h>
#include <sys/types.h>
#include <sys/stat.h>
@@ -102,6 +103,9 @@ static ulong last_trust_web_key;
static TRUST_SEG_LIST last_trust_web_tslist;
+#define HEXTOBIN(a) ( (a) >= '0' && (a) <= '9' ? ((a)-'0') : \
+ (a) >= 'A' && (a) <= 'F' ? ((a)-'A'+10) : ((a)-'a'+10))
+
/**********************************************
************* list helpers *******************
**********************************************/
@@ -945,6 +949,7 @@ update_sigs( TRUSTREC *dir )
}
else {
/* fixme: handle other sig classes here */
+ /* FIXME: Revocations!!! */
}
}
}
@@ -1243,7 +1248,16 @@ list_trustdb( const char *username )
{
TRUSTREC rec;
- if( username ) {
+ if( username && *username == '#' ) {
+ int rc;
+ ulong lid = atoi(username+1);
+
+ if( (rc = list_records( lid)) )
+ log_error("user '%s' read problem: %s\n", username, g10_errstr(rc));
+ else if( (rc = list_sigs( lid )) )
+ log_error("user '%s' list problem: %s\n", username, g10_errstr(rc));
+ }
+ else if( username ) {
PKT_public_key *pk = m_alloc_clear( sizeof *pk );
int rc;
@@ -1274,10 +1288,10 @@ list_trustdb( const char *username )
}
/****************
- * make a list of all defined owner trust value.
+ * Print a list of all defined owner trust value.
*/
void
-list_ownertrust()
+export_ownertrust()
{
TRUSTREC rec;
TRUSTREC rec2;
@@ -1307,6 +1321,67 @@ list_ownertrust()
}
}
+
+void
+import_ownertrust( const char *fname )
+{
+ FILE *fp;
+ int is_stdin=0;
+ char line[256];
+ char *p;
+ size_t n, fprlen;
+ unsigned otrust;
+
+ if( !fname || (*fname == '-' && !fname[1]) ) {
+ fp = stdin;
+ fname = "[stdin]";
+ is_stdin = 1;
+ }
+ else if( !(fp = fopen( fname, "r" )) ) {
+ log_error_f(fname, _("can't open file: %s\n"), strerror(errno) );
+ return;
+ }
+
+ while( fgets( line, DIM(line)-1, fp ) ) {
+ if( !*line || *line == '#' )
+ continue;
+ n = strlen(line);
+ if( line[n-1] != '\n' ) {
+ log_error_f(fname, "line to long\n" );
+ break; /* can't continue */
+ }
+ for(p = line; *p && *p != ':' ; p++ )
+ if( !isxdigit(*p) )
+ break;
+ if( *p != ':' ) {
+ log_error_f(fname, "error: missing colon\n" );
+ continue;
+ }
+ fprlen = p - line;
+ if( fprlen != 32 && fprlen != 40 ) {
+ log_error_f(fname, "error: invalid fingerprint\n" );
+ continue;
+ }
+ if( sscanf(p, ":%u:", &otrust ) != 1 ) {
+ log_error_f(fname, "error: no otrust value\n" );
+ continue;
+ }
+ if( !otrust )
+ continue; /* no otrust defined - no need to update or insert */
+ /* convert the ascii fingerprint to binary */
+ for(p=line, fprlen=0; *p != ':'; p += 2 )
+ line[fprlen++] = HEXTOBIN(p[0]) * 16 + HEXTOBIN(p[1]);
+ line[fprlen] = 0;
+
+ log_hexdump("found: ", line, fprlen );
+ }
+ if( ferror(fp) )
+ log_error_f(fname, _("read error: %s\n"), strerror(errno) );
+ if( !is_stdin )
+ fclose(fp);
+}
+
+
void
list_trust_path( int max_depth, const char *username )
{
@@ -1405,7 +1480,17 @@ check_trustdb( const char *username )
TRUSTREC rec;
int rc;
- if( username ) {
+ if( username && *username == '#' ) {
+ int rc;
+ ulong lid = atoi(username+1);
+
+ if( (rc = update_sigs_by_lid( lid )) )
+ log_error("lid %lu: check failed: %s\n",
+ lid, g10_errstr(rc));
+ else
+ log_info("lid %lu: checked: %s\n", lid, g10_errstr(rc));
+ }
+ else if( username ) {
PKT_public_key *pk = m_alloc_clear( sizeof *pk );
if( (rc = get_pubkey_byname( pk, username )) )
@@ -1724,7 +1809,7 @@ insert_trust_record( PKT_public_key *orig_pk )
BUG(); /* more than one primary key */
keyid_from_pk( pk, keyid );
}
- fingerprint = fingerprint_from_pk( orig_pk, NULL, &fingerlen );
+ fingerprint = fingerprint_from_pk( pk, NULL, &fingerlen );
rec = m_alloc_clear( sizeof *rec );
rec->rectype = RECTYPE_KEY;
rec->r.key.pubkey_algo = pk->pubkey_algo;
diff --git a/g10/trustdb.h b/g10/trustdb.h
index aaf0d4a8d..dba38188b 100644
--- a/g10/trustdb.h
+++ b/g10/trustdb.h
@@ -38,7 +38,8 @@
/*-- trustdb.c --*/
void list_trustdb(const char *username);
void list_trust_path( int max_depth, const char *username );
-void list_ownertrust(void);
+void export_ownertrust(void);
+void import_ownertrust(const char *fname);
void check_trustdb( const char *username );
int init_trustdb( int level, const char *dbname );
int check_trust( PKT_public_key *pk, unsigned *r_trustlevel );
diff --git a/include/cipher.h b/include/cipher.h
index 0e2b95a79..8ddd3655a 100644
--- a/include/cipher.h
+++ b/include/cipher.h
@@ -35,6 +35,7 @@
#define CIPHER_ALGO_DES_SK 6
#define CIPHER_ALGO_BLOWFISH160 42 /* blowfish 160 bit key (not in OpenPGP)*/
#define CIPHER_ALGO_SKIPJACK 101 /* experimental: skipjack */
+#define CIPHER_ALGO_TWOFISH 102 /* experimental: twofish 128 bit */
#define CIPHER_ALGO_DUMMY 110 /* no encryption at all */
#define PUBKEY_ALGO_RSA 1
@@ -130,6 +131,7 @@ int string_to_cipher_algo( const char *string );
const char * cipher_algo_to_string( int algo );
int check_cipher_algo( int algo );
unsigned cipher_get_keylen( int algo );
+unsigned cipher_get_blocksize( int algo );
CIPHER_HANDLE cipher_open( int algo, int mode, int secure );
void cipher_close( CIPHER_HANDLE c );
void cipher_setkey( CIPHER_HANDLE c, byte *key, unsigned keylen );
diff --git a/include/ttyio.h b/include/ttyio.h
index 2949cfd19..e4119db86 100644
--- a/include/ttyio.h
+++ b/include/ttyio.h
@@ -25,6 +25,7 @@ void tty_print_string( byte *p, size_t n );
char *tty_get( const char *prompt );
char *tty_get_hidden( const char *prompt );
void tty_kill_prompt(void);
+int tty_get_answer_is_yes( const char *prompt );
#endif /*G10_TTYIO_H*/
diff --git a/mpi/g10m.c b/mpi/g10m.c
index 6cad79587..28feaf08c 100644
--- a/mpi/g10m.c
+++ b/mpi/g10m.c
@@ -49,7 +49,7 @@ g10m_release( MPI a )
void
g10m_resize( MPI a, unsigned nbits )
{
- return mpi_resize( a, (nbits+BITS_PER_MPI_LIMB-1) / BITS_PER_MPI_LIMB );
+ mpi_resize( a, (nbits+BITS_PER_MPI_LIMB-1) / BITS_PER_MPI_LIMB );
}
MPI g10m_copy( MPI a ) { return mpi_copy( a ); }
diff --git a/mpi/mpi-inv.c b/mpi/mpi-inv.c
index 25efbd979..150d87ca1 100644
--- a/mpi/mpi-inv.c
+++ b/mpi/mpi-inv.c
@@ -120,6 +120,7 @@ mpi_invm( MPI x, MPI a, MPI n )
mpi_rshift(t2, t2, 1);
mpi_rshift(t3, t3, 1);
Y4:
+ ;
} while( !mpi_test_bit( t3, 0 ) ); /* while t3 is even */
if( !t3->sign ) {
@@ -216,6 +217,7 @@ mpi_invm( MPI x, MPI a, MPI n )
mpi_rshift(t3, t3, 1);
}
Y4:
+ ;
} while( !mpi_test_bit( t3, 0 ) ); /* while t3 is even */
if( !t3->sign ) {
diff --git a/po/de.po b/po/de.po
index 54cc7eab2..9b0de2d28 100644
--- a/po/de.po
+++ b/po/de.po
@@ -400,11 +400,6 @@ msgstr "--clearsign [Dateiname]"
msgid "--decrypt [filename]"
msgstr "--decrypt [Dateiname]"
-#. sign the key given as argument
-#: g10/g10.c:802
-msgid "--sign-key username"
-msgstr "--sign-key Benutzername"
-
#: g10/g10.c:810
msgid "--edit-key username"
msgstr "--edit-key Benutzername"
@@ -417,12 +412,6 @@ msgstr "--delete-secret-key Benutzername"
msgid "--delete-key username"
msgstr "--delete-key Benutzername"
-#. Change the passphrase
-#. no arg: use default, 1 arg use this one
-#: g10/g10.c:829
-msgid "--change-passphrase [username]"
-msgstr "--change-passphrase [Benutzername]"
-
#. prepare iobufs
#: g10/encode.c:200 g10/g10.c:853 g10/keylist.c:79
msgid "can't open %s: %s\n"
@@ -810,12 +799,12 @@ msgstr "\"passphrase\" nicht richtig wiederholt; noch einmal.\n"
msgid ""
"You don't want a passphrase - this is probably a *bad* idea!\n"
"I will do it anyway. You can change your passphrase at any time,\n"
-"using this program with the option \"--change-passphrase\".\n"
+"using this program with the option \"--edit-key\".\n"
"\n"
msgstr ""
"Sie m\366chten keine \"passphrase\" - Dies ist eine *schlechte* Idee!\n"
"Es ist trotzdem m\366glich. Sie k\366nnen Ihre \"phassphrase\" jederzeit\n"
-"\344ndern, indem sie dieses Programm mit dem Kommando \"--change-passphrase\"\n"
+"\344ndern, indem sie dieses Programm mit dem Kommando \"--edit-key\"\n"
"aufrufen.\n"
"\n"
diff --git a/util/ChangeLog b/util/ChangeLog
index a52ea0a69..aa9afe6e3 100644
--- a/util/ChangeLog
+++ b/util/ChangeLog
@@ -1,3 +1,7 @@
+Wed Jul 29 14:53:34 1998 Werner Koch (wk@(none))
+
+ * ttyio.c (tty_get_answer_is_yes): New.
+
Tue Jul 21 10:35:48 1998 Werner Koch (wk@(none))
* argparse.c: New option flag to distinguish options and commands.
diff --git a/util/miscutil.c b/util/miscutil.c
index 3bdc68a21..e4c2cf1ae 100644
--- a/util/miscutil.c
+++ b/util/miscutil.c
@@ -91,3 +91,4 @@ answer_is_yes( const char *s )
return 0;
}
+
diff --git a/util/secmem.c b/util/secmem.c
index 4721bcd91..d12621324 100644
--- a/util/secmem.c
+++ b/util/secmem.c
@@ -204,7 +204,7 @@ secmem_malloc( size_t size )
}
/* allocate a new block */
if( (poollen + size <= poolsize) ) {
- mb = pool + poollen;
+ mb = (void*)((char*)pool + poollen);
poollen += size;
mb->size = size;
}
@@ -240,7 +240,7 @@ secmem_realloc( void *p, size_t newsize )
return p; /* it is easier not to shrink the memory */
a = secmem_malloc( newsize );
memcpy(a, p, size);
- memset(a+size, 0, newsize-size);
+ memset((char*)a+size, 0, newsize-size);
secmem_free(p);
return a;
}
@@ -271,7 +271,7 @@ secmem_free( void *a )
int
m_is_secure( const void *p )
{
- return p >= pool && p < (pool+poolsize);
+ return p >= pool && p < ((char*)pool+poolsize);
}
void
diff --git a/util/ttyio.c b/util/ttyio.c
index bb795c282..99927d660 100644
--- a/util/ttyio.c
+++ b/util/ttyio.c
@@ -328,3 +328,15 @@ tty_kill_prompt()
last_prompt_len = 0;
}
+
+int
+tty_get_answer_is_yes( const char *prompt )
+{
+ int yes;
+ char *p = tty_get( prompt );
+ tty_kill_prompt();
+ yes = answer_is_yes(p);
+ m_free(p);
+ return yes;
+}
+