gnodet-bot commented on code in PR #28099:
URL: https://github.com/apache/camel/pull/28099#discussion_r4322005899


##########
components/camel-pqc/src/main/java/org/apache/camel/component/pqc/PQCProducer.java:
##########
@@ -1146,47 +1156,102 @@ private void checkStatefulKeyBeforeSign() {
     }
 
     /**
-     * Persists stateful key state after a signing operation through the 
KeyLifecycleManager, if configured. This
-     * ensures the key index is tracked across restarts.
+     * Records the use of the signing key through the KeyLifecycleManager, if 
one is configured and the exchange names a
+     * key.
+     * <p/>
+     * This advances {@code usageCount}, which is what the {@code maxKeyUsage} 
rotation signal of
+     * {@link org.apache.camel.component.pqc.lifecycle.KeyRotationScheduler} 
reads. It therefore runs for every signing
+     * key, not only the stateful ones: ML-DSA, SLH-DSA and Falcon keys would 
otherwise sit at a usage count of zero
+     * forever and never be rotated.
+     * <p/>
+     * The key encapsulation operations do not call this method, so a KEM key 
still does not advance its usage count and
+     * {@code maxKeyUsage} does not apply to it.
+     * <p/>
+     * For a stateful signature key the advanced private key is stored as 
well, so the one-time index survives a
+     * restart.
      */
-    private void persistStatefulKeyStateAfterSign(Exchange exchange) throws 
Exception {
+    private void recordKeyUsageAfterSign(Exchange exchange) throws Exception {
         if (keyPair == null || keyPair.getPrivate() == null) {
             return;
         }
 
         PrivateKey privateKey = keyPair.getPrivate();
-        long remaining = getStatefulKeyRemaining(privateKey);
-        if (remaining < 0) {
-            // Not a stateful key
-            return;
-        }
+        boolean stateful = getStatefulKeyRemaining(privateKey) >= 0;
 
         KeyLifecycleManager klm = getConfiguration().getKeyLifecycleManager();
         if (klm == null) {
+            // Only the stateful risk is worth reporting here. A plain signing 
endpoint with no lifecycle management
+            // is an ordinary setup, and with no manager there is no 
maxKeyUsage threshold to miss.
+            if (stateful) {
+                warnKeyUsageNotRecorded(true, "no keyLifecycleManager is 
configured on the endpoint");
+            }
             return;
         }
 
         String keyId = exchange.getMessage().getHeader(PQCConstants.KEY_ID, 
String.class);
         if (ObjectHelper.isEmpty(keyId)) {
+            warnKeyUsageNotRecorded(stateful,
+                    "the exchange carries no " + PQCConstants.KEY_ID + " 
header identifying the key");
             return;
         }
 
-        // Update metadata with current usage
         KeyMetadata metadata = klm.getKeyMetadata(keyId);
         if (metadata == null) {

Review Comment:
   ⚠️ **Bug: unwrapped `getKeyMetadata` can fail the exchange for a 
non-stateful key**
   
   This call declares `throws Exception`, and remote vault implementations 
(Hashicorp, Azure) perform a network read here. If it throws, the exception 
propagates through `signature()` / `hybridSignature()` and **fails the exchange 
after the signature was already computed but before the signature header is 
set** — exactly what the try-catch around `updateKeyMetadata` below (line 1215) 
was designed to prevent.
   
   The author's comment at that try-catch is explicit: _"Failing the exchange 
over it would throw away a perfectly good signature."_ The same reasoning 
applies to this read.
   
   Fix: restructure `recordKeyUsageAfterSign` so that for the non-stateful 
path, the entire `getKeyMetadata` + null-check + `updateLastUsed` + 
`updateKeyMetadata` sequence is inside a single try-catch. The stateful path 
(`storeKey`) does not need this protection because losing a stateful index on a 
vault write failure is already fatal.



-- 
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