openssl/openssl

EVP_DigestSign succeeds with SLH-DSA raw private keys that fail key_check/pairwise_check

Open

#31.055 aperta il 1 mag 2026

Vedi su GitHub
 (3 commenti) (0 reazioni) (1 assegnatario)C (11.262 fork)batch import
help wantedissue: bug reporttriaged: bugtriaged: feature

Metriche repository

Star
 (30.157 star)
Metriche merge PR
 (Nessuna PR mergiata in 30 g)

Descrizione

Summary

For SLH-DSA raw private keys imported with EVP_PKEY_new_raw_private_key_ex(), OpenSSL accepts exact-length component-mutated private keys.

For these mutated keys, EVP_PKEY_check() and EVP_PKEY_pairwise_check() reject the key, but EVP_DigestSign() still succeeds and produces a signature that does not verify under the public key exported from the same EVP_PKEY object.

This report is not claiming that EVP_PKEY_check() or EVP_PKEY_pairwise_check() are broken. The behavior I would like to clarify is whether signing should proceed after these consistency checks would reject the key.

Minimal reproducer

A minimal standalone reproducer is attached:

  • openssl_slh_dsa_raw_private_key_consistency_repro.cpp

The reproducer:

  1. Generates an SLH-DSA-SHA2-128s key.
  2. Exports the raw private key with EVP_PKEY_get_raw_private_key().
  3. Mutates one byte in selected raw private-key components while preserving the exact raw private-key length.
  4. Re-imports the mutated raw private key with EVP_PKEY_new_raw_private_key_ex().
  5. Runs EVP_PKEY_public_check(), EVP_PKEY_private_check(), EVP_PKEY_check(), and EVP_PKEY_pairwise_check().
  6. Calls EVP_DigestSign().
  7. Verifies the resulting signature using the public key exported from the same imported EVP_PKEY object.

Observed behavior

OpenSSL version: OpenSSL 3.5.6 7 Apr 2026

algorithm,mutation,raw_private_len,import,public_check,private_check,key_check,pairwise_check,sign,self_verify,exported_public_verify,public_export,public_import,sig_len
SLH-DSA-SHA2-128s,valid,64,accept,1,1,1,1,success,1,1,yes,yes,7856
SLH-DSA-SHA2-128s,mutate_SK_seed,64,accept,1,1,0,0,success,0,0,yes,yes,7856
SLH-DSA-SHA2-128s,mutate_PK_seed,64,accept,1,1,0,0,success,0,0,yes,yes,7856
SLH-DSA-SHA2-128s,mutate_PK_root,64,accept,1,1,0,0,success,0,0,yes,yes,7856

[RESULT] signing succeeded with mutated raw private keys that failed key_check/pairwise_check; the signatures did not verify
exit_code=1

The valid control behaves as expected.

For the mutated SK.seed, PK.seed, and PK.root cases:

  • raw private-key import succeeds;
  • EVP_PKEY_public_check() and EVP_PKEY_private_check() return 1;
  • EVP_PKEY_check() and EVP_PKEY_pairwise_check() return 0;
  • EVP_DigestSign() succeeds;
  • the produced signature fails verification with the same imported key object;
  • the produced signature also fails verification with the public key exported from that same key object.

Expected behavior / clarification request

Since EVP_PKEY_check() and EVP_PKEY_pairwise_check() reject these imported SLH-DSA keys, I would expect either:

  1. EVP_DigestSign() to reject such keys before producing a signature; or
  2. the documentation to clarify that callers must explicitly run EVP_PKEY_check() or EVP_PKEY_pairwise_check() after raw private key import, because signing may otherwise succeed with an inconsistent key and produce an unverifiable signature.

Could you clarify whether the current behavior is intentional?

Environment

OpenSSL 3.5.6 7 Apr 2026
Algorithm: SLH-DSA-SHA2-128s
Compiler: g++ 11.4.0 with -std=c++17
Platform: linux-x86_64

Attachments

  • openssl_slh_dsa_raw_private_key_consistency_repro.cpp
  • run_output_openssl_3_5_6.txt
  • env_openssl_3_5_6_sanitized.txt

env_openssl_3_5_6_sanitized.txt openssl_slh_dsa_raw_private_key_consistency_repro.cpp run_output_openssl_3_5_6.txt

Guida contributor