1
0
mirror of git://git.gnupg.org/gnupg.git synced 2024-12-22 10:19:57 +01:00

overhauled the trustdb stuff

This commit is contained in:
Werner Koch 1998-11-05 18:00:08 +00:00
parent b9dd2ebb2c
commit aad7f1a0fc
2 changed files with 347 additions and 273 deletions

18
doc/FAQ
View File

@ -282,6 +282,20 @@
For more see the chapter "The Web of Trust" in the For more see the chapter "The Web of Trust" in the
Manual [gpg: Oops: Internal error: manual not found - sorry] Manual [gpg: Oops: Internal error: manual not found - sorry]
Q: How do interpret some of the informational outputs:
A: While checking the validness of a key, GnuPG sometimes print
some informations which are prefixed with information about
the checked item:
"key 12345678.3456"
This is about the key with key ID 12345678 and the internal
number 3456, which is the record number of the so called
directory record in the trustdb.
"uid 12345678.3456/ACDE"
This is about the user ID for the same key; to identify the
user ID the last two bytes of a ripe-md-160 over the user ID
tring is printed.
"sig 12345678.3456/ACDE/9A8B7C6D"
This is about the signature with key ID 9A8B7C6D for the
above key and user ID, if it is a signature which is direct
on a key, the user ID part is empty (..//..).

View File

@ -98,6 +98,11 @@ static int list_sigs( ulong pubkey_id );
static int do_check( TRUSTREC *drec, unsigned *trustlevel ); static int do_check( TRUSTREC *drec, unsigned *trustlevel );
static int get_dir_record( PKT_public_key *pk, TRUSTREC *rec ); 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 revoke );
/* a table used to keep track of ultimately trusted keys /* a table used to keep track of ultimately trusted keys
* which are the ones from our secrings */ * which are the ones from our secrings */
@ -769,7 +774,12 @@ collect_paths( int depth, int max_depth, int all, TRUSTREC *drec,
read_record( rn, &rec, RECTYPE_UID ); read_record( rn, &rec, RECTYPE_UID );
uidrn = rec.r.uid.next; uidrn = rec.r.uid.next;
/* fixme: continue if the uidrec is not marked valid */ if( !(rec.r.uid.uidflags & UIDF_CHECKED) )
continue; /* user id has not been checked */
if( !(rec.r.uid.uidflags & UIDF_VALID) )
continue; /* user id is not valid */
if( (rec.r.uid.uidflags & UIDF_REVOKED) )
continue; /* user id has been revoked */
/* loop over all signature records */ /* loop over all signature records */
for( rn = rec.r.uid.siglist; rn; rn = sigrn ) { for( rn = rec.r.uid.siglist; rn; rn = sigrn ) {
@ -1650,6 +1660,7 @@ check_hint_sig( ulong lid, KBNODE keyblock, u32 *keyid, byte *uidrec_hash,
PKT_signature *sigpkt = NULL; PKT_signature *sigpkt = NULL;
TRUSTREC tmp; TRUSTREC tmp;
u32 sigkid[2]; u32 sigkid[2];
int revoke = 0;
if( sigrec->r.sig.sig[sigidx].flag & SIGF_CHECKED ) if( sigrec->r.sig.sig[sigidx].flag & SIGF_CHECKED )
log_info(_("note: sig rec %lu[%d] in hintlist " log_info(_("note: sig rec %lu[%d] in hintlist "
@ -1664,7 +1675,7 @@ check_hint_sig( ulong lid, KBNODE keyblock, u32 *keyid, byte *uidrec_hash,
if( tmp.rectype != RECTYPE_DIR ) { if( tmp.rectype != RECTYPE_DIR ) {
/* we need the dir record */ /* we need the dir record */
log_error(_("sig rec %lu[%d] in hintlist " log_error(_("sig rec %lu[%d] in hintlist "
"of %u does not point to a dir record\n"), "of %lu does not point to a dir record\n"),
sigrec->recnum, sigidx, hint_owner ); sigrec->recnum, sigidx, hint_owner );
return; return;
} }
@ -1693,7 +1704,8 @@ check_hint_sig( ulong lid, KBNODE keyblock, u32 *keyid, byte *uidrec_hash,
sigpkt = node->pkt->pkt.signature; sigpkt = node->pkt->pkt.signature;
if( sigpkt->keyid[0] == sigkid[0] if( sigpkt->keyid[0] == sigkid[0]
&& sigpkt->keyid[1] == sigkid[1] && sigpkt->keyid[1] == sigkid[1]
&& (sigpkt->sig_class&~3) == 0x10 ) { && ( (sigpkt->sig_class&~3) == 0x10
|| ( revoke = (sigpkt->sig_class == 0x30)) ) ) {
state = 2; state = 2;
break; /* found */ break; /* found */
} }
@ -1715,23 +1727,29 @@ check_hint_sig( ulong lid, KBNODE keyblock, u32 *keyid, byte *uidrec_hash,
log_error(_("lid %lu: self-signature in hintlist\n"), lid ); log_error(_("lid %lu: self-signature in hintlist\n"), lid );
return; return;
} }
/* FiXME: handling fo SIGF_REVOKED is not correct! */
if( !rc ) { /* valid signature */ if( !rc ) { /* valid signature */
if( opt.verbose ) if( opt.verbose )
log_info(_("key %08lX.%lu, uid %02X%02X, sig %08lX: " log_info("sig %08lX.%lu/%02X%02X/%08lX: %s\n",
"Good signature (3)\n"),
(ulong)keyid[1], lid, uhash[18], uhash[19], (ulong)keyid[1], lid, uhash[18], uhash[19],
(ulong)sigpkt->keyid[1] ); (ulong)sigpkt->keyid[1],
revoke? _("Valid certificate revocation")
: _("Good certificate") );
sigrec->r.sig.sig[sigidx].flag = SIGF_CHECKED | SIGF_VALID; sigrec->r.sig.sig[sigidx].flag = SIGF_CHECKED | SIGF_VALID;
if( revoke )
sigrec->r.sig.sig[sigidx].flag |= SIGF_REVOKED;
} }
else if( rc == G10ERR_NO_PUBKEY ) { else if( rc == G10ERR_NO_PUBKEY ) {
log_info(_("key %08lX.%lu, uid %02X%02X, sig %08lX: " log_info("sig %08lX.%lu/%02X%02X/%08lX: %s\n",
"very strange: no public key\n"),
(ulong)keyid[1], lid, uhash[18], uhash[19], (ulong)keyid[1], lid, uhash[18], uhash[19],
(ulong)sigpkt->keyid[1] ); (ulong)sigpkt->keyid[1],
_("very strange: no public key\n") );
sigrec->r.sig.sig[sigidx].flag = SIGF_NOPUBKEY; sigrec->r.sig.sig[sigidx].flag = SIGF_NOPUBKEY;
} }
else { else {
log_info(_("key %08lX.%lu, uid %02X%02X, sig %08lX: %s\n"), log_info("sig %08lX.%lu/%02X%02X/%08lX: %s\n",
(ulong)keyid[1], lid, uhash[18], uhash[19], (ulong)keyid[1], lid, uhash[18], uhash[19],
(ulong)sigpkt->keyid[1], g10_errstr(rc) ); (ulong)sigpkt->keyid[1], g10_errstr(rc) );
sigrec->r.sig.sig[sigidx].flag = SIGF_CHECKED; sigrec->r.sig.sig[sigidx].flag = SIGF_CHECKED;
@ -1923,8 +1941,8 @@ upd_key_record( KBNODE keyblock, KBNODE keynode, u32 *keyid,
{ {
TRUSTREC krec; TRUSTREC krec;
KBNODE node; KBNODE node;
PKT_public_key *pk = keynode->pkt->pkt.public_key,; PKT_public_key *pk = keynode->pkt->pkt.public_key;
ulon lid = drec->recnum; ulong lid = drec->recnum;
byte fpr[MAX_FINGERPRINT_LEN]; byte fpr[MAX_FINGERPRINT_LEN];
size_t fprlen; size_t fprlen;
ulong recno, newrecno; ulong recno, newrecno;
@ -1982,75 +2000,78 @@ upd_key_record( KBNODE keyblock, KBNODE keynode, u32 *keyid,
} }
for( node=keynode->next; node; node = node->next ) { for( node=keynode->next; node; node = node->next ) {
PKT_signature *sig;
if( node->pkt->pkttype == PKT_PUBLIC_SUBKEY ) if( node->pkt->pkttype == PKT_PUBLIC_SUBKEY )
break; /* ready */ break; /* ready */
else if( node->pkt->pkttype == PKT_PUBLIC_SIGNATURE ) { else if( node->pkt->pkttype != PKT_SIGNATURE )
PKT_signature *sig = node->pkt->pkt.signature; continue;
if( keyid[0] != sig->keyid[0] || keyid[1] != sig->keyid[1] ) sig = node->pkt->pkt.signature;
continue; /* not a self signature */
if( sig->sig_class == 0x18 && !keybind_seen ) { /* a keybinding */ if( keyid[0] != sig->keyid[0] || keyid[1] != sig->keyid[1] )
if( keynode->pkt->pkttype == PKT_PUBLIC_KEY ) continue; /* not a self signature */
continue; /* oops, not for a main key */ if( sig->sig_class == 0x18 && !keybind_seen ) { /* a keybinding */
/* we check until we find a valid keybinding */ if( keynode->pkt->pkttype == PKT_PUBLIC_KEY )
rc = check_key_signature( keyblock, node, NULL ); continue; /* oops, not for a main key */
if( !rc ) { /* we check until we find a valid keybinding */
if( opt.verbose ) rc = check_key_signature( keyblock, node, NULL );
log_info(_( if( !rc ) {
"key %08lX.%lu: Good subkey binding\n"), if( opt.verbose )
(ulong)keyid_from_pk(pk,NULL), lid );
krec.r.key.keyflags |= KEYF_CHECKED | KEYF_VALID;
}
else {
log_info(_( log_info(_(
"key %08lX.%lu: Invalid subkey binding: %s\n"), "key %08lX.%lu: Good subkey binding\n"),
(ulong)keyid_from_pk(pk,NULL), lid, g10_errstr(rc) ); (ulong)keyid_from_pk(pk,NULL), lid );
krec.r.key.keyflags |= KEYF_CHECKED; krec.r.key.keyflags |= KEYF_CHECKED | KEYF_VALID;
krec.r.key.keyflags &= ~KEYF_VALID;
}
keybind_seen = 1;
} }
else if( sig->sig_class == 0x20 && !revoke_seen ) { else {
if( keynode->pkt->pkttype == PKT_PUBLIC_SUBKEY ) log_info(_(
continue; /* a subkey is not expected here */ "key %08lX.%lu: Invalid subkey binding: %s\n"),
/* This is a key revocation certificate: check it */ (ulong)keyid_from_pk(pk,NULL), lid, g10_errstr(rc) );
rc = check_key_signature( keyblock, node, NULL ); krec.r.key.keyflags |= KEYF_CHECKED;
if( !rc ) { krec.r.key.keyflags &= ~KEYF_VALID;
if( opt.verbose ) }
log_info(_( keybind_seen = 1;
"key %08lX.%lu: Valid key revocation\n"), }
(ulong)keyid_from_pk(pk,NULL), lid ); else if( sig->sig_class == 0x20 && !revoke_seen ) {
krec.r.key.keyflags |= KEYF_REVOKED; if( keynode->pkt->pkttype == PKT_PUBLIC_SUBKEY )
} continue; /* a subkey is not expected here */
else { /* This is a key revocation certificate: check it */
rc = check_key_signature( keyblock, node, NULL );
if( !rc ) {
if( opt.verbose )
log_info(_( log_info(_(
"key %08lX.%lu: Invalid key revocation: %s\n"), "key %08lX.%lu: Valid key revocation\n"),
(ulong)keyid_from_pk(pk,NULL), lid, g10_errstr(rc) ); (ulong)keyid_from_pk(pk,NULL), lid );
} krec.r.key.keyflags |= KEYF_REVOKED;
revoke_seen = 1;
} }
else if( sig->sig_class == 0x28 && !revoke_seen ) { else {
if( keynode->pkt->pkttype == PKT_PUBLIC_KEY ) log_info(_(
continue; /* a mainkey is not expected here */ "key %08lX.%lu: Invalid key revocation: %s\n"),
/* This is a subkey revocation certificate: check it */ (ulong)keyid_from_pk(pk,NULL), lid, g10_errstr(rc) );
/* fixme: we should also check the revocation }
* is newer tha the key (OpenPGP) */ revoke_seen = 1;
rc = check_key_signature( keyblock, node, NULL ); }
if( !rc ) { else if( sig->sig_class == 0x28 && !revoke_seen ) {
if( opt.verbose ) if( keynode->pkt->pkttype == PKT_PUBLIC_KEY )
log_info(_( continue; /* a mainkey is not expected here */
"key %08lX.%lu: Valid subkey revocation\n"), /* This is a subkey revocation certificate: check it */
(ulong)keyid_from_pk(pk,NULL), lid ); /* fixme: we should also check the revocation
krec.r.key.keyflags |= KEYF_REVOKED; * is newer than the key (OpenPGP) */
} rc = check_key_signature( keyblock, node, NULL );
else { if( !rc ) {
if( opt.verbose )
log_info(_( log_info(_(
"key %08lX.%lu: Invalid subkey binding: %s\n"), "key %08lX.%lu: Valid subkey revocation\n"),
(ulong)keyid_from_pk(pk,NULL), lid, g10_errstr(rc) ); (ulong)keyid_from_pk(pk,NULL), lid );
} krec.r.key.keyflags |= KEYF_REVOKED;
revoke_seen = 1;
} }
} /* end signature */ else {
log_info(_(
"key %08lX.%lu: Invalid subkey binding: %s\n"),
(ulong)keyid_from_pk(pk,NULL), lid, g10_errstr(rc) );
}
revoke_seen = 1;
}
} }
write_record( &krec ); write_record( &krec );
@ -2076,22 +2097,24 @@ upd_uid_record( KBNODE keyblock, KBNODE uidnode, u32 *keyid,
ulong lid = drec->recnum; ulong lid = drec->recnum;
PKT_user_id *uid = uidnode->pkt->pkt.user_id; PKT_user_id *uid = uidnode->pkt->pkt.user_id;
TRUSTREC urec; TRUSTREC urec;
PKT_signature *selfsig = NULL;
byte uidhash[20]; byte uidhash[20];
KBNODE node;
ulong recno, newrecno; ulong recno, newrecno;
int rc;
/* see whether we already have an uid record */ /* see whether we already have an uid record */
WORK WORK
rmd160_hash_buffer( uidhash, uid->name, uid->len ); rmd160_hash_buffer( uidhash, uid->name, uid->len );
for( recno=drec->r.dir.uidlist; recno; recno = urec.r.uid.next ) { for( recno=drec->r.dir.uidlist; recno; recno = urec.r.uid.next ) {
read_record( recno, &urec, RECTYPE_UID ); read_record( recno, &urec, RECTYPE_UID );
if( !memcmp( uidhash, urec.r.uid.namehash, 20 ) ) if( !memcmp( uidhash, urec.r.uid.namehash, 20 ) )
break; break;
} }
if( recno ) { if( recno ) { /* we already have this record */
ins_recno_list( recno_list, recno, RECTYPE_UID ); ins_recno_list( recno_list, recno, RECTYPE_UID );
*uidrecno = recno;
} }
else { /* new user id */ else { /* new user id */
recheck = 1;
memset( &urec, 0 , sizeof(urec) ); memset( &urec, 0 , sizeof(urec) );
urec.rectype = RECTYPE_UID; urec.rectype = RECTYPE_UID;
urec.r.uid.lid = drec->recnum; urec.r.uid.lid = drec->recnum;
@ -2105,131 +2128,229 @@ upd_uid_record( KBNODE keyblock, KBNODE uidnode, u32 *keyid,
drec->dirty = 1; drec->dirty = 1;
} }
else { /* we already have an uid, append it to the list */ else { /* we already have an uid, append it to the list */
TRUSTREC save = urec;
for( ; recno; recno = urec.r.key.next ) for( ; recno; recno = urec.r.key.next )
read_record( recno, &urec, RECTYPE_UID ); read_record( recno, &urec, RECTYPE_UID );
urec.r.uid.next = newrecno; urec.r.uid.next = newrecno;
write_record( &urec ); write_record( &urec );
urec = save;
} }
*uidrecno = newrecno;
} }
if( recheck || !(urec.r.uid.uidflags & UIDF_CHECKED) ) {
/* check self signatures */
urec.r.uid.uidflags = 0;
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 {
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;
}
}
else if( sig->sig_class == 0x30 ) { /* cert revocation */
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],
_("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) );
}
}
}
write_record( &urec );
} /* 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 );
/* check non-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; /* skip self signature */
if( (sig->sig_class&~3) == 0x10 ) { /* regular certification */
upd_cert_record( keyblock, node, keyid, drec, recno_list,
recheck, &urec, uidhash, 0 );
}
else if( sig->sig_class == 0x30 ) { /* cert revocation */
upd_cert_record( keyblock, node, keyid, drec, recno_list,
recheck, &urec, uidhash, 1 );
}
} /* end check certificates */
write_record( &urec );
} }
/****************
*
*
*/
static void static void
upd_pref_record( PKT_signature *sig, ulong lid, const u32 *keyid, upd_pref_record( TRUSTREC *urec, u32 *keyid, PKT_signature *sig )
TRUSTREC *urec, const byte *uidhash )
{ {
static struct { static struct {
sigsubpkttype_t subpkttype; sigsubpkttype_t subpkttype;
int preftype; int preftype;
} prefs[] = { } ptable[] = {
{ SIGSUBPKT_PREF_SYM, PREFTYPE_SYM }, { SIGSUBPKT_PREF_SYM, PREFTYPE_SYM },
{ SIGSUBPKT_PREF_HASH, PREFTYPE_HASH }, { SIGSUBPKT_PREF_HASH, PREFTYPE_HASH },
{ SIGSUBPKT_PREF_COMPR, PREFTYPE_COMPR }, { SIGSUBPKT_PREF_COMPR, PREFTYPE_COMPR },
{ 0, 0 } { 0, 0 }
}; };
TRUSTREC prec; TRUSTREC prec;
ulong lid = urec->r.uid.lid ;
const byte *uidhash = urec->r.uid.namehash;
const byte *s; const byte *s;
size_t n; size_t n;
int k, i; int k, i;
ulong recno_tbl[10];
int recno_idx = 0;
ulong recno; ulong recno;
byte prefs_sig[200];
int n_prefs_sig = 0;
byte prefs_rec[200];
int n_prefs_rec = 0;
/* First delete all pref records /* check for changed preferences */
for(k=0; ptable[k].subpkttype; k++ ) {
s = parse_sig_subpkt2( sig, ptable[k].subpkttype, &n );
if( s ) {
if( n_prefs_sig >= DIM(prefs_sig)-1 ) {
log_info("uid %08lX.%lu/%02X%02X: %s\n",
(ulong)keyid[1], lid, uidhash[18], uidhash[19],
_("Too many preferences") );
break;
}
prefs_sig[n_prefs_sig++] = ptable[k].preftype;
prefs_sig[n_prefs_sig++] = *s;
}
}
for( recno=urec->r.uid.prefrec; recno; recno = prec.r.pref.next ) {
read_record( recno, &prec, RECTYPE_PREF );
for(i = 0; i < ITEMS_PER_PREF_RECORD; i +=2 ) {
if( n_prefs_rec >= DIM(prefs_rec)-1 ) {
log_info("uid %08lX.%lu/%02X%02X: %s\n",
(ulong)keyid[1], lid, uidhash[18], uidhash[19],
_("Too many preferences items") );
break;
}
prefs_rec[n_prefs_rec++] = prec.r.pref.data[i];
prefs_rec[n_prefs_rec++] = prec.r.pref.data[i+1];
}
}
if( n_prefs_sig == n_prefs_rec
&& !memcmp( prefs_sig, prefs_rec, n_prefs_sig ) )
return; /* not chnaged */
/* Preferences have changed: Delete all pref records
* This is much simpler than checking whether we have to * This is much simpler than checking whether we have to
* do update the record at all - the record cache may care about it * do update the record at all - the record cache may care about it
* FIXME: We never get correct statistics if we do it like this */ */
for( recno=urec->r.uid.prefrec; recno; recno = prec.r.pref.next ) { for( recno=urec->r.uid.prefrec; recno; recno = prec.r.pref.next ) {
read_record( recno, &prec, RECTYPE_PREF ); read_record( recno, &prec, RECTYPE_PREF );
delete_record( recno ); delete_record( recno );
} }
/* and write the new ones */ if( n_prefs_sig > ITEMS_PER_PREF_RECORD )
i = 0; log_info("cannot yet handle long preferences");
for(k=0; prefs[k].subpkttype; k++ ) {
s = parse_sig_subpkt2( sig, prefs[k].subpkttype, &n ); memset( &prec, 0, sizeof prec );
if( s ) { prec.recnum = tdbio_new_recnum();
while( n ) { prec.rectype = RECTYPE_PREF;
if( !i || i >= ITEMS_PER_PREF_RECORD ) { prec.r.pref.lid = lid;
if( recno_idx >= DIM(recno_tbl)-1 ) { if( n_prefs_sig <= ITEMS_PER_PREF_RECORD )
log_info("too many preferences\n"); memcpy( prec.r.pref.data, prefs_sig, n_prefs_sig );
break; else { /* need more than one pref record */
} TRUSTREC tmp;
if( i ) { ulong nextrn;
recno_tbl[recno_idx]=tdbio_new_recnum(); int n = n_prefs_sig;
prec.recnum = recno_tbl[recno_idx++]; byte *pp = prefs_sig;
write_record( &prec );
} memcpy( prec.r.pref.data, pp, ITEMS_PER_PREF_RECORD );
memset( &prec, 0, sizeof prec ); n -= ITEMS_PER_PREF_RECORD;
prec.rectype = RECTYPE_PREF; pp += ITEMS_PER_PREF_RECORD;
prec.r.pref.lid = lid; nextrn = prec.r.pref.next = tdbio_new_recnum();
i = 0; do {
} memset( &tmp, 0, sizeof tmp );
prec.r.pref.data[i++] = prefs[k].preftype; tmp.recnum = nextrn;
prec.r.pref.data[i++] = *s++; tmp.rectype = RECTYPE_PREF;
n--; tmp.r.pref.lid = lid;
if( n <= ITEMS_PER_PREF_RECORD ) {
memcpy( tmp.r.pref.data, pp, n );
n = 0;
} }
} else {
memcpy( tmp.r.pref.data, pp, ITEMS_PER_PREF_RECORD );
n -= ITEMS_PER_PREF_RECORD;
pp += ITEMS_PER_PREF_RECORD;
nextrn = tmp.r.pref.next = tdbio_new_recnum();
}
write_record( &tmp );
} while( n );
} }
if( i ) { /* write the last one */ write_record( &prec );
recno_tbl[recno_idx]=tdbio_new_recnum(); urec->r.uid.prefrec = prec.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;
urec->dirty = 1; urec->dirty = 1;
} }
/****************
* update self key signatures (class 0x10..0x13)
*/
static void static void
upd_self_key_sigs( PKT_signature *sig, TRUSTREC *urec, upd_cert_record( KBNODE keyblock, KBNODE signode, u32 *keyid,
ulong lid, const u32 *keyid, const byte *uidhash, TRUSTREC *drec, RECNO_LIST *recno_list, int recheck,
KBNODE keyblock, KBNODE signode) TRUSTREC *urec, const byte *uidhash, int revoke )
{
int rc;
/* must verify this selfsignature here, so that we can
* build the preference record and validate the uid record
*/
if( !(urec->r.uid.uidflags & UIDF_CHECKED) ) {
rc = check_key_signature( keyblock, signode, NULL );
if( !rc ) {
if( opt.verbose )
log_info(_(
"key %08lX.%lu, uid %02X%02X: Good self-signature\n"),
(ulong)keyid[1], lid, uidhash[18], uidhash[19] );
upd_pref_record( sig, lid, keyid, urec, uidhash );
urec->r.uid.uidflags = UIDF_CHECKED | UIDF_VALID;
}
else {
log_info(_("key %08lX, uid %02X%02X: Invalid self-signature: %s\n"),
(ulong)keyid[1], uidhash[18], uidhash[19], g10_errstr(rc) );
urec->r.uid.uidflags = UIDF_CHECKED;
}
urec->dirty = 1;
}
}
/****************
* update non-self key signatures (class 0x10..0x13)
*/
static void
upd_nonself_key_sigs( PKT_signature *sig, TRUSTREC *urec,
ulong lid, const u32 *keyid, const byte *uidhash,
KBNODE keyblock, KBNODE signode, int fast)
{ {
/* We simply insert the signature into the sig records but /* We simply insert the signature into the sig records but
* avoid duplicate ones. We do not check them here because * avoid duplicate ones. We do not check them here because
@ -2240,6 +2361,8 @@ upd_nonself_key_sigs( PKT_signature *sig, TRUSTREC *urec,
* be converted to a dir record as soon as a new public key is * be converted to a dir record as soon as a new public key is
* inserted into the trustdb. * inserted into the trustdb.
*/ */
ulong lid = drec->recnum;
PKT_signature *sig = signode->pkt->pkt.signature;
TRUSTREC rec; TRUSTREC rec;
ulong recno; ulong recno;
TRUSTREC delrec; TRUSTREC delrec;
@ -2294,19 +2417,19 @@ upd_nonself_key_sigs( PKT_signature *sig, TRUSTREC *urec,
} }
if( rec.r.sig.sig[i].lid == pk_lid ) { if( rec.r.sig.sig[i].lid == pk_lid ) {
if( found_sig ) { if( found_sig ) {
log_info(_("key %08lX.%lu, uid %02X%02X, sig %08lX: " log_info( "sig %08lX.%lu/%02X%02X/%08lX: %s\n",
"duplicated signature - deleted\n"), (ulong)keyid[1], lid, uidhash[18],
(ulong)keyid[1], lid, uidhash[18], uidhash[19], (ulong)sig->keyid[1],
uidhash[19], (ulong)sig->keyid[1] ); _("Duplicated certificate - deleted") );
rec.r.sig.sig[i].lid = 0; rec.r.sig.sig[i].lid = 0;
rec.dirty = 1; rec.dirty = 1;
continue; continue;
} }
found_sig = 1; found_sig = 1;
} }
if( fast && (rec.r.sig.sig[i].flag & SIGF_CHECKED) ) if( !recheck && !revoke && (rec.r.sig.sig[i].flag & SIGF_CHECKED) )
continue; /* we already checked this signature */ continue; /* we already checked this signature */
if( fast && (rec.r.sig.sig[i].flag & SIGF_NOPUBKEY) ) if( !recheck && (rec.r.sig.sig[i].flag & SIGF_NOPUBKEY) )
continue; /* we do not have the public key */ continue; /* we do not have the public key */
read_record( rec.r.sig.sig[i].lid, &tmp, 0 ); read_record( rec.r.sig.sig[i].lid, &tmp, 0 );
@ -2315,28 +2438,35 @@ upd_nonself_key_sigs( PKT_signature *sig, TRUSTREC *urec,
rc = check_key_signature( keyblock, signode, NULL ); rc = check_key_signature( keyblock, signode, NULL );
if( !rc ) { /* valid signature */ if( !rc ) { /* valid signature */
if( opt.verbose ) if( opt.verbose )
log_info(_( log_info("sig %08lX.%lu/%02X%02X/%08lX: %s\n",
"key %08lX.%lu, uid %02X%02X, sig %08lX: "
"Good signature (1)\n"),
(ulong)keyid[1], lid, uidhash[18], (ulong)keyid[1], lid, uidhash[18],
uidhash[19], (ulong)sig->keyid[1] ); uidhash[19], (ulong)sig->keyid[1],
revoke? _("Valid certificate revocation")
: _("Good certificate") );
rec.r.sig.sig[i].flag = SIGF_CHECKED | SIGF_VALID; rec.r.sig.sig[i].flag = SIGF_CHECKED | SIGF_VALID;
if( revoke )
rec.r.sig.sig[i].flag |= SIGF_REVOKED;
} }
else if( rc == G10ERR_NO_PUBKEY ) { else if( rc == G10ERR_NO_PUBKEY ) {
if( (rec.r.sig.sig[i].flag & SIGF_CHECKED) ) if( (rec.r.sig.sig[i].flag & SIGF_CHECKED) )
log_info(_("key %08lX.%lu, uid %02X%02X, sig %08lX: " log_info("sig %08lX.%lu/%02X%02X/%08lX: %s\n",
"public key lost\n"),
(ulong)keyid[1], lid, uidhash[18], (ulong)keyid[1], lid, uidhash[18],
uidhash[19], (ulong)sig->keyid[1] ); uidhash[19], (ulong)sig->keyid[1],
_("public key lost") );
rec.r.sig.sig[i].flag = SIGF_NOPUBKEY; rec.r.sig.sig[i].flag = SIGF_NOPUBKEY;
if( revoke )
rec.r.sig.sig[i].flag |= SIGF_REVOKED;
} }
else { else {
log_info(_("key %08lX.%lu, uid %02X%02X, sig %08lX:" log_info("sig %08lX.%lu/%02X%02X/%08lX: %s: %s\n",
" %s\n"),
(ulong)keyid[1], lid, uidhash[18], (ulong)keyid[1], lid, uidhash[18],
uidhash[19], (ulong)sig->keyid[1], uidhash[19], (ulong)sig->keyid[1],
revoke? _("Invalid certificate revocation")
: _("Invalid certificate"),
g10_errstr(rc)); g10_errstr(rc));
rec.r.sig.sig[i].flag = SIGF_CHECKED; rec.r.sig.sig[i].flag = SIGF_CHECKED;
if( revoke )
rec.r.sig.sig[i].flag |= SIGF_REVOKED;
} }
rec.dirty = 1; rec.dirty = 1;
} }
@ -2347,11 +2477,13 @@ upd_nonself_key_sigs( PKT_signature *sig, TRUSTREC *urec,
&& (!tmp.r.sdir.pubkey_algo && (!tmp.r.sdir.pubkey_algo
|| tmp.r.sdir.pubkey_algo == sig->pubkey_algo )) { || tmp.r.sdir.pubkey_algo == sig->pubkey_algo )) {
if( !(rec.r.sig.sig[i].flag & SIGF_NOPUBKEY) ) if( !(rec.r.sig.sig[i].flag & SIGF_NOPUBKEY) )
log_info(_("key %08lX.%lu, uid %02X%02X: " log_info("uid %08lX.%lu/%02X%02X: "
"has shadow dir %lu but not yet marked.\n"), "has shadow dir %lu but not yet marked.\n",
(ulong)keyid[1], lid, (ulong)keyid[1], lid,
uidhash[18], uidhash[19], tmp.recnum ); uidhash[18], uidhash[19], tmp.recnum );
rec.r.sig.sig[i].flag = SIGF_NOPUBKEY; rec.r.sig.sig[i].flag = SIGF_NOPUBKEY;
if( revoke )
rec.r.sig.sig[i].flag |= SIGF_REVOKED;
rec.dirty = 1; rec.dirty = 1;
/* fixme: should we verify that the record is /* fixme: should we verify that the record is
* in the hintlist? - This case here should anyway * in the hintlist? - This case here should anyway
@ -2388,31 +2520,40 @@ upd_nonself_key_sigs( PKT_signature *sig, TRUSTREC *urec,
if( !rc ) { /* valid signature */ if( !rc ) { /* valid signature */
if( opt.verbose ) if( opt.verbose )
log_info(_("key %08lX.%lu, uid %02X%02X, sig %08lX: " log_info("sig %08lX.%lu/%02X%02X/%08lX: %s\n",
"Good signature (2)\n"),
(ulong)keyid[1], lid, uidhash[18], (ulong)keyid[1], lid, uidhash[18],
uidhash[19], (ulong)sig->keyid[1] ); uidhash[19], (ulong)sig->keyid[1],
revoke? _("Valid certificate revocation")
: _("Good certificate") );
newlid = pk_lid; /* this is the pk of the signature */ newlid = pk_lid; /* this is the pk of the signature */
newflag = SIGF_CHECKED | SIGF_VALID; newflag = SIGF_CHECKED | SIGF_VALID;
if( revoke )
newflag |= SIGF_REVOKED;
} }
else if( rc == G10ERR_NO_PUBKEY ) { else if( rc == G10ERR_NO_PUBKEY ) {
if( opt.verbose > 1 ) if( opt.verbose > 1 )
log_info(_("key %08lX.%lu, uid %02X%02X, sig %08lX: " log_info("sig %08lX.%lu/%02X%02X/%08lX: %s\n",
"no public key\n"), (ulong)keyid[1], lid, uidhash[18],
(ulong)keyid[1], lid, uidhash[18], uidhash[19], (ulong)sig->keyid[1], g10_errstr(rc) );
uidhash[19], (ulong)sig->keyid[1] );
newlid = create_shadow_dir( sig, lid ); newlid = create_shadow_dir( sig, lid );
newflag = SIGF_NOPUBKEY; newflag = SIGF_NOPUBKEY;
if( revoke )
newflag |= SIGF_REVOKED;
} }
else { else {
log_info(_("key %08lX.%lu, uid %02X%02X, sig %08lX: %s\n"), log_info( "sig %08lX.%lu/%02X%02X/%08lX: %s: %s\n",
(ulong)keyid[1], lid, uidhash[18], uidhash[19], (ulong)keyid[1], lid, uidhash[18], uidhash[19],
(ulong)sig->keyid[1], g10_errstr(rc)); (ulong)sig->keyid[1],
revoke? _("Invalid certificate revocation")
: _("Invalid certificate"),
g10_errstr(rc));
newlid = create_shadow_dir( sig, lid ); newlid = create_shadow_dir( sig, lid );
newflag = SIGF_CHECKED; newflag = SIGF_CHECKED;
if( revoke )
newflag |= SIGF_REVOKED;
} }
if( delrec.recnum ) { /* we can reuse a deleted slot */ if( delrec.recnum ) { /* we can reuse a deleted/unused slot */
delrec.r.sig.sig[delrecidx].lid = newlid; delrec.r.sig.sig[delrecidx].lid = newlid;
delrec.r.sig.sig[delrecidx].flag= newflag; delrec.r.sig.sig[delrecidx].flag= newflag;
write_record( &delrec ); write_record( &delrec );
@ -2434,80 +2575,6 @@ upd_nonself_key_sigs( PKT_signature *sig, TRUSTREC *urec,
} }
/****************
* Note: A signature made with a secondary 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 fast)
{
TRUSTREC urec;
ulong lid = drec->recnum;
if( !*uidrecno ) {
switch( sig->sig_class ) {
case 0x20:
case 0x28: /* We do not need uids for [sub]key revications */
case 0x18: /* or subkey binding */
memset( &urec, 0, sizeof urec ); /* to catch errors */
break;
default:
log_error("key %08lX: signature (class %02x) without user id\n",
(ulong)keyid[1], sig->sig_class );
return;
}
}
else
read_record( *uidrecno, &urec, RECTYPE_UID );
if( keyid[0] == sig->keyid[0] && keyid[1] == sig->keyid[1] ) {
if( (sig->sig_class&~3) == 0x10 ) {
upd_self_key_sigs( sig, &urec, lid, keyid, uidhash,
keyblock, signode );
}
else if( sig->sig_class == 0x18 ) { /* key binding */
}
else if( sig->sig_class == 0x20 ) { /* key revocation */
/* FIXME */
}
else if( sig->sig_class == 0x28 ) { /* subkey revocation */
/* FIXME */
}
else if( sig->sig_class == 0x30 ) { /* cert revocation */
/* FIXME */
}
}
else if( (sig->sig_class&~3) == 0x10 ) {
upd_nonself_key_sigs( sig, &urec, lid, keyid, uidhash,
keyblock, signode, fast );
}
else if( sig->sig_class == 0x18 ) { /* key binding */
log_info(_("key %08lX: bogus key binding by %08lX\n"),
(ulong)keyid[1], (ulong)sig->keyid[1] );
}
else if( sig->sig_class == 0x20 ) { /* key revocation */
log_info(_("key %08lX: bogus key revocation by %08lX\n"),
(ulong)keyid[1], (ulong)sig->keyid[1] );
}
else if( sig->sig_class == 0x28 ) { /* subkey revocation */
log_info(_("key %08lX: bogus subkey revocation by %08lX\n"),
(ulong)keyid[1], (ulong)sig->keyid[1] );
}
else if( sig->sig_class == 0x30 ) { /* cert revocation */
/* fixme: a signator wants to revoke his certification signature */
}
if( urec.dirty ) {
write_record( &urec );
urec.dirty = 0;
}
}
/**************** /****************
* Update all the info from the public keyblock. * Update all the info from the public keyblock.
* The key must already exist in the keydb. * The key must already exist in the keydb.
@ -2528,8 +2595,6 @@ update_trust_record( KBNODE keyblock, int recheck, int *modified )
int rc = 0; int rc = 0;
u32 keyid[2]; /* keyid of primary key */ u32 keyid[2]; /* keyid of primary key */
ulong recno, lastrecno; ulong recno, lastrecno;
ulong uidrecno = 0;
byte uidhash[20];
RECNO_LIST recno_list = NULL; /* list of verified records */ RECNO_LIST recno_list = NULL; /* list of verified records */
/* fixme: replace recno_list by a lookup on node->recno */ /* fixme: replace recno_list by a lookup on node->recno */
@ -2566,8 +2631,6 @@ update_trust_record( KBNODE keyblock, int recheck, int *modified )
&drec, &recno_list, recheck ); &drec, &recno_list, recheck );
} }
WORk - WORK
/* delete keyrecords from the trustdb which are not anymore used */ /* delete keyrecords from the trustdb which are not anymore used */
/* should we really do this, or is it better to keep them and */ /* should we really do this, or is it better to keep them and */
/* mark as unused? */ /* mark as unused? */
@ -2626,12 +2689,9 @@ update_trust_record( KBNODE keyblock, int recheck, int *modified )
if( rc ) if( rc )
rc = tdbio_cancel_transaction(); rc = tdbio_cancel_transaction();
else { else {
if( drec.dirty ) { write_record( &drec );
drec.r.dir.dirflags &= ~DIRF_CHECKED; /* reset flag */
write_record( &drec );
}
if( modified && tdbio_is_dirty() ) if( modified && tdbio_is_dirty() )
*modified = 0; *modified = 1;
rc = tdbio_end_transaction(); rc = tdbio_end_transaction();
} }
rel_recno_list( &recno_list ); rel_recno_list( &recno_list );