diff options
author | Werner Koch <[email protected]> | 1998-01-16 21:15:24 +0000 |
---|---|---|
committer | Werner Koch <[email protected]> | 1998-01-16 21:15:24 +0000 |
commit | 4ec1775f3eaf8733a5285460b631253b90d3c6fb (patch) | |
tree | 3061decd5793f93c5a51dab58cb45c8e79a26403 /g10/trustdb.c | |
parent | *** empty log message *** (diff) | |
download | gnupg-4ec1775f3eaf8733a5285460b631253b90d3c6fb.tar.gz gnupg-4ec1775f3eaf8733a5285460b631253b90d3c6fb.zip |
added some trust model stuff
Diffstat (limited to '')
-rw-r--r-- | g10/trustdb.c | 859 |
1 files changed, 765 insertions, 94 deletions
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"); |