diff options
author | Moritz Schulte <mo@g10code.com> | 2006-04-22 16:09:23 +0000 |
---|---|---|
committer | Moritz Schulte <mo@g10code.com> | 2006-04-22 16:09:23 +0000 |
commit | 9771a836746cc94699b4eaee6c68ba07caee3472 (patch) | |
tree | e0cb694d3d1799ad1d796ed76c83b284538e3b52 /cipher | |
parent | eaee2dd54a87f0adad6f47244cbf56aa0b04cd23 (diff) | |
download | libgcrypt-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/ChangeLog | 19 | ||||
-rw-r--r-- | cipher/random-daemon.c | 267 | ||||
-rw-r--r-- | cipher/random.c | 15 | ||||
-rw-r--r-- | cipher/random.h | 5 |
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); |