Skip to content

JCA TLS path doesn't validate PQC signatureScheme against certificate key OID #2278

@programsurf

Description

@programsurf

Hi, the BC lightweight TLS path (BcTlsRawKeyCertificate) correctly validates that the CertificateVerify signatureScheme matches the certificate's key algorithm OID, but the JCA TLS path (JcaTlsCertificate) skips this check for ML-DSA and SLH-DSA.

JCA path (JcaTlsCertificate.java:277-280) — no validation:

case SignatureScheme.mldsa44:
case SignatureScheme.mldsa65:
case SignatureScheme.mldsa87:
    return crypto.createTls13Verifier("ML-DSA", null, getPubKeyMLDSA());

BC lightweight path (BcTlsRawKeyCertificate.java:256-262) — validates:

case SignatureScheme.mldsa44:
case SignatureScheme.mldsa65:
case SignatureScheme.mldsa87:
{
    ASN1ObjectIdentifier mlDsaAlgOid = PQCUtil.getMLDSAObjectidentifier(signatureScheme);
    validateMLDSA(mlDsaAlgOid);  // checks key OID matches scheme
    // ...
}

The same asymmetry exists for all 12 SLH-DSA schemes (lines 281-294).

This isn't exploitable — signature length differences between SLH-DSA parameter sets (e.g. 7,856 bytes for 128s vs 49,856 for 256s) and hash binding in the key parameters prevent cross-parameter forgery. But it's a RFC 8446 §4.4.3 compliance gap, and the fix is straightforward: add validateMLDSA()/validateSLHDSA() calls to JcaTlsCertificate.createVerifier() matching BcTlsRawKeyCertificate's pattern.

Looks like the validation was implemented for the BC lightweight path but missed for the JCA path when PQC TLS support was added.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions