aboutsummaryrefslogtreecommitdiffstats
path: root/g10/trustdb.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--g10/trustdb.c1335
1 files changed, 782 insertions, 553 deletions
diff --git a/g10/trustdb.c b/g10/trustdb.c
index 78b7b0aa0..18726f151 100644
--- a/g10/trustdb.c
+++ b/g10/trustdb.c
@@ -85,7 +85,7 @@ struct recno_list_struct {
typedef struct recno_list_struct *RECNO_LIST;
-static int walk_sigrecs( SIGREC_CONTEXT *c, int create );
+static int walk_sigrecs( SIGREC_CONTEXT *c );
static LOCAL_ID_INFO *new_lid_table(void);
static void release_lid_table( LOCAL_ID_INFO *tbl );
@@ -96,11 +96,11 @@ static void upd_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( TRUST_INFO *stack, int depth, int max_depth,
LOCAL_ID_INFO *lids, TRUST_SEG_LIST *tslist );
-static int update_sigs_by_lid( ulong lid );
static int list_sigs( ulong pubkey_id );
static int propagate_trust( TRUST_SEG_LIST tslist );
static int do_check( TRUSTREC *drec, unsigned *trustlevel );
+static int get_dir_record( PKT_public_key *pk, TRUSTREC *rec );
/* a table used to keep track of ultimately trusted keys
@@ -282,34 +282,6 @@ upd_lid_table_flag( LOCAL_ID_INFO *tbl, ulong lid, unsigned flag )
BUG();
}
-/****************
- * If we do not have a local_id in a signature packet, find the owner of
- * the signature packet in our trustdb or insert them into the trustdb
- */
-static int
-set_signature_packets_lid( PKT_signature *sig )
-{
- PKT_public_key *pk = m_alloc_clear( sizeof *pk );
- TRUSTREC rec;
- int rc;
-
- rc = get_pubkey( pk, sig->keyid );
- if( rc)
- goto leave;
- if( !pk->local_id ) {
- rc = tdbio_search_dir_bypk( pk, &rec );
- if( rc == -1 )
- rc = insert_trust_record( pk );
- if( rc )
- goto leave;
- }
- sig->local_id = pk->local_id;
-
- leave:
- free_public_key( pk );
- return rc;
-}
-
/****************
@@ -343,6 +315,24 @@ keyid_from_lid( ulong lid, u32 *keyid )
return 0;
}
+
+ulong
+lid_from_keyblock( KBNODE keyblock )
+{
+ KBNODE node = find_kbnode( keyblock, PKT_PUBLIC_KEY );
+ PKT_public_key *pk;
+ if( !node )
+ BUG();
+ pk = node->pkt->pkt.public_key;
+ if( !pk->local_id ) {
+ TRUSTREC rec;
+
+ get_dir_record( pk, &rec );
+ }
+ return pk->local_id;
+}
+
+
/****************
@@ -356,9 +346,8 @@ keyid_from_lid( ulong lid, u32 *keyid )
* Returns: 0 - okay, -1 for eof (no more sigs) or any other errorcode
*/
static int
-walk_sigrecs( SIGREC_CONTEXT *c, int create )
+walk_sigrecs( SIGREC_CONTEXT *c )
{
- int rc=0;
TRUSTREC *r;
ulong rnum;
@@ -380,20 +369,6 @@ walk_sigrecs( SIGREC_CONTEXT *c, int create )
rnum = r->r.sig.next;
if( !rnum && c->ctl.nextuid ) { /* read next uid record */
read_record( c->ctl.nextuid, r, RECTYPE_UID );
- if( !r->r.uid.siglist && create ) {
- rc = update_sigs_by_lid( c->lid );
- if( rc ) {
- if( rc == G10ERR_BAD_CERT )
- rc = -1; /* maybe no selfsignature */
- if( rc != -1 )
- log_info("LID %lu: "
- "error building sigs on the fly: %s\n",
- c->lid, g10_errstr(rc) );
- c->ctl.eof = 1;
- return rc;
- }
- read_record( c->ctl.nextuid, r, RECTYPE_UID );
- }
c->ctl.nextuid = r->r.uid.next;
rnum = r->r.uid.siglist;
}
@@ -557,7 +532,7 @@ do_list_sigs( ulong root, ulong pubkey, int depth,
memset( &sx, 0, sizeof sx );
sx.lid = pubkey;
for(;;) {
- rc = walk_sigrecs( &sx, 0 );
+ rc = walk_sigrecs( &sx );
if( rc )
break;
rc = keyid_from_lid( sx.sig_lid, keyid );
@@ -716,7 +691,7 @@ do_list_path( TRUST_INFO *stack, int depth, int max_depth,
memset( &sx, 0, sizeof sx );
sx.lid = stack[depth-1].lid;
/* loop over all signatures. If we do not have any, try to create them */
- while( !(rc = walk_sigrecs( &sx, 1 )) ) {
+ while( !(rc = walk_sigrecs( &sx )) ) {
TRUST_SEG_LIST tsl, t2, tl;
int i;
@@ -767,291 +742,6 @@ do_list_path( TRUST_INFO *stack, int depth, int max_depth,
/****************
- * find the uid record given the uid packet and the dir-record.
- * Returns: 0 = found
- * -1 = No such uid-record
- * or other error
- */
-static int
-find_urec( TRUSTREC *dir, PKT_user_id *uid, TRUSTREC *urec )
-{
- byte nhash[20];
- ulong recno;
-
- assert(dir->rectype == RECTYPE_DIR );
- rmd160_hash_buffer( nhash, uid->name, uid->len );
- for( recno=dir->r.dir.uidlist; recno; recno = urec->r.uid.next ) {
- read_record( recno, urec, RECTYPE_UID );
- if( !memcmp( nhash, urec->r.uid.namehash, 20 ) )
- return 0;
- }
-
- return -1;
-}
-
-
-/****************
- * Test whether zthe signature lid is already in the (in mem) list.
- * Returns: True if it is a duplicate
- */
-static int
-test_dupsig( TRUSTREC *rec, ulong lid )
-{
- int i;
- ulong alid;
-
- for( ; rec; rec = rec->next ) {
- for(i=0; i < SIGS_PER_RECORD && (alid = rec->r.sig.sig[i].lid); i++ )
- if( alid == lid )
- return 1;
- }
- return 0;
-}
-
-
-/****************
- * release the sigrec from the uidlist
- */
-static void
-rel_uidsigs( TRUSTREC *urec )
-{
- TRUSTREC *r2, *rec;
- assert( urec->rectype == RECTYPE_UID );
-
- for(rec=urec->next ; rec; rec = r2 ) {
- assert( rec->rectype == RECTYPE_SIG );
- r2 = rec->next;
- m_free( rec );
- }
- urec->next = NULL;
-}
-
-static int
-no_selfsig_del( ulong lid, u32 *keyid, TRUSTREC *urec )
-{
- int rc;
-
- log_error("key %08lX.%lu, uid %02X%02X: "
- "no self-signature - user id removed\n",
- (ulong)keyid[1], lid, urec->r.uid.namehash[18],
- urec->r.uid.namehash[19] );
- rel_uidsigs( urec );
- rc = tdbio_delete_uidrec( lid, urec->recnum );
- if( rc )
- log_error("no_selfsig_del: delete_uid %lu failed: %s\n",
- lid, g10_errstr(rc) );
- return rc;
-}
-
-/****************
- * Write the signature records from the in-mem list at urec
- * (The sequence of signatures does not matter)
- */
-static int
-write_sigs_from_urec( ulong lid, u32 *keyid, TRUSTREC *urec )
-{
- TRUSTREC *rec, srec;
- ulong nextrecno;
- ulong recno;
-
- nextrecno = urec->r.uid.siglist;
- urec->r.uid.siglist = 0; /* end of list marker */
- for( rec = urec->next; rec; rec = rec->next ) {
- assert( rec->rectype == RECTYPE_SIG );
- if( nextrecno ) { /* read the sig record, so it can be reused */
- read_record( nextrecno, &srec, RECTYPE_SIG );
- recno = nextrecno;
- nextrecno = srec.r.sig.next;
- }
- else
- recno = tdbio_new_recnum();
-
- /* link together (the sequence of signatures does not matter) */
- rec->r.sig.next = urec->r.uid.siglist;
- urec->r.uid.siglist = recno;
- rec->r.sig.lid = lid;
- /* and write */
- rec->recnum = recno;
- write_record( rec );
- }
-
- /* write the urec back */
- write_record( urec );
-
- /* delete remaining old sigrecords */
- while( nextrecno ) {
- read_record( nextrecno, &srec, RECTYPE_SIG );
- delete_record( nextrecno );
- nextrecno = srec.r.sig.next;
- }
-
- return 0;
-}
-
-/****************
- * If we do not have sigrecs for the given key, build them and write them
- * to the trustdb
- */
-static int
-update_sigs( TRUSTREC *dir )
-{
- TRUSTREC *rec, krec;
- TRUSTREC urec;
- TRUSTREC *sigrec_list;
- KBNODE keyblock = NULL;
- KBNODE node;
- int i, sigidx, have_urec ;
- ulong lid = dir->r.dir.lid;
- u32 keyid[2];
- int miskey=0;
- int rc=0;
-
- if( DBG_TRUST )
- log_debug("update_sigs for %lu\n", lid );
-
- read_record( dir->r.dir.keylist, &krec, RECTYPE_KEY );
- rc = get_keyblock_byfprint( &keyblock, krec.r.key.fingerprint,
- krec.r.key.fingerprint_len );
- if( rc ) {
- log_error( "update_sigs: keyblock for %lu not found: %s\n",
- lid, g10_errstr(rc) );
- goto leave;
- }
-
- /* check all key signatures */
- assert( keyblock->pkt->pkttype == PKT_PUBLIC_KEY );
- have_urec = 0;
- sigrec_list = NULL;
- sigidx = 0;
- for( node=keyblock; node; node = node->next ) {
- if( node->pkt->pkttype == PKT_PUBLIC_KEY )
- keyid_from_pk( node->pkt->pkt.public_key, keyid );
- else if( node->pkt->pkttype == PKT_USER_ID ) {
- if( have_urec && !(urec.mark & 1) ) {
- if( (rc = no_selfsig_del(lid, keyid, &urec )) )
- goto leave;
- have_urec = 0;
- }
- if( have_urec ) {
- rc = write_sigs_from_urec( lid, keyid, &urec );
- if( rc )
- goto leave;
- rel_uidsigs( &urec );
- }
- rc = find_urec( dir, node->pkt->pkt.user_id, &urec );
- urec.next = NULL;
- urec.mark = 0;
- have_urec = sigidx = 0;
- if( rc == -1 ) {
- log_info("update_sigs: new user id for %lu\n", lid );
- /* fixme: we should add the new user id here */
- }
- else if( rc ) {
- log_error("update_sigs: find_urec %lu failed: %s\n",
- lid, g10_errstr(rc) );
- goto leave;
- }
- else
- have_urec = 1;
- }
- else if( have_urec && node->pkt->pkttype == PKT_SIGNATURE ) {
- PKT_signature *sig = node->pkt->pkt.signature;
-
- if( (sig->sig_class&~3) == 0x10 ) {
- rc = check_key_signature( keyblock, node, &i );
- if( rc == G10ERR_NO_PUBKEY ) {
- if( opt.verbose )
- log_info(_("key %08lX.%lu, uid %02X%02X: "
- "no public key for signature %08lX\n"),
- (ulong)keyid[1], lid, urec.r.uid.namehash[18],
- urec.r.uid.namehash[19], (ulong)sig->keyid[1] );
- miskey = 1;
- }
- else if( rc )
- log_info(_("key %08lX.%lu, uid %02X%02X: "
- "invalid %ssignature: %s\n"),
- (ulong)keyid[1], lid, urec.r.uid.namehash[18],
- urec.r.uid.namehash[19],
- i?"self-":"",g10_errstr(rc));
- else if( i ) /* mark that we have a valid selfsignature */
- urec.mark |= 1;
- else if( (rc = set_signature_packets_lid( sig )) )
- log_error("key %08lX.%lu, uid %02X%02X: "
- "can't get LID of signer: %s\n",
- (ulong)keyid[1], lid, urec.r.uid.namehash[18],
- urec.r.uid.namehash[19], g10_errstr(rc));
- else if( !test_dupsig( urec.next, sig->local_id ) ) {
- /* put the valid signature into a list */
- rec = urec.next;
- if( !rec || sigidx == SIGS_PER_RECORD ) {
- rec = m_alloc_clear( sizeof *rec );
- rec->rectype = RECTYPE_SIG;
- rec->next = urec.next;
- urec.next = rec;
- sigidx = 0;
- }
- rec->r.sig.sig[sigidx].lid = sig->local_id;
- rec->r.sig.sig[sigidx].flag = 0;
- sigidx++;
- if( DBG_TRUST )
- log_debug("key %08lX.%lu, uid %02X%02X: "
- "signed by LID %lu\n",
- (ulong)keyid[1], lid, urec.r.uid.namehash[18],
- urec.r.uid.namehash[19], sig->local_id);
- }
- else if( DBG_TRUST )
- log_debug("key %08lX.%lu, uid %02X%02X: "
- "duplicate signature by LID %lu\n",
- (ulong)keyid[1], lid, urec.r.uid.namehash[18],
- urec.r.uid.namehash[19], sig->local_id );
- rc = 0;
- }
- else {
- /* fixme: handle other sig classes here */
- /* FIXME: Revocations!!! */
- }
- }
- }
- if( have_urec && !(urec.mark & 1) ) {
- if( (rc = no_selfsig_del(lid, keyid, &urec )) )
- goto leave;
- have_urec = 0;
- }
- if( have_urec ) {
- rc = write_sigs_from_urec( lid, keyid, &urec );
- if( rc )
- goto leave;
- rel_uidsigs( &urec );
- }
- dir->r.dir.dirflags |= DIRF_CHECKED;
- if( miskey )
- dir->r.dir.dirflags |= DIRF_MISKEY;
- else
- dir->r.dir.dirflags &= ~DIRF_MISKEY;
- write_record( dir );
-
- leave:
- /* fixme: need more cleanup in case of an error */
- release_kbnode( keyblock );
- if( DBG_TRUST )
- log_debug("update_sigs for %lu: %s\n", lid, g10_errstr(rc) );
- return rc;
-}
-
-
-static int
-update_sigs_by_lid( ulong lid )
-{
- int rc;
- TRUSTREC rec;
-
- read_record( lid, &rec, RECTYPE_DIR );
- if( !(rec.r.dir.dirflags & DIRF_CHECKED) )
- rc = update_sigs( &rec );
- return rc;
-}
-
-/****************
* Make a list of trust paths
*/
static int
@@ -1170,8 +860,7 @@ do_check( TRUSTREC *dr, unsigned *trustlevel )
}
/* did we already check the signatures */
- if( !(dr->r.dir.dirflags & DIRF_CHECKED) ) /* no - do it now */
- rc = update_sigs( dr );
+ /* fixme:.... */
if( dr->r.dir.dirflags & DIRF_REVOKED )
tflags |= TRUST_FLAG_REVOKED;
@@ -1557,55 +1246,111 @@ list_trust_path( int max_depth, const char *username )
/****************
- * Check the complete trustdb or only the entries for the given username
- * FIXME: We need a mode which only looks at keys with the MISKEY flag set.
+ * Check the complete trustdb or only the entries for the given username.
+ * Special hack: A username "REBUILD" inserts all records from the public
+ * key rings into the trustdb.
*/
void
check_trustdb( const char *username )
{
TRUSTREC rec;
+ KBNODE keyblock = NULL;
+ KBPOS kbpos;
int rc;
+ int rebuild = username && !strcmp(username, "REBUILD");
- if( username && *username == '#' ) {
- int rc;
- ulong lid = atoi(username+1);
+ if( username && !rebuild ) {
+ rc = find_keyblock_byname( &kbpos, username );
+ if( !rc )
+ rc = read_keyblock( &kbpos, &keyblock );
+ if( rc ) {
+ log_error("%s: keyblock read problem: %s\n",
+ username, g10_errstr(rc));
+ }
+ else {
+ rc = update_trust_record( keyblock );
+ if( rc == -1 ) { /* not yet in trustdb: insert */
+ rc = insert_trust_record(
+ find_kbnode( keyblock, PKT_PUBLIC_KEY
+ ) ->pkt->pkt.public_key );
- if( (rc = update_sigs_by_lid( lid )) )
- log_error("lid %lu: check failed: %s\n",
- lid, g10_errstr(rc));
- else
- log_info("lid %lu: checked: %s\n", lid, g10_errstr(rc));
- }
- else if( username ) {
- PKT_public_key *pk = m_alloc_clear( sizeof *pk );
+ }
+ if( rc )
+ log_error("%s: update failed: %s\n",
+ username, g10_errstr(rc) );
+ else
+ log_info("%s: updated\n", username );
- if( (rc = get_pubkey_byname( pk, username )) )
- log_error("user '%s' not found: %s\n", username, g10_errstr(rc) );
- else if( (rc=tdbio_search_dir_bypk( pk, &rec )) && 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 = update_sigs( &rec )) )
- log_error("lid %lu: check failed: %s\n",
- rec.recnum, g10_errstr(rc));
- else
- log_info("lid %lu: checked: %s\n", rec.recnum, g10_errstr(rc));
- free_public_key( pk );
+ }
+ release_kbnode( keyblock ); keyblock = NULL;
}
else {
ulong recnum;
for(recnum=0; !tdbio_read_record( recnum, &rec, 0); recnum++ ) {
if( rec.rectype == RECTYPE_DIR ) {
- rc = update_sigs( &rec );
+ TRUSTREC tmp;
+ if( !rec.r.dir.keylist ) {
+ log_info("lid %lu: dir record w/o key - skipped\n", recnum);
+ continue;
+ }
+
+ read_record( rec.r.dir.keylist, &tmp, RECTYPE_KEY );
+
+ rc = get_keyblock_byfprint( &keyblock,
+ tmp.r.key.fingerprint,
+ tmp.r.key.fingerprint_len );
+ if( rc ) {
+ log_error("lid %lu: keyblock not found: %s\n",
+ recnum, g10_errstr(rc) );
+ continue;
+ }
+ rc = update_trust_record( keyblock );
if( rc )
- log_error("lid %lu: check failed: %s\n",
+ log_error("lid %lu: update failed: %s\n",
recnum, g10_errstr(rc) );
else
- log_info("lid %lu: checked\n", recnum );
+ log_info("lid %lu: updated\n", recnum );
+
+ release_kbnode( keyblock ); keyblock = NULL;
}
}
+ if( rebuild ) {
+ log_info("adding new entries.\n");
+
+ rc = enum_keyblocks( 0, &kbpos, &keyblock );
+ if( !rc ) {
+ while( !(rc = enum_keyblocks( 1, &kbpos, &keyblock )) ) {
+ rc = update_trust_record( keyblock );
+ if( rc == -1 ) { /* not yet in trustdb: insert */
+ PKT_public_key *pk =
+ find_kbnode( keyblock, PKT_PUBLIC_KEY
+ ) ->pkt->pkt.public_key;
+ rc = insert_trust_record( pk );
+ if( rc && !pk->local_id )
+ log_error("lid ?: insert failed: %s\n",
+ g10_errstr(rc) );
+ else if( rc )
+ log_error("lid %lu: insert failed: %s\n",
+ pk->local_id, g10_errstr(rc) );
+ else
+ log_info("lid %lu: inserted\n", pk->local_id );
+ }
+ else if( rc )
+ log_error("lid %lu: update failed: %s\n",
+ lid_from_keyblock(keyblock), g10_errstr(rc) );
+ else
+ log_info("lid %lu: updated\n",
+ lid_from_keyblock(keyblock) );
+ }
+ }
+ if( rc && rc != -1 )
+ log_error("enum_keyblocks failed: %s\n", g10_errstr(rc));
+
+ enum_keyblocks( 2, &kbpos, &keyblock ); /* close */
+ release_kbnode( keyblock );
+ }
+
}
}
@@ -1929,11 +1674,601 @@ clear_trust_checked_flag( PKT_public_key *pk )
+
+static void
+check_hint_sig( ulong lid, KBNODE keyblock, u32 *keyid, byte *uidrec_hash,
+ TRUSTREC *sigrec, int sigidx, ulong hint_owner )
+{
+ KBNODE node;
+ int rc, state=0;
+ byte uhash[20];
+ int is_selfsig;
+ PKT_signature *sigpkt = NULL;
+
+ if( sigrec->r.sig.sig[sigidx].flag & SIGF_CHECKED )
+ log_info(_("note: sig rec %lu[%d] in hintlist "
+ "of %lu but marked as checked\n"),
+ sigrec->recnum, sigidx, hint_owner );
+ if( !(sigrec->r.sig.sig[sigidx].flag & SIGF_NOPUBKEY) )
+ log_info(_("note: sig rec %lu[%d] in hintlist "
+ "of %lu but not marked\n"),
+ sigrec->recnum, sigidx, hint_owner );
+
+ /* find the correct signature packet */
+ for( node=keyblock; node; node = node->next ) {
+ if( node->pkt->pkttype == PKT_USER_ID ) {
+ PKT_user_id *uidpkt = node->pkt->pkt.user_id;
+
+ if( state )
+ break;
+ rmd160_hash_buffer( uhash, uidpkt->name, uidpkt->len );
+ if( !memcmp( uhash, uidrec_hash, 20 ) )
+ state = 1;
+ }
+ else if( state && node->pkt->pkttype == PKT_SIGNATURE ) {
+ sigpkt = node->pkt->pkt.signature;
+ if( sigpkt->keyid[0] == keyid[0]
+ && sigpkt->keyid[1] == keyid[1]
+ && (sigpkt->sig_class&~3) == 0x10 )
+ break; /* found */
+ }
+ }
+
+ if( !node ) {
+ log_error(_("lid %lu: user id not found in keyblock\n"), lid );
+ return ;
+ }
+
+ /* and check the sig */
+ rc = check_key_signature( keyblock, node, &is_selfsig );
+ if( is_selfsig ) {
+ log_error(_("lid %lu: self-signature in hintlist\n"), lid );
+ return ;
+ }
+ if( !rc ) { /* valid signature */
+ sigrec->r.sig.sig[sigidx].flag = SIGF_CHECKED | SIGF_VALID;
+ }
+ else if( rc == G10ERR_NO_PUBKEY ) {
+ log_info(_("key %08lX.%lu, uid %02X%02X: "
+ "very strange: no public key for signature %08lX\n"),
+ (ulong)keyid[1], lid, uhash[18], uhash[19],
+ (ulong)sigpkt->keyid[1] );
+ sigrec->r.sig.sig[sigidx].flag = SIGF_NOPUBKEY;
+ }
+ else {
+ log_info(_("key %08lX.%lu, uid %02X%02X: "
+ "invalid signature: %s\n"),
+ (ulong)keyid[1], lid,
+ uhash[18], uhash[19], g10_errstr(rc));
+ sigrec->r.sig.sig[sigidx].flag = SIGF_CHECKED;
+ }
+ sigrec->dirty = 1;
+}
+
+
+/****************
+ * Process a hintlist.
+ * Fixme: this list is not anymore anchored to another
+ * record, so it should be put elsewehere in case of an error
+ */
+static void
+process_hintlist( ulong hintlist, ulong hint_owner )
+{
+ ulong hlst_rn;
+ int rc;
+
+ for( hlst_rn = hintlist; hlst_rn; ) {
+ TRUSTREC hlstrec;
+ int hlst_idx;
+
+ read_record( hlst_rn, &hlstrec, RECTYPE_HLST );
+
+ for( hlst_idx=0; hlst_idx < ITEMS_PER_HLST_RECORD; hlst_idx++ ) {
+ TRUSTREC dirrec;
+ TRUSTREC uidrec;
+ TRUSTREC tmprec;
+ KBNODE keyblock = NULL;
+ u32 keyid[2];
+ ulong lid;
+ ulong r1, r2;
+
+ lid = hlstrec.r.hlst.rnum[hlst_idx];
+ if( !lid )
+ continue;
+
+ read_record( lid, &dirrec, 0 );
+ /* make sure it points to a dir record:
+ * this should be true because it only makes sense to
+ * call this function if the dir record is available */
+ if( dirrec.rectype != RECTYPE_DIR ) {
+ log_error(_("hintlist %lu[%d] of %lu "
+ "does not point to a dir record\n"),
+ hlst_rn, hlst_idx, hint_owner );
+ continue;
+ }
+ if( !dirrec.r.dir.keylist ) {
+ log_error(_("lid %lu does not have a key\n"), lid );
+ continue;
+ }
+
+ /* get the keyblock */
+ read_record( dirrec.r.dir.keylist, &tmprec, RECTYPE_KEY );
+ rc = get_keyblock_byfprint( &keyblock,
+ tmprec.r.key.fingerprint,
+ tmprec.r.key.fingerprint_len );
+ if( rc ) {
+ log_error(_("lid %lu: can't get keyblock: %s\n"),
+ lid, g10_errstr(rc) );
+ continue;
+ }
+ keyid_from_fingerprint( tmprec.r.key.fingerprint,
+ tmprec.r.key.fingerprint_len, keyid );
+
+ /* Walk over all user ids and their signatures and check all
+ * the signature which are created by hint_owner */
+ for( r1 = dirrec.r.dir.uidlist; r1; r1 = uidrec.r.uid.next ) {
+ TRUSTREC sigrec;
+
+ read_record( r1, &uidrec, RECTYPE_UID );
+ for( r2 = uidrec.r.uid.siglist; r2; r2 = sigrec.r.sig.next ) {
+ int i;
+
+ read_record( r2, &sigrec, RECTYPE_SIG );
+ sigrec.dirty = 0;
+ for(i=0; i < SIGS_PER_RECORD; i++ ) {
+ if( !sigrec.r.sig.sig[i].lid )
+ continue; /* skip deleted sigs */
+ if( sigrec.r.sig.sig[i].lid != hint_owner )
+ continue; /* not for us */
+ /* some diagnostic messages */
+ /* and do the signature check */
+ check_hint_sig( lid, keyblock, keyid,
+ uidrec.r.uid.namehash,
+ &sigrec, i, hint_owner );
+ }
+ if( sigrec.dirty )
+ write_record( &sigrec );
+ }
+ }
+ release_kbnode( keyblock );
+ } /* loop over hlst entries */
+
+ /* delete this hlst record */
+ hlst_rn = hlstrec.r.hlst.next;
+ delete_record( hlstrec.recnum );
+ } /* loop over hintlist */
+}
+
+
+
+static void
+upd_key_record( PKT_public_key *pk, TRUSTREC *drec, RECNO_LIST *recno_list )
+{
+ TRUSTREC krec;
+ byte fpr[MAX_FINGERPRINT_LEN];
+ size_t fprlen;
+ ulong recno, newrecno;
+
+ fingerprint_from_pk( pk, fpr, &fprlen );
+ /* do we already have this key? */
+ for( recno=drec->r.dir.keylist; recno; recno = krec.r.key.next ) {
+ read_record( recno, &krec, RECTYPE_KEY );
+ if( krec.r.key.fingerprint_len == fprlen
+ && !memcmp( krec.r.key.fingerprint, fpr, fprlen ) )
+ break;
+ }
+ if( recno ) { /* yes */
+ ins_recno_list( recno_list, recno, RECTYPE_KEY );
+ /* here we would compare/update the keyflags */
+ }
+ else { /* no: insert this new key */
+ memset( &krec, 0, sizeof(krec) );
+ krec.rectype = RECTYPE_KEY;
+ krec.r.key.lid = drec->recnum;
+ krec.r.key.pubkey_algo = pk->pubkey_algo;
+ krec.r.key.fingerprint_len = fprlen;
+ memcpy(krec.r.key.fingerprint, fpr, fprlen );
+ krec.recnum = newrecno = tdbio_new_recnum();
+ write_record( &krec );
+ ins_recno_list( recno_list, newrecno, RECTYPE_KEY );
+ /* and put this new record at the end of the keylist */
+ if( !(recno=drec->r.dir.keylist) ) {
+ /* this is the first key */
+ drec->r.dir.keylist = newrecno;
+ drec->dirty = 1;
+ }
+ else { /* we already have a key, append it to the list */
+ for( ; recno; recno = krec.r.key.next )
+ read_record( recno, &krec, RECTYPE_KEY );
+ krec.r.key.next = newrecno;
+ write_record( &krec );
+ }
+ }
+}
+
+
+static void
+upd_uid_record( PKT_user_id *uid, TRUSTREC *drec, RECNO_LIST *recno_list,
+ u32 *keyid, ulong *uidrecno, byte *uidhash )
+{
+ TRUSTREC urec;
+ ulong recno, newrecno;
+
+ rmd160_hash_buffer( uidhash, uid->name, uid->len );
+ for( recno=drec->r.dir.uidlist; recno; recno = urec.r.uid.next ) {
+ read_record( recno, &urec, RECTYPE_UID );
+ if( !memcmp( uidhash, urec.r.uid.namehash, 20 ) )
+ break;
+ }
+ if( recno ) {
+ ins_recno_list( recno_list, recno, RECTYPE_UID );
+ *uidrecno = recno;
+ }
+ else { /* new user id */
+ memset( &urec, 0 , sizeof(urec) );
+ urec.rectype = RECTYPE_UID;
+ urec.r.uid.lid = drec->recnum;
+ memcpy(urec.r.uid.namehash, uidhash, 20 );
+ urec.recnum = newrecno = tdbio_new_recnum();
+ write_record( &urec );
+ ins_recno_list( recno_list, newrecno, RECTYPE_UID );
+ /* and put this new record at the end of the uidlist */
+ if( !(recno=drec->r.dir.uidlist) ) { /* this is the first uid */
+ drec->r.dir.uidlist = newrecno;
+ drec->dirty = 1;
+ }
+ else { /* we already have an uid, append it to the list */
+ for( ; recno; recno = urec.r.key.next )
+ read_record( recno, &urec, RECTYPE_UID );
+ urec.r.uid.next = newrecno;
+ write_record( &urec );
+ }
+ *uidrecno = newrecno;
+ }
+}
+
+
+static void
+upd_pref_record( PKT_signature *sig, TRUSTREC *drec,
+ u32 *keyid, ulong *uidrecno, byte *uidhash )
+{
+ static struct {
+ sigsubpkttype_t subpkttype;
+ int preftype;
+ } prefs[] = {
+ { SIGSUBPKT_PREF_SYM, PREFTYPE_SYM },
+ { SIGSUBPKT_PREF_HASH, PREFTYPE_HASH },
+ { SIGSUBPKT_PREF_COMPR, PREFTYPE_COMPR },
+ { 0, 0 }
+ };
+ TRUSTREC urec, prec;
+ const byte *s;
+ size_t n;
+ int k, i;
+ ulong recno_tbl[10];
+ int recno_idx = 0;
+ ulong recno;
+
+ /* we need the uid record */
+ read_record( *uidrecno, &urec, RECTYPE_UID );
+
+ /* First delete all pref records
+ * This is much simpler than checking whether we have to
+ * do update the record at all - the record cache may care about it */
+ for( recno=urec.r.uid.prefrec; recno; recno = prec.r.pref.next ) {
+ read_record( recno, &prec, RECTYPE_PREF );
+ delete_record( recno );
+ }
+
+ /* and write the new ones */
+ i = 0;
+ for(k=0; prefs[k].subpkttype; k++ ) {
+ s = parse_sig_subpkt2( sig, prefs[k].subpkttype, &n );
+ if( s ) {
+ while( n ) {
+ if( !i || i >= ITEMS_PER_PREF_RECORD ) {
+ if( recno_idx >= DIM(recno_tbl)-1 ) {
+ log_info("too many preferences\n");
+ break;
+ }
+ if( i ) {
+ recno_tbl[recno_idx]=tdbio_new_recnum();
+ prec.recnum = recno_tbl[recno_idx++];
+ write_record( &prec );
+ }
+ memset( &prec, 0, sizeof prec );
+ prec.rectype = RECTYPE_PREF;
+ prec.r.pref.lid = drec->recnum;
+ i = 0;
+ }
+ prec.r.pref.data[i++] = prefs[k].preftype;
+ prec.r.pref.data[i++] = *s++;
+ n--;
+ }
+ }
+ }
+ if( i ) { /* write the last one */
+ recno_tbl[recno_idx]=tdbio_new_recnum();
+ prec.recnum = recno_tbl[recno_idx++];
+ write_record( &prec );
+ }
+ /* now link them together */
+ for(i=0; i < recno_idx-1; i++ ) {
+ read_record( recno_tbl[i], &prec, RECTYPE_PREF );
+ prec.r.pref.next = recno_tbl[i+1];
+ write_record( &prec );
+ }
+ /* don't need to write the last one, but update the uid */
+ urec.r.uid.prefrec = recno_idx? recno_tbl[0] : 0;
+ write_record( &urec );
+}
+
+
+
/****************
- * Update all the info from the public keyblock, the signatures-checked
- * flag is reset. The key must already exist in the keydb.
- *
- * Implementation of this function needs a cache for tdbio record updates
+ * Note: A signature made with a secondayr key is not considered a
+ * self-signature.
+ */
+static void
+upd_sig_record( PKT_signature *sig, TRUSTREC *drec,
+ u32 *keyid, ulong *uidrecno, byte *uidhash,
+ KBNODE keyblock, KBNODE signode )
+{
+ int rc;
+ ulong lid = drec->recnum;
+
+ if( keyid[0] == sig->keyid[0] && keyid[1] == sig->keyid[1] ) {
+ if( (sig->sig_class&~3) == 0x10 ) {
+ /* must verify this selfsignature here, so that we can
+ * build the preference record and validate the uid record
+ */
+ if( !*uidrecno ) {
+ log_error("key %08lX: self-signature without user id\n",
+ (ulong)keyid[1] );
+ }
+ else if( (rc = check_key_signature( keyblock, signode, NULL ))) {
+ log_error("key %08lX, uid %02X%02X: "
+ "invalid self-signature: %s\n", (ulong)keyid[1],
+ uidhash[18], uidhash[19], g10_errstr(rc) );
+ }
+ else { /* valid sig (may be revoked, but that doesn't matter here) */
+ upd_pref_record( sig, drec, keyid, uidrecno, uidhash );
+ }
+ }
+ else {/* is revocation sig etc */
+ /* FIXME */
+ }
+ }
+ else if( !*uidrecno )
+ ; /* skip record with direct key signatures here */
+ else if( (sig->sig_class&~3) == 0x10 ) {
+ /* We simply insert the signature into the sig records but
+ * avoid duplicate ones. We do not check them here because
+ * there is a big chance, that we import required public keys
+ * later. The problem with this is that we must somewhere store
+ * the information about this signature (we need a record id).
+ * We do this by using the record type shadow dir, which will
+ * be converted to a dir record as soon as a new public key is
+ * inserted into the trustdb.
+ */
+ TRUSTREC urec, rec;
+ ulong recno;
+ TRUSTREC delrec;
+ int delrecidx;
+ int newflag = 0;
+ ulong newlid = 0;
+ PKT_public_key *pk = m_alloc_clear( sizeof *pk );
+
+ delrec.recnum = 0;
+ /* we need the uid record */
+ read_record( *uidrecno, &urec, RECTYPE_UID );
+
+ for( recno = urec.r.uid.siglist; recno; recno = rec.r.sig.next ) {
+ int i;
+
+ read_record( recno, &rec, RECTYPE_SIG );
+ for(i=0; i < SIGS_PER_RECORD; i++ ) {
+ TRUSTREC tmp;
+ if( !rec.r.sig.sig[i].lid ) {
+ if( !delrec.recnum ) {
+ delrec = rec;
+ delrecidx = i;
+ }
+ continue; /* skip deleted sigs */
+ }
+ if( rec.r.sig.sig[i].flag & SIGF_CHECKED )
+ continue; /* we already checked this signature */
+ if( rec.r.sig.sig[i].flag & SIGF_NOPUBKEY )
+ continue; /* we do not have the public key */
+
+ read_record( rec.r.sig.sig[i].lid, &tmp, 0 );
+ if( tmp.rectype == RECTYPE_DIR ) {
+ /* In this case we should now be able to check
+ * the signature: */
+ rc = check_key_signature( keyblock, signode, NULL );
+ if( !rc ) { /* valid signature */
+ rec.r.sig.sig[i].flag = SIGF_CHECKED | SIGF_VALID;
+ }
+ else if( rc == G10ERR_NO_PUBKEY ) {
+ log_info(_("key %08lX.%lu, uid %02X%02X: "
+ "weird: no public key for signature %08lX\n"),
+ (ulong)keyid[1], lid, uidhash[18],
+ uidhash[19], (ulong)sig->keyid[1] );
+ rec.r.sig.sig[i].flag = SIGF_NOPUBKEY;
+ }
+ else {
+ log_info(_("key %08lX.%lu, uid %02X%02X: "
+ "invalid signature: %s\n"),
+ (ulong)keyid[1], lid,
+ uidhash[18], uidhash[19], g10_errstr(rc));
+ rec.r.sig.sig[i].flag = SIGF_CHECKED;
+ }
+ write_record( &rec );
+ goto ready;
+ }
+ else if( tmp.rectype == RECTYPE_SDIR ) {
+ /* must check that it is the right one */
+ if( tmp.r.sdir.keyid[0] == sig->keyid[0]
+ && tmp.r.sdir.keyid[1] == sig->keyid[1]
+ && (!tmp.r.sdir.pubkey_algo
+ || tmp.r.sdir.pubkey_algo == sig->pubkey_algo )) {
+ log_info(_("key %08lX.%lu, uid %02X%02X: "
+ "has shadow dir %lu but not yet marked.\n"),
+ (ulong)keyid[1], lid,
+ uidhash[18], uidhash[19], tmp.recnum );
+ rec.r.sig.sig[i].flag = SIGF_NOPUBKEY;
+ write_record( &rec );
+ /* fixme: should we verify that the record is
+ * in the hintlist? - This case here should anyway
+ * never occur */
+ goto ready;
+ }
+ }
+ else {
+ log_error("sig record %lu[%d] points to wrong record.\n",
+ rec.r.sig.sig[i].lid, i );
+ die_invalid_db();
+ }
+ }
+ }
+ /* at this point, we have verified, that the signature is not in
+ * our list of signatures. Add a new record with that signature
+ * and if the public key is there, check the signature. */
+ rc = get_pubkey( pk, sig->keyid );
+ if( !rc ) {
+ /* check that we already have the record in the trustdb;
+ * if not we should not check the signature, because we do
+ * not have the lid of the signature and therefore can't add
+ * a signature record. We will fake a no_pubkey error, so
+ * that this is handled, like we do not have the publick key at
+ * at all. The alternative would be a recursive insert of
+ * records - but that is not good.
+ */
+ rc = query_trust_record( pk );
+ if( rc == -1 )
+ rc = G10ERR_NO_PUBKEY;
+ else
+ rc = check_key_signature( keyblock, signode, NULL );
+ }
+ if( !rc ) { /* valid signature */
+ newlid = pk->local_id; /* this is the pk of the signature */
+ if( !newlid )
+ BUG();
+ newflag = SIGF_CHECKED | SIGF_VALID;
+ }
+ else if( rc == G10ERR_NO_PUBKEY ) {
+ if( opt.verbose )
+ log_info(_("key %08lX.%lu, uid %02X%02X: "
+ "no public key for signature %08lX\n"),
+ (ulong)keyid[1], lid, uidhash[18],
+ uidhash[19], (ulong)sig->keyid[1] );
+ newflag = SIGF_NOPUBKEY;
+ }
+ else {
+ log_info(_("key %08lX.%lu, uid %02X%02X: "
+ "invalid signature: %s\n"),
+ (ulong)keyid[1], lid, uidhash[18], uidhash[19],
+ g10_errstr(rc));
+ newflag = SIGF_CHECKED;
+ }
+ free_public_key( pk );
+
+ if( !newlid ) { /* create a shadow dir record */
+ TRUSTREC sdir, hlst, tmphlst;
+ int tmpidx;
+ /* first see whether we already have such a record */
+ rc = tdbio_search_sdir( sig->keyid, sig->pubkey_algo, &sdir );
+ if( rc && rc != -1 ) {
+ log_error("tdbio_search_dir failed: %s\n", g10_errstr(rc));
+ die_invalid_db();
+ }
+ if( rc == -1 ) { /* not found: create */
+ memset( &sdir, 0, sizeof sdir );
+ sdir.recnum = tdbio_new_recnum();
+ sdir.rectype= RECTYPE_SDIR;
+ sdir.r.sdir.lid = sdir.recnum;
+ sdir.r.sdir.keyid[0] = sig->keyid[0];
+ sdir.r.sdir.keyid[1] = sig->keyid[1];
+ sdir.r.sdir.pubkey_algo = sig->pubkey_algo;
+ sdir.r.sdir.hintlist = 0;
+ write_record( &sdir );
+ }
+ newlid = sdir.recnum;
+ /* Put the record number into the hintlist.
+ * (It is easier to use the lid and not the record number of the
+ * key to save some space (assuming that a signator has
+ * signed more than one user id - and it is easier to implement.)
+ */
+ tmphlst.recnum = 0;
+ for( recno=sdir.r.sdir.hintlist; recno; recno = hlst.r.hlst.next) {
+ int i;
+ read_record( recno, &hlst, RECTYPE_HLST );
+ for( i=0; i < ITEMS_PER_HLST_RECORD; i++ ) {
+ if( !hlst.r.hlst.rnum[i] ) {
+ if( !tmphlst.recnum ) {
+ tmphlst = hlst;
+ tmpidx = i;
+ }
+ }
+ else if( hlst.r.hlst.rnum[i] == lid )
+ goto have_hint;
+ }
+ }
+ /* not yet in the hint list, write it */
+ if( tmphlst.recnum ) { /* we have an empty slot */
+ tmphlst.r.hlst.rnum[tmpidx] = lid;
+ write_record( &tmphlst );
+ }
+ else { /* must append a new hlst record */
+ memset( &hlst, 0, sizeof hlst );
+ hlst.recnum = tdbio_new_recnum();
+ hlst.rectype = RECTYPE_HLST;
+ hlst.r.hlst.next = sdir.r.sdir.hintlist;
+ hlst.r.hlst.rnum[0] = lid;
+ write_record( &hlst );
+ sdir.r.sdir.hintlist = hlst.recnum;
+ write_record( &sdir );
+ }
+ have_hint: /* "goto considered useful" (don't tell Dijkstra) */
+ ;
+ }
+
+ if( delrec.recnum ) { /* we can reuse a deleted slot */
+ delrec.r.sig.sig[delrecidx].lid = newlid;
+ delrec.r.sig.sig[delrecidx].flag= newflag;
+ write_record( &delrec );
+ }
+ else { /* must insert a new sig record */
+ TRUSTREC tmp;
+
+ memset( &tmp, 0, sizeof tmp );
+ tmp.recnum = tdbio_new_recnum();
+ tmp.rectype = RECTYPE_SIG;
+ tmp.r.sig.lid = lid;
+ tmp.r.sig.next = urec.r.uid.siglist;
+ tmp.r.sig.sig[0].lid = newlid;
+ tmp.r.sig.sig[0].flag= newflag;
+ write_record( &tmp );
+ urec.r.uid.siglist = tmp.recnum;
+ write_record( &urec );
+ }
+
+ ready:
+ ;
+ }
+ else {
+ /* handle other sig classes */
+ }
+
+}
+
+
+/****************
+ * Update all the info from the public keyblock.
+ * The key must already exist in the keydb.
+ * This function is responsible for checking the signatures in cases
+ * where the public key is already available. If we no not have the public
+ * key, the check is done by some special code in insert_trust_record().
*/
int
update_trust_record( KBNODE keyblock )
@@ -1942,13 +2277,12 @@ update_trust_record( KBNODE keyblock )
KBNODE node;
TRUSTREC drec;
TRUSTREC krec;
- TRUSTREC prec;
TRUSTREC urec;
+ TRUSTREC prec;
TRUSTREC helprec;
- int modified = 0;
int rc = 0;
u32 keyid[2]; /* keyid of primary key */
- ulong recno, newrecno, lastrecno;
+ ulong recno, lastrecno;
ulong uidrecno = 0;
byte uidhash[20];
RECNO_LIST recno_list = NULL; /* list of verified records */
@@ -1958,189 +2292,46 @@ update_trust_record( KBNODE keyblock )
rc = get_dir_record( primary_pk, &drec );
if( rc )
return rc;
+ if( !primary_pk->local_id )
+ primary_pk->local_id = drec.recnum;
keyid_from_pk( primary_pk, keyid );
/* fixme: start a transaction */
/* now update keys and user ids */
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;
- byte fpr[MAX_FINGERPRINT_LEN];
- size_t fprlen;
-
+ switch( node->pkt->pkttype ) {
+ case PKT_PUBLIC_KEY:
+ case PKT_PUBLIC_SUBKEY:
uidrecno = 0;
+ upd_key_record( node->pkt->pkt.public_key, &drec, &recno_list );
+ break;
- fingerprint_from_pk( pk, fpr, &fprlen );
- /* do we already have this key? */
- for( recno=drec.r.dir.keylist; recno; recno = krec.r.key.next ) {
- read_record( recno, &krec, RECTYPE_KEY );
- if( krec.r.key.fingerprint_len == fprlen
- && !memcmp( krec.r.key.fingerprint, fpr, fprlen ) )
- break;
+ case PKT_USER_ID:
+ if( drec.dirty ) { /* upd_pref_record may read the drec */
+ write_record( &drec );
+ drec.dirty = 0;
}
- if( recno ) { /* yes */
- ins_recno_list( &recno_list, recno, RECTYPE_KEY );
- /* here we would compare/update the keyflags */
- }
- else { /* no: insert this new key */
- memset( &krec, 0, sizeof(krec) );
- krec.rectype = RECTYPE_KEY;
- krec.r.key.lid = drec.recnum;
- krec.r.key.pubkey_algo = pk->pubkey_algo;
- krec.r.key.fingerprint_len = fprlen;
- memcpy(krec.r.key.fingerprint, fpr, fprlen );
- krec.recnum = newrecno = tdbio_new_recnum();
- write_record( &krec );
- ins_recno_list( &recno_list, newrecno, RECTYPE_KEY );
- /* and put this new record at the end of the keylist */
- if( !(recno=drec.r.dir.keylist) ) {
- /* this is the first key */
- drec.r.dir.keylist = newrecno;
- modified = 1;
- }
- else { /* we already have key, append it to the list */
- for( ; recno; recno = krec.r.key.next )
- read_record( recno, &krec, RECTYPE_KEY );
- krec.r.key.next = newrecno;
- write_record( &krec );
- }
- } /* end insert new key */
- } /* end packet type public key packet */
- else if( node->pkt->pkttype == PKT_USER_ID ) {
- PKT_user_id *uid = node->pkt->pkt.user_id;
- TRUSTREC urec;
-
- rmd160_hash_buffer( uidhash, uid->name, uid->len );
- for( recno=drec.r.dir.uidlist; recno; recno = urec.r.uid.next ) {
- read_record( recno, &urec, RECTYPE_UID );
- if( !memcmp( uidhash, urec.r.uid.namehash, 20 ) )
- break;
- }
- if( recno ) {
- ins_recno_list( &recno_list, recno, RECTYPE_UID );
- uidrecno = recno;
- }
- else { /* new user id */
- memset( &urec, 0 , sizeof(urec) );
- urec.rectype = RECTYPE_UID;
- urec.r.uid.lid = drec.recnum;
- memcpy(urec.r.uid.namehash, uidhash, 20 );
- urec.recnum = newrecno = tdbio_new_recnum();
- write_record( &urec );
- ins_recno_list( &recno_list, newrecno, RECTYPE_UID );
- /* and put this new record at the end of the uidlist */
- if( !(recno=drec.r.dir.uidlist) ) {
- /* this is the first uid */
- drec.r.dir.uidlist = newrecno;
- modified = 1;
- }
- else { /* we already have an uid, append it to the list */
- for( ; recno; recno = urec.r.key.next )
- read_record( recno, &urec, RECTYPE_UID );
- urec.r.uid.next = newrecno;
- write_record( &urec );
- }
- uidrecno = newrecno;
- }
- }
- else if( node->pkt->pkttype == PKT_SIGNATURE ) {
- PKT_signature *sig = node->pkt->pkt.signature;
-
- if( keyid[0] == sig->keyid[0] && keyid[1] == sig->keyid[1]
- && (node->pkt->pkt.signature->sig_class&~3) == 0x10 ) {
- /* must verify this selfsignature here, so that we can
- * build the preference record and validate the uid record
- */
- if( !uidrecno ) {
- log_error("key %08lX: self-signature without user id\n",
- (ulong)keyid[1] );
- }
- else if( (rc = check_key_signature( keyblock, node, NULL ))) {
- log_error("key %08lX, uid %02X%02X: "
- "invalid self-signature: %s\n", (ulong)keyid[1],
- uidhash[18], uidhash[19], g10_errstr(rc) );
- rc = 0;
- }
- else { /* build the prefrecord */
- static struct {
- sigsubpkttype_t subpkttype;
- int preftype;
- } prefs[] = {
- { SIGSUBPKT_PREF_SYM, PREFTYPE_SYM },
- { SIGSUBPKT_PREF_HASH, PREFTYPE_HASH },
- { SIGSUBPKT_PREF_COMPR, PREFTYPE_COMPR },
- { 0, 0 }
- };
- const byte *s;
- size_t n;
- int k, i;
- ulong recno_tbl[10];
- int recno_idx = 0;
-
- read_record( uidrecno, &urec, RECTYPE_UID );
-
- /* first delete all pref records */
- for(recno=urec.r.uid.prefrec ; recno;
- recno = prec.r.pref.next ) {
- read_record( recno, &prec, RECTYPE_PREF );
- delete_record( recno );
- }
+ upd_uid_record( node->pkt->pkt.user_id, &drec, &recno_list,
+ keyid, &uidrecno, uidhash );
+ break;
- /* and write the new ones */
- i = 0;
- for(k=0; prefs[k].subpkttype; k++ ) {
- s = parse_sig_subpkt2( sig, prefs[k].subpkttype, &n );
- if( s ) {
- while( n ) {
- if( !i || i >= ITEMS_PER_PREF_RECORD ) {
- if( recno_idx >= DIM(recno_tbl)-1 ) {
- log_info("too many preferences\n");
- break;
- }
- if( i ) {
- recno_tbl[recno_idx]=tdbio_new_recnum();
- prec.recnum = recno_tbl[recno_idx++];
- write_record( &prec );
- }
- memset( &prec, 0, sizeof prec );
- prec.rectype = RECTYPE_PREF;
- prec.r.pref.lid = drec.recnum;
- i = 0;
- }
- prec.r.pref.data[i++] = prefs[k].preftype;
- prec.r.pref.data[i++] = *s++;
- n--;
- }
- }
- }
- if( i ) { /* write the last one */
- recno_tbl[recno_idx]=tdbio_new_recnum();
- prec.recnum = recno_tbl[recno_idx++];
- write_record( &prec );
- }
- /* now link them together */
- for(i=0; i < recno_idx-1; i++ ) {
- read_record( recno_tbl[i], &prec, RECTYPE_PREF );
- prec.r.pref.next = recno_tbl[i+1];
- write_record( &prec );
- }
- /* don't need to write the last one, but update the uid */
- urec.r.uid.prefrec = recno_idx? recno_tbl[0] : 0;
- write_record( &urec );
- }
- }
- else if( 0 /* is revocation sig etc */ ) {
- /* handle it here */
- }
- else { /* not a selfsignature */
+ case PKT_SIGNATURE:
+ if( drec.dirty ) { /* upd_sig_recrod may read the drec */
+ write_record( &drec );
+ drec.dirty = 0;
}
+ upd_sig_record( node->pkt->pkt.signature, &drec,
+ keyid, &uidrecno, uidhash, keyblock, node );
+ break;
+
+ default:
+ break;
}
} /* end loop over all nodes */
- /* now delete keyrecords from the trustdb which are not anymore used */
+ /* delete keyrecords from the trustdb which are not anymore used */
lastrecno = 0;
for( recno=drec.r.dir.keylist; recno; recno = krec.r.key.next ) {
read_record( recno, &krec, RECTYPE_KEY );
@@ -2148,7 +2339,7 @@ update_trust_record( KBNODE keyblock )
/* delete this one */
if( !lastrecno ) {
drec.r.dir.keylist = krec.r.key.next;
- modified = 1;
+ drec.dirty = 1;
}
else {
read_record( lastrecno, &helprec, RECTYPE_KEY );
@@ -2160,7 +2351,7 @@ update_trust_record( KBNODE keyblock )
else
lastrecno = recno;
}
- /* now delete uid records and their pref records from the
+ /* delete uid records and sig and their pref records from the
* trustdb which are not anymore used */
lastrecno = 0;
for( recno=drec.r.dir.uidlist; recno; recno = urec.r.uid.next ) {
@@ -2170,7 +2361,7 @@ update_trust_record( KBNODE keyblock )
/* delete this one */
if( !lastrecno ) {
drec.r.dir.uidlist = urec.r.uid.next;
- modified = 1;
+ drec.dirty = 1;
}
else {
read_record( lastrecno, &helprec, RECTYPE_UID );
@@ -2181,6 +2372,10 @@ update_trust_record( KBNODE keyblock )
read_record( r2, &prec, RECTYPE_PREF );
delete_record( r2 );
}
+ for(r2=urec.r.uid.siglist ; r2; r2 = helprec.r.sig.next ) {
+ read_record( r2, &helprec, RECTYPE_SIG );
+ delete_record( r2 );
+ }
delete_record( recno );
}
else
@@ -2191,7 +2386,7 @@ update_trust_record( KBNODE keyblock )
if( rc )
; /* fixme: cancel transaction */
- else if( modified ) {
+ else if( drec.dirty ) {
drec.r.dir.dirflags &= ~DIRF_CHECKED; /* reset flag */
write_record( &drec );
/* fixme: commit_transaction */
@@ -2203,29 +2398,33 @@ update_trust_record( KBNODE keyblock )
/****************
* Insert a trust record into the TrustDB
- * This function fails if this record already exists.
- *
- * We build everything we can do at this point. We cannot build
- * the sig records, because their LIDs are needed and we may not have them.
+ * This function assumes that the record does not yet exist.
*/
int
insert_trust_record( PKT_public_key *pk )
{
TRUSTREC dirrec;
+ TRUSTREC shadow;
KBNODE keyblock = NULL;
KBNODE node;
- byte *fingerprint;
+ byte fingerprint[MAX_FINGERPRINT_LEN];
size_t fingerlen;
int rc = 0;
-
+ ulong hintlist = 0;
if( pk->local_id )
log_bug("pk->local_id=%lu\n", pk->local_id );
- fingerprint = fingerprint_from_pk( pk, NULL, &fingerlen );
+ fingerprint_from_pk( pk, fingerprint, &fingerlen );
/* fixme: assert that we do not have this record.
* we can do this by searching for the primary keyid
+ *
+ * fixme: If there is no such key we should look whether one
+ * of the subkeys has been used to sign another key and in this case
+ * we got the key anyway. Because a secondary key can't be used
+ * without a primary key (it is needed to bind the secondary one
+ * to the primary one which has the user ids etc.)
*/
/* get the keyblock which has the key */
@@ -2236,9 +2435,37 @@ insert_trust_record( PKT_public_key *pk )
goto leave;
}
+ /* check that we used the primary key (we are little bit paranoid) */
+ { PKT_public_key *a_pk;
+ node = find_kbnode( keyblock, PKT_PUBLIC_KEY );
+ a_pk = node->pkt->pkt.public_key;
+ if( cmp_public_keys( a_pk, pk ) ) {
+ log_error("did not use primary key for insert_trust_record()\n");
+ rc = G10ERR_GENERAL;
+ goto leave;
+ }
+ }
+
+ /* We have to look for a shadow dir record which must be reused
+ * as the dir record. And: check all signatures which are listed
+ * in the hintlist of the shadow dir record.
+ */
+ rc = tdbio_search_sdir( pk->keyid, pk->pubkey_algo, &shadow );
+ if( rc && rc != -1 ) {
+ log_error("tdbio_search_dir failed: %s\n", g10_errstr(rc));
+ die_invalid_db();
+ }
memset( &dirrec, 0, sizeof dirrec );
dirrec.rectype = RECTYPE_DIR;
- dirrec.recnum = tdbio_new_recnum();
+ if( !rc ) {
+ /* hey, great: this key has already signed other keys
+ * convert this to a real directory entry */
+ hintlist = shadow.r.sdir.hintlist;
+ dirrec.recnum = shadow.recnum;
+ }
+ else {
+ dirrec.recnum = tdbio_new_recnum();
+ }
dirrec.r.dir.lid = dirrec.recnum;
write_record( &dirrec );
@@ -2258,10 +2485,12 @@ insert_trust_record( PKT_public_key *pk )
/* and put all the other stuff into the keydb */
rc = update_trust_record( keyblock );
-
+ if( !rc )
+ process_hintlist( hintlist, dirrec.r.dir.lid );
leave:
- m_free(fingerprint);
+ if( rc && hintlist )
+ ; /* fixme: the hintlist is not anymore anchored */
release_kbnode( keyblock );
return rc;
}