edit-key is now complete

This commit is contained in:
Werner Koch 1998-07-29 19:35:05 +00:00
parent 1a80de41a5
commit 5ae562b41d
48 changed files with 2044 additions and 984 deletions

View File

@ -6,3 +6,7 @@ Werner Koch. Designed and implemented gnupg.
TRANSLATIONS Marco d'Itri 1997-02-22 TRANSLATIONS Marco d'Itri 1997-02-22
Disclaim Disclaim
Twofish Matthew Skala ????????????

25
NEWS
View File

@ -1,12 +1,37 @@
Noteworthy changes in version 0.3.3 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 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 * Signatures are now checked even if the output file could not
be created. Command "--verify" tries to find the detached data. be created. Command "--verify" tries to find the detached data.
* gpg now disables core dumps. * 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 Noteworthy changes in version 0.3.2
----------------------------------- -----------------------------------

3
README
View File

@ -135,6 +135,9 @@
Creates a signature of file, but writes the output to the file "out". 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 Encrypt
------- -------

3
THANKS
View File

@ -5,6 +5,7 @@ errors.
Anand Kumria wildfire@progsoc.uts.edu.au Anand Kumria wildfire@progsoc.uts.edu.au
Brian Warner warner@lothar.com Brian Warner warner@lothar.com
Caskey L. Dickson caskey@technocage.com
Charles Levert charles@comm.polymtl.ca Charles Levert charles@comm.polymtl.ca
Christian von Roques roques@pond.sub.org Christian von Roques roques@pond.sub.org
Daniel Eisenbud eisenbud@cs.swarthmore.edu Daniel Eisenbud eisenbud@cs.swarthmore.edu
@ -25,8 +26,10 @@ Martin Schulte schulte@thp.uni-koeln.de
Matthew Skala mskala@ansuz.sooke.bc.ca Matthew Skala mskala@ansuz.sooke.bc.ca
Max Valianskiy maxcom@maxcom.ml.org Max Valianskiy maxcom@maxcom.ml.org
Nicolas Graner Nicolas.Graner@cri.u-psud.fr Nicolas Graner Nicolas.Graner@cri.u-psud.fr
Oskari Jääskeläinen f33003a@cc.hut.fi
Peter Gutmann pgut001@cs.auckland.ac.nz Peter Gutmann pgut001@cs.auckland.ac.nz
Ralph Gillen gillen@theochem.uni-duesseldorf.de Ralph Gillen gillen@theochem.uni-duesseldorf.de
Steffen Ullrich ccrlphr@xensei.com
Thomas Roessler roessler@guug.de Thomas Roessler roessler@guug.de
Tom Spindler dogcow@home.merit.edu Tom Spindler dogcow@home.merit.edu
Tom Zerucha tzeruch@ceddec.com Tom Zerucha tzeruch@ceddec.com

16
TODO
View File

@ -2,6 +2,16 @@
can also hold the localid and extend the localid to hold information can also hold the localid and extend the localid to hold information
of the subkey number because two subkeys may have the same keyid. 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) * invalid packets (Marco)
* add some sanity checks to read_keyblock, so that we are sure that * 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? * what about the CR,LF in cleartext singatures?
* add option --restore-ownertrust * add option --import-ownertrust
* always put key signatures before the first subkey.
* add a way to delete subkeys (in edit-keys?) * add a way to delete subkeys (in edit-keys?)
@ -33,8 +41,6 @@
* add checking of armor trailers * add checking of armor trailers
* remove all "Fixmes" * 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 * 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. a backup system of only the secret part of the secret key.

View File

@ -61,10 +61,10 @@ chdir () {
set -e set -e
pgmname=$(basename $0) pgmname=`basename $0`
#trap cleanup SIGHUP SIGINT SIGQUIT #trap cleanup SIGHUP SIGINT SIGQUIT
[ -z $srcdir ] && fatal "not called from make" [ -z "$srcdir" ] && fatal "not called from make"
cat <<EOF >./options cat <<EOF >./options
no-greeting no-greeting

View File

@ -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) 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. * random.c (read_pool): Simple alloc if secure_alloc is not set.

View File

@ -1,6 +1,6 @@
## Process this file with automake to produce Makefile.in ## 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 INCLUDES = -I$(top_srcdir)/include -I$(top_srcdir)/intl -I../intl
@ -42,9 +42,13 @@ libcipher_a_SOURCES = cipher.c \
smallprime.c smallprime.c
EXTRA_tiger_SOURCES = tiger.c EXTRA_tiger_SOURCES = tiger.c
EXTRA_twofish_SOURCES = twofish.c
tiger: tiger.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: install-exec-hook:
@list='$(pkglib_PROGRAMS)'; for p in $$list; do \ @list='$(pkglib_PROGRAMS)'; for p in $$list; do \

View File

@ -34,12 +34,13 @@
#include "dynload.h" #include "dynload.h"
#define STD_BLOCKSIZE 8 #define MAX_BLOCKSIZE 16
#define TABLE_SIZE 10 #define TABLE_SIZE 10
struct cipher_table_s { struct cipher_table_s {
const char *name; const char *name;
int algo; int algo;
size_t blocksize;
size_t keylen; size_t keylen;
size_t contextsize; /* allocate this amount of context */ size_t contextsize; /* allocate this amount of context */
void (*setkey)( void *c, byte *key, unsigned keylen ); 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 { struct cipher_handle_s {
int algo; int algo;
int mode; int mode;
byte iv[STD_BLOCKSIZE]; /* (this should be ulong aligned) */ size_t blocksize;
byte lastiv[STD_BLOCKSIZE]; byte iv[MAX_BLOCKSIZE]; /* (this should be ulong aligned) */
byte lastiv[MAX_BLOCKSIZE];
int unused; /* in IV */ int unused; /* in IV */
void (*setkey)( void *c, byte *key, unsigned keylen ); void (*setkey)( void *c, byte *key, unsigned keylen );
void (*encrypt)( void *c, byte *outbuf, byte *inbuf ); void (*encrypt)( void *c, byte *outbuf, byte *inbuf );
@ -80,44 +82,44 @@ setup_cipher_table()
{ {
int i; int i;
size_t blocksize;
i = 0; i = 0;
cipher_table[i].algo = CIPHER_ALGO_BLOWFISH; cipher_table[i].algo = CIPHER_ALGO_BLOWFISH;
cipher_table[i].name = blowfish_get_info( cipher_table[i].algo, cipher_table[i].name = blowfish_get_info( cipher_table[i].algo,
&cipher_table[i].keylen, &cipher_table[i].keylen,
&blocksize, &cipher_table[i].blocksize,
&cipher_table[i].contextsize, &cipher_table[i].contextsize,
&cipher_table[i].setkey, &cipher_table[i].setkey,
&cipher_table[i].encrypt, &cipher_table[i].encrypt,
&cipher_table[i].decrypt ); &cipher_table[i].decrypt );
if( !cipher_table[i].name || blocksize != STD_BLOCKSIZE ) if( !cipher_table[i].name )
BUG(); BUG();
i++; i++;
cipher_table[i].algo = CIPHER_ALGO_CAST5; cipher_table[i].algo = CIPHER_ALGO_CAST5;
cipher_table[i].name = cast5_get_info( cipher_table[i].algo, cipher_table[i].name = cast5_get_info( cipher_table[i].algo,
&cipher_table[i].keylen, &cipher_table[i].keylen,
&blocksize, &cipher_table[i].blocksize,
&cipher_table[i].contextsize, &cipher_table[i].contextsize,
&cipher_table[i].setkey, &cipher_table[i].setkey,
&cipher_table[i].encrypt, &cipher_table[i].encrypt,
&cipher_table[i].decrypt ); &cipher_table[i].decrypt );
if( !cipher_table[i].name || blocksize != STD_BLOCKSIZE ) if( !cipher_table[i].name )
BUG(); BUG();
i++; i++;
cipher_table[i].algo = CIPHER_ALGO_BLOWFISH160; cipher_table[i].algo = CIPHER_ALGO_BLOWFISH160;
cipher_table[i].name = blowfish_get_info( cipher_table[i].algo, cipher_table[i].name = blowfish_get_info( cipher_table[i].algo,
&cipher_table[i].keylen, &cipher_table[i].keylen,
&blocksize, &cipher_table[i].blocksize,
&cipher_table[i].contextsize, &cipher_table[i].contextsize,
&cipher_table[i].setkey, &cipher_table[i].setkey,
&cipher_table[i].encrypt, &cipher_table[i].encrypt,
&cipher_table[i].decrypt ); &cipher_table[i].decrypt );
if( !cipher_table[i].name || blocksize != STD_BLOCKSIZE ) if( !cipher_table[i].name )
BUG(); BUG();
i++; i++;
cipher_table[i].algo = CIPHER_ALGO_DUMMY; cipher_table[i].algo = CIPHER_ALGO_DUMMY;
cipher_table[i].name = "DUMMY"; cipher_table[i].name = "DUMMY";
cipher_table[i].blocksize = 8;
cipher_table[i].keylen = 128; cipher_table[i].keylen = 128;
cipher_table[i].contextsize = 0; cipher_table[i].contextsize = 0;
cipher_table[i].setkey = dummy_setkey; cipher_table[i].setkey = dummy_setkey;
@ -141,7 +143,6 @@ load_cipher_modules()
void *context = NULL; void *context = NULL;
struct cipher_table_s *ct; struct cipher_table_s *ct;
int ct_idx; int ct_idx;
size_t blocksize;
int i; int i;
const char *name; const char *name;
int any = 0; int any = 0;
@ -164,9 +165,9 @@ load_cipher_modules()
BUG(); /* table already full */ BUG(); /* table already full */
/* now load all extensions */ /* now load all extensions */
while( (name = enum_gnupgext_ciphers( &context, &ct->algo, 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)) ) { &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); log_info("skipping cipher %d: unsupported blocksize\n", ct->algo);
continue; continue;
} }
@ -271,6 +272,26 @@ cipher_get_keylen( int algo )
return 0; 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 * 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 ) + cipher_table[i].contextsize )
: m_alloc_clear( sizeof *hd + cipher_table[i].contextsize ); : m_alloc_clear( sizeof *hd + cipher_table[i].contextsize );
hd->algo = algo; hd->algo = algo;
hd->blocksize = cipher_table[i].blocksize;
hd->setkey = cipher_table[i].setkey; hd->setkey = cipher_table[i].setkey;
hd->encrypt = cipher_table[i].encrypt; hd->encrypt = cipher_table[i].encrypt;
hd->decrypt = cipher_table[i].decrypt; hd->decrypt = cipher_table[i].decrypt;
@ -336,9 +358,9 @@ void
cipher_setiv( CIPHER_HANDLE c, const byte *iv ) cipher_setiv( CIPHER_HANDLE c, const byte *iv )
{ {
if( iv ) if( iv )
memcpy( c->iv, iv, STD_BLOCKSIZE ); memcpy( c->iv, iv, c->blocksize );
else else
memset( c->iv, 0, STD_BLOCKSIZE ); memset( c->iv, 0, c->blocksize );
c->unused = 0; 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++ ) { for(n=0; n < nblocks; n++ ) {
(*c->encrypt)( &c->context, outbuf, inbuf ); (*c->encrypt)( &c->context, outbuf, inbuf );
inbuf += STD_BLOCKSIZE;; inbuf += c->blocksize;
outbuf += STD_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++ ) { for(n=0; n < nblocks; n++ ) {
(*c->decrypt)( &c->context, outbuf, inbuf ); (*c->decrypt)( &c->context, outbuf, inbuf );
inbuf += STD_BLOCKSIZE;; inbuf += c->blocksize;
outbuf += STD_BLOCKSIZE; outbuf += c->blocksize;
} }
} }
@ -373,11 +395,12 @@ static void
do_cfb_encrypt( CIPHER_HANDLE c, byte *outbuf, byte *inbuf, unsigned nbytes ) do_cfb_encrypt( CIPHER_HANDLE c, byte *outbuf, byte *inbuf, unsigned nbytes )
{ {
byte *ivp; byte *ivp;
size_t blocksize = c->blocksize;
if( nbytes <= c->unused ) { if( nbytes <= c->unused ) {
/* short enough to be encoded by the remaining XOR mask */ /* short enough to be encoded by the remaining XOR mask */
/* XOR the input with the IV and store input into IV */ /* 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++); *outbuf++ = (*ivp++ ^= *inbuf++);
return; return;
} }
@ -385,26 +408,26 @@ do_cfb_encrypt( CIPHER_HANDLE c, byte *outbuf, byte *inbuf, unsigned nbytes )
if( c->unused ) { if( c->unused ) {
/* XOR the input with the IV and store input into IV */ /* XOR the input with the IV and store input into IV */
nbytes -= c->unused; 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++); *outbuf++ = (*ivp++ ^= *inbuf++);
} }
/* now we can process complete blocks */ /* now we can process complete blocks */
while( nbytes >= STD_BLOCKSIZE ) { while( nbytes >= blocksize ) {
int i; int i;
/* encrypt the IV (and save the current one) */ /* 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->encrypt)( &c->context, c->iv, c->iv );
/* XOR the input with the IV and store input into 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++); *outbuf++ = (*ivp++ ^= *inbuf++);
nbytes -= STD_BLOCKSIZE; nbytes -= blocksize;
} }
if( nbytes ) { /* process the remaining bytes */ if( nbytes ) { /* process the remaining bytes */
/* encrypt the IV (and save the current one) */ /* 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->encrypt)( &c->context, c->iv, c->iv );
c->unused = STD_BLOCKSIZE; c->unused = blocksize;
/* and apply the xor */ /* and apply the xor */
c->unused -= nbytes; c->unused -= nbytes;
for(ivp=c->iv; nbytes; 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; byte *ivp;
ulong temp; ulong temp;
size_t blocksize = c->blocksize;
if( nbytes <= c->unused ) { if( nbytes <= c->unused ) {
/* short enough to be encoded by the remaining XOR mask */ /* short enough to be encoded by the remaining XOR mask */
/* XOR the input with the IV and store input into IV */ /* 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++; temp = *inbuf++;
*outbuf++ = *ivp ^ temp; *outbuf++ = *ivp ^ temp;
*ivp++ = temp; *ivp++ = temp;
@ -432,7 +456,7 @@ do_cfb_decrypt( CIPHER_HANDLE c, byte *outbuf, byte *inbuf, unsigned nbytes )
if( c->unused ) { if( c->unused ) {
/* XOR the input with the IV and store input into IV */ /* XOR the input with the IV and store input into IV */
nbytes -= c->unused; 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++; temp = *inbuf++;
*outbuf++ = *ivp ^ temp; *outbuf++ = *ivp ^ temp;
*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 */ /* now we can process complete blocks */
#ifdef BIG_ENDIAN_HOST while( nbytes >= blocksize ) {
/* This does only make sense for big endian hosts, due to ... ivp = temp*/ int i;
if( !((ulong)inbuf % SIZEOF_UNSIGNED_LONG) ) { /* encrypt the IV (and save the current one) */
while( nbytes >= STD_BLOCKSIZE ) { memcpy( c->lastiv, c->iv, blocksize );
/* encrypt the IV (and save the current one) */ (*c->encrypt)( &c->context, c->iv, c->iv );
memcpy( c->lastiv, c->iv, STD_BLOCKSIZE ); /* XOR the input with the IV and store input into IV */
(*c->encrypt)( &c->context, c->iv, c->iv ); for(ivp=c->iv,i=0; i < blocksize; i++ ) {
ivp = c->iv; temp = *inbuf++;
/* XOR the input with the IV and store input into IV */ *outbuf++ = *ivp ^ temp;
#if SIZEOF_UNSIGNED_LONG == STD_BLOCKSIZE *ivp++ = temp;
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;
} }
nbytes -= 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;
}
#ifdef BIG_ENDIAN_HOST
}
#endif
if( nbytes ) { /* process the remaining bytes */ if( nbytes ) { /* process the remaining bytes */
/* encrypt the IV (and save the current one) */ /* 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->encrypt)( &c->context, c->iv, c->iv );
c->unused = STD_BLOCKSIZE; c->unused = blocksize;
/* and apply the xor */ /* and apply the xor */
c->unused -= nbytes; c->unused -= nbytes;
for(ivp=c->iv; nbytes; nbytes-- ) { for(ivp=c->iv; nbytes; nbytes-- ) {
@ -576,8 +554,8 @@ void
cipher_sync( CIPHER_HANDLE c ) cipher_sync( CIPHER_HANDLE c )
{ {
if( c->mode == CIPHER_MODE_PHILS_CFB && c->unused ) { if( c->mode == CIPHER_MODE_PHILS_CFB && c->unused ) {
memmove(c->iv + c->unused, c->iv, STD_BLOCKSIZE - c->unused ); memmove(c->iv + c->unused, c->iv, c->blocksize - c->unused );
memcpy(c->iv, c->lastiv + STD_BLOCKSIZE - c->unused, c->unused); memcpy(c->iv, c->lastiv + c->blocksize - c->unused, c->unused);
c->unused = 0; c->unused = 0;
} }
} }

View File

@ -939,7 +939,6 @@ gnupgext_enum_func( int what, int *sequence, int *class, int *vers )
void *ret; void *ret;
int i = *sequence; int i = *sequence;
/*log_info("gnupgext_enum_func in rsa+idea called what=%d i=%d: ", what, i);*/
do { do {
if( i >= DIM(func_table) || i < 0 ) { if( i >= DIM(func_table) || i < 0 ) {
/*fprintf(stderr, "failed\n");*/ /*fprintf(stderr, "failed\n");*/

View File

@ -56,23 +56,18 @@ Record type 1:
-------------- --------------
Version information for this TrustDB. This is always the first Version information for this TrustDB. This is always the first
record of the DB and the only one with type 1. record of the DB and the only one with type 1.
1 byte value 2 1 byte value 1
3 bytes 'gpg' magic value 3 bytes 'gpg' magic value
1 byte Version of the TrustDB 1 byte Version of the TrustDB
3 byte reserved 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 trustdb creation
1 u32 timestamp of last modification 1 u32 timestamp of last modification
1 u32 timestamp of last validation 1 u32 timestamp of last validation
(Used to keep track of the time, when this TrustDB was checked (Used to keep track of the time, when this TrustDB was checked
against the pubring) against the pubring)
1 u32 reserved 1 u32 record number of keyhashtable
1 byte marginals needed 12 bytes reserved
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
Record type 2: (directory record) Record type 2: (directory record)
@ -183,9 +178,9 @@ Record type 9: (cache record)
Record Type 10 (hash table) 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 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 used directly as hash values. (They can be considered as strong
random numbers.) random numbers.)
What we use is a dynamic multilevel architecture, which combines 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 This record is a hashtable of 256 entries; a special property
is that all these records are stored consecutively to make one is that all these records are stored consecutively to make one
big table. The hash value is simple the 1st, 2nd, ... byte of 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 value 10
1 byte reserved 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 n = (reclen-2)/4 which yields 9 for the current record length
of 40 bytes. of 40 bytes.
@ -206,18 +201,15 @@ Record Type 10 (hash table)
m = (256+n-1) / n m = (256+n-1) / n
which is 29 for a record length of 40. which is 29 for a record length of 40.
To look up a key we use its lsb to get the recnum from this To look up a key we use the first byte of the fingerprint to get
hashtable and look up the addressed record: the recnum from this hashtable and look up the addressed record:
- If this record is another hashtable, we use 2nd lsb - If this record is another hashtable, we use 2nd byte
to index this hast table and so on. to index this hast table and so on.
- if this record is a hashlist, we walk thru the - if this record is a hashlist, we walk all entries
reclist records until we found one whose hash field until we found one a matching one.
matches the MSB of our keyid, and lookup this record - if this record is a key record, we compare the
- if this record is a dir record, we compare the fingerprint and to decide whether it is the requested key;
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.
Record type 11 (hash list) Record type 11 (hash list)
-------------- --------------
@ -226,11 +218,10 @@ Record type 11 (hash list)
1 byte value 11 1 byte value 11
1 byte reserved 1 byte reserved
1 u32 next next hash list record 1 u32 next next hash list record
n times n = (reclen-6)/5 n times n = (reclen-5)/5
1 byte hash
1 u32 recnum 1 u32 recnum
For the current record length of 40, n is 6 For the current record length of 40, n is 7

View File

@ -5,6 +5,7 @@ gpg - GNU Privacy Guard
=head1 SYNOPSIS =head1 SYNOPSIS
B<gpg> [--homedir name] [--options file] [options] command [args] B<gpg> [--homedir name] [--options file] [options] command [args]
B<gpgm> [--homedir name] [--options file] [options] command [args] B<gpgm> [--homedir name] [--options file] [options] command [args]
=head1 DESCRIPTION =head1 DESCRIPTION
@ -98,23 +99,46 @@ B<--gen-key>
Generate a new key pair. This command can only be Generate a new key pair. This command can only be
used interactive. 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> B<--delete-key>
Remove key from the public keyring Remove key from the public keyring
@ -122,12 +146,6 @@ B<--delete-key>
B<--delete-secret-key> B<--delete-secret-key>
Remove key from the secret and public keyring 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> B<--gen-revoke>
Generate a revocation certificate. Generate a revocation certificate.
@ -142,10 +160,15 @@ B<--export> [I<names>]
B<--import> B<--import>
import/merge keys import/merge keys
B<--list-ownertrust> B<--export-ownertrust>
List the assigned ownertrust values in ascii format for List the assigned ownertrust values in ascii format for
backup purposes [B<gpgm> only]. 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 =head1 OPTIONS
Long options can be put in an options file (default F<~/.gnupg/options>); Long options can be put in an options file (default F<~/.gnupg/options>);

View File

@ -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)) Tue Jul 21 14:37:09 1998 Werner Koch (wk@(none))
* import.c (import_one): Now creates a trustdb record. * import.c (import_one): Now creates a trustdb record.

View File

@ -48,7 +48,6 @@ common_source = \
status.c \ status.c \
status.h \ status.h \
sign.c \ sign.c \
keyedit.c \
plaintext.c \ plaintext.c \
encr-data.c \ encr-data.c \
encode.c \ encode.c \
@ -61,6 +60,7 @@ gpg_SOURCES = g10.c \
$(common_source) \ $(common_source) \
verify.c \ verify.c \
decrypt.c \ decrypt.c \
keyedit.c \
keygen.c keygen.c

View File

@ -57,3 +57,9 @@ compress-sigs
# Normally, compressing of signatures does not make sense; so this # Normally, compressing of signatures does not make sense; so this
# is disabled for detached signatures unless this option is used. # 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.

View File

@ -51,6 +51,7 @@ static int calc_header_length( u32 len );
static int write_16(IOBUF inp, u16 a); static int write_16(IOBUF inp, u16 a);
static int write_32(IOBUF inp, u32 a); static int write_32(IOBUF inp, u32 a);
static int write_header( IOBUF out, int ctb, u32 len ); 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_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_new_header( IOBUF out, int ctb, u32 len, int hdrlen );
static int write_version( IOBUF out, int ctb ); 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++ ) for(i=0; i < n; i++ )
mpi_write(a, sig->data[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 ) ) if( iobuf_write_temp( out, a ) )
rc = G10ERR_WRITE_FILE; rc = G10ERR_WRITE_FILE;
@ -747,6 +751,18 @@ write_header( IOBUF out, int ctb, u32 len )
return write_header2( out, ctb, len, 0, 1 ); 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. * 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. * we need this, so that we can hash packets without reading them again.

View File

@ -42,7 +42,8 @@ write_header( cipher_filter_context_t *cfx, IOBUF a )
{ {
PACKET pkt; PACKET pkt;
PKT_encrypted ed; PKT_encrypted ed;
byte temp[10]; byte temp[18];
unsigned blocksize;
memset( &ed, 0, sizeof ed ); memset( &ed, 0, sizeof ed );
ed.len = cfx->datalen; ed.len = cfx->datalen;
@ -52,15 +53,18 @@ write_header( cipher_filter_context_t *cfx, IOBUF a )
pkt.pkt.encrypted = &ed; pkt.pkt.encrypted = &ed;
if( build_packet( a, &pkt )) if( build_packet( a, &pkt ))
log_bug("build_packet(ENCR_DATA) failed\n"); log_bug("build_packet(ENCR_DATA) failed\n");
randomize_buffer( temp, 8, 1 ); blocksize = cipher_get_blocksize( cfx->dek->algo );
temp[8] = temp[6]; if( blocksize < 8 || blocksize > 16 )
temp[9] = temp[7]; 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 ); 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_setkey( cfx->cipher_hd, cfx->dek->key, cfx->dek->keylen );
cipher_setiv( cfx->cipher_hd, NULL ); 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 ); cipher_sync( cfx->cipher_hd );
iobuf_write(a, temp, 10); iobuf_write(a, temp, blocksize+2);
cfx->header=1; cfx->header=1;
} }

View File

@ -49,7 +49,8 @@ decrypt_data( PKT_encrypted *ed, DEK *dek )
decode_filter_ctx_t dfx; decode_filter_ctx_t dfx;
byte *p; byte *p;
int rc, c, i; int rc, c, i;
byte temp[16]; byte temp[32];
unsigned blocksize;
if( opt.verbose ) { if( opt.verbose ) {
const char *s = cipher_algo_to_string( dek->algo ); 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)) ) if( (rc=check_cipher_algo(dek->algo)) )
return rc; 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 */ log_bug("Nanu\n"); /* oops: found a bug */
dfx.cipher_hd = cipher_open( dek->algo, CIPHER_MODE_AUTO_CFB, 1 ); 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 ) { if( ed->len ) {
iobuf_set_limit( ed->buf, 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); temp[i] = iobuf_get(ed->buf);
} }
else { else {
for(i=0; i < 10; i++ ) for(i=0; i < (blocksize+2); i++ )
if( (c=iobuf_get(ed->buf)) == -1 ) if( (c=iobuf_get(ed->buf)) == -1 )
break; break;
else else
temp[i] = c; 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 ); cipher_sync( dfx.cipher_hd );
p = temp; 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); cipher_close(dfx.cipher_hd);
return G10ERR_BAD_KEY; return G10ERR_BAD_KEY;
} }

View File

@ -55,7 +55,7 @@ void
free_seckey_enc( PKT_signature *sig ) free_seckey_enc( PKT_signature *sig )
{ {
int n, i; int n, i;
n = pubkey_get_nenc( sig->pubkey_algo ); n = pubkey_get_nsig( sig->pubkey_algo );
if( !n ) { if( !n ) {
m_free(sig->data[0]); m_free(sig->data[0]);
sig->data[0] = NULL; sig->data[0] = NULL;
@ -107,6 +107,20 @@ cp_fake_data( MPI a )
return d; 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 * PKT_public_key *
copy_public_key( PKT_public_key *d, PKT_public_key *s ) 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; 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 void
release_secret_key_parts( PKT_secret_key *sk ) release_secret_key_parts( PKT_secret_key *sk )
{ {

View File

@ -68,11 +68,8 @@ static ARGPARSE_OPTS opts[] = {
{ 558, "list-secret-keys", 256, N_("list secret keys")}, { 558, "list-secret-keys", 256, N_("list secret keys")},
#ifdef IS_G10 #ifdef IS_G10
{ 503, "gen-key", 256, N_("generate a new key pair")}, { 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")}, { 505, "delete-key",256, N_("remove key from the public keyring")},
{ 524, "edit-key" ,256, N_("edit a key signature")}, { 524, "edit-key" ,256, N_("sign or edit a key")},
{ 525, "change-passphrase", 256, N_("change the passphrase of your secret keyring")},
{ 542, "gen-revoke",256, N_("generate a revocation certificate")}, { 542, "gen-revoke",256, N_("generate a revocation certificate")},
#endif #endif
{ 537, "export" , 256, N_("export keys") }, { 537, "export" , 256, N_("export keys") },
@ -81,7 +78,8 @@ static ARGPARSE_OPTS opts[] = {
{ 530, "import", 256 , N_("import/merge keys")}, { 530, "import", 256 , N_("import/merge keys")},
{ 521, "list-packets",256,N_("list only the sequence of packets")}, { 521, "list-packets",256,N_("list only the sequence of packets")},
#ifdef IS_G10MAINT #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")}, { 567, "check-trustdb",0 , N_("|[NAMES]|check the trust database")},
{ 546, "dearmor", 256, N_("De-Armor a file or stdin") }, { 546, "dearmor", 256, N_("De-Armor a file or stdin") },
{ 547, "enarmor", 256, N_("En-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, "@" }, { 504, "delete-secret-key",0, "@" },
{ 524, "edit-sig" ,0, "@"}, /* alias for edit-key */ { 524, "edit-sig" ,0, "@"}, /* alias for edit-key */
{ 523, "passphrase-fd",1, "@" }, { 523, "passphrase-fd",1, "@" },
{ 506, "sign-key" ,256, "@" }, /* alias for edit-key */
#endif #endif
{ 532, "quick-random", 0, "@"}, { 532, "quick-random", 0, "@"},
{ 526, "no-verbose", 0, "@"}, { 526, "no-verbose", 0, "@"},
@ -173,18 +172,18 @@ static ARGPARSE_OPTS opts[] = {
{ 566, "compress-sigs",0, "@"}, { 566, "compress-sigs",0, "@"},
{ 559, "always-trust", 0, "@"}, { 559, "always-trust", 0, "@"},
{ 562, "emulate-checksum-bug", 0, "@"}, { 562, "emulate-checksum-bug", 0, "@"},
/*554 is unused */
{0} }; {0} };
enum cmd_values { aNull = 0, enum cmd_values { aNull = 0,
aSym, aStore, aEncr, aKeygen, aSign, aSignEncr, aSym, aStore, aEncr, aKeygen, aSign, aSignEncr,
aSignKey, aClearsign, aListPackets, aEditKey, aDeleteKey, aDeleteSecretKey, aSignKey, aClearsign, aListPackets, aEditKey, aDeleteKey, aDeleteSecretKey,
aKMode, aKModeC, aChangePass, aImport, aVerify, aDecrypt, aListKeys, aKMode, aKModeC, aImport, aVerify, aDecrypt, aListKeys,
aListSigs, aKeyadd, aListSecretKeys, aListSigs, aListSecretKeys, aExport, aExportSecret,
aExport, aExportSecret,
aCheckKeys, aGenRevoke, aPrimegen, aPrintMD, aPrintMDs, aCheckKeys, aGenRevoke, aPrimegen, aPrintMD, aPrintMDs,
aCheckTrustDB, aListTrustDB, aListTrustPath, aListOwnerTrust, aCheckTrustDB, aListTrustDB, aListTrustPath,
aExportOwnerTrust, aImportOwnerTrust,
aDeArmor, aEnArmor, aGenRandom, aDeArmor, aEnArmor, aGenRandom,
aTest }; aTest };
@ -521,7 +520,6 @@ main( int argc, char **argv )
case 507: set_cmd( &cmd, aStore); break; case 507: set_cmd( &cmd, aStore); break;
case 523: set_passphrase_fd( pargs.r.ret_int ); break; case 523: set_passphrase_fd( pargs.r.ret_int ); break;
case 524: set_cmd( &cmd, aEditKey); 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 527: def_cipher_string = m_strdup(pargs.r.ret_str); break;
case 529: def_digest_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; case 539: set_cmd( &cmd, aClearsign); break;
@ -548,7 +546,8 @@ main( int argc, char **argv )
case 546: set_cmd( &cmd, aDeArmor); break; case 546: set_cmd( &cmd, aDeArmor); break;
case 547: set_cmd( &cmd, aEnArmor); break; case 547: set_cmd( &cmd, aEnArmor); break;
case 555: set_cmd( &cmd, aPrintMD); 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 */ #endif /* IS_G10MAINT */
case 'o': opt.outfile = pargs.r.ret_str; break; 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 510: opt.debug |= pargs.r.ret_ulong; break;
case 511: opt.debug = ~0; break; case 511: opt.debug = ~0; break;
case 512: set_status_fd( pargs.r.ret_int ); 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 517: append_to_strlist( &sec_nrings, pargs.r.ret_str); break;
case 518: case 518:
/* config files may not be nested (silently ignore them) */ /* 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 551: set_cmd( &cmd, aListKeys); break;
case 552: set_cmd( &cmd, aListSigs); break; case 552: set_cmd( &cmd, aListSigs); break;
case 553: opt.skip_verify=1; 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 556: opt.def_compress_algo = pargs.r.ret_int; break;
case 557: opt.compress_keys = 1; break; case 557: opt.compress_keys = 1; break;
case 558: set_cmd( &cmd, aListSecretKeys); break; case 558: set_cmd( &cmd, aListSecretKeys); break;
case 559: opt.always_trust = 1; break; case 559: opt.always_trust = 1; break;
case 560: register_cipher_extension(pargs.r.ret_str); break; case 560: register_cipher_extension(pargs.r.ret_str); break;
case 561: opt.rfc1991 = 1; break; case 561: opt.rfc1991 = 1; opt.no_comment = 1; break;
case 562: opt.emulate_bugs |= 1; break; case 562: opt.emulate_bugs |= EMUBUG_GPGCHKSUM; break;
case 563: set_cmd( &cmd, aExportSecret); break; case 563: set_cmd( &cmd, aExportSecret); break;
case 565: opt.do_not_export_rsa = 1; break; case 565: opt.do_not_export_rsa = 1; break;
case 566: opt.compress_sigs = 1; break; case 566: opt.compress_sigs = 1; break;
case 554:
default : errors++; pargs.err = configfp? 1:2; break; 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 */ if( opt.with_colons ) /* need this to list the trust */
rc = init_trustdb(1, trustdb_name ); rc = init_trustdb(1, trustdb_name );
break; 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; case aListTrustDB: rc = init_trustdb( argc? 1:0, trustdb_name ); break;
default: rc = init_trustdb(1, 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 */ 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 */ case aEditKey: /* Edit a key signature */
if( argc != 1 ) if( argc != 1 )
wrong_args(_("--edit-key username")); wrong_args(_("--edit-key username"));
/* note: fname is the user id! */ keyedit_menu(fname, locusr );
if( (rc = edit_keysigs(fname)) )
log_error("%s: edit signature failed: %s\n", print_fname_stdin(fname), g10_errstr(rc) );
break; break;
case aDeleteSecretKey: 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) ); log_error("%s: delete key failed: %s\n", print_fname_stdin(fname), g10_errstr(rc) );
break; 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 */ #endif /* IS_G10 */
case aCheckKeys: case aCheckKeys:
@ -880,11 +862,6 @@ main( int argc, char **argv )
wrong_args("--gen-key"); wrong_args("--gen-key");
generate_keypair(); generate_keypair();
break; break;
case aKeyadd: /* add a subkey (interactive) */
if( argc != 1 )
wrong_args("--add-key userid");
generate_subkeypair(*argv);
break;
#endif #endif
case aImport: case aImport:
@ -1049,10 +1026,16 @@ main( int argc, char **argv )
list_trust_path( atoi(*argv), argv[1] ); list_trust_path( atoi(*argv), argv[1] );
break; break;
case aListOwnerTrust: case aExportOwnerTrust:
if( argc ) if( argc )
wrong_args("--list-ownertrust"); wrong_args("--export-ownertrust");
list_ownertrust(); export_ownertrust();
break;
case aImportOwnerTrust:
if( argc > 1 )
wrong_args("--import-ownertrust [file]");
import_ownertrust( argc? *argv:NULL );
break; break;
#endif /* IS_G10MAINT */ #endif /* IS_G10MAINT */

View File

@ -851,7 +851,7 @@ merge_sigs( KBNODE dst, KBNODE src, int *n_sigs,
* We add a clone to the original keyblock, because this * We add a clone to the original keyblock, because this
* one is released first */ * one is released first */
n2 = clone_kbnode(n); n2 = clone_kbnode(n);
insert_kbnode( dst, n2, PKT_USER_ID ); insert_kbnode( dst, n2, PKT_SIGNATURE );
n2->flag |= 1; n2->flag |= 1;
n->flag |= 1; n->flag |= 1;
++*n_sigs; ++*n_sigs;

View File

@ -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) * (only if PKTTYPE != 0)
*/ */
void void
@ -108,7 +109,7 @@ insert_kbnode( KBNODE root, KBNODE node, int pkttype )
KBNODE n1; KBNODE n1;
for(n1=root; n1->next; n1 = n1->next) for(n1=root; n1->next; n1 = n1->next)
if( pkttype == n1->next->pkt->pkttype ) { if( pkttype != n1->next->pkt->pkttype ) {
node->next = n1->next; node->next = n1->next;
n1->next = node; n1->next = node;
return; return;

View File

@ -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_pk( PKT_public_key *pk );
const char *datestr_from_sk( PKT_secret_key *sk ); const char *datestr_from_sk( PKT_secret_key *sk );
const char *datestr_from_sig( PKT_signature *sig ); 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_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 ); 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 ); KBNODE walk_kbnode( KBNODE root, KBNODE *context, int all );
void clear_kbnode_flags( KBNODE n ); void clear_kbnode_flags( KBNODE n );
int commit_kbnode( KBNODE *root ); int commit_kbnode( KBNODE *root );
void dump_kbnode( KBNODE node );
/*-- ringedit.c --*/ /*-- ringedit.c --*/
int add_keyblock_resource( const char *filename, int force, int secret ); int add_keyblock_resource( const char *filename, int force, int secret );

File diff suppressed because it is too large Load Diff

View File

@ -74,8 +74,8 @@ add_key_expire( PKT_signature *sig, void *opaque )
* Add preference to the self signature packet. * Add preference to the self signature packet.
* This is only called for packets with version > 3. * This is only called for packets with version > 3.
*/ */
static int int
add_prefs( PKT_signature *sig, void *opaque ) keygen_add_std_prefs( PKT_signature *sig, void *opaque )
{ {
byte buf[8]; byte buf[8];
@ -134,7 +134,7 @@ write_selfsig( KBNODE root, KBNODE pub_root, PKT_secret_key *sk )
/* and make the signature */ /* and make the signature */
rc = make_keysig_packet( &sig, pk, uid, NULL, sk, 0x13, 0, rc = make_keysig_packet( &sig, pk, uid, NULL, sk, 0x13, 0,
add_prefs, sk ); keygen_add_std_prefs, sk );
if( rc ) { if( rc ) {
log_error("make_keysig_packet failed: %s\n", g10_errstr(rc) ); log_error("make_keysig_packet failed: %s\n", g10_errstr(rc) );
return rc; return rc;
@ -444,25 +444,18 @@ ask_keysize( int algo )
else if( nbits > 2048 ) { else if( nbits > 2048 ) {
tty_printf(_("Keysizes larger than 2048 are not suggested because " tty_printf(_("Keysizes larger than 2048 are not suggested because "
"computations take REALLY long!\n")); "computations take REALLY long!\n"));
answer = tty_get(_("Are you sure that you want this keysize? ")); if( tty_get_answer_is_yes(_(
tty_kill_prompt(); "Are you sure that you want this keysize? ")) ) {
if( answer_is_yes(answer) ) {
m_free(answer);
tty_printf(_("Okay, but keep in mind that your monitor " tty_printf(_("Okay, but keep in mind that your monitor "
"and keyboard radiation is also very vulnerable " "and keyboard radiation is also very vulnerable "
"to attacks!\n")); "to attacks!\n"));
break; break;
} }
m_free(answer);
} }
else if( nbits > 1536 ) { else if( nbits > 1536 ) {
answer = tty_get(_("Do you really need such a large keysize? ")); if( tty_get_answer_is_yes(_(
tty_kill_prompt(); "Do you really need such a large keysize? ")) )
if( answer_is_yes(answer) ) {
m_free(answer);
break; break;
}
m_free(answer);
} }
else else
break; break;
@ -524,10 +517,7 @@ ask_valid_days()
add_days_to_timestamp( make_timestamp(), valid_days ))); add_days_to_timestamp( make_timestamp(), valid_days )));
} }
m_free(answer); if( tty_get_answer_is_yes(_("Is this correct (y/n)? ")) )
answer = tty_get(_("Is this correct (y/n)? "));
tty_kill_prompt();
if( answer_is_yes(answer) )
break; break;
} }
m_free(answer); m_free(answer);
@ -549,12 +539,13 @@ has_invalid_email_chars( const char *s )
static char * static char *
ask_user_id() ask_user_id( int mode )
{ {
char *answer; char *answer;
char *aname, *acomment, *amail, *uid; 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" "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" "from Real Name, Comment and Email Address in this form:\n"
" \"Heinrich Heine (Der Dichter) <heinrichh@duesseldorf.de>\"\n\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); tty_printf(_("You selected this USER-ID:\n \"%s\"\n\n"), uid);
/* fixme: add a warning if this user-id already exists */ /* fixme: add a warning if this user-id already exists */
for(;;) { 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(); tty_kill_prompt();
if( strlen(answer) > 1 ) if( strlen(answer) > 1 )
; ;
else if( *answer == 'N' || *answer == 'n' ) { else if( *answer == ansstr[0] || *answer == ansstr[1] ) {
m_free(aname); aname = NULL; m_free(aname); aname = NULL;
break; break;
} }
else if( *answer == 'C' || *answer == 'c' ) { else if( *answer == ansstr[2] || *answer == ansstr[3] ) {
m_free(acomment); acomment = NULL; m_free(acomment); acomment = NULL;
break; break;
} }
else if( *answer == 'E' || *answer == 'e' ) { else if( *answer == ansstr[4] || *answer == ansstr[5] ) {
m_free(amail); amail = NULL; m_free(amail); amail = NULL;
break; break;
} }
else if( *answer == 'O' || *answer == 'o' ) { else if( *answer == ansstr[6] || *answer == ansstr[7] ) {
m_free(aname); aname = NULL; m_free(aname); aname = NULL;
m_free(acomment); acomment = NULL; m_free(acomment); acomment = NULL;
m_free(amail); amail = NULL; m_free(amail); amail = NULL;
break; 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);
} }
m_free(answer); m_free(answer);
@ -685,7 +685,7 @@ ask_passphrase( STRING2KEY **ret_s2k )
tty_printf(_( tty_printf(_(
"You don't want a passphrase - this is probably a *bad* idea!\n" "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" "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; break;
} }
else else
@ -728,6 +728,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 * Generate a keypair
*/ */
@ -762,7 +783,11 @@ generate_keypair()
} }
nbits = ask_keysize( algo ); nbits = ask_keysize( algo );
ndays = ask_valid_days(); 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 ); dek = ask_passphrase( &s2k );
@ -879,88 +904,29 @@ generate_keypair()
/**************** /****************
* add a new subkey to an existing key. * add a new subkey to an existing key.
* Returns true if a new key has been generated and put into the keyblocks.
*/ */
void int
generate_subkeypair( const char *username ) generate_subkeypair( KBNODE pub_keyblock, KBNODE sec_keyblock )
{ {
int rc=0; int okay=0, rc=0;
KBPOS pub_kbpos, sec_kbpos;
KBNODE pub_keyblock = NULL;
KBNODE sec_keyblock = NULL;
KBNODE node; KBNODE node;
PKT_secret_key *sk = NULL; /* this is the primary sk */ PKT_secret_key *sk = NULL; /* this is the primary sk */
u32 keyid[2];
int v4, algo, ndays; int v4, algo, ndays;
unsigned nbits; unsigned nbits;
char *passphrase = NULL; char *passphrase = NULL;
DEK *dek = NULL; DEK *dek = NULL;
STRING2KEY *s2k = NULL; STRING2KEY *s2k = NULL;
if( opt.batch || opt.answer_yes || opt.answer_no ) { /* break out the primary secret key */
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 */
node = find_kbnode( sec_keyblock, PKT_SECRET_KEY ); node = find_kbnode( sec_keyblock, PKT_SECRET_KEY );
if( !node ) { if( !node ) {
log_error("Oops; secret key not found anymore!\n"); log_error("Oops; secret key not found anymore!\n");
rc = G10ERR_GENERAL;
goto leave; goto leave;
} }
/* make a copy of the sk to keep the protected one in the keyblock */ /* make a copy of the sk to keep the protected one in the keyblock */
sk = copy_secret_key( NULL, node->pkt->pkt.secret_key ); 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 */ /* unprotect to get the passphrase */
switch( is_secret_key_protected( sk ) ) { switch( is_secret_key_protected( sk ) ) {
case -1: case -1:
@ -984,6 +950,8 @@ generate_subkeypair( const char *username )
assert(algo); assert(algo);
nbits = ask_keysize( algo ); nbits = ask_keysize( algo );
ndays = ask_valid_days(); ndays = ask_valid_days();
if( !tty_get_answer_is_yes( _("Really create? ") ) )
goto leave;
if( passphrase ) { if( passphrase ) {
s2k = m_alloc_secure( sizeof *s2k ); s2k = m_alloc_secure( sizeof *s2k );
@ -999,31 +967,18 @@ generate_subkeypair( const char *username )
rc = write_keybinding(pub_keyblock, pub_keyblock, sk); rc = write_keybinding(pub_keyblock, pub_keyblock, sk);
if( !rc ) if( !rc )
rc = write_keybinding(sec_keyblock, pub_keyblock, sk); 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 ) if( !rc )
tty_printf(_("public and secret subkey created.\n") ); okay = 1;
leave: leave:
if( rc ) 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( passphrase );
m_free( dek ); m_free( dek );
m_free( s2k ); m_free( s2k );
if( sk ) /* release the copy of the (now unprotected) secret key */ if( sk ) /* release the copy of the (now unprotected) secret key */
free_secret_key(sk); free_secret_key(sk);
release_kbnode( sec_keyblock );
release_kbnode( pub_keyblock );
set_next_passphrase( NULL ); set_next_passphrase( NULL );
return okay;
} }

View File

@ -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 * 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 * The length of the array is returned in ret_len. Caller must free

View File

@ -202,6 +202,8 @@ list_one( const char *name, int secret )
any = 1; any = 1;
} }
keyid_from_pk( pk2, keyid2 ); keyid_from_pk( pk2, keyid2 );
if( opt.with_colons ) { if( opt.with_colons ) {
printf("sub:%c:%u:%d:%08lX%08lX:%s:%u:", 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 ), pubkey_letter( pk2->pubkey_algo ),
(ulong)keyid2[1], (ulong)keyid2[1],
datestr_from_pk( pk2 ) ); datestr_from_pk( pk2 ) );
if( opt.fingerprint > 1 )
fingerprint( pk2, NULL );
} }
else if( node->pkt->pkttype == PKT_SECRET_SUBKEY ) { else if( node->pkt->pkttype == PKT_SECRET_SUBKEY ) {
u32 keyid2[2]; u32 keyid2[2];
@ -251,6 +255,9 @@ list_one( const char *name, int secret )
pubkey_letter( sk2->pubkey_algo ), pubkey_letter( sk2->pubkey_algo ),
(ulong)keyid2[1], (ulong)keyid2[1],
datestr_from_sk( sk2 ) ); datestr_from_sk( sk2 ) );
if( opt.fingerprint > 1 )
fingerprint( NULL, sk2 );
} }
else if( opt.list_sigs && node->pkt->pkttype == PKT_SIGNATURE ) { else if( opt.list_sigs && node->pkt->pkttype == PKT_SIGNATURE ) {
PKT_signature *sig = node->pkt->pkt.signature; PKT_signature *sig = node->pkt->pkt.signature;

View File

@ -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 ); int check_key_signature( KBNODE root, KBNODE node, int *is_selfsig );
/*-- keyedit.c --*/ /*-- 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 delete_key( const char *username, int secure );
int change_passphrase( const char *username ); void keyedit_menu( const char *username, STRLIST locusr );
/*-- keygen.c --*/ /*-- keygen.c --*/
void generate_keypair(void); 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 --*/ /*-- openfile.c --*/
int overwrite_filep( const char *fname ); int overwrite_filep( const char *fname );

View File

@ -520,6 +520,8 @@ list_node( CTX c, KBNODE node )
} }
if( !any ) if( !any )
putchar('\n'); putchar('\n');
if( !mainkey && opt.fingerprint > 1 )
print_fingerprint( pk, NULL );
} }
else if( (mainkey = (node->pkt->pkttype == PKT_SECRET_KEY) ) else if( (mainkey = (node->pkt->pkttype == PKT_SECRET_KEY) )
|| node->pkt->pkttype == PKT_SECRET_SUBKEY ) { || node->pkt->pkttype == PKT_SECRET_SUBKEY ) {
@ -583,6 +585,8 @@ list_node( CTX c, KBNODE node )
} }
if( !any ) if( !any )
putchar('\n'); putchar('\n');
if( !mainkey && opt.fingerprint > 1 )
print_fingerprint( NULL, sk );
} }
else if( node->pkt->pkttype == PKT_SIGNATURE ) { else if( node->pkt->pkttype == PKT_SIGNATURE ) {
PKT_signature *sig = node->pkt->pkt.signature; PKT_signature *sig = node->pkt->pkt.signature;

View File

@ -98,7 +98,7 @@ checksum_u16( unsigned n )
u16 a; u16 a;
a = (n >> 8) & 0xff; a = (n >> 8) & 0xff;
if( opt.emulate_bugs & 1 ) { if( opt.emulate_bugs & EMUBUG_GPGCHKSUM ) {
a |= n & 0xff; a |= n & 0xff;
log_debug("csum_u16 emulated for n=%u\n", n); 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. * this stored value if it is still available.
*/ */
if( opt.emulate_bugs & 1 ) if( opt.emulate_bugs & EMUBUG_GPGCHKSUM )
nbits = 0; nbits = 0;
else else
nbits = mpi_get_nbit_info(a); nbits = mpi_get_nbit_info(a);

View File

@ -50,10 +50,12 @@ struct {
int compress_sigs; int compress_sigs;
int always_trust; int always_trust;
int rfc1991; int rfc1991;
unsigned emulate_bugs; /* bug emulation flags */ unsigned emulate_bugs; /* bug emulation flags EMUBUG_xxxx */
} opt; } opt;
#define EMUBUG_GPGCHKSUM 1
#define DBG_PACKET_VALUE 1 /* debug packet reading/writing */ #define DBG_PACKET_VALUE 1 /* debug packet reading/writing */
#define DBG_MPI_VALUE 2 /* debug mpi details */ #define DBG_MPI_VALUE 2 /* debug mpi details */
#define DBG_CIPHER_VALUE 4 /* debug cipher handling */ #define DBG_CIPHER_VALUE 4 /* debug cipher handling */

View File

@ -258,7 +258,9 @@ void free_comment( PKT_comment *rem );
void free_packet( PACKET *pkt ); void free_packet( PACKET *pkt );
PKT_public_key *copy_public_key( PKT_public_key *d, PKT_public_key *s ); 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 ); 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_public_secret_key( PKT_public_key *pk, PKT_secret_key *sk );
int cmp_user_ids( PKT_user_id *a, PKT_user_id *b ); 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 *), int (*mksubpkt)(PKT_signature *, void *),
void *opaque ); void *opaque );
/*-- keygen.c --*/
PKT_user_id *generate_user_id(void);
#endif /*G10_PACKET_H*/ #endif /*G10_PACKET_H*/

View File

@ -349,7 +349,7 @@ parse( IOBUF inp, PACKET *pkt, int reqtype, ulong *retpos,
} }
leave: leave:
if( rc == -1 && iobuf_error(inp) ) if( !rc && iobuf_error(inp) )
rc = G10ERR_INV_KEYRING; rc = G10ERR_INV_KEYRING;
return rc; return rc;
} }
@ -434,7 +434,8 @@ skip_rest( IOBUF inp, unsigned long pktlen )
} }
else { else {
for( ; pktlen; pktlen-- ) 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; rc = G10ERR_INVALID_PACKET;
goto leave; goto leave;
} }
/* fixme: Add support for other blocksizes */
for(i=0; i < 8 && pktlen; i++, pktlen-- ) for(i=0; i < 8 && pktlen; i++, pktlen-- )
temp[i] = iobuf_get_noeof(inp); temp[i] = iobuf_get_noeof(inp);
if( list_mode ) { if( list_mode ) {

View File

@ -53,6 +53,8 @@ do_check( PKT_secret_key *sk )
BUG(); BUG();
if( check_cipher_algo( sk->protect.algo ) ) if( check_cipher_algo( sk->protect.algo ) )
return G10ERR_CIPHER_ALGO; /* unsupported protection algorithm */ 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 ); keyid_from_sk( sk, keyid );
dek = passphrase_to_dek( keyid, sk->protect.algo, dek = passphrase_to_dek( keyid, sk->protect.algo,
&sk->protect.s2k, 0 ); &sk->protect.s2k, 0 );
@ -76,7 +78,7 @@ do_check( PKT_secret_key *sk )
csum += checksum_mpi( sk->skey[i] ); csum += checksum_mpi( sk->skey[i] );
m_free( buffer ); m_free( buffer );
} }
if( opt.emulate_bugs & 1 ) { if( opt.emulate_bugs & EMUBUG_GPGCHKSUM ) {
csum = sk->csum; csum = sk->csum;
} }
cipher_close( cipher_hd ); cipher_close( cipher_hd );
@ -180,6 +182,8 @@ protect_secret_key( PKT_secret_key *sk, DEK *dek )
if( check_cipher_algo( sk->protect.algo ) ) if( check_cipher_algo( sk->protect.algo ) )
rc = G10ERR_CIPHER_ALGO; /* unsupport protection algorithm */ rc = G10ERR_CIPHER_ALGO; /* unsupport protection algorithm */
else if( cipher_get_blocksize( sk->protect.algo ) != 8 )
rc = G10ERR_CIPHER_ALGO; /* unsupport protection algorithm */
else { else {
cipher_hd = cipher_open( sk->protect.algo, cipher_hd = cipher_open( sk->protect.algo,
CIPHER_MODE_AUTO_CFB, 1 ); CIPHER_MODE_AUTO_CFB, 1 );

View File

@ -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;
}

View File

@ -45,46 +45,8 @@ static char *db_name;
static int db_fd = -1; static int db_fd = -1;
static void create_db( const char *fname );
static void open_db(void); 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 int
tdbio_set_dbname( const char *new_dbname, int create ) 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; return G10ERR_TRUSTDB;
} }
if( create ) { if( create ) {
FILE *fp;
TRUSTREC rec;
int rc;
char *p = strrchr( fname, '/' ); char *p = strrchr( fname, '/' );
assert(p); assert(p);
*p = 0; *p = 0;
if( access( fname, F_OK ) ) { 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") ); log_fatal_f(fname, _("directory does not exist!\n") );
} }
*p = '/'; *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); 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 static void
open_db() 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 void
tdbio_dump_record( TRUSTREC *rec, FILE *fp ) tdbio_dump_record( TRUSTREC *rec, FILE *fp )
{ {
int i, any; int i;
ulong rnum = rec->recnum; ulong rnum = rec->recnum;
fprintf(fp, "rec %5lu, ", rnum ); fprintf(fp, "rec %5lu, ", rnum );
@ -193,7 +362,8 @@ tdbio_dump_record( TRUSTREC *rec, FILE *fp )
switch( rec->rectype ) { switch( rec->rectype ) {
case 0: fprintf(fp, "free\n"); case 0: fprintf(fp, "free\n");
break; break;
case RECTYPE_VER: fprintf(fp, "version\n"); case RECTYPE_VER: fprintf(fp, "version, keyhashtbl=%lu\n",
rec->r.ver.keyhashtbl );
break; break;
case RECTYPE_DIR: case RECTYPE_DIR:
fprintf(fp, "dir %lu, keys=%lu, uids=%lu, cach=%lu, ot=%02x", 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); putc('\n', fp);
break; break;
case RECTYPE_KEY: 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.lid,
rec->r.key.next, rec->r.key.next,
rec->r.key.pubkey_algo, rec->r.key.pubkey_algo );
rec->r.key.fingerprint_len ); 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 ) if( rec->r.key.keyflags & KEYF_REVOKED )
fputs(", revoked", fp ); fputs(", revoked", fp );
putc('\n', fp); putc('\n', fp);
@ -239,29 +410,29 @@ tdbio_dump_record( TRUSTREC *rec, FILE *fp )
rec->r.uid.next); rec->r.uid.next);
break; break;
case RECTYPE_SIG: case RECTYPE_SIG:
fprintf(fp, "sig %lu, next=%lu\n", fprintf(fp, "sig %lu, next=%lu,",
rec->r.sig.lid, rec->r.sig.next ); rec->r.sig.lid, rec->r.sig.next );
for(i=any=0; i < SIGS_PER_RECORD; i++ ) { for(i=0; i < SIGS_PER_RECORD; i++ ) {
if( rec->r.sig.sig[i].lid ) { if( rec->r.sig.sig[i].lid )
if( !any ) { fprintf(fp, " %lu:%02x", rec->r.sig.sig[i].lid,
putc('\t', fp);
any++;
}
fprintf(fp, " %lu:%02x", rec->r.sig.sig[i].lid,
rec->r.sig.sig[i].flag ); rec->r.sig.sig[i].flag );
}
} }
if( any ) putc('\n', fp);
putc('\n', fp);
break; break;
case RECTYPE_CACH: case RECTYPE_CACH:
fprintf(fp, "cach\n"); fprintf(fp, "cach\n");
break; break;
case RECTYPE_HTBL: 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; break;
case RECTYPE_HLST: 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; break;
default: default:
fprintf(fp, "unknown type %d\n", rec->rectype ); 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 ); recnum, expected, rec->rectype );
return G10ERR_TRUSTDB; return G10ERR_TRUSTDB;
} }
p++; p++; /* skip reserved byte */
switch( rec->rectype ) { switch( rec->rectype ) {
case 0: /* unused record */ case 0: /* unused (free) record */
break; break;
case RECTYPE_VER: /* version record */ case RECTYPE_VER: /* version record */
if( memcmp(buf+1, "gpg", 3 ) ) { if( memcmp(buf+1, "gpg", 3 ) ) {
log_error_f( db_name, _("not a trustdb file\n") ); log_error_f( db_name, _("not a trustdb file\n") );
rc = G10ERR_TRUSTDB; rc = G10ERR_TRUSTDB;
} }
p += 2; /* skip magic */ p += 2; /* skip "pgp" */
rec->r.ver.version = *p++; 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.created = buftoulong(p); p += 4;
rec->r.ver.modified = buftoulong(p); p += 4; rec->r.ver.modified = buftoulong(p); p += 4;
rec->r.ver.validated= buftoulong(p); p += 4; rec->r.ver.validated= buftoulong(p); p += 4;
rec->r.ver.marginals_needed = *p++; rec->r.ver.keyhashtbl=buftoulong(p); p += 4;
rec->r.ver.completes_needed = *p++;
rec->r.ver.max_cert_depth = *p++;
if( recnum ) { if( recnum ) {
log_error_f( db_name, "version record with recnum %lu\n", log_error_f( db_name, "version record with recnum %lu\n",
(ulong)recnum ); (ulong)recnum );
rc = G10ERR_TRUSTDB; 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", log_error_f( db_name, "invalid file version %d\n",
rec->r.ver.version ); rec->r.ver.version );
rc = G10ERR_TRUSTDB; 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; memcpy(rec->r.cache.blockhash, p, 20); p += 20;
rec->r.cache.trustlevel = *p++; rec->r.cache.trustlevel = *p++;
break; 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: default:
log_error_f( db_name, "invalid record type %d at recnum %lu\n", log_error_f( db_name, "invalid record type %d at recnum %lu\n",
rec->rectype, (ulong)recnum ); rec->rectype, (ulong)recnum );
@ -412,8 +593,16 @@ tdbio_write_record( TRUSTREC *rec )
switch( rec->rectype ) { switch( rec->rectype ) {
case 0: /* unused record */ case 0: /* unused record */
break; break;
case 1: /* version record */ case RECTYPE_VER: /* version record */
BUG(); 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; break;
case RECTYPE_DIR: /*directory record */ case RECTYPE_DIR: /*directory record */
@ -466,6 +655,19 @@ tdbio_write_record( TRUSTREC *rec )
*p++ = rec->r.cache.trustlevel; *p++ = rec->r.cache.trustlevel;
break; 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: default:
BUG(); BUG();
} }
@ -479,6 +681,8 @@ tdbio_write_record( TRUSTREC *rec )
log_error(_("trustdb: write failed (n=%d): %s\n"), n, strerror(errno) ); log_error(_("trustdb: write failed (n=%d): %s\n"), n, strerror(errno) );
return G10ERR_WRITE_FILE; return G10ERR_WRITE_FILE;
} }
else if( rec->rectype == RECTYPE_KEY )
rc = update_keyhashtbl( rec );
return rc; return rc;
} }
@ -528,9 +732,6 @@ tdbio_new_recnum()
/**************** /****************
* Search the trustdb for a key which matches PK and return the dir record * 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 * 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 int
tdbio_search_dir_record( PKT_public_key *pk, TRUSTREC *rec ) 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; byte *fingerprint;
size_t fingerlen; size_t fingerlen;
int rc; int rc;
ulong hashrec, item;
int msb;
int level=0;
keyid_from_pk( pk, keyid ); keyid_from_pk( pk, keyid );
fingerprint = fingerprint_from_pk( pk, NULL, &fingerlen ); fingerprint = fingerprint_from_pk( pk, NULL, &fingerlen );
assert( fingerlen == 20 || fingerlen == 16 ); assert( fingerlen == 20 || fingerlen == 16 );
for(recnum=1; !(rc=tdbio_read_record( recnum, rec, 0)); recnum++ ) { /* locate the key using the hash table */
if( rec->rectype != RECTYPE_KEY ) hashrec = get_keyhashrec();
continue; next_level:
if( rec->r.key.pubkey_algo == pk->pubkey_algo msb = fingerprint[level];
&& !memcmp(rec->r.key.fingerprint, fingerprint, fingerlen) ) { hashrec += msb / ITEMS_PER_HTBL_RECORD;
/* found: read the dir record for this key */ rc = tdbio_read_record( hashrec, rec, RECTYPE_HTBL );
recnum = rec->r.key.lid; if( rc ) {
rc = tdbio_read_record( recnum, rec, RECTYPE_DIR); log_error( db_name, "scan keyhashtbl failed: %s\n", g10_errstr(rc) );
if( rc ) return 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;
}
} }
if( rc != -1 )
log_error_f( db_name, _("search_db failed: %s\n"), g10_errstr(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;
}
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; return rc;
} }

View File

@ -60,15 +60,12 @@ struct trust_record {
int mark; int mark;
ulong recnum; ulong recnum;
union { union {
struct { /* version record: */ struct { /* version record: */
byte version; /* should be 1 */ byte version; /* should be 2 */
ulong locked; /* pid of process which holds a lock */
ulong created; /* timestamp of trustdb creation */ ulong created; /* timestamp of trustdb creation */
ulong modified; /* timestamp of last modification */ ulong modified; /* timestamp of last modification */
ulong validated; /* timestamp of last validation */ ulong validated; /* timestamp of last validation */
byte marginals_needed; ulong keyhashtbl;
byte completes_needed;
byte max_cert_depth;
} ver; } ver;
struct { /* directory record */ struct { /* directory record */
ulong lid; ulong lid;
@ -117,10 +114,7 @@ struct trust_record {
} htbl; } htbl;
struct { struct {
ulong next; ulong next;
struct { ulong rnum[ITEMS_PER_HLST_RECORD]; /* of a key record */
byte hash;
ulong rnum;
} item[ITEMS_PER_HLST_RECORD];
} hlst; } hlst;
} r; } r;
}; };

View File

@ -23,6 +23,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <errno.h> #include <errno.h>
#include <ctype.h>
#include <assert.h> #include <assert.h>
#include <sys/types.h> #include <sys/types.h>
#include <sys/stat.h> #include <sys/stat.h>
@ -102,6 +103,9 @@ static ulong last_trust_web_key;
static TRUST_SEG_LIST last_trust_web_tslist; 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 ******************* ************* list helpers *******************
**********************************************/ **********************************************/
@ -945,6 +949,7 @@ update_sigs( TRUSTREC *dir )
} }
else { else {
/* fixme: handle other sig classes here */ /* fixme: handle other sig classes here */
/* FIXME: Revocations!!! */
} }
} }
} }
@ -1243,7 +1248,16 @@ list_trustdb( const char *username )
{ {
TRUSTREC rec; 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 ); PKT_public_key *pk = m_alloc_clear( sizeof *pk );
int rc; 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 void
list_ownertrust() export_ownertrust()
{ {
TRUSTREC rec; TRUSTREC rec;
TRUSTREC rec2; 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 void
list_trust_path( int max_depth, const char *username ) list_trust_path( int max_depth, const char *username )
{ {
@ -1405,7 +1480,17 @@ check_trustdb( const char *username )
TRUSTREC rec; TRUSTREC rec;
int rc; 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 ); PKT_public_key *pk = m_alloc_clear( sizeof *pk );
if( (rc = get_pubkey_byname( pk, username )) ) 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 */ BUG(); /* more than one primary key */
keyid_from_pk( pk, keyid ); 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 = m_alloc_clear( sizeof *rec );
rec->rectype = RECTYPE_KEY; rec->rectype = RECTYPE_KEY;
rec->r.key.pubkey_algo = pk->pubkey_algo; rec->r.key.pubkey_algo = pk->pubkey_algo;

View File

@ -38,7 +38,8 @@
/*-- trustdb.c --*/ /*-- trustdb.c --*/
void list_trustdb(const char *username); void list_trustdb(const char *username);
void list_trust_path( int max_depth, 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 ); void check_trustdb( const char *username );
int init_trustdb( int level, const char *dbname ); int init_trustdb( int level, const char *dbname );
int check_trust( PKT_public_key *pk, unsigned *r_trustlevel ); int check_trust( PKT_public_key *pk, unsigned *r_trustlevel );

View File

@ -35,6 +35,7 @@
#define CIPHER_ALGO_DES_SK 6 #define CIPHER_ALGO_DES_SK 6
#define CIPHER_ALGO_BLOWFISH160 42 /* blowfish 160 bit key (not in OpenPGP)*/ #define CIPHER_ALGO_BLOWFISH160 42 /* blowfish 160 bit key (not in OpenPGP)*/
#define CIPHER_ALGO_SKIPJACK 101 /* experimental: skipjack */ #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 CIPHER_ALGO_DUMMY 110 /* no encryption at all */
#define PUBKEY_ALGO_RSA 1 #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 ); const char * cipher_algo_to_string( int algo );
int check_cipher_algo( int algo ); int check_cipher_algo( int algo );
unsigned cipher_get_keylen( int algo ); unsigned cipher_get_keylen( int algo );
unsigned cipher_get_blocksize( int algo );
CIPHER_HANDLE cipher_open( int algo, int mode, int secure ); CIPHER_HANDLE cipher_open( int algo, int mode, int secure );
void cipher_close( CIPHER_HANDLE c ); void cipher_close( CIPHER_HANDLE c );
void cipher_setkey( CIPHER_HANDLE c, byte *key, unsigned keylen ); void cipher_setkey( CIPHER_HANDLE c, byte *key, unsigned keylen );

View File

@ -25,6 +25,7 @@ void tty_print_string( byte *p, size_t n );
char *tty_get( const char *prompt ); char *tty_get( const char *prompt );
char *tty_get_hidden( const char *prompt ); char *tty_get_hidden( const char *prompt );
void tty_kill_prompt(void); void tty_kill_prompt(void);
int tty_get_answer_is_yes( const char *prompt );
#endif /*G10_TTYIO_H*/ #endif /*G10_TTYIO_H*/

View File

@ -49,7 +49,7 @@ g10m_release( MPI a )
void void
g10m_resize( MPI a, unsigned nbits ) 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 ); } MPI g10m_copy( MPI a ) { return mpi_copy( a ); }

View File

@ -120,6 +120,7 @@ mpi_invm( MPI x, MPI a, MPI n )
mpi_rshift(t2, t2, 1); mpi_rshift(t2, t2, 1);
mpi_rshift(t3, t3, 1); mpi_rshift(t3, t3, 1);
Y4: Y4:
;
} while( !mpi_test_bit( t3, 0 ) ); /* while t3 is even */ } while( !mpi_test_bit( t3, 0 ) ); /* while t3 is even */
if( !t3->sign ) { if( !t3->sign ) {
@ -216,6 +217,7 @@ mpi_invm( MPI x, MPI a, MPI n )
mpi_rshift(t3, t3, 1); mpi_rshift(t3, t3, 1);
} }
Y4: Y4:
;
} while( !mpi_test_bit( t3, 0 ) ); /* while t3 is even */ } while( !mpi_test_bit( t3, 0 ) ); /* while t3 is even */
if( !t3->sign ) { if( !t3->sign ) {

View File

@ -400,11 +400,6 @@ msgstr "--clearsign [Dateiname]"
msgid "--decrypt [filename]" msgid "--decrypt [filename]"
msgstr "--decrypt [Dateiname]" 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 #: g10/g10.c:810
msgid "--edit-key username" msgid "--edit-key username"
msgstr "--edit-key Benutzername" msgstr "--edit-key Benutzername"
@ -417,12 +412,6 @@ msgstr "--delete-secret-key Benutzername"
msgid "--delete-key username" msgid "--delete-key username"
msgstr "--delete-key Benutzername" 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 #. prepare iobufs
#: g10/encode.c:200 g10/g10.c:853 g10/keylist.c:79 #: g10/encode.c:200 g10/g10.c:853 g10/keylist.c:79
msgid "can't open %s: %s\n" msgid "can't open %s: %s\n"
@ -810,12 +799,12 @@ msgstr "\"passphrase\" nicht richtig wiederholt; noch einmal.\n"
msgid "" msgid ""
"You don't want a passphrase - this is probably a *bad* idea!\n" "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" "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" "\n"
msgstr "" msgstr ""
"Sie m\366chten keine \"passphrase\" - Dies ist eine *schlechte* Idee!\n" "Sie m\366chten keine \"passphrase\" - Dies ist eine *schlechte* Idee!\n"
"Es ist trotzdem m\366glich. Sie k\366nnen Ihre \"phassphrase\" jederzeit\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" "aufrufen.\n"
"\n" "\n"

View File

@ -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)) Tue Jul 21 10:35:48 1998 Werner Koch (wk@(none))
* argparse.c: New option flag to distinguish options and commands. * argparse.c: New option flag to distinguish options and commands.

View File

@ -91,3 +91,4 @@ answer_is_yes( const char *s )
return 0; return 0;
} }

View File

@ -204,7 +204,7 @@ secmem_malloc( size_t size )
} }
/* allocate a new block */ /* allocate a new block */
if( (poollen + size <= poolsize) ) { if( (poollen + size <= poolsize) ) {
mb = pool + poollen; mb = (void*)((char*)pool + poollen);
poollen += size; poollen += size;
mb->size = 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 */ return p; /* it is easier not to shrink the memory */
a = secmem_malloc( newsize ); a = secmem_malloc( newsize );
memcpy(a, p, size); memcpy(a, p, size);
memset(a+size, 0, newsize-size); memset((char*)a+size, 0, newsize-size);
secmem_free(p); secmem_free(p);
return a; return a;
} }
@ -271,7 +271,7 @@ secmem_free( void *a )
int int
m_is_secure( const void *p ) m_is_secure( const void *p )
{ {
return p >= pool && p < (pool+poolsize); return p >= pool && p < ((char*)pool+poolsize);
} }
void void

View File

@ -328,3 +328,15 @@ tty_kill_prompt()
last_prompt_len = 0; 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;
}