#include "rand_lcl.h"
#include "internal/rand_int.h"
#include <stdio.h>
+#include "internal/dso.h"
#if defined(__linux)
# include <sys/syscall.h>
#endif
# include <sys/sysctl.h>
# include <sys/param.h>
#endif
-#if defined(__OpenBSD__)
+#if defined(__OpenBSD__) || defined(__NetBSD__)
# include <sys/param.h>
#endif
#ifdef OPENSSL_SYS_UNIX
# error "librandom not (yet) supported"
# endif
-# if defined(__FreeBSD__) && defined(KERN_ARND)
+# if (defined(__FreeBSD__) || defined(__NetBSD__)) && defined(KERN_ARND)
/*
* sysctl_random(): Use sysctl() to read a random number from the kernel
* Returns the size on success, 0 on failure.
size_t len;
/*
- * Old implementations returned longs, newer versions support variable
- * sizes up to 256 byte. The code below would not work properly when
- * the sysctl returns long and we want to request something not a multiple
- * of longs, which should never be the case.
+ * On FreeBSD old implementations returned longs, newer versions support
+ * variable sizes up to 256 byte. The code below would not work properly
+ * when the sysctl returns long and we want to request something not a
+ * multiple of longs, which should never be the case.
*/
if (!ossl_assert(buflen % sizeof(long) == 0))
return 0;
+ /*
+ * On NetBSD before 4.0 KERN_ARND was an alias for KERN_URND, and only
+ * filled in an int, leaving the rest uninitialized. Since NetBSD 4.0
+ * it returns a variable number of bytes with the current version supporting
+ * up to 256 bytes.
+ * Just return an error on older NetBSD versions.
+ */
+#if defined(__NetBSD__) && __NetBSD_Version__ < 400000000
+ return 0;
+#endif
+
mib[0] = CTL_KERN;
mib[1] = KERN_ARND;
*/
int syscall_random(void *buf, size_t buflen)
{
+ union {
+ void *p;
+ int (*f)(void *buffer, size_t length);
+ } p_getentropy;
+
+ /*
+ * Do runtime detection to find getentropy().
+ *
+ * We could cache the result of the lookup, but we normally don't
+ * call this function often.
+ *
+ * Known OSs that should support this:
+ * - Darwin since 16 (OSX 10.12, IOS 10.0).
+ * - Solaris since 11.3
+ * - OpenBSD since 5.6
+ * - Linux since 3.17 with glibc 2.25
+ * - FreeBSD since 12.0 (1200061)
+ */
+ p_getentropy.p = DSO_global_lookup("getentropy");
+ if (p_getentropy.p != NULL)
+ return p_getentropy.f(buf, buflen);
+
# if defined(OPENSSL_HAVE_GETRANDOM)
return (int)getrandom(buf, buflen, 0);
# endif
+ /* Linux supports this since version 3.17 */
# if defined(__linux) && defined(SYS_getrandom)
return (int)syscall(SYS_getrandom, buf, buflen, 0);
# endif
-# if defined(__FreeBSD__) && defined(KERN_ARND)
+# if (defined(__FreeBSD__) || defined(__NetBSD__)) && defined(KERN_ARND)
return (int)sysctl_random(buf, buflen);
# endif
- /* Supported since OpenBSD 5.6 */
-# if defined(__OpenBSD__) && OpenBSD >= 201411
- return getentropy(buf, buflen);
-# endif
-
return -1;
}