Skip to content
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

Use system random generator in crypto #5798

Closed
speakeasypuncture opened this issue Mar 19, 2016 · 154 comments
Closed

Use system random generator in crypto #5798

speakeasypuncture opened this issue Mar 19, 2016 · 154 comments
Labels
crypto Issues and PRs related to the crypto subsystem. security Issues and PRs related to security.

Comments

@speakeasypuncture
Copy link

randomBytes uses OpenSSL as its random number generator. It would be wiser and less errorprone to use a system RNG like urandom on Unix platforms, getrandom syscall on Linux and CryptGenRandom on Windows.

@mscdex mscdex added crypto Issues and PRs related to the crypto subsystem. feature request Issues that request new features to be added to Node.js. labels Mar 19, 2016
@bnoordhuis
Copy link
Member

Instead of linking to a blog post, please summarize the pros and cons here.

@ChALkeR
Copy link
Member

ChALkeR commented Mar 19, 2016

Perhaps @joepie91 or @paragonie-scott would be interested to elaborate that here.

@paragonie-scott
Copy link

From "a blog post":

Why not {SecureRandom, OpenSSL, havaged, &c}?

These are userspace CSPRNGs. You want to use the kernel’s CSPRNG, because:

  • The kernel has access to raw device entropy.
  • It can promise not to share the same state between applications.
  • A good kernel CSPRNG, like FreeBSD’s, can also promise not to feed you random data before it’s seeded.

Additionally, OpenSSL's userspace PRNG has caused issues in other languages (PHP under Apache for sure) because it's not fork-safe, which caused random numbers to repeat. (Combine this with the consequences of nonce reuse for most stream ciphers and boom your cryptosystem loses all privacy.)

A safer bet would be to adopt what PHP 7's random_bytes() does:
https://github.com/php/php-src/blob/e8f056e535813bf864743626c3a208ceafee70b9/ext/standard/random.c#L83-L186

@bnoordhuis
Copy link
Member

OpenSSL's PRNG is seeded from /dev/{,s,u}random, can get entropy from entropy-collecting daemons, and forking is not an issue for node.js. So far I'm not seeing a compelling reason to switch.

@ChALkeR
Copy link
Member

ChALkeR commented Mar 19, 2016

@paragonie-scott That's does not look like a good reasoning. Could you please be more calm? ;-)

@joepie91
Copy link
Contributor

@bnoordhuis Trying to find specific reasons to explain away potential issues is not a good approach to security-related matters. The issues exist, and there's no way to predict how Node will evolve - for example, if fork-safety might start to matter due to future changes, at which point people will likely have forgotten about this specific issue.

We should be striving for the optimally secure implementation (within technical constraints), instead of attempting to 'defend' the current implementation when there are known edge cases / issues with it.

This post addresses that further.

@ChALkeR
Copy link
Member

ChALkeR commented Mar 19, 2016

I do not yet have a strong opinion on this. I called @joepie91 and @paragonie-scott here because they expressed similar considerations as @speakeasypuncture in an IRC chat earlier.

@bnoordhuis, as I understand their points, the reasons here are:

  1. System PRNG is good for this, is known to be stable and hasn't caused many security issues.
  2. Adding a user-space PRNG of top of that doesn't make it more secure, but it makes it more prone to errors.
  3. OpenSSL isn't actually a very high code quality product.
  4. Using OpenSSL PRNG caused serious security issues for some projects, namely for Debian, Android and PHP (that latter is still not fixed, btw), though that was mostly their fault. Those issues are not directly applicable to Node.js, but this gives an uneasy feeling.
  5. There seems to be no reason not to ditch OpenSSL PRNG and reduce the possible errors.

Everyone — did I miss anything?

@ChALkeR ChALkeR added the security Issues and PRs related to security. label Mar 19, 2016
@ChALkeR
Copy link
Member

ChALkeR commented Mar 19, 2016

Again: I do not yet have a strong opinion on this.

I would like to hear what would the drawbacks of this change be, and is there something where (or why) OpenSSL PRNG could be better than the system PRNG.
Excluding the fact that it's already used, of course — that also isn't a good enough argument, this won't even be a semver-major change. It's not documented that crypto.randomBytes() uses OpenSSL.

@ChALkeR
Copy link
Member

ChALkeR commented Mar 19, 2016

/cc @nodejs/crypto.

@ChALkeR
Copy link
Member

ChALkeR commented Mar 19, 2016

@mscdex I'm not sure if this is a «feature request», it looks like a proposal to change the implementation of crypto.randomBytes() to me.

@joepie91
Copy link
Contributor

