From 0e1d311168f8c847d66ed03d18f678ac2c767d35 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Niels=20M=C3=B6ller?= <nisse@lysator.liu.se>
Date: Tue, 14 Nov 2023 19:54:18 +0100
Subject: [PATCH] Add side-channel test for ecdsa-sign-test.

---
 ChangeLog                    | 19 +++++++++++++++++++
 configure.ac                 |  9 +++++++++
 ecc-internal.h               |  8 ++++++++
 ecc-mod-arith.c              | 12 ++++++------
 ecc-mod-inv.c                | 10 +++++-----
 ecc-mod.c                    |  4 ++--
 testsuite/Makefile.in        |  3 ++-
 testsuite/ecdsa-sign-test.c  | 10 ++++++++++
 testsuite/sc-ecdsa-sign-test |  6 ++++++
 9 files changed, 67 insertions(+), 14 deletions(-)
 create mode 100755 testsuite/sc-ecdsa-sign-test

diff --git a/ChangeLog b/ChangeLog
index be68bab2..27655667 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,22 @@
+2023-11-14  Niels Möller  <nisse@lysator.liu.se>
+
+	Add a first side-channel test for the ECC code.
+	* configure.ac: New option --enable-extra-asserts. Enables asserts
+	that are disabled by default, due to conflict with tests of
+	side-channel silence.
+	(WITH_EXTRA_ASSERTS): Corresponding new define.
+	* ecc-internal.h (assert_maybe): Conditionally define this assert
+	macro, depending on WITH_EXTRA_ASSERTS.
+	* ecc-mod-arith.c: Convert most asserts to assert_maybe.
+	* ecc-mod-inv.c (ecc_mod_inv): Likewise.
+	* ecc-mod.c (ecc_mod): Likewise.
+	* testsuite/ecdsa-sign-test.c (test_ecdsa): Add calls to
+	mark_bytes_undefined and mark_bytes_defined.
+	(test_main): Skip test if both side channel tests and extra
+	asserts are enabled.
+	* testsuite/sc-ecdsa-sign-test: New testcase.
+	* testsuite/Makefile.in (TS_SC): Add sc-ecdsa-sign-test.
+
 2023-11-12  Niels Möller  <nisse@lysator.liu.se>
 
 	* gmp-glue.h (GMP_LIMB_BITS) [NETTLE_USE_MINI_GMP]: Define as alias for
diff --git a/configure.ac b/configure.ac
index 867767a6..c0709498 100644
--- a/configure.ac
+++ b/configure.ac
@@ -116,6 +116,10 @@ AC_ARG_ENABLE(s390x-msa,
   AS_HELP_STRING([--enable-s390x-msa], [Enable message-security assist extensions on z/Architecture. (default=no)]),,
   [enable_s390x_msa=no])
 
+AC_ARG_ENABLE(extra-asserts,
+  AS_HELP_STRING([--enable-extra-asserts], [Enable additional asserts in ECC code (incompatible side-channel tests)]),,
+  [enable_extra_asserts=no])
+
 AC_ARG_ENABLE(mini-gmp,
   AS_HELP_STRING([--enable-mini-gmp], [Enable mini-gmp, used instead of libgmp.]),,
   [enable_mini_gmp=no])
@@ -132,6 +136,11 @@ fi
 AC_SUBST([NETTLE_USE_MINI_GMP])
 AC_SUBST([HOGWEED_EXTRA_SYMBOLS])
 
