Skip to content

Commit

Permalink
Merge pull request #4197 from Rohde-Schwarz/ct/poison_overloads
Browse files Browse the repository at this point in the history
  • Loading branch information
reneme authored Jul 12, 2024
2 parents 1af5545 + 85b06f4 commit 6c92e4b
Show file tree
Hide file tree
Showing 9 changed files with 151 additions and 29 deletions.
4 changes: 2 additions & 2 deletions src/lib/math/bigint/bigint.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -520,11 +520,11 @@ void BigInt::ct_cond_assign(bool predicate, const BigInt& other) {
}

#if defined(BOTAN_HAS_VALGRIND)
void BigInt::const_time_poison() const {
void BigInt::_const_time_poison() const {
CT::poison(m_data.const_data(), m_data.size());
}

void BigInt::const_time_unpoison() const {
void BigInt::_const_time_unpoison() const {
CT::unpoison(m_data.const_data(), m_data.size());
}
#endif
Expand Down
14 changes: 9 additions & 5 deletions src/lib/math/bigint/bigint.h
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ class BOTAN_PUBLIC_API(2, 0) BigInt final {
*/
BigInt(BigInt&& other) { this->swap(other); }

~BigInt() { const_time_unpoison(); }
~BigInt() { _const_time_unpoison(); }

/**
* Move assignment
Expand Down Expand Up @@ -800,13 +800,17 @@ class BOTAN_PUBLIC_API(2, 0) BigInt final {
*/
void cond_flip_sign(bool predicate);

BOTAN_DEPRECATED("replaced by internal API") void const_time_poison() const { _const_time_poison(); }

BOTAN_DEPRECATED("replaced by internal API") void const_time_unpoison() const { _const_time_unpoison(); }

#if defined(BOTAN_HAS_VALGRIND)
void const_time_poison() const;
void const_time_unpoison() const;
void _const_time_poison() const;
void _const_time_unpoison() const;
#else
void const_time_poison() const {}
constexpr void _const_time_poison() const {}

void const_time_unpoison() const {}
constexpr void _const_time_unpoison() const {}
#endif

/**
Expand Down
3 changes: 2 additions & 1 deletion src/lib/math/numbertheory/mod_inv.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,8 @@ BigInt inverse_mod_pow2(const BigInt& a1, size_t k) {
}

X.mask_bits(k);
X.const_time_unpoison();

CT::unpoison(X);
return X;
}

Expand Down
6 changes: 4 additions & 2 deletions src/lib/math/numbertheory/monty.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@

#include <botan/bigint.h>

#include <botan/internal/ct_utils.h>

namespace Botan {

class Modular_Reducer;
Expand Down Expand Up @@ -112,9 +114,9 @@ class BOTAN_TEST_API Montgomery_Int final {

Montgomery_Int& mul_by_8(secure_vector<word>& ws);

void const_time_poison() const { m_v.const_time_poison(); }
void _const_time_poison() const { CT::poison(m_v); }

void const_time_unpoison() const { return m_v.const_time_unpoison(); }
void _const_time_unpoison() const { CT::unpoison(m_v); }

private:
std::shared_ptr<const Montgomery_Params> m_params;
Expand Down
11 changes: 6 additions & 5 deletions src/lib/math/numbertheory/monty_exp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -59,9 +59,10 @@ Montgomery_Exponentation_State::Montgomery_Exponentation_State(const std::shared
// Resize each element to exactly p words
for(size_t i = 0; i != window_size; ++i) {
m_g[i].fix_size();
if(const_time) {
m_g[i].const_time_poison();
}
}

if(const_time) {
CT::poison_range(m_g);
}
}

Expand Down Expand Up @@ -114,7 +115,7 @@ BigInt Montgomery_Exponentation_State::exponentiation(const BigInt& scalar, size
x.mul_by(e_bits, ws);
}

x.const_time_unpoison();
CT::unpoison(x);
return x.value();
}

Expand All @@ -138,7 +139,7 @@ BigInt Montgomery_Exponentation_State::exponentiation_vartime(const BigInt& scal
}
}

x.const_time_unpoison();
CT::unpoison(x);
return x.value();
}

Expand Down
6 changes: 2 additions & 4 deletions src/lib/math/numbertheory/numthry.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -204,8 +204,7 @@ BigInt gcd(const BigInt& a, const BigInt& b) {
u += a;
v += b;

u.const_time_poison();
v.const_time_poison();
CT::poison_all(u, v);

u.set_sign(BigInt::Positive);
v.set_sign(BigInt::Positive);
Expand Down Expand Up @@ -260,8 +259,7 @@ BigInt gcd(const BigInt& a, const BigInt& b) {
// re-apply the factors of two
u.ct_shift_left(factors_of_two);

u.const_time_unpoison();
v.const_time_unpoison();
CT::unpoison_all(u, v);

return u;
}
Expand Down
127 changes: 121 additions & 6 deletions src/lib/utils/ct_utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,13 @@
#ifndef BOTAN_CT_UTILS_H_
#define BOTAN_CT_UTILS_H_

#include <botan/concepts.h>
#include <botan/secmem.h>
#include <botan/internal/bit_ops.h>
#include <botan/internal/stl_util.h>

#include <optional>
#include <span>
#include <type_traits>

#if defined(BOTAN_HAS_VALGRIND)
Expand All @@ -25,6 +29,9 @@

namespace Botan::CT {

/// @name Constant Time Check Annotation Helpers
/// @{

/**
* Use valgrind to mark the contents of memory as being undefined.
* Valgrind will accept operations which manipulate undefined values,
Expand Down Expand Up @@ -64,17 +71,121 @@ constexpr inline void unpoison(const T* p, size_t n) {
BOTAN_UNUSED(p, n);
}

/// @}

/// @name Constant Time Check Annotation Convenience overloads
/// @{

/**
* Poison a single integral object
*/
template <std::integral T>
constexpr void poison(T& p) {
poison(&p, 1);
}

template <std::integral T>
constexpr void unpoison(T& p) {
unpoison(&p, 1);
}

/**
* Poison a contiguous buffer of trivial objects (e.g. integers and such)
*/
template <ranges::spanable_range R>
requires std::is_trivially_copyable_v<std::ranges::range_value_t<R>>
constexpr void poison(R&& r) {
std::span s{r};
poison(s.data(), s.size());
}

template <ranges::spanable_range R>
requires std::is_trivially_copyable_v<std::ranges::range_value_t<R>>
constexpr void unpoison(R&& r) {
std::span s{r};
unpoison(s.data(), s.size());
}

/**
* Poison a class type that provides a public `_const_time_poison()` method
* For instance: BigInt, CT::Mask<>, FrodoMatrix, ...
*/
template <typename T>
constexpr inline void unpoison(T& p) {
#if defined(BOTAN_HAS_VALGRIND)
if(!std::is_constant_evaluated()) {
VALGRIND_MAKE_MEM_DEFINED(&p, sizeof(T));
requires requires(const T& x) { x._const_time_poison(); }
constexpr void poison(const T& x) {
x._const_time_poison();
}

template <typename T>
requires requires(const T& x) { x._const_time_unpoison(); }
constexpr void unpoison(const T& x) {
x._const_time_unpoison();
}

/// @}

/// @name Higher-level Constant Time Check Annotation Helpers
/// @{

template <typename T>
concept poisonable = requires(const T& v) { ::Botan::CT::poison(v); };
template <typename T>
concept unpoisonable = requires(const T& v) { ::Botan::CT::unpoison(v); };

/**
* Poison a range of objects by calling `poison` on each element.
*/
template <std::ranges::range R>
requires poisonable<std::ranges::range_value_t<R>>
constexpr void poison_range(R&& r) {
for(const auto& v : r) {
poison(v);
}
#endif
}

BOTAN_UNUSED(p);
template <std::ranges::range R>
requires unpoisonable<std::ranges::range_value_t<R>>
constexpr void unpoison_range(R&& r) {
for(const auto& v : r) {
unpoison(v);
}
}

/**
* Poisons an arbitrary number of values in a single call.
* Mostly syntactic sugar to save clutter (i.e. lines-of-code).
*/
template <poisonable... Ts>
requires(sizeof...(Ts) > 0)
constexpr void poison_all(Ts&&... ts) {
(poison(ts), ...);
}

template <unpoisonable... Ts>
requires(sizeof...(Ts) > 0)
constexpr void unpoison_all(Ts&&... ts) {
(unpoison(ts), ...);
}

/**
* Poisons an arbitrary number of poisonable values, and unpoisons them when the
* returned object runs out-of-scope
*
* Use this when you want to poison a value that remains valid longer than the
* scope you are currently in. For instance, a private key structure that is a
* member of a Signature_Operation object, that may be used for multiple
* signatures.
*/
template <typename... Ts>
requires(sizeof...(Ts) > 0) && (poisonable<Ts> && ...) && (unpoisonable<Ts> && ...)
[[nodiscard]] constexpr auto scoped_poison(const Ts&... xs) {
auto scope = scoped_cleanup([&] { unpoison_all(xs...); });
poison_all(xs...);
return scope;
}

/// @}

/**
* This function returns its argument, but (if called in a non-constexpr context)
* attempts to prevent the compiler from reasoning about the value or the possible
Expand Down Expand Up @@ -422,6 +533,10 @@ class Mask final {
*/
constexpr T value() const { return value_barrier<T>(m_mask); }

constexpr void _const_time_poison() const { CT::poison(m_mask); }

constexpr void _const_time_unpoison() const { CT::unpoison(m_mask); }

private:
constexpr Mask(T m) : m_mask(m) {}

Expand Down
4 changes: 2 additions & 2 deletions src/lib/utils/stl_util.h
Original file line number Diff line number Diff line change
Expand Up @@ -357,8 +357,8 @@ class scoped_cleanup {

scoped_cleanup(const scoped_cleanup&) = delete;
scoped_cleanup& operator=(const scoped_cleanup&) = delete;
scoped_cleanup(scoped_cleanup&&) = delete;
scoped_cleanup& operator=(scoped_cleanup&&) = delete;
scoped_cleanup(scoped_cleanup&&) = default;
scoped_cleanup& operator=(scoped_cleanup&&) = default;

~scoped_cleanup() {
if(m_cleanup.has_value()) {
Expand Down
5 changes: 3 additions & 2 deletions src/tests/test_bigint.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include <botan/bigint.h>
#include <botan/numthry.h>
#include <botan/reducer.h>
#include <botan/internal/ct_utils.h>
#include <botan/internal/divide.h>
#include <botan/internal/fmt.h>
#include <botan/internal/mp_core.h>
Expand Down Expand Up @@ -553,9 +554,9 @@ Test::Result test_const_time_left_shift() {
for(size_t i = 0; i < bits; ++i) {
auto ct = a;
auto chk = a;
ct.const_time_poison();
Botan::CT::poison(ct);
ct.ct_shift_left(i);
ct.const_time_unpoison();
Botan::CT::unpoison(ct);
chk <<= i;
result.test_eq(Botan::fmt("ct << {}", i), ct, chk);
}
Expand Down

0 comments on commit 6c92e4b

Please sign in to comment.