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]
