From 0389d46010a854e519fb61ecd0ac70600008d882 Mon Sep 17 00:00:00 2001 From: Joe Richey Date: Mon, 25 May 2020 03:03:21 -0700 Subject: [PATCH 01/10] Update docs for 0.2 The main things here are clarifying how fallback functionatliy works. Signed-off-by: Joe Richey --- Cargo.toml | 6 +-- README.md | 25 ++--------- src/custom.rs | 40 +++++++++++++++--- src/error.rs | 8 +++- src/lib.rs | 115 +++++++++++++++++++++++++++++--------------------- 5 files changed, 117 insertions(+), 77 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 83df2da9..d4642fce 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -35,8 +35,9 @@ wasm-bindgen = { version = "0.2.62", default-features = false, optional = true } wasm-bindgen-test = "0.3.12" [features] +# Implement std-only traits for getrandom::Error std = [] -# Feature to enable fallback RDRAND-based implementation +# Feature to enable fallback RDRAND-based implementation on x86/x86_64 rdrand = [] # Feature to enable JavaScript bindings on wasm32-unknown-unknown js = ["stdweb", "wasm-bindgen"] @@ -44,8 +45,7 @@ js = ["stdweb", "wasm-bindgen"] custom = [] # Unstable feature to support being a libstd dependency rustc-dep-of-std = ["compiler_builtins", "core"] - -# Test/wasm-bindgen only feature to run tests in a browser +# Unstable/test-only feature to run wasm-bindgen tests in a browser test-in-browser = [] [package.metadata.docs.rs] diff --git a/README.md b/README.md index 456c2450..5513c8ae 100644 --- a/README.md +++ b/README.md @@ -37,27 +37,10 @@ fn get_random_buf() -> Result<[u8; 32], getrandom::Error> { } ``` -## Features - -This library is `no_std` for every supported target. However, getting randomness -usually requires calling some external system API. This means most platforms -will require linking against system libraries (i.e. `libc` for Unix, -`Advapi32.dll` for Windows, Security framework on iOS, etc...). - -For the `wasm32-unknown-unknown` target, one of the following features should be -enabled: - -- [`wasm-bindgen`](https://crates.io/crates/wasm_bindgen) -- [`stdweb`](https://crates.io/crates/stdweb) - -By default, compiling `getrandom` for an unsupported target will result in -a compilation error. If you want to build an application which uses `getrandom` -for such target, you can either: -- Use [`[replace]`][replace] or [`[patch]`][patch] section in your `Cargo.toml` -to switch to a custom implementation with a support of your target. - -[replace]: https://doc.rust-lang.org/cargo/reference/manifest.html#the-replace-section -[patch]: https://doc.rust-lang.org/cargo/reference/manifest.html#the-patch-section +For more information about supported targets, entropy sources, `no_std` targets, +crate features, WASM support and Custom RNGs see the +[`getrandom` documentation](https://docs.rs/getrandom/latest) and +[`getrandom::Error` documentation](https://docs.rs/getrandom/latest/getrandom/struct.Error.html). ## Minimum Supported Rust Version diff --git a/src/custom.rs b/src/custom.rs index 71a1533c..18ac6c67 100644 --- a/src/custom.rs +++ b/src/custom.rs @@ -10,13 +10,43 @@ use crate::Error; use core::num::NonZeroU32; -/// Register a function to be invoked by `getrandom` on custom targets. +/// Register a function to be invoked by `getrandom` on unsupported targets. /// -/// This function will only be invoked on targets not supported by `getrandom`. -/// This prevents crate dependencies from either inadvertently or maliciously -/// overriding the secure RNG implementations in `getrandom`. +/// *This API requires the following Cargo features to be activated: `"custom"`* /// -/// *This API requires the following crate features to be activated: `custom`* +/// ## Writing your own custom `getrandom` implementation +/// +/// Users can define custom implementations either in their root crate or in a +/// target specific helper-crate. We will use the helper-crate approach in this +/// example, defining `dummy-getrandom`, an implementation that always fails. +/// +/// First, in `dummy-getrandom/Cargo.toml` we depend on `getrandom`: +/// ```toml +/// [dependencies] +/// getrandom = { version = "0.2", features = ["custom"] } +/// ``` +/// +/// Next, in `dummy-getrandom/src/lib.rs`, we define our custom implementation and register it: +/// ```rust +/// use core::num::NonZeroU32; +/// use getrandom::{Error, register_custom_getrandom}; +/// +/// const MY_CUSTOM_ERROR_CODE: u32 = Error::CUSTOM_START + 42; +/// fn always_fail(buf: &mut [u8]) -> Result<(), Error> { +/// let code = NonZeroU32::new(MY_CUSTOM_ERROR_CODE).unwrap(); +/// Err(Error::from(code)) +/// } +/// +/// register_custom_getrandom!(always_fail); +/// ``` +/// the registered function must have the same type signature as +/// [`getrandom::getrandom`](crate::getrandom). +/// +/// Now any user of `getrandom` (direct or indirect) on this target will use the +/// above custom implementation. Note that if you are using a helper-crate, some +/// crate in the build needs to depend on `dummy-getrandom` via a +/// `use dummy_getrandom;` statement. Failure to do this will result +/// in linker errors. #[macro_export] macro_rules! register_custom_getrandom { ($path:path) => { diff --git a/src/error.rs b/src/error.rs index 7b5d3ca4..48abdc11 100644 --- a/src/error.rs +++ b/src/error.rs @@ -7,7 +7,7 @@ // except according to those terms. use core::{fmt, num::NonZeroU32}; -/// A small and `no_std` compatible error type. +/// A small and `no_std` compatible error type /// /// The [`Error::raw_os_error()`] will indicate if the error is from the OS, and /// if so, which error code the OS gave the application. If such an error is @@ -15,6 +15,12 @@ use core::{fmt, num::NonZeroU32}; /// /// Internally this type is a NonZeroU32, with certain values reserved for /// certain purposes, see [`Error::INTERNAL_START`] and [`Error::CUSTOM_START`]. +/// +/// *If this crate's `"std"` Cargo feature is enabled*, then: +/// - [`getrandom::Error`][Error] implements +/// [`std::error::Error`](https://doc.rust-lang.org/std/error/trait.Error.html) +/// - [`std::io::Error`](https://doc.rust-lang.org/std/io/struct.Error.html) implements +/// [`From`](https://doc.rust-lang.org/std/convert/trait.From.html). #[derive(Copy, Clone, Eq, PartialEq)] pub struct Error(NonZeroU32); diff --git a/src/lib.rs b/src/lib.rs index 2cfc20d8..7d40766a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -6,14 +6,15 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! Interface to the random number generator of the operating system. +//! Interface to the operating system's random number generator. //! -//! # Platform sources +//! # Supported targets //! -//! | OS | interface +//! | Target | Implementation //! |------------------|--------------------------------------------------------- //! | Linux, Android | [`getrandom`][1] system call if available, otherwise [`/dev/urandom`][2] after successfully polling `/dev/random` //! | Windows | [`RtlGenRandom`][3] +//! | [Windows UWP][22]| [`BCryptGenRandom`][23] //! | macOS | [`getentropy()`][19] if available, otherwise [`/dev/random`][20] (identical to `/dev/urandom`) //! | iOS | [`SecRandomCopyBytes`][4] //! | FreeBSD | [`getrandom()`][21] if available, otherwise [`kern.arandom`][5] @@ -27,65 +28,86 @@ //! | Haiku | `/dev/random` (identical to `/dev/urandom`) //! | SGX | [RDRAND][18] //! | VxWorks | `randABytes` after checking entropy pool initialization with `randSecure` -//! | Web browsers | [`Crypto.getRandomValues`][14] (see [Support for WebAssembly and asm.js][16]) -//! | Node.js | [`crypto.randomBytes`][15] (see [Support for WebAssembly and asm.js][16]) +//! | Emscripten | `/dev/random` (identical to `/dev/urandom`) //! | WASI | [`__wasi_random_get`][17] +//! | Web Browser | [`Crypto.getRandomValues()`][14], see [support for WebAssembly][16] +//! | Node.js | [`crypto.randomBytes`][15], see [support for WebAssembly][16] //! -//! Getrandom doesn't have a blanket implementation for all Unix-like operating -//! systems that reads from `/dev/urandom`. This ensures all supported operating -//! systems are using the recommended interface and respect maximum buffer -//! sizes. +//! There is no blanket implementation on `unix` targets that reads from +//! `/dev/urandom`. This ensures all supported targets are using the recommended +//! interface and respect maximum buffer sizes. +//! +//! Pull Requests that add support for new targets to `getrandom` are always welcome. //! //! ## Unsupported targets //! -//! By default, compiling `getrandom` for an unsupported target will result in -//! a compilation error. If you want to build an application which uses `getrandom` -//! for such target, you can either: -//! - Use [`[replace]`][replace] or [`[patch]`][patch] section in your `Cargo.toml` -//! to switch to a custom implementation with a support of your target. +//! By default, `getrandom` will not compile on unsupported targets, but certain +//! features allow a user to select a "fallback" implementation if no supported +//! implementation exists. +//! +//! All of the below mechanisms only affect unsupported +//! targets. Supported targets will _always_ use their supported implementations. +//! This prevents a crate from overriding a secure source of randomness +//! (either accidentally or intentionally). +//! +//! ### RDRAND on x86 //! -//! [replace]: https://doc.rust-lang.org/cargo/reference/manifest.html#the-replace-section -//! [patch]: https://doc.rust-lang.org/cargo/reference/manifest.html#the-patch-section +//! *If the `"rdrand"` Cargo feature is enabled*, `getrandom` will fallback to using +//! the [`RDRAND`][18] instruction to get randomness on `no_std` `x86`/`x86_64` +//! targets. This feature has no effect on other CPU architectures. //! -//! ## Support for WebAssembly and asm.js +//! ### Support for WebAssembly //! -//! Getrandom supports all of Rust's current `wasm32` targets, and it works with -//! both Node.js and web browsers. The three Emscripten targets -//! `asmjs-unknown-emscripten`, `wasm32-unknown-emscripten`, and -//! `wasm32-experimental-emscripten` use Emscripten's `/dev/random` emulation. -//! The WASI target `wasm32-wasi` uses the [`__wasi_random_get`][17] function -//! defined by the WASI standard. +//! This crate fully supports the `wasm32-wasi` and `wasm32-unknown-emscripten` +//! targets. However, the `wasm32-unknown-unknown` target is not supported since, +//! from the target name alone, we cannot deduce which JavaScript interface is +//! in use (or if JavaScript is available at all). //! -//! Getrandom also supports `wasm32-unknown-unknown` by directly calling -//! JavaScript methods. Rust currently has two ways to do this: [bindgen] and -//! [stdweb]. Getrandom supports using either one by enabling the -//! `wasm-bindgen` or `stdweb` crate features. Note that if both features are -//! enabled, `wasm-bindgen` will be used. If neither feature is enabled, calls -//! to `getrandom` will always fail at runtime. +//! Instead, *if the `"js"` Cargo feature is enabled*, this crate will assume +//! that you are building for an environment containing JavaScript, and will +//! call the appropriate methods. Both Browser and Node.js environments are +//! supported (see above), and both [wasm-bindgen] and [stdweb] toolchains are +//! supported. //! -//! [bindgen]: https://github.com/rust-lang/rust-bindgen +//! [wasm-bindgen]: https://github.com/rust-lang/rust-bindgen //! [stdweb]: https://github.com/koute/stdweb //! +//! ### Use a custom implementation +//! +//! Some external crates define `getrandom` implementations for specific +//! unsupported targets. If you depend on one of these external crates and you +//! are building for an unsupported target, `getrandom` will use this external +//! implementation instead of failing to compile. +//! +//! See [`register_custom_getrandom!`] for information about writing your own +//! custom `getrandom` implementation for an unsupported target. +//! +//! ### Indirect Dependencies +//! +//! If `getrandom` is not a direct dependency of your crate, you can still +//! enable any of above fallback behaviors by simply enabling the relevant +//! feature in your root crate's `[dependencies]` section: +//! ```toml +//! getrandom = { version = "0.2", features = ["rdrand"] } +//! ``` +//! //! ## Early boot //! -//! It is possible that early in the boot process the OS hasn't had enough time -//! yet to collect entropy to securely seed its RNG, especially on virtual -//! machines. +//! Sometimes, early in the boot process, the OS has not collected enough +//! entropy to securely seed its RNG. This is especially common on virtual +//! machines, where standard "random" events are hard to come by. //! -//! Some operating systems always block the thread until the RNG is securely +//! Some operating system interfaces always block until the RNG is securely //! seeded. This can take anywhere from a few seconds to more than a minute. -//! Others make a best effort to use a seed from before the shutdown and don't -//! document much. +//! A few (Linux, NetBSD and Solaris) offer a choice between blocking and +//! getting an error; in these cases, we always choose to block. //! -//! A few, Linux, NetBSD and Solaris, offer a choice between blocking and -//! getting an error; in these cases we always choose to block. -//! -//! On Linux (when the `getrandom` system call is not available) and on NetBSD -//! reading from `/dev/urandom` never blocks, even when the OS hasn't collected -//! enough entropy yet. To avoid returning low-entropy bytes, we first read from +//! On Linux (when the `getrandom` system call is not available), reading from +//! `/dev/urandom` never blocks, even when the OS hasn't collected enough +//! entropy yet. To avoid returning low-entropy bytes, we first poll //! `/dev/random` and only switch to `/dev/urandom` once this has succeeded. //! -//! # Error handling +//! ## Error handling //! //! We always choose failure over returning insecure "random" bytes. In general, //! on supported platforms, failure is highly unlikely, though not impossible. @@ -93,9 +115,6 @@ //! `getrandom`, hence after the first successful call one can be reasonably //! confident that no errors will occur. //! -//! On unsupported platforms, `getrandom` always fails. See the [`Error`] type -//! for more information on what data is returned on failure. -//! //! [1]: http://man7.org/linux/man-pages/man2/getrandom.2.html //! [2]: http://man7.org/linux/man-pages/man4/urandom.4.html //! [3]: https://docs.microsoft.com/en-us/windows/desktop/api/ntsecapi/nf-ntsecapi-rtlgenrandom @@ -111,12 +130,14 @@ //! [13]: https://github.com/nuxinl/cloudabi#random_get //! [14]: https://www.w3.org/TR/WebCryptoAPI/#Crypto-method-getRandomValues //! [15]: https://nodejs.org/api/crypto.html#crypto_crypto_randombytes_size_callback -//! [16]: #support-for-webassembly-and-asmjs +//! [16]: #support-for-webassembly //! [17]: https://github.com/WebAssembly/WASI/blob/master/design/WASI-core.md#__wasi_random_get //! [18]: https://software.intel.com/en-us/articles/intel-digital-random-number-generator-drng-software-implementation-guide //! [19]: https://www.unix.com/man-page/mojave/2/getentropy/ //! [20]: https://www.unix.com/man-page/mojave/4/random/ //! [21]: https://www.freebsd.org/cgi/man.cgi?query=getrandom&manpath=FreeBSD+12.0-stable +//! [22]: https://docs.microsoft.com/en-us/windows/uwp/ +//! [23]: https://docs.microsoft.com/en-us/windows/win32/api/bcrypt/nf-bcrypt-bcryptgenrandom #![doc( html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk.png", From 8fc3c6af1168b16af54757b5f228f7db553266be Mon Sep 17 00:00:00 2001 From: Joe Richey Date: Tue, 8 Sep 2020 14:05:38 -0700 Subject: [PATCH 02/10] Format compile_error! Signed-off-by: Joe Richey --- src/lib.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 7d40766a..132be41c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -215,10 +215,8 @@ cfg_if! { } else if #[cfg(feature = "custom")] { use custom as imp; } else { - compile_error!("\ - target is not supported, for more information see: \ - https://docs.rs/getrandom/#unsupported-targets\ - "); + compile_error!("target is not supported, for more information see: \ + https://docs.rs/getrandom/#unsupported-targets"); } } From 0a0723e780160dbe079f7aa1c3b77bb60be60e1e Mon Sep 17 00:00:00 2001 From: Joe Richey Date: Tue, 8 Sep 2020 14:44:40 -0700 Subject: [PATCH 03/10] docs: Update wasm32 support section Include more links, exampales, and clarify wording Signed-off-by: Joe Richey --- src/lib.rs | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 132be41c..d4504c4a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -58,19 +58,22 @@ //! //! ### Support for WebAssembly //! -//! This crate fully supports the `wasm32-wasi` and `wasm32-unknown-emscripten` -//! targets. However, the `wasm32-unknown-unknown` target is not supported since, -//! from the target name alone, we cannot deduce which JavaScript interface is -//! in use (or if JavaScript is available at all). +//! This crate fully supports the +//! [`wasm32-wasi`](https://github.com/CraneStation/wasi) and +//! [`wasm32-unknown-emscripten`](https://www.hellorust.com/setup/emscripten/) +//! targets. However, the `wasm32-unknown-unknown` target is not automatically +//! supported since, from the target name alone, we cannot deduce which +//! JavaScript interface is in use (or if JavaScript is available at all). //! //! Instead, *if the `"js"` Cargo feature is enabled*, this crate will assume //! that you are building for an environment containing JavaScript, and will -//! call the appropriate methods. Both Browser and Node.js environments are -//! supported (see above), and both [wasm-bindgen] and [stdweb] toolchains are -//! supported. +//! call the appropriate methods. Both web browser (main window and Web Workers) +//! and Node.js environments are supported, invoking the methods +//! [described above](#supported-targets). This crate can be built with either +//! the [wasm-bindgen](https://github.com/rust-lang/rust-bindgen) or +//! [cargo-web](https://github.com/koute/cargo-web) toolchains. //! -//! [wasm-bindgen]: https://github.com/rust-lang/rust-bindgen -//! [stdweb]: https://github.com/koute/stdweb +//! This feature has no effect on targets other than `wasm32-unknown-unknown`. //! //! ### Use a custom implementation //! @@ -85,10 +88,11 @@ //! ### Indirect Dependencies //! //! If `getrandom` is not a direct dependency of your crate, you can still -//! enable any of above fallback behaviors by simply enabling the relevant -//! feature in your root crate's `[dependencies]` section: +//! enable any of the above fallback behaviors by enabling the relevant +//! feature in your root crate's `Cargo.toml`: //! ```toml -//! getrandom = { version = "0.2", features = ["rdrand"] } +//! [dependencies] +//! getrandom = { version = "0.2", features = ["js"] } //! ``` //! //! ## Early boot From 92f1034659a7c89ecae9bfa761988fe1620029b9 Mon Sep 17 00:00:00 2001 From: Joe Richey Date: Tue, 8 Sep 2020 16:22:15 -0700 Subject: [PATCH 04/10] docs: Clarify when/where to use custom implementations Signed-off-by: Joe Richey --- src/custom.rs | 11 +++++------ src/lib.rs | 15 +++++++++++++++ 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/src/custom.rs b/src/custom.rs index 18ac6c67..66636bc9 100644 --- a/src/custom.rs +++ b/src/custom.rs @@ -25,12 +25,12 @@ use core::num::NonZeroU32; /// [dependencies] /// getrandom = { version = "0.2", features = ["custom"] } /// ``` -/// +/// /// Next, in `dummy-getrandom/src/lib.rs`, we define our custom implementation and register it: /// ```rust /// use core::num::NonZeroU32; /// use getrandom::{Error, register_custom_getrandom}; -/// +/// /// const MY_CUSTOM_ERROR_CODE: u32 = Error::CUSTOM_START + 42; /// fn always_fail(buf: &mut [u8]) -> Result<(), Error> { /// let code = NonZeroU32::new(MY_CUSTOM_ERROR_CODE).unwrap(); @@ -43,10 +43,9 @@ use core::num::NonZeroU32; /// [`getrandom::getrandom`](crate::getrandom). /// /// Now any user of `getrandom` (direct or indirect) on this target will use the -/// above custom implementation. Note that if you are using a helper-crate, some -/// crate in the build needs to depend on `dummy-getrandom` via a -/// `use dummy_getrandom;` statement. Failure to do this will result -/// in linker errors. +/// above custom implementation. See the +/// [usage documentation](index.html#use-a-custom-implementation) for information about +/// _using_ such a custom implementation. #[macro_export] macro_rules! register_custom_getrandom { ($path:path) => { diff --git a/src/lib.rs b/src/lib.rs index d4504c4a..9ec5043d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -82,6 +82,21 @@ //! are building for an unsupported target, `getrandom` will use this external //! implementation instead of failing to compile. //! +//! Using such an external implementation requires depending on it in your +//! `Cargo.toml` _and_ using it in your binary crate with: +//! ```ignore +//! use some_custom_getrandom_crate; +//! ``` +//! (failure to do this will cause linker errors). +//! +//! Other than [dev-dependencies](https://doc.rust-lang.org/stable/rust-by-example/testing/dev_dependencies.html), +//! library crates should **not** depend on external implementation crates. +//! Only binary crates should depend/use such crates. This is similar to +//! [`#[panic_handler]`](https://doc.rust-lang.org/nomicon/panic-handler.html) or +//! [`#[global_allocator]`](https://doc.rust-lang.org/edition-guide/rust-2018/platform-and-target-support/global-allocators.html), +//! where helper crates define handlers/allocators but only the binary crate +//! actually _uses_ the functionality. +//! //! See [`register_custom_getrandom!`] for information about writing your own //! custom `getrandom` implementation for an unsupported target. //! From e0c9680d2ba3fb4196fd0592305a2407a546aea5 Mon Sep 17 00:00:00 2001 From: Joe Richey Date: Tue, 8 Sep 2020 23:50:41 -0700 Subject: [PATCH 05/10] travis: Make sure to run docs tests for all features Signed-off-by: Joe Richey --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index e360a4d0..1ad1bb14 100644 --- a/.travis.yml +++ b/.travis.yml @@ -114,7 +114,7 @@ jobs: - cargo doc --no-deps --features=std,custom - cargo deadlinks --dir target/doc # Check that our tests pass in the default/minimal configuration - - cargo test --tests --benches + - cargo test --tests --benches --features=std,custom - cargo generate-lockfile -Z minimal-versions - cargo test --tests --benches From d7c8944227b325baeac4eabf0dfe10e999474ede Mon Sep 17 00:00:00 2001 From: Joe Richey Date: Tue, 8 Sep 2020 23:51:24 -0700 Subject: [PATCH 06/10] docs: Update section headers Signed-off-by: Joe Richey --- src/lib.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 9ec5043d..14414de3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -30,8 +30,8 @@ //! | VxWorks | `randABytes` after checking entropy pool initialization with `randSecure` //! | Emscripten | `/dev/random` (identical to `/dev/urandom`) //! | WASI | [`__wasi_random_get`][17] -//! | Web Browser | [`Crypto.getRandomValues()`][14], see [support for WebAssembly][16] -//! | Node.js | [`crypto.randomBytes`][15], see [support for WebAssembly][16] +//! | Web Browser | [`Crypto.getRandomValues()`][14], see [WebAssembly support][16] +//! | Node.js | [`crypto.randomBytes`][15], see [WebAssembly support][16] //! //! There is no blanket implementation on `unix` targets that reads from //! `/dev/urandom`. This ensures all supported targets are using the recommended @@ -56,7 +56,7 @@ //! the [`RDRAND`][18] instruction to get randomness on `no_std` `x86`/`x86_64` //! targets. This feature has no effect on other CPU architectures. //! -//! ### Support for WebAssembly +//! ### WebAssembly support //! //! This crate fully supports the //! [`wasm32-wasi`](https://github.com/CraneStation/wasi) and @@ -149,7 +149,7 @@ //! [13]: https://github.com/nuxinl/cloudabi#random_get //! [14]: https://www.w3.org/TR/WebCryptoAPI/#Crypto-method-getRandomValues //! [15]: https://nodejs.org/api/crypto.html#crypto_crypto_randombytes_size_callback -//! [16]: #support-for-webassembly +//! [16]: #webassembly-support //! [17]: https://github.com/WebAssembly/WASI/blob/master/design/WASI-core.md#__wasi_random_get //! [18]: https://software.intel.com/en-us/articles/intel-digital-random-number-generator-drng-software-implementation-guide //! [19]: https://www.unix.com/man-page/mojave/2/getentropy/ From c8f40e18d710ed5e04ddaf05cc0ec199142baa00 Mon Sep 17 00:00:00 2001 From: Joe Richey Date: Tue, 8 Sep 2020 23:53:18 -0700 Subject: [PATCH 07/10] docs: Clarify intended usage for Custom RNGs Signed-off-by: Joe Richey --- src/custom.rs | 56 +++++++++++++++++++++++++++++++++++++-------------- src/lib.rs | 31 +++++++++------------------- 2 files changed, 50 insertions(+), 37 deletions(-) diff --git a/src/custom.rs b/src/custom.rs index 66636bc9..cc3a751f 100644 --- a/src/custom.rs +++ b/src/custom.rs @@ -12,40 +12,66 @@ use core::num::NonZeroU32; /// Register a function to be invoked by `getrandom` on unsupported targets. /// -/// *This API requires the following Cargo features to be activated: `"custom"`* +/// *This API requires the `"custom"` Cargo feature to be activated*. /// -/// ## Writing your own custom `getrandom` implementation +/// ## Writing a custom `getrandom` implementation /// -/// Users can define custom implementations either in their root crate or in a -/// target specific helper-crate. We will use the helper-crate approach in this -/// example, defining `dummy-getrandom`, an implementation that always fails. +/// The function to register must have the same signature as +/// [`getrandom::getrandom`](crate::getrandom). The function can be defined +/// wherever you want, either in root crate or a dependant crate. /// -/// First, in `dummy-getrandom/Cargo.toml` we depend on `getrandom`: +/// For example, if we wanted a `failure-getrandom` crate containing an +/// implementation that always fails, we would first depend on `getrandom` +/// (for the [`Error`] type) in `failure-getrandom/Cargo.toml`: /// ```toml /// [dependencies] -/// getrandom = { version = "0.2", features = ["custom"] } +/// getrandom = "0.2" /// ``` +/// Note that the crate containing this function does **not** need to enable the +/// `"custom"` Cargo feature. /// -/// Next, in `dummy-getrandom/src/lib.rs`, we define our custom implementation and register it: +/// Next, in `failure-getrandom/src/lib.rs`, we define our function: /// ```rust /// use core::num::NonZeroU32; -/// use getrandom::{Error, register_custom_getrandom}; +/// use getrandom::Error; /// +/// // Some application-specific error code /// const MY_CUSTOM_ERROR_CODE: u32 = Error::CUSTOM_START + 42; -/// fn always_fail(buf: &mut [u8]) -> Result<(), Error> { +/// pub fn always_fail(buf: &mut [u8]) -> Result<(), Error> { /// let code = NonZeroU32::new(MY_CUSTOM_ERROR_CODE).unwrap(); /// Err(Error::from(code)) /// } +/// ``` +/// +/// ## Registering a custom `getrandom` implementation +/// +/// Functions can only be registered in the root binary crate. Attempting to +/// register a function in a non-root crate will result in a linker error. +/// This is similar to +/// [`#[panic_handler]`](https://doc.rust-lang.org/nomicon/panic-handler.html) or +/// [`#[global_allocator]`](https://doc.rust-lang.org/edition-guide/rust-2018/platform-and-target-support/global-allocators.html), +/// where helper crates define handlers/allocators but only the binary crate +/// actually _uses_ the functionality. +/// +/// To register the function, we first depend on `getrandom` in `Cargo.toml`: +/// ```toml +/// [dependencies] +/// getrandom = { version = "0.2", features = ["custom"] } +/// ``` +/// +/// Then, we register the function in `src/main.rs`: +/// ```rust +/// # mod failure_getrandom { pub fn always_fail(_: &mut [u8]) -> Result<(), getrandom::Error> { unimplemented!() } } +/// use failure_getrandom::always_fail; +/// use getrandom::register_custom_getrandom; /// /// register_custom_getrandom!(always_fail); /// ``` -/// the registered function must have the same type signature as -/// [`getrandom::getrandom`](crate::getrandom). /// /// Now any user of `getrandom` (direct or indirect) on this target will use the -/// above custom implementation. See the -/// [usage documentation](index.html#use-a-custom-implementation) for information about -/// _using_ such a custom implementation. +/// registered function. As noted in the +/// [top-level documentation](index.html#use-a-custom-implementation) this +/// registration only has an effect on unsupported targets. #[macro_export] macro_rules! register_custom_getrandom { ($path:path) => { diff --git a/src/lib.rs b/src/lib.rs index 14414de3..f17f1cb1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -75,30 +75,17 @@ //! //! This feature has no effect on targets other than `wasm32-unknown-unknown`. //! -//! ### Use a custom implementation +//! ### Custom implementations //! -//! Some external crates define `getrandom` implementations for specific -//! unsupported targets. If you depend on one of these external crates and you -//! are building for an unsupported target, `getrandom` will use this external -//! implementation instead of failing to compile. +//! The [`register_custom_getrandom!`] macro allows a user to mark their own +//! function as the backing implementation for [`getrandom`]. See the macro's +//! documentation for more information about writing and registering your own +//! custom implementations. //! -//! Using such an external implementation requires depending on it in your -//! `Cargo.toml` _and_ using it in your binary crate with: -//! ```ignore -//! use some_custom_getrandom_crate; -//! ``` -//! (failure to do this will cause linker errors). -//! -//! Other than [dev-dependencies](https://doc.rust-lang.org/stable/rust-by-example/testing/dev_dependencies.html), -//! library crates should **not** depend on external implementation crates. -//! Only binary crates should depend/use such crates. This is similar to -//! [`#[panic_handler]`](https://doc.rust-lang.org/nomicon/panic-handler.html) or -//! [`#[global_allocator]`](https://doc.rust-lang.org/edition-guide/rust-2018/platform-and-target-support/global-allocators.html), -//! where helper crates define handlers/allocators but only the binary crate -//! actually _uses_ the functionality. -//! -//! See [`register_custom_getrandom!`] for information about writing your own -//! custom `getrandom` implementation for an unsupported target. +//! Note that registering a custom implementation only has an effect on targets +//! that would otherwise not compile. Any supported targets (including those +//! using `"rdrand"` and `"js"` Cargo features) continue using their normal +//! implementations even if a function is registered. //! //! ### Indirect Dependencies //! From 8e1ab1a3da9a96bed15a6628e43e4fda6cad7035 Mon Sep 17 00:00:00 2001 From: Joe Richey Date: Tue, 8 Sep 2020 23:55:20 -0700 Subject: [PATCH 08/10] custom: Add check for function type This makes sure we get a good compiler error if we give a bad path. Signed-off-by: Joe Richey --- src/custom.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/custom.rs b/src/custom.rs index cc3a751f..82d45112 100644 --- a/src/custom.rs +++ b/src/custom.rs @@ -78,8 +78,9 @@ macro_rules! register_custom_getrandom { // We use an extern "C" function to get the guarantees of a stable ABI. #[no_mangle] extern "C" fn __getrandom_custom(dest: *mut u8, len: usize) -> u32 { + let f: fn(&mut [u8]) -> Result<(), ::getrandom::Error> = $path; let slice = unsafe { ::core::slice::from_raw_parts_mut(dest, len) }; - match $path(slice) { + match f(slice) { Ok(()) => 0, Err(e) => e.code().get(), } From afc364d3084397e02b6648fc596eb3832f68513a Mon Sep 17 00:00:00 2001 From: Joe Richey Date: Tue, 8 Sep 2020 23:57:46 -0700 Subject: [PATCH 09/10] docs: Clarify deps of root binary crate Signed-off-by: Joe Richey --- src/custom.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/custom.rs b/src/custom.rs index 82d45112..2fbbc30c 100644 --- a/src/custom.rs +++ b/src/custom.rs @@ -53,9 +53,11 @@ use core::num::NonZeroU32; /// where helper crates define handlers/allocators but only the binary crate /// actually _uses_ the functionality. /// -/// To register the function, we first depend on `getrandom` in `Cargo.toml`: +/// To register the function, we first depend on `failure-getrandom` _and_ +/// `getrandom` in `Cargo.toml`: /// ```toml /// [dependencies] +/// failure-getrandom = "0.1" /// getrandom = { version = "0.2", features = ["custom"] } /// ``` /// From 17fb7d7d4453d15e6b8ea664644474d65b53e652 Mon Sep 17 00:00:00 2001 From: Joe Richey Date: Wed, 9 Sep 2020 19:52:29 -0700 Subject: [PATCH 10/10] docs: add target triple to docs table Signed-off-by: Joe Richey --- src/lib.rs | 44 ++++++++++++++++++++++---------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index f17f1cb1..d19717e0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -10,28 +10,28 @@ //! //! # Supported targets //! -//! | Target | Implementation -//! |------------------|--------------------------------------------------------- -//! | Linux, Android | [`getrandom`][1] system call if available, otherwise [`/dev/urandom`][2] after successfully polling `/dev/random` -//! | Windows | [`RtlGenRandom`][3] -//! | [Windows UWP][22]| [`BCryptGenRandom`][23] -//! | macOS | [`getentropy()`][19] if available, otherwise [`/dev/random`][20] (identical to `/dev/urandom`) -//! | iOS | [`SecRandomCopyBytes`][4] -//! | FreeBSD | [`getrandom()`][21] if available, otherwise [`kern.arandom`][5] -//! | OpenBSD | [`getentropy`][6] -//! | NetBSD | [`kern.arandom`][7] -//! | Dragonfly BSD | [`/dev/random`][8] -//! | Solaris, illumos | [`getrandom`][9] system call if available, otherwise [`/dev/random`][10] -//! | Fuchsia OS | [`cprng_draw`][11] -//! | Redox | [`rand:`][12] -//! | CloudABI | [`cloudabi_sys_random_get`][13] -//! | Haiku | `/dev/random` (identical to `/dev/urandom`) -//! | SGX | [RDRAND][18] -//! | VxWorks | `randABytes` after checking entropy pool initialization with `randSecure` -//! | Emscripten | `/dev/random` (identical to `/dev/urandom`) -//! | WASI | [`__wasi_random_get`][17] -//! | Web Browser | [`Crypto.getRandomValues()`][14], see [WebAssembly support][16] -//! | Node.js | [`crypto.randomBytes`][15], see [WebAssembly support][16] +//! | Target | Target Triple | Implementation +//! | ----------------- | ------------------ | -------------- +//! | Linux, Android | `*‑linux‑*` | [`getrandom`][1] system call if available, otherwise [`/dev/urandom`][2] after successfully polling `/dev/random` | +//! | Windows | `*‑pc‑windows‑*` | [`RtlGenRandom`][3] | +//! | [Windows UWP][22] | `*‑uwp‑windows‑*` | [`BCryptGenRandom`][23] | +//! | macOS | `*‑apple‑darwin` | [`getentropy()`][19] if available, otherwise [`/dev/random`][20] (identical to `/dev/urandom`) +//! | iOS | `*‑apple‑ios` | [`SecRandomCopyBytes`][4] +//! | FreeBSD | `*‑freebsd` | [`getrandom()`][21] if available, otherwise [`kern.arandom`][5] +//! | OpenBSD | `*‑openbsd` | [`getentropy`][6] +//! | NetBSD | `*‑netbsd` | [`kern.arandom`][7] +//! | Dragonfly BSD | `*‑dragonfly` | [`/dev/random`][8] +//! | Solaris, illumos | `*‑solaris`, `*‑illumos` | [`getrandom()`][9] if available, otherwise [`/dev/random`][10] +//! | Fuchsia OS | `*‑fuchsia` | [`cprng_draw`][11] +//! | Redox | `*‑cloudabi` | [`rand:`][12] +//! | CloudABI | `*‑redox` | [`cloudabi_sys_random_get`][13] +//! | Haiku | `*‑haiku` | `/dev/random` (identical to `/dev/urandom`) +//! | SGX | `x86_64‑*‑sgx` | [RDRAND][18] +//! | VxWorks | `*‑wrs‑vxworks‑*` | `randABytes` after checking entropy pool initialization with `randSecure` +//! | Emscripten | `*‑emscripten` | `/dev/random` (identical to `/dev/urandom`) +//! | WASI | `wasm32‑wasi` | [`__wasi_random_get`][17] +//! | Web Browser | `wasm32‑*‑unknown` | [`Crypto.getRandomValues()`][14], see [WebAssembly support][16] +//! | Node.js | `wasm32‑*‑unknown` | [`crypto.randomBytes`][15], see [WebAssembly support][16] //! //! There is no blanket implementation on `unix` targets that reads from //! `/dev/urandom`. This ensures all supported targets are using the recommended