oscerd opened a new pull request, #27884: URL: https://github.com/apache/camel/pull/27884
## Backport of #27768 Cherry-pick of #27768 onto `camel-4.18.x`. **Original PR:** #27768 - CAMEL-25603: camel-pqc - do not share a KeyGenerator or KeyAgreement across concurrent KEM operations **Original author:** @oscerd **Target branch:** `camel-4.18.x` ### Port notes This is a hand port, not a straight cherry-pick. `camel-4.18.x` differs from `main` here: - There is no `HybridKEM` and there are no hybrid KEM operations, so the `HybridKEM` and `KeyAgreement` parts of the change, `HybridKEMConcurrencyTest` and `ProbedKeyAgreement` are left out. - `PQCProducer` and `PQCDataFormat` were ported by hand onto the 4.18.x code, which still passes `new SecureRandom()`. The change is the same: a new `KeyGenerator` per operation when Camel creates it (the producer keeps the `Provider` object), and the lock held from `init()` to `generateKey()` on a configured or shared instance. - `pqc-component.adoc` gets the same note, without the hybrid `KeyAgreement`. `pqc-dataformat.adoc` on 4.18.x is a short page with no "Caching KeyGenerator" tip, so it is unchanged. There are no catalog doc copies on this branch. - The new tests use the JUnit 5 `CamelTestSupport`. `PQCDataFormatConcurrencyTest` converts the unmarshal result with the type converter, because the 4.18.x data format returns a stream cache rather than a byte array. - The new tests fail on `camel-4.18.x` without the change (wrong secrets, the other operation's encapsulation, failed decryption) and pass with it. `camel-pqc`: 119 tests, 0 failures, 1 skipped (a JDK 25-only test). - The upgrade guides stay on `main`, which already has the 4.18.6 note (in `camel-4x-upgrade-guide-4_18.adoc`, "Upgrading from 4.18.5 to 4.18.6"). ### Original description Fixes [CAMEL-25603](https://issues.apache.org/jira/browse/CAMEL-25603). A KEM `KeyGenerator` keeps the spec passed to `init()` until `generateKey()` reads it, and a `KeyAgreement` keeps its state from `init()` to `generateSecret()`. Neither is thread-safe, but: - `PQCProducer` held one `KeyGenerator` for `generateSecretKeyEncapsulation` / `extractSecretKeyEncapsulation`, and one `KeyGenerator` plus one `KeyAgreement` for the hybrid KEM operations, for all exchanges. - `HybridKEM` ran the init-to-result sequences on whatever instances it was given. - `PQCDataFormat` cached one `KeyGenerator` at start, also when none was configured, and used it for every marshal and unmarshal. Overlapping exchanges could get a result computed from another exchange's parameters, or fail (`AEADBadTagException`, or a `NullPointerException` from the Bouncy Castle SPI). ## Change Same approach as CAMEL-24445 for `Signature`: - `PQCProducer` creates a new `KeyGenerator` / `KeyAgreement` for every exchange when it created them itself. It keeps the `Provider` object of the generator created at start, so creating another one does not depend on the provider still being registered (`PQCEndpoint.doStop()` removes the Bouncy Castle providers from the JVM). - A configured instance (an autowired registry bean, or the `PQCDefault*Material` defaults, which are shared JVM-wide) is used as-is, and each init-to-result sequence holds its monitor: in `PQCProducer`, in `HybridKEM` (so callers of the public utility are covered too) and in `PQCDataFormat`. - `PQCDataFormat` creates a `KeyGenerator` for every operation unless one is configured; `doStart()` still fails fast on an unknown algorithm or provider. As a side effect, the documented `CamelPQCKemAlgorithm` header now applies to a started data format. - Instances that `PQCComponent` puts into the configuration itself (the `parameterSpec` path, and the `PQCDefault*Material` defaults) count as configured and are used one at a time. Letting the producer create its own instead is a throughput improvement for `main`, tracked in [CAMEL-25624](https://issues.apache.org/jira/browse/CAMEL-25624). ## Tests New tests, all failing without the change: - `PQCKemSharedKeyGeneratorIsolationTest`: a configured `KeyGenerator` shared by a generate and an extract endpoint. Overlapping extractions, and an overlapping generation and extraction, each keep their own result. A small test helper (`InterleavingProbe`, with `ProbedKeyGenerator` / `ProbedKeyAgreement` wrappers) holds the first caller between `init()` and the result and records whether another `init()` got in. - `PQCKemConcurrentExtractionIsolationTest`: 8 threads x 40 extractions through one producer that created its own generator. - `HybridKEMConcurrencyTest`: overlapping extractions and encapsulations on a shared `KeyAgreement` and `KeyGenerator`. - `PQCDataFormatConcurrencyTest`: concurrent round trips through one data format with no `KeyGenerator` configured, and an overlapping marshal and unmarshal on a configured one. `camel-pqc`: 239 tests, 0 failures, 1 skipped (pre-existing). Full reactor `clean install -DskipTests -DskipITs`: BUILD SUCCESS (703 modules); the only regenerated files are the catalog copies of the two pqc docs. ## Docs - `pqc-component.adoc`: a note on how KEM `KeyGenerator` / `KeyAgreement` instances are used; registering a `KeyGenerator` bean is optional. - `pqc-dataformat.adoc`: the "Caching KeyGenerator" tip is replaced, since a shared instance now runs one operation at a time. - Upgrade guide notes for 4.24, 4.22.2 and 4.18.6, all on `main`. Backports to `camel-4.22.x` and `camel-4.18.x` will be opened by hand once this is merged, without `port/*` labels on purpose: the guide files stay on `main`, and on `camel-4.18.x` a straight cherry-pick does not compile (no hybrid KEM, different `PQCProducer` / `PQCDataFormat`, JUnit 5 tests). _Claude Code 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]
