| EVP_PKEY-ML-DSA(7SSL) | OpenSSL | EVP_PKEY-ML-DSA(7SSL) |
EVP_PKEY-ML-DSA, EVP_KEYMGMT-ML-DSA, EVP_PKEY-ML-DSA-44, EVP_PKEY-ML-DSA-65, EVP_PKEY-ML-DSA-87 - EVP_PKEY ML-DSA keytype and algorithm support
ML-DSA implements the algorithms ML-DSA-44, ML-DSA-65 and ML-DSA-87. The key types EVP_PKEY_ML_DSA_44, EVP_PKEY_ML_DSA_65 and EVP_PKEY_ML_DSA_87 are implemented in OpenSSL's default and FIPS providers. These implementations support the associated key, containing the public key pub and the private key priv.
Each of the different key types has an associated security category. This value is one of 2, 3 or 5 for key types ML-DSA-44, ML-DSA-65 and ML-DSA-87 respectively, which correspond to security strengths of 128, 192 and 256 repsectively.
Generated keys default to retaining the seed used. The seed is also by default retained when keys are loaded from PKCS#8 files in the seed format. When available, the seed parameter is also used during key export and import, with keys (by default) regenerated from the seed even when also provided on import. See "Provider configuration parameters" below for related controls.
When the seed is retained, it is also available as a gettable parameter, and private key output to PKCS#8 files will by default include the seed. When the seed was not initially known, or was not retained, PKCS#8 private key files will contain only the private key in FIPS 204 "sk" format.
Use EVP_PKEY_CTX_set_params(3) after calling EVP_PKEY_keygen_init(3).
In addition to the common parameters that all keytypes should support (see "Common Information Parameters" in provider-keymgmt(7), the implementation of these key types support the parameters listed below. These are gettable using EVP_PKEY_get_octet_string_param(3) or EVP_PKEY_get_params(3). They can be initialised via EVP_PKEY_fromdata(3), and are returned by EVP_PKEY_todata(3) given a suitable selection. Once a public or private key is configured, it can no longer be modified, nor can another key component be added.
See the description of the -provparam option in openssl(1) to learn how to set provider configuration parameters in the command line tools. See OSSL_PROVIDER_add_conf_parameter(3) to learn how to set provider configuration options programmatically.
Values specified on the command-line override any configuration file settings. By default all the supported formats are enabled. The supported formats are:
ML-DSA-PrivateKey ::= CHOICE {
seed [0] IMPLICIT OCTET STRING (SIZE (32)),
expandedKey OCTET STRING (SIZE (2560 | 4032 | 4896)),
both SEQUENCE {
seed OCTET STRING (SIZE (32)),
expandedKey OCTET STRING (SIZE (2560 | 4032 | 4896)) } }
If the "seed-priv" format is not included in the list, this format will not be recognised on input.
This supports the same set of formats as described under "ml-dsa.input_formats" above. The order in which elements are listed is important, the selected format will be the first one that is possible to output. If the key seed is known, the first listed format will be selected. If the key seed is not known, the first format that omits the seed will be selected. The default order is equivalent to "seed-priv" first and "priv-only" second, with both seed and key output when the seed is available, and just the key otherwise. If "seed-only" is listed first, then the seed will be output without the key when available, otherwise the output will have just the key. If "priv-only" is listed first, then just the key is output regardless of whether the seed is present. The legacy "oqskeypair", "bare-seed" and "bare-priv" formats can also be output, by listing those first.
An EVP_PKEY context can be obtained by calling:
EVP_PKEY_CTX *pctx =
EVP_PKEY_CTX_new_from_name(NULL, "ML-DSA-44", NULL);
An ML-DSA-44 key can be generated like this:
pkey = EVP_PKEY_Q_keygen(NULL, NULL, "ML-DSA-44");
The key pair components can be extracted from a key by calling:
/* Sizes large enough for ML-DSA-87 */
uint8_t pub[2592], priv[4896], seed[32]:
size_t priv_len, pub_len, seed_len;
EVP_PKEY_get_octet_string_param(pkey, OSSL_PKEY_PARAM_ML_DSA_SEED,
seed, sizeof(seed), &seed_len);
EVP_PKEY_get_octet_string_param(pkey, OSSL_PKEY_PARAM_PRIV_KEY,
priv, sizeof(priv), &priv_len);
EVP_PKEY_get_octet_string_param(pkey, OSSL_PKEY_PARAM_PUB_KEY,
pub, sizeof(pub), &pub_len));
An ML-DSA private key in seed format can be converted to a key in the FIPS 204 sk format by running:
$ openssl pkey -provparam ml-dsa.retain_seed=no \
-in seed-only.pem -out priv-only.pem
To generate an, e.g., ML-DSA-65 key, in FIPS 204 sk format, you can run:
$ openssl genpkey -provparam ml-dsa.retain_seed=no \
-algorithm ml-dsa-65 -out priv-only.pem
If you have a PKCS#8 file with both a seed and a key, and prefer to import the companion key rather than the seed, you can run:
$ openssl pkey -provparam ml-dsa.prefer_seed=no \
-in seed-priv.pem -out priv-only.pem
In the openssl.cnf file, this looks like:
openssl_conf = openssl_init
[openssl_init]
providers = providers_sect
# Can be referenced in one or more provider sections
[ml_dsa_sect]
prefer_seed = yes
retain_seed = yes
# OQS legacy formats disabled
input_formats = seed-priv, seed-only, priv-only
# Output either the seed alone, or else the key alone
output_formats = seed-only, priv-only
[providers_sect]
default = default_sect
# Or perhaps just: base = default_sect
base = base_sect
[default_sect]
ml-dsa = ml_dsa_sect
[base_sect]
ml-dsa = ml_dsa_sect
EVP_KEYMGMT(3), EVP_PKEY(3), provider-keymgmt(7), EVP_PKEY_get_raw_private_key(3), EVP_PKEY_get_raw_public_key(3), EVP_PKEY_get1_encoded_public_key(3), OSSL_PROVIDER_add_conf_parameter(3), provider-keymgmt(7), EVP_SIGNATURE-ML-DSA(7)
This functionality was added in OpenSSL 3.5.
Copyright 2025 The OpenSSL Project Authors. All Rights Reserved.
Licensed under the Apache License 2.0 (the "License"). You may not use this file except in compliance with the License. You can obtain a copy in the file LICENSE in the source distribution or at <https://www.openssl.org/source/license.html>.
| 2025-09-30 | 3.5.4 |