-
Notifications
You must be signed in to change notification settings - Fork 2.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
entropy: Add support for BSD sysctl(KERN_ARND) #3423
Conversation
This is basically the same as reading from /dev/urandom on supported systems, only it has a limit of 256 bytes per call, and does not require an open file descriptor (so it can be used in chroots, when resource limits are in place, or are otherwise exhausted). It's functionally equivalent to the comparable function getentropy(), but has been around for longer. It's actually used to implement getentropy in FreeBSD's libc. Discussions about adding getrandom or getentropy to NetBSD are still ongoing. It's present in all supported versions of FreeBSD and NetBSD. It's not present in DragonFly or OpenBSD. Documentation: https://netbsd.gw.com/cgi-bin/man-cgi?sysctl+7 Comparable code in OpenSSL: https://github.com/openssl/openssl/blob/ddec332f329a432a45c0131d83f3bfb46114532b/crypto/rand/rand_unix.c#L208 Signed-off-by: nia <[email protected]>
Signed-off-by: nia <[email protected]>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for your contribution! This looks generally good to me, except two details, one of which really needs fixing as it breaks one of our testing scripts.
* 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 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note: I also found it useful to have a look as sysctl(3) as well, but since it's prominently linked from the above, I'm not requesting any change here.
Signed-off-by: nia <[email protected]>
Unfortunately this breaks the build on FreeBSD.
|
Signed-off-by: nia <[email protected]>
It should build with clang now. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The code looks ok, but I don't understand why this is the right approach.
* 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). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What's the advantage of KERN_ARND
over arc4random_buf
?
Apparently arc4random_buf
ha been using ChaCha20 with backtracking resistance (replacing an older implementation based on RC4) since:
So arc4random_buf
looks fine to me on non-antique NetBSD, non-antique OpenBSD and the latest major release of FreeBSD, but wouldn't be ok on FreeBSD 11.x which is still supported.
So why not call arc4random_buf
on modern BSD, and fall back to /dev/urandom
on FreeBSD <12?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've discussed this with other projects and the response has been mixed. Certain libraries expressed a preference towards using a system call because it's harder to reconstruct the RNG state than it is for arc4random_buf
where the state lives in libc and is per-process.
If this was simply about providing an endless stream of random numbers to applications, I'd use arc4random without question, but since this is an "entropy" API that is intended for seeding other RNGs, it seemed more prudent to use a system call.
Using the sysctl will be safe on antique releases and using it doesn't involve having to check for the presence of a function in libc, just the presence of a #define (the sysctl
API is ancient BSD stuff). OpenSSL has an explicit policy of supporting OS versions that even we don't support, so they had a preference for this API.
Speaking from the NetBSD side, I'd like to see more software using arc4random_buf
(other developers and users may disagree with me), but it's up to you which you prefer to use in mbedtls. It's certainly safe in all versions I care about, and provides some very nice performance and simplicity — at the expense of keeping its state in the application, and an awkward name and possibly fatal insecurity on some OS versions. I can resubmit a PR that uses arc4random on a set of allowed operating system versions, if that's what is preferred. :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm starting to wonder if a three-layer approach would make sense:
- If we're on a set of known-good OS and versions use
arc4random_buf
. - Otherwise use
KERN_ARND
if available. - Otherwise fall back to
open()
ing/dev/urandom
.
If we go for this approach, we could begin by finalizing and merging this PR, and then have another one adding the arc4random layer.
The question is: what platforms would benefit from the KERN_ARND
layer in such an approach?
- FreeBSD 11 still uses ARC4 for
arc4random
and hasKERN_ARND
but it will be EOL in a bit more than a year (end of September 2021). - Dragonfly BSD looks like it's still using ARC4 for
arc4random
, according to this man page, but doesn't haveKERN_ARND
so can't benefit from this layer anyway.
So maybe three layers are not necessary, and just having arc4random()
when it's known to be safe, and /dev/urandom
as a fallback would be enough.
Wdyt?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not strongly opinionated about which approach gets chosen — I really just want a better default choice than reading from /dev/urandom
for NetBSD. Other than obvious performance differences, the only meaningful difference on all supported versions of NetBSD is that the application can't access the state of the KERN_ARND
RNG.
If you're happy using arc4random_buf
in an entropy function, I will submit a new PR after this one is closed or merged.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, so there is a minor security advantage to the sysctl
approach: if the arc4random state is compromised by a memory read vulnerability before it's used to seed the entropy for mbedtls, that compromises the mbedtls entropy. (If the arc4random state is compromised later, that shouldn't affect the mbedtls entropy since modern arc4random has backtracking resistance.) It's not such a big advantage that I'd reject arc4random, which is simpler, but since the sysctl code is there, I'm happy to use it.
Regarding OS version support, we don't have a well-defined policy, but we do try to accommodate people who run Mbed TLS on “oddball” platforms, including out-of-support platforms. But we can only promise best effort, not results, when it comes to platforms for which we don't have technical knowledge on the team and a CI system in place.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for fixing the build issue, however I think the fix could be improved.
Signed-off-by: nia <[email protected]>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Approved, with the caveat that it's not clear to me that and I'm happy to use KERN_ARND
is preferable to the simpler arc4random_buf
(except on FreeBSD <12 where we can continue to live with /dev/urandom
)KERN_ARND
rather than arc4random
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for adjusting the function prototype as suggested. Looks all good to me now.
Motivation: the default behaviour of reopening /dev/urandom repeatedly for every 128 bytes of entropy required is _exceedingly_ slow on NetBSD. Not helped is using fread(), which assumes a long-lived file and buffers excessively. This change makes the standard gen_entropy tool run in milliseconds instead of seconds when it generates 48K of randomness. Not only that, but sysctl is a lot more robust in e.g. chroots, resource limited processes, etc. Risk: On NetBSD, the security properties of the previous and current behaviour are identical. Upstreamed: Mbed-TLS/mbedtls#3423 Bump PKGREVISION.
This is basically the same as reading from
/dev/urandom
on supported systems, only it has a limit of 256 bytes per call (just to stop programs from spending too much time in the kernel), and does not require an open file descriptor (so it can be used in chroots, when resource limits are in place, or are otherwise exhausted).It's functionally equivalent to the comparable function
getentropy
, but has been around for longer. It's actually used to implementgetentropy
in FreeBSD's libc. Discussions about addinggetrandom
orgetentropy
to NetBSD are still ongoing.Note: this is also much faster than reading from
/dev/urandom
on NetBSD-current (the performance increase may not be as significant on other platforms).time(1)
reports unpatched mbedTLSgen_entropy
as spending 2-3 seconds in the kernel. With this patch applied, that number is 0. The overhead of reopening/dev/urandom
768 times in the process of generating 48K bytes is removed, and the overhead of libc stdio buffering forfread
is removed -- libc is not optimized for repeated short reads on short lived files, so reads far more than necessary and stores it in a buffer.KERN_ARND
is present and works as described in all supported versions of FreeBSD and NetBSD, going back 10 years.