From 1b6a04ca5504955c571d1c97504fb45ea0befee4 Mon Sep 17 00:00:00 2001 From: Valentin Popov Date: Mon, 8 Jan 2024 01:21:28 +0400 Subject: Initial vendor packages Signed-off-by: Valentin Popov --- vendor/zeroize/src/lib.rs | 822 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 822 insertions(+) create mode 100644 vendor/zeroize/src/lib.rs (limited to 'vendor/zeroize/src/lib.rs') diff --git a/vendor/zeroize/src/lib.rs b/vendor/zeroize/src/lib.rs new file mode 100644 index 0000000..b67b5c9 --- /dev/null +++ b/vendor/zeroize/src/lib.rs @@ -0,0 +1,822 @@ +#![no_std] +#![cfg_attr(docsrs, feature(doc_cfg))] +#![doc( + html_logo_url = "https://raw.githubusercontent.com/RustCrypto/media/6ee8e381/logo.svg", + html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/media/6ee8e381/logo.svg" +)] +#![warn(missing_docs, rust_2018_idioms, unused_qualifications)] + +//! Securely zero memory with a simple trait ([`Zeroize`]) built on stable Rust +//! primitives which guarantee the operation will not be "optimized away". +//! +//! ## About +//! +//! [Zeroing memory securely is hard] - compilers optimize for performance, and +//! in doing so they love to "optimize away" unnecessary zeroing calls. There are +//! many documented "tricks" to attempt to avoid these optimizations and ensure +//! that a zeroing routine is performed reliably. +//! +//! This crate isn't about tricks: it uses [`core::ptr::write_volatile`] +//! and [`core::sync::atomic`] memory fences to provide easy-to-use, portable +//! zeroing behavior which works on all of Rust's core number types and slices +//! thereof, implemented in pure Rust with no usage of FFI or assembly. +//! +//! - No insecure fallbacks! +//! - No dependencies! +//! - No FFI or inline assembly! **WASM friendly** (and tested)! +//! - `#![no_std]` i.e. **embedded-friendly**! +//! - No functionality besides securely zeroing memory! +//! - (Optional) Custom derive support for zeroing complex structures +//! +//! ## Minimum Supported Rust Version +//! +//! Requires Rust **1.60** or newer. +//! +//! In the future, we reserve the right to change MSRV (i.e. MSRV is out-of-scope +//! for this crate's SemVer guarantees), however when we do it will be accompanied +//! by a minor version bump. +//! +//! ## Usage +//! +//! ``` +//! use zeroize::Zeroize; +//! +//! fn main() { +//! // Protip: don't embed secrets in your source code. +//! // This is just an example. +//! let mut secret = b"Air shield password: 1,2,3,4,5".to_vec(); +//! // [ ... ] open the air shield here +//! +//! // Now that we're done using the secret, zero it out. +//! secret.zeroize(); +//! } +//! ``` +//! +//! The [`Zeroize`] trait is impl'd on all of Rust's core scalar types including +//! integers, floats, `bool`, and `char`. +//! +//! Additionally, it's implemented on slices and `IterMut`s of the above types. +//! +//! When the `alloc` feature is enabled (which it is by default), it's also +//! impl'd for `Vec` for the above types as well as `String`, where it provides +//! [`Vec::clear`] / [`String::clear`]-like behavior (truncating to zero-length) +//! but ensures the backing memory is securely zeroed with some caveats. +//! +//! With the `std` feature enabled (which it is **not** by default), [`Zeroize`] +//! is also implemented for [`CString`]. After calling `zeroize()` on a `CString`, +//! its internal buffer will contain exactly one nul byte. The backing +//! memory is zeroed by converting it to a `Vec` and back into a `CString`. +//! (NOTE: see "Stack/Heap Zeroing Notes" for important `Vec`/`String`/`CString` details) +//! +//! +//! The [`DefaultIsZeroes`] marker trait can be impl'd on types which also +//! impl [`Default`], which implements [`Zeroize`] by overwriting a value with +//! the default value. +//! +//! ## Custom Derive Support +//! +//! This crate has custom derive support for the `Zeroize` trait, +//! gated under the `zeroize` crate's `zeroize_derive` Cargo feature, +//! which automatically calls `zeroize()` on all members of a struct +//! or tuple struct. +//! +//! Attributes supported for `Zeroize`: +//! +//! On the item level: +//! - `#[zeroize(drop)]`: *deprecated* use `ZeroizeOnDrop` instead +//! - `#[zeroize(bound = "T: MyTrait")]`: this replaces any trait bounds +//! inferred by zeroize +//! +//! On the field level: +//! - `#[zeroize(skip)]`: skips this field or variant when calling `zeroize()` +//! +//! Attributes supported for `ZeroizeOnDrop`: +//! +//! On the field level: +//! - `#[zeroize(skip)]`: skips this field or variant when calling `zeroize()` +//! +//! Example which derives `Drop`: +//! +//! ``` +//! # #[cfg(feature = "zeroize_derive")] +//! # { +//! use zeroize::{Zeroize, ZeroizeOnDrop}; +//! +//! // This struct will be zeroized on drop +//! #[derive(Zeroize, ZeroizeOnDrop)] +//! struct MyStruct([u8; 32]); +//! # } +//! ``` +//! +//! Example which does not derive `Drop` (useful for e.g. `Copy` types) +//! +//! ``` +//! #[cfg(feature = "zeroize_derive")] +//! # { +//! use zeroize::Zeroize; +//! +//! // This struct will *NOT* be zeroized on drop +//! #[derive(Copy, Clone, Zeroize)] +//! struct MyStruct([u8; 32]); +//! # } +//! ``` +//! +//! Example which only derives `Drop`: +//! +//! ``` +//! # #[cfg(feature = "zeroize_derive")] +//! # { +//! use zeroize::ZeroizeOnDrop; +//! +//! // This struct will be zeroized on drop +//! #[derive(ZeroizeOnDrop)] +//! struct MyStruct([u8; 32]); +//! # } +//! ``` +//! +//! ## `Zeroizing`: wrapper for zeroizing arbitrary values on drop +//! +//! `Zeroizing` is a generic wrapper type that impls `Deref` +//! and `DerefMut`, allowing access to an inner value of type `Z`, and also +//! impls a `Drop` handler which calls `zeroize()` on its contents: +//! +//! ``` +//! use zeroize::Zeroizing; +//! +//! fn main() { +//! let mut secret = Zeroizing::new([0u8; 5]); +//! +//! // Set the air shield password +//! // Protip (again): don't embed secrets in your source code. +//! secret.copy_from_slice(&[1, 2, 3, 4, 5]); +//! assert_eq!(secret.as_ref(), &[1, 2, 3, 4, 5]); +//! +//! // The contents of `secret` will be automatically zeroized on drop +//! } +//! ``` +//! +//! ## What guarantees does this crate provide? +//! +//! This crate guarantees the following: +//! +//! 1. The zeroing operation can't be "optimized away" by the compiler. +//! 2. All subsequent reads to memory will see "zeroized" values. +//! +//! LLVM's volatile semantics ensure #1 is true. +//! +//! Additionally, thanks to work by the [Unsafe Code Guidelines Working Group], +//! we can now fairly confidently say #2 is true as well. Previously there were +//! worries that the approach used by this crate (mixing volatile and +//! non-volatile accesses) was undefined behavior due to language contained +//! in the documentation for `write_volatile`, however after some discussion +//! [these remarks have been removed] and the specific usage pattern in this +//! crate is considered to be well-defined. +//! +//! Additionally this crate leverages [`core::sync::atomic::compiler_fence`] +//! with the strictest ordering +//! ([`Ordering::SeqCst`]) as a +//! precaution to help ensure reads are not reordered before memory has been +//! zeroed. +//! +//! All of that said, there is still potential for microarchitectural attacks +//! (ala Spectre/Meltdown) to leak "zeroized" secrets through covert channels. +//! This crate makes no guarantees that zeroized values cannot be leaked +//! through such channels, as they represent flaws in the underlying hardware. +//! +//! ## Stack/Heap Zeroing Notes +//! +//! This crate can be used to zero values from either the stack or the heap. +//! +//! However, be aware several operations in Rust can unintentionally leave +//! copies of data in memory. This includes but is not limited to: +//! +//! - Moves and [`Copy`] +//! - Heap reallocation when using [`Vec`] and [`String`] +//! - Borrowers of a reference making copies of the data +//! +//! [`Pin`][`core::pin::Pin`] can be leveraged in conjunction with this crate +//! to ensure data kept on the stack isn't moved. +//! +//! The `Zeroize` impls for `Vec`, `String` and `CString` zeroize the entire +//! capacity of their backing buffer, but cannot guarantee copies of the data +//! were not previously made by buffer reallocation. It's therefore important +//! when attempting to zeroize such buffers to initialize them to the correct +//! capacity, and take care to prevent subsequent reallocation. +//! +//! The `secrecy` crate provides higher-level abstractions for eliminating +//! usage patterns which can cause reallocations: +//! +//! +//! +//! ## What about: clearing registers, mlock, mprotect, etc? +//! +//! This crate is focused on providing simple, unobtrusive support for reliably +//! zeroing memory using the best approach possible on stable Rust. +//! +//! Clearing registers is a difficult problem that can't easily be solved by +//! something like a crate, and requires either inline ASM or rustc support. +//! See for background on +//! this particular problem. +//! +//! Other memory protection mechanisms are interesting and useful, but often +//! overkill (e.g. defending against RAM scraping or attackers with swap access). +//! In as much as there may be merit to these approaches, there are also many +//! other crates that already implement more sophisticated memory protections. +//! Such protections are explicitly out-of-scope for this crate. +//! +//! Zeroing memory is [good cryptographic hygiene] and this crate seeks to promote +//! it in the most unobtrusive manner possible. This includes omitting complex +//! `unsafe` memory protection systems and just trying to make the best memory +//! zeroing crate available. +//! +//! [Zeroing memory securely is hard]: http://www.daemonology.net/blog/2014-09-04-how-to-zero-a-buffer.html +//! [Unsafe Code Guidelines Working Group]: https://github.com/rust-lang/unsafe-code-guidelines +//! [these remarks have been removed]: https://github.com/rust-lang/rust/pull/60972 +//! [good cryptographic hygiene]: https://github.com/veorq/cryptocoding#clean-memory-of-secret-data +//! [`Ordering::SeqCst`]: core::sync::atomic::Ordering::SeqCst + +#[cfg(feature = "alloc")] +extern crate alloc; + +#[cfg(feature = "std")] +extern crate std; + +#[cfg(feature = "zeroize_derive")] +#[cfg_attr(docsrs, doc(cfg(feature = "zeroize_derive")))] +pub use zeroize_derive::{Zeroize, ZeroizeOnDrop}; + +#[cfg(all(feature = "aarch64", target_arch = "aarch64"))] +mod aarch64; +#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] +mod x86; + +use core::{ + marker::{PhantomData, PhantomPinned}, + mem::{self, MaybeUninit}, + num::{ + self, NonZeroI128, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI8, NonZeroIsize, + NonZeroU128, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8, NonZeroUsize, + }, + ops, ptr, + slice::IterMut, + sync::atomic, +}; + +#[cfg(feature = "alloc")] +use alloc::{boxed::Box, string::String, vec::Vec}; + +#[cfg(feature = "std")] +use std::ffi::CString; + +/// Trait for securely erasing values from memory. +pub trait Zeroize { + /// Zero out this object from memory using Rust intrinsics which ensure the + /// zeroization operation is not "optimized away" by the compiler. + fn zeroize(&mut self); +} + +/// Marker trait signifying that this type will [`Zeroize::zeroize`] itself on [`Drop`]. +pub trait ZeroizeOnDrop {} + +/// Marker trait for types whose [`Default`] is the desired zeroization result +pub trait DefaultIsZeroes: Copy + Default + Sized {} + +/// Fallible trait for representing cases where zeroization may or may not be +/// possible. +/// +/// This is primarily useful for scenarios like reference counted data, where +/// zeroization is only possible when the last reference is dropped. +pub trait TryZeroize { + /// Try to zero out this object from memory using Rust intrinsics which + /// ensure the zeroization operation is not "optimized away" by the + /// compiler. + #[must_use] + fn try_zeroize(&mut self) -> bool; +} + +impl Zeroize for Z +where + Z: DefaultIsZeroes, +{ + fn zeroize(&mut self) { + volatile_write(self, Z::default()); + atomic_fence(); + } +} + +macro_rules! impl_zeroize_with_default { + ($($type:ty),+) => { + $(impl DefaultIsZeroes for $type {})+ + }; +} + +#[rustfmt::skip] +impl_zeroize_with_default! { + PhantomPinned, (), bool, char, + f32, f64, + i8, i16, i32, i64, i128, isize, + u8, u16, u32, u64, u128, usize +} + +/// `PhantomPinned` is zero sized so provide a ZeroizeOnDrop implementation. +impl ZeroizeOnDrop for PhantomPinned {} + +/// `()` is zero sized so provide a ZeroizeOnDrop implementation. +impl ZeroizeOnDrop for () {} + +macro_rules! impl_zeroize_for_non_zero { + ($($type:ty),+) => { + $( + impl Zeroize for $type { + fn zeroize(&mut self) { + const ONE: $type = match <$type>::new(1) { + Some(one) => one, + None => unreachable!(), + }; + volatile_write(self, ONE); + atomic_fence(); + } + } + )+ + }; +} + +impl_zeroize_for_non_zero!( + NonZeroI8, + NonZeroI16, + NonZeroI32, + NonZeroI64, + NonZeroI128, + NonZeroIsize, + NonZeroU8, + NonZeroU16, + NonZeroU32, + NonZeroU64, + NonZeroU128, + NonZeroUsize +); + +impl Zeroize for num::Wrapping +where + Z: Zeroize, +{ + fn zeroize(&mut self) { + self.0.zeroize(); + } +} + +/// Impl [`Zeroize`] on arrays of types that impl [`Zeroize`]. +impl Zeroize for [Z; N] +where + Z: Zeroize, +{ + fn zeroize(&mut self) { + self.iter_mut().zeroize(); + } +} + +/// Impl [`ZeroizeOnDrop`] on arrays of types that impl [`ZeroizeOnDrop`]. +impl ZeroizeOnDrop for [Z; N] where Z: ZeroizeOnDrop {} + +impl Zeroize for IterMut<'_, Z> +where + Z: Zeroize, +{ + fn zeroize(&mut self) { + for elem in self { + elem.zeroize(); + } + } +} + +impl Zeroize for Option +where + Z: Zeroize, +{ + fn zeroize(&mut self) { + if let Some(value) = self { + value.zeroize(); + + // Ensures self is None and that the value was dropped. Without the take, the drop + // of the (zeroized) value isn't called, which might lead to a leak or other + // unexpected behavior. For example, if this were Option>, the above call to + // zeroize would not free the allocated memory, but the the `take` call will. + self.take(); + } + + // Ensure that if the `Option` were previously `Some` but a value was copied/moved out + // that the remaining space in the `Option` is zeroized. + // + // Safety: + // + // The memory pointed to by `self` is valid for `mem::size_of::()` bytes. + // It is also properly aligned, because `u8` has an alignment of `1`. + unsafe { + volatile_set((self as *mut Self).cast::(), 0, mem::size_of::()); + } + + // Ensures self is overwritten with the `None` bit pattern. volatile_write can't be + // used because Option is not copy. + // + // Safety: + // + // self is safe to replace with `None`, which the take() call above should have + // already done semantically. Any value which needed to be dropped will have been + // done so by take(). + unsafe { ptr::write_volatile(self, None) } + + atomic_fence(); + } +} + +impl ZeroizeOnDrop for Option where Z: ZeroizeOnDrop {} + +/// Impl [`Zeroize`] on [`MaybeUninit`] types. +/// +/// This fills the memory with zeroes. +/// Note that this ignore invariants that `Z` might have, because +/// [`MaybeUninit`] removes all invariants. +impl Zeroize for MaybeUninit { + fn zeroize(&mut self) { + // Safety: + // `MaybeUninit` is valid for any byte pattern, including zeros. + unsafe { ptr::write_volatile(self, MaybeUninit::zeroed()) } + atomic_fence(); + } +} + +/// Impl [`Zeroize`] on slices of [`MaybeUninit`] types. +/// +/// This impl can eventually be optimized using an memset intrinsic, +/// such as [`core::intrinsics::volatile_set_memory`]. +/// +/// This fills the slice with zeroes. +/// +/// Note that this ignore invariants that `Z` might have, because +/// [`MaybeUninit`] removes all invariants. +impl Zeroize for [MaybeUninit] { + fn zeroize(&mut self) { + let ptr = self.as_mut_ptr().cast::>(); + let size = self.len().checked_mul(mem::size_of::()).unwrap(); + assert!(size <= isize::MAX as usize); + + // Safety: + // + // This is safe, because every valid pointer is well aligned for u8 + // and it is backed by a single allocated object for at least `self.len() * size_pf::()` bytes. + // and 0 is a valid value for `MaybeUninit` + // The memory of the slice should not wrap around the address space. + unsafe { volatile_set(ptr, MaybeUninit::zeroed(), size) } + atomic_fence(); + } +} + +/// Impl [`Zeroize`] on slices of types that can be zeroized with [`Default`]. +/// +/// This impl can eventually be optimized using an memset intrinsic, +/// such as [`core::intrinsics::volatile_set_memory`]. For that reason the +/// blanket impl on slices is bounded by [`DefaultIsZeroes`]. +/// +/// To zeroize a mut slice of `Z: Zeroize` which does not impl +/// [`DefaultIsZeroes`], call `iter_mut().zeroize()`. +impl Zeroize for [Z] +where + Z: DefaultIsZeroes, +{ + fn zeroize(&mut self) { + assert!(self.len() <= isize::MAX as usize); + + // Safety: + // + // This is safe, because the slice is well aligned and is backed by a single allocated + // object for at least `self.len()` elements of type `Z`. + // `self.len()` is also not larger than an `isize`, because of the assertion above. + // The memory of the slice should not wrap around the address space. + unsafe { volatile_set(self.as_mut_ptr(), Z::default(), self.len()) }; + atomic_fence(); + } +} + +impl Zeroize for str { + fn zeroize(&mut self) { + // Safety: + // A zeroized byte slice is a valid UTF-8 string. + unsafe { self.as_bytes_mut().zeroize() } + } +} + +/// [`PhantomData`] is always zero sized so provide a [`Zeroize`] implementation. +impl Zeroize for PhantomData { + fn zeroize(&mut self) {} +} + +/// [`PhantomData` is always zero sized so provide a ZeroizeOnDrop implementation. +impl ZeroizeOnDrop for PhantomData {} + +macro_rules! impl_zeroize_tuple { + ( $( $type_name:ident ),+ ) => { + impl<$($type_name: Zeroize),+> Zeroize for ($($type_name,)+) { + fn zeroize(&mut self) { + #[allow(non_snake_case)] + let ($($type_name,)+) = self; + $($type_name.zeroize());+ + } + } + + impl<$($type_name: ZeroizeOnDrop),+> ZeroizeOnDrop for ($($type_name,)+) { } + } +} + +// Generic implementations for tuples up to 10 parameters. +impl_zeroize_tuple!(A); +impl_zeroize_tuple!(A, B); +impl_zeroize_tuple!(A, B, C); +impl_zeroize_tuple!(A, B, C, D); +impl_zeroize_tuple!(A, B, C, D, E); +impl_zeroize_tuple!(A, B, C, D, E, F); +impl_zeroize_tuple!(A, B, C, D, E, F, G); +impl_zeroize_tuple!(A, B, C, D, E, F, G, H); +impl_zeroize_tuple!(A, B, C, D, E, F, G, H, I); +impl_zeroize_tuple!(A, B, C, D, E, F, G, H, I, J); + +#[cfg(feature = "alloc")] +#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] +impl Zeroize for Vec +where + Z: Zeroize, +{ + /// "Best effort" zeroization for `Vec`. + /// + /// Ensures the entire capacity of the `Vec` is zeroed. Cannot ensure that + /// previous reallocations did not leave values on the heap. + fn zeroize(&mut self) { + // Zeroize all the initialized elements. + self.iter_mut().zeroize(); + + // Set the Vec's length to 0 and drop all the elements. + self.clear(); + + // Zero the full capacity of `Vec`. + self.spare_capacity_mut().zeroize(); + } +} + +#[cfg(feature = "alloc")] +#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] +impl ZeroizeOnDrop for Vec where Z: ZeroizeOnDrop {} + +#[cfg(feature = "alloc")] +#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] +impl Zeroize for Box<[Z]> +where + Z: Zeroize, +{ + /// Unlike `Vec`, `Box<[Z]>` cannot reallocate, so we can be sure that we are not leaving + /// values on the heap. + fn zeroize(&mut self) { + self.iter_mut().zeroize(); + } +} + +#[cfg(feature = "alloc")] +#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] +impl ZeroizeOnDrop for Box<[Z]> where Z: ZeroizeOnDrop {} + +#[cfg(feature = "alloc")] +#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] +impl Zeroize for Box { + fn zeroize(&mut self) { + self.as_mut().zeroize(); + } +} + +#[cfg(feature = "alloc")] +#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] +impl Zeroize for String { + fn zeroize(&mut self) { + unsafe { self.as_mut_vec() }.zeroize(); + } +} + +#[cfg(feature = "std")] +#[cfg_attr(docsrs, doc(cfg(feature = "std")))] +impl Zeroize for CString { + fn zeroize(&mut self) { + // mem::take uses replace internally to swap the pointer + // Unfortunately this results in an allocation for a Box::new(&[0]) as CString must + // contain a trailing zero byte + let this = mem::take(self); + + // - CString::into_bytes_with_nul calls ::into_vec which takes ownership of the heap pointer + // as a Vec + // - Calling .zeroize() on the resulting vector clears out the bytes + // From: https://github.com/RustCrypto/utils/pull/759#issuecomment-1087976570 + let mut buf = this.into_bytes_with_nul(); + buf.zeroize(); + + // expect() should never fail, because zeroize() truncates the Vec + let zeroed = CString::new(buf).expect("buf not truncated"); + + // Replace self by the zeroed CString to maintain the original ptr of the buffer + let _ = mem::replace(self, zeroed); + } +} + +/// `Zeroizing` is a a wrapper for any `Z: Zeroize` type which implements a +/// `Drop` handler which zeroizes dropped values. +#[derive(Debug, Default, Eq, PartialEq)] +pub struct Zeroizing(Z); + +impl Zeroizing +where + Z: Zeroize, +{ + /// Move value inside a `Zeroizing` wrapper which ensures it will be + /// zeroized when it's dropped. + #[inline(always)] + pub fn new(value: Z) -> Self { + Self(value) + } +} + +impl Clone for Zeroizing { + #[inline(always)] + fn clone(&self) -> Self { + Self(self.0.clone()) + } + + #[inline(always)] + fn clone_from(&mut self, source: &Self) { + self.0.zeroize(); + self.0.clone_from(&source.0); + } +} + +impl From for Zeroizing +where + Z: Zeroize, +{ + #[inline(always)] + fn from(value: Z) -> Zeroizing { + Zeroizing(value) + } +} + +impl ops::Deref for Zeroizing +where + Z: Zeroize, +{ + type Target = Z; + + #[inline(always)] + fn deref(&self) -> &Z { + &self.0 + } +} + +impl ops::DerefMut for Zeroizing +where + Z: Zeroize, +{ + #[inline(always)] + fn deref_mut(&mut self) -> &mut Z { + &mut self.0 + } +} + +impl AsRef for Zeroizing +where + T: ?Sized, + Z: AsRef + Zeroize, +{ + #[inline(always)] + fn as_ref(&self) -> &T { + self.0.as_ref() + } +} + +impl AsMut for Zeroizing +where + T: ?Sized, + Z: AsMut + Zeroize, +{ + #[inline(always)] + fn as_mut(&mut self) -> &mut T { + self.0.as_mut() + } +} + +impl Zeroize for Zeroizing +where + Z: Zeroize, +{ + fn zeroize(&mut self) { + self.0.zeroize(); + } +} + +impl ZeroizeOnDrop for Zeroizing where Z: Zeroize {} + +impl Drop for Zeroizing +where + Z: Zeroize, +{ + fn drop(&mut self) { + self.0.zeroize() + } +} + +#[cfg(feature = "serde")] +impl serde::Serialize for Zeroizing +where + Z: Zeroize + serde::Serialize, +{ + #[inline(always)] + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + self.0.serialize(serializer) + } +} + +#[cfg(feature = "serde")] +impl<'de, Z> serde::Deserialize<'de> for Zeroizing +where + Z: Zeroize + serde::Deserialize<'de>, +{ + #[inline(always)] + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + Ok(Self(Z::deserialize(deserializer)?)) + } +} + +/// Use fences to prevent accesses from being reordered before this +/// point, which should hopefully help ensure that all accessors +/// see zeroes after this point. +#[inline(always)] +fn atomic_fence() { + atomic::compiler_fence(atomic::Ordering::SeqCst); +} + +/// Perform a volatile write to the destination +#[inline(always)] +fn volatile_write(dst: &mut T, src: T) { + unsafe { ptr::write_volatile(dst, src) } +} + +/// Perform a volatile `memset` operation which fills a slice with a value +/// +/// Safety: +/// The memory pointed to by `dst` must be a single allocated object that is valid for `count` +/// contiguous elements of `T`. +/// `count` must not be larger than an `isize`. +/// `dst` being offset by `mem::size_of:: * count` bytes must not wrap around the address space. +/// Also `dst` must be properly aligned. +#[inline(always)] +unsafe fn volatile_set(dst: *mut T, src: T, count: usize) { + // TODO(tarcieri): use `volatile_set_memory` when stabilized + for i in 0..count { + // Safety: + // + // This is safe because there is room for at least `count` objects of type `T` in the + // allocation pointed to by `dst`, because `count <= isize::MAX` and because + // `dst.add(count)` must not wrap around the address space. + let ptr = dst.add(i); + + // Safety: + // + // This is safe, because the pointer is valid and because `dst` is well aligned for `T` and + // `ptr` is an offset of `dst` by a multiple of `mem::size_of::()` bytes. + ptr::write_volatile(ptr, src); + } +} + +/// Internal module used as support for `AssertZeroizeOnDrop`. +#[doc(hidden)] +pub mod __internal { + use super::*; + + /// Auto-deref workaround for deriving `ZeroizeOnDrop`. + pub trait AssertZeroizeOnDrop { + fn zeroize_or_on_drop(self); + } + + impl AssertZeroizeOnDrop for &&mut T { + fn zeroize_or_on_drop(self) {} + } + + /// Auto-deref workaround for deriving `ZeroizeOnDrop`. + pub trait AssertZeroize { + fn zeroize_or_on_drop(&mut self); + } + + impl AssertZeroize for T { + fn zeroize_or_on_drop(&mut self) { + self.zeroize() + } + } +} -- cgit v1.2.3