oscerd opened a new pull request, #28099:
URL: https://github.com/apache/camel/pull/28099

   Fixes [CAMEL-25796](https://issues.apache.org/jira/browse/CAMEL-25796).
   
   > **Stacked on #28094.** This branch is based on 
`fix/CAMEL-25797-pqc-rotation-signals`, so until that merges this PR
   > shows two commits. Both change `PQCProducer.recordKeyUsageAfterSign` and 
its two call sites, so branching from
   > `main` would have guaranteed a conflict. **Review only the `CAMEL-25796:` 
commit here**; the diff collapses to that
   > commit alone once #28094 lands. Merge #28094 first.
   
   ## Problem
   
   `sign()` consumes the one-time index inside an LMS, HSS, XMSS or XMSSMT 
private key. The signature was published
   first and the advanced key persisted afterwards:
   
   ```java
       signature = signerForExchange.sign();
   }
   exchange.getMessage().setHeader(PQCConstants.SIGNATURE, signature);
   
   recordKeyUsageAfterSign(exchange);
   ```
   
   A crash, a `kill -9`, or any failure inside the persist step leaves an 
emitted signature in the world while the
   stored key still sits at the old index. On restart the key resumes there and 
signs a second time with an index
   already in use — exactly what the one-time property of these schemes forbids.
   
   Three further paths skipped persistence silently for a stateful key: no 
`keyLifecycleManager`, no `CamelPQCKeyId`
   header, and no stored metadata. Only the last one warned.
   
   ## Fix
   
   The order is reversed in both `signature()` and `hybridSignature()` — key 
state recorded first, signature headers
   set afterwards.
   
   The window cannot be closed completely: BouncyCastle advances the index 
*inside* `sign()` and exposes no
   reserve-then-sign API, so a true reservation is not available. What this 
buys is that a persistence failure now
   **fails the exchange** instead of releasing a signature whose index advance 
was never stored. Losing a signature is
   recoverable; reusing a one-time index is not.
   
   The three silent paths now log a warning naming the specific reason, once 
per producer so a high-volume route does
   not flood the log.
   
   ## Tests
   
   New `PQCStatefulKeyPersistOrderTest`, using an `InMemoryKeyLifecycleManager` 
whose `storeKey` can be made to fail
   (standing in for an unreachable vault):
   
   - `aFailureToPersistTheIndexFailsTheExchange`
   - `theSignatureIsNotPublishedWhenPersistenceFails` — the discriminating 
test: against the pre-change baseline a
     signature **is** published despite the failure
   - `aSuccessfulSignStillPersistsAndPublishes` — guards the happy path, 
asserting exactly one `storeKey` and a usage
     count of 1
   
   Full `camel-pqc` build green: 244 tests, 0 failures, no regenerated-file 
drift.
   
   ## Upgrade guide
   
   Added a 4.24 entry — an exchange that previously returned a signature with 
unpersisted key state now fails, which is
   a visible behaviour change even though it is the safer outcome.
   
   ---
   _Reported, analysed and fixed by Claude Code (AI agent) on behalf of 
@oscerd._
   
   🤖 Generated with [Claude Code](https://claude.com/claude-code)


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to