forked from wolfSSL/wolfssl
RSA Decrypt Bounds Checking
1. Added some bounds checking on the ciphertext passed into the RSA decrypt function. NIST SP 800-56B specifies that the ciphertext shouldn't be a number larger than the modulus. 2. Added an API test to check that the direct RSA decrypt function returns an error with a "bad" message. 3. Added an ifndef guard to disable the bounds check. Default is to keep the bounds check. 4. RSA Decrypt bounds check only checked the first time into wc_RsaFunction().
This commit is contained in:
78
tests/api.c
78
tests/api.c
@@ -9495,6 +9495,83 @@ static int test_wc_MakeRsaKey (void)
|
|||||||
|
|
||||||
} /* END test_wc_MakeRsaKey */
|
} /* END test_wc_MakeRsaKey */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Test the bounds checking on the cipher text versus the key modulus.
|
||||||
|
* 1. Make a new RSA key.
|
||||||
|
* 2. Set c to 1.
|
||||||
|
* 3. Decrypt c into k. (error)
|
||||||
|
* 4. Copy the key modulus to c and sub 1 from the copy.
|
||||||
|
* 5. Decrypt c into k. (error)
|
||||||
|
* Valid bounds test cases are covered by all the other RSA tests.
|
||||||
|
*/
|
||||||
|
static int test_RsaDecryptBoundsCheck(void)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
#if !defined(NO_RSA) && defined(WC_RSA_NO_PADDING) && \
|
||||||
|
(defined(USE_CERT_BUFFERS_1024) || defined(USE_CERT_BUFFERS_2048)) && \
|
||||||
|
defined(WOLFSSL_PUBLIC_MP) && !defined(NO_RSA_BOUNDS_CHECK)
|
||||||
|
RsaKey key;
|
||||||
|
byte flatC[256];
|
||||||
|
word32 flatCSz;
|
||||||
|
byte out[256];
|
||||||
|
word32 outSz = sizeof(out);
|
||||||
|
WC_RNG rng;
|
||||||
|
|
||||||
|
printf(testingFmt, "RSA decrypt bounds check");
|
||||||
|
|
||||||
|
ret = wc_InitRng(&rng);
|
||||||
|
|
||||||
|
if (ret == 0)
|
||||||
|
ret = wc_InitRsaKey(&key, NULL);
|
||||||
|
|
||||||
|
if (ret == 0) {
|
||||||
|
const byte* derKey;
|
||||||
|
word32 derKeySz;
|
||||||
|
word32 idx = 0;
|
||||||
|
|
||||||
|
#ifdef USE_CERT_BUFFERS_1024
|
||||||
|
derKey = server_key_der_1024;
|
||||||
|
derKeySz = (word32)sizeof_server_key_der_1024;
|
||||||
|
flatCSz = 128;
|
||||||
|
#else
|
||||||
|
derKey = server_key_der_2048;
|
||||||
|
derKeySz = (word32)sizeof_server_key_der_2048;
|
||||||
|
flatCSz = 256;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
ret = wc_RsaPrivateKeyDecode(derKey, &idx, &key, derKeySz);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ret == 0) {
|
||||||
|
XMEMSET(flatC, 0, flatCSz);
|
||||||
|
flatC[flatCSz-1] = 1;
|
||||||
|
|
||||||
|
ret = wc_RsaDirect(flatC, flatCSz, out, &outSz, &key,
|
||||||
|
RSA_PRIVATE_DECRYPT, &rng);
|
||||||
|
}
|
||||||
|
if (ret == RSA_OUT_OF_RANGE_E) {
|
||||||
|
mp_int c;
|
||||||
|
mp_init_copy(&c, &key.n);
|
||||||
|
mp_sub_d(&c, 1, &c);
|
||||||
|
mp_to_unsigned_bin(&c, flatC);
|
||||||
|
ret = wc_RsaDirect(flatC, sizeof(flatC), out, &outSz, &key,
|
||||||
|
RSA_PRIVATE_DECRYPT, NULL);
|
||||||
|
mp_clear(&c);
|
||||||
|
}
|
||||||
|
if (ret == RSA_OUT_OF_RANGE_E)
|
||||||
|
ret = 0;
|
||||||
|
|
||||||
|
if (wc_FreeRsaKey(&key) || wc_FreeRng(&rng) || ret != 0)
|
||||||
|
ret = WOLFSSL_FATAL_ERROR;
|
||||||
|
|
||||||
|
printf(resultFmt, ret == 0 ? passed : failed);
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
} /* END test_wc_RsaDecryptBoundsCheck */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Testing wc_SetKeyUsage()
|
* Testing wc_SetKeyUsage()
|
||||||
*/
|
*/
|
||||||
@@ -17586,6 +17663,7 @@ void ApiTest(void)
|
|||||||
AssertIntEQ(test_wc_RsaEncryptSize(), 0);
|
AssertIntEQ(test_wc_RsaEncryptSize(), 0);
|
||||||
AssertIntEQ(test_wc_RsaSSL_SignVerify(), 0);
|
AssertIntEQ(test_wc_RsaSSL_SignVerify(), 0);
|
||||||
AssertIntEQ(test_wc_RsaFlattenPublicKey(), 0);
|
AssertIntEQ(test_wc_RsaFlattenPublicKey(), 0);
|
||||||
|
AssertIntEQ(test_RsaDecryptBoundsCheck(), 0);
|
||||||
AssertIntEQ(test_wc_AesCcmSetKey(), 0);
|
AssertIntEQ(test_wc_AesCcmSetKey(), 0);
|
||||||
AssertIntEQ(test_wc_AesCcmEncryptDecrypt(), 0);
|
AssertIntEQ(test_wc_AesCcmEncryptDecrypt(), 0);
|
||||||
AssertIntEQ(test_wc_Hc128_SetKey(), 0);
|
AssertIntEQ(test_wc_Hc128_SetKey(), 0);
|
||||||
|
@@ -452,6 +452,9 @@ const char* wc_GetErrorString(int error)
|
|||||||
case BER_INDEF_E:
|
case BER_INDEF_E:
|
||||||
return "Unable to decode an indefinite length encoded message";
|
return "Unable to decode an indefinite length encoded message";
|
||||||
|
|
||||||
|
case RSA_OUT_OF_RANGE_E:
|
||||||
|
return "Ciphertext to decrypt is out of range";
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return "unknown error number";
|
return "unknown error number";
|
||||||
|
|
||||||
|
@@ -1326,7 +1326,7 @@ static int wc_RsaFunctionSync(const byte* in, word32 inLen, byte* out,
|
|||||||
/* tmp = tmp*rnd mod n */
|
/* tmp = tmp*rnd mod n */
|
||||||
if (mp_mulmod(&tmp, &rnd, &key->n, &tmp) != MP_OKAY)
|
if (mp_mulmod(&tmp, &rnd, &key->n, &tmp) != MP_OKAY)
|
||||||
ERROR_OUT(MP_MULMOD_E);
|
ERROR_OUT(MP_MULMOD_E);
|
||||||
#endif /* WC_RSA_BLINGING */
|
#endif /* WC_RSA_BLINDING */
|
||||||
|
|
||||||
#ifdef RSA_LOW_MEM /* half as much memory but twice as slow */
|
#ifdef RSA_LOW_MEM /* half as much memory but twice as slow */
|
||||||
if (mp_exptmod(&tmp, &key->d, &key->n, &tmp) != MP_OKAY)
|
if (mp_exptmod(&tmp, &key->d, &key->n, &tmp) != MP_OKAY)
|
||||||
@@ -1609,13 +1609,44 @@ int wc_RsaDirect(byte* in, word32 inLen, byte* out, word32* outSz,
|
|||||||
int wc_RsaFunction(const byte* in, word32 inLen, byte* out,
|
int wc_RsaFunction(const byte* in, word32 inLen, byte* out,
|
||||||
word32* outLen, int type, RsaKey* key, WC_RNG* rng)
|
word32* outLen, int type, RsaKey* key, WC_RNG* rng)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret = 0;
|
||||||
|
|
||||||
if (key == NULL || in == NULL || inLen == 0 || out == NULL ||
|
if (key == NULL || in == NULL || inLen == 0 || out == NULL ||
|
||||||
outLen == NULL || *outLen == 0 || type == RSA_TYPE_UNKNOWN) {
|
outLen == NULL || *outLen == 0 || type == RSA_TYPE_UNKNOWN) {
|
||||||
return BAD_FUNC_ARG;
|
return BAD_FUNC_ARG;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef NO_RSA_BOUNDS_CHECK
|
||||||
|
if (type == RSA_PRIVATE_DECRYPT &&
|
||||||
|
key->state == RSA_STATE_DECRYPT_EXPTMOD) {
|
||||||
|
|
||||||
|
/* Check that 1 < in < n-1. (Requirement of 800-56B.) */
|
||||||
|
mp_int c;
|
||||||
|
|
||||||
|
if (mp_init(&c) != MP_OKAY)
|
||||||
|
ret = MEMORY_E;
|
||||||
|
if (ret == 0) {
|
||||||
|
if (mp_read_unsigned_bin(&c, in, inLen) != 0)
|
||||||
|
ret = MP_READ_E;
|
||||||
|
}
|
||||||
|
if (ret == 0) {
|
||||||
|
/* check c > 1 */
|
||||||
|
if (mp_cmp_d(&c, 1) != MP_GT)
|
||||||
|
ret = RSA_OUT_OF_RANGE_E;
|
||||||
|
}
|
||||||
|
if (ret == 0) {
|
||||||
|
/* check c+1 < n */
|
||||||
|
mp_add_d(&c, 1, &c);
|
||||||
|
if (mp_cmp(&c, &key->n) != MP_LT)
|
||||||
|
ret = RSA_OUT_OF_RANGE_E;
|
||||||
|
}
|
||||||
|
mp_clear(&c);
|
||||||
|
|
||||||
|
if (ret != 0)
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
#endif /* NO_RSA_BOUNDS_CHECK */
|
||||||
|
|
||||||
#if defined(WOLFSSL_ASYNC_CRYPT) && defined(WC_ASYNC_ENABLE_RSA)
|
#if defined(WOLFSSL_ASYNC_CRYPT) && defined(WC_ASYNC_ENABLE_RSA)
|
||||||
if (key->asyncDev.marker == WOLFSSL_ASYNC_MARKER_RSA &&
|
if (key->asyncDev.marker == WOLFSSL_ASYNC_MARKER_RSA &&
|
||||||
key->n.raw.len > 0) {
|
key->n.raw.len > 0) {
|
||||||
|
@@ -197,10 +197,10 @@ enum {
|
|||||||
|
|
||||||
PSS_SALTLEN_E = -250, /* PSS length of salt is to long for hash */
|
PSS_SALTLEN_E = -250, /* PSS length of salt is to long for hash */
|
||||||
PRIME_GEN_E = -251, /* Failure finding a prime. */
|
PRIME_GEN_E = -251, /* Failure finding a prime. */
|
||||||
|
|
||||||
BER_INDEF_E = -252, /* Cannot decode indefinite length BER. */
|
BER_INDEF_E = -252, /* Cannot decode indefinite length BER. */
|
||||||
|
RSA_OUT_OF_RANGE_E = -253, /* Ciphertext to decrypt out of range. */
|
||||||
|
|
||||||
WC_LAST_E = -252, /* Update this to indicate last error */
|
WC_LAST_E = -253, /* Update this to indicate last error */
|
||||||
MIN_CODE_E = -300 /* errors -101 - -299 */
|
MIN_CODE_E = -300 /* errors -101 - -299 */
|
||||||
|
|
||||||
/* add new companion error id strings for any new error codes
|
/* add new companion error id strings for any new error codes
|
||||||
|
Reference in New Issue
Block a user