
The `csprng_bytes()` function generates randomness and writes it into a caller-provided buffer. It abstracts over a couple of implementations, where the exact one that is used depends on the platform. These implementations have different guarantees: while some guarantee to never fail (arc4random(3)), others may fail. There are two significant failures to distinguish from one another: - Systemic failure, where e.g. opening "/dev/urandom" fails or when OpenSSL doesn't have a provider configured. - Entropy failure, where the entropy pool is exhausted, and thus the function cannot guarantee strong cryptographic randomness. While we cannot do anything about the former, the latter failure can be acceptable in some situations where we don't care whether or not the randomness can be predicted. Introduce a new `CSPRNG_BYTES_INSECURE` flag that allows callers to opt into weak cryptographic randomness. The exact behaviour of the flag depends on the underlying implementation: - `arc4random_buf()` never returns an error, so it doesn't change. - `getrandom()` pulls from "/dev/urandom" by default, which never blocks on modern systems even when the entropy pool is empty. - `getentropy()` seems to block when there is not enough randomness available, and there is no way of changing that behaviour. - `GtlGenRandom()` doesn't mention anything about its specific failure mode. - The fallback reads from "/dev/urandom", which also returns bytes in case the entropy pool is drained in modern Linux systems. That only leaves OpenSSL with `RAND_bytes()`, which returns an error in case the returned data wouldn't be cryptographically safe. This function is replaced with a call to `RAND_pseudo_bytes()`, which can indicate whether or not the returned data is cryptographically secure via its return value. If it is insecure, and if the `CSPRNG_BYTES_INSECURE` flag is set, then we ignore the insecurity and return the data regardless. It is somewhat questionable whether we really need the flag in the first place, or whether we wouldn't just ignore the potentially-insecure data. But the risk of doing that is that we might have or grow callsites that aren't aware of the potential insecureness of the data in places where it really matters. So using a flag to opt-in to that behaviour feels like the more secure choice. Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>
29 lines
562 B
C
29 lines
562 B
C
#include "test-tool.h"
|
|
#include "git-compat-util.h"
|
|
|
|
int cmd__csprng(int argc, const char **argv)
|
|
{
|
|
unsigned long count;
|
|
unsigned char buf[1024];
|
|
|
|
if (argc > 2) {
|
|
fprintf(stderr, "usage: %s [<size>]\n", argv[0]);
|
|
return 2;
|
|
}
|
|
|
|
count = (argc == 2) ? strtoul(argv[1], NULL, 0) : ULONG_MAX;
|
|
|
|
while (count) {
|
|
unsigned long chunk = count < sizeof(buf) ? count : sizeof(buf);
|
|
if (csprng_bytes(buf, chunk, 0) < 0) {
|
|
perror("failed to read");
|
|
return 5;
|
|
}
|
|
if (fwrite(buf, chunk, 1, stdout) != chunk)
|
|
return 1;
|
|
count -= chunk;
|
|
}
|
|
|
|
return 0;
|
|
}
|