From 1fffe4a4636c43f0ac148630b3da221be980f584 Mon Sep 17 00:00:00 2001 From: David Garske Date: Wed, 10 Apr 2019 21:05:46 -0700 Subject: [PATCH 1/6] Improvements to the maximum ECC signature claculations. The `wc_ecc_sig_size` function provides actual max based on curve order. The `wc_ecc_sig_size_calc` has also been adjusted to provide a more accurate maximum size. --- wolfcrypt/src/ecc.c | 76 ++++++++++++++++++++++++++++++----------- wolfssl/wolfcrypt/ecc.h | 4 +-- 2 files changed, 59 insertions(+), 21 deletions(-) diff --git a/wolfcrypt/src/ecc.c b/wolfcrypt/src/ecc.c index def11e8a3..5fd514e40 100644 --- a/wolfcrypt/src/ecc.c +++ b/wolfcrypt/src/ecc.c @@ -4229,6 +4229,26 @@ int wc_ecc_set_flags(ecc_key* key, word32 flags) return 0; } + +static int wc_ecc_get_curve_order_bit_count(const ecc_set_type* dp) +{ + int err; + word32 orderBits; + DECLARE_CURVE_SPECS(curve, 1); + + /* if the input is larger than curve order, we must truncate */ + ALLOC_CURVE_SPECS(1); + err = wc_ecc_curve_load(dp, &curve, ECC_CURVE_FIELD_ORDER); + if (err != 0) { + FREE_CURVE_SPECS(); + return err; + } + orderBits = mp_count_bits(curve->order); + + FREE_CURVE_SPECS(); + return (int)orderBits; +} + #ifdef HAVE_ECC_SIGN #ifndef NO_ASN @@ -4245,26 +4265,16 @@ static int wc_ecc_sign_hash_hw(const byte* in, word32 inlen, #endif { word32 keysize = (word32)key->dp->size; - word32 orderBits; - DECLARE_CURVE_SPECS(curve, 1); + word32 orderBits = wc_ecc_get_curve_order_bit_count(key->dp); /* Check args */ if (keysize > ECC_MAX_CRYPTO_HW_SIZE || *outlen < keysize*2) { return ECC_BAD_ARG_E; } - /* if the input is larger than curve order, we must truncate */ - ALLOC_CURVE_SPECS(1); - err = wc_ecc_curve_load(key->dp, &curve, ECC_CURVE_FIELD_ORDER); - if (err != 0) { - FREE_CURVE_SPECS(); - return err; - } - orderBits = mp_count_bits(curve->order); if ((inlen * WOLFSSL_BIT_SIZE) > orderBits) { inlen = (orderBits + WOLFSSL_BIT_SIZE - 1) / WOLFSSL_BIT_SIZE; } - FREE_CURVE_SPECS(); #if defined(WOLFSSL_ATECC508A) key->slot = atmel_ecc_alloc(ATMEL_SLOT_DEVICE); @@ -7066,25 +7076,53 @@ int wc_ecc_import_raw(ecc_key* key, const char* qx, const char* qy, /* key size in octets */ int wc_ecc_size(ecc_key* key) { - if (key == NULL) return 0; + if (key == NULL) + return 0; return key->dp->size; } +/* maximum signature size based on key size */ int wc_ecc_sig_size_calc(int sz) { - return (sz * 2) + SIG_HEADER_SZ + ECC_MAX_PAD_SZ; + int maxSigSz = 0; + + /* calculate based on key bits */ + maxSigSz = (sz * 2) + (SIG_HEADER_SZ - 1) + ECC_MAX_PAD_SZ; + + /* if total length exceeds 127 then add 1 */ + if (maxSigSz >= 127) + maxSigSz += 1; + + return maxSigSz; } -/* worst case estimate, check actual return from wc_ecc_sign_hash for actual - value of signature size in octets */ +/* maximum signature size based on actual key curve */ int wc_ecc_sig_size(ecc_key* key) { - int sz = wc_ecc_size(key); - if (sz <= 0) - return sz; + int maxSigSz; + int orderBits, keySz; - return wc_ecc_sig_size_calc(sz); + if (key == NULL || key->dp == NULL) + return 0; + + /* the signature r and s will always be less than order */ + /* if the order MSB (top bit of byte) is set then ASN encoding needs + extra byte for r and s, so add 2 */ + keySz = key->dp->size; + orderBits = wc_ecc_get_curve_order_bit_count(key->dp); + /* signature header is minimum of 6 */ + maxSigSz = (keySz * 2) + (SIG_HEADER_SZ - 1); + if ((orderBits % 8) == 0) { + /* MSB can be set, so add 2 */ + maxSigSz += ECC_MAX_PAD_SZ; + } + /* if total length exceeds 127 then add 1 */ + if (maxSigSz >= 127) { + maxSigSz += 1; + } + + return maxSigSz; } diff --git a/wolfssl/wolfcrypt/ecc.h b/wolfssl/wolfcrypt/ecc.h index 49b6b1acb..cc18cef38 100644 --- a/wolfssl/wolfcrypt/ecc.h +++ b/wolfssl/wolfcrypt/ecc.h @@ -111,12 +111,12 @@ enum { ECC_PRIVATEKEY = 2, ECC_PRIVATEKEY_ONLY = 3, ECC_MAXNAME = 16, /* MAX CURVE NAME LENGTH */ - SIG_HEADER_SZ = 6, /* ECC signature header size */ + SIG_HEADER_SZ = 7, /* ECC signature header size (30 81 87 02 42 [R] 02 42 [S]) */ ECC_BUFSIZE = 256, /* for exported keys temp buffer */ ECC_MINSIZE = 20, /* MIN Private Key size */ ECC_MAXSIZE = 66, /* MAX Private Key size */ ECC_MAXSIZE_GEN = 74, /* MAX Buffer size required when generating ECC keys*/ - ECC_MAX_PAD_SZ = 4, /* ECC maximum padding size */ + ECC_MAX_PAD_SZ = 2, /* ECC maximum padding size (when MSB is set extra byte required for R and S) */ ECC_MAX_OID_LEN = 16, ECC_MAX_SIG_SIZE= ((MAX_ECC_BYTES * 2) + ECC_MAX_PAD_SZ + SIG_HEADER_SZ), From ae9ef3998c0b740c9c01cc0c9326c37b1b25d5da Mon Sep 17 00:00:00 2001 From: David Garske Date: Wed, 10 Apr 2019 21:06:17 -0700 Subject: [PATCH 2/6] Enable the TFM speedups when used with `--enable-ecccustcurves=all` and fastmath and x86. --- configure.ac | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 02f6bfa74..c60a4a891 100644 --- a/configure.ac +++ b/configure.ac @@ -1500,6 +1500,7 @@ fi AM_CONDITIONAL([BUILD_ECC], [test "x$ENABLED_ECC" = "xyes"]) + # ECC Custom Curves AC_ARG_ENABLE([ecccustcurves], [AS_HELP_STRING([--enable-ecccustcurves],[Enable ECC custom curves (default: disabled)])], @@ -1511,7 +1512,7 @@ if test "$ENABLED_ECCCUSTCURVES" != "no" then AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_CUSTOM_CURVES" - # For distro or all builds, enable all curve types + # For distro, all or ecccustcurves=all builds, enable all curve types if test "$ENABLED_DISTRO" = "yes" || test "$ENABLED_ALL" = "yes" || test "$ENABLED_ECCCUSTCURVES" = "all" then # Enable ECC SECPR2, SECPR3, BRAINPOOL and KOBLITZ curves @@ -1519,6 +1520,12 @@ then # Enable ECC Cofactor support AM_CFLAGS="$AM_CFLAGS -DHAVE_ECC_CDH" + + # If fastmath enabled and on x86 use speedups + if test "x$ENABLED_FASTMATH" = "xyes" && test "$host_cpu" = "x86_64" + then + AM_CFLAGS="$AM_CFLAGS -DTFM_ECC192 -DTFM_ECC224 -DTFM_ECC256 -DTFM_ECC384 -DTFM_ECC521" + fi fi fi From bd618970c1c67e87676465d765dc6f4c5a9cce0c Mon Sep 17 00:00:00 2001 From: David Garske Date: Wed, 10 Apr 2019 21:18:17 -0700 Subject: [PATCH 3/6] Fixed API unit test for `wc_ecc_sig_size` to allow smaller result. --- tests/api.c | 2 +- wolfcrypt/src/ecc.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/api.c b/tests/api.c index 87efb38b1..ed5b2d6fa 100644 --- a/tests/api.c +++ b/tests/api.c @@ -14737,7 +14737,7 @@ static int test_wc_ecc_sig_size (void) if (ret == 0) { ret = wc_ecc_sig_size(&key); - if (ret == (2 * keySz + SIG_HEADER_SZ + ECC_MAX_PAD_SZ)) { + if (ret <= (2 * keySz + SIG_HEADER_SZ + ECC_MAX_PAD_SZ)) { ret = 0; } } diff --git a/wolfcrypt/src/ecc.c b/wolfcrypt/src/ecc.c index 5fd514e40..05c0a9069 100644 --- a/wolfcrypt/src/ecc.c +++ b/wolfcrypt/src/ecc.c @@ -4236,7 +4236,6 @@ static int wc_ecc_get_curve_order_bit_count(const ecc_set_type* dp) word32 orderBits; DECLARE_CURVE_SPECS(curve, 1); - /* if the input is larger than curve order, we must truncate */ ALLOC_CURVE_SPECS(1); err = wc_ecc_curve_load(dp, &curve, ECC_CURVE_FIELD_ORDER); if (err != 0) { @@ -4272,6 +4271,7 @@ static int wc_ecc_sign_hash_hw(const byte* in, word32 inlen, return ECC_BAD_ARG_E; } + /* if the input is larger than curve order, we must truncate */ if ((inlen * WOLFSSL_BIT_SIZE) > orderBits) { inlen = (orderBits + WOLFSSL_BIT_SIZE - 1) / WOLFSSL_BIT_SIZE; } From 4ee4cb2068dceb23e494c07a0b976b798b462a47 Mon Sep 17 00:00:00 2001 From: David Garske Date: Mon, 15 Apr 2019 11:08:08 -0700 Subject: [PATCH 4/6] Improved readability for ECC signature max size calculations. --- wolfcrypt/src/ecc.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/wolfcrypt/src/ecc.c b/wolfcrypt/src/ecc.c index 05c0a9069..a3a140c1b 100644 --- a/wolfcrypt/src/ecc.c +++ b/wolfcrypt/src/ecc.c @@ -7088,11 +7088,13 @@ int wc_ecc_sig_size_calc(int sz) int maxSigSz = 0; /* calculate based on key bits */ - maxSigSz = (sz * 2) + (SIG_HEADER_SZ - 1) + ECC_MAX_PAD_SZ; + /* maximum possible signature header size is 7 bytes plus 2 bytes padding */ + maxSigSz = (sz * 2) + SIG_HEADER_SZ + ECC_MAX_PAD_SZ; - /* if total length exceeds 127 then add 1 */ - if (maxSigSz >= 127) - maxSigSz += 1; + /* if total length is less than or equal to 128 then subtract 1 */ + if (maxSigSz <= 128) { + maxSigSz -= 1; + } return maxSigSz; } @@ -7111,15 +7113,15 @@ int wc_ecc_sig_size(ecc_key* key) extra byte for r and s, so add 2 */ keySz = key->dp->size; orderBits = wc_ecc_get_curve_order_bit_count(key->dp); - /* signature header is minimum of 6 */ - maxSigSz = (keySz * 2) + (SIG_HEADER_SZ - 1); + /* maximum possible signature header size is 7 bytes */ + maxSigSz = (keySz * 2) + SIG_HEADER_SZ; if ((orderBits % 8) == 0) { /* MSB can be set, so add 2 */ maxSigSz += ECC_MAX_PAD_SZ; } - /* if total length exceeds 127 then add 1 */ - if (maxSigSz >= 127) { - maxSigSz += 1; + /* if total length is less than or equal to 128 then subtract 1 */ + if (maxSigSz <= 128) { + maxSigSz -= 1; } return maxSigSz; From 5bfc49f63f1ff0b5722dada2cafd1e83994c015b Mon Sep 17 00:00:00 2001 From: David Garske Date: Mon, 15 Apr 2019 14:56:04 -0700 Subject: [PATCH 5/6] Changed `ECC_MAX_PAD_SZ` to be overridable macro for rare case where user might require additional padding. --- wolfssl/wolfcrypt/ecc.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/wolfssl/wolfcrypt/ecc.h b/wolfssl/wolfcrypt/ecc.h index cc18cef38..1a731af97 100644 --- a/wolfssl/wolfcrypt/ecc.h +++ b/wolfssl/wolfcrypt/ecc.h @@ -105,6 +105,10 @@ #define MAX_ECC_BYTES ((MAX_ECC_BITS / 8) + 1) #endif +#ifndef ECC_MAX_PAD_SZ + /* ECC maximum padding size (when MSB is set extra byte required for R and S) */ + #define ECC_MAX_PAD_SZ 2 +#endif enum { ECC_PUBLICKEY = 1, @@ -116,7 +120,6 @@ enum { ECC_MINSIZE = 20, /* MIN Private Key size */ ECC_MAXSIZE = 66, /* MAX Private Key size */ ECC_MAXSIZE_GEN = 74, /* MAX Buffer size required when generating ECC keys*/ - ECC_MAX_PAD_SZ = 2, /* ECC maximum padding size (when MSB is set extra byte required for R and S) */ ECC_MAX_OID_LEN = 16, ECC_MAX_SIG_SIZE= ((MAX_ECC_BYTES * 2) + ECC_MAX_PAD_SZ + SIG_HEADER_SZ), From 443fef6a6a6eea8d262eca7f57850d0c0f810ccb Mon Sep 17 00:00:00 2001 From: David Garske Date: Tue, 30 Apr 2019 08:50:19 -0700 Subject: [PATCH 6/6] Further optimization of the ECC signature size calculation. --- wolfcrypt/src/ecc.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/wolfcrypt/src/ecc.c b/wolfcrypt/src/ecc.c index a3a140c1b..ce486687f 100644 --- a/wolfcrypt/src/ecc.c +++ b/wolfcrypt/src/ecc.c @@ -7091,8 +7091,8 @@ int wc_ecc_sig_size_calc(int sz) /* maximum possible signature header size is 7 bytes plus 2 bytes padding */ maxSigSz = (sz * 2) + SIG_HEADER_SZ + ECC_MAX_PAD_SZ; - /* if total length is less than or equal to 128 then subtract 1 */ - if (maxSigSz <= 128) { + /* if total length is less than 128 + SEQ(1)+LEN(1) then subtract 1 */ + if (maxSigSz < (128 + 2)) { maxSigSz -= 1; } @@ -7119,8 +7119,8 @@ int wc_ecc_sig_size(ecc_key* key) /* MSB can be set, so add 2 */ maxSigSz += ECC_MAX_PAD_SZ; } - /* if total length is less than or equal to 128 then subtract 1 */ - if (maxSigSz <= 128) { + /* if total length is less than 128 + SEQ(1)+LEN(1) then subtract 1 */ + if (maxSigSz < (128 + 2)) { maxSigSz -= 1; }