Compare commits

...

10 Commits

Author SHA1 Message Date
openeuler-ci-bot
fb1f4f7d38
!102 Backport follow-up patch for CVE-2025-30258
From: @yixiangzhike 
Reviewed-by: @zcfsite 
Signed-off-by: @zcfsite
2025-05-07 02:30:13 +00:00
yixiangzhike
9f96fcacf6 Backport follow-up patch for CVE-2025-30258 2025-05-06 11:11:43 +08:00
openeuler-ci-bot
f679c558e3
!90 Fix CVE-2025-30258
From: @yixiangzhike 
Reviewed-by: @zcfsite 
Signed-off-by: @zcfsite
2025-03-31 03:20:18 +00:00
yixiangzhike
3fa17fcb5d Fix CVE-2025-30258 2025-03-27 17:33:28 +08:00
openeuler-ci-bot
4d733ed2ef
!82 Fix double free of internal data
From: @yixiangzhike 
Reviewed-by: @zcfsite 
Signed-off-by: @zcfsite
2025-03-21 06:22:53 +00:00
yixiangzhike
0939804794 Fix double free of internal data 2025-03-21 11:39:36 +08:00
openeuler-ci-bot
8254eb1b76
!72 【openEuler-24.03-LTS】Fix minor memory leak
From: @yixiangzhike 
Reviewed-by: @zcfsite 
Signed-off-by: @zcfsite
2024-10-08 01:25:23 +00:00
yixiangzhike
93d6ff8f80 Fix minor memory leak 2024-09-30 16:26:02 +08:00
openeuler-ci-bot
4e6af19394
!69 【openEuler-24.03-LTS】gpg Make --no-literal work again for -c and --store
From: @yixiangzhike 
Reviewed-by: @zcfsite 
Signed-off-by: @zcfsite
2024-09-26 02:34:16 +00:00
yixiangzhike
a3f1223a00 gpg Make --no-literal work again for -c and --store 2024-09-25 16:46:22 +08:00
10 changed files with 1391 additions and 1 deletions

View File

@ -0,0 +1,52 @@
From 794950ec755eab3729d5a5905cbbc2e2d98b8699 Mon Sep 17 00:00:00 2001
From: Werner Koch <wk@gnupg.org>
Date: Thu, 31 Oct 2024 15:11:55 +0100
Subject: [PATCH] gpg: Allow the use of an ADSK subkey as ADSK subkey.
* g10/packet.h (PKT_public_key): Increased size of req_usage to 16.
* g10/getkey.c (key_byname): Set allow_adsk in the context if ir was
requested via req_usage.
(finish_lookup): Allow RENC usage matching.
* g10/keyedit.c (append_adsk_to_key): Adjust the assert.
* g10/keygen.c (prepare_adsk): Also allow to find an RENC subkey.
--
If an ADSK is to be added it may happen that an ADSK subkey is found
first and this should then be used even that it does not have the E
usage. However, it used to have that E usage when it was added.
While testing this I found another pecularity: If you do
gpg -k ADSK_SUBKEY_FPR
without the '!' suffix and no corresponding encryption subkey is dound,
you will get an unusabe key error. I hesitate to fix that due to
possible side-effects.
GnuPG-bug-id: 6882
Adaptation: only reserve the change "Increased size of req_usage to 16"
---
g10/packet.h | 7 +++----
1 files changed, 3 insertions(+), 4 deletions(-)
diff --git a/g10/packet.h b/g10/packet.h
index 80ba91389..7bc0a6461 100644
--- a/g10/packet.h
+++ b/g10/packet.h
@@ -400,11 +400,10 @@ typedef struct
when serializing. (Serialized.) */
byte version;
byte selfsigversion; /* highest version of all of the self-sigs */
- /* The public key algorithm. (Serialized.) */
- byte pubkey_algo;
- u16 pubkey_usage; /* carries the usage info. */
- byte req_usage; /* hack to pass a request to getkey() */
byte fprlen; /* 0 or length of FPR. */
+ byte pubkey_algo; /* The public key algorithm. (PGP format) */
+ u16 pubkey_usage; /* carries the usage info. */
+ u16 req_usage; /* hack to pass a request to getkey() */
u32 has_expired; /* set to the expiration date if expired */
/* keyid of the primary key. Never access this value directly.
Instead, use pk_main_keyid(). */
--
2.33.0

View File

