diff options
Diffstat (limited to 'g10')
-rw-r--r-- | g10/ChangeLog | 13 | ||||
-rw-r--r-- | g10/getkey.c | 14 | ||||
-rw-r--r-- | g10/keyedit.c | 10 | ||||
-rw-r--r-- | g10/keylist.c | 9 | ||||
-rw-r--r-- | g10/keyring.c | 3 | ||||
-rw-r--r-- | g10/skclist.c | 4 | ||||
-rw-r--r-- | g10/trustdb.c | 294 |
7 files changed, 212 insertions, 135 deletions
diff --git a/g10/ChangeLog b/g10/ChangeLog index 6eebdf4ab..c4736394c 100644 --- a/g10/ChangeLog +++ b/g10/ChangeLog @@ -1,5 +1,18 @@ 2001-09-28 Werner Koch <[email protected]> + * keyedit.c (sign_uids): Always use the primary key to sign keys. + * getkey.c (finish_lookup): Hack to return only the primary key if + a certification key has been requested. + + * trustdb.c (cmp_kid_for_make_key_array): Renamed to + (validate_one_keyblock): this and changed arg for direct calling. + (make_key_array): Renamed to + (validate_one_keyblock): this and changed args for direct calling. + (mark_usable_uid_certs, validate_one_keyblock) + (validate_key_list): Add next_expire arg to keep track of + expiration times. + (validate_keys): Ditto for UTKs and write the stamp. + * tdbio.c (migrate_from_v2): Check return code of tbdio_sync. * tdbdump.c (import_ownertrust): Do a tdbio_sync(). diff --git a/g10/getkey.c b/g10/getkey.c index 3a1b51839..7236c4042 100644 --- a/g10/getkey.c +++ b/g10/getkey.c @@ -1110,6 +1110,8 @@ fixup_uidnode ( KBNODE uidnode, KBNODE signode, u32 keycreated ) uid->help_key_usage |= PUBKEY_USAGE_SIG; if ( (*p & 12) ) uid->help_key_usage |= PUBKEY_USAGE_ENC; + /* Note: we do not set the CERT flag here because it can be assumed + * that thre is no real policy to set it. */ } /* ditto or the key expiration */ @@ -1656,7 +1658,7 @@ merge_public_with_secret ( KBNODE pubblock, KBNODE secblock ) * secret subkey is avalable and deletes the public subkey otherwise. * We need this function because we can't delete it later when we * actually merge the secret parts into the pubring. - & The function also plays some games with the node flags. + * The function also plays some games with the node flags. */ static void premerge_public_with_secret ( KBNODE pubblock, KBNODE secblock ) @@ -1754,6 +1756,7 @@ finish_lookup (GETKEY_CTX ctx) PKT_user_id *foundu = NULL; #define USAGE_MASK (PUBKEY_USAGE_SIG|PUBKEY_USAGE_ENC) unsigned int req_usage = ( ctx->req_usage & USAGE_MASK ); + int req_cert = (ctx->req_usage & PUBKEY_USAGE_CERT); u32 latest_date; KBNODE latest_key; u32 curtime = make_timestamp (); @@ -1803,7 +1806,8 @@ finish_lookup (GETKEY_CTX ctx) latest_date = 0; latest_key = NULL; - if ( !foundk || foundk->pkt->pkttype == PKT_PUBLIC_SUBKEY ) { + /* do not look at subkeys if a certification key is requested */ + if ((!foundk || foundk->pkt->pkttype == PKT_PUBLIC_SUBKEY) && !req_cert) { KBNODE nextk; /* either start a loop or check just this one subkey */ for (k=foundk?foundk:keyblock; k; k = nextk ) { @@ -1854,11 +1858,11 @@ finish_lookup (GETKEY_CTX ctx) } } - /* Okay now try the primary key unless we have want an exact + /* Okay now try the primary key unless we want an exact * key ID match on a subkey */ - if ( !latest_key && !(ctx->exact && foundk != keyblock) ) { + if ((!latest_key && !(ctx->exact && foundk != keyblock)) || req_cert) { PKT_public_key *pk; - if (DBG_CACHE && !foundk ) + if (DBG_CACHE && !foundk && !req_cert ) log_debug( "\tno suitable subkeys found - trying primary\n"); pk = keyblock->pkt->pkt.public_key; if ( !pk->is_valid ) { diff --git a/g10/keyedit.c b/g10/keyedit.c index 770b2cdfb..ed4c0c279 100644 --- a/g10/keyedit.c +++ b/g10/keyedit.c @@ -253,8 +253,14 @@ sign_uids( KBNODE keyblock, STRLIST locusr, int *ret_modified, int local ) int select_all = !count_selected_uids(keyblock); int upd_trust = 0; - /* build a list of all signators */ - rc=build_sk_list( locusr, &sk_list, 0, 1 ); + /* build a list of all signators. + * + * We use the CERT flag to request the primary which must always + * be one which is capable of signing keys. I can't see a reason + * why to sign keys using a subkey. Implementation of SUAGE_CERT + * is just a hack in getkey.c and does not mean that a subkey + * marked as certification capable will be used */ + rc=build_sk_list( locusr, &sk_list, 0, PUBKEY_USAGE_SIG|PUBKEY_USAGE_CERT); if( rc ) goto leave; diff --git a/g10/keylist.c b/g10/keylist.c index 35ce75842..dc79a7afd 100644 --- a/g10/keylist.c +++ b/g10/keylist.c @@ -121,6 +121,15 @@ list_one( STRLIST names, int secret ) KBNODE keyblock = NULL; GETKEY_CTX ctx; + /* fixme: using the bynames function has the disadvantage that we + * don't knowether one of the names given was not found. OTOH, + * this function has the advantage to list the names in the + * sequence as defined by the keyDB and does not duplicate + * outputs. A solution could be do test whether all given have + * been listed (this needs a way to use the keyDB search + * functions) or to have the search function return indicators for + * found names. Yet another way is to use the keydb search + * facilities directly. */ if( secret ) { rc = get_seckey_bynames( &ctx, NULL, names, &keyblock ); if( rc ) { diff --git a/g10/keyring.c b/g10/keyring.c index 1ca36ad7c..fae6e11ae 100644 --- a/g10/keyring.c +++ b/g10/keyring.c @@ -102,6 +102,7 @@ new_offset_item (void) return k; } +#if 0 static void release_offset_items (struct off_item *k) { @@ -113,7 +114,7 @@ release_offset_items (struct off_item *k) m_free (k); } } - +#endif static OffsetHashTable new_offset_hash_table (void) diff --git a/g10/skclist.c b/g10/skclist.c index c40bff91d..d895b3eff 100644 --- a/g10/skclist.c +++ b/g10/skclist.c @@ -82,8 +82,8 @@ is_duplicated_entry (STRLIST list, STRLIST item) int -build_sk_list( STRLIST locusr, SK_LIST *ret_sk_list, int unlock, - unsigned use ) +build_sk_list( STRLIST locusr, SK_LIST *ret_sk_list, + int unlock, unsigned int use ) { SK_LIST sk_list = NULL; int rc; diff --git a/g10/trustdb.c b/g10/trustdb.c index 9714bf938..9c29d1af7 100644 --- a/g10/trustdb.c +++ b/g10/trustdb.c @@ -452,12 +452,33 @@ trust_letter (unsigned int value) /**************** - * Recreate the WoT but do not ask for new ownertrusts + * Recreate the WoT but do not ask for new ownertrusts. Special + * feature: In batch mode and without a forced yes, this is only done + * when a check is due. This can be used to run the check from a crontab */ void -check_trustdb() +check_trustdb () { init_trustdb(); + if (opt.batch && !opt.answer_yes) + { + ulong scheduled; + + scheduled = tdbio_read_nextcheck (); + if (!scheduled) + { + log_info (_("no need for a trustdb check\n")); + return; + } + + if (scheduled > make_timestamp ()) + { + log_info (_("next trustdb check due at %s\n"), + strtimestamp (scheduled)); + return; + } + } + validate_keys (0); } @@ -865,116 +886,6 @@ mark_keyblock_seen (KeyHashTable tbl, KBNODE node) } -static int -search_skipfnc (void *opaque, u32 *kid) -{ - return test_key_hash_table ((KeyHashTable)opaque, kid); -} - -/* - * Scan all keys and return a key_array of all keys which are - * indicated as found by the supplied CMPFNC. The caller has to pass - * a keydb handle so that we don't use to create our own. Returns - * either a key_array or NULL in case of an error. No results found - * are indicated by an empty array. Caller hast to release the - * returned array. - */ -static struct key_array * -make_key_array (KEYDB_HANDLE hd, KeyHashTable visited, - int (*cmpfnc)(KBNODE kb, void *opaque), void *cmpval) -{ - KBNODE keyblock = NULL; - struct key_array *keys = NULL; - size_t nkeys, maxkeys; - int rc; - KEYDB_SEARCH_DESC desc; - - maxkeys = 1000; - keys = m_alloc ((maxkeys+1) * sizeof *keys); - nkeys = 0; - - rc = keydb_search_reset (hd); - if (rc) - { - log_error ("keydb_search_reset failed: %s\n", g10_errstr(rc)); - m_free (keys); - return NULL; - } - - memset (&desc, 0, sizeof desc); - desc.mode = KEYDB_SEARCH_MODE_FIRST; - desc.skipfnc = search_skipfnc; - desc.skipfncvalue = visited; - rc = keydb_search (hd, &desc, 1); - if (rc == -1) - { - keys[nkeys].keyblock = NULL; - return keys; - } - if (rc) - { - log_error ("keydb_search_first failed: %s\n", g10_errstr(rc)); - m_free (keys); - return NULL; - } - - desc.mode = KEYDB_SEARCH_MODE_NEXT; /* change mode */ - do - { - PKT_public_key *pk; - - rc = keydb_get_keyblock (hd, &keyblock); - if (rc) - { - log_error ("keydb_get_keyblock failed: %s\n", g10_errstr(rc)); - m_free (keys); - return NULL; - } - - if ( keyblock->pkt->pkttype != PKT_PUBLIC_KEY) - { - log_debug ("ooops: invalid pkttype %d encountered\n", - keyblock->pkt->pkttype); - dump_kbnode (keyblock); - release_kbnode(keyblock); - continue; - } - - /* prepare the keyblock for further processing */ - merge_keys_and_selfsig (keyblock); - clear_kbnode_flags (keyblock); - pk = keyblock->pkt->pkt.public_key; - if (pk->has_expired || pk->is_revoked) - { - /* it does not make sense to look further at those keys */ - mark_keyblock_seen (visited, keyblock); - } - else if (cmpfnc (keyblock, cmpval)) - { - if (nkeys == maxkeys) { - maxkeys += 1000; - keys = m_realloc (keys, (maxkeys+1) * sizeof *keys); - } - keys[nkeys++].keyblock = keyblock; - /* This key is signed - don't check it again */ - mark_keyblock_seen (visited, keyblock); - } - else - release_kbnode (keyblock); - keyblock = NULL; - } - while ( !(rc = keydb_search (hd, &desc, 1)) ); - if (rc && rc != -1) - { - log_error ("keydb_search_next failed: %s\n", g10_errstr(rc)); - m_free (keys); - return NULL; - } - - keys[nkeys].keyblock = NULL; - return keys; -} - static void dump_key_array (int depth, struct key_array *keys) @@ -1077,7 +988,8 @@ is_in_klist (struct key_item *k, PKT_signature *sig) */ static void mark_usable_uid_certs (KBNODE keyblock, KBNODE uidnode, - u32 *main_kid, struct key_item *klist, u32 curtime) + u32 *main_kid, struct key_item *klist, + u32 curtime, u32 *next_expire) { KBNODE node; PKT_signature *sig = node->pkt->pkt.signature; @@ -1157,12 +1069,16 @@ mark_usable_uid_certs (KBNODE keyblock, KBNODE uidnode, * system falls back to an older certification which has a * different expiration time */ const byte *p; + u32 expire; 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 */ + expire = p? sig->timestamp + buffer_to_u32(p) : 0; + if ( expire < curtime ) + { + signode->flag |= (1<<8); /* yeah, found a good cert */ + if (expire && expire < *next_expire) + *next_expire = expire; + } } } } @@ -1181,9 +1097,8 @@ mark_usable_uid_certs (KBNODE keyblock, KBNODE uidnode, * This function assumes that all kbnode flags are cleared on entry. */ static int -cmp_kid_for_make_key_array (KBNODE kb, void *opaque) +validate_one_keyblock (KBNODE kb, struct key_item *klist, u32 *next_expire) { - struct key_item *klist = opaque; struct key_item *kr; KBNODE node, uidnode=NULL; PKT_public_key *pk = kb->pkt->pkt.public_key; @@ -1209,7 +1124,8 @@ 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); + mark_usable_uid_certs (kb, uidnode, main_kid, klist, + curtime, next_expire); } else if (node->pkt->pkttype == PKT_SIGNATURE && (node->flag & (1<<8)) ) @@ -1245,6 +1161,120 @@ cmp_kid_for_make_key_array (KBNODE kb, void *opaque) } +static int +search_skipfnc (void *opaque, u32 *kid) +{ + return test_key_hash_table ((KeyHashTable)opaque, kid); +} + +/* + * Scan all keys and return a key_array of all suitable keys from + * kllist. The caller has to pass keydb handle so that we don't use + * to create our own. Returns either a key_array or NULL in case of + * an error. No results found are indicated by an empty array. + * Caller hast to release the returned array. + */ +static struct key_array * +validate_key_list (KEYDB_HANDLE hd, KeyHashTable visited, + struct key_item *klist, u32 *next_expire) +{ + KBNODE keyblock = NULL; + struct key_array *keys = NULL; + size_t nkeys, maxkeys; + int rc; + KEYDB_SEARCH_DESC desc; + + maxkeys = 1000; + keys = m_alloc ((maxkeys+1) * sizeof *keys); + nkeys = 0; + + rc = keydb_search_reset (hd); + if (rc) + { + log_error ("keydb_search_reset failed: %s\n", g10_errstr(rc)); + m_free (keys); + return NULL; + } + + memset (&desc, 0, sizeof desc); + desc.mode = KEYDB_SEARCH_MODE_FIRST; + desc.skipfnc = search_skipfnc; + desc.skipfncvalue = visited; + rc = keydb_search (hd, &desc, 1); + if (rc == -1) + { + keys[nkeys].keyblock = NULL; + return keys; + } + if (rc) + { + log_error ("keydb_search_first failed: %s\n", g10_errstr(rc)); + m_free (keys); + return NULL; + } + + desc.mode = KEYDB_SEARCH_MODE_NEXT; /* change mode */ + do + { + PKT_public_key *pk; + + rc = keydb_get_keyblock (hd, &keyblock); + if (rc) + { + log_error ("keydb_get_keyblock failed: %s\n", g10_errstr(rc)); + m_free (keys); + return NULL; + } + + if ( keyblock->pkt->pkttype != PKT_PUBLIC_KEY) + { + log_debug ("ooops: invalid pkttype %d encountered\n", + keyblock->pkt->pkttype); + dump_kbnode (keyblock); + release_kbnode(keyblock); + continue; + } + + /* prepare the keyblock for further processing */ + merge_keys_and_selfsig (keyblock); + clear_kbnode_flags (keyblock); + pk = keyblock->pkt->pkt.public_key; + if (pk->has_expired || pk->is_revoked) + { + /* it does not make sense to look further at those keys */ + mark_keyblock_seen (visited, keyblock); + } + else if (validate_one_keyblock (keyblock, klist, next_expire)) + { + if (pk->expiredate && pk->expiredate < *next_expire) + *next_expire = pk->expiredate; + + if (nkeys == maxkeys) { + maxkeys += 1000; + keys = m_realloc (keys, (maxkeys+1) * sizeof *keys); + } + keys[nkeys++].keyblock = keyblock; + /* this key is signed - don't check it again */ + mark_keyblock_seen (visited, keyblock); + keyblock = NULL; + } + + release_kbnode (keyblock); + keyblock = NULL; + } + while ( !(rc = keydb_search (hd, &desc, 1)) ); + if (rc && rc != -1) + { + log_error ("keydb_search_next failed: %s\n", g10_errstr(rc)); + m_free (keys); + return NULL; + } + + keys[nkeys].keyblock = NULL; + return keys; +} + + /* * Run the key validation procedure. * @@ -1283,6 +1313,7 @@ validate_keys (int interactive) int key_count; int ot_unknown, ot_undefined, ot_never, ot_marginal, ot_full, ot_ultimate; KeyHashTable visited; + u32 next_expire; visited = new_key_hash_table (); /* Fixme: Instead of always building a UTK list, we could just build it @@ -1293,10 +1324,13 @@ validate_keys (int interactive) goto leave; } + next_expire = 0xffffffff; /* set next expire to the year 2106 */ + /* mark all UTKs as visited and set validity to ultimate */ for (k=utk_list; k; k = k->next) { KBNODE keyblock; + PKT_public_key *pk; keyblock = get_pubkeyblock (k->kid); if (!keyblock) @@ -1306,6 +1340,7 @@ validate_keys (int interactive) continue; } mark_keyblock_seen (visited, keyblock); + pk = keyblock->pkt->pkt.public_key; for (node=keyblock; node; node = node->next) { if (node->pkt->pkttype == PKT_USER_ID) @@ -1317,10 +1352,12 @@ validate_keys (int interactive) rmd160_hash_buffer (namehash, uid->photo, uid->photolen); else rmd160_hash_buffer (namehash, uid->name, uid->len ); - update_validity (keyblock->pkt->pkt.public_key, - namehash, 0, TRUST_ULTIMATE); + update_validity (pk, namehash, 0, TRUST_ULTIMATE); } } + if ( pk->expiredate && pk->expiredate < next_expire) + next_expire = pk->expiredate; + release_kbnode (keyblock); do_sync (); } @@ -1355,10 +1392,10 @@ validate_keys (int interactive) } /* Find all keys which are signed by a key in kdlist */ - keys = make_key_array (kdb, visited, cmp_kid_for_make_key_array, klist); + keys = validate_key_list (kdb, visited, klist, &next_expire); if (!keys) { - log_error ("make_key_array failed\n"); + log_error ("validate_key_list failed\n"); rc = G10ERR_GENERAL; goto leave; } @@ -1413,7 +1450,14 @@ validate_keys (int interactive) release_key_hash_table (visited); if (!rc) /* mark trustDB as checked */ { - tdbio_write_nextcheck (0); + if (next_expire == 0xffffffff) + tdbio_write_nextcheck (0); + else + { + tdbio_write_nextcheck (next_expire); + log_info (_("next trustdb check due at %s\n"), + strtimestamp (next_expire)); + } do_sync (); } return rc; |