From 52be6a8aef56444a8c3f261b50f4c1c3ce2a4a7d Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Wed, 26 Sep 2001 12:49:10 +0000 Subject: [PATCH] completed the new key validation code --- TODO | 5 +- g10/ChangeLog | 9 ++ g10/getkey.c | 1 + g10/keyedit.c | 2 +- g10/keyring.c | 6 +- g10/keyring.o | Bin 65256 -> 0 bytes g10/trustdb.c | 240 ++++++++++++++++++++++++++++++++++++-------------- util/memory.c | 2 +- 8 files changed, 192 insertions(+), 73 deletions(-) delete mode 100644 g10/keyring.o 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 + + * 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 * 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 edce50322a2de8f7fee129f3f2e66ae0416499b1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 65256 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 r=1{ZNtTRWOnext) + 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; } @@ -1016,6 +1016,121 @@ store_validation_status (int depth, KBNODE keyblock) do_sync (); } +/* + * 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 @@ -1023,6 +1138,10 @@ store_validation_status (int depth, KBNODE keyblock) * 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;