aboutsummaryrefslogtreecommitdiffstats
path: root/g10
diff options
context:
space:
mode:
Diffstat (limited to 'g10')
-rw-r--r--g10/ChangeLog13
-rw-r--r--g10/getkey.c14
-rw-r--r--g10/keyedit.c10
-rw-r--r--g10/keylist.c9
-rw-r--r--g10/keyring.c3
-rw-r--r--g10/skclist.c4
-rw-r--r--g10/trustdb.c294
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;