summaryrefslogtreecommitdiffstats
path: root/openpgp
diff options
context:
space:
mode:
authorJustus Winter <justus@sequoia-pgp.org>2023-09-25 10:45:16 +0200
committerJustus Winter <justus@sequoia-pgp.org>2023-09-26 13:39:58 +0200
commit6251bc81f2db3a4a93a02cee3e0883f6a436d47b (patch)
tree05d8a60ab20e64cde49c08c61d4a0860eb5ddc0b /openpgp
parent55b16c4904b9875a68193ca2a15f4a61ad05d9ac (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.rs41
-rw-r--r--openpgp/src/macros.rs35
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)
+ };
+}