Bug#1134196: bouncycastle: proposed bullseye LTS fix for CVE-2026-5588
James Montgomery
james_montgomery at disroot.org
Mon Apr 20 03:04:33 BST 2026
Hi,
I prepared a candidate bullseye-security update for CVE-2026-5588:
bouncycastle 1.68-2+deb11u1.
Summary:
- backports upstream commit 656bae0dbd9b1521f840521ff786e78749fe3057
- adds a regression test for an empty composite signature sequence
- clean bullseye pbuilder build passed
- targeted runtime check against the built libbcprov/libbcpkix jars passed
- lintian reports only pre-existing doc-package embedded JavaScript warnings
- no autopkgtest exists for this source package
I am new to LTS contribution and not a DD, so I have not claimed
bouncycastle in dla-needed.txt or attempted any upload. I am planning to
ask debian-lts at lists.debian.org whether this is useful for review or
sponsorship.
The debdiff is attached.
Regards,
James
-------------- next part --------------
diff -Nru bouncycastle-1.68/debian/changelog bouncycastle-1.68/debian/changelog
--- bouncycastle-1.68/debian/changelog 2021-05-14 02:14:07.000000000 +0000
+++ bouncycastle-1.68/debian/changelog 2026-04-20 01:18:25.000000000 +0000
@@ -1,3 +1,10 @@
+bouncycastle (1.68-2+deb11u1) bullseye-security; urgency=medium
+
+ * Non-maintainer upload.
+ * Fix CVE-2026-5588: reject empty composite signature sequences.
+
+ -- James Montgomery <james_montgomery at disroot.org> Mon, 20 Apr 2026 01:18:25 +0000
+
bouncycastle (1.68-2) unstable; urgency=medium
* Team upload.
@@ -495,4 +502,3 @@
* Initial release (Closes: #234048)
-- Charles Fry <debian at frogcircus.org> Mon, 19 Sep 2005 08:02:36 -0400
-
diff -Nru bouncycastle-1.68/debian/patches/CVE-2026-5588.patch bouncycastle-1.68/debian/patches/CVE-2026-5588.patch
--- bouncycastle-1.68/debian/patches/CVE-2026-5588.patch 1970-01-01 00:00:00.000000000 +0000
+++ bouncycastle-1.68/debian/patches/CVE-2026-5588.patch 2026-04-20 01:13:49.000000000 +0000
@@ -0,0 +1,115 @@
+Description: reject empty composite signature sequences
+ CompositeVerifier accepted an empty ASN.1 sequence as a valid composite
+ signature because no component signature failed verification. Track whether
+ at least one component signature was checked and require that condition for
+ successful verification.
+Origin: upstream, https://github.com/bcgit/bc-java/commit/656bae0dbd9b1521f840521ff786e78749fe3057
+Bug-Debian: https://bugs.debian.org/1134196
+Applied-Upstream: 1.84, commit:656bae0dbd9b1521f840521ff786e78749fe3057
+
+--- bouncycastle-1.68.orig/pkix/src/main/java/org/bouncycastle/operator/jcajce/JcaContentVerifierProviderBuilder.java
++++ bouncycastle-1.68/pkix/src/main/java/org/bouncycastle/operator/jcajce/JcaContentVerifierProviderBuilder.java
+@@ -429,17 +429,19 @@ public class JcaContentVerifierProviderB
+ {
+ ASN1Sequence sigSeq = ASN1Sequence.getInstance(expected);
+ boolean failed = false;
++ boolean atLeastOneChecked = false;
+ for (int i = 0; i != sigSeq.size(); i++)
+ {
+ if (sigs[i] != null)
+ {
++ atLeastOneChecked = true;
+ if (!sigs[i].verify(DERBitString.getInstance(sigSeq.getObjectAt(i)).getBytes()))
+ {
+ failed = true;
+ }
+ }
+ }
+- return !failed;
++ return !failed & atLeastOneChecked;
+ }
+ catch (SignatureException e)
+ {
+@@ -447,4 +449,4 @@ public class JcaContentVerifierProviderB
+ }
+ }
+ }
+-}
+\ No newline at end of file
++}
+--- bouncycastle-1.68.orig/pkix/src/test/java/org/bouncycastle/cert/cmp/test/AllTests.java
++++ bouncycastle-1.68/pkix/src/test/java/org/bouncycastle/cert/cmp/test/AllTests.java
+@@ -17,6 +17,8 @@ import junit.framework.TestCase;
+ import junit.framework.TestSuite;
+ import org.bouncycastle.asn1.ASN1Integer;
+ import org.bouncycastle.asn1.ASN1Primitive;
++import org.bouncycastle.asn1.DERBitString;
++import org.bouncycastle.asn1.DERNull;
+ import org.bouncycastle.asn1.DERSequence;
+ import org.bouncycastle.asn1.cmp.CMPCertificate;
+ import org.bouncycastle.asn1.cmp.CertConfirmContent;
+@@ -25,6 +27,7 @@ import org.bouncycastle.asn1.cmp.CertRep
+ import org.bouncycastle.asn1.cmp.CertResponse;
+ import org.bouncycastle.asn1.cmp.CertifiedKeyPair;
+ import org.bouncycastle.asn1.cmp.PKIBody;
++import org.bouncycastle.asn1.cmp.PKIHeaderBuilder;
+ import org.bouncycastle.asn1.cmp.PKIMessage;
+ import org.bouncycastle.asn1.cmp.PKIStatus;
+ import org.bouncycastle.asn1.cmp.PKIStatusInfo;
+@@ -34,9 +37,12 @@ import org.bouncycastle.asn1.crmf.Encryp
+ import org.bouncycastle.asn1.crmf.EncryptedValue;
+ import org.bouncycastle.asn1.crmf.ProofOfPossession;
+ import org.bouncycastle.asn1.crmf.SubsequentMessage;
++import org.bouncycastle.asn1.misc.MiscObjectIdentifiers;
+ import org.bouncycastle.asn1.pkcs.EncryptedPrivateKeyInfo;
++import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+ import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
+ import org.bouncycastle.asn1.x500.X500Name;
++import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+ import org.bouncycastle.asn1.x509.GeneralName;
+ import org.bouncycastle.cert.CertException;
+ import org.bouncycastle.cert.X509CertificateHolder;
+@@ -330,6 +336,36 @@ public class AllTests
+ doNotBeforeNotAfterTest(kp, new Date(0L), null);
+ }
+
++ public void testForgedComposite()
++ throws Exception
++ {
++ KeyPairGenerator kGen = KeyPairGenerator.getInstance("RSA", BC);
++ kGen.initialize(2048);
++ KeyPair kp = kGen.generateKeyPair();
++
++ ContentVerifierProvider verifier =
++ new JcaContentVerifierProviderBuilder().build(kp.getPublic());
++
++ GeneralName sender = new GeneralName(new X500Name("CN=attacker"));
++ GeneralName recipient = new GeneralName(new X500Name("CN=victim"));
++ PKIBody body = new PKIBody(PKIBody.TYPE_CONFIRM, DERNull.INSTANCE);
++
++ AlgorithmIdentifier innerAlg = new AlgorithmIdentifier(
++ PKCSObjectIdentifiers.sha256WithRSAEncryption, DERNull.INSTANCE);
++ AlgorithmIdentifier compositeAlg = new AlgorithmIdentifier(
++ MiscObjectIdentifiers.id_alg_composite,
++ new DERSequence(innerAlg));
++
++ PKIHeaderBuilder headerBuilder = new PKIHeaderBuilder(2, sender, recipient);
++ headerBuilder.setProtectionAlg(compositeAlg);
++
++ DERBitString emptySigSeq = new DERBitString(new DERSequence().getEncoded());
++ PKIMessage forged = new PKIMessage(headerBuilder.build(), body, emptySigSeq);
++ ProtectedPKIMessage forgedPM = new ProtectedPKIMessage(new GeneralPKIMessage(forged));
++
++ assertFalse(forgedPM.verify(verifier));
++ }
++
+ private void doNotBeforeNotAfterTest(KeyPair kp, Date notBefore, Date notAfter)
+ throws Exception
+ {
+@@ -405,4 +441,4 @@ public class AllTests
+ throw new RuntimeException(e.toString());
+ }
+ }
+-}
+\ No newline at end of file
++}
diff -Nru bouncycastle-1.68/debian/patches/series bouncycastle-1.68/debian/patches/series
--- bouncycastle-1.68/debian/patches/series 2021-05-14 02:14:07.000000000 +0000
+++ bouncycastle-1.68/debian/patches/series 2026-04-20 01:13:25.000000000 +0000
@@ -1,3 +1,4 @@
02_index.patch
fix-encoding.patch
backward-compatibility.patch
+CVE-2026-5588.patch
More information about the pkg-java-maintainers
mailing list