@ChALkeR Your summary seems accurate to me.

@paragonie-scott
Copy link

Also, random number generators are hot-swappable without compatibility concerns, only security concerns.

@indutny
Copy link
Member

indutny commented Mar 20, 2016

I'm -1 on this, no compelling reasons for me.

@joepie91
Copy link
Contributor

@indutny Please refer back to this comment in particular, plus several others in the thread. There is a lack of reasons not to do this (insofar anybody has stated them, that is), while there are documented reasons to do it.

If you feel that there is a reason not to do it, then please share it - but "no compelling reasons for me" really isn't a sufficient argument for a security-related matter. Even a small defect can have disastrous consequences.

@indutny
Copy link
Member

indutny commented Mar 20, 2016

@joepie91 sure, sorry for too short reply.

What about systems with "good" PRNG? How many of them are there? Do we have to carry both implementations to support them?

@joepie91
Copy link
Contributor

@indutny Thanks for the elaboration.

As I understand it (and please correct me if not), OpenSSL depends on the system PRNG to begin with. I'm not aware of any platforms (of those supported by Node, that is) where OpenSSL can provide a better PRNG than the one that the system offers natively.

It should thus be possible to just remove OpenSSL's PRNG from the equation entirely, and rely purely on the system PRNG, as PHP has done.

@indutny
Copy link
Member

indutny commented Mar 20, 2016

@joepie91 do you suggest to use this randomness for TLS protocol as well? I'm not sure if it is possible, though.

@joepie91
Copy link
Contributor

While that would probably be nice (albeit requiring more investigation), I don't think that's doable. As far as I know, OpenSSL's other functionality relies internally on its own PRNG with no ability to change that - unless we want to get rid of OpenSSL entirely, which would be a separate proposal (and likely not viable at this stage, given the lack of well-tested alternatives).

So, this specific proposal would concern the "user-facing" randomBytes method only.

@indutny
Copy link
Member

indutny commented Mar 20, 2016

Ok, considering arguments it probably make more sense now.

@bnoordhuis
Copy link
Member

Here's a reason not to switch: OpenSSL's PRNG is a known quantity, the strength of platform-specific PRNGs is not. If the next Windows or FreeBSD release has a flawed PRNG, that will compromise node.js.

If (generic) you think moving to platform-specific solutions is the way forward, get OpenSSL to adopt your approach and node.js will automatically go along. I believe @paragonie-scott is volunteering? He sure seems to feel strongly about it.

if fork-safety might start to matter due to future changes, at which point people will likely have forgotten about this specific issue.

@joepie91 The bucket list of fork-safety issues that would have to be addressed is so long that I think it's safe to say that node.js will never be fork-safe. There are many things that keep me awake at night but this is not one of them.

@alfiepates
Copy link

If the next Windows or FreeBSD release has a flawed PRNG, that will compromise node.js.

I don't believe this argument holds any merit, honestly.

~FreeBSD are not just going to push broken code~~ EDIT: FreeBSD are not going to push broken code to the -STABLE kernel branch, especially when they have a perfectly functional CSPRNG already, and especially as they have a security team of their own who would definitely catch any changes to the CSPRNG which would lead to a vulnerability in the OS.

I'm going to be frank, here: Attempting to justify away security issues is downright irresponsible, and possibly dangerous. You need to strive for bulletproof security, or you may as well not implement any security at all (And no, don't twist this to mean "Don't bother with security", because that's just lazy.)

I appreciate it's "extra work" to make a change like this, but considering you're using a PRNG which has actually caused security issues in the past, I'd err on the safe side and move to something more provably secure.

@bnoordhuis
Copy link
Member

as they have a security team of their own who would definitely catch any changes to the CSPRNG which would lead to a vulnerability in the OS

Besides being an appeal to authority, you're asking (generic) me to trust several teams of implementors (the platforms) instead of just one (OpenSSL) to get their implementation right.

considering you're using a PRNG which has actually caused security issues in the past

Are you saying you feel OpenSSL's PRNG is insecure? If so, why aren't you taking that up with the OpenSSL team? Griping about it here isn't going to do any good.

I'll repeat what I've said above: get the upstream project to move over, and we as downstream consumers will automatically move along with it.

@joepie91
Copy link
Contributor

Here's a reason not to switch: OpenSSL's PRNG is a known quantity, the strength of platform-specific PRNGs is not. If the next Windows or FreeBSD release has a flawed PRNG, that will compromise node.js.

Yet OpenSSL's PRNG relies on these platform-specific PRNGs, and mixing in one broken PRNG can weaken the entire (combined) PRNG. How does relying on OpenSSL fix the issue you've described?

