From a5d8c1dd34924dabc4b09e1de45a7de1c5a72f60 Mon Sep 17 00:00:00 2001 From: Hayden Roche Date: Fri, 22 Apr 2022 10:58:48 -0700 Subject: [PATCH 1/3] Add support for X9.31 padding with RSA signatures. --- src/we_rsa.c | 423 +++++++++++++++++++++++++++++++++++++++++++++++- test/test_rsa.c | 154 ++++++++++-------- test/unit.c | 1 + test/unit.h | 1 + 4 files changed, 511 insertions(+), 68 deletions(-) diff --git a/src/we_rsa.c b/src/we_rsa.c index d26ebab..377ed22 100644 --- a/src/we_rsa.c +++ b/src/we_rsa.c @@ -219,6 +219,214 @@ static int we_pss_salt_len_to_wc(int saltLen, const EVP_MD *md, RsaKey *key, return saltLen; } +/** + * Add X9.31 padding to the input buffer, placing the result in the output + * buffer. + * + * @param to [out] Buffer to store padded result. + * @param toLen [in] Length of "to" buffer. + * @param from [in] Input buffer. + * @param fromLen [in] Length of input buffer. + * @returns 1 on success and 0 on failure. + */ +static int we_add_x931_padding(unsigned char* to, size_t toLen, + const unsigned char* from, size_t fromLen) +{ + int ret = 1; + int padBytes; + + WOLFENGINE_ENTER(WE_LOG_PK, "we_add_x931_padding"); + WOLFENGINE_MSG_VERBOSE(WE_LOG_PK, "ARGS [to = %p, toLen = %zu, from = %p, " + "fromLen = %zu]", to, toLen, from, fromLen); + + if (to == NULL || from == NULL) { + WOLFENGINE_ERROR_MSG(WE_LOG_PK, "Bad argument."); + ret = 0; + } + else { + /* Need at least two bytes for trailer and header. */ + padBytes = toLen - fromLen - 2; + if (padBytes < 0) { + WOLFENGINE_ERROR_MSG(WE_LOG_PK, "Output buffer too small."); + ret = 0; + } + } + + if (ret == 1) { + if (padBytes == 0) { + to[0] = 0x6A; + } + else { + to[0] = 0x6B; + if (padBytes > 1) { + XMEMSET(&to[1], 0xBB, padBytes - 1); + } + to[padBytes] = 0xBA; + } + + XMEMCPY(&to[padBytes + 1], from, fromLen); + to[toLen - 1] = 0xCC; + } + + WOLFENGINE_LEAVE(WE_LOG_PK, "we_add_x931_padding", ret); + + return ret; +} + +/** + * Remove X9.31 padding from the input buffer, placing the result in the output + * buffer. + * + * @param to [out] Pointer to buffer holding unpadded result. This + * buffer will be allocated by this function if *to is + * NULL. + * @param from [in] Input buffer. + * @param fromLen [in] Length of input buffer. + * @returns Length of unpadded result on success and -1 on failure. + */ +static int we_remove_x931_padding(unsigned char** to, const unsigned char* from, + size_t fromLen) +{ + int ret = 1; + size_t idx = 0; + int numCopy = 0; + + WOLFENGINE_ENTER(WE_LOG_PK, "we_remove_x931_padding"); + WOLFENGINE_MSG_VERBOSE(WE_LOG_PK, "ARGS [to = %p, from = %p, fromLen = " + "%zu]", to, from, fromLen); + + if (to == NULL || from == NULL || fromLen < 2) { + WOLFENGINE_ERROR_MSG(WE_LOG_PK, "Bad argument."); + ret = -1; + } + else { + if (from[fromLen - 1] != 0xCC) { + WOLFENGINE_ERROR_MSG(WE_LOG_PK, "Bad X9.31 trailer."); + ret = -1; + } + + if (from[idx] == 0x6B) { + while (++idx < fromLen && from[idx] == 0xBB) {} + + if (idx == fromLen || from[idx] != 0xBA) { + WOLFENGINE_ERROR_MSG(WE_LOG_PK, "Bad X9.31 padding."); + ret = -1; + } + } + else if (from[idx] != 0x6A) { + WOLFENGINE_ERROR_MSG(WE_LOG_PK, "Bad X9.31 header."); + ret = -1; + } + } + + if (ret == 1) { + ++idx; + numCopy = fromLen - idx - 1; + if (numCopy > 0) { + if (*to == NULL) { + *to = (unsigned char*)OPENSSL_malloc(numCopy); + if (*to == NULL) { + WOLFENGINE_ERROR_FUNC_NULL(WE_LOG_PK, "OPENSSL_malloc", + *to); + ret = -1; + } + } + if (ret == 1){ + XMEMCPY(*to, from + idx, numCopy); + } + } + } + + if (ret == 1) { + ret = numCopy; + } + + WOLFENGINE_LEAVE(WE_LOG_PK, "we_remove_x931_padding", ret); + + return ret; +} + +/** + * Return the X9.31 code associated with the passed in NID. + * + * @param nid [in] NID associated with hash. + * @returns Hash code on success and 0 on failure. + */ +static int we_rsa_get_x931_hash_code(int nid) { + int ret = 0; + + if (nid == NID_sha1) { + ret = 0x33; + } + else if (nid == NID_sha256) { + ret = 0x34; + } + else if (nid == NID_sha384) { + ret = 0x36; + } + else if (nid == NID_sha512) { + ret = 0x35; + } + + return ret; +} + +/** + * Add the X9.31 hash code derived from the digest to the end of the input + * buffer. + * + * @param md [in] Digest to derive hash code from. + * @param to [out] Pointer to output buffer. If NULL, this function will + * allocate the buffer for the caller. If not NULL, the + * buffer should be at least fromLen + 1 bytes long. + * @param from [in] Input buffer. + * @param fromLen [in] Length of input buffer. + * @returns 1 on success and 0 on failure. + */ +static int we_rsa_add_x931_hash_code(const EVP_MD* md, unsigned char** to, + const unsigned char* from, size_t fromLen) +{ + int ret = 1; + int nid; + unsigned char hashCode; + char errBuff[WOLFENGINE_MAX_LOG_WIDTH]; + + WOLFENGINE_ENTER(WE_LOG_PK, "we_rsa_add_x931_hash_code"); + WOLFENGINE_MSG_VERBOSE(WE_LOG_PK, "ARGS [md = %p, to = %p, from = %p, " + "fromLen = %zu]", md, to, from, fromLen); + + if (md == NULL || to == NULL || from == NULL || fromLen == 0) { + WOLFENGINE_ERROR_MSG(WE_LOG_PK, "Bad argument."); + ret = 0; + } + + if (ret == 1 && *to == NULL) { + *to = (unsigned char*)OPENSSL_malloc(fromLen + 1); + if (*to == NULL) { + WOLFENGINE_ERROR_FUNC_NULL(WE_LOG_PK, "OPENSSL_malloc", *to); + ret = 0; + } + } + if (ret == 1) { + nid = EVP_MD_type(md); + hashCode = we_rsa_get_x931_hash_code(nid); + if (hashCode == 0) { + XSNPRINTF(errBuff, sizeof(errBuff), "Unsupported digest NID: %d.", + nid); + WOLFENGINE_ERROR_MSG(WE_LOG_PK, errBuff); + ret = 0; + } + } + if (ret == 1) { + XMEMCPY(*to, from, fromLen); + (*to)[fromLen] = hashCode; + } + + WOLFENGINE_LEAVE(WE_LOG_PK, "we_rsa_add_x931_hash_code", ret); + + return ret; +} + /** * Set the public key in a we_Rsa structure. * @@ -807,6 +1015,11 @@ static int we_rsa_priv_enc_int(size_t fromLen, const unsigned char *from, WC_RNG *rng = we_rng; #endif char errBuff[WOLFENGINE_MAX_LOG_WIDTH]; + unsigned char* padded = NULL; + int paddedSz; + mp_int toMp; + mp_int nMinusTo; + int rc; WOLFENGINE_ENTER(WE_LOG_PK, "we_rsa_priv_enc_int"); WOLFENGINE_MSG_VERBOSE(WE_LOG_PK, "ARGS [fromLen = %zu, from = %p, " @@ -867,6 +1080,81 @@ static int we_rsa_priv_enc_int(size_t fromLen, const unsigned char *from, ret = -1; } } + break; + case RSA_X931_PADDING: + WOLFENGINE_MSG(WE_LOG_PK, "padMode: RSA_X931_PADDING"); + paddedSz = wc_RsaEncryptSize(&rsa->key); + if (paddedSz <= 0) { + WOLFENGINE_ERROR_FUNC(WE_LOG_PK, "wc_RsaEncryptSize", ret); + ret = -1; + } + else { + padded = (unsigned char *)OPENSSL_malloc(paddedSz); + if (padded == NULL) { + WOLFENGINE_ERROR_FUNC_NULL(WE_LOG_PK, "OPENSSL_malloc", + padded); + ret = -1; + } + else { + ret = we_add_x931_padding(padded, paddedSz, from, fromLen); + if (ret != 1) { + WOLFENGINE_ERROR_FUNC(WE_LOG_PK, "we_add_x931_padding", ret); + ret = -1; + } + else { + ret = wc_RsaDirect(padded, paddedSz, to, &tLen, + &rsa->key, RSA_PRIVATE_ENCRYPT, rng); + if (ret < 0) { + WOLFENGINE_ERROR_FUNC(WE_LOG_PK, "wc_RsaDirect", + ret); + ret = -1; + } + } + } + } + + if (padded != NULL) { + OPENSSL_free(padded); + } + + if (ret != -1) { + rc = mp_init_multi(&toMp, &nMinusTo, NULL, NULL, NULL, NULL); + if (rc != MP_OKAY) { + WOLFENGINE_ERROR_FUNC(WE_LOG_PK, "mp_init_multi", rc); + ret = -1; + } + else { + rc = mp_read_unsigned_bin(&toMp, to, toLen); + if (rc != MP_OKAY) { + WOLFENGINE_ERROR_FUNC(WE_LOG_PK, "mp_read_unsigned_bin", + rc); + ret = -1; + } + else { + /* + * X9.31 specifies, "The signature is either the result + * or its complement to n, whichever is smaller." + */ + rc = mp_sub(&rsa->key.n, &toMp, &nMinusTo); + if (rc != MP_OKAY) { + WOLFENGINE_ERROR_FUNC(WE_LOG_PK, "mp_sub", rc); + ret = -1; + } + else if (mp_cmp(&toMp, &nMinusTo) == MP_GT) { + rc = mp_to_unsigned_bin(&nMinusTo, to); + if (rc != MP_OKAY) { + WOLFENGINE_ERROR_FUNC(WE_LOG_PK, + "mp_to_unsigned_bin", rc); + ret = -1; + } + } + } + + mp_free(&toMp); + mp_free(&nMinusTo); + } + } + break; default: /* Unsupported padding mode for RSA private encryption. */ @@ -991,6 +1279,10 @@ static int we_rsa_pub_dec_int(size_t fromLen, const unsigned char *from, WC_RNG *rng = we_rng; #endif char errBuff[WOLFENGINE_MAX_LOG_WIDTH]; + unsigned char* unpadded = NULL; + mp_int toMp; + mp_int nMinusTo; + int rc; WOLFENGINE_ENTER(WE_LOG_PK, "we_rsa_pub_dec_int"); WOLFENGINE_MSG_VERBOSE(WE_LOG_PK, "ARGS [fromLen = %zu, from = %p, " @@ -1065,6 +1357,73 @@ static int we_rsa_pub_dec_int(size_t fromLen, const unsigned char *from, } } break; + case RSA_X931_PADDING: + WOLFENGINE_MSG(WE_LOG_PK, "padMode: RSA_X931_PADDING"); + ret = wc_RsaDirect((byte*)from, (unsigned int)fromLen, to, + &tLen, &rsa->key, RSA_PUBLIC_DECRYPT, rng); + if (ret < 0) { + WOLFENGINE_ERROR_FUNC(WE_LOG_PK, "wc_RsaDirect", ret); + ret = -1; + } + else { + /* + * X9.31 specifies, "If e is odd, then + * - If RR = 12 mod 16, then IR = RR ; + * - If n - RR = 12 mod 16, then IR = n - RR ;" + * RR is "to" and IR is the value to unpad in the next + * step. Taking "to" mod 16 is the same as just checking the + * lower 4 bits of "to." + */ + if ((to[toLen-1] & 0x0F) != 12) { + rc = mp_init_multi(&toMp, &nMinusTo, NULL, NULL, NULL, + NULL); + if (rc != MP_OKAY) { + WOLFENGINE_ERROR_FUNC(WE_LOG_PK, "mp_init_multi", + ret); + ret = -1; + } + else { + rc = mp_read_unsigned_bin(&toMp, to, toLen); + if (rc != MP_OKAY) { + WOLFENGINE_ERROR_FUNC(WE_LOG_PK, + "mp_read_unsigned_bin", ret); + ret = -1; + } + else { + rc = mp_sub(&rsa->key.n, &toMp, &nMinusTo); + if (rc != MP_OKAY) { + WOLFENGINE_ERROR_FUNC(WE_LOG_PK, "mp_sub", rc); + ret = -1; + } + else { + rc = mp_to_unsigned_bin(&nMinusTo, to); + if (rc != MP_OKAY) { + WOLFENGINE_ERROR_FUNC(WE_LOG_PK, + "mp_to_unsigned_bin", rc); + ret = -1; + } + } + } + + mp_free(&toMp); + mp_free(&nMinusTo); + } + } + + if (ret != -1) { + ret = we_remove_x931_padding(&unpadded, to, tLen); + if (ret <= 0) { + WOLFENGINE_ERROR_FUNC(WE_LOG_PK, + "we_remove_x931_padding", ret); + ret = -1; + } + else { + XMEMCPY(to, unpadded, ret); + OPENSSL_free(unpadded); + } + } + } + break; default: /* Unsupported padding mode for RSA public decryption. */ XSNPRINTF(errBuff, sizeof(errBuff), "Unknown padding mode: %d", @@ -1649,7 +2008,8 @@ static int we_rsa_pkey_ctrl(EVP_PKEY_CTX *ctx, int type, int num, void *ptr) if (num != RSA_PKCS1_PADDING && num != RSA_PKCS1_PSS_PADDING && num != RSA_PKCS1_OAEP_PADDING && - num != RSA_NO_PADDING) + num != RSA_NO_PADDING && + num != RSA_X931_PADDING) { WOLFENGINE_ERROR_MSG(WE_LOG_PK, "Unsupported RSA padding mode."); @@ -2113,6 +2473,7 @@ static int we_rsa_pkey_sign(EVP_PKEY_CTX *ctx, unsigned char *sig, int len; int actualSigLen = 0; int keySize = 0; + unsigned char* tbsWithHashCode = NULL; WOLFENGINE_ENTER(WE_LOG_PK, "we_rsa_pkey_sign"); WOLFENGINE_MSG_VERBOSE(WE_LOG_PK, "ARGS [ctx = %p, sig = %p, sigLen = %p, " @@ -2204,6 +2565,26 @@ static int we_rsa_pkey_sign(EVP_PKEY_CTX *ctx, unsigned char *sig, } } if (ret == 1) { + if (rsa->padMode == RSA_X931_PADDING) { + if (rsa->md == NULL) { + WOLFENGINE_ERROR_MSG(WE_LOG_PK, "No digest specified for " + "X9.31 padding."); + ret = 0; + } + else { + ret = we_rsa_add_x931_hash_code(rsa->md, &tbsWithHashCode, + tbs, tbsLen); + if (ret != 1) { + WOLFENGINE_ERROR_FUNC(WE_LOG_PK, + "we_rsa_add_x931_hash_code", ret); + ret = 0; + } + else { + tbs = tbsWithHashCode; + ++tbsLen; + } + } + } /* Pad and private encrypt. */ actualSigLen = we_rsa_priv_enc_int(tbsLen, tbs, *sigLen, sig, rsa); if (actualSigLen == -1) { @@ -2221,6 +2602,9 @@ static int we_rsa_pkey_sign(EVP_PKEY_CTX *ctx, unsigned char *sig, if (encodedDigest != NULL) { OPENSSL_free(encodedDigest); } + if (tbsWithHashCode != NULL) { + OPENSSL_free(tbsWithHashCode); + } WOLFENGINE_LEAVE(WE_LOG_PK, "we_rsa_pkey_sign", ret); @@ -2250,6 +2634,9 @@ static int we_rsa_pkey_verify(EVP_PKEY_CTX *ctx, const unsigned char *sig, unsigned char *encodedDigest = NULL; int encodedDigestLen = 0; int keySize = 0; + int nid; + unsigned char hashCode; + char errBuff[WOLFENGINE_MAX_LOG_WIDTH]; WOLFENGINE_ENTER(WE_LOG_PK, "we_rsa_pkey_verify"); WOLFENGINE_MSG_VERBOSE(WE_LOG_PK, "ARGS [ctx = %p, sig = %p, sigLen = %zu, " @@ -2354,6 +2741,40 @@ static int we_rsa_pkey_verify(EVP_PKEY_CTX *ctx, const unsigned char *sig, tbsLen = encodedDigestLen; } } + if (ret == 1 && rsa->padMode == RSA_X931_PADDING) { + if (rsa->md == NULL) { + WOLFENGINE_ERROR_MSG(WE_LOG_PK, "No digest specified for " + "X9.31 padding."); + ret = 0; + } + else { + nid = EVP_MD_type(rsa->md); + hashCode = we_rsa_get_x931_hash_code(nid); + if (hashCode == 0) { + XSNPRINTF(errBuff, sizeof(errBuff), "Unsupported digest " + "NID: %d.", nid); + WOLFENGINE_ERROR_MSG(WE_LOG_PK, errBuff); + ret = 0; + } + else { + if (hashCode != decryptedSig[rc-1]) { + XSNPRINTF(errBuff, sizeof(errBuff), "Expected hash code" + ": 0x%02X but got 0x%02X.", hashCode, + decryptedSig[rc-1]); + WOLFENGINE_ERROR_MSG(WE_LOG_PK, errBuff); + ret = 0; + } + else if (EVP_MD_size(rsa->md) != (rc - 1)) { + WOLFENGINE_ERROR_MSG(WE_LOG_PK, "Actual Digest size " + "doesn't match digest size implied by hash code."); + ret = 0; + } + else { + --rc; + } + } + } + } if ((ret == 1) && (tbsLen != (size_t)rc)) { WOLFENGINE_ERROR_MSG(WE_LOG_PK, "Encoding different size"); ret = 0; diff --git a/test/test_rsa.c b/test/test_rsa.c index 813edda..19baaf0 100644 --- a/test/test_rsa.c +++ b/test/test_rsa.c @@ -384,15 +384,14 @@ static int test_rsa_direct(ENGINE *e, const unsigned char *der, size_t derLen, int inBufLen; } TestVector; #if defined(_MSC_VER) || defined(__MINGW32__) || defined(__CYGWIN__) || defined(_WIN32_WCE) -#define numTestVectors 3 +#define numTestVectors 4 #else - const int numTestVectors = 3; + const int numTestVectors = 4; #endif TestVector testVectors[numTestVectors]; int i = 0; int rsaSize = 0; - PRINT_MSG("Load RSA key"); err = load_static_rsa_key(e, der, derLen, &weRsaKey, &osslRsaKey) != 1; if (err == 0) { rsaSize = RSA_size(weRsaKey); @@ -434,6 +433,10 @@ static int test_rsa_direct(ENGINE *e, const unsigned char *der, size_t derLen, testVectors[2].padName = "RSA_NO_PADDING"; testVectors[2].inBuf = noPaddingBuf; testVectors[2].inBufLen = rsaSize; + testVectors[3].padding = RSA_X931_PADDING; + testVectors[3].padName = "RSA_X931_PADDING"; + testVectors[3].inBuf = buf; + testVectors[3].inBufLen = sizeof(buf); } for (; err == 0 && i < numTestVectors; ++i) { @@ -447,7 +450,6 @@ static int test_rsa_direct(ENGINE *e, const unsigned char *der, size_t derLen, } if (err == 0) { PRINT_MSG("Private encrypt with wolfengine"); - PRINT_MSG(testVectors[i].padName); encryptedLen = RSA_private_encrypt(testVectors[i].inBufLen, testVectors[i].inBuf, encryptedBuf, weRsaKey, @@ -464,6 +466,11 @@ static int test_rsa_direct(ENGINE *e, const unsigned char *der, size_t derLen, } break; case PRIVATE_DECRYPT: + if (testVectors[i].padding == RSA_X931_PADDING) { + /* OpenSSL doesn't support X9.31 padding for private + * decrypt. */ + continue; + } if (err == 0) { PRINT_MSG("Public encrypt with OpenSSL"); encryptedLen = RSA_public_encrypt(testVectors[i].inBufLen, @@ -482,9 +489,13 @@ static int test_rsa_direct(ENGINE *e, const unsigned char *der, size_t derLen, } break; case PUBLIC_ENCRYPT: + if (testVectors[i].padding == RSA_X931_PADDING) { + /* OpenSSL doesn't support X9.31 padding for public + * encrypt. */ + continue; + } if (err == 0) { PRINT_MSG("Public encrypt with wolfengine"); - PRINT_MSG(testVectors[i].padName); encryptedLen = RSA_public_encrypt(testVectors[i].inBufLen, testVectors[i].inBuf, encryptedBuf, weRsaKey, @@ -508,7 +519,6 @@ static int test_rsa_direct(ENGINE *e, const unsigned char *der, size_t derLen, } if (err == 0) { PRINT_MSG("Private encrypt with OpenSSL"); - PRINT_MSG(testVectors[i].padName); encryptedLen = RSA_private_encrypt(testVectors[i].inBufLen, testVectors[i].inBuf, encryptedBuf, osslRsaKey, @@ -729,7 +739,6 @@ static int test_rsa_sign_verify_pad(ENGINE *e, int padMode, const EVP_MD *md, unsigned char *buf = NULL; const unsigned char *p = rsa_key_der_2048; - PRINT_MSG("Load RSA key"); pkey = d2i_PrivateKey(EVP_PKEY_RSA, NULL, &p, sizeof(rsa_key_der_2048)); err = pkey == NULL; if (err == 0) { @@ -757,69 +766,73 @@ static int test_rsa_sign_verify_pad(ENGINE *e, int padMode, const EVP_MD *md, buf[0] = 0; } - /* Don't run these first tests in the case of PSS, which is strictly for - * signatures and not arbitrary data. */ - if ((err == 0) && (padMode != RSA_PKCS1_PSS_PADDING)) { - PRINT_MSG("Test signing/verifying arbitrary data"); - PRINT_MSG("Sign with OpenSSL"); - err = test_pkey_sign(pkey, NULL, buf, bufLen, rsaSig, &rsaSigLen, - padMode, md, mgf1Md); - } - if ((err == 0) && (padMode != RSA_PKCS1_PSS_PADDING)) { - PRINT_MSG("Verify with wolfengine"); - err = test_pkey_verify(pkey, e, buf, bufLen, rsaSig, rsaSigLen, - padMode, md, mgf1Md); - } - if ((err == 0) && (padMode != RSA_PKCS1_PSS_PADDING)) { - PRINT_MSG("Verify bad signature with wolfengine"); - rsaSig[1] ^= 0x80; - res = test_pkey_verify(pkey, e, buf, bufLen, rsaSig, rsaSigLen, - padMode, md, mgf1Md); - if (res != 1) - err = 1; - } - if ((err == 0) && (padMode != RSA_PKCS1_PSS_PADDING)) { - PRINT_MSG("Sign with wolfengine"); - rsaSigLen = RSA_size(rsaKey); - err = test_pkey_sign(pkey, e, buf, bufLen, rsaSig, &rsaSigLen, - padMode, md, mgf1Md); - } - if ((err == 0) && (padMode != RSA_PKCS1_PSS_PADDING)) { - PRINT_MSG("Verify with OpenSSL"); - err = test_pkey_verify(pkey, NULL, buf, bufLen, rsaSig, rsaSigLen, - padMode, md, mgf1Md); + /* Don't run these first tests in the case of PSS or X9.31, which are + * strictly for signatures and not arbitrary data. */ + if (padMode != RSA_PKCS1_PSS_PADDING && padMode != RSA_X931_PADDING) { + if (err == 0) { + PRINT_MSG("Test signing/verifying arbitrary data"); + PRINT_MSG("Sign with OpenSSL"); + err = test_pkey_sign(pkey, NULL, buf, bufLen, rsaSig, &rsaSigLen, + padMode, md, mgf1Md); + } + if (err == 0) { + PRINT_MSG("Verify with wolfengine"); + err = test_pkey_verify(pkey, e, buf, bufLen, rsaSig, rsaSigLen, + padMode, md, mgf1Md); + } + if (err == 0) { + PRINT_MSG("Verify bad signature with wolfengine"); + rsaSig[1] ^= 0x80; + res = test_pkey_verify(pkey, e, buf, bufLen, rsaSig, rsaSigLen, + padMode, md, mgf1Md); + if (res != 1) + err = 1; + } + if (err == 0) { + PRINT_MSG("Sign with wolfengine"); + rsaSigLen = RSA_size(rsaKey); + err = test_pkey_sign(pkey, e, buf, bufLen, rsaSig, &rsaSigLen, + padMode, md, mgf1Md); + } + if (err == 0) { + PRINT_MSG("Verify with OpenSSL"); + err = test_pkey_verify(pkey, NULL, buf, bufLen, rsaSig, rsaSigLen, + padMode, md, mgf1Md); + } } /* OpenSSL doesn't allow RSA signatures with no padding. */ - if ((err == 0) && (padMode != RSA_NO_PADDING)) { - PRINT_MSG("Test creating/verifying a signature"); - PRINT_MSG("Sign with OpenSSL"); - err = test_digest_sign(pkey, NULL, buf, bufLen, EVP_sha256(), - rsaSig, &rsaSigLen, padMode); - } - if ((err == 0) && (padMode != RSA_NO_PADDING)) { - PRINT_MSG("Verify with wolfengine"); - err = test_digest_verify(pkey, e, buf, bufLen, EVP_sha256(), - rsaSig, rsaSigLen, padMode); - } - if ((err == 0) && (padMode != RSA_NO_PADDING)) { - PRINT_MSG("Verify bad signature with wolfengine"); - rsaSig[1] ^= 0x80; - res = test_digest_verify(pkey, e, buf, bufLen, EVP_sha256(), - rsaSig, rsaSigLen, padMode); - if (res != 1) - err = 1; - } - if ((err == 0) && (padMode != RSA_NO_PADDING)) { - PRINT_MSG("Sign with wolfengine"); - rsaSigLen = RSA_size(rsaKey); - err = test_digest_sign(pkey, e, buf, bufLen, EVP_sha256(), - rsaSig, &rsaSigLen, padMode); - } - if ((err == 0) && (padMode != RSA_NO_PADDING)) { - PRINT_MSG("Verify with OpenSSL"); - err = test_digest_verify(pkey, NULL, buf, bufLen, EVP_sha256(), - rsaSig, rsaSigLen, padMode); + if (padMode != RSA_NO_PADDING) { + if (err == 0) { + PRINT_MSG("Test creating/verifying a signature"); + PRINT_MSG("Sign with OpenSSL"); + err = test_digest_sign(pkey, NULL, buf, bufLen, EVP_sha256(), + rsaSig, &rsaSigLen, padMode); + } + if (err == 0) { + PRINT_MSG("Verify with wolfengine"); + err = test_digest_verify(pkey, e, buf, bufLen, EVP_sha256(), + rsaSig, rsaSigLen, padMode); + } + if (err == 0) { + PRINT_MSG("Verify bad signature with wolfengine"); + rsaSig[1] ^= 0x80; + res = test_digest_verify(pkey, e, buf, bufLen, EVP_sha256(), + rsaSig, rsaSigLen, padMode); + if (res != 1) + err = 1; + } + if (err == 0) { + PRINT_MSG("Sign with wolfengine"); + rsaSigLen = RSA_size(rsaKey); + err = test_digest_sign(pkey, e, buf, bufLen, EVP_sha256(), + rsaSig, &rsaSigLen, padMode); + } + if (err == 0) { + PRINT_MSG("Verify with OpenSSL"); + err = test_digest_verify(pkey, NULL, buf, bufLen, EVP_sha256(), + rsaSig, rsaSigLen, padMode); + } } EVP_PKEY_free(pkey); @@ -935,6 +948,13 @@ int test_rsa_sign_verify_pss(ENGINE *e, void *data) return err; } +int test_rsa_sign_verify_x931(ENGINE *e, void *data) +{ + (void)data; + + return test_rsa_sign_verify_pad(e, RSA_X931_PADDING, NULL, NULL); +} + static int test_rsa_enc_dec(ENGINE *e, const unsigned char *der, size_t derLen, int padMode, const EVP_MD *rsaMd, const EVP_MD *rsaMgf1Md) diff --git a/test/unit.c b/test/unit.c index c38ee18..3e5939e 100644 --- a/test/unit.c +++ b/test/unit.c @@ -174,6 +174,7 @@ TEST_CASE test_case[] = { #ifdef WE_HAVE_RSA TEST_DECL(test_rsa_sign_sha1, NULL), TEST_DECL(test_rsa_sign_verify_pkcs1, NULL), + TEST_DECL(test_rsa_sign_verify_x931, NULL), TEST_DECL(test_rsa_sign_verify_no_pad, NULL), TEST_DECL(test_rsa_sign_verify_pss, NULL), TEST_DECL(test_rsa_enc_dec_pkcs1, NULL), diff --git a/test/unit.h b/test/unit.h index cde1e52..7f49bc6 100644 --- a/test/unit.h +++ b/test/unit.h @@ -228,6 +228,7 @@ int test_pkey_dec_rsa(EVP_PKEY *pkey, ENGINE *e, unsigned char *msg, size_t msgL const EVP_MD *rsaMd, const EVP_MD *rsaMgf1Md); int test_rsa_sign_sha1(ENGINE *e, void *data); int test_rsa_sign_verify_pkcs1(ENGINE *e, void *data); +int test_rsa_sign_verify_x931(ENGINE *e, void *data); int test_rsa_sign_verify_no_pad(ENGINE *e, void *data); int test_rsa_sign_verify_pss(ENGINE *e, void *data); int test_rsa_enc_dec_pkcs1(ENGINE *e, void *data); From 64ead2cf44c9dacbf2c77072bddb77667dc331a6 Mon Sep 17 00:00:00 2001 From: Hayden Roche Date: Mon, 25 Apr 2022 16:11:45 -0700 Subject: [PATCH 2/3] Add X9.31 padding support to we_rsa_pkey_ctrl_str. --- src/we_rsa.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/we_rsa.c b/src/we_rsa.c index 377ed22..7da741c 100644 --- a/src/we_rsa.c +++ b/src/we_rsa.c @@ -245,7 +245,7 @@ static int we_add_x931_padding(unsigned char* to, size_t toLen, } else { /* Need at least two bytes for trailer and header. */ - padBytes = toLen - fromLen - 2; + padBytes = (int)(toLen - fromLen - 2); if (padBytes < 0) { WOLFENGINE_ERROR_MSG(WE_LOG_PK, "Output buffer too small."); ret = 0; @@ -289,7 +289,7 @@ static int we_remove_x931_padding(unsigned char** to, const unsigned char* from, { int ret = 1; size_t idx = 0; - int numCopy = 0; + size_t numCopy = 0; WOLFENGINE_ENTER(WE_LOG_PK, "we_remove_x931_padding"); WOLFENGINE_MSG_VERBOSE(WE_LOG_PK, "ARGS [to = %p, from = %p, fromLen = " @@ -338,7 +338,7 @@ static int we_remove_x931_padding(unsigned char** to, const unsigned char* from, } if (ret == 1) { - ret = numCopy; + ret = (int)numCopy; } WOLFENGINE_LEAVE(WE_LOG_PK, "we_remove_x931_padding", ret); @@ -1124,7 +1124,7 @@ static int we_rsa_priv_enc_int(size_t fromLen, const unsigned char *from, ret = -1; } else { - rc = mp_read_unsigned_bin(&toMp, to, toLen); + rc = mp_read_unsigned_bin(&toMp, to, (int)toLen); if (rc != MP_OKAY) { WOLFENGINE_ERROR_FUNC(WE_LOG_PK, "mp_read_unsigned_bin", rc); @@ -1383,7 +1383,7 @@ static int we_rsa_pub_dec_int(size_t fromLen, const unsigned char *from, ret = -1; } else { - rc = mp_read_unsigned_bin(&toMp, to, toLen); + rc = mp_read_unsigned_bin(&toMp, to, (int)toLen); if (rc != MP_OKAY) { WOLFENGINE_ERROR_FUNC(WE_LOG_PK, "mp_read_unsigned_bin", ret); @@ -2298,6 +2298,9 @@ static int we_rsa_pkey_ctrl_str(EVP_PKEY_CTX *ctx, const char *type, else if (XSTRNCMP(value, "pss", 4) == 0) { rsa->padMode = RSA_PKCS1_PSS_PADDING; } + else if (XSTRNCMP(value, "x931", 5) == 0) { + rsa->padMode = RSA_X931_PADDING; + } else { ret = 0; } From 97061a03e258d660031caa3c1f3b5466edf021a9 Mon Sep 17 00:00:00 2001 From: Hayden Roche Date: Mon, 16 May 2022 11:11:58 -0700 Subject: [PATCH 3/3] Add macro guard for RSA X9.31 padding, on by default. --- configure.ac | 13 +++++++++++++ src/we_rsa.c | 26 +++++++++++++++++++++++--- test/test_rsa.c | 12 ++++++++++++ test/unit.c | 2 ++ test/unit.h | 2 ++ 5 files changed, 52 insertions(+), 3 deletions(-) diff --git a/configure.ac b/configure.ac index 176638d..b909efd 100644 --- a/configure.ac +++ b/configure.ac @@ -482,6 +482,18 @@ then AM_CFLAGS="$AM_CFLAGS -DWE_HAVE_RSA" fi +# RSA X9.31 padding +AC_ARG_ENABLE([rsa-x931], + [AS_HELP_STRING([--enable-rsa-x931],[Enable X9.31 padding for RSA signatures (default: enabled)])], + [ ENABLED_RSA_X931=$enableval ], + [ ENABLED_RSA_X931=yes ] + ) + +if test "$ENABLED_RSA" = "yes" && test "$ENABLED_RSA_X931" = "yes" +then + AM_CFLAGS="$AM_CFLAGS -DWE_HAVE_RSA_X931" +fi + # DH AC_ARG_ENABLE([dh], [AS_HELP_STRING([--enable-dh],[Enable Diffie-Hellman (DH) (default: enabled)])], @@ -739,6 +751,7 @@ echo " * TLS1 PRF: $ENABLED_TLS1_PRF" echo " * HKDF: $ENABLED_HKDF" echo " * Random: $ENABLED_RAND" echo " * RSA: $ENABLED_RSA" +echo " * RSA X9.31 padding: $ENABLED_RSA_X931" echo " * DH: $ENABLED_DH" echo " * AES-GCM: $ENABLED_AESGCM" echo " * AES-CBC: $ENABLED_AESCBC" diff --git a/src/we_rsa.c b/src/we_rsa.c index 7da741c..f36a090 100644 --- a/src/we_rsa.c +++ b/src/we_rsa.c @@ -219,6 +219,7 @@ static int we_pss_salt_len_to_wc(int saltLen, const EVP_MD *md, RsaKey *key, return saltLen; } +#ifdef WE_HAVE_RSA_X931 /** * Add X9.31 padding to the input buffer, placing the result in the output * buffer. @@ -426,6 +427,7 @@ static int we_rsa_add_x931_hash_code(const EVP_MD* md, unsigned char** to, return ret; } +#endif /* WE_HAVE_RSA_X931 */ /** * Set the public key in a we_Rsa structure. @@ -1015,11 +1017,13 @@ static int we_rsa_priv_enc_int(size_t fromLen, const unsigned char *from, WC_RNG *rng = we_rng; #endif char errBuff[WOLFENGINE_MAX_LOG_WIDTH]; +#ifdef WE_HAVE_RSA_X931 unsigned char* padded = NULL; int paddedSz; mp_int toMp; mp_int nMinusTo; int rc; +#endif WOLFENGINE_ENTER(WE_LOG_PK, "we_rsa_priv_enc_int"); WOLFENGINE_MSG_VERBOSE(WE_LOG_PK, "ARGS [fromLen = %zu, from = %p, " @@ -1081,6 +1085,7 @@ static int we_rsa_priv_enc_int(size_t fromLen, const unsigned char *from, } } break; + #ifdef WE_HAVE_RSA_X931 case RSA_X931_PADDING: WOLFENGINE_MSG(WE_LOG_PK, "padMode: RSA_X931_PADDING"); paddedSz = wc_RsaEncryptSize(&rsa->key); @@ -1154,8 +1159,8 @@ static int we_rsa_priv_enc_int(size_t fromLen, const unsigned char *from, mp_free(&nMinusTo); } } - break; + #endif /* WE_HAVE_RSA_X931 */ default: /* Unsupported padding mode for RSA private encryption. */ WOLFENGINE_ERROR_MSG(WE_LOG_PK, @@ -1279,10 +1284,12 @@ static int we_rsa_pub_dec_int(size_t fromLen, const unsigned char *from, WC_RNG *rng = we_rng; #endif char errBuff[WOLFENGINE_MAX_LOG_WIDTH]; +#ifdef WE_HAVE_RSA_X931 unsigned char* unpadded = NULL; mp_int toMp; mp_int nMinusTo; int rc; +#endif WOLFENGINE_ENTER(WE_LOG_PK, "we_rsa_pub_dec_int"); WOLFENGINE_MSG_VERBOSE(WE_LOG_PK, "ARGS [fromLen = %zu, from = %p, " @@ -1357,6 +1364,7 @@ static int we_rsa_pub_dec_int(size_t fromLen, const unsigned char *from, } } break; + #ifdef WE_HAVE_RSA_X931 case RSA_X931_PADDING: WOLFENGINE_MSG(WE_LOG_PK, "padMode: RSA_X931_PADDING"); ret = wc_RsaDirect((byte*)from, (unsigned int)fromLen, to, @@ -1424,6 +1432,7 @@ static int we_rsa_pub_dec_int(size_t fromLen, const unsigned char *from, } } break; + #endif /* WE_HAVE_RSA_X931 */ default: /* Unsupported padding mode for RSA public decryption. */ XSNPRINTF(errBuff, sizeof(errBuff), "Unknown padding mode: %d", @@ -2008,8 +2017,11 @@ static int we_rsa_pkey_ctrl(EVP_PKEY_CTX *ctx, int type, int num, void *ptr) if (num != RSA_PKCS1_PADDING && num != RSA_PKCS1_PSS_PADDING && num != RSA_PKCS1_OAEP_PADDING && - num != RSA_NO_PADDING && - num != RSA_X931_PADDING) + num != RSA_NO_PADDING + #ifdef WE_HAVE_RSA_X931 + && num != RSA_X931_PADDING + #endif + ) { WOLFENGINE_ERROR_MSG(WE_LOG_PK, "Unsupported RSA padding mode."); @@ -2298,9 +2310,11 @@ static int we_rsa_pkey_ctrl_str(EVP_PKEY_CTX *ctx, const char *type, else if (XSTRNCMP(value, "pss", 4) == 0) { rsa->padMode = RSA_PKCS1_PSS_PADDING; } + #ifdef WE_HAVE_RSA_X931 else if (XSTRNCMP(value, "x931", 5) == 0) { rsa->padMode = RSA_X931_PADDING; } + #endif else { ret = 0; } @@ -2568,6 +2582,7 @@ static int we_rsa_pkey_sign(EVP_PKEY_CTX *ctx, unsigned char *sig, } } if (ret == 1) { + #ifdef WE_HAVE_RSA_X931 if (rsa->padMode == RSA_X931_PADDING) { if (rsa->md == NULL) { WOLFENGINE_ERROR_MSG(WE_LOG_PK, "No digest specified for " @@ -2588,6 +2603,7 @@ static int we_rsa_pkey_sign(EVP_PKEY_CTX *ctx, unsigned char *sig, } } } + #endif /* Pad and private encrypt. */ actualSigLen = we_rsa_priv_enc_int(tbsLen, tbs, *sigLen, sig, rsa); if (actualSigLen == -1) { @@ -2637,9 +2653,11 @@ static int we_rsa_pkey_verify(EVP_PKEY_CTX *ctx, const unsigned char *sig, unsigned char *encodedDigest = NULL; int encodedDigestLen = 0; int keySize = 0; +#ifdef WE_HAVE_RSA_X931 int nid; unsigned char hashCode; char errBuff[WOLFENGINE_MAX_LOG_WIDTH]; +#endif WOLFENGINE_ENTER(WE_LOG_PK, "we_rsa_pkey_verify"); WOLFENGINE_MSG_VERBOSE(WE_LOG_PK, "ARGS [ctx = %p, sig = %p, sigLen = %zu, " @@ -2744,6 +2762,7 @@ static int we_rsa_pkey_verify(EVP_PKEY_CTX *ctx, const unsigned char *sig, tbsLen = encodedDigestLen; } } + #ifdef WE_HAVE_RSA_X931 if (ret == 1 && rsa->padMode == RSA_X931_PADDING) { if (rsa->md == NULL) { WOLFENGINE_ERROR_MSG(WE_LOG_PK, "No digest specified for " @@ -2778,6 +2797,7 @@ static int we_rsa_pkey_verify(EVP_PKEY_CTX *ctx, const unsigned char *sig, } } } + #endif if ((ret == 1) && (tbsLen != (size_t)rc)) { WOLFENGINE_ERROR_MSG(WE_LOG_PK, "Encoding different size"); ret = 0; diff --git a/test/test_rsa.c b/test/test_rsa.c index 19baaf0..cf0aa4a 100644 --- a/test/test_rsa.c +++ b/test/test_rsa.c @@ -384,9 +384,17 @@ static int test_rsa_direct(ENGINE *e, const unsigned char *der, size_t derLen, int inBufLen; } TestVector; #if defined(_MSC_VER) || defined(__MINGW32__) || defined(__CYGWIN__) || defined(_WIN32_WCE) +#ifdef WE_HAVE_RSA_X931 #define numTestVectors 4 #else +#define numTestVectors 3 +#endif /* WE_HAVE_RSA_X931 */ +#else +#ifdef WE_HAVE_RSA_X931 const int numTestVectors = 4; +#else + const int numTestVectors = 3; +#endif /* WE_HAVE_RSA_X931 */ #endif TestVector testVectors[numTestVectors]; int i = 0; @@ -433,10 +441,12 @@ static int test_rsa_direct(ENGINE *e, const unsigned char *der, size_t derLen, testVectors[2].padName = "RSA_NO_PADDING"; testVectors[2].inBuf = noPaddingBuf; testVectors[2].inBufLen = rsaSize; + #ifdef WE_HAVE_RSA_X931 testVectors[3].padding = RSA_X931_PADDING; testVectors[3].padName = "RSA_X931_PADDING"; testVectors[3].inBuf = buf; testVectors[3].inBufLen = sizeof(buf); + #endif } for (; err == 0 && i < numTestVectors; ++i) { @@ -948,12 +958,14 @@ int test_rsa_sign_verify_pss(ENGINE *e, void *data) return err; } +#ifdef WE_HAVE_RSA_X931 int test_rsa_sign_verify_x931(ENGINE *e, void *data) { (void)data; return test_rsa_sign_verify_pad(e, RSA_X931_PADDING, NULL, NULL); } +#endif /* WE_HAVE_RSA_X931 */ static int test_rsa_enc_dec(ENGINE *e, const unsigned char *der, size_t derLen, int padMode, const EVP_MD *rsaMd, diff --git a/test/unit.c b/test/unit.c index 3e5939e..0ecbfa8 100644 --- a/test/unit.c +++ b/test/unit.c @@ -174,7 +174,9 @@ TEST_CASE test_case[] = { #ifdef WE_HAVE_RSA TEST_DECL(test_rsa_sign_sha1, NULL), TEST_DECL(test_rsa_sign_verify_pkcs1, NULL), +#ifdef WE_HAVE_RSA_X931 TEST_DECL(test_rsa_sign_verify_x931, NULL), +#endif /* WE_HAVE_RSA_X931 */ TEST_DECL(test_rsa_sign_verify_no_pad, NULL), TEST_DECL(test_rsa_sign_verify_pss, NULL), TEST_DECL(test_rsa_enc_dec_pkcs1, NULL), diff --git a/test/unit.h b/test/unit.h index 7f49bc6..22362b7 100644 --- a/test/unit.h +++ b/test/unit.h @@ -228,7 +228,9 @@ int test_pkey_dec_rsa(EVP_PKEY *pkey, ENGINE *e, unsigned char *msg, size_t msgL const EVP_MD *rsaMd, const EVP_MD *rsaMgf1Md); int test_rsa_sign_sha1(ENGINE *e, void *data); int test_rsa_sign_verify_pkcs1(ENGINE *e, void *data); +#ifdef WE_HAVE_RSA_X931 int test_rsa_sign_verify_x931(ENGINE *e, void *data); +#endif /* WE_HAVE_RSA_X931 */ int test_rsa_sign_verify_no_pad(ENGINE *e, void *data); int test_rsa_sign_verify_pss(ENGINE *e, void *data); int test_rsa_enc_dec_pkcs1(ENGINE *e, void *data);