Skip to content

Commit c8fa1e9

Browse files
committed
Fix for RSA private key parsing (allowing public) and RSA keygen no malloc support.
1 parent 4574a0c commit c8fa1e9

File tree

6 files changed

+68
-11
lines changed

6 files changed

+68
-11
lines changed

.github/workflows/os-check.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ jobs:
7070
'--enable-all --enable-certgencache',
7171
'--enable-sessionexport --enable-dtls --enable-dtls13',
7272
'--enable-sessionexport',
73+
'--disable-examples CPPFLAGS=-DWOLFSSL_NO_MALLOC',
7374
]
7475
name: make check
7576
if: github.repository_owner == 'wolfssl'

tests/api.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16971,12 +16971,13 @@ static int test_wolfSSL_d2i_PrivateKeys_bio(void)
1697116971

1697216972
RSA_free(rsa);
1697316973
rsa = NULL;
16974+
/* d2i_RSA_PUBKEY_bio should fail when given private key DER.
16975+
* wc_RsaPublicKeyDecode correctly rejects private key format. */
1697416976
ExpectIntGT(BIO_write(bio, client_key_der_2048,
1697516977
sizeof_client_key_der_2048), 0);
16976-
ExpectNotNull(d2i_RSA_PUBKEY_bio(bio, &rsa));
16978+
ExpectNull(d2i_RSA_PUBKEY_bio(bio, &rsa));
1697716979
(void)BIO_reset(bio);
1697816980

16979-
RSA_free(rsa);
1698016981
rsa = RSA_new();
1698116982
ExpectIntEQ(wolfSSL_i2d_RSAPrivateKey(rsa, NULL), 0);
1698216983
#endif /* USE_CERT_BUFFERS_2048 WOLFSSL_KEY_GEN */

tests/api/test_ossl_rsa.c

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -402,12 +402,11 @@ int test_wolfSSL_RSA_DER(void)
402402