The bucket list of fork-safety issues that would have to be addressed is so long that I think it's safe to say that node.js will never be fork-safe. There are many things that keep me awake at night but this is not one of them.

That is a very dangerous assumption to make.

f so, why aren't you taking that up with the OpenSSL team?

I think the existence of this project should give an indication. At this stage, there's a fairly wide consensus around the security community that OpenSSL is awful software, and the only real reason it is still being recommended is because it's what has been tested in the real world for so long. Not because it is of high quality or well-maintained.

@ChALkeR ChALkeR added the discuss Issues opened for discussions and feedbacks. label Mar 20, 2016
@paragonie-scott
Copy link

@bnoordhuis:

Here's a reason not to switch: OpenSSL's PRNG is a known quantity, the strength of platform-specific PRNGs is not. If the next Windows or FreeBSD release has a flawed PRNG, that will compromise node.js.

This is a common argument that people make, but it's ultimately invalid.

Even if you avoid depending on the operating system's PRNG, the rest of your system definitely depends on it for security. Node.js will be compromised regardless of what Node.js does.

@indutny
Copy link
Member

indutny commented Mar 20, 2016

Just a bit of FYI for everyone here:

http://lwn.net/Articles/633805/rss

"FreeBSD random number generator broken for last 4 months"

@ChALkeR
Copy link
Member

ChALkeR commented Mar 20, 2016

@indutny Note that it also affects keys generated by Node.js on FreeBSD (using crypto.randomBytes()):

This includes, but not limited to, ssh keys and keys generated by openssl.

@technion
Copy link

Any changes to OpenSSL, even if they improve in this space, are going to show up on a new major release, which moves much, much slower than Node. If they made a great release tomorrow, it will take years to hit some distributions at all. I don't feel you want to wait on this.

@Trott
Copy link
Member

Trott commented May 31, 2017

If they made a great release tomorrow, it will take years to hit some distributions at all.

Node.js doesn't use the operating system's OpenSSL. Node.js ships with its own copy of OpenSSL.

@bnoordhuis
Copy link
Member

I might be open to bundling libsodium in addition to openssl but that should be its own issue because there will be numerous details to hash out.

We sure as heck are not going to ship something homegrown and until openssl grows the requisite APIs there isn't anything actionable. I'm closing this again and I'm locking it to prevent this already humongous thread from growing bigger.

@nodejs nodejs locked and limited conversation to collaborators May 31, 2017
@ChALkeR
Copy link
Member

ChALkeR commented Jun 1, 2017

