nodejs / node

Node.js JavaScript runtime ✨🐢🚀✨
https://nodejs.org
Other
105.5k stars 28.62k forks source link

Use system random generator in crypto #5798

Closed speakeasypuncture closed 6 years ago

speakeasypuncture commented 8 years ago

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.

azet commented 8 years ago

EGD the protocol is implemented by several programs that collect or distribute entropy, e.g., low-entropy VMs that get their initial state from a hardware RNG on the network.

Can you please add a reference to that statement? What are you exactly referring to?

Indeed it is not. OpenSSL not being fork-safe is not relevant because node doesn't fork.

Have you read further down? My point being node builds on libuv, libuv uses threads, OpenSSL is not thread safe. Also it's rather easy to produce a fork bomb with node using spawn() in detached mode.

Context is everything. The code you pasted seeds V8's Math.random() and the hash table seed. If you thought it had anything to do with the crypto module - it does not.

Context? The code I pasted has a comment above it saying it uses /dev/urandom why would it seed from Math.random()? That's insane given it's your core crypto interface. I'm referring to https://github.com/nodejs/node/blob/master/src/node_crypto.cc#L268-275 - if this is not your entropy source, where is it?

If node didn't override the defaults, V8 will try to open /dev/urandom but happily continues with almost zero entropy if it fails - which, per the contract of Math.random(), is perfectly acceptable.

I do not understand this sentence. And /dev/urandom does not block nor does "run out of entropy" in any sense that's relevant to security for nodejs.

Knowing what you know now, wouldn't you agree that OpenSSL's RNG is better?

No. Take a look at libsodium.

Seeding from /dev/urandom (and /dev/random and /dev/srandom) is exactly what OpenSSL does. Why then do you consider it so broken?

Because it does not stop there, it seeds from it then mixes in "entropy" from user-land that can easily be tampered with, hence producing predictable output. See the very last link in my previous comment. There're many other examples.

I've commented on that before but to reiterate: that doesn't help while we still support 2.6.18 and 2.6.32. Performance regressions on older kernels are not acceptable.

I absolutely agree there. These are patches being worked on right now, they won''t be around for a while. Can you explain which performance regressions you're experiencing on older kernels specifically?

I'd appreciate it if you could back up that claim with names and places. I've never heard any of the OpenSSL developers publicly state that.

I have not done so on purpose, I thought that was obvious. Why do you think both LibreSSL and BoringSSL (now powering all of Google, including desktop applications [e.g. Chrome] et cetera) have switched to other RNG designs?

bnoordhuis commented 8 years ago

OpenSSL is not thread safe

This is wrong.

Also it's rather easy to produce a fork bomb with node using spawn() in detached mode.

Irrelevant. Why do you even bring it up?

Context? The code I pasted has a comment above it saying it uses /dev/urandom why would it seed from Math.random()?

I think you should go back and read what I wrote again (hint: not 'from'.) Please put more effort in your replies, will you?

Because it does not stop there, it seeds from it then mixes in "entropy" from user-land that can easily be tampered with, hence producing predictable output.

Can you explain? If by 'tamper' you mean 'attach with ptrace', then predictable output is the least of your worries. If you mean 'exploitable program bugs', the kernel is no stranger to that either.

Can you explain which performance regressions you're experiencing on older kernels specifically?

Try reading from /dev/urandom from multiple processes simultaneously and you'll see what I mean. It's slow - very slow - and can have a dramatic impact on overall system performance, not just the readers.

I have not done so on purpose, I thought that was obvious.

I hope you understand I won't be able to just take your word for it.

paragonie-scott commented 8 years ago

This is getting nonproductive, fast.

I have a lot of work on my plate right now, but once it's done, expect a patch so we can stop discussing the theoretical realm.

The patch I'm envisioning will do exactly what libsodium 1.0.11 and newer (not yet released) does:

ChALkeR commented 8 years ago

@azet Several corrections, to clear misunderstanding here:

  1. Not OpenSSL is not thread-safe, but some parts of it (including the random number generator).
  2. The fact that node uses libuv, that libuv has a thread pool, and that node uses OpenSSL RAND_bytes() for crypto.randomBytes() does not imply that calls to crypto.randomBytes() are performed from the thread pool.