+AH_TEMPLATE([WITH_EXTRA_ASSERTS], [Defined to enable additional asserts])
+if test "$enable_extra_asserts" = yes ; then
+  AC_DEFINE(WITH_EXTRA_ASSERTS)
+fi
+
 LSH_RPATH_INIT([`echo $with_lib_path | sed 's/:/ /g'` \
     `echo $exec_prefix | sed "s@^NONE@$prefix/lib@g" | sed "s@^NONE@$ac_default_prefix/lib@g"` \
     /usr/local/lib /sw/local/lib /sw/lib \
diff --git a/ecc-internal.h b/ecc-internal.h
index 53359b57..17c51c31 100644
--- a/ecc-internal.h
+++ b/ecc-internal.h
@@ -85,6 +85,14 @@
 #define curve25519_eh_to_x _nettle_curve25519_eh_to_x
 #define curve448_eh_to_x _nettle_curve448_eh_to_x
 
+/* For asserts that are incompatible with sc tests. Currently used
+   only by ECC code. */
+#if WITH_EXTRA_ASSERTS
+#define assert_maybe(x) assert(x)
+#else
+#define assert_maybe(x)
+#endif
+
 extern const struct ecc_curve _nettle_secp_192r1;
 extern const struct ecc_curve _nettle_secp_224r1;
 extern const struct ecc_curve _nettle_secp_256r1;
diff --git a/ecc-mod-arith.c b/ecc-mod-arith.c
index 3b9bcb47..2c39a816 100644
--- a/ecc-mod-arith.c
+++ b/ecc-mod-arith.c
@@ -76,7 +76,7 @@ ecc_mod_add (const struct ecc_modulo *m, mp_limb_t *rp,
   cy = mpn_add_n (rp, ap, bp, m->size);
   cy = mpn_cnd_add_n (cy, rp, rp, m->B, m->size);
   cy = mpn_cnd_add_n (cy, rp, rp, m->B, m->size);
-  assert (cy == 0);  
+  assert_maybe (cy == 0);
 }
 
 void
@@ -100,7 +100,7 @@ ecc_mod_sub (const struct ecc_modulo *m, mp_limb_t *rp,
    */
   cy = mpn_cnd_sub_n (cy, rp, rp, m->Bm2m, m->size);
   cy = mpn_cnd_sub_n (cy, rp, rp, m->B, m->size);
-  assert (cy == 0);  
+  assert_maybe (cy == 0);
 }
 
 void
@@ -112,10 +112,10 @@ ecc_mod_mul_1 (const struct ecc_modulo *m, mp_limb_t *rp,
   assert (b <= 0xffffffff);
   hi = mpn_mul_1 (rp, ap, m->size, b);
   hi = mpn_addmul_1 (rp, m->B, m->size, hi);
-  assert (hi <= 1);
+  assert_maybe (hi <= 1);
   hi = mpn_cnd_add_n (hi, rp, rp, m->B, m->size);
   /* Sufficient if b < B^size / p */
-  assert (hi == 0);
+  assert_maybe (hi == 0);
 }
 
 void
@@ -142,10 +142,10 @@ ecc_mod_submul_1 (const struct ecc_modulo *m, mp_limb_t *rp,
   assert (b <= 0xffffffff);
   hi = mpn_submul_1 (rp, ap, m->size, b);
   hi = mpn_submul_1 (rp, m->B, m->size, hi);
-  assert (hi <= 1);
+  assert_maybe (hi <= 1);
   hi = mpn_cnd_sub_n (hi, rp, rp, m->B, m->size);
   /* Sufficient roughly if b < B^size / p */
-  assert (hi == 0);
+  assert_maybe (hi == 0);
 }
 
 void
diff --git a/ecc-mod-inv.c b/ecc-mod-inv.c
index 254fb697..5d1f8475 100644
--- a/ecc-mod-inv.c
+++ b/ecc-mod-inv.c
@@ -135,7 +135,7 @@ ecc_mod_inv (const struct ecc_modulo *m,
          also v = orig_a^{-1} (mod m)
       */
 
-      assert (bp[0] & 1);
+      assert_maybe (bp[0] & 1);
       odd = ap[0] & 1;
 
       swap = mpn_cnd_sub_n (odd, ap, ap, bp, n);
@@ -145,15 +145,15 @@ ecc_mod_inv (const struct ecc_modulo *m,
       mpn_cnd_swap (swap, up, vp, n);
       cy = mpn_cnd_sub_n (odd, up, up, vp, n);
       cy -= mpn_cnd_add_n (cy, up, up, m->m, n);
-      assert (cy == 0);
+      assert_maybe (cy == 0);
 
       cy = mpn_rshift (ap, ap, n, 1);
-      assert (cy == 0);
+      assert_maybe (cy == 0);
       cy = mpn_rshift (up, up, n, 1);
       cy = mpn_cnd_add_n (cy, up, up, m->mp1h, n);
-      assert (cy == 0);
+      assert_maybe (cy == 0);
     }
-  assert ( (ap[0] | ap[n-1]) == 0);
+  assert_maybe ( (ap[0] | ap[n-1]) == 0);
 #undef ap
 #undef bp
 #undef up
diff --git a/ecc-mod.c b/ecc-mod.c
index 7532d1ec..74314b8d 100644
--- a/ecc-mod.c
+++ b/ecc-mod.c
@@ -82,7 +82,7 @@ ecc_mod (const struct ecc_modulo *m, mp_limb_t *rp, mp_limb_t *xp)
 				     
 	  hi = mpn_add_n (xp + rn - sn, xp + rn - sn, xp + rn, sn);
 	  hi = mpn_cnd_add_n (hi, xp + rn - mn, xp + rn - mn, m->B, mn);
-	  assert (hi == 0);
+	  assert_maybe (hi == 0);
 	}
     }
 
@@ -111,6 +111,6 @@ ecc_mod (const struct ecc_modulo *m, mp_limb_t *rp, mp_limb_t *xp)
   else
     {
       hi = mpn_cnd_add_n (hi, rp, xp, m->B, mn);
-      assert (hi == 0);
+      assert_maybe (hi == 0);
     }
 }
diff --git a/testsuite/Makefile.in b/testsuite/Makefile.in
index 0cb896ff..fb2b4031 100644
--- a/testsuite/Makefile.in
+++ b/testsuite/Makefile.in
@@ -67,7 +67,8 @@ TS_C = $(TS_NETTLE) @IF_HOGWEED@ $(TS_HOGWEED)
 TS_CXX = @IF_CXX@ $(CXX_SOURCES:.cxx=$(EXEEXT))
 TARGETS = $(TS_C) $(TS_CXX)
 TS_SC = sc-cnd-memcpy-test sc-gcm-test sc-memeql-test \
-	@IF_HOGWEED@ sc-pkcs1-sec-decrypt-test sc-rsa-sec-decrypt-test
+	@IF_HOGWEED@ sc-pkcs1-sec-decrypt-test sc-rsa-sec-decrypt-test sc-ecdsa-sign-test
+
 TS_SH = symbols-test @IF_VALGRIND@ $(TS_SC)
 TS_ALL = $(TARGETS) $(TS_SH) @IF_DLOPEN_TEST@ dlopen-test$(EXEEXT)
 
diff --git a/testsuite/ecdsa-sign-test.c b/testsuite/ecdsa-sign-test.c
index b8a100b6..a3c43568 100644
--- a/testsuite/ecdsa-sign-test.c
+++ b/testsuite/ecdsa-sign-test.c
@@ -28,9 +28,15 @@ test_ecdsa (const struct ecc_curve *ecc,
   mpz_limbs_copy (zp, z, ecc->p.size);
   mpz_limbs_copy (kp, k, ecc->p.size);
 
+  mark_bytes_undefined (sizeof(mp_limb_t) * ecc->p.size, zp);
+  mark_bytes_undefined (sizeof(mp_limb_t) * ecc->p.size, kp);
+
   ecc_ecdsa_sign (ecc, zp, kp,
 		  h->length, h->data, rp, sp, scratch);
 
+  mark_bytes_defined (sizeof(mp_limb_t) * ecc->p.size, rp);
+  mark_bytes_defined (sizeof(mp_limb_t) * ecc->p.size, sp);
+
   mpz_set_str (ref.r, r, 16);
   mpz_set_str (ref.s, s, 16);
 
@@ -64,6 +70,10 @@ test_ecdsa (const struct ecc_curve *ecc,
 void
 test_main (void)
 {
+#if WITH_EXTRA_ASSERTS
+  if (test_side_channel)
+    SKIP();
+#endif
   /* Producing the signature for corresponding test in
      ecdsa-verify-test.c, with special u1 and u2. */
   test_ecdsa (&_nettle_secp_224r1,
diff --git a/testsuite/sc-ecdsa-sign-test b/testsuite/sc-ecdsa-sign-test
new file mode 100755
index 00000000..c1fbf0e2
--- /dev/null
+++ b/testsuite/sc-ecdsa-sign-test
@@ -0,0 +1,6 @@
+#! /bin/sh
+
+srcdir=`dirname $0`
+. "${srcdir}/sc-valgrind.sh"
+
+with_valgrind ./ecdsa-sign-test
-- 
GitLab