Problem:
The EVP_DigestSign/EVP_DigestVerify code path for ML-DSA hardcodes the FIPS 204 context string to (NULL, 0), making it impossible to sign or verify with a non-empty context string through the standard EVP interface.
|
// RAW sign mode |
|
if (!sign_digest) { |
|
if (!pqdsa->method->pqdsa_sign_message(key->private_key, sig, sig_len, message, message_len, NULL, 0)) { |
|
OPENSSL_PUT_ERROR(EVP, ERR_R_INTERNAL_ERROR); |
|
return 0; |
|
} |
|
} |
And
|
if(!verify_digest) { |
|
if (sig_len != pqdsa->signature_len || |
|
!pqdsa->method->pqdsa_verify_message(key->public_key, sig, sig_len, message, message_len, NULL, 0)) { |
|
OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_SIGNATURE); |
|
return 0; |
|
} |
|
} |
The underlying ml_dsa_{44,65,87}_sign and ml_dsa_{44,65,87}_verify functions already accept ctx_string and ctx_string_len parameters, and the PQDSA_METHOD function pointer table declares them.
In my efforts into adding support for MLDSA using AWS-LC in pyca/cryptography, I've resorted to use the lower level API functions (here - ⚠️ code not merged, in PR only).
Solution:
Add a control to EVP_PKEY_CTX that lets callers set the context string before signing or verifying.
-
Extend PQDSA_PKEY_CTXto store a context string:
typedef struct {
const PQDSA *pqdsa;
uint8_t ctx_string[MLDSA_MAX_CONTEXT_STRING_LEN]; // 255
size_t ctx_string_len;
} PQDSA_PKEY_CTX;
-
Add an helper function to set the context
-
Update pkey_pqdsa_sign_message and pkey_pqdsa_verify_message to pass dctx->ctx_string and dctx->ctx_string_len instead of NULL, 0.
- Does this change any public APIs? Yes - adds one new exported function (to set the context) and one new constant (for the context max size). No existing APIs change.
- Which algorithm(s) will this impact? ML-DSA-44, ML-DSA-65, ML-DSA-87.
Requirements / Acceptance Criteria:
- RFC links:FIPS 204 §5.2–5.3
- Related Issues: None
- Will the Usage Guide or other documentation need to be updated?
- Testing: Unit tests in
p_pqdsa_test.cc; update existing Wycheproof harness to use EVP path for context-string cases
- Will this change trigger AWS LibCrypto Formal Verification changes? Only plumbing an existing parameter through the EVP layer
- Should this change be fuzz tested? The context string is bounded to 255 bytes but I think it could be fuzzed.
Out of scope:
None
/cc @alex
Problem:
The
EVP_DigestSign/EVP_DigestVerifycode path for ML-DSA hardcodes the FIPS 204 context string to(NULL, 0), making it impossible to sign or verify with a non-empty context string through the standard EVP interface.aws-lc/crypto/fipsmodule/evp/p_pqdsa.c
Lines 109 to 115 in 092453f
And
aws-lc/crypto/fipsmodule/evp/p_pqdsa.c
Lines 184 to 190 in 092453f
The underlying
ml_dsa_{44,65,87}_signandml_dsa_{44,65,87}_verifyfunctions already acceptctx_stringandctx_string_lenparameters, and thePQDSA_METHODfunction pointer table declares them.In my efforts into adding support for MLDSA using AWS-LC in⚠️ code not merged, in PR only).
pyca/cryptography, I've resorted to use the lower level API functions (here -Solution:
Add a control to
EVP_PKEY_CTXthat lets callers set the context string before signing or verifying.Extend
PQDSA_PKEY_CTXto store a context string:Add an helper function to set the context
Update
pkey_pqdsa_sign_messageandpkey_pqdsa_verify_messageto passdctx->ctx_stringanddctx->ctx_string_leninstead ofNULL, 0.Requirements / Acceptance Criteria:
EVP_DigestSignwith a non-empty context string produces a valid signatureEVP_DigestVerifywith a non-empty context string verifies correctlyp_pqdsa_test.cc; update existing Wycheproof harness to use EVP path for context-string casesOut of scope:
None
/cc @alex