summaryrefslogtreecommitdiff
path: root/cipher
diff options
context:
space:
mode:
authorMoritz Schulte <mo@g10code.com>2006-04-22 16:09:23 +0000
committerMoritz Schulte <mo@g10code.com>2006-04-22 16:09:23 +0000
commit9771a836746cc94699b4eaee6c68ba07caee3472 (patch)
treee0cb694d3d1799ad1d796ed76c83b284538e3b52 /cipher
parenteaee2dd54a87f0adad6f47244cbf56aa0b04cd23 (diff)
downloadlibgcrypt-9771a836746cc94699b4eaee6c68ba07caee3472.tar.gz
cipher/ChangeLog:
2006-04-22 Moritz Schulte <moritz@g10code.com> * random-daemon.c (_gcry_daemon_initialize_basics): New argument: SOCKETNAME. Passing on to connect_to_socket() if non-NULL. (connect_to_socket, writen, readn, call_daemon): New functions. (_gcry_daemon_randomize, _gcry_daemon_get_random_bytes) (_gcry_daemon_create_nonce): Call call_daemon(). (RANDOM_DAEMON_SOCKET): New symbol. (daemon_socket): New static variable. * random.h (_gcry_daemon_initialize_basics): New parameter: SOCKETNAME. (_gcry_set_random_daemon_socket): New declaration. * random.c (initialize_basics): Pass DAEMON_SOCKET_NAME to _gcry_daemon_initialize_basics. (_gcry_set_random_daemon_socket): New function, setting DAEMON_SOCKET_NAME. src/ChangeLog: 2006-04-22 Moritz Schulte <moritz@g10code.com> * gcrypt.h (enum gcry_ctl_cmds): New commands: GCRYCTL_SET_RANDOM_DAEMON_SOCKET, GCRYCTL_USE_RANDOM_DAEMON. * global.c (gcry_control): Handle new commands, calling _gcry_set_random_daemon_socket() and _gcry_use_random_daemon().
Diffstat (limited to 'cipher')
-rw-r--r--cipher/ChangeLog19
-rw-r--r--cipher/random-daemon.c267
-rw-r--r--cipher/random.c15
-rw-r--r--cipher/random.h5
4 files changed, 297 insertions, 9 deletions
diff --git a/cipher/ChangeLog b/cipher/ChangeLog
index 1588e94e..70f1cf8b 100644
--- a/cipher/ChangeLog
+++ b/cipher/ChangeLog
@@ -1,3 +1,22 @@
+2006-04-22 Moritz Schulte <moritz@g10code.com>
+
+ * random-daemon.c (_gcry_daemon_initialize_basics): New argument:
+ SOCKETNAME. Passing on to connect_to_socket() if non-NULL.
+ (connect_to_socket, writen, readn, call_daemon): New functions.
+ (_gcry_daemon_randomize, _gcry_daemon_get_random_bytes)
+ (_gcry_daemon_create_nonce): Call call_daemon().
+ (RANDOM_DAEMON_SOCKET): New symbol.
+ (daemon_socket): New static variable.
+
+ * random.h (_gcry_daemon_initialize_basics): New parameter:
+ SOCKETNAME.
+ (_gcry_set_random_daemon_socket): New declaration.
+
+ * random.c (initialize_basics): Pass DAEMON_SOCKET_NAME to
+ _gcry_daemon_initialize_basics.
+ (_gcry_set_random_daemon_socket): New function, setting
+ DAEMON_SOCKET_NAME.
+
2006-04-01 Moritz Schulte <moritz@g10code.com>
* ac.c (eme_pkcs_v1_5_encode): Use KEY_SIZE directly, no need to
diff --git a/cipher/random-daemon.c b/cipher/random-daemon.c
index b659caaa..6a42d551 100644
--- a/cipher/random-daemon.c
+++ b/cipher/random-daemon.c
@@ -33,21 +33,98 @@
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <errno.h>
+#include <unistd.h>
#include "g10lib.h"
#include "random.h"
#include "ath.h"
+
-/* The lock taken while talking to the daemon. */
+/* This is default socket name we use in case the provided socket name
+ is NULL. */
+#define RANDOM_DAEMON_SOCKET "/var/run/libgcrypt/S.gcryptrnd"
+
+/* The lock serializing access to the daemon. */
static ath_mutex_t daemon_lock = ATH_MUTEX_INITIALIZER;
+/* The socket connected to the daemon. */
+static int daemon_socket = -1;
+
+/* Creates a socket connected to the daemon. On success, store the
+ socket fd in *SOCK. Returns error code. */
+static gcry_error_t
+connect_to_socket (const char *socketname, int *sock)
+{
+ struct sockaddr_un *srvr_addr;
+ socklen_t addrlen;
+ gcry_error_t err;
+ int fd;
+ int rc;
+
+ srvr_addr = NULL;
+
+ /* Create a socket. */
+ fd = socket (AF_UNIX, SOCK_STREAM, 0);
+ if (fd == -1)
+ {
+ log_error ("can't create socket: %s\n", strerror (errno));
+ err = gcry_error_from_errno (errno);
+ goto out;
+ }
+
+ /* Set up address. */
+ srvr_addr = gcry_malloc (sizeof *srvr_addr);
+ if (! srvr_addr)
+ {
+ log_error ("malloc failed: %s\n", strerror (errno));
+ err = gcry_error_from_errno (errno);
+ goto out;
+ }
+ memset (srvr_addr, 0, sizeof *srvr_addr);
+ srvr_addr->sun_family = AF_UNIX;
+ if (strlen (socketname) + 1 >= sizeof (srvr_addr->sun_path))
+ {
+ log_error ("socket name `%s' too long\n", socketname);
+ err = gcry_error (GPG_ERR_INTERNAL); /* FIXME? */
+ goto out;
+ }
+ strcpy (srvr_addr->sun_path, socketname);
+ addrlen = (offsetof (struct sockaddr_un, sun_path)
+ + strlen (srvr_addr->sun_path) + 1);
+
+ /* Connect socket. */
+ rc = connect (fd, (struct sockaddr *) srvr_addr, addrlen);
+ if (rc == -1)
+ {
+ log_error ("error connecting socket `%s': %s\n",
+ srvr_addr->sun_path, strerror (errno));
+ err = gcry_error_from_errno (errno);
+ goto out;
+ }
+
+ err = 0;
+
+ out:
+
+ *sock = fd;
+ gcry_free (srvr_addr);
+
+ if (err)
+ close (fd);
+
+ return err;
+}
/* Initialize basics of this module. This should be viewed as a
constroctur to prepare locking. */
void
-_gcry_daemon_initialize_basics (void)
+_gcry_daemon_initialize_basics (const char *socketname)
{
static int initialized;
int err;
@@ -58,24 +135,177 @@ _gcry_daemon_initialize_basics (void)
err = ath_mutex_init (&daemon_lock);
if (err)
log_fatal ("failed to create the daemon lock: %s\n", strerror (err) );
+
+ err = connect_to_socket (socketname ? socketname : RANDOM_DAEMON_SOCKET,
+ &daemon_socket);
+ if (err)
+ log_info ("not using random daemon\n");
}
}
+
+/* Send LENGTH bytes of BUFFER to file descriptor FD. Returns 0 on
+ success or another value on write error. */
+static int
+writen (int fd, const void *buffer, size_t length)
+{
+ ssize_t n;
+
+ while (length)
+ {
+ do
+ n = ath_write (fd, buffer, length);
+ while (n < 0 && errno == EINTR);
+ if (n < 0)
+ {
+ log_error ("write error: %s\n", strerror (errno));
+ return -1; /* write error */
+ }
+ length -= n;
+ buffer += n;
+ }
+ return 0; /* Okay */
+}
+
+static int
+readn (int fd, void *buf, size_t buflen, size_t *ret_nread)
+{
+ size_t nleft = buflen;
+ int nread;
+ char *p;
+
+ p = buf;
+ while (nleft > 0)
+ {
+ nread = ath_read (fd, buf, nleft);
+ if (nread < 0)
+ {
+ if (nread == EINTR)
+ nread = 0;
+ else
+ return -1;
+ }
+ else if (!nread)
+ break; /* EOF */
+ nleft -= nread;
+ buf = (char*)buf + nread;
+ }
+ if (ret_nread)
+ *ret_nread = buflen - nleft;
+ return 0;
+}
+
+/* This functions requests REQ_NBYTES from the daemon. If NONCE is
+ true, the data should be suited for a nonce. If NONCE is FALSE,
+ data of random level LEVEL will be generated. The retrieved random
+ data will be stored in BUFFER. Returns error code. */
+static gcry_error_t
+call_daemon (void *buffer, size_t req_nbytes, int nonce,
+ enum gcry_random_level level)
+{
+ unsigned char buf[255];
+ gcry_error_t err;
+ size_t nbytes;
+ size_t nread;
+ int rc;
+ err = 0;
+ if (! req_nbytes)
+ return 0;
+ ath_mutex_lock (&daemon_lock);
+ do
+ {
+ /* Process in chunks. */
+ nbytes = req_nbytes > sizeof (buf) ? sizeof (buf) : req_nbytes;
+ req_nbytes -= nbytes;
+ /* Construct request. */
+ buf[0] = 3;
+ if (nonce)
+ buf[1] = 10;
+ else if (level == GCRY_VERY_STRONG_RANDOM)
+ buf[1] = 12;
+ else if (level == GCRY_STRONG_RANDOM)
+ buf[1] = 11;
+ buf[2] = nbytes;
+ /* Send request. */
+ rc = writen (daemon_socket, buf, 3);
+ if (rc == -1)
+ {
+ err = gcry_error_from_errno (errno);
+ break;
+ }
+
+ /* Retrieve response. */
+ rc = readn (daemon_socket, buf, 2, &nread);
+ if (rc == -1)
+ {
+ err = gcry_error_from_errno (errno);
+ log_error ("read error: %s\n", gcry_strerror (err));
+ break;
+ }
+ if (nread && buf[0])
+ {
+ log_error ("random daemon returned error code %d\n", buf[0]);
+ err = gcry_error (GPG_ERR_INTERNAL); /* ? */
+ break;
+ }
+ if (nread != 2)
+ {
+ log_error ("response too small\n");
+ err = gcry_error (GPG_ERR_PROTOCOL_VIOLATION); /* ? */
+ break;
+ }
+ // if (1) /* FIXME, verbose */
+ // log_info ("received response with %d bytes of data\n", buf[1]);
+ if (buf[1] < nbytes)
+ {
+ log_error ("error: server returned less bytes than requested\n");
+ err = gcry_error (GPG_ERR_PROTOCOL_VIOLATION); /* ? */
+ break;
+ }
+ else if (buf[1] > nbytes)
+ {
+ log_error ("warning: server returned more bytes than requested\n");
+ err = gcry_error (GPG_ERR_PROTOCOL_VIOLATION); /* ? */
+ break;
+ }
+ assert (nbytes <= sizeof (buf));
+ rc = readn (daemon_socket, buf, nbytes, &nread);
+ if (rc == -1)
+ {
+ err = gcry_error_from_errno (errno);
+ log_error ("read error: %s\n", gcry_strerror (err));
+ break;
+ }
+
+ if (nread != nbytes)
+ {
+ log_error ("too little random data read\n");
+ err = gcry_error (GPG_ERR_INTERNAL);
+ break;
+ }
+ /* Successfuly read another chunk of data. */
+ memcpy (buffer, buf, nbytes);
+ buffer = ((char *) buffer) + nbytes;
+ }
+ while (req_nbytes);
+ ath_mutex_unlock (&daemon_lock);
+ return err;
+}
/* Internal function to fill BUFFER with LENGTH bytes of random. We
support GCRY_STRONG_RANDOM and GCRY_VERY_STRONG_RANDOM here.
@@ -84,7 +314,11 @@ int
_gcry_daemon_randomize (void *buffer, size_t length,
enum gcry_random_level level)
{
- return -1;
+ gcry_error_t err;
+
+ err = call_daemon (buffer, length, 0, level);
+
+ return err ? -1 : 0;
}
/* Internal function to return a pointer to a randomized buffer of
@@ -95,7 +329,24 @@ _gcry_daemon_randomize (void *buffer, size_t length,
void *
_gcry_daemon_get_random_bytes (size_t nbytes, int level, int secure)
{
- return NULL;
+ gcry_error_t err;
+ void *p;
+
+ err = _gcry_malloc (nbytes, secure ? GCRY_ALLOC_FLAG_SECURE : 0, &p);
+ if (err)
+ goto out;
+
+ err = call_daemon (p, nbytes, 0, level);
+
+ out:
+
+ if (err)
+ {
+ gcry_free (p);
+ p = NULL;
+ }
+
+ return p;
}
@@ -104,5 +355,11 @@ _gcry_daemon_get_random_bytes (size_t nbytes, int level, int secure)
int
_gcry_daemon_create_nonce (void *buffer, size_t length)
{
- return -1;
+ gcry_error_t err;
+
+ err = call_daemon (buffer, length, 1, 0);
+
+ return err ? -1 : 0;
}
+
+/* END */
diff --git a/cipher/random.c b/cipher/random.c
index ea69f4c9..039997d4 100644
--- a/cipher/random.c
+++ b/cipher/random.c
@@ -105,6 +105,7 @@ static int pool_balance;
static int just_mixed;
static int did_initial_extra_seeding;
static char *seed_file_name;
+static char *daemon_socket_name;
static int allow_seed_file_update;
static int secure_alloc;
@@ -160,7 +161,7 @@ initialize_basics(void)
if (err)
log_fatal ("failed to create the nonce buffer lock: %s\n",
strerror (err) );
- _gcry_daemon_initialize_basics ();
+ _gcry_daemon_initialize_basics (daemon_socket_name);
}
}
@@ -251,6 +252,15 @@ _gcry_quick_random_gen( int onoff )
}
+void
+_gcry_set_random_daemon_socket (const char *socketname)
+{
+ if (daemon_socket_name)
+ BUG ();
+
+ daemon_socket_name = gcry_xstrdup (socketname);
+}
+
/* With ONOFF set to 1, enable the use of the daemon. With ONOFF set
to 0, disable the use of the daemon. With ONOF set to -1, return
whether the daemon has been enabled. */
@@ -258,11 +268,12 @@ int
_gcry_use_random_daemon (int onoff)
{
int last;
-
+
/* FIXME: This is not really thread safe. */
last = allow_daemon;
if (onoff != -1)
allow_daemon = onoff;
+
return last;
}
diff --git a/cipher/random.h b/cipher/random.h
index c87f46e3..afed64c7 100644
--- a/cipher/random.h
+++ b/cipher/random.h
@@ -1,5 +1,5 @@
/* random.h - random functions
- * Copyright (C) 1998, 2002 Free Software Foundation, Inc.
+ * Copyright (C) 1998, 2002, 2006 Free Software Foundation, Inc.
*
* This file is part of Libgcrypt.
*
@@ -37,7 +37,8 @@ byte *_gcry_get_random_bits( size_t nbits, int level, int secure );
void _gcry_fast_random_poll( void );
/*-- random-daemon.c (only used from random.c) --*/
-void _gcry_daemon_initialize_basics (void);
+void _gcry_set_random_daemon_socket (const char *socketname);
+void _gcry_daemon_initialize_basics (const char *socketname);
int _gcry_daemon_randomize (void *buffer, size_t length,
enum gcry_random_level level);
void *_gcry_daemon_get_random_bytes (size_t nbytes, int level, int secure);