Use openssl's RAND_load_file() and RAND_bytes() to get randomness.
authorAndre Noll <maan@systemlinux.org>
Sun, 14 Jun 2009 09:02:17 +0000 (11:02 +0200)
committerAndre Noll <maan@systemlinux.org>
Sun, 14 Jun 2009 09:02:17 +0000 (11:02 +0200)
This should yield random data that is cryptographically stronger than
random().

command.c
crypt.c
crypt.h
para.h
server.c

index 15b166a..ab765a1 100644 (file)
--- a/command.c
+++ b/command.c
@@ -591,10 +591,7 @@ static struct server_command *parse_cmd(const char *cmdstr)
 
 static void init_rc4_keys(void)
 {
-       int i;
-
-       for (i = 0; i < 2 * RC4_KEY_LEN; i++)
-               rc4_buf[i] = para_random(256);
+       get_random_bytes_or_die(rc4_buf, 2 * RC4_KEY_LEN);
        PARA_DEBUG_LOG("rc4 keys initialized (%u:%u)\n",
                (unsigned char) rc4_buf[0],
                (unsigned char) rc4_buf[RC4_KEY_LEN]);
@@ -702,7 +699,6 @@ __noreturn void handle_connect(int fd, const char *peername)
        ret = mark_fd_blocking(fd);
        if (ret < 0)
                goto err_out;
-       challenge_nr = random();
        /* send Welcome message */
        ret = send_va_buffer(fd, "This is para_server, version "
                PACKAGE_VERSION  ".\n" );
@@ -726,6 +722,8 @@ __noreturn void handle_connect(int fd, const char *peername)
        u = lookup_user(p);
        if (!u)
                goto err_out;
+       get_random_bytes_or_die((unsigned char *)&challenge_nr,
+               sizeof(challenge_nr));
        ret = para_encrypt_challenge(u->rsa, challenge_nr, crypt_buf);
        if (ret <= 0)
                goto err_out;
diff --git a/crypt.c b/crypt.c
index 73eebe1..580974d 100644 (file)
--- a/crypt.c
+++ b/crypt.c
 #include "error.h"
 #include "string.h"
 #include "crypt.h"
+#include <openssl/rand.h>
+#include <openssl/err.h>
+
+/**
+ * Fill a buffer with random content.
+ *
+ * \param buf The buffer to fill.
+ * \param num The size of \a buf in bytes.
+ *
+ * This function puts \a num cryptographically strong pseudo-random bytes into
+ * buf. If libssl can not guarantee an unpredictable byte sequence (for example
+ * because the PRNG has not been seeded with enough randomness) the function
+ * logs an error message and calls exit().
+ */
+void get_random_bytes_or_die(unsigned char *buf, int num)
+{
+       unsigned long err;
+
+       /* RAND_bytes() returns 1 on success, 0 otherwise. */
+       if (RAND_bytes(buf, num) == 1)
+               return;
+       err = ERR_get_error();
+       PARA_EMERG_LOG("%s\n", ERR_reason_error_string(err));
+       exit(EXIT_FAILURE);
+}
+
+/**
+ * Seed pseudo random number generators.
+ *
+ * This function reads 64 bytes from /dev/urandom and adds them to the SSL
+ * PRNG. It also seeds the PRNG used by random() with a random seed obtained
+ * from SSL. If /dev/random could not be read, an error message is logged and
+ * the function calls exit().
+ *
+ * \sa RAND_load_file(3), \ref get_random_bytes_or_die(), srandom(3),
+ * random(3), \ref para_random().
+ */
+void init_random_seed_or_die(void)
+{
+       int seed, ret = RAND_load_file("/dev/urandom", 64);
+
+       if (ret != 64) {
+               PARA_EMERG_LOG("could not seed PRNG (ret = %d)\n", ret);
+               exit(EXIT_FAILURE);
+       }
+       get_random_bytes_or_die((unsigned char *)&seed, sizeof(seed));
+       srandom(seed);
+}
 
 static EVP_PKEY *load_key(const char *file, int private)
 {
diff --git a/crypt.h b/crypt.h
index 88af9e8..1ed3985 100644 (file)
--- a/crypt.h
+++ b/crypt.h
@@ -18,6 +18,8 @@ int para_decrypt_buffer(char *key_file, unsigned char *outbuf, unsigned char *in
 int get_rsa_key(char *key_file, RSA **rsa, int private);
 
 void rsa_free(RSA *rsa);
+void get_random_bytes_or_die(unsigned char *buf, int num);
+void init_random_seed_or_die(void);
 
 /** \cond used to distinguish between loading of private/public key */
 #define LOAD_PUBLIC_KEY 0
diff --git a/para.h b/para.h
index 7cdc5e0..1dbffdf 100644 (file)
--- a/para.h
+++ b/para.h
@@ -224,7 +224,7 @@ __printf_2_3 void para_log(int, const char*, ...);
  *
  * \return An integer between zero and \p max - 1, inclusively.
  */
-static inline long int para_random(unsigned max)
+_static_inline_ long int para_random(unsigned max)
 {
        return ((max + 0.0) * (random() / (RAND_MAX + 1.0)));
 }
index 2e5f5f7..6c3373d 100644 (file)
--- a/server.c
+++ b/server.c
@@ -372,7 +372,6 @@ static void command_post_select(struct sched *s, struct task *t)
        PARA_INFO_LOG("got connection from %s, forking\n", peer_name);
        mmd->num_connects++;
        mmd->active_connections++;
-       random();
        /* The chunk table and the info_string are pointers located in the
         * mmd struct that point to dynamically allocated memory that must be
         * freed by the parent and the child. However, as the mmd struct is in
@@ -438,35 +437,6 @@ err:
        exit(EXIT_FAILURE);
 }
 
-static void init_random_seed(void)
-{
-       unsigned int seed;
-       int fd, ret = para_open("/dev/urandom", O_RDONLY, 0);
-
-       if (ret < 0)
-               goto err;
-       fd = ret;
-       ret = read(fd, &seed, sizeof(seed));
-       if (ret < 0) {
-               ret = -ERRNO_TO_PARA_ERROR(errno);
-               goto out;
-       }
-       if (ret != sizeof(seed)) {
-               ret = -ERRNO_TO_PARA_ERROR(EIO);
-               goto out;
-       }
-       srandom(seed);
-       ret = 1;
-out:
-       close(fd);
-       if (ret >= 0)
-               return;
-err:
-       PARA_EMERG_LOG("can not seed pseudo random number generator: %s\n",
-               para_strerror(-ret));
-       exit(EXIT_FAILURE);
-}
-
 static int init_afs(void)
 {
        int ret, afs_server_socket[2];
@@ -474,7 +444,8 @@ static int init_afs(void)
        ret = socketpair(PF_UNIX, SOCK_DGRAM, 0, afs_server_socket);
        if (ret < 0)
                exit(EXIT_FAILURE);
-       afs_socket_cookie = para_random((uint32_t)-1);
+       get_random_bytes_or_die((unsigned char *)&afs_socket_cookie,
+               sizeof(afs_socket_cookie));
        mmd->afs_pid = fork();
        if (mmd->afs_pid < 0)
                exit(EXIT_FAILURE);
@@ -510,7 +481,7 @@ static void server_init(int argc, char **argv)
        int afs_socket;
 
        valid_fd_012();
-       init_random_seed();
+       init_random_seed_or_die();
        /* parse command line options */
        server_cmdline_parser_ext(argc, argv, &conf, &params);
        HANDLE_VERSION_FLAG("server", conf);