[Pkg-gnupg-commit] [gnupg2] 07/102: gpg: Emit new status line KEY_CONSIDERED.
Daniel Kahn Gillmor
dkg at fifthhorseman.net
Fri Jun 17 00:14:49 UTC 2016
This is an automated email from the git hooks/post-receive script.
dkg pushed a commit to branch experimental
in repository gnupg2.
commit ff71521d9698c7c5df94831a1398e948213af433
Author: Werner Koch <wk at gnupg.org>
Date: Fri May 13 16:24:59 2016 +0200
gpg: Emit new status line KEY_CONSIDERED.
* common/status.h (STATUS_KEY_CONSIDERED): New.
* g10/getkey.c: Include status.h.
(LOOKUP_NOT_SELECTED, LOOKUP_ALL_SUBKEYS_EXPIRED): New.
(finish_lookup): Add arg R_FLAGS. Count expired and revoked keys and
set flag. Check a requested usage before checking for expiraion or
revocation.
(print_status_key_considered): New.
(lookup): Print new status.
Signed-off-by: Werner Koch <wk at gnupg.org>
---
common/status.h | 1 +
doc/DETAILS | 13 +++-
g10/getkey.c | 220 +++++++++++++++++++++++++++++++++++---------------------
3 files changed, 151 insertions(+), 83 deletions(-)
diff --git a/common/status.h b/common/status.h
index 730a75c..966489f 100644
--- a/common/status.h
+++ b/common/status.h
@@ -105,6 +105,7 @@ enum
STATUS_INV_SGNR,
STATUS_NO_RECP,
STATUS_NO_SGNR,
+ STATUS_KEY_CONSIDERED,
STATUS_ALREADY_SIGNED,
STATUS_KEYEXPIRED,
diff --git a/doc/DETAILS b/doc/DETAILS
index 5ceab68..2710007 100644
--- a/doc/DETAILS
+++ b/doc/DETAILS
@@ -548,7 +548,7 @@ pkd:0:1024:B665B1435F4C2 .... FF26ABB:
that case, this status tag does not appear.
*** ATTRIBUTE <arguments>
- The list or argemnts are:
+ The list or arguments are:
- <fpr>
- <octets>
- <type>
@@ -602,18 +602,29 @@ pkd:0:1024:B665B1435F4C2 .... FF26ABB:
- 13 :: Key disabled
- 14 :: Syntax error in specification
+ If no specific reason was given a previously emitted status code
+ KEY_CONSIDERED may be used to analyzed the problem.
+
Note that for historical reasons the INV_RECP status is also used
for gpgsm's SIGNER command where it relates to signer's of course.
Newer GnuPG versions are using INV_SGNR; applications should
ignore the INV_RECP during the sender's command processing once
they have seen an INV_SGNR. Different codes are used so that they
can be distinguish while doing an encrypt+sign operation.
+
*** NO_RECP <reserved>
Issued if no recipients are usable.
*** NO_SGNR <reserved>
Issued if no senders are usable.
+*** KEY_CONSIDERED <fpr> <flags>
+ Issued to explian the lookup of a key. FPR is the hexified
+ fingerprint of the primary key. The bit values for FLAGS are:
+
+ - 1 :: The key has not been selected.
+ - 2 :: All subkeys of the key are expired or have been revoked.
+
*** KEYEXPIRED <expire-timestamp>
The key has expired. expire-timestamp is the expiration time in
seconds since Epoch. This status line is not very useful because
diff --git a/g10/getkey.c b/g10/getkey.c
index 907007b..ad0148e 100644
--- a/g10/getkey.c
+++ b/g10/getkey.c
@@ -38,6 +38,7 @@
#include "call-agent.h"
#include "host2net.h"
#include "mbox-util.h"
+#include "status.h"
#define MAX_PK_CACHE_ENTRIES PK_UID_CACHE_SIZE
#define MAX_UID_CACHE_ENTRIES PK_UID_CACHE_SIZE
@@ -46,6 +47,13 @@
#error We need the cache for key creation
#endif
+/* Flags values returned by the lookup code. Note that the values are
+ * directly used by the KEY_CONSIDERED status line. */
+#define LOOKUP_NOT_SELECTED (1<<0)
+#define LOOKUP_ALL_SUBKEYS_EXPIRED (1<<1) /* or revoked */
+
+
+/* A context object used by the lookup functions. */
struct getkey_ctx_s
{
/* Part of the search criteria: whether the search is an exact
@@ -3045,51 +3053,54 @@ merge_selfsigs (KBNODE keyblock)
/* See whether the key satisfies any additional requirements specified
- in CTX. If so, return 1 and set CTX->FOUND_KEY to an appropriate
- key or subkey. Otherwise, return 0 if there was no appropriate
- key.
-
- In case the primary key is not required, select a suitable subkey.
- We need the primary key if PUBKEY_USAGE_CERT is set in
- CTX->REQ_USAGE or we are in PGP6 or PGP7 mode and PUBKEY_USAGE_SIG
- is set in CTX->REQ_USAGE.
-
- If any of PUBKEY_USAGE_SIG, PUBKEY_USAGE_ENC and PUBKEY_USAGE_CERT
- are set in CTX->REQ_USAGE, we filter by the key's function.
- Concretely, if PUBKEY_USAGE_SIG and PUBKEY_USAGE_CERT are set, then
- we only return a key if it is (at least) either a signing or a
- certification key.
-
- If CTX->REQ_USAGE is set, then we reject any keys that are not good
- (i.e., valid, not revoked, not expired, etc.). This allows the
- getkey functions to be used for plain key listings.
-
- Sets the matched key's user id field (pk->user_id) to the user id
- that matched the low-level search criteria or NULL.
-
-
- This function needs to handle several different cases:
-
- 1. No requested usage and no primary key requested
- Examples for this case are that we have a keyID to be used
- for decrytion or verification.
- 2. No usage but primary key requested
- This is the case for all functions which work on an
- entire keyblock, e.g. for editing or listing
- 3. Usage and primary key requested
- FXME
- 4. Usage but no primary key requested
- FIXME
-
+ * in CTX. If so, return 1 and set CTX->FOUND_KEY to an appropriate
+ * key or subkey. Otherwise, return 0 if there was no appropriate
+ * key.
+ *
+ * In case the primary key is not required, select a suitable subkey.
+ * We need the primary key if PUBKEY_USAGE_CERT is set in
+ * CTX->REQ_USAGE or we are in PGP6 or PGP7 mode and PUBKEY_USAGE_SIG
+ * is set in CTX->REQ_USAGE.
+ *
+ * If any of PUBKEY_USAGE_SIG, PUBKEY_USAGE_ENC and PUBKEY_USAGE_CERT
+ * are set in CTX->REQ_USAGE, we filter by the key's function.
+ * Concretely, if PUBKEY_USAGE_SIG and PUBKEY_USAGE_CERT are set, then
+ * we only return a key if it is (at least) either a signing or a
+ * certification key.
+ *
+ * If CTX->REQ_USAGE is set, then we reject any keys that are not good
+ * (i.e., valid, not revoked, not expired, etc.). This allows the
+ * getkey functions to be used for plain key listings.
+ *
+ * Sets the matched key's user id field (pk->user_id) to the user id
+ * that matched the low-level search criteria or NULL. If R_FLAGS is
+ * not NULL set certain flags for more detailed error reporting. Used
+ * flags are:
+ * - LOOKUP_ALL_SUBKEYS_EXPIRED :: All Subkeys are expired or have
+ * been revoked.
+ *
+ * This function needs to handle several different cases:
+ *
+ * 1. No requested usage and no primary key requested
+ * Examples for this case are that we have a keyID to be used
+ * for decrytion or verification.
+ * 2. No usage but primary key requested
+ * This is the case for all functions which work on an
+ * entire keyblock, e.g. for editing or listing
+ * 3. Usage and primary key requested
+ * FIXME
+ * 4. Usage but no primary key requested
+ * FIXME
+ *
*/
-static KBNODE
-finish_lookup (GETKEY_CTX ctx, KBNODE keyblock)
+static kbnode_t
+finish_lookup (getkey_ctx_t ctx, kbnode_t keyblock, unsigned int *r_flags)
{
- KBNODE k;
+ kbnode_t k;
/* If CTX->EXACT is set, the key or subkey that actually matched the
low-level search criteria. */
- KBNODE foundk = NULL;
+ kbnode_t foundk = NULL;
/* The user id (if any) that matched the low-level search criteria. */
PKT_user_id *foundu = NULL;
@@ -3100,21 +3111,23 @@ finish_lookup (GETKEY_CTX ctx, KBNODE keyblock)
if signing data while --pgp6 or --pgp7 is on since pgp 6 and 7
do not understand signatures made by a signing subkey. PGP 8
does. */
- int req_prim = (ctx->req_usage & PUBKEY_USAGE_CERT) ||
- ((PGP6 || PGP7) && (ctx->req_usage & PUBKEY_USAGE_SIG));
+ int req_prim = ((ctx->req_usage & PUBKEY_USAGE_CERT)
+ || ((PGP6 || PGP7) && (ctx->req_usage & PUBKEY_USAGE_SIG)));
u32 curtime = make_timestamp ();
u32 latest_date;
- KBNODE latest_key;
+ kbnode_t latest_key;
PKT_public_key *pk;
-
log_assert (keyblock->pkt->pkttype == PKT_PUBLIC_KEY);
+ if (r_flags)
+ *r_flags = 0;
+
+ /* For an exact match mark the primary or subkey that matched the
+ low-level search criteria. */
if (ctx->exact)
- /* Get the key or subkey that matched the low-level search
- criteria. */
{
for (k = keyblock; k; k = k->next)
{
@@ -3154,24 +3167,28 @@ finish_lookup (GETKEY_CTX ctx, KBNODE keyblock)
latest_date = 0;
latest_key = NULL;
- /* Set latest_key to the latest (the one with the most recent
- timestamp) good (valid, not revoked, not expired, etc.) subkey.
-
- Don't bother if we are only looking for a primary key or we need
- an exact match and the exact match is not a subkey. */
+ /* Set LATEST_KEY to the latest (the one with the most recent
+ * timestamp) good (valid, not revoked, not expired, etc.) subkey.
+ *
+ * Don't bother if we are only looking for a primary key or we need
+ * an exact match and the exact match is not a subkey. */
if (req_prim || (foundk && foundk->pkt->pkttype != PKT_PUBLIC_SUBKEY))
;
else
{
- KBNODE nextk;
+ kbnode_t nextk;
+ int n_subkeys = 0;
+ int n_revoked_or_expired = 0;
/* Either start a loop or check just this one subkey. */
for (k = foundk ? foundk : keyblock; k; k = nextk)
{
if (foundk)
- /* If FOUNDK is not NULL, then only consider that exact
- key, i.e., don't iterate. */
- nextk = NULL;
+ {
+ /* If FOUNDK is not NULL, then only consider that exact
+ key, i.e., don't iterate. */
+ nextk = NULL;
+ }
else
nextk = k->next;
@@ -3182,24 +3199,35 @@ finish_lookup (GETKEY_CTX ctx, KBNODE keyblock)
if (DBG_LOOKUP)
log_debug ("\tchecking subkey %08lX\n",
(ulong) keyid_from_pk (pk, NULL));
+
if (!pk->flags.valid)
{
if (DBG_LOOKUP)
log_debug ("\tsubkey not valid\n");
continue;
}
+ if (!((pk->pubkey_usage & USAGE_MASK) & req_usage))
+ {
+ if (DBG_LOOKUP)
+ log_debug ("\tusage does not match: want=%x have=%x\n",
+ req_usage, pk->pubkey_usage);
+ continue;
+ }
+
+ n_subkeys++;
if (pk->flags.revoked)
{
if (DBG_LOOKUP)
log_debug ("\tsubkey has been revoked\n");
+ n_revoked_or_expired++;
continue;
}
if (pk->has_expired)
{
if (DBG_LOOKUP)
log_debug ("\tsubkey has expired\n");
+ n_revoked_or_expired++;
continue;
-
}
if (pk->timestamp > curtime && !opt.ignore_valid_from)
{
@@ -3208,14 +3236,6 @@ finish_lookup (GETKEY_CTX ctx, KBNODE keyblock)
continue;
}
- if (!((pk->pubkey_usage & USAGE_MASK) & req_usage))
- {
- if (DBG_LOOKUP)
- log_debug ("\tusage does not match: want=%x have=%x\n",
- req_usage, pk->pubkey_usage);
- continue;
- }
-
if (DBG_LOOKUP)
log_debug ("\tsubkey might be fine\n");
/* In case a key has a timestamp of 0 set, we make sure
@@ -3228,18 +3248,20 @@ finish_lookup (GETKEY_CTX ctx, KBNODE keyblock)
latest_key = k;
}
}
+ if (n_subkeys == n_revoked_or_expired && r_flags)
+ *r_flags |= LOOKUP_ALL_SUBKEYS_EXPIRED;
}
/* Check if the primary key is ok (valid, not revoke, not expire,
- matches requested usage) if:
-
- - we didn't find an appropriate subkey and we're not doing an
- exact search,
-
- - we're doing an exact match and the exact match was the
- primary key, or,
-
- - we're just considering the primary key. */
+ * matches requested usage) if:
+ *
+ * - we didn't find an appropriate subkey and we're not doing an
+ * exact search,
+ *
+ * - we're doing an exact match and the exact match was the
+ * primary key, or,
+ *
+ * - we're just considering the primary key. */
if ((!latest_key && !ctx->exact) || foundk == keyblock || req_prim)
{
if (DBG_LOOKUP && !foundk && !req_prim)
@@ -3250,6 +3272,12 @@ finish_lookup (GETKEY_CTX ctx, KBNODE keyblock)
if (DBG_LOOKUP)
log_debug ("\tprimary key not valid\n");
}
+ else if (!((pk->pubkey_usage & USAGE_MASK) & req_usage))
+ {
+ if (DBG_LOOKUP)
+ log_debug ("\tprimary key usage does not match: "
+ "want=%x have=%x\n", req_usage, pk->pubkey_usage);
+ }
else if (pk->flags.revoked)
{
if (DBG_LOOKUP)
@@ -3260,12 +3288,6 @@ finish_lookup (GETKEY_CTX ctx, KBNODE keyblock)
if (DBG_LOOKUP)
log_debug ("\tprimary key has expired\n");
}
- else if (!((pk->pubkey_usage & USAGE_MASK) & req_usage))
- {
- if (DBG_LOOKUP)
- log_debug ("\tprimary key usage does not match: "
- "want=%x have=%x\n", req_usage, pk->pubkey_usage);
- }
else /* Okay. */
{
if (DBG_LOOKUP)
@@ -3309,6 +3331,34 @@ found:
}
+/* Print a KEY_CONSIDERED status line. */
+static void
+print_status_key_considered (kbnode_t keyblock, unsigned int flags)
+{
+ char hexfpr[2*MAX_FINGERPRINT_LEN + 1];
+ kbnode_t node;
+ char flagbuf[20];
+
+ if (!is_status_enabled ())
+ return;
+
+ for (node=keyblock; node; node = node->next)
+ if (node->pkt->pkttype == PKT_PUBLIC_KEY
+ || node->pkt->pkttype == PKT_SECRET_KEY)
+ break;
+ if (!node)
+ {
+ log_error ("%s: keyblock w/o primary key\n", __func__);
+ return;
+ }
+
+ hexfingerprint (node->pkt->pkt.public_key, hexfpr, sizeof hexfpr);
+ snprintf (flagbuf, sizeof flagbuf, " %u", flags);
+ write_status_strings (STATUS_KEY_CONSIDERED, hexfpr, flagbuf, NULL);
+}
+
+
+
/* A high-level function to lookup keys.
This function builds on top of the low-level keydb API. It first
@@ -3329,6 +3379,7 @@ lookup (getkey_ctx_t ctx, kbnode_t *ret_keyblock, kbnode_t *ret_found_key,
int no_suitable_key = 0;
KBNODE keyblock = NULL;
KBNODE found_key = NULL;
+ unsigned int infoflags;
if (ret_keyblock)
*ret_keyblock = NULL;
@@ -3360,14 +3411,19 @@ lookup (getkey_ctx_t ctx, kbnode_t *ret_keyblock, kbnode_t *ret_found_key,
* merge_selfsigs. For secret keys, premerge transferred the
* keys to the keyblock. */
merge_selfsigs (keyblock);
- found_key = finish_lookup (ctx, keyblock);
+ found_key = finish_lookup (ctx, keyblock, &infoflags);
+ if (!found_key)
+ infoflags |= LOOKUP_NOT_SELECTED;
+ print_status_key_considered (keyblock, infoflags);
if (found_key)
{
no_suitable_key = 0;
goto found;
}
else
- no_suitable_key = 1;
+ {
+ no_suitable_key = 1;
+ }
skip:
/* Release resources and continue search. */
@@ -3381,7 +3437,7 @@ lookup (getkey_ctx_t ctx, kbnode_t *ret_keyblock, kbnode_t *ret_found_key,
keydb_disable_caching (ctx->kr_handle);
}
-found:
+ found:
if (rc && gpg_err_code (rc) != GPG_ERR_NOT_FOUND)
log_error ("keydb_search failed: %s\n", gpg_strerror (rc));
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-gnupg/gnupg2.git
More information about the Pkg-gnupg-commit
mailing list