Revise error types and codes

This commit is contained in:
Diggory Hardy 2019-03-01 11:27:43 +00:00
parent 679c52c23b
commit b771a82ea6
19 changed files with 161 additions and 54 deletions

View File

@ -22,3 +22,6 @@ pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> {
Err(Error::from(code))
}
}
#[inline(always)]
pub fn error_msg_inner(_: NonZeroU32) -> Option<&'static str> { None }

View File

@ -7,11 +7,12 @@
// except according to those terms.
//! Implementation for DragonFly / Haiku
use super::Error;
use super::utils::use_init;
use error::Error;
use utils::use_init;
use std::fs::File;
use std::io::Read;
use std::cell::RefCell;
use std::num::NonZeroU32;
thread_local!(static RNG_FILE: RefCell<Option<File>> = RefCell::new(None));
@ -23,3 +24,6 @@ pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> {
)
})
}
#[inline(always)]
pub fn error_msg_inner(_: NonZeroU32) -> Option<&'static str> { None }

View File

@ -7,9 +7,13 @@
// except according to those terms.
//! A dummy implementation for unsupported targets which always returns
//! `Err(UNAVAILABLE_ERROR)`
use super::UNAVAILABLE_ERROR;
//! `Err(error::UNAVAILABLE)`
use std::num::NonZeroU32;
use error::{Error, UNAVAILABLE};
pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> {
Err(UNAVAILABLE_ERROR)
pub fn getrandom_inner(_: &mut [u8]) -> Result<(), Error> {
Err(UNAVAILABLE)
}
#[inline(always)]
pub fn error_msg_inner(_: NonZeroU32) -> Option<&'static str> { None }

View File

@ -7,11 +7,12 @@
// except according to those terms.
//! Implementation for Emscripten
use super::Error;
use error::Error;
use std::fs::File;
use std::io::Read;
use std::cell::RefCell;
use super::utils::use_init;
use std::num::NonZeroU32;
use utils::use_init;
thread_local!(static RNG_FILE: RefCell<Option<File>> = RefCell::new(None));
@ -29,3 +30,6 @@ pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> {
})
})
}
#[inline(always)]
pub fn error_msg_inner(_: NonZeroU32) -> Option<&'static str> { None }

View File

