aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJack Lloyd <[email protected]>2016-01-03 19:56:04 -0500
committerJack Lloyd <[email protected]>2016-01-03 19:56:04 -0500
commit77b8eb8a4ed5f5b63710afd85766e8f30d0bd2d9 (patch)
treed17fcc018b990faaedc523dc6025ca655dcd4805
parent9ec5243e2dc8fba1d024269f1a756af7df0421b8 (diff)
Use valgrind's memcheck API for checking const time annotations
Has the same effect as using ctgrind, but without requiring a custom-compiled valgrind binary. Add ct checking annotations to the SSSE3 AES code.
-rw-r--r--doc/news.rst17
-rw-r--r--src/build-data/buildh.in6
-rw-r--r--src/lib/block/aes_ssse3/aes_ssse3.cpp33
-rw-r--r--src/lib/utils/ct_utils.h41
4 files changed, 74 insertions, 23 deletions
diff --git a/doc/news.rst b/doc/news.rst
index 89f9aa6de..04996a938 100644
--- a/doc/news.rst
+++ b/doc/news.rst
@@ -17,10 +17,10 @@ Version 1.11.26, Not Yet Released
indicating support for the extended master secret flag, which is
needed for proper handling of the extension.
-* Root all exceptions thrown by the library in the `Botan::Exception` class.
- Previously the library would in many cases throw `std::runtime_error`
- or `std::invalid_argument` exceptions which would make it hard to determine
- the source of the error in some cases.
+* Root all exceptions thrown by the library in the ``Botan::Exception`` class.
+ Previously the library would in many cases throw ``std::runtime_error``
+ or ``std::invalid_argument`` exceptions which would make it hard to
+ determine the source of the error in some cases.
* The command line interface has been mostly rewritten. The syntax of
many of the sub-programs has changed, and a number have been
@@ -65,7 +65,7 @@ Version 1.11.26, Not Yet Released
are corner cases where this can occur, such as pointing to the very
end of a buffer.
-* The function `RandomNumberGenerator::gen_mask` (added in 1.11.20)
+* The function ``RandomNumberGenerator::gen_mask`` (added in 1.11.20)
had undefined behavior when called with a bits value of 32 or
higher, and was tested to behave in unpleasant ways (such as
returning zero) when compiled by common compilers. This function was
@@ -73,6 +73,13 @@ Version 1.11.26, Not Yet Released
something without a use case to justify it it seemed simpler to
remove it. Undefined behavior found by Daniel Neus.
+* Support for using ``ctgrind`` for checking const time blocks has
+ been replaced by calling the valgrind memcheck APIs directly. This
+ allows const-time behavior to be tested without requiring a modified
+ valgrind binary. Adding the appropriate calls requires defining
+ BOTAN_HAS_VALGRIND in build.h. A binary compiled with this flag set
+ can still run normally (though with some slight runtime overhead).
+
* Export MGF1 function mgf1_mask GH #380
Version 1.11.25, 2015-12-07
diff --git a/src/build-data/buildh.in b/src/build-data/buildh.in
index 967e067e4..6ee309bdc 100644
--- a/src/build-data/buildh.in
+++ b/src/build-data/buildh.in
@@ -98,10 +98,10 @@
#define BOTAN_PRIVATE_KEY_STRONG_CHECKS_ON_GENERATE 1
/*
-* Define BOTAN_USE_CTGRIND to enable checking constant time
-* annotations using ctgrind https://github.com/agl/ctgrind
+* Define BOTAN_HAS_VALGRIND to enable checking constant time annotations
+* TODO: expose as configure.py flag --with-valgrind
*/
-//#define BOTAN_USE_CTGRIND
+#define BOTAN_HAS_VALGRIND
/*
* RNGs will automatically poll the system for additional seed material
diff --git a/src/lib/block/aes_ssse3/aes_ssse3.cpp b/src/lib/block/aes_ssse3/aes_ssse3.cpp
index bfc76ecee..373a5265a 100644
--- a/src/lib/block/aes_ssse3/aes_ssse3.cpp
+++ b/src/lib/block/aes_ssse3/aes_ssse3.cpp
@@ -1,6 +1,6 @@
/*
* AES using SSSE3
-* (C) 2010 Jack Lloyd
+* (C) 2010,2016 Jack Lloyd
*
* This is more or less a direct translation of public domain x86-64
* assembly written by Mike Hamburg, described in "Accelerating AES
@@ -12,6 +12,7 @@
#include <botan/aes_ssse3.h>
#include <botan/cpuid.h>
+#include <botan/internal/ct_utils.h>
#include <tmmintrin.h>
namespace Botan {
@@ -345,11 +346,16 @@ void AES_128_SSSE3::encrypt_n(const byte in[], byte out[], size_t blocks) const
const __m128i* keys = reinterpret_cast<const __m128i*>(EK.data());
+ CT::poison(in, blocks * block_size());
+
for(size_t i = 0; i != blocks; ++i)
{
__m128i B = _mm_loadu_si128(in_mm + i);
_mm_storeu_si128(out_mm + i, aes_ssse3_encrypt(B, keys, 10));
}
+
+ CT::unpoison(in, blocks * block_size());
+ CT::unpoison(out, blocks * block_size());
}
/*
@@ -362,11 +368,16 @@ void AES_128_SSSE3::decrypt_n(const byte in[], byte out[], size_t blocks) const
const __m128i* keys = reinterpret_cast<const __m128i*>(DK.data());
+ CT::poison(in, blocks * block_size());
+
for(size_t i = 0; i != blocks; ++i)
{
__m128i B = _mm_loadu_si128(in_mm + i);
_mm_storeu_si128(out_mm + i, aes_ssse3_decrypt(B, keys, 10));
}
+
+ CT::unpoison(in, blocks * block_size());
+ CT::unpoison(out, blocks * block_size());
}
/*
@@ -423,11 +434,16 @@ void AES_192_SSSE3::encrypt_n(const byte in[], byte out[], size_t blocks) const
const __m128i* keys = reinterpret_cast<const __m128i*>(EK.data());
+ CT::poison(in, blocks * block_size());
+
for(size_t i = 0; i != blocks; ++i)
{
__m128i B = _mm_loadu_si128(in_mm + i);
_mm_storeu_si128(out_mm + i, aes_ssse3_encrypt(B, keys, 12));
}
+
+ CT::unpoison(in, blocks * block_size());
+ CT::unpoison(out, blocks * block_size());
}
/*
@@ -440,11 +456,16 @@ void AES_192_SSSE3::decrypt_n(const byte in[], byte out[], size_t blocks) const
const __m128i* keys = reinterpret_cast<const __m128i*>(DK.data());
+ CT::poison(in, blocks * block_size());
+
for(size_t i = 0; i != blocks; ++i)
{
__m128i B = _mm_loadu_si128(in_mm + i);
_mm_storeu_si128(out_mm + i, aes_ssse3_decrypt(B, keys, 12));
}
+
+ CT::unpoison(in, blocks * block_size());
+ CT::unpoison(out, blocks * block_size());
}
/*
@@ -530,11 +551,16 @@ void AES_256_SSSE3::encrypt_n(const byte in[], byte out[], size_t blocks) const
const __m128i* keys = reinterpret_cast<const __m128i*>(EK.data());
+ CT::poison(in, blocks * block_size());
+
for(size_t i = 0; i != blocks; ++i)
{
__m128i B = _mm_loadu_si128(in_mm + i);
_mm_storeu_si128(out_mm + i, aes_ssse3_encrypt(B, keys, 14));
}
+
+ CT::unpoison(in, blocks * block_size());
+ CT::unpoison(out, blocks * block_size());
}
/*
@@ -547,11 +573,16 @@ void AES_256_SSSE3::decrypt_n(const byte in[], byte out[], size_t blocks) const
const __m128i* keys = reinterpret_cast<const __m128i*>(DK.data());
+ CT::poison(in, blocks * block_size());
+
for(size_t i = 0; i != blocks; ++i)
{
__m128i B = _mm_loadu_si128(in_mm + i);
_mm_storeu_si128(out_mm + i, aes_ssse3_decrypt(B, keys, 14));
}
+
+ CT::unpoison(in, blocks * block_size());
+ CT::unpoison(out, blocks * block_size());
}
/*
diff --git a/src/lib/utils/ct_utils.h b/src/lib/utils/ct_utils.h
index 2307dd587..a10e242a6 100644
--- a/src/lib/utils/ct_utils.h
+++ b/src/lib/utils/ct_utils.h
@@ -1,12 +1,12 @@
/*
* Functions for constant time operations on data and testing of
-* constant time annotations using ctgrind.
+* constant time annotations using valgrind.
*
* For more information about constant time programming see
* Wagner, Molnar, et al "The Program Counter Security Model"
*
* (C) 2010 Falko Strenzke
-* (C) 2015 Jack Lloyd
+* (C) 2015,2016 Jack Lloyd
*
* Botan is released under the Simplified BSD License (see license.txt)
*/
@@ -17,23 +17,36 @@
#include <botan/secmem.h>
#include <vector>
-#if defined(BOTAN_USE_CTGRIND)
-
-// These are external symbols from libctgrind.so
-extern "C" void ct_poison(const void* address, size_t length);
-extern "C" void ct_unpoison(const void* address, size_t length);
-
+#if defined(BOTAN_HAS_VALGRIND)
+ #include <valgrind/memcheck.h>
#endif
namespace Botan {
namespace CT {
+/**
+* Use valgrind to mark the contents of memory as being undefined.
+* Valgrind will accept operations which manipulate undefined values,
+* but will warn if an undefined value is used to decided a conditional
+* jump or a load/store address. So if we poison all of our inputs we
+* can confirm that the operations in question are truly const time
+* when compiled by whatever compiler is in use.
+*
+* Even better, the VALGRIND_MAKE_MEM_* macros work even when the
+* program is not run under valgrind (though with a few cycles of
+* overhead, which is unfortunate in final binaries as these
+* annotations tend to be used in fairly important loops).
+*
+* This approach was first used in ctgrind (https://github.com/agl/ctgrind)
+* but calling the valgrind mecheck API directly works just as well and
+* doesn't require a custom patched valgrind.
+*/
template<typename T>
-inline void poison(T* p, size_t n)
+inline void poison(const T* p, size_t n)
{
-#if defined(BOTAN_USE_CTGRIND)
- ct_poison(p, sizeof(T)*n);
+#if defined(BOTAN_HAS_VALGRIND)
+ VALGRIND_MAKE_MEM_UNDEFINED(p, n * sizeof(T));
#else
BOTAN_UNUSED(p);
BOTAN_UNUSED(n);
@@ -41,10 +54,10 @@ inline void poison(T* p, size_t n)
}
template<typename T>
-inline void unpoison(T* p, size_t n)
+inline void unpoison(const T* p, size_t n)
{
-#if defined(BOTAN_USE_CTGRIND)
- ct_unpoison(p, sizeof(T)*n);
+#if defined(BOTAN_HAS_VALGRIND)
+ VALGRIND_MAKE_MEM_DEFINED(p, n * sizeof(T));
#else
BOTAN_UNUSED(p);
BOTAN_UNUSED(n);