403403
for (i = 0; tbl[i].der != NULL; i++)
404404
{
405-
/* Passing in pointer results in pointer moving. */
405+
/* d2i_RSAPublicKey should fail when given private key DER.
406+
* wc_RsaPublicKeyDecode correctly rejects private key format. */
406407
buff = tbl[i].der;
407-
ExpectNotNull(d2i_RSAPublicKey(&rsa, &buff, tbl[i].sz));
408-
ExpectNotNull(rsa);
409-
RSA_free(rsa);
410-
rsa = NULL;
408+
ExpectNull(d2i_RSAPublicKey(&rsa, &buff, tbl[i].sz));
409+
ExpectNull(rsa);
411410
}
412411
for (i = 0; tbl[i].der != NULL; i++)
413412
{

wolfcrypt/src/asn.c

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11009,6 +11009,8 @@ int wc_RsaPublicKeyDecode_ex(const byte* input, word32* inOutIdx, word32 inSz,
1100911009
#ifndef WOLFSSL_ASN_TEMPLATE
1101011010
int ret = 0;
1101111011
int length = 0;
11012+
int firstLen = 0;
11013+
word32 seqEndIdx = 0;
1101211014
#if defined(OPENSSL_EXTRA) || defined(RSA_DECODE_EXTRA)
1101311015
word32 localIdx;
1101411016
byte tag;
@@ -11066,16 +11068,19 @@ int wc_RsaPublicKeyDecode_ex(const byte* input, word32* inOutIdx, word32 inSz,
1106611068
}
1106711069
#endif /* OPENSSL_EXTRA */
1106811070

11071+
/* Calculate where the sequence should end for public key validation */
11072+
seqEndIdx = *inOutIdx + (word32)length;
11073+
1106911074
/* Get modulus */
11070-
ret = GetASNInt(input, inOutIdx, &length, inSz);
11075+
ret = GetASNInt(input, inOutIdx, &firstLen, inSz);
1107111076
if (ret < 0) {
1107211077
return ASN_RSA_KEY_E;
1107311078
}
1107411079
if (nSz)
11075-
*nSz = (word32)length;
11080+
*nSz = (word32)firstLen;
1107611081
if (n)
1107711082
*n = &input[*inOutIdx];
11078-
*inOutIdx += (word32)length;
11083+
*inOutIdx += (word32)firstLen;
1107911084

1108011085
/* Get exponent */
1108111086
ret = GetASNInt(input, inOutIdx, &length, inSz);
@@ -11088,6 +11093,18 @@ int wc_RsaPublicKeyDecode_ex(const byte* input, word32* inOutIdx, word32 inSz,
1108811093
*e = &input[*inOutIdx];
1108911094
*inOutIdx += (word32)length;
1109011095

11096+
/* Detect if this is an RSA private key being passed as public key.
11097+
* An RSA private key has: version (small), modulus (large), exponent,
11098+
* followed by more integers (d, p, q, etc.).
11099+
* An RSA public key has: modulus (large), exponent, and nothing more.
11100+
* If the first integer is small (like version 0) AND there is more data
11101+
* remaining in the sequence, this is likely a private key. */
11102+
if (firstLen <= MAX_VERSION_SZ && *inOutIdx < seqEndIdx) {
11103+
/* First integer is small and there's more data - looks like
11104+
* version field of a private key, not a modulus */
11105+
return ASN_RSA_KEY_E;
11106+
}
11107+
1109111108
return ret;
1109211109
#else
1109311110
DECL_ASNGETDATA(dataASN, rsaPublicKeyASN_Length);
@@ -11157,6 +11174,21 @@ int wc_RsaPublicKeyDecode_ex(const byte* input, word32* inOutIdx, word32 inSz,
1115711174
}
1115811175
}
1115911176
#endif
11177+
if (ret == 0) {
11178+
/* Detect if this is an RSA private key being passed as public key.
11179+
* An RSA private key has: version (small int), modulus, exponent, ...
11180+
* An RSA public key has: modulus (large int), exponent, nothing more.
11181+
* If the first integer is small (like version 0) and there's more data
11182+
* after what we consumed, this is likely a private key. */
11183+
word32 nLen = dataASN[RSAPUBLICKEYASN_IDX_PUBKEY_RSA_N].data.ref.length;
11184+
if (nLen <= MAX_VERSION_SZ && *inOutIdx < inSz) {
11185+
/* Check if next byte could be an INTEGER tag - indicating more
11186+
* fields like in a private key structure */
11187+
if (input[*inOutIdx] == ASN_INTEGER) {
11188+
ret = ASN_RSA_KEY_E;
11189+
}
11190+
}
11191+
}
1116011192
if (ret == 0) {
1116111193
/* Return the buffers and lengths asked for. */
1116211194
if (n != NULL) {

wolfcrypt/src/rsa.c

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -628,7 +628,11 @@ int wc_FreeRsaKey(RsaKey* key)
628628
static int _ifc_pairwise_consistency_test(RsaKey* key, WC_RNG* rng)
629629
{
630630
static const char* msg = "Everyone gets Friday off.";
631-
byte* sig;
631+
#ifndef WOLFSSL_NO_MALLOC
632+
byte* sig = NULL;
633+
#else
634+
byte sig[RSA_MAX_SIZE/8];
635+
#endif
632636
byte* plain;
633637
int ret = 0;
634638
word32 msgLen, plainLen, sigLen;
@@ -643,11 +647,13 @@ static int _ifc_pairwise_consistency_test(RsaKey* key, WC_RNG* rng)
643647

644648
WOLFSSL_MSG("Doing RSA consistency test");
645649

650+
#ifndef WOLFSSL_NO_MALLOC
646651
/* Sign and verify. */
647652
sig = (byte*)XMALLOC(sigLen, key->heap, DYNAMIC_TYPE_RSA);
648653
if (sig == NULL) {
649654
return MEMORY_E;
650655
}
656+
#endif
651657
XMEMSET(sig, 0, sigLen);
652658
#ifdef WOLFSSL_CHECK_MEM_ZERO
653659
wc_MemZero_Add("Pairwise CT sig", sig, sigLen);
@@ -690,7 +696,9 @@ static int _ifc_pairwise_consistency_test(RsaKey* key, WC_RNG* rng)
690696
ret = RSA_KEY_PAIR_E;
691697

692698
ForceZero(sig, sigLen);
699+
#ifndef WOLFSSL_NO_MALLOC
693700
XFREE(sig, key->heap, DYNAMIC_TYPE_RSA);
701+
#endif
694702

695703
return ret;
696704
}

wolfcrypt/test/test.c

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22717,6 +22717,22 @@ static wc_test_ret_t rsa_decode_test(RsaKey* keyPub)
2271722717
goto done;
2271822718
}
2271922719

22720+
#ifdef USE_CERT_BUFFERS_2048
22721+
/* Test that public key decode rejects a private key */
22722+
wc_FreeRsaKey(keyPub);
22723+
ret = wc_InitRsaKey(keyPub, NULL);
22724+
if (ret != 0)
22725+
return WC_TEST_RET_ENC_EC(ret);
22726+
inOutIdx = 0;
22727+
ret = wc_RsaPublicKeyDecode(client_key_der_2048, &inOutIdx, keyPub,
22728+
sizeof_client_key_der_2048);
22729+
if (ret != WC_NO_ERR_TRACE(ASN_RSA_KEY_E)) {
22730+
ret = WC_TEST_RET_ENC_EC(ret);
22731+
goto done;
22732+
}
22733+
ret = 0; /* success - public key decode correctly rejected private key */
22734+
#endif
22735+
2272022736
done:
2272122737
wc_FreeRsaKey(keyPub);
2272222738
return ret;

0 commit comments

Comments
 (0)