Commit 24172bd2 authored by Evan Hunt's avatar Evan Hunt
Browse files

[master] completed and corrected the crypto-random change

4724.	[func]		By default, BIND now uses the random number
			functions provided by the crypto library (i.e.,
			OpenSSL or a PKCS#11 provider) as a source of
			randomness rather than /dev/random.  This is
			suitable for virtual machine environments
			which have limited entropy pools and lack
			hardware random number generators.

			This can be overridden by specifying another
			entropy source via the "random-device" option
			in named.conf, or via the -r command line option;
			however, for functions requiring full cryptographic
			strength, such as DNSSEC key generation, this
			cannot be overridden. In particular, the -r
			command line option no longer has any effect on
			dnssec-keygen.

			This can be disabled by building with
			"configure --disable-crypto-rand".
			[RT #31459] [RT #46047]
parent 86e5d14e
......@@ -63,15 +63,26 @@
location to be reported is "update_completed".
[RT #46014]
 
4724. [func] When the random device (i.e. the "random-device"
option in named.conf, or the -r command line option
in various tools) is set to "openssl", the OpenSSL
RAND routine is used as the source of entropy/
randomness. This is suitable for a virtual
machine environment without a hardware random
number generator. This behavior can be overridden
by using "configure --disable-crypto-rand" or
native PKCS#11. [RT #31459]
4724. [func] By default, BIND now uses the random number
functions provided by the crypto library (i.e.,
OpenSSL or a PKCS#11 provider) as a source of
randomness rather than /dev/random. This is
suitable for virtual machine environments
which have limited entropy pools and lack
hardware random number generators.
This can be overridden by specifying another
entropy source via the "random-device" option
in named.conf, or via the -r command line option;
however, for functions requiring full cryptographic
strength, such as DNSSEC key generation, this
cannot be overridden. In particular, the -r
command line option no longer has any effect on
dnssec-keygen.
This can be disabled by building with
"configure --disable-crypto-rand".
[RT #31459] [RT #46047]
 
4723. [bug] Statistics counter DNSTAPdropped was misidentified
as DNSSECdropped. [RT #46002]
......
......@@ -151,17 +151,15 @@ generate_key(isc_mem_t *mctx, const char *randomfile, dns_secalg_t alg,
DO("create entropy context", isc_entropy_create(mctx, &ectx));
if (randomfile != NULL && strcmp(randomfile, "keyboard") == 0) {
randomfile = NULL;
open_keyboard = ISC_ENTROPY_KEYBOARDYES;
}
#ifdef ISC_PLATFORM_CRYPTORANDOM
if (randomfile != NULL &&
strcmp(randomfile, ISC_PLATFORM_CRYPTORANDOM) == 0) {
randomfile = NULL;
if (randomfile == NULL) {
isc_entropy_usehook(ectx, ISC_TRUE);
}
#endif
if (randomfile != NULL && strcmp(randomfile, "keyboard") == 0) {
randomfile = NULL;
open_keyboard = ISC_ENTROPY_KEYBOARDYES;
}
DO("start entropy source", isc_entropy_usebestsource(ectx,
&entropy_source,
randomfile,
......
......@@ -347,15 +347,23 @@
<term>-r <replaceable class="parameter">randomdev</replaceable></term>
<listitem>
<para>
Specifies the source of randomness. If the operating
system does not provide a <filename>/dev/random</filename>
or equivalent device, the default source of randomness
is keyboard input. <filename>randomdev</filename>
specifies
Specifies a source of randomness. Normally, when generating
DNSSEC keys, this option has no effect; the random number
generation function provided by the cryptographic library will
be used.
</para>
<para>
If that behavior is disabled at compile time, however,
the specified file will be used as entropy source
for key generation. <filename>randomdev</filename> is
the name of a character device or file containing random
data to be used instead of the default. The special value
<filename>keyboard</filename> indicates that keyboard
input should be used.
data to be used. The special value <filename>keyboard</filename>
indicates that keyboard input should be used.
</para>
<para>
The default is <filename>/dev/random</filename> if the
operating system provides it or an equivalent device;
if not, the default source of randomness is keyboard input.
</para>
</listitem>
</varlistentry>
......
......@@ -234,18 +234,16 @@ setup_entropy(isc_mem_t *mctx, const char *randomfile, isc_entropy_t **ectx) {
ISC_LIST_INIT(sources);
}
#ifdef ISC_PLATFORM_CRYPTORANDOM
if (randomfile == NULL) {
isc_entropy_usehook(*ectx, ISC_TRUE);
}
#endif
if (randomfile != NULL && strcmp(randomfile, "keyboard") == 0) {
usekeyboard = ISC_ENTROPY_KEYBOARDYES;
randomfile = NULL;
}
#ifdef ISC_PLATFORM_CRYPTORANDOM
if (randomfile != NULL &&
strcmp(randomfile, ISC_PLATFORM_CRYPTORANDOM) == 0) {
randomfile = NULL;
isc_entropy_usehook(*ectx, ISC_TRUE);
}
#endif
result = isc_entropy_usebestsource(*ectx, &source, randomfile,
usekeyboard);
......
......@@ -86,7 +86,9 @@ options {\n\
# pid-file \"" NAMED_LOCALSTATEDIR "/run/named/named.pid\"; \n\
port 53;\n\
prefetch 2 9;\n"
#ifdef PATH_RANDOMDEV
#if defined(ISC_PLATFORM_CRYPTORANDOM)
" random-device none;\n"
#elif defined(PATH_RANDOMDEV)
" random-device \"" PATH_RANDOMDEV "\";\n"
#endif
" recursing-file \"named.recursing\";\n\
......
......@@ -320,9 +320,10 @@ log_invalid(isccc_ccmsg_t *ccmsg, isc_result_t result) {
static void
control_recvmessage(isc_task_t *task, isc_event_t *event) {
controlconnection_t *conn;
controllistener_t *listener;
controlkey_t *key;
controlconnection_t *conn = NULL;
controllistener_t *listener = NULL;
named_server_t *server = NULL;
controlkey_t *key = NULL;
isccc_sexpr_t *request = NULL;
isccc_sexpr_t *response = NULL;
isc_uint32_t algorithm;
......@@ -333,16 +334,17 @@ control_recvmessage(isc_task_t *task, isc_event_t *event) {
isc_buffer_t *text;
isc_result_t result;
isc_result_t eresult;
isccc_sexpr_t *_ctrl;
isccc_sexpr_t *_ctrl = NULL;
isccc_time_t sent;
isccc_time_t exp;
isc_uint32_t nonce;
isccc_sexpr_t *data;
isccc_sexpr_t *data = NULL;
REQUIRE(event->ev_type == ISCCC_EVENT_CCMSG);
conn = event->ev_arg;
listener = conn->listener;
server = listener->controls->server;
algorithm = DST_ALG_UNKNOWN;
secret.rstart = NULL;
text = NULL;
......@@ -453,8 +455,11 @@ control_recvmessage(isc_task_t *task, isc_event_t *event) {
* Establish nonce.
*/
if (conn->nonce == 0) {
while (conn->nonce == 0)
isc_random_get(&conn->nonce);
while (conn->nonce == 0) {
isc_uint16_t r1 = isc_rng_random(server->sctx->rngctx);
isc_uint16_t r2 = isc_rng_random(server->sctx->rngctx);
conn->nonce = (r1 << 16) | r2;
}
eresult = ISC_R_SUCCESS;
} else
eresult = named_control_docommand(request, listener->readonly,
......
......@@ -8289,34 +8289,47 @@ load_configuration(const char *filename, named_server_t *server,
* Open the source of entropy.
*/
if (first_time) {
const char *randomdev = NULL;
int level = ISC_LOG_ERROR;
obj = NULL;
result = named_config_get(maps, "random-device", &obj);
if (result != ISC_R_SUCCESS) {
if (result == ISC_R_SUCCESS) {
if (!cfg_obj_isvoid(obj)) {
level = ISC_LOG_INFO;
randomdev = cfg_obj_asstring(obj);
}
}
if (randomdev == NULL) {
#ifdef ISC_PLATFORM_CRYPTORANDOM
isc_entropy_usehook(named_g_entropy, ISC_TRUE);
#else
if ((obj != NULL) && !cfg_obj_isvoid(obj))
level = ISC_LOG_INFO;
isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
NAMED_LOGMODULE_SERVER, level,
"no source of entropy found");
if ((obj == NULL) || cfg_obj_isvoid(obj)) {
CHECK(ISC_R_FAILURE);
}
#endif
} else {
const char *randomdev = cfg_obj_asstring(obj);
#ifdef ISC_PLATFORM_CRYPTORANDOM
if (strcmp(randomdev, ISC_PLATFORM_CRYPTORANDOM) == 0)
isc_entropy_usehook(named_g_entropy, ISC_TRUE);
#else
int level = ISC_LOG_ERROR;
result = isc_entropy_createfilesource(named_g_entropy,
randomdev);
#ifdef PATH_RANDOMDEV
if (named_g_fallbackentropy != NULL)
if (named_g_fallbackentropy != NULL) {
level = ISC_LOG_INFO;
}
#endif
if (result != ISC_R_SUCCESS)
if (result != ISC_R_SUCCESS) {
isc_log_write(named_g_lctx,
NAMED_LOGCATEGORY_GENERAL,
NAMED_LOGMODULE_SERVER,
level,
"could not open entropy source "
"%s: %s",
"could not open "
"entropy source %s: %s",
randomdev,
isc_result_totext(result));
}
#ifdef PATH_RANDOMDEV
if (named_g_fallbackentropy != NULL) {
if (result != ISC_R_SUCCESS) {
......@@ -8334,7 +8347,6 @@ load_configuration(const char *filename, named_server_t *server,
}
isc_entropy_detach(&named_g_fallbackentropy);
}
#endif
#endif
}
}
......@@ -13298,10 +13310,10 @@ newzone_cfgctx_destroy(void **cfgp) {
static isc_result_t
generate_salt(unsigned char *salt, size_t saltlen) {
int i, n;
size_t i, n;
union {
unsigned char rnd[256];
isc_uint32_t rnd32[64];
isc_uint16_t rnd16[128];
} rnd;
unsigned char text[512 + 1];
isc_region_t r;
......@@ -13311,9 +13323,10 @@ generate_salt(unsigned char *salt, size_t saltlen) {
if (saltlen > 256U)
return (ISC_R_RANGE);
n = (int) (saltlen + sizeof(isc_uint32_t) - 1) / sizeof(isc_uint32_t);
for (i = 0; i < n; i++)
isc_random_get(&rnd.rnd32[i]);
n = (saltlen + sizeof(isc_uint16_t) - 1) / sizeof(isc_uint16_t);
for (i = 0; i < n; i++) {
rnd.rnd16[i] = isc_rng_random(named_g_server->sctx->rngctx);
}
memmove(salt, rnd.rnd, saltlen);
......
......@@ -273,9 +273,7 @@ setup_entropy(isc_mem_t *mctx, const char *randomfile, isc_entropy_t **ectx) {
}
#ifdef ISC_PLATFORM_CRYPTORANDOM
if (randomfile != NULL &&
strcmp(randomfile, ISC_PLATFORM_CRYPTORANDOM) == 0) {
randomfile = NULL;
if (randomfile == NULL) {
isc_entropy_usehook(*ectx, ISC_TRUE);
}
#endif
......
......@@ -248,9 +248,7 @@ main(int argc, char *argv[]) {
ectx = NULL;
RUNCHECK(isc_entropy_create(mctx, &ectx));
#ifdef ISC_PLATFORM_CRYPTORANDOM
if (randomfile != NULL &&
strcmp(randomfile, ISC_PLATFORM_CRYPTORANDOM) == 0) {
randomfile = NULL;
if (randomfile == NULL) {
isc_entropy_usehook(ectx, ISC_TRUE);
}
#endif
......
......@@ -250,9 +250,7 @@ main(int argc, char *argv[]) {
ectx = NULL;
RUNCHECK(isc_entropy_create(mctx, &ectx));
#ifdef ISC_PLATFORM_CRYPTORANDOM
if (randomfile != NULL &&
strcmp(randomfile, ISC_PLATFORM_CRYPTORANDOM) == 0) {
randomfile = NULL;
if (randomfile == NULL) {
isc_entropy_usehook(ectx, ISC_TRUE);
}
#endif
......
......@@ -180,9 +180,7 @@ main(int argc, char **argv) {
ectx = NULL;
RUNCHECK(isc_entropy_create(mctx, &ectx));
#ifdef ISC_PLATFORM_CRYPTORANDOM
if (randomfile != NULL &&
strcmp(randomfile, ISC_PLATFORM_CRYPTORANDOM) == 0) {
randomfile = NULL;
if (randomfile == NULL) {
isc_entropy_usehook(ectx, ISC_TRUE);
}
#endif
......
......@@ -5274,22 +5274,45 @@ badresp:1,adberr:0,findfail:0,valfail:0]
<term><command>random-device</command></term>
<listitem>
<para>
The source of entropy to be used by the server. Entropy is
primarily needed
for DNSSEC operations, such as TKEY transactions and dynamic
update of signed
zones. This options specifies the device (or file) from which
to read
entropy. If this is a file, operations requiring entropy will
fail when the
file has been exhausted. If not specified, the default value
is
<filename>/dev/random</filename>
(or equivalent) when present, and none otherwise. The
<command>random-device</command> option takes
effect during
the initial configuration load at server startup time and
is ignored on subsequent reloads.
Specifies a source of entropy to be used by the server.
This is a device or file from which to read entropy.
If it is a file, operations requiring entropy
will fail when the file has been exhausted.
</para>
<para>
Entropy is needed for cryptographic operations such as
TKEY transactions, dynamic update of signed zones, and
generation of TSIG session keys. It is also used for
seeding and stirring the pseudo-random number generator,
which is used for less critical functions requiring
randomness such as generation of DNS message transaction
ID's.
</para>
<para>
If <command>random-device</command> is not specified, or
if it is set to <literal>none</literal>, entropy will be
read from the random number generation function supplied
by the cryptographic library with which BIND was linked
(i.e. OpenSSL or a PKCS#11 provider).
</para>
<para>
The <command>random-device</command> option takes
effect during the initial configuration load at server
startup time and is ignored on subsequent reloads.
</para>
<para>
If BIND is built with
<command>configure --disable-crypto-rand</command>, then
entropy is <emphasis>not</emphasis> sourced from the
cryptographic library. In this case, if
<command>random-device</command> is not specified, the
default value is the system random device,
<filename>/dev/random</filename> or the equivalent.
This default can be overridden with
<command>configure --with-randomdev</command>.
If no system random device exists, then no entropy source
will be configured, and <command>named</command> will only
be able to use pseudo-random numbers.
</para>
</listitem>
</varlistentry>
......
......@@ -362,20 +362,28 @@
</listitem>
<listitem>
<para>
When <command>named</command> is linked with OpenSSL, the
OpenSSL RAND routine can be used as the source of entropy/
randomness by specifying
<command>random-device openssl;</command> in
<filename>named.conf</filename>. It can also be used in tools
such as <command>dnssec-keygen</command>,
<command>tsig-keygen</command>,
and <command>nsupdate</command> by specifying
<command>-r openssl</command> on the command line.
This is suitable for a virtual machine environment without
a hardware random number generator.
This behavior can be overridden by using
<command>configure --disable-crypto-rand</command> or
building with native PKCS#11. [RT #31459]
By default, BIND now uses the random number generation functions
in the cryptographic library (i.e., OpenSSL or a PKCS#11
provider) as a source of high-quality randomness rather than
<filename>/dev/random</filename>. This is suitable for virtual
machine environments, which may have limited entropy pools and
lack hardware random number generators.
</para>
<para>
This can be overridden by specifying another entropy source via
the <command>random-device</command> option in
<filename>named.conf</filename>, or via the <command>-r</command>
command line option. However, for functions requiring full
cryptographic strength, such as DNSSEC key generation, this
<emphasis>cannot</emphasis> be overridden. In particular, the
<command>-r</command> command line option no longer has any
effect on <command>dnssec-keygen</command>.
</para>
<para>
This can be disabled by building with
<command>configure --disable-crypto-rand</command>, in which
case <filename>/dev/random</filename> will be the default
entropy source. [RT #31459] [RT #46047]
</para>
</listitem>
</itemizedlist>
......
......@@ -269,8 +269,9 @@ dst_lib_init2(isc_mem_t *mctx, isc_entropy_t *ectx,
#endif
#if defined(OPENSSL) || defined(PKCS11CRYPTO)
#ifdef ISC_PLATFORM_CRYPTORANDOM
if (dst_entropy_pool != NULL)
if (dst_entropy_pool != NULL) {
isc_entropy_sethook(dst_random_getdata);
}
#endif
#endif /* defined(OPENSSL) || defined(PKCS11CRYPTO) */
dst_initialized = ISC_TRUE;
......@@ -2007,10 +2008,12 @@ dst__entropy_getdata(void *buf, unsigned int len, isc_boolean_t pseudo) {
else
flags |= ISC_ENTROPY_BLOCKING;
#ifdef ISC_PLATFORM_CRYPTORANDOM
/* get entropy directly from crypto provider */
return (dst_random_getdata(buf, len, NULL, flags));
#else
/* get entropy from entropy source or hook function */
return (isc_entropy_getdata(dst_entropy_pool, buf, len, NULL, flags));
#endif
#endif /* ISC_PLATFORM_CRYPTORANDOM */
#endif /* PKCS11CRYPTO */
}
......
......@@ -158,8 +158,18 @@ isc_result_t
dst_random_getdata(void *data, unsigned int length,
unsigned int *returned, unsigned int flags);
/*%<
* \brief Return data from the crypto random generator.
* Specialization of isc_entropy_getdata().
* Gets random data from the random generator provided by the
* crypto library, if BIND was built with --enable-crypto-rand.
*
* See isc_entropy_getdata() for parameter usage. Normally when
* this function is available, it will be set up as a hook in the
* entropy context, so that isc_entropy_getdata() is a front-end to
* this function.
*
* Returns:
* \li ISC_R_SUCCESS on success
* \li ISC_R_NOTIMPLEMENTED if BIND is built with --disable-crypto-rand
* \li DST_R_OPENSSLFAILURE, DST_R_CRYPTOFAILURE, or other codes on error
*/
isc_boolean_t
......
......@@ -485,7 +485,8 @@ dst__openssl_getengine(const char *engine) {
isc_result_t
dst_random_getdata(void *data, unsigned int length,
unsigned int *returned, unsigned int flags) {
unsigned int *returned, unsigned int flags)
{
#ifdef ISC_PLATFORM_CRYPTORANDOM
#ifndef DONT_REQUIRE_DST_LIB_INIT
INSIST(dst__memory_pool != NULL);
......
......@@ -6,8 +6,6 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
/* $Id: entropy.h,v 1.35 2009/10/19 02:37:08 marka Exp $ */
#ifndef ISC_ENTROPY_H
#define ISC_ENTROPY_H 1
......@@ -187,9 +185,8 @@ isc_entropy_createcallbacksource(isc_entropy_t *ent,
/*!<
* \brief Create an entropy source that is polled via a callback.
*
* This would
* be used when keyboard input is used, or a GUI input method. It can
* also be used to hook in any external entropy source.
* This would be used when keyboard input is used, or a GUI input method.
* It can also be used to hook in any external entropy source.
*
* Samples are added via isc_entropy_addcallbacksample(), below.
* _addcallbacksample() is the only function which may be called from
......@@ -230,15 +227,32 @@ isc_result_t
isc_entropy_getdata(isc_entropy_t *ent, void *data, unsigned int length,
unsigned int *returned, unsigned int flags);
/*!<
* \brief Extract data from the entropy pool. This may load the pool from various
* sources.
* \brief Get random data from entropy pool 'ent'.
*
* If a hook has been set up using isc_entropy_sethook() and
* isc_entropy_usehook(), then the hook function will be called to get
* random data.
*
* Otherwise, randomness is extracted from the entropy pool set up in BIND.
* This may cause the pool to be loaded from various sources. Ths is done
* by stirring the pool and returning a part of hash as randomness.
* (Note that no secrets are given away here since parts of the hash are
* XORed together before returning.)
*
* 'flags' may contain ISC_ENTROPY_GOODONLY, ISC_ENTROPY_PARTIAL, or
* ISC_ENTROPY_BLOCKING. These will be honored if the hook function is
* not in use. If it is, the flags will be passed to the hook function
* but it may ignore them.
*
* Do this by stiring the pool and returning a part of hash as randomness.
* Note that no secrets are given away here since parts of the hash are
* xored together before returned.
* Up to 'length' bytes of randomness are retrieved and copied into 'data'.
* (If 'returned' is not NULL, and the number of bytes copied is less than
* 'length' - which may happen if ISC_ENTROPY_PARTIAL was used - then the
* number of bytes copied will be stored in *returned.)
*
* Honor the request from the caller to only return good data, any data,
* etc.
* Returns:
* \li ISC_R_SUCCESS on success
* \li ISC_R_NOENTROPY if entropy pool is empty
* \li other error codes are possible when a hook is in use
*/
void
......@@ -303,13 +317,21 @@ isc_entropy_usebestsource(isc_entropy_t *ectx, isc_entropysource_t **source,
void
isc_entropy_usehook(isc_entropy_t *ectx, isc_boolean_t onoff);
/*!<
* \brief Mark/unmark the given entropy structure as being hooked.
* \brief Configure entropy context 'ectx' to use the hook function
*
* Sets the entropy context to call the hook function for random number
* generation, if such a function has been configured via
* isc_entropy_sethook(), whenever isc_entropy_getdata() is called.
*/
void
isc_entropy_sethook(isc_entropy_getdata_t myhook);
/*!<
* \brief Set the getdata hook (e.g., for a crypto random generator).
* \brief Set the hook function.
*
* The hook function is a global value: only one hook function
* can be set in the system. Individual entropy contexts may be
* configured to use it, or not, by calling isc_entropy_usehook().
*/
ISC_LANG_ENDDECLS
......
......@@ -6,8 +6,6 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
/* $Id: random.h,v 1.20 2009/01/17 23:47:43 tbox Exp $ */
#ifndef ISC_RANDOM_H
#define ISC_RANDOM_H 1
......@@ -18,13 +16,23 @@
#include <isc/mutex.h>
/*! \file isc/random.h
* \brief Implements a random state pool which will let the caller return a
* series of possibly non-reproducible random values.
* \brief Implements pseudo random number generators.
*
* Two pseudo-random number generators are implemented, in isc_random_*
* and isc_rng_*. Neither one is very strong; they should not be used
* in cryptography functions.
*
* isc_random_* is based on arc4random if it is available on the system.
* Otherwise it is based on the posix srand() and rand() functions.
* It is useful for jittering values a bit here and there, such as
* timeouts, etc, but should not be relied upon to generate
* unpredictable sequences (for example, when choosing transaction IDs).
*
* Note that the
* strength of these numbers is not all that high, and should not be
* used in cryptography functions. It is useful for jittering values
* a bit here and there, such as timeouts, etc.
* isc_rng_* is based on ChaCha20, and is seeded and stirred from the
* system entropy source. It is stronger than isc_random_* and can
* be used for generating unpredictable sequences. It is still not as
* good as using system entropy directly (see entropy.h) and should not
* be used for cryptographic functions such as key generation.
*/
ISC_LANG_BEGINDECLS
......@@ -112,8 +120,8 @@ isc_rng_random(isc_rng_t *rngctx);
isc_uint16_t
isc_rng_uniformrandom(isc_rng_t *rngctx, isc_uint16_t upper_bound);
/*%<
* Returns a uniformly distributed pseudo random 16-bit unsigned
* integer.
* Returns a uniformly distributed pseudo-random 16-bit unsigned integer
* less than 'upper_bound'.
*/
ISC_LANG_ENDDECLS
......
......@@ -1104,7 +1104,7 @@ options_clauses[] = {
{ "pid-file", &cfg_type_qstringornone, 0 },
{ "port", &cfg_type_uint32, 0 },
{ "querylog", &cfg_type_boolean, 0 },
{ "random-device", &cfg_type_qstring, 0 },
{ "random-device", &cfg_type_qstringornone, 0 },
{ "recursing-file", &cfg_type_qstring, 0 },
{ "recursive-clients", &cfg_type_uint32, 0 },
{ "reserved-sockets", &cfg_type_uint32, 0 },
......
......@@ -1638,7 +1638,9 @@ ns_client_addopt(ns_client_t *client, dns_message_t *message,
isc_buffer_init(&buf, cookie, sizeof(cookie));