From 5d91cb9b0ed833517cc9288e9ca802d8a1b62757 Mon Sep 17 00:00:00 2001 From: Andre Noll Date: Sun, 14 Jun 2009 11:02:17 +0200 Subject: [PATCH] Use openssl's RAND_load_file() and RAND_bytes() to get randomness. This should yield random data that is cryptographically stronger than random(). --- command.c | 8 +++----- crypt.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ crypt.h | 2 ++ para.h | 2 +- server.c | 35 +++-------------------------------- 5 files changed, 57 insertions(+), 38 deletions(-) diff --git a/command.c b/command.c index 15b166ad..ab765a1b 100644 --- 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 73eebe18..580974d7 100644 --- a/crypt.c +++ b/crypt.c @@ -10,6 +10,54 @@ #include "error.h" #include "string.h" #include "crypt.h" +#include +#include + +/** + * 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 88af9e89..1ed3985d 100644 --- 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 7cdc5e07..1dbffdf8 100644 --- 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))); } diff --git a/server.c b/server.c index 2e5f5f74..6c3373d3 100644 --- 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, ¶ms); HANDLE_VERSION_FLAG("server", conf); -- 2.39.2