@ -12,20 +12,25 @@ use core::fmt;
#[cfg(not(target_env = "sgx"))]
use std::{io, error};
// A randomly-chosen 16-bit prefix for our codes
pub(crate) const CODE_PREFIX: u32 = 0x57f40000;
const CODE_UNKNOWN: u32 = CODE_PREFIX | 0;
const CODE_UNAVAILABLE: u32 = CODE_PREFIX | 1;
/// An unknown error.
pub const UNKNOWN_ERROR: Error = Error(unsafe {
NonZeroU32::new_unchecked(0x756e6b6e) // "unkn"
pub const UNKNOWN: Error = Error(unsafe {
NonZeroU32::new_unchecked(CODE_UNKNOWN)
});
/// No generator is available.
pub const UNAVAILABLE_ERROR: Error = Error(unsafe {
NonZeroU32::new_unchecked(0x4e416e61) // "NAna"
pub const UNAVAILABLE: Error = Error(unsafe {
NonZeroU32::new_unchecked(CODE_UNAVAILABLE)
});
/// The error type.
///
/// This type is small and no-std compatible.
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
#[derive(Copy, Clone, Eq, PartialEq)]
pub struct Error(NonZeroU32);
impl Error {
@ -38,14 +43,34 @@ impl Error {
pub fn code(&self) -> NonZeroU32 {
self.0
}
fn msg(&self) -> Option<&'static str> {
if let Some(msg) = super::error_msg_inner(self.0) {
Some(msg)
} else {
match *self {
UNKNOWN => Some("getrandom: unknown error"),
UNAVAILABLE => Some("getrandom: unavailable"),
_ => None
}
}
}
}
impl fmt::Debug for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
match self.msg() {
Some(msg) => write!(f, "Error(\"{}\")", msg),
None => write!(f, "Error({})", self.0.get()),
}
}
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
match *self {
UNKNOWN_ERROR => write!(f, "Getrandom Error: unknown"),
UNAVAILABLE_ERROR => write!(f, "Getrandom Error: unavailable"),
code => write!(f, "Getrandom Error: {}", code.0.get()),
match self.msg() {
Some(msg) => write!(f, "{}", msg),
None => write!(f, "getrandom: unknown code {}", self.0.get()),
}
}
}
@ -63,22 +88,31 @@ impl From<io::Error> for Error {
.and_then(|code| NonZeroU32::new(code as u32))
.map(|code| Error(code))
// in practice this should never happen
.unwrap_or(UNKNOWN_ERROR)
.unwrap_or(UNKNOWN)
}
}
#[cfg(not(target_env = "sgx"))]
impl From<Error> for io::Error {
fn from(err: Error) -> Self {
match err {
UNKNOWN_ERROR => io::Error::new(io::ErrorKind::Other,
"getrandom error: unknown"),
UNAVAILABLE_ERROR => io::Error::new(io::ErrorKind::Other,
"getrandom error: entropy source is unavailable"),
code => io::Error::from_raw_os_error(code.0.get() as i32),
match err.msg() {
Some(msg) => io::Error::new(io::ErrorKind::Other, msg),
None => io::Error::from_raw_os_error(err.0.get() as i32),
}
}
}
#[cfg(not(target_env = "sgx"))]
impl error::Error for Error { }
#[cfg(test)]
mod tests {
use std::mem::size_of;
use super::Error;
#[test]
fn test_size() {
assert_eq!(size_of::<Error>(), 4);
assert_eq!(size_of::<Result<(), Error>>(), 4);
}
}

View File

@ -9,9 +9,10 @@
//! Implementation for FreeBSD
extern crate libc;
use super::Error;
use error::Error;
use core::ptr;
use std::io;
use std::num::NonZeroU32;
pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> {
let mib = [libc::CTL_KERN, libc::KERN_ARND];
@ -30,3 +31,6 @@ pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> {
}
Ok(())
}
#[inline(always)]
pub fn error_msg_inner(_: NonZeroU32) -> Option<&'static str> { None }

View File

@ -9,9 +9,13 @@
//! Implementation for Fuchsia Zircon
extern crate fuchsia_cprng;
use super::Error;
use std::num::NonZeroU32;
use error::Error;
pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> {
fuchsia_cprng::cprng_draw(dest);
Ok(())
}
#[inline(always)]
pub fn error_msg_inner(_: NonZeroU32) -> Option<&'static str> { None }

View File

@ -123,8 +123,7 @@ extern crate wasm_bindgen;
target_arch = "wasm32",
))]
mod utils;
mod error;
pub use error::{Error, UNKNOWN_ERROR, UNAVAILABLE_ERROR};
pub mod error;
// System-specific implementations.
@ -136,7 +135,7 @@ macro_rules! mod_use {
#[$cond]
mod $module;
#[$cond]
use $module::getrandom_inner;
use $module::{getrandom_inner, error_msg_inner};
}
}
@ -221,7 +220,7 @@ mod_use!(
/// 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> {
pub fn getrandom(dest: &mut [u8]) -> Result<(), error::Error> {
getrandom_inner(dest)
}

View File

@ -9,12 +9,13 @@
//! Implementation for Linux / Android
extern crate libc;
use super::Error;
use super::utils::use_init;
use error::Error;
use utils::use_init;
use std::fs::File;
use std::io;
use std::io::Read;
use std::cell::RefCell;
use std::num::NonZeroU32;
use std::sync::atomic::{AtomicBool, Ordering};
static RNG_INIT: AtomicBool = AtomicBool::new(false);
@ -80,3 +81,6 @@ fn is_getrandom_available() -> bool {
AVAILABLE.load(Ordering::Relaxed)
}
#[inline(always)]
pub fn error_msg_inner(_: NonZeroU32) -> Option<&'static str> { None }

View File

@ -9,8 +9,9 @@
//! Implementation for MacOS / iOS
extern crate libc;
use super::Error;
use error::Error;
use std::io;
use std::num::NonZeroU32;
use self::libc::{c_int, size_t};
enum SecRandom {}
@ -40,3 +41,6 @@ pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> {
Ok(())
}
}
#[inline(always)]
pub fn error_msg_inner(_: NonZeroU32) -> Option<&'static str> { None }