Update: I have made a mistake here, see explanation below: https://github.com/nodejs/node/issues/5798#issuecomment-222373530.

ChALkeR commented 8 years ago

@paragonie-scott Thanks. I'm not sure though about pulling in the platform abstraction here instead of a dependency (openssl or libuv, for example). Also, what you proposed is going to affect speed, and may cause significant performance drop on Linux, which is bad even from the security side. Perhaps we will need tests, though.

azet commented 8 years ago

@bnoordhuis

This is wrong.

No it is not. Which version of OpenSSL is nodejs using? git-master? Take a look at the commit history in general from the RNG in question: https://github.com/openssl/openssl/commits/master/crypto/rand/md_rand.c

The new threading API was added to 1.1.0-pre5 on 8th of march this year: https://github.com/openssl/openssl/commit/8eed7e873bb54ab46b15e6efa3aff416e02f4d7f

Before that you had to explicitly call CRYPTO_set_locking_callback something I'm unaware node is doing w.r.t. to the OpenSSL RNG. Maybe I'm missing something?

I think you should go back and read what I wrote again (hint: not 'from'.) Please put more effort in your replies, will you?

So it seeds from urandom and mixes into Math.random()? That's still a completely unacceptable design.

Try reading from /dev/urandom from multiple processes simultaneously and you'll see what I mean. It's slow - very slow - and can have a dramatic impact on overall system performance, not just the readers.

I'm aware /dev/urandom is currently slow. That's not the point. As suggested previously: take a look at libsodium it only uses random/urandom as a seed. Newer OpenSSL releases have improved a lot, but a lot of sytems do not ship bleeding edge releases.

I hope you understand I won't be able to just take your word for it.

Sure. Again: look at their commit log, those of BoringSSL et cetera. I'm not going to name devs. - it doesn't even matter, development and changes are public.

BTW: I'm still waiting for an answer on EGD - I'm not sure what you mean.

azet commented 8 years ago

@ChALkeR

The fact that node uses libuv, that libuv has a thread pool, and that node uses OpenSSL RAND_bytes() for crypto.randomBytes() does not imply that calls to crypto.randomBytes() are performed from the thread pool.

Thanks for the information. So how does it work if multiple child processes want to read from crypto.randomBytes()?

indutny commented 8 years ago

@azet each child process starts from scratch without sharing anything except an possibly std input/outputs. So it just seeds the entropy from the kernel's RNG.

technion commented 8 years ago
// The only time when /dev/urandom may conceivably block is right after boot,
// when the whole system is still low on entropy.  That's not something we can
// do anything about.

Regardless of the rest of the discussion, this is objectively wrong. /dev/urandom does not block. I'm loathe to refer to the generally poor man page, but from random(4):

A read from the /dev/urandom device will not block waiting for more entropy.  If there is not sufficient entropy, a pseudorandom number generator is used to create the requested bytes
paragonie-scott commented 8 years ago

/dev/urandom never blocking is only a problem for programs that can run during the Linux kernel's boot process and embedded devices. There are two solutions to this:

  1. If getrandom(2) is available, use it and forsake urandom. This does the correct thing: Blocks until there's enough entropy is available, then never blocks again. It's also immune to file descriptor exhaustion, making it the preferred solution.
  2. Poll /dev/random until it's available, and then read from /dev/urandom forever more. Linux seeds the unblocking entropy pool (urandom) before the blocking pool. This means once you can successfully poll /dev/random, then /dev/urandom has been seeded with at least 128 bits of entropy. You may then safely read from urandom without a care in the world.

It's never acceptable to read from /dev/random and use something hacky like egd or haveged to "feed entropy" into the system.

azet commented 8 years ago

@indutny

each child process starts from scratch without sharing anything except an possibly std input/outputs. So it just seeds the entropy from the kernel's RNG.

Thanks for the explanation, and I've tested this on a 12core/2thread, 128GB machine over night. And it seems to be fine given a recent and well maintained OpenSSL release (debian jessie). BTW the only reason this is the case - as far as I can tell - is that commit https://github.com/openssl/openssl/commit/3cd8547a2018ada88a4303067a2aa15eadc17f39 has been added in 2013 to mitigate a problem on Android. With earlier releases it may still have been possible to exploit the PID-overlap issue and non-existent thread safety in the RNG, if I'm not mistaken.