@MylesBorins Re: FIPS compliance — if libsodium randombytes.c is not compliant and if FIPS compliance is desired, that could be fixed with a runtime flag that switches back the impl to OpenSSL (as we won't stop bundling OpenSSL nevertheless). Also, see this link.

@sam-github
Copy link
Contributor

Note that openssl 1.1 won't be FIPS compliant for quite a while, so FIPS users will need to stick to a node built on 1.0. cf. https://www.openssl.org/blog/blog/2016/07/20/fips/

I'm still hopeful that OpenSSL will deal with this for us, I'm not saying we should be thinking of libsodium for 8.x, but I don't think FIPS would be a blocker if we go looking elsewhere for a PRNG. Also, I'm not sure random seeds are covered by FIPS, anyway, that would take some looking into.

@ChALkeR ChALkeR removed the ctc-agenda label Jun 7, 2017
@mhdawson mhdawson reopened this Jun 8, 2017
@nodejs nodejs unlocked this conversation Jun 8, 2017
@shigeki
Copy link
Contributor

shigeki commented Aug 3, 2017

Note that OpenSSL has just landed a commit to use DRGB with AES-CTR of NIST SP 800-90A as openssl/openssl@75e2c87. We can use it with the os-specific seeding source (e.g. /dev/urandom) by a default define flag of OPENSSL_RAND_SEED_OS.
I think it is best for us to wait for the next release of OpenSSL-1.1.1.

saghul added a commit to saghul/libuv that referenced this issue Aug 15, 2017
@Trott Trott removed the discuss Issues opened for discussions and feedbacks. label Mar 11, 2018
@davisjam
Copy link
Contributor

davisjam commented Mar 13, 2018

[Edited arguments for and against based on feedback]

I'm going to attempt to summarize the conversation and arguments that have happened on this issue. Sorry if I missed your post, I can amend.

Preliminaries

@speakeasypuncture initially opened this issue.
Per @joepie91, this issue is about Node's crypto.randomBytes. (Statement).

Issue statement

Node's crypto.randomBytes may not be cryptographically secure.

  • Operating systems expose a "system" RNG (Cryptographically Secure Pseudo-Random Number Generator or CSPRNG) which offers the best source of randomness on the system.
  • Rather than use the system RNG, Node.js relies on OpenSSL for crypto.randomBytes.
  • OpenSSL can be no more secure than the system RNG, and may be less secure. OpenSSL's use of a user-space CSPRNG on top of the kernel's CSPRNG is unnecessary and simply adds a layer of vulnerability.

I do not believe anyone has claimed that OpenSSL's CSPRNG is currently broken, although @ChALkeR pointed out some reasons why it might not be trustworthy.

Proposal

Node should consider an alternative implementation for random numbers that is definitely derived securely.

  1. @azet says that libsodium is a better option for random numbers than OpenSSL is, because libsodium underwent a review.
  2. @FiloSottile here and @ircmaxell here add that avoiding reliance on a user-space CSPRNG, whether derived from a kernel CSPRNG or not, would reduce Node's attack surface.

Arguments against

The major arguments from the Node maintainers (and I may be reading between the lines a little bit) appear to be:

  • @bnoordhuis here and @sam-github here: if Node's security is broken because of issues in OpenSSL, it seems like the right answer is to pursue enhancements to OpenSSL. @shigeki here says that efforts along these lines are underway.
  • Code inertia. The OpenSSL-based implementation works. Changing the implementation to one derived from another library means investing time and energy into development and maintenance.

Peer pressure

My impressions

  • This proposal seems unlikely to result in motion from the Node maintainers until the OpenSSL API is available.
  • It seems like adopting libsodium would lead to unnecessary code churn because the OpenSSL API is on its way, albeit perhaps slowly.
  • In the interim, if security-conscious developers don't trust OpenSSL, they can use an npm module or an add-on that accesses platform-specific sources of randomness directly.

@paragonie-scott
Copy link

paragonie-scott commented Mar 13, 2018

There's an upstream proposal to make OpenSSL create the equivalent of libsodium's randombytes_sysrandom() (which uses the OS's CSPRNG) which Node could then use instead of the userspace PRNG. This isn't close-worthy, it's stalled until OpenSSL does something.

Swapping out one userspace PRNG for another userspace PRNG is not a fix. Bypassing the userspace and using the OS's CSPRNG is the solution.

@Trott Trott added stalled Issues and PRs that are stalled. and removed stalled Issues and PRs that are stalled. labels Mar 13, 2018
@bnoordhuis
Copy link
Member

This isn't close-worthy, it's stalled until OpenSSL does something.

It's not actionable at the moment and won't be for a long time to come. Inactionable items clog up the bug tracker so I'll close this out for now. We can revisit when we upgrade to an openssl version that supports this new API.

@ChALkeR
Copy link
Member

ChALkeR commented Mar 13, 2018

@bnoordhuis How are we going to remember to revisit it, then?

Perhaps introducing a separate label for temporary-inactionable items that were closed just because of that is needed so we don't forget to revisit?

@bnoordhuis
Copy link
Member

We go over the changelog with a fine-tooth comb whenever we upgrade (at least I do) so it's unlikely that such a change would go unnoticed.

Perhaps introducing a separate label for temporary-inactionable items that were closed just because of that is needed so we don't forget to revisit?

I'm not completely opposed.

@FiloSottile
Copy link

Thanks for summarizing, but I don't think that captures the point. We are not advocating for reimplementing something that's in a library (for whatever reason), but for removing the library entirely. The library implements a user-space CSPRNG on top of kernel entropy, it might be good or bad, doesn't matter, we are arguing for not using one at all.

What you say is valid about primitives, which have to be implemented somewhere, but here we are talking about removing a layer from a system, where each layer is an independent point of failure.

As for "they are the ones that know about security", OpenSSL is bound by a lot of legacy, BoringSSL and libsodium are widely regarded as secure modern implementations, and those use the kernel CSPRNG.

@davisjam
Copy link
Contributor

@FiloSottile Thanks, I've amended my post. Holler if you're still unhappy with my representations.

@atoponce
Copy link

What's the current status with this issue?

@technion
Copy link

@atoponce I could well have made a mistake somewhere, but tracing randomBytes appears to land here:

https://github.com/nodejs/node/blob/f69a4f61b2c133878159a9573ac438d58f8a05ac/src/crypto/crypto_random.cc

In which we first call RAND_status and then RAND_byes, these being OpenSSL functions.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
crypto Issues and PRs related to the crypto subsystem. security Issues and PRs related to security.
Projects
None yet
Development

No branches or pull requests