View File

@ -8,11 +8,12 @@
//! Implementation for NetBSD
use super::Error;
use super::utils::use_init;
use error::Error;
use utils::use_init;
use std::fs::File;
use std::io::Read;
use std::cell::RefCell;
use std::num::NonZeroU32;
use std::sync::atomic::{AtomicBool, Ordering};
static RNG_INIT: AtomicBool = AtomicBool::new(false);
@ -32,3 +33,6 @@ pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> {
}, |f| f.read_exact(dest).map_err(From::from))
})
}
#[inline(always)]
pub fn error_msg_inner(_: NonZeroU32) -> Option<&'static str> { None }

View File

@ -9,8 +9,9 @@
//! Implementation for OpenBSD / Bitrig
extern crate libc;
use super::Error;
use error::Error;
use std::io;
use std::num::NonZeroU32;
pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> {
for chunk in dest.chunks_mut(256) {
@ -26,3 +27,6 @@ pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> {
}
Ok(())
}
#[inline(always)]
pub fn error_msg_inner(_: NonZeroU32) -> Option<&'static str> { None }

View File

@ -7,11 +7,12 @@
// except according to those terms.
//! Implementation for Redox
use super::Error;
use super::utils::use_init;
use error::Error;
use utils::use_init;
use std::fs::File;
use std::io::Read;
use std::cell::RefCell;
use std::num::NonZeroU32;
thread_local!(static RNG_FILE: RefCell<Option<File>> = RefCell::new(None));
@ -23,3 +24,6 @@ pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> {
)
}).map_err(From::from)
}
#[inline(always)]
pub fn error_msg_inner(_: NonZeroU32) -> Option<&'static str> { None }

View File

@ -7,10 +7,11 @@
// except according to those terms.
//! Implementation for SGX using RDRAND instruction
use super::{Error, UNKNOWN_ERROR};
use error::{Error, UNKNOWN};
use core::{mem, ptr};
use core::arch::x86_64::_rdrand64_step;
use core::num::NonZeroU32;
#[cfg(not(target_feature = "rdrand"))]
compile_error!("enable rdrand target feature!");
@ -26,7 +27,7 @@ fn get_rand_u64() -> Result<u64, Error> {
}
};
}
Err(UNKNOWN_ERROR)
Err(UNKNOWN)
}
pub fn getrandom_inner(mut dest: &mut [u8]) -> Result<(), Error> {
@ -46,3 +47,6 @@ pub fn getrandom_inner(mut dest: &mut [u8]) -> Result<(), Error> {
}
Ok(())
}
#[inline(always)]
pub fn error_msg_inner(_: NonZeroU32) -> Option<&'static str> { None }

View File

@ -19,11 +19,12 @@
//! libc::dlsym.
extern crate libc;
use super::Error;
use error::Error;
use std::cell::RefCell;
use std::fs::File;
use std::io;
use std::io::Read;
use std::num::NonZeroU32;
use utils::use_init;
#[cfg(target_os = "illumos")]
@ -97,3 +98,6 @@ fn fetch_getrandom() -> Option<GetRandomFn> {
let ptr = FPTR.load(Ordering::SeqCst);
unsafe { mem::transmute::<usize, Option<GetRandomFn>>(ptr) }
}
#[inline(always)]
pub fn error_msg_inner(_: NonZeroU32) -> Option<&'static str> { None }

View File

@ -5,7 +5,7 @@
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use super::Error;
use error::Error;
use core::cell::RefCell;
use core::ops::DerefMut;

View File