The thing is, as explained before, as per your seeding mechanism, if RAND_bytes returns anything but -1 (i.e. 0 for low entropy or e.g. a broken userland RNG state) - if I understand @bnoordhuis correctly - the fallback would be a seed from urandom that mixes into Math.random() which is a completely unacceptable design, and predictable, it doesn't matter that the seed was of good quality in this case. You just accept the broken RNG state instead, which is completely insane as well.

@technion

Regardless of the rest of the discussion, this is objectively wrong. /dev/urandom does not block.

I agree.

@paragonie-scott

/dev/urandom never blocking is only a problem for programs that can run during the Linux kernel's boot process and embedded devices.

Unless you're planning on runnning node in initramfs there's really no reason to think about that. As for embedded devices: it largely depends, this is usually manufacturer error. They still have noise sources and interrupts, someone just forgot to configure the kernel properly or submit a patch. In any case this is nothing that node itself can do about, it's a proper upstream problem. I don't like the polling idea, getrandom(2) is perfectly fine as it's the new interface on Linux but as such: it's not available everywhere. Instead of writing your own solution I'd suggest importing sysrandom from libsodium. This is vetted code that works.

It's never acceptable to read from /dev/random and use something hacky like egd or haveged to "feed entropy" into the system.

Exactly. And I'm thus not sure what @bnoordhuis is referring to. All these have been deprecated, the OpenSSL interface is ancient and their support for it has been dropped.

paragonie-scott commented 8 years ago

Instead of writing your own solution I'd suggest importing sysrandom from libsodium. This is vetted code that works.

Agreed. I previously ported a significant chunk of libsodium's sysrandom to PHP 7's random_bytes(). I was intending to do the same thing here.

ChALkeR commented 8 years ago

@azet Btw, I made a mistake in the comment above. Requests to RAND_bytes are indeed coming from the thread pool if callback is specified. However, OpenSSL rng is not thread-safe only unless thread safety is ensured with CRYPTO_set_locking_callback (see https://wiki.openssl.org/index.php/Random_Numbers#Thread_Safety), and some more bits. Node.js is doing those since https://github.com/nodejs/node/commit/97cada0e6a130791ceafaa750f9009d8fdaaadbb.

Also, OpenSSL RAND_bytes is not fork-safe, but that doesn't affect us, because Node.js doesn't fork, it runs new instances.

eozu commented 8 years ago

A little late to the party, but if this helps, the folks over at Chromium had a similar discussion regarding the CSPRNGs. If I read it correctly, they dropped OpenBSD's RC4/ARC4 for kernel-space sources.

The current implementation (as clarified here) appears to grab hardware-based entropy – if available – before reverting to standalone urandom. Specifically, it tests for the presence of RDRAND Intel's Digital Random Number Generator (DRNG), and if available, combines it with urandom and ChaCha20.

I think this is similar to what @paragonie-scott is aiming to patch, but I'm unsure if the RC4 flaws have been addressed?

Thank you all for doing your best to keep us secure. 👍

Edit: Intel no longer calls it RDRAND for various reasons. ;)

ChALkeR commented 7 years ago

Looks like Linux urandom will now be ChaCha20-based: http://lkml.iu.edu/hypermail/linux/kernel/1607.3/00275.html

ChALkeR commented 7 years ago

(Loosely related): yet another userspace prng has falled down: https://lists.gnupg.org/pipermail/gnupg-announce/2016q3/000395.html

ChALkeR commented 7 years ago

/cc @saghul — would something like https://github.com/nodejs/node/issues/5798#issuecomment-222329062 make sense in libuv?

saghul commented 7 years ago

@ChALkeR I think it would. Moreover, I was planning on doing it myself, since I implemented a similar thing for another project not so long ago.

The key will be documenting what guarantees we promise. I'll try to make a quick stub this week to ge the conversation started over there.

saghul commented 7 years ago

Not 100% ready yet, but feedback is more than welcome: https://github.com/libuv/libuv/pull/1055

sam-github commented 7 years ago

For those that believe Linux's /dev/urandom can have no security issues: https://www.schneier.com/blog/archives/2013/10/insecurities_in.html (and others).

I haven't seen a single compelling reason in this thread to switch away from OpenSSL's PRNG, its a platform abstraction layer on top of platform-specific entropy sources... seems like exactly what we want.

