This is an automated email from the ASF dual-hosted git repository.
Croway pushed a commit to branch camel-4.18.x
in repository https://gitbox.apache.org/repos/asf/camel.git
The following commit(s) were added to refs/heads/camel-4.18.x by this push:
new 1466b0fdf5a6 CAMEL-24445: camel-pqc - use a per-exchange Signature
instance
1466b0fdf5a6 is described below
commit 1466b0fdf5a6e9a8fd859893f9b245218f30ea17
Author: Andrea Cosentino <[email protected]>
AuthorDate: Fri Aug 28 06:35:36 2026 +0200
CAMEL-24445: camel-pqc - use a per-exchange Signature instance
PQCProducer held a single Signature and called initSign/update/sign on it
from
every exchange. java.security.Signature is stateful and not thread safe, so
concurrent exchanges on the same producer interleaved on one instance.
Backport of #25825. camel-pqc has diverged considerably between main and
this
branch (214 lines here against main's much larger producer), so the
cherry-pick
did not apply and the equivalent change is written directly against this
branch's code: remember the algorithm and provider when the producer creates
the Signature, build a fresh one per exchange, and fall back to sharing
under
synchronization when the user configured the instance.
Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
---
.../apache/camel/component/pqc/PQCProducer.java | 50 ++++++++++++++++------
1 file changed, 37 insertions(+), 13 deletions(-)
diff --git
a/components/camel-pqc/src/main/java/org/apache/camel/component/pqc/PQCProducer.java
b/components/camel-pqc/src/main/java/org/apache/camel/component/pqc/PQCProducer.java
index df67f451af21..1e16d1df6987 100644
---
a/components/camel-pqc/src/main/java/org/apache/camel/component/pqc/PQCProducer.java
+++
b/components/camel-pqc/src/main/java/org/apache/camel/component/pqc/PQCProducer.java
@@ -39,6 +39,10 @@ import org.bouncycastle.jcajce.spec.KEMGenerateSpec;
public class PQCProducer extends DefaultProducer {
private Signature signer;
+ // Set only when this producer created the Signature itself, so it knows
how to create another one.
+ // Left null when the user configured an instance, which then has to be
shared and locked instead.
+ private String signerAlgorithm;
+ private String signerProvider;
private KeyGenerator keyGenerator;
private KeyPair keyPair;
@@ -96,7 +100,9 @@ public class PQCProducer extends DefaultProducer {
if (ObjectHelper.isEmpty(signer)) {
PQCSignatureAlgorithms sigAlg =
PQCSignatureAlgorithms.valueOf(getConfiguration().getSignatureAlgorithm());
- signer = Signature.getInstance(sigAlg.getAlgorithm(),
sigAlg.getBcProvider());
+ signerAlgorithm = sigAlg.getAlgorithm();
+ signerProvider = sigAlg.getBcProvider();
+ signer = Signature.getInstance(signerAlgorithm,
signerProvider);
}
}
@@ -126,27 +132,45 @@ public class PQCProducer extends DefaultProducer {
}
private void signature(Exchange exchange)
- throws InvalidPayloadException, InvalidKeyException,
SignatureException {
+ throws InvalidPayloadException, InvalidKeyException,
SignatureException, NoSuchAlgorithmException,
+ NoSuchProviderException {
String payload = exchange.getMessage().getMandatoryBody(String.class);
- signer.initSign(keyPair.getPrivate());
- signer.update(payload.getBytes(StandardCharsets.UTF_8));
-
- byte[] signature = signer.sign();
+ Signature signerForExchange = signerForExchange();
+ byte[] signature;
+ synchronized (signerForExchange) {
+ signerForExchange.initSign(keyPair.getPrivate());
+ signerForExchange.update(payload.getBytes(StandardCharsets.UTF_8));
+ signature = signerForExchange.sign();
+ }
exchange.getMessage().setHeader(PQCConstants.SIGNATURE, signature);
}
+ /**
+ * java.security.Signature is stateful and not thread safe, so a single
instance cannot serve concurrent exchanges.
+ * A signer this producer created is rebuilt per exchange; one the user
configured cannot be recreated, so it is
+ * shared and the caller locks on it.
+ */
+ private Signature signerForExchange() throws NoSuchAlgorithmException,
NoSuchProviderException {
+ if (signerAlgorithm == null) {
+ return signer;
+ }
+ return Signature.getInstance(signerAlgorithm, signerProvider);
+ }
+
private void verification(Exchange exchange)
- throws InvalidPayloadException, InvalidKeyException,
SignatureException {
+ throws InvalidPayloadException, InvalidKeyException,
SignatureException, NoSuchAlgorithmException,
+ NoSuchProviderException {
String payload = exchange.getMessage().getMandatoryBody(String.class);
- signer.initVerify(keyPair.getPublic());
- signer.update(payload.getBytes(StandardCharsets.UTF_8));
- if
(signer.verify(exchange.getMessage().getHeader(PQCConstants.SIGNATURE,
byte[].class))) {
- exchange.getMessage().setHeader(PQCConstants.VERIFY, true);
- } else {
- exchange.getMessage().setHeader(PQCConstants.VERIFY, false);
+ Signature signerForExchange = signerForExchange();
+ boolean verified;
+ synchronized (signerForExchange) {
+ signerForExchange.initVerify(keyPair.getPublic());
+ signerForExchange.update(payload.getBytes(StandardCharsets.UTF_8));
+ verified =
signerForExchange.verify(exchange.getMessage().getHeader(PQCConstants.SIGNATURE,
byte[].class));
}
+ exchange.getMessage().setHeader(PQCConstants.VERIFY, verified);
}
private void generateEncapsulation(Exchange exchange)