@ -10,13 +10,17 @@
use std::cell::RefCell;
use std::mem;
use std::num::NonZeroU32;
use wasm_bindgen::prelude::*;
use super::__wbg_shims::*;
use super::{Error, UNAVAILABLE_ERROR};
use super::utils::use_init;
use __wbg_shims::*;
use error::Error;
use utils::use_init;
const CODE_PREFIX: u32 = ::error::CODE_PREFIX | 0x8e00;
const CODE_CRYPTO_UNDEF: u32 = CODE_PREFIX | 1;
const CODE_GRV_UNDEF: u32 = CODE_PREFIX | 2;
#[derive(Clone, Debug)]
pub enum RngSource {
@ -75,18 +79,29 @@ fn getrandom_init() -> Result<RngSource, Error> {
// we're in an older web browser and the OS RNG isn't available.
let crypto = this.crypto();
if crypto.is_undefined() {
let msg = "self.crypto is undefined";
return Err(UNAVAILABLE_ERROR) // TODO: report msg
return Err(Error::from(unsafe {
NonZeroU32::new_unchecked(CODE_CRYPTO_UNDEF)
}));
}
// Test if `crypto.getRandomValues` is undefined as well
let crypto: BrowserCrypto = crypto.into();
if crypto.get_random_values_fn().is_undefined() {
let msg = "crypto.getRandomValues is undefined";
return Err(UNAVAILABLE_ERROR) // TODO: report msg
return Err(Error::from(unsafe {
NonZeroU32::new_unchecked(CODE_GRV_UNDEF)
}));
}
// Ok! `self.crypto.getRandomValues` is a defined value, so let's
// assume we can do browser crypto.
Ok(RngSource::Browser(crypto))
}
#[inline(always)]
pub fn error_msg_inner(n: NonZeroU32) -> Option<&'static str> {
match n.get() {
CODE_CRYPTO_UNDEF => Some("getrandom: self.crypto is undefined"),
CODE_GRV_UNDEF => Some("crypto.getRandomValues is undefined"),
_ => None
}
}

View File

@ -10,12 +10,13 @@
use std::cell::RefCell;
use std::mem;
use std::num::NonZeroU32;
use stdweb::unstable::TryInto;
use stdweb::web::error::Error as WebError;
use super::{Error, UNAVAILABLE_ERROR, UNKNOWN_ERROR};
use super::utils::use_init;
use error::{Error, UNAVAILABLE, UNKNOWN};
use utils::use_init;
#[derive(Clone, Debug)]
enum RngSource {
@ -65,7 +66,7 @@ fn getrandom_init() -> Result<RngSource, Error> {
else { unreachable!() }
} else {
let err: WebError = js!{ return @{ result }.error }.try_into().unwrap();
Err(UNAVAILABLE_ERROR) // TODO: forward err
Err(UNAVAILABLE) // TODO: forward err
}
}
@ -100,8 +101,11 @@ fn getrandom_fill(source: &mut RngSource, dest: &mut [u8]) -> Result<(), Error>
if js!{ return @{ result.as_ref() }.success } != true {
let err: WebError = js!{ return @{ result }.error }.try_into().unwrap();
return Err(UNKNOWN_ERROR) // TODO: forward err
return Err(UNKNOWN) // TODO: forward err
}
}
Ok(())
}
#[inline(always)]
pub fn error_msg_inner(_: NonZeroU32) -> Option<&'static str> { None }

View File

@ -13,7 +13,8 @@ use self::winapi::shared::minwindef::ULONG;
use self::winapi::um::ntsecapi::RtlGenRandom;
use self::winapi::um::winnt::PVOID;
use std::io;
use super::Error;
use std::num::NonZeroU32;
use error::Error;
pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> {
let ret = unsafe {
@ -22,3 +23,6 @@ pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> {
if ret == 0 { return Err(io::Error::last_os_error().into()); }
Ok(())
}
#[inline(always)]
pub fn error_msg_inner(_: NonZeroU32) -> Option<&'static str> { None }