Also, its easy to complain about some kind of perceived "low quality" of OpenSSL - but suggesting that the Node.js team has a better cryptographic background than their devs, and that we should be writing our own PRNG abstraction layer is a bit tenuous, IMO. We certainly wouldn't get the scrutiny that they do.

paragonie-scott commented 7 years ago

For those that believe Linux's /dev/urandom can have no security issues: https://www.schneier.com/blog/archives/2013/10/insecurities_in.html (and others).

That's not the argument, at all. The argument is this:

  1. Your entire operating system already depends on the kernel's CSPRNG (e.g. /dev/urandom) to be secure. If that's insecure, your entire system is hosed.
  2. Adding a second userspace PRNG doesn't create defense-in-depth against the failure of the OS's CSPRNG, it just creates an additional point of failure.
  3. Given that OpenSSL's userspace PRNG has a lot of problems (i.e. isn't fork-safe, which screwed over the security of PHP applications that depended on its PRNG), there's more urgency to get off of a userspace PRNG in favor of the kernel's CSPRNG than if it were a better-designed userspace PRNG.

That's a very different argument than "there will never be a /dev/urandom flaw".

Several security experts have chimed in on this thread. The consensus is unanimously in favor of using the kernel's CSPRNG over OpenSSL's userspace PRNG.

I haven't seen a single compelling reason in this thread to switch away from OpenSSL's PRNG

I linked several research papers above. Did you read through them all?

its a platform abstraction layer on top of platform-specific entropy sources... seems like exactly what we want.

If that were true, there'd be no complaint. But that's not what's going on under the hood. OpenSSL's RAND_bytes() seeds itself with 32 bytes from urandom, then maintains its own internal PRNG state (mixed with SHA1 by default, but the code supports mixing with MD5) and never touches the kernel's CSPRNG again.

What you want is something like libsodium's sysrandom. @bascule previously wrote a Ruby gem, called sysrandom, which is a secure replacement for Ruby's SecureRandom (misnomer, also uses OpenSSL).

I've written about this in a blog post appropriately titled, How to Generate Secure Random Numbers in Various Programming Languages.

Also, its easy to complain about some kind of perceived "low quality" of OpenSSL - but suggesting that the Node.js team has a better cryptographic background than their devs, and that we should be writing our own PRNG abstraction layer is a bit tenuous, IMO.

You're right. We should just use libsodium's, which does the job better than any other implementation I've seen.

We certainly wouldn't get the scrutiny that they do.

Until last year, I'd have taken this as tongue-in-cheek, with Heartbleed and whatnot.

sam-github commented 7 years ago

Adding a second userspace PRNG doesn't create defense-in-depth against the failure of the OS's CSPRNG, it just creates an additional point of failure.

User-space gives defence against locking problems in urandom, as you have been told, and is one of the objections to OpenSSL itself shifting over to direct read of urandom.

A well-constructed PRNG cannot magically add entropy, but neither does it magically subtract.

Node implementing its own platform abstraction for entropy also adds an additional point of not-well-reviewed failure, so this point is not compelling without demonstrating that OpenSSL currently has security flaws that effect node and need to be fixed by bypassing it.

Given that OpenSSL's userspace PRNG has a lot of problems (i.e. isn't fork-safe, which screwed over the security of PHP applications that depended on its PRNG), there's more urgency to get off of a userspace PRNG in favor of the kernel's CSPRNG than if it were a better-designed userspace PRNG.

Irrelevant, node doesn't fork, why do people keep bringing this up?

Are there other, relevant, criticisms?

Several security experts have chimed in on this thread.

You should keep in mind that it is impossible in this thread to distinguish between security experts, and people just playing them on the internet. Also that security experts are contributors to OpenSSL.

Who do you think are security experts, and why?

Trott commented 7 years ago

Aside: Assuming we're not already doing so, it might be a good idea to add the sodium package to our CITGM runs. Doesn't seem to get a ton of usage, but a decent amount, and it seems like exactly the kind of thing that might help us find some unusual corner cases. (Plus, I'm sure we'd be doing the maintainers a favor if we identified either unusual platforms where the module does not work or notified them ahead of time that an upcoming Node.js release is going to break their package.) /ping @TheAlphaNerd

paragonie-scott commented 7 years ago

