summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/crypto-backend.h1
-rw-r--r--lib/gnutls_global.c8
-rw-r--r--lib/nettle/rnd-common.c40
-rw-r--r--lib/nettle/rnd-common.h1
-rw-r--r--lib/nettle/rnd.c10
-rw-r--r--lib/random.h1
6 files changed, 58 insertions, 3 deletions
diff --git a/lib/crypto-backend.h b/lib/crypto-backend.h
index 7f4e1b61c6..09a7d92c67 100644
--- a/lib/crypto-backend.h
+++ b/lib/crypto-backend.h
@@ -77,6 +77,7 @@ typedef struct {
typedef struct gnutls_crypto_rnd {
int (*init) (void **ctx);
+ int (*check) (void **ctx);
int (*rnd) (void *ctx, int level, void *data, size_t datasize);
void (*rnd_refresh) (void *ctx);
void (*deinit) (void *ctx);
diff --git a/lib/gnutls_global.c b/lib/gnutls_global.c
index e4a303fcd6..5f340533d1 100644
--- a/lib/gnutls_global.c
+++ b/lib/gnutls_global.c
@@ -208,6 +208,14 @@ int gnutls_global_init(void)
_gnutls_init++;
if (_gnutls_init > 1) {
+ if (_gnutls_init == 1 && _gnutls_init_ret == 0) {
+ /* some applications may close the urandom fd
+ * before calling gnutls_global_init(). in that
+ * case reopen it */
+ ret = _gnutls_rnd_check();
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+ }
ret = _gnutls_init_ret;
goto out;
}
diff --git a/lib/nettle/rnd-common.c b/lib/nettle/rnd-common.c
index 88aa7677d1..4c83ac6549 100644
--- a/lib/nettle/rnd-common.c
+++ b/lib/nettle/rnd-common.c
@@ -39,9 +39,10 @@
#if defined(HAVE_LINUX_GETRANDOM)
# include <linux/random.h>
-#elif defined(HAVE_GETENTROPY)
-# include <unistd.h>
#endif
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
/* gnulib wants to claim strerror even if it cannot provide it. WTF */
#undef strerror
@@ -99,6 +100,11 @@ int _rnd_get_system_entropy_win32(void* rnd, size_t size)
get_entropy_func _rnd_get_system_entropy = _rnd_get_system_entropy_win32;
+int _rnd_system_entropy_check(void)
+{
+ return 0;
+}
+
int _rnd_system_entropy_init(void)
{
int old;
@@ -133,6 +139,7 @@ void _rnd_system_entropy_deinit(void)
#include "egd.h"
int _gnutls_urandom_fd = -1;
+static mode_t _gnutls_urandom_fd_mode = 0;
get_entropy_func _rnd_get_system_entropy = NULL;
@@ -167,6 +174,11 @@ int _rnd_system_entropy_init(void)
return 0;
}
+int _rnd_system_entropy_check(void)
+{
+ return 0;
+}
+
void _rnd_system_entropy_deinit(void)
{
return;
@@ -229,9 +241,22 @@ int _rnd_get_system_entropy_egd(void* _rnd, size_t size)
return 0;
}
+int _rnd_system_entropy_check(void)
+{
+ int ret;
+ struct stat st;
+
+ ret = fstat(_gnutls_urandom_fd, &st);
+ if (ret < 0 && st.st_mode != _gnutls_urandom_fd_mode) {
+ return _rnd_system_entropy_init();
+ }
+ return 0;
+}
+
int _rnd_system_entropy_init(void)
{
-int old;
+ int old;
+ struct stat st;
_gnutls_urandom_fd = open("/dev/urandom", O_RDONLY);
if (_gnutls_urandom_fd < 0) {
@@ -243,6 +268,10 @@ int old;
if (old != -1)
fcntl(_gnutls_urandom_fd, F_SETFD, old | FD_CLOEXEC);
+ if (fstat(_gnutls_urandom_fd, &st) >= 0) {
+ _gnutls_urandom_fd_mode = st.st_mode;
+ }
+
_rnd_get_system_entropy = _rnd_get_system_entropy_urandom;
return 0;
@@ -254,6 +283,11 @@ fallback:
gnutls_assert_val
(GNUTLS_E_RANDOM_DEVICE_ERROR);
}
+
+ if (fstat(_gnutls_urandom_fd, &st) >= 0) {
+ _gnutls_urandom_fd_mode = st.st_mode;
+ }
+
_rnd_get_system_entropy = _rnd_get_system_entropy_egd;
return 0;
diff --git a/lib/nettle/rnd-common.h b/lib/nettle/rnd-common.h
index a43f7be233..c795f81131 100644
--- a/lib/nettle/rnd-common.h
+++ b/lib/nettle/rnd-common.h
@@ -50,6 +50,7 @@ __attribute__((packed))
void _rnd_get_event(struct event_st *e);
int _rnd_system_entropy_init(void);
+int _rnd_system_entropy_check(void);
void _rnd_system_entropy_deinit(void);
typedef int (*get_entropy_func)(void* rnd, size_t size);
diff --git a/lib/nettle/rnd.c b/lib/nettle/rnd.c
index 8dd98c3bf4..d4dbdc144f 100644
--- a/lib/nettle/rnd.c
+++ b/lib/nettle/rnd.c
@@ -257,6 +257,15 @@ static int wrap_nettle_rnd_init(void **ctx)
return 0;
}
+/* This is called when gnutls_global_init() is called for second time.
+ * It must check whether any resources are still available.
+ * The particular problem it solves is to verify that the urandom fd is still
+ * open (for applications that for some reason closed all fds */
+static int wrap_nettle_rnd_check(void **ctx)
+{
+ return _rnd_system_entropy_check();
+}
+
static int
wrap_nettle_rnd_nonce(void *_ctx, void *data, size_t datasize)
{
@@ -360,6 +369,7 @@ int crypto_rnd_prio = INT_MAX;
gnutls_crypto_rnd_st _gnutls_rnd_ops = {
.init = wrap_nettle_rnd_init,
+ .check = wrap_nettle_rnd_check,
.deinit = wrap_nettle_rnd_deinit,
.rnd = wrap_nettle_rnd,
.rnd_refresh = wrap_nettle_rnd_refresh,
diff --git a/lib/random.h b/lib/random.h
index 8c755f8997..35857be357 100644
--- a/lib/random.h
+++ b/lib/random.h
@@ -47,6 +47,7 @@ inline static void _gnutls_rnd_refresh(void)
void _gnutls_rnd_deinit(void);
int _gnutls_rnd_init(void);
+int _gnutls_rnd_check(void);
#ifndef _WIN32
extern int _gnutls_urandom_fd;