mirror of
https://gitlab.isc.org/isc-projects/bind9
synced 2025-08-30 14:07:59 +00:00
add blocking mode, and add a flag to indicate the input is a device
This commit is contained in:
@@ -26,14 +26,16 @@ static void
|
|||||||
hex_dump(char *msg, void *data, unsigned int length) {
|
hex_dump(char *msg, void *data, unsigned int length) {
|
||||||
unsigned int len;
|
unsigned int len;
|
||||||
unsigned char *base;
|
unsigned char *base;
|
||||||
|
isc_boolean_t first = ISC_TRUE;
|
||||||
|
|
||||||
base = data;
|
base = data;
|
||||||
|
|
||||||
printf("DUMP of %d bytes: %s\n", length, msg);
|
printf("DUMP of %d bytes: %s\n\t", length, msg);
|
||||||
for (len = 0 ; len < length ; len++) {
|
for (len = 0 ; len < length ; len++) {
|
||||||
if (len % 16 == 0)
|
if (len % 16 == 0 && !first)
|
||||||
printf("\n");
|
printf("\n\t");
|
||||||
printf("%02x ", base[len]);
|
printf("%02x ", base[len]);
|
||||||
|
first = ISC_FALSE;
|
||||||
}
|
}
|
||||||
printf("\n");
|
printf("\n");
|
||||||
}
|
}
|
||||||
@@ -69,10 +71,20 @@ main(int argc, char **argv) {
|
|||||||
|
|
||||||
isc_entropy_stats(ent, stderr);
|
isc_entropy_stats(ent, stderr);
|
||||||
|
|
||||||
|
#if 1
|
||||||
devrandom = NULL;
|
devrandom = NULL;
|
||||||
|
flags = 0;
|
||||||
|
flags |= ISC_ENTROPYSOURCE_ISDEVICE;
|
||||||
CHECK("isc_entropy_createfilesource()",
|
CHECK("isc_entropy_createfilesource()",
|
||||||
isc_entropy_createfilesource(ent, "/dev/random",
|
isc_entropy_createfilesource(ent, "/dev/random",
|
||||||
0, &devrandom));
|
flags, &devrandom));
|
||||||
|
#else
|
||||||
|
devrandom = NULL;
|
||||||
|
flags = 0;
|
||||||
|
CHECK("isc_entropy_createfilesource()",
|
||||||
|
isc_entropy_createfilesource(ent, "/tmp/foo",
|
||||||
|
flags, &devrandom));
|
||||||
|
#endif
|
||||||
|
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"Reading 32 bytes of GOOD random data only, partial OK\n");
|
"Reading 32 bytes of GOOD random data only, partial OK\n");
|
||||||
@@ -83,18 +95,25 @@ main(int argc, char **argv) {
|
|||||||
result = isc_entropy_getdata(ent, buffer, 32, &returned, flags);
|
result = isc_entropy_getdata(ent, buffer, 32, &returned, flags);
|
||||||
if (result == ISC_R_NOENTROPY) {
|
if (result == ISC_R_NOENTROPY) {
|
||||||
fprintf(stderr, "No entropy.\n");
|
fprintf(stderr, "No entropy.\n");
|
||||||
goto out;
|
goto any;
|
||||||
}
|
}
|
||||||
hex_dump("good data only:", buffer, returned);
|
hex_dump("good data only:", buffer, returned);
|
||||||
|
|
||||||
|
any:
|
||||||
isc_entropy_stats(ent, stderr);
|
isc_entropy_stats(ent, stderr);
|
||||||
|
|
||||||
CHECK("isc_entropy_getdata()",
|
CHECK("isc_entropy_getdata()",
|
||||||
isc_entropy_getdata(ent, buffer, 128, NULL, 0));
|
isc_entropy_getdata(ent, buffer, 128, NULL, 0));
|
||||||
|
hex_dump("pseudorandom data", buffer, 128);
|
||||||
|
|
||||||
hex_dump("entropy data", buffer, 128);
|
isc_entropy_stats(ent, stderr);
|
||||||
|
flags = 0;
|
||||||
|
flags |= ISC_ENTROPY_GOODONLY;
|
||||||
|
flags |= ISC_ENTROPY_BLOCKING;
|
||||||
|
result = isc_entropy_getdata(ent, buffer, sizeof buffer, &returned,
|
||||||
|
flags);
|
||||||
|
CHECK("good data only, blocking mode", result);
|
||||||
|
hex_dump("blocking mode data", buffer, sizeof buffer);
|
||||||
|
|
||||||
out:
|
|
||||||
{
|
{
|
||||||
isc_entropy_t *entcopy1 = NULL;
|
isc_entropy_t *entcopy1 = NULL;
|
||||||
isc_entropy_t *entcopy2 = NULL;
|
isc_entropy_t *entcopy2 = NULL;
|
||||||
|
@@ -96,15 +96,15 @@ ISC_LANG_BEGINDECLS
|
|||||||
* Estimate the amount of entropy contained in the sample pool.
|
* Estimate the amount of entropy contained in the sample pool.
|
||||||
* If this is not set, the source will be gathered and perodically
|
* If this is not set, the source will be gathered and perodically
|
||||||
* mixed into the entropy pool, but no increment in contained entropy
|
* mixed into the entropy pool, but no increment in contained entropy
|
||||||
* will be assumed.
|
* will be assumed. This flag only makes sense on sample sources.
|
||||||
*
|
*
|
||||||
* _POLLABLE
|
* _ISDEVICE
|
||||||
* The entropy source is pollable for more data. This is most useful
|
* The file named is really a device file, and blocking is possible.
|
||||||
* for things like files and devices. It should not be used for
|
* Otherwise, the file is assumed to be a finite length file, and
|
||||||
* tty/keyboard data, device timings, etc.
|
* any I/O error (including blocking) terminates the source.
|
||||||
*/
|
*/
|
||||||
#define ISC_ENTROPYSOURCE_ESTIMATE 0x00000001U
|
#define ISC_ENTROPYSOURCE_ESTIMATE 0x00000001U
|
||||||
#define ISC_ENTROPYSOURCE_POLLABLE 0x00000002U
|
#define ISC_ENTROPYSOURCE_ISDEVICE 0x00000002U
|
||||||
|
|
||||||
/***
|
/***
|
||||||
*** Functions
|
*** Functions
|
||||||
|
@@ -52,8 +52,8 @@
|
|||||||
/*
|
/*
|
||||||
* size of entropy pool in 32-bit words. This _MUST_ be a power of 2.
|
* size of entropy pool in 32-bit words. This _MUST_ be a power of 2.
|
||||||
*/
|
*/
|
||||||
#define RND_POOLWORDS 128
|
#define RND_POOLWORDS 512
|
||||||
#define RND_POOLBITS (RND_POOLWORDS * 32)
|
#define RND_POOLBITS (RND_POOLWORDS * 32)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Number of bytes returned per hash. This must be true:
|
* Number of bytes returned per hash. This must be true:
|
||||||
@@ -130,6 +130,9 @@ entropypool_add_word(isc_entropypool_t *, isc_uint32_t);
|
|||||||
static void
|
static void
|
||||||
fillpool(isc_entropy_t *, unsigned int, isc_boolean_t);
|
fillpool(isc_entropy_t *, unsigned int, isc_boolean_t);
|
||||||
|
|
||||||
|
static int
|
||||||
|
wait_for_sources(isc_entropy_t *);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Add in entropy, even when the value we're adding in could be
|
* Add in entropy, even when the value we're adding in could be
|
||||||
* very large.
|
* very large.
|
||||||
@@ -275,10 +278,13 @@ get_from_filesource(isc_entropysource_t *source, isc_uint32_t desired) {
|
|||||||
int fd = source->sources.file.fd;
|
int fd = source->sources.file.fd;
|
||||||
ssize_t n, ndesired;
|
ssize_t n, ndesired;
|
||||||
isc_uint32_t added;
|
isc_uint32_t added;
|
||||||
|
isc_boolean_t isdevice;
|
||||||
|
|
||||||
if (fd == -1)
|
if (fd == -1)
|
||||||
return (0);
|
return (0);
|
||||||
|
|
||||||
|
isdevice = ISC_TF((source->flags & ISC_ENTROPYSOURCE_ISDEVICE) != 0);
|
||||||
|
|
||||||
desired = desired / 8 + (((desired & 0x07) > 0) ? 1 : 0);
|
desired = desired / 8 + (((desired & 0x07) > 0) ? 1 : 0);
|
||||||
|
|
||||||
added = 0;
|
added = 0;
|
||||||
@@ -286,13 +292,17 @@ get_from_filesource(isc_entropysource_t *source, isc_uint32_t desired) {
|
|||||||
ndesired = ISC_MIN(desired, sizeof(buf));
|
ndesired = ISC_MIN(desired, sizeof(buf));
|
||||||
n = read(fd, buf, ndesired);
|
n = read(fd, buf, ndesired);
|
||||||
if (n < 0) {
|
if (n < 0) {
|
||||||
if (errno == EAGAIN)
|
if (isdevice && (errno == EAGAIN))
|
||||||
goto out;
|
goto out;
|
||||||
close(fd);
|
close(fd);
|
||||||
source->sources.file.fd = -1;
|
source->sources.file.fd = -1;
|
||||||
}
|
|
||||||
if (n == 0)
|
|
||||||
goto out;
|
goto out;
|
||||||
|
}
|
||||||
|
if (n == 0) {
|
||||||
|
close(fd);
|
||||||
|
source->sources.file.fd = -1;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
entropypool_adddata(ent, buf, n, n * 8);
|
entropypool_adddata(ent, buf, n, n * 8);
|
||||||
added += n * 8;
|
added += n * 8;
|
||||||
@@ -329,6 +339,10 @@ fillpool(isc_entropy_t *ent, unsigned int needed, isc_boolean_t blocking) {
|
|||||||
* Next, if we are asked to add a specific bit of entropy, make
|
* Next, if we are asked to add a specific bit of entropy, make
|
||||||
* certain that we will do so. Clamp how much we try to add to
|
* certain that we will do so. Clamp how much we try to add to
|
||||||
* (DIGEST_SIZE * 8 < needed < POOLBITS - entropy).
|
* (DIGEST_SIZE * 8 < needed < POOLBITS - entropy).
|
||||||
|
*
|
||||||
|
* Note that if we are in a blocking mode, we will only try to
|
||||||
|
* get as much data as we need, not as much as we might want
|
||||||
|
* to build up.
|
||||||
*/
|
*/
|
||||||
if (needed == 0) {
|
if (needed == 0) {
|
||||||
isc_uint32_t needed_ent, needed_ps;
|
isc_uint32_t needed_ent, needed_ps;
|
||||||
@@ -350,6 +364,11 @@ fillpool(isc_entropy_t *ent, unsigned int needed, isc_boolean_t blocking) {
|
|||||||
needed = ISC_MIN(needed, RND_POOLBITS);
|
needed = ISC_MIN(needed, RND_POOLBITS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* In any case, clamp how much we need to how much we can add.
|
||||||
|
*/
|
||||||
|
needed = ISC_MIN(needed, RND_POOLBITS - ent->pool.entropy);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Poll each file source to see if we can read anything useful from
|
* Poll each file source to see if we can read anything useful from
|
||||||
* it. XXXMLG When where are multiple sources, we should keep a
|
* it. XXXMLG When where are multiple sources, we should keep a
|
||||||
@@ -358,25 +377,67 @@ fillpool(isc_entropy_t *ent, unsigned int needed, isc_boolean_t blocking) {
|
|||||||
* others are always drained.
|
* others are always drained.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
again:
|
||||||
source = ISC_LIST_HEAD(ent->sources);
|
source = ISC_LIST_HEAD(ent->sources);
|
||||||
added = 0;
|
added = 0;
|
||||||
while (source != NULL) {
|
while (source != NULL && needed > 0) {
|
||||||
desired = ISC_MIN(needed, RND_POOLBITS - ent->pool.entropy);
|
|
||||||
if (source->type == ENTROPY_SOURCETYPE_FILE)
|
if (source->type == ENTROPY_SOURCETYPE_FILE)
|
||||||
added += get_from_filesource(source, desired);
|
added += get_from_filesource(source, needed);
|
||||||
|
|
||||||
if (added > needed)
|
if (added >= needed)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
if (needed > added)
|
||||||
|
needed -= added;
|
||||||
|
else
|
||||||
|
needed = 0;
|
||||||
|
|
||||||
source = ISC_LIST_NEXT(source, link);
|
source = ISC_LIST_NEXT(source, link);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (blocking && added < needed) {
|
||||||
|
if (wait_for_sources(ent) > 0)
|
||||||
|
goto again;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Adjust counts.
|
* Adjust counts.
|
||||||
*/
|
*/
|
||||||
subtract_pseudo(ent, added);
|
subtract_pseudo(ent, added);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
wait_for_sources(isc_entropy_t *ent) {
|
||||||
|
isc_entropysource_t *source;
|
||||||
|
int maxfd, fd;
|
||||||
|
int cc;
|
||||||
|
fd_set reads;
|
||||||
|
|
||||||
|
maxfd = -1;
|
||||||
|
FD_ZERO(&reads);
|
||||||
|
|
||||||
|
source = ISC_LIST_HEAD(ent->sources);
|
||||||
|
while (source != NULL) {
|
||||||
|
if (source->type == ENTROPY_SOURCETYPE_FILE) {
|
||||||
|
fd = source->sources.file.fd;
|
||||||
|
if (fd >= 0) {
|
||||||
|
maxfd = ISC_MAX(maxfd, fd);
|
||||||
|
FD_SET(fd, &reads);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
source = ISC_LIST_NEXT(source, link);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (maxfd < 0)
|
||||||
|
return (-1);
|
||||||
|
|
||||||
|
cc = select(maxfd + 1, &reads, NULL, NULL, NULL);
|
||||||
|
if (cc < 0)
|
||||||
|
return (-1);
|
||||||
|
|
||||||
|
return (cc);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Extract some number of bytes from the random pool, decreasing the
|
* Extract some number of bytes from the random pool, decreasing the
|
||||||
* estimate of randomness as each byte is extracted.
|
* estimate of randomness as each byte is extracted.
|
||||||
@@ -444,11 +505,16 @@ isc_entropy_getdata(isc_entropy_t *ent, void *data, unsigned int length,
|
|||||||
* are not ok.
|
* are not ok.
|
||||||
*/
|
*/
|
||||||
if (goodonly) {
|
if (goodonly) {
|
||||||
fillpool(ent, (length - remain) * 8, blocking);
|
fillpool(ent, remain * 8, blocking);
|
||||||
if (!partial && !blocking
|
if (!blocking && !partial
|
||||||
&& ((ent->pool.entropy < count * 8)
|
&& ((ent->pool.entropy < count * 8)
|
||||||
|| (ent->pool.entropy < RND_ENTROPY_THRESHOLD * 8)))
|
|| (ent->pool.entropy
|
||||||
|
< RND_ENTROPY_THRESHOLD * 8)))
|
||||||
goto zeroize;
|
goto zeroize;
|
||||||
|
if (blocking
|
||||||
|
&& (ent->pool.entropy
|
||||||
|
<= RND_ENTROPY_THRESHOLD * 8))
|
||||||
|
goto zeroize;
|
||||||
} else {
|
} else {
|
||||||
/*
|
/*
|
||||||
* If we've extracted half our pool size in bits
|
* If we've extracted half our pool size in bits
|
||||||
@@ -477,10 +543,9 @@ isc_entropy_getdata(isc_entropy_t *ent, void *data, unsigned int length,
|
|||||||
deltae = ISC_MIN(deltae, ent->pool.entropy);
|
deltae = ISC_MIN(deltae, ent->pool.entropy);
|
||||||
total += deltae;
|
total += deltae;
|
||||||
subtract_entropy(ent, deltae);
|
subtract_entropy(ent, deltae);
|
||||||
|
add_pseudo(ent, count * 8);
|
||||||
}
|
}
|
||||||
|
|
||||||
add_pseudo(ent, total);
|
|
||||||
|
|
||||||
memset(digest, 0, sizeof(digest));
|
memset(digest, 0, sizeof(digest));
|
||||||
|
|
||||||
if (returned != NULL)
|
if (returned != NULL)
|
||||||
|
Reference in New Issue
Block a user