summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNikos Mavrogiannopoulos <nmav@redhat.com>2016-07-15 14:34:38 +0200
committerNikos Mavrogiannopoulos <nmav@redhat.com>2016-07-15 14:41:41 +0200
commit4061f56129449bf66a93fa6faf059c47a947659c (patch)
treee1c15d20991ec3764a18b21a0d4f12fb2630717a
parent5c9151f84d36fae6391073f3c2885a3c02f5e8f2 (diff)
downloadgnutls-4061f56129449bf66a93fa6faf059c47a947659c.tar.gz
Added auto-detection of getrandom() system call in Linux systems
In addition use getrandom() via the syscall interface if it doesn't exist in Libc. The reason for the latter is that getrandom() support for glibc is in limbo for several years, and for auto-detection is that even if it is going to be present in libc we will not be able to guarrantee that the system call is available just because it is present in glibc. For that we detect on initialization whether getrandom() can obtain random data, and if yes, we continue using that.
-rw-r--r--lib/nettle/rnd-common.c53
1 files changed, 48 insertions, 5 deletions
diff --git a/lib/nettle/rnd-common.c b/lib/nettle/rnd-common.c
index 680126033a..0c27a1e3aa 100644
--- a/lib/nettle/rnd-common.c
+++ b/lib/nettle/rnd-common.c
@@ -37,11 +37,6 @@
#include <rnd-common.h>
#include <hash-pjw-bare.h>
-#if defined(HAVE_LINUX_GETRANDOM)
-# include <linux/random.h>
-# define getentropy(x, size) getrandom(x, size, 0)
-# define HAVE_GETENTROPY
-#endif
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
@@ -178,6 +173,41 @@ void _rnd_system_entropy_deinit(void)
#else /* /dev/urandom - egd approach */
+#if defined(__linux)
+
+#ifdef HAVE_LINUX_GETRANDOM
+# include <linux/random.h>
+#else
+# include <sys/syscall.h>
+# undef getrandom
+# define getrandom(dst,s,flags) syscall(__NR_getrandom, (void*)dst, (size_t)s, (unsigned int)flags)
+#endif
+
+static unsigned have_getrandom(void)
+{
+ char c;
+ if (getrandom(&c, 1, 0) == 1)
+ return 1;
+ return 0;
+}
+
+static int _rnd_get_system_entropy_getrandom(void* _rnd, size_t size)
+{
+ int ret;
+ ret = getrandom(_rnd, size, 0);
+ if (ret == -1) {
+ gnutls_assert();
+ _gnutls_debug_log
+ ("Failed to use getrandom: %s\n",
+ strerror(errno));
+ return GNUTLS_E_RANDOM_DEVICE_ERROR;
+ }
+ return 0;
+}
+#else
+# define have_getrandom() 0
+#endif
+
static int _rnd_get_system_entropy_urandom(void* _rnd, size_t size)
{
uint8_t* rnd = _rnd;
@@ -238,6 +268,9 @@ int _rnd_system_entropy_check(void)
int ret;
struct stat st;
+ if (_gnutls_urandom_fd == -1) /* not using urandom */
+ return 0;
+
ret = fstat(_gnutls_urandom_fd, &st);
if (ret < 0 || st.st_mode != _gnutls_urandom_fd_mode) {
return _rnd_system_entropy_init();
@@ -250,6 +283,14 @@ int _rnd_system_entropy_init(void)
int old;
struct stat st;
+ /* Enable getrandom() usage if available */
+ if (have_getrandom()) {
+ _rnd_get_system_entropy = _rnd_get_system_entropy_getrandom;
+ _gnutls_debug_log("getrandom random generator was detected\n");
+ return 0;
+ }
+
+ /* First fallback: /dev/unrandom */
_gnutls_urandom_fd = open("/dev/urandom", O_RDONLY);
if (_gnutls_urandom_fd < 0) {
_gnutls_debug_log("Cannot open urandom!\n");
@@ -268,6 +309,7 @@ int _rnd_system_entropy_init(void)
return 0;
fallback:
+ /* Third fallback: EGD */
_gnutls_urandom_fd = _rndegd_connect_socket();
if (_gnutls_urandom_fd < 0) {
_gnutls_debug_log("Cannot open egd socket!\n");
@@ -280,6 +322,7 @@ fallback:
_gnutls_urandom_fd_mode = st.st_mode;
}
+ _gnutls_debug_log("EGD random generator was detected\n");
_rnd_get_system_entropy = _rnd_get_system_entropy_egd;
return 0;