From 882ab7fef9bf4440900c32d7463469307224f11a Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Mon, 12 Aug 2024 14:50:08 +0200 Subject: [PATCH] gpg: Improve decryption diagnostic for an ADSK key. * g10/keydb.h (GET_PUBKEYBLOCK_FLAG_ADSK): New constant. * g10/packet.h (PUBKEY_USAGE_XENC_MASK): New constant. * g10/pubkey-enc.c (get_session_key): Consider an ADSK also as "marked for encryption use". (get_it): Print a note if an ADSK key was used. Use the new get_pubkeyblock flag. * g10/getkey.c (struct getkey_ctx_s): Add field allow_adsk. (get_pubkeyblock): Factor all code out to ... (get_pubkeyblock_ext): new. (finish_lookup): Add new arg allow_adsk and make use of it. -- This patch solves two purposes: - We write a note that the ADSK key was used for decryption - We avoid running into a "oops: public key not found for preference check\n" due to ADSK keys. The error is mostly harmless but lets gpg return with an exit code of 2. --- doc/gpg.texi | 2 +- g10/getkey.c | 32 ++++++++++++++++++++++++-------- g10/keydb.h | 2 ++ g10/packet.h | 4 ++++ g10/pubkey-enc.c | 15 +++++++++++---- 5 files changed, 42 insertions(+), 13 deletions(-) diff --git a/doc/gpg.texi b/doc/gpg.texi index 501e075d2..ae1603924 100644 --- a/doc/gpg.texi +++ b/doc/gpg.texi @@ -4076,7 +4076,7 @@ current home directory (@pxref{option --homedir}). startup. It may contain options pertaining to all components of GnuPG. Its current main use is for the "use-keyboxd" option. If the default home directory @file{~/.gnupg} does not exist, GnuPG creates - this directory and a @file{common.conf} file with "use_keyboxd". + this directory and a @file{common.conf} file with "use-keyboxd". @end table diff --git a/g10/getkey.c b/g10/getkey.c index 1fb9458a5..f91ec34eb 100644 --- a/g10/getkey.c +++ b/g10/getkey.c @@ -68,6 +68,9 @@ struct getkey_ctx_s details. */ int exact; + /* Allow returning an ADSK key. */ + int allow_adsk; + /* Part of the search criteria: Whether the caller only wants keys with an available secret key. This is used by getkey_next to get the next result with the same initial criteria. */ @@ -141,7 +144,8 @@ static int lookup (ctrl_t ctrl, getkey_ctx_t ctx, int want_secret, kbnode_t *ret_keyblock, kbnode_t *ret_found_key); static kbnode_t finish_lookup (kbnode_t keyblock, unsigned int req_usage, int want_exact, - int want_secret, unsigned int *r_flags); + int want_secret, int allow_adsk, + unsigned int *r_flags); static void print_status_key_considered (kbnode_t keyblock, unsigned int flags); @@ -586,7 +590,7 @@ get_pubkeyblock_for_sig (ctrl_t ctrl, PKT_signature *sig) * The self-signed data has already been merged into the public key * using merge_selfsigs. */ kbnode_t -get_pubkeyblock (ctrl_t ctrl, u32 * keyid) +get_pubkeyblock_ext (ctrl_t ctrl, u32 * keyid, unsigned int flags) { struct getkey_ctx_s ctx; int rc = 0; @@ -602,6 +606,7 @@ get_pubkeyblock (ctrl_t ctrl, u32 * keyid) ctx.items[0].mode = KEYDB_SEARCH_MODE_LONG_KID; ctx.items[0].u.kid[0] = keyid[0]; ctx.items[0].u.kid[1] = keyid[1]; + ctx.allow_adsk = !!(flags & GET_PUBKEYBLOCK_FLAG_ADSK); rc = lookup (ctrl, &ctx, 0, &keyblock, NULL); getkey_end (ctrl, &ctx); @@ -609,6 +614,12 @@ get_pubkeyblock (ctrl_t ctrl, u32 * keyid) } +kbnode_t +get_pubkeyblock (ctrl_t ctrl, u32 * keyid) +{ + return get_pubkeyblock_ext (ctrl, keyid, 0); +} + /* Return the public key with the key id KEYID iff the secret key is * available and store it at PK. The resources should be released * using release_public_key_parts(). @@ -1770,7 +1781,7 @@ get_pubkey_fromfile (ctrl_t ctrl, PKT_public_key *pk, const char *fname, /* Warning: node flag bits 0 and 1 should be preserved by * merge_selfsigs. FIXME: Check whether this still holds. */ merge_selfsigs (ctrl, keyblock); - found_key = finish_lookup (keyblock, pk->req_usage, 0, 0, &infoflags); + found_key = finish_lookup (keyblock, pk->req_usage, 0, 0, 0, &infoflags); print_status_key_considered (keyblock, infoflags); if (found_key) pk_from_block (pk, keyblock, found_key); @@ -3652,7 +3663,7 @@ merge_selfsigs (ctrl_t ctrl, kbnode_t keyblock) */ static kbnode_t finish_lookup (kbnode_t keyblock, unsigned int req_usage, int want_exact, - int want_secret, unsigned int *r_flags) + int want_secret, int allow_adsk, unsigned int *r_flags) { kbnode_t k; @@ -3673,6 +3684,9 @@ finish_lookup (kbnode_t keyblock, unsigned int req_usage, int want_exact, #define USAGE_MASK (PUBKEY_USAGE_SIG|PUBKEY_USAGE_ENC|PUBKEY_USAGE_CERT) req_usage &= USAGE_MASK; + /* In allow ADSK mode make sure both encryption bis are set. */ + if (allow_adsk && (req_usage & PUBKEY_USAGE_XENC_MASK)) + req_usage |= PUBKEY_USAGE_XENC_MASK; /* Request the primary if we're certifying another key, and also if * signing data while --pgp7 is on since pgp 7 do @@ -3700,7 +3714,8 @@ finish_lookup (kbnode_t keyblock, unsigned int req_usage, int want_exact, pk->flags.exact = 1; break; } - else if ((k->pkt->pkt.public_key->pubkey_usage == PUBKEY_USAGE_RENC)) + else if (!allow_adsk && (k->pkt->pkt.public_key->pubkey_usage + == PUBKEY_USAGE_RENC)) { if (DBG_LOOKUP) log_debug ("finish_lookup: found via ADSK - not selected\n"); @@ -3806,7 +3821,7 @@ finish_lookup (kbnode_t keyblock, unsigned int req_usage, int want_exact, } if (opt.flags.require_pqc_encryption - && (req_usage & PUBKEY_USAGE_ENC) + && (req_usage & PUBKEY_USAGE_XENC_MASK) && pk->pubkey_algo != PUBKEY_ALGO_KYBER) { if (DBG_LOOKUP) @@ -3894,7 +3909,7 @@ finish_lookup (kbnode_t keyblock, unsigned int req_usage, int want_exact, log_debug ("\tprimary key has expired\n"); } else if (opt.flags.require_pqc_encryption - && (req_usage & PUBKEY_USAGE_ENC) + && (req_usage & PUBKEY_USAGE_XENC_MASK) && pk->pubkey_algo != PUBKEY_ALGO_KYBER) { if (DBG_LOOKUP) @@ -4037,7 +4052,8 @@ lookup (ctrl_t ctrl, getkey_ctx_t ctx, int want_secret, * merge_selfsigs. */ merge_selfsigs (ctrl, keyblock); found_key = finish_lookup (keyblock, ctx->req_usage, ctx->exact, - want_secret, &infoflags); + want_secret, ctx->allow_adsk, + &infoflags); print_status_key_considered (keyblock, infoflags); if (found_key) { diff --git a/g10/keydb.h b/g10/keydb.h index d96debeb7..2cdc8f2e5 100644 --- a/g10/keydb.h +++ b/g10/keydb.h @@ -351,6 +351,8 @@ int get_pubkey_fast (ctrl_t ctrl, PKT_public_key *pk, u32 *keyid); kbnode_t get_pubkeyblock_for_sig (ctrl_t ctrl, PKT_signature *sig); /* Return the key block for the key with KEYID. */ +#define GET_PUBKEYBLOCK_FLAG_ADSK 1 /* Allow returning ADSK key. */ +kbnode_t get_pubkeyblock_ext (ctrl_t ctrl, u32 *keyid, unsigned int flags); kbnode_t get_pubkeyblock (ctrl_t ctrl, u32 *keyid); /* A list used by get_pubkeys to gather all of the matches. */ diff --git a/g10/packet.h b/g10/packet.h index b16b775a2..6c3e1b80d 100644 --- a/g10/packet.h +++ b/g10/packet.h @@ -60,10 +60,14 @@ #define PUBKEY_USAGE_RENC 1024 /* Restricted encryption. */ #define PUBKEY_USAGE_TIME 2048 /* Timestamp use. */ + /* The usage bits which can be derived from the algo. */ #define PUBKEY_USAGE_BASIC_MASK (PUBKEY_USAGE_SIG|PUBKEY_USAGE_ENC\ |PUBKEY_USAGE_CERT|PUBKEY_USAGE_AUTH) +/* The usage bits which define encryption. */ +#define PUBKEY_USAGE_XENC_MASK (PUBKEY_USAGE_ENC | PUBKEY_USAGE_RENC) + /* Bitflags to convey hints on what kind of signature is created. */ #define SIGNHINT_KEYSIG 1 #define SIGNHINT_SELFSIG 2 diff --git a/g10/pubkey-enc.c b/g10/pubkey-enc.c index 563077803..dced3dfb0 100644 --- a/g10/pubkey-enc.c +++ b/g10/pubkey-enc.c @@ -143,7 +143,7 @@ get_session_key (ctrl_t ctrl, struct pubkey_enc_list *list, DEK *dek) else if (opt.try_all_secrets || (k->keyid[0] == keyid[0] && k->keyid[1] == keyid[1])) { - if (!opt.quiet && !(sk->pubkey_usage & PUBKEY_USAGE_ENC)) + if (!opt.quiet && !(sk->pubkey_usage & PUBKEY_USAGE_XENC_MASK)) log_info (_("used key is not marked for encryption use.\n")); } else @@ -156,7 +156,7 @@ get_session_key (ctrl_t ctrl, struct pubkey_enc_list *list, DEK *dek) if (!opt.quiet && !k->keyid[0] && !k->keyid[1]) { log_info (_("okay, we are the anonymous recipient.\n")); - if (!(sk->pubkey_usage & PUBKEY_USAGE_ENC)) + if (!(sk->pubkey_usage & PUBKEY_USAGE_XENC_MASK)) log_info (_("used key is not marked for encryption use.\n") ); } @@ -443,7 +443,7 @@ get_it (ctrl_t ctrl, { PKT_public_key *pk = NULL; PKT_public_key *mainpk = NULL; - KBNODE pkb = get_pubkeyblock (ctrl, keyid); + KBNODE pkb = get_pubkeyblock_ext (ctrl, keyid, GET_PUBKEYBLOCK_FLAG_ADSK); if (!pkb) { @@ -495,6 +495,13 @@ get_it (ctrl_t ctrl, } } + if (pk && !(pk->pubkey_usage & PUBKEY_USAGE_ENC) + && (pk->pubkey_usage & PUBKEY_USAGE_RENC)) + { + log_info (_("Note: ADSK key has been used for decryption")); + log_printf ("\n"); + } + if (pk && pk->flags.revoked) { log_info (_("Note: key has been revoked")); @@ -512,7 +519,7 @@ get_it (ctrl_t ctrl, /* Note that we do not want to create a trustdb just for * getting the ownertrust: If there is no trustdb there can't - * be ulitmately trusted key anyway and thus the ownertrust + * be an ultimately trusted key anyway and thus the ownertrust * value is irrelevant. */ write_status_printf (STATUS_DECRYPTION_KEY, "%s %s %c", pkhex, mainpkhex,