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
32 changes: 27 additions & 5 deletions src/internal.c
Original file line number Diff line number Diff line change
Expand Up @@ -8458,6 +8458,28 @@ 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 @@ -8546,6 +8568,10 @@ static int DoUserAuthRequestRsa(WOLFSSH* ssh, WS_UserAuthData_PublicKey* pk,
}
}

if (ret == WS_SUCCESS) {
Comment thread
ejohnstown marked this conversation as resolved.
Comment thread
ejohnstown marked this conversation as resolved.
ret = CheckRsaKeyBits(key);
}

if (ret == WS_SUCCESS) {
i = 0;
/* Check that the signature's pubkey type matches the expected one. */
Expand Down Expand Up @@ -8705,11 +8731,7 @@ static int DoUserAuthRequestRsaCert(WOLFSSH* ssh, WS_UserAuthData_PublicKey* pk,
}

if (ret == WS_SUCCESS) {
int keySz = wc_RsaEncryptSize(key) * 8;
if (keySz < 2048) {
WLOG(WS_LOG_DEBUG, "Key size too small (%d)", keySz);
ret = WS_CERT_KEY_SIZE_E;
}
ret = CheckRsaKeyBits(key);
}

if (ret == WS_SUCCESS) {
Expand Down
46 changes: 40 additions & 6 deletions tests/unit.c
Original file line number Diff line number Diff line change
Expand Up @@ -10650,23 +10650,39 @@ static const byte userAuthRsaSigBlob[] = {
/* 257: one past the actual signature size */
static const byte userAuthRsaSigLenOverrun[] = { 0x00, 0x00, 0x01, 0x01 };

/* Offsets of interest in userAuthRsaPubKeyBlob. */
#define RSA_PUB_BLOB_NLEN 18 /* length of the modulus mpint */
#define RSA_PUB_BLOB_N 23 /* first byte of the modulus, past the pad */

/* 129: the mpint pad byte plus a 1024 bit modulus */
static const byte userAuthRsaPubKeyNLen1024[] = { 0x00, 0x00, 0x00, 0x81 };
/* Clears the modulus' top bit, leaving 2047 bits in 256 bytes. */
static const byte userAuthRsaPubKeyMsb2047[] = { 0x7F };

typedef struct {
const char* name;
word32 patchIdx;
const byte* patch;
word32 patchSz; /* 0 = no patch */
word32 flipIdx; /* XOR 0x01 into this index; 0 = none */
word32 pubPatchIdx;
const byte* pubPatch;
word32 pubPatchSz; /* 0 = no patch */
int expected;
} UserAuthRsaTestVector;

static const UserAuthRsaTestVector userAuthRsaTestVectors[] = {
{ "high bit signature accepted", 0, NULL, 0, 0, WS_SUCCESS },
{ "high bit signature accepted", 0, NULL, 0, 0, 0, NULL, 0, WS_SUCCESS },
{ "corrupt signature rejected", 0, NULL, 0, RSA_SIG_BLOB_SIG + 128,
WS_RSA_E },
0, NULL, 0, WS_RSA_E },
{ "signature length overrun", RSA_SIG_BLOB_LEN, userAuthRsaSigLenOverrun,
4, 0, WS_BUFFER_E },
4, 0, 0, NULL, 0, WS_BUFFER_E },
{ "signature algo name mismatch", RSA_SIG_BLOB_ALGO,
(const byte*)"ssh-dss", 7, 0, WS_INVALID_ALGO_ID },
(const byte*)"ssh-dss", 7, 0, 0, NULL, 0, WS_INVALID_ALGO_ID },
{ "1024 bit key rejected", 0, NULL, 0, 0,
RSA_PUB_BLOB_NLEN, userAuthRsaPubKeyNLen1024, 4, WS_CERT_KEY_SIZE_E },
{ "2047 bit key rejected", 0, NULL, 0, 0,
RSA_PUB_BLOB_N, userAuthRsaPubKeyMsb2047, 1, WS_CERT_KEY_SIZE_E },
};

