From f0a0cd1078b9fe20c2fd4ee295a995bf957a517a Mon Sep 17 00:00:00 2001 From: Jacob Barthelmeh Date: Mon, 14 Feb 2022 09:55:38 -0700 Subject: [PATCH 1/5] fix for larger curve sizes with deterministic ECC sign --- wolfcrypt/src/ecc.c | 46 +++++++++++++++++--------- wolfcrypt/test/test.c | 76 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 107 insertions(+), 15 deletions(-) diff --git a/wolfcrypt/src/ecc.c b/wolfcrypt/src/ecc.c index de36e8a48..54dad8ada 100644 --- a/wolfcrypt/src/ecc.c +++ b/wolfcrypt/src/ecc.c @@ -6287,7 +6287,7 @@ int wc_ecc_gen_deterministic_k(const byte* hash, word32 hashSz, { int ret = 0, qbits = 0; #ifndef WOLFSSL_SMALL_STACK - byte h1[WC_MAX_DIGEST_SIZE]; + byte h1[MAX_ECC_BYTES]; byte V[WC_MAX_DIGEST_SIZE]; byte K[WC_MAX_DIGEST_SIZE]; byte x[MAX_ECC_BYTES]; @@ -6317,7 +6317,7 @@ int wc_ecc_gen_deterministic_k(const byte* hash, word32 hashSz, } #ifdef WOLFSSL_SMALL_STACK - h1 = (byte*)XMALLOC(WC_MAX_DIGEST_SIZE, heap, DYNAMIC_TYPE_DIGEST); + h1 = (byte*)XMALLOC(MAX_ECC_BYTES, heap, DYNAMIC_TYPE_DIGEST); if (h1 == NULL) { ret = MEMORY_E; } @@ -6360,7 +6360,8 @@ int wc_ecc_gen_deterministic_k(const byte* hash, word32 hashSz, } #endif - VSz = KSz = h1len = xSz = hashSz; + VSz = KSz = hashSz; + xSz = h1len = mp_unsigned_bin_size(order); /* 3.2 b. Set V = 0x01 0x01 ... */ XMEMSET(V, 0x01, VSz); @@ -6369,7 +6370,7 @@ int wc_ecc_gen_deterministic_k(const byte* hash, word32 hashSz, XMEMSET(K, 0x00, KSz); mp_init(z1); /* always init z1 and free z1 */ - ret = mp_to_unsigned_bin_len(priv, x, hashSz); + ret = mp_to_unsigned_bin_len(priv, x, xSz); if (ret == 0) { qbits = mp_count_bits(order); ret = mp_read_unsigned_bin(z1, hash, hashSz); @@ -6377,9 +6378,7 @@ int wc_ecc_gen_deterministic_k(const byte* hash, word32 hashSz, /* bits2octets on h1 */ if (ret == 0) { - /* right shift by bits in hash minus bits in order */ - mp_rshb(z1, (hashSz * WOLFSSL_BIT_SIZE) - qbits); - XMEMSET(h1, 0, WC_MAX_DIGEST_SIZE); + XMEMSET(h1, 0, MAX_ECC_BYTES); #if !defined(WOLFSSL_ECDSA_DETERMINISTIC_K_VARIANT) /* mod reduce by order using conditional subtract @@ -6391,20 +6390,18 @@ int wc_ecc_gen_deterministic_k(const byte* hash, word32 hashSz, mp_sub(z1, order, z1); z1Sz = mp_unsigned_bin_size(z1); - if (z1Sz < 0 || z1Sz > WC_MAX_DIGEST_SIZE) { + if (z1Sz < 0 || z1Sz > MAX_ECC_BYTES) { ret = BUFFER_E; } else { - h1len = (word32)z1Sz; - ret = mp_to_unsigned_bin(z1, h1); + ret = mp_to_unsigned_bin_len(z1, h1, h1len); } } else #endif { /* use original hash and keep leading 0's */ - h1len = hashSz; - XMEMCPY(h1, hash, hashSz); + mp_to_unsigned_bin_len(z1, h1, h1len); } } mp_free(z1); @@ -6438,18 +6435,37 @@ int wc_ecc_gen_deterministic_k(const byte* hash, word32 hashSz, /* 3.2 step h. loop through the next steps until a valid value is found */ if (ret == 0 ) { + word32 qLen = (qbits+7)/8; int err; intOct = 0x00; do { + xSz = 0; /* used as tLen */ err = 0; /* start as good until generated k is tested */ /* 3.2 step h.2 when tlen < qlen do V = HMAC_K(V); T = T || V */ - ret = _HMAC_K(K, KSz, V, VSz, NULL, 0, NULL, 0, NULL, V, hashType, - heap); + while (xSz < qLen) { + ret = _HMAC_K(K, KSz, V, VSz, NULL, 0, NULL, 0, NULL, V, + hashType, heap); + if (ret == 0) { + int sz; + + sz = (qLen - xSz < VSz) ? qLen-xSz : VSz; + if (xSz + sz > qLen) { + ret = BUFFER_E; + break; + } + XMEMCPY(x + xSz, V, sz); + xSz += sz; + } + else { + break; /* error case */ + } + } + if (ret == 0) { mp_clear(k); /* 3.2 step h.1 clear T */ - ret = mp_read_unsigned_bin(k, V, VSz); + ret = mp_read_unsigned_bin(k, x, xSz); } if ((ret == 0) && ((int)(VSz * WOLFSSL_BIT_SIZE) != qbits)) { diff --git a/wolfcrypt/test/test.c b/wolfcrypt/test/test.c index a4ef84533..bd6e39daf 100644 --- a/wolfcrypt/test/test.c +++ b/wolfcrypt/test/test.c @@ -20869,6 +20869,77 @@ static int ecc_test_deterministic_k(WC_RNG* rng) } TEST_SLEEP(); +done: + wc_ecc_free(&key); + return ret; +} + +/* KAT from RFC6979 */ +static int ecc384_test_deterministic_k(WC_RNG* rng) +{ + int ret; + ecc_key key; + byte sig[72]; + word32 sigSz; + unsigned char msg[] = "sample"; + unsigned char hash[32]; + const char* dIUT = + "6B9D3DAD2E1B8C1C05B19875B6659F4DE23C3B667BF297BA9AA47740787137D8" + "96D5724E4C70A825F872C9EA60D2EDF5"; + const char* QIUTx = + "EC3A4E415B4E19A4568618029F427FA5DA9A8BC4AE92E02E06AAE5286B300C64" + "DEF8F0EA9055866064A254515480BC13"; + const char* QIUTy = + "8015D9B72D7D57244EA8EF9AC0C621896708A59367F9DFB9F54CA84B3F1C9DB1" + "288B231C3AE0D4FE7344FD2533264720"; + const char* expRstr = + "21B13D1E013C7FA1392D03C5F99AF8B30C570C6F98D4EA8E354B63A21D3DAA33" + "BDE1E888E63355D92FA2B3C36D8FB2CD"; + const char* expSstr = + "F3AA443FB107745BF4BD77CB3891674632068A10CA67E3D45DB2266FA7D1FEEB" + "EFDC63ECCD1AC42EC0CB8668A4FA0AB0"; + mp_int r,s, expR, expS; + + mp_init_multi(&r, &s, &expR, &expS, NULL, NULL); + ret = wc_ecc_init_ex(&key, HEAP_HINT, devId); + if (ret != 0) { + return ret; + } + ret = wc_ecc_import_raw(&key, QIUTx, QIUTy, dIUT, "SECP384R1"); + if (ret != 0) { + goto done; + } + + ret = wc_Hash(WC_HASH_TYPE_SHA256, msg, + (word32)XSTRLEN((const char*)msg), hash, sizeof(hash)); + if (ret != 0) { + goto done; + } + + ret = wc_ecc_set_deterministic(&key, 1); + if (ret != 0) { + goto done; + } + + sigSz = sizeof(sig); + do { + #if defined(WOLFSSL_ASYNC_CRYPT) + ret = wc_AsyncWait(ret, &key.asyncDev, WC_ASYNC_FLAG_CALL_AGAIN); + #endif + if (ret == 0) + ret = wc_ecc_sign_hash_ex(hash, sizeof(hash), rng, &key, &r, &s); + } while (ret == WC_PENDING_E); + if (ret != 0) { + goto done; + } + TEST_SLEEP(); + + mp_read_radix(&expR, expRstr, MP_RADIX_HEX); + mp_read_radix(&expS, expSstr, MP_RADIX_HEX); + if (mp_cmp(&r, &expR) != MP_EQ) { + ret = -1; + } + done: wc_ecc_free(&key); return ret; @@ -23812,6 +23883,11 @@ WOLFSSL_TEST_SUBROUTINE int ecc_test(void) printf("ecc_test_deterministic_k failed! %d\n", ret); goto done; } + ret = ecc384_test_deterministic_k(&rng); + if (ret != 0) { + printf("ecc384_test_deterministic_k failed! %d\n", ret); + goto done; + } #endif #if defined(HAVE_ECC_SIGN) && defined(WOLFSSL_ECDSA_SET_K) From a5ce2a33eb0a7f89946382d96bd275f71422dd6e Mon Sep 17 00:00:00 2001 From: Jacob Barthelmeh Date: Tue, 15 Feb 2022 11:58:59 -0700 Subject: [PATCH 2/5] add macro guard around test case --- wolfcrypt/test/test.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/wolfcrypt/test/test.c b/wolfcrypt/test/test.c index bd6e39daf..80c8322ef 100644 --- a/wolfcrypt/test/test.c +++ b/wolfcrypt/test/test.c @@ -20874,6 +20874,7 @@ done: return ret; } +#ifdef WOLFSSL_PUBLIC_MP /* KAT from RFC6979 */ static int ecc384_test_deterministic_k(WC_RNG* rng) { @@ -20944,6 +20945,7 @@ done: wc_ecc_free(&key); return ret; } +#endif /* WOLFSSL_PUBLIC_MP */ #endif @@ -23883,11 +23885,13 @@ WOLFSSL_TEST_SUBROUTINE int ecc_test(void) printf("ecc_test_deterministic_k failed! %d\n", ret); goto done; } + #ifdef WOLFSSL_PUBLIC_MP ret = ecc384_test_deterministic_k(&rng); if (ret != 0) { printf("ecc384_test_deterministic_k failed! %d\n", ret); goto done; } + #endif #endif #if defined(HAVE_ECC_SIGN) && defined(WOLFSSL_ECDSA_SET_K) From 56de8cd6229f0ffd005c161622a774c581e93ad2 Mon Sep 17 00:00:00 2001 From: Jacob Barthelmeh Date: Wed, 2 Mar 2022 16:52:04 -0700 Subject: [PATCH 3/5] add check on hash size passed in --- wolfcrypt/src/ecc.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/wolfcrypt/src/ecc.c b/wolfcrypt/src/ecc.c index 54dad8ada..f7fb835fa 100644 --- a/wolfcrypt/src/ecc.c +++ b/wolfcrypt/src/ecc.c @@ -6311,6 +6311,11 @@ int wc_ecc_gen_deterministic_k(const byte* hash, word32 hashSz, return BAD_FUNC_ARG; } + if (hashSz != WC_SHA256_DIGEST_SIZE) { + WOLFSSL_MSG("Currently only SHA256 digest is supported"); + return BAD_FUNC_ARG; + } + if (mp_unsigned_bin_size(priv) > MAX_ECC_BYTES) { WOLFSSL_MSG("private key larger than max expected!"); return BAD_FUNC_ARG; From d1212f924719e19c9be34780451386331617ae81 Mon Sep 17 00:00:00 2001 From: Jacob Barthelmeh Date: Thu, 3 Mar 2022 10:44:24 -0700 Subject: [PATCH 4/5] add P521 test case and fix for k generation --- wolfcrypt/src/ecc.c | 11 +++--- wolfcrypt/test/test.c | 86 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 91 insertions(+), 6 deletions(-) diff --git a/wolfcrypt/src/ecc.c b/wolfcrypt/src/ecc.c index f7fb835fa..aac9fe657 100644 --- a/wolfcrypt/src/ecc.c +++ b/wolfcrypt/src/ecc.c @@ -6299,7 +6299,7 @@ int wc_ecc_gen_deterministic_k(const byte* hash, word32 hashSz, byte *x = NULL; mp_int *z1 = NULL; #endif - word32 xSz, VSz, KSz, h1len; + word32 xSz, VSz, KSz, h1len, qLen; byte intOct; if (hash == NULL || k == NULL || order == NULL) { @@ -6366,7 +6366,7 @@ int wc_ecc_gen_deterministic_k(const byte* hash, word32 hashSz, #endif VSz = KSz = hashSz; - xSz = h1len = mp_unsigned_bin_size(order); + qLen = xSz = h1len = mp_unsigned_bin_size(order); /* 3.2 b. Set V = 0x01 0x01 ... */ XMEMSET(V, 0x01, VSz); @@ -6375,7 +6375,7 @@ int wc_ecc_gen_deterministic_k(const byte* hash, word32 hashSz, XMEMSET(K, 0x00, KSz); mp_init(z1); /* always init z1 and free z1 */ - ret = mp_to_unsigned_bin_len(priv, x, xSz); + ret = mp_to_unsigned_bin_len(priv, x, qLen); if (ret == 0) { qbits = mp_count_bits(order); ret = mp_read_unsigned_bin(z1, hash, hashSz); @@ -6440,7 +6440,6 @@ int wc_ecc_gen_deterministic_k(const byte* hash, word32 hashSz, /* 3.2 step h. loop through the next steps until a valid value is found */ if (ret == 0 ) { - word32 qLen = (qbits+7)/8; int err; intOct = 0x00; @@ -6473,10 +6472,10 @@ int wc_ecc_gen_deterministic_k(const byte* hash, word32 hashSz, ret = mp_read_unsigned_bin(k, x, xSz); } - if ((ret == 0) && ((int)(VSz * WOLFSSL_BIT_SIZE) != qbits)) { + if ((ret == 0) && ((int)(xSz * WOLFSSL_BIT_SIZE) != qbits)) { /* handle odd case where shift of 'k' is needed with RFC 6979 * k = bits2int(T) in section 3.2 h.3 */ - mp_rshb(k, (VSz * WOLFSSL_BIT_SIZE) - qbits); + mp_rshb(k, (xSz * WOLFSSL_BIT_SIZE) - qbits); } /* 3.2 step h.3 the key should be smaller than the order of base diff --git a/wolfcrypt/test/test.c b/wolfcrypt/test/test.c index 80c8322ef..1e953fd5d 100644 --- a/wolfcrypt/test/test.c +++ b/wolfcrypt/test/test.c @@ -20945,6 +20945,85 @@ done: wc_ecc_free(&key); return ret; } + +#if defined(HAVE_ECC521) +/* KAT from RFC6979 */ +static int ecc512_test_deterministic_k(WC_RNG* rng) +{ + int ret; + ecc_key key; + byte sig[ECC_MAX_SIG_SIZE]; + word32 sigSz; + unsigned char msg[] = "sample"; + unsigned char hash[32]; + + const char* dIUT = + "0FAD06DAA62BA3B25D2FB40133DA757205DE67F5BB0018FEE8C86E1B68C7E75C" + "AA896EB32F1F47C70855836A6D16FCC1466F6D8FBEC67DB89EC0C08B0E996B83" + "538"; + const char* QIUTx = + "1894550D0785932E00EAA23B694F213F8C3121F86DC97A04E5A7167DB4E5BCD3" + "71123D46E45DB6B5D5370A7F20FB633155D38FFA16D2BD761DCAC474B9A2F502" + "3A4"; + const char* QIUTy = + "0493101C962CD4D2FDDF782285E64584139C2F91B47F87FF82354D6630F746A2" + "8A0DB25741B5B34A828008B22ACC23F924FAAFBD4D33F81EA66956DFEAA2BFDF" + "CF5"; + const char* expRstr = + "1511BB4D675114FE266FC4372B87682BAECC01D3CC62CF2303C92B3526012659" + "D16876E25C7C1E57648F23B73564D67F61C6F14D527D54972810421E7D87589E" + "1A7"; + const char* expSstr = + "04A171143A83163D6DF460AAF61522695F207A58B95C0644D87E52AA1A347916" + "E4F7A72930B1BC06DBE22CE3F58264AFD23704CBB63B29B931F7DE6C9D949A7E" + "CFC"; + mp_int r,s, expR, expS; + + mp_init_multi(&r, &s, &expR, &expS, NULL, NULL); + ret = wc_ecc_init_ex(&key, HEAP_HINT, devId); + if (ret != 0) { + return ret; + } + ret = wc_ecc_import_raw(&key, QIUTx, QIUTy, dIUT, "SECP521R1"); + if (ret != 0) { + goto done; + } + + ret = wc_Hash(WC_HASH_TYPE_SHA256, msg, + (word32)XSTRLEN((const char*)msg), hash, sizeof(hash)); + if (ret != 0) { + goto done; + } + + ret = wc_ecc_set_deterministic(&key, 1); + if (ret != 0) { + goto done; + } + + sigSz = sizeof(sig); + do { + #if defined(WOLFSSL_ASYNC_CRYPT) + ret = wc_AsyncWait(ret, &key.asyncDev, WC_ASYNC_FLAG_CALL_AGAIN); + #endif + if (ret == 0) + ret = wc_ecc_sign_hash_ex(hash, sizeof(hash), rng, &key, &r, &s); + } while (ret == WC_PENDING_E); + if (ret != 0) { + goto done; + } + TEST_SLEEP(); + + mp_read_radix(&expR, expRstr, MP_RADIX_HEX); + mp_read_radix(&expS, expSstr, MP_RADIX_HEX); + if (mp_cmp(&r, &expR) != MP_EQ) { + ret = -1; + } + +done: + wc_ecc_free(&key); + return ret; +} +#endif /* HAVE_ECC521 */ #endif /* WOLFSSL_PUBLIC_MP */ #endif @@ -23891,6 +23970,13 @@ WOLFSSL_TEST_SUBROUTINE int ecc_test(void) printf("ecc384_test_deterministic_k failed! %d\n", ret); goto done; } + #if defined(HAVE_ECC521) + ret = ecc512_test_deterministic_k(&rng); + if (ret != 0) { + printf("ecc512_test_deterministic_k failed! %d\n", ret); + goto done; + } + #endif #endif #endif From a4a4bdc20f6a06a260f126a0b5a1fc49ea33dac2 Mon Sep 17 00:00:00 2001 From: Jacob Barthelmeh Date: Fri, 4 Mar 2022 10:49:11 -0700 Subject: [PATCH 5/5] fix typo, add macro guard, remove dead code path --- wolfcrypt/src/ecc.c | 6 +----- wolfcrypt/test/test.c | 8 ++++++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/wolfcrypt/src/ecc.c b/wolfcrypt/src/ecc.c index aac9fe657..ebc3ca45f 100644 --- a/wolfcrypt/src/ecc.c +++ b/wolfcrypt/src/ecc.c @@ -6454,11 +6454,7 @@ int wc_ecc_gen_deterministic_k(const byte* hash, word32 hashSz, if (ret == 0) { int sz; - sz = (qLen - xSz < VSz) ? qLen-xSz : VSz; - if (xSz + sz > qLen) { - ret = BUFFER_E; - break; - } + sz = MIN(qLen - xSz, VSz); XMEMCPY(x + xSz, V, sz); xSz += sz; } diff --git a/wolfcrypt/test/test.c b/wolfcrypt/test/test.c index 1e953fd5d..33869df64 100644 --- a/wolfcrypt/test/test.c +++ b/wolfcrypt/test/test.c @@ -20875,6 +20875,7 @@ done: } #ifdef WOLFSSL_PUBLIC_MP +#if defined(HAVE_ECC384) /* KAT from RFC6979 */ static int ecc384_test_deterministic_k(WC_RNG* rng) { @@ -20945,10 +20946,11 @@ done: wc_ecc_free(&key); return ret; } +#endif /* HAVE_ECC384 */ #if defined(HAVE_ECC521) /* KAT from RFC6979 */ -static int ecc512_test_deterministic_k(WC_RNG* rng) +static int ecc521_test_deterministic_k(WC_RNG* rng) { int ret; ecc_key key; @@ -23965,13 +23967,15 @@ WOLFSSL_TEST_SUBROUTINE int ecc_test(void) goto done; } #ifdef WOLFSSL_PUBLIC_MP + #if defined(HAVE_ECC384) ret = ecc384_test_deterministic_k(&rng); if (ret != 0) { printf("ecc384_test_deterministic_k failed! %d\n", ret); goto done; } + #endif #if defined(HAVE_ECC521) - ret = ecc512_test_deterministic_k(&rng); + ret = ecc521_test_deterministic_k(&rng); if (ret != 0) { printf("ecc512_test_deterministic_k failed! %d\n", ret); goto done;