Who do you think are security experts, and why?

In no particular order:

Additionally, there are plenty of people I consider colleagues worth mentioning because:

  1. They research these topics
  2. If I'm wrong, they'll say so

And so the list expands to include:

Feel free to ask anyone on that list if they'd prefer OpenSSL's userspace PRNG or the operating system kernel's CSPRNG for cryptography purposes. I guarantee you'll get 100% in favor of urandom (and urandom equivalent).

Feel free to try to find cryptographers and real world security experts to offer a dissenting opinion. By and large, you'll be more successful at finding folks who agree with me than disagree with me (only on this particular point).

paragonie-scott commented 7 years ago

(Corrected a mistake in my previous comment and wanted to make it known that there are probably about 50 - 100 other people I could have listed there too, but the list is plenty long enough.)

sam-github commented 7 years ago

OK, I also got the opinions of someone I know to be a security expert (the requirement is a successful track record of breaking systems), and they agree with you (and know you): current best practice is direct read from O/S entropy sources.

Whether that is best for Node.js though, is not as clear, there are other factors to consider.

  1. Is it proposed to only modify crypto.randomBytes(), or to also replace the entropy source used during SSL/TLS exchanges by OpenSSL? If we don't make OpenSSL/Node.js's HTTPS implementation bypass the user-space PRNG, then we aren't getting a win for Node.js's common use-cases.
  2. Following on to that... if OpenSSL changes upstream to do direct read (as they seem to have an interest in doing)... then we can take advantage of that for both HTTPS, and crypto.randomBytes() with zero work (other than an OpenSSL update).
  3. Performance remains a concern. In the absence of a current vulnerability in OpenSSL, we would be gaining a theoretical security advantage, but losing actual performance. This should be addressed. Perhaps by convincing ourselves that HTTPS performance is not impacted, and crypto.randomBytes() isn't used enough for us to care (or notice).
  4. Maintenance remains a concern. If Node takes on the burden of maintaining an abstraction layer for system entropy collection, our abstraction code could become the new weakest link in the chain of randomness. Whereas if we push that up to OpenSSL (or even libsodium), we can benefit from their work. Bringing in an entire new sub-dep (libsodium) is a heavy price to just remove a theoretical problem.
paragonie-scott commented 7 years ago

1, 2, and 4: RAND_system_bytes() is not implemented as of 1.1.0 (which was just released), and we'll be waiting for a while until 1.2.0 comes out. But fixing it in OpenSSL rather than in each language would be the ideal solution.

3: If the two are in conflict, security should take precedence over performance when it comes to cryptography. However, a significant performance penalty just invites DoS attacks (which is a security problem). So I agree, this should be addressed.

