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);
_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;
}
#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
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;
#include "egd.h"
int _gnutls_urandom_fd = -1;
+static mode_t _gnutls_urandom_fd_mode = 0;
get_entropy_func _rnd_get_system_entropy = NULL;
return 0;
}
+int _rnd_system_entropy_check(void)
+{
+ return 0;
+}
+
void _rnd_system_entropy_deinit(void)
{
return;
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) {
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;
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;
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);
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)
{
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,
void _gnutls_rnd_deinit(void);
int _gnutls_rnd_init(void);
+int _gnutls_rnd_check(void);
#ifndef _WIN32
extern int _gnutls_urandom_fd;