Closed briansmith closed 1 month ago
The thing that's special about SGX isn't the target_vendor
, but all(target_arch = "x86_64", any(target_os = "none", target_os="unknown"), target_feature = "rdrand")
. So maybe we can leave the vendor and target vendor out of the consideration when considering whether to use RDRAND.
Also, the only thing special about SGX is that we have to know that we cannot invoke CPUID. It doesn't matter though because it already has target_feature = "rdrand"
so we never need to invoke CPUID on it anyway. Thus we really don't need any SGX-specific configuration.
IMO, most any(target_os = "none", target_os="unknown")
environments really need to make their own real CSPRNG that mixes several sources of entropy, instead of just relying on RDRAND. In this sense, it isn't much different than the situation with ESPIDF, where nobody should be using the implementation getrandom
currently provides, but we provide it to give them something that "works" so they can port things.
With this in mind, I don't think we need to have RDRAND (or the ESPIDF equivalent) by default for ANY target. I think instead we could require all these targets to register a custom implementation. Somebody could make a getrandom-rdrand
crate that registers a custom implementation that uses RDRAND, which we could discourage people from using but also tell them how to use it. Then they can, in their Cargo.toml, choose the targets for which they want that. And rand
or other crates can decide on their own what they want to do. rand
has its own ChaCha CSPRNG already, so presumably it would use that.
In other words, getrandom
should stop defaulting to--or even providing--bad implementations when it doesn't have an OS implementation to use.
Copying from #438
I would propose fixing #230 by simply having the
custom
feature take precedence over therdrand
feature. This would allow users who are fine with the CSPRNG ofrdrand
to simply specify therdrand
feature, while users who want more complexity can use thecustom
feature to provide their own implementation. If necessary, we can also have an x86-onlyfn rdrand_fill(&mut [u8]) -> Result<(), Error>
orfn rdrand() -> Result<[u8; 8], Error>
helper function to make such implementations easier.For SGX targets we currently unconditionally use the
rdrand
implementation. This is probably not ideal, given thattarget_env = "sgx"
may not mean the same thing across different targets. I would make the following changes:
- Only use the
rdrand
implemenation by default onx86_64-fortanix-unknown-sgx
. Other unsupported targets will need to explicitly setrdrand
.- Even on
x86_64-fortanix-unknown-sgx
, havecustom
take precedence overrdrand
, ensuring that ourrdrand
implementation always interacts withcustom
in a consistent way.- Effectively, this just makes the
rdrand
feature on by default forx86_64-fortanix-unknown-sgx
which seems ideal.
I would propose fixing https://github.com/rust-random/getrandom/issues/230 by simply having the custom feature take precedence over the rdrand feature.
Currently, --features=custom,rdrand
means "use rdrand on x86-64 when there's no system getrandom, use my custom implementation on other targets." So in theory your proposal could be a breaking change, if they didn't define custom implementation when target_arch="x86_64" (e.g. they use cfg_if!
much like we do).
Perhaps we should create a new custom feature, "custom2", with a better API, and with "overrides features=custom,rdrand" semantics. Then we can issue a deprecated warning when #[cfg_attr(all(feature = "custom", feature = "custom2"), deprecated(note = "The original 'custom' feature is deprecated and ignored when the 'custom2' feature is enabled, and will be deprecated unconditionally in the future.))
.
Similarly, when rdrand and custom2 are both enabled at the same time, we should warn that the rdrand feature is deprecated and that the custom2 implementation will be used.
fn rdrand_fill(&mut [u8]) -> Result<(), Error>
Worst-case scenerio, they can use the RDRAND crate or do it themselves using intrinsics or inline assembly. I do think it is a good idea to support an API for RDRAND, but we should design it separately.
Eventually, maybe a year or two from now, when either the original custom or rdrand features are used, we should warn that they are deprecated.
See https://github.com/rust-random/getrandom/blob/30308ae845b0bf3839e5a92120559eaf56048c28/src/lib.rs#L208-L217:
Presently, the RDRAND implementation supersedes the custom implementation, and there's no way to prevent that for SGX or when the
rdrand
feature is explicitly set. Further, there's no way to use RDRAND through this crate from a custom implementation.More generally, in any target we should be able to avoid using RDRAND output directly. For example, in an SGX and/or UEFI or operating system kernel, one may want to implement their own RNG, perhaps one that conforms to external security standards (FIPS, NIST, etc.), perhaps using RDRAND as one entropy source. Or, the implementation may want to mix the RDRAND output into a DRBG (using NIST terminology) to protect against unknown issues with RDRAND.
And, I think we
getrandom
even avoid defaulting to RDRAND on any target.In UEFI and SGX, I would like to force the use of my custom implementation, and I'd like to implement mine partially in terms of RDRAND.
Concretely, I suggest:
rdrand
feature is requested, expose a new API to get the (raw, unbiased) results of RDRAND, independent of the currentgetrandom()
API.rdrand
andcustom
features are requested, provide an API for registering the RDRAND implementation as the custom implementation, and document that environments such as UEFI and SGX must do this registration before usinggetrandom
, just like any custom implementation.