diff --git a/src/backends/apple_other.rs b/src/backends/apple_other.rs index 127a31e3..a8c0a24d 100644 --- a/src/backends/apple_other.rs +++ b/src/backends/apple_other.rs @@ -10,6 +10,11 @@ pub fn fill_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { if ret == libc::kCCSuccess { Ok(()) } else { - Err(Error::IOS_SEC_RANDOM) + Err(Error::IOS_RANDOM_GEN) } } + +impl Error { + /// Call to `CCRandomGenerateBytes` failed. + pub(crate) const IOS_RANDOM_GEN: Error = Self::new_internal(10); +} diff --git a/src/backends/rdrand.rs b/src/backends/rdrand.rs index 19fa97ba..67dc7129 100644 --- a/src/backends/rdrand.rs +++ b/src/backends/rdrand.rs @@ -170,3 +170,10 @@ pub fn fill_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { // SAFETY: After this point, we know rdrand is supported. unsafe { rdrand_exact(dest) }.ok_or(Error::FAILED_RDRAND) } + +impl Error { + /// RDRAND instruction failed due to a hardware issue. + pub(crate) const FAILED_RDRAND: Error = Self::new_internal(10); + /// RDRAND instruction unsupported on this target. + pub(crate) const NO_RDRAND: Error = Self::new_internal(11); +} diff --git a/src/backends/rndr.rs b/src/backends/rndr.rs index bd2878f0..7db90355 100644 --- a/src/backends/rndr.rs +++ b/src/backends/rndr.rs @@ -132,3 +132,10 @@ pub fn fill_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { Err(Error::RNDR_NOT_AVAILABLE) } } + +impl Error { + /// RNDR register read failed due to a hardware issue. + pub(crate) const RNDR_FAILURE: Error = Self::new_internal(10); + /// RNDR register is not supported on this target. + pub(crate) const RNDR_NOT_AVAILABLE: Error = Self::new_internal(11); +} diff --git a/src/backends/vxworks.rs b/src/backends/vxworks.rs index 51b7580e..f03ab184 100644 --- a/src/backends/vxworks.rs +++ b/src/backends/vxworks.rs @@ -42,3 +42,8 @@ pub fn fill_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { } Ok(()) } + +impl Error { + /// On VxWorks, call to `randSecure` failed (random number generator is not yet initialized). + pub(crate) const VXWORKS_RAND_SECURE: Error = Self::new_internal(10); +} diff --git a/src/backends/wasm_js.rs b/src/backends/wasm_js.rs index 8556f768..c4943652 100644 --- a/src/backends/wasm_js.rs +++ b/src/backends/wasm_js.rs @@ -65,3 +65,8 @@ extern "C" { #[wasm_bindgen(js_namespace = ["globalThis", "crypto"], js_name = getRandomValues, catch)] fn get_random_values(buf: &js_sys::Uint8Array) -> Result<(), JsValue>; } + +impl Error { + /// The environment does not support the Web Crypto API. + pub(crate) const WEB_CRYPTO: Error = Self::new_internal(10); +} diff --git a/src/backends/windows.rs b/src/backends/windows.rs index 6c8e46b1..76435943 100644 --- a/src/backends/windows.rs +++ b/src/backends/windows.rs @@ -40,3 +40,8 @@ pub fn fill_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { _ => Err(Error::WINDOWS_PROCESS_PRNG), } } + +impl Error { + /// Calling Windows ProcessPrng failed. + pub(crate) const WINDOWS_PROCESS_PRNG: Error = Self::new_internal(10); +} diff --git a/src/backends/windows7.rs b/src/backends/windows7.rs index 2546719e..5b3c86c9 100644 --- a/src/backends/windows7.rs +++ b/src/backends/windows7.rs @@ -37,3 +37,8 @@ pub fn fill_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { } Ok(()) } + +impl Error { + /// Call to Windows [`RtlGenRandom`](https://docs.microsoft.com/en-us/windows/win32/api/ntsecapi/nf-ntsecapi-rtlgenrandom) failed. + pub(crate) const WINDOWS_RTL_GEN_RANDOM: Error = Self::new_internal(10); +} diff --git a/src/error.rs b/src/error.rs index 0c60f929..7449fed3 100644 --- a/src/error.rs +++ b/src/error.rs @@ -27,26 +27,6 @@ impl Error { pub const ERRNO_NOT_POSITIVE: Error = Self::new_internal(1); /// Encountered an unexpected situation which should not happen in practice. pub const UNEXPECTED: Error = Self::new_internal(2); - /// Call to [`CCRandomGenerateBytes`](https://opensource.apple.com/source/CommonCrypto/CommonCrypto-60074/include/CommonRandom.h.auto.html) failed - /// on iOS, tvOS, or waatchOS. - // TODO: Update this constant name in the next breaking release. - pub const IOS_SEC_RANDOM: Error = Self::new_internal(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 = Self::new_internal(4); - /// RDRAND instruction failed due to a hardware issue. - pub const FAILED_RDRAND: Error = Self::new_internal(5); - /// RDRAND instruction unsupported on this target. - pub const NO_RDRAND: Error = Self::new_internal(6); - /// The environment does not support the Web Crypto API. - pub const WEB_CRYPTO: Error = Self::new_internal(7); - /// On VxWorks, call to `randSecure` failed (random number generator is not yet initialized). - pub const VXWORKS_RAND_SECURE: Error = Self::new_internal(11); - /// Calling Windows ProcessPrng failed. - pub const WINDOWS_PROCESS_PRNG: Error = Self::new_internal(12); - /// RNDR register read failed due to a hardware issue. - pub const RNDR_FAILURE: Error = Self::new_internal(13); - /// RNDR register is not supported on this target. - pub const RNDR_NOT_AVAILABLE: Error = Self::new_internal(14); /// Codes below this point represent OS Errors (i.e. positive i32 values). /// Codes at or above this point, but below [`Error::CUSTOM_START`] are @@ -101,11 +81,52 @@ impl Error { } /// Creates a new instance of an `Error` from a particular internal error code. - const fn new_internal(n: u16) -> Error { + pub(crate) const fn new_internal(n: u16) -> Error { // SAFETY: code > 0 as INTERNAL_START > 0 and adding n won't overflow a u32. let code = Error::INTERNAL_START + (n as u32); Error(unsafe { NonZeroU32::new_unchecked(code) }) } + + fn internal_desc(&self) -> Option<&'static str> { + let desc = match *self { + Error::UNSUPPORTED => "getrandom: this target is not supported", + Error::ERRNO_NOT_POSITIVE => "errno: did not return a positive value", + Error::UNEXPECTED => "unexpected situation", + #[cfg(any( + target_os = "ios", + target_os = "visionos", + target_os = "watchos", + target_os = "tvos", + ))] + Error::IOS_RANDOM_GEN => "SecRandomCopyBytes: iOS Security framework failure", + #[cfg(all(windows, not(target_vendor = "win7")))] + Error::WINDOWS_PROCESS_PRNG => "ProcessPrng: Windows system function failure", + #[cfg(all(windows, target_vendor = "win7"))] + Error::WINDOWS_RTL_GEN_RANDOM => "RtlGenRandom: Windows system function failure", + #[cfg(getrandom_backend = "wasm_js")] + Error::WEB_CRYPTO => "Web Crypto API is unavailable", + #[cfg(target_os = "vxworks")] + Error::VXWORKS_RAND_SECURE => "randSecure: VxWorks RNG module is not initialized", + + #[cfg(any( + getrandom_backend = "rdrand", + all(target_arch = "x86_64", target_env = "sgx") + ))] + Error::FAILED_RDRAND => "RDRAND: failed multiple times: CPU issue likely", + #[cfg(any( + getrandom_backend = "rdrand", + all(target_arch = "x86_64", target_env = "sgx") + ))] + Error::NO_RDRAND => "RDRAND: instruction not supported", + + #[cfg(getrandom_backend = "rndr")] + Error::RNDR_FAILURE => "RNDR: Could not generate a random number", + #[cfg(getrandom_backend = "rndr")] + Error::RNDR_NOT_AVAILABLE => "RNDR: Register not supported", + _ => return None, + }; + Some(desc) + } } impl fmt::Debug for Error { @@ -115,7 +136,7 @@ impl fmt::Debug for Error { dbg.field("os_error", &errno); #[cfg(feature = "std")] dbg.field("description", &std::io::Error::from_raw_os_error(errno)); - } else if let Some(desc) = internal_desc(*self) { + } else if let Some(desc) = self.internal_desc() { dbg.field("internal_code", &self.0.get()); dbg.field("description", &desc); } else { @@ -135,7 +156,7 @@ impl fmt::Display for Error { write!(f, "OS Error: {}", errno) } } - } else if let Some(desc) = internal_desc(*self) { + } else if let Some(desc) = self.internal_desc() { f.write_str(desc) } else { write!(f, "Unknown Error: {}", self.0.get()) @@ -143,25 +164,6 @@ impl fmt::Display for Error { } } -fn internal_desc(error: Error) -> Option<&'static str> { - let desc = match error { - Error::UNSUPPORTED => "getrandom: this target is not supported", - Error::ERRNO_NOT_POSITIVE => "errno: did not return a positive value", - Error::UNEXPECTED => "unexpected situation", - Error::IOS_SEC_RANDOM => "SecRandomCopyBytes: iOS Security framework failure", - Error::WINDOWS_RTL_GEN_RANDOM => "RtlGenRandom: Windows system function failure", - Error::FAILED_RDRAND => "RDRAND: failed multiple times: CPU issue likely", - Error::NO_RDRAND => "RDRAND: instruction not supported", - Error::WEB_CRYPTO => "Web Crypto API is unavailable", - Error::VXWORKS_RAND_SECURE => "randSecure: VxWorks RNG module is not initialized", - Error::WINDOWS_PROCESS_PRNG => "ProcessPrng: Windows system function failure", - Error::RNDR_FAILURE => "RNDR: Could not generate a random number", - Error::RNDR_NOT_AVAILABLE => "RNDR: Register not supported", - _ => return None, - }; - Some(desc) -} - #[cfg(test)] mod tests { use super::Error;