diff options
Diffstat (limited to 'g10/trustdb.c')
-rw-r--r-- | g10/trustdb.c | 255 |
1 files changed, 176 insertions, 79 deletions
diff --git a/g10/trustdb.c b/g10/trustdb.c index 916eeffd1..593e12cd2 100644 --- a/g10/trustdb.c +++ b/g10/trustdb.c @@ -42,6 +42,10 @@ #include "tdbio.h" +#if MAX_FINGERPRINT_LEN > 20 + #error Must change structure of trustdb +#endif + typedef struct local_id_info *LOCAL_ID_INFO; struct local_id_info { LOCAL_ID_INFO next; @@ -85,11 +89,10 @@ 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 ); +static int build_sigrecs( ulong local_id ); static int propagate_trust( TRUST_SEG_LIST tslist ); -static int do_check( ulong pubkeyid, TRUSTREC *drec, unsigned *trustlevel ); +static int do_check( TRUSTREC *drec, unsigned *trustlevel ); -static int update_no_sigs( ulong lid, int no_sigs ); /* a table used to keep track of ultimately trusted keys * which are the ones from our secrings */ @@ -186,12 +189,11 @@ set_signature_packets_local_id( PKT_signature *sig ) if( rc) goto leave; if( !pk->local_id ) { - rc = tdbio_search_record( pk, &rec ); + rc = tdbio_search_dir_record( pk, &rec ); if( rc == -1 ) rc = insert_trust_record( pk ); if( rc ) goto leave; - /* fixme: we should propagate the local_id to all copies of the PK */ } sig->local_id = pk->local_id; @@ -666,35 +668,36 @@ check_sigs( KBNODE keyblock, int *selfsig_okay, int *revoked ) * to the trustdb */ static int -build_sigrecs( ulong pubkeyid ) +build_sigrecs( ulong lid ) { TRUSTREC rec, krec, rec2; - KBNODE keyblock = NULL; - KBNODE node; + KBNODE keyblock = NULL; + KBNODE node; int rc=0; int i, selfsig, revoked; ulong rnum, rnum2; ulong first_sigrec = 0; if( DBG_TRUST ) - log_debug("trustdb: build_sigrecs for pubkey %lu\n", (ulong)pubkeyid ); + log_debug("trustdb: build_sigrecs for LID %lu\n", lid ); /* get the keyblock */ - if( (rc=tdbio_read_record( pubkeyid, &rec, RECTYPE_DIR )) ) { - log_error(_("%lu: build_sigrecs: can't read dir record\n"), pubkeyid ); + if( (rc=tdbio_read_record( lid, &rec, RECTYPE_DIR )) ) { + log_error( "build_sigrecs: can't read dir record %lu\n"), lid ); goto leave; } - if( (rc=tdbio_read_record( rec.r.dir.keyrec, &krec, RECTYPE_KEY )) ) { - log_error(_("%lu: build_sigrecs: can't read key record\n"), pubkeyid); + if( (rc=tdbio_read_record( rec.r.dir.keylist, &krec, RECTYPE_KEY )) ) { + log_error("build_sigrecs: can't read primary key record %lu\n"), lid); goto leave; } rc = get_keyblock_byfprint( &keyblock, krec.r.key.fingerprint, krec.r.key.fingerprint_len ); if( rc ) { - log_error(_("build_sigrecs: get_keyblock_byfprint failed: %s\n"), - g10_errstr(rc) ); + log_error( "build_sigrecs: keyblock for %lu not found: %s\n", + lid, g10_errstr(rc) ); goto leave; } + /* check all key signatures */ rc = check_sigs( keyblock, &selfsig, &revoked ); if( rc ) { @@ -703,19 +706,18 @@ build_sigrecs( ulong pubkeyid ) } if( !selfsig ) { log_error(_("build_sigrecs: self-signature missing\n") ); - update_no_sigs( pubkeyid, 2 ); + tdbio_update_sigflag( lid, 2 ); rc = G10ERR_BAD_CERT; goto leave; } if( revoked ) { log_info(_("build_sigrecs: key has been revoked\n") ); - update_no_sigs( pubkeyid, 3 ); + tdbio_update_sigflag( lid, 3 ); } else - update_no_sigs( pubkeyid, 0 ); /* assume we have sigs */ + tdbio_update_sigflag( lid, 0 ); /* assume we have sigs */ - /* valid key signatures are now marked; we can now build the - * sigrecs */ + /* valid key signatures are now marked; we can now build the sigrecs */ memset( &rec, 0, sizeof rec ); rec.rectype = RECTYPE_SIG; i = 0; @@ -740,8 +742,8 @@ build_sigrecs( ulong pubkeyid ) /* write the record */ rnum = tdbio_new_recnum(); if( rnum2 ) { /* write the stored record */ - rec2.r.sig.owner = pubkeyid; - rec2.r.sig.chain = rnum; /* the next record number */ + rec2.r.sig.lid = lid; + rec2.r.sig.next = rnum; /* the next record number */ rc = tdbio_write_record( rnum2, &rec2 ); if( rc ) { log_error(_("build_sigrecs: write_record failed\n") ); @@ -756,7 +758,7 @@ build_sigrecs( ulong pubkeyid ) rec.rectype = RECTYPE_SIG; i = 0; } - rec.r.sig.sig[i].local_id = node->pkt->pkt.signature->local_id; + rec.r.sig.sig[i].lid = node->pkt->pkt.signature->local_id; rec.r.sig.sig[i].flag = 0; i++; } @@ -765,8 +767,8 @@ build_sigrecs( ulong pubkeyid ) /* write the record */ rnum = tdbio_new_recnum(); if( rnum2 ) { /* write the stored record */ - rec2.r.sig.owner = pubkeyid; - rec2.r.sig.chain = rnum; + rec2.r.sig.lid = lid; + rec2.r.sig.next = rnum; rc = tdbio_write_record( rnum2, &rec2 ); if( rc ) { log_error(_("build_sigrecs: write_record failed\n") ); @@ -776,8 +778,8 @@ build_sigrecs( ulong pubkeyid ) first_sigrec = rnum2; } if( i ) { /* write the pending record */ - rec.r.sig.owner = pubkeyid; - rec.r.sig.chain = 0; + rec.r.sig.lid = lid; + rec.r.sig.next = 0; rc = tdbio_write_record( rnum, &rec ); if( rc ) { log_error(_("build_sigrecs: write_record failed\n") ); @@ -787,8 +789,7 @@ build_sigrecs( ulong pubkeyid ) first_sigrec = rnum; } } - if( first_sigrec ) { - /* update the dir record */ + if( first_sigrec ) { /* update the uid records */ if( (rc =tdbio_read_record( pubkeyid, &rec, RECTYPE_DIR )) ) { log_error(_("update_dir_record: read failed\n")); goto leave; @@ -800,7 +801,7 @@ build_sigrecs( ulong pubkeyid ) } } else - update_no_sigs( pubkeyid, revoked? 3:1 ); /* no signatures */ + tdbio_update_sigflag( lid, revoked? 3:1 ); /* no signatures */ leave: release_kbnode( keyblock ); @@ -900,12 +901,24 @@ propagate_trust( TRUST_SEG_LIST tslist ) } + /**************** - * we have the pubkey record but nothing more is known. - * (function may re-read dr) + * check whether we already build signature records + * Return: true if we have. */ static int -do_check( ulong pubkeyid, TRUSTREC *dr, unsigned *trustlevel ) +do_we_have_sigs( TRUSTREC *dr ) +{ +} + + +/**************** + * we have the pubkey record and all needed informations are in the trustdb + * but nothing more is known. + * (this function may re-read the dir record dr) + */ +static int +do_check( TRUSTREC *dr, unsigned *trustlevel ) { int i, rc=0; TRUST_SEG_LIST tsl, tsl2, tslist; @@ -919,16 +932,27 @@ do_check( ulong pubkeyid, TRUSTREC *dr, unsigned *trustlevel ) *trustlevel = TRUST_UNDEFINED; + if( !dr->r.dir.keylist ) { + log_error("Ooops, no keys\n"); + return G10ERR_TRUSTDB + } + if( !dr->r.dir.uidlist ) { + log_error("Ooops, no user ids\n"); + return G10ERR_TRUSTDB + } + /* verify the cache */ /* do we have sigrecs */ - if( !dr->r.dir.sigrec && !dr->r.dir.no_sigs) { - /* no sigrecs, so build them */ - rc = build_sigrecs( pubkeyid ); + if( !do_we_have_sigs( dr ) ) { /* no sigrecs, so build them */ + rc = build_sigrecs( dr->lid ); if( !rc ) /* and read again */ - rc = tdbio_read_record( pubkeyid, dr, RECTYPE_DIR ); + rc = tdbio_read_record( dr->lid, dr, RECTYPE_DIR ); } + + !!!!WORK!!!! + if( dr->r.dir.no_sigs == 3 ) tflags |= TRUST_FLAG_REVOKED; @@ -1199,9 +1223,7 @@ list_trust_path( int max_depth, const char *username ) * yes: return trustlevel from cache * no: make a cache record and all the other stuff * not found: - * Return with a trustlevel, saying that we do not have - * a trust record for it. The caller may use insert_trust_record() - * and then call this function here again. + * try to insert the pubkey into the trustdb and check again * * Problems: How do we get the complete keyblock to check that the * cache record is actually valid? Think we need a clever @@ -1225,17 +1247,17 @@ check_trust( PKT_public_key *pk, unsigned *r_trustlevel ) /* get the pubkey record */ if( pk->local_id ) { if( tdbio_read_record( pk->local_id, &rec, RECTYPE_DIR ) ) { - log_error(_("check_trust: read dir record failed\n")); + log_error("check_trust: read dir record failed\n"); return G10ERR_TRUSTDB; } } else { /* no local_id: scan the trustdb */ - if( (rc=tdbio_search_record( pk, &rec )) && rc != -1 ) { - log_error(_("check_trust: search_record failed: %s\n"), + if( (rc=tdbio_search_dir_record( pk, &rec )) && rc != -1 ) { + log_error("check_trust: search dir record failed: %s\n", g10_errstr(rc)); return rc; } - else if( rc == -1 ) { + else if( rc == -1 ) { /* not found - insert */ rc = insert_trust_record( pk ); if( rc ) { log_error(_("key %08lX: insert trust record failed: %s\n"), @@ -1263,7 +1285,7 @@ check_trust( PKT_public_key *pk, unsigned *r_trustlevel ) trustlevel = TRUST_EXPIRED; } else { - rc = do_check( pk->local_id, &rec, &trustlevel ); + rc = do_check( &rec, &trustlevel ); if( rc ) { log_error(_("key %08lX.%lu: trust check failed: %s\n"), keyid[1], pk->local_id, g10_errstr(rc)); @@ -1424,24 +1446,119 @@ query_trust_record( PKT_public_key *pk ) * This function fails if this record already exists. */ int -insert_trust_record( PKT_public_key *pk ) +insert_trust_record( PKT_public_key *orig_pk ) { - TRUSTREC rec; + TRUSTREC dirrec, *rec; + TRUSTREC **keylist_tail, *keylist; + TRUSTREC **uidlist_tail, *uidlist; + KBNODE keyblock = NULL; + KBNODE node; u32 keyid[2]; ulong knum, dnum; byte *fingerprint; size_t fingerlen; + int rc = 0; - if( pk->local_id ) + if( orig_pk->local_id ) log_bug("pk->local_id=%lu\n", (ulong)pk->local_id ); - keyid_from_pk( pk, keyid ); - fingerprint = fingerprint_from_pk( pk, &fingerlen ); + fingerprint = fingerprint_from_pk( orig_pk, &fingerlen ); + + /* fixme: assert that we do not have this record. + * we can do this by searching for the primary keyid + */ + + /* get the keyblock which has the key */ + rc = get_keyblock_byfprint( &keyblock, fingerprint, fingerlen ); + if( rc ) { /* that should never happen */ + log_error( "insert_trust_record: keyblock not found: %s\n", + g10_errstr(rc) ); + return rc; + } + + /* prepare dir record */ + memset( &dirrec, 0, sizeof dirrec ); + dirrec.rectype = RECTYPE_DIR; + dirrec.r.dir.lid = tdbio_new_recnum(); + + keylist = NULL; + keylist_tail = &dirrec.r.dir.keylist; + uidlist = NULL; + uidlist_tail = &dirrec.r.dir.uidlist; + /* loop over the keyblock */ + for( node=keyblock; node; node = node->next ) { + if( node->pkt->pkttype == PKT_PUBLIC_KEY + || node->pkt->pkttype == PKT_PUBLIC_SUBKEY ) { + PKT_public_key *pk = node->pkt->pkt.public_key; + + if( keylist && node->pkt->pkttype == PKT_PUBLIC_KEY ) + BUG(); /* more than one primary key */ + fingerprint = fingerprint_from_pk( orig_pk, &fingerlen ); + rec = m_alloc_clear( sizeof *rec ); + rec->r.key.pubkey_algo = pk->pubkey_algo; + rec->r.key.fingerprint_len = fingerlen; + memcpy(rec->r.key.fingerprint, fingerprint, fingerlen ); + + if( keylist ) + keylist_tail = &keylist->next; + *keylist_tail = keylist = rec; + } + else if( node->pkt->pkttype == PKT_USER_ID ) { + PKT_user_id *uid = node->pkt->pkt.user_id; + + rec = m_alloc_clear( sizeof *rec ); + rmd160_hash_buffer( rec->r.uid.namehash, uid->name, uid->len ); + + if( uidlist ) + uidlist_tail = &uidlist->next; + *uidlist_tail = uidlist = rec; + } + if( node->pkt->pkttype == PKT_SIGNATURE + && ( (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 ) { + 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( selfsig ) { + 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( 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", + (ulong)node->pkt->pkt.signature->keyid[1], + node->pkt->pkt.signature->local_id, + g10_errstr(rc), (node->flag&4)?" (dup)":"" ); + } + } + + + + + + + + - /* fixme: assert that we do not have this record. */ - dnum = tdbio_new_recnum(); knum = tdbio_new_recnum(); /* build dir record */ memset( &rec, 0, sizeof rec ); @@ -1451,10 +1568,6 @@ insert_trust_record( PKT_public_key *pk ) rec.r.dir.keyid[1] = keyid[1]; rec.r.dir.keyrec = knum; rec.r.dir.no_sigs = 0; - if( tdbio_write_record( dnum, &rec ) ) { - log_error("writing dir record failed\n"); - return G10ERR_TRUSTDB; - } /* and the key record */ memset( &rec, 0, sizeof rec ); rec.rectype = RECTYPE_KEY; @@ -1469,8 +1582,14 @@ insert_trust_record( PKT_public_key *pk ) log_error("wrinting key record failed\n"); return G10ERR_TRUSTDB; } + + if( tdbio_write_record( dirrec.r.dir.lid, &dirrec ) ) { + log_error("writing dir record failed\n"); + return G10ERR_TRUSTDB; + } + /* and store the LID */ - pk->local_id = dnum; + orig_pk->local_id = dnum; return 0; } @@ -1504,27 +1623,5 @@ 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( tdbio_read_record( lid, &rec, RECTYPE_DIR ) ) { - log_error("update_no_sigs: read failed\n"); - return G10ERR_TRUSTDB; - } - - rec.r.dir.no_sigs = no_sigs; - if( tdbio_write_record( lid, &rec ) ) { - log_error("update_no_sigs: write failed\n"); - return G10ERR_TRUSTDB; - } - - return 0; -} |