diff options
Diffstat (limited to 'g10/getkey.c')
-rw-r--r-- | g10/getkey.c | 108 |
1 files changed, 67 insertions, 41 deletions
diff --git a/g10/getkey.c b/g10/getkey.c index bee5ff356..21f996a5b 100644 --- a/g10/getkey.c +++ b/g10/getkey.c @@ -316,27 +316,50 @@ pk_from_block (PKT_public_key *pk, kbnode_t keyblock, kbnode_t found_key) /* Specialized version of get_pubkey which retrieves the key based on * information in SIG. In contrast to get_pubkey PK is required. IF - * FORCED_PK is not NULL, this public key is used and copied to PK. */ + * FORCED_PK is not NULL, this public key is used and copied to PK. + * If R_KEYBLOCK is not NULL the entire keyblock is stored there if + * found and FORCED_PK is not used; if not used or on error NULL is + * stored there. */ gpg_error_t get_pubkey_for_sig (ctrl_t ctrl, PKT_public_key *pk, PKT_signature *sig, - PKT_public_key *forced_pk) + PKT_public_key *forced_pk, kbnode_t *r_keyblock) { + gpg_error_t err; const byte *fpr; size_t fprlen; + if (r_keyblock) + *r_keyblock = NULL; + if (forced_pk) { copy_public_key (pk, forced_pk); return 0; } + /* Make sure to request only keys cabable of signing. This makes + * sure that a subkey w/o a valid backsig or with bad usage flags + * will be skipped. */ + pk->req_usage = PUBKEY_USAGE_SIG; + /* First try the ISSUER_FPR info. */ fpr = issuer_fpr_raw (sig, &fprlen); - if (fpr && !get_pubkey_byfpr (ctrl, pk, NULL, fpr, fprlen)) + if (fpr && !get_pubkey_byfpr (ctrl, pk, r_keyblock, fpr, fprlen)) return 0; + if (r_keyblock) + { + release_kbnode (*r_keyblock); + *r_keyblock = NULL; + } /* Fallback to use the ISSUER_KEYID. */ - return get_pubkey (ctrl, pk, sig->keyid); + err = get_pubkey_bykid (ctrl, pk, r_keyblock, sig->keyid); + if (err && r_keyblock) + { + release_kbnode (*r_keyblock); + *r_keyblock = NULL; + } + return err; } @@ -354,6 +377,10 @@ get_pubkey_for_sig (ctrl_t ctrl, PKT_public_key *pk, PKT_signature *sig, * usage will be returned. As such, it is essential that * PK->REQ_USAGE be correctly initialized! * + * If R_KEYBLOCK is not NULL, then the first result's keyblock is + * returned in *R_KEYBLOCK. This should be freed using + * release_kbnode(). + * * Returns 0 on success, GPG_ERR_NO_PUBKEY if there is no public key * with the specified key id, or another error code if an error * occurs. @@ -361,24 +388,30 @@ get_pubkey_for_sig (ctrl_t ctrl, PKT_public_key *pk, PKT_signature *sig, * If the data was not read from the cache, then the self-signed data * has definitely been merged into the public key using * merge_selfsigs. */ -int -get_pubkey (ctrl_t ctrl, PKT_public_key * pk, u32 * keyid) +gpg_error_t +get_pubkey_bykid (ctrl_t ctrl, PKT_public_key *pk, kbnode_t *r_keyblock, + u32 *keyid) { int internal = 0; - int rc = 0; + gpg_error_t rc = 0; + + if (r_keyblock) + *r_keyblock = NULL; #if MAX_PK_CACHE_ENTRIES - if (pk) + if (pk && !r_keyblock) { /* Try to get it from the cache. We don't do this when pk is - NULL as it does not guarantee that the user IDs are - cached. */ + * NULL as it does not guarantee that the user IDs are cached. + * The old get_pubkey_function did not check PK->REQ_USAGE when + * reading form the caceh. This is probably a bug. Note that + * the cache is not used when the caller asked to return the + * entire keyblock. This is because the cache does not + * associate the public key wit its primary key. */ pk_cache_entry_t ce; for (ce = pk_cache; ce; ce = ce->next) { if (ce->keyid[0] == keyid[0] && ce->keyid[1] == keyid[1]) - /* XXX: We don't check PK->REQ_USAGE here, but if we don't - read from the cache, we do check it! */ { copy_public_key (pk, ce->pk); return 0; @@ -386,6 +419,7 @@ get_pubkey (ctrl_t ctrl, PKT_public_key * pk, u32 * keyid) } } #endif + /* More init stuff. */ if (!pk) { @@ -431,16 +465,18 @@ get_pubkey (ctrl_t ctrl, PKT_public_key * pk, u32 * keyid) ctx.req_usage = pk->req_usage; rc = lookup (ctrl, &ctx, 0, &kb, &found_key); if (!rc) + pk_from_block (pk, kb, found_key); + getkey_end (ctrl, &ctx); + if (!rc && r_keyblock) { - pk_from_block (pk, kb, found_key); + *r_keyblock = kb; + kb = NULL; } - getkey_end (ctrl, &ctx); release_kbnode (kb); } - if (!rc) - goto leave; - rc = GPG_ERR_NO_PUBKEY; + if (rc) /* Return a more useful error code. */ + rc = gpg_error (GPG_ERR_NO_PUBKEY); leave: if (!rc) @@ -451,6 +487,14 @@ leave: } +/* Wrapper for get_pubkey_bykid w/o keyblock return feature. */ +int +get_pubkey (ctrl_t ctrl, PKT_public_key *pk, u32 *keyid) +{ + return get_pubkey_bykid (ctrl, pk, NULL, keyid); +} + + /* Same as get_pubkey but if the key was not found the function tries * to import it from LDAP. FIXME: We should not need this but switch * to a fingerprint lookup. */ @@ -563,28 +607,6 @@ get_pubkey_fast (ctrl_t ctrl, PKT_public_key * pk, u32 * keyid) } -/* Return the entire keyblock used to create SIG. This is a - * specialized version of get_pubkeyblock. - * - * FIXME: This is a hack because get_pubkey_for_sig was already called - * and it could have used a cache to hold the key. */ -kbnode_t -get_pubkeyblock_for_sig (ctrl_t ctrl, PKT_signature *sig) -{ - const byte *fpr; - size_t fprlen; - kbnode_t keyblock; - - /* First try the ISSUER_FPR info. */ - fpr = issuer_fpr_raw (sig, &fprlen); - if (fpr && !get_pubkey_byfpr (ctrl, NULL, &keyblock, fpr, fprlen)) - return keyblock; - - /* Fallback to use the ISSUER_KEYID. */ - return get_pubkeyblock (ctrl, sig->keyid); -} - - /* Return the key block for the key with key id KEYID or NULL, if an * error occurs. Use release_kbnode() to release the key block. * @@ -3700,6 +3722,7 @@ finish_lookup (kbnode_t keyblock, unsigned int req_usage, int want_exact, kbnode_t latest_key; PKT_public_key *pk; int req_prim; + int diag_exactfound = 0; u32 curtime = make_timestamp (); if (r_flags) @@ -3730,11 +3753,10 @@ finish_lookup (kbnode_t keyblock, unsigned int req_usage, int want_exact, { if (want_exact) { - if (DBG_LOOKUP) - log_debug ("finish_lookup: exact search requested and found\n"); foundk = k; pk = k->pkt->pkt.public_key; pk->flags.exact = 1; + diag_exactfound = 1; break; } else if (!allow_adsk && (k->pkt->pkt.public_key->pubkey_usage @@ -3764,10 +3786,14 @@ finish_lookup (kbnode_t keyblock, unsigned int req_usage, int want_exact, log_debug ("finish_lookup: checking key %08lX (%s)(req_usage=%x)\n", (ulong) keyid_from_pk (keyblock->pkt->pkt.public_key, NULL), foundk ? "one" : "all", req_usage); + if (diag_exactfound && DBG_LOOKUP) + log_debug ("\texact search requested and found\n"); if (!req_usage) { latest_key = foundk ? foundk : keyblock; + if (DBG_LOOKUP) + log_debug ("\tno usage requested - accepting key\n"); goto found; } |