Merge pull request #3423 from niacat/sysctl-arnd
entropy: Add support for BSD sysctl(KERN_ARND)
diff --git a/ChangeLog.d/sysctl-arnd-support.txt b/ChangeLog.d/sysctl-arnd-support.txt
new file mode 100644
index 0000000..14ad674
--- /dev/null
+++ b/ChangeLog.d/sysctl-arnd-support.txt
@@ -0,0 +1,2 @@
+Features
+ * Added support to entropy_poll for the kern.arandom syscall supported on some BSD systems. Contributed by Nia Alarie in #3423.
diff --git a/library/entropy_poll.c b/library/entropy_poll.c
index 8b4a5af..dc62183 100644
--- a/library/entropy_poll.c
+++ b/library/entropy_poll.c
@@ -115,6 +115,41 @@
#endif /* SYS_getrandom */
#endif /* __linux__ || __midipix__ */
+/*
+ * Some BSD systems provide KERN_ARND.
+ * This is equivalent to reading from /dev/urandom, only it doesn't require an
+ * open file descriptor, and provides up to 256 bytes per call (basically the
+ * same as getentropy(), but with a longer history).
+ *
+ * Documentation: https://netbsd.gw.com/cgi-bin/man-cgi?sysctl+7
+ */
+#if (defined(__FreeBSD__) || defined(__NetBSD__)) && !defined(HAVE_GETRANDOM)
+#include <sys/param.h>
+#include <sys/sysctl.h>
+#if defined(KERN_ARND)
+#define HAVE_SYSCTL_ARND
+
+static int sysctl_arnd_wrapper( unsigned char *buf, size_t buflen )
+{
+ int name[2];
+ size_t len;
+
+ name[0] = CTL_KERN;
+ name[1] = KERN_ARND;
+
+ while( buflen > 0 )
+ {
+ len = buflen > 256 ? 256 : buflen;
+ if( sysctl(name, 2, buf, &len, NULL, 0) == -1 )
+ return( -1 );
+ buflen -= len;
+ buf += len;
+ }
+ return( 0 );
+}
+#endif /* KERN_ARND */
+#endif /* __FreeBSD__ || __NetBSD__ */
+
#include <stdio.h>
int mbedtls_platform_entropy_poll( void *data,
@@ -139,6 +174,15 @@
((void) ret);
#endif /* HAVE_GETRANDOM */
+#if defined(HAVE_SYSCTL_ARND)
+ ((void) file);
+ ((void) read_len);
+ if( sysctl_arnd_wrapper( output, len ) == -1 )
+ return( MBEDTLS_ERR_ENTROPY_SOURCE_FAILED );
+ *olen = len;
+ return( 0 );
+#else
+
*olen = 0;
file = fopen( "/dev/urandom", "rb" );
@@ -156,6 +200,7 @@
*olen = len;
return( 0 );
+#endif /* HAVE_SYSCTL_ARND */
}
#endif /* _WIN32 && !EFIX64 && !EFI32 */
#endif /* !MBEDTLS_NO_PLATFORM_ENTROPY */