Andrea Cosentino created CAMEL-25802:
----------------------------------------

             Summary: camel-pqc - align the key material classes on 
SecureRandom, provider names and documented defaults
                 Key: CAMEL-25802
                 URL: https://issues.apache.org/jira/browse/CAMEL-25802
             Project: Camel
          Issue Type: Improvement
          Components: camel-pqc
            Reporter: Andrea Cosentino


The twenty-one {{PQCDefault*Material}} classes were written by cloning each 
other and have drifted. None of the items below is individually serious; 
together they make the module's security-relevant defaults unpredictable and 
undocumented.

h3. 1. Only 6 of 11 signature materials seed with {{SecureRandomHelper}}

Seeded: MLDSA, DILITHIUM, SLHDSA, SPHINCSPLUS, XMSS, XMSSMT. Not seeded — 
Falcon, MAYO, SNOVA, LMS, HSS fall back to the provider default RNG. 
{{PQCDefaultFalconMaterial.java:50-52}}:
{code:java}
        KeyPairGenerator kpGen = 
KeyPairGenerator.getInstance(PQCSignatureAlgorithms.FALCON.getAlgorithm(),
                PQCSignatureAlgorithms.FALCON.getBcProvider());
        kpGen.initialize(FalconParameterSpec.falcon_1024);
{code}
Same at {{PQCDefaultHSSMaterial.java:59}}, {{PQCDefaultLMSMaterial.java:54}}, 
{{PQCDefaultMAYOMaterial.java:52}}, {{PQCDefaultSNOVAMaterial.java:52}}. All 
ten KEM materials do seed. {{SecureRandomHelper}} exists precisely to 
centralise this choice. Note that {{PQCComponent.resolveKeyPair}} ({{:264}}) 
always seeds, so the same algorithm gets a different RNG depending on whether 
{{parameterSpec}} was set.

h3. 2. Aliases of the same algorithm default to different security levels

{{MLKEM("ML-KEM", "BC")}} and {{KYBER("ML-KEM", "BC")}} are the same JCE 
algorithm, yet {{PQCDefaultMLKEMMaterial.java:55}} uses 
{{MLKEMParameterSpec.ml_kem_512}} (NIST level 1) while 
{{PQCDefaultKYBERMaterial.java:55}} uses {{ml_kem_1024}} (level 5), and the 
hybrid materials independently pick {{ml_kem_768}}. The production autowired 
default for the flagship standardised KEM is therefore the weakest of the 
three. The same split exists for {{MLDSA}} ({{ml_dsa_65}}) versus {{DILITHIUM}} 
({{ml_dsa_87}}). None of these levels is documented anywhere.

Related drift across the family with no stated rationale: 
{{CMCEParameterSpec.mceliece8192128f}} (highest), 
{{SABERParameterSpec.lightsaberkem256r3}} and 
{{NTRUParameterSpec.ntruhps2048509}} (lowest), versus {{bike192}} / {{hqc192}} 
/ {{frodokem976aes}} (middle). {{PQCDefaultLMSMaterial}} uses 
{{LMOtsParameters.sha256_n32_w1}} while {{PQCDefaultHSSMaterial.java:56}} uses 
{{w2}} for the same underlying scheme, and the LMS default 
{{lms_sha256_n32_h5}} is a height-5 tree, i.e. *32 signatures* before permanent 
exhaustion.

h3. 3. Residual {{BCPQC}} provider strings

Twelve enum constants still name {{"BCPQC"}} — 
{{PQCSignatureAlgorithms.java:26-27}}:
{code:java}
    XMSS("XMSS", "BCPQC"),
    XMSSMT("XMSSMT", "BCPQC"),
{code}
plus FALCON/SNOVA/MAYO and six KEM constants — mixed with {{"BC"}} for the 
rest, with no principle distinguishing them. (They resolve identically in 
Bouncy Castle 1.86, so this is cosmetic, but it is arbitrary.) There are also 
six hardcoded {{"BC"}} literals in the hybrid materials, and 
{{HybridKEM.java:293}} / {{PQCProducer.java:452,481}} resolve classical 
primitives with no provider at all, so one hybrid exchange can mix 
SunEC-produced keys with BC objects. No shared provider constant exists in 
{{PQCConstants}}.

h3. 4. {{DILITHIUM}} and {{SPHINCSPLUS}} get a factually wrong warning

{{PQCProducer.java:96-103}} puts both in {{NON_FIPS_PQ_SIGNATURES}}, which 
drives {{PQCProducer.java:1280}}:
{code:java}
                LOG.warn("PQC signature algorithm {} is not part of NIST FIPS 
204/205. Consider using "
                         + "ML-DSA (FIPS 204) or SLH-DSA (FIPS 205) for 
production hybrid deployments.",
{code}
But {{PQCSignatureAlgorithms.java:28,34}} are {{DILITHIUM("ML-DSA", "BC")}} and 
{{SPHINCSPLUS("SLH-DSA", "BC")}} — they already *are* the FIPS 204/205 
algorithms the warning recommends. The module knows this: 
{{PQCParameterSpecResolver.java:117}} says "DILITHIUM and SPHINCSPLUS generate 
ML-DSA and SLH-DSA keys". Either drop them from the set or warn that the name 
is a deprecated alias.

h3. 5. {{parameterSpec}} is refused for MAYO and SNOVA on a premise that is not 
true for BC 1.86

{{PQCParameterSpecResolver.java:43-45}}:
{code:java}
 * algorithms (XMSS, XMSSMT, LMS, HSS) and MAYO/SNOVA have no name-addressable 
BouncyCastle parameter spec and are
 * therefore not supported here
{code}
Verified against {{bcprov-jdk18on-1.86.jar}}: both {{MayoParameterSpec}} and 
{{SnovaParameterSpec}} declare {{public static ... 
fromName(java.lang.String)}}. The claim is correct for XMSS/XMSSMT/LMS/HSS 
({{XMSSParameterSpec}} has no {{fromName}}) but wrong for MAYO/SNOVA, which are 
not stateful. {{PQCParameterSpecResolverTest.java:115}} enshrines the wrong 
premise with {{assertFalse(PQCParameterSpecResolver.isSupported("MAYO"));}}.

h3. 6. {{label}} is a required URI path option that can never be bound

{{PQCConfiguration.java:36-38}}:
{code:java}
    @UriPath(description = "Logical name")
    @Metadata(required = true)
    private String label;
{code}
There is no {{getLabel}} or {{setLabel}} anywhere in the module, and 
{{PQCComponent.createEndpoint}} ({{:85-89}}) never uses its {{remaining}} 
argument. The generated {{pqc.json}} emits it as {{"kind": "path", "required": 
true}} and {{PQCEndpointUriFactory}} builds it, but nothing ever reads it.

h3. 7. Observability and Javadoc gaps

{{PQCProducer.java:233}} is the only {{recordOperation}} call site in the 
module; {{PQCDataFormat}}, {{KeyRotationScheduler}} and all five 
{{KeyLifecycleManager}} implementations have no metrics at all, so key 
generation, rotation and storage are unobserved. Twenty-three public classes 
have no class-level Javadoc (all 21 material classes, {{PQCConfiguration}}, 
{{KeyMetadataCodec}}) while every hybrid class, enum and lifecycle manager is 
documented.

h3. Suggested direction

Most of this collapses if the clone-and-tweak material classes are replaced by 
one parameterised factory driven by {{PQCParameterSpecResolver}}: that removes 
the SecureRandom split, the undocumented level drift and the missing Javadoc in 
one change, and it makes the "add a new algorithm" path a single registration 
instead of a new file plus two switch arms.

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