This is an automated email from the ASF dual-hosted git repository.

acosentino pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel.git


The following commit(s) were added to refs/heads/main by this push:
     new 5795fa0a2e74 CAMEL-23248 - Camel-PQC: Add stateful key usage tracking 
and warnings for XMSS/LMS (#22264)
5795fa0a2e74 is described below

commit 5795fa0a2e7442892e5cc330f621daaef666cfb1
Author: Andrea Cosentino <[email protected]>
AuthorDate: Wed Mar 25 15:22:06 2026 +0100

    CAMEL-23248 - Camel-PQC: Add stateful key usage tracking and warnings for 
XMSS/LMS (#22264)
    
    * CAMEL-23248 - Camel-PQC: Add stateful key usage tracking and warnings for 
XMSS/LMS
    
    Add pre-sign remaining signature checks for stateful hash-based signature
    schemes (XMSS, XMSSMT, LMS/HSS). When remaining signatures reach zero,
    an IllegalStateException is thrown to prevent key reuse. When below a
    configurable threshold (default 10%), a WARN log is emitted.
    
    Add PQCStatefulKeyHealthCheck extending AbstractHealthCheck to report
    stateful key capacity via Camel's health API (remaining signatures,
    total capacity, exhaustion status).
    
    Add statefulKeyWarningThreshold config parameter to PQCConfiguration.
    
    Persist key state through KeyLifecycleManager after each signing to
    prevent index reuse across restarts.
    
    Add camel-health dependency to pom.xml.
    
    Add PQCStatefulKeyTrackingTest with 4 unit tests covering signature
    count decrease, key exhaustion, and StatefulKeyState model behavior.
    
    Signed-off-by: Andrea Cosentino <[email protected]>
    
    * CAMEL-23248 - Camel-PQC: Add stateful key usage tracking and warnings for 
XMSS/LMS
    
    Signed-off-by: Andrea Cosentino <[email protected]>
    
    ---------
    
    Signed-off-by: Andrea Cosentino <[email protected]>
---
 .../org/apache/camel/catalog/components/pqc.json   |  22 +--
 components/camel-pqc/pom.xml                       |   4 +
 .../component/pqc/PQCComponentConfigurer.java      |   6 +
 .../camel/component/pqc/PQCEndpointConfigurer.java |   6 +
 .../camel/component/pqc/PQCEndpointUriFactory.java |   3 +-
 .../org/apache/camel/component/pqc/pqc.json        |  22 +--
 .../camel/component/pqc/PQCConfiguration.java      |  22 +++
 .../apache/camel/component/pqc/PQCProducer.java    | 141 ++++++++++++++-
 .../component/pqc/PQCStatefulKeyHealthCheck.java   | 103 +++++++++++
 .../component/pqc/PQCStatefulKeyTrackingTest.java  | 194 +++++++++++++++++++++
 .../component/dsl/PqcComponentBuilderFactory.java  |  23 +++
 .../endpoint/dsl/PQCEndpointBuilderFactory.java    |  40 +++++
 12 files changed, 564 insertions(+), 22 deletions(-)

diff --git 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/pqc.json
 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/pqc.json
index 04323a8b95c0..c1e44735e9ae 100644
--- 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/pqc.json
+++ 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/pqc.json
@@ -43,12 +43,13 @@
     "keyStorePassword": { "index": 16, "kind": "property", "displayName": "Key 
Store Password", "group": "advanced", "label": "advanced", "required": false, 
"type": "string", "javaType": "java.lang.String", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": true, 
"configurationClass": "org.apache.camel.component.pqc.PQCConfiguration", 
"configurationField": "configuration", "description": "The KeyStore password to 
use in combination with KeyStore Parameter" },
     "signatureAlgorithm": { "index": 17, "kind": "property", "displayName": 
"Signature Algorithm", "group": "advanced", "label": "advanced", "required": 
false, "type": "enum", "javaType": "java.lang.String", "enum": [ "MLDSA", 
"SLHDSA", "LMS", "HSS", "XMSS", "XMSSMT", "DILITHIUM", "FALCON", "PICNIC", 
"SNOVA", "MAYO", "SPHINCSPLUS" ], "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "configurationClass": 
"org.apache.camel.component.pqc.PQCConfiguration", "c [...]
     "signer": { "index": 18, "kind": "property", "displayName": "Signer", 
"group": "advanced", "label": "advanced", "required": false, "type": "object", 
"javaType": "java.security.Signature", "deprecated": false, "deprecationNote": 
"", "autowired": true, "secret": false, "configurationClass": 
"org.apache.camel.component.pqc.PQCConfiguration", "configurationField": 
"configuration", "description": "The Signer to be used" },
-    "storeExtractedSecretKeyAsHeader": { "index": 19, "kind": "property", 
"displayName": "Store Extracted Secret Key As Header", "group": "advanced", 
"label": "advanced", "required": false, "type": "boolean", "javaType": 
"boolean", "deprecated": false, "deprecationNote": "", "autowired": false, 
"secret": false, "defaultValue": false, "configurationClass": 
"org.apache.camel.component.pqc.PQCConfiguration", "configurationField": 
"configuration", "description": "In the context of extractSec [...]
-    "strictKeyLifecycle": { "index": 20, "kind": "property", "displayName": 
"Strict Key Lifecycle", "group": "advanced", "label": "advanced", "required": 
false, "type": "boolean", "javaType": "boolean", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "defaultValue": 
true, "configurationClass": "org.apache.camel.component.pqc.PQCConfiguration", 
"configurationField": "configuration", "description": "Whether to enforce key 
status checks before cryptographic  [...]
-    "symmetricKeyAlgorithm": { "index": 21, "kind": "property", "displayName": 
"Symmetric Key Algorithm", "group": "advanced", "label": "advanced", 
"required": false, "type": "enum", "javaType": "java.lang.String", "enum": [ 
"AES", "ARIA", "RC2", "RC5", "CAMELLIA", "CAST5", "CAST6", "CHACHA7539", 
"DSTU7624", "GOST28147", "GOST3412_2015", "GRAIN128", "HC128", "HC256", 
"SALSA20", "SEED", "SM4", "DESEDE" ], "deprecated": false, "deprecationNote": 
"", "autowired": false, "secret": false, "co [...]
-    "symmetricKeyLength": { "index": 22, "kind": "property", "displayName": 
"Symmetric Key Length", "group": "advanced", "label": "advanced", "required": 
false, "type": "integer", "javaType": "int", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "defaultValue": 
128, "configurationClass": "org.apache.camel.component.pqc.PQCConfiguration", 
"configurationField": "configuration", "description": "The required length of 
the symmetric key used" },
-    "healthCheckConsumerEnabled": { "index": 23, "kind": "property", 
"displayName": "Health Check Consumer Enabled", "group": "health", "label": 
"health", "required": false, "type": "boolean", "javaType": "boolean", 
"deprecated": false, "autowired": false, "secret": false, "defaultValue": true, 
"description": "Used for enabling or disabling all consumer based health checks 
from this component" },
-    "healthCheckProducerEnabled": { "index": 24, "kind": "property", 
"displayName": "Health Check Producer Enabled", "group": "health", "label": 
"health", "required": false, "type": "boolean", "javaType": "boolean", 
"deprecated": false, "autowired": false, "secret": false, "defaultValue": true, 
"description": "Used for enabling or disabling all producer based health checks 
from this component. Notice: Camel has by default disabled all producer based 
health-checks. You can turn on produce [...]
+    "statefulKeyWarningThreshold": { "index": 19, "kind": "property", 
"displayName": "Stateful Key Warning Threshold", "group": "advanced", "label": 
"advanced", "required": false, "type": "number", "javaType": "double", 
"deprecated": false, "deprecationNote": "", "autowired": false, "secret": 
false, "defaultValue": 0.1, "configurationClass": 
"org.apache.camel.component.pqc.PQCConfiguration", "configurationField": 
"configuration", "description": "The warning threshold for stateful key exh 
[...]
+    "storeExtractedSecretKeyAsHeader": { "index": 20, "kind": "property", 
"displayName": "Store Extracted Secret Key As Header", "group": "advanced", 
"label": "advanced", "required": false, "type": "boolean", "javaType": 
"boolean", "deprecated": false, "deprecationNote": "", "autowired": false, 
"secret": false, "defaultValue": false, "configurationClass": 
"org.apache.camel.component.pqc.PQCConfiguration", "configurationField": 
"configuration", "description": "In the context of extractSec [...]
+    "strictKeyLifecycle": { "index": 21, "kind": "property", "displayName": 
"Strict Key Lifecycle", "group": "advanced", "label": "advanced", "required": 
false, "type": "boolean", "javaType": "boolean", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "defaultValue": 
true, "configurationClass": "org.apache.camel.component.pqc.PQCConfiguration", 
"configurationField": "configuration", "description": "Whether to enforce key 
status checks before cryptographic  [...]
+    "symmetricKeyAlgorithm": { "index": 22, "kind": "property", "displayName": 
"Symmetric Key Algorithm", "group": "advanced", "label": "advanced", 
"required": false, "type": "enum", "javaType": "java.lang.String", "enum": [ 
"AES", "ARIA", "RC2", "RC5", "CAMELLIA", "CAST5", "CAST6", "CHACHA7539", 
"DSTU7624", "GOST28147", "GOST3412_2015", "GRAIN128", "HC128", "HC256", 
"SALSA20", "SEED", "SM4", "DESEDE" ], "deprecated": false, "deprecationNote": 
"", "autowired": false, "secret": false, "co [...]
+    "symmetricKeyLength": { "index": 23, "kind": "property", "displayName": 
"Symmetric Key Length", "group": "advanced", "label": "advanced", "required": 
false, "type": "integer", "javaType": "int", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "defaultValue": 
128, "configurationClass": "org.apache.camel.component.pqc.PQCConfiguration", 
"configurationField": "configuration", "description": "The required length of 
the symmetric key used" },
+    "healthCheckConsumerEnabled": { "index": 24, "kind": "property", 
"displayName": "Health Check Consumer Enabled", "group": "health", "label": 
"health", "required": false, "type": "boolean", "javaType": "boolean", 
"deprecated": false, "autowired": false, "secret": false, "defaultValue": true, 
"description": "Used for enabling or disabling all consumer based health checks 
from this component" },
+    "healthCheckProducerEnabled": { "index": 25, "kind": "property", 
"displayName": "Health Check Producer Enabled", "group": "health", "label": 
"health", "required": false, "type": "boolean", "javaType": "boolean", 
"deprecated": false, "autowired": false, "secret": false, "defaultValue": true, 
"description": "Used for enabling or disabling all producer based health checks 
from this component. Notice: Camel has by default disabled all producer based 
health-checks. You can turn on produce [...]
   },
   "headers": {
     "CamelPQCOperation": { "index": 0, "kind": "header", "displayName": "", 
"group": "producer", "label": "", "required": false, "javaType": "String", 
"deprecated": false, "deprecationNote": "", "autowired": false, "secret": 
false, "description": "The operation we want to perform", "constantName": 
"org.apache.camel.component.pqc.PQCConstants#OPERATION" },
@@ -94,9 +95,10 @@
     "keyStorePassword": { "index": 15, "kind": "parameter", "displayName": 
"Key Store Password", "group": "advanced", "label": "advanced", "required": 
false, "type": "string", "javaType": "java.lang.String", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": true, 
"configurationClass": "org.apache.camel.component.pqc.PQCConfiguration", 
"configurationField": "configuration", "description": "The KeyStore password to 
use in combination with KeyStore Parameter" },
     "signatureAlgorithm": { "index": 16, "kind": "parameter", "displayName": 
"Signature Algorithm", "group": "advanced", "label": "advanced", "required": 
false, "type": "enum", "javaType": "java.lang.String", "enum": [ "MLDSA", 
"SLHDSA", "LMS", "HSS", "XMSS", "XMSSMT", "DILITHIUM", "FALCON", "PICNIC", 
"SNOVA", "MAYO", "SPHINCSPLUS" ], "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "configurationClass": 
"org.apache.camel.component.pqc.PQCConfiguration", " [...]
     "signer": { "index": 17, "kind": "parameter", "displayName": "Signer", 
"group": "advanced", "label": "advanced", "required": false, "type": "object", 
"javaType": "java.security.Signature", "deprecated": false, "deprecationNote": 
"", "autowired": true, "secret": false, "configurationClass": 
"org.apache.camel.component.pqc.PQCConfiguration", "configurationField": 
"configuration", "description": "The Signer to be used" },
-    "storeExtractedSecretKeyAsHeader": { "index": 18, "kind": "parameter", 
"displayName": "Store Extracted Secret Key As Header", "group": "advanced", 
"label": "advanced", "required": false, "type": "boolean", "javaType": 
"boolean", "deprecated": false, "deprecationNote": "", "autowired": false, 
"secret": false, "defaultValue": false, "configurationClass": 
"org.apache.camel.component.pqc.PQCConfiguration", "configurationField": 
"configuration", "description": "In the context of extractSe [...]
-    "strictKeyLifecycle": { "index": 19, "kind": "parameter", "displayName": 
"Strict Key Lifecycle", "group": "advanced", "label": "advanced", "required": 
false, "type": "boolean", "javaType": "boolean", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "defaultValue": 
true, "configurationClass": "org.apache.camel.component.pqc.PQCConfiguration", 
"configurationField": "configuration", "description": "Whether to enforce key 
status checks before cryptographic [...]
-    "symmetricKeyAlgorithm": { "index": 20, "kind": "parameter", 
"displayName": "Symmetric Key Algorithm", "group": "advanced", "label": 
"advanced", "required": false, "type": "enum", "javaType": "java.lang.String", 
"enum": [ "AES", "ARIA", "RC2", "RC5", "CAMELLIA", "CAST5", "CAST6", 
"CHACHA7539", "DSTU7624", "GOST28147", "GOST3412_2015", "GRAIN128", "HC128", 
"HC256", "SALSA20", "SEED", "SM4", "DESEDE" ], "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "c [...]
-    "symmetricKeyLength": { "index": 21, "kind": "parameter", "displayName": 
"Symmetric Key Length", "group": "advanced", "label": "advanced", "required": 
false, "type": "integer", "javaType": "int", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "defaultValue": 
128, "configurationClass": "org.apache.camel.component.pqc.PQCConfiguration", 
"configurationField": "configuration", "description": "The required length of 
the symmetric key used" }
+    "statefulKeyWarningThreshold": { "index": 18, "kind": "parameter", 
"displayName": "Stateful Key Warning Threshold", "group": "advanced", "label": 
"advanced", "required": false, "type": "number", "javaType": "double", 
"deprecated": false, "deprecationNote": "", "autowired": false, "secret": 
false, "defaultValue": 0.1, "configurationClass": 
"org.apache.camel.component.pqc.PQCConfiguration", "configurationField": 
"configuration", "description": "The warning threshold for stateful key ex [...]
+    "storeExtractedSecretKeyAsHeader": { "index": 19, "kind": "parameter", 
"displayName": "Store Extracted Secret Key As Header", "group": "advanced", 
"label": "advanced", "required": false, "type": "boolean", "javaType": 
"boolean", "deprecated": false, "deprecationNote": "", "autowired": false, 
"secret": false, "defaultValue": false, "configurationClass": 
"org.apache.camel.component.pqc.PQCConfiguration", "configurationField": 
"configuration", "description": "In the context of extractSe [...]
+    "strictKeyLifecycle": { "index": 20, "kind": "parameter", "displayName": 
"Strict Key Lifecycle", "group": "advanced", "label": "advanced", "required": 
false, "type": "boolean", "javaType": "boolean", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "defaultValue": 
true, "configurationClass": "org.apache.camel.component.pqc.PQCConfiguration", 
"configurationField": "configuration", "description": "Whether to enforce key 
status checks before cryptographic [...]
+    "symmetricKeyAlgorithm": { "index": 21, "kind": "parameter", 
"displayName": "Symmetric Key Algorithm", "group": "advanced", "label": 
"advanced", "required": false, "type": "enum", "javaType": "java.lang.String", 
"enum": [ "AES", "ARIA", "RC2", "RC5", "CAMELLIA", "CAST5", "CAST6", 
"CHACHA7539", "DSTU7624", "GOST28147", "GOST3412_2015", "GRAIN128", "HC128", 
"HC256", "SALSA20", "SEED", "SM4", "DESEDE" ], "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "c [...]
+    "symmetricKeyLength": { "index": 22, "kind": "parameter", "displayName": 
"Symmetric Key Length", "group": "advanced", "label": "advanced", "required": 
false, "type": "integer", "javaType": "int", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "defaultValue": 
128, "configurationClass": "org.apache.camel.component.pqc.PQCConfiguration", 
"configurationField": "configuration", "description": "The required length of 
the symmetric key used" }
   }
 }
diff --git a/components/camel-pqc/pom.xml b/components/camel-pqc/pom.xml
index fcc695c27b7f..e641acefda96 100644
--- a/components/camel-pqc/pom.xml
+++ b/components/camel-pqc/pom.xml
@@ -42,6 +42,10 @@
             <groupId>org.apache.camel</groupId>
             <artifactId>camel-support</artifactId>
         </dependency>
+        <dependency>
+            <groupId>org.apache.camel</groupId>
+            <artifactId>camel-health</artifactId>
+        </dependency>
         <dependency>
             <groupId>org.bouncycastle</groupId>
             <artifactId>bcprov-jdk18on</artifactId>
diff --git 
a/components/camel-pqc/src/generated/java/org/apache/camel/component/pqc/PQCComponentConfigurer.java
 
b/components/camel-pqc/src/generated/java/org/apache/camel/component/pqc/PQCComponentConfigurer.java
index 9044003da182..39e46f037f72 100644
--- 
a/components/camel-pqc/src/generated/java/org/apache/camel/component/pqc/PQCComponentConfigurer.java
+++ 
b/components/camel-pqc/src/generated/java/org/apache/camel/component/pqc/PQCComponentConfigurer.java
@@ -69,6 +69,8 @@ public class PQCComponentConfigurer extends 
PropertyConfigurerSupport implements
         case "signaturealgorithm":
         case "signatureAlgorithm": 
getOrCreateConfiguration(target).setSignatureAlgorithm(property(camelContext, 
java.lang.String.class, value)); return true;
         case "signer": 
getOrCreateConfiguration(target).setSigner(property(camelContext, 
java.security.Signature.class, value)); return true;
+        case "statefulkeywarningthreshold":
+        case "statefulKeyWarningThreshold": 
getOrCreateConfiguration(target).setStatefulKeyWarningThreshold(property(camelContext,
 double.class, value)); return true;
         case "storeextractedsecretkeyasheader":
         case "storeExtractedSecretKeyAsHeader": 
getOrCreateConfiguration(target).setStoreExtractedSecretKeyAsHeader(property(camelContext,
 boolean.class, value)); return true;
         case "strictkeylifecycle":
@@ -128,6 +130,8 @@ public class PQCComponentConfigurer extends 
PropertyConfigurerSupport implements
         case "signaturealgorithm":
         case "signatureAlgorithm": return java.lang.String.class;
         case "signer": return java.security.Signature.class;
+        case "statefulkeywarningthreshold":
+        case "statefulKeyWarningThreshold": return double.class;
         case "storeextractedsecretkeyasheader":
         case "storeExtractedSecretKeyAsHeader": return boolean.class;
         case "strictkeylifecycle":
@@ -183,6 +187,8 @@ public class PQCComponentConfigurer extends 
PropertyConfigurerSupport implements
         case "signaturealgorithm":
         case "signatureAlgorithm": return 
getOrCreateConfiguration(target).getSignatureAlgorithm();
         case "signer": return getOrCreateConfiguration(target).getSigner();
+        case "statefulkeywarningthreshold":
+        case "statefulKeyWarningThreshold": return 
getOrCreateConfiguration(target).getStatefulKeyWarningThreshold();
         case "storeextractedsecretkeyasheader":
         case "storeExtractedSecretKeyAsHeader": return 
getOrCreateConfiguration(target).isStoreExtractedSecretKeyAsHeader();
         case "strictkeylifecycle":
diff --git 
a/components/camel-pqc/src/generated/java/org/apache/camel/component/pqc/PQCEndpointConfigurer.java
 
b/components/camel-pqc/src/generated/java/org/apache/camel/component/pqc/PQCEndpointConfigurer.java
index fe426f7b55dd..97181137be25 100644
--- 
a/components/camel-pqc/src/generated/java/org/apache/camel/component/pqc/PQCEndpointConfigurer.java
+++ 
b/components/camel-pqc/src/generated/java/org/apache/camel/component/pqc/PQCEndpointConfigurer.java
@@ -55,6 +55,8 @@ public class PQCEndpointConfigurer extends 
PropertyConfigurerSupport implements
         case "signaturealgorithm":
         case "signatureAlgorithm": 
target.getConfiguration().setSignatureAlgorithm(property(camelContext, 
java.lang.String.class, value)); return true;
         case "signer": 
target.getConfiguration().setSigner(property(camelContext, 
java.security.Signature.class, value)); return true;
+        case "statefulkeywarningthreshold":
+        case "statefulKeyWarningThreshold": 
target.getConfiguration().setStatefulKeyWarningThreshold(property(camelContext, 
double.class, value)); return true;
         case "storeextractedsecretkeyasheader":
         case "storeExtractedSecretKeyAsHeader": 
target.getConfiguration().setStoreExtractedSecretKeyAsHeader(property(camelContext,
 boolean.class, value)); return true;
         case "strictkeylifecycle":
@@ -107,6 +109,8 @@ public class PQCEndpointConfigurer extends 
PropertyConfigurerSupport implements
         case "signaturealgorithm":
         case "signatureAlgorithm": return java.lang.String.class;
         case "signer": return java.security.Signature.class;
+        case "statefulkeywarningthreshold":
+        case "statefulKeyWarningThreshold": return double.class;
         case "storeextractedsecretkeyasheader":
         case "storeExtractedSecretKeyAsHeader": return boolean.class;
         case "strictkeylifecycle":
@@ -155,6 +159,8 @@ public class PQCEndpointConfigurer extends 
PropertyConfigurerSupport implements
         case "signaturealgorithm":
         case "signatureAlgorithm": return 
target.getConfiguration().getSignatureAlgorithm();
         case "signer": return target.getConfiguration().getSigner();
+        case "statefulkeywarningthreshold":
+        case "statefulKeyWarningThreshold": return 
target.getConfiguration().getStatefulKeyWarningThreshold();
         case "storeextractedsecretkeyasheader":
         case "storeExtractedSecretKeyAsHeader": return 
target.getConfiguration().isStoreExtractedSecretKeyAsHeader();
         case "strictkeylifecycle":
diff --git 
a/components/camel-pqc/src/generated/java/org/apache/camel/component/pqc/PQCEndpointUriFactory.java
 
b/components/camel-pqc/src/generated/java/org/apache/camel/component/pqc/PQCEndpointUriFactory.java
index 1f1bfe4747fe..c151e1f44691 100644
--- 
a/components/camel-pqc/src/generated/java/org/apache/camel/component/pqc/PQCEndpointUriFactory.java
+++ 
b/components/camel-pqc/src/generated/java/org/apache/camel/component/pqc/PQCEndpointUriFactory.java
@@ -23,7 +23,7 @@ public class PQCEndpointUriFactory extends 
org.apache.camel.support.component.En
     private static final Set<String> SECRET_PROPERTY_NAMES;
     private static final Map<String, String> MULTI_VALUE_PREFIXES;
     static {
-        Set<String> props = new HashSet<>(22);
+        Set<String> props = new HashSet<>(23);
         props.add("classicalKEMAlgorithm");
         props.add("classicalKeyAgreement");
         props.add("classicalKeyPair");
@@ -42,6 +42,7 @@ public class PQCEndpointUriFactory extends 
org.apache.camel.support.component.En
         props.add("operation");
         props.add("signatureAlgorithm");
         props.add("signer");
+        props.add("statefulKeyWarningThreshold");
         props.add("storeExtractedSecretKeyAsHeader");
         props.add("strictKeyLifecycle");
         props.add("symmetricKeyAlgorithm");
diff --git 
a/components/camel-pqc/src/generated/resources/META-INF/org/apache/camel/component/pqc/pqc.json
 
b/components/camel-pqc/src/generated/resources/META-INF/org/apache/camel/component/pqc/pqc.json
index 04323a8b95c0..c1e44735e9ae 100644
--- 
a/components/camel-pqc/src/generated/resources/META-INF/org/apache/camel/component/pqc/pqc.json
+++ 
b/components/camel-pqc/src/generated/resources/META-INF/org/apache/camel/component/pqc/pqc.json
@@ -43,12 +43,13 @@
     "keyStorePassword": { "index": 16, "kind": "property", "displayName": "Key 
Store Password", "group": "advanced", "label": "advanced", "required": false, 
"type": "string", "javaType": "java.lang.String", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": true, 
"configurationClass": "org.apache.camel.component.pqc.PQCConfiguration", 
"configurationField": "configuration", "description": "The KeyStore password to 
use in combination with KeyStore Parameter" },
     "signatureAlgorithm": { "index": 17, "kind": "property", "displayName": 
"Signature Algorithm", "group": "advanced", "label": "advanced", "required": 
false, "type": "enum", "javaType": "java.lang.String", "enum": [ "MLDSA", 
"SLHDSA", "LMS", "HSS", "XMSS", "XMSSMT", "DILITHIUM", "FALCON", "PICNIC", 
"SNOVA", "MAYO", "SPHINCSPLUS" ], "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "configurationClass": 
"org.apache.camel.component.pqc.PQCConfiguration", "c [...]
     "signer": { "index": 18, "kind": "property", "displayName": "Signer", 
"group": "advanced", "label": "advanced", "required": false, "type": "object", 
"javaType": "java.security.Signature", "deprecated": false, "deprecationNote": 
"", "autowired": true, "secret": false, "configurationClass": 
"org.apache.camel.component.pqc.PQCConfiguration", "configurationField": 
"configuration", "description": "The Signer to be used" },
-    "storeExtractedSecretKeyAsHeader": { "index": 19, "kind": "property", 
"displayName": "Store Extracted Secret Key As Header", "group": "advanced", 
"label": "advanced", "required": false, "type": "boolean", "javaType": 
"boolean", "deprecated": false, "deprecationNote": "", "autowired": false, 
"secret": false, "defaultValue": false, "configurationClass": 
"org.apache.camel.component.pqc.PQCConfiguration", "configurationField": 
"configuration", "description": "In the context of extractSec [...]
-    "strictKeyLifecycle": { "index": 20, "kind": "property", "displayName": 
"Strict Key Lifecycle", "group": "advanced", "label": "advanced", "required": 
false, "type": "boolean", "javaType": "boolean", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "defaultValue": 
true, "configurationClass": "org.apache.camel.component.pqc.PQCConfiguration", 
"configurationField": "configuration", "description": "Whether to enforce key 
status checks before cryptographic  [...]
-    "symmetricKeyAlgorithm": { "index": 21, "kind": "property", "displayName": 
"Symmetric Key Algorithm", "group": "advanced", "label": "advanced", 
"required": false, "type": "enum", "javaType": "java.lang.String", "enum": [ 
"AES", "ARIA", "RC2", "RC5", "CAMELLIA", "CAST5", "CAST6", "CHACHA7539", 
"DSTU7624", "GOST28147", "GOST3412_2015", "GRAIN128", "HC128", "HC256", 
"SALSA20", "SEED", "SM4", "DESEDE" ], "deprecated": false, "deprecationNote": 
"", "autowired": false, "secret": false, "co [...]
-    "symmetricKeyLength": { "index": 22, "kind": "property", "displayName": 
"Symmetric Key Length", "group": "advanced", "label": "advanced", "required": 
false, "type": "integer", "javaType": "int", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "defaultValue": 
128, "configurationClass": "org.apache.camel.component.pqc.PQCConfiguration", 
"configurationField": "configuration", "description": "The required length of 
the symmetric key used" },
-    "healthCheckConsumerEnabled": { "index": 23, "kind": "property", 
"displayName": "Health Check Consumer Enabled", "group": "health", "label": 
"health", "required": false, "type": "boolean", "javaType": "boolean", 
"deprecated": false, "autowired": false, "secret": false, "defaultValue": true, 
"description": "Used for enabling or disabling all consumer based health checks 
from this component" },
-    "healthCheckProducerEnabled": { "index": 24, "kind": "property", 
"displayName": "Health Check Producer Enabled", "group": "health", "label": 
"health", "required": false, "type": "boolean", "javaType": "boolean", 
"deprecated": false, "autowired": false, "secret": false, "defaultValue": true, 
"description": "Used for enabling or disabling all producer based health checks 
from this component. Notice: Camel has by default disabled all producer based 
health-checks. You can turn on produce [...]
+    "statefulKeyWarningThreshold": { "index": 19, "kind": "property", 
"displayName": "Stateful Key Warning Threshold", "group": "advanced", "label": 
"advanced", "required": false, "type": "number", "javaType": "double", 
"deprecated": false, "deprecationNote": "", "autowired": false, "secret": 
false, "defaultValue": 0.1, "configurationClass": 
"org.apache.camel.component.pqc.PQCConfiguration", "configurationField": 
"configuration", "description": "The warning threshold for stateful key exh 
[...]
+    "storeExtractedSecretKeyAsHeader": { "index": 20, "kind": "property", 
"displayName": "Store Extracted Secret Key As Header", "group": "advanced", 
"label": "advanced", "required": false, "type": "boolean", "javaType": 
"boolean", "deprecated": false, "deprecationNote": "", "autowired": false, 
"secret": false, "defaultValue": false, "configurationClass": 
"org.apache.camel.component.pqc.PQCConfiguration", "configurationField": 
"configuration", "description": "In the context of extractSec [...]
+    "strictKeyLifecycle": { "index": 21, "kind": "property", "displayName": 
"Strict Key Lifecycle", "group": "advanced", "label": "advanced", "required": 
false, "type": "boolean", "javaType": "boolean", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "defaultValue": 
true, "configurationClass": "org.apache.camel.component.pqc.PQCConfiguration", 
"configurationField": "configuration", "description": "Whether to enforce key 
status checks before cryptographic  [...]
+    "symmetricKeyAlgorithm": { "index": 22, "kind": "property", "displayName": 
"Symmetric Key Algorithm", "group": "advanced", "label": "advanced", 
"required": false, "type": "enum", "javaType": "java.lang.String", "enum": [ 
"AES", "ARIA", "RC2", "RC5", "CAMELLIA", "CAST5", "CAST6", "CHACHA7539", 
"DSTU7624", "GOST28147", "GOST3412_2015", "GRAIN128", "HC128", "HC256", 
"SALSA20", "SEED", "SM4", "DESEDE" ], "deprecated": false, "deprecationNote": 
"", "autowired": false, "secret": false, "co [...]
+    "symmetricKeyLength": { "index": 23, "kind": "property", "displayName": 
"Symmetric Key Length", "group": "advanced", "label": "advanced", "required": 
false, "type": "integer", "javaType": "int", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "defaultValue": 
128, "configurationClass": "org.apache.camel.component.pqc.PQCConfiguration", 
"configurationField": "configuration", "description": "The required length of 
the symmetric key used" },
+    "healthCheckConsumerEnabled": { "index": 24, "kind": "property", 
"displayName": "Health Check Consumer Enabled", "group": "health", "label": 
"health", "required": false, "type": "boolean", "javaType": "boolean", 
"deprecated": false, "autowired": false, "secret": false, "defaultValue": true, 
"description": "Used for enabling or disabling all consumer based health checks 
from this component" },
+    "healthCheckProducerEnabled": { "index": 25, "kind": "property", 
"displayName": "Health Check Producer Enabled", "group": "health", "label": 
"health", "required": false, "type": "boolean", "javaType": "boolean", 
"deprecated": false, "autowired": false, "secret": false, "defaultValue": true, 
"description": "Used for enabling or disabling all producer based health checks 
from this component. Notice: Camel has by default disabled all producer based 
health-checks. You can turn on produce [...]
   },
   "headers": {
     "CamelPQCOperation": { "index": 0, "kind": "header", "displayName": "", 
"group": "producer", "label": "", "required": false, "javaType": "String", 
"deprecated": false, "deprecationNote": "", "autowired": false, "secret": 
false, "description": "The operation we want to perform", "constantName": 
"org.apache.camel.component.pqc.PQCConstants#OPERATION" },
@@ -94,9 +95,10 @@
     "keyStorePassword": { "index": 15, "kind": "parameter", "displayName": 
"Key Store Password", "group": "advanced", "label": "advanced", "required": 
false, "type": "string", "javaType": "java.lang.String", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": true, 
"configurationClass": "org.apache.camel.component.pqc.PQCConfiguration", 
"configurationField": "configuration", "description": "The KeyStore password to 
use in combination with KeyStore Parameter" },
     "signatureAlgorithm": { "index": 16, "kind": "parameter", "displayName": 
"Signature Algorithm", "group": "advanced", "label": "advanced", "required": 
false, "type": "enum", "javaType": "java.lang.String", "enum": [ "MLDSA", 
"SLHDSA", "LMS", "HSS", "XMSS", "XMSSMT", "DILITHIUM", "FALCON", "PICNIC", 
"SNOVA", "MAYO", "SPHINCSPLUS" ], "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "configurationClass": 
"org.apache.camel.component.pqc.PQCConfiguration", " [...]
     "signer": { "index": 17, "kind": "parameter", "displayName": "Signer", 
"group": "advanced", "label": "advanced", "required": false, "type": "object", 
"javaType": "java.security.Signature", "deprecated": false, "deprecationNote": 
"", "autowired": true, "secret": false, "configurationClass": 
"org.apache.camel.component.pqc.PQCConfiguration", "configurationField": 
"configuration", "description": "The Signer to be used" },
-    "storeExtractedSecretKeyAsHeader": { "index": 18, "kind": "parameter", 
"displayName": "Store Extracted Secret Key As Header", "group": "advanced", 
"label": "advanced", "required": false, "type": "boolean", "javaType": 
"boolean", "deprecated": false, "deprecationNote": "", "autowired": false, 
"secret": false, "defaultValue": false, "configurationClass": 
"org.apache.camel.component.pqc.PQCConfiguration", "configurationField": 
"configuration", "description": "In the context of extractSe [...]
-    "strictKeyLifecycle": { "index": 19, "kind": "parameter", "displayName": 
"Strict Key Lifecycle", "group": "advanced", "label": "advanced", "required": 
false, "type": "boolean", "javaType": "boolean", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "defaultValue": 
true, "configurationClass": "org.apache.camel.component.pqc.PQCConfiguration", 
"configurationField": "configuration", "description": "Whether to enforce key 
status checks before cryptographic [...]
-    "symmetricKeyAlgorithm": { "index": 20, "kind": "parameter", 
"displayName": "Symmetric Key Algorithm", "group": "advanced", "label": 
"advanced", "required": false, "type": "enum", "javaType": "java.lang.String", 
"enum": [ "AES", "ARIA", "RC2", "RC5", "CAMELLIA", "CAST5", "CAST6", 
"CHACHA7539", "DSTU7624", "GOST28147", "GOST3412_2015", "GRAIN128", "HC128", 
"HC256", "SALSA20", "SEED", "SM4", "DESEDE" ], "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "c [...]
-    "symmetricKeyLength": { "index": 21, "kind": "parameter", "displayName": 
"Symmetric Key Length", "group": "advanced", "label": "advanced", "required": 
false, "type": "integer", "javaType": "int", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "defaultValue": 
128, "configurationClass": "org.apache.camel.component.pqc.PQCConfiguration", 
"configurationField": "configuration", "description": "The required length of 
the symmetric key used" }
+    "statefulKeyWarningThreshold": { "index": 18, "kind": "parameter", 
"displayName": "Stateful Key Warning Threshold", "group": "advanced", "label": 
"advanced", "required": false, "type": "number", "javaType": "double", 
"deprecated": false, "deprecationNote": "", "autowired": false, "secret": 
false, "defaultValue": 0.1, "configurationClass": 
"org.apache.camel.component.pqc.PQCConfiguration", "configurationField": 
"configuration", "description": "The warning threshold for stateful key ex [...]
+    "storeExtractedSecretKeyAsHeader": { "index": 19, "kind": "parameter", 
"displayName": "Store Extracted Secret Key As Header", "group": "advanced", 
"label": "advanced", "required": false, "type": "boolean", "javaType": 
"boolean", "deprecated": false, "deprecationNote": "", "autowired": false, 
"secret": false, "defaultValue": false, "configurationClass": 
"org.apache.camel.component.pqc.PQCConfiguration", "configurationField": 
"configuration", "description": "In the context of extractSe [...]
+    "strictKeyLifecycle": { "index": 20, "kind": "parameter", "displayName": 
"Strict Key Lifecycle", "group": "advanced", "label": "advanced", "required": 
false, "type": "boolean", "javaType": "boolean", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "defaultValue": 
true, "configurationClass": "org.apache.camel.component.pqc.PQCConfiguration", 
"configurationField": "configuration", "description": "Whether to enforce key 
status checks before cryptographic [...]
+    "symmetricKeyAlgorithm": { "index": 21, "kind": "parameter", 
"displayName": "Symmetric Key Algorithm", "group": "advanced", "label": 
"advanced", "required": false, "type": "enum", "javaType": "java.lang.String", 
"enum": [ "AES", "ARIA", "RC2", "RC5", "CAMELLIA", "CAST5", "CAST6", 
"CHACHA7539", "DSTU7624", "GOST28147", "GOST3412_2015", "GRAIN128", "HC128", 
"HC256", "SALSA20", "SEED", "SM4", "DESEDE" ], "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "c [...]
+    "symmetricKeyLength": { "index": 22, "kind": "parameter", "displayName": 
"Symmetric Key Length", "group": "advanced", "label": "advanced", "required": 
false, "type": "integer", "javaType": "int", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "defaultValue": 
128, "configurationClass": "org.apache.camel.component.pqc.PQCConfiguration", 
"configurationField": "configuration", "description": "The required length of 
the symmetric key used" }
   }
 }
diff --git 
a/components/camel-pqc/src/main/java/org/apache/camel/component/pqc/PQCConfiguration.java
 
b/components/camel-pqc/src/main/java/org/apache/camel/component/pqc/PQCConfiguration.java
index 938e2f706866..bfac40af1cb2 100644
--- 
a/components/camel-pqc/src/main/java/org/apache/camel/component/pqc/PQCConfiguration.java
+++ 
b/components/camel-pqc/src/main/java/org/apache/camel/component/pqc/PQCConfiguration.java
@@ -114,6 +114,14 @@ public class PQCConfiguration implements Cloneable {
     @Metadata(label = "advanced")
     private boolean strictKeyLifecycle = true;
 
+    @UriParam(defaultValue = "0.1",
+              description = "The warning threshold for stateful key exhaustion 
as a fraction of total signatures (0.0 to 1.0). "
+                            + "When the remaining signatures for a stateful 
key (XMSS, XMSSMT, LMS/HSS) drop below this "
+                            + "fraction of the total capacity, a WARN log is 
emitted. When remaining signatures reach zero, "
+                            + "an exception is thrown to prevent key reuse. 
Set to 0 to disable warnings.")
+    @Metadata(label = "advanced")
+    private double statefulKeyWarningThreshold = 0.1;
+
     public PQCOperations getOperation() {
         return operation;
     }
@@ -339,6 +347,20 @@ public class PQCConfiguration implements Cloneable {
         this.strictKeyLifecycle = strictKeyLifecycle;
     }
 
+    public double getStatefulKeyWarningThreshold() {
+        return statefulKeyWarningThreshold;
+    }
+
+    /**
+     * The warning threshold for stateful key exhaustion as a fraction of 
total signatures (0.0 to 1.0). When the
+     * remaining signatures for a stateful key (XMSS, XMSSMT, LMS/HSS) drop 
below this fraction of the total capacity, a
+     * WARN log is emitted. When remaining signatures reach zero, an exception 
is thrown to prevent key reuse. Set to 0
+     * to disable warnings.
+     */
+    public void setStatefulKeyWarningThreshold(double 
statefulKeyWarningThreshold) {
+        this.statefulKeyWarningThreshold = statefulKeyWarningThreshold;
+    }
+
     // *************************************************
     //
     // *************************************************
diff --git 
a/components/camel-pqc/src/main/java/org/apache/camel/component/pqc/PQCProducer.java
 
b/components/camel-pqc/src/main/java/org/apache/camel/component/pqc/PQCProducer.java
index d3e7ef4c029a..ed169ae65e7f 100644
--- 
a/components/camel-pqc/src/main/java/org/apache/camel/component/pqc/PQCProducer.java
+++ 
b/components/camel-pqc/src/main/java/org/apache/camel/component/pqc/PQCProducer.java
@@ -36,6 +36,9 @@ import 
org.apache.camel.component.pqc.crypto.hybrid.HybridSignature;
 import org.apache.camel.component.pqc.lifecycle.KeyLifecycleManager;
 import org.apache.camel.component.pqc.lifecycle.KeyMetadata;
 import org.apache.camel.component.pqc.stateful.StatefulKeyState;
+import org.apache.camel.health.HealthCheck;
+import org.apache.camel.health.HealthCheckHelper;
+import org.apache.camel.health.WritableHealthCheckRepository;
 import org.apache.camel.support.DefaultProducer;
 import org.apache.camel.util.ObjectHelper;
 import org.bouncycastle.jcajce.SecretKeyWithEncapsulation;
@@ -108,6 +111,10 @@ public class PQCProducer extends DefaultProducer {
     private KeyAgreement classicalKeyAgreement;
     private KeyPair classicalKeyPair;
 
+    // Health check fields
+    private HealthCheck producerHealthCheck;
+    private WritableHealthCheckRepository healthCheckRepository;
+
     public PQCProducer(Endpoint endpoint) {
         super(endpoint);
     }
@@ -381,10 +388,34 @@ public class PQCProducer extends DefaultProducer {
             // Initialize classical key pair
             classicalKeyPair = getConfiguration().getClassicalKeyPair();
         }
+
+        // Register health check for stateful key monitoring
+        healthCheckRepository = HealthCheckHelper.getHealthCheckRepository(
+                getEndpoint().getCamelContext(),
+                "producers",
+                WritableHealthCheckRepository.class);
+
+        if (ObjectHelper.isNotEmpty(healthCheckRepository)) {
+            String id = getEndpoint().getId();
+            producerHealthCheck = new PQCStatefulKeyHealthCheck(getEndpoint(), 
id);
+            
producerHealthCheck.setEnabled(getEndpoint().getComponent().isHealthCheckProducerEnabled());
+            healthCheckRepository.addHealthCheck(producerHealthCheck);
+        }
+    }
+
+    @Override
+    protected void doStop() throws Exception {
+        if (ObjectHelper.isNotEmpty(healthCheckRepository) && 
ObjectHelper.isNotEmpty(producerHealthCheck)) {
+            healthCheckRepository.removeHealthCheck(producerHealthCheck);
+            producerHealthCheck = null;
+        }
+        super.doStop();
     }
 
     private void signature(Exchange exchange)
-            throws InvalidPayloadException, InvalidKeyException, 
SignatureException {
+            throws Exception {
+        checkStatefulKeyBeforeSign();
+
         String payload = exchange.getMessage().getMandatoryBody(String.class);
 
         signer.initSign(keyPair.getPrivate());
@@ -392,6 +423,8 @@ public class PQCProducer extends DefaultProducer {
 
         byte[] signature = signer.sign();
         exchange.getMessage().setHeader(PQCConstants.SIGNATURE, signature);
+
+        persistStatefulKeyStateAfterSign(exchange);
     }
 
     private void verification(Exchange exchange)
@@ -812,6 +845,112 @@ public class PQCProducer extends DefaultProducer {
         }
     }
 
+    /**
+     * Checks whether the current key is a stateful signature key (XMSS, 
XMSSMT, LMS/HSS) and if so, validates that it
+     * has remaining signatures available. Logs a warning when remaining 
signatures fall below the configured threshold.
+     *
+     * @throws IllegalStateException if the key has zero remaining signatures
+     */
+    private void checkStatefulKeyBeforeSign() {
+        if (keyPair == null || keyPair.getPrivate() == null) {
+            return;
+        }
+
+        PrivateKey privateKey = keyPair.getPrivate();
+        long remaining = getStatefulKeyRemaining(privateKey);
+        if (remaining < 0) {
+            // Not a stateful key
+            return;
+        }
+
+        if (remaining <= 0) {
+            throw new IllegalStateException(
+                    "Stateful key (" + privateKey.getAlgorithm() + ") is 
exhausted with 0 remaining signatures. "
+                                            + "The key must not be reused — 
generate a new key pair.");
+        }
+
+        double threshold = getConfiguration().getStatefulKeyWarningThreshold();
+        if (threshold > 0) {
+            long totalCapacity = getStatefulKeyIndex(privateKey) + remaining;
+            if (totalCapacity > 0) {
+                double fractionRemaining = (double) remaining / totalCapacity;
+                if (fractionRemaining <= threshold) {
+                    LOG.warn(
+                            "Stateful key ({}) is approaching exhaustion: {} 
signatures remaining out of {} total ({} remaining). "
+                             + "Consider generating a new key pair.",
+                            privateKey.getAlgorithm(), remaining, 
totalCapacity,
+                            String.format("%.1f%%", fractionRemaining * 100));
+                }
+            }
+        }
+    }
+
+    /**
+     * Persists stateful key state after a signing operation through the 
KeyLifecycleManager, if configured. This
+     * ensures the key index is tracked across restarts.
+     */
+    private void persistStatefulKeyStateAfterSign(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;
+        }
+
+        KeyLifecycleManager klm = getConfiguration().getKeyLifecycleManager();
+        if (klm == null) {
+            return;
+        }
+
+        String keyId = exchange.getMessage().getHeader(PQCConstants.KEY_ID, 
String.class);
+        if (ObjectHelper.isEmpty(keyId)) {
+            return;
+        }
+
+        // Update metadata with current usage
+        KeyMetadata metadata = klm.getKeyMetadata(keyId);
+        if (metadata != null) {
+            metadata.updateLastUsed();
+            klm.updateKeyMetadata(keyId, metadata);
+        }
+
+        // Persist the updated key (with new index) so state survives restarts
+        klm.storeKey(keyId, keyPair, metadata);
+    }
+
+    /**
+     * Returns the remaining signatures for a stateful private key, or -1 if 
the key is not stateful.
+     */
+    private long getStatefulKeyRemaining(PrivateKey privateKey) {
+        if (privateKey instanceof XMSSPrivateKey) {
+            return ((XMSSPrivateKey) privateKey).getUsagesRemaining();
+        } else if (privateKey instanceof XMSSMTPrivateKey) {
+            return ((XMSSMTPrivateKey) privateKey).getUsagesRemaining();
+        } else if (privateKey instanceof LMSPrivateKey) {
+            return ((LMSPrivateKey) privateKey).getUsagesRemaining();
+        }
+        return -1;
+    }
+
+    /**
+     * Returns the current index (number of signatures already produced) for a 
stateful private key, or 0 if the key is
+     * not stateful.
+     */
+    private long getStatefulKeyIndex(PrivateKey privateKey) {
+        if (privateKey instanceof XMSSPrivateKey) {
+            return ((XMSSPrivateKey) privateKey).getIndex();
+        } else if (privateKey instanceof XMSSMTPrivateKey) {
+            return ((XMSSMTPrivateKey) privateKey).getIndex();
+        } else if (privateKey instanceof LMSPrivateKey) {
+            return ((LMSPrivateKey) privateKey).getIndex();
+        }
+        return 0;
+    }
+
     // ========== Configuration Validation ==========
 
     /**
diff --git 
a/components/camel-pqc/src/main/java/org/apache/camel/component/pqc/PQCStatefulKeyHealthCheck.java
 
b/components/camel-pqc/src/main/java/org/apache/camel/component/pqc/PQCStatefulKeyHealthCheck.java
new file mode 100644
index 000000000000..23acc4e43a6c
--- /dev/null
+++ 
b/components/camel-pqc/src/main/java/org/apache/camel/component/pqc/PQCStatefulKeyHealthCheck.java
@@ -0,0 +1,103 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.pqc;
+
+import java.security.KeyPair;
+import java.security.PrivateKey;
+import java.util.Map;
+
+import org.apache.camel.health.HealthCheckResultBuilder;
+import org.apache.camel.impl.health.AbstractHealthCheck;
+import org.bouncycastle.pqc.jcajce.interfaces.LMSPrivateKey;
+import org.bouncycastle.pqc.jcajce.interfaces.XMSSMTPrivateKey;
+import org.bouncycastle.pqc.jcajce.interfaces.XMSSPrivateKey;
+
+/**
+ * Health check that reports the state of stateful PQC signature keys (XMSS, 
XMSSMT, LMS/HSS). These hash-based
+ * signature schemes have a finite number of signatures. This health check 
reports DOWN when a key is exhausted and
+ * includes remaining signature capacity as a detail.
+ */
+public class PQCStatefulKeyHealthCheck extends AbstractHealthCheck {
+
+    private final PQCEndpoint endpoint;
+
+    public PQCStatefulKeyHealthCheck(PQCEndpoint endpoint, String clientId) {
+        super("camel", "producer:pqc-stateful-key-" + clientId);
+        this.endpoint = endpoint;
+    }
+
+    @Override
+    protected void doCall(HealthCheckResultBuilder builder, Map<String, 
Object> options) {
+        PQCConfiguration configuration = endpoint.getConfiguration();
+        KeyPair keyPair = configuration.getKeyPair();
+
+        if (keyPair == null || keyPair.getPrivate() == null) {
+            builder.detail("stateful_key", false);
+            builder.up();
+            return;
+        }
+
+        PrivateKey privateKey = keyPair.getPrivate();
+        long remaining = -1;
+        long index = 0;
+        String algorithm = privateKey.getAlgorithm();
+
+        if (privateKey instanceof XMSSPrivateKey) {
+            XMSSPrivateKey xmssKey = (XMSSPrivateKey) privateKey;
+            remaining = xmssKey.getUsagesRemaining();
+            index = xmssKey.getIndex();
+        } else if (privateKey instanceof XMSSMTPrivateKey) {
+            XMSSMTPrivateKey xmssmtKey = (XMSSMTPrivateKey) privateKey;
+            remaining = xmssmtKey.getUsagesRemaining();
+            index = xmssmtKey.getIndex();
+        } else if (privateKey instanceof LMSPrivateKey) {
+            LMSPrivateKey lmsKey = (LMSPrivateKey) privateKey;
+            remaining = lmsKey.getUsagesRemaining();
+            index = lmsKey.getIndex();
+        }
+
+        if (remaining < 0) {
+            // Not a stateful key - always healthy
+            builder.detail("stateful_key", false);
+            builder.detail("algorithm", algorithm);
+            builder.up();
+            return;
+        }
+
+        builder.detail("stateful_key", true);
+        builder.detail("algorithm", algorithm);
+        builder.detail("remaining_signatures", remaining);
+        builder.detail("signatures_used", index);
+        builder.detail("total_capacity", index + remaining);
+
+        if (remaining <= 0) {
+            builder.message("Stateful key (" + algorithm + ") is exhausted 
with 0 remaining signatures");
+            builder.down();
+            return;
+        }
+
+        double threshold = configuration.getStatefulKeyWarningThreshold();
+        long totalCapacity = index + remaining;
+        if (threshold > 0 && totalCapacity > 0) {
+            double fractionRemaining = (double) remaining / totalCapacity;
+            builder.detail("fraction_remaining", String.format("%.4f", 
fractionRemaining));
+            builder.detail("warning_threshold", String.valueOf(threshold));
+        }
+
+        builder.up();
+    }
+}
diff --git 
a/components/camel-pqc/src/test/java/org/apache/camel/component/pqc/PQCStatefulKeyTrackingTest.java
 
b/components/camel-pqc/src/test/java/org/apache/camel/component/pqc/PQCStatefulKeyTrackingTest.java
new file mode 100644
index 000000000000..fc7c133e96dd
--- /dev/null
+++ 
b/components/camel-pqc/src/test/java/org/apache/camel/component/pqc/PQCStatefulKeyTrackingTest.java
@@ -0,0 +1,194 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.pqc;
+
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.SecureRandom;
+import java.security.Security;
+import java.security.Signature;
+
+import org.apache.camel.BindToRegistry;
+import org.apache.camel.EndpointInject;
+import org.apache.camel.Produce;
+import org.apache.camel.ProducerTemplate;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.camel.component.pqc.stateful.StatefulKeyState;
+import org.apache.camel.test.junit6.CamelTestSupport;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+import org.bouncycastle.pqc.jcajce.provider.BouncyCastlePQCProvider;
+import org.bouncycastle.pqc.jcajce.spec.XMSSParameterSpec;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+/**
+ * Tests for stateful key usage tracking with XMSS. Uses a very small tree 
height (2) so the key has only 4 total
+ * signatures, making it feasible to test exhaustion and threshold warnings.
+ */
+public class PQCStatefulKeyTrackingTest extends CamelTestSupport {
+
+    @EndpointInject("mock:signed")
+    protected MockEndpoint resultSigned;
+
+    @EndpointInject("mock:state")
+    protected MockEndpoint resultState;
+
+    @Produce("direct:sign")
+    protected ProducerTemplate templateSign;
+
+    @Produce("direct:getState")
+    protected ProducerTemplate templateGetState;
+
+    public PQCStatefulKeyTrackingTest() throws NoSuchAlgorithmException {
+    }
+
+    private static void ensureProviders() {
+        if (Security.getProvider(BouncyCastleProvider.PROVIDER_NAME) == null) {
+            Security.addProvider(new BouncyCastleProvider());
+        }
+        if (Security.getProvider(BouncyCastlePQCProvider.PROVIDER_NAME) == 
null) {
+            Security.addProvider(new BouncyCastlePQCProvider());
+        }
+    }
+
+    @Override
+    protected RouteBuilder createRouteBuilder() {
+        return new RouteBuilder() {
+            @Override
+            public void configure() {
+                from("direct:sign")
+                        
.to("pqc:sign?operation=sign&statefulKeyWarningThreshold=0.5")
+                        .to("mock:signed");
+
+                from("direct:getState")
+                        .to("pqc:state?operation=getKeyState")
+                        .to("mock:state");
+            }
+        };
+    }
+
+    @BindToRegistry("Keypair")
+    public KeyPair setKeyPair() throws Exception {
+        ensureProviders();
+        KeyPairGenerator kpGen = KeyPairGenerator.getInstance(
+                PQCSignatureAlgorithms.XMSS.getAlgorithm(),
+                PQCSignatureAlgorithms.XMSS.getBcProvider());
+        kpGen.initialize(new XMSSParameterSpec(2, XMSSParameterSpec.SHA256), 
new SecureRandom());
+        return kpGen.generateKeyPair();
+    }
+
+    @BindToRegistry("Signer")
+    public Signature getSigner() throws NoSuchAlgorithmException, 
NoSuchProviderException {
+        ensureProviders();
+        return Signature.getInstance(
+                PQCSignatureAlgorithms.XMSS.getAlgorithm(),
+                PQCSignatureAlgorithms.XMSS.getBcProvider());
+    }
+
+    @Test
+    void testSignDecreasesRemainingSignatures() throws Exception {
+        // Get initial state
+        resultState.expectedMessageCount(1);
+        templateGetState.sendBody("check");
+        resultState.assertIsSatisfied();
+
+        StatefulKeyState initialState = resultState.getExchanges().get(0)
+                .getMessage().getHeader(PQCConstants.KEY_STATE, 
StatefulKeyState.class);
+        assertNotNull(initialState);
+        long initialRemaining = initialState.getUsagesRemaining();
+        assertTrue(initialRemaining > 0, "Initial key should have remaining 
signatures");
+
+        // Sign once
+        resultSigned.expectedMessageCount(1);
+        templateSign.sendBody("Hello");
+        resultSigned.assertIsSatisfied();
+
+        // Get state after signing
+        resultState.reset();
+        resultState.expectedMessageCount(1);
+        templateGetState.sendBody("check");
+        resultState.assertIsSatisfied();
+
+        StatefulKeyState afterState = resultState.getExchanges().get(0)
+                .getMessage().getHeader(PQCConstants.KEY_STATE, 
StatefulKeyState.class);
+        assertNotNull(afterState);
+        assertEquals(initialRemaining - 1, afterState.getUsagesRemaining(),
+                "Remaining signatures should decrease by 1 after signing");
+    }
+
+    @Test
+    void testKeyExhaustion() throws Exception {
+        ensureProviders();
+
+        // Create a fresh key with height=2 (4 signatures)
+        KeyPairGenerator kpGen = KeyPairGenerator.getInstance(
+                PQCSignatureAlgorithms.XMSS.getAlgorithm(),
+                PQCSignatureAlgorithms.XMSS.getBcProvider());
+        kpGen.initialize(new XMSSParameterSpec(2, XMSSParameterSpec.SHA256), 
new SecureRandom());
+        KeyPair exhaustionKeyPair = kpGen.generateKeyPair();
+
+        // Sign 4 times to exhaust the key
+        Signature xmssSigner = Signature.getInstance(
+                PQCSignatureAlgorithms.XMSS.getAlgorithm(),
+                PQCSignatureAlgorithms.XMSS.getBcProvider());
+
+        for (int i = 0; i < 4; i++) {
+            xmssSigner.initSign(exhaustionKeyPair.getPrivate());
+            xmssSigner.update(("message" + i).getBytes());
+            xmssSigner.sign();
+        }
+
+        // Now the key should be exhausted
+        org.bouncycastle.pqc.jcajce.interfaces.XMSSPrivateKey xmssPriv
+                = (org.bouncycastle.pqc.jcajce.interfaces.XMSSPrivateKey) 
exhaustionKeyPair.getPrivate();
+        assertEquals(0, xmssPriv.getUsagesRemaining(), "Key should be 
exhausted after 4 signatures with height=2");
+    }
+
+    @Test
+    void testStatefulKeyStateNotExhausted() throws Exception {
+        ensureProviders();
+
+        KeyPairGenerator kpGen = KeyPairGenerator.getInstance(
+                PQCSignatureAlgorithms.XMSS.getAlgorithm(),
+                PQCSignatureAlgorithms.XMSS.getBcProvider());
+        kpGen.initialize(new XMSSParameterSpec(2, XMSSParameterSpec.SHA256), 
new SecureRandom());
+        KeyPair freshKeyPair = kpGen.generateKeyPair();
+
+        org.bouncycastle.pqc.jcajce.interfaces.XMSSPrivateKey xmssPriv
+                = (org.bouncycastle.pqc.jcajce.interfaces.XMSSPrivateKey) 
freshKeyPair.getPrivate();
+
+        StatefulKeyState state = new StatefulKeyState(
+                xmssPriv.getAlgorithm(), xmssPriv.getIndex(), 
xmssPriv.getUsagesRemaining());
+
+        assertFalse(state.isExhausted(), "Fresh key should not be exhausted");
+        assertEquals(4, state.getUsagesRemaining(), "Fresh XMSS key with 
height=2 should have 4 remaining");
+        assertEquals(0, state.getIndex(), "Fresh key should have index 0");
+    }
+
+    @Test
+    void testStatefulKeyStateExhausted() {
+        StatefulKeyState state = new StatefulKeyState("XMSS", 4, 0);
+
+        assertTrue(state.isExhausted(), "Key with 0 remaining should be 
exhausted");
+        assertEquals(0, state.getUsagesRemaining());
+        assertEquals(4, state.getIndex());
+    }
+}
diff --git 
a/dsl/camel-componentdsl/src/generated/java/org/apache/camel/builder/component/dsl/PqcComponentBuilderFactory.java
 
b/dsl/camel-componentdsl/src/generated/java/org/apache/camel/builder/component/dsl/PqcComponentBuilderFactory.java
index ef5b2cd6758c..6d9dbb4f6003 100644
--- 
a/dsl/camel-componentdsl/src/generated/java/org/apache/camel/builder/component/dsl/PqcComponentBuilderFactory.java
+++ 
b/dsl/camel-componentdsl/src/generated/java/org/apache/camel/builder/component/dsl/PqcComponentBuilderFactory.java
@@ -371,6 +371,28 @@ public interface PqcComponentBuilderFactory {
         }
     
         
+        /**
+         * The warning threshold for stateful key exhaustion as a fraction of
+         * total signatures (0.0 to 1.0). When the remaining signatures for a
+         * stateful key (XMSS, XMSSMT, LMS/HSS) drop below this fraction of the
+         * total capacity, a WARN log is emitted. When remaining signatures
+         * reach zero, an exception is thrown to prevent key reuse. Set to 0 to
+         * disable warnings.
+         * 
+         * The option is a: &lt;code&gt;double&lt;/code&gt; type.
+         * 
+         * Default: 0.1
+         * Group: advanced
+         * 
+         * @param statefulKeyWarningThreshold the value to set
+         * @return the dsl builder
+         */
+        default PqcComponentBuilder statefulKeyWarningThreshold(double 
statefulKeyWarningThreshold) {
+            doSetProperty("statefulKeyWarningThreshold", 
statefulKeyWarningThreshold);
+            return this;
+        }
+    
+        
         /**
          * In the context of extractSecretKeyFromEncapsulation operation, this
          * option define if we want to have the key set as header.
@@ -520,6 +542,7 @@ public interface PqcComponentBuilderFactory {
             case "keyStorePassword": getOrCreateConfiguration((PQCComponent) 
component).setKeyStorePassword((java.lang.String) value); return true;
             case "signatureAlgorithm": getOrCreateConfiguration((PQCComponent) 
component).setSignatureAlgorithm((java.lang.String) value); return true;
             case "signer": getOrCreateConfiguration((PQCComponent) 
component).setSigner((java.security.Signature) value); return true;
+            case "statefulKeyWarningThreshold": 
getOrCreateConfiguration((PQCComponent) 
component).setStatefulKeyWarningThreshold((double) value); return true;
             case "storeExtractedSecretKeyAsHeader": 
getOrCreateConfiguration((PQCComponent) 
component).setStoreExtractedSecretKeyAsHeader((boolean) value); return true;
             case "strictKeyLifecycle": getOrCreateConfiguration((PQCComponent) 
component).setStrictKeyLifecycle((boolean) value); return true;
             case "symmetricKeyAlgorithm": 
getOrCreateConfiguration((PQCComponent) 
component).setSymmetricKeyAlgorithm((java.lang.String) value); return true;
diff --git 
a/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/PQCEndpointBuilderFactory.java
 
b/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/PQCEndpointBuilderFactory.java
index c88f80bcbc4c..b7381219cf05 100644
--- 
a/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/PQCEndpointBuilderFactory.java
+++ 
b/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/PQCEndpointBuilderFactory.java
@@ -476,6 +476,46 @@ public interface PQCEndpointBuilderFactory {
             doSetProperty("signer", signer);
             return this;
         }
+        /**
+         * The warning threshold for stateful key exhaustion as a fraction of
+         * total signatures (0.0 to 1.0). When the remaining signatures for a
+         * stateful key (XMSS, XMSSMT, LMS/HSS) drop below this fraction of the
+         * total capacity, a WARN log is emitted. When remaining signatures
+         * reach zero, an exception is thrown to prevent key reuse. Set to 0 to
+         * disable warnings.
+         * 
+         * The option is a: <code>double</code> type.
+         * 
+         * Default: 0.1
+         * Group: advanced
+         * 
+         * @param statefulKeyWarningThreshold the value to set
+         * @return the dsl builder
+         */
+        default AdvancedPQCEndpointBuilder statefulKeyWarningThreshold(double 
statefulKeyWarningThreshold) {
+            doSetProperty("statefulKeyWarningThreshold", 
statefulKeyWarningThreshold);
+            return this;
+        }
+        /**
+         * The warning threshold for stateful key exhaustion as a fraction of
+         * total signatures (0.0 to 1.0). When the remaining signatures for a
+         * stateful key (XMSS, XMSSMT, LMS/HSS) drop below this fraction of the
+         * total capacity, a WARN log is emitted. When remaining signatures
+         * reach zero, an exception is thrown to prevent key reuse. Set to 0 to
+         * disable warnings.
+         * 
+         * The option will be converted to a <code>double</code> type.
+         * 
+         * Default: 0.1
+         * Group: advanced
+         * 
+         * @param statefulKeyWarningThreshold the value to set
+         * @return the dsl builder
+         */
+        default AdvancedPQCEndpointBuilder statefulKeyWarningThreshold(String 
statefulKeyWarningThreshold) {
+            doSetProperty("statefulKeyWarningThreshold", 
statefulKeyWarningThreshold);
+            return this;
+        }
         /**
          * In the context of extractSecretKeyFromEncapsulation operation, this
          * option define if we want to have the key set as header.

Reply via email to