From b758180325b90184f7ac66267141cb5465c07a9f Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Wed, 18 Feb 1998 13:58:46 +0000 Subject: [PATCH] added revcation stuff and fixed a couple of bugs --- NEWS | 14 +++- cipher/ChangeLog | 4 + cipher/md.c | 23 ++---- cipher/md.h | 2 + doc/DETAILS | 61 +++++++++++++- g10/ChangeLog | 24 ++++++ g10/Makefile.in | 2 +- g10/armor.c | 5 +- g10/build-packet.c | 20 ++++- g10/filter.h | 2 + g10/free-packet.c | 2 - g10/g10.c | 2 +- g10/import.c | 195 +++++++++++++++++++++++++++++++++++++++++---- g10/keygen.c | 1 - g10/mainproc.c | 56 ++++++++----- g10/packet.h | 1 - g10/parse-packet.c | 10 --- g10/pkclist.c | 21 ++++- g10/revoke.c | 1 + g10/sig-check.c | 44 ++++++---- g10/sign.c | 1 + g10/trustdb.c | 58 +++++++++----- g10/trustdb.h | 7 +- zlib/Makefile.am | 2 +- 24 files changed, 441 insertions(+), 117 deletions(-) diff --git a/NEWS b/NEWS index 882670e45..f875e3399 100644 --- a/NEWS +++ b/NEWS @@ -1,11 +1,21 @@ Noteworthy changes in version 0.2.7 ----------------------------------- - * new option --dearmot for g10maint + * New command "gen-revoke" to create a key revocation certificate. - * option --version now conforming to the GNU standards and lists + * New option "homedir" to set the homedir (which defaults to "~/.g10"). + This directory is created if it does not exists (only the last + part of the name and not the complete hierarchy) + + * Command "import" works. (Try: "finger gcrypt@ftp.guug.de|g10 --import") + + * New commands "dearmor/enarmor" for g10maint. These are mainly + used for internal test purposes. + + * Option --version now conforming to the GNU standards and lists the available ciphers, message digests and public key algorithms. + * Assembler code for m68k (not tested). Noteworthy changes in version 0.2.6 ----------------------------------- diff --git a/cipher/ChangeLog b/cipher/ChangeLog index e915c3bcc..29626e55e 100644 --- a/cipher/ChangeLog +++ b/cipher/ChangeLog @@ -1,3 +1,7 @@ +Wed Feb 18 14:08:30 1998 Werner Koch (wk@isil.d.shuttle.de) + + * md.c, md.h : New debugging support + Mon Feb 16 10:08:47 1998 Werner Koch (wk@isil.d.shuttle.de) * misc.c (cipher_algo_to_string): New diff --git a/cipher/md.c b/cipher/md.c index 46083960f..fbae09765 100644 --- a/cipher/md.c +++ b/cipher/md.c @@ -27,10 +27,6 @@ #include "cipher.h" #include "errors.h" - - -/*static FILE *dumpfp;*/ - /**************** * Open a message digest handle for use with algorithm ALGO. * More algorithms may be added by md_enable(). The initial algorithm @@ -41,13 +37,6 @@ md_open( int algo, int secure ) { MD_HANDLE hd; - #if 0 - if( !dumpfp ) - dumpfp = fopen("md.out", "w"); - if( !dumpfp ) - BUG(); - { int i; for(i=0; i < 16; i++ ) putc('\xff', dumpfp ); } - #endif hd = secure ? m_alloc_secure_clear( sizeof *hd ) : m_alloc_clear( sizeof *hd ); hd->secure = secure; @@ -81,7 +70,6 @@ md_copy( MD_HANDLE a ) { MD_HANDLE b; - /*{ int i; for(i=0; i < 16; i++ ) putc('\xee', dumpfp ); }*/ b = a->secure ? m_alloc_secure( sizeof *b ) : m_alloc( sizeof *b ); memcpy( b, a, sizeof *a ); @@ -101,10 +89,12 @@ md_close(MD_HANDLE a) void md_write( MD_HANDLE a, byte *inbuf, size_t inlen) { - /* if( a->bufcount && fwrite(a->buffer, a->bufcount, 1, dumpfp ) != 1 ) - BUG(); - if( inlen && fwrite(inbuf, inlen, 1, dumpfp ) != 1 ) - BUG(); */ + if( a->debug ) { + if( a->bufcount && fwrite(a->buffer, a->bufcount, 1, a->debug ) != 1 ) + BUG(); + if( inlen && fwrite(inbuf, inlen, 1, a->debug ) != 1 ) + BUG(); + } if( a->use_rmd160 ) { rmd160_write( &a->rmd160, a->buffer, a->bufcount ); rmd160_write( &a->rmd160, inbuf, inlen ); @@ -127,7 +117,6 @@ md_final(MD_HANDLE a) { if( a->bufcount ) md_write( a, NULL, 0 ); - /*{ int i; for(i=0; i < 16; i++ ) putc('\xcc', dumpfp ); }*/ if( a->use_rmd160 ) { byte *p; rmd160_final( &a->rmd160 ); diff --git a/cipher/md.h b/cipher/md.h index fc5d28df6..5903946c2 100644 --- a/cipher/md.h +++ b/cipher/md.h @@ -20,6 +20,7 @@ #ifndef G10_MD_H #define G10_MD_H +#include #include "types.h" #include "rmd.h" #include "sha1.h" @@ -37,6 +38,7 @@ typedef struct { byte buffer[MD_BUFFER_SIZE]; /* primary buffer */ int bufcount; int secure; + FILE *debug; } *MD_HANDLE; diff --git a/doc/DETAILS b/doc/DETAILS index 7455a38bf..dc3e55421 100644 --- a/doc/DETAILS +++ b/doc/DETAILS @@ -6,6 +6,10 @@ a rmd160 hash value from it. This is used as the fingerprint and the low 64 bits are the keyid. + * Revocation certificates consists only of the signature packet; + "import" knows how to handle this. The rationale behind it is + to keep them small. + @@ -162,7 +166,7 @@ Record Type 6 (hash table) if this is not the correct dir record, we look at the next dir record which is linked by the link field. -Record type 7 (hast list) +Record type 7 (hash list) ------------- see hash table for an explanation. @@ -175,3 +179,58 @@ Record type 7 (hast list) For the current record length of 40, n is 6 + + + +Packet Headers +=============== + +G10 uses PGP 2 packet headers and also understand OpenPGP packet header. +There is one enhavement used ith the old style packet headers: + + CTB bits 10, the "packet-length length bits", have values listed in + the following table: + + 00 - 1-byte packet-length field + 01 - 2-byte packet-length field + 10 - 4-byte packet-length field + 11 - no packet length supplied, unknown packet length + + As indicated in this table, depending on the packet-length length + bits, the remaining 1, 2, 4, or 0 bytes of the packet structure field + are a "packet-length field". The packet-length field is a whole + number field. The value of the packet-length field is defined to be + the value of the whole number field. + + A value of 11 is currently used in one place: on compressed data. + That is, a compressed data block currently looks like , + where , binary 10 1000 11, is an indefinite-length packet. The + proper interpretation is "until the end of the enclosing structure", + although it should never appear outermost (where the enclosing + structure is a file). + ++ This will be changed with another version, where the new meaning of ++ the value 11 (see below) will also take place. ++ ++ A value of 11 for other packets enables a special length encoding, ++ which is used in case, where the length of the following packet can ++ not be determined prior to writing the packet; especially this will ++ be used if large amounts of data are processed in filter mode. ++ ++ It works like this: After the CTB (with a length field of 11) a ++ marker field is used, which gives the length of the following datablock. ++ This is a simple 2 byte field (MSB first) containig the amount of data ++ following this field, not including this length field. After this datablock ++ another length field follows, which gives the size of the next datablock. ++ A value of 0 indicates the end of the packet. The maximum size of a ++ data block is limited to 65534, thereby reserving a value of 0xffff for ++ future extensions. These length markers must be insereted into the data ++ stream just before writing the data out. ++ ++ This 2 byte filed is large enough, because the application must buffer ++ this amount of data to prepend the length marker before writing it out. ++ Data block sizes larger than about 32k doesn't make any sense. Note ++ that this may also be used for compressed data streams, but we must use ++ another packet version to tell the application that it can not assume, ++ that this is the last packet. + diff --git a/g10/ChangeLog b/g10/ChangeLog index 414b051f0..6be310564 100644 --- a/g10/ChangeLog +++ b/g10/ChangeLog @@ -1,3 +1,27 @@ +Wed Feb 18 13:35:58 1998 Werner Koch (wk@isil.d.shuttle.de) + + * mainproc.c (do_check_sig): Now uses hash_public_cert. + * parse-packet.c (parse_certificate): Removed hashing. + * packet.h (public_cert): Removed hash variable. + * free-packet.c (copy_public_cert, free_public_cert): Likewise. + + * sig-check.c (check_key_signatures): Changed semantics. + +Wed Feb 18 12:11:28 1998 Werner Koch (wk@isil.d.shuttle.de) + + * trustdb.c (do_check): Add handling for revocation certificates. + (build_sigrecs): Ditto. + (check_sigs): Ditto. + +Wed Feb 18 09:31:04 1998 Werner Koch (wk@isil.d.shuttle.de) + + * armor.c (armor_filter): Add afx->hdrlines. + * revoke.c (gen_revoke): Add comment line. + * dearmor.c (enarmor_file): Ditto. + + * sig-check.c (check_key_signature): Add handling for class 0x20. + * mainproc.c : Ditto. + Tue Feb 17 21:24:17 1998 Werner Koch (wk@isil.d.shuttle.de) * armor.c : Add header lines "...ARMORED FILE .." diff --git a/g10/Makefile.in b/g10/Makefile.in index 953b13b6b..318423c56 100644 --- a/g10/Makefile.in +++ b/g10/Makefile.in @@ -87,7 +87,7 @@ VERSION = @VERSION@ ZLIBS = @ZLIBS@ INCLUDES = -I$(top_srcdir)/include -EXTRA_DIST = OPTIONS pubring.g10 +EXTRA_DIST = OPTIONS pubring.asc needed_libs = ../cipher/libcipher.a ../mpi/libmpi.a ../util/libutil.a bin_PROGRAMS = g10 g10maint diff --git a/g10/armor.c b/g10/armor.c index 03a393b35..1fc8ae0b0 100644 --- a/g10/armor.c +++ b/g10/armor.c @@ -944,7 +944,10 @@ armor_filter( void *opaque, int control, iobuf_writestr(a, "-----\n"); iobuf_writestr(a, "Version: G10 v" VERSION " (" PRINTABLE_OS_NAME ")\n"); - iobuf_writestr(a, "Comment: This is an alpha version!\n\n"); + iobuf_writestr(a, "Comment: This is an alpha version!\n"); + if( afx->hdrlines ) + iobuf_writestr(a, afx->hdrlines); + iobuf_put(a, '\n'); afx->status++; afx->idx = 0; afx->idx2 = 0; diff --git a/g10/build-packet.c b/g10/build-packet.c index 2e1a48337..b032a67b0 100644 --- a/g10/build-packet.c +++ b/g10/build-packet.c @@ -211,7 +211,12 @@ 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");*/ + #if 1 + FILE *fp = fopen("dump.pkc", "a"); + int i=0; + + fprintf(fp, "\nHashing PKC:\n"); + #endif /* build the packet */ init_packet(&pkt); @@ -220,10 +225,19 @@ hash_public_cert( MD_HANDLE md, 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 ) { - /* putc( c, fp);*/ + #if 1 + fprintf( fp," %02x", c ); + if( (++i == 24) ) { + putc('\n', fp); + i=0; + } + #endif md_putc( md, c ); } - /*fclose(fp);*/ + #if 1 + putc('\n', fp); + fclose(fp); + #endif iobuf_cancel(a); } diff --git a/g10/filter.h b/g10/filter.h index 93e72ce9c..965b75bd0 100644 --- a/g10/filter.h +++ b/g10/filter.h @@ -20,6 +20,7 @@ #ifndef G10_FILTER_H #define G10_FILTER_H +#include "types.h" #include "cipher.h" typedef struct { @@ -41,6 +42,7 @@ typedef struct { int inp_checked; /* set if inp has been checked */ int inp_bypass; /* set if the input is not armored */ int inp_eof; + const char *hdrlines; } armor_filter_context_t; diff --git a/g10/free-packet.c b/g10/free-packet.c index f2467a78b..9152f9051 100644 --- a/g10/free-packet.c +++ b/g10/free-packet.c @@ -87,7 +87,6 @@ release_public_cert_parts( PKT_public_cert *cert ) mpi_free( cert->d.rsa.rsa_n ); cert->d.rsa.rsa_n = NULL; mpi_free( cert->d.rsa.rsa_e ); cert->d.rsa.rsa_e = NULL; } - md_close( cert->mfx.md ); cert->mfx.md = NULL; } void @@ -112,7 +111,6 @@ copy_public_cert( PKT_public_cert *d, PKT_public_cert *s ) d->d.rsa.rsa_n = mpi_copy( s->d.rsa.rsa_n ); d->d.rsa.rsa_e = mpi_copy( s->d.rsa.rsa_e ); } - d->mfx.md = NULL; return d; } diff --git a/g10/g10.c b/g10/g10.c index f9ae0fc69..433955717 100644 --- a/g10/g10.c +++ b/g10/g10.c @@ -474,7 +474,7 @@ main( int argc, char **argv ) if( greeting ) { tty_printf("%s %s; %s\n", strusage(11), strusage(13), strusage(14) ); - tty_printf("%s", strusage(15) ); + tty_printf("%s\n", strusage(15) ); } /* initialize the secure memory. */ diff --git a/g10/import.c b/g10/import.c index 43e64239f..fa08e8657 100644 --- a/g10/import.c +++ b/g10/import.c @@ -38,6 +38,7 @@ static int read_block( IOBUF a, compress_filter_context_t *cfx, PACKET **pending_pkt, KBNODE *ret_root ); static int import_one( const char *fname, KBNODE keyblock ); +static int import_revoke_cert( const char *fname, KBNODE node ); static int chk_self_sigs( const char *fname, KBNODE keyblock, PKT_public_cert *pkc, u32 *keyid ); static int delete_inv_parts( const char *fname, KBNODE keyblock, u32 *keyid ); @@ -56,7 +57,6 @@ static int merge_sigs( KBNODE dst, KBNODE src, int *n_sigs, * Other signatures are not not checked. * * Actually this functtion does a merge. It works like this: - * FIXME: add handling for revocation certs * * - get the keyblock * - check self-signatures and remove all userids and their signatures @@ -78,6 +78,8 @@ static int merge_sigs( KBNODE dst, KBNODE src, int *n_sigs, * is used. * - Proceed with next signature. * + * Key revocation certificates have a special handling. + * */ int import_pubkeys( const char *fname ) @@ -107,6 +109,9 @@ import_pubkeys( const char *fname ) while( !(rc = read_block( inp, &cfx, &pending_pkt, &keyblock) )) { if( keyblock->pkt->pkttype == PKT_PUBLIC_CERT ) rc = import_one( fname, keyblock ); + else if( keyblock->pkt->pkttype == PKT_SIGNATURE + && keyblock->pkt->pkt.signature->sig_class == 0x20 ) + rc = import_revoke_cert( fname, keyblock ); else log_info("%s: skipping block of type %d\n", fname, keyblock->pkt->pkttype ); @@ -159,6 +164,16 @@ read_block( IOBUF a, compress_filter_context_t *cfx, init_packet(pkt); continue; } + + if( !root && pkt->pkttype == PKT_SIGNATURE + && pkt->pkt.signature->sig_class == 0x20 ) { + /* this is a revocation certificate which is handled + * in a special way */ + root = new_kbnode( pkt ); + pkt = NULL; + goto ready; + } + /* make a linked list of all packets */ switch( pkt->pkttype ) { case PKT_COMPRESSED: @@ -332,7 +347,7 @@ import_one( const char *fname, KBNODE keyblock ) if( (rc=lock_keyblock( &kbpos )) ) log_error("can't lock public keyring '%s': %s\n", keyblock_resource_name(&kbpos), g10_errstr(rc) ); - else if( (rc=insert_keyblock( &kbpos, keyblock )) ) + else if( (rc=update_keyblock( &kbpos, keyblock )) ) log_error("%s: can't write to '%s': %s\n", fname, keyblock_resource_name(&kbpos), g10_errstr(rc) ); unlock_keyblock( &kbpos ); @@ -361,6 +376,105 @@ import_one( const char *fname, KBNODE keyblock ) } +/**************** + * Import a revocation certificate, this is a single signature packet. + */ +static int +import_revoke_cert( const char *fname, KBNODE node ) +{ + PKT_public_cert *pkc=NULL; + KBNODE onode, keyblock = NULL; + KBPOS kbpos; + u32 keyid[2]; + int rc = 0; + + assert( !node->next ); + assert( node->pkt->pkttype == PKT_SIGNATURE ); + assert( node->pkt->pkt.signature->sig_class == 0x20 ); + + keyid[0] = node->pkt->pkt.signature->keyid[0]; + keyid[1] = node->pkt->pkt.signature->keyid[1]; + + pkc = m_alloc_clear( sizeof *pkc ); + rc = get_pubkey( pkc, keyid ); + if( rc == G10ERR_NO_PUBKEY ) { + log_info("%s: key %08lX, no public key - " + "can't apply revocation certificate\n", + fname, (ulong)keyid[1]); + rc = 0; + goto leave; + } + else if( rc ) { + log_error("%s: key %08lX, public key not found: %s\n", + fname, (ulong)keyid[1], g10_errstr(rc)); + goto leave; + } + + /* read the original keyblock */ + rc = find_keyblock_bypkc( &kbpos, pkc ); + if( rc ) { + log_error("%s: key %08lX, can't locate original keyblock: %s\n", + fname, (ulong)keyid[1], g10_errstr(rc)); + goto leave; + } + rc = read_keyblock( &kbpos, &keyblock ); + if( rc ) { + log_error("%s: key %08lX, can't read original keyblock: %s\n", + fname, (ulong)keyid[1], g10_errstr(rc)); + goto leave; + } + + + /* it is okay, that node is not in keyblock because + * check_key_signature works fine for sig_class 0x20 in this + * special case. */ + rc = check_key_signature( keyblock, node, NULL); + if( rc ) { + log_error("%s: key %08lX, invalid revocation certificate" + ": %s - rejected\n", + fname, (ulong)keyid[1], g10_errstr(rc)); + } + + + /* check wether we already have this */ + for(onode=keyblock->next; onode; onode=onode->next ) { + if( onode->pkt->pkttype == PKT_USER_ID ) + break; + else if( onode->pkt->pkttype == PKT_SIGNATURE + && onode->pkt->pkt.signature->sig_class == 0x20 + && keyid[0] == onode->pkt->pkt.signature->keyid[0] + && keyid[1] == onode->pkt->pkt.signature->keyid[1] ) { + rc = 0; + goto leave; /* yes, we already know about it */ + } + } + + + /* insert it */ + insert_kbnode( keyblock, clone_kbnode(node), 0 ); + + /* and write the keyblock back */ + if( opt.verbose > 1 ) + log_info("%s: writing to '%s'\n", + fname, keyblock_resource_name(&kbpos) ); + if( (rc=lock_keyblock( &kbpos )) ) + log_error("can't lock public keyring '%s': %s\n", + keyblock_resource_name(&kbpos), g10_errstr(rc) ); + else if( (rc=update_keyblock( &kbpos, keyblock )) ) + log_error("%s: can't write to '%s': %s\n", fname, + keyblock_resource_name(&kbpos), g10_errstr(rc) ); + unlock_keyblock( &kbpos ); + /* we are ready */ + log_info("%s: key %08lX, added revocation certificate\n", + fname, (ulong)keyid[1]); + + leave: + release_kbnode( keyblock ); + free_public_cert( pkc ); + return rc; +} + + /**************** * loop over the keyblock an check all self signatures. * Mark all user-ids with a self-signature by setting flag bit 0. @@ -408,10 +522,11 @@ static int delete_inv_parts( const char *fname, KBNODE keyblock, u32 *keyid ) { KBNODE node; - int nvalid=0; + int nvalid=0, uid_seen=0; for(node=keyblock->next; node; node = node->next ) { if( node->pkt->pkttype == PKT_USER_ID ) { + uid_seen = 1; if( (node->flag & 2) || !(node->flag & 1) ) { if( opt.verbose ) { log_info("%s: key %08lX, removed userid '", @@ -434,6 +549,23 @@ delete_inv_parts( const char *fname, KBNODE keyblock, u32 *keyid ) && check_pubkey_algo( node->pkt->pkt.signature->pubkey_algo) && node->pkt->pkt.signature->pubkey_algo != PUBKEY_ALGO_RSA ) delete_kbnode( node ); /* build_packet() can't handle this */ + else if( node->pkt->pkttype == PKT_SIGNATURE + && node->pkt->pkt.signature->sig_class == 0x20 ) { + if( uid_seen ) { + log_error("%s: key %08lX, revocation certificate at wrong " + "place - removed\n", fname, (ulong)keyid[1]); + delete_kbnode( node ); + } + else { + int rc = check_key_signature( keyblock, node, NULL); + if( rc ) { + log_error("%s: key %08lX, invalid revocation certificate" + ": %s - removed\n", + fname, (ulong)keyid[1], g10_errstr(rc)); + delete_kbnode( node ); + } + } + } } /* note: because keyblock is the public key, it is never marked @@ -460,36 +592,67 @@ static int merge_blocks( const char *fname, KBNODE keyblock_orig, KBNODE keyblock, u32 *keyid, int *n_uids, int *n_sigs ) { - KBNODE node_orig, node; - int rc; + KBNODE onode, node; + int rc, found; - /* first, try to merge new ones in */ - for(node_orig=keyblock_orig->next; node_orig; node_orig=node_orig->next ) { - if( !(node_orig->flag & 1) && node_orig->pkt->pkttype == PKT_USER_ID) { + /* 1st: handle revocation certificates */ + for(node=keyblock->next; node; node=node->next ) { + if( node->pkt->pkttype == PKT_USER_ID ) + break; + else if( node->pkt->pkttype == PKT_SIGNATURE + && node->pkt->pkt.signature->sig_class == 0x20 ) { + /* check wether we already have this */ + found = 0; + for(onode=keyblock_orig->next; onode; onode=onode->next ) { + if( onode->pkt->pkttype == PKT_USER_ID ) + break; + else if( onode->pkt->pkttype == PKT_SIGNATURE + && onode->pkt->pkt.signature->sig_class == 0x20 + && node->pkt->pkt.signature->keyid[0] + == onode->pkt->pkt.signature->keyid[0] + && node->pkt->pkt.signature->keyid[1] + == onode->pkt->pkt.signature->keyid[1] ) { + found = 1; + break; + } + } + if( !found ) { + KBNODE n2 = clone_kbnode(node); + insert_kbnode( keyblock_orig, n2, 0 ); + n2->flag |= 1; + node->flag |= 1; + log_info("%s: key %08lX, added revocation certificate\n", + fname, (ulong)keyid[1]); + } + } + } + + /* 2nd: try to merge new ones in */ + for(onode=keyblock_orig->next; onode; onode=onode->next ) { + if( !(onode->flag & 1) && onode->pkt->pkttype == PKT_USER_ID) { /* find the user id in the imported keyblock */ for(node=keyblock->next; node; node=node->next ) if( !(node->flag & 1) && node->pkt->pkttype == PKT_USER_ID - && !cmp_user_ids( node_orig->pkt->pkt.user_id, + && !cmp_user_ids( onode->pkt->pkt.user_id, node->pkt->pkt.user_id ) ) break; if( node ) { /* found: merge */ - rc = merge_sigs( node_orig, node, n_sigs, fname, keyid ); + rc = merge_sigs( onode, node, n_sigs, fname, keyid ); if( rc ) return rc; } } } - /* second, add new user-ids */ + /* 3rd: add new user-ids */ for(node=keyblock->next; node; node=node->next ) { if( !(node->flag & 1) && node->pkt->pkttype == PKT_USER_ID) { /* do we have this in the original keyblock */ - for(node_orig=keyblock_orig->next; node_orig; - node_orig=node_orig->next ) - if( !(node_orig->flag & 1) - && node_orig->pkt->pkttype == PKT_USER_ID - && cmp_user_ids( node_orig->pkt->pkt.user_id, + for(onode=keyblock_orig->next; onode; onode=onode->next ) + if( !(onode->flag & 1) + && onode->pkt->pkttype == PKT_USER_ID + && cmp_user_ids( onode->pkt->pkt.user_id, node->pkt->pkt.user_id ) ) break; if( !node ) { /* this is a new user id: append */ diff --git a/g10/keygen.c b/g10/keygen.c index f0cbda3d0..96a867c1e 100644 --- a/g10/keygen.c +++ b/g10/keygen.c @@ -154,7 +154,6 @@ gen_elg(unsigned nbits, KBNODE pub_root, KBNODE sec_root, DEK *dek, 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; - memset(&pkc->mfx, 0, sizeof pkc->mfx); pkc->d.elg.p = pk.p; pkc->d.elg.g = pk.g; pkc->d.elg.y = pk.y; diff --git a/g10/mainproc.c b/g10/mainproc.c index f2b50ac9d..2bbe7418c 100644 --- a/g10/mainproc.c +++ b/g10/mainproc.c @@ -265,11 +265,8 @@ do_check_sig( CTX c, KBNODE node ) assert( node->pkt->pkttype == PKT_SIGNATURE ); sig = node->pkt->pkt.signature; - if( sig->pubkey_algo == PUBKEY_ALGO_ELGAMAL ) - algo = sig->d.elg.digest_algo; - else if(sig->pubkey_algo == PUBKEY_ALGO_RSA ) - algo = sig->d.rsa.digest_algo; - else + algo = digest_algo_from_sig( sig ); + if( !algo ) return G10ERR_PUBKEY_ALGO; if( (rc=check_digest_algo(algo)) ) return rc; @@ -282,24 +279,36 @@ do_check_sig( CTX c, KBNODE node ) * in canonical mode ??? (calculating both modes???) */ md = md_copy( c->mfx.md ); } - else if( (sig->sig_class&~3) == 0x10 ) { /* classes 0x10 .. 0x13 */ + else if( (sig->sig_class&~3) == 0x10 + || sig->sig_class == 0x20 + || sig->sig_class == 0x30 ) { /* classes 0x10..0x13,0x20,0x30 */ if( c->list->pkt->pkttype == PKT_PUBLIC_CERT ) { - KBNODE n1 = find_prev_kbnode( c->list, node, PKT_USER_ID ); + #if 0 + KBNODE n1; - if( n1 ) { - if( c->list->pkt->pkt.public_cert->mfx.md ) - md = md_copy( c->list->pkt->pkt.public_cert->mfx.md ); - else - BUG(); - md_write( md, n1->pkt->pkt.user_id->name, n1->pkt->pkt.user_id->len); + if( sig->sig_class == 0x20 ) { + md = md_open( algo, 0 ); + hash_public_cert( md, c->list->pkt->pkt.public_cert ); + } + else if( (n1=find_prev_kbnode( c->list, node, PKT_USER_ID )) ) { + md = md_open( algo, 0 ); + hash_public_cert( md, c->list->pkt->pkt.public_cert ); + if( sig->sig_class != 0x20 ) + md_write( md, n1->pkt->pkt.user_id->name, + n1->pkt->pkt.user_id->len); } else { - log_error("invalid parent packet for sigclass 0x10\n"); + log_error("invalid parent packet for sigclass %02x\n", + sig->sig_class); return G10ERR_SIG_CLASS; } + #endif + + return check_key_signature( c->list, node, NULL ); } else { - log_error("invalid root packet for sigclass 0x10\n"); + log_error("invalid root packet for sigclass %02x\n", + sig->sig_class); return G10ERR_SIG_CLASS; } } @@ -374,7 +383,13 @@ list_node( CTX c, KBNODE node ) datestr_from_pkc( pkc ) ); /* and now list all userids with their signatures */ for( node = node->next; node; node = node->next ) { - if( node->pkt->pkttype == PKT_USER_ID ) { + if( any != 2 && node->pkt->pkttype == PKT_SIGNATURE ) { + if( !any ) + putchar('\n'); + list_node(c, node ); + any = 1; + } + else if( node->pkt->pkttype == PKT_USER_ID ) { KBNODE n; if( any ) @@ -389,10 +404,10 @@ list_node( CTX c, KBNODE node ) if( n->pkt->pkttype == PKT_SIGNATURE ) list_node(c, n ); } - any=1; + any=2; } } - if( !any ) + if( any != 2 ) printf("ERROR: no user id!\n"); } else if( node->pkt->pkttype == PKT_SECRET_CERT ) { @@ -423,7 +438,10 @@ list_node( CTX c, KBNODE node ) if( !opt.list_sigs ) return; - fputs("sig", stdout); + if( sig->sig_class == 0x20 || sig->sig_class == 0x30 ) + fputs("rev", stdout); + else + fputs("sig", stdout); if( opt.check_sigs ) { fflush(stdout); switch( (rc2=do_check_sig( c, node )) ) { diff --git a/g10/packet.h b/g10/packet.h index 98015a365..c41f32006 100644 --- a/g10/packet.h +++ b/g10/packet.h @@ -99,7 +99,6 @@ typedef struct { byte hdrbytes; /* number of header bytes */ byte version; byte pubkey_algo; /* algorithm used for public key scheme */ - md_filter_context_t mfx; ulong local_id; /* internal use, valid if > 0 */ union { struct { diff --git a/g10/parse-packet.c b/g10/parse-packet.c index 0e13f6d18..b50c584bd 100644 --- a/g10/parse-packet.c +++ b/g10/parse-packet.c @@ -592,14 +592,6 @@ parse_certificate( IOBUF inp, int pkttype, unsigned long pktlen, unsigned short valid_period; int is_v4=0; - if( pkttype == PKT_PUBLIC_CERT ) { - pkt->pkt.public_cert->mfx.md = md_open(DIGEST_ALGO_MD5, 0); - md_enable(pkt->pkt.public_cert->mfx.md, DIGEST_ALGO_RMD160); - md_enable(pkt->pkt.public_cert->mfx.md, DIGEST_ALGO_SHA1); - pkt->pkt.public_cert->mfx.maxbuf_size = 1; - md_write(pkt->pkt.public_cert->mfx.md, hdr, hdrlen); - iobuf_push_filter( inp, md_filter, &pkt->pkt.public_cert->mfx ); - } if( pktlen < 12 ) { log_error("packet(%d) too short\n", pkttype); @@ -765,8 +757,6 @@ parse_certificate( IOBUF inp, int pkttype, unsigned long pktlen, leave: - if( pkttype == PKT_PUBLIC_CERT ) - iobuf_pop_filter( inp, md_filter, &pkt->pkt.public_cert->mfx ); skip_rest(inp, pktlen); return 0; } diff --git a/g10/pkclist.c b/g10/pkclist.c index f123fc0d8..cd453323f 100644 --- a/g10/pkclist.c +++ b/g10/pkclist.c @@ -167,7 +167,24 @@ do_we_trust( PKT_public_cert *pkc, int trustlevel ) { int rc; - switch( trustlevel ) { + if( (trustlevel & TRUST_FLAG_REVOKED) ) { + char *answer; + int yes; + + log_info("key has beed revoked!\n"); + if( opt.batch ) + return 0; + + answer = tty_get("Use this key anyway? "); + tty_kill_prompt(); + yes = answer_is_yes(answer); + m_free(answer); + if( !yes ) + return 0; + } + + + switch( (trustlevel & TRUST_MASK) ) { case TRUST_UNKNOWN: /* No pubkey in trustDB: Insert and check again */ rc = insert_trust_record( pkc ); if( rc ) { @@ -184,7 +201,7 @@ do_we_trust( PKT_public_cert *pkc, int trustlevel ) return do_we_trust( pkc, trustlevel ); case TRUST_EXPIRED: - log_error("trust has expired: NOT yet implemented\n"); + log_info("trust has expired: NOT yet implemented\n"); return 0; /* no */ case TRUST_UNDEFINED: diff --git a/g10/revoke.c b/g10/revoke.c index 2a8c5fc5c..59d866b92 100644 --- a/g10/revoke.c +++ b/g10/revoke.c @@ -152,6 +152,7 @@ gen_revoke( const char *uname ) } afx.what = 1; + afx.hdrlines = "Comment: A revocation certificate should follow\n"; iobuf_push_filter( out, armor_filter, &afx ); if( opt.compress ) iobuf_push_filter( out, compress_filter, &zfx ); diff --git a/g10/sig-check.c b/g10/sig-check.c index 4615c46e0..360a184c8 100644 --- a/g10/sig-check.c +++ b/g10/sig-check.c @@ -183,7 +183,9 @@ do_check( PKT_public_cert *pkc, PKT_signature *sig, MD_HANDLE digest ) /**************** - * check the signature pointed to by NODE. This is a key signatures + * check the signature pointed to by NODE. This is a key signatures. + * If the function detects a elf signature, it uses the PKC from + * NODE and does not read the any public key. */ int check_key_signature( KBNODE root, KBNODE node, int *is_selfsig ) @@ -198,7 +200,6 @@ check_key_signature( KBNODE root, KBNODE node, int *is_selfsig ) 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 ); pkc = root->pkt->pkt.public_cert; @@ -213,27 +214,36 @@ check_key_signature( KBNODE root, KBNODE node, int *is_selfsig ) if( (rc=check_digest_algo(algo)) ) return rc; - unode = find_prev_kbnode( root, node, PKT_USER_ID ); - - if( unode ) { - 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; - } + if( sig->sig_class == 0x20 ) { md = md_open( algo, 0 ); hash_public_cert( md, pkc ); - md_write( md, uid->name, uid->len ); rc = do_check( pkc, sig, md ); md_close(md); } else { - log_error("no user id for key signature packet\n"); - rc = G10ERR_SIG_CLASS; + unode = find_prev_kbnode( root, node, PKT_USER_ID ); + + if( unode ) { + PKT_user_id *uid = unode->pkt->pkt.user_id; + u32 keyid[2]; + + keyid_from_pkc( pkc, keyid ); + md = md_open( algo, 0 ); + hash_public_cert( md, pkc ); + md_write( md, uid->name, uid->len ); + if( keyid[0] == sig->keyid[0] && keyid[1] == sig->keyid[1] ) { + if( is_selfsig ) + *is_selfsig = 1; + rc = do_check( pkc, sig, md ); + } + else + rc = signature_check( sig, md ); + md_close(md); + } + else { + log_error("no user id for key signature packet\n"); + rc = G10ERR_SIG_CLASS; + } } return rc; diff --git a/g10/sign.c b/g10/sign.c index 2bf3045fc..0cbcbd3a2 100644 --- a/g10/sign.c +++ b/g10/sign.c @@ -987,6 +987,7 @@ make_keysig_packet( PKT_signature **ret_sig, PKT_public_cert *pkc, assert( (sigclass >= 0x10 && sigclass <= 0x13) || sigclass == 0x20 ); md = md_open( digest_algo, 0 ); + /* hash the public key certificate and the user id */ hash_public_cert( md, pkc ); if( sigclass != 0x20 ) diff --git a/g10/trustdb.c b/g10/trustdb.c index 0c2620a95..836f9806d 100644 --- a/g10/trustdb.c +++ b/g10/trustdb.c @@ -380,8 +380,10 @@ dump_record( ulong rnum, TRUSTREC *rec, FILE *fp ) fputs(", (none)", fp ); else if( rec->r.dir.no_sigs == 2 ) fputs(", (invalid)", fp ); - else if( rec->r.dir.no_sigs ) + else if( rec->r.dir.no_sigs == 3 ) fputs(", (revoked)", fp ); + else if( rec->r.dir.no_sigs ) + fputs(", (??)", fp ); putc('\n', fp); break; case RECTYPE_KEY: fprintf(fp, "key keyid=%08lX, own=%lu, ownertrust=%02x\n", @@ -1084,17 +1086,19 @@ do_list_path( TRUST_INFO *stack, int depth, int max_depth, * some of them are bad? */ static int -check_sigs( KBNODE keyblock, int *selfsig_okay ) +check_sigs( KBNODE keyblock, int *selfsig_okay, int *revoked ) { - KBNODE kbctx; KBNODE node; int rc; LOCAL_ID_INFO *dups = NULL; *selfsig_okay = 0; - for( kbctx=NULL; (node=walk_kbnode( keyblock, &kbctx,0)) ; ) { + *revoked = 0; + for( node=keyblock; node; node = node->next ) { if( node->pkt->pkttype == PKT_SIGNATURE - && (node->pkt->pkt.signature->sig_class&~3) == 0x10 ) { + && ( (node->pkt->pkt.signature->sig_class&~3) == 0x10 + || node->pkt->pkt.signature->sig_class == 0x20 + || node->pkt->pkt.signature->sig_class == 0x30) ) { int selfsig; rc = check_key_signature( keyblock, node, &selfsig ); if( !rc ) { @@ -1106,13 +1110,18 @@ check_sigs( KBNODE keyblock, int *selfsig_okay ) node->flag |= 2; /* mark signature valid */ *selfsig_okay = 1; } + else if( node->pkt->pkt.signature->sig_class == 0x20 ) + *revoked = 1; else node->flag |= 1; /* mark signature valid */ - if( !dups ) - dups = new_lid_table(); - if( ins_lid_table_item( dups, - node->pkt->pkt.signature->local_id, 0) ) - node->flag |= 4; /* mark as duplicate */ + + if( node->pkt->pkt.signature->sig_class != 0x20 ) { + if( !dups ) + dups = new_lid_table(); + if( ins_lid_table_item( dups, + node->pkt->pkt.signature->local_id, 0) ) + node->flag |= 4; /* mark as duplicate */ + } } if( DBG_TRUST ) log_debug("trustdb: sig from %08lX(%lu): %s%s\n", @@ -1138,10 +1147,9 @@ build_sigrecs( ulong pubkeyid ) PUBKEY_FIND_INFO finfo=NULL; KBPOS kbpos; KBNODE keyblock = NULL; - KBNODE kbctx; KBNODE node; int rc=0; - int i, selfsig; + int i, selfsig, revoked; ulong rnum, rnum2; ulong first_sigrec = 0; @@ -1173,7 +1181,7 @@ build_sigrecs( ulong pubkeyid ) goto leave; } /* check all key signatures */ - rc = check_sigs( keyblock, &selfsig ); + rc = check_sigs( keyblock, &selfsig, &revoked ); if( rc ) { log_error("build_sigrecs: check_sigs failed\n" ); goto leave; @@ -1184,7 +1192,12 @@ build_sigrecs( ulong pubkeyid ) rc = G10ERR_BAD_CERT; goto leave; } - update_no_sigs( pubkeyid, 0 ); /* assume we have sigs */ + if( revoked ) { + log_info("build_sigrecs: key has been revoked\n" ); + update_no_sigs( pubkeyid, 3 ); + } + else + update_no_sigs( pubkeyid, 0 ); /* assume we have sigs */ /* valid key signatures are now marked; we can now build the * sigrecs */ @@ -1192,7 +1205,7 @@ build_sigrecs( ulong pubkeyid ) rec.rectype = RECTYPE_SIG; i = 0; rnum = rnum2 = 0; - for( kbctx=NULL; (node=walk_kbnode( keyblock, &kbctx, 0)) ; ) { + for( node=keyblock; node; node = node->next ) { /* insert sigs which are not a selfsig nor a duplicate */ if( (node->flag & 1) && !(node->flag & 4) ) { assert( node->pkt->pkttype == PKT_SIGNATURE ); @@ -1272,7 +1285,7 @@ build_sigrecs( ulong pubkeyid ) } } else - update_no_sigs( pubkeyid, 1 ); /* no signatures */ + update_no_sigs( pubkeyid, revoked? 3:1 ); /* no signatures */ leave: m_free( finfo ); @@ -1385,6 +1398,7 @@ do_check( ulong pubkeyid, TRUSTREC *dr, unsigned *trustlevel ) int marginal, fully; int fully_needed = opt.completes_needed; int marginal_needed = opt.marginals_needed; + unsigned tflags = 0; assert( fully_needed > 0 && marginal_needed > 1 ); @@ -1400,10 +1414,14 @@ do_check( ulong pubkeyid, TRUSTREC *dr, unsigned *trustlevel ) if( !rc ) /* and read again */ rc = read_record( pubkeyid, dr, RECTYPE_DIR ); } + + if( dr->r.dir.no_sigs == 3 ) + tflags |= TRUST_FLAG_REVOKED; + if( !rc && !dr->r.dir.sigrec ) { /* See wether this is our own key */ if( !qry_lid_table_flag( ultikey_table, pubkeyid, NULL ) ) { - *trustlevel = TRUST_ULTIMATE; + *trustlevel = tflags | TRUST_ULTIMATE; return 0; } else @@ -1442,7 +1460,7 @@ do_check( ulong pubkeyid, TRUSTREC *dr, unsigned *trustlevel ) if( tsl->dup ) continue; if( tsl->seg[0].trust == TRUST_ULTIMATE ) { - *trustlevel = TRUST_ULTIMATE; /* our own key */ + *trustlevel = tflags | TRUST_ULTIMATE; /* our own key */ break; } if( tsl->seg[0].trust == TRUST_FULLY ) { @@ -1453,12 +1471,12 @@ do_check( ulong pubkeyid, TRUSTREC *dr, unsigned *trustlevel ) marginal++; if( fully >= fully_needed ) { - *trustlevel = TRUST_FULLY; + *trustlevel = tflags | TRUST_FULLY; break; } } if( !tsl && marginal >= marginal_needed ) - *trustlevel = TRUST_MARGINAL; + *trustlevel = tflags | TRUST_MARGINAL; /* cache the tslist */ if( last_trust_web_key ) { diff --git a/g10/trustdb.h b/g10/trustdb.h index 5eb52c9a2..48f006e76 100644 --- a/g10/trustdb.h +++ b/g10/trustdb.h @@ -22,14 +22,17 @@ #define G10_TRUSTDB_H -/* Trust values mus be sorted in ascending order */ +/* Trust values must be sorted in ascending order */ +#define TRUST_MASK 15 #define TRUST_UNKNOWN 0 /* not yet calculated */ #define TRUST_EXPIRED 1 /* calculation may be invalid */ #define TRUST_UNDEFINED 2 /* not enough informations for calculation */ -#define TRUST_NEVER 3 /* never trusted this pubkey */ +#define TRUST_NEVER 3 /* never trust this pubkey */ #define TRUST_MARGINAL 4 /* marginally trusted */ #define TRUST_FULLY 5 /* fully trusted */ #define TRUST_ULTIMATE 6 /* ultimately trusted */ +/* trust values not covered by the mask */ +#define TRUST_FLAG_REVOKED 32 /*-- trustdb.c --*/ diff --git a/zlib/Makefile.am b/zlib/Makefile.am index 2d2d749df..2f2f65a29 100644 --- a/zlib/Makefile.am +++ b/zlib/Makefile.am @@ -5,7 +5,7 @@ CFLAGS = -O -Wall -EXTRA_DIST = README algorithm.doc ChangeLog example.c +EXTRA_DIST = README algorithm.doc ChangeLog example.c # I found no other easy way to use this only if zlib is neede # doing this with SUBDIR = @xxx@ in the top Makefile.am does not