static int test_DoUserAuthRequestRsa(void)
Expand All @@ -10688,6 +10704,15 @@ static int test_DoUserAuthRequestRsa(void)
return 1;
}

/* The key size vectors patch the modulus in place, so the offsets have
* to still point at a 257 byte mpint holding a 2048 bit modulus. */
if (userAuthRsaPubKeyBlob[RSA_PUB_BLOB_NLEN + 2] != 0x01
|| userAuthRsaPubKeyBlob[RSA_PUB_BLOB_NLEN + 3] != 0x01
|| (userAuthRsaPubKeyBlob[RSA_PUB_BLOB_N] & 0x80) == 0) {
fprintf(stderr, "\tuserAuthRsaPubKeyBlob offsets are stale\n");
return 1;
}

ctx = wolfSSH_CTX_new(WOLFSSH_ENDPOINT_SERVER, NULL);
if (ctx == NULL)
return 1;
Expand All @@ -10699,21 +10724,25 @@ static int test_DoUserAuthRequestRsa(void)

for (i = 0, tv = userAuthRsaTestVectors; i < tc; i++, tv++) {
byte sigBlob[sizeof(userAuthRsaSigBlob)];
byte pubBlob[sizeof(userAuthRsaPubKeyBlob)];
byte digest[sizeof(userAuthRsaDigest)];
WS_UserAuthData_PublicKey pk;

WMEMCPY(sigBlob, userAuthRsaSigBlob, sizeof(sigBlob));
WMEMCPY(pubBlob, userAuthRsaPubKeyBlob, sizeof(pubBlob));
WMEMCPY(digest, userAuthRsaDigest, sizeof(digest));
if (tv->patchSz > 0)
WMEMCPY(sigBlob + tv->patchIdx, tv->patch, tv->patchSz);
if (tv->flipIdx > 0)
sigBlob[tv->flipIdx] ^= 0x01;
if (tv->pubPatchSz > 0)
WMEMCPY(pubBlob + tv->pubPatchIdx, tv->pubPatch, tv->pubPatchSz);

WMEMSET(&pk, 0, sizeof(pk));
pk.publicKeyType = (const byte*)"ssh-rsa";
pk.publicKeyTypeSz = 7;
pk.publicKey = userAuthRsaPubKeyBlob;
pk.publicKeySz = (word32)sizeof(userAuthRsaPubKeyBlob);
pk.publicKey = pubBlob;
pk.publicKeySz = (word32)sizeof(pubBlob);
pk.hasSignature = 1;
pk.signature = sigBlob;
pk.signatureSz = (word32)sizeof(sigBlob);
Expand Down Expand Up @@ -10900,6 +10929,11 @@ static int test_DoUserAuthRequestRsaCert(void)
byte digest[sizeof(userAuthRsaDigest)];
WS_UserAuthData_PublicKey pk;

/* Vectors that patch the raw public key blob don't apply here; the
* cert path takes its key from a fixed certificate. */
if (tv->pubPatchSz > 0)
continue;

WMEMCPY(sigBlob, userAuthRsaSigBlob, sizeof(sigBlob));
WMEMCPY(digest, userAuthRsaDigest, sizeof(digest));
if (tv->patchSz > 0)
Expand Down
7 changes: 7 additions & 0 deletions wolfssh/internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -566,6 +566,13 @@ enum NameIdType {
#ifndef WOLFSSH_DEFAULT_GEXDH_MIN
#define WOLFSSH_DEFAULT_GEXDH_MIN 2048
#endif

#ifndef WOLFSSH_RSA_MIN_KEY_BITS
/* Minimum accepted RSA public-key size (bits) for user authentication.
* Per NIST SP 800-131A; override at build time if a smaller key must be
* accepted. */
#define WOLFSSH_RSA_MIN_KEY_BITS 2048
Comment thread
ejohnstown marked this conversation as resolved.
#endif
#ifndef WOLFSSH_DEFAULT_GEXDH_PREFERRED
#define WOLFSSH_DEFAULT_GEXDH_PREFERRED 3072
#endif
Expand Down
Loading