Fixing the issue upstream would be the best solution (since it'd pay forward to lots of programming languages), but in the absence of an upstream solution, what do we do?

A. Keep using a userspace PRNG and not exposing an alternative CSPRNG interface? B. Fix it at the interpreter layer, like PHP did?

That's for the Node team to decide. I'm jumping over the OpenSSL repository to discuss getting a patch ready to expose this API in the next version.

saghul commented 7 years ago

I'd like to clarify that while libuv might get this API I didn't implement it with this issue in mind. Node need not use it.

Moreover, even if the libuv patch lands tomorrow (which will not happen anyway) it's targeted at master, not v1.x. That means that in principle it will be part of libuv 2.0. This is intentional, so we have a bit more leeway to make changes should issues be discovered with the implementation.

On Sep 16, 2016 23:52, "Scott" notifications@github.com wrote:

1, 2, and 4: RAND_system_bytes() is not implemented as of 1.1.0 (which was just released), and we'll be waiting for a while until 1.2.0 comes out. That would be the ideal solution.

3: If the two are in conflict, security should take precedence over performance when it comes to cryptography. However, a significant performance penalty just invites DoS attacks (which is a security problem). So I agree, this should be addressed.

Fixing the issue upstream would be the best solution (since it'd pay forward to lots of programming languages), but in the absence of an upstream solution, what do we do?

A. Keep using a userspace PRNG and not exposing an alternative CSPRNG interface? B. Fix it at the interpreter layer, like PHP did?

That's for the Node team to decide. I'm jumping over the OpenSSL repository to discuss getting a patch ready to expose this API in the next version.

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/nodejs/node/issues/5798#issuecomment-247717511, or mute the thread https://github.com/notifications/unsubscribe-auth/AATYGKYZE_uzOGuvyEgLZUs257XOxBJyks5qqw-UgaJpZM4H0YGk .

joepie91 commented 7 years ago

@sam-github: Is it proposed to only modify crypto.randomBytes(), or to also replace the entropy source used during SSL/TLS exchanges by OpenSSL? If we don't make OpenSSL/Node.js's HTTPS implementation bypass the user-space PRNG, then we aren't getting a win for Node.js's common use-cases.

I just want to point out here that there are plenty common non-HTTPS usecases for crypto.randomBytes in Node - from UUID generation, to other (non-OpenSSL) crypto implementations, to lottery-type random-number-picking, and so on. Even if the problem would remain unsolved for HTTPS, there'd still be a clear win in other areas.

co60ca commented 7 years ago

To @joepie91 I've seen a implementation of UUID v4 use math.random so yes, a secure default that pulls from system entropy would be fantastic.

atoponce commented 7 years ago

As another example of using crypto.randomBytes() in a non-HTTPS setting, I am using it in a password generator: https://github.com/atoponce/nodepassgen.

jasnell commented 7 years ago

ping @nodejs/crypto ... should this remain open?

bnoordhuis commented 7 years ago

No, let's close.

azet commented 7 years ago

this issue remains unfixed and there has been valuable discussion on resolving the problem. similar issues in e.g. ruby proper lead to switch to libsodium-like approaches: https://bugs.ruby-lang.org/issues/9569

OpenSSL's implementation remains, to my knowledge, largely untested and specifically optimized to cater to TLS implementation's needs for fast random numbers. most languages (e.g. python) opt to use the /dev/urandom device on Linux distributions. libsodium is platform aware and spares the overhead of fiddling and maintaining distribution specific code-paths. libsodium has also been reviewed and is used by a lot of people and projects to provide a layer of abstraction for obtaining cryptographically secure pseudo random numbers.

I urge the core team to use libsodium's reviewed, platform-aware way to obtain secure pseudo random numbers: https://github.com/jedisct1/libsodium/blob/master/src/libsodium/randombytes/randombytes.c

please re-open this security relevant issue.

tarcieri commented 7 years ago

What was the rationale for closing this issue?

Trott commented 7 years ago

If I understand correctly (which is a big "if" when it comes to cryptography and related issues):

Especially given activity on https://github.com/openssl/openssl/issues/898 fairly recently, and that progress there could mean a suitable fix here that can still use OpenSSL APIs, I'd be for keeping this open.

sam-github commented 7 years ago

@nodejs/crypto I think we should keep it open until its fixed. Last discussion was that OpenSSL were themselves moving this direction, and we hoped to simply inherit their fix. From https://github.com/openssl/openssl/issues/898, it does indeed look like they are moving along (slowly, but with recent progress). But if OpenSSL 1.1 doesn't change this, we could revisit whether node should use some other way of getting pseudo-random.

MylesBorins commented 7 years ago

As a handful of people (including collaborators) have chimed in about wanting to continue the discussion. I'm reopening

That being said I think this might be part of a larger conversation about openssl... perhaps we can look into improving their implementation on systems that have support?

afaict libsodium is going to be a nonstarter if it doesn't have fips support

paragonie-scott commented 7 years ago

afaict libsodium is going to be a nonstarter if it doesn't have fips support

Replacing OpenSSL entirely with Libsodium might be a nonstarter.

Is FIPS-140-2 compliance an absolute mandatory requirement? Because ECB mode is FIPS compliant, and you sure as hell don't want people encrypting that way.

technion commented 7 years ago

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 commented 7 years ago

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 commented 7 years ago

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.

ChALkeR commented 7 years ago

@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 commented 7 years ago

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.

shigeki commented 6 years ago

Note that OpenSSL has just landed a commit to use DRGB with AES-CTR of NIST SP 800-90A as https://github.com/openssl/openssl/commit/75e2c877650444fb829547bdb58d46eb1297bc1a. 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.

davisjam commented 6 years ago

[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.

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:

Peer pressure

My impressions

paragonie-scott commented 6 years ago

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.

bnoordhuis commented 6 years ago

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 commented 6 years ago

@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 commented 6 years ago

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.