Home | History | Annotate | Line # | Download | only in designs
      1 SLH-DSA Design
      2 ==============
      3 
      4 This document covers OpenSSL specific SLH-DSA implementation details.
      5 FIPS 205 clearly states most of the requirements of SLH-DSA and has comprehensive
      6 pseudo code for all its algorithms.
      7 
      8 SLH_DSA Parameters & Functions
      9 ------------------------------
     10 
     11 There are 12 different parameter sets in FIPS 205. (See Section 11)
     12 There are constants related to these, as well as there being a group of functions
     13 associated with each set.
     14 
     15 The constants include things like hash sizes and tree heights.
     16 
     17 OpenSSL will have 12 different key managers and 12 corresponding signature functions.
     18 The names used are of the form "SLH-DSA-SHA2-128s" and "SLH-DSA-SHAKE-128f".
     19 
     20 There are 7 hash functions used. The algorithms using SHAKE have a much simpler
     21 set of 7 functions as they just use SHAKE-256 XOF (Even for the SHAKE-128 names).
     22 The SHA2 algorithms are much more complex and require HMAC, MGF1, as well as digests.
     23 There are 2 sets of functions for the SHA2 case.
     24 
     25 Some of the hash functions use an ADRS object. This is 32 bytes for SHAKE algorithms
     26 and 22 bytes for SHA2. Because SHA2 used a compressed format the ADRS functions are
     27 different.
     28 
     29 There are many functions required to implement the sign and verify paths, which include
     30 Merkle trees and WOTS+. The different functions normally call one of 2 of the
     31 7 hash functions, as well as calling ADRS functions to pass to the HASH functions.
     32 
     33 Rather that duplicating this code 12 times for every function, the constants are
     34 stored within the SLH_DSA_KEY. This contains the HASH functions,
     35 the ADRS functions, and the parameter constants. It also contains pre fetched algorithms.
     36 A SLH_DSA_HASH_CTX object is also created, that references the key, as well as
     37 containing per operation hash context objects.
     38 This SLH_DSA_HASH_CTX is then passed to all functions. This context is allocated in the
     39 provider's SLH_DSA signature context.
     40 
     41 SLH-DSA keys
     42 ------------
     43 
     44 SLH-DSA keys have 2 elements of size `n` for both the public and private keys.
     45 Since different algorithms have different key sizes, buffers of the maximum size
     46 will be used to hold the keys (since the keys are only a maximum of 64 bytes each)
     47 
     48 struct slh_dsa_key_st {
     49     /* The public key consists of a SEED and ROOT values each of size |n| */
     50     uint8_t pub[SLH_DSA_MAX_KEYLEN];
     51     /* The private key consists of a SEED and PRF values of size |n| */
     52     uint8_t priv[SLH_DSA_MAX_KEYLEN];
     53     size_t key_len; /* This value is set to 2 * n if there is a public key */
     54     /* contains the algorithm name and constants such as |n| */
     55     const SLH_DSA_PARAMS *params;
     56     int has_priv; /* Set to 1 if there is a private key component */
     57     ...
     58 };
     59 
     60 The fields `key_len` and `has_priv` are used to determine if a key has loaded
     61 the public and private key elements.
     62 The `params` field is the parameter set which is resolved via the algorithm name.
     63 
     64 In FIPS 205 the SLH_DSA private key contains the public key.
     65 In OpenSSL these components are stored separately, so there must always be a
     66 public key in order for the key to be valid.
     67 
     68 The key generation process creates a private key and half of the public key
     69 using DRBG's. The public key root component is then computed based on these
     70 values. For ACVP testing these values are supplied as an ENTROPY parameter.
     71 It is assumed that from data will not deal with a partial public key, and if this
     72 is required the user should use the key generation operation.
     73 
     74 Pure vs Pre Hashed Signature Generation
     75 ----------------------------------------
     76 
     77 The normal signing process (called Pure SLH-DSA Signature Generation)
     78 encodes the message internally as 0x00 || len(ctx) || ctx || message.
     79 where `ctx` is some optional value of size 0x00..0xFF.
     80 
     81 ACVP Testing requires the ability for the message to not be encoded also. This
     82 will be controlled by settable parameters.
     83 
     84 Pre Hash SLH-DSA Signature Generation encodes the message as
     85 
     86 ```c
     87 0x01 || len(ctx) || ctx || digest_OID || H(message).
     88 ```
     89 
     90 The scenario that is stated that this is useful for is when this encoded message
     91 is supplied from an external source.
     92 
     93 Currently we do not support the Pre Hash variant as this does not sit well with the
     94 OpenSSL API's.
     95 
     96 Signing API
     97 -------------
     98 
     99 As only the one-shot implementation is required and the message is not digested
    100 the API's used should be
    101 
    102 EVP_PKEY_sign_message_init(), EVP_PKEY_sign(),
    103 EVP_PKEY_verify_message_init(), EVP_PKEY_verify().
    104 
    105 OpenSSL command line support
    106 ----------------------------
    107 
    108 For backwards compatibility reasons EVP_DigestSignInit_ex(), EVP_DigestSign(),
    109 EVP_DigestVerifyInit_ex() and EVP_DigestVerify() may also be used, but the digest
    110 passed in `mdname` must be NULL (i.e. it effectively behaves the same as above).
    111 Passing a non NULL digest results in an error.
    112 
    113 OSSL_PKEY_PARAM_MANDATORY_DIGEST must return "" in the key manager getter and
    114 OSSL_SIGNATURE_PARAM_ALGORITHM_ID in the signature context getter.
    115 
    116 Buffers
    117 -------
    118 
    119 There are many functions pass buffers of size `n` Where n is one of 16,24,32
    120 depending on the algorithm name. These are used for key elements and hashes, so
    121 PACKETS are not used for these.
    122 
    123 Where it makes sense to, WPACKET is used for output (such as signature generation)
    124 and PACKET for reading signature data.
    125 
    126 Constant Time Considerations
    127 ----------------------------
    128 
    129 As the security of SLH-DSA depends only on hash functions, we do not foresee
    130 there being any constant time issues. Some if statements have been added to
    131 detect failures in hash operations, and these errors are propagated all the way
    132 up the function call stack. These errors should not happen in general so should
    133 not affect the security of the algorithms.
    134