diff --git a/configure.ac b/configure.ac index 218b1659b2..e791276434 100644 --- a/configure.ac +++ b/configure.ac @@ -2357,6 +2357,16 @@ else AM_CFLAGS="$AM_CFLAGS -DWC_NO_HARDEN -DWC_NO_CACHE_RESISTANT" fi +# Fault protection hardening +AC_ARG_ENABLE([faultharden], + [AS_HELP_STRING([--enable-faultharden],[Enable Fault Hardened build (default: disabled)])], + [ENABLED_FAULTHARDEN=$enableval], + [ENABLED_FAULTHARDEN=yes]) + +if test "$ENABLED_FAULTHARDEN" = "yes" +then + AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_CHECK_SIG_FAULTS -DWOLFSSL_CHECK_VER_FAULTS" +fi # IPv6 Test Apps AC_ARG_ENABLE([ipv6], diff --git a/wolfcrypt/src/ecc.c b/wolfcrypt/src/ecc.c index 612ef0f736..40b2aed0bd 100644 --- a/wolfcrypt/src/ecc.c +++ b/wolfcrypt/src/ecc.c @@ -104,6 +104,9 @@ Possible ECC enable options: * unmasked copy is computed and stored each time it is * needed. * default: off + * WOLFSSL_CHECK_VER_FAULTS + * Sanity check on verification steps in case of faults. + * default: off */ /* @@ -8970,13 +8973,28 @@ static int ecc_verify_hash(mp_int *r, mp_int *s, const byte* hash, #endif if (err == MP_OKAY) { +#ifdef WOLFSSL_CHECK_VER_FAULTS + u1 = (mp_int*)XMALLOC(sizeof(mp_int), key->heap, DYNAMIC_TYPE_ECC); + u2 = (mp_int*)XMALLOC(sizeof(mp_int), key->heap, DYNAMIC_TYPE_ECC); + if (u1 == NULL || u2 == NULL) + err = MEMORY_E; +#else u1 = e; u2 = w; +#endif v = w; } if (err == MP_OKAY) { err = INIT_MP_INT_SIZE(w, ECC_KEY_MAX_BITS_NONULLCHECK(key)); } +#ifdef WOLFSSL_CHECK_VER_FAULTS + if (err == MP_OKAY) { + err = INIT_MP_INT_SIZE(u1, ECC_KEY_MAX_BITS_NONULLCHECK(key)); + } + if (err == MP_OKAY) { + err = INIT_MP_INT_SIZE(u2, ECC_KEY_MAX_BITS_NONULLCHECK(key)); + } +#endif /* allocate points */ if (err == MP_OKAY) { @@ -9000,10 +9018,22 @@ static int ecc_verify_hash(mp_int *r, mp_int *s, const byte* hash, if (err == MP_OKAY) err = mp_mulmod(e, w, curve->order, u1); +#ifdef WOLFSSL_CHECK_VER_FAULTS + if (err == MP_OKAY && mp_iszero(e) != MP_YES && mp_cmp(u1, e) == MP_EQ) { + err = BAD_STATE_E; + } +#endif + /* u2 = rw */ if (err == MP_OKAY) err = mp_mulmod(r, w, curve->order, u2); +#ifdef WOLFSSL_CHECK_VER_FAULTS + if (err == MP_OKAY && mp_cmp(u2, w) == MP_EQ) { + err = BAD_STATE_E; + } +#endif + /* find mG and mQ */ if (err == MP_OKAY) err = mp_copy(curve->Gx, mG->x); @@ -9031,16 +9061,35 @@ static int ecc_verify_hash(mp_int *r, mp_int *s, const byte* hash, #ifndef ECC_SHAMIR if (err == MP_OKAY) { + #ifdef WOLFSSL_CHECK_VER_FAULTS + ecc_point mG1, mQ1; + wc_ecc_copy_point(mQ, &mQ1); + wc_ecc_copy_point(mG, &mG1); + #endif + mp_digit mp = 0; if (!mp_iszero((MP_INT_SIZE*)u1)) { /* compute u1*mG + u2*mQ = mG */ err = wc_ecc_mulmod_ex(u1, mG, mG, curve->Af, curve->prime, 0, key->heap); + #ifdef WOLFSSL_CHECK_VER_FAULTS + if (err == MP_OKAY && wc_ecc_cmp_point(mG, &mG1) == MP_EQ) { + err = BAD_STATE_E; + } + + /* store new value for comparing with after add operation */ + wc_ecc_copy_point(mG, &mG1); + #endif if (err == MP_OKAY) { err = wc_ecc_mulmod_ex(u2, mQ, mQ, curve->Af, curve->prime, 0, key->heap); } + #ifdef WOLFSSL_CHECK_VER_FAULTS + if (err == MP_OKAY && wc_ecc_cmp_point(mQ, &mQ1) == MP_EQ) { + err = BAD_STATE_E; + } + #endif /* find the montgomery mp */ if (err == MP_OKAY) @@ -9050,6 +9099,14 @@ static int ecc_verify_hash(mp_int *r, mp_int *s, const byte* hash, if (err == MP_OKAY) err = ecc_projective_add_point_safe(mQ, mG, mG, curve->Af, curve->prime, mp, NULL); + #ifdef WOLFSSL_CHECK_VER_FAULTS + if (err == MP_OKAY && wc_ecc_cmp_point(mG, &mG1) == MP_EQ) { + err = BAD_STATE_E; + } + if (err == MP_OKAY && wc_ecc_cmp_point(mG, mQ) == MP_EQ) { + err = BAD_STATE_E; + } + #endif } else { /* compute 0*mG + u2*mQ = mG */ @@ -9072,6 +9129,7 @@ static int ecc_verify_hash(mp_int *r, mp_int *s, const byte* hash, } #endif /* ECC_SHAMIR */ #endif /* FREESCALE_LTC_ECC */ + /* v = X_x1 mod n */ if (err == MP_OKAY) err = mp_mod(mG->x, curve->order, v); @@ -9080,6 +9138,11 @@ static int ecc_verify_hash(mp_int *r, mp_int *s, const byte* hash, if (err == MP_OKAY) { if (mp_cmp(v, r) == MP_EQ) *res = 1; +#ifdef WOLFSSL_CHECK_VER_FAULTS + /* redundant comparison as sanity check that first one happened */ + if (*res == 1 && mp_cmp(r, v) != MP_EQ) + *res = 0; +#endif } /* cleanup */ @@ -9089,6 +9152,12 @@ static int ecc_verify_hash(mp_int *r, mp_int *s, const byte* hash, mp_clear(e); mp_clear(w); FREE_MP_INT_SIZE(w, key->heap, DYNAMIC_TYPE_ECC); +#ifdef WOLFSSL_CHECK_VER_FAULTS + mp_clear(u1); + FREE_MP_INT_SIZE(u1, key->heap, DYNAMIC_TYPE_ECC); + mp_clear(u2); + FREE_MP_INT_SIZE(u2, key->heap, DYNAMIC_TYPE_ECC); +#endif #if !defined(WOLFSSL_ASYNC_CRYPT) || !defined(HAVE_CAVIUM_V) FREE_MP_INT_SIZE(e_lcl, key->heap, DYNAMIC_TYPE_ECC); #endif diff --git a/wolfcrypt/src/ed25519.c b/wolfcrypt/src/ed25519.c index 09777dde76..fd80f86c1a 100644 --- a/wolfcrypt/src/ed25519.c +++ b/wolfcrypt/src/ed25519.c @@ -48,6 +48,7 @@ #include #include +#include #include #include #ifdef NO_INLINE @@ -628,6 +629,35 @@ int wc_ed25519ph_sign_msg(const byte* in, word32 inLen, byte* out, #ifdef HAVE_ED25519_VERIFY #ifndef WOLFSSL_SE050 + +#ifdef WOLFSSL_CHECK_VER_FAULTS +static const byte sha512_empty[] = { + 0xcf, 0x83, 0xe1, 0x35, 0x7e, 0xef, 0xb8, 0xbd, + 0xf1, 0x54, 0x28, 0x50, 0xd6, 0x6d, 0x80, 0x07, + 0xd6, 0x20, 0xe4, 0x05, 0x0b, 0x57, 0x15, 0xdc, + 0x83, 0xf4, 0xa9, 0x21, 0xd3, 0x6c, 0xe9, 0xce, + 0x47, 0xd0, 0xd1, 0x3c, 0x5d, 0x85, 0xf2, 0xb0, + 0xff, 0x83, 0x18, 0xd2, 0x87, 0x7e, 0xec, 0x2f, + 0x63, 0xb9, 0x31, 0xbd, 0x47, 0x41, 0x7a, 0x81, + 0xa5, 0x38, 0x32, 0x7a, 0xf9, 0x27, 0xda, 0x3e +}; + +/* sanity check that hash operation happened + * returns 0 on success */ +static int ed25519_hash_check(ed25519_key* key, byte* h) +{ + (void)key; /* passing in key in case other hash algroithms are used */ + + if (XMEMCMP(h, sha512_empty, WC_SHA512_DIGEST_SIZE) != 0) { + return 0; + } + else { + return BAD_STATE_E; + } +} +#endif + + /* sig is array of bytes containing the signature sigLen is the length of sig byte array @@ -675,6 +705,22 @@ static int ed25519_verify_msg_init_with_sha(const byte* sig, word32 sigLen, } if (ret == 0) ret = ed25519_hash_update(key, sha, sig, ED25519_SIG_SIZE/2); + +#ifdef WOLFSSL_CHECK_VER_FAULTS + /* sanity check that hash operation happened */ + if (ret == 0) { + byte h[WC_MAX_DIGEST_SIZE]; + + ret = wc_Sha512GetHash(sha, h); + if (ret == 0) { + ret = ed25519_hash_check(key, h); + if (ret != 0) { + WOLFSSL_MSG("Unexpected initial state of hash found"); + } + } + } +#endif + if (ret == 0) ret = ed25519_hash_update(key, sha, key->p, ED25519_PUB_KEY_SIZE); @@ -791,7 +837,16 @@ static int ed25519_verify_msg_final_with_sha(const byte* sig, word32 sigLen, ret = ConstantCompare(rcheck, sig, ED25519_SIG_SIZE/2); if (ret != 0) { ret = SIG_VERIFY_E; - } else { + } + +#ifdef WOLFSSL_CHECK_VER_FAULTS + /* redundant comparison as sanity check that first one happened */ + if (ret == 0 && ConstantCompare(rcheck, sig, ED25519_SIG_SIZE/2) != 0) { + ret = SIG_VERIFY_E; + } +#endif + + if (ret == 0) { /* set the verification status */ *res = 1; } diff --git a/wolfcrypt/src/ge_low_mem.c b/wolfcrypt/src/ge_low_mem.c index df747a126c..cb505af481 100644 --- a/wolfcrypt/src/ge_low_mem.c +++ b/wolfcrypt/src/ge_low_mem.c @@ -512,6 +512,33 @@ int ge_frombytes_negate_vartime(ge_p3 *p,const unsigned char *s) return ret; } +#ifdef WOLFSSL_CHECK_VER_FAULTS +/* return 0 if equal and -1 if not equal */ +static int ge_equal(ge a, ge b) +{ + if (XMEMCMP(a, b, sizeof(ge)) == 0) { + return 0; + } + else { + return -1; + } +} + +/* returns 0 if a == b */ +static int ge_p3_equal(ge_p3* a, ge_p3* b) +{ + int ret = 0; + + ret |= ge_equal(a->X, b->X); + ret |= ge_equal(a->Y, b->Y); + ret |= ge_equal(a->Z, b->Z); + ret |= ge_equal(a->T, b->T); + + return ret; +} +#endif + + int ge_double_scalarmult_vartime(ge_p2* R, const unsigned char *h, const ge_p3 *inA,const unsigned char *sig) @@ -526,9 +553,19 @@ int ge_double_scalarmult_vartime(ge_p2* R, const unsigned char *h, /* find H(R,A,M) * -A */ ed25519_smult(&A, &A, h); +#ifdef WOLFSSL_CHECK_VER_FAULTS + if (ge_p3_equal(&A, (ge_p3*)inA) == 0) { + ret = BAD_STATE_E; + } +#endif /* SB + -H(R,A,M)A */ ed25519_add(&A, &p, &A); +#ifdef WOLFSSL_CHECK_VER_FAULTS + if (ge_p3_equal(&A, &p) == 0) { + ret = BAD_STATE_E; + } +#endif lm_copy(R->X, A.X); lm_copy(R->Y, A.Y); diff --git a/wolfcrypt/src/ge_operations.c b/wolfcrypt/src/ge_operations.c index bcf9d354b5..95d58b2e2a 100644 --- a/wolfcrypt/src/ge_operations.c +++ b/wolfcrypt/src/ge_operations.c @@ -9467,6 +9467,13 @@ int ge_double_scalarmult_vartime(ge_p2 *r, const unsigned char *a, ge_p1p1_to_p2(r,t); } +#ifdef WOLFSSL_CHECK_VER_FAULTS + if (i != -1) { + /* did not go through whole loop */ + return BAD_STATE_E; + } +#endif + #if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_SP_NO_MALLOC) out: