EVP_PKEY-ML-DSA(7ossl)
β¨ NAME β¨
okay so bestie, welcome to EVP_PKEY-ML-DSA(7ossl), the OpenSSL manual page for the ML-DSA keytype + algorithm support. It covers EVP_PKEY-ML-DSA, EVP_KEYMGMT-ML-DSA, EVP_PKEY-ML-DSA-44, EVP_PKEY-ML-DSA-65, and EVP_PKEY-ML-DSA-87 β literally the whole EVP_PKEY ML-DSA keytype and algorithm support situation. π«Ά
πΈ DESCRIPTION πΈ
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. no cap.
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 respectively. itβs giving very specific math girlie energy π
π Keygen Parameters π
"seed"(OSSL_PKEY_PARAM_ML_DSA_SEED)<octet string>β The seed can be used to generate the private and public key components in a deterministic manner. The length of the value supplied must be 32 bytes. When this value is not supplied, the seed is generated randomly using a DRBG.
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. periodt.
"properties"(OSSL_PKEY_PARAM_PROPERTIES)<UTF8 string>β Sets properties to be used when fetching algorithm implementations used for ML-DSA hashing operations.
Use EVP_PKEY_CTX_set_params(3) after calling EVP_PKEY_keygen_init(3).
The following key generation parameter can be retrieved with EVP_PKEY_CTX_get_params(3) from the OpenSSL FIPS provider:
"fips-indicator"(OSSL_PKEY_PARAM_FIPS_APPROVED_INDICATOR)<integer>β Returns1if the operation is FIPS approved, or0otherwise. See "FIPS indicators" infips_module(7)for more information.
π¦ Common ML-DSA parameters π¦
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 supports 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. like, thatβs the lock-in phase, bestie π
"pub"(OSSL_PKEY_PARAM_PUB_KEY)<octet string>β The encoded public key value of size1312,1952, or2592bytes depending on the respective key type ofML-DSA-44,ML-DSA-65, orML-DSA-87."priv"(OSSL_PKEY_PARAM_PRIV_KEY)<octet string>β The encoded private key value of size2560,4032, or4896bytes depending on the respective key type ofML-DSA-44,ML-DSA-65, orML-DSA-87.
π§ Provider configuration parameters π§
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. very demure, very documented β¨
"ml-dsa.retain_seed"(OSSL_PKEY_PARAM_ML_DSA_RETAIN_SEED)<UTF8 string>β When set to a string representing a false boolean value (seeOSSL_PROVIDER_conf_get_bool(3)), the seed will not be retained after key generation or key import from a seed value. If the resulting key is then written to a PKCS#8 object, it will contain only the FIPS 204"sk"key."ml-dsa.prefer_seed"(OSSL_PKEY_PARAM_ML_DSA_PREFER_SEED)<UTF8 string>β When decoding PKCS#8 objects that contain both a seed and the FIPS 204"sk"private key, the seed is by default used to regenerate the key, and the companion private key is ignored. When this configuration parameter is set to a string representing a false boolean value (seeOSSL_PROVIDER_conf_get_bool(3)), the seed is ignored (neither used to regenerate the key, nor retained), and the companion key is used instead."ml-dsa.input_formats"(OSSL_PKEY_PARAM_ML_DSA_INPUT_FORMATS)<UTF8 string>β List of enabled private key input formats when parsing PKCS#8 objects. List elements are separated by commas, spaces, or tabs. The list of enabled formats can be specified in the configuration file, as seen in the "EXAMPLES" section below, or via the-provparamcommand-line option (see alsoOSSL_PROVIDER_add_conf_parameter(3)).
Values specified on the command-line override any configuration file settings. By default all the supported formats are enabled. The supported formats are:
"seed-priv"β This format represents PKCS#8 objects in which both the FIPS 204 32-byteΞΎseed and the secret keyskare present in the private key as part of the DER encoding of the ASN.1 sequence:
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.
"seed-only"β This format represents PKCS#8 objects in which only the 32-byte FIPS 204ΞΎseed is present in the above sequence. If the"seed-only"format is not included in the list, this format will not be recognised on input."priv-only"β This format represents PKCS#8 objects in which only the FIPS 204 private keyskis present in the above sequence. If the"priv-only"format is not included in the list, this format will not be recognised on input."oqskeypair"β This format represents PKCS#8 objects in which the private key is a DER encoding of an octet string containing the concatenation of the FIPS 204 private keyskand the public keypk. This encoding is used in some builds of the"oqsprovider". If the"oqskeypair"format is not included in the list, this format will not be recognised on input."bare-seed"β This format represents PKCS#8 objects in which the private key contains the 32-byte FIPS 204 seedΞΎwithout any ASN.1 encapsulation. If the"bare-seed"format is not included in the list, this format will not be recognised on input."bare-priv"β This format represents PKCS#8 objects in which the private key contains the FIPS 204 secret keyskwithout any ASN.1 encapsulation. If the"bare-priv"format is not included in the list, this format will not be recognised on input.
"ml-dsa.output_formats"(OSSL_PKEY_PARAM_ML_DSA_OUTPUT_FORMATS)<UTF8 string>β Ordered list of enabled private key output formats when writing PKCS#8 files. List elements are separated by commas, spaces, or tabs. The list of enabled formats can be specified in the configuration file, as seen in the "EXAMPLES" section below, or via the-provparamcommand-line option.
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. slay π
π CONFORMING TO π
FIPS 204 π«Άβ¨
β¨ EXAMPLES β¨
Okay bestie, this is the part where it gets fun. π Grab your laptop, we're actually doing stuff.
Wanna get yourself an EVP_PKEY context? Just call this, it's giving effortless:
EVP_PKEY_CTX *pctx =
EVP_PKEY_CTX_new_from_name(NULL, "ML-DSA-44", NULL);
And if you need to generate an ML-DSA-44 key, it's literally one line. One. Line. Iconic behaviour:
pkey = EVP_PKEY_Q_keygen(NULL, NULL, "ML-DSA-44");
π¦ pulling the key pair apart
You can extract the key pair components from a key by calling this lil' block of joy:
/* 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));
Note the buffer sizes β those are the big-boss ML-DSA-87 sizes, so they'll fit the smaller ones too. No cap. π
πΈ turning a seed-only key into an sk-format key
Got an ML-DSA private key in seed format and you want it in the FIPS 204 sk format instead? Run this, bestie:
$ openssl pkey -provparam ml-dsa.retain_seed=no \
-in seed-only.pem -out priv-only.pem
And if you wanna generate β say β an ML-DSA-65 key already in FIPS 204 sk format, you can just do:
$ openssl genpkey -provparam ml-dsa.retain_seed=no \
-algorithm ml-dsa-65 -out priv-only.pem
π seed in one hand, key in the other
Okay so picture it: you've got a PKCS#8 file with both a seed and a key, and honestly you'd rather import the companion key than the seed. Respect. Do this:
$ openssl pkey -provparam ml-dsa.prefer_seed=no \
-in seed-priv.pem -out priv-only.pem
π§ the openssl.cnf glow-up
And if you're the config-file type (main character energy, honestly), 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
See how [ml_dsa_sect] gets referenced from both provider sections? That's the move. π₯
π SEE ALSO π
Go read these too, they're all part of the friend group:
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)
(Yes, provider-keymgmt(7) is in there twice. Manpage said it twice, so we're saying it twice. Periodt. π)
π°οΈ HISTORY π°οΈ
This functionality was added in OpenSSL 3.5. So if you're on anything older, that's a no-go, bestie. π
π COPYRIGHT π
Copyright 2025-2026 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>.
π aaaand that's the whole page, bestie! This one's from OpenSSL 3.5.9, dated 2026-09-29, and it's the EVP_PKEY-ML-DSA(7ossl) manual page. Go forth and ML-DSA responsibly. πβ¨π
π¦ where this page comes from
- alpine 3.23: openssl-doc 3.5.9-r0 Β· Apache-2.0
- alpine 3.24: openssl-doc 3.5.9-r0 Β· Apache-2.0
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash-1017 on : a language model's rewrite of the original, under its terms