Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
134 changes: 97 additions & 37 deletions src/internal.c
Original file line number Diff line number Diff line change
Expand Up @@ -7398,6 +7398,54 @@ struct wolfSSH_sigKeyBlock {
static int InitPubKey(struct wolfSSH_sigKeyBlock *p, WOLFSSH *ssh);


#ifndef WOLFSSH_NO_RSA
/* Utility for the RSA host key and user auth paths. */
/* returns WS_SUCCESS when the key clears WOLFSSH_RSA_MIN_KEY_BITS. */
static int CheckRsaKeyBits(RsaKey* key)
{
int ret = WS_SUCCESS;
int keyBits;

/* The encrypt size rounds up to a byte; offload builds leave n empty. */
keyBits = mp_count_bits(&key->n);
if (keyBits == 0) {
keyBits = wc_RsaEncryptSize(key) * 8;
}

if (keyBits < WOLFSSH_RSA_MIN_KEY_BITS) {
WLOG(WS_LOG_DEBUG, "RSA key too small (%d bits)", keyBits);
ret = WS_CERT_KEY_SIZE_E;
}

return ret;
}
#endif


#if !defined(WOLFSSH_NO_RSA) || !defined(WOLFSSH_NO_ED25519) \
|| !defined(WOLFSSH_NO_MLDSA)
/* Compare the format identifier at the start of a public key blob
* against the expected name (RFC 4253 section 6.6). */
static int GetPubKeyFormat(const char* expected, const byte* pubKey,
word32 pubKeySz, word32* pubKeyIdx)
{
const byte* name = NULL;
word32 nameSz = 0;
int ret;

ret = GetStringRef(&nameSz, &name, pubKey, pubKeySz, pubKeyIdx);
if (ret == WS_SUCCESS) {
if (nameSz != (word32)WSTRLEN(expected)
|| WMEMCMP(name, expected, nameSz) != 0) {
ret = WS_INVALID_ALGO_ID;
}
}

return ret;
}
#endif


/* Parse out a RAW RSA public key from buffer */
static int ParseRSAPubKey(WOLFSSH *ssh,
struct wolfSSH_sigKeyBlock *sigKeyBlock_ptr, byte *pubKey, word32 pubKeySz)
Expand All @@ -7411,9 +7459,9 @@ static int ParseRSAPubKey(WOLFSSH *ssh,
word32 pubKeyIdx = 0;

ret = InitPubKey(sigKeyBlock_ptr, ssh);
/* Skip the algo name. */
/* All three RSA host key algorithms use the "ssh-rsa" format. */
if (ret == WS_SUCCESS)
ret = GetSkip(pubKey, pubKeySz, &pubKeyIdx);
ret = GetPubKeyFormat("ssh-rsa", pubKey, pubKeySz, &pubKeyIdx);
if (ret == WS_SUCCESS) {
ret = GetUint32(&eSz, pubKey, pubKeySz, &pubKeyIdx);
if (ret == WS_SUCCESS && eSz > pubKeySz - pubKeyIdx)
Expand All @@ -7430,13 +7478,15 @@ static int ParseRSAPubKey(WOLFSSH *ssh,
n = pubKey + pubKeyIdx;
ret = wc_RsaPublicKeyDecodeRaw(n, nSz, e, eSz,
&sigKeyBlock_ptr->sk.rsa.key);
if (ret != 0)
ret = WS_RSA_E;
}
if (ret == WS_SUCCESS)
ret = CheckRsaKeyBits(&sigKeyBlock_ptr->sk.rsa.key);

if (ret == 0) {
if (ret == WS_SUCCESS) {
sigKeyBlock_ptr->keySz = (word32)sizeof(sigKeyBlock_ptr->sk.rsa.key);
}
else
ret = WS_RSA_E;
#else
WOLFSSH_UNUSED(ssh);
WOLFSSH_UNUSED(sigKeyBlock_ptr);
Expand Down Expand Up @@ -7552,9 +7602,8 @@ static int ParseEd25519PubKey(WOLFSSH *ssh,

ret = InitPubKey(sigKeyBlock_ptr, ssh);

/* Skip the algo name */
if (ret == WS_SUCCESS) {
ret = GetSkip(pubKey, pubKeySz, &pubKeyIdx);
ret = GetPubKeyFormat("ssh-ed25519", pubKey, pubKeySz, &pubKeyIdx);
}

if (ret == WS_SUCCESS) {
Expand Down Expand Up @@ -7636,8 +7685,7 @@ static int ParseMlDsaPubKey(WOLFSSH* ssh,
return WS_INVALID_ALGO_ID;
}

/* skip the algo name string */
ret = GetSkip(pubKey, pubKeySz, &pubKeyIdx);
ret = GetPubKeyFormat(IdToName(keyId), pubKey, pubKeySz, &pubKeyIdx);
if (ret == WS_SUCCESS)
ret = GetStringRef(&pubSz, &pub, pubKey, pubKeySz, &pubKeyIdx);
if (ret == WS_SUCCESS)
Expand Down Expand Up @@ -7905,6 +7953,8 @@ static int ParseRSAPubKeyCert(WOLFSSH *ssh,
if (error == 0)
error = wc_RsaPublicKeyDecode(der, &idx,
&sigKeyBlock_ptr->sk.rsa.key, derSz);
if (error == 0)
error = CheckRsaKeyBits(&sigKeyBlock_ptr->sk.rsa.key);
if (error == 0) {
sigKeyBlock_ptr->keySz =
(word32)sizeof(sigKeyBlock_ptr->sk.rsa.key);
Expand Down Expand Up @@ -8163,8 +8213,12 @@ static int KeyAgreeDh_client(WOLFSSH* ssh, byte hashId,

/* Reject a peer public value outside the safe range [2, p-2] before key
* agreement. Keeps wolfSSH independent of whether the linked wolfSSL
* validates the peer key inside wc_DhAgree. */
ret = wc_DhCheckPubKey(&ssh->handshake->privKey.dh, f, fSz);
* validates the peer key inside wc_DhAgree. f is an mpint, so a set
* top bit makes it negative (RFC 4251 section 5). */
if (fSz > 0 && (f[0] & 0x80) != 0)
ret = WS_PARSE_E;
else
ret = wc_DhCheckPubKey(&ssh->handshake->privKey.dh, f, fSz);
if (ret != 0) {
/* Peer-driven reject; log at DEBUG like other peer-input rejections
* so a remote peer cannot flood the error log. */
Expand Down Expand Up @@ -10208,28 +10262,6 @@ static int DoUserAuthRequestPassword(WOLFSSH* ssh, WS_UserAuthData* authData,
}

#ifndef WOLFSSH_NO_RSA
/* Utility for the RSA user auth paths. */
/* returns WS_SUCCESS when the key clears WOLFSSH_RSA_MIN_KEY_BITS. */
static int CheckRsaKeyBits(RsaKey* key)
{
int ret = WS_SUCCESS;
int keyBits;

/* The encrypt size rounds up to a byte; offload builds leave n empty. */
keyBits = mp_count_bits(&key->n);
if (keyBits == 0) {
keyBits = wc_RsaEncryptSize(key) * 8;
}

if (keyBits < WOLFSSH_RSA_MIN_KEY_BITS) {
WLOG(WS_LOG_DEBUG, "RSA auth key too small (%d bits)", keyBits);
ret = WS_CERT_KEY_SIZE_E;
}

return ret;
}


/* Utility for DoUserAuthRequestPublicKey() */
/* returns negative for error, positive is size of digest. */
static int DoUserAuthRequestRsa(WOLFSSH* ssh, WS_UserAuthData_PublicKey* pk,
Expand Down Expand Up @@ -17060,10 +17092,24 @@ static int KeyAgreeDh_server(WOLFSSH* ssh, byte hashId, byte* f, word32* fSz)
PRIVATE_KEY_LOCK();
}
/* Reject a peer public value outside the safe range [2, p-2] before
* key agreement, independent of the linked wolfSSL's own check. */
if (ret == 0)
ret = wc_DhCheckPubKey(privKey, ssh->handshake->e,
ssh->handshake->eSz);
* key agreement, independent of the linked wolfSSL's own check.
* e is an mpint, so a set top bit makes it negative (RFC 4251
* section 5). */
if (ret == 0) {
if (ssh->handshake->eSz > 0
&& (ssh->handshake->e[0] & 0x80) != 0)
ret = WS_PARSE_E;
else
ret = wc_DhCheckPubKey(privKey, ssh->handshake->e,
ssh->handshake->eSz);
if (ret != 0) {
/* Peer-driven reject; log at DEBUG like other peer-input
* rejections so a remote peer cannot flood the error log. */
WLOG(WS_LOG_DEBUG,
"Peer DH public key out of range, %d", ret);
ret = WS_CRYPTO_FAILED;
}
}
if (ret == 0) {
PRIVATE_KEY_UNLOCK();
ret = wc_DhAgree(privKey, ssh->k, &ssh->kSz, y_ptr, ySz,
Expand Down Expand Up @@ -26529,6 +26575,20 @@ int wolfSSH_TestDoUserAuthRequestEd25519(WOLFSSH* ssh,

#ifndef WOLFSSH_NO_MLDSA

int wolfSSH_TestParseMlDsaPubKey(WOLFSSH* ssh, byte* pubKey, word32 pubKeySz,
byte keyId)
{
struct wolfSSH_sigKeyBlock sigKeyBlock;
int ret;

WMEMSET(&sigKeyBlock, 0, sizeof(sigKeyBlock));
sigKeyBlock.useMlDsa = 1;
ret = ParseMlDsaPubKey(ssh, &sigKeyBlock, pubKey, pubKeySz, keyId);
FreePubKey(&sigKeyBlock);

return ret;
}

WOLFSSH_API int wolfSSH_TestDoUserAuthRequestMlDsa(WOLFSSH* ssh,
WS_UserAuthData* authData, word32 pubKeyBlobSz)
{
Expand Down
Loading
Loading