From soap at gentoo.org Tue Nov 3 13:17:24 2026 From: soap at gentoo.org (David Seifert) Date: Tue, 3 Nov 2026 13:17:24 +0100 Subject: [PATCH gnupg] scd:piv: Let the card decide whether signing needs a PIN Message-ID: <20261103121726.2212590-1-soap@gentoo.org> * scd/app-piv.c (YKPIV_METADATA_POLICY_TAG): Remove. (get_cached_data): Remove support for special tag 0xF7xx. (check_pin_policy): Remove. (do_sign): Do not verify the PIN before signing. If GENERAL AUTHENTICATE fails with GPG_ERR_BAD_PIN, force a verify and retry once. -- Deciding up front whether to ask for the PIN requires knowing the card's per-key PIN policy. The YubiKey GET METADATA command (0xF7) only exists on YubiKey 5.3 and later and was only used for cards detected as YubiKeys. Older YubiKeys and other cards implementing the same per-key policies (e.g. TOKEN2 PIV) thus fall back to forcing a verify for 9C on every signature, ignoring a configured ONCE or NEVER policy. Instead, just try the operation first. If the card refuses it with 6982 (mapped to GPG_ERR_BAD_PIN), force a fresh PIN entry and retry once. This works for any card that enforces its own policy, needs no vendor detection, and still prompts for every signature with a "PIN Always" key, because a forced verify bypasses the PIN cache. This changes signing for all keys handled by do_sign (and thus do_auth), not only 9C: e.g. 9E now signs without a PIN, as intended by SP 800-73. I have tested the change against various smartcards with PIV functionality. A fake pinentry counted the prompts - each scenario starts with a fresh P-256 key in 9C and a card reset. TOKEN2 PIV card (PIN+ R3.3, policy read back via GET METADATA): 9C policy Operations Prompts Result NEVER sign, sign 0, 0 both signed ONCE sign, sign 1, 0 both signed ALWAYS sign, sign 1, 1 both signed ALWAYS cancel 1 canceled, retries kept (6) ALWAYS wrong, good PIN 1, 1 Bad PIN (6 -> 5), then signed, retries back to 6 YubiKey 4 (firmware 4.3.7, policy confirmed via attestation): 9C policy Operations Prompts Result NEVER sign, sign 0, 0 both signed ONCE sign, sign 1, 0 both signed ALWAYS sign, sign 1, 1 both signed ALWAYS cancel 1 canceled, retries kept (3) ALWAYS wrong, good PIN 1, 1 Bad PIN (3 -> 2), then signed, retries back to 3 YubiKey 5 NFC (firmware 5.1.2, policy confirmed via attestation): 9C policy Operations Prompts Result NEVER sign, sign 0, 0 both signed ONCE sign, sign 1, 0 both signed ALWAYS sign, sign 1, 1 both signed ALWAYS cancel 1 canceled, retries kept (3) ALWAYS wrong, good PIN 1, 1 Bad PIN (3 -> 2), then signed, retries back to 3 Nitrokey 3 (accepts but ignores the policy at key generation and enforces "PIN Always" for 9C): 9C policy Operations Prompts Result NEVER sign, sign 1, 1 both signed ONCE sign, sign 1, 1 both signed ALWAYS sign, sign 1, 1 both signed ALWAYS cancel 1 canceled, retries kept (3) ALWAYS wrong, good PIN 1, 1 Bad PIN (3 -> 2), then signed, retries back to 3 Signed-off-by: David Seifert --- scd/app-piv.c | 109 ++++++++------------------------------------------ 1 file changed, 16 insertions(+), 93 deletions(-) diff --git a/scd/app-piv.c b/scd/app-piv.c index 9652ff68e..d9ff8be06 100644 --- a/scd/app-piv.c +++ b/scd/app-piv.c @@ -266,14 +266,9 @@ do_deinit (app_t app) } -#define YKPIV_METADATA_POLICY_TAG 0x02 - /* Wrapper around iso7816_get_data which first tries to get the data * from the cache. With GET_IMMEDIATE passed as true, the cache is * bypassed. The tag-53 container is also removed. - * - * A special tag F7xx is also supported to get PIN Policy and Touch - * Policy. */ static gpg_error_t get_cached_data (app_t app, int tag, @@ -311,43 +306,7 @@ get_cached_data (app_t app, int tag, } } - if (app->app_local->flags.yubikey && (tag >> 8) == 0xF7) - /* Get policies from metadata for a key slot. */ - { - unsigned char apdu[4]; - - /* We use a proprietary Yubikey command to get metadata for KEYREF. */ - apdu[0] = 0; - apdu[1] = 0xf7; /* Yubikey: Get metadata. */ - apdu[2] = 0; - apdu[3] = (tag & 0xff); - err = iso7816_apdu_direct (app_get_slot (app), apdu, 4, 1, - NULL, &p, &len); - if (!err) - { - unsigned char *policies = NULL; - - s = find_tlv (p, len, YKPIV_METADATA_POLICY_TAG, &len); - if (s && len == 2) - { - policies = xtrymalloc (len); - if (!policies) - err = gpg_error_from_syserror (); - else - memcpy (policies, s, len); - } - xfree (p); - if (policies) - p = policies; - else - { - p = NULL; - len = 0; - } - } - } - else - err = iso7816_get_data_odd (app_get_slot (app), 0, tag, &p, &len); + err = iso7816_get_data_odd (app_get_slot (app), 0, tag, &p, &len); if (err) return err; @@ -356,8 +315,6 @@ get_cached_data (app_t app, int tag, * (SP 800-73-5 Part 2, section 3.1.2) */ if (tag == 0x7E || tag == 0x7F61) ; - else if (app->app_local->flags.yubikey && (tag >> 8) == 0xF7) - ; else if (len && *p == 0x53 && (s = find_tlv (p, len, 0x53, &n))) { memmove (p, s, n); @@ -2191,48 +2148,6 @@ do_check_chv (app_t app, ctrl_t ctrl, const char *pwidstr) } -/* Examining the per slot PIN policy for KEYREF, return 1 if the - * verification of PIN is always required. Return 0, otherwise. */ -static int -check_pin_policy (app_t app, int keyref) -{ - unsigned char *buffer; - size_t buflen; - gpg_error_t err; - int value; - int force; - - if (!app->app_local->flags.yubikey) - { - no_f7xx: - switch (keyref) - { - case 0x9c: force = 1; break; - default: force = 0; break; - } - return force; - } - - /* Use special tag F7xx to get PIN Policy and Touch Policy. */ - err = get_cached_data (app, ((0xf7 << 8) | keyref), &buffer, &buflen, 0); - if (err) - goto no_f7xx; - - if (buflen == 2) - value = buffer[0]; /* 0: Default, 1: Never, 2: Once, 3: Always */ - else - goto no_f7xx; - - switch (keyref) - { - case 0x9c: force = (value == 0 || value == 3); break; - default: force = (value == 3); break; - } - - xfree (buffer); - return force; -} - /* Compute a digital signature using the GENERAL AUTHENTICATE command * on INDATA which is expected to be the raw message digest. The * KEYIDSTR has the key reference or its OID (e.g. "PIV.9A"). The @@ -2261,7 +2176,6 @@ do_sign (app_t app, ctrl_t ctrl, const char *keyidstr, int hashalgo, unsigned char *indata_buffer = NULL; /* Malloced helper. */ unsigned char *apdudata = NULL; size_t apdudatalen; - int force_verify; (void)ctrl; @@ -2284,7 +2198,9 @@ do_sign (app_t app, ctrl_t ctrl, const char *keyidstr, int hashalgo, * for each key. It's user's control. * https://developers.yubico.com/PIV/Introduction/Yubico_extensions.html */ - force_verify = check_pin_policy (app, keyref); + /* Don't hardcode per-key PIN rules: let the card enforce its own + * policy (SP 800-73 "PIN Always", Yubico per-key policies, ...). + * We try the operation first and only VERIFY if the card refuses. */ err = get_key_algorithm_by_dobj (app, dobj, &mechanism); if (err) @@ -2446,11 +2362,6 @@ do_sign (app_t app, ctrl_t ctrl, const char *keyidstr, int hashalgo, goto leave; } - /* Now verify the Application PIN. */ - err = verify_chv (app, ctrl, 0x80, force_verify); - if (err) - goto leave; - /* Build the Dynamic Authentication Template. */ err = concat_tlv_list (0, &apdudata, &apdudatalen, (int)0x7c, (size_t)0, NULL, /* Constructed. */ @@ -2465,6 +2376,18 @@ do_sign (app_t app, ctrl_t ctrl, const char *keyidstr, int hashalgo, mechanism, keyref, apdudata, (int)apdudatalen, 0, &outdata, &outdatalen); + /* GPG_ERR_BAD_PIN (SW 6982 or 63Cx): the card wants a VERIFY first. + * Force it even if the PIN is already verified, because a "PIN + * Always" key needs a fresh one. Retry only once. */ + if (gpg_err_code (err) == GPG_ERR_BAD_PIN) + { + err = verify_chv (app, ctrl, 0x80, 1); + if (!err) + err = iso7816_general_authenticate (app_get_slot (app), -1, + mechanism, keyref, + apdudata, (int)apdudatalen, 0, + &outdata, &outdatalen); + } if (err) goto leave; -- 2.56.0 From reishoku at reishoku.net Wed Nov 4 01:00:38 2026 From: reishoku at reishoku.net (KOSHIKAWA Kenichi) Date: Wed, 4 Nov 2026 09:00:38 +0900 Subject: [gnupg] gpgv --output FILE leaves FILE.part (regression in 2.5.21) Message-ID: Hello, I could not open a task on dev.gnupg.org, so I am reporting this here. Since 2.5.21, "gpgv --output FILE" exits with 0 and reports a good signature, but FILE is never created. The data is left in FILE.part. "gpg --verify --output FILE" is not affected. Affected: 2.5.21 to 2.5.24, and master as of 5b001e5ccd62 Good: 2.5.20, 2.4.x (checked 2.4.4 and 2.4.7) Systems: Linux x86_64 (Ubuntu 24.04, built from git) macOS 27.0.1 arm64 (2.5.24 from Homebrew) Recipe (any gpg 2.x can create the key and the signature): mkdir -m 700 home gpg --homedir home --batch --pinentry-mode loopback --passphrase '' \ --quick-gen-key 'Test ' ed25519 sign never printf 'Hello\n' > data.txt gpg --homedir home --batch --clearsign -o signed.asc data.txt gpg --homedir home --batch --export > trusted.gpg gpgv --homedir home --keyring ./trusted.gpg --output out signed.asc ls out* Expected: out Actual: out.part Output of the gpgv steps with 2.5.24, built from the gnupg-2.5.24 tag on Linux x86_64 (the key and signature were made with gpg 2.4.4): $ gpgv --version | head -n 1 gpgv (GnuPG) 2.5.24 $ gpgv --homedir home --keyring ./trusted.gpg --output out signed.asc gpgv: Signature made Tue Nov 3 16:12:01 2026 UTC gpgv: using EDDSA key 200E09EBB8AD23B976698A94C71F7B4433288887 gpgv: Good signature from "Test " $ echo $? 0 $ ls out* out.part With master (2.5.25-beta34) the result is the same. With 2.5.20, "ls out*" shows "out", and its content is the signed text. git bisect between gnupg-2.5.20 and gnupg-2.5.24 gives ab2e64e4b490 gpg: Defer renaming at exit, so that it can remove on failure. (T7873) as the first bad commit. With it, pfg_close_file only registers the rename, and gnupg_commit_partial_file is called from g10_exit in g10/gpg.c. gpgv has its own g10_exit in g10/gpgv.c, which does not call it, so the .part file is never renamed. The later changes for T8399 and 31339d07 only touch the gpg side. Exit code when FILE cannot be created (FILE is an existing directory): 2.4.4, 2.5.20 2 "error creating 'out'" a9c9435c (2.5.21-beta15) 2 "renaming 'out.part' ... failed" 2.5.24, master 0 (FILE.part is left, as above) In g10/gpg.c, gnupg_commit_partial_file is called after the exit code is computed, so the log_error from a failed rename is not counted. "gpg --verify --output FILE" on master prints "renaming 'out.part' to 'out' failed" and exits with 0 in the same case. This looks like the same problem on the gpg side. When FILE already exists, gpgv 2.5.21 and later keep its old content and still exit with 0 and GOODSIG. A caller that passes a file created with mktemp, or that reuses an output path, may then read old data as verified. I leave it to you whether this needs more than a normal bug fix. The test suite did not catch this, because tests/openpgp/gpgv.scm does not use --output. I can test a fix on Linux and macOS. I used an AI assistant (Anthropic's Claude) for the bisect and the analysis, and to help write this report. I have checked the results above myself. Thanks, Kenichi -- KOSHIKAWA Kenichi reishoku at reishoku.net -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 265 bytes Desc: not available URL: From peijiankang at kylinos.cn Thu Nov 5 04:39:13 2026 From: peijiankang at kylinos.cn (=?UTF-8?B?6KO05bu65bq3?=) Date: Thu, 05 Nov 2026 11:39:13 +0800 Subject: =?UTF-8?B?W1BBVENIXSBwaW5lbnRyeS1lbWFjczogZml4IHRpbWVvdXQgcmFjZSBpbiByZWFkX2Zyb21fZW1hY3MgKENXRS0zNjIp?= Message-ID: <15sf6pup1j2j-15sk5dd3kmvg@nsmail8.2--kylin--1> An HTML attachment was scrubbed... URL: -------------- next part -------------- A non-text attachment was scrubbed... Name: 0001-fix-timeout-race-1.3.3.patch Type: application/octet-stream Size: 1808 bytes Desc: not available URL: From gniibe at fsij.org Thu Nov 5 06:16:52 2026 From: gniibe at fsij.org (NIIBE Yutaka) Date: Thu, 05 Nov 2026 14:16:52 +0900 Subject: [gnupg] gpgv --output FILE leaves FILE.part (regression in 2.5.21) In-Reply-To: References: Message-ID: <87cxsjamd7.fsf@haruna.fsij.org> Hello, Thank you for your report with repro. I didn't notice until today (sorry, I rarely use gpgv). KOSHIKAWA Kenichi wrote: > ab2e64e4b490 gpg: Defer renaming at exit, so that it can remove > on failure. (T7873) Ah, indeed. One liner could fix the issue: ========================== diff --git a/g10/gpgv.c b/g10/gpgv.c index 382720ef8..9790cae3b 100644 --- a/g10/gpgv.c +++ b/g10/gpgv.c @@ -322,6 +322,7 @@ g10_exit (int rc) else if (opt.assert_pubkey_algos && assert_pubkey_algo_false) rc = 1; + gnupg_commit_partial_file (); exit (rc); } ========================== I created a ticket for this: https://static.dev.gnupg.org/T8540.html -- From gniibe at fsij.org Thu Nov 5 06:26:01 2026 From: gniibe at fsij.org (NIIBE Yutaka) Date: Thu, 05 Nov 2026 14:26:01 +0900 Subject: [PATCH] pinentry-emacs: fix timeout race in read_from_emacs (CWE-362) In-Reply-To: <15sf6pup1j2j-15sk5dd3kmvg@nsmail8.2--kylin--1> References: <15sf6pup1j2j-15sk5dd3kmvg@nsmail8.2--kylin--1> Message-ID: <87a4nnalxy.fsf@haruna.fsij.org> Hello, Thank you for your report. pinentry-emacs is deprecated, it only existed in the pinentry source code repository until recently. It has been removed already from the repository. 裴建康 wrote: > Tested on openEuler 20.03 LTS-SP4 with its /usr/bin/pinentry-emacs > (pinentry 1.1.0). The patch is against pinentry-1.3.3 and also applies > to 1.1.0, 1.1.1 and 1.2.x. pinentry-emacs is for GnuPG 2.0 or older (with Emacs 25 or older). I wonder the reason why openEuler 20.03 includes pinentry-emacs. Which version of Emacs it has? Are you (or any users) using it? And in what situation? If any users with openEuler, I would suggest to build your pinentry-emacs with the patch. -- From gniibe at fsij.org Fri Nov 6 06:14:04 2026 From: gniibe at fsij.org (NIIBE Yutaka) Date: Fri, 06 Nov 2026 14:14:04 +0900 Subject: [PATCH gnupg] scd:piv: Let the card decide whether signing needs a PIN In-Reply-To: <20261103121726.2212590-1-soap@gentoo.org> References: <20261103121726.2212590-1-soap@gentoo.org> Message-ID: <87zevmsfs3.fsf@haruna.fsij.org> Hello, Thank you for your contribution. David Seifert wrote: > * scd/app-piv.c (YKPIV_METADATA_POLICY_TAG): Remove. > (get_cached_data): Remove support for special tag 0xF7xx. > (check_pin_policy): Remove. > (do_sign): Do not verify the PIN before signing. If GENERAL > AUTHENTICATE fails with GPG_ERR_BAD_PIN, force a verify and retry > once. Looks good. Please have a look at gnupg/doc/HACKING, specifically, the "License policy" section. And please consider sending your signed DCO. -- From soap at gentoo.org Fri Nov 6 10:03:14 2026 From: soap at gentoo.org (David Seifert) Date: Fri, 06 Nov 2026 10:03:14 +0100 Subject: DCO for David Seifert Message-ID: <6dec6090812be78fb6971ece854849c0e391fda2.camel@gentoo.org> GnuPG Developer's Certificate of Origin. Version 1.0 ===================================================== By making a contribution to the GnuPG project, I certify that: (a) The contribution was created in whole or in part by me and I have the right to submit it under the free software license indicated in the file; or (b) The contribution is based upon previous work that, to the best of my knowledge, is covered under an appropriate free software license and I have the right under that license to submit that work with modifications, whether created in whole or in part by me, under the same free software license (unless I am permitted to submit under a different license), as indicated in the file; or (c) The contribution was provided directly to me by some other person who certified (a), (b) or (c) and I have not modified it. (d) I understand and agree that this project and the contribution are public and that a record of the contribution (including all personal information I submit with it, including my sign-off) is maintained indefinitely and may be redistributed consistent with this project or the free software license(s) involved. Signed-off-by: David Seifert -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 1042 bytes Desc: This is a digitally signed message part URL: From soap at gentoo.org Fri Nov 6 10:05:26 2026 From: soap at gentoo.org (David Seifert) Date: Fri, 06 Nov 2026 10:05:26 +0100 Subject: [PATCH gnupg] scd:piv: Let the card decide whether signing needs a PIN In-Reply-To: <87zevmsfs3.fsf@haruna.fsij.org> References: <20261103121726.2212590-1-soap@gentoo.org> <87zevmsfs3.fsf@haruna.fsij.org> Message-ID: On Fri, 2026-11-06 at 14:14 +0900, NIIBE Yutaka wrote: > Hello, > > Thank you for your contribution. > > David Seifert wrote: > > * scd/app-piv.c (YKPIV_METADATA_POLICY_TAG): Remove. > > (get_cached_data): Remove support for special tag 0xF7xx. > > (check_pin_policy): Remove. > > (do_sign): Do not verify the PIN before signing. If GENERAL > > AUTHENTICATE fails with GPG_ERR_BAD_PIN, force a verify and retry > > once. > > Looks good. > > Please have a look at gnupg/doc/HACKING, specifically, the "License > policy" section.  And please consider sending your signed DCO. Hi Niibe, I just sent in the DCO, it likely got lost before I registered for gnupg-devel. Regards David From reishoku at reishoku.net Sat Nov 7 05:01:27 2026 From: reishoku at reishoku.net (KOSHIKAWA Kenichi) Date: Sat, 7 Nov 2026 13:01:27 +0900 Subject: [gnupg] gpgv --output FILE leaves FILE.part (regression in 2.5.21) In-Reply-To: <87cxsjamd7.fsf@haruna.fsij.org> References: <87cxsjamd7.fsf@haruna.fsij.org> Message-ID: Hello NIIBE-san, NIIBE Yutaka wrote: > One liner could fix the issue: [...] > I created a ticket for this: > > https://static.dev.gnupg.org/T8540.html Thank you for the fix and for pushing it (e10ce533). I tested master (a6aa02c0) on Linux x86_64: - The recipe from my report now creates "out" with the signed text, and no out.part is left. - A bad signature gives exit code 1, as in 2.4. - An existing "out" is now replaced with the verified data. - "make -C tests/openpgp check": 64 succeeded, 0 failed, 3 skipped. Outputs of the recipe described previously, as of a6aa02c0: $ git log -1 --format='%h %s' a6aa02c0 gpgsm: Use a separate source file also for KEM based encryption. $ git merge-base --is-ancestor e10ce533 a6aa02c0 && echo "e10ce533 is in a6aa02c0" e10ce533 is in a6aa02c0 $ gpgv --version | head -n 1 gpgv (GnuPG) 2.5.25-beta38 $ gpgv --homedir home --keyring ./trusted.gpg --output out signed.asc gpgv: Signature made Sat Nov 7 03:47:15 2026 UTC gpgv: using EDDSA key 81724F3A3B331D3DEB423ADFB70F62D0A395009F gpgv: Good signature from "Test " $ echo $? 0 $ ls out* out $ cat out Hello Expected: out Actual: out (previously: out.part) Thanks, Kenichi -- KOSHIKAWA Kenichi reishoku at reishoku.net On Thu, Nov 05, 2026 at 02:16:52PM +0900, NIIBE Yutaka wrote: > Hello, > > Thank you for your report with repro. I didn't notice until today > (sorry, I rarely use gpgv). > > KOSHIKAWA Kenichi wrote: > > ab2e64e4b490 gpg: Defer renaming at exit, so that it can remove > > on failure. (T7873) > > Ah, indeed. > > One liner could fix the issue: > ========================== > diff --git a/g10/gpgv.c b/g10/gpgv.c > index 382720ef8..9790cae3b 100644 > --- a/g10/gpgv.c > +++ b/g10/gpgv.c > @@ -322,6 +322,7 @@ g10_exit (int rc) > else if (opt.assert_pubkey_algos && assert_pubkey_algo_false) > rc = 1; > > + gnupg_commit_partial_file (); > exit (rc); > } > > ========================== > > I created a ticket for this: > > https://static.dev.gnupg.org/T8540.html > -- -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 265 bytes Desc: not available URL: