Skip to content

Commit ff0b5e2

Browse files
ejohnstownphilljj
authored andcommitted
Enforce the RSA key size floor on host keys
ParseRSAPubKey() and ParseRSAPubKeyCert() run the server's host key through CheckRsaKeyBits(), so a client rejects an RSA host key under WOLFSSH_RSA_MIN_KEY_BITS the same way a server rejects a short user auth key. The failure ends the key exchange in DoKexDhReply(). - move CheckRsaKeyBits() above the host key parsers - ParseRSAPubKey() maps only the decode failure to WS_RSA_E, so a parse error or a short key keeps its own code - test 1024 and 2047 bit host keys in test_ParseRSAPubKey() Issue: F-14687
1 parent ba0a8c2 commit ff0b5e2

3 files changed

Lines changed: 55 additions & 28 deletions

File tree

‎src/internal.c‎

Lines changed: 31 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -7595,6 +7595,30 @@ struct wolfSSH_sigKeyBlock {
75957595
static int InitPubKey(struct wolfSSH_sigKeyBlock *p, WOLFSSH *ssh);
75967596

75977597

7598+
#ifndef WOLFSSH_NO_RSA
7599+
/* Utility for the RSA host key and user auth paths. */
7600+
/* returns WS_SUCCESS when the key clears WOLFSSH_RSA_MIN_KEY_BITS. */
7601+
static int CheckRsaKeyBits(RsaKey* key)
7602+
{
7603+
int ret = WS_SUCCESS;
7604+
int keyBits;
7605+
7606+
/* The encrypt size rounds up to a byte; offload builds leave n empty. */
7607+
keyBits = mp_count_bits(&key->n);
7608+
if (keyBits == 0) {
7609+
keyBits = wc_RsaEncryptSize(key) * 8;
7610+
}
7611+
7612+
if (keyBits < WOLFSSH_RSA_MIN_KEY_BITS) {
7613+
WLOG(WS_LOG_DEBUG, "RSA key too small (%d bits)", keyBits);
7614+
ret = WS_CERT_KEY_SIZE_E;
7615+
}
7616+
7617+
return ret;
7618+
}
7619+
#endif
7620+
7621+
75987622
/* Parse out a RAW RSA public key from buffer */
75997623
static int ParseRSAPubKey(WOLFSSH *ssh,
76007624
struct wolfSSH_sigKeyBlock *sigKeyBlock_ptr, byte *pubKey, word32 pubKeySz)
@@ -7627,13 +7651,15 @@ static int ParseRSAPubKey(WOLFSSH *ssh,
76277651
n = pubKey + pubKeyIdx;
76287652
ret = wc_RsaPublicKeyDecodeRaw(n, nSz, e, eSz,
76297653
&sigKeyBlock_ptr->sk.rsa.key);
7654+
if (ret != 0)
7655+
ret = WS_RSA_E;
76307656
}
7657+
if (ret == WS_SUCCESS)
7658+
ret = CheckRsaKeyBits(&sigKeyBlock_ptr->sk.rsa.key);
76317659

7632-
if (ret == 0) {
7660+
if (ret == WS_SUCCESS) {
76337661
sigKeyBlock_ptr->keySz = (word32)sizeof(sigKeyBlock_ptr->sk.rsa.key);
76347662
}
7635-
else
7636-
ret = WS_RSA_E;
76377663
#else
76387664
WOLFSSH_UNUSED(ssh);
76397665
WOLFSSH_UNUSED(sigKeyBlock_ptr);
@@ -8102,6 +8128,8 @@ static int ParseRSAPubKeyCert(WOLFSSH *ssh,
81028128
if (error == 0)
81038129
error = wc_RsaPublicKeyDecode(der, &idx,
81048130
&sigKeyBlock_ptr->sk.rsa.key, derSz);
8131+
if (error == 0)
8132+
error = CheckRsaKeyBits(&sigKeyBlock_ptr->sk.rsa.key);
81058133
if (error == 0) {
81068134
sigKeyBlock_ptr->keySz =
81078135
(word32)sizeof(sigKeyBlock_ptr->sk.rsa.key);
@@ -10437,28 +10465,6 @@ static int DoUserAuthRequestPassword(WOLFSSH* ssh, WS_UserAuthData* authData,
1043710465
}
1043810466

1043910467
#ifndef WOLFSSH_NO_RSA
10440-
/* Utility for the RSA user auth paths. */
10441-
/* returns WS_SUCCESS when the key clears WOLFSSH_RSA_MIN_KEY_BITS. */
10442-
static int CheckRsaKeyBits(RsaKey* key)
10443-
{
10444-
int ret = WS_SUCCESS;
10445-
int keyBits;
10446-
10447-
/* The encrypt size rounds up to a byte; offload builds leave n empty. */
10448-
keyBits = mp_count_bits(&key->n);
10449-
if (keyBits == 0) {
10450-
keyBits = wc_RsaEncryptSize(key) * 8;
10451-
}
10452-
10453-
if (keyBits < WOLFSSH_RSA_MIN_KEY_BITS) {
10454-
WLOG(WS_LOG_DEBUG, "RSA auth key too small (%d bits)", keyBits);
10455-
ret = WS_CERT_KEY_SIZE_E;
10456-
}
10457-
10458-
return ret;
10459-
}
10460-
10461-
1046210468
/* Utility for DoUserAuthRequestPublicKey() */
1046310469
/* returns negative for error, positive is size of digest. */
1046410470
static int DoUserAuthRequestRsa(WOLFSSH* ssh, WS_UserAuthData_PublicKey* pk,

‎tests/unit.c‎

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22857,9 +22857,29 @@ static int test_ParseRSAPubKey(void)
2285722857

2285822858
/* truncated blob: fails after the key is initialized */
2285922859
ret = wolfSSH_TestParseRSAPubKey(ssh, blob, (word32)(sizeof(blob) / 2));
22860-
if (ret != WS_RSA_E) {
22860+
if (ret != WS_BUFFER_E) {
2286122861
fprintf(stderr, "\t\"truncated\" FAIL: got %d, expected %d\n",
22862-
ret, WS_RSA_E);
22862+
ret, WS_BUFFER_E);
22863+
failures++;
22864+
}
22865+
22866+
/* host key under WOLFSSH_RSA_MIN_KEY_BITS */
22867+
WMEMCPY(blob + RSA_PUB_BLOB_NLEN, userAuthRsaPubKeyNLen1024,
22868+
sizeof(userAuthRsaPubKeyNLen1024));
22869+
ret = wolfSSH_TestParseRSAPubKey(ssh, blob, (word32)sizeof(blob));
22870+
if (ret != WS_CERT_KEY_SIZE_E) {
22871+
fprintf(stderr, "\t\"1024 bit\" FAIL: got %d, expected %d\n",
22872+
ret, WS_CERT_KEY_SIZE_E);
22873+
failures++;
22874+
}
22875+
22876+
WMEMCPY(blob, userAuthRsaPubKeyBlob, sizeof(blob));
22877+
WMEMCPY(blob + RSA_PUB_BLOB_N, userAuthRsaPubKeyMsb2047,
22878+
sizeof(userAuthRsaPubKeyMsb2047));
22879+
ret = wolfSSH_TestParseRSAPubKey(ssh, blob, (word32)sizeof(blob));
22880+
if (ret != WS_CERT_KEY_SIZE_E) {
22881+
fprintf(stderr, "\t\"2047 bit\" FAIL: got %d, expected %d\n",
22882+
ret, WS_CERT_KEY_SIZE_E);
2286322883
failures++;
2286422884
}
2286522885

‎wolfssh/internal.h‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -719,7 +719,8 @@ enum NameIdType {
719719
#endif
720720

721721
#ifndef WOLFSSH_RSA_MIN_KEY_BITS
722-
/* Minimum accepted RSA public-key size (bits) for user authentication.
722+
/* Minimum accepted RSA public-key size (bits) for host keys and user
723+
* authentication.
723724
* Per NIST SP 800-131A; override at build time if a smaller key must be
724725
* accepted. */
725726
#define WOLFSSH_RSA_MIN_KEY_BITS 2048

0 commit comments

Comments
 (0)