Commit 8a99cb29 authored by Adam Langley's avatar Adam Langley Committed by Ben Laurie
Browse files

Add secure DSA nonce flag.

This change adds the option to calculate (EC)DSA nonces by hashing the
message and private key along with entropy to avoid leaking the private
key if the PRNG fails.
parent 64a786a2
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -676,6 +676,10 @@ const BIGNUM *BN_get0_nist_prime_521(void);

int (*BN_nist_mod_func(const BIGNUM *p))(BIGNUM *r, const BIGNUM *a, const BIGNUM *field, BN_CTX *ctx);

int BN_generate_dsa_nonce(BIGNUM *out, const BIGNUM *range, const BIGNUM *priv,
			  const unsigned char *message, size_t message_len,
			  BN_CTX *ctx);

/* library internal functions */

#define bn_expand(a,bits) ((((((bits+BN_BITS2-1))/BN_BITS2)) <= (a)->dmax)?\
@@ -868,6 +872,7 @@ void ERR_load_BN_strings(void);
#define BN_R_NOT_INITIALIZED				 107
#define BN_R_NO_INVERSE					 108
#define BN_R_NO_SOLUTION				 116
#define BN_R_PRIVATE_KEY_TOO_LARGE			 117
#define BN_R_P_IS_NOT_PRIME				 112
#define BN_R_TOO_MANY_ITERATIONS			 113
#define BN_R_TOO_MANY_TEMPORARY_VARIABLES		 109
+2 −1
Original line number Diff line number Diff line
/* crypto/bn/bn_err.c */
/* ====================================================================
 * Copyright (c) 1999-2007 The OpenSSL Project.  All rights reserved.
 * Copyright (c) 1999-2013 The OpenSSL Project.  All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
@@ -132,6 +132,7 @@ static ERR_STRING_DATA BN_str_reasons[]=
{ERR_REASON(BN_R_NOT_INITIALIZED)        ,"not initialized"},
{ERR_REASON(BN_R_NO_INVERSE)             ,"no inverse"},
{ERR_REASON(BN_R_NO_SOLUTION)            ,"no solution"},
{ERR_REASON(BN_R_PRIVATE_KEY_TOO_LARGE)  ,"private key too large"},
{ERR_REASON(BN_R_P_IS_NOT_PRIME)         ,"p is not prime"},
{ERR_REASON(BN_R_TOO_MANY_ITERATIONS)    ,"too many iterations"},
{ERR_REASON(BN_R_TOO_MANY_TEMPORARY_VARIABLES),"too many temporary variables"},
+70 −0
Original line number Diff line number Diff line
@@ -116,6 +116,7 @@
#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)
	{
@@ -313,3 +314,72 @@ 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 */
+24 −8
Original line number Diff line number Diff line
@@ -91,13 +91,27 @@
#define OPENSSL_DSA_FIPS_MIN_MODULUS_BITS 1024

#define DSA_FLAG_CACHE_MONT_P	0x01
#define DSA_FLAG_NO_EXP_CONSTTIME       0x02 /* new with 0.9.7h; the built-in DSA
                                              * implementation now uses constant time
                                              * modular exponentiation for secret exponents
                                              * by default. This flag causes the
                                              * faster variable sliding window method to
                                              * be used for all exponents.
#define DSA_FLAG_NO_EXP_CONSTTIME       0x02 /* new with 0.9.7h; the
                                              * built-in DSA
                                              * implementation now
                                              * uses constant time
                                              * modular exponentiation
                                              * for secret exponents
                                              * by default. This flag
                                              * causes the faster
                                              * variable sliding
                                              * window method to be
                                              * used for all
                                              * exponents.
                                              */
#define DSA_FLAG_NONCE_FROM_HASH	0x04 /* Causes the DSA nonce
					      * to be calculated from
					      * SHA512(private_key +
					      * H(message) +
					      * random). This
					      * strengthens DSA
					      * against a weak
					      * PRNG. */

/* If this flag is set the DSA method is FIPS compliant and can be used
 * in FIPS mode. This is set in the validated module method. If an
@@ -133,8 +147,9 @@ struct dsa_method
	{
	const char *name;
	DSA_SIG * (*dsa_do_sign)(const unsigned char *dgst, int dlen, DSA *dsa);
	int (*dsa_sign_setup)(DSA *dsa, BN_CTX *ctx_in, BIGNUM **kinvp,
								BIGNUM **rp);
	int (*dsa_sign_setup)(DSA *dsa, BN_CTX *ctx_in,
			      BIGNUM **kinvp, BIGNUM **rp,
			      const unsigned char *dgst, int dlen);
	int (*dsa_do_verify)(const unsigned char *dgst, int dgst_len,
			     DSA_SIG *sig, DSA *dsa);
	int (*dsa_mod_exp)(DSA *dsa, BIGNUM *rr, BIGNUM *a1, BIGNUM *p1,
@@ -338,6 +353,7 @@ void ERR_load_DSA_strings(void);
#define DSA_R_MISSING_PARAMETERS			 101
#define DSA_R_MODULUS_TOO_LARGE				 103
#define DSA_R_NEED_NEW_SETUP_VALUES			 110
#define DSA_R_NONCE_CANNOT_BE_PRECOMPUTED		 114
#define DSA_R_NO_PARAMETERS_SET				 107
#define DSA_R_PARAMETER_ENCODING_ERROR			 105
#define DSA_R_Q_NOT_PRIME				 113
+2 −1
Original line number Diff line number Diff line
/* crypto/dsa/dsa_err.c */
/* ====================================================================
 * Copyright (c) 1999-2010 The OpenSSL Project.  All rights reserved.
 * Copyright (c) 1999-2013 The OpenSSL Project.  All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
@@ -112,6 +112,7 @@ static ERR_STRING_DATA DSA_str_reasons[]=
{ERR_REASON(DSA_R_MISSING_PARAMETERS)    ,"missing parameters"},
{ERR_REASON(DSA_R_MODULUS_TOO_LARGE)     ,"modulus too large"},
{ERR_REASON(DSA_R_NEED_NEW_SETUP_VALUES) ,"need new setup values"},
{ERR_REASON(DSA_R_NONCE_CANNOT_BE_PRECOMPUTED),"nonce cannot be precomputed"},
{ERR_REASON(DSA_R_NO_PARAMETERS_SET)     ,"no parameters set"},
{ERR_REASON(DSA_R_PARAMETER_ENCODING_ERROR),"parameter encoding error"},
{ERR_REASON(DSA_R_Q_NOT_PRIME)           ,"q not prime"},
Loading