Skip to content

ML-DSA signatures with not matching schemes in TLS are accepted #28762

@tomato42

Description

@tomato42

When running the current master (f7feb2d) OpenSSL will accept an ML-DSA signature that identifies itself as a wrong scheme. For example, client certificate with ML-DSA-65 includes a valid signature in CertificateVerify that has a mldsa44 SignatureScheme.

To Reproduce

reproducer

openssl req -x509 -newkey rsa -keyout /tmp/localhost.key -out /tmp/localhost.crt -subj /CN=localhost -nodes -batch
openssl s_server -key /tmp/localhost.key -cert /tmp/localhost.crt -Verify 1 -HTTP 2>server.err >server.out &
openssl_pid=$!
git clone https://github.com/tomato42/tlsfuzzer
pushd tlsfuzzer
# won't be needed after https://github.com/tlsfuzzer/tlsfuzzer/pull/1017 is merged
git checkout more-ml-dsa
git clone https://github.com/tomato42/tlslite-ng .tlslite-ng
ln -s .tlslite-ng/tlslite tlslite
git clone https://github.com/warner/python-ecdsa .python-ecdsa
ln -s .python-ecdsa/src/ecdsa ecdsa
git clone https://github.com/GiacomoPope/kyber-py .kyber-py
ln -s .kyber-py/src/kyber_py kyber_py
git clone https://github.com/GiacomoPope/dilithium-py .dilithium-py
ln -s .dilithium-py/src/dilithium_py dilithium_py
PYTHONPATH=. python3 scripts/test-tls13-mldsa-in-certificate-verify.py -k tests/serverMldsa65Key.pem -c tests/serverMldsa65Cert.pem -s "mldsa65 mldsa87 mldsa44 ecdsa_secp256r1_sha256 ecdsa_secp384r1_sha384 ecdsa_secp521r1_sha512 ed25519 ed448 ecdsa_brainpoolP256r1tls13_sha256 ecdsa_brainpoolP384r1tls13_sha384 ecdsa_brainpoolP512r1tls13_sha512 rsa_pss_pss_sha256 rsa_pss_pss_sha384 rsa_pss_pss_sha512 rsa_pss_rsae_sha256 rsa_pss_rsae_sha384 rsa_pss_rsae_sha512 rsa_pkcs1_sha256 rsa_pkcs1_sha384 rsa_pkcs1_sha512" 'check mldsa signature with mismatched scheme fails' sanity
popd
kill $openssl_pid

OpenSSL output

verify depth is 1, must return a certificate
Using default temp DH parameters
ACCEPT
depth=0 CN=localhost
verify error:num=20:unable to get local issuer certificate
verify return:1
depth=0 CN=localhost
verify error:num=26:unsuitable certificate purpose
verify return:1
depth=0 CN=localhost
verify error:num=21:unable to verify the first certificate
verify return:1
depth=0 CN=localhost
verify return:1
depth=0 CN=localhost
verify error:num=20:unable to get local issuer certificate
verify return:1
depth=0 CN=localhost
verify error:num=26:unsuitable certificate purpose
verify return:1
depth=0 CN=localhost
verify error:num=21:unable to verify the first certificate
verify return:1
depth=0 CN=localhost
verify return:1
depth=0 CN=localhost
verify error:num=20:unable to get local issuer certificate
verify return:1
depth=0 CN=localhost
verify error:num=26:unsuitable certificate purpose
verify return:1
depth=0 CN=localhost
verify error:num=21:unable to verify the first certificate
verify return:1
depth=0 CN=localhost
verify return:1

tlsfuzzer output

sanity ...
OK

check mldsa signature with mismatched scheme fails ...
Error encountered while processing node ExpectAlert(level=2, description=47) (child: <tlsfuzzer.expect.ExpectClose object at 0x7fa40caeb9d0>) with last message being: <tlslite.messages.Message object at 0x7fa4056c2390>
Error while processing
Traceback (most recent call last):
  File "/home/hkario/dev/tlsfuzzer/tlsfuzzer/_apps/test_tls13_mldsa_in_certificate_verify.py", line 646, in main
    runner.run()
    ~~~~~~~~~~^^
  File "/home/hkario/dev/tlsfuzzer/tlsfuzzer/runner.py", line 235, in run
    raise AssertionError("Unexpected message from peer: " +
    ...<4 lines>...
                                        RecordHeader2)))
AssertionError: Unexpected message from peer: Handshake(new_session_ticket)

sanity ...
OK

Test to verify that server properly accepts or refuses
ML-DSA signatures in TLS1.3
Test should be executed three times, once each with ML-DSA-44,
ML-DSA-65 and ML-DSA-87 (if all are supported by the server).

Test end
====================
version: 2
====================
TOTAL: 3
SKIP: 0
PASS: 2
XFAIL: 0
FAIL: 1
XPASS: 0
====================
FAILED:
        'check mldsa signature with mismatched scheme fails'

Expected behavior

The server should check if the signature ID matches the client certificate and reject the connection with an illegal_parameter alert.

Metadata

Metadata

Assignees

Labels

branch: 3.0Applies to openssl-3.0 branchbranch: 3.2Applies to openssl-3.2 (EOL)branch: 3.3Applies to openssl-3.3branch: 3.4Applies to openssl-3.4branch: 3.5Applies to openssl-3.5branch: 3.6Applies to openssl-3.6branch: masterApplies to master branchtriaged: bugThe issue/pr is/fixes a bug

Type

Projects

Status

Done

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions