[ 
https://issues.apache.org/jira/browse/CAMEL-25797?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
 ]

Claus Ibsen updated CAMEL-25797:
--------------------------------
    Fix Version/s: 4.24.0

> camel-pqc - the usage-count and PENDING_ROTATION key rotation signals never 
> fire
> --------------------------------------------------------------------------------
>
>                 Key: CAMEL-25797
>                 URL: https://issues.apache.org/jira/browse/CAMEL-25797
>             Project: Camel
>          Issue Type: Bug
>          Components: camel-pqc
>            Reporter: Andrea Cosentino
>            Assignee: Andrea Cosentino
>            Priority: Major
>             Fix For: 4.24.0
>
>
> {{KeyRotationScheduler}} documents three rotation signals: key age, usage 
> count, and a {{PENDING_ROTATION}} status on the key metadata. Two of the 
> three cannot trigger.
> h3. 1. {{usageCount}} is only ever advanced for stateful keys
> {{KeyMetadata.updateLastUsed()}} is the only thing that increments the 
> counter — {{KeyMetadata.java:81-84}}:
> {code:java}
>     public void updateLastUsed() {
>         this.lastUsedAt = Instant.now();
>         this.usageCount++;
> {code}
> It has exactly one production caller, {{PQCProducer.java:1185}}, inside 
> {{persistStatefulKeyStateAfterSign}}, which returns early for anything that 
> is not XMSS/XMSSMT/LMS/HSS — {{PQCProducer.java:1159-1162}}:
> {code:java}
>         long remaining = getStatefulKeyRemaining(privateKey);
>         if (remaining < 0) {
>             // Not a stateful key
>             return;
>         }
> {code}
> So for ML-DSA, SLH-DSA, Falcon and every KEM key — the overwhelming majority 
> — {{usageCount}} stays {{0}} forever, while all five managers gate rotation 
> on it, e.g. {{InMemoryKeyLifecycleManager.java:158}}:
> {code:java}
>         return maxUsage > 0 && keyMetadata.getUsageCount() >= maxUsage;
> {code}
> {{KeyRotationScheduler.setMaxKeyUsage}} and the documented 
> {{camel.component.pqc.key-rotation-max-usage}} property 
> ({{pqc-key-lifecycle.adoc:975}}, "rotate keys used more than 1,000,000 
> times") are therefore inert.
> h3. 2. {{PENDING_ROTATION}} is filtered out before it is consulted
> {{KeyRotationScheduler.java:79}}:
> {code:java}
>     private Predicate<KeyMetadata> keyFilter = metadata -> 
> metadata.getStatus() == KeyMetadata.KeyStatus.ACTIVE;
> {code}
> {{KeyRotationScheduler.java:130-137}}:
> {code:java}
>             for (KeyMetadata metadata : keys) {
>                 if (metadata == null || !keyFilter.test(metadata)) {
>                     continue;
>                 }
>                 String keyId = metadata.getKeyId();
>                 try {
>                     if (keyManager.needsRotation(keyId, maxKeyAge, 
> maxKeyUsage)) {
> {code}
> {{KeyMetadata.needsRotation()}} ({{:130-132}}) does check the status:
> {code:java}
>     public boolean needsRotation() {
>         return status == KeyStatus.PENDING_ROTATION
>                 || (nextRotationAt != null && 
> Instant.now().isAfter(nextRotationAt));
> {code}
> but a key whose status an operator set to {{PENDING_ROTATION}} is no longer 
> {{ACTIVE}}, so it is {{continue}}d at {{:132}} before {{needsRotation}} ever 
> runs. Only {{nextRotationAt}} on an otherwise-ACTIVE key works today.
> The scheduler javadoc ({{:62-64}}) and {{pqc-key-lifecycle.adoc:929-931}} 
> both advertise {{PENDING_ROTATION}} as a supported signal.
> h3. Suggested fix
> Increment {{usageCount}} on every successful sign/verify/KEM operation, not 
> just the stateful path. Widen the default {{keyFilter}} to {{ACTIVE}} or 
> {{PENDING_ROTATION}}, or test {{needsRotation()}} before applying the filter.
> h3. Test gap
> {{KeyRotationSchedulerTest}} increments {{usageCount}} by hand ({{:87}}), 
> which hides that production never does, and never asserts that a 
> {{PENDING_ROTATION}} key rotates.
> ----
> _Reported by Claude Code (AI agent) on behalf of [~oscerd]. Every code 
> reference was verified against commit {{7aae27315946}} on {{main}}._



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to