Skip to content

Commit

Permalink
wolfSSH Client with OpenSSH-format Keys
Browse files Browse the repository at this point in the history
1. Add two error codes for the new key format decoding.
2. Add in some better error and bound checking.
3. Fix ordering on a WOLFSSH_UNUSED and variable declaration.
4. Remove redundant ; from WOLFSSH_UNUSED function-like macro.
  • Loading branch information
ejohnstown committed Oct 16, 2023
1 parent 4f5f471 commit 2a5da5f
Show file tree
Hide file tree
Showing 4 changed files with 99 additions and 65 deletions.
155 changes: 94 additions & 61 deletions src/internal.c
Original file line number Diff line number Diff line change
Expand Up @@ -418,6 +418,12 @@ const char* GetErrorString(int err)
case WS_MATCH_UA_KEY_ID_E:
return "unable to match user auth key type";

case WS_KEY_AUTH_MAGIC_E:
return "key auth magic check error";

case WS_KEY_CHECK_VAL_E:
return "key check value error";

default:
return "Unknown error code";
}
Expand Down Expand Up @@ -1040,8 +1046,8 @@ int IdentifyAsn1Key(const byte* in, word32 inSz, int isPrivate, void* heap)
static int GetOpenSshKeyRsa(RsaKey* key,
const byte* buf, word32 len, word32* idx)
{
const byte* val;
word32 valSz;
const byte* val = NULL;
word32 valSz = 0;
mp_int m;

GetMpint(&valSz, &val, buf, len, idx); /* n */
Expand Down Expand Up @@ -1073,8 +1079,8 @@ static int GetOpenSshKeyRsa(RsaKey* key,
static int GetOpenSshKeyEcc(ecc_key* key,
const byte* buf, word32 len, word32* idx)
{
const byte *name, *priv, *pub;
word32 nameSz, privSz, pubSz;
const byte *name = NULL, *priv = NULL, *pub = NULL;
word32 nameSz = 0, privSz = 0, pubSz = 0;
int ret;

GetStringRef(&nameSz, &name, buf, len, idx); /* curve name */
Expand All @@ -1093,72 +1099,100 @@ static int GetOpenSshKey(WS_KeySignature *key,
const byte* buf, word32 len, word32* idx)
{
const char AuthMagic[] = "openssh-key-v1";
const byte* str;
const byte* str = NULL;
word32 keyCount = 0, strSz = 0, i;
int ret = WS_SUCCESS;
word32 keyCount, i, strSz;

if (strcmp(AuthMagic, (const char*)buf) != 0) {
ret = -1;
ret = WS_KEY_AUTH_MAGIC_E;
}
strSz = (word32)strlen(AuthMagic);
*idx += strSz + 1;

GetSkip(buf, len, idx); /* ciphername */
GetSkip(buf, len, idx); /* kdfname */
GetSkip(buf, len, idx); /* kdfoptions */
if (ret == WS_SUCCESS) {
*idx += (word32)strlen(AuthMagic) + 1;
ret = GetSkip(buf, len, idx); /* ciphername */
}

GetUint32(&keyCount, buf, len, idx); /* key count */
if (ret == WS_SUCCESS)
ret = GetSkip(buf, len, idx); /* kdfname */

if (ret == WS_SUCCESS)
ret = GetSkip(buf, len, idx); /* kdfoptions */

if (ret == WS_SUCCESS)
ret = GetUint32(&keyCount, buf, len, idx); /* key count */

for (i = 0; i < keyCount; i++) {
GetStringRef(&strSz, &str, buf, len, idx); /* public buf */
if (ret == WS_SUCCESS)
ret = GetStringRef(&strSz, &str, buf, len, idx); /* public buf */
}

GetStringRef(&strSz, &str, buf, len, idx); /* list of private keys */
if (keyCount > 0) {
if (ret == WS_SUCCESS) {
ret = GetStringRef(&strSz, &str, buf, len, idx);
/* list of private keys */
}

if (strSz > 0) {
const byte* subStr;
word32 subStrSz, subIdx = 0, check1 = 0, check2 = ~0;
byte keyId;

idx = 0;
GetUint32(&check1, str, strSz, &subIdx); /* checkint 1 */
GetUint32(&check2, str, strSz, &subIdx); /* checkint 2 */
if (check1 == check2) {
for (i = 0; i < keyCount; i++) {
GetStringRef(&subStrSz, &subStr, str, strSz, &subIdx);
keyId = NameToId((const char*)subStr, subStrSz);
wolfSSH_KEY_init(key, keyId, NULL);
switch (keyId) {
#ifndef WOLFSSH_NO_RSA
case ID_SSH_RSA:
GetOpenSshKeyRsa(&key->ks.rsa.key,
str, strSz, &subIdx);
break;
#endif
#ifndef WOLFSSH_NO_ECDSA
case ID_ECDSA_SHA2_NISTP256:
GetOpenSshKeyEcc(&key->ks.ecc.key,
str, strSz, &subIdx);
break;
#endif
default:
ret = WS_UNIMPLEMENTED_E;
break;
if (strSz > 0) {
const byte* subStr = NULL;
word32 subStrSz = 0, subIdx = 0, check1 = 0, check2 = ~0;
byte keyId;

idx = 0;
if (ret == WS_SUCCESS)
ret = GetUint32(&check1, str, strSz, &subIdx); /* checkint 1 */
if (ret == WS_SUCCESS)
ret = GetUint32(&check2, str, strSz, &subIdx); /* checkint 2 */
if (ret == WS_SUCCESS) {
if (check1 != check2) {
ret = WS_KEY_CHECK_VAL_E;
}
GetSkip(str, strSz, &subIdx); /* comment */
}
/* Padding: Add increasing digits to pad to the nearest block
* size. Default block size is 8, but depends on the encryption
* algo. The private key chunk's length, and the length of the
* comment delimit the end of the encrypted blob. No added
* padding required. */
if (strSz % 8 == 0) {
if (strSz - subIdx > 0) {
/* The padding starts at 1. */
check2 = strSz - subIdx;
for (check1 = 1; check1 <= check2; check1++, subIdx++) {
if (check1 != str[subIdx]) {
/* Bad pad value. */
}
if (ret == WS_SUCCESS) {
for (i = 0; i < keyCount; i++) {
ret = GetStringRef(&subStrSz, &subStr,
str, strSz, &subIdx);
if (ret == WS_SUCCESS) {
keyId = NameToId((const char*)subStr, subStrSz);
wolfSSH_KEY_init(key, keyId, NULL);
switch (keyId) {
#ifndef WOLFSSH_NO_RSA
case ID_SSH_RSA:
GetOpenSshKeyRsa(&key->ks.rsa.key,
str, strSz, &subIdx);
break;
#endif
#ifndef WOLFSSH_NO_ECDSA
case ID_ECDSA_SHA2_NISTP256:
GetOpenSshKeyEcc(&key->ks.ecc.key,
str, strSz, &subIdx);
break;
#endif
default:
ret = WS_UNIMPLEMENTED_E;
break;
}
if (ret == WS_SUCCESS)
ret = GetSkip(str, strSz, &subIdx);
/* key comment */
}
}
/* Padding: Add increasing digits to pad to the nearest
* block size. Default block size is 8, but depends on
* the encryption algo. The private key chunk's length,
* and the length of the comment delimit the end of the
* encrypted blob. No added padding required. */
if (ret == WS_SUCCESS) {
if (strSz % 8 == 0) {
if (strSz - subIdx > 0) {
/* The padding starts at 1. */
check2 = strSz - subIdx;
for (check1 = 1;
check1 <= check2;
check1++, subIdx++) {
if (check1 != str[subIdx]) {
/* Bad pad value. */
}
}
}
}
}
Expand Down Expand Up @@ -1598,9 +1632,6 @@ int wolfSSH_ProcessBuffer(WOLFSSH_CTX* ctx,
derSz = (word32)ret;
}
#endif /* WOLFSSH_CERTS */
else if (format == WOLFSSH_FORMAT_OPENSSH) {
/* TODO */
}
else {
return WS_UNIMPLEMENTED_E;
}
Expand Down Expand Up @@ -11304,6 +11335,7 @@ static int PrepareUserAuthRequestEcc(WOLFSSH* ssh, word32* payloadSz,
}
else
#endif
{
ret = wc_EccPrivateKeyDecode(authData->sf.publicKey.privateKey,
&idx, &keySig->ks.ecc.key,
authData->sf.publicKey.privateKeySz);
Expand All @@ -11313,6 +11345,7 @@ static int PrepareUserAuthRequestEcc(WOLFSSH* ssh, word32* payloadSz,
authData->sf.publicKey.privateKey,
authData->sf.publicKey.privateKeySz, &idx);
}
}
}

if (ret == WS_SUCCESS) {
Expand Down
3 changes: 1 addition & 2 deletions src/ssh.c
Original file line number Diff line number Diff line change
Expand Up @@ -1584,11 +1584,10 @@ static int DoPemKey(const byte* in, word32 inSz, byte** out,
{
int ret = WS_SUCCESS;
byte* newKey = NULL;
word32 newKeySz = inSz; /* binary will be smaller than PEM */

WOLFSSH_UNUSED(heap);

word32 newKeySz = inSz; /* binary will be smaller than PEM */

if (*out == NULL) {
newKey = (byte*)WMALLOC(newKeySz, heap, DYNTYPE_PRIVKEY);
if (newKey == NULL) {
Expand Down
4 changes: 3 additions & 1 deletion wolfssh/error.h
Original file line number Diff line number Diff line change
Expand Up @@ -128,8 +128,10 @@ enum WS_ErrorCodes {
WS_CERT_KEY_SIZE_E = -1087, /* Key size error */
WS_CTX_KEY_COUNT_E = -1088, /* Adding too many private keys */
WS_MATCH_UA_KEY_ID_E = -1089, /* Match user auth key key fail */
WS_KEY_AUTH_MAGIC_E = -1090, /* OpenSSH key auth magic check fail */
WS_KEY_CHECK_VAL_E = -1091, /* OpenSSH key check value fail */

WS_LAST_E = -1089 /* Update this to indicate last error */
WS_LAST_E = -1091 /* Update this to indicate last error */
};


Expand Down
2 changes: 1 addition & 1 deletion wolfssh/port.h
Original file line number Diff line number Diff line change
Expand Up @@ -1306,7 +1306,7 @@ extern "C" {


#ifndef WOLFSSH_UNUSED
#define WOLFSSH_UNUSED(arg) (void)(arg);
#define WOLFSSH_UNUSED(arg) (void)(arg)
#endif


Expand Down

0 comments on commit 2a5da5f

Please sign in to comment.