Merge bitcoin-core/secp256k1#1579: Clear sensitive memory without getting optimized out (revival of #636)
765ef53335Clear _gej instances after point multiplication to avoid potential leaks (Sebastian Falbesoner)349e6ab916Introduce separate _clear functions for hash module (Tim Ruffing)99cc9fd6d0Don't rely on memset to set signed integers to 0 (Tim Ruffing)97c57f42baImplement various _clear() functions with secp256k1_memclear() (Tim Ruffing)9bb368d146Use secp256k1_memclear() to clear stack memory instead of memset() (Tim Ruffing)e3497bbf00Separate between clearing memory and setting to zero in tests (Tim Ruffing)d79a6ccd43Separate secp256k1_fe_set_int( . , 0 ) from secp256k1_fe_clear() (Tim Ruffing)1c08126222Add secp256k1_memclear() for clearing secret data (Tim Ruffing)e7d384488eDon't clear secrets in pippenger implementation (Tim Ruffing) Pull request description: This PR picks up #636 (which in turn picked up #448, so this is take number three) and is essentially a rebase on master. Some changes to the original PR: * the clearing function now has the `secp256k1_` prefix again, since the related helper `_memczero` got it as well (see PR #835 / commite89278f211) * the original commit b17a7df8145a6a86d49c354c7e7b59a432ea5346 ("Make _set_fe_int( . , 0 ) set magnitude to 0") is not needed anymore, since it was already applied in PR #943 (commitd49011f54c) * clearing of stack memory with `secp256k1_memclear` is now also done on modules that have been newly introduced since then, i.e. schnorr and ellswift (of course, there is still no guarantee that all places where clearing is necessary are covered) So far I haven't looked at any disassembly and possible performance implications yet (there were some concerns expressed in https://github.com/bitcoin-core/secp256k1/pull/636#issuecomment-620118629), happy to go deeper there if this gets Concept ACKed. The proposed method of using a memory barrier to prevent optimizating away the memset is still used in BoringSSL (where it was originally picked up from) and in the Linux Kernel, see e.g.5af122c3df/crypto/mem.c (L335)andd456068672/include/linux/string.h (L348)/d456068672/include/linux/compiler.h (L102)Fixes #185. ACKs for top commit: sipa: reACK765ef53335real-or-random: ACK765ef53335Tree-SHA512: 5a034d5ad14178c06928022459f3d4f0877d06f576b24ab07b86b3608b0b3e9273217b8309a1db606f024f3032731f13013114b1e0828964b578814d1efb2959
This commit is contained in:
36
src/util.h
36
src/util.h
@@ -8,11 +8,17 @@
|
||||
#define SECP256K1_UTIL_H
|
||||
|
||||
#include "../include/secp256k1.h"
|
||||
#include "checkmem.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <limits.h>
|
||||
#if defined(_MSC_VER)
|
||||
/* For SecureZeroMemory */
|
||||
#include <Windows.h>
|
||||
#endif
|
||||
|
||||
#define STR_(x) #x
|
||||
#define STR(x) STR_(x)
|
||||
@@ -213,6 +219,34 @@ static SECP256K1_INLINE void secp256k1_memczero(void *s, size_t len, int flag) {
|
||||
}
|
||||
}
|
||||
|
||||
/* Cleanses memory to prevent leaking sensitive info. Won't be optimized out. */
|
||||
static SECP256K1_INLINE void secp256k1_memclear(void *ptr, size_t len) {
|
||||
#if defined(_MSC_VER)
|
||||
/* SecureZeroMemory is guaranteed not to be optimized out by MSVC. */
|
||||
SecureZeroMemory(ptr, len);
|
||||
#elif defined(__GNUC__)
|
||||
/* We use a memory barrier that scares the compiler away from optimizing out the memset.
|
||||
*
|
||||
* Quoting Adam Langley <agl@google.com> in commit ad1907fe73334d6c696c8539646c21b11178f20f
|
||||
* in BoringSSL (ISC License):
|
||||
* As best as we can tell, this is sufficient to break any optimisations that
|
||||
* might try to eliminate "superfluous" memsets.
|
||||
* This method is used in memzero_explicit() the Linux kernel, too. Its advantage is that it
|
||||
* is pretty efficient, because the compiler can still implement the memset() efficently,
|
||||
* just not remove it entirely. See "Dead Store Elimination (Still) Considered Harmful" by
|
||||
* Yang et al. (USENIX Security 2017) for more background.
|
||||
*/
|
||||
memset(ptr, 0, len);
|
||||
__asm__ __volatile__("" : : "r"(ptr) : "memory");
|
||||
#else
|
||||
void *(*volatile const volatile_memset)(void *, int, size_t) = memset;
|
||||
volatile_memset(ptr, 0, len);
|
||||
#endif
|
||||
#ifdef VERIFY
|
||||
SECP256K1_CHECKMEM_UNDEFINE(ptr, len);
|
||||
#endif
|
||||
}
|
||||
|
||||
/** Semantics like memcmp. Variable-time.
|
||||
*
|
||||
* We use this to avoid possible compiler bugs with memcmp, e.g.
|
||||
@@ -243,7 +277,7 @@ static SECP256K1_INLINE int secp256k1_is_zero_array(const unsigned char *s, size
|
||||
}
|
||||
ret = (acc == 0);
|
||||
/* acc may contain secret values. Try to explicitly clear it. */
|
||||
acc = 0;
|
||||
secp256k1_memclear(&acc, sizeof(acc));
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user