FreeBSD announced direct use of RDRAND as sole entropy source is not recommended.[1][2][3]
In Tor crypto_global_init() there is a call to ENGINE_load_builtin_engines() which lets OpenSSL take advantage of
AES-NI acceleration. This is almost always A Good Thing.
From Sandy Bridge onward, however, this also results in the application using RDRAND directly for all entropy.
Since Tor cannot build the OpenSSL linked against (to set OPENSSL_NO_RDRAND), the workaround is to call RAND_set_rand_engine(NULL) after ENGINE_load_builtin_engines().
If you have a Sandy Bridge, Ivy Bridge, or other recent Intel CPU with RDRAND, can you try building Tor against openssl-1.0.1e and HardwareAccel 1 set in config?
If you see a log message:
... "OpenSSL is using RDRAND by default. Attempting to force disable."
please post the results of the following "Using OpenSSL engine ... for RAND" statement to confirm.
I have applied your patch (tor-latest-rdrand-disable.patch) to Tor on Mac OS X Mavericks system with Intel Core i5 CPU that, according to sysctl hw.optional.rdrand has support for RDRAND instruction. Tor source code was cloned from Git master and was compiled with OpenSSL 1.0.1e. When trying to run the patched Tor, it crashed with the following error message:
Dec 14 18:30:52.000 [warn] OpenSSL is using RDRAND by default. Attempting to force disable.============================================================ T= 1387038652Tor 0.2.5.1-alpha-dev (git-e6590efaa77c8cf1) died: Caught signal 110 tor 0x0000000109b7f2ce crash_handler + 461 libsystem_platform.dylib 0x00007fff9897d5aa _sigtramp + 262 libcrypto.1.0.0.dylib 0x0000000109d928ae ENGINE_set_default_RAND + 73 tor 0x0000000109b95594 crypto_global_init + 9324 tor 0x0000000109b2b655 tor_init + 9335 tor 0x0000000109b2bab7 tor_main + 876 tor 0x0000000109aa3b99 main + 257 libdyld.dylib 0x00007fff989c55fd start + 18 ??? 0x0000000000000001 0x0 + 1Abort trap: 6
In collaboration with coderman from #tor-dev, it was found that changing ENGINE_set_default_RAND(NULL); to ENGINE_unregister_RAND(t); prevents the crash.
/* If we are using a version of OpenSSL that supports native RDRAND make sure that we force disable its use as sole entropy source. See https://trac.torproject.org/projects/tor/ticket/10402 */ if (SSLeay() > OPENSSL_V_SERIES(1,0,0)) { t = ENGINE_get_default_RAND(); if (t && (strcmp(ENGINE_get_id(t), "rdrand") == 0)) { log_warn(LD_CRYPTO, "OpenSSL is using RDRAND by default." " Attempting to force disable."); ENGINE_unregister_RAND(t); ENGINE_register_all_complete(); } } /* Log, if available, the intersection of the set of algorithms used by Tor and the set of algorithms available in the engine */ log_engine("RSA", ENGINE_get_default_RSA()); . .
And should result in a log like:
Dec ... [warn] OpenSSL is using RDRAND by default. Attempting to force disable.Dec ... [notice] Using OpenSSL engine RSAX engine support [rsax] for RSADec ... [notice] Using default implementation for RAND . .
What you should NOT see is this line: "[notice] Using OpenSSL engine Intel RDRAND engine [rdrand] for RAND" which is synonymous with EPICFAIL. grin
One last note: the OS kernel will likely use RDRAND to keep /dev/random populated. This is a Good Thing (TM) as long as you make sure you're using a recent kernel that integrates RDRAND properly, e.g.:
Mix RDRAND into a hash across the pool, not XOR'd against output
Mix the mix back into pool (prevent backtrack attacks)
Atomically extract portion of pool and mix
Fold final extracted output in half for conservative operation
The engine table code is a bit tricky to follow, and the API is a bit odd. Has anybody used a debugger or other tool to verify that after unregistering the engine, we really get the original PRNG ? (That is, to check that that the md_rand.c code is called, and the eng_rdrand.c code is not.)
That patch didn't work for me (Tor 0.2.4, OSX 10.9.1, openssl 1.0.1e from homebrew). I get:
Dec 18 10:55:56.000 [warn] OpenSSL is using RDRAND by default. Attempting to force disable.Dec 18 10:55:56.000 [notice] Using OpenSSL engine RSAX engine support [rsax] for RSADec 18 10:55:56.000 [notice] Using OpenSSL engine Intel RDRAND engine [rdrand] for RAND
On investigation, I think that the log message is wrong: It looks at ENGINE_get_default_RAND(), which should have just gotten pulled off the engine table.
There's also something else screwy going in here, though. It appears that we aren't actually using the RDRAND backend, even when I enable HardwareAccel.
AHA.
We are frequently not using any RAND engine at all. (That's probably a good thing!)
That's because, if any RAND_* function is invoked before setting a RAND engine, the call in rand_lib.c to RAND_get_rand_method() will set the default_RAND_method pointer. That RAND_METHOD pointer will stay that way until it's changed, and nothing will change it unless we somehow clear and re-initialize it.
And when do we first call any random function? During ordinary operation, if we start up with a state file that has any circuit build time values, we'll shuffle them in circuit_build_times_shuffle_store_array.
If we have no state file, then the rand method is not set when the crypto_init() code is first called.
Of course, this isn't really a fix, because when we first start Tor, we'll have no state file, and we'll use the default rand method after all. But wow, this junk sure made debugging hard.
Branch bug10402_redux_024 in my public repository takes the simpler approach. Please review. Does this work for you?
(I am fairly sure that the other one did not work; when I added logging code to dump RAND_get_rand_method() and RAND_SSLeay(), and ran Tor with an empty state file, those methods were different before.)
Regarding "Of course, this isn't really a fix, because when we first start Tor, we'll have no state file, and we'll use the default rand method after all. But wow, this junk sure made debugging hard."
I created a BADENGINE that behaves like RdRand except uses libc rand() for testing purposes. I ran the current git Tor on a clean run (no state file) and on subsequent runs.
This confirmed that on the first run without state file, RdRand (or BADRAND) will be used by default, but every subsequent run it will not. Unfortunately first run might also generate long lived secrets depending on Tor config.
Confirmed!
"Dec 18 14:25:20.000 [notice] It appears that one of our engines has provided a replacement the OpenSSL RNG. Resetting it to the default implementation."