This patch adds EGD-gathering support to apr_generate_random_bytes.
At this time, you just specify the EGD socket at configure-time
FWIW, I used --with-egd=/home/jerenkrantz/.entropy and started
PRNGd with "prngd /home/jerenkrantz/.entropy" and ran the testrand
I added to apr/test/.
Ideally, I'd like to add an apr_generate_random_bytes_setup function
that takes in a path name that will configure the random device
(you'd have to know what random device is being used APR, but it'd
be useful). This will be even more useful if/when we add an internal
entropy gatherer that will need a config file. We can have
compiled-in defaults (see DEFAULT_EGD_SOCKET), but I'd like the
application be able to override these choices. -- justin
P.S. It'd be nice if apr_generate_random_bytes took in a pool...
Index: acconfig.h
===================================================================
RCS file: /home/cvs/apr/acconfig.h,v
retrieving revision 1.53
diff -u -r1.53 acconfig.h
--- acconfig.h 29 Nov 2001 00:34:27 -0000 1.53
+++ acconfig.h 5 Jan 2002 00:42:32 -0000
@@ -10,6 +10,8 @@
#undef HAVE_CODESET
#undef HAVE_PTHREAD_PROCESS_SHARED
#undef DEV_RANDOM
+#undef HAVE_EGD
+#undef EGD_DEFAULT_SOCKET
#undef HAVE_TRUERAND
#undef HAVE_POLLIN
#undef HAVE_isascii
Index: configure.in
===================================================================
RCS file: /home/cvs/apr/configure.in,v
retrieving revision 1.392
diff -u -r1.392 configure.in
--- configure.in 2 Jan 2002 09:12:37 -0000 1.392
+++ configure.in 5 Jan 2002 00:42:32 -0000
@@ -1186,19 +1188,32 @@
AC_MSG_RESULT(/dev/urandom)
rand="1"
else
- AC_MSG_RESULT(not found);
-
case $host in
# we have built in support for OS/2
*-os2*)
+ AC_MSG_RESULT([Using OS/2 builtin random])
rand="1"
;;
- # no other choice, try for truerand
*)
- if test "$ac_cv_lib_truerand_main" = "yes"; then
+ AC_ARG_WITH(egd,
+ [ --with-egd=<path> use egd-compatible socket],
+ [ if test "$withval" = "yes"; then
+ AC_ERROR([You must specify a default EGD socket path.])
+ fi
+ AC_DEFINE(HAVE_EGD)
+ AC_DEFINE_UNQUOTED(EGD_DEFAULT_SOCKET, [$withval])
+ AC_MSG_RESULT(EGD-compatible daemon)
rand="1"
- else
+ ])
+ if test "$rand" != "1"; then
+ if test "$ac_cv_lib_truerand_main" = "yes"; then
+ AC_DEFINE(HAVE_TRUERAND)
+ AC_MSG_RESULT(truerand)
+ rand="1"
+ else
+ AC_MSG_RESULT(not found)
rand="0"
+ fi
fi
;;
esac
Index: misc/unix/rand.c
===================================================================
RCS file: /home/cvs/apr/misc/unix/rand.c,v
retrieving revision 1.7
diff -u -r1.7 rand.c
--- misc/unix/rand.c 10 Aug 2001 21:04:47 -0000 1.7
+++ misc/unix/rand.c 5 Jan 2002 00:42:33 -0000
@@ -62,13 +62,14 @@
#if APR_HAS_RANDOM
+/* This tells the preprocessor to put quotes around the value. */
#define XSTR(x) #x
#define STR(x) XSTR(x)
APR_DECLARE(apr_status_t) apr_generate_random_bytes(unsigned char *buf,
int length)
{
-#ifdef DEV_RANDOM
+#ifdef DEV_RANDOM
int rnd;
size_t got, tot;
@@ -89,7 +90,79 @@
for (idx=0; idx<length; idx++)
buf[idx] = randbyte();
-#else /* use truerand */
+#elif defined(HAVE_EGD)
+ /* use EGD-compatible socket daemon (such as EGD or PRNGd).
+ * message format:
+ * 0x00 (get entropy level)
+ * 0xMM (msb) 0xmm 0xll 0xLL (lsb)
+ * 0x01 (read entropy nonblocking) 0xNN (bytes requested)
+ * 0xMM (bytes granted) MM bytes
+ * 0x02 (read entropy blocking) 0xNN (bytes desired)
+ * [block] NN bytes
+ * 0x03 (write entropy) 0xMM 0xLL (bits of entropy) 0xNN (bytes of data)
+ * NN bytes
+ * (no response - write only)
+ * 0x04 (report PID)
+ * 0xMM (length of PID string, not null-terminated) MM chars
+ */
+ apr_status_t rv;
+ apr_socket_t *egd_socket;
+ apr_sockaddr_t *egd_sockaddr;
+ apr_pool_t *pool;
+ apr_size_t req_expected, resp_expected;
+ unsigned char req[2], resp[255];
+ char *curbuf = buf;
+
+ apr_pool_create(&pool, NULL);
+ apr_socket_create(&egd_socket, APR_UNIX, SOCK_STREAM, pool);
+
+ apr_socket_addr_get(&egd_sockaddr, APR_LOCAL, egd_socket);
+
+ /* We need to be able to set this via APR. */
+ memcpy(egd_sockaddr->sa.sunix.sun_path, STR(EGD_DEFAULT_SOCKET),
+ strlen(STR(EGD_DEFAULT_SOCKET)));
+
+ rv = apr_connect(egd_socket, egd_sockaddr);
+ if (rv != APR_SUCCESS) {
+ apr_pool_destroy(pool);
+ return rv;
+ }
+
+ /* EGD can only take 255 bytes (2 bytes) of data. Silly. */
+ while (length > 0) {
+ req[0] = 2; /* We'll block for now. */
+ req[1] = length > 255 ? 255: length;
+
+ req_expected = 2;
+ rv = apr_send(egd_socket, req, &req_expected);
+ if (rv != APR_SUCCESS) {
+ apr_shutdown(egd_socket, APR_SHUTDOWN_READWRITE);
+ apr_pool_destroy(pool);
+ return rv;
+ }
+
+ if (req_expected != 2) {
+ apr_shutdown(egd_socket, APR_SHUTDOWN_READWRITE);
+ apr_pool_destroy(pool);
+ return APR_EGENERAL; /* Try again. */
+ }
+
+ resp_expected = req[1];
+ rv = apr_recv(egd_socket, resp, &resp_expected);
+ if (rv != APR_SUCCESS) {
+ apr_shutdown(egd_socket, APR_SHUTDOWN_READWRITE);
+ apr_pool_destroy(pool);
+ return rv;
+ }
+ memcpy(curbuf, resp, resp_expected);
+ curbuf += resp_expected;
+ length -= resp_expected;
+ }
+
+ apr_shutdown(egd_socket, APR_SHUTDOWN_READWRITE);
+ apr_pool_destroy(pool);
+
+#elif defined(HAVE_TRUERAND) /* use truerand */
extern int randbyte(void); /* from the truerand library */
unsigned int idx;