From 70e68f1fb04ee44d948a384f8815821f086eac68 Mon Sep 17 00:00:00 2001 From: Paul Schaub Date: Wed, 17 Dec 2025 13:42:05 +0100 Subject: [PATCH] OpenPGPCertificate: Fix getCertification(date) accidentally returning non-self-sig --- .../openpgp/api/OpenPGPCertificate.java | 28 +++++++++++----- .../api/test/OpenPGPCertificateTest.java | 32 +++++++++++++++++++ 2 files changed, 52 insertions(+), 8 deletions(-) diff --git a/pg/src/main/java/org/bouncycastle/openpgp/api/OpenPGPCertificate.java b/pg/src/main/java/org/bouncycastle/openpgp/api/OpenPGPCertificate.java index 267cfd72ce..c1aa953556 100644 --- a/pg/src/main/java/org/bouncycastle/openpgp/api/OpenPGPCertificate.java +++ b/pg/src/main/java/org/bouncycastle/openpgp/api/OpenPGPCertificate.java @@ -1227,14 +1227,16 @@ public OpenPGPSignatureChains getSignatureChains() } /** - * Return the (at evaluation time) latest certification signature binding this component. + * Return the (at evaluation time) latest self certification signature binding this component. * * @param evaluationTime reference time * @return latest component certification signature */ public OpenPGPComponentSignature getCertification(Date evaluationTime) { - OpenPGPSignatureChain certification = getSignatureChains().getCertificationAt(evaluationTime); + OpenPGPSignatureChain certification = getSignatureChains() + .fromOrigin(getCertificate().getPrimaryKey()) + .getCertificationAt(evaluationTime); if (certification != null) { return certification.getSignature(); @@ -1243,14 +1245,16 @@ public OpenPGPComponentSignature getCertification(Date evaluationTime) } /** - * Return the (at evaluation time) latest revocation signature revoking this component. + * Return the (at evaluation time) latest self revocation signature revoking this component. * * @param evaluationTime reference time * @return latest component revocation signature */ public OpenPGPComponentSignature getRevocation(Date evaluationTime) { - OpenPGPSignatureChain revocation = getSignatureChains().getRevocationAt(evaluationTime); + OpenPGPSignatureChain revocation = getSignatureChains() + .fromOrigin(getCertificate().getPrimaryKey()) + .getRevocationAt(evaluationTime); if (revocation != null) { return revocation.getSignature(); @@ -2113,7 +2117,9 @@ public Date getCreationTime() @Override public OpenPGPComponentSignature getLatestSelfSignature(Date evaluationTime) { - OpenPGPSignatureChain currentDKChain = getSignatureChains().getChainAt(evaluationTime); + OpenPGPSignatureChain currentDKChain = getSignatureChains() + .fromOrigin(getCertificate().getPrimaryKey()) + .getChainAt(evaluationTime); if (currentDKChain != null && !currentDKChain.chainLinks.isEmpty()) { return currentDKChain.getSignature(); @@ -2299,7 +2305,9 @@ public OpenPGPComponentSignature getLatestDirectKeySelfSignature() */ public OpenPGPComponentSignature getLatestDirectKeySelfSignature(Date evaluationTime) { - OpenPGPSignatureChain currentDKChain = getCertificate().getAllSignatureChainsFor(this) + OpenPGPSignatureChain currentDKChain = getCertificate() + .getAllSignatureChainsFor(this) + .fromOrigin(this) .getCertificationAt(evaluationTime); if (currentDKChain != null && !currentDKChain.chainLinks.isEmpty()) { @@ -2327,7 +2335,9 @@ public OpenPGPComponentSignature getLatestKeyRevocationSelfSignature() */ public OpenPGPComponentSignature getLatestKeyRevocationSelfSignature(Date evaluationTime) { - OpenPGPSignatureChain currentRevocationChain = getCertificate().getAllSignatureChainsFor(this) + OpenPGPSignatureChain currentRevocationChain = getCertificate() + .getAllSignatureChainsFor(this) + .fromOrigin(this) .getRevocationAt(evaluationTime); if (currentRevocationChain != null && !currentRevocationChain.chainLinks.isEmpty()) { @@ -2676,7 +2686,9 @@ public OpenPGPPrimaryKey getPrimaryKey() @Override public OpenPGPComponentSignature getLatestSelfSignature(Date evaluationTime) { - OpenPGPSignatureChain currentChain = getSignatureChains().getChainAt(evaluationTime); + OpenPGPSignatureChain currentChain = getSignatureChains() + .fromOrigin(getPrimaryKey()) + .getChainAt(evaluationTime); if (currentChain != null && !currentChain.chainLinks.isEmpty()) { return currentChain.getSignature(); diff --git a/pg/src/test/java/org/bouncycastle/openpgp/api/test/OpenPGPCertificateTest.java b/pg/src/test/java/org/bouncycastle/openpgp/api/test/OpenPGPCertificateTest.java index 7fbd93f5a2..eef448e15e 100644 --- a/pg/src/test/java/org/bouncycastle/openpgp/api/test/OpenPGPCertificateTest.java +++ b/pg/src/test/java/org/bouncycastle/openpgp/api/test/OpenPGPCertificateTest.java @@ -15,6 +15,7 @@ import org.bouncycastle.openpgp.PGPException; import org.bouncycastle.openpgp.PGPObjectFactory; import org.bouncycastle.openpgp.PGPSignature; +import org.bouncycastle.openpgp.PGPSignatureException; import org.bouncycastle.openpgp.PGPSignatureList; import org.bouncycastle.openpgp.PGPSignatureSubpacketGenerator; import org.bouncycastle.openpgp.api.OpenPGPApi; @@ -49,6 +50,8 @@ protected void performTestWith(OpenPGPApi api) testSKSignsPKRevokedNoSubpacket(api); testPKSignsPKRevocationSuperseded(api); testGetPrimaryUserId(api); + + testIgnoreThirdPartySigsForSelfSigs(api); } private void testOpenPGPv6Key(OpenPGPApi api) @@ -879,6 +882,35 @@ public String getMsg() } } + private void testIgnoreThirdPartySigsForSelfSigs(OpenPGPApi api) + throws IOException, PGPSignatureException + { + String certWith3rdPartyUIDSig = "-----BEGIN PGP PUBLIC KEY BLOCK-----\n" + + "Comment: 2933 CBF1 9C19 5FEC C3D8 F6BB 7875 DF0D 34D8 0659\n" + + "Comment: Alice\n" + + "\n" + + "mCYEaUKQbBvoc5joeGZFjSjl2LoEuEfTn4dzNPkF68PUTROte/Yn2LQFQWxpY2XC\n" + + "cQQTGwoAHRahBCkzy/GcGV/sw9j2u3h13w002AZZBYJpQpBsAAoJEHh13w002AZZ\n" + + "XM1wwAo+gEchltvtokJUM2alG9z/iCOzBVs7WONrPo5rDJb+RRXXhVz+Mw1lYGWo\n" + + "USe86sZiTnjThA+Ech7JZdoHwnUEEBYKACcFgmlCnn0JEG2VRHjfrsFLFqEE2gJf\n" + + "vjCRGba1de0nbZVEeN+uwUsAAM3RAP0fEo5u5CdRg849xsNYAPv1oHT03el6LyGc\n" + + "Bk44oz7INgD/cFTufapwXJJB5IRX+lJA84w++6Xg0SS9h9TBmQBMiw24JgRpQpBs\n" + + "GyB6+bOfuk3Xaqlv2y9W08EiasmbznRLVaPhlLYTdNzCwsAnBBgbCgCTFqEEKTPL\n" + + "8ZwZX+zD2Pa7eHXfDTTYBlkFgmlCkGwCmwJyoAQZGwoAHRahBB7oLGA9/n/GLv02\n" + + "vM2YyJHfn7e+BYJpQpBsAAoJEM2YyJHfn7e+b0/C2Cv/ujgLxz3TOGi5rTFW7LQ+\n" + + "8vxC25T7ryBmnXaBdZvv0dBvOXy7MpSzRIrgxJQQWpoDNLHFZKosEGYCCUwKAAoJ\n" + + "EHh13w002AZZLI0VnHaOFQRwf+6BCOD/+0d9JhYAOh6nP24pAc0kTeZ7UHZusysk\n" + + "SfhI5KGG2gFUEJlItnagBCsIzxV0GwFoLSwAuCYEaUKQbBnAZbXB6dCd6LT+HeS6\n" + + "1Js5qhp7S+GPhFW4MfGeCBU/F8J0BBgbCgAgFqEEKTPL8ZwZX+zD2Pa7eHXfDTTY\n" + + "BlkFgmlCkGwCmwwACgkQeHXfDTTYBllHw49G2YdupzV1pu1qk4KXgDtsVQumEthi\n" + + "fOXKC8sGfUZASw5bPNFMcWfT/nFrzmuvi01DD+pfUo9a8GoRAZ6qSQ0=\n" + + "=oG2x\n" + + "-----END PGP PUBLIC KEY BLOCK-----"; + + OpenPGPCertificate cert = api.readKeyOrCertificate().parseCertificate(certWith3rdPartyUIDSig); + cert.getUserId("Alice").getCertification(new Date()).verify(api.getImplementation()); + } + public static void main(String[] args) { runTest(new OpenPGPCertificateTest());