POD: Fix list termination
[openssl.git] / crypto / bn / bn_rand.c
index b9ce9e5d3fb84fa819b40d4a35519ddd5a829d7b..d550f497d9f55da6b42aa4e1cee9d89eb4eba75d 100644 (file)
  *
  */
 
+#define OPENSSL_FIPSAPI
+
 #include <stdio.h>
 #include <time.h>
 #include "cryptlib.h"
 #include "bn_lcl.h"
 #include <openssl/rand.h>
+#include <openssl/sha.h>
 
 static int bnrand(int pseudorand, BIGNUM *rnd, int bits, int top, int bottom)
        {
@@ -134,13 +137,13 @@ static int bnrand(int pseudorand, BIGNUM *rnd, int bits, int top, int bottom)
        buf=(unsigned char *)OPENSSL_malloc(bytes);
        if (buf == NULL)
                {
-               BNerr(BN_F_BN_RAND,ERR_R_MALLOC_FAILURE);
+               BNerr(BN_F_BNRAND,ERR_R_MALLOC_FAILURE);
                goto err;
                }
 
        /* make a random number and set the top and bottom bits */
        time(&tim);
-       RAND_add(&tim,sizeof(tim),0);
+       RAND_add(&tim,sizeof(tim),0.0);
 
        if (pseudorand)
                {
@@ -201,9 +204,10 @@ static int bnrand(int pseudorand, BIGNUM *rnd, int bits, int top, int bottom)
 err:
        if (buf != NULL)
                {
-               memset(buf,0,bytes);
+               OPENSSL_cleanse(buf,bytes);
                OPENSSL_free(buf);
                }
+       bn_check_top(rnd);
        return(ret);
        }
 
@@ -226,10 +230,11 @@ int     BN_bntest_rand(BIGNUM *rnd, int bits, int top, int bottom)
 
 
 /* random number r:  0 <= r < range */
-static int bn_rand_range(int pseudo, BIGNUM *r, BIGNUM *range)
+static int bn_rand_range(int pseudo, BIGNUM *r, const BIGNUM *range)
        {
        int (*bn_rand)(BIGNUM *, int, int, int) = pseudo ? BN_pseudo_rand : BN_rand;
        int n;
+       int count = 100;
 
        if (range->neg || BN_is_zero(range))
                {
@@ -239,22 +244,21 @@ static int bn_rand_range(int pseudo, BIGNUM *r, BIGNUM *range)
 
        n = BN_num_bits(range); /* n > 0 */
 
+       /* BN_is_bit_set(range, n - 1) always holds */
+
        if (n == 1)
+               BN_zero(r);
+#ifdef OPENSSL_FIPS
+       /* FIPS 186-3 is picky about how random numbers for keys etc are
+        * generated. So we just use the second case which is equivalent to
+        * "Generation by Testing Candidates" mentioned in B.1.2 et al.
+        */
+       else if (!FIPS_module_mode() && !BN_is_bit_set(range, n - 2) && !BN_is_bit_set(range, n - 3))
+#else
+       else if (!BN_is_bit_set(range, n - 2) && !BN_is_bit_set(range, n - 3))
+#endif
                {
-               if (!BN_zero(r)) return 0;
-               }
-       else if (BN_is_bit_set(range, n - 2))
-               {
-               do
-                       {
-                       /* range = 11..._2, so each iteration succeeds with probability >= .75 */
-                       if (!bn_rand(r, n, -1, 0)) return 0;
-                       }
-               while (BN_cmp(r, range) >= 0);
-               }
-       else
-               {
-               /* range = 10..._2,
+               /* range = 100..._2,
                 * so  3*range (= 11..._2)  is exactly one bit longer than  range */
                do
                        {
@@ -270,20 +274,112 @@ static int bn_rand_range(int pseudo, BIGNUM *r, BIGNUM *range)
                                if (BN_cmp(r, range) >= 0)
                                        if (!BN_sub(r, r, range)) return 0;
                                }
+
+                       if (!--count)
+                               {
+                               BNerr(BN_F_BN_RAND_RANGE, BN_R_TOO_MANY_ITERATIONS);
+                               return 0;
+                               }
+                       
                        }
                while (BN_cmp(r, range) >= 0);
                }
+       else
+               {
+               do
+                       {
+                       /* range = 11..._2  or  range = 101..._2 */
+                       if (!bn_rand(r, n, -1, 0)) return 0;
 
+                       if (!--count)
+                               {
+                               BNerr(BN_F_BN_RAND_RANGE, BN_R_TOO_MANY_ITERATIONS);
+                               return 0;
+                               }
+                       }
+               while (BN_cmp(r, range) >= 0);
+               }
+
+       bn_check_top(r);
        return 1;
        }
 
 
-int    BN_rand_range(BIGNUM *r, BIGNUM *range)
+int    BN_rand_range(BIGNUM *r, const BIGNUM *range)
        {
        return bn_rand_range(0, r, range);
        }
 
-int    BN_pseudo_rand_range(BIGNUM *r, BIGNUM *range)
+int    BN_pseudo_rand_range(BIGNUM *r, const BIGNUM *range)
        {
        return bn_rand_range(1, r, range);
        }
+
+#ifndef OPENSSL_NO_SHA512
+/* BN_generate_dsa_nonce generates a random number 0 <= out < range. Unlike
+ * BN_rand_range, it also includes the contents of |priv| and |message| in the
+ * generation so that an RNG failure isn't fatal as long as |priv| remains
+ * secret. This is intended for use in DSA and ECDSA where an RNG weakness
+ * leads directly to private key exposure unless this function is used. */
+int BN_generate_dsa_nonce(BIGNUM *out, const BIGNUM *range, const BIGNUM* priv,
+                         const unsigned char *message, size_t message_len,
+                         BN_CTX *ctx)
+       {
+       SHA512_CTX sha;
+       /* We use 512 bits of random data per iteration to
+        * ensure that we have at least |range| bits of randomness. */
+       unsigned char random_bytes[64];
+       unsigned char digest[SHA512_DIGEST_LENGTH];
+       unsigned done, todo;
+       /* We generate |range|+8 bytes of random output. */
+       const unsigned num_k_bytes = BN_num_bytes(range) + 8;
+       unsigned char private_bytes[96];
+       unsigned char *k_bytes;
+       int ret = 0;
+
+       k_bytes = OPENSSL_malloc(num_k_bytes);
+       if (!k_bytes)
+               goto err;
+
+       /* We copy |priv| into a local buffer to avoid exposing its length. */
+       todo = sizeof(priv->d[0])*priv->top;
+       if (todo > sizeof(private_bytes))
+               {
+               /* No reasonable DSA or ECDSA key should have a private key
+                * this large and we don't handle this case in order to avoid
+                * leaking the length of the private key. */
+               BNerr(BN_F_BN_GENERATE_DSA_NONCE, BN_R_PRIVATE_KEY_TOO_LARGE);
+               goto err;
+               }
+       memcpy(private_bytes, priv->d, todo);
+       memset(private_bytes + todo, 0, sizeof(private_bytes) - todo);
+
+       for (done = 0; done < num_k_bytes;) {
+               if (RAND_bytes(random_bytes, sizeof(random_bytes)) != 1)
+                       goto err;
+               SHA512_Init(&sha);
+               SHA512_Update(&sha, &done, sizeof(done));
+               SHA512_Update(&sha, private_bytes, sizeof(private_bytes));
+               SHA512_Update(&sha, message, message_len);
+               SHA512_Update(&sha, random_bytes, sizeof(random_bytes));
+               SHA512_Final(digest, &sha);
+
+               todo = num_k_bytes - done;
+               if (todo > SHA512_DIGEST_LENGTH)
+                       todo = SHA512_DIGEST_LENGTH;
+               memcpy(k_bytes + done, digest, todo);
+               done += todo;
+       }
+
+       if (!BN_bin2bn(k_bytes, num_k_bytes, out))
+               goto err;
+       if (BN_mod(out, out, range, ctx) != 1)
+               goto err;
+       ret = 1;
+
+err:
+       if (k_bytes)
+               OPENSSL_free(k_bytes);
+       return ret;
+       }
+#endif  /* OPENSSL_NO_SHA512 */