entropy.c revision 0c27b3fe77ac1d5094ba3521e8142d9e7973133f
beff4152e9f0fe90885458d1a1733b183a2a8816Christian Maeder * Copyright (C) 2000-2008, 2012, 2016 Internet Systems Consortium, Inc. ("ISC")
e6d40133bc9f858308654afb1262b8b483ec5922Till Mossakowski * This Source Code Form is subject to the terms of the Mozilla Public
2725abe920f91de62ae5c0b7230c1627cccf5fabChristian Maeder * License, v. 2.0. If a copy of the MPL was not distributed with this
98890889ffb2e8f6f722b00e265a211f13b5a861Corneliu-Claudiu Prodescu * file, You can obtain one at http://mozilla.org/MPL/2.0/.
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder/* $Id: entropy.c,v 1.82 2008/12/01 23:47:45 tbox Exp $ */
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder * This is the system dependent part of the ISC entropy API.
109a53dbf4c9233f869f63ba7a7f3fece49973c3Christian Maeder#include <sys/param.h> /* Openserver 5.0.6A and FD_SETSIZE */
109a53dbf4c9233f869f63ba7a7f3fece49973c3Christian Maeder * There is only one variable in the entropy data structures that is not
109a53dbf4c9233f869f63ba7a7f3fece49973c3Christian Maeder * system independent, but pulling the structure that uses it into this file
109a53dbf4c9233f869f63ba7a7f3fece49973c3Christian Maeder * ultimately means pulling several other independent structures here also to
109a53dbf4c9233f869f63ba7a7f3fece49973c3Christian Maeder * resolve their interdependencies. Thus only the problem variable's type
109a53dbf4c9233f869f63ba7a7f3fece49973c3Christian Maeder * is defined here.
a461314c811f4187dff85c8be079a41b2f13f176Christian Maedertypedef struct {
9d6562465b41f17c7967d4e5678f34811d958cb2Christian Maederstatic unsigned int
b53688bfed888214b485cf76439d57262d80e0a7Christian Maederget_from_filesource(isc_entropysource_t *source, isc_uint32_t desired) {
38c817b94e0a5b1ae94178b1075c187e07bcc5e1Christian Maeder desired = desired / 8 + (((desired & 0x07) > 0) ? 1 : 0);
b53688bfed888214b485cf76439d57262d80e0a7Christian Maederstatic unsigned int
b53688bfed888214b485cf76439d57262d80e0a7Christian Maederget_from_usocketsource(isc_entropysource_t *source, isc_uint32_t desired) {
fefee7e1dee1ee5f0768a03a4abae88d1ca2c3fdRazvan Pascanu unsigned int added;
b324cda6178c49ddeead3ce62b832ccf644cbcabRazvan Pascanu size_t sz_to_recv = source->sources.usocket.sz_to_recv;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder desired = desired / 8 + (((desired & 0x07) > 0) ? 1 : 0);
d4ebd9e5adc974cfa2bdf4bdd155e07be0e26f75Christian Maeder switch ( source->sources.usocket.status ) {
8865728716566f42fa73e7e0bc080ba3225df764Christian Maeder if ((n = sendto(fd, buf, 1, 0, NULL, 0)) < 0) {
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder if (errno == EWOULDBLOCK || errno == EINTR ||
b76d27eba526ecac2a20400fa505ec5c642ae7d2Dominik Luecke if ((n = sendto(fd, buf, 2, 0, NULL, 0)) < 0) {
b76d27eba526ecac2a20400fa505ec5c642ae7d2Dominik Luecke if (errno == EWOULDBLOCK || errno == EINTR ||
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder if (n == 1) {
a3a7d8b3cdf05c8040c62dbcf9a15dc5042cd721Christian Maeder /*FALLTHROUGH*/
0b13f102310e03a20b38c870b5acb88712f316a4Christian Maeder if (recvfrom(fd, buf, 1, 0, NULL, NULL) != 1) {
a3a7d8b3cdf05c8040c62dbcf9a15dc5042cd721Christian Maeder * The problem of EAGAIN (try again
00df6fd583c19393fa141d5a0e21ac74c7bf5b19Christian Maeder * later) is a major issue on HP-UX.
a3a7d8b3cdf05c8040c62dbcf9a15dc5042cd721Christian Maeder * Solaris actually tries the recvfrom
cb2044812811d66efe038d914966e04290be93faChristian Maeder * call again, while HP-UX just dies.
a3a7d8b3cdf05c8040c62dbcf9a15dc5042cd721Christian Maeder * This code is an attempt to let the
96ae1a1d2197d0e0d5b80da2474b64c456feb1b0Christian Maeder * entropy pool fill back up (at least
a3a7d8b3cdf05c8040c62dbcf9a15dc5042cd721Christian Maeder * that's what I think the problem is.)
a3a7d8b3cdf05c8040c62dbcf9a15dc5042cd721Christian Maeder * We go to eagain_loop because if we
8d780c893d6df5dab3dcc7d8444b7517f6547f11Christian Maeder * just "break", then the "desired"
a3a7d8b3cdf05c8040c62dbcf9a15dc5042cd721Christian Maeder * amount gets borked.
bbba6dd86153aacb0f662b182b128df0eb09fd54Christian Maeder if (errno == EWOULDBLOCK || errno == EINTR)
d4ebd9e5adc974cfa2bdf4bdd155e07be0e26f75Christian Maeder source->sources.usocket.sz_to_recv = sz_to_recv;
b6ff72be73dad3d1394cf2c71e29e67624ff030bChristian Maeder /*FALLTHROUGH*/
d4ebd9e5adc974cfa2bdf4bdd155e07be0e26f75Christian Maeder source->sources.usocket.status = isc_usocketsource_disconnected;
0b13f102310e03a20b38c870b5acb88712f316a4Christian Maeder * Poll each source, trying to get data from it to stuff into the entropy
dff1de7ad15d1582e25d636c3724dd202874897fChristian Maederfillpool(isc_entropy_t *ent, unsigned int desired, isc_boolean_t blocking) {
a3a7d8b3cdf05c8040c62dbcf9a15dc5042cd721Christian Maeder * This logic is a little strange, so an explanation is in order.
96ae1a1d2197d0e0d5b80da2474b64c456feb1b0Christian Maeder * If needed is 0, it means we are being asked to "fill to whatever
8c8545dd3bf34fbcbc16904b65d249658f8f9efcChristian Maeder * we think is best." This means that if we have at least a
33fcc19ef2b59493b4e91eebf701df95fd230765Christian Maeder * partially full pool (say, > 1/4th of the pool) we probably don't
d4ebd9e5adc974cfa2bdf4bdd155e07be0e26f75Christian Maeder * need to add anything.
0b13f102310e03a20b38c870b5acb88712f316a4Christian Maeder * Also, we will check to see if the "pseudo" count is too high.
0b13f102310e03a20b38c870b5acb88712f316a4Christian Maeder * If it is, try to mix in better data. Too high is currently
0b13f102310e03a20b38c870b5acb88712f316a4Christian Maeder * defined as 1/4th of the pool.
a3a7d8b3cdf05c8040c62dbcf9a15dc5042cd721Christian Maeder * Next, if we are asked to add a specific bit of entropy, make
8bb80c9684e905de8dcfcfb1291542677e7d77b6Christian Maeder * certain that we will do so. Clamp how much we try to add to
a3a7d8b3cdf05c8040c62dbcf9a15dc5042cd721Christian Maeder * (DIGEST_SIZE * 8 < needed < POOLBITS - entropy).
966519955f5f7111abac20118563132b9dd41165Christian Maeder * Note that if we are in a blocking mode, we will only try to
dff1de7ad15d1582e25d636c3724dd202874897fChristian Maeder * get as much data as we need, not as much as we might want
8bb80c9684e905de8dcfcfb1291542677e7d77b6Christian Maeder * to build up.
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder if ((ent->pool.entropy >= RND_POOLBITS / 4)
966519955f5f7111abac20118563132b9dd41165Christian Maeder * In any case, clamp how much we need to how much we can add.
a3a7d8b3cdf05c8040c62dbcf9a15dc5042cd721Christian Maeder needed = ISC_MIN(needed, RND_POOLBITS - ent->pool.entropy);
dff1de7ad15d1582e25d636c3724dd202874897fChristian Maeder * But wait! If we're not yet initialized, we need at least
a3a7d8b3cdf05c8040c62dbcf9a15dc5042cd721Christian Maeder * THRESHOLD_BITS
cb2044812811d66efe038d914966e04290be93faChristian Maeder * of randomness.
a3a7d8b3cdf05c8040c62dbcf9a15dc5042cd721Christian Maeder needed = ISC_MAX(needed, THRESHOLD_BITS - ent->initialized);
a3a7d8b3cdf05c8040c62dbcf9a15dc5042cd721Christian Maeder * Poll each file source to see if we can read anything useful from
a3a7d8b3cdf05c8040c62dbcf9a15dc5042cd721Christian Maeder * it. XXXMLG When where are multiple sources, we should keep a
00df6fd583c19393fa141d5a0e21ac74c7bf5b19Christian Maeder * record of which one we last used so we can start from it (or the
a3a7d8b3cdf05c8040c62dbcf9a15dc5042cd721Christian Maeder * next one) to avoid letting some sources build up entropy while
a3a7d8b3cdf05c8040c62dbcf9a15dc5042cd721Christian Maeder * others are always drained.
33fcc19ef2b59493b4e91eebf701df95fd230765Christian Maeder ent->nextsource = ISC_LIST_HEAD(ent->sources);
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder for (nsource = 0; nsource < ent->nsources; nsource++) {
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder unsigned int got;
2360728d4185c0c04279c999941c64d36626af79Christian Maeder got = get_from_filesource(source, remaining);
2360728d4185c0c04279c999941c64d36626af79Christian Maeder got = get_from_usocketsource(source, remaining);
2360728d4185c0c04279c999941c64d36626af79Christian Maeder * Here, if there are bits remaining to be had and we can block,
2360728d4185c0c04279c999941c64d36626af79Christian Maeder * check to see if we have a callback source. If so, call them.
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder while ((remaining != 0) && (source != NULL)) {
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder unsigned int got;
dff1de7ad15d1582e25d636c3724dd202874897fChristian Maeder if (source->type == ENTROPY_SOURCETYPE_CALLBACK)
a3a7d8b3cdf05c8040c62dbcf9a15dc5042cd721Christian Maeder got = get_from_callback(source, remaining, blocking);
a3a7d8b3cdf05c8040c62dbcf9a15dc5042cd721Christian Maeder * Mark as initialized if we've added enough data.
b47b1ea8a412f6e4c731779f6a572384e7cf06d8Christian Maeder if (source->type == ENTROPY_SOURCETYPE_FILE) {
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder if (source->type == ENTROPY_SOURCETYPE_USOCKET) {
a68ff26ddb1d300f7e16097edef615f130fcd5ceChristian Maeder cc = select(maxfd + 1, &reads, &writes, NULL, NULL);
beff4152e9f0fe90885458d1a1733b183a2a8816Christian Maederdestroyfilesource(isc_entropyfilesource_t *source) {
b53688bfed888214b485cf76439d57262d80e0a7Christian Maederdestroyusocketsource(isc_entropyusocketsource_t *source) {
12324a24aa5aa42edc749c7473fcf5264d4a81e4Christian Maeder * Make a fd non-blocking
8a5c05062ef501bf725a86a370a5145a198e81fdKlaus Luettich isc__strerror(errno, strbuf, sizeof(strbuf));
a3a7d8b3cdf05c8040c62dbcf9a15dc5042cd721Christian Maederisc_entropy_createfilesource(isc_entropy_t *ent, const char *fname) {
df86c42574168135e8e2af9cf468fae774874cd0Christian Maeder * Solaris 2.5.1 does not have support for sockets (S_IFSOCK),
3ec3a22fe2b9c38a3575c98a82b4e3f988af64a6Eugen Kuksa * but it does return type S_IFIFO (the OS believes that
4c872eeb600fe8479dbda395405cf13c3d573c24Soeren D. Schulze * the socket is a fifo). This may be an issue if we tell
a3a7d8b3cdf05c8040c62dbcf9a15dc5042cd721Christian Maeder * the program to look at an actual FIFO as its source of
3490b73f69b58ab742417b0867d0e2d4a7778cc0Christian Maeder fd = open(fname, O_RDONLY | PORT_NONBLOCK, 0);
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder strlcpy(sname.sun_path, fname, sizeof(sname.sun_path));
beff4152e9f0fe90885458d1a1733b183a2a8816Christian Maeder (sizeof(*(su)) - sizeof((su)->sun_path) + strlen((su)->sun_path))
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder if (connect(fd, (struct sockaddr *) &sname,
b6ff72be73dad3d1394cf2c71e29e67624ff030bChristian Maeder sizeof(struct sockaddr_un)) < 0) {
511284753313165e629cedf508752d6818ccc4d2Christian Maeder source = isc_mem_get(ent->mctx, sizeof(isc_entropysource_t));
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder * From here down, no failures can occur.
a3a7d8b3cdf05c8040c62dbcf9a15dc5042cd721Christian Maeder memset(source->name, 0, sizeof(source->name));
91ba5d95b2472cb075646b6120a559dc6581a867Christian Maeder * Hook it into the entropy system.