From: slontis Date: Fri, 8 Nov 2024 06:23:18 +0000 (+1100) Subject: Add SLH-DSA design document X-Git-Tag: openssl-3.5.0-alpha1~189 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=acdd2c8bff7952d17b3cd61143c7f0b6cb3d7398;p=thirdparty%2Fopenssl.git Add SLH-DSA design document Reviewed-by: Paul Dale Reviewed-by: Viktor Dukhovni Reviewed-by: Tim Hudson (Merged from https://github.com/openssl/openssl/pull/25882) --- diff --git a/CHANGES.md b/CHANGES.md index 8dd1ccfdd2d..d96540bb211 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -39,7 +39,7 @@ OpenSSL 3.5 *Neil Horman* -* Add SLH-DSA as specified by FIPS 205. +* Add SLH-DSA as specified in FIPS 205. *Shane Lontis* diff --git a/doc/designs/slh-dsa.md b/doc/designs/slh-dsa.md new file mode 100644 index 00000000000..537fb1d71db --- /dev/null +++ b/doc/designs/slh-dsa.md @@ -0,0 +1,99 @@ +SLH-DSA Design +============== + +This document covers OpenSSL specific SLH-DSA implementation details. +FIPS 205 clearly states most of the requirements of SLH-DSA and has comprehensive +pseudo code for all its algorithms. + +SLH_DSA Parameters & Functions +------------------------------ + +There are 12 different parameter sets in FIPS 205. (See Section 11) +There are constants related to these, as well as there being a group of functions +associated with each set. + +The constants include things like hash sizes and tree heights. + +OpenSSL will have 12 different key managers and 12 corresponding signature functions. +The names used are of the form "SLH-DSA-SHA2-128s" and "SLH-DSA-SHAKE-128f". + +There are 7 hash functions used. The algorithms using SHAKE have a much simpler +set of 7 functions as they just use SHAKE-256 XOF (Even for the SHAKE-128 names). +The SHA2 algorithms are much more complex and require HMAC, MGF1, and well as digests. +There are 2 sets of functions for the SHA2 case. + +Some of the hash functions use an ADRS object. This is 32 bytes for SHAKE algorithms +and 22 bytes for SHA2. Because SHA2 used a compressed format the ADRS functions are +different. + +There are many functions required to implement the sign and verify paths, which include +Merkle trees and WOTS+. The different functions normally call one of 2 of the +7 hash functions, as well as calling ADRS functions to pass to the HASH functions. + +Rather that duplicating this code 12 times for every function, instead a +SLH_DSA_CTX object is created. +This contains the HASH functions, the ADRS functions, and the parameter constants. +It also contains pre fetched algorithms. + +This SLH_DSA_CTX is then passed to all functions. This context is allocated in the +providers SLH_DSA signature context. + +SLH-DSA keys +------------ + +SLH-DSA keys have 2 elements of size n for both the public and private keys. +Since different algorithms have different key sizes, buffers of the maximum size +will be used to hold the keys (since the keys are only a maximum of 64 bytes each) + +struct slh_dsa_key_st { + /* The public key consists of a SEED and ROOT values each of size |n| */ + uint8_t pub[SLH_DSA_MAX_KEYLEN]; + /* The private key consists of a SEED and PRF values of size |n| */ + uint8_t priv[SLH_DSA_MAX_KEYLEN]; + size_t key_len; /* This value is set to 2 * n if there is a public key */ + /* contains the algorithm name and constants such as |n| */ + const SLH_DSA_PARAMS *params; + int has_priv; /* Set to 1 if there is a private key component */ +}; + +The fields 'key_len' and 'has_priv' are used to determine if a key has loaded +the public and private key elements. +The 'params' field is the parameter set which is resolved via the algorithm name. + +The FIPS 205 the SLH_DSA private key contains the public key. +In OpenSSL these components are stored separately, so there must always be a +public key in order for the key to be valid. + +The key generation process creates a private key and half of the public key +using DRBG's. The public key root component is then computed based on these +values. For ACVP testing these values are supplied as an ENTROPY parameter. +It is assumed that from data will not deal with a partial public key, and if this +is required the user should use the key generation operation. + +Pure vs Pre Hashed Signature Generation +---------------------------------------- + +The normal signing process (called Pure SLH-DSA Signature Generation) +encodes the message internally as 0x00 || len(ctx) || ctx || message. +where B is some optional value of size 0x00..0xFF. + +ACVP Testing requires the ability for the message to not be encoded also. This +will be controlled by settable parameters. + +Pre Hash SLH-DSA Signature Generation encode the message as +0x01 || len(ctx) || ctx || digest_OID || H(message). +The scenario that is stated that this is useful for is when this encoded message +is supplied from an external source. + +Currently I do not support the Pre Hash variant as this does not sit well with the +OpenSSL API's. The user could do the encoding themselves and then set the settable +to not encode the passed in message. + +Buffers +------- + +Many functions need to pass around key elements and return signature buffers of +various sizes which are often updated in loops in parts, all of these sizes +are known quantities. Currently there is no attempt to use wpacket to pass +around these sizes. asserts are currently done by the child functions to check +that the expected size does not exceed the size passed in by the parent.