aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWerner Koch <[email protected]>2001-09-26 12:49:10 +0000
committerWerner Koch <[email protected]>2001-09-26 12:49:10 +0000
commit52be6a8aef56444a8c3f261b50f4c1c3ce2a4a7d (patch)
tree020e0d6d37e052978d4b6e60ead83f48671ee51f
parentAdded 2 texinfo file which are actually build files but automake does (diff)
downloadgnupg-52be6a8aef56444a8c3f261b50f4c1c3ce2a4a7d.tar.gz
gnupg-52be6a8aef56444a8c3f261b50f4c1c3ce2a4a7d.zip
completed the new key validation code
-rw-r--r--TODO5
-rw-r--r--g10/ChangeLog9
-rw-r--r--g10/getkey.c1
-rw-r--r--g10/keyedit.c2
-rw-r--r--g10/keyring.c6
-rw-r--r--g10/keyring.obin65256 -> 0 bytes
-rw-r--r--g10/trustdb.c240
-rw-r--r--util/memory.c2
8 files changed, 192 insertions, 73 deletions
diff --git a/TODO b/TODO
index 046267c7f..117cc8e11 100644
--- a/TODO
+++ b/TODO
@@ -1,6 +1,8 @@
* Selection using +wordlist does not work.
+ * Make the offtbl in keyring.c global.
+
* Always use the primary key to sign other keys.
* add listing of notation data
@@ -61,7 +63,8 @@
* Add option to put the list of recipients (from the encryption
layer) into the signatures notation data.
- * Allow to update key signatures.
+ * Allow to update key signatures. It is also not possible to resign
+ an already revoked key signature.
* For FreeBSD only: spit out a message that rndcontrol (8) should be
used to enable the use of IRQs for entropy gathering.
diff --git a/g10/ChangeLog b/g10/ChangeLog
index 8e6185d79..9d11f1c6b 100644
--- a/g10/ChangeLog
+++ b/g10/ChangeLog
@@ -1,3 +1,12 @@
+2001-09-26 Werner Koch <[email protected]>
+
+ * trustdb.c (new_key_hash_table): Increased the table size to 1024
+ and changed the masks accordingly.
+ (validate): Changed stats printing.
+ (mark_usable_uid_certs): New.
+ (cmp_kid_for_make_key_array): Does now check the signatures and
+ figures out a usable one.
+
2001-09-25 Werner Koch <[email protected]>
* keyring.c (new_offset_item,release_offset_items)
diff --git a/g10/getkey.c b/g10/getkey.c
index ad009d3d1..3a1b51839 100644
--- a/g10/getkey.c
+++ b/g10/getkey.c
@@ -442,6 +442,7 @@ seckey_available( u32 *keyid )
{
int rc;
KEYDB_HANDLE hd = keydb_new (1);
+
rc = keydb_search_kid (hd, keyid);
if ( rc == -1 )
rc = G10ERR_NO_SECKEY;
diff --git a/g10/keyedit.c b/g10/keyedit.c
index 2e66b4b6e..9c55b555d 100644
--- a/g10/keyedit.c
+++ b/g10/keyedit.c
@@ -2028,7 +2028,7 @@ menu_revsig( KBNODE keyblock )
}
else if( node->pkt->pkttype == PKT_SIGNATURE
&& ((sig = node->pkt->pkt.signature),
- !seckey_available( sig->keyid ) ) ) {
+ !seckey_available(sig->keyid) ) ) {
if( (sig->sig_class&~3) == 0x10 ) {
tty_printf(_(" signed by %08lX at %s\n"),
(ulong)sig->keyid[1], datestr_from_sig(sig) );
diff --git a/g10/keyring.c b/g10/keyring.c
index 5b5caca49..cdfb65861 100644
--- a/g10/keyring.c
+++ b/g10/keyring.c
@@ -479,7 +479,7 @@ keyring_update_keyblock (KEYRING_HANDLE hd, KBNODE kb)
rc = do_copy (3, hd->found.kr->fname, kb, hd->secret,
hd->found.offset, hd->found.n_packets );
if (!rc) {
- if (hd->current.kr->offtbl)
+ if (hd->current.kr && hd->current.kr->offtbl)
{
/* we do not have the offset but as it is not use it does not
* matter*/
@@ -521,7 +521,7 @@ keyring_insert_keyblock (KEYRING_HANDLE hd, KBNODE kb)
/* do the insert */
rc = do_copy (1, fname, kb, hd->secret, 0, 0 );
- if (!rc && hd->current.kr->offtbl)
+ if (!rc && hd->current.kr && hd->current.kr->offtbl)
{
/* we do not have the offset but as it is not use it does not matter*/
update_offset_hash_table_from_kb (hd->current.kr->offtbl, kb, 0);
@@ -881,7 +881,7 @@ keyring_search (KEYRING_HANDLE hd, KEYDB_SEARCH_DESC *desc, size_t ndesc)
if (rc)
return rc;
- offtbl = hd->current.kr->offtbl;
+ offtbl = hd->secret? NULL:hd->current.kr->offtbl;
offtbl_ready = hd->current.kr->offtbl_ready;
if (!offtbl)
;
diff --git a/g10/keyring.o b/g10/keyring.o
deleted file mode 100644
index edce50322..000000000
--- a/g10/keyring.o
+++ /dev/null
Binary files differ
diff --git a/g10/trustdb.c b/g10/trustdb.c
index fb06e858d..6f3de849d 100644
--- a/g10/trustdb.c
+++ b/g10/trustdb.c
@@ -107,7 +107,7 @@ release_key_items (struct key_item *k)
* For fast keylook up we need a hash table. Each byte of a KeyIDs
* should be distributed equally over the 256 possible values (except
* for v3 keyIDs but we consider them as not important here). So we
- * can just use one byte to index a table of 256 key items.
+ * can just use 10 bits to index a table of 1024 key items.
* Possible optimization: Don not use key_items but other hash_table when the
* duplicates lists gets too large.
*/
@@ -116,7 +116,7 @@ new_key_hash_table (void)
{
struct key_item **tbl;
- tbl = m_alloc_clear (256 * sizeof *tbl);
+ tbl = m_alloc_clear (1024 * sizeof *tbl);
return tbl;
}
@@ -127,7 +127,7 @@ release_key_hash_table (KeyHashTable tbl)
if (!tbl)
return;
- for (i=0; i < 256; i++)
+ for (i=0; i < 1024; i++)
release_key_items (tbl[i]);
m_free (tbl);
}
@@ -140,7 +140,7 @@ test_key_hash_table (KeyHashTable tbl, u32 *kid)
{
struct key_item *k;
- for (k = tbl[(kid[1] & 0xff)]; k; k = k->next)
+ for (k = tbl[(kid[1] & 0x03ff)]; k; k = k->next)
if (k->kid[0] == kid[0] && k->kid[1] == kid[1])
return 1;
return 0;
@@ -154,15 +154,15 @@ add_key_hash_table (KeyHashTable tbl, u32 *kid)
{
struct key_item *k, *kk;
- for (k = tbl[(kid[1] & 0xff)]; k; k = k->next)
+ for (k = tbl[(kid[1] & 0x03ff)]; k; k = k->next)
if (k->kid[0] == kid[0] && k->kid[1] == kid[1])
return; /* already in table */
kk = new_key_item ();
kk->kid[0] = kid[0];
kk->kid[1] = kid[1];
- kk->next = tbl[(kid[1] & 0xff)];
- tbl[(kid[1] & 0xff)] = kk;
+ kk->next = tbl[(kid[1] & 0x03ff)];
+ tbl[(kid[1] & 0x03ff)] = kk;
}
@@ -1017,12 +1017,131 @@ store_validation_status (int depth, KBNODE keyblock)
}
/*
+ * check whether the signature sig is in the klist k
+ */
+static struct key_item *
+is_in_klist (struct key_item *k, PKT_signature *sig)
+{
+ for (; k; k = k->next)
+ {
+ if (k->kid[0] == sig->keyid[0] && k->kid[1] == sig->keyid[1])
+ return k;
+ }
+ return NULL;
+}
+
+/*
+ * Mark the signature of the given UID which are used to certify it.
+ * To do this, we first revmove all signatures which are not valid and
+ * from the remain ones we look for the latest one. If this is not a
+ * certification revocation signature we mark the signature by setting
+ * node flag bit 8. Note that flag bits 9 and 10 are used for internal
+ * purposes.
+ */
+static void
+mark_usable_uid_certs (KBNODE keyblock, KBNODE uidnode,
+ u32 *main_kid, struct key_item *klist, u32 curtime)
+{
+ KBNODE node;
+ PKT_signature *sig = node->pkt->pkt.signature;
+
+ /* first check all signatures */
+ for (node=uidnode->next; node; node = node->next)
+ {
+ node->flag &= ~(1<<8 | 1<<9 | 1<<10);
+ if (node->pkt->pkttype == PKT_USER_ID
+ || node->pkt->pkttype == PKT_PUBLIC_SUBKEY)
+ break; /* ready */
+ if (node->pkt->pkttype != PKT_SIGNATURE)
+ continue;
+
+ sig = node->pkt->pkt.signature;
+ if (sig->keyid[0] == main_kid[0] && sig->keyid[1] == main_kid[1])
+ continue; /* ignore self-signatures */
+ if (!IS_UID_SIG(sig) && !IS_UID_REV(sig))
+ continue; /* we only look at these signature classes */
+ if (!is_in_klist (klist, sig))
+ continue; /* no need to check it then */
+ if (check_key_signature (keyblock, node, NULL))
+ continue; /* ignore invalid signatures */
+ node->flag |= 1<<9;
+ }
+ /* reset the remaining flags */
+ for (; node; node = node->next)
+ node->flag &= ~(1<<8 | 1<<9 | 1 << 10);
+
+ /* kbnode flag usage: bit 9 is here set for signatures to consider,
+ * bit 10 will be set by the loop to keep track of keyIDs already
+ * processed, bit 8 will be set for the usable signatures */
+
+ /* for each cert figure out the latest valid one */
+ for (node=uidnode->next; node; node = node->next)
+ {
+ KBNODE n, signode;
+ u32 kid[2];
+ u32 sigdate;
+
+ if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY)
+ break;
+ if ( !(node->flag & (1<<9)) )
+ continue; /* not a node to look at */
+ if ( (node->flag & (1<<10)) )
+ continue; /* signature with a keyID already processed */
+ node->flag |= (1<<10); /* mark this node as processed */
+ sig = node->pkt->pkt.signature;
+ signode = node;
+ sigdate = sig->timestamp;
+ kid[0] = sig->keyid[0]; kid[1] = sig->keyid[1];
+ for (n=uidnode->next; n; n = n->next)
+ {
+ if (n->pkt->pkttype == PKT_PUBLIC_SUBKEY)
+ break;
+ if ( !(n->flag & (1<<9)) )
+ continue;
+ if ( (n->flag & (1<<10)) )
+ continue; /* shortcut already processed signatures */
+ sig = n->pkt->pkt.signature;
+ if (kid[0] != sig->keyid[0] || kid[1] != sig->keyid[1])
+ continue;
+ n->flag |= (1<<10); /* mark this node as processed */
+ if (sig->timestamp >= sigdate)
+ {
+ signode = n;
+ sigdate = sig->timestamp;
+ }
+ }
+ sig = signode->pkt->pkt.signature;
+ if (IS_UID_SIG (sig))
+ { /* this seems to be a usable one which is not revoked.
+ * Just need to check whether there is an expiration time,
+ * We do the expired certification after finding a suitable
+ * certification, the assumption is that a signator does not
+ * want that after the expiration of his certificate the
+ * system falls back to an older certification which has a
+ * different expiration time */
+ const byte *p;
+
+ p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_SIG_EXPIRE, NULL );
+ if ( p && (sig->timestamp + buffer_to_u32(p)) >= curtime )
+ ; /* signature expired */
+ else
+ signode->flag |= (1<<8); /* yeah eventually we found a good cert */
+ }
+ }
+}
+
+
+/*
* Return true if the key is signed by one of the keys in the given
* key ID list. User IDs with a valid signature are marked by node
* flags as follows:
* flag bit 0: There is at least one signature
* 1: There is marginal confidence that this is a legitimate uid
* 2: There is full confidence that this is a legitimate uid.
+ * 8: Used for internal purposes.
+ * 9: Ditto (in mark_usable_uid_certs())
+ * 10: Ditto (ditto)
+ * This function assumes that all kbnode flags are cleared on entry.
*/
static int
cmp_kid_for_make_key_array (KBNODE kb, void *opaque)
@@ -1033,7 +1152,8 @@ cmp_kid_for_make_key_array (KBNODE kb, void *opaque)
PKT_public_key *pk = kb->pkt->pkt.public_key;
u32 main_kid[2];
int issigned=0, any_signed = 0, fully_count =0, marginal_count = 0;
-
+ u32 curtime = make_timestamp();
+
keyid_from_pk(pk, main_kid);
for (node=kb; node; node = node->next)
{
@@ -1052,42 +1172,23 @@ cmp_kid_for_make_key_array (KBNODE kb, void *opaque)
uidnode = node;
issigned = 0;
fully_count = marginal_count = 0;
+ mark_usable_uid_certs (kb, uidnode, main_kid, klist, curtime);
}
- else if (node->pkt->pkttype == PKT_SIGNATURE)
+ else if (node->pkt->pkttype == PKT_SIGNATURE
+ && (node->flag & (1<<8)) )
{
PKT_signature *sig = node->pkt->pkt.signature;
- if ( sig->keyid[0] == main_kid[0] && sig->keyid[1] == main_kid[1])
- ; /* ignore self-signatures */
- else if ( IS_UID_SIG(sig) )
- { /* certification */
- for (kr=klist; kr; kr = kr->next)
- {
- if (kr->kid[0] == sig->keyid[0]
- && kr->kid[1] == sig->keyid[1])
- {
- /* Hmmm: Should we first look whether this
- * signature has been revoked? Avoids problem in
- * fixing the counters later and we might also
- * want to check the signature here. It might
- * also be worth to find the latest signature
- * first so that we count only one signature for
- * each key */
- if (kr->ownertrust == TRUST_ULTIMATE)
- fully_count = opt.completes_needed;
- else if (kr->ownertrust == TRUST_FULLY)
- fully_count++;
- else if (kr->ownertrust == TRUST_MARGINAL)
- marginal_count++;
- issigned = 1;
- /* fixme: track timestamp to see handle cert revocs */
- break;
- }
- }
- }
- else if ( IS_UID_REV(sig) )
- { /* certificate revocation */
- /* fixme: reset issigned and counter if needed */
+ kr = is_in_klist (klist, sig);
+ if (kr)
+ {
+ if (kr->ownertrust == TRUST_ULTIMATE)
+ fully_count = opt.completes_needed;
+ else if (kr->ownertrust == TRUST_FULLY)
+ fully_count++;
+ else if (kr->ownertrust == TRUST_MARGINAL)
+ marginal_count++;
+ issigned = 1;
}
}
}
@@ -1110,25 +1211,25 @@ cmp_kid_for_make_key_array (KBNODE kb, void *opaque)
/*
* Run the key validation procedure.
*
- *-----------------------------------
- * Assume all signatures are good.
- * Find all ultimately trusted keys (UTK).
- * mark them all as seen.
- * Loop over all key to find keys signed by an UTK.
- * mark key as seen
- * if OWNERTRUST of that key is undefined
- * ask user for ownertrust
- * For each user ID of that key which is signed by the UTK
- * Calculate validity by counting trusted signatures.
- * Set validity of user ID
- * if user ID validity is full
- * Loop over all keys to find keys signed by current key
- * skip those which are already seen.
- *
- *TODO:
- *
- * - Make sure that only valid signatures are checked.
- * - Skip revoked keys.
+ * This works this way:
+ * Step 1: Find all ultimately trusted keys (UTK).
+ * mark them all as seen and put them into klist.
+ * Step 2: loop max_cert_times
+ * Step 3: if OWNERTRUST of any key in klist is undefined
+ * ask user to assign ownertrust
+ * Step 4: Loop over all keys in the keyDB which are not marked seen
+ * Step 5: if key is revoked or expired
+ * mark key as seen
+ * continue loop at Step 4
+ * Step 6: For each user ID of that key signed by a key in klist
+ * Calculate validity by counting trusted signatures.
+ * Set validity of user ID
+ * Step 7: If any signed user ID was found
+ * mark key as seen
+ * End Loop
+ * Step 8: Build a new klist from all fully trusted keys from step 6
+ * End Loop
+ * Ready
*
*/
static int
@@ -1143,20 +1244,21 @@ validate_keys (int interactive)
KBNODE node;
int depth;
int key_count;
- int ot_unknown;
- int ot_undefined;
- int ot_marginal;
- int ot_full;
- int ot_ultimate;
+ int ot_unknown, ot_undefined, ot_never, ot_marginal, ot_full, ot_ultimate;
KeyHashTable visited;
visited = new_key_hash_table ();
+ /* Fixme: Instead of always building a UTK list, we could just build it
+ * here when needed */
if (!utk_list)
{
log_info ("no ultimately trusted keys found\n");
goto leave;
}
+ for (k=utk_list; k; k = k->next)
+ add_key_hash_table (visited, k->kid);
+
klist = utk_list;
kdb = keydb_new (0);
@@ -1165,7 +1267,8 @@ validate_keys (int interactive)
/* See whether we should assign ownertrust values to the
* keys in utk_list.
*/
- ot_unknown = ot_undefined = ot_marginal = ot_full = ot_ultimate = 0;
+ ot_unknown = ot_undefined = ot_never = 0;
+ ot_marginal = ot_full = ot_ultimate = 0;
for (k=klist; k; k = k->next)
{
if (interactive && k->ownertrust == TRUST_UNKNOWN)
@@ -1174,6 +1277,8 @@ validate_keys (int interactive)
ot_unknown++;
else if (k->ownertrust == TRUST_UNDEFINED)
ot_undefined++;
+ else if (k->ownertrust == TRUST_NEVER)
+ ot_never++;
else if (k->ownertrust == TRUST_MARGINAL)
ot_marginal++;
else if (k->ownertrust == TRUST_FULLY)
@@ -1199,9 +1304,10 @@ validate_keys (int interactive)
if (opt.verbose > 1)
dump_key_array (depth, keys);
- log_info (_("depth=%d keys=%d (-=%d q=%d m=%d f=%d u=%d)\n"),
+ log_info (_("checking at depth %d signed=%d"
+ " ot(-/q/n/m/f/u)=%d/%d/%d/%d/%d/%d\n"),
depth, key_count, ot_unknown, ot_undefined,
- ot_marginal, ot_full, ot_ultimate );
+ ot_never, ot_marginal, ot_full, ot_ultimate );
for (kar=keys; kar->keyblock; kar++)
store_validation_status (depth, kar->keyblock);
diff --git a/util/memory.c b/util/memory.c
index 9822b1114..76368cd97 100644
--- a/util/memory.c
+++ b/util/memory.c
@@ -562,7 +562,7 @@ size_t
m_size( const void *a )
{
#ifndef M_GUARD
- log_debug("Ooops, m_size called\n");
+ log_debug("dummy m_size called\n");
return 0;
#else
const byte *p = a;