Skip to content

Commit d4a9bb8

Browse files
committed
Merge branch 'bcpqc-signature-reinit' into 'main'
Discard the message buffered by the AIMer, FAEST, Falcon, HAETAE, MAYO, MQOM,... See merge request root/bc-java!332
2 parents c5b1323 + c864a96 commit d4a9bb8

27 files changed

Lines changed: 997 additions & 228 deletions

File tree

‎docs/releasenotes.md‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,9 @@ Date: 2026, TBD
9494

9595
- ITSExplicitCertificateBuilder chose the certificate's Signature CHOICE from the VerificationKeyIndicator CHOICE rather than from the signing key's curve, so brainpoolP256r1 signatures were labelled as NIST P-256 and rejected by BC's own verifier, brainpoolP384r1 keys could not sign a certificate at all, and a P-256 signature under an implicit issuer was labelled as brainpoolP256r1. The signature type is now taken from the content signer's curve (github PR #2463).
9696

97+
- The Signature implementations for AIMer, FAEST, HAETAE, MAYO, MQOM, QR-UOV, SDitH, SNOVA and SQIsign in the BCPQC provider, and for Falcon in both the BC and BCPQC providers, kept the message bytes passed to update() across a re-initialisation: initSign and initVerify left in place the data buffered for the operation they ended, and sign() or verify() then took it as the start of the next message. A Signature initialised again before completing an operation, or switched between signing and verifying, therefore signed the abandoned bytes followed by the new message, or rejected a valid signature. The buffer is now discarded at the start of every initSign and initVerify, before the key is checked, so a re-initialisation ends the message in progress even when it refuses the key. UOV in the BCPQC provider already discarded the buffer, but only after accepting the new key, so following an initSign or initVerify that refused its key the Signature, still in its previous mode, signed or verified the earlier bytes followed by the new ones; it now discards the buffer at the start as well.
98+
- The Signature implementations for AIMer, FAEST, HAETAE, MAYO, MQOM, QR-UOV, SDitH, SNOVA and UOV in the BCPQC provider discarded the underlying exception when initVerify refused a public key it could not decode, and those implementations, together with Falcon in the BC and BCPQC providers and SPHINCS-256, did the same when sign() failed, keeping only its text in the InvalidKeyException or SignatureException they threw. The SMAUG-T Cipher in the BCPQC provider did the same when wrap() or unwrap() failed, in the IllegalBlockSizeException, InvalidKeyException or NoSuchAlgorithmException it threw, where the other KEM Ciphers already kept the cause. The original exception is now attached as the cause through the SecurityExceptions factories, so callers can walk getCause(); exception types and message texts are unchanged.
99+
97100
### 2.1.3 Additional Features and Functionality
98101

99102
- The CRMF certificate request message controls now include the RFC 4211 sec. 6.6 protocolEncrKey control, which names the key a CA is to encrypt its response with: org.bouncycastle.cert.crmf.ProtocolEncrKeyControl carries the SubjectPublicKeyInfo the control is defined to take, and CertificateRequestMessage.getControl() recognises id-regCtrl-protocolEncrKey alongside the regToken, authenticator and pkiArchiveOptions controls it already returned (github PR #2443).

‎prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/aimer/SignatureSpi.java‎

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
1212
import org.bouncycastle.crypto.CipherParameters;
1313
import org.bouncycastle.crypto.params.ParametersWithRandom;
14+
import org.bouncycastle.jcajce.provider.util.SecurityExceptions;
1415
import org.bouncycastle.pqc.crypto.aimer.AIMerParameters;
1516
import org.bouncycastle.pqc.crypto.aimer.AIMerSigner;
1617
import org.bouncycastle.util.Strings;
@@ -44,6 +45,8 @@ protected SignatureSpi(AIMerSigner signer, AIMerParameters parameters)
4445
protected void engineInitVerify(PublicKey publicKey)
4546
throws InvalidKeyException
4647
{
48+
bOut.reset();
49+
4750
if (!(publicKey instanceof BCAIMerPublicKey))
4851
{
4952
try
@@ -52,7 +55,7 @@ protected void engineInitVerify(PublicKey publicKey)
5255
}
5356
catch (Exception e)
5457
{
55-
throw new InvalidKeyException("unknown public key passed to AIMer: " + e.getMessage());
58+
throw SecurityExceptions.invalidKeyException("unknown public key passed to AIMer: " + e.getMessage(), e);
5659
}
5760
}
5861

@@ -80,6 +83,8 @@ protected void engineInitSign(PrivateKey privateKey, SecureRandom random)
8083
protected void engineInitSign(PrivateKey privateKey)
8184
throws InvalidKeyException
8285
{
86+
bOut.reset();
87+
8388
if (privateKey instanceof BCAIMerPrivateKey)
8489
{
8590
BCAIMerPrivateKey key = (BCAIMerPrivateKey)privateKey;
@@ -134,7 +139,7 @@ protected byte[] engineSign()
134139
}
135140
catch (Exception e)
136141
{
137-
throw new SignatureException(e.toString());
142+
throw SecurityExceptions.signatureException(e.toString(), e);
138143
}
139144
}
140145

‎prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/faest/SignatureSpi.java‎

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
1212
import org.bouncycastle.crypto.CipherParameters;
1313
import org.bouncycastle.crypto.params.ParametersWithRandom;
14+
import org.bouncycastle.jcajce.provider.util.SecurityExceptions;
1415
import org.bouncycastle.pqc.crypto.faest.FaestParameters;
1516
import org.bouncycastle.pqc.crypto.faest.FaestSigner;
1617
import org.bouncycastle.util.Strings;
@@ -44,6 +45,8 @@ protected SignatureSpi(FaestSigner signer, FaestParameters parameters)
4445
protected void engineInitVerify(PublicKey publicKey)
4546
throws InvalidKeyException
4647
{
48+
bOut.reset();
49+
4750
if (!(publicKey instanceof BCFaestPublicKey))
4851
{
4952
try
@@ -52,7 +55,7 @@ protected void engineInitVerify(PublicKey publicKey)
5255
}
5356
catch (Exception e)
5457
{
55-
throw new InvalidKeyException("unknown public key passed to Faest: " + e.getMessage());
58+
throw SecurityExceptions.invalidKeyException("unknown public key passed to Faest: " + e.getMessage(), e);
5659
}
5760
}
5861

@@ -80,6 +83,8 @@ protected void engineInitSign(PrivateKey privateKey, SecureRandom random)
8083
protected void engineInitSign(PrivateKey privateKey)
8184
throws InvalidKeyException
8285
{
86+
bOut.reset();
87+
8388
if (privateKey instanceof BCFaestPrivateKey)
8489
{
8590
BCFaestPrivateKey key = (BCFaestPrivateKey)privateKey;
@@ -134,7 +139,7 @@ protected byte[] engineSign()
134139
}
135140
catch (Exception e)
136141
{
137-
throw new SignatureException(e.toString());
142+
throw SecurityExceptions.signatureException(e.toString(), e);
138143
}
139144
}
140145

‎prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/falcon/SignatureSpi.java‎

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,8 @@ protected SignatureSpi(FalconSigner signer, FalconParameters parameters)
4848
protected void engineInitVerify(PublicKey publicKey)
4949
throws InvalidKeyException
5050
{
51+
bOut.reset();
52+
5153
if (!(publicKey instanceof BCFalconPublicKey))
5254
{
5355
try
@@ -84,6 +86,8 @@ protected void engineInitSign(PrivateKey privateKey, SecureRandom random)
8486
protected void engineInitSign(PrivateKey privateKey)
8587
throws InvalidKeyException
8688
{
89+
bOut.reset();
90+
8791
if (privateKey instanceof BCFalconPrivateKey)
8892
{
8993
BCFalconPrivateKey key = (BCFalconPrivateKey)privateKey;
@@ -138,7 +142,7 @@ protected byte[] engineSign()
138142
}
139143
catch (Exception e)
140144
{
141-
throw new SignatureException(e.toString());
145+
throw SecurityExceptions.signatureException(e.toString(), e);
142146
}
143147
}
144148

‎prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/haetae/SignatureSpi.java‎

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
1212
import org.bouncycastle.crypto.CipherParameters;
1313
import org.bouncycastle.crypto.params.ParametersWithRandom;
14+
import org.bouncycastle.jcajce.provider.util.SecurityExceptions;
1415
import org.bouncycastle.pqc.crypto.haetae.HAETAEParameters;
1516
import org.bouncycastle.pqc.crypto.haetae.HAETAESigner;
1617
import org.bouncycastle.util.Strings;
@@ -53,6 +54,8 @@ protected SignatureSpi(HAETAESigner signer, HAETAEParameters parameters)
5354
protected void engineInitVerify(PublicKey publicKey)
5455
throws InvalidKeyException
5556
{
57+
bOut.reset();
58+
5659
if (!(publicKey instanceof BCHaetaePublicKey))
5760
{
5861
try
@@ -61,7 +64,7 @@ protected void engineInitVerify(PublicKey publicKey)
6164
}
6265
catch (Exception e)
6366
{
64-
throw new InvalidKeyException("unknown public key passed to Haetae: " + e.getMessage());
67+
throw SecurityExceptions.invalidKeyException("unknown public key passed to Haetae: " + e.getMessage(), e);
6568
}
6669
}
6770

@@ -89,6 +92,8 @@ protected void engineInitSign(PrivateKey privateKey, SecureRandom random)
8992
protected void engineInitSign(PrivateKey privateKey)
9093
throws InvalidKeyException
9194
{
95+
bOut.reset();
96+
9297
if (privateKey instanceof BCHaetaePrivateKey)
9398
{
9499
BCHaetaePrivateKey key = (BCHaetaePrivateKey)privateKey;
@@ -143,7 +148,7 @@ protected byte[] engineSign()
143148
}
144149
catch (Exception e)
145150
{
146-
throw new SignatureException(e.toString());
151+
throw SecurityExceptions.signatureException(e.toString(), e);
147152
}
148153
}
149154

‎prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mayo/SignatureSpi.java‎

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
1212
import org.bouncycastle.crypto.CipherParameters;
1313
import org.bouncycastle.crypto.params.ParametersWithRandom;
14+
import org.bouncycastle.jcajce.provider.util.SecurityExceptions;
1415
import org.bouncycastle.pqc.crypto.mayo.MayoParameters;
1516
import org.bouncycastle.pqc.crypto.mayo.MayoSigner;
1617
import org.bouncycastle.util.Strings;
@@ -44,6 +45,8 @@ protected SignatureSpi(MayoSigner signer, MayoParameters parameters)
4445
protected void engineInitVerify(PublicKey publicKey)
4546
throws InvalidKeyException
4647
{
48+
bOut.reset();
49+
4750
if (!(publicKey instanceof BCMayoPublicKey))
4851
{
4952
try
@@ -52,7 +55,7 @@ protected void engineInitVerify(PublicKey publicKey)
5255
}
5356
catch (Exception e)
5457
{
55-
throw new InvalidKeyException("unknown public key passed to Mayo: " + e.getMessage());
58+
throw SecurityExceptions.invalidKeyException("unknown public key passed to Mayo: " + e.getMessage(), e);
5659
}
5760
}
5861

@@ -80,6 +83,8 @@ protected void engineInitSign(PrivateKey privateKey, SecureRandom random)
8083
protected void engineInitSign(PrivateKey privateKey)
8184
throws InvalidKeyException
8285
{
86+
bOut.reset();
87+
8388
if (privateKey instanceof BCMayoPrivateKey)
8489
{
8590
BCMayoPrivateKey key = (BCMayoPrivateKey)privateKey;
@@ -134,7 +139,7 @@ protected byte[] engineSign()
134139
}
135140
catch (Exception e)
136141
{
137-
throw new SignatureException(e.toString());
142+
throw SecurityExceptions.signatureException(e.toString(), e);
138143
}
139144
}
140145

‎prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mqom/SignatureSpi.java‎

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
1212
import org.bouncycastle.crypto.CipherParameters;
1313
import org.bouncycastle.crypto.params.ParametersWithRandom;
14+
import org.bouncycastle.jcajce.provider.util.SecurityExceptions;
1415
import org.bouncycastle.pqc.crypto.mqom.MQOMParameters;
1516
import org.bouncycastle.pqc.crypto.mqom.MQOMSigner;
1617
import org.bouncycastle.util.Strings;
@@ -42,6 +43,8 @@ protected SignatureSpi(MQOMSigner signer, MQOMParameters parameters)
4243
protected void engineInitVerify(PublicKey publicKey)
4344
throws InvalidKeyException
4445
{
46+
bOut.reset();
47+
4548
if (!(publicKey instanceof BCMQOMPublicKey))
4649
{
4750
try
@@ -50,7 +53,7 @@ protected void engineInitVerify(PublicKey publicKey)
5053
}
5154
catch (Exception e)
5255
{
53-
throw new InvalidKeyException("unknown public key passed to MQOM: " + e.getMessage());
56+
throw SecurityExceptions.invalidKeyException("unknown public key passed to MQOM: " + e.getMessage(), e);
5457
}
5558
}
5659

@@ -78,6 +81,8 @@ protected void engineInitSign(PrivateKey privateKey, SecureRandom random)
7881
protected void engineInitSign(PrivateKey privateKey)
7982
throws InvalidKeyException
8083
{
84+
bOut.reset();
85+
8186
if (privateKey instanceof BCMQOMPrivateKey)
8287
{
8388
BCMQOMPrivateKey key = (BCMQOMPrivateKey) privateKey;
@@ -130,7 +135,7 @@ protected byte[] engineSign()
130135
}
131136
catch (Exception e)
132137
{
133-
throw new SignatureException(e.toString());
138+
throw SecurityExceptions.signatureException(e.toString(), e);
134139
}
135140
}
136141

‎prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/qruov/SignatureSpi.java‎

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
1212
import org.bouncycastle.crypto.CipherParameters;
1313
import org.bouncycastle.crypto.params.ParametersWithRandom;
14+
import org.bouncycastle.jcajce.provider.util.SecurityExceptions;
1415
import org.bouncycastle.pqc.crypto.qruov.QRUOVParameters;
1516
import org.bouncycastle.pqc.crypto.qruov.QRUOVSigner;
1617
import org.bouncycastle.util.Strings;
@@ -49,6 +50,8 @@ private static String canonicalName(QRUOVParameters parameters)
4950
protected void engineInitVerify(PublicKey publicKey)
5051
throws InvalidKeyException
5152
{
53+
bOut.reset();
54+
5255
if (!(publicKey instanceof BCQRUOVPublicKey))
5356
{
5457
try
@@ -57,7 +60,7 @@ protected void engineInitVerify(PublicKey publicKey)
5760
}
5861
catch (Exception e)
5962
{
60-
throw new InvalidKeyException("unknown public key passed to QRUOV: " + e.getMessage());
63+
throw SecurityExceptions.invalidKeyException("unknown public key passed to QRUOV: " + e.getMessage(), e);
6164
}
6265
}
6366

@@ -85,6 +88,8 @@ protected void engineInitSign(PrivateKey privateKey, SecureRandom random)
8588
protected void engineInitSign(PrivateKey privateKey)
8689
throws InvalidKeyException
8790
{
91+
bOut.reset();
92+
8893
if (privateKey instanceof BCQRUOVPrivateKey)
8994
{
9095
BCQRUOVPrivateKey key = (BCQRUOVPrivateKey)privateKey;
@@ -137,7 +142,7 @@ protected byte[] engineSign()
137142
}
138143
catch (Exception e)
139144
{
140-
throw new SignatureException(e.toString());
145+
throw SecurityExceptions.signatureException(e.toString(), e);
141146
}
142147
}
143148

‎prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/sdith/SignatureSpi.java‎

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
1212
import org.bouncycastle.crypto.CipherParameters;
1313
import org.bouncycastle.crypto.params.ParametersWithRandom;
14+
import org.bouncycastle.jcajce.provider.util.SecurityExceptions;
1415
import org.bouncycastle.pqc.crypto.sdith.SDitHParameters;
1516
import org.bouncycastle.pqc.crypto.sdith.SDitHSigner;
1617
import org.bouncycastle.util.Strings;
@@ -44,6 +45,8 @@ protected SignatureSpi(SDitHSigner signer, SDitHParameters parameters)
4445
protected void engineInitVerify(PublicKey publicKey)
4546
throws InvalidKeyException
4647
{
48+
bOut.reset();
49+
4750
if (!(publicKey instanceof BCSDitHPublicKey))
4851
{
4952
try
@@ -52,7 +55,7 @@ protected void engineInitVerify(PublicKey publicKey)
5255
}
5356
catch (Exception e)
5457
{
55-
throw new InvalidKeyException("unknown public key passed to SDitH: " + e.getMessage());
58+
throw SecurityExceptions.invalidKeyException("unknown public key passed to SDitH: " + e.getMessage(), e);
5659
}
5760
}
5861

@@ -80,6 +83,8 @@ protected void engineInitSign(PrivateKey privateKey, SecureRandom random)
8083
protected void engineInitSign(PrivateKey privateKey)
8184
throws InvalidKeyException
8285
{
86+
bOut.reset();
87+
8388
if (privateKey instanceof BCSDitHPrivateKey)
8489
{
8590
BCSDitHPrivateKey key = (BCSDitHPrivateKey) privateKey;
@@ -132,7 +137,7 @@ protected byte[] engineSign()
132137
}
133138
catch (Exception e)
134139
{
135-
throw new SignatureException(e.toString());
140+
throw SecurityExceptions.signatureException(e.toString(), e);
136141
}
137142
}
138143

‎prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/smaugt/SmaugTCipherSpi.java‎

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import org.bouncycastle.crypto.Wrapper;
2626
import org.bouncycastle.crypto.params.KeyParameter;
2727
import org.bouncycastle.jcajce.provider.asymmetric.util.WrapUtil;
28+
import org.bouncycastle.jcajce.provider.util.SecurityExceptions;
2829
import org.bouncycastle.jcajce.spec.KEMParameterSpec;
2930
import org.bouncycastle.jcajce.spec.KTSParameterSpec;
3031
import org.bouncycastle.pqc.crypto.smaugt.SmaugTKEMExtractor;
@@ -267,11 +268,11 @@ protected byte[] engineWrap(
267268
}
268269
catch (IllegalArgumentException e)
269270
{
270-
throw new IllegalBlockSizeException("unable to generate KTS secret: " + e.getMessage());
271+
throw SecurityExceptions.illegalBlockSizeException("unable to generate KTS secret: " + e.getMessage(), e);
271272
}
272273
catch (DestroyFailedException e)
273274
{
274-
throw new IllegalBlockSizeException("unable to destroy interim values: " + e.getMessage());
275+
throw SecurityExceptions.illegalBlockSizeException("unable to destroy interim values: " + e.getMessage(), e);
275276
}
276277
}
277278

@@ -309,11 +310,11 @@ protected Key engineUnwrap(
309310
}
310311
catch (IllegalArgumentException e)
311312
{
312-
throw new NoSuchAlgorithmException("unable to extract KTS secret: " + e.getMessage());
313+
throw SecurityExceptions.noSuchAlgorithmException("unable to extract KTS secret: " + e.getMessage(), e);
313314
}
314315
catch (InvalidCipherTextException e)
315316
{
316-
throw new InvalidKeyException("unable to extract KTS secret: " + e.getMessage());
317+
throw SecurityExceptions.invalidKeyException("unable to extract KTS secret: " + e.getMessage(), e);
317318
}
318319
}
319320

0 commit comments

Comments
 (0)