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)

Reply via email to