@ -0,0 +1,147 @@
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] 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
---
g10/getkey.c | 27 ++++++++++++++++++++++-----
g10/import.c | 8 ++++----
g10/keydb.h | 9 +++++----
3 files changed, 31 insertions(+), 13 deletions(-)
diff --git a/g10/getkey.c b/g10/getkey.c
index 618ad13e9..20ae84332 100644
--- a/g10/getkey.c
+++ b/g10/getkey.c
@@ -1946,7 +1946,7 @@ get_pubkey_byfprint_fast (ctrl_t ctrl, PKT_public_key * pk,
KBNODE keyblock;
err = get_keyblock_byfprint_fast (ctrl,
- &keyblock, NULL, fprint, fprint_len, 0);
+ &keyblock, NULL, 0, fprint, fprint_len, 0);
if (!err)
{
if (pk)
@@ -1963,18 +1963,23 @@ get_pubkey_byfprint_fast (ctrl_t ctrl, PKT_public_key * pk,
* 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 (ctrl_t ctrl,
- kbnode_t *r_keyblock, KEYDB_HANDLE *r_hd,
- const byte *fprint, size_t fprint_len, int lock)
+ kbnode_t *r_keyblock, KEYDB_HANDLE *r_hd,
+ int primary_only,
+ const byte *fprint, size_t fprint_len, int lock)
{
gpg_error_t err;
KEYDB_HANDLE hd;
kbnode_t keyblock;
byte fprbuf[MAX_FINGERPRINT_LEN];
int i;
+ byte tmpfpr[MAX_FINGERPRINT_LEN];
+ size_t tmpfprlen;
if (r_keyblock)
*r_keyblock = NULL;
@@ -2006,6 +2011,7 @@ get_keyblock_byfprint_fast (ctrl_t ctrl,
if (r_hd)
*r_hd = hd;
+ again:
err = keydb_search_fpr (hd, fprbuf, fprint_len);
if (gpg_err_code (err) == GPG_ERR_NOT_FOUND)
{
@@ -2025,6 +2031,17 @@ get_keyblock_byfprint_fast (ctrl_t ctrl,
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. */
diff --git a/g10/import.c b/g10/import.c
index 7e48284c1..9adda3e8c 100644
--- a/g10/import.c
+++ b/g10/import.c
@@ -1993,7 +1993,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;
@@ -2014,8 +2013,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 );
@@ -2212,7 +2211,8 @@ import_one_real (ctrl_t ctrl,
/* Do we have this key already in one of our pubrings ? */
err = get_keyblock_byfprint_fast (ctrl, &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)
diff --git a/g10/keydb.h b/g10/keydb.h
index ac0953659..658c85a29 100644
--- a/g10/keydb.h
+++ b/g10/keydb.h
@@ -420,10 +420,11 @@ gpg_error_t get_pubkey_byfprint_fast (ctrl_t ctrl, PKT_public_key *pk,
merge the self-signed data into the public key and subkeys or into
the user ids. */
gpg_error_t get_keyblock_byfprint_fast (ctrl_t ctrl,
- kbnode_t *r_keyblock,
- KEYDB_HANDLE *r_hd,
- const byte *fprint, size_t fprint_len,
- int lock);
+ kbnode_t *r_keyblock,
+ KEYDB_HANDLE *r_hd,
+ int primary_only,
+ const byte *fpr, size_t fprlen,
+ int lock);
/* Returns true if a secret key is available for the public key with
--
2.33.0

View File

@ -0,0 +1,127 @@
From 9cd371b12d80cfc5bc85cb6e5f5eebb4decbe94f Mon Sep 17 00:00:00 2001
From: Werner Koch <wk@gnupg.org>
Date: Thu, 20 Feb 2025 14:50:20 +0100
Subject: [PATCH] gpg: Remove a signature check function wrapper.
* g10/sig-check.c (check_signature2): Rename to
(check_signature): this and remove the old wrapper. Adjust all
callers.
---
g10/mainproc.c | 13 +++++--------
g10/packet.h | 6 +-----
g10/sig-check.c | 26 ++++++++------------------
3 files changed, 14 insertions(+), 31 deletions(-)
diff --git a/g10/mainproc.c b/g10/mainproc.c
index 739ad0a35..86f5a2db9 100644
--- a/g10/mainproc.c
+++ b/g10/mainproc.c
@@ -1240,19 +1240,17 @@ do_check_sig (CTX c, kbnode_t node, const void *extrahash, size_t extrahashlen,
/* We only get here if we are checking the signature of a binary
(0x00) or text document (0x01). */
- rc = check_signature2 (c->ctrl, sig, md, extrahash, extrahashlen,
- forced_pk,
- NULL, is_expkey, is_revkey, r_pk);
+ rc = check_signature (c->ctrl, sig, md, extrahash, extrahashlen,
+ forced_pk, NULL, is_expkey, is_revkey, r_pk);
if (! rc)
md_good = md;
else if (gpg_err_code (rc) == GPG_ERR_BAD_SIGNATURE && md2)
{
PKT_public_key *pk2;
- rc = check_signature2 (c->ctrl, sig, md2, extrahash, extrahashlen,
- forced_pk,
- NULL, is_expkey, is_revkey,
- r_pk? &pk2 : NULL);
+ rc = check_signature (c->ctrl, sig, md2, extrahash, extrahashlen,
+ forced_pk, NULL, is_expkey, is_revkey,
+ r_pk? &pk2 : NULL);
if (!rc)
{
md_good = md2;
@@ -1834,7 +1832,6 @@ issuer_fpr_string (PKT_signature *sig)
return p? bin2hex (p, n, NULL) : NULL;
}
-
static void
print_good_bad_signature (int statno, const char *keyid_str, kbnode_t un,
PKT_signature *sig, int rc)
diff --git a/g10/packet.h b/g10/packet.h
index 7bc0a6461..b61c65417 100644
--- a/g10/packet.h
+++ b/g10/packet.h
@@ -907,16 +907,12 @@ int cmp_user_ids( PKT_user_id *a, PKT_user_id *b );
/*-- sig-check.c --*/
-/* Check a signature. This is shorthand for check_signature2 with
- the unnamed arguments passed as NULL. */
-int check_signature (ctrl_t ctrl, PKT_signature *sig, gcry_md_hd_t digest);
-
/* Check a signature. Looks up the public key from the key db. (If
* R_PK is not NULL, it is stored at RET_PK.) DIGEST contains a
* valid hash context that already includes the signed data. This
* function adds the relevant meta-data to the hash before finalizing
* it and verifying the signature. FOCRED_PK is usually NULL. */
-gpg_error_t check_signature2 (ctrl_t ctrl,
+gpg_error_t check_signature (ctrl_t ctrl,
PKT_signature *sig, gcry_md_hd_t digest,
const void *extrahash, size_t extrahashlen,
PKT_public_key *forced_pk,
diff --git a/g10/sig-check.c b/g10/sig-check.c
index 06329f659..54db2089a 100644
--- a/g10/sig-check.c
+++ b/g10/sig-check.c
@@ -88,17 +88,6 @@ check_key_verify_compliance (PKT_public_key *pk)
}
-
-/* Check a signature. This is shorthand for check_signature2 with
- the unnamed arguments passed as NULL. */
-int
-check_signature (ctrl_t ctrl, PKT_signature *sig, gcry_md_hd_t digest)
-{
- return check_signature2 (ctrl, sig, digest, NULL, 0, NULL,
- NULL, NULL, NULL, NULL);
-}
-
-
/* Check a signature.
*
* Looks up the public key that created the signature (SIG->KEYID)
@@ -144,12 +133,12 @@ check_signature (ctrl_t ctrl, PKT_signature *sig, gcry_md_hd_t digest)
*
* Returns 0 on success. An error code otherwise. */
gpg_error_t
-check_signature2 (ctrl_t ctrl,
- PKT_signature *sig, gcry_md_hd_t digest,
- const void *extrahash, size_t extrahashlen,
- PKT_public_key *forced_pk,
- u32 *r_expiredate,
- int *r_expired, int *r_revoked, PKT_public_key **r_pk)
+check_signature (ctrl_t ctrl,
+ PKT_signature *sig, gcry_md_hd_t digest,
+ const void *extrahash, size_t extrahashlen,
+ PKT_public_key *forced_pk,
+ u32 *r_expiredate, int *r_expired, int *r_revoked,
+ PKT_public_key **r_pk)
{
int rc=0;
PKT_public_key *pk;
@@ -802,7 +791,8 @@ check_revocation_keys (ctrl_t ctrl, PKT_public_key *pk, PKT_signature *sig)
hash_public_key(md,pk);
/* Note: check_signature only checks that the signature
is good. It does not fail if the key is revoked. */
- rc = check_signature (ctrl, sig, md);
+ rc = check_signature (ctrl, sig, md, NULL, 0, NULL,
+ NULL, NULL, NULL, NULL);
cache_sig_result(sig,rc);
gcry_md_close (md);
break;
--
2.33.0

View File

@ -0,0 +1,625 @@
From da0164efc7f32013bc24d97b9afa9f8d67c318bb Mon Sep 17 00:00:00 2001
From: Werner Koch <wk@gnupg.org>
Date: Fri, 21 Feb 2025 12:16:17 +0100
Subject: [PATCH] gpg: Fix a verification DoS due to a malicious subkey in the
keyring.
* g10/getkey.c (get_pubkey): Factor code out to ...
(get_pubkey_bykid): new. Add feature to return the keyblock.
(get_pubkey_for_sig): Add arg r_keyblock to return the used keyblock.
Request a signing usage.
(get_pubkeyblock_for_sig): Remove.
(finish_lookup): Improve debug output.
* g10/sig-check.c (check_signature): Add arg r_keyblock and pass it
down.
* g10/mainproc.c (do_check_sig): Ditto.
(check_sig_and_print): Use the keyblock returned by do_check_sig to
show further information instead of looking it up again with
get_pubkeyblock_for_sig. Also re-check the signature after the import
of an included keyblock.
--
The problem here is that it is possible to import a key from someone
who added a signature subkey from another public key and thus inhibits
that a good signature good be verified.
Such a malicious key signature subkey must have been created w/o the
mandatory backsig which bind a signature subkey to its primary key.
For encryption subkeys this is not an issue because the existence of a
decryption private key is all you need to decrypt something and then
it does not matter if the public subkey or its binding signature has
been put below another primary key; in fact we do the latter for
ADSKs.
GnuPG-bug-id: 7527
Backported-from-master: 48978ccb4e20866472ef18436a32744350a65158
---
g10/getkey.c | 108 ++++++++++++++++++++++++++++++------------------
g10/gpg.h | 3 +-
g10/keydb.h | 10 ++++-
g10/mainproc.c | 92 ++++++++++++++++++++++++++---------------
g10/packet.h | 2 +-
g10/sig-check.c | 23 +++++++----
6 files changed, 152 insertions(+), 86 deletions(-)
diff --git a/g10/getkey.c b/g10/getkey.c
index 20ae84332..c4d02fbb1 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_byfprint (ctrl, pk, NULL, fpr, fprlen))
+ if (fpr && !get_pubkey_byfprint (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 swicth
* 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_byfprint (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.
*
@@ -3701,6 +3723,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)
@@ -3731,11 +3754,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 ((k->pkt->pkt.public_key->pubkey_usage == PUBKEY_USAGE_RENC))
@@ -3765,10 +3787,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;
}
diff --git a/g10/gpg.h b/g10/gpg.h
index c51bbbb46..0cdcb8b12 100644
--- a/g10/gpg.h
+++ b/g10/gpg.h
@@ -69,7 +69,8 @@ struct dirmngr_local_s;
typedef struct dirmngr_local_s *dirmngr_local_t;
/* Object used to describe a keyblock node. */
-typedef struct kbnode_struct *KBNODE; /* Deprecated use kbnode_t. */typedef struct kbnode_struct *kbnode_t;
+typedef struct kbnode_struct *KBNODE; /* Deprecated use kbnode_t. */
+typedef struct kbnode_struct *kbnode_t;
/* The handle for keydb operations. */
typedef struct keydb_handle_s *KEYDB_HANDLE;
diff --git a/g10/keydb.h b/g10/keydb.h
index 658c85a29..7d25b3550 100644
--- a/g10/keydb.h
+++ b/g10/keydb.h
@@ -332,9 +332,15 @@ void getkey_disable_caches(void);
/* Return the public key used for signature SIG and store it at PK. */
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);
-/* Return the public key with the key id KEYID and store it at PK. */
+/* Return the public key with the key id KEYID and store it at PK.
+ * Optionally return the entire keyblock. */
+gpg_error_t get_pubkey_bykid (ctrl_t ctrl, PKT_public_key *pk,
+ kbnode_t *r_keyblock, u32 *keyid);
+
+/* Same as get_pubkey_bykid but w/o r_keyblock. */
int get_pubkey (ctrl_t ctrl, PKT_public_key *pk, u32 *keyid);
/* Same as get_pubkey but with auto LDAP fetch. */
diff --git a/g10/mainproc.c b/g10/mainproc.c
index 86f5a2db9..308738839 100644
--- a/g10/mainproc.c
+++ b/g10/mainproc.c
@@ -1150,12 +1150,15 @@ proc_compressed (CTX c, PACKET *pkt)
* used to verify the signature will be stored there, or NULL if not
* found. If FORCED_PK is not NULL, this public key is used to verify
* _data signatures_ and no key lookup is done. Returns: 0 = valid
- * signature or an error code
+ * signature or an error code. If R_KEYBLOCK is not NULL the keyblock
+ * carries the used PK is stored there. The caller should always free
+ * the return value using release_kbnode.
*/
static int
do_check_sig (CTX c, kbnode_t node, const void *extrahash, size_t extrahashlen,
PKT_public_key *forced_pk, int *is_selfsig,
- int *is_expkey, int *is_revkey, PKT_public_key **r_pk)
+ int *is_expkey, int *is_revkey,
+ PKT_public_key **r_pk, kbnode_t *r_keyblock)
{
PKT_signature *sig;
gcry_md_hd_t md = NULL;
@@ -1165,6 +1168,8 @@ do_check_sig (CTX c, kbnode_t node, const void *extrahash, size_t extrahashlen,
if (r_pk)
*r_pk = NULL;
+ if (r_keyblock)
+ *r_keyblock = NULL;
log_assert (node->pkt->pkttype == PKT_SIGNATURE);
if (is_selfsig)
@@ -1241,16 +1246,19 @@ do_check_sig (CTX c, kbnode_t node, const void *extrahash, size_t extrahashlen,
/* We only get here if we are checking the signature of a binary
(0x00) or text document (0x01). */
rc = check_signature (c->ctrl, sig, md, extrahash, extrahashlen,
- forced_pk, NULL, is_expkey, is_revkey, r_pk);
+ forced_pk, NULL, is_expkey, is_revkey,
+ r_pk, r_keyblock);
if (! rc)
md_good = md;
else if (gpg_err_code (rc) == GPG_ERR_BAD_SIGNATURE && md2)
{
PKT_public_key *pk2;
+ if (r_keyblock)
+ release_kbnode (*r_keyblock);
rc = check_signature (c->ctrl, sig, md2, extrahash, extrahashlen,
forced_pk, NULL, is_expkey, is_revkey,
- r_pk? &pk2 : NULL);
+ r_pk? &pk2 : NULL, r_keyblock);
if (!rc)
{
md_good = md2;
@@ -1413,7 +1421,7 @@ list_node (CTX c, kbnode_t node)
{
fflush (stdout);
rc2 = do_check_sig (c, node, NULL, 0, NULL,
- &is_selfsig, NULL, NULL, NULL);
+ &is_selfsig, NULL, NULL, NULL, NULL);
switch (gpg_err_code (rc2))
{
case 0: sigrc = '!'; break;
@@ -1872,7 +1880,7 @@ check_sig_and_print (CTX c, kbnode_t node)
PKT_public_key *pk = NULL; /* The public key for the signature or NULL. */
const void *extrahash = NULL;
size_t extrahashlen = 0;
- kbnode_t included_keyblock = NULL;
+ kbnode_t keyblock = NULL;
if (opt.skip_verify)
{
@@ -1993,7 +2001,8 @@ check_sig_and_print (CTX c, kbnode_t node)
{
ambiguous:
log_error(_("can't handle this ambiguous signature data\n"));
- return 0;
+ rc = 0;
+ goto leave;
}
} /* End checking signature packet composition. */
@@ -2029,7 +2038,7 @@ check_sig_and_print (CTX c, kbnode_t node)
log_info (_(" issuer \"%s\"\n"), sig->signers_uid);
rc = do_check_sig (c, node, extrahash, extrahashlen, NULL,
- NULL, &is_expkey, &is_revkey, &pk);
+ NULL, &is_expkey, &is_revkey, &pk, &keyblock);
/* If the key is not found but the signature includes a key block we
* use that key block for verification and on success import it. */
@@ -2037,6 +2046,7 @@ check_sig_and_print (CTX c, kbnode_t node)
&& sig->flags.key_block
&& opt.flags.auto_key_import)
{
+ kbnode_t included_keyblock = NULL;
PKT_public_key *included_pk;
const byte *kblock;
size_t kblock_len;
@@ -2048,10 +2058,12 @@ check_sig_and_print (CTX c, kbnode_t node)
kblock+1, kblock_len-1,
sig->keyid, &included_keyblock))
{
+ /* Note: This is the only place where we use the forced_pk
+ * arg (ie. included_pk) with do_check_sig. */
rc = do_check_sig (c, node, extrahash, extrahashlen, included_pk,
- NULL, &is_expkey, &is_revkey, &pk);
+ NULL, &is_expkey, &is_revkey, &pk, NULL);
if (opt.verbose)
- log_debug ("checked signature using included key block: %s\n",
+ log_info ("checked signature using included key block: %s\n",
gpg_strerror (rc));
if (!rc)
{
@@ -2061,6 +2073,18 @@ check_sig_and_print (CTX c, kbnode_t node)
}
free_public_key (included_pk);
+ release_kbnode (included_keyblock);
+
+ /* To make sure that nothing strange happened we check the
+ * signature again now using our own key store. This also
+ * returns the keyblock which we use later on. */
+ if (!rc)
+ {
+ release_kbnode (keyblock);
+ keyblock = NULL;
+ rc = do_check_sig (c, node, extrahash, extrahashlen, NULL,
+ NULL, &is_expkey, &is_revkey, &pk, &keyblock);
+ }
}
/* If the key isn't found, check for a preferred keyserver. Note
@@ -2107,8 +2131,13 @@ check_sig_and_print (CTX c, kbnode_t node)
KEYSERVER_IMPORT_FLAG_QUICK);
glo_ctrl.in_auto_key_retrieve--;
if (!res)
- rc = do_check_sig (c, node, extrahash, extrahashlen, NULL,
- NULL, &is_expkey, &is_revkey, &pk);
+ {
+ release_kbnode (keyblock);
+ keyblock = NULL;
+ rc = do_check_sig (c, node, extrahash, extrahashlen, NULL,
+ NULL, &is_expkey, &is_revkey, &pk,
+ &keyblock);
+ }
else if (DBG_LOOKUP)
log_debug ("lookup via %s failed: %s\n", "Pref-KS",
gpg_strerror (res));
@@ -2149,8 +2178,12 @@ check_sig_and_print (CTX c, kbnode_t node)
/* Fixme: If the fingerprint is embedded in the signature,
* compare it to the fingerprint of the returned key. */
if (!res)
- rc = do_check_sig (c, node, extrahash, extrahashlen, NULL,
- NULL, &is_expkey, &is_revkey, &pk);
+ {
+ release_kbnode (keyblock);
+ keyblock = NULL;
+ rc = do_check_sig (c, node, extrahash, extrahashlen, NULL,
+ NULL, &is_expkey, &is_revkey, &pk, &keyblock);
+ }
else if (DBG_LOOKUP)
log_debug ("lookup via %s failed: %s\n", "WKD", gpg_strerror (res));
}
@@ -2180,8 +2213,13 @@ check_sig_and_print (CTX c, kbnode_t node)
KEYSERVER_IMPORT_FLAG_QUICK);
glo_ctrl.in_auto_key_retrieve--;
if (!res)
- rc = do_check_sig (c, node, extrahash, extrahashlen, NULL,
- NULL, &is_expkey, &is_revkey, &pk);
+ {
+ release_kbnode (keyblock);
+ keyblock = NULL;
+ rc = do_check_sig (c, node, extrahash, extrahashlen, NULL,
+ NULL, &is_expkey, &is_revkey, &pk,
+ &keyblock);
+ }
else if (DBG_LOOKUP)
log_debug ("lookup via %s failed: %s\n", "KS", gpg_strerror (res));
}
@@ -2192,7 +2230,7 @@ check_sig_and_print (CTX c, kbnode_t node)
{
/* We have checked the signature and the result is either a good
* signature or a bad signature. Further examination follows. */
- kbnode_t un, keyblock;
+ kbnode_t un;
int count = 0;
int keyblock_has_pk = 0; /* For failsafe check. */
int statno;
@@ -2210,18 +2248,6 @@ check_sig_and_print (CTX c, kbnode_t node)
else
statno = STATUS_GOODSIG;
- /* FIXME: We should have the public key in PK and thus the
- * keyblock has already been fetched. Thus we could use the
- * fingerprint or PK itself to lookup the entire keyblock. That
- * would best be done with a cache. */
- if (included_keyblock)
- {
- keyblock = included_keyblock;
- included_keyblock = NULL;
- }
- else
- keyblock = get_pubkeyblock_for_sig (c->ctrl, sig);
-
snprintf (keyid_str, sizeof keyid_str, "%08lX%08lX [uncertain] ",
(ulong)sig->keyid[0], (ulong)sig->keyid[1]);
@@ -2287,10 +2313,10 @@ check_sig_and_print (CTX c, kbnode_t node)
* contained in the keyring.*/
}
- log_assert (mainpk);
- if (!keyblock_has_pk)
+ if (!mainpk || !keyblock_has_pk)
{
- log_error ("signature key lost from keyblock\n");
+ log_error ("signature key lost from keyblock (%p,%p,%d)\n",
+ keyblock, mainpk, keyblock_has_pk);
rc = gpg_error (GPG_ERR_INTERNAL);
}
@@ -2562,8 +2588,8 @@ check_sig_and_print (CTX c, kbnode_t node)
log_error (_("Can't check signature: %s\n"), gpg_strerror (rc));
}
+ leave:
free_public_key (pk);
- release_kbnode (included_keyblock);
xfree (issuer_fpr);
return rc;
}
diff --git a/g10/packet.h b/g10/packet.h
index b61c65417..d6cbef4bc 100644
--- a/g10/packet.h
+++ b/g10/packet.h
@@ -917,7 +917,7 @@ gpg_error_t check_signature (ctrl_t ctrl,
const void *extrahash, size_t extrahashlen,
PKT_public_key *forced_pk,
u32 *r_expiredate, int *r_expired, int *r_revoked,
- PKT_public_key **r_pk);
+ PKT_public_key **r_pk, kbnode_t *r_keyblock);
/*-- pubkey-enc.c --*/
diff --git a/g10/sig-check.c b/g10/sig-check.c
index 54db2089a..456c29320 100644
--- a/g10/sig-check.c
+++ b/g10/sig-check.c
@@ -131,6 +131,11 @@ check_key_verify_compliance (PKT_public_key *pk)
* If R_PK is not NULL, the public key is stored at that address if it
* was found; other wise NULL is stored.
*
+ * If R_KEYBLOCK is not NULL, the entire keyblock used to verify the
+ * signature is stored at that address. If no key was found or on
+ * some other errors NULL is stored there. The callers needs to
+ * release the keyblock using release_kbnode (kb).
+ *
* Returns 0 on success. An error code otherwise. */
gpg_error_t
check_signature (ctrl_t ctrl,
@@ -138,7 +143,7 @@ check_signature (ctrl_t ctrl,
const void *extrahash, size_t extrahashlen,
PKT_public_key *forced_pk,
u32 *r_expiredate, int *r_expired, int *r_revoked,
- PKT_public_key **r_pk)
+ PKT_public_key **r_pk, kbnode_t *r_keyblock)
{
int rc=0;
PKT_public_key *pk;
@@ -151,6 +156,8 @@ check_signature (ctrl_t ctrl,
*r_revoked = 0;
if (r_pk)
*r_pk = NULL;
+ if (r_keyblock)
+ *r_keyblock = NULL;
pk = xtrycalloc (1, sizeof *pk);
if (!pk)
@@ -181,7 +188,7 @@ check_signature (ctrl_t ctrl,
log_info(_("WARNING: signature digest conflict in message\n"));
rc = gpg_error (GPG_ERR_GENERAL);
}
- else if (get_pubkey_for_sig (ctrl, pk, sig, forced_pk))
+ else if (get_pubkey_for_sig (ctrl, pk, sig, forced_pk, r_keyblock))
rc = gpg_error (GPG_ERR_NO_PUBKEY);
else if ((rc = check_key_verify_compliance (pk)))
;/* Compliance failure. */
@@ -780,9 +787,9 @@ check_revocation_keys (ctrl_t ctrl, PKT_public_key *pk, PKT_signature *sig)
keyid_from_fingerprint (ctrl, pk->revkey[i].fpr, pk->revkey[i].fprlen,
keyid);
- if(keyid[0]==sig->keyid[0] && keyid[1]==sig->keyid[1])
- /* The signature was generated by a designated revoker.
- Verify the signature. */
+ /* If the signature was generated by a designated revoker
+ * verify the signature. */
+ if (keyid[0] == sig->keyid[0] && keyid[1] == sig->keyid[1])
{
gcry_md_hd_t md;
@@ -790,9 +797,9 @@ check_revocation_keys (ctrl_t ctrl, PKT_public_key *pk, PKT_signature *sig)
BUG ();
hash_public_key(md,pk);
/* Note: check_signature only checks that the signature
- is good. It does not fail if the key is revoked. */
+ * is good. It does not fail if the key is revoked. */
rc = check_signature (ctrl, sig, md, NULL, 0, NULL,
- NULL, NULL, NULL, NULL);
+ NULL, NULL, NULL, NULL, NULL);
cache_sig_result(sig,rc);
gcry_md_close (md);
break;
@@ -997,7 +1004,7 @@ check_signature_over_key_or_uid (ctrl_t ctrl, PKT_public_key *signer,
if (IS_CERT (sig))
signer->req_usage = PUBKEY_USAGE_CERT;
- rc = get_pubkey_for_sig (ctrl, signer, sig, NULL);
+ rc = get_pubkey_for_sig (ctrl, signer, sig, NULL, NULL);
if (rc)
{
xfree (signer);
--
2.33.0

View File

@ -0,0 +1,177 @@
From 1e581619bf5315957f2be06b3b1a7f513304c126 Mon Sep 17 00:00:00 2001
From: Werner Koch <wk@gnupg.org>
Date: Thu, 6 Mar 2025 17:17:17 +0100
Subject: [PATCH] gpg: Fix regression for the recent malicious subkey DoS fix.
* g10/packet.h (PUBKEY_USAGE_VERIFY): New.
* g10/getkey.c (get_pubkey_for_sig): Pass new flag also to requested
usage.
(finish_lookup): Introduce a verify_mode.
--
Fixes-commit: da0164efc7f32013bc24d97b9afa9f8d67c318bb
GnuPG-bug-id: 7547
---
g10/getkey.c | 44 ++++++++++++++++++++++++++++----------------
g10/packet.h | 1 +
2 files changed, 29 insertions(+), 16 deletions(-)
diff --git a/g10/getkey.c b/g10/getkey.c
index c4d02fbb1..e3264062f 100644
--- a/g10/getkey.c
+++ b/g10/getkey.c
@@ -315,11 +315,12 @@ 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
+ * 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.
* 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. */
+ * stored there. Use this function only to find the key for
+ * verification; it can't be used to select a key for signing. */
gpg_error_t
get_pubkey_for_sig (ctrl_t ctrl, PKT_public_key *pk, PKT_signature *sig,
PKT_public_key *forced_pk, kbnode_t *r_keyblock)
@@ -339,8 +340,9 @@ get_pubkey_for_sig (ctrl_t ctrl, PKT_public_key *pk, PKT_signature *sig,
/* 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;
+ * will be skipped. We also request the verification mode so that
+ * expired and reoked keys are returned. */
+ pk->req_usage = (PUBKEY_USAGE_SIG | PUBKEY_USAGE_VERIFY);
/* First try the ISSUER_FPR info. */
fpr = issuer_fpr_raw (sig, &fprlen);
@@ -404,10 +406,10 @@ get_pubkey_bykid (ctrl_t ctrl, PKT_public_key *pk, kbnode_t *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.
* The old get_pubkey_function did not check PK->REQ_USAGE when
- * reading form the caceh. This is probably a bug. Note that
+ * reading from the cache. 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. */
+ * associate the public key with its primary key. */
pk_cache_entry_t ce;
for (ce = pk_cache; ce; ce = ce->next)
{
@@ -3724,11 +3726,18 @@ finish_lookup (kbnode_t keyblock, unsigned int req_usage, int want_exact,
PKT_public_key *pk;
int req_prim;
int diag_exactfound = 0;
+ int verify_mode = 0;
u32 curtime = make_timestamp ();
if (r_flags)
*r_flags = 0;
+
+ /* The verify mode is used to change the behaviour so that we can
+ * return an expired or revoked key for signature verification. */
+ verify_mode = ((req_usage & PUBKEY_USAGE_VERIFY)
+ && (req_usage & PUBKEY_USAGE_SIG));
+
#define USAGE_MASK (PUBKEY_USAGE_SIG|PUBKEY_USAGE_ENC|PUBKEY_USAGE_CERT)
req_usage &= USAGE_MASK;
@@ -3784,9 +3793,9 @@ finish_lookup (kbnode_t keyblock, unsigned int req_usage, int want_exact,
}
if (DBG_LOOKUP)
- log_debug ("finish_lookup: checking key %08lX (%s)(req_usage=%x)\n",
+ log_debug ("finish_lookup: checking key %08lX (%s)(req_usage=%x%s)\n",
(ulong) keyid_from_pk (keyblock->pkt->pkt.public_key, NULL),
- foundk ? "one" : "all", req_usage);
+ foundk ? "one" : "all", req_usage, verify_mode? ",verify":"");
if (diag_exactfound && DBG_LOOKUP)
log_debug ("\texact search requested and found\n");
@@ -3850,28 +3859,29 @@ finish_lookup (kbnode_t keyblock, unsigned int req_usage, int want_exact,
}
n_subkeys++;
- if (pk->flags.revoked)
+ if (!verify_mode && pk->flags.revoked)
{
if (DBG_LOOKUP)
log_debug ("\tsubkey has been revoked\n");
n_revoked_or_expired++;
continue;
}
- if (pk->has_expired && !opt.ignore_expiration)
+ if (!verify_mode && pk->has_expired && !opt.ignore_expiration)
{
if (DBG_LOOKUP)
log_debug ("\tsubkey has expired\n");
n_revoked_or_expired++;
continue;
}
- if (pk->timestamp > curtime && !opt.ignore_valid_from)
+ if (!verify_mode && pk->timestamp > curtime && !opt.ignore_valid_from)
{
if (DBG_LOOKUP)
log_debug ("\tsubkey not yet valid\n");
continue;
}
- if (want_secret)
+
+ if (!verify_mode && want_secret)
{
int secret_key_avail = agent_probe_secret_key (NULL, pk);
@@ -3898,7 +3908,8 @@ finish_lookup (kbnode_t keyblock, unsigned int req_usage, int want_exact,
}
if (DBG_LOOKUP)
- log_debug ("\tsubkey might be fine\n");
+ log_debug ("\tsubkey might be fine%s\n",
+ verify_mode? " for verification":"");
/* In case a key has a timestamp of 0 set, we make sure
that it is used. A better change would be to compare
">=" but that might also change the selected keys and
@@ -3939,12 +3950,12 @@ finish_lookup (kbnode_t keyblock, unsigned int req_usage, int want_exact,
log_debug ("\tprimary key usage does not match: "
"want=%x have=%x\n", req_usage, pk->pubkey_usage);
}
- else if (pk->flags.revoked)
+ else if (!verify_mode && pk->flags.revoked)
{
if (DBG_LOOKUP)
log_debug ("\tprimary key has been revoked\n");
}
- else if (pk->has_expired)
+ else if (!verify_mode && pk->has_expired)
{
if (DBG_LOOKUP)
log_debug ("\tprimary key has expired\n");
@@ -3952,7 +3963,8 @@ finish_lookup (kbnode_t keyblock, unsigned int req_usage, int want_exact,
else /* Okay. */
{
if (DBG_LOOKUP)
- log_debug ("\tprimary key may be used\n");
+ log_debug ("\tprimary key may be used%s\n",
+ verify_mode? " for verification":"");
latest_key = keyblock;
}
}
diff --git a/g10/packet.h b/g10/packet.h
index d6cbef4bc..9a1198d4a 100644
--- a/g10/packet.h
+++ b/g10/packet.h
@@ -60,6 +60,7 @@
#define PUBKEY_USAGE_RENC 1024 /* Restricted encryption. */
#define PUBKEY_USAGE_TIME 2048 /* Timestamp use. */
+#define PUBKEY_USAGE_VERIFY 16384 /* Verify only modifier. */
/* Bitflags to convey hints on what kind of signature is created. */
#define SIGNHINT_KEYSIG 1
#define SIGNHINT_SELFSIG 2
--
2.33.0

View File

@ -0,0 +1,48 @@
From 9b7c067717d815e16f9ea3cec88bca09a6cce7cb Mon Sep 17 00:00:00 2001
From: Werner Koch <wk@gnupg.org>
Date: Fri, 2 May 2025 11:11:05 +0200
Subject: [PATCH] gpg: Fix another regression due to the T7547 fix.
* g10/getkey.c (get_pubkey_for_sig): Keep a requested
PUBKEY_USAGE_CERT.
(finish_lookup): For correctness in future use cases allow
PUBKEY_USAGE_CERT to also trigger verify mode.
--
The case here was that a cert-only primary key was removed with
export-clean.
GnuPG-bug-id: 7583
---
g10/getkey.c | 8 +++++---
1 file changed, 5 insertions(+), 3 deletions(-)
diff --git a/g10/getkey.c b/g10/getkey.c
index e3264062f..ae0e00220 100644
--- a/g10/getkey.c
+++ b/g10/getkey.c
@@ -341,8 +341,10 @@ get_pubkey_for_sig (ctrl_t ctrl, PKT_public_key *pk, PKT_signature *sig,
/* 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. We also request the verification mode so that
- * expired and reoked keys are returned. */
- pk->req_usage = (PUBKEY_USAGE_SIG | PUBKEY_USAGE_VERIFY);
+ * expired and revoked keys are returned. We keep only a requested
+ * CERT usage in PK for the sake of key signatures. */
+ pk->req_usage = (PUBKEY_USAGE_SIG | PUBKEY_USAGE_VERIFY
+ | (pk->req_usage & PUBKEY_USAGE_CERT));
/* First try the ISSUER_FPR info. */
fpr = issuer_fpr_raw (sig, &fprlen);
@@ -3736,7 +3738,7 @@ finish_lookup (kbnode_t keyblock, unsigned int req_usage, int want_exact,
/* The verify mode is used to change the behaviour so that we can
* return an expired or revoked key for signature verification. */
verify_mode = ((req_usage & PUBKEY_USAGE_VERIFY)
- && (req_usage & PUBKEY_USAGE_SIG));
+ && (req_usage & (PUBKEY_USAGE_CERT|PUBKEY_USAGE_SIG)));
#define USAGE_MASK (PUBKEY_USAGE_SIG|PUBKEY_USAGE_ENC|PUBKEY_USAGE_CERT)
req_usage &= USAGE_MASK;
--
2.43.0

View File

@ -0,0 +1,32 @@
From 4be25979a6b3e2a79d7c9667b07db8b09fb046e9 Mon Sep 17 00:00:00 2001
From: Werner Koch <wk@gnupg.org>
Date: Thu, 13 Mar 2025 11:35:34 +0100
Subject: [PATCH] gpg: Fix double free of internal data.
* g10/sig-check.c (check_signature_over_key_or_uid): Do not free in
no-sig-cache mode if allocated by caller.
--
GnuPG-bug-id: 7547
Fixes-commit: 44cdb9d73f1a0b7d2c8483a119b9c4d6caabc1ec
---
g10/sig-check.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/g10/sig-check.c b/g10/sig-check.c
index 456c29320..ed83c23f9 100644
--- a/g10/sig-check.c
+++ b/g10/sig-check.c
@@ -1007,7 +1007,8 @@ check_signature_over_key_or_uid (ctrl_t ctrl, PKT_public_key *signer,
rc = get_pubkey_for_sig (ctrl, signer, sig, NULL, NULL);
if (rc)
{
- xfree (signer);
+ if (signer_alloced != 1)
+ xfree (signer);
signer = NULL;
signer_alloced = 0;
goto leave;
--
2.33.0

View File

@ -0,0 +1,47 @@
From 95b9a31f81e4a56518269d2476b54a1f10fe8b3e Mon Sep 17 00:00:00 2001
From: Werner Koch <wk@gnupg.org>
Date: Fri, 27 Oct 2023 14:20:47 +0200
Subject: [PATCH] gpg: Fix minor memory leak during certain smartcard
operations.
* g10/keygen.c (card_store_key_with_backup): Fix memory leak on error.
---
g10/keygen.c | 13 +++++++++++--
1 file changed, 11 insertions(+), 2 deletions(-)
diff --git a/g10/keygen.c b/g10/keygen.c
index 87940722d..2f8528278 100644
--- a/g10/keygen.c
+++ b/g10/keygen.c
@@ -5386,17 +5386,26 @@ card_store_key_with_backup (ctrl_t ctrl, PKT_public_key *sub_psk,
{
ecdh_param_str = ecdh_param_str_from_pk (sk);
if (!ecdh_param_str)
- return gpg_error_from_syserror ();
+ {
+ free_public_key (sk);
+ return gpg_error_from_syserror ();
+ }
}
err = hexkeygrip_from_pk (sk, &hexgrip);
if (err)
- goto leave;
+ {
+ xfree (ecdh_param_str);
+ free_public_key (sk);
+ goto leave;
+ }
memset(&info, 0, sizeof (info));
rc = agent_scd_getattr ("SERIALNO", &info);
if (rc)
{
+ xfree (ecdh_param_str);
+ free_public_key (sk);
err = (gpg_error_t)rc;
goto leave;
}
--
2.33.0

View File

@ -0,0 +1,111 @@
From 9a741aba3d9040d2bb367db79e9021ba6abc12dd Mon Sep 17 00:00:00 2001
From: Werner Koch <wk@gnupg.org>
Date: Fri, 6 Sep 2024 15:46:41 +0200
Subject: [PATCH] gpg: Make --no-literal work again for -c and --store.
* g10/dearmor.c (dearmor_file): Check for errors of iobuf_copy.
(enarmor_file): Ditto.
* g10/encrypt.c (encrypt_simple): Fix error check of iobuf_copy
(encrypt_crypt): Use iobuf_copy.
--
Fixes-commit: 756c0bd5d89bd0a773f844fbc2ec508c1a36c63d
GnuPG-bug-id: 5852
---
g10/dearmor.c | 12 ++++++++++++
g10/encrypt.c | 35 +++++++++++++++++------------------
2 files changed, 29 insertions(+), 18 deletions(-)
diff --git a/g10/dearmor.c b/g10/dearmor.c
index f6bb59ef6..667888362 100644
--- a/g10/dearmor.c
+++ b/g10/dearmor.c
@@ -67,6 +67,12 @@ dearmor_file( const char *fname )
goto leave;
iobuf_copy (out, inp);
+ if ((rc = iobuf_error (inp)))
+ log_error (_("error reading '%s': %s\n"),
+ iobuf_get_fname_nonnull (inp), gpg_strerror (rc));
+ else if ((rc = iobuf_error (out)))
+ log_error (_("error writing '%s': %s\n"),
+ iobuf_get_fname_nonnull (out), gpg_strerror (rc));
leave:
if( rc )
@@ -115,6 +121,12 @@ enarmor_file( const char *fname )
push_armor_filter ( afx, out );
iobuf_copy (out, inp);
+ if ((rc = iobuf_error (inp)))
+ log_error (_("error reading '%s': %s\n"),
+ iobuf_get_fname_nonnull (inp), gpg_strerror (rc));
+ else if ((rc = iobuf_error (out)))
+ log_error (_("error writing '%s': %s\n"),
+ iobuf_get_fname_nonnull (out), gpg_strerror (rc));
leave:
if( rc )
diff --git a/g10/encrypt.c b/g10/encrypt.c
index 3fc10a7b8..cc8f37fe2 100644
--- a/g10/encrypt.c
+++ b/g10/encrypt.c
@@ -633,9 +633,13 @@ encrypt_simple (const char *filename, int mode, int use_seskey)
{
/* User requested not to create a literal packet, so we copy the
plain data. */
- rc = iobuf_copy (out, inp);
- if (rc)
- log_error ("copying input to output failed: %s\n", gpg_strerror (rc));
+ iobuf_copy (out, inp);
+ if ((rc = iobuf_error (inp)))
+ log_error (_("error reading '%s': %s\n"),
+ iobuf_get_fname_nonnull (inp), gpg_strerror (rc));
+ else if ((rc = iobuf_error (out)))
+ log_error (_("error writing '%s': %s\n"),
+ iobuf_get_fname_nonnull (out), gpg_strerror (rc));
}
/* Finish the stuff. */
@@ -760,8 +764,8 @@ write_symkey_enc (STRING2KEY *symkey_s2k, aead_algo_t aead_algo,
* The caller may provide a checked list of public keys in
* PROVIDED_PKS; if not the function builds a list of keys on its own.
*
- * Note that FILEFD is currently only used by cmd_encrypt in the
- * not yet finished server.c.
+ * Note that FILEFD and OUTPUTFD are currently only used by
+ * cmd_encrypt in the not yet finished server.c.
*/
int
encrypt_crypt (ctrl_t ctrl, int filefd, const char *filename,
@@ -996,19 +1000,14 @@ encrypt_crypt (ctrl_t ctrl, int filefd, const char *filename,
{
/* User requested not to create a literal packet, so we copy the
plain data. */
- byte copy_buffer[4096];
- int bytes_copied;
- while ((bytes_copied = iobuf_read (inp, copy_buffer, 4096)) != -1)
- {
- rc = iobuf_write (out, copy_buffer, bytes_copied);
- if (rc)
- {
- log_error ("copying input to output failed: %s\n",
- gpg_strerror (rc));
- break;
- }
- }
- wipememory (copy_buffer, 4096); /* Burn the buffer. */
+ iobuf_copy (out, inp);
+ if ((rc = iobuf_error (inp)))
+ log_error (_("error reading '%s': %s\n"),
+ iobuf_get_fname_nonnull (inp), gpg_strerror (rc));
+ else if ((rc = iobuf_error (out)))
+ log_error (_("error writing '%s': %s\n"),
+ iobuf_get_fname_nonnull (out), gpg_strerror (rc));
+
}
/* Finish the stuff. */
--
2.33.0

View File

@ -1,6 +1,6 @@
Name: gnupg2
Version: 2.4.3
Release: 2
Release: 7
Summary: Utility for secure communication and data storage
License: GPLv3+
@ -18,6 +18,15 @@ Patch7: gnupg-2.2.20-file-is-digest.patch
Patch8: gnupg-2.2.21-coverity.patch
Patch9: gnupg2-revert-rfc4880bis.patch
Patch10: backport-dirmngr-Enable-the-call-of-ks_ldap_help_variables-wh.patch
Patch11: backport-gpg-Make-no-literal-work-again-for-c-and-store.patch
Patch12: backport-gpg-Fix-minor-memory-leak-during-certain-smartcard-o.patch
Patch13: backport-0001-CVE-2025-30258.patch
Patch14: backport-0002-CVE-2025-30258.patch
Patch15: backport-0003-CVE-2025-30258.patch
Patch16: backport-0004-CVE-2025-30258.patch
Patch17: backport-0005-CVE-2025-30258.patch
Patch18: backport-0006-CVE-2025-30258.patch
Patch19: backport-gpg-Fix-double-free-of-internal-data.patch
BuildRequires: gcc
BuildRequires: zlib-devel, npth-devel, texinfo
@ -119,6 +128,21 @@ make check
%changelog
* Tue May 6 2025 yixiangzhike <yixiangzhike007@163.com> - 2.4.3-7
- backport follow-up patch for CVE-2025-30258
* Thu Mar 27 2025 yixiangzhike <yixiangzhike007@163.com> - 2.4.3-6
- fix CVE-2025-30258
* Fri Mar 21 2025 yixiangzhike <yixiangzhike007@163.com> - 2.4.3-5
- backport upstream patch to fix double free
* Mon Sep 30 2024 yixiangzhike <yixiangzhike007@163.com> - 2.4.3-4
- backport upstream patch to fix minor memory leak
* Wed Sep 25 2024 yixiangzhike <yixiangzhike007@163.com> - 2.4.3-3
- gpg Make --no-literal work again for -c and --store
* Tue Jan 2 2024 yixiangzhike <yixiangzhike007@163.com> - 2.4.3-2
- use gpgtar to replace gpg-zip