File gnupg-CVE-2025-30258-Lookup-key-for-merging-inserting-only-by-primary-key.patch of Package gpg2.41297
From 25d748c3dfc0102f9e54afea59ff26b3969bd8c1 Mon Sep 17 00:00:00 2001
From: Werner Koch <wk@gnupg.org>
Date: Tue, 11 Feb 2025 14:44:23 +0100
Subject: [PATCH 1/6] gpg: Lookup key for merging/inserting only by primary key.
* g10/getkey.c (get_keyblock_byfpr_fast): Add arg primary_only and
implement.
* g10/import.c (import_one_real): Simplify filling the fpr buffer with
zeroes.
(import_one_real): Find key only by primary fingerprint.
--
This should have been done early: When looking up the original
keyblock we want to update, we need to lookup it up only using the
primary key. This avoids to find a key which has the primary key also
has a subkey.
GnuPG-bug-id: 7527
Signed-off-by: Lucas Mulling <lucas.mulling@suse.com>
---
g10/getkey.c | 27 ++++++++++++++++++++++-----
g10/import.c | 8 ++++----
g10/keydb.h | 9 +++++----
3 files changed, 31 insertions(+), 13 deletions(-)
--- a/g10/getkey.c
+++ b/g10/getkey.c
@@ -1826,7 +1826,7 @@ get_pubkey_byfprint_fast (PKT_public_key
gpg_error_t err;
KBNODE keyblock;
- err = get_keyblock_byfprint_fast (&keyblock, NULL, fprint, fprint_len, 0);
+ err = get_keyblock_byfprint_fast (&keyblock, NULL, 0, fprint, fprint_len, 0);
if (!err)
{
if (pk)
@@ -1843,10 +1843,13 @@ get_pubkey_byfprint_fast (PKT_public_key
* R_HD may be NULL. If LOCK is set the handle has been opend in
* locked mode and keydb_disable_caching () has been called. On error
* R_KEYBLOCK is set to NULL but R_HD must be released by the caller;
- * it may have a value of NULL, though. This allows to do an insert
- * operation on a locked keydb handle. */
+ * it may have a value of NULL, though. This allows one to do an
+ * insert operation on a locked keydb handle. If PRIMARY_ONLY is set
+ * the function returns a keyblock which has the requested fingerprint
+ * has primary key. */
gpg_error_t
get_keyblock_byfprint_fast (kbnode_t *r_keyblock, KEYDB_HANDLE *r_hd,
+ int primary_only,
const byte *fprint, size_t fprint_len, int lock)
{
gpg_error_t err;
@@ -1854,6 +1857,8 @@ get_keyblock_byfprint_fast (kbnode_t *r_
kbnode_t keyblock;
byte fprbuf[MAX_FINGERPRINT_LEN];
int i;
+ byte tmpfpr[MAX_FINGERPRINT_LEN];
+ size_t tmpfprlen;
if (r_keyblock)
*r_keyblock = NULL;
@@ -1887,6 +1892,7 @@ get_keyblock_byfprint_fast (kbnode_t *r_
if (r_hd)
*r_hd = hd;
+ again:
err = keydb_search_fpr (hd, fprbuf);
if (gpg_err_code (err) == GPG_ERR_NOT_FOUND)
{
@@ -1906,6 +1912,17 @@ get_keyblock_byfprint_fast (kbnode_t *r_
log_assert (keyblock->pkt->pkttype == PKT_PUBLIC_KEY
|| keyblock->pkt->pkttype == PKT_PUBLIC_SUBKEY);
+ if (primary_only)
+ {
+ fingerprint_from_pk (keyblock->pkt->pkt.public_key, tmpfpr, &tmpfprlen);
+ if (fprint_len != tmpfprlen || memcmp (fprint, tmpfpr, fprint_len))
+ {
+ release_kbnode (keyblock);
+ keyblock = NULL;
+ goto again;
+ }
+ }
+
/* Not caching key here since it won't have all of the fields
properly set. */
--- a/g10/import.c
+++ b/g10/import.c
@@ -1840,7 +1840,6 @@ import_one_real (ctrl_t ctrl,
int mod_key = 0;
int same_key = 0;
int non_self = 0;
- size_t an;
char pkstrbuf[PUBKEY_STRING_SIZE];
int merge_keys_done = 0;
KEYDB_HANDLE hd = NULL;
@@ -1860,8 +1859,8 @@ import_one_real (ctrl_t ctrl,
pk = node->pkt->pkt.public_key;
fingerprint_from_pk (pk, fpr2, &fpr2len);
- for (an = fpr2len; an < MAX_FINGERPRINT_LEN; an++)
- fpr2[an] = 0;
+ if (MAX_FINGERPRINT_LEN > fpr2len)
+ memset (fpr2+fpr2len, 0, MAX_FINGERPRINT_LEN - fpr2len);
keyid_from_pk( pk, keyid );
uidnode = find_next_kbnode( keyblock, PKT_USER_ID );
@@ -2009,7 +2008,8 @@ import_one_real (ctrl_t ctrl,
/* Do we have this key already in one of our pubrings ? */
err = get_keyblock_byfprint_fast (&keyblock_orig, &hd,
- fpr2, fpr2len, 1/*locked*/);
+ 1 /*primary only */,
+ fpr2, fpr2len, 1/*locked*/);
if ((err
&& gpg_err_code (err) != GPG_ERR_NO_PUBKEY
&& gpg_err_code (err) != GPG_ERR_UNUSABLE_PUBKEY)
--- a/g10/keydb.h
+++ b/g10/keydb.h
@@ -397,9 +397,10 @@ gpg_error_t get_pubkey_byfprint_fast (PK
merge the self-signed data into the public key and subkeys or into
the user ids. */
gpg_error_t get_keyblock_byfprint_fast (kbnode_t *r_keyblock,
- KEYDB_HANDLE *r_hd,
- const byte *fprint, size_t fprint_len,
- int lock);
+ KEYDB_HANDLE *r_hd,
+ int primary_only,
+ const byte *fprint, size_t fprint_len,
+ int lock);
/* Returns true if a secret key is available for the public key with