openssl: OpenSSL 3.0.0 RNG fork-safety regression? [security?]
Earlier versions of OpenSSL would take some pains to ensure that calling fork() was was safe in the presence of an RNG. This appears to be gone with the OpenSSL 3.0.0 code.
Specifically: when I write a program that calls RAND_bytes() in the main process, then forks several times, and each child process calls RAND_bytes(), I get the same result from RAND_bytes() in every one of the child processes. This is still the case when the child processes call RAND_poll(), which suggests to me that something is deeply wrong.
OpenSSL 1.1.1 behaves as expected in this case.
Found by Tor’s unit tests. (I don’t want to get preachy, but I’d strongly recommend that OpenSSL adds a regression test for this case: this is exactly the kind of a thing we worry about an RNG doing.)
Here is a demo program:
#include <openssl/rand.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
int should_poll = 1;
void
check_rand_status(void)
{
if (RAND_status() != 1) {
puts("RAND_status is unhappy!");
} else {
// puts("RAND_status says everything is fine...e");
}
}
void
try_rand(void)
{
unsigned u;
check_rand_status();
if (should_poll)
RAND_poll();
check_rand_status();
int r = RAND_bytes((void*)&u, sizeof(u));
if (r == 0) {
printf("Process %d: error!\n", (int)getpid());
} else {
printf("Process %d: rng value is %u.\n",
(int)getpid(), u);
}
check_rand_status();
}
int main(int argc, char **argv)
{
check_rand_status();
try_rand();
check_rand_status();
for (int i = 0; i < 8; ++i) {
pid_t child;
if ((child = fork())) {
// parent.
} else {
try_rand();
exit(0);
}
}
return 0;
}
Here is an example output from openssl-master:
Process 680496: rng value is 1796322885.
Process 680497: rng value is 345659543.
Process 680498: rng value is 345659543.
Process 680499: rng value is 345659543.
Process 680500: rng value is 345659543.
Process 680501: rng value is 345659543.
Process 680502: rng value is 345659543.
Process 680503: rng value is 345659543.
Process 680504: rng value is 345659543.
Here is an example output from openssl 1.1.1g:
Process 680544: rng value is 2039804308.
Process 680545: rng value is 2038236718.
Process 680546: rng value is 1374486369.
Process 680547: rng value is 2441531771.
Process 680548: rng value is 892829712.
Process 680549: rng value is 1349569669.
Process 680550: rng value is 3048351340.
Process 680551: rng value is 2647008208.
Process 680552: rng value is 1731649072.
All tests run on Fedora 32.
About this issue
- Original URL
- State: closed
- Created 4 years ago
- Comments: 34 (34 by maintainers)
Commits related to this issue
- Fix aes-ctr based drbg's forking behavior Fixes #12377 Signed-off-by: Patrick Steuer <patrick.steuer@de.ibm.com> — committed to p-steuer/openssl by p-steuer 4 years ago
- test/drbgtest: improve the reseed after fork test Issue #12377 demonstrated that it is not sufficient to verify that after a fork a reseeding is triggered in the child. This commit enhances the test ... — committed to mspncp/openssl by mspncp 4 years ago
- test/drbgtest: improve the reseed after fork test Issue #12377 demonstrated that it is not sufficient to verify that after a fork a reseeding is triggered in the child. This commit enhances the test ... — committed to mspncp/openssl by mspncp 4 years ago
- Fix provider cipher reinit issue Calling Init()/Update() and then Init()/Update() again gave a different result when using the same key and iv. Cipher modes that were using ctx->num were not resettin... — committed to slontis/openssl by slontis 4 years ago
- test/drbgtest: improve the reseed after fork test Issue #12377 demonstrated that it is not sufficient to verify that after a fork a reseeding is triggered in the child. This commit enhances the test ... — committed to mspncp/openssl by mspncp 4 years ago
- test/drbgtest: improve the reseed after fork test Issue #12377 demonstrated that it is not sufficient to verify that after a fork a reseeding is triggered in the child. This commit enhances the test ... — committed to mspncp/openssl by mspncp 4 years ago
- Fix provider cipher reinit issue Calling Init()/Update() and then Init()/Update() again gave a different result when using the same key and iv. Cipher modes that were using ctx->num were not resettin... — committed to slontis/openssl by slontis 4 years ago
- squash! test/drbgtest: improve the reseed after fork test (add the following text to the commit message) The analysis of #12377 (see [1]) showed that due to an error in the resetting of the AES-CTR ... — committed to mspncp/openssl by mspncp 4 years ago
Thank you again @nmathewson for reporting this important security issue. It would have deserved a CVE if it had slipped into the final release.
I moved my commit backwards on master and put it right in front of the 1.1.1 label. Then i did a bisect …
The commit id is obv. wrong due to the rebase on top of my commit. The real commit id is 819a7ae9fc7721f675757c0925821f91b20dfc8f .
Since the commit does nothing special besides moving AES-CTR to the default provider, it occurs to me that either the default provider or providers in general are not fork safe.
Thanks for reporting. Im looking into it.