Home | History | Annotate | Line # | Download | only in crypto
      1 /*
      2  * Copyright 2022-2024 The OpenSSL Project Authors. All Rights Reserved.
      3  *
      4  * Licensed under the Apache License 2.0 (the "License").  You may not use
      5  * this file except in compliance with the License.  You can obtain a copy
      6  * in the file LICENSE in the source distribution or at
      7  * https://www.openssl.org/source/license.html
      8  */
      9 
     10 #include <string.h>
     11 #include <openssl/bn.h>
     12 #include <openssl/evp.h>
     13 #include <openssl/core_names.h>
     14 #include <openssl/kdf.h>
     15 #include "internal/deterministic_nonce.h"
     16 #include "crypto/bn.h"
     17 
     18 /*
     19  * Convert a Bit String to an Integer (See RFC 6979 Section 2.3.2)
     20  *
     21  * Params:
     22  *     out The returned Integer as a BIGNUM
     23  *     qlen_bits The maximum size of the returned integer in bits. The returned
     24  *        Integer is shifted right if inlen is larger than qlen_bits..
     25  *     in, inlen The input Bit String (in bytes).
     26  * Returns: 1 if successful, or  0 otherwise.
     27  */
     28 static int bits2int(BIGNUM *out, int qlen_bits,
     29     const unsigned char *in, size_t inlen)
     30 {
     31     int blen_bits = inlen * 8;
     32     int shift;
     33 
     34     if (BN_bin2bn(in, (int)inlen, out) == NULL)
     35         return 0;
     36 
     37     shift = blen_bits - qlen_bits;
     38     if (shift > 0)
     39         return BN_rshift(out, out, shift);
     40     return 1;
     41 }
     42 
     43 /*
     44  * Convert as above a Bit String in const time to an Integer w fixed top
     45  *
     46  * Params:
     47  *     out The returned Integer as a BIGNUM
     48  *     qlen_bits The maximum size of the returned integer in bits. The returned
     49  *        Integer is shifted right if inlen is larger than qlen_bits..
     50  *     in, inlen The input Bit String (in bytes). It has sizeof(BN_ULONG) bytes
     51  *               prefix with all bits set that needs to be cleared out after
     52  *               the conversion.
     53  * Returns: 1 if successful, or  0 otherwise.
     54  */
     55 static int bits2int_consttime(BIGNUM *out, int qlen_bits,
     56     const unsigned char *in, size_t inlen)
     57 {
     58     int blen_bits = (inlen - sizeof(BN_ULONG)) * 8;
     59     int shift;
     60 
     61     if (BN_bin2bn(in, (int)inlen, out) == NULL)
     62         return 0;
     63 
     64     BN_set_flags(out, BN_FLG_CONSTTIME);
     65     ossl_bn_mask_bits_fixed_top(out, blen_bits);
     66 
     67     shift = blen_bits - qlen_bits;
     68     if (shift > 0)
     69         return bn_rshift_fixed_top(out, out, shift);
     70     return 1;
     71 }
     72 
     73 /*
     74  * Convert an Integer to an Octet String (See RFC 6979 2.3.3).
     75  * The value is zero padded if required.
     76  *
     77  * Params:
     78  *     out The returned Octet String
     79  *     num The input Integer
     80  *     rlen The required size of the returned Octet String in bytes
     81  * Returns: 1 if successful, or  0 otherwise.
     82  */
     83 static int int2octets(unsigned char *out, const BIGNUM *num, int rlen)
     84 {
     85     return BN_bn2binpad(num, out, rlen) >= 0;
     86 }
     87 
     88 /*
     89  * Convert a Bit String to an Octet String (See RFC 6979 Section 2.3.4)
     90  *
     91  * Params:
     92  *     out The returned octet string.
     93  *     q The modulus
     94  *     qlen_bits The length of q in bits
     95  *     rlen The value of qlen_bits rounded up to the nearest 8 bits.
     96  *     in, inlen The input bit string (in bytes)
     97  * Returns: 1 if successful, or  0 otherwise.
     98  */
     99 static int bits2octets(unsigned char *out, const BIGNUM *q, int qlen_bits,
    100     int rlen, const unsigned char *in, size_t inlen)
    101 {
    102     int ret = 0;
    103     BIGNUM *z = BN_new();
    104 
    105     if (z == NULL
    106         || !bits2int(z, qlen_bits, in, inlen))
    107         goto err;
    108 
    109     /* z2 = z1 mod q (Do a simple subtract, since z1 < 2^qlen_bits) */
    110     if (BN_cmp(z, q) >= 0
    111         && !BN_usub(z, z, q))
    112         goto err;
    113 
    114     ret = int2octets(out, z, rlen);
    115 err:
    116     BN_free(z);
    117     return ret;
    118 }
    119 
    120 /*
    121  * Setup a KDF HMAC_DRBG object using fixed entropy and nonce data.
    122  *
    123  * Params:
    124  *     digestname The digest name for the HMAC
    125  *     entropy, entropylen A fixed input entropy buffer
    126  *     nonce, noncelen A fixed input nonce buffer
    127  *     libctx, propq Are used for fetching algorithms
    128  *
    129  * Returns: The created KDF HMAC_DRBG object if successful, or NULL otherwise.
    130  */
    131 static EVP_KDF_CTX *kdf_setup(const char *digestname,
    132     const unsigned char *entropy, size_t entropylen,
    133     const unsigned char *nonce, size_t noncelen,
    134     OSSL_LIB_CTX *libctx, const char *propq)
    135 {
    136     EVP_KDF_CTX *ctx = NULL;
    137     EVP_KDF *kdf = NULL;
    138     OSSL_PARAM params[5], *p;
    139 
    140     kdf = EVP_KDF_fetch(libctx, "HMAC-DRBG-KDF", propq);
    141     ctx = EVP_KDF_CTX_new(kdf);
    142     EVP_KDF_free(kdf);
    143     if (ctx == NULL)
    144         goto err;
    145 
    146     p = params;
    147     *p++ = OSSL_PARAM_construct_utf8_string(OSSL_KDF_PARAM_DIGEST,
    148         (char *)digestname, 0);
    149     if (propq != NULL)
    150         *p++ = OSSL_PARAM_construct_utf8_string(OSSL_KDF_PARAM_PROPERTIES,
    151             (char *)propq, 0);
    152     *p++ = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_HMACDRBG_ENTROPY,
    153         (void *)entropy, entropylen);
    154     *p++ = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_HMACDRBG_NONCE,
    155         (void *)nonce, noncelen);
    156     *p = OSSL_PARAM_construct_end();
    157 
    158     if (EVP_KDF_CTX_set_params(ctx, params) <= 0)
    159         goto err;
    160 
    161     return ctx;
    162 err:
    163     EVP_KDF_CTX_free(ctx);
    164     return NULL;
    165 }
    166 
    167 /*
    168  * Generate a Deterministic nonce 'k' for DSA/ECDSA as defined in
    169  * RFC 6979 Section 3.3.  "Alternate Description of the Generation of k"
    170  *
    171  * Params:
    172  *     out Returns the generated deterministic nonce 'k'
    173  *     q A large prime number used for modulus operations for DSA and ECDSA.
    174  *     priv The private key in the range [1, q-1]
    175  *     hm, hmlen The digested message buffer in bytes
    176  *     digestname The digest name used for signing. It is used as the HMAC digest.
    177  *     libctx, propq Used for fetching algorithms
    178  *
    179  * Returns: 1 if successful, or  0 otherwise.
    180  */
    181 int ossl_gen_deterministic_nonce_rfc6979(BIGNUM *out, const BIGNUM *q,
    182     const BIGNUM *priv,
    183     const unsigned char *hm, size_t hmlen,
    184     const char *digestname,
    185     OSSL_LIB_CTX *libctx,
    186     const char *propq)
    187 {
    188     EVP_KDF_CTX *kdfctx = NULL;
    189     int ret = 0, rlen = 0, qlen_bits = 0;
    190     unsigned char *entropyx = NULL, *nonceh = NULL, *rbits = NULL, *T = NULL;
    191     size_t allocsz = 0;
    192     const size_t prefsz = sizeof(BN_ULONG);
    193 
    194     if (out == NULL)
    195         return 0;
    196 
    197     qlen_bits = BN_num_bits(q);
    198     if (qlen_bits == 0)
    199         return 0;
    200 
    201     /* Note rlen used here is in bytes since the input values are byte arrays */
    202     rlen = (qlen_bits + 7) / 8;
    203     allocsz = prefsz + 3 * rlen;
    204 
    205     /* Use a single alloc for the buffers T, nonceh and entropyx */
    206     T = (unsigned char *)OPENSSL_zalloc(allocsz);
    207     if (T == NULL)
    208         return 0;
    209     rbits = T + prefsz;
    210     nonceh = rbits + rlen;
    211     entropyx = nonceh + rlen;
    212 
    213     memset(T, 0xff, prefsz);
    214 
    215     if (!int2octets(entropyx, priv, rlen)
    216         || !bits2octets(nonceh, q, qlen_bits, rlen, hm, hmlen))
    217         goto end;
    218 
    219     kdfctx = kdf_setup(digestname, entropyx, rlen, nonceh, rlen, libctx, propq);
    220     if (kdfctx == NULL)
    221         goto end;
    222 
    223     do {
    224         if (!EVP_KDF_derive(kdfctx, rbits, rlen, NULL)
    225             || !bits2int_consttime(out, qlen_bits, T, rlen + prefsz))
    226             goto end;
    227     } while (ossl_bn_is_word_fixed_top(out, 0)
    228         || ossl_bn_is_word_fixed_top(out, 1)
    229         || BN_ucmp(out, q) >= 0);
    230 #ifdef BN_DEBUG
    231     /* With BN_DEBUG on a fixed top number cannot be returned */
    232     bn_correct_top(out);
    233 #endif
    234     ret = 1;
    235 
    236 end:
    237     EVP_KDF_CTX_free(kdfctx);
    238     OPENSSL_clear_free(T, allocsz);
    239     return ret;
    240 }
    241