Merge pull request #8289 from JacobBarthelmeh/harden

add option for additional sanity checks
This commit is contained in:
Sean Parkinson
2024-12-24 09:17:08 +10:00
committed by GitHub
5 changed files with 190 additions and 2 deletions

View File

@@ -2416,6 +2416,16 @@ else
AM_CFLAGS="$AM_CFLAGS -DWC_NO_HARDEN -DWC_NO_CACHE_RESISTANT" AM_CFLAGS="$AM_CFLAGS -DWC_NO_HARDEN -DWC_NO_CACHE_RESISTANT"
fi fi
# Fault protection hardening
AC_ARG_ENABLE([faultharden],
[AS_HELP_STRING([--enable-faultharden],[Enable Fault Hardened build (default: disabled)])],
[ENABLED_FAULTHARDEN=$enableval],
[ENABLED_FAULTHARDEN=no])
if test "$ENABLED_FAULTHARDEN" = "yes"
then
AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_CHECK_SIG_FAULTS -DWOLFSSL_CHECK_VER_FAULTS"
fi
# IPv6 Test Apps # IPv6 Test Apps
AC_ARG_ENABLE([ipv6], AC_ARG_ENABLE([ipv6],

View File

@@ -104,6 +104,9 @@ Possible ECC enable options:
* unmasked copy is computed and stored each time it is * unmasked copy is computed and stored each time it is
* needed. * needed.
* default: off * default: off
* WOLFSSL_CHECK_VER_FAULTS
* Sanity check on verification steps in case of faults.
* default: off
*/ */
/* /*
@@ -8880,9 +8883,12 @@ static int ecc_verify_hash(mp_int *r, mp_int *s, const byte* hash,
#endif #endif
mp_int* e; mp_int* e;
mp_int* v = NULL; /* Will be w. */ mp_int* v = NULL; /* Will be w. */
#if defined(WOLFSSL_CHECK_VER_FAULTS) && defined(WOLFSSL_NO_MALLOC)
mp_int u1tmp[1];
mp_int u2tmp[1];
#endif
mp_int* u1 = NULL; /* Will be e. */ mp_int* u1 = NULL; /* Will be e. */
mp_int* u2 = NULL; /* Will be w. */ mp_int* u2 = NULL; /* Will be w. */
#if defined(WOLFSSL_ASYNC_CRYPT) && defined(HAVE_CAVIUM_V) #if defined(WOLFSSL_ASYNC_CRYPT) && defined(HAVE_CAVIUM_V)
err = wc_ecc_alloc_mpint(key, &key->e); err = wc_ecc_alloc_mpint(key, &key->e);
if (err != 0) { if (err != 0) {
@@ -8970,13 +8976,33 @@ static int ecc_verify_hash(mp_int *r, mp_int *s, const byte* hash,
#endif #endif
if (err == MP_OKAY) { if (err == MP_OKAY) {
#ifdef WOLFSSL_CHECK_VER_FAULTS
#ifndef WOLFSSL_NO_MALLOC
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 = u1tmp;
u2 = u2tmp;
#endif
#else
u1 = e; u1 = e;
u2 = w; u2 = w;
#endif
v = w; v = w;
} }
if (err == MP_OKAY) { if (err == MP_OKAY) {
err = INIT_MP_INT_SIZE(w, ECC_KEY_MAX_BITS_NONULLCHECK(key)); 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 */ /* allocate points */
if (err == MP_OKAY) { if (err == MP_OKAY) {
@@ -9000,10 +9026,22 @@ static int ecc_verify_hash(mp_int *r, mp_int *s, const byte* hash,
if (err == MP_OKAY) if (err == MP_OKAY)
err = mp_mulmod(e, w, curve->order, u1); 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 */ /* u2 = rw */
if (err == MP_OKAY) if (err == MP_OKAY)
err = mp_mulmod(r, w, curve->order, u2); 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 */ /* find mG and mQ */
if (err == MP_OKAY) if (err == MP_OKAY)
err = mp_copy(curve->Gx, mG->x); err = mp_copy(curve->Gx, mG->x);
@@ -9031,16 +9069,35 @@ static int ecc_verify_hash(mp_int *r, mp_int *s, const byte* hash,
#ifndef ECC_SHAMIR #ifndef ECC_SHAMIR
if (err == MP_OKAY) 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; mp_digit mp = 0;
if (!mp_iszero((MP_INT_SIZE*)u1)) { if (!mp_iszero((MP_INT_SIZE*)u1)) {
/* compute u1*mG + u2*mQ = mG */ /* compute u1*mG + u2*mQ = mG */
err = wc_ecc_mulmod_ex(u1, mG, mG, curve->Af, curve->prime, 0, err = wc_ecc_mulmod_ex(u1, mG, mG, curve->Af, curve->prime, 0,
key->heap); 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) { if (err == MP_OKAY) {
err = wc_ecc_mulmod_ex(u2, mQ, mQ, curve->Af, curve->prime, 0, err = wc_ecc_mulmod_ex(u2, mQ, mQ, curve->Af, curve->prime, 0,
key->heap); 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 */ /* find the montgomery mp */
if (err == MP_OKAY) if (err == MP_OKAY)
@@ -9050,6 +9107,14 @@ static int ecc_verify_hash(mp_int *r, mp_int *s, const byte* hash,
if (err == MP_OKAY) if (err == MP_OKAY)
err = ecc_projective_add_point_safe(mQ, mG, mG, curve->Af, err = ecc_projective_add_point_safe(mQ, mG, mG, curve->Af,
curve->prime, mp, NULL); 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 { else {
/* compute 0*mG + u2*mQ = mG */ /* compute 0*mG + u2*mQ = mG */
@@ -9072,6 +9137,7 @@ static int ecc_verify_hash(mp_int *r, mp_int *s, const byte* hash,
} }
#endif /* ECC_SHAMIR */ #endif /* ECC_SHAMIR */
#endif /* FREESCALE_LTC_ECC */ #endif /* FREESCALE_LTC_ECC */
/* v = X_x1 mod n */ /* v = X_x1 mod n */
if (err == MP_OKAY) if (err == MP_OKAY)
err = mp_mod(mG->x, curve->order, v); err = mp_mod(mG->x, curve->order, v);
@@ -9080,6 +9146,11 @@ static int ecc_verify_hash(mp_int *r, mp_int *s, const byte* hash,
if (err == MP_OKAY) { if (err == MP_OKAY) {
if (mp_cmp(v, r) == MP_EQ) if (mp_cmp(v, r) == MP_EQ)
*res = 1; *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 */ /* cleanup */
@@ -9089,6 +9160,14 @@ static int ecc_verify_hash(mp_int *r, mp_int *s, const byte* hash,
mp_clear(e); mp_clear(e);
mp_clear(w); mp_clear(w);
FREE_MP_INT_SIZE(w, key->heap, DYNAMIC_TYPE_ECC); FREE_MP_INT_SIZE(w, key->heap, DYNAMIC_TYPE_ECC);
#ifdef WOLFSSL_CHECK_VER_FAULTS
mp_clear(u1);
mp_clear(u2);
#ifndef WOLFSSL_NO_MALLOC
XFREE(u1, key->heap, DYNAMIC_TYPE_ECC);
XFREE(u2, key->heap, DYNAMIC_TYPE_ECC);
#endif
#endif
#if !defined(WOLFSSL_ASYNC_CRYPT) || !defined(HAVE_CAVIUM_V) #if !defined(WOLFSSL_ASYNC_CRYPT) || !defined(HAVE_CAVIUM_V)
FREE_MP_INT_SIZE(e_lcl, key->heap, DYNAMIC_TYPE_ECC); FREE_MP_INT_SIZE(e_lcl, key->heap, DYNAMIC_TYPE_ECC);
#endif #endif

View File

@@ -48,6 +48,7 @@
#include <wolfssl/wolfcrypt/ed25519.h> #include <wolfssl/wolfcrypt/ed25519.h>
#include <wolfssl/wolfcrypt/ge_operations.h> #include <wolfssl/wolfcrypt/ge_operations.h>
#include <wolfssl/wolfcrypt/logging.h>
#include <wolfssl/wolfcrypt/error-crypt.h> #include <wolfssl/wolfcrypt/error-crypt.h>
#include <wolfssl/wolfcrypt/hash.h> #include <wolfssl/wolfcrypt/hash.h>
#ifdef NO_INLINE #ifdef NO_INLINE
@@ -628,6 +629,35 @@ int wc_ed25519ph_sign_msg(const byte* in, word32 inLen, byte* out,
#ifdef HAVE_ED25519_VERIFY #ifdef HAVE_ED25519_VERIFY
#ifndef WOLFSSL_SE050 #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 sig is array of bytes containing the signature
sigLen is the length of sig byte array 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) if (ret == 0)
ret = ed25519_hash_update(key, sha, sig, ED25519_SIG_SIZE/2); 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) if (ret == 0)
ret = ed25519_hash_update(key, sha, key->p, ED25519_PUB_KEY_SIZE); 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); ret = ConstantCompare(rcheck, sig, ED25519_SIG_SIZE/2);
if (ret != 0) { if (ret != 0) {
ret = SIG_VERIFY_E; 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 */ /* set the verification status */
*res = 1; *res = 1;
} }

View File

@@ -512,6 +512,33 @@ int ge_frombytes_negate_vartime(ge_p3 *p,const unsigned char *s)
return ret; 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, int ge_double_scalarmult_vartime(ge_p2* R, const unsigned char *h,
const ge_p3 *inA,const unsigned char *sig) 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 */ /* find H(R,A,M) * -A */
ed25519_smult(&A, &A, h); 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 */ /* SB + -H(R,A,M)A */
ed25519_add(&A, &p, &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->X, A.X);
lm_copy(R->Y, A.Y); lm_copy(R->Y, A.Y);

View File

@@ -9468,6 +9468,13 @@ int ge_double_scalarmult_vartime(ge_p2 *r, const unsigned char *a,
ge_p1p1_to_p2(r,t); 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) #if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_SP_NO_MALLOC)
out: out: