Skip to content

Commit 5e1c885

Browse files
Merge #754: Fix uninit values passed into cmov
f79a7ad Add valgrind uninit check to cmovs output (Elichai Turkel) a39c2b0 Fixed UB(arithmetics on uninit values) in cmovs (Elichai Turkel) Pull request description: This should fix #753. Used @peterdettman's solution here for the `ECMULT_CONST_TABLE_GET_GE` #753 (comment) and in ecdsa_sign I initialize `s` and `r` to a zero scalar. The second commit adds a valgrind check to the cmovs that could've caught this (in ecdsa_sign, not in ecmult_const because there's a scalar clear there under `VERIFY_SETUP`) ACKs for top commit: sipa: utACK f79a7ad jonasnick: ACK f79a7ad real-or-random: ACK f79a7ad Tree-SHA512: 6fd7b7c84f392bda733a973f4dcfc12bf1478aac2591e2c87b69e637847d3b063c4243cc8feccaffc3a5824c18183a5e66bd4251c2322abaf63bb6439b38defe
2 parents 05d315a + f79a7ad commit 5e1c885

12 files changed

+38
-18
lines changed

src/ecmult_const_impl.h

+6-2
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414

1515
/* This is like `ECMULT_TABLE_GET_GE` but is constant time */
1616
#define ECMULT_CONST_TABLE_GET_GE(r,pre,n,w) do { \
17-
int m; \
17+
int m = 0; \
1818
/* Extract the sign-bit for a constant time absolute-value. */ \
1919
int mask = (n) >> (sizeof(n) * CHAR_BIT - 1); \
2020
int abs_n = ((n) + mask) ^ mask; \
@@ -25,7 +25,11 @@
2525
VERIFY_CHECK((n) <= ((1 << ((w)-1)) - 1)); \
2626
VERIFY_SETUP(secp256k1_fe_clear(&(r)->x)); \
2727
VERIFY_SETUP(secp256k1_fe_clear(&(r)->y)); \
28-
for (m = 0; m < ECMULT_TABLE_SIZE(w); m++) { \
28+
/* Unconditionally set r->x = (pre)[m].x. r->y = (pre)[m].y. because it's either the correct one \
29+
* or will get replaced in the later iterations, this is needed to make sure `r` is initialized. */ \
30+
(r)->x = (pre)[m].x; \
31+
(r)->y = (pre)[m].y; \
32+
for (m = 1; m < ECMULT_TABLE_SIZE(w); m++) { \
2933
/* This loop is used to avoid secret data in array indices. See
3034
* the comment in ecmult_gen_impl.h for rationale. */ \
3135
secp256k1_fe_cmov(&(r)->x, &(pre)[m].x, m == idx_n); \

src/field.h

+2-2
Original file line numberDiff line numberDiff line change
@@ -125,10 +125,10 @@ static void secp256k1_fe_to_storage(secp256k1_fe_storage *r, const secp256k1_fe
125125
/** Convert a field element back from the storage type. */
126126
static void secp256k1_fe_from_storage(secp256k1_fe *r, const secp256k1_fe_storage *a);
127127

128-
/** If flag is true, set *r equal to *a; otherwise leave it. Constant-time. */
128+
/** If flag is true, set *r equal to *a; otherwise leave it. Constant-time. Both *r and *a must be initialized.*/
129129
static void secp256k1_fe_storage_cmov(secp256k1_fe_storage *r, const secp256k1_fe_storage *a, int flag);
130130

131-
/** If flag is true, set *r equal to *a; otherwise leave it. Constant-time. */
131+
/** If flag is true, set *r equal to *a; otherwise leave it. Constant-time. Both *r and *a must be initialized.*/
132132
static void secp256k1_fe_cmov(secp256k1_fe *r, const secp256k1_fe *a, int flag);
133133

134134
#endif /* SECP256K1_FIELD_H */

src/field_10x26_impl.h

+2
Original file line numberDiff line numberDiff line change
@@ -1097,6 +1097,7 @@ static void secp256k1_fe_sqr(secp256k1_fe *r, const secp256k1_fe *a) {
10971097

10981098
static SECP256K1_INLINE void secp256k1_fe_cmov(secp256k1_fe *r, const secp256k1_fe *a, int flag) {
10991099
uint32_t mask0, mask1;
1100+
VG_CHECK_VERIFY(r->n, sizeof(r->n));
11001101
mask0 = flag + ~((uint32_t)0);
11011102
mask1 = ~mask0;
11021103
r->n[0] = (r->n[0] & mask0) | (a->n[0] & mask1);
@@ -1119,6 +1120,7 @@ static SECP256K1_INLINE void secp256k1_fe_cmov(secp256k1_fe *r, const secp256k1_
11191120

11201121
static SECP256K1_INLINE void secp256k1_fe_storage_cmov(secp256k1_fe_storage *r, const secp256k1_fe_storage *a, int flag) {
11211122
uint32_t mask0, mask1;
1123+
VG_CHECK_VERIFY(r->n, sizeof(r->n));
11221124
mask0 = flag + ~((uint32_t)0);
11231125
mask1 = ~mask0;
11241126
r->n[0] = (r->n[0] & mask0) | (a->n[0] & mask1);

src/field_5x52_impl.h

+2
Original file line numberDiff line numberDiff line change
@@ -449,6 +449,7 @@ static void secp256k1_fe_sqr(secp256k1_fe *r, const secp256k1_fe *a) {
449449

450450
static SECP256K1_INLINE void secp256k1_fe_cmov(secp256k1_fe *r, const secp256k1_fe *a, int flag) {
451451
uint64_t mask0, mask1;
452+
VG_CHECK_VERIFY(r->n, sizeof(r->n));
452453
mask0 = flag + ~((uint64_t)0);
453454
mask1 = ~mask0;
454455
r->n[0] = (r->n[0] & mask0) | (a->n[0] & mask1);
@@ -466,6 +467,7 @@ static SECP256K1_INLINE void secp256k1_fe_cmov(secp256k1_fe *r, const secp256k1_
466467

467468
static SECP256K1_INLINE void secp256k1_fe_storage_cmov(secp256k1_fe_storage *r, const secp256k1_fe_storage *a, int flag) {
468469
uint64_t mask0, mask1;
470+
VG_CHECK_VERIFY(r->n, sizeof(r->n));
469471
mask0 = flag + ~((uint64_t)0);
470472
mask1 = ~mask0;
471473
r->n[0] = (r->n[0] & mask0) | (a->n[0] & mask1);

src/group.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ static void secp256k1_ge_to_storage(secp256k1_ge_storage *r, const secp256k1_ge
132132
/** Convert a group element back from the storage type. */
133133
static void secp256k1_ge_from_storage(secp256k1_ge *r, const secp256k1_ge_storage *a);
134134

135-
/** If flag is true, set *r equal to *a; otherwise leave it. Constant-time. */
135+
/** If flag is true, set *r equal to *a; otherwise leave it. Constant-time. Both *r and *a must be initialized.*/
136136
static void secp256k1_ge_storage_cmov(secp256k1_ge_storage *r, const secp256k1_ge_storage *a, int flag);
137137

138138
/** Rescale a jacobian point by b which must be non-zero. Constant-time. */

src/scalar.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ static void secp256k1_scalar_split_lambda(secp256k1_scalar *r1, secp256k1_scalar
111111
/** Multiply a and b (without taking the modulus!), divide by 2**shift, and round to the nearest integer. Shift must be at least 256. */
112112
static void secp256k1_scalar_mul_shift_var(secp256k1_scalar *r, const secp256k1_scalar *a, const secp256k1_scalar *b, unsigned int shift);
113113

114-
/** If flag is true, set *r equal to *a; otherwise leave it. Constant-time. */
114+
/** If flag is true, set *r equal to *a; otherwise leave it. Constant-time. Both *r and *a must be initialized.*/
115115
static void secp256k1_scalar_cmov(secp256k1_scalar *r, const secp256k1_scalar *a, int flag);
116116

117117
#endif /* SECP256K1_SCALAR_H */

src/scalar_4x64_impl.h

+1
Original file line numberDiff line numberDiff line change
@@ -948,6 +948,7 @@ SECP256K1_INLINE static void secp256k1_scalar_mul_shift_var(secp256k1_scalar *r,
948948

949949
static SECP256K1_INLINE void secp256k1_scalar_cmov(secp256k1_scalar *r, const secp256k1_scalar *a, int flag) {
950950
uint64_t mask0, mask1;
951+
VG_CHECK_VERIFY(r->d, sizeof(r->d));
951952
mask0 = flag + ~((uint64_t)0);
952953
mask1 = ~mask0;
953954
r->d[0] = (r->d[0] & mask0) | (a->d[0] & mask1);

src/scalar_8x32_impl.h

+1
Original file line numberDiff line numberDiff line change
@@ -720,6 +720,7 @@ SECP256K1_INLINE static void secp256k1_scalar_mul_shift_var(secp256k1_scalar *r,
720720

721721
static SECP256K1_INLINE void secp256k1_scalar_cmov(secp256k1_scalar *r, const secp256k1_scalar *a, int flag) {
722722
uint32_t mask0, mask1;
723+
VG_CHECK_VERIFY(r->d, sizeof(r->d));
723724
mask0 = flag + ~((uint32_t)0);
724725
mask1 = ~mask0;
725726
r->d[0] = (r->d[0] & mask0) | (a->d[0] & mask1);

src/scalar_low_impl.h

+1
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,7 @@ SECP256K1_INLINE static int secp256k1_scalar_eq(const secp256k1_scalar *a, const
116116

117117
static SECP256K1_INLINE void secp256k1_scalar_cmov(secp256k1_scalar *r, const secp256k1_scalar *a, int flag) {
118118
uint32_t mask0, mask1;
119+
VG_CHECK_VERIFY(r, sizeof(*r));
119120
mask0 = flag + ~((uint32_t)0);
120121
mask1 = ~mask0;
121122
*r = (*r & mask0) | (*a & mask1);

src/secp256k1.c

+2-1
Original file line numberDiff line numberDiff line change
@@ -468,7 +468,8 @@ const secp256k1_nonce_function secp256k1_nonce_function_rfc6979 = nonce_function
468468
const secp256k1_nonce_function secp256k1_nonce_function_default = nonce_function_rfc6979;
469469

470470
int secp256k1_ecdsa_sign(const secp256k1_context* ctx, secp256k1_ecdsa_signature *signature, const unsigned char *msg32, const unsigned char *seckey, secp256k1_nonce_function noncefp, const void* noncedata) {
471-
secp256k1_scalar r, s;
471+
/* Default initialization here is important so we won't pass uninit values to the cmov in the end */
472+
secp256k1_scalar r = secp256k1_scalar_zero, s = secp256k1_scalar_zero;
472473
secp256k1_scalar sec, non, msg;
473474
int ret = 0;
474475
int is_sec_valid;

src/tests.c

-11
Original file line numberDiff line numberDiff line change
@@ -32,17 +32,6 @@ void ECDSA_SIG_get0(const ECDSA_SIG *sig, const BIGNUM **pr, const BIGNUM **ps)
3232
#include "contrib/lax_der_parsing.c"
3333
#include "contrib/lax_der_privatekey_parsing.c"
3434

35-
#if !defined(VG_CHECK)
36-
# if defined(VALGRIND)
37-
# include <valgrind/memcheck.h>
38-
# define VG_UNDEF(x,y) VALGRIND_MAKE_MEM_UNDEFINED((x),(y))
39-
# define VG_CHECK(x,y) VALGRIND_CHECK_MEM_IS_DEFINED((x),(y))
40-
# else
41-
# define VG_UNDEF(x,y)
42-
# define VG_CHECK(x,y)
43-
# endif
44-
#endif
45-
4635
static int count = 64;
4736
static secp256k1_context *ctx = NULL;
4837

src/util.h

+19
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,25 @@ static SECP256K1_INLINE void secp256k1_callback_call(const secp256k1_callback *
6969
#define VERIFY_SETUP(stmt)
7070
#endif
7171

72+
/* Define `VG_UNDEF` and `VG_CHECK` when VALGRIND is defined */
73+
#if !defined(VG_CHECK)
74+
# if defined(VALGRIND)
75+
# include <valgrind/memcheck.h>
76+
# define VG_UNDEF(x,y) VALGRIND_MAKE_MEM_UNDEFINED((x),(y))
77+
# define VG_CHECK(x,y) VALGRIND_CHECK_MEM_IS_DEFINED((x),(y))
78+
# else
79+
# define VG_UNDEF(x,y)
80+
# define VG_CHECK(x,y)
81+
# endif
82+
#endif
83+
84+
/* Like `VG_CHECK` but on VERIFY only */
85+
#if defined(VERIFY)
86+
#define VG_CHECK_VERIFY(x,y) VG_CHECK((x), (y))
87+
#else
88+
#define VG_CHECK_VERIFY(x,y)
89+
#endif
90+
7291
static SECP256K1_INLINE void *checked_malloc(const secp256k1_callback* cb, size_t size) {
7392
void *ret = malloc(size);
7493
if (ret == NULL) {

0 commit comments

Comments
 (0)