diff --git a/.travis.yml b/.travis.yml index cc3de535..49353822 100644 --- a/.travis.yml +++ b/.travis.yml @@ -21,7 +21,6 @@ matrix: - rustup target add aarch64-apple-ios script: - cargo test - - cargo test --examples - cargo build --target aarch64-apple-ios - name: "Linux, beta" @@ -40,11 +39,11 @@ matrix: # Get latest geckodriver - export VERSION=$(curl -s https://api.github.com/repos/mozilla/geckodriver/releases/latest | jq -r ".tag_name") - wget -O geckodriver.tar.gz https://github.com/mozilla/geckodriver/releases/download/$VERSION/geckodriver-$VERSION-linux64.tar.gz - - tar -xzf geckodriver.tar.gz + - tar -xzf geckodriver.tar.gz -C $HOME # Get latest chromedirver - export VERSION=$(wget -q -O - https://chromedriver.storage.googleapis.com/LATEST_RELEASE) - wget -O chromedriver.zip https://chromedriver.storage.googleapis.com/$VERSION/chromedriver_linux64.zip - - unzip chromedriver.zip + - unzip chromedriver.zip -d $HOME # Get cargo-web - export VERSION=0.6.26 # Pin version for stability - wget -O cargo-web.gz https://github.com/koute/cargo-web/releases/download/$VERSION/cargo-web-x86_64-unknown-linux-gnu.gz @@ -76,44 +75,34 @@ matrix: - cargo web test --target=wasm32-unknown-unknown --features=stdweb # wasm-bindgen tests (Node, Firefox, Chrome) - cargo test --target wasm32-unknown-unknown --features=wasm-bindgen - - GECKODRIVER=$PWD/geckodriver cargo test --target wasm32-unknown-unknown --features=test-in-browser - - CHROMEDRIVER=$PWD/chromedriver cargo test --target wasm32-unknown-unknown --features=test-in-browser + - GECKODRIVER=$HOME/geckodriver cargo test --target wasm32-unknown-unknown --features=test-in-browser + - CHROMEDRIVER=$HOME/chromedriver cargo test --target wasm32-unknown-unknown --features=test-in-browser - - name: "Linux, nightly, docs" + - &nightly_and_docs + name: "Linux, nightly, docs" rust: nightly os: linux install: - cargo --list | egrep "^\s*deadlinks$" -q || cargo install cargo-deadlinks - cargo deadlinks -V script: + # Check that our tests pass in the default configuration - cargo test - cargo test --benches - - cargo test --examples + # Check that setting various features does not break the build + - cargo build --features=std + - cargo build --features=log # remove cached documentation, otherwise files from previous PRs can get included - rm -rf target/doc - - cargo doc --no-deps --all --features=std,log + - cargo doc --no-deps --features=std - cargo deadlinks --dir target/doc # also test minimum dependency versions are usable - cargo generate-lockfile -Z minimal-versions - - cargo test + - cargo test --features=std,log - - name: "OSX, nightly, docs" - rust: nightly + - <<: *nightly_and_docs + name: "OSX, nightly, docs" os: osx - install: - - cargo --list | egrep "^\s*deadlinks$" -q || cargo install cargo-deadlinks - - cargo deadlinks -V - script: - - cargo test - - cargo test --benches - - cargo test --examples - # remove cached documentation, otherwise files from previous PRs can get included - - rm -rf target/doc - - cargo doc --no-deps --all --features=std,log - - cargo deadlinks --dir target/doc - # also test minimum dependency versions are usable - - cargo generate-lockfile -Z minimal-versions - - cargo test - name: "cross-platform build only" rust: nightly @@ -139,6 +128,7 @@ matrix: - cargo xbuild --target=x86_64-unknown-uefi - cargo xbuild --target=x86_64-unknown-hermit - cargo xbuild --target=x86_64-unknown-l4re-uclibc + - cargo xbuild --target=x86_64-uwp-windows-gnu - cargo xbuild --target=x86_64-wrs-vxworks # also test minimum dependency versions are usable - cargo generate-lockfile -Z minimal-versions @@ -153,6 +143,7 @@ matrix: - cargo xbuild --target=x86_64-unknown-hermit - cargo xbuild --target=x86_64-unknown-l4re-uclibc - cargo xbuild --target=x86_64-uwp-windows-gnu + - cargo xbuild --target=x86_64-wrs-vxworks # Trust cross-built/emulated targets. We must repeat all non-default values. - name: "Linux (MIPS, big-endian)" @@ -199,7 +190,6 @@ before_script: script: - cargo test - - cargo test --examples after_script: set +e diff --git a/Cargo.toml b/Cargo.toml index fbb0a2eb..7aa8780f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "getrandom" -version = "0.1.12" +version = "0.2.0" edition = "2018" authors = ["The Rand Project Developers"] license = "MIT OR Apache-2.0" @@ -41,3 +41,6 @@ std = [] rustc-dep-of-std = ["compiler_builtins", "core"] # Unstable feature for testing test-in-browser = ["wasm-bindgen"] + +[package.metadata.docs.rs] +features = ["std"] diff --git a/src/error.rs b/src/error.rs index b2cb9a8d..2ffc252f 100644 --- a/src/error.rs +++ b/src/error.rs @@ -19,13 +19,36 @@ use core::num::NonZeroU32; #[derive(Copy, Clone, Eq, PartialEq)] pub struct Error(NonZeroU32); +// TODO: Convert to a function when min_version >= 1.33 +macro_rules! internal_error { + ($n:expr) => { + Error(unsafe { NonZeroU32::new_unchecked(Error::INTERNAL_START + $n as u16 as u32) }) + }; +} + impl Error { - #[deprecated(since = "0.1.7")] - /// Unknown error. - pub const UNKNOWN: Error = UNSUPPORTED; - #[deprecated(since = "0.1.7")] - /// System entropy source is unavailable. - pub const UNAVAILABLE: Error = UNSUPPORTED; + /// This target/platform is not supported by `getrandom`. + pub const UNSUPPORTED: Error = internal_error!(0); + /// The platform-specific `errno` returned a non-positive value. + pub const ERRNO_NOT_POSITIVE: Error = internal_error!(1); + /// Call to iOS [`SecRandomCopyBytes`](https://developer.apple.com/documentation/security/1399291-secrandomcopybytes) failed. + pub const IOS_SEC_RANDOM: Error = internal_error!(3); + /// Call to Windows [`RtlGenRandom`](https://docs.microsoft.com/en-us/windows/win32/api/ntsecapi/nf-ntsecapi-rtlgenrandom) failed. + pub const WINDOWS_RTL_GEN_RANDOM: Error = internal_error!(4); + /// RDRAND instruction failed due to a hardware issue. + pub const FAILED_RDRAND: Error = internal_error!(5); + /// RDRAND instruction unsupported on this target. + pub const NO_RDRAND: Error = internal_error!(6); + /// Using `wasm-bindgen`, browser does not support `self.crypto`. + pub const BINDGEN_CRYPTO_UNDEF: Error = internal_error!(7); + /// Using `wasm-bindgen`, browser does not support `crypto.getRandomValues`. + pub const BINDGEN_GRV_UNDEF: Error = internal_error!(8); + /// Using `stdweb`, no cryptographic RNG is available. + pub const STDWEB_NO_RNG: Error = internal_error!(9); + /// Using `stdweb`, invoking a cryptographic RNG failed. + pub const STDWEB_RNG_FAILED: Error = internal_error!(10); + /// On VxWorks, call to `randSecure` failed (random number generator is not yet initialized). + pub const VXWORKS_RAND_SECURE: Error = internal_error!(11); /// Codes below this point represent OS Errors (i.e. positive i32 values). /// Codes at or above this point, but below [`Error::CUSTOM_START`] are @@ -38,9 +61,11 @@ impl Error { /// Extract the raw OS error code (if this error came from the OS) /// - /// This method is identical to `std::io::Error::raw_os_error()`, except + /// This method is identical to [`std::io::Error::raw_os_error()`][1], except /// that it works in `no_std` contexts. If this method returns `None`, the /// error value can still be formatted via the `Display` implementation. + /// + /// [1]: https://doc.rust-lang.org/std/io/struct.Error.html#method.raw_os_error #[inline] pub fn raw_os_error(self) -> Option { if self.0.get() < Self::INTERNAL_START { @@ -126,41 +151,19 @@ impl From for Error { } } -// TODO: Convert to a function when min_version >= 1.33 -macro_rules! internal_error { - ($n:expr) => { - Error(unsafe { NonZeroU32::new_unchecked(Error::INTERNAL_START + $n as u16 as u32) }) - }; -} - -/// Internal Error constants -pub(crate) const UNSUPPORTED: Error = internal_error!(0); -pub(crate) const ERRNO_NOT_POSITIVE: Error = internal_error!(1); -pub(crate) const UNKNOWN_IO_ERROR: Error = internal_error!(2); -pub(crate) const SEC_RANDOM_FAILED: Error = internal_error!(3); -pub(crate) const RTL_GEN_RANDOM_FAILED: Error = internal_error!(4); -pub(crate) const FAILED_RDRAND: Error = internal_error!(5); -pub(crate) const NO_RDRAND: Error = internal_error!(6); -pub(crate) const BINDGEN_CRYPTO_UNDEF: Error = internal_error!(7); -pub(crate) const BINDGEN_GRV_UNDEF: Error = internal_error!(8); -pub(crate) const STDWEB_NO_RNG: Error = internal_error!(9); -pub(crate) const STDWEB_RNG_FAILED: Error = internal_error!(10); -pub(crate) const RAND_SECURE_FATAL: Error = internal_error!(11); - fn internal_desc(error: Error) -> Option<&'static str> { match error { - UNSUPPORTED => Some("getrandom: this target is not supported"), - ERRNO_NOT_POSITIVE => Some("errno: did not return a positive value"), - UNKNOWN_IO_ERROR => Some("Unknown std::io::Error"), - SEC_RANDOM_FAILED => Some("SecRandomCopyBytes: call failed"), - RTL_GEN_RANDOM_FAILED => Some("RtlGenRandom: call failed"), - FAILED_RDRAND => Some("RDRAND: failed multiple times: CPU issue likely"), - NO_RDRAND => Some("RDRAND: instruction not supported"), - BINDGEN_CRYPTO_UNDEF => Some("wasm-bindgen: self.crypto is undefined"), - BINDGEN_GRV_UNDEF => Some("wasm-bindgen: crypto.getRandomValues is undefined"), - STDWEB_NO_RNG => Some("stdweb: no randomness source available"), - STDWEB_RNG_FAILED => Some("stdweb: failed to get randomness"), - RAND_SECURE_FATAL => Some("randSecure: random number generator module is not initialized"), + Error::UNSUPPORTED => Some("getrandom: this target is not supported"), + Error::ERRNO_NOT_POSITIVE => Some("errno: did not return a positive value"), + Error::IOS_SEC_RANDOM => Some("SecRandomCopyBytes: iOS Secuirty framework failure"), + Error::WINDOWS_RTL_GEN_RANDOM => Some("RtlGenRandom: Windows system function failure"), + Error::FAILED_RDRAND => Some("RDRAND: failed multiple times: CPU issue likely"), + Error::NO_RDRAND => Some("RDRAND: instruction not supported"), + Error::BINDGEN_CRYPTO_UNDEF => Some("wasm-bindgen: self.crypto is undefined"), + Error::BINDGEN_GRV_UNDEF => Some("wasm-bindgen: crypto.getRandomValues is undefined"), + Error::STDWEB_NO_RNG => Some("stdweb: no randomness source available"), + Error::STDWEB_RNG_FAILED => Some("stdweb: failed to get randomness"), + Error::VXWORKS_RAND_SECURE => Some("randSecure: VxWorks RNG module is not initialized"), _ => None, } } diff --git a/src/error_impls.rs b/src/error_impls.rs index 007472e4..5cb88405 100644 --- a/src/error_impls.rs +++ b/src/error_impls.rs @@ -7,22 +7,10 @@ // except according to those terms. extern crate std; -use crate::{error::UNKNOWN_IO_ERROR, Error}; +use crate::Error; use core::convert::From; -use core::num::NonZeroU32; use std::io; -impl From for Error { - fn from(err: io::Error) -> Self { - if let Some(errno) = err.raw_os_error() { - if let Some(code) = NonZeroU32::new(errno as u32) { - return Error::from(code); - } - } - UNKNOWN_IO_ERROR - } -} - impl From for io::Error { fn from(err: Error) -> Self { match err.raw_os_error() { diff --git a/src/ios.rs b/src/ios.rs index 30c008c2..e940b0a5 100644 --- a/src/ios.rs +++ b/src/ios.rs @@ -7,7 +7,7 @@ // except according to those terms. //! Implementation for iOS -use crate::{error::SEC_RANDOM_FAILED, Error}; +use crate::Error; // TODO: Make extern once extern_types feature is stabilized. See: // https://github.com/rust-lang/rust/issues/43467 @@ -24,7 +24,7 @@ extern "C" { pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> { let ret = unsafe { SecRandomCopyBytes(kSecRandomDefault, dest.len(), dest.as_mut_ptr()) }; if ret == -1 { - Err(SEC_RANDOM_FAILED) + Err(Error::IOS_SEC_RANDOM) } else { Ok(()) } diff --git a/src/lib.rs b/src/lib.rs index 2a2003dc..b11795d5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -243,7 +243,7 @@ cfg_if! { /// In general, `getrandom` will be fast enough for interactive usage, though /// significantly slower than a user-space CSPRNG; for the latter consider /// [`rand::thread_rng`](https://docs.rs/rand/*/rand/fn.thread_rng.html). -pub fn getrandom(dest: &mut [u8]) -> Result<(), error::Error> { +pub fn getrandom(dest: &mut [u8]) -> Result<(), Error> { if dest.is_empty() { return Ok(()); } diff --git a/src/rdrand.rs b/src/rdrand.rs index e4416821..c38ac59d 100644 --- a/src/rdrand.rs +++ b/src/rdrand.rs @@ -7,7 +7,6 @@ // except according to those terms. //! Implementation for SGX using RDRAND instruction -use crate::error::{FAILED_RDRAND, NO_RDRAND}; #[cfg(not(target_feature = "rdrand"))] use crate::util::LazyBool; use crate::Error; @@ -37,7 +36,7 @@ unsafe fn rdrand() -> Result<[u8; WORD_SIZE], Error> { // Keep looping in case this was a false positive. } } - Err(FAILED_RDRAND) + Err(Error::FAILED_RDRAND) } // "rdrand" target feature requires "+rdrnd" flag, see https://github.com/rust-lang/rust/issues/49653. @@ -64,7 +63,7 @@ fn is_rdrand_supported() -> bool { pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> { if !is_rdrand_supported() { - return Err(NO_RDRAND); + return Err(Error::NO_RDRAND); } // SAFETY: After this point, rdrand is supported, so calling the rdrand diff --git a/src/util_libc.rs b/src/util_libc.rs index fde39c9c..3c36e01c 100644 --- a/src/util_libc.rs +++ b/src/util_libc.rs @@ -6,7 +6,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. #![allow(dead_code)] -use crate::error::ERRNO_NOT_POSITIVE; use crate::util::LazyUsize; use crate::Error; use core::num::NonZeroU32; @@ -34,7 +33,7 @@ pub fn last_os_error() -> Error { if errno > 0 { Error::from(NonZeroU32::new(errno as u32).unwrap()) } else { - ERRNO_NOT_POSITIVE + Error::ERRNO_NOT_POSITIVE } } diff --git a/src/vxworks.rs b/src/vxworks.rs index a2fe52ad..79113022 100644 --- a/src/vxworks.rs +++ b/src/vxworks.rs @@ -7,8 +7,8 @@ // except according to those terms. //! Implementation for VxWorks -use crate::error::{Error, RAND_SECURE_FATAL}; use crate::util_libc::last_os_error; +use crate::Error; use core::sync::atomic::{AtomicBool, Ordering::Relaxed}; pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> { @@ -16,7 +16,7 @@ pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> { while !RNG_INIT.load(Relaxed) { let ret = unsafe { libc::randSecure() }; if ret < 0 { - return Err(RAND_SECURE_FATAL); + return Err(Error::VXWORKS_RAND_SECURE); } else if ret > 0 { RNG_INIT.store(true, Relaxed); break; diff --git a/src/wasm32_bindgen.rs b/src/wasm32_bindgen.rs index 86839a09..42d3eda9 100644 --- a/src/wasm32_bindgen.rs +++ b/src/wasm32_bindgen.rs @@ -15,7 +15,6 @@ use std::thread_local; use wasm_bindgen::prelude::*; -use crate::error::{BINDGEN_CRYPTO_UNDEF, BINDGEN_GRV_UNDEF}; use crate::Error; #[derive(Clone, Debug)] @@ -66,13 +65,13 @@ fn getrandom_init() -> Result { let crypto = self_.crypto(); if crypto.is_undefined() { - return Err(BINDGEN_CRYPTO_UNDEF); + return Err(Error::BINDGEN_CRYPTO_UNDEF); } // Test if `crypto.getRandomValues` is undefined as well let crypto: BrowserCrypto = crypto.into(); if crypto.get_random_values_fn().is_undefined() { - return Err(BINDGEN_GRV_UNDEF); + return Err(Error::BINDGEN_GRV_UNDEF); } return Ok(RngSource::Browser(crypto)); diff --git a/src/wasm32_stdweb.rs b/src/wasm32_stdweb.rs index 6e5e78a4..4e79363c 100644 --- a/src/wasm32_stdweb.rs +++ b/src/wasm32_stdweb.rs @@ -10,14 +10,13 @@ extern crate std; use core::mem; +use std::sync::Once; use stdweb::js; use stdweb::unstable::TryInto; use stdweb::web::error::Error as WebError; -use crate::error::{STDWEB_NO_RNG, STDWEB_RNG_FAILED}; use crate::Error; -use std::sync::Once; #[derive(Clone, Copy, Debug)] enum RngSource { @@ -71,7 +70,7 @@ fn getrandom_init() -> Result { } else { let _err: WebError = js! { return @{ result }.error }.try_into().unwrap(); error!("getrandom unavailable: {}", _err); - Err(STDWEB_NO_RNG) + Err(Error::STDWEB_NO_RNG) } } @@ -107,7 +106,7 @@ fn getrandom_fill(source: RngSource, dest: &mut [u8]) -> Result<(), Error> { if js! { return @{ result.as_ref() }.success } != true { let _err: WebError = js! { return @{ result }.error }.try_into().unwrap(); error!("getrandom failed: {}", _err); - return Err(STDWEB_RNG_FAILED); + return Err(Error::STDWEB_RNG_FAILED); } } Ok(()) diff --git a/src/windows.rs b/src/windows.rs index e1b8df66..a5b05659 100644 --- a/src/windows.rs +++ b/src/windows.rs @@ -7,7 +7,7 @@ // except according to those terms. //! Implementation for Windows -use crate::{error::RTL_GEN_RANDOM_FAILED, Error}; +use crate::Error; extern "system" { #[link_name = "SystemFunction036"] @@ -19,7 +19,7 @@ pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> { for chunk in dest.chunks_mut(u32::max_value() as usize) { let ret = unsafe { RtlGenRandom(chunk.as_mut_ptr(), chunk.len() as u32) }; if ret == 0 { - return Err(RTL_GEN_RANDOM_FAILED); + return Err(Error::WINDOWS_RTL_GEN_RANDOM); } } Ok(())