diff options
author | Justus Winter <justus@sequoia-pgp.org> | 2023-09-25 10:45:16 +0200 |
---|---|---|
committer | Justus Winter <justus@sequoia-pgp.org> | 2023-09-26 13:39:58 +0200 |
commit | 6251bc81f2db3a4a93a02cee3e0883f6a436d47b (patch) | |
tree | 05d8a60ab20e64cde49c08c61d4a0860eb5ddc0b /openpgp | |
parent | 55b16c4904b9875a68193ca2a15f4a61ad05d9ac (diff) |
openpgp: More ergonomic and robust interface to zero stacks.
- This is only effective if the value is computed by a function that
is never inlined. Add a macro that takes care of that.
Diffstat (limited to 'openpgp')
-rw-r--r-- | openpgp/src/crypto/mem.rs | 41 | ||||
-rw-r--r-- | openpgp/src/macros.rs | 35 |
2 files changed, 76 insertions, 0 deletions
diff --git a/openpgp/src/crypto/mem.rs b/openpgp/src/crypto/mem.rs index c86c6731..5c0580da 100644 --- a/openpgp/src/crypto/mem.rs +++ b/openpgp/src/crypto/mem.rs @@ -24,6 +24,8 @@ use std::fmt; use std::hash::{Hash, Hasher}; use std::ops::{Deref, DerefMut}; +/// Whether to trace execution by default (on stderr). +const TRACE: bool = false; /// Protected memory. /// @@ -152,10 +154,49 @@ impl From<Vec<u8>> for Protected { } } +/// Zeros N bytes on the stack after running the given closure. +/// +/// Note: In general, don't use this function directly, use the more +/// convenient and robust macro zero_stack! instead, like so: +/// +/// ```ignore +/// zero_stack!(128 bytes after running { +/// let mut a = [0; 6]; +/// a.copy_from_slice(b"secret"); +/// }) +/// ``` +/// +/// Or, if you need to specify the type of the expression: +/// +/// ```ignore +/// zero_stack!(128 bytes after running || -> () { +/// let mut a = [0; 6]; +/// a.copy_from_slice(b"secret"); +/// }) +/// ``` +/// +/// If you must use this function directly, make sure to declare `fun` +/// as `#[inline(never)]`. +#[allow(dead_code)] +#[inline(never)] +pub(crate) fn zero_stack_after<const N: usize, T>(fun: impl FnOnce() -> T) -> T +{ + zero_stack::<N, T>(fun()) +} + /// Zeros N bytes on the stack, returning the given value. +/// +/// Note: In general, don't use this function directly. This is only +/// effective if `v` has been computed by a function that has been +/// marked as `#[inline(never)]`. However, since the inline attribute +/// is only a hint that may be freely ignored by the compiler, it is +/// sometimes necessary to use this function directly. #[allow(dead_code)] +#[inline(never)] pub(crate) fn zero_stack<const N: usize, T>(v: T) -> T { + tracer!(TRACE, "zero_stack"); let mut a = [0xffu8; N]; + t!("zeroing {:?}..{:?}", a.as_ptr(), unsafe { a.as_ptr().offset(N as _) }); unsafe { memsec::memzero(a.as_mut_ptr(), a.len()); } diff --git a/openpgp/src/macros.rs b/openpgp/src/macros.rs index aa316480..3858618c 100644 --- a/openpgp/src/macros.rs +++ b/openpgp/src/macros.rs @@ -232,3 +232,38 @@ mod test_assert_send_and_sync { } assert_send_and_sync!(MyWriterWithLifetime<'_, C, W> where C, W: std::io::Write); } + +/// Zeros the stack after executing a block of code. +/// +/// These are more convenient and more robust ways of using +/// crypto::mem::zero_stack and crypto::mem::zero_stack_after. You +/// should prefer this macro over using the functions directly. +/// +/// # Examples +/// +/// ```ignore +/// zero_stack!(128 bytes after running { +/// let mut a = [0; 6]; +/// a.copy_from_slice(b"secret"); +/// }) +/// ``` +/// +/// Or, if you need to specify the type of the expression: +/// +/// ```ignore +/// zero_stack!(128 bytes after running || -> () { +/// let mut a = [0; 6]; +/// a.copy_from_slice(b"secret"); +/// }) +/// ``` +#[allow(unused_macros)] +macro_rules! zero_stack { + ($n:literal bytes after running || -> $t:ty $code:block) => { + crate::crypto::mem::zero_stack_after::<$n, _>( + #[inline(never)] || -> $t { $code }) + }; + ($n:literal bytes after running $code:block) => { + crate::crypto::mem::zero_stack_after::<$n, _>( + #[inline(never)] || $code) + }; +} |