Skip to content

Commit 58ca6a1

Browse files
authored
Merge pull request #10302 from JacobBarthelmeh/ecc
additional sanity checks on invalid input
2 parents 80a0455 + f140546 commit 58ca6a1

9 files changed

Lines changed: 122 additions & 36 deletions

File tree

.github/workflows/os-check.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@ jobs:
106106
'CPPFLAGS=-DNO_WOLFSSL_CLIENT',
107107
'CPPFLAGS=-DNO_WOLFSSL_SERVER',
108108
'--enable-lms=small,verify-only --enable-xmss=small,verify-only',
109+
'--enable-opensslall --enable-ecc CPPFLAGS="-DWC_ALLOW_ECC_ZERO_HASH"',
109110
'--enable-curve25519=nonblock --enable-ecc=nonblock --enable-sp=yes,nonblock CPPFLAGS="-DWOLFSSL_PUBLIC_MP -DWOLFSSL_DEBUG_NONBLOCK"',
110111
'--enable-certreq --enable-certext --enable-certgen --disable-secure-renegotiation-info CPPFLAGS="-DNO_TLS"',
111112
# Minimal DTLS 1.3 client-only build. The SHA-224/384/512/3

.wolfssl_known_macro_extras

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -623,6 +623,7 @@ USS_API
623623
WC_AESXTS_STREAM_NO_REQUEST_ACCOUNTING
624624
WC_AES_BS_WORD_SIZE
625625
WC_AES_GCM_DEC_AUTH_EARLY
626+
WC_ALLOW_ECC_ZERO_HASH
626627
WC_ASN_HASH_SHA256
627628
WC_ASN_RUNTIME_DATE_CHECK_CONTROL
628629
WC_ASYNC_ENABLE_ECC_KEYGEN

tests/api/test_evp_cipher.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2195,7 +2195,7 @@ int test_wolfssl_EVP_sm4_ecb(void)
21952195
};
21962196
byte cipherText[sizeof(plainText) + SM4_BLOCK_SIZE];
21972197
byte decryptedText[sizeof(plainText) + SM4_BLOCK_SIZE];
2198-
EVP_CIPHER_CTX* ctx;
2198+
EVP_CIPHER_CTX* ctx = NULL;
21992199
int outSz;
22002200

22012201
XMEMSET(key, 0, sizeof(key));
@@ -2251,7 +2251,7 @@ int test_wolfssl_EVP_sm4_cbc(void)
22512251
};
22522252
byte cipherText[sizeof(plainText) + SM4_BLOCK_SIZE];
22532253
byte decryptedText[sizeof(plainText) + SM4_BLOCK_SIZE];
2254-
EVP_CIPHER_CTX* ctx;
2254+
EVP_CIPHER_CTX* ctx = NULL;
22552255
int outSz;
22562256

22572257
XMEMSET(key, 0, sizeof(key));
@@ -2319,7 +2319,7 @@ int test_wolfssl_EVP_sm4_ctr(void)
23192319
byte plainText[] = {0xDE, 0xAD, 0xBE, 0xEF};
23202320
byte cipherText[sizeof(plainText)];
23212321
byte decryptedText[sizeof(plainText)];
2322-
EVP_CIPHER_CTX* ctx;
2322+
EVP_CIPHER_CTX* ctx = NULL;
23232323
int outSz;
23242324

23252325
XMEMSET(key, 0, sizeof(key));

tests/api/test_evp_pkey.c

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1592,9 +1592,25 @@ static int test_wolfSSL_EVP_PKEY_sign_verify(int keyType)
15921592
ExpectIntEQ(EVP_PKEY_verify(
15931593
ctx_verify, sig, siglen, hash, SHA256_DIGEST_LENGTH),
15941594
WOLFSSL_SUCCESS);
1595-
ExpectIntEQ(EVP_PKEY_verify(
1596-
ctx_verify, sig, siglen, zero, SHA256_DIGEST_LENGTH),
1597-
WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
1595+
1596+
if (keyType == EVP_PKEY_EC) {
1597+
#ifdef WC_TEST_NO_ECC_SIGN_VERIFY_ZERO_DIGEST
1598+
/* wolfSSL differs from OpenSSL in that it treats a hash of all 0's as a
1599+
* fatal error and does not attempt to verify */
1600+
ExpectIntEQ(EVP_PKEY_verify(
1601+
ctx_verify, sig, siglen, zero, SHA256_DIGEST_LENGTH),
1602+
WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR));
1603+
#else
1604+
ExpectIntEQ(EVP_PKEY_verify(
1605+
ctx_verify, sig, siglen, zero, SHA256_DIGEST_LENGTH),
1606+
WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
1607+
#endif
1608+
}
1609+
else {
1610+
ExpectIntEQ(EVP_PKEY_verify(
1611+
ctx_verify, sig, siglen, zero, SHA256_DIGEST_LENGTH),
1612+
WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
1613+
}
15981614

15991615
#if defined(OPENSSL_EXTRA) && !defined(NO_RSA) && defined(WOLFSSL_KEY_GEN) && \
16001616
!defined(HAVE_SELFTEST)

wolfcrypt/src/ecc.c

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7272,6 +7272,10 @@ int wc_ecc_sign_hash_ex(const byte* in, word32 inlen, WC_RNG* rng,
72727272
ecc_key* key, mp_int *r, mp_int *s)
72737273
{
72747274
int err = 0;
7275+
#ifndef WC_ALLOW_ECC_ZERO_HASH
7276+
byte hashIsZero = 0;
7277+
word32 zIdx;
7278+
#endif
72757279
#if !defined(WOLFSSL_SP_MATH)
72767280
mp_int* e;
72777281
#if !defined(WOLFSSL_ASYNC_CRYPT) || !defined(HAVE_CAVIUM_V)
@@ -7298,6 +7302,14 @@ int wc_ecc_sign_hash_ex(const byte* in, word32 inlen, WC_RNG* rng,
72987302
return BAD_LENGTH_E;
72997303
}
73007304

7305+
#ifndef WC_ALLOW_ECC_ZERO_HASH
7306+
/* reject all 0's hash */
7307+
for (zIdx = 0; zIdx < inlen; zIdx++)
7308+
hashIsZero |= in[zIdx];
7309+
if (hashIsZero == 0)
7310+
return ECC_BAD_ARG_E;
7311+
#endif
7312+
73017313
/* is this a private key? */
73027314
if (key->type != ECC_PRIVATEKEY && key->type != ECC_PRIVATEKEY_ONLY) {
73037315
return ECC_BAD_ARG_E;
@@ -9274,6 +9286,10 @@ int wc_ecc_verify_hash_ex(mp_int *r, mp_int *s, const byte* hash,
92749286
#else
92759287
int err;
92769288
word32 keySz = 0;
9289+
#ifndef WC_ALLOW_ECC_ZERO_HASH
9290+
byte hashIsZero = 0;
9291+
word32 zIdx;
9292+
#endif
92779293
#if defined(WOLFSSL_ATECC508A) || defined(WOLFSSL_ATECC608A)
92789294
byte sigRS[ATECC_KEY_SIZE*2];
92799295
#elif defined(WOLFSSL_CRYPTOCELL)
@@ -9303,6 +9319,14 @@ int wc_ecc_verify_hash_ex(mp_int *r, mp_int *s, const byte* hash,
93039319
return BAD_LENGTH_E;
93049320
}
93059321

9322+
#ifndef WC_ALLOW_ECC_ZERO_HASH
9323+
/* reject all 0's hash */
9324+
for (zIdx = 0; zIdx < hashlen; zIdx++)
9325+
hashIsZero |= hash[zIdx];
9326+
if (hashIsZero == 0)
9327+
return ECC_BAD_ARG_E;
9328+
#endif
9329+
93069330
/* default to invalid signature */
93079331
*res = 0;
93089332

wolfcrypt/src/port/atmel/atmel.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -469,6 +469,16 @@ int atmel_ecc_create_key(int slotId, byte* peerKey)
469469
int atmel_ecc_sign(int slotId, const byte* message, byte* signature)
470470
{
471471
int ret;
472+
#ifndef WC_ALLOW_ECC_ZERO_HASH
473+
byte hashIsZero = 0;
474+
word32 zIdx;
475+
476+
/* defensive sanity check on all 0's hash */
477+
for (zIdx = 0; zIdx < ATECC_KEY_SIZE; zIdx++)
478+
hashIsZero |= message[zIdx];
479+
if (hashIsZero == 0)
480+
return ECC_BAD_ARG_E;
481+
#endif
472482

473483
ret = atcab_sign(slotId, message, signature);
474484
ret = atmel_ecc_translate_err(ret);

wolfcrypt/src/port/nxp/se050_port.c

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2113,6 +2113,10 @@ int se050_ecc_sign_hash_ex(const byte* in, word32 inLen, MATH_INT_T* r, MATH_INT
21132113
size_t sigSz = sizeof(sigBuf);
21142114
word32 rLen = 0;
21152115
word32 sLen = 0;
2116+
#ifndef WC_ALLOW_ECC_ZERO_HASH
2117+
byte hashIsZero = 0;
2118+
word32 zIdx;
2119+
#endif
21162120

21172121
#ifdef SE050_DEBUG
21182122
printf("se050_ecc_sign_hash_ex: key %p, in %p (%d), out %p (%d), "
@@ -2124,6 +2128,15 @@ int se050_ecc_sign_hash_ex(const byte* in, word32 inLen, MATH_INT_T* r, MATH_INT
21242128
return BAD_FUNC_ARG;
21252129
}
21262130

2131+
#ifndef WC_ALLOW_ECC_ZERO_HASH
2132+
/* SE050 hardware does not reject all-zero digests; mirror the
2133+
* software path's check so behavior is consistent. */
2134+
for (zIdx = 0; zIdx < inLen; zIdx++)
2135+
hashIsZero |= in[zIdx];
2136+
if (hashIsZero == 0)
2137+
return ECC_BAD_ARG_E;
2138+
#endif
2139+
21272140
if (cfg_se050_i2c_pi == NULL) {
21282141
return WC_HW_E;
21292142
}

wolfcrypt/test/test.c

Lines changed: 40 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -36876,9 +36876,12 @@ static wc_test_ret_t ecc_test_curve_size(WC_RNG* rng, int keySize, int testVerif
3687636876
#if !defined(ECC_TIMING_RESISTANT) || (defined(ECC_TIMING_RESISTANT) && \
3687736877
!defined(WC_NO_RNG) && !defined(WOLFSSL_KCAPI_ECC))
3687836878
#ifdef HAVE_ECC_SIGN
36879-
/* some hardware doesn't support sign/verify of all zero digest */
36880-
#if !defined(WC_TEST_NO_ECC_SIGN_VERIFY_ZERO_DIGEST)
36881-
/* test DSA sign hash with zeros */
36879+
/* WC_TEST_NO_ECC_SIGN_VERIFY_ZERO_DIGEST: build rejects all-zero digest,
36880+
* so test expects failure. */
36881+
#ifdef WOLFSSL_SM2
36882+
if (curve_id != ECC_SM2P256V1)
36883+
#endif
36884+
{
3688236885
for (i = 0; i < (int)ECC_DIGEST_SIZE; i++) {
3688336886
digest[i] = 0;
3688436887
}
@@ -36892,29 +36895,47 @@ static wc_test_ret_t ecc_test_curve_size(WC_RNG* rng, int keySize, int testVerif
3689236895
ret = wc_ecc_sign_hash(digest, ECC_DIGEST_SIZE, sig, &x, rng,
3689336896
userA);
3689436897
} while (ret == WC_NO_ERR_TRACE(WC_PENDING_E));
36898+
#ifdef WC_TEST_NO_ECC_SIGN_VERIFY_ZERO_DIGEST
36899+
if (ret == 0) {
36900+
ERROR_OUT(WC_TEST_RET_ENC_EC(ret), done);
36901+
}
36902+
else {
36903+
ret = 0;
36904+
}
36905+
#else
3689536906
if (ret != 0)
3689636907
ERROR_OUT(WC_TEST_RET_ENC_EC(ret), done);
36908+
#endif
3689736909
TEST_SLEEP();
3689836910

3689936911
#ifdef HAVE_ECC_VERIFY
36900-
for (i=0; i<testVerifyCount; i++) {
36901-
verify = 0;
36902-
do {
36903-
#if defined(WOLFSSL_ASYNC_CRYPT)
36904-
ret = wc_AsyncWait(ret, &userA->asyncDev, WC_ASYNC_FLAG_CALL_AGAIN);
36905-
#endif
36906-
if (ret == 0)
36907-
ret = wc_ecc_verify_hash(sig, x, digest, ECC_DIGEST_SIZE,
36908-
&verify, userA);
36909-
} while (ret == WC_NO_ERR_TRACE(WC_PENDING_E));
36910-
if (ret != 0)
36911-
ERROR_OUT(WC_TEST_RET_ENC_EC(ret), done);
36912-
if (verify != 1)
36913-
ERROR_OUT(WC_TEST_RET_ENC_NC, done);
36914-
TEST_SLEEP();
36912+
verify = 0;
36913+
do {
36914+
#if defined(WOLFSSL_ASYNC_CRYPT)
36915+
ret = wc_AsyncWait(ret, &userA->asyncDev, WC_ASYNC_FLAG_CALL_AGAIN);
36916+
#endif
36917+
if (ret == 0)
36918+
ret = wc_ecc_verify_hash(sig, x, digest, ECC_DIGEST_SIZE,
36919+
&verify, userA);
36920+
} while (ret == WC_NO_ERR_TRACE(WC_PENDING_E));
36921+
#ifdef WC_TEST_NO_ECC_SIGN_VERIFY_ZERO_DIGEST
36922+
if (ret == 0) {
36923+
ERROR_OUT(WC_TEST_RET_ENC_EC(ret), done);
3691536924
}
36925+
else {
36926+
ret = 0;
36927+
}
36928+
if (verify == 1)
36929+
ERROR_OUT(WC_TEST_RET_ENC_NC, done);
36930+
#else
36931+
if (ret != 0)
36932+
ERROR_OUT(WC_TEST_RET_ENC_EC(ret), done);
36933+
if (verify != 1)
36934+
ERROR_OUT(WC_TEST_RET_ENC_NC, done);
36935+
#endif
36936+
TEST_SLEEP();
3691636937
#endif /* HAVE_ECC_VERIFY */
36917-
#endif /* !WC_TEST_NO_ECC_SIGN_VERIFY_ZERO_DIGEST */
36938+
}
3691836939

3691936940
/* test DSA sign hash with sequence (0,1,2,3,4,...) */
3692036941
for (i = 0; i < (int)ECC_DIGEST_SIZE; i++) {

wolfssl/wolfcrypt/settings.h

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3518,13 +3518,18 @@ extern void uITRON4_free(void *p) ;
35183518
#undef NO_DH
35193519
#endif
35203520

3521-
/* CryptoCell defines */
3522-
#ifdef WOLFSSL_CRYPTOCELL
3523-
#if defined(HAVE_ECC) && defined(HAVE_ECC_SIGN)
3524-
/* Don't attempt to sign/verify an all-zero digest in wolfCrypt tests */
3521+
#ifdef HAVE_ECC
3522+
/* defined for all ECC non FIPS builds and for FIPS v7+ (including
3523+
* fips-ready/fips-dev which track the latest in-development source),
3524+
* unless the user explicitly opts in to allowing an all-zero digest with
3525+
* WC_ALLOW_ECC_ZERO_HASH or is building with HAVE_SELFTEST */
3526+
#if (!defined(HAVE_FIPS) || FIPS_VERSION_GT(7,0) || \
3527+
defined(WOLFSSL_FIPS_READY) || defined(WOLFSSL_FIPS_DEV)) && \
3528+
!defined(HAVE_SELFTEST) && !defined(WC_ALLOW_ECC_ZERO_HASH)
3529+
/* sign/verify of an all-zero digest in wolfCrypt rejected */
35253530
#define WC_TEST_NO_ECC_SIGN_VERIFY_ZERO_DIGEST
3526-
#endif /* HAVE_ECC && HAVE_ECC_SIGN */
3527-
#endif
3531+
#endif
3532+
#endif /* HAVE_ECC */
35283533

35293534
/* Asynchronous Crypto */
35303535
#ifdef WOLFSSL_ASYNC_CRYPT
@@ -3551,11 +3556,6 @@ extern void uITRON4_free(void *p) ;
35513556
#define ECC_CACHE_CURVE
35523557
#endif
35533558

3554-
#if defined(HAVE_ECC) && defined(HAVE_ECC_SIGN)
3555-
/* Don't attempt to sign/verify an all-zero digest in wolfCrypt tests */
3556-
#define WC_TEST_NO_ECC_SIGN_VERIFY_ZERO_DIGEST
3557-
#endif /* HAVE_ECC && HAVE_ECC_SIGN */
3558-
35593559
#endif /* WOLFSSL_ASYNC_CRYPT */
35603560
#ifndef WC_ASYNC_DEV_SIZE
35613561
#define WC_ASYNC_DEV_SIZE 0

0 commit comments

Comments
 (0)