Skip to content

ML-DSA SignatureSpi.verifyInit() ClassCastException with non-BC public keys due to pqc/crypto package type mismatch #2287

@bakajstep

Description

@bakajstep

Bouncy Castle version: 1.84 (bcprov-jdk18on)
JDK version: 25.0.2

Summary

SignatureSpi.verifyInit() in org.bouncycastle.jcajce.provider.asymmetric.mldsa throws a ClassCastException when the provided PublicKey is not a BCMLDSAPublicKey (e.g. a JDK 25 native ML-DSA key). This worked correctly in
BC 1.83.

Root Cause

In BC 1.84, the ML-DSA SignatureSpi was updated to use the new org.bouncycastle.crypto.params package types:

  import org.bouncycastle.crypto.params.MLDSAPublicKeyParameters;  // NEW type                                                                                                                                                      

However, the verifyInit() else branch still delegates to the old pqc PublicKeyFactory:

  // Returns org.bouncycastle.pqc.crypto.mldsa.MLDSAPublicKeyParameters (OLD type)                                                                                                                                                  
  this.keyParams = org.bouncycastle.pqc.crypto.util.PublicKeyFactory.createKey(pubKeyInfo);
                                                                                                                                                                                                                                    
  // Casts to org.bouncycastle.crypto.params.MLDSAPublicKeyParameters (NEW type) — ClassCastException!                                                                                                                              
  publicKey = new BCMLDSAPublicKey((MLDSAPublicKeyParameters)this.keyParams);                                                                                                                                                       

The old pqc.crypto.mldsa.MLDSAPublicKeyParameters and the new crypto.params.MLDSAPublicKeyParameters are separate class hierarchies (both extend AsymmetricKeyParameter through their own MLDSAKeyParameters), so the cast
always fails.

Suggested fix

In SignatureSpi.verifyInit(), replace the old pqc factory with the new one:

  // before                                                                                                                                                                                                                         
  this.keyParams = org.bouncycastle.pqc.crypto.util.PublicKeyFactory.createKey(pubKeyInfo);
                                                                                                                                                                                                                                    
  // after                                                                                                                                                                                                                          
  this.keyParams = org.bouncycastle.crypto.util.PublicKeyFactory.createKey(pubKeyInfo);                                                                                                                                             

The new crypto.util.PublicKeyFactory returns crypto.params.MLDSAPublicKeyParameters, which matches the imported type and makes the cast succeed.

Impact

Any code that passes a non-BC PublicKey (or a certificate parsed by a non-BC CertificateFactory) to Signature.initVerify() for ML-DSA will silently fail verification. This is particularly likely on JDK 25 where the default
SUN provider natively handles ML-DSA certificates.

This is a regression from BC 1.83 where both the PublicKeyFactory and SignatureSpi consistently used the pqc.crypto.mldsa package types.

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