From 14dc5fe2e3a06eebdc0c2146d22d3886cc29ca42 Mon Sep 17 00:00:00 2001 From: Martin Akman Date: Fri, 31 Jan 2020 23:05:56 +1000 Subject: [PATCH 01/60] Fixes for 16bit processors --- wolfcrypt/src/asn.c | 25 +++++++++++++++++-------- wolfcrypt/src/integer.c | 12 ++++++------ wolfssl/ssl.h | 6 +++--- wolfssl/wolfcrypt/types.h | 4 ++-- 4 files changed, 28 insertions(+), 19 deletions(-) diff --git a/wolfcrypt/src/asn.c b/wolfcrypt/src/asn.c index e9971d9581..e96e693a3f 100644 --- a/wolfcrypt/src/asn.c +++ b/wolfcrypt/src/asn.c @@ -6122,6 +6122,14 @@ static WC_INLINE int GetTime(int* value, const byte* date, int* idx) int ExtractDate(const unsigned char* date, unsigned char format, struct tm* certTime, int* idx) { + /* Extract the time from the struct tm - 16bit processors store as uint8_t */ + int tm_year = certTime->tm_year; + int tm_mon = certTime->tm_mon; + int tm_mday = certTime->tm_mday; + int tm_hour = certTime->tm_hour; + int tm_min = certTime->tm_min; + int tm_sec = certTime->tm_sec; + XMEMSET(certTime, 0, sizeof(struct tm)); if (format == ASN_UTC_TIME) { @@ -6136,14 +6144,15 @@ int ExtractDate(const unsigned char* date, unsigned char format, } /* adjust tm_year, tm_mon */ - if (GetTime(&certTime->tm_year, date, idx) != 0) return 0; - certTime->tm_year -= 1900; - if (GetTime(&certTime->tm_mon , date, idx) != 0) return 0; - certTime->tm_mon -= 1; - if (GetTime(&certTime->tm_mday, date, idx) != 0) return 0; - if (GetTime(&certTime->tm_hour, date, idx) != 0) return 0; - if (GetTime(&certTime->tm_min , date, idx) != 0) return 0; - if (GetTime(&certTime->tm_sec , date, idx) != 0) return 0; + tm_year -= 1900; + tm_mon -= 1; + + if (GetTime(&tm_year, date, idx) != 0) return 0; + if (GetTime(&tm_mon , date, idx) != 0) return 0; + if (GetTime(&tm_mday, date, idx) != 0) return 0; + if (GetTime(&tm_hour, date, idx) != 0) return 0; + if (GetTime(&tm_min , date, idx) != 0) return 0; + if (GetTime(&tm_sec , date, idx) != 0) return 0; return 1; } diff --git a/wolfcrypt/src/integer.c b/wolfcrypt/src/integer.c index 9e45ebdc2d..1a19168c4e 100644 --- a/wolfcrypt/src/integer.c +++ b/wolfcrypt/src/integer.c @@ -1994,7 +1994,7 @@ int mp_exptmod_fast (mp_int * G, mp_int * X, mp_int * P, mp_int * Y, calls/ifs) */ #ifdef BN_FAST_MP_MONTGOMERY_REDUCE_C if (((P->used * 2 + 1) < (int)MP_WARRAY) && - P->used < (1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) { + P->used < (1L << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) { redux = fast_mp_montgomery_reduce; } else #endif @@ -2244,7 +2244,7 @@ int mp_exptmod_base_2(mp_int * X, mp_int * P, mp_int * Y) calls/ifs) */ #ifdef BN_FAST_MP_MONTGOMERY_REDUCE_C if (((P->used * 2 + 1) < (int)MP_WARRAY) && - P->used < (1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) { + P->used < (1L << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) { redux = fast_mp_montgomery_reduce; } else #endif @@ -2604,7 +2604,7 @@ int mp_montgomery_reduce (mp_int * x, mp_int * n, mp_digit rho) digs = n->used * 2 + 1; if ((digs < (int)MP_WARRAY) && n->used < - (1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) { + (1L << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) { return fast_mp_montgomery_reduce (x, n, rho); } @@ -3043,7 +3043,7 @@ int mp_mul (mp_int * a, mp_int * b, mp_int * c) #ifdef BN_FAST_S_MP_MUL_DIGS_C if ((digs < (int)MP_WARRAY) && MIN(a->used, b->used) <= - (1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) { + (1L << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) { res = fast_s_mp_mul_digs (a, b, c, digs); } else #endif @@ -3506,7 +3506,7 @@ int s_mp_mul_digs (mp_int * a, mp_int * b, mp_int * c, int digs) /* can we use the fast multiplier? */ if ((digs < (int)MP_WARRAY) && MIN (a->used, b->used) < - (1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) { + (1L << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) { return fast_s_mp_mul_digs (a, b, c, digs); } @@ -4014,7 +4014,7 @@ int s_mp_mul_high_digs (mp_int * a, mp_int * b, mp_int * c, int digs) #ifdef BN_FAST_S_MP_MUL_HIGH_DIGS_C if (((a->used + b->used + 1) < (int)MP_WARRAY) && MIN (a->used, b->used) < - (1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) { + (1L << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) { return fast_s_mp_mul_high_digs (a, b, c, digs); } #endif diff --git a/wolfssl/ssl.h b/wolfssl/ssl.h index ca1f6aa01d..b8a44e4ea0 100644 --- a/wolfssl/ssl.h +++ b/wolfssl/ssl.h @@ -2469,7 +2469,7 @@ struct DhKey; typedef int (*CallbackDhAgree)(WOLFSSL* ssl, struct DhKey* key, const unsigned char* priv, unsigned int privSz, const unsigned char* otherPubKeyDer, unsigned int otherPubKeySz, - unsigned char* out, unsigned int* outlen, + unsigned char* out, word32* outlen, void* ctx); WOLFSSL_API void wolfSSL_CTX_SetDhAgreeCb(WOLFSSL_CTX*, CallbackDhAgree); WOLFSSL_API void wolfSSL_SetDhAgreeCtx(WOLFSSL* ssl, void *ctx); @@ -2523,7 +2523,7 @@ WOLFSSL_API void* wolfSSL_GetX25519SharedSecretCtx(WOLFSSL* ssl); #ifndef NO_RSA typedef int (*CallbackRsaSign)(WOLFSSL* ssl, const unsigned char* in, unsigned int inSz, - unsigned char* out, unsigned int* outSz, + unsigned char* out, word32* outSz, const unsigned char* keyDer, unsigned int keySz, void* ctx); WOLFSSL_API void wolfSSL_CTX_SetRsaSignCb(WOLFSSL_CTX*, CallbackRsaSign); @@ -2568,7 +2568,7 @@ WOLFSSL_API void* wolfSSL_GetRsaPssVerifyCtx(WOLFSSL* ssl); /* RSA Public Encrypt cb */ typedef int (*CallbackRsaEnc)(WOLFSSL* ssl, const unsigned char* in, unsigned int inSz, - unsigned char* out, unsigned int* outSz, + unsigned char* out, word32* outSz, const unsigned char* keyDer, unsigned int keySz, void* ctx); WOLFSSL_API void wolfSSL_CTX_SetRsaEncCb(WOLFSSL_CTX*, CallbackRsaEnc); diff --git a/wolfssl/wolfcrypt/types.h b/wolfssl/wolfcrypt/types.h index 08553b4b14..6d0cff4264 100644 --- a/wolfssl/wolfcrypt/types.h +++ b/wolfssl/wolfcrypt/types.h @@ -323,9 +323,9 @@ #else /* just use plain C stdlib stuff if desired */ #include - #define XMALLOC(s, h, t) malloc((s)) + #define XMALLOC(s, h, t) malloc((size_t)(s)) #define XFREE(p, h, t) {void* xp = (p); if((xp)) free((xp));} - #define XREALLOC(p, n, h, t) realloc((p), (n)) + #define XREALLOC(p, n, h, t) realloc((p), (size_t)(n)) #endif #elif !defined(MICRIUM_MALLOC) && !defined(EBSNET) \ && !defined(WOLFSSL_SAFERTOS) && !defined(FREESCALE_MQX) \ From 809472febc25a52e374c5b196fefdb735a3e89cd Mon Sep 17 00:00:00 2001 From: Martin Akman Date: Thu, 9 Jan 2020 16:01:52 +1000 Subject: [PATCH 02/60] Added VERY_SMALL_SESSION_CACHE --- src/ssl.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/ssl.c b/src/ssl.c index 149594eb07..45c0151ecb 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -4992,6 +4992,9 @@ int AddCA(WOLFSSL_CERT_MANAGER* cm, DerBuffer** pDer, int type, int verify) #elif defined(SMALL_SESSION_CACHE) #define SESSIONS_PER_ROW 2 #define SESSION_ROWS 3 + #elif defined(VERY_SMALL_SESSION_CACHE) + #define SESSIONS_PER_ROW 2 + #define SESSION_ROWS 1 #else #define SESSIONS_PER_ROW 3 #define SESSION_ROWS 11 From 6c1e0ff0493be5ef566de39d837c6eaa13e8f017 Mon Sep 17 00:00:00 2001 From: Martin Akman Date: Sat, 4 Jan 2020 10:23:03 +1000 Subject: [PATCH 03/60] ATECC: Option to disable I2C transport key --- wolfcrypt/src/port/atmel/atmel.c | 4 ++++ wolfssl/wolfcrypt/port/atmel/atmel.h | 5 +++++ 2 files changed, 9 insertions(+) diff --git a/wolfcrypt/src/port/atmel/atmel.c b/wolfcrypt/src/port/atmel/atmel.c index cfe0a93c79..65dd4dfa7e 100644 --- a/wolfcrypt/src/port/atmel/atmel.c +++ b/wolfcrypt/src/port/atmel/atmel.c @@ -347,7 +347,11 @@ int atmel_ecc_create_pms(int slotId, const uint8_t* peerKey, uint8_t* pms) ATECC_GET_ENC_KEY(read_key, sizeof(read_key)); /* send the encrypted version of the ECDH command */ +#if defined(ATECC_USE_TRANSPORT_KEY) && ATECC_USE_TRANSPORT_KEY ret = atcab_ecdh_enc(slotId, peerKey, pms, read_key, slotIdEnc); +#else + ret = atcab_ecdh(slotId, peerKey, pms); +#endif ret = atmel_ecc_translate_err(ret); /* free the ECDHE slot */ diff --git a/wolfssl/wolfcrypt/port/atmel/atmel.h b/wolfssl/wolfcrypt/port/atmel/atmel.h index 70035130cb..3d7b54d2da 100644 --- a/wolfssl/wolfcrypt/port/atmel/atmel.h +++ b/wolfssl/wolfcrypt/port/atmel/atmel.h @@ -60,6 +60,11 @@ #define ATECC_SLOT_ENC_PARENT (0x7) #endif +/* Use a I2C transport key */ +#ifndef ATECC_USE_TRANSPORT_KEY +#define ATECC_USE_TRANSPORT_KEY 1 +#endif + /* ATECC_KEY_SIZE required for ecc.h */ #include From 20c0beb9e548f384aecb628a336b1c5311df0fcb Mon Sep 17 00:00:00 2001 From: Martin Akman Date: Fri, 31 Jan 2020 23:06:15 +1000 Subject: [PATCH 04/60] 'WOLFSSL_USE_FLASHMEM' to store constant tables in flash memory --- wolfcrypt/src/aes.c | 8 ++-- wolfcrypt/src/des3.c | 10 ++--- wolfcrypt/src/integer.c | 2 +- wolfcrypt/src/random.c | 74 +++++++++++++++++++++++++++++++----- wolfcrypt/src/sha256.c | 2 +- wolfssl/wolfcrypt/settings.h | 7 ++++ 6 files changed, 82 insertions(+), 21 deletions(-) diff --git a/wolfcrypt/src/aes.c b/wolfcrypt/src/aes.c index 946fae4fe2..52467f09f2 100644 --- a/wolfcrypt/src/aes.c +++ b/wolfcrypt/src/aes.c @@ -782,14 +782,14 @@ #ifdef NEED_AES_TABLES -static const word32 rcon[] = { +static const FLASH_QUALIFIER word32 rcon[] = { 0x01000000, 0x02000000, 0x04000000, 0x08000000, 0x10000000, 0x20000000, 0x40000000, 0x80000000, 0x1B000000, 0x36000000, /* for 128-bit blocks, Rijndael never uses more than 10 rcon values */ }; -static const word32 Te[4][256] = { +static const FLASH_QUALIFIER word32 Te[4][256] = { { 0xc66363a5U, 0xf87c7c84U, 0xee777799U, 0xf67b7b8dU, 0xfff2f20dU, 0xd66b6bbdU, 0xde6f6fb1U, 0x91c5c554U, @@ -1057,7 +1057,7 @@ static const word32 Te[4][256] = { }; #ifdef HAVE_AES_DECRYPT -static const word32 Td[4][256] = { +static const FLASH_QUALIFIER word32 Td[4][256] = { { 0x51f4a750U, 0x7e416553U, 0x1a17a4c3U, 0x3a275e96U, 0x3bab6bcbU, 0x1f9d45f1U, 0xacfa58abU, 0x4be30393U, @@ -1328,7 +1328,7 @@ static const word32 Td[4][256] = { #if (defined(HAVE_AES_CBC) && !defined(WOLFSSL_DEVCRYPTO_CBC)) \ || defined(WOLFSSL_AES_DIRECT) -static const byte Td4[256] = +static const FLASH_QUALIFIER byte Td4[256] = { 0x52U, 0x09U, 0x6aU, 0xd5U, 0x30U, 0x36U, 0xa5U, 0x38U, 0xbfU, 0x40U, 0xa3U, 0x9eU, 0x81U, 0xf3U, 0xd7U, 0xfbU, diff --git a/wolfcrypt/src/des3.c b/wolfcrypt/src/des3.c index f07498a5d7..1d24e90f71 100644 --- a/wolfcrypt/src/des3.c +++ b/wolfcrypt/src/des3.c @@ -1144,7 +1144,7 @@ #ifdef NEED_SOFT_DES /* permuted choice table (key) */ - static const byte pc1[] = { + static const FLASH_QUALIFIER byte pc1[] = { 57, 49, 41, 33, 25, 17, 9, 1, 58, 50, 42, 34, 26, 18, 10, 2, 59, 51, 43, 35, 27, @@ -1157,12 +1157,12 @@ }; /* number left rotations of pc1 */ - static const byte totrot[] = { + static const FLASH_QUALIFIER byte totrot[] = { 1,2,4,6,8,10,12,14,15,17,19,21,23,25,27,28 }; /* permuted choice key (table) */ - static const byte pc2[] = { + static const FLASH_QUALIFIER byte pc2[] = { 14, 17, 11, 24, 1, 5, 3, 28, 15, 6, 21, 10, 23, 19, 12, 4, 26, 8, @@ -1176,11 +1176,11 @@ /* End of DES-defined tables */ /* bit 0 is left-most in byte */ - static const int bytebit[] = { + static const FLASH_QUALIFIER int bytebit[] = { 0200,0100,040,020,010,04,02,01 }; - static const word32 Spbox[8][64] = { + static const FLASH_QUALIFIER word32 Spbox[8][64] = { { 0x01010400,0x00000000,0x00010000,0x01010404, 0x01010004,0x00010404,0x00000004,0x00010000, 0x00000400,0x01010400,0x01010404,0x00000400, diff --git a/wolfcrypt/src/integer.c b/wolfcrypt/src/integer.c index 1a19168c4e..a1a4fcd344 100644 --- a/wolfcrypt/src/integer.c +++ b/wolfcrypt/src/integer.c @@ -4543,7 +4543,7 @@ int mp_mod_d (mp_int * a, mp_digit b, mp_digit * c) #if defined(WOLFSSL_KEY_GEN) || !defined(NO_DH) || !defined(NO_DSA) || !defined(NO_RSA) -const mp_digit ltm_prime_tab[PRIME_SIZE] = { +const FLASH_QUALIFIER mp_digit ltm_prime_tab[PRIME_SIZE] = { 0x0002, 0x0003, 0x0005, 0x0007, 0x000B, 0x000D, 0x0011, 0x0013, 0x0017, 0x001D, 0x001F, 0x0025, 0x0029, 0x002B, 0x002F, 0x0035, 0x003B, 0x003D, 0x0043, 0x0047, 0x0049, 0x004F, 0x0053, 0x0059, diff --git a/wolfcrypt/src/random.c b/wolfcrypt/src/random.c index a9dcac362c..c20e43a9f1 100644 --- a/wolfcrypt/src/random.c +++ b/wolfcrypt/src/random.c @@ -1102,20 +1102,20 @@ exit_rng_ht: } -const byte seedA[] = { +const FLASH_QUALIFIER byte _seedA[] = { 0x63, 0x36, 0x33, 0x77, 0xe4, 0x1e, 0x86, 0x46, 0x8d, 0xeb, 0x0a, 0xb4, 0xa8, 0xed, 0x68, 0x3f, 0x6a, 0x13, 0x4e, 0x47, 0xe0, 0x14, 0xc7, 0x00, 0x45, 0x4e, 0x81, 0xe9, 0x53, 0x58, 0xa5, 0x69, 0x80, 0x8a, 0xa3, 0x8f, 0x2a, 0x72, 0xa6, 0x23, 0x59, 0x91, 0x5a, 0x9f, 0x8a, 0x04, 0xca, 0x68 }; -const byte reseedSeedA[] = { +const FLASH_QUALIFIER byte _reseedSeedA[] = { 0xe6, 0x2b, 0x8a, 0x8e, 0xe8, 0xf1, 0x41, 0xb6, 0x98, 0x05, 0x66, 0xe3, 0xbf, 0xe3, 0xc0, 0x49, 0x03, 0xda, 0xd4, 0xac, 0x2c, 0xdf, 0x9f, 0x22, 0x80, 0x01, 0x0a, 0x67, 0x39, 0xbc, 0x83, 0xd3 }; -const byte outputA[] = { +const FLASH_QUALIFIER byte _outputA[] = { 0x04, 0xee, 0xc6, 0x3b, 0xb2, 0x31, 0xdf, 0x2c, 0x63, 0x0a, 0x1a, 0xfb, 0xe7, 0x24, 0x94, 0x9d, 0x00, 0x5a, 0x58, 0x78, 0x51, 0xe1, 0xaa, 0x79, 0x5e, 0x47, 0x73, 0x47, 0xc8, 0xb0, 0x56, 0x62, 0x1c, 0x18, 0xbd, 0xdc, @@ -1129,7 +1129,7 @@ const byte outputA[] = { 0xa1, 0x80, 0x18, 0x3a, 0x07, 0xdf, 0xae, 0x17 }; -const byte seedB[] = { +const FLASH_QUALIFIER byte _seedB[] = { 0xa6, 0x5a, 0xd0, 0xf3, 0x45, 0xdb, 0x4e, 0x0e, 0xff, 0xe8, 0x75, 0xc3, 0xa2, 0xe7, 0x1f, 0x42, 0xc7, 0x12, 0x9d, 0x62, 0x0f, 0xf5, 0xc1, 0x19, 0xa9, 0xef, 0x55, 0xf0, 0x51, 0x85, 0xe0, 0xfb, /* nonce next */ @@ -1137,7 +1137,7 @@ const byte seedB[] = { 0xdb, 0xcb, 0xcc, 0x2e }; -const byte outputB[] = { +const FLASH_QUALIFIER byte _outputB[] = { 0xd3, 0xe1, 0x60, 0xc3, 0x5b, 0x99, 0xf3, 0x40, 0xb2, 0x62, 0x82, 0x64, 0xd1, 0x75, 0x10, 0x60, 0xe0, 0x04, 0x5d, 0xa3, 0x83, 0xff, 0x57, 0xa5, 0x7d, 0x73, 0xa6, 0x73, 0xd2, 0xb8, 0xd8, 0x0d, 0xaa, 0xf6, 0xa6, 0xc3, @@ -1170,17 +1170,65 @@ static int wc_RNG_HealthTestLocal(int reseed) #endif if (reseed) { - ret = wc_RNG_HealthTest(1, seedA, sizeof(seedA), - reseedSeedA, sizeof(reseedSeedA), +#ifdef WOLFSSL_USE_FLASHMEM + byte* seedA = (byte*)XMALLOC(sizeof(_seedA), NULL, + DYNAMIC_TYPE_TMP_BUFFER); + byte* reseedSeedA = (byte*)XMALLOC(sizeof(_reseedSeedA), NULL, + DYNAMIC_TYPE_TMP_BUFFER); + byte* outputA = (byte*)XMALLOC(sizeof(_outputA), NULL, + DYNAMIC_TYPE_TMP_BUFFER); + + if (!seedA || !reseedSeedA || !outputA) { + XFREE(seedA, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(reseedSeedA, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(outputA, NULL, DYNAMIC_TYPE_TMP_BUFFER); + ret = MEMORY_E; + } + else { + XMEMCPY_P(seedA, _seedA, sizeof(_seedA)); + XMEMCPY_P(reseedSeedA, _reseedSeedA, sizeof(_reseedSeedA)); + XMEMCPY_P(outputA, _outputA, sizeof(_outputA)); +#else + const byte* seedA = _seedA; + const byte* reseedSeedA = _reseedSeedA; + const byte* outputA = _outputA; +#endif + ret = wc_RNG_HealthTest(1, seedA, sizeof(_seedA), + reseedSeedA, sizeof(_reseedSeedA), check, RNG_HEALTH_TEST_CHECK_SIZE); if (ret == 0) { if (ConstantCompare(check, outputA, RNG_HEALTH_TEST_CHECK_SIZE) != 0) ret = -1; } + +#ifdef WOLFSSL_USE_FLASHMEM + XFREE(seedA, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(reseedSeedA, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(outputA, NULL, DYNAMIC_TYPE_TMP_BUFFER); + } +#endif } else { - ret = wc_RNG_HealthTest(0, seedB, sizeof(seedB), +#ifdef WOLFSSL_USE_FLASHMEM + byte* seedB = (byte*)XMALLOC(sizeof(_seedB), NULL, + DYNAMIC_TYPE_TMP_BUFFER); + byte* outputB = (byte*)XMALLOC(sizeof(_outputB), NULL, + DYNAMIC_TYPE_TMP_BUFFER); + + if (!seedB || !outputB) { + XFREE(seedB, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(outputB, NULL, DYNAMIC_TYPE_TMP_BUFFER); + ret = MEMORY_E; + } + else { + XMEMCPY_P(seedB, _seedB, sizeof(_seedB)); + XMEMCPY_P(outputB, _outputB, sizeof(_outputB)); +#else + const byte* seedB = _seedB; + const byte* outputB = _outputB; +#endif + ret = wc_RNG_HealthTest(0, seedB, sizeof(_seedB), NULL, 0, check, RNG_HEALTH_TEST_CHECK_SIZE); if (ret == 0) { @@ -1195,16 +1243,22 @@ static int wc_RNG_HealthTestLocal(int reseed) * byte 32, feed them into the health test separately. */ if (ret == 0) { ret = wc_RNG_HealthTest_ex(0, - seedB + 32, sizeof(seedB) - 32, + seedB + 32, sizeof(_seedB) - 32, seedB, 32, NULL, 0, check, RNG_HEALTH_TEST_CHECK_SIZE, NULL, INVALID_DEVID); if (ret == 0) { - if (ConstantCompare(check, outputB, sizeof(outputB)) != 0) + if (ConstantCompare(check, outputB, sizeof(_outputB)) != 0) ret = -1; } } + +#ifdef WOLFSSL_USE_FLASHMEM + XFREE(seedB, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(outputB, NULL, DYNAMIC_TYPE_TMP_BUFFER); + } +#endif } #ifdef WOLFSSL_SMALL_STACK diff --git a/wolfcrypt/src/sha256.c b/wolfcrypt/src/sha256.c index de49e32830..f75136b076 100644 --- a/wolfcrypt/src/sha256.c +++ b/wolfcrypt/src/sha256.c @@ -642,7 +642,7 @@ static int InitSha256(wc_Sha256* sha256) #ifdef NEED_SOFT_SHA256 - static const ALIGN32 word32 K[64] = { + static const FLASH_QUALIFIER ALIGN32 word32 K[64] = { 0x428A2F98L, 0x71374491L, 0xB5C0FBCFL, 0xE9B5DBA5L, 0x3956C25BL, 0x59F111F1L, 0x923F82A4L, 0xAB1C5ED5L, 0xD807AA98L, 0x12835B01L, 0x243185BEL, 0x550C7DC3L, 0x72BE5D74L, 0x80DEB1FEL, 0x9BDC06A7L, diff --git a/wolfssl/wolfcrypt/settings.h b/wolfssl/wolfcrypt/settings.h index 572b108b67..67cd9009ad 100644 --- a/wolfssl/wolfcrypt/settings.h +++ b/wolfssl/wolfcrypt/settings.h @@ -882,6 +882,13 @@ extern void uITRON4_free(void *p) ; #define TFM_TIMING_RESISTANT #endif +#ifdef WOLFSSL_USE_FLASHMEM + #define FLASH_QUALIFIER __flash + #define XMEMCPY_P(pdest, psrc, size) memcpy_P((pdest), (psrc), (size)) +#else + #define FLASH_QUALIFIER +#endif + #ifdef FREESCALE_MQX_5_0 /* use normal Freescale MQX port, but with minor changes for 5.0 */ #define FREESCALE_MQX From 3bbd8be5c96a2048d71efaea5a48896427fd6589 Mon Sep 17 00:00:00 2001 From: Martin Akman Date: Tue, 25 Feb 2020 22:03:55 +1000 Subject: [PATCH 05/60] ATECC: Don't init transport key if not used --- wolfcrypt/src/port/atmel/atmel.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/wolfcrypt/src/port/atmel/atmel.c b/wolfcrypt/src/port/atmel/atmel.c index 65dd4dfa7e..419b656114 100644 --- a/wolfcrypt/src/port/atmel/atmel.c +++ b/wolfcrypt/src/port/atmel/atmel.c @@ -291,6 +291,7 @@ int atmel_get_enc_key_default(byte* enckey, word16 keysize) /** * \brief Write enc key before. */ +#if defined(ATECC_USE_TRANSPORT_KEY) && ATECC_USE_TRANSPORT_KEY static int atmel_init_enc_key(void) { int ret; @@ -315,6 +316,7 @@ static int atmel_init_enc_key(void) return ret; } +#endif int atmel_get_rev_info(word32* revision) { @@ -447,6 +449,7 @@ int atmel_init(void) device_init_default(); #endif +#if defined(ATECC_USE_TRANSPORT_KEY) && ATECC_USE_TRANSPORT_KEY /* Init the I2C pipe encryption key. */ /* Value is generated/stored during pair for the ATECC508A and stored on micro flash */ @@ -455,6 +458,7 @@ int atmel_init(void) WOLFSSL_MSG("Failed to initialize transport key"); return WC_HW_E; } +#endif mAtcaInitDone = 1; } From 568ce62b81a2d7c8370d265e834514735a427120 Mon Sep 17 00:00:00 2001 From: Martin Akman Date: Tue, 31 Mar 2020 18:25:59 +1000 Subject: [PATCH 06/60] Updates from code review --- wolfcrypt/src/asn.c | 8 ++++++++ wolfssl/wolfcrypt/settings.h | 6 ++++++ 2 files changed, 14 insertions(+) diff --git a/wolfcrypt/src/asn.c b/wolfcrypt/src/asn.c index e96e693a3f..bba9aed5be 100644 --- a/wolfcrypt/src/asn.c +++ b/wolfcrypt/src/asn.c @@ -6154,6 +6154,14 @@ int ExtractDate(const unsigned char* date, unsigned char format, if (GetTime(&tm_min , date, idx) != 0) return 0; if (GetTime(&tm_sec , date, idx) != 0) return 0; + /* Re-populate certTime with computed values */ + certTime->tm_year = tm_year; + certTime->tm_mon = tm_mon; + certTime->tm_mday = tm_mday; + certTime->tm_hour = tm_hour; + certTime->tm_min = tm_min; + certTime->tm_sec = tm_sec; + return 1; } diff --git a/wolfssl/wolfcrypt/settings.h b/wolfssl/wolfcrypt/settings.h index 67cd9009ad..27088cd00f 100644 --- a/wolfssl/wolfcrypt/settings.h +++ b/wolfssl/wolfcrypt/settings.h @@ -882,8 +882,14 @@ extern void uITRON4_free(void *p) ; #define TFM_TIMING_RESISTANT #endif +/* To support storing some of the large constant tables in flash memory rather than SRAM. + Useful for processors that have limited SRAM, such as the AVR family of microtrollers. */ #ifdef WOLFSSL_USE_FLASHMEM + /* This is supported on the avr-gcc compiler, for more information see: + https://gcc.gnu.org/onlinedocs/gcc/Named-Address-Spaces.html */ #define FLASH_QUALIFIER __flash + + /* Copy data out of flash memory and into SRAM */ #define XMEMCPY_P(pdest, psrc, size) memcpy_P((pdest), (psrc), (size)) #else #define FLASH_QUALIFIER From 85437e4097591605b975388c12ebab7ed6141108 Mon Sep 17 00:00:00 2001 From: Jacob Barthelmeh Date: Mon, 13 Jul 2020 17:17:57 -0600 Subject: [PATCH 07/60] add sanity check on padSz --- src/internal.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/internal.c b/src/internal.c index dbcc565a8c..354a8e2280 100644 --- a/src/internal.c +++ b/src/internal.c @@ -15335,6 +15335,13 @@ int ProcessReply(WOLFSSL* ssl) if (ssl->options.tls1_3) { word16 i = (word16)(ssl->buffers.inputBuffer.length - ssl->keys.padSz); + + /* sanity check on underflow */ + if (ssl->keys.padSz >= ssl->buffers.inputBuffer.length) { + WOLFSSL_ERROR(DECRYPT_ERROR); + return DECRYPT_ERROR; + } + /* Remove padding from end of plain text. */ for (--i; i > ssl->buffers.inputBuffer.idx; i--) { if (ssl->buffers.inputBuffer.buffer[i] != 0) From 20682ef0aa2f248ff2b9a20b35ea5c647282987e Mon Sep 17 00:00:00 2001 From: TakayukiMatsuo Date: Tue, 14 Jul 2020 11:33:19 +0900 Subject: [PATCH 08/60] Add support for RX72N Envision Kit --- IDE/Renesas/e2studio/RX72NEnvisionKit/README | 155 ++++ .../RX72NEnvisionKit/common/strings.h | 22 + .../e2studio/RX72NEnvisionKit/common/unistd.h | 22 + .../RX72NEnvisionKit/common/user_settings.h | 181 ++++ .../RX72NEnvisionKit/common/wolfssl_dummy.c | 41 + .../e2studio/RX72NEnvisionKit/include.am | 23 + .../e2studio/RX72NEnvisionKit/smc/.cproject | 146 +++ .../e2studio/RX72NEnvisionKit/smc/.project | 31 + .../e2studio/RX72NEnvisionKit/smc/smc.scfg | 859 ++++++++++++++++++ .../e2studio/RX72NEnvisionKit/test/.cproject | 508 +++++++++++ .../e2studio/RX72NEnvisionKit/test/.project | 59 ++ .../RX72NEnvisionKit/test/src/key_data.c | 126 +++ .../RX72NEnvisionKit/test/src/key_data.h | 54 ++ .../RX72NEnvisionKit/test/src/test_main.c | 251 +++++ .../RX72NEnvisionKit/test/src/wolf_client.c | 212 +++++ .../RX72NEnvisionKit/test/src/wolf_server.c | 203 +++++ .../RX72NEnvisionKit/test/src/wolfssl_demo.h | 48 + .../test/test_HardwareDebug.launch | 167 ++++ .../RX72NEnvisionKit/wolfssl/.cproject | 104 +++ .../RX72NEnvisionKit/wolfssl/.project | 393 ++++++++ 20 files changed, 3605 insertions(+) create mode 100644 IDE/Renesas/e2studio/RX72NEnvisionKit/README create mode 100644 IDE/Renesas/e2studio/RX72NEnvisionKit/common/strings.h create mode 100644 IDE/Renesas/e2studio/RX72NEnvisionKit/common/unistd.h create mode 100644 IDE/Renesas/e2studio/RX72NEnvisionKit/common/user_settings.h create mode 100644 IDE/Renesas/e2studio/RX72NEnvisionKit/common/wolfssl_dummy.c create mode 100644 IDE/Renesas/e2studio/RX72NEnvisionKit/include.am create mode 100644 IDE/Renesas/e2studio/RX72NEnvisionKit/smc/.cproject create mode 100644 IDE/Renesas/e2studio/RX72NEnvisionKit/smc/.project create mode 100644 IDE/Renesas/e2studio/RX72NEnvisionKit/smc/smc.scfg create mode 100644 IDE/Renesas/e2studio/RX72NEnvisionKit/test/.cproject create mode 100644 IDE/Renesas/e2studio/RX72NEnvisionKit/test/.project create mode 100644 IDE/Renesas/e2studio/RX72NEnvisionKit/test/src/key_data.c create mode 100644 IDE/Renesas/e2studio/RX72NEnvisionKit/test/src/key_data.h create mode 100644 IDE/Renesas/e2studio/RX72NEnvisionKit/test/src/test_main.c create mode 100644 IDE/Renesas/e2studio/RX72NEnvisionKit/test/src/wolf_client.c create mode 100644 IDE/Renesas/e2studio/RX72NEnvisionKit/test/src/wolf_server.c create mode 100644 IDE/Renesas/e2studio/RX72NEnvisionKit/test/src/wolfssl_demo.h create mode 100644 IDE/Renesas/e2studio/RX72NEnvisionKit/test/test_HardwareDebug.launch create mode 100644 IDE/Renesas/e2studio/RX72NEnvisionKit/wolfssl/.cproject create mode 100644 IDE/Renesas/e2studio/RX72NEnvisionKit/wolfssl/.project diff --git a/IDE/Renesas/e2studio/RX72NEnvisionKit/README b/IDE/Renesas/e2studio/RX72NEnvisionKit/README new file mode 100644 index 0000000000..331debab13 --- /dev/null +++ b/IDE/Renesas/e2studio/RX72NEnvisionKit/README @@ -0,0 +1,155 @@ +----------------------------------------------------- +0. 初めに +----------------------------------------------------- + +このドキュメントではE2Studio上でwolfsslを含んだテストアプリケーションを作成する手順を示します。 + +このREADMEが含まれているフォルダには + 1.smc    ---スマートコンフィギュレータ用プロジェクトが格納されているフォルダです + 2.test    ---テストアプリケーション用プロジェクトが格納されているフォルダです + 3.wolfssl  ---テストアプリケーションにリンクされて使用されるwolfsslライブラリ用プロジェクトが格納されているフォルダです + 4.common   ---設定ファイル等が格納されたフォルダです + +フォルダが存在しています。 + +------------------------------------- +1.プロジェクトのインポート +------------------------------------- + +e2studioを起動したら、プロジェクト・エクスプローラー画面を表示させ、"ファイル"メニュー > ”ファイル・システムからプロジェクトを開く...”を選択し、 +プロジェクトインポートダイアログを表示させます。 + +ディレクトリボタンを押して、上記の1~3のフォルダの3プロジェクトをインポートしてください。 + +------------------------------------- +2.smcプロジェクトでソースファイルを生成させる +------------------------------------- + +smcプロジェクトにはsmc.scfgファイルが既に用意してあります。 +このファイルをダブルクリックするとスマートコンフィギュレータパースペクティブが開き、複数のタブを含んだ設定ページが表示されます。 +概要タブに現在選択されているコンポーネントがバージョンとともにリストアップされています。 +これらはテストアプリケーションの実行に必要なものが設定済みとなっています。 +ボード情報、クロック設定などもRX72N EnvisionKitに合わせて設定済みです。 + +設定が必要な個所は、 +コンポーネントタブで r_t4_rx コンポーネントの設定を表示させます。ここで、次のプロパティの値 +#IP address for ch0,when DHCP disable. + +として、RX72N EnvisionKitに設定するIPv4アドレスを皆さんの環境に合った値に設定してください。 +ここだけが設定が必要な個所です。 + +設定を保存し、画面右上のソースファイル生成ボタンを押してソースファイルを生成させてください。 + +------------------------------------- +3.testプロジェクトに生成させたソースファイルをコピーする +------------------------------------- + +e2studioのプロジェクト・エクスプローラー画面のtestプロジェクトのフォルダを展開すると、 +srcフォルダがあります。このフォルダに、smcプロジェクトフォルダ内のsrc/smc_genをコピーしてください。 + +------------------------------------- +4.testプロジェクトの動作を選択する +------------------------------------- + +テストアプリケーションは、暗号化テスト、ベンチマーク、TLSクライアント、TLSサーバーの +4種類の動作を選択できます。選択は、common/user_settings.hの +定義文のいずれか一つを有効化することで行います。 + +------------------------------------- +5.wolfsslプロジェクト、testプロジェクトをビルドする +------------------------------------- + +ビルド前に必ず上記4の設定が終わっていることを確認してください。 +ビルドはwolfssl,testの順に行います。 + +------------------------------------- +6.エミュレータを使ってtestアプリケーションを実行する +------------------------------------- + +エミュレータとターゲットボードとPCをケーブルで接続したら、すでに、test HardwareDebug.launchが用意してありますから +e2studioのメニュー”実行” >”デバッグ”を選択してデバッグを開始してください。 + +お手持ちのエミュレータが異なる場合はデバッグ構成を変更して上記ファイルを更新してください。 + +デバッグパースペクティブ表示になったら、e2studioのメニュー”Renesas Views” > ”デバッグ” > "Renesas Debug Virtual Console"を選択して +デバッグコンソール画面を表示してください。 testアプリケーション実行時の経過、結果等の表示がこのコンソールに出力されます。 + + +================================================================================= + +----------------------------------------------------- +0. About this document +----------------------------------------------------- + +This document will show you how to create a test application containing wolfssl on E2Studio. + +The folder that contains this README has: + 1.smc --- the folder where the smart configurator project is stored. + 2.test --- the folder where the test application project is stored + 3.wolfssl --- the folder where the project for the wolfssl library used by the test application is stored. + 4.common --- the folder where the configuration files etc. are stored + + +------------------------------------- +1. Import projects +------------------------------------- + +After starting e2studio, display the project explorer screen, +select "File" menu> "Open project from file system...", +Display the project import dialog. + +Press the directory button and import the 3 projects in the folders 1 to 3 above. + +------------------------------------- +2. Generate source files in smc project +------------------------------------- + +The smc.scfg file is already prepared in the smc project. +Double-clicking on this file will open the Smart Configurator perspective, +displaying a configuration page with multiple tabs. +The components currently selected in the Overview tab are listed along with their version. +These are already set up to run the test application. +Board information and clock settings are already set according to RX72N EnvisionKit. + +The points that need to be set are +Display the r_t4_rx component settings in the component tab. Where the value of the following property +#IP address for ch0,when DHCP disable. + +Then, set the IPv4 address set in RX72N EnvisionKit to a value that suits your environment. +This is the only place that needs to be set. + +Save the settings and press the source file generation button at the top right of the screen to generate the source file. + +------------------------------------- +3. Copy the source files generated in the test project +------------------------------------- + +When you expand the test project folder on the e2studio Project Explorer screen, +There is a src folder. Copy src/smc_gen in the smc project folder to test/src folder. + +------------------------------------- +4. Select the behavior of the test project +------------------------------------- + +Test applications include encryption test, benchmark, TLS client, TLS server +You can select four types of operation. +This is done by activating one of those commented definition statements in common/user_settings.h. + +------------------------------------- +5. Build wolfssl project, test project +------------------------------------- + +Make sure that the above settings are completed before building. +Build in order of wolfssl and test. + +------------------------------------- +6. Run the test application using the emulator +------------------------------------- + +After connecting the emulator, target board and PC with a cable, test HardwareDebug.launch is already prepared. +Select "Run"> "Debug" in e2 studio to start debugging. + +If the emulator you have is different, change the debug configuration and update the above file. + +When the debug perspective is displayed, select the e2 studio menu "Renesas Views"> "Debug"> "Renesas Debug Virtual Console" +Display the debug console screen. The progress and results of the test application execution are output to this console. diff --git a/IDE/Renesas/e2studio/RX72NEnvisionKit/common/strings.h b/IDE/Renesas/e2studio/RX72NEnvisionKit/common/strings.h new file mode 100644 index 0000000000..fd2cf86e6a --- /dev/null +++ b/IDE/Renesas/e2studio/RX72NEnvisionKit/common/strings.h @@ -0,0 +1,22 @@ +/* strings.h + * + * Copyright (C) 2006-2020 wolfSSL Inc. + * + * This file is part of wolfSSL. + * + * wolfSSL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * wolfSSL is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + */ + +int strncasecmp(const char *s1, const char * s2, unsigned int sz); diff --git a/IDE/Renesas/e2studio/RX72NEnvisionKit/common/unistd.h b/IDE/Renesas/e2studio/RX72NEnvisionKit/common/unistd.h new file mode 100644 index 0000000000..d91dd47903 --- /dev/null +++ b/IDE/Renesas/e2studio/RX72NEnvisionKit/common/unistd.h @@ -0,0 +1,22 @@ +/* unistd.h + * + * Copyright (C) 2006-2020 wolfSSL Inc. + * + * This file is part of wolfSSL. + * + * wolfSSL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * wolfSSL is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + */ + +/* DUMMY Header */ diff --git a/IDE/Renesas/e2studio/RX72NEnvisionKit/common/user_settings.h b/IDE/Renesas/e2studio/RX72NEnvisionKit/common/user_settings.h new file mode 100644 index 0000000000..0add31be15 --- /dev/null +++ b/IDE/Renesas/e2studio/RX72NEnvisionKit/common/user_settings.h @@ -0,0 +1,181 @@ +/* user_settings.h + * + * Copyright (C) 2006-2020 wolfSSL Inc. + * + * This file is part of wolfSSL. + * + * wolfSSL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * wolfSSL is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + */ + +/*-- Renesas MCU type --------------------------------------------------------- + * + * + *----------------------------------------------------------------------------*/ +/*#define WOLFSSL_RENESAS_RX65N*/ + #define WOLFSSL_RENESAS_RX72N + + +/*-- Renesas TSIP usage and its version --------------------------------------- + * + * "WOLFSSL_RENESAS_TSIP" definition makes wolfSSL to use H/W acceleration + * for cipher operations. + * TSIP definition asks to have its version number. + * "WOLFSSL_RENESAS_TSIP_VER" takes following value: + * 106: TSIPv1.06 + * 109: TSIPv1.09 + * + *----------------------------------------------------------------------------*/ + #define WOLFSSL_RENESAS_TSIP + #define WOLFSSL_RENESAS_TSIP_VER 109 + + +/*-- TLS version definitions -------------------------------------------------- + * + * wolfSSL supports TLSv1.2 by default. In case you want your system supports + * TLSv1.3, uncomment line below. + * + *----------------------------------------------------------------------------*/ +/*#define WOLFSSL_TLS13*/ + + +/*-- Operating System related definitions -------------------------------------- + * + * In case any real-time OS is used, define its name(e.g. FREERTOS). + * Otherwise, define "SINGLE_THREADED". They are exclusive each other. + * + *----------------------------------------------------------------------------*/ + #define SINGLE_THREADED +/*#define FREERTOS*/ + + +/*-- Cipher related definitions ----------------------------------------------- + * + * + *----------------------------------------------------------------------------*/ + + #define NO_DEV_RANDOM + #define USE_CERT_BUFFERS_2048 + #define WOLFSSL_DH_CONST + #define HAVE_TLS_EXTENSIONS + + #define HAVE_AESGCM + #define HAVE_AES_CBC + #define WOLFSSL_SHA512 + + #define HAVE_SUPPORTED_CURVES + #define HAVE_ECC + #define HAVE_CURVE25519 + #define CURVE25519_SMALL + #define HAVE_ED25519 + + #define WOLFSSL_STATIC_RSA + + +/*-- Misc definitions --------------------------------------------------------- + * + * + *----------------------------------------------------------------------------*/ + #define SIZEOF_LONG_LONG 8 + +#if !defined(min) + #define min(data1, data2) _builtin_min(data1, data2) +#endif + + /* + * -- "NO_ASN_TIME" macro is to avoid certificate expiration validation -- + * + * Note. In your actual products, do not forget to comment-out + * "NO_ASN_TIME" macro. And prepare time function to get calender time, + * otherwise, certificate expiration validation will not work. + */ + #define NO_ASN_TIME + + #define NO_MAIN_DRIVER + #define BENCH_EMBEDDED + #define NO_WOLFSSL_DIR + #define WOLFSSL_NO_CURRDIR + #define NO_FILESYSTEM + #define WOLFSSL_LOG_PRINTF + #define WOLFSSL_HAVE_MIN + #define WOLFSSL_HAVE_MAX + #define WOLFSSL_SMALL_STACK + #define NO_WRITEV + #define WOLFSSL_USER_IO + + #define WOLFSSL_USER_CURRTIME + #define USER_TIME + #define XTIME time + #define USE_WOLF_SUSECONDS_T + #define USE_WOLF_TIMEVAL_T + + #define WOLFSSL_USER_CURRTIME /* for benchmark */ + #define WC_RSA_BLINDING + #define TFM_TIMING_RESISTANT + #define ECC_TIMING_RESISTANT + +/*-- Debugging options ------------------------------------------------------ + * + * "DEBUG_WOLFSSL" definition enables log to output into stdout. + * Note: wolfSSL_Debugging_ON() must be called just after wolfSSL_Init(). + *----------------------------------------------------------------------------*/ + +/*#define DEBUG_WOLFSSL*/ + +/*-- Definitions for functionality negation ----------------------------------- + * + * + *----------------------------------------------------------------------------*/ + +/*#define NO_RENESAS_TSIP_CRYPT*/ +/*#define NO_WOLFSSL_RENESAS_TSIP_TLS_SESSION*/ + + +/*-- Consistency checking between definitions --------------------------------- + * + * + *----------------------------------------------------------------------------*/ + +/*-- TSIP TLS specific definitions --*/ +#if defined(WOLFSSL_RENESAS_TSIP) + #if !defined(WOLFSSL_RENESAS_TSIP_VER) + #error "WOLFSSL_RENESAS_TSIP_VER is required to be defined and have value" + #endif +#endif + +/*-- Complementary definitions ------------------------------------------------ + * + * + *----------------------------------------------------------------------------*/ + +#if defined(WOLFSSL_RENESAS_TSIP) + + #if !defined(NO_RENESAS_TSIP_CRYPT) + #define WOLFSSL_RENESAS_TSIP_CRYPT + #define WOLFSSL_RENESAS_TSIP_TLS + #define WOLFSSL_RENESAS_TSIP_TLS_AES_CRYPT + #endif + +#else + #define OPENSSL_EXTRA + #define WOLFSSL_GENSEED_FORTEST /* Warning: define your own seed gen */ +#endif + + +/*-- TLS version and required definitions --*/ +#if defined(WOLFSSL_TLS13) + #define HAVE_FFDHE_2048 + #define HAVE_HKDF + #define WC_RSA_PSS +#endif diff --git a/IDE/Renesas/e2studio/RX72NEnvisionKit/common/wolfssl_dummy.c b/IDE/Renesas/e2studio/RX72NEnvisionKit/common/wolfssl_dummy.c new file mode 100644 index 0000000000..8fa6340b45 --- /dev/null +++ b/IDE/Renesas/e2studio/RX72NEnvisionKit/common/wolfssl_dummy.c @@ -0,0 +1,41 @@ +/* wolfssl_dummy.c + * + * Copyright (C) 2006-2020 wolfSSL Inc. + * + * This file is part of wolfSSL. + * + * wolfSSL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * wolfSSL is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + */ + +typedef unsigned long time_t; + +#define YEAR 2020 +#define MON 7 + +static int tick = 0; + +time_t time(time_t *t) +{ + return ((YEAR-1970)*365+30*MON)*24*60*60 + tick++; +} + +#include +int strncasecmp(const char *s1, const char * s2, unsigned int sz) +{ + for( ; sz>0; sz--) + if(toupper(s1++) != toupper(s2++)) + return 1; + return 0; +} diff --git a/IDE/Renesas/e2studio/RX72NEnvisionKit/include.am b/IDE/Renesas/e2studio/RX72NEnvisionKit/include.am new file mode 100644 index 0000000000..1b59192e70 --- /dev/null +++ b/IDE/Renesas/e2studio/RX72NEnvisionKit/include.am @@ -0,0 +1,23 @@ +# vim:ft=automake +# included from Top Level Makefile.am +# All paths should be given relative to the root + +EXTRA_DIST+= IDE/Renesas/e2studio/RX72NEnvisionKit/README +EXTRA_DIST+= IDE/Renesas/e2studio/RX72NEnvisionKit/wolfssl/.cproject +EXTRA_DIST+= IDE/Renesas/e2studio/RX72NEnvisionKit/wolfssl/.project +EXTRA_DIST+= IDE/Renesas/e2studio/RX72NEnvisionKit/test/.cproject +EXTRA_DIST+= IDE/Renesas/e2studio/RX72NEnvisionKit/test/.project +EXTRA_DIST+= IDE/Renesas/e2studio/RX72NEnvisionKit/test/test_HardwareDebug.launch +EXTRA_DIST+= IDE/Renesas/e2studio/RX72NEnvisionKit/test/src/test_main.c +EXTRA_DIST+= IDE/Renesas/e2studio/RX72NEnvisionKit/test/src/key_data.c +EXTRA_DIST+= IDE/Renesas/e2studio/RX72NEnvisionKit/test/src/key_data.h +EXTRA_DIST+= IDE/Renesas/e2studio/RX72NEnvisionKit/test/src/wolf_client.c +EXTRA_DIST+= IDE/Renesas/e2studio/RX72NEnvisionKit/test/src/wolf_server.c +EXTRA_DIST+= IDE/Renesas/e2studio/RX72NEnvisionKit/test/src/wolfssl_demo.h +EXTRA_DIST+= IDE/Renesas/e2studio/RX72NEnvisionKit/common/wolfssl_dummy.c +EXTRA_DIST+= IDE/Renesas/e2studio/RX72NEnvisionKit/common/strings.h +EXTRA_DIST+= IDE/Renesas/e2studio/RX72NEnvisionKit/common/unistd.h +EXTRA_DIST+= IDE/Renesas/e2studio/RX72NEnvisionKit/common/user_settings.h +EXTRA_DIST+= IDE/Renesas/e2studio/RX72NEnvisionKit/smc/.cproject +EXTRA_DIST+= IDE/Renesas/e2studio/RX72NEnvisionKit/smc/.project +EXTRA_DIST+= IDE/Renesas/e2studio/RX72NEnvisionKit/smc/smc.scfg \ No newline at end of file diff --git a/IDE/Renesas/e2studio/RX72NEnvisionKit/smc/.cproject b/IDE/Renesas/e2studio/RX72NEnvisionKit/smc/.cproject new file mode 100644 index 0000000000..bd4b162235 --- /dev/null +++ b/IDE/Renesas/e2studio/RX72NEnvisionKit/smc/.cproject @@ -0,0 +1,146 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/IDE/Renesas/e2studio/RX72NEnvisionKit/smc/.project b/IDE/Renesas/e2studio/RX72NEnvisionKit/smc/.project new file mode 100644 index 0000000000..eb9d9de48c --- /dev/null +++ b/IDE/Renesas/e2studio/RX72NEnvisionKit/smc/.project @@ -0,0 +1,31 @@ + + + smc + + + + + + org.eclipse.cdt.managedbuilder.core.genmakebuilder + clean,full,incremental, + + + + + org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder + full,incremental, + + + + + com.renesas.cdt.managedbuild.renesas.misrachecker.builder + + + + + + org.eclipse.cdt.core.cnature + org.eclipse.cdt.managedbuilder.core.managedBuildNature + org.eclipse.cdt.managedbuilder.core.ScannerConfigNature + + diff --git a/IDE/Renesas/e2studio/RX72NEnvisionKit/smc/smc.scfg b/IDE/Renesas/e2studio/RX72NEnvisionKit/smc/smc.scfg new file mode 100644 index 0000000000..aae3bb2e31 --- /dev/null +++ b/IDE/Renesas/e2studio/RX72NEnvisionKit/smc/smc.scfg @@ -0,0 +1,859 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/IDE/Renesas/e2studio/RX72NEnvisionKit/test/.cproject b/IDE/Renesas/e2studio/RX72NEnvisionKit/test/.cproject new file mode 100644 index 0000000000..266d7d6f04 --- /dev/null +++ b/IDE/Renesas/e2studio/RX72NEnvisionKit/test/.cproject @@ -0,0 +1,508 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/IDE/Renesas/e2studio/RX72NEnvisionKit/test/.project b/IDE/Renesas/e2studio/RX72NEnvisionKit/test/.project new file mode 100644 index 0000000000..0a68066534 --- /dev/null +++ b/IDE/Renesas/e2studio/RX72NEnvisionKit/test/.project @@ -0,0 +1,59 @@ + + + test + + + + + + org.eclipse.cdt.managedbuilder.core.genmakebuilder + clean,full,incremental, + + + + + org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder + full,incremental, + + + + + com.renesas.cdt.managedbuild.renesas.misrachecker.builder + + + + + + org.eclipse.cdt.core.cnature + org.eclipse.cdt.managedbuilder.core.managedBuildNature + org.eclipse.cdt.managedbuilder.core.ScannerConfigNature + + + + src/benchmark.c + 1 + $%7BPARENT-5-PROJECT_LOC%7D/wolfcrypt/benchmark/benchmark.c + + + src/benchmark.h + 1 + $%7BPARENT-5-PROJECT_LOC%7D/wolfcrypt/benchmark/benchmark.h + + + src/test.c + 1 + PARENT-5-PROJECT_LOC/wolfcrypt/test/test.c + + + src/wolfssl_dummy.c + 1 + $%7BPARENT-1-PROJECT_LOC%7D/common/wolfssl_dummy.c + + + + + copy_PARENT + $%7BPARENT-3-ECLIPSE_HOME%7D/workspace/wolfssl + + + diff --git a/IDE/Renesas/e2studio/RX72NEnvisionKit/test/src/key_data.c b/IDE/Renesas/e2studio/RX72NEnvisionKit/test/src/key_data.c new file mode 100644 index 0000000000..6dfac9811f --- /dev/null +++ b/IDE/Renesas/e2studio/RX72NEnvisionKit/test/src/key_data.c @@ -0,0 +1,126 @@ +/* key_data.c + * + * Copyright (C) 2006-2020 wolfSSL Inc. + * + * This file is part of wolfSSL. + * + * wolfSSL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * wolfSSL is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + */ +#include "key_data.h" + +/*------------------------------------------------------------------------- + TSIP v1.09 +--------------------------------------------------------------------------*/ +#if defined(WOLFSSL_RENESAS_TSIP_TLS) && (WOLFSSL_RENESAS_TSIP_VER >=109) + +/* Key type of the encrypted user_public_key 0: RSA-2048 2: ECDSA-P256*/ +const uint32_t encrypted_user_key_type = 0; + +const st_key_block_data_t g_key_block_data = +{ + /* uint8_t encrypted_provisioning_key[R_TSIP_AES_CBC_IV_BYTE_SIZE * 2]; */ + { + 0xD8, 0xB3, 0xA7, 0xDB, 0xD1, 0x5E, 0x44, 0x24, 0x00, 0xDA, 0xEB, 0xB3, 0x33, 0xE1, 0x49, 0xAF, + 0x4B, 0xAC, 0xC5, 0xF5, 0xC8, 0xD5, 0xAC, 0x12, 0x7F, 0xF7, 0x58, 0xAE, 0x59, 0xFE, 0xFB, 0x32 + }, + /* uint8_t iv[R_TSIP_AES_CBC_IV_BYTE_SIZE]; */ + { + 0xF6, 0xA9, 0x83, 0x5A, 0xA1, 0x65, 0x1D, 0x28, 0xC8, 0x1A, 0xA6, 0x9D, 0x34, 0xB2, 0x4D, 0x92 + }, + /* uint8_t encrypted_user_rsa2048_ne_key[R_TSIP_RSA2048_NE_KEY_BYTE_SIZE + 16]; */ + { + 0xC1, 0xB7, 0xCC, 0x99, 0x0A, 0xC8, 0x3E, 0xAB, 0x74, 0x35, 0x9D, 0x1C, 0x81, 0x32, 0x72, 0xA7, + 0xA8, 0x0D, 0xBA, 0x1B, 0x35, 0x42, 0x2F, 0x7B, 0xB4, 0x1C, 0x86, 0x81, 0xC4, 0xFA, 0xD9, 0x65, + 0xCE, 0x8A, 0x70, 0x1A, 0x28, 0x09, 0x72, 0xC0, 0x4F, 0x7A, 0x4A, 0xC7, 0xE6, 0x21, 0x65, 0x6E, + 0xEB, 0x11, 0x45, 0x23, 0x35, 0xC0, 0x0F, 0x1D, 0x48, 0xC6, 0x8A, 0x1C, 0x27, 0x70, 0xA6, 0x26, + 0xD0, 0x49, 0xCD, 0x42, 0x8D, 0x65, 0x2F, 0xFC, 0x32, 0x12, 0x6F, 0xE6, 0x61, 0xB6, 0x2F, 0xD9, + 0xA7, 0xC3, 0xB0, 0x3A, 0x4F, 0x58, 0xFD, 0x1E, 0x8E, 0xDE, 0x5C, 0xD4, 0xF3, 0x4E, 0xF7, 0x45, + 0x01, 0xDC, 0x39, 0x38, 0x15, 0x37, 0x8A, 0xFD, 0x59, 0x1A, 0x6C, 0x04, 0x55, 0x31, 0x56, 0x14, + 0x07, 0x71, 0x9A, 0x19, 0x81, 0x7F, 0x69, 0x88, 0xD7, 0xD5, 0xBE, 0xB4, 0x95, 0x83, 0xC5, 0x35, + 0xA8, 0xDE, 0x65, 0x5E, 0x95, 0xBB, 0xE3, 0x9C, 0x81, 0x4C, 0x8B, 0x18, 0x4C, 0xEA, 0x12, 0xEE, + 0xF3, 0x98, 0x68, 0x35, 0xC8, 0xA5, 0x69, 0x6F, 0x71, 0x8C, 0xAA, 0xB5, 0x3F, 0xF7, 0x3C, 0x10, + 0xC0, 0xD4, 0x46, 0x4D, 0xD0, 0x56, 0xDB, 0x7F, 0xC1, 0x52, 0xE0, 0x06, 0xD8, 0xB9, 0x5E, 0x41, + 0x43, 0x0E, 0xBB, 0xCD, 0x5C, 0x4D, 0x02, 0x37, 0xD1, 0xFD, 0x88, 0xCB, 0x49, 0xC3, 0x51, 0x0C, + 0x8A, 0x17, 0x71, 0xFE, 0x97, 0x8F, 0xF6, 0x65, 0xFC, 0xF8, 0xB4, 0xC2, 0x65, 0x4B, 0x5B, 0x74, + 0x4B, 0xFF, 0x35, 0xE9, 0x33, 0x3A, 0xBE, 0xDF, 0x23, 0x4F, 0xDB, 0x3F, 0x94, 0x6F, 0x34, 0x21, + 0x76, 0x14, 0xAF, 0x2B, 0x96, 0x62, 0xA5, 0x52, 0x80, 0xB9, 0x36, 0x7E, 0x25, 0xAF, 0xB6, 0x75, + 0xE5, 0x79, 0x8E, 0xE8, 0x67, 0xE4, 0xDD, 0x4B, 0x3D, 0xB2, 0x7F, 0xAF, 0x32, 0xC5, 0xF5, 0x1B, + 0x90, 0x0E, 0x41, 0x97, 0x5D, 0xFD, 0xC1, 0x9A, 0xA1, 0xF9, 0x57, 0xF1, 0x21, 0x94, 0xF9, 0x31, + 0xC9, 0xC7, 0x16, 0xAA, 0xD8, 0xE9, 0x78, 0x03, 0xAD, 0xEF, 0x3E, 0x98, 0x1F, 0x32, 0x3D, 0x8E + }, + /* uint8_t encrypted_user_update_key[R_TSIP_AES256_KEY_BYTE_SIZE + 16]; */ + { + 0x70, 0xA8, 0xB5, 0x63, 0xE9, 0xC2, 0xA0, 0xFC, 0xE5, 0xA5, 0x4D, 0x94, 0x6E, 0x69, 0xE8, 0x94, + 0xAC, 0xE6, 0x68, 0x7C, 0xB2, 0xB9, 0xDC, 0xCF, 0x69, 0xBC, 0xE6, 0xB9, 0x8C, 0xDA, 0x72, 0x5C, + 0x62, 0xE9, 0xB9, 0xC1, 0xB4, 0xC7, 0x60, 0x21, 0xAE, 0x1B, 0x52, 0x25, 0x06, 0x8A, 0x91, 0xA1 + }, + +}; +/* ./ca-cert.der.sign, */ +const unsigned char ca_cert_sig[] = +{ +0x04,0x1C,0x4C,0x29,0x93,0x38,0x78,0x72,0x32,0x55,0x90,0x4F,0xA7,0x43,0xC8,0x00, +0x98,0x75,0xC8,0x62,0x37,0xEC,0x8F,0xAD,0x8F,0x98,0x04,0x5B,0xC9,0x50,0xD2,0xE3, +0xC3,0x89,0x21,0xC7,0xF4,0x43,0x27,0xFB,0xC0,0x7A,0x17,0x45,0x5C,0x10,0x23,0x1B, +0xC0,0x63,0x2F,0x61,0xE5,0xEE,0x0B,0x89,0xF2,0x6E,0x6B,0x49,0xFB,0xD4,0xB5,0x89, +0xED,0xB4,0x7F,0x70,0xA0,0x68,0x44,0x6F,0xE6,0x15,0x0F,0x0C,0x78,0x9D,0x4C,0xBD, +0x1C,0x24,0x50,0xAE,0xD2,0xB4,0x53,0xA5,0x7C,0x5F,0x5D,0x8C,0x8C,0x37,0xAB,0x72, +0x61,0x83,0x39,0xDD,0x76,0x86,0xB4,0xEC,0xCF,0x57,0x35,0xC4,0x56,0x6B,0x45,0xCE, +0x4C,0x06,0x35,0xBE,0xF2,0x95,0x5A,0x37,0x43,0x15,0x7F,0x42,0x3A,0xBA,0x90,0xE7, +0x01,0x37,0x10,0x46,0x5B,0x65,0x7D,0x2F,0xAF,0x9F,0xCB,0xBB,0xFF,0x0D,0x5D,0xE0, +0xCD,0xA8,0x09,0x62,0xCA,0x38,0x10,0x09,0x1B,0x81,0x2D,0xC2,0x3E,0x15,0x9E,0x36, +0x6B,0x10,0xF9,0xD9,0x55,0xBF,0x93,0x79,0xC0,0x0D,0x74,0x31,0x83,0xA4,0xB9,0x66, +0x30,0x6C,0xC9,0xA9,0xE6,0x93,0xF0,0x1D,0x61,0x18,0xBD,0x95,0xA5,0xB4,0x0F,0x69, +0xCD,0xD7,0xA3,0x4A,0x74,0x8B,0xBE,0x2D,0x90,0xA5,0x49,0x69,0x9B,0x59,0x29,0x3A, +0x4D,0x77,0xF0,0x4F,0x37,0x42,0x89,0x67,0xE2,0x62,0x91,0xC6,0x25,0xA6,0x2B,0x35, +0x2C,0x59,0x60,0xB4,0xAF,0x9F,0xBF,0x43,0x4E,0x32,0x11,0xCE,0x8F,0x7A,0x4C,0xA4, +0x26,0xBF,0x3A,0x35,0x70,0xD6,0x9F,0x0C,0x76,0xC8,0xCA,0x94,0xA0,0xD4,0x0B,0x2D +}; +const int sizeof_ca_cert_sig = sizeof(ca_cert_sig); +/* ./client-cert.der.sign, */ +const unsigned char client_cert_der_sign[] = +{ + 0x5D, 0x1F, 0x89, 0x41, 0xEC, 0x47, 0xC8, 0x90, 0x61, 0x79, + 0x8A, 0x16, 0x1F, 0x31, 0x96, 0x67, 0xD9, 0x3C, 0xEC, 0x6B, + 0x58, 0xC6, 0x5A, 0xED, 0x99, 0xB3, 0xEF, 0x27, 0x6F, 0x04, + 0x8C, 0xD9, 0x68, 0xB1, 0xD6, 0x23, 0x15, 0x84, 0x00, 0xE1, + 0x27, 0xD1, 0x1F, 0x68, 0xB7, 0x3F, 0x13, 0x53, 0x8A, 0x95, + 0x5A, 0x20, 0x7C, 0xB2, 0x76, 0x5B, 0xDC, 0xE0, 0xA6, 0x21, + 0x7C, 0x49, 0xCF, 0x93, 0xBA, 0xD5, 0x12, 0x9F, 0xEE, 0x90, + 0x5B, 0x3F, 0xA3, 0x9D, 0x13, 0x72, 0xAC, 0x72, 0x16, 0xFE, + 0x1D, 0xBE, 0xEB, 0x8E, 0xC7, 0xDC, 0xC4, 0xF8, 0x1A, 0xD8, + 0xA0, 0xA4, 0xF6, 0x04, 0x30, 0xF6, 0x7E, 0xB6, 0xC8, 0xE1, + 0xAB, 0x88, 0x37, 0x08, 0x63, 0x72, 0xAA, 0x46, 0xCC, 0xCA, + 0xF0, 0x9E, 0x02, 0x1E, 0x65, 0x67, 0xFF, 0x2C, 0x9D, 0x81, + 0x6C, 0x1E, 0xF1, 0x54, 0x05, 0x68, 0x68, 0x18, 0x72, 0x26, + 0x55, 0xB6, 0x2C, 0x95, 0xC0, 0xC9, 0xB2, 0xA7, 0x0B, 0x60, + 0xD7, 0xEB, 0x1D, 0x08, 0x1A, 0xA2, 0x54, 0x15, 0x89, 0xCB, + 0x83, 0x21, 0x5D, 0x15, 0x9B, 0x38, 0xAC, 0x89, 0x63, 0xD5, + 0x4B, 0xF4, 0x8B, 0x47, 0x93, 0x78, 0x43, 0xCB, 0x9B, 0x71, + 0xBF, 0x94, 0x76, 0xB5, 0xCE, 0x35, 0xA9, 0x1A, 0xD5, 0xA5, + 0xD8, 0x19, 0xA6, 0x04, 0x39, 0xB1, 0x09, 0x8C, 0x65, 0x02, + 0x58, 0x3A, 0x95, 0xEF, 0xA2, 0xC3, 0x85, 0x18, 0x61, 0x23, + 0x2D, 0xC5, 0xCD, 0x62, 0xC1, 0x19, 0x31, 0xE5, 0x36, 0x95, + 0x22, 0xDB, 0x3E, 0x1A, 0x3C, 0xE8, 0xC6, 0x2E, 0xDF, 0xD9, + 0x2F, 0x84, 0xC1, 0xF0, 0x38, 0x2B, 0xE5, 0x73, 0x35, 0x4F, + 0x05, 0xE2, 0xA5, 0x60, 0x79, 0xB0, 0x23, 0xDC, 0x56, 0x4C, + 0xE7, 0xD9, 0x1F, 0xCF, 0x6A, 0xFC, 0x55, 0xEB, 0xAA, 0x48, + 0x3E, 0x95, 0x2A, 0x10, 0x01, 0x05 +}; +const int sizeof_client_cert_der_sign = sizeof(client_cert_der_sign); + +uint32_t s_inst1[R_TSIP_SINST_WORD_SIZE] = { 0 }; +uint32_t s_inst2[R_TSIP_SINST2_WORD_SIZE]= { 0 }; +#endif diff --git a/IDE/Renesas/e2studio/RX72NEnvisionKit/test/src/key_data.h b/IDE/Renesas/e2studio/RX72NEnvisionKit/test/src/key_data.h new file mode 100644 index 0000000000..74e9ed2423 --- /dev/null +++ b/IDE/Renesas/e2studio/RX72NEnvisionKit/test/src/key_data.h @@ -0,0 +1,54 @@ +/* key_data.h + * + * Copyright (C) 2006-2020 wolfSSL Inc. + * + * This file is part of wolfSSL. + * + * wolfSSL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * wolfSSL is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + */ + + + +#ifndef KEY_DATA_H_ +#define KEY_DATA_H_ + +#include + + +#if defined(WOLFSSL_RENESAS_TSIP) + +#include "r_tsip_rx_if.h" + +typedef struct st_key_block_data +{ + uint8_t encrypted_provisioning_key[R_TSIP_AES_CBC_IV_BYTE_SIZE * 2]; + uint8_t iv[R_TSIP_AES_CBC_IV_BYTE_SIZE]; + uint8_t encrypted_user_rsa2048_ne_key[R_TSIP_RSA2048_NE_KEY_BYTE_SIZE + 16]; + uint8_t encrypted_user_update_key[R_TSIP_AES256_KEY_BYTE_SIZE + 16]; +} st_key_block_data_t; + + +extern const uint32_t encrypted_user_key_type; +extern const st_key_block_data_t g_key_block_data; + +extern const unsigned char ca_cert_sig[]; +extern const unsigned char ca_cert_der[]; +extern const unsigned char client_cert_der_sign[]; +extern const int sizeof_ca_cert_der; + + +#endif /* (WOLFSSL_RENESAS_TSIP */ +#endif /* KEY_DATA_H_ */ + diff --git a/IDE/Renesas/e2studio/RX72NEnvisionKit/test/src/test_main.c b/IDE/Renesas/e2studio/RX72NEnvisionKit/test/src/test_main.c new file mode 100644 index 0000000000..7d336826a2 --- /dev/null +++ b/IDE/Renesas/e2studio/RX72NEnvisionKit/test/src/test_main.c @@ -0,0 +1,251 @@ +/* test_main.c + * + * Copyright (C) 2006-2020 wolfSSL Inc. + * + * This file is part of wolfSSL. + * + * wolfSSL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * wolfSSL is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + */ + + +#include "stdio.h" +#include "stdint.h" +#include +#include "wolfssl/wolfcrypt/types.h" +#include "wolfssl_demo.h" + +void main(void); +#ifdef __cplusplus +extern "C" { +void abort(void); +} +#endif + + +#if defined(TLS_CLIENT) || defined(TLS_SERVER) + #include "r_t4_itcpip.h" + #include "r_sys_time_rx_if.h" + #include "Pin.h" + + #define T4_WORK_SIZE (14800) + static UW tcpudp_work[(T4_WORK_SIZE / 4) + 1]; + + #if defined(WOLFSSL_RENESAS_TSIP) + #include "key_data.h" + #include + + extern const st_key_block_data_t g_key_block_data; + #endif + +#endif + +static long tick; +static void timeTick(void *pdata) +{ + tick++; +} + +typedef struct func_args { + int argc; + char** argv; + int return_code; +} func_args; + + +void wolfcrypt_test(func_args args); +int benchmark_test(void *args); + +double current_time(int reset) +{ + if(reset) tick = 0 ; + return ((double)tick/FREQ) ; +} + +#if defined(TLS_CLIENT) || defined(TLS_SERVER) + +int SetTsiptlsKey() +{ +#if defined(WOLFSSL_RENESAS_TSIP) && (WOLFSSL_RENESAS_TSIP_VER >=109) + + #if defined(TLS_CLIENT) + + tsip_inform_cert_sign((const byte *)ca_cert_sig); + tsip_inform_user_keys_ex( + (byte*)&g_key_block_data.encrypted_provisioning_key, + (byte*)&g_key_block_data.iv, + (byte*)&g_key_block_data.encrypted_user_rsa2048_ne_key, + encrypted_user_key_type); + + #elif defined(TLS_SERVER) + + tsip_inform_cert_sign((const byte *)client_cert_der_sign); + tsip_inform_user_keys_ex( + (byte*)&g_key_block_data.encrypted_provisioning_key, + (byte*)&g_key_block_data.iv, + (byte*)&g_key_block_data.encrypted_user_rsa2048_ne_key, + encrypted_user_key_type); + + #endif + +#elif defined(WOLFSSL_RENESAS_TSIP) && (WOLFSSL_RENESAS_TSIP_VER >=106) + + #if defined(TLS_CLIENT) + + tsip_inform_cert_sign((const byte *)ca_cert_sig); + tsip_inform_user_keys((byte*)&g_key_block_data.encrypted_session_key, + (byte*)&g_key_block_data.iv, + (byte*)&g_key_block_data.encrypted_user_rsa2048_ne_key); + + #elif defined(TLS_SERVER) + + tsip_inform_cert_sign((const byte *)client_cert_der_sign); + tsip_inform_user_keys((byte*)&g_key_block_data.encrypted_session_key, + (byte*)&g_key_block_data.iv, + (byte*)&g_key_block_data.encrypted_user_rsa2048_ne_key); + + #endif + +#endif + return 0; +} + +int Open_tcp( ) +{ + ER ercd; + W size; + sys_time_err_t sys_ercd; + char ver[128]; + + /* cast from uint8_t to char* */ + strcpy(ver, (char*)R_t4_version.library); + + sys_ercd = R_SYS_TIME_Open(); + if (sys_ercd != SYS_TIME_SUCCESS) { + printf("ERROR : R_SYS_TIME_Open() failed\n"); + return -1; + } + R_Pins_Create(); + /* start LAN controller */ + ercd = lan_open(); + /* initialize TCP/IP */ + size = tcpudp_get_ramsize(); + if (size > (sizeof(tcpudp_work))) { + printf("size > (sizeof(tcpudp_work))!\n"); + return -1; + } + ercd = tcpudp_open(tcpudp_work); + if (ercd != E_OK) { + printf("ERROR : tcpudp_open failed\n"); + return -1; + } + + return 0; +} + +void Close_tcp() +{ + /* end TCP/IP */ + tcpudp_close(); + lan_close(); + R_SYS_TIME_Close(); +} +#endif + +void main(void) +{ + (void)timeTick; + +#if defined(CRYPT_TEST) || defined(BENCHMARK) +#if defined(CRYPT_TEST) + int ret; + func_args args = { 0 }; + + if ((ret = wolfCrypt_Init()) != 0) { + printf("wolfCrypt_Init failed %d\n", ret); + } + + printf("Start wolfCrypt Test\n"); + wolfcrypt_test(args); + printf("End wolfCrypt Test\n"); + + if ((ret = wolfCrypt_Cleanup()) != 0) { + printf("wolfCrypt_Cleanup failed %d\n", ret); + } +#endif +#if defined(BENCHMARK) + #include "r_cmt_rx_if.h" + + uint32_t channel; + R_CMT_CreatePeriodic(FREQ, &timeTick, &channel); + + printf("Start wolfCrypt Benchmark\n"); + benchmark_test(NULL); + printf("End wolfCrypt Benchmark\n"); +#endif +#elif defined(TLS_CLIENT) + #include "r_cmt_rx_if.h" + +#if defined(WOLFSSL_RENESAS_TSIP) + const char* cipherlist[] = { + + "AES128-SHA", + "AES128-SHA256", + "AES256-SHA", + "AES256-SHA256" + }; + const int cipherlist_sz = 4; +#else + const char* cipherlist[] = { NULL }; + const int cipherlist_sz = 0; + +#endif + int i = 0; + + Open_tcp(); +#if defined(WOLFSSL_RENESAS_TSIP) + SetTsiptlsKey(); +#endif + + do { + if(cipherlist_sz > 0 ) printf("cipher : %s\n", cipherlist[i]); + + wolfSSL_TLS_client_init(cipherlist[i]); + + wolfSSL_TLS_client(); + + i++; + } while (i < cipherlist_sz); + + Close_tcp(); +#elif defined(TLS_SERVER) + + Open_tcp(); +#if defined(WOLFSSL_RENESAS_TSIP) + SetTsiptlsKey(); +#endif + + wolfSSL_TLS_server_init(); + wolfSSL_TLS_server(); + + Close_tcp(); +#endif +} + +#ifdef __cplusplus +void abort(void) +{ + +} +#endif diff --git a/IDE/Renesas/e2studio/RX72NEnvisionKit/test/src/wolf_client.c b/IDE/Renesas/e2studio/RX72NEnvisionKit/test/src/wolf_client.c new file mode 100644 index 0000000000..ff09b1a807 --- /dev/null +++ b/IDE/Renesas/e2studio/RX72NEnvisionKit/test/src/wolf_client.c @@ -0,0 +1,212 @@ +/* wolf_client.c + * + * Copyright (C) 2006-2020 wolfSSL Inc. + * + * This file is part of wolfSSL. + * + * wolfSSL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * wolfSSL is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + */ + +#include +#include +#include "r_t4_itcpip.h" +#include "wolfssl/wolfcrypt/settings.h" +#include "wolfssl/ssl.h" +#include "wolfssl/certs_test.h" +#include "key_data.h" +#include "wolfssl_demo.h" + + +#define SIMPLE_TLSSEVER_IP "192.168.1.3" +#define SIMPLE_TLSSERVER_PORT "11111" + +ER t4_tcp_callback(ID cepid, FN fncd , VP p_parblk); +uint32_t g_encrypted_root_public_key[140]; + +static WOLFSSL_CTX *client_ctx; + + +static int my_IORecv(WOLFSSL* ssl, char* buff, int sz, void* ctx) +{ + int ret; + ID cepid; + + if(ctx != NULL) + cepid = *(ID *)ctx; + else + return WOLFSSL_CBIO_ERR_GENERAL; + + ret = tcp_rcv_dat(cepid, buff, sz, TMO_FEVR); + if(ret > 0) + return ret; + else + return WOLFSSL_CBIO_ERR_GENERAL; +} + +static int my_IOSend(WOLFSSL* ssl, char* buff, int sz, void* ctx) +{ + int ret; + ID cepid; + + if(ctx != NULL) + cepid = *(ID *)ctx; + else + return WOLFSSL_CBIO_ERR_GENERAL; + + ret = tcp_snd_dat(cepid, buff, sz, TMO_FEVR); + if(ret == sz) + return ret; + else + return WOLFSSL_CBIO_ERR_GENERAL; +} + +static int getIPaddr(char *arg) +{ + int a1, a2, a3, a4; + if(sscanf(arg, "%d.%d.%d.%d", &a1, &a2, &a3, &a4) == 4) + return (a1 << 24) | (a2 << 16) | (a3 << 8) | a4; + else return 0; +} + +static int getPort(char *arg) +{ + int port; + if(sscanf(arg, "%d", &port) == 1) + return port; + else return 0; +} + +void wolfSSL_TLS_client_init(const char* cipherlist) +{ + + #ifndef NO_FILESYSTEM + #ifdef USE_ECC_CERT + char *cert = "./certs/ca-ecc-cert.pem"; + #else + char *cert = "./certs/ca-cert.pem"; + #endif + #else + #ifdef USE_ECC_CERT + const unsigned char *cert = ca_ecc_der_256; + #define SIZEOF_CERT sizeof_ca_ecc_der_256 + #else + const unsigned char *cert = ca_cert_der_2048; + #define SIZEOF_CERT sizeof_ca_cert_der_2048 + #endif + #endif + + wolfSSL_Init(); + #ifdef DEBUG_WOLFSSL + wolfSSL_Debugging_ON(); + #endif + + /* Create and initialize WOLFSSL_CTX */ + if ((client_ctx = wolfSSL_CTX_new(wolfTLSv1_2_client_method_ex((void *)NULL))) == NULL) { + printf("ERROR: failed to create WOLFSSL_CTX\n"); + return; + } + + #if !defined(NO_FILESYSTEM) + if (wolfSSL_CTX_load_verify_locations(client_ctx, cert, 0) != SSL_SUCCESS) { + printf("ERROR: can't load \"%s\"\n", cert); + return NULL; + } + #else + if (wolfSSL_CTX_load_verify_buffer(client_ctx, cert, SIZEOF_CERT, SSL_FILETYPE_ASN1) != SSL_SUCCESS){ + printf("ERROR: can't load certificate data\n"); + return; + } + #endif + + /* Register callbacks */ + wolfSSL_SetIORecv(client_ctx, my_IORecv); + wolfSSL_SetIOSend(client_ctx, my_IOSend); + + /* use specific cipher */ + if (cipherlist != NULL && wolfSSL_CTX_set_cipher_list(client_ctx, cipherlist) != WOLFSSL_SUCCESS) { + wolfSSL_CTX_free(client_ctx); client_ctx = NULL; + printf("client can't set cipher list 1"); + } +} + +void wolfSSL_TLS_client( ) +{ + ID cepid = 1; + ER ercd; + int ret; + WOLFSSL_CTX *ctx = (WOLFSSL_CTX *)client_ctx; + WOLFSSL *ssl; + + #define BUFF_SIZE 256 + static const char sendBuff[]= "Hello Server\n" ; + + char rcvBuff[BUFF_SIZE] = {0}; + + static T_IPV4EP my_addr = { 0, 0 }; + + T_IPV4EP dst_addr; + + if((dst_addr.ipaddr = getIPaddr(SIMPLE_TLSSEVER_IP)) == 0){ + printf("ERROR: IP address\n"); + return; + } + if((dst_addr.portno = getPort(SIMPLE_TLSSERVER_PORT)) == 0){ + printf("ERROR: IP address\n"); + return; + } + + if((ercd = tcp_con_cep(cepid, &my_addr, &dst_addr, TMO_FEVR)) != E_OK) { + printf("ERROR TCP Connect: %d\n", ercd); + return; + } + + if((ssl = wolfSSL_new(ctx)) == NULL) { + printf("ERROR wolfSSL_new: %d\n", wolfSSL_get_error(ssl, 0)); + return; + } + + /* set callback context */ + wolfSSL_SetIOReadCtx(ssl, (void *)&cepid); + wolfSSL_SetIOWriteCtx(ssl, (void *)&cepid); + + + if(wolfSSL_connect(ssl) != SSL_SUCCESS) { + printf("ERROR SSL connect: %d\n", wolfSSL_get_error(ssl, 0)); + return; + } + + if (wolfSSL_write(ssl, sendBuff, strlen(sendBuff)) != strlen(sendBuff)) { + printf("ERROR SSL write: %d\n", wolfSSL_get_error(ssl, 0)); + return; + } + + if ((ret=wolfSSL_read(ssl, rcvBuff, BUFF_SIZE)) < 0) { + printf("ERROR SSL read: %d\n", wolfSSL_get_error(ssl, 0)); + return; + } + + rcvBuff[ret] = '\0' ; + printf("Received: %s\n\n", rcvBuff); + + /* frees all data before client termination */ + wolfSSL_free(ssl); + wolfSSL_CTX_free(ctx); + wolfSSL_Cleanup(); + + tcp_sht_cep(cepid); + tcp_cls_cep(cepid, TMO_FEVR); + + return; +} diff --git a/IDE/Renesas/e2studio/RX72NEnvisionKit/test/src/wolf_server.c b/IDE/Renesas/e2studio/RX72NEnvisionKit/test/src/wolf_server.c new file mode 100644 index 0000000000..5d38b03588 --- /dev/null +++ b/IDE/Renesas/e2studio/RX72NEnvisionKit/test/src/wolf_server.c @@ -0,0 +1,203 @@ +/* wolf_server.c + * + * Copyright (C) 2006-2020 wolfSSL Inc. + * + * This file is part of wolfSSL. + * + * wolfSSL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * wolfSSL is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + */ +#include +#include +#include "r_t4_itcpip.h" + +#include "wolfssl/wolfcrypt/settings.h" +#include "wolfssl/ssl.h" +#include "wolfssl/certs_test.h" +#include "wolfssl_demo.h" + +static WOLFSSL_CTX *server_ctx; +static byte doCliCertCheck; + +static int my_IORecv(WOLFSSL* ssl, char* buff, int sz, void* ctx) +{ + int ret; + ID cepid; + + if(ctx != NULL) + cepid = *(ID *)ctx; + else + return WOLFSSL_CBIO_ERR_GENERAL; + + ret = tcp_rcv_dat(cepid, buff, sz, TMO_FEVR); + if(ret == sz) + return ret; + else + return WOLFSSL_CBIO_ERR_GENERAL; +} + +static int my_IOSend(WOLFSSL* ssl, char* buff, int sz, void* ctx) +{ + int ret; + ID cepid; + + if(ctx != NULL) + cepid = *(ID *)ctx; + else + return WOLFSSL_CBIO_ERR_GENERAL; + + ret = tcp_snd_dat(cepid, buff, sz, TMO_FEVR); + if(ret == sz) + return ret; + else + return WOLFSSL_CBIO_ERR_GENERAL; +} + + +void wolfSSL_TLS_server_init(byte doClientCheck) +{ + + int ret; + + + #ifndef NO_FILESYSTEM + #ifdef USE_ECC_CERT + char *cert = "./certs/server-ecc-cert.pem"; + char *key = "./certs/server-ecc-key.pem"; + #else + char *cert = "./certs/server-cert.pem"; + char *key = "./certs/server-key.pem"; + #endif + char *clientCert = "./certs/client-cert.pem"; + #else + #ifdef USE_ECC_CERT + char *cert = serv_ecc_der_256; + int sizeof_cert = sizeof_serv_ecc_der_256; + char *cert = serv_ecc_key_der_256; + int sizeof_key = sizeof_serv_ecc_key_der_256; + #else + const unsigned char *cert = server_cert_der_2048; + #define sizeof_cert sizeof_server_cert_der_2048 + const unsigned char *key = server_key_der_2048; + #define sizeof_key sizeof_server_key_der_2048 + const unsigned char *clientCert = client_cert_der_2048; + #define sizeof_clicert sizeof_client_cert_der_2048 + #endif + #endif + + + wolfSSL_Init(); + #ifdef DEBUG_WOLFSSL + wolfSSL_Debugging_ON(); + #endif + + /* Create and initialize WOLFSSL_CTX */ + if ((server_ctx = wolfSSL_CTX_new(wolfSSLv23_server_method_ex((void *)NULL))) + == NULL) { + printf("ERROR: failed to create WOLFSSL_CTX\n"); + return; + } + + #if !defined(NO_FILESYSTEM) + ret = wolfSSL_CTX_use_certificate_file(server_ctx, cert, 0); + #else + ret = wolfSSL_CTX_use_certificate_buffer(server_ctx, cert, + sizeof_cert, SSL_FILETYPE_ASN1); + #endif + if (ret != SSL_SUCCESS) { + printf("Error %d loading server-cert!\n", ret); + return; + } + + /* Load server key into WOLFSSL_CTX */ + #if !defined(NO_FILESYSTEM) + ret = wolfSSL_CTX_use_PrivateKey_file(server_ctx, key, 0); + #else + ret = wolfSSL_CTX_use_PrivateKey_buffer(server_ctx, key, sizeof_key, + SSL_FILETYPE_ASN1); + #endif + if (ret != SSL_SUCCESS) { + printf("Error %d loading server-key!\n", ret); + return; + } +#if defined(WOLFSSL_RENESAS_TSIP) + doCliCertCheck = 1; +#endif + if (doCliCertCheck) { + wolfSSL_CTX_set_verify(server_ctx, WOLFSSL_VERIFY_PEER | + WOLFSSL_VERIFY_FAIL_IF_NO_PEER_CERT, 0); +#if !defined(NO_FILESYSTEM) + if (wolfSSL_CTX_load_verify_locations(server_ctx, clientCert, 0) + != WOLFSSL_SUCCESS) +#else + if (wolfSSL_CTX_load_verify_buffer(server_ctx, clientCert, + sizeof_clicert, + SSL_FILETYPE_ASN1) != SSL_SUCCESS) +#endif + printf("can't load ca file, Please run from wolfSSL home dir\n"); + } + + /* Register callbacks */ + wolfSSL_SetIORecv(server_ctx, my_IORecv); + wolfSSL_SetIOSend(server_ctx, my_IOSend); + +} + +void wolfSSL_TLS_server( ) +{ + ID cepid = 1; + ID repid = 1; + ER ercd; + WOLFSSL_CTX *ctx = (WOLFSSL_CTX *)server_ctx; + + WOLFSSL *ssl; + int len; + #define BUFF_SIZE 256 + char buff[BUFF_SIZE]; + T_IPV4EP dst_addr = {0, 0}; + + if((ercd = tcp_acp_cep(cepid, repid, &dst_addr, TMO_FEVR)) != E_OK) { + printf("ERROR TCP Accept: %d\n", ercd); + return; + } + + if((ssl = wolfSSL_new(ctx)) == NULL) { + printf("ERROR: failed wolfSSL_new\n"); + return; + } + + wolfSSL_SetIOReadCtx(ssl, (void *)&cepid); + wolfSSL_SetIOWriteCtx(ssl, (void *)&cepid); + + if (wolfSSL_accept(ssl) < 0) { + printf("ERROR: SSL Accept(%d)\n", wolfSSL_get_error(ssl, 0)); + return; + } + + if ((len = wolfSSL_read(ssl, buff, sizeof(buff) - 1)) < 0) { + printf("ERROR: SSL Read(%d)\n", wolfSSL_get_error(ssl, 0)); + return; + } + + buff[len] = '\0'; + printf("Received: %s\n", buff); + + if (wolfSSL_write(ssl, buff, len) != len) { + printf("ERROR: SSL Write(%d)\n", wolfSSL_get_error(ssl, 0)); + return; + } + + wolfSSL_free(ssl); + tcp_sht_cep(cepid); +} diff --git a/IDE/Renesas/e2studio/RX72NEnvisionKit/test/src/wolfssl_demo.h b/IDE/Renesas/e2studio/RX72NEnvisionKit/test/src/wolfssl_demo.h new file mode 100644 index 0000000000..b2a2722452 --- /dev/null +++ b/IDE/Renesas/e2studio/RX72NEnvisionKit/test/src/wolfssl_demo.h @@ -0,0 +1,48 @@ +/* wolfssl_demo.h + * + * Copyright (C) 2006-2020 wolfSSL Inc. + * + * This file is part of wolfSSL. + * + * wolfSSL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * wolfSSL is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + */ + +#ifndef WOLFSSL_DEMO_H_ +#define WOLFSSL_DEMO_H_ + +#define FREQ 10000 /* Hz */ + +/* Enable wolfcrypt test */ +/* can be enabled with benchmark test */ +/* #define CRYPT_TEST */ + +/* Enable benchmark */ +/* can be enabled with cyrpt test */ +/* #define BENCHMARK*/ + +/* Enable TLS client */ +/* cannot enable with other definition */ +/* #define TLS_CLIENT*/ + +/* Enable TLS server */ +/* cannot enable with other definition */ +/* #define TLS_SERVER */ + +void wolfSSL_TLS_client_init(); +void wolfSSL_TLS_client(); +void wolfSSL_TLS_server_init(); +void wolfSSL_TLS_server(); + +#endif /* WOLFSSL_DEMO_H_ */ diff --git a/IDE/Renesas/e2studio/RX72NEnvisionKit/test/test_HardwareDebug.launch b/IDE/Renesas/e2studio/RX72NEnvisionKit/test/test_HardwareDebug.launch new file mode 100644 index 0000000000..e4db5e81b6 --- /dev/null +++ b/IDE/Renesas/e2studio/RX72NEnvisionKit/test/test_HardwareDebug.launch @@ -0,0 +1,167 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/IDE/Renesas/e2studio/RX72NEnvisionKit/wolfssl/.cproject b/IDE/Renesas/e2studio/RX72NEnvisionKit/wolfssl/.cproject new file mode 100644 index 0000000000..d93a048063 --- /dev/null +++ b/IDE/Renesas/e2studio/RX72NEnvisionKit/wolfssl/.cproject @@ -0,0 +1,104 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/IDE/Renesas/e2studio/RX72NEnvisionKit/wolfssl/.project b/IDE/Renesas/e2studio/RX72NEnvisionKit/wolfssl/.project new file mode 100644 index 0000000000..46ee100915 --- /dev/null +++ b/IDE/Renesas/e2studio/RX72NEnvisionKit/wolfssl/.project @@ -0,0 +1,393 @@ + + + wolfssl + + + + + + org.eclipse.cdt.managedbuilder.core.genmakebuilder + clean,full,incremental, + + + + + org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder + full,incremental, + + + + + + org.eclipse.cdt.core.cnature + org.eclipse.cdt.managedbuilder.core.managedBuildNature + org.eclipse.cdt.managedbuilder.core.ScannerConfigNature + + + + src/crl.c + 1 + PARENT-5-PROJECT_LOC/src/crl.c + + + src/internal.c + 1 + PARENT-5-PROJECT_LOC/src/internal.c + + + src/keys.c + 1 + PARENT-5-PROJECT_LOC/src/keys.c + + + src/ocsp.c + 1 + PARENT-5-PROJECT_LOC/src/ocsp.c + + + src/sniffer.c + 1 + PARENT-5-PROJECT_LOC/src/sniffer.c + + + src/ssl.c + 1 + PARENT-5-PROJECT_LOC/src/ssl.c + + + src/tls.c + 1 + PARENT-5-PROJECT_LOC/src/tls.c + + + src/tls13.c + 1 + PARENT-5-PROJECT_LOC/src/tls13.c + + + src/wolfio.c + 1 + PARENT-5-PROJECT_LOC/src/wolfio.c + + + wolfcrypt/port/renesas_tsip_aes.c + 1 + PARENT-5-PROJECT_LOC/wolfcrypt/src/port/Renesas/renesas_tsip_aes.c + + + wolfcrypt/port/renesas_tsip_sha.c + 1 + PARENT-5-PROJECT_LOC/wolfcrypt/src/port/Renesas/renesas_tsip_sha.c + + + wolfcrypt/port/renesas_tsip_util.c + 1 + PARENT-5-PROJECT_LOC/wolfcrypt/src/port/Renesas/renesas_tsip_util.c + + + wolfcrypt/src/aes.c + 1 + PARENT-5-PROJECT_LOC/wolfcrypt/src/aes.c + + + wolfcrypt/src/arc4.c + 1 + PARENT-5-PROJECT_LOC/wolfcrypt/src/arc4.c + + + wolfcrypt/src/asm.c + 1 + PARENT-5-PROJECT_LOC/wolfcrypt/src/asm.c + + + wolfcrypt/src/asn.c + 1 + PARENT-5-PROJECT_LOC/wolfcrypt/src/asn.c + + + wolfcrypt/src/blake2b.c + 1 + PARENT-5-PROJECT_LOC/wolfcrypt/src/blake2b.c + + + wolfcrypt/src/camellia.c + 1 + PARENT-5-PROJECT_LOC/wolfcrypt/src/camellia.c + + + wolfcrypt/src/chacha.c + 1 + PARENT-5-PROJECT_LOC/wolfcrypt/src/chacha.c + + + wolfcrypt/src/chacha20_poly1305.c + 1 + PARENT-5-PROJECT_LOC/wolfcrypt/src/chacha20_poly1305.c + + + wolfcrypt/src/cmac.c + 1 + PARENT-5-PROJECT_LOC/wolfcrypt/src/cmac.c + + + wolfcrypt/src/coding.c + 1 + PARENT-5-PROJECT_LOC/wolfcrypt/src/coding.c + + + wolfcrypt/src/compress.c + 1 + PARENT-5-PROJECT_LOC/wolfcrypt/src/compress.c + + + wolfcrypt/src/cpuid.c + 1 + PARENT-5-PROJECT_LOC/wolfcrypt/src/cpuid.c + + + wolfcrypt/src/cryptocb.c + 1 + PARENT-5-PROJECT_LOC/wolfcrypt/src/cryptocb.c + + + wolfcrypt/src/curve25519.c + 1 + PARENT-5-PROJECT_LOC/wolfcrypt/src/curve25519.c + + + wolfcrypt/src/des3.c + 1 + PARENT-5-PROJECT_LOC/wolfcrypt/src/des3.c + + + wolfcrypt/src/dh.c + 1 + PARENT-5-PROJECT_LOC/wolfcrypt/src/dh.c + + + wolfcrypt/src/dsa.c + 1 + PARENT-5-PROJECT_LOC/wolfcrypt/src/dsa.c + + + wolfcrypt/src/ecc.c + 1 + PARENT-5-PROJECT_LOC/wolfcrypt/src/ecc.c + + + wolfcrypt/src/ecc_fp.c + 1 + PARENT-5-PROJECT_LOC/wolfcrypt/src/ecc_fp.c + + + wolfcrypt/src/ed25519.c + 1 + PARENT-5-PROJECT_LOC/wolfcrypt/src/ed25519.c + + + wolfcrypt/src/error.c + 1 + PARENT-5-PROJECT_LOC/wolfcrypt/src/error.c + + + wolfcrypt/src/fe_low_mem.c + 1 + PARENT-5-PROJECT_LOC/wolfcrypt/src/fe_low_mem.c + + + wolfcrypt/src/fe_operations.c + 1 + PARENT-5-PROJECT_LOC/wolfcrypt/src/fe_operations.c + + + wolfcrypt/src/ge_low_mem.c + 1 + PARENT-5-PROJECT_LOC/wolfcrypt/src/ge_low_mem.c + + + wolfcrypt/src/ge_operations.c + 1 + PARENT-5-PROJECT_LOC/wolfcrypt/src/ge_operations.c + + + wolfcrypt/src/hash.c + 1 + PARENT-5-PROJECT_LOC/wolfcrypt/src/hash.c + + + wolfcrypt/src/hc128.c + 1 + PARENT-5-PROJECT_LOC/wolfcrypt/src/hc128.c + + + wolfcrypt/src/hmac.c + 1 + PARENT-5-PROJECT_LOC/wolfcrypt/src/hmac.c + + + wolfcrypt/src/idea.c + 1 + PARENT-5-PROJECT_LOC/wolfcrypt/src/idea.c + + + wolfcrypt/src/include.am + 1 + PARENT-5-PROJECT_LOC/wolfcrypt/src/include.am + + + wolfcrypt/src/integer.c + 1 + PARENT-5-PROJECT_LOC/wolfcrypt/src/integer.c + + + wolfcrypt/src/logging.c + 1 + PARENT-5-PROJECT_LOC/wolfcrypt/src/logging.c + + + wolfcrypt/src/md2.c + 1 + PARENT-5-PROJECT_LOC/wolfcrypt/src/md2.c + + + wolfcrypt/src/md4.c + 1 + PARENT-5-PROJECT_LOC/wolfcrypt/src/md4.c + + + wolfcrypt/src/md5.c + 1 + PARENT-5-PROJECT_LOC/wolfcrypt/src/md5.c + + + wolfcrypt/src/memory.c + 1 + PARENT-5-PROJECT_LOC/wolfcrypt/src/memory.c + + + wolfcrypt/src/pkcs12.c + 1 + PARENT-5-PROJECT_LOC/wolfcrypt/src/pkcs12.c + + + wolfcrypt/src/pkcs7.c + 1 + PARENT-5-PROJECT_LOC/wolfcrypt/src/pkcs7.c + + + wolfcrypt/src/poly1305.c + 1 + PARENT-5-PROJECT_LOC/wolfcrypt/src/poly1305.c + + + wolfcrypt/src/pwdbased.c + 1 + PARENT-5-PROJECT_LOC/wolfcrypt/src/pwdbased.c + + + wolfcrypt/src/rabbit.c + 1 + PARENT-5-PROJECT_LOC/wolfcrypt/src/rabbit.c + + + wolfcrypt/src/random.c + 1 + PARENT-5-PROJECT_LOC/wolfcrypt/src/random.c + + + wolfcrypt/src/ripemd.c + 1 + PARENT-5-PROJECT_LOC/wolfcrypt/src/ripemd.c + + + wolfcrypt/src/rsa.c + 1 + PARENT-5-PROJECT_LOC/wolfcrypt/src/rsa.c + + + wolfcrypt/src/sha.c + 1 + PARENT-5-PROJECT_LOC/wolfcrypt/src/sha.c + + + wolfcrypt/src/sha256.c + 1 + PARENT-5-PROJECT_LOC/wolfcrypt/src/sha256.c + + + wolfcrypt/src/sha3.c + 1 + PARENT-5-PROJECT_LOC/wolfcrypt/src/sha3.c + + + wolfcrypt/src/sha512.c + 1 + PARENT-5-PROJECT_LOC/wolfcrypt/src/sha512.c + + + wolfcrypt/src/signature.c + 1 + PARENT-5-PROJECT_LOC/wolfcrypt/src/signature.c + + + wolfcrypt/src/sp_arm32.c + 1 + PARENT-5-PROJECT_LOC/wolfcrypt/src/sp_arm32.c + + + wolfcrypt/src/sp_arm64.c + 1 + PARENT-5-PROJECT_LOC/wolfcrypt/src/sp_arm64.c + + + wolfcrypt/src/sp_c32.c + 1 + PARENT-5-PROJECT_LOC/wolfcrypt/src/sp_c32.c + + + wolfcrypt/src/sp_c64.c + 1 + PARENT-5-PROJECT_LOC/wolfcrypt/src/sp_c64.c + + + wolfcrypt/src/sp_int.c + 1 + PARENT-5-PROJECT_LOC/wolfcrypt/src/sp_int.c + + + wolfcrypt/src/sp_x86_64.c + 1 + PARENT-5-PROJECT_LOC/wolfcrypt/src/sp_x86_64.c + + + wolfcrypt/src/srp.c + 1 + PARENT-5-PROJECT_LOC/wolfcrypt/src/srp.c + + + wolfcrypt/src/tfm.c + 1 + PARENT-5-PROJECT_LOC/wolfcrypt/src/tfm.c + + + wolfcrypt/src/wc_encrypt.c + 1 + PARENT-5-PROJECT_LOC/wolfcrypt/src/wc_encrypt.c + + + wolfcrypt/src/wc_port.c + 1 + PARENT-5-PROJECT_LOC/wolfcrypt/src/wc_port.c + + + wolfcrypt/src/wolfevent.c + 1 + PARENT-5-PROJECT_LOC/wolfcrypt/src/wolfevent.c + + + wolfcrypt/src/wolfmath.c + 1 + PARENT-5-PROJECT_LOC/wolfcrypt/src/wolfmath.c + + + From ddad95d52cc5c3bea8a192ed38efdf9054c54f82 Mon Sep 17 00:00:00 2001 From: Sean Parkinson Date: Tue, 14 Jul 2020 09:11:24 +1000 Subject: [PATCH 09/60] mp_sub_d (integer.c): return error when digit is too big Code can't handle subtracting a number (an mp_digit) larger than DIGIT_BIT. Now returns an error rather than giving wrong result. --- src/ssl.c | 2 +- wolfcrypt/src/integer.c | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/ssl.c b/src/ssl.c index 6ea012544d..2d5077255e 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -41804,7 +41804,7 @@ int wolfSSL_X509_NAME_print_ex(WOLFSSL_BIO* bio, WOLFSSL_X509_NAME* name, if (i < count - 1) { /* tmpSz+1 for last null char */ XSNPRINTF(tmp, tmpSz+1, "%s=%s,", buf, str->data); - XSTRNCAT(fullName, tmp, tmpSz); + XSTRNCAT(fullName, tmp, tmpSz+1); } else { XSNPRINTF(tmp, tmpSz, "%s=%s", buf, str->data); diff --git a/wolfcrypt/src/integer.c b/wolfcrypt/src/integer.c index 56d684b464..e819c3f8ee 100644 --- a/wolfcrypt/src/integer.c +++ b/wolfcrypt/src/integer.c @@ -4324,6 +4324,8 @@ int mp_sub_d (mp_int * a, mp_digit b, mp_int * c) mp_digit *tmpa, *tmpc, mu; int res, ix, oldused; + if (b > MP_MASK) return MP_VAL; + /* grow c as required */ if (c->alloc < a->used + 1) { if ((res = mp_grow(c, a->used + 1)) != MP_OKAY) { From eb7a01342f5d359d2e6b04f7756525bb940558eb Mon Sep 17 00:00:00 2001 From: Sean Parkinson Date: Thu, 16 Jul 2020 09:39:42 +1000 Subject: [PATCH 10/60] fp_set_bit: return error when bit offset is too large If the bit to set is beyond the predefined maximum size then return an error. Same for fp_is_bit_set(). --- wolfcrypt/src/tfm.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/wolfcrypt/src/tfm.c b/wolfcrypt/src/tfm.c index 82569d3af0..6cbd8262d7 100644 --- a/wolfcrypt/src/tfm.c +++ b/wolfcrypt/src/tfm.c @@ -3311,9 +3311,9 @@ int fp_is_bit_set (fp_int *a, fp_digit b) fp_digit i; if (b > FP_MAX_BITS) - return 0; - else - i = b/DIGIT_BIT; + return FP_VAL; + + i = b/DIGIT_BIT; if ((fp_digit)a->used < i) return 0; @@ -3327,9 +3327,9 @@ int fp_set_bit (fp_int * a, fp_digit b) fp_digit i; if (b > FP_MAX_BITS) - return 0; - else - i = b/DIGIT_BIT; + return FP_VAL; + + i = b/DIGIT_BIT; /* set the used count of where the bit will go if required */ if (a->used < (int)(i+1)) From cd025d4e03fb66f73df8af02f9bac3b14c08fb9f Mon Sep 17 00:00:00 2001 From: TakayukiMatsuo Date: Fri, 17 Jul 2020 09:30:40 +0900 Subject: [PATCH 11/60] Added RX72NEnvisionkit/include.am --- IDE/include.am | 1 + 1 file changed, 1 insertion(+) diff --git a/IDE/include.am b/IDE/include.am index 1372979ff2..0fcc8642a9 100644 --- a/IDE/include.am +++ b/IDE/include.am @@ -26,6 +26,7 @@ include IDE/Renesas/cs+/Projects/include.am include IDE/Renesas/e2studio/Projects/include.am include IDE/Renesas/e2studio/RA6M3/include.am include IDE/Renesas/e2studio/GR-ROSE/include.am +include IDE/Renesas/e2studio/RX72NEnvisionKit/include.am include IDE/WICED-STUDIO/include.am include IDE/CRYPTOCELL/include.am include IDE/M68K/include.am From 547144bc9ca7f5559efded810fa1414ee9f16ba6 Mon Sep 17 00:00:00 2001 From: David Garske Date: Thu, 16 Jul 2020 16:06:22 -0700 Subject: [PATCH 12/60] Adds ECC non-blocking sign/verify support when used with SP math. New `--enable-sp=nonblock` and `--enable-ecc=nonblock` options. Example `./configure --enable-ecc=nonblock --enable-sp=yes,nonblock`. --- configure.ac | 40 +- wolfcrypt/src/ecc.c | 208 ++-- wolfcrypt/src/sp_arm32.c | 1400 +++++++++++++++++++++++ wolfcrypt/src/sp_arm64.c | 1400 +++++++++++++++++++++++ wolfcrypt/src/sp_armthumb.c | 1400 +++++++++++++++++++++++ wolfcrypt/src/sp_c32.c | 1628 ++++++++++++++++++++++++++ wolfcrypt/src/sp_c64.c | 1628 ++++++++++++++++++++++++++ wolfcrypt/src/sp_cortexm.c | 1400 +++++++++++++++++++++++ wolfcrypt/src/sp_int.c | 12 +- wolfcrypt/src/sp_x86_64.c | 2156 +++++++++++++++++++++++++++++++++++ wolfssl/wolfcrypt/ecc.h | 25 + wolfssl/wolfcrypt/sp.h | 13 +- wolfssl/wolfcrypt/sp_int.h | 14 +- 13 files changed, 11216 insertions(+), 108 deletions(-) diff --git a/configure.ac b/configure.ac index 6e1dce91c4..7315827a7b 100644 --- a/configure.ac +++ b/configure.ac @@ -1545,13 +1545,18 @@ then ENABLED_ECC="yes" fi -if test "$ENABLED_ECC" = "yes" +if test "$ENABLED_ECC" != "no" then AM_CFLAGS="$AM_CFLAGS -DHAVE_ECC -DTFM_ECC256" if test "$ENABLED_ECC_SHAMIR" = "yes" && test "$ENABLED_LOWRESOURCE" = "no" then AM_CFLAGS="$AM_CFLAGS -DECC_SHAMIR" fi + + if test "$ENABLED_ECC" = "nonblock" + then + AM_CFLAGS="$AM_CFLAGS -DWC_ECC_NONBLOCK" + fi fi @@ -3206,7 +3211,7 @@ then ENABLED_ENCRYPT_THEN_MAC=yes AM_CFLAGS="$AM_CFLAGS -DHAVE_TLS_EXTENSIONS -DHAVE_SNI -DHAVE_MAX_FRAGMENT -DHAVE_TRUNCATED_HMAC -DHAVE_ALPN -DHAVE_TRUSTED_CA" # Check the ECC supported curves prereq - AS_IF([test "x$ENABLED_ECC" = "xyes" || test "x$ENABLED_CURVE25519" = "xyes" || test "x$ENABLED_TLS13" = "xyes"], + AS_IF([test "x$ENABLED_ECC" != "xno" || test "x$ENABLED_CURVE25519" = "xyes" || test "x$ENABLED_TLS13" = "xyes"], [ENABLED_SUPPORTED_CURVES=yes AM_CFLAGS="$AM_CFLAGS -DHAVE_SUPPORTED_CURVES"]) fi @@ -3762,7 +3767,7 @@ then AM_CFLAGS="$AM_CFLAGS -DHAVE_TLS_EXTENSIONS -DHAVE_SNI -DHAVE_MAX_FRAGMENT -DHAVE_TRUNCATED_HMAC" # Check the ECC supported curves prereq - AS_IF([test "x$ENABLED_ECC" = "xyes" || test "x$ENABLED_CURVE25519" = "xyes"], + AS_IF([test "x$ENABLED_ECC" != "xno" || test "x$ENABLED_CURVE25519" = "xyes"], [ENABLED_SUPPORTED_CURVES=yes AM_CFLAGS="$AM_CFLAGS -DHAVE_SUPPORTED_CURVES"]) fi @@ -3905,7 +3910,7 @@ then AC_MSG_ERROR([please enable psk if disabling asn.]) fi - if test "x$ENABLED_ECC" = "xyes" && test "x$ENABLED_ASN" = "xno" + if test "x$ENABLED_ECC" != "xno" && test "x$ENABLED_ASN" = "xno" then AC_MSG_ERROR([please disable ecc if disabling asn.]) fi @@ -4251,6 +4256,7 @@ ENABLED_SP_ECC=no ENABLED_SP_EC_256=no ENABLED_SP_EC_384=no ENABLED_SP_NO_MALLOC=no +ENABLED_SP_NONBLOCK=no for v in `echo $ENABLED_SP | tr "," " "` do case $v in @@ -4267,6 +4273,7 @@ do ENABLED_SP_EC_384=yes fi ;; + yes) ENABLED_SP_RSA=yes ENABLED_SP_DH=yes @@ -4279,6 +4286,7 @@ do ENABLED_SP_EC_384=yes fi ;; + no) ;; @@ -4312,7 +4320,6 @@ do ENABLED_SP_DH=yes ENABLED_SP_FF_2048=yes ;; - smallrsa2048) ENABLED_SP_SMALL=yes ENABLED_SP_RSA=yes @@ -4334,7 +4341,6 @@ do ENABLED_SP_DH=yes ENABLED_SP_FF_3072=yes ;; - smallrsa3072) ENABLED_SP_SMALL=yes ENABLED_SP_RSA=yes @@ -4351,19 +4357,16 @@ do ENABLED_SP_DH=yes ENABLED_SP_FF_4096=yes ;; - 4096 | +4096) ENABLED_SP_RSA=yes ENABLED_SP_DH=yes ENABLED_SP_FF_4096=yes ;; - smallrsa4096) ENABLED_SP_SMALL=yes ENABLED_SP_RSA=yes ENABLED_SP_FF_4096=yes ;; - rsa4096) ENABLED_SP_RSA=yes ENABLED_SP_FF_4096=yes @@ -4373,6 +4376,13 @@ do ENABLED_SP_NO_MALLOC=yes ;; + nonblock) + # Requires small and no malloc + ENABLED_SP_NONBLOCK=yes + ENABLED_SP_NO_MALLOC=yes + ENABLED_SP_SMALL=yes + ;; + *) AC_MSG_ERROR([Invalid choice of Single Precision length in bits [256, 2048, 3072]: $ENABLED_SP.]) break;; @@ -4404,7 +4414,7 @@ if test "$ENABLED_SP_RSA" = "yes" || test "$ENABLED_SP_DH" = "yes"; then AM_CCASFLAGS="$AM_CCASFLAGS -DWOLFSSL_SP_4096" fi fi -if test "$ENABLED_ECC" = "yes" && test "$ENABLED_SP_ECC" = "yes"; then +if test "$ENABLED_ECC" != "no" && test "$ENABLED_SP_ECC" = "yes"; then ENABLED_SP=yes AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_HAVE_SP_ECC" AM_CCASFLAGS="$AM_CCASFLAGS -DWOLFSSL_HAVE_SP_ECC" @@ -4425,6 +4435,10 @@ if test "$ENABLED_SP_NO_MALLOC" = "yes"; then AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_SP_NO_MALLOC" AM_CCASFLAGS="$AM_CCASFLAGS -DWOLFSSL_SP_NO_MALLOC" fi +if test "$ENABLED_SP_NONBLOCK" = "yes"; then + AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_SP_NONBLOCK" + AM_CCASFLAGS="$AM_CCASFLAGS -DWOLFSSL_SP_NONBLOCK" +fi AC_ARG_ENABLE([sp-asm], @@ -4908,7 +4922,7 @@ AS_CASE(["$CFLAGS $CPPFLAGS"],[*'WOLFSSL_TRUST_PEER_CERT'*],[ENABLED_TRUSTED_PEE # dertermine if we have key validation mechanism -if test "x$ENABLED_ECC" = "xyes" || test "x$ENABLED_RSA" = "xyes" +if test "x$ENABLED_ECC" != "xno" || test "x$ENABLED_RSA" = "xyes" then if test "x$ENABLED_ASN" = "xyes" then @@ -5046,7 +5060,7 @@ then ENABLED_AESKEYWRAP="yes" AM_CFLAGS="$AM_CFLAGS -DHAVE_AES_KEYWRAP -DWOLFSSL_AES_DIRECT" fi - if test "x$ENABLED_X963KDF" = "xno" && test "$ENABLED_ECC" = "yes" + if test "x$ENABLED_X963KDF" = "xno" && test "$ENABLED_ECC" != "no" then ENABLED_X963KDF="yes" AM_CFLAGS="$AM_CFLAGS -DHAVE_X963_KDF" @@ -5218,7 +5232,7 @@ AM_CONDITIONAL([BUILD_BLAKE2],[test "x$ENABLED_BLAKE2" = "xyes" || test "x$ENABL AM_CONDITIONAL([BUILD_BLAKE2S],[test "x$ENABLED_BLAKE2S" = "xyes" || test "x$ENABLED_USERSETTINGS" = "xyes"]) AM_CONDITIONAL([BUILD_SHA512],[test "x$ENABLED_SHA512" = "xyes" || test "x$ENABLED_SHA384" = "xyes" || test "x$ENABLED_USERSETTINGS" = "xyes"]) AM_CONDITIONAL([BUILD_DSA],[test "x$ENABLED_DSA" = "xyes" || test "x$ENABLED_USERSETTINGS" = "xyes"]) -AM_CONDITIONAL([BUILD_ECC],[test "x$ENABLED_ECC" = "xyes" || test "x$ENABLED_USERSETTINGS" = "xyes"]) +AM_CONDITIONAL([BUILD_ECC],[test "x$ENABLED_ECC" != "xno" || test "x$ENABLED_USERSETTINGS" = "xyes"]) AM_CONDITIONAL([BUILD_ED25519],[test "x$ENABLED_ED25519" = "xyes" || test "x$ENABLED_USERSETTINGS" = "xyes"]) AM_CONDITIONAL([BUILD_ED25519_SMALL],[test "x$ENABLED_ED25519_SMALL" = "xyes"]) AM_CONDITIONAL([BUILD_FEMATH], [test "x$ENABLED_FEMATH" = "xyes" || test "x$ENABLED_USERSETTINGS" = "xyes"]) diff --git a/wolfcrypt/src/ecc.c b/wolfcrypt/src/ecc.c index f3f21c258a..58d57fb562 100644 --- a/wolfcrypt/src/ecc.c +++ b/wolfcrypt/src/ecc.c @@ -48,7 +48,7 @@ Possible ECC enable options: * WOLFSSL_CUSTOM_CURVES: Allow non-standard curves. default: off * Includes the curve "a" variable in calculation * ECC_DUMP_OID: Enables dump of OID encoding and sum default: off - * ECC_CACHE_CURVE: Enables cache of curve info to improve perofrmance + * ECC_CACHE_CURVE: Enables cache of curve info to improve performance default: off * FP_ECC: ECC Fixed Point Cache default: off * USE_ECC_B_PARAM: Enable ECC curve B param default: off @@ -56,6 +56,10 @@ Possible ECC enable options: * WOLFSSL_ECC_CURVE_STATIC: default off (on for windows) For the ECC curve paramaters `ecc_set_type` use fixed array for hex string + * WC_ECC_NONBLOCK: Enable non-blocking support for sign/verify. + Requires SP with WOLFSSL_SP_NONBLOCK + * WC_ECC_NONBLOCK_ONLY Enable the non-blocking function only, no fall-back to + normal blocking API's */ /* @@ -4891,60 +4895,54 @@ int wc_ecc_sign_hash_ex(const byte* in, word32 inlen, WC_RNG* rng, } #ifdef WOLFSSL_SP_MATH -#ifndef WOLFSSL_SP_NO_256 - if (key->idx != ECC_CUSTOM_IDX && ecc_sets[key->idx].id == ECC_SECP256R1) { - #ifndef WOLFSSL_ECDSA_SET_K - return sp_ecc_sign_256(in, inlen, rng, &key->k, r, s, NULL, key->heap); - #else - return sp_ecc_sign_256(in, inlen, rng, &key->k, r, s, key->sign_k, - key->heap); - #endif + if (key->idx == ECC_CUSTOM_IDX || + (ecc_sets[key->idx].id != ECC_SECP256R1 && + ecc_sets[key->idx].id != ECC_SECP384R1)) { + return WC_KEY_SIZE_E; } #endif -#ifdef WOLFSSL_SP_384 - if (key->idx != ECC_CUSTOM_IDX && ecc_sets[key->idx].id == ECC_SECP384R1) { - #ifndef WOLFSSL_ECDSA_SET_K - return sp_ecc_sign_384(in, inlen, rng, &key->k, r, s, NULL, key->heap); - #else - return sp_ecc_sign_384(in, inlen, rng, &key->k, r, s, key->sign_k, - key->heap); - #endif - } -#endif - return WC_KEY_SIZE_E; -#else -#ifdef WOLFSSL_HAVE_SP_ECC - #if defined(WOLFSSL_ASYNC_CRYPT) && defined(WC_ASYNC_ENABLE_ECC) - if (key->asyncDev.marker != WOLFSSL_ASYNC_MARKER_ECC) - #endif - { -#ifndef WOLFSSL_SP_NO_256 - if (key->idx != ECC_CUSTOM_IDX && - ecc_sets[key->idx].id == ECC_SECP256R1) { - #ifndef WOLFSSL_ECDSA_SET_K - return sp_ecc_sign_256(in, inlen, rng, &key->k, r, s, NULL, - key->heap); - #else - return sp_ecc_sign_256(in, inlen, rng, &key->k, r, s, key->sign_k, - key->heap); - #endif - } -#endif -#ifdef WOLFSSL_SP_384 - if (key->idx != ECC_CUSTOM_IDX && - ecc_sets[key->idx].id == ECC_SECP384R1) { - #ifndef WOLFSSL_ECDSA_SET_K - return sp_ecc_sign_384(in, inlen, rng, &key->k, r, s, NULL, - key->heap); - #else - return sp_ecc_sign_384(in, inlen, rng, &key->k, r, s, key->sign_k, - key->heap); - #endif - } -#endif - } -#endif /* WOLFSSL_HAVE_SP_ECC */ +#if defined(WOLFSSL_SP_MATH) || defined(WOLFSSL_HAVE_SP_ECC) + if (key->idx != ECC_CUSTOM_IDX + #if defined(WOLFSSL_ASYNC_CRYPT) && defined(WC_ASYNC_ENABLE_ECC) + && key->asyncDev.marker != WOLFSSL_ASYNC_MARKER_ECC + #endif + ) { + #ifdef WOLFSSL_ECDSA_SET_K + mp_int* sign_k = key->sign_k; + #else + mp_int* sign_k = NULL; + #endif + #ifndef WOLFSSL_SP_NO_256 + if (ecc_sets[key->idx].id == ECC_SECP256R1) { + #ifdef WC_ECC_NONBLOCK + if (key->nb_ctx) { + return sp_ecc_sign_256_nb(&key->nb_ctx->sp_ctx, in, inlen, rng, &key->k, r, s, sign_k, key->heap); + } + #endif + #ifndef WC_ECC_NONBLOCK_ONLY + return sp_ecc_sign_256(in, inlen, rng, &key->k, r, s, sign_k, key->heap); + #else + return NOT_COMPILED_IN; + #endif + } + #endif + #ifdef WOLFSSL_SP_384 + if (ecc_sets[key->idx].id == ECC_SECP384R1) { + #ifdef WC_ECC_NONBLOCK + if (key->nb_ctx) { + return sp_ecc_sign_384_nb(&key->nb_ctx->sp_ctx, in, inlen, rng, &key->k, r, s, sign_k, key->heap); + } + #endif + #ifndef WC_ECC_NONBLOCK_ONLY + return sp_ecc_sign_384(in, inlen, rng, &key->k, r, s, sign_k, key->heap); + #else + return NOT_COMPILED_IN; + #endif + } + #endif + } +#endif #if defined(WOLFSSL_ASYNC_CRYPT) && defined(WC_ASYNC_ENABLE_ECC) && \ defined(WOLFSSL_ASYNC_CRYPT_TEST) @@ -4962,6 +4960,9 @@ int wc_ecc_sign_hash_ex(const byte* in, word32 inlen, WC_RNG* rng, } #endif + +#ifndef WOLFSSL_SP_MATH + #if defined(WOLFSSL_ASYNC_CRYPT) && defined(HAVE_CAVIUM_V) err = wc_ecc_alloc_mpint(key, &key->e); if (err != 0) { @@ -5288,7 +5289,7 @@ int wc_ecc_sign_set_k(const byte* k, word32 klen, ecc_key* key) #endif /* WOLFSSL_ECDSA_SET_K */ #endif /* WOLFSSL_ATECC508A && WOLFSSL_CRYPTOCELL*/ -#endif /* HAVE_ECC_SIGN */ +#endif /* !HAVE_ECC_SIGN */ #ifdef WOLFSSL_CUSTOM_CURVES void wc_ecc_free_curve(const ecc_set_type* curve, void* heap) @@ -5992,44 +5993,57 @@ int wc_ecc_verify_hash_ex(mp_int *r, mp_int *s, const byte* hash, key->pubkey.z, r, s, res, key->heap); } #endif + #if defined(WOLFSSL_SP_MATH) && !defined(FREESCALE_LTC_ECC) -#ifndef WOLFSSL_SP_NO_256 - if (key->idx != ECC_CUSTOM_IDX && ecc_sets[key->idx].id == ECC_SECP256R1) { - return sp_ecc_verify_256(hash, hashlen, key->pubkey.x, key->pubkey.y, - key->pubkey.z, r, s, res, key->heap); - } -#endif -#ifdef WOLFSSL_SP_384 - if (key->idx != ECC_CUSTOM_IDX && ecc_sets[key->idx].id == ECC_SECP384R1) { - return sp_ecc_verify_384(hash, hashlen, key->pubkey.x, key->pubkey.y, - key->pubkey.z, r, s, res, key->heap); - } -#endif - return WC_KEY_SIZE_E; -#else -#if defined WOLFSSL_HAVE_SP_ECC && !defined(FREESCALE_LTC_ECC) - #if defined(WOLFSSL_ASYNC_CRYPT) && defined(WC_ASYNC_ENABLE_ECC) - if (key->asyncDev.marker != WOLFSSL_ASYNC_MARKER_ECC) - #endif - { -#ifndef WOLFSSL_SP_NO_256 - if (key->idx != ECC_CUSTOM_IDX && - ecc_sets[key->idx].id == ECC_SECP256R1) { - return sp_ecc_verify_256(hash, hashlen, key->pubkey.x, - key->pubkey.y, key->pubkey.z,r, s, res, - key->heap); - } -#endif /* WOLFSSL_SP_NO_256 */ -#ifdef WOLFSSL_SP_384 - if (key->idx != ECC_CUSTOM_IDX && - ecc_sets[key->idx].id == ECC_SECP384R1) { - return sp_ecc_verify_384(hash, hashlen, key->pubkey.x, - key->pubkey.y, key->pubkey.z,r, s, res, - key->heap); - } -#endif /* WOLFSSL_SP_384 */ + if (key->idx == ECC_CUSTOM_IDX || + (ecc_sets[key->idx].id != ECC_SECP256R1 && + ecc_sets[key->idx].id != ECC_SECP384R1)) { + return WC_KEY_SIZE_E; } -#endif /* WOLFSSL_HAVE_SP_ECC */ +#endif + +#if (defined(WOLFSSL_SP_MATH) || defined(WOLFSSL_HAVE_SP_ECC)) && !defined(FREESCALE_LTC_ECC) + if (key->idx != ECC_CUSTOM_IDX + #if defined(WOLFSSL_ASYNC_CRYPT) && defined(WC_ASYNC_ENABLE_ECC) + && key->asyncDev.marker != WOLFSSL_ASYNC_MARKER_ECC + #endif + ) { + #ifndef WOLFSSL_SP_NO_256 + if (ecc_sets[key->idx].id == ECC_SECP256R1) { + #ifdef WC_ECC_NONBLOCK + if (key->nb_ctx) { + return sp_ecc_verify_256_nb(&key->nb_ctx->sp_ctx, hash, hashlen, + key->pubkey.x, key->pubkey.y, key->pubkey.z, r, s, res, key->heap); + } + #endif + #ifndef WC_ECC_NONBLOCK_ONLY + return sp_ecc_verify_256(hash, hashlen, key->pubkey.x, + key->pubkey.y, key->pubkey.z, r, s, res, key->heap); + #else + return NOT_COMPILED_IN; + #endif + } + #endif + #ifdef WOLFSSL_SP_384 + if (ecc_sets[key->idx].id == ECC_SECP384R1) { + #ifdef WC_ECC_NONBLOCK + if (key->nb_ctx) { + return sp_ecc_verify_384_nb(&key->nb_ctx->sp_ctx, hash, hashlen, + key->pubkey.x, key->pubkey.y, key->pubkey.z, r, s, res, key->heap); + } + #endif + #ifndef WC_ECC_NONBLOCK_ONLY + return sp_ecc_verify_384(hash, hashlen, key->pubkey.x, + key->pubkey.y, key->pubkey.z, r, s, res, key->heap); + #else + return NOT_COMPILED_IN; + #endif + } + #endif + } +#endif + +#if !defined(WOLFSSL_SP_MATH) || defined(FREESCALE_LTC_ECC) ALLOC_CURVE_SPECS(ECC_CURVE_FIELD_COUNT); @@ -6287,7 +6301,7 @@ int wc_ecc_verify_hash_ex(mp_int *r, mp_int *s, const byte* hash, wc_ecc_curve_free(curve); FREE_CURVE_SPECS(); -#endif /* WOLFSSL_SP_MATH */ +#endif /* !WOLFSSL_SP_MATH || FREESCALE_LTC_ECC */ #endif /* WOLFSSL_ATECC508A */ (void)keySz; @@ -10816,4 +10830,18 @@ int wc_X963_KDF(enum wc_HashType type, const byte* secret, word32 secretSz, } #endif /* HAVE_X963_KDF */ +#ifdef WC_ECC_NONBLOCK +/* Enable ECC support for non-blocking operations */ +int wc_ecc_set_nonblock(ecc_key *key, ecc_nb_ctx_t* ctx) +{ + if (key) { + if (ctx) { + XMEMSET(ctx, 0, sizeof(ecc_nb_ctx_t)); + } + key->nb_ctx = ctx; + } + return 0; +} +#endif /* WC_ECC_NONBLOCK */ + #endif /* HAVE_ECC */ diff --git a/wolfcrypt/src/sp_arm32.c b/wolfcrypt/src/sp_arm32.c index c0743d619a..2ba17cbd1d 100644 --- a/wolfcrypt/src/sp_arm32.c +++ b/wolfcrypt/src/sp_arm32.c @@ -31332,6 +31332,141 @@ static void sp_256_div2_8(sp_digit* r, const sp_digit* a, const sp_digit* m) * p Point to double. * t Temporary ordinate data. */ +#ifdef WOLFSSL_SP_NONBLOCK +typedef struct sp_256_proj_point_dbl_8_ctx { + int state; + sp_digit* t1; + sp_digit* t2; + sp_digit* x; + sp_digit* y; + sp_digit* z; +} sp_256_proj_point_dbl_8_ctx; + +static int sp_256_proj_point_dbl_8_nb(sp_ecc_ctx_t* sp_ctx, sp_point_256* r, const sp_point_256* p, sp_digit* t) +{ + int err = FP_WOULDBLOCK; + sp_256_proj_point_dbl_8_ctx* ctx = (sp_256_proj_point_dbl_8_ctx*)sp_ctx->data; + + typedef char ctx_size_test[sizeof(sp_256_proj_point_dbl_8_ctx) >= sizeof(*sp_ctx) ? -1 : 1]; + (void)sizeof(ctx_size_test); + + switch (ctx->state) { + case 0: + ctx->t1 = t; + ctx->t2 = t + 2*8; + ctx->x = r->x; + ctx->y = r->y; + ctx->z = r->z; + + /* Put infinity into result. */ + if (r != p) { + r->infinity = p->infinity; + } + ctx->state = 1; + break; + case 1: + /* T1 = Z * Z */ + sp_256_mont_sqr_8(ctx->t1, p->z, p256_mod, p256_mp_mod); + ctx->state = 2; + break; + case 2: + /* Z = Y * Z */ + sp_256_mont_mul_8(ctx->z, p->y, p->z, p256_mod, p256_mp_mod); + ctx->state = 3; + break; + case 3: + /* Z = 2Z */ + sp_256_mont_dbl_8(ctx->z, ctx->z, p256_mod); + ctx->state = 4; + break; + case 4: + /* T2 = X - T1 */ + sp_256_mont_sub_8(ctx->t2, p->x, ctx->t1, p256_mod); + ctx->state = 5; + break; + case 5: + /* T1 = X + T1 */ + sp_256_mont_add_8(ctx->t1, p->x, ctx->t1, p256_mod); + ctx->state = 6; + break; + case 6: + /* T2 = T1 * T2 */ + sp_256_mont_mul_8(ctx->t2, ctx->t1, ctx->t2, p256_mod, p256_mp_mod); + ctx->state = 7; + break; + case 7: + /* T1 = 3T2 */ + sp_256_mont_tpl_8(ctx->t1, ctx->t2, p256_mod); + ctx->state = 8; + break; + case 8: + /* Y = 2Y */ + sp_256_mont_dbl_8(ctx->y, p->y, p256_mod); + ctx->state = 9; + break; + case 9: + /* Y = Y * Y */ + sp_256_mont_sqr_8(ctx->y, ctx->y, p256_mod, p256_mp_mod); + ctx->state = 10; + break; + case 10: + /* T2 = Y * Y */ + sp_256_mont_sqr_8(ctx->t2, ctx->y, p256_mod, p256_mp_mod); + ctx->state = 11; + break; + case 11: + /* T2 = T2/2 */ + sp_256_div2_8(ctx->t2, ctx->t2, p256_mod); + ctx->state = 12; + break; + case 12: + /* Y = Y * X */ + sp_256_mont_mul_8(ctx->y, ctx->y, p->x, p256_mod, p256_mp_mod); + ctx->state = 13; + break; + case 13: + /* X = T1 * T1 */ + sp_256_mont_sqr_8(ctx->x, ctx->t1, p256_mod, p256_mp_mod); + ctx->state = 14; + break; + case 14: + /* X = X - Y */ + sp_256_mont_sub_8(ctx->x, ctx->x, ctx->y, p256_mod); + ctx->state = 15; + break; + case 15: + /* X = X - Y */ + sp_256_mont_sub_8(ctx->x, ctx->x, ctx->y, p256_mod); + ctx->state = 16; + break; + case 16: + /* Y = Y - X */ + sp_256_mont_sub_8(ctx->y, ctx->y, ctx->x, p256_mod); + ctx->state = 17; + break; + case 17: + /* Y = Y * T1 */ + sp_256_mont_mul_8(ctx->y, ctx->y, ctx->t1, p256_mod, p256_mp_mod); + ctx->state = 18; + break; + case 18: + /* Y = Y - T2 */ + sp_256_mont_sub_8(ctx->y, ctx->y, ctx->t2, p256_mod); + ctx->state = 19; + /* fall-through */ + case 19: + err = MP_OKAY; + break; + } + + if (err == MP_OKAY && ctx->state != 19) { + err = FP_WOULDBLOCK; + } + + return err; +} +#endif /* WOLFSSL_SP_NONBLOCK */ + static void sp_256_proj_point_dbl_8(sp_point_256* r, const sp_point_256* p, sp_digit* t) { sp_digit* t1 = t; @@ -31504,6 +31639,209 @@ static int sp_256_cmp_equal_8(const sp_digit* a, const sp_digit* b) * q Second point to add. * t Temporary ordinate data. */ + +#ifdef WOLFSSL_SP_NONBLOCK +typedef struct sp_256_proj_point_add_8_ctx { + int state; + sp_256_proj_point_dbl_8_ctx dbl_ctx; + const sp_point_256* ap[2]; + sp_point_256* rp[2]; + sp_digit* t1; + sp_digit* t2; + sp_digit* t3; + sp_digit* t4; + sp_digit* t5; + sp_digit* x; + sp_digit* y; + sp_digit* z; +} sp_256_proj_point_add_8_ctx; + +static int sp_256_proj_point_add_8_nb(sp_ecc_ctx_t* sp_ctx, sp_point_256* r, + const sp_point_256* p, const sp_point_256* q, sp_digit* t) +{ + int err = FP_WOULDBLOCK; + sp_256_proj_point_add_8_ctx* ctx = (sp_256_proj_point_add_8_ctx*)sp_ctx->data; + + /* Ensure only the first point is the same as the result. */ + if (q == r) { + const sp_point_256* a = p; + p = q; + q = a; + } + + typedef char ctx_size_test[sizeof(sp_256_proj_point_add_8_ctx) >= sizeof(*sp_ctx) ? -1 : 1]; + (void)sizeof(ctx_size_test); + + switch (ctx->state) { + case 0: /* INIT */ + ctx->t1 = t; + ctx->t2 = t + 2*8; + ctx->t3 = t + 4*8; + ctx->t4 = t + 6*8; + ctx->t5 = t + 8*8; + + ctx->state = 1; + break; + case 1: + /* Check double */ + (void)sp_256_sub_8(ctx->t1, p256_mod, q->y); + sp_256_norm_8(ctx->t1); + if ((sp_256_cmp_equal_8(p->x, q->x) & sp_256_cmp_equal_8(p->z, q->z) & + (sp_256_cmp_equal_8(p->y, q->y) | sp_256_cmp_equal_8(p->y, ctx->t1))) != 0) + { + XMEMSET(&ctx->dbl_ctx, 0, sizeof(ctx->dbl_ctx)); + ctx->state = 2; + } + else { + ctx->state = 3; + } + break; + case 2: + err = sp_256_proj_point_dbl_8_nb((sp_ecc_ctx_t*)&ctx->dbl_ctx, r, p, t); + if (err == MP_OKAY) + ctx->state = 27; /* done */ + break; + case 3: + { + int i; + ctx->rp[0] = r; + + /*lint allow cast to different type of pointer*/ + ctx->rp[1] = (sp_point_256*)t; /*lint !e9087 !e740*/ + XMEMSET(ctx->rp[1], 0, sizeof(sp_point_256)); + ctx->x = ctx->rp[p->infinity | q->infinity]->x; + ctx->y = ctx->rp[p->infinity | q->infinity]->y; + ctx->z = ctx->rp[p->infinity | q->infinity]->z; + + ctx->ap[0] = p; + ctx->ap[1] = q; + for (i=0; i<8; i++) { + r->x[i] = ctx->ap[p->infinity]->x[i]; + } + for (i=0; i<8; i++) { + r->y[i] = ctx->ap[p->infinity]->y[i]; + } + for (i=0; i<8; i++) { + r->z[i] = ctx->ap[p->infinity]->z[i]; + } + r->infinity = ctx->ap[p->infinity]->infinity; + + ctx->state = 4; + break; + } + case 4: + /* U1 = X1*Z2^2 */ + sp_256_mont_sqr_8(ctx->t1, q->z, p256_mod, p256_mp_mod); + ctx->state = 5; + break; + case 5: + sp_256_mont_mul_8(ctx->t3, ctx->t1, q->z, p256_mod, p256_mp_mod); + ctx->state = 6; + break; + case 6: + sp_256_mont_mul_8(ctx->t1, ctx->t1, ctx->x, p256_mod, p256_mp_mod); + ctx->state = 7; + break; + case 7: + /* U2 = X2*Z1^2 */ + sp_256_mont_sqr_8(ctx->t2, ctx->z, p256_mod, p256_mp_mod); + ctx->state = 8; + break; + case 8: + sp_256_mont_mul_8(ctx->t4, ctx->t2, ctx->z, p256_mod, p256_mp_mod); + ctx->state = 9; + break; + case 9: + sp_256_mont_mul_8(ctx->t2, ctx->t2, q->x, p256_mod, p256_mp_mod); + ctx->state = 10; + break; + case 10: + /* S1 = Y1*Z2^3 */ + sp_256_mont_mul_8(ctx->t3, ctx->t3, ctx->y, p256_mod, p256_mp_mod); + ctx->state = 11; + break; + case 11: + /* S2 = Y2*Z1^3 */ + sp_256_mont_mul_8(ctx->t4, ctx->t4, q->y, p256_mod, p256_mp_mod); + ctx->state = 12; + break; + case 12: + /* H = U2 - U1 */ + sp_256_mont_sub_8(ctx->t2, ctx->t2, ctx->t1, p256_mod); + ctx->state = 13; + break; + case 13: + /* R = S2 - S1 */ + sp_256_mont_sub_8(ctx->t4, ctx->t4, ctx->t3, p256_mod); + ctx->state = 14; + break; + case 14: + /* Z3 = H*Z1*Z2 */ + sp_256_mont_mul_8(ctx->z, ctx->z, q->z, p256_mod, p256_mp_mod); + ctx->state = 15; + break; + case 15: + sp_256_mont_mul_8(ctx->z, ctx->z, ctx->t2, p256_mod, p256_mp_mod); + ctx->state = 16; + break; + case 16: + /* X3 = R^2 - H^3 - 2*U1*H^2 */ + sp_256_mont_sqr_8(ctx->x, ctx->t4, p256_mod, p256_mp_mod); + ctx->state = 17; + break; + case 17: + sp_256_mont_sqr_8(ctx->t5, ctx->t2, p256_mod, p256_mp_mod); + ctx->state = 18; + break; + case 18: + sp_256_mont_mul_8(ctx->y, ctx->t1, ctx->t5, p256_mod, p256_mp_mod); + ctx->state = 19; + break; + case 19: + sp_256_mont_mul_8(ctx->t5, ctx->t5, ctx->t2, p256_mod, p256_mp_mod); + ctx->state = 20; + break; + case 20: + sp_256_mont_sub_8(ctx->x, ctx->x, ctx->t5, p256_mod); + ctx->state = 21; + break; + case 21: + sp_256_mont_dbl_8(ctx->t1, ctx->y, p256_mod); + ctx->state = 22; + break; + case 22: + sp_256_mont_sub_8(ctx->x, ctx->x, ctx->t1, p256_mod); + ctx->state = 23; + break; + case 23: + /* Y3 = R*(U1*H^2 - X3) - S1*H^3 */ + sp_256_mont_sub_8(ctx->y, ctx->y, ctx->x, p256_mod); + ctx->state = 24; + break; + case 24: + sp_256_mont_mul_8(ctx->y, ctx->y, ctx->t4, p256_mod, p256_mp_mod); + ctx->state = 25; + break; + case 25: + sp_256_mont_mul_8(ctx->t5, ctx->t5, ctx->t3, p256_mod, p256_mp_mod); + ctx->state = 26; + break; + case 26: + sp_256_mont_sub_8(ctx->y, ctx->y, ctx->t5, p256_mod); + ctx->state = 27; + /* fall-through */ + case 27: + err = MP_OKAY; + break; + } + + if (err == MP_OKAY && ctx->state != 27) { + err = FP_WOULDBLOCK; + } + return err; +} +#endif /* WOLFSSL_SP_NONBLOCK */ + static void sp_256_proj_point_add_8(sp_point_256* r, const sp_point_256* p, const sp_point_256* q, sp_digit* t) { @@ -35706,6 +36044,46 @@ static void sp_256_mont_sqr_n_order_8(sp_digit* r, const sp_digit* a, int n) * a Number to invert. * td Temporary data. */ + +#ifdef WOLFSSL_SP_NONBLOCK +typedef struct sp_256_mont_inv_order_8_ctx { + int state; + int i; +} sp_256_mont_inv_order_8_ctx; +static int sp_256_mont_inv_order_8_nb(sp_ecc_ctx_t* sp_ctx, sp_digit* r, const sp_digit* a, + sp_digit* t) +{ + int err = FP_WOULDBLOCK; + sp_256_mont_inv_order_8_ctx* ctx = (sp_256_mont_inv_order_8_ctx*)sp_ctx; + + typedef char ctx_size_test[sizeof(sp_256_mont_inv_order_8_ctx) >= sizeof(*sp_ctx) ? -1 : 1]; + (void)sizeof(ctx_size_test); + + switch (ctx->state) { + case 0: + XMEMCPY(t, a, sizeof(sp_digit) * 8); + ctx->i = 254; + ctx->state = 1; + break; + case 1: + sp_256_mont_sqr_order_8(t, t); + if ((p256_order_minus_2[ctx->i / 32] & ((sp_int_digit)1 << (ctx->i % 32))) != 0) { + sp_256_mont_mul_order_8(t, t, a); + } + ctx->i--; + if (ctx->i == 0) { + ctx->state = 2; + } + break; + case 2: + XMEMCPY(r, t, sizeof(sp_digit) * 8U); + err = MP_OKAY; + break; + } + return err; +} +#endif /* WOLFSSL_SP_NONBLOCK */ + static void sp_256_mont_inv_order_8(sp_digit* r, const sp_digit* a, sp_digit* td) { @@ -35821,6 +36199,165 @@ static void sp_256_mont_inv_order_8(sp_digit* r, const sp_digit* a, * returns RNG failures, MEMORY_E when memory allocation fails and * MP_OKAY on success. */ +#ifdef WOLFSSL_SP_NONBLOCK +typedef struct sp_ecc_sign_256_ctx { + int state; + union { + sp_256_ecc_mulmod_8_ctx mulmod_ctx; + sp_256_mont_inv_order_8_ctx mont_inv_order_ctx; + }; + sp_digit e[2*8]; + sp_digit x[2*8]; + sp_digit k[2*8]; + sp_digit r[2*8]; + sp_digit tmp[3 * 2*8]; + sp_point_256 point; + sp_digit* s; + sp_digit* kInv; + int i; +} sp_ecc_sign_256_ctx; + +int sp_ecc_sign_256_nb(sp_ecc_ctx_t* sp_ctx, const byte* hash, word32 hashLen, WC_RNG* rng, mp_int* priv, + mp_int* rm, mp_int* sm, mp_int* km, void* heap) +{ + int err = FP_WOULDBLOCK; + sp_ecc_sign_256_ctx* ctx = (sp_ecc_sign_256_ctx*)sp_ctx->data; + + typedef char ctx_size_test[sizeof(sp_ecc_sign_256_ctx) >= sizeof(*sp_ctx) ? -1 : 1]; + (void)sizeof(ctx_size_test); + + (void)heap; + + switch (ctx->state) { + case 0: /* INIT */ + ctx->s = ctx->e; + ctx->kInv = ctx->k; + if (hashLen > 32U) { + hashLen = 32U; + } + + sp_256_from_bin(ctx->e, 8, hash, (int)hashLen); + + ctx->i = SP_ECC_MAX_SIG_GEN; + ctx->state = 1; + break; + case 1: /* GEN */ + sp_256_from_mp(ctx->x, 8, priv); + /* New random point. */ + if (km == NULL || mp_iszero(km)) { + err = sp_256_ecc_gen_k_8(rng, ctx->k); + } + else { + sp_256_from_mp(ctx->k, 8, km); + mp_zero(km); + } + XMEMSET(&ctx->mulmod_ctx, 0, sizeof(ctx->mulmod_ctx)); + ctx->state = 2; + break; + case 2: /* MULMOD */ + err = sp_256_ecc_mulmod_8_nb((sp_ecc_ctx_t*)&ctx->mulmod_ctx, + &ctx->point, &p256_base, ctx->k, 1, heap); + if (err == MP_OKAY) { + ctx->state = 3; + } + break; + case 3: /* MODORDER */ + { + int32_t c; + /* r = point->x mod order */ + XMEMCPY(ctx->r, ctx->point.x, sizeof(sp_digit) * 8U); + sp_256_norm_8(ctx->r); + c = sp_256_cmp_8(ctx->r, p256_order); + sp_256_cond_sub_8(ctx->r, ctx->r, p256_order, 0L - (sp_digit)(c >= 0)); + sp_256_norm_8(ctx->r); + ctx->state = 4; + break; + } + case 4: /* KMODORDER */ + /* Conv k to Montgomery form (mod order) */ + sp_256_mul_8(ctx->k, ctx->k, p256_norm_order); + err = sp_256_mod_8(ctx->k, ctx->k, p256_order); + if (err == MP_OKAY) { + sp_256_norm_8(ctx->k); + XMEMSET(&ctx->mont_inv_order_ctx, 0, sizeof(ctx->mont_inv_order_ctx)); + ctx->state = 5; + } + break; + case 5: /* KINV */ + /* kInv = 1/k mod order */ + err = sp_256_mont_inv_order_8_nb((sp_ecc_ctx_t*)&ctx->mont_inv_order_ctx, ctx->kInv, ctx->k, ctx->tmp); + if (err == MP_OKAY) { + XMEMSET(&ctx->mont_inv_order_ctx, 0, sizeof(ctx->mont_inv_order_ctx)); + ctx->state = 6; + } + break; + case 6: /* KINVNORM */ + sp_256_norm_8(ctx->kInv); + ctx->state = 7; + break; + case 7: /* R */ + /* s = r * x + e */ + sp_256_mul_8(ctx->x, ctx->x, ctx->r); + ctx->state = 8; + break; + case 8: /* S1 */ + err = sp_256_mod_8(ctx->x, ctx->x, p256_order); + if (err == MP_OKAY) + ctx->state = 9; + break; + case 9: /* S2 */ + { + sp_digit carry; + int32_t c; + sp_256_norm_8(ctx->x); + carry = sp_256_add_8(ctx->s, ctx->e, ctx->x); + sp_256_cond_sub_8(ctx->s, ctx->s, p256_order, 0 - carry); + sp_256_norm_8(ctx->s); + c = sp_256_cmp_8(ctx->s, p256_order); + sp_256_cond_sub_8(ctx->s, ctx->s, p256_order, 0L - (sp_digit)(c >= 0)); + sp_256_norm_8(ctx->s); + + /* s = s * k^-1 mod order */ + sp_256_mont_mul_order_8(ctx->s, ctx->s, ctx->kInv); + sp_256_norm_8(ctx->s); + + /* Check that signature is usable. */ + if (sp_256_iszero_8(ctx->s) == 0) { + ctx->state = 10; + break; + } + + /* not usable gen, try again */ + ctx->i--; + if (ctx->i == 0) { + err = RNG_FAILURE_E; + } + ctx->state = 1; + break; + } + case 10: /* RES */ + err = sp_256_to_mp(ctx->r, rm); + if (err == MP_OKAY) { + err = sp_256_to_mp(ctx->s, sm); + } + break; + } + + if (err == MP_OKAY && ctx->state != 10) { + err = FP_WOULDBLOCK; + } + if (err != FP_WOULDBLOCK) { + XMEMSET(ctx->e, 0, sizeof(sp_digit) * 2U * 8U); + XMEMSET(ctx->x, 0, sizeof(sp_digit) * 2U * 8U); + XMEMSET(ctx->k, 0, sizeof(sp_digit) * 2U * 8U); + XMEMSET(ctx->r, 0, sizeof(sp_digit) * 2U * 8U); + XMEMSET(ctx->tmp, 0, sizeof(sp_digit) * 3U * 2U * 8U); + } + + return err; +} +#endif /* WOLFSSL_SP_NONBLOCK */ + int sp_ecc_sign_256(const byte* hash, word32 hashLen, WC_RNG* rng, mp_int* priv, mp_int* rm, mp_int* sm, mp_int* km, void* heap) { @@ -35992,6 +36529,169 @@ int sp_ecc_sign_256(const byte* hash, word32 hashLen, WC_RNG* rng, mp_int* priv, * returns RNG failures, MEMORY_E when memory allocation fails and * MP_OKAY on success. */ +#ifdef WOLFSSL_SP_NONBLOCK +typedef struct sp_ecc_verify_256_ctx { + int state; + union { + sp_256_ecc_mulmod_8_ctx mulmod_ctx; + sp_256_mont_inv_order_8_ctx mont_inv_order_ctx; + sp_256_proj_point_dbl_8_ctx dbl_ctx; + sp_256_proj_point_add_8_ctx add_ctx; + }; + sp_digit u1[2*8]; + sp_digit u2[2*8]; + sp_digit s[2*8]; + sp_digit tmp[2*8 * 5]; + sp_point_256 p1; + sp_point_256 p2; +} sp_ecc_verify_256_ctx; + +int sp_ecc_verify_256_nb(sp_ecc_ctx_t* sp_ctx, const byte* hash, word32 hashLen, mp_int* pX, + mp_int* pY, mp_int* pZ, mp_int* r, mp_int* sm, int* res, void* heap) +{ + int err = FP_WOULDBLOCK; + sp_ecc_verify_256_ctx* ctx = (sp_ecc_verify_256_ctx*)sp_ctx->data; + + typedef char ctx_size_test[sizeof(sp_ecc_verify_256_ctx) >= sizeof(*sp_ctx) ? -1 : 1]; + (void)sizeof(ctx_size_test); + + switch (ctx->state) { + case 0: /* INIT */ + if (hashLen > 32U) { + hashLen = 32U; + } + + sp_256_from_bin(ctx->u1, 8, hash, (int)hashLen); + sp_256_from_mp(ctx->u2, 8, r); + sp_256_from_mp(ctx->s, 8, sm); + sp_256_from_mp(ctx->p2.x, 8, pX); + sp_256_from_mp(ctx->p2.y, 8, pY); + sp_256_from_mp(ctx->p2.z, 8, pZ); + sp_256_mul_8(ctx->s, ctx->s, p256_norm_order); + err = sp_256_mod_8(ctx->s, ctx->s, p256_order); + if (err == MP_OKAY) + ctx->state = 1; + break; + case 1: /* NORMS1 */ + sp_256_norm_8(ctx->s); + XMEMSET(&ctx->mont_inv_order_ctx, 0, sizeof(ctx->mont_inv_order_ctx)); + ctx->state = 2; + break; + case 2: /* NORMS2 */ + err = sp_256_mont_inv_order_8_nb((sp_ecc_ctx_t*)&ctx->mont_inv_order_ctx, ctx->s, ctx->s, ctx->tmp); + if (err == MP_OKAY) { + ctx->state = 3; + } + break; + case 3: /* NORMS3 */ + sp_256_mont_mul_order_8(ctx->u1, ctx->u1, ctx->s); + ctx->state = 4; + break; + case 4: /* NORMS4 */ + sp_256_mont_mul_order_8(ctx->u2, ctx->u2, ctx->s); + XMEMSET(&ctx->mulmod_ctx, 0, sizeof(ctx->mulmod_ctx)); + ctx->state = 5; + break; + case 5: /* MULBASE */ + err = sp_256_ecc_mulmod_8_nb((sp_ecc_ctx_t*)&ctx->mulmod_ctx, &ctx->p1, &p256_base, ctx->u1, 0, heap); + if (err == MP_OKAY) { + XMEMSET(&ctx->mulmod_ctx, 0, sizeof(ctx->mulmod_ctx)); + ctx->state = 6; + } + break; + case 6: /* MULMOD */ + err = sp_256_ecc_mulmod_8_nb((sp_ecc_ctx_t*)&ctx->mulmod_ctx, &ctx->p2, &ctx->p2, ctx->u2, 0, heap); + if (err == MP_OKAY) { + XMEMSET(&ctx->add_ctx, 0, sizeof(ctx->add_ctx)); + ctx->state = 7; + } + break; + case 7: /* ADD */ + err = sp_256_proj_point_add_8_nb((sp_ecc_ctx_t*)&ctx->add_ctx, &ctx->p1, &ctx->p1, &ctx->p2, ctx->tmp); + if (err == MP_OKAY) + ctx->state = 8; + break; + case 8: /* DBLPREP */ + if (sp_256_iszero_8(ctx->p1.z)) { + if (sp_256_iszero_8(ctx->p1.x) && sp_256_iszero_8(ctx->p1.y)) { + XMEMSET(&ctx->dbl_ctx, 0, sizeof(ctx->dbl_ctx)); + ctx->state = 9; + break; + } + else { + /* Y ordinate is not used from here - don't set. */ + int i; + for (i=0; i<8; i++) { + ctx->p1.x[i] = 0; + } + XMEMCPY(ctx->p1.z, p256_norm_mod, sizeof(p256_norm_mod)); + } + } + ctx->state = 10; + break; + case 9: /* DBL */ + err = sp_256_proj_point_dbl_8_nb((sp_ecc_ctx_t*)&ctx->dbl_ctx, &ctx->p1, + &ctx->p2, ctx->tmp); + if (err == MP_OKAY) { + ctx->state = 10; + } + break; + case 10: /* MONT */ + /* (r + n*order).z'.z' mod prime == (u1.G + u2.Q)->x' */ + /* Reload r and convert to Montgomery form. */ + sp_256_from_mp(ctx->u2, 8, r); + err = sp_256_mod_mul_norm_8(ctx->u2, ctx->u2, p256_mod); + if (err == MP_OKAY) + ctx->state = 11; + break; + case 11: /* SQR */ + /* u1 = r.z'.z' mod prime */ + sp_256_mont_sqr_8(ctx->p1.z, ctx->p1.z, p256_mod, p256_mp_mod); + ctx->state = 12; + break; + case 12: /* MUL */ + sp_256_mont_mul_8(ctx->u1, ctx->u2, ctx->p1.z, p256_mod, p256_mp_mod); + ctx->state = 13; + break; + case 13: /* RES */ + err = MP_OKAY; /* math okay, now check result */ + *res = (int)(sp_256_cmp_8(ctx->p1.x, ctx->u1) == 0); + if (*res == 0) { + sp_digit carry; + int32_t c; + + /* Reload r and add order. */ + sp_256_from_mp(ctx->u2, 8, r); + carry = sp_256_add_8(ctx->u2, ctx->u2, p256_order); + /* Carry means result is greater than mod and is not valid. */ + if (carry == 0) { + sp_256_norm_8(ctx->u2); + + /* Compare with mod and if greater or equal then not valid. */ + c = sp_256_cmp_8(ctx->u2, p256_mod); + if (c < 0) { + /* Convert to Montogomery form */ + err = sp_256_mod_mul_norm_8(ctx->u2, ctx->u2, p256_mod); + if (err == MP_OKAY) { + /* u1 = (r + 1*order).z'.z' mod prime */ + sp_256_mont_mul_8(ctx->u1, ctx->u2, ctx->p1.z, p256_mod, + p256_mp_mod); + *res = (int)(sp_256_cmp_8(ctx->p1.x, ctx->u1) == 0); + } + } + } + } + break; + } + + if (err == MP_OKAY && ctx->state != 13) { + err = FP_WOULDBLOCK; + } + + return err; +} +#endif /* WOLFSSL_SP_NONBLOCK */ + int sp_ecc_verify_256(const byte* hash, word32 hashLen, mp_int* pX, mp_int* pY, mp_int* pZ, mp_int* r, mp_int* sm, int* res, void* heap) { @@ -40102,6 +40802,141 @@ static void sp_384_div2_12(sp_digit* r, const sp_digit* a, const sp_digit* m) * p Point to double. * t Temporary ordinate data. */ +#ifdef WOLFSSL_SP_NONBLOCK +typedef struct sp_384_proj_point_dbl_12_ctx { + int state; + sp_digit* t1; + sp_digit* t2; + sp_digit* x; + sp_digit* y; + sp_digit* z; +} sp_384_proj_point_dbl_12_ctx; + +static int sp_384_proj_point_dbl_12_nb(sp_ecc_ctx_t* sp_ctx, sp_point_384* r, const sp_point_384* p, sp_digit* t) +{ + int err = FP_WOULDBLOCK; + sp_384_proj_point_dbl_12_ctx* ctx = (sp_384_proj_point_dbl_12_ctx*)sp_ctx->data; + + typedef char ctx_size_test[sizeof(sp_384_proj_point_dbl_12_ctx) >= sizeof(*sp_ctx) ? -1 : 1]; + (void)sizeof(ctx_size_test); + + switch (ctx->state) { + case 0: + ctx->t1 = t; + ctx->t2 = t + 2*12; + ctx->x = r->x; + ctx->y = r->y; + ctx->z = r->z; + + /* Put infinity into result. */ + if (r != p) { + r->infinity = p->infinity; + } + ctx->state = 1; + break; + case 1: + /* T1 = Z * Z */ + sp_384_mont_sqr_12(ctx->t1, p->z, p384_mod, p384_mp_mod); + ctx->state = 2; + break; + case 2: + /* Z = Y * Z */ + sp_384_mont_mul_12(ctx->z, p->y, p->z, p384_mod, p384_mp_mod); + ctx->state = 3; + break; + case 3: + /* Z = 2Z */ + sp_384_mont_dbl_12(ctx->z, ctx->z, p384_mod); + ctx->state = 4; + break; + case 4: + /* T2 = X - T1 */ + sp_384_mont_sub_12(ctx->t2, p->x, ctx->t1, p384_mod); + ctx->state = 5; + break; + case 5: + /* T1 = X + T1 */ + sp_384_mont_add_12(ctx->t1, p->x, ctx->t1, p384_mod); + ctx->state = 6; + break; + case 6: + /* T2 = T1 * T2 */ + sp_384_mont_mul_12(ctx->t2, ctx->t1, ctx->t2, p384_mod, p384_mp_mod); + ctx->state = 7; + break; + case 7: + /* T1 = 3T2 */ + sp_384_mont_tpl_12(ctx->t1, ctx->t2, p384_mod); + ctx->state = 8; + break; + case 8: + /* Y = 2Y */ + sp_384_mont_dbl_12(ctx->y, p->y, p384_mod); + ctx->state = 9; + break; + case 9: + /* Y = Y * Y */ + sp_384_mont_sqr_12(ctx->y, ctx->y, p384_mod, p384_mp_mod); + ctx->state = 10; + break; + case 10: + /* T2 = Y * Y */ + sp_384_mont_sqr_12(ctx->t2, ctx->y, p384_mod, p384_mp_mod); + ctx->state = 11; + break; + case 11: + /* T2 = T2/2 */ + sp_384_div2_12(ctx->t2, ctx->t2, p384_mod); + ctx->state = 12; + break; + case 12: + /* Y = Y * X */ + sp_384_mont_mul_12(ctx->y, ctx->y, p->x, p384_mod, p384_mp_mod); + ctx->state = 13; + break; + case 13: + /* X = T1 * T1 */ + sp_384_mont_sqr_12(ctx->x, ctx->t1, p384_mod, p384_mp_mod); + ctx->state = 14; + break; + case 14: + /* X = X - Y */ + sp_384_mont_sub_12(ctx->x, ctx->x, ctx->y, p384_mod); + ctx->state = 15; + break; + case 15: + /* X = X - Y */ + sp_384_mont_sub_12(ctx->x, ctx->x, ctx->y, p384_mod); + ctx->state = 16; + break; + case 16: + /* Y = Y - X */ + sp_384_mont_sub_12(ctx->y, ctx->y, ctx->x, p384_mod); + ctx->state = 17; + break; + case 17: + /* Y = Y * T1 */ + sp_384_mont_mul_12(ctx->y, ctx->y, ctx->t1, p384_mod, p384_mp_mod); + ctx->state = 18; + break; + case 18: + /* Y = Y - T2 */ + sp_384_mont_sub_12(ctx->y, ctx->y, ctx->t2, p384_mod); + ctx->state = 19; + /* fall-through */ + case 19: + err = MP_OKAY; + break; + } + + if (err == MP_OKAY && ctx->state != 19) { + err = FP_WOULDBLOCK; + } + + return err; +} +#endif /* WOLFSSL_SP_NONBLOCK */ + static void sp_384_proj_point_dbl_12(sp_point_384* r, const sp_point_384* p, sp_digit* t) { sp_digit* t1 = t; @@ -40177,6 +41012,209 @@ static int sp_384_cmp_equal_12(const sp_digit* a, const sp_digit* b) * q Second point to add. * t Temporary ordinate data. */ + +#ifdef WOLFSSL_SP_NONBLOCK +typedef struct sp_384_proj_point_add_12_ctx { + int state; + sp_384_proj_point_dbl_12_ctx dbl_ctx; + const sp_point_384* ap[2]; + sp_point_384* rp[2]; + sp_digit* t1; + sp_digit* t2; + sp_digit* t3; + sp_digit* t4; + sp_digit* t5; + sp_digit* x; + sp_digit* y; + sp_digit* z; +} sp_384_proj_point_add_12_ctx; + +static int sp_384_proj_point_add_12_nb(sp_ecc_ctx_t* sp_ctx, sp_point_384* r, + const sp_point_384* p, const sp_point_384* q, sp_digit* t) +{ + int err = FP_WOULDBLOCK; + sp_384_proj_point_add_12_ctx* ctx = (sp_384_proj_point_add_12_ctx*)sp_ctx->data; + + /* Ensure only the first point is the same as the result. */ + if (q == r) { + const sp_point_384* a = p; + p = q; + q = a; + } + + typedef char ctx_size_test[sizeof(sp_384_proj_point_add_12_ctx) >= sizeof(*sp_ctx) ? -1 : 1]; + (void)sizeof(ctx_size_test); + + switch (ctx->state) { + case 0: /* INIT */ + ctx->t1 = t; + ctx->t2 = t + 2*12; + ctx->t3 = t + 4*12; + ctx->t4 = t + 6*12; + ctx->t5 = t + 8*12; + + ctx->state = 1; + break; + case 1: + /* Check double */ + (void)sp_384_sub_12(ctx->t1, p384_mod, q->y); + sp_384_norm_12(ctx->t1); + if ((sp_384_cmp_equal_12(p->x, q->x) & sp_384_cmp_equal_12(p->z, q->z) & + (sp_384_cmp_equal_12(p->y, q->y) | sp_384_cmp_equal_12(p->y, ctx->t1))) != 0) + { + XMEMSET(&ctx->dbl_ctx, 0, sizeof(ctx->dbl_ctx)); + ctx->state = 2; + } + else { + ctx->state = 3; + } + break; + case 2: + err = sp_384_proj_point_dbl_12_nb((sp_ecc_ctx_t*)&ctx->dbl_ctx, r, p, t); + if (err == MP_OKAY) + ctx->state = 27; /* done */ + break; + case 3: + { + int i; + ctx->rp[0] = r; + + /*lint allow cast to different type of pointer*/ + ctx->rp[1] = (sp_point_384*)t; /*lint !e9087 !e740*/ + XMEMSET(ctx->rp[1], 0, sizeof(sp_point_384)); + ctx->x = ctx->rp[p->infinity | q->infinity]->x; + ctx->y = ctx->rp[p->infinity | q->infinity]->y; + ctx->z = ctx->rp[p->infinity | q->infinity]->z; + + ctx->ap[0] = p; + ctx->ap[1] = q; + for (i=0; i<12; i++) { + r->x[i] = ctx->ap[p->infinity]->x[i]; + } + for (i=0; i<12; i++) { + r->y[i] = ctx->ap[p->infinity]->y[i]; + } + for (i=0; i<12; i++) { + r->z[i] = ctx->ap[p->infinity]->z[i]; + } + r->infinity = ctx->ap[p->infinity]->infinity; + + ctx->state = 4; + break; + } + case 4: + /* U1 = X1*Z2^2 */ + sp_384_mont_sqr_12(ctx->t1, q->z, p384_mod, p384_mp_mod); + ctx->state = 5; + break; + case 5: + sp_384_mont_mul_12(ctx->t3, ctx->t1, q->z, p384_mod, p384_mp_mod); + ctx->state = 6; + break; + case 6: + sp_384_mont_mul_12(ctx->t1, ctx->t1, ctx->x, p384_mod, p384_mp_mod); + ctx->state = 7; + break; + case 7: + /* U2 = X2*Z1^2 */ + sp_384_mont_sqr_12(ctx->t2, ctx->z, p384_mod, p384_mp_mod); + ctx->state = 8; + break; + case 8: + sp_384_mont_mul_12(ctx->t4, ctx->t2, ctx->z, p384_mod, p384_mp_mod); + ctx->state = 9; + break; + case 9: + sp_384_mont_mul_12(ctx->t2, ctx->t2, q->x, p384_mod, p384_mp_mod); + ctx->state = 10; + break; + case 10: + /* S1 = Y1*Z2^3 */ + sp_384_mont_mul_12(ctx->t3, ctx->t3, ctx->y, p384_mod, p384_mp_mod); + ctx->state = 11; + break; + case 11: + /* S2 = Y2*Z1^3 */ + sp_384_mont_mul_12(ctx->t4, ctx->t4, q->y, p384_mod, p384_mp_mod); + ctx->state = 12; + break; + case 12: + /* H = U2 - U1 */ + sp_384_mont_sub_12(ctx->t2, ctx->t2, ctx->t1, p384_mod); + ctx->state = 13; + break; + case 13: + /* R = S2 - S1 */ + sp_384_mont_sub_12(ctx->t4, ctx->t4, ctx->t3, p384_mod); + ctx->state = 14; + break; + case 14: + /* Z3 = H*Z1*Z2 */ + sp_384_mont_mul_12(ctx->z, ctx->z, q->z, p384_mod, p384_mp_mod); + ctx->state = 15; + break; + case 15: + sp_384_mont_mul_12(ctx->z, ctx->z, ctx->t2, p384_mod, p384_mp_mod); + ctx->state = 16; + break; + case 16: + /* X3 = R^2 - H^3 - 2*U1*H^2 */ + sp_384_mont_sqr_12(ctx->x, ctx->t4, p384_mod, p384_mp_mod); + ctx->state = 17; + break; + case 17: + sp_384_mont_sqr_12(ctx->t5, ctx->t2, p384_mod, p384_mp_mod); + ctx->state = 18; + break; + case 18: + sp_384_mont_mul_12(ctx->y, ctx->t1, ctx->t5, p384_mod, p384_mp_mod); + ctx->state = 19; + break; + case 19: + sp_384_mont_mul_12(ctx->t5, ctx->t5, ctx->t2, p384_mod, p384_mp_mod); + ctx->state = 20; + break; + case 20: + sp_384_mont_sub_12(ctx->x, ctx->x, ctx->t5, p384_mod); + ctx->state = 21; + break; + case 21: + sp_384_mont_dbl_12(ctx->t1, ctx->y, p384_mod); + ctx->state = 22; + break; + case 22: + sp_384_mont_sub_12(ctx->x, ctx->x, ctx->t1, p384_mod); + ctx->state = 23; + break; + case 23: + /* Y3 = R*(U1*H^2 - X3) - S1*H^3 */ + sp_384_mont_sub_12(ctx->y, ctx->y, ctx->x, p384_mod); + ctx->state = 24; + break; + case 24: + sp_384_mont_mul_12(ctx->y, ctx->y, ctx->t4, p384_mod, p384_mp_mod); + ctx->state = 25; + break; + case 25: + sp_384_mont_mul_12(ctx->t5, ctx->t5, ctx->t3, p384_mod, p384_mp_mod); + ctx->state = 26; + break; + case 26: + sp_384_mont_sub_12(ctx->y, ctx->y, ctx->t5, p384_mod); + ctx->state = 27; + /* fall-through */ + case 27: + err = MP_OKAY; + break; + } + + if (err == MP_OKAY && ctx->state != 27) { + err = FP_WOULDBLOCK; + } + return err; +} +#endif /* WOLFSSL_SP_NONBLOCK */ + static void sp_384_proj_point_add_12(sp_point_384* r, const sp_point_384* p, const sp_point_384* q, sp_digit* t) { @@ -43458,6 +44496,46 @@ static void sp_384_mont_sqr_n_order_12(sp_digit* r, const sp_digit* a, int n) * a Number to invert. * td Temporary data. */ + +#ifdef WOLFSSL_SP_NONBLOCK +typedef struct sp_384_mont_inv_order_12_ctx { + int state; + int i; +} sp_384_mont_inv_order_12_ctx; +static int sp_384_mont_inv_order_12_nb(sp_ecc_ctx_t* sp_ctx, sp_digit* r, const sp_digit* a, + sp_digit* t) +{ + int err = FP_WOULDBLOCK; + sp_384_mont_inv_order_12_ctx* ctx = (sp_384_mont_inv_order_12_ctx*)sp_ctx; + + typedef char ctx_size_test[sizeof(sp_384_mont_inv_order_12_ctx) >= sizeof(*sp_ctx) ? -1 : 1]; + (void)sizeof(ctx_size_test); + + switch (ctx->state) { + case 0: + XMEMCPY(t, a, sizeof(sp_digit) * 12); + ctx->i = 382; + ctx->state = 1; + break; + case 1: + sp_384_mont_sqr_order_12(t, t); + if ((p384_order_minus_2[ctx->i / 32] & ((sp_int_digit)1 << (ctx->i % 32))) != 0) { + sp_384_mont_mul_order_12(t, t, a); + } + ctx->i--; + if (ctx->i == 0) { + ctx->state = 2; + } + break; + case 2: + XMEMCPY(r, t, sizeof(sp_digit) * 12U); + err = MP_OKAY; + break; + } + return err; +} +#endif /* WOLFSSL_SP_NONBLOCK */ + static void sp_384_mont_inv_order_12(sp_digit* r, const sp_digit* a, sp_digit* td) { @@ -43544,6 +44622,165 @@ static void sp_384_mont_inv_order_12(sp_digit* r, const sp_digit* a, * returns RNG failures, MEMORY_E when memory allocation fails and * MP_OKAY on success. */ +#ifdef WOLFSSL_SP_NONBLOCK +typedef struct sp_ecc_sign_384_ctx { + int state; + union { + sp_384_ecc_mulmod_12_ctx mulmod_ctx; + sp_384_mont_inv_order_12_ctx mont_inv_order_ctx; + }; + sp_digit e[2*12]; + sp_digit x[2*12]; + sp_digit k[2*12]; + sp_digit r[2*12]; + sp_digit tmp[3 * 2*12]; + sp_point_384 point; + sp_digit* s; + sp_digit* kInv; + int i; +} sp_ecc_sign_384_ctx; + +int sp_ecc_sign_384_nb(sp_ecc_ctx_t* sp_ctx, const byte* hash, word32 hashLen, WC_RNG* rng, mp_int* priv, + mp_int* rm, mp_int* sm, mp_int* km, void* heap) +{ + int err = FP_WOULDBLOCK; + sp_ecc_sign_384_ctx* ctx = (sp_ecc_sign_384_ctx*)sp_ctx->data; + + typedef char ctx_size_test[sizeof(sp_ecc_sign_384_ctx) >= sizeof(*sp_ctx) ? -1 : 1]; + (void)sizeof(ctx_size_test); + + (void)heap; + + switch (ctx->state) { + case 0: /* INIT */ + ctx->s = ctx->e; + ctx->kInv = ctx->k; + if (hashLen > 48U) { + hashLen = 48U; + } + + sp_384_from_bin(ctx->e, 12, hash, (int)hashLen); + + ctx->i = SP_ECC_MAX_SIG_GEN; + ctx->state = 1; + break; + case 1: /* GEN */ + sp_384_from_mp(ctx->x, 12, priv); + /* New random point. */ + if (km == NULL || mp_iszero(km)) { + err = sp_384_ecc_gen_k_12(rng, ctx->k); + } + else { + sp_384_from_mp(ctx->k, 12, km); + mp_zero(km); + } + XMEMSET(&ctx->mulmod_ctx, 0, sizeof(ctx->mulmod_ctx)); + ctx->state = 2; + break; + case 2: /* MULMOD */ + err = sp_384_ecc_mulmod_12_nb((sp_ecc_ctx_t*)&ctx->mulmod_ctx, + &ctx->point, &p384_base, ctx->k, 1, heap); + if (err == MP_OKAY) { + ctx->state = 3; + } + break; + case 3: /* MODORDER */ + { + int32_t c; + /* r = point->x mod order */ + XMEMCPY(ctx->r, ctx->point.x, sizeof(sp_digit) * 12U); + sp_384_norm_12(ctx->r); + c = sp_384_cmp_12(ctx->r, p384_order); + sp_384_cond_sub_12(ctx->r, ctx->r, p384_order, 0L - (sp_digit)(c >= 0)); + sp_384_norm_12(ctx->r); + ctx->state = 4; + break; + } + case 4: /* KMODORDER */ + /* Conv k to Montgomery form (mod order) */ + sp_384_mul_12(ctx->k, ctx->k, p384_norm_order); + err = sp_384_mod_12(ctx->k, ctx->k, p384_order); + if (err == MP_OKAY) { + sp_384_norm_12(ctx->k); + XMEMSET(&ctx->mont_inv_order_ctx, 0, sizeof(ctx->mont_inv_order_ctx)); + ctx->state = 5; + } + break; + case 5: /* KINV */ + /* kInv = 1/k mod order */ + err = sp_384_mont_inv_order_12_nb((sp_ecc_ctx_t*)&ctx->mont_inv_order_ctx, ctx->kInv, ctx->k, ctx->tmp); + if (err == MP_OKAY) { + XMEMSET(&ctx->mont_inv_order_ctx, 0, sizeof(ctx->mont_inv_order_ctx)); + ctx->state = 6; + } + break; + case 6: /* KINVNORM */ + sp_384_norm_12(ctx->kInv); + ctx->state = 7; + break; + case 7: /* R */ + /* s = r * x + e */ + sp_384_mul_12(ctx->x, ctx->x, ctx->r); + ctx->state = 8; + break; + case 8: /* S1 */ + err = sp_384_mod_12(ctx->x, ctx->x, p384_order); + if (err == MP_OKAY) + ctx->state = 9; + break; + case 9: /* S2 */ + { + sp_digit carry; + int32_t c; + sp_384_norm_12(ctx->x); + carry = sp_384_add_12(ctx->s, ctx->e, ctx->x); + sp_384_cond_sub_12(ctx->s, ctx->s, p384_order, 0 - carry); + sp_384_norm_12(ctx->s); + c = sp_384_cmp_12(ctx->s, p384_order); + sp_384_cond_sub_12(ctx->s, ctx->s, p384_order, 0L - (sp_digit)(c >= 0)); + sp_384_norm_12(ctx->s); + + /* s = s * k^-1 mod order */ + sp_384_mont_mul_order_12(ctx->s, ctx->s, ctx->kInv); + sp_384_norm_12(ctx->s); + + /* Check that signature is usable. */ + if (sp_384_iszero_12(ctx->s) == 0) { + ctx->state = 10; + break; + } + + /* not usable gen, try again */ + ctx->i--; + if (ctx->i == 0) { + err = RNG_FAILURE_E; + } + ctx->state = 1; + break; + } + case 10: /* RES */ + err = sp_384_to_mp(ctx->r, rm); + if (err == MP_OKAY) { + err = sp_384_to_mp(ctx->s, sm); + } + break; + } + + if (err == MP_OKAY && ctx->state != 10) { + err = FP_WOULDBLOCK; + } + if (err != FP_WOULDBLOCK) { + XMEMSET(ctx->e, 0, sizeof(sp_digit) * 2U * 12U); + XMEMSET(ctx->x, 0, sizeof(sp_digit) * 2U * 12U); + XMEMSET(ctx->k, 0, sizeof(sp_digit) * 2U * 12U); + XMEMSET(ctx->r, 0, sizeof(sp_digit) * 2U * 12U); + XMEMSET(ctx->tmp, 0, sizeof(sp_digit) * 3U * 2U * 12U); + } + + return err; +} +#endif /* WOLFSSL_SP_NONBLOCK */ + int sp_ecc_sign_384(const byte* hash, word32 hashLen, WC_RNG* rng, mp_int* priv, mp_int* rm, mp_int* sm, mp_int* km, void* heap) { @@ -43715,6 +44952,169 @@ int sp_ecc_sign_384(const byte* hash, word32 hashLen, WC_RNG* rng, mp_int* priv, * returns RNG failures, MEMORY_E when memory allocation fails and * MP_OKAY on success. */ +#ifdef WOLFSSL_SP_NONBLOCK +typedef struct sp_ecc_verify_384_ctx { + int state; + union { + sp_384_ecc_mulmod_12_ctx mulmod_ctx; + sp_384_mont_inv_order_12_ctx mont_inv_order_ctx; + sp_384_proj_point_dbl_12_ctx dbl_ctx; + sp_384_proj_point_add_12_ctx add_ctx; + }; + sp_digit u1[2*12]; + sp_digit u2[2*12]; + sp_digit s[2*12]; + sp_digit tmp[2*12 * 5]; + sp_point_384 p1; + sp_point_384 p2; +} sp_ecc_verify_384_ctx; + +int sp_ecc_verify_384_nb(sp_ecc_ctx_t* sp_ctx, const byte* hash, word32 hashLen, mp_int* pX, + mp_int* pY, mp_int* pZ, mp_int* r, mp_int* sm, int* res, void* heap) +{ + int err = FP_WOULDBLOCK; + sp_ecc_verify_384_ctx* ctx = (sp_ecc_verify_384_ctx*)sp_ctx->data; + + typedef char ctx_size_test[sizeof(sp_ecc_verify_384_ctx) >= sizeof(*sp_ctx) ? -1 : 1]; + (void)sizeof(ctx_size_test); + + switch (ctx->state) { + case 0: /* INIT */ + if (hashLen > 48U) { + hashLen = 48U; + } + + sp_384_from_bin(ctx->u1, 12, hash, (int)hashLen); + sp_384_from_mp(ctx->u2, 12, r); + sp_384_from_mp(ctx->s, 12, sm); + sp_384_from_mp(ctx->p2.x, 12, pX); + sp_384_from_mp(ctx->p2.y, 12, pY); + sp_384_from_mp(ctx->p2.z, 12, pZ); + sp_384_mul_12(ctx->s, ctx->s, p384_norm_order); + err = sp_384_mod_12(ctx->s, ctx->s, p384_order); + if (err == MP_OKAY) + ctx->state = 1; + break; + case 1: /* NORMS1 */ + sp_384_norm_12(ctx->s); + XMEMSET(&ctx->mont_inv_order_ctx, 0, sizeof(ctx->mont_inv_order_ctx)); + ctx->state = 2; + break; + case 2: /* NORMS2 */ + err = sp_384_mont_inv_order_12_nb((sp_ecc_ctx_t*)&ctx->mont_inv_order_ctx, ctx->s, ctx->s, ctx->tmp); + if (err == MP_OKAY) { + ctx->state = 3; + } + break; + case 3: /* NORMS3 */ + sp_384_mont_mul_order_12(ctx->u1, ctx->u1, ctx->s); + ctx->state = 4; + break; + case 4: /* NORMS4 */ + sp_384_mont_mul_order_12(ctx->u2, ctx->u2, ctx->s); + XMEMSET(&ctx->mulmod_ctx, 0, sizeof(ctx->mulmod_ctx)); + ctx->state = 5; + break; + case 5: /* MULBASE */ + err = sp_384_ecc_mulmod_12_nb((sp_ecc_ctx_t*)&ctx->mulmod_ctx, &ctx->p1, &p384_base, ctx->u1, 0, heap); + if (err == MP_OKAY) { + XMEMSET(&ctx->mulmod_ctx, 0, sizeof(ctx->mulmod_ctx)); + ctx->state = 6; + } + break; + case 6: /* MULMOD */ + err = sp_384_ecc_mulmod_12_nb((sp_ecc_ctx_t*)&ctx->mulmod_ctx, &ctx->p2, &ctx->p2, ctx->u2, 0, heap); + if (err == MP_OKAY) { + XMEMSET(&ctx->add_ctx, 0, sizeof(ctx->add_ctx)); + ctx->state = 7; + } + break; + case 7: /* ADD */ + err = sp_384_proj_point_add_12_nb((sp_ecc_ctx_t*)&ctx->add_ctx, &ctx->p1, &ctx->p1, &ctx->p2, ctx->tmp); + if (err == MP_OKAY) + ctx->state = 8; + break; + case 8: /* DBLPREP */ + if (sp_384_iszero_12(ctx->p1.z)) { + if (sp_384_iszero_12(ctx->p1.x) && sp_384_iszero_12(ctx->p1.y)) { + XMEMSET(&ctx->dbl_ctx, 0, sizeof(ctx->dbl_ctx)); + ctx->state = 9; + break; + } + else { + /* Y ordinate is not used from here - don't set. */ + int i; + for (i=0; i<12; i++) { + ctx->p1.x[i] = 0; + } + XMEMCPY(ctx->p1.z, p384_norm_mod, sizeof(p384_norm_mod)); + } + } + ctx->state = 10; + break; + case 9: /* DBL */ + err = sp_384_proj_point_dbl_12_nb((sp_ecc_ctx_t*)&ctx->dbl_ctx, &ctx->p1, + &ctx->p2, ctx->tmp); + if (err == MP_OKAY) { + ctx->state = 10; + } + break; + case 10: /* MONT */ + /* (r + n*order).z'.z' mod prime == (u1.G + u2.Q)->x' */ + /* Reload r and convert to Montgomery form. */ + sp_384_from_mp(ctx->u2, 12, r); + err = sp_384_mod_mul_norm_12(ctx->u2, ctx->u2, p384_mod); + if (err == MP_OKAY) + ctx->state = 11; + break; + case 11: /* SQR */ + /* u1 = r.z'.z' mod prime */ + sp_384_mont_sqr_12(ctx->p1.z, ctx->p1.z, p384_mod, p384_mp_mod); + ctx->state = 12; + break; + case 12: /* MUL */ + sp_384_mont_mul_12(ctx->u1, ctx->u2, ctx->p1.z, p384_mod, p384_mp_mod); + ctx->state = 13; + break; + case 13: /* RES */ + err = MP_OKAY; /* math okay, now check result */ + *res = (int)(sp_384_cmp_12(ctx->p1.x, ctx->u1) == 0); + if (*res == 0) { + sp_digit carry; + int32_t c; + + /* Reload r and add order. */ + sp_384_from_mp(ctx->u2, 12, r); + carry = sp_384_add_12(ctx->u2, ctx->u2, p384_order); + /* Carry means result is greater than mod and is not valid. */ + if (carry == 0) { + sp_384_norm_12(ctx->u2); + + /* Compare with mod and if greater or equal then not valid. */ + c = sp_384_cmp_12(ctx->u2, p384_mod); + if (c < 0) { + /* Convert to Montogomery form */ + err = sp_384_mod_mul_norm_12(ctx->u2, ctx->u2, p384_mod); + if (err == MP_OKAY) { + /* u1 = (r + 1*order).z'.z' mod prime */ + sp_384_mont_mul_12(ctx->u1, ctx->u2, ctx->p1.z, p384_mod, + p384_mp_mod); + *res = (int)(sp_384_cmp_12(ctx->p1.x, ctx->u1) == 0); + } + } + } + } + break; + } + + if (err == MP_OKAY && ctx->state != 13) { + err = FP_WOULDBLOCK; + } + + return err; +} +#endif /* WOLFSSL_SP_NONBLOCK */ + int sp_ecc_verify_384(const byte* hash, word32 hashLen, mp_int* pX, mp_int* pY, mp_int* pZ, mp_int* r, mp_int* sm, int* res, void* heap) { diff --git a/wolfcrypt/src/sp_arm64.c b/wolfcrypt/src/sp_arm64.c index 3ea3c4ec10..378ffbf652 100644 --- a/wolfcrypt/src/sp_arm64.c +++ b/wolfcrypt/src/sp_arm64.c @@ -20053,6 +20053,141 @@ static void sp_256_div2_4(sp_digit* r, const sp_digit* a, const sp_digit* m) * p Point to double. * t Temporary ordinate data. */ +#ifdef WOLFSSL_SP_NONBLOCK +typedef struct sp_256_proj_point_dbl_4_ctx { + int state; + sp_digit* t1; + sp_digit* t2; + sp_digit* x; + sp_digit* y; + sp_digit* z; +} sp_256_proj_point_dbl_4_ctx; + +static int sp_256_proj_point_dbl_4_nb(sp_ecc_ctx_t* sp_ctx, sp_point_256* r, const sp_point_256* p, sp_digit* t) +{ + int err = FP_WOULDBLOCK; + sp_256_proj_point_dbl_4_ctx* ctx = (sp_256_proj_point_dbl_4_ctx*)sp_ctx->data; + + typedef char ctx_size_test[sizeof(sp_256_proj_point_dbl_4_ctx) >= sizeof(*sp_ctx) ? -1 : 1]; + (void)sizeof(ctx_size_test); + + switch (ctx->state) { + case 0: + ctx->t1 = t; + ctx->t2 = t + 2*4; + ctx->x = r->x; + ctx->y = r->y; + ctx->z = r->z; + + /* Put infinity into result. */ + if (r != p) { + r->infinity = p->infinity; + } + ctx->state = 1; + break; + case 1: + /* T1 = Z * Z */ + sp_256_mont_sqr_4(ctx->t1, p->z, p256_mod, p256_mp_mod); + ctx->state = 2; + break; + case 2: + /* Z = Y * Z */ + sp_256_mont_mul_4(ctx->z, p->y, p->z, p256_mod, p256_mp_mod); + ctx->state = 3; + break; + case 3: + /* Z = 2Z */ + sp_256_mont_dbl_4(ctx->z, ctx->z, p256_mod); + ctx->state = 4; + break; + case 4: + /* T2 = X - T1 */ + sp_256_mont_sub_4(ctx->t2, p->x, ctx->t1, p256_mod); + ctx->state = 5; + break; + case 5: + /* T1 = X + T1 */ + sp_256_mont_add_4(ctx->t1, p->x, ctx->t1, p256_mod); + ctx->state = 6; + break; + case 6: + /* T2 = T1 * T2 */ + sp_256_mont_mul_4(ctx->t2, ctx->t1, ctx->t2, p256_mod, p256_mp_mod); + ctx->state = 7; + break; + case 7: + /* T1 = 3T2 */ + sp_256_mont_tpl_4(ctx->t1, ctx->t2, p256_mod); + ctx->state = 8; + break; + case 8: + /* Y = 2Y */ + sp_256_mont_dbl_4(ctx->y, p->y, p256_mod); + ctx->state = 9; + break; + case 9: + /* Y = Y * Y */ + sp_256_mont_sqr_4(ctx->y, ctx->y, p256_mod, p256_mp_mod); + ctx->state = 10; + break; + case 10: + /* T2 = Y * Y */ + sp_256_mont_sqr_4(ctx->t2, ctx->y, p256_mod, p256_mp_mod); + ctx->state = 11; + break; + case 11: + /* T2 = T2/2 */ + sp_256_div2_4(ctx->t2, ctx->t2, p256_mod); + ctx->state = 12; + break; + case 12: + /* Y = Y * X */ + sp_256_mont_mul_4(ctx->y, ctx->y, p->x, p256_mod, p256_mp_mod); + ctx->state = 13; + break; + case 13: + /* X = T1 * T1 */ + sp_256_mont_sqr_4(ctx->x, ctx->t1, p256_mod, p256_mp_mod); + ctx->state = 14; + break; + case 14: + /* X = X - Y */ + sp_256_mont_sub_4(ctx->x, ctx->x, ctx->y, p256_mod); + ctx->state = 15; + break; + case 15: + /* X = X - Y */ + sp_256_mont_sub_4(ctx->x, ctx->x, ctx->y, p256_mod); + ctx->state = 16; + break; + case 16: + /* Y = Y - X */ + sp_256_mont_sub_4(ctx->y, ctx->y, ctx->x, p256_mod); + ctx->state = 17; + break; + case 17: + /* Y = Y * T1 */ + sp_256_mont_mul_4(ctx->y, ctx->y, ctx->t1, p256_mod, p256_mp_mod); + ctx->state = 18; + break; + case 18: + /* Y = Y - T2 */ + sp_256_mont_sub_4(ctx->y, ctx->y, ctx->t2, p256_mod); + ctx->state = 19; + /* fall-through */ + case 19: + err = MP_OKAY; + break; + } + + if (err == MP_OKAY && ctx->state != 19) { + err = FP_WOULDBLOCK; + } + + return err; +} +#endif /* WOLFSSL_SP_NONBLOCK */ + static void sp_256_proj_point_dbl_4(sp_point_256* r, const sp_point_256* p, sp_digit* t) { sp_digit* t1 = t; @@ -20303,6 +20438,209 @@ static int sp_256_cmp_equal_4(const sp_digit* a, const sp_digit* b) * q Second point to add. * t Temporary ordinate data. */ + +#ifdef WOLFSSL_SP_NONBLOCK +typedef struct sp_256_proj_point_add_4_ctx { + int state; + sp_256_proj_point_dbl_4_ctx dbl_ctx; + const sp_point_256* ap[2]; + sp_point_256* rp[2]; + sp_digit* t1; + sp_digit* t2; + sp_digit* t3; + sp_digit* t4; + sp_digit* t5; + sp_digit* x; + sp_digit* y; + sp_digit* z; +} sp_256_proj_point_add_4_ctx; + +static int sp_256_proj_point_add_4_nb(sp_ecc_ctx_t* sp_ctx, sp_point_256* r, + const sp_point_256* p, const sp_point_256* q, sp_digit* t) +{ + int err = FP_WOULDBLOCK; + sp_256_proj_point_add_4_ctx* ctx = (sp_256_proj_point_add_4_ctx*)sp_ctx->data; + + /* Ensure only the first point is the same as the result. */ + if (q == r) { + const sp_point_256* a = p; + p = q; + q = a; + } + + typedef char ctx_size_test[sizeof(sp_256_proj_point_add_4_ctx) >= sizeof(*sp_ctx) ? -1 : 1]; + (void)sizeof(ctx_size_test); + + switch (ctx->state) { + case 0: /* INIT */ + ctx->t1 = t; + ctx->t2 = t + 2*4; + ctx->t3 = t + 4*4; + ctx->t4 = t + 6*4; + ctx->t5 = t + 8*4; + + ctx->state = 1; + break; + case 1: + /* Check double */ + (void)sp_256_sub_4(ctx->t1, p256_mod, q->y); + sp_256_norm_4(ctx->t1); + if ((sp_256_cmp_equal_4(p->x, q->x) & sp_256_cmp_equal_4(p->z, q->z) & + (sp_256_cmp_equal_4(p->y, q->y) | sp_256_cmp_equal_4(p->y, ctx->t1))) != 0) + { + XMEMSET(&ctx->dbl_ctx, 0, sizeof(ctx->dbl_ctx)); + ctx->state = 2; + } + else { + ctx->state = 3; + } + break; + case 2: + err = sp_256_proj_point_dbl_4_nb((sp_ecc_ctx_t*)&ctx->dbl_ctx, r, p, t); + if (err == MP_OKAY) + ctx->state = 27; /* done */ + break; + case 3: + { + int i; + ctx->rp[0] = r; + + /*lint allow cast to different type of pointer*/ + ctx->rp[1] = (sp_point_256*)t; /*lint !e9087 !e740*/ + XMEMSET(ctx->rp[1], 0, sizeof(sp_point_256)); + ctx->x = ctx->rp[p->infinity | q->infinity]->x; + ctx->y = ctx->rp[p->infinity | q->infinity]->y; + ctx->z = ctx->rp[p->infinity | q->infinity]->z; + + ctx->ap[0] = p; + ctx->ap[1] = q; + for (i=0; i<4; i++) { + r->x[i] = ctx->ap[p->infinity]->x[i]; + } + for (i=0; i<4; i++) { + r->y[i] = ctx->ap[p->infinity]->y[i]; + } + for (i=0; i<4; i++) { + r->z[i] = ctx->ap[p->infinity]->z[i]; + } + r->infinity = ctx->ap[p->infinity]->infinity; + + ctx->state = 4; + break; + } + case 4: + /* U1 = X1*Z2^2 */ + sp_256_mont_sqr_4(ctx->t1, q->z, p256_mod, p256_mp_mod); + ctx->state = 5; + break; + case 5: + sp_256_mont_mul_4(ctx->t3, ctx->t1, q->z, p256_mod, p256_mp_mod); + ctx->state = 6; + break; + case 6: + sp_256_mont_mul_4(ctx->t1, ctx->t1, ctx->x, p256_mod, p256_mp_mod); + ctx->state = 7; + break; + case 7: + /* U2 = X2*Z1^2 */ + sp_256_mont_sqr_4(ctx->t2, ctx->z, p256_mod, p256_mp_mod); + ctx->state = 8; + break; + case 8: + sp_256_mont_mul_4(ctx->t4, ctx->t2, ctx->z, p256_mod, p256_mp_mod); + ctx->state = 9; + break; + case 9: + sp_256_mont_mul_4(ctx->t2, ctx->t2, q->x, p256_mod, p256_mp_mod); + ctx->state = 10; + break; + case 10: + /* S1 = Y1*Z2^3 */ + sp_256_mont_mul_4(ctx->t3, ctx->t3, ctx->y, p256_mod, p256_mp_mod); + ctx->state = 11; + break; + case 11: + /* S2 = Y2*Z1^3 */ + sp_256_mont_mul_4(ctx->t4, ctx->t4, q->y, p256_mod, p256_mp_mod); + ctx->state = 12; + break; + case 12: + /* H = U2 - U1 */ + sp_256_mont_sub_4(ctx->t2, ctx->t2, ctx->t1, p256_mod); + ctx->state = 13; + break; + case 13: + /* R = S2 - S1 */ + sp_256_mont_sub_4(ctx->t4, ctx->t4, ctx->t3, p256_mod); + ctx->state = 14; + break; + case 14: + /* Z3 = H*Z1*Z2 */ + sp_256_mont_mul_4(ctx->z, ctx->z, q->z, p256_mod, p256_mp_mod); + ctx->state = 15; + break; + case 15: + sp_256_mont_mul_4(ctx->z, ctx->z, ctx->t2, p256_mod, p256_mp_mod); + ctx->state = 16; + break; + case 16: + /* X3 = R^2 - H^3 - 2*U1*H^2 */ + sp_256_mont_sqr_4(ctx->x, ctx->t4, p256_mod, p256_mp_mod); + ctx->state = 17; + break; + case 17: + sp_256_mont_sqr_4(ctx->t5, ctx->t2, p256_mod, p256_mp_mod); + ctx->state = 18; + break; + case 18: + sp_256_mont_mul_4(ctx->y, ctx->t1, ctx->t5, p256_mod, p256_mp_mod); + ctx->state = 19; + break; + case 19: + sp_256_mont_mul_4(ctx->t5, ctx->t5, ctx->t2, p256_mod, p256_mp_mod); + ctx->state = 20; + break; + case 20: + sp_256_mont_sub_4(ctx->x, ctx->x, ctx->t5, p256_mod); + ctx->state = 21; + break; + case 21: + sp_256_mont_dbl_4(ctx->t1, ctx->y, p256_mod); + ctx->state = 22; + break; + case 22: + sp_256_mont_sub_4(ctx->x, ctx->x, ctx->t1, p256_mod); + ctx->state = 23; + break; + case 23: + /* Y3 = R*(U1*H^2 - X3) - S1*H^3 */ + sp_256_mont_sub_4(ctx->y, ctx->y, ctx->x, p256_mod); + ctx->state = 24; + break; + case 24: + sp_256_mont_mul_4(ctx->y, ctx->y, ctx->t4, p256_mod, p256_mp_mod); + ctx->state = 25; + break; + case 25: + sp_256_mont_mul_4(ctx->t5, ctx->t5, ctx->t3, p256_mod, p256_mp_mod); + ctx->state = 26; + break; + case 26: + sp_256_mont_sub_4(ctx->y, ctx->y, ctx->t5, p256_mod); + ctx->state = 27; + /* fall-through */ + case 27: + err = MP_OKAY; + break; + } + + if (err == MP_OKAY && ctx->state != 27) { + err = FP_WOULDBLOCK; + } + return err; +} +#endif /* WOLFSSL_SP_NONBLOCK */ + static void sp_256_proj_point_add_4(sp_point_256* r, const sp_point_256* p, const sp_point_256* q, sp_digit* t) { @@ -35477,6 +35815,46 @@ static void sp_256_mont_sqr_n_order_4(sp_digit* r, const sp_digit* a, int n) * a Number to invert. * td Temporary data. */ + +#ifdef WOLFSSL_SP_NONBLOCK +typedef struct sp_256_mont_inv_order_4_ctx { + int state; + int i; +} sp_256_mont_inv_order_4_ctx; +static int sp_256_mont_inv_order_4_nb(sp_ecc_ctx_t* sp_ctx, sp_digit* r, const sp_digit* a, + sp_digit* t) +{ + int err = FP_WOULDBLOCK; + sp_256_mont_inv_order_4_ctx* ctx = (sp_256_mont_inv_order_4_ctx*)sp_ctx; + + typedef char ctx_size_test[sizeof(sp_256_mont_inv_order_4_ctx) >= sizeof(*sp_ctx) ? -1 : 1]; + (void)sizeof(ctx_size_test); + + switch (ctx->state) { + case 0: + XMEMCPY(t, a, sizeof(sp_digit) * 4); + ctx->i = 254; + ctx->state = 1; + break; + case 1: + sp_256_mont_sqr_order_4(t, t); + if ((p256_order_minus_2[ctx->i / 64] & ((sp_int_digit)1 << (ctx->i % 64))) != 0) { + sp_256_mont_mul_order_4(t, t, a); + } + ctx->i--; + if (ctx->i == 0) { + ctx->state = 2; + } + break; + case 2: + XMEMCPY(r, t, sizeof(sp_digit) * 4U); + err = MP_OKAY; + break; + } + return err; +} +#endif /* WOLFSSL_SP_NONBLOCK */ + static void sp_256_mont_inv_order_4(sp_digit* r, const sp_digit* a, sp_digit* td) { @@ -35592,6 +35970,165 @@ static void sp_256_mont_inv_order_4(sp_digit* r, const sp_digit* a, * returns RNG failures, MEMORY_E when memory allocation fails and * MP_OKAY on success. */ +#ifdef WOLFSSL_SP_NONBLOCK +typedef struct sp_ecc_sign_256_ctx { + int state; + union { + sp_256_ecc_mulmod_4_ctx mulmod_ctx; + sp_256_mont_inv_order_4_ctx mont_inv_order_ctx; + }; + sp_digit e[2*4]; + sp_digit x[2*4]; + sp_digit k[2*4]; + sp_digit r[2*4]; + sp_digit tmp[3 * 2*4]; + sp_point_256 point; + sp_digit* s; + sp_digit* kInv; + int i; +} sp_ecc_sign_256_ctx; + +int sp_ecc_sign_256_nb(sp_ecc_ctx_t* sp_ctx, const byte* hash, word32 hashLen, WC_RNG* rng, mp_int* priv, + mp_int* rm, mp_int* sm, mp_int* km, void* heap) +{ + int err = FP_WOULDBLOCK; + sp_ecc_sign_256_ctx* ctx = (sp_ecc_sign_256_ctx*)sp_ctx->data; + + typedef char ctx_size_test[sizeof(sp_ecc_sign_256_ctx) >= sizeof(*sp_ctx) ? -1 : 1]; + (void)sizeof(ctx_size_test); + + (void)heap; + + switch (ctx->state) { + case 0: /* INIT */ + ctx->s = ctx->e; + ctx->kInv = ctx->k; + if (hashLen > 32U) { + hashLen = 32U; + } + + sp_256_from_bin(ctx->e, 4, hash, (int)hashLen); + + ctx->i = SP_ECC_MAX_SIG_GEN; + ctx->state = 1; + break; + case 1: /* GEN */ + sp_256_from_mp(ctx->x, 4, priv); + /* New random point. */ + if (km == NULL || mp_iszero(km)) { + err = sp_256_ecc_gen_k_4(rng, ctx->k); + } + else { + sp_256_from_mp(ctx->k, 4, km); + mp_zero(km); + } + XMEMSET(&ctx->mulmod_ctx, 0, sizeof(ctx->mulmod_ctx)); + ctx->state = 2; + break; + case 2: /* MULMOD */ + err = sp_256_ecc_mulmod_4_nb((sp_ecc_ctx_t*)&ctx->mulmod_ctx, + &ctx->point, &p256_base, ctx->k, 1, heap); + if (err == MP_OKAY) { + ctx->state = 3; + } + break; + case 3: /* MODORDER */ + { + int64_t c; + /* r = point->x mod order */ + XMEMCPY(ctx->r, ctx->point.x, sizeof(sp_digit) * 4U); + sp_256_norm_4(ctx->r); + c = sp_256_cmp_4(ctx->r, p256_order); + sp_256_cond_sub_4(ctx->r, ctx->r, p256_order, 0L - (sp_digit)(c >= 0)); + sp_256_norm_4(ctx->r); + ctx->state = 4; + break; + } + case 4: /* KMODORDER */ + /* Conv k to Montgomery form (mod order) */ + sp_256_mul_4(ctx->k, ctx->k, p256_norm_order); + err = sp_256_mod_4(ctx->k, ctx->k, p256_order); + if (err == MP_OKAY) { + sp_256_norm_4(ctx->k); + XMEMSET(&ctx->mont_inv_order_ctx, 0, sizeof(ctx->mont_inv_order_ctx)); + ctx->state = 5; + } + break; + case 5: /* KINV */ + /* kInv = 1/k mod order */ + err = sp_256_mont_inv_order_4_nb((sp_ecc_ctx_t*)&ctx->mont_inv_order_ctx, ctx->kInv, ctx->k, ctx->tmp); + if (err == MP_OKAY) { + XMEMSET(&ctx->mont_inv_order_ctx, 0, sizeof(ctx->mont_inv_order_ctx)); + ctx->state = 6; + } + break; + case 6: /* KINVNORM */ + sp_256_norm_4(ctx->kInv); + ctx->state = 7; + break; + case 7: /* R */ + /* s = r * x + e */ + sp_256_mul_4(ctx->x, ctx->x, ctx->r); + ctx->state = 8; + break; + case 8: /* S1 */ + err = sp_256_mod_4(ctx->x, ctx->x, p256_order); + if (err == MP_OKAY) + ctx->state = 9; + break; + case 9: /* S2 */ + { + sp_digit carry; + int64_t c; + sp_256_norm_4(ctx->x); + carry = sp_256_add_4(ctx->s, ctx->e, ctx->x); + sp_256_cond_sub_4(ctx->s, ctx->s, p256_order, 0 - carry); + sp_256_norm_4(ctx->s); + c = sp_256_cmp_4(ctx->s, p256_order); + sp_256_cond_sub_4(ctx->s, ctx->s, p256_order, 0L - (sp_digit)(c >= 0)); + sp_256_norm_4(ctx->s); + + /* s = s * k^-1 mod order */ + sp_256_mont_mul_order_4(ctx->s, ctx->s, ctx->kInv); + sp_256_norm_4(ctx->s); + + /* Check that signature is usable. */ + if (sp_256_iszero_4(ctx->s) == 0) { + ctx->state = 10; + break; + } + + /* not usable gen, try again */ + ctx->i--; + if (ctx->i == 0) { + err = RNG_FAILURE_E; + } + ctx->state = 1; + break; + } + case 10: /* RES */ + err = sp_256_to_mp(ctx->r, rm); + if (err == MP_OKAY) { + err = sp_256_to_mp(ctx->s, sm); + } + break; + } + + if (err == MP_OKAY && ctx->state != 10) { + err = FP_WOULDBLOCK; + } + if (err != FP_WOULDBLOCK) { + XMEMSET(ctx->e, 0, sizeof(sp_digit) * 2U * 4U); + XMEMSET(ctx->x, 0, sizeof(sp_digit) * 2U * 4U); + XMEMSET(ctx->k, 0, sizeof(sp_digit) * 2U * 4U); + XMEMSET(ctx->r, 0, sizeof(sp_digit) * 2U * 4U); + XMEMSET(ctx->tmp, 0, sizeof(sp_digit) * 3U * 2U * 4U); + } + + return err; +} +#endif /* WOLFSSL_SP_NONBLOCK */ + int sp_ecc_sign_256(const byte* hash, word32 hashLen, WC_RNG* rng, mp_int* priv, mp_int* rm, mp_int* sm, mp_int* km, void* heap) { @@ -35763,6 +36300,169 @@ int sp_ecc_sign_256(const byte* hash, word32 hashLen, WC_RNG* rng, mp_int* priv, * returns RNG failures, MEMORY_E when memory allocation fails and * MP_OKAY on success. */ +#ifdef WOLFSSL_SP_NONBLOCK +typedef struct sp_ecc_verify_256_ctx { + int state; + union { + sp_256_ecc_mulmod_4_ctx mulmod_ctx; + sp_256_mont_inv_order_4_ctx mont_inv_order_ctx; + sp_256_proj_point_dbl_4_ctx dbl_ctx; + sp_256_proj_point_add_4_ctx add_ctx; + }; + sp_digit u1[2*4]; + sp_digit u2[2*4]; + sp_digit s[2*4]; + sp_digit tmp[2*4 * 5]; + sp_point_256 p1; + sp_point_256 p2; +} sp_ecc_verify_256_ctx; + +int sp_ecc_verify_256_nb(sp_ecc_ctx_t* sp_ctx, const byte* hash, word32 hashLen, mp_int* pX, + mp_int* pY, mp_int* pZ, mp_int* r, mp_int* sm, int* res, void* heap) +{ + int err = FP_WOULDBLOCK; + sp_ecc_verify_256_ctx* ctx = (sp_ecc_verify_256_ctx*)sp_ctx->data; + + typedef char ctx_size_test[sizeof(sp_ecc_verify_256_ctx) >= sizeof(*sp_ctx) ? -1 : 1]; + (void)sizeof(ctx_size_test); + + switch (ctx->state) { + case 0: /* INIT */ + if (hashLen > 32U) { + hashLen = 32U; + } + + sp_256_from_bin(ctx->u1, 4, hash, (int)hashLen); + sp_256_from_mp(ctx->u2, 4, r); + sp_256_from_mp(ctx->s, 4, sm); + sp_256_from_mp(ctx->p2.x, 4, pX); + sp_256_from_mp(ctx->p2.y, 4, pY); + sp_256_from_mp(ctx->p2.z, 4, pZ); + sp_256_mul_4(ctx->s, ctx->s, p256_norm_order); + err = sp_256_mod_4(ctx->s, ctx->s, p256_order); + if (err == MP_OKAY) + ctx->state = 1; + break; + case 1: /* NORMS1 */ + sp_256_norm_4(ctx->s); + XMEMSET(&ctx->mont_inv_order_ctx, 0, sizeof(ctx->mont_inv_order_ctx)); + ctx->state = 2; + break; + case 2: /* NORMS2 */ + err = sp_256_mont_inv_order_4_nb((sp_ecc_ctx_t*)&ctx->mont_inv_order_ctx, ctx->s, ctx->s, ctx->tmp); + if (err == MP_OKAY) { + ctx->state = 3; + } + break; + case 3: /* NORMS3 */ + sp_256_mont_mul_order_4(ctx->u1, ctx->u1, ctx->s); + ctx->state = 4; + break; + case 4: /* NORMS4 */ + sp_256_mont_mul_order_4(ctx->u2, ctx->u2, ctx->s); + XMEMSET(&ctx->mulmod_ctx, 0, sizeof(ctx->mulmod_ctx)); + ctx->state = 5; + break; + case 5: /* MULBASE */ + err = sp_256_ecc_mulmod_4_nb((sp_ecc_ctx_t*)&ctx->mulmod_ctx, &ctx->p1, &p256_base, ctx->u1, 0, heap); + if (err == MP_OKAY) { + XMEMSET(&ctx->mulmod_ctx, 0, sizeof(ctx->mulmod_ctx)); + ctx->state = 6; + } + break; + case 6: /* MULMOD */ + err = sp_256_ecc_mulmod_4_nb((sp_ecc_ctx_t*)&ctx->mulmod_ctx, &ctx->p2, &ctx->p2, ctx->u2, 0, heap); + if (err == MP_OKAY) { + XMEMSET(&ctx->add_ctx, 0, sizeof(ctx->add_ctx)); + ctx->state = 7; + } + break; + case 7: /* ADD */ + err = sp_256_proj_point_add_4_nb((sp_ecc_ctx_t*)&ctx->add_ctx, &ctx->p1, &ctx->p1, &ctx->p2, ctx->tmp); + if (err == MP_OKAY) + ctx->state = 8; + break; + case 8: /* DBLPREP */ + if (sp_256_iszero_4(ctx->p1.z)) { + if (sp_256_iszero_4(ctx->p1.x) && sp_256_iszero_4(ctx->p1.y)) { + XMEMSET(&ctx->dbl_ctx, 0, sizeof(ctx->dbl_ctx)); + ctx->state = 9; + break; + } + else { + /* Y ordinate is not used from here - don't set. */ + int i; + for (i=0; i<4; i++) { + ctx->p1.x[i] = 0; + } + XMEMCPY(ctx->p1.z, p256_norm_mod, sizeof(p256_norm_mod)); + } + } + ctx->state = 10; + break; + case 9: /* DBL */ + err = sp_256_proj_point_dbl_4_nb((sp_ecc_ctx_t*)&ctx->dbl_ctx, &ctx->p1, + &ctx->p2, ctx->tmp); + if (err == MP_OKAY) { + ctx->state = 10; + } + break; + case 10: /* MONT */ + /* (r + n*order).z'.z' mod prime == (u1.G + u2.Q)->x' */ + /* Reload r and convert to Montgomery form. */ + sp_256_from_mp(ctx->u2, 4, r); + err = sp_256_mod_mul_norm_4(ctx->u2, ctx->u2, p256_mod); + if (err == MP_OKAY) + ctx->state = 11; + break; + case 11: /* SQR */ + /* u1 = r.z'.z' mod prime */ + sp_256_mont_sqr_4(ctx->p1.z, ctx->p1.z, p256_mod, p256_mp_mod); + ctx->state = 12; + break; + case 12: /* MUL */ + sp_256_mont_mul_4(ctx->u1, ctx->u2, ctx->p1.z, p256_mod, p256_mp_mod); + ctx->state = 13; + break; + case 13: /* RES */ + err = MP_OKAY; /* math okay, now check result */ + *res = (int)(sp_256_cmp_4(ctx->p1.x, ctx->u1) == 0); + if (*res == 0) { + sp_digit carry; + int64_t c; + + /* Reload r and add order. */ + sp_256_from_mp(ctx->u2, 4, r); + carry = sp_256_add_4(ctx->u2, ctx->u2, p256_order); + /* Carry means result is greater than mod and is not valid. */ + if (carry == 0) { + sp_256_norm_4(ctx->u2); + + /* Compare with mod and if greater or equal then not valid. */ + c = sp_256_cmp_4(ctx->u2, p256_mod); + if (c < 0) { + /* Convert to Montogomery form */ + err = sp_256_mod_mul_norm_4(ctx->u2, ctx->u2, p256_mod); + if (err == MP_OKAY) { + /* u1 = (r + 1*order).z'.z' mod prime */ + sp_256_mont_mul_4(ctx->u1, ctx->u2, ctx->p1.z, p256_mod, + p256_mp_mod); + *res = (int)(sp_256_cmp_4(ctx->p1.x, ctx->u1) == 0); + } + } + } + } + break; + } + + if (err == MP_OKAY && ctx->state != 13) { + err = FP_WOULDBLOCK; + } + + return err; +} +#endif /* WOLFSSL_SP_NONBLOCK */ + int sp_ecc_verify_256(const byte* hash, word32 hashLen, mp_int* pX, mp_int* pY, mp_int* pZ, mp_int* r, mp_int* sm, int* res, void* heap) { @@ -38098,6 +38798,141 @@ static void sp_384_div2_6(sp_digit* r, const sp_digit* a, const sp_digit* m) * p Point to double. * t Temporary ordinate data. */ +#ifdef WOLFSSL_SP_NONBLOCK +typedef struct sp_384_proj_point_dbl_6_ctx { + int state; + sp_digit* t1; + sp_digit* t2; + sp_digit* x; + sp_digit* y; + sp_digit* z; +} sp_384_proj_point_dbl_6_ctx; + +static int sp_384_proj_point_dbl_6_nb(sp_ecc_ctx_t* sp_ctx, sp_point_384* r, const sp_point_384* p, sp_digit* t) +{ + int err = FP_WOULDBLOCK; + sp_384_proj_point_dbl_6_ctx* ctx = (sp_384_proj_point_dbl_6_ctx*)sp_ctx->data; + + typedef char ctx_size_test[sizeof(sp_384_proj_point_dbl_6_ctx) >= sizeof(*sp_ctx) ? -1 : 1]; + (void)sizeof(ctx_size_test); + + switch (ctx->state) { + case 0: + ctx->t1 = t; + ctx->t2 = t + 2*6; + ctx->x = r->x; + ctx->y = r->y; + ctx->z = r->z; + + /* Put infinity into result. */ + if (r != p) { + r->infinity = p->infinity; + } + ctx->state = 1; + break; + case 1: + /* T1 = Z * Z */ + sp_384_mont_sqr_6(ctx->t1, p->z, p384_mod, p384_mp_mod); + ctx->state = 2; + break; + case 2: + /* Z = Y * Z */ + sp_384_mont_mul_6(ctx->z, p->y, p->z, p384_mod, p384_mp_mod); + ctx->state = 3; + break; + case 3: + /* Z = 2Z */ + sp_384_mont_dbl_6(ctx->z, ctx->z, p384_mod); + ctx->state = 4; + break; + case 4: + /* T2 = X - T1 */ + sp_384_mont_sub_6(ctx->t2, p->x, ctx->t1, p384_mod); + ctx->state = 5; + break; + case 5: + /* T1 = X + T1 */ + sp_384_mont_add_6(ctx->t1, p->x, ctx->t1, p384_mod); + ctx->state = 6; + break; + case 6: + /* T2 = T1 * T2 */ + sp_384_mont_mul_6(ctx->t2, ctx->t1, ctx->t2, p384_mod, p384_mp_mod); + ctx->state = 7; + break; + case 7: + /* T1 = 3T2 */ + sp_384_mont_tpl_6(ctx->t1, ctx->t2, p384_mod); + ctx->state = 8; + break; + case 8: + /* Y = 2Y */ + sp_384_mont_dbl_6(ctx->y, p->y, p384_mod); + ctx->state = 9; + break; + case 9: + /* Y = Y * Y */ + sp_384_mont_sqr_6(ctx->y, ctx->y, p384_mod, p384_mp_mod); + ctx->state = 10; + break; + case 10: + /* T2 = Y * Y */ + sp_384_mont_sqr_6(ctx->t2, ctx->y, p384_mod, p384_mp_mod); + ctx->state = 11; + break; + case 11: + /* T2 = T2/2 */ + sp_384_div2_6(ctx->t2, ctx->t2, p384_mod); + ctx->state = 12; + break; + case 12: + /* Y = Y * X */ + sp_384_mont_mul_6(ctx->y, ctx->y, p->x, p384_mod, p384_mp_mod); + ctx->state = 13; + break; + case 13: + /* X = T1 * T1 */ + sp_384_mont_sqr_6(ctx->x, ctx->t1, p384_mod, p384_mp_mod); + ctx->state = 14; + break; + case 14: + /* X = X - Y */ + sp_384_mont_sub_6(ctx->x, ctx->x, ctx->y, p384_mod); + ctx->state = 15; + break; + case 15: + /* X = X - Y */ + sp_384_mont_sub_6(ctx->x, ctx->x, ctx->y, p384_mod); + ctx->state = 16; + break; + case 16: + /* Y = Y - X */ + sp_384_mont_sub_6(ctx->y, ctx->y, ctx->x, p384_mod); + ctx->state = 17; + break; + case 17: + /* Y = Y * T1 */ + sp_384_mont_mul_6(ctx->y, ctx->y, ctx->t1, p384_mod, p384_mp_mod); + ctx->state = 18; + break; + case 18: + /* Y = Y - T2 */ + sp_384_mont_sub_6(ctx->y, ctx->y, ctx->t2, p384_mod); + ctx->state = 19; + /* fall-through */ + case 19: + err = MP_OKAY; + break; + } + + if (err == MP_OKAY && ctx->state != 19) { + err = FP_WOULDBLOCK; + } + + return err; +} +#endif /* WOLFSSL_SP_NONBLOCK */ + static void sp_384_proj_point_dbl_6(sp_point_384* r, const sp_point_384* p, sp_digit* t) { sp_digit* t1 = t; @@ -38260,6 +39095,209 @@ static int sp_384_cmp_equal_6(const sp_digit* a, const sp_digit* b) * q Second point to add. * t Temporary ordinate data. */ + +#ifdef WOLFSSL_SP_NONBLOCK +typedef struct sp_384_proj_point_add_6_ctx { + int state; + sp_384_proj_point_dbl_6_ctx dbl_ctx; + const sp_point_384* ap[2]; + sp_point_384* rp[2]; + sp_digit* t1; + sp_digit* t2; + sp_digit* t3; + sp_digit* t4; + sp_digit* t5; + sp_digit* x; + sp_digit* y; + sp_digit* z; +} sp_384_proj_point_add_6_ctx; + +static int sp_384_proj_point_add_6_nb(sp_ecc_ctx_t* sp_ctx, sp_point_384* r, + const sp_point_384* p, const sp_point_384* q, sp_digit* t) +{ + int err = FP_WOULDBLOCK; + sp_384_proj_point_add_6_ctx* ctx = (sp_384_proj_point_add_6_ctx*)sp_ctx->data; + + /* Ensure only the first point is the same as the result. */ + if (q == r) { + const sp_point_384* a = p; + p = q; + q = a; + } + + typedef char ctx_size_test[sizeof(sp_384_proj_point_add_6_ctx) >= sizeof(*sp_ctx) ? -1 : 1]; + (void)sizeof(ctx_size_test); + + switch (ctx->state) { + case 0: /* INIT */ + ctx->t1 = t; + ctx->t2 = t + 2*6; + ctx->t3 = t + 4*6; + ctx->t4 = t + 6*6; + ctx->t5 = t + 8*6; + + ctx->state = 1; + break; + case 1: + /* Check double */ + (void)sp_384_sub_6(ctx->t1, p384_mod, q->y); + sp_384_norm_6(ctx->t1); + if ((sp_384_cmp_equal_6(p->x, q->x) & sp_384_cmp_equal_6(p->z, q->z) & + (sp_384_cmp_equal_6(p->y, q->y) | sp_384_cmp_equal_6(p->y, ctx->t1))) != 0) + { + XMEMSET(&ctx->dbl_ctx, 0, sizeof(ctx->dbl_ctx)); + ctx->state = 2; + } + else { + ctx->state = 3; + } + break; + case 2: + err = sp_384_proj_point_dbl_6_nb((sp_ecc_ctx_t*)&ctx->dbl_ctx, r, p, t); + if (err == MP_OKAY) + ctx->state = 27; /* done */ + break; + case 3: + { + int i; + ctx->rp[0] = r; + + /*lint allow cast to different type of pointer*/ + ctx->rp[1] = (sp_point_384*)t; /*lint !e9087 !e740*/ + XMEMSET(ctx->rp[1], 0, sizeof(sp_point_384)); + ctx->x = ctx->rp[p->infinity | q->infinity]->x; + ctx->y = ctx->rp[p->infinity | q->infinity]->y; + ctx->z = ctx->rp[p->infinity | q->infinity]->z; + + ctx->ap[0] = p; + ctx->ap[1] = q; + for (i=0; i<6; i++) { + r->x[i] = ctx->ap[p->infinity]->x[i]; + } + for (i=0; i<6; i++) { + r->y[i] = ctx->ap[p->infinity]->y[i]; + } + for (i=0; i<6; i++) { + r->z[i] = ctx->ap[p->infinity]->z[i]; + } + r->infinity = ctx->ap[p->infinity]->infinity; + + ctx->state = 4; + break; + } + case 4: + /* U1 = X1*Z2^2 */ + sp_384_mont_sqr_6(ctx->t1, q->z, p384_mod, p384_mp_mod); + ctx->state = 5; + break; + case 5: + sp_384_mont_mul_6(ctx->t3, ctx->t1, q->z, p384_mod, p384_mp_mod); + ctx->state = 6; + break; + case 6: + sp_384_mont_mul_6(ctx->t1, ctx->t1, ctx->x, p384_mod, p384_mp_mod); + ctx->state = 7; + break; + case 7: + /* U2 = X2*Z1^2 */ + sp_384_mont_sqr_6(ctx->t2, ctx->z, p384_mod, p384_mp_mod); + ctx->state = 8; + break; + case 8: + sp_384_mont_mul_6(ctx->t4, ctx->t2, ctx->z, p384_mod, p384_mp_mod); + ctx->state = 9; + break; + case 9: + sp_384_mont_mul_6(ctx->t2, ctx->t2, q->x, p384_mod, p384_mp_mod); + ctx->state = 10; + break; + case 10: + /* S1 = Y1*Z2^3 */ + sp_384_mont_mul_6(ctx->t3, ctx->t3, ctx->y, p384_mod, p384_mp_mod); + ctx->state = 11; + break; + case 11: + /* S2 = Y2*Z1^3 */ + sp_384_mont_mul_6(ctx->t4, ctx->t4, q->y, p384_mod, p384_mp_mod); + ctx->state = 12; + break; + case 12: + /* H = U2 - U1 */ + sp_384_mont_sub_6(ctx->t2, ctx->t2, ctx->t1, p384_mod); + ctx->state = 13; + break; + case 13: + /* R = S2 - S1 */ + sp_384_mont_sub_6(ctx->t4, ctx->t4, ctx->t3, p384_mod); + ctx->state = 14; + break; + case 14: + /* Z3 = H*Z1*Z2 */ + sp_384_mont_mul_6(ctx->z, ctx->z, q->z, p384_mod, p384_mp_mod); + ctx->state = 15; + break; + case 15: + sp_384_mont_mul_6(ctx->z, ctx->z, ctx->t2, p384_mod, p384_mp_mod); + ctx->state = 16; + break; + case 16: + /* X3 = R^2 - H^3 - 2*U1*H^2 */ + sp_384_mont_sqr_6(ctx->x, ctx->t4, p384_mod, p384_mp_mod); + ctx->state = 17; + break; + case 17: + sp_384_mont_sqr_6(ctx->t5, ctx->t2, p384_mod, p384_mp_mod); + ctx->state = 18; + break; + case 18: + sp_384_mont_mul_6(ctx->y, ctx->t1, ctx->t5, p384_mod, p384_mp_mod); + ctx->state = 19; + break; + case 19: + sp_384_mont_mul_6(ctx->t5, ctx->t5, ctx->t2, p384_mod, p384_mp_mod); + ctx->state = 20; + break; + case 20: + sp_384_mont_sub_6(ctx->x, ctx->x, ctx->t5, p384_mod); + ctx->state = 21; + break; + case 21: + sp_384_mont_dbl_6(ctx->t1, ctx->y, p384_mod); + ctx->state = 22; + break; + case 22: + sp_384_mont_sub_6(ctx->x, ctx->x, ctx->t1, p384_mod); + ctx->state = 23; + break; + case 23: + /* Y3 = R*(U1*H^2 - X3) - S1*H^3 */ + sp_384_mont_sub_6(ctx->y, ctx->y, ctx->x, p384_mod); + ctx->state = 24; + break; + case 24: + sp_384_mont_mul_6(ctx->y, ctx->y, ctx->t4, p384_mod, p384_mp_mod); + ctx->state = 25; + break; + case 25: + sp_384_mont_mul_6(ctx->t5, ctx->t5, ctx->t3, p384_mod, p384_mp_mod); + ctx->state = 26; + break; + case 26: + sp_384_mont_sub_6(ctx->y, ctx->y, ctx->t5, p384_mod); + ctx->state = 27; + /* fall-through */ + case 27: + err = MP_OKAY; + break; + } + + if (err == MP_OKAY && ctx->state != 27) { + err = FP_WOULDBLOCK; + } + return err; +} +#endif /* WOLFSSL_SP_NONBLOCK */ + static void sp_384_proj_point_add_6(sp_point_384* r, const sp_point_384* p, const sp_point_384* q, sp_digit* t) { @@ -41099,6 +42137,46 @@ static void sp_384_mont_sqr_n_order_6(sp_digit* r, const sp_digit* a, int n) * a Number to invert. * td Temporary data. */ + +#ifdef WOLFSSL_SP_NONBLOCK +typedef struct sp_384_mont_inv_order_6_ctx { + int state; + int i; +} sp_384_mont_inv_order_6_ctx; +static int sp_384_mont_inv_order_6_nb(sp_ecc_ctx_t* sp_ctx, sp_digit* r, const sp_digit* a, + sp_digit* t) +{ + int err = FP_WOULDBLOCK; + sp_384_mont_inv_order_6_ctx* ctx = (sp_384_mont_inv_order_6_ctx*)sp_ctx; + + typedef char ctx_size_test[sizeof(sp_384_mont_inv_order_6_ctx) >= sizeof(*sp_ctx) ? -1 : 1]; + (void)sizeof(ctx_size_test); + + switch (ctx->state) { + case 0: + XMEMCPY(t, a, sizeof(sp_digit) * 6); + ctx->i = 382; + ctx->state = 1; + break; + case 1: + sp_384_mont_sqr_order_6(t, t); + if ((p384_order_minus_2[ctx->i / 64] & ((sp_int_digit)1 << (ctx->i % 64))) != 0) { + sp_384_mont_mul_order_6(t, t, a); + } + ctx->i--; + if (ctx->i == 0) { + ctx->state = 2; + } + break; + case 2: + XMEMCPY(r, t, sizeof(sp_digit) * 6U); + err = MP_OKAY; + break; + } + return err; +} +#endif /* WOLFSSL_SP_NONBLOCK */ + static void sp_384_mont_inv_order_6(sp_digit* r, const sp_digit* a, sp_digit* td) { @@ -41185,6 +42263,165 @@ static void sp_384_mont_inv_order_6(sp_digit* r, const sp_digit* a, * returns RNG failures, MEMORY_E when memory allocation fails and * MP_OKAY on success. */ +#ifdef WOLFSSL_SP_NONBLOCK +typedef struct sp_ecc_sign_384_ctx { + int state; + union { + sp_384_ecc_mulmod_6_ctx mulmod_ctx; + sp_384_mont_inv_order_6_ctx mont_inv_order_ctx; + }; + sp_digit e[2*6]; + sp_digit x[2*6]; + sp_digit k[2*6]; + sp_digit r[2*6]; + sp_digit tmp[3 * 2*6]; + sp_point_384 point; + sp_digit* s; + sp_digit* kInv; + int i; +} sp_ecc_sign_384_ctx; + +int sp_ecc_sign_384_nb(sp_ecc_ctx_t* sp_ctx, const byte* hash, word32 hashLen, WC_RNG* rng, mp_int* priv, + mp_int* rm, mp_int* sm, mp_int* km, void* heap) +{ + int err = FP_WOULDBLOCK; + sp_ecc_sign_384_ctx* ctx = (sp_ecc_sign_384_ctx*)sp_ctx->data; + + typedef char ctx_size_test[sizeof(sp_ecc_sign_384_ctx) >= sizeof(*sp_ctx) ? -1 : 1]; + (void)sizeof(ctx_size_test); + + (void)heap; + + switch (ctx->state) { + case 0: /* INIT */ + ctx->s = ctx->e; + ctx->kInv = ctx->k; + if (hashLen > 48U) { + hashLen = 48U; + } + + sp_384_from_bin(ctx->e, 6, hash, (int)hashLen); + + ctx->i = SP_ECC_MAX_SIG_GEN; + ctx->state = 1; + break; + case 1: /* GEN */ + sp_384_from_mp(ctx->x, 6, priv); + /* New random point. */ + if (km == NULL || mp_iszero(km)) { + err = sp_384_ecc_gen_k_6(rng, ctx->k); + } + else { + sp_384_from_mp(ctx->k, 6, km); + mp_zero(km); + } + XMEMSET(&ctx->mulmod_ctx, 0, sizeof(ctx->mulmod_ctx)); + ctx->state = 2; + break; + case 2: /* MULMOD */ + err = sp_384_ecc_mulmod_6_nb((sp_ecc_ctx_t*)&ctx->mulmod_ctx, + &ctx->point, &p384_base, ctx->k, 1, heap); + if (err == MP_OKAY) { + ctx->state = 3; + } + break; + case 3: /* MODORDER */ + { + int64_t c; + /* r = point->x mod order */ + XMEMCPY(ctx->r, ctx->point.x, sizeof(sp_digit) * 6U); + sp_384_norm_6(ctx->r); + c = sp_384_cmp_6(ctx->r, p384_order); + sp_384_cond_sub_6(ctx->r, ctx->r, p384_order, 0L - (sp_digit)(c >= 0)); + sp_384_norm_6(ctx->r); + ctx->state = 4; + break; + } + case 4: /* KMODORDER */ + /* Conv k to Montgomery form (mod order) */ + sp_384_mul_6(ctx->k, ctx->k, p384_norm_order); + err = sp_384_mod_6(ctx->k, ctx->k, p384_order); + if (err == MP_OKAY) { + sp_384_norm_6(ctx->k); + XMEMSET(&ctx->mont_inv_order_ctx, 0, sizeof(ctx->mont_inv_order_ctx)); + ctx->state = 5; + } + break; + case 5: /* KINV */ + /* kInv = 1/k mod order */ + err = sp_384_mont_inv_order_6_nb((sp_ecc_ctx_t*)&ctx->mont_inv_order_ctx, ctx->kInv, ctx->k, ctx->tmp); + if (err == MP_OKAY) { + XMEMSET(&ctx->mont_inv_order_ctx, 0, sizeof(ctx->mont_inv_order_ctx)); + ctx->state = 6; + } + break; + case 6: /* KINVNORM */ + sp_384_norm_6(ctx->kInv); + ctx->state = 7; + break; + case 7: /* R */ + /* s = r * x + e */ + sp_384_mul_6(ctx->x, ctx->x, ctx->r); + ctx->state = 8; + break; + case 8: /* S1 */ + err = sp_384_mod_6(ctx->x, ctx->x, p384_order); + if (err == MP_OKAY) + ctx->state = 9; + break; + case 9: /* S2 */ + { + sp_digit carry; + int64_t c; + sp_384_norm_6(ctx->x); + carry = sp_384_add_6(ctx->s, ctx->e, ctx->x); + sp_384_cond_sub_6(ctx->s, ctx->s, p384_order, 0 - carry); + sp_384_norm_6(ctx->s); + c = sp_384_cmp_6(ctx->s, p384_order); + sp_384_cond_sub_6(ctx->s, ctx->s, p384_order, 0L - (sp_digit)(c >= 0)); + sp_384_norm_6(ctx->s); + + /* s = s * k^-1 mod order */ + sp_384_mont_mul_order_6(ctx->s, ctx->s, ctx->kInv); + sp_384_norm_6(ctx->s); + + /* Check that signature is usable. */ + if (sp_384_iszero_6(ctx->s) == 0) { + ctx->state = 10; + break; + } + + /* not usable gen, try again */ + ctx->i--; + if (ctx->i == 0) { + err = RNG_FAILURE_E; + } + ctx->state = 1; + break; + } + case 10: /* RES */ + err = sp_384_to_mp(ctx->r, rm); + if (err == MP_OKAY) { + err = sp_384_to_mp(ctx->s, sm); + } + break; + } + + if (err == MP_OKAY && ctx->state != 10) { + err = FP_WOULDBLOCK; + } + if (err != FP_WOULDBLOCK) { + XMEMSET(ctx->e, 0, sizeof(sp_digit) * 2U * 6U); + XMEMSET(ctx->x, 0, sizeof(sp_digit) * 2U * 6U); + XMEMSET(ctx->k, 0, sizeof(sp_digit) * 2U * 6U); + XMEMSET(ctx->r, 0, sizeof(sp_digit) * 2U * 6U); + XMEMSET(ctx->tmp, 0, sizeof(sp_digit) * 3U * 2U * 6U); + } + + return err; +} +#endif /* WOLFSSL_SP_NONBLOCK */ + int sp_ecc_sign_384(const byte* hash, word32 hashLen, WC_RNG* rng, mp_int* priv, mp_int* rm, mp_int* sm, mp_int* km, void* heap) { @@ -41356,6 +42593,169 @@ int sp_ecc_sign_384(const byte* hash, word32 hashLen, WC_RNG* rng, mp_int* priv, * returns RNG failures, MEMORY_E when memory allocation fails and * MP_OKAY on success. */ +#ifdef WOLFSSL_SP_NONBLOCK +typedef struct sp_ecc_verify_384_ctx { + int state; + union { + sp_384_ecc_mulmod_6_ctx mulmod_ctx; + sp_384_mont_inv_order_6_ctx mont_inv_order_ctx; + sp_384_proj_point_dbl_6_ctx dbl_ctx; + sp_384_proj_point_add_6_ctx add_ctx; + }; + sp_digit u1[2*6]; + sp_digit u2[2*6]; + sp_digit s[2*6]; + sp_digit tmp[2*6 * 5]; + sp_point_384 p1; + sp_point_384 p2; +} sp_ecc_verify_384_ctx; + +int sp_ecc_verify_384_nb(sp_ecc_ctx_t* sp_ctx, const byte* hash, word32 hashLen, mp_int* pX, + mp_int* pY, mp_int* pZ, mp_int* r, mp_int* sm, int* res, void* heap) +{ + int err = FP_WOULDBLOCK; + sp_ecc_verify_384_ctx* ctx = (sp_ecc_verify_384_ctx*)sp_ctx->data; + + typedef char ctx_size_test[sizeof(sp_ecc_verify_384_ctx) >= sizeof(*sp_ctx) ? -1 : 1]; + (void)sizeof(ctx_size_test); + + switch (ctx->state) { + case 0: /* INIT */ + if (hashLen > 48U) { + hashLen = 48U; + } + + sp_384_from_bin(ctx->u1, 6, hash, (int)hashLen); + sp_384_from_mp(ctx->u2, 6, r); + sp_384_from_mp(ctx->s, 6, sm); + sp_384_from_mp(ctx->p2.x, 6, pX); + sp_384_from_mp(ctx->p2.y, 6, pY); + sp_384_from_mp(ctx->p2.z, 6, pZ); + sp_384_mul_6(ctx->s, ctx->s, p384_norm_order); + err = sp_384_mod_6(ctx->s, ctx->s, p384_order); + if (err == MP_OKAY) + ctx->state = 1; + break; + case 1: /* NORMS1 */ + sp_384_norm_6(ctx->s); + XMEMSET(&ctx->mont_inv_order_ctx, 0, sizeof(ctx->mont_inv_order_ctx)); + ctx->state = 2; + break; + case 2: /* NORMS2 */ + err = sp_384_mont_inv_order_6_nb((sp_ecc_ctx_t*)&ctx->mont_inv_order_ctx, ctx->s, ctx->s, ctx->tmp); + if (err == MP_OKAY) { + ctx->state = 3; + } + break; + case 3: /* NORMS3 */ + sp_384_mont_mul_order_6(ctx->u1, ctx->u1, ctx->s); + ctx->state = 4; + break; + case 4: /* NORMS4 */ + sp_384_mont_mul_order_6(ctx->u2, ctx->u2, ctx->s); + XMEMSET(&ctx->mulmod_ctx, 0, sizeof(ctx->mulmod_ctx)); + ctx->state = 5; + break; + case 5: /* MULBASE */ + err = sp_384_ecc_mulmod_6_nb((sp_ecc_ctx_t*)&ctx->mulmod_ctx, &ctx->p1, &p384_base, ctx->u1, 0, heap); + if (err == MP_OKAY) { + XMEMSET(&ctx->mulmod_ctx, 0, sizeof(ctx->mulmod_ctx)); + ctx->state = 6; + } + break; + case 6: /* MULMOD */ + err = sp_384_ecc_mulmod_6_nb((sp_ecc_ctx_t*)&ctx->mulmod_ctx, &ctx->p2, &ctx->p2, ctx->u2, 0, heap); + if (err == MP_OKAY) { + XMEMSET(&ctx->add_ctx, 0, sizeof(ctx->add_ctx)); + ctx->state = 7; + } + break; + case 7: /* ADD */ + err = sp_384_proj_point_add_6_nb((sp_ecc_ctx_t*)&ctx->add_ctx, &ctx->p1, &ctx->p1, &ctx->p2, ctx->tmp); + if (err == MP_OKAY) + ctx->state = 8; + break; + case 8: /* DBLPREP */ + if (sp_384_iszero_6(ctx->p1.z)) { + if (sp_384_iszero_6(ctx->p1.x) && sp_384_iszero_6(ctx->p1.y)) { + XMEMSET(&ctx->dbl_ctx, 0, sizeof(ctx->dbl_ctx)); + ctx->state = 9; + break; + } + else { + /* Y ordinate is not used from here - don't set. */ + int i; + for (i=0; i<6; i++) { + ctx->p1.x[i] = 0; + } + XMEMCPY(ctx->p1.z, p384_norm_mod, sizeof(p384_norm_mod)); + } + } + ctx->state = 10; + break; + case 9: /* DBL */ + err = sp_384_proj_point_dbl_6_nb((sp_ecc_ctx_t*)&ctx->dbl_ctx, &ctx->p1, + &ctx->p2, ctx->tmp); + if (err == MP_OKAY) { + ctx->state = 10; + } + break; + case 10: /* MONT */ + /* (r + n*order).z'.z' mod prime == (u1.G + u2.Q)->x' */ + /* Reload r and convert to Montgomery form. */ + sp_384_from_mp(ctx->u2, 6, r); + err = sp_384_mod_mul_norm_6(ctx->u2, ctx->u2, p384_mod); + if (err == MP_OKAY) + ctx->state = 11; + break; + case 11: /* SQR */ + /* u1 = r.z'.z' mod prime */ + sp_384_mont_sqr_6(ctx->p1.z, ctx->p1.z, p384_mod, p384_mp_mod); + ctx->state = 12; + break; + case 12: /* MUL */ + sp_384_mont_mul_6(ctx->u1, ctx->u2, ctx->p1.z, p384_mod, p384_mp_mod); + ctx->state = 13; + break; + case 13: /* RES */ + err = MP_OKAY; /* math okay, now check result */ + *res = (int)(sp_384_cmp_6(ctx->p1.x, ctx->u1) == 0); + if (*res == 0) { + sp_digit carry; + int64_t c; + + /* Reload r and add order. */ + sp_384_from_mp(ctx->u2, 6, r); + carry = sp_384_add_6(ctx->u2, ctx->u2, p384_order); + /* Carry means result is greater than mod and is not valid. */ + if (carry == 0) { + sp_384_norm_6(ctx->u2); + + /* Compare with mod and if greater or equal then not valid. */ + c = sp_384_cmp_6(ctx->u2, p384_mod); + if (c < 0) { + /* Convert to Montogomery form */ + err = sp_384_mod_mul_norm_6(ctx->u2, ctx->u2, p384_mod); + if (err == MP_OKAY) { + /* u1 = (r + 1*order).z'.z' mod prime */ + sp_384_mont_mul_6(ctx->u1, ctx->u2, ctx->p1.z, p384_mod, + p384_mp_mod); + *res = (int)(sp_384_cmp_6(ctx->p1.x, ctx->u1) == 0); + } + } + } + } + break; + } + + if (err == MP_OKAY && ctx->state != 13) { + err = FP_WOULDBLOCK; + } + + return err; +} +#endif /* WOLFSSL_SP_NONBLOCK */ + int sp_ecc_verify_384(const byte* hash, word32 hashLen, mp_int* pX, mp_int* pY, mp_int* pZ, mp_int* r, mp_int* sm, int* res, void* heap) { diff --git a/wolfcrypt/src/sp_armthumb.c b/wolfcrypt/src/sp_armthumb.c index b1c23b8d2f..0463607980 100644 --- a/wolfcrypt/src/sp_armthumb.c +++ b/wolfcrypt/src/sp_armthumb.c @@ -17060,6 +17060,141 @@ SP_NOINLINE static void sp_256_div2_8(sp_digit* r, const sp_digit* a, const sp_d * p Point to double. * t Temporary ordinate data. */ +#ifdef WOLFSSL_SP_NONBLOCK +typedef struct sp_256_proj_point_dbl_8_ctx { + int state; + sp_digit* t1; + sp_digit* t2; + sp_digit* x; + sp_digit* y; + sp_digit* z; +} sp_256_proj_point_dbl_8_ctx; + +static int sp_256_proj_point_dbl_8_nb(sp_ecc_ctx_t* sp_ctx, sp_point_256* r, const sp_point_256* p, sp_digit* t) +{ + int err = FP_WOULDBLOCK; + sp_256_proj_point_dbl_8_ctx* ctx = (sp_256_proj_point_dbl_8_ctx*)sp_ctx->data; + + typedef char ctx_size_test[sizeof(sp_256_proj_point_dbl_8_ctx) >= sizeof(*sp_ctx) ? -1 : 1]; + (void)sizeof(ctx_size_test); + + switch (ctx->state) { + case 0: + ctx->t1 = t; + ctx->t2 = t + 2*8; + ctx->x = r->x; + ctx->y = r->y; + ctx->z = r->z; + + /* Put infinity into result. */ + if (r != p) { + r->infinity = p->infinity; + } + ctx->state = 1; + break; + case 1: + /* T1 = Z * Z */ + sp_256_mont_sqr_8(ctx->t1, p->z, p256_mod, p256_mp_mod); + ctx->state = 2; + break; + case 2: + /* Z = Y * Z */ + sp_256_mont_mul_8(ctx->z, p->y, p->z, p256_mod, p256_mp_mod); + ctx->state = 3; + break; + case 3: + /* Z = 2Z */ + sp_256_mont_dbl_8(ctx->z, ctx->z, p256_mod); + ctx->state = 4; + break; + case 4: + /* T2 = X - T1 */ + sp_256_mont_sub_8(ctx->t2, p->x, ctx->t1, p256_mod); + ctx->state = 5; + break; + case 5: + /* T1 = X + T1 */ + sp_256_mont_add_8(ctx->t1, p->x, ctx->t1, p256_mod); + ctx->state = 6; + break; + case 6: + /* T2 = T1 * T2 */ + sp_256_mont_mul_8(ctx->t2, ctx->t1, ctx->t2, p256_mod, p256_mp_mod); + ctx->state = 7; + break; + case 7: + /* T1 = 3T2 */ + sp_256_mont_tpl_8(ctx->t1, ctx->t2, p256_mod); + ctx->state = 8; + break; + case 8: + /* Y = 2Y */ + sp_256_mont_dbl_8(ctx->y, p->y, p256_mod); + ctx->state = 9; + break; + case 9: + /* Y = Y * Y */ + sp_256_mont_sqr_8(ctx->y, ctx->y, p256_mod, p256_mp_mod); + ctx->state = 10; + break; + case 10: + /* T2 = Y * Y */ + sp_256_mont_sqr_8(ctx->t2, ctx->y, p256_mod, p256_mp_mod); + ctx->state = 11; + break; + case 11: + /* T2 = T2/2 */ + sp_256_div2_8(ctx->t2, ctx->t2, p256_mod); + ctx->state = 12; + break; + case 12: + /* Y = Y * X */ + sp_256_mont_mul_8(ctx->y, ctx->y, p->x, p256_mod, p256_mp_mod); + ctx->state = 13; + break; + case 13: + /* X = T1 * T1 */ + sp_256_mont_sqr_8(ctx->x, ctx->t1, p256_mod, p256_mp_mod); + ctx->state = 14; + break; + case 14: + /* X = X - Y */ + sp_256_mont_sub_8(ctx->x, ctx->x, ctx->y, p256_mod); + ctx->state = 15; + break; + case 15: + /* X = X - Y */ + sp_256_mont_sub_8(ctx->x, ctx->x, ctx->y, p256_mod); + ctx->state = 16; + break; + case 16: + /* Y = Y - X */ + sp_256_mont_sub_8(ctx->y, ctx->y, ctx->x, p256_mod); + ctx->state = 17; + break; + case 17: + /* Y = Y * T1 */ + sp_256_mont_mul_8(ctx->y, ctx->y, ctx->t1, p256_mod, p256_mp_mod); + ctx->state = 18; + break; + case 18: + /* Y = Y - T2 */ + sp_256_mont_sub_8(ctx->y, ctx->y, ctx->t2, p256_mod); + ctx->state = 19; + /* fall-through */ + case 19: + err = MP_OKAY; + break; + } + + if (err == MP_OKAY && ctx->state != 19) { + err = FP_WOULDBLOCK; + } + + return err; +} +#endif /* WOLFSSL_SP_NONBLOCK */ + static void sp_256_proj_point_dbl_8(sp_point_256* r, const sp_point_256* p, sp_digit* t) { sp_digit* t1 = t; @@ -17225,6 +17360,209 @@ static int sp_256_cmp_equal_8(const sp_digit* a, const sp_digit* b) * q Second point to add. * t Temporary ordinate data. */ + +#ifdef WOLFSSL_SP_NONBLOCK +typedef struct sp_256_proj_point_add_8_ctx { + int state; + sp_256_proj_point_dbl_8_ctx dbl_ctx; + const sp_point_256* ap[2]; + sp_point_256* rp[2]; + sp_digit* t1; + sp_digit* t2; + sp_digit* t3; + sp_digit* t4; + sp_digit* t5; + sp_digit* x; + sp_digit* y; + sp_digit* z; +} sp_256_proj_point_add_8_ctx; + +static int sp_256_proj_point_add_8_nb(sp_ecc_ctx_t* sp_ctx, sp_point_256* r, + const sp_point_256* p, const sp_point_256* q, sp_digit* t) +{ + int err = FP_WOULDBLOCK; + sp_256_proj_point_add_8_ctx* ctx = (sp_256_proj_point_add_8_ctx*)sp_ctx->data; + + /* Ensure only the first point is the same as the result. */ + if (q == r) { + const sp_point_256* a = p; + p = q; + q = a; + } + + typedef char ctx_size_test[sizeof(sp_256_proj_point_add_8_ctx) >= sizeof(*sp_ctx) ? -1 : 1]; + (void)sizeof(ctx_size_test); + + switch (ctx->state) { + case 0: /* INIT */ + ctx->t1 = t; + ctx->t2 = t + 2*8; + ctx->t3 = t + 4*8; + ctx->t4 = t + 6*8; + ctx->t5 = t + 8*8; + + ctx->state = 1; + break; + case 1: + /* Check double */ + (void)sp_256_sub_8(ctx->t1, p256_mod, q->y); + sp_256_norm_8(ctx->t1); + if ((sp_256_cmp_equal_8(p->x, q->x) & sp_256_cmp_equal_8(p->z, q->z) & + (sp_256_cmp_equal_8(p->y, q->y) | sp_256_cmp_equal_8(p->y, ctx->t1))) != 0) + { + XMEMSET(&ctx->dbl_ctx, 0, sizeof(ctx->dbl_ctx)); + ctx->state = 2; + } + else { + ctx->state = 3; + } + break; + case 2: + err = sp_256_proj_point_dbl_8_nb((sp_ecc_ctx_t*)&ctx->dbl_ctx, r, p, t); + if (err == MP_OKAY) + ctx->state = 27; /* done */ + break; + case 3: + { + int i; + ctx->rp[0] = r; + + /*lint allow cast to different type of pointer*/ + ctx->rp[1] = (sp_point_256*)t; /*lint !e9087 !e740*/ + XMEMSET(ctx->rp[1], 0, sizeof(sp_point_256)); + ctx->x = ctx->rp[p->infinity | q->infinity]->x; + ctx->y = ctx->rp[p->infinity | q->infinity]->y; + ctx->z = ctx->rp[p->infinity | q->infinity]->z; + + ctx->ap[0] = p; + ctx->ap[1] = q; + for (i=0; i<8; i++) { + r->x[i] = ctx->ap[p->infinity]->x[i]; + } + for (i=0; i<8; i++) { + r->y[i] = ctx->ap[p->infinity]->y[i]; + } + for (i=0; i<8; i++) { + r->z[i] = ctx->ap[p->infinity]->z[i]; + } + r->infinity = ctx->ap[p->infinity]->infinity; + + ctx->state = 4; + break; + } + case 4: + /* U1 = X1*Z2^2 */ + sp_256_mont_sqr_8(ctx->t1, q->z, p256_mod, p256_mp_mod); + ctx->state = 5; + break; + case 5: + sp_256_mont_mul_8(ctx->t3, ctx->t1, q->z, p256_mod, p256_mp_mod); + ctx->state = 6; + break; + case 6: + sp_256_mont_mul_8(ctx->t1, ctx->t1, ctx->x, p256_mod, p256_mp_mod); + ctx->state = 7; + break; + case 7: + /* U2 = X2*Z1^2 */ + sp_256_mont_sqr_8(ctx->t2, ctx->z, p256_mod, p256_mp_mod); + ctx->state = 8; + break; + case 8: + sp_256_mont_mul_8(ctx->t4, ctx->t2, ctx->z, p256_mod, p256_mp_mod); + ctx->state = 9; + break; + case 9: + sp_256_mont_mul_8(ctx->t2, ctx->t2, q->x, p256_mod, p256_mp_mod); + ctx->state = 10; + break; + case 10: + /* S1 = Y1*Z2^3 */ + sp_256_mont_mul_8(ctx->t3, ctx->t3, ctx->y, p256_mod, p256_mp_mod); + ctx->state = 11; + break; + case 11: + /* S2 = Y2*Z1^3 */ + sp_256_mont_mul_8(ctx->t4, ctx->t4, q->y, p256_mod, p256_mp_mod); + ctx->state = 12; + break; + case 12: + /* H = U2 - U1 */ + sp_256_mont_sub_8(ctx->t2, ctx->t2, ctx->t1, p256_mod); + ctx->state = 13; + break; + case 13: + /* R = S2 - S1 */ + sp_256_mont_sub_8(ctx->t4, ctx->t4, ctx->t3, p256_mod); + ctx->state = 14; + break; + case 14: + /* Z3 = H*Z1*Z2 */ + sp_256_mont_mul_8(ctx->z, ctx->z, q->z, p256_mod, p256_mp_mod); + ctx->state = 15; + break; + case 15: + sp_256_mont_mul_8(ctx->z, ctx->z, ctx->t2, p256_mod, p256_mp_mod); + ctx->state = 16; + break; + case 16: + /* X3 = R^2 - H^3 - 2*U1*H^2 */ + sp_256_mont_sqr_8(ctx->x, ctx->t4, p256_mod, p256_mp_mod); + ctx->state = 17; + break; + case 17: + sp_256_mont_sqr_8(ctx->t5, ctx->t2, p256_mod, p256_mp_mod); + ctx->state = 18; + break; + case 18: + sp_256_mont_mul_8(ctx->y, ctx->t1, ctx->t5, p256_mod, p256_mp_mod); + ctx->state = 19; + break; + case 19: + sp_256_mont_mul_8(ctx->t5, ctx->t5, ctx->t2, p256_mod, p256_mp_mod); + ctx->state = 20; + break; + case 20: + sp_256_mont_sub_8(ctx->x, ctx->x, ctx->t5, p256_mod); + ctx->state = 21; + break; + case 21: + sp_256_mont_dbl_8(ctx->t1, ctx->y, p256_mod); + ctx->state = 22; + break; + case 22: + sp_256_mont_sub_8(ctx->x, ctx->x, ctx->t1, p256_mod); + ctx->state = 23; + break; + case 23: + /* Y3 = R*(U1*H^2 - X3) - S1*H^3 */ + sp_256_mont_sub_8(ctx->y, ctx->y, ctx->x, p256_mod); + ctx->state = 24; + break; + case 24: + sp_256_mont_mul_8(ctx->y, ctx->y, ctx->t4, p256_mod, p256_mp_mod); + ctx->state = 25; + break; + case 25: + sp_256_mont_mul_8(ctx->t5, ctx->t5, ctx->t3, p256_mod, p256_mp_mod); + ctx->state = 26; + break; + case 26: + sp_256_mont_sub_8(ctx->y, ctx->y, ctx->t5, p256_mod); + ctx->state = 27; + /* fall-through */ + case 27: + err = MP_OKAY; + break; + } + + if (err == MP_OKAY && ctx->state != 27) { + err = FP_WOULDBLOCK; + } + return err; +} +#endif /* WOLFSSL_SP_NONBLOCK */ + static void sp_256_proj_point_add_8(sp_point_256* r, const sp_point_256* p, const sp_point_256* q, sp_digit* t) { @@ -20479,6 +20817,46 @@ static void sp_256_mont_sqr_n_order_8(sp_digit* r, const sp_digit* a, int n) * a Number to invert. * td Temporary data. */ + +#ifdef WOLFSSL_SP_NONBLOCK +typedef struct sp_256_mont_inv_order_8_ctx { + int state; + int i; +} sp_256_mont_inv_order_8_ctx; +static int sp_256_mont_inv_order_8_nb(sp_ecc_ctx_t* sp_ctx, sp_digit* r, const sp_digit* a, + sp_digit* t) +{ + int err = FP_WOULDBLOCK; + sp_256_mont_inv_order_8_ctx* ctx = (sp_256_mont_inv_order_8_ctx*)sp_ctx; + + typedef char ctx_size_test[sizeof(sp_256_mont_inv_order_8_ctx) >= sizeof(*sp_ctx) ? -1 : 1]; + (void)sizeof(ctx_size_test); + + switch (ctx->state) { + case 0: + XMEMCPY(t, a, sizeof(sp_digit) * 8); + ctx->i = 254; + ctx->state = 1; + break; + case 1: + sp_256_mont_sqr_order_8(t, t); + if ((p256_order_minus_2[ctx->i / 32] & ((sp_int_digit)1 << (ctx->i % 32))) != 0) { + sp_256_mont_mul_order_8(t, t, a); + } + ctx->i--; + if (ctx->i == 0) { + ctx->state = 2; + } + break; + case 2: + XMEMCPY(r, t, sizeof(sp_digit) * 8U); + err = MP_OKAY; + break; + } + return err; +} +#endif /* WOLFSSL_SP_NONBLOCK */ + static void sp_256_mont_inv_order_8(sp_digit* r, const sp_digit* a, sp_digit* td) { @@ -20594,6 +20972,165 @@ static void sp_256_mont_inv_order_8(sp_digit* r, const sp_digit* a, * returns RNG failures, MEMORY_E when memory allocation fails and * MP_OKAY on success. */ +#ifdef WOLFSSL_SP_NONBLOCK +typedef struct sp_ecc_sign_256_ctx { + int state; + union { + sp_256_ecc_mulmod_8_ctx mulmod_ctx; + sp_256_mont_inv_order_8_ctx mont_inv_order_ctx; + }; + sp_digit e[2*8]; + sp_digit x[2*8]; + sp_digit k[2*8]; + sp_digit r[2*8]; + sp_digit tmp[3 * 2*8]; + sp_point_256 point; + sp_digit* s; + sp_digit* kInv; + int i; +} sp_ecc_sign_256_ctx; + +int sp_ecc_sign_256_nb(sp_ecc_ctx_t* sp_ctx, const byte* hash, word32 hashLen, WC_RNG* rng, mp_int* priv, + mp_int* rm, mp_int* sm, mp_int* km, void* heap) +{ + int err = FP_WOULDBLOCK; + sp_ecc_sign_256_ctx* ctx = (sp_ecc_sign_256_ctx*)sp_ctx->data; + + typedef char ctx_size_test[sizeof(sp_ecc_sign_256_ctx) >= sizeof(*sp_ctx) ? -1 : 1]; + (void)sizeof(ctx_size_test); + + (void)heap; + + switch (ctx->state) { + case 0: /* INIT */ + ctx->s = ctx->e; + ctx->kInv = ctx->k; + if (hashLen > 32U) { + hashLen = 32U; + } + + sp_256_from_bin(ctx->e, 8, hash, (int)hashLen); + + ctx->i = SP_ECC_MAX_SIG_GEN; + ctx->state = 1; + break; + case 1: /* GEN */ + sp_256_from_mp(ctx->x, 8, priv); + /* New random point. */ + if (km == NULL || mp_iszero(km)) { + err = sp_256_ecc_gen_k_8(rng, ctx->k); + } + else { + sp_256_from_mp(ctx->k, 8, km); + mp_zero(km); + } + XMEMSET(&ctx->mulmod_ctx, 0, sizeof(ctx->mulmod_ctx)); + ctx->state = 2; + break; + case 2: /* MULMOD */ + err = sp_256_ecc_mulmod_8_nb((sp_ecc_ctx_t*)&ctx->mulmod_ctx, + &ctx->point, &p256_base, ctx->k, 1, heap); + if (err == MP_OKAY) { + ctx->state = 3; + } + break; + case 3: /* MODORDER */ + { + int32_t c; + /* r = point->x mod order */ + XMEMCPY(ctx->r, ctx->point.x, sizeof(sp_digit) * 8U); + sp_256_norm_8(ctx->r); + c = sp_256_cmp_8(ctx->r, p256_order); + sp_256_cond_sub_8(ctx->r, ctx->r, p256_order, 0L - (sp_digit)(c >= 0)); + sp_256_norm_8(ctx->r); + ctx->state = 4; + break; + } + case 4: /* KMODORDER */ + /* Conv k to Montgomery form (mod order) */ + sp_256_mul_8(ctx->k, ctx->k, p256_norm_order); + err = sp_256_mod_8(ctx->k, ctx->k, p256_order); + if (err == MP_OKAY) { + sp_256_norm_8(ctx->k); + XMEMSET(&ctx->mont_inv_order_ctx, 0, sizeof(ctx->mont_inv_order_ctx)); + ctx->state = 5; + } + break; + case 5: /* KINV */ + /* kInv = 1/k mod order */ + err = sp_256_mont_inv_order_8_nb((sp_ecc_ctx_t*)&ctx->mont_inv_order_ctx, ctx->kInv, ctx->k, ctx->tmp); + if (err == MP_OKAY) { + XMEMSET(&ctx->mont_inv_order_ctx, 0, sizeof(ctx->mont_inv_order_ctx)); + ctx->state = 6; + } + break; + case 6: /* KINVNORM */ + sp_256_norm_8(ctx->kInv); + ctx->state = 7; + break; + case 7: /* R */ + /* s = r * x + e */ + sp_256_mul_8(ctx->x, ctx->x, ctx->r); + ctx->state = 8; + break; + case 8: /* S1 */ + err = sp_256_mod_8(ctx->x, ctx->x, p256_order); + if (err == MP_OKAY) + ctx->state = 9; + break; + case 9: /* S2 */ + { + sp_digit carry; + int32_t c; + sp_256_norm_8(ctx->x); + carry = sp_256_add_8(ctx->s, ctx->e, ctx->x); + sp_256_cond_sub_8(ctx->s, ctx->s, p256_order, 0 - carry); + sp_256_norm_8(ctx->s); + c = sp_256_cmp_8(ctx->s, p256_order); + sp_256_cond_sub_8(ctx->s, ctx->s, p256_order, 0L - (sp_digit)(c >= 0)); + sp_256_norm_8(ctx->s); + + /* s = s * k^-1 mod order */ + sp_256_mont_mul_order_8(ctx->s, ctx->s, ctx->kInv); + sp_256_norm_8(ctx->s); + + /* Check that signature is usable. */ + if (sp_256_iszero_8(ctx->s) == 0) { + ctx->state = 10; + break; + } + + /* not usable gen, try again */ + ctx->i--; + if (ctx->i == 0) { + err = RNG_FAILURE_E; + } + ctx->state = 1; + break; + } + case 10: /* RES */ + err = sp_256_to_mp(ctx->r, rm); + if (err == MP_OKAY) { + err = sp_256_to_mp(ctx->s, sm); + } + break; + } + + if (err == MP_OKAY && ctx->state != 10) { + err = FP_WOULDBLOCK; + } + if (err != FP_WOULDBLOCK) { + XMEMSET(ctx->e, 0, sizeof(sp_digit) * 2U * 8U); + XMEMSET(ctx->x, 0, sizeof(sp_digit) * 2U * 8U); + XMEMSET(ctx->k, 0, sizeof(sp_digit) * 2U * 8U); + XMEMSET(ctx->r, 0, sizeof(sp_digit) * 2U * 8U); + XMEMSET(ctx->tmp, 0, sizeof(sp_digit) * 3U * 2U * 8U); + } + + return err; +} +#endif /* WOLFSSL_SP_NONBLOCK */ + int sp_ecc_sign_256(const byte* hash, word32 hashLen, WC_RNG* rng, mp_int* priv, mp_int* rm, mp_int* sm, mp_int* km, void* heap) { @@ -20765,6 +21302,169 @@ int sp_ecc_sign_256(const byte* hash, word32 hashLen, WC_RNG* rng, mp_int* priv, * returns RNG failures, MEMORY_E when memory allocation fails and * MP_OKAY on success. */ +#ifdef WOLFSSL_SP_NONBLOCK +typedef struct sp_ecc_verify_256_ctx { + int state; + union { + sp_256_ecc_mulmod_8_ctx mulmod_ctx; + sp_256_mont_inv_order_8_ctx mont_inv_order_ctx; + sp_256_proj_point_dbl_8_ctx dbl_ctx; + sp_256_proj_point_add_8_ctx add_ctx; + }; + sp_digit u1[2*8]; + sp_digit u2[2*8]; + sp_digit s[2*8]; + sp_digit tmp[2*8 * 5]; + sp_point_256 p1; + sp_point_256 p2; +} sp_ecc_verify_256_ctx; + +int sp_ecc_verify_256_nb(sp_ecc_ctx_t* sp_ctx, const byte* hash, word32 hashLen, mp_int* pX, + mp_int* pY, mp_int* pZ, mp_int* r, mp_int* sm, int* res, void* heap) +{ + int err = FP_WOULDBLOCK; + sp_ecc_verify_256_ctx* ctx = (sp_ecc_verify_256_ctx*)sp_ctx->data; + + typedef char ctx_size_test[sizeof(sp_ecc_verify_256_ctx) >= sizeof(*sp_ctx) ? -1 : 1]; + (void)sizeof(ctx_size_test); + + switch (ctx->state) { + case 0: /* INIT */ + if (hashLen > 32U) { + hashLen = 32U; + } + + sp_256_from_bin(ctx->u1, 8, hash, (int)hashLen); + sp_256_from_mp(ctx->u2, 8, r); + sp_256_from_mp(ctx->s, 8, sm); + sp_256_from_mp(ctx->p2.x, 8, pX); + sp_256_from_mp(ctx->p2.y, 8, pY); + sp_256_from_mp(ctx->p2.z, 8, pZ); + sp_256_mul_8(ctx->s, ctx->s, p256_norm_order); + err = sp_256_mod_8(ctx->s, ctx->s, p256_order); + if (err == MP_OKAY) + ctx->state = 1; + break; + case 1: /* NORMS1 */ + sp_256_norm_8(ctx->s); + XMEMSET(&ctx->mont_inv_order_ctx, 0, sizeof(ctx->mont_inv_order_ctx)); + ctx->state = 2; + break; + case 2: /* NORMS2 */ + err = sp_256_mont_inv_order_8_nb((sp_ecc_ctx_t*)&ctx->mont_inv_order_ctx, ctx->s, ctx->s, ctx->tmp); + if (err == MP_OKAY) { + ctx->state = 3; + } + break; + case 3: /* NORMS3 */ + sp_256_mont_mul_order_8(ctx->u1, ctx->u1, ctx->s); + ctx->state = 4; + break; + case 4: /* NORMS4 */ + sp_256_mont_mul_order_8(ctx->u2, ctx->u2, ctx->s); + XMEMSET(&ctx->mulmod_ctx, 0, sizeof(ctx->mulmod_ctx)); + ctx->state = 5; + break; + case 5: /* MULBASE */ + err = sp_256_ecc_mulmod_8_nb((sp_ecc_ctx_t*)&ctx->mulmod_ctx, &ctx->p1, &p256_base, ctx->u1, 0, heap); + if (err == MP_OKAY) { + XMEMSET(&ctx->mulmod_ctx, 0, sizeof(ctx->mulmod_ctx)); + ctx->state = 6; + } + break; + case 6: /* MULMOD */ + err = sp_256_ecc_mulmod_8_nb((sp_ecc_ctx_t*)&ctx->mulmod_ctx, &ctx->p2, &ctx->p2, ctx->u2, 0, heap); + if (err == MP_OKAY) { + XMEMSET(&ctx->add_ctx, 0, sizeof(ctx->add_ctx)); + ctx->state = 7; + } + break; + case 7: /* ADD */ + err = sp_256_proj_point_add_8_nb((sp_ecc_ctx_t*)&ctx->add_ctx, &ctx->p1, &ctx->p1, &ctx->p2, ctx->tmp); + if (err == MP_OKAY) + ctx->state = 8; + break; + case 8: /* DBLPREP */ + if (sp_256_iszero_8(ctx->p1.z)) { + if (sp_256_iszero_8(ctx->p1.x) && sp_256_iszero_8(ctx->p1.y)) { + XMEMSET(&ctx->dbl_ctx, 0, sizeof(ctx->dbl_ctx)); + ctx->state = 9; + break; + } + else { + /* Y ordinate is not used from here - don't set. */ + int i; + for (i=0; i<8; i++) { + ctx->p1.x[i] = 0; + } + XMEMCPY(ctx->p1.z, p256_norm_mod, sizeof(p256_norm_mod)); + } + } + ctx->state = 10; + break; + case 9: /* DBL */ + err = sp_256_proj_point_dbl_8_nb((sp_ecc_ctx_t*)&ctx->dbl_ctx, &ctx->p1, + &ctx->p2, ctx->tmp); + if (err == MP_OKAY) { + ctx->state = 10; + } + break; + case 10: /* MONT */ + /* (r + n*order).z'.z' mod prime == (u1.G + u2.Q)->x' */ + /* Reload r and convert to Montgomery form. */ + sp_256_from_mp(ctx->u2, 8, r); + err = sp_256_mod_mul_norm_8(ctx->u2, ctx->u2, p256_mod); + if (err == MP_OKAY) + ctx->state = 11; + break; + case 11: /* SQR */ + /* u1 = r.z'.z' mod prime */ + sp_256_mont_sqr_8(ctx->p1.z, ctx->p1.z, p256_mod, p256_mp_mod); + ctx->state = 12; + break; + case 12: /* MUL */ + sp_256_mont_mul_8(ctx->u1, ctx->u2, ctx->p1.z, p256_mod, p256_mp_mod); + ctx->state = 13; + break; + case 13: /* RES */ + err = MP_OKAY; /* math okay, now check result */ + *res = (int)(sp_256_cmp_8(ctx->p1.x, ctx->u1) == 0); + if (*res == 0) { + sp_digit carry; + int32_t c; + + /* Reload r and add order. */ + sp_256_from_mp(ctx->u2, 8, r); + carry = sp_256_add_8(ctx->u2, ctx->u2, p256_order); + /* Carry means result is greater than mod and is not valid. */ + if (carry == 0) { + sp_256_norm_8(ctx->u2); + + /* Compare with mod and if greater or equal then not valid. */ + c = sp_256_cmp_8(ctx->u2, p256_mod); + if (c < 0) { + /* Convert to Montogomery form */ + err = sp_256_mod_mul_norm_8(ctx->u2, ctx->u2, p256_mod); + if (err == MP_OKAY) { + /* u1 = (r + 1*order).z'.z' mod prime */ + sp_256_mont_mul_8(ctx->u1, ctx->u2, ctx->p1.z, p256_mod, + p256_mp_mod); + *res = (int)(sp_256_cmp_8(ctx->p1.x, ctx->u1) == 0); + } + } + } + } + break; + } + + if (err == MP_OKAY && ctx->state != 13) { + err = FP_WOULDBLOCK; + } + + return err; +} +#endif /* WOLFSSL_SP_NONBLOCK */ + int sp_ecc_verify_256(const byte* hash, word32 hashLen, mp_int* pX, mp_int* pY, mp_int* pZ, mp_int* r, mp_int* sm, int* res, void* heap) { @@ -22937,6 +23637,141 @@ SP_NOINLINE static void sp_384_div2_12(sp_digit* r, const sp_digit* a, const sp_ * p Point to double. * t Temporary ordinate data. */ +#ifdef WOLFSSL_SP_NONBLOCK +typedef struct sp_384_proj_point_dbl_12_ctx { + int state; + sp_digit* t1; + sp_digit* t2; + sp_digit* x; + sp_digit* y; + sp_digit* z; +} sp_384_proj_point_dbl_12_ctx; + +static int sp_384_proj_point_dbl_12_nb(sp_ecc_ctx_t* sp_ctx, sp_point_384* r, const sp_point_384* p, sp_digit* t) +{ + int err = FP_WOULDBLOCK; + sp_384_proj_point_dbl_12_ctx* ctx = (sp_384_proj_point_dbl_12_ctx*)sp_ctx->data; + + typedef char ctx_size_test[sizeof(sp_384_proj_point_dbl_12_ctx) >= sizeof(*sp_ctx) ? -1 : 1]; + (void)sizeof(ctx_size_test); + + switch (ctx->state) { + case 0: + ctx->t1 = t; + ctx->t2 = t + 2*12; + ctx->x = r->x; + ctx->y = r->y; + ctx->z = r->z; + + /* Put infinity into result. */ + if (r != p) { + r->infinity = p->infinity; + } + ctx->state = 1; + break; + case 1: + /* T1 = Z * Z */ + sp_384_mont_sqr_12(ctx->t1, p->z, p384_mod, p384_mp_mod); + ctx->state = 2; + break; + case 2: + /* Z = Y * Z */ + sp_384_mont_mul_12(ctx->z, p->y, p->z, p384_mod, p384_mp_mod); + ctx->state = 3; + break; + case 3: + /* Z = 2Z */ + sp_384_mont_dbl_12(ctx->z, ctx->z, p384_mod); + ctx->state = 4; + break; + case 4: + /* T2 = X - T1 */ + sp_384_mont_sub_12(ctx->t2, p->x, ctx->t1, p384_mod); + ctx->state = 5; + break; + case 5: + /* T1 = X + T1 */ + sp_384_mont_add_12(ctx->t1, p->x, ctx->t1, p384_mod); + ctx->state = 6; + break; + case 6: + /* T2 = T1 * T2 */ + sp_384_mont_mul_12(ctx->t2, ctx->t1, ctx->t2, p384_mod, p384_mp_mod); + ctx->state = 7; + break; + case 7: + /* T1 = 3T2 */ + sp_384_mont_tpl_12(ctx->t1, ctx->t2, p384_mod); + ctx->state = 8; + break; + case 8: + /* Y = 2Y */ + sp_384_mont_dbl_12(ctx->y, p->y, p384_mod); + ctx->state = 9; + break; + case 9: + /* Y = Y * Y */ + sp_384_mont_sqr_12(ctx->y, ctx->y, p384_mod, p384_mp_mod); + ctx->state = 10; + break; + case 10: + /* T2 = Y * Y */ + sp_384_mont_sqr_12(ctx->t2, ctx->y, p384_mod, p384_mp_mod); + ctx->state = 11; + break; + case 11: + /* T2 = T2/2 */ + sp_384_div2_12(ctx->t2, ctx->t2, p384_mod); + ctx->state = 12; + break; + case 12: + /* Y = Y * X */ + sp_384_mont_mul_12(ctx->y, ctx->y, p->x, p384_mod, p384_mp_mod); + ctx->state = 13; + break; + case 13: + /* X = T1 * T1 */ + sp_384_mont_sqr_12(ctx->x, ctx->t1, p384_mod, p384_mp_mod); + ctx->state = 14; + break; + case 14: + /* X = X - Y */ + sp_384_mont_sub_12(ctx->x, ctx->x, ctx->y, p384_mod); + ctx->state = 15; + break; + case 15: + /* X = X - Y */ + sp_384_mont_sub_12(ctx->x, ctx->x, ctx->y, p384_mod); + ctx->state = 16; + break; + case 16: + /* Y = Y - X */ + sp_384_mont_sub_12(ctx->y, ctx->y, ctx->x, p384_mod); + ctx->state = 17; + break; + case 17: + /* Y = Y * T1 */ + sp_384_mont_mul_12(ctx->y, ctx->y, ctx->t1, p384_mod, p384_mp_mod); + ctx->state = 18; + break; + case 18: + /* Y = Y - T2 */ + sp_384_mont_sub_12(ctx->y, ctx->y, ctx->t2, p384_mod); + ctx->state = 19; + /* fall-through */ + case 19: + err = MP_OKAY; + break; + } + + if (err == MP_OKAY && ctx->state != 19) { + err = FP_WOULDBLOCK; + } + + return err; +} +#endif /* WOLFSSL_SP_NONBLOCK */ + static void sp_384_proj_point_dbl_12(sp_point_384* r, const sp_point_384* p, sp_digit* t) { sp_digit* t1 = t; @@ -23012,6 +23847,209 @@ static int sp_384_cmp_equal_12(const sp_digit* a, const sp_digit* b) * q Second point to add. * t Temporary ordinate data. */ + +#ifdef WOLFSSL_SP_NONBLOCK +typedef struct sp_384_proj_point_add_12_ctx { + int state; + sp_384_proj_point_dbl_12_ctx dbl_ctx; + const sp_point_384* ap[2]; + sp_point_384* rp[2]; + sp_digit* t1; + sp_digit* t2; + sp_digit* t3; + sp_digit* t4; + sp_digit* t5; + sp_digit* x; + sp_digit* y; + sp_digit* z; +} sp_384_proj_point_add_12_ctx; + +static int sp_384_proj_point_add_12_nb(sp_ecc_ctx_t* sp_ctx, sp_point_384* r, + const sp_point_384* p, const sp_point_384* q, sp_digit* t) +{ + int err = FP_WOULDBLOCK; + sp_384_proj_point_add_12_ctx* ctx = (sp_384_proj_point_add_12_ctx*)sp_ctx->data; + + /* Ensure only the first point is the same as the result. */ + if (q == r) { + const sp_point_384* a = p; + p = q; + q = a; + } + + typedef char ctx_size_test[sizeof(sp_384_proj_point_add_12_ctx) >= sizeof(*sp_ctx) ? -1 : 1]; + (void)sizeof(ctx_size_test); + + switch (ctx->state) { + case 0: /* INIT */ + ctx->t1 = t; + ctx->t2 = t + 2*12; + ctx->t3 = t + 4*12; + ctx->t4 = t + 6*12; + ctx->t5 = t + 8*12; + + ctx->state = 1; + break; + case 1: + /* Check double */ + (void)sp_384_sub_12(ctx->t1, p384_mod, q->y); + sp_384_norm_12(ctx->t1); + if ((sp_384_cmp_equal_12(p->x, q->x) & sp_384_cmp_equal_12(p->z, q->z) & + (sp_384_cmp_equal_12(p->y, q->y) | sp_384_cmp_equal_12(p->y, ctx->t1))) != 0) + { + XMEMSET(&ctx->dbl_ctx, 0, sizeof(ctx->dbl_ctx)); + ctx->state = 2; + } + else { + ctx->state = 3; + } + break; + case 2: + err = sp_384_proj_point_dbl_12_nb((sp_ecc_ctx_t*)&ctx->dbl_ctx, r, p, t); + if (err == MP_OKAY) + ctx->state = 27; /* done */ + break; + case 3: + { + int i; + ctx->rp[0] = r; + + /*lint allow cast to different type of pointer*/ + ctx->rp[1] = (sp_point_384*)t; /*lint !e9087 !e740*/ + XMEMSET(ctx->rp[1], 0, sizeof(sp_point_384)); + ctx->x = ctx->rp[p->infinity | q->infinity]->x; + ctx->y = ctx->rp[p->infinity | q->infinity]->y; + ctx->z = ctx->rp[p->infinity | q->infinity]->z; + + ctx->ap[0] = p; + ctx->ap[1] = q; + for (i=0; i<12; i++) { + r->x[i] = ctx->ap[p->infinity]->x[i]; + } + for (i=0; i<12; i++) { + r->y[i] = ctx->ap[p->infinity]->y[i]; + } + for (i=0; i<12; i++) { + r->z[i] = ctx->ap[p->infinity]->z[i]; + } + r->infinity = ctx->ap[p->infinity]->infinity; + + ctx->state = 4; + break; + } + case 4: + /* U1 = X1*Z2^2 */ + sp_384_mont_sqr_12(ctx->t1, q->z, p384_mod, p384_mp_mod); + ctx->state = 5; + break; + case 5: + sp_384_mont_mul_12(ctx->t3, ctx->t1, q->z, p384_mod, p384_mp_mod); + ctx->state = 6; + break; + case 6: + sp_384_mont_mul_12(ctx->t1, ctx->t1, ctx->x, p384_mod, p384_mp_mod); + ctx->state = 7; + break; + case 7: + /* U2 = X2*Z1^2 */ + sp_384_mont_sqr_12(ctx->t2, ctx->z, p384_mod, p384_mp_mod); + ctx->state = 8; + break; + case 8: + sp_384_mont_mul_12(ctx->t4, ctx->t2, ctx->z, p384_mod, p384_mp_mod); + ctx->state = 9; + break; + case 9: + sp_384_mont_mul_12(ctx->t2, ctx->t2, q->x, p384_mod, p384_mp_mod); + ctx->state = 10; + break; + case 10: + /* S1 = Y1*Z2^3 */ + sp_384_mont_mul_12(ctx->t3, ctx->t3, ctx->y, p384_mod, p384_mp_mod); + ctx->state = 11; + break; + case 11: + /* S2 = Y2*Z1^3 */ + sp_384_mont_mul_12(ctx->t4, ctx->t4, q->y, p384_mod, p384_mp_mod); + ctx->state = 12; + break; + case 12: + /* H = U2 - U1 */ + sp_384_mont_sub_12(ctx->t2, ctx->t2, ctx->t1, p384_mod); + ctx->state = 13; + break; + case 13: + /* R = S2 - S1 */ + sp_384_mont_sub_12(ctx->t4, ctx->t4, ctx->t3, p384_mod); + ctx->state = 14; + break; + case 14: + /* Z3 = H*Z1*Z2 */ + sp_384_mont_mul_12(ctx->z, ctx->z, q->z, p384_mod, p384_mp_mod); + ctx->state = 15; + break; + case 15: + sp_384_mont_mul_12(ctx->z, ctx->z, ctx->t2, p384_mod, p384_mp_mod); + ctx->state = 16; + break; + case 16: + /* X3 = R^2 - H^3 - 2*U1*H^2 */ + sp_384_mont_sqr_12(ctx->x, ctx->t4, p384_mod, p384_mp_mod); + ctx->state = 17; + break; + case 17: + sp_384_mont_sqr_12(ctx->t5, ctx->t2, p384_mod, p384_mp_mod); + ctx->state = 18; + break; + case 18: + sp_384_mont_mul_12(ctx->y, ctx->t1, ctx->t5, p384_mod, p384_mp_mod); + ctx->state = 19; + break; + case 19: + sp_384_mont_mul_12(ctx->t5, ctx->t5, ctx->t2, p384_mod, p384_mp_mod); + ctx->state = 20; + break; + case 20: + sp_384_mont_sub_12(ctx->x, ctx->x, ctx->t5, p384_mod); + ctx->state = 21; + break; + case 21: + sp_384_mont_dbl_12(ctx->t1, ctx->y, p384_mod); + ctx->state = 22; + break; + case 22: + sp_384_mont_sub_12(ctx->x, ctx->x, ctx->t1, p384_mod); + ctx->state = 23; + break; + case 23: + /* Y3 = R*(U1*H^2 - X3) - S1*H^3 */ + sp_384_mont_sub_12(ctx->y, ctx->y, ctx->x, p384_mod); + ctx->state = 24; + break; + case 24: + sp_384_mont_mul_12(ctx->y, ctx->y, ctx->t4, p384_mod, p384_mp_mod); + ctx->state = 25; + break; + case 25: + sp_384_mont_mul_12(ctx->t5, ctx->t5, ctx->t3, p384_mod, p384_mp_mod); + ctx->state = 26; + break; + case 26: + sp_384_mont_sub_12(ctx->y, ctx->y, ctx->t5, p384_mod); + ctx->state = 27; + /* fall-through */ + case 27: + err = MP_OKAY; + break; + } + + if (err == MP_OKAY && ctx->state != 27) { + err = FP_WOULDBLOCK; + } + return err; +} +#endif /* WOLFSSL_SP_NONBLOCK */ + static void sp_384_proj_point_add_12(sp_point_384* r, const sp_point_384* p, const sp_point_384* q, sp_digit* t) { @@ -26300,6 +27338,46 @@ static void sp_384_mont_sqr_n_order_12(sp_digit* r, const sp_digit* a, int n) * a Number to invert. * td Temporary data. */ + +#ifdef WOLFSSL_SP_NONBLOCK +typedef struct sp_384_mont_inv_order_12_ctx { + int state; + int i; +} sp_384_mont_inv_order_12_ctx; +static int sp_384_mont_inv_order_12_nb(sp_ecc_ctx_t* sp_ctx, sp_digit* r, const sp_digit* a, + sp_digit* t) +{ + int err = FP_WOULDBLOCK; + sp_384_mont_inv_order_12_ctx* ctx = (sp_384_mont_inv_order_12_ctx*)sp_ctx; + + typedef char ctx_size_test[sizeof(sp_384_mont_inv_order_12_ctx) >= sizeof(*sp_ctx) ? -1 : 1]; + (void)sizeof(ctx_size_test); + + switch (ctx->state) { + case 0: + XMEMCPY(t, a, sizeof(sp_digit) * 12); + ctx->i = 382; + ctx->state = 1; + break; + case 1: + sp_384_mont_sqr_order_12(t, t); + if ((p384_order_minus_2[ctx->i / 32] & ((sp_int_digit)1 << (ctx->i % 32))) != 0) { + sp_384_mont_mul_order_12(t, t, a); + } + ctx->i--; + if (ctx->i == 0) { + ctx->state = 2; + } + break; + case 2: + XMEMCPY(r, t, sizeof(sp_digit) * 12U); + err = MP_OKAY; + break; + } + return err; +} +#endif /* WOLFSSL_SP_NONBLOCK */ + static void sp_384_mont_inv_order_12(sp_digit* r, const sp_digit* a, sp_digit* td) { @@ -26386,6 +27464,165 @@ static void sp_384_mont_inv_order_12(sp_digit* r, const sp_digit* a, * returns RNG failures, MEMORY_E when memory allocation fails and * MP_OKAY on success. */ +#ifdef WOLFSSL_SP_NONBLOCK +typedef struct sp_ecc_sign_384_ctx { + int state; + union { + sp_384_ecc_mulmod_12_ctx mulmod_ctx; + sp_384_mont_inv_order_12_ctx mont_inv_order_ctx; + }; + sp_digit e[2*12]; + sp_digit x[2*12]; + sp_digit k[2*12]; + sp_digit r[2*12]; + sp_digit tmp[3 * 2*12]; + sp_point_384 point; + sp_digit* s; + sp_digit* kInv; + int i; +} sp_ecc_sign_384_ctx; + +int sp_ecc_sign_384_nb(sp_ecc_ctx_t* sp_ctx, const byte* hash, word32 hashLen, WC_RNG* rng, mp_int* priv, + mp_int* rm, mp_int* sm, mp_int* km, void* heap) +{ + int err = FP_WOULDBLOCK; + sp_ecc_sign_384_ctx* ctx = (sp_ecc_sign_384_ctx*)sp_ctx->data; + + typedef char ctx_size_test[sizeof(sp_ecc_sign_384_ctx) >= sizeof(*sp_ctx) ? -1 : 1]; + (void)sizeof(ctx_size_test); + + (void)heap; + + switch (ctx->state) { + case 0: /* INIT */ + ctx->s = ctx->e; + ctx->kInv = ctx->k; + if (hashLen > 48U) { + hashLen = 48U; + } + + sp_384_from_bin(ctx->e, 12, hash, (int)hashLen); + + ctx->i = SP_ECC_MAX_SIG_GEN; + ctx->state = 1; + break; + case 1: /* GEN */ + sp_384_from_mp(ctx->x, 12, priv); + /* New random point. */ + if (km == NULL || mp_iszero(km)) { + err = sp_384_ecc_gen_k_12(rng, ctx->k); + } + else { + sp_384_from_mp(ctx->k, 12, km); + mp_zero(km); + } + XMEMSET(&ctx->mulmod_ctx, 0, sizeof(ctx->mulmod_ctx)); + ctx->state = 2; + break; + case 2: /* MULMOD */ + err = sp_384_ecc_mulmod_12_nb((sp_ecc_ctx_t*)&ctx->mulmod_ctx, + &ctx->point, &p384_base, ctx->k, 1, heap); + if (err == MP_OKAY) { + ctx->state = 3; + } + break; + case 3: /* MODORDER */ + { + int32_t c; + /* r = point->x mod order */ + XMEMCPY(ctx->r, ctx->point.x, sizeof(sp_digit) * 12U); + sp_384_norm_12(ctx->r); + c = sp_384_cmp_12(ctx->r, p384_order); + sp_384_cond_sub_12(ctx->r, ctx->r, p384_order, 0L - (sp_digit)(c >= 0)); + sp_384_norm_12(ctx->r); + ctx->state = 4; + break; + } + case 4: /* KMODORDER */ + /* Conv k to Montgomery form (mod order) */ + sp_384_mul_12(ctx->k, ctx->k, p384_norm_order); + err = sp_384_mod_12(ctx->k, ctx->k, p384_order); + if (err == MP_OKAY) { + sp_384_norm_12(ctx->k); + XMEMSET(&ctx->mont_inv_order_ctx, 0, sizeof(ctx->mont_inv_order_ctx)); + ctx->state = 5; + } + break; + case 5: /* KINV */ + /* kInv = 1/k mod order */ + err = sp_384_mont_inv_order_12_nb((sp_ecc_ctx_t*)&ctx->mont_inv_order_ctx, ctx->kInv, ctx->k, ctx->tmp); + if (err == MP_OKAY) { + XMEMSET(&ctx->mont_inv_order_ctx, 0, sizeof(ctx->mont_inv_order_ctx)); + ctx->state = 6; + } + break; + case 6: /* KINVNORM */ + sp_384_norm_12(ctx->kInv); + ctx->state = 7; + break; + case 7: /* R */ + /* s = r * x + e */ + sp_384_mul_12(ctx->x, ctx->x, ctx->r); + ctx->state = 8; + break; + case 8: /* S1 */ + err = sp_384_mod_12(ctx->x, ctx->x, p384_order); + if (err == MP_OKAY) + ctx->state = 9; + break; + case 9: /* S2 */ + { + sp_digit carry; + int32_t c; + sp_384_norm_12(ctx->x); + carry = sp_384_add_12(ctx->s, ctx->e, ctx->x); + sp_384_cond_sub_12(ctx->s, ctx->s, p384_order, 0 - carry); + sp_384_norm_12(ctx->s); + c = sp_384_cmp_12(ctx->s, p384_order); + sp_384_cond_sub_12(ctx->s, ctx->s, p384_order, 0L - (sp_digit)(c >= 0)); + sp_384_norm_12(ctx->s); + + /* s = s * k^-1 mod order */ + sp_384_mont_mul_order_12(ctx->s, ctx->s, ctx->kInv); + sp_384_norm_12(ctx->s); + + /* Check that signature is usable. */ + if (sp_384_iszero_12(ctx->s) == 0) { + ctx->state = 10; + break; + } + + /* not usable gen, try again */ + ctx->i--; + if (ctx->i == 0) { + err = RNG_FAILURE_E; + } + ctx->state = 1; + break; + } + case 10: /* RES */ + err = sp_384_to_mp(ctx->r, rm); + if (err == MP_OKAY) { + err = sp_384_to_mp(ctx->s, sm); + } + break; + } + + if (err == MP_OKAY && ctx->state != 10) { + err = FP_WOULDBLOCK; + } + if (err != FP_WOULDBLOCK) { + XMEMSET(ctx->e, 0, sizeof(sp_digit) * 2U * 12U); + XMEMSET(ctx->x, 0, sizeof(sp_digit) * 2U * 12U); + XMEMSET(ctx->k, 0, sizeof(sp_digit) * 2U * 12U); + XMEMSET(ctx->r, 0, sizeof(sp_digit) * 2U * 12U); + XMEMSET(ctx->tmp, 0, sizeof(sp_digit) * 3U * 2U * 12U); + } + + return err; +} +#endif /* WOLFSSL_SP_NONBLOCK */ + int sp_ecc_sign_384(const byte* hash, word32 hashLen, WC_RNG* rng, mp_int* priv, mp_int* rm, mp_int* sm, mp_int* km, void* heap) { @@ -26557,6 +27794,169 @@ int sp_ecc_sign_384(const byte* hash, word32 hashLen, WC_RNG* rng, mp_int* priv, * returns RNG failures, MEMORY_E when memory allocation fails and * MP_OKAY on success. */ +#ifdef WOLFSSL_SP_NONBLOCK +typedef struct sp_ecc_verify_384_ctx { + int state; + union { + sp_384_ecc_mulmod_12_ctx mulmod_ctx; + sp_384_mont_inv_order_12_ctx mont_inv_order_ctx; + sp_384_proj_point_dbl_12_ctx dbl_ctx; + sp_384_proj_point_add_12_ctx add_ctx; + }; + sp_digit u1[2*12]; + sp_digit u2[2*12]; + sp_digit s[2*12]; + sp_digit tmp[2*12 * 5]; + sp_point_384 p1; + sp_point_384 p2; +} sp_ecc_verify_384_ctx; + +int sp_ecc_verify_384_nb(sp_ecc_ctx_t* sp_ctx, const byte* hash, word32 hashLen, mp_int* pX, + mp_int* pY, mp_int* pZ, mp_int* r, mp_int* sm, int* res, void* heap) +{ + int err = FP_WOULDBLOCK; + sp_ecc_verify_384_ctx* ctx = (sp_ecc_verify_384_ctx*)sp_ctx->data; + + typedef char ctx_size_test[sizeof(sp_ecc_verify_384_ctx) >= sizeof(*sp_ctx) ? -1 : 1]; + (void)sizeof(ctx_size_test); + + switch (ctx->state) { + case 0: /* INIT */ + if (hashLen > 48U) { + hashLen = 48U; + } + + sp_384_from_bin(ctx->u1, 12, hash, (int)hashLen); + sp_384_from_mp(ctx->u2, 12, r); + sp_384_from_mp(ctx->s, 12, sm); + sp_384_from_mp(ctx->p2.x, 12, pX); + sp_384_from_mp(ctx->p2.y, 12, pY); + sp_384_from_mp(ctx->p2.z, 12, pZ); + sp_384_mul_12(ctx->s, ctx->s, p384_norm_order); + err = sp_384_mod_12(ctx->s, ctx->s, p384_order); + if (err == MP_OKAY) + ctx->state = 1; + break; + case 1: /* NORMS1 */ + sp_384_norm_12(ctx->s); + XMEMSET(&ctx->mont_inv_order_ctx, 0, sizeof(ctx->mont_inv_order_ctx)); + ctx->state = 2; + break; + case 2: /* NORMS2 */ + err = sp_384_mont_inv_order_12_nb((sp_ecc_ctx_t*)&ctx->mont_inv_order_ctx, ctx->s, ctx->s, ctx->tmp); + if (err == MP_OKAY) { + ctx->state = 3; + } + break; + case 3: /* NORMS3 */ + sp_384_mont_mul_order_12(ctx->u1, ctx->u1, ctx->s); + ctx->state = 4; + break; + case 4: /* NORMS4 */ + sp_384_mont_mul_order_12(ctx->u2, ctx->u2, ctx->s); + XMEMSET(&ctx->mulmod_ctx, 0, sizeof(ctx->mulmod_ctx)); + ctx->state = 5; + break; + case 5: /* MULBASE */ + err = sp_384_ecc_mulmod_12_nb((sp_ecc_ctx_t*)&ctx->mulmod_ctx, &ctx->p1, &p384_base, ctx->u1, 0, heap); + if (err == MP_OKAY) { + XMEMSET(&ctx->mulmod_ctx, 0, sizeof(ctx->mulmod_ctx)); + ctx->state = 6; + } + break; + case 6: /* MULMOD */ + err = sp_384_ecc_mulmod_12_nb((sp_ecc_ctx_t*)&ctx->mulmod_ctx, &ctx->p2, &ctx->p2, ctx->u2, 0, heap); + if (err == MP_OKAY) { + XMEMSET(&ctx->add_ctx, 0, sizeof(ctx->add_ctx)); + ctx->state = 7; + } + break; + case 7: /* ADD */ + err = sp_384_proj_point_add_12_nb((sp_ecc_ctx_t*)&ctx->add_ctx, &ctx->p1, &ctx->p1, &ctx->p2, ctx->tmp); + if (err == MP_OKAY) + ctx->state = 8; + break; + case 8: /* DBLPREP */ + if (sp_384_iszero_12(ctx->p1.z)) { + if (sp_384_iszero_12(ctx->p1.x) && sp_384_iszero_12(ctx->p1.y)) { + XMEMSET(&ctx->dbl_ctx, 0, sizeof(ctx->dbl_ctx)); + ctx->state = 9; + break; + } + else { + /* Y ordinate is not used from here - don't set. */ + int i; + for (i=0; i<12; i++) { + ctx->p1.x[i] = 0; + } + XMEMCPY(ctx->p1.z, p384_norm_mod, sizeof(p384_norm_mod)); + } + } + ctx->state = 10; + break; + case 9: /* DBL */ + err = sp_384_proj_point_dbl_12_nb((sp_ecc_ctx_t*)&ctx->dbl_ctx, &ctx->p1, + &ctx->p2, ctx->tmp); + if (err == MP_OKAY) { + ctx->state = 10; + } + break; + case 10: /* MONT */ + /* (r + n*order).z'.z' mod prime == (u1.G + u2.Q)->x' */ + /* Reload r and convert to Montgomery form. */ + sp_384_from_mp(ctx->u2, 12, r); + err = sp_384_mod_mul_norm_12(ctx->u2, ctx->u2, p384_mod); + if (err == MP_OKAY) + ctx->state = 11; + break; + case 11: /* SQR */ + /* u1 = r.z'.z' mod prime */ + sp_384_mont_sqr_12(ctx->p1.z, ctx->p1.z, p384_mod, p384_mp_mod); + ctx->state = 12; + break; + case 12: /* MUL */ + sp_384_mont_mul_12(ctx->u1, ctx->u2, ctx->p1.z, p384_mod, p384_mp_mod); + ctx->state = 13; + break; + case 13: /* RES */ + err = MP_OKAY; /* math okay, now check result */ + *res = (int)(sp_384_cmp_12(ctx->p1.x, ctx->u1) == 0); + if (*res == 0) { + sp_digit carry; + int32_t c; + + /* Reload r and add order. */ + sp_384_from_mp(ctx->u2, 12, r); + carry = sp_384_add_12(ctx->u2, ctx->u2, p384_order); + /* Carry means result is greater than mod and is not valid. */ + if (carry == 0) { + sp_384_norm_12(ctx->u2); + + /* Compare with mod and if greater or equal then not valid. */ + c = sp_384_cmp_12(ctx->u2, p384_mod); + if (c < 0) { + /* Convert to Montogomery form */ + err = sp_384_mod_mul_norm_12(ctx->u2, ctx->u2, p384_mod); + if (err == MP_OKAY) { + /* u1 = (r + 1*order).z'.z' mod prime */ + sp_384_mont_mul_12(ctx->u1, ctx->u2, ctx->p1.z, p384_mod, + p384_mp_mod); + *res = (int)(sp_384_cmp_12(ctx->p1.x, ctx->u1) == 0); + } + } + } + } + break; + } + + if (err == MP_OKAY && ctx->state != 13) { + err = FP_WOULDBLOCK; + } + + return err; +} +#endif /* WOLFSSL_SP_NONBLOCK */ + int sp_ecc_verify_384(const byte* hash, word32 hashLen, mp_int* pX, mp_int* pY, mp_int* pZ, mp_int* r, mp_int* sm, int* res, void* heap) { diff --git a/wolfcrypt/src/sp_c32.c b/wolfcrypt/src/sp_c32.c index 3662ceae2e..714729f4fb 100644 --- a/wolfcrypt/src/sp_c32.c +++ b/wolfcrypt/src/sp_c32.c @@ -57,6 +57,10 @@ static const size_t addr_mask[2] = { 0, (size_t)-1 }; #endif +#if defined(WOLFSSL_SP_NONBLOCK) && (!defined(WOLFSSL_SP_NO_MALLOC) || !defined(WOLFSSL_SP_SMALL)) + #error SP non-blocking requires small and no-malloc (WOLFSSL_SP_SMALL and WOLFSSL_SP_NO_MALLOC) +#endif + #if defined(WOLFSSL_HAVE_SP_RSA) || defined(WOLFSSL_HAVE_SP_DH) #ifndef WOLFSSL_SP_NO_2048 /* Read big endian unsigned byte array into r. @@ -13847,6 +13851,141 @@ static void sp_256_div2_10(sp_digit* r, const sp_digit* a, const sp_digit* m) * p Point to double. * t Temporary ordinate data. */ +#ifdef WOLFSSL_SP_NONBLOCK +typedef struct sp_256_proj_point_dbl_10_ctx { + int state; + sp_digit* t1; + sp_digit* t2; + sp_digit* x; + sp_digit* y; + sp_digit* z; +} sp_256_proj_point_dbl_10_ctx; + +static int sp_256_proj_point_dbl_10_nb(sp_ecc_ctx_t* sp_ctx, sp_point_256* r, const sp_point_256* p, sp_digit* t) +{ + int err = FP_WOULDBLOCK; + sp_256_proj_point_dbl_10_ctx* ctx = (sp_256_proj_point_dbl_10_ctx*)sp_ctx->data; + + typedef char ctx_size_test[sizeof(sp_256_proj_point_dbl_10_ctx) >= sizeof(*sp_ctx) ? -1 : 1]; + (void)sizeof(ctx_size_test); + + switch (ctx->state) { + case 0: + ctx->t1 = t; + ctx->t2 = t + 2*10; + ctx->x = r->x; + ctx->y = r->y; + ctx->z = r->z; + + /* Put infinity into result. */ + if (r != p) { + r->infinity = p->infinity; + } + ctx->state = 1; + break; + case 1: + /* T1 = Z * Z */ + sp_256_mont_sqr_10(ctx->t1, p->z, p256_mod, p256_mp_mod); + ctx->state = 2; + break; + case 2: + /* Z = Y * Z */ + sp_256_mont_mul_10(ctx->z, p->y, p->z, p256_mod, p256_mp_mod); + ctx->state = 3; + break; + case 3: + /* Z = 2Z */ + sp_256_mont_dbl_10(ctx->z, ctx->z, p256_mod); + ctx->state = 4; + break; + case 4: + /* T2 = X - T1 */ + sp_256_mont_sub_10(ctx->t2, p->x, ctx->t1, p256_mod); + ctx->state = 5; + break; + case 5: + /* T1 = X + T1 */ + sp_256_mont_add_10(ctx->t1, p->x, ctx->t1, p256_mod); + ctx->state = 6; + break; + case 6: + /* T2 = T1 * T2 */ + sp_256_mont_mul_10(ctx->t2, ctx->t1, ctx->t2, p256_mod, p256_mp_mod); + ctx->state = 7; + break; + case 7: + /* T1 = 3T2 */ + sp_256_mont_tpl_10(ctx->t1, ctx->t2, p256_mod); + ctx->state = 8; + break; + case 8: + /* Y = 2Y */ + sp_256_mont_dbl_10(ctx->y, p->y, p256_mod); + ctx->state = 9; + break; + case 9: + /* Y = Y * Y */ + sp_256_mont_sqr_10(ctx->y, ctx->y, p256_mod, p256_mp_mod); + ctx->state = 10; + break; + case 10: + /* T2 = Y * Y */ + sp_256_mont_sqr_10(ctx->t2, ctx->y, p256_mod, p256_mp_mod); + ctx->state = 11; + break; + case 11: + /* T2 = T2/2 */ + sp_256_div2_10(ctx->t2, ctx->t2, p256_mod); + ctx->state = 12; + break; + case 12: + /* Y = Y * X */ + sp_256_mont_mul_10(ctx->y, ctx->y, p->x, p256_mod, p256_mp_mod); + ctx->state = 13; + break; + case 13: + /* X = T1 * T1 */ + sp_256_mont_sqr_10(ctx->x, ctx->t1, p256_mod, p256_mp_mod); + ctx->state = 14; + break; + case 14: + /* X = X - Y */ + sp_256_mont_sub_10(ctx->x, ctx->x, ctx->y, p256_mod); + ctx->state = 15; + break; + case 15: + /* X = X - Y */ + sp_256_mont_sub_10(ctx->x, ctx->x, ctx->y, p256_mod); + ctx->state = 16; + break; + case 16: + /* Y = Y - X */ + sp_256_mont_sub_10(ctx->y, ctx->y, ctx->x, p256_mod); + ctx->state = 17; + break; + case 17: + /* Y = Y * T1 */ + sp_256_mont_mul_10(ctx->y, ctx->y, ctx->t1, p256_mod, p256_mp_mod); + ctx->state = 18; + break; + case 18: + /* Y = Y - T2 */ + sp_256_mont_sub_10(ctx->y, ctx->y, ctx->t2, p256_mod); + ctx->state = 19; + /* fall-through */ + case 19: + err = MP_OKAY; + break; + } + + if (err == MP_OKAY && ctx->state != 19) { + err = FP_WOULDBLOCK; + } + + return err; +} +#endif /* WOLFSSL_SP_NONBLOCK */ + static void sp_256_proj_point_dbl_10(sp_point_256* r, const sp_point_256* p, sp_digit* t) { sp_digit* t1 = t; @@ -13922,6 +14061,209 @@ static int sp_256_cmp_equal_10(const sp_digit* a, const sp_digit* b) * q Second point to add. * t Temporary ordinate data. */ + +#ifdef WOLFSSL_SP_NONBLOCK +typedef struct sp_256_proj_point_add_10_ctx { + int state; + sp_256_proj_point_dbl_10_ctx dbl_ctx; + const sp_point_256* ap[2]; + sp_point_256* rp[2]; + sp_digit* t1; + sp_digit* t2; + sp_digit* t3; + sp_digit* t4; + sp_digit* t5; + sp_digit* x; + sp_digit* y; + sp_digit* z; +} sp_256_proj_point_add_10_ctx; + +static int sp_256_proj_point_add_10_nb(sp_ecc_ctx_t* sp_ctx, sp_point_256* r, + const sp_point_256* p, const sp_point_256* q, sp_digit* t) +{ + int err = FP_WOULDBLOCK; + sp_256_proj_point_add_10_ctx* ctx = (sp_256_proj_point_add_10_ctx*)sp_ctx->data; + + /* Ensure only the first point is the same as the result. */ + if (q == r) { + const sp_point_256* a = p; + p = q; + q = a; + } + + typedef char ctx_size_test[sizeof(sp_256_proj_point_add_10_ctx) >= sizeof(*sp_ctx) ? -1 : 1]; + (void)sizeof(ctx_size_test); + + switch (ctx->state) { + case 0: /* INIT */ + ctx->t1 = t; + ctx->t2 = t + 2*10; + ctx->t3 = t + 4*10; + ctx->t4 = t + 6*10; + ctx->t5 = t + 8*10; + + ctx->state = 1; + break; + case 1: + /* Check double */ + (void)sp_256_sub_10(ctx->t1, p256_mod, q->y); + sp_256_norm_10(ctx->t1); + if ((sp_256_cmp_equal_10(p->x, q->x) & sp_256_cmp_equal_10(p->z, q->z) & + (sp_256_cmp_equal_10(p->y, q->y) | sp_256_cmp_equal_10(p->y, ctx->t1))) != 0) + { + XMEMSET(&ctx->dbl_ctx, 0, sizeof(ctx->dbl_ctx)); + ctx->state = 2; + } + else { + ctx->state = 3; + } + break; + case 2: + err = sp_256_proj_point_dbl_10_nb((sp_ecc_ctx_t*)&ctx->dbl_ctx, r, p, t); + if (err == MP_OKAY) + ctx->state = 27; /* done */ + break; + case 3: + { + int i; + ctx->rp[0] = r; + + /*lint allow cast to different type of pointer*/ + ctx->rp[1] = (sp_point_256*)t; /*lint !e9087 !e740*/ + XMEMSET(ctx->rp[1], 0, sizeof(sp_point_256)); + ctx->x = ctx->rp[p->infinity | q->infinity]->x; + ctx->y = ctx->rp[p->infinity | q->infinity]->y; + ctx->z = ctx->rp[p->infinity | q->infinity]->z; + + ctx->ap[0] = p; + ctx->ap[1] = q; + for (i=0; i<10; i++) { + r->x[i] = ctx->ap[p->infinity]->x[i]; + } + for (i=0; i<10; i++) { + r->y[i] = ctx->ap[p->infinity]->y[i]; + } + for (i=0; i<10; i++) { + r->z[i] = ctx->ap[p->infinity]->z[i]; + } + r->infinity = ctx->ap[p->infinity]->infinity; + + ctx->state = 4; + break; + } + case 4: + /* U1 = X1*Z2^2 */ + sp_256_mont_sqr_10(ctx->t1, q->z, p256_mod, p256_mp_mod); + ctx->state = 5; + break; + case 5: + sp_256_mont_mul_10(ctx->t3, ctx->t1, q->z, p256_mod, p256_mp_mod); + ctx->state = 6; + break; + case 6: + sp_256_mont_mul_10(ctx->t1, ctx->t1, ctx->x, p256_mod, p256_mp_mod); + ctx->state = 7; + break; + case 7: + /* U2 = X2*Z1^2 */ + sp_256_mont_sqr_10(ctx->t2, ctx->z, p256_mod, p256_mp_mod); + ctx->state = 8; + break; + case 8: + sp_256_mont_mul_10(ctx->t4, ctx->t2, ctx->z, p256_mod, p256_mp_mod); + ctx->state = 9; + break; + case 9: + sp_256_mont_mul_10(ctx->t2, ctx->t2, q->x, p256_mod, p256_mp_mod); + ctx->state = 10; + break; + case 10: + /* S1 = Y1*Z2^3 */ + sp_256_mont_mul_10(ctx->t3, ctx->t3, ctx->y, p256_mod, p256_mp_mod); + ctx->state = 11; + break; + case 11: + /* S2 = Y2*Z1^3 */ + sp_256_mont_mul_10(ctx->t4, ctx->t4, q->y, p256_mod, p256_mp_mod); + ctx->state = 12; + break; + case 12: + /* H = U2 - U1 */ + sp_256_mont_sub_10(ctx->t2, ctx->t2, ctx->t1, p256_mod); + ctx->state = 13; + break; + case 13: + /* R = S2 - S1 */ + sp_256_mont_sub_10(ctx->t4, ctx->t4, ctx->t3, p256_mod); + ctx->state = 14; + break; + case 14: + /* Z3 = H*Z1*Z2 */ + sp_256_mont_mul_10(ctx->z, ctx->z, q->z, p256_mod, p256_mp_mod); + ctx->state = 15; + break; + case 15: + sp_256_mont_mul_10(ctx->z, ctx->z, ctx->t2, p256_mod, p256_mp_mod); + ctx->state = 16; + break; + case 16: + /* X3 = R^2 - H^3 - 2*U1*H^2 */ + sp_256_mont_sqr_10(ctx->x, ctx->t4, p256_mod, p256_mp_mod); + ctx->state = 17; + break; + case 17: + sp_256_mont_sqr_10(ctx->t5, ctx->t2, p256_mod, p256_mp_mod); + ctx->state = 18; + break; + case 18: + sp_256_mont_mul_10(ctx->y, ctx->t1, ctx->t5, p256_mod, p256_mp_mod); + ctx->state = 19; + break; + case 19: + sp_256_mont_mul_10(ctx->t5, ctx->t5, ctx->t2, p256_mod, p256_mp_mod); + ctx->state = 20; + break; + case 20: + sp_256_mont_sub_10(ctx->x, ctx->x, ctx->t5, p256_mod); + ctx->state = 21; + break; + case 21: + sp_256_mont_dbl_10(ctx->t1, ctx->y, p256_mod); + ctx->state = 22; + break; + case 22: + sp_256_mont_sub_10(ctx->x, ctx->x, ctx->t1, p256_mod); + ctx->state = 23; + break; + case 23: + /* Y3 = R*(U1*H^2 - X3) - S1*H^3 */ + sp_256_mont_sub_10(ctx->y, ctx->y, ctx->x, p256_mod); + ctx->state = 24; + break; + case 24: + sp_256_mont_mul_10(ctx->y, ctx->y, ctx->t4, p256_mod, p256_mp_mod); + ctx->state = 25; + break; + case 25: + sp_256_mont_mul_10(ctx->t5, ctx->t5, ctx->t3, p256_mod, p256_mp_mod); + ctx->state = 26; + break; + case 26: + sp_256_mont_sub_10(ctx->y, ctx->y, ctx->t5, p256_mod); + ctx->state = 27; + /* fall-through */ + case 27: + err = MP_OKAY; + break; + } + + if (err == MP_OKAY && ctx->state != 27) { + err = FP_WOULDBLOCK; + } + return err; +} +#endif /* WOLFSSL_SP_NONBLOCK */ + static void sp_256_proj_point_add_10(sp_point_256* r, const sp_point_256* p, const sp_point_256* q, sp_digit* t) { @@ -14020,6 +14362,118 @@ static void sp_256_proj_point_add_10(sp_point_256* r, const sp_point_256* p, con * heap Heap to use for allocation. * returns MEMORY_E when memory allocation fails and MP_OKAY on success. */ + +#ifdef WOLFSSL_SP_NONBLOCK +typedef struct sp_256_ecc_mulmod_10_ctx { + int state; + union { + sp_256_proj_point_dbl_10_ctx dbl_ctx; + sp_256_proj_point_add_10_ctx add_ctx; + }; + sp_point_256 t[3]; + sp_digit tmp[2 * 10 * 5]; + sp_digit n; + int i; + int c; + int y; +} sp_256_ecc_mulmod_10_ctx; + +static int sp_256_ecc_mulmod_10_nb(sp_ecc_ctx_t* sp_ctx, sp_point_256* r, + const sp_point_256* g, const sp_digit* k, int map, void* heap) +{ + int err = FP_WOULDBLOCK; + sp_256_ecc_mulmod_10_ctx* ctx = (sp_256_ecc_mulmod_10_ctx*)sp_ctx->data; + + typedef char ctx_size_test[sizeof(sp_256_ecc_mulmod_10_ctx) >= sizeof(*sp_ctx) ? -1 : 1]; + (void)sizeof(ctx_size_test); + + switch (ctx->state) { + case 0: /* INIT */ + XMEMSET(ctx->t, 0, sizeof(sp_point_256) * 3); + ctx->i = 9; + ctx->c = 22; + ctx->n = k[ctx->i--] << (26 - ctx->c); + + /* t[0] = {0, 0, 1} * norm */ + ctx->t[0].infinity = 1; + ctx->state = 1; + break; + case 1: /* T1X */ + /* t[1] = {g->x, g->y, g->z} * norm */ + err = sp_256_mod_mul_norm_10(ctx->t[1].x, g->x, p256_mod); + ctx->state = 2; + break; + case 2: /* T1Y */ + err = sp_256_mod_mul_norm_10(ctx->t[1].y, g->y, p256_mod); + ctx->state = 3; + break; + case 3: /* T1Z */ + err = sp_256_mod_mul_norm_10(ctx->t[1].z, g->z, p256_mod); + ctx->state = 4; + break; + case 4: /* ADDPREP */ + if (ctx->c == 0) { + if (ctx->i == -1) { + ctx->state = 7; + break; + } + + ctx->n = k[ctx->i--]; + ctx->c = 26; + } + ctx->y = (ctx->n >> 25) & 1; + ctx->n <<= 1; + XMEMSET(&ctx->add_ctx, 0, sizeof(ctx->add_ctx)); + ctx->state = 5; + break; + case 5: /* ADD */ + err = sp_256_proj_point_add_10_nb((sp_ecc_ctx_t*)&ctx->add_ctx, + &ctx->t[ctx->y^1], &ctx->t[0], &ctx->t[1], ctx->tmp); + if (err == MP_OKAY) { + XMEMCPY(&ctx->t[2], (void*)(((size_t)&ctx->t[0] & addr_mask[ctx->y^1]) + + ((size_t)&ctx->t[1] & addr_mask[ctx->y])), + sizeof(sp_point_256)); + XMEMSET(&ctx->dbl_ctx, 0, sizeof(ctx->dbl_ctx)); + ctx->state = 6; + } + break; + case 6: /* DBL */ + err = sp_256_proj_point_dbl_10_nb((sp_ecc_ctx_t*)&ctx->dbl_ctx, &ctx->t[2], + &ctx->t[2], ctx->tmp); + if (err == MP_OKAY) { + XMEMCPY((void*)(((size_t)&ctx->t[0] & addr_mask[ctx->y^1]) + + ((size_t)&ctx->t[1] & addr_mask[ctx->y])), &ctx->t[2], + sizeof(sp_point_256)); + ctx->state = 4; + ctx->c--; + } + break; + case 7: /* MAP */ + if (map != 0) { + sp_256_map_10(r, &ctx->t[0], ctx->tmp); + } + else { + XMEMCPY(r, &ctx->t[0], sizeof(sp_point_256)); + } + err = MP_OKAY; + break; + } + + if (err == MP_OKAY && ctx->state != 7) { + err = FP_WOULDBLOCK; + } + if (err != FP_WOULDBLOCK) { + ForceZero(ctx->tmp, sizeof(ctx->tmp)); + ForceZero(ctx->t, sizeof(ctx->t)); + } + + (void)heap; + + return err; +} + +#endif /* WOLFSSL_SP_NONBLOCK */ + static int sp_256_ecc_mulmod_10(sp_point_256* r, const sp_point_256* g, const sp_digit* k, int map, void* heap) { @@ -16826,6 +17280,46 @@ static void sp_256_mont_sqr_n_order_10(sp_digit* r, const sp_digit* a, int n) * a Number to invert. * td Temporary data. */ + +#ifdef WOLFSSL_SP_NONBLOCK +typedef struct sp_256_mont_inv_order_10_ctx { + int state; + int i; +} sp_256_mont_inv_order_10_ctx; +static int sp_256_mont_inv_order_10_nb(sp_ecc_ctx_t* sp_ctx, sp_digit* r, const sp_digit* a, + sp_digit* t) +{ + int err = FP_WOULDBLOCK; + sp_256_mont_inv_order_10_ctx* ctx = (sp_256_mont_inv_order_10_ctx*)sp_ctx; + + typedef char ctx_size_test[sizeof(sp_256_mont_inv_order_10_ctx) >= sizeof(*sp_ctx) ? -1 : 1]; + (void)sizeof(ctx_size_test); + + switch (ctx->state) { + case 0: + XMEMCPY(t, a, sizeof(sp_digit) * 10); + ctx->i = 254; + ctx->state = 1; + break; + case 1: + sp_256_mont_sqr_order_10(t, t); + if ((p256_order_minus_2[ctx->i / 32] & ((sp_int_digit)1 << (ctx->i % 32))) != 0) { + sp_256_mont_mul_order_10(t, t, a); + } + ctx->i--; + if (ctx->i == 0) { + ctx->state = 2; + } + break; + case 2: + XMEMCPY(r, t, sizeof(sp_digit) * 10U); + err = MP_OKAY; + break; + } + return err; +} +#endif /* WOLFSSL_SP_NONBLOCK */ + static void sp_256_mont_inv_order_10(sp_digit* r, const sp_digit* a, sp_digit* td) { @@ -16941,6 +17435,165 @@ static void sp_256_mont_inv_order_10(sp_digit* r, const sp_digit* a, * returns RNG failures, MEMORY_E when memory allocation fails and * MP_OKAY on success. */ +#ifdef WOLFSSL_SP_NONBLOCK +typedef struct sp_ecc_sign_256_ctx { + int state; + union { + sp_256_ecc_mulmod_10_ctx mulmod_ctx; + sp_256_mont_inv_order_10_ctx mont_inv_order_ctx; + }; + sp_digit e[2*10]; + sp_digit x[2*10]; + sp_digit k[2*10]; + sp_digit r[2*10]; + sp_digit tmp[3 * 2*10]; + sp_point_256 point; + sp_digit* s; + sp_digit* kInv; + int i; +} sp_ecc_sign_256_ctx; + +int sp_ecc_sign_256_nb(sp_ecc_ctx_t* sp_ctx, const byte* hash, word32 hashLen, WC_RNG* rng, mp_int* priv, + mp_int* rm, mp_int* sm, mp_int* km, void* heap) +{ + int err = FP_WOULDBLOCK; + sp_ecc_sign_256_ctx* ctx = (sp_ecc_sign_256_ctx*)sp_ctx->data; + + typedef char ctx_size_test[sizeof(sp_ecc_sign_256_ctx) >= sizeof(*sp_ctx) ? -1 : 1]; + (void)sizeof(ctx_size_test); + + (void)heap; + + switch (ctx->state) { + case 0: /* INIT */ + ctx->s = ctx->e; + ctx->kInv = ctx->k; + if (hashLen > 32U) { + hashLen = 32U; + } + + sp_256_from_bin(ctx->e, 10, hash, (int)hashLen); + + ctx->i = SP_ECC_MAX_SIG_GEN; + ctx->state = 1; + break; + case 1: /* GEN */ + sp_256_from_mp(ctx->x, 10, priv); + /* New random point. */ + if (km == NULL || mp_iszero(km)) { + err = sp_256_ecc_gen_k_10(rng, ctx->k); + } + else { + sp_256_from_mp(ctx->k, 10, km); + mp_zero(km); + } + XMEMSET(&ctx->mulmod_ctx, 0, sizeof(ctx->mulmod_ctx)); + ctx->state = 2; + break; + case 2: /* MULMOD */ + err = sp_256_ecc_mulmod_10_nb((sp_ecc_ctx_t*)&ctx->mulmod_ctx, + &ctx->point, &p256_base, ctx->k, 1, heap); + if (err == MP_OKAY) { + ctx->state = 3; + } + break; + case 3: /* MODORDER */ + { + int32_t c; + /* r = point->x mod order */ + XMEMCPY(ctx->r, ctx->point.x, sizeof(sp_digit) * 10U); + sp_256_norm_10(ctx->r); + c = sp_256_cmp_10(ctx->r, p256_order); + sp_256_cond_sub_10(ctx->r, ctx->r, p256_order, 0L - (sp_digit)(c >= 0)); + sp_256_norm_10(ctx->r); + ctx->state = 4; + break; + } + case 4: /* KMODORDER */ + /* Conv k to Montgomery form (mod order) */ + sp_256_mul_10(ctx->k, ctx->k, p256_norm_order); + err = sp_256_mod_10(ctx->k, ctx->k, p256_order); + if (err == MP_OKAY) { + sp_256_norm_10(ctx->k); + XMEMSET(&ctx->mont_inv_order_ctx, 0, sizeof(ctx->mont_inv_order_ctx)); + ctx->state = 5; + } + break; + case 5: /* KINV */ + /* kInv = 1/k mod order */ + err = sp_256_mont_inv_order_10_nb((sp_ecc_ctx_t*)&ctx->mont_inv_order_ctx, ctx->kInv, ctx->k, ctx->tmp); + if (err == MP_OKAY) { + XMEMSET(&ctx->mont_inv_order_ctx, 0, sizeof(ctx->mont_inv_order_ctx)); + ctx->state = 6; + } + break; + case 6: /* KINVNORM */ + sp_256_norm_10(ctx->kInv); + ctx->state = 7; + break; + case 7: /* R */ + /* s = r * x + e */ + sp_256_mul_10(ctx->x, ctx->x, ctx->r); + ctx->state = 8; + break; + case 8: /* S1 */ + err = sp_256_mod_10(ctx->x, ctx->x, p256_order); + if (err == MP_OKAY) + ctx->state = 9; + break; + case 9: /* S2 */ + { + sp_digit carry; + int32_t c; + sp_256_norm_10(ctx->x); + carry = sp_256_add_10(ctx->s, ctx->e, ctx->x); + sp_256_cond_sub_10(ctx->s, ctx->s, p256_order, 0 - carry); + sp_256_norm_10(ctx->s); + c = sp_256_cmp_10(ctx->s, p256_order); + sp_256_cond_sub_10(ctx->s, ctx->s, p256_order, 0L - (sp_digit)(c >= 0)); + sp_256_norm_10(ctx->s); + + /* s = s * k^-1 mod order */ + sp_256_mont_mul_order_10(ctx->s, ctx->s, ctx->kInv); + sp_256_norm_10(ctx->s); + + /* Check that signature is usable. */ + if (sp_256_iszero_10(ctx->s) == 0) { + ctx->state = 10; + break; + } + + /* not usable gen, try again */ + ctx->i--; + if (ctx->i == 0) { + err = RNG_FAILURE_E; + } + ctx->state = 1; + break; + } + case 10: /* RES */ + err = sp_256_to_mp(ctx->r, rm); + if (err == MP_OKAY) { + err = sp_256_to_mp(ctx->s, sm); + } + break; + } + + if (err == MP_OKAY && ctx->state != 10) { + err = FP_WOULDBLOCK; + } + if (err != FP_WOULDBLOCK) { + XMEMSET(ctx->e, 0, sizeof(sp_digit) * 2U * 10U); + XMEMSET(ctx->x, 0, sizeof(sp_digit) * 2U * 10U); + XMEMSET(ctx->k, 0, sizeof(sp_digit) * 2U * 10U); + XMEMSET(ctx->r, 0, sizeof(sp_digit) * 2U * 10U); + XMEMSET(ctx->tmp, 0, sizeof(sp_digit) * 3U * 2U * 10U); + } + + return err; +} +#endif /* WOLFSSL_SP_NONBLOCK */ + int sp_ecc_sign_256(const byte* hash, word32 hashLen, WC_RNG* rng, mp_int* priv, mp_int* rm, mp_int* sm, mp_int* km, void* heap) { @@ -17112,6 +17765,169 @@ int sp_ecc_sign_256(const byte* hash, word32 hashLen, WC_RNG* rng, mp_int* priv, * returns RNG failures, MEMORY_E when memory allocation fails and * MP_OKAY on success. */ +#ifdef WOLFSSL_SP_NONBLOCK +typedef struct sp_ecc_verify_256_ctx { + int state; + union { + sp_256_ecc_mulmod_10_ctx mulmod_ctx; + sp_256_mont_inv_order_10_ctx mont_inv_order_ctx; + sp_256_proj_point_dbl_10_ctx dbl_ctx; + sp_256_proj_point_add_10_ctx add_ctx; + }; + sp_digit u1[2*10]; + sp_digit u2[2*10]; + sp_digit s[2*10]; + sp_digit tmp[2*10 * 5]; + sp_point_256 p1; + sp_point_256 p2; +} sp_ecc_verify_256_ctx; + +int sp_ecc_verify_256_nb(sp_ecc_ctx_t* sp_ctx, const byte* hash, word32 hashLen, mp_int* pX, + mp_int* pY, mp_int* pZ, mp_int* r, mp_int* sm, int* res, void* heap) +{ + int err = FP_WOULDBLOCK; + sp_ecc_verify_256_ctx* ctx = (sp_ecc_verify_256_ctx*)sp_ctx->data; + + typedef char ctx_size_test[sizeof(sp_ecc_verify_256_ctx) >= sizeof(*sp_ctx) ? -1 : 1]; + (void)sizeof(ctx_size_test); + + switch (ctx->state) { + case 0: /* INIT */ + if (hashLen > 32U) { + hashLen = 32U; + } + + sp_256_from_bin(ctx->u1, 10, hash, (int)hashLen); + sp_256_from_mp(ctx->u2, 10, r); + sp_256_from_mp(ctx->s, 10, sm); + sp_256_from_mp(ctx->p2.x, 10, pX); + sp_256_from_mp(ctx->p2.y, 10, pY); + sp_256_from_mp(ctx->p2.z, 10, pZ); + sp_256_mul_10(ctx->s, ctx->s, p256_norm_order); + err = sp_256_mod_10(ctx->s, ctx->s, p256_order); + if (err == MP_OKAY) + ctx->state = 1; + break; + case 1: /* NORMS1 */ + sp_256_norm_10(ctx->s); + XMEMSET(&ctx->mont_inv_order_ctx, 0, sizeof(ctx->mont_inv_order_ctx)); + ctx->state = 2; + break; + case 2: /* NORMS2 */ + err = sp_256_mont_inv_order_10_nb((sp_ecc_ctx_t*)&ctx->mont_inv_order_ctx, ctx->s, ctx->s, ctx->tmp); + if (err == MP_OKAY) { + ctx->state = 3; + } + break; + case 3: /* NORMS3 */ + sp_256_mont_mul_order_10(ctx->u1, ctx->u1, ctx->s); + ctx->state = 4; + break; + case 4: /* NORMS4 */ + sp_256_mont_mul_order_10(ctx->u2, ctx->u2, ctx->s); + XMEMSET(&ctx->mulmod_ctx, 0, sizeof(ctx->mulmod_ctx)); + ctx->state = 5; + break; + case 5: /* MULBASE */ + err = sp_256_ecc_mulmod_10_nb((sp_ecc_ctx_t*)&ctx->mulmod_ctx, &ctx->p1, &p256_base, ctx->u1, 0, heap); + if (err == MP_OKAY) { + XMEMSET(&ctx->mulmod_ctx, 0, sizeof(ctx->mulmod_ctx)); + ctx->state = 6; + } + break; + case 6: /* MULMOD */ + err = sp_256_ecc_mulmod_10_nb((sp_ecc_ctx_t*)&ctx->mulmod_ctx, &ctx->p2, &ctx->p2, ctx->u2, 0, heap); + if (err == MP_OKAY) { + XMEMSET(&ctx->add_ctx, 0, sizeof(ctx->add_ctx)); + ctx->state = 7; + } + break; + case 7: /* ADD */ + err = sp_256_proj_point_add_10_nb((sp_ecc_ctx_t*)&ctx->add_ctx, &ctx->p1, &ctx->p1, &ctx->p2, ctx->tmp); + if (err == MP_OKAY) + ctx->state = 8; + break; + case 8: /* DBLPREP */ + if (sp_256_iszero_10(ctx->p1.z)) { + if (sp_256_iszero_10(ctx->p1.x) && sp_256_iszero_10(ctx->p1.y)) { + XMEMSET(&ctx->dbl_ctx, 0, sizeof(ctx->dbl_ctx)); + ctx->state = 9; + break; + } + else { + /* Y ordinate is not used from here - don't set. */ + int i; + for (i=0; i<10; i++) { + ctx->p1.x[i] = 0; + } + XMEMCPY(ctx->p1.z, p256_norm_mod, sizeof(p256_norm_mod)); + } + } + ctx->state = 10; + break; + case 9: /* DBL */ + err = sp_256_proj_point_dbl_10_nb((sp_ecc_ctx_t*)&ctx->dbl_ctx, &ctx->p1, + &ctx->p2, ctx->tmp); + if (err == MP_OKAY) { + ctx->state = 10; + } + break; + case 10: /* MONT */ + /* (r + n*order).z'.z' mod prime == (u1.G + u2.Q)->x' */ + /* Reload r and convert to Montgomery form. */ + sp_256_from_mp(ctx->u2, 10, r); + err = sp_256_mod_mul_norm_10(ctx->u2, ctx->u2, p256_mod); + if (err == MP_OKAY) + ctx->state = 11; + break; + case 11: /* SQR */ + /* u1 = r.z'.z' mod prime */ + sp_256_mont_sqr_10(ctx->p1.z, ctx->p1.z, p256_mod, p256_mp_mod); + ctx->state = 12; + break; + case 12: /* MUL */ + sp_256_mont_mul_10(ctx->u1, ctx->u2, ctx->p1.z, p256_mod, p256_mp_mod); + ctx->state = 13; + break; + case 13: /* RES */ + err = MP_OKAY; /* math okay, now check result */ + *res = (int)(sp_256_cmp_10(ctx->p1.x, ctx->u1) == 0); + if (*res == 0) { + sp_digit carry; + int32_t c; + + /* Reload r and add order. */ + sp_256_from_mp(ctx->u2, 10, r); + carry = sp_256_add_10(ctx->u2, ctx->u2, p256_order); + /* Carry means result is greater than mod and is not valid. */ + if (carry == 0) { + sp_256_norm_10(ctx->u2); + + /* Compare with mod and if greater or equal then not valid. */ + c = sp_256_cmp_10(ctx->u2, p256_mod); + if (c < 0) { + /* Convert to Montogomery form */ + err = sp_256_mod_mul_norm_10(ctx->u2, ctx->u2, p256_mod); + if (err == MP_OKAY) { + /* u1 = (r + 1*order).z'.z' mod prime */ + sp_256_mont_mul_10(ctx->u1, ctx->u2, ctx->p1.z, p256_mod, + p256_mp_mod); + *res = (int)(sp_256_cmp_10(ctx->p1.x, ctx->u1) == 0); + } + } + } + } + break; + } + + if (err == MP_OKAY && ctx->state != 13) { + err = FP_WOULDBLOCK; + } + + return err; +} +#endif /* WOLFSSL_SP_NONBLOCK */ + int sp_ecc_verify_256(const byte* hash, word32 hashLen, mp_int* pX, mp_int* pY, mp_int* pZ, mp_int* r, mp_int* sm, int* res, void* heap) { @@ -19472,6 +20288,141 @@ static void sp_384_div2_15(sp_digit* r, const sp_digit* a, const sp_digit* m) * p Point to double. * t Temporary ordinate data. */ +#ifdef WOLFSSL_SP_NONBLOCK +typedef struct sp_384_proj_point_dbl_15_ctx { + int state; + sp_digit* t1; + sp_digit* t2; + sp_digit* x; + sp_digit* y; + sp_digit* z; +} sp_384_proj_point_dbl_15_ctx; + +static int sp_384_proj_point_dbl_15_nb(sp_ecc_ctx_t* sp_ctx, sp_point_384* r, const sp_point_384* p, sp_digit* t) +{ + int err = FP_WOULDBLOCK; + sp_384_proj_point_dbl_15_ctx* ctx = (sp_384_proj_point_dbl_15_ctx*)sp_ctx->data; + + typedef char ctx_size_test[sizeof(sp_384_proj_point_dbl_15_ctx) >= sizeof(*sp_ctx) ? -1 : 1]; + (void)sizeof(ctx_size_test); + + switch (ctx->state) { + case 0: + ctx->t1 = t; + ctx->t2 = t + 2*15; + ctx->x = r->x; + ctx->y = r->y; + ctx->z = r->z; + + /* Put infinity into result. */ + if (r != p) { + r->infinity = p->infinity; + } + ctx->state = 1; + break; + case 1: + /* T1 = Z * Z */ + sp_384_mont_sqr_15(ctx->t1, p->z, p384_mod, p384_mp_mod); + ctx->state = 2; + break; + case 2: + /* Z = Y * Z */ + sp_384_mont_mul_15(ctx->z, p->y, p->z, p384_mod, p384_mp_mod); + ctx->state = 3; + break; + case 3: + /* Z = 2Z */ + sp_384_mont_dbl_15(ctx->z, ctx->z, p384_mod); + ctx->state = 4; + break; + case 4: + /* T2 = X - T1 */ + sp_384_mont_sub_15(ctx->t2, p->x, ctx->t1, p384_mod); + ctx->state = 5; + break; + case 5: + /* T1 = X + T1 */ + sp_384_mont_add_15(ctx->t1, p->x, ctx->t1, p384_mod); + ctx->state = 6; + break; + case 6: + /* T2 = T1 * T2 */ + sp_384_mont_mul_15(ctx->t2, ctx->t1, ctx->t2, p384_mod, p384_mp_mod); + ctx->state = 7; + break; + case 7: + /* T1 = 3T2 */ + sp_384_mont_tpl_15(ctx->t1, ctx->t2, p384_mod); + ctx->state = 8; + break; + case 8: + /* Y = 2Y */ + sp_384_mont_dbl_15(ctx->y, p->y, p384_mod); + ctx->state = 9; + break; + case 9: + /* Y = Y * Y */ + sp_384_mont_sqr_15(ctx->y, ctx->y, p384_mod, p384_mp_mod); + ctx->state = 10; + break; + case 10: + /* T2 = Y * Y */ + sp_384_mont_sqr_15(ctx->t2, ctx->y, p384_mod, p384_mp_mod); + ctx->state = 11; + break; + case 11: + /* T2 = T2/2 */ + sp_384_div2_15(ctx->t2, ctx->t2, p384_mod); + ctx->state = 12; + break; + case 12: + /* Y = Y * X */ + sp_384_mont_mul_15(ctx->y, ctx->y, p->x, p384_mod, p384_mp_mod); + ctx->state = 13; + break; + case 13: + /* X = T1 * T1 */ + sp_384_mont_sqr_15(ctx->x, ctx->t1, p384_mod, p384_mp_mod); + ctx->state = 14; + break; + case 14: + /* X = X - Y */ + sp_384_mont_sub_15(ctx->x, ctx->x, ctx->y, p384_mod); + ctx->state = 15; + break; + case 15: + /* X = X - Y */ + sp_384_mont_sub_15(ctx->x, ctx->x, ctx->y, p384_mod); + ctx->state = 16; + break; + case 16: + /* Y = Y - X */ + sp_384_mont_sub_15(ctx->y, ctx->y, ctx->x, p384_mod); + ctx->state = 17; + break; + case 17: + /* Y = Y * T1 */ + sp_384_mont_mul_15(ctx->y, ctx->y, ctx->t1, p384_mod, p384_mp_mod); + ctx->state = 18; + break; + case 18: + /* Y = Y - T2 */ + sp_384_mont_sub_15(ctx->y, ctx->y, ctx->t2, p384_mod); + ctx->state = 19; + /* fall-through */ + case 19: + err = MP_OKAY; + break; + } + + if (err == MP_OKAY && ctx->state != 19) { + err = FP_WOULDBLOCK; + } + + return err; +} +#endif /* WOLFSSL_SP_NONBLOCK */ + static void sp_384_proj_point_dbl_15(sp_point_384* r, const sp_point_384* p, sp_digit* t) { sp_digit* t1 = t; @@ -19548,6 +20499,209 @@ static int sp_384_cmp_equal_15(const sp_digit* a, const sp_digit* b) * q Second point to add. * t Temporary ordinate data. */ + +#ifdef WOLFSSL_SP_NONBLOCK +typedef struct sp_384_proj_point_add_15_ctx { + int state; + sp_384_proj_point_dbl_15_ctx dbl_ctx; + const sp_point_384* ap[2]; + sp_point_384* rp[2]; + sp_digit* t1; + sp_digit* t2; + sp_digit* t3; + sp_digit* t4; + sp_digit* t5; + sp_digit* x; + sp_digit* y; + sp_digit* z; +} sp_384_proj_point_add_15_ctx; + +static int sp_384_proj_point_add_15_nb(sp_ecc_ctx_t* sp_ctx, sp_point_384* r, + const sp_point_384* p, const sp_point_384* q, sp_digit* t) +{ + int err = FP_WOULDBLOCK; + sp_384_proj_point_add_15_ctx* ctx = (sp_384_proj_point_add_15_ctx*)sp_ctx->data; + + /* Ensure only the first point is the same as the result. */ + if (q == r) { + const sp_point_384* a = p; + p = q; + q = a; + } + + typedef char ctx_size_test[sizeof(sp_384_proj_point_add_15_ctx) >= sizeof(*sp_ctx) ? -1 : 1]; + (void)sizeof(ctx_size_test); + + switch (ctx->state) { + case 0: /* INIT */ + ctx->t1 = t; + ctx->t2 = t + 2*15; + ctx->t3 = t + 4*15; + ctx->t4 = t + 6*15; + ctx->t5 = t + 8*15; + + ctx->state = 1; + break; + case 1: + /* Check double */ + (void)sp_384_sub_15(ctx->t1, p384_mod, q->y); + sp_384_norm_15(ctx->t1); + if ((sp_384_cmp_equal_15(p->x, q->x) & sp_384_cmp_equal_15(p->z, q->z) & + (sp_384_cmp_equal_15(p->y, q->y) | sp_384_cmp_equal_15(p->y, ctx->t1))) != 0) + { + XMEMSET(&ctx->dbl_ctx, 0, sizeof(ctx->dbl_ctx)); + ctx->state = 2; + } + else { + ctx->state = 3; + } + break; + case 2: + err = sp_384_proj_point_dbl_15_nb((sp_ecc_ctx_t*)&ctx->dbl_ctx, r, p, t); + if (err == MP_OKAY) + ctx->state = 27; /* done */ + break; + case 3: + { + int i; + ctx->rp[0] = r; + + /*lint allow cast to different type of pointer*/ + ctx->rp[1] = (sp_point_384*)t; /*lint !e9087 !e740*/ + XMEMSET(ctx->rp[1], 0, sizeof(sp_point_384)); + ctx->x = ctx->rp[p->infinity | q->infinity]->x; + ctx->y = ctx->rp[p->infinity | q->infinity]->y; + ctx->z = ctx->rp[p->infinity | q->infinity]->z; + + ctx->ap[0] = p; + ctx->ap[1] = q; + for (i=0; i<15; i++) { + r->x[i] = ctx->ap[p->infinity]->x[i]; + } + for (i=0; i<15; i++) { + r->y[i] = ctx->ap[p->infinity]->y[i]; + } + for (i=0; i<15; i++) { + r->z[i] = ctx->ap[p->infinity]->z[i]; + } + r->infinity = ctx->ap[p->infinity]->infinity; + + ctx->state = 4; + break; + } + case 4: + /* U1 = X1*Z2^2 */ + sp_384_mont_sqr_15(ctx->t1, q->z, p384_mod, p384_mp_mod); + ctx->state = 5; + break; + case 5: + sp_384_mont_mul_15(ctx->t3, ctx->t1, q->z, p384_mod, p384_mp_mod); + ctx->state = 6; + break; + case 6: + sp_384_mont_mul_15(ctx->t1, ctx->t1, ctx->x, p384_mod, p384_mp_mod); + ctx->state = 7; + break; + case 7: + /* U2 = X2*Z1^2 */ + sp_384_mont_sqr_15(ctx->t2, ctx->z, p384_mod, p384_mp_mod); + ctx->state = 8; + break; + case 8: + sp_384_mont_mul_15(ctx->t4, ctx->t2, ctx->z, p384_mod, p384_mp_mod); + ctx->state = 9; + break; + case 9: + sp_384_mont_mul_15(ctx->t2, ctx->t2, q->x, p384_mod, p384_mp_mod); + ctx->state = 10; + break; + case 10: + /* S1 = Y1*Z2^3 */ + sp_384_mont_mul_15(ctx->t3, ctx->t3, ctx->y, p384_mod, p384_mp_mod); + ctx->state = 11; + break; + case 11: + /* S2 = Y2*Z1^3 */ + sp_384_mont_mul_15(ctx->t4, ctx->t4, q->y, p384_mod, p384_mp_mod); + ctx->state = 12; + break; + case 12: + /* H = U2 - U1 */ + sp_384_mont_sub_15(ctx->t2, ctx->t2, ctx->t1, p384_mod); + ctx->state = 13; + break; + case 13: + /* R = S2 - S1 */ + sp_384_mont_sub_15(ctx->t4, ctx->t4, ctx->t3, p384_mod); + ctx->state = 14; + break; + case 14: + /* Z3 = H*Z1*Z2 */ + sp_384_mont_mul_15(ctx->z, ctx->z, q->z, p384_mod, p384_mp_mod); + ctx->state = 15; + break; + case 15: + sp_384_mont_mul_15(ctx->z, ctx->z, ctx->t2, p384_mod, p384_mp_mod); + ctx->state = 16; + break; + case 16: + /* X3 = R^2 - H^3 - 2*U1*H^2 */ + sp_384_mont_sqr_15(ctx->x, ctx->t4, p384_mod, p384_mp_mod); + ctx->state = 17; + break; + case 17: + sp_384_mont_sqr_15(ctx->t5, ctx->t2, p384_mod, p384_mp_mod); + ctx->state = 18; + break; + case 18: + sp_384_mont_mul_15(ctx->y, ctx->t1, ctx->t5, p384_mod, p384_mp_mod); + ctx->state = 19; + break; + case 19: + sp_384_mont_mul_15(ctx->t5, ctx->t5, ctx->t2, p384_mod, p384_mp_mod); + ctx->state = 20; + break; + case 20: + sp_384_mont_sub_15(ctx->x, ctx->x, ctx->t5, p384_mod); + ctx->state = 21; + break; + case 21: + sp_384_mont_dbl_15(ctx->t1, ctx->y, p384_mod); + ctx->state = 22; + break; + case 22: + sp_384_mont_sub_15(ctx->x, ctx->x, ctx->t1, p384_mod); + ctx->state = 23; + break; + case 23: + /* Y3 = R*(U1*H^2 - X3) - S1*H^3 */ + sp_384_mont_sub_15(ctx->y, ctx->y, ctx->x, p384_mod); + ctx->state = 24; + break; + case 24: + sp_384_mont_mul_15(ctx->y, ctx->y, ctx->t4, p384_mod, p384_mp_mod); + ctx->state = 25; + break; + case 25: + sp_384_mont_mul_15(ctx->t5, ctx->t5, ctx->t3, p384_mod, p384_mp_mod); + ctx->state = 26; + break; + case 26: + sp_384_mont_sub_15(ctx->y, ctx->y, ctx->t5, p384_mod); + ctx->state = 27; + /* fall-through */ + case 27: + err = MP_OKAY; + break; + } + + if (err == MP_OKAY && ctx->state != 27) { + err = FP_WOULDBLOCK; + } + return err; +} +#endif /* WOLFSSL_SP_NONBLOCK */ + static void sp_384_proj_point_add_15(sp_point_384* r, const sp_point_384* p, const sp_point_384* q, sp_digit* t) { @@ -19646,6 +20800,118 @@ static void sp_384_proj_point_add_15(sp_point_384* r, const sp_point_384* p, con * heap Heap to use for allocation. * returns MEMORY_E when memory allocation fails and MP_OKAY on success. */ + +#ifdef WOLFSSL_SP_NONBLOCK +typedef struct sp_384_ecc_mulmod_15_ctx { + int state; + union { + sp_384_proj_point_dbl_15_ctx dbl_ctx; + sp_384_proj_point_add_15_ctx add_ctx; + }; + sp_point_384 t[3]; + sp_digit tmp[2 * 15 * 6]; + sp_digit n; + int i; + int c; + int y; +} sp_384_ecc_mulmod_15_ctx; + +static int sp_384_ecc_mulmod_15_nb(sp_ecc_ctx_t* sp_ctx, sp_point_384* r, + const sp_point_384* g, const sp_digit* k, int map, void* heap) +{ + int err = FP_WOULDBLOCK; + sp_384_ecc_mulmod_15_ctx* ctx = (sp_384_ecc_mulmod_15_ctx*)sp_ctx->data; + + typedef char ctx_size_test[sizeof(sp_384_ecc_mulmod_15_ctx) >= sizeof(*sp_ctx) ? -1 : 1]; + (void)sizeof(ctx_size_test); + + switch (ctx->state) { + case 0: /* INIT */ + XMEMSET(ctx->t, 0, sizeof(sp_point_384) * 3); + ctx->i = 14; + ctx->c = 20; + ctx->n = k[ctx->i--] << (26 - ctx->c); + + /* t[0] = {0, 0, 1} * norm */ + ctx->t[0].infinity = 1; + ctx->state = 1; + break; + case 1: /* T1X */ + /* t[1] = {g->x, g->y, g->z} * norm */ + err = sp_384_mod_mul_norm_15(ctx->t[1].x, g->x, p384_mod); + ctx->state = 2; + break; + case 2: /* T1Y */ + err = sp_384_mod_mul_norm_15(ctx->t[1].y, g->y, p384_mod); + ctx->state = 3; + break; + case 3: /* T1Z */ + err = sp_384_mod_mul_norm_15(ctx->t[1].z, g->z, p384_mod); + ctx->state = 4; + break; + case 4: /* ADDPREP */ + if (ctx->c == 0) { + if (ctx->i == -1) { + ctx->state = 7; + break; + } + + ctx->n = k[ctx->i--]; + ctx->c = 26; + } + ctx->y = (ctx->n >> 25) & 1; + ctx->n <<= 1; + XMEMSET(&ctx->add_ctx, 0, sizeof(ctx->add_ctx)); + ctx->state = 5; + break; + case 5: /* ADD */ + err = sp_384_proj_point_add_15_nb((sp_ecc_ctx_t*)&ctx->add_ctx, + &ctx->t[ctx->y^1], &ctx->t[0], &ctx->t[1], ctx->tmp); + if (err == MP_OKAY) { + XMEMCPY(&ctx->t[2], (void*)(((size_t)&ctx->t[0] & addr_mask[ctx->y^1]) + + ((size_t)&ctx->t[1] & addr_mask[ctx->y])), + sizeof(sp_point_384)); + XMEMSET(&ctx->dbl_ctx, 0, sizeof(ctx->dbl_ctx)); + ctx->state = 6; + } + break; + case 6: /* DBL */ + err = sp_384_proj_point_dbl_15_nb((sp_ecc_ctx_t*)&ctx->dbl_ctx, &ctx->t[2], + &ctx->t[2], ctx->tmp); + if (err == MP_OKAY) { + XMEMCPY((void*)(((size_t)&ctx->t[0] & addr_mask[ctx->y^1]) + + ((size_t)&ctx->t[1] & addr_mask[ctx->y])), &ctx->t[2], + sizeof(sp_point_384)); + ctx->state = 4; + ctx->c--; + } + break; + case 7: /* MAP */ + if (map != 0) { + sp_384_map_15(r, &ctx->t[0], ctx->tmp); + } + else { + XMEMCPY(r, &ctx->t[0], sizeof(sp_point_384)); + } + err = MP_OKAY; + break; + } + + if (err == MP_OKAY && ctx->state != 7) { + err = FP_WOULDBLOCK; + } + if (err != FP_WOULDBLOCK) { + ForceZero(ctx->tmp, sizeof(ctx->tmp)); + ForceZero(ctx->t, sizeof(ctx->t)); + } + + (void)heap; + + return err; +} + +#endif /* WOLFSSL_SP_NONBLOCK */ + static int sp_384_ecc_mulmod_15(sp_point_384* r, const sp_point_384* g, const sp_digit* k, int map, void* heap) { @@ -22973,6 +24239,46 @@ static void sp_384_mont_sqr_n_order_15(sp_digit* r, const sp_digit* a, int n) * a Number to invert. * td Temporary data. */ + +#ifdef WOLFSSL_SP_NONBLOCK +typedef struct sp_384_mont_inv_order_15_ctx { + int state; + int i; +} sp_384_mont_inv_order_15_ctx; +static int sp_384_mont_inv_order_15_nb(sp_ecc_ctx_t* sp_ctx, sp_digit* r, const sp_digit* a, + sp_digit* t) +{ + int err = FP_WOULDBLOCK; + sp_384_mont_inv_order_15_ctx* ctx = (sp_384_mont_inv_order_15_ctx*)sp_ctx; + + typedef char ctx_size_test[sizeof(sp_384_mont_inv_order_15_ctx) >= sizeof(*sp_ctx) ? -1 : 1]; + (void)sizeof(ctx_size_test); + + switch (ctx->state) { + case 0: + XMEMCPY(t, a, sizeof(sp_digit) * 15); + ctx->i = 382; + ctx->state = 1; + break; + case 1: + sp_384_mont_sqr_order_15(t, t); + if ((p384_order_minus_2[ctx->i / 32] & ((sp_int_digit)1 << (ctx->i % 32))) != 0) { + sp_384_mont_mul_order_15(t, t, a); + } + ctx->i--; + if (ctx->i == 0) { + ctx->state = 2; + } + break; + case 2: + XMEMCPY(r, t, sizeof(sp_digit) * 15U); + err = MP_OKAY; + break; + } + return err; +} +#endif /* WOLFSSL_SP_NONBLOCK */ + static void sp_384_mont_inv_order_15(sp_digit* r, const sp_digit* a, sp_digit* td) { @@ -23059,6 +24365,165 @@ static void sp_384_mont_inv_order_15(sp_digit* r, const sp_digit* a, * returns RNG failures, MEMORY_E when memory allocation fails and * MP_OKAY on success. */ +#ifdef WOLFSSL_SP_NONBLOCK +typedef struct sp_ecc_sign_384_ctx { + int state; + union { + sp_384_ecc_mulmod_15_ctx mulmod_ctx; + sp_384_mont_inv_order_15_ctx mont_inv_order_ctx; + }; + sp_digit e[2*15]; + sp_digit x[2*15]; + sp_digit k[2*15]; + sp_digit r[2*15]; + sp_digit tmp[3 * 2*15]; + sp_point_384 point; + sp_digit* s; + sp_digit* kInv; + int i; +} sp_ecc_sign_384_ctx; + +int sp_ecc_sign_384_nb(sp_ecc_ctx_t* sp_ctx, const byte* hash, word32 hashLen, WC_RNG* rng, mp_int* priv, + mp_int* rm, mp_int* sm, mp_int* km, void* heap) +{ + int err = FP_WOULDBLOCK; + sp_ecc_sign_384_ctx* ctx = (sp_ecc_sign_384_ctx*)sp_ctx->data; + + typedef char ctx_size_test[sizeof(sp_ecc_sign_384_ctx) >= sizeof(*sp_ctx) ? -1 : 1]; + (void)sizeof(ctx_size_test); + + (void)heap; + + switch (ctx->state) { + case 0: /* INIT */ + ctx->s = ctx->e; + ctx->kInv = ctx->k; + if (hashLen > 48U) { + hashLen = 48U; + } + + sp_384_from_bin(ctx->e, 15, hash, (int)hashLen); + + ctx->i = SP_ECC_MAX_SIG_GEN; + ctx->state = 1; + break; + case 1: /* GEN */ + sp_384_from_mp(ctx->x, 15, priv); + /* New random point. */ + if (km == NULL || mp_iszero(km)) { + err = sp_384_ecc_gen_k_15(rng, ctx->k); + } + else { + sp_384_from_mp(ctx->k, 15, km); + mp_zero(km); + } + XMEMSET(&ctx->mulmod_ctx, 0, sizeof(ctx->mulmod_ctx)); + ctx->state = 2; + break; + case 2: /* MULMOD */ + err = sp_384_ecc_mulmod_15_nb((sp_ecc_ctx_t*)&ctx->mulmod_ctx, + &ctx->point, &p384_base, ctx->k, 1, heap); + if (err == MP_OKAY) { + ctx->state = 3; + } + break; + case 3: /* MODORDER */ + { + int32_t c; + /* r = point->x mod order */ + XMEMCPY(ctx->r, ctx->point.x, sizeof(sp_digit) * 15U); + sp_384_norm_15(ctx->r); + c = sp_384_cmp_15(ctx->r, p384_order); + sp_384_cond_sub_15(ctx->r, ctx->r, p384_order, 0L - (sp_digit)(c >= 0)); + sp_384_norm_15(ctx->r); + ctx->state = 4; + break; + } + case 4: /* KMODORDER */ + /* Conv k to Montgomery form (mod order) */ + sp_384_mul_15(ctx->k, ctx->k, p384_norm_order); + err = sp_384_mod_15(ctx->k, ctx->k, p384_order); + if (err == MP_OKAY) { + sp_384_norm_15(ctx->k); + XMEMSET(&ctx->mont_inv_order_ctx, 0, sizeof(ctx->mont_inv_order_ctx)); + ctx->state = 5; + } + break; + case 5: /* KINV */ + /* kInv = 1/k mod order */ + err = sp_384_mont_inv_order_15_nb((sp_ecc_ctx_t*)&ctx->mont_inv_order_ctx, ctx->kInv, ctx->k, ctx->tmp); + if (err == MP_OKAY) { + XMEMSET(&ctx->mont_inv_order_ctx, 0, sizeof(ctx->mont_inv_order_ctx)); + ctx->state = 6; + } + break; + case 6: /* KINVNORM */ + sp_384_norm_15(ctx->kInv); + ctx->state = 7; + break; + case 7: /* R */ + /* s = r * x + e */ + sp_384_mul_15(ctx->x, ctx->x, ctx->r); + ctx->state = 8; + break; + case 8: /* S1 */ + err = sp_384_mod_15(ctx->x, ctx->x, p384_order); + if (err == MP_OKAY) + ctx->state = 9; + break; + case 9: /* S2 */ + { + sp_digit carry; + int32_t c; + sp_384_norm_15(ctx->x); + carry = sp_384_add_15(ctx->s, ctx->e, ctx->x); + sp_384_cond_sub_15(ctx->s, ctx->s, p384_order, 0 - carry); + sp_384_norm_15(ctx->s); + c = sp_384_cmp_15(ctx->s, p384_order); + sp_384_cond_sub_15(ctx->s, ctx->s, p384_order, 0L - (sp_digit)(c >= 0)); + sp_384_norm_15(ctx->s); + + /* s = s * k^-1 mod order */ + sp_384_mont_mul_order_15(ctx->s, ctx->s, ctx->kInv); + sp_384_norm_15(ctx->s); + + /* Check that signature is usable. */ + if (sp_384_iszero_15(ctx->s) == 0) { + ctx->state = 10; + break; + } + + /* not usable gen, try again */ + ctx->i--; + if (ctx->i == 0) { + err = RNG_FAILURE_E; + } + ctx->state = 1; + break; + } + case 10: /* RES */ + err = sp_384_to_mp(ctx->r, rm); + if (err == MP_OKAY) { + err = sp_384_to_mp(ctx->s, sm); + } + break; + } + + if (err == MP_OKAY && ctx->state != 10) { + err = FP_WOULDBLOCK; + } + if (err != FP_WOULDBLOCK) { + XMEMSET(ctx->e, 0, sizeof(sp_digit) * 2U * 15U); + XMEMSET(ctx->x, 0, sizeof(sp_digit) * 2U * 15U); + XMEMSET(ctx->k, 0, sizeof(sp_digit) * 2U * 15U); + XMEMSET(ctx->r, 0, sizeof(sp_digit) * 2U * 15U); + XMEMSET(ctx->tmp, 0, sizeof(sp_digit) * 3U * 2U * 15U); + } + + return err; +} +#endif /* WOLFSSL_SP_NONBLOCK */ + int sp_ecc_sign_384(const byte* hash, word32 hashLen, WC_RNG* rng, mp_int* priv, mp_int* rm, mp_int* sm, mp_int* km, void* heap) { @@ -23230,6 +24695,169 @@ int sp_ecc_sign_384(const byte* hash, word32 hashLen, WC_RNG* rng, mp_int* priv, * returns RNG failures, MEMORY_E when memory allocation fails and * MP_OKAY on success. */ +#ifdef WOLFSSL_SP_NONBLOCK +typedef struct sp_ecc_verify_384_ctx { + int state; + union { + sp_384_ecc_mulmod_15_ctx mulmod_ctx; + sp_384_mont_inv_order_15_ctx mont_inv_order_ctx; + sp_384_proj_point_dbl_15_ctx dbl_ctx; + sp_384_proj_point_add_15_ctx add_ctx; + }; + sp_digit u1[2*15]; + sp_digit u2[2*15]; + sp_digit s[2*15]; + sp_digit tmp[2*15 * 5]; + sp_point_384 p1; + sp_point_384 p2; +} sp_ecc_verify_384_ctx; + +int sp_ecc_verify_384_nb(sp_ecc_ctx_t* sp_ctx, const byte* hash, word32 hashLen, mp_int* pX, + mp_int* pY, mp_int* pZ, mp_int* r, mp_int* sm, int* res, void* heap) +{ + int err = FP_WOULDBLOCK; + sp_ecc_verify_384_ctx* ctx = (sp_ecc_verify_384_ctx*)sp_ctx->data; + + typedef char ctx_size_test[sizeof(sp_ecc_verify_384_ctx) >= sizeof(*sp_ctx) ? -1 : 1]; + (void)sizeof(ctx_size_test); + + switch (ctx->state) { + case 0: /* INIT */ + if (hashLen > 48U) { + hashLen = 48U; + } + + sp_384_from_bin(ctx->u1, 15, hash, (int)hashLen); + sp_384_from_mp(ctx->u2, 15, r); + sp_384_from_mp(ctx->s, 15, sm); + sp_384_from_mp(ctx->p2.x, 15, pX); + sp_384_from_mp(ctx->p2.y, 15, pY); + sp_384_from_mp(ctx->p2.z, 15, pZ); + sp_384_mul_15(ctx->s, ctx->s, p384_norm_order); + err = sp_384_mod_15(ctx->s, ctx->s, p384_order); + if (err == MP_OKAY) + ctx->state = 1; + break; + case 1: /* NORMS1 */ + sp_384_norm_15(ctx->s); + XMEMSET(&ctx->mont_inv_order_ctx, 0, sizeof(ctx->mont_inv_order_ctx)); + ctx->state = 2; + break; + case 2: /* NORMS2 */ + err = sp_384_mont_inv_order_15_nb((sp_ecc_ctx_t*)&ctx->mont_inv_order_ctx, ctx->s, ctx->s, ctx->tmp); + if (err == MP_OKAY) { + ctx->state = 3; + } + break; + case 3: /* NORMS3 */ + sp_384_mont_mul_order_15(ctx->u1, ctx->u1, ctx->s); + ctx->state = 4; + break; + case 4: /* NORMS4 */ + sp_384_mont_mul_order_15(ctx->u2, ctx->u2, ctx->s); + XMEMSET(&ctx->mulmod_ctx, 0, sizeof(ctx->mulmod_ctx)); + ctx->state = 5; + break; + case 5: /* MULBASE */ + err = sp_384_ecc_mulmod_15_nb((sp_ecc_ctx_t*)&ctx->mulmod_ctx, &ctx->p1, &p384_base, ctx->u1, 0, heap); + if (err == MP_OKAY) { + XMEMSET(&ctx->mulmod_ctx, 0, sizeof(ctx->mulmod_ctx)); + ctx->state = 6; + } + break; + case 6: /* MULMOD */ + err = sp_384_ecc_mulmod_15_nb((sp_ecc_ctx_t*)&ctx->mulmod_ctx, &ctx->p2, &ctx->p2, ctx->u2, 0, heap); + if (err == MP_OKAY) { + XMEMSET(&ctx->add_ctx, 0, sizeof(ctx->add_ctx)); + ctx->state = 7; + } + break; + case 7: /* ADD */ + err = sp_384_proj_point_add_15_nb((sp_ecc_ctx_t*)&ctx->add_ctx, &ctx->p1, &ctx->p1, &ctx->p2, ctx->tmp); + if (err == MP_OKAY) + ctx->state = 8; + break; + case 8: /* DBLPREP */ + if (sp_384_iszero_15(ctx->p1.z)) { + if (sp_384_iszero_15(ctx->p1.x) && sp_384_iszero_15(ctx->p1.y)) { + XMEMSET(&ctx->dbl_ctx, 0, sizeof(ctx->dbl_ctx)); + ctx->state = 9; + break; + } + else { + /* Y ordinate is not used from here - don't set. */ + int i; + for (i=0; i<15; i++) { + ctx->p1.x[i] = 0; + } + XMEMCPY(ctx->p1.z, p384_norm_mod, sizeof(p384_norm_mod)); + } + } + ctx->state = 10; + break; + case 9: /* DBL */ + err = sp_384_proj_point_dbl_15_nb((sp_ecc_ctx_t*)&ctx->dbl_ctx, &ctx->p1, + &ctx->p2, ctx->tmp); + if (err == MP_OKAY) { + ctx->state = 10; + } + break; + case 10: /* MONT */ + /* (r + n*order).z'.z' mod prime == (u1.G + u2.Q)->x' */ + /* Reload r and convert to Montgomery form. */ + sp_384_from_mp(ctx->u2, 15, r); + err = sp_384_mod_mul_norm_15(ctx->u2, ctx->u2, p384_mod); + if (err == MP_OKAY) + ctx->state = 11; + break; + case 11: /* SQR */ + /* u1 = r.z'.z' mod prime */ + sp_384_mont_sqr_15(ctx->p1.z, ctx->p1.z, p384_mod, p384_mp_mod); + ctx->state = 12; + break; + case 12: /* MUL */ + sp_384_mont_mul_15(ctx->u1, ctx->u2, ctx->p1.z, p384_mod, p384_mp_mod); + ctx->state = 13; + break; + case 13: /* RES */ + err = MP_OKAY; /* math okay, now check result */ + *res = (int)(sp_384_cmp_15(ctx->p1.x, ctx->u1) == 0); + if (*res == 0) { + sp_digit carry; + int32_t c; + + /* Reload r and add order. */ + sp_384_from_mp(ctx->u2, 15, r); + carry = sp_384_add_15(ctx->u2, ctx->u2, p384_order); + /* Carry means result is greater than mod and is not valid. */ + if (carry == 0) { + sp_384_norm_15(ctx->u2); + + /* Compare with mod and if greater or equal then not valid. */ + c = sp_384_cmp_15(ctx->u2, p384_mod); + if (c < 0) { + /* Convert to Montogomery form */ + err = sp_384_mod_mul_norm_15(ctx->u2, ctx->u2, p384_mod); + if (err == MP_OKAY) { + /* u1 = (r + 1*order).z'.z' mod prime */ + sp_384_mont_mul_15(ctx->u1, ctx->u2, ctx->p1.z, p384_mod, + p384_mp_mod); + *res = (int)(sp_384_cmp_15(ctx->p1.x, ctx->u1) == 0); + } + } + } + } + break; + } + + if (err == MP_OKAY && ctx->state != 13) { + err = FP_WOULDBLOCK; + } + + return err; +} +#endif /* WOLFSSL_SP_NONBLOCK */ + int sp_ecc_verify_384(const byte* hash, word32 hashLen, mp_int* pX, mp_int* pY, mp_int* pZ, mp_int* r, mp_int* sm, int* res, void* heap) { diff --git a/wolfcrypt/src/sp_c64.c b/wolfcrypt/src/sp_c64.c index 74e54f2268..4d4d3b645c 100644 --- a/wolfcrypt/src/sp_c64.c +++ b/wolfcrypt/src/sp_c64.c @@ -57,6 +57,10 @@ static const size_t addr_mask[2] = { 0, (size_t)-1 }; #endif +#if defined(WOLFSSL_SP_NONBLOCK) && (!defined(WOLFSSL_SP_NO_MALLOC) || !defined(WOLFSSL_SP_SMALL)) + #error SP non-blocking requires small and no-malloc (WOLFSSL_SP_SMALL and WOLFSSL_SP_NO_MALLOC) +#endif + #if defined(WOLFSSL_HAVE_SP_RSA) || defined(WOLFSSL_HAVE_SP_DH) #ifndef WOLFSSL_SP_NO_2048 /* Read big endian unsigned byte array into r. @@ -13668,6 +13672,141 @@ static void sp_256_div2_5(sp_digit* r, const sp_digit* a, const sp_digit* m) * p Point to double. * t Temporary ordinate data. */ +#ifdef WOLFSSL_SP_NONBLOCK +typedef struct sp_256_proj_point_dbl_5_ctx { + int state; + sp_digit* t1; + sp_digit* t2; + sp_digit* x; + sp_digit* y; + sp_digit* z; +} sp_256_proj_point_dbl_5_ctx; + +static int sp_256_proj_point_dbl_5_nb(sp_ecc_ctx_t* sp_ctx, sp_point_256* r, const sp_point_256* p, sp_digit* t) +{ + int err = FP_WOULDBLOCK; + sp_256_proj_point_dbl_5_ctx* ctx = (sp_256_proj_point_dbl_5_ctx*)sp_ctx->data; + + typedef char ctx_size_test[sizeof(sp_256_proj_point_dbl_5_ctx) >= sizeof(*sp_ctx) ? -1 : 1]; + (void)sizeof(ctx_size_test); + + switch (ctx->state) { + case 0: + ctx->t1 = t; + ctx->t2 = t + 2*5; + ctx->x = r->x; + ctx->y = r->y; + ctx->z = r->z; + + /* Put infinity into result. */ + if (r != p) { + r->infinity = p->infinity; + } + ctx->state = 1; + break; + case 1: + /* T1 = Z * Z */ + sp_256_mont_sqr_5(ctx->t1, p->z, p256_mod, p256_mp_mod); + ctx->state = 2; + break; + case 2: + /* Z = Y * Z */ + sp_256_mont_mul_5(ctx->z, p->y, p->z, p256_mod, p256_mp_mod); + ctx->state = 3; + break; + case 3: + /* Z = 2Z */ + sp_256_mont_dbl_5(ctx->z, ctx->z, p256_mod); + ctx->state = 4; + break; + case 4: + /* T2 = X - T1 */ + sp_256_mont_sub_5(ctx->t2, p->x, ctx->t1, p256_mod); + ctx->state = 5; + break; + case 5: + /* T1 = X + T1 */ + sp_256_mont_add_5(ctx->t1, p->x, ctx->t1, p256_mod); + ctx->state = 6; + break; + case 6: + /* T2 = T1 * T2 */ + sp_256_mont_mul_5(ctx->t2, ctx->t1, ctx->t2, p256_mod, p256_mp_mod); + ctx->state = 7; + break; + case 7: + /* T1 = 3T2 */ + sp_256_mont_tpl_5(ctx->t1, ctx->t2, p256_mod); + ctx->state = 8; + break; + case 8: + /* Y = 2Y */ + sp_256_mont_dbl_5(ctx->y, p->y, p256_mod); + ctx->state = 9; + break; + case 9: + /* Y = Y * Y */ + sp_256_mont_sqr_5(ctx->y, ctx->y, p256_mod, p256_mp_mod); + ctx->state = 10; + break; + case 10: + /* T2 = Y * Y */ + sp_256_mont_sqr_5(ctx->t2, ctx->y, p256_mod, p256_mp_mod); + ctx->state = 11; + break; + case 11: + /* T2 = T2/2 */ + sp_256_div2_5(ctx->t2, ctx->t2, p256_mod); + ctx->state = 12; + break; + case 12: + /* Y = Y * X */ + sp_256_mont_mul_5(ctx->y, ctx->y, p->x, p256_mod, p256_mp_mod); + ctx->state = 13; + break; + case 13: + /* X = T1 * T1 */ + sp_256_mont_sqr_5(ctx->x, ctx->t1, p256_mod, p256_mp_mod); + ctx->state = 14; + break; + case 14: + /* X = X - Y */ + sp_256_mont_sub_5(ctx->x, ctx->x, ctx->y, p256_mod); + ctx->state = 15; + break; + case 15: + /* X = X - Y */ + sp_256_mont_sub_5(ctx->x, ctx->x, ctx->y, p256_mod); + ctx->state = 16; + break; + case 16: + /* Y = Y - X */ + sp_256_mont_sub_5(ctx->y, ctx->y, ctx->x, p256_mod); + ctx->state = 17; + break; + case 17: + /* Y = Y * T1 */ + sp_256_mont_mul_5(ctx->y, ctx->y, ctx->t1, p256_mod, p256_mp_mod); + ctx->state = 18; + break; + case 18: + /* Y = Y - T2 */ + sp_256_mont_sub_5(ctx->y, ctx->y, ctx->t2, p256_mod); + ctx->state = 19; + /* fall-through */ + case 19: + err = MP_OKAY; + break; + } + + if (err == MP_OKAY && ctx->state != 19) { + err = FP_WOULDBLOCK; + } + + return err; +} +#endif /* WOLFSSL_SP_NONBLOCK */ + static void sp_256_proj_point_dbl_5(sp_point_256* r, const sp_point_256* p, sp_digit* t) { sp_digit* t1 = t; @@ -13742,6 +13881,209 @@ static int sp_256_cmp_equal_5(const sp_digit* a, const sp_digit* b) * q Second point to add. * t Temporary ordinate data. */ + +#ifdef WOLFSSL_SP_NONBLOCK +typedef struct sp_256_proj_point_add_5_ctx { + int state; + sp_256_proj_point_dbl_5_ctx dbl_ctx; + const sp_point_256* ap[2]; + sp_point_256* rp[2]; + sp_digit* t1; + sp_digit* t2; + sp_digit* t3; + sp_digit* t4; + sp_digit* t5; + sp_digit* x; + sp_digit* y; + sp_digit* z; +} sp_256_proj_point_add_5_ctx; + +static int sp_256_proj_point_add_5_nb(sp_ecc_ctx_t* sp_ctx, sp_point_256* r, + const sp_point_256* p, const sp_point_256* q, sp_digit* t) +{ + int err = FP_WOULDBLOCK; + sp_256_proj_point_add_5_ctx* ctx = (sp_256_proj_point_add_5_ctx*)sp_ctx->data; + + /* Ensure only the first point is the same as the result. */ + if (q == r) { + const sp_point_256* a = p; + p = q; + q = a; + } + + typedef char ctx_size_test[sizeof(sp_256_proj_point_add_5_ctx) >= sizeof(*sp_ctx) ? -1 : 1]; + (void)sizeof(ctx_size_test); + + switch (ctx->state) { + case 0: /* INIT */ + ctx->t1 = t; + ctx->t2 = t + 2*5; + ctx->t3 = t + 4*5; + ctx->t4 = t + 6*5; + ctx->t5 = t + 8*5; + + ctx->state = 1; + break; + case 1: + /* Check double */ + (void)sp_256_sub_5(ctx->t1, p256_mod, q->y); + sp_256_norm_5(ctx->t1); + if ((sp_256_cmp_equal_5(p->x, q->x) & sp_256_cmp_equal_5(p->z, q->z) & + (sp_256_cmp_equal_5(p->y, q->y) | sp_256_cmp_equal_5(p->y, ctx->t1))) != 0) + { + XMEMSET(&ctx->dbl_ctx, 0, sizeof(ctx->dbl_ctx)); + ctx->state = 2; + } + else { + ctx->state = 3; + } + break; + case 2: + err = sp_256_proj_point_dbl_5_nb((sp_ecc_ctx_t*)&ctx->dbl_ctx, r, p, t); + if (err == MP_OKAY) + ctx->state = 27; /* done */ + break; + case 3: + { + int i; + ctx->rp[0] = r; + + /*lint allow cast to different type of pointer*/ + ctx->rp[1] = (sp_point_256*)t; /*lint !e9087 !e740*/ + XMEMSET(ctx->rp[1], 0, sizeof(sp_point_256)); + ctx->x = ctx->rp[p->infinity | q->infinity]->x; + ctx->y = ctx->rp[p->infinity | q->infinity]->y; + ctx->z = ctx->rp[p->infinity | q->infinity]->z; + + ctx->ap[0] = p; + ctx->ap[1] = q; + for (i=0; i<5; i++) { + r->x[i] = ctx->ap[p->infinity]->x[i]; + } + for (i=0; i<5; i++) { + r->y[i] = ctx->ap[p->infinity]->y[i]; + } + for (i=0; i<5; i++) { + r->z[i] = ctx->ap[p->infinity]->z[i]; + } + r->infinity = ctx->ap[p->infinity]->infinity; + + ctx->state = 4; + break; + } + case 4: + /* U1 = X1*Z2^2 */ + sp_256_mont_sqr_5(ctx->t1, q->z, p256_mod, p256_mp_mod); + ctx->state = 5; + break; + case 5: + sp_256_mont_mul_5(ctx->t3, ctx->t1, q->z, p256_mod, p256_mp_mod); + ctx->state = 6; + break; + case 6: + sp_256_mont_mul_5(ctx->t1, ctx->t1, ctx->x, p256_mod, p256_mp_mod); + ctx->state = 7; + break; + case 7: + /* U2 = X2*Z1^2 */ + sp_256_mont_sqr_5(ctx->t2, ctx->z, p256_mod, p256_mp_mod); + ctx->state = 8; + break; + case 8: + sp_256_mont_mul_5(ctx->t4, ctx->t2, ctx->z, p256_mod, p256_mp_mod); + ctx->state = 9; + break; + case 9: + sp_256_mont_mul_5(ctx->t2, ctx->t2, q->x, p256_mod, p256_mp_mod); + ctx->state = 10; + break; + case 10: + /* S1 = Y1*Z2^3 */ + sp_256_mont_mul_5(ctx->t3, ctx->t3, ctx->y, p256_mod, p256_mp_mod); + ctx->state = 11; + break; + case 11: + /* S2 = Y2*Z1^3 */ + sp_256_mont_mul_5(ctx->t4, ctx->t4, q->y, p256_mod, p256_mp_mod); + ctx->state = 12; + break; + case 12: + /* H = U2 - U1 */ + sp_256_mont_sub_5(ctx->t2, ctx->t2, ctx->t1, p256_mod); + ctx->state = 13; + break; + case 13: + /* R = S2 - S1 */ + sp_256_mont_sub_5(ctx->t4, ctx->t4, ctx->t3, p256_mod); + ctx->state = 14; + break; + case 14: + /* Z3 = H*Z1*Z2 */ + sp_256_mont_mul_5(ctx->z, ctx->z, q->z, p256_mod, p256_mp_mod); + ctx->state = 15; + break; + case 15: + sp_256_mont_mul_5(ctx->z, ctx->z, ctx->t2, p256_mod, p256_mp_mod); + ctx->state = 16; + break; + case 16: + /* X3 = R^2 - H^3 - 2*U1*H^2 */ + sp_256_mont_sqr_5(ctx->x, ctx->t4, p256_mod, p256_mp_mod); + ctx->state = 17; + break; + case 17: + sp_256_mont_sqr_5(ctx->t5, ctx->t2, p256_mod, p256_mp_mod); + ctx->state = 18; + break; + case 18: + sp_256_mont_mul_5(ctx->y, ctx->t1, ctx->t5, p256_mod, p256_mp_mod); + ctx->state = 19; + break; + case 19: + sp_256_mont_mul_5(ctx->t5, ctx->t5, ctx->t2, p256_mod, p256_mp_mod); + ctx->state = 20; + break; + case 20: + sp_256_mont_sub_5(ctx->x, ctx->x, ctx->t5, p256_mod); + ctx->state = 21; + break; + case 21: + sp_256_mont_dbl_5(ctx->t1, ctx->y, p256_mod); + ctx->state = 22; + break; + case 22: + sp_256_mont_sub_5(ctx->x, ctx->x, ctx->t1, p256_mod); + ctx->state = 23; + break; + case 23: + /* Y3 = R*(U1*H^2 - X3) - S1*H^3 */ + sp_256_mont_sub_5(ctx->y, ctx->y, ctx->x, p256_mod); + ctx->state = 24; + break; + case 24: + sp_256_mont_mul_5(ctx->y, ctx->y, ctx->t4, p256_mod, p256_mp_mod); + ctx->state = 25; + break; + case 25: + sp_256_mont_mul_5(ctx->t5, ctx->t5, ctx->t3, p256_mod, p256_mp_mod); + ctx->state = 26; + break; + case 26: + sp_256_mont_sub_5(ctx->y, ctx->y, ctx->t5, p256_mod); + ctx->state = 27; + /* fall-through */ + case 27: + err = MP_OKAY; + break; + } + + if (err == MP_OKAY && ctx->state != 27) { + err = FP_WOULDBLOCK; + } + return err; +} +#endif /* WOLFSSL_SP_NONBLOCK */ + static void sp_256_proj_point_add_5(sp_point_256* r, const sp_point_256* p, const sp_point_256* q, sp_digit* t) { @@ -13840,6 +14182,118 @@ static void sp_256_proj_point_add_5(sp_point_256* r, const sp_point_256* p, cons * heap Heap to use for allocation. * returns MEMORY_E when memory allocation fails and MP_OKAY on success. */ + +#ifdef WOLFSSL_SP_NONBLOCK +typedef struct sp_256_ecc_mulmod_5_ctx { + int state; + union { + sp_256_proj_point_dbl_5_ctx dbl_ctx; + sp_256_proj_point_add_5_ctx add_ctx; + }; + sp_point_256 t[3]; + sp_digit tmp[2 * 5 * 5]; + sp_digit n; + int i; + int c; + int y; +} sp_256_ecc_mulmod_5_ctx; + +static int sp_256_ecc_mulmod_5_nb(sp_ecc_ctx_t* sp_ctx, sp_point_256* r, + const sp_point_256* g, const sp_digit* k, int map, void* heap) +{ + int err = FP_WOULDBLOCK; + sp_256_ecc_mulmod_5_ctx* ctx = (sp_256_ecc_mulmod_5_ctx*)sp_ctx->data; + + typedef char ctx_size_test[sizeof(sp_256_ecc_mulmod_5_ctx) >= sizeof(*sp_ctx) ? -1 : 1]; + (void)sizeof(ctx_size_test); + + switch (ctx->state) { + case 0: /* INIT */ + XMEMSET(ctx->t, 0, sizeof(sp_point_256) * 3); + ctx->i = 4; + ctx->c = 48; + ctx->n = k[ctx->i--] << (52 - ctx->c); + + /* t[0] = {0, 0, 1} * norm */ + ctx->t[0].infinity = 1; + ctx->state = 1; + break; + case 1: /* T1X */ + /* t[1] = {g->x, g->y, g->z} * norm */ + err = sp_256_mod_mul_norm_5(ctx->t[1].x, g->x, p256_mod); + ctx->state = 2; + break; + case 2: /* T1Y */ + err = sp_256_mod_mul_norm_5(ctx->t[1].y, g->y, p256_mod); + ctx->state = 3; + break; + case 3: /* T1Z */ + err = sp_256_mod_mul_norm_5(ctx->t[1].z, g->z, p256_mod); + ctx->state = 4; + break; + case 4: /* ADDPREP */ + if (ctx->c == 0) { + if (ctx->i == -1) { + ctx->state = 7; + break; + } + + ctx->n = k[ctx->i--]; + ctx->c = 52; + } + ctx->y = (ctx->n >> 51) & 1; + ctx->n <<= 1; + XMEMSET(&ctx->add_ctx, 0, sizeof(ctx->add_ctx)); + ctx->state = 5; + break; + case 5: /* ADD */ + err = sp_256_proj_point_add_5_nb((sp_ecc_ctx_t*)&ctx->add_ctx, + &ctx->t[ctx->y^1], &ctx->t[0], &ctx->t[1], ctx->tmp); + if (err == MP_OKAY) { + XMEMCPY(&ctx->t[2], (void*)(((size_t)&ctx->t[0] & addr_mask[ctx->y^1]) + + ((size_t)&ctx->t[1] & addr_mask[ctx->y])), + sizeof(sp_point_256)); + XMEMSET(&ctx->dbl_ctx, 0, sizeof(ctx->dbl_ctx)); + ctx->state = 6; + } + break; + case 6: /* DBL */ + err = sp_256_proj_point_dbl_5_nb((sp_ecc_ctx_t*)&ctx->dbl_ctx, &ctx->t[2], + &ctx->t[2], ctx->tmp); + if (err == MP_OKAY) { + XMEMCPY((void*)(((size_t)&ctx->t[0] & addr_mask[ctx->y^1]) + + ((size_t)&ctx->t[1] & addr_mask[ctx->y])), &ctx->t[2], + sizeof(sp_point_256)); + ctx->state = 4; + ctx->c--; + } + break; + case 7: /* MAP */ + if (map != 0) { + sp_256_map_5(r, &ctx->t[0], ctx->tmp); + } + else { + XMEMCPY(r, &ctx->t[0], sizeof(sp_point_256)); + } + err = MP_OKAY; + break; + } + + if (err == MP_OKAY && ctx->state != 7) { + err = FP_WOULDBLOCK; + } + if (err != FP_WOULDBLOCK) { + ForceZero(ctx->tmp, sizeof(ctx->tmp)); + ForceZero(ctx->t, sizeof(ctx->t)); + } + + (void)heap; + + return err; +} + +#endif /* WOLFSSL_SP_NONBLOCK */ + static int sp_256_ecc_mulmod_5(sp_point_256* r, const sp_point_256* g, const sp_digit* k, int map, void* heap) { @@ -16627,6 +17081,46 @@ static void sp_256_mont_sqr_n_order_5(sp_digit* r, const sp_digit* a, int n) * a Number to invert. * td Temporary data. */ + +#ifdef WOLFSSL_SP_NONBLOCK +typedef struct sp_256_mont_inv_order_5_ctx { + int state; + int i; +} sp_256_mont_inv_order_5_ctx; +static int sp_256_mont_inv_order_5_nb(sp_ecc_ctx_t* sp_ctx, sp_digit* r, const sp_digit* a, + sp_digit* t) +{ + int err = FP_WOULDBLOCK; + sp_256_mont_inv_order_5_ctx* ctx = (sp_256_mont_inv_order_5_ctx*)sp_ctx; + + typedef char ctx_size_test[sizeof(sp_256_mont_inv_order_5_ctx) >= sizeof(*sp_ctx) ? -1 : 1]; + (void)sizeof(ctx_size_test); + + switch (ctx->state) { + case 0: + XMEMCPY(t, a, sizeof(sp_digit) * 5); + ctx->i = 254; + ctx->state = 1; + break; + case 1: + sp_256_mont_sqr_order_5(t, t); + if ((p256_order_minus_2[ctx->i / 64] & ((sp_int_digit)1 << (ctx->i % 64))) != 0) { + sp_256_mont_mul_order_5(t, t, a); + } + ctx->i--; + if (ctx->i == 0) { + ctx->state = 2; + } + break; + case 2: + XMEMCPY(r, t, sizeof(sp_digit) * 5U); + err = MP_OKAY; + break; + } + return err; +} +#endif /* WOLFSSL_SP_NONBLOCK */ + static void sp_256_mont_inv_order_5(sp_digit* r, const sp_digit* a, sp_digit* td) { @@ -16742,6 +17236,165 @@ static void sp_256_mont_inv_order_5(sp_digit* r, const sp_digit* a, * returns RNG failures, MEMORY_E when memory allocation fails and * MP_OKAY on success. */ +#ifdef WOLFSSL_SP_NONBLOCK +typedef struct sp_ecc_sign_256_ctx { + int state; + union { + sp_256_ecc_mulmod_5_ctx mulmod_ctx; + sp_256_mont_inv_order_5_ctx mont_inv_order_ctx; + }; + sp_digit e[2*5]; + sp_digit x[2*5]; + sp_digit k[2*5]; + sp_digit r[2*5]; + sp_digit tmp[3 * 2*5]; + sp_point_256 point; + sp_digit* s; + sp_digit* kInv; + int i; +} sp_ecc_sign_256_ctx; + +int sp_ecc_sign_256_nb(sp_ecc_ctx_t* sp_ctx, const byte* hash, word32 hashLen, WC_RNG* rng, mp_int* priv, + mp_int* rm, mp_int* sm, mp_int* km, void* heap) +{ + int err = FP_WOULDBLOCK; + sp_ecc_sign_256_ctx* ctx = (sp_ecc_sign_256_ctx*)sp_ctx->data; + + typedef char ctx_size_test[sizeof(sp_ecc_sign_256_ctx) >= sizeof(*sp_ctx) ? -1 : 1]; + (void)sizeof(ctx_size_test); + + (void)heap; + + switch (ctx->state) { + case 0: /* INIT */ + ctx->s = ctx->e; + ctx->kInv = ctx->k; + if (hashLen > 32U) { + hashLen = 32U; + } + + sp_256_from_bin(ctx->e, 5, hash, (int)hashLen); + + ctx->i = SP_ECC_MAX_SIG_GEN; + ctx->state = 1; + break; + case 1: /* GEN */ + sp_256_from_mp(ctx->x, 5, priv); + /* New random point. */ + if (km == NULL || mp_iszero(km)) { + err = sp_256_ecc_gen_k_5(rng, ctx->k); + } + else { + sp_256_from_mp(ctx->k, 5, km); + mp_zero(km); + } + XMEMSET(&ctx->mulmod_ctx, 0, sizeof(ctx->mulmod_ctx)); + ctx->state = 2; + break; + case 2: /* MULMOD */ + err = sp_256_ecc_mulmod_5_nb((sp_ecc_ctx_t*)&ctx->mulmod_ctx, + &ctx->point, &p256_base, ctx->k, 1, heap); + if (err == MP_OKAY) { + ctx->state = 3; + } + break; + case 3: /* MODORDER */ + { + int64_t c; + /* r = point->x mod order */ + XMEMCPY(ctx->r, ctx->point.x, sizeof(sp_digit) * 5U); + sp_256_norm_5(ctx->r); + c = sp_256_cmp_5(ctx->r, p256_order); + sp_256_cond_sub_5(ctx->r, ctx->r, p256_order, 0L - (sp_digit)(c >= 0)); + sp_256_norm_5(ctx->r); + ctx->state = 4; + break; + } + case 4: /* KMODORDER */ + /* Conv k to Montgomery form (mod order) */ + sp_256_mul_5(ctx->k, ctx->k, p256_norm_order); + err = sp_256_mod_5(ctx->k, ctx->k, p256_order); + if (err == MP_OKAY) { + sp_256_norm_5(ctx->k); + XMEMSET(&ctx->mont_inv_order_ctx, 0, sizeof(ctx->mont_inv_order_ctx)); + ctx->state = 5; + } + break; + case 5: /* KINV */ + /* kInv = 1/k mod order */ + err = sp_256_mont_inv_order_5_nb((sp_ecc_ctx_t*)&ctx->mont_inv_order_ctx, ctx->kInv, ctx->k, ctx->tmp); + if (err == MP_OKAY) { + XMEMSET(&ctx->mont_inv_order_ctx, 0, sizeof(ctx->mont_inv_order_ctx)); + ctx->state = 6; + } + break; + case 6: /* KINVNORM */ + sp_256_norm_5(ctx->kInv); + ctx->state = 7; + break; + case 7: /* R */ + /* s = r * x + e */ + sp_256_mul_5(ctx->x, ctx->x, ctx->r); + ctx->state = 8; + break; + case 8: /* S1 */ + err = sp_256_mod_5(ctx->x, ctx->x, p256_order); + if (err == MP_OKAY) + ctx->state = 9; + break; + case 9: /* S2 */ + { + sp_digit carry; + int64_t c; + sp_256_norm_5(ctx->x); + carry = sp_256_add_5(ctx->s, ctx->e, ctx->x); + sp_256_cond_sub_5(ctx->s, ctx->s, p256_order, 0 - carry); + sp_256_norm_5(ctx->s); + c = sp_256_cmp_5(ctx->s, p256_order); + sp_256_cond_sub_5(ctx->s, ctx->s, p256_order, 0L - (sp_digit)(c >= 0)); + sp_256_norm_5(ctx->s); + + /* s = s * k^-1 mod order */ + sp_256_mont_mul_order_5(ctx->s, ctx->s, ctx->kInv); + sp_256_norm_5(ctx->s); + + /* Check that signature is usable. */ + if (sp_256_iszero_5(ctx->s) == 0) { + ctx->state = 10; + break; + } + + /* not usable gen, try again */ + ctx->i--; + if (ctx->i == 0) { + err = RNG_FAILURE_E; + } + ctx->state = 1; + break; + } + case 10: /* RES */ + err = sp_256_to_mp(ctx->r, rm); + if (err == MP_OKAY) { + err = sp_256_to_mp(ctx->s, sm); + } + break; + } + + if (err == MP_OKAY && ctx->state != 10) { + err = FP_WOULDBLOCK; + } + if (err != FP_WOULDBLOCK) { + XMEMSET(ctx->e, 0, sizeof(sp_digit) * 2U * 5U); + XMEMSET(ctx->x, 0, sizeof(sp_digit) * 2U * 5U); + XMEMSET(ctx->k, 0, sizeof(sp_digit) * 2U * 5U); + XMEMSET(ctx->r, 0, sizeof(sp_digit) * 2U * 5U); + XMEMSET(ctx->tmp, 0, sizeof(sp_digit) * 3U * 2U * 5U); + } + + return err; +} +#endif /* WOLFSSL_SP_NONBLOCK */ + int sp_ecc_sign_256(const byte* hash, word32 hashLen, WC_RNG* rng, mp_int* priv, mp_int* rm, mp_int* sm, mp_int* km, void* heap) { @@ -16913,6 +17566,169 @@ int sp_ecc_sign_256(const byte* hash, word32 hashLen, WC_RNG* rng, mp_int* priv, * returns RNG failures, MEMORY_E when memory allocation fails and * MP_OKAY on success. */ +#ifdef WOLFSSL_SP_NONBLOCK +typedef struct sp_ecc_verify_256_ctx { + int state; + union { + sp_256_ecc_mulmod_5_ctx mulmod_ctx; + sp_256_mont_inv_order_5_ctx mont_inv_order_ctx; + sp_256_proj_point_dbl_5_ctx dbl_ctx; + sp_256_proj_point_add_5_ctx add_ctx; + }; + sp_digit u1[2*5]; + sp_digit u2[2*5]; + sp_digit s[2*5]; + sp_digit tmp[2*5 * 5]; + sp_point_256 p1; + sp_point_256 p2; +} sp_ecc_verify_256_ctx; + +int sp_ecc_verify_256_nb(sp_ecc_ctx_t* sp_ctx, const byte* hash, word32 hashLen, mp_int* pX, + mp_int* pY, mp_int* pZ, mp_int* r, mp_int* sm, int* res, void* heap) +{ + int err = FP_WOULDBLOCK; + sp_ecc_verify_256_ctx* ctx = (sp_ecc_verify_256_ctx*)sp_ctx->data; + + typedef char ctx_size_test[sizeof(sp_ecc_verify_256_ctx) >= sizeof(*sp_ctx) ? -1 : 1]; + (void)sizeof(ctx_size_test); + + switch (ctx->state) { + case 0: /* INIT */ + if (hashLen > 32U) { + hashLen = 32U; + } + + sp_256_from_bin(ctx->u1, 5, hash, (int)hashLen); + sp_256_from_mp(ctx->u2, 5, r); + sp_256_from_mp(ctx->s, 5, sm); + sp_256_from_mp(ctx->p2.x, 5, pX); + sp_256_from_mp(ctx->p2.y, 5, pY); + sp_256_from_mp(ctx->p2.z, 5, pZ); + sp_256_mul_5(ctx->s, ctx->s, p256_norm_order); + err = sp_256_mod_5(ctx->s, ctx->s, p256_order); + if (err == MP_OKAY) + ctx->state = 1; + break; + case 1: /* NORMS1 */ + sp_256_norm_5(ctx->s); + XMEMSET(&ctx->mont_inv_order_ctx, 0, sizeof(ctx->mont_inv_order_ctx)); + ctx->state = 2; + break; + case 2: /* NORMS2 */ + err = sp_256_mont_inv_order_5_nb((sp_ecc_ctx_t*)&ctx->mont_inv_order_ctx, ctx->s, ctx->s, ctx->tmp); + if (err == MP_OKAY) { + ctx->state = 3; + } + break; + case 3: /* NORMS3 */ + sp_256_mont_mul_order_5(ctx->u1, ctx->u1, ctx->s); + ctx->state = 4; + break; + case 4: /* NORMS4 */ + sp_256_mont_mul_order_5(ctx->u2, ctx->u2, ctx->s); + XMEMSET(&ctx->mulmod_ctx, 0, sizeof(ctx->mulmod_ctx)); + ctx->state = 5; + break; + case 5: /* MULBASE */ + err = sp_256_ecc_mulmod_5_nb((sp_ecc_ctx_t*)&ctx->mulmod_ctx, &ctx->p1, &p256_base, ctx->u1, 0, heap); + if (err == MP_OKAY) { + XMEMSET(&ctx->mulmod_ctx, 0, sizeof(ctx->mulmod_ctx)); + ctx->state = 6; + } + break; + case 6: /* MULMOD */ + err = sp_256_ecc_mulmod_5_nb((sp_ecc_ctx_t*)&ctx->mulmod_ctx, &ctx->p2, &ctx->p2, ctx->u2, 0, heap); + if (err == MP_OKAY) { + XMEMSET(&ctx->add_ctx, 0, sizeof(ctx->add_ctx)); + ctx->state = 7; + } + break; + case 7: /* ADD */ + err = sp_256_proj_point_add_5_nb((sp_ecc_ctx_t*)&ctx->add_ctx, &ctx->p1, &ctx->p1, &ctx->p2, ctx->tmp); + if (err == MP_OKAY) + ctx->state = 8; + break; + case 8: /* DBLPREP */ + if (sp_256_iszero_5(ctx->p1.z)) { + if (sp_256_iszero_5(ctx->p1.x) && sp_256_iszero_5(ctx->p1.y)) { + XMEMSET(&ctx->dbl_ctx, 0, sizeof(ctx->dbl_ctx)); + ctx->state = 9; + break; + } + else { + /* Y ordinate is not used from here - don't set. */ + int i; + for (i=0; i<5; i++) { + ctx->p1.x[i] = 0; + } + XMEMCPY(ctx->p1.z, p256_norm_mod, sizeof(p256_norm_mod)); + } + } + ctx->state = 10; + break; + case 9: /* DBL */ + err = sp_256_proj_point_dbl_5_nb((sp_ecc_ctx_t*)&ctx->dbl_ctx, &ctx->p1, + &ctx->p2, ctx->tmp); + if (err == MP_OKAY) { + ctx->state = 10; + } + break; + case 10: /* MONT */ + /* (r + n*order).z'.z' mod prime == (u1.G + u2.Q)->x' */ + /* Reload r and convert to Montgomery form. */ + sp_256_from_mp(ctx->u2, 5, r); + err = sp_256_mod_mul_norm_5(ctx->u2, ctx->u2, p256_mod); + if (err == MP_OKAY) + ctx->state = 11; + break; + case 11: /* SQR */ + /* u1 = r.z'.z' mod prime */ + sp_256_mont_sqr_5(ctx->p1.z, ctx->p1.z, p256_mod, p256_mp_mod); + ctx->state = 12; + break; + case 12: /* MUL */ + sp_256_mont_mul_5(ctx->u1, ctx->u2, ctx->p1.z, p256_mod, p256_mp_mod); + ctx->state = 13; + break; + case 13: /* RES */ + err = MP_OKAY; /* math okay, now check result */ + *res = (int)(sp_256_cmp_5(ctx->p1.x, ctx->u1) == 0); + if (*res == 0) { + sp_digit carry; + int64_t c; + + /* Reload r and add order. */ + sp_256_from_mp(ctx->u2, 5, r); + carry = sp_256_add_5(ctx->u2, ctx->u2, p256_order); + /* Carry means result is greater than mod and is not valid. */ + if (carry == 0) { + sp_256_norm_5(ctx->u2); + + /* Compare with mod and if greater or equal then not valid. */ + c = sp_256_cmp_5(ctx->u2, p256_mod); + if (c < 0) { + /* Convert to Montogomery form */ + err = sp_256_mod_mul_norm_5(ctx->u2, ctx->u2, p256_mod); + if (err == MP_OKAY) { + /* u1 = (r + 1*order).z'.z' mod prime */ + sp_256_mont_mul_5(ctx->u1, ctx->u2, ctx->p1.z, p256_mod, + p256_mp_mod); + *res = (int)(sp_256_cmp_5(ctx->p1.x, ctx->u1) == 0); + } + } + } + } + break; + } + + if (err == MP_OKAY && ctx->state != 13) { + err = FP_WOULDBLOCK; + } + + return err; +} +#endif /* WOLFSSL_SP_NONBLOCK */ + int sp_ecc_verify_256(const byte* hash, word32 hashLen, mp_int* pX, mp_int* pY, mp_int* pZ, mp_int* r, mp_int* sm, int* res, void* heap) { @@ -18854,6 +19670,141 @@ static void sp_384_div2_7(sp_digit* r, const sp_digit* a, const sp_digit* m) * p Point to double. * t Temporary ordinate data. */ +#ifdef WOLFSSL_SP_NONBLOCK +typedef struct sp_384_proj_point_dbl_7_ctx { + int state; + sp_digit* t1; + sp_digit* t2; + sp_digit* x; + sp_digit* y; + sp_digit* z; +} sp_384_proj_point_dbl_7_ctx; + +static int sp_384_proj_point_dbl_7_nb(sp_ecc_ctx_t* sp_ctx, sp_point_384* r, const sp_point_384* p, sp_digit* t) +{ + int err = FP_WOULDBLOCK; + sp_384_proj_point_dbl_7_ctx* ctx = (sp_384_proj_point_dbl_7_ctx*)sp_ctx->data; + + typedef char ctx_size_test[sizeof(sp_384_proj_point_dbl_7_ctx) >= sizeof(*sp_ctx) ? -1 : 1]; + (void)sizeof(ctx_size_test); + + switch (ctx->state) { + case 0: + ctx->t1 = t; + ctx->t2 = t + 2*7; + ctx->x = r->x; + ctx->y = r->y; + ctx->z = r->z; + + /* Put infinity into result. */ + if (r != p) { + r->infinity = p->infinity; + } + ctx->state = 1; + break; + case 1: + /* T1 = Z * Z */ + sp_384_mont_sqr_7(ctx->t1, p->z, p384_mod, p384_mp_mod); + ctx->state = 2; + break; + case 2: + /* Z = Y * Z */ + sp_384_mont_mul_7(ctx->z, p->y, p->z, p384_mod, p384_mp_mod); + ctx->state = 3; + break; + case 3: + /* Z = 2Z */ + sp_384_mont_dbl_7(ctx->z, ctx->z, p384_mod); + ctx->state = 4; + break; + case 4: + /* T2 = X - T1 */ + sp_384_mont_sub_7(ctx->t2, p->x, ctx->t1, p384_mod); + ctx->state = 5; + break; + case 5: + /* T1 = X + T1 */ + sp_384_mont_add_7(ctx->t1, p->x, ctx->t1, p384_mod); + ctx->state = 6; + break; + case 6: + /* T2 = T1 * T2 */ + sp_384_mont_mul_7(ctx->t2, ctx->t1, ctx->t2, p384_mod, p384_mp_mod); + ctx->state = 7; + break; + case 7: + /* T1 = 3T2 */ + sp_384_mont_tpl_7(ctx->t1, ctx->t2, p384_mod); + ctx->state = 8; + break; + case 8: + /* Y = 2Y */ + sp_384_mont_dbl_7(ctx->y, p->y, p384_mod); + ctx->state = 9; + break; + case 9: + /* Y = Y * Y */ + sp_384_mont_sqr_7(ctx->y, ctx->y, p384_mod, p384_mp_mod); + ctx->state = 10; + break; + case 10: + /* T2 = Y * Y */ + sp_384_mont_sqr_7(ctx->t2, ctx->y, p384_mod, p384_mp_mod); + ctx->state = 11; + break; + case 11: + /* T2 = T2/2 */ + sp_384_div2_7(ctx->t2, ctx->t2, p384_mod); + ctx->state = 12; + break; + case 12: + /* Y = Y * X */ + sp_384_mont_mul_7(ctx->y, ctx->y, p->x, p384_mod, p384_mp_mod); + ctx->state = 13; + break; + case 13: + /* X = T1 * T1 */ + sp_384_mont_sqr_7(ctx->x, ctx->t1, p384_mod, p384_mp_mod); + ctx->state = 14; + break; + case 14: + /* X = X - Y */ + sp_384_mont_sub_7(ctx->x, ctx->x, ctx->y, p384_mod); + ctx->state = 15; + break; + case 15: + /* X = X - Y */ + sp_384_mont_sub_7(ctx->x, ctx->x, ctx->y, p384_mod); + ctx->state = 16; + break; + case 16: + /* Y = Y - X */ + sp_384_mont_sub_7(ctx->y, ctx->y, ctx->x, p384_mod); + ctx->state = 17; + break; + case 17: + /* Y = Y * T1 */ + sp_384_mont_mul_7(ctx->y, ctx->y, ctx->t1, p384_mod, p384_mp_mod); + ctx->state = 18; + break; + case 18: + /* Y = Y - T2 */ + sp_384_mont_sub_7(ctx->y, ctx->y, ctx->t2, p384_mod); + ctx->state = 19; + /* fall-through */ + case 19: + err = MP_OKAY; + break; + } + + if (err == MP_OKAY && ctx->state != 19) { + err = FP_WOULDBLOCK; + } + + return err; +} +#endif /* WOLFSSL_SP_NONBLOCK */ + static void sp_384_proj_point_dbl_7(sp_point_384* r, const sp_point_384* p, sp_digit* t) { sp_digit* t1 = t; @@ -18928,6 +19879,209 @@ static int sp_384_cmp_equal_7(const sp_digit* a, const sp_digit* b) * q Second point to add. * t Temporary ordinate data. */ + +#ifdef WOLFSSL_SP_NONBLOCK +typedef struct sp_384_proj_point_add_7_ctx { + int state; + sp_384_proj_point_dbl_7_ctx dbl_ctx; + const sp_point_384* ap[2]; + sp_point_384* rp[2]; + sp_digit* t1; + sp_digit* t2; + sp_digit* t3; + sp_digit* t4; + sp_digit* t5; + sp_digit* x; + sp_digit* y; + sp_digit* z; +} sp_384_proj_point_add_7_ctx; + +static int sp_384_proj_point_add_7_nb(sp_ecc_ctx_t* sp_ctx, sp_point_384* r, + const sp_point_384* p, const sp_point_384* q, sp_digit* t) +{ + int err = FP_WOULDBLOCK; + sp_384_proj_point_add_7_ctx* ctx = (sp_384_proj_point_add_7_ctx*)sp_ctx->data; + + /* Ensure only the first point is the same as the result. */ + if (q == r) { + const sp_point_384* a = p; + p = q; + q = a; + } + + typedef char ctx_size_test[sizeof(sp_384_proj_point_add_7_ctx) >= sizeof(*sp_ctx) ? -1 : 1]; + (void)sizeof(ctx_size_test); + + switch (ctx->state) { + case 0: /* INIT */ + ctx->t1 = t; + ctx->t2 = t + 2*7; + ctx->t3 = t + 4*7; + ctx->t4 = t + 6*7; + ctx->t5 = t + 8*7; + + ctx->state = 1; + break; + case 1: + /* Check double */ + (void)sp_384_sub_7(ctx->t1, p384_mod, q->y); + sp_384_norm_7(ctx->t1); + if ((sp_384_cmp_equal_7(p->x, q->x) & sp_384_cmp_equal_7(p->z, q->z) & + (sp_384_cmp_equal_7(p->y, q->y) | sp_384_cmp_equal_7(p->y, ctx->t1))) != 0) + { + XMEMSET(&ctx->dbl_ctx, 0, sizeof(ctx->dbl_ctx)); + ctx->state = 2; + } + else { + ctx->state = 3; + } + break; + case 2: + err = sp_384_proj_point_dbl_7_nb((sp_ecc_ctx_t*)&ctx->dbl_ctx, r, p, t); + if (err == MP_OKAY) + ctx->state = 27; /* done */ + break; + case 3: + { + int i; + ctx->rp[0] = r; + + /*lint allow cast to different type of pointer*/ + ctx->rp[1] = (sp_point_384*)t; /*lint !e9087 !e740*/ + XMEMSET(ctx->rp[1], 0, sizeof(sp_point_384)); + ctx->x = ctx->rp[p->infinity | q->infinity]->x; + ctx->y = ctx->rp[p->infinity | q->infinity]->y; + ctx->z = ctx->rp[p->infinity | q->infinity]->z; + + ctx->ap[0] = p; + ctx->ap[1] = q; + for (i=0; i<7; i++) { + r->x[i] = ctx->ap[p->infinity]->x[i]; + } + for (i=0; i<7; i++) { + r->y[i] = ctx->ap[p->infinity]->y[i]; + } + for (i=0; i<7; i++) { + r->z[i] = ctx->ap[p->infinity]->z[i]; + } + r->infinity = ctx->ap[p->infinity]->infinity; + + ctx->state = 4; + break; + } + case 4: + /* U1 = X1*Z2^2 */ + sp_384_mont_sqr_7(ctx->t1, q->z, p384_mod, p384_mp_mod); + ctx->state = 5; + break; + case 5: + sp_384_mont_mul_7(ctx->t3, ctx->t1, q->z, p384_mod, p384_mp_mod); + ctx->state = 6; + break; + case 6: + sp_384_mont_mul_7(ctx->t1, ctx->t1, ctx->x, p384_mod, p384_mp_mod); + ctx->state = 7; + break; + case 7: + /* U2 = X2*Z1^2 */ + sp_384_mont_sqr_7(ctx->t2, ctx->z, p384_mod, p384_mp_mod); + ctx->state = 8; + break; + case 8: + sp_384_mont_mul_7(ctx->t4, ctx->t2, ctx->z, p384_mod, p384_mp_mod); + ctx->state = 9; + break; + case 9: + sp_384_mont_mul_7(ctx->t2, ctx->t2, q->x, p384_mod, p384_mp_mod); + ctx->state = 10; + break; + case 10: + /* S1 = Y1*Z2^3 */ + sp_384_mont_mul_7(ctx->t3, ctx->t3, ctx->y, p384_mod, p384_mp_mod); + ctx->state = 11; + break; + case 11: + /* S2 = Y2*Z1^3 */ + sp_384_mont_mul_7(ctx->t4, ctx->t4, q->y, p384_mod, p384_mp_mod); + ctx->state = 12; + break; + case 12: + /* H = U2 - U1 */ + sp_384_mont_sub_7(ctx->t2, ctx->t2, ctx->t1, p384_mod); + ctx->state = 13; + break; + case 13: + /* R = S2 - S1 */ + sp_384_mont_sub_7(ctx->t4, ctx->t4, ctx->t3, p384_mod); + ctx->state = 14; + break; + case 14: + /* Z3 = H*Z1*Z2 */ + sp_384_mont_mul_7(ctx->z, ctx->z, q->z, p384_mod, p384_mp_mod); + ctx->state = 15; + break; + case 15: + sp_384_mont_mul_7(ctx->z, ctx->z, ctx->t2, p384_mod, p384_mp_mod); + ctx->state = 16; + break; + case 16: + /* X3 = R^2 - H^3 - 2*U1*H^2 */ + sp_384_mont_sqr_7(ctx->x, ctx->t4, p384_mod, p384_mp_mod); + ctx->state = 17; + break; + case 17: + sp_384_mont_sqr_7(ctx->t5, ctx->t2, p384_mod, p384_mp_mod); + ctx->state = 18; + break; + case 18: + sp_384_mont_mul_7(ctx->y, ctx->t1, ctx->t5, p384_mod, p384_mp_mod); + ctx->state = 19; + break; + case 19: + sp_384_mont_mul_7(ctx->t5, ctx->t5, ctx->t2, p384_mod, p384_mp_mod); + ctx->state = 20; + break; + case 20: + sp_384_mont_sub_7(ctx->x, ctx->x, ctx->t5, p384_mod); + ctx->state = 21; + break; + case 21: + sp_384_mont_dbl_7(ctx->t1, ctx->y, p384_mod); + ctx->state = 22; + break; + case 22: + sp_384_mont_sub_7(ctx->x, ctx->x, ctx->t1, p384_mod); + ctx->state = 23; + break; + case 23: + /* Y3 = R*(U1*H^2 - X3) - S1*H^3 */ + sp_384_mont_sub_7(ctx->y, ctx->y, ctx->x, p384_mod); + ctx->state = 24; + break; + case 24: + sp_384_mont_mul_7(ctx->y, ctx->y, ctx->t4, p384_mod, p384_mp_mod); + ctx->state = 25; + break; + case 25: + sp_384_mont_mul_7(ctx->t5, ctx->t5, ctx->t3, p384_mod, p384_mp_mod); + ctx->state = 26; + break; + case 26: + sp_384_mont_sub_7(ctx->y, ctx->y, ctx->t5, p384_mod); + ctx->state = 27; + /* fall-through */ + case 27: + err = MP_OKAY; + break; + } + + if (err == MP_OKAY && ctx->state != 27) { + err = FP_WOULDBLOCK; + } + return err; +} +#endif /* WOLFSSL_SP_NONBLOCK */ + static void sp_384_proj_point_add_7(sp_point_384* r, const sp_point_384* p, const sp_point_384* q, sp_digit* t) { @@ -19026,6 +20180,118 @@ static void sp_384_proj_point_add_7(sp_point_384* r, const sp_point_384* p, cons * heap Heap to use for allocation. * returns MEMORY_E when memory allocation fails and MP_OKAY on success. */ + +#ifdef WOLFSSL_SP_NONBLOCK +typedef struct sp_384_ecc_mulmod_7_ctx { + int state; + union { + sp_384_proj_point_dbl_7_ctx dbl_ctx; + sp_384_proj_point_add_7_ctx add_ctx; + }; + sp_point_384 t[3]; + sp_digit tmp[2 * 7 * 6]; + sp_digit n; + int i; + int c; + int y; +} sp_384_ecc_mulmod_7_ctx; + +static int sp_384_ecc_mulmod_7_nb(sp_ecc_ctx_t* sp_ctx, sp_point_384* r, + const sp_point_384* g, const sp_digit* k, int map, void* heap) +{ + int err = FP_WOULDBLOCK; + sp_384_ecc_mulmod_7_ctx* ctx = (sp_384_ecc_mulmod_7_ctx*)sp_ctx->data; + + typedef char ctx_size_test[sizeof(sp_384_ecc_mulmod_7_ctx) >= sizeof(*sp_ctx) ? -1 : 1]; + (void)sizeof(ctx_size_test); + + switch (ctx->state) { + case 0: /* INIT */ + XMEMSET(ctx->t, 0, sizeof(sp_point_384) * 3); + ctx->i = 6; + ctx->c = 54; + ctx->n = k[ctx->i--] << (55 - ctx->c); + + /* t[0] = {0, 0, 1} * norm */ + ctx->t[0].infinity = 1; + ctx->state = 1; + break; + case 1: /* T1X */ + /* t[1] = {g->x, g->y, g->z} * norm */ + err = sp_384_mod_mul_norm_7(ctx->t[1].x, g->x, p384_mod); + ctx->state = 2; + break; + case 2: /* T1Y */ + err = sp_384_mod_mul_norm_7(ctx->t[1].y, g->y, p384_mod); + ctx->state = 3; + break; + case 3: /* T1Z */ + err = sp_384_mod_mul_norm_7(ctx->t[1].z, g->z, p384_mod); + ctx->state = 4; + break; + case 4: /* ADDPREP */ + if (ctx->c == 0) { + if (ctx->i == -1) { + ctx->state = 7; + break; + } + + ctx->n = k[ctx->i--]; + ctx->c = 55; + } + ctx->y = (ctx->n >> 54) & 1; + ctx->n <<= 1; + XMEMSET(&ctx->add_ctx, 0, sizeof(ctx->add_ctx)); + ctx->state = 5; + break; + case 5: /* ADD */ + err = sp_384_proj_point_add_7_nb((sp_ecc_ctx_t*)&ctx->add_ctx, + &ctx->t[ctx->y^1], &ctx->t[0], &ctx->t[1], ctx->tmp); + if (err == MP_OKAY) { + XMEMCPY(&ctx->t[2], (void*)(((size_t)&ctx->t[0] & addr_mask[ctx->y^1]) + + ((size_t)&ctx->t[1] & addr_mask[ctx->y])), + sizeof(sp_point_384)); + XMEMSET(&ctx->dbl_ctx, 0, sizeof(ctx->dbl_ctx)); + ctx->state = 6; + } + break; + case 6: /* DBL */ + err = sp_384_proj_point_dbl_7_nb((sp_ecc_ctx_t*)&ctx->dbl_ctx, &ctx->t[2], + &ctx->t[2], ctx->tmp); + if (err == MP_OKAY) { + XMEMCPY((void*)(((size_t)&ctx->t[0] & addr_mask[ctx->y^1]) + + ((size_t)&ctx->t[1] & addr_mask[ctx->y])), &ctx->t[2], + sizeof(sp_point_384)); + ctx->state = 4; + ctx->c--; + } + break; + case 7: /* MAP */ + if (map != 0) { + sp_384_map_7(r, &ctx->t[0], ctx->tmp); + } + else { + XMEMCPY(r, &ctx->t[0], sizeof(sp_point_384)); + } + err = MP_OKAY; + break; + } + + if (err == MP_OKAY && ctx->state != 7) { + err = FP_WOULDBLOCK; + } + if (err != FP_WOULDBLOCK) { + ForceZero(ctx->tmp, sizeof(ctx->tmp)); + ForceZero(ctx->t, sizeof(ctx->t)); + } + + (void)heap; + + return err; +} + +#endif /* WOLFSSL_SP_NONBLOCK */ + static int sp_384_ecc_mulmod_7(sp_point_384* r, const sp_point_384* g, const sp_digit* k, int map, void* heap) { @@ -22344,6 +23610,46 @@ static void sp_384_mont_sqr_n_order_7(sp_digit* r, const sp_digit* a, int n) * a Number to invert. * td Temporary data. */ + +#ifdef WOLFSSL_SP_NONBLOCK +typedef struct sp_384_mont_inv_order_7_ctx { + int state; + int i; +} sp_384_mont_inv_order_7_ctx; +static int sp_384_mont_inv_order_7_nb(sp_ecc_ctx_t* sp_ctx, sp_digit* r, const sp_digit* a, + sp_digit* t) +{ + int err = FP_WOULDBLOCK; + sp_384_mont_inv_order_7_ctx* ctx = (sp_384_mont_inv_order_7_ctx*)sp_ctx; + + typedef char ctx_size_test[sizeof(sp_384_mont_inv_order_7_ctx) >= sizeof(*sp_ctx) ? -1 : 1]; + (void)sizeof(ctx_size_test); + + switch (ctx->state) { + case 0: + XMEMCPY(t, a, sizeof(sp_digit) * 7); + ctx->i = 382; + ctx->state = 1; + break; + case 1: + sp_384_mont_sqr_order_7(t, t); + if ((p384_order_minus_2[ctx->i / 64] & ((sp_int_digit)1 << (ctx->i % 64))) != 0) { + sp_384_mont_mul_order_7(t, t, a); + } + ctx->i--; + if (ctx->i == 0) { + ctx->state = 2; + } + break; + case 2: + XMEMCPY(r, t, sizeof(sp_digit) * 7U); + err = MP_OKAY; + break; + } + return err; +} +#endif /* WOLFSSL_SP_NONBLOCK */ + static void sp_384_mont_inv_order_7(sp_digit* r, const sp_digit* a, sp_digit* td) { @@ -22430,6 +23736,165 @@ static void sp_384_mont_inv_order_7(sp_digit* r, const sp_digit* a, * returns RNG failures, MEMORY_E when memory allocation fails and * MP_OKAY on success. */ +#ifdef WOLFSSL_SP_NONBLOCK +typedef struct sp_ecc_sign_384_ctx { + int state; + union { + sp_384_ecc_mulmod_7_ctx mulmod_ctx; + sp_384_mont_inv_order_7_ctx mont_inv_order_ctx; + }; + sp_digit e[2*7]; + sp_digit x[2*7]; + sp_digit k[2*7]; + sp_digit r[2*7]; + sp_digit tmp[3 * 2*7]; + sp_point_384 point; + sp_digit* s; + sp_digit* kInv; + int i; +} sp_ecc_sign_384_ctx; + +int sp_ecc_sign_384_nb(sp_ecc_ctx_t* sp_ctx, const byte* hash, word32 hashLen, WC_RNG* rng, mp_int* priv, + mp_int* rm, mp_int* sm, mp_int* km, void* heap) +{ + int err = FP_WOULDBLOCK; + sp_ecc_sign_384_ctx* ctx = (sp_ecc_sign_384_ctx*)sp_ctx->data; + + typedef char ctx_size_test[sizeof(sp_ecc_sign_384_ctx) >= sizeof(*sp_ctx) ? -1 : 1]; + (void)sizeof(ctx_size_test); + + (void)heap; + + switch (ctx->state) { + case 0: /* INIT */ + ctx->s = ctx->e; + ctx->kInv = ctx->k; + if (hashLen > 48U) { + hashLen = 48U; + } + + sp_384_from_bin(ctx->e, 7, hash, (int)hashLen); + + ctx->i = SP_ECC_MAX_SIG_GEN; + ctx->state = 1; + break; + case 1: /* GEN */ + sp_384_from_mp(ctx->x, 7, priv); + /* New random point. */ + if (km == NULL || mp_iszero(km)) { + err = sp_384_ecc_gen_k_7(rng, ctx->k); + } + else { + sp_384_from_mp(ctx->k, 7, km); + mp_zero(km); + } + XMEMSET(&ctx->mulmod_ctx, 0, sizeof(ctx->mulmod_ctx)); + ctx->state = 2; + break; + case 2: /* MULMOD */ + err = sp_384_ecc_mulmod_7_nb((sp_ecc_ctx_t*)&ctx->mulmod_ctx, + &ctx->point, &p384_base, ctx->k, 1, heap); + if (err == MP_OKAY) { + ctx->state = 3; + } + break; + case 3: /* MODORDER */ + { + int64_t c; + /* r = point->x mod order */ + XMEMCPY(ctx->r, ctx->point.x, sizeof(sp_digit) * 7U); + sp_384_norm_7(ctx->r); + c = sp_384_cmp_7(ctx->r, p384_order); + sp_384_cond_sub_7(ctx->r, ctx->r, p384_order, 0L - (sp_digit)(c >= 0)); + sp_384_norm_7(ctx->r); + ctx->state = 4; + break; + } + case 4: /* KMODORDER */ + /* Conv k to Montgomery form (mod order) */ + sp_384_mul_7(ctx->k, ctx->k, p384_norm_order); + err = sp_384_mod_7(ctx->k, ctx->k, p384_order); + if (err == MP_OKAY) { + sp_384_norm_7(ctx->k); + XMEMSET(&ctx->mont_inv_order_ctx, 0, sizeof(ctx->mont_inv_order_ctx)); + ctx->state = 5; + } + break; + case 5: /* KINV */ + /* kInv = 1/k mod order */ + err = sp_384_mont_inv_order_7_nb((sp_ecc_ctx_t*)&ctx->mont_inv_order_ctx, ctx->kInv, ctx->k, ctx->tmp); + if (err == MP_OKAY) { + XMEMSET(&ctx->mont_inv_order_ctx, 0, sizeof(ctx->mont_inv_order_ctx)); + ctx->state = 6; + } + break; + case 6: /* KINVNORM */ + sp_384_norm_7(ctx->kInv); + ctx->state = 7; + break; + case 7: /* R */ + /* s = r * x + e */ + sp_384_mul_7(ctx->x, ctx->x, ctx->r); + ctx->state = 8; + break; + case 8: /* S1 */ + err = sp_384_mod_7(ctx->x, ctx->x, p384_order); + if (err == MP_OKAY) + ctx->state = 9; + break; + case 9: /* S2 */ + { + sp_digit carry; + int64_t c; + sp_384_norm_7(ctx->x); + carry = sp_384_add_7(ctx->s, ctx->e, ctx->x); + sp_384_cond_sub_7(ctx->s, ctx->s, p384_order, 0 - carry); + sp_384_norm_7(ctx->s); + c = sp_384_cmp_7(ctx->s, p384_order); + sp_384_cond_sub_7(ctx->s, ctx->s, p384_order, 0L - (sp_digit)(c >= 0)); + sp_384_norm_7(ctx->s); + + /* s = s * k^-1 mod order */ + sp_384_mont_mul_order_7(ctx->s, ctx->s, ctx->kInv); + sp_384_norm_7(ctx->s); + + /* Check that signature is usable. */ + if (sp_384_iszero_7(ctx->s) == 0) { + ctx->state = 10; + break; + } + + /* not usable gen, try again */ + ctx->i--; + if (ctx->i == 0) { + err = RNG_FAILURE_E; + } + ctx->state = 1; + break; + } + case 10: /* RES */ + err = sp_384_to_mp(ctx->r, rm); + if (err == MP_OKAY) { + err = sp_384_to_mp(ctx->s, sm); + } + break; + } + + if (err == MP_OKAY && ctx->state != 10) { + err = FP_WOULDBLOCK; + } + if (err != FP_WOULDBLOCK) { + XMEMSET(ctx->e, 0, sizeof(sp_digit) * 2U * 7U); + XMEMSET(ctx->x, 0, sizeof(sp_digit) * 2U * 7U); + XMEMSET(ctx->k, 0, sizeof(sp_digit) * 2U * 7U); + XMEMSET(ctx->r, 0, sizeof(sp_digit) * 2U * 7U); + XMEMSET(ctx->tmp, 0, sizeof(sp_digit) * 3U * 2U * 7U); + } + + return err; +} +#endif /* WOLFSSL_SP_NONBLOCK */ + int sp_ecc_sign_384(const byte* hash, word32 hashLen, WC_RNG* rng, mp_int* priv, mp_int* rm, mp_int* sm, mp_int* km, void* heap) { @@ -22601,6 +24066,169 @@ int sp_ecc_sign_384(const byte* hash, word32 hashLen, WC_RNG* rng, mp_int* priv, * returns RNG failures, MEMORY_E when memory allocation fails and * MP_OKAY on success. */ +#ifdef WOLFSSL_SP_NONBLOCK +typedef struct sp_ecc_verify_384_ctx { + int state; + union { + sp_384_ecc_mulmod_7_ctx mulmod_ctx; + sp_384_mont_inv_order_7_ctx mont_inv_order_ctx; + sp_384_proj_point_dbl_7_ctx dbl_ctx; + sp_384_proj_point_add_7_ctx add_ctx; + }; + sp_digit u1[2*7]; + sp_digit u2[2*7]; + sp_digit s[2*7]; + sp_digit tmp[2*7 * 5]; + sp_point_384 p1; + sp_point_384 p2; +} sp_ecc_verify_384_ctx; + +int sp_ecc_verify_384_nb(sp_ecc_ctx_t* sp_ctx, const byte* hash, word32 hashLen, mp_int* pX, + mp_int* pY, mp_int* pZ, mp_int* r, mp_int* sm, int* res, void* heap) +{ + int err = FP_WOULDBLOCK; + sp_ecc_verify_384_ctx* ctx = (sp_ecc_verify_384_ctx*)sp_ctx->data; + + typedef char ctx_size_test[sizeof(sp_ecc_verify_384_ctx) >= sizeof(*sp_ctx) ? -1 : 1]; + (void)sizeof(ctx_size_test); + + switch (ctx->state) { + case 0: /* INIT */ + if (hashLen > 48U) { + hashLen = 48U; + } + + sp_384_from_bin(ctx->u1, 7, hash, (int)hashLen); + sp_384_from_mp(ctx->u2, 7, r); + sp_384_from_mp(ctx->s, 7, sm); + sp_384_from_mp(ctx->p2.x, 7, pX); + sp_384_from_mp(ctx->p2.y, 7, pY); + sp_384_from_mp(ctx->p2.z, 7, pZ); + sp_384_mul_7(ctx->s, ctx->s, p384_norm_order); + err = sp_384_mod_7(ctx->s, ctx->s, p384_order); + if (err == MP_OKAY) + ctx->state = 1; + break; + case 1: /* NORMS1 */ + sp_384_norm_7(ctx->s); + XMEMSET(&ctx->mont_inv_order_ctx, 0, sizeof(ctx->mont_inv_order_ctx)); + ctx->state = 2; + break; + case 2: /* NORMS2 */ + err = sp_384_mont_inv_order_7_nb((sp_ecc_ctx_t*)&ctx->mont_inv_order_ctx, ctx->s, ctx->s, ctx->tmp); + if (err == MP_OKAY) { + ctx->state = 3; + } + break; + case 3: /* NORMS3 */ + sp_384_mont_mul_order_7(ctx->u1, ctx->u1, ctx->s); + ctx->state = 4; + break; + case 4: /* NORMS4 */ + sp_384_mont_mul_order_7(ctx->u2, ctx->u2, ctx->s); + XMEMSET(&ctx->mulmod_ctx, 0, sizeof(ctx->mulmod_ctx)); + ctx->state = 5; + break; + case 5: /* MULBASE */ + err = sp_384_ecc_mulmod_7_nb((sp_ecc_ctx_t*)&ctx->mulmod_ctx, &ctx->p1, &p384_base, ctx->u1, 0, heap); + if (err == MP_OKAY) { + XMEMSET(&ctx->mulmod_ctx, 0, sizeof(ctx->mulmod_ctx)); + ctx->state = 6; + } + break; + case 6: /* MULMOD */ + err = sp_384_ecc_mulmod_7_nb((sp_ecc_ctx_t*)&ctx->mulmod_ctx, &ctx->p2, &ctx->p2, ctx->u2, 0, heap); + if (err == MP_OKAY) { + XMEMSET(&ctx->add_ctx, 0, sizeof(ctx->add_ctx)); + ctx->state = 7; + } + break; + case 7: /* ADD */ + err = sp_384_proj_point_add_7_nb((sp_ecc_ctx_t*)&ctx->add_ctx, &ctx->p1, &ctx->p1, &ctx->p2, ctx->tmp); + if (err == MP_OKAY) + ctx->state = 8; + break; + case 8: /* DBLPREP */ + if (sp_384_iszero_7(ctx->p1.z)) { + if (sp_384_iszero_7(ctx->p1.x) && sp_384_iszero_7(ctx->p1.y)) { + XMEMSET(&ctx->dbl_ctx, 0, sizeof(ctx->dbl_ctx)); + ctx->state = 9; + break; + } + else { + /* Y ordinate is not used from here - don't set. */ + int i; + for (i=0; i<7; i++) { + ctx->p1.x[i] = 0; + } + XMEMCPY(ctx->p1.z, p384_norm_mod, sizeof(p384_norm_mod)); + } + } + ctx->state = 10; + break; + case 9: /* DBL */ + err = sp_384_proj_point_dbl_7_nb((sp_ecc_ctx_t*)&ctx->dbl_ctx, &ctx->p1, + &ctx->p2, ctx->tmp); + if (err == MP_OKAY) { + ctx->state = 10; + } + break; + case 10: /* MONT */ + /* (r + n*order).z'.z' mod prime == (u1.G + u2.Q)->x' */ + /* Reload r and convert to Montgomery form. */ + sp_384_from_mp(ctx->u2, 7, r); + err = sp_384_mod_mul_norm_7(ctx->u2, ctx->u2, p384_mod); + if (err == MP_OKAY) + ctx->state = 11; + break; + case 11: /* SQR */ + /* u1 = r.z'.z' mod prime */ + sp_384_mont_sqr_7(ctx->p1.z, ctx->p1.z, p384_mod, p384_mp_mod); + ctx->state = 12; + break; + case 12: /* MUL */ + sp_384_mont_mul_7(ctx->u1, ctx->u2, ctx->p1.z, p384_mod, p384_mp_mod); + ctx->state = 13; + break; + case 13: /* RES */ + err = MP_OKAY; /* math okay, now check result */ + *res = (int)(sp_384_cmp_7(ctx->p1.x, ctx->u1) == 0); + if (*res == 0) { + sp_digit carry; + int64_t c; + + /* Reload r and add order. */ + sp_384_from_mp(ctx->u2, 7, r); + carry = sp_384_add_7(ctx->u2, ctx->u2, p384_order); + /* Carry means result is greater than mod and is not valid. */ + if (carry == 0) { + sp_384_norm_7(ctx->u2); + + /* Compare with mod and if greater or equal then not valid. */ + c = sp_384_cmp_7(ctx->u2, p384_mod); + if (c < 0) { + /* Convert to Montogomery form */ + err = sp_384_mod_mul_norm_7(ctx->u2, ctx->u2, p384_mod); + if (err == MP_OKAY) { + /* u1 = (r + 1*order).z'.z' mod prime */ + sp_384_mont_mul_7(ctx->u1, ctx->u2, ctx->p1.z, p384_mod, + p384_mp_mod); + *res = (int)(sp_384_cmp_7(ctx->p1.x, ctx->u1) == 0); + } + } + } + } + break; + } + + if (err == MP_OKAY && ctx->state != 13) { + err = FP_WOULDBLOCK; + } + + return err; +} +#endif /* WOLFSSL_SP_NONBLOCK */ + int sp_ecc_verify_384(const byte* hash, word32 hashLen, mp_int* pX, mp_int* pY, mp_int* pZ, mp_int* r, mp_int* sm, int* res, void* heap) { diff --git a/wolfcrypt/src/sp_cortexm.c b/wolfcrypt/src/sp_cortexm.c index be01f9757c..5f54b56d66 100644 --- a/wolfcrypt/src/sp_cortexm.c +++ b/wolfcrypt/src/sp_cortexm.c @@ -15902,6 +15902,141 @@ SP_NOINLINE static void sp_256_div2_8(sp_digit* r, const sp_digit* a, const sp_d * p Point to double. * t Temporary ordinate data. */ +#ifdef WOLFSSL_SP_NONBLOCK +typedef struct sp_256_proj_point_dbl_8_ctx { + int state; + sp_digit* t1; + sp_digit* t2; + sp_digit* x; + sp_digit* y; + sp_digit* z; +} sp_256_proj_point_dbl_8_ctx; + +static int sp_256_proj_point_dbl_8_nb(sp_ecc_ctx_t* sp_ctx, sp_point_256* r, const sp_point_256* p, sp_digit* t) +{ + int err = FP_WOULDBLOCK; + sp_256_proj_point_dbl_8_ctx* ctx = (sp_256_proj_point_dbl_8_ctx*)sp_ctx->data; + + typedef char ctx_size_test[sizeof(sp_256_proj_point_dbl_8_ctx) >= sizeof(*sp_ctx) ? -1 : 1]; + (void)sizeof(ctx_size_test); + + switch (ctx->state) { + case 0: + ctx->t1 = t; + ctx->t2 = t + 2*8; + ctx->x = r->x; + ctx->y = r->y; + ctx->z = r->z; + + /* Put infinity into result. */ + if (r != p) { + r->infinity = p->infinity; + } + ctx->state = 1; + break; + case 1: + /* T1 = Z * Z */ + sp_256_mont_sqr_8(ctx->t1, p->z, p256_mod, p256_mp_mod); + ctx->state = 2; + break; + case 2: + /* Z = Y * Z */ + sp_256_mont_mul_8(ctx->z, p->y, p->z, p256_mod, p256_mp_mod); + ctx->state = 3; + break; + case 3: + /* Z = 2Z */ + sp_256_mont_dbl_8(ctx->z, ctx->z, p256_mod); + ctx->state = 4; + break; + case 4: + /* T2 = X - T1 */ + sp_256_mont_sub_8(ctx->t2, p->x, ctx->t1, p256_mod); + ctx->state = 5; + break; + case 5: + /* T1 = X + T1 */ + sp_256_mont_add_8(ctx->t1, p->x, ctx->t1, p256_mod); + ctx->state = 6; + break; + case 6: + /* T2 = T1 * T2 */ + sp_256_mont_mul_8(ctx->t2, ctx->t1, ctx->t2, p256_mod, p256_mp_mod); + ctx->state = 7; + break; + case 7: + /* T1 = 3T2 */ + sp_256_mont_tpl_8(ctx->t1, ctx->t2, p256_mod); + ctx->state = 8; + break; + case 8: + /* Y = 2Y */ + sp_256_mont_dbl_8(ctx->y, p->y, p256_mod); + ctx->state = 9; + break; + case 9: + /* Y = Y * Y */ + sp_256_mont_sqr_8(ctx->y, ctx->y, p256_mod, p256_mp_mod); + ctx->state = 10; + break; + case 10: + /* T2 = Y * Y */ + sp_256_mont_sqr_8(ctx->t2, ctx->y, p256_mod, p256_mp_mod); + ctx->state = 11; + break; + case 11: + /* T2 = T2/2 */ + sp_256_div2_8(ctx->t2, ctx->t2, p256_mod); + ctx->state = 12; + break; + case 12: + /* Y = Y * X */ + sp_256_mont_mul_8(ctx->y, ctx->y, p->x, p256_mod, p256_mp_mod); + ctx->state = 13; + break; + case 13: + /* X = T1 * T1 */ + sp_256_mont_sqr_8(ctx->x, ctx->t1, p256_mod, p256_mp_mod); + ctx->state = 14; + break; + case 14: + /* X = X - Y */ + sp_256_mont_sub_8(ctx->x, ctx->x, ctx->y, p256_mod); + ctx->state = 15; + break; + case 15: + /* X = X - Y */ + sp_256_mont_sub_8(ctx->x, ctx->x, ctx->y, p256_mod); + ctx->state = 16; + break; + case 16: + /* Y = Y - X */ + sp_256_mont_sub_8(ctx->y, ctx->y, ctx->x, p256_mod); + ctx->state = 17; + break; + case 17: + /* Y = Y * T1 */ + sp_256_mont_mul_8(ctx->y, ctx->y, ctx->t1, p256_mod, p256_mp_mod); + ctx->state = 18; + break; + case 18: + /* Y = Y - T2 */ + sp_256_mont_sub_8(ctx->y, ctx->y, ctx->t2, p256_mod); + ctx->state = 19; + /* fall-through */ + case 19: + err = MP_OKAY; + break; + } + + if (err == MP_OKAY && ctx->state != 19) { + err = FP_WOULDBLOCK; + } + + return err; +} +#endif /* WOLFSSL_SP_NONBLOCK */ + static void sp_256_proj_point_dbl_8(sp_point_256* r, const sp_point_256* p, sp_digit* t) { sp_digit* t1 = t; @@ -16067,6 +16202,209 @@ static int sp_256_cmp_equal_8(const sp_digit* a, const sp_digit* b) * q Second point to add. * t Temporary ordinate data. */ + +#ifdef WOLFSSL_SP_NONBLOCK +typedef struct sp_256_proj_point_add_8_ctx { + int state; + sp_256_proj_point_dbl_8_ctx dbl_ctx; + const sp_point_256* ap[2]; + sp_point_256* rp[2]; + sp_digit* t1; + sp_digit* t2; + sp_digit* t3; + sp_digit* t4; + sp_digit* t5; + sp_digit* x; + sp_digit* y; + sp_digit* z; +} sp_256_proj_point_add_8_ctx; + +static int sp_256_proj_point_add_8_nb(sp_ecc_ctx_t* sp_ctx, sp_point_256* r, + const sp_point_256* p, const sp_point_256* q, sp_digit* t) +{ + int err = FP_WOULDBLOCK; + sp_256_proj_point_add_8_ctx* ctx = (sp_256_proj_point_add_8_ctx*)sp_ctx->data; + + /* Ensure only the first point is the same as the result. */ + if (q == r) { + const sp_point_256* a = p; + p = q; + q = a; + } + + typedef char ctx_size_test[sizeof(sp_256_proj_point_add_8_ctx) >= sizeof(*sp_ctx) ? -1 : 1]; + (void)sizeof(ctx_size_test); + + switch (ctx->state) { + case 0: /* INIT */ + ctx->t1 = t; + ctx->t2 = t + 2*8; + ctx->t3 = t + 4*8; + ctx->t4 = t + 6*8; + ctx->t5 = t + 8*8; + + ctx->state = 1; + break; + case 1: + /* Check double */ + (void)sp_256_sub_8(ctx->t1, p256_mod, q->y); + sp_256_norm_8(ctx->t1); + if ((sp_256_cmp_equal_8(p->x, q->x) & sp_256_cmp_equal_8(p->z, q->z) & + (sp_256_cmp_equal_8(p->y, q->y) | sp_256_cmp_equal_8(p->y, ctx->t1))) != 0) + { + XMEMSET(&ctx->dbl_ctx, 0, sizeof(ctx->dbl_ctx)); + ctx->state = 2; + } + else { + ctx->state = 3; + } + break; + case 2: + err = sp_256_proj_point_dbl_8_nb((sp_ecc_ctx_t*)&ctx->dbl_ctx, r, p, t); + if (err == MP_OKAY) + ctx->state = 27; /* done */ + break; + case 3: + { + int i; + ctx->rp[0] = r; + + /*lint allow cast to different type of pointer*/ + ctx->rp[1] = (sp_point_256*)t; /*lint !e9087 !e740*/ + XMEMSET(ctx->rp[1], 0, sizeof(sp_point_256)); + ctx->x = ctx->rp[p->infinity | q->infinity]->x; + ctx->y = ctx->rp[p->infinity | q->infinity]->y; + ctx->z = ctx->rp[p->infinity | q->infinity]->z; + + ctx->ap[0] = p; + ctx->ap[1] = q; + for (i=0; i<8; i++) { + r->x[i] = ctx->ap[p->infinity]->x[i]; + } + for (i=0; i<8; i++) { + r->y[i] = ctx->ap[p->infinity]->y[i]; + } + for (i=0; i<8; i++) { + r->z[i] = ctx->ap[p->infinity]->z[i]; + } + r->infinity = ctx->ap[p->infinity]->infinity; + + ctx->state = 4; + break; + } + case 4: + /* U1 = X1*Z2^2 */ + sp_256_mont_sqr_8(ctx->t1, q->z, p256_mod, p256_mp_mod); + ctx->state = 5; + break; + case 5: + sp_256_mont_mul_8(ctx->t3, ctx->t1, q->z, p256_mod, p256_mp_mod); + ctx->state = 6; + break; + case 6: + sp_256_mont_mul_8(ctx->t1, ctx->t1, ctx->x, p256_mod, p256_mp_mod); + ctx->state = 7; + break; + case 7: + /* U2 = X2*Z1^2 */ + sp_256_mont_sqr_8(ctx->t2, ctx->z, p256_mod, p256_mp_mod); + ctx->state = 8; + break; + case 8: + sp_256_mont_mul_8(ctx->t4, ctx->t2, ctx->z, p256_mod, p256_mp_mod); + ctx->state = 9; + break; + case 9: + sp_256_mont_mul_8(ctx->t2, ctx->t2, q->x, p256_mod, p256_mp_mod); + ctx->state = 10; + break; + case 10: + /* S1 = Y1*Z2^3 */ + sp_256_mont_mul_8(ctx->t3, ctx->t3, ctx->y, p256_mod, p256_mp_mod); + ctx->state = 11; + break; + case 11: + /* S2 = Y2*Z1^3 */ + sp_256_mont_mul_8(ctx->t4, ctx->t4, q->y, p256_mod, p256_mp_mod); + ctx->state = 12; + break; + case 12: + /* H = U2 - U1 */ + sp_256_mont_sub_8(ctx->t2, ctx->t2, ctx->t1, p256_mod); + ctx->state = 13; + break; + case 13: + /* R = S2 - S1 */ + sp_256_mont_sub_8(ctx->t4, ctx->t4, ctx->t3, p256_mod); + ctx->state = 14; + break; + case 14: + /* Z3 = H*Z1*Z2 */ + sp_256_mont_mul_8(ctx->z, ctx->z, q->z, p256_mod, p256_mp_mod); + ctx->state = 15; + break; + case 15: + sp_256_mont_mul_8(ctx->z, ctx->z, ctx->t2, p256_mod, p256_mp_mod); + ctx->state = 16; + break; + case 16: + /* X3 = R^2 - H^3 - 2*U1*H^2 */ + sp_256_mont_sqr_8(ctx->x, ctx->t4, p256_mod, p256_mp_mod); + ctx->state = 17; + break; + case 17: + sp_256_mont_sqr_8(ctx->t5, ctx->t2, p256_mod, p256_mp_mod); + ctx->state = 18; + break; + case 18: + sp_256_mont_mul_8(ctx->y, ctx->t1, ctx->t5, p256_mod, p256_mp_mod); + ctx->state = 19; + break; + case 19: + sp_256_mont_mul_8(ctx->t5, ctx->t5, ctx->t2, p256_mod, p256_mp_mod); + ctx->state = 20; + break; + case 20: + sp_256_mont_sub_8(ctx->x, ctx->x, ctx->t5, p256_mod); + ctx->state = 21; + break; + case 21: + sp_256_mont_dbl_8(ctx->t1, ctx->y, p256_mod); + ctx->state = 22; + break; + case 22: + sp_256_mont_sub_8(ctx->x, ctx->x, ctx->t1, p256_mod); + ctx->state = 23; + break; + case 23: + /* Y3 = R*(U1*H^2 - X3) - S1*H^3 */ + sp_256_mont_sub_8(ctx->y, ctx->y, ctx->x, p256_mod); + ctx->state = 24; + break; + case 24: + sp_256_mont_mul_8(ctx->y, ctx->y, ctx->t4, p256_mod, p256_mp_mod); + ctx->state = 25; + break; + case 25: + sp_256_mont_mul_8(ctx->t5, ctx->t5, ctx->t3, p256_mod, p256_mp_mod); + ctx->state = 26; + break; + case 26: + sp_256_mont_sub_8(ctx->y, ctx->y, ctx->t5, p256_mod); + ctx->state = 27; + /* fall-through */ + case 27: + err = MP_OKAY; + break; + } + + if (err == MP_OKAY && ctx->state != 27) { + err = FP_WOULDBLOCK; + } + return err; +} +#endif /* WOLFSSL_SP_NONBLOCK */ + static void sp_256_proj_point_add_8(sp_point_256* r, const sp_point_256* p, const sp_point_256* q, sp_digit* t) { @@ -20047,6 +20385,46 @@ static void sp_256_mont_sqr_n_order_8(sp_digit* r, const sp_digit* a, int n) * a Number to invert. * td Temporary data. */ + +#ifdef WOLFSSL_SP_NONBLOCK +typedef struct sp_256_mont_inv_order_8_ctx { + int state; + int i; +} sp_256_mont_inv_order_8_ctx; +static int sp_256_mont_inv_order_8_nb(sp_ecc_ctx_t* sp_ctx, sp_digit* r, const sp_digit* a, + sp_digit* t) +{ + int err = FP_WOULDBLOCK; + sp_256_mont_inv_order_8_ctx* ctx = (sp_256_mont_inv_order_8_ctx*)sp_ctx; + + typedef char ctx_size_test[sizeof(sp_256_mont_inv_order_8_ctx) >= sizeof(*sp_ctx) ? -1 : 1]; + (void)sizeof(ctx_size_test); + + switch (ctx->state) { + case 0: + XMEMCPY(t, a, sizeof(sp_digit) * 8); + ctx->i = 254; + ctx->state = 1; + break; + case 1: + sp_256_mont_sqr_order_8(t, t); + if ((p256_order_minus_2[ctx->i / 32] & ((sp_int_digit)1 << (ctx->i % 32))) != 0) { + sp_256_mont_mul_order_8(t, t, a); + } + ctx->i--; + if (ctx->i == 0) { + ctx->state = 2; + } + break; + case 2: + XMEMCPY(r, t, sizeof(sp_digit) * 8U); + err = MP_OKAY; + break; + } + return err; +} +#endif /* WOLFSSL_SP_NONBLOCK */ + static void sp_256_mont_inv_order_8(sp_digit* r, const sp_digit* a, sp_digit* td) { @@ -20162,6 +20540,165 @@ static void sp_256_mont_inv_order_8(sp_digit* r, const sp_digit* a, * returns RNG failures, MEMORY_E when memory allocation fails and * MP_OKAY on success. */ +#ifdef WOLFSSL_SP_NONBLOCK +typedef struct sp_ecc_sign_256_ctx { + int state; + union { + sp_256_ecc_mulmod_8_ctx mulmod_ctx; + sp_256_mont_inv_order_8_ctx mont_inv_order_ctx; + }; + sp_digit e[2*8]; + sp_digit x[2*8]; + sp_digit k[2*8]; + sp_digit r[2*8]; + sp_digit tmp[3 * 2*8]; + sp_point_256 point; + sp_digit* s; + sp_digit* kInv; + int i; +} sp_ecc_sign_256_ctx; + +int sp_ecc_sign_256_nb(sp_ecc_ctx_t* sp_ctx, const byte* hash, word32 hashLen, WC_RNG* rng, mp_int* priv, + mp_int* rm, mp_int* sm, mp_int* km, void* heap) +{ + int err = FP_WOULDBLOCK; + sp_ecc_sign_256_ctx* ctx = (sp_ecc_sign_256_ctx*)sp_ctx->data; + + typedef char ctx_size_test[sizeof(sp_ecc_sign_256_ctx) >= sizeof(*sp_ctx) ? -1 : 1]; + (void)sizeof(ctx_size_test); + + (void)heap; + + switch (ctx->state) { + case 0: /* INIT */ + ctx->s = ctx->e; + ctx->kInv = ctx->k; + if (hashLen > 32U) { + hashLen = 32U; + } + + sp_256_from_bin(ctx->e, 8, hash, (int)hashLen); + + ctx->i = SP_ECC_MAX_SIG_GEN; + ctx->state = 1; + break; + case 1: /* GEN */ + sp_256_from_mp(ctx->x, 8, priv); + /* New random point. */ + if (km == NULL || mp_iszero(km)) { + err = sp_256_ecc_gen_k_8(rng, ctx->k); + } + else { + sp_256_from_mp(ctx->k, 8, km); + mp_zero(km); + } + XMEMSET(&ctx->mulmod_ctx, 0, sizeof(ctx->mulmod_ctx)); + ctx->state = 2; + break; + case 2: /* MULMOD */ + err = sp_256_ecc_mulmod_8_nb((sp_ecc_ctx_t*)&ctx->mulmod_ctx, + &ctx->point, &p256_base, ctx->k, 1, heap); + if (err == MP_OKAY) { + ctx->state = 3; + } + break; + case 3: /* MODORDER */ + { + int32_t c; + /* r = point->x mod order */ + XMEMCPY(ctx->r, ctx->point.x, sizeof(sp_digit) * 8U); + sp_256_norm_8(ctx->r); + c = sp_256_cmp_8(ctx->r, p256_order); + sp_256_cond_sub_8(ctx->r, ctx->r, p256_order, 0L - (sp_digit)(c >= 0)); + sp_256_norm_8(ctx->r); + ctx->state = 4; + break; + } + case 4: /* KMODORDER */ + /* Conv k to Montgomery form (mod order) */ + sp_256_mul_8(ctx->k, ctx->k, p256_norm_order); + err = sp_256_mod_8(ctx->k, ctx->k, p256_order); + if (err == MP_OKAY) { + sp_256_norm_8(ctx->k); + XMEMSET(&ctx->mont_inv_order_ctx, 0, sizeof(ctx->mont_inv_order_ctx)); + ctx->state = 5; + } + break; + case 5: /* KINV */ + /* kInv = 1/k mod order */ + err = sp_256_mont_inv_order_8_nb((sp_ecc_ctx_t*)&ctx->mont_inv_order_ctx, ctx->kInv, ctx->k, ctx->tmp); + if (err == MP_OKAY) { + XMEMSET(&ctx->mont_inv_order_ctx, 0, sizeof(ctx->mont_inv_order_ctx)); + ctx->state = 6; + } + break; + case 6: /* KINVNORM */ + sp_256_norm_8(ctx->kInv); + ctx->state = 7; + break; + case 7: /* R */ + /* s = r * x + e */ + sp_256_mul_8(ctx->x, ctx->x, ctx->r); + ctx->state = 8; + break; + case 8: /* S1 */ + err = sp_256_mod_8(ctx->x, ctx->x, p256_order); + if (err == MP_OKAY) + ctx->state = 9; + break; + case 9: /* S2 */ + { + sp_digit carry; + int32_t c; + sp_256_norm_8(ctx->x); + carry = sp_256_add_8(ctx->s, ctx->e, ctx->x); + sp_256_cond_sub_8(ctx->s, ctx->s, p256_order, 0 - carry); + sp_256_norm_8(ctx->s); + c = sp_256_cmp_8(ctx->s, p256_order); + sp_256_cond_sub_8(ctx->s, ctx->s, p256_order, 0L - (sp_digit)(c >= 0)); + sp_256_norm_8(ctx->s); + + /* s = s * k^-1 mod order */ + sp_256_mont_mul_order_8(ctx->s, ctx->s, ctx->kInv); + sp_256_norm_8(ctx->s); + + /* Check that signature is usable. */ + if (sp_256_iszero_8(ctx->s) == 0) { + ctx->state = 10; + break; + } + + /* not usable gen, try again */ + ctx->i--; + if (ctx->i == 0) { + err = RNG_FAILURE_E; + } + ctx->state = 1; + break; + } + case 10: /* RES */ + err = sp_256_to_mp(ctx->r, rm); + if (err == MP_OKAY) { + err = sp_256_to_mp(ctx->s, sm); + } + break; + } + + if (err == MP_OKAY && ctx->state != 10) { + err = FP_WOULDBLOCK; + } + if (err != FP_WOULDBLOCK) { + XMEMSET(ctx->e, 0, sizeof(sp_digit) * 2U * 8U); + XMEMSET(ctx->x, 0, sizeof(sp_digit) * 2U * 8U); + XMEMSET(ctx->k, 0, sizeof(sp_digit) * 2U * 8U); + XMEMSET(ctx->r, 0, sizeof(sp_digit) * 2U * 8U); + XMEMSET(ctx->tmp, 0, sizeof(sp_digit) * 3U * 2U * 8U); + } + + return err; +} +#endif /* WOLFSSL_SP_NONBLOCK */ + int sp_ecc_sign_256(const byte* hash, word32 hashLen, WC_RNG* rng, mp_int* priv, mp_int* rm, mp_int* sm, mp_int* km, void* heap) { @@ -20333,6 +20870,169 @@ int sp_ecc_sign_256(const byte* hash, word32 hashLen, WC_RNG* rng, mp_int* priv, * returns RNG failures, MEMORY_E when memory allocation fails and * MP_OKAY on success. */ +#ifdef WOLFSSL_SP_NONBLOCK +typedef struct sp_ecc_verify_256_ctx { + int state; + union { + sp_256_ecc_mulmod_8_ctx mulmod_ctx; + sp_256_mont_inv_order_8_ctx mont_inv_order_ctx; + sp_256_proj_point_dbl_8_ctx dbl_ctx; + sp_256_proj_point_add_8_ctx add_ctx; + }; + sp_digit u1[2*8]; + sp_digit u2[2*8]; + sp_digit s[2*8]; + sp_digit tmp[2*8 * 5]; + sp_point_256 p1; + sp_point_256 p2; +} sp_ecc_verify_256_ctx; + +int sp_ecc_verify_256_nb(sp_ecc_ctx_t* sp_ctx, const byte* hash, word32 hashLen, mp_int* pX, + mp_int* pY, mp_int* pZ, mp_int* r, mp_int* sm, int* res, void* heap) +{ + int err = FP_WOULDBLOCK; + sp_ecc_verify_256_ctx* ctx = (sp_ecc_verify_256_ctx*)sp_ctx->data; + + typedef char ctx_size_test[sizeof(sp_ecc_verify_256_ctx) >= sizeof(*sp_ctx) ? -1 : 1]; + (void)sizeof(ctx_size_test); + + switch (ctx->state) { + case 0: /* INIT */ + if (hashLen > 32U) { + hashLen = 32U; + } + + sp_256_from_bin(ctx->u1, 8, hash, (int)hashLen); + sp_256_from_mp(ctx->u2, 8, r); + sp_256_from_mp(ctx->s, 8, sm); + sp_256_from_mp(ctx->p2.x, 8, pX); + sp_256_from_mp(ctx->p2.y, 8, pY); + sp_256_from_mp(ctx->p2.z, 8, pZ); + sp_256_mul_8(ctx->s, ctx->s, p256_norm_order); + err = sp_256_mod_8(ctx->s, ctx->s, p256_order); + if (err == MP_OKAY) + ctx->state = 1; + break; + case 1: /* NORMS1 */ + sp_256_norm_8(ctx->s); + XMEMSET(&ctx->mont_inv_order_ctx, 0, sizeof(ctx->mont_inv_order_ctx)); + ctx->state = 2; + break; + case 2: /* NORMS2 */ + err = sp_256_mont_inv_order_8_nb((sp_ecc_ctx_t*)&ctx->mont_inv_order_ctx, ctx->s, ctx->s, ctx->tmp); + if (err == MP_OKAY) { + ctx->state = 3; + } + break; + case 3: /* NORMS3 */ + sp_256_mont_mul_order_8(ctx->u1, ctx->u1, ctx->s); + ctx->state = 4; + break; + case 4: /* NORMS4 */ + sp_256_mont_mul_order_8(ctx->u2, ctx->u2, ctx->s); + XMEMSET(&ctx->mulmod_ctx, 0, sizeof(ctx->mulmod_ctx)); + ctx->state = 5; + break; + case 5: /* MULBASE */ + err = sp_256_ecc_mulmod_8_nb((sp_ecc_ctx_t*)&ctx->mulmod_ctx, &ctx->p1, &p256_base, ctx->u1, 0, heap); + if (err == MP_OKAY) { + XMEMSET(&ctx->mulmod_ctx, 0, sizeof(ctx->mulmod_ctx)); + ctx->state = 6; + } + break; + case 6: /* MULMOD */ + err = sp_256_ecc_mulmod_8_nb((sp_ecc_ctx_t*)&ctx->mulmod_ctx, &ctx->p2, &ctx->p2, ctx->u2, 0, heap); + if (err == MP_OKAY) { + XMEMSET(&ctx->add_ctx, 0, sizeof(ctx->add_ctx)); + ctx->state = 7; + } + break; + case 7: /* ADD */ + err = sp_256_proj_point_add_8_nb((sp_ecc_ctx_t*)&ctx->add_ctx, &ctx->p1, &ctx->p1, &ctx->p2, ctx->tmp); + if (err == MP_OKAY) + ctx->state = 8; + break; + case 8: /* DBLPREP */ + if (sp_256_iszero_8(ctx->p1.z)) { + if (sp_256_iszero_8(ctx->p1.x) && sp_256_iszero_8(ctx->p1.y)) { + XMEMSET(&ctx->dbl_ctx, 0, sizeof(ctx->dbl_ctx)); + ctx->state = 9; + break; + } + else { + /* Y ordinate is not used from here - don't set. */ + int i; + for (i=0; i<8; i++) { + ctx->p1.x[i] = 0; + } + XMEMCPY(ctx->p1.z, p256_norm_mod, sizeof(p256_norm_mod)); + } + } + ctx->state = 10; + break; + case 9: /* DBL */ + err = sp_256_proj_point_dbl_8_nb((sp_ecc_ctx_t*)&ctx->dbl_ctx, &ctx->p1, + &ctx->p2, ctx->tmp); + if (err == MP_OKAY) { + ctx->state = 10; + } + break; + case 10: /* MONT */ + /* (r + n*order).z'.z' mod prime == (u1.G + u2.Q)->x' */ + /* Reload r and convert to Montgomery form. */ + sp_256_from_mp(ctx->u2, 8, r); + err = sp_256_mod_mul_norm_8(ctx->u2, ctx->u2, p256_mod); + if (err == MP_OKAY) + ctx->state = 11; + break; + case 11: /* SQR */ + /* u1 = r.z'.z' mod prime */ + sp_256_mont_sqr_8(ctx->p1.z, ctx->p1.z, p256_mod, p256_mp_mod); + ctx->state = 12; + break; + case 12: /* MUL */ + sp_256_mont_mul_8(ctx->u1, ctx->u2, ctx->p1.z, p256_mod, p256_mp_mod); + ctx->state = 13; + break; + case 13: /* RES */ + err = MP_OKAY; /* math okay, now check result */ + *res = (int)(sp_256_cmp_8(ctx->p1.x, ctx->u1) == 0); + if (*res == 0) { + sp_digit carry; + int32_t c; + + /* Reload r and add order. */ + sp_256_from_mp(ctx->u2, 8, r); + carry = sp_256_add_8(ctx->u2, ctx->u2, p256_order); + /* Carry means result is greater than mod and is not valid. */ + if (carry == 0) { + sp_256_norm_8(ctx->u2); + + /* Compare with mod and if greater or equal then not valid. */ + c = sp_256_cmp_8(ctx->u2, p256_mod); + if (c < 0) { + /* Convert to Montogomery form */ + err = sp_256_mod_mul_norm_8(ctx->u2, ctx->u2, p256_mod); + if (err == MP_OKAY) { + /* u1 = (r + 1*order).z'.z' mod prime */ + sp_256_mont_mul_8(ctx->u1, ctx->u2, ctx->p1.z, p256_mod, + p256_mp_mod); + *res = (int)(sp_256_cmp_8(ctx->p1.x, ctx->u1) == 0); + } + } + } + } + break; + } + + if (err == MP_OKAY && ctx->state != 13) { + err = FP_WOULDBLOCK; + } + + return err; +} +#endif /* WOLFSSL_SP_NONBLOCK */ + int sp_ecc_verify_256(const byte* hash, word32 hashLen, mp_int* pX, mp_int* pY, mp_int* pZ, mp_int* r, mp_int* sm, int* res, void* heap) { @@ -22356,6 +23056,141 @@ SP_NOINLINE static void sp_384_div2_12(sp_digit* r, const sp_digit* a, const sp_ * p Point to double. * t Temporary ordinate data. */ +#ifdef WOLFSSL_SP_NONBLOCK +typedef struct sp_384_proj_point_dbl_12_ctx { + int state; + sp_digit* t1; + sp_digit* t2; + sp_digit* x; + sp_digit* y; + sp_digit* z; +} sp_384_proj_point_dbl_12_ctx; + +static int sp_384_proj_point_dbl_12_nb(sp_ecc_ctx_t* sp_ctx, sp_point_384* r, const sp_point_384* p, sp_digit* t) +{ + int err = FP_WOULDBLOCK; + sp_384_proj_point_dbl_12_ctx* ctx = (sp_384_proj_point_dbl_12_ctx*)sp_ctx->data; + + typedef char ctx_size_test[sizeof(sp_384_proj_point_dbl_12_ctx) >= sizeof(*sp_ctx) ? -1 : 1]; + (void)sizeof(ctx_size_test); + + switch (ctx->state) { + case 0: + ctx->t1 = t; + ctx->t2 = t + 2*12; + ctx->x = r->x; + ctx->y = r->y; + ctx->z = r->z; + + /* Put infinity into result. */ + if (r != p) { + r->infinity = p->infinity; + } + ctx->state = 1; + break; + case 1: + /* T1 = Z * Z */ + sp_384_mont_sqr_12(ctx->t1, p->z, p384_mod, p384_mp_mod); + ctx->state = 2; + break; + case 2: + /* Z = Y * Z */ + sp_384_mont_mul_12(ctx->z, p->y, p->z, p384_mod, p384_mp_mod); + ctx->state = 3; + break; + case 3: + /* Z = 2Z */ + sp_384_mont_dbl_12(ctx->z, ctx->z, p384_mod); + ctx->state = 4; + break; + case 4: + /* T2 = X - T1 */ + sp_384_mont_sub_12(ctx->t2, p->x, ctx->t1, p384_mod); + ctx->state = 5; + break; + case 5: + /* T1 = X + T1 */ + sp_384_mont_add_12(ctx->t1, p->x, ctx->t1, p384_mod); + ctx->state = 6; + break; + case 6: + /* T2 = T1 * T2 */ + sp_384_mont_mul_12(ctx->t2, ctx->t1, ctx->t2, p384_mod, p384_mp_mod); + ctx->state = 7; + break; + case 7: + /* T1 = 3T2 */ + sp_384_mont_tpl_12(ctx->t1, ctx->t2, p384_mod); + ctx->state = 8; + break; + case 8: + /* Y = 2Y */ + sp_384_mont_dbl_12(ctx->y, p->y, p384_mod); + ctx->state = 9; + break; + case 9: + /* Y = Y * Y */ + sp_384_mont_sqr_12(ctx->y, ctx->y, p384_mod, p384_mp_mod); + ctx->state = 10; + break; + case 10: + /* T2 = Y * Y */ + sp_384_mont_sqr_12(ctx->t2, ctx->y, p384_mod, p384_mp_mod); + ctx->state = 11; + break; + case 11: + /* T2 = T2/2 */ + sp_384_div2_12(ctx->t2, ctx->t2, p384_mod); + ctx->state = 12; + break; + case 12: + /* Y = Y * X */ + sp_384_mont_mul_12(ctx->y, ctx->y, p->x, p384_mod, p384_mp_mod); + ctx->state = 13; + break; + case 13: + /* X = T1 * T1 */ + sp_384_mont_sqr_12(ctx->x, ctx->t1, p384_mod, p384_mp_mod); + ctx->state = 14; + break; + case 14: + /* X = X - Y */ + sp_384_mont_sub_12(ctx->x, ctx->x, ctx->y, p384_mod); + ctx->state = 15; + break; + case 15: + /* X = X - Y */ + sp_384_mont_sub_12(ctx->x, ctx->x, ctx->y, p384_mod); + ctx->state = 16; + break; + case 16: + /* Y = Y - X */ + sp_384_mont_sub_12(ctx->y, ctx->y, ctx->x, p384_mod); + ctx->state = 17; + break; + case 17: + /* Y = Y * T1 */ + sp_384_mont_mul_12(ctx->y, ctx->y, ctx->t1, p384_mod, p384_mp_mod); + ctx->state = 18; + break; + case 18: + /* Y = Y - T2 */ + sp_384_mont_sub_12(ctx->y, ctx->y, ctx->t2, p384_mod); + ctx->state = 19; + /* fall-through */ + case 19: + err = MP_OKAY; + break; + } + + if (err == MP_OKAY && ctx->state != 19) { + err = FP_WOULDBLOCK; + } + + return err; +} +#endif /* WOLFSSL_SP_NONBLOCK */ + static void sp_384_proj_point_dbl_12(sp_point_384* r, const sp_point_384* p, sp_digit* t) { sp_digit* t1 = t; @@ -22431,6 +23266,209 @@ static int sp_384_cmp_equal_12(const sp_digit* a, const sp_digit* b) * q Second point to add. * t Temporary ordinate data. */ + +#ifdef WOLFSSL_SP_NONBLOCK +typedef struct sp_384_proj_point_add_12_ctx { + int state; + sp_384_proj_point_dbl_12_ctx dbl_ctx; + const sp_point_384* ap[2]; + sp_point_384* rp[2]; + sp_digit* t1; + sp_digit* t2; + sp_digit* t3; + sp_digit* t4; + sp_digit* t5; + sp_digit* x; + sp_digit* y; + sp_digit* z; +} sp_384_proj_point_add_12_ctx; + +static int sp_384_proj_point_add_12_nb(sp_ecc_ctx_t* sp_ctx, sp_point_384* r, + const sp_point_384* p, const sp_point_384* q, sp_digit* t) +{ + int err = FP_WOULDBLOCK; + sp_384_proj_point_add_12_ctx* ctx = (sp_384_proj_point_add_12_ctx*)sp_ctx->data; + + /* Ensure only the first point is the same as the result. */ + if (q == r) { + const sp_point_384* a = p; + p = q; + q = a; + } + + typedef char ctx_size_test[sizeof(sp_384_proj_point_add_12_ctx) >= sizeof(*sp_ctx) ? -1 : 1]; + (void)sizeof(ctx_size_test); + + switch (ctx->state) { + case 0: /* INIT */ + ctx->t1 = t; + ctx->t2 = t + 2*12; + ctx->t3 = t + 4*12; + ctx->t4 = t + 6*12; + ctx->t5 = t + 8*12; + + ctx->state = 1; + break; + case 1: + /* Check double */ + (void)sp_384_sub_12(ctx->t1, p384_mod, q->y); + sp_384_norm_12(ctx->t1); + if ((sp_384_cmp_equal_12(p->x, q->x) & sp_384_cmp_equal_12(p->z, q->z) & + (sp_384_cmp_equal_12(p->y, q->y) | sp_384_cmp_equal_12(p->y, ctx->t1))) != 0) + { + XMEMSET(&ctx->dbl_ctx, 0, sizeof(ctx->dbl_ctx)); + ctx->state = 2; + } + else { + ctx->state = 3; + } + break; + case 2: + err = sp_384_proj_point_dbl_12_nb((sp_ecc_ctx_t*)&ctx->dbl_ctx, r, p, t); + if (err == MP_OKAY) + ctx->state = 27; /* done */ + break; + case 3: + { + int i; + ctx->rp[0] = r; + + /*lint allow cast to different type of pointer*/ + ctx->rp[1] = (sp_point_384*)t; /*lint !e9087 !e740*/ + XMEMSET(ctx->rp[1], 0, sizeof(sp_point_384)); + ctx->x = ctx->rp[p->infinity | q->infinity]->x; + ctx->y = ctx->rp[p->infinity | q->infinity]->y; + ctx->z = ctx->rp[p->infinity | q->infinity]->z; + + ctx->ap[0] = p; + ctx->ap[1] = q; + for (i=0; i<12; i++) { + r->x[i] = ctx->ap[p->infinity]->x[i]; + } + for (i=0; i<12; i++) { + r->y[i] = ctx->ap[p->infinity]->y[i]; + } + for (i=0; i<12; i++) { + r->z[i] = ctx->ap[p->infinity]->z[i]; + } + r->infinity = ctx->ap[p->infinity]->infinity; + + ctx->state = 4; + break; + } + case 4: + /* U1 = X1*Z2^2 */ + sp_384_mont_sqr_12(ctx->t1, q->z, p384_mod, p384_mp_mod); + ctx->state = 5; + break; + case 5: + sp_384_mont_mul_12(ctx->t3, ctx->t1, q->z, p384_mod, p384_mp_mod); + ctx->state = 6; + break; + case 6: + sp_384_mont_mul_12(ctx->t1, ctx->t1, ctx->x, p384_mod, p384_mp_mod); + ctx->state = 7; + break; + case 7: + /* U2 = X2*Z1^2 */ + sp_384_mont_sqr_12(ctx->t2, ctx->z, p384_mod, p384_mp_mod); + ctx->state = 8; + break; + case 8: + sp_384_mont_mul_12(ctx->t4, ctx->t2, ctx->z, p384_mod, p384_mp_mod); + ctx->state = 9; + break; + case 9: + sp_384_mont_mul_12(ctx->t2, ctx->t2, q->x, p384_mod, p384_mp_mod); + ctx->state = 10; + break; + case 10: + /* S1 = Y1*Z2^3 */ + sp_384_mont_mul_12(ctx->t3, ctx->t3, ctx->y, p384_mod, p384_mp_mod); + ctx->state = 11; + break; + case 11: + /* S2 = Y2*Z1^3 */ + sp_384_mont_mul_12(ctx->t4, ctx->t4, q->y, p384_mod, p384_mp_mod); + ctx->state = 12; + break; + case 12: + /* H = U2 - U1 */ + sp_384_mont_sub_12(ctx->t2, ctx->t2, ctx->t1, p384_mod); + ctx->state = 13; + break; + case 13: + /* R = S2 - S1 */ + sp_384_mont_sub_12(ctx->t4, ctx->t4, ctx->t3, p384_mod); + ctx->state = 14; + break; + case 14: + /* Z3 = H*Z1*Z2 */ + sp_384_mont_mul_12(ctx->z, ctx->z, q->z, p384_mod, p384_mp_mod); + ctx->state = 15; + break; + case 15: + sp_384_mont_mul_12(ctx->z, ctx->z, ctx->t2, p384_mod, p384_mp_mod); + ctx->state = 16; + break; + case 16: + /* X3 = R^2 - H^3 - 2*U1*H^2 */ + sp_384_mont_sqr_12(ctx->x, ctx->t4, p384_mod, p384_mp_mod); + ctx->state = 17; + break; + case 17: + sp_384_mont_sqr_12(ctx->t5, ctx->t2, p384_mod, p384_mp_mod); + ctx->state = 18; + break; + case 18: + sp_384_mont_mul_12(ctx->y, ctx->t1, ctx->t5, p384_mod, p384_mp_mod); + ctx->state = 19; + break; + case 19: + sp_384_mont_mul_12(ctx->t5, ctx->t5, ctx->t2, p384_mod, p384_mp_mod); + ctx->state = 20; + break; + case 20: + sp_384_mont_sub_12(ctx->x, ctx->x, ctx->t5, p384_mod); + ctx->state = 21; + break; + case 21: + sp_384_mont_dbl_12(ctx->t1, ctx->y, p384_mod); + ctx->state = 22; + break; + case 22: + sp_384_mont_sub_12(ctx->x, ctx->x, ctx->t1, p384_mod); + ctx->state = 23; + break; + case 23: + /* Y3 = R*(U1*H^2 - X3) - S1*H^3 */ + sp_384_mont_sub_12(ctx->y, ctx->y, ctx->x, p384_mod); + ctx->state = 24; + break; + case 24: + sp_384_mont_mul_12(ctx->y, ctx->y, ctx->t4, p384_mod, p384_mp_mod); + ctx->state = 25; + break; + case 25: + sp_384_mont_mul_12(ctx->t5, ctx->t5, ctx->t3, p384_mod, p384_mp_mod); + ctx->state = 26; + break; + case 26: + sp_384_mont_sub_12(ctx->y, ctx->y, ctx->t5, p384_mod); + ctx->state = 27; + /* fall-through */ + case 27: + err = MP_OKAY; + break; + } + + if (err == MP_OKAY && ctx->state != 27) { + err = FP_WOULDBLOCK; + } + return err; +} +#endif /* WOLFSSL_SP_NONBLOCK */ + static void sp_384_proj_point_add_12(sp_point_384* r, const sp_point_384* p, const sp_point_384* q, sp_digit* t) { @@ -25581,6 +26619,46 @@ static void sp_384_mont_sqr_n_order_12(sp_digit* r, const sp_digit* a, int n) * a Number to invert. * td Temporary data. */ + +#ifdef WOLFSSL_SP_NONBLOCK +typedef struct sp_384_mont_inv_order_12_ctx { + int state; + int i; +} sp_384_mont_inv_order_12_ctx; +static int sp_384_mont_inv_order_12_nb(sp_ecc_ctx_t* sp_ctx, sp_digit* r, const sp_digit* a, + sp_digit* t) +{ + int err = FP_WOULDBLOCK; + sp_384_mont_inv_order_12_ctx* ctx = (sp_384_mont_inv_order_12_ctx*)sp_ctx; + + typedef char ctx_size_test[sizeof(sp_384_mont_inv_order_12_ctx) >= sizeof(*sp_ctx) ? -1 : 1]; + (void)sizeof(ctx_size_test); + + switch (ctx->state) { + case 0: + XMEMCPY(t, a, sizeof(sp_digit) * 12); + ctx->i = 382; + ctx->state = 1; + break; + case 1: + sp_384_mont_sqr_order_12(t, t); + if ((p384_order_minus_2[ctx->i / 32] & ((sp_int_digit)1 << (ctx->i % 32))) != 0) { + sp_384_mont_mul_order_12(t, t, a); + } + ctx->i--; + if (ctx->i == 0) { + ctx->state = 2; + } + break; + case 2: + XMEMCPY(r, t, sizeof(sp_digit) * 12U); + err = MP_OKAY; + break; + } + return err; +} +#endif /* WOLFSSL_SP_NONBLOCK */ + static void sp_384_mont_inv_order_12(sp_digit* r, const sp_digit* a, sp_digit* td) { @@ -25667,6 +26745,165 @@ static void sp_384_mont_inv_order_12(sp_digit* r, const sp_digit* a, * returns RNG failures, MEMORY_E when memory allocation fails and * MP_OKAY on success. */ +#ifdef WOLFSSL_SP_NONBLOCK +typedef struct sp_ecc_sign_384_ctx { + int state; + union { + sp_384_ecc_mulmod_12_ctx mulmod_ctx; + sp_384_mont_inv_order_12_ctx mont_inv_order_ctx; + }; + sp_digit e[2*12]; + sp_digit x[2*12]; + sp_digit k[2*12]; + sp_digit r[2*12]; + sp_digit tmp[3 * 2*12]; + sp_point_384 point; + sp_digit* s; + sp_digit* kInv; + int i; +} sp_ecc_sign_384_ctx; + +int sp_ecc_sign_384_nb(sp_ecc_ctx_t* sp_ctx, const byte* hash, word32 hashLen, WC_RNG* rng, mp_int* priv, + mp_int* rm, mp_int* sm, mp_int* km, void* heap) +{ + int err = FP_WOULDBLOCK; + sp_ecc_sign_384_ctx* ctx = (sp_ecc_sign_384_ctx*)sp_ctx->data; + + typedef char ctx_size_test[sizeof(sp_ecc_sign_384_ctx) >= sizeof(*sp_ctx) ? -1 : 1]; + (void)sizeof(ctx_size_test); + + (void)heap; + + switch (ctx->state) { + case 0: /* INIT */ + ctx->s = ctx->e; + ctx->kInv = ctx->k; + if (hashLen > 48U) { + hashLen = 48U; + } + + sp_384_from_bin(ctx->e, 12, hash, (int)hashLen); + + ctx->i = SP_ECC_MAX_SIG_GEN; + ctx->state = 1; + break; + case 1: /* GEN */ + sp_384_from_mp(ctx->x, 12, priv); + /* New random point. */ + if (km == NULL || mp_iszero(km)) { + err = sp_384_ecc_gen_k_12(rng, ctx->k); + } + else { + sp_384_from_mp(ctx->k, 12, km); + mp_zero(km); + } + XMEMSET(&ctx->mulmod_ctx, 0, sizeof(ctx->mulmod_ctx)); + ctx->state = 2; + break; + case 2: /* MULMOD */ + err = sp_384_ecc_mulmod_12_nb((sp_ecc_ctx_t*)&ctx->mulmod_ctx, + &ctx->point, &p384_base, ctx->k, 1, heap); + if (err == MP_OKAY) { + ctx->state = 3; + } + break; + case 3: /* MODORDER */ + { + int32_t c; + /* r = point->x mod order */ + XMEMCPY(ctx->r, ctx->point.x, sizeof(sp_digit) * 12U); + sp_384_norm_12(ctx->r); + c = sp_384_cmp_12(ctx->r, p384_order); + sp_384_cond_sub_12(ctx->r, ctx->r, p384_order, 0L - (sp_digit)(c >= 0)); + sp_384_norm_12(ctx->r); + ctx->state = 4; + break; + } + case 4: /* KMODORDER */ + /* Conv k to Montgomery form (mod order) */ + sp_384_mul_12(ctx->k, ctx->k, p384_norm_order); + err = sp_384_mod_12(ctx->k, ctx->k, p384_order); + if (err == MP_OKAY) { + sp_384_norm_12(ctx->k); + XMEMSET(&ctx->mont_inv_order_ctx, 0, sizeof(ctx->mont_inv_order_ctx)); + ctx->state = 5; + } + break; + case 5: /* KINV */ + /* kInv = 1/k mod order */ + err = sp_384_mont_inv_order_12_nb((sp_ecc_ctx_t*)&ctx->mont_inv_order_ctx, ctx->kInv, ctx->k, ctx->tmp); + if (err == MP_OKAY) { + XMEMSET(&ctx->mont_inv_order_ctx, 0, sizeof(ctx->mont_inv_order_ctx)); + ctx->state = 6; + } + break; + case 6: /* KINVNORM */ + sp_384_norm_12(ctx->kInv); + ctx->state = 7; + break; + case 7: /* R */ + /* s = r * x + e */ + sp_384_mul_12(ctx->x, ctx->x, ctx->r); + ctx->state = 8; + break; + case 8: /* S1 */ + err = sp_384_mod_12(ctx->x, ctx->x, p384_order); + if (err == MP_OKAY) + ctx->state = 9; + break; + case 9: /* S2 */ + { + sp_digit carry; + int32_t c; + sp_384_norm_12(ctx->x); + carry = sp_384_add_12(ctx->s, ctx->e, ctx->x); + sp_384_cond_sub_12(ctx->s, ctx->s, p384_order, 0 - carry); + sp_384_norm_12(ctx->s); + c = sp_384_cmp_12(ctx->s, p384_order); + sp_384_cond_sub_12(ctx->s, ctx->s, p384_order, 0L - (sp_digit)(c >= 0)); + sp_384_norm_12(ctx->s); + + /* s = s * k^-1 mod order */ + sp_384_mont_mul_order_12(ctx->s, ctx->s, ctx->kInv); + sp_384_norm_12(ctx->s); + + /* Check that signature is usable. */ + if (sp_384_iszero_12(ctx->s) == 0) { + ctx->state = 10; + break; + } + + /* not usable gen, try again */ + ctx->i--; + if (ctx->i == 0) { + err = RNG_FAILURE_E; + } + ctx->state = 1; + break; + } + case 10: /* RES */ + err = sp_384_to_mp(ctx->r, rm); + if (err == MP_OKAY) { + err = sp_384_to_mp(ctx->s, sm); + } + break; + } + + if (err == MP_OKAY && ctx->state != 10) { + err = FP_WOULDBLOCK; + } + if (err != FP_WOULDBLOCK) { + XMEMSET(ctx->e, 0, sizeof(sp_digit) * 2U * 12U); + XMEMSET(ctx->x, 0, sizeof(sp_digit) * 2U * 12U); + XMEMSET(ctx->k, 0, sizeof(sp_digit) * 2U * 12U); + XMEMSET(ctx->r, 0, sizeof(sp_digit) * 2U * 12U); + XMEMSET(ctx->tmp, 0, sizeof(sp_digit) * 3U * 2U * 12U); + } + + return err; +} +#endif /* WOLFSSL_SP_NONBLOCK */ + int sp_ecc_sign_384(const byte* hash, word32 hashLen, WC_RNG* rng, mp_int* priv, mp_int* rm, mp_int* sm, mp_int* km, void* heap) { @@ -25838,6 +27075,169 @@ int sp_ecc_sign_384(const byte* hash, word32 hashLen, WC_RNG* rng, mp_int* priv, * returns RNG failures, MEMORY_E when memory allocation fails and * MP_OKAY on success. */ +#ifdef WOLFSSL_SP_NONBLOCK +typedef struct sp_ecc_verify_384_ctx { + int state; + union { + sp_384_ecc_mulmod_12_ctx mulmod_ctx; + sp_384_mont_inv_order_12_ctx mont_inv_order_ctx; + sp_384_proj_point_dbl_12_ctx dbl_ctx; + sp_384_proj_point_add_12_ctx add_ctx; + }; + sp_digit u1[2*12]; + sp_digit u2[2*12]; + sp_digit s[2*12]; + sp_digit tmp[2*12 * 5]; + sp_point_384 p1; + sp_point_384 p2; +} sp_ecc_verify_384_ctx; + +int sp_ecc_verify_384_nb(sp_ecc_ctx_t* sp_ctx, const byte* hash, word32 hashLen, mp_int* pX, + mp_int* pY, mp_int* pZ, mp_int* r, mp_int* sm, int* res, void* heap) +{ + int err = FP_WOULDBLOCK; + sp_ecc_verify_384_ctx* ctx = (sp_ecc_verify_384_ctx*)sp_ctx->data; + + typedef char ctx_size_test[sizeof(sp_ecc_verify_384_ctx) >= sizeof(*sp_ctx) ? -1 : 1]; + (void)sizeof(ctx_size_test); + + switch (ctx->state) { + case 0: /* INIT */ + if (hashLen > 48U) { + hashLen = 48U; + } + + sp_384_from_bin(ctx->u1, 12, hash, (int)hashLen); + sp_384_from_mp(ctx->u2, 12, r); + sp_384_from_mp(ctx->s, 12, sm); + sp_384_from_mp(ctx->p2.x, 12, pX); + sp_384_from_mp(ctx->p2.y, 12, pY); + sp_384_from_mp(ctx->p2.z, 12, pZ); + sp_384_mul_12(ctx->s, ctx->s, p384_norm_order); + err = sp_384_mod_12(ctx->s, ctx->s, p384_order); + if (err == MP_OKAY) + ctx->state = 1; + break; + case 1: /* NORMS1 */ + sp_384_norm_12(ctx->s); + XMEMSET(&ctx->mont_inv_order_ctx, 0, sizeof(ctx->mont_inv_order_ctx)); + ctx->state = 2; + break; + case 2: /* NORMS2 */ + err = sp_384_mont_inv_order_12_nb((sp_ecc_ctx_t*)&ctx->mont_inv_order_ctx, ctx->s, ctx->s, ctx->tmp); + if (err == MP_OKAY) { + ctx->state = 3; + } + break; + case 3: /* NORMS3 */ + sp_384_mont_mul_order_12(ctx->u1, ctx->u1, ctx->s); + ctx->state = 4; + break; + case 4: /* NORMS4 */ + sp_384_mont_mul_order_12(ctx->u2, ctx->u2, ctx->s); + XMEMSET(&ctx->mulmod_ctx, 0, sizeof(ctx->mulmod_ctx)); + ctx->state = 5; + break; + case 5: /* MULBASE */ + err = sp_384_ecc_mulmod_12_nb((sp_ecc_ctx_t*)&ctx->mulmod_ctx, &ctx->p1, &p384_base, ctx->u1, 0, heap); + if (err == MP_OKAY) { + XMEMSET(&ctx->mulmod_ctx, 0, sizeof(ctx->mulmod_ctx)); + ctx->state = 6; + } + break; + case 6: /* MULMOD */ + err = sp_384_ecc_mulmod_12_nb((sp_ecc_ctx_t*)&ctx->mulmod_ctx, &ctx->p2, &ctx->p2, ctx->u2, 0, heap); + if (err == MP_OKAY) { + XMEMSET(&ctx->add_ctx, 0, sizeof(ctx->add_ctx)); + ctx->state = 7; + } + break; + case 7: /* ADD */ + err = sp_384_proj_point_add_12_nb((sp_ecc_ctx_t*)&ctx->add_ctx, &ctx->p1, &ctx->p1, &ctx->p2, ctx->tmp); + if (err == MP_OKAY) + ctx->state = 8; + break; + case 8: /* DBLPREP */ + if (sp_384_iszero_12(ctx->p1.z)) { + if (sp_384_iszero_12(ctx->p1.x) && sp_384_iszero_12(ctx->p1.y)) { + XMEMSET(&ctx->dbl_ctx, 0, sizeof(ctx->dbl_ctx)); + ctx->state = 9; + break; + } + else { + /* Y ordinate is not used from here - don't set. */ + int i; + for (i=0; i<12; i++) { + ctx->p1.x[i] = 0; + } + XMEMCPY(ctx->p1.z, p384_norm_mod, sizeof(p384_norm_mod)); + } + } + ctx->state = 10; + break; + case 9: /* DBL */ + err = sp_384_proj_point_dbl_12_nb((sp_ecc_ctx_t*)&ctx->dbl_ctx, &ctx->p1, + &ctx->p2, ctx->tmp); + if (err == MP_OKAY) { + ctx->state = 10; + } + break; + case 10: /* MONT */ + /* (r + n*order).z'.z' mod prime == (u1.G + u2.Q)->x' */ + /* Reload r and convert to Montgomery form. */ + sp_384_from_mp(ctx->u2, 12, r); + err = sp_384_mod_mul_norm_12(ctx->u2, ctx->u2, p384_mod); + if (err == MP_OKAY) + ctx->state = 11; + break; + case 11: /* SQR */ + /* u1 = r.z'.z' mod prime */ + sp_384_mont_sqr_12(ctx->p1.z, ctx->p1.z, p384_mod, p384_mp_mod); + ctx->state = 12; + break; + case 12: /* MUL */ + sp_384_mont_mul_12(ctx->u1, ctx->u2, ctx->p1.z, p384_mod, p384_mp_mod); + ctx->state = 13; + break; + case 13: /* RES */ + err = MP_OKAY; /* math okay, now check result */ + *res = (int)(sp_384_cmp_12(ctx->p1.x, ctx->u1) == 0); + if (*res == 0) { + sp_digit carry; + int32_t c; + + /* Reload r and add order. */ + sp_384_from_mp(ctx->u2, 12, r); + carry = sp_384_add_12(ctx->u2, ctx->u2, p384_order); + /* Carry means result is greater than mod and is not valid. */ + if (carry == 0) { + sp_384_norm_12(ctx->u2); + + /* Compare with mod and if greater or equal then not valid. */ + c = sp_384_cmp_12(ctx->u2, p384_mod); + if (c < 0) { + /* Convert to Montogomery form */ + err = sp_384_mod_mul_norm_12(ctx->u2, ctx->u2, p384_mod); + if (err == MP_OKAY) { + /* u1 = (r + 1*order).z'.z' mod prime */ + sp_384_mont_mul_12(ctx->u1, ctx->u2, ctx->p1.z, p384_mod, + p384_mp_mod); + *res = (int)(sp_384_cmp_12(ctx->p1.x, ctx->u1) == 0); + } + } + } + } + break; + } + + if (err == MP_OKAY && ctx->state != 13) { + err = FP_WOULDBLOCK; + } + + return err; +} +#endif /* WOLFSSL_SP_NONBLOCK */ + int sp_ecc_verify_384(const byte* hash, word32 hashLen, mp_int* pX, mp_int* pY, mp_int* pZ, mp_int* r, mp_int* sm, int* res, void* heap) { diff --git a/wolfcrypt/src/sp_int.c b/wolfcrypt/src/sp_int.c index e21f4888fe..1f9c8cf88f 100644 --- a/wolfcrypt/src/sp_int.c +++ b/wolfcrypt/src/sp_int.c @@ -38,8 +38,10 @@ * WOLFSSL_HAVE_SP_RSA: Enable SP RSA support * WOLFSSL_HAVE_SP_DH: Enable SP DH support * WOLFSSL_HAVE_SP_ECC: Enable SP ECC support - * WOLFSSL_SP_MATH: Use only single precision math and algorithms it supports (no fastmath tfm.c or normal integer.c) - * WOLFSSL_SP_SMALL: Use smaller version of code and avoid large stack variables + * WOLFSSL_SP_MATH: Use only single precision math and algorithms + * it supports (no fastmath tfm.c or normal integer.c) + * WOLFSSL_SP_SMALL: Use smaller version of code and avoid large + * stack variables * WOLFSSL_SP_NO_MALLOC: Always use stack, no heap XMALLOC/XFREE allowed * WOLFSSL_SP_NO_2048: Disable RSA/DH 2048-bit support * WOLFSSL_SP_NO_3072: Disable RSA/DH 3072-bit support @@ -52,8 +54,12 @@ * WOLFSSL_SP_ARM32_ASM Enable Aarch32 assembly speedups * WOLFSSL_SP_ARM64_ASM Enable Aarch64 assembly speedups * WOLFSSL_SP_ARM_CORTEX_M_ASM Enable Cortex-M assembly speedups - * WOLFSSL_SP_ARM_THUMB_ASM Enable ARM Thumb assembly speedups (used with -mthumb) + * WOLFSSL_SP_ARM_THUMB_ASM Enable ARM Thumb assembly speedups + * (used with -mthumb) * SP_WORD_SIZE Force 32 or 64 bit mode + * WOLFSSL_SP_NONBLOCK Enables "non blocking" mode for SP math, which + * will return FP_WOULDBLOCK for long operations and function must be + * called again until complete. */ #ifdef WOLFSSL_SP_MATH diff --git a/wolfcrypt/src/sp_x86_64.c b/wolfcrypt/src/sp_x86_64.c index 435aa22344..67eadecffb 100644 --- a/wolfcrypt/src/sp_x86_64.c +++ b/wolfcrypt/src/sp_x86_64.c @@ -6562,6 +6562,141 @@ extern void sp_256_div2_4(sp_digit* r, const sp_digit* a, const sp_digit* m); * p Point to double. * t Temporary ordinate data. */ +#ifdef WOLFSSL_SP_NONBLOCK +typedef struct sp_256_proj_point_dbl_4_ctx { + int state; + sp_digit* t1; + sp_digit* t2; + sp_digit* x; + sp_digit* y; + sp_digit* z; +} sp_256_proj_point_dbl_4_ctx; + +static int sp_256_proj_point_dbl_4_nb(sp_ecc_ctx_t* sp_ctx, sp_point_256* r, const sp_point_256* p, sp_digit* t) +{ + int err = FP_WOULDBLOCK; + sp_256_proj_point_dbl_4_ctx* ctx = (sp_256_proj_point_dbl_4_ctx*)sp_ctx->data; + + typedef char ctx_size_test[sizeof(sp_256_proj_point_dbl_4_ctx) >= sizeof(*sp_ctx) ? -1 : 1]; + (void)sizeof(ctx_size_test); + + switch (ctx->state) { + case 0: + ctx->t1 = t; + ctx->t2 = t + 2*4; + ctx->x = r->x; + ctx->y = r->y; + ctx->z = r->z; + + /* Put infinity into result. */ + if (r != p) { + r->infinity = p->infinity; + } + ctx->state = 1; + break; + case 1: + /* T1 = Z * Z */ + sp_256_mont_sqr_4(ctx->t1, p->z, p256_mod, p256_mp_mod); + ctx->state = 2; + break; + case 2: + /* Z = Y * Z */ + sp_256_mont_mul_4(ctx->z, p->y, p->z, p256_mod, p256_mp_mod); + ctx->state = 3; + break; + case 3: + /* Z = 2Z */ + sp_256_mont_dbl_4(ctx->z, ctx->z, p256_mod); + ctx->state = 4; + break; + case 4: + /* T2 = X - T1 */ + sp_256_mont_sub_4(ctx->t2, p->x, ctx->t1, p256_mod); + ctx->state = 5; + break; + case 5: + /* T1 = X + T1 */ + sp_256_mont_add_4(ctx->t1, p->x, ctx->t1, p256_mod); + ctx->state = 6; + break; + case 6: + /* T2 = T1 * T2 */ + sp_256_mont_mul_4(ctx->t2, ctx->t1, ctx->t2, p256_mod, p256_mp_mod); + ctx->state = 7; + break; + case 7: + /* T1 = 3T2 */ + sp_256_mont_tpl_4(ctx->t1, ctx->t2, p256_mod); + ctx->state = 8; + break; + case 8: + /* Y = 2Y */ + sp_256_mont_dbl_4(ctx->y, p->y, p256_mod); + ctx->state = 9; + break; + case 9: + /* Y = Y * Y */ + sp_256_mont_sqr_4(ctx->y, ctx->y, p256_mod, p256_mp_mod); + ctx->state = 10; + break; + case 10: + /* T2 = Y * Y */ + sp_256_mont_sqr_4(ctx->t2, ctx->y, p256_mod, p256_mp_mod); + ctx->state = 11; + break; + case 11: + /* T2 = T2/2 */ + sp_256_div2_4(ctx->t2, ctx->t2, p256_mod); + ctx->state = 12; + break; + case 12: + /* Y = Y * X */ + sp_256_mont_mul_4(ctx->y, ctx->y, p->x, p256_mod, p256_mp_mod); + ctx->state = 13; + break; + case 13: + /* X = T1 * T1 */ + sp_256_mont_sqr_4(ctx->x, ctx->t1, p256_mod, p256_mp_mod); + ctx->state = 14; + break; + case 14: + /* X = X - Y */ + sp_256_mont_sub_4(ctx->x, ctx->x, ctx->y, p256_mod); + ctx->state = 15; + break; + case 15: + /* X = X - Y */ + sp_256_mont_sub_4(ctx->x, ctx->x, ctx->y, p256_mod); + ctx->state = 16; + break; + case 16: + /* Y = Y - X */ + sp_256_mont_sub_4(ctx->y, ctx->y, ctx->x, p256_mod); + ctx->state = 17; + break; + case 17: + /* Y = Y * T1 */ + sp_256_mont_mul_4(ctx->y, ctx->y, ctx->t1, p256_mod, p256_mp_mod); + ctx->state = 18; + break; + case 18: + /* Y = Y - T2 */ + sp_256_mont_sub_4(ctx->y, ctx->y, ctx->t2, p256_mod); + ctx->state = 19; + /* fall-through */ + case 19: + err = MP_OKAY; + break; + } + + if (err == MP_OKAY && ctx->state != 19) { + err = FP_WOULDBLOCK; + } + + return err; +} +#endif /* WOLFSSL_SP_NONBLOCK */ + static void sp_256_proj_point_dbl_4(sp_point_256* r, const sp_point_256* p, sp_digit* t) { sp_digit* t1 = t; @@ -6723,6 +6858,209 @@ static int sp_256_cmp_equal_4(const sp_digit* a, const sp_digit* b) * q Second point to add. * t Temporary ordinate data. */ + +#ifdef WOLFSSL_SP_NONBLOCK +typedef struct sp_256_proj_point_add_4_ctx { + int state; + sp_256_proj_point_dbl_4_ctx dbl_ctx; + const sp_point_256* ap[2]; + sp_point_256* rp[2]; + sp_digit* t1; + sp_digit* t2; + sp_digit* t3; + sp_digit* t4; + sp_digit* t5; + sp_digit* x; + sp_digit* y; + sp_digit* z; +} sp_256_proj_point_add_4_ctx; + +static int sp_256_proj_point_add_4_nb(sp_ecc_ctx_t* sp_ctx, sp_point_256* r, + const sp_point_256* p, const sp_point_256* q, sp_digit* t) +{ + int err = FP_WOULDBLOCK; + sp_256_proj_point_add_4_ctx* ctx = (sp_256_proj_point_add_4_ctx*)sp_ctx->data; + + /* Ensure only the first point is the same as the result. */ + if (q == r) { + const sp_point_256* a = p; + p = q; + q = a; + } + + typedef char ctx_size_test[sizeof(sp_256_proj_point_add_4_ctx) >= sizeof(*sp_ctx) ? -1 : 1]; + (void)sizeof(ctx_size_test); + + switch (ctx->state) { + case 0: /* INIT */ + ctx->t1 = t; + ctx->t2 = t + 2*4; + ctx->t3 = t + 4*4; + ctx->t4 = t + 6*4; + ctx->t5 = t + 8*4; + + ctx->state = 1; + break; + case 1: + /* Check double */ + (void)sp_256_sub_4(ctx->t1, p256_mod, q->y); + sp_256_norm_4(ctx->t1); + if ((sp_256_cmp_equal_4(p->x, q->x) & sp_256_cmp_equal_4(p->z, q->z) & + (sp_256_cmp_equal_4(p->y, q->y) | sp_256_cmp_equal_4(p->y, ctx->t1))) != 0) + { + XMEMSET(&ctx->dbl_ctx, 0, sizeof(ctx->dbl_ctx)); + ctx->state = 2; + } + else { + ctx->state = 3; + } + break; + case 2: + err = sp_256_proj_point_dbl_4_nb((sp_ecc_ctx_t*)&ctx->dbl_ctx, r, p, t); + if (err == MP_OKAY) + ctx->state = 27; /* done */ + break; + case 3: + { + int i; + ctx->rp[0] = r; + + /*lint allow cast to different type of pointer*/ + ctx->rp[1] = (sp_point_256*)t; /*lint !e9087 !e740*/ + XMEMSET(ctx->rp[1], 0, sizeof(sp_point_256)); + ctx->x = ctx->rp[p->infinity | q->infinity]->x; + ctx->y = ctx->rp[p->infinity | q->infinity]->y; + ctx->z = ctx->rp[p->infinity | q->infinity]->z; + + ctx->ap[0] = p; + ctx->ap[1] = q; + for (i=0; i<4; i++) { + r->x[i] = ctx->ap[p->infinity]->x[i]; + } + for (i=0; i<4; i++) { + r->y[i] = ctx->ap[p->infinity]->y[i]; + } + for (i=0; i<4; i++) { + r->z[i] = ctx->ap[p->infinity]->z[i]; + } + r->infinity = ctx->ap[p->infinity]->infinity; + + ctx->state = 4; + break; + } + case 4: + /* U1 = X1*Z2^2 */ + sp_256_mont_sqr_4(ctx->t1, q->z, p256_mod, p256_mp_mod); + ctx->state = 5; + break; + case 5: + sp_256_mont_mul_4(ctx->t3, ctx->t1, q->z, p256_mod, p256_mp_mod); + ctx->state = 6; + break; + case 6: + sp_256_mont_mul_4(ctx->t1, ctx->t1, ctx->x, p256_mod, p256_mp_mod); + ctx->state = 7; + break; + case 7: + /* U2 = X2*Z1^2 */ + sp_256_mont_sqr_4(ctx->t2, ctx->z, p256_mod, p256_mp_mod); + ctx->state = 8; + break; + case 8: + sp_256_mont_mul_4(ctx->t4, ctx->t2, ctx->z, p256_mod, p256_mp_mod); + ctx->state = 9; + break; + case 9: + sp_256_mont_mul_4(ctx->t2, ctx->t2, q->x, p256_mod, p256_mp_mod); + ctx->state = 10; + break; + case 10: + /* S1 = Y1*Z2^3 */ + sp_256_mont_mul_4(ctx->t3, ctx->t3, ctx->y, p256_mod, p256_mp_mod); + ctx->state = 11; + break; + case 11: + /* S2 = Y2*Z1^3 */ + sp_256_mont_mul_4(ctx->t4, ctx->t4, q->y, p256_mod, p256_mp_mod); + ctx->state = 12; + break; + case 12: + /* H = U2 - U1 */ + sp_256_mont_sub_4(ctx->t2, ctx->t2, ctx->t1, p256_mod); + ctx->state = 13; + break; + case 13: + /* R = S2 - S1 */ + sp_256_mont_sub_4(ctx->t4, ctx->t4, ctx->t3, p256_mod); + ctx->state = 14; + break; + case 14: + /* Z3 = H*Z1*Z2 */ + sp_256_mont_mul_4(ctx->z, ctx->z, q->z, p256_mod, p256_mp_mod); + ctx->state = 15; + break; + case 15: + sp_256_mont_mul_4(ctx->z, ctx->z, ctx->t2, p256_mod, p256_mp_mod); + ctx->state = 16; + break; + case 16: + /* X3 = R^2 - H^3 - 2*U1*H^2 */ + sp_256_mont_sqr_4(ctx->x, ctx->t4, p256_mod, p256_mp_mod); + ctx->state = 17; + break; + case 17: + sp_256_mont_sqr_4(ctx->t5, ctx->t2, p256_mod, p256_mp_mod); + ctx->state = 18; + break; + case 18: + sp_256_mont_mul_4(ctx->y, ctx->t1, ctx->t5, p256_mod, p256_mp_mod); + ctx->state = 19; + break; + case 19: + sp_256_mont_mul_4(ctx->t5, ctx->t5, ctx->t2, p256_mod, p256_mp_mod); + ctx->state = 20; + break; + case 20: + sp_256_mont_sub_4(ctx->x, ctx->x, ctx->t5, p256_mod); + ctx->state = 21; + break; + case 21: + sp_256_mont_dbl_4(ctx->t1, ctx->y, p256_mod); + ctx->state = 22; + break; + case 22: + sp_256_mont_sub_4(ctx->x, ctx->x, ctx->t1, p256_mod); + ctx->state = 23; + break; + case 23: + /* Y3 = R*(U1*H^2 - X3) - S1*H^3 */ + sp_256_mont_sub_4(ctx->y, ctx->y, ctx->x, p256_mod); + ctx->state = 24; + break; + case 24: + sp_256_mont_mul_4(ctx->y, ctx->y, ctx->t4, p256_mod, p256_mp_mod); + ctx->state = 25; + break; + case 25: + sp_256_mont_mul_4(ctx->t5, ctx->t5, ctx->t3, p256_mod, p256_mp_mod); + ctx->state = 26; + break; + case 26: + sp_256_mont_sub_4(ctx->y, ctx->y, ctx->t5, p256_mod); + ctx->state = 27; + /* fall-through */ + case 27: + err = MP_OKAY; + break; + } + + if (err == MP_OKAY && ctx->state != 27) { + err = FP_WOULDBLOCK; + } + return err; +} +#endif /* WOLFSSL_SP_NONBLOCK */ + static void sp_256_proj_point_add_4(sp_point_256* r, const sp_point_256* p, const sp_point_256* q, sp_digit* t) { @@ -7286,6 +7624,141 @@ static void sp_256_map_avx2_4(sp_point_256* r, const sp_point_256* p, sp_digit* * p Point to double. * t Temporary ordinate data. */ +#ifdef WOLFSSL_SP_NONBLOCK +typedef struct sp_256_proj_point_dbl_avx2_4_ctx { + int state; + sp_digit* t1; + sp_digit* t2; + sp_digit* x; + sp_digit* y; + sp_digit* z; +} sp_256_proj_point_dbl_avx2_4_ctx; + +static int sp_256_proj_point_dbl_avx2_4_nb(sp_ecc_ctx_t* sp_ctx, sp_point_256* r, const sp_point_256* p, sp_digit* t) +{ + int err = FP_WOULDBLOCK; + sp_256_proj_point_dbl_avx2_4_ctx* ctx = (sp_256_proj_point_dbl_avx2_4_ctx*)sp_ctx->data; + + typedef char ctx_size_test[sizeof(sp_256_proj_point_dbl_avx2_4_ctx) >= sizeof(*sp_ctx) ? -1 : 1]; + (void)sizeof(ctx_size_test); + + switch (ctx->state) { + case 0: + ctx->t1 = t; + ctx->t2 = t + 2*4; + ctx->x = r->x; + ctx->y = r->y; + ctx->z = r->z; + + /* Put infinity into result. */ + if (r != p) { + r->infinity = p->infinity; + } + ctx->state = 1; + break; + case 1: + /* T1 = Z * Z */ + sp_256_mont_sqr_avx2_4(ctx->t1, p->z, p256_mod, p256_mp_mod); + ctx->state = 2; + break; + case 2: + /* Z = Y * Z */ + sp_256_mont_mul_avx2_4(ctx->z, p->y, p->z, p256_mod, p256_mp_mod); + ctx->state = 3; + break; + case 3: + /* Z = 2Z */ + sp_256_mont_dbl_avx2_4(ctx->z, ctx->z, p256_mod); + ctx->state = 4; + break; + case 4: + /* T2 = X - T1 */ + sp_256_mont_sub_avx2_4(ctx->t2, p->x, ctx->t1, p256_mod); + ctx->state = 5; + break; + case 5: + /* T1 = X + T1 */ + sp_256_mont_add_avx2_4(ctx->t1, p->x, ctx->t1, p256_mod); + ctx->state = 6; + break; + case 6: + /* T2 = T1 * T2 */ + sp_256_mont_mul_avx2_4(ctx->t2, ctx->t1, ctx->t2, p256_mod, p256_mp_mod); + ctx->state = 7; + break; + case 7: + /* T1 = 3T2 */ + sp_256_mont_tpl_avx2_4(ctx->t1, ctx->t2, p256_mod); + ctx->state = 8; + break; + case 8: + /* Y = 2Y */ + sp_256_mont_dbl_avx2_4(ctx->y, p->y, p256_mod); + ctx->state = 9; + break; + case 9: + /* Y = Y * Y */ + sp_256_mont_sqr_avx2_4(ctx->y, ctx->y, p256_mod, p256_mp_mod); + ctx->state = 10; + break; + case 10: + /* T2 = Y * Y */ + sp_256_mont_sqr_avx2_4(ctx->t2, ctx->y, p256_mod, p256_mp_mod); + ctx->state = 11; + break; + case 11: + /* T2 = T2/2 */ + sp_256_div2_avx2_4(ctx->t2, ctx->t2, p256_mod); + ctx->state = 12; + break; + case 12: + /* Y = Y * X */ + sp_256_mont_mul_avx2_4(ctx->y, ctx->y, p->x, p256_mod, p256_mp_mod); + ctx->state = 13; + break; + case 13: + /* X = T1 * T1 */ + sp_256_mont_sqr_avx2_4(ctx->x, ctx->t1, p256_mod, p256_mp_mod); + ctx->state = 14; + break; + case 14: + /* X = X - Y */ + sp_256_mont_sub_avx2_4(ctx->x, ctx->x, ctx->y, p256_mod); + ctx->state = 15; + break; + case 15: + /* X = X - Y */ + sp_256_mont_sub_avx2_4(ctx->x, ctx->x, ctx->y, p256_mod); + ctx->state = 16; + break; + case 16: + /* Y = Y - X */ + sp_256_mont_sub_avx2_4(ctx->y, ctx->y, ctx->x, p256_mod); + ctx->state = 17; + break; + case 17: + /* Y = Y * T1 */ + sp_256_mont_mul_avx2_4(ctx->y, ctx->y, ctx->t1, p256_mod, p256_mp_mod); + ctx->state = 18; + break; + case 18: + /* Y = Y - T2 */ + sp_256_mont_sub_avx2_4(ctx->y, ctx->y, ctx->t2, p256_mod); + ctx->state = 19; + /* fall-through */ + case 19: + err = MP_OKAY; + break; + } + + if (err == MP_OKAY && ctx->state != 19) { + err = FP_WOULDBLOCK; + } + + return err; +} +#endif /* WOLFSSL_SP_NONBLOCK */ + static void sp_256_proj_point_dbl_avx2_4(sp_point_256* r, const sp_point_256* p, sp_digit* t) { sp_digit* t1 = t; @@ -7435,6 +7908,209 @@ static void sp_256_proj_point_dbl_n_avx2_4(sp_point_256* p, int n, sp_digit* t) * q Second point to add. * t Temporary ordinate data. */ + +#ifdef WOLFSSL_SP_NONBLOCK +typedef struct sp_256_proj_point_add_avx2_4_ctx { + int state; + sp_256_proj_point_dbl_avx2_4_ctx dbl_ctx; + const sp_point_256* ap[2]; + sp_point_256* rp[2]; + sp_digit* t1; + sp_digit* t2; + sp_digit* t3; + sp_digit* t4; + sp_digit* t5; + sp_digit* x; + sp_digit* y; + sp_digit* z; +} sp_256_proj_point_add_avx2_4_ctx; + +static int sp_256_proj_point_add_avx2_4_nb(sp_ecc_ctx_t* sp_ctx, sp_point_256* r, + const sp_point_256* p, const sp_point_256* q, sp_digit* t) +{ + int err = FP_WOULDBLOCK; + sp_256_proj_point_add_avx2_4_ctx* ctx = (sp_256_proj_point_add_avx2_4_ctx*)sp_ctx->data; + + /* Ensure only the first point is the same as the result. */ + if (q == r) { + const sp_point_256* a = p; + p = q; + q = a; + } + + typedef char ctx_size_test[sizeof(sp_256_proj_point_add_avx2_4_ctx) >= sizeof(*sp_ctx) ? -1 : 1]; + (void)sizeof(ctx_size_test); + + switch (ctx->state) { + case 0: /* INIT */ + ctx->t1 = t; + ctx->t2 = t + 2*4; + ctx->t3 = t + 4*4; + ctx->t4 = t + 6*4; + ctx->t5 = t + 8*4; + + ctx->state = 1; + break; + case 1: + /* Check double */ + (void)sp_256_sub_avx2_4(ctx->t1, p256_mod, q->y); + sp_256_norm_avx2_4(ctx->t1); + if ((sp_256_cmp_equal_avx2_4(p->x, q->x) & sp_256_cmp_equal_avx2_4(p->z, q->z) & + (sp_256_cmp_equal_avx2_4(p->y, q->y) | sp_256_cmp_equal_avx2_4(p->y, ctx->t1))) != 0) + { + XMEMSET(&ctx->dbl_ctx, 0, sizeof(ctx->dbl_ctx)); + ctx->state = 2; + } + else { + ctx->state = 3; + } + break; + case 2: + err = sp_256_proj_point_dbl_avx2_4_nb((sp_ecc_ctx_t*)&ctx->dbl_ctx, r, p, t); + if (err == MP_OKAY) + ctx->state = 27; /* done */ + break; + case 3: + { + int i; + ctx->rp[0] = r; + + /*lint allow cast to different type of pointer*/ + ctx->rp[1] = (sp_point_256*)t; /*lint !e9087 !e740*/ + XMEMSET(ctx->rp[1], 0, sizeof(sp_point_256)); + ctx->x = ctx->rp[p->infinity | q->infinity]->x; + ctx->y = ctx->rp[p->infinity | q->infinity]->y; + ctx->z = ctx->rp[p->infinity | q->infinity]->z; + + ctx->ap[0] = p; + ctx->ap[1] = q; + for (i=0; i<4; i++) { + r->x[i] = ctx->ap[p->infinity]->x[i]; + } + for (i=0; i<4; i++) { + r->y[i] = ctx->ap[p->infinity]->y[i]; + } + for (i=0; i<4; i++) { + r->z[i] = ctx->ap[p->infinity]->z[i]; + } + r->infinity = ctx->ap[p->infinity]->infinity; + + ctx->state = 4; + break; + } + case 4: + /* U1 = X1*Z2^2 */ + sp_256_mont_sqr_avx2_4(ctx->t1, q->z, p256_mod, p256_mp_mod); + ctx->state = 5; + break; + case 5: + sp_256_mont_mul_avx2_4(ctx->t3, ctx->t1, q->z, p256_mod, p256_mp_mod); + ctx->state = 6; + break; + case 6: + sp_256_mont_mul_avx2_4(ctx->t1, ctx->t1, ctx->x, p256_mod, p256_mp_mod); + ctx->state = 7; + break; + case 7: + /* U2 = X2*Z1^2 */ + sp_256_mont_sqr_avx2_4(ctx->t2, ctx->z, p256_mod, p256_mp_mod); + ctx->state = 8; + break; + case 8: + sp_256_mont_mul_avx2_4(ctx->t4, ctx->t2, ctx->z, p256_mod, p256_mp_mod); + ctx->state = 9; + break; + case 9: + sp_256_mont_mul_avx2_4(ctx->t2, ctx->t2, q->x, p256_mod, p256_mp_mod); + ctx->state = 10; + break; + case 10: + /* S1 = Y1*Z2^3 */ + sp_256_mont_mul_avx2_4(ctx->t3, ctx->t3, ctx->y, p256_mod, p256_mp_mod); + ctx->state = 11; + break; + case 11: + /* S2 = Y2*Z1^3 */ + sp_256_mont_mul_avx2_4(ctx->t4, ctx->t4, q->y, p256_mod, p256_mp_mod); + ctx->state = 12; + break; + case 12: + /* H = U2 - U1 */ + sp_256_mont_sub_avx2_4(ctx->t2, ctx->t2, ctx->t1, p256_mod); + ctx->state = 13; + break; + case 13: + /* R = S2 - S1 */ + sp_256_mont_sub_avx2_4(ctx->t4, ctx->t4, ctx->t3, p256_mod); + ctx->state = 14; + break; + case 14: + /* Z3 = H*Z1*Z2 */ + sp_256_mont_mul_avx2_4(ctx->z, ctx->z, q->z, p256_mod, p256_mp_mod); + ctx->state = 15; + break; + case 15: + sp_256_mont_mul_avx2_4(ctx->z, ctx->z, ctx->t2, p256_mod, p256_mp_mod); + ctx->state = 16; + break; + case 16: + /* X3 = R^2 - H^3 - 2*U1*H^2 */ + sp_256_mont_sqr_avx2_4(ctx->x, ctx->t4, p256_mod, p256_mp_mod); + ctx->state = 17; + break; + case 17: + sp_256_mont_sqr_avx2_4(ctx->t5, ctx->t2, p256_mod, p256_mp_mod); + ctx->state = 18; + break; + case 18: + sp_256_mont_mul_avx2_4(ctx->y, ctx->t1, ctx->t5, p256_mod, p256_mp_mod); + ctx->state = 19; + break; + case 19: + sp_256_mont_mul_avx2_4(ctx->t5, ctx->t5, ctx->t2, p256_mod, p256_mp_mod); + ctx->state = 20; + break; + case 20: + sp_256_mont_sub_avx2_4(ctx->x, ctx->x, ctx->t5, p256_mod); + ctx->state = 21; + break; + case 21: + sp_256_mont_dbl_avx2_4(ctx->t1, ctx->y, p256_mod); + ctx->state = 22; + break; + case 22: + sp_256_mont_sub_avx2_4(ctx->x, ctx->x, ctx->t1, p256_mod); + ctx->state = 23; + break; + case 23: + /* Y3 = R*(U1*H^2 - X3) - S1*H^3 */ + sp_256_mont_sub_avx2_4(ctx->y, ctx->y, ctx->x, p256_mod); + ctx->state = 24; + break; + case 24: + sp_256_mont_mul_avx2_4(ctx->y, ctx->y, ctx->t4, p256_mod, p256_mp_mod); + ctx->state = 25; + break; + case 25: + sp_256_mont_mul_avx2_4(ctx->t5, ctx->t5, ctx->t3, p256_mod, p256_mp_mod); + ctx->state = 26; + break; + case 26: + sp_256_mont_sub_avx2_4(ctx->y, ctx->y, ctx->t5, p256_mod); + ctx->state = 27; + /* fall-through */ + case 27: + err = MP_OKAY; + break; + } + + if (err == MP_OKAY && ctx->state != 27) { + err = FP_WOULDBLOCK; + } + return err; +} +#endif /* WOLFSSL_SP_NONBLOCK */ + static void sp_256_proj_point_add_avx2_4(sp_point_256* r, const sp_point_256* p, const sp_point_256* q, sp_digit* t) { @@ -22626,6 +23302,46 @@ static void sp_256_mont_sqr_n_order_4(sp_digit* r, const sp_digit* a, int n) * a Number to invert. * td Temporary data. */ + +#ifdef WOLFSSL_SP_NONBLOCK +typedef struct sp_256_mont_inv_order_4_ctx { + int state; + int i; +} sp_256_mont_inv_order_4_ctx; +static int sp_256_mont_inv_order_4_nb(sp_ecc_ctx_t* sp_ctx, sp_digit* r, const sp_digit* a, + sp_digit* t) +{ + int err = FP_WOULDBLOCK; + sp_256_mont_inv_order_4_ctx* ctx = (sp_256_mont_inv_order_4_ctx*)sp_ctx; + + typedef char ctx_size_test[sizeof(sp_256_mont_inv_order_4_ctx) >= sizeof(*sp_ctx) ? -1 : 1]; + (void)sizeof(ctx_size_test); + + switch (ctx->state) { + case 0: + XMEMCPY(t, a, sizeof(sp_digit) * 4); + ctx->i = 254; + ctx->state = 1; + break; + case 1: + sp_256_mont_sqr_order_4(t, t); + if ((p256_order_minus_2[ctx->i / 64] & ((sp_int_digit)1 << (ctx->i % 64))) != 0) { + sp_256_mont_mul_order_4(t, t, a); + } + ctx->i--; + if (ctx->i == 0) { + ctx->state = 2; + } + break; + case 2: + XMEMCPY(r, t, sizeof(sp_digit) * 4U); + err = MP_OKAY; + break; + } + return err; +} +#endif /* WOLFSSL_SP_NONBLOCK */ + static void sp_256_mont_inv_order_4(sp_digit* r, const sp_digit* a, sp_digit* td) { @@ -22772,6 +23488,46 @@ static void sp_256_mont_sqr_n_order_avx2_4(sp_digit* r, const sp_digit* a, int n * a Number to invert. * td Temporary data. */ + +#ifdef WOLFSSL_SP_NONBLOCK +typedef struct sp_256_mont_inv_order_avx2_4_ctx { + int state; + int i; +} sp_256_mont_inv_order_avx2_4_ctx; +static int sp_256_mont_inv_order_avx2_4_nb(sp_ecc_ctx_t* sp_ctx, sp_digit* r, const sp_digit* a, + sp_digit* t) +{ + int err = FP_WOULDBLOCK; + sp_256_mont_inv_order_avx2_4_ctx* ctx = (sp_256_mont_inv_order_avx2_4_ctx*)sp_ctx; + + typedef char ctx_size_test[sizeof(sp_256_mont_inv_order_avx2_4_ctx) >= sizeof(*sp_ctx) ? -1 : 1]; + (void)sizeof(ctx_size_test); + + switch (ctx->state) { + case 0: + XMEMCPY(t, a, sizeof(sp_digit) * 4); + ctx->i = 254; + ctx->state = 1; + break; + case 1: + sp_256_mont_sqr_order_avx2_4(t, t); + if ((p256_order_minus_2[ctx->i / 64] & ((sp_int_digit)1 << (ctx->i % 64))) != 0) { + sp_256_mont_mul_order_avx2_4(t, t, a); + } + ctx->i--; + if (ctx->i == 0) { + ctx->state = 2; + } + break; + case 2: + XMEMCPY(r, t, sizeof(sp_digit) * 4U); + err = MP_OKAY; + break; + } + return err; +} +#endif /* WOLFSSL_SP_NONBLOCK */ + static void sp_256_mont_inv_order_avx2_4(sp_digit* r, const sp_digit* a, sp_digit* td) { @@ -22888,6 +23644,165 @@ static void sp_256_mont_inv_order_avx2_4(sp_digit* r, const sp_digit* a, * returns RNG failures, MEMORY_E when memory allocation fails and * MP_OKAY on success. */ +#ifdef WOLFSSL_SP_NONBLOCK +typedef struct sp_ecc_sign_256_ctx { + int state; + union { + sp_256_ecc_mulmod_4_ctx mulmod_ctx; + sp_256_mont_inv_order_4_ctx mont_inv_order_ctx; + }; + sp_digit e[2*4]; + sp_digit x[2*4]; + sp_digit k[2*4]; + sp_digit r[2*4]; + sp_digit tmp[3 * 2*4]; + sp_point_256 point; + sp_digit* s; + sp_digit* kInv; + int i; +} sp_ecc_sign_256_ctx; + +int sp_ecc_sign_256_nb(sp_ecc_ctx_t* sp_ctx, const byte* hash, word32 hashLen, WC_RNG* rng, mp_int* priv, + mp_int* rm, mp_int* sm, mp_int* km, void* heap) +{ + int err = FP_WOULDBLOCK; + sp_ecc_sign_256_ctx* ctx = (sp_ecc_sign_256_ctx*)sp_ctx->data; + + typedef char ctx_size_test[sizeof(sp_ecc_sign_256_ctx) >= sizeof(*sp_ctx) ? -1 : 1]; + (void)sizeof(ctx_size_test); + + (void)heap; + + switch (ctx->state) { + case 0: /* INIT */ + ctx->s = ctx->e; + ctx->kInv = ctx->k; + if (hashLen > 32U) { + hashLen = 32U; + } + + sp_256_from_bin(ctx->e, 4, hash, (int)hashLen); + + ctx->i = SP_ECC_MAX_SIG_GEN; + ctx->state = 1; + break; + case 1: /* GEN */ + sp_256_from_mp(ctx->x, 4, priv); + /* New random point. */ + if (km == NULL || mp_iszero(km)) { + err = sp_256_ecc_gen_k_4(rng, ctx->k); + } + else { + sp_256_from_mp(ctx->k, 4, km); + mp_zero(km); + } + XMEMSET(&ctx->mulmod_ctx, 0, sizeof(ctx->mulmod_ctx)); + ctx->state = 2; + break; + case 2: /* MULMOD */ + err = sp_256_ecc_mulmod_4_nb((sp_ecc_ctx_t*)&ctx->mulmod_ctx, + &ctx->point, &p256_base, ctx->k, 1, heap); + if (err == MP_OKAY) { + ctx->state = 3; + } + break; + case 3: /* MODORDER */ + { + int64_t c; + /* r = point->x mod order */ + XMEMCPY(ctx->r, ctx->point.x, sizeof(sp_digit) * 4U); + sp_256_norm_4(ctx->r); + c = sp_256_cmp_4(ctx->r, p256_order); + sp_256_cond_sub_4(ctx->r, ctx->r, p256_order, 0L - (sp_digit)(c >= 0)); + sp_256_norm_4(ctx->r); + ctx->state = 4; + break; + } + case 4: /* KMODORDER */ + /* Conv k to Montgomery form (mod order) */ + sp_256_mul_4(ctx->k, ctx->k, p256_norm_order); + err = sp_256_mod_4(ctx->k, ctx->k, p256_order); + if (err == MP_OKAY) { + sp_256_norm_4(ctx->k); + XMEMSET(&ctx->mont_inv_order_ctx, 0, sizeof(ctx->mont_inv_order_ctx)); + ctx->state = 5; + } + break; + case 5: /* KINV */ + /* kInv = 1/k mod order */ + err = sp_256_mont_inv_order_4_nb((sp_ecc_ctx_t*)&ctx->mont_inv_order_ctx, ctx->kInv, ctx->k, ctx->tmp); + if (err == MP_OKAY) { + XMEMSET(&ctx->mont_inv_order_ctx, 0, sizeof(ctx->mont_inv_order_ctx)); + ctx->state = 6; + } + break; + case 6: /* KINVNORM */ + sp_256_norm_4(ctx->kInv); + ctx->state = 7; + break; + case 7: /* R */ + /* s = r * x + e */ + sp_256_mul_4(ctx->x, ctx->x, ctx->r); + ctx->state = 8; + break; + case 8: /* S1 */ + err = sp_256_mod_4(ctx->x, ctx->x, p256_order); + if (err == MP_OKAY) + ctx->state = 9; + break; + case 9: /* S2 */ + { + sp_digit carry; + int64_t c; + sp_256_norm_4(ctx->x); + carry = sp_256_add_4(ctx->s, ctx->e, ctx->x); + sp_256_cond_sub_4(ctx->s, ctx->s, p256_order, 0 - carry); + sp_256_norm_4(ctx->s); + c = sp_256_cmp_4(ctx->s, p256_order); + sp_256_cond_sub_4(ctx->s, ctx->s, p256_order, 0L - (sp_digit)(c >= 0)); + sp_256_norm_4(ctx->s); + + /* s = s * k^-1 mod order */ + sp_256_mont_mul_order_4(ctx->s, ctx->s, ctx->kInv); + sp_256_norm_4(ctx->s); + + /* Check that signature is usable. */ + if (sp_256_iszero_4(ctx->s) == 0) { + ctx->state = 10; + break; + } + + /* not usable gen, try again */ + ctx->i--; + if (ctx->i == 0) { + err = RNG_FAILURE_E; + } + ctx->state = 1; + break; + } + case 10: /* RES */ + err = sp_256_to_mp(ctx->r, rm); + if (err == MP_OKAY) { + err = sp_256_to_mp(ctx->s, sm); + } + break; + } + + if (err == MP_OKAY && ctx->state != 10) { + err = FP_WOULDBLOCK; + } + if (err != FP_WOULDBLOCK) { + XMEMSET(ctx->e, 0, sizeof(sp_digit) * 2U * 4U); + XMEMSET(ctx->x, 0, sizeof(sp_digit) * 2U * 4U); + XMEMSET(ctx->k, 0, sizeof(sp_digit) * 2U * 4U); + XMEMSET(ctx->r, 0, sizeof(sp_digit) * 2U * 4U); + XMEMSET(ctx->tmp, 0, sizeof(sp_digit) * 3U * 2U * 4U); + } + + return err; +} +#endif /* WOLFSSL_SP_NONBLOCK */ + int sp_ecc_sign_256(const byte* hash, word32 hashLen, WC_RNG* rng, mp_int* priv, mp_int* rm, mp_int* sm, mp_int* km, void* heap) { @@ -23087,6 +24002,169 @@ int sp_ecc_sign_256(const byte* hash, word32 hashLen, WC_RNG* rng, mp_int* priv, * returns RNG failures, MEMORY_E when memory allocation fails and * MP_OKAY on success. */ +#ifdef WOLFSSL_SP_NONBLOCK +typedef struct sp_ecc_verify_256_ctx { + int state; + union { + sp_256_ecc_mulmod_4_ctx mulmod_ctx; + sp_256_mont_inv_order_4_ctx mont_inv_order_ctx; + sp_256_proj_point_dbl_4_ctx dbl_ctx; + sp_256_proj_point_add_4_ctx add_ctx; + }; + sp_digit u1[2*4]; + sp_digit u2[2*4]; + sp_digit s[2*4]; + sp_digit tmp[2*4 * 5]; + sp_point_256 p1; + sp_point_256 p2; +} sp_ecc_verify_256_ctx; + +int sp_ecc_verify_256_nb(sp_ecc_ctx_t* sp_ctx, const byte* hash, word32 hashLen, mp_int* pX, + mp_int* pY, mp_int* pZ, mp_int* r, mp_int* sm, int* res, void* heap) +{ + int err = FP_WOULDBLOCK; + sp_ecc_verify_256_ctx* ctx = (sp_ecc_verify_256_ctx*)sp_ctx->data; + + typedef char ctx_size_test[sizeof(sp_ecc_verify_256_ctx) >= sizeof(*sp_ctx) ? -1 : 1]; + (void)sizeof(ctx_size_test); + + switch (ctx->state) { + case 0: /* INIT */ + if (hashLen > 32U) { + hashLen = 32U; + } + + sp_256_from_bin(ctx->u1, 4, hash, (int)hashLen); + sp_256_from_mp(ctx->u2, 4, r); + sp_256_from_mp(ctx->s, 4, sm); + sp_256_from_mp(ctx->p2.x, 4, pX); + sp_256_from_mp(ctx->p2.y, 4, pY); + sp_256_from_mp(ctx->p2.z, 4, pZ); + sp_256_mul_4(ctx->s, ctx->s, p256_norm_order); + err = sp_256_mod_4(ctx->s, ctx->s, p256_order); + if (err == MP_OKAY) + ctx->state = 1; + break; + case 1: /* NORMS1 */ + sp_256_norm_4(ctx->s); + XMEMSET(&ctx->mont_inv_order_ctx, 0, sizeof(ctx->mont_inv_order_ctx)); + ctx->state = 2; + break; + case 2: /* NORMS2 */ + err = sp_256_mont_inv_order_4_nb((sp_ecc_ctx_t*)&ctx->mont_inv_order_ctx, ctx->s, ctx->s, ctx->tmp); + if (err == MP_OKAY) { + ctx->state = 3; + } + break; + case 3: /* NORMS3 */ + sp_256_mont_mul_order_4(ctx->u1, ctx->u1, ctx->s); + ctx->state = 4; + break; + case 4: /* NORMS4 */ + sp_256_mont_mul_order_4(ctx->u2, ctx->u2, ctx->s); + XMEMSET(&ctx->mulmod_ctx, 0, sizeof(ctx->mulmod_ctx)); + ctx->state = 5; + break; + case 5: /* MULBASE */ + err = sp_256_ecc_mulmod_4_nb((sp_ecc_ctx_t*)&ctx->mulmod_ctx, &ctx->p1, &p256_base, ctx->u1, 0, heap); + if (err == MP_OKAY) { + XMEMSET(&ctx->mulmod_ctx, 0, sizeof(ctx->mulmod_ctx)); + ctx->state = 6; + } + break; + case 6: /* MULMOD */ + err = sp_256_ecc_mulmod_4_nb((sp_ecc_ctx_t*)&ctx->mulmod_ctx, &ctx->p2, &ctx->p2, ctx->u2, 0, heap); + if (err == MP_OKAY) { + XMEMSET(&ctx->add_ctx, 0, sizeof(ctx->add_ctx)); + ctx->state = 7; + } + break; + case 7: /* ADD */ + err = sp_256_proj_point_add_4_nb((sp_ecc_ctx_t*)&ctx->add_ctx, &ctx->p1, &ctx->p1, &ctx->p2, ctx->tmp); + if (err == MP_OKAY) + ctx->state = 8; + break; + case 8: /* DBLPREP */ + if (sp_256_iszero_4(ctx->p1.z)) { + if (sp_256_iszero_4(ctx->p1.x) && sp_256_iszero_4(ctx->p1.y)) { + XMEMSET(&ctx->dbl_ctx, 0, sizeof(ctx->dbl_ctx)); + ctx->state = 9; + break; + } + else { + /* Y ordinate is not used from here - don't set. */ + int i; + for (i=0; i<4; i++) { + ctx->p1.x[i] = 0; + } + XMEMCPY(ctx->p1.z, p256_norm_mod, sizeof(p256_norm_mod)); + } + } + ctx->state = 10; + break; + case 9: /* DBL */ + err = sp_256_proj_point_dbl_4_nb((sp_ecc_ctx_t*)&ctx->dbl_ctx, &ctx->p1, + &ctx->p2, ctx->tmp); + if (err == MP_OKAY) { + ctx->state = 10; + } + break; + case 10: /* MONT */ + /* (r + n*order).z'.z' mod prime == (u1.G + u2.Q)->x' */ + /* Reload r and convert to Montgomery form. */ + sp_256_from_mp(ctx->u2, 4, r); + err = sp_256_mod_mul_norm_4(ctx->u2, ctx->u2, p256_mod); + if (err == MP_OKAY) + ctx->state = 11; + break; + case 11: /* SQR */ + /* u1 = r.z'.z' mod prime */ + sp_256_mont_sqr_4(ctx->p1.z, ctx->p1.z, p256_mod, p256_mp_mod); + ctx->state = 12; + break; + case 12: /* MUL */ + sp_256_mont_mul_4(ctx->u1, ctx->u2, ctx->p1.z, p256_mod, p256_mp_mod); + ctx->state = 13; + break; + case 13: /* RES */ + err = MP_OKAY; /* math okay, now check result */ + *res = (int)(sp_256_cmp_4(ctx->p1.x, ctx->u1) == 0); + if (*res == 0) { + sp_digit carry; + int64_t c; + + /* Reload r and add order. */ + sp_256_from_mp(ctx->u2, 4, r); + carry = sp_256_add_4(ctx->u2, ctx->u2, p256_order); + /* Carry means result is greater than mod and is not valid. */ + if (carry == 0) { + sp_256_norm_4(ctx->u2); + + /* Compare with mod and if greater or equal then not valid. */ + c = sp_256_cmp_4(ctx->u2, p256_mod); + if (c < 0) { + /* Convert to Montogomery form */ + err = sp_256_mod_mul_norm_4(ctx->u2, ctx->u2, p256_mod); + if (err == MP_OKAY) { + /* u1 = (r + 1*order).z'.z' mod prime */ + sp_256_mont_mul_4(ctx->u1, ctx->u2, ctx->p1.z, p256_mod, + p256_mp_mod); + *res = (int)(sp_256_cmp_4(ctx->p1.x, ctx->u1) == 0); + } + } + } + } + break; + } + + if (err == MP_OKAY && ctx->state != 13) { + err = FP_WOULDBLOCK; + } + + return err; +} +#endif /* WOLFSSL_SP_NONBLOCK */ + int sp_ecc_verify_256(const byte* hash, word32 hashLen, mp_int* pX, mp_int* pY, mp_int* pZ, mp_int* r, mp_int* sm, int* res, void* heap) { @@ -24596,6 +25674,141 @@ extern void sp_384_div2_6(sp_digit* r, const sp_digit* a, const sp_digit* m); * p Point to double. * t Temporary ordinate data. */ +#ifdef WOLFSSL_SP_NONBLOCK +typedef struct sp_384_proj_point_dbl_6_ctx { + int state; + sp_digit* t1; + sp_digit* t2; + sp_digit* x; + sp_digit* y; + sp_digit* z; +} sp_384_proj_point_dbl_6_ctx; + +static int sp_384_proj_point_dbl_6_nb(sp_ecc_ctx_t* sp_ctx, sp_point_384* r, const sp_point_384* p, sp_digit* t) +{ + int err = FP_WOULDBLOCK; + sp_384_proj_point_dbl_6_ctx* ctx = (sp_384_proj_point_dbl_6_ctx*)sp_ctx->data; + + typedef char ctx_size_test[sizeof(sp_384_proj_point_dbl_6_ctx) >= sizeof(*sp_ctx) ? -1 : 1]; + (void)sizeof(ctx_size_test); + + switch (ctx->state) { + case 0: + ctx->t1 = t; + ctx->t2 = t + 2*6; + ctx->x = r->x; + ctx->y = r->y; + ctx->z = r->z; + + /* Put infinity into result. */ + if (r != p) { + r->infinity = p->infinity; + } + ctx->state = 1; + break; + case 1: + /* T1 = Z * Z */ + sp_384_mont_sqr_6(ctx->t1, p->z, p384_mod, p384_mp_mod); + ctx->state = 2; + break; + case 2: + /* Z = Y * Z */ + sp_384_mont_mul_6(ctx->z, p->y, p->z, p384_mod, p384_mp_mod); + ctx->state = 3; + break; + case 3: + /* Z = 2Z */ + sp_384_mont_dbl_6(ctx->z, ctx->z, p384_mod); + ctx->state = 4; + break; + case 4: + /* T2 = X - T1 */ + sp_384_mont_sub_6(ctx->t2, p->x, ctx->t1, p384_mod); + ctx->state = 5; + break; + case 5: + /* T1 = X + T1 */ + sp_384_mont_add_6(ctx->t1, p->x, ctx->t1, p384_mod); + ctx->state = 6; + break; + case 6: + /* T2 = T1 * T2 */ + sp_384_mont_mul_6(ctx->t2, ctx->t1, ctx->t2, p384_mod, p384_mp_mod); + ctx->state = 7; + break; + case 7: + /* T1 = 3T2 */ + sp_384_mont_tpl_6(ctx->t1, ctx->t2, p384_mod); + ctx->state = 8; + break; + case 8: + /* Y = 2Y */ + sp_384_mont_dbl_6(ctx->y, p->y, p384_mod); + ctx->state = 9; + break; + case 9: + /* Y = Y * Y */ + sp_384_mont_sqr_6(ctx->y, ctx->y, p384_mod, p384_mp_mod); + ctx->state = 10; + break; + case 10: + /* T2 = Y * Y */ + sp_384_mont_sqr_6(ctx->t2, ctx->y, p384_mod, p384_mp_mod); + ctx->state = 11; + break; + case 11: + /* T2 = T2/2 */ + sp_384_div2_6(ctx->t2, ctx->t2, p384_mod); + ctx->state = 12; + break; + case 12: + /* Y = Y * X */ + sp_384_mont_mul_6(ctx->y, ctx->y, p->x, p384_mod, p384_mp_mod); + ctx->state = 13; + break; + case 13: + /* X = T1 * T1 */ + sp_384_mont_sqr_6(ctx->x, ctx->t1, p384_mod, p384_mp_mod); + ctx->state = 14; + break; + case 14: + /* X = X - Y */ + sp_384_mont_sub_6(ctx->x, ctx->x, ctx->y, p384_mod); + ctx->state = 15; + break; + case 15: + /* X = X - Y */ + sp_384_mont_sub_6(ctx->x, ctx->x, ctx->y, p384_mod); + ctx->state = 16; + break; + case 16: + /* Y = Y - X */ + sp_384_mont_sub_6(ctx->y, ctx->y, ctx->x, p384_mod); + ctx->state = 17; + break; + case 17: + /* Y = Y * T1 */ + sp_384_mont_mul_6(ctx->y, ctx->y, ctx->t1, p384_mod, p384_mp_mod); + ctx->state = 18; + break; + case 18: + /* Y = Y - T2 */ + sp_384_mont_sub_6(ctx->y, ctx->y, ctx->t2, p384_mod); + ctx->state = 19; + /* fall-through */ + case 19: + err = MP_OKAY; + break; + } + + if (err == MP_OKAY && ctx->state != 19) { + err = FP_WOULDBLOCK; + } + + return err; +} +#endif /* WOLFSSL_SP_NONBLOCK */ + static void sp_384_proj_point_dbl_6(sp_point_384* r, const sp_point_384* p, sp_digit* t) { sp_digit* t1 = t; @@ -24758,6 +25971,209 @@ static int sp_384_cmp_equal_6(const sp_digit* a, const sp_digit* b) * q Second point to add. * t Temporary ordinate data. */ + +#ifdef WOLFSSL_SP_NONBLOCK +typedef struct sp_384_proj_point_add_6_ctx { + int state; + sp_384_proj_point_dbl_6_ctx dbl_ctx; + const sp_point_384* ap[2]; + sp_point_384* rp[2]; + sp_digit* t1; + sp_digit* t2; + sp_digit* t3; + sp_digit* t4; + sp_digit* t5; + sp_digit* x; + sp_digit* y; + sp_digit* z; +} sp_384_proj_point_add_6_ctx; + +static int sp_384_proj_point_add_6_nb(sp_ecc_ctx_t* sp_ctx, sp_point_384* r, + const sp_point_384* p, const sp_point_384* q, sp_digit* t) +{ + int err = FP_WOULDBLOCK; + sp_384_proj_point_add_6_ctx* ctx = (sp_384_proj_point_add_6_ctx*)sp_ctx->data; + + /* Ensure only the first point is the same as the result. */ + if (q == r) { + const sp_point_384* a = p; + p = q; + q = a; + } + + typedef char ctx_size_test[sizeof(sp_384_proj_point_add_6_ctx) >= sizeof(*sp_ctx) ? -1 : 1]; + (void)sizeof(ctx_size_test); + + switch (ctx->state) { + case 0: /* INIT */ + ctx->t1 = t; + ctx->t2 = t + 2*6; + ctx->t3 = t + 4*6; + ctx->t4 = t + 6*6; + ctx->t5 = t + 8*6; + + ctx->state = 1; + break; + case 1: + /* Check double */ + (void)sp_384_sub_6(ctx->t1, p384_mod, q->y); + sp_384_norm_6(ctx->t1); + if ((sp_384_cmp_equal_6(p->x, q->x) & sp_384_cmp_equal_6(p->z, q->z) & + (sp_384_cmp_equal_6(p->y, q->y) | sp_384_cmp_equal_6(p->y, ctx->t1))) != 0) + { + XMEMSET(&ctx->dbl_ctx, 0, sizeof(ctx->dbl_ctx)); + ctx->state = 2; + } + else { + ctx->state = 3; + } + break; + case 2: + err = sp_384_proj_point_dbl_6_nb((sp_ecc_ctx_t*)&ctx->dbl_ctx, r, p, t); + if (err == MP_OKAY) + ctx->state = 27; /* done */ + break; + case 3: + { + int i; + ctx->rp[0] = r; + + /*lint allow cast to different type of pointer*/ + ctx->rp[1] = (sp_point_384*)t; /*lint !e9087 !e740*/ + XMEMSET(ctx->rp[1], 0, sizeof(sp_point_384)); + ctx->x = ctx->rp[p->infinity | q->infinity]->x; + ctx->y = ctx->rp[p->infinity | q->infinity]->y; + ctx->z = ctx->rp[p->infinity | q->infinity]->z; + + ctx->ap[0] = p; + ctx->ap[1] = q; + for (i=0; i<6; i++) { + r->x[i] = ctx->ap[p->infinity]->x[i]; + } + for (i=0; i<6; i++) { + r->y[i] = ctx->ap[p->infinity]->y[i]; + } + for (i=0; i<6; i++) { + r->z[i] = ctx->ap[p->infinity]->z[i]; + } + r->infinity = ctx->ap[p->infinity]->infinity; + + ctx->state = 4; + break; + } + case 4: + /* U1 = X1*Z2^2 */ + sp_384_mont_sqr_6(ctx->t1, q->z, p384_mod, p384_mp_mod); + ctx->state = 5; + break; + case 5: + sp_384_mont_mul_6(ctx->t3, ctx->t1, q->z, p384_mod, p384_mp_mod); + ctx->state = 6; + break; + case 6: + sp_384_mont_mul_6(ctx->t1, ctx->t1, ctx->x, p384_mod, p384_mp_mod); + ctx->state = 7; + break; + case 7: + /* U2 = X2*Z1^2 */ + sp_384_mont_sqr_6(ctx->t2, ctx->z, p384_mod, p384_mp_mod); + ctx->state = 8; + break; + case 8: + sp_384_mont_mul_6(ctx->t4, ctx->t2, ctx->z, p384_mod, p384_mp_mod); + ctx->state = 9; + break; + case 9: + sp_384_mont_mul_6(ctx->t2, ctx->t2, q->x, p384_mod, p384_mp_mod); + ctx->state = 10; + break; + case 10: + /* S1 = Y1*Z2^3 */ + sp_384_mont_mul_6(ctx->t3, ctx->t3, ctx->y, p384_mod, p384_mp_mod); + ctx->state = 11; + break; + case 11: + /* S2 = Y2*Z1^3 */ + sp_384_mont_mul_6(ctx->t4, ctx->t4, q->y, p384_mod, p384_mp_mod); + ctx->state = 12; + break; + case 12: + /* H = U2 - U1 */ + sp_384_mont_sub_6(ctx->t2, ctx->t2, ctx->t1, p384_mod); + ctx->state = 13; + break; + case 13: + /* R = S2 - S1 */ + sp_384_mont_sub_6(ctx->t4, ctx->t4, ctx->t3, p384_mod); + ctx->state = 14; + break; + case 14: + /* Z3 = H*Z1*Z2 */ + sp_384_mont_mul_6(ctx->z, ctx->z, q->z, p384_mod, p384_mp_mod); + ctx->state = 15; + break; + case 15: + sp_384_mont_mul_6(ctx->z, ctx->z, ctx->t2, p384_mod, p384_mp_mod); + ctx->state = 16; + break; + case 16: + /* X3 = R^2 - H^3 - 2*U1*H^2 */ + sp_384_mont_sqr_6(ctx->x, ctx->t4, p384_mod, p384_mp_mod); + ctx->state = 17; + break; + case 17: + sp_384_mont_sqr_6(ctx->t5, ctx->t2, p384_mod, p384_mp_mod); + ctx->state = 18; + break; + case 18: + sp_384_mont_mul_6(ctx->y, ctx->t1, ctx->t5, p384_mod, p384_mp_mod); + ctx->state = 19; + break; + case 19: + sp_384_mont_mul_6(ctx->t5, ctx->t5, ctx->t2, p384_mod, p384_mp_mod); + ctx->state = 20; + break; + case 20: + sp_384_mont_sub_6(ctx->x, ctx->x, ctx->t5, p384_mod); + ctx->state = 21; + break; + case 21: + sp_384_mont_dbl_6(ctx->t1, ctx->y, p384_mod); + ctx->state = 22; + break; + case 22: + sp_384_mont_sub_6(ctx->x, ctx->x, ctx->t1, p384_mod); + ctx->state = 23; + break; + case 23: + /* Y3 = R*(U1*H^2 - X3) - S1*H^3 */ + sp_384_mont_sub_6(ctx->y, ctx->y, ctx->x, p384_mod); + ctx->state = 24; + break; + case 24: + sp_384_mont_mul_6(ctx->y, ctx->y, ctx->t4, p384_mod, p384_mp_mod); + ctx->state = 25; + break; + case 25: + sp_384_mont_mul_6(ctx->t5, ctx->t5, ctx->t3, p384_mod, p384_mp_mod); + ctx->state = 26; + break; + case 26: + sp_384_mont_sub_6(ctx->y, ctx->y, ctx->t5, p384_mod); + ctx->state = 27; + /* fall-through */ + case 27: + err = MP_OKAY; + break; + } + + if (err == MP_OKAY && ctx->state != 27) { + err = FP_WOULDBLOCK; + } + return err; +} +#endif /* WOLFSSL_SP_NONBLOCK */ + static void sp_384_proj_point_add_6(sp_point_384* r, const sp_point_384* p, const sp_point_384* q, sp_digit* t) { @@ -25373,6 +26789,141 @@ static void sp_384_map_avx2_6(sp_point_384* r, const sp_point_384* p, sp_digit* * p Point to double. * t Temporary ordinate data. */ +#ifdef WOLFSSL_SP_NONBLOCK +typedef struct sp_384_proj_point_dbl_avx2_6_ctx { + int state; + sp_digit* t1; + sp_digit* t2; + sp_digit* x; + sp_digit* y; + sp_digit* z; +} sp_384_proj_point_dbl_avx2_6_ctx; + +static int sp_384_proj_point_dbl_avx2_6_nb(sp_ecc_ctx_t* sp_ctx, sp_point_384* r, const sp_point_384* p, sp_digit* t) +{ + int err = FP_WOULDBLOCK; + sp_384_proj_point_dbl_avx2_6_ctx* ctx = (sp_384_proj_point_dbl_avx2_6_ctx*)sp_ctx->data; + + typedef char ctx_size_test[sizeof(sp_384_proj_point_dbl_avx2_6_ctx) >= sizeof(*sp_ctx) ? -1 : 1]; + (void)sizeof(ctx_size_test); + + switch (ctx->state) { + case 0: + ctx->t1 = t; + ctx->t2 = t + 2*6; + ctx->x = r->x; + ctx->y = r->y; + ctx->z = r->z; + + /* Put infinity into result. */ + if (r != p) { + r->infinity = p->infinity; + } + ctx->state = 1; + break; + case 1: + /* T1 = Z * Z */ + sp_384_mont_sqr_avx2_6(ctx->t1, p->z, p384_mod, p384_mp_mod); + ctx->state = 2; + break; + case 2: + /* Z = Y * Z */ + sp_384_mont_mul_avx2_6(ctx->z, p->y, p->z, p384_mod, p384_mp_mod); + ctx->state = 3; + break; + case 3: + /* Z = 2Z */ + sp_384_mont_dbl_avx2_6(ctx->z, ctx->z, p384_mod); + ctx->state = 4; + break; + case 4: + /* T2 = X - T1 */ + sp_384_mont_sub_avx2_6(ctx->t2, p->x, ctx->t1, p384_mod); + ctx->state = 5; + break; + case 5: + /* T1 = X + T1 */ + sp_384_mont_add_avx2_6(ctx->t1, p->x, ctx->t1, p384_mod); + ctx->state = 6; + break; + case 6: + /* T2 = T1 * T2 */ + sp_384_mont_mul_avx2_6(ctx->t2, ctx->t1, ctx->t2, p384_mod, p384_mp_mod); + ctx->state = 7; + break; + case 7: + /* T1 = 3T2 */ + sp_384_mont_tpl_avx2_6(ctx->t1, ctx->t2, p384_mod); + ctx->state = 8; + break; + case 8: + /* Y = 2Y */ + sp_384_mont_dbl_avx2_6(ctx->y, p->y, p384_mod); + ctx->state = 9; + break; + case 9: + /* Y = Y * Y */ + sp_384_mont_sqr_avx2_6(ctx->y, ctx->y, p384_mod, p384_mp_mod); + ctx->state = 10; + break; + case 10: + /* T2 = Y * Y */ + sp_384_mont_sqr_avx2_6(ctx->t2, ctx->y, p384_mod, p384_mp_mod); + ctx->state = 11; + break; + case 11: + /* T2 = T2/2 */ + sp_384_div2_avx2_6(ctx->t2, ctx->t2, p384_mod); + ctx->state = 12; + break; + case 12: + /* Y = Y * X */ + sp_384_mont_mul_avx2_6(ctx->y, ctx->y, p->x, p384_mod, p384_mp_mod); + ctx->state = 13; + break; + case 13: + /* X = T1 * T1 */ + sp_384_mont_sqr_avx2_6(ctx->x, ctx->t1, p384_mod, p384_mp_mod); + ctx->state = 14; + break; + case 14: + /* X = X - Y */ + sp_384_mont_sub_avx2_6(ctx->x, ctx->x, ctx->y, p384_mod); + ctx->state = 15; + break; + case 15: + /* X = X - Y */ + sp_384_mont_sub_avx2_6(ctx->x, ctx->x, ctx->y, p384_mod); + ctx->state = 16; + break; + case 16: + /* Y = Y - X */ + sp_384_mont_sub_avx2_6(ctx->y, ctx->y, ctx->x, p384_mod); + ctx->state = 17; + break; + case 17: + /* Y = Y * T1 */ + sp_384_mont_mul_avx2_6(ctx->y, ctx->y, ctx->t1, p384_mod, p384_mp_mod); + ctx->state = 18; + break; + case 18: + /* Y = Y - T2 */ + sp_384_mont_sub_avx2_6(ctx->y, ctx->y, ctx->t2, p384_mod); + ctx->state = 19; + /* fall-through */ + case 19: + err = MP_OKAY; + break; + } + + if (err == MP_OKAY && ctx->state != 19) { + err = FP_WOULDBLOCK; + } + + return err; +} +#endif /* WOLFSSL_SP_NONBLOCK */ + static void sp_384_proj_point_dbl_avx2_6(sp_point_384* r, const sp_point_384* p, sp_digit* t) { sp_digit* t1 = t; @@ -25522,6 +27073,209 @@ static void sp_384_proj_point_dbl_n_avx2_6(sp_point_384* p, int n, sp_digit* t) * q Second point to add. * t Temporary ordinate data. */ + +#ifdef WOLFSSL_SP_NONBLOCK +typedef struct sp_384_proj_point_add_avx2_6_ctx { + int state; + sp_384_proj_point_dbl_avx2_6_ctx dbl_ctx; + const sp_point_384* ap[2]; + sp_point_384* rp[2]; + sp_digit* t1; + sp_digit* t2; + sp_digit* t3; + sp_digit* t4; + sp_digit* t5; + sp_digit* x; + sp_digit* y; + sp_digit* z; +} sp_384_proj_point_add_avx2_6_ctx; + +static int sp_384_proj_point_add_avx2_6_nb(sp_ecc_ctx_t* sp_ctx, sp_point_384* r, + const sp_point_384* p, const sp_point_384* q, sp_digit* t) +{ + int err = FP_WOULDBLOCK; + sp_384_proj_point_add_avx2_6_ctx* ctx = (sp_384_proj_point_add_avx2_6_ctx*)sp_ctx->data; + + /* Ensure only the first point is the same as the result. */ + if (q == r) { + const sp_point_384* a = p; + p = q; + q = a; + } + + typedef char ctx_size_test[sizeof(sp_384_proj_point_add_avx2_6_ctx) >= sizeof(*sp_ctx) ? -1 : 1]; + (void)sizeof(ctx_size_test); + + switch (ctx->state) { + case 0: /* INIT */ + ctx->t1 = t; + ctx->t2 = t + 2*6; + ctx->t3 = t + 4*6; + ctx->t4 = t + 6*6; + ctx->t5 = t + 8*6; + + ctx->state = 1; + break; + case 1: + /* Check double */ + (void)sp_384_sub_avx2_6(ctx->t1, p384_mod, q->y); + sp_384_norm_avx2_6(ctx->t1); + if ((sp_384_cmp_equal_avx2_6(p->x, q->x) & sp_384_cmp_equal_avx2_6(p->z, q->z) & + (sp_384_cmp_equal_avx2_6(p->y, q->y) | sp_384_cmp_equal_avx2_6(p->y, ctx->t1))) != 0) + { + XMEMSET(&ctx->dbl_ctx, 0, sizeof(ctx->dbl_ctx)); + ctx->state = 2; + } + else { + ctx->state = 3; + } + break; + case 2: + err = sp_384_proj_point_dbl_avx2_6_nb((sp_ecc_ctx_t*)&ctx->dbl_ctx, r, p, t); + if (err == MP_OKAY) + ctx->state = 27; /* done */ + break; + case 3: + { + int i; + ctx->rp[0] = r; + + /*lint allow cast to different type of pointer*/ + ctx->rp[1] = (sp_point_384*)t; /*lint !e9087 !e740*/ + XMEMSET(ctx->rp[1], 0, sizeof(sp_point_384)); + ctx->x = ctx->rp[p->infinity | q->infinity]->x; + ctx->y = ctx->rp[p->infinity | q->infinity]->y; + ctx->z = ctx->rp[p->infinity | q->infinity]->z; + + ctx->ap[0] = p; + ctx->ap[1] = q; + for (i=0; i<6; i++) { + r->x[i] = ctx->ap[p->infinity]->x[i]; + } + for (i=0; i<6; i++) { + r->y[i] = ctx->ap[p->infinity]->y[i]; + } + for (i=0; i<6; i++) { + r->z[i] = ctx->ap[p->infinity]->z[i]; + } + r->infinity = ctx->ap[p->infinity]->infinity; + + ctx->state = 4; + break; + } + case 4: + /* U1 = X1*Z2^2 */ + sp_384_mont_sqr_avx2_6(ctx->t1, q->z, p384_mod, p384_mp_mod); + ctx->state = 5; + break; + case 5: + sp_384_mont_mul_avx2_6(ctx->t3, ctx->t1, q->z, p384_mod, p384_mp_mod); + ctx->state = 6; + break; + case 6: + sp_384_mont_mul_avx2_6(ctx->t1, ctx->t1, ctx->x, p384_mod, p384_mp_mod); + ctx->state = 7; + break; + case 7: + /* U2 = X2*Z1^2 */ + sp_384_mont_sqr_avx2_6(ctx->t2, ctx->z, p384_mod, p384_mp_mod); + ctx->state = 8; + break; + case 8: + sp_384_mont_mul_avx2_6(ctx->t4, ctx->t2, ctx->z, p384_mod, p384_mp_mod); + ctx->state = 9; + break; + case 9: + sp_384_mont_mul_avx2_6(ctx->t2, ctx->t2, q->x, p384_mod, p384_mp_mod); + ctx->state = 10; + break; + case 10: + /* S1 = Y1*Z2^3 */ + sp_384_mont_mul_avx2_6(ctx->t3, ctx->t3, ctx->y, p384_mod, p384_mp_mod); + ctx->state = 11; + break; + case 11: + /* S2 = Y2*Z1^3 */ + sp_384_mont_mul_avx2_6(ctx->t4, ctx->t4, q->y, p384_mod, p384_mp_mod); + ctx->state = 12; + break; + case 12: + /* H = U2 - U1 */ + sp_384_mont_sub_avx2_6(ctx->t2, ctx->t2, ctx->t1, p384_mod); + ctx->state = 13; + break; + case 13: + /* R = S2 - S1 */ + sp_384_mont_sub_avx2_6(ctx->t4, ctx->t4, ctx->t3, p384_mod); + ctx->state = 14; + break; + case 14: + /* Z3 = H*Z1*Z2 */ + sp_384_mont_mul_avx2_6(ctx->z, ctx->z, q->z, p384_mod, p384_mp_mod); + ctx->state = 15; + break; + case 15: + sp_384_mont_mul_avx2_6(ctx->z, ctx->z, ctx->t2, p384_mod, p384_mp_mod); + ctx->state = 16; + break; + case 16: + /* X3 = R^2 - H^3 - 2*U1*H^2 */ + sp_384_mont_sqr_avx2_6(ctx->x, ctx->t4, p384_mod, p384_mp_mod); + ctx->state = 17; + break; + case 17: + sp_384_mont_sqr_avx2_6(ctx->t5, ctx->t2, p384_mod, p384_mp_mod); + ctx->state = 18; + break; + case 18: + sp_384_mont_mul_avx2_6(ctx->y, ctx->t1, ctx->t5, p384_mod, p384_mp_mod); + ctx->state = 19; + break; + case 19: + sp_384_mont_mul_avx2_6(ctx->t5, ctx->t5, ctx->t2, p384_mod, p384_mp_mod); + ctx->state = 20; + break; + case 20: + sp_384_mont_sub_avx2_6(ctx->x, ctx->x, ctx->t5, p384_mod); + ctx->state = 21; + break; + case 21: + sp_384_mont_dbl_avx2_6(ctx->t1, ctx->y, p384_mod); + ctx->state = 22; + break; + case 22: + sp_384_mont_sub_avx2_6(ctx->x, ctx->x, ctx->t1, p384_mod); + ctx->state = 23; + break; + case 23: + /* Y3 = R*(U1*H^2 - X3) - S1*H^3 */ + sp_384_mont_sub_avx2_6(ctx->y, ctx->y, ctx->x, p384_mod); + ctx->state = 24; + break; + case 24: + sp_384_mont_mul_avx2_6(ctx->y, ctx->y, ctx->t4, p384_mod, p384_mp_mod); + ctx->state = 25; + break; + case 25: + sp_384_mont_mul_avx2_6(ctx->t5, ctx->t5, ctx->t3, p384_mod, p384_mp_mod); + ctx->state = 26; + break; + case 26: + sp_384_mont_sub_avx2_6(ctx->y, ctx->y, ctx->t5, p384_mod); + ctx->state = 27; + /* fall-through */ + case 27: + err = MP_OKAY; + break; + } + + if (err == MP_OKAY && ctx->state != 27) { + err = FP_WOULDBLOCK; + } + return err; +} +#endif /* WOLFSSL_SP_NONBLOCK */ + static void sp_384_proj_point_add_avx2_6(sp_point_384* r, const sp_point_384* p, const sp_point_384* q, sp_digit* t) { @@ -28483,6 +30237,46 @@ static void sp_384_mont_sqr_n_order_6(sp_digit* r, const sp_digit* a, int n) * a Number to invert. * td Temporary data. */ + +#ifdef WOLFSSL_SP_NONBLOCK +typedef struct sp_384_mont_inv_order_6_ctx { + int state; + int i; +} sp_384_mont_inv_order_6_ctx; +static int sp_384_mont_inv_order_6_nb(sp_ecc_ctx_t* sp_ctx, sp_digit* r, const sp_digit* a, + sp_digit* t) +{ + int err = FP_WOULDBLOCK; + sp_384_mont_inv_order_6_ctx* ctx = (sp_384_mont_inv_order_6_ctx*)sp_ctx; + + typedef char ctx_size_test[sizeof(sp_384_mont_inv_order_6_ctx) >= sizeof(*sp_ctx) ? -1 : 1]; + (void)sizeof(ctx_size_test); + + switch (ctx->state) { + case 0: + XMEMCPY(t, a, sizeof(sp_digit) * 6); + ctx->i = 382; + ctx->state = 1; + break; + case 1: + sp_384_mont_sqr_order_6(t, t); + if ((p384_order_minus_2[ctx->i / 64] & ((sp_int_digit)1 << (ctx->i % 64))) != 0) { + sp_384_mont_mul_order_6(t, t, a); + } + ctx->i--; + if (ctx->i == 0) { + ctx->state = 2; + } + break; + case 2: + XMEMCPY(r, t, sizeof(sp_digit) * 6U); + err = MP_OKAY; + break; + } + return err; +} +#endif /* WOLFSSL_SP_NONBLOCK */ + static void sp_384_mont_inv_order_6(sp_digit* r, const sp_digit* a, sp_digit* td) { @@ -28596,6 +30390,46 @@ static void sp_384_mont_sqr_n_order_avx2_6(sp_digit* r, const sp_digit* a, int n * a Number to invert. * td Temporary data. */ + +#ifdef WOLFSSL_SP_NONBLOCK +typedef struct sp_384_mont_inv_order_avx2_6_ctx { + int state; + int i; +} sp_384_mont_inv_order_avx2_6_ctx; +static int sp_384_mont_inv_order_avx2_6_nb(sp_ecc_ctx_t* sp_ctx, sp_digit* r, const sp_digit* a, + sp_digit* t) +{ + int err = FP_WOULDBLOCK; + sp_384_mont_inv_order_avx2_6_ctx* ctx = (sp_384_mont_inv_order_avx2_6_ctx*)sp_ctx; + + typedef char ctx_size_test[sizeof(sp_384_mont_inv_order_avx2_6_ctx) >= sizeof(*sp_ctx) ? -1 : 1]; + (void)sizeof(ctx_size_test); + + switch (ctx->state) { + case 0: + XMEMCPY(t, a, sizeof(sp_digit) * 6); + ctx->i = 382; + ctx->state = 1; + break; + case 1: + sp_384_mont_sqr_order_avx2_6(t, t); + if ((p384_order_minus_2[ctx->i / 64] & ((sp_int_digit)1 << (ctx->i % 64))) != 0) { + sp_384_mont_mul_order_avx2_6(t, t, a); + } + ctx->i--; + if (ctx->i == 0) { + ctx->state = 2; + } + break; + case 2: + XMEMCPY(r, t, sizeof(sp_digit) * 6U); + err = MP_OKAY; + break; + } + return err; +} +#endif /* WOLFSSL_SP_NONBLOCK */ + static void sp_384_mont_inv_order_avx2_6(sp_digit* r, const sp_digit* a, sp_digit* td) { @@ -28683,6 +30517,165 @@ static void sp_384_mont_inv_order_avx2_6(sp_digit* r, const sp_digit* a, * returns RNG failures, MEMORY_E when memory allocation fails and * MP_OKAY on success. */ +#ifdef WOLFSSL_SP_NONBLOCK +typedef struct sp_ecc_sign_384_ctx { + int state; + union { + sp_384_ecc_mulmod_6_ctx mulmod_ctx; + sp_384_mont_inv_order_6_ctx mont_inv_order_ctx; + }; + sp_digit e[2*6]; + sp_digit x[2*6]; + sp_digit k[2*6]; + sp_digit r[2*6]; + sp_digit tmp[3 * 2*6]; + sp_point_384 point; + sp_digit* s; + sp_digit* kInv; + int i; +} sp_ecc_sign_384_ctx; + +int sp_ecc_sign_384_nb(sp_ecc_ctx_t* sp_ctx, const byte* hash, word32 hashLen, WC_RNG* rng, mp_int* priv, + mp_int* rm, mp_int* sm, mp_int* km, void* heap) +{ + int err = FP_WOULDBLOCK; + sp_ecc_sign_384_ctx* ctx = (sp_ecc_sign_384_ctx*)sp_ctx->data; + + typedef char ctx_size_test[sizeof(sp_ecc_sign_384_ctx) >= sizeof(*sp_ctx) ? -1 : 1]; + (void)sizeof(ctx_size_test); + + (void)heap; + + switch (ctx->state) { + case 0: /* INIT */ + ctx->s = ctx->e; + ctx->kInv = ctx->k; + if (hashLen > 48U) { + hashLen = 48U; + } + + sp_384_from_bin(ctx->e, 6, hash, (int)hashLen); + + ctx->i = SP_ECC_MAX_SIG_GEN; + ctx->state = 1; + break; + case 1: /* GEN */ + sp_384_from_mp(ctx->x, 6, priv); + /* New random point. */ + if (km == NULL || mp_iszero(km)) { + err = sp_384_ecc_gen_k_6(rng, ctx->k); + } + else { + sp_384_from_mp(ctx->k, 6, km); + mp_zero(km); + } + XMEMSET(&ctx->mulmod_ctx, 0, sizeof(ctx->mulmod_ctx)); + ctx->state = 2; + break; + case 2: /* MULMOD */ + err = sp_384_ecc_mulmod_6_nb((sp_ecc_ctx_t*)&ctx->mulmod_ctx, + &ctx->point, &p384_base, ctx->k, 1, heap); + if (err == MP_OKAY) { + ctx->state = 3; + } + break; + case 3: /* MODORDER */ + { + int64_t c; + /* r = point->x mod order */ + XMEMCPY(ctx->r, ctx->point.x, sizeof(sp_digit) * 6U); + sp_384_norm_6(ctx->r); + c = sp_384_cmp_6(ctx->r, p384_order); + sp_384_cond_sub_6(ctx->r, ctx->r, p384_order, 0L - (sp_digit)(c >= 0)); + sp_384_norm_6(ctx->r); + ctx->state = 4; + break; + } + case 4: /* KMODORDER */ + /* Conv k to Montgomery form (mod order) */ + sp_384_mul_6(ctx->k, ctx->k, p384_norm_order); + err = sp_384_mod_6(ctx->k, ctx->k, p384_order); + if (err == MP_OKAY) { + sp_384_norm_6(ctx->k); + XMEMSET(&ctx->mont_inv_order_ctx, 0, sizeof(ctx->mont_inv_order_ctx)); + ctx->state = 5; + } + break; + case 5: /* KINV */ + /* kInv = 1/k mod order */ + err = sp_384_mont_inv_order_6_nb((sp_ecc_ctx_t*)&ctx->mont_inv_order_ctx, ctx->kInv, ctx->k, ctx->tmp); + if (err == MP_OKAY) { + XMEMSET(&ctx->mont_inv_order_ctx, 0, sizeof(ctx->mont_inv_order_ctx)); + ctx->state = 6; + } + break; + case 6: /* KINVNORM */ + sp_384_norm_6(ctx->kInv); + ctx->state = 7; + break; + case 7: /* R */ + /* s = r * x + e */ + sp_384_mul_6(ctx->x, ctx->x, ctx->r); + ctx->state = 8; + break; + case 8: /* S1 */ + err = sp_384_mod_6(ctx->x, ctx->x, p384_order); + if (err == MP_OKAY) + ctx->state = 9; + break; + case 9: /* S2 */ + { + sp_digit carry; + int64_t c; + sp_384_norm_6(ctx->x); + carry = sp_384_add_6(ctx->s, ctx->e, ctx->x); + sp_384_cond_sub_6(ctx->s, ctx->s, p384_order, 0 - carry); + sp_384_norm_6(ctx->s); + c = sp_384_cmp_6(ctx->s, p384_order); + sp_384_cond_sub_6(ctx->s, ctx->s, p384_order, 0L - (sp_digit)(c >= 0)); + sp_384_norm_6(ctx->s); + + /* s = s * k^-1 mod order */ + sp_384_mont_mul_order_6(ctx->s, ctx->s, ctx->kInv); + sp_384_norm_6(ctx->s); + + /* Check that signature is usable. */ + if (sp_384_iszero_6(ctx->s) == 0) { + ctx->state = 10; + break; + } + + /* not usable gen, try again */ + ctx->i--; + if (ctx->i == 0) { + err = RNG_FAILURE_E; + } + ctx->state = 1; + break; + } + case 10: /* RES */ + err = sp_384_to_mp(ctx->r, rm); + if (err == MP_OKAY) { + err = sp_384_to_mp(ctx->s, sm); + } + break; + } + + if (err == MP_OKAY && ctx->state != 10) { + err = FP_WOULDBLOCK; + } + if (err != FP_WOULDBLOCK) { + XMEMSET(ctx->e, 0, sizeof(sp_digit) * 2U * 6U); + XMEMSET(ctx->x, 0, sizeof(sp_digit) * 2U * 6U); + XMEMSET(ctx->k, 0, sizeof(sp_digit) * 2U * 6U); + XMEMSET(ctx->r, 0, sizeof(sp_digit) * 2U * 6U); + XMEMSET(ctx->tmp, 0, sizeof(sp_digit) * 3U * 2U * 6U); + } + + return err; +} +#endif /* WOLFSSL_SP_NONBLOCK */ + int sp_ecc_sign_384(const byte* hash, word32 hashLen, WC_RNG* rng, mp_int* priv, mp_int* rm, mp_int* sm, mp_int* km, void* heap) { @@ -28882,6 +30875,169 @@ int sp_ecc_sign_384(const byte* hash, word32 hashLen, WC_RNG* rng, mp_int* priv, * returns RNG failures, MEMORY_E when memory allocation fails and * MP_OKAY on success. */ +#ifdef WOLFSSL_SP_NONBLOCK +typedef struct sp_ecc_verify_384_ctx { + int state; + union { + sp_384_ecc_mulmod_6_ctx mulmod_ctx; + sp_384_mont_inv_order_6_ctx mont_inv_order_ctx; + sp_384_proj_point_dbl_6_ctx dbl_ctx; + sp_384_proj_point_add_6_ctx add_ctx; + }; + sp_digit u1[2*6]; + sp_digit u2[2*6]; + sp_digit s[2*6]; + sp_digit tmp[2*6 * 5]; + sp_point_384 p1; + sp_point_384 p2; +} sp_ecc_verify_384_ctx; + +int sp_ecc_verify_384_nb(sp_ecc_ctx_t* sp_ctx, const byte* hash, word32 hashLen, mp_int* pX, + mp_int* pY, mp_int* pZ, mp_int* r, mp_int* sm, int* res, void* heap) +{ + int err = FP_WOULDBLOCK; + sp_ecc_verify_384_ctx* ctx = (sp_ecc_verify_384_ctx*)sp_ctx->data; + + typedef char ctx_size_test[sizeof(sp_ecc_verify_384_ctx) >= sizeof(*sp_ctx) ? -1 : 1]; + (void)sizeof(ctx_size_test); + + switch (ctx->state) { + case 0: /* INIT */ + if (hashLen > 48U) { + hashLen = 48U; + } + + sp_384_from_bin(ctx->u1, 6, hash, (int)hashLen); + sp_384_from_mp(ctx->u2, 6, r); + sp_384_from_mp(ctx->s, 6, sm); + sp_384_from_mp(ctx->p2.x, 6, pX); + sp_384_from_mp(ctx->p2.y, 6, pY); + sp_384_from_mp(ctx->p2.z, 6, pZ); + sp_384_mul_6(ctx->s, ctx->s, p384_norm_order); + err = sp_384_mod_6(ctx->s, ctx->s, p384_order); + if (err == MP_OKAY) + ctx->state = 1; + break; + case 1: /* NORMS1 */ + sp_384_norm_6(ctx->s); + XMEMSET(&ctx->mont_inv_order_ctx, 0, sizeof(ctx->mont_inv_order_ctx)); + ctx->state = 2; + break; + case 2: /* NORMS2 */ + err = sp_384_mont_inv_order_6_nb((sp_ecc_ctx_t*)&ctx->mont_inv_order_ctx, ctx->s, ctx->s, ctx->tmp); + if (err == MP_OKAY) { + ctx->state = 3; + } + break; + case 3: /* NORMS3 */ + sp_384_mont_mul_order_6(ctx->u1, ctx->u1, ctx->s); + ctx->state = 4; + break; + case 4: /* NORMS4 */ + sp_384_mont_mul_order_6(ctx->u2, ctx->u2, ctx->s); + XMEMSET(&ctx->mulmod_ctx, 0, sizeof(ctx->mulmod_ctx)); + ctx->state = 5; + break; + case 5: /* MULBASE */ + err = sp_384_ecc_mulmod_6_nb((sp_ecc_ctx_t*)&ctx->mulmod_ctx, &ctx->p1, &p384_base, ctx->u1, 0, heap); + if (err == MP_OKAY) { + XMEMSET(&ctx->mulmod_ctx, 0, sizeof(ctx->mulmod_ctx)); + ctx->state = 6; + } + break; + case 6: /* MULMOD */ + err = sp_384_ecc_mulmod_6_nb((sp_ecc_ctx_t*)&ctx->mulmod_ctx, &ctx->p2, &ctx->p2, ctx->u2, 0, heap); + if (err == MP_OKAY) { + XMEMSET(&ctx->add_ctx, 0, sizeof(ctx->add_ctx)); + ctx->state = 7; + } + break; + case 7: /* ADD */ + err = sp_384_proj_point_add_6_nb((sp_ecc_ctx_t*)&ctx->add_ctx, &ctx->p1, &ctx->p1, &ctx->p2, ctx->tmp); + if (err == MP_OKAY) + ctx->state = 8; + break; + case 8: /* DBLPREP */ + if (sp_384_iszero_6(ctx->p1.z)) { + if (sp_384_iszero_6(ctx->p1.x) && sp_384_iszero_6(ctx->p1.y)) { + XMEMSET(&ctx->dbl_ctx, 0, sizeof(ctx->dbl_ctx)); + ctx->state = 9; + break; + } + else { + /* Y ordinate is not used from here - don't set. */ + int i; + for (i=0; i<6; i++) { + ctx->p1.x[i] = 0; + } + XMEMCPY(ctx->p1.z, p384_norm_mod, sizeof(p384_norm_mod)); + } + } + ctx->state = 10; + break; + case 9: /* DBL */ + err = sp_384_proj_point_dbl_6_nb((sp_ecc_ctx_t*)&ctx->dbl_ctx, &ctx->p1, + &ctx->p2, ctx->tmp); + if (err == MP_OKAY) { + ctx->state = 10; + } + break; + case 10: /* MONT */ + /* (r + n*order).z'.z' mod prime == (u1.G + u2.Q)->x' */ + /* Reload r and convert to Montgomery form. */ + sp_384_from_mp(ctx->u2, 6, r); + err = sp_384_mod_mul_norm_6(ctx->u2, ctx->u2, p384_mod); + if (err == MP_OKAY) + ctx->state = 11; + break; + case 11: /* SQR */ + /* u1 = r.z'.z' mod prime */ + sp_384_mont_sqr_6(ctx->p1.z, ctx->p1.z, p384_mod, p384_mp_mod); + ctx->state = 12; + break; + case 12: /* MUL */ + sp_384_mont_mul_6(ctx->u1, ctx->u2, ctx->p1.z, p384_mod, p384_mp_mod); + ctx->state = 13; + break; + case 13: /* RES */ + err = MP_OKAY; /* math okay, now check result */ + *res = (int)(sp_384_cmp_6(ctx->p1.x, ctx->u1) == 0); + if (*res == 0) { + sp_digit carry; + int64_t c; + + /* Reload r and add order. */ + sp_384_from_mp(ctx->u2, 6, r); + carry = sp_384_add_6(ctx->u2, ctx->u2, p384_order); + /* Carry means result is greater than mod and is not valid. */ + if (carry == 0) { + sp_384_norm_6(ctx->u2); + + /* Compare with mod and if greater or equal then not valid. */ + c = sp_384_cmp_6(ctx->u2, p384_mod); + if (c < 0) { + /* Convert to Montogomery form */ + err = sp_384_mod_mul_norm_6(ctx->u2, ctx->u2, p384_mod); + if (err == MP_OKAY) { + /* u1 = (r + 1*order).z'.z' mod prime */ + sp_384_mont_mul_6(ctx->u1, ctx->u2, ctx->p1.z, p384_mod, + p384_mp_mod); + *res = (int)(sp_384_cmp_6(ctx->p1.x, ctx->u1) == 0); + } + } + } + } + break; + } + + if (err == MP_OKAY && ctx->state != 13) { + err = FP_WOULDBLOCK; + } + + return err; +} +#endif /* WOLFSSL_SP_NONBLOCK */ + int sp_ecc_verify_384(const byte* hash, word32 hashLen, mp_int* pX, mp_int* pY, mp_int* pZ, mp_int* r, mp_int* sm, int* res, void* heap) { diff --git a/wolfssl/wolfcrypt/ecc.h b/wolfssl/wolfcrypt/ecc.h index 3dc0f32532..930b96199e 100644 --- a/wolfssl/wolfcrypt/ecc.h +++ b/wolfssl/wolfcrypt/ecc.h @@ -58,6 +58,11 @@ #include #endif +#ifdef WOLFSSL_HAVE_SP_ECC + #include +#endif + + #ifdef __cplusplus extern "C" { #endif @@ -353,6 +358,19 @@ enum { #endif }; +/* ECC non-blocking */ +#ifdef WC_ECC_NONBLOCK + typedef struct ecc_nb_ctx { + #if defined(WOLFSSL_HAVE_SP_ECC) && defined(WOLFSSL_SP_NONBLOCK) + sp_ecc_ctx_t sp_ctx; + #else + /* build configuration not supported */ + #error ECC non-blocking only supports SP (--enable-sp=nonblock) + #endif + } ecc_nb_ctx_t; +#endif /* WC_ECC_NONBLOCK */ + + /* An ECC Key */ struct ecc_key { int type; /* Public or Private */ @@ -413,6 +431,9 @@ struct ecc_key { #ifdef WOLFSSL_DSP remote_handle64 handle; #endif +#ifdef WC_ECC_NONBLOCK + ecc_nb_ctx_t* nb_ctx; +#endif }; @@ -757,6 +778,10 @@ int sp_dsp_ecc_verify_256(remote_handle64 handle, const byte* hash, word32 hashL mp_int* pY, mp_int* pZ, mp_int* r, mp_int* sm, int* res, void* heap); #endif +#ifdef WC_ECC_NONBLOCK + WOLFSSL_API int wc_ecc_set_nonblock(ecc_key *key, ecc_nb_ctx_t* ctx); +#endif + #ifdef __cplusplus } /* extern "C" */ #endif diff --git a/wolfssl/wolfcrypt/sp.h b/wolfssl/wolfcrypt/sp.h index e468a06fa4..5e01b82a82 100644 --- a/wolfssl/wolfcrypt/sp.h +++ b/wolfssl/wolfcrypt/sp.h @@ -141,7 +141,18 @@ int sp_ecc_proj_dbl_point_384(mp_int* pX, mp_int* pY, mp_int* pZ, int sp_ecc_map_384(mp_int* pX, mp_int* pY, mp_int* pZ); int sp_ecc_uncompress_384(mp_int* xm, int odd, mp_int* ym); -#endif /*ifdef WOLFSSL_HAVE_SP_ECC */ +#ifdef WOLFSSL_SP_NONBLOCK +int sp_ecc_sign_256_nb(sp_ecc_ctx_t* ctx, const byte* hash, word32 hashLen, WC_RNG* rng, mp_int* priv, + mp_int* rm, mp_int* sm, mp_int* km, void* heap); +int sp_ecc_verify_256_nb(sp_ecc_ctx_t* ctx, const byte* hash, word32 hashLen, mp_int* pX, mp_int* pY, + mp_int* pZ, mp_int* r, mp_int* sm, int* res, void* heap); +int sp_ecc_sign_384_nb(sp_ecc_ctx_t* ctx, const byte* hash, word32 hashLen, WC_RNG* rng, mp_int* priv, + mp_int* rm, mp_int* sm, mp_int* km, void* heap); +int sp_ecc_verify_384_nb(sp_ecc_ctx_t* ctx, const byte* hash, word32 hashLen, mp_int* pX, mp_int* pY, + mp_int* pZ, mp_int* r, mp_int* sm, int* res, void* heap); +#endif /* WOLFSSL_SP_NONBLOCK */ + +#endif /* WOLFSSL_HAVE_SP_ECC */ #ifdef __cplusplus diff --git a/wolfssl/wolfcrypt/sp_int.h b/wolfssl/wolfcrypt/sp_int.h index e3cc191bec..ef0ebbb0a3 100644 --- a/wolfssl/wolfcrypt/sp_int.h +++ b/wolfssl/wolfcrypt/sp_int.h @@ -109,6 +109,17 @@ #define SP_MASK (sp_digit)(-1) + +#if defined(WOLFSSL_HAVE_SP_ECC) && defined(WOLFSSL_SP_NONBLOCK) +typedef struct sp_ecc_ctx { + #ifdef WOLFSSL_SP_384 + byte data[48*80]; /* stack data */ + #else + byte data[32*80]; /* stack data */ + #endif +} sp_ecc_ctx_t; +#endif + #ifdef WOLFSSL_SP_MATH #include @@ -216,7 +227,6 @@ MP_API void sp_rshb(sp_int* a, int n, sp_int* r); MP_API int sp_mul_d(sp_int* a, sp_int_digit n, sp_int* r); -#define MP_OKAY 0 #define MP_NO 0 #define MP_YES 1 @@ -226,8 +236,10 @@ MP_API int sp_mul_d(sp_int* a, sp_int_digit n, sp_int* r); #define MP_EQ 0 #define MP_LT -1 +#define MP_OKAY 0 #define MP_MEM -2 #define MP_VAL -3 +#define FP_WOULDBLOCK -4 #define DIGIT_BIT SP_WORD_SIZE #define MP_MASK SP_MASK From 90ee12f51ad173b5f15056fce3c4af28a13ab845 Mon Sep 17 00:00:00 2001 From: David Garske Date: Fri, 17 Jul 2020 12:26:27 -0700 Subject: [PATCH 13/60] Added test case for ECC non-blocking. `./configure --enable-ecc=nonblock --enable-sp=yes,nonblock CFLAGS="-DWOLFSSL_PUBLIC_MP" && make`. --- configure.ac | 3 + wolfcrypt/test/test.c | 435 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 438 insertions(+) diff --git a/configure.ac b/configure.ac index 7315827a7b..937cebd642 100644 --- a/configure.ac +++ b/configure.ac @@ -4450,6 +4450,9 @@ if test "$ENABLED_SP_ASM" = "yes"; then if test "$ENABLED_SP" = "no"; then AC_MSG_ERROR([Must have SP enabled: --enable-sp]) fi + if test "$ENABLED_SP_NONBLOCK" = "yes"; then + AC_MSG_ERROR([SP non-blocking not supported with sp-asm]) + fi if test "$ENABLED_ASM" = "no"; then AC_MSG_ERROR([Assembly code turned off]) fi diff --git a/wolfcrypt/test/test.c b/wolfcrypt/test/test.c index b2f871b8bb..217b17ee2f 100644 --- a/wolfcrypt/test/test.c +++ b/wolfcrypt/test/test.c @@ -20051,6 +20051,433 @@ exit: } #endif +/* ECC Non-blocking tests for Sign and Verify */ +/* Requires SP math and supports P384 or P256 */ +/* ./configure --enable-ecc=nonblock --enable-sp=yes,nonblock CFLAGS="-DWOLFSSL_PUBLIC_MP" */ +#if defined(WC_ECC_NONBLOCK) && defined(WOLFSSL_PUBLIC_MP) && \ + defined(HAVE_ECC_SIGN) && defined(HAVE_ECC_VERIFY) +/* Test Data - Random */ +static const uint8_t kMsg[] = { + 0x69, 0xbc, 0x9f, 0xce, 0x68, 0x17, 0xc2, 0x10, 0xea, 0xfc, 0x10, 0x65, 0x67, 0x52, 0xed, 0x78, + 0x6e, 0xb8, 0x83, 0x9c, 0x9a, 0xb4, 0x56, 0x0d, 0xc1, 0x0d, 0x1f, 0x78, 0x6e, 0x75, 0xd7, 0xbe, + 0x92, 0x6b, 0x12, 0xf6, 0x76, 0x60, 0x8e, 0xb1, 0xf4, 0x19, 0x0c, 0x81, 0xe7, 0x54, 0x5e, 0xbc, + 0xe0, 0xae, 0xc2, 0x7d, 0x1b, 0xc4, 0x6e, 0xec, 0xb1, 0x99, 0x6c, 0xbf, 0x0e, 0x38, 0xa8, 0x01, + 0xa6, 0x9a, 0x48, 0x12, 0xe4, 0xc9, 0x3b, 0xf0, 0x63, 0x46, 0x15, 0xb4, 0x61, 0xa8, 0x1a, 0x60, + 0x71, 0x87, 0x98, 0xd7, 0x6f, 0x98, 0x7b, 0x2d, 0xb9, 0x19, 0x1b, 0x21, 0x9c, 0x70, 0x58, 0xe8, + 0x0d, 0x0f, 0xe9, 0x2d, 0x9a, 0x9a, 0xf1, 0x55, 0xa0, 0x4c, 0xd3, 0x07, 0xbd, 0x97, 0x48, 0xec, + 0x88, 0x0a, 0xaf, 0xb3, 0x80, 0x78, 0xa4, 0x59, 0x43, 0x57, 0xd3, 0xa7, 0x01, 0x66, 0x0e, 0xfc +}; + +/* ECC Private Key "d" */ +static const uint8_t kPrivKey[] = { +#ifdef HAVE_ECC384 + /* SECP384R1 */ + /* d */ + 0xa4, 0xe5, 0x06, 0xe8, 0x06, 0x16, 0x3e, 0xab, + 0x89, 0xf8, 0x60, 0x43, 0xc0, 0x60, 0x25, 0xdb, + 0xba, 0x7b, 0xfe, 0x19, 0x35, 0x08, 0x55, 0x65, + 0x76, 0xe2, 0xdc, 0xe0, 0x01, 0x8b, 0x6b, 0x68, + 0xdf, 0xcf, 0x6f, 0x80, 0x12, 0xce, 0x79, 0x37, + 0xeb, 0x2b, 0x9c, 0x7b, 0xc4, 0x68, 0x1c, 0x74 +#else + /* SECP256R1 */ + /* d */ + 0x1e, 0xe7, 0x70, 0x07, 0xd3, 0x30, 0x94, 0x39, + 0x28, 0x90, 0xdf, 0x23, 0x88, 0x2c, 0x4a, 0x34, + 0x15, 0xdb, 0x4c, 0x43, 0xcd, 0xfa, 0xe5, 0x1f, + 0x3d, 0x4c, 0x37, 0xfe, 0x59, 0x3b, 0x96, 0xd8 +#endif +}; + +/* ECC public key Qx/Qy */ +static const uint8_t kPubKey[] = { +#ifdef HAVE_ECC384 + /* SECP384R1 */ + /* Qx */ + 0xea, 0xcf, 0x93, 0x4f, 0x2c, 0x09, 0xbb, 0x39, + 0x14, 0x0f, 0x56, 0x64, 0xc3, 0x40, 0xb4, 0xdf, + 0x0e, 0x63, 0xae, 0xe5, 0x71, 0x4b, 0x00, 0xcc, + 0x04, 0x97, 0xff, 0xe1, 0xe9, 0x38, 0x96, 0xbb, + 0x5f, 0x91, 0xb2, 0x6a, 0xcc, 0xb5, 0x39, 0x5f, + 0x8f, 0x70, 0x59, 0xf1, 0x01, 0xf6, 0x5a, 0x2b, + /* Qy */ + 0x01, 0x6c, 0x68, 0x0b, 0xcf, 0x55, 0x25, 0xaf, + 0x6d, 0x98, 0x48, 0x0a, 0xa8, 0x74, 0xc9, 0xa9, + 0x17, 0xa0, 0x0c, 0xc3, 0xfb, 0xd3, 0x23, 0x68, + 0xfe, 0x04, 0x3c, 0x63, 0x50, 0x88, 0x3b, 0xb9, + 0x4f, 0x7c, 0x67, 0x34, 0xf7, 0x3b, 0xa9, 0x73, + 0xe7, 0x1b, 0xc3, 0x51, 0x5e, 0x22, 0x18, 0xec +#else + /* SECP256R1 */ + /* Qx */ + 0x96, 0x93, 0x1c, 0x53, 0x0b, 0x43, 0x6c, 0x42, + 0x0c, 0x52, 0x90, 0xe4, 0xa7, 0xec, 0x98, 0xb1, + 0xaf, 0xd4, 0x14, 0x49, 0xd8, 0xc1, 0x42, 0x82, + 0x04, 0x78, 0xd1, 0x90, 0xae, 0xa0, 0x6c, 0x07, + /* Qy */ + 0xf2, 0x3a, 0xb5, 0x10, 0x32, 0x8d, 0xce, 0x9e, + 0x76, 0xa0, 0xd2, 0x8c, 0xf3, 0xfc, 0xa9, 0x94, + 0x43, 0x24, 0xe6, 0x82, 0x00, 0x40, 0xc6, 0xdb, + 0x1c, 0x2f, 0xcd, 0x38, 0x4b, 0x60, 0xdd, 0x61 +#endif +}; + +/* ECC Curve */ +#ifdef HAVE_ECC384 + /* SECP384R1 */ + #define ECC_CURVE_SZ 48 + #define ECC_CURVE_ID ECC_SECP384R1 +#else + /* SECP256R1 */ + #define ECC_CURVE_SZ 32 + #define ECC_CURVE_ID ECC_SECP256R1 +#endif + +/* Hash Algorithm */ +#if defined(HAVE_ECC384) && defined(WOLFSSL_SHA3) + #define HASH_DIGEST_SZ WC_SHA3_384_DIGEST_SIZE + #define HASH_SHA_VER 3 + #define CRYPTO_HASH_FN crypto_sha3_384 +#elif defined(HAVE_ECC384) && defined(WOLFSSL_SHA384) + #define HASH_DIGEST_SZ WC_SHA384_DIGEST_SIZE + #define HASH_SHA_VER 2 + #define CRYPTO_HASH_FN crypto_sha2_384 +#elif !defined(NO_SHA256) + #define HASH_DIGEST_SZ WC_SHA256_DIGEST_SIZE + #define HASH_SHA_VER 2 + #define CRYPTO_HASH_FN crypto_sha2_256 +#else + #error test configuration not supported +#endif + +#if defined(HAVE_ECC384) && defined(WOLFSSL_SHA3) +/* helper to perform hashing block by block */ +static int crypto_sha3_384(const uint8_t *buf, uint32_t len, uint8_t *hash, + uint32_t hashSz, uint32_t blkSz) +{ + int ret; + uint32_t i = 0, chunk; + wc_Sha3 sha3; + + /* validate arguments */ + if ((buf == NULL && len > 0) || hash == NULL || + hashSz < WC_SHA3_384_DIGEST_SIZE || blkSz == 0) + { + return BAD_FUNC_ARG; + } + + /* Init Sha3_384 structure */ + ret = wc_InitSha3_384(&sha3, NULL, INVALID_DEVID); + if (ret != 0) { + return ret; + } + while (i < len) { + chunk = blkSz; + if ((chunk + i) > len) + chunk = len - i; + /* Perform chunked update */ + ret = wc_Sha3_384_Update(&sha3, (buf + i), chunk); + if (ret != 0) { + break; + } + i += chunk; + } + if (ret == 0) { + /* Get final digest result */ + ret = wc_Sha3_384_Final(&sha3, hash); + } + return ret; +} +#elif defined(HAVE_ECC384) && defined(WOLFSSL_SHA384) +/* helper to perform hashing block by block */ +static int crypto_sha2_384(const uint8_t *buf, uint32_t len, uint8_t *hash, + uint32_t hashSz, uint32_t blkSz) +{ + int ret; + uint32_t i = 0, chunk; + wc_Sha384 sha384; + + /* validate arguments */ + if ((buf == NULL && len > 0) || hash == NULL || + hashSz < WC_SHA384_DIGEST_SIZE || blkSz == 0) + { + return BAD_FUNC_ARG; + } + + /* Init Sha384 structure */ + ret = wc_InitSha384(&sha384); + if (ret != 0) { + return ret; + } + while (i < len) { + chunk = blkSz; + if ((chunk + i) > len) + chunk = len - i; + /* Perform chunked update */ + ret = wc_Sha384Update(&sha384, (buf + i), chunk); + if (ret != 0) { + break; + } + i += chunk; + } + if (ret == 0) { + /* Get final digest result */ + ret = wc_Sha384Final(&sha384, hash); + } + return ret; +} +#elif !defined(NO_SHA256) +/* helper to perform hashing block by block */ +static int crypto_sha2_256(const uint8_t *buf, uint32_t len, uint8_t *hash, + uint32_t hashSz, uint32_t blkSz) +{ + int ret; + uint32_t i = 0, chunk; + wc_Sha256 sha256; + + /* validate arguments */ + if ((buf == NULL && len > 0) || hash == NULL || + hashSz < WC_SHA256_DIGEST_SIZE || blkSz == 0) + { + return BAD_FUNC_ARG; + } + + /* Init Sha256 structure */ + ret = wc_InitSha256(&sha256); + if (ret != 0) { + return ret; + } + while (i < len) { + chunk = blkSz; + if ((chunk + i) > len) + chunk = len - i; + /* Perform chunked update */ + ret = wc_Sha256Update(&sha256, (buf + i), chunk); + if (ret != 0) { + break; + } + i += chunk; + } + if (ret == 0) { + /* Get final digest result */ + ret = wc_Sha256Final(&sha256, hash); + } + return ret; +} +#endif + +/* perform verify of signature and hash using public key */ +/* key is public Qx + public Qy */ +/* sig is r + s */ +static int crypto_ecc_verify(const uint8_t *key, uint32_t keySz, + const uint8_t *hash, uint32_t hashSz, const uint8_t *sig, uint32_t sigSz, + uint32_t curveSz, int curveId) +{ + int ret, verify_res = 0; + mp_int r, s; + ecc_key ecc; + ecc_nb_ctx_t nb_ctx; + + /* validate arguments */ + if (key == NULL || hash == NULL || sig == NULL || curveSz == 0 || + hashSz == 0 || keySz < (curveSz*2) || sigSz < (curveSz*2)) + { + return BAD_FUNC_ARG; + } + + /* Setup the ECC key */ + ret = wc_ecc_init(&ecc); + if (ret < 0) { + return ret; + } + + ret = wc_ecc_set_nonblock(&ecc, &nb_ctx); + if (ret != MP_OKAY) { + wc_ecc_free(&ecc); + return ret; + } + + /* Setup the signature r/s variables */ + ret = mp_init(&r); + if (ret != MP_OKAY) { + wc_ecc_free(&ecc); + return ret; + } + ret = mp_init(&s); + if (ret != MP_OKAY) { + mp_clear(&r); + wc_ecc_free(&ecc); + return ret; + } + + /* Import public key x/y */ + ret = wc_ecc_import_unsigned( + &ecc, + (byte*)key, /* Public "x" Coordinate */ + (byte*)(key + curveSz), /* Public "y" Coordinate */ + NULL, /* Private "d" (optional) */ + curveId /* ECC Curve Id */ + ); + /* Make sure it was a public key imported */ + if (ret == 0 && ecc.type != ECC_PUBLICKEY) { + ret = ECC_BAD_ARG_E; + } + + /* Import signature r/s */ + if (ret == 0) { + ret = mp_read_unsigned_bin(&r, sig, curveSz); + } + if (ret == 0) { + ret = mp_read_unsigned_bin(&s, sig + curveSz, curveSz); + } + + /* Verify ECC Signature */ + if (ret == 0) { + do { + ret = wc_ecc_verify_hash_ex( + &r, &s, /* r/s as mp_int */ + hash, hashSz, /* computed hash digest */ + &verify_res, /* verification result 1=success */ + &ecc + ); + + /* TODO: Real-time work can be called here */ + } while (ret == FP_WOULDBLOCK); + } + + /* check verify result */ + if (ret == 0 && verify_res == 0) { + ret = SIG_VERIFY_E; + } + + mp_clear(&r); + mp_clear(&s); + wc_ecc_free(&ecc); + + return ret; +} + +/* perform signature operation against hash using private key */ +static int crypto_ecc_sign(const uint8_t *key, uint32_t keySz, + const uint8_t *hash, uint32_t hashSz, uint8_t *sig, uint32_t* sigSz, + uint32_t curveSz, int curveId, WC_RNG* rng) +{ + int ret; + mp_int r, s; + ecc_key ecc; + ecc_nb_ctx_t nb_ctx; + + /* validate arguments */ + if (key == NULL || hash == NULL || sig == NULL || sigSz == NULL || + curveSz == 0 || hashSz == 0 || keySz < curveSz || *sigSz < (curveSz*2)) + { + return BAD_FUNC_ARG; + } + + /* Initialize signature result */ + memset(sig, 0, curveSz*2); + + /* Setup the ECC key */ + ret = wc_ecc_init(&ecc); + if (ret < 0) { + return ret; + } + + ret = wc_ecc_set_nonblock(&ecc, &nb_ctx); + if (ret != MP_OKAY) { + wc_ecc_free(&ecc); + return ret; + } + + /* Setup the signature r/s variables */ + ret = mp_init(&r); + if (ret != MP_OKAY) { + wc_ecc_free(&ecc); + return ret; + } + ret = mp_init(&s); + if (ret != MP_OKAY) { + mp_clear(&r); + wc_ecc_free(&ecc); + return ret; + } + + /* Import private key "k" */ + ret = wc_ecc_import_private_key_ex( + key, keySz, /* private key "d" */ + NULL, 0, /* public (optional) */ + &ecc, + curveId /* ECC Curve Id */ + ); + + if (ret == 0) { + do { + /* Verify ECC Signature */ + ret = wc_ecc_sign_hash_ex( + hash, hashSz, /* computed hash digest */ + rng, &ecc, /* random and key context */ + &r, &s /* r/s as mp_int */ + ); + + /* TODO: Real-time work can be called here */ + } while (ret == FP_WOULDBLOCK); + } + + if (ret == 0) { + /* export r/s */ + mp_to_unsigned_bin(&r, sig); + mp_to_unsigned_bin(&s, sig + curveSz); + } + + mp_clear(&r); + mp_clear(&s); + wc_ecc_free(&ecc); + + return ret; +} + +static int ecc_test_nonblock(WC_RNG* rng) +{ + int ret; + uint8_t hash[HASH_DIGEST_SZ]; + uint8_t sig[ECC_CURVE_SZ*2]; + uint32_t sigSz = sizeof(sig); + + ret = CRYPTO_HASH_FN( + kMsg, sizeof(kMsg), /* input message */ + hash, sizeof(hash), /* hash digest result */ + 32 /* configurable block / chunk size */ + ); + if (ret == 0) { + /* Sign hash using private key */ + /* Note: result of an ECC sign varies for each call even with same + private key and hash. This is because a new random public key is + used for each operation. */ + ret = crypto_ecc_sign( + kPrivKey, sizeof(kPrivKey), /* private key */ + hash, sizeof(hash), /* computed hash digest */ + sig, &sigSz, /* signature r/s */ + ECC_CURVE_SZ, /* curve size in bytes */ + ECC_CURVE_ID, /* curve id */ + rng + ); + } + + if (ret == 0) { + /* Verify generated signature is valid */ + ret = crypto_ecc_verify( + kPubKey, sizeof(kPubKey), /* public key point x/y */ + hash, sizeof(hash), /* computed hash digest */ + sig, sigSz, /* signature r/s */ + ECC_CURVE_SZ, /* curve size in bytes */ + ECC_CURVE_ID /* curve id */ + ); + } + + return ret; +} +#endif /* WC_ECC_NONBLOCK && WOLFSSL_PUBLIC_MP && HAVE_ECC_SIGN && HAVE_ECC_VERIFY */ + int ecc_test(void) { int ret; @@ -20193,6 +20620,14 @@ int ecc_test(void) } #endif +#if defined(WC_ECC_NONBLOCK) && defined(WOLFSSL_PUBLIC_MP) && \ + defined(HAVE_ECC_SIGN) && defined(HAVE_ECC_VERIFY) + ret = ecc_test_nonblock(&rng); + if (ret != 0) { + printf("ecc_test_nonblock failed!: %d\n", ret); + } +#endif + done: wc_FreeRng(&rng); From 80f5fe149425b460f67a4d2f9bc25a3dd2ed3f97 Mon Sep 17 00:00:00 2001 From: David Garske Date: Fri, 17 Jul 2020 15:20:23 -0700 Subject: [PATCH 14/60] Added documentation for `wc_ecc_set_nonblock`. --- doc/dox_comments/header_files/ecc.h | 45 ++++++++++++++++++++++++++++- 1 file changed, 44 insertions(+), 1 deletion(-) diff --git a/doc/dox_comments/header_files/ecc.h b/doc/dox_comments/header_files/ecc.h index 1128af9e4f..edda0d9ed3 100644 --- a/doc/dox_comments/header_files/ecc.h +++ b/doc/dox_comments/header_files/ecc.h @@ -1752,8 +1752,51 @@ int wc_ecc_encrypt(ecc_key* privKey, ecc_key* pubKey, const byte* msg, } \endcode - \sa Wc_ecc_encrypt + \sa wc_ecc_encrypt */ WOLFSSL_API int wc_ecc_decrypt(ecc_key* privKey, ecc_key* pubKey, const byte* msg, word32 msgSz, byte* out, word32* outSz, ecEncCtx* ctx); + + +/*! + \ingroup ECC + + \brief Enable ECC support for non-blocking operations. Supported for + Single Precision (SP) math with the following build options: + WOLFSSL_SP_NONBLOCK + WOLFSSL_SP_SMALL + WOLFSSL_SP_NO_MALLOC + WC_ECC_NONBLOCK + + \return 0 Returned upon successfully setting the callback context the input message + + \param key pointer to the ecc_key object + \param ctx pointer to ecc_nb_ctx_t structure with stack data cache for SP + + _Example_ + \code + int ret; + ecc_key ecc; + ecc_nb_ctx_t nb_ctx; + + ret = wc_ecc_init(&ecc); + if (ret == 0) { + ret = wc_ecc_set_nonblock(&ecc, &nb_ctx); + if (ret == 0) { + do { + ret = wc_ecc_verify_hash_ex( + &r, &s, // r/s as mp_int + hash, hashSz, // computed hash digest + &verify_res, // verification result 1=success + &key + ); + + // TODO: Real-time work can be called here + } while (ret == FP_WOULDBLOCK); + } + wc_ecc_free(&key); + } + \endcode +*/ +WOLFSSL_API int wc_ecc_set_nonblock(ecc_key *key, ecc_nb_ctx_t* ctx); From 1b051d9c5bcda8e1b8b1bbef6494592ceb68467a Mon Sep 17 00:00:00 2001 From: David Garske Date: Thu, 9 Jul 2020 13:52:49 -0700 Subject: [PATCH 15/60] TLS v1.3 sniffer support: * Added TLS v1.3 sniffer support using static ephemeral key. * Add support for using a static ephemeral DH and ECC keys with TLS v1.3 using `WOLFSSL_STATIC_EPHEMERAL`. * Adds new API's `wolfSSL_CTX_set_ephemeral_key` and `wolfSSL_set_ephemeral_key`. * Expanded TLS extension support in sniffer. * Refactor of the handshake hashing code. * Added parameter checking to the TLS v1.3 key derivations (protects use of "DoTls13Finished" if handshake resources have been free'd). * Added support for loading DH keys via `wc_DhImportKeyPair` and `wc_DhExportKeyPair`, enabled with `WOLFSSL_DH_EXTRA`. * Added sniffer documentation `sslSniffer/README.md`. --- certs/include.am | 1 + certs/statickeys/dh-ffdhe2048-params.pem | 8 + certs/statickeys/dh-ffdhe2048.der | Bin 0 -> 323 bytes certs/statickeys/dh-ffdhe2048.pem | 9 + certs/statickeys/ecc-secp256r1.der | Bin 0 -> 121 bytes certs/statickeys/ecc-secp256r1.pem | 5 + certs/statickeys/gen-static.sh | 12 + certs/statickeys/include.am | 17 + configure.ac | 7 +- doc/dox_comments/header_files/ssl.h | 23 + examples/client/client.c | 7 +- examples/server/server.c | 27 +- src/internal.c | 139 +-- src/sniffer.c | 1197 +++++++++++++++++----- src/ssl.c | 140 ++- src/tls.c | 65 +- src/tls13.c | 142 +-- sslSniffer/README.md | 640 ++++++++++++ sslSniffer/sslSnifferTest/include.am | 1 + sslSniffer/sslSnifferTest/snifftest.c | 270 +++-- wolfcrypt/src/asn.c | 67 +- wolfcrypt/src/dh.c | 120 ++- wolfcrypt/src/ecc.c | 2 +- wolfcrypt/src/wc_port.c | 59 +- wolfcrypt/test/test.c | 38 +- wolfssl/internal.h | 43 +- wolfssl/sniffer.h | 36 +- wolfssl/sniffer_error.h | 1 + wolfssl/ssl.h | 9 + wolfssl/test.h | 14 +- wolfssl/wolfcrypt/dh.h | 32 +- wolfssl/wolfcrypt/wc_port.h | 3 + 32 files changed, 2465 insertions(+), 669 deletions(-) create mode 100644 certs/statickeys/dh-ffdhe2048-params.pem create mode 100644 certs/statickeys/dh-ffdhe2048.der create mode 100644 certs/statickeys/dh-ffdhe2048.pem create mode 100644 certs/statickeys/ecc-secp256r1.der create mode 100644 certs/statickeys/ecc-secp256r1.pem create mode 100644 certs/statickeys/gen-static.sh create mode 100644 certs/statickeys/include.am create mode 100644 sslSniffer/README.md diff --git a/certs/include.am b/certs/include.am index 45193b5ae2..7a425515c6 100644 --- a/certs/include.am +++ b/certs/include.am @@ -108,6 +108,7 @@ include certs/ed25519/include.am include certs/ed448/include.am include certs/external/include.am include certs/ocsp/include.am +include certs/statickeys/include.am include certs/test/include.am include certs/test-pathlen/include.am include certs/intermediate/include.am diff --git a/certs/statickeys/dh-ffdhe2048-params.pem b/certs/statickeys/dh-ffdhe2048-params.pem new file mode 100644 index 0000000000..088f9673dc --- /dev/null +++ b/certs/statickeys/dh-ffdhe2048-params.pem @@ -0,0 +1,8 @@ +-----BEGIN DH PARAMETERS----- +MIIBCAKCAQEA//////////+t+FRYortKmq/cViAnPTzx2LnFg84tNpWp4TZBFGQz ++8yTnc4kmz75fS/jY2MMddj2gbICrsRhetPfHtXV/WVhJDP1H18GbtCFY2VVPe0a +87VXE15/V8k1mE8McODmi3fipona8+/och3xWKE2rec1MKzKT0g6eXq8CrGCsyT7 +YdEIqUuyyOP7uWrat2DX9GgdT0Kj3jlN9K5W7edjcrsZCwenyO4KbXCeAvzhzffi +7MA0BM0oNC9hkXL+nOmFg/+OTxIy7vKBg8P+OxtMb61zO7X8vC7CIAXFjvGDfRaD +ssbzSibBsu/6iGtCOGEoXJf//////////wIBAg== +-----END DH PARAMETERS----- \ No newline at end of file diff --git a/certs/statickeys/dh-ffdhe2048.der b/certs/statickeys/dh-ffdhe2048.der new file mode 100644 index 0000000000000000000000000000000000000000..f59cec3d22f02d9bd656f4b371fc786e76e3d005 GIT binary patch literal 323 zcmXqLVzg&sWH4xA6ldeqYV&CO&dbQmXwbyS!PLaa$nYNu*8T{IShU+~*7`eP3hK5t zA8+hD+I&veZ0gE~W{x5$#=p-@o_kJZw%yNK{m044Jf%0jHEv>BcO{yaSU{n48PCM;()O!N~c7X6#^vbFhtpTCgNyHAbHhyPhi`{b`Jw%+<@ zkKQ2#)}wtNn`_0IHy!)zrFL-B`(GW|P8Nw8G1H;m{?Ek7#3Iim8}qyE`>#Nz%EEaE YG-oiMw@Y>VX0l_$!BDI3C!BWx0JWi{>;M1& literal 0 HcmV?d00001 diff --git a/certs/statickeys/dh-ffdhe2048.pem b/certs/statickeys/dh-ffdhe2048.pem new file mode 100644 index 0000000000..957a02544f --- /dev/null +++ b/certs/statickeys/dh-ffdhe2048.pem @@ -0,0 +1,9 @@ +-----BEGIN PRIVATE KEY----- +MIIBPwIBADCCARcGCSqGSIb3DQEDATCCAQgCggEBAP//////////rfhUWKK7Spqv +3FYgJz088di5xYPOLTaVqeE2QRRkM/vMk53OJJs++X0v42NjDHXY9oGyAq7EYXrT +3x7V1f1lYSQz9R9fBm7QhWNlVT3tGvO1VxNef1fJNZhPDHDg5ot34qaJ2vPv6HId +8VihNq3nNTCsyk9IOnl6vAqxgrMk+2HRCKlLssjj+7lq2rdg1/RoHU9Co945TfSu +Vu3nY3K7GQsHp8juCm1wngL84c334uzANATNKDQvYZFy/pzphYP/jk8SMu7ygYPD +/jsbTG+tczu1/LwuwiAFxY7xg30Wg7LG80omwbLv+ohrQjhhKFyX//////////8C +AQIEHwIdXPuG9/pRAnlxnsApmAPPPmVG9jS4sMFVOvfIQ7g= +-----END PRIVATE KEY----- diff --git a/certs/statickeys/ecc-secp256r1.der b/certs/statickeys/ecc-secp256r1.der new file mode 100644 index 0000000000000000000000000000000000000000..69614a58c7a03712bb79cd627c4393e46cefec89 GIT binary patch literal 121 zcmXpgXJTYzQMjCaETin+jpalpn_cli_protos = NULL; } #endif +#ifdef WOLFSSL_STATIC_EPHEMERAL + if (ctx->staticKE.key) { + FreeDer(&ctx->staticKE.key); + } +#endif #ifdef WOLFSSL_STATIC_MEMORY if (ctx->heap != NULL) { #ifdef WOLFSSL_HEAP_TEST @@ -5680,6 +5685,10 @@ int InitSSL(WOLFSSL* ssl, WOLFSSL_CTX* ctx, int writeDup) ssl->options.useClientOrder = ctx->useClientOrder; ssl->options.mutualAuth = ctx->mutualAuth; +#ifdef WOLFSSL_STATIC_EPHEMERAL + ssl->staticKE = ctx->staticKE; +#endif + #ifdef WOLFSSL_TLS13 #ifdef HAVE_SESSION_TICKET ssl->options.noTicketTls13 = ctx->noTicketTls13; @@ -6409,6 +6418,11 @@ void SSL_ResourceFree(WOLFSSL* ssl) XFREE(curr, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER); } #endif +#ifdef WOLFSSL_STATIC_EPHEMERAL + if (ssl->staticKE.key != NULL && ssl->staticKE.key != ssl->ctx->staticKE.key) { + FreeDer(&ssl->staticKE.key); + } +#endif #ifdef WOLFSSL_STATIC_MEMORY /* check if using fixed io buffers and free them */ @@ -7674,49 +7688,46 @@ static int EdDSA_Update(WOLFSSL* ssl, const byte* data, int sz) } #endif /* (HAVE_ED25519 || HAVE_ED448) && !WOLFSSL_NO_CLIENT_AUTH */ -int HashOutputRaw(WOLFSSL* ssl, const byte* output, int sz) +int HashRaw(WOLFSSL* ssl, const byte* data, int sz) { int ret = 0; - (void)output; + (void)data; (void)sz; - if (ssl->hsHashes == NULL) + if (ssl->hsHashes == NULL) { return BAD_FUNC_ARG; + } -#ifdef HAVE_FUZZER - if (ssl->fuzzerCb) - ssl->fuzzerCb(ssl, output, sz, FUZZ_HASH, ssl->fuzzerCtx); -#endif #ifndef NO_OLD_TLS #ifndef NO_SHA - wc_ShaUpdate(&ssl->hsHashes->hashSha, output, sz); + wc_ShaUpdate(&ssl->hsHashes->hashSha, data, sz); #endif #ifndef NO_MD5 - wc_Md5Update(&ssl->hsHashes->hashMd5, output, sz); + wc_Md5Update(&ssl->hsHashes->hashMd5, data, sz); #endif #endif /* NO_OLD_TLS */ if (IsAtLeastTLSv1_2(ssl)) { #ifndef NO_SHA256 - ret = wc_Sha256Update(&ssl->hsHashes->hashSha256, output, sz); + ret = wc_Sha256Update(&ssl->hsHashes->hashSha256, data, sz); if (ret != 0) return ret; #endif #ifdef WOLFSSL_SHA384 - ret = wc_Sha384Update(&ssl->hsHashes->hashSha384, output, sz); + ret = wc_Sha384Update(&ssl->hsHashes->hashSha384, data, sz); if (ret != 0) return ret; #endif #ifdef WOLFSSL_SHA512 - ret = wc_Sha512Update(&ssl->hsHashes->hashSha512, output, sz); + ret = wc_Sha512Update(&ssl->hsHashes->hashSha512, data, sz); if (ret != 0) return ret; #endif #if !defined(WOLFSSL_NO_CLIENT_AUTH) && \ ((defined(HAVE_ED25519) && !defined(NO_ED25519_CLIENT_AUTH)) || \ (defined(HAVE_ED448) && !defined(NO_ED448_CLIENT_AUTH))) - ret = EdDSA_Update(ssl, output, sz); + ret = EdDSA_Update(ssl, data, sz); if (ret != 0) return ret; #endif @@ -7728,7 +7739,6 @@ int HashOutputRaw(WOLFSSL* ssl, const byte* output, int sz) /* add output to md5 and sha handshake hashes, exclude record header */ int HashOutput(WOLFSSL* ssl, const byte* output, int sz, int ivSz) { - int ret = 0; const byte* adj; if (ssl->hsHashes == NULL) @@ -7747,55 +7757,23 @@ int HashOutput(WOLFSSL* ssl, const byte* output, int sz, int ivSz) sz -= DTLS_RECORD_EXTRA; } #endif -#ifndef NO_OLD_TLS - #ifndef NO_SHA - wc_ShaUpdate(&ssl->hsHashes->hashSha, adj, sz); - #endif - #ifndef NO_MD5 - wc_Md5Update(&ssl->hsHashes->hashMd5, adj, sz); - #endif -#endif - if (IsAtLeastTLSv1_2(ssl)) { - #ifndef NO_SHA256 - ret = wc_Sha256Update(&ssl->hsHashes->hashSha256, adj, sz); - if (ret != 0) - return ret; - #endif - #ifdef WOLFSSL_SHA384 - ret = wc_Sha384Update(&ssl->hsHashes->hashSha384, adj, sz); - if (ret != 0) - return ret; - #endif - #ifdef WOLFSSL_SHA512 - ret = wc_Sha512Update(&ssl->hsHashes->hashSha512, adj, sz); - if (ret != 0) - return ret; - #endif - #if !defined(WOLFSSL_NO_CLIENT_AUTH) && \ - ((defined(HAVE_ED25519) && !defined(NO_ED25519_CLIENT_AUTH)) || \ - (defined(HAVE_ED448) && !defined(NO_ED448_CLIENT_AUTH))) - ret = EdDSA_Update(ssl, adj, sz); - if (ret != 0) - return ret; - #endif - } - - return ret; + return HashRaw(ssl, adj, sz); } /* add input to md5 and sha handshake hashes, include handshake header */ int HashInput(WOLFSSL* ssl, const byte* input, int sz) { - int ret = 0; const byte* adj; + if (ssl->hsHashes == NULL) { + return BAD_FUNC_ARG; + } + adj = input - HANDSHAKE_HEADER_SZ; sz += HANDSHAKE_HEADER_SZ; - (void)adj; - #ifdef WOLFSSL_DTLS if (ssl->options.dtls) { adj -= DTLS_HANDSHAKE_EXTRA; @@ -7803,45 +7781,7 @@ int HashInput(WOLFSSL* ssl, const byte* input, int sz) } #endif - if (ssl->hsHashes == NULL) { - return BAD_FUNC_ARG; - } - -#ifndef NO_OLD_TLS - #ifndef NO_SHA - wc_ShaUpdate(&ssl->hsHashes->hashSha, adj, sz); - #endif - #ifndef NO_MD5 - wc_Md5Update(&ssl->hsHashes->hashMd5, adj, sz); - #endif -#endif - - if (IsAtLeastTLSv1_2(ssl)) { - #ifndef NO_SHA256 - ret = wc_Sha256Update(&ssl->hsHashes->hashSha256, adj, sz); - if (ret != 0) - return ret; - #endif - #ifdef WOLFSSL_SHA384 - ret = wc_Sha384Update(&ssl->hsHashes->hashSha384, adj, sz); - if (ret != 0) - return ret; - #endif - #ifdef WOLFSSL_SHA512 - ret = wc_Sha512Update(&ssl->hsHashes->hashSha512, adj, sz); - if (ret != 0) - return ret; - #endif - #if !defined(WOLFSSL_NO_CLIENT_AUTH) && \ - ((defined(HAVE_ED25519) && !defined(NO_ED25519_CLIENT_AUTH)) || \ - (defined(HAVE_ED448) && !defined(NO_ED448_CLIENT_AUTH))) - ret = EdDSA_Update(ssl, adj, sz); - if (ret != 0) - return ret; - #endif - } - - return ret; + return HashRaw(ssl, adj, sz); } @@ -16920,15 +16860,15 @@ int SendCertificate(WOLFSSL* ssl) if (!ssl->options.dtls) { AddFragHeaders(output, fragSz, 0, payloadSz, certificate, ssl); if (!IsEncryptionOn(ssl, 1)) - HashOutputRaw(ssl, output + RECORD_HEADER_SZ, + HashRaw(ssl, output + RECORD_HEADER_SZ, HANDSHAKE_HEADER_SZ); } else { #ifdef WOLFSSL_DTLS AddHeaders(output, payloadSz, certificate, ssl); - HashOutputRaw(ssl, - output + RECORD_HEADER_SZ + DTLS_RECORD_EXTRA, - HANDSHAKE_HEADER_SZ + DTLS_HANDSHAKE_EXTRA); + HashRaw(ssl, + output + RECORD_HEADER_SZ + DTLS_RECORD_EXTRA, + HANDSHAKE_HEADER_SZ + DTLS_HANDSHAKE_EXTRA); /* Adding the headers increments these, decrement them for * actual message header. */ ssl->keys.dtls_handshake_number--; @@ -16940,22 +16880,22 @@ int SendCertificate(WOLFSSL* ssl) /* list total */ c32to24(listSz, output + i); if (ssl->options.dtls || !IsEncryptionOn(ssl, 1)) - HashOutputRaw(ssl, output + i, CERT_HEADER_SZ); + HashRaw(ssl, output + i, CERT_HEADER_SZ); i += CERT_HEADER_SZ; length -= CERT_HEADER_SZ; fragSz -= CERT_HEADER_SZ; if (certSz) { c32to24(certSz, output + i); if (ssl->options.dtls || !IsEncryptionOn(ssl, 1)) - HashOutputRaw(ssl, output + i, CERT_HEADER_SZ); + HashRaw(ssl, output + i, CERT_HEADER_SZ); i += CERT_HEADER_SZ; length -= CERT_HEADER_SZ; fragSz -= CERT_HEADER_SZ; if (ssl->options.dtls || !IsEncryptionOn(ssl, 1)) { - HashOutputRaw(ssl, ssl->buffers.certificate->buffer, certSz); + HashRaw(ssl, ssl->buffers.certificate->buffer, certSz); if (certChainSz) - HashOutputRaw(ssl, ssl->buffers.certChain->buffer, + HashRaw(ssl, ssl->buffers.certChain->buffer, certChainSz); } } @@ -21004,7 +20944,7 @@ exit_dpk: return ret; } -#endif /* HAVE_ECC */ +#endif /* HAVE_ECC || HAVE_CURVE25519 || HAVE_CURVE448 */ /* Persistable DoServerKeyExchange arguments */ typedef struct DskeArgs { @@ -28077,6 +28017,7 @@ static int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx, #endif } InternalTicket; + /* RFC 5077 defines this for session tickets */ /* fit within SESSION_TICKET_LEN */ typedef struct ExternalTicket { byte key_name[WOLFSSL_TICKET_NAME_SZ]; /* key context name */ diff --git a/src/sniffer.c b/src/sniffer.c index 72b4c1077a..31c77077b7 100644 --- a/src/sniffer.c +++ b/src/sniffer.c @@ -44,7 +44,6 @@ #define SNPRINTF snprintf #endif -#include #include #include #include @@ -90,13 +89,36 @@ enum { TRACE_MSG_SZ = 80, /* Trace Message buffer size */ HASH_SIZE = 499, /* Session Hash Table Rows */ PSEUDO_HDR_SZ = 12, /* TCP Pseudo Header size in bytes */ - FATAL_ERROR_STATE = 1, /* SnifferSession fatal error state */ + FATAL_ERROR_STATE = 1, /* SnifferSession fatal error state */ TICKET_HINT_LEN = 4, /* Session Ticket Hint length */ - EXT_TYPE_SZ = 2, /* Extension length */ + TICKET_HINT_AGE_LEN= 4, /* Session Ticket Age add length */ + EXT_TYPE_SZ = 2, /* Extension type length */ MAX_INPUT_SZ = MAX_RECORD_SIZE + COMP_EXTRA + MAX_MSG_EXTRA + MTU_EXTRA, /* Max input sz of reassembly */ - EXT_MASTER_SECRET = 0x17, /* Extended Master Secret Extension ID */ - TICKET_EXT_ID = 0x23 /* Session Ticket Extension ID */ + + /* TLS Extensions */ + EXT_SERVER_NAME = 0x0000, /* a.k.a. SNI */ + EXT_MAX_FRAGMENT_LENGTH = 0x0001, + EXT_TRUSTED_CA_KEYS = 0x0003, + EXT_TRUNCATED_HMAC = 0x0004, + EXT_STATUS_REQUEST = 0x0005, /* a.k.a. OCSP stapling */ + EXT_SUPPORTED_GROUPS = 0x000a, /* a.k.a. Supported Curves */ + EXT_EC_POINT_FORMATS = 0x000b, + EXT_SIGNATURE_ALGORITHMS = 0x000d, + EXT_APPLICATION_LAYER_PROTOCOL = 0x0010, /* a.k.a. ALPN */ + EXT_STATUS_REQUEST_V2 = 0x0011, /* a.k.a. OCSP stapling v2 */ + EXT_ENCRYPT_THEN_MAC = 0x0016, /* RFC 7366 */ + EXT_MASTER_SECRET = 0x0017, /* Extended Master Secret Extension ID */ + EXT_TICKET_ID = 0x0023, /* Session Ticket Extension ID */ + EXT_PRE_SHARED_KEY = 0x0029, + EXT_EARLY_DATA = 0x002a, + EXT_SUPPORTED_VERSIONS = 0x002b, + EXT_COOKIE = 0x002c, + EXT_PSK_KEY_EXCHANGE_MODES = 0x002d, + EXT_POST_HANDSHAKE_AUTH = 0x0031, + EXT_SIGNATURE_ALGORITHMS_CERT = 0x0032, + EXT_KEY_SHARE = 0x0033, + EXT_RENEGOTIATION_INFO = 0xff01 }; @@ -275,7 +297,8 @@ static const char* const msgTable[] = /* 91 */ "No data destination Error", "Store data callback failed", - "Loading chain input" + "Loading chain input", + "Got encrypted extension", }; @@ -318,6 +341,7 @@ typedef struct NamedKey { word32 nameSz; /* size of server DNS name */ byte* key; /* DER private key */ word32 keySz; /* size of DER private key */ + int isEphemeralKey; struct NamedKey* next; /* for list */ } NamedKey; @@ -335,7 +359,7 @@ typedef struct IpAddrInfo { /* Sniffer Server holds info for each server/port monitored */ typedef struct SnifferServer { - SSL_CTX* ctx; /* SSL context */ + WOLFSSL_CTX* ctx; /* SSL context */ char address[MAX_SERVER_ADDRESS]; /* passed in server address */ IpAddrInfo server; /* network order address */ int port; /* server port */ @@ -364,16 +388,17 @@ typedef struct Flags { #ifdef HAVE_EXTENDED_MASTER byte expectEms; /* expect extended master secret */ #endif + byte gotFinished; /* processed finished */ } Flags; /* Out of Order FIN capture */ -typedef struct FinCaputre { +typedef struct FinCapture { word32 cliFinSeq; /* client relative sequence FIN 0 is no */ word32 srvFinSeq; /* server relative sequence FIN, 0 is no */ byte cliCounted; /* did we count yet, detects duplicates */ byte srvCounted; /* did we count yet, detects duplicates */ -} FinCaputre; +} FinCapture; typedef struct HsHashes { @@ -384,7 +409,7 @@ typedef struct HsHashes { #ifndef NO_MD5 wc_Md5 hashMd5; #endif -#endif +#endif /* !NO_OLD_TLS */ #ifndef NO_SHA256 wc_Sha256 hashSha256; #endif @@ -393,12 +418,22 @@ typedef struct HsHashes { #endif } HsHashes; +typedef struct KeyShareInfo { + word16 named_group; + int key_len; + const byte* key; + + /* additional info */ + int dh_key_bits; + int curve_id; +} KeyShareInfo; + /* Sniffer Session holds info for each client/server SSL/TLS session */ typedef struct SnifferSession { SnifferServer* context; /* server context */ - SSL* sslServer; /* SSL server side decode */ - SSL* sslClient; /* SSL client side decode */ + WOLFSSL* sslServer; /* SSL server side decode */ + WOLFSSL* sslClient; /* SSL client side decode */ IpAddrInfo server; /* server address in network byte order */ IpAddrInfo client; /* client address in network byte order */ word16 srvPort; /* server port */ @@ -407,21 +442,27 @@ typedef struct SnifferSession { word32 srvSeqStart; /* server start sequence */ word32 cliExpected; /* client expected sequence (relative) */ word32 srvExpected; /* server expected sequence (relative) */ - FinCaputre finCaputre; /* retain out of order FIN s */ + FinCapture finCapture; /* retain out of order FIN s */ Flags flags; /* session flags */ - time_t lastUsed; /* last used ticks */ + time_t lastUsed; /* last used ticks */ word32 keySz; /* size of the private key */ PacketBuffer* cliReassemblyList; /* client out of order packets */ PacketBuffer* srvReassemblyList; /* server out of order packets */ word32 cliReassemblyMemory; /* client packet memory used */ word32 srvReassemblyMemory; /* server packet memory used */ - struct SnifferSession* next; /* for hash table list */ - byte* ticketID; /* mac ID of session ticket */ + struct SnifferSession* next; /* for hash table list */ + byte* ticketID; /* mac ID of session ticket */ #ifdef HAVE_SNI const char* sni; /* server name indication */ #endif #ifdef HAVE_EXTENDED_MASTER - HsHashes* hash; + HsHashes* hash; +#endif +#ifdef WOLFSSL_TLS13 + byte* cliKeyShare; + word32 cliKeyShareSz; + KeyShareInfo srvKs; + KeyShareInfo cliKs; #endif } SnifferSession; @@ -603,6 +644,10 @@ static void FreeSnifferSession(SnifferSession* session) XFREE(session->ticketID, NULL, DYNAMIC_TYPE_SNIFFER_TICKET_ID); #ifdef HAVE_EXTENDED_MASTER XFREE(session->hash, NULL, DYNAMIC_TYPE_HASHES); +#endif +#ifdef WOLFSSL_TLS13 + if (session->cliKeyShare) + XFREE(session->cliKeyShare, NULL, DYNAMIC_TYPE_TMP_BUFFER); #endif } XFREE(session, NULL, DYNAMIC_TYPE_SNIFFER_SESSION); @@ -677,11 +722,10 @@ static int HashInit(HsHashes* hash) ret = wc_InitSha(&hash->hashSha); #endif #ifndef NO_MD5 - if (ret == 0) { + if (ret == 0) ret = wc_InitMd5(&hash->hashMd5); - } -#endif #endif +#endif /* !NO_OLD_TLS */ #ifndef NO_SHA256 if (ret == 0) ret = wc_InitSha256(&hash->hashSha256); @@ -694,7 +738,6 @@ static int HashInit(HsHashes* hash) return ret; } - static int HashUpdate(HsHashes* hash, const byte* input, int sz) { int ret = 0; @@ -708,11 +751,10 @@ static int HashUpdate(HsHashes* hash, const byte* input, int sz) ret = wc_ShaUpdate(&hash->hashSha, input, sz); #endif #ifndef NO_MD5 - if (ret == 0) { + if (ret == 0) ret = wc_Md5Update(&hash->hashMd5, input, sz); - } -#endif #endif +#endif /* !NO_OLD_TLS */ #ifndef NO_SHA256 if (ret == 0) ret = wc_Sha256Update(&hash->hashSha256, input, sz); @@ -725,23 +767,21 @@ static int HashUpdate(HsHashes* hash, const byte* input, int sz) return ret; } - static int HashCopy(HS_Hashes* d, HsHashes* s) { #ifndef NO_OLD_TLS #ifndef NO_SHA - XMEMCPY(&d->hashSha, &s->hashSha, sizeof(wc_Sha)); + XMEMCPY(&d->hashSha, &s->hashSha, sizeof(wc_Sha)); #endif #ifndef NO_MD5 - XMEMCPY(&d->hashMd5, &s->hashMd5, sizeof(wc_Md5)); + XMEMCPY(&d->hashMd5, &s->hashMd5, sizeof(wc_Md5)); #endif -#endif - +#endif /* !NO_OLD_TLS */ #ifndef NO_SHA256 - XMEMCPY(&d->hashSha256, &s->hashSha256, sizeof(wc_Sha256)); + XMEMCPY(&d->hashSha256, &s->hashSha256, sizeof(wc_Sha256)); #endif #ifdef WOLFSSL_SHA384 - XMEMCPY(&d->hashSha384, &s->hashSha384, sizeof(wc_Sha384)); + XMEMCPY(&d->hashSha384, &s->hashSha384, sizeof(wc_Sha384)); #endif return 0; @@ -765,9 +805,9 @@ static void InitFlags(Flags* flags) /* Initialize FIN Capture */ -static void InitFinCapture(FinCaputre* cap) +static void InitFinCapture(FinCapture* cap) { - XMEMSET(cap, 0, sizeof(FinCaputre)); + XMEMSET(cap, 0, sizeof(FinCapture)); } @@ -776,7 +816,7 @@ static void InitSession(SnifferSession* session) { XMEMSET(session, 0, sizeof(SnifferSession)); InitFlags(&session->flags); - InitFinCapture(&session->finCaputre); + InitFinCapture(&session->finCapture); } @@ -1461,7 +1501,7 @@ static int CreateWatchSnifferServer(char* error) return -1; } InitSnifferServer(sniffer); - sniffer->ctx = SSL_CTX_new(TLSv1_2_client_method()); + sniffer->ctx = SSL_CTX_new(SSLv23_client_method()); if (!sniffer->ctx) { SetError(MEMORY_STR, error, NULL, 0); FreeSnifferServer(sniffer); @@ -1480,7 +1520,8 @@ static int CreateWatchSnifferServer(char* error) static int SetNamedPrivateKey(const char* name, const char* address, int port, - const char* keyFile, int keySz, int typeKey, const char* password, char* error) + const char* keyFile, int keySz, int typeKey, const char* password, + char* error, int isEphemeralKey) { SnifferServer* sniffer; int ret; @@ -1509,7 +1550,7 @@ static int SetNamedPrivateKey(const char* name, const char* address, int port, namedKey->nameSz = sizeof(namedKey->name)-1; XSTRNCPY(namedKey->name, name, namedKey->nameSz); namedKey->name[MAX_SERVER_NAME-1] = '\0'; - + namedKey->isEphemeralKey = isEphemeralKey; ret = LoadKeyFile(&namedKey->key, &namedKey->keySz, keyFile, keySz, type, password); if (ret < 0) { @@ -1551,7 +1592,7 @@ static int SetNamedPrivateKey(const char* name, const char* address, int port, sniffer->server = serverIp; sniffer->port = port; - sniffer->ctx = SSL_CTX_new(TLSv1_2_client_method()); + sniffer->ctx = SSL_CTX_new(SSLv23_client_method()); if (!sniffer->ctx) { SetError(MEMORY_STR, error, NULL, 0); #ifdef HAVE_SNI @@ -1570,12 +1611,26 @@ static int SetNamedPrivateKey(const char* name, const char* address, int port, sniffer->ctx, (void*)password); #endif } - if (keySz == 0) { - ret = SSL_CTX_use_PrivateKey_file(sniffer->ctx, keyFile, type); + + #ifdef WOLFSSL_STATIC_EPHEMERAL + if (isEphemeralKey) { + /* auto detect key type with WC_PK_TYPE_NONE */ + /* keySz == 0 mean load file */ + ret = wolfSSL_CTX_set_ephemeral_key(sniffer->ctx, WC_PK_TYPE_NONE, + keyFile, 0, type); + if (ret == 0) + ret = WOLFSSL_SUCCESS; } - else { - ret = wolfSSL_CTX_use_PrivateKey_buffer(sniffer->ctx, - (const byte*)keyFile, keySz, type); + else + #endif + { + if (keySz == 0) { + ret = SSL_CTX_use_PrivateKey_file(sniffer->ctx, keyFile, type); + } + else { + ret = wolfSSL_CTX_use_PrivateKey_buffer(sniffer->ctx, + (const byte*)keyFile, keySz, type); + } } if (ret != WOLFSSL_SUCCESS) { SetError(KEY_FILE_STR, error, NULL, 0); @@ -1606,7 +1661,6 @@ static int SetNamedPrivateKey(const char* name, const char* address, int port, #ifdef HAVE_SNI - /* Sets the private key for a specific name, server and port */ /* returns 0 on success, -1 on error */ int ssl_SetNamedPrivateKey(const char* name, @@ -1621,7 +1675,7 @@ int ssl_SetNamedPrivateKey(const char* name, wc_LockMutex(&ServerListMutex); ret = SetNamedPrivateKey(name, address, port, keyFile, 0, - typeKey, password, error); + typeKey, password, error, 0); wc_UnLockMutex(&ServerListMutex); if (ret == 0) @@ -1630,12 +1684,10 @@ int ssl_SetNamedPrivateKey(const char* name, return ret; } - int ssl_SetNamedPrivateKeyBuffer(const char* name, - const char* address, int port, - const char* keyBuf, int keySz, - int typeKey, const char* password, - char* error) + const char* address, int port, + const char* keyBuf, int keySz, int typeKey, + const char* password, char* error) { int ret; @@ -1644,7 +1696,7 @@ int ssl_SetNamedPrivateKeyBuffer(const char* name, wc_LockMutex(&ServerListMutex); ret = SetNamedPrivateKey(name, address, port, keyBuf, keySz, - typeKey, password, error); + typeKey, password, error, 0); wc_UnLockMutex(&ServerListMutex); if (ret == 0) @@ -1652,14 +1704,13 @@ int ssl_SetNamedPrivateKeyBuffer(const char* name, return ret; } - -#endif - +#endif /* HAVE_SNI */ /* Sets the private key for a specific server and port */ /* returns 0 on success, -1 on error */ -int ssl_SetPrivateKey(const char* address, int port, const char* keyFile, - int typeKey, const char* password, char* error) +int ssl_SetPrivateKey(const char* address, int port, + const char* keyFile, int typeKey, + const char* password, char* error) { int ret; @@ -1668,7 +1719,7 @@ int ssl_SetPrivateKey(const char* address, int port, const char* keyFile, wc_LockMutex(&ServerListMutex); ret = SetNamedPrivateKey(NULL, address, port, keyFile, 0, - typeKey, password, error); + typeKey, password, error, 0); wc_UnLockMutex(&ServerListMutex); if (ret == 0) @@ -1678,9 +1729,8 @@ int ssl_SetPrivateKey(const char* address, int port, const char* keyFile, } int ssl_SetPrivateKeyBuffer(const char* address, int port, - const char* keyBuf, int keySz, - int typeKey, const char* password, - char* error) + const char* keyBuf, int keySz, int typeKey, + const char* password, char* error) { int ret; @@ -1689,7 +1739,7 @@ int ssl_SetPrivateKeyBuffer(const char* address, int port, wc_LockMutex(&ServerListMutex); ret = SetNamedPrivateKey(NULL, address, port, keyBuf, keySz, - typeKey, password, error); + typeKey, password, error, 0); wc_UnLockMutex(&ServerListMutex); if (ret == 0) @@ -1698,6 +1748,95 @@ int ssl_SetPrivateKeyBuffer(const char* address, int port, return ret; } +#ifdef WOLFSSL_STATIC_EPHEMERAL +#ifdef HAVE_SNI +/* Sets the ephemeral key for a specific name, server and port */ +/* returns 0 on success, -1 on error */ +int ssl_SetNamedEphemeralKey(const char* name, + const char* address, int port, + const char* keyFile, int typeKey, + const char* password, char* error) +{ + int ret; + + TraceHeader(); + TraceSetNamedServer(name, address, port, keyFile); + + wc_LockMutex(&ServerListMutex); + ret = SetNamedPrivateKey(name, address, port, keyFile, 0, + typeKey, password, error, 1); + wc_UnLockMutex(&ServerListMutex); + + if (ret == 0) + Trace(NEW_SERVER_STR); + + return ret; +} + +int ssl_SetNamedEphemeralKeyBuffer(const char* name, + const char* address, int port, + const char* keyBuf, int keySz, int typeKey, + const char* password, char* error) +{ + int ret; + + TraceHeader(); + TraceSetNamedServer(name, address, port, NULL); + + wc_LockMutex(&ServerListMutex); + ret = SetNamedPrivateKey(name, address, port, keyBuf, keySz, + typeKey, password, error, 1); + wc_UnLockMutex(&ServerListMutex); + + if (ret == 0) + Trace(NEW_SERVER_STR); + + return ret; +} +#endif /* HAVE_SNI */ + +/* Sets the ephemeral key for a specific server and port */ +/* returns 0 on success, -1 on error */ +int ssl_SetEphemeralKey(const char* address, int port, + const char* keyFile, int typeKey, + const char* password, char* error) +{ + int ret; + + TraceHeader(); + TraceSetServer(address, port, keyFile); + + wc_LockMutex(&ServerListMutex); + ret = SetNamedPrivateKey(NULL, address, port, keyFile, 0, + typeKey, password, error, 1); + wc_UnLockMutex(&ServerListMutex); + + if (ret == 0) + Trace(NEW_SERVER_STR); + + return ret; +} + +int ssl_SetEphemeralKeyBuffer(const char* address, int port, + const char* keyBuf, int keySz, int typeKey, + const char* password, char* error) +{ + int ret; + + TraceHeader(); + TraceSetServer(address, port, NULL); + + wc_LockMutex(&ServerListMutex); + ret = SetNamedPrivateKey(NULL, address, port, keyBuf, keySz, + typeKey, password, error, 1); + wc_UnLockMutex(&ServerListMutex); + + if (ret == 0) + Trace(NEW_SERVER_STR); + + return ret; +} +#endif /* WOLFSSL_STATIC_EPHEMERAL */ /* Check IP Header for IPV6, TCP, and a registered server address */ /* returns 0 on success, -1 on error */ @@ -1739,7 +1878,7 @@ static int CheckIp6Hdr(Ip6Hdr* iphdr, IpInfo* info, int length, char* error) info->length = exthdrsz; info->total = ntohs(iphdr->length) + info->length; - /* IPv6 doesn't include its own header size in the length like v4. */ + /* IPv6 doesn't include its own header size in the length like v4. */ info->src.version = IPV6; XMEMCPY(info->src.ip6, iphdr->src, sizeof(info->src.ip6)); info->dst.version = IPV6; @@ -1863,14 +2002,14 @@ static void CopySessionInfo(SnifferSession* session, SSLInfo* sslInfo) [sizeof(sslInfo->serverCipherSuiteName) - 1] = '\0'; } sslInfo->keySize = session->keySz; - #ifdef HAVE_SNI + #ifdef HAVE_SNI if (NULL != session->sni) { XSTRNCPY((char*)sslInfo->serverNameIndication, session->sni, sizeof(sslInfo->serverNameIndication)); sslInfo->serverNameIndication [sizeof(sslInfo->serverNameIndication) - 1] = '\0'; } - #endif + #endif TraceSessionInfo(sslInfo); } } @@ -1887,41 +2026,50 @@ static void CallConnectionCb(SnifferSession* session) } } +#ifdef SHOW_SECRETS +static void ShowTlsSecrets(SnifferSession* session) +{ + int i; + printf("server master secret: "); + for (i = 0; i < SECRET_LEN; i++) + printf("%02x", session->sslServer->arrays->masterSecret[i]); + printf("\n"); -/* Process Client Key Exchange, RSA or static ECDH */ -static int ProcessClientKeyExchange(const byte* input, int* sslBytes, - SnifferSession* session, char* error) + printf("client master secret: "); + for (i = 0; i < SECRET_LEN; i++) + printf("%02x", session->sslClient->arrays->masterSecret[i]); + printf("\n"); + + printf("server suite = %d\n", session->sslServer->options.cipherSuite); + printf("client suite = %d\n", session->sslClient->options.cipherSuite); +} +#endif + + +/* Process Keys */ +static int SetupKeys(const byte* input, int* sslBytes, SnifferSession* session, + char* error, KeyShareInfo* ksInfo, DerBuffer* keyBuf) { word32 idx = 0; - int tryEcc = 0; int ret; - if (session->sslServer->buffers.key == NULL || - session->sslServer->buffers.key->buffer == NULL || - session->sslServer->buffers.key->length == 0) { - - SetError(RSA_KEY_MISSING_STR, error, session, FATAL_ERROR_STATE); - return -1; - } - - { +#ifndef NO_RSA + /* Static RSA */ + if (ksInfo == NULL) { RsaKey key; int length; ret = wc_InitRsaKey(&key, 0); if (ret == 0) { - ret = wc_RsaPrivateKeyDecode( - session->sslServer->buffers.key->buffer, - &idx, &key, session->sslServer->buffers.key->length); + ret = wc_RsaPrivateKeyDecode(keyBuf->buffer, &idx, &key, keyBuf->length); if (ret != 0) { - tryEcc = 1; - #ifndef HAVE_ECC - SetError(RSA_DECODE_STR, error, session, FATAL_ERROR_STATE); - #else - /* If we can do ECC, this isn't fatal. Not loading an ECC - * key will be fatal, though. */ - SetError(RSA_DECODE_STR, error, session, 0); - #endif + #ifndef HAVE_ECC + SetError(RSA_DECODE_STR, error, session, FATAL_ERROR_STATE); + #else + /* If we can do ECC, this isn't fatal. Not loading an ECC + * key will be fatal, though. */ + SetError(RSA_DECODE_STR, error, session, 0); + #endif } } @@ -1970,9 +2118,99 @@ static int ProcessClientKeyExchange(const byte* input, int* sslBytes, wc_FreeRsaKey(&key); } +#endif /* !NO_RSA */ + +#if !defined(NO_DH) && defined(WOLFSSL_DH_EXTRA) + /* Static Ephemeral DH Key */ + if (ksInfo && ksInfo->dh_key_bits != 0) { + DhKey dhKey; + const DhParams* params; + word32 privKeySz; + byte privKey[52]; /* max for TLS */ + + /* get DH params */ + switch (ksInfo->named_group) { + #ifdef HAVE_FFDHE_2048 + case WOLFSSL_FFDHE_2048: + params = wc_Dh_ffdhe2048_Get(); + privKeySz = 29; + break; + #endif + #ifdef HAVE_FFDHE_3072 + case WOLFSSL_FFDHE_3072: + params = wc_Dh_ffdhe3072_Get(); + privKeySz = 34; + break; + #endif + #ifdef HAVE_FFDHE_4096 + case WOLFSSL_FFDHE_4096: + params = wc_Dh_ffdhe4096_Get(); + privKeySz = 39; + break; + #endif + #ifdef HAVE_FFDHE_6144 + case WOLFSSL_FFDHE_6144: + params = wc_Dh_ffdhe6144_Get(); + privKeySz = 46; + break; + #endif + #ifdef HAVE_FFDHE_8192 + case WOLFSSL_FFDHE_8192: + params = wc_Dh_ffdhe8192_Get(); + privKeySz = 52; + break; + #endif + default: + return BAD_FUNC_ARG; + } + + ret = wc_InitDhKey(&dhKey); + if (ret == 0) { + ret = wc_DhSetKey(&dhKey, + (byte*)params->p, params->p_len, + (byte*)params->g, params->g_len); + if (ret == 0) { + ret = wc_DhKeyDecode(keyBuf->buffer, &idx, &dhKey, + keyBuf->length); + } + if (ret == 0) { + ret = wc_DhExportKeyPair(&dhKey, privKey, &privKeySz, NULL, + NULL); + } + + /* Derive secret from private key and peer's public key */ + do { + #ifdef WOLFSSL_ASYNC_CRYPT + ret = wc_AsyncWait(ret, &dhPriv.asyncDev, + WC_ASYNC_FLAG_CALL_AGAIN); + #endif + if (ret >= 0) { + ret = wc_DhAgree(&dhKey, + session->sslServer->arrays->preMasterSecret, + &session->sslServer->arrays->preMasterSz, + privKey, privKeySz, + input, *sslBytes); + } + } while (ret == WC_PENDING_E); + + wc_FreeDhKey(&dhKey); + + /* left-padded with zeros up to the size of the prime */ + if (params->p_len > session->sslServer->arrays->preMasterSz) { + word32 diff = params->p_len - session->sslServer->arrays->preMasterSz; + XMEMMOVE(session->sslServer->arrays->preMasterSecret + diff, + session->sslServer->arrays->preMasterSecret, + session->sslServer->arrays->preMasterSz); + XMEMSET(session->sslServer->arrays->preMasterSecret, 0, diff); + session->sslServer->arrays->preMasterSz = params->p_len; + } + } + } +#endif /* !NO_DH && WOLFSSL_DH_EXTRA */ - if (tryEcc) { #ifdef HAVE_ECC + /* Static Ephemeral ECC Key */ + if (ksInfo && ksInfo->curve_id != 0) { ecc_key key; ecc_key pubKey; int length, keyInit = 0, pubKeyInit = 0; @@ -1985,9 +2223,7 @@ static int ProcessClientKeyExchange(const byte* input, int* sslBytes, } if (ret == 0) { pubKeyInit = 1; - ret = wc_EccPrivateKeyDecode( - session->sslServer->buffers.key->buffer, - &idx, &key, session->sslServer->buffers.key->length); + ret = wc_EccPrivateKeyDecode(keyBuf->buffer, &idx, &key, keyBuf->length); if (ret != 0) { SetError(ECC_DECODE_STR, error, session, FATAL_ERROR_STATE); } @@ -1997,19 +2233,18 @@ static int ProcessClientKeyExchange(const byte* input, int* sslBytes, length = wc_ecc_size(&key) * 2 + 1; /* The length should be 2 times the key size (x and y), plus 1 * for the type byte. */ - if (IsTLS(session->sslServer)) { + if (IsTLS(session->sslServer) && !IsAtLeastTLSv1_3(session->sslServer->version)) { input += 1; /* Don't include the TLS length for the key. */ } - if (length + 1 > *sslBytes) { - SetError(PARTIAL_INPUT_STR, - error, session, FATAL_ERROR_STATE); + if (length > *sslBytes) { + SetError(PARTIAL_INPUT_STR, error, session, FATAL_ERROR_STATE); ret = -1; } } if (ret == 0) { - ret = wc_ecc_import_x963_ex(input, length, &pubKey, ECC_CURVE_DEF); + ret = wc_ecc_import_x963_ex(input, length, &pubKey, ksInfo->curve_id); if (ret != 0) { SetError(ECC_PUB_DECODE_STR, error, session, FATAL_ERROR_STATE); } @@ -2044,8 +2279,8 @@ static int ProcessClientKeyExchange(const byte* input, int* sslBytes, wc_ecc_free(&key); if (pubKeyInit) wc_ecc_free(&pubKey); -#endif } +#endif /* HAVE_ECC */ /* store for client side as well */ XMEMCPY(session->sslClient->arrays->preMasterSecret, @@ -2054,7 +2289,7 @@ static int ProcessClientKeyExchange(const byte* input, int* sslBytes, session->sslClient->arrays->preMasterSz = session->sslServer->arrays->preMasterSz; - #ifdef SHOW_SECRETS +#ifdef SHOW_SECRETS { word32 i; printf("pre master secret: "); @@ -2062,7 +2297,7 @@ static int ProcessClientKeyExchange(const byte* input, int* sslBytes, printf("%02x", session->sslServer->arrays->preMasterSecret[i]); printf("\n"); } - #endif +#endif if (SetCipherSpecs(session->sslServer) != 0) { SetError(BAD_CIPHER_SPEC_STR, error, session, FATAL_ERROR_STATE); @@ -2074,32 +2309,41 @@ static int ProcessClientKeyExchange(const byte* input, int* sslBytes, return -1; } - ret = MakeMasterSecret(session->sslServer); - ret += MakeMasterSecret(session->sslClient); - ret += SetKeysSide(session->sslServer, ENCRYPT_AND_DECRYPT_SIDE); - ret += SetKeysSide(session->sslClient, ENCRYPT_AND_DECRYPT_SIDE); - +#ifdef WOLFSSL_TLS13 + /* TLS v1.3 derive handshake key */ + if (IsAtLeastTLSv1_3(session->sslServer->version)) { + ret = DeriveEarlySecret(session->sslServer); + ret += DeriveEarlySecret(session->sslClient); + ret += DeriveHandshakeSecret(session->sslServer); + ret += DeriveHandshakeSecret(session->sslClient); + ret += DeriveTls13Keys(session->sslServer, handshake_key, ENCRYPT_AND_DECRYPT_SIDE, 1); + ret += DeriveTls13Keys(session->sslClient, handshake_key, ENCRYPT_AND_DECRYPT_SIDE, 1); + #ifdef WOLFSSL_EARLY_DATA + ret += SetKeysSide(session->sslServer, DECRYPT_SIDE_ONLY); + ret += SetKeysSide(session->sslClient, DECRYPT_SIDE_ONLY); + #else + ret += SetKeysSide(session->sslServer, ENCRYPT_AND_DECRYPT_SIDE); + ret += SetKeysSide(session->sslClient, ENCRYPT_AND_DECRYPT_SIDE); + #endif + } + else +#endif + { + ret = MakeMasterSecret(session->sslServer); + ret += MakeMasterSecret(session->sslClient); + ret += SetKeysSide(session->sslServer, ENCRYPT_AND_DECRYPT_SIDE); + ret += SetKeysSide(session->sslClient, ENCRYPT_AND_DECRYPT_SIDE); + } if (ret != 0) { SetError(BAD_DERIVE_STR, error, session, FATAL_ERROR_STATE); return -1; } #ifdef SHOW_SECRETS - { - int i; - printf("server master secret: "); - for (i = 0; i < SECRET_LEN; i++) - printf("%02x", session->sslServer->arrays->masterSecret[i]); - printf("\n"); - - printf("client master secret: "); - for (i = 0; i < SECRET_LEN; i++) - printf("%02x", session->sslClient->arrays->masterSecret[i]); - printf("\n"); - - printf("server suite = %d\n", session->sslServer->options.cipherSuite); - printf("client suite = %d\n", session->sslClient->options.cipherSuite); - } + #ifdef WOLFSSL_TLS13 + if (!IsAtLeastTLSv1_3(session->sslServer->version)) + #endif + ShowTlsSecrets(session); #endif CallConnectionCb(session); @@ -2107,35 +2351,219 @@ static int ProcessClientKeyExchange(const byte* input, int* sslBytes, return ret; } +/* Process Client Key Exchange, static RSA */ +static int ProcessClientKeyExchange(const byte* input, int* sslBytes, + SnifferSession* session, char* error) +{ + if (session->sslServer->buffers.key == NULL || + session->sslServer->buffers.key->buffer == NULL || + session->sslServer->buffers.key->length == 0) { + + SetError(RSA_KEY_MISSING_STR, error, session, FATAL_ERROR_STATE); + return -1; + } + + return SetupKeys(input, sslBytes, session, error, NULL, + session->sslServer->buffers.key); +} + +#ifdef WOLFSSL_TLS13 +static int ProcessKeyShare(KeyShareInfo* info, const byte* input, int len, + word16 filter_group) +{ + int index = 0; + while (index < len) { + /* Named group and public key */ + info->named_group = (word16)((input[index] << 8) | input[index+1]); + index += OPAQUE16_LEN; + info->key_len = (word16)((input[index] << 8) | input[index+1]); + index += OPAQUE16_LEN; + if (info->key_len == 0 || info->key_len > len - index) { + return -1; + } + info->key = &input[index]; + index += info->key_len; + + switch (info->named_group) { + #ifndef NO_DH + #ifdef HAVE_FFDHE_2048 + case WOLFSSL_FFDHE_2048: + info->dh_key_bits = 2048; + break; + #endif + #ifdef HAVE_FFDHE_3072 + case WOLFSSL_FFDHE_3072: + info->dh_key_bits = 3072; + break; + #endif + #ifdef HAVE_FFDHE_4096 + case WOLFSSL_FFDHE_4096: + info->dh_key_bits = 4096; + break; + #endif + #ifdef HAVE_FFDHE_6144 + case WOLFSSL_FFDHE_6144: + info->dh_key_bits = 6144; + break; + #endif + #ifdef HAVE_FFDHE_8192 + case WOLFSSL_FFDHE_8192: + info->dh_key_bits = 8192; + break; + #endif + #endif /* !NO_DH */ + #ifdef HAVE_ECC + #if !defined(NO_ECC256) || defined(HAVE_ALL_CURVES) + #ifndef NO_ECC_SECP + case WOLFSSL_ECC_SECP256R1: + info->curve_id = ECC_SECP256R1; + break; + #endif /* !NO_ECC_SECP */ + #endif + #if defined(HAVE_ECC384) || defined(HAVE_ALL_CURVES) + #ifndef NO_ECC_SECP + case WOLFSSL_ECC_SECP384R1: + info->curve_id = ECC_SECP384R1; + break; + #endif /* !NO_ECC_SECP */ + #endif + #if defined(HAVE_ECC521) || defined(HAVE_ALL_CURVES) + #ifndef NO_ECC_SECP + case WOLFSSL_ECC_SECP521R1: + info->curve_id = ECC_SECP521R1; + break; + #endif /* !NO_ECC_SECP */ + #endif + #endif /* HAVE_ECC */ + #ifdef HAVE_CURVE25519 + case WOLFSSL_ECC_X25519: + info->curve_id = ECC_X25519; + break; + #endif + #ifdef HAVE_X448 + case WOLFSSL_ECC_X448: + info->curve_id = ECC_X448; + break; + #endif + default: + /* unsupported curve */ + return ECC_PEERKEY_ERROR; + } + + if (filter_group == 0 || filter_group == info->named_group) { + return 0; + } + } + return -1; +} + +static int ProcessServerKeyShare(SnifferSession* session, const byte* input, int len, + char* error) +{ + int ret; + + if (session->cliKeyShare == NULL || session->cliKeyShareSz == 0) { + SetError(BAD_INPUT_STR, error, session, FATAL_ERROR_STATE); + return -1; + } + + /* Get server_hello key share */ + ret = ProcessKeyShare(&session->srvKs, input, len, 0); + if (ret == 0) { + /* Get client_hello key share */ + ret = ProcessKeyShare(&session->cliKs, session->cliKeyShare, + session->cliKeyShareSz, session->srvKs.named_group); + } + if (ret != 0) { + SetError(SERVER_HELLO_INPUT_STR, error, session, FATAL_ERROR_STATE); + return -1; + } + + return ret; +} +#endif /* WOLFSSL_TLS13 */ /* Process Session Ticket */ static int ProcessSessionTicket(const byte* input, int* sslBytes, SnifferSession* session, char* error) { word16 len; + WOLFSSL* ssl; - /* make sure can read through hint and len */ - if (TICKET_HINT_LEN + LENGTH_SZ > *sslBytes) { + if (session->flags.side == WOLFSSL_SERVER_END) + ssl = session->sslServer; + else + ssl = session->sslClient; + + /* make sure can read through hint len */ + if (TICKET_HINT_LEN > *sslBytes) { SetError(BAD_INPUT_STR, error, session, FATAL_ERROR_STATE); return -1; } - - input += TICKET_HINT_LEN; /* skip over hint */ + input += TICKET_HINT_LEN; /* skip over hint len */ *sslBytes -= TICKET_HINT_LEN; - len = (word16)((input[0] << 8) | input[1]); - input += LENGTH_SZ; - *sslBytes -= LENGTH_SZ; +#ifdef WOLFSSL_TLS13 + /* TLS v1.3 has hint age and nonce */ + if (IsAtLeastTLSv1_3(ssl->version)) { + /* make sure can read through hint age and nonce len */ + if (TICKET_HINT_AGE_LEN + 1 > *sslBytes) { + SetError(BAD_INPUT_STR, error, session, FATAL_ERROR_STATE); + return -1; + } + input += TICKET_HINT_AGE_LEN; /* skip over hint age */ + *sslBytes -= TICKET_HINT_AGE_LEN; - /* make sure can read through ticket */ - if (len > *sslBytes || len < ID_LEN) { + /* ticket nonce */ + len = input[0]; + if (len > MAX_TICKET_NONCE_SZ) { + SetError(BAD_INPUT_STR, error, session, FATAL_ERROR_STATE); + return -1; + } + input += OPAQUE8_LEN + len; + *sslBytes -= OPAQUE8_LEN + len; + } +#endif + + /* make sure can read through len */ + if (OPAQUE16_LEN > *sslBytes) { SetError(BAD_INPUT_STR, error, session, FATAL_ERROR_STATE); return -1; } - /* store session with macID as sessionID */ - session->sslServer->options.haveSessionId = 1; - XMEMCPY(session->sslServer->arrays->sessionID, input + len - ID_LEN,ID_LEN); + len = (word16)((input[0] << 8) | input[1]); + input += OPAQUE16_LEN; + *sslBytes -= OPAQUE16_LEN; + + /* make sure can read through ticket */ + if (len > *sslBytes) { + SetError(BAD_INPUT_STR, error, session, FATAL_ERROR_STATE); + return -1; + } + +#ifdef WOLFSSL_TLS13 + /* TLS v1.3 has hint age and nonce */ + if (IsAtLeastTLSv1_3(ssl->version)) { + #ifdef HAVE_SESSION_TICKET + if (SetTicket(ssl, input, len) != 0) { + SetError(BAD_INPUT_STR, error, session, FATAL_ERROR_STATE); + return -1; + } + #endif + } + else +#endif + { + /* make sure ticket id isn't too long */ + if (len > ID_LEN) { + SetError(BAD_INPUT_STR, error, session, FATAL_ERROR_STATE); + return -1; + } + /* store session with macID as sessionID */ + session->sslServer->options.haveSessionId = 1; + XMEMCPY(session->sslServer->arrays->sessionID, + input + len - ID_LEN, ID_LEN); + } return 0; } @@ -2145,10 +2573,11 @@ static int ProcessSessionTicket(const byte* input, int* sslBytes, static int ProcessServerHello(int msgSz, const byte* input, int* sslBytes, SnifferSession* session, char* error) { + int ret = 0; ProtocolVersion pv; byte b, b0; int toRead = VERSION_SZ + RAN_LEN + ENUM_LEN; - int doResume = 0; + int doResume = 0; int initialBytes = *sslBytes; (void)msgSz; @@ -2175,7 +2604,7 @@ static int ProcessServerHello(int msgSz, const byte* input, int* sslBytes, XMEMCPY(session->sslServer->arrays->serverRandom, input, RAN_LEN); XMEMCPY(session->sslClient->arrays->serverRandom, input, RAN_LEN); - input += RAN_LEN; + input += RAN_LEN; *sslBytes -= RAN_LEN; b = *input++; @@ -2187,6 +2616,9 @@ static int ProcessServerHello(int msgSz, const byte* input, int* sslBytes, return -1; } if (b) { + #ifdef WOLFSSL_TLS13 + XMEMCPY(session->sslServer->session.sessionID, input, ID_LEN); + #endif XMEMCPY(session->sslServer->arrays->sessionID, input, ID_LEN); session->sslServer->options.haveSessionId = 1; } @@ -2230,7 +2662,6 @@ static int ProcessServerHello(int msgSz, const byte* input, int* sslBytes, return -1; } -#ifdef HAVE_EXTENDED_MASTER /* extensions */ if ((initialBytes - *sslBytes) < msgSz) { word16 len; @@ -2251,15 +2682,14 @@ static int ProcessServerHello(int msgSz, const byte* input, int* sslBytes, } while (len >= EXT_TYPE_SZ + LENGTH_SZ) { - byte extType[EXT_TYPE_SZ]; + word16 extType; word16 extLen; - extType[0] = input[0]; - extType[1] = input[1]; + extType = (word16)((input[0] << 8) | input[1]); input += EXT_TYPE_SZ; *sslBytes -= EXT_TYPE_SZ; - extLen = (word16)((input[0] << 8) | input[1]); + extLen = (word16)((input[0] << 8) | input[1]); input += LENGTH_SZ; *sslBytes -= LENGTH_SZ; @@ -2270,8 +2700,35 @@ static int ProcessServerHello(int msgSz, const byte* input, int* sslBytes, return -1; } - if (extType[0] == 0x00 && extType[1] == EXT_MASTER_SECRET) { + switch (extType) { + #ifdef WOLFSSL_TLS13 + case EXT_KEY_SHARE: + ret = ProcessServerKeyShare(session, input, extLen, error); + if (ret != 0) { + SetError(SERVER_HELLO_INPUT_STR, error, session, + FATAL_ERROR_STATE); + return -1; + } + break; + #endif + #ifdef HAVE_SESSION_TICKET + case EXT_PRE_SHARED_KEY: + /* indicates we want to use resumption */ + session->sslServer->options.resuming = 1; + session->sslClient->options.resuming = 1; + break; + #endif + case EXT_SUPPORTED_VERSIONS: + session->sslServer->version.major = input[0]; + session->sslServer->version.minor = input[1]; + session->sslClient->version.major = input[0]; + session->sslClient->version.minor = input[1]; + break; + case EXT_MASTER_SECRET: + #ifdef HAVE_EXTENDED_MASTER session->flags.expectEms = 1; + #endif + break; } input += extLen; @@ -2280,6 +2737,7 @@ static int ProcessServerHello(int msgSz, const byte* input, int* sslBytes, } } +#ifdef HAVE_EXTENDED_MASTER if (!session->flags.expectEms) { XFREE(session->hash, NULL, DYNAMIC_TYPE_HASHES); session->hash = NULL; @@ -2288,13 +2746,15 @@ static int ProcessServerHello(int msgSz, const byte* input, int* sslBytes, if (session->sslServer->options.haveSessionId) { if (XMEMCMP(session->sslServer->arrays->sessionID, - session->sslClient->arrays->sessionID, ID_LEN) == 0) + session->sslClient->arrays->sessionID, ID_LEN) == 0) { doResume = 1; - } + } + } else if (session->sslClient->options.haveSessionId == 0 && session->sslServer->options.haveSessionId == 0 && - session->ticketID) + session->ticketID) { doResume = 1; + } if (session->ticketID && doResume) { /* use ticketID to retrieve from session, prefer over sessionID */ @@ -2303,11 +2763,10 @@ static int ProcessServerHello(int msgSz, const byte* input, int* sslBytes, actual sessionID */ } - if (doResume ) { - int ret = 0; + if (doResume) { SSL_SESSION* resume = GetSession(session->sslServer, session->sslServer->arrays->masterSecret, 0); - if (resume == NULL) { + if (resume == NULL && !IsAtLeastTLSv1_3(session->sslServer->version)) { #ifdef WOLFSSL_SNIFFER_STATS INC_STAT(SnifferStats.sslResumeMisses); #endif @@ -2334,16 +2793,34 @@ static int ProcessServerHello(int msgSz, const byte* input, int* sslBytes, return -1; } - if (session->sslServer->options.tls) { - ret = DeriveTlsKeys(session->sslServer); - ret += DeriveTlsKeys(session->sslClient); + #ifdef WOLFSSL_TLS13 + if (IsAtLeastTLSv1_3(session->sslServer->version)) { + #ifdef HAVE_SESSION_TICKET + /* Resumption PSK is resumption master secret. */ + session->sslServer->arrays->psk_keySz = session->sslServer->specs.hash_size; + session->sslClient->arrays->psk_keySz = session->sslClient->specs.hash_size; + ret = DeriveResumptionPSK(session->sslServer, session->sslServer->session.ticketNonce.data, + session->sslServer->session.ticketNonce.len, session->sslServer->arrays->psk_key); + /* Copy resumption PSK to client */ + XMEMCPY(session->sslClient->arrays->psk_key, + session->sslServer->arrays->psk_key, + session->sslServer->arrays->psk_keySz); + #endif } - else { - ret = DeriveKeys(session->sslServer); - ret += DeriveKeys(session->sslClient); + else + #endif + { + if (IsTLS(session->sslServer)) { + ret = DeriveTlsKeys(session->sslServer); + ret += DeriveTlsKeys(session->sslClient); + } + else { + ret = DeriveKeys(session->sslServer); + ret += DeriveKeys(session->sslClient); + } + ret += SetKeysSide(session->sslServer, ENCRYPT_AND_DECRYPT_SIDE); + ret += SetKeysSide(session->sslClient, ENCRYPT_AND_DECRYPT_SIDE); } - ret += SetKeysSide(session->sslServer, ENCRYPT_AND_DECRYPT_SIDE); - ret += SetKeysSide(session->sslClient, ENCRYPT_AND_DECRYPT_SIDE); if (ret != 0) { SetError(BAD_DERIVE_STR, error, session, FATAL_ERROR_STATE); @@ -2355,6 +2832,7 @@ static int ProcessServerHello(int msgSz, const byte* input, int* sslBytes, INC_STAT(SnifferStats.sslStandardConns); #endif } + #ifdef SHOW_SECRETS { int i; @@ -2366,6 +2844,29 @@ static int ProcessServerHello(int msgSz, const byte* input, int* sslBytes, printf("\n"); } #endif + +#ifdef WOLFSSL_TLS13 + /* Setup handshake keys */ + if (IsAtLeastTLSv1_3(session->sslServer->version)) { + DerBuffer* key = session->sslServer->buffers.key; + #ifdef WOLFSSL_STATIC_EPHEMERAL + if (session->sslServer->staticKE.key) + key = session->sslServer->staticKE.key; + #endif + ret = SetupKeys(session->cliKs.key, &session->cliKs.key_len, + session, error, &session->cliKs, key); + if (ret != 0) { + SetError(SERVER_HELLO_INPUT_STR, error, session, FATAL_ERROR_STATE); + return ret; + } + + if (session->flags.side == WOLFSSL_SERVER_END) + session->flags.serverCipherOn = 1; + else + session->flags.clientCipherOn = 1; + } +#endif + return 0; } @@ -2374,15 +2875,19 @@ static int ProcessServerHello(int msgSz, const byte* input, int* sslBytes, static int ProcessClientHello(const byte* input, int* sslBytes, SnifferSession* session, char* error) { + int ret = 0; byte bLen; word16 len; int toRead = VERSION_SZ + RAN_LEN + ENUM_LEN; + const byte* inputHello = input; + int inputHelloSz = *sslBytes; + WOLFSSL* ssl = session->sslServer; + int didHash = 0; #ifdef HAVE_SNI { byte name[MAX_SERVER_NAME]; word32 nameSz = sizeof(name); - int ret; ret = wolfSSL_SNI_GetFromBuffer( input - HANDSHAKE_HEADER_SZ - RECORD_HEADER_SZ, @@ -2400,9 +2905,23 @@ static int ProcessClientHello(const byte* input, int* sslBytes, while (namedKey != NULL) { if (nameSz == namedKey->nameSz && XSTRNCMP((char*)name, namedKey->name, nameSz) == 0) { - if (wolfSSL_use_PrivateKey_buffer(session->sslServer, - namedKey->key, namedKey->keySz, - WOLFSSL_FILETYPE_ASN1) != WOLFSSL_SUCCESS) { + #ifdef WOLFSSL_STATIC_EPHEMERAL + if (namedKey->isEphemeralKey) { + /* auto detect key type with WC_PK_TYPE_NONE */ + ret = wolfSSL_set_ephemeral_key(ssl, + WC_PK_TYPE_NONE, (const char*)namedKey->key, + namedKey->keySz, WOLFSSL_FILETYPE_ASN1); + if (ret == 0) + ret = WOLFSSL_SUCCESS; + } + else + #endif + { + ret = wolfSSL_use_PrivateKey_buffer(ssl, + namedKey->key, namedKey->keySz, + WOLFSSL_FILETYPE_ASN1); + } + if (ret != WOLFSSL_SUCCESS) { wc_UnLockMutex(&session->context->namedKeysMutex); SetError(CLIENT_HELLO_LATE_KEY_STR, error, session, FATAL_ERROR_STATE); @@ -2446,6 +2965,9 @@ static int ProcessClientHello(const byte* input, int* sslBytes, return -1; } Trace(CLIENT_RESUME_TRY_STR); +#ifdef WOLFSSL_TLS13 + XMEMCPY(session->sslClient->session.sessionID, input, ID_LEN); +#endif XMEMCPY(session->sslClient->arrays->sessionID, input, ID_LEN); session->sslClient->options.haveSessionId = 1; } @@ -2454,7 +2976,7 @@ static int ProcessClientHello(const byte* input, int* sslBytes, int i; printf("client random: "); for (i = 0; i < RAN_LEN; i++) - printf("%02x", session->sslServer->arrays->clientRandom[i]); + printf("%02x", ssl->arrays->clientRandom[i]); printf("\n"); } #endif @@ -2511,15 +3033,14 @@ static int ProcessClientHello(const byte* input, int* sslBytes, } while (len >= EXT_TYPE_SZ + LENGTH_SZ) { - byte extType[EXT_TYPE_SZ]; + word16 extType; word16 extLen; - extType[0] = input[0]; - extType[1] = input[1]; + extType = (word16)((input[0] << 8) | input[1]); input += EXT_TYPE_SZ; *sslBytes -= EXT_TYPE_SZ; - extLen = (word16)((input[0] << 8) | input[1]); + extLen = (word16)((input[0] << 8) | input[1]); input += LENGTH_SZ; *sslBytes -= LENGTH_SZ; @@ -2529,17 +3050,102 @@ static int ProcessClientHello(const byte* input, int* sslBytes, return -1; } - if (extType[0] == 0x00 && extType[1] == TICKET_EXT_ID) { + switch (extType) { + #ifdef WOLFSSL_TLS13 + case EXT_KEY_SHARE: + { + word16 ksLen = (word16)((input[0] << 8) | input[1]); + if (ksLen + OPAQUE16_LEN > extLen) { + SetError(CLIENT_HELLO_INPUT_STR, error, session, FATAL_ERROR_STATE); + return -1; + } + /* cache key share data till server_hello */ + session->cliKeyShareSz = ksLen; + session->cliKeyShare = (byte*)XMALLOC(ksLen, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (session->cliKeyShare == NULL) { + SetError(MEMORY_STR, error, session, FATAL_ERROR_STATE); + break; + } + XMEMCPY(session->cliKeyShare, &input[2], ksLen); + /* The server side handshake encryption is on for future packets */ + session->flags.serverCipherOn = 1; + break; + } + #ifdef HAVE_SESSION_TICKET + case EXT_PRE_SHARED_KEY: + { + word16 idsLen, idLen, bindersLen, idx = 0; + word32 ticketAge; + const byte *identity, *binders; + + idsLen = (word16)((input[idx] << 8) | input[idx+1]); + if (idsLen + OPAQUE16_LEN + idx > extLen) { + SetError(CLIENT_HELLO_INPUT_STR, error, session, FATAL_ERROR_STATE); + return -1; + } + idx += OPAQUE16_LEN; + + /* PSK identity */ + idLen = (word16)((input[idx] << 8) | input[idx+1]); + if (idLen + OPAQUE16_LEN + idx > extLen) { + SetError(CLIENT_HELLO_INPUT_STR, error, session, FATAL_ERROR_STATE); + return -1; + } + idx += OPAQUE16_LEN; + identity = &input[idx]; + idx += idLen; + + /* Obfuscated Ticket Age 32-bits */ + ticketAge = (word32)((input[idx] << 24) | (input[idx+1] << 16) | + (input[idx+2] << 8) | input[idx+3]); + (void)ticketAge; /* not used */ + idx += OPAQUE32_LEN; + + /* binders - all binders */ + bindersLen = (word16)((input[idx] << 8) | input[idx+1]); + if (bindersLen + OPAQUE16_LEN + idx > extLen) { + SetError(CLIENT_HELLO_INPUT_STR, error, session, FATAL_ERROR_STATE); + return -1; + } + idx += OPAQUE16_LEN; + binders = &input[idx]; + bindersLen += OPAQUE16_LEN; /* includes 2 bytes for total len */ + (void)binders; /* not used */ + + /* Hash data up to binders for deriving binders in PSK extension. */ + HashRaw(session->sslServer, inputHello - HANDSHAKE_HEADER_SZ, + inputHelloSz - bindersLen + HANDSHAKE_HEADER_SZ); + HashRaw(session->sslClient, inputHello - HANDSHAKE_HEADER_SZ, + inputHelloSz - bindersLen + HANDSHAKE_HEADER_SZ); + + /* call to decrypt session ticket */ + ret = DoClientTicket(ssl, identity, idLen); + if (ret != 0) { + SetError(CLIENT_HELLO_INPUT_STR, error, session, FATAL_ERROR_STATE); + return -1; + } + ssl->options.resuming = 1; + + /* Hash the rest of the ClientHello. */ + HashRaw(session->sslServer, inputHello + inputHelloSz - bindersLen, bindersLen); + HashRaw(session->sslClient, inputHello + inputHelloSz - bindersLen, bindersLen); + didHash = 1; + break; + } + #endif /* HAVE_SESSION_TICKET */ + #endif /* WOLFSSL_TLS13 */ + case EXT_SUPPORTED_VERSIONS: + break; + case EXT_TICKET_ID: /* make sure can read through ticket if there is a non blank one */ if (extLen && extLen < ID_LEN) { SetError(CLIENT_HELLO_INPUT_STR, error, session, FATAL_ERROR_STATE); return -1; } - if (extLen) { - if (session->ticketID == 0) { + if (session->ticketID == NULL) { session->ticketID = (byte*)XMALLOC(ID_LEN, NULL, DYNAMIC_TYPE_SNIFFER_TICKET_ID); if (session->ticketID == 0) { @@ -2550,6 +3156,7 @@ static int ProcessClientHello(const byte* input, int* sslBytes, } XMEMCPY(session->ticketID, input + extLen - ID_LEN, ID_LEN); } + break; } input += extLen; @@ -2557,33 +3164,74 @@ static int ProcessClientHello(const byte* input, int* sslBytes, len -= extLen + EXT_TYPE_SZ + LENGTH_SZ; } - return 0; + if (!didHash) { + HashRaw(session->sslServer, inputHello - HANDSHAKE_HEADER_SZ, + inputHelloSz + HANDSHAKE_HEADER_SZ); + HashRaw(session->sslClient, inputHello - HANDSHAKE_HEADER_SZ, + inputHelloSz + HANDSHAKE_HEADER_SZ); + } + + (void)ssl; + + return ret; } #ifdef WOLFSSL_SNIFFER_WATCH -/* Process Certificate */ -static int ProcessCertificate(const byte* input, int* sslBytes, - SnifferSession* session, char* error) +static int KeyWatchCall(SnifferSession* session, const byte* data, int dataSz, + char* error) { - Sha256 sha; - const byte* certChain; - word32 certChainSz; - word32 certSz; int ret; + Sha256 sha; byte digest[SHA256_DIGEST_SIZE]; - /* If the receiver is the server, this is the client certificate message, - * and it should be ignored at this point. */ - if (session->flags.side == WOLFSSL_SERVER_END) - return 0; - if (WatchCb == NULL) { SetError(WATCH_CB_MISSING_STR, error, session, FATAL_ERROR_STATE); return -1; } + ret = wc_InitSha256(&sha); + if (ret == 0) + ret = wc_Sha256Update(&sha, data, dataSz); + if (ret == 0) + ret = wc_Sha256Final(&sha, digest); + if (ret != 0) { + SetError(WATCH_HASH_STR, error, session, FATAL_ERROR_STATE); + return -1; + } + + ret = WatchCb((void*)session, digest, sizeof(digest), + data, dataSz, WatchCbCtx, error); + if (ret != 0) { +#ifdef WOLFSSL_SNIFFER_STATS + INC_STAT(SnifferStats.sslKeysUnmatched); +#endif + SetError(WATCH_FAIL_STR, error, session, FATAL_ERROR_STATE); + ret = -1; + } + else { +#ifdef WOLFSSL_SNIFFER_STATS + INC_STAT(SnifferStats.sslKeyMatches); +#endif + } + return ret; +} + +/* Process Certificate */ +static int ProcessCertificate(const byte* input, int* sslBytes, + SnifferSession* session, char* error) +{ + int ret; + const byte* certChain; + word32 certChainSz; + word32 certSz; + + /* If the receiver is the server, this is the client certificate message, + * and it should be ignored at this point. */ + if (session->flags.side == WOLFSSL_SERVER_END) + return 0; + if (*sslBytes < CERT_HEADER_SZ) { SetError(BAD_CERT_MSG_STR, error, session, FATAL_ERROR_STATE); return -1; @@ -2607,32 +3255,7 @@ static int ProcessCertificate(const byte* input, int* sslBytes, *sslBytes -= certChainSz; - ret = wc_InitSha256(&sha); - if (ret == 0) - ret = wc_Sha256Update(&sha, input, certSz); - if (ret == 0) - ret = wc_Sha256Final(&sha, digest); - if (ret != 0) { - SetError(WATCH_HASH_STR, error, session, FATAL_ERROR_STATE); - return -1; - } - - ret = WatchCb((void*)session, digest, sizeof(digest), - certChain, certChainSz, WatchCbCtx, error); - if (ret != 0) { -#ifdef WOLFSSL_SNIFFER_STATS - INC_STAT(SnifferStats.sslKeysUnmatched); -#endif - SetError(WATCH_FAIL_STR, error, session, FATAL_ERROR_STATE); - return -1; - } - else { -#ifdef WOLFSSL_SNIFFER_STATS - INC_STAT(SnifferStats.sslKeyMatches); -#endif - } - - return 0; + return KeyWatchCall(session, input, certSz, error); } #endif @@ -2642,7 +3265,7 @@ static int ProcessCertificate(const byte* input, int* sslBytes, static int ProcessFinished(const byte* input, int size, int* sslBytes, SnifferSession* session, char* error) { - SSL* ssl; + WOLFSSL* ssl; word32 inOutIdx = 0; int ret; @@ -2651,8 +3274,20 @@ static int ProcessFinished(const byte* input, int size, int* sslBytes, else ssl = session->sslClient; - ret = DoFinished(ssl, input, &inOutIdx, (word32) size, (word32) *sslBytes, - SNIFF); +#ifdef WOLFSSL_TLS13 + if (IsAtLeastTLSv1_3(ssl->version)) { + ret = DoTls13Finished(ssl, input, &inOutIdx, (word32)size, + (word32)*sslBytes, SNIFF); + + ssl->options.handShakeState = HANDSHAKE_DONE; + ssl->options.handShakeDone = 1; + } + else +#endif + { + ret = DoFinished(ssl, input, &inOutIdx, (word32)size, + (word32)*sslBytes, SNIFF); + } *sslBytes -= (int)inOutIdx; if (ret < 0) { @@ -2673,6 +3308,38 @@ static int ProcessFinished(const byte* input, int size, int* sslBytes, } } +#ifdef WOLFSSL_TLS13 + /* Derive TLS v1.3 traffic keys */ + if (IsAtLeastTLSv1_3(ssl->version) && !session->flags.gotFinished) { + /* When either side gets "finished" derive master secret and keys, but only set the key for the side encrypting data */ + ret = DeriveMasterSecret(session->sslServer); + ret += DeriveMasterSecret(session->sslClient); + #ifdef WOLFSSL_EARLY_DATA + ret += DeriveTls13Keys(session->sslServer, traffic_key, ENCRYPT_AND_DECRYPT_SIDE, ssl->earlyData == no_early_data); + ret += DeriveTls13Keys(session->sslClient, traffic_key, ENCRYPT_AND_DECRYPT_SIDE, ssl->earlyData == no_early_data); + #else + ret += DeriveTls13Keys(session->sslServer, traffic_key, ENCRYPT_AND_DECRYPT_SIDE, 1); + ret += DeriveTls13Keys(session->sslClient, traffic_key, ENCRYPT_AND_DECRYPT_SIDE, 1); + #endif + if (session->flags.side == WOLFSSL_SERVER_END) { + ret += SetKeysSide(session->sslServer, DECRYPT_SIDE_ONLY); + ret += SetKeysSide(session->sslClient, ENCRYPT_SIDE_ONLY); + } + else { + ret += SetKeysSide(session->sslServer, ENCRYPT_SIDE_ONLY); + ret += SetKeysSide(session->sslClient, DECRYPT_SIDE_ONLY); + } + if (ret != 0) { + SetError(BAD_FINISHED_MSG, error, session, FATAL_ERROR_STATE); + return -1; + } + session->flags.gotFinished = 1; + #ifdef SHOW_SECRETS + ShowTlsSecrets(session); + #endif + } +#endif + /* If receiving a finished message from one side, free the resources * from the other side's tracker. */ if (session->flags.side == WOLFSSL_SERVER_END) @@ -2692,6 +3359,7 @@ static int DoHandShake(const byte* input, int* sslBytes, int size; int ret = 0; int startBytes; + WOLFSSL* ssl; if (*sslBytes < HANDSHAKE_HEADER_SZ) { SetError(HANDSHAKE_INPUT_STR, error, session, FATAL_ERROR_STATE); @@ -2710,14 +3378,34 @@ static int DoHandShake(const byte* input, int* sslBytes, return ret; } - /* A session's arrays are released when the handshake is completed. */ - if (session->sslServer->arrays == NULL && - session->sslClient->arrays == NULL) { + if (session->flags.side == WOLFSSL_SERVER_END) + ssl = session->sslServer; + else + ssl = session->sslClient; - SetError(NO_SECURE_RENEGOTIATION, error, session, FATAL_ERROR_STATE); - return -1; +#ifdef HAVE_SECURE_RENEGOTIATION + if (!IsAtLeastTLSv1_3(ssl->version)) { + /* A session's arrays are released when the handshake is completed. */ + if (session->sslServer->arrays == NULL && + session->sslClient->arrays == NULL) { + + SetError(NO_SECURE_RENEGOTIATION, error, session, FATAL_ERROR_STATE); + return -1; + } } +#endif +#ifdef WOLFSSL_TLS13 + if (type != client_hello) { + /* For resumption the hash is before / after client_hello PSK binder */ + /* hash the packet including header */ + /* TLS v1.3 requires the hash for the handshake and transfer key derivation */ + /* we hash even for non TLS v1.3, since we don't know if its actually + TLS v1.3 till later at EXT_SUPPORTED_VERSIONS in server_hello */ + HashRaw(session->sslServer, input - HANDSHAKE_HEADER_SZ, size + HANDSHAKE_HEADER_SZ); + HashRaw(session->sslClient, input - HANDSHAKE_HEADER_SZ, size + HANDSHAKE_HEADER_SZ); + } +#endif #ifdef HAVE_EXTENDED_MASTER if (session->hash) { if (HashUpdate(session->hash, input, size) != 0) { @@ -2755,6 +3443,10 @@ static int DoHandShake(const byte* input, int* sslBytes, SetError(BAD_CIPHER_SPEC_STR, error, session, FATAL_ERROR_STATE); ret = -1; break; + case encrypted_extensions: + Trace(GOT_ENC_EXT_STR); + ssl->msgsReceived.got_encrypted_extensions = 1; + break; case certificate: Trace(GOT_CERT_STR); if (session->flags.side == WOLFSSL_SERVER_END) { @@ -2824,7 +3516,7 @@ static int DoHandShake(const byte* input, int* sslBytes, /* Decrypt input into plain output, 0 on success */ -static int Decrypt(SSL* ssl, byte* output, const byte* input, word32 sz) +static int Decrypt(WOLFSSL* ssl, byte* output, const byte* input, word32 sz) { int ret = 0; @@ -2881,7 +3573,6 @@ static int Decrypt(SSL* ssl, byte* output, const byte* input, word32 sz) { /* scratch buffer, sniffer ignores auth tag*/ byte authTag[WOLFSSL_MIN_AUTH_TAG_SZ]; - byte nonce[AESGCM_NONCE_SZ]; XMEMCPY(nonce, ssl->keys.aead_dec_imp_IV, AESGCM_IMP_IV_SZ); XMEMCPY(nonce + AESGCM_IMP_IV_SZ, input, AESGCM_EXP_IV_SZ); @@ -2903,7 +3594,7 @@ static int Decrypt(SSL* ssl, byte* output, const byte* input, word32 sz) ret = -1; } break; - #endif + #endif #ifdef HAVE_NULL_CIPHER case wolfssl_cipher_null: @@ -2922,19 +3613,28 @@ static int Decrypt(SSL* ssl, byte* output, const byte* input, word32 sz) /* Decrypt input message into output, adjust output steam if needed */ -static const byte* DecryptMessage(SSL* ssl, const byte* input, word32 sz, - byte* output, int* error, int* advance) +static const byte* DecryptMessage(WOLFSSL* ssl, const byte* input, word32 sz, + byte* output, int* error, int* advance, RecordLayerHeader* rh) { int ivExtra = 0; - - int ret = Decrypt(ssl, output, input, sz); + int ret; + +#ifdef WOLFSSL_TLS13 + if (IsAtLeastTLSv1_3(ssl->version)) { + ret = DecryptTls13(ssl, output, input, sz, (byte*)rh, RECORD_HEADER_SZ); + } + else +#endif + { + ret = Decrypt(ssl, output, input, sz); + } if (ret != 0) { *error = ret; return NULL; } ssl->keys.encryptSz = sz; if (ssl->options.tls1_1 && ssl->specs.cipher_type == block) { - output += ssl->specs.block_size; /* go past TLSv1.1 IV */ + output += ssl->specs.block_size; /* go past TLSv1.1 IV */ ivExtra = ssl->specs.block_size; *advance = ssl->specs.block_size; } @@ -2949,6 +3649,21 @@ static const byte* DecryptMessage(SSL* ssl, const byte* input, word32 sz, if (ssl->specs.cipher_type == block) ssl->keys.padSz += *(output + sz - ivExtra - 1) + 1; +#ifdef WOLFSSL_TLS13 + if (IsAtLeastTLSv1_3(ssl->version)) { + word16 i = (word16)(sz - ssl->keys.padSz); + /* Remove padding from end of plain text. */ + for (--i; i > 0; i--) { + if (output[i] != 0) + break; + } + /* Get the real content type from the end of the data. */ + rh->type = output[i]; + ssl->keys.padSz = sz - i; + } +#endif + (void)rh; + return output; } @@ -3433,12 +4148,12 @@ static int AddToReassembly(byte from, word32 seq, const byte* sslFrame, static int AddFinCapture(SnifferSession* session, word32 sequence) { if (session->flags.side == WOLFSSL_SERVER_END) { - if (session->finCaputre.cliCounted == 0) - session->finCaputre.cliFinSeq = sequence; + if (session->finCapture.cliCounted == 0) + session->finCapture.cliFinSeq = sequence; } else { - if (session->finCaputre.srvCounted == 0) - session->finCaputre.srvFinSeq = sequence; + if (session->finCapture.srvCounted == 0) + session->finCapture.srvFinSeq = sequence; } return 1; } @@ -3574,7 +4289,7 @@ static int FindNextRecordInAssembly(SnifferSession* session, word32* reassemblyMemory = (session->flags.side == WOLFSSL_SERVER_END) ? &session->cliReassemblyMemory : &session->srvReassemblyMemory; - SSL* ssl = (session->flags.side == WOLFSSL_SERVER_END) ? + WOLFSSL* ssl = (session->flags.side == WOLFSSL_SERVER_END) ? session->sslServer : session->sslClient; ProtocolVersion pv = ssl->version; @@ -3755,7 +4470,7 @@ static int CheckPreRecord(IpInfo* ipInfo, TcpInfo* tcpInfo, void* vChain, word32 chainSz, char* error) { word32 length; - SSL* ssl = ((*session)->flags.side == WOLFSSL_SERVER_END) ? + WOLFSSL* ssl = ((*session)->flags.side == WOLFSSL_SERVER_END) ? (*session)->sslServer : (*session)->sslClient; byte skipPartial = ((*session)->flags.side == WOLFSSL_SERVER_END) ? (*session)->flags.srvSkipPartial : @@ -3894,16 +4609,16 @@ static int HaveMoreInput(SnifferSession* session, const byte** sslFrame, word32* expected = (session->flags.side == WOLFSSL_SERVER_END) ? &session->cliExpected : &session->srvExpected; /* buffer is on receiving end */ - word32* length = (session->flags.side == WOLFSSL_SERVER_END) ? + word32* length = (session->flags.side == WOLFSSL_SERVER_END) ? &session->sslServer->buffers.inputBuffer.length : &session->sslClient->buffers.inputBuffer.length; byte** myBuffer = (session->flags.side == WOLFSSL_SERVER_END) ? &session->sslServer->buffers.inputBuffer.buffer : &session->sslClient->buffers.inputBuffer.buffer; - word32* bufferSize = (session->flags.side == WOLFSSL_SERVER_END) ? + word32* bufferSize = (session->flags.side == WOLFSSL_SERVER_END) ? &session->sslServer->buffers.inputBuffer.bufferSize : &session->sslClient->buffers.inputBuffer.bufferSize; - SSL* ssl = (session->flags.side == WOLFSSL_SERVER_END) ? + WOLFSSL* ssl = (session->flags.side == WOLFSSL_SERVER_END) ? session->sslServer : session->sslClient; word32* reassemblyMemory = (session->flags.side == WOLFSSL_SERVER_END) ? &session->cliReassemblyMemory : &session->srvReassemblyMemory; @@ -3965,8 +4680,8 @@ static int ProcessMessage(const byte* sslFrame, SnifferSession* session, int decoded = 0; /* bytes stored for user in data */ int notEnough; /* notEnough bytes yet flag */ int decrypted = 0; /* was current msg decrypted */ - SSL* ssl = (session->flags.side == WOLFSSL_SERVER_END) ? - session->sslServer : session->sslClient; + WOLFSSL* ssl = (session->flags.side == WOLFSSL_SERVER_END) ? + session->sslServer : session->sslClient; doMessage: notEnough = 0; if (sslBytes < 0) { @@ -4022,7 +4737,7 @@ doMessage: } sslFrame = DecryptMessage(ssl, sslFrame, rhSize, ssl->buffers.outputBuffer.buffer, &errCode, - &ivAdvance); + &ivAdvance, &rh); recordEnd = sslFrame - ivAdvance + rhSize; /* sslFrame moved so should recordEnd */ decrypted = 1; @@ -4207,21 +4922,21 @@ static int CheckFinCapture(IpInfo* ipInfo, TcpInfo* tcpInfo, SnifferSession* session) { int ret = 0; - if (session->finCaputre.cliFinSeq && session->finCaputre.cliFinSeq <= + if (session->finCapture.cliFinSeq && session->finCapture.cliFinSeq <= session->cliExpected) { - if (session->finCaputre.cliCounted == 0) { + if (session->finCapture.cliCounted == 0) { session->flags.finCount += 1; - session->finCaputre.cliCounted = 1; - TraceClientFin(session->finCaputre.cliFinSeq, session->cliExpected); + session->finCapture.cliCounted = 1; + TraceClientFin(session->finCapture.cliFinSeq, session->cliExpected); } } - if (session->finCaputre.srvFinSeq && session->finCaputre.srvFinSeq <= + if (session->finCapture.srvFinSeq && session->finCapture.srvFinSeq <= session->srvExpected) { - if (session->finCaputre.srvCounted == 0) { + if (session->finCapture.srvCounted == 0) { session->flags.finCount += 1; - session->finCaputre.srvCounted = 1; - TraceServerFin(session->finCaputre.srvFinSeq, session->srvExpected); + session->finCapture.srvCounted = 1; + TraceServerFin(session->finCapture.srvFinSeq, session->srvExpected); } } diff --git a/src/ssl.c b/src/ssl.c index 2a2ab77865..1d4b63e4ee 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -28686,21 +28686,21 @@ int SetDhInternal(WOLFSSL_DH* dh) int ret = WOLFSSL_FATAL_ERROR; int pSz = 1024; int gSz = 1024; -#if defined(WOLFSSL_QT) || defined(OPENSSL_ALL) +#ifdef WOLFSSL_DH_EXTRA int privSz = 256; /* Up to 2048-bit */ int pubSz = 256; #endif #ifdef WOLFSSL_SMALL_STACK unsigned char* p = NULL; unsigned char* g = NULL; - #if defined(WOLFSSL_QT) || defined(OPENSSL_ALL) + #ifdef WOLFSSL_DH_EXTRA unsigned char* priv_key = NULL; unsigned char* pub_key = NULL; #endif #else unsigned char p[1024]; unsigned char g[1024]; - #if defined(WOLFSSL_QT) || defined(OPENSSL_ALL) + #ifdef WOLFSSL_DH_EXTRA unsigned char priv_key[256]; unsigned char pub_key[256]; #endif @@ -28714,21 +28714,22 @@ int SetDhInternal(WOLFSSL_DH* dh) WOLFSSL_MSG("Bad p internal size"); else if (wolfSSL_BN_bn2bin(dh->g, NULL) > gSz) WOLFSSL_MSG("Bad g internal size"); - #if defined(WOLFSSL_QT) || defined(OPENSSL_ALL) +#ifdef WOLFSSL_DH_EXTRA else if (wolfSSL_BN_bn2bin(dh->priv_key, NULL) > privSz) WOLFSSL_MSG("Bad private key internal size"); else if (wolfSSL_BN_bn2bin(dh->pub_key, NULL) > privSz) WOLFSSL_MSG("Bad public key internal size"); - #endif +#endif else { #ifdef WOLFSSL_SMALL_STACK p = (unsigned char*)XMALLOC(pSz, NULL, DYNAMIC_TYPE_PUBLIC_KEY); g = (unsigned char*)XMALLOC(gSz, NULL, DYNAMIC_TYPE_PUBLIC_KEY); - - #if defined(WOLFSSL_QT) || defined(OPENSSL_ALL) - priv_key = (unsigned char*)XMALLOC(privSz,NULL,DYNAMIC_TYPE_PRIVATE_KEY); - pub_key = (unsigned char*)XMALLOC(pubSz,NULL,DYNAMIC_TYPE_PUBLIC_KEY); - #endif + #ifdef WOLFSSL_DH_EXTRA + priv_key = (unsigned char*)XMALLOC(privSz, NULL, + DYNAMIC_TYPE_PRIVATE_KEY); + pub_key = (unsigned char*)XMALLOC(pubSz, NULL, + DYNAMIC_TYPE_PUBLIC_KEY); + #endif if (p == NULL || g == NULL) { XFREE(p, NULL, DYNAMIC_TYPE_PUBLIC_KEY); @@ -28737,7 +28738,7 @@ int SetDhInternal(WOLFSSL_DH* dh) } #endif /* WOLFSSL_SMALL_STACK */ - #if defined(WOLFSSL_QT) || defined(OPENSSL_ALL) + #ifdef WOLFSSL_DH_EXTRA privSz = wolfSSL_BN_bn2bin(dh->priv_key, priv_key); pubSz = wolfSSL_BN_bn2bin(dh->pub_key, pub_key); if (privSz <= 0) { @@ -28747,13 +28748,17 @@ int SetDhInternal(WOLFSSL_DH* dh) WOLFSSL_MSG("No public key size."); } if (privSz > 0 || pubSz > 0) { - ret = wc_DhSetFullKeys((DhKey*)dh->internal,priv_key,privSz, - pub_key,pubSz); - if (ret == WOLFSSL_FAILURE) { + ret = wc_DhImportKeyPair((DhKey*)dh->internal, priv_key, privSz, + pub_key, pubSz); + if (ret == 0) { + ret = WOLFSSL_SUCCESS; + } + else { WOLFSSL_MSG("Failed setting private or public key."); + ret = WOLFSSL_FAILURE; } } - #endif /* WOLFSSL_QT || OPENSSL_ALL */ + #endif /* WOLFSSL_DH_EXTRA */ pSz = wolfSSL_BN_bn2bin(dh->p, p); gSz = wolfSSL_BN_bn2bin(dh->g, g); @@ -28770,14 +28775,13 @@ int SetDhInternal(WOLFSSL_DH* dh) #ifdef WOLFSSL_SMALL_STACK XFREE(p, NULL, DYNAMIC_TYPE_PUBLIC_KEY); XFREE(g, NULL, DYNAMIC_TYPE_PUBLIC_KEY); - #if defined(WOLFSSL_QT) || defined(OPENSSL_ALL) + #ifdef WOLFSSL_DH_EXTRA XFREE(priv_key, NULL, DYNAMIC_TYPE_PRIVATE_KEY); XFREE(pub_key, NULL, DYNAMIC_TYPE_PUBLIC_KEY); #endif #endif } - return ret; } @@ -47743,4 +47747,106 @@ int wolfSSL_X509_REQ_set_pubkey(WOLFSSL_X509 *req, WOLFSSL_EVP_PKEY *pkey) } #endif /* OPENSSL_EXTRA && !NO_CERTS && WOLFSSL_CERT_GEN && WOLFSSL_CERT_REQ */ +#ifdef WOLFSSL_STATIC_EPHEMERAL +static int SetStaticEphemeralKey(StaticKeyExchangeInfo_t* staticKE, int keyAlgo, + const char* key, unsigned int keySz, int format, void* heap) +{ + int ret = 0; + byte* keyBuf = NULL; +#ifndef NO_FILESYSTEM + const char* keyFile = NULL; +#endif + /* allow empty key to free buffer */ + if (staticKE == NULL || (key == NULL && keySz > 0)) { + return BAD_FUNC_ARG; + } + + /* check if just free'ing key */ + if (key == NULL && keySz == 0) { + return 0; + } + +#ifndef NO_FILESYSTEM + /* load file from filesystem */ + if (key && keySz == 0) { + size_t keyBufSz = 0; + keyFile = (const char*)key; + ret = wc_FileLoad(keyFile, &keyBuf, &keyBufSz, heap); + if (ret != 0) { + return ret; + } + keySz = (unsigned int)keyBufSz; + } + else +#endif + { + /* use as key buffer directly */ + keyBuf = (byte*)key; + } + + if (format == WOLFSSL_FILETYPE_PEM) { + #ifdef WOLFSSL_PEM_TO_DER + int keyFormat = 0; + ret = PemToDer(keyBuf, keySz, PRIVATEKEY_TYPE, &staticKE->key, + heap, NULL, &keyFormat); + /* auto detect key type */ + if (ret == 0 && keyAlgo == 0) { + if (keyFormat == ECDSAk) + keyAlgo = WC_PK_TYPE_ECDH; + else + keyAlgo = WC_PK_TYPE_DH; + } + #else + ret = NOT_COMPILED_IN; + #endif + } + else { + ret = AllocDer(&staticKE->key, keySz, PRIVATEKEY_TYPE, heap); + if (ret == 0) { + XMEMCPY(staticKE->key->buffer, keyBuf, keySz); + } + } + staticKE->keyAlgo = keyAlgo; + +#ifndef NO_FILESYSTEM + if (keyFile && keyBuf) { + XFREE(keyBuf, heap, DYNAMIC_TYPE_TMP_BUFFER); + } +#endif + return ret; +} + +int wolfSSL_CTX_set_ephemeral_key(WOLFSSL_CTX* ctx, int keyAlgo, + const char* key, unsigned int keySz, int format) +{ + if (ctx == NULL) { + return BAD_FUNC_ARG; + } + + /* if key is already set free it */ + if (ctx->staticKE.key != NULL) { + FreeDer(&ctx->staticKE.key); + } + + return SetStaticEphemeralKey(&ctx->staticKE, keyAlgo, key, keySz, format, + ctx->heap); +} + +int wolfSSL_set_ephemeral_key(WOLFSSL* ssl, int keyAlgo, + const char* key, unsigned int keySz, int format) +{ + if (ssl == NULL) { + return BAD_FUNC_ARG; + } + + /* if key is already set and not created by ctx... set free it */ + if (ssl->staticKE.key != NULL && ssl->staticKE.key != ssl->ctx->staticKE.key) { + FreeDer(&ssl->staticKE.key); + } + + return SetStaticEphemeralKey(&ssl->staticKE, keyAlgo, key, keySz, format, + ssl->heap); +} + +#endif /* WOLFSSL_STATIC_EPHEMERAL */ diff --git a/src/tls.c b/src/tls.c index ff410ebf9a..1c67e15cdf 100644 --- a/src/tls.c +++ b/src/tls.c @@ -6621,14 +6621,14 @@ static int TLSX_KeyShare_GenDhKey(WOLFSSL *ssl, KeyShareEntry* kse) return ret; } - /* Allocate space for the public key. */ + /* Allocate space for the public key */ dataSz = params->p_len; keyData = (byte*)XMALLOC(dataSz, ssl->heap, DYNAMIC_TYPE_PUBLIC_KEY); if (keyData == NULL) { ret = MEMORY_E; goto end; } - /* Allocate space for the private key. */ + /* Allocate space for the private key */ key = (byte*)XMALLOC(keySz, ssl->heap, DYNAMIC_TYPE_PRIVATE_KEY); if (key == NULL) { ret = MEMORY_E; @@ -6642,20 +6642,34 @@ static int TLSX_KeyShare_GenDhKey(WOLFSSL *ssl, KeyShareEntry* kse) if (ret != 0) goto end; - /* Generate a new key pair. */ - ret = wc_DhGenerateKeyPair(dhKey, ssl->rng, (byte*)key, &keySz, keyData, - &dataSz); -#ifdef WOLFSSL_ASYNC_CRYPT - /* TODO: Make this function non-blocking */ - if (ret == WC_PENDING_E) { - ret = wc_AsyncWait(ret, &dhKey->asyncDev, WC_ASYNC_FLAG_NONE); +#if defined(WOLFSSL_STATIC_EPHEMERAL) && defined(WOLFSSL_DH_EXTRA) + if (ssl->staticKE.key && ssl->staticKE.keyAlgo == WC_PK_TYPE_DH) { + DerBuffer* keyDer = ssl->staticKE.key; + word32 idx = 0; + WOLFSSL_MSG("Using static DH key"); + ret = wc_DhKeyDecode(keyDer->buffer, &idx, dhKey, keyDer->length); + if (ret == 0) { + ret = wc_DhExportKeyPair(dhKey, (byte*)key, &keySz, keyData, &dataSz); + } } + else #endif + { + /* Generate a new key pair */ + ret = wc_DhGenerateKeyPair(dhKey, ssl->rng, (byte*)key, &keySz, keyData, + &dataSz); + #ifdef WOLFSSL_ASYNC_CRYPT + /* TODO: Make this function non-blocking */ + if (ret == WC_PENDING_E) { + ret = wc_AsyncWait(ret, &dhKey->asyncDev, WC_ASYNC_FLAG_NONE); + } + #endif + } if (ret != 0) goto end; if (params->p_len != dataSz) { - /* Pad the front of the key data with zeros. */ + /* Zero pad the front of the public key to match prime "p" size */ XMEMMOVE(keyData + params->p_len - dataSz, keyData, dataSz); XMEMSET(keyData, 0, params->p_len - dataSz); } @@ -6913,13 +6927,26 @@ static int TLSX_KeyShare_GenEccKey(WOLFSSL *ssl, KeyShareEntry* kse) ret = wc_ecc_init_ex(eccKey, ssl->heap, ssl->devId); if (ret != 0) goto end; - ret = wc_ecc_make_key_ex(ssl->rng, keySize, eccKey, curveId); -#ifdef WOLFSSL_ASYNC_CRYPT - /* TODO: Make this function non-blocking */ - if (ret == WC_PENDING_E) { - ret = wc_AsyncWait(ret, &eccKey->asyncDev, WC_ASYNC_FLAG_NONE); + +#ifdef WOLFSSL_STATIC_EPHEMERAL + if (ssl->staticKE.key && ssl->staticKE.keyAlgo == WC_PK_TYPE_ECDH) { + DerBuffer* keyDer = ssl->staticKE.key; + word32 idx = 0; + WOLFSSL_MSG("Using static ECDH key"); + ret = wc_EccPrivateKeyDecode(keyDer->buffer, &idx, eccKey, keyDer->length); } + else #endif + { + /* Generate ephemeral ECC key */ + ret = wc_ecc_make_key_ex(ssl->rng, keySize, eccKey, curveId); + #ifdef WOLFSSL_ASYNC_CRYPT + /* TODO: Make this function non-blocking */ + if (ret == WC_PENDING_E) { + ret = wc_AsyncWait(ret, &eccKey->asyncDev, WC_ASYNC_FLAG_NONE); + } + #endif + } if (ret != 0) goto end; @@ -9120,6 +9147,7 @@ void TLSX_FreeAll(TLSX* list, void* heap) MFL_FREE_ALL(extension->data, heap); break; + case TLSX_EXTENDED_MASTER_SECRET: case TLSX_TRUNCATED_HMAC: /* Nothing to do. */ break; @@ -9235,7 +9263,6 @@ static int TLSX_GetSize(TLSX* list, byte* semaphore, byte msgType, /* extension type + extension data length. */ length += HELLO_EXT_TYPE_SZ + OPAQUE16_LEN; - switch (extension->type) { case TLSX_SERVER_NAME: @@ -9254,6 +9281,7 @@ static int TLSX_GetSize(TLSX* list, byte* semaphore, byte msgType, length += MFL_GET_SIZE(extension->data); break; + case TLSX_EXTENDED_MASTER_SECRET: case TLSX_TRUNCATED_HMAC: /* always empty. */ break; @@ -9404,6 +9432,11 @@ static int TLSX_Write(TLSX* list, byte* output, byte* semaphore, offset += MFL_WRITE((byte*)extension->data, output + offset); break; + case TLSX_EXTENDED_MASTER_SECRET: + WOLFSSL_MSG("Extended Master Secret"); + /* always empty. */ + break; + case TLSX_TRUNCATED_HMAC: WOLFSSL_MSG("Truncated HMAC extension to write"); /* always empty. */ diff --git a/src/tls13.c b/src/tls13.c index eef2aa06d6..1b021f56a8 100644 --- a/src/tls13.c +++ b/src/tls13.c @@ -444,6 +444,9 @@ static const byte binderKeyLabel[BINDER_KEY_LABEL_SZ + 1] = static int DeriveBinderKey(WOLFSSL* ssl, byte* key) { WOLFSSL_MSG("Derive Binder Key"); + if (ssl == NULL || ssl->arrays == NULL) { + return BAD_FUNC_ARG; + } return DeriveKeyMsg(ssl, key, -1, ssl->arrays->secret, binderKeyLabel, BINDER_KEY_LABEL_SZ, NULL, 0, ssl->specs.mac_algorithm); @@ -467,6 +470,9 @@ static const byte binderKeyResumeLabel[BINDER_KEY_RESUME_LABEL_SZ + 1] = static int DeriveBinderKeyResume(WOLFSSL* ssl, byte* key) { WOLFSSL_MSG("Derive Binder Key - Resumption"); + if (ssl == NULL || ssl->arrays == NULL) { + return BAD_FUNC_ARG; + } return DeriveKeyMsg(ssl, key, -1, ssl->arrays->secret, binderKeyResumeLabel, BINDER_KEY_RESUME_LABEL_SZ, NULL, 0, ssl->specs.mac_algorithm); @@ -491,6 +497,9 @@ static int DeriveEarlyTrafficSecret(WOLFSSL* ssl, byte* key) { int ret; WOLFSSL_MSG("Derive Early Traffic Secret"); + if (ssl == NULL || ssl->arrays == NULL) { + return BAD_FUNC_ARG; + } ret = DeriveKey(ssl, key, -1, ssl->arrays->secret, earlyTrafficLabel, EARLY_TRAFFIC_LABEL_SZ, ssl->specs.mac_algorithm, 1); @@ -523,6 +532,9 @@ static int DeriveEarlyExporterSecret(WOLFSSL* ssl, byte* key) { int ret; WOLFSSL_MSG("Derive Early Exporter Secret"); + if (ssl == NULL || ssl->arrays == NULL) { + return BAD_FUNC_ARG; + } ret = DeriveKey(ssl, key, -1, ssl->arrays->secret, earlyExporterLabel, EARLY_EXPORTER_LABEL_SZ, ssl->specs.mac_algorithm, 1); @@ -556,6 +568,9 @@ static int DeriveClientHandshakeSecret(WOLFSSL* ssl, byte* key) { int ret; WOLFSSL_MSG("Derive Client Handshake Secret"); + if (ssl == NULL || ssl->arrays == NULL) { + return BAD_FUNC_ARG; + } ret = DeriveKey(ssl, key, -1, ssl->arrays->preMasterSecret, clientHandshakeLabel, CLIENT_HANDSHAKE_LABEL_SZ, ssl->specs.mac_algorithm, 1); @@ -587,6 +602,9 @@ static int DeriveServerHandshakeSecret(WOLFSSL* ssl, byte* key) { int ret; WOLFSSL_MSG("Derive Server Handshake Secret"); + if (ssl == NULL || ssl->arrays == NULL) { + return BAD_FUNC_ARG; + } ret = DeriveKey(ssl, key, -1, ssl->arrays->preMasterSecret, serverHandshakeLabel, SERVER_HANDSHAKE_LABEL_SZ, ssl->specs.mac_algorithm, 1); @@ -618,6 +636,9 @@ static int DeriveClientTrafficSecret(WOLFSSL* ssl, byte* key) { int ret; WOLFSSL_MSG("Derive Client Traffic Secret"); + if (ssl == NULL || ssl->arrays == NULL) { + return BAD_FUNC_ARG; + } ret = DeriveKey(ssl, key, -1, ssl->arrays->masterSecret, clientAppLabel, CLIENT_APP_LABEL_SZ, ssl->specs.mac_algorithm, 1); @@ -649,6 +670,9 @@ static int DeriveServerTrafficSecret(WOLFSSL* ssl, byte* key) { int ret; WOLFSSL_MSG("Derive Server Traffic Secret"); + if (ssl == NULL || ssl->arrays == NULL) { + return BAD_FUNC_ARG; + } ret = DeriveKey(ssl, key, -1, ssl->arrays->masterSecret, serverAppLabel, SERVER_APP_LABEL_SZ, ssl->specs.mac_algorithm, 1); @@ -681,6 +705,9 @@ static int DeriveExporterSecret(WOLFSSL* ssl, byte* key) { int ret; WOLFSSL_MSG("Derive Exporter Secret"); + if (ssl == NULL || ssl->arrays == NULL) { + return BAD_FUNC_ARG; + } ret = DeriveKey(ssl, key, -1, ssl->arrays->masterSecret, exporterMasterLabel, EXPORTER_MASTER_LABEL_SZ, ssl->specs.mac_algorithm, 1); @@ -713,6 +740,9 @@ static const byte resumeMasterLabel[RESUME_MASTER_LABEL_SZ + 1] = static int DeriveResumptionSecret(WOLFSSL* ssl, byte* key) { WOLFSSL_MSG("Derive Resumption Secret"); + if (ssl == NULL || ssl->arrays == NULL) { + return BAD_FUNC_ARG; + } return DeriveKey(ssl, key, -1, ssl->arrays->masterSecret, resumeMasterLabel, RESUME_MASTER_LABEL_SZ, ssl->specs.mac_algorithm, 1); @@ -761,9 +791,12 @@ static int DeriveTrafficSecret(WOLFSSL* ssl, byte* secret) * * ssl The SSL/TLS object. */ -static int DeriveEarlySecret(WOLFSSL* ssl) +int DeriveEarlySecret(WOLFSSL* ssl) { WOLFSSL_MSG("Derive Early Secret"); + if (ssl == NULL || ssl->arrays == NULL) { + return BAD_FUNC_ARG; + } #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) return Tls13_HKDF_Extract(ssl->arrays->secret, NULL, 0, ssl->arrays->psk_key, ssl->arrays->psk_keySz, @@ -784,13 +817,14 @@ static const byte derivedLabel[DERIVED_LABEL_SZ + 1] = * * ssl The SSL/TLS object. */ -static int DeriveHandshakeSecret(WOLFSSL* ssl) +int DeriveHandshakeSecret(WOLFSSL* ssl) { byte key[WC_MAX_DIGEST_SIZE]; int ret; - WOLFSSL_MSG("Derive Handshake Secret"); - + if (ssl == NULL || ssl->arrays == NULL) { + return BAD_FUNC_ARG; + } ret = DeriveKeyMsg(ssl, key, -1, ssl->arrays->secret, derivedLabel, DERIVED_LABEL_SZ, NULL, 0, ssl->specs.mac_algorithm); @@ -807,13 +841,14 @@ static int DeriveHandshakeSecret(WOLFSSL* ssl) * * ssl The SSL/TLS object. */ -static int DeriveMasterSecret(WOLFSSL* ssl) +int DeriveMasterSecret(WOLFSSL* ssl) { byte key[WC_MAX_DIGEST_SIZE]; int ret; - WOLFSSL_MSG("Derive Master Secret"); - + if (ssl == NULL || ssl->arrays == NULL) { + return BAD_FUNC_ARG; + } ret = DeriveKeyMsg(ssl, key, -1, ssl->arrays->preMasterSecret, derivedLabel, DERIVED_LABEL_SZ, NULL, 0, ssl->specs.mac_algorithm); @@ -838,8 +873,7 @@ static const byte resumptionLabel[RESUMPTION_LABEL_SZ+1] = "resumption"; * secret The derived secret. * returns 0 on success, otherwise failure. */ -static int DeriveResumptionPSK(WOLFSSL* ssl, byte* nonce, byte nonceLen, - byte* secret) +int DeriveResumptionPSK(WOLFSSL* ssl, byte* nonce, byte nonceLen, byte* secret) { int digestAlg; /* Only one protocol version defined at this time. */ @@ -894,6 +928,10 @@ static int BuildTls13HandshakeHmac(WOLFSSL* ssl, byte* key, byte* hash, int hashSz = WC_SHA256_DIGEST_SIZE; int ret = BAD_FUNC_ARG; + if (ssl == NULL || key == NULL || hash == NULL) { + return BAD_FUNC_ARG; + } + /* Get the hash of the previous handshake messages. */ switch (ssl->specs.mac_algorithm) { #ifndef NO_SHA256 @@ -965,7 +1003,7 @@ static const byte writeIVLabel[WRITE_IV_LABEL_SZ+1] = "iv"; * store ready for provisioning. * returns 0 on success, otherwise failure. */ -static int DeriveTls13Keys(WOLFSSL* ssl, int secret, int side, int store) +int DeriveTls13Keys(WOLFSSL* ssl, int secret, int side, int store) { int ret = BAD_FUNC_ARG; /* Assume failure */ int i = 0; @@ -1321,39 +1359,6 @@ end: #endif /* HAVE_SESSION_TICKET || !NO_PSK */ -#if !defined(NO_WOLFSSL_SERVER) && (defined(HAVE_SESSION_TICKET) || \ - !defined(NO_PSK)) -/* Add input to all handshake hashes. - * - * ssl The SSL/TLS object. - * input The data to hash. - * sz The size of the data to hash. - * returns 0 on success, otherwise failure. - */ -static int HashInputRaw(WOLFSSL* ssl, const byte* input, int sz) -{ - int ret = BAD_FUNC_ARG; - -#ifndef NO_SHA256 - ret = wc_Sha256Update(&ssl->hsHashes->hashSha256, input, sz); - if (ret != 0) - return ret; -#endif -#ifdef WOLFSSL_SHA384 - ret = wc_Sha384Update(&ssl->hsHashes->hashSha384, input, sz); - if (ret != 0) - return ret; -#endif -#ifdef WOLFSSL_TLS13_SHA512 - ret = wc_Sha512Update(&ssl->hsHashes->hashSha512, input, sz); - if (ret != 0) - return ret; -#endif - - return ret; -} -#endif - /* Extract the handshake header information. * * ssl The SSL/TLS object. @@ -2402,10 +2407,10 @@ static int RestartHandshakeHash(WOLFSSL* ssl) ret = InitHandshakeHashes(ssl); if (ret != 0) return ret; - ret = HashOutputRaw(ssl, header, sizeof(header)); + ret = HashRaw(ssl, header, sizeof(header)); if (ret != 0) return ret; - return HashOutputRaw(ssl, hash, hashSz); + return HashRaw(ssl, hash, hashSz); } /* The value in the random field of a ServerHello to indicate @@ -2578,7 +2583,7 @@ static int WritePSKBinders(WOLFSSL* ssl, byte* output, word32 idx) return ret; /* Hash binders to complete the hash of the ClientHello. */ - ret = HashOutputRaw(ssl, output + idx, len); + ret = HashRaw(ssl, output + idx, len); if (ret < 0) return ret; @@ -3456,7 +3461,7 @@ static int DoPreSharedKeys(WOLFSSL* ssl, const byte* input, word32 helloSz, } /* Hash the rest of the ClientHello. */ - ret = HashInputRaw(ssl, input + helloSz - bindersLen, bindersLen); + ret = HashRaw(ssl, input + helloSz - bindersLen, bindersLen); if (ret != 0) return ret; @@ -3624,9 +3629,9 @@ static int RestartHandshakeHashWithCookie(WOLFSSL* ssl, Cookie* cookie) AddTls13HandShakeHeader(header, hashSz, 0, 0, message_hash, ssl); if ((ret = InitHandshakeHashes(ssl)) != 0) return ret; - if ((ret = HashOutputRaw(ssl, header, sizeof(header))) != 0) + if ((ret = HashRaw(ssl, header, sizeof(header))) != 0) return ret; - if ((ret = HashOutputRaw(ssl, cookieData + idx, hashSz)) != 0) + if ((ret = HashRaw(ssl, cookieData + idx, hashSz)) != 0) return ret; /* Reconstruct the HelloRetryMessage for handshake hash. */ @@ -3705,9 +3710,9 @@ static int RestartHandshakeHashWithCookie(WOLFSSL* ssl, Cookie* cookie) WOLFSSL_BUFFER(cookieData, cookie->len); #endif - if ((ret = HashOutputRaw(ssl, hrr, hrrIdx)) != 0) + if ((ret = HashRaw(ssl, hrr, hrrIdx)) != 0) return ret; - return HashOutputRaw(ssl, cookieData, cookie->len); + return HashRaw(ssl, cookieData, cookie->len); } #endif @@ -5849,7 +5854,7 @@ exit_dcv: * sniff Indicates whether we are sniffing packets. * returns 0 on success and otherwise failure. */ -static int DoTls13Finished(WOLFSSL* ssl, const byte* input, word32* inOutIdx, +int DoTls13Finished(WOLFSSL* ssl, const byte* input, word32* inOutIdx, word32 size, word32 totalSz, int sniff) { int ret; @@ -5888,19 +5893,22 @@ static int DoTls13Finished(WOLFSSL* ssl, const byte* input, word32* inOutIdx, secret = ssl->keys.server_write_MAC_secret; } - else + else { secret = ssl->keys.client_write_MAC_secret; + } - ret = BuildTls13HandshakeHmac(ssl, secret, mac, &finishedSz); - if (ret != 0) - return ret; - if (size != finishedSz) - return BUFFER_ERROR; + if (sniff == NO_SNIFF) { + ret = BuildTls13HandshakeHmac(ssl, secret, mac, &finishedSz); + if (ret != 0) + return ret; + if (size != finishedSz) + return BUFFER_ERROR; + } - #ifdef WOLFSSL_CALLBACKS - if (ssl->hsInfoOn) AddPacketName(ssl, "Finished"); - if (ssl->toInfoOn) AddLateName("Finished", &ssl->timeoutInfo); - #endif +#ifdef WOLFSSL_CALLBACKS + if (ssl->hsInfoOn) AddPacketName(ssl, "Finished"); + if (ssl->toInfoOn) AddLateName("Finished", &ssl->timeoutInfo); +#endif if (sniff == NO_SNIFF) { /* Actually check verify data. */ @@ -6349,8 +6357,8 @@ static int DoTls13NewSessionTicket(WOLFSSL* ssl, const byte* input, word32 ageAdd; word16 length; word32 now; - const byte* nonce; - byte nonceLength; + const byte* nonce; + byte nonceLength; WOLFSSL_START(WC_FUNC_NEW_SESSION_TICKET_DO); WOLFSSL_ENTER("DoTls13NewSessionTicket"); @@ -6506,14 +6514,14 @@ static int ExpectedResumptionSecret(WOLFSSL* ssl) #ifdef WOLFSSL_EARLY_DATA if (ssl->earlyData != no_early_data) { static byte endOfEarlyData[] = { 0x05, 0x00, 0x00, 0x00 }; - ret = HashInputRaw(ssl, endOfEarlyData, sizeof(endOfEarlyData)); + ret = HashRaw(ssl, endOfEarlyData, sizeof(endOfEarlyData)); if (ret != 0) return ret; } #endif - if ((ret = HashInputRaw(ssl, header, sizeof(header))) != 0) + if ((ret = HashRaw(ssl, header, sizeof(header))) != 0) return ret; - if ((ret = HashInputRaw(ssl, mac, finishedSz)) != 0) + if ((ret = HashRaw(ssl, mac, finishedSz)) != 0) return ret; if ((ret = DeriveResumptionSecret(ssl, ssl->session.masterSecret)) != 0) diff --git a/sslSniffer/README.md b/sslSniffer/README.md new file mode 100644 index 0000000000..a9c48eecc6 --- /dev/null +++ b/sslSniffer/README.md @@ -0,0 +1,640 @@ +# wolfSSL Sniffer + +The wolfSSL sniffer can be used to passively sniff SSL traffic including https traffic. Of course the server’s private key is required in order to decode the SSL handshake and allow future decryption of SSL messages. Input to the sniffer should be raw packets beginning with the IP header. + +## Installation + +The wolfSSL sniffer requires the wolfSSL library version 1.8.0 or later. Future releases can be obtained from http://www.wolfssl.com + +To build and install wolfSSL including the wolfSSL sniffer: + +```sh +./configure --enable-sniffer +make +sudo make install +``` + + +## Build Options + +The wolfSSL sniffer has several build options to include some extra behavior: SSL Statistics, Session Watching, Store Data Callback, Chain Input, and allowing STARTTLS protocols. + +The SSL Statistics option provides the logging of some additional statistics regarding the sessions being decoded. The statistics tracking uses a mutex to protect access to the tracking storage. To enable this option, use the following configure command line and build as before: + +`./configure --enable-sniffer CPPFLAGS=-DWOLFSSL_SNIFFER_STATS` + +The Session Watching option allows the sniffer to watch any packet provided it without initial setup. It will start to decode all TLS sessions and when the server’s certificate is detected, the certificate is given to a callback function provided by the user which should provide the appropriate private key. To enable this option, use the following configure command line and build as before: + +`./configure --enable-sniffer CPPFLAGS=-DWOLFSSL_SNIFFER_WATCH` + +The Store Data Callback option allows the sniffer to take a callback that is called when storing the application data into a custom buffer rather than into the reallocated data pointer the callback is called in a loop until all data is consumed. To enable this option, use the following configure command line and build as before: + +`./configure --enable-sniffer CPPFLAGS=-DWOLFSSL_SNIFFER_STORE_DATA_CB` + +The Chain Input option allows the sniffer to receive its input as a struct iovec list rather than a pointer to a raw packet. To enable this option, use the following configure command line and build as before: + +`./configure --enable-sniffer CPPFLAGS=-DWOLFSSL_SNIFFER_CHAIN_INPUT` + +The STARTTLS option allows the sniffer to receive and ignore plaintext before receiving the first TLS handshake message. This is useful for protocols like SMTP and POP3 which start out in plaintext and switch to TLS during the connection. To enable this option, use the following configure command line and build as before: + +`./configure --enable-sniffer CPPFLAGS=-DSTARTTLS_ALLOWED` + +All options may be enabled with the following configure command line: + +```sh +./configure --enable-sniffer \ + CPPFLAGS=”-DWOLFSSL_SNIFFER_STATS -DWOLFSSL_SNIFFER_WATCH \ + -DWOLFSSL_SNIFFER_STORE_DATA_CB -DWOLFSSL_SNIFFER_CHAIN_INPUT \ + -DSTARTTLS_ALLOWED” +``` + +To add some other cipher support to the sniffer, you can add options like: + +```sh +--enable-arc4 +--enable-nullcipher +--enable-des3 +``` + +By default, wolfSSL restricts RSA key sizes to 1024-bits minimum. To allow the decoding of smaller, less secure RSA keys like 512-bit keys, you will need to add the compiler flag `-DWOLFSSL_MIN_RSA_BITS=512` to CFLAGS or CPPFLAGS, or define it in your user-settings header. + + +## Synchronous Cryptography Offload Options + +The sniffer can take advantage of some crypto offload hardware if available. If you have an Intel QuickAssist board or a Cavium OCTEON II or III. Currently, only the algorithms AES-CBC, AES-GCM, and DES3-CBC are offloaded to the hardware. These directions assume you already have the QAT or OCTEON-SDK libraries built. + +To build for QAT, use the following configure options: + +```sh +./configure --enable-sniffer --enable-cryptocb \ + --with-intelqa-sync=/path/to/qat +``` + +To build with OCTEON II support for a standalone host: + +```sh +./configure --enable-sniffer --enable-cryptocb \ + --with-octeon-sync=/path/to/octeon-sdk +``` + +To build with OCTEON III support for a Linux host: + +```sh +./configure --enable-sniffer --enable-cryptocb \ + --with-octeon-sync=/path/to/octeon-sdk \ + OCTEON_OBJ=obj-octeon3 OCTEON_HOST=linux +``` + + +## Command Line Options + +The wolfSSL sniffer includes a test application `snifftest` in the `sslSniffer/sslSnifferTest/ directory`. The command line application has several options that can be passed in at runtime to change the default behavior of the application. To execute a “live” sniff just run the application without any parameters and then pick an interface to sniff on followed by the port. + +An example startup may look like this: + +```sh +$ cd sslSniffer/sslSnifferTest +$ ./snifftest + +1. en0 (No description available) +2. fw0 (No description available) +3. en1 (No description available) +4. fw1 (No description available) +5. p2p0 (No description available) +6. en3 (No description available) +7. lo0 (No description available) + +Enter the interface number (1-7): 7 +server = 127.0.0.1 +server = ::1 +server = fe80::1 + +Enter the port to scan: 11111 +``` + +The above example sniffs on the localhost interface (lo0) with the default wolfSSL port of 11111 and uses the default wolfSSL server key `../../certs/server-key.pem` for RSA and `../../certs/ecc-key.pem` for ECC. + +Trace output will be written to a file named `tracefile.txt`. + +To decode a previously saved pcap file you will need to enter a few parameters. + +The following table lists the accepted inputs in saved file mode. + +Synopsis: + +`snifftest dumpFile pemKey [server] [port] [password]` + +`snifftest` Options Summary: + +``` +Option Description Default Value +dumpFile A previously saved pcap file NA +pemKey The server’s private key in PEM format NA +server The server’s IP address (v4 or v6) 127.0.0.1 +port The server port to sniff 443 +password Private Key Password if required NA +``` + +To decode a pcap file named test.pcap with a server key file called myKey.pem that was generated on the localhost with a server at port 443 just use: + +`./snifftest test.pcap myKey.pem` + +If the server was on 10.0.1.2 and on port 12345 you could instead use: + +`./snifftest test.pcap myKey.pem 10.0.1.2 12345` + +If the server was on localhost using IPv6 and on port 12345 you could instead use: + +`./snifftest test.pcap myKey.pem ::1 12345` + + +## API Usage + +The wolfSSL sniffer can be integrated into any application using the existing sniffer API. + +Use the include `#include `. + +### ssl_InitSniffer + +```c +void ssl_InitSniffer(void); +``` + +Initializes the wolfSSL sniffer for use and should be called once per application. + +### ssl_FreeSniffer + +```c +void ssl_FreeSniffer(void); +``` + +Frees all resources consumed by the wolfSSL sniffer and should be called when use of the wolfSSL sniffer is no longer required. + +### ssl_Trace + +```c +int ssl_Trace(const char* traceFile, char* error); +``` + +Enables Tracing when a file is passed in. Disables Tracing if previously on and a NULL value is passed in for the file. + +Returns Values: + +* 0 on success +* -1 if a problem occurred, the string error will hold a message describing the problem + +### ssl_SetPrivateKey + +```c +int ssl_SetPrivateKey(const char* serverAddress, int port, + const char* keyFile, int keyFormat, + const char* password, char* error); +``` + +Creates a sniffer session based on the `serverAddress` and `port` inputs using the ECC or RSA `keyFile` as the server’s key. + +The `keyFormat` can be either `FILETYPE_PEM` or `FILETYPE_DER`. If the keyFile has password protection then the password parameter can hold the proper value. + +Return Values: + +* 0 on success +* -1 if a problem occurred, the string error will hold a message describing the problem + +### ssl_SetPrivateKeyBuffer + +```c +int ssl_SetPrivateKeyBuffer(const char* address, int port, + const char* keyBuf, int keySz, int typeKey, + const char* password, char* error) +``` + +Creates a sniffer session based on the `serverAddress` and `port` inputs using the ECC or RSA `keyBuf` and `keySz` as the server’s key. + +The `keyFormat` can be either `FILETYPE_PEM` or `FILETYPE_DER`. If the keyFile has password protection then the password parameter can hold the proper value. + +Return Values: + +* 0 on success +* -1 if a problem occurred, the string error will hold a message describing the problem + + +### ssl_SetNamedPrivateKey + +```c +int ssl_SetNamedPrivateKey(const char* name, + const char* serverAddress, int port, + const char* keyFile, int keyFormat, + const char* password, char* error); +``` + +Creates a sniffer session for a server named `name` based on the `serverAddress` and `port` inputs using the ECC or RSA `keyFile` as the server’s key. + +The `keyFormat` can be either `FILETYPE_PEM` or `FILETYPE_DER`. If the keyFile has password protection then the password parameter can hold the proper value. + +This function requires that the SNI extension is enabled in the build (`HAVE_SNI`). + +Return Values: + +* 0 on success +* -1 if a problem occurred, the string error will hold a message describing the problem + +### ssl_SetNamedPrivateKeyBuffer + +```c +int ssl_SetNamedPrivateKeyBuffer(const char* name, + const char* address, int port, + const char* keyBuf, int keySz, int typeKey, + const char* password, char* error) +``` + +Creates a sniffer session for a server named `name` based on the `serverAddress` and `port` inputs using the ECC or RSA `keyBuf` and `keySz` as the server’s key. + +The `keyFormat` can be either `FILETYPE_PEM` or `FILETYPE_DER`. If the keyFile has password protection then the password parameter can hold the proper value. + +This function requires that the SNI extension is enabled in the build (`HAVE_SNI`). + +Return Values: + +* 0 on success +* -1 if a problem occurred, the string error will hold a message describing the problem + +### ssl_SetNamedEphemeralKey + +```c +int ssl_SetNamedEphemeralKey(const char* name, + const char* address, int port, + const char* keyFile, int typeKey, + const char* password, char* error) +``` + +Creates a sniffer session for a server named `name` based on the `serverAddress` and `port` inputs using ECC or DH static ephemeral key. + +The `keyFormat` can be either `FILETYPE_PEM` or `FILETYPE_DER`. If the keyFile has password protection then the password parameter can hold the proper value. + +This function requires that static ephemeral key support (`WOLFSSL_STATIC_EPHEMERAL`) and the SNI extension (`HAVE_SNI`) are enabled in the build. + +Return Values: + +* 0 on success +* -1 if a problem occurred, the string error will hold a message describing the problem + +### ssl_SetEphemeralKey + +```c +int ssl_SetEphemeralKey(const char* address, int port, + const char* keyFile, int typeKey, + const char* password, char* error) +``` +Creates a sniffer session based on the `serverAddress` and `port` inputs using ECC or DH static ephemeral key. + +The `keyFormat` can be either `FILETYPE_PEM` or `FILETYPE_DER`. If the keyFile has password protection then the password parameter can hold the proper value. + +This function requires that static ephemeral key support (`WOLFSSL_STATIC_EPHEMERAL`) and the SNI extension (`HAVE_SNI`) are enabled in the build. + +Return Values: + +* 0 on success +* -1 if a problem occurred, the string error will hold a message describing the problem + +### ssl_DecodePacket + +```c +int ssl_DecodePacket(const unsigned char** packet, int length, + unsigned char* data, char* error); +``` + +### ssl_DecodePacketWithSessionInfo + +```c +int ssl_DecodePacketWithSessionInfo(const unsigned char* packet, int length, + unsigned char** data, SSLInfo* sslInfo, char* error); +``` + +Decodes a raw packet that begins with the IP header and is length bytes long. Any SSL application data will be stored in data which should be at least 16,384 bytes, the maximum SSL record size. Information about the SSL session will be copied into `sslInfo` if it is non-null. + +The `SSLInfo` structure can be found in `sniffer.h`. It has information about the protocol version, cipher suite, server name indication, and key size in bits. + +```c +typedef struct SSLInfo +{ + unsigned char isValid; /* indicates if the info in this struct is valid: 0 = no, 1 = yes */ + unsigned char protocolVersionMajor; /* SSL Version: major */ + unsigned char protocolVersionMinor; /* SSL Version: minor */ + unsigned char serverCipherSuite0; /* first byte, normally 0 */ + unsigned char serverCipherSuite; /* second byte, actual suite */ + unsigned char serverCipherSuiteName[256]; /* cipher name, e.g., "TLS_RSA_..." */ + unsigned char serverNameIndication[128]; + unsigned int keySize; +} SSLInfo; +``` + +Return Values: + +* >0 on success and indicates the number of bytes written to data +* 0 indicates no SSL data is ready yet +* -1 if a problem occurred, the string error will hold a message describing the problem + + +### ssl_SetConnectionCb + +```c +int ssl_SetConnectionCb(SSLConnCb cb); +``` + +Sets a callback function that will be called when the full session information is known and will provide a pointer to the session’s information. The callback function has the signature: + +```c +typedef void (*SSLConnCb)(const void* session, SSLInfo* info, void* ctx); +``` + +Where session is the current session. info will be a pointer to the session’s info. The ctx is application specific context data passed to the callback. + +Return Values: + +* >0 on success and indicates the number of bytes written to data +* 0 indicates no SSL data is ready yet +* -1 if a problem occurred, the string error will hold a message describing the problem + +### ssl_SetConnectionCtx + +```c +int ssl_SetConnectionCtx(void* ctx); +``` + +Stores ctx, a pointer to application specific context data that will be passed to the connection callback function. The wolfSSL sniffer will not know anything about the context data. + +Return Values: + +* 0 on success +* -1 if a problem occurred + + +## API Usage: SSL Statistics options + +For an example on the use of the sniffer stats option, search the source `snifftest.c` for `WOLFSSL_SNIFFER_STATS`. + +See the header file `sniffer.h` for the structure `SSLStats` for the list of statistics that can be read. + +```c +typedef struct SSLStats +{ + unsigned long int sslStandardConns; + unsigned long int sslClientAuthConns; + unsigned long int sslResumedConns; + unsigned long int sslEphemeralMisses; + unsigned long int sslResumeMisses; + unsigned long int sslCiphersUnsupported; + unsigned long int sslKeysUnmatched; + unsigned long int sslKeyFails; + unsigned long int sslDecodeFails; + unsigned long int sslAlerts; + unsigned long int sslDecryptedBytes; + unsigned long int sslEncryptedBytes; + unsigned long int sslEncryptedPackets; + unsigned long int sslDecryptedPackets; + unsigned long int sslKeyMatches; + unsigned long int sslEncryptedConns; + + unsigned long int sslResumptionValid; + unsigned long int sslResumptionInserts; +} SSLStats; +``` + +### ssl_ResetStatistics + +```c +int ssl_ResetStatistics(void); +``` + +Zeroes out the SSL sniffer statistics tracking storage. + +Return Values: + +* 0 on success +* -1 if a problem occurred + +### ssl_ReadStatistics + +```c +int ssl_ReadStatistics(SSLStats* stats); +``` + +Copies the SSL sniffer statistics into the provided `SSLStats` record, stats. + +Return Values: + +* 0 on success +* -1 if a problem occurred + +### ssl_ReadResetStatistics + +```c +int ssl_ReadResetStatistics(SSLStats* stats); +``` + +Copies the SSL sniffer statistics into the provided `SSLStats` records, stats, and then zeroes out the SSL sniffer statistics tracking storage in one action. + +Return Values: + +* 0 on success +* -1 if a problem occurred + + +## API Usage: Session Watching option + +For an example on the use of the session watching option, search the source `snifftest.c` for `WOLFSSL_SNIFFER_WATCH`. + +### ssl_SetWatchKeyCallback + +```c +int ssl_SetWatchKeyCallback(SSLWatchCb cb, char* error); +int ssl_SetWatchKeyCallback_ex(SSLWatchCb cb, int devId, char* error); +``` + +Assigns a callback function to the wolfSSL sniffer used to locate and load a private key for a session at the time the sniffer knows the true identity of the server, when receiving its certificate message. The callback function is given to the parameter cb and any error string will be written into error. The function ssl_SetWatchKeyCallback_ex() takes an additional parameter called devId, the device ID of the hardware device handling the cryptography. The callback function has the signature: + +```c +typedef int (*SSLWatchCb)(void* vSniffer, + const unsigned char* certHash, unsigned int certHashSz, + const unsigned char* certChain, unsigned int certChainSz, + void* ctx, char* error); +``` + +The parameter `vSniffer` is a typeless pointer to the current sniffer session and is meant to be passed directly to the function `ssl_SetWatchKey`. `certHash` is a SHA-256 hash of the certificate sent by the server, and its size is `certHashSz`. A pointer to certificate message’s payload is provided in the parameter `certChain`, and the certificate chain’s size in `certChainSz`. This will be a list of pairs of 24-bit certificate sizes and raw DER certificates in network order from the wire. The application space callback context data is provided in parameter ctx and is set by the function `ssl_SetWatchKeyCtx`. Any error string is copied into parameter error. Your callback function can use these values to locate the appropriate private key and load it into the sniffer session with the function `ssl_SetWatchKey`. + +Return Values: + +* 0 on success +* -1 if a problem occurred, the string error will hold a message describing the problem + +### ssl_SetWatchKeyCtx + +```c +int ssl_SetWatchKeyCtx(void* ctx, char* error); +``` + +Stores ctx, a pointer to application specific context data that will be passed to the watch key callback function. The wolfSSL sniffer will not know anything about the context data. + +Return Values: + +* 0 on success +* -1 if a problem occurred, the string error will hold a message describing the problem + +### ssl_SetWatchKey_file + +```c +int ssl_SetWatchKey_file(void* vSniffer, const char* keyFile, int keyType, + const char* password, char* error); +``` + +This function must be called from the watch key callback. Gives the sniffer session, vSniffer, the private key to be used to decrypt the pre-master secret. The key’s file name is given in the parameter keyFile, and that file will be loaded. The keyType is either `FILETYPE_PEM` or `FILETYPE_DER`. If the private key is encrypted, provide the text string password. Any error string is returned in error. + +Return Values: + +* 0 on success +* -1 if a problem occurred, the string error will hold a message describing the problem + +### ssl_SetWatchKey_buffer + +```c +int ssl_SetWatchKey_buffer(void* vSniffer, const unsigned char* key, + unsigned int keySz, int keyType, char* error); +``` + +This function must be called from the watch key callback. Gives the sniffer session, vSniffer, the private key to be used to decrypt the pre-master secret. The key is passed in by the pointer key, and is of size keySz. The keyType is either `FILETYPE_PEM` or `FILETYPE_DER`. Any error string is returned in error. + +Return Values: + +* 0 on success +* -1 if a problem occurred, the string error will hold a message describing the problem + + +## API Usage: Store Data Callback option + +For an example on the use of the store data callback option, search the source `snifftest.c` for `WOLFSSL_SNIFFER_STORE_DATA_CB`. + +### ssl_SetStoreDataCallback + +```c +int ssl_SetStoreDataCallback(SSLStoreDataCb cb); +``` + +Assigns a callback function to the wolfSSL sniffer used to store data when processing an application data record. The callback function is given to the parameter cb. + +The callback function has the signature: + +```c +typedef int (*SSLStoreDataCb)(const unsigned char* decryptBuf, + unsigned int decryptBufSz, unsigned int decryptBufOffset, + void* ctx); +``` + +The parameter `decryptBuf` is a pointer to the beginning of the decrypted application data buffer. The value `decryptBufSz` is the number of bytes stored in the `decryptBuf`. `decryptBufOffset` is the offset into the `decryptBuf` where a copy should start. The `ctx` is an application specific parameter passed in the call to `ssl_DecodePacketWithSessionInfoStoreData()`. The callback should return the number of bytes copied out of `decryptBuf`. `decryptBufOffset` is a running sum of the bytes returned by the callback, and the loop stops when all bytes are consumed. + +Return Values: + +* 0 on success +* -1 if a problem occurred + +### ssl_DecodePacketWithSessionInfoStoreData + +```c +int ssl_DecodePacketWithSessionInfoStoreData(const unsigned char* packet, + in1t length, void* ctx, SSLInfo* sslInfo, char* error); +``` + +Decodes a raw packet that begins with the IP header and is length bytes long. Any SSL application data will be handed to the store data callback function, along with the parameter `ctx`. Information about the SSL session will be copied into `sslInfo` if it is non-null. + +The SSLInfo structure can be found in sniffer.h. It has information about the protocol version, cipher suite, server name indication, and key size in bits. + +Return Values: + +* >0 on success and indicates the number of bytes written by the store data callback +* 0 indicates no SSL data is ready yet +* -1 if a problem occurred, the string error will hold a message describing the problem + + +## API Usage: Chain Input option + +For an example on the use of the chain input option, search the source `snifftest.c` for `WOLFSSL_SNIFFER_CHAIN_INPUT`. + +### ssl_DecodePacketWithChain + +```c +int ssl_DecodePacketWithChain(void* vChain, unsigned int chainSz, + unsigned char** data, char* error); +``` + +Decodes a raw chain of packet buffers stored in an iovec passed in as the value vChain. The first buffer in the chain begins with the IP header. The chain is chainSz packets long. Any SSL application data will be stored in data, which may be allocated by the sniffer. Information about the SSL session will be copied into sslInfo if it is non-null. + +The SSLInfo structure can be found in sniffer.h. It has information about the protocol version, cipher suite, server name indication, and key size in bits. + +Return Values: + +* >0 on success and indicates the number of bytes written by the store data callback +* 0 indicates no SSL data is ready yet +* -1 if a problem occurred, the string error will hold a message describing the problem + +### ssl_DecodePacketWithChainSessionInfoStoreData + +```c +int ssl_DecodePacketWithChainSessionInfoStoreData(void* vChain, + unsigned int chainSz, void* ctx, SSLInfo* sslInfo, char* error); +``` + +This combines the options of decoding a chain input and storing data using a callback. Decodes a raw chain of packet buffers stored in an iovec passed in as the value vChain. The first buffer in the chain begins with the IP header. The chain is chainSz packets long. Any SSL application data will be handed to the store data callback function, along with the parameter ctx. Information about the SSL session will be copied into sslInfo if it is non-null. + +The SSLInfo structure can be found in sniffer.h. It has information about the protocol version, cipher suite, server name indication, and key size in bits. + +Return Values: + +* >0 on success and indicates the number of bytes written by the store data callback +* 0 indicates no SSL data is ready yet +* -1 if a problem occurred, the string error will hold a message describing the problem + + +## Notes + +### Performance + +Once your SSL sniffing is working as expected you should be able to get some performance gains by compiling wolfSSL with fastmath enabled. You can do this by adding `--enable-fastmath` to your ./configure options. + +### Start up + +Remember to always start the sniffing application before the server. This is important because if the SSL handshake is missed then future packets from that session will not be decoded. In addition, any future sessions that use the “missed” session to do session resumption, renegotiation, or use session tickets based on that “missed” session will have the same problems. + +### Cipher Suite Limitations + +As a passive sniffer the wolfSSL sniffer will not be able to decode any SSL session that uses DHE (Ephemeral Diffie-Hellman) because it will not have access to the temporary key that the server generates. You may need to disable DHE cipher suites on the server and/or client to prevent these cipher suites from being used. + +### Thread Safety + +Access to the sniffer session table is thread safe. What is not thread safe, is using the same sniffer session from multiple threads. For example, say sniffer session A is created by thread X. If 3 new packets come in for session A and threads X, Y, and Z all try to handle those packets concurrently that's a problem. Ideally, the main thread would associate an ssl sniffer session (client ip/client port <-> server ip/server port) with a particular thread and use that same thread for the lifetime of the session. Short of that, the sniffer session would need a lock which isn't ideal in a multithreaded scenario because once thread X locks the first packet from session A threads Y and Z would be blocked until thread X is done. That defeats the whole purpose doing multithreaded sniffing. + +### Server Name Indication + +Some webservers use virtual domain name mapping where multiple servers using separate SSL keys and certificates are sharing the same IP address and port. The Server Name Indication client hello extension allows the SSL client to specify the name of the server it is connecting to. When running the configure command in section 2.1, add the option --enable-sni. + +### STARTTLS + +Many protocols use ssl as a layer between them and the network layer, and have a dedicated port for the secure connection. Other protocols start out on their classic well known port number in the clear and then offer the “STARTTLS” command which tells the server the client wants to use ssl. The server responds with an affirmation, and the client sends its TLS client hello message and starts negotiation. The sniffer can ignore non-TLS messages on a session until the client starts to negotiate TLS and then proceed as normal. + + +## Missing Features + +### PSK + +While wolfSSL supports Pre Shared Keys, the current version of the sniffer does not. + +### Client Certificate URLs + +Neither wolfSSL nor the sniffer current supports the TLS extension Client Certificate URLs. + +### Secure Renegotiation + +While wolfSSL supports secure renegotiation, the current version of the sniffer does not. The sniffer does support session resumption. + + +## Support + +For issues or questions please email support@wolfssl.com. diff --git a/sslSniffer/sslSnifferTest/include.am b/sslSniffer/sslSnifferTest/include.am index 23de07f914..56ce4f81f4 100644 --- a/sslSniffer/sslSnifferTest/include.am +++ b/sslSniffer/sslSnifferTest/include.am @@ -8,6 +8,7 @@ sslSniffer_sslSnifferTest_snifftest_SOURCES = sslSniffer/sslSnifferTest/snifftes sslSniffer_sslSnifferTest_snifftest_LDADD = src/libwolfssl.la -lpcap $(LIB_STATIC_ADD) sslSniffer_sslSnifferTest_snifftest_DEPENDENCIES = src/libwolfssl.la endif +EXTRA_DIST += sslSniffer/README.md EXTRA_DIST += sslSniffer/sslSniffer.vcproj EXTRA_DIST += sslSniffer/sslSniffer.vcxproj EXTRA_DIST += sslSniffer/sslSnifferTest/sslSniffTest.vcproj diff --git a/sslSniffer/sslSnifferTest/snifftest.c b/sslSniffer/sslSnifferTest/snifftest.c index f8873962b9..7d42f0bd19 100644 --- a/sslSniffer/sslSnifferTest/snifftest.c +++ b/sslSniffer/sslSnifferTest/snifftest.c @@ -25,6 +25,8 @@ #endif #include +#include +#include #ifdef WOLFSSL_SNIFFER_STORE_DATA_CB #include @@ -49,8 +51,8 @@ int main(void) /* do a full build */ #ifdef _MSC_VER - /* builds on *nix too, for scanf device and port */ - #define _CRT_SECURE_NO_WARNINGS + /* builds on *nix too, for scanf device and port */ + #define _CRT_SECURE_NO_WARNINGS #endif #include /* pcap stuff */ @@ -96,6 +98,44 @@ enum { #endif +#define DEFAULT_SERVER_EPH_KEY_ECC "../../certs/statickeys/ecc-secp256r1.pem" +#define DEFAULT_SERVER_EPH_KEY_DH "../../certs/statickeys/dh-ffdhe2048.pem" +#ifndef DEFAULT_SERVER_EPH_KEY + #if defined(HAVE_ECC) && !defined(NO_ECC_SECP) && \ + (!defined(NO_ECC256) || defined(HAVE_ALL_CURVES)) + #define DEFAULT_SERVER_EPH_KEY DEFAULT_SERVER_EPH_KEY_ECC + #elif !defined(NO_DH) + #define DEFAULT_SERVER_EPH_KEY DEFAULT_SERVER_EPH_KEY_DH + #endif +#endif + +#define DEFAULT_SERVER_KEY_RSA "../../certs/server-key.pem" +#define DEFAULT_SERVER_KEY_ECC "../../certs/ecc-key.pem" +#ifndef DEFAULT_SERVER_KEY + #ifndef NO_RSA + #define DEFAULT_SERVER_KEY DEFAULT_SERVER_KEY_RSA + #elif defined(HAVE_ECC) + #define DEFAULT_SERVER_KEY DEFAULT_SERVER_KEY_ECC + #endif +#endif + + +#ifdef WOLFSSL_SNIFFER_WATCH +static const byte rsaHash[] = { + 0x4e, 0xa8, 0x55, 0x02, 0xe1, 0x84, 0x7e, 0xe1, + 0xb5, 0x97, 0xd2, 0xf0, 0x92, 0x3a, 0xfd, 0x0d, + 0x98, 0x26, 0x06, 0x85, 0x8d, 0xa4, 0xc7, 0x35, + 0xd4, 0x74, 0x8f, 0xd0, 0xe7, 0xa8, 0x27, 0xaa +}; +static const byte eccHash[] = { + 0x80, 0x3d, 0xff, 0xca, 0x2e, 0x20, 0xd9, 0xdf, + 0xfe, 0x64, 0x4e, 0x25, 0x6a, 0xee, 0xee, 0x60, + 0xc1, 0x48, 0x7b, 0xff, 0xa0, 0xfb, 0xeb, 0xac, + 0xe2, 0xa4, 0xdd, 0xb5, 0x18, 0x38, 0x78, 0x38 +}; +#endif + + pcap_t* pcap = NULL; pcap_if_t* alldevs = NULL; @@ -113,7 +153,6 @@ static void FreeAll(void) #ifdef WOLFSSL_SNIFFER_STATS - static void DumpStats(void) { SSLStats sslStats; @@ -152,8 +191,7 @@ static void DumpStats(void) printf("SSL Stats (sslEncryptedConns):%lu\n", sslStats.sslEncryptedConns); } - -#endif +#endif /* WOLFSSL_SNIFFER_STATS */ static void sig_handler(const int sig) @@ -170,64 +208,45 @@ static void sig_handler(const int sig) static void err_sys(const char* msg) { - fprintf(stderr, "%s\n", msg); + fprintf(stderr, "%s\n", msg); if (msg) - exit(EXIT_FAILURE); + exit(EXIT_FAILURE); } #ifdef _WIN32 - #define SNPRINTF _snprintf + #define SNPRINTF _snprintf #else - #define SNPRINTF snprintf + #define SNPRINTF snprintf #endif static char* iptos(const struct in_addr* addr) { - static char output[32]; - byte *p = (byte*)&addr->s_addr; + static char output[32]; + byte *p = (byte*)&addr->s_addr; - snprintf(output, sizeof(output), "%d.%d.%d.%d", p[0], p[1], p[2], p[3]); + snprintf(output, sizeof(output), "%d.%d.%d.%d", p[0], p[1], p[2], p[3]); - return output; + return output; } - static const char* ip6tos(const struct in6_addr* addr) { - static char output[42]; - return inet_ntop(AF_INET6, addr, output, 42); + static char output[42]; + return inet_ntop(AF_INET6, addr, output, 42); } #if defined(WOLFSSL_SNIFFER_STORE_DATA_CB) || defined(WOLFSSL_SNIFFER_CHAIN_INPUT) - static inline unsigned int min(unsigned int a, unsigned int b) { return a > b ? b : a; } - #endif #ifdef WOLFSSL_SNIFFER_WATCH - -const byte rsaHash[] = { - 0xD1, 0xB6, 0x12, 0xAD, 0xB6, 0x50, 0x7B, 0x59, - 0x97, 0x83, 0x6B, 0xCB, 0x35, 0xF5, 0xB8, 0x67, - 0xEB, 0x83, 0x75, 0x40, 0x1B, 0x42, 0x61, 0xF1, - 0x03, 0x72, 0xDC, 0x09, 0x0D, 0x60, 0x83, 0x15 -}; - -const byte eccHash[] = { - 0xDA, 0x08, 0x6D, 0xB5, 0x0B, 0xC4, 0x9F, 0x8A, - 0x9E, 0x61, 0x9E, 0x87, 0x57, 0x5F, 0x00, 0xAA, - 0x76, 0xE5, 0x1C, 0x9C, 0x74, 0x2A, 0x19, 0xBE, - 0x22, 0xAE, 0x25, 0x3F, 0xA8, 0xAF, 0x8E, 0x7F -}; - - static int myWatchCb(void* vSniffer, const unsigned char* certHash, unsigned int certHashSz, const unsigned char* certChain, unsigned int certChainSz, @@ -240,23 +259,23 @@ static int myWatchCb(void* vSniffer, (void)ctx; if (certHashSz == sizeof(rsaHash) && - memcmp(certHash, rsaHash, certHashSz) == 0) - certName = "../../certs/server-key.pem"; + XMEMCMP(certHash, rsaHash, certHashSz) == 0) { + certName = DEFAULT_SERVER_KEY_RSA; + } if (certHashSz == sizeof(eccHash) && - memcmp(certHash, eccHash, certHashSz) == 0) - certName = "../../certs/ecc-key.pem"; + XMEMCMP(certHash, eccHash, certHashSz) == 0) { + certName = DEFAULT_SERVER_KEY_ECC; + } if (certName == NULL) return -1; return ssl_SetWatchKey_file(vSniffer, certName, FILETYPE_PEM, NULL, error); } - -#endif +#endif /* WOLFSSL_SNIFFER_WATCH */ #ifdef WOLFSSL_SNIFFER_STORE_DATA_CB - static int myStoreDataCb(const unsigned char* decryptBuf, unsigned int decryptBufSz, unsigned int decryptBufOffset, void* ctx) { @@ -283,29 +302,28 @@ static int myStoreDataCb(const unsigned char* decryptBuf, *data = tmpData; } - memcpy(*data + decryptBufOffset, decryptBuf + decryptBufOffset, qty); + XMEMCPY(*data + decryptBufOffset, decryptBuf + decryptBufOffset, qty); return qty; } - -#endif +#endif /* WOLFSSL_SNIFFER_STORE_DATA_CB */ int main(int argc, char** argv) { int ret = 0; int hadBadPacket = 0; - int inum; - int port; + int inum = 0; + int port = 0; int saveFile = 0; - int i = 0; + int i = 0, defDev = 0; int frame = ETHER_IF_FRAME_LEN; char err[PCAP_ERRBUF_SIZE]; - char filter[32]; - const char *server = NULL; - struct bpf_program fp; - pcap_if_t *d; - pcap_addr_t *a; + char filter[32]; + const char *server = NULL; + struct bpf_program fp; + pcap_if_t *d; + pcap_addr_t *a; #ifdef WOLFSSL_SNIFFER_CHAIN_INPUT struct iovec chain[CHAIN_INPUT_COUNT]; int chainSz; @@ -315,6 +333,9 @@ int main(int argc, char** argv) #ifndef _WIN32 ssl_InitSniffer(); /* dll load on Windows */ +#endif +#ifdef DEBUG_WOLFSSL + //wolfSSL_Debugging_ON(); #endif ssl_Trace("./tracefile.txt", err); ssl_EnableRecovery(1, -1, err); @@ -326,54 +347,58 @@ int main(int argc, char** argv) #endif if (argc == 1) { + char cmdLineArg[128]; /* normal case, user chooses device and port */ - if (pcap_findalldevs(&alldevs, err) == -1) - err_sys("Error in pcap_findalldevs"); + if (pcap_findalldevs(&alldevs, err) == -1) + err_sys("Error in pcap_findalldevs"); - for (d = alldevs; d; d=d->next) { - printf("%d. %s", ++i, d->name); - if (d->description) - printf(" (%s)\n", d->description); - else - printf(" (No description available)\n"); - } - - if (i == 0) - err_sys("No interfaces found! Make sure pcap or WinPcap is" - " installed correctly and you have sufficient permissions"); - - printf("Enter the interface number (1-%d): ", i); - ret = scanf("%d", &inum); - if (ret != 1) { - printf("scanf port failed\n"); + for (d = alldevs; d; d=d->next) { + printf("%d. %s", ++i, d->name); + if (strcmp(d->name, "lo0") == 0) { + defDev = i; + } + if (d->description) + printf(" (%s)\n", d->description); + else + printf(" (No description available)\n"); } - if (inum < 1 || inum > i) - err_sys("Interface number out of range"); + if (i == 0) + err_sys("No interfaces found! Make sure pcap or WinPcap is" + " installed correctly and you have sufficient permissions"); - /* Jump to the selected adapter */ - for (d = alldevs, i = 0; i < inum - 1; d = d->next, i++); + printf("Enter the interface number (1-%d) [default: %d]: ", i, defDev); + XMEMSET(cmdLineArg, 0, sizeof(cmdLineArg)); + if (XFGETS(cmdLineArg, sizeof(cmdLineArg), stdin)) + inum = XATOI(cmdLineArg); + if (inum == 0) + inum = defDev; + else if (inum < 1 || inum > i) + err_sys("Interface number out of range"); - pcap = pcap_create(d->name, err); + /* Jump to the selected adapter */ + for (d = alldevs, i = 0; i < inum - 1; d = d->next, i++); + + pcap = pcap_create(d->name, err); if (pcap == NULL) printf("pcap_create failed %s\n", err); /* print out addresses for selected interface */ - for (a = d->addresses; a; a = a->next) { + for (a = d->addresses; a; a = a->next) { if (a->addr->sa_family == AF_INET) { - server = + server = iptos(&((struct sockaddr_in *)a->addr)->sin_addr); - printf("server = %s\n", server); + printf("server = %s\n", server); } else if (a->addr->sa_family == AF_INET6) { server = ip6tos(&((struct sockaddr_in6 *)a->addr)->sin6_addr); - printf("server = %s\n", server); + printf("server = %s\n", server); } - } - if (server == NULL) - err_sys("Unable to get device IPv4 or IPv6 address"); + } + if (server == NULL) + err_sys("Unable to get device IPv4 or IPv6 address"); ret = pcap_set_snaplen(pcap, 65536); if (ret != 0) printf("pcap_set_snaplen failed %s\n", pcap_geterr(pcap)); @@ -383,7 +408,7 @@ int main(int argc, char** argv) ret = pcap_set_buffer_size(pcap, 1000000); if (ret != 0) - printf("pcap_set_buffer_size failed %s\n", pcap_geterr(pcap)); + printf("pcap_set_buffer_size failed %s\n", pcap_geterr(pcap)); ret = pcap_set_promisc(pcap, 1); if (ret != 0) printf("pcap_set_promisc failed %s\n", pcap_geterr(pcap)); @@ -392,24 +417,27 @@ int main(int argc, char** argv) ret = pcap_activate(pcap); if (ret != 0) printf("pcap_activate failed %s\n", pcap_geterr(pcap)); - printf("Enter the port to scan: "); - ret = scanf("%d", &port); - if (ret != 1) - printf("scanf port failed\n"); + printf("Enter the port to scan [default: 11111]: "); + XMEMSET(cmdLineArg, 0, sizeof(cmdLineArg)); + if (XFGETS(cmdLineArg, sizeof(cmdLineArg), stdin)) { + port = XATOI(cmdLineArg); + } + if (port <= 0) + port = 11111; - SNPRINTF(filter, sizeof(filter), "tcp and port %d", port); + SNPRINTF(filter, sizeof(filter), "tcp and port %d", port); - ret = pcap_compile(pcap, &fp, filter, 0, 0); + ret = pcap_compile(pcap, &fp, filter, 0, 0); if (ret != 0) printf("pcap_compile failed %s\n", pcap_geterr(pcap)); ret = pcap_setfilter(pcap, &fp); if (ret != 0) printf("pcap_setfilter failed %s\n", pcap_geterr(pcap)); - /* get IPv4 or IPv6 addresses for selected interface */ - for (a = d->addresses; a; a = a->next) { + /* get IPv4 or IPv6 addresses for selected interface */ + for (a = d->addresses; a; a = a->next) { server = NULL; if (a->addr->sa_family == AF_INET) { - server = + server = iptos(&((struct sockaddr_in *)a->addr)->sin_addr); } else if (a->addr->sa_family == AF_INET6) { @@ -418,35 +446,41 @@ int main(int argc, char** argv) } if (server) { - #ifndef WOLFSSL_SNIFFER_WATCH - ret = ssl_SetPrivateKey(server, port, - "../../certs/server-key.pem", - FILETYPE_PEM, NULL, err); + #ifdef DEFAULT_SERVER_KEY + ret = ssl_SetPrivateKey(server, port, DEFAULT_SERVER_KEY, + FILETYPE_PEM, NULL, err); if (ret != 0) { printf("Please run directly from sslSniffer/sslSnifferTest" "dir\n"); } + #endif + #if defined(WOLFSSL_STATIC_EPHEMERAL) && defined(DEFAULT_SERVER_EPH_KEY) + ret = ssl_SetEphemeralKey(server, port, DEFAULT_SERVER_EPH_KEY, + FILETYPE_PEM, NULL, err); + if (ret != 0) { + printf("Please run directly from sslSniffer/sslSnifferTest" + "dir\n"); + } + #endif /* WOLFSSL_STATIC_EPHEMERAL */ + #ifndef WOLFSSL_SNIFFER_WATCH #ifdef HAVE_SNI - { - char altName[128]; - - printf("Enter alternate SNI: "); - ret = scanf("%s", altName); - - if (strnlen(altName, 128) > 0) { - ret = ssl_SetNamedPrivateKey(altName, - server, port, "../../certs/server-key.pem", + printf("Enter alternate SNI: "); + XMEMSET(cmdLineArg, 0, sizeof(cmdLineArg)); + if (XFGETS(cmdLineArg, sizeof(cmdLineArg), stdin)) { + if (XSTRLEN(cmdLineArg) > 0) { + ret = ssl_SetNamedPrivateKey(cmdLineArg, + server, port, DEFAULT_SERVER_KEY, FILETYPE_PEM, NULL, err); if (ret != 0) { printf("Please run directly from " - "sslSniffer/sslSnifferTest dir\n"); + "sslSniffer/sslSnifferTest dir\n"); } } } - #endif - #endif + #endif /* HAVE_SNI */ + #endif /* WOLFSSL_SNIFFER_WATCH */ } - } + } } else if (argc >= 3) { saveFile = 1; @@ -457,6 +491,7 @@ int main(int argc, char** argv) } else { const char* passwd = NULL; + int isEphemeralKey = 0; /* defaults for server and port */ port = 443; server = "127.0.0.1"; @@ -465,13 +500,22 @@ int main(int argc, char** argv) server = argv[3]; if (argc >= 5) - port = atoi(argv[4]); + port = XATOI(argv[4]); if (argc >= 6) passwd = argv[5]; - ret = ssl_SetPrivateKey(server, port, argv[2], + if (argc >= 7) + isEphemeralKey = 1; + + if (isEphemeralKey) { + ret = ssl_SetEphemeralKey(server, port, argv[2], FILETYPE_PEM, passwd, err); + } + else { + ret = ssl_SetPrivateKey(server, port, argv[2], + FILETYPE_PEM, passwd, err); + } } } else { @@ -498,8 +542,8 @@ int main(int argc, char** argv) byte* data = NULL; if (header.caplen > 40) { /* min ip(20) + min tcp(20) */ - packet += frame; - header.caplen -= frame; + packet += frame; + header.caplen -= frame; } else continue; diff --git a/wolfcrypt/src/asn.c b/wolfcrypt/src/asn.c index 54f91d7b8b..3174e0ffda 100644 --- a/wolfcrypt/src/asn.c +++ b/wolfcrypt/src/asn.c @@ -1521,9 +1521,9 @@ static word32 SetBitString16Bit(word16 val, byte* output) #ifdef HAVE_ED448 static const byte keyEd448Oid[] = {43, 101, 113}; #endif /* HAVE_ED448 */ -#if !defined(NO_DH) && (defined(WOLFSSL_QT) || defined(OPENSSL_ALL)) +#ifndef NO_DH static const byte keyDhOid[] = {42, 134, 72, 134, 247, 13, 1, 3, 1}; -#endif /* ! NO_DH ... */ +#endif /* !NO_DH */ /* curveType */ #ifdef HAVE_ECC @@ -1869,12 +1869,12 @@ const byte* OidFromId(word32 id, word32 type, word32* oidSz) *oidSz = sizeof(keyEd448Oid); break; #endif /* HAVE_ED448 */ - #if !defined(NO_DH) && (defined(WOLFSSL_QT) || defined(OPENSSL_ALL)) + #ifndef NO_DH case DHk: oid = keyDhOid; *oidSz = sizeof(keyDhOid); break; - #endif /* ! NO_DH && (WOLFSSL_QT || OPENSSL_ALL */ + #endif /* !NO_DH */ default: break; } @@ -4416,17 +4416,20 @@ int wc_RsaPublicKeyDecodeRaw(const byte* n, word32 nSz, const byte* e, #endif /* !NO_RSA */ #ifndef NO_DH - +/* Supports either: + * - DH params G/P (PKCS#3 DH) file or + * - DH key file (if WOLFSSL_DH_EXTRA enabled) */ +/* The wc_DhParamsLoad function also loads DH params, but directly into buffers, not DhKey */ int wc_DhKeyDecode(const byte* input, word32* inOutIdx, DhKey* key, word32 inSz) { int ret = 0; int length; - #if defined(WOLFSSL_QT) || defined(OPENSSL_ALL) - #if !defined(HAVE_FIPS) || (defined(HAVE_FIPS_VERSION) && \ - (HAVE_FIPS_VERSION>2)) +#ifdef WOLFSSL_DH_EXTRA + #if !defined(HAVE_FIPS) || \ + (defined(HAVE_FIPS_VERSION) && (HAVE_FIPS_VERSION > 2)) word32 oid = 0, temp = 0; #endif - #endif +#endif WOLFSSL_ENTER("wc_DhKeyDecode"); @@ -4435,26 +4438,33 @@ int wc_DhKeyDecode(const byte* input, word32* inOutIdx, DhKey* key, word32 inSz) if (GetSequence(input, inOutIdx, &length, inSz) < 0) return ASN_PARSE_E; - #if defined(WOLFSSL_QT) || defined(OPENSSL_ALL) - #if !defined(HAVE_FIPS) || (defined(HAVE_FIPS_VERSION) && \ - (HAVE_FIPS_VERSION>2)) - temp = *inOutIdx; - #endif /* !HAVE_FIPS || HAVE_FIPS_VERSION > 2 */ - #endif +#ifdef WOLFSSL_DH_EXTRA + #if !defined(HAVE_FIPS) || \ + (defined(HAVE_FIPS_VERSION) && (HAVE_FIPS_VERSION > 2)) + temp = *inOutIdx; + #endif +#endif /* Assume input started after 1.2.840.113549.1.3.1 dhKeyAgreement */ if (GetInt(&key->p, input, inOutIdx, inSz) < 0 || GetInt(&key->g, input, inOutIdx, inSz) < 0) { ret = ASN_DH_KEY_E; } - #if defined(WOLFSSL_QT) || defined(OPENSSL_ALL) - #if !defined(HAVE_FIPS) || (defined(HAVE_FIPS_VERSION) && \ - (HAVE_FIPS_VERSION>2)) +#ifdef WOLFSSL_DH_EXTRA + #if !defined(HAVE_FIPS) || \ + (defined(HAVE_FIPS_VERSION) && (HAVE_FIPS_VERSION > 2)) /* If ASN_DH_KEY_E: Check if input started at beginning of key */ if (ret == ASN_DH_KEY_E) { - /* rewind back to after the first sequence */ *inOutIdx = temp; + + /* the version (0) */ + if (GetASNInt(input, inOutIdx, &length, inSz) < 0) { + return ASN_PARSE_E; + } + *inOutIdx += length; + + /* Size of dhKeyAgreement section */ if (GetSequence(input, inOutIdx, &length, inSz) < 0) return ASN_PARSE_E; @@ -4466,8 +4476,8 @@ int wc_DhKeyDecode(const byte* input, word32* inOutIdx, DhKey* key, word32 inSz) if (GetSequence(input, inOutIdx, &length, inSz) < 0) return ASN_PARSE_E; - if (GetInt(&key->p, input, inOutIdx, inSz) < 0 || - GetInt(&key->g, input, inOutIdx, inSz) < 0) { + if (GetInt(&key->p, input, inOutIdx, inSz) < 0 || + GetInt(&key->g, input, inOutIdx, inSz) < 0) { return ASN_DH_KEY_E; } } @@ -4487,7 +4497,9 @@ int wc_DhKeyDecode(const byte* input, word32* inOutIdx, DhKey* key, word32 inSz) /* Found Octet String */ if (GetInt(&key->priv, input, inOutIdx, inSz) == 0) { WOLFSSL_MSG("Found Private Key"); - ret = 0; + + /* Compute public */ + ret = mp_exptmod(&key->g, &key->priv, &key->p, &key->pub); } } else { /* Don't use length from failed CheckBitString/GetOctetString */ @@ -4496,14 +4508,13 @@ int wc_DhKeyDecode(const byte* input, word32* inOutIdx, DhKey* key, word32 inSz) } } #endif /* !HAVE_FIPS || HAVE_FIPS_VERSION > 2 */ - #endif /* WOLFSSL_QT || OPENSSL_ALL */ +#endif /* WOLFSSL_DH_EXTRA */ - WOLFSSL_MSG("wc_DhKeyDecode Success"); + WOLFSSL_LEAVE("wc_DhKeyDecode", ret); return ret; } - int wc_DhParamsLoad(const byte* input, word32 inSz, byte* p, word32* pInOutSz, byte* g, word32* gInOutSz) { @@ -4541,7 +4552,7 @@ int wc_DhParamsLoad(const byte* input, word32 inSz, byte* p, word32* pInOutSz, return 0; } -#endif /* NO_DH */ +#endif /* !NO_DH */ #ifndef NO_DSA @@ -9895,7 +9906,7 @@ int wc_PemGetHeaderFooter(int type, const char** header, const char** footer) if (footer) *footer = END_PUB_KEY; ret = 0; break; - #if !defined(NO_DH) && (defined(WOLFSSL_QT) || defined(OPENSSL_ALL)) + #ifndef NO_DH case DH_PRIVATEKEY_TYPE: #endif case PKCS8_PRIVATEKEY_TYPE: @@ -15068,7 +15079,7 @@ int StoreDHparams(byte* out, word32* outLen, mp_int* p, mp_int* g) return 0; } -#endif /* !NO_DH && WOLFSSL_QT || OPENSSL_ALL */ +#endif /* !NO_DH && (WOLFSSL_QT || OPENSSL_ALL) */ #ifdef HAVE_ECC diff --git a/wolfcrypt/src/dh.c b/wolfcrypt/src/dh.c index 78decc3f8b..7661ff2b9b 100644 --- a/wolfcrypt/src/dh.c +++ b/wolfcrypt/src/dh.c @@ -930,10 +930,10 @@ int wc_InitDhKey_ex(DhKey* key, void* heap, int devId) key->heap = heap; /* for XMALLOC/XFREE in future */ -#if !defined(WOLFSSL_QT) && !defined(OPENSSL_ALL) - if (mp_init_multi(&key->p, &key->g, &key->q, NULL, NULL, NULL) != MP_OKAY) +#ifdef WOLFSSL_DH_EXTRA + if (mp_init_multi(&key->p, &key->g, &key->q, &key->pub, &key->priv, NULL) != MP_OKAY) #else - if (mp_init_multi(&key->p,&key->g,&key->q,&key->pub,&key->priv,NULL) != MP_OKAY) + if (mp_init_multi(&key->p, &key->g, &key->q, NULL, NULL, NULL) != MP_OKAY) #endif return MEMORY_E; @@ -960,6 +960,10 @@ int wc_FreeDhKey(DhKey* key) mp_clear(&key->p); mp_clear(&key->g); mp_clear(&key->q); + #ifdef WOLFSSL_DH_EXTRA + mp_clear(&key->pub); + mp_forcezero(&key->priv); + #endif #if defined(WOLFSSL_ASYNC_CRYPT) && defined(WC_ASYNC_ENABLE_DH) wolfAsync_DevCtxFree(&key->asyncDev, WOLFSSL_ASYNC_MARKER_DH); @@ -1148,7 +1152,6 @@ static int GeneratePrivateDh186(DhKey* key, WC_RNG* rng, byte* priv, } mp_forcezero(tmpX); - mp_clear(tmpX); mp_clear(tmpQ); #ifdef WOLFSSL_SMALL_STACK XFREE(tmpQ, key->heap, DYNAMIC_TYPE_DH); @@ -1798,7 +1801,6 @@ int wc_DhCheckKeyPair(DhKey* key, const byte* pub, word32 pubSz, } mp_forcezero(privateKey); - mp_clear(privateKey); mp_clear(publicKey); mp_clear(checkKey); #ifdef WOLFSSL_SMALL_STACK @@ -1834,7 +1836,6 @@ int wc_DhGenerateKeyPair(DhKey* key, WC_RNG* rng, return ret; } - static int wc_DhAgree_Sync(DhKey* key, byte* agree, word32* agreeSz, const byte* priv, word32 privSz, const byte* otherPub, word32 pubSz) { @@ -2065,76 +2066,113 @@ int wc_DhAgree(DhKey* key, byte* agree, word32* agreeSz, const byte* priv, return ret; } -#if defined(WOLFSSL_QT) || defined(OPENSSL_ALL) +#ifdef WOLFSSL_DH_EXTRA /* Sets private and public key in DhKey if both are available, otherwise sets - either private or public key, depending on which is available. - Returns WOLFSSL_SUCCESS if at least one of the keys was set. */ -WOLFSSL_LOCAL int wc_DhSetFullKeys(DhKey* key,const byte* priv_key,word32 privSz, - const byte* pub_key, word32 pubSz) + either private or public key, depending on which is available. */ +int wc_DhImportKeyPair(DhKey* key, const byte* priv, word32 privSz, + const byte* pub, word32 pubSz) { - byte havePriv = 0; - byte havePub = 0; - mp_int* keyPriv = NULL; - mp_int* keyPub = NULL; + byte havePriv, havePub; + mp_int *keyPriv = NULL, *keyPub = NULL; if (key == NULL) { return BAD_FUNC_ARG; } - havePriv = ( (priv_key != NULL) && (privSz > 0) ); - havePub = ( (pub_key != NULL) && (pubSz > 0) ); + havePriv = ( (priv != NULL) && (privSz > 0) ); + havePub = ( (pub != NULL) && (pubSz > 0) ); if (!havePub && !havePriv) { WOLFSSL_MSG("No Public or Private Key to Set"); return BAD_FUNC_ARG; } + /* Set Private Key */ - if (havePriv == TRUE) { + if (havePriv) { /* may have leading 0 */ - if (priv_key[0] == 0) { - privSz--; priv_key++; + if (priv[0] == 0) { + privSz--; priv++; } if (mp_init(&key->priv) != MP_OKAY) - havePriv = FALSE; + havePriv = 0; } - - if (havePriv == TRUE) { - if (mp_read_unsigned_bin(&key->priv, priv_key, privSz) != MP_OKAY) { - havePriv = FALSE; + if (havePriv) { + if (mp_read_unsigned_bin(&key->priv, priv, privSz) != MP_OKAY) { + mp_clear(&key->priv); + havePriv = 0; } else { keyPriv = &key->priv; - WOLFSSL_MSG("DH Private Key Set."); + WOLFSSL_MSG("DH Private Key Set"); } } /* Set Public Key */ - if (havePub == TRUE) { + if (havePub) { /* may have leading 0 */ - if (pub_key[0] == 0) { - pubSz--; pub_key++; + if (pub[0] == 0) { + pubSz--; pub++; } if (mp_init(&key->pub) != MP_OKAY) - havePub = FALSE; + havePub = 0; } - - if (havePub == TRUE) { - if (mp_read_unsigned_bin(&key->pub, pub_key, pubSz) != MP_OKAY) { - havePub = FALSE; + if (havePub) { + if (mp_read_unsigned_bin(&key->pub, pub, pubSz) != MP_OKAY) { + mp_clear(&key->pub); + havePub = 0; } else { keyPub = &key->pub; - WOLFSSL_MSG("DH Public Key Set."); + WOLFSSL_MSG("DH Public Key Set"); } } - /* Free Memory if error occured */ - if (havePriv == FALSE && keyPriv != NULL) + /* Free Memory if error occurred */ + if (havePriv == 0 && keyPriv != NULL) mp_clear(keyPriv); - if (havePub == FALSE && keyPub != NULL) + if (havePub == 0 && keyPub != NULL) mp_clear(keyPub); - /* WOLFSSL_SUCCESS if private or public was set else WOLFSSL_FAILURE */ - return havePriv || havePub; + if (havePriv == 0 && havePub == 0) { + return MEMORY_E; + } + + return 0; } -#endif + +/* Can be used with WOLFSSL_DH_EXTRA when key is loaded with + wc_DhKeyDecode or wc_DhImportKeyPair */ +int wc_DhExportKeyPair(DhKey* key, byte* priv, word32* pPrivSz, + byte* pub, word32* pPubSz) +{ + int ret = 0; + word32 pubSz, privSz; + + if (key == NULL || (priv && pPrivSz == NULL) || (pub && pPubSz == NULL)) { + return BAD_FUNC_ARG; + } + + if (priv) { + privSz = mp_unsigned_bin_size(&key->priv); + if (privSz > *pPrivSz) { + return BUFFER_E; + } + *pPrivSz = privSz; + ret |= mp_to_unsigned_bin(&key->priv, priv); + } + + if (pub) { + pubSz = mp_unsigned_bin_size(&key->pub); + if (pubSz > *pPubSz) { + return BUFFER_E; + } + *pPubSz = pubSz; + ret |= mp_to_unsigned_bin(&key->pub, pub); + } + + if (ret != 0) + ret = ASN_DH_KEY_E; + return ret; +} + +#endif /* WOLFSSL_DH_EXTRA */ static int _DhSetKey(DhKey* key, const byte* p, word32 pSz, const byte* g, word32 gSz, const byte* q, word32 qSz, int trusted, diff --git a/wolfcrypt/src/ecc.c b/wolfcrypt/src/ecc.c index f3f21c258a..bc56d71ccc 100644 --- a/wolfcrypt/src/ecc.c +++ b/wolfcrypt/src/ecc.c @@ -48,7 +48,7 @@ Possible ECC enable options: * WOLFSSL_CUSTOM_CURVES: Allow non-standard curves. default: off * Includes the curve "a" variable in calculation * ECC_DUMP_OID: Enables dump of OID encoding and sum default: off - * ECC_CACHE_CURVE: Enables cache of curve info to improve perofrmance + * ECC_CACHE_CURVE: Enables cache of curve info to improve performance default: off * FP_ECC: ECC Fixed Point Cache default: off * USE_ECC_B_PARAM: Enable ECC curve B param default: off diff --git a/wolfcrypt/src/wc_port.c b/wolfcrypt/src/wc_port.c index d660f22926..b30359c957 100644 --- a/wolfcrypt/src/wc_port.c +++ b/wolfcrypt/src/wc_port.c @@ -331,8 +331,60 @@ int wolfCrypt_Cleanup(void) return ret; } -#if !defined(NO_FILESYSTEM) && !defined(NO_WOLFSSL_DIR) && \ - !defined(WOLFSSL_NUCLEUS) && !defined(WOLFSSL_NUCLEUS_1_2) +#ifndef NO_FILESYSTEM + +/* Helpful function to load file into allocated buffer */ +int wc_FileLoad(const char* fname, unsigned char** buf, size_t* bufLen, + void* heap) +{ + int ret; + size_t fileSz; + XFILE f; + + if (fname == NULL || buf == NULL || bufLen == NULL) { + return BAD_FUNC_ARG; + } + + /* set defaults */ + *buf = NULL; + *bufLen = 0; + + /* open file (read-only binary) */ + f = XFOPEN(fname, "rb"); + if (!f) { + WOLFSSL_MSG("wc_LoadFile file load error"); + return BAD_PATH_ERROR; + } + + XFSEEK(f, 0, SEEK_END); + fileSz = XFTELL(f); + XREWIND(f); + if (fileSz > 0) { + *bufLen = fileSz; + *buf = (byte*)XMALLOC(*bufLen, heap, DYNAMIC_TYPE_TMP_BUFFER); + if (*buf == NULL) { + WOLFSSL_MSG("wc_LoadFile memory error"); + ret = MEMORY_E; + } + else { + size_t readLen = XFREAD(*buf, 1, *bufLen, f); + + /* check response code */ + ret = (readLen == *bufLen) ? 0 : -1; + } + } + else { + ret = BUFFER_E; + } + XFCLOSE(f); + + (void)heap; + + return ret; +} + +#if !defined(NO_WOLFSSL_DIR) && \ + !defined(WOLFSSL_NUCLEUS) && !defined(WOLFSSL_NUCLEUS_1_2) /* File Handling Helpers */ /* returns 0 if file found, WC_READDIR_NOFILE if no files or negative error */ @@ -631,7 +683,8 @@ void wc_ReadDirClose(ReadDirCtx* ctx) #endif } -#endif /* !NO_FILESYSTEM && !NO_WOLFSSL_DIR */ +#endif /* !NO_WOLFSSL_DIR */ +#endif /* !NO_FILESYSTEM */ #if !defined(NO_FILESYSTEM) && defined(WOLFSSL_ZEPHYR) XFILE z_fs_open(const char* filename, const char* perm) diff --git a/wolfcrypt/test/test.c b/wolfcrypt/test/test.c index b2f871b8bb..5b017302b0 100644 --- a/wolfcrypt/test/test.c +++ b/wolfcrypt/test/test.c @@ -10385,7 +10385,10 @@ byte GetEntropy(ENTROPY_CMD cmd, byte* out) !defined(USE_CERT_BUFFERS_3072) && !defined(USE_CERT_BUFFERS_4096) && \ !defined(NO_ASN) #ifndef NO_DH - static const char* dhKey = CERT_ROOT "dh2048.der"; + static const char* dhParamsFile = CERT_ROOT "dh2048.der"; + #ifdef WOLFSSL_DH_EXTRA + static const char* dhKeyFile = CERT_ROOT "statickeys/dh-ffdhe2048.der"; + #endif #endif #ifndef NO_DSA static const char* dsaKey = CERT_ROOT "dsa2048.der"; @@ -14144,7 +14147,6 @@ static int dh_fips_generate_test(WC_RNG *rng) if (ret != 0) { ERROR_OUT(-7796, exit_gen_test); } - #endif /* WOLFSSL_KEY_GEN */ #endif /* HAVE_SELFTEST */ @@ -14428,7 +14430,7 @@ int dh_test(void) #elif defined(NO_ASN) /* don't use file, no DER parsing */ #elif !defined(NO_FILESYSTEM) - XFILE file = XFOPEN(dhKey, "rb"); + XFILE file = XFOPEN(dhParamsFile, "rb"); if (!file) return -7900; @@ -14545,6 +14547,36 @@ int dh_test(void) } #endif + + + /* Test DH key import / export */ +#ifdef WOLFSSL_DH_EXTRA +#if !defined(NO_ASN) && !defined(NO_FILESYSTEM) + file = XFOPEN(dhKeyFile, "rb"); + if (!file) + return -7950; + bytes = (word32)XFREAD(tmp, 1, sizeof(tmp), file); + XFCLOSE(file); + + idx = 0; + ret = wc_DhKeyDecode(tmp, &idx, &key, bytes); + if (ret != 0) { + return -7951; + } +#endif + + privSz = sizeof(priv); + pubSz = sizeof(pub); + ret = wc_DhExportKeyPair(&key, priv, &privSz, pub, &pubSz); + if (ret != 0) { + return -7952; + } + ret = wc_DhImportKeyPair(&key2, priv, privSz, pub, pubSz); + if (ret != 0) { + return -7953; + } +#endif /* WOLFSSL_DH_EXTRA */ + ret = dh_generate_test(&rng); if (ret == 0) ret = dh_fips_generate_test(&rng); diff --git a/wolfssl/internal.h b/wolfssl/internal.h index a7ad54fc05..5371c5ee6e 100644 --- a/wolfssl/internal.h +++ b/wolfssl/internal.h @@ -1657,6 +1657,10 @@ WOLFSSL_LOCAL int InitSSL_Side(WOLFSSL* ssl, word16 side); /* for sniffer */ WOLFSSL_LOCAL int DoFinished(WOLFSSL* ssl, const byte* input, word32* inOutIdx, word32 size, word32 totalSz, int sniff); +#ifdef WOLFSSL_TLS13 +WOLFSSL_LOCAL int DoTls13Finished(WOLFSSL* ssl, const byte* input, word32* inOutIdx, + word32 size, word32 totalSz, int sniff); +#endif WOLFSSL_LOCAL int DoApplicationData(WOLFSSL* ssl, byte* input, word32* inOutIdx); /* TLS v1.3 needs these */ WOLFSSL_LOCAL int HandleTlsResumption(WOLFSSL* ssl, int bogusID, @@ -1692,10 +1696,11 @@ WOLFSSL_LOCAL int CheckAltNames(DecodedCert* dCert, char* domain); WOLFSSL_LOCAL int CheckIPAddr(DecodedCert* dCert, const char* ipasc); #endif WOLFSSL_LOCAL int CreateTicket(WOLFSSL* ssl); -WOLFSSL_LOCAL int HashOutputRaw(WOLFSSL* ssl, const byte* output, int sz); +WOLFSSL_LOCAL int HashRaw(WOLFSSL* ssl, const byte* output, int sz); WOLFSSL_LOCAL int HashOutput(WOLFSSL* ssl, const byte* output, int sz, int ivSz); WOLFSSL_LOCAL int HashInput(WOLFSSL* ssl, const byte* input, int sz); + #if defined(OPENSSL_ALL) || defined(HAVE_STUNNEL) || defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY) WOLFSSL_LOCAL int SNI_Callback(WOLFSSL* ssl); #endif @@ -2150,13 +2155,14 @@ typedef enum { TLSX_SUPPORTED_GROUPS = 0x000a, /* a.k.a. Supported Curves */ TLSX_EC_POINT_FORMATS = 0x000b, #if !defined(WOLFSSL_NO_SIGALG) - TLSX_SIGNATURE_ALGORITHMS = 0x000d, + TLSX_SIGNATURE_ALGORITHMS = 0x000d, /* HELLO_EXT_SIG_ALGO */ #endif TLSX_APPLICATION_LAYER_PROTOCOL = 0x0010, /* a.k.a. ALPN */ TLSX_STATUS_REQUEST_V2 = 0x0011, /* a.k.a. OCSP stapling v2 */ #if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY) TLSX_ENCRYPT_THEN_MAC = 0x0016, /* RFC 7366 */ #endif + TLSX_EXTENDED_MASTER_SECRET = 0x0017, /* HELLO_EXT_EXTMS */ TLSX_QUANTUM_SAFE_HYBRID = 0x0018, /* a.k.a. QSH */ TLSX_SESSION_TICKET = 0x0023, #ifdef WOLFSSL_TLS13 @@ -2579,6 +2585,12 @@ enum DeriveKeyType { update_traffic_key }; +WOLFSSL_LOCAL int DeriveEarlySecret(WOLFSSL* ssl); +WOLFSSL_LOCAL int DeriveHandshakeSecret(WOLFSSL* ssl); +WOLFSSL_LOCAL int DeriveTls13Keys(WOLFSSL* ssl, int secret, int side, int store); +WOLFSSL_LOCAL int DeriveMasterSecret(WOLFSSL* ssl); +WOLFSSL_LOCAL int DeriveResumptionPSK(WOLFSSL* ssl, byte* nonce, byte nonceLen, byte* secret); + /* The key update request values for KeyUpdate message. */ enum KeyUpdateRequest { update_not_requested, @@ -2595,6 +2607,14 @@ enum SetCBIO { }; #endif +#ifdef WOLFSSL_STATIC_EPHEMERAL +typedef struct { + int keyAlgo; + DerBuffer* key; +} StaticKeyExchangeInfo_t; +#endif + + /* wolfSSL context type */ struct WOLFSSL_CTX { WOLFSSL_METHOD* method; @@ -2868,16 +2888,19 @@ struct WOLFSSL_CTX { #endif /* NO_RSA */ #endif /* HAVE_PK_CALLBACKS */ #ifdef HAVE_WOLF_EVENT - WOLF_EVENT_QUEUE event_queue; + WOLF_EVENT_QUEUE event_queue; #endif /* HAVE_WOLF_EVENT */ #ifdef HAVE_EXT_CACHE - WOLFSSL_SESSION*(*get_sess_cb)(WOLFSSL*, unsigned char*, int, int*); - int (*new_sess_cb)(WOLFSSL*, WOLFSSL_SESSION*); - void (*rem_sess_cb)(WOLFSSL_CTX*, WOLFSSL_SESSION*); + WOLFSSL_SESSION*(*get_sess_cb)(WOLFSSL*, unsigned char*, int, int*); + int (*new_sess_cb)(WOLFSSL*, WOLFSSL_SESSION*); + void (*rem_sess_cb)(WOLFSSL_CTX*, WOLFSSL_SESSION*); #endif #if defined(OPENSSL_EXTRA) && defined(WOLFCRYPT_HAVE_SRP) && !defined(NO_SHA256) - Srp* srp; /* TLS Secure Remote Password Protocol*/ - byte* srp_password; + Srp* srp; /* TLS Secure Remote Password Protocol*/ + byte* srp_password; +#endif +#ifdef WOLFSSL_STATIC_EPHEMERAL + StaticKeyExchangeInfo_t staticKE; #endif }; @@ -2942,7 +2965,6 @@ enum KeyExchangeAlgorithm { ecc_static_diffie_hellman_kea /* for verify suite only */ }; - /* Supported Authentication Schemes */ enum SignatureAlgorithm { anonymous_sa_algo = 0, @@ -4220,6 +4242,9 @@ struct WOLFSSL { WOLFSSL_STACK* supportedCiphers; /* Used in wolfSSL_get_ciphers_compat */ WOLFSSL_STACK* peerCertChain; /* Used in wolfSSL_get_peer_cert_chain */ #endif +#ifdef WOLFSSL_STATIC_EPHEMERAL + StaticKeyExchangeInfo_t staticKE; +#endif }; diff --git a/wolfssl/sniffer.h b/wolfssl/sniffer.h index 8c31b024d6..f18415a9ea 100644 --- a/wolfssl/sniffer.h +++ b/wolfssl/sniffer.h @@ -49,18 +49,19 @@ SSL_SNIFFER_API int ssl_SetPrivateKey(const char* address, int port, const char* keyFile, int typeK, const char* password, char* error); -WOLFSSL_API -SSL_SNIFFER_API int ssl_SetNamedPrivateKey(const char* name, - const char* address, int port, - const char* keyFile, int typeK, - const char* password, char* error); - WOLFSSL_API SSL_SNIFFER_API int ssl_SetPrivateKeyBuffer(const char* address, int port, const char* keyBuf, int keySz, int typeK, const char* password, char* error); + +WOLFSSL_API +SSL_SNIFFER_API int ssl_SetNamedPrivateKey(const char* name, + const char* address, int port, + const char* keyFile, int typeK, + const char* password, char* error); + WOLFSSL_API SSL_SNIFFER_API int ssl_SetNamedPrivateKeyBuffer(const char* name, const char* address, int port, @@ -68,6 +69,29 @@ SSL_SNIFFER_API int ssl_SetNamedPrivateKeyBuffer(const char* name, int typeK, const char* password, char* error); +WOLFSSL_API +SSL_SNIFFER_API int ssl_SetEphemeralKey(const char* address, int port, + const char* keyFile, int typeKey, + const char* password, char* error); + +WOLFSSL_API +SSL_SNIFFER_API int ssl_SetEphemeralKeyBuffer(const char* address, int port, + const char* keyBuf, int keySz, int typeKey, + const char* password, char* error); + + +WOLFSSL_API +SSL_SNIFFER_API int ssl_SetNamedEphemeralKey(const char* name, + const char* address, int port, + const char* keyFile, int typeKey, + const char* password, char* error); + +WOLFSSL_API +SSL_SNIFFER_API int ssl_SetNamedEphemeralKeyBuffer(const char* name, + const char* address, int port, + const char* keyBuf, int keySz, int typeKey, + const char* password, char* error); + WOLFSSL_API SSL_SNIFFER_API int ssl_DecodePacket(const unsigned char* packet, int length, unsigned char** data, char* error); diff --git a/wolfssl/sniffer_error.h b/wolfssl/sniffer_error.h index d4e8369273..882aaeae7b 100644 --- a/wolfssl/sniffer_error.h +++ b/wolfssl/sniffer_error.h @@ -130,6 +130,7 @@ #define NO_DATA_DEST_STR 91 #define STORE_DATA_FAIL_STR 92 #define CHAIN_INPUT_STR 93 +#define GOT_ENC_EXT_STR 94 /* !!!! also add to msgTable in sniffer.c and .rc file !!!! */ diff --git a/wolfssl/ssl.h b/wolfssl/ssl.h index 8714786cb3..7f53918f11 100644 --- a/wolfssl/ssl.h +++ b/wolfssl/ssl.h @@ -3910,6 +3910,15 @@ WOLFSSL_API int wolfSSL_CTX_AllowEncryptThenMac(WOLFSSL_CTX *, int); WOLFSSL_API int wolfSSL_AllowEncryptThenMac(WOLFSSL *s, int); #endif +/* This feature is used to set a fixed ephemeral key and is for testing only */ +/* Currently allows ECDHE and DHE only */ +#ifdef WOLFSSL_STATIC_EPHEMERAL +WOLFSSL_API int wolfSSL_CTX_set_ephemeral_key(WOLFSSL_CTX* ctx, int keyAlgo, + const char* key, unsigned int keySz, int format); +WOLFSSL_API int wolfSSL_set_ephemeral_key(WOLFSSL* ssl, int keyAlgo, + const char* key, unsigned int keySz, int format); +#endif + #ifdef __cplusplus } /* extern "C" */ #endif diff --git a/wolfssl/test.h b/wolfssl/test.h index 385a3be211..6111d1592d 100644 --- a/wolfssl/test.h +++ b/wolfssl/test.h @@ -3601,15 +3601,16 @@ static WC_INLINE const char* mymktemp(char *tempfn, int len, int num) int enc, byte* ticket, int inLen, int* outLen, void* userCtx) { - (void)ssl; - (void)userCtx; - int ret; word16 sLen = XHTONS(inLen); byte aad[WOLFSSL_TICKET_NAME_SZ + WOLFSSL_TICKET_IV_SZ + 2]; int aadSz = WOLFSSL_TICKET_NAME_SZ + WOLFSSL_TICKET_IV_SZ + 2; byte* tmp = aad; + (void)ssl; + (void)userCtx; + + /* encrypt */ if (enc) { XMEMCPY(key_name, myKey_ctx.name, WOLFSSL_TICKET_NAME_SZ); @@ -3630,8 +3631,9 @@ static WC_INLINE const char* mymktemp(char *tempfn, int len, int num) mac); if (ret != 0) return WOLFSSL_TICKET_RET_REJECT; *outLen = inLen; /* no padding in this mode */ - } else { - /* decrypt */ + } + /* decrypt */ + else { /* see if we know this key */ if (XMEMCMP(key_name, myKey_ctx.name, WOLFSSL_TICKET_NAME_SZ) != 0){ @@ -3658,7 +3660,7 @@ static WC_INLINE const char* mymktemp(char *tempfn, int len, int num) return WOLFSSL_TICKET_RET_OK; } -#endif /* HAVE_SESSION_TICKET && CHACHA20 && POLY1305 */ +#endif /* HAVE_SESSION_TICKET && HAVE_CHACHA && HAVE_POLY1305 */ static WC_INLINE word16 GetRandomPort(void) { diff --git a/wolfssl/wolfcrypt/dh.h b/wolfssl/wolfcrypt/dh.h index a69232cc09..a92d7b3ce1 100644 --- a/wolfssl/wolfcrypt/dh.h +++ b/wolfssl/wolfcrypt/dh.h @@ -45,11 +45,19 @@ #ifdef WOLFSSL_ASYNC_CRYPT #include #endif + +/* Optional support extended DH public / private keys */ +#if !defined(WOLFSSL_DH_EXTRA) && (defined(WOLFSSL_QT) || \ + defined(OPENSSL_ALL) || defined(WOLFSSL_OPENSSH) || \ + defined(WOLFSSL_STATIC_EPHEMERAL)) + #define WOLFSSL_DH_EXTRA +#endif + typedef struct DhParams { - #ifdef HAVE_FFDHE_Q +#ifdef HAVE_FFDHE_Q const byte* q; word32 q_len; - #endif /* HAVE_FFDHE_Q */ +#endif /* HAVE_FFDHE_Q */ const byte* p; word32 p_len; const byte* g; @@ -58,8 +66,8 @@ typedef struct DhParams { /* Diffie-Hellman Key */ struct DhKey { - mp_int p, g, q; /* group parameters */ -#if defined(WOLFSSL_QT) || defined(OPENSSL_ALL) || defined(WOLFSSL_OPENSSH) + mp_int p, g, q; /* group parameters */ +#ifdef WOLFSSL_DH_EXTRA mp_int pub; mp_int priv; #endif @@ -101,15 +109,20 @@ WOLFSSL_API int wc_DhAgree(DhKey* key, byte* agree, word32* agreeSz, word32 pubSz); WOLFSSL_API int wc_DhKeyDecode(const byte* input, word32* inOutIdx, DhKey* key, - word32); + word32); /* wc_DhKeyDecode is in asn.c */ + WOLFSSL_API int wc_DhSetKey(DhKey* key, const byte* p, word32 pSz, const byte* g, word32 gSz); WOLFSSL_API int wc_DhSetKey_ex(DhKey* key, const byte* p, word32 pSz, const byte* g, word32 gSz, const byte* q, word32 qSz); -#if defined(WOLFSSL_QT) || defined(OPENSSL_ALL) -WOLFSSL_LOCAL int wc_DhSetFullKeys(DhKey* key,const byte* priv_key,word32 privSz, - const byte* pub_key, word32 pubSz); -#endif + +#ifdef WOLFSSL_DH_EXTRA +WOLFSSL_API int wc_DhImportKeyPair(DhKey* key, const byte* priv, word32 privSz, + const byte* pub, word32 pubSz); +WOLFSSL_API int wc_DhExportKeyPair(DhKey* key, byte* priv, word32* pPrivSz, + byte* pub, word32* pPubSz); +#endif /* WOLFSSL_DH_EXTRA */ + WOLFSSL_API int wc_DhSetCheckKey(DhKey* key, const byte* p, word32 pSz, const byte* g, word32 gSz, const byte* q, word32 qSz, int trusted, WC_RNG* rng); @@ -136,4 +149,3 @@ WOLFSSL_API int wc_DhExportParamsRaw(DhKey* dh, byte* p, word32* pSz, #endif /* NO_DH */ #endif /* WOLF_CRYPT_DH_H */ - diff --git a/wolfssl/wolfcrypt/wc_port.h b/wolfssl/wolfcrypt/wc_port.h index 41e8bfe6df..617a9e34e0 100644 --- a/wolfssl/wolfcrypt/wc_port.h +++ b/wolfssl/wolfcrypt/wc_port.h @@ -455,6 +455,9 @@ WOLFSSL_API int wolfCrypt_Cleanup(void); #define MAX_PATH 256 #endif + WOLFSSL_LOCAL int wc_FileLoad(const char* fname, unsigned char** buf, + size_t* bufLen, void* heap); + #if !defined(NO_WOLFSSL_DIR) && !defined(WOLFSSL_NUCLEUS) && \ !defined(WOLFSSL_NUCLEUS_1_2) typedef struct ReadDirCtx { From 3be390d50dcd9b948d68d85b1b51d57823d62d7a Mon Sep 17 00:00:00 2001 From: David Garske Date: Wed, 15 Jul 2020 11:42:43 -0700 Subject: [PATCH 16/60] Added TLS v1.3 session resumption support. TLS v1.3 uses session tickets and a resumption secret is derived after the "finished" message. This uses the internal static wolf session cache to retain the resumption secret between sniffer sessions. --- src/sniffer.c | 120 +++++++++++++++++++++++++++++++++------------ src/tls13.c | 2 +- wolfssl/internal.h | 1 + 3 files changed, 92 insertions(+), 31 deletions(-) diff --git a/src/sniffer.c b/src/sniffer.c index 31c77077b7..8fcfe648ac 100644 --- a/src/sniffer.c +++ b/src/sniffer.c @@ -2520,8 +2520,14 @@ static int ProcessSessionTicket(const byte* input, int* sslBytes, SetError(BAD_INPUT_STR, error, session, FATAL_ERROR_STATE); return -1; } - input += OPAQUE8_LEN + len; - *sslBytes -= OPAQUE8_LEN + len; + input += OPAQUE8_LEN; + *sslBytes -= OPAQUE8_LEN; + /* store nonce in server for DeriveResumptionPSK */ + session->sslServer->session.ticketNonce.len = len; + if (len > 0) + XMEMCPY(&session->sslServer->session.ticketNonce.data, input, len); + input += len; + *sslBytes -= len; } #endif @@ -2549,10 +2555,24 @@ static int ProcessSessionTicket(const byte* input, int* sslBytes, SetError(BAD_INPUT_STR, error, session, FATAL_ERROR_STATE); return -1; } - #endif + /* set haveSessionId to use the wolfSession cache */ + ssl->options.haveSessionId = 1; + + /* Use the wolf Session cache to retain resumption secret */ + if (session->flags.cached == 0) { + WOLFSSL_SESSION* sess = GetSession(ssl, NULL, 0); + if (sess == NULL) { + AddSession(ssl); /* don't re add */ + #ifdef WOLFSSL_SNIFFER_STATS + INC_STAT(SnifferStats.sslResumptionInserts); + #endif + } + session->flags.cached = 1; + } + #endif /* HAVE_SESSION_TICKET */ } else -#endif +#endif /* WOLFSSL_TLS13 */ { /* make sure ticket id isn't too long */ if (len > ID_LEN) { @@ -2716,6 +2736,11 @@ static int ProcessServerHello(int msgSz, const byte* input, int* sslBytes, /* indicates we want to use resumption */ session->sslServer->options.resuming = 1; session->sslClient->options.resuming = 1; + /* default nonce to len = 1, data = 0 */ + session->sslServer->session.ticketNonce.len = 1; + session->sslServer->session.ticketNonce.data[0] = 0; + session->sslClient->session.ticketNonce.len = 1; + session->sslClient->session.ticketNonce.data[0] = 0; break; #endif case EXT_SUPPORTED_VERSIONS: @@ -2764,18 +2789,32 @@ static int ProcessServerHello(int msgSz, const byte* input, int* sslBytes, } if (doResume) { - SSL_SESSION* resume = GetSession(session->sslServer, - session->sslServer->arrays->masterSecret, 0); - if (resume == NULL && !IsAtLeastTLSv1_3(session->sslServer->version)) { + WOLFSSL_SESSION* resume; + if (IsAtLeastTLSv1_3(session->sslServer->version)) { + resume = GetSession(session->sslServer, + session->sslServer->session.masterSecret, 0); + } + else { + resume = GetSession(session->sslServer, + session->sslServer->arrays->masterSecret, 0); + } + if (resume == NULL) { #ifdef WOLFSSL_SNIFFER_STATS INC_STAT(SnifferStats.sslResumeMisses); #endif SetError(BAD_SESSION_RESUME_STR, error, session, FATAL_ERROR_STATE); return -1; } + /* make sure client has master secret too */ - XMEMCPY(session->sslClient->arrays->masterSecret, - session->sslServer->arrays->masterSecret, SECRET_LEN); + if (IsAtLeastTLSv1_3(session->sslServer->version)) { + XMEMCPY(session->sslClient->session.masterSecret, + session->sslServer->session.masterSecret, SECRET_LEN); + } + else { + XMEMCPY(session->sslClient->arrays->masterSecret, + session->sslServer->arrays->masterSecret, SECRET_LEN); + } session->flags.resuming = 1; Trace(SERVER_DID_RESUMPTION_STR); @@ -2806,6 +2845,7 @@ static int ProcessServerHello(int msgSz, const byte* input, int* sslBytes, session->sslServer->arrays->psk_key, session->sslServer->arrays->psk_keySz); #endif + /* handshake key setup below and traffic keys done in SetupKeys */ } else #endif @@ -3120,10 +3160,9 @@ static int ProcessClientHello(const byte* input, int* sslBytes, inputHelloSz - bindersLen + HANDSHAKE_HEADER_SZ); /* call to decrypt session ticket */ - ret = DoClientTicket(ssl, identity, idLen); - if (ret != 0) { - SetError(CLIENT_HELLO_INPUT_STR, error, session, FATAL_ERROR_STATE); - return -1; + if (DoClientTicket(ssl, identity, idLen) != 0) { + /* we aren't decrypting the resumption, since we know the master secret */ + /* ignore errors */ } ssl->options.resuming = 1; @@ -3310,33 +3349,54 @@ static int ProcessFinished(const byte* input, int size, int* sslBytes, #ifdef WOLFSSL_TLS13 /* Derive TLS v1.3 traffic keys */ - if (IsAtLeastTLSv1_3(ssl->version) && !session->flags.gotFinished) { - /* When either side gets "finished" derive master secret and keys, but only set the key for the side encrypting data */ - ret = DeriveMasterSecret(session->sslServer); - ret += DeriveMasterSecret(session->sslClient); - #ifdef WOLFSSL_EARLY_DATA - ret += DeriveTls13Keys(session->sslServer, traffic_key, ENCRYPT_AND_DECRYPT_SIDE, ssl->earlyData == no_early_data); - ret += DeriveTls13Keys(session->sslClient, traffic_key, ENCRYPT_AND_DECRYPT_SIDE, ssl->earlyData == no_early_data); - #else - ret += DeriveTls13Keys(session->sslServer, traffic_key, ENCRYPT_AND_DECRYPT_SIDE, 1); - ret += DeriveTls13Keys(session->sslClient, traffic_key, ENCRYPT_AND_DECRYPT_SIDE, 1); - #endif + if (IsAtLeastTLSv1_3(ssl->version)) { + if (!session->flags.gotFinished) { + /* When either side gets "finished" derive master secret and keys */ + ret = DeriveMasterSecret(session->sslServer); + ret += DeriveMasterSecret(session->sslClient); + #ifdef WOLFSSL_EARLY_DATA + ret += DeriveTls13Keys(session->sslServer, traffic_key, ENCRYPT_AND_DECRYPT_SIDE, ssl->earlyData == no_early_data); + ret += DeriveTls13Keys(session->sslClient, traffic_key, ENCRYPT_AND_DECRYPT_SIDE, ssl->earlyData == no_early_data); + #else + ret += DeriveTls13Keys(session->sslServer, traffic_key, ENCRYPT_AND_DECRYPT_SIDE, 1); + ret += DeriveTls13Keys(session->sslClient, traffic_key, ENCRYPT_AND_DECRYPT_SIDE, 1); + #endif + + if (ret != 0) { + SetError(BAD_FINISHED_MSG, error, session, FATAL_ERROR_STATE); + return -1; + } + + session->flags.gotFinished = 1; + #ifdef SHOW_SECRETS + ShowTlsSecrets(session); + #endif + } + if (session->flags.side == WOLFSSL_SERVER_END) { - ret += SetKeysSide(session->sslServer, DECRYPT_SIDE_ONLY); + /* finished from client to server */ + ret = SetKeysSide(session->sslServer, DECRYPT_SIDE_ONLY); ret += SetKeysSide(session->sslClient, ENCRYPT_SIDE_ONLY); + + #ifdef HAVE_SESSION_TICKET + /* derive resumption secret for next session - on finished (from client) */ + ret += DeriveResumptionSecret(session->sslClient, session->sslClient->session.masterSecret); + + /* copy resumption secret to server */ + XMEMCPY(session->sslServer->session.masterSecret, + session->sslClient->session.masterSecret, SECRET_LEN); + #endif } else { - ret += SetKeysSide(session->sslServer, ENCRYPT_SIDE_ONLY); + /* finished from server to client */ + ret = SetKeysSide(session->sslServer, ENCRYPT_SIDE_ONLY); ret += SetKeysSide(session->sslClient, DECRYPT_SIDE_ONLY); } + if (ret != 0) { SetError(BAD_FINISHED_MSG, error, session, FATAL_ERROR_STATE); return -1; } - session->flags.gotFinished = 1; - #ifdef SHOW_SECRETS - ShowTlsSecrets(session); - #endif } #endif diff --git a/src/tls13.c b/src/tls13.c index 1b021f56a8..7c70d6f3db 100644 --- a/src/tls13.c +++ b/src/tls13.c @@ -737,7 +737,7 @@ static const byte resumeMasterLabel[RESUME_MASTER_LABEL_SZ + 1] = * key The derived key. * returns 0 on success, otherwise failure. */ -static int DeriveResumptionSecret(WOLFSSL* ssl, byte* key) +int DeriveResumptionSecret(WOLFSSL* ssl, byte* key) { WOLFSSL_MSG("Derive Resumption Secret"); if (ssl == NULL || ssl->arrays == NULL) { diff --git a/wolfssl/internal.h b/wolfssl/internal.h index 5371c5ee6e..f1d3a2868f 100644 --- a/wolfssl/internal.h +++ b/wolfssl/internal.h @@ -2590,6 +2590,7 @@ WOLFSSL_LOCAL int DeriveHandshakeSecret(WOLFSSL* ssl); WOLFSSL_LOCAL int DeriveTls13Keys(WOLFSSL* ssl, int secret, int side, int store); WOLFSSL_LOCAL int DeriveMasterSecret(WOLFSSL* ssl); WOLFSSL_LOCAL int DeriveResumptionPSK(WOLFSSL* ssl, byte* nonce, byte nonceLen, byte* secret); +WOLFSSL_LOCAL int DeriveResumptionSecret(WOLFSSL* ssl, byte* key); /* The key update request values for KeyUpdate message. */ enum KeyUpdateRequest { From e15e0828bf6fb82d11751314a68ed36df687ea89 Mon Sep 17 00:00:00 2001 From: David Garske Date: Wed, 15 Jul 2020 11:45:24 -0700 Subject: [PATCH 17/60] Cleanup of the `SHOW_SECRET` debugging. Use only latest wolf API's (not older Cyassl names). --- src/sniffer.c | 76 ++++++++++++++++++++++----------------------------- src/ssl.c | 4 +-- 2 files changed, 34 insertions(+), 46 deletions(-) diff --git a/src/sniffer.c b/src/sniffer.c index 8fcfe648ac..912e5f7e7f 100644 --- a/src/sniffer.c +++ b/src/sniffer.c @@ -599,7 +599,7 @@ static void FreeSnifferServer(SnifferServer* srv) wc_UnLockMutex(&srv->namedKeysMutex); wc_FreeMutex(&srv->namedKeysMutex); #endif - SSL_CTX_free(srv->ctx); + wolfSSL_CTX_free(srv->ctx); } XFREE(srv, NULL, DYNAMIC_TYPE_SNIFFER_SERVER); } @@ -635,8 +635,8 @@ static void FreePacketList(PacketBuffer* in) static void FreeSnifferSession(SnifferSession* session) { if (session) { - SSL_free(session->sslClient); - SSL_free(session->sslServer); + wolfSSL_free(session->sslClient); + wolfSSL_free(session->sslServer); FreePacketList(session->cliReassemblyList); FreePacketList(session->srvReassemblyList); @@ -1501,7 +1501,7 @@ static int CreateWatchSnifferServer(char* error) return -1; } InitSnifferServer(sniffer); - sniffer->ctx = SSL_CTX_new(SSLv23_client_method()); + sniffer->ctx = wolfSSL_CTX_new(SSLv23_client_method()); if (!sniffer->ctx) { SetError(MEMORY_STR, error, NULL, 0); FreeSnifferServer(sniffer); @@ -1592,7 +1592,7 @@ static int SetNamedPrivateKey(const char* name, const char* address, int port, sniffer->server = serverIp; sniffer->port = port; - sniffer->ctx = SSL_CTX_new(SSLv23_client_method()); + sniffer->ctx = wolfSSL_CTX_new(SSLv23_client_method()); if (!sniffer->ctx) { SetError(MEMORY_STR, error, NULL, 0); #ifdef HAVE_SNI @@ -1606,8 +1606,8 @@ static int SetNamedPrivateKey(const char* name, const char* address, int port, if (name == NULL) { if (password) { #ifdef WOLFSSL_ENCRYPTED_KEYS - SSL_CTX_set_default_passwd_cb(sniffer->ctx, SetPassword); - SSL_CTX_set_default_passwd_cb_userdata( + wolfSSL_CTX_set_default_passwd_cb(sniffer->ctx, SetPassword); + wolfSSL_CTX_set_default_passwd_cb_userdata( sniffer->ctx, (void*)password); #endif } @@ -1625,7 +1625,7 @@ static int SetNamedPrivateKey(const char* name, const char* address, int port, #endif { if (keySz == 0) { - ret = SSL_CTX_use_PrivateKey_file(sniffer->ctx, keyFile, type); + ret = wolfSSL_CTX_use_PrivateKey_file(sniffer->ctx, keyFile, type); } else { ret = wolfSSL_CTX_use_PrivateKey_buffer(sniffer->ctx, @@ -2027,23 +2027,24 @@ static void CallConnectionCb(SnifferSession* session) } #ifdef SHOW_SECRETS -static void ShowTlsSecrets(SnifferSession* session) +static void PrintSecret(const char* desc, const byte* buf, int sz) { int i; - printf("server master secret: "); - for (i = 0; i < SECRET_LEN; i++) - printf("%02x", session->sslServer->arrays->masterSecret[i]); - printf("\n"); - - printf("client master secret: "); - for (i = 0; i < SECRET_LEN; i++) - printf("%02x", session->sslClient->arrays->masterSecret[i]); + printf("%s: ", desc); + for (i = 0; i < sz; i++) { + printf("%02x", buf[i]); + } printf("\n"); +} +static void ShowTlsSecrets(SnifferSession* session) +{ + PrintSecret("server master secret", session->sslServer->arrays->masterSecret, SECRET_LEN); + PrintSecret("client master secret", session->sslClient->arrays->masterSecret, SECRET_LEN); printf("server suite = %d\n", session->sslServer->options.cipherSuite); printf("client suite = %d\n", session->sslClient->options.cipherSuite); } -#endif +#endif /* SHOW_SECRETS */ /* Process Keys */ @@ -2290,13 +2291,9 @@ static int SetupKeys(const byte* input, int* sslBytes, SnifferSession* session, session->sslServer->arrays->preMasterSz; #ifdef SHOW_SECRETS - { - word32 i; - printf("pre master secret: "); - for (i = 0; i < session->sslServer->arrays->preMasterSz; i++) - printf("%02x", session->sslServer->arrays->preMasterSecret[i]); - printf("\n"); - } + PrintSecret("pre master secret", + session->sslServer->arrays->preMasterSecret, + session->sslServer->arrays->preMasterSz); #endif if (SetCipherSpecs(session->sslServer) != 0) { @@ -2874,15 +2871,8 @@ static int ProcessServerHello(int msgSz, const byte* input, int* sslBytes, } #ifdef SHOW_SECRETS - { - int i; - printf("cipher suite = 0x%02x\n", - session->sslServer->options.cipherSuite); - printf("server random: "); - for (i = 0; i < RAN_LEN; i++) - printf("%02x", session->sslServer->arrays->serverRandom[i]); - printf("\n"); - } + printf("cipher suite = 0x%02x\n", session->sslServer->options.cipherSuite); + PrintSecret("server random", session->sslServer->arrays->serverRandom, RAN_LEN); #endif #ifdef WOLFSSL_TLS13 @@ -3011,14 +3001,9 @@ static int ProcessClientHello(const byte* input, int* sslBytes, XMEMCPY(session->sslClient->arrays->sessionID, input, ID_LEN); session->sslClient->options.haveSessionId = 1; } + #ifdef SHOW_SECRETS - { - int i; - printf("client random: "); - for (i = 0; i < RAN_LEN; i++) - printf("%02x", ssl->arrays->clientRandom[i]); - printf("\n"); - } + PrintSecret("client random", ssl->arrays->clientRandom, RAN_LEN); #endif input += bLen; @@ -3385,6 +3370,9 @@ static int ProcessFinished(const byte* input, int size, int* sslBytes, /* copy resumption secret to server */ XMEMCPY(session->sslServer->session.masterSecret, session->sslClient->session.masterSecret, SECRET_LEN); + #ifdef SHOW_SECRETS + PrintSecret("resumption secret", session->sslClient->session.masterSecret, SECRET_LEN); + #endif #endif } else { @@ -3841,15 +3829,15 @@ static SnifferSession* CreateSession(IpInfo* ipInfo, TcpInfo* tcpInfo, return 0; } - session->sslServer = SSL_new(session->context->ctx); + session->sslServer = wolfSSL_new(session->context->ctx); if (session->sslServer == NULL) { SetError(BAD_NEW_SSL_STR, error, session, FATAL_ERROR_STATE); XFREE(session, NULL, DYNAMIC_TYPE_SNIFFER_SESSION); return 0; } - session->sslClient = SSL_new(session->context->ctx); + session->sslClient = wolfSSL_new(session->context->ctx); if (session->sslClient == NULL) { - SSL_free(session->sslServer); + wolfSSL_free(session->sslServer); session->sslServer = 0; SetError(BAD_NEW_SSL_STR, error, session, FATAL_ERROR_STATE); diff --git a/src/ssl.c b/src/ssl.c index 1d4b63e4ee..0e16c0688a 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -24958,9 +24958,9 @@ long wolfSSL_set_tlsext_debug_arg(WOLFSSL* ssl, void *arg) #endif /* HAVE_PK_CALLBACKS */ #if defined(OPENSSL_ALL) || defined(WOLFSSL_HAPROXY) -const unsigned char *SSL_SESSION_get0_id_context(const SSL_SESSION *sess, unsigned int *sid_ctx_length) +const unsigned char *SSL_SESSION_get0_id_context(const WOLFSSL_SESSION *sess, unsigned int *sid_ctx_length) { - const byte *c = wolfSSL_SESSION_get_id((SSL_SESSION *)sess, sid_ctx_length); + const byte *c = wolfSSL_SESSION_get_id((WOLFSSL_SESSION *)sess, sid_ctx_length); return c; } #endif From 9409d8682f7590443f786b1aa4247b82218db257 Mon Sep 17 00:00:00 2001 From: David Garske Date: Wed, 15 Jul 2020 12:58:58 -0700 Subject: [PATCH 18/60] Fix for building without `session-ticket`. --- src/sniffer.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/sniffer.c b/src/sniffer.c index 912e5f7e7f..e83aa982b3 100644 --- a/src/sniffer.c +++ b/src/sniffer.c @@ -2519,10 +2519,12 @@ static int ProcessSessionTicket(const byte* input, int* sslBytes, } input += OPAQUE8_LEN; *sslBytes -= OPAQUE8_LEN; + #ifdef HAVE_SESSION_TICKET /* store nonce in server for DeriveResumptionPSK */ session->sslServer->session.ticketNonce.len = len; if (len > 0) XMEMCPY(&session->sslServer->session.ticketNonce.data, input, len); + #endif input += len; *sslBytes -= len; } From 23a3ead758c2ba1c1866aa313a691fffea2016ac Mon Sep 17 00:00:00 2001 From: David Garske Date: Fri, 17 Jul 2020 15:56:56 -0700 Subject: [PATCH 19/60] Framework for new TLS v1.3 sniffer tests. --- scripts/include.am | 3 +++ scripts/sniffer-testsuite.test | 18 ++++++++++++++++++ scripts/sniffer-tls13-dh.pcap | Bin 0 -> 49100 bytes scripts/sniffer-tls13-ecc.pcap | Bin 0 -> 47396 bytes scripts/sniffer-tls13-gen.sh | 24 ++++++++++++++++++++++++ sslSniffer/sslSnifferTest/snifftest.c | 2 +- 6 files changed, 46 insertions(+), 1 deletion(-) create mode 100644 scripts/sniffer-tls13-dh.pcap create mode 100644 scripts/sniffer-tls13-ecc.pcap create mode 100755 scripts/sniffer-tls13-gen.sh diff --git a/scripts/include.am b/scripts/include.am index 195dae78a1..50eeed9a3a 100644 --- a/scripts/include.am +++ b/scripts/include.am @@ -85,6 +85,9 @@ endif EXTRA_DIST += scripts/testsuite.pcap \ scripts/sniffer-ipv6.pcap \ + scripts/sniffer-tls13-dh.pcap \ + scripts/sniffer-tls13-ecc.pcap \ + scripts/sniffer-tls13-gen.sh \ scripts/ping.test # leave openssl.test as extra until non bash works diff --git a/scripts/sniffer-testsuite.test b/scripts/sniffer-testsuite.test index 491c1197e4..3125499211 100755 --- a/scripts/sniffer-testsuite.test +++ b/scripts/sniffer-testsuite.test @@ -8,7 +8,25 @@ echo -e "\nStaring snifftest on testsuite.pcap...\n" RESULT=$? [ $RESULT -ne 0 ] && echo -e "\nsnifftest failed\n" && exit 1 +# TLS v1.3 sniffer test ECC (and resumption) +if test $# -ne 0 +then + ./sslSniffer/sslSnifferTest/snifftest ./scripts/sniffer-tls13-ecc.pcap ./certs/statickeys/ecc-secp256r1.pem 127.0.0.1 11111 + RESULT=$? + [ $RESULT -ne 0 ] && echo -e "\nsnifftest TLS v1.3 ECC\n" && exit 1 +fi + +# TLS v1.3 sniffer test DH (and resumption) +if test $# -ne 0 +then + ./sslSniffer/sslSnifferTest/snifftest ./scripts/sniffer-tls13-dh.pcap ./certs/statickeys/dh-ffdhe2048.pem 127.0.0.1 11111 + + RESULT=$? + [ $RESULT -ne 0 ] && echo -e "\nsnifftest TLS v1.3 DH\n" && exit 1 +fi + +# IPv6 if test $# -ne 0 && test "x$1" = "x-6"; then echo -e "\nStaring snifftest on sniffer-ipv6.pcap...\n" diff --git a/scripts/sniffer-tls13-dh.pcap b/scripts/sniffer-tls13-dh.pcap new file mode 100644 index 0000000000000000000000000000000000000000..e1ca556a098eacb2eb58d1f916426bc120a53b44 GIT binary patch literal 49100 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 Date: Mon, 20 Jul 2020 11:10:46 -0700 Subject: [PATCH 20/60] Fix in `snifftest` to try loading private key into static ephemeral and private key. Updated pcap files (were missing TCP packets). --- scripts/sniffer-testsuite.test | 3 +++ scripts/sniffer-tls13-dh.pcap | Bin 49100 -> 64220 bytes scripts/sniffer-tls13-ecc.pcap | Bin 47396 -> 62868 bytes sslSniffer/sslSnifferTest/snifftest.c | 29 +++++++++++++++++--------- 4 files changed, 22 insertions(+), 10 deletions(-) diff --git a/scripts/sniffer-testsuite.test b/scripts/sniffer-testsuite.test index 3125499211..9bfb39b46e 100755 --- a/scripts/sniffer-testsuite.test +++ b/scripts/sniffer-testsuite.test @@ -2,6 +2,9 @@ #sniffer-testsuite.test +# ./configure --enable-sniffer [--enable-session-ticket] +# Resumption tests require "--enable-session-ticket" + echo -e "\nStaring snifftest on testsuite.pcap...\n" ./sslSniffer/sslSnifferTest/snifftest ./scripts/testsuite.pcap ./certs/server-key.pem 127.0.0.1 11111 diff --git a/scripts/sniffer-tls13-dh.pcap b/scripts/sniffer-tls13-dh.pcap index e1ca556a098eacb2eb58d1f916426bc120a53b44..f1d5d306199b5a0e6cf41a39a3a66e10f1586d4d 100644 GIT binary patch literal 64220 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 literal 49100 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 6) passwd = argv[5]; - if (argc >= 7) - isEphemeralKey = 1; - - if (isEphemeralKey) { - ret = ssl_SetEphemeralKey(server, port, argv[2], - FILETYPE_PEM, passwd, err); + /* try and load as both static ephemeral and private key */ + /* only fail if no key is loaded */ + #ifdef WOLFSSL_STATIC_EPHEMERAL + ret = ssl_SetEphemeralKey(server, port, argv[2], + FILETYPE_PEM, passwd, err); + if (ret == 0) + loadCount++; + #endif + ret = ssl_SetPrivateKey(server, port, argv[2], + FILETYPE_PEM, passwd, err); + if (ret == 0) + loadCount++; + if (loadCount > 0) { + ret = 0; } else { - ret = ssl_SetPrivateKey(server, port, argv[2], - FILETYPE_PEM, passwd, err); + printf("Failed loading private key %d\n", ret); + exit(EXIT_FAILURE); } } } else { /* usage error */ printf( "usage: ./snifftest or ./snifftest dump pemKey" - " [server] [port] [password] [isEphemeral]\n"); + " [server] [port] [password]\n"); exit(EXIT_FAILURE); } From 10c293a76cdd72d8a93260fc6eafe9821b16685e Mon Sep 17 00:00:00 2001 From: John Safranek Date: Mon, 20 Jul 2020 15:03:48 -0700 Subject: [PATCH 21/60] SCTP Test 1. Removed test cases for DTLSv1.0 that used AEAD ciphers. 2. Cleaned up some typos in the test configs. 3. Fixed typo in a WOLFSSL_SCTP ifdef check. --- src/ssl.c | 2 +- tests/test-sctp-sha2.conf | 16 +++++----- tests/test-sctp.conf | 65 ++++++++++----------------------------- 3 files changed, 25 insertions(+), 58 deletions(-) diff --git a/src/ssl.c b/src/ssl.c index 2a2ab77865..dd17f84416 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -2025,7 +2025,7 @@ static int wolfSSL_read_internal(WOLFSSL* ssl, void* data, int sz, int peek) #ifdef WOLFSSL_SCTP if (ssl->options.dtlsSctp) #endif -#if defined(WOLLSSL_SCTP) || defined(WOLFSSL_DTLS_MTU) +#if defined(WOLFSSL_SCTP) || defined(WOLFSSL_DTLS_MTU) ssl->dtls_expected_rx = max(ssl->dtls_expected_rx, ssl->dtlsMtuSz); #endif } diff --git a/tests/test-sctp-sha2.conf b/tests/test-sctp-sha2.conf index 4c72d4b408..a40c0ea08f 100644 --- a/tests/test-sctp-sha2.conf +++ b/tests/test-sctp-sha2.conf @@ -18,49 +18,49 @@ -v 2 -l AES256-SHA256 -# server TLSv1 ECDHE-PSK-AES128-SHA256 +# server DTLSv1 ECDHE-PSK-AES128-SHA256 -s -G -v 1 -l ECDHE-PSK-AES128-SHA256 -# client TLSv1 ECDHE-PSK-AES128-SHA256 +# client DTLSv1 ECDHE-PSK-AES128-SHA256 -s -G -v 1 -l ECDHE-PSK-AES128-SHA256 -# server TLSv1.1 ECDHE-PSK-AES128-SHA256 +# server DTLSv1.1 ECDHE-PSK-AES128-SHA256 -s -G -v 2 -l ECDHE-PSK-AES128-SHA256 -# client TLSv1.1 ECDHE-PSK-AES128-SHA256 +# client DTLSv1.1 ECDHE-PSK-AES128-SHA256 -s -G -v 2 -l ECDHE-PSK-AES128-SHA256 -# server TLSv1 ECDHE-PSK-NULL-SHA256 +# server DTLSv1 ECDHE-PSK-NULL-SHA256 -s -G -v 1 -l ECDHE-PSK-NULL-SHA256 -# client TLSv1 ECDHE-PSK-NULL-SHA256 +# client DTLSv1 ECDHE-PSK-NULL-SHA256 -s -G -v 1 -l ECDHE-PSK-NULL-SHA256 -# server TLSv1.1 ECDHE-PSK-NULL-SHA256 +# server DTLSv1.1 ECDHE-PSK-NULL-SHA256 -s -G -v 2 -l ECDHE-PSK-NULL-SHA256 -# client TLSv1.1 ECDHE-PSK-NULL-SHA256 +# client DTLSv1.1 ECDHE-PSK-NULL-SHA256 -s -G -v 2 diff --git a/tests/test-sctp.conf b/tests/test-sctp.conf index a2c2bc052a..5dfae30c99 100644 --- a/tests/test-sctp.conf +++ b/tests/test-sctp.conf @@ -1,36 +1,3 @@ -# server DTLSv1 DHE-RSA-CHACHA20-POLY1305 --G --v 2 --l DHE-RSA-CHACHA20-POLY1305 - -# client DTLSv1 DHE-RSA-CHACHA20-POLY1305 --G --v 2 --l DHE-RSA-CHACHA20-POLY1305 - -# server DTLSv1 ECDHE-RSA-CHACHA20-POLY1305 --G --v 2 --l ECDHE-RSA-CHACHA20-POLY1305 - -# client DTLSv1 ECDHE-RSA-CHACHA20-POLY1305 --G --v 2 --l ECDHE-RSA-CHACHA20-POLY1305 - -# server DTLSv1 ECDHE-EDCSA-CHACHA20-POLY1305 --G --v 2 --l ECDHE-ECDSA-CHACHA20-POLY1305 --c ./certs/server-ecc.pem --k ./certs/ecc-key.pem - -# client DTLSv1 ECDHE-ECDSA-CHACHA20-POLY1305 --G --v 2 --l ECDHE-ECDSA-CHACHA20-POLY1305 --A ./certs/ca-ecc-cert.pem - # server DTLSv1.2 DHE-RSA-CHACHA20-POLY1305 -G -v 3 @@ -64,37 +31,37 @@ -l ECDHE-ECDSA-CHACHA20-POLY1305 -A ./certs/ca-ecc-cert.pem -# server TLSv1.2 DHE-PSK-CHACHA20-POLY1305 +# server DTLSv1.2 DHE-PSK-CHACHA20-POLY1305 -G -v 3 -s -l DHE-PSK-CHACHA20-POLY1305 -# client TLSv1.2 DHE-PSK-CHACHA20-POLY1305 +# client DTLSv1.2 DHE-PSK-CHACHA20-POLY1305 -G -v 3 -s -l DHE-PSK-CHACHA20-POLY1305 -# server TLSv1.2 ECDHE-PSK-CHACHA20-POLY1305 +# server DTLSv1.2 ECDHE-PSK-CHACHA20-POLY1305 -G -v 3 -s -l ECDHE-PSK-CHACHA20-POLY1305 -# client TLSv1.2 ECDHE-PSK-CHACHA20-POLY1305 +# client DTLSv1.2 ECDHE-PSK-CHACHA20-POLY1305 -G -v 3 -s -l ECDHE-PSK-CHACHA20-POLY1305 -# server TLSv1.2 PSK-CHACHA20-POLY1305 +# server DTLSv1.2 PSK-CHACHA20-POLY1305 -G -v 3 -s -l PSK-CHACHA20-POLY1305 -# client TLSv1.2 PSK-CHACHA20-POLY1305 +# client DTLSv1.2 PSK-CHACHA20-POLY1305 -G -v 3 -s @@ -333,40 +300,40 @@ -v 3 -l ECDHE-RSA-AES256-SHA -# server TLSv1 ECDHE-ECDSA-NULL-SHA +# server DTLSv1 ECDHE-ECDSA-NULL-SHA -G -v 1 -l ECDHE-ECDSA-NULL-SHA -c ./certs/server-ecc.pem -k ./certs/ecc-key.pem -# client TLSv1 ECDHE-ECDSA-NULL-SHA +# client DTLSv1 ECDHE-ECDSA-NULL-SHA -G -v 1 -l ECDHE-ECDSA-NULL-SHA -A ./certs/ca-ecc-cert.pem -# server TLSv1.1 ECDHE-ECDSA-NULL-SHA +# server DTLSv1.1 ECDHE-ECDSA-NULL-SHA -G -v 2 -l ECDHE-ECDSA-NULL-SHA -c ./certs/server-ecc.pem -k ./certs/ecc-key.pem -# client TLSv1 ECDHE-ECDSA-NULL-SHA +# client DTLSv1 ECDHE-ECDSA-NULL-SHA -G -v 2 -l ECDHE-ECDSA-NULL-SHA -A ./certs/ca-ecc-cert.pem -# server TLSv1.2 ECDHE-ECDSA-NULL-SHA +# server DTLSv1.2 ECDHE-ECDSA-NULL-SHA -G -v 3 -l ECDHE-ECDSA-NULL-SHA -c ./certs/server-ecc.pem -k ./certs/ecc-key.pem -# client TLSv1.2 ECDHE-ECDSA-NULL-SHA +# client DTLSv1.2 ECDHE-ECDSA-NULL-SHA -G -v 3 -l ECDHE-ECDSA-NULL-SHA @@ -762,25 +729,25 @@ -l ECDH-ECDSA-AES256-SHA384 -A ./certs/ca-ecc-cert.pem -# server TLSv1.2 ECDHE-PSK-AES128-SHA256 +# server DTLSv1.2 ECDHE-PSK-AES128-SHA256 -s -G -v 3 -l ECDHE-PSK-AES128-SHA256 -# client TLSv1.2 ECDHE-PSK-AES128-SHA256 +# client DTLSv1.2 ECDHE-PSK-AES128-SHA256 -s -G -v 3 -l ECDHE-PSK-AES128-SHA256 -# server TLSv1.2 ECDHE-PSK-NULL-SHA256 +# server DTLSv1.2 ECDHE-PSK-NULL-SHA256 -s -G -v 3 -l ECDHE-PSK-NULL-SHA256 -# client TLSv1.2 ECDHE-PSK-NULL-SHA256 +# client DTLSv1.2 ECDHE-PSK-NULL-SHA256 -s -G -v 3 From 5d5aa129ca2ee85c6ec0f444ac7b2fb89786f479 Mon Sep 17 00:00:00 2001 From: John Safranek Date: Mon, 20 Jul 2020 16:14:53 -0700 Subject: [PATCH 22/60] When attempting to send a message with DTLS, if it is too large, return an error rather than splitting it across records. (ZD 10602) --- src/internal.c | 13 +++++++++---- wolfssl/error-ssl.h | 1 + 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/internal.c b/src/internal.c index 36eed125f1..39af97f692 100644 --- a/src/internal.c +++ b/src/internal.c @@ -17709,9 +17709,11 @@ int SendData(WOLFSSL* ssl, const void* data, int sz) len = wolfSSL_GetMaxRecordSize(ssl, sz - sent); -#ifdef WOLFSSL_DTLS - if (IsDtlsNotSctpMode(ssl)) { - len = min(len, MAX_UDP_SIZE); +#if defined(WOLFSSL_DTLS) && !defined(WOLFSSL_NO_DTLS_SIZE_CHECK) + if (ssl->options.dtls && (len < sz - sent)) { + ssl->error = DTLS_SIZE_ERROR; + WOLFSSL_ERROR(ssl->error); + return ssl->error; } #endif buffSz = len; @@ -18439,6 +18441,9 @@ const char* wolfSSL_ERR_reason_error_string(unsigned long e) case TLS13_SECRET_CB_E: return "TLS1.3 Secret Callback Error"; + case DTLS_SIZE_ERROR: + return "DTLS trying to send too much in single datagram error"; + default : return "unknown error number"; } @@ -29977,7 +29982,7 @@ int wolfSSL_GetMaxRecordSize(WOLFSSL* ssl, int maxFragment) } #endif /* HAVE_MAX_FRAGMENT */ #ifdef WOLFSSL_DTLS - if ((ssl->options.dtls) && (maxFragment > MAX_UDP_SIZE)) { + if (IsDtlsNotSctpMode(ssl) && (maxFragment > MAX_UDP_SIZE)) { maxFragment = MAX_UDP_SIZE; } #endif diff --git a/wolfssl/error-ssl.h b/wolfssl/error-ssl.h index 9b44326e7f..9478242aa0 100644 --- a/wolfssl/error-ssl.h +++ b/wolfssl/error-ssl.h @@ -167,6 +167,7 @@ enum wolfSSL_ErrorCodes { CLIENT_CERT_CB_ERROR = -436, /* Client cert callback error */ SSL_SHUTDOWN_ALREADY_DONE_E = -437, /* Shutdown called redundantly */ TLS13_SECRET_CB_E = -438, /* TLS1.3 secret Cb fcn failure */ + DTLS_SIZE_ERROR = -439, /* Trying to send too much data */ /* add strings to wolfSSL_ERR_reason_error_string in internal.c !!!!! */ From c204eb0fb15fd8ad5d776fbf72a0ec855fa4b063 Mon Sep 17 00:00:00 2001 From: TakayukiMatsuo Date: Tue, 21 Jul 2020 16:09:16 +0900 Subject: [PATCH 23/60] commented out NO_ASM_TIME macro to enable certificate validation --- IDE/Renesas/e2studio/RX72NEnvisionKit/common/user_settings.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/IDE/Renesas/e2studio/RX72NEnvisionKit/common/user_settings.h b/IDE/Renesas/e2studio/RX72NEnvisionKit/common/user_settings.h index 0add31be15..bcc83bdb76 100644 --- a/IDE/Renesas/e2studio/RX72NEnvisionKit/common/user_settings.h +++ b/IDE/Renesas/e2studio/RX72NEnvisionKit/common/user_settings.h @@ -100,7 +100,7 @@ * "NO_ASN_TIME" macro. And prepare time function to get calender time, * otherwise, certificate expiration validation will not work. */ - #define NO_ASN_TIME + /*#define NO_ASN_TIME*/ #define NO_MAIN_DRIVER #define BENCH_EMBEDDED From c45e1925818bba595b00b58da0897d9007ab6146 Mon Sep 17 00:00:00 2001 From: Sean Parkinson Date: Fri, 17 Jul 2020 10:58:59 +1000 Subject: [PATCH 24/60] Send more detail alerts for bad certificates --- src/internal.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/src/internal.c b/src/internal.c index 36eed125f1..aeab8e3cce 100644 --- a/src/internal.c +++ b/src/internal.c @@ -11062,8 +11062,11 @@ int ProcessPeerCerts(WOLFSSL* ssl, byte* input, word32* inOutIdx, } else if (ret == ASN_PARSE_E || ret == BUFFER_E) { WOLFSSL_MSG("Got Peer cert ASN PARSE or BUFFER ERROR"); + #if defined(WOLFSSL_EXTRA_ALERTS) || defined(OPENSSL_EXTRA) || \ + defined(OPENSSL_EXTRA_X509_SMALL) + DoCertFatalAlert(ssl, ret); + #endif #if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) - SendAlert(ssl, alert_fatal, bad_certificate); ssl->peerVerifyRet = X509_V_ERR_CERT_REJECTED; #endif args->fatal = 1; @@ -11078,12 +11081,20 @@ int ProcessPeerCerts(WOLFSSL* ssl, byte* input, word32* inOutIdx, "\tCallback override available, will continue"); /* check if fatal error */ args->fatal = (args->verifyErr) ? 1 : 0; + #if defined(WOLFSSL_EXTRA_ALERTS) || \ + defined(OPENSSL_EXTRA) || \ + defined(OPENSSL_EXTRA_X509_SMALL) + if (args->fatal) + DoCertFatalAlert(ssl, ret); + #endif } else { WOLFSSL_MSG("\tNo callback override available, fatal"); args->fatal = 1; - #ifdef OPENSSL_EXTRA - SendAlert(ssl, alert_fatal, bad_certificate); + #if defined(WOLFSSL_EXTRA_ALERTS) || \ + defined(OPENSSL_EXTRA) || \ + defined(OPENSSL_EXTRA_X509_SMALL) + DoCertFatalAlert(ssl, ret); #endif } } From 9268ae1397d2aa74c0c9bda37af9d5a92c8f777a Mon Sep 17 00:00:00 2001 From: David Garske Date: Tue, 21 Jul 2020 10:41:25 -0700 Subject: [PATCH 25/60] Fix line length issues. Add debug msg in test to show number of non-blocking iterations. ``` $ ./configure --enable-ecc=nonblock --enable-sp=yes,nonblock CFLAGS="-DWOLFSSL_PUBLIC_MP" --enable-debug && make $ ./wolfcrypt/test/testwolfcrypt ... ECC non-block sign: 18063 times ECC non-block verify: 35759 times ECC test passed! ``` --- wolfcrypt/src/ecc.c | 29 ++++++++++++++++++----------- wolfcrypt/test/test.c | 17 +++++++++++++++-- 2 files changed, 33 insertions(+), 13 deletions(-) diff --git a/wolfcrypt/src/ecc.c b/wolfcrypt/src/ecc.c index 58d57fb562..5371505325 100644 --- a/wolfcrypt/src/ecc.c +++ b/wolfcrypt/src/ecc.c @@ -4917,11 +4917,13 @@ int wc_ecc_sign_hash_ex(const byte* in, word32 inlen, WC_RNG* rng, if (ecc_sets[key->idx].id == ECC_SECP256R1) { #ifdef WC_ECC_NONBLOCK if (key->nb_ctx) { - return sp_ecc_sign_256_nb(&key->nb_ctx->sp_ctx, in, inlen, rng, &key->k, r, s, sign_k, key->heap); + return sp_ecc_sign_256_nb(&key->nb_ctx->sp_ctx, in, inlen, rng, + &key->k, r, s, sign_k, key->heap); } #endif #ifndef WC_ECC_NONBLOCK_ONLY - return sp_ecc_sign_256(in, inlen, rng, &key->k, r, s, sign_k, key->heap); + return sp_ecc_sign_256(in, inlen, rng, &key->k, r, s, sign_k, + key->heap); #else return NOT_COMPILED_IN; #endif @@ -4931,11 +4933,13 @@ int wc_ecc_sign_hash_ex(const byte* in, word32 inlen, WC_RNG* rng, if (ecc_sets[key->idx].id == ECC_SECP384R1) { #ifdef WC_ECC_NONBLOCK if (key->nb_ctx) { - return sp_ecc_sign_384_nb(&key->nb_ctx->sp_ctx, in, inlen, rng, &key->k, r, s, sign_k, key->heap); + return sp_ecc_sign_384_nb(&key->nb_ctx->sp_ctx, in, inlen, rng, + &key->k, r, s, sign_k, key->heap); } #endif #ifndef WC_ECC_NONBLOCK_ONLY - return sp_ecc_sign_384(in, inlen, rng, &key->k, r, s, sign_k, key->heap); + return sp_ecc_sign_384(in, inlen, rng, &key->k, r, s, sign_k, + key->heap); #else return NOT_COMPILED_IN; #endif @@ -5985,12 +5989,12 @@ int wc_ecc_verify_hash_ex(mp_int *r, mp_int *s, const byte* hash, #if defined(WOLFSSL_DSP) && !defined(FREESCALE_LTC_ECC) if (key->handle != -1) { - return sp_dsp_ecc_verify_256(key->handle, hash, hashlen, key->pubkey.x, key->pubkey.y, - key->pubkey.z, r, s, res, key->heap); + return sp_dsp_ecc_verify_256(key->handle, hash, hashlen, key->pubkey.x, + key->pubkey.y, key->pubkey.z, r, s, res, key->heap); } if (wolfSSL_GetHandleCbSet() == 1) { - return sp_dsp_ecc_verify_256(0, hash, hashlen, key->pubkey.x, key->pubkey.y, - key->pubkey.z, r, s, res, key->heap); + return sp_dsp_ecc_verify_256(0, hash, hashlen, key->pubkey.x, + key->pubkey.y, key->pubkey.z, r, s, res, key->heap); } #endif @@ -6002,7 +6006,8 @@ int wc_ecc_verify_hash_ex(mp_int *r, mp_int *s, const byte* hash, } #endif -#if (defined(WOLFSSL_SP_MATH) || defined(WOLFSSL_HAVE_SP_ECC)) && !defined(FREESCALE_LTC_ECC) +#if (defined(WOLFSSL_SP_MATH) || defined(WOLFSSL_HAVE_SP_ECC)) && \ + !defined(FREESCALE_LTC_ECC) if (key->idx != ECC_CUSTOM_IDX #if defined(WOLFSSL_ASYNC_CRYPT) && defined(WC_ASYNC_ENABLE_ECC) && key->asyncDev.marker != WOLFSSL_ASYNC_MARKER_ECC @@ -6013,7 +6018,8 @@ int wc_ecc_verify_hash_ex(mp_int *r, mp_int *s, const byte* hash, #ifdef WC_ECC_NONBLOCK if (key->nb_ctx) { return sp_ecc_verify_256_nb(&key->nb_ctx->sp_ctx, hash, hashlen, - key->pubkey.x, key->pubkey.y, key->pubkey.z, r, s, res, key->heap); + key->pubkey.x, key->pubkey.y, key->pubkey.z, r, s, res, + key->heap); } #endif #ifndef WC_ECC_NONBLOCK_ONLY @@ -6029,7 +6035,8 @@ int wc_ecc_verify_hash_ex(mp_int *r, mp_int *s, const byte* hash, #ifdef WC_ECC_NONBLOCK if (key->nb_ctx) { return sp_ecc_verify_384_nb(&key->nb_ctx->sp_ctx, hash, hashlen, - key->pubkey.x, key->pubkey.y, key->pubkey.z, r, s, res, key->heap); + key->pubkey.x, key->pubkey.y, key->pubkey.z, r, s, res, + key->heap); } #endif #ifndef WC_ECC_NONBLOCK_ONLY diff --git a/wolfcrypt/test/test.c b/wolfcrypt/test/test.c index 217b17ee2f..019e0b95cc 100644 --- a/wolfcrypt/test/test.c +++ b/wolfcrypt/test/test.c @@ -20273,7 +20273,7 @@ static int crypto_ecc_verify(const uint8_t *key, uint32_t keySz, const uint8_t *hash, uint32_t hashSz, const uint8_t *sig, uint32_t sigSz, uint32_t curveSz, int curveId) { - int ret, verify_res = 0; + int ret, verify_res = 0, count = 0; mp_int r, s; ecc_key ecc; ecc_nb_ctx_t nb_ctx; @@ -20340,9 +20340,13 @@ static int crypto_ecc_verify(const uint8_t *key, uint32_t keySz, &verify_res, /* verification result 1=success */ &ecc ); + count++; /* TODO: Real-time work can be called here */ } while (ret == FP_WOULDBLOCK); + #ifdef DEBUG_WOLFSSL + printf("ECC non-block verify: %d times\n", count); + #endif } /* check verify result */ @@ -20354,6 +20358,8 @@ static int crypto_ecc_verify(const uint8_t *key, uint32_t keySz, mp_clear(&s); wc_ecc_free(&ecc); + (void)count; + return ret; } @@ -20362,7 +20368,7 @@ static int crypto_ecc_sign(const uint8_t *key, uint32_t keySz, const uint8_t *hash, uint32_t hashSz, uint8_t *sig, uint32_t* sigSz, uint32_t curveSz, int curveId, WC_RNG* rng) { - int ret; + int ret, count = 0; mp_int r, s; ecc_key ecc; ecc_nb_ctx_t nb_ctx; @@ -20418,9 +20424,14 @@ static int crypto_ecc_sign(const uint8_t *key, uint32_t keySz, rng, &ecc, /* random and key context */ &r, &s /* r/s as mp_int */ ); + count++; /* TODO: Real-time work can be called here */ } while (ret == FP_WOULDBLOCK); + + #ifdef DEBUG_WOLFSSL + printf("ECC non-block sign: %d times\n", count); + #endif } if (ret == 0) { @@ -20433,6 +20444,8 @@ static int crypto_ecc_sign(const uint8_t *key, uint32_t keySz, mp_clear(&s); wc_ecc_free(&ecc); + (void)count; + return ret; } From e8034619ba447a5694b6fcdf385aa5f13d7eb2a5 Mon Sep 17 00:00:00 2001 From: Ethan Looney Date: Tue, 21 Jul 2020 08:45:20 -0700 Subject: [PATCH 26/60] Add more if defined to ERR_print_errors_fp --- tests/api.c | 76 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) diff --git a/tests/api.c b/tests/api.c index fb7c1fe80c..b864a7fd7d 100644 --- a/tests/api.c +++ b/tests/api.c @@ -27143,7 +27143,79 @@ static void test_wolfSSL_ERR_print_errors_cb(void) printf(resultFmt, passed); #endif } +/* + * Testing WOLFSSL_ERROR_MSG + */ +static int test_WOLFSSL_ERROR_MSG (void) +{ + int ret = 0; +#if defined(DEBUG_WOLFSSL) || defined(OPENSSL_ALL) || defined(WOLFSSL_NGINX) ||\ + defined(WOLFSSL_HAPROXY) || defined(OPENSSL_EXTRA) + const char* msg = "Everyone gets Friday off."; + printf(testingFmt, "WOLFSSL_ERROR_MSG()"); + + WOLFSSL_ERROR_MSG(msg); + + printf(resultFmt, ret == 0 ? passed : failed); + +#endif + return ret; + +}/*End test_WOLFSSL_ERROR_MSG*/ +/* + * Testing wc_ERR_remove_state + */ +static int test_wc_ERR_remove_state (void) +{ + int ret = 0; + +#if defined(OPENSSL_EXTRA) || defined(DEBUG_WOLFSSL_VERBOSE) + + printf(testingFmt, "wc_ERR_remove_state()"); + + ret = wc_ERR_remove_state(); + + printf(resultFmt, ret == 0 ? passed : failed); + +#endif + return ret; + +}/*End test_wc_ERR_remove_state*/ +/* + * Testing wc_ERR_print_errors_fp + */ +static int test_wc_ERR_print_errors_fp (void) +{ + int ret = 0; +#if (defined(OPENSSL_EXTRA) || defined(DEBUG_WOLFSSL_VERBOSE)) && \ + (!defined(NO_FILESYSTEM) && !defined(NO_STDIO_FILESYSTEM)) + + printf(testingFmt, "wc_ERR_print_errors_fp()"); + + XFILE fp = XFOPEN("./certs/dsa2048.der", "rb"); + wc_ERR_print_errors_fp(fp); + + printf(resultFmt, ret == 0 ? passed : failed); + XFCLOSE(fp); +#endif + + return ret; + +}/*End test_wc_ERR_print_errors_fp*/ +/* + * Testing wolfSSL_GetLoggingCb + */ +static int test_wolfSSL_GetLoggingCb (void) +{ + int ret = 0; + printf(testingFmt, "wolfSSL_GetLoggingCb()"); + + wolfSSL_GetLoggingCb(); + + printf(resultFmt, ret == 0 ? passed : failed); + return ret; +}/*End test_wolfSSL_GetLoggingCb*/ static void test_wolfSSL_HMAC(void) { #if defined(OPENSSL_EXTRA) && !defined(NO_SHA256) @@ -34923,6 +34995,10 @@ void ApiTest(void) test_wolfSSL_ERR_peek_last_error_line(); #endif test_wolfSSL_ERR_print_errors_cb(); + AssertFalse(test_wolfSSL_GetLoggingCb()); + AssertFalse(test_WOLFSSL_ERROR_MSG()); + AssertFalse(test_wc_ERR_remove_state()); + AssertFalse(test_wc_ERR_print_errors_fp()); test_wolfSSL_set_options(); test_wolfSSL_sk_SSL_CIPHER(); test_wolfSSL_X509_STORE_CTX(); From b500a54fc59102de920afe34bedc9c9e82a1b9e0 Mon Sep 17 00:00:00 2001 From: Ethan Looney Date: Tue, 21 Jul 2020 11:59:04 -0700 Subject: [PATCH 27/60] Added new file to read in and dump error message and added cleanup within cleanup script --- scripts/cleanup_testfiles.sh | 1 + tests/api.c | 24 +++++++++++++++--------- 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/scripts/cleanup_testfiles.sh b/scripts/cleanup_testfiles.sh index c7f3885fc8..f4ffd69061 100755 --- a/scripts/cleanup_testfiles.sh +++ b/scripts/cleanup_testfiles.sh @@ -12,3 +12,4 @@ rm -f ./certeccrsa.der rm -f ./ecc-key.der rm -f ./ecc-key.pem rm -f ./ecc-public-key.der +rm -f ./test-log-dump-to-file.txt diff --git a/tests/api.c b/tests/api.c index b864a7fd7d..e85dad1358 100644 --- a/tests/api.c +++ b/tests/api.c @@ -27169,16 +27169,16 @@ static int test_WOLFSSL_ERROR_MSG (void) static int test_wc_ERR_remove_state (void) { int ret = 0; - #if defined(OPENSSL_EXTRA) || defined(DEBUG_WOLFSSL_VERBOSE) printf(testingFmt, "wc_ERR_remove_state()"); - ret = wc_ERR_remove_state(); - + wc_ERR_remove_state(); + printf(resultFmt, ret == 0 ? passed : failed); - + #endif + return ret; }/*End test_wc_ERR_remove_state*/ @@ -27190,16 +27190,22 @@ static int test_wc_ERR_print_errors_fp (void) int ret = 0; #if (defined(OPENSSL_EXTRA) || defined(DEBUG_WOLFSSL_VERBOSE)) && \ (!defined(NO_FILESYSTEM) && !defined(NO_STDIO_FILESYSTEM)) - + int sz; printf(testingFmt, "wc_ERR_print_errors_fp()"); - - XFILE fp = XFOPEN("./certs/dsa2048.der", "rb"); + WOLFSSL_ERROR(BAD_FUNC_ARG); + //XFILE fp = XFOPEN("./certs/ecc-keyPkcs8.pem", "rb"); + XFILE fp = XFOPEN("./test-log-dump-to-file.txt", "ar"); wc_ERR_print_errors_fp(fp); - + + AssertTrue(XFSEEK(fp, 0, XSEEK_END) == 0); + sz = XFTELL(fp); + if (sz == 0) { + ret = BAD_FUNC_ARG; + } + printf(resultFmt, ret == 0 ? passed : failed); XFCLOSE(fp); #endif - return ret; }/*End test_wc_ERR_print_errors_fp*/ From 89913076f1ed5e8e2641174efa113a40ba9eb7ba Mon Sep 17 00:00:00 2001 From: Eric Blankenhorn Date: Tue, 21 Jul 2020 16:36:30 -0500 Subject: [PATCH 28/60] Fix build error with X509_SMALL config --- src/ssl.c | 24 +++++++++++------------- wolfssl/ssl.h | 2 +- 2 files changed, 12 insertions(+), 14 deletions(-) diff --git a/src/ssl.c b/src/ssl.c index 2a2ab77865..91be1adc6d 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -29441,9 +29441,10 @@ int wolfSSL_DH_set0_pqg(WOLFSSL_DH *dh, WOLFSSL_BIGNUM *p, #endif /* !HAVE_FIPS || HAVE_FIPS_VERSION > 2 */ #endif /* NO_DH */ +#endif /* OPENSSL_EXTRA */ - -#ifndef NO_DSA +#if !defined(NO_DSA) && \ + (defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)) static void InitwolfSSL_DSA(WOLFSSL_DSA* dsa) { if (dsa) { @@ -29516,12 +29517,6 @@ void wolfSSL_DSA_free(WOLFSSL_DSA* dsa) } } -#endif /* NO_DSA */ -#endif /* OPENSSL_EXTRA */ - -#ifdef OPENSSL_EXTRA - -#ifndef NO_DSA /* wolfSSL -> OpenSSL */ int SetDsaExternal(WOLFSSL_DSA* dsa) { @@ -29564,7 +29559,10 @@ int SetDsaExternal(WOLFSSL_DSA* dsa) return WOLFSSL_SUCCESS; } +#endif /* !NO_DSA && (OPENSSL_EXTRA || OPENSSL_EXTRA_X509_SMALL) */ + +#if !defined(NO_DSA) && defined(OPENSSL_EXTRA) /* Openssl -> WolfSSL */ int SetDsaInternal(WOLFSSL_DSA* dsa) { @@ -29620,8 +29618,7 @@ int SetDsaInternal(WOLFSSL_DSA* dsa) return WOLFSSL_SUCCESS; } -#endif /* NO_DSA */ -#endif /* OPENSSL_EXTRA */ +#endif /* !NO_DSA && OPENSSL_EXTRA */ #ifdef OPENSSL_EXTRA @@ -35559,8 +35556,8 @@ int wolfSSL_RSA_set0_key(WOLFSSL_RSA *r, WOLFSSL_BIGNUM *n, WOLFSSL_BIGNUM *e, #endif /* OPENSSL_EXTRA */ #endif /* NO_RSA */ -#ifdef OPENSSL_EXTRA -#ifndef NO_DSA +#if !defined(NO_DSA) && \ + (defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)) /* return WOLFSSL_SUCCESS if success, WOLFSSL_FATAL_ERROR if error */ int wolfSSL_DSA_LoadDer(WOLFSSL_DSA* dsa, const unsigned char* derBuf, int derSz) { @@ -35630,8 +35627,9 @@ int wolfSSL_DSA_LoadDer_ex(WOLFSSL_DSA* dsa, const unsigned char* derBuf, return WOLFSSL_SUCCESS; } -#endif /* !NO_DSA */ +#endif /* !NO_DSA && (OPENSSL_EXTRA || OPENSSL_EXTRA_X509_SMALL) */ +#ifdef OPENSSL_EXTRA #ifdef HAVE_ECC /* return WOLFSSL_SUCCESS if success, WOLFSSL_FATAL_ERROR if error */ int wolfSSL_EC_KEY_LoadDer(WOLFSSL_EC_KEY* key, const unsigned char* derBuf, diff --git a/wolfssl/ssl.h b/wolfssl/ssl.h index 8714786cb3..bd2b9254ef 100644 --- a/wolfssl/ssl.h +++ b/wolfssl/ssl.h @@ -3898,7 +3898,7 @@ WOLFSSL_API WOLFSSL_EVP_PKEY* wolfSSL_d2i_AutoPrivateKey( WOLFSSL_API unsigned long wolfSSL_X509_subject_name_hash(const WOLFSSL_X509* x509); -#endif /* OPENSSL_EXTRA */ +#endif /* OPENSSL_EXTRA || OPENSSL_EXTRA_X509_SMALL */ #ifdef HAVE_PK_CALLBACKS WOLFSSL_API int wolfSSL_IsPrivatePkSet(WOLFSSL* ssl); From 953e7cf18197a4d836aa4d89861f556c82dfe697 Mon Sep 17 00:00:00 2001 From: Ethan Looney Date: Tue, 21 Jul 2020 15:28:17 -0700 Subject: [PATCH 29/60] Changed sz type from int to long --- tests/api.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/api.c b/tests/api.c index e85dad1358..23778d8972 100644 --- a/tests/api.c +++ b/tests/api.c @@ -27190,7 +27190,7 @@ static int test_wc_ERR_print_errors_fp (void) int ret = 0; #if (defined(OPENSSL_EXTRA) || defined(DEBUG_WOLFSSL_VERBOSE)) && \ (!defined(NO_FILESYSTEM) && !defined(NO_STDIO_FILESYSTEM)) - int sz; + long sz; printf(testingFmt, "wc_ERR_print_errors_fp()"); WOLFSSL_ERROR(BAD_FUNC_ARG); //XFILE fp = XFOPEN("./certs/ecc-keyPkcs8.pem", "rb"); From c8e9d058f043a21db3fb8a0e0f4e01e1b49f1afa Mon Sep 17 00:00:00 2001 From: John Safranek Date: Mon, 20 Jul 2020 16:40:20 -0700 Subject: [PATCH 30/60] DTLS Test Speedup Change the example client to use select instead of sleep. If building for the standalone client, it will wait 1 second. If built for no main driver, it'll wait 10ms rather than 1 second. --- examples/client/client.c | 34 +++++++++++++++++++++++++++++++--- tests/api.c | 2 +- 2 files changed, 32 insertions(+), 4 deletions(-) diff --git a/examples/client/client.c b/examples/client/client.c index fcab9d5f2a..a8225f8b58 100644 --- a/examples/client/client.c +++ b/examples/client/client.c @@ -65,6 +65,13 @@ #define OCSP_STAPLINGV2_MULTI 3 #define OCSP_STAPLING_OPT_MAX OCSP_STAPLINGV2_MULTI +#define WXSLEEP(x,y) do { \ + struct timeval tv = {(x),(y)}; \ + select(0, NULL, NULL, NULL, &tv); \ +} while (0) +#define WUSLEEP(x) WXSLEEP(0,x) +#define WSLEEP(x) WXSLEEP(x,0) + /* Note on using port 0: the client standalone example doesn't utilize the * port 0 port sharing; that is used by (1) the server in external control * test mode and (2) the testsuite which uses this code and sets up the correct @@ -3140,7 +3147,14 @@ THREAD_RETURN WOLFSSL_THREAD client_test(void* args) #elif defined(WOLFSSL_TIRTOS) Task_sleep(1); #else - sleep(1); + /* This is to force the server's thread to get a chance to + * execute before continuing the resume in non-blocking + * DTLS test cases. */ +#ifdef NO_MAIN_DRIVER + WUSLEEP(10000); +#else + WSLEEP(1); +#endif #endif #endif /* WOLFSSL_SESSION_EXPORT_DEBUG */ @@ -3245,7 +3259,14 @@ THREAD_RETURN WOLFSSL_THREAD client_test(void* args) #elif defined(WOLFSSL_TIRTOS) Task_sleep(1); #else - sleep(1); + /* This is to force the server's thread to get a chance to + * execute before continuing the resume in non-blocking + * DTLS test cases. */ + #ifdef NO_MAIN_DRIVER + WUSLEEP(10000); + #else + WSLEEP(1); + #endif #endif } tcp_connect(&sockfd, host, port, dtlsUDP, dtlsSCTP, sslResume); @@ -3373,7 +3394,14 @@ THREAD_RETURN WOLFSSL_THREAD client_test(void* args) #elif defined(WOLFSSL_TIRTOS) Task_sleep(1); #else - sleep(1); + /* This is to force the server's thread to get a chance to + * execute before continuing the resume in non-blocking + * DTLS test cases. */ + #ifdef NO_MAIN_DRIVER + WUSLEEP(10000); + #else + WSLEEP(1); + #endif #endif #endif /* WOLFSSL_SESSION_EXPORT_DEBUG */ diff --git a/tests/api.c b/tests/api.c index 454bd91e33..55a2c3be0e 100644 --- a/tests/api.c +++ b/tests/api.c @@ -34432,7 +34432,7 @@ static void test_wolfSSL_ASN1_STRING_print(void){ asnStr = ASN1_STRING_type_new(V_ASN1_OCTET_STRING); ASN1_STRING_set(asnStr,(const void*)unprintableData, - sizeof(unprintableData)); + (int)sizeof(unprintableData)); /* test */ p_len = wolfSSL_ASN1_STRING_print(bio, asnStr); AssertIntEQ(p_len, 46); From 5e515c12fba333a06003876344f0676840b67ed0 Mon Sep 17 00:00:00 2001 From: Ethan Looney Date: Wed, 22 Jul 2020 08:28:43 -0700 Subject: [PATCH 31/60] Removed unneeded comment --- tests/api.c | 27 ++++++++++++--------------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/tests/api.c b/tests/api.c index 23778d8972..f81ffbb463 100644 --- a/tests/api.c +++ b/tests/api.c @@ -27161,7 +27161,6 @@ static int test_WOLFSSL_ERROR_MSG (void) #endif return ret; - }/*End test_WOLFSSL_ERROR_MSG*/ /* * Testing wc_ERR_remove_state @@ -27174,13 +27173,11 @@ static int test_wc_ERR_remove_state (void) printf(testingFmt, "wc_ERR_remove_state()"); wc_ERR_remove_state(); - - printf(resultFmt, ret == 0 ? passed : failed); - -#endif - - return ret; + printf(resultFmt, ret == 0 ? passed : failed); + +#endif + return ret; }/*End test_wc_ERR_remove_state*/ /* * Testing wc_ERR_print_errors_fp @@ -27191,23 +27188,23 @@ static int test_wc_ERR_print_errors_fp (void) #if (defined(OPENSSL_EXTRA) || defined(DEBUG_WOLFSSL_VERBOSE)) && \ (!defined(NO_FILESYSTEM) && !defined(NO_STDIO_FILESYSTEM)) long sz; + printf(testingFmt, "wc_ERR_print_errors_fp()"); + WOLFSSL_ERROR(BAD_FUNC_ARG); - //XFILE fp = XFOPEN("./certs/ecc-keyPkcs8.pem", "rb"); XFILE fp = XFOPEN("./test-log-dump-to-file.txt", "ar"); wc_ERR_print_errors_fp(fp); - + AssertTrue(XFSEEK(fp, 0, XSEEK_END) == 0); sz = XFTELL(fp); if (sz == 0) { ret = BAD_FUNC_ARG; - } - + } + printf(resultFmt, ret == 0 ? passed : failed); XFCLOSE(fp); #endif return ret; - }/*End test_wc_ERR_print_errors_fp*/ /* * Testing wolfSSL_GetLoggingCb @@ -33463,7 +33460,7 @@ static int test_wc_InitRngNonce(void) { int ret=0; #if !defined(WC_NO_RNG) && !defined(HAVE_SELFTEST) && \ - (!defined(HAVE_FIPS) || (defined(HAVE_FIPS_VERSION) && HAVE_FIPS_VERSION >= 2)) + (!defined(HAVE_FIPS) || (defined(HAVE_FIPS_VERSION) && HAVE_FIPS_VERSION >= 2)) WC_RNG rng; byte nonce[] = "\x0D\x74\xDB\x42\xA9\x10\x77\xDE" "\x45\xAC\x13\x7A\xE1\x48\xAF\x16"; @@ -33489,14 +33486,14 @@ static int test_wc_InitRngNonce_ex(void) { int ret=0; #if !defined(WC_NO_RNG) && !defined(HAVE_SELFTEST) && \ - (!defined(HAVE_FIPS) || (defined(HAVE_FIPS_VERSION) && HAVE_FIPS_VERSION >= 2)) + (!defined(HAVE_FIPS) || (defined(HAVE_FIPS_VERSION) && HAVE_FIPS_VERSION >= 2)) WC_RNG rng; byte nonce[] = "\x0D\x74\xDB\x42\xA9\x10\x77\xDE" "\x45\xAC\x13\x7A\xE1\x48\xAF\x16"; word32 nonceSz = sizeof(nonce); printf(testingFmt, "wc_InitRngNonce_ex()"); - + if (ret == 0){ ret = wc_InitRngNonce_ex(&rng, nonce, nonceSz, HEAP_HINT, devId); } From 1af38c5c5590b38e5968a29e8f864f522d781940 Mon Sep 17 00:00:00 2001 From: David Garske Date: Wed, 22 Jul 2020 10:47:35 -0700 Subject: [PATCH 32/60] Fixes for building with `WOLFSSL_ARMASM` when user_settings.h is used. --- .../Benchmark/wolfBench.xcodeproj/project.pbxproj | 12 ++++++++++++ wolfcrypt/src/port/arm/armv8-curve25519.c | 13 +++++++++---- wolfcrypt/src/port/arm/armv8-poly1305.c | 7 +++---- wolfcrypt/src/port/arm/armv8-sha512-asm.c | 12 ++++++++---- 4 files changed, 32 insertions(+), 12 deletions(-) diff --git a/IDE/XCODE/Benchmark/wolfBench.xcodeproj/project.pbxproj b/IDE/XCODE/Benchmark/wolfBench.xcodeproj/project.pbxproj index 9850627f92..61a9b2de81 100644 --- a/IDE/XCODE/Benchmark/wolfBench.xcodeproj/project.pbxproj +++ b/IDE/XCODE/Benchmark/wolfBench.xcodeproj/project.pbxproj @@ -95,6 +95,9 @@ A4ADF9281FCE0C5600A06E90 /* ecc.c in Sources */ = {isa = PBXBuildFile; fileRef = A4ADF8CC1FCE0C5500A06E90 /* ecc.c */; }; A4ADF92A1FCE0C5600A06E90 /* coding.c in Sources */ = {isa = PBXBuildFile; fileRef = A4ADF8CE1FCE0C5500A06E90 /* coding.c */; }; A4ADF92C1FCE0C5600A06E90 /* ge_low_mem.c in Sources */ = {isa = PBXBuildFile; fileRef = A4ADF8D01FCE0C5500A06E90 /* ge_low_mem.c */; }; + A4CA2EA124C8AF97003CCC50 /* armv8-curve25519.c in Sources */ = {isa = PBXBuildFile; fileRef = A4CA2E9C24C8AF97003CCC50 /* armv8-curve25519.c */; }; + A4CA2EA324C8AF97003CCC50 /* armv8-sha512.c in Sources */ = {isa = PBXBuildFile; fileRef = A4CA2E9E24C8AF97003CCC50 /* armv8-sha512.c */; }; + A4CA2EA524C8B273003CCC50 /* armv8-sha512-asm.c in Sources */ = {isa = PBXBuildFile; fileRef = A4CA2EA424C8B273003CCC50 /* armv8-sha512-asm.c */; }; A4DFEC0D1FD4CAA300A7BB33 /* benchmark.c in Sources */ = {isa = PBXBuildFile; fileRef = A4DFEC0C1FD4CAA300A7BB33 /* benchmark.c */; }; A4DFEC101FD4CB8500A7BB33 /* armv8-sha256.c in Sources */ = {isa = PBXBuildFile; fileRef = A4DFEC0E1FD4CB8500A7BB33 /* armv8-sha256.c */; }; A4DFEC111FD4CB8500A7BB33 /* armv8-aes.c in Sources */ = {isa = PBXBuildFile; fileRef = A4DFEC0F1FD4CB8500A7BB33 /* armv8-aes.c */; }; @@ -195,6 +198,9 @@ A4ADF8CC1FCE0C5500A06E90 /* ecc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = ecc.c; path = ../../../wolfcrypt/src/ecc.c; sourceTree = ""; }; A4ADF8CE1FCE0C5500A06E90 /* coding.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = coding.c; path = ../../../wolfcrypt/src/coding.c; sourceTree = ""; }; A4ADF8D01FCE0C5500A06E90 /* ge_low_mem.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = ge_low_mem.c; path = ../../../wolfcrypt/src/ge_low_mem.c; sourceTree = ""; }; + A4CA2E9C24C8AF97003CCC50 /* armv8-curve25519.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = "armv8-curve25519.c"; path = "../../../wolfcrypt/src/port/arm/armv8-curve25519.c"; sourceTree = ""; }; + A4CA2E9E24C8AF97003CCC50 /* armv8-sha512.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = "armv8-sha512.c"; path = "../../../wolfcrypt/src/port/arm/armv8-sha512.c"; sourceTree = ""; }; + A4CA2EA424C8B273003CCC50 /* armv8-sha512-asm.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = "armv8-sha512-asm.c"; path = "../../../wolfcrypt/src/port/arm/armv8-sha512-asm.c"; sourceTree = ""; }; A4DFEC0C1FD4CAA300A7BB33 /* benchmark.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = benchmark.c; path = ../../../wolfcrypt/benchmark/benchmark.c; sourceTree = ""; }; A4DFEC0E1FD4CB8500A7BB33 /* armv8-sha256.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = "armv8-sha256.c"; path = "../../../wolfcrypt/src/port/arm/armv8-sha256.c"; sourceTree = ""; }; A4DFEC0F1FD4CB8500A7BB33 /* armv8-aes.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = "armv8-aes.c"; path = "../../../wolfcrypt/src/port/arm/armv8-aes.c"; sourceTree = ""; }; @@ -273,8 +279,11 @@ A4ADF8921FCE0C4E00A06E90 /* arc4.c */, A4DFEC0F1FD4CB8500A7BB33 /* armv8-aes.c */, A46FE14C2493E8F500A25BE7 /* armv8-chacha.c */, + A4CA2E9C24C8AF97003CCC50 /* armv8-curve25519.c */, A46FE1502493E8F600A25BE7 /* armv8-poly1305.c */, A4DFEC0E1FD4CB8500A7BB33 /* armv8-sha256.c */, + A4CA2EA424C8B273003CCC50 /* armv8-sha512-asm.c */, + A4CA2E9E24C8AF97003CCC50 /* armv8-sha512.c */, A4ADF8A01FCE0C4F00A06E90 /* asm.c */, A4ADF8C21FCE0C5300A06E90 /* asn.c */, A4ADF8B11FCE0C5100A06E90 /* blake2b.c */, @@ -455,6 +464,7 @@ A4ADF8DB1FCE0C5600A06E90 /* hc128.c in Sources */, A4ADF8E31FCE0C5600A06E90 /* compress.c in Sources */, A4ADF8731FCE0C1C00A06E90 /* tls13.c in Sources */, + A4CA2EA124C8AF97003CCC50 /* armv8-curve25519.c in Sources */, A4ADF90D1FCE0C5600A06E90 /* blake2b.c in Sources */, A4ADF9071FCE0C5600A06E90 /* dh.c in Sources */, A46FE1912493E8F800A25BE7 /* sp_c32.c in Sources */, @@ -473,6 +483,7 @@ A4ADF8D51FCE0C5600A06E90 /* md5.c in Sources */, A46FE1892493E8F800A25BE7 /* sp_dsp32.c in Sources */, A4ADF8DF1FCE0C5600A06E90 /* sha256.c in Sources */, + A4CA2EA524C8B273003CCC50 /* armv8-sha512-asm.c in Sources */, A4ADF8711FCE0C1C00A06E90 /* sniffer.c in Sources */, A46FE1882493E8F800A25BE7 /* sp_arm32.c in Sources */, A4ADF8701FCE0C1C00A06E90 /* tls.c in Sources */, @@ -522,6 +533,7 @@ A4ADF8D71FCE0C5600A06E90 /* wolfevent.c in Sources */, A46FE1802493E8F800A25BE7 /* ed448.c in Sources */, A4DFEC0D1FD4CAA300A7BB33 /* benchmark.c in Sources */, + A4CA2EA324C8AF97003CCC50 /* armv8-sha512.c in Sources */, A4ADF91D1FCE0C5600A06E90 /* cpuid.c in Sources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/wolfcrypt/src/port/arm/armv8-curve25519.c b/wolfcrypt/src/port/arm/armv8-curve25519.c index b84a9d1902..2695ec1cae 100644 --- a/wolfcrypt/src/port/arm/armv8-curve25519.c +++ b/wolfcrypt/src/port/arm/armv8-curve25519.c @@ -23,15 +23,20 @@ * cd ../scripts * ruby ./x25519/x25519.rb arm64 ../wolfssl/wolfcrypt/src/port/arm/armv8-curve25519.c */ -#ifdef WOLFSSL_ARMASM -#ifdef __aarch64__ -#include + #ifdef HAVE_CONFIG_H #include -#endif /* HAVE_CONFIG_H */ +#endif + #include + +#ifdef WOLFSSL_ARMASM +#ifdef __aarch64__ + +#include #include + void fe_init() { __asm__ __volatile__ ( diff --git a/wolfcrypt/src/port/arm/armv8-poly1305.c b/wolfcrypt/src/port/arm/armv8-poly1305.c index 3df07f701a..2f2dd8c834 100644 --- a/wolfcrypt/src/port/arm/armv8-poly1305.c +++ b/wolfcrypt/src/port/arm/armv8-poly1305.c @@ -24,9 +24,6 @@ * and Daniel J. Bernstein */ - -#ifdef __aarch64__ - #ifdef HAVE_CONFIG_H #include #endif @@ -34,6 +31,8 @@ #include #ifdef WOLFSSL_ARMASM +#ifdef __aarch64__ + #ifdef HAVE_POLY1305 #include #include @@ -1162,5 +1161,5 @@ int wc_Poly1305Final(Poly1305* ctx, byte* mac) } #endif /* HAVE_POLY1305 */ -#endif /* WOLFSSL_ARMASM */ #endif /* __aarch64__ */ +#endif /* WOLFSSL_ARMASM */ diff --git a/wolfcrypt/src/port/arm/armv8-sha512-asm.c b/wolfcrypt/src/port/arm/armv8-sha512-asm.c index 1ecfa3ebbb..94568dc379 100644 --- a/wolfcrypt/src/port/arm/armv8-sha512-asm.c +++ b/wolfcrypt/src/port/arm/armv8-sha512-asm.c @@ -23,13 +23,17 @@ * cd ../scripts * ruby ./sha2/sha512.rb arm64 ../wolfssl/wolfcrypt/src/port/arm/armv8-sha512-asm.c */ -#ifdef WOLFSSL_ARMASM -#ifdef __aarch64__ -#include + #ifdef HAVE_CONFIG_H #include -#endif /* HAVE_CONFIG_H */ +#endif + #include + +#ifdef WOLFSSL_ARMASM +#ifdef __aarch64__ + +#include #include static const uint64_t L_SHA512_transform_neon_len_k[] = { From 39271e92348cbf267a87297cc3eae9649198e1c9 Mon Sep 17 00:00:00 2001 From: Eric Blankenhorn Date: Wed, 22 Jul 2020 14:08:57 -0500 Subject: [PATCH 33/60] Fix build issue with OPENSSL_EXTRA_X509_SMALL --- src/ssl.c | 66 ++++++++++++++++++++++++++++++------------------------- 1 file changed, 36 insertions(+), 30 deletions(-) diff --git a/src/ssl.c b/src/ssl.c index 2a2ab77865..48d3d48a10 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -17388,6 +17388,34 @@ WOLFSSL_X509* wolfSSL_X509_d2i(WOLFSSL_X509** x509, const byte* in, int len) return newX509; } + +int wolfSSL_X509_get_isCA(WOLFSSL_X509* x509) +{ + int isCA = 0; + + WOLFSSL_ENTER("wolfSSL_X509_get_isCA"); + + if (x509 != NULL) + isCA = x509->isCa; + + WOLFSSL_LEAVE("wolfSSL_X509_get_isCA", isCA); + + return isCA; +} + +/* returns the number of entries in the WOLFSSL_X509_NAME */ +int wolfSSL_X509_NAME_entry_count(WOLFSSL_X509_NAME* name) +{ + int count = 0; + + WOLFSSL_ENTER("wolfSSL_X509_NAME_entry_count"); + + if (name != NULL) + count = name->entrySz; + + WOLFSSL_LEAVE("wolfSSL_X509_NAME_entry_count", count); + return count; +} #endif /* KEEP_PEER_CERT || SESSION_CERTS || OPENSSL_EXTRA || OPENSSL_EXTRA_X509_SMALL */ @@ -17416,20 +17444,6 @@ WOLFSSL_X509* wolfSSL_X509_d2i(WOLFSSL_X509** x509, const byte* in, int len) return ret; } - int wolfSSL_X509_get_isCA(WOLFSSL_X509* x509) - { - int isCA = 0; - - WOLFSSL_ENTER("wolfSSL_X509_get_isCA"); - - if (x509 != NULL) - isCA = x509->isCa; - - WOLFSSL_LEAVE("wolfSSL_X509_get_isCA", isCA); - - return isCA; - } - int wolfSSL_X509_get_signature(WOLFSSL_X509* x509, unsigned char* buf, int* bufSz) { @@ -20264,21 +20278,6 @@ int wolfSSL_X509_cmp(const WOLFSSL_X509 *a, const WOLFSSL_X509 *b) return id; } - - - /* returns the number of entries in the WOLFSSL_X509_NAME */ - int wolfSSL_X509_NAME_entry_count(WOLFSSL_X509_NAME* name) - { - int count = 0; - - WOLFSSL_ENTER("wolfSSL_X509_NAME_entry_count"); - - if (name != NULL) - count = name->entrySz; - - WOLFSSL_LEAVE("wolfSSL_X509_NAME_entry_count", count); - return count; - } #endif /* !NO_CERTS && OPENSSL_EXTRA */ #if defined(OPENSSL_EXTRA) || defined(WOLFSSL_WPAS_SMALL) || \ @@ -36748,9 +36747,16 @@ static int CopyX509NameToCertName(WOLFSSL_X509_NAME* n, CertName* cName) int hashType; int sigType = WOLFSSL_FAILURE; + #if !defined(NO_PWDBASED) /* Convert key type and hash algorithm to a signature algorithm */ - if (wolfSSL_EVP_get_hashinfo(md, &hashType, NULL) == WOLFSSL_FAILURE) + if (wolfSSL_EVP_get_hashinfo(md, &hashType, NULL) == WOLFSSL_FAILURE) { return WOLFSSL_FAILURE; + } + #else + (void)md; + WOLFSSL_MSG("Cannot get hashinfo when NO_PWDBASED is defined"); + return WOLFSSL_FAILURE; + #endif /* !defined(NO_PWDBASED) */ if (pkey->type == EVP_PKEY_RSA) { From 3a2be130431b69fbdbf5361f41f0541718283dfb Mon Sep 17 00:00:00 2001 From: David Garske Date: Wed, 22 Jul 2020 12:52:53 -0700 Subject: [PATCH 34/60] Remove execute bit on file. --- IDE/WIN/user_settings.h | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 IDE/WIN/user_settings.h diff --git a/IDE/WIN/user_settings.h b/IDE/WIN/user_settings.h old mode 100755 new mode 100644 From fe08f23a50767efff70680d8fb7699e31e06c43e Mon Sep 17 00:00:00 2001 From: David Garske Date: Wed, 22 Jul 2020 13:08:57 -0700 Subject: [PATCH 35/60] Improved test sleep. Cleanup `sleep` calls. --- examples/benchmark/tls_bench.c | 4 +-- examples/client/client.c | 59 +++++++--------------------------- wolfssl/test.h | 16 +++++++-- 3 files changed, 27 insertions(+), 52 deletions(-) diff --git a/examples/benchmark/tls_bench.c b/examples/benchmark/tls_bench.c index be11be362d..f130f28d14 100644 --- a/examples/benchmark/tls_bench.c +++ b/examples/benchmark/tls_bench.c @@ -1285,7 +1285,7 @@ static int bench_tls_server(info_t* info) ret = SocketWaitClient(info); #ifdef BENCH_USE_NONBLOCK if (ret == -2) { - sleep(0); + XSLEEP_MS(0); continue; } #endif @@ -1831,7 +1831,7 @@ int bench_tls(void* args) info = &theadInfo[i]; if (!info->to_client.done || !info->to_server.done) { doShutdown = 0; - sleep(1); /* Allow other threads to run */ + XSLEEP_MS(1000); /* Allow other threads to run */ } } diff --git a/examples/client/client.c b/examples/client/client.c index a8225f8b58..8266159969 100644 --- a/examples/client/client.c +++ b/examples/client/client.c @@ -65,12 +65,14 @@ #define OCSP_STAPLINGV2_MULTI 3 #define OCSP_STAPLING_OPT_MAX OCSP_STAPLINGV2_MULTI -#define WXSLEEP(x,y) do { \ - struct timeval tv = {(x),(y)}; \ - select(0, NULL, NULL, NULL, &tv); \ -} while (0) -#define WUSLEEP(x) WXSLEEP(0,x) -#define WSLEEP(x) WXSLEEP(x,0) +#if defined(XUSLEEP) && defined(NO_MAIN_DRIVER) + /* This is to force the server's thread to get a chance to + * execute before continuing the resume in non-blocking + * DTLS test cases. */ + #define TEST_DELAY() XSLEEP_US(10000) +#else + #define TEST_DELAY() XSLEEP_MS(1000) +#endif /* Note on using port 0: the client standalone example doesn't utilize the * port 0 port sharing; that is used by (1) the server in external control @@ -3142,20 +3144,7 @@ THREAD_RETURN WOLFSSL_THREAD client_test(void* args) /* allow some time for exporting the session */ #ifdef WOLFSSL_SESSION_EXPORT_DEBUG -#ifdef USE_WINDOWS_API - Sleep(500); -#elif defined(WOLFSSL_TIRTOS) - Task_sleep(1); -#else - /* This is to force the server's thread to get a chance to - * execute before continuing the resume in non-blocking - * DTLS test cases. */ -#ifdef NO_MAIN_DRIVER - WUSLEEP(10000); -#else - WSLEEP(1); -#endif -#endif + TEST_DELAY(); #endif /* WOLFSSL_SESSION_EXPORT_DEBUG */ #ifdef WOLFSSL_TLS13 @@ -3254,20 +3243,7 @@ THREAD_RETURN WOLFSSL_THREAD client_test(void* args) #endif if (dtlsUDP) { -#ifdef USE_WINDOWS_API - Sleep(500); -#elif defined(WOLFSSL_TIRTOS) - Task_sleep(1); -#else - /* This is to force the server's thread to get a chance to - * execute before continuing the resume in non-blocking - * DTLS test cases. */ - #ifdef NO_MAIN_DRIVER - WUSLEEP(10000); - #else - WSLEEP(1); - #endif -#endif + TEST_DELAY(); } tcp_connect(&sockfd, host, port, dtlsUDP, dtlsSCTP, sslResume); if (wolfSSL_set_fd(sslResume, sockfd) != WOLFSSL_SUCCESS) { @@ -3389,20 +3365,7 @@ THREAD_RETURN WOLFSSL_THREAD client_test(void* args) /* allow some time for exporting the session */ #ifdef WOLFSSL_SESSION_EXPORT_DEBUG - #ifdef USE_WINDOWS_API - Sleep(500); - #elif defined(WOLFSSL_TIRTOS) - Task_sleep(1); - #else - /* This is to force the server's thread to get a chance to - * execute before continuing the resume in non-blocking - * DTLS test cases. */ - #ifdef NO_MAIN_DRIVER - WUSLEEP(10000); - #else - WSLEEP(1); - #endif - #endif + TEST_DELAY(); #endif /* WOLFSSL_SESSION_EXPORT_DEBUG */ #ifdef HAVE_SECURE_RENEGOTIATION diff --git a/wolfssl/test.h b/wolfssl/test.h index 385a3be211..3c2f4ada9e 100644 --- a/wolfssl/test.h +++ b/wolfssl/test.h @@ -55,6 +55,7 @@ #endif #define SOCKET_T SOCKET #define SNPRINTF _snprintf + #define XSLEEP_MS(t) Sleep(t) #elif defined(WOLFSSL_MDK_ARM) || defined(WOLFSSL_KEIL_TCP_NET) #include #include "rl_net.h" @@ -69,9 +70,9 @@ return(ret) ; } #if defined(HAVE_KEIL_RTX) - #define sleep(t) os_dly_wait(t/1000+1); + #define XSLEEP_MS(t) os_dly_wait(t) #elif defined(WOLFSSL_CMSIS_RTOS) || defined(WOLFSSL_CMSIS_RTOSv2) - #define sleep(t) osDelay(t/1000+1); + #define XSLEEP_MS(t) osDelay(t) #endif #elif defined(WOLFSSL_TIRTOS) #include @@ -88,6 +89,7 @@ char **h_addr_list; /* list of addresses from name server */ }; #define SOCKET_T int + #define XSLEEP_MS(t) Task_sleep(t/1000) #elif defined(WOLFSSL_VXWORKS) #include #include @@ -148,8 +150,18 @@ #include /* ignore SIGPIPE */ #endif #define SNPRINTF snprintf + + #define XSELECT_WAIT(x,y) do { \ + struct timeval tv = {(x),(y)}; \ + select(0, NULL, NULL, NULL, &tv); \ + } while (0) + #define XSLEEP_US(u) XSELECT_WAIT(0,u) #endif /* USE_WINDOWS_API */ +#ifndef XSLEEP_MS + #define XSLEEP_MS(t) sleep(t/1000) +#endif + #ifdef WOLFSSL_ASYNC_CRYPT #include #endif From 98ae3a2352dd42e4c40f518fcbbbdda6c6c55e94 Mon Sep 17 00:00:00 2001 From: John Safranek Date: Wed, 22 Jul 2020 13:20:23 -0700 Subject: [PATCH 36/60] Added a suite test use case to cover the new error check. Also fixed and issue with passing a couple flags to the test case runner, and some other changes to support the new test. --- examples/client/client.c | 22 ++++++++++++++++++---- examples/server/server.c | 18 ++++++++++++++++-- tests/include.am | 1 + tests/suites.c | 17 ++++++++++++++++- tests/test-dtls-fails.conf | 16 ++++++++++++++++ tests/test-fails.conf | 9 ++++++++- 6 files changed, 75 insertions(+), 8 deletions(-) create mode 100644 tests/test-dtls-fails.conf diff --git a/examples/client/client.c b/examples/client/client.c index fcab9d5f2a..c87429b779 100644 --- a/examples/client/client.c +++ b/examples/client/client.c @@ -486,7 +486,7 @@ static int ClientBenchmarkConnections(WOLFSSL_CTX* ctx, char* host, word16 port, /* Measures throughput in kbps. Throughput = number of bytes */ static int ClientBenchmarkThroughput(WOLFSSL_CTX* ctx, char* host, word16 port, int dtlsUDP, int dtlsSCTP, int block, size_t throughput, int useX25519, - int useX448) + int useX448, int exitWithRet) { double start, conn_time = 0, tx_time = 0, rx_time = 0; SOCKET_T sockfd; @@ -591,7 +591,10 @@ static int ClientBenchmarkThroughput(WOLFSSL_CTX* ctx, char* host, word16 port, } while (err == WC_PENDING_E); if (ret != len) { printf("SSL_write bench error %d!\n", err); - err_sys("SSL_write failed"); + if (!exitWithRet) + err_sys("SSL_write failed"); + ret = err; + goto doExit; } tx_time += current_time(0) - start; @@ -645,6 +648,7 @@ static int ClientBenchmarkThroughput(WOLFSSL_CTX* ctx, char* host, word16 port, else { err_sys("Client buffer malloc failed"); } +doExit: if(tx_buffer) XFREE(tx_buffer, NULL, DYNAMIC_TYPE_TMP_BUFFER); if(rx_buffer) XFREE(rx_buffer, NULL, DYNAMIC_TYPE_TMP_BUFFER); } @@ -656,6 +660,9 @@ static int ClientBenchmarkThroughput(WOLFSSL_CTX* ctx, char* host, word16 port, wolfSSL_free(ssl); ssl = NULL; CloseSocket(sockfd); + if (exitWithRet) + return err; + #if !defined(__MINGW32__) printf("wolfSSL Client Benchmark %zu bytes\n" #else @@ -1595,6 +1602,9 @@ THREAD_RETURN WOLFSSL_THREAD client_test(void* args) StackTrap(); + /* Reinitialize the global myVerifyAction. */ + myVerifyAction = VERIFY_OVERRIDE_ERROR; + #ifndef WOLFSSL_VXWORKS /* Not used: All used */ while ((ch = mygetopt(argc, argv, "?:" @@ -2613,9 +2623,13 @@ THREAD_RETURN WOLFSSL_THREAD client_test(void* args) if (throughput) { ((func_args*)args)->return_code = ClientBenchmarkThroughput(ctx, host, port, dtlsUDP, dtlsSCTP, - block, throughput, useX25519, useX448); + block, throughput, useX25519, useX448, + exitWithRet); wolfSSL_CTX_free(ctx); ctx = NULL; - XEXIT_T(EXIT_SUCCESS); + if (!exitWithRet) + XEXIT_T(EXIT_SUCCESS); + else + goto exit; } #if defined(WOLFSSL_MDK_ARM) diff --git a/examples/server/server.c b/examples/server/server.c index c575f2f882..5394c16814 100644 --- a/examples/server/server.c +++ b/examples/server/server.c @@ -381,6 +381,8 @@ int ServerEchoData(SSL* ssl, int clientfd, int echoData, int block, err_sys_ex(runWithErrors, "SSL_read failed"); break; } + if (err == WOLFSSL_ERROR_ZERO_RETURN) + return WOLFSSL_ERROR_ZERO_RETURN; } else { rx_pos += ret; @@ -438,7 +440,7 @@ int ServerEchoData(SSL* ssl, int clientfd, int echoData, int block, ); } - return EXIT_SUCCESS; + return 0; } static void ServerRead(WOLFSSL* ssl, char* input, int inputLen) @@ -1097,6 +1099,10 @@ THREAD_RETURN WOLFSSL_THREAD server_test(void* args) #ifdef WOLFSSL_VXWORKS useAnyAddr = 1; #else + + /* Reinitialize the global myVerifyAction. */ + myVerifyAction = VERIFY_OVERRIDE_ERROR; + /* Not Used: h, z, F, T, V, W, X */ while ((ch = mygetopt(argc, argv, "?:" "abc:defgijk:l:mnop:q:rstuv:wxy" @@ -2446,7 +2452,15 @@ THREAD_RETURN WOLFSSL_THREAD server_test(void* args) #endif } else if (err == 0 || err == WOLFSSL_ERROR_ZERO_RETURN) { - ServerEchoData(ssl, clientfd, echoData, block, throughput); + err = ServerEchoData(ssl, clientfd, echoData, block, throughput); + if (err != 0) { + SSL_free(ssl); ssl = NULL; + SSL_CTX_free(ctx); ctx = NULL; + CloseSocket(clientfd); + CloseSocket(sockfd); + ((func_args*)args)->return_code = err; + goto exit; + } } #if defined(WOLFSSL_MDK_SHELL) && defined(HAVE_MDK_RTX) diff --git a/tests/include.am b/tests/include.am index 07230abf34..1ef0a7cdf5 100644 --- a/tests/include.am +++ b/tests/include.am @@ -31,6 +31,7 @@ EXTRA_DIST += tests/test.conf \ tests/test-psk-no-id.conf \ tests/test-psk-no-id-sha2.conf \ tests/test-dtls.conf \ + tests/test-dtls-fails.conf \ tests/test-dtls-group.conf \ tests/test-dtls-reneg-client.conf \ tests/test-dtls-reneg-server.conf \ diff --git a/tests/suites.c b/tests/suites.c index d4e4107af6..72ae8fddf3 100644 --- a/tests/suites.c +++ b/tests/suites.c @@ -455,6 +455,7 @@ static int execute_test_case(int svr_argc, char** svr_argv, return NOT_BUILT_IN; } printf("trying client command line[%d]: %s\n", tests, commandLine); + tests++; /* determine based on args if this test is expected to fail */ if (XSTRSTR(commandLine, exitWithRetFlag) != NULL) { @@ -881,6 +882,20 @@ int SuiteTest(int argc, char** argv) goto exit; } #endif +#ifndef WOLFSSL_NO_DTLS_SIZE_CHECK + /* failure tests */ + args.argc = 3; + strcpy(argv0[1], "tests/test-dtls-fails.conf"); + strcpy(argv0[2], "expFail"); /* tests are expected to fail */ + printf("starting dtls tests that expect failure\n"); + test_harness(&args); + if (args.return_code != 0) { + printf("error from script %d\n", args.return_code); + args.return_code = EXIT_FAILURE; + goto exit; + } + strcpy(argv0[2], ""); +#endif #endif #ifdef WOLFSSL_SCTP /* add dtls-sctp extra suites */ @@ -1038,7 +1053,7 @@ int SuiteTest(int argc, char** argv) args.argc = 3; strcpy(argv0[1], "tests/test-dhprime.conf"); strcpy(argv0[2], "doDH"); /* add DH prime flag */ - printf("starting tests that expect failure\n"); + printf("starting dh prime tests\n"); test_harness(&args); if (args.return_code != 0) { printf("error from script %d\n", args.return_code); diff --git a/tests/test-dtls-fails.conf b/tests/test-dtls-fails.conf new file mode 100644 index 0000000000..07492f2f7b --- /dev/null +++ b/tests/test-dtls-fails.conf @@ -0,0 +1,16 @@ +# DTLS test +# server DTLSv1.2 too big test +-v 3 +-l ECDHE-ECDSA-AES128-SHA256 +-c ./certs/server-ecc.pem +-k ./certs/ecc-key.pem +-u +-B 9000 + +# client DTLSv1.2 too big test +-v 3 +-l ECDHE-ECDSA-AES128-SHA256 +-A ./certs/ca-ecc-cert.pem +-u +-B 9000 + diff --git a/tests/test-fails.conf b/tests/test-fails.conf index d1dd444175..40afb54e0f 100644 --- a/tests/test-fails.conf +++ b/tests/test-fails.conf @@ -114,6 +114,7 @@ # server -v 3 -l ECDHE-RSA-AES128-GCM-SHA256 +-H verifyFail # client verify should fail -v 3 @@ -128,10 +129,12 @@ # client -v 3 -l ECDHE-RSA-AES128-GCM-SHA256 +-H verifyFail # server -v 3 -l ECDHE-ECDSA-AES128-GCM-SHA256 +-H verifyFail # client verify should fail -v 3 @@ -146,6 +149,7 @@ # client -v 3 -l ECDHE-ECDSA-AES128-GCM-SHA256 +-H verifyFail # error going into callback, return error # server @@ -153,6 +157,7 @@ -l ECDHE-RSA-AES128-GCM-SHA256 -c ./certs/test/server-cert-rsa-badsig.pem -k ./certs/server-key.pem +-H verifyFail # client verify should fail -v 3 @@ -164,6 +169,7 @@ -l ECDHE-ECDSA-AES128-GCM-SHA256 -c ./certs/test/server-cert-ecc-badsig.pem -k ./certs/ecc-key.pem +-H verifyFail # client verify should fail -v 3 @@ -173,10 +179,12 @@ # server send alert on no mutual authentication -v 3 -F +-H verifyFail # client send alert on no mutual authentication -v 3 -x +-H verifyFail # server TLSv1.3 fail on no client certificate # server always sets WOLFSSL_VERIFY_FAIL_IF_NO_PEER_CERT unless using -d @@ -187,4 +195,3 @@ -v 4 -l TLS13-AES128-GCM-SHA256 -x - From 9b421ce497277f95aee47e0ba409315aacb8586e Mon Sep 17 00:00:00 2001 From: Eric Blankenhorn Date: Wed, 22 Jul 2020 17:22:46 -0500 Subject: [PATCH 37/60] Fix for config failure --- src/ssl.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/ssl.c b/src/ssl.c index 48d3d48a10..47e5ddc8a0 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -17402,7 +17402,10 @@ int wolfSSL_X509_get_isCA(WOLFSSL_X509* x509) return isCA; } +#endif /* KEEP_PEER_CERT || SESSION_CERTS || OPENSSL_EXTRA || + OPENSSL_EXTRA_X509_SMALL */ +#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) /* returns the number of entries in the WOLFSSL_X509_NAME */ int wolfSSL_X509_NAME_entry_count(WOLFSSL_X509_NAME* name) { @@ -17416,8 +17419,7 @@ int wolfSSL_X509_NAME_entry_count(WOLFSSL_X509_NAME* name) WOLFSSL_LEAVE("wolfSSL_X509_NAME_entry_count", count); return count; } -#endif /* KEEP_PEER_CERT || SESSION_CERTS || OPENSSL_EXTRA || - OPENSSL_EXTRA_X509_SMALL */ +#endif /* OPENSSL_EXTRA || OPENSSL_EXTRA_X509_SMALL */ From f7e4c1c8ad76e2dd076a1195d6b6120dcc52df38 Mon Sep 17 00:00:00 2001 From: Ethan Looney Date: Wed, 22 Jul 2020 15:44:13 -0700 Subject: [PATCH 38/60] Added SetLoggingCb check --- tests/api.c | 34 ++++++++++++++++++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) diff --git a/tests/api.c b/tests/api.c index f81ffbb463..3664e615f1 100644 --- a/tests/api.c +++ b/tests/api.c @@ -27206,17 +27206,47 @@ static int test_wc_ERR_print_errors_fp (void) #endif return ret; }/*End test_wc_ERR_print_errors_fp*/ +#ifdef DEBUG_WOLFSSL +static void Logging_cb(const int logLevel, const char *const logMessage) +{ + (void)logLevel; + (void)logMessage; +} +#endif /* * Testing wolfSSL_GetLoggingCb */ static int test_wolfSSL_GetLoggingCb (void) { int ret = 0; +#ifdef DEBUG_WOLFSSL printf(testingFmt, "wolfSSL_GetLoggingCb()"); - wolfSSL_GetLoggingCb(); - + /*Testing without wolfSSL_SetLoggingCb()*/ + if (ret == 0) { + if(wolfSSL_GetLoggingCb() == NULL){ /*Should be true*/ + ret = 0; + } + if(wolfSSL_GetLoggingCb() != NULL){ /*Should not be true*/ + ret = -1; + } + } + /*Testing with wolfSSL_SetLoggingCb()*/ + if (ret == 0) { + ret = wolfSSL_SetLoggingCb(Logging_cb); + if (ret == 0){ + if(wolfSSL_GetLoggingCb() == NULL){ /*Should not be true*/ + ret = -1; + } + if (ret == 0) { + if(wolfSSL_GetLoggingCb() == Logging_cb){ /*Should be true*/ + ret = 0; + } + } + } + } printf(resultFmt, ret == 0 ? passed : failed); +#endif return ret; }/*End test_wolfSSL_GetLoggingCb*/ static void test_wolfSSL_HMAC(void) From 568fc8f5bdc045e12d5a60968e992c8a9f21dbb6 Mon Sep 17 00:00:00 2001 From: Sean Parkinson Date: Thu, 23 Jul 2020 18:08:37 +1000 Subject: [PATCH 39/60] Fixes for compiling for ARM64 iOS Fix bug in ChaCha20 assembly code (was writing one byte too many). Fix the assembly code to have APPLE format. Change Poly1305 inline assembly as requested by compiler. Initialize variables that will be set anyway - compiler complaint. Change to use the assembly code files for Curve25519 and SHA-512. Ed25519 not suported with ARM assembly. --- .../wolfBench.xcodeproj/project.pbxproj | 32 +- IDE/XCODE/user_settings.h | 4 +- wolfcrypt/src/port/arm/armv8-chacha.c | 16 +- wolfcrypt/src/port/arm/armv8-curve25519.S | 749 +++++++++++++++--- wolfcrypt/src/port/arm/armv8-curve25519.c | 351 +++++++- wolfcrypt/src/port/arm/armv8-poly1305.c | 10 +- wolfcrypt/src/port/arm/armv8-sha512-asm.S | 57 +- wolfcrypt/src/port/arm/armv8-sha512-asm.c | 29 +- wolfcrypt/src/sp_arm32.c | 96 +-- wolfcrypt/src/sp_arm64.c | 96 +-- wolfcrypt/src/sp_armthumb.c | 96 +-- wolfcrypt/src/sp_c32.c | 126 +-- wolfcrypt/src/sp_c64.c | 126 +-- wolfcrypt/src/sp_cortexm.c | 96 +-- 14 files changed, 1414 insertions(+), 470 deletions(-) diff --git a/IDE/XCODE/Benchmark/wolfBench.xcodeproj/project.pbxproj b/IDE/XCODE/Benchmark/wolfBench.xcodeproj/project.pbxproj index 61a9b2de81..46767b6a35 100644 --- a/IDE/XCODE/Benchmark/wolfBench.xcodeproj/project.pbxproj +++ b/IDE/XCODE/Benchmark/wolfBench.xcodeproj/project.pbxproj @@ -10,7 +10,6 @@ 52114C8721B5A7320022ADA1 /* sp_c64.c in Sources */ = {isa = PBXBuildFile; fileRef = 52114C8621B5A7320022ADA1 /* sp_c64.c */; }; A46FE16F2493E8F800A25BE7 /* armv8-chacha.c in Sources */ = {isa = PBXBuildFile; fileRef = A46FE14C2493E8F500A25BE7 /* armv8-chacha.c */; }; A46FE1702493E8F800A25BE7 /* sp_int.c in Sources */ = {isa = PBXBuildFile; fileRef = A46FE14D2493E8F600A25BE7 /* sp_int.c */; }; - A46FE1732493E8F800A25BE7 /* armv8-poly1305.c in Sources */ = {isa = PBXBuildFile; fileRef = A46FE1502493E8F600A25BE7 /* armv8-poly1305.c */; }; A46FE1742493E8F800A25BE7 /* sp_cortexm.c in Sources */ = {isa = PBXBuildFile; fileRef = A46FE1512493E8F600A25BE7 /* sp_cortexm.c */; }; A46FE1752493E8F800A25BE7 /* blake2s.c in Sources */ = {isa = PBXBuildFile; fileRef = A46FE1522493E8F600A25BE7 /* blake2s.c */; }; A46FE1772493E8F800A25BE7 /* wc_pkcs11.c in Sources */ = {isa = PBXBuildFile; fileRef = A46FE1542493E8F600A25BE7 /* wc_pkcs11.c */; }; @@ -95,20 +94,20 @@ A4ADF9281FCE0C5600A06E90 /* ecc.c in Sources */ = {isa = PBXBuildFile; fileRef = A4ADF8CC1FCE0C5500A06E90 /* ecc.c */; }; A4ADF92A1FCE0C5600A06E90 /* coding.c in Sources */ = {isa = PBXBuildFile; fileRef = A4ADF8CE1FCE0C5500A06E90 /* coding.c */; }; A4ADF92C1FCE0C5600A06E90 /* ge_low_mem.c in Sources */ = {isa = PBXBuildFile; fileRef = A4ADF8D01FCE0C5500A06E90 /* ge_low_mem.c */; }; - A4CA2EA124C8AF97003CCC50 /* armv8-curve25519.c in Sources */ = {isa = PBXBuildFile; fileRef = A4CA2E9C24C8AF97003CCC50 /* armv8-curve25519.c */; }; A4CA2EA324C8AF97003CCC50 /* armv8-sha512.c in Sources */ = {isa = PBXBuildFile; fileRef = A4CA2E9E24C8AF97003CCC50 /* armv8-sha512.c */; }; - A4CA2EA524C8B273003CCC50 /* armv8-sha512-asm.c in Sources */ = {isa = PBXBuildFile; fileRef = A4CA2EA424C8B273003CCC50 /* armv8-sha512-asm.c */; }; A4DFEC0D1FD4CAA300A7BB33 /* benchmark.c in Sources */ = {isa = PBXBuildFile; fileRef = A4DFEC0C1FD4CAA300A7BB33 /* benchmark.c */; }; A4DFEC101FD4CB8500A7BB33 /* armv8-sha256.c in Sources */ = {isa = PBXBuildFile; fileRef = A4DFEC0E1FD4CB8500A7BB33 /* armv8-sha256.c */; }; A4DFEC111FD4CB8500A7BB33 /* armv8-aes.c in Sources */ = {isa = PBXBuildFile; fileRef = A4DFEC0F1FD4CB8500A7BB33 /* armv8-aes.c */; }; A4DFEC3C1FD6B9CC00A7BB33 /* test.c in Sources */ = {isa = PBXBuildFile; fileRef = A4DFEC3B1FD6B9CC00A7BB33 /* test.c */; }; + CB81DE1D24C9284700B98DA6 /* armv8-poly1305.c in Sources */ = {isa = PBXBuildFile; fileRef = CB81DE1C24C9284700B98DA6 /* armv8-poly1305.c */; }; + CB81DE1F24C93EC000B98DA6 /* armv8-curve25519.S in Sources */ = {isa = PBXBuildFile; fileRef = CB81DE1E24C93EC000B98DA6 /* armv8-curve25519.S */; }; + CB81DE2324C93FB300B98DA6 /* armv8-sha512-asm.S in Sources */ = {isa = PBXBuildFile; fileRef = CB81DE2224C93FB300B98DA6 /* armv8-sha512-asm.S */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ 52114C8621B5A7320022ADA1 /* sp_c64.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = sp_c64.c; path = ../../../wolfcrypt/src/sp_c64.c; sourceTree = ""; }; A46FE14C2493E8F500A25BE7 /* armv8-chacha.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = "armv8-chacha.c"; path = "../../../wolfcrypt/src/port/arm/armv8-chacha.c"; sourceTree = ""; }; A46FE14D2493E8F600A25BE7 /* sp_int.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = sp_int.c; path = ../../../wolfcrypt/src/sp_int.c; sourceTree = ""; }; - A46FE1502493E8F600A25BE7 /* armv8-poly1305.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = "armv8-poly1305.c"; path = "../../../wolfcrypt/src/port/arm/armv8-poly1305.c"; sourceTree = ""; }; A46FE1512493E8F600A25BE7 /* sp_cortexm.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = sp_cortexm.c; path = ../../../wolfcrypt/src/sp_cortexm.c; sourceTree = ""; }; A46FE1522493E8F600A25BE7 /* blake2s.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = blake2s.c; path = ../../../wolfcrypt/src/blake2s.c; sourceTree = ""; }; A46FE1542493E8F600A25BE7 /* wc_pkcs11.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = wc_pkcs11.c; path = ../../../wolfcrypt/src/wc_pkcs11.c; sourceTree = ""; }; @@ -198,13 +197,14 @@ A4ADF8CC1FCE0C5500A06E90 /* ecc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = ecc.c; path = ../../../wolfcrypt/src/ecc.c; sourceTree = ""; }; A4ADF8CE1FCE0C5500A06E90 /* coding.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = coding.c; path = ../../../wolfcrypt/src/coding.c; sourceTree = ""; }; A4ADF8D01FCE0C5500A06E90 /* ge_low_mem.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = ge_low_mem.c; path = ../../../wolfcrypt/src/ge_low_mem.c; sourceTree = ""; }; - A4CA2E9C24C8AF97003CCC50 /* armv8-curve25519.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = "armv8-curve25519.c"; path = "../../../wolfcrypt/src/port/arm/armv8-curve25519.c"; sourceTree = ""; }; A4CA2E9E24C8AF97003CCC50 /* armv8-sha512.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = "armv8-sha512.c"; path = "../../../wolfcrypt/src/port/arm/armv8-sha512.c"; sourceTree = ""; }; - A4CA2EA424C8B273003CCC50 /* armv8-sha512-asm.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = "armv8-sha512-asm.c"; path = "../../../wolfcrypt/src/port/arm/armv8-sha512-asm.c"; sourceTree = ""; }; A4DFEC0C1FD4CAA300A7BB33 /* benchmark.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = benchmark.c; path = ../../../wolfcrypt/benchmark/benchmark.c; sourceTree = ""; }; A4DFEC0E1FD4CB8500A7BB33 /* armv8-sha256.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = "armv8-sha256.c"; path = "../../../wolfcrypt/src/port/arm/armv8-sha256.c"; sourceTree = ""; }; A4DFEC0F1FD4CB8500A7BB33 /* armv8-aes.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = "armv8-aes.c"; path = "../../../wolfcrypt/src/port/arm/armv8-aes.c"; sourceTree = ""; }; A4DFEC3B1FD6B9CC00A7BB33 /* test.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = test.c; path = ../../../wolfcrypt/test/test.c; sourceTree = ""; }; + CB81DE1C24C9284700B98DA6 /* armv8-poly1305.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = "armv8-poly1305.c"; path = "../../../wolfcrypt/src/port/arm/armv8-poly1305.c"; sourceTree = ""; }; + CB81DE1E24C93EC000B98DA6 /* armv8-curve25519.S */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; name = "armv8-curve25519.S"; path = "../../../wolfcrypt/src/port/arm/armv8-curve25519.S"; sourceTree = ""; }; + CB81DE2224C93FB300B98DA6 /* armv8-sha512-asm.S */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; name = "armv8-sha512-asm.S"; path = "../../../wolfcrypt/src/port/arm/armv8-sha512-asm.S"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -279,11 +279,11 @@ A4ADF8921FCE0C4E00A06E90 /* arc4.c */, A4DFEC0F1FD4CB8500A7BB33 /* armv8-aes.c */, A46FE14C2493E8F500A25BE7 /* armv8-chacha.c */, - A4CA2E9C24C8AF97003CCC50 /* armv8-curve25519.c */, - A46FE1502493E8F600A25BE7 /* armv8-poly1305.c */, + CB81DE1E24C93EC000B98DA6 /* armv8-curve25519.S */, + CB81DE1C24C9284700B98DA6 /* armv8-poly1305.c */, A4DFEC0E1FD4CB8500A7BB33 /* armv8-sha256.c */, - A4CA2EA424C8B273003CCC50 /* armv8-sha512-asm.c */, A4CA2E9E24C8AF97003CCC50 /* armv8-sha512.c */, + CB81DE2224C93FB300B98DA6 /* armv8-sha512-asm.S */, A4ADF8A01FCE0C4F00A06E90 /* asm.c */, A4ADF8C21FCE0C5300A06E90 /* asn.c */, A4ADF8B11FCE0C5100A06E90 /* blake2b.c */, @@ -443,6 +443,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + CB81DE2324C93FB300B98DA6 /* armv8-sha512-asm.S in Sources */, A4ADF9041FCE0C5600A06E90 /* des3.c in Sources */, A46FE18A2493E8F800A25BE7 /* ge_448.c in Sources */, A4ADF9121FCE0C5600A06E90 /* wc_port.c in Sources */, @@ -464,10 +465,11 @@ A4ADF8DB1FCE0C5600A06E90 /* hc128.c in Sources */, A4ADF8E31FCE0C5600A06E90 /* compress.c in Sources */, A4ADF8731FCE0C1C00A06E90 /* tls13.c in Sources */, - A4CA2EA124C8AF97003CCC50 /* armv8-curve25519.c in Sources */, A4ADF90D1FCE0C5600A06E90 /* blake2b.c in Sources */, A4ADF9071FCE0C5600A06E90 /* dh.c in Sources */, A46FE1912493E8F800A25BE7 /* sp_c32.c in Sources */, + CB81DE1D24C9284700B98DA6 /* armv8-poly1305.c in Sources */, + CB81DE1F24C93EC000B98DA6 /* armv8-curve25519.S in Sources */, A4ADF8F31FCE0C5600A06E90 /* rsa.c in Sources */, A46FE1752493E8F800A25BE7 /* blake2s.c in Sources */, A4ADF8FA1FCE0C5600A06E90 /* pkcs12.c in Sources */, @@ -483,7 +485,6 @@ A4ADF8D51FCE0C5600A06E90 /* md5.c in Sources */, A46FE1892493E8F800A25BE7 /* sp_dsp32.c in Sources */, A4ADF8DF1FCE0C5600A06E90 /* sha256.c in Sources */, - A4CA2EA524C8B273003CCC50 /* armv8-sha512-asm.c in Sources */, A4ADF8711FCE0C1C00A06E90 /* sniffer.c in Sources */, A46FE1882493E8F800A25BE7 /* sp_arm32.c in Sources */, A4ADF8701FCE0C1C00A06E90 /* tls.c in Sources */, @@ -509,7 +510,6 @@ A4ADF9051FCE0C5600A06E90 /* cmac.c in Sources */, 52114C8721B5A7320022ADA1 /* sp_c64.c in Sources */, A4ADF8F41FCE0C5600A06E90 /* pkcs7.c in Sources */, - A46FE1732493E8F800A25BE7 /* armv8-poly1305.c in Sources */, A4ADF90B1FCE0C5600A06E90 /* logging.c in Sources */, A4ADF8E01FCE0C5600A06E90 /* ecc_fp.c in Sources */, A4ADF8EB1FCE0C5600A06E90 /* chacha20_poly1305.c in Sources */, @@ -683,10 +683,10 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_STYLE = Automatic; - DEVELOPMENT_TEAM = 2S2PAGNS5B; + DEVELOPMENT_TEAM = TJKX238PPD; INFOPLIST_FILE = wolfBench/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = com.wolfSSL.wolfBench; + PRODUCT_BUNDLE_IDENTIFIER = "com.wolfSSL.wolfBench-ios"; PRODUCT_NAME = "$(TARGET_NAME)"; TARGETED_DEVICE_FAMILY = "1,2"; }; @@ -697,10 +697,10 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_STYLE = Automatic; - DEVELOPMENT_TEAM = 2S2PAGNS5B; + DEVELOPMENT_TEAM = TJKX238PPD; INFOPLIST_FILE = wolfBench/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = com.wolfSSL.wolfBench; + PRODUCT_BUNDLE_IDENTIFIER = "com.wolfSSL.wolfBench-ios"; PRODUCT_NAME = "$(TARGET_NAME)"; TARGETED_DEVICE_FAMILY = "1,2"; }; diff --git a/IDE/XCODE/user_settings.h b/IDE/XCODE/user_settings.h index 62da56ba32..53d8ebe113 100644 --- a/IDE/XCODE/user_settings.h +++ b/IDE/XCODE/user_settings.h @@ -56,7 +56,9 @@ #define HAVE_CHACHA #define HAVE_CURVE25519 - #define HAVE_ED25519 + #ifndef WOLFSSL_ARMASM + #define HAVE_ED25519 + #endif /* TLS extensions */ #define HAVE_ONE_TIME_AUTH diff --git a/wolfcrypt/src/port/arm/armv8-chacha.c b/wolfcrypt/src/port/arm/armv8-chacha.c index df76bece0b..93387cd819 100644 --- a/wolfcrypt/src/port/arm/armv8-chacha.c +++ b/wolfcrypt/src/port/arm/armv8-chacha.c @@ -2186,17 +2186,15 @@ static WC_INLINE void wc_Chacha_encrypt_64(const word32* input, const byte* m, "BEQ L_chacha20_arm64_64_done_%= \n\t" "\n" "L_chacha20_arm64_64_lt_8_%=: \n\t" - "MOV x4, v0.D[0] \n\t" - "LSL x5, %[bytes], #3 \n\t" + "MOV x4, v0.D[0] \n\t" "\n" "L_chacha20_arm64_64_loop_lt_8_%=: \n\t" - "LDRB w6, [%[m], %[bytes]] \n\t" - "ROR x7, x4, x5 \n\t" - "EOR w6, w6, w7 \n\t" - "STRB w6, [%[c], %[bytes]] \n\t" - "SUBS %[bytes], %[bytes], #1 \n\t" - "SUB x5, x5, #8 \n\t" - "BGE L_chacha20_arm64_64_loop_lt_8_%= \n\t" + "LDRB w6, [%[m]], #1 \n\t" + "EOR w6, w6, w4 \n\t" + "STRB w6, [%[c]], #1 \n\t" + "SUBS %[bytes], %[bytes], #1 \n\t" + "LSR x4, x4, #8 \n\t" + "BGT L_chacha20_arm64_64_loop_lt_8_%= \n\t" "\n" "L_chacha20_arm64_64_done_%=: \n\t" : [input] "+r" (input), [m] "+r" (m), [c] "+r" (c), [bytes] "+r" (bytes64) diff --git a/wolfcrypt/src/port/arm/armv8-curve25519.S b/wolfcrypt/src/port/arm/armv8-curve25519.S index 36be60de56..e8da5267ff 100644 --- a/wolfcrypt/src/port/arm/armv8-curve25519.S +++ b/wolfcrypt/src/port/arm/armv8-curve25519.S @@ -19,36 +19,66 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA */ +#ifdef HAVE_CONFIG_H + #include +#endif /* HAVE_CONFIG_H */ +#include + /* Generated using (from wolfssl): * cd ../scripts * ruby ./x25519/x25519.rb arm64 ../wolfssl/wolfcrypt/src/port/arm/armv8-curve25519.S */ #ifdef WOLFSSL_ARMASM #ifdef __aarch64__ - .text - .align 2 - .globl fe_init - .type fe_init, %function +#ifndef __APPLE__ +.text +.globl fe_init +.type fe_init,@function +.align 2 fe_init: +#else +.section __TEXT,__text +.globl _fe_init +.p2align 2 +_fe_init: +#endif /* __APPLE__ */ ret +#ifndef __APPLE__ .size fe_init,.-fe_init - .text - .align 2 - .globl fe_frombytes - .type fe_frombytes, %function +#endif /* __APPLE__ */ +#ifndef __APPLE__ +.text +.globl fe_frombytes +.type fe_frombytes,@function +.align 2 fe_frombytes: +#else +.section __TEXT,__text +.globl _fe_frombytes +.p2align 2 +_fe_frombytes: +#endif /* __APPLE__ */ ldp x2, x3, [x1] ldp x4, x5, [x1, #16] and x5, x5, #0x7fffffffffffffff stp x2, x3, [x0] stp x4, x5, [x0, #16] ret +#ifndef __APPLE__ .size fe_frombytes,.-fe_frombytes - .text - .align 2 - .globl fe_tobytes - .type fe_tobytes, %function +#endif /* __APPLE__ */ +#ifndef __APPLE__ +.text +.globl fe_tobytes +.type fe_tobytes,@function +.align 2 fe_tobytes: +#else +.section __TEXT,__text +.globl _fe_tobytes +.p2align 2 +_fe_tobytes: +#endif /* __APPLE__ */ mov x7, #19 ldp x2, x3, [x1] ldp x4, x5, [x1, #16] @@ -65,45 +95,81 @@ fe_tobytes: stp x2, x3, [x0] stp x4, x5, [x0, #16] ret +#ifndef __APPLE__ .size fe_tobytes,.-fe_tobytes - .text - .align 2 - .globl fe_1 - .type fe_1, %function +#endif /* __APPLE__ */ +#ifndef __APPLE__ +.text +.globl fe_1 +.type fe_1,@function +.align 2 fe_1: +#else +.section __TEXT,__text +.globl _fe_1 +.p2align 2 +_fe_1: +#endif /* __APPLE__ */ # Set one mov x1, #1 stp x1, xzr, [x0] stp xzr, xzr, [x0, #16] ret +#ifndef __APPLE__ .size fe_1,.-fe_1 - .text - .align 2 - .globl fe_0 - .type fe_0, %function +#endif /* __APPLE__ */ +#ifndef __APPLE__ +.text +.globl fe_0 +.type fe_0,@function +.align 2 fe_0: +#else +.section __TEXT,__text +.globl _fe_0 +.p2align 2 +_fe_0: +#endif /* __APPLE__ */ # Set zero stp xzr, xzr, [x0] stp xzr, xzr, [x0, #16] ret +#ifndef __APPLE__ .size fe_0,.-fe_0 - .text - .align 2 - .globl fe_copy - .type fe_copy, %function +#endif /* __APPLE__ */ +#ifndef __APPLE__ +.text +.globl fe_copy +.type fe_copy,@function +.align 2 fe_copy: +#else +.section __TEXT,__text +.globl _fe_copy +.p2align 2 +_fe_copy: +#endif /* __APPLE__ */ # Copy ldp x2, x3, [x1] ldp x4, x5, [x1, #16] stp x2, x3, [x0] stp x4, x5, [x0, #16] ret +#ifndef __APPLE__ .size fe_copy,.-fe_copy - .text - .align 2 - .globl fe_sub - .type fe_sub, %function +#endif /* __APPLE__ */ +#ifndef __APPLE__ +.text +.globl fe_sub +.type fe_sub,@function +.align 2 fe_sub: +#else +.section __TEXT,__text +.globl _fe_sub +.p2align 2 +_fe_sub: +#endif /* __APPLE__ */ # Sub ldp x3, x4, [x1] ldp x5, x6, [x1, #16] @@ -126,12 +192,21 @@ fe_sub: stp x3, x4, [x0] stp x5, x6, [x0, #16] ret +#ifndef __APPLE__ .size fe_sub,.-fe_sub - .text - .align 2 - .globl fe_add - .type fe_add, %function +#endif /* __APPLE__ */ +#ifndef __APPLE__ +.text +.globl fe_add +.type fe_add,@function +.align 2 fe_add: +#else +.section __TEXT,__text +.globl _fe_add +.p2align 2 +_fe_add: +#endif /* __APPLE__ */ # Add ldp x3, x4, [x1] ldp x5, x6, [x1, #16] @@ -154,12 +229,21 @@ fe_add: stp x3, x4, [x0] stp x5, x6, [x0, #16] ret +#ifndef __APPLE__ .size fe_add,.-fe_add - .text - .align 2 - .globl fe_neg - .type fe_neg, %function +#endif /* __APPLE__ */ +#ifndef __APPLE__ +.text +.globl fe_neg +.type fe_neg,@function +.align 2 fe_neg: +#else +.section __TEXT,__text +.globl _fe_neg +.p2align 2 +_fe_neg: +#endif /* __APPLE__ */ ldp x2, x3, [x1] ldp x4, x5, [x1, #16] mov x6, #-19 @@ -173,12 +257,21 @@ fe_neg: stp x6, x7, [x0] stp x8, x9, [x0, #16] ret +#ifndef __APPLE__ .size fe_neg,.-fe_neg - .text - .align 2 - .globl fe_isnonzero - .type fe_isnonzero, %function +#endif /* __APPLE__ */ +#ifndef __APPLE__ +.text +.globl fe_isnonzero +.type fe_isnonzero,@function +.align 2 fe_isnonzero: +#else +.section __TEXT,__text +.globl _fe_isnonzero +.p2align 2 +_fe_isnonzero: +#endif /* __APPLE__ */ mov x6, #19 ldp x1, x2, [x0] ldp x3, x4, [x0, #16] @@ -196,12 +289,21 @@ fe_isnonzero: orr x3, x3, x4 orr x0, x0, x3 ret +#ifndef __APPLE__ .size fe_isnonzero,.-fe_isnonzero - .text - .align 2 - .globl fe_isnegative - .type fe_isnegative, %function +#endif /* __APPLE__ */ +#ifndef __APPLE__ +.text +.globl fe_isnegative +.type fe_isnegative,@function +.align 2 fe_isnegative: +#else +.section __TEXT,__text +.globl _fe_isnegative +.p2align 2 +_fe_isnegative: +#endif /* __APPLE__ */ mov x6, #19 ldp x1, x2, [x0] ldp x3, x4, [x0, #16] @@ -212,12 +314,21 @@ fe_isnegative: and x0, x1, #1 eor x0, x0, x5, lsr 63 ret +#ifndef __APPLE__ .size fe_isnegative,.-fe_isnegative - .text - .align 2 - .globl fe_cmov_table - .type fe_cmov_table, %function +#endif /* __APPLE__ */ +#ifndef __APPLE__ +.text +.globl fe_cmov_table +.type fe_cmov_table,@function +.align 2 fe_cmov_table: +#else +.section __TEXT,__text +.globl _fe_cmov_table +.p2align 2 +_fe_cmov_table: +#endif /* __APPLE__ */ stp x29, x30, [sp, #-128]! add x29, sp, #0 str x17, [x29, #40] @@ -438,12 +549,21 @@ fe_cmov_table: ldr x28, [x29, #120] ldp x29, x30, [sp], #0x80 ret +#ifndef __APPLE__ .size fe_cmov_table,.-fe_cmov_table - .text - .align 2 - .globl fe_mul - .type fe_mul, %function +#endif /* __APPLE__ */ +#ifndef __APPLE__ +.text +.globl fe_mul +.type fe_mul,@function +.align 2 fe_mul: +#else +.section __TEXT,__text +.globl _fe_mul +.p2align 2 +_fe_mul: +#endif /* __APPLE__ */ stp x29, x30, [sp, #-64]! add x29, sp, #0 str x17, [x29, #24] @@ -596,12 +716,21 @@ fe_mul: ldr x22, [x29, #56] ldp x29, x30, [sp], #0x40 ret +#ifndef __APPLE__ .size fe_mul,.-fe_mul - .text - .align 2 - .globl fe_sq - .type fe_sq, %function +#endif /* __APPLE__ */ +#ifndef __APPLE__ +.text +.globl fe_sq +.type fe_sq,@function +.align 2 fe_sq: +#else +.section __TEXT,__text +.globl _fe_sq +.p2align 2 +_fe_sq: +#endif /* __APPLE__ */ # Square ldp x13, x14, [x1] ldp x15, x16, [x1, #16] @@ -709,12 +838,21 @@ fe_sq: stp x5, x6, [x0] stp x7, x8, [x0, #16] ret +#ifndef __APPLE__ .size fe_sq,.-fe_sq - .text - .align 2 - .globl fe_invert - .type fe_invert, %function +#endif /* __APPLE__ */ +#ifndef __APPLE__ +.text +.globl fe_invert +.type fe_invert,@function +.align 2 fe_invert: +#else +.section __TEXT,__text +.globl _fe_invert +.p2align 2 +_fe_invert: +#endif /* __APPLE__ */ stp x29, x30, [sp, #-176]! add x29, sp, #0 str x20, [x29, #168] @@ -722,124 +860,245 @@ fe_invert: str x0, [x29, #144] str x1, [x29, #152] add x0, x29, #16 +#ifndef __APPLE__ bl fe_sq +#else + bl _fe_sq +#endif /* __APPLE__ */ add x0, x29, #48 add x1, x29, #16 +#ifndef __APPLE__ bl fe_sq +#else + bl _fe_sq +#endif /* __APPLE__ */ add x1, x29, #48 +#ifndef __APPLE__ bl fe_sq +#else + bl _fe_sq +#endif /* __APPLE__ */ ldr x1, [x29, #152] add x2, x29, #48 +#ifndef __APPLE__ bl fe_mul +#else + bl _fe_mul +#endif /* __APPLE__ */ add x0, x29, #16 add x1, x29, #16 add x2, x29, #48 +#ifndef __APPLE__ bl fe_mul +#else + bl _fe_mul +#endif /* __APPLE__ */ add x0, x29, #0x50 +#ifndef __APPLE__ bl fe_sq +#else + bl _fe_sq +#endif /* __APPLE__ */ add x0, x29, #48 add x1, x29, #48 add x2, x29, #0x50 +#ifndef __APPLE__ bl fe_mul +#else + bl _fe_mul +#endif /* __APPLE__ */ add x0, x29, #0x50 +#ifndef __APPLE__ bl fe_sq +#else + bl _fe_sq +#endif /* __APPLE__ */ mov x20, #4 add x1, x29, #0x50 L_fe_invert1: +#ifndef __APPLE__ bl fe_sq +#else + bl _fe_sq +#endif /* __APPLE__ */ sub x20, x20, #1 cmp x20, #0 bne L_fe_invert1 add x0, x29, #48 add x2, x29, #48 +#ifndef __APPLE__ bl fe_mul +#else + bl _fe_mul +#endif /* __APPLE__ */ add x0, x29, #0x50 add x1, x29, #48 +#ifndef __APPLE__ bl fe_sq +#else + bl _fe_sq +#endif /* __APPLE__ */ mov x20, #9 add x1, x29, #0x50 L_fe_invert2: +#ifndef __APPLE__ bl fe_sq +#else + bl _fe_sq +#endif /* __APPLE__ */ sub x20, x20, #1 cmp x20, #0 bne L_fe_invert2 add x2, x29, #48 +#ifndef __APPLE__ bl fe_mul +#else + bl _fe_mul +#endif /* __APPLE__ */ add x0, x29, #0x70 +#ifndef __APPLE__ bl fe_sq +#else + bl _fe_sq +#endif /* __APPLE__ */ mov x20, #19 add x1, x29, #0x70 L_fe_invert3: +#ifndef __APPLE__ bl fe_sq +#else + bl _fe_sq +#endif /* __APPLE__ */ sub x20, x20, #1 cmp x20, #0 bne L_fe_invert3 add x0, x29, #0x50 add x2, x29, #0x50 +#ifndef __APPLE__ bl fe_mul +#else + bl _fe_mul +#endif /* __APPLE__ */ mov x20, #10 add x1, x29, #0x50 L_fe_invert4: +#ifndef __APPLE__ bl fe_sq +#else + bl _fe_sq +#endif /* __APPLE__ */ sub x20, x20, #1 cmp x20, #0 bne L_fe_invert4 add x0, x29, #48 add x2, x29, #48 +#ifndef __APPLE__ bl fe_mul +#else + bl _fe_mul +#endif /* __APPLE__ */ add x0, x29, #0x50 add x1, x29, #48 +#ifndef __APPLE__ bl fe_sq +#else + bl _fe_sq +#endif /* __APPLE__ */ mov x20, #49 add x1, x29, #0x50 L_fe_invert5: +#ifndef __APPLE__ bl fe_sq +#else + bl _fe_sq +#endif /* __APPLE__ */ sub x20, x20, #1 cmp x20, #0 bne L_fe_invert5 add x2, x29, #48 +#ifndef __APPLE__ bl fe_mul +#else + bl _fe_mul +#endif /* __APPLE__ */ add x0, x29, #0x70 +#ifndef __APPLE__ bl fe_sq +#else + bl _fe_sq +#endif /* __APPLE__ */ mov x20, #0x63 add x1, x29, #0x70 L_fe_invert6: +#ifndef __APPLE__ bl fe_sq +#else + bl _fe_sq +#endif /* __APPLE__ */ sub x20, x20, #1 cmp x20, #0 bne L_fe_invert6 add x0, x29, #0x50 add x2, x29, #0x50 +#ifndef __APPLE__ bl fe_mul +#else + bl _fe_mul +#endif /* __APPLE__ */ mov x20, #50 add x1, x29, #0x50 L_fe_invert7: +#ifndef __APPLE__ bl fe_sq +#else + bl _fe_sq +#endif /* __APPLE__ */ sub x20, x20, #1 cmp x20, #0 bne L_fe_invert7 add x0, x29, #48 add x2, x29, #48 +#ifndef __APPLE__ bl fe_mul +#else + bl _fe_mul +#endif /* __APPLE__ */ mov x20, #5 add x1, x29, #48 L_fe_invert8: +#ifndef __APPLE__ bl fe_sq +#else + bl _fe_sq +#endif /* __APPLE__ */ sub x20, x20, #1 cmp x20, #0 bne L_fe_invert8 ldr x0, [x29, #144] add x2, x29, #16 +#ifndef __APPLE__ bl fe_mul +#else + bl _fe_mul +#endif /* __APPLE__ */ ldr x20, [x29, #168] ldp x29, x30, [sp], #0xb0 ret +#ifndef __APPLE__ .size fe_invert,.-fe_invert - .text - .align 2 - .globl curve25519 - .type curve25519, %function +#endif /* __APPLE__ */ +#ifndef __APPLE__ +.text +.globl curve25519 +.type curve25519,@function +.align 2 curve25519: +#else +.section __TEXT,__text +.globl _curve25519 +.p2align 2 +_curve25519: +#endif /* __APPLE__ */ stp x29, x30, [sp, #-288]! add x29, sp, #0 str x17, [x29, #200] @@ -2157,115 +2416,227 @@ L_curve25519_bits: # Invert add x0, x29, #48 add x1, x29, #16 +#ifndef __APPLE__ bl fe_sq +#else + bl _fe_sq +#endif /* __APPLE__ */ add x0, x29, #0x50 add x1, x29, #48 +#ifndef __APPLE__ bl fe_sq +#else + bl _fe_sq +#endif /* __APPLE__ */ add x1, x29, #0x50 +#ifndef __APPLE__ bl fe_sq +#else + bl _fe_sq +#endif /* __APPLE__ */ add x1, x29, #16 add x2, x29, #0x50 +#ifndef __APPLE__ bl fe_mul +#else + bl _fe_mul +#endif /* __APPLE__ */ add x0, x29, #48 add x1, x29, #48 add x2, x29, #0x50 +#ifndef __APPLE__ bl fe_mul +#else + bl _fe_mul +#endif /* __APPLE__ */ add x0, x29, #0x70 +#ifndef __APPLE__ bl fe_sq +#else + bl _fe_sq +#endif /* __APPLE__ */ add x0, x29, #0x50 add x1, x29, #0x50 add x2, x29, #0x70 +#ifndef __APPLE__ bl fe_mul +#else + bl _fe_mul +#endif /* __APPLE__ */ add x0, x29, #0x70 +#ifndef __APPLE__ bl fe_sq +#else + bl _fe_sq +#endif /* __APPLE__ */ mov x24, #4 add x1, x29, #0x70 L_curve25519_inv_1: +#ifndef __APPLE__ bl fe_sq +#else + bl _fe_sq +#endif /* __APPLE__ */ sub x24, x24, #1 cmp x24, #0 bne L_curve25519_inv_1 add x0, x29, #0x50 add x2, x29, #0x50 +#ifndef __APPLE__ bl fe_mul +#else + bl _fe_mul +#endif /* __APPLE__ */ add x0, x29, #0x70 add x1, x29, #0x50 +#ifndef __APPLE__ bl fe_sq +#else + bl _fe_sq +#endif /* __APPLE__ */ mov x24, #9 add x1, x29, #0x70 L_curve25519_inv_2: +#ifndef __APPLE__ bl fe_sq +#else + bl _fe_sq +#endif /* __APPLE__ */ sub x24, x24, #1 cmp x24, #0 bne L_curve25519_inv_2 add x2, x29, #0x50 +#ifndef __APPLE__ bl fe_mul +#else + bl _fe_mul +#endif /* __APPLE__ */ add x0, x29, #0x90 +#ifndef __APPLE__ bl fe_sq +#else + bl _fe_sq +#endif /* __APPLE__ */ mov x24, #19 add x1, x29, #0x90 L_curve25519_inv_3: +#ifndef __APPLE__ bl fe_sq +#else + bl _fe_sq +#endif /* __APPLE__ */ sub x24, x24, #1 cmp x24, #0 bne L_curve25519_inv_3 add x0, x29, #0x70 add x2, x29, #0x70 +#ifndef __APPLE__ bl fe_mul +#else + bl _fe_mul +#endif /* __APPLE__ */ mov x24, #10 add x1, x29, #0x70 L_curve25519_inv_4: +#ifndef __APPLE__ bl fe_sq +#else + bl _fe_sq +#endif /* __APPLE__ */ sub x24, x24, #1 cmp x24, #0 bne L_curve25519_inv_4 add x0, x29, #0x50 add x2, x29, #0x50 +#ifndef __APPLE__ bl fe_mul +#else + bl _fe_mul +#endif /* __APPLE__ */ add x0, x29, #0x70 add x1, x29, #0x50 +#ifndef __APPLE__ bl fe_sq +#else + bl _fe_sq +#endif /* __APPLE__ */ mov x24, #49 add x1, x29, #0x70 L_curve25519_inv_5: +#ifndef __APPLE__ bl fe_sq +#else + bl _fe_sq +#endif /* __APPLE__ */ sub x24, x24, #1 cmp x24, #0 bne L_curve25519_inv_5 add x2, x29, #0x50 +#ifndef __APPLE__ bl fe_mul +#else + bl _fe_mul +#endif /* __APPLE__ */ add x0, x29, #0x90 +#ifndef __APPLE__ bl fe_sq +#else + bl _fe_sq +#endif /* __APPLE__ */ mov x24, #0x63 add x1, x29, #0x90 L_curve25519_inv_6: +#ifndef __APPLE__ bl fe_sq +#else + bl _fe_sq +#endif /* __APPLE__ */ sub x24, x24, #1 cmp x24, #0 bne L_curve25519_inv_6 add x0, x29, #0x70 add x2, x29, #0x70 +#ifndef __APPLE__ bl fe_mul +#else + bl _fe_mul +#endif /* __APPLE__ */ mov x24, #50 add x1, x29, #0x70 L_curve25519_inv_7: +#ifndef __APPLE__ bl fe_sq +#else + bl _fe_sq +#endif /* __APPLE__ */ sub x24, x24, #1 cmp x24, #0 bne L_curve25519_inv_7 add x0, x29, #0x50 add x2, x29, #0x50 +#ifndef __APPLE__ bl fe_mul +#else + bl _fe_mul +#endif /* __APPLE__ */ mov x24, #5 add x1, x29, #0x50 L_curve25519_inv_8: +#ifndef __APPLE__ bl fe_sq +#else + bl _fe_sq +#endif /* __APPLE__ */ sub x24, x24, #1 cmp x24, #0 bne L_curve25519_inv_8 add x0, x29, #16 add x2, x29, #48 +#ifndef __APPLE__ bl fe_mul +#else + bl _fe_mul +#endif /* __APPLE__ */ ldr x0, [x29, #176] # Multiply ldp x6, x7, [x0] @@ -2417,12 +2788,21 @@ L_curve25519_inv_8: ldr x28, [x29, #280] ldp x29, x30, [sp], #0x120 ret +#ifndef __APPLE__ .size curve25519,.-curve25519 - .text - .align 2 - .globl fe_pow22523 - .type fe_pow22523, %function +#endif /* __APPLE__ */ +#ifndef __APPLE__ +.text +.globl fe_pow22523 +.type fe_pow22523,@function +.align 2 fe_pow22523: +#else +.section __TEXT,__text +.globl _fe_pow22523 +.p2align 2 +_fe_pow22523: +#endif /* __APPLE__ */ stp x29, x30, [sp, #-144]! add x29, sp, #0 str x21, [x29, #136] @@ -2430,123 +2810,244 @@ fe_pow22523: str x0, [x29, #112] str x1, [x29, #120] add x0, x29, #16 +#ifndef __APPLE__ bl fe_sq +#else + bl _fe_sq +#endif /* __APPLE__ */ add x0, x29, #48 add x1, x29, #16 +#ifndef __APPLE__ bl fe_sq +#else + bl _fe_sq +#endif /* __APPLE__ */ add x1, x29, #48 +#ifndef __APPLE__ bl fe_sq +#else + bl _fe_sq +#endif /* __APPLE__ */ ldr x1, [x29, #120] add x2, x29, #48 +#ifndef __APPLE__ bl fe_mul +#else + bl _fe_mul +#endif /* __APPLE__ */ add x0, x29, #16 add x1, x29, #16 add x2, x29, #48 +#ifndef __APPLE__ bl fe_mul +#else + bl _fe_mul +#endif /* __APPLE__ */ +#ifndef __APPLE__ bl fe_sq +#else + bl _fe_sq +#endif /* __APPLE__ */ add x1, x29, #48 add x2, x29, #16 +#ifndef __APPLE__ bl fe_mul +#else + bl _fe_mul +#endif /* __APPLE__ */ add x0, x29, #48 add x1, x29, #16 +#ifndef __APPLE__ bl fe_sq +#else + bl _fe_sq +#endif /* __APPLE__ */ mov x21, #4 add x1, x29, #48 L_fe_pow22523_1: +#ifndef __APPLE__ bl fe_sq +#else + bl _fe_sq +#endif /* __APPLE__ */ sub x21, x21, #1 cmp x21, #0 bne L_fe_pow22523_1 add x0, x29, #16 add x2, x29, #16 +#ifndef __APPLE__ bl fe_mul +#else + bl _fe_mul +#endif /* __APPLE__ */ add x0, x29, #48 add x1, x29, #16 +#ifndef __APPLE__ bl fe_sq +#else + bl _fe_sq +#endif /* __APPLE__ */ mov x21, #9 add x1, x29, #48 L_fe_pow22523_2: +#ifndef __APPLE__ bl fe_sq +#else + bl _fe_sq +#endif /* __APPLE__ */ sub x21, x21, #1 cmp x21, #0 bne L_fe_pow22523_2 add x2, x29, #16 +#ifndef __APPLE__ bl fe_mul +#else + bl _fe_mul +#endif /* __APPLE__ */ add x0, x29, #0x50 +#ifndef __APPLE__ bl fe_sq +#else + bl _fe_sq +#endif /* __APPLE__ */ mov x21, #19 add x1, x29, #0x50 L_fe_pow22523_3: +#ifndef __APPLE__ bl fe_sq +#else + bl _fe_sq +#endif /* __APPLE__ */ sub x21, x21, #1 cmp x21, #0 bne L_fe_pow22523_3 add x0, x29, #48 add x2, x29, #48 +#ifndef __APPLE__ bl fe_mul +#else + bl _fe_mul +#endif /* __APPLE__ */ mov x21, #10 add x1, x29, #48 L_fe_pow22523_4: +#ifndef __APPLE__ bl fe_sq +#else + bl _fe_sq +#endif /* __APPLE__ */ sub x21, x21, #1 cmp x21, #0 bne L_fe_pow22523_4 add x0, x29, #16 add x2, x29, #16 +#ifndef __APPLE__ bl fe_mul +#else + bl _fe_mul +#endif /* __APPLE__ */ add x0, x29, #48 add x1, x29, #16 +#ifndef __APPLE__ bl fe_sq +#else + bl _fe_sq +#endif /* __APPLE__ */ mov x21, #49 add x1, x29, #48 L_fe_pow22523_5: +#ifndef __APPLE__ bl fe_sq +#else + bl _fe_sq +#endif /* __APPLE__ */ sub x21, x21, #1 cmp x21, #0 bne L_fe_pow22523_5 add x2, x29, #16 +#ifndef __APPLE__ bl fe_mul +#else + bl _fe_mul +#endif /* __APPLE__ */ add x0, x29, #0x50 +#ifndef __APPLE__ bl fe_sq +#else + bl _fe_sq +#endif /* __APPLE__ */ mov x21, #0x63 add x1, x29, #0x50 L_fe_pow22523_6: +#ifndef __APPLE__ bl fe_sq +#else + bl _fe_sq +#endif /* __APPLE__ */ sub x21, x21, #1 cmp x21, #0 bne L_fe_pow22523_6 add x0, x29, #48 add x2, x29, #48 +#ifndef __APPLE__ bl fe_mul +#else + bl _fe_mul +#endif /* __APPLE__ */ mov x21, #50 add x1, x29, #48 L_fe_pow22523_7: +#ifndef __APPLE__ bl fe_sq +#else + bl _fe_sq +#endif /* __APPLE__ */ sub x21, x21, #1 cmp x21, #0 bne L_fe_pow22523_7 add x0, x29, #16 add x2, x29, #16 +#ifndef __APPLE__ bl fe_mul +#else + bl _fe_mul +#endif /* __APPLE__ */ mov x21, #2 add x1, x29, #16 L_fe_pow22523_8: +#ifndef __APPLE__ bl fe_sq +#else + bl _fe_sq +#endif /* __APPLE__ */ sub x21, x21, #1 cmp x21, #0 bne L_fe_pow22523_8 ldr x0, [x29, #112] ldr x2, [x29, #120] +#ifndef __APPLE__ bl fe_mul +#else + bl _fe_mul +#endif /* __APPLE__ */ ldr x21, [x29, #136] ldp x29, x30, [sp], #0x90 ret +#ifndef __APPLE__ .size fe_pow22523,.-fe_pow22523 - .text - .align 2 - .globl fe_ge_to_p2 - .type fe_ge_to_p2, %function +#endif /* __APPLE__ */ +#ifndef __APPLE__ +.text +.globl fe_ge_to_p2 +.type fe_ge_to_p2,@function +.align 2 fe_ge_to_p2: +#else +.section __TEXT,__text +.globl _fe_ge_to_p2 +.p2align 2 +_fe_ge_to_p2: +#endif /* __APPLE__ */ stp x29, x30, [sp, #-112]! add x29, sp, #0 str x17, [x29, #72] @@ -2990,12 +3491,21 @@ fe_ge_to_p2: ldr x22, [x29, #104] ldp x29, x30, [sp], #0x70 ret +#ifndef __APPLE__ .size fe_ge_to_p2,.-fe_ge_to_p2 - .text - .align 2 - .globl fe_ge_to_p3 - .type fe_ge_to_p3, %function +#endif /* __APPLE__ */ +#ifndef __APPLE__ +.text +.globl fe_ge_to_p3 +.type fe_ge_to_p3,@function +.align 2 fe_ge_to_p3: +#else +.section __TEXT,__text +.globl _fe_ge_to_p3 +.p2align 2 +_fe_ge_to_p3: +#endif /* __APPLE__ */ stp x29, x30, [sp, #-160]! add x29, sp, #0 str x17, [x29, #88] @@ -3578,12 +4088,21 @@ fe_ge_to_p3: ldr x26, [x29, #152] ldp x29, x30, [sp], #0xa0 ret +#ifndef __APPLE__ .size fe_ge_to_p3,.-fe_ge_to_p3 - .text - .align 2 - .globl fe_ge_dbl - .type fe_ge_dbl, %function +#endif /* __APPLE__ */ +#ifndef __APPLE__ +.text +.globl fe_ge_dbl +.type fe_ge_dbl,@function +.align 2 fe_ge_dbl: +#else +.section __TEXT,__text +.globl _fe_ge_dbl +.p2align 2 +_fe_ge_dbl: +#endif /* __APPLE__ */ stp x29, x30, [sp, #-176]! add x29, sp, #0 str x17, [x29, #88] @@ -4134,12 +4653,21 @@ fe_ge_dbl: ldr x28, [x29, #168] ldp x29, x30, [sp], #0xb0 ret +#ifndef __APPLE__ .size fe_ge_dbl,.-fe_ge_dbl - .text - .align 2 - .globl fe_ge_madd - .type fe_ge_madd, %function +#endif /* __APPLE__ */ +#ifndef __APPLE__ +.text +.globl fe_ge_madd +.type fe_ge_madd,@function +.align 2 fe_ge_madd: +#else +.section __TEXT,__text +.globl _fe_ge_madd +.p2align 2 +_fe_ge_madd: +#endif /* __APPLE__ */ stp x29, x30, [sp, #-176]! add x29, sp, #0 str x17, [x29, #88] @@ -4709,12 +5237,21 @@ fe_ge_madd: ldr x28, [x29, #168] ldp x29, x30, [sp], #0xb0 ret +#ifndef __APPLE__ .size fe_ge_madd,.-fe_ge_madd - .text - .align 2 - .globl fe_ge_msub - .type fe_ge_msub, %function +#endif /* __APPLE__ */ +#ifndef __APPLE__ +.text +.globl fe_ge_msub +.type fe_ge_msub,@function +.align 2 fe_ge_msub: +#else +.section __TEXT,__text +.globl _fe_ge_msub +.p2align 2 +_fe_ge_msub: +#endif /* __APPLE__ */ stp x29, x30, [sp, #-176]! add x29, sp, #0 str x17, [x29, #88] @@ -5284,12 +5821,21 @@ fe_ge_msub: ldr x28, [x29, #168] ldp x29, x30, [sp], #0xb0 ret +#ifndef __APPLE__ .size fe_ge_msub,.-fe_ge_msub - .text - .align 2 - .globl fe_ge_add - .type fe_ge_add, %function +#endif /* __APPLE__ */ +#ifndef __APPLE__ +.text +.globl fe_ge_add +.type fe_ge_add,@function +.align 2 fe_ge_add: +#else +.section __TEXT,__text +.globl _fe_ge_add +.p2align 2 +_fe_ge_add: +#endif /* __APPLE__ */ stp x29, x30, [sp, #-176]! add x29, sp, #0 str x17, [x29, #88] @@ -5998,12 +6544,21 @@ fe_ge_add: ldr x28, [x29, #168] ldp x29, x30, [sp], #0xb0 ret +#ifndef __APPLE__ .size fe_ge_add,.-fe_ge_add - .text - .align 2 - .globl fe_ge_sub - .type fe_ge_sub, %function +#endif /* __APPLE__ */ +#ifndef __APPLE__ +.text +.globl fe_ge_sub +.type fe_ge_sub,@function +.align 2 fe_ge_sub: +#else +.section __TEXT,__text +.globl _fe_ge_sub +.p2align 2 +_fe_ge_sub: +#endif /* __APPLE__ */ stp x29, x30, [sp, #-176]! add x29, sp, #0 str x17, [x29, #88] @@ -6712,7 +7267,9 @@ fe_ge_sub: ldr x28, [x29, #168] ldp x29, x30, [sp], #0xb0 ret +#ifndef __APPLE__ .size fe_ge_sub,.-fe_ge_sub +#endif /* __APPLE__ */ #endif /* __aarch64__ */ #endif /* WOLFSSL_ARMASM */ diff --git a/wolfcrypt/src/port/arm/armv8-curve25519.c b/wolfcrypt/src/port/arm/armv8-curve25519.c index 2695ec1cae..97d30025f5 100644 --- a/wolfcrypt/src/port/arm/armv8-curve25519.c +++ b/wolfcrypt/src/port/arm/armv8-curve25519.c @@ -19,24 +19,19 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA */ +#ifdef HAVE_CONFIG_H + #include +#endif /* HAVE_CONFIG_H */ +#include + /* Generated using (from wolfssl): * cd ../scripts * ruby ./x25519/x25519.rb arm64 ../wolfssl/wolfcrypt/src/port/arm/armv8-curve25519.c */ - -#ifdef HAVE_CONFIG_H - #include -#endif - -#include - #ifdef WOLFSSL_ARMASM #ifdef __aarch64__ - -#include #include - void fe_init() { __asm__ __volatile__ ( @@ -776,123 +771,235 @@ void fe_invert(fe r, const fe a) "str %x[r], [x29, #144]\n\t" "str %x[a], [x29, #152]\n\t" "add x0, x29, #16\n\t" +#ifndef __APPLE__ "bl fe_sq\n\t" +#else + "bl _fe_sq\n\t" +#endif /* __APPLE__ */ "add x0, x29, #48\n\t" "add x1, x29, #16\n\t" +#ifndef __APPLE__ "bl fe_sq\n\t" +#else + "bl _fe_sq\n\t" +#endif /* __APPLE__ */ "add x1, x29, #48\n\t" +#ifndef __APPLE__ "bl fe_sq\n\t" +#else + "bl _fe_sq\n\t" +#endif /* __APPLE__ */ "ldr x1, [x29, #152]\n\t" "add x2, x29, #48\n\t" +#ifndef __APPLE__ "bl fe_mul\n\t" +#else + "bl _fe_mul\n\t" +#endif /* __APPLE__ */ "add x0, x29, #16\n\t" "add x1, x29, #16\n\t" "add x2, x29, #48\n\t" +#ifndef __APPLE__ "bl fe_mul\n\t" +#else + "bl _fe_mul\n\t" +#endif /* __APPLE__ */ "add x0, x29, #0x50\n\t" +#ifndef __APPLE__ "bl fe_sq\n\t" +#else + "bl _fe_sq\n\t" +#endif /* __APPLE__ */ "add x0, x29, #48\n\t" "add x1, x29, #48\n\t" "add x2, x29, #0x50\n\t" +#ifndef __APPLE__ "bl fe_mul\n\t" +#else + "bl _fe_mul\n\t" +#endif /* __APPLE__ */ "add x0, x29, #0x50\n\t" +#ifndef __APPLE__ "bl fe_sq\n\t" +#else + "bl _fe_sq\n\t" +#endif /* __APPLE__ */ "mov x20, #4\n\t" "add x1, x29, #0x50\n\t" "\n" "L_fe_invert1_%=: \n\t" +#ifndef __APPLE__ "bl fe_sq\n\t" +#else + "bl _fe_sq\n\t" +#endif /* __APPLE__ */ "sub x20, x20, #1\n\t" "cmp x20, #0\n\t" "bne L_fe_invert1_%=\n\t" "add x0, x29, #48\n\t" "add x2, x29, #48\n\t" +#ifndef __APPLE__ "bl fe_mul\n\t" +#else + "bl _fe_mul\n\t" +#endif /* __APPLE__ */ "add x0, x29, #0x50\n\t" "add x1, x29, #48\n\t" +#ifndef __APPLE__ "bl fe_sq\n\t" +#else + "bl _fe_sq\n\t" +#endif /* __APPLE__ */ "mov x20, #9\n\t" "add x1, x29, #0x50\n\t" "\n" "L_fe_invert2_%=: \n\t" +#ifndef __APPLE__ "bl fe_sq\n\t" +#else + "bl _fe_sq\n\t" +#endif /* __APPLE__ */ "sub x20, x20, #1\n\t" "cmp x20, #0\n\t" "bne L_fe_invert2_%=\n\t" "add x2, x29, #48\n\t" +#ifndef __APPLE__ "bl fe_mul\n\t" +#else + "bl _fe_mul\n\t" +#endif /* __APPLE__ */ "add x0, x29, #0x70\n\t" +#ifndef __APPLE__ "bl fe_sq\n\t" +#else + "bl _fe_sq\n\t" +#endif /* __APPLE__ */ "mov x20, #19\n\t" "add x1, x29, #0x70\n\t" "\n" "L_fe_invert3_%=: \n\t" +#ifndef __APPLE__ "bl fe_sq\n\t" +#else + "bl _fe_sq\n\t" +#endif /* __APPLE__ */ "sub x20, x20, #1\n\t" "cmp x20, #0\n\t" "bne L_fe_invert3_%=\n\t" "add x0, x29, #0x50\n\t" "add x2, x29, #0x50\n\t" +#ifndef __APPLE__ "bl fe_mul\n\t" +#else + "bl _fe_mul\n\t" +#endif /* __APPLE__ */ "mov x20, #10\n\t" "add x1, x29, #0x50\n\t" "\n" "L_fe_invert4_%=: \n\t" +#ifndef __APPLE__ "bl fe_sq\n\t" +#else + "bl _fe_sq\n\t" +#endif /* __APPLE__ */ "sub x20, x20, #1\n\t" "cmp x20, #0\n\t" "bne L_fe_invert4_%=\n\t" "add x0, x29, #48\n\t" "add x2, x29, #48\n\t" +#ifndef __APPLE__ "bl fe_mul\n\t" +#else + "bl _fe_mul\n\t" +#endif /* __APPLE__ */ "add x0, x29, #0x50\n\t" "add x1, x29, #48\n\t" +#ifndef __APPLE__ "bl fe_sq\n\t" +#else + "bl _fe_sq\n\t" +#endif /* __APPLE__ */ "mov x20, #49\n\t" "add x1, x29, #0x50\n\t" "\n" "L_fe_invert5_%=: \n\t" +#ifndef __APPLE__ "bl fe_sq\n\t" +#else + "bl _fe_sq\n\t" +#endif /* __APPLE__ */ "sub x20, x20, #1\n\t" "cmp x20, #0\n\t" "bne L_fe_invert5_%=\n\t" "add x2, x29, #48\n\t" +#ifndef __APPLE__ "bl fe_mul\n\t" +#else + "bl _fe_mul\n\t" +#endif /* __APPLE__ */ "add x0, x29, #0x70\n\t" +#ifndef __APPLE__ "bl fe_sq\n\t" +#else + "bl _fe_sq\n\t" +#endif /* __APPLE__ */ "mov x20, #0x63\n\t" "add x1, x29, #0x70\n\t" "\n" "L_fe_invert6_%=: \n\t" +#ifndef __APPLE__ "bl fe_sq\n\t" +#else + "bl _fe_sq\n\t" +#endif /* __APPLE__ */ "sub x20, x20, #1\n\t" "cmp x20, #0\n\t" "bne L_fe_invert6_%=\n\t" "add x0, x29, #0x50\n\t" "add x2, x29, #0x50\n\t" +#ifndef __APPLE__ "bl fe_mul\n\t" +#else + "bl _fe_mul\n\t" +#endif /* __APPLE__ */ "mov x20, #50\n\t" "add x1, x29, #0x50\n\t" "\n" "L_fe_invert7_%=: \n\t" +#ifndef __APPLE__ "bl fe_sq\n\t" +#else + "bl _fe_sq\n\t" +#endif /* __APPLE__ */ "sub x20, x20, #1\n\t" "cmp x20, #0\n\t" "bne L_fe_invert7_%=\n\t" "add x0, x29, #48\n\t" "add x2, x29, #48\n\t" +#ifndef __APPLE__ "bl fe_mul\n\t" +#else + "bl _fe_mul\n\t" +#endif /* __APPLE__ */ "mov x20, #5\n\t" "add x1, x29, #48\n\t" "\n" "L_fe_invert8_%=: \n\t" +#ifndef __APPLE__ "bl fe_sq\n\t" +#else + "bl _fe_sq\n\t" +#endif /* __APPLE__ */ "sub x20, x20, #1\n\t" "cmp x20, #0\n\t" "bne L_fe_invert8_%=\n\t" "ldr x0, [x29, #144]\n\t" "add x2, x29, #16\n\t" +#ifndef __APPLE__ "bl fe_mul\n\t" +#else + "bl _fe_mul\n\t" +#endif /* __APPLE__ */ "ldp x29, x30, [sp], #0xa0\n\t" : [r] "+r" (r), [a] "+r" (a) : @@ -2215,123 +2322,235 @@ int curve25519(byte* r, byte* n, byte* a) /* Invert */ "add x0, x29, #48\n\t" "add x1, x29, #16\n\t" +#ifndef __APPLE__ "bl fe_sq\n\t" +#else + "bl _fe_sq\n\t" +#endif /* __APPLE__ */ "add x0, x29, #0x50\n\t" "add x1, x29, #48\n\t" +#ifndef __APPLE__ "bl fe_sq\n\t" +#else + "bl _fe_sq\n\t" +#endif /* __APPLE__ */ "add x1, x29, #0x50\n\t" +#ifndef __APPLE__ "bl fe_sq\n\t" +#else + "bl _fe_sq\n\t" +#endif /* __APPLE__ */ "add x1, x29, #16\n\t" "add x2, x29, #0x50\n\t" +#ifndef __APPLE__ "bl fe_mul\n\t" +#else + "bl _fe_mul\n\t" +#endif /* __APPLE__ */ "add x0, x29, #48\n\t" "add x1, x29, #48\n\t" "add x2, x29, #0x50\n\t" +#ifndef __APPLE__ "bl fe_mul\n\t" +#else + "bl _fe_mul\n\t" +#endif /* __APPLE__ */ "add x0, x29, #0x70\n\t" +#ifndef __APPLE__ "bl fe_sq\n\t" +#else + "bl _fe_sq\n\t" +#endif /* __APPLE__ */ "add x0, x29, #0x50\n\t" "add x1, x29, #0x50\n\t" "add x2, x29, #0x70\n\t" +#ifndef __APPLE__ "bl fe_mul\n\t" +#else + "bl _fe_mul\n\t" +#endif /* __APPLE__ */ "add x0, x29, #0x70\n\t" +#ifndef __APPLE__ "bl fe_sq\n\t" +#else + "bl _fe_sq\n\t" +#endif /* __APPLE__ */ "mov x24, #4\n\t" "add x1, x29, #0x70\n\t" "\n" "L_curve25519_inv_1_%=: \n\t" +#ifndef __APPLE__ "bl fe_sq\n\t" +#else + "bl _fe_sq\n\t" +#endif /* __APPLE__ */ "sub x24, x24, #1\n\t" "cmp x24, #0\n\t" "bne L_curve25519_inv_1_%=\n\t" "add x0, x29, #0x50\n\t" "add x2, x29, #0x50\n\t" +#ifndef __APPLE__ "bl fe_mul\n\t" +#else + "bl _fe_mul\n\t" +#endif /* __APPLE__ */ "add x0, x29, #0x70\n\t" "add x1, x29, #0x50\n\t" +#ifndef __APPLE__ "bl fe_sq\n\t" +#else + "bl _fe_sq\n\t" +#endif /* __APPLE__ */ "mov x24, #9\n\t" "add x1, x29, #0x70\n\t" "\n" "L_curve25519_inv_2_%=: \n\t" +#ifndef __APPLE__ "bl fe_sq\n\t" +#else + "bl _fe_sq\n\t" +#endif /* __APPLE__ */ "sub x24, x24, #1\n\t" "cmp x24, #0\n\t" "bne L_curve25519_inv_2_%=\n\t" "add x2, x29, #0x50\n\t" +#ifndef __APPLE__ "bl fe_mul\n\t" +#else + "bl _fe_mul\n\t" +#endif /* __APPLE__ */ "add x0, x29, #0x90\n\t" +#ifndef __APPLE__ "bl fe_sq\n\t" +#else + "bl _fe_sq\n\t" +#endif /* __APPLE__ */ "mov x24, #19\n\t" "add x1, x29, #0x90\n\t" "\n" "L_curve25519_inv_3_%=: \n\t" +#ifndef __APPLE__ "bl fe_sq\n\t" +#else + "bl _fe_sq\n\t" +#endif /* __APPLE__ */ "sub x24, x24, #1\n\t" "cmp x24, #0\n\t" "bne L_curve25519_inv_3_%=\n\t" "add x0, x29, #0x70\n\t" "add x2, x29, #0x70\n\t" +#ifndef __APPLE__ "bl fe_mul\n\t" +#else + "bl _fe_mul\n\t" +#endif /* __APPLE__ */ "mov x24, #10\n\t" "add x1, x29, #0x70\n\t" "\n" "L_curve25519_inv_4_%=: \n\t" +#ifndef __APPLE__ "bl fe_sq\n\t" +#else + "bl _fe_sq\n\t" +#endif /* __APPLE__ */ "sub x24, x24, #1\n\t" "cmp x24, #0\n\t" "bne L_curve25519_inv_4_%=\n\t" "add x0, x29, #0x50\n\t" "add x2, x29, #0x50\n\t" +#ifndef __APPLE__ "bl fe_mul\n\t" +#else + "bl _fe_mul\n\t" +#endif /* __APPLE__ */ "add x0, x29, #0x70\n\t" "add x1, x29, #0x50\n\t" +#ifndef __APPLE__ "bl fe_sq\n\t" +#else + "bl _fe_sq\n\t" +#endif /* __APPLE__ */ "mov x24, #49\n\t" "add x1, x29, #0x70\n\t" "\n" "L_curve25519_inv_5_%=: \n\t" +#ifndef __APPLE__ "bl fe_sq\n\t" +#else + "bl _fe_sq\n\t" +#endif /* __APPLE__ */ "sub x24, x24, #1\n\t" "cmp x24, #0\n\t" "bne L_curve25519_inv_5_%=\n\t" "add x2, x29, #0x50\n\t" +#ifndef __APPLE__ "bl fe_mul\n\t" +#else + "bl _fe_mul\n\t" +#endif /* __APPLE__ */ "add x0, x29, #0x90\n\t" +#ifndef __APPLE__ "bl fe_sq\n\t" +#else + "bl _fe_sq\n\t" +#endif /* __APPLE__ */ "mov x24, #0x63\n\t" "add x1, x29, #0x90\n\t" "\n" "L_curve25519_inv_6_%=: \n\t" +#ifndef __APPLE__ "bl fe_sq\n\t" +#else + "bl _fe_sq\n\t" +#endif /* __APPLE__ */ "sub x24, x24, #1\n\t" "cmp x24, #0\n\t" "bne L_curve25519_inv_6_%=\n\t" "add x0, x29, #0x70\n\t" "add x2, x29, #0x70\n\t" +#ifndef __APPLE__ "bl fe_mul\n\t" +#else + "bl _fe_mul\n\t" +#endif /* __APPLE__ */ "mov x24, #50\n\t" "add x1, x29, #0x70\n\t" "\n" "L_curve25519_inv_7_%=: \n\t" +#ifndef __APPLE__ "bl fe_sq\n\t" +#else + "bl _fe_sq\n\t" +#endif /* __APPLE__ */ "sub x24, x24, #1\n\t" "cmp x24, #0\n\t" "bne L_curve25519_inv_7_%=\n\t" "add x0, x29, #0x50\n\t" "add x2, x29, #0x50\n\t" +#ifndef __APPLE__ "bl fe_mul\n\t" +#else + "bl _fe_mul\n\t" +#endif /* __APPLE__ */ "mov x24, #5\n\t" "add x1, x29, #0x50\n\t" "\n" "L_curve25519_inv_8_%=: \n\t" +#ifndef __APPLE__ "bl fe_sq\n\t" +#else + "bl _fe_sq\n\t" +#endif /* __APPLE__ */ "sub x24, x24, #1\n\t" "cmp x24, #0\n\t" "bne L_curve25519_inv_8_%=\n\t" "add x0, x29, #16\n\t" "add x2, x29, #48\n\t" +#ifndef __APPLE__ "bl fe_mul\n\t" +#else + "bl _fe_mul\n\t" +#endif /* __APPLE__ */ "ldr %x[r], [x29, #176]\n\t" /* Multiply */ "ldp x6, x7, [%x[r]]\n\t" @@ -2491,122 +2710,234 @@ void fe_pow22523(fe r, const fe a) "str %x[r], [x29, #112]\n\t" "str %x[a], [x29, #120]\n\t" "add x0, x29, #16\n\t" +#ifndef __APPLE__ "bl fe_sq\n\t" +#else + "bl _fe_sq\n\t" +#endif /* __APPLE__ */ "add x0, x29, #48\n\t" "add x1, x29, #16\n\t" +#ifndef __APPLE__ "bl fe_sq\n\t" +#else + "bl _fe_sq\n\t" +#endif /* __APPLE__ */ "add x1, x29, #48\n\t" +#ifndef __APPLE__ "bl fe_sq\n\t" +#else + "bl _fe_sq\n\t" +#endif /* __APPLE__ */ "ldr x1, [x29, #120]\n\t" "add x2, x29, #48\n\t" +#ifndef __APPLE__ "bl fe_mul\n\t" +#else + "bl _fe_mul\n\t" +#endif /* __APPLE__ */ "add x0, x29, #16\n\t" "add x1, x29, #16\n\t" "add x2, x29, #48\n\t" +#ifndef __APPLE__ "bl fe_mul\n\t" +#else + "bl _fe_mul\n\t" +#endif /* __APPLE__ */ +#ifndef __APPLE__ "bl fe_sq\n\t" +#else + "bl _fe_sq\n\t" +#endif /* __APPLE__ */ "add x1, x29, #48\n\t" "add x2, x29, #16\n\t" +#ifndef __APPLE__ "bl fe_mul\n\t" +#else + "bl _fe_mul\n\t" +#endif /* __APPLE__ */ "add x0, x29, #48\n\t" "add x1, x29, #16\n\t" +#ifndef __APPLE__ "bl fe_sq\n\t" +#else + "bl _fe_sq\n\t" +#endif /* __APPLE__ */ "mov x21, #4\n\t" "add x1, x29, #48\n\t" "\n" "L_fe_pow22523_1_%=: \n\t" +#ifndef __APPLE__ "bl fe_sq\n\t" +#else + "bl _fe_sq\n\t" +#endif /* __APPLE__ */ "sub x21, x21, #1\n\t" "cmp x21, #0\n\t" "bne L_fe_pow22523_1_%=\n\t" "add x0, x29, #16\n\t" "add x2, x29, #16\n\t" +#ifndef __APPLE__ "bl fe_mul\n\t" +#else + "bl _fe_mul\n\t" +#endif /* __APPLE__ */ "add x0, x29, #48\n\t" "add x1, x29, #16\n\t" +#ifndef __APPLE__ "bl fe_sq\n\t" +#else + "bl _fe_sq\n\t" +#endif /* __APPLE__ */ "mov x21, #9\n\t" "add x1, x29, #48\n\t" "\n" "L_fe_pow22523_2_%=: \n\t" +#ifndef __APPLE__ "bl fe_sq\n\t" +#else + "bl _fe_sq\n\t" +#endif /* __APPLE__ */ "sub x21, x21, #1\n\t" "cmp x21, #0\n\t" "bne L_fe_pow22523_2_%=\n\t" "add x2, x29, #16\n\t" +#ifndef __APPLE__ "bl fe_mul\n\t" +#else + "bl _fe_mul\n\t" +#endif /* __APPLE__ */ "add x0, x29, #0x50\n\t" +#ifndef __APPLE__ "bl fe_sq\n\t" +#else + "bl _fe_sq\n\t" +#endif /* __APPLE__ */ "mov x21, #19\n\t" "add x1, x29, #0x50\n\t" "\n" "L_fe_pow22523_3_%=: \n\t" +#ifndef __APPLE__ "bl fe_sq\n\t" +#else + "bl _fe_sq\n\t" +#endif /* __APPLE__ */ "sub x21, x21, #1\n\t" "cmp x21, #0\n\t" "bne L_fe_pow22523_3_%=\n\t" "add x0, x29, #48\n\t" "add x2, x29, #48\n\t" +#ifndef __APPLE__ "bl fe_mul\n\t" +#else + "bl _fe_mul\n\t" +#endif /* __APPLE__ */ "mov x21, #10\n\t" "add x1, x29, #48\n\t" "\n" "L_fe_pow22523_4_%=: \n\t" +#ifndef __APPLE__ "bl fe_sq\n\t" +#else + "bl _fe_sq\n\t" +#endif /* __APPLE__ */ "sub x21, x21, #1\n\t" "cmp x21, #0\n\t" "bne L_fe_pow22523_4_%=\n\t" "add x0, x29, #16\n\t" "add x2, x29, #16\n\t" +#ifndef __APPLE__ "bl fe_mul\n\t" +#else + "bl _fe_mul\n\t" +#endif /* __APPLE__ */ "add x0, x29, #48\n\t" "add x1, x29, #16\n\t" +#ifndef __APPLE__ "bl fe_sq\n\t" +#else + "bl _fe_sq\n\t" +#endif /* __APPLE__ */ "mov x21, #49\n\t" "add x1, x29, #48\n\t" "\n" "L_fe_pow22523_5_%=: \n\t" +#ifndef __APPLE__ "bl fe_sq\n\t" +#else + "bl _fe_sq\n\t" +#endif /* __APPLE__ */ "sub x21, x21, #1\n\t" "cmp x21, #0\n\t" "bne L_fe_pow22523_5_%=\n\t" "add x2, x29, #16\n\t" +#ifndef __APPLE__ "bl fe_mul\n\t" +#else + "bl _fe_mul\n\t" +#endif /* __APPLE__ */ "add x0, x29, #0x50\n\t" +#ifndef __APPLE__ "bl fe_sq\n\t" +#else + "bl _fe_sq\n\t" +#endif /* __APPLE__ */ "mov x21, #0x63\n\t" "add x1, x29, #0x50\n\t" "\n" "L_fe_pow22523_6_%=: \n\t" +#ifndef __APPLE__ "bl fe_sq\n\t" +#else + "bl _fe_sq\n\t" +#endif /* __APPLE__ */ "sub x21, x21, #1\n\t" "cmp x21, #0\n\t" "bne L_fe_pow22523_6_%=\n\t" "add x0, x29, #48\n\t" "add x2, x29, #48\n\t" +#ifndef __APPLE__ "bl fe_mul\n\t" +#else + "bl _fe_mul\n\t" +#endif /* __APPLE__ */ "mov x21, #50\n\t" "add x1, x29, #48\n\t" "\n" "L_fe_pow22523_7_%=: \n\t" +#ifndef __APPLE__ "bl fe_sq\n\t" +#else + "bl _fe_sq\n\t" +#endif /* __APPLE__ */ "sub x21, x21, #1\n\t" "cmp x21, #0\n\t" "bne L_fe_pow22523_7_%=\n\t" "add x0, x29, #16\n\t" "add x2, x29, #16\n\t" +#ifndef __APPLE__ "bl fe_mul\n\t" +#else + "bl _fe_mul\n\t" +#endif /* __APPLE__ */ "mov x21, #2\n\t" "add x1, x29, #16\n\t" "\n" "L_fe_pow22523_8_%=: \n\t" +#ifndef __APPLE__ "bl fe_sq\n\t" +#else + "bl _fe_sq\n\t" +#endif /* __APPLE__ */ "sub x21, x21, #1\n\t" "cmp x21, #0\n\t" "bne L_fe_pow22523_8_%=\n\t" "ldr x0, [x29, #112]\n\t" "ldr x2, [x29, #120]\n\t" +#ifndef __APPLE__ "bl fe_mul\n\t" +#else + "bl _fe_mul\n\t" +#endif /* __APPLE__ */ "ldp x29, x30, [sp], #0x80\n\t" : [r] "+r" (r), [a] "+r" (a) : diff --git a/wolfcrypt/src/port/arm/armv8-poly1305.c b/wolfcrypt/src/port/arm/armv8-poly1305.c index 2f2dd8c834..11f3c7c63a 100644 --- a/wolfcrypt/src/port/arm/armv8-poly1305.c +++ b/wolfcrypt/src/port/arm/armv8-poly1305.c @@ -207,11 +207,11 @@ void poly1305_blocks(Poly1305* ctx, const unsigned char *m, "MOV v28.D[0], x9 \n\t" "AND x22, x22, #0x3ffffff \n\t" /* Zero accumulator registers */ - "MOVI v15.2D, #0x0 \n\t" - "MOVI v16.2D, #0x0 \n\t" - "MOVI v17.2D, #0x0 \n\t" - "MOVI v18.2D, #0x0 \n\t" - "MOVI v19.2D, #0x0 \n\t" + "MOVI v15.16B, #0x0 \n\t" + "MOVI v16.16B, #0x0 \n\t" + "MOVI v17.16B, #0x0 \n\t" + "MOVI v18.16B, #0x0 \n\t" + "MOVI v19.16B, #0x0 \n\t" /* Set hibit */ "CMP %[finished], #0 \n\t" "CSET x9, EQ \n\t" diff --git a/wolfcrypt/src/port/arm/armv8-sha512-asm.S b/wolfcrypt/src/port/arm/armv8-sha512-asm.S index 6ae7a30c4d..8cff141da0 100644 --- a/wolfcrypt/src/port/arm/armv8-sha512-asm.S +++ b/wolfcrypt/src/port/arm/armv8-sha512-asm.S @@ -19,17 +19,30 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA */ +#ifdef HAVE_CONFIG_H + #include +#endif /* HAVE_CONFIG_H */ +#include + /* Generated using (from wolfssl): * cd ../scripts * ruby ./sha2/sha512.rb arm64 ../wolfssl/wolfcrypt/src/port/arm/armv8-sha512-asm.S */ #ifdef WOLFSSL_ARMASM #ifdef __aarch64__ +#ifndef __APPLE__ .text - .section .rodata .type L_SHA512_transform_neon_len_k, %object + .section .rodata .size L_SHA512_transform_neon_len_k, 640 +#else + .section __DATA,__data +#endif /* __APPLE__ */ +#ifndef __APPLE__ .align 3 +#else + .p2align 3 +#endif /* __APPLE__ */ L_SHA512_transform_neon_len_k: .xword 0x428a2f98d728ae22 .xword 0x7137449123ef65cd @@ -111,18 +124,33 @@ L_SHA512_transform_neon_len_k: .xword 0x597f299cfc657e2a .xword 0x5fcb6fab3ad6faec .xword 0x6c44198c4a475817 +#ifndef __APPLE__ .text - .section .rodata .type L_SHA512_transform_neon_len_ror8, %object + .section .rodata .size L_SHA512_transform_neon_len_ror8, 16 +#else + .section __DATA,__data +#endif /* __APPLE__ */ +#ifndef __APPLE__ .align 4 +#else + .p2align 4 +#endif /* __APPLE__ */ L_SHA512_transform_neon_len_ror8: .xword 0x7060504030201, 0x80f0e0d0c0b0a09 - .text - .align 2 - .globl Transform_Sha512_Len - .type Transform_Sha512_Len, %function +#ifndef __APPLE__ +.text +.globl Transform_Sha512_Len +.type Transform_Sha512_Len,@function +.align 2 Transform_Sha512_Len: +#else +.section __TEXT,__text +.globl _Transform_Sha512_Len +.p2align 2 +_Transform_Sha512_Len: +#endif /* __APPLE__ */ stp x29, x30, [sp, #-128]! add x29, sp, #0 str x17, [x29, #16] @@ -133,8 +161,18 @@ Transform_Sha512_Len: stp x26, x27, [x29, #80] stp d8, d9, [x29, #96] stp d10, d11, [x29, #112] +#ifndef __APPLE__ adr x3, L_SHA512_transform_neon_len_k +#else + adrp x3, L_SHA512_transform_neon_len_k@PAGE + add x3, x3, :lo12:L_SHA512_transform_neon_len_k@PAGEOFF +#endif /* __APPLE__ */ +#ifndef __APPLE__ adr x27, L_SHA512_transform_neon_len_ror8 +#else + adrp x27, L_SHA512_transform_neon_len_ror8@PAGE + add x27, x27, :lo12:L_SHA512_transform_neon_len_ror8@PAGEOFF +#endif /* __APPLE__ */ ld1 {v11.16b}, [x27] # Load digest into working vars ldp x4, x5, [x0] @@ -1026,7 +1064,12 @@ L_sha512_len_neon_start: add x6, x6, x21 add x5, x5, x20 add x4, x4, x19 +#ifndef __APPLE__ adr x3, L_SHA512_transform_neon_len_k +#else + adrp x3, L_SHA512_transform_neon_len_k@PAGE + add x3, x3, :lo12:L_SHA512_transform_neon_len_k@PAGEOFF +#endif /* __APPLE__ */ subs w2, w2, #0x80 bne L_sha512_len_neon_begin stp x4, x5, [x0] @@ -1043,7 +1086,9 @@ L_sha512_len_neon_start: ldp d10, d11, [x29, #112] ldp x29, x30, [sp], #0x80 ret +#ifndef __APPLE__ .size Transform_Sha512_Len,.-Transform_Sha512_Len +#endif /* __APPLE__ */ #endif /* __aarch64__ */ #endif /* WOLFSSL_ARMASM */ diff --git a/wolfcrypt/src/port/arm/armv8-sha512-asm.c b/wolfcrypt/src/port/arm/armv8-sha512-asm.c index 94568dc379..49dffd7789 100644 --- a/wolfcrypt/src/port/arm/armv8-sha512-asm.c +++ b/wolfcrypt/src/port/arm/armv8-sha512-asm.c @@ -19,21 +19,17 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA */ +#ifdef HAVE_CONFIG_H + #include +#endif /* HAVE_CONFIG_H */ +#include + /* Generated using (from wolfssl): * cd ../scripts * ruby ./sha2/sha512.rb arm64 ../wolfssl/wolfcrypt/src/port/arm/armv8-sha512-asm.c */ - -#ifdef HAVE_CONFIG_H - #include -#endif - -#include - #ifdef WOLFSSL_ARMASM #ifdef __aarch64__ - -#include #include static const uint64_t L_SHA512_transform_neon_len_k[] = { @@ -129,8 +125,18 @@ void Transform_Sha512_Len(wc_Sha512* sha512, const byte* data, word32 len) __asm__ __volatile__ ( "stp x29, x30, [sp, #-16]!\n\t" "add x29, sp, #0\n\t" +#ifndef __APPLE__ "adr x3, %[L_SHA512_transform_neon_len_k]\n\t" +#else + "adrp x3, %[L_SHA512_transform_neon_len_k]@PAGE\n\t" + "add x3, x3, %[L_SHA512_transform_neon_len_k]@PAGEOFF\n\t" +#endif /* __APPLE__ */ +#ifndef __APPLE__ "adr x27, %[L_SHA512_transform_neon_len_ror8]\n\t" +#else + "adrp x27, %[L_SHA512_transform_neon_len_ror8]@PAGE\n\t" + "add x27, x27, %[L_SHA512_transform_neon_len_ror8]@PAGEOFF\n\t" +#endif /* __APPLE__ */ "ld1 {v11.16b}, [x27]\n\t" /* Load digest into working vars */ "ldp x4, x5, [%x[sha512]]\n\t" @@ -1024,7 +1030,12 @@ void Transform_Sha512_Len(wc_Sha512* sha512, const byte* data, word32 len) "add x6, x6, x21\n\t" "add x5, x5, x20\n\t" "add x4, x4, x19\n\t" +#ifndef __APPLE__ "adr x3, %[L_SHA512_transform_neon_len_k]\n\t" +#else + "adrp x3, %[L_SHA512_transform_neon_len_k]@PAGE\n\t" + "add x3, x3, %[L_SHA512_transform_neon_len_k]@PAGEOFF\n\t" +#endif /* __APPLE__ */ "subs %w[len], %w[len], #0x80\n\t" "bne L_sha512_len_neon_begin_%=\n\t" "stp x4, x5, [%x[sha512]]\n\t" diff --git a/wolfcrypt/src/sp_arm32.c b/wolfcrypt/src/sp_arm32.c index 2ba17cbd1d..085d8c0690 100644 --- a/wolfcrypt/src/sp_arm32.c +++ b/wolfcrypt/src/sp_arm32.c @@ -7394,11 +7394,11 @@ int sp_RsaPublic_2048(const byte* in, word32 inLen, mp_int* em, mp_int* mm, sp_digit a[128], m[64], r[128]; #else sp_digit* d = NULL; - sp_digit* a; - sp_digit* m; - sp_digit* r; + sp_digit* a = NULL; + sp_digit* m = NULL; + sp_digit* r = NULL; #endif - sp_digit *ah; + sp_digit *ah = NULL; sp_digit e[1]; int err = MP_OKAY; @@ -7734,10 +7734,10 @@ int sp_RsaPrivate_2048(const byte* in, word32 inLen, mp_int* dm, byte* out, word32* outLen) { #if defined(SP_RSA_PRIVATE_EXP_D) || defined(RSA_LOW_MEM) - sp_digit* a; + sp_digit* a = NULL; sp_digit* d = NULL; - sp_digit* m; - sp_digit* r; + sp_digit* m = NULL; + sp_digit* r = NULL; int err = MP_OKAY; (void)pm; @@ -7796,16 +7796,16 @@ int sp_RsaPrivate_2048(const byte* in, word32 inLen, mp_int* dm, sp_digit tmpa[64], tmpb[64]; #else sp_digit* t = NULL; - sp_digit* a; - sp_digit* p; - sp_digit* q; - sp_digit* dp; - sp_digit* tmpa; - sp_digit* tmpb; + sp_digit* a = NULL; + sp_digit* p = NULL; + sp_digit* q = NULL; + sp_digit* dp = NULL; + sp_digit* tmpa = NULL; + sp_digit* tmpb = NULL; #endif - sp_digit* r; - sp_digit* qi; - sp_digit* dq; + sp_digit* r = NULL; + sp_digit* qi = NULL; + sp_digit* dq = NULL; sp_digit c; int err = MP_OKAY; @@ -18953,11 +18953,11 @@ int sp_RsaPublic_3072(const byte* in, word32 inLen, mp_int* em, mp_int* mm, sp_digit a[192], m[96], r[192]; #else sp_digit* d = NULL; - sp_digit* a; - sp_digit* m; - sp_digit* r; + sp_digit* a = NULL; + sp_digit* m = NULL; + sp_digit* r = NULL; #endif - sp_digit *ah; + sp_digit *ah = NULL; sp_digit e[1]; int err = MP_OKAY; @@ -19373,10 +19373,10 @@ int sp_RsaPrivate_3072(const byte* in, word32 inLen, mp_int* dm, byte* out, word32* outLen) { #if defined(SP_RSA_PRIVATE_EXP_D) || defined(RSA_LOW_MEM) - sp_digit* a; + sp_digit* a = NULL; sp_digit* d = NULL; - sp_digit* m; - sp_digit* r; + sp_digit* m = NULL; + sp_digit* r = NULL; int err = MP_OKAY; (void)pm; @@ -19435,16 +19435,16 @@ int sp_RsaPrivate_3072(const byte* in, word32 inLen, mp_int* dm, sp_digit tmpa[96], tmpb[96]; #else sp_digit* t = NULL; - sp_digit* a; - sp_digit* p; - sp_digit* q; - sp_digit* dp; - sp_digit* tmpa; - sp_digit* tmpb; + sp_digit* a = NULL; + sp_digit* p = NULL; + sp_digit* q = NULL; + sp_digit* dp = NULL; + sp_digit* tmpa = NULL; + sp_digit* tmpb = NULL; #endif - sp_digit* r; - sp_digit* qi; - sp_digit* dq; + sp_digit* r = NULL; + sp_digit* qi = NULL; + sp_digit* dq = NULL; sp_digit c; int err = MP_OKAY; @@ -26940,11 +26940,11 @@ int sp_RsaPublic_4096(const byte* in, word32 inLen, mp_int* em, mp_int* mm, sp_digit a[256], m[128], r[256]; #else sp_digit* d = NULL; - sp_digit* a; - sp_digit* m; - sp_digit* r; + sp_digit* a = NULL; + sp_digit* m = NULL; + sp_digit* r = NULL; #endif - sp_digit *ah; + sp_digit *ah = NULL; sp_digit e[1]; int err = MP_OKAY; @@ -27440,10 +27440,10 @@ int sp_RsaPrivate_4096(const byte* in, word32 inLen, mp_int* dm, byte* out, word32* outLen) { #if defined(SP_RSA_PRIVATE_EXP_D) || defined(RSA_LOW_MEM) - sp_digit* a; + sp_digit* a = NULL; sp_digit* d = NULL; - sp_digit* m; - sp_digit* r; + sp_digit* m = NULL; + sp_digit* r = NULL; int err = MP_OKAY; (void)pm; @@ -27502,16 +27502,16 @@ int sp_RsaPrivate_4096(const byte* in, word32 inLen, mp_int* dm, sp_digit tmpa[128], tmpb[128]; #else sp_digit* t = NULL; - sp_digit* a; - sp_digit* p; - sp_digit* q; - sp_digit* dp; - sp_digit* tmpa; - sp_digit* tmpb; + sp_digit* a = NULL; + sp_digit* p = NULL; + sp_digit* q = NULL; + sp_digit* dp = NULL; + sp_digit* tmpa = NULL; + sp_digit* tmpb = NULL; #endif - sp_digit* r; - sp_digit* qi; - sp_digit* dq; + sp_digit* r = NULL; + sp_digit* qi = NULL; + sp_digit* dq = NULL; sp_digit c; int err = MP_OKAY; diff --git a/wolfcrypt/src/sp_arm64.c b/wolfcrypt/src/sp_arm64.c index 378ffbf652..067b4a1266 100644 --- a/wolfcrypt/src/sp_arm64.c +++ b/wolfcrypt/src/sp_arm64.c @@ -4888,11 +4888,11 @@ int sp_RsaPublic_2048(const byte* in, word32 inLen, mp_int* em, mp_int* mm, sp_digit a[64], m[32], r[64]; #else sp_digit* d = NULL; - sp_digit* a; - sp_digit* m; - sp_digit* r; + sp_digit* a = NULL; + sp_digit* m = NULL; + sp_digit* r = NULL; #endif - sp_digit *ah; + sp_digit *ah = NULL; sp_digit e[1]; int err = MP_OKAY; @@ -5124,10 +5124,10 @@ int sp_RsaPrivate_2048(const byte* in, word32 inLen, mp_int* dm, byte* out, word32* outLen) { #if defined(SP_RSA_PRIVATE_EXP_D) || defined(RSA_LOW_MEM) - sp_digit* a; + sp_digit* a = NULL; sp_digit* d = NULL; - sp_digit* m; - sp_digit* r; + sp_digit* m = NULL; + sp_digit* r = NULL; int err = MP_OKAY; (void)pm; @@ -5186,16 +5186,16 @@ int sp_RsaPrivate_2048(const byte* in, word32 inLen, mp_int* dm, sp_digit tmpa[32], tmpb[32]; #else sp_digit* t = NULL; - sp_digit* a; - sp_digit* p; - sp_digit* q; - sp_digit* dp; - sp_digit* tmpa; - sp_digit* tmpb; + sp_digit* a = NULL; + sp_digit* p = NULL; + sp_digit* q = NULL; + sp_digit* dp = NULL; + sp_digit* tmpa = NULL; + sp_digit* tmpb = NULL; #endif - sp_digit* r; - sp_digit* qi; - sp_digit* dq; + sp_digit* r = NULL; + sp_digit* qi = NULL; + sp_digit* dq = NULL; sp_digit c; int err = MP_OKAY; @@ -12597,11 +12597,11 @@ int sp_RsaPublic_3072(const byte* in, word32 inLen, mp_int* em, mp_int* mm, sp_digit a[96], m[48], r[96]; #else sp_digit* d = NULL; - sp_digit* a; - sp_digit* m; - sp_digit* r; + sp_digit* a = NULL; + sp_digit* m = NULL; + sp_digit* r = NULL; #endif - sp_digit *ah; + sp_digit *ah = NULL; sp_digit e[1]; int err = MP_OKAY; @@ -12861,10 +12861,10 @@ int sp_RsaPrivate_3072(const byte* in, word32 inLen, mp_int* dm, byte* out, word32* outLen) { #if defined(SP_RSA_PRIVATE_EXP_D) || defined(RSA_LOW_MEM) - sp_digit* a; + sp_digit* a = NULL; sp_digit* d = NULL; - sp_digit* m; - sp_digit* r; + sp_digit* m = NULL; + sp_digit* r = NULL; int err = MP_OKAY; (void)pm; @@ -12923,16 +12923,16 @@ int sp_RsaPrivate_3072(const byte* in, word32 inLen, mp_int* dm, sp_digit tmpa[48], tmpb[48]; #else sp_digit* t = NULL; - sp_digit* a; - sp_digit* p; - sp_digit* q; - sp_digit* dp; - sp_digit* tmpa; - sp_digit* tmpb; + sp_digit* a = NULL; + sp_digit* p = NULL; + sp_digit* q = NULL; + sp_digit* dp = NULL; + sp_digit* tmpa = NULL; + sp_digit* tmpb = NULL; #endif - sp_digit* r; - sp_digit* qi; - sp_digit* dq; + sp_digit* r = NULL; + sp_digit* qi = NULL; + sp_digit* dq = NULL; sp_digit c; int err = MP_OKAY; @@ -17528,11 +17528,11 @@ int sp_RsaPublic_4096(const byte* in, word32 inLen, mp_int* em, mp_int* mm, sp_digit a[128], m[64], r[128]; #else sp_digit* d = NULL; - sp_digit* a; - sp_digit* m; - sp_digit* r; + sp_digit* a = NULL; + sp_digit* m = NULL; + sp_digit* r = NULL; #endif - sp_digit *ah; + sp_digit *ah = NULL; sp_digit e[1]; int err = MP_OKAY; @@ -17820,10 +17820,10 @@ int sp_RsaPrivate_4096(const byte* in, word32 inLen, mp_int* dm, byte* out, word32* outLen) { #if defined(SP_RSA_PRIVATE_EXP_D) || defined(RSA_LOW_MEM) - sp_digit* a; + sp_digit* a = NULL; sp_digit* d = NULL; - sp_digit* m; - sp_digit* r; + sp_digit* m = NULL; + sp_digit* r = NULL; int err = MP_OKAY; (void)pm; @@ -17882,16 +17882,16 @@ int sp_RsaPrivate_4096(const byte* in, word32 inLen, mp_int* dm, sp_digit tmpa[64], tmpb[64]; #else sp_digit* t = NULL; - sp_digit* a; - sp_digit* p; - sp_digit* q; - sp_digit* dp; - sp_digit* tmpa; - sp_digit* tmpb; + sp_digit* a = NULL; + sp_digit* p = NULL; + sp_digit* q = NULL; + sp_digit* dp = NULL; + sp_digit* tmpa = NULL; + sp_digit* tmpb = NULL; #endif - sp_digit* r; - sp_digit* qi; - sp_digit* dq; + sp_digit* r = NULL; + sp_digit* qi = NULL; + sp_digit* dq = NULL; sp_digit c; int err = MP_OKAY; diff --git a/wolfcrypt/src/sp_armthumb.c b/wolfcrypt/src/sp_armthumb.c index 0463607980..91a4bc367c 100644 --- a/wolfcrypt/src/sp_armthumb.c +++ b/wolfcrypt/src/sp_armthumb.c @@ -4259,11 +4259,11 @@ int sp_RsaPublic_2048(const byte* in, word32 inLen, mp_int* em, mp_int* mm, sp_digit a[128], m[64], r[128]; #else sp_digit* d = NULL; - sp_digit* a; - sp_digit* m; - sp_digit* r; + sp_digit* a = NULL; + sp_digit* m = NULL; + sp_digit* r = NULL; #endif - sp_digit *ah; + sp_digit *ah = NULL; sp_digit e[1]; int err = MP_OKAY; @@ -4432,10 +4432,10 @@ int sp_RsaPrivate_2048(const byte* in, word32 inLen, mp_int* dm, byte* out, word32* outLen) { #if defined(SP_RSA_PRIVATE_EXP_D) || defined(RSA_LOW_MEM) - sp_digit* a; + sp_digit* a = NULL; sp_digit* d = NULL; - sp_digit* m; - sp_digit* r; + sp_digit* m = NULL; + sp_digit* r = NULL; int err = MP_OKAY; (void)pm; @@ -4494,16 +4494,16 @@ int sp_RsaPrivate_2048(const byte* in, word32 inLen, mp_int* dm, sp_digit tmpa[64], tmpb[64]; #else sp_digit* t = NULL; - sp_digit* a; - sp_digit* p; - sp_digit* q; - sp_digit* dp; - sp_digit* tmpa; - sp_digit* tmpb; + sp_digit* a = NULL; + sp_digit* p = NULL; + sp_digit* q = NULL; + sp_digit* dp = NULL; + sp_digit* tmpa = NULL; + sp_digit* tmpb = NULL; #endif - sp_digit* r; - sp_digit* qi; - sp_digit* dq; + sp_digit* r = NULL; + sp_digit* qi = NULL; + sp_digit* dq = NULL; sp_digit c; int err = MP_OKAY; @@ -10065,11 +10065,11 @@ int sp_RsaPublic_3072(const byte* in, word32 inLen, mp_int* em, mp_int* mm, sp_digit a[192], m[96], r[192]; #else sp_digit* d = NULL; - sp_digit* a; - sp_digit* m; - sp_digit* r; + sp_digit* a = NULL; + sp_digit* m = NULL; + sp_digit* r = NULL; #endif - sp_digit *ah; + sp_digit *ah = NULL; sp_digit e[1]; int err = MP_OKAY; @@ -10238,10 +10238,10 @@ int sp_RsaPrivate_3072(const byte* in, word32 inLen, mp_int* dm, byte* out, word32* outLen) { #if defined(SP_RSA_PRIVATE_EXP_D) || defined(RSA_LOW_MEM) - sp_digit* a; + sp_digit* a = NULL; sp_digit* d = NULL; - sp_digit* m; - sp_digit* r; + sp_digit* m = NULL; + sp_digit* r = NULL; int err = MP_OKAY; (void)pm; @@ -10300,16 +10300,16 @@ int sp_RsaPrivate_3072(const byte* in, word32 inLen, mp_int* dm, sp_digit tmpa[96], tmpb[96]; #else sp_digit* t = NULL; - sp_digit* a; - sp_digit* p; - sp_digit* q; - sp_digit* dp; - sp_digit* tmpa; - sp_digit* tmpb; + sp_digit* a = NULL; + sp_digit* p = NULL; + sp_digit* q = NULL; + sp_digit* dp = NULL; + sp_digit* tmpa = NULL; + sp_digit* tmpb = NULL; #endif - sp_digit* r; - sp_digit* qi; - sp_digit* dq; + sp_digit* r = NULL; + sp_digit* qi = NULL; + sp_digit* dq = NULL; sp_digit c; int err = MP_OKAY; @@ -13952,11 +13952,11 @@ int sp_RsaPublic_4096(const byte* in, word32 inLen, mp_int* em, mp_int* mm, sp_digit a[256], m[128], r[256]; #else sp_digit* d = NULL; - sp_digit* a; - sp_digit* m; - sp_digit* r; + sp_digit* a = NULL; + sp_digit* m = NULL; + sp_digit* r = NULL; #endif - sp_digit *ah; + sp_digit *ah = NULL; sp_digit e[1]; int err = MP_OKAY; @@ -14126,10 +14126,10 @@ int sp_RsaPrivate_4096(const byte* in, word32 inLen, mp_int* dm, byte* out, word32* outLen) { #if defined(SP_RSA_PRIVATE_EXP_D) || defined(RSA_LOW_MEM) - sp_digit* a; + sp_digit* a = NULL; sp_digit* d = NULL; - sp_digit* m; - sp_digit* r; + sp_digit* m = NULL; + sp_digit* r = NULL; int err = MP_OKAY; (void)pm; @@ -14188,16 +14188,16 @@ int sp_RsaPrivate_4096(const byte* in, word32 inLen, mp_int* dm, sp_digit tmpa[128], tmpb[128]; #else sp_digit* t = NULL; - sp_digit* a; - sp_digit* p; - sp_digit* q; - sp_digit* dp; - sp_digit* tmpa; - sp_digit* tmpb; + sp_digit* a = NULL; + sp_digit* p = NULL; + sp_digit* q = NULL; + sp_digit* dp = NULL; + sp_digit* tmpa = NULL; + sp_digit* tmpb = NULL; #endif - sp_digit* r; - sp_digit* qi; - sp_digit* dq; + sp_digit* r = NULL; + sp_digit* qi = NULL; + sp_digit* dq = NULL; sp_digit c; int err = MP_OKAY; diff --git a/wolfcrypt/src/sp_c32.c b/wolfcrypt/src/sp_c32.c index 714729f4fb..4dec2d99ca 100644 --- a/wolfcrypt/src/sp_c32.c +++ b/wolfcrypt/src/sp_c32.c @@ -2087,7 +2087,7 @@ static int sp_2048_mod_exp_45(sp_digit* r, const sp_digit* a, const sp_digit* e, sp_digit td[(32 * 90) + 90]; #endif sp_digit* t[32]; - sp_digit* rt; + sp_digit* rt = NULL; sp_digit* norm; sp_digit mp = 1; sp_digit n; @@ -3040,7 +3040,7 @@ static int sp_2048_mod_exp_90(sp_digit* r, const sp_digit* a, const sp_digit* e, sp_digit td[(32 * 180) + 180]; #endif sp_digit* t[32]; - sp_digit* rt; + sp_digit* rt = NULL; sp_digit* norm; sp_digit mp = 1; sp_digit n; @@ -3192,10 +3192,10 @@ int sp_RsaPublic_2048(const byte* in, word32 inLen, mp_int* em, mp_int* mm, { #ifdef WOLFSSL_SP_SMALL sp_digit* d = NULL; - sp_digit* a; - sp_digit* m; - sp_digit* r; - sp_digit* norm; + sp_digit* a = NULL; + sp_digit* m = NULL; + sp_digit* r = NULL; + sp_digit* norm = NULL; sp_digit e[1] = {0}; sp_digit mp; int i; @@ -3289,9 +3289,9 @@ int sp_RsaPublic_2048(const byte* in, word32 inLen, mp_int* em, mp_int* mm, #else sp_digit* d = NULL; #endif - sp_digit* a; - sp_digit* m; - sp_digit* r; + sp_digit* a = NULL; + sp_digit* m = NULL; + sp_digit* r = NULL; sp_digit e[1] = {0}; int err = MP_OKAY; @@ -3430,10 +3430,10 @@ int sp_RsaPrivate_2048(const byte* in, word32 inLen, mp_int* dm, { #if defined(SP_RSA_PRIVATE_EXP_D) || defined(RSA_LOW_MEM) #if (defined(WOLFSSL_SP_SMALL) || defined(WOLFSSL_SMALL_STACK)) && !defined(WOLFSSL_SP_NO_MALLOC) - sp_digit* a; + sp_digit* a = NULL; sp_digit* d = NULL; - sp_digit* m; - sp_digit* r; + sp_digit* m = NULL; + sp_digit* r = NULL; int err = MP_OKAY; (void)pm; @@ -3530,15 +3530,15 @@ int sp_RsaPrivate_2048(const byte* in, word32 inLen, mp_int* dm, #else #if (defined(WOLFSSL_SP_SMALL) || defined(WOLFSSL_SMALL_STACK)) && !defined(WOLFSSL_SP_NO_MALLOC) sp_digit* t = NULL; - sp_digit* a; - sp_digit* p; - sp_digit* q; - sp_digit* dp; - sp_digit* dq; - sp_digit* qi; - sp_digit* tmpa; - sp_digit* tmpb; - sp_digit* r; + sp_digit* a = NULL; + sp_digit* p = NULL; + sp_digit* q = NULL; + sp_digit* dp = NULL; + sp_digit* dq = NULL; + sp_digit* qi = NULL; + sp_digit* tmpa = NULL; + sp_digit* tmpb = NULL; + sp_digit* r = NULL; int err = MP_OKAY; (void)dm; @@ -5928,7 +5928,7 @@ static int sp_3072_mod_exp_67(sp_digit* r, const sp_digit* a, const sp_digit* e, sp_digit td[(32 * 134) + 134]; #endif sp_digit* t[32]; - sp_digit* rt; + sp_digit* rt = NULL; sp_digit* norm; sp_digit mp = 1; sp_digit n; @@ -6917,7 +6917,7 @@ static int sp_3072_mod_exp_134(sp_digit* r, const sp_digit* a, const sp_digit* e sp_digit td[(32 * 268) + 268]; #endif sp_digit* t[32]; - sp_digit* rt; + sp_digit* rt = NULL; sp_digit* norm; sp_digit mp = 1; sp_digit n; @@ -7069,10 +7069,10 @@ int sp_RsaPublic_3072(const byte* in, word32 inLen, mp_int* em, mp_int* mm, { #ifdef WOLFSSL_SP_SMALL sp_digit* d = NULL; - sp_digit* a; - sp_digit* m; - sp_digit* r; - sp_digit* norm; + sp_digit* a = NULL; + sp_digit* m = NULL; + sp_digit* r = NULL; + sp_digit* norm = NULL; sp_digit e[1] = {0}; sp_digit mp; int i; @@ -7166,9 +7166,9 @@ int sp_RsaPublic_3072(const byte* in, word32 inLen, mp_int* em, mp_int* mm, #else sp_digit* d = NULL; #endif - sp_digit* a; - sp_digit* m; - sp_digit* r; + sp_digit* a = NULL; + sp_digit* m = NULL; + sp_digit* r = NULL; sp_digit e[1] = {0}; int err = MP_OKAY; @@ -7307,10 +7307,10 @@ int sp_RsaPrivate_3072(const byte* in, word32 inLen, mp_int* dm, { #if defined(SP_RSA_PRIVATE_EXP_D) || defined(RSA_LOW_MEM) #if (defined(WOLFSSL_SP_SMALL) || defined(WOLFSSL_SMALL_STACK)) && !defined(WOLFSSL_SP_NO_MALLOC) - sp_digit* a; + sp_digit* a = NULL; sp_digit* d = NULL; - sp_digit* m; - sp_digit* r; + sp_digit* m = NULL; + sp_digit* r = NULL; int err = MP_OKAY; (void)pm; @@ -7407,15 +7407,15 @@ int sp_RsaPrivate_3072(const byte* in, word32 inLen, mp_int* dm, #else #if (defined(WOLFSSL_SP_SMALL) || defined(WOLFSSL_SMALL_STACK)) && !defined(WOLFSSL_SP_NO_MALLOC) sp_digit* t = NULL; - sp_digit* a; - sp_digit* p; - sp_digit* q; - sp_digit* dp; - sp_digit* dq; - sp_digit* qi; - sp_digit* tmpa; - sp_digit* tmpb; - sp_digit* r; + sp_digit* a = NULL; + sp_digit* p = NULL; + sp_digit* q = NULL; + sp_digit* dp = NULL; + sp_digit* dq = NULL; + sp_digit* qi = NULL; + sp_digit* tmpa = NULL; + sp_digit* tmpb = NULL; + sp_digit* r = NULL; int err = MP_OKAY; (void)dm; @@ -9992,7 +9992,7 @@ static int sp_4096_mod_exp_98(sp_digit* r, const sp_digit* a, const sp_digit* e, sp_digit td[(32 * 196) + 196]; #endif sp_digit* t[32]; - sp_digit* rt; + sp_digit* rt = NULL; sp_digit* norm; sp_digit mp = 1; sp_digit n; @@ -10958,7 +10958,7 @@ static int sp_4096_mod_exp_196(sp_digit* r, const sp_digit* a, const sp_digit* e sp_digit td[(32 * 392) + 392]; #endif sp_digit* t[32]; - sp_digit* rt; + sp_digit* rt = NULL; sp_digit* norm; sp_digit mp = 1; sp_digit n; @@ -11110,10 +11110,10 @@ int sp_RsaPublic_4096(const byte* in, word32 inLen, mp_int* em, mp_int* mm, { #ifdef WOLFSSL_SP_SMALL sp_digit* d = NULL; - sp_digit* a; - sp_digit* m; - sp_digit* r; - sp_digit* norm; + sp_digit* a = NULL; + sp_digit* m = NULL; + sp_digit* r = NULL; + sp_digit* norm = NULL; sp_digit e[1] = {0}; sp_digit mp; int i; @@ -11207,9 +11207,9 @@ int sp_RsaPublic_4096(const byte* in, word32 inLen, mp_int* em, mp_int* mm, #else sp_digit* d = NULL; #endif - sp_digit* a; - sp_digit* m; - sp_digit* r; + sp_digit* a = NULL; + sp_digit* m = NULL; + sp_digit* r = NULL; sp_digit e[1] = {0}; int err = MP_OKAY; @@ -11348,10 +11348,10 @@ int sp_RsaPrivate_4096(const byte* in, word32 inLen, mp_int* dm, { #if defined(SP_RSA_PRIVATE_EXP_D) || defined(RSA_LOW_MEM) #if (defined(WOLFSSL_SP_SMALL) || defined(WOLFSSL_SMALL_STACK)) && !defined(WOLFSSL_SP_NO_MALLOC) - sp_digit* a; + sp_digit* a = NULL; sp_digit* d = NULL; - sp_digit* m; - sp_digit* r; + sp_digit* m = NULL; + sp_digit* r = NULL; int err = MP_OKAY; (void)pm; @@ -11448,15 +11448,15 @@ int sp_RsaPrivate_4096(const byte* in, word32 inLen, mp_int* dm, #else #if (defined(WOLFSSL_SP_SMALL) || defined(WOLFSSL_SMALL_STACK)) && !defined(WOLFSSL_SP_NO_MALLOC) sp_digit* t = NULL; - sp_digit* a; - sp_digit* p; - sp_digit* q; - sp_digit* dp; - sp_digit* dq; - sp_digit* qi; - sp_digit* tmpa; - sp_digit* tmpb; - sp_digit* r; + sp_digit* a = NULL; + sp_digit* p = NULL; + sp_digit* q = NULL; + sp_digit* dp = NULL; + sp_digit* dq = NULL; + sp_digit* qi = NULL; + sp_digit* tmpa = NULL; + sp_digit* tmpb = NULL; + sp_digit* r = NULL; int err = MP_OKAY; (void)dm; diff --git a/wolfcrypt/src/sp_c64.c b/wolfcrypt/src/sp_c64.c index 4d4d3b645c..cec1f2eb2d 100644 --- a/wolfcrypt/src/sp_c64.c +++ b/wolfcrypt/src/sp_c64.c @@ -1735,7 +1735,7 @@ static int sp_2048_mod_exp_18(sp_digit* r, const sp_digit* a, const sp_digit* e, sp_digit td[(32 * 36) + 36]; #endif sp_digit* t[32]; - sp_digit* rt; + sp_digit* rt = NULL; sp_digit* norm; sp_digit mp = 1; sp_digit n; @@ -2680,7 +2680,7 @@ static int sp_2048_mod_exp_36(sp_digit* r, const sp_digit* a, const sp_digit* e, sp_digit td[(32 * 72) + 72]; #endif sp_digit* t[32]; - sp_digit* rt; + sp_digit* rt = NULL; sp_digit* norm; sp_digit mp = 1; sp_digit n; @@ -2832,10 +2832,10 @@ int sp_RsaPublic_2048(const byte* in, word32 inLen, mp_int* em, mp_int* mm, { #ifdef WOLFSSL_SP_SMALL sp_digit* d = NULL; - sp_digit* a; - sp_digit* m; - sp_digit* r; - sp_digit* norm; + sp_digit* a = NULL; + sp_digit* m = NULL; + sp_digit* r = NULL; + sp_digit* norm = NULL; sp_digit e[1] = {0}; sp_digit mp; int i; @@ -2929,9 +2929,9 @@ int sp_RsaPublic_2048(const byte* in, word32 inLen, mp_int* em, mp_int* mm, #else sp_digit* d = NULL; #endif - sp_digit* a; - sp_digit* m; - sp_digit* r; + sp_digit* a = NULL; + sp_digit* m = NULL; + sp_digit* r = NULL; sp_digit e[1] = {0}; int err = MP_OKAY; @@ -3070,10 +3070,10 @@ int sp_RsaPrivate_2048(const byte* in, word32 inLen, mp_int* dm, { #if defined(SP_RSA_PRIVATE_EXP_D) || defined(RSA_LOW_MEM) #if (defined(WOLFSSL_SP_SMALL) || defined(WOLFSSL_SMALL_STACK)) && !defined(WOLFSSL_SP_NO_MALLOC) - sp_digit* a; + sp_digit* a = NULL; sp_digit* d = NULL; - sp_digit* m; - sp_digit* r; + sp_digit* m = NULL; + sp_digit* r = NULL; int err = MP_OKAY; (void)pm; @@ -3170,15 +3170,15 @@ int sp_RsaPrivate_2048(const byte* in, word32 inLen, mp_int* dm, #else #if (defined(WOLFSSL_SP_SMALL) || defined(WOLFSSL_SMALL_STACK)) && !defined(WOLFSSL_SP_NO_MALLOC) sp_digit* t = NULL; - sp_digit* a; - sp_digit* p; - sp_digit* q; - sp_digit* dp; - sp_digit* dq; - sp_digit* qi; - sp_digit* tmpa; - sp_digit* tmpb; - sp_digit* r; + sp_digit* a = NULL; + sp_digit* p = NULL; + sp_digit* q = NULL; + sp_digit* dp = NULL; + sp_digit* dq = NULL; + sp_digit* qi = NULL; + sp_digit* tmpa = NULL; + sp_digit* tmpb = NULL; + sp_digit* r = NULL; int err = MP_OKAY; (void)dm; @@ -5916,7 +5916,7 @@ static int sp_3072_mod_exp_27(sp_digit* r, const sp_digit* a, const sp_digit* e, sp_digit td[(32 * 54) + 54]; #endif sp_digit* t[32]; - sp_digit* rt; + sp_digit* rt = NULL; sp_digit* norm; sp_digit mp = 1; sp_digit n; @@ -6831,7 +6831,7 @@ static int sp_3072_mod_exp_54(sp_digit* r, const sp_digit* a, const sp_digit* e, sp_digit td[(32 * 108) + 108]; #endif sp_digit* t[32]; - sp_digit* rt; + sp_digit* rt = NULL; sp_digit* norm; sp_digit mp = 1; sp_digit n; @@ -6983,10 +6983,10 @@ int sp_RsaPublic_3072(const byte* in, word32 inLen, mp_int* em, mp_int* mm, { #ifdef WOLFSSL_SP_SMALL sp_digit* d = NULL; - sp_digit* a; - sp_digit* m; - sp_digit* r; - sp_digit* norm; + sp_digit* a = NULL; + sp_digit* m = NULL; + sp_digit* r = NULL; + sp_digit* norm = NULL; sp_digit e[1] = {0}; sp_digit mp; int i; @@ -7080,9 +7080,9 @@ int sp_RsaPublic_3072(const byte* in, word32 inLen, mp_int* em, mp_int* mm, #else sp_digit* d = NULL; #endif - sp_digit* a; - sp_digit* m; - sp_digit* r; + sp_digit* a = NULL; + sp_digit* m = NULL; + sp_digit* r = NULL; sp_digit e[1] = {0}; int err = MP_OKAY; @@ -7221,10 +7221,10 @@ int sp_RsaPrivate_3072(const byte* in, word32 inLen, mp_int* dm, { #if defined(SP_RSA_PRIVATE_EXP_D) || defined(RSA_LOW_MEM) #if (defined(WOLFSSL_SP_SMALL) || defined(WOLFSSL_SMALL_STACK)) && !defined(WOLFSSL_SP_NO_MALLOC) - sp_digit* a; + sp_digit* a = NULL; sp_digit* d = NULL; - sp_digit* m; - sp_digit* r; + sp_digit* m = NULL; + sp_digit* r = NULL; int err = MP_OKAY; (void)pm; @@ -7321,15 +7321,15 @@ int sp_RsaPrivate_3072(const byte* in, word32 inLen, mp_int* dm, #else #if (defined(WOLFSSL_SP_SMALL) || defined(WOLFSSL_SMALL_STACK)) && !defined(WOLFSSL_SP_NO_MALLOC) sp_digit* t = NULL; - sp_digit* a; - sp_digit* p; - sp_digit* q; - sp_digit* dp; - sp_digit* dq; - sp_digit* qi; - sp_digit* tmpa; - sp_digit* tmpb; - sp_digit* r; + sp_digit* a = NULL; + sp_digit* p = NULL; + sp_digit* q = NULL; + sp_digit* dp = NULL; + sp_digit* dq = NULL; + sp_digit* qi = NULL; + sp_digit* tmpa = NULL; + sp_digit* tmpb = NULL; + sp_digit* r = NULL; int err = MP_OKAY; (void)dm; @@ -10213,7 +10213,7 @@ static int sp_4096_mod_exp_39(sp_digit* r, const sp_digit* a, const sp_digit* e, sp_digit td[(32 * 78) + 78]; #endif sp_digit* t[32]; - sp_digit* rt; + sp_digit* rt = NULL; sp_digit* norm; sp_digit mp = 1; sp_digit n; @@ -11227,7 +11227,7 @@ static int sp_4096_mod_exp_78(sp_digit* r, const sp_digit* a, const sp_digit* e, sp_digit td[(32 * 156) + 156]; #endif sp_digit* t[32]; - sp_digit* rt; + sp_digit* rt = NULL; sp_digit* norm; sp_digit mp = 1; sp_digit n; @@ -11379,10 +11379,10 @@ int sp_RsaPublic_4096(const byte* in, word32 inLen, mp_int* em, mp_int* mm, { #ifdef WOLFSSL_SP_SMALL sp_digit* d = NULL; - sp_digit* a; - sp_digit* m; - sp_digit* r; - sp_digit* norm; + sp_digit* a = NULL; + sp_digit* m = NULL; + sp_digit* r = NULL; + sp_digit* norm = NULL; sp_digit e[1] = {0}; sp_digit mp; int i; @@ -11476,9 +11476,9 @@ int sp_RsaPublic_4096(const byte* in, word32 inLen, mp_int* em, mp_int* mm, #else sp_digit* d = NULL; #endif - sp_digit* a; - sp_digit* m; - sp_digit* r; + sp_digit* a = NULL; + sp_digit* m = NULL; + sp_digit* r = NULL; sp_digit e[1] = {0}; int err = MP_OKAY; @@ -11617,10 +11617,10 @@ int sp_RsaPrivate_4096(const byte* in, word32 inLen, mp_int* dm, { #if defined(SP_RSA_PRIVATE_EXP_D) || defined(RSA_LOW_MEM) #if (defined(WOLFSSL_SP_SMALL) || defined(WOLFSSL_SMALL_STACK)) && !defined(WOLFSSL_SP_NO_MALLOC) - sp_digit* a; + sp_digit* a = NULL; sp_digit* d = NULL; - sp_digit* m; - sp_digit* r; + sp_digit* m = NULL; + sp_digit* r = NULL; int err = MP_OKAY; (void)pm; @@ -11717,15 +11717,15 @@ int sp_RsaPrivate_4096(const byte* in, word32 inLen, mp_int* dm, #else #if (defined(WOLFSSL_SP_SMALL) || defined(WOLFSSL_SMALL_STACK)) && !defined(WOLFSSL_SP_NO_MALLOC) sp_digit* t = NULL; - sp_digit* a; - sp_digit* p; - sp_digit* q; - sp_digit* dp; - sp_digit* dq; - sp_digit* qi; - sp_digit* tmpa; - sp_digit* tmpb; - sp_digit* r; + sp_digit* a = NULL; + sp_digit* p = NULL; + sp_digit* q = NULL; + sp_digit* dp = NULL; + sp_digit* dq = NULL; + sp_digit* qi = NULL; + sp_digit* tmpa = NULL; + sp_digit* tmpb = NULL; + sp_digit* r = NULL; int err = MP_OKAY; (void)dm; diff --git a/wolfcrypt/src/sp_cortexm.c b/wolfcrypt/src/sp_cortexm.c index 5f54b56d66..e930b34bb9 100644 --- a/wolfcrypt/src/sp_cortexm.c +++ b/wolfcrypt/src/sp_cortexm.c @@ -4013,11 +4013,11 @@ int sp_RsaPublic_2048(const byte* in, word32 inLen, mp_int* em, mp_int* mm, sp_digit a[128], m[64], r[128]; #else sp_digit* d = NULL; - sp_digit* a; - sp_digit* m; - sp_digit* r; + sp_digit* a = NULL; + sp_digit* m = NULL; + sp_digit* r = NULL; #endif - sp_digit *ah; + sp_digit *ah = NULL; sp_digit e[1]; int err = MP_OKAY; @@ -4184,10 +4184,10 @@ int sp_RsaPrivate_2048(const byte* in, word32 inLen, mp_int* dm, byte* out, word32* outLen) { #if defined(SP_RSA_PRIVATE_EXP_D) || defined(RSA_LOW_MEM) - sp_digit* a; + sp_digit* a = NULL; sp_digit* d = NULL; - sp_digit* m; - sp_digit* r; + sp_digit* m = NULL; + sp_digit* r = NULL; int err = MP_OKAY; (void)pm; @@ -4246,16 +4246,16 @@ int sp_RsaPrivate_2048(const byte* in, word32 inLen, mp_int* dm, sp_digit tmpa[64], tmpb[64]; #else sp_digit* t = NULL; - sp_digit* a; - sp_digit* p; - sp_digit* q; - sp_digit* dp; - sp_digit* tmpa; - sp_digit* tmpb; + sp_digit* a = NULL; + sp_digit* p = NULL; + sp_digit* q = NULL; + sp_digit* dp = NULL; + sp_digit* tmpa = NULL; + sp_digit* tmpb = NULL; #endif - sp_digit* r; - sp_digit* qi; - sp_digit* dq; + sp_digit* r = NULL; + sp_digit* qi = NULL; + sp_digit* dq = NULL; sp_digit c; int err = MP_OKAY; @@ -8668,11 +8668,11 @@ int sp_RsaPublic_3072(const byte* in, word32 inLen, mp_int* em, mp_int* mm, sp_digit a[192], m[96], r[192]; #else sp_digit* d = NULL; - sp_digit* a; - sp_digit* m; - sp_digit* r; + sp_digit* a = NULL; + sp_digit* m = NULL; + sp_digit* r = NULL; #endif - sp_digit *ah; + sp_digit *ah = NULL; sp_digit e[1]; int err = MP_OKAY; @@ -8839,10 +8839,10 @@ int sp_RsaPrivate_3072(const byte* in, word32 inLen, mp_int* dm, byte* out, word32* outLen) { #if defined(SP_RSA_PRIVATE_EXP_D) || defined(RSA_LOW_MEM) - sp_digit* a; + sp_digit* a = NULL; sp_digit* d = NULL; - sp_digit* m; - sp_digit* r; + sp_digit* m = NULL; + sp_digit* r = NULL; int err = MP_OKAY; (void)pm; @@ -8901,16 +8901,16 @@ int sp_RsaPrivate_3072(const byte* in, word32 inLen, mp_int* dm, sp_digit tmpa[96], tmpb[96]; #else sp_digit* t = NULL; - sp_digit* a; - sp_digit* p; - sp_digit* q; - sp_digit* dp; - sp_digit* tmpa; - sp_digit* tmpb; + sp_digit* a = NULL; + sp_digit* p = NULL; + sp_digit* q = NULL; + sp_digit* dp = NULL; + sp_digit* tmpa = NULL; + sp_digit* tmpb = NULL; #endif - sp_digit* r; - sp_digit* qi; - sp_digit* dq; + sp_digit* r = NULL; + sp_digit* qi = NULL; + sp_digit* dq = NULL; sp_digit c; int err = MP_OKAY; @@ -11875,11 +11875,11 @@ int sp_RsaPublic_4096(const byte* in, word32 inLen, mp_int* em, mp_int* mm, sp_digit a[256], m[128], r[256]; #else sp_digit* d = NULL; - sp_digit* a; - sp_digit* m; - sp_digit* r; + sp_digit* a = NULL; + sp_digit* m = NULL; + sp_digit* r = NULL; #endif - sp_digit *ah; + sp_digit *ah = NULL; sp_digit e[1]; int err = MP_OKAY; @@ -12047,10 +12047,10 @@ int sp_RsaPrivate_4096(const byte* in, word32 inLen, mp_int* dm, byte* out, word32* outLen) { #if defined(SP_RSA_PRIVATE_EXP_D) || defined(RSA_LOW_MEM) - sp_digit* a; + sp_digit* a = NULL; sp_digit* d = NULL; - sp_digit* m; - sp_digit* r; + sp_digit* m = NULL; + sp_digit* r = NULL; int err = MP_OKAY; (void)pm; @@ -12109,16 +12109,16 @@ int sp_RsaPrivate_4096(const byte* in, word32 inLen, mp_int* dm, sp_digit tmpa[128], tmpb[128]; #else sp_digit* t = NULL; - sp_digit* a; - sp_digit* p; - sp_digit* q; - sp_digit* dp; - sp_digit* tmpa; - sp_digit* tmpb; + sp_digit* a = NULL; + sp_digit* p = NULL; + sp_digit* q = NULL; + sp_digit* dp = NULL; + sp_digit* tmpa = NULL; + sp_digit* tmpb = NULL; #endif - sp_digit* r; - sp_digit* qi; - sp_digit* dq; + sp_digit* r = NULL; + sp_digit* qi = NULL; + sp_digit* dq = NULL; sp_digit c; int err = MP_OKAY; From d02e52e07ba44b8f9fadfa705a711d33e0751408 Mon Sep 17 00:00:00 2001 From: Martin Akman Date: Wed, 22 Jul 2020 09:49:09 +1000 Subject: [PATCH 40/60] More updates from code review --- src/ssl.c | 3 --- wolfcrypt/src/asn.c | 32 +++++++++++++++++---------- wolfcrypt/src/random.c | 50 +++++++++++++++++++++--------------------- 3 files changed, 46 insertions(+), 39 deletions(-) diff --git a/src/ssl.c b/src/ssl.c index 45c0151ecb..149594eb07 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -4992,9 +4992,6 @@ int AddCA(WOLFSSL_CERT_MANAGER* cm, DerBuffer** pDer, int type, int verify) #elif defined(SMALL_SESSION_CACHE) #define SESSIONS_PER_ROW 2 #define SESSION_ROWS 3 - #elif defined(VERY_SMALL_SESSION_CACHE) - #define SESSIONS_PER_ROW 2 - #define SESSION_ROWS 1 #else #define SESSIONS_PER_ROW 3 #define SESSION_ROWS 11 diff --git a/wolfcrypt/src/asn.c b/wolfcrypt/src/asn.c index bba9aed5be..5b4fb9e595 100644 --- a/wolfcrypt/src/asn.c +++ b/wolfcrypt/src/asn.c @@ -6122,14 +6122,6 @@ static WC_INLINE int GetTime(int* value, const byte* date, int* idx) int ExtractDate(const unsigned char* date, unsigned char format, struct tm* certTime, int* idx) { - /* Extract the time from the struct tm - 16bit processors store as uint8_t */ - int tm_year = certTime->tm_year; - int tm_mon = certTime->tm_mon; - int tm_mday = certTime->tm_mday; - int tm_hour = certTime->tm_hour; - int tm_min = certTime->tm_min; - int tm_sec = certTime->tm_sec; - XMEMSET(certTime, 0, sizeof(struct tm)); if (format == ASN_UTC_TIME) { @@ -6143,9 +6135,16 @@ int ExtractDate(const unsigned char* date, unsigned char format, certTime->tm_year *= 100; } - /* adjust tm_year, tm_mon */ - tm_year -= 1900; - tm_mon -= 1; +#ifdef AVR + /* Extract the time from the struct tm and adjust tm_year, tm_mon */ + /* AVR libc stores these as uint8_t instead of int */ + /* AVR time_t also offsets from midnight 1 Jan 2000 */ + int tm_year = certTime->tm_year - 2000; + int tm_mon = certTime->tm_mon - 1; + int tm_mday = certTime->tm_mday; + int tm_hour = certTime->tm_hour; + int tm_min = certTime->tm_min; + int tm_sec = certTime->tm_sec; if (GetTime(&tm_year, date, idx) != 0) return 0; if (GetTime(&tm_mon , date, idx) != 0) return 0; @@ -6161,6 +6160,17 @@ int ExtractDate(const unsigned char* date, unsigned char format, certTime->tm_hour = tm_hour; certTime->tm_min = tm_min; certTime->tm_sec = tm_sec; +#else + /* adjust tm_year, tm_mon */ + if (GetTime(&certTime->tm_year, date, idx) != 0) return 0; + certTime->tm_year -= 1900; + if (GetTime(&certTime->tm_mon , date, idx) != 0) return 0; + certTime->tm_mon -= 1; + if (GetTime(&certTime->tm_mday, date, idx) != 0) return 0; + if (GetTime(&certTime->tm_hour, date, idx) != 0) return 0; + if (GetTime(&certTime->tm_min , date, idx) != 0) return 0; + if (GetTime(&certTime->tm_sec , date, idx) != 0) return 0; +#endif return 1; } diff --git a/wolfcrypt/src/random.c b/wolfcrypt/src/random.c index c20e43a9f1..453d1315e8 100644 --- a/wolfcrypt/src/random.c +++ b/wolfcrypt/src/random.c @@ -1102,20 +1102,20 @@ exit_rng_ht: } -const FLASH_QUALIFIER byte _seedA[] = { +const FLASH_QUALIFIER byte seedA_data[] = { 0x63, 0x36, 0x33, 0x77, 0xe4, 0x1e, 0x86, 0x46, 0x8d, 0xeb, 0x0a, 0xb4, 0xa8, 0xed, 0x68, 0x3f, 0x6a, 0x13, 0x4e, 0x47, 0xe0, 0x14, 0xc7, 0x00, 0x45, 0x4e, 0x81, 0xe9, 0x53, 0x58, 0xa5, 0x69, 0x80, 0x8a, 0xa3, 0x8f, 0x2a, 0x72, 0xa6, 0x23, 0x59, 0x91, 0x5a, 0x9f, 0x8a, 0x04, 0xca, 0x68 }; -const FLASH_QUALIFIER byte _reseedSeedA[] = { +const FLASH_QUALIFIER byte reseedSeedA_data[] = { 0xe6, 0x2b, 0x8a, 0x8e, 0xe8, 0xf1, 0x41, 0xb6, 0x98, 0x05, 0x66, 0xe3, 0xbf, 0xe3, 0xc0, 0x49, 0x03, 0xda, 0xd4, 0xac, 0x2c, 0xdf, 0x9f, 0x22, 0x80, 0x01, 0x0a, 0x67, 0x39, 0xbc, 0x83, 0xd3 }; -const FLASH_QUALIFIER byte _outputA[] = { +const FLASH_QUALIFIER byte outputA_data[] = { 0x04, 0xee, 0xc6, 0x3b, 0xb2, 0x31, 0xdf, 0x2c, 0x63, 0x0a, 0x1a, 0xfb, 0xe7, 0x24, 0x94, 0x9d, 0x00, 0x5a, 0x58, 0x78, 0x51, 0xe1, 0xaa, 0x79, 0x5e, 0x47, 0x73, 0x47, 0xc8, 0xb0, 0x56, 0x62, 0x1c, 0x18, 0xbd, 0xdc, @@ -1129,7 +1129,7 @@ const FLASH_QUALIFIER byte _outputA[] = { 0xa1, 0x80, 0x18, 0x3a, 0x07, 0xdf, 0xae, 0x17 }; -const FLASH_QUALIFIER byte _seedB[] = { +const FLASH_QUALIFIER byte seedB_data[] = { 0xa6, 0x5a, 0xd0, 0xf3, 0x45, 0xdb, 0x4e, 0x0e, 0xff, 0xe8, 0x75, 0xc3, 0xa2, 0xe7, 0x1f, 0x42, 0xc7, 0x12, 0x9d, 0x62, 0x0f, 0xf5, 0xc1, 0x19, 0xa9, 0xef, 0x55, 0xf0, 0x51, 0x85, 0xe0, 0xfb, /* nonce next */ @@ -1137,7 +1137,7 @@ const FLASH_QUALIFIER byte _seedB[] = { 0xdb, 0xcb, 0xcc, 0x2e }; -const FLASH_QUALIFIER byte _outputB[] = { +const FLASH_QUALIFIER byte outputB_data[] = { 0xd3, 0xe1, 0x60, 0xc3, 0x5b, 0x99, 0xf3, 0x40, 0xb2, 0x62, 0x82, 0x64, 0xd1, 0x75, 0x10, 0x60, 0xe0, 0x04, 0x5d, 0xa3, 0x83, 0xff, 0x57, 0xa5, 0x7d, 0x73, 0xa6, 0x73, 0xd2, 0xb8, 0xd8, 0x0d, 0xaa, 0xf6, 0xa6, 0xc3, @@ -1171,11 +1171,11 @@ static int wc_RNG_HealthTestLocal(int reseed) if (reseed) { #ifdef WOLFSSL_USE_FLASHMEM - byte* seedA = (byte*)XMALLOC(sizeof(_seedA), NULL, + byte* seedA = (byte*)XMALLOC(sizeof(seedA_data), NULL, DYNAMIC_TYPE_TMP_BUFFER); - byte* reseedSeedA = (byte*)XMALLOC(sizeof(_reseedSeedA), NULL, + byte* reseedSeedA = (byte*)XMALLOC(sizeof(reseedSeedA_data), NULL, DYNAMIC_TYPE_TMP_BUFFER); - byte* outputA = (byte*)XMALLOC(sizeof(_outputA), NULL, + byte* outputA = (byte*)XMALLOC(sizeof(outputA_data), NULL, DYNAMIC_TYPE_TMP_BUFFER); if (!seedA || !reseedSeedA || !outputA) { @@ -1185,16 +1185,16 @@ static int wc_RNG_HealthTestLocal(int reseed) ret = MEMORY_E; } else { - XMEMCPY_P(seedA, _seedA, sizeof(_seedA)); - XMEMCPY_P(reseedSeedA, _reseedSeedA, sizeof(_reseedSeedA)); - XMEMCPY_P(outputA, _outputA, sizeof(_outputA)); + XMEMCPY_P(seedA, seedA_data, sizeof(seedA_data)); + XMEMCPY_P(reseedSeedA, reseedSeedA_data, sizeof(reseedSeedA_data)); + XMEMCPY_P(outputA, outputA_data, sizeof(outputA_data)); #else - const byte* seedA = _seedA; - const byte* reseedSeedA = _reseedSeedA; - const byte* outputA = _outputA; + const byte* seedA = seedA_data; + const byte* reseedSeedA = reseedSeedA_data; + const byte* outputA = outputA_data; #endif - ret = wc_RNG_HealthTest(1, seedA, sizeof(_seedA), - reseedSeedA, sizeof(_reseedSeedA), + ret = wc_RNG_HealthTest(1, seedA, sizeof(seedA_data), + reseedSeedA, sizeof(reseedSeedA_data), check, RNG_HEALTH_TEST_CHECK_SIZE); if (ret == 0) { if (ConstantCompare(check, outputA, @@ -1211,9 +1211,9 @@ static int wc_RNG_HealthTestLocal(int reseed) } else { #ifdef WOLFSSL_USE_FLASHMEM - byte* seedB = (byte*)XMALLOC(sizeof(_seedB), NULL, + byte* seedB = (byte*)XMALLOC(sizeof(seedB_data), NULL, DYNAMIC_TYPE_TMP_BUFFER); - byte* outputB = (byte*)XMALLOC(sizeof(_outputB), NULL, + byte* outputB = (byte*)XMALLOC(sizeof(outputB_data), NULL, DYNAMIC_TYPE_TMP_BUFFER); if (!seedB || !outputB) { @@ -1222,13 +1222,13 @@ static int wc_RNG_HealthTestLocal(int reseed) ret = MEMORY_E; } else { - XMEMCPY_P(seedB, _seedB, sizeof(_seedB)); - XMEMCPY_P(outputB, _outputB, sizeof(_outputB)); + XMEMCPY_P(seedB, seedB_data, sizeof(seedB_data)); + XMEMCPY_P(outputB, outputB_data, sizeof(outputB_data)); #else - const byte* seedB = _seedB; - const byte* outputB = _outputB; + const byte* seedB = seedB_data; + const byte* outputB = outputB_data; #endif - ret = wc_RNG_HealthTest(0, seedB, sizeof(_seedB), + ret = wc_RNG_HealthTest(0, seedB, sizeof(seedB_data), NULL, 0, check, RNG_HEALTH_TEST_CHECK_SIZE); if (ret == 0) { @@ -1243,13 +1243,13 @@ static int wc_RNG_HealthTestLocal(int reseed) * byte 32, feed them into the health test separately. */ if (ret == 0) { ret = wc_RNG_HealthTest_ex(0, - seedB + 32, sizeof(_seedB) - 32, + seedB + 32, sizeof(seedB_data) - 32, seedB, 32, NULL, 0, check, RNG_HEALTH_TEST_CHECK_SIZE, NULL, INVALID_DEVID); if (ret == 0) { - if (ConstantCompare(check, outputB, sizeof(_outputB)) != 0) + if (ConstantCompare(check, outputB, sizeof(outputB_data)) != 0) ret = -1; } } From 563806c497faee5ee2f41300dcc51ddfe56425a6 Mon Sep 17 00:00:00 2001 From: Ethan Looney Date: Thu, 23 Jul 2020 10:12:40 -0700 Subject: [PATCH 41/60] Changed the log dump txt file's directory to include /tests and added it to make clean --- Makefile.am | 3 ++- scripts/cleanup_testfiles.sh | 2 +- tests/api.c | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/Makefile.am b/Makefile.am index 37533fa230..94ce2f6801 100644 --- a/Makefile.am +++ b/Makefile.am @@ -118,7 +118,8 @@ CLEANFILES+= cert.der \ pkcs7signedEncryptedCompressedFirmwarePkgData_ECDSA_SHA256.der \ pkcs7signedEncryptedCompressedFirmwarePkgData_ECDSA_SHA256_noattr.der \ pkcs7signedEncryptedCompressedFirmwarePkgData_RSA_SHA256.der \ - pkcs7signedEncryptedCompressedFirmwarePkgData_RSA_SHA256_noattr.der + pkcs7signedEncryptedCompressedFirmwarePkgData_RSA_SHA256_noattr.der \ + tests/test-log-dump-to-file.txt exampledir = $(docdir)/example dist_example_DATA= diff --git a/scripts/cleanup_testfiles.sh b/scripts/cleanup_testfiles.sh index f4ffd69061..5d96211ed2 100755 --- a/scripts/cleanup_testfiles.sh +++ b/scripts/cleanup_testfiles.sh @@ -12,4 +12,4 @@ rm -f ./certeccrsa.der rm -f ./ecc-key.der rm -f ./ecc-key.pem rm -f ./ecc-public-key.der -rm -f ./test-log-dump-to-file.txt +rm -f ./tests/test-log-dump-to-file.txt diff --git a/tests/api.c b/tests/api.c index 3664e615f1..77e4054844 100644 --- a/tests/api.c +++ b/tests/api.c @@ -27192,7 +27192,7 @@ static int test_wc_ERR_print_errors_fp (void) printf(testingFmt, "wc_ERR_print_errors_fp()"); WOLFSSL_ERROR(BAD_FUNC_ARG); - XFILE fp = XFOPEN("./test-log-dump-to-file.txt", "ar"); + XFILE fp = XFOPEN("./tests/test-log-dump-to-file.txt", "ar"); wc_ERR_print_errors_fp(fp); AssertTrue(XFSEEK(fp, 0, XSEEK_END) == 0); From 3c5c0f88d44c16a0e392c4b971b0307714b71f0a Mon Sep 17 00:00:00 2001 From: kaleb-himes Date: Thu, 23 Jul 2020 12:20:41 -0600 Subject: [PATCH 42/60] Address buffer underflow, thanks to J.S. for the report on ZD10580 --- wolfcrypt/src/asn.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/wolfcrypt/src/asn.c b/wolfcrypt/src/asn.c index 54f91d7b8b..f9c90a7455 100644 --- a/wolfcrypt/src/asn.c +++ b/wolfcrypt/src/asn.c @@ -10555,9 +10555,22 @@ int PemToDer(const unsigned char* buff, long longSz, int type, #ifndef NO_WOLFSSL_SKIP_TRAILING_PAD #ifndef NO_DES3 if (info->cipherType == WC_CIPHER_DES3) { - padVal = der->buffer[der->length-1]; - if (padVal <= DES_BLOCK_SIZE) { - der->length -= padVal; + /* Assuming there is padding: + * (der->length > 0 && + * (der->length % DES_BLOCK_SIZE) != 0) + * and assuming the last value signifies the number of + * padded bytes IE if last value is 0x08 then there are + * 8 bytes of padding: + * padVal = der->buffer[der->length-1]; + * then strip this padding before proceeding: + * der->length -= padVal; + */ + if (der->length > 0 && + (der->length % DES_BLOCK_SIZE) != 0) { + padVal = der->buffer[der->length-1]; + if (padVal <= DES_BLOCK_SIZE) { + der->length -= padVal; + } } } #endif /* !NO_DES3 */ From 839044d9e11c4897b0f5c9c3ec50f9ceee3417cb Mon Sep 17 00:00:00 2001 From: John Safranek Date: Thu, 23 Jul 2020 12:26:49 -0700 Subject: [PATCH 43/60] 1. Remove dead assignment from client test. 2. Fix memory leak in example server test. 3. Use verify callback on certificates to allow callback to fail them. 4. Restore the forced failure test cases. 5. Make the verify action thread local. --- examples/client/client.c | 1 - examples/server/server.c | 7 +++++-- src/internal.c | 2 ++ tests/test-fails.conf | 9 +-------- wolfssl/test.h | 2 +- 5 files changed, 9 insertions(+), 12 deletions(-) diff --git a/examples/client/client.c b/examples/client/client.c index c87429b779..4865086297 100644 --- a/examples/client/client.c +++ b/examples/client/client.c @@ -593,7 +593,6 @@ static int ClientBenchmarkThroughput(WOLFSSL_CTX* ctx, char* host, word16 port, printf("SSL_write bench error %d!\n", err); if (!exitWithRet) err_sys("SSL_write failed"); - ret = err; goto doExit; } tx_time += current_time(0) - start; diff --git a/examples/server/server.c b/examples/server/server.c index 5394c16814..44bc313489 100644 --- a/examples/server/server.c +++ b/examples/server/server.c @@ -381,8 +381,10 @@ int ServerEchoData(SSL* ssl, int clientfd, int echoData, int block, err_sys_ex(runWithErrors, "SSL_read failed"); break; } - if (err == WOLFSSL_ERROR_ZERO_RETURN) + if (err == WOLFSSL_ERROR_ZERO_RETURN) { + free(buffer); return WOLFSSL_ERROR_ZERO_RETURN; + } } else { rx_pos += ret; @@ -1813,7 +1815,8 @@ THREAD_RETURN WOLFSSL_THREAD server_test(void* args) SSL_CTX_set_verify(ctx, WOLFSSL_VERIFY_PEER | (usePskPlus ? WOLFSSL_VERIFY_FAIL_EXCEPT_PSK : WOLFSSL_VERIFY_FAIL_IF_NO_PEER_CERT), - myVerifyAction == VERIFY_OVERRIDE_DATE_ERR ? myVerify : NULL); + (myVerifyAction == VERIFY_OVERRIDE_DATE_ERR || + myVerifyAction == VERIFY_FORCE_FAIL) ? myVerify : NULL); #ifdef TEST_BEFORE_DATE verify_flags |= WOLFSSL_LOAD_FLAG_DATE_ERR_OKAY; diff --git a/src/internal.c b/src/internal.c index 39af97f692..29d9a5748d 100644 --- a/src/internal.c +++ b/src/internal.c @@ -10007,6 +10007,8 @@ int DoVerifyCallback(WOLFSSL_CERT_MANAGER* cm, WOLFSSL* ssl, int ret, /* Determine if verify was okay */ if (ret == 0) { verify_ok = 1; + use_cb = 1; /* use verify callback on success, in case callback + * could force fail a cert */ } /* Determine if verify callback should be used */ diff --git a/tests/test-fails.conf b/tests/test-fails.conf index 40afb54e0f..d1dd444175 100644 --- a/tests/test-fails.conf +++ b/tests/test-fails.conf @@ -114,7 +114,6 @@ # server -v 3 -l ECDHE-RSA-AES128-GCM-SHA256 --H verifyFail # client verify should fail -v 3 @@ -129,12 +128,10 @@ # client -v 3 -l ECDHE-RSA-AES128-GCM-SHA256 --H verifyFail # server -v 3 -l ECDHE-ECDSA-AES128-GCM-SHA256 --H verifyFail # client verify should fail -v 3 @@ -149,7 +146,6 @@ # client -v 3 -l ECDHE-ECDSA-AES128-GCM-SHA256 --H verifyFail # error going into callback, return error # server @@ -157,7 +153,6 @@ -l ECDHE-RSA-AES128-GCM-SHA256 -c ./certs/test/server-cert-rsa-badsig.pem -k ./certs/server-key.pem --H verifyFail # client verify should fail -v 3 @@ -169,7 +164,6 @@ -l ECDHE-ECDSA-AES128-GCM-SHA256 -c ./certs/test/server-cert-ecc-badsig.pem -k ./certs/ecc-key.pem --H verifyFail # client verify should fail -v 3 @@ -179,12 +173,10 @@ # server send alert on no mutual authentication -v 3 -F --H verifyFail # client send alert on no mutual authentication -v 3 -x --H verifyFail # server TLSv1.3 fail on no client certificate # server always sets WOLFSSL_VERIFY_FAIL_IF_NO_PEER_CERT unless using -d @@ -195,3 +187,4 @@ -v 4 -l TLS13-AES128-GCM-SHA256 -x + diff --git a/wolfssl/test.h b/wolfssl/test.h index 385a3be211..aff5c4d65f 100644 --- a/wolfssl/test.h +++ b/wolfssl/test.h @@ -1684,7 +1684,7 @@ enum { VERIFY_USE_PREVERFIY, VERIFY_OVERRIDE_DATE_ERR, }; -static int myVerifyAction = VERIFY_OVERRIDE_ERROR; +static THREAD_LS_T int myVerifyAction = VERIFY_OVERRIDE_ERROR; /* The verify callback is called for every certificate only when * --enable-opensslextra is defined because it sets WOLFSSL_ALWAYS_VERIFY_CB and From 6bc4bfd7f2a8c4fd34c4cc0e5460b64abbb50f4e Mon Sep 17 00:00:00 2001 From: Ethan Looney Date: Thu, 23 Jul 2020 13:25:18 -0700 Subject: [PATCH 44/60] Added doxygen comments to include all missing ABI functions and changed footer date from 2017 to 2020 --- doc/dox_comments/header_files/ecc.h | 68 ++++++++++ doc/dox_comments/header_files/random.h | 60 +++++++++ doc/dox_comments/header_files/ssl.h | 172 +++++++++++++++++++++++++ doc/formats/html/footer.html | 2 +- 4 files changed, 301 insertions(+), 1 deletion(-) diff --git a/doc/dox_comments/header_files/ecc.h b/doc/dox_comments/header_files/ecc.h index 1128af9e4f..a843d9b2ea 100644 --- a/doc/dox_comments/header_files/ecc.h +++ b/doc/dox_comments/header_files/ecc.h @@ -149,6 +149,28 @@ int wc_ecc_make_key_ex(WC_RNG* rng, int keysize, ecc_key* key, int curve_id); WOLFSSL_API int wc_ecc_check_key(ecc_key* key); +/*! + \ingroup ECC + + \brief This function frees an ecc_key key after it has been used. + + \return int integer returned indicating wolfSSL error or success status. + + \param key pointer to the ecc_key object to free + + _Example_ + \code + // initialize key and perform secure exchanges + ... + wc_ecc_key_free(&key); + \endcode + + \sa wc_ecc_key_new + \sa wc_ecc_init_ex +*/ +WOLFSSL_API +int wc_ecc_key_free(ecc_key* key); + /*! \ingroup ECC @@ -541,6 +563,52 @@ int wc_ecc_verify_hash_ex(mp_int *r, mp_int *s, const byte* hash, WOLFSSL_API int wc_ecc_init(ecc_key* key); +/*! + \ingroup ECC + + \brief This function initializes an ecc_key object for future + use with message verification or key negotiation. + + \return 0 Returned upon successfully initializing the ecc_key object + \return MEMORY_E Returned if there is an error allocating memory + + \param key pointer to the ecc_key object to initialize + + _Example_ + \code + ecc_key key; + wc_ecc_init_ex(&key, heap, devId); + \endcode + + \sa wc_ecc_make_key + \sa wc_ecc_free + \sa wc_ecc_init +*/ +WOLFSSL_API +int wc_ecc_init_ex(ecc_key* key, void* heap, int devId); + +/*! + \ingroup ECC + + \brief This function uses a user defined heap and allocates space for the + key structure. + + \return 0 Returned upon successfully initializing the ecc_key object + \return MEMORY_E Returned if there is an error allocating memory + + + _Example_ + \code + wc_ecc_key_new(&heap); + \endcode + + \sa wc_ecc_make_key + \sa wc_ecc_key_free + \sa wc_ecc_init +*/ +WOLFSSL_API +ecc_key* wc_ecc_key_new(void* heap); + /*! \ingroup ECC diff --git a/doc/dox_comments/header_files/random.h b/doc/dox_comments/header_files/random.h index 366dc8908d..9bd52c0155 100644 --- a/doc/dox_comments/header_files/random.h +++ b/doc/dox_comments/header_files/random.h @@ -137,6 +137,36 @@ WOLFSSL_API int wc_InitRng(WC_RNG*); */ WOLFSSL_API int wc_RNG_GenerateBlock(WC_RNG*, byte*, word32 sz); +/*! + \ingroup Random + + \brief Creates a new random number. + + + \return rng on success + \return NULL on error + + + \param rng random number generator initialized with wc_InitRng + + _Example_ + \code + RNG rng; + byte nonce[] = { initialize nonce }; + word32 nonceSz = sizeof(nonce); + + wc_rng_new(&nonce, nonceSz, &heap); + + + \endcode + + \sa wc_InitRng + \sa wc_rng_free + \sa wc_FreeRng + \sa wc_RNG_HealthTest +*/ +WOLFSSL_API WC_RNG* wc_rng_new(byte* nonce, word32 nonceSz, void* heap) + /*! \ingroup Random @@ -211,6 +241,36 @@ WOLFSSL_API int wc_RNG_GenerateByte(WC_RNG*, byte*); */ WOLFSSL_API int wc_FreeRng(WC_RNG*); +/*! + \ingroup Random + + \brief Should be called when RNG no longer needed in order to securely + free rng. + + + \param rng random number generator initialized with wc_InitRng + + _Example_ + \code + RNG rng; + byte nonce[] = { initialize nonce }; + word32 nonceSz = sizeof(nonce); + + rng = wc_rng_new(&nonce, nonceSz, &heap); + + // use rng + + wc_rng_free(&rng); + + \endcode + + \sa wc_InitRng + \sa wc_rng_new + \sa wc_FreeRng + \sa wc_RNG_HealthTest +*/ +WOLFSSL_API WC_RNG* wc_rng_free(WC_RNG* rng); + /*! \ingroup Random diff --git a/doc/dox_comments/header_files/ssl.h b/doc/dox_comments/header_files/ssl.h index eb25908f07..fd07ec3cd0 100644 --- a/doc/dox_comments/header_files/ssl.h +++ b/doc/dox_comments/header_files/ssl.h @@ -2698,6 +2698,72 @@ WOLFSSL_API void wolfSSL_load_error_strings(void); */ WOLFSSL_API int wolfSSL_library_init(void); +/*! + \brief This function sets the Device Id. + + \return WOLFSSL_SUCCESS upon success. + \return BAD_FUNC_ARG if ssl is NULL. + + \param ssl pointer to a SSL object, created with wolfSSL_new(). + + _Example_ + \code + WOLFSSL* ssl; + int DevId = -2; + + wolfSSL_SetDevId(ssl, devId); + + \endcode + + \sa wolfSSL_CTX_SetDevId + \sa wolfSSL_CTX_GetDevId +*/ +WOLFSSL_API int wolfSSL_SetDevId(WOLFSSL* ssl, int devId) + +/*! + \brief This function sets the Device Id. + + \return WOLFSSL_SUCCESS upon success. + \return BAD_FUNC_ARG if ssl is NULL. + + \param ssl pointer to a SSL object, created with wolfSSL_CTX_new(). + + _Example_ + \code + WOLFSSL_CTX* ctx; + int DevId = -2; + + wolfSSL_CTX_SetDevId(ctx, devId); + + \endcode + + \sa wolfSSL_SetDevId + \sa wolfSSL_CTX_GetDevId +*/ +WOLFSSL_API int wolfSSL_CTX_SetDevId(WOLFSSL_CTX* ctx, int devId) + +/*! + \brief This function retrieves the Device Id. + + \return devId upon success. + \return INVALID_DEVID if both ssl and ctx are NULL. + + \param ssl pointer to a SSL object, created with wolfSSL_CTX_new(). + + _Example_ + \code + WOLFSSL_CTX* ctx; + + wolfSSL_CTX_GetDevId(ctx, ssl); + + \endcode + + \sa wolfSSL_SetDevId + \sa wolfSSL_CTX_SetDevId + +*/ +WOLFSSL_API int wolfSSL_CTX_GetDevId(WOLFSSL_CTX* ctx, WOLFSSL* ssl); + /*! \ingroup Setup @@ -4423,6 +4489,31 @@ WOLFSSL_API int wolfSSL_X509_NAME_get_text_by_NID( */ WOLFSSL_API int wolfSSL_X509_get_signature_type(WOLFSSL_X509*); +/*! + \brief This function frees an external WOLFSSL_X509 structure. + + + \param x509 a pointer to the WOLFSSL_X509 struct. + + _Example_ + \code + WOLFSSL_X509* x509 = (WOLFSSL_X509)XMALOC(sizeof(WOLFSSL_X509), NULL, + DYNAMIC_TYPE_X509) ; + + wolfSSL_X509_free(x509); + + \endcode + + \sa wolfSSL_X509_get_signature + \sa wolfSSL_X509_version + \sa wolfSSL_X509_get_der + \sa wolfSSL_X509_get_serial_number + \sa wolfSSL_X509_notBefore + \sa wolfSSL_X509_notAfter + +*/ +WOLFSSL_API void wolfSSL_X509_free(WOLFSSL_X509* x509); + /*! \ingroup CertsKeys @@ -4538,6 +4629,66 @@ WOLFSSL_API WOLFSSL_STACK* wolfSSL_X509_STORE_CTX_get_chain( WOLFSSL_API int wolfSSL_X509_STORE_set_flags(WOLFSSL_X509_STORE* store, unsigned long flag); +/*! + \ingroup CertsKeys + + \brief This function returns the value stored in the sigOID + member of the WOLFSSL_X509 structure. + + \return NULL returned if the WOLFSSL_X509 structure is NULL. + \return byte is returned that contains the notBeforeData. + + \param ssl a pointer to a WOLFSSL structure, created using wolfSSL_new(). + + _Example_ + \code + WOLFSSL_X509 x509 = (WOLFSSL_X509*)XMALLOC(sizeof(WOLFSSL_X509), NULL, + DYNAMIC_TYPE_X509); + ... + byte notBeforeData = wolfSSL_X509_notBefore(x509); + + + \endcode + + \sa wolfSSL_X509_get_signature + \sa wolfSSL_X509_version + \sa wolfSSL_X509_get_der + \sa wolfSSL_X509_get_serial_number + \sa wolfSSL_X509_notAfter + \sa wolfSSL_X509_free +*/ +WOLFSSL_API const byte* wolfSSL_X509_notBefore(WOLFSSL_X509* x509); + +/*! + \ingroup CertsKeys + + \brief This function returns the value stored in the sigOID + member of the WOLFSSL_X509 structure. + + \return NULL returned if the WOLFSSL_X509 structure is NULL. + \return byte is returned that contains the notAfterData. + + \param ssl a pointer to a WOLFSSL structure, created using wolfSSL_new(). + + _Example_ + \code + WOLFSSL_X509 x509 = (WOLFSSL_X509*)XMALLOC(sizeof(WOLFSSL_X509), NULL, + DYNAMIC_TYPE_X509); + ... + byte notAfterData = wolfSSL_X509_notAfter(x509); + + + \endcode + + \sa wolfSSL_X509_get_signature + \sa wolfSSL_X509_version + \sa wolfSSL_X509_get_der + \sa wolfSSL_X509_get_serial_number + \sa wolfSSL_X509_notBefore + \sa wolfSSL_X509_free +*/ +WOLFSSL_API const byte* wolfSSL_X509_notAfter(WOLFSSL_X509* x509); + /*! \ingroup Setup @@ -7604,6 +7755,27 @@ WOLFSSL_API int wolfSSL_DTLS_SetCookieSecret(WOLFSSL*, const unsigned char*, unsigned int); +/*! + \brief This function retrieves the Device Id. + + \return rng upon success. + \return NULL if ssl is NULL. + + \param ssl pointer to a SSL object, created with wolfSSL_CTX_new(). + + _Example_ + \code + WOLFSSL* ssl; + + wolfSSL_GetRNG(ssl); + + \endcode + + \sa wolfSSL_CTX_new_rng + +*/ +WOLFSSL_API WC_RNG* wolfSSL_GetRNG(WOLFSSL* ssl); + /*! \ingroup Setup diff --git a/doc/formats/html/footer.html b/doc/formats/html/footer.html index 996406d4b8..d4f5a624a2 100644 --- a/doc/formats/html/footer.html +++ b/doc/formats/html/footer.html @@ -32,7 +32,7 @@
-

Copyright © 2017 wolfSSL Inc.
All rights reserved.

+

Copyright © 2020 wolfSSL Inc.
All rights reserved.

Help and Support

    From 20ef2daa9ff07bf644a890d34d6d518c6de8c4fc Mon Sep 17 00:00:00 2001 From: David Garske Date: Thu, 23 Jul 2020 14:31:41 -0700 Subject: [PATCH 45/60] Fix for ECC non-blocking to allow calling without context set and block when `WC_ECC_NONBLOCK_ONLY` is defined. In FIPS mode we need "blocking". --- wolfcrypt/src/ecc.c | 56 +++++++++++++++++++++++++++++++++++---------- 1 file changed, 44 insertions(+), 12 deletions(-) diff --git a/wolfcrypt/src/ecc.c b/wolfcrypt/src/ecc.c index 5371505325..11b9dffea9 100644 --- a/wolfcrypt/src/ecc.c +++ b/wolfcrypt/src/ecc.c @@ -4913,35 +4913,50 @@ int wc_ecc_sign_hash_ex(const byte* in, word32 inlen, WC_RNG* rng, #else mp_int* sign_k = NULL; #endif + #ifdef WC_ECC_NONBLOCK_ONLY + /* perform blocking call to non-blocking function */ + ecc_nb_ctx_t nb_ctx; + XMEMSET(&nb_ctx, 0, sizeof(nb_ctx)); + #endif #ifndef WOLFSSL_SP_NO_256 if (ecc_sets[key->idx].id == ECC_SECP256R1) { - #ifdef WC_ECC_NONBLOCK + #if defined(WC_ECC_NONBLOCK) || defined(WC_ECC_NONBLOCK_ONLY) if (key->nb_ctx) { return sp_ecc_sign_256_nb(&key->nb_ctx->sp_ctx, in, inlen, rng, &key->k, r, s, sign_k, key->heap); } + #ifdef WC_ECC_NONBLOCK_ONLY + do { /* perform blocking call to non-blocking function */ + err = sp_ecc_sign_256_nb(&nb_ctx.sp_ctx, in, inlen, rng, + &key->k, r, s, sign_k, key->heap); + } while (err == FP_WOULDBLOCK); + return err; + #endif #endif #ifndef WC_ECC_NONBLOCK_ONLY return sp_ecc_sign_256(in, inlen, rng, &key->k, r, s, sign_k, key->heap); - #else - return NOT_COMPILED_IN; #endif } #endif #ifdef WOLFSSL_SP_384 if (ecc_sets[key->idx].id == ECC_SECP384R1) { - #ifdef WC_ECC_NONBLOCK + #if defined(WC_ECC_NONBLOCK) || defined(WC_ECC_NONBLOCK_ONLY) if (key->nb_ctx) { return sp_ecc_sign_384_nb(&key->nb_ctx->sp_ctx, in, inlen, rng, &key->k, r, s, sign_k, key->heap); } + #ifdef WC_ECC_NONBLOCK_ONLY + do { /* perform blocking call to non-blocking function */ + err = sp_ecc_sign_384_nb(&nb_ctx.sp_ctx, in, inlen, rng, + &key->k, r, s, sign_k, key->heap); + } while (err == FP_WOULDBLOCK); + return err; + #endif #endif #ifndef WC_ECC_NONBLOCK_ONLY return sp_ecc_sign_384(in, inlen, rng, &key->k, r, s, sign_k, key->heap); - #else - return NOT_COMPILED_IN; #endif } #endif @@ -6013,37 +6028,54 @@ int wc_ecc_verify_hash_ex(mp_int *r, mp_int *s, const byte* hash, && key->asyncDev.marker != WOLFSSL_ASYNC_MARKER_ECC #endif ) { + #ifdef WC_ECC_NONBLOCK_ONLY + /* perform blocking call to non-blocking function */ + ecc_nb_ctx_t nb_ctx; + XMEMSET(&nb_ctx, 0, sizeof(nb_ctx)); + #endif #ifndef WOLFSSL_SP_NO_256 if (ecc_sets[key->idx].id == ECC_SECP256R1) { - #ifdef WC_ECC_NONBLOCK + #if defined(WC_ECC_NONBLOCK) || defined(WC_ECC_NONBLOCK_ONLY) if (key->nb_ctx) { return sp_ecc_verify_256_nb(&key->nb_ctx->sp_ctx, hash, hashlen, key->pubkey.x, key->pubkey.y, key->pubkey.z, r, s, res, key->heap); } + #ifdef WC_ECC_NONBLOCK_ONLY + do { /* perform blocking call to non-blocking function */ + err = sp_ecc_verify_256_nb(&nb_ctx->sp_ctx, hash, hashlen, + key->pubkey.x, key->pubkey.y, key->pubkey.z, r, s, res, + key->heap); + } while (err == FP_WOULDBLOCK); + return err; + #endif #endif #ifndef WC_ECC_NONBLOCK_ONLY return sp_ecc_verify_256(hash, hashlen, key->pubkey.x, key->pubkey.y, key->pubkey.z, r, s, res, key->heap); - #else - return NOT_COMPILED_IN; #endif } #endif #ifdef WOLFSSL_SP_384 if (ecc_sets[key->idx].id == ECC_SECP384R1) { - #ifdef WC_ECC_NONBLOCK + #if defined(WC_ECC_NONBLOCK) || defined(WC_ECC_NONBLOCK_ONLY) if (key->nb_ctx) { return sp_ecc_verify_384_nb(&key->nb_ctx->sp_ctx, hash, hashlen, key->pubkey.x, key->pubkey.y, key->pubkey.z, r, s, res, key->heap); } + #ifdef WC_ECC_NONBLOCK_ONLY + do { /* perform blocking call to non-blocking function */ + err = sp_ecc_verify_384_nb(&nb_ctx.sp_ctx, hash, hashlen, + key->pubkey.x, key->pubkey.y, key->pubkey.z, r, s, res, + key->heap); + } while (err == FP_WOULDBLOCK); + return err; + #endif #endif #ifndef WC_ECC_NONBLOCK_ONLY return sp_ecc_verify_384(hash, hashlen, key->pubkey.x, key->pubkey.y, key->pubkey.z, r, s, res, key->heap); - #else - return NOT_COMPILED_IN; #endif } #endif From fd1a1bd0f77df159cfd080bf27f60afb12b1cbb2 Mon Sep 17 00:00:00 2001 From: John Safranek Date: Thu, 23 Jul 2020 14:32:48 -0700 Subject: [PATCH 46/60] Add some missing frees to the example client when using in the return-not-exit mode for tests. --- examples/client/client.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/examples/client/client.c b/examples/client/client.c index 4865086297..fd62cb59f6 100644 --- a/examples/client/client.c +++ b/examples/client/client.c @@ -3165,12 +3165,16 @@ THREAD_RETURN WOLFSSL_THREAD client_test(void* args) err = ClientWrite(ssl, msg, msgSz, "", exitWithRet); if (exitWithRet && (err != 0)) { ((func_args*)args)->return_code = err; + wolfSSL_free(ssl); ssl = NULL; + wolfSSL_CTX_free(ctx); ctx = NULL; goto exit; } err = ClientRead(ssl, reply, sizeof(reply)-1, 1, "", exitWithRet); if (exitWithRet && (err != 0)) { ((func_args*)args)->return_code = err; + wolfSSL_free(ssl); ssl = NULL; + wolfSSL_CTX_free(ctx); ctx = NULL; goto exit; } From 1559d66261c33fd8b9f779c91b506ebc2918fcca Mon Sep 17 00:00:00 2001 From: David Garske Date: Thu, 23 Jul 2020 15:41:09 -0700 Subject: [PATCH 47/60] Fix for `WC_ECC_NONBLOCK_ONLY` case to also check `WC_ECC_NONBLOCK`. --- wolfcrypt/src/ecc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/wolfcrypt/src/ecc.c b/wolfcrypt/src/ecc.c index 11b9dffea9..8af793f55d 100644 --- a/wolfcrypt/src/ecc.c +++ b/wolfcrypt/src/ecc.c @@ -4913,7 +4913,7 @@ int wc_ecc_sign_hash_ex(const byte* in, word32 inlen, WC_RNG* rng, #else mp_int* sign_k = NULL; #endif - #ifdef WC_ECC_NONBLOCK_ONLY + #if defined(WC_ECC_NONBLOCK) && defined(WC_ECC_NONBLOCK_ONLY) /* perform blocking call to non-blocking function */ ecc_nb_ctx_t nb_ctx; XMEMSET(&nb_ctx, 0, sizeof(nb_ctx)); @@ -6028,7 +6028,7 @@ int wc_ecc_verify_hash_ex(mp_int *r, mp_int *s, const byte* hash, && key->asyncDev.marker != WOLFSSL_ASYNC_MARKER_ECC #endif ) { - #ifdef WC_ECC_NONBLOCK_ONLY + #if defined(WC_ECC_NONBLOCK) && defined(WC_ECC_NONBLOCK_ONLY) /* perform blocking call to non-blocking function */ ecc_nb_ctx_t nb_ctx; XMEMSET(&nb_ctx, 0, sizeof(nb_ctx)); From 6324aec179cedba3362285a2f18ac6515b801186 Mon Sep 17 00:00:00 2001 From: David Garske Date: Fri, 24 Jul 2020 09:30:45 -0700 Subject: [PATCH 48/60] Fix for `./configure --enable-sp=yes,nonblock --enable-sp-math CFLAGS="-DWC_ECC_NONBLOCK_ONLY"`. --- wolfcrypt/src/ecc.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/wolfcrypt/src/ecc.c b/wolfcrypt/src/ecc.c index 8af793f55d..fec7903bf9 100644 --- a/wolfcrypt/src/ecc.c +++ b/wolfcrypt/src/ecc.c @@ -4920,7 +4920,7 @@ int wc_ecc_sign_hash_ex(const byte* in, word32 inlen, WC_RNG* rng, #endif #ifndef WOLFSSL_SP_NO_256 if (ecc_sets[key->idx].id == ECC_SECP256R1) { - #if defined(WC_ECC_NONBLOCK) || defined(WC_ECC_NONBLOCK_ONLY) + #ifdef WC_ECC_NONBLOCK if (key->nb_ctx) { return sp_ecc_sign_256_nb(&key->nb_ctx->sp_ctx, in, inlen, rng, &key->k, r, s, sign_k, key->heap); @@ -4932,8 +4932,8 @@ int wc_ecc_sign_hash_ex(const byte* in, word32 inlen, WC_RNG* rng, } while (err == FP_WOULDBLOCK); return err; #endif - #endif - #ifndef WC_ECC_NONBLOCK_ONLY + #endif /* WC_ECC_NONBLOCK */ + #if !defined(WC_ECC_NONBLOCK) || (defined(WC_ECC_NONBLOCK) && !defined(WC_ECC_NONBLOCK_ONLY)) return sp_ecc_sign_256(in, inlen, rng, &key->k, r, s, sign_k, key->heap); #endif @@ -4941,7 +4941,7 @@ int wc_ecc_sign_hash_ex(const byte* in, word32 inlen, WC_RNG* rng, #endif #ifdef WOLFSSL_SP_384 if (ecc_sets[key->idx].id == ECC_SECP384R1) { - #if defined(WC_ECC_NONBLOCK) || defined(WC_ECC_NONBLOCK_ONLY) + #ifdef WC_ECC_NONBLOCK if (key->nb_ctx) { return sp_ecc_sign_384_nb(&key->nb_ctx->sp_ctx, in, inlen, rng, &key->k, r, s, sign_k, key->heap); @@ -4953,8 +4953,8 @@ int wc_ecc_sign_hash_ex(const byte* in, word32 inlen, WC_RNG* rng, } while (err == FP_WOULDBLOCK); return err; #endif - #endif - #ifndef WC_ECC_NONBLOCK_ONLY + #endif /* WC_ECC_NONBLOCK */ + #if !defined(WC_ECC_NONBLOCK) || (defined(WC_ECC_NONBLOCK) && !defined(WC_ECC_NONBLOCK_ONLY)) return sp_ecc_sign_384(in, inlen, rng, &key->k, r, s, sign_k, key->heap); #endif @@ -6035,7 +6035,7 @@ int wc_ecc_verify_hash_ex(mp_int *r, mp_int *s, const byte* hash, #endif #ifndef WOLFSSL_SP_NO_256 if (ecc_sets[key->idx].id == ECC_SECP256R1) { - #if defined(WC_ECC_NONBLOCK) || defined(WC_ECC_NONBLOCK_ONLY) + #ifdef WC_ECC_NONBLOCK if (key->nb_ctx) { return sp_ecc_verify_256_nb(&key->nb_ctx->sp_ctx, hash, hashlen, key->pubkey.x, key->pubkey.y, key->pubkey.z, r, s, res, @@ -6049,8 +6049,8 @@ int wc_ecc_verify_hash_ex(mp_int *r, mp_int *s, const byte* hash, } while (err == FP_WOULDBLOCK); return err; #endif - #endif - #ifndef WC_ECC_NONBLOCK_ONLY + #endif /* WC_ECC_NONBLOCK */ + #if !defined(WC_ECC_NONBLOCK) || (defined(WC_ECC_NONBLOCK) && !defined(WC_ECC_NONBLOCK_ONLY)) return sp_ecc_verify_256(hash, hashlen, key->pubkey.x, key->pubkey.y, key->pubkey.z, r, s, res, key->heap); #endif @@ -6058,7 +6058,7 @@ int wc_ecc_verify_hash_ex(mp_int *r, mp_int *s, const byte* hash, #endif #ifdef WOLFSSL_SP_384 if (ecc_sets[key->idx].id == ECC_SECP384R1) { - #if defined(WC_ECC_NONBLOCK) || defined(WC_ECC_NONBLOCK_ONLY) + #ifdef WC_ECC_NONBLOCK if (key->nb_ctx) { return sp_ecc_verify_384_nb(&key->nb_ctx->sp_ctx, hash, hashlen, key->pubkey.x, key->pubkey.y, key->pubkey.z, r, s, res, @@ -6072,8 +6072,8 @@ int wc_ecc_verify_hash_ex(mp_int *r, mp_int *s, const byte* hash, } while (err == FP_WOULDBLOCK); return err; #endif - #endif - #ifndef WC_ECC_NONBLOCK_ONLY + #endif /* WC_ECC_NONBLOCK */ + #if !defined(WC_ECC_NONBLOCK) || (defined(WC_ECC_NONBLOCK) && !defined(WC_ECC_NONBLOCK_ONLY)) return sp_ecc_verify_384(hash, hashlen, key->pubkey.x, key->pubkey.y, key->pubkey.z, r, s, res, key->heap); #endif From 6088a7bd7904917d4b589f51a2f3c4da2fa72aa5 Mon Sep 17 00:00:00 2001 From: Ethan Looney Date: Fri, 24 Jul 2020 10:03:49 -0700 Subject: [PATCH 49/60] Added if defined debug check to only print to file if debug is enabled --- tests/api.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/api.c b/tests/api.c index 77e4054844..842ae075ab 100644 --- a/tests/api.c +++ b/tests/api.c @@ -27194,15 +27194,16 @@ static int test_wc_ERR_print_errors_fp (void) WOLFSSL_ERROR(BAD_FUNC_ARG); XFILE fp = XFOPEN("./tests/test-log-dump-to-file.txt", "ar"); wc_ERR_print_errors_fp(fp); - +#if defined(DEBUG_WOLFSSL) AssertTrue(XFSEEK(fp, 0, XSEEK_END) == 0); sz = XFTELL(fp); if (sz == 0) { ret = BAD_FUNC_ARG; } - +#endif printf(resultFmt, ret == 0 ? passed : failed); XFCLOSE(fp); + (void)sz; #endif return ret; }/*End test_wc_ERR_print_errors_fp*/ From 7b357cff39911198807404de71b424f3739ca7b5 Mon Sep 17 00:00:00 2001 From: Ethan Looney Date: Fri, 24 Jul 2020 12:54:29 -0700 Subject: [PATCH 50/60] Changed param's, examples and brief's --- doc/dox_comments/header_files/ecc.h | 9 +++--- doc/dox_comments/header_files/random.h | 8 ++++-- doc/dox_comments/header_files/ssl.h | 40 ++++++++++++++------------ 3 files changed, 32 insertions(+), 25 deletions(-) diff --git a/doc/dox_comments/header_files/ecc.h b/doc/dox_comments/header_files/ecc.h index a843d9b2ea..3b2e268da6 100644 --- a/doc/dox_comments/header_files/ecc.h +++ b/doc/dox_comments/header_files/ecc.h @@ -154,13 +154,12 @@ int wc_ecc_check_key(ecc_key* key); \brief This function frees an ecc_key key after it has been used. - \return int integer returned indicating wolfSSL error or success status. - \param key pointer to the ecc_key object to free + \param key pointer to the ecc_key structure to free _Example_ \code - // initialize key and perform secure exchanges + // initialize key and perform ECC operations ... wc_ecc_key_free(&key); \endcode @@ -169,7 +168,7 @@ int wc_ecc_check_key(ecc_key* key); \sa wc_ecc_init_ex */ WOLFSSL_API -int wc_ecc_key_free(ecc_key* key); +void wc_ecc_key_free(ecc_key* key); /*! \ingroup ECC @@ -573,6 +572,8 @@ int wc_ecc_init(ecc_key* key); \return MEMORY_E Returned if there is an error allocating memory \param key pointer to the ecc_key object to initialize + \param devId ID to use with async hardware + \param heap pointer to a heap identifier _Example_ \code diff --git a/doc/dox_comments/header_files/random.h b/doc/dox_comments/header_files/random.h index 9bd52c0155..8e5f0eb139 100644 --- a/doc/dox_comments/header_files/random.h +++ b/doc/dox_comments/header_files/random.h @@ -140,14 +140,16 @@ WOLFSSL_API int wc_RNG_GenerateBlock(WC_RNG*, byte*, word32 sz); /*! \ingroup Random - \brief Creates a new random number. + \brief Creates a new WC_RNG structure. - \return rng on success + \return WC_RNG structure on success \return NULL on error - \param rng random number generator initialized with wc_InitRng + \param heap pointer to a heap identifier + \param nonce pointer to the buffer containing the nonce + \param nonceSz length of the nonce _Example_ \code diff --git a/doc/dox_comments/header_files/ssl.h b/doc/dox_comments/header_files/ssl.h index fd07ec3cd0..184e52fb15 100644 --- a/doc/dox_comments/header_files/ssl.h +++ b/doc/dox_comments/header_files/ssl.h @@ -2699,12 +2699,13 @@ WOLFSSL_API void wolfSSL_load_error_strings(void); WOLFSSL_API int wolfSSL_library_init(void); /*! - \brief This function sets the Device Id. + \brief This function sets the Device Id at the WOLFSSL session level. \return WOLFSSL_SUCCESS upon success. \return BAD_FUNC_ARG if ssl is NULL. \param ssl pointer to a SSL object, created with wolfSSL_new(). + \param devId ID to use with async hardware _Example_ \code @@ -2721,12 +2722,13 @@ WOLFSSL_API int wolfSSL_library_init(void); WOLFSSL_API int wolfSSL_SetDevId(WOLFSSL* ssl, int devId) /*! - \brief This function sets the Device Id. + \brief This function sets the Device Id at the WOLFSSL_CTX context level. \return WOLFSSL_SUCCESS upon success. \return BAD_FUNC_ARG if ssl is NULL. - \param ssl pointer to a SSL object, created with wolfSSL_CTX_new(). + \param ssl pointer to a SSL object, created with wolfSSL_new(). + \param devId ID to use with async hardware _Example_ \code @@ -2748,7 +2750,8 @@ WOLFSSL_API int wolfSSL_CTX_SetDevId(WOLFSSL_CTX* ctx, int devId) \return devId upon success. \return INVALID_DEVID if both ssl and ctx are NULL. - \param ssl pointer to a SSL object, created with wolfSSL_CTX_new(). + \param ctx pointer to the SSL context, created with wolfSSL_CTX_new(). + \param ssl pointer to a SSL object, created with wolfSSL_new(). _Example_ \code @@ -4490,14 +4493,14 @@ WOLFSSL_API int wolfSSL_X509_NAME_get_text_by_NID( WOLFSSL_API int wolfSSL_X509_get_signature_type(WOLFSSL_X509*); /*! - \brief This function frees an external WOLFSSL_X509 structure. + \brief This function frees a WOLFSSL_X509 structure. \param x509 a pointer to the WOLFSSL_X509 struct. _Example_ \code - WOLFSSL_X509* x509 = (WOLFSSL_X509)XMALOC(sizeof(WOLFSSL_X509), NULL, + WOLFSSL_X509* x509 = (WOLFSSL_X509*)XMALOC(sizeof(WOLFSSL_X509), NULL, DYNAMIC_TYPE_X509) ; wolfSSL_X509_free(x509); @@ -4632,20 +4635,21 @@ WOLFSSL_API int wolfSSL_X509_STORE_set_flags(WOLFSSL_X509_STORE* store, /*! \ingroup CertsKeys - \brief This function returns the value stored in the sigOID - member of the WOLFSSL_X509 structure. + \brief This function the certificate "not before" validity encoded as + a byte array. + \return NULL returned if the WOLFSSL_X509 structure is NULL. \return byte is returned that contains the notBeforeData. - \param ssl a pointer to a WOLFSSL structure, created using wolfSSL_new(). + \param x509 pointer to a WOLFSSL_X509 structure. _Example_ \code - WOLFSSL_X509 x509 = (WOLFSSL_X509*)XMALLOC(sizeof(WOLFSSL_X509), NULL, + WOLFSSL_X509* x509 = (WOLFSSL_X509*)XMALLOC(sizeof(WOLFSSL_X509), NULL, DYNAMIC_TYPE_X509); ... - byte notBeforeData = wolfSSL_X509_notBefore(x509); + byte* notBeforeData = wolfSSL_X509_notBefore(x509); \endcode @@ -4662,20 +4666,20 @@ WOLFSSL_API const byte* wolfSSL_X509_notBefore(WOLFSSL_X509* x509); /*! \ingroup CertsKeys - \brief This function returns the value stored in the sigOID - member of the WOLFSSL_X509 structure. + \brief This function the certificate "not after" validity encoded as + a byte array. \return NULL returned if the WOLFSSL_X509 structure is NULL. \return byte is returned that contains the notAfterData. - \param ssl a pointer to a WOLFSSL structure, created using wolfSSL_new(). + \param x509 pointer to a WOLFSSL_X509 structure. _Example_ \code - WOLFSSL_X509 x509 = (WOLFSSL_X509*)XMALLOC(sizeof(WOLFSSL_X509), NULL, + WOLFSSL_X509* x509 = (WOLFSSL_X509*)XMALLOC(sizeof(WOLFSSL_X509), NULL, DYNAMIC_TYPE_X509); ... - byte notAfterData = wolfSSL_X509_notAfter(x509); + byte* notAfterData = wolfSSL_X509_notAfter(x509); \endcode @@ -7756,12 +7760,12 @@ WOLFSSL_API int wolfSSL_DTLS_SetCookieSecret(WOLFSSL*, unsigned int); /*! - \brief This function retrieves the Device Id. + \brief This function retrieves the random number. \return rng upon success. \return NULL if ssl is NULL. - \param ssl pointer to a SSL object, created with wolfSSL_CTX_new(). + \param ssl pointer to a SSL object, created with wolfSSL_new(). _Example_ \code From b734b131200af943b5f50b01e55a416279c22148 Mon Sep 17 00:00:00 2001 From: Ethan Looney Date: Fri, 24 Jul 2020 14:24:50 -0700 Subject: [PATCH 51/60] Changed ifndef(NO_SHA224) to ifdef(WOLFSSL_SHA224) due to 'NO_SHA224' not existing --- tests/api.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/api.c b/tests/api.c index 454bd91e33..af55ff12c8 100644 --- a/tests/api.c +++ b/tests/api.c @@ -7710,7 +7710,7 @@ static int test_wc_Sha224Final (void) static int test_wc_Sha224SetFlags (void) { int flag = 0; -#if !defined(NO_SHA224) && \ +#if defined(WOLFSSL_SHA224) && \ (defined(WOLFSSL_HASH_FLAGS) || defined(WOLF_CRYPTO_CB)) wc_Sha224 sha224; word32 flags = 0; @@ -7742,7 +7742,7 @@ static int test_wc_Sha224SetFlags (void) static int test_wc_Sha224GetFlags (void) { int flag = 0; -#if !defined(NO_SHA224) && \ +#if defined(WOLFSSL_SHA224) && \ (defined(WOLFSSL_HASH_FLAGS) || defined(WOLF_CRYPTO_CB)) wc_Sha224 sha224; word32 flags = 0; @@ -7775,7 +7775,7 @@ static int test_wc_Sha224GetFlags (void) static int test_wc_Sha224Free (void) { int flag = 0; -#if !defined(NO_SHA224) && \ +#if defined(WOLFSSL_SHA224) && \ (defined(WOLFSSL_HASH_FLAGS) || defined(WOLF_CRYPTO_CB)) printf(testingFmt, "wc_Sha224Free()"); @@ -7794,7 +7794,7 @@ static int test_wc_Sha224Free (void) static int test_wc_Sha224GetHash (void) { int flag = 0; -#if !defined(NO_SHA224) && \ +#if defined(WOLFSSL_SHA224) && \ (defined(WOLFSSL_HASH_FLAGS) || defined(WOLF_CRYPTO_CB)) wc_Sha224 sha224; byte hash1[WC_SHA224_DIGEST_SIZE]; @@ -7841,7 +7841,7 @@ static int test_wc_Sha224GetHash (void) static int test_wc_Sha224Copy (void) { int flag = 0; -#if !defined(NO_SHA224) && \ +#if defined(WOLFSSL_SHA224) && \ (defined(WOLFSSL_HASH_FLAGS) || defined(WOLF_CRYPTO_CB)) wc_Sha224 sha224; wc_Sha224 temp; From b775058f49ad8525b365014b0c3d41214b4e51d8 Mon Sep 17 00:00:00 2001 From: Sean Parkinson Date: Mon, 27 Jul 2020 09:32:14 +1000 Subject: [PATCH 52/60] TLS 1.3 server MUST NOT use OCSP Status V2 Parses the extension but does not use the information. TLSX code change to ensure that the OCSP Status V2 extension is not written out in EncryptedExtension, CertificateRequest nor Certificate messages. --- src/tls.c | 30 ++++++++++++++++++++++++------ 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/src/tls.c b/src/tls.c index 1c67e15cdf..292dfb8718 100644 --- a/src/tls.c +++ b/src/tls.c @@ -3528,14 +3528,19 @@ static int TLSX_CSR2_Parse(WOLFSSL* ssl, byte* input, word16 length, return 0; #endif - /* accept the first good status_type and return */ - ret = TLSX_UseCertificateStatusRequestV2(&ssl->extensions, + /* TLS 1.3 servers MUST NOT act upon presence or information in + * this extension (RFC 8448 Section 4.4.2.1). + */ + if (!IsAtLeastTLSv1_3(ssl->version)) { + /* accept the first good status_type and return */ + ret = TLSX_UseCertificateStatusRequestV2(&ssl->extensions, status_type, 0, ssl->heap, ssl->devId); - if (ret != WOLFSSL_SUCCESS) - return ret; /* throw error */ + if (ret != WOLFSSL_SUCCESS) + return ret; /* throw error */ - TLSX_SetResponse(ssl, TLSX_STATUS_REQUEST_V2); - ssl->status_request_v2 = status_type; + TLSX_SetResponse(ssl, TLSX_STATUS_REQUEST_V2); + ssl->status_request_v2 = status_type; + } return 0; } @@ -10327,6 +10332,7 @@ int TLSX_GetRequestSize(WOLFSSL* ssl, byte msgType, word16* pLength) #ifdef WOLFSSL_TLS13 #ifndef NO_CERTS else if (msgType == certificate_request) { + /* Don't send out any extension except those that are turned off. */ XMEMSET(semaphore, 0xff, SEMAPHORE_SIZE); #if !defined(WOLFSSL_NO_SIGALG) TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_SIGNATURE_ALGORITHMS)); @@ -10421,6 +10427,7 @@ int TLSX_WriteRequest(WOLFSSL* ssl, byte* output, byte msgType, word16* pOffset) #ifdef WOLFSSL_TLS13 #ifndef NO_CERTS else if (msgType == certificate_request) { + /* Don't send out any extension except those that are turned off. */ XMEMSET(semaphore, 0xff, SEMAPHORE_SIZE); #if !defined(WOLFSSL_NO_SIGALG) TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_SIGNATURE_ALGORITHMS)); @@ -10524,6 +10531,7 @@ int TLSX_GetResponseSize(WOLFSSL* ssl, byte msgType, word16* pLength) #ifdef WOLFSSL_TLS13 case encrypted_extensions: + /* Send out all extension except those that are turned on. */ TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_EC_POINT_FORMATS)); TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_SUPPORTED_VERSIONS)); TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_SESSION_TICKET)); @@ -10534,6 +10542,9 @@ int TLSX_GetResponseSize(WOLFSSL* ssl, byte msgType, word16* pLength) #ifdef HAVE_CERTIFICATE_STATUS_REQUEST TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_STATUS_REQUEST)); #endif + #ifdef HAVE_CERTIFICATE_STATUS_REQUEST_V2 + TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_STATUS_REQUEST_V2)); + #endif #if defined(HAVE_SECURE_RENEGOTIATION) TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_RENEGOTIATION_INFO)); #endif @@ -10553,6 +10564,7 @@ int TLSX_GetResponseSize(WOLFSSL* ssl, byte msgType, word16* pLength) #ifdef WOLFSSL_TLS13 #ifndef NO_CERTS case certificate: + /* Don't send out any extension except those that are turned off. */ XMEMSET(semaphore, 0xff, SEMAPHORE_SIZE); TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_STATUS_REQUEST)); /* TODO: TLSX_SIGNED_CERTIFICATE_TIMESTAMP, @@ -10640,6 +10652,7 @@ int TLSX_WriteResponse(WOLFSSL *ssl, byte* output, byte msgType, word16* pOffset #ifdef WOLFSSL_TLS13 case encrypted_extensions: + /* Send out all extension except those that are turned on. */ TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_EC_POINT_FORMATS)); TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_SUPPORTED_VERSIONS)); TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_SESSION_TICKET)); @@ -10650,6 +10663,9 @@ int TLSX_WriteResponse(WOLFSSL *ssl, byte* output, byte msgType, word16* pOffset #ifdef HAVE_CERTIFICATE_STATUS_REQUEST TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_STATUS_REQUEST)); #endif + #ifdef HAVE_CERTIFICATE_STATUS_REQUEST_V2 + TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_STATUS_REQUEST_V2)); + #endif #if defined(HAVE_SECURE_RENEGOTIATION) TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_RENEGOTIATION_INFO)); #endif @@ -10669,6 +10685,8 @@ int TLSX_WriteResponse(WOLFSSL *ssl, byte* output, byte msgType, word16* pOffset #ifdef WOLFSSL_TLS13 #ifndef NO_CERTS case certificate: + /* Don't send out any extension except those that are turned + * off. */ XMEMSET(semaphore, 0xff, SEMAPHORE_SIZE); TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_STATUS_REQUEST)); /* TODO: TLSX_SIGNED_CERTIFICATE_TIMESTAMP, From 76a35f2a77d7881ffb935e297aa5851ab930d01f Mon Sep 17 00:00:00 2001 From: Sean Parkinson Date: Mon, 20 Jul 2020 09:12:43 +1000 Subject: [PATCH 53/60] TLS 1.3: Client with no certificate an error with define WOLFSSL_NO_CLIENT_CERT_ERROR --- src/internal.c | 3 +++ src/tls13.c | 6 ++++++ wolfssl/error-ssl.h | 1 + 3 files changed, 10 insertions(+) diff --git a/src/internal.c b/src/internal.c index 58b3d39ad6..5c8ab15c87 100644 --- a/src/internal.c +++ b/src/internal.c @@ -18404,6 +18404,9 @@ const char* wolfSSL_ERR_reason_error_string(unsigned long e) case DTLS_SIZE_ERROR: return "DTLS trying to send too much in single datagram error"; + case NO_CERT_ERROR: + return "TLS1.3 No Certificate Set Error"; + default : return "unknown error number"; } diff --git a/src/tls13.c b/src/tls13.c index 7c70d6f3db..755a916d1d 100644 --- a/src/tls13.c +++ b/src/tls13.c @@ -3202,7 +3202,13 @@ static int DoTls13CertificateRequest(WOLFSSL* ssl, const byte* input, ssl->options.sendVerify = SEND_CERT; } else { +#ifndef WOLFSSL_NO_CLIENT_CERT_ERROR ssl->options.sendVerify = SEND_BLANK_CERT; +#else + WOLFSSL_MSG("Certificate required but none set on client"); + SendAlert(ssl, alert_fatal, illegal_parameter); + return NO_CERT_ERROR; +#endif } /* This message is always encrypted so add encryption padding. */ diff --git a/wolfssl/error-ssl.h b/wolfssl/error-ssl.h index 9478242aa0..c6870d96c4 100644 --- a/wolfssl/error-ssl.h +++ b/wolfssl/error-ssl.h @@ -168,6 +168,7 @@ enum wolfSSL_ErrorCodes { SSL_SHUTDOWN_ALREADY_DONE_E = -437, /* Shutdown called redundantly */ TLS13_SECRET_CB_E = -438, /* TLS1.3 secret Cb fcn failure */ DTLS_SIZE_ERROR = -439, /* Trying to send too much data */ + NO_CERT_ERROR = -440, /* TLS1.3 - no cert set error */ /* add strings to wolfSSL_ERR_reason_error_string in internal.c !!!!! */ From e7429c8504c2f238fc37c864df441d8657b3ce42 Mon Sep 17 00:00:00 2001 From: Ethan Looney Date: Mon, 27 Jul 2020 09:32:25 -0700 Subject: [PATCH 54/60] Added unit tests for wc_port.c --- tests/api.c | 61 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/tests/api.c b/tests/api.c index 454bd91e33..95688eba5c 100644 --- a/tests/api.c +++ b/tests/api.c @@ -13662,6 +13662,65 @@ static int test_wc_SetKeyUsage (void) return ret; } /* END test_wc_SetKeyUsage */ +#if defined(OPENSSL_EXTRA) || defined(HAVE_WEBSERVER) +static void sample_mutex_cb (int flag, int type, const char* file, int line) +{ + (void)flag; + (void)type; + (void)file; + (void)line; +} +#endif +/* + * Testing wc_LockMutex_ex + */ +static int test_wc_LockMutex_ex (void) +{ + int ret = 0; +#if defined(OPENSSL_EXTRA) || defined(HAVE_WEBSERVER) + int flag = CRYPTO_LOCK; + int type = F_LOCK; + const char* file = "./test-LockMutex_ex.txt"; + int line = 0; + XFILE fp = XFOPEN("./test-LockMutex_ex.txt", "ar"); + + printf(testingFmt, "wc_LockMutex_ex()"); + + /*without SetMutexCb*/ + ret = wc_LockMutex_ex(flag, type, file, line); + if (ret == BAD_STATE_E) { + ret = 0; + } + /*with SetMutexCb*/ + if (ret == 0) { + ret = wc_SetMutexCb(sample_mutex_cb); + if (ret == 0) { + ret = wc_LockMutex_ex(flag, type, file, line); + } + } + + printf(resultFmt, ret == 0 ? passed : failed); + XFCLOSE(fp); + +#endif + return ret; +}/*End test_wc_LockMutex_ex*/ +/* + * Testing wc_SetMutexCb + */ +static int test_wc_SetMutexCb (void) +{ + int ret = 0; +#if defined(OPENSSL_EXTRA) || defined(HAVE_WEBSERVER) + + printf(testingFmt, "wc_SetMutexCb()"); + + ret = wc_SetMutexCb(sample_mutex_cb); + + printf(resultFmt, ret == 0 ? passed : failed); +#endif + return ret; +}/*End test_wc_SetMutexCb*/ /* * Testing wc_RsaKeyToDer() @@ -35472,6 +35531,8 @@ void ApiTest(void) AssertIntEQ(test_wc_MakeRsaKey(), 0); AssertIntEQ(test_wc_SetKeyUsage (), 0); + AssertIntEQ(test_wc_SetMutexCb(), 0); + AssertIntEQ(test_wc_LockMutex_ex(), 0); AssertIntEQ(test_wc_RsaKeyToDer(), 0); AssertIntEQ(test_wc_RsaKeyToPublicDer(), 0); From 8440973d99c1ce00493cb718e7443376065c0a76 Mon Sep 17 00:00:00 2001 From: David Garske Date: Mon, 27 Jul 2020 15:44:53 -0700 Subject: [PATCH 55/60] Fix for `derSz` calculation on non-const value `keySz`. ZD 10654 --- tests/api.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/api.c b/tests/api.c index 565b8ae8a5..e2ee60a893 100644 --- a/tests/api.c +++ b/tests/api.c @@ -131,7 +131,7 @@ #endif #endif #if !defined(DER_SZ) - #define DER_SZ (keySz * 2 + 1) + #define DER_SZ(ks) (ks * 2 + 1) #endif #endif #ifndef NO_ASN @@ -20018,9 +20018,9 @@ static int test_wc_ecc_pointFns (void) ecc_point* cpypt = NULL; int idx = 0; int keySz = KEY32; - byte der[DER_SZ]; + byte der[DER_SZ(KEY32)]; word32 derlenChk = 0; - word32 derSz = (int)sizeof(der); + word32 derSz = DER_SZ(KEY32); /* Init stack variables. */ XMEMSET(der, 0, derSz); From 25fcd082d734477142c15426242cffd30859ecdc Mon Sep 17 00:00:00 2001 From: David Garske Date: Tue, 28 Jul 2020 08:19:32 -0700 Subject: [PATCH 56/60] Improve the `mutex_test` test with pthreads. Fixes #3109 --- wolfcrypt/test/test.c | 8 ++++++-- wolfssl/wolfcrypt/settings.h | 1 - 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/wolfcrypt/test/test.c b/wolfcrypt/test/test.c index e19428c1d1..d9e653a302 100644 --- a/wolfcrypt/test/test.c +++ b/wolfcrypt/test/test.c @@ -28493,12 +28493,15 @@ int mutex_test(void) XFREE(mm, NULL, DYNAMIC_TYPE_MUTEX); #endif + /* Can optionally enable advanced pthread tests using "ENABLE_PTHREAD_LOCKFREE_TESTS" */ #ifdef WOLFSSL_PTHREADS if (wc_InitMutex(&m) != 0) return -12701; if (wc_LockMutex(&m) != 0) return -12702; -#if !defined(WOLFSSL_SOLARIS) +#if !defined(WOLFSSL_SOLARIS) && defined(ENABLE_PTHREAD_LOCKFREE_TESTS) + /* trying to free a locked mutex is not portable behavior with pthread */ + /* Attempting to destroy a locked mutex results in undefined behavior */ if (wc_FreeMutex(&m) != BAD_MUTEX_E) return -12703; #endif @@ -28506,7 +28509,8 @@ int mutex_test(void) return -12704; if (wc_FreeMutex(&m) != 0) return -12705; -#if !defined(WOLFSSL_NO_MUTEXLOCK_AFTER_FREE) +#if !defined(WOLFSSL_SOLARIS) && defined(ENABLE_PTHREAD_LOCKFREE_TESTS) + /* Trying to use a pthread after free'ing is not portable behavior */ if (wc_LockMutex(&m) != BAD_MUTEX_E) return -12706; if (wc_UnLockMutex(&m) != BAD_MUTEX_E) diff --git a/wolfssl/wolfcrypt/settings.h b/wolfssl/wolfcrypt/settings.h index 87f1ab396b..b2ec674773 100644 --- a/wolfssl/wolfcrypt/settings.h +++ b/wolfssl/wolfcrypt/settings.h @@ -1450,7 +1450,6 @@ extern void uITRON4_free(void *p) ; #endif #ifdef WOLFSSL_SOLARIS - #define WOLFSSL_NO_MUTEXLOCK_AFTER_FREE /* Avoid naming clash with fp_zero from math.h > ieefp.h */ #define WOLFSSL_DH_CONST #endif From 044800453514c6dd5674abe9f881e4e028048590 Mon Sep 17 00:00:00 2001 From: Ethan Looney Date: Tue, 28 Jul 2020 08:39:23 -0700 Subject: [PATCH 57/60] Added semicolons to two functions to fix doxygen issues and deleted ssl param and replaced it with ctx param --- doc/dox_comments/header_files/ssl.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/dox_comments/header_files/ssl.h b/doc/dox_comments/header_files/ssl.h index 184e52fb15..58d20e5572 100644 --- a/doc/dox_comments/header_files/ssl.h +++ b/doc/dox_comments/header_files/ssl.h @@ -2719,7 +2719,7 @@ WOLFSSL_API int wolfSSL_library_init(void); \sa wolfSSL_CTX_SetDevId \sa wolfSSL_CTX_GetDevId */ -WOLFSSL_API int wolfSSL_SetDevId(WOLFSSL* ssl, int devId) +WOLFSSL_API int wolfSSL_SetDevId(WOLFSSL* ssl, int devId); /*! \brief This function sets the Device Id at the WOLFSSL_CTX context level. @@ -2727,7 +2727,7 @@ WOLFSSL_API int wolfSSL_SetDevId(WOLFSSL* ssl, int devId) \return WOLFSSL_SUCCESS upon success. \return BAD_FUNC_ARG if ssl is NULL. - \param ssl pointer to a SSL object, created with wolfSSL_new(). + \param ctx pointer to the SSL context, created with wolfSSL_CTX_new(). \param devId ID to use with async hardware _Example_ @@ -2742,7 +2742,7 @@ WOLFSSL_API int wolfSSL_SetDevId(WOLFSSL* ssl, int devId) \sa wolfSSL_SetDevId \sa wolfSSL_CTX_GetDevId */ -WOLFSSL_API int wolfSSL_CTX_SetDevId(WOLFSSL_CTX* ctx, int devId) +WOLFSSL_API int wolfSSL_CTX_SetDevId(WOLFSSL_CTX* ctx, int devId); /*! \brief This function retrieves the Device Id. From 5af4872baba5e1f8ad63eea0ca3a689fbaefc82d Mon Sep 17 00:00:00 2001 From: Ethan Looney Date: Tue, 28 Jul 2020 09:16:43 -0700 Subject: [PATCH 58/60] Changed lock type to 0 --- tests/api.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/api.c b/tests/api.c index 95688eba5c..dfa7704879 100644 --- a/tests/api.c +++ b/tests/api.c @@ -13679,7 +13679,7 @@ static int test_wc_LockMutex_ex (void) int ret = 0; #if defined(OPENSSL_EXTRA) || defined(HAVE_WEBSERVER) int flag = CRYPTO_LOCK; - int type = F_LOCK; + int type = 0; const char* file = "./test-LockMutex_ex.txt"; int line = 0; XFILE fp = XFOPEN("./test-LockMutex_ex.txt", "ar"); From b524926837c692fef5a447f7bf8e40229cd58de6 Mon Sep 17 00:00:00 2001 From: Ethan Looney Date: Wed, 29 Jul 2020 09:31:37 -0700 Subject: [PATCH 59/60] Deleted unneeded xfopen and xfclose --- tests/api.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/api.c b/tests/api.c index dfa7704879..1cfc007c12 100644 --- a/tests/api.c +++ b/tests/api.c @@ -13682,7 +13682,6 @@ static int test_wc_LockMutex_ex (void) int type = 0; const char* file = "./test-LockMutex_ex.txt"; int line = 0; - XFILE fp = XFOPEN("./test-LockMutex_ex.txt", "ar"); printf(testingFmt, "wc_LockMutex_ex()"); @@ -13700,7 +13699,6 @@ static int test_wc_LockMutex_ex (void) } printf(resultFmt, ret == 0 ? passed : failed); - XFCLOSE(fp); #endif return ret; From 397d1ab19cb15083313b806079b0d1ac2ffb7bf8 Mon Sep 17 00:00:00 2001 From: John Safranek Date: Wed, 29 Jul 2020 16:51:08 -0700 Subject: [PATCH 60/60] DTLS Test Speed Fix Redux 1. Fix the check for XSLEEP_US in the client. 2. Added XSLEEP_MS to mirror XSLEEP_US, in terms of XSELECT(). --- examples/client/client.c | 2 +- wolfssl/test.h | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/client/client.c b/examples/client/client.c index c7942ae058..b97c25e750 100644 --- a/examples/client/client.c +++ b/examples/client/client.c @@ -65,7 +65,7 @@ #define OCSP_STAPLINGV2_MULTI 3 #define OCSP_STAPLING_OPT_MAX OCSP_STAPLINGV2_MULTI -#if defined(XUSLEEP) && defined(NO_MAIN_DRIVER) +#if defined(XSLEEP_US) && defined(NO_MAIN_DRIVER) /* This is to force the server's thread to get a chance to * execute before continuing the resume in non-blocking * DTLS test cases. */ diff --git a/wolfssl/test.h b/wolfssl/test.h index 1188a17aa7..9e192c040c 100644 --- a/wolfssl/test.h +++ b/wolfssl/test.h @@ -156,6 +156,7 @@ select(0, NULL, NULL, NULL, &tv); \ } while (0) #define XSLEEP_US(u) XSELECT_WAIT(0,u) + #define XSLEEP_MS(m) XSELECT_WAIT(0,(m)*1000) #endif /* USE_WINDOWS_API */ #ifndef XSLEEP_MS