From e9187f5f00b86218e6ae16915657c63af0890eeb Mon Sep 17 00:00:00 2001 From: Sean Parkinson Date: Tue, 5 Apr 2022 18:16:20 +1000 Subject: [PATCH] Wycheproof fixes/changes Allow Chachac20-Poly1305 to take an empty msg. Allow AES-SIV to have an empty nonce. Don't allow the length to be malleable. Must use the smallest number of bytes to represent value. ECDSA and DSA signature values are positive. Add Sha512-224 and Sha512-256 OIDs. ASN template - ensure the ECDSA/DSA signature uses all data. Curve25519/Curve448 - WOLFSSL_ECDHX_SHARED_NOT_ZERO means shared secret can't be 0. Curve25519/Curve448 - check public value is less than order. ECC - x or y may be zero but not both. Ed25519/Ed448 - check S is less than order. Ed448 - ge_p3_dbl can be simplified for ASM. Prime check (integer.c/tfm.c/sp_int.c): Don't allow negative values and make sure random candidate doesn't have bits higher than those in a set when bits not a multiple of 8. RSA: support Sha512-224 and Sha512-256. RSA: Fix check for invalid in decryption. Affects plaintexts 256 bytes and longer. RSA: Don't allow base be larger than modulus. RSA: Check small ciphertext (1 or 0) on decrypt when not using OAEP. RSA: WOLFSSL_RSA_DECRYPT_TO_0_LEN allows decrypted value to be 0. SP math all: fix div to handle large a and d when checking size of remainder. SP math all: set sign of result in sp_mod_2d() --- tests/api.c | 6 +- wolfcrypt/src/aes.c | 5 +- wolfcrypt/src/asn.c | 91 +++++++++++++++++++++++++++++-- wolfcrypt/src/chacha20_poly1305.c | 4 +- wolfcrypt/src/curve25519.c | 40 ++++++++++++-- wolfcrypt/src/curve448.c | 56 ++++++++++++++++++- wolfcrypt/src/ecc.c | 11 +++- wolfcrypt/src/ed25519.c | 42 +++++++++++++- wolfcrypt/src/ed448.c | 25 +++++++++ wolfcrypt/src/ge_operations.c | 14 +++-- wolfcrypt/src/integer.c | 15 ++++- wolfcrypt/src/rsa.c | 48 ++++++++++++---- wolfcrypt/src/sp_int.c | 19 ++++++- wolfcrypt/src/tfm.c | 11 +++- wolfcrypt/test/test.c | 8 +-- wolfssl/wolfcrypt/rsa.h | 14 +++-- 16 files changed, 359 insertions(+), 50 deletions(-) diff --git a/tests/api.c b/tests/api.c index 78e6b5b11..f9362532f 100644 --- a/tests/api.c +++ b/tests/api.c @@ -16259,7 +16259,7 @@ static int test_wc_ChaCha20Poly1305_aead (void) sizeof(plaintext), generatedCiphertext, generatedAuthTag); AssertIntEQ(ret, BAD_FUNC_ARG); ret = wc_ChaCha20Poly1305_Encrypt(key, iv, aad, sizeof(aad), - plaintext, 0, generatedCiphertext, generatedAuthTag); + NULL, sizeof(plaintext), generatedCiphertext, generatedAuthTag); AssertIntEQ(ret, BAD_FUNC_ARG); ret = wc_ChaCha20Poly1305_Encrypt(key, iv, aad, sizeof(aad), plaintext, sizeof(plaintext), NULL, generatedAuthTag); @@ -16298,8 +16298,8 @@ static int test_wc_ChaCha20Poly1305_aead (void) ret = wc_ChaCha20Poly1305_Decrypt(key, iv, aad, sizeof(aad), cipher, sizeof(cipher), authTag, NULL); AssertIntEQ(ret, BAD_FUNC_ARG); - ret = wc_ChaCha20Poly1305_Decrypt(key, iv, aad, sizeof(aad), cipher, - 0, authTag, generatedPlaintext); + ret = wc_ChaCha20Poly1305_Decrypt(key, iv, aad, sizeof(aad), NULL, + sizeof(cipher), authTag, generatedPlaintext); AssertIntEQ(ret, BAD_FUNC_ARG); if (ret == BAD_FUNC_ARG) { ret = 0; diff --git a/wolfcrypt/src/aes.c b/wolfcrypt/src/aes.c index 7844043d0..ab00c8ff5 100644 --- a/wolfcrypt/src/aes.c +++ b/wolfcrypt/src/aes.c @@ -11993,13 +11993,16 @@ static WARN_UNUSED_RESULT int S2V( } } - if (ret == 0) { + if ((ret == 0) && (nonceSz > 0)) { ShiftAndXorRb(tmp[0], tmp[1]); ret = wc_AesCmacGenerate(tmp[1], &macSz, nonce, nonceSz, key, keySz); if (ret == 0) { xorbuf(tmp[0], tmp[1], AES_BLOCK_SIZE); } } + else { + XMEMCPY(tmp[0], tmp[1], AES_BLOCK_SIZE); + } if (ret == 0) { if (dataSz >= AES_BLOCK_SIZE) { diff --git a/wolfcrypt/src/asn.c b/wolfcrypt/src/asn.c index bfb3bb92a..1f2c73383 100644 --- a/wolfcrypt/src/asn.c +++ b/wolfcrypt/src/asn.c @@ -2089,6 +2089,19 @@ int GetLength_ex(const byte* input, word32* inOutIdx, int* len, word32 maxIdx, * Note: 0 indicates indefinte length encoding *not* 0 bytes of length. */ word32 bytes = b & 0x7F; + int minLen; + + /* Calculate minimum length to be encoded with bytes. */ + if (b == 0x80) { + /* Indefinite length encoding - no length bytes. */ + minLen = 0; + } + else if (bytes == 1) { + minLen = 0x80; + } + else { + minLen = 1 << ((bytes - 1) * 8); + } /* Check the number of bytes required are available. */ if ((idx + bytes) > maxIdx) { @@ -2109,6 +2122,10 @@ int GetLength_ex(const byte* input, word32* inOutIdx, int* len, word32 maxIdx, if (length < 0) { return ASN_PARSE_E; } + /* Don't allow lengths that are longer than strictly required. */ + if (length < minLen) { + return ASN_PARSE_E; + } } else { /* Length in first byte. */ @@ -3122,6 +3139,42 @@ int GetInt(mp_int* mpi, const byte* input, word32* inOutIdx, word32 maxIdx) #endif } +#if (defined(HAVE_ECC) || !defined(NO_DSA)) && !defined(WOLFSSL_ASN_TEMPLATE) +static int GetIntPositive(mp_int* mpi, const byte* input, word32* inOutIdx, + word32 maxIdx) +{ + word32 idx = *inOutIdx; + int ret; + int length; + + ret = GetASNInt(input, &idx, &length, maxIdx); + if (ret != 0) + return ret; + + if (((input[idx] & 0x80) == 0x80) && (input[idx - 1] != 0x00)) + return MP_INIT_E; + + if (mp_init(mpi) != MP_OKAY) + return MP_INIT_E; + + if (mp_read_unsigned_bin(mpi, input + idx, length) != 0) { + mp_clear(mpi); + return ASN_GETINT_E; + } + +#ifdef HAVE_WOLF_BIGINT + if (wc_bigint_from_unsigned_bin(&mpi->raw, input + idx, length) != 0) { + mp_clear(mpi); + return ASN_GETINT_E; + } +#endif /* HAVE_WOLF_BIGINT */ + + *inOutIdx = idx + length; + + return 0; +} +#endif /* (ECC || !NO_DSA) && !WOLFSSL_ASN_TEMPLATE */ + #ifndef WOLFSSL_ASN_TEMPLATE #if (!defined(WOLFSSL_KEY_GEN) && !defined(OPENSSL_EXTRA) && defined(RSA_LOW_MEM)) \ || defined(WOLFSSL_RSA_PUBLIC_ONLY) || (!defined(NO_DSA)) @@ -3737,6 +3790,12 @@ static word32 SetBitString16Bit(word16 val, byte* output) #endif #ifdef WOLFSSL_SHA512 static const byte hashSha512hOid[] = {96, 134, 72, 1, 101, 3, 4, 2, 3}; + #ifndef WOLFSSL_NOSHA512_224 + static const byte hashSha512_224hOid[] = {96, 134, 72, 1, 101, 3, 4, 2, 5}; + #endif + #ifndef WOLFSSL_NOSHA512_256 + static const byte hashSha512_256hOid[] = {96, 134, 72, 1, 101, 3, 4, 2, 6}; + #endif #endif #ifdef WOLFSSL_SHA3 #ifndef WOLFSSL_NOSHA3_224 @@ -4130,6 +4189,18 @@ const byte* OidFromId(word32 id, word32 type, word32* oidSz) break; #endif #ifdef WOLFSSL_SHA512 + #ifndef WOLFSSL_NOSHA512_224 + case SHA512_224h: + oid = hashSha512_224hOid; + *oidSz = sizeof(hashSha512_224hOid); + break; + #endif + #ifndef WOLFSSL_NOSHA512_256 + case SHA512_256h: + oid = hashSha512_256hOid; + *oidSz = sizeof(hashSha512_256hOid); + break; + #endif case SHA512h: oid = hashSha512hOid; *oidSz = sizeof(hashSha512hOid); @@ -27119,11 +27190,11 @@ int DecodeECC_DSA_Sig(const byte* sig, word32 sigLen, mp_int* r, mp_int* s) } #endif - if (GetInt(r, sig, &idx, sigLen) < 0) { + if (GetIntPositive(r, sig, &idx, sigLen) < 0) { return ASN_ECC_KEY_E; } - if (GetInt(s, sig, &idx, sigLen) < 0) { + if (GetIntPositive(s, sig, &idx, sigLen) < 0) { mp_clear(r); return ASN_ECC_KEY_E; } @@ -27142,6 +27213,7 @@ int DecodeECC_DSA_Sig(const byte* sig, word32 sigLen, mp_int* r, mp_int* s) #else ASNGetData dataASN[dsaSigASN_Length]; word32 idx = 0; + int ret; /* Clear dynamic data and set mp_ints to put r and s into. */ XMEMSET(dataASN, 0, sizeof(dataASN)); @@ -27149,8 +27221,19 @@ int DecodeECC_DSA_Sig(const byte* sig, word32 sigLen, mp_int* r, mp_int* s) GetASN_MP(&dataASN[DSASIGASN_IDX_S], s); /* Decode the DSA signature. */ - return GetASN_Items(dsaSigASN, dataASN, dsaSigASN_Length, 1, sig, &idx, - sigLen); + ret = GetASN_Items(dsaSigASN, dataASN, dsaSigASN_Length, 1, sig, &idx, + sigLen); +#ifndef NO_STRICT_ECDSA_LEN + /* sanity check that the index has been advanced all the way to the end of + * the buffer */ + if ((ret == 0) && (idx != sigLen)) { + mp_clear(r); + mp_clear(s); + ret = ASN_ECC_KEY_E; + } + + return ret; +#endif #endif /* WOLFSSL_ASN_TEMPLATE */ } #endif diff --git a/wolfcrypt/src/chacha20_poly1305.c b/wolfcrypt/src/chacha20_poly1305.c index 417b3e226..5ec856e99 100644 --- a/wolfcrypt/src/chacha20_poly1305.c +++ b/wolfcrypt/src/chacha20_poly1305.c @@ -60,7 +60,7 @@ int wc_ChaCha20Poly1305_Encrypt( /* Validate function arguments */ if (!inKey || !inIV || - !inPlaintext || !inPlaintextLen || + (inPlaintextLen > 0 && inPlaintext == NULL) || !outCiphertext || !outAuthTag) { @@ -93,7 +93,7 @@ int wc_ChaCha20Poly1305_Decrypt( /* Validate function arguments */ if (!inKey || !inIV || - !inCiphertext || !inCiphertextLen || + (inCiphertextLen > 0 && inCiphertext == NULL) || !inAuthTag || !outPlaintext) { diff --git a/wolfcrypt/src/curve25519.c b/wolfcrypt/src/curve25519.c index f4ba3fe49..16d6074e0 100644 --- a/wolfcrypt/src/curve25519.c +++ b/wolfcrypt/src/curve25519.c @@ -312,6 +312,18 @@ int wc_curve25519_shared_secret_ex(curve25519_key* private_key, RESTORE_VECTOR_REGISTERS(); } +#endif +#ifdef WOLFSSL_ECDHX_SHARED_NOT_ZERO + if (ret == 0) { + int i; + byte t = 0; + for (i = 0; i < CURVE25519_KEYSIZE; i++) { + t |= o.point[i]; + } + if (t == 0) { + ret = ECC_OUT_OF_RANGE_E; + } + } #endif if (ret != 0) { ForceZero(&o, sizeof(o)); @@ -444,7 +456,7 @@ int wc_curve25519_check_public(const byte* pub, word32 pubSz, int endian) if (endian == EC25519_LITTLE_ENDIAN) { /* Check for value of zero or one */ - for (i = pubSz - 1; i > 0; i--) { + for (i = CURVE25519_KEYSIZE - 1; i > 0; i--) { if (pub[i] != 0) break; } @@ -452,21 +464,41 @@ int wc_curve25519_check_public(const byte* pub, word32 pubSz, int endian) return ECC_BAD_ARG_E; /* Check high bit set */ - if (pub[CURVE25519_KEYSIZE-1] & 0x80) + if (pub[CURVE25519_KEYSIZE - 1] & 0x80) return ECC_OUT_OF_RANGE_E; + + /* Check for order-1 or higher. */ + if (pub[CURVE25519_KEYSIZE - 1] == 0x7f) { + for (i = CURVE25519_KEYSIZE - 2; i > 0; i--) { + if (pub[i] != 0xff) + break; + } + if (i == 0 && (pub[0] >= 0xec)) + return ECC_BAD_ARG_E; + } } else { /* Check for value of zero or one */ - for (i = 0; i < pubSz-1; i++) { + for (i = 0; i < CURVE25519_KEYSIZE - 1; i++) { if (pub[i] != 0) break; } - if (i == pubSz - 1 && (pub[i] == 0 || pub[i] == 1)) + if (i == CURVE25519_KEYSIZE - 1 && (pub[i] == 0 || pub[i] == 1)) return ECC_BAD_ARG_E; /* Check high bit set */ if (pub[0] & 0x80) return ECC_OUT_OF_RANGE_E; + + /* Check for order-1 or higher. */ + if (pub[0] == 0x7f) { + for (i = 1; i < CURVE25519_KEYSIZE - 1; i++) { + if (pub[i] != 0) + break; + } + if (i == CURVE25519_KEYSIZE - 1 && (pub[i] >= 0xec)) + return ECC_BAD_ARG_E; + } } return 0; diff --git a/wolfcrypt/src/curve448.c b/wolfcrypt/src/curve448.c index 43c8dd83a..6a084f134 100644 --- a/wolfcrypt/src/curve448.c +++ b/wolfcrypt/src/curve448.c @@ -170,6 +170,17 @@ int wc_curve448_shared_secret_ex(curve448_key* private_key, if (ret == 0) { ret = curve448(o, private_key->k, public_key->p); } +#ifdef WOLFSSL_ECDHX_SHARED_NOT_ZERO + if (ret == 0) { + byte t = 0; + for (i = 0; i < CURVE448_PUB_KEY_SIZE; i++) { + t |= o[i]; + } + if (t == 0) { + ret = ECC_OUT_OF_RANGE_E; + } + } +#endif if (ret == 0) { if (endian == EC448_BIG_ENDIAN) { /* put shared secret key in Big Endian format */ @@ -353,7 +364,7 @@ int wc_curve448_check_public(const byte* pub, word32 pubSz, int endian) if (ret == 0) { if (endian == EC448_LITTLE_ENDIAN) { /* Check for value of zero or one */ - for (i = pubSz - 1; i > 0; i--) { + for (i = CURVE448_PUB_KEY_SIZE - 1; i > 0; i--) { if (pub[i] != 0) { break; } @@ -361,17 +372,56 @@ int wc_curve448_check_public(const byte* pub, word32 pubSz, int endian) if ((i == 0) && (pub[0] == 0 || pub[0] == 1)) { return ECC_BAD_ARG_E; } + /* Check for order-1 or higher */ + for (i = CURVE448_PUB_KEY_SIZE - 1; i > 28; i--) { + if (pub[i] != 0xff) { + break; + } + } + if ((i == 28) && (pub[i] == 0xff)) { + return ECC_BAD_ARG_E; + } + if ((i == 28) && (pub[i] == 0xfe)) { + for (--i; i > 0; i--) { + if (pub[i] != 0xff) { + break; + } + } + if ((i == 0) && (pub[i] >= 0xfe)) { + return ECC_BAD_ARG_E; + } + } } else { /* Check for value of zero or one */ - for (i = 0; i < pubSz-1; i++) { + for (i = 0; i < CURVE448_PUB_KEY_SIZE-1; i++) { if (pub[i] != 0) { break; } } - if ((i == pubSz - 1) && (pub[i] == 0 || pub[i] == 1)) { + if ((i == CURVE448_PUB_KEY_SIZE - 1) && + (pub[i] == 0 || pub[i] == 1)) { ret = ECC_BAD_ARG_E; } + /* Check for order-1 or higher */ + for (i = 0; i < 27; i++) { + if (pub[i] != 0xff) { + break; + } + } + if ((i == 27) && (pub[i] == 0xff)) { + return ECC_BAD_ARG_E; + } + if ((i == 27) && (pub[i] == 0xfe)) { + for (++i; i < CURVE448_PUB_KEY_SIZE - 1; i--) { + if (pub[i] != 0xff) { + break; + } + } + if ((i == CURVE448_PUB_KEY_SIZE) && (pub[i] >= 0xfe)) { + return ECC_BAD_ARG_E; + } + } } } diff --git a/wolfcrypt/src/ecc.c b/wolfcrypt/src/ecc.c index fa5eb0ac0..28e8013eb 100644 --- a/wolfcrypt/src/ecc.c +++ b/wolfcrypt/src/ecc.c @@ -10011,7 +10011,7 @@ static int wc_ecc_import_raw_private(ecc_key* key, const char* qx, err = mp_read_unsigned_bin(key->pubkey.x, (const byte*)qx, key->dp->size); - if (mp_iszero(key->pubkey.x) || mp_isneg(key->pubkey.x)) { + if (mp_isneg(key->pubkey.x)) { WOLFSSL_MSG("Invalid Qx"); err = BAD_FUNC_ARG; } @@ -10025,12 +10025,19 @@ static int wc_ecc_import_raw_private(ecc_key* key, const char* qx, err = mp_read_unsigned_bin(key->pubkey.y, (const byte*)qy, key->dp->size); - if (mp_iszero(key->pubkey.y) || mp_isneg(key->pubkey.y)) { + if (mp_isneg(key->pubkey.y)) { WOLFSSL_MSG("Invalid Qy"); err = BAD_FUNC_ARG; } } + if (err == MP_OKAY) { + if (mp_iszero(key->pubkey.x) && mp_iszero(key->pubkey.y)) { + WOLFSSL_MSG("Invalid Qx and Qy"); + err = BAD_FUNC_ARG; + } + } + if (err == MP_OKAY) err = mp_set(key->pubkey.z, 1); diff --git a/wolfcrypt/src/ed25519.c b/wolfcrypt/src/ed25519.c index 628394774..9c5e55bf8 100644 --- a/wolfcrypt/src/ed25519.c +++ b/wolfcrypt/src/ed25519.c @@ -572,6 +572,15 @@ static int ed25519_verify_msg_update_with_sha(const byte* msgSegment, return ed25519_hash_update(key, sha, msgSegment, msgSegmentLen); } +/* Low part of order in big endian. */ +static const byte ed25519_low_order[] = { + 0x14, 0xde, 0xf9, 0xde, 0xa2, 0xf7, 0x9c, 0xd6, + 0x58, 0x12, 0x63, 0x1a, 0x5c, 0xf5, 0xd3, 0xed +}; + +#define ED25519_SIG_LOW_ORDER_IDX \ + ((int)(ED25519_SIG_SIZE/2 + sizeof(ed25519_low_order) - 1)) + /* sig is array of bytes containing the signature sigLen is the length of sig byte array @@ -599,8 +608,39 @@ static int ed25519_verify_msg_final_with_sha(const byte* sig, word32 sigLen, *res = 0; /* check on basics needed to verify signature */ - if (sigLen != ED25519_SIG_SIZE || (sig[ED25519_SIG_SIZE-1] & 224)) + if (sigLen != ED25519_SIG_SIZE) return BAD_FUNC_ARG; + /* S is not larger or equal to the order: + * 2^252 + 0x14def9dea2f79cd65812631a5cf5d3ed + * = 0x1000000000000000000000000000000014def9dea2f79cd65812631a5cf5d3ed + */ + if (sig[ED25519_SIG_SIZE-1] > 0x10) + return BAD_FUNC_ARG; + if (sig[ED25519_SIG_SIZE-1] == 0x10) { + int i = ED25519_SIG_SIZE-1; + int j; + + /* Check high zeros. */ + for (--i; i > ED25519_SIG_LOW_ORDER_IDX; i--) { + if (sig[i] > 0x00) + break; + } + /* Did we see all zeros up to lower order index? */ + if (i == ED25519_SIG_LOW_ORDER_IDX) { + /* Check lower part. */ + for (j = 0; j < (int)sizeof(ed25519_low_order); j++, i--) { + /* Check smaller. */ + if (sig[i] < ed25519_low_order[j]) + break; + /* Check bigger. */ + if (sig[i] > ed25519_low_order[j]) + return BAD_FUNC_ARG; + } + /* Check equal - all bytes match. */ + if (i == ED25519_SIG_SIZE/2 - 1) + return BAD_FUNC_ARG; + } + } /* uncompress A (public key), test if valid, and negate it */ #ifndef FREESCALE_LTC_ECC diff --git a/wolfcrypt/src/ed448.c b/wolfcrypt/src/ed448.c index cdbb3111b..2a2c41e59 100644 --- a/wolfcrypt/src/ed448.c +++ b/wolfcrypt/src/ed448.c @@ -547,6 +547,18 @@ static int ed448_verify_msg_update_with_sha(const byte* msgSegment, return ed448_hash_update(key, sha, msgSegment, msgSegmentLen); } +/* Order of the ed448 curve - little endian. */ +static const byte ed448_order[] = { + 0xf3, 0x44, 0x58, 0xab, 0x92, 0xc2, 0x78, 0x23, + 0x55, 0x8f, 0xc5, 0x8d, 0x72, 0xc2, 0x6c, 0x21, + 0x90, 0x36, 0xd6, 0xae, 0x49, 0xdb, 0x4e, 0xc4, + 0xe9, 0x23, 0xca, 0x7c, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, + 0x00 +}; + /* Verify the message using the ed448 public key. * * sig [in] Signature to verify. @@ -566,6 +578,7 @@ static int ed448_verify_msg_final_with_sha(const byte* sig, word32 sigLen, ge448_p2 A; ge448_p2 R; int ret; + int i; /* sanity check on arguments */ if ((sig == NULL) || (res == NULL) || (key == NULL)) @@ -577,6 +590,18 @@ static int ed448_verify_msg_final_with_sha(const byte* sig, word32 sigLen, /* check on basics needed to verify signature */ if (sigLen != ED448_SIG_SIZE) return BAD_FUNC_ARG; + /* Check S is not larger than or equal to order. */ + for (i = (int)sizeof(ed448_order) - 1; i >= 0; i--) { + /* Bigger than order. */ + if (sig[ED448_SIG_SIZE/2 + i] > ed448_order[i]) + return BAD_FUNC_ARG; + /* Less than order. */ + if (sig[ED448_SIG_SIZE/2 + i] < ed448_order[i]) + break; + } + /* Same value as order. */ + if (i == -1) + return BAD_FUNC_ARG; /* uncompress A (public key), test if valid, and negate it */ if (ge448_from_bytes_negate_vartime(&A, key->p) != 0) diff --git a/wolfcrypt/src/ge_operations.c b/wolfcrypt/src/ge_operations.c index aedfc53ac..379bd8fd7 100644 --- a/wolfcrypt/src/ge_operations.c +++ b/wolfcrypt/src/ge_operations.c @@ -59,8 +59,8 @@ static void ge_p2_0(ge_p2 *h); #ifndef CURVED25519_ASM static void ge_precomp_0(ge_precomp *h); -#endif static void ge_p3_to_p2(ge_p2 *r,const ge_p3 *p); +#endif static WC_INLINE void ge_p3_to_cached(ge_cached *r,const ge_p3 *p); static void ge_p1p1_to_p2(ge_p2 *r,const ge_p1p1 *p); static WC_INLINE void ge_p1p1_to_p3(ge_p3 *r,const ge_p1p1 *p); @@ -9725,9 +9725,13 @@ r = 2 * p static void ge_p3_dbl(ge_p1p1 *r,const ge_p3 *p) { - ge_p2 q; - ge_p3_to_p2(&q,p); - ge_p2_dbl(r,&q); +#ifndef CURVED25519_ASM + ge_p2 q; + ge_p3_to_p2(&q,p); + ge_p2_dbl(r,&q); +#else + fe_ge_dbl(r->X, r->Y, r->Z, r->T, p->X, p->Y, p->Z); +#endif } @@ -9772,12 +9776,14 @@ static WC_INLINE void ge_p3_to_cached(ge_cached *r,const ge_p3 *p) r = p */ +#ifndef CURVED25519_ASM static void ge_p3_to_p2(ge_p2 *r,const ge_p3 *p) { fe_copy(r->X,p->X); fe_copy(r->Y,p->Y); fe_copy(r->Z,p->Z); } +#endif /* ge p3 tobytes */ diff --git a/wolfcrypt/src/integer.c b/wolfcrypt/src/integer.c index cbdd3f661..0dda84250 100644 --- a/wolfcrypt/src/integer.c +++ b/wolfcrypt/src/integer.c @@ -4905,6 +4905,7 @@ int mp_prime_is_prime_ex (mp_int * a, int t, int *result, WC_RNG *rng) mp_int b, c; int ix, err, res; byte* base = NULL; + word32 bitSz = 0; word32 baseSz = 0; /* default to no */ @@ -4915,6 +4916,10 @@ int mp_prime_is_prime_ex (mp_int * a, int t, int *result, WC_RNG *rng) return MP_VAL; } + if (a->sign == MP_NEG) { + return MP_VAL; + } + if (mp_isone(a)) { *result = MP_NO; return MP_OKAY; @@ -4947,8 +4952,9 @@ int mp_prime_is_prime_ex (mp_int * a, int t, int *result, WC_RNG *rng) return err; } - baseSz = mp_count_bits(a); - baseSz = (baseSz / 8) + ((baseSz % 8) ? 1 : 0); + bitSz = mp_count_bits(a); + baseSz = (bitSz / 8) + ((bitSz % 8) ? 1 : 0); + bitSz %= 8; base = (byte*)XMALLOC(baseSz, NULL, DYNAMIC_TYPE_TMP_BUFFER); if (base == NULL) { @@ -4968,6 +4974,11 @@ int mp_prime_is_prime_ex (mp_int * a, int t, int *result, WC_RNG *rng) goto LBL_B; } + /* Clear bits higher than those in a. */ + if (bitSz > 0) { + base[0] &= (1 << bitSz) - 1; + } + if ((err = mp_read_unsigned_bin(&b, base, baseSz)) != MP_OKAY) { goto LBL_B; } diff --git a/wolfcrypt/src/rsa.c b/wolfcrypt/src/rsa.c index 7e6e3cdda..6da4c740d 100644 --- a/wolfcrypt/src/rsa.c +++ b/wolfcrypt/src/rsa.c @@ -986,6 +986,18 @@ static int RsaMGF(int type, byte* seed, word32 seedSz, byte* out, case WC_MGF1SHA512: ret = RsaMGF1(WC_HASH_TYPE_SHA512, seed, seedSz, out, outSz, heap); break; + #ifndef WOLFSSL_NOSHA512_224 + case WC_MGF1SHA512_224: + ret = RsaMGF1(WC_HASH_TYPE_SHA512_224, seed, seedSz, out, outSz, + heap); + break; + #endif + #ifndef WOLFSSL_NOSHA512_256 + case WC_MGF1SHA512_256: + ret = RsaMGF1(WC_HASH_TYPE_SHA512_256, seed, seedSz, out, outSz, + heap); + break; + #endif #endif default: WOLFSSL_MSG("Unknown MGF type: check build options"); @@ -1770,7 +1782,7 @@ static int RsaUnPad(const byte *pkcsBlock, unsigned int pkcsBlockLen, invalid |= ctMaskNotEq(pkcsBlock[1], padValue); *output = (byte *)(pkcsBlock + i); - ret = ((int)(byte)~invalid) & (pkcsBlockLen - i); + ret = ((int)-1 + (int)(invalid >> 7)) & (pkcsBlockLen - i); } #endif @@ -2277,8 +2289,13 @@ static int wc_RsaFunctionSync(const byte* in, word32 inLen, byte* out, #endif #endif int ret = 0; - word32 keyLen = 0; #endif + word32 keyLen = wc_RsaEncryptSize(key); + + if (inLen > keyLen) { + WOLFSSL_MSG("Expected that inLen be no longer RSA key length"); + return BAD_FUNC_ARG; + } if (mp_iseven(&key->n)) { return MP_VAL; @@ -2578,7 +2595,6 @@ static int wc_RsaFunctionSync(const byte* in, word32 inLen, byte* out, } if (ret == 0) { - keyLen = wc_RsaEncryptSize(key); if (keyLen > *outLen) ret = RSA_BUFFER_E; } @@ -2591,7 +2607,6 @@ static int wc_RsaFunctionSync(const byte* in, word32 inLen, byte* out, #else (void)type; (void)key; - (void)keyLen; XMEMCPY(out, in, inLen); *outLen = inLen; #endif @@ -2885,8 +2900,9 @@ int cc310_RsaSSL_Verify(const byte* in, word32 inLen, byte* sig, } #endif /* WOLFSSL_CRYPTOCELL */ -int wc_RsaFunction(const byte* in, word32 inLen, byte* out, - word32* outLen, int type, RsaKey* key, WC_RNG* rng) +static int wc_RsaFunction_ex(const byte* in, word32 inLen, byte* out, + word32* outLen, int type, RsaKey* key, WC_RNG* rng, + int checkSmallCt) { int ret = 0; @@ -2944,7 +2960,7 @@ int wc_RsaFunction(const byte* in, word32 inLen, byte* out, } if (ret == 0) { /* check c > 1 */ - if (mp_cmp_d(c, 1) != MP_GT) + if (checkSmallCt && (mp_cmp_d(c, 1) != MP_GT)) ret = RSA_OUT_OF_RANGE_E; } if (ret == 0) { @@ -2971,6 +2987,8 @@ int wc_RsaFunction(const byte* in, word32 inLen, byte* out, } #endif /* NO_RSA_BOUNDS_CHECK */ #endif +#else + (void)checkSmallCt; #endif #if defined(WOLFSSL_ASYNC_CRYPT) && defined(WC_ASYNC_ENABLE_RSA) @@ -3012,6 +3030,12 @@ int wc_RsaFunction(const byte* in, word32 inLen, byte* out, #endif /* WOLF_CRYPTO_CB_ONLY_RSA */ } +int wc_RsaFunction(const byte* in, word32 inLen, byte* out, + word32* outLen, int type, RsaKey* key, WC_RNG* rng) +{ + /* Always check for ciphertext of 0 or 1. (Should't for OAEP decrypt.) */ + return wc_RsaFunction_ex(in, inLen, out, outLen, type, key, rng, 1); +} #ifndef WOLFSSL_RSA_VERIFY_ONLY /* Internal Wrappers */ @@ -3260,10 +3284,12 @@ static int RsaPrivateDecryptEx(const byte* in, word32 inLen, byte* out, case RSA_STATE_DECRYPT_EXPTMOD: #if !defined(WOLFSSL_RSA_VERIFY_ONLY) && !defined(WOLFSSL_RSA_VERIFY_INLINE) - ret = wc_RsaFunction(key->data, inLen, key->data, &key->dataLen, - rsa_type, key, rng); + ret = wc_RsaFunction_ex(key->data, inLen, key->data, &key->dataLen, + rsa_type, key, rng, + pad_type != WC_RSA_OAEP_PAD); #else - ret = wc_RsaFunction(in, inLen, out, &key->dataLen, rsa_type, key, rng); + ret = wc_RsaFunction_ex(in, inLen, out, &key->dataLen, rsa_type, key, + rng, pad_type != WC_RSA_OAEP_PAD); #endif if (ret >= 0 || ret == WC_PENDING_E) { @@ -3319,7 +3345,9 @@ static int RsaPrivateDecryptEx(const byte* in, word32 inLen, byte* out, #if !defined(WOLFSSL_RSA_VERIFY_ONLY) ret = ctMaskSelInt(ctMaskLTE(ret, outLen), ret, RSA_BUFFER_E); + #ifndef WOLFSSL_RSA_DECRYPT_TO_0_LEN ret = ctMaskSelInt(ctMaskNotEq(ret, 0), ret, RSA_BUFFER_E); + #endif #else if (outLen < (word32)ret) ret = RSA_BUFFER_E; diff --git a/wolfcrypt/src/sp_int.c b/wolfcrypt/src/sp_int.c index 72bd0eb3c..284b6bc6a 100644 --- a/wolfcrypt/src/sp_int.c +++ b/wolfcrypt/src/sp_int.c @@ -6712,8 +6712,13 @@ int sp_div(sp_int* a, sp_int* d, sp_int* r, sp_int* rem) if ((err == MP_OKAY) && (r != NULL) && (r->size < a->used - d->used + 2)) { err = MP_VAL; } - if ((err == MP_OKAY) && (rem != NULL) && (rem->size < a->used + 1)) { - err = MP_VAL; + if ((err == MP_OKAY) && (rem != NULL)) { + if ((a->used <= d->used) && (rem->size < a->used + 1)) { + err = MP_VAL; + } + else if ((a->used > d->used) && (rem->size < d->used + 1)) { + err = MP_VAL; + } } /* May need to shift number being divided left into a new word. */ if ((err == MP_OKAY) && (a->used == SP_INT_DIGITS)) { @@ -11528,6 +11533,9 @@ int sp_mod_2d(sp_int* a, int e, sp_int* r) if (a != r) { XMEMCPY(r->dp, a->dp, digits * sizeof(sp_int_digit)); r->used = a->used; + #ifdef WOLFSSL_SP_INT_NEGATIVE + r->sign = a->sign; + #endif } #ifndef WOLFSSL_SP_INT_NEGATIVE if (digits <= a->used) @@ -15632,6 +15640,12 @@ int sp_prime_is_prime_ex(sp_int* a, int t, int* result, WC_RNG* rng) err = MP_VAL; } +#ifdef WOLFSSL_SP_INT_NEGATIVE + if ((err == MP_OKAY) && (a->sign == MP_NEG)) { + err = MP_VAL; + } +#endif + if ((err == MP_OKAY) && sp_isone(a)) { ret = MP_NO; haveRes = 1; @@ -15700,6 +15714,7 @@ int sp_prime_is_prime_ex(sp_int* a, int t, int* result, WC_RNG* rng) /* Ensure the top word has no more bits than necessary. */ if (bits > 0) { b->dp[b->used - 1] &= ((sp_digit)1 << bits) - 1; + sp_clamp(b); } if ((sp_cmp_d(b, 2) != MP_GT) || (_sp_cmp(b, c) != MP_LT)) { diff --git a/wolfcrypt/src/tfm.c b/wolfcrypt/src/tfm.c index 22fe61dca..c9a557b9b 100644 --- a/wolfcrypt/src/tfm.c +++ b/wolfcrypt/src/tfm.c @@ -5069,6 +5069,8 @@ int mp_prime_is_prime_ex(mp_int* a, int t, int* result, WC_RNG* rng) if (a == NULL || result == NULL || rng == NULL) return FP_VAL; + if (a->sign == FP_NEG) + return FP_VAL; if (fp_isone(a)) { *result = FP_NO; @@ -5107,12 +5109,14 @@ int mp_prime_is_prime_ex(mp_int* a, int t, int* result, WC_RNG* rng) byte* base; #endif word32 baseSz; + word32 bitSz; int err; - baseSz = fp_count_bits(a); + bitSz = fp_count_bits(a); /* The base size is the number of bits / 8. One is added if the number * of bits isn't an even 8. */ - baseSz = (baseSz / 8) + ((baseSz % 8) ? 1 : 0); + baseSz = (bitSz / 8) + ((bitSz % 8) ? 1 : 0); + bitSz %= 8; #ifndef WOLFSSL_SMALL_STACK if (baseSz > sizeof(base)) @@ -5153,6 +5157,9 @@ int mp_prime_is_prime_ex(mp_int* a, int t, int* result, WC_RNG* rng) return err; } + if (bitSz != 0) + base[0] &= (1 << bitSz) - 1; + err = fp_read_unsigned_bin(b, base, baseSz); if (err != FP_OKAY) { #ifdef WOLFSSL_SMALL_STACK diff --git a/wolfcrypt/test/test.c b/wolfcrypt/test/test.c index 04c6b5838..be79698c3 100644 --- a/wolfcrypt/test/test.c +++ b/wolfcrypt/test/test.c @@ -5860,8 +5860,8 @@ WOLFSSL_TEST_SUBROUTINE int chacha20_poly1305_aead_test(void) sizeof(plaintext1), generatedCiphertext, NULL); if (err != BAD_FUNC_ARG) return -4904; - err = wc_ChaCha20Poly1305_Encrypt(key1, iv1, aad1, sizeof(aad1), plaintext1, - 0, generatedCiphertext, generatedAuthTag); + err = wc_ChaCha20Poly1305_Encrypt(key1, iv1, aad1, sizeof(aad1), NULL, + sizeof(plaintext1), generatedCiphertext, generatedAuthTag); if (err != BAD_FUNC_ARG) return -4905; /* Decrypt */ @@ -5885,8 +5885,8 @@ WOLFSSL_TEST_SUBROUTINE int chacha20_poly1305_aead_test(void) sizeof(cipher2), authTag2, NULL); if (err != BAD_FUNC_ARG) return -4910; - err = wc_ChaCha20Poly1305_Decrypt(key2, iv2, aad2, sizeof(aad2), cipher2, - 0, authTag2, generatedPlaintext); + err = wc_ChaCha20Poly1305_Decrypt(key2, iv2, aad2, sizeof(aad2), NULL, + sizeof(cipher2), authTag2, generatedPlaintext); if (err != BAD_FUNC_ARG) return -4911; diff --git a/wolfssl/wolfcrypt/rsa.h b/wolfssl/wolfcrypt/rsa.h index 70697f5a5..8d3c243a8 100644 --- a/wolfssl/wolfcrypt/rsa.h +++ b/wolfssl/wolfcrypt/rsa.h @@ -329,12 +329,14 @@ WOLFSSL_API int wc_RsaPublicKeyDecodeRaw(const byte* n, word32 nSz, */ /* Mask Generation Function Identifiers */ -#define WC_MGF1NONE 0 -#define WC_MGF1SHA1 26 -#define WC_MGF1SHA224 4 -#define WC_MGF1SHA256 1 -#define WC_MGF1SHA384 2 -#define WC_MGF1SHA512 3 +#define WC_MGF1NONE 0 +#define WC_MGF1SHA1 26 +#define WC_MGF1SHA224 4 +#define WC_MGF1SHA256 1 +#define WC_MGF1SHA384 2 +#define WC_MGF1SHA512 3 +#define WC_MGF1SHA512_224 5 +#define WC_MGF1SHA512_256 6 /* Padding types */ #define WC_RSA_PKCSV15_PAD 0