summaryrefslogtreecommitdiffstats
path: root/g10/trustdb.c
diff options
context:
space:
mode:
authorWerner Koch <wk@gnupg.org>1999-06-29 21:50:54 +0200
committerWerner Koch <wk@gnupg.org>1999-06-29 21:50:54 +0200
commit75ed03c960bf6613d13435499cba0bddc79dc3fd (patch)
treeb2f1fcd92a2dca9c77ae16f98395c04fa9476eb2 /g10/trustdb.c
parentSee ChangeLog: Sat Jun 26 13:54:43 CEST 1999 Werner Koch (diff)
downloadgnupg2-75ed03c960bf6613d13435499cba0bddc79dc3fd.tar.xz
gnupg2-75ed03c960bf6613d13435499cba0bddc79dc3fd.zip
See ChangeLog: Tue Jun 29 21:44:25 CEST 1999 Werner Koch
Diffstat (limited to 'g10/trustdb.c')
-rw-r--r--g10/trustdb.c1728
1 files changed, 604 insertions, 1124 deletions
diff --git a/g10/trustdb.c b/g10/trustdb.c
index 9f12757b1..1e804d704 100644
--- a/g10/trustdb.c
+++ b/g10/trustdb.c
@@ -125,12 +125,6 @@ static int do_check( TRUSTREC *drec, unsigned *trustlevel,
unsigned *retflgs);
static int get_dir_record( PKT_public_key *pk, TRUSTREC *rec );
-static void upd_pref_record( TRUSTREC *urec, u32 *keyid, PKT_signature *sig );
-static void upd_cert_record( KBNODE keyblock, KBNODE signode, u32 *keyid,
- TRUSTREC *drec, RECNO_LIST *recno_list, int recheck,
- TRUSTREC *urec, const byte *uidhash, int revoked,
- int *mod_up, int *mod_down );
-
/* a table used to keep track of ultimately trusted keys
* which are the ones from our secrings and the trusted keys */
static LOCAL_ID_TABLE ultikey_table;
@@ -213,42 +207,6 @@ do_sync(void)
***************** helpers ******************
**********************************************/
-/****************
- * Insert a new item into a recno list
- */
-static void
-ins_recno_list( RECNO_LIST *head, ulong recno, int type )
-{
- RECNO_LIST item = m_alloc( sizeof *item );
-
- item->recno = recno;
- item->type = type;
- item->next = *head;
- *head = item;
-}
-
-static RECNO_LIST
-qry_recno_list( RECNO_LIST list, ulong recno, int type )
-{
- for( ; list; list = list->next ) {
- if( list->recno == recno && (!type || list->type == type) )
- return list;
- }
- return NULL;
-}
-
-
-static void
-rel_recno_list( RECNO_LIST *head )
-{
- RECNO_LIST r, r2;
-
- for(r = *head; r; r = r2 ) {
- r2 = r->next;
- m_free(r);
- }
- *head = NULL;
-}
static LOCAL_ID_TABLE
new_lid_table(void)
@@ -449,7 +407,9 @@ get_dir_record( PKT_public_key *pk, TRUSTREC *rec )
* Get the LID of a public key.
* Returns: The LID of the key (note, that this may be a shadow dir)
* or 0 if not available.
+ * fixme: make this ftser by putting entries into the sdir hash table
*/
+#if 0
static ulong
lid_from_keyid( u32 *keyid )
{
@@ -479,6 +439,29 @@ lid_from_keyid( u32 *keyid )
free_public_key( pk );
return lid;
}
+#endif
+
+static ulong
+lid_from_keyid_no_sdir( u32 *keyid )
+{
+ PKT_public_key *pk = m_alloc_clear( sizeof *pk );
+ TRUSTREC rec;
+ ulong lid = 0;
+ int rc;
+
+ rc = get_pubkey( pk, keyid );
+ if( !rc ) {
+ if( pk->local_id )
+ lid = pk->local_id;
+ else {
+ rc = tdbio_search_dir_bypk( pk, &rec );
+ if( !rc )
+ lid = rec.recnum;
+ }
+ }
+ free_public_key( pk );
+ return lid;
+}
@@ -833,226 +816,19 @@ dump_tn_tree_with_colons( int level, TN tree )
************* trustdb maintenance ***********
***********************************************/
-
-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;
- byte uhash[20];
- int is_selfsig;
- PKT_signature *sigpkt = NULL;
- TRUSTREC tmp;
- u32 sigkid[2];
- int revoked = 0;
-
- 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 );
-
- read_record( sigrec->r.sig.sig[sigidx].lid, &tmp, 0 );
- if( tmp.rectype != RECTYPE_DIR ) {
- /* we need the dir record */
- log_error(_("sig rec %lu[%d] in hintlist "
- "of %lu does not point to a dir record\n"),
- sigrec->recnum, sigidx, hint_owner );
- return;
- }
- if( !tmp.r.dir.keylist ) {
- log_error(_("lid %lu: no primary key\n"), tmp.r.dir.lid );
- return;
- }
- read_record(tmp.r.dir.keylist, &tmp, RECTYPE_KEY );
- keyid_from_fingerprint( tmp.r.key.fingerprint,
- tmp.r.key.fingerprint_len, sigkid );
-
-
- /* find the correct signature packet */
- state = 0;
- 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] == sigkid[0]
- && sigpkt->keyid[1] == sigkid[1]
- && ( (sigpkt->sig_class&~3) == 0x10
- || ( revoked = (sigpkt->sig_class == 0x30)) ) ) {
- state = 2;
- break; /* found */
- }
- }
- }
-
- if( !node ) {
- log_info(_("lid %lu: user id not found in keyblock\n"), lid );
- return ;
- }
- if( state != 2 ) {
- log_info(_("lid %lu: user id without signature\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;
- }
-
- /* FiXME: handling fo SIGF_REVOKED is not correct! */
-
- if( !rc ) { /* valid signature */
- if( opt.verbose )
- log_info("sig %08lX.%lu/%02X%02X/%08lX: %s\n",
- (ulong)keyid[1], lid, uhash[18], uhash[19],
- (ulong)sigpkt->keyid[1],
- revoked? _("Valid certificate revocation")
- : _("Good certificate") );
- sigrec->r.sig.sig[sigidx].flag = SIGF_CHECKED | SIGF_VALID;
- if( revoked )
- sigrec->r.sig.sig[sigidx].flag |= SIGF_REVOKED;
- }
- else if( rc == G10ERR_NO_PUBKEY ) {
- log_info("sig %08lX.%lu/%02X%02X/%08lX: %s\n",
- (ulong)keyid[1], lid, uhash[18], uhash[19],
- (ulong)sigpkt->keyid[1],
- _("very strange: no public key\n") );
- sigrec->r.sig.sig[sigidx].flag = SIGF_NOPUBKEY;
- }
- else {
- log_info("sig %08lX.%lu/%02X%02X/%08lX: %s\n",
- (ulong)keyid[1], lid, uhash[18], uhash[19],
- (ulong)sigpkt->keyid[1], 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
- * FIXME: add mod_up/down handling
- */
-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 */
-}
-
-
/****************
* Create or update shadow dir record and return the LID of the record
*/
static ulong
-create_shadow_dir( PKT_signature *sig, ulong lid )
+create_shadow_dir( PKT_signature *sig )
{
- TRUSTREC sdir, hlst, tmphlst;
- ulong recno, newlid;
- int tmpidx=0; /* avoids gcc warnign - this is controlled by tmphlst */
+ TRUSTREC sdir;
int rc;
/* 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));
+ log_error(_("tdbio_search_sdir failed: %s\n"), g10_errstr(rc));
tdbio_invalid();
}
if( rc == -1 ) { /* not found: create */
@@ -1063,415 +839,26 @@ create_shadow_dir( PKT_signature *sig, ulong lid )
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 )
- return newlid; /* the signature is already in the hintlist */
- }
- }
- /* 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 );
}
-
- return newlid;
+ return sdir.recnum;
}
-/****************
- * This function checks the given public key and inserts or updates
- * the keyrecord from the trustdb. Revocation certificates
- * are handled here and the keybinding of subkeys is checked.
- * Hmmm: Should we check here, that the key has at least one valid
- * user ID or do we allow keys w/o user ID?
- *
- * keyblock points to the first node in the keyblock,
- * keynode is the node with the public key to check
- * (either primary or secondary), keyid is the keyid of
- * the primary key, drec is the directory record and recno_list
- * is a list used to keep track of visited records.
- * Existing keyflags are recalculated if recheck is true.
- */
-static void
-upd_key_record( KBNODE keyblock, KBNODE keynode, u32 *keyid,
- TRUSTREC *drec, RECNO_LIST *recno_list, int recheck )
+static ulong
+find_or_create_lid( PKT_signature *sig )
{
- TRUSTREC krec;
- KBNODE node;
- PKT_public_key *pk = keynode->pkt->pkt.public_key;
- ulong lid = drec->recnum;
- byte fpr[MAX_FINGERPRINT_LEN];
- size_t fprlen;
- ulong recno, newrecno;
- int keybind_seen = 0;
- int revoke_seen = 0;
- int rc;
-
- 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 );
- }
- else { /* no: insert this new key */
- recheck = 1; /* same as recheck */
- memset( &krec, 0, sizeof(krec) );
- krec.rectype = RECTYPE_KEY;
- krec.r.key.lid = lid;
- 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 the new one */
- TRUSTREC save = krec;
- for( ; recno; recno = krec.r.key.next )
- read_record( recno, &krec, RECTYPE_KEY );
- krec.r.key.next = newrecno;
- write_record( &krec );
- krec = save;
- }
- }
-
- if( !recheck && (krec.r.key.keyflags & KEYF_CHECKED) )
- return;
-
- /* check keybindings and revocations */
- krec.r.key.keyflags = 0;
- if( keynode->pkt->pkttype == PKT_PUBLIC_KEY ) {
- /* we assume that a primary key is always valid
- * and check later whether we have a revocation */
- krec.r.key.keyflags |= KEYF_CHECKED | KEYF_VALID;
- }
-
- for( node=keynode->next; node; node = node->next ) {
- PKT_signature *sig;
-
- if( node->pkt->pkttype == PKT_PUBLIC_SUBKEY )
- break; /* ready (we check only one key at a time) */
- else if( node->pkt->pkttype != PKT_SIGNATURE )
- continue;
-
- sig = node->pkt->pkt.signature;
-
- if( keyid[0] != sig->keyid[0] || keyid[1] != sig->keyid[1] )
- continue; /* here we only care about a self-signatures */
-
- if( sig->sig_class == 0x18 && !keybind_seen ) { /* a keybinding */
- if( keynode->pkt->pkttype == PKT_PUBLIC_KEY )
- continue; /* oops, ignore subkey binding on main key */
-
- /* we check until we find a valid keybinding */
- rc = check_key_signature( keyblock, node, NULL );
- if( !rc ) {
- if( opt.verbose )
- log_info(_(
- "key %08lX.%lu: Good subkey binding\n"),
- (ulong)keyid_from_pk(pk,NULL), lid );
- krec.r.key.keyflags |= KEYF_CHECKED | KEYF_VALID;
- }
- else {
- log_info(_(
- "key %08lX.%lu: Invalid subkey binding: %s\n"),
- (ulong)keyid_from_pk(pk,NULL), lid, g10_errstr(rc) );
- krec.r.key.keyflags |= KEYF_CHECKED;
- krec.r.key.keyflags &= ~KEYF_VALID;
- }
- keybind_seen = 1;
- }
- else if( sig->sig_class == 0x20 && !revoke_seen ) {
- if( keynode->pkt->pkttype == PKT_PUBLIC_SUBKEY )
- continue; /* a subkey is not expected here */
-
- /* This is a key revocation certificate: check it */
- rc = check_key_signature( keyblock, node, NULL );
- if( !rc ) {
- if( opt.verbose )
- log_info(_(
- "key %08lX.%lu: Valid key revocation\n"),
- (ulong)keyid_from_pk(pk,NULL), lid );
- krec.r.key.keyflags |= KEYF_REVOKED;
- }
- else {
- log_info(_(
- "key %08lX.%lu: Invalid key revocation: %s\n"),
- (ulong)keyid_from_pk(pk,NULL), lid, g10_errstr(rc) );
- }
- revoke_seen = 1;
- }
- else if( sig->sig_class == 0x28 && !revoke_seen ) {
- if( keynode->pkt->pkttype == PKT_PUBLIC_KEY )
- continue; /* a mainkey is not expected here */
- /* This is a subkey revocation certificate: check it */
- /* fixme: we should also check the revocation
- * is newer than the key (OpenPGP) */
- rc = check_key_signature( keyblock, node, NULL );
- if( !rc ) {
- if( opt.verbose )
- log_info(_(
- "key %08lX.%lu: Valid subkey revocation\n"),
- (ulong)keyid_from_pk(pk,NULL), lid );
- krec.r.key.keyflags |= KEYF_REVOKED;
- }
- else {
- log_info(_(
- "key %08lX.%lu: Invalid subkey binding: %s\n"),
- (ulong)keyid_from_pk(pk,NULL), lid, g10_errstr(rc) );
- }
- revoke_seen = 1;
- }
- }
+ ulong lid;
- write_record( &krec );
+ lid = lid_from_keyid_no_sdir( sig->keyid );
+ if( !lid )
+ lid = create_shadow_dir( sig );
+ return lid;
}
-/****************
- * This function checks the given user ID and inserts or updates
- * the uid record of the trustdb. Revocation certificates
- * are handled here.
- *
- * keyblock points to the first node in the keyblock,
- * uidnode is the node with the user id to check
- * keyid is the keyid of
- * the primary key, drec is the directory record and recno_list
- * is a list used to keep track of visited records.
- * Existing uidflags are recalculated if recheck is true.
- */
-static void
-upd_uid_record( KBNODE keyblock, KBNODE uidnode, u32 *keyid,
- TRUSTREC *drec, RECNO_LIST *recno_list,
- int recheck, int *mod_up, int *mod_down )
-{
- ulong lid = drec->recnum;
- PKT_user_id *uid = uidnode->pkt->pkt.user_id;
- TRUSTREC urec;
- PKT_signature *selfsig = NULL;
- byte uidhash[20];
- KBNODE node;
- ulong recno, newrecno;
- int rc;
-
- if( DBG_TRUST )
- log_debug("upd_uid_record for %08lX/%02X%02X\n",
- (ulong)keyid[1], uidhash[18], uidhash[19]);
-
- /* see whether we already have an uid record */
- 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 ) { /* we already have this record */
- ins_recno_list( recno_list, recno, RECTYPE_UID );
- }
- else { /* new user id */
- recheck = 1; /* insert is the same as a recheck */
- 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 */
- TRUSTREC save = urec;
- for( ; recno; recno = urec.r.key.next )
- read_record( recno, &urec, RECTYPE_UID );
- urec.r.uid.next = newrecno;
- write_record( &urec );
- urec = save;
- }
- }
-
- if( recheck || !(urec.r.uid.uidflags & UIDF_CHECKED) ) {
- unsigned orig_uidflags = urec.r.uid.uidflags;
-
- urec.r.uid.uidflags = 0;
- /* first check regular self signatures */
- for( node=uidnode->next; node; node = node->next ) {
- PKT_signature *sig;
-
- if( node->pkt->pkttype == PKT_USER_ID )
- break; /* ready */
- if( node->pkt->pkttype == PKT_PUBLIC_SUBKEY )
- break; /* ready */
- if( node->pkt->pkttype != PKT_SIGNATURE )
- continue;
-
- sig = node->pkt->pkt.signature;
-
- if( keyid[0] != sig->keyid[0] || keyid[1] != sig->keyid[1] )
- continue; /* not a self signature */
-
- if( (sig->sig_class&~3) == 0x10 ) { /* regular self signature */
- rc = check_key_signature( keyblock, node, NULL );
- if( !rc ) {
- if( opt.verbose )
- log_info( "uid %08lX.%lu/%02X%02X: %s\n",
- (ulong)keyid[1], lid, uidhash[18], uidhash[19],
- _("Good self-signature") );
- urec.r.uid.uidflags |= UIDF_CHECKED | UIDF_VALID;
- if( !selfsig )
- selfsig = sig; /* use the first valid sig */
- else if( sig->timestamp > selfsig->timestamp
- && sig->sig_class >= selfsig->sig_class )
- selfsig = sig; /* but this one is newer */
- }
- else {
- log_info( "uid %08lX/%02X%02X: %s: %s\n",
- (ulong)keyid[1], uidhash[18], uidhash[19],
- _("Invalid self-signature"),
- g10_errstr(rc) );
- urec.r.uid.uidflags |= UIDF_CHECKED;
- }
- }
- }
-
- /* and now check for revocations- we must do this after the
- * self signature check because a selfsignature which is newer
- * than a revocation makes the revocation invalid.
- * Fixme: Is this correct - check with rfc2440
- */
- for( node=uidnode->next; node; node = node->next ) {
- PKT_signature *sig;
-
- if( node->pkt->pkttype == PKT_USER_ID )
- break; /* ready */
- if( node->pkt->pkttype == PKT_PUBLIC_SUBKEY )
- break; /* ready */
- if( node->pkt->pkttype != PKT_SIGNATURE )
- continue;
-
- sig = node->pkt->pkt.signature;
-
- if( keyid[0] != sig->keyid[0] || keyid[1] != sig->keyid[1] )
- continue; /* not a self signature */
-
- if( sig->sig_class == 0x30 ) { /* cert revocation */
- rc = check_key_signature( keyblock, node, NULL );
- if( !rc && selfsig && selfsig->timestamp > sig->timestamp ) {
- log_info( "uid %08lX.%lu/%02X%02X: %s\n",
- (ulong)keyid[1], lid, uidhash[18], uidhash[19],
- _("Valid user ID revocation skipped "
- "due to a newer self signature\n") );
- }
- else if( !rc ) {
- if( opt.verbose )
- log_info( "uid %08lX.%lu/%02X%02X: %s\n",
- (ulong)keyid[1], lid, uidhash[18], uidhash[19],
- _("Valid user ID revocation\n") );
- urec.r.uid.uidflags |= UIDF_CHECKED | UIDF_VALID;
- urec.r.uid.uidflags |= UIDF_REVOKED;
- }
- else {
- log_info("uid %08lX/%02X%02X: %s: %s\n",
- (ulong)keyid[1], uidhash[18], uidhash[19],
- _("Invalid user ID revocation"),
- g10_errstr(rc) );
- }
- }
-
- }
-
- if( orig_uidflags != urec.r.uid.uidflags ) {
- write_record( &urec );
- if( !( urec.r.uid.uidflags & UIDF_VALID )
- || ( urec.r.uid.uidflags & UIDF_REVOKED ) )
- *mod_down=1;
- else
- *mod_up=1; /*(maybe a new user id)*/
- /* Hmmm, did we catch changed expiration dates? */
- }
-
- } /* end check self-signatures */
-
-
- if( (urec.r.uid.uidflags & (UIDF_CHECKED|UIDF_VALID))
- != (UIDF_CHECKED|UIDF_VALID) )
- return; /* user ID is not valid, so no need to check more things */
-
- /* check the preferences */
- if( selfsig )
- upd_pref_record( &urec, keyid, selfsig );
-
- /* Now we va check the certication signatures */
- for( node=uidnode->next; node; node = node->next ) {
- PKT_signature *sig;
-
- if( node->pkt->pkttype == PKT_USER_ID )
- break; /* ready */
- if( node->pkt->pkttype == PKT_PUBLIC_SUBKEY )
- break; /* ready */
- if( node->pkt->pkttype != PKT_SIGNATURE )
- continue;
-
- sig = node->pkt->pkt.signature;
-
- if( keyid[0] == sig->keyid[0] || keyid[1] == sig->keyid[1] )
- continue; /* here we skip the self-signatures */
-
- if( (sig->sig_class&~3) == 0x10 ) { /* regular certification */
- upd_cert_record( keyblock, node, keyid, drec, recno_list,
- recheck, &urec, uidhash, 0, mod_up, mod_down );
- }
- else if( sig->sig_class == 0x30 ) { /* cert revocation */
- upd_cert_record( keyblock, node, keyid, drec, recno_list,
- recheck, &urec, uidhash, 1, mod_up, mod_down );
- }
- } /* end check certificates */
-
- write_record( &urec );
-}
-
+#if 0
static void
upd_pref_record( TRUSTREC *urec, u32 *keyid, PKT_signature *sig )
{
@@ -1586,264 +973,463 @@ upd_pref_record( TRUSTREC *urec, u32 *keyid, PKT_signature *sig )
urec->r.uid.prefrec = prec.recnum;
urec->dirty = 1;
}
+#endif
-static void
-upd_cert_record( KBNODE keyblock, KBNODE signode, u32 *keyid,
- TRUSTREC *drec, RECNO_LIST *recno_list, int recheck,
- TRUSTREC *urec, const byte *uidhash, int revoked,
- int *mod_up, int *mod_down )
+/****************
+ * Check the validity of a key and calculate the keyflags
+ * keynode points to
+ * a node with a [sub]key. mainkid has the key ID of the primary key
+ * keyblock is the complete keyblock which is needed for signature
+ * checking. LID and PK is only used in verbose mode.
+ */
+static unsigned int
+check_keybinding( KBNODE keyblock, KBNODE keynode, u32 *mainkid,
+ ulong lid, PKT_public_key *pk )
{
- /* 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 when the missing public key
- * gets inserted into the trustdb.
- */
- ulong lid = drec->recnum;
- PKT_signature *sig = signode->pkt->pkt.signature;
- TRUSTREC rec;
- ulong recno;
- TRUSTREC delrec;
- int delrecidx=0;
- int newflag = 0;
- ulong newlid = 0;
- ulong pk_lid = 0;
- int found_sig = 0;
- int found_delrec = 0;
+ KBNODE node;
+ int keybind_seen = 0;
+ int revoke_seen = 0;
+ unsigned int keyflags=0;
+ int is_main = (keynode->pkt->pkttype == PKT_PUBLIC_KEY);
int rc;
+ if( is_main ) {
+ /* a primary key is always valid (user IDs are handled elsewhere)*/
+ keyflags = KEYF_CHECKED | KEYF_VALID;
+ }
- if( DBG_TRUST )
- log_debug("upd_cert_record for %08lX.?/%02X%02X/%08lX\n",
- (ulong)keyid[1], uidhash[18],
- uidhash[19], (ulong)sig->keyid[1] );
+ for( node=keynode->next; node; node = node->next ) {
+ PKT_signature *sig;
- delrec.recnum = 0;
+ if( node->pkt->pkttype == PKT_PUBLIC_SUBKEY )
+ break; /* ready */
+ if( node->pkt->pkttype != PKT_SIGNATURE )
+ continue; /* don't care about other packets */
- /* get the LID of the pubkey of the signature under verification */
- pk_lid = lid_from_keyid( sig->keyid );
+ sig = node->pkt->pkt.signature;
- /* Loop over all signatures just in case one is not correctly
- * marked. If we see the correct signature, set a flag.
- * delete duplicate signatures (should not happen but...) */
- for( recno = urec->r.uid.siglist; recno; recno = rec.r.sig.next ) {
- int i;
+ if( mainkid[0] != sig->keyid[0] || mainkid[1] != sig->keyid[1] )
+ continue; /* we only care about self-signatures */
- read_record( recno, &rec, RECTYPE_SIG );
- for(i=0; i < SIGS_PER_RECORD; i++ ) {
- TRUSTREC tmp;
- if( !rec.r.sig.sig[i].lid ) {
- /* (remember this unused slot) */
- if( !found_delrec && !delrec.recnum ) {
- delrec = rec;
- delrecidx = i;
- found_delrec=1;
- }
- continue; /* skip unused slots */
+ if( sig->sig_class == 0x18 && !keybind_seen && !is_main ) {
+ /* check until we find a valid keybinding */
+ rc = check_key_signature( keyblock, node, NULL );
+ if( !rc ) {
+ if( opt.verbose )
+ log_info(_("key %08lX.%lu: Good subkey binding\n"),
+ (ulong)keyid_from_pk(pk,NULL), lid );
+ keyflags |= KEYF_CHECKED | KEYF_VALID;
}
-
- if( rec.r.sig.sig[i].lid == pk_lid ) {
- if( found_sig ) {
- log_info( "sig %08lX.%lu/%02X%02X/%08lX: %s\n",
- (ulong)keyid[1], lid, uidhash[18],
- uidhash[19], (ulong)sig->keyid[1],
- _("duplicated certificate - deleted") );
- rec.r.sig.sig[i].lid = 0;
- rec.dirty = 1;
- continue;
- }
- found_sig = 1;
+ else {
+ log_info(_(
+ "key %08lX.%lu: Invalid subkey binding: %s\n"),
+ (ulong)keyid_from_pk(pk,NULL), lid, g10_errstr(rc) );
+ keyflags |= KEYF_CHECKED;
+ keyflags &= ~KEYF_VALID;
}
- if( !recheck && !revoked && (rec.r.sig.sig[i].flag & SIGF_CHECKED))
- continue; /* we already checked this signature */
- if( !recheck && (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 ) {
- /* the public key is in the trustdb: check sig */
- rc = check_key_signature( keyblock, signode, NULL );
- if( !rc ) { /* valid signature */
- if( opt.verbose )
- log_info("sig %08lX.%lu/%02X%02X/%08lX: %s\n",
- (ulong)keyid[1], lid, uidhash[18],
- uidhash[19], (ulong)sig->keyid[1],
- revoked? _("Valid certificate revocation")
- : _("Good certificate") );
- rec.r.sig.sig[i].flag = SIGF_CHECKED | SIGF_VALID;
- if( revoked ) { /* we are investigating revocations */
- rec.r.sig.sig[i].flag |= SIGF_REVOKED;
- *mod_down = 1;
- }
- else
- *mod_up = 1;
- }
- else if( rc == G10ERR_NO_PUBKEY ) {
- /* This may happen if the key is still in the trustdb
- * but not available in the keystorage */
- if( (rec.r.sig.sig[i].flag & SIGF_CHECKED) )
- log_info("sig %08lX.%lu/%02X%02X/%08lX: %s\n",
- (ulong)keyid[1], lid, uidhash[18],
- uidhash[19], (ulong)sig->keyid[1],
- _("public key not anymore available") );
- rec.r.sig.sig[i].flag = SIGF_NOPUBKEY;
- *mod_down = 1;
- if( revoked )
- rec.r.sig.sig[i].flag |= SIGF_REVOKED;
- }
- else {
- log_info("sig %08lX.%lu/%02X%02X/%08lX: %s: %s\n",
- (ulong)keyid[1], lid, uidhash[18],
- uidhash[19], (ulong)sig->keyid[1],
- revoked? _("Invalid certificate revocation")
- : _("Invalid certificate"),
- g10_errstr(rc));
- rec.r.sig.sig[i].flag = SIGF_CHECKED;
- if( revoked ) {
- rec.r.sig.sig[i].flag |= SIGF_REVOKED;
- *mod_down = 1;
- }
- }
- rec.dirty = 1;
+ keybind_seen = 1;
+ }
+ else if( sig->sig_class == 0x20 && !revoke_seen ) {
+ /* this is a key revocation certificate: check it */
+ rc = check_key_signature( keyblock, node, NULL );
+ if( !rc ) {
+ if( opt.verbose )
+ log_info(_("key %08lX.%lu: Valid key revocation\n"),
+ (ulong)keyid_from_pk(pk, NULL), lid );
+ keyflags |= KEYF_REVOKED; /* fixme: revoke the main key too*/
}
- 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 )) {
- if( !(rec.r.sig.sig[i].flag & SIGF_NOPUBKEY) )
- log_info(_("uid %08lX.%lu/%02X%02X: "
- "has shadow dir %lu but is not yet marked.\n"),
- (ulong)keyid[1], lid,
- uidhash[18], uidhash[19], tmp.recnum );
- rec.r.sig.sig[i].flag = SIGF_NOPUBKEY;
- if( revoked )
- rec.r.sig.sig[i].flag |= SIGF_REVOKED;
- rec.dirty = 1;
- /* fixme: should we verify that the record is
- * in the hintlist? - This case here should anyway
- * never occur */
- }
+ else {
+ log_info(_(
+ "key %08lX.%lu: Invalid key revocation: %s\n"),
+ (ulong)keyid_from_pk(pk,NULL), lid, g10_errstr(rc) );
+ }
+ revoke_seen = 1;
+ }
+ else if( sig->sig_class == 0x28 && !revoke_seen && !is_main ) {
+ /* this is a subkey revocation certificate: check it */
+ /* fixme: we should also check that the revocation
+ * is newer than the key (OpenPGP) */
+ rc = check_key_signature( keyblock, node, NULL );
+ if( !rc ) {
+ if( opt.verbose )
+ log_info(_(
+ "key %08lX.%lu: Valid subkey revocation\n"),
+ (ulong)keyid_from_pk(pk,NULL), lid );
+ keyflags |= KEYF_REVOKED;
}
else {
- log_error(_("sig record %lu[%d] points to wrong record.\n"),
- rec.r.sig.sig[i].lid, i );
- tdbio_invalid();
+ log_info(_(
+ "key %08lX.%lu: Invalid subkey binding: %s\n"),
+ (ulong)keyid_from_pk(pk,NULL), lid, g10_errstr(rc) );
}
+ revoke_seen = 1;
}
- if( found_delrec && delrec.recnum ) {
- delrec = rec;
- found_delrec = 0; /* we only want the first one */
+ /* Hmmm: should we handle direct key signatures here? */
+ }
+
+ return keyflags;
+}
+
+
+static ulong
+make_key_records( KBNODE keyblock, ulong lid, u32 *keyid )
+{
+ TRUSTREC *krecs, **kend, *k, *k2;
+ KBNODE node;
+ PKT_public_key *pk;
+ byte fpr[MAX_FINGERPRINT_LEN];
+ size_t fprlen;
+ ulong keyrecno;
+
+ krecs = NULL; kend = &krecs;
+ for( node=keyblock; node; node = node->next ) {
+ if( node->pkt->pkttype != PKT_PUBLIC_KEY
+ && node->pkt->pkttype != PKT_PUBLIC_SUBKEY )
+ continue;
+ pk = node->pkt->pkt.public_key;
+ fingerprint_from_pk( pk, fpr, &fprlen );
+
+ /* create the key record */
+ k = m_alloc_clear( sizeof *k );
+ k->rectype = RECTYPE_KEY;
+ k->r.key.lid = lid;
+ k->r.key.pubkey_algo = pk->pubkey_algo;
+ k->r.key.fingerprint_len = fprlen;
+ memcpy(k->r.key.fingerprint, fpr, fprlen );
+ k->recnum = tdbio_new_recnum();
+ *kend = k;
+ kend = &k->next;
+
+ k->r.key.keyflags = check_keybinding( keyblock, node, keyid, lid, pk );
+
+ }
+
+ keyrecno = krecs? krecs->recnum : 0;
+ /* write the keylist and release the memory */
+ for( k = krecs; k ; k = k2 ) {
+ if( k->next )
+ k->r.key.next = k->next->recnum;
+ write_record( k );
+ k2 = k->next;
+ m_free( k );
+ }
+ return keyrecno;
+}
+
+
+/****************
+ * Check the validity of a user ID and calculate the uidflags
+ * keynode points to
+ * a node with a user ID. mainkid has the key ID of the primary key
+ * keyblock is the complete keyblock which is needed for signature
+ * checking.
+ */
+static unsigned int
+check_uidsigs( KBNODE keyblock, KBNODE keynode, u32 *mainkid, ulong lid )
+{
+ KBNODE node;
+ unsigned int uidflags = 0;
+ PKT_signature *sig;
+ PKT_signature *selfsig = NULL; /* the latest valid self signature */
+ int rc;
+
+ /* first we check only the selfsignatures */
+ for( node=keynode->next; node; node = node->next ) {
+ if( node->pkt->pkttype == PKT_USER_ID
+ || node->pkt->pkttype == PKT_PUBLIC_SUBKEY )
+ break; /* ready */
+ if( node->pkt->pkttype != PKT_SIGNATURE )
+ continue; /* don't care about other packets */
+ sig = node->pkt->pkt.signature;
+ if( mainkid[0] != sig->keyid[0] || mainkid[1] != sig->keyid[1] )
+ continue; /* we only care about self-signatures for now */
+
+ if( (sig->sig_class&~3) == 0x10 ) { /* regular self signature */
+ rc = check_key_signature( keyblock, node, NULL );
+ if( !rc ) {
+ if( opt.verbose )
+ log_info( "uid %08lX.%lu: %s\n",
+ (ulong)mainkid[1], lid, _("Good self-signature") );
+ uidflags |= UIDF_CHECKED | UIDF_VALID;
+ if( !selfsig )
+ selfsig = sig; /* use the first valid sig */
+ else if( sig->timestamp > selfsig->timestamp
+ && sig->sig_class >= selfsig->sig_class )
+ selfsig = sig; /* but this one is newer */
+ }
+ else {
+ log_info( "uid %08lX: %s: %s\n",
+ (ulong)mainkid[1], _("Invalid self-signature"),
+ g10_errstr(rc) );
+ uidflags |= UIDF_CHECKED;
+ }
}
- if( rec.dirty ) {
- write_record( &rec );
- rec.dirty = 0;
+ }
+
+ /* and now check for revocations - we must do this after the
+ * self signature check because a self-signature which is newer
+ * than a revocation makes the revocation invalid.
+ * Fixme: Is this correct - check with rfc2440 */
+ for( node=keynode->next; node; node = node->next ) {
+ if( node->pkt->pkttype == PKT_USER_ID
+ || node->pkt->pkttype == PKT_PUBLIC_SUBKEY )
+ break; /* ready */
+ if( node->pkt->pkttype != PKT_SIGNATURE )
+ continue; /* don't care about other packets */
+ sig = node->pkt->pkt.signature;
+ if( mainkid[0] != sig->keyid[0] || mainkid[1] != sig->keyid[1] )
+ continue; /* we only care about self-signatures for now */
+
+ if( sig->sig_class == 0x30 ) { /* cert revocation */
+ rc = check_key_signature( keyblock, node, NULL );
+ if( !rc && selfsig && selfsig->timestamp > sig->timestamp ) {
+ log_info( "uid %08lX.%lu: %s\n",
+ (ulong)mainkid[1], lid,
+ _("Valid user ID revocation skipped "
+ "due to a newer self signature") );
+ }
+ else if( !rc ) {
+ if( opt.verbose )
+ log_info( "uid %08lX.%lu: %s\n",
+ (ulong)mainkid[1], lid, _("Valid user ID revocation") );
+ uidflags |= UIDF_CHECKED | UIDF_VALID | UIDF_REVOKED;
+ }
+ else {
+ log_info("uid %08lX: %s: %s\n",
+ (ulong)mainkid[1], _("Invalid user ID revocation"),
+ g10_errstr(rc) );
+ }
}
}
- if( found_sig )
- return;
- /* 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. */
+ return uidflags;
+}
+
- if( !pk_lid ) /* we have already seen that there is no pubkey */
- rc = G10ERR_NO_PUBKEY;
+static unsigned int
+check_sig_record( KBNODE keyblock, KBNODE signode,
+ ulong siglid, int sigidx, u32 *keyid, ulong lid )
+{
+ PKT_signature *sig = signode->pkt->pkt.signature;
+ unsigned int sigflag = 0;
+ TRUSTREC tmp;
+ int revocation=0, rc;
+
+ if( (sig->sig_class&~3) == 0x10 ) /* regular certification */
+ ;
+ else if( sig->sig_class == 0x30 ) /* cert revocation */
+ revocation = 1;
else
- rc = check_key_signature( keyblock, signode, NULL );
+ return SIGF_CHECKED | SIGF_IGNORED;
- if( !rc ) { /* valid signature */
- if( opt.verbose )
- log_info("sig %08lX.%lu/%02X%02X/%08lX: %s\n",
- (ulong)keyid[1], lid, uidhash[18],
- uidhash[19], (ulong)sig->keyid[1],
- revoked? _("Valid certificate revocation")
- : _("Good certificate") );
- newlid = pk_lid; /* this is the pk of the signature */
- newflag = SIGF_CHECKED | SIGF_VALID;
- if( revoked ) {
- newflag |= SIGF_REVOKED;
- *mod_down = 1;
+ read_record( siglid, &tmp, 0 );
+ if( tmp.rectype == RECTYPE_DIR ) {
+ /* the public key is in the trustdb: check sig */
+ rc = check_key_signature( keyblock, signode, NULL );
+ if( !rc ) { /* valid signature */
+ if( opt.verbose )
+ log_info("sig %08lX.%lu/%lu[%d]/%08lX: %s\n",
+ (ulong)keyid[1], lid, siglid, sigidx,
+ (ulong)sig->keyid[1],
+ revocation? _("Valid certificate revocation")
+ : _("Good certificate") );
+ sigflag |= SIGF_CHECKED | SIGF_VALID;
+ if( revocation ) {
+ sigflag |= SIGF_REVOKED;
+ /**mod_down = 1;*/
+ }
+ else
+ /**mod_up = 1*/;
+ }
+ else if( rc == G10ERR_NO_PUBKEY ) {
+ /* This may happen if the key is still in the trustdb
+ * but not available in the keystorage */
+ sigflag |= SIGF_NOPUBKEY;
+ /**mod_down = 1;*/
+ if( revocation )
+ sigflag |= SIGF_REVOKED;
+ }
+ else {
+ log_info("sig %08lX.%lu/%lu[%d]/%08lX: %s: %s\n",
+ (ulong)keyid[1], lid, siglid, sigidx,
+ (ulong)sig->keyid[1],
+ revocation? _("Invalid certificate revocation")
+ : _("Invalid certificate"),
+ g10_errstr(rc));
+ sigflag |= SIGF_CHECKED;
+ if( revocation ) {
+ sigflag |= SIGF_REVOKED;
+ /**mod_down = 1;*/
+ }
}
+ }
+ else if( tmp.rectype == RECTYPE_SDIR ) {
+ /* better 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 ))
+ sigflag |= SIGF_NOPUBKEY;
else
- *mod_up = 1;
- }
- else if( rc == G10ERR_NO_PUBKEY ) {
- if( opt.verbose > 1 || DBG_TRUST )
- log_info("sig %08lX.%lu/%02X%02X/%08lX: %s\n",
- (ulong)keyid[1], lid, uidhash[18],
- uidhash[19], (ulong)sig->keyid[1], g10_errstr(rc) );
- newlid = create_shadow_dir( sig, lid );
- newflag = SIGF_NOPUBKEY;
- if( revoked )
- newflag |= SIGF_REVOKED;
+ log_error(_("sig record %lu[%d] points to wrong record.\n"),
+ siglid, sigidx );
}
else {
- log_info( "sig %08lX.%lu/%02X%02X/%08lX: %s: %s\n",
- (ulong)keyid[1], lid, uidhash[18], uidhash[19],
- (ulong)sig->keyid[1],
- revoked? _("Invalid certificate revocation")
- : _("Invalid certificate"),
- g10_errstr(rc));
- newlid = create_shadow_dir( sig, lid );
- newflag = SIGF_CHECKED;
- if( revoked )
- newflag |= SIGF_REVOKED;
- *mod_down = 1;
+ log_error(_("sig record %lu[%d] points to wrong record.\n"),
+ siglid, sigidx );
+ tdbio_invalid();
}
- if( delrec.recnum ) { /* we can reuse an unused slot */
- delrec.r.sig.sig[delrecidx].lid = newlid;
- delrec.r.sig.sig[delrecidx].flag= newflag;
- write_record( &delrec );
+ return sigflag;
+}
+
+/****************
+ * Make the sig records for the given uid record
+ * We don't set flags here or even check the signatures; this will
+ * happen latter.
+ */
+static ulong
+make_sig_records( KBNODE keyblock, KBNODE uidnode, ulong lid, u32 *mainkid )
+{
+ TRUSTREC *srecs, **s_end, *s=NULL, *s2;
+ KBNODE node;
+ PKT_signature *sig;
+ ulong sigrecno, siglid;
+ int i, sigidx = 0;
+
+ srecs = NULL; s_end = &srecs;
+ for( node=uidnode->next; node; node = node->next ) {
+ if( node->pkt->pkttype == PKT_USER_ID
+ || node->pkt->pkttype == PKT_PUBLIC_SUBKEY )
+ break; /* ready */
+ if( node->pkt->pkttype != PKT_SIGNATURE )
+ continue; /* don't care about other packets */
+ sig = node->pkt->pkt.signature;
+ if( mainkid[0] == sig->keyid[0] && mainkid[1] == sig->keyid[1] )
+ continue; /* we don't care about self-signatures here */
+
+ siglid = find_or_create_lid( sig );
+ /* smash dups */
+ for( s2 = s; s2 ; s2 = s2->next ) {
+ for(i=0; i < sigidx; i++ ) {
+ if( s2->r.sig.sig[i].lid == siglid )
+ goto leaveduptest;
+ }
+ }
+ for( s2 = srecs; s2 ; s2 = s2->next ) {
+ for(i=0; i < SIGS_PER_RECORD; i++ ) {
+ if( s2->r.sig.sig[i].lid == siglid )
+ goto leaveduptest;
+ }
+ }
+ leaveduptest:
+ if( s2 ) {
+ log_info( "sig %08lX.%lu: %s\n", (ulong)mainkid[1], lid,
+ _("duplicated certificate - deleted") );
+ continue;
+ }
+
+ /* create the sig record */
+ if( !sigidx ) {
+ s = m_alloc_clear( sizeof *s );
+ s->rectype = RECTYPE_SIG;
+ s->r.sig.lid = lid;
+ }
+ s->r.sig.sig[sigidx].lid = siglid;
+ s->r.sig.sig[sigidx].flag= check_sig_record( keyblock, node,
+ siglid, sigidx,
+ mainkid, lid );
+ sigidx++;
+ if( sigidx == SIGS_PER_RECORD ) {
+ s->recnum = tdbio_new_recnum();
+ *s_end = s;
+ s_end = &s->next;
+ sigidx = 0;
+ }
+ }
+ if( sigidx ) {
+ s->recnum = tdbio_new_recnum();
+ *s_end = s;
+ s_end = &s->next;
}
- else { /* we 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;
- urec->dirty = 1;
+ sigrecno = srecs? srecs->recnum : 0;
+ /* write the keylist and release the memory */
+ for( s = srecs; s ; s = s2 ) {
+ if( s->next )
+ s->r.sig.next = s->next->recnum;
+ write_record( s );
+ s2 = s->next;
+ m_free( s );
}
+ return sigrecno;
}
+static ulong
+make_uid_records( KBNODE keyblock, ulong lid, u32 *keyid )
+{
+ TRUSTREC *urecs, **uend, *u, *u2;
+ KBNODE node;
+ PKT_user_id *uid;
+ byte uidhash[20];
+ ulong uidrecno;
+
+ urecs = NULL; uend = &urecs;
+ for( node=keyblock; node; node = node->next ) {
+ if( node->pkt->pkttype != PKT_USER_ID )
+ continue;
+ uid = node->pkt->pkt.user_id;
+ rmd160_hash_buffer( uidhash, uid->name, uid->len );
+
+ /* create the uid record */
+ u = m_alloc_clear( sizeof *u );
+ u->rectype = RECTYPE_UID;
+ u->r.uid.lid = lid;
+ memcpy(u->r.uid.namehash, uidhash, 20 );
+ u->recnum = tdbio_new_recnum();
+ *uend = u;
+ uend = &u->next;
+
+ u->r.uid.uidflags = check_uidsigs( keyblock, node, keyid, lid );
+ if( (u->r.uid.uidflags & UIDF_CHECKED)
+ && (u->r.uid.uidflags & UIDF_VALID) )
+ /*make_pref_record( &urec, keyid, selfsig )*/;
+ /* create the list of signatures */
+ u->r.uid.siglist = make_sig_records( keyblock, node, lid, keyid );
+ }
+
+ uidrecno = urecs? urecs->recnum : 0;
+ /* write the uidlist and release the memory */
+ for( u = urecs; u ; u = u2 ) {
+ if( u->next )
+ u->r.uid.next = u->next->recnum;
+ write_record( u );
+ u2 = u->next;
+ m_free( u );
+ }
+ return uidrecno;
+}
+
+
+
/****************
* 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 do not have the public
- * key, the check is done by some special code in insert_trust_record().
*/
int
update_trust_record( KBNODE keyblock, int recheck, int *modified )
{
PKT_public_key *primary_pk;
KBNODE node;
- TRUSTREC drec;
- TRUSTREC krec;
- TRUSTREC urec;
- TRUSTREC prec;
- TRUSTREC helprec;
+ TRUSTREC drec, krec, urec, prec, helprec;
int rc = 0;
u32 keyid[2]; /* keyid of primary key */
- ulong recno, lastrecno;
int mod_up = 0;
int mod_down = 0;
- RECNO_LIST recno_list = NULL; /* list of verified records */
- /* fixme: replace recno_list by a lookup on node->recno */
+ ulong recno, r2;
if( opt.dry_run )
return 0;
@@ -1862,89 +1448,47 @@ update_trust_record( KBNODE keyblock, int recheck, int *modified )
keyid_from_pk( primary_pk, keyid );
- /* fixme: check that the keyblock has a valid structure */
-
rc = tdbio_begin_transaction();
if( rc )
return rc;
- /* update the keys */
- for( node=keyblock; node; node = node->next ) {
- if( node->pkt->pkttype == PKT_PUBLIC_KEY
- || node->pkt->pkttype == PKT_PUBLIC_SUBKEY )
- upd_key_record( keyblock, node, keyid,
- &drec, &recno_list, recheck );
- }
- /* update the user IDs */
- for( node=keyblock; node; node = node->next ) {
- if( node->pkt->pkttype == PKT_USER_ID )
- upd_uid_record( keyblock, node, keyid,
- &drec, &recno_list, recheck, &mod_up, &mod_down );
- }
-
- /* delete keyrecords from the trustdb which are not anymore used */
- /* should we really do this, or is it better to keep them and */
- /* mark as unused? */
- /* And set the revocation flag into the dir record */
- drec.r.dir.dirflags &= ~DIRF_REVOKED;
- lastrecno = 0;
+ /* delete the old stuff */
for( recno=drec.r.dir.keylist; recno; recno = krec.r.key.next ) {
read_record( recno, &krec, RECTYPE_KEY );
- if( recno == drec.r.dir.keylist ) { /* this is the primary key */
- if( (krec.r.key.keyflags & KEYF_REVOKED) ) {
- drec.r.dir.dirflags |= DIRF_REVOKED;
- drec.dirty = 1;
- }
- }
-
- if( !qry_recno_list( recno_list, recno, RECTYPE_KEY ) ) {
- /* delete this one */
- if( !lastrecno ) {
- drec.r.dir.keylist = krec.r.key.next;
- drec.dirty = 1;
- }
- else {
- read_record( lastrecno, &helprec, RECTYPE_KEY );
- helprec.r.key.next = krec.r.key.next;
- write_record( &helprec );
- }
- delete_record( recno );
- }
- else
- lastrecno = recno;
+ delete_record( recno );
}
- /* delete uid records and sig and their pref records from the
- * trustdb which are not anymore used */
- lastrecno = 0;
+ drec.r.dir.keylist = 0;
for( recno=drec.r.dir.uidlist; recno; recno = urec.r.uid.next ) {
read_record( recno, &urec, RECTYPE_UID );
- if( !qry_recno_list( recno_list, recno, RECTYPE_UID ) ) {
- ulong r2;
- /* delete this one */
- if( !lastrecno ) {
- drec.r.dir.uidlist = urec.r.uid.next;
- drec.dirty = 1;
- }
- else {
- read_record( lastrecno, &helprec, RECTYPE_UID );
- helprec.r.uid.next = urec.r.uid.next;
- write_record( &helprec );
- }
- for(r2=urec.r.uid.prefrec ; r2; r2 = prec.r.pref.next ) {
- 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 );
+ for(r2=urec.r.uid.prefrec ; r2; r2 = prec.r.pref.next ) {
+ read_record( r2, &prec, RECTYPE_PREF );
+ delete_record( r2 );
}
- else
- lastrecno = recno;
+ for(r2=urec.r.uid.siglist ; r2; r2 = helprec.r.sig.next ) {
+ read_record( r2, &helprec, RECTYPE_SIG );
+ delete_record( r2 );
+ }
+ delete_record( recno );
}
+ drec.r.dir.uidlist = 0;
+ /* insert new stuff */
+ drec.r.dir.dirflags &= ~DIRF_REVOKED;
+ drec.r.dir.keylist = make_key_records( keyblock, drec.recnum, keyid );
+ drec.r.dir.uidlist = make_uid_records( keyblock, drec.recnum, keyid );
+ #if 0
+ if( orig_uidflags != urec.r.uid.uidflags ) {
+ write_record( &urec );
+ if( !( urec.r.uid.uidflags & UIDF_VALID )
+ || ( urec.r.uid.uidflags & UIDF_REVOKED ) )
+ *mod_down=1;
+ else
+ *mod_up=1; /*(maybe a new user id)*/
+ #endif
+
+ /* FIXME: if the primary key has been revoked, we should
+ set the revoked flag in the dir records */
if( rc )
rc = tdbio_cancel_transaction();
@@ -1953,15 +1497,16 @@ update_trust_record( KBNODE keyblock, int recheck, int *modified )
*modified = 1;
drec.r.dir.dirflags |= DIRF_CHECKED;
drec.r.dir.valcheck = 0;
+ drec.r.dir.checkat = make_timestamp();
write_record( &drec );
- tdbio_write_modify_stamp( mod_up, mod_down );
+ /*tdbio_write_modify_stamp( mod_up, mod_down );*/
rc = tdbio_end_transaction();
}
- rel_recno_list( &recno_list );
return rc;
}
+
/****************
* Insert a trust record into the TrustDB
* This function assumes that the record does not yet exist.
@@ -1976,7 +1521,6 @@ insert_trust_record( PKT_public_key *orig_pk )
byte fingerprint[MAX_FINGERPRINT_LEN];
size_t fingerlen;
int rc = 0;
- ulong hintlist = 0;
PKT_public_key *pk;
@@ -2022,9 +1566,7 @@ insert_trust_record( PKT_public_key *orig_pk )
}
/* 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.
- */
+ * as the 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));
@@ -2032,19 +1574,14 @@ insert_trust_record( PKT_public_key *orig_pk )
}
memset( &dirrec, 0, sizeof dirrec );
dirrec.rectype = RECTYPE_DIR;
- if( !rc ) {
- /* hey, great: this key has already signed other keys
- * convert this to a real directory entry */
- hintlist = shadow.r.sdir.hintlist;
+ if( !rc ) /* we have a shadow dir record - convert to dir record */
dirrec.recnum = shadow.recnum;
- }
- else {
+ else
dirrec.recnum = tdbio_new_recnum();
- }
dirrec.r.dir.lid = dirrec.recnum;
write_record( &dirrec );
- /* out the LID into the keyblock */
+ /* put the LID into the in-memory copy of the keyblock */
pk->local_id = dirrec.r.dir.lid;
orig_pk->local_id = dirrec.r.dir.lid;
for( node=keyblock; node; node = node->next ) {
@@ -2064,18 +1601,137 @@ insert_trust_record( PKT_public_key *orig_pk )
/* and put all the other stuff into the keydb */
rc = update_trust_record( keyblock, 1, NULL );
- if( !rc )
- process_hintlist( hintlist, dirrec.r.dir.lid );
leave:
- if( rc && hintlist )
- ; /* fixme: the hintlist is not anymore anchored */
release_kbnode( keyblock );
do_sync();
return rc;
}
+/****************
+ * Walk over the keyrings and create trustdb records for all keys
+ * It is intended to be used after a fast-import operation.
+ */
+void
+update_trustdb()
+{
+ KBNODE keyblock = NULL;
+ KBPOS kbpos;
+ int rc;
+
+ if( opt.dry_run )
+ return;
+
+ init_trustdb();
+ rc = enum_keyblocks( 0, &kbpos, &keyblock );
+ if( !rc ) {
+ ulong count=0, upd_count=0, err_count=0, new_count=0;
+
+ while( !(rc = enum_keyblocks( 1, &kbpos, &keyblock )) ) {
+ int modified;
+
+ rc = update_trust_record( keyblock, 1, &modified );
+ if( rc == -1 ) { /* not yet in trustdb: insert */
+ PKT_public_key *pk = keyblock->pkt->pkt.public_key;
+ rc = insert_trust_record( pk );
+ if( rc && !pk->local_id ) {
+ log_error(_("lid ?: insert failed: %s\n"),
+ g10_errstr(rc) );
+ err_count++;
+ }
+ else if( rc ) {
+ log_error(_("lid %lu: insert failed: %s\n"),
+ pk->local_id, g10_errstr(rc) );
+ err_count++;
+ }
+ else {
+ if( opt.verbose )
+ log_info(_("lid %lu: inserted\n"), pk->local_id );
+ new_count++;
+ }
+ }
+ else if( rc ) {
+ log_error(_("lid %lu: update failed: %s\n"),
+ lid_from_keyblock(keyblock), g10_errstr(rc) );
+ err_count++;
+ }
+ else if( modified ) {
+ if( opt.verbose )
+ log_info(_("lid %lu: updated\n"),
+ lid_from_keyblock(keyblock));
+ upd_count++;
+ }
+ else if( opt.verbose > 1 )
+ log_info(_("lid %lu: okay\n"), lid_from_keyblock(keyblock) );
+
+ release_kbnode( keyblock ); keyblock = NULL;
+ if( !(++count % 100) )
+ log_info(_("%lu keys so far processed\n"), count);
+ }
+ log_info(_("%lu keys processed\n"), count);
+ if( err_count )
+ log_info(_("\t%lu keys with errors\n"), err_count);
+ if( upd_count )
+ log_info(_("\t%lu keys updated\n"), upd_count);
+ if( new_count )
+ log_info(_("\t%lu keys inserted\n"), new_count);
+ }
+ if( rc && rc != -1 )
+ log_error(_("enumerate keyblocks failed: %s\n"), g10_errstr(rc));
+
+ enum_keyblocks( 2, &kbpos, &keyblock ); /* close */
+ release_kbnode( keyblock );
+}
+
+
+
+/****************
+ * Do all required check in the trustdb. This function walks over all
+ * records in the trustdb and does scheduled processing.
+ */
+void
+check_trustdb( const char *username )
+{
+ TRUSTREC rec;
+ ulong recnum;
+ ulong count=0, upd_count=0, err_count=0, skip_count=0;
+ ulong current_time = make_timestamp();
+
+ if( username )
+ log_info("given user IDs ignored in check_trustdb\n");
+
+ init_trustdb();
+
+ for(recnum=0; !tdbio_read_record( recnum, &rec, 0); recnum++ ) {
+ if( rec.rectype != RECTYPE_DIR )
+ continue; /* we only want the dir records */
+
+ if( count && !(count % 100) && !opt.quiet )
+ log_info(_("%lu keys so far processed\n"), count);
+ count++;
+ if( !rec.r.dir.checkat || rec.r.dir.checkat > current_time ) {
+ skip_count++;
+ continue; /* not scheduled for checking */
+ }
+
+ if( !rec.r.dir.keylist ) {
+ log_info(_("lid %lu: dir record w/o key - skipped\n"), recnum);
+ skip_count++;
+ continue;
+ }
+
+ }
+
+ log_info(_("%lu keys processed\n"), count);
+ if( skip_count )
+ log_info(_("\t%lu keys skipped\n"), skip_count);
+ if( err_count )
+ log_info(_("\t%lu keys with errors\n"), err_count);
+ if( upd_count )
+ log_info(_("\t%lu keys updated\n"), upd_count);
+}
+
/***********************************************
@@ -2499,184 +2155,6 @@ clear_trust_checked_flag( PKT_public_key *pk )
}
-/****************
- * Put new entries from the pubrings into the trustdb.
- * This function honors the sig flags to speed up the check.
- */
-void
-update_trustdb( )
-{
- KBNODE keyblock = NULL;
- KBPOS kbpos;
- int rc;
-
- if( opt.dry_run )
- return;
-
- init_trustdb();
- rc = enum_keyblocks( 0, &kbpos, &keyblock );
- if( !rc ) {
- ulong count=0, upd_count=0, err_count=0, new_count=0;
-
- while( !(rc = enum_keyblocks( 1, &kbpos, &keyblock )) ) {
- int modified;
-
- rc = update_trust_record( keyblock, 1, &modified );
- if( rc == -1 ) { /* not yet in trustdb: insert */
- PKT_public_key *pk = keyblock->pkt->pkt.public_key;
- rc = insert_trust_record( pk );
- if( rc && !pk->local_id ) {
- log_error(_("lid ?: insert failed: %s\n"),
- g10_errstr(rc) );
- err_count++;
- }
- else if( rc ) {
- log_error(_("lid %lu: insert failed: %s\n"),
- pk->local_id, g10_errstr(rc) );
- err_count++;
- }
- else {
- if( opt.verbose )
- log_info(_("lid %lu: inserted\n"), pk->local_id );
- new_count++;
- }
- }
- else if( rc ) {
- log_error(_("lid %lu: update failed: %s\n"),
- lid_from_keyblock(keyblock), g10_errstr(rc) );
- err_count++;
- }
- else if( modified ) {
- if( opt.verbose )
- log_info(_("lid %lu: updated\n"),
- lid_from_keyblock(keyblock));
- upd_count++;
- }
- else if( opt.verbose > 1 )
- log_info(_("lid %lu: okay\n"), lid_from_keyblock(keyblock) );
-
- release_kbnode( keyblock ); keyblock = NULL;
- if( !(++count % 100) )
- log_info(_("%lu keys so far processed\n"), count);
- }
- log_info(_("%lu keys processed\n"), count);
- if( err_count )
- log_info(_("\t%lu keys with errors\n"), err_count);
- if( upd_count )
- log_info(_("\t%lu keys updated\n"), upd_count);
- if( new_count )
- log_info(_("\t%lu keys inserted\n"), new_count);
- }
- if( rc && rc != -1 )
- log_error(_("enumerate keyblocks failed: %s\n"), g10_errstr(rc));
-
- enum_keyblocks( 2, &kbpos, &keyblock ); /* close */
- release_kbnode( keyblock );
-}
-
-/****************
- * Check the complete trustdb or only the entries for the given username.
- * We check the complete database. If a username is given or the special
- * username "*" is used, a complete recheck is done. With no user ID
- * only the records which are not yet checkd are now checked.
- */
-void
-check_trustdb( const char *username )
-{
- TRUSTREC rec;
- KBNODE keyblock = NULL;
- KBPOS kbpos;
- int rc;
- int recheck = username && *username == '*' && !username[1];
-
- init_trustdb();
- if( username && !recheck ) {
- 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 {
- int modified;
-
- rc = update_trust_record( keyblock, 1, &modified );
- if( rc == -1 ) { /* not yet in trustdb: insert */
- rc = insert_trust_record(
- find_kbnode( keyblock, PKT_PUBLIC_KEY
- ) ->pkt->pkt.public_key );
-
- }
- if( rc )
- log_error(_("%s: update failed: %s\n"),
- username, g10_errstr(rc) );
- else if( modified )
- log_info(_("%s: updated\n"), username );
- else
- log_info(_("%s: okay\n"), username );
-
- }
- release_kbnode( keyblock ); keyblock = NULL;
- }
- else {
- ulong recnum;
- ulong count=0, upd_count=0, err_count=0, skip_count=0;
-
- for(recnum=0; !tdbio_read_record( recnum, &rec, 0); recnum++ ) {
- if( rec.rectype == RECTYPE_DIR ) {
- TRUSTREC tmp;
- int modified;
-
- if( !rec.r.dir.keylist ) {
- log_info(_("lid %lu: dir record w/o key - skipped\n"),
- recnum);
- count++;
- skip_count++;
- 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) );
- count++;
- skip_count++;
- continue;
- }
-
- rc = update_trust_record( keyblock, recheck, &modified );
- if( rc ) {
- log_error(_("lid %lu: update failed: %s\n"),
- recnum, g10_errstr(rc) );
- err_count++;
- }
- else if( modified ) {
- if( opt.verbose )
- log_info(_("lid %lu: updated\n"), recnum );
- upd_count++;
- }
- else if( opt.verbose > 1 )
- log_info(_("lid %lu: okay\n"), recnum );
-
- release_kbnode( keyblock ); keyblock = NULL;
- if( !(++count % 100) )
- log_info(_("%lu keys so far processed\n"), count);
- }
- }
- log_info(_("%lu keys processed\n"), count);
- if( skip_count )
- log_info(_("\t%lu keys skipped\n"), skip_count);
- if( err_count )
- log_info(_("\t%lu keys with errors\n"), err_count);
- if( upd_count )
- log_info(_("\t%lu keys updated\n"), upd_count);
- }
-}
@@ -2828,6 +2306,8 @@ query_trust_info( PKT_public_key *pk, const byte *namehash )
init_trustdb();
if( check_trust( pk, &trustlevel, namehash, NULL, NULL ) )
return '?';
+ if( trustlevel & TRUST_FLAG_DISABLED )
+ return 'd';
if( trustlevel & TRUST_FLAG_REVOKED )
return 'r';
c = trust_letter( (trustlevel & TRUST_MASK) );