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 */
|
||||
|
||||
/*
|
||||
* 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()
|
||||
*/
|
||||
@ -17586,6 +17663,7 @@ void ApiTest(void)
|
||||
AssertIntEQ(test_wc_RsaEncryptSize(), 0);
|
||||
AssertIntEQ(test_wc_RsaSSL_SignVerify(), 0);
|
||||
AssertIntEQ(test_wc_RsaFlattenPublicKey(), 0);
|
||||
AssertIntEQ(test_RsaDecryptBoundsCheck(), 0);
|
||||
AssertIntEQ(test_wc_AesCcmSetKey(), 0);
|
||||
AssertIntEQ(test_wc_AesCcmEncryptDecrypt(), 0);
|
||||
AssertIntEQ(test_wc_Hc128_SetKey(), 0);
|
||||
|
@ -452,6 +452,9 @@ const char* wc_GetErrorString(int error)
|
||||
case BER_INDEF_E:
|
||||
return "Unable to decode an indefinite length encoded message";
|
||||
|
||||
case RSA_OUT_OF_RANGE_E:
|
||||
return "Ciphertext to decrypt is out of range";
|
||||
|
||||
default:
|
||||
return "unknown error number";
|
||||
|
||||
|
@ -1326,7 +1326,7 @@ static int wc_RsaFunctionSync(const byte* in, word32 inLen, byte* out,
|
||||
/* tmp = tmp*rnd mod n */
|
||||
if (mp_mulmod(&tmp, &rnd, &key->n, &tmp) != MP_OKAY)
|
||||
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 */
|
||||
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,
|
||||
word32* outLen, int type, RsaKey* key, WC_RNG* rng)
|
||||
{
|
||||
int ret;
|
||||
int ret = 0;
|
||||
|
||||
if (key == NULL || in == NULL || inLen == 0 || out == NULL ||
|
||||
outLen == NULL || *outLen == 0 || type == RSA_TYPE_UNKNOWN) {
|
||||
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 (key->asyncDev.marker == WOLFSSL_ASYNC_MARKER_RSA &&
|
||||
key->n.raw.len > 0) {
|
||||
|
@ -197,10 +197,10 @@ enum {
|
||||
|
||||
PSS_SALTLEN_E = -250, /* PSS length of salt is to long for hash */
|
||||
PRIME_GEN_E = -251, /* Failure finding a prime. */
|
||||
|
||||
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 */
|
||||
|
||||
/* add new companion error id strings for any new error codes
|
||||
|
Reference in New Issue
Block a user