cipher/ChangeLog:
authorMoritz Schulte <mo@g10code.com>
Sat, 22 Apr 2006 16:09:23 +0000 (16:09 +0000)
committerMoritz Schulte <mo@g10code.com>
Sat, 22 Apr 2006 16:09:23 +0000 (16:09 +0000)
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().

cipher/ChangeLog
cipher/random-daemon.c
cipher/random.c
cipher/random.h
src/ChangeLog
src/gcrypt.h
src/global.c

index 1588e94..70f1cf8 100644 (file)
@@ -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
index b659caa..6a42d55 100644 (file)
 #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"
 
+\f
 
-/* 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");
     }
 }
 
+\f
 
+/* 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 */
index ea69f4c..039997d 100644 (file)
@@ -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;
 }
 
index c87f46e..afed64c 100644 (file)
@@ -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);
index a2fb5cd..f7c638c 100644 (file)
@@ -1,3 +1,10 @@
+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().
+
 2006-04-01  Moritz Schulte  <moritz@g10code.com>
 
        * gcrypt.h (gcry_ac_eme_pkcs_v1_5): Removed members: key, handle;
index 30368a7..ba38562 100644 (file)
@@ -327,7 +327,9 @@ enum gcry_ctl_cmds
     GCRYCTL_SET_RANDOM_SEED_FILE = 45,
     GCRYCTL_UPDATE_RANDOM_SEED_FILE = 46,
     GCRYCTL_SET_THREAD_CBS = 47,
-    GCRYCTL_FAST_POLL = 48
+    GCRYCTL_FAST_POLL = 48,
+    GCRYCTL_SET_RANDOM_DAEMON_SOCKET = 49,
+    GCRYCTL_USE_RANDOM_DAEMON = 50
   };
 
 /* Perform various operations defined by CMD. */
index 8dd2657..399fc76 100644 (file)
@@ -334,6 +334,17 @@ gcry_control (enum gcry_ctl_cmds cmd, ...)
       _gcry_fast_random_poll (); 
       break;
 
+    case GCRYCTL_SET_RANDOM_DAEMON_SOCKET:
+      _gcry_set_random_daemon_socket (va_arg (arg_ptr, const char *));
+      break;
+
+    case GCRYCTL_USE_RANDOM_DAEMON:
+      /* We need to do make sure that the random pool is really
+         initialized so that the poll fucntion is not a NOP. */
+      _gcry_random_initialize (1);
+      _gcry_use_random_daemon (!! va_arg (arg_ptr, int));
+      break;
+
     default:
       err = GPG_ERR_INV_OP;
     }