* tools/sexp-conv-test: Likewise.
* tools/pkcs1-conv-test: Likewise.
+2023-08-05 Niels Möller <nisse@lysator.liu.se>
+
+ * testsuite/testutils.c (mark_bytes_undefined)
+ (mark_bytes_defined): New functions. Update side-channel related
+ tests to use them.
+ (main): Check environment variable NETTLE_TEST_SIDE_CHANNEL.
+ (test_side_channel): New global variable.
+
+ * testsuite/sc-valgrind.sh (with_valgrind): New file, new shell
+ utility function.
+
+ * testsuite/sc-pkcs1-sec-decrypt-test: New test, for side channel
+ silence.
+ * testsuite/sc-memeql-test: Likewise.
+ * testsuite/sc-gcm-test: Likewise.
+ * testsuite/sc-cnd-memcpy-test: Likewise.
+ * testsuite/rsa-sec-decrypt-test: Likewise.
+
+ * rsa-sec-decrypt.c (_rsa_sec_decrypt): New internal function,
+ without input range checks.
+ (rsa_sec_decrypt): Use it.
+
2023-08-02 Niels Möller <nisse@lysator.liu.se>
* configure.ac: Replace obsoleted macros, require autoconf-2.69,
#define _rsa_sec_compute_root_itch _nettle_rsa_sec_compute_root_itch
#define _rsa_sec_compute_root _nettle_rsa_sec_compute_root
#define _rsa_sec_compute_root_tr _nettle_rsa_sec_compute_root_tr
+#define _rsa_sec_decrypt _nettle_rsa_sec_decrypt
/* Internal functions. */
int
void *random_ctx, nettle_random_func *random,
mp_limb_t *x, const mp_limb_t *m);
+/* Variant without range check of the input, to ease testing for
+ side-channel silence. */
+int
+_rsa_sec_decrypt (const struct rsa_public_key *pub,
+ const struct rsa_private_key *key,
+ void *random_ctx, nettle_random_func *random,
+ size_t length, uint8_t *message,
+ const mpz_t gibberish);
+
#endif /* NETTLE_RSA_INTERNAL_H_INCLUDED */
#include "gmp-glue.h"
+/* Variant without range check of the input, to ease testing for
+ side-channel silence. */
int
-rsa_sec_decrypt(const struct rsa_public_key *pub,
- const struct rsa_private_key *key,
- void *random_ctx, nettle_random_func *random,
- size_t length, uint8_t *message,
- const mpz_t gibberish)
+_rsa_sec_decrypt (const struct rsa_public_key *pub,
+ const struct rsa_private_key *key,
+ void *random_ctx, nettle_random_func *random,
+ size_t length, uint8_t *message,
+ const mpz_t gibberish)
{
TMP_GMP_DECL (m, mp_limb_t);
TMP_GMP_DECL (em, uint8_t);
int res;
- /* First check that input is in range. */
- if (mpz_sgn (gibberish) < 0 || mpz_cmp (gibberish, pub->n) >= 0)
- return 0;
-
TMP_GMP_ALLOC (m, mpz_size(pub->n));
TMP_GMP_ALLOC (em, key->size);
return res;
}
+int
+rsa_sec_decrypt (const struct rsa_public_key *pub,
+ const struct rsa_private_key *key,
+ void *random_ctx, nettle_random_func *random,
+ size_t length, uint8_t *message,
+ const mpz_t gibberish)
+{
+ /* First check that input is in range. */
+ if (mpz_sgn (gibberish) < 0 || mpz_cmp (gibberish, pub->n) >= 0)
+ return 0;
+
+ return _rsa_sec_decrypt (pub, key, random_ctx, random, length, message, gibberish);
+}
TS_C = $(TS_NETTLE) @IF_HOGWEED@ $(TS_HOGWEED)
TS_CXX = @IF_CXX@ $(CXX_SOURCES:.cxx=$(EXEEXT))
TARGETS = $(TS_C) $(TS_CXX)
-TS_SH = symbols-test
+TS_SC = sc-cnd-memcpy-test sc-gcm-test sc-memeql-test \
+ @IF_HOGWEED@ sc-pkcs1-sec-decrypt-test sc-rsa-sec-decrypt-test
+TS_SH = $(TS_SC) symbols-test
TS_ALL = $(TARGETS) $(TS_SH) @IF_DLOPEN_TEST@ dlopen-test$(EXEEXT)
TS_FAT = $(patsubst %, %$(EXEEXT), aes-test cbc-test \
# data.
VALGRIND = valgrind --error-exitcode=1 --leak-check=full --show-reachable=yes @IF_ASM@ --partial-loads-ok=yes
-check: $(TS_ALL)
+check: $(TS_ALL) $(TS_ALL:sc-%=%)
TEST_SHLIB_DIR="$(TEST_SHLIB_DIR)" \
srcdir="$(srcdir)" \
EMULATOR="$(EMULATOR)" NM="$(NM)" EXEEXT="$(EXEEXT)" \
#include "knuth-lfib.h"
#include "memops.h"
-#if HAVE_VALGRIND_MEMCHECK_H
-# include <valgrind/memcheck.h>
static void
cnd_memcpy_for_test(int cnd, void *dst, const void *src, size_t n)
{
/* Makes valgrind trigger on any branches depending on the input
data. */
- VALGRIND_MAKE_MEM_UNDEFINED (dst, n);
- VALGRIND_MAKE_MEM_UNDEFINED (src, n);
- VALGRIND_MAKE_MEM_UNDEFINED (&cnd, sizeof(cnd));
+ mark_bytes_undefined (n, dst);
+ mark_bytes_undefined (n, src);
+ mark_bytes_undefined (sizeof(cnd), &cnd);
cnd_memcpy (cnd, dst, src, n);
- VALGRIND_MAKE_MEM_DEFINED (src, n);
- VALGRIND_MAKE_MEM_DEFINED (dst, n);
+ mark_bytes_defined (n, src);
+ mark_bytes_defined (n, dst);
}
-#else
-#define cnd_memcpy_for_test cnd_memcpy
-#endif
#define MAX_SIZE 50
void
#include "gcm.h"
#include "ghash-internal.h"
-#if HAVE_VALGRIND_MEMCHECK_H
-# include <valgrind/memcheck.h>
-#else
-# define VALGRIND_MAKE_MEM_UNDEFINED(p, n)
-# define VALGRIND_MAKE_MEM_DEFINED(p, n)
-#endif
-
static void
test_gcm_hash (const struct tstring *msg, const struct tstring *ref)
{
struct gcm_key gcm_key;
union nettle_block16 state;
- /* Use VALGRIND_MAKE_MEM_DEFINED to mark inputs as "undefined", to
- get valgrind to warn about any branches or memory accesses
- depending on secret data. */
+ /* Mark inputs as "undefined" to valgrind, to get warnings about any
+ branches or memory accesses depending on secret data. */
memcpy (state.b, key->data, GCM_BLOCK_SIZE);
- VALGRIND_MAKE_MEM_UNDEFINED (&state, sizeof(state));
+ mark_bytes_undefined (sizeof(state), &state);
_ghash_set_key (&gcm_key, &state);
memcpy (state.b, iv->data, GCM_BLOCK_SIZE);
- VALGRIND_MAKE_MEM_UNDEFINED (&state, sizeof(state));
- VALGRIND_MAKE_MEM_UNDEFINED (message->data, message->length);
+ mark_bytes_undefined (sizeof(state), &state);
+ mark_bytes_undefined (message->length, message->data);
_ghash_update (&gcm_key, &state, message->length / GCM_BLOCK_SIZE, message->data);
- VALGRIND_MAKE_MEM_DEFINED (&state, sizeof(state));
- VALGRIND_MAKE_MEM_DEFINED (message->data, message->length);
+ mark_bytes_defined (sizeof(state), &state);
+ mark_bytes_defined (message->length, message->data);
+
if (!MEMEQ(GCM_BLOCK_SIZE, state.b, digest->data))
{
fprintf (stderr, "gcm_hash (internal) failed\n");
#include "knuth-lfib.h"
#include "memops.h"
-#if HAVE_VALGRIND_MEMCHECK_H
-# include <valgrind/memcheck.h>
static int
memeql_sec_for_test(const void *a, const void *b, size_t n)
{
/* Makes valgrind trigger on any branches depending on the input
data. */
- VALGRIND_MAKE_MEM_UNDEFINED (a, n);
- VALGRIND_MAKE_MEM_UNDEFINED (b, n);
+ mark_bytes_undefined (n, a);
+ mark_bytes_undefined (n, b);
res = memeql_sec (a, b, n);
- VALGRIND_MAKE_MEM_DEFINED (&res, sizeof(res));
+ mark_bytes_defined (sizeof(res), &res);
return res;
}
-#else
-#define memeql_sec_for_test memeql_sec
-#endif
#define MAX_SIZE 50
void
#include "pkcs1-internal.h"
-#if HAVE_VALGRIND_MEMCHECK_H
-# include <valgrind/memcheck.h>
static int
pkcs1_decrypt_for_test(size_t msg_len, uint8_t *msg,
size_t pad_len, uint8_t *pad)
{
int ret;
- VALGRIND_MAKE_MEM_UNDEFINED (msg, msg_len);
- VALGRIND_MAKE_MEM_UNDEFINED (pad, pad_len);
+ mark_bytes_undefined (msg_len, msg);
+ mark_bytes_undefined (pad_len, pad);
ret = _pkcs1_sec_decrypt (msg_len, msg, pad_len, pad);
- VALGRIND_MAKE_MEM_DEFINED (msg, msg_len);
- VALGRIND_MAKE_MEM_DEFINED (pad, pad_len);
- VALGRIND_MAKE_MEM_DEFINED (&ret, sizeof (ret));
+ mark_bytes_defined (msg_len, msg);
+ mark_bytes_defined (pad_len, pad);
+ mark_bytes_defined (sizeof (ret), &ret);
return ret;
}
-#else
-#define pkcs1_decrypt_for_test _pkcs1_sec_decrypt
-#endif
void
test_main(void)
#include "testutils.h"
#include "rsa.h"
+#include "rsa-internal.h"
#include "knuth-lfib.h"
-#if HAVE_VALGRIND_MEMCHECK_H
-# include <valgrind/memcheck.h>
+#define MARK_MPZ_LIMBS_UNDEFINED(x) \
+ mark_bytes_undefined (mpz_size (x) * sizeof (mp_limb_t), mpz_limbs_read (x))
+
+#define MARK_MPZ_LIMBS_DEFINED(x) \
+ mark_bytes_defined (mpz_size (x) * sizeof (mp_limb_t), mpz_limbs_read (x))
-#define MARK_MPZ_LIMBS_UNDEFINED(parm) \
- VALGRIND_MAKE_MEM_UNDEFINED (mpz_limbs_read (parm), \
- mpz_size (parm) * sizeof (mp_limb_t))
-#define MARK_MPZ_LIMBS_DEFINED(parm) \
- VALGRIND_MAKE_MEM_DEFINED (mpz_limbs_read (parm), \
- mpz_size (parm) * sizeof (mp_limb_t))
static int
rsa_decrypt_for_test(const struct rsa_public_key *pub,
const struct rsa_private_key *key,
const mpz_t gibberish)
{
int ret;
+ if (!test_side_channel)
+ return rsa_sec_decrypt (pub, key, random_ctx, random, length, message, gibberish);
+
/* Makes valgrind trigger on any branches depending on the input
data. Except that (i) we have to allow rsa_sec_compute_root_tr to
check that p and q are odd, (ii) mpn_sec_div_r may leak
normalization check and table lookup in invert_limb, and (iii)
mpn_sec_powm may leak information about the least significant
bits of p and q, due to table lookup in binvert_limb. */
- VALGRIND_MAKE_MEM_UNDEFINED (message, length);
+ mark_bytes_undefined (length, message);
MARK_MPZ_LIMBS_UNDEFINED(gibberish);
MARK_MPZ_LIMBS_UNDEFINED(key->a);
MARK_MPZ_LIMBS_UNDEFINED(key->b);
MARK_MPZ_LIMBS_UNDEFINED(key->c);
- VALGRIND_MAKE_MEM_UNDEFINED(mpz_limbs_read (key->p) + 1,
- (mpz_size (key->p) - 3) * sizeof(mp_limb_t));
- VALGRIND_MAKE_MEM_UNDEFINED(mpz_limbs_read (key->q) + 1,
- (mpz_size (key->q) - 3) * sizeof(mp_limb_t));
+ mark_bytes_undefined ((mpz_size (key->p) - 3) * sizeof(mp_limb_t),
+ mpz_limbs_read (key->p) + 1);
+ mark_bytes_undefined((mpz_size (key->q) - 3) * sizeof(mp_limb_t),
+ mpz_limbs_read (key->q) + 1);
- ret = rsa_sec_decrypt (pub, key, random_ctx, random, length, message, gibberish);
+ /* Call variant not checking that 0 <= gibberish < n. */
+ ret = _rsa_sec_decrypt (pub, key, random_ctx, random, length, message, gibberish);
- VALGRIND_MAKE_MEM_DEFINED (message, length);
- VALGRIND_MAKE_MEM_DEFINED (&ret, sizeof(ret));
+ mark_bytes_defined (length, message);
+ mark_bytes_defined (sizeof(ret), &ret);
MARK_MPZ_LIMBS_DEFINED(gibberish);
MARK_MPZ_LIMBS_DEFINED(key->a);
MARK_MPZ_LIMBS_DEFINED(key->b);
return ret;
}
-#else
-#define rsa_decrypt_for_test rsa_sec_decrypt
-#endif
#define PAYLOAD_SIZE 50
#define DECRYPTED_SIZE 256
--- /dev/null
+#! /bin/sh
+
+srcdir=`dirname $0`
+. "${srcdir}/sc-valgrind.sh"
+
+with_valgrind ./cnd-memcpy-test
--- /dev/null
+#! /bin/sh
+
+srcdir=`dirname $0`
+. "${srcdir}/sc-valgrind.sh"
+
+with_valgrind ./gcm-test
--- /dev/null
+#! /bin/sh
+
+srcdir=`dirname $0`
+. "${srcdir}/sc-valgrind.sh"
+
+with_valgrind ./memeql-test
--- /dev/null
+#! /bin/sh
+
+srcdir=`dirname $0`
+. "${srcdir}/sc-valgrind.sh"
+
+with_valgrind ./pkcs1-sec-decrypt-test
--- /dev/null
+#! /bin/sh
+
+srcdir=`dirname $0`
+. "${srcdir}/sc-valgrind.sh"
+
+with_valgrind ./rsa-sec-decrypt-test
--- /dev/null
+# To setup a test to check for branches or memory accesses depending on secret data,
+# using valgrind.
+
+with_valgrind () {
+ type valgrind >/dev/null || exit 77
+ NETTLE_TEST_SIDE_CHANNEL=1 valgrind -q --error-exitcode=1 "$@"
+}
#include <ctype.h>
#include <sys/time.h>
+#if HAVE_VALGRIND_MEMCHECK_H
+# include <valgrind/memcheck.h>
+# include <valgrind/valgrind.h>
+#endif
+
void
die(const char *format, ...)
{
int verbose = 0;
+#if HAVE_VALGRIND_MEMCHECK_H
+int test_side_channel = 0;
+
+void
+mark_bytes_undefined (size_t size, const void *p)
+{
+ if (test_side_channel)
+ VALGRIND_MAKE_MEM_UNDEFINED(p, size);
+}
+void
+mark_bytes_defined (size_t size, const void *p)
+{
+ if (test_side_channel)
+ VALGRIND_MAKE_MEM_DEFINED(p, size);
+}
+#else
+void
+mark_bytes_undefined (size_t size, const void *p) {}
+void
+mark_bytes_defined (size_t size, const void *p) {}
+#endif
+
int
main(int argc, char **argv)
{
}
}
+ if (getenv("NETTLE_TEST_SIDE_CHANNEL"))
+ {
+#if HAVE_VALGRIND_MEMCHECK_H
+ if (RUNNING_ON_VALGRIND)
+ test_side_channel = 1;
+ else
+#endif
+ SKIP();
+ }
test_main();
tstring_clear();
void
print_hex(size_t length, const uint8_t *data);
+/* If side-channel tests are requested, attach valgrind annotations on
+ given memory area. */
+void
+mark_bytes_undefined (size_t size, const void *p);
+
+void
+mark_bytes_defined (size_t size, const void *p);
+
/* The main program */
void
test_main(void);
extern int verbose;
+extern int test_side_channel;
typedef void
nettle_encrypt_message_func(void *ctx,