diff --git a/NEWS b/NEWS index f2282082a..c5fbdafb8 100644 --- a/NEWS +++ b/NEWS @@ -1,4 +1,12 @@ + * The logic to handle the web of trust is now implemented. It is + has some bugs; but I'm going to change the algorithm anyway. + It works by calculating the trustlevel on the fly. It may ask + you to provide trust parameters if the calculated trust probability + is too low. I will write a paper which discusses this new approach. + + * a couple of changes to the configure script. + * 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 diff --git a/README b/README index 1f2879c86..4aa3f6e1a 100644 --- a/README +++ b/README @@ -11,14 +11,11 @@ * Some features are not yet implemented - I provide this version as a reality check to start discussion. Please subscribe to g10@net.lut.ac.uk by sending a mail with the word "subscribe" in the body to "g10-request@net.lut.ac.uk". - See the file COPYING for copyright and warranty information. - Due to the fact that G10 does not use use any patented algorithm, it cannot be compatible to old PGP versions, because those use IDEA (which is worldwide patented) and RSA (which is patented in @@ -210,7 +207,8 @@ depth. If depth is negative, duplicate introducers are not listed, because those would increase the trust probabilty only minimal. (you must use the special option "--" to stop option parsing when - using a negative number) + using a negative number). This option may create new entries in the + trustdb. --print-mds filenames diff --git a/TODO b/TODO index 9e762099b..65079b605 100644 --- a/TODO +++ b/TODO @@ -39,4 +39,9 @@ * Burn the buffers used by fopen(). + * bug: g10/trustdb.c#build_sigrecs caled to often by do_list_path + and remove the bad kludge. Maybe we should put all sigs into the trustdb + and mark them as valid/invalid/nopubkey, and how do we check, that + we have a self-signature -> put this stuff into a kind of directory + record, as it does not belong to the pubkey record? diff --git a/VERSION b/VERSION index 845639eef..0ea3a944b 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.1.4 +0.2.0 diff --git a/doc/DETAILS b/doc/DETAILS index d5d1abe09..37d0a02d8 100644 --- a/doc/DETAILS +++ b/doc/DETAILS @@ -11,6 +11,8 @@ Layout of the TrustDB ===================== +FIXME: use a directory record as top node instead of the pubkey record + The TrustDB is build from fixed length records, where the first bytes describes the record type. All numeric values are stored in network byte order. The length of each record is 40 bytes. The first record of @@ -74,7 +76,9 @@ Record type 2: we have control over the secret key too. Bit 3: set if key is revoked; do not use it. Bit 7-4: reserved - 3 byte reserved + 1 byte No signatures (used to avoid duplicate building). + FIXME: this should be moved to the cahce record + 2 byte reserved Record type 3: (cache record) diff --git a/g10/g10.c b/g10/g10.c index d36717a31..b9ce92564 100644 --- a/g10/g10.c +++ b/g10/g10.c @@ -191,6 +191,8 @@ main( int argc, char **argv ) { 532, "quick-random", 0, "\r"}, { 533, "list-trust-path",0, "\r"}, { 534, "no-comment", 0, "do not write comment packets"}, + { 535, "completes_needed", 1, "(default is 1)"}, + { 536, "marginals_needed", 1, "(default is 3)"}, {0} }; ARGPARSE_ARGS pargs; @@ -219,6 +221,8 @@ main( int argc, char **argv ) opt.def_cipher_algo = CIPHER_ALGO_BLOWFISH; opt.def_pubkey_algo = PUBKEY_ALGO_ELGAMAL; opt.def_digest_algo = DIGEST_ALGO_RMD160; + opt.completes_needed = 1; + opt.marginals_needed = 3; /* check wether we have a config file on the commandline */ orig_argc = argc; @@ -338,6 +342,8 @@ main( int argc, char **argv ) case 532: quick_random_gen(1); break; case 533: set_cmd( &cmd, aListTrustPath); break; case 534: opt.no_comment=1; break; + case 535: opt.completes_needed = pargs.r.ret_int; break; + case 536: opt.marginals_needed = pargs.r.ret_int; break; default : errors++; pargs.err = configfp? 1:2; break; } } @@ -360,9 +366,18 @@ main( int argc, char **argv ) log_error("selected digest algorithm is invalid\n"); errors++; } + if( opt.completes_needed < 1 ) { + log_error("completes_needed must be greater than 0\n"); + errors++; + } + if( opt.marginals_needed < 2 ) { + log_error("marginals_needed must be greater than 1\n"); + errors++; + } if( errors ) exit(2); + set_debug(); if( cmd == aKMode || cmd == aKModeC ) { /* kludge to be compatible to pgp */ if( cmd == aKModeC ) { diff --git a/g10/options.h b/g10/options.h index 7a9a4c587..ed0cc6579 100644 --- a/g10/options.h +++ b/g10/options.h @@ -40,8 +40,8 @@ struct { int def_pubkey_algo; int def_digest_algo; int no_comment; - int reserved10; - int reserved11; + int marginals_needed; + int completes_needed; int reserved12; int reserved13; int reserved14; diff --git a/g10/trustdb.c b/g10/trustdb.c index 4f8975107..f3396ab3c 100644 --- a/g10/trustdb.c +++ b/g10/trustdb.c @@ -66,6 +66,7 @@ struct trust_record { byte reserved; byte fingerprint[20]; byte ownertrust; + byte no_sigs; /* fixme: indicate a flag to */ } pubkey; struct { /* cache record */ @@ -94,7 +95,7 @@ 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 */ + unsigned sig_flag; /* returned signature record flag */ struct { /* internal data */ int eof; TRUSTREC rec; @@ -138,7 +139,7 @@ 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 int walk_sigrecs( SIGREC_CONTEXT *c, int create ); static LOCAL_ID_INFO *new_lid_table(void); static void release_lid_table( LOCAL_ID_INFO *tbl ); @@ -151,9 +152,11 @@ static int do_list_path( TRUST_INFO *stack, int depth, int max_depth, LOCAL_ID_INFO *lids, TRUST_SEG_LIST *tslist ); static int list_sigs( ulong pubkey_id ); +static int build_sigrecs( ulong pubkeyid, int kludge ); static int propagate_trust( TRUST_SEG_LIST tslist ); static int do_check( ulong pubkeyid, unsigned *trustlevel ); +static int update_no_sigs( ulong lid, int no_sigs ); static char *db_name; static int db_fd = -1; @@ -329,6 +332,7 @@ read_record( ulong recnum, TRUSTREC *rec ) rec->r.pubkey.reserved = *p++; memcpy( rec->r.pubkey.fingerprint, p, 20); p += 20; rec->r.pubkey.ownertrust = *p++; + rec->r.pubkey.no_sigs = *p++; if( rec->r.pubkey.local_id != recnum ) { log_error("%s: pubkey local_id != recnum (%lu,%lu)\n", db_name, @@ -399,6 +403,7 @@ write_record( ulong recnum, TRUSTREC *rec ) *p++ = rec->r.pubkey.reserved; memcpy( p, rec->r.pubkey.fingerprint, 20); p += 20; *p++ = rec->r.pubkey.ownertrust; + *p++ = rec->r.pubkey.no_sigs; assert( rec->r.pubkey.local_id == recnum ); break; case 3: @@ -563,8 +568,9 @@ dump_record( ulong rnum, TRUSTREC *rec, FILE *fp ) 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 ); + case 2: fprintf(fp, "pubkey, keyid=%08lX, ownertrust=%02x%s\n", + rec->r.pubkey.keyid[1], rec->r.pubkey.ownertrust, + rec->r.pubkey.no_sigs?" (inv sigs)":""); break; case 3: fprintf(fp, "cache\n"); case 4: @@ -674,9 +680,17 @@ list_trust_path( int max_depth, const char *username ) 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 { + else if( rc == -1 ) { + log_info("user '%s' not in trustdb - inserting\n", username); + rc = insert_trust_record( pkc ); + if( rc ) + log_error("failed to put '%s' into trustdb: %s\n", username, g10_errstr(rc)); + else { + assert( pkc->local_id ); + } + } + + if( !rc ) { TRUST_SEG_LIST tsl, tslist = NULL; if( !qry_lid_table_flag( ultikey_table, pkc->local_id, NULL ) ) { @@ -742,7 +756,7 @@ list_trust_path( int max_depth, const char *username ) * Returns: 0 - okay, -1 for eof (no more sigs) or any other errorcode */ static int -walk_sigrecs( SIGREC_CONTEXT *c ) +walk_sigrecs( SIGREC_CONTEXT *c, int create ) { int rc=0; TRUSTREC *r; @@ -753,6 +767,17 @@ walk_sigrecs( SIGREC_CONTEXT *c ) r = &c->ctl.rec; if( !r->rectype ) { /* this is the first call */ rc = scan_record( c->pubkey_id, r, 4, &rnum ); + if( rc == -1 && create ) { /* no signature records */ + rc = build_sigrecs( c->pubkey_id, 1 ); + if( rc ) { + if( rc != -1 ) + log_info("%lu: error building sigs on the fly: %s\n", + c->pubkey_id, g10_errstr(rc) ); + rc = -1; + } + else /* once more */ + rc = scan_record( c->pubkey_id, r, 4, &rnum ); + } if( rc == -1 ) { /* no signature records */ c->ctl.eof = 1; return -1; /* return eof */ @@ -997,7 +1022,7 @@ do_list_sigs( ulong root, ulong pubkey, int depth, memset( &sx, 0, sizeof sx ); sx.pubkey_id = pubkey; for(;;) { - rc = walk_sigrecs( &sx ); + rc = walk_sigrecs( &sx, 0 ); if( rc ) break; rc = keyid_from_local_id( sx.sig_id, keyid ); @@ -1090,7 +1115,9 @@ do_list_path( TRUST_INFO *stack, int depth, int max_depth, } memset( &sx, 0, sizeof sx ); sx.pubkey_id = stack[depth-1].lid; - while( !(rc = walk_sigrecs( &sx )) ) { + /* loop over all signatures. If we do not have any, try to + * create them */ + while( !(rc = walk_sigrecs( &sx, 1 )) ) { TRUST_SEG_LIST tsl, t2, tl; int i; @@ -1181,7 +1208,7 @@ check_sigs( KBNODE keyblock, int *selfsig_okay ) * to the trustdb */ static int -build_sigrecs( ulong pubkeyid ) +build_sigrecs( ulong pubkeyid, int kludge ) { TRUSTREC rec, rec2; PUBKEY_FIND_INFO finfo=NULL; @@ -1201,6 +1228,10 @@ build_sigrecs( ulong pubkeyid ) log_error("build_sigrecs: can't read pubkey record\n"); goto leave; } + if( kludge && rec.r.pubkey.no_sigs ) { + rc = -1; + goto leave; + } finfo = m_alloc_clear( sizeof *finfo ); finfo->keyid[0] = rec.r.pubkey.keyid[0]; finfo->keyid[1] = rec.r.pubkey.keyid[1]; @@ -1224,10 +1255,12 @@ build_sigrecs( ulong pubkeyid ) } if( !selfsig ) { log_error("build_sigrecs: self-certificate missing\n" ); + update_no_sigs( pubkeyid, 1 ); rc = G10ERR_BAD_CERT; goto leave; } + update_no_sigs( pubkeyid, 0 ); /* valid key signatures are now marked; we can now build the * sigrecs */ memset( &rec, 0, sizeof rec ); @@ -1241,7 +1274,9 @@ build_sigrecs( ulong pubkeyid ) /* 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. */ + * this can fail are I/o errors of the trustdb or a + * remove operation on the pubkey database - which should + * not disturb us, because we have to chace them anyway. */ rc = set_signature_packets_local_id( node->pkt->pkt.signature ); if( rc ) log_fatal("set_signature_packets_local_id failed: %s\n", @@ -1401,8 +1436,11 @@ do_check( ulong pubkeyid, unsigned *trustlevel ) TRUSTREC rec; TRUST_SEG_LIST tsl, tsl2, tslist; int marginal, fully; - int fully_needed = 4; - int marginal_needed = 6; + int fully_needed = opt.completes_needed; + int marginal_needed = opt.marginals_needed; + + assert( fully_needed > 0 && marginal_needed > 1 ); + *trustlevel = TRUST_UNDEFINED; @@ -1411,7 +1449,7 @@ do_check( ulong pubkeyid, unsigned *trustlevel ) /* do we have sigrecs */ rc = scan_record( pubkeyid, &rec, 4, &rnum ); if( rc == -1 ) { /* no sigrecs, so build them */ - rc = build_sigrecs( pubkeyid ); + rc = build_sigrecs( pubkeyid, 1 ); if( !rc ) /* and read again */ rc = scan_record( pubkeyid, &rec, 4, &rnum ); } @@ -1575,8 +1613,14 @@ check_trust( PKT_public_cert *pkc, unsigned *r_trustlevel ) return rc; } else if( rc == -1 ) { - log_error("check_trust: pubkey not in TrustDB\n"); - goto leave; + rc = insert_trust_record( pkc ); + if( rc ) { + log_error("failed to insert pubkey into trustdb: %s\n", + g10_errstr(rc)); + goto leave; + } + log_info("pubkey not in trustdb - inserted as %lu\n", + pkc->local_id ); } } /* fixme: do some additional checks on the pubkey record */ @@ -1735,6 +1779,7 @@ insert_trust_record( PKT_public_cert *pkc ) rec.r.pubkey.pubkey_algo = pkc->pubkey_algo; memcpy(rec.r.pubkey.fingerprint, fingerprint, fingerlen ); rec.r.pubkey.ownertrust = 0; + rec.r.pubkey.no_sigs = 0; if( write_record( recnum, &rec ) ) { log_error("insert_trust_record: write failed\n"); return G10ERR_TRUSTDB; @@ -1771,6 +1816,36 @@ update_ownertrust( ulong lid, unsigned new_trust ) } + +/**************** + * Kludge to prevent duplicate build_sigrecs() due to an invalid + * certificate (no selfsignature or something like this) + */ +static int +update_no_sigs( ulong lid, int no_sigs ) +{ + TRUSTREC rec; + + if( read_record( lid, &rec ) ) { + log_error("update_no_sigs: read failed\n"); + return G10ERR_TRUSTDB; + } + /* check keyid, fingerprint etc ? */ + if( rec.rectype != 2 ) { + log_error("update_no_sigs: invalid record type\n"); + return G10ERR_TRUSTDB; + } + + rec.r.pubkey.no_sigs = !!no_sigs; + if( write_record( lid, &rec ) ) { + log_error("update_no_sigs: write failed\n"); + return G10ERR_TRUSTDB; + } + + return 0; +} + + int verify_private_data() {