From b1b355c836fe25097f82636a4c19ac9a17b0ae50 Mon Sep 17 00:00:00 2001 From: Josh Drake Date: Thu, 24 Sep 2026 15:09:57 -0500 Subject: [PATCH] Identify and verify ML-DSA certificates Certificates signed with or holding ML-DSA keys (RFC 9881) were parsed with an unknown signature and public key algorithm, so their JSON reported "signature_algorithm": {"name": "0", "oid": ""} and "key_algorithm": {"name": "unknown_algorithm"}, and self-signed ML-DSA roots were reported as not self-signed. This is what step certificate inspect --format json shows for ML-DSA certificates. Add the ML-DSA-44, ML-DSA-65 and ML-DSA-87 signature algorithms and an ML-DSA public key algorithm, named as crypto/x509 names them. They are identified on every toolchain. With Go 1.27 or later, public keys are parsed into *mldsa.PublicKey and signatures are verified with crypto/mldsa, rejecting a signature whose parameter set differs from the key's. Older toolchains parse the certificate but report its signatures as unsupported, following the stub pattern in go.step.sm/crypto/mldsa. Key lengths are checked on every toolchain so a certificate parses the same way regardless of Go version. When crypto/mldsa is unavailable at runtime, as with the FIPS 140-3 Go Cryptographic Module v1.0.0, the certificate still parses with a nil public key instead of failing. The test certificates are generated with OpenSSL by x509/testdata/mldsa/gen.sh, so they come from an ML-DSA implementation independent of Go's. --- x509/mldsa.go | 11 ++ x509/mldsa_go127.go | 61 +++++++ x509/mldsa_go127_test.go | 77 +++++++++ x509/mldsa_stub.go | 18 ++ x509/mldsa_stub_test.go | 23 +++ x509/mldsa_test.go | 115 +++++++++++++ x509/testdata/mldsa/gen.sh | 35 ++++ x509/testdata/mldsa/mldsa-44-leaf.pem | 104 ++++++++++++ x509/testdata/mldsa/mldsa-44-root.pem | 86 ++++++++++ .../mldsa/mldsa-65-root-invalid-sig.pem | 118 +++++++++++++ x509/testdata/mldsa/mldsa-65-root.pem | 118 +++++++++++++ x509/testdata/mldsa/mldsa-87-root.pem | 159 ++++++++++++++++++ x509/x509.go | 27 +++ x509/x509_modified.go | 21 +++ 14 files changed, 973 insertions(+) create mode 100644 x509/mldsa.go create mode 100644 x509/mldsa_go127.go create mode 100644 x509/mldsa_go127_test.go create mode 100644 x509/mldsa_stub.go create mode 100644 x509/mldsa_stub_test.go create mode 100644 x509/mldsa_test.go create mode 100755 x509/testdata/mldsa/gen.sh create mode 100644 x509/testdata/mldsa/mldsa-44-leaf.pem create mode 100644 x509/testdata/mldsa/mldsa-44-root.pem create mode 100644 x509/testdata/mldsa/mldsa-65-root-invalid-sig.pem create mode 100644 x509/testdata/mldsa/mldsa-65-root.pem create mode 100644 x509/testdata/mldsa/mldsa-87-root.pem diff --git a/x509/mldsa.go b/x509/mldsa.go new file mode 100644 index 00000000..b83ab088 --- /dev/null +++ b/x509/mldsa.go @@ -0,0 +1,11 @@ +package x509 + +// Encoded ML-DSA public key sizes, FIPS 204 Table 2. They are declared here +// rather than taken from crypto/mldsa so that ML-DSA certificates parse +// identically on toolchains that predate that package; see mldsa_go127.go and +// mldsa_stub.go. +const ( + mldsa44PublicKeySize = 1312 + mldsa65PublicKeySize = 1952 + mldsa87PublicKeySize = 2592 +) diff --git a/x509/mldsa_go127.go b/x509/mldsa_go127.go new file mode 100644 index 00000000..914b381c --- /dev/null +++ b/x509/mldsa_go127.go @@ -0,0 +1,61 @@ +//go:build go1.27 + +package x509 + +import ( + "crypto/mldsa" + "encoding/asn1" + "fmt" +) + +// parseMLDSAPublicKey returns the ML-DSA public key encoded in data as a +// *mldsa.PublicKey. The caller has already checked the length of data against +// the parameter set named by oid, so any failure here means ML-DSA itself is +// unavailable, as it is with the FIPS 140-3 Go Cryptographic Module v1.0.0. +// In that case it returns nil: the certificate still parses and reports its +// algorithms, but its signatures cannot be checked. +func parseMLDSAPublicKey(oid asn1.ObjectIdentifier, data []byte) interface{} { + var params mldsa.Parameters + switch { + case oid.Equal(oidKeyMLDSA44): + params = mldsa.MLDSA44() + case oid.Equal(oidKeyMLDSA65): + params = mldsa.MLDSA65() + case oid.Equal(oidKeyMLDSA87): + params = mldsa.MLDSA87() + default: + return nil + } + pub, err := mldsa.NewPublicKey(params, data) + if err != nil { + return nil + } + return pub +} + +// checkMLDSASignature verifies a pure ML-DSA signature, with an empty context +// string, as RFC 9881 requires for X.509. +func checkMLDSASignature(publicKey interface{}, algo SignatureAlgorithm, signed, signature []byte) error { + pub, ok := publicKey.(*mldsa.PublicKey) + if !ok { + return ErrUnsupportedAlgorithm + } + var keyAlgo SignatureAlgorithm + switch pub.Parameters() { + case mldsa.MLDSA44(): + keyAlgo = MLDSA44 + case mldsa.MLDSA65(): + keyAlgo = MLDSA65 + case mldsa.MLDSA87(): + keyAlgo = MLDSA87 + default: + return ErrUnsupportedAlgorithm + } + if algo != keyAlgo { + return fmt.Errorf("x509: %s signature does not match %s public key", algo, keyAlgo) + } + if err := mldsa.Verify(pub, signed, signature, nil); err != nil { + return fmt.Errorf("x509: ML-DSA verification failure: %w", err) + } + return nil +} diff --git a/x509/mldsa_go127_test.go b/x509/mldsa_go127_test.go new file mode 100644 index 00000000..bac31c83 --- /dev/null +++ b/x509/mldsa_go127_test.go @@ -0,0 +1,77 @@ +//go:build go1.27 + +package x509 + +import ( + "crypto/mldsa" + stdx509 "crypto/x509" + "testing" +) + +func TestMLDSASignatures(t *testing.T) { + roots := map[string]mldsa.Parameters{ + "mldsa-44-root.pem": mldsa.MLDSA44(), + "mldsa-65-root.pem": mldsa.MLDSA65(), + "mldsa-87-root.pem": mldsa.MLDSA87(), + } + for filename, params := range roots { + t.Run(filename, func(t *testing.T) { + c := parseMLDSATestCertificate(t, filename) + pub, ok := c.PublicKey.(*mldsa.PublicKey) + if !ok { + t.Fatalf("PublicKey is %T, want *mldsa.PublicKey", c.PublicKey) + } + if pub.Parameters() != params { + t.Errorf("PublicKey parameters = %s, want %s", pub.Parameters(), params) + } + if !c.SelfSigned { + t.Error("SelfSigned = false, want true") + } + }) + } + + t.Run("invalid signature", func(t *testing.T) { + c := parseMLDSATestCertificate(t, "mldsa-65-root-invalid-sig.pem") + if c.SelfSigned { + t.Error("SelfSigned = true, want false") + } + }) + + t.Run("chain", func(t *testing.T) { + leaf := parseMLDSATestCertificate(t, "mldsa-44-leaf.pem") + root := parseMLDSATestCertificate(t, "mldsa-65-root.pem") + if err := leaf.CheckSignatureFrom(root); err != nil { + t.Errorf("CheckSignatureFrom(ML-DSA-65 root) = %v, want nil", err) + } + }) + + t.Run("parameter mismatch", func(t *testing.T) { + // The leaf's ML-DSA-65 signature must not be checked with an + // ML-DSA-44 key, even one whose certificate is otherwise usable. + leaf := parseMLDSATestCertificate(t, "mldsa-44-leaf.pem") + wrong := parseMLDSATestCertificate(t, "mldsa-44-root.pem") + if err := CheckSignatureFromKey(wrong.PublicKey, leaf.SignatureAlgorithm, leaf.RawTBSCertificate, leaf.Signature); err == nil { + t.Error("CheckSignatureFromKey with an ML-DSA-44 key accepted an ML-DSA-65 signature") + } + }) +} + +// TestMLDSAMatchesStandardLibrary checks that zcrypto names ML-DSA algorithms +// the same way crypto/x509 does. +func TestMLDSAMatchesStandardLibrary(t *testing.T) { + for _, filename := range []string{"mldsa-44-root.pem", "mldsa-65-root.pem", "mldsa-87-root.pem", "mldsa-44-leaf.pem"} { + t.Run(filename, func(t *testing.T) { + c := parseMLDSATestCertificate(t, filename) + std, err := stdx509.ParseCertificate(c.Raw) + if err != nil { + t.Fatalf("crypto/x509: %s", err) + } + if got, want := c.SignatureAlgorithm.String(), std.SignatureAlgorithm.String(); got != want { + t.Errorf("SignatureAlgorithm = %q, crypto/x509 has %q", got, want) + } + if got, want := c.PublicKeyAlgorithm.String(), std.PublicKeyAlgorithm.String(); got != want { + t.Errorf("PublicKeyAlgorithm = %q, crypto/x509 has %q", got, want) + } + }) + } +} diff --git a/x509/mldsa_stub.go b/x509/mldsa_stub.go new file mode 100644 index 00000000..be79fc3d --- /dev/null +++ b/x509/mldsa_stub.go @@ -0,0 +1,18 @@ +//go:build !go1.27 + +package x509 + +import "encoding/asn1" + +// parseMLDSAPublicKey returns nil because crypto/mldsa requires Go 1.27. ML-DSA +// certificates still parse and report their algorithms; only signature checks +// are unavailable. Remove this file once the minimum Go version is 1.27. +func parseMLDSAPublicKey(asn1.ObjectIdentifier, []byte) interface{} { + return nil +} + +// checkMLDSASignature reports ML-DSA signatures as unsupported because +// crypto/mldsa requires Go 1.27. +func checkMLDSASignature(interface{}, SignatureAlgorithm, []byte, []byte) error { + return ErrUnsupportedAlgorithm +} diff --git a/x509/mldsa_stub_test.go b/x509/mldsa_stub_test.go new file mode 100644 index 00000000..afca3b55 --- /dev/null +++ b/x509/mldsa_stub_test.go @@ -0,0 +1,23 @@ +//go:build !go1.27 + +package x509 + +import ( + "errors" + "testing" +) + +// Without crypto/mldsa, ML-DSA certificates parse but their signatures are +// reported as unsupported rather than invalid. +func TestMLDSASignaturesUnsupported(t *testing.T) { + c := parseMLDSATestCertificate(t, "mldsa-65-root.pem") + if c.PublicKey != nil { + t.Errorf("PublicKey = %T, want nil", c.PublicKey) + } + if c.SelfSigned { + t.Error("SelfSigned = true, want false") + } + if err := c.CheckSignature(c.SignatureAlgorithm, c.RawTBSCertificate, c.Signature); !errors.Is(err, ErrUnsupportedAlgorithm) { + t.Errorf("CheckSignature = %v, want ErrUnsupportedAlgorithm", err) + } +} diff --git a/x509/mldsa_test.go b/x509/mldsa_test.go new file mode 100644 index 00000000..ccd95d6c --- /dev/null +++ b/x509/mldsa_test.go @@ -0,0 +1,115 @@ +package x509 + +import ( + "encoding/asn1" + "encoding/json" + "encoding/pem" + "os" + "testing" + + "github.com/smallstep/zcrypto/x509/pkix" +) + +const mldsaTestdataPrefix = testdataPrefix + "mldsa/" + +func parseMLDSATestCertificate(t *testing.T, filename string) *Certificate { + t.Helper() + b, err := os.ReadFile(mldsaTestdataPrefix + filename) + if err != nil { + t.Fatalf("could not open %s: %s", filename, err) + } + p, _ := pem.Decode(b) + if p == nil { + t.Fatalf("bad pem %s", filename) + } + c, err := ParseCertificate(p.Bytes) + if err != nil { + t.Fatalf("could not parse %s: %s", filename, err) + } + return c +} + +// TestParseMLDSACertificates checks that ML-DSA algorithms are identified on +// every toolchain, including those without crypto/mldsa. +func TestParseMLDSACertificates(t *testing.T) { + tests := []struct { + filename string + sigAlgo SignatureAlgorithm + sigName string + sigOID string + }{ + {"mldsa-44-root.pem", MLDSA44, "ML-DSA-44", "2.16.840.1.101.3.4.3.17"}, + {"mldsa-65-root.pem", MLDSA65, "ML-DSA-65", "2.16.840.1.101.3.4.3.18"}, + {"mldsa-87-root.pem", MLDSA87, "ML-DSA-87", "2.16.840.1.101.3.4.3.19"}, + // Issued by the ML-DSA-65 root, but holding an ML-DSA-44 key. + {"mldsa-44-leaf.pem", MLDSA65, "ML-DSA-65", "2.16.840.1.101.3.4.3.18"}, + } + for _, test := range tests { + t.Run(test.filename, func(t *testing.T) { + c := parseMLDSATestCertificate(t, test.filename) + if c.SignatureAlgorithm != test.sigAlgo { + t.Errorf("SignatureAlgorithm = %v, want %v", c.SignatureAlgorithm, test.sigAlgo) + } + if got := c.SignatureAlgorithmName(); got != test.sigName { + t.Errorf("SignatureAlgorithmName() = %q, want %q", got, test.sigName) + } + if c.PublicKeyAlgorithm != MLDSA { + t.Errorf("PublicKeyAlgorithm = %v, want %v", c.PublicKeyAlgorithm, MLDSA) + } + if got := c.PublicKeyAlgorithmName(); got != "ML-DSA" { + t.Errorf("PublicKeyAlgorithmName() = %q, want %q", got, "ML-DSA") + } + + b, err := json.Marshal(c) + if err != nil { + t.Fatalf("json.Marshal: %s", err) + } + var out struct { + SignatureAlgorithm struct { + Name string `json:"name"` + OID string `json:"oid"` + } `json:"signature_algorithm"` + SubjectKeyInfo struct { + KeyAlgorithm struct { + Name string `json:"name"` + } `json:"key_algorithm"` + } `json:"subject_key_info"` + } + if err := json.Unmarshal(b, &out); err != nil { + t.Fatalf("json.Unmarshal: %s", err) + } + if out.SignatureAlgorithm.Name != test.sigName || out.SignatureAlgorithm.OID != test.sigOID { + t.Errorf("JSON signature_algorithm = %+v, want {Name:%s OID:%s}", out.SignatureAlgorithm, test.sigName, test.sigOID) + } + if out.SubjectKeyInfo.KeyAlgorithm.Name != "ML-DSA" { + t.Errorf("JSON subject_key_info.key_algorithm.name = %q, want %q", out.SubjectKeyInfo.KeyAlgorithm.Name, "ML-DSA") + } + }) + } +} + +func TestParseMLDSAPublicKeyLength(t *testing.T) { + tests := []struct { + name string + oid asn1.ObjectIdentifier + size int + }{ + {"ML-DSA-44", oidKeyMLDSA44, mldsa44PublicKeySize}, + {"ML-DSA-65", oidKeyMLDSA65, mldsa65PublicKeySize}, + {"ML-DSA-87", oidKeyMLDSA87, mldsa87PublicKeySize}, + } + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + for _, n := range []int{0, test.size - 1, test.size, test.size + 1} { + keyData := &publicKeyInfo{ + Algorithm: pkix.AlgorithmIdentifier{Algorithm: test.oid}, + PublicKey: asn1.BitString{Bytes: make([]byte, n), BitLength: 8 * n}, + } + _, err := parsePublicKey(MLDSA, keyData) + if wantErr := n != test.size; (err != nil) != wantErr { + t.Errorf("%d-byte key: err = %v, want error: %t", n, err, wantErr) + } + } + }) + } +} diff --git a/x509/testdata/mldsa/gen.sh b/x509/testdata/mldsa/gen.sh new file mode 100755 index 00000000..cc119c92 --- /dev/null +++ b/x509/testdata/mldsa/gen.sh @@ -0,0 +1,35 @@ +#!/usr/bin/env bash +# Regenerates the ML-DSA test certificates with OpenSSL 3.5 or later, an ML-DSA +# implementation independent of Go's crypto/mldsa. Run from this directory. +set -euo pipefail + +tmp=$(mktemp -d) +trap 'rm -rf "$tmp"' EXIT + +# Self-signed roots, one per parameter set. +for n in 44 65 87; do + openssl req -x509 -newkey "ML-DSA-$n" -keyout "$tmp/root-$n.key" -nodes \ + -subj "/CN=ML-DSA-$n Root" -days 36500 \ + -addext basicConstraints=critical,CA:TRUE \ + -addext keyUsage=critical,keyCertSign,cRLSign \ + -out "mldsa-$n-root.pem" +done + +# An ML-DSA-44 leaf issued by the ML-DSA-65 root, so the certificate's +# signature algorithm (ML-DSA-65) differs from its own key's (ML-DSA-44). +openssl req -new -newkey ML-DSA-44 -keyout "$tmp/leaf.key" -nodes \ + -subj "/CN=leaf.test" -out "$tmp/leaf.csr" +openssl x509 -req -in "$tmp/leaf.csr" -CA mldsa-65-root.pem -CAkey "$tmp/root-65.key" \ + -days 36500 -set_serial 2 -extfile <(printf 'subjectAltName=DNS:leaf.test\n') \ + -out mldsa-44-leaf.pem + +# The ML-DSA-65 root with one signature byte flipped. The signature is the last +# field of the certificate, so flipping the final byte leaves the DER valid. +openssl x509 -in mldsa-65-root.pem -outform DER -out "$tmp/root-65.der" +python3 - "$tmp/root-65.der" "$tmp/bad.der" <<'EOF' +import sys +b = bytearray(open(sys.argv[1], "rb").read()) +b[-1] ^= 0x01 +open(sys.argv[2], "wb").write(b) +EOF +openssl x509 -inform DER -in "$tmp/bad.der" -out mldsa-65-root-invalid-sig.pem diff --git a/x509/testdata/mldsa/mldsa-44-leaf.pem b/x509/testdata/mldsa/mldsa-44-leaf.pem new file mode 100644 index 00000000..89a66dcd --- /dev/null +++ b/x509/testdata/mldsa/mldsa-44-leaf.pem @@ -0,0 +1,104 @@ +-----BEGIN CERTIFICATE----- +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 +AAAAAAAAAAAABQ8VGyMm +-----END CERTIFICATE----- diff --git a/x509/testdata/mldsa/mldsa-44-root.pem b/x509/testdata/mldsa/mldsa-44-root.pem new file mode 100644 index 00000000..04f4c207 --- /dev/null +++ b/x509/testdata/mldsa/mldsa-44-root.pem @@ -0,0 +1,86 @@ +-----BEGIN CERTIFICATE----- +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 +s8PFy9Pa9fkAAAAAAAAAAAAAAAAADhgtQw== +-----END CERTIFICATE----- diff --git a/x509/testdata/mldsa/mldsa-65-root-invalid-sig.pem b/x509/testdata/mldsa/mldsa-65-root-invalid-sig.pem new file mode 100644 index 00000000..81c906d8 --- /dev/null +++ b/x509/testdata/mldsa/mldsa-65-root-invalid-sig.pem @@ -0,0 +1,118 @@ +-----BEGIN CERTIFICATE----- +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 +AAAAAAAAAAAAAAAABRAVGRwi +-----END CERTIFICATE----- diff --git a/x509/testdata/mldsa/mldsa-65-root.pem b/x509/testdata/mldsa/mldsa-65-root.pem new file mode 100644 index 00000000..bd479ce1 --- /dev/null +++ b/x509/testdata/mldsa/mldsa-65-root.pem @@ -0,0 +1,118 @@ +-----BEGIN CERTIFICATE----- +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 +AAAAAAAAAAAAAAAABRAVGRwj +-----END CERTIFICATE----- diff --git a/x509/testdata/mldsa/mldsa-87-root.pem b/x509/testdata/mldsa/mldsa-87-root.pem new file mode 100644 index 00000000..100363ad --- /dev/null +++ b/x509/testdata/mldsa/mldsa-87-root.pem @@ -0,0 +1,159 @@ +-----BEGIN CERTIFICATE----- +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 +CBAYISc0PEU= +-----END CERTIFICATE----- diff --git a/x509/x509.go b/x509/x509.go index 125eae20..f0054313 100644 --- a/x509/x509.go +++ b/x509/x509.go @@ -187,6 +187,9 @@ const ( SHA384WithRSAPSS SHA512WithRSAPSS ED25519SIG + MLDSA44 + MLDSA65 + MLDSA87 ) func (algo SignatureAlgorithm) isRSAPSS() bool { @@ -215,6 +218,9 @@ var algoName = [...]string{ ECDSAWithSHA384: "ECDSA-SHA384", ECDSAWithSHA512: "ECDSA-SHA512", ED25519SIG: "Ed25519", + MLDSA44: "ML-DSA-44", + MLDSA65: "ML-DSA-65", + MLDSA87: "ML-DSA-87", } func (algo SignatureAlgorithm) String() string { @@ -336,6 +342,9 @@ var signatureAlgorithmDetails = []struct { {ECDSAWithSHA384, oidSignatureECDSAWithSHA384, ECDSA, crypto.SHA384}, {ECDSAWithSHA512, oidSignatureECDSAWithSHA512, ECDSA, crypto.SHA512}, {ED25519SIG, oidKeyEd25519, ED25519, crypto.Hash(0)}, + {MLDSA44, oidKeyMLDSA44, MLDSA, crypto.Hash(0) /* no pre-hashing */}, + {MLDSA65, oidKeyMLDSA65, MLDSA, crypto.Hash(0) /* no pre-hashing */}, + {MLDSA87, oidKeyMLDSA87, MLDSA, crypto.Hash(0) /* no pre-hashing */}, } // pssParameters reflects the parameters in an AlgorithmIdentifier that @@ -478,6 +487,8 @@ func getPublicKeyAlgorithmFromOID(oid asn1.ObjectIdentifier) PublicKeyAlgorithm return ED25519 case oid.Equal(oidKeyX25519): return X25519 + case oid.Equal(oidKeyMLDSA44), oid.Equal(oidKeyMLDSA65), oid.Equal(oidKeyMLDSA87): + return MLDSA } return UnknownPublicKeyAlgorithm } @@ -513,6 +524,22 @@ var ( oidKeyEd25519 = asn1.ObjectIdentifier{1, 3, 101, 112} ) +// RFC 9881, 2. Algorithm Identifiers. The same OIDs identify both ML-DSA +// public keys and ML-DSA signatures, and their parameters MUST be absent. +// +// id-ml-dsa-44 OBJECT IDENTIFIER ::= { joint-iso-itu-t(2) +// country(16) us(840) organization(1) gov(101) csor(3) +// nistAlgorithm(4) sigAlgs(3) id-ml-dsa-44(17) } +// +// id-ml-dsa-65 OBJECT IDENTIFIER ::= { ... sigAlgs(3) id-ml-dsa-65(18) } +// +// id-ml-dsa-87 OBJECT IDENTIFIER ::= { ... sigAlgs(3) id-ml-dsa-87(19) } +var ( + oidKeyMLDSA44 = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 3, 17} + oidKeyMLDSA65 = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 3, 18} + oidKeyMLDSA87 = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 3, 19} +) + func namedCurveFromOID(oid asn1.ObjectIdentifier) elliptic.Curve { switch { case oid.Equal(oidNamedCurveP224): diff --git a/x509/x509_modified.go b/x509/x509_modified.go index 76edca2e..58415b96 100644 --- a/x509/x509_modified.go +++ b/x509/x509_modified.go @@ -98,6 +98,7 @@ const ( ECDSA ED25519 X25519 + MLDSA total_key_algorithms ) @@ -108,6 +109,7 @@ var keyAlgorithmNames = []string{ "ECDSA", "Ed25519", "X25519", + "ML-DSA", } func maxValidationLevel(a, b CertValidationLevel) CertValidationLevel { @@ -480,6 +482,8 @@ func CheckSignatureFromKey(publicKey interface{}, algo SignatureAlgorithm, signe return InsecureAlgorithmError(algo) case ED25519SIG: hashType = 0 + case MLDSA44, MLDSA65, MLDSA87: + return checkMLDSASignature(publicKey, algo, signed, signature) default: return ErrUnsupportedAlgorithm } @@ -705,6 +709,23 @@ func parsePublicKey(algo PublicKeyAlgorithm, keyData *publicKeyInfo) (interface{ return nil, errors.New("x509: trailing data after X25519 public key") } return p, nil + case MLDSA: + // Unlike the standard library, keys with parameters present are + // accepted, matching the leniency applied to RSA keys above. + oid := keyData.Algorithm.Algorithm + var size int + switch { + case oid.Equal(oidKeyMLDSA44): + size = mldsa44PublicKeySize + case oid.Equal(oidKeyMLDSA65): + size = mldsa65PublicKeySize + case oid.Equal(oidKeyMLDSA87): + size = mldsa87PublicKeySize + } + if len(asn1Data) != size { + return nil, fmt.Errorf("x509: invalid %s public key length %d", GetSignatureAlgorithmFromAI(keyData.Algorithm), len(asn1Data)) + } + return parseMLDSAPublicKey(oid, asn1Data), nil default: return nil, nil }