From 4ec1775f3eaf8733a5285460b631253b90d3c6fb Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Fri, 16 Jan 1998 21:15:24 +0000 Subject: [PATCH] added some trust model stuff --- Makefile.in | 4 +- NEWS | 11 + cipher/blowfish.c | 2 +- cipher/md.c | 2 +- cipher/md5.c | 1 - cipher/misc.c | 6 +- cipher/primegen.c | 4 +- cipher/random.c | 16 +- configure.in | 2 +- g10/Makefile.am | 1 + g10/Makefile.in | 26 +- g10/armor.c | 15 +- g10/build-packet.c | 101 ++++-- g10/compress.c | 6 +- g10/encode.c | 4 +- g10/g10.c | 69 +++- g10/import.c | 146 ++++++++ g10/keydb.h | 17 +- g10/keygen.c | 26 +- g10/keyid.c | 1 - g10/main.h | 5 +- g10/mainproc.c | 10 +- g10/packet.h | 10 +- g10/parse-packet.c | 148 ++++++-- g10/passphrase.c | 1 + g10/pkclist.c | 3 +- g10/ringedit.c | 121 ++++++- g10/seckey-cert.c | 10 +- g10/seskey.c | 13 +- g10/sig-check.c | 15 +- g10/sign.c | 19 +- g10/skclist.c | 1 - g10/trustdb.c | 859 ++++++++++++++++++++++++++++++++++++++++----- g10/trustdb.h | 6 +- include/cipher.h | 1 + include/errors.h | 1 + include/iobuf.h | 1 + include/mpi.h | 1 - include/util.h | 31 +- mpi/mpi-bit.c | 3 +- mpi/mpi-internal.h | 2 +- mpi/mpi-pow.c | 2 +- mpi/mpicoder.c | 52 ++- mpi/mpiutil.c | 4 +- util/argparse.c | 1 - util/errors.c | 7 +- util/iobuf.c | 106 +++++- util/logger.c | 16 +- util/ttyio.c | 2 +- 49 files changed, 1580 insertions(+), 331 deletions(-) create mode 100644 g10/import.c diff --git a/Makefile.in b/Makefile.in index b25badfe5..ff5231486 100644 --- a/Makefile.in +++ b/Makefile.in @@ -45,8 +45,8 @@ CONFIG_HEADER_IN = config.h.in mkinstalldirs = $(top_srcdir)/scripts/mkinstalldirs CONFIG_HEADER = ./config.h DIST_COMMON = README AUTHORS COPYING ChangeLog INSTALL Makefile.am \ -Makefile.in NEWS README TODO acconfig.h config.h.in configure.in \ -stamp-h.in +Makefile.in NEWS README TODO acconfig.h config.h.in configure \ +configure.in stamp-h.in PACKAGE = @PACKAGE@ diff --git a/NEWS b/NEWS index eeee0dcb0..f2282082a 100644 --- a/NEWS +++ b/NEWS @@ -1,4 +1,15 @@ + * New option "--quick-random" which uses a much quicker random + number generator. Keys generated while this option is in effect + are flags with "INSECURE!" in the user-id. This is a development + only option. + + * Read support for new version packets (OpenPGP). + + * Comment packets are now of coorect OpenPGP type 16. Old comment + packets writen by G10 are detected because they always start with + a hash which is an invalid version byte. + * The string "(INSECURE!)" is appended to a new user-id if this is generated on a system without a good random number generator. diff --git a/cipher/blowfish.c b/cipher/blowfish.c index 5dbaf7195..81e33d080 100644 --- a/cipher/blowfish.c +++ b/cipher/blowfish.c @@ -412,7 +412,7 @@ selftest() void blowfish_setkey( BLOWFISH_context *c, byte *key, unsigned keylen ) { - int i, j, k; + int i, j; u32 data, datal, datar; static int initialized; diff --git a/cipher/md.c b/cipher/md.c index e88a45c77..eb7b7b845 100644 --- a/cipher/md.c +++ b/cipher/md.c @@ -144,7 +144,7 @@ md_read( MD_HANDLE a, int algo ) if( algo == DIGEST_ALGO_MD5 ) return md5_read( &a->md5 ); } - log_bug(NULL); + BUG(); } int diff --git a/cipher/md5.c b/cipher/md5.c index 6906503d4..c9f9a86b4 100644 --- a/cipher/md5.c +++ b/cipher/md5.c @@ -73,7 +73,6 @@ #endif -static void Init( MD5_CONTEXT *mdContext); static void Transform(u32 *buf,u32 *in); static byte PADDING[64] = { diff --git a/cipher/misc.c b/cipher/misc.c index cd0d31a49..7c8f2e3c7 100644 --- a/cipher/misc.c +++ b/cipher/misc.c @@ -67,7 +67,7 @@ string_to_cipher_algo( const char *string ) int i; const char *s; - for(i=0; s=cipher_names[i].name; i++ ) + for(i=0; (s=cipher_names[i].name); i++ ) if( !stricmp( s, string ) ) return cipher_names[i].algo; return 0; @@ -83,7 +83,7 @@ string_to_pubkey_algo( const char *string ) int i; const char *s; - for(i=0; s=pubkey_names[i].name; i++ ) + for(i=0; (s=pubkey_names[i].name); i++ ) if( !stricmp( s, string ) ) return pubkey_names[i].algo; return 0; @@ -98,7 +98,7 @@ string_to_digest_algo( const char *string ) int i; const char *s; - for(i=0; s=digest_names[i].name; i++ ) + for(i=0; (s=digest_names[i].name); i++ ) if( !stricmp( s, string ) ) return digest_names[i].algo; return 0; diff --git a/cipher/primegen.c b/cipher/primegen.c index 3f6c1f325..9514fdae8 100644 --- a/cipher/primegen.c +++ b/cipher/primegen.c @@ -319,8 +319,6 @@ check_prime( MPI prime ) int i; unsigned x; int count=0; - MPI result; - MPI val_2; /* check against small primes */ for(i=0; (x = small_prime_numbers[i]); i++ ) { @@ -431,7 +429,7 @@ m_out_of_n( char *array, int m, int n ) array[i] = 1; return; } - log_bug(NULL); + BUG(); } for(j=1; j < n; j++ ) { diff --git a/cipher/random.c b/cipher/random.c index 41f001e7e..b082022af 100644 --- a/cipher/random.c +++ b/cipher/random.c @@ -30,6 +30,7 @@ #include #include "util.h" #include "cipher.h" +#include "ttyio.h" struct cache { int len; @@ -41,6 +42,18 @@ static struct cache cache[3]; static void fill_buffer( byte *buffer, size_t length, int level ); +static int quick_test; + + +int +quick_random_gen( int onoff ) +{ + int last = quick_test; + if( onoff != -1 ) + quick_test = onoff; + return last; +} + /**************** * Fill the buffer with LENGTH bytes of cryptologic strong @@ -95,14 +108,13 @@ open_device( const char *name, int minor ) static void fill_buffer( byte *buffer, size_t length, int level ) { - FILE *fp; static int fd_urandom = -1; static int fd_random = -1; int fd; int n; int warn=0; - if( level == 2 ) { + if( level == 2 && !quick_test ) { if( fd_random == -1 ) fd_random = open_device( "/dev/random", 8 ); fd = fd_random; diff --git a/configure.in b/configure.in index f01033baf..6a97d416a 100644 --- a/configure.in +++ b/configure.in @@ -19,8 +19,8 @@ AC_ARG_ENABLE(m-debug, [ --enable-m-debug Enable debugging of memory allocation]) if test "$enableval" = y || test "$enableval" = yes; then AC_DEFINE(M_DEBUG) - CFLAGS=-g fi +CFLAGS="-g -Wall" dnl some additional macros diff --git a/g10/Makefile.am b/g10/Makefile.am index b6b9ce572..5c22b4b7e 100644 --- a/g10/Makefile.am +++ b/g10/Makefile.am @@ -40,6 +40,7 @@ g10_SOURCES = g10.c \ seckey-cert.c \ seskey.c \ sign.c \ + import.c \ comment.c \ sig-check.c diff --git a/g10/Makefile.in b/g10/Makefile.in index 7e5ef73ac..1212499da 100644 --- a/g10/Makefile.in +++ b/g10/Makefile.in @@ -78,6 +78,7 @@ g10_SOURCES = g10.c \ seckey-cert.c \ seskey.c \ sign.c \ + import.c \ comment.c \ sig-check.c @@ -103,7 +104,8 @@ g10_OBJECTS = g10.o build-packet.o compress.o encode.o encr-data.o \ free-packet.o getkey.o pkclist.o skclist.o ringedit.o kbnode.o keygen.o \ mainproc.o armor.o mdfilter.o textfilter.o cipher.o elg.o rsa.o \ openfile.o keyid.o trustdb.o parse-packet.o passphrase.o plaintext.o \ -pubkey-enc.o seckey-cert.o seskey.o sign.o comment.o sig-check.o +pubkey-enc.o seckey-cert.o seskey.o sign.o import.o comment.o \ +sig-check.o EXTRA_g10_SOURCES = g10_LDADD = $(LDADD) DIST_COMMON = Makefile.am Makefile.in @@ -123,17 +125,17 @@ $(srcdir)/.deps/cipher.P $(srcdir)/.deps/comment.P \ $(srcdir)/.deps/compress.P $(srcdir)/.deps/elg.P \ $(srcdir)/.deps/encode.P $(srcdir)/.deps/encr-data.P \ $(srcdir)/.deps/free-packet.P $(srcdir)/.deps/g10.P \ -$(srcdir)/.deps/getkey.P $(srcdir)/.deps/kbnode.P \ -$(srcdir)/.deps/keygen.P $(srcdir)/.deps/keyid.P \ -$(srcdir)/.deps/mainproc.P $(srcdir)/.deps/mdfilter.P \ -$(srcdir)/.deps/openfile.P $(srcdir)/.deps/parse-packet.P \ -$(srcdir)/.deps/passphrase.P $(srcdir)/.deps/pkclist.P \ -$(srcdir)/.deps/plaintext.P $(srcdir)/.deps/pubkey-enc.P \ -$(srcdir)/.deps/ringedit.P $(srcdir)/.deps/rsa.P \ -$(srcdir)/.deps/seckey-cert.P $(srcdir)/.deps/seskey.P \ -$(srcdir)/.deps/sig-check.P $(srcdir)/.deps/sign.P \ -$(srcdir)/.deps/skclist.P $(srcdir)/.deps/textfilter.P \ -$(srcdir)/.deps/trustdb.P +$(srcdir)/.deps/getkey.P $(srcdir)/.deps/import.P \ +$(srcdir)/.deps/kbnode.P $(srcdir)/.deps/keygen.P \ +$(srcdir)/.deps/keyid.P $(srcdir)/.deps/mainproc.P \ +$(srcdir)/.deps/mdfilter.P $(srcdir)/.deps/openfile.P \ +$(srcdir)/.deps/parse-packet.P $(srcdir)/.deps/passphrase.P \ +$(srcdir)/.deps/pkclist.P $(srcdir)/.deps/plaintext.P \ +$(srcdir)/.deps/pubkey-enc.P $(srcdir)/.deps/ringedit.P \ +$(srcdir)/.deps/rsa.P $(srcdir)/.deps/seckey-cert.P \ +$(srcdir)/.deps/seskey.P $(srcdir)/.deps/sig-check.P \ +$(srcdir)/.deps/sign.P $(srcdir)/.deps/skclist.P \ +$(srcdir)/.deps/textfilter.P $(srcdir)/.deps/trustdb.P SOURCES = $(g10_SOURCES) OBJECTS = $(g10_OBJECTS) diff --git a/g10/armor.c b/g10/armor.c index f6e6305d4..6a432d318 100644 --- a/g10/armor.c +++ b/g10/armor.c @@ -275,7 +275,7 @@ check_input( armor_filter_context_t *afx, IOBUF a ) { int rc = 0; int c; - size_t n = 0, nn=0, nn_limit=0; + size_t n = 0, nn=0; struct fhdr_struct fhdr; assert( DIM(afx->helpbuf) >= 50 ); @@ -339,7 +339,7 @@ fake_packet( armor_filter_context_t *afx, IOBUF a, { int rc = 0; int c; - size_t n = 0, nn=0, nn_limit=0; + size_t n = 0; struct fhdr_struct *fhdr = afx->fake; byte *helpbuf = afx->helpbuf; int helpidx = afx->helpidx; @@ -347,7 +347,6 @@ fake_packet( armor_filter_context_t *afx, IOBUF a, byte *tempbuf = afx->tempbuf; int tempidx = afx->tempidx; int templen = afx->templen; - int defer=1; /* FIXME: have to read one ahead or do some other mimic to * get rid of the lf before the "begin signed message" @@ -417,7 +416,7 @@ radix64_read( armor_filter_context_t *afx, IOBUF a, size_t *retn, int c, c2; int checkcrc=0; int rc = 0; - size_t n = 0, nn=0; + size_t n = 0; int idx, i; u32 crc; @@ -450,7 +449,7 @@ radix64_read( armor_filter_context_t *afx, IOBUF a, size_t *retn, idx = (idx+1) % 4; } for(i=0; i < n; i++ ) - crc = (crc << 8) ^ crc_table[(crc >> 16)&0xff ^ buf[i]]; + crc = (crc << 8) ^ crc_table[((crc >> 16)&0xff) ^ buf[i]]; crc &= 0x00ffffff; afx->crc = crc; afx->idx = idx; @@ -533,7 +532,7 @@ armor_filter( void *opaque, int control, { size_t size = *ret_len; armor_filter_context_t *afx = opaque; - int rc=0, i, c, c2; + int rc=0, i, c; byte radbuf[3]; int idx, idx2; size_t n=0; @@ -553,7 +552,7 @@ armor_filter( void *opaque, int control, } else if( control == IOBUFCTRL_UNDERFLOW ) { if( size < 20 ) - log_bug(NULL); /* supplied buffer maybe too short */ + BUG(); /* supplied buffer maybe too short */ if( afx->inp_eof ) { *ret_len = 0; @@ -608,7 +607,7 @@ armor_filter( void *opaque, int control, radbuf[i] = afx->radbuf[i]; for(i=0; i < size; i++ ) - crc = (crc << 8) ^ crc_table[(crc >> 16)&0xff ^ buf[i]]; + crc = (crc << 8) ^ crc_table[((crc >> 16)&0xff) ^ buf[i]]; crc &= 0x00ffffff; for( ; size; buf++, size-- ) { diff --git a/g10/build-packet.c b/g10/build-packet.c index 5bacf3f86..a541c8cae 100644 --- a/g10/build-packet.c +++ b/g10/build-packet.c @@ -50,7 +50,8 @@ static int calc_header_length( u32 len ); static int write_16(IOBUF inp, u16 a); static int write_32(IOBUF inp, u32 a); static int write_header( IOBUF out, int ctb, u32 len ); -static int write_header2( IOBUF out, int ctb, u32 len, 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_version( IOBUF out, int ctb ); /**************** @@ -67,7 +68,10 @@ build_packet( IOBUF out, PACKET *pkt ) if( DBG_PACKET ) log_debug("build_packet() type=%d\n", pkt->pkttype ); assert( pkt->pkt.generic ); - ctb = 0x80 | ((pkt->pkttype & 15)<<2); + if( pkt->pkttype > 15 ) /* new format */ + ctb = 0xc0 | (pkt->pkttype & 0x3f); + else + ctb = 0x80 | ((pkt->pkttype & 15)<<2); switch( pkt->pkttype ) { case PKT_USER_ID: rc = do_user_id( out, ctb, pkt->pkt.user_id ); @@ -164,7 +168,10 @@ do_public_cert( IOBUF out, int ctb, PKT_public_cert *pkc ) int rc = 0; IOBUF a = iobuf_temp(); - write_version( a, ctb ); + if( !pkc->version ) + iobuf_put( a, 3 ); + else + iobuf_put( a, pkc->version ); write_32(a, pkc->timestamp ); write_16(a, pkc->valid_days ); iobuf_put(a, pkc->pubkey_algo ); @@ -182,7 +189,7 @@ do_public_cert( IOBUF out, int ctb, PKT_public_cert *pkc ) goto leave; } - write_header(out, ctb, iobuf_get_temp_length(a) ); + write_header2(out, ctb, iobuf_get_temp_length(a), pkc->hdrbytes, 1 ); if( iobuf_write_temp( out, a ) ) rc = G10ERR_WRITE_FILE; @@ -202,6 +209,7 @@ hash_public_cert( MD_HANDLE md, PKT_public_cert *pkc ) int rc = 0; int c; IOBUF a = iobuf_temp(); + FILE *fp = fopen("dump.pkc", "a"); /* build the packet */ init_packet(&pkt); @@ -209,9 +217,11 @@ hash_public_cert( MD_HANDLE md, PKT_public_cert *pkc ) pkt.pkt.public_cert = pkc; if( (rc = build_packet( a, &pkt )) ) log_fatal("build public_cert for hashing failed: %s\n", g10_errstr(rc)); - while( (c=iobuf_get(a)) != -1 ) + while( (c=iobuf_get(a)) != -1 ) { + putc( c, fp); md_putc( md, c ); - + } + fclose(fp); iobuf_cancel(a); } @@ -222,7 +232,10 @@ do_secret_cert( IOBUF out, int ctb, PKT_secret_cert *skc ) int rc = 0; IOBUF a = iobuf_temp(); - write_version( a, ctb ); + if( !skc->version ) + iobuf_put( a, 3 ); + else + iobuf_put( a, skc->version ); write_32(a, skc->timestamp ); write_16(a, skc->valid_days ); iobuf_put(a, skc->pubkey_algo ); @@ -262,7 +275,7 @@ do_secret_cert( IOBUF out, int ctb, PKT_secret_cert *skc ) goto leave; } - write_header(out, ctb, iobuf_get_temp_length(a) ); + write_header2(out, ctb, iobuf_get_temp_length(a), skc->hdrbytes, 1 ); if( iobuf_write_temp( out, a ) ) rc = G10ERR_WRITE_FILE; @@ -365,7 +378,7 @@ do_compressed( IOBUF out, int ctb, PKT_compressed *cd ) int rc = 0; /* we must use the old convention and don't use blockmode */ - write_header2(out, ctb, 0, 0 ); + write_header2(out, ctb, 0, 0, 0 ); iobuf_put(out, cd->algorithm ); /* This is all. The caller has to write the real data */ @@ -433,7 +446,6 @@ do_onepass_sig( IOBUF out, int ctb, PKT_onepass_sig *ops ) if( iobuf_write_temp( out, a ) ) rc = G10ERR_WRITE_FILE; - leave: iobuf_close(a); return rc; } @@ -482,20 +494,39 @@ calc_header_length( u32 len ) static int write_header( IOBUF out, int ctb, u32 len ) { - return write_header2( out, ctb, len, 1 ); + return write_header2( out, ctb, len, 0, 1 ); } +/**************** + * if HDRLEN is > 0, try to build a header of this length. + * we need this, so hat we can hash packets without reading them again. + */ static int -write_header2( IOBUF out, int ctb, u32 len, int blkmode ) +write_header2( IOBUF out, int ctb, u32 len, int hdrlen, int blkmode ) { - if( !len ) - ctb |= 3; - else if( len < 256 ) - ; - else if( len < 65536 ) - ctb |= 1; - else - ctb |= 2; + if( ctb & 0x40 ) + return write_new_header( out, ctb, len, hdrlen ); + + if( hdrlen ) { + if( !len ) + ctb |= 3; + else if( hdrlen == 2 && len < 256 ) + ; + else if( hdrlen == 3 && len < 65536 ) + ctb |= 1; + else + ctb |= 2; + } + else { + if( !len ) + ctb |= 3; + else if( len < 256 ) + ; + else if( len < 65536 ) + ctb |= 1; + else + ctb |= 2; + } if( iobuf_put(out, ctb ) ) return -1; if( !len ) { @@ -515,6 +546,36 @@ write_header2( IOBUF out, int ctb, u32 len, int blkmode ) return 0; } + +static int +write_new_header( IOBUF out, int ctb, u32 len, int hdrlen ) +{ + if( hdrlen ) + log_bug("can't cope with hdrlen yet\n"); + + if( iobuf_put(out, ctb ) ) + return -1; + if( !len ) { + log_bug("can't write partial headers yet\n"); + } + else { + if( len < 192 ) { + if( iobuf_put(out, len ) ) + return -1; + } + else if( len < 8384 ) { + len -= 192; + if( iobuf_put( out, (len / 256) + 192) ) + return -1; + if( iobuf_put( out, (len % 256) ) ) + return -1; + } + else + log_bug("need a partial header to code a length %lu\n", (ulong)len); + } + return 0; +} + static int write_version( IOBUF out, int ctb ) { diff --git a/g10/compress.c b/g10/compress.c index 0502b3637..8f8b5e6de 100644 --- a/g10/compress.c +++ b/g10/compress.c @@ -41,7 +41,6 @@ static void init_compress( compress_filter_context_t *zfx, z_stream *zs ) { int rc; - byte *inbuf, *outbuf; int level; @@ -102,9 +101,6 @@ static void init_uncompress( compress_filter_context_t *zfx, z_stream *zs ) { int rc; - byte *inbuf, *outbuf; - int level; - /**************** * PGP uses a windowsize of 13 bits. Using a negative value for @@ -175,7 +171,7 @@ compress_filter( void *opaque, int control, size_t size = *ret_len; compress_filter_context_t *zfx = opaque; z_stream *zs = zfx->opaque; - int zrc, rc=0; + int rc=0; if( control == IOBUFCTRL_UNDERFLOW ) { if( !zfx->status ) { diff --git a/g10/encode.c b/g10/encode.c index ff125079e..04aebefdb 100644 --- a/g10/encode.c +++ b/g10/encode.c @@ -265,7 +265,7 @@ encrypt_filter( void *opaque, int control, int rc=0; if( control == IOBUFCTRL_UNDERFLOW ) { /* decrypt */ - log_bug(NULL); /* not used */ + BUG(); /* not used */ } else if( control == IOBUFCTRL_FLUSH ) { /* encrypt */ if( !efx->header_okay ) { @@ -317,7 +317,7 @@ write_pubkey_enc_from_list( PKC_LIST pkc_list, DEK *dek, IOBUF out ) else if( enc->pubkey_algo == PUBKEY_ALGO_RSA ) g10_rsa_encrypt( pkc, enc, dek ); else - log_bug(NULL); + BUG(); /* and write it */ init_packet(&pkt); pkt.pkttype = PKT_PUBKEY_ENC; diff --git a/g10/g10.c b/g10/g10.c index 2002e69e1..a00a3f97a 100644 --- a/g10/g10.c +++ b/g10/g10.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include "packet.h" @@ -35,11 +36,13 @@ #include "cipher.h" #include "filter.h" #include "trustdb.h" +#include "ttyio.h" enum cmd_values { aNull = 0, aSym, aStore, aEncr, aPrimegen, aKeygen, aSign, aSignEncr, aPrintMDs, aSignKey, aClearsig, aListPackets, aEditSig, - aKMode, aKModeC, aChangePass, + aKMode, aKModeC, aChangePass, aImport, aListTrustDB, + aListTrustPath, aTest }; @@ -88,6 +91,15 @@ strusage( int level ) return p; } +static void +wrong_args( const char *text) +{ + fputs("Usage: g10 [options] ",stderr); + fputs(text,stderr); + putc('\n',stderr); + exit(2); +} + static void set_debug(void) { @@ -174,11 +186,15 @@ main( int argc, char **argv ) { 527, "cipher-algo", 2 , "select default cipher algorithm" }, { 528, "pubkey-algo", 2 , "select default puplic key algorithm" }, { 529, "digest-algo", 2 , "select default message digest algorithm" }, + { 530, "import", 0 , "put public keys into the trustdb" }, + { 531, "list-trustdb",0 , "\r"}, + { 532, "quick-random", 0, "\r"}, + { 533, "list-trust-path",0, "\r"}, {0} }; ARGPARSE_ARGS pargs; IOBUF a; - int rc; + int rc=0; int orig_argc; char **orig_argv; const char *fname, *fname_print; @@ -316,9 +332,10 @@ main( int argc, char **argv ) case 529: opt.def_digest_algo = string_to_digest_algo(pargs.r.ret_str); break; - - - break; + case 530: set_cmd( &cmd, aImport); break; + case 531: set_cmd( &cmd, aListTrustDB); break; + case 532: quick_random_gen(1); break; + case 533: set_cmd( &cmd, aListTrustPath); break; default : errors++; pargs.err = configfp? 1:2; break; } } @@ -393,11 +410,15 @@ main( int argc, char **argv ) } } - if( cmd != aPrimegen && cmd != aPrintMDs ) { - rc = check_trustdb(0); - if( rc ) - log_error("failed to initialize the TrustDB: %s\n", g10_errstr(rc)); + switch( cmd ) { + case aPrimegen: + case aPrintMDs: + break; + case aListTrustDB: rc = init_trustdb( argc? 1:0 ); break; + default: rc = init_trustdb(1); break; } + if( rc ) + log_error("failed to initialize the TrustDB: %s\n", g10_errstr(rc)); switch( cmd ) { @@ -487,7 +508,7 @@ main( int argc, char **argv ) int i, seq=0; const char *s; - while( s=get_keyring(seq++) ) { + while( (s=get_keyring(seq++)) ) { if( !(a = iobuf_open(s)) ) { log_error("can't open '%s'\n", s); continue; @@ -554,6 +575,32 @@ main( int argc, char **argv ) case aTest: do_test( argc? atoi(*argv): 0 ); break; + case aImport: + if( !argc ) + usage(1); + for( ; argc; argc--, argv++ ) { + rc = import_pubkeys( *argv ); + if( rc ) + log_error("import from '%s' failed: %s\n", + *argv, g10_errstr(rc) ); + } + break; + + case aListTrustDB: + if( !argc ) + list_trustdb(NULL); + else { + for( ; argc; argc--, argv++ ) + list_trustdb( *argv ); + } + break; + + case aListTrustPath: + if( argc != 2 ) + wrong_args("--list-trust-path "); + list_trust_path( atoi(*argv), argv[1] ); + break; + case aListPackets: opt.list_packets=1; default: @@ -631,8 +678,6 @@ print_mds( const char *fname ) if( ferror(fp) ) log_error("%s: %s\n", fname, strerror(errno) ); else { - byte *p; - md_final(md); printf( "%s: MD5 =", fname ); print_hex(md_read(md, DIGEST_ALGO_MD5), 16 ); printf("\n%s: RMD160 =", fname ); print_hex(md_read(md, DIGEST_ALGO_RMD160), 20 ); diff --git a/g10/import.c b/g10/import.c new file mode 100644 index 000000000..91140d459 --- /dev/null +++ b/g10/import.c @@ -0,0 +1,146 @@ +/* import.c + * Copyright (c) 1998 by Werner Koch (dd9jn) + * + * This file is part of G10. + * + * G10 is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * G10 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include +#include +#include +#include +#include +#include + +#include "options.h" +#include "packet.h" +#include "errors.h" +#include "keydb.h" +#include "memory.h" +#include "util.h" +#include "trustdb.h" + + +/**************** + * Import the public keys from the given filename. + * Import is a somewhat misleading name, as we (only) add informations + * about the public keys into aout trustdb. + * + * NOTE: this function is not really needed and will be changed to + * a function which reads a plain textfile, describing a public + * key and its associated ownertrust. This can be used (together + * with the export function) to make a backup of the assigned + * ownertrusts. + */ +int +import_pubkeys( const char *filename ) +{ + int rc; + PACKET pkt; + int save_mode; + ulong offset; + IOBUF iobuf = NULL; + + init_packet(&pkt); + save_mode = set_packet_list_mode(0); + + if( !(iobuf = iobuf_open( filename )) ) { + rc = G10ERR_KEYRING_OPEN; + goto leave; + } + + while( !(rc=search_packet(iobuf, &pkt, PKT_PUBLIC_CERT, &offset)) ) { + PKT_public_cert *pkc = pkt.pkt.public_cert; + u32 keyid[2]; + int otrust; + + assert( pkt.pkttype == PKT_PUBLIC_CERT ); + + keyid_from_pkc( pkc, keyid ); + rc = get_ownertrust( pkc, &otrust ); + if( rc && rc != -1 ) { + log_error("error getting otrust of %08lX: %s\n", + keyid[1], g10_errstr(rc) ); + } + else if( rc == -1 ) { /* No pubkey in trustDB: Insert */ + rc = insert_trust_record( pkc ); + if( rc ) { + log_error("failed to insert it into the trustdb: %s\n", + g10_errstr(rc) ); + } + else { + rc = get_ownertrust( pkc, &otrust ); + if( rc ) + log_fatal("failed to reread the pubkey record: %s\n", + g10_errstr(rc) ); + log_info("key %08lX inserted in trustdb (localid=%lu)\n", + keyid[1], pkc->local_id ); + } + } + else + log_info("key %08lX already in trustdb (localid=%lu)\n", + keyid[1], pkc->local_id ); + + free_packet(&pkt); + } + + iobuf_close(iobuf); + if( !(iobuf = iobuf_open( filename )) ) { + rc = G10ERR_KEYRING_OPEN; + goto leave; + } + + while( !(rc=search_packet(iobuf, &pkt, PKT_PUBLIC_CERT, &offset)) ) { + PKT_public_cert *pkc = pkt.pkt.public_cert; + u32 keyid[2]; + int trustlevel; + + assert( pkt.pkttype == PKT_PUBLIC_CERT ); + + keyid_from_pkc( pkc, keyid ); + rc = check_pkc_trust( pkc, &trustlevel ); + if( rc ) { + log_error("error checking trust of %08lX: %s\n", + keyid[1], g10_errstr(rc) ); + } + else if( trustlevel & TRUST_NO_PUBKEY ) { + /* No pubkey in trustDB: Insert and check again */ + rc = insert_trust_record( pkc ); + if( rc ) { + log_error("failed to insert it into the trustdb: %s\n", + g10_errstr(rc) ); + } + else { + rc = check_pkc_trust( pkc, &trustlevel ); + if( rc ) + log_fatal("trust check after insert failed: %s\n", + g10_errstr(rc) ); + if( trustlevel & TRUST_NO_PUBKEY ) + BUG(); + } + } + + free_packet(&pkt); + } + + leave: + iobuf_close(iobuf); + free_packet(&pkt); + set_packet_list_mode(save_mode); + return rc; +} + + diff --git a/g10/keydb.h b/g10/keydb.h index 8eb49478d..818b64307 100644 --- a/g10/keydb.h +++ b/g10/keydb.h @@ -72,6 +72,17 @@ struct skc_list { int mark; }; +/* structure to collect all informations which can be used to + * identify a public key */ +typedef struct pubkey_find_info *PUBKEY_FIND_INFO; +struct pubkey_find_info { + u32 keyid[2]; + unsigned nbits; + byte pubkey_algo; + byte fingerprint[20]; + char userid[1]; +}; + /*-- pkclist.c --*/ void release_pkc_list( PKC_LIST pkc_list ); @@ -128,9 +139,9 @@ void clear_kbnode_flags( KBNODE n ); /*-- ringedit.c --*/ int add_keyblock_resource( const char *filename, int force, int secret ); int get_keyblock_handle( const char *filename, int secret, KBPOS *kbpos ); -int search_keyblock( PACKET *pkt, KBPOS *kbpos, int secret ); -int search_keyblock_byname( KBPOS *kbpos, const char *username ); -int search_secret_keyblock_byname( KBPOS *kbpos, const char *username ); +int find_keyblock( PUBKEY_FIND_INFO info, KBPOS *kbpos ); +int find_keyblock_byname( KBPOS *kbpos, const char *username ); +int find_secret_keyblock_byname( KBPOS *kbpos, const char *username ); int lock_keyblock( KBPOS *kbpos ); void unlock_keyblock( KBPOS *kbpos ); int read_keyblock( KBPOS *kbpos, KBNODE *ret_root ); diff --git a/g10/keygen.c b/g10/keygen.c index c83d8660a..1f932f71b 100644 --- a/g10/keygen.c +++ b/g10/keygen.c @@ -113,7 +113,7 @@ write_selfsig( KBNODE root, KBNODE pub_root, PKT_secret_cert *skc ) break; } if( !node ) - log_bug(NULL); /* no user id packet in tree */ + BUG(); /* no user id packet in tree */ uid = node->pkt->pkt.user_id; /* get the pkc packet from the pub_tree */ for( kbctx=NULL; (node=walk_kbtree( pub_root, &kbctx)) ; ) { @@ -121,7 +121,7 @@ write_selfsig( KBNODE root, KBNODE pub_root, PKT_secret_cert *skc ) break; } if( !node ) - log_bug(NULL); + BUG(); pkc = node->pkt->pkt.public_cert; /* and make the signature */ @@ -149,12 +149,11 @@ gen_elg(unsigned nbits, KBNODE pub_root, KBNODE sec_root, DEK *dek, PKT_public_cert *pkc; ELG_public_key pk; ELG_secret_key sk; - unsigned nbytes; elg_generate( &pk, &sk, nbits ); - skc = m_alloc( sizeof *skc ); - pkc = m_alloc( sizeof *pkc ); + skc = m_alloc_clear( sizeof *skc ); + pkc = m_alloc_clear( sizeof *pkc ); skc->timestamp = pkc->timestamp = make_timestamp(); skc->valid_days = pkc->valid_days = 0; /* fixme: make it configurable*/ skc->pubkey_algo = pkc->pubkey_algo = PUBKEY_ALGO_ELGAMAL; @@ -217,8 +216,8 @@ gen_rsa(unsigned nbits, IOBUF pub_io, IOBUF sec_io, DEK *dek, rsa_generate( &pk, &sk, nbits ); - skc = m_alloc( sizeof *skc ); - pkc = m_alloc( sizeof *pkc ); + skc = m_alloc_clear( sizeof *skc ); + pkc = m_alloc_clear( sizeof *pkc ); skc->timestamp = pkc->timestamp = make_timestamp(); skc->valid_days = pkc->valid_days = 0; /* fixme: make it configurable*/ skc->pubkey_algo = pkc->pubkey_algo = PUBKEY_ALGO_RSA; @@ -297,8 +296,6 @@ generate_keypair() char *pub_fname = NULL; char *sec_fname = NULL; char *uid = NULL; - IOBUF pub_io = NULL; - IOBUF sec_io = NULL; KBNODE pub_root = NULL; KBNODE sec_root = NULL; PKT_secret_cert *skc = NULL; @@ -473,9 +470,14 @@ generate_keypair() p = stpcpy(stpcpy(stpcpy(p," ("), acomment),")"); if( *amail ) p = stpcpy(stpcpy(stpcpy(p," <"), amail),">"); - #ifndef HAVE_DEV_RANDOM - strcpy(p, " (INSECURE!)" ); + + /* append a warning if we do not have dev/random + * or it is switched into quick testmode */ + #ifdef HAVE_DEV_RANDOM + if( quick_random_gen(-1) ) #endif + strcpy(p, " (INSECURE!)" ); + tty_printf("You selected this USER-ID:\n \"%s\"\n\n", uid); for(;;) { @@ -570,7 +572,7 @@ generate_keypair() else if( algo == PUBKEY_ALGO_DSA ) rc = gen_dsa(nbits, pub_root, sec_root, dek, &skc ); else - log_bug(NULL); + BUG(); if( !rc ) write_uid(pub_root, uid ); if( !rc ) diff --git a/g10/keyid.c b/g10/keyid.c index 01604dfe1..5d5a043c5 100644 --- a/g10/keyid.c +++ b/g10/keyid.c @@ -106,7 +106,6 @@ static MD_HANDLE v3_elg_fingerprint_md_skc( PKT_secret_cert *skc ) { PKT_public_cert pkc; - byte *p; pkc.pubkey_algo = skc->pubkey_algo; pkc.timestamp = skc->timestamp; diff --git a/g10/main.h b/g10/main.h index a1a13e41e..273e7a823 100644 --- a/g10/main.h +++ b/g10/main.h @@ -48,7 +48,7 @@ int edit_keysigs( const char *username ); int change_passphrase( const char *username ); /*-- sig-check.c --*/ -int check_key_signature( KBNODE root, KBNODE node ); +int check_key_signature( KBNODE root, KBNODE node, int *is_selfsig ); /*-- keygen.c --*/ void generate_keypair(void); @@ -77,5 +77,8 @@ void g10_elg_sign( PKT_secret_cert *skc, PKT_signature *sig, MD_HANDLE md ); void g10_rsa_encrypt( PKT_public_cert *pkc, PKT_pubkey_enc *enc, DEK *dek ); void g10_rsa_sign( PKT_secret_cert *skc, PKT_signature *sig, MD_HANDLE md ); +/*-- import.c --*/ +int import_pubkeys( const char *filename ); + #endif /*G10_MAIN_H*/ diff --git a/g10/mainproc.c b/g10/mainproc.c index f64a2cda5..36c3381da 100644 --- a/g10/mainproc.c +++ b/g10/mainproc.c @@ -110,7 +110,6 @@ add_secret_cert( CTX c, PACKET *pkt ) static int add_user_id( CTX c, PACKET *pkt ) { - u32 keyid[2]; KBNODE node, n1, n2; if( !c->cert ) { @@ -142,7 +141,6 @@ add_user_id( CTX c, PACKET *pkt ) static int add_signature( CTX c, PACKET *pkt ) { - u32 keyid[2]; KBNODE node, n1, n2; if( !c->cert ) { @@ -329,7 +327,7 @@ do_check_sig( CTX c, KBNODE node ) if( c->cert->pkt->pkt.public_cert->mfx.md ) md = md_copy( c->cert->pkt->pkt.public_cert->mfx.md ); else - log_bug(NULL); + BUG(); md_write( md, n1->pkt->pkt.user_id->name, n1->pkt->pkt.user_id->len); } else { @@ -356,7 +354,7 @@ static void print_userid( PACKET *pkt ) { if( !pkt ) - log_bug(NULL); + BUG(); if( pkt->pkttype != PKT_USER_ID ) { printf("ERROR: unexpected packet type %d", pkt->pkttype ); return; @@ -493,9 +491,7 @@ proc_packets( IOBUF a ) { CTX c = m_alloc_clear( sizeof *c ); PACKET *pkt = m_alloc( sizeof *pkt ); - int rc, result; - int lvl0, lvl1; - u32 keyid[2]; + int rc; int newpkt; c->iobuf = a; diff --git a/g10/packet.h b/g10/packet.h index 6326c43d4..285695213 100644 --- a/g10/packet.h +++ b/g10/packet.h @@ -42,9 +42,8 @@ typedef enum { PKT_PLAINTEXT =11, /* plaintext data with filename and mode */ PKT_RING_TRUST =12, /* keyring trust packet */ PKT_USER_ID =13, /* user id packet */ - PKT_COMMENT =14, /* comment packet */ PKT_PUBKEY_SUBCERT=14, /* subkey certificate (OpenPGP) */ - PKT_NEW_COMMENT =16 /* new comment packet (OpenPGP) */ + PKT_COMMENT =16 /* new comment packet (OpenPGP) */ } pkttype_t; typedef struct packet_struct PACKET; @@ -74,6 +73,7 @@ typedef struct { typedef struct { u32 keyid[2]; /* 64 bit keyid */ + ulong local_id; /* internal use, valid if > 0 */ u32 timestamp; /* signature made */ byte sig_class; /* sig classification, append for MD calculation*/ byte pubkey_algo; /* algorithm used for public key scheme */ @@ -96,9 +96,11 @@ typedef struct { typedef struct { u32 timestamp; /* certificate made */ u16 valid_days; /* valid for this number of days */ + byte hdrbytes; /* number of header bytes */ + byte version; byte pubkey_algo; /* algorithm used for public key scheme */ md_filter_context_t mfx; - u32 local_id; /* internal use, valid if > 0 */ + ulong local_id; /* internal use, valid if > 0 */ union { struct { MPI p; /* prime */ @@ -115,6 +117,8 @@ typedef struct { typedef struct { u32 timestamp; /* certificate made */ u16 valid_days; /* valid for this number of days */ + byte hdrbytes; /* number of header bytes */ + byte version; byte pubkey_algo; /* algorithm used for public key scheme */ union { struct { diff --git a/g10/parse-packet.c b/g10/parse-packet.c index 1d056d8ea..5d967564e 100644 --- a/g10/parse-packet.c +++ b/g10/parse-packet.c @@ -50,6 +50,7 @@ static int parse_certificate( IOBUF inp, int pkttype, unsigned long pktlen, byte *hdr, int hdrlen, PACKET *packet ); static int parse_user_id( IOBUF inp, int pkttype, unsigned long pktlen, PACKET *packet ); +static void parse_subkey( IOBUF inp, int pkttype, unsigned long pktlen ); static void parse_comment( IOBUF inp, int pkttype, unsigned long pktlen ); static void parse_trust( IOBUF inp, int pkttype, unsigned long pktlen ); static int parse_plaintext( IOBUF inp, int pkttype, unsigned long pktlen, @@ -58,7 +59,7 @@ static int parse_compressed( IOBUF inp, int pkttype, unsigned long pktlen, PACKET *packet ); static int parse_encrypted( IOBUF inp, int pkttype, unsigned long pktlen, PACKET *packet ); - +#if 0 static u16 checksum( byte *p ) { @@ -70,6 +71,7 @@ checksum( byte *p ) a += *p++; return a; } +#endif static unsigned short read_16(IOBUF inp) @@ -143,10 +145,11 @@ search_packet( IOBUF inp, PACKET *pkt, int pkttype, ulong *retpos ) static int parse( IOBUF inp, PACKET *pkt, int reqtype, ulong *retpos, int *skip ) { - int rc, ctb, pkttype, lenbytes; + int rc, c, ctb, pkttype, lenbytes; unsigned long pktlen; byte hdr[5]; int hdrlen; + int pgp3 = 0; *skip = 0; assert( !pkt->pkt.generic ); @@ -157,22 +160,49 @@ parse( IOBUF inp, PACKET *pkt, int reqtype, ulong *retpos, int *skip ) hdrlen=0; hdr[hdrlen++] = ctb; if( !(ctb & 0x80) ) { - log_error("invalid packet at '%s'\n", iobuf_where(inp) ); + log_error("%s: invalid packet (ctb=%02x)\n", iobuf_where(inp), ctb ); return G10ERR_INVALID_PACKET; } - /* we handle the pgp 3 extensions here, so that we can skip such packets*/ - pkttype = ctb & 0x40 ? (ctb & 0x3f) : ((ctb>>2)&0xf); - lenbytes = (ctb & 0x40) || ((ctb&3)==3)? 0 : (1<<(ctb & 3)); pktlen = 0; - if( !lenbytes ) { - pktlen = 0; /* don't know the value */ - if( pkttype != PKT_COMPRESSED ) - iobuf_set_block_mode(inp, 1); + pgp3 = !!(ctb & 0x40); + if( pgp3 ) { + pkttype = ctb & 0x3f; + if( (c = iobuf_get(inp)) == -1 ) { + log_error("%s: 1st length byte missing\n", iobuf_where(inp) ); + return G10ERR_INVALID_PACKET; + } + hdr[hdrlen++] = c; + if( c < 192 ) + pktlen = c; + else if( c < 224 ) { + pktlen = (c - 192) * 256; + if( (c = iobuf_get(inp)) == -1 ) { + log_error("%s: 2nd length byte missing\n", iobuf_where(inp) ); + return G10ERR_INVALID_PACKET; + } + hdr[hdrlen++] = c; + pktlen += c + 192; + } + else { /* partial body length */ + pktlen = 1 << (c & 0x1f); + log_debug("partial body length of %lu bytes\n", pktlen ); + iobuf_set_partial_block_mode(inp, pktlen); + pktlen = 0;/* to indicate partial length */ + } } else { - for( ; lenbytes; lenbytes-- ) { - pktlen <<= 8; - pktlen |= hdr[hdrlen++] = iobuf_get_noeof(inp); + pkttype = (ctb>>2)&0xf; + lenbytes = ((ctb&3)==3)? 0 : (1<<(ctb & 3)); + if( !lenbytes ) { + pktlen = 0; /* don't know the value */ + if( pkttype != PKT_COMPRESSED ) + iobuf_set_block_mode(inp, 1); + } + else { + for( ; lenbytes; lenbytes-- ) { + pktlen <<= 8; + pktlen |= hdr[hdrlen++] = iobuf_get_noeof(inp); + } } } @@ -183,10 +213,10 @@ parse( IOBUF inp, PACKET *pkt, int reqtype, ulong *retpos, int *skip ) } if( DBG_PACKET ) - log_debug("parse_packet(iob=%d): type=%d length=%lu\n", - iobuf_id(inp), pkttype, pktlen ); + log_debug("parse_packet(iob=%d): type=%d length=%lu%s\n", + iobuf_id(inp), pkttype, pktlen, pgp3?" (pgp3)":"" ); pkt->pkttype = pkttype; - rc = G10ERR_UNKNOWN_PACKET; /* default to no error */ + rc = G10ERR_UNKNOWN_PACKET; /* default error */ switch( pkttype ) { case PKT_PUBLIC_CERT: pkt->pkt.public_cert = m_alloc_clear(sizeof *pkt->pkt.public_cert ); @@ -211,6 +241,9 @@ parse( IOBUF inp, PACKET *pkt, int reqtype, ulong *retpos, int *skip ) case PKT_USER_ID: rc = parse_user_id(inp, pkttype, pktlen, pkt ); break; + case PKT_PUBKEY_SUBCERT: + parse_subkey(inp, pkttype, pktlen); + break; case PKT_COMMENT: parse_comment(inp, pkttype, pktlen); break; @@ -234,12 +267,43 @@ parse( IOBUF inp, PACKET *pkt, int reqtype, ulong *retpos, int *skip ) return rc; } +static void +dump_hex_line( int c, int *i ) +{ + if( *i && !(*i%8) ) { + if( *i && !(*i%24) ) + printf("\n%4d:", *i ); + else + putchar(' '); + } + if( c == -1 ) + printf(" EOF" ); + else + printf(" %02x", c ); + ++*i; +} + static void skip_packet( IOBUF inp, int pkttype, unsigned long pktlen ) { - if( list_mode ) + if( list_mode ) { printf(":unknown packet: type %2d, length %lu\n", pkttype, pktlen ); + if( pkttype ) { + int c, i=0 ; + printf("dump:"); + if( iobuf_in_block_mode(inp) ) { + while( (c=iobuf_get(inp)) != -1 ) + dump_hex_line(c, &i); + } + else { + for( ; pktlen; pktlen-- ) + dump_hex_line(iobuf_get(inp), &i); + } + putchar('\n'); + return; + } + } skip_rest(inp,pktlen); } @@ -278,7 +342,7 @@ parse_publickey( IOBUF inp, int pkttype, unsigned long pktlen, PACKET *packet ) k->keyid[1] = read_32(inp); pktlen -= 4; k->pubkey_algo = iobuf_get_noeof(inp); pktlen--; if( list_mode ) - printf(":public key packet: keyid %08lX%08lX\n", + printf(":public key encoded packet: keyid %08lX%08lX\n", k->keyid[0], k->keyid[1]); if( k->pubkey_algo == PUBKEY_ALGO_ELGAMAL ) { n = pktlen; @@ -394,7 +458,6 @@ parse_onepass_sig( IOBUF inp, int pkttype, unsigned long pktlen, PKT_onepass_sig *ops ) { int version; - unsigned n; if( pktlen < 13 ) { log_error("packet(%d) too short\n", pkttype); @@ -461,22 +524,27 @@ parse_certificate( IOBUF inp, int pkttype, unsigned long pktlen, timestamp = read_32(inp); pktlen -= 4; if( is_v4 ) valid_period = 0; - else + else { valid_period = read_16(inp); pktlen -= 2; + } algorithm = iobuf_get_noeof(inp); pktlen--; if( list_mode ) - printf(":%s key certification packet:\n" + printf(":%s key packet:\n" "\tversion %d, created %lu, valid for %hu days\n", pkttype == PKT_PUBLIC_CERT? "public": "secret", version, timestamp, valid_period ); if( pkttype == PKT_SECRET_CERT ) { pkt->pkt.secret_cert->timestamp = timestamp; pkt->pkt.secret_cert->valid_days = valid_period; + pkt->pkt.secret_cert->hdrbytes = hdrlen; + pkt->pkt.secret_cert->version = version; pkt->pkt.secret_cert->pubkey_algo = algorithm; } else { pkt->pkt.public_cert->timestamp = timestamp; pkt->pkt.public_cert->valid_days = valid_period; + pkt->pkt.public_cert->hdrbytes = hdrlen; + pkt->pkt.public_cert->version = version; pkt->pkt.public_cert->pubkey_algo = algorithm; } @@ -486,7 +554,7 @@ parse_certificate( IOBUF inp, int pkttype, unsigned long pktlen, n = pktlen; elg_g = mpi_read(inp, &n, 0 ); pktlen -=n; n = pktlen; elg_y = mpi_read(inp, &n, 0 ); pktlen -=n; if( list_mode ) { - printf( "\telg p: "); + printf( "\telg p: "); mpi_print(stdout, elg_p, mpi_print_mode ); printf("\n\telg g: "); mpi_print(stdout, elg_g, mpi_print_mode ); @@ -502,7 +570,6 @@ parse_certificate( IOBUF inp, int pkttype, unsigned long pktlen, else { PKT_secret_cert *cert = pkt->pkt.secret_cert; byte temp[8]; - byte *mpibuf; pkt->pkt.secret_cert->d.elg.p = elg_p; pkt->pkt.secret_cert->d.elg.g = elg_g; @@ -558,7 +625,6 @@ parse_certificate( IOBUF inp, int pkttype, unsigned long pktlen, else { PKT_secret_cert *cert = pkt->pkt.secret_cert; byte temp[8]; - byte *mpibuf; pkt->pkt.secret_cert->d.rsa.rsa_n = rsa_pub_mod; pkt->pkt.secret_cert->d.rsa.rsa_e = rsa_pub_exp; @@ -636,6 +702,39 @@ parse_user_id( IOBUF inp, int pkttype, unsigned long pktlen, PACKET *packet ) return 0; } + +static void +parse_subkey( IOBUF inp, int pkttype, unsigned long pktlen ) +{ + int version; + + version = iobuf_get_noeof(inp); pktlen--; + if( pkttype == PKT_PUBKEY_SUBCERT && version == '#' ) { + /* early versions of G10 use old comments packets; luckily all those + * comments are are started by a hash */ + if( list_mode ) { + printf(":old comment packet: \"" ); + for( ; pktlen; pktlen-- ) { + int c; + c = iobuf_get_noeof(inp); + if( c >= ' ' && c <= 'z' ) + putchar(c); + else + printf("\\x%02x", c ); + } + printf("\"\n"); + } + skip_rest(inp, pktlen); + return; + } + + if( list_mode ) + printf(":public subkey packet: \"" ); + skip_rest(inp, pktlen); +} + + + static void parse_comment( IOBUF inp, int pkttype, unsigned long pktlen ) { @@ -749,7 +848,6 @@ static int parse_compressed( IOBUF inp, int pkttype, unsigned long pktlen, PACKET *pkt ) { PKT_compressed *zd; - int algorithm; /* pktlen is here 0, but data follows * (this should be the last object in a file or diff --git a/g10/passphrase.c b/g10/passphrase.c index 462c7c752..d1b91465e 100644 --- a/g10/passphrase.c +++ b/g10/passphrase.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include "util.h" #include "memory.h" diff --git a/g10/pkclist.c b/g10/pkclist.c index 3fd22549c..7feea8a00 100644 --- a/g10/pkclist.c +++ b/g10/pkclist.c @@ -56,7 +56,7 @@ do_we_trust( PKT_public_cert *pkc, int trustlevel ) log_fatal("trust check after insert failed: %s\n", g10_errstr(rc) ); if( trustlevel & TRUST_NO_PUBKEY ) - log_bug(NULL); + BUG(); } @@ -84,7 +84,6 @@ int build_pkc_list( STRLIST remusr, PKC_LIST *ret_pkc_list ) { PKC_LIST pkc_list = NULL; - PKC_LIST pkc_rover = NULL; int rc; if( !remusr ) { /* ask!!! */ diff --git a/g10/ringedit.c b/g10/ringedit.c index 8b7431961..ad5706c1e 100644 --- a/g10/ringedit.c +++ b/g10/ringedit.c @@ -68,7 +68,12 @@ typedef struct resource_table_struct RESTBL; static RESTBL resource_table[MAX_RESOURCES]; +static int search( PACKET *pkt, KBPOS *kbpos, int secret ); + + static int keyring_search( PACKET *pkt, KBPOS *kbpos, IOBUF iobuf ); +static int keyring_search2( PUBKEY_FIND_INFO info, KBPOS *kbpos, + const char *fname); static int keyring_read( KBPOS *kbpos, KBNODE *ret_root ); static int keyring_insert( KBPOS *kbpos, KBNODE root ); static int keyring_delete( KBPOS *kbpos ); @@ -138,6 +143,37 @@ get_keyblock_handle( const char *filename, int secret, KBPOS *kbpos ) return -1; /* not found */ } + +/**************** + * Find a keyblock from the informations provided in INFO + * This can only be used fro public keys + */ +int +find_keyblock( PUBKEY_FIND_INFO info, KBPOS *kbpos ) +{ + int i, rc, last_rc=-1; + + for(i=0; i < MAX_RESOURCES; i++ ) { + if( resource_table[i].used && !resource_table[i].secret ) { + /* note: here we have to add different search functions, + * depending on the type of the resource */ + rc = keyring_search2( info, kbpos, resource_table[i].fname ); + if( !rc ) { + kbpos->resno = i; + return 0; + } + if( rc != -1 ) { + log_error("error searching resource %d: %s\n", + i, g10_errstr(rc)); + last_rc = rc; + } + } + } + return last_rc; +} + + + /**************** * Search a keyblock which starts with the given packet and put all * informations into KBPOS, which can be used later to access this key block. @@ -149,8 +185,8 @@ get_keyblock_handle( const char *filename, int secret, KBPOS *kbpos ) * * Returns: 0 if found, -1 if not found or an errorcode. */ -int -search_keyblock( PACKET *pkt, KBPOS *kbpos, int secret ) +static int +search( PACKET *pkt, KBPOS *kbpos, int secret ) { int i, rc, last_rc=-1; @@ -179,7 +215,7 @@ search_keyblock( PACKET *pkt, KBPOS *kbpos, int secret ) * of the keyblock. */ int -search_keyblock_byname( KBPOS *kbpos, const char *username ) +find_keyblock_byname( KBPOS *kbpos, const char *username ) { PACKET pkt; PKT_public_cert *pkc = m_alloc_clear( sizeof *pkc ); @@ -194,7 +230,7 @@ search_keyblock_byname( KBPOS *kbpos, const char *username ) init_packet( &pkt ); pkt.pkttype = PKT_PUBLIC_CERT; pkt.pkt.public_cert = pkc; - rc = search_keyblock( &pkt, kbpos, 0 ); + rc = search( &pkt, kbpos, 0 ); free_public_cert(pkc); return rc; } @@ -204,7 +240,7 @@ search_keyblock_byname( KBPOS *kbpos, const char *username ) * of the keyblock. This function does not unprotect the secret key. */ int -search_secret_keyblock_byname( KBPOS *kbpos, const char *username ) +find_secret_keyblock_byname( KBPOS *kbpos, const char *username ) { PACKET pkt; PKT_secret_cert *skc = m_alloc_clear( sizeof *skc ); @@ -219,7 +255,7 @@ search_secret_keyblock_byname( KBPOS *kbpos, const char *username ) init_packet( &pkt ); pkt.pkttype = PKT_SECRET_CERT; pkt.pkt.secret_cert = skc; - rc = search_keyblock( &pkt, kbpos, 1 ); + rc = search( &pkt, kbpos, 1 ); free_secret_cert(skc); return rc; } @@ -229,13 +265,11 @@ search_secret_keyblock_byname( KBPOS *kbpos, const char *username ) * Lock the keyblock; wait until it's available * This function may change the internal data in kbpos, in cases * when the to be locked keyblock has been modified. - * fixme: remove this function and add an option to search_keyblock()? + * fixme: remove this function and add an option to search()? */ int lock_keyblock( KBPOS *kbpos ) { - int rc; - if( !check_pos(kbpos) ) return G10ERR_GENERAL; return 0; @@ -248,7 +282,7 @@ void unlock_keyblock( KBPOS *kbpos ) { if( !check_pos(kbpos) ) - log_bug(NULL); + BUG(); } /**************** @@ -389,7 +423,7 @@ keyring_search( PACKET *req, KBPOS *kbpos, IOBUF iobuf ) break; /* found */ } else - log_bug(NULL); + BUG(); free_packet(&pkt); } if( !rc ) @@ -401,6 +435,68 @@ keyring_search( PACKET *req, KBPOS *kbpos, IOBUF iobuf ) return rc; } +/**************** + * search one keyring, return 0 if found, -1 if not found or an errorcode. + * this version uses the finger print and other informations + */ +static int +keyring_search2( PUBKEY_FIND_INFO info, KBPOS *kbpos, const char *fname ) +{ + int rc; + PACKET pkt; + int save_mode; + ulong offset; + IOBUF iobuf; + + init_packet(&pkt); + save_mode = set_packet_list_mode(0); + + #if 0 + if( iobuf_seek( iobuf, 0 ) ) { + log_error("can't rewind keyring file: %s\n", g10_errstr(rc)); + rc = G10ERR_KEYRING_OPEN; + goto leave; + } + #else + iobuf = iobuf_open( fname ); + if( !iobuf ) { + log_error("can't open '%s'\n", fname ); + rc = G10ERR_OPEN_FILE; + goto leave; + } + #endif + + while( !(rc=search_packet(iobuf, &pkt, PKT_PUBLIC_CERT, &offset)) ) { + PKT_public_cert *pkc = pkt.pkt.public_cert; + u32 keyid[2]; + + assert( pkt.pkttype == PKT_PUBLIC_CERT ); + keyid_from_pkc( pkc, keyid ); + if( keyid[0] == info->keyid[0] && keyid[1] == info->keyid[1] + && pkc->pubkey_algo == info->pubkey_algo ) { + /* fixme: shall we check nbits too? (good for rsa keys) */ + /* fixme: check userid???? */ + size_t len; + byte *fp = fingerprint_from_pkc( pkc, &len ); + + if( !memcmp( fp, info->fingerprint, len ) ) { + m_free(fp); + break; /* found */ + } + m_free(fp); + } + free_packet(&pkt); + } + if( !rc ) + kbpos->offset = offset; + + leave: + iobuf_close(iobuf); + free_packet(&pkt); + set_packet_list_mode(save_mode); + return rc; +} + static int keyring_read( KBPOS *kbpos, KBNODE *ret_root ) @@ -562,7 +658,6 @@ keyring_delete( KBPOS *kbpos ) { RESTBL *rentry; IOBUF fp; - KBNODE kbctx, node; int rc; u32 len; int ctb; @@ -588,7 +683,7 @@ keyring_delete( KBPOS *kbpos ) /*log_debug("writing a dummy packet of length %lu\n", (ulong)len);*/ if( len < 2 ) - log_bug(NULL); + BUG(); if( len < 256 ) { ctb = 0x80; diff --git a/g10/seckey-cert.c b/g10/seckey-cert.c index 7f76b31e8..ab1034051 100644 --- a/g10/seckey-cert.c +++ b/g10/seckey-cert.c @@ -60,7 +60,7 @@ static int check_elg( PKT_secret_cert *cert ) { byte *buffer; - u16 n, csum=0; + u16 csum=0; int res; unsigned nbytes; u32 keyid[2]; @@ -73,7 +73,7 @@ check_elg( PKT_secret_cert *cert ) BLOWFISH_context *blowfish_ctx=NULL; switch( cert->d.elg.protect_algo ) { - case CIPHER_ALGO_NONE: log_bug(NULL); break; + case CIPHER_ALGO_NONE: BUG(); break; case CIPHER_ALGO_BLOWFISH: keyid_from_skc( cert, keyid ); dek = get_passphrase_hash( keyid, NULL ); @@ -142,7 +142,7 @@ protect_elg( PKT_secret_cert *cert, DEK *dek ) BLOWFISH_context *blowfish_ctx=NULL; switch( cert->d.elg.protect_algo ) { - case CIPHER_ALGO_NONE: log_bug(NULL); break; + case CIPHER_ALGO_NONE: BUG(); break; case CIPHER_ALGO_BLOWFISH: blowfish_ctx = m_alloc_secure( sizeof *blowfish_ctx ); blowfish_setkey( blowfish_ctx, dek->key, dek->keylen ); @@ -171,7 +171,7 @@ static int check_rsa( PKT_secret_cert *cert ) { byte *buffer; - u16 n, csum=0; + u16 csum=0; int res; unsigned nbytes; u32 keyid[2]; @@ -183,7 +183,7 @@ check_rsa( PKT_secret_cert *cert ) switch( cert->d.rsa.protect_algo ) { /* FIXME: use test variables to check for the correct key */ - case CIPHER_ALGO_NONE: log_bug(NULL); break; + case CIPHER_ALGO_NONE: BUG(); break; case CIPHER_ALGO_BLOWFISH: keyid_from_skc( cert, keyid ); dek = get_passphrase_hash( keyid, NULL ); diff --git a/g10/seskey.c b/g10/seskey.c index c99bed598..63e7b28f1 100644 --- a/g10/seskey.c +++ b/g10/seskey.c @@ -46,7 +46,7 @@ make_session_key( DEK *dek ) randomize_buffer( dek->key, dek->keylen, 1 ); break; - default: log_bug("invalid algo %d in make_session_key()\n"); + default: log_bug("invalid algo %d in make_session_key()\n", dek->algo); } } @@ -116,9 +116,8 @@ encode_rmd160_value( byte *md, unsigned len, unsigned nbits ) { 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x24, 0x03, 0x02, 0x01, 0x05, 0x00, 0x04, 0x14 }; int nframe = (nbits+7) / 8; - byte *p; MPI frame; - int i,n,c; + int i,n; if( (nbits % BITS_PER_MPI_LIMB) || nframe < 42 || len != 20 ) log_bug("can't encode a %d bit MD into a %d bits frame\n",len*8, nbits); @@ -156,9 +155,8 @@ encode_sha1_value( byte *md, unsigned len, unsigned nbits ) { 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x05, 0x00, 0x04, 0x14 }; int nframe = (nbits+7) / 8; - byte *p; MPI frame; - int i,n,c; + int i,n; if( (nbits % BITS_PER_MPI_LIMB) || nframe < 42 || len != 20 ) log_bug("can't encode a %d bit MD into a %d bits frame\n",len*8, nbits); @@ -197,9 +195,8 @@ encode_md5_value( byte *md, unsigned len, unsigned nbits ) { 0x30, 0x20, 0x30, 0x0c, 0x06, 0x08, 0x2a, 0x86,0x48, 0x86, 0xf7, 0x0d, 0x02, 0x05, 0x05, 0x00, 0x04, 0x10 }; int nframe = (nbits+7) / 8; - byte *p; MPI frame; - int i,n,c; + int i,n; if( (nbits % BITS_PER_MPI_LIMB) || nframe < 38 || len != 16 ) log_bug("can't encode a %d bit MD into a %d bits frame\n",len*8, nbits); @@ -236,7 +233,7 @@ encode_md_value( MD_HANDLE md, unsigned nbits ) case DIGEST_ALGO_SHA1: return encode_sha1_value( md_read(md, DIGEST_ALGO_SHA1), 20, nbits ); default: - log_bug(NULL); + BUG(); } } diff --git a/g10/sig-check.c b/g10/sig-check.c index 74517507e..54ccae951 100644 --- a/g10/sig-check.c +++ b/g10/sig-check.c @@ -143,7 +143,7 @@ signature_check( PKT_signature *sig, MD_HANDLE digest ) md_putc( digest, a & 0xff ); } md_final( digest ); - dp = md_read( digest, 0 ); + dp = md_read( digest, DIGEST_ALGO_RMD160 ); for(i=19; i >= 0; i--, dp++ ) if( mpi_getbyte( result, i ) != *dp ) { rc = G10ERR_BAD_SIGN; @@ -187,7 +187,7 @@ signature_check( PKT_signature *sig, MD_HANDLE digest ) md_putc( digest, a & 0xff ); } md_final( digest ); - dp = md_read( digest, 0 ); + dp = md_read( digest, DIGEST_ALGO_MD5 ); for(i=15; i >= 0; i--, dp++ ) if( mpi_getbyte( result, i ) != *dp ) { rc = G10ERR_BAD_SIGN; @@ -220,7 +220,7 @@ signature_check( PKT_signature *sig, MD_HANDLE digest ) * check the signature pointed to by NODE. This is a key signatures */ int -check_key_signature( KBNODE root, KBNODE node ) +check_key_signature( KBNODE root, KBNODE node, int *is_selfsig ) { KBNODE unode; MD_HANDLE md; @@ -229,6 +229,8 @@ check_key_signature( KBNODE root, KBNODE node ) int algo; int rc; + if( is_selfsig ) + *is_selfsig = 0; assert( node->pkt->pkttype == PKT_SIGNATURE ); assert( (node->pkt->pkt.signature->sig_class&~3) == 0x10 ); assert( root->pkt->pkttype == PKT_PUBLIC_CERT ); @@ -250,6 +252,13 @@ check_key_signature( KBNODE root, KBNODE node ) if( unode && unode->pkt->pkttype == PKT_USER_ID ) { PKT_user_id *uid = unode->pkt->pkt.user_id; + if( is_selfsig ) { + u32 keyid[2]; + + keyid_from_pkc( pkc, keyid ); + if( keyid[0] == sig->keyid[0] && keyid[1] == sig->keyid[1] ) + *is_selfsig = 1; + } md = md_open( algo, 0 ); hash_public_cert( md, pkc ); md_write( md, uid->name, uid->len ); diff --git a/g10/sign.c b/g10/sign.c index 9e8275ae9..247b30edd 100644 --- a/g10/sign.c +++ b/g10/sign.c @@ -52,7 +52,7 @@ complete_sig( PKT_signature *sig, PKT_secret_cert *skc, MD_HANDLE md ) else if( sig->pubkey_algo == PUBKEY_ALGO_RSA ) g10_rsa_sign( skc, sig, md ); else - log_bug(NULL); + BUG(); /* fixme: should we check wether the signature is okay? */ @@ -89,7 +89,7 @@ sign_file( STRLIST filenames, int detached, STRLIST locusr, PACKET pkt; PKT_plaintext *pt = NULL; u32 filesize; - int last_rc, rc = 0; + int rc = 0; PKC_LIST pkc_list = NULL; SKC_LIST skc_list = NULL; SKC_LIST skc_rover = NULL; @@ -318,7 +318,7 @@ sign_file( STRLIST filenames, int detached, STRLIST locusr, } #endif/*HAVE_RSA_CIPHER*/ else - log_bug(NULL); + BUG(); md_close( md ); @@ -428,7 +428,7 @@ check_all_keysigs( KBNODE keyblock ) int sigrc; tty_printf("sig"); - switch( (rc = check_key_signature( keyblock, node )) ) { + switch( (rc = check_key_signature( keyblock, node,NULL)) ) { case 0: node->flag = 0; sigrc = '!'; break; case G10ERR_BAD_SIGN: inv_sigs++; node->flag = 1; sigrc = '-'; break; case G10ERR_NO_PUBKEY: no_key++; node->flag = 2; sigrc = '?'; break; @@ -478,7 +478,6 @@ remove_keysigs( KBNODE keyblock, int all ) && node->pkt->pkttype == PKT_SIGNATURE && (node->pkt->pkt.signature->sig_class&~3) == 0x10 ) { PKT_signature *sig = node->pkt->pkt.signature; - int sigrc; if( all ) { /* fixme: skip self-sig */ @@ -546,14 +545,13 @@ sign_key( const char *username, STRLIST locusr ) KBNODE kbctx, node; KBPOS kbpos; PKT_public_cert *pkc; - int any; u32 pkc_keyid[2]; char *answer; memset( &mfx, 0, sizeof mfx); /* search the userid */ - rc = search_keyblock_byname( &kbpos, username ); + rc = find_keyblock_byname( &kbpos, username ); if( rc ) { log_error("user '%s' not found\n", username ); goto leave; @@ -687,12 +685,10 @@ edit_keysigs( const char *username ) KBNODE kbctx, node; KBPOS kbpos; PKT_public_cert *pkc; - int any; u32 pkc_keyid[2]; - char *answer; /* search the userid */ - rc = search_keyblock_byname( &kbpos, username ); + rc = find_keyblock_byname( &kbpos, username ); if( rc ) { log_error("user '%s' not found\n", username ); goto leave; @@ -755,13 +751,12 @@ change_passphrase( const char *username ) KBNODE kbctx, node; KBPOS kbpos; PKT_secret_cert *skc; - int any; u32 skc_keyid[2]; char *answer; int changed=0; /* search the userid */ - rc = search_secret_keyblock_byname( &kbpos, username ); + rc = find_secret_keyblock_byname( &kbpos, username ); if( rc ) { log_error("secret key for user '%s' not found\n", username ); goto leave; diff --git a/g10/skclist.c b/g10/skclist.c index e7c9071d6..f906fc6af 100644 --- a/g10/skclist.c +++ b/g10/skclist.c @@ -49,7 +49,6 @@ int build_skc_list( STRLIST locusr, SKC_LIST *ret_skc_list, int unlock ) { SKC_LIST skc_list = NULL; - SKC_LIST skc_rover = NULL; int rc; if( !locusr ) { /* use the default one */ diff --git a/g10/trustdb.c b/g10/trustdb.c index 092e98f61..9f5bef7a1 100644 --- a/g10/trustdb.c +++ b/g10/trustdb.c @@ -34,10 +34,13 @@ #include "util.h" #include "trustdb.h" #include "options.h" +#include "packet.h" +#include "main.h" #define TRUST_RECORD_LEN 40 #define SIGS_PER_RECORD ((TRUST_RECORD_LEN-10)/5) +#define MAX_LIST_SIGS_DEPTH 20 struct trust_record { byte rectype; @@ -47,27 +50,27 @@ struct trust_record { byte magic[2]; byte version; /* should be 1 */ byte reserved[3]; - u32 locked; /* pid of process which holds a lock */ - u32 created; /* timestamp of trustdb creation */ - u32 modified; /* timestamp of last modification */ - u32 validated; /* timestamp of last validation */ - u32 local_id_counter; + ulong locked; /* pid of process which holds a lock */ + ulong created; /* timestamp of trustdb creation */ + ulong modified; /* timestamp of last modification */ + ulong validated; /* timestamp of last validation */ + ulong local_id_counter; byte marginals_needed; byte completes_needed; byte max_cert_depth; } version; struct { /* public key record */ - u32 local_id; - u32 keyid[2]; - byte algo; + ulong local_id; + u32 keyid[2]; + byte pubkey_algo; byte reserved; byte fingerprint[20]; byte ownertrust; /* fixme: indicate a flag to */ } pubkey; struct { /* cache record */ - u32 owner; - u32 keyid[2]; /* needed?? */ + ulong owner; + u32 keyid[2]; /* needed?? */ byte valid; byte reserved; byte blockhash[20]; @@ -77,10 +80,10 @@ struct trust_record { byte trustlevel; } cache; struct { - u32 owner; /* local_id of record owner (pubkey record) */ - u32 chain; /* offset of next record or NULL for last one */ + ulong owner; /* local_id of record owner (pubkey record) */ + ulong chain; /* offset of next record or NULL for last one */ struct { - u32 local_id; /* of pubkey record of signator (0=unused) */ + ulong local_id; /* of pubkey record of signator (0=unused) */ byte flag; /* reserved */ } sig[SIGS_PER_RECORD]; } sigrec; @@ -88,29 +91,67 @@ struct trust_record { }; typedef struct trust_record TRUSTREC; +typedef struct { + ulong pubkey_id; /* localid of the pubkey */ + ulong sig_id; /* returned signature id */ + unsigned sig_flag; /* returned signaure record flag */ + struct { /* internal data */ + int eof; + TRUSTREC rec; + int index; + } ctl; +} SIGREC_CONTEXT; + +typedef struct local_id_info *LOCAL_ID_INFO; +struct local_id_info { + LOCAL_ID_INFO next; + ulong lid; + unsigned flag; +}; + + static void create_db( const char *fname ); static void open_db(void); -static int read_record( u32 recnum, TRUSTREC *rec ); -static u32 new_local_id(void); +static int read_record( ulong recnum, TRUSTREC *rec ); +static int write_record( ulong recnum, TRUSTREC *rec ); +static ulong new_recnum(void); +static void dump_record( ulong rnum, TRUSTREC *rec, FILE *fp ); +static int walk_sigrecs( SIGREC_CONTEXT *c ); + +static LOCAL_ID_INFO *new_lid_table(void); +static void release_lid_table( LOCAL_ID_INFO *tbl ); +static int get_lid_table_flag( LOCAL_ID_INFO *tbl, ulong lid, unsigned *flag ); + +static void print_user_id( const char *text, u32 *keyid ); +static int do_list_path( ulong pubkey, int depth, int max_depth, + LOCAL_ID_INFO *lids, ulong *stack ); + +static int list_sigs( ulong pubkey_id ); + static char *db_name; static int db_fd = -1; static int no_io_dbg = 0; +/* a table used to keep track of ultimately trusted keys + * which are the ones from our secrings */ +static LOCAL_ID_INFO *ultikey_table; -#define buftou32( p ) ((*(byte*)(p) << 24) | (*((byte*)(p)+1)<< 16) | \ +#define buftoulong( p ) ((*(byte*)(p) << 24) | (*((byte*)(p)+1)<< 16) | \ (*((byte*)(p)+2) << 8) | (*((byte*)(p)+3))) -#define buftou16( p ) ((*((byte*)(p)) << 8) | (*((byte*)(p)+1))) -#define u32tobuf( p, a ) do { \ +#define buftoushort( p ) ((*((byte*)(p)) << 8) | (*((byte*)(p)+1))) +#define ulongtobuf( p, a ) do { \ ((byte*)p)[0] = a >> 24; \ ((byte*)p)[1] = a >> 16; \ ((byte*)p)[2] = a >> 8; \ ((byte*)p)[3] = a ; \ } while(0) -#define u16tobuf( p, a ) do { \ +#define ushorttobuf( p, a ) do { \ ((byte*)p)[0] = a >> 8; \ ((byte*)p)[1] = a ; \ } while(0) +#define buftou32( p) buftoulong( (p) ) +#define u32tobuf( p, a) ulongtobuf( (p), (a) ) /************************************************** @@ -124,25 +165,18 @@ fwrite_8(FILE *fp, byte a) log_fatal("error writing byte to trustdb: %s\n", strerror(errno) ); } -static void -fwrite_16(FILE *fp, u16 a) -{ - putc( (a>>8) & 0x0ff , fp ); - if( putc( a & 0xff, fp ) == EOF ) - log_fatal("error writing u16 to trustdb: %s\n", strerror(errno) ); -} -static int -fwrite_32( FILE*fp, u32 a) +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 u32 to trustdb: %s\n", strerror(errno) ); + log_fatal("error writing ulong to trustdb: %s\n", strerror(errno) ); } -static int +static void fwrite_zeros( FILE *fp, size_t n) { while( n-- ) @@ -163,8 +197,6 @@ static void create_db( const char *fname ) { FILE *fp; - u32 along; - u16 ashort; fp =fopen( fname, "w" ); if( !fp ) @@ -207,7 +239,7 @@ open_db() * returns: -1 on error, 0 on success */ static int -read_record( u32 recnum, TRUSTREC *rec ) +read_record( ulong recnum, TRUSTREC *rec ) { byte buf[TRUST_RECORD_LEN], *p; int rc = 0; @@ -242,11 +274,11 @@ read_record( u32 recnum, TRUSTREC *rec ) rec->r.version.magic[1] = *p++; rec->r.version.version = *p++; memcpy( rec->r.version.reserved, p, 3); p += 3; - rec->r.version.locked = buftou32(p); p += 4; - rec->r.version.created = buftou32(p); p += 4; - rec->r.version.modified = buftou32(p); p += 4; - rec->r.version.validated= buftou32(p); p += 4; - rec->r.version.local_id_counter = buftou32(p); p += 4; + rec->r.version.locked = buftoulong(p); p += 4; + rec->r.version.created = buftoulong(p); p += 4; + rec->r.version.modified = buftoulong(p); p += 4; + rec->r.version.validated= buftoulong(p); p += 4; + rec->r.version.local_id_counter = buftoulong(p); p += 4; rec->r.version.marginals_needed = *p++; rec->r.version.completes_needed = *p++; rec->r.version.max_cert_depth = *p++; @@ -267,10 +299,10 @@ read_record( u32 recnum, TRUSTREC *rec ) } break; case 2: - rec->r.pubkey.local_id = buftou32(p); p += 4; + rec->r.pubkey.local_id = buftoulong(p); p += 4; rec->r.pubkey.keyid[0] = buftou32(p); p += 4; rec->r.pubkey.keyid[1] = buftou32(p); p += 4; - rec->r.pubkey.algo = *p++; + rec->r.pubkey.pubkey_algo = *p++; rec->r.pubkey.reserved = *p++; memcpy( rec->r.pubkey.fingerprint, p, 20); p += 20; rec->r.pubkey.ownertrust = *p++; @@ -283,7 +315,7 @@ read_record( u32 recnum, TRUSTREC *rec ) } break; case 3: - rec->r.cache.local_id = buftou32(p); p += 4; + rec->r.cache.owner = buftoulong(p); p += 4; rec->r.cache.keyid[0] = buftou32(p); p += 4; rec->r.cache.keyid[1] = buftou32(p); p += 4; rec->r.cache.valid = *p++; @@ -296,10 +328,10 @@ read_record( u32 recnum, TRUSTREC *rec ) break; case 4: case 5: - rec->r.sigrec.owner = buftou32(p); p += 4; - rec->r.sigrec.chain = buftou32(p); p += 4; + rec->r.sigrec.owner = buftoulong(p); p += 4; + rec->r.sigrec.chain = buftoulong(p); p += 4; for(i=0; i < SIGS_PER_RECORD; i++ ) { - rec->r.sigrec.sig[i].local_id = buftou32(p); p += 4; + rec->r.sigrec.sig[i].local_id = buftoulong(p); p += 4; rec->r.sigrec.sig[i].flag = *p++; } break; @@ -309,7 +341,10 @@ read_record( u32 recnum, TRUSTREC *rec ) rc = G10ERR_TRUSTDB; break; } - + if( DBG_TRUST && !rc && !no_io_dbg ) { + log_debug("trustdb: "); + dump_record( recnum, rec, stderr); + } return rc; } @@ -318,7 +353,7 @@ read_record( u32 recnum, TRUSTREC *rec ) * Write the record at RECNUM */ static int -write_record( u32 recnum, TRUSTREC *rec ) +write_record( ulong recnum, TRUSTREC *rec ) { byte buf[TRUST_RECORD_LEN], *p; int rc = 0; @@ -337,20 +372,20 @@ write_record( u32 recnum, TRUSTREC *rec ) case 0: /* unused record */ break; case 1: /* version record */ - log_bug(NULL); + BUG(); break; case 2: - u32tobuf(p, rec->r.pubkey.local_id); p += 4; + ulongtobuf(p, rec->r.pubkey.local_id); p += 4; u32tobuf(p, rec->r.pubkey.keyid[0]); p += 4; u32tobuf(p, rec->r.pubkey.keyid[1]); p += 4; - *p++ = rec->r.pubkey.algo; + *p++ = rec->r.pubkey.pubkey_algo; *p++ = rec->r.pubkey.reserved; memcpy( p, rec->r.pubkey.fingerprint, 20); p += 20; *p++ = rec->r.pubkey.ownertrust; assert( rec->r.pubkey.local_id == recnum ); break; case 3: - u32tobuf(p, rec->r.cache.local_id); p += 4; + ulongtobuf(p, rec->r.cache.owner); p += 4; u32tobuf(p, rec->r.cache.keyid[0]); p += 4; u32tobuf(p, rec->r.cache.keyid[1]); p += 4; *p++ = rec->r.cache.valid; @@ -363,15 +398,15 @@ write_record( u32 recnum, TRUSTREC *rec ) break; case 4: case 5: - u32tobuf(p, rec->r.sigrec.owner); p += 4; - u32tobuf(p, rec->r.sigrec.chain); p += 4; + ulongtobuf(p, rec->r.sigrec.owner); p += 4; + ulongtobuf(p, rec->r.sigrec.chain); p += 4; for(i=0; i < SIGS_PER_RECORD; i++ ) { - u32tobuf(p, rec->r.sigrec.sig[i].local_id); p += 4; + ulongtobuf(p, rec->r.sigrec.sig[i].local_id); p += 4; *p++ = rec->r.sigrec.sig[i].flag; } break; default: - log_bug(NULL); + BUG(); } if( lseek( db_fd, recnum * TRUST_RECORD_LEN, SEEK_SET ) == -1 ) { @@ -387,11 +422,18 @@ write_record( u32 recnum, TRUSTREC *rec ) return rc; } -static u32 -new_local_id() + + +/**************** + * create a new record and return its record number + */ +static ulong +new_recnum() { off_t offset; - u32 recnum; + ulong recnum; + TRUSTREC rec; + int rc; /* fixme: look for unused records */ offset = lseek( db_fd, 0, SEEK_END ); @@ -399,6 +441,15 @@ new_local_id() 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 */ + + /* we must write a record, so that the next call to this function + * returns another recnum */ + memset( &rec, 0, sizeof rec ); + rec.rectype = 0; /* free record */ + rc = write_record(recnum, &rec ); + if( rc ) + log_fatal("%s: failed to append a record: %s\n", + db_name, g10_errstr(rc)); return recnum ; } @@ -409,11 +460,10 @@ new_local_id() static int scan_record_by_pkc( PKT_public_cert *pkc, TRUSTREC *rec, int rectype ) { - u32 recnum; + ulong recnum; u32 keyid[2]; byte *fingerprint; size_t fingerlen; - int dbg = DBG_TRUST; int rc; assert( rectype == 2 || rectype == 3 ); @@ -431,7 +481,7 @@ scan_record_by_pkc( PKT_public_cert *pkc, TRUSTREC *rec, int rectype ) if( rec->rectype == 2 ) { if( rec->r.pubkey.keyid[0] == keyid[0] && rec->r.pubkey.keyid[1] == keyid[1] - && rec->r.pubkey.algo == pkc->pubkey_algo + && rec->r.pubkey.pubkey_algo == pkc->pubkey_algo && !memcmp(rec->r.pubkey.fingerprint, fingerprint, fingerlen) ) { /* found */ /* store the local_id */ @@ -460,11 +510,9 @@ scan_record_by_pkc( PKT_public_cert *pkc, TRUSTREC *rec, int rectype ) * with LOCAL_ID */ static int -scan_record( u32 local_id, TRUSTREC *rec, int rectype, u32 *r_recnum ) +scan_record( ulong local_id, TRUSTREC *rec, int rectype, ulong *r_recnum ) { - u32 recnum; - u32 keyid[2]; - int dbg = DBG_TRUST; + ulong recnum; int rc; assert( rectype == 3 || rectype == 4 ); @@ -502,11 +550,292 @@ scan_record( u32 local_id, TRUSTREC *rec, int rectype, u32 *r_recnum ) } +static void +dump_record( ulong rnum, TRUSTREC *rec, FILE *fp ) +{ + int i, any; + + fprintf(fp, "trust record %lu, type=", rnum ); + + switch( rec->rectype ) { + case 0: fprintf(fp, "free\n"); + break; + case 1: fprintf(fp, "version\n"); + break; + case 2: fprintf(fp, "pubkey, keyid=%08lX, ownertrust=%02x\n", + rec->r.pubkey.keyid[1], rec->r.pubkey.ownertrust ); + break; + case 3: fprintf(fp, "cache\n"); + case 4: + case 5: + fprintf(fp, "sigrec, owner=%lu, chain=%lu%s\n", + rec->r.sigrec.owner, rec->r.sigrec.chain, + rec->rectype == 4?"":" (extend)"); + for(i=any=0; i < SIGS_PER_RECORD; i++ ) { + if( rec->r.sigrec.sig[i].local_id ) { + if( !any ) { + putc('\t', fp); + any++; + } + fprintf(fp, " %lu:%02x", rec->r.sigrec.sig[i].local_id, + rec->r.sigrec.sig[i].flag ); + } + } + if( any ) + putc('\n', fp); + break; + default: + fprintf(fp, "%d (unknown)\n", rec->rectype ); + break; + } +} + + +/**************** + * If we do not have a local_id in a signature packet, find the owner of + * the signature packet in our trustdb or insert him into the trustdb + */ +static int +set_signature_packets_local_id( PKT_signature *sig ) +{ + PKT_public_cert *pkc = m_alloc_clear( sizeof *pkc ); + TRUSTREC rec; + int rc; + + rc = get_pubkey( pkc, sig->keyid ); + if( rc) + goto leave; + if( !pkc->local_id ) { + rc = scan_record_by_pkc( pkc, &rec, 2 ); + if( rc == -1 ) + rc = insert_trust_record( pkc ); + if( rc ) + goto leave; + /* fixme: we should propagate the local_id to all copies of the PKC */ + } + sig->local_id = pkc->local_id; + + leave: + free_public_cert( pkc ); + return rc; +} + + +void +list_trustdb( const char *username ) +{ + TRUSTREC rec; + + if( username ) { + PKT_public_cert *pkc = m_alloc_clear( sizeof *pkc ); + int rc; + + if( (rc = get_pubkey_byname( pkc, username )) ) + log_error("user '%s' not found: %s\n", username, g10_errstr(rc) ); + else if( (rc=scan_record_by_pkc( pkc, &rec, 2 )) && rc != -1 ) + log_error("problem finding '%s' in trustdb: %s\n", + username, g10_errstr(rc)); + else if( rc == -1 ) + log_error("user '%s' not in trustdb\n", username); + else if( (rc = list_sigs( pkc->local_id )) ) + log_error("user '%s' list problem: %s\n", username, g10_errstr(rc)); + free_public_cert( pkc ); + } + else { + ulong recnum; + int i; + + printf("TrustDB: %s\n", db_name ); + for(i=9+strlen(db_name); i > 0; i-- ) + putchar('-'); + putchar('\n'); + no_io_dbg = 1; + for(recnum=0; !read_record( recnum, &rec); recnum++ ) + dump_record( recnum, &rec, stdout ); + no_io_dbg = 0; + } +} + +void +list_trust_path( int max_depth, const char *username ) +{ + int rc; + TRUSTREC rec; + PKT_public_cert *pkc = m_alloc_clear( sizeof *pkc ); + + if( max_depth < 1 ) + max_depth = MAX_LIST_SIGS_DEPTH+1; + + + if( (rc = get_pubkey_byname( pkc, username )) ) + log_error("user '%s' not found: %s\n", username, g10_errstr(rc) ); + else if( (rc=scan_record_by_pkc( pkc, &rec, 2 )) && rc != -1 ) + log_error("problem finding '%s' in trustdb: %s\n", + username, g10_errstr(rc)); + else if( rc == -1 ) + log_error("user '%s' not in trustdb\n", username); + else { + LOCAL_ID_INFO *lids; + ulong stack[MAX_LIST_SIGS_DEPTH]; + + lids = new_lid_table(); + stack[0] = pkc->local_id; + rc = do_list_path( pkc->local_id, 1, max_depth, lids, stack ); + putchar('\n'); + + release_lid_table(lids); + if( rc ) + log_error("user '%s' list problem: %s\n", username, g10_errstr(rc)); + } + + free_public_cert( pkc ); +} + +/**************** + * Walk throug the signatures of a public key. + * The caller must provide a context structure, with all fields set + * to zero, but the pubkeyid filed set to the requested pubkey; + * This function does not change this field. On return the context + * is filled with the local-id of the signature and the signature flag. + * No fields should be changed (clearing all fields and setting + * pubkeyid is okay to continue with an other pubkey) + * Returns: 0 - okay, -1 for eof (no more sigs) or any other errorcode + */ +static int +walk_sigrecs( SIGREC_CONTEXT *c ) +{ + int rc=0; + TRUSTREC *r; + ulong rnum; + + if( c->ctl.eof ) + return -1; + r = &c->ctl.rec; + if( !r->rectype ) { /* this is the first call */ + rc = scan_record( c->pubkey_id, r, 4, &rnum ); + if( rc == -1 ) { /* no signature records */ + c->ctl.eof = 1; + return -1; /* return eof */ + } + if( rc ) { + log_error("scan_record(sigrec) failed: %s\n", g10_errstr(rc)); + c->ctl.eof = 1; + return rc; + } + c->ctl.index = 0; + } + /* enter loop to skip deleted sigs */ + do { + if( c->ctl.index >= SIGS_PER_RECORD ) { + /* read the next record */ + if( !r->r.sigrec.chain ) { + c->ctl.eof = 1; + return -1; /* return eof */ + } + rnum = r->r.sigrec.chain; + rc = read_record( rnum, r ); + if( rc ) { + log_error("error reading next sigrec: %s\n", g10_errstr(rc)); + c->ctl.eof = 1; + return rc; + } + if( r->r.sigrec.owner != c->pubkey_id ) { + log_error("chained sigrec %lu has a wrong owner\n", rnum ); + c->ctl.eof = 1; + return G10ERR_TRUSTDB; + } + c->ctl.index = 0; + } + } while( !r->r.sigrec.sig[c->ctl.index++].local_id ); + c->sig_id = r->r.sigrec.sig[c->ctl.index-1].local_id; + c->sig_flag = r->r.sigrec.sig[c->ctl.index-1].flag; + return 0; +} /*********************************************** ************* trust logic ******************* ***********************************************/ +static LOCAL_ID_INFO * +new_lid_table(void) +{ + return m_alloc_clear( 16 * sizeof(LOCAL_ID_INFO)); +} + +static void +release_lid_table( LOCAL_ID_INFO *tbl ) +{ + LOCAL_ID_INFO a, a2; + int i; + + for(i=0; i < 16; i++ ) { + for(a=tbl[i]; a; a = a2 ) { + a2 = a->next; + m_free(a); + } + } + m_free(tbl); +} + +/**************** + * Add a new item to the table or return 1 if we aread have this item + * fixme: maybe its a good idea to tage items from an unused item list. + */ +static int +add_lid_table_item( LOCAL_ID_INFO *tbl, ulong lid, unsigned flag ) +{ + LOCAL_ID_INFO a; + + for( a = tbl[lid & 0x0f]; a; a = a->next ) + if( a->lid == lid ) + return 1; + a = m_alloc( sizeof *a ); + a->lid = lid; + a->flag = flag; + a->next = tbl[lid & 0x0f]; + tbl[lid & 0x0f] = a; + return 0; +} + +static int +get_lid_table_flag( LOCAL_ID_INFO *tbl, ulong lid, unsigned *flag ) +{ + LOCAL_ID_INFO a; + + for( a = tbl[lid & 0x0f]; a; a = a->next ) + if( a->lid == lid ) { + if( flag ) + *flag = a->flag; + return 0; + } + return -1; +} + + + + +static int +keyid_from_local_id( ulong lid, u32 *keyid ) +{ + TRUSTREC rec; + int rc; + + rc = read_record( lid, &rec ); + if( rc ) { + log_error("error reading record with local_id %lu: %s\n", + lid, g10_errstr(rc)); + return G10ERR_TRUSTDB; + } + if( rec.rectype != 2 ) { + log_error("record with local_id %lu is not a pubkey record\n", lid); + return G10ERR_TRUSTDB; + } + keyid[0] = rec.r.pubkey.keyid[0]; + keyid[1] = rec.r.pubkey.keyid[1]; + return 0; +} + + /**************** * Verify, that all our public keys are in the trustDB and marked as * ultimately trusted. @@ -522,7 +851,7 @@ verify_own_certs() int trust; while( !(rc=enum_secret_keys( &enum_context, skc) ) ) { - /* fixme: to be sure that it is a secret key of our own, + /* fixed: to be sure that it is a secret key of our own, * we should check it, but this needs a passphrase * for every key and this boring for the user. * Solution: Sign the secring and the trustring @@ -557,12 +886,26 @@ verify_own_certs() } if( trust & TRUST_NO_PUBKEY ) { log_info("keyid %08lX: not yet in trustdb\n", (ulong)keyid[1] ); - /* FIXME: insert */ + rc = insert_trust_record( pkc ); + if( rc ) + log_error("keyid %08lX: insert failed: %s\n", + (ulong)keyid[1], g10_errstr(rc) ); + else + log_info("keyid %08lX: inserted\n", (ulong)keyid[1] ); } else if( (trust & TRUST_MASK) != TRUST_ULT_TRUST ) { - log_error("keyid %08lX: not marked as ultimately trusted\n", + /*log_error("keyid %08lX: not marked as ultimately trusted\n", (ulong)keyid[1] ); - /* FIXME: mark */ + FIXME: mark */ + } + + if( !(trust & TRUST_NO_PUBKEY) ) { + if( DBG_TRUST ) + log_debug("putting %08lX(%lu) into ultikey_table\n", + (ulong)keyid[1], pkc->local_id ); + if( add_lid_table_item( ultikey_table, pkc->local_id, 0 ) ) + log_error("keyid %08lX: already in ultikey_table\n", + (ulong)keyid[1]); } release_secret_cert_parts( skc ); @@ -579,6 +922,156 @@ verify_own_certs() return rc; } +static void +print_user_id( const char *text, u32 *keyid ) +{ + char *p; + size_t n; + + p = get_user_id( keyid, &n ); + if( *text ) { + fputs( text, stdout); + putchar(' '); + } + putchar('\"'); + print_string( stdout, p, n ); + putchar('\"'); + putchar('\n'); + m_free(p); +} + +/* (a non-recursive algorithm would be easier) */ +static int +do_list_sigs( ulong root, ulong pubkey, int depth, + LOCAL_ID_INFO *lids, unsigned *lineno ) +{ + SIGREC_CONTEXT sx; + int rc; + u32 keyid[2]; + + memset( &sx, 0, sizeof sx ); + sx.pubkey_id = pubkey; + for(;;) { + rc = walk_sigrecs( &sx ); + if( rc ) + break; + rc = keyid_from_local_id( sx.sig_id, keyid ); + if( rc ) { + printf("%6u: %*s????????(%lu:%02x)\n", *lineno, depth*4, "", + sx.sig_id, sx.sig_flag ); + ++*lineno; + } + else { + printf("%6u: %*s%08lX(%lu:%02x) ", *lineno, depth*4, "", + (ulong)keyid[1], sx.sig_id, sx.sig_flag ); + /* check wether we already checked this pubkey */ + if( !get_lid_table_flag( ultikey_table, sx.sig_id, NULL ) ) { + print_user_id("[ultimately trusted]", keyid); + ++*lineno; + } + else if( sx.sig_id == pubkey ) { + printf("[self-signature]\n"); + ++*lineno; + } + else if( sx.sig_id == root ) { + printf("[closed]\n"); + ++*lineno; + } + else if( add_lid_table_item( lids, sx.sig_id, *lineno ) ) { + unsigned refline; + get_lid_table_flag( lids, sx.sig_id, &refline ); + printf("[see line %u]\n", refline); + ++*lineno; + } + else if( depth+1 >= MAX_LIST_SIGS_DEPTH ) { + print_user_id( "[too deeply nested]", keyid ); + ++*lineno; + } + else { + print_user_id( "", keyid ); + ++*lineno; + rc = do_list_sigs( root, sx.sig_id, depth+1, lids, lineno ); + if( rc ) + break; + } + } + } + return rc==-1? 0 : rc; +} + +/**************** + * List all signatures of a public key + */ +static int +list_sigs( ulong pubkey_id ) +{ + int rc; + u32 keyid[2]; + LOCAL_ID_INFO *lids; + unsigned lineno = 1; + + rc = keyid_from_local_id( pubkey_id, keyid ); + if( rc ) { + log_error("Hmmm, no pubkey record for local_id %lu\n", pubkey_id); + return rc; + } + printf("Signatures of %08lX(%lu) ", (ulong)keyid[1], pubkey_id ); + print_user_id("", keyid); + printf("----------------------\n"); + + lids = new_lid_table(); + rc = do_list_sigs( pubkey_id, pubkey_id, 0, lids, &lineno ); + putchar('\n'); + release_lid_table(lids); + return rc; +} + + + + + +static int +do_list_path( ulong pubkey, int depth, int max_depth, + LOCAL_ID_INFO *lids, ulong *stack ) +{ + SIGREC_CONTEXT sx; + int rc; + + if( depth > max_depth || depth >= MAX_LIST_SIGS_DEPTH ) + return 0; + if( !get_lid_table_flag( ultikey_table, pubkey, NULL ) ) { + /* found a path */ + int i; + u32 keyid[2]; + + for(i=0; i < depth; i++ ) { + if( keyid_from_local_id( stack[i], keyid ) ) + printf("%*s????????(%lu) ", i*4,"", stack[i] ); + else { + printf("%*s%08lX(%lu) ", i*4,"", keyid[1], stack[i] ); + print_user_id("", keyid ); + } + } + putchar('\n'); + return 0; + } + + if( add_lid_table_item( lids, pubkey, 0 ) ) + return 0; + + memset( &sx, 0, sizeof sx ); + sx.pubkey_id = pubkey; + do { + rc = walk_sigrecs( &sx ); + if( !rc ) { + stack[depth] = sx.sig_id; + rc = do_list_path( sx.sig_id, depth+1, max_depth, lids, stack ); + } + } while( !rc ); + return rc==-1? 0 : rc; +} + + /**************** @@ -586,23 +1079,30 @@ verify_own_certs() * as checked. */ static int -check_sigs( KBNODE keyblock ) +check_sigs( KBNODE keyblock, int *selfsig_okay ) { KBNODE kbctx; KBNODE node; int rc; + *selfsig_okay = 0; for( kbctx=NULL; (node=walk_kbtree( keyblock, &kbctx)) ; ) { if( node->pkt->pkttype == PKT_SIGNATURE && (node->pkt->pkt.signature->sig_class&~3) == 0x10 ) { - PKT_signature *sig = node->pkt->pkt.signature; - - rc = check_key_signature( keyblock, node ); - if( !rc ) - node->flag |= 1; /* mark signature valid */ + int selfsig; + rc = check_key_signature( keyblock, node, &selfsig ); + if( !rc ) { + if( selfsig ) { + node->flag |= 2; /* mark signature valid */ + *selfsig_okay = 1; + } + else + node->flag |= 1; /* mark signature valid */ + } if( DBG_TRUST ) log_debug("trustdb: sig from %08lX: %s\n", - rc? g10_errstr(rc): "okay" ); + (ulong)node->pkt->pkt.signature->keyid[1], + g10_errstr(rc) ); } } return 0; @@ -614,8 +1114,124 @@ check_sigs( KBNODE keyblock ) * to the trustdb */ static int -build_sigrecs( KBNODE keyblock ) +build_sigrecs( ulong pubkeyid ) { + TRUSTREC rec, rec2; + PUBKEY_FIND_INFO finfo=NULL; + KBPOS kbpos; + KBNODE keyblock = NULL; + KBNODE kbctx; + KBNODE node; + int rc=0; + int i, selfsig; + ulong rnum, rnum2; + + if( DBG_TRUST ) + log_debug("trustdb: build_sigrecs for pubkey %lu\n", (ulong)pubkeyid ); + + /* get the keyblock */ + if( (rc=read_record( pubkeyid, &rec )) ) { + log_error("build_sigrecs: can't read pubkey record\n"); + goto leave; + } + finfo = m_alloc_clear( sizeof *finfo ); + finfo->keyid[0] = rec.r.pubkey.keyid[0]; + finfo->keyid[1] = rec.r.pubkey.keyid[1]; + finfo->pubkey_algo = rec.r.pubkey.pubkey_algo; + memcpy( finfo->fingerprint, rec.r.pubkey.fingerprint, 20); + rc = find_keyblock( finfo, &kbpos ); + if( rc ) { + log_error("build_sigrecs: find_keyblock failed\n" ); + goto leave; + } + rc = read_keyblock( &kbpos, &keyblock ); + if( rc ) { + log_error("build_sigrecs: read_keyblock failed\n" ); + goto leave; + } + /* check all key signatures */ + rc = check_sigs( keyblock, &selfsig ); + if( rc ) { + log_error("build_sigrecs: check_sigs failed\n" ); + goto leave; + } + if( !selfsig ) { + log_error("build_sigrecs: self-certificate missing\n" ); + rc = G10ERR_BAD_CERT; + goto leave; + } + + /* valid key signatures are now marked; we can now build the + * sigrecs */ + memset( &rec, 0, sizeof rec ); + rec.rectype = 4; + i = 0; + rnum = rnum2 = 0; + for( kbctx=NULL; (node=walk_kbtree( keyblock, &kbctx)) ; ) { + if( node->flag & 1 ) { + assert( node->pkt->pkttype == PKT_SIGNATURE ); + if( !node->pkt->pkt.signature->local_id ) { + /* the next function should always succeed, because + * we have already checked the signature, and for this + * it was necessary to have the pubkey. The only reason + * this can fail are I/o erros of the trustdb. */ + rc = set_signature_packets_local_id( node->pkt->pkt.signature ); + if( rc ) + log_fatal("set_signature_packets_local_id failed: %s\n", + g10_errstr(rc)); + } + if( i == SIGS_PER_RECORD ) { + /* write the record */ + rnum = new_recnum(); + if( rnum2 ) { /* write the stored record */ + rec2.r.sigrec.owner = pubkeyid; + rec2.r.sigrec.chain = rnum; /* the next record number */ + rc = write_record( rnum2, &rec2 ); + if( rc ) { + log_error("build_sigrecs: write_record failed\n" ); + goto leave; + } + } + rec2 = rec; + rnum2 = rnum; + memset( &rec, 0, sizeof rec ); + rec.rectype = 5; + i = 0; + } + rec.r.sigrec.sig[i].local_id = node->pkt->pkt.signature->local_id; + rec.r.sigrec.sig[i].flag = 0; + i++; + } + } + if( i || rnum2 ) { + /* write the record */ + rnum = new_recnum(); + if( rnum2 ) { /* write the stored record */ + rec2.r.sigrec.owner = pubkeyid; + rec2.r.sigrec.chain = rnum; + rc = write_record( rnum2, &rec2 ); + if( rc ) { + log_error("build_sigrecs: write_record failed\n" ); + goto leave; + } + } + if( i ) { /* write the pending record */ + rec.r.sigrec.owner = pubkeyid; + rec.r.sigrec.chain = 0; + rc = write_record( rnum, &rec ); + if( rc ) { + log_error("build_sigrecs: write_record failed\n" ); + goto leave; + } + } + } + + leave: + m_free( finfo ); + release_kbnode( keyblock ); + if( DBG_TRUST ) + log_debug("trustdb: build_sigrecs: %s\n", g10_errstr(rc) ); + return rc; } @@ -624,6 +1240,7 @@ build_sigrecs( KBNODE keyblock ) /**************** * Recursive check the signatures. */ + #if 0 static int walk( KBNODE keyblock, int levels ) { @@ -640,9 +1257,9 @@ walk( KBNODE keyblock, int levels ) } } } - + return -1; } - +#endif @@ -651,10 +1268,25 @@ walk( KBNODE keyblock, int levels ) * */ static int -check_trust() +check_trust( ulong pubkeyid ) { - /* check the ca + int rc=0; + ulong rnum; + TRUSTREC rec; + /* verify the cache */ + + /* do we have sigrecs */ + rc = scan_record( pubkeyid, &rec, 4, &rnum ); + if( rc == -1 ) { /* no sigrecs, so build them */ + rc = build_sigrecs( pubkeyid ); + if( !rc ) /* and read again */ + rc = scan_record( pubkeyid, &rec, 4, &rnum ); + } + if( rc ) + return rc; /* error while looking for sigrec or building sigrecs */ + + return 0; } @@ -665,26 +1297,34 @@ check_trust() /**************** * Perform some checks over the trustdb - * level 0: used for initial program startup + * level 0: only open the db + * 1: used for initial program startup */ int -check_trustdb( int level ) +init_trustdb( int level ) { int rc=0; - if( !level ) { - char *fname = make_filename("~/.g10", "trustDB", NULL ); + if( !ultikey_table ) + ultikey_table = new_lid_table(); + + if( !level || level==1 ) { + char *fname = make_filename("~/.g10", "trustdb.g10", NULL ); if( access( fname, R_OK ) ) { if( errno != ENOENT ) { log_error("can't access %s: %s\n", fname, strerror(errno) ); m_free(fname); return G10ERR_TRUSTDB; } - create_db( fname ); + if( level ) + create_db( fname ); } m_free(db_name); db_name = fname; + if( !level ) + return 0; + /* we can verify a signature about our local data (secring and trustdb) * in ~/.g10/ here */ rc = verify_private_data(); @@ -699,7 +1339,7 @@ check_trustdb( int level ) } } else - log_bug(NULL); + BUG(); return rc; } @@ -747,7 +1387,7 @@ check_pkc_trust( PKT_public_cert *pkc, int *r_trustlevel ) if( (rc=scan_record_by_pkc( pkc, &rec, 2 )) && rc != -1 ) { log_error("check_pkc_trust: scan_record_by_pkc(2) failed: %s\n", g10_errstr(rc)); - return G10ERR_TRUSTDB; + return rc; } else if( rc == -1 ) { log_error("check_pkc_trust: pubkey not in TrustDB\n"); @@ -757,7 +1397,11 @@ check_pkc_trust( PKT_public_cert *pkc, int *r_trustlevel ) } /* fixme: do some additional checks on the pubkey record */ - /* see wether we have a cache record */ + rc = check_trust( pkc->local_id ); + if( rc ) { + log_error("check_pkc_trust: check_trust failed: %s\n", g10_errstr(rc)); + return rc; + } leave: @@ -768,6 +1412,33 @@ check_pkc_trust( PKT_public_cert *pkc, int *r_trustlevel ) } +int +get_ownertrust( PKT_public_cert *pkc, int *r_otrust ) +{ + TRUSTREC rec; + int rc; + + /* get the pubkey record */ + if( pkc->local_id ) { + if( read_record( pkc->local_id, &rec ) ) { + log_error("get_ownertrust: read record failed\n"); + return G10ERR_TRUSTDB; + } + } + else { /* no local_id: scan the trustdb */ + if( (rc=scan_record_by_pkc( pkc, &rec, 2 )) && rc != -1 ) { + log_error("get_ownertrust: scan_record_by_pkc(2) failed: %s\n", + g10_errstr(rc)); + return rc; + } + else if( rc == -1 ) + return rc; + } + *r_otrust = rec.r.pubkey.ownertrust; + return 0; +} + + /**************** * Insert a trust record into the TrustDB * This function failes if this record already exists. @@ -777,7 +1448,7 @@ insert_trust_record( PKT_public_cert *pkc ) { TRUSTREC rec; u32 keyid[2]; - u32 recnum; + ulong recnum; byte *fingerprint; size_t fingerlen; @@ -785,21 +1456,22 @@ insert_trust_record( PKT_public_cert *pkc ) if( DBG_TRUST ) log_debug("trustdb: insert_record\n"); - assert( !pkc->local_id ); + if( pkc->local_id ) + log_bug("pkc->local_id=%lu\n", (ulong)pkc->local_id ); keyid_from_pkc( pkc, keyid ); fingerprint = fingerprint_from_pkc( pkc, &fingerlen ); /* FIXME: check that we do not have this record. */ - recnum = new_local_id(); + recnum = new_recnum(); /* build record */ memset( &rec, 0, sizeof rec ); rec.rectype = 2; /* the pubkey record */ rec.r.pubkey.local_id = recnum; rec.r.pubkey.keyid[0] = keyid[0]; rec.r.pubkey.keyid[1] = keyid[1]; - rec.r.pubkey.algo = pkc->pubkey_algo; + rec.r.pubkey.pubkey_algo = pkc->pubkey_algo; memcpy(rec.r.pubkey.fingerprint, fingerprint, fingerlen ); rec.r.pubkey.ownertrust = 0; if( write_record( recnum, &rec ) ) { @@ -817,8 +1489,7 @@ int update_trust_record( PKT_public_cert *pkc, int new_trust ) { TRUSTREC rec; - u32 keyid[2]; - u32 recnum; + ulong recnum; if( DBG_TRUST ) log_debug("trustdb: update_record\n"); diff --git a/g10/trustdb.h b/g10/trustdb.h index aff668e84..bd15d25b0 100644 --- a/g10/trustdb.h +++ b/g10/trustdb.h @@ -34,8 +34,12 @@ /*-- trustdb.c --*/ -int check_trustdb( int level ); +void list_trustdb(const char *username); +void list_trust_path( int max_depth, const char *username ); +int init_trustdb( int level ); int check_pkc_trust( PKT_public_cert *pkc, int *r_trustlevel ); +int get_ownertrust( PKT_public_cert *pkc, int *r_otrust ); +int insert_trust_record( PKT_public_cert *pkc ); int verify_private_data(void); int sign_private_data(void); diff --git a/include/cipher.h b/include/cipher.h index 1f615e54d..52d1a7503 100644 --- a/include/cipher.h +++ b/include/cipher.h @@ -78,6 +78,7 @@ int check_pubkey_algo( int algo ); int check_digest_algo( int algo ); /*-- random.c --*/ +int quick_random_gen( int onoff ); void randomize_buffer( byte *buffer, size_t length, int level ); byte get_random_byte( int level ); diff --git a/include/errors.h b/include/errors.h index 450d910cf..305a147e8 100644 --- a/include/errors.h +++ b/include/errors.h @@ -53,5 +53,6 @@ #define G10ERR_RESOURCE_LIMIT 31 #define G10ERR_INV_KEYRING 32 #define G10ERR_TRUSTDB 33 /* a problem with the trustdb */ +#define G10ERR_BAD_CERT 34 /* bad certicate */ #endif /*G10_ERRORS_H*/ diff --git a/include/iobuf.h b/include/iobuf.h index d29e0a06e..e381445a5 100644 --- a/include/iobuf.h +++ b/include/iobuf.h @@ -93,6 +93,7 @@ u32 iobuf_get_filelength( IOBUF a ); const char *iobuf_get_fname( IOBUF a ); void iobuf_set_block_mode( IOBUF a, size_t n ); +void iobuf_set_partial_block_mode( IOBUF a, size_t len ); int iobuf_in_block_mode( IOBUF a ); /* get a byte form the iobuf; must check for eof prior to this function diff --git a/include/mpi.h b/include/mpi.h index 7c4639f18..7a43b3018 100644 --- a/include/mpi.h +++ b/include/mpi.h @@ -41,7 +41,6 @@ int mpi_debug_mode; #define BITS_PER_MPI_LIMB (8*SIZEOF_UNSIGNED_LONG) #define BYTES_PER_MPI_LIMB SIZEOF_UNSIGNED_LONG -#define BYTES_PER_MPI_LIMB2 (2*SIZEOF_UNSIGNED_LONG) typedef unsigned long int mpi_limb_t; typedef signed long int mpi_limb_signed_t; diff --git a/include/util.h b/include/util.h index 7f2593022..a33b7f21f 100644 --- a/include/util.h +++ b/include/util.h @@ -58,20 +58,38 @@ typedef struct { /*-- logger.c --*/ void log_set_pid( int pid ); int log_get_errorcount( int clear ); -void printstr( int level, const char *fmt, ... ); -void log_bug( const char *fmt, ... ); -void log_fatal( const char *fmt, ... ); -void log_error( const char *fmt, ... ); -void log_info( const char *fmt, ... ); -void log_debug( const char *fmt, ... ); void log_hexdump( const char *text, char *buf, size_t len ); void log_mpidump( const char *text, MPI a ); +#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 5 ) + void printstr( int level, const char *fmt, ... ) + __attribute__ ((format (printf,2,3))); + void log_bug( const char *fmt, ... ) + __attribute__ ((noreturn, format (printf,1,2))); + void log_bug0( void ) __attribute__ ((noreturn)); + void log_fatal( const char *fmt, ... ) + __attribute__ ((noreturn, format (printf,1,2))); + void log_error( const char *fmt, ... ) __attribute__ ((format (printf,1,2))); + void log_info( const char *fmt, ... ) __attribute__ ((format (printf,1,2))); + void log_debug( const char *fmt, ... ) __attribute__ ((format (printf,1,2))); +#else + void printstr( int level, const char *fmt, ... ); + void log_bug( const char *fmt, ... ); + void log_bug0( void ); + void log_fatal( const char *fmt, ... ); + void log_error( const char *fmt, ... ); + void log_info( const char *fmt, ... ); + void log_debug( const char *fmt, ... ); +#endif + + /*-- errors.c --*/ const char * g10_errstr( int no ); /*-- argparse.c --*/ int arg_parse( ARGPARSE_ARGS *arg, ARGPARSE_OPTS *opts); +int optfile_parse( FILE *fp, const char *filename, unsigned *lineno, + ARGPARSE_ARGS *arg, ARGPARSE_OPTS *opts); void usage( int level ); const char *default_strusage( int level ); @@ -112,5 +130,6 @@ char *strlwr(char *a); #define STR2(v) STR(v) #define DIM(v) (sizeof(v)/sizeof((v)[0])) #define DIMof(type,member) DIM(((type *)0)->member) +#define BUG() log_bug0() #endif /*G10_UTIL_H*/ diff --git a/mpi/mpi-bit.c b/mpi/mpi-bit.c index 1eb63a02d..864dc0236 100644 --- a/mpi/mpi-bit.c +++ b/mpi/mpi-bit.c @@ -32,8 +32,7 @@ unsigned mpi_get_nbits( MPI a ) { - unsigned nbits; - unsigned n, count = 0; + unsigned n; if( a->nlimbs ) { mpi_limb_t alimb = a->d[a->nlimbs-1]; diff --git a/mpi/mpi-internal.h b/mpi/mpi-internal.h index f084c7e8a..638d980b3 100644 --- a/mpi/mpi-internal.h +++ b/mpi/mpi-internal.h @@ -193,7 +193,7 @@ void mpih_sqr_n_basecase( mpi_ptr_t prodp, mpi_ptr_t up, mpi_size_t size ); void mpih_sqr_n( mpi_ptr_t prodp, mpi_ptr_t up, mpi_size_t size, mpi_ptr_t tspace); -/*-- mpihelp-mul_1.c (or xxx/cpu/*.S) --*/ +/*-- mpihelp-mul_1.c (or xxx/cpu/ *.S) --*/ mpi_limb_t mpihelp_mul_1( mpi_ptr_t res_ptr, mpi_ptr_t s1_ptr, mpi_size_t s1_size, mpi_limb_t s2_limb); diff --git a/mpi/mpi-pow.c b/mpi/mpi-pow.c index fcf500c36..2df34b778 100644 --- a/mpi/mpi-pow.c +++ b/mpi/mpi-pow.c @@ -52,7 +52,7 @@ mpi_powm( MPI res, MPI base, MPI exp, MPI mod) mpi_ptr_t xp_marker=NULL; int assign_rp=0; mpi_ptr_t tspace = NULL; - mpi_size_t tsize; + mpi_size_t tsize=0; /* to avoid compiler warning, fixme: check */ esize = exp->nlimbs; msize = mod->nlimbs; diff --git a/mpi/mpicoder.c b/mpi/mpicoder.c index 43b97beea..75583996d 100644 --- a/mpi/mpicoder.c +++ b/mpi/mpicoder.c @@ -41,36 +41,23 @@ int mpi_write( IOBUF out, MPI a ) { - int i; - unsigned nbits = a->nlimbs * BITS_PER_MPI_LIMB; - mpi_limb_t limb; + int rc; + unsigned nbits = mpi_get_nbits(a); + byte *p, *buf; + unsigned n; - /* fixme: use a->nbits if valid */ if( nbits > MAX_EXTERN_MPI_BITS ) log_bug("mpi_encode: mpi too large (%u bits)\n", nbits); + iobuf_put(out, (nbits >>8) ); iobuf_put(out, (nbits) ); - for(i=a->nlimbs-1; i >= 0; i-- ) { - limb = a->d[i]; - #if BYTES_PER_MPI_LIMB == 4 - iobuf_put(out, (limb >> 24) ); - iobuf_put(out, (limb >> 16) ); - iobuf_put(out, (limb >> 8) ); - iobuf_put(out, (limb ) ); - #elif BYTES_PER_MPI_LIMB == 8 - iobuf_put(out, (limb >> 56) ); - iobuf_put(out, (limb >> 48) ); - iobuf_put(out, (limb >> 40) ); - iobuf_put(out, (limb >> 32) ); - iobuf_put(out, (limb >> 24) ); - iobuf_put(out, (limb >> 16) ); - iobuf_put(out, (limb >> 8) ); - iobuf_put(out, (limb ) ); - #else - #error Make this function work with other LIMB sizes - #endif - } - return 0; + + p = buf = mpi_get_buffer( a, &n, NULL ); + for( ; !*p && n; p++, n-- ) + ; + rc = iobuf_write( out, p, n ); + m_free(buf); + return rc; } @@ -225,13 +212,22 @@ mpi_print( FILE *fp, MPI a, int mode ) if( a == MPI_NULL ) return fprintf(fp, "[MPI_NULL]"); if( !mode ) - n += fprintf(fp, "[%d bits]", a->nlimbs * BITS_PER_MPI_LIMB ); + n += fprintf(fp, "[%u bits]", mpi_get_nbits(a) ); else { if( a->sign ) putc('-', fp); + #if BYTES_PER_MPI_LIMB == 2 + #define X "4" + #elif BYTES_PER_MPI_LIMB == 4 + #define X "8" + #elif BYTES_PER_MPI_LIMB == 8 + #define X "16" + #else + #error please define the format here + #endif for(i=a->nlimbs; i > 0 ; i-- ) { - n += fprintf(fp, i!=a->nlimbs? "%0" STR2(BYTES_PER_MPI_LIMB2) - "lX":"%lX", (unsigned long)a->d[i-1] ); + n += fprintf(fp, i!=a->nlimbs? "%0" X "lX":"%lX", (ulong)a->d[i-1]); + #undef X } if( !a->nlimbs ) putc('0', fp ); diff --git a/mpi/mpiutil.c b/mpi/mpiutil.c index 0c8e648b1..068a9a399 100644 --- a/mpi/mpiutil.c +++ b/mpi/mpiutil.c @@ -45,7 +45,7 @@ mpi_alloc( unsigned nlimbs ) MPI a; if( DBG_MEMORY ) - log_debug("mpi_alloc(%lu)\n", nlimbs*BITS_PER_MPI_LIMB ); + log_debug("mpi_alloc(%u)\n", nlimbs*BITS_PER_MPI_LIMB ); #ifdef M_DEBUG a = m_debug_alloc( sizeof *a, info ); a->d = nlimbs? mpi_debug_alloc_limb_space( nlimbs, 0, info ) : NULL; @@ -77,7 +77,7 @@ mpi_alloc_secure( unsigned nlimbs ) MPI a; if( DBG_MEMORY ) - log_debug("mpi_alloc_secure(%lu)\n", nlimbs*BITS_PER_MPI_LIMB ); + log_debug("mpi_alloc_secure(%u)\n", nlimbs*BITS_PER_MPI_LIMB ); #ifdef M_DEBUG a = m_debug_alloc( sizeof *a, info ); a->d = nlimbs? mpi_debug_alloc_limb_space( nlimbs, 1, info ) : NULL; diff --git a/util/argparse.c b/util/argparse.c index 80b7fcd3d..c6c0302b9 100644 --- a/util/argparse.c +++ b/util/argparse.c @@ -188,7 +188,6 @@ int optfile_parse( FILE *fp, const char *filename, unsigned *lineno, ARGPARSE_ARGS *arg, ARGPARSE_OPTS *opts) { - char *s, *s2; int state, i, c; int index=0; char keyword[100]; diff --git a/util/errors.c b/util/errors.c index 46797df3b..9b8848f4c 100644 --- a/util/errors.c +++ b/util/errors.c @@ -33,6 +33,8 @@ g10_errstr( int err ) #define X(n,s) case G10ERR_##n : p = s; break; switch( err ) { + case -1: p = "eof"; break; + case 0: p = "okay"; break; X(GENERAL, "General error") X(UNKNOWN_PACKET, "Unknown packet type") X(UNKNOWN_VERSION,"Unknown version") @@ -46,6 +48,7 @@ g10_errstr( int err ) X(NO_PUBKEY ,"Public key not found") X(CIPHER_ALGO ,"Unknown cipher algorithm") X(KEYRING_OPEN ,"Can't open the keyring") + X(INVALID_PACKET ,"Invalid packet") X(BAD_RING ,"Broken keyring") X(NO_USER_ID ,"No such user id found") X(NO_SECKEY ,"Secret key not available") @@ -61,8 +64,10 @@ g10_errstr( int err ) X(NI_PUBKEY ,"Unimplemented pubkey algorithm") X(NI_CIPHER ,"Unimplemented cipher algorithm") X(SIG_CLASS ,"Unknown signature class") + X(TRUSTDB ,"TrustDB error") + X(BAD_CERT ,"Bad certificate") - default: p = buf; sprintf(buf, "Error code %d", err); break; + default: p = buf; sprintf(buf, "g10err=%d", err); break; } #undef X return p; diff --git a/util/iobuf.c b/util/iobuf.c index ad9821972..72a14f503 100644 --- a/util/iobuf.c +++ b/util/iobuf.c @@ -40,6 +40,7 @@ typedef struct { int usage; size_t size; size_t count; + int partial; /* 1 = partial header, 2 in last partial packet */ int eof; } block_filter_ctx_t; @@ -143,20 +144,64 @@ block_filter(void *opaque, int control, IOBUF chain, byte *buf, size_t *ret_len) rc = -1; while( !rc && size ) { if( !a->size ) { /* get the length bytes */ - c = iobuf_get(chain); - a->size = c << 8; - c = iobuf_get(chain); - a->size |= c; - if( c == -1 ) { - log_error("block_filter: error reading length info\n"); - rc = G10ERR_READ_FILE; - } - if( !a->size ) { + if( a->partial == 2 ) { a->eof = 1; if( !n ) rc = -1; break; } + else if( a->partial ) { + if( (c = iobuf_get(chain)) == -1 ) { + log_error("block_filter: 1st length byte missing\n"); + rc = G10ERR_READ_FILE; + break; + } + if( c < 192 ) { + a->size = c; + a->partial = 2; + if( !a->size ) { + a->eof = 1; + if( !n ) + rc = -1; + break; + } + } + else if( c < 224 ) { + a->size = (c - 192) * 256; + if( (c = iobuf_get(chain)) == -1 ) { + log_error("block_filter: 2nd length byte missing\n"); + rc = G10ERR_READ_FILE; + break; + } + a->size += c + 192; + a->partial = 2; + if( !a->size ) { + a->eof = 1; + if( !n ) + rc = -1; + break; + } + } + else { /* next partial body length */ + a->size = 1 << (c & 0x1f); + } + } + else { + c = iobuf_get(chain); + a->size = c << 8; + c = iobuf_get(chain); + a->size |= c; + if( c == -1 ) { + log_error("block_filter: error reading length info\n"); + rc = G10ERR_READ_FILE; + } + if( !a->size ) { + a->eof = 1; + if( !n ) + rc = -1; + break; + } + } } for(; !rc && size && a->size; size--, a->size-- ) { @@ -176,6 +221,7 @@ block_filter(void *opaque, int control, IOBUF chain, byte *buf, size_t *ret_len) else if( control == IOBUFCTRL_FLUSH ) { size_t avail, n; + assert( !a->partial ); for(p=buf; !rc && size; ) { n = size; avail = a->size - a->count; @@ -205,7 +251,9 @@ block_filter(void *opaque, int control, IOBUF chain, byte *buf, size_t *ret_len) else if( control == IOBUFCTRL_INIT ) { if( DBG_IOBUF ) log_debug("init block_filter %p\n", a ); - if( a->usage == 1 ) + if( a->partial ) + a->count = 0; + else if( a->usage == 1 ) a->count = a->size = 0; else a->count = a->size; /* force first length bytes */ @@ -216,8 +264,12 @@ block_filter(void *opaque, int control, IOBUF chain, byte *buf, size_t *ret_len) } else if( control == IOBUFCTRL_FREE ) { if( a->usage == 2 ) { /* write the end markers */ - iobuf_writebyte(chain, 0); - iobuf_writebyte(chain, 0); + if( a->partial ) { + } + else { + iobuf_writebyte(chain, 0); + iobuf_writebyte(chain, 0); + } } else if( a->size ) { log_error("block_filter: pending bytes!\n"); @@ -784,7 +836,10 @@ iobuf_seek( IOBUF a, ulong newpos ) return -1; } a->ntotal = newpos; - /* FIXME: flush all buffers (and remove filters?)*/ + /* remove filters, but the last */ + while( a->chain ) + iobuf_pop_filter( a, a->filter, NULL ); + return 0; } @@ -800,8 +855,6 @@ iobuf_seek( IOBUF a, ulong newpos ) const char * iobuf_get_fname( IOBUF a ) { - struct stat st; - for( ; a; a = a->chain ) if( !a->chain && a->filter == file_filter ) { file_filter_ctx_t *b = a->filter_ov; @@ -832,6 +885,27 @@ iobuf_set_block_mode( IOBUF a, size_t n ) } } +/**************** + * enable patial block mode as descriped in the OpenPGP draft. + * LEN is the first length + */ +void +iobuf_set_partial_block_mode( IOBUF a, size_t len ) +{ + block_filter_ctx_t *ctx = m_alloc_clear( sizeof *ctx ); + + assert( a->usage == 1 || a->usage == 2 ); + ctx->usage = a->usage; + if( !len ) { + iobuf_pop_filter(a, block_filter, NULL ); + } + else { + ctx->partial = 1; + ctx->size = len; + iobuf_push_filter(a, block_filter, ctx ); + } +} + /**************** * Checks wether the stream is in block mode @@ -841,7 +915,7 @@ int iobuf_in_block_mode( IOBUF a ) { if( a && a->filter == block_filter ) - return 1; /* yes */ + return 1; /* yes */ return 0; /* no */ } diff --git a/util/logger.c b/util/logger.c index c32332b48..2355b6267 100644 --- a/util/logger.c +++ b/util/logger.c @@ -120,17 +120,19 @@ log_bug( const char *fmt, ... ) va_list arg_ptr ; fprintf(stderr, "\nInternal Error%s: ", pidstring ) ; - if( fmt ) { - va_start( arg_ptr, fmt ) ; - vfprintf(stderr,fmt,arg_ptr) ; - va_end(arg_ptr); - } - else - fputs("Ohhh jeeee ...\n", stderr); + va_start( arg_ptr, fmt ) ; + vfprintf(stderr,fmt,arg_ptr) ; + va_end(arg_ptr); fflush(stderr); abort(); } +void +log_bug0() +{ + log_bug("Ohhhh jeeee ...\n"); +} + void log_debug( const char *fmt, ... ) { diff --git a/util/ttyio.c b/util/ttyio.c index 2cb52448c..ec7b6502b 100644 --- a/util/ttyio.c +++ b/util/ttyio.c @@ -23,6 +23,7 @@ #include #include #include +#include #ifdef HAVE_TCGETATTR #include #endif @@ -99,7 +100,6 @@ do_get( const char *prompt, int hidden ) char *buf; byte cbuf[1]; int c, n, i; - FILE *fp; #ifdef HAVE_TCGETATTR struct termios termsave; #endif