From 70aa287d78c9804abe7fe2e0f208b918ba33d35f Mon Sep 17 00:00:00 2001 From: John Safranek Date: Fri, 13 Oct 2023 14:11:13 -0700 Subject: [PATCH 1/9] wolfSSH Client with OpenSSH-format Keys 1. Move the KeySignature struct around in internal.c so it can be used for a couple tasks. 2. Add decoder for the OpenSSH-format keys. 3. Add an identification function for the new key. 4. Update ReadKey to handle the new format. --- apps/wolfssh/common.c | 2 +- src/internal.c | 428 ++++++++++++++++++++++++++++++++++-------- src/ssh.c | 298 +++++++++++++++++++---------- wolfssh/internal.h | 8 +- wolfssh/ssh.h | 1 + 5 files changed, 556 insertions(+), 181 deletions(-) diff --git a/apps/wolfssh/common.c b/apps/wolfssh/common.c index 3945866c2..7d0ccb44d 100644 --- a/apps/wolfssh/common.c +++ b/apps/wolfssh/common.c @@ -379,7 +379,7 @@ int ClientSetEcho(int type) newTerm.c_lflag &= ~(ICANON | ECHOE | ECHOK | ECHONL | ISIG); } else { - newTerm.c_lflag |= (ICANON | ECHONL); + newTerm.c_lflag |= ICANON; } if (tcsetattr(STDIN_FILENO, TCSANOW, &newTerm) != 0) { diff --git a/src/internal.c b/src/internal.c index f8732546e..0f4407d01 100644 --- a/src/internal.c +++ b/src/internal.c @@ -845,21 +845,100 @@ void SshResourceFree(WOLFSSH* ssh, void* heap) #endif } -union wolfSSH_key { + +typedef struct WS_KeySignature { + byte keySigId; + word32 sigSz; + const char *name; + word32 nameSz; + union { #ifndef WOLFSSH_NO_RSA - RsaKey rsa; + struct { + RsaKey key; + byte e[256]; + word32 eSz; + byte ePad; + byte n[256]; + word32 nSz; + byte nPad; + } rsa; #endif #ifndef WOLFSSH_NO_ECDSA - ecc_key ecc; + struct { + ecc_key key; + word32 keyBlobSz; + const char *keyBlobName; + word32 keyBlobNameSz; + byte q[256]; + word32 qSz; + byte qPad; + const char *primeName; + word32 primeNameSz; + } ecc; #endif -}; + } ks; +} WS_KeySignature; + + +static int wolfSSH_KEY_init(WS_KeySignature* key, byte keyId, void* heap) +{ + int ret = WS_SUCCESS; + + if (key != NULL) { + key->keySigId = keyId; + + switch (keyId) { +#ifndef WOLFSSH_NO_RSA + case ID_SSH_RSA: + ret = wc_InitRsaKey(&key->ks.rsa.key, NULL); + break; +#endif +#ifndef WOLFSSH_NO_ECDSA + case ID_ECDSA_SHA2_NISTP256: + ret = wc_ecc_init_ex(&key->ks.ecc.key, heap, INVALID_DEVID); + break; +#endif + default: + ret = WS_INVALID_ALGO_ID; + } + } + + return ret; +} + + +static int wolfSSH_KEY_clean(WS_KeySignature* key) +{ + int ret = WS_SUCCESS; + + if (key != NULL) { + switch (key->keySigId) { +#ifndef WOLFSSH_NO_RSA + case ID_SSH_RSA: + wc_FreeRsaKey(&key->ks.rsa.key); + break; +#endif +#ifndef WOLFSSH_NO_ECDSA + case ID_ECDSA_SHA2_NISTP256: + case ID_ECDSA_SHA2_NISTP384: + case ID_ECDSA_SHA2_NISTP521: + wc_ecc_free(&key->ks.ecc.key); + break; +#endif + default: + ret = WS_INVALID_ALGO_ID; + } + } + + return ret; +} /* - * Identifies the flavor of a key, RSA or ECDSA, and returns the key type ID. - * The process is to decode the key as if it was RSA and if that fails try - * to load it as if ECDSA. Both public and private keys can be decoded. - * For RSA keys, the key format is described as "ssh-rsa". + * Identifies the flavor of an ASN.1 key, RSA or ECDSA, and returns the key + * type ID. The process is to decode the key as if it was RSA and if that + * fails try to load it as if ECDSA. Both public and private keys can be + * decoded. For RSA keys, the key format is described as "ssh-rsa". * * @param in key to identify * @param inSz size of key @@ -867,88 +946,271 @@ union wolfSSH_key { * @param heap heap to use for memory allocation * @return keyId as int, WS_MEMORY_E, WS_UNIMPLEMENTED_E */ -int IdentifyKey(const byte* in, word32 inSz, int isPrivate, void* heap) +int IdentifyAsn1Key(const byte* in, word32 inSz, int isPrivate, void* heap) { - union wolfSSH_key *key = NULL; - int keyId = ID_UNKNOWN; + WS_KeySignature *key = NULL; word32 idx; int ret; int dynType = isPrivate ? DYNTYPE_PRIVKEY : DYNTYPE_PUBKEY; WOLFSSH_UNUSED(dynType); - key = (union wolfSSH_key*)WMALLOC(sizeof(union wolfSSH_key), heap, dynType); + key = (WS_KeySignature*)WMALLOC(sizeof(WS_KeySignature), heap, dynType); + + if (key == NULL) { + ret = WS_MEMORY_E; + } + else { + WMEMSET(key, 0, sizeof(*key)); + key->keySigId = ID_UNKNOWN; #ifndef WOLFSSH_NO_RSA - if (key != NULL) { /* Check RSA key */ - if (keyId == ID_UNKNOWN) { + if (key->keySigId == ID_UNKNOWN) { idx = 0; - ret = wc_InitRsaKey(&key->rsa, NULL); + ret = wc_InitRsaKey(&key->ks.rsa.key, NULL); if (ret == 0) { if (isPrivate) { - ret = wc_RsaPrivateKeyDecode(in, &idx, &key->rsa, inSz); + ret = wc_RsaPrivateKeyDecode(in, &idx, + &key->ks.rsa.key, inSz); } else { - ret = wc_RsaPublicKeyDecode(in, &idx, &key->rsa, inSz); + ret = wc_RsaPublicKeyDecode(in, &idx, + &key->ks.rsa.key, inSz); } /* If decode was successful, this is an RSA key. */ if (ret == 0) { - keyId = ID_SSH_RSA; + key->keySigId = ID_SSH_RSA; } } - wc_FreeRsaKey(&key->rsa); + wc_FreeRsaKey(&key->ks.rsa.key); } - } #endif /* WOLFSSH_NO_RSA */ #ifndef WOLFSSH_NO_ECDSA - if (key != NULL) { /* Check ECDSA key */ - if (keyId == ID_UNKNOWN) { + if (key->keySigId == ID_UNKNOWN) { idx = 0; - ret = wc_ecc_init_ex(&key->ecc, heap, INVALID_DEVID); + ret = wc_ecc_init_ex(&key->ks.ecc.key, heap, INVALID_DEVID); if (ret == 0) { if (isPrivate) { - ret = wc_EccPrivateKeyDecode(in, &idx, &key->ecc, inSz); + ret = wc_EccPrivateKeyDecode(in, &idx, + &key->ks.ecc.key, inSz); } else { - ret = wc_EccPublicKeyDecode(in, &idx, &key->ecc, inSz); + ret = wc_EccPublicKeyDecode(in, &idx, + &key->ks.ecc.key, inSz); } /* If decode was successful, this is an ECDSA key. */ if (ret == 0) { - switch (wc_ecc_get_curve_id(key->ecc.idx)) { + switch (wc_ecc_get_curve_id(key->ks.ecc.key.idx)) { case ECC_SECP256R1: - keyId = ID_ECDSA_SHA2_NISTP256; + key->keySigId = ID_ECDSA_SHA2_NISTP256; break; case ECC_SECP384R1: - keyId = ID_ECDSA_SHA2_NISTP384; + key->keySigId = ID_ECDSA_SHA2_NISTP384; break; case ECC_SECP521R1: - keyId = ID_ECDSA_SHA2_NISTP521; + key->keySigId = ID_ECDSA_SHA2_NISTP521; break; } } } - wc_ecc_free(&key->ecc); + wc_ecc_free(&key->ks.ecc.key); } - } #endif /* WOLFSSH_NO_ECDSA */ + if (key->keySigId == ID_UNKNOWN) { + ret = WS_UNIMPLEMENTED_E; + } + else { + ret = key->keySigId; + } + + WFREE(key, heap, dynType); + } + + return ret; +} + + +static int GetOpenSshKeyRsa(RsaKey* key, + const byte* buf, word32 len, word32* idx) +{ + const byte* val; + word32 valSz; + mp_int m; + + GetMpint(&valSz, &val, buf, len, idx); /* n */ + mp_read_unsigned_bin(&key->n, val, valSz); + GetMpint(&valSz, &val, buf, len, idx); /* e */ + mp_read_unsigned_bin(&key->e, val, valSz); + GetMpint(&valSz, &val, buf, len, idx); /* d */ + mp_read_unsigned_bin(&key->d, val, valSz); + GetMpint(&valSz, &val, buf, len, idx); /* iqmp */ + mp_read_unsigned_bin(&key->u, val, valSz); + GetMpint(&valSz, &val, buf, len, idx); /* p */ + mp_read_unsigned_bin(&key->p, val, valSz); + GetMpint(&valSz, &val, buf, len, idx); /* q */ + mp_read_unsigned_bin(&key->q, val, valSz); + + /* Calculate dP and dQ for wolfCrypt. */ + mp_init(&m); + mp_sub_d(&key->p, 1, &m); + mp_mod(&key->d, &m, &key->dP); + mp_sub_d(&key->q, 1, &m); + mp_mod(&key->d, &m, &key->dQ); + mp_forcezero(&m); + mp_free(&m); + + return 0; +} + + +static int GetOpenSshKeyEcc(ecc_key* key, + const byte* buf, word32 len, word32* idx) +{ + const byte *name, *priv, *pub; + word32 nameSz, privSz, pubSz; + int ret; + + GetStringRef(&nameSz, &name, buf, len, idx); /* curve name */ + GetStringRef(&pubSz, &pub, buf, len, idx); /* Q */ + GetMpint(&privSz, &priv, buf, len, idx); /* d */ + + ret = wc_ecc_import_private_key_ex(priv, privSz, pub, pubSz, + key, ECC_CURVE_DEF); + + return ret != 0; +} + + + +static int GetOpenSshKey(WS_KeySignature *key, + const byte* buf, word32 len, word32* idx) +{ + const char AuthMagic[] = "openssh-key-v1"; + const byte* str; + int ret = WS_SUCCESS; + word32 keyCount, i, strSz; + + if (strcmp(AuthMagic, (const char*)buf) != 0) { + ret = -1; + } + strSz = (word32)strlen(AuthMagic); + *idx += strSz + 1; + + GetSkip(buf, len, idx); /* ciphername */ + GetSkip(buf, len, idx); /* kdfname */ + GetSkip(buf, len, idx); /* kdfoptions */ + + GetUint32(&keyCount, buf, len, idx); /* key count */ + + for (i = 0; i < keyCount; i++) { + GetStringRef(&strSz, &str, buf, len, idx); /* public buf */ + } + + 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; + } + 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. */ + } + } + } + } + } + } + + return ret; +} + + +/* + * Identifies the flavor of an OpenSSH key, RSA or ECDSA, and returns the + * key type ID. The process is to decode the key extracting the identifiers, + * and try to decode the key as the type indicated type. For RSA keys, the + * key format is described as "ssh-rsa". + * + * @param in key to identify + * @param inSz size of key + * @param heap heap to use for memory allocation + * @return keyId as int, WS_MEMORY_E, WS_UNIMPLEMENTED_E, + * WS_INVALID_ALGO_ID + */ +int IdentifyOpenSshKey(const byte* in, word32 inSz, void* heap) +{ + WS_KeySignature *key = NULL; + word32 idx = 0; + int ret; + + key = (WS_KeySignature*)WMALLOC(sizeof(WS_KeySignature), + heap, DYNTYPE_PRIVKEY); + if (key == NULL) { ret = WS_MEMORY_E; } - else if (keyId == ID_UNKNOWN) { - ret = WS_UNIMPLEMENTED_E; - } else { - ret = keyId; + WMEMSET(key, 0, sizeof(*key)); + key->keySigId = ID_UNKNOWN; + + ret = GetOpenSshKey(key, in, inSz, &idx); + + if (ret == WS_SUCCESS) { + ret = key->keySigId; + } + else if (key->keySigId == ID_UNKNOWN) { + ret = WS_UNIMPLEMENTED_E; + } + + wolfSSH_KEY_clean(key); + WFREE(key, heap, DYNTYPE_PRIVKEY); } - WFREE(key, heap, dynType); return ret; } @@ -958,7 +1220,7 @@ int IdentifyKey(const byte* in, word32 inSz, int isPrivate, void* heap) /* * Identifies the flavor of an X.509 certificate, RSA or ECDSA, and returns * the key type ID. The process is to decode the certificate and pass the - * public key to IdentifyKey. + * public key to IdentifyAsn1Key. * * @param in certificate to identify * @param inSz size of certificate @@ -1005,7 +1267,7 @@ static int IdentifyCert(const byte* in, word32 inSz, void* heap) } if (ret == 0) { - ret = IdentifyKey(key, keySz, 0, heap); + ret = IdentifyAsn1Key(key, keySz, 0, heap); } WFREE(key, heap, DYNTYPE_PUBKEY); @@ -1288,9 +1550,12 @@ int wolfSSH_ProcessBuffer(WOLFSSH_CTX* ctx, if (ctx == NULL || in == NULL || inSz == 0) return WS_BAD_ARGUMENT; - if (format != WOLFSSH_FORMAT_ASN1 && format != WOLFSSH_FORMAT_PEM && - format != WOLFSSH_FORMAT_RAW) + if (format != WOLFSSH_FORMAT_ASN1 + && format != WOLFSSH_FORMAT_PEM + && format != WOLFSSH_FORMAT_RAW + && format != WOLFSSH_FORMAT_OPENSSH) { return WS_BAD_FILETYPE_E; + } if (type == BUFTYPE_CA) { dynamicType = DYNTYPE_CA; @@ -1334,6 +1599,9 @@ int wolfSSH_ProcessBuffer(WOLFSSH_CTX* ctx, derSz = (word32)ret; } #endif /* WOLFSSH_CERTS */ + else if (format == WOLFSSH_FORMAT_OPENSSH) { + /* TODO */ + } else { return WS_UNIMPLEMENTED_E; } @@ -1341,7 +1609,7 @@ int wolfSSH_ProcessBuffer(WOLFSSH_CTX* ctx, /* Maybe decrypt */ if (type == BUFTYPE_PRIVKEY) { - ret = IdentifyKey(der, derSz, 1, ctx->heap); + ret = IdentifyAsn1Key(der, derSz, 1, ctx->heap); if (ret < 0) { WFREE(der, heap, dynamicType); return ret; @@ -1713,6 +1981,11 @@ static const NameIdPair NameIdMap[] = { /* Ext Info IDs */ { ID_EXTINFO_SERVER_SIG_ALGS, "server-sig-algs" }, + + /* Curve Name IDs */ + { ID_CURVE_NISTP256, "nistp256" }, + { ID_CURVE_NISTP384, "nistp384" }, + { ID_CURVE_NISTP521, "nistp521" }, }; @@ -2397,6 +2670,26 @@ int GetSize(word32* v, const byte* buf, word32 len, word32* idx) } +int GetSkip(const byte* buf, word32 len, word32* idx) +{ + int result; + word32 sz; + + result = GetUint32(&sz, buf, len, idx); + + if (result == WS_SUCCESS) { + result = WS_BUFFER_E; + + if (*idx < len && sz <= len - *idx) { + *idx += sz; + result = WS_SUCCESS; + } + } + + return result; +} + + /* Gets the size of the mpint, and puts the pointer to the start of * buf's number into *mpint. This function does not copy. */ int GetMpint(word32* mpintSz, const byte** mpint, @@ -10556,40 +10849,6 @@ int SendExtInfo(WOLFSSH* ssh) } -typedef struct WS_KeySignature { - byte keySigId; - word32 sigSz; - const char *name; - word32 nameSz; - union { -#ifndef WOLFSSH_NO_RSA - struct { - RsaKey key; - byte e[256]; - word32 eSz; - byte ePad; - byte n[256]; - word32 nSz; - byte nPad; - } rsa; -#endif -#ifndef WOLFSSH_NO_ECDSA - struct { - ecc_key key; - word32 keyBlobSz; - const char *keyBlobName; - word32 keyBlobNameSz; - byte q[256]; - word32 qSz; - byte qPad; - const char *primeName; - word32 primeNameSz; - } ecc; -#endif - } ks; -} WS_KeySignature; - - /* Updates the payload size, and maybe loads keys. */ static int PrepareUserAuthRequestPassword(WOLFSSH* ssh, word32* payloadSz, const WS_UserAuthData* authData) @@ -10647,15 +10906,24 @@ static int PrepareUserAuthRequestRsa(WOLFSSH* ssh, word32* payloadSz, if (ret == WS_SUCCESS) { word32 idx = 0; #ifdef WOLFSSH_AGENT - if (ssh->agentEnabled) + if (ssh->agentEnabled) { ret = wc_RsaPublicKeyDecode(authData->sf.publicKey.publicKey, &idx, &keySig->ks.rsa.key, authData->sf.publicKey.publicKeySz); + } else #endif + { ret = wc_RsaPrivateKeyDecode(authData->sf.publicKey.privateKey, &idx, &keySig->ks.rsa.key, authData->sf.publicKey.privateKeySz); + if (ret != 0) { + idx = 0; + ret = GetOpenSshKey(keySig, + authData->sf.publicKey.privateKey, + authData->sf.publicKey.privateKeySz, &idx); + } + } } if (ret == WS_SUCCESS) { @@ -11040,6 +11308,12 @@ static int PrepareUserAuthRequestEcc(WOLFSSH* ssh, word32* payloadSz, ret = wc_EccPrivateKeyDecode(authData->sf.publicKey.privateKey, &idx, &keySig->ks.ecc.key, authData->sf.publicKey.privateKeySz); + if (ret != 0) { + idx = 0; + ret = GetOpenSshKey(keySig, + authData->sf.publicKey.privateKey, + authData->sf.publicKey.privateKeySz, &idx); + } } if (ret == WS_SUCCESS) { @@ -13491,7 +13765,6 @@ int wolfSSH_CleanPath(WOLFSSH* ssh, char* in) #endif /* WOLFSSH_SFTP || WOLFSSH_SCP */ -#ifdef DEBUG_WOLFSSH #define LINE_WIDTH 16 void DumpOctetString(const byte* input, word32 inputSz) @@ -13527,7 +13800,6 @@ void DumpOctetString(const byte* input, word32 inputSz) } } -#endif #ifdef WOLFSSH_SFTP diff --git a/src/ssh.c b/src/ssh.c index 93a5df572..738d54d1f 100644 --- a/src/ssh.c +++ b/src/ssh.c @@ -1323,7 +1323,6 @@ void* wolfSSH_GetPublicKeyCheckCtx(WOLFSSH* ssh) return NULL; } -#ifdef WOLFSSH_TERM #if defined(WOLFSSH_TERM) && !defined(NO_FILESYSTEM) /* Used to resize terminal window with shell connections @@ -1361,8 +1360,6 @@ void wolfSSH_SetTerminalResizeCtx(WOLFSSH* ssh, void* usrCtx) } #endif -#endif - /* Used to set the channel request type sent in wolfSSH connect. The default * type set is shell if this function is not called. @@ -1489,137 +1486,232 @@ union wolfSSH_key { #endif }; -/* Reads a key from the buffer in to out. If the out buffer doesn't exist - it is created. The type of key is stored in outType. It'll be a pointer - to a constant string. Format indicates the format of the key, currently - either SSH format (a public key) or ASN.1 in DER or PEM format (a - private key). */ -int wolfSSH_ReadKey_buffer(const byte* in, word32 inSz, int format, - byte** out, word32* outSz, const byte** outType, word32* outTypeSz, +static const char* PrivBeginOpenSSH = "-----BEGIN OPENSSH PRIVATE KEY-----"; +static const char* PrivEndOpenSSH = "-----END OPENSSH PRIVATE KEY-----"; +static const char* PrivBeginPrefix = "-----BEGIN "; +/* static const char* PrivEndPrefix = "-----END "; */ +static const char* PrivSuffix = " PRIVATE KEY-----"; + + +static int DoSshPubKey(const byte* in, word32 inSz, byte** out, + word32* outSz, const byte** outType, word32* outTypeSz, void* heap) { int ret = WS_SUCCESS; byte* newKey = NULL; + char* c; + char* last; + char* type = NULL; + char* key = NULL; + WOLFSSH_UNUSED(inSz); WOLFSSH_UNUSED(heap); - if (in == NULL || inSz == 0 || out == NULL || outSz == NULL || - outType == NULL || outTypeSz == NULL) - return WS_BAD_ARGUMENT; + /* + SSH format is: + type AAAABASE64ENCODEDKEYDATA comment + */ + c = WSTRDUP((const char*)in, heap, DYNTYPE_STRING); + type = WSTRTOK(c, " \n", &last); + key = WSTRTOK(NULL, " \n", &last); - if (format == WOLFSSH_FORMAT_SSH) { - char* c; - char* last; - char* type = NULL; - char* key = NULL; - - /* - SSH format is: - type AAAABASE64ENCODEDKEYDATA comment - */ - c = WSTRDUP((const char*)in, heap, DYNTYPE_STRING); - type = WSTRTOK(c, " \n", &last); - key = WSTRTOK(NULL, " \n", &last); - - if (type != NULL && key != NULL) { - const char* name; - word32 typeSz; - byte nameId; - - typeSz = (word32)WSTRLEN(type); - - nameId = NameToId(type, typeSz); - name = IdToName(nameId); - *outType = (const byte*)name; - *outTypeSz = typeSz; - - if (*out == NULL) { - /* set size based on sanity check in wolfSSL base64 decode - * function */ - *outSz = ((word32)WSTRLEN(key) * 3 + 3) / 4; - newKey = (byte*)WMALLOC(*outSz, heap, DYNTYPE_PRIVKEY); - if (newKey == NULL) { - return WS_MEMORY_E; - } - *out = newKey; - } + if (type != NULL && key != NULL) { + const char* name; + word32 typeSz; + byte nameId; - ret = Base64_Decode((byte*)key, (word32)WSTRLEN(key), *out, outSz); - } + typeSz = (word32)WSTRLEN(type); - if (ret != 0) { - WLOG(WS_LOG_DEBUG, "Base64 decode of public key failed."); - ret = WS_PARSE_E; - } + nameId = NameToId(type, typeSz); + name = IdToName(nameId); + *outType = (const byte*)name; + *outTypeSz = typeSz; - WFREE(c, heap, DYNTYPE_STRING); - } - else if (format == WOLFSSH_FORMAT_ASN1) { if (*out == NULL) { - newKey = (byte*)WMALLOC(inSz, heap, DYNTYPE_PRIVKEY); + /* set size based on sanity check in wolfSSL base64 decode + * function */ + *outSz = ((word32)WSTRLEN(key) * 3 + 3) / 4; + newKey = (byte*)WMALLOC(*outSz, heap, DYNTYPE_PRIVKEY); if (newKey == NULL) { return WS_MEMORY_E; } *out = newKey; } - else { - if (*outSz < inSz) { - WLOG(WS_LOG_DEBUG, "DER private key output size too small"); - return WS_BUFFER_E; - } - newKey = *out; + + ret = Base64_Decode((byte*)key, (word32)WSTRLEN(key), *out, outSz); + } + + if (ret != 0) { + WLOG(WS_LOG_DEBUG, "Base64 decode of public key failed."); + ret = WS_PARSE_E; + } + + WFREE(c, heap, DYNTYPE_STRING); + return ret; +} + + +static int DoAsn1Key(const byte* in, word32 inSz, byte** out, + word32* outSz, const byte** outType, word32* outTypeSz, + void* heap) +{ + int ret = WS_SUCCESS; + byte* newKey = NULL; + + WOLFSSH_UNUSED(heap); + + if (*out == NULL) { + newKey = (byte*)WMALLOC(inSz, heap, DYNTYPE_PRIVKEY); + if (newKey == NULL) { + return WS_MEMORY_E; + } + *out = newKey; + } + else { + if (*outSz < inSz) { + WLOG(WS_LOG_DEBUG, "DER private key output size too small"); + return WS_BUFFER_E; + } + newKey = *out; + } + *outSz = inSz; + WMEMCPY(newKey, in, inSz); + + ret = IdentifyAsn1Key(in, inSz, 1, heap); + if (ret > 0) { + *outType = (const byte*)IdToName(ret); + *outTypeSz = (word32)WSTRLEN((const char*)*outType); + ret = WS_SUCCESS; + } + + return ret; +} + + +static int DoPemKey(const byte* in, word32 inSz, byte** out, + word32* outSz, const byte** outType, word32* outTypeSz, + void* heap) +{ + int ret = WS_SUCCESS; + byte* newKey = NULL; + + 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) { + return WS_MEMORY_E; + } + *out = newKey; + } + else { + if (*outSz < inSz) { + WLOG(WS_LOG_DEBUG, "PEM private key output size too small"); + return WS_BUFFER_E; } - *outSz = inSz; - WMEMCPY(newKey, in, inSz); + newKey = *out; + } + + /* If it is PEM, convert to ASN1 then process. */ + ret = wc_KeyPemToDer(in, inSz, newKey, newKeySz, NULL); + if (ret > 0) { + newKeySz = (word32)ret; + ret = WS_SUCCESS; + } + else { + WLOG(WS_LOG_DEBUG, "Base64 decode of public key failed."); + ret = WS_PARSE_E; + } - ret = IdentifyKey(in, inSz, 1, heap); + if (ret == WS_SUCCESS) { + ret = IdentifyAsn1Key(newKey, newKeySz, 1, heap); if (ret > 0) { + *outSz = newKeySz; *outType = (const byte*)IdToName(ret); *outTypeSz = (word32)WSTRLEN((const char*)*outType); ret = WS_SUCCESS; } + else { + WLOG(WS_LOG_DEBUG, "unable to identify key"); + } } - else if (format == WOLFSSH_FORMAT_PEM) { - word32 newKeySz = inSz; /* binary will be smaller than PEM */ - if (*out == NULL) { - newKey = (byte*)WMALLOC(newKeySz, heap, DYNTYPE_PRIVKEY); - if (newKey == NULL) { - return WS_MEMORY_E; - } - *out = newKey; + return ret; +} + + +static int DoOpenSshKey(const byte* in, word32 inSz, byte** out, + word32* outSz, const byte** outType, word32* outTypeSz, + void* heap) +{ + int ret = WS_SUCCESS; + byte* newKey = NULL; + word32 newKeySz = inSz; /* binary will be smaller than PEM */ + + if (*out == NULL) { + newKey = (byte*)WMALLOC(newKeySz, heap, DYNTYPE_PRIVKEY); + if (newKey == NULL) { + return WS_MEMORY_E; } - else { - if (*outSz < inSz) { - WLOG(WS_LOG_DEBUG, "PEM private key output size too small"); - return WS_BUFFER_E; - } - newKey = *out; + *out = newKey; + } + else { + if (*outSz < inSz) { + WLOG(WS_LOG_DEBUG, "PEM private key output size too small"); + return WS_BUFFER_E; } + newKey = *out; + } + + in += strlen(PrivBeginOpenSSH); + inSz -= (strlen(PrivBeginOpenSSH) + strlen(PrivEndOpenSSH) + 2); - /* If it is PEM, convert to ASN1 then process. */ - ret = wc_KeyPemToDer(in, inSz, newKey, newKeySz, NULL); + ret = Base64_Decode((byte*)in, inSz, newKey, &newKeySz); + if (ret == 0) { + ret = IdentifyOpenSshKey(newKey, newKeySz, heap); if (ret > 0) { - newKeySz = (word32)ret; + *outSz = newKeySz; + *outType = (const byte*)IdToName(ret); + *outTypeSz = (word32)WSTRLEN((const char*)*outType); ret = WS_SUCCESS; } else { - WLOG(WS_LOG_DEBUG, "Base64 decode of public key failed."); - ret = WS_PARSE_E; + WLOG(WS_LOG_DEBUG, "unable to identify key"); } + } - if (ret == WS_SUCCESS) { - ret = IdentifyKey(newKey, newKeySz, 1, heap); - if (ret > 0) { - *outSz = newKeySz; - *outType = (const byte*)IdToName(ret); - *outTypeSz = (word32)WSTRLEN((const char*)*outType); - ret = WS_SUCCESS; - } - else { - WLOG(WS_LOG_DEBUG, "unable to identify key"); - } - } + return ret; +} + + +/* Reads a key from the buffer in to out. If the out buffer doesn't exist + it is created. The type of key is stored in outType. It'll be a pointer + to a constant string. Format indicates the format of the key, currently + either SSH format (a public key) or ASN.1 in DER or PEM format (a + private key). */ +int wolfSSH_ReadKey_buffer(const byte* in, word32 inSz, int format, + byte** out, word32* outSz, const byte** outType, word32* outTypeSz, + void* heap) +{ + int ret = WS_SUCCESS; + + if (in == NULL || inSz == 0 || out == NULL || outSz == NULL || + outType == NULL || outTypeSz == NULL) + return WS_BAD_ARGUMENT; + + if (format == WOLFSSH_FORMAT_SSH) { + ret = DoSshPubKey(in, inSz, out, outSz, outType, outTypeSz, heap); + } + else if (format == WOLFSSH_FORMAT_ASN1) { + ret = DoAsn1Key(in, inSz, out, outSz, outType, outTypeSz, heap); + } + else if (format == WOLFSSH_FORMAT_PEM) { + ret = DoPemKey(in, inSz, out, outSz, outType, outTypeSz, heap); + } + else if (format == WOLFSSH_FORMAT_OPENSSH) { + ret = DoOpenSshKey(in, inSz, out, outSz, outType, outTypeSz, heap); } else { WLOG(WS_LOG_DEBUG, "Invalid key format"); @@ -1687,9 +1779,13 @@ int wolfSSH_ReadKey_file(const char* name, format = WOLFSSH_FORMAT_SSH; in[inSz] = 0; } - else if ((WSTRNSTR((const char*)in, "-----BEGIN ", inSz) + else if (WSTRNSTR((const char*)in, PrivBeginOpenSSH, inSz) != NULL) { + *isPrivate = 1; + format = WOLFSSH_FORMAT_OPENSSH; + } + else if ((WSTRNSTR((const char*)in, PrivBeginPrefix, inSz) == (const char*)in) - && (WSTRNSTR((const char*)in, "PRIVATE KEY-----", inSz) + && (WSTRNSTR((const char*)in, PrivSuffix, inSz) != NULL)) { *isPrivate = 1; format = WOLFSSH_FORMAT_PEM; diff --git a/wolfssh/internal.h b/wolfssh/internal.h index b7650cbeb..2c411c076 100644 --- a/wolfssh/internal.h +++ b/wolfssh/internal.h @@ -347,6 +347,10 @@ enum { ID_EXTINFO_SERVER_SIG_ALGS, + ID_CURVE_NISTP256, + ID_CURVE_NISTP384, + ID_CURVE_NISTP521, + ID_UNKNOWN }; @@ -855,8 +859,9 @@ WOLFSSH_LOCAL void ChannelDelete(WOLFSSH_CHANNEL*, void*); WOLFSSH_LOCAL WOLFSSH_CHANNEL* ChannelFind(WOLFSSH*, word32, byte); WOLFSSH_LOCAL int ChannelRemove(WOLFSSH*, word32, byte); WOLFSSH_LOCAL int ChannelPutData(WOLFSSH_CHANNEL*, byte*, word32); -WOLFSSH_LOCAL int IdentifyKey(const byte* in, word32 inSz, +WOLFSSH_LOCAL int IdentifyAsn1Key(const byte* in, word32 inSz, int isPrivate, void* heap); +WOLFSSH_LOCAL int IdentifyOpenSshKey(const byte* in, word32 inSz, void* heap); WOLFSSH_LOCAL int wolfSSH_ProcessBuffer(WOLFSSH_CTX*, const byte*, word32, int, int); @@ -869,6 +874,7 @@ WOLFSSH_LOCAL int GetUint32(word32* v, const byte* buf, word32 len, word32* idx); WOLFSSH_LOCAL int GetSize(word32* v, const byte* buf, word32 len, word32* idx); +WOLFSSH_LOCAL int GetSkip(const byte* buf, word32 len, word32* idx); WOLFSSH_LOCAL int GetMpint(word32* mpintSz, const byte** mpint, const byte* buf, word32 len, word32* idx); WOLFSSH_LOCAL int GetString(char* s, word32* sSz, diff --git a/wolfssh/ssh.h b/wolfssh/ssh.h index 492ab5dd4..ab315daad 100644 --- a/wolfssh/ssh.h +++ b/wolfssh/ssh.h @@ -311,6 +311,7 @@ enum WS_FormatTypes { WOLFSSH_FORMAT_PEM, WOLFSSH_FORMAT_RAW, WOLFSSH_FORMAT_SSH, + WOLFSSH_FORMAT_OPENSSH }; From 732aba4bc6a0d7d694f01758b2086749d688a715 Mon Sep 17 00:00:00 2001 From: John Safranek Date: Mon, 16 Oct 2023 16:29:17 -0700 Subject: [PATCH 2/9] wolfSSH Client with OpenSSH-format Keys 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. --- src/internal.c | 155 +++++++++++++++++++++++++++++------------------- src/ssh.c | 5 +- wolfssh/error.h | 4 +- wolfssh/port.h | 2 +- 4 files changed, 100 insertions(+), 66 deletions(-) diff --git a/src/internal.c b/src/internal.c index 0f4407d01..00f4eb498 100644 --- a/src/internal.c +++ b/src/internal.c @@ -419,6 +419,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"; } @@ -1041,8 +1047,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 */ @@ -1074,8 +1080,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 */ @@ -1094,72 +1100,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. */ + } + } } } } @@ -1599,9 +1633,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; } @@ -11305,6 +11336,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); @@ -11314,6 +11346,7 @@ static int PrepareUserAuthRequestEcc(WOLFSSH* ssh, word32* payloadSz, authData->sf.publicKey.privateKey, authData->sf.publicKey.privateKeySz, &idx); } + } } if (ret == WS_SUCCESS) { diff --git a/src/ssh.c b/src/ssh.c index 738d54d1f..80535ddc5 100644 --- a/src/ssh.c +++ b/src/ssh.c @@ -1594,11 +1594,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) { @@ -1666,7 +1665,7 @@ static int DoOpenSshKey(const byte* in, word32 inSz, byte** out, } in += strlen(PrivBeginOpenSSH); - inSz -= (strlen(PrivBeginOpenSSH) + strlen(PrivEndOpenSSH) + 2); + inSz -= (word32)(strlen(PrivBeginOpenSSH) + strlen(PrivEndOpenSSH) + 2); ret = Base64_Decode((byte*)in, inSz, newKey, &newKeySz); if (ret == 0) { diff --git a/wolfssh/error.h b/wolfssh/error.h index d964b7ac3..10ed54d3e 100644 --- a/wolfssh/error.h +++ b/wolfssh/error.h @@ -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 */ }; diff --git a/wolfssh/port.h b/wolfssh/port.h index 241fa5c5f..a0bfbc282 100644 --- a/wolfssh/port.h +++ b/wolfssh/port.h @@ -1390,7 +1390,7 @@ extern "C" { #ifndef WOLFSSH_UNUSED - #define WOLFSSH_UNUSED(arg) (void)(arg); + #define WOLFSSH_UNUSED(arg) (void)(arg) #endif From 9bbfcf1a96c15c576416a61d5cc5388ca96c1ebc Mon Sep 17 00:00:00 2001 From: John Safranek Date: Wed, 1 Nov 2023 17:07:43 -0700 Subject: [PATCH 3/9] PR review: Update some std-C functions with the proper porting wrappers. --- src/internal.c | 11 ++++++----- src/ssh.c | 4 ++-- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/internal.c b/src/internal.c index 00f4eb498..863847f14 100644 --- a/src/internal.c +++ b/src/internal.c @@ -891,6 +891,7 @@ static int wolfSSH_KEY_init(WS_KeySignature* key, byte keyId, void* heap) int ret = WS_SUCCESS; if (key != NULL) { + WMEMSET(key, 0, sizeof(*key)); key->keySigId = keyId; switch (keyId) { @@ -1104,12 +1105,12 @@ static int GetOpenSshKey(WS_KeySignature *key, word32 keyCount = 0, strSz = 0, i; int ret = WS_SUCCESS; - if (strcmp(AuthMagic, (const char*)buf) != 0) { + if (WSTRCMP(AuthMagic, (const char*)buf) != 0) { ret = WS_KEY_AUTH_MAGIC_E; } if (ret == WS_SUCCESS) { - *idx += (word32)strlen(AuthMagic) + 1; + *idx += (word32)WSTRLEN(AuthMagic) + 1; ret = GetSkip(buf, len, idx); /* ciphername */ } @@ -9138,7 +9139,7 @@ static int SendKexGetSigningKey(WOLFSSH* ssh, sigKeyBlock_ptr->sk.ecc.primeName = PrimeNameForId(ssh->handshake->pubKeyId); sigKeyBlock_ptr->sk.ecc.primeNameSz = - (word32)strlen(sigKeyBlock_ptr->sk.ecc.primeName); + (word32)WSTRLEN(sigKeyBlock_ptr->sk.ecc.primeName); /* Decode the user-configured ECDSA private key. */ sigKeyBlock_ptr->sk.ecc.qSz = @@ -9428,7 +9429,7 @@ int SendKexDhReply(WOLFSSH* ssh) sigKeyBlock_ptr->pubKeyName = IdToName(SigTypeForId(sigKeyBlock_ptr->pubKeyId)); sigKeyBlock_ptr->pubKeyNameSz = - (word32)strlen(sigKeyBlock_ptr->pubKeyName); + (word32)WSTRLEN(sigKeyBlock_ptr->pubKeyName); sigKeyBlock_ptr->pubKeyFmtId = sigKeyBlock_ptr->pubKeyId; if (sigKeyBlock_ptr->pubKeyId == ID_RSA_SHA2_256 || sigKeyBlock_ptr->pubKeyId == ID_RSA_SHA2_512) { @@ -9437,7 +9438,7 @@ int SendKexDhReply(WOLFSSH* ssh) sigKeyBlock_ptr->pubKeyFmtName = IdToName(sigKeyBlock_ptr->pubKeyFmtId); sigKeyBlock_ptr->pubKeyFmtNameSz = - (word32)strlen(sigKeyBlock_ptr->pubKeyFmtName); + (word32)WSTRLEN(sigKeyBlock_ptr->pubKeyFmtName); switch (ssh->handshake->kexId) { #ifndef WOLFSSH_NO_ECDH_SHA2_NISTP256 diff --git a/src/ssh.c b/src/ssh.c index 80535ddc5..b5b6171a8 100644 --- a/src/ssh.c +++ b/src/ssh.c @@ -1664,8 +1664,8 @@ static int DoOpenSshKey(const byte* in, word32 inSz, byte** out, newKey = *out; } - in += strlen(PrivBeginOpenSSH); - inSz -= (word32)(strlen(PrivBeginOpenSSH) + strlen(PrivEndOpenSSH) + 2); + in += WSTRLEN(PrivBeginOpenSSH); + inSz -= (word32)(WSTRLEN(PrivBeginOpenSSH) + WSTRLEN(PrivEndOpenSSH) + 2); ret = Base64_Decode((byte*)in, inSz, newKey, &newKeySz); if (ret == 0) { From 8049606f2e6e774c2aac3ba10e75a4cfd475b873 Mon Sep 17 00:00:00 2001 From: John Safranek Date: Thu, 2 Nov 2023 15:57:11 -0700 Subject: [PATCH 4/9] PR review: Fix potential memory leak when failing to parse a key of any type. --- src/ssh.c | 136 ++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 91 insertions(+), 45 deletions(-) diff --git a/src/ssh.c b/src/ssh.c index b5b6171a8..1ad8c5c6f 100644 --- a/src/ssh.c +++ b/src/ssh.c @@ -1497,12 +1497,13 @@ static int DoSshPubKey(const byte* in, word32 inSz, byte** out, word32* outSz, const byte** outType, word32* outTypeSz, void* heap) { - int ret = WS_SUCCESS; byte* newKey = NULL; char* c; char* last; char* type = NULL; char* key = NULL; + int ret = WS_SUCCESS; + word32 newKeySz, typeSz; WOLFSSH_UNUSED(inSz); WOLFSSH_UNUSED(heap); @@ -1512,38 +1513,60 @@ static int DoSshPubKey(const byte* in, word32 inSz, byte** out, type AAAABASE64ENCODEDKEYDATA comment */ c = WSTRDUP((const char*)in, heap, DYNTYPE_STRING); - type = WSTRTOK(c, " \n", &last); - key = WSTRTOK(NULL, " \n", &last); + if (c != NULL) { + type = WSTRTOK(c, " \n", &last); + key = WSTRTOK(NULL, " \n", &last); + } + else { + ret = WS_MEMORY_E; + } - if (type != NULL && key != NULL) { - const char* name; - word32 typeSz; - byte nameId; + if (ret == WS_SUCCESS) { + if (type == NULL || key == NULL) { + ret = WS_PARSE_E; + } + } + if (ret == WS_SUCCESS) { typeSz = (word32)WSTRLEN(type); - - nameId = NameToId(type, typeSz); - name = IdToName(nameId); - *outType = (const byte*)name; - *outTypeSz = typeSz; - + /* set size based on sanity check in wolfSSL base64 decode + * function */ + newKeySz = ((word32)WSTRLEN(key) * 3 + 3) / 4; if (*out == NULL) { - /* set size based on sanity check in wolfSSL base64 decode - * function */ - *outSz = ((word32)WSTRLEN(key) * 3 + 3) / 4; newKey = (byte*)WMALLOC(*outSz, heap, DYNTYPE_PRIVKEY); if (newKey == NULL) { - return WS_MEMORY_E; + ret = WS_MEMORY_E; + } + } + else { + if (*outSz < newKeySz) { + WLOG(WS_LOG_DEBUG, "PEM private key output size too small"); + ret = WS_BUFFER_E; + } + else { + newKey = *out; } - *out = newKey; } - - ret = Base64_Decode((byte*)key, (word32)WSTRLEN(key), *out, outSz); } - if (ret != 0) { - WLOG(WS_LOG_DEBUG, "Base64 decode of public key failed."); - ret = WS_PARSE_E; + if (ret == WS_SUCCESS) { + ret = Base64_Decode((byte*)key, (word32)WSTRLEN(key), + newKey, &newKeySz); + + if (ret == 0) { + *out = newKey; + *outSz = newKeySz; + *outType = (const byte *)IdToName(NameToId(type, typeSz)); + *outTypeSz = (word32)WSTRLEN((const char*)*outType); + ret = WS_SUCCESS; + } + else { + WLOG(WS_LOG_DEBUG, "Base64 decode of public key failed."); + if (*out == NULL) { + WFREE(newKey, heap, DYNTYPE_PRIVKEY); + } + ret = WS_PARSE_E; + } } WFREE(c, heap, DYNTYPE_STRING); @@ -1565,7 +1588,6 @@ static int DoAsn1Key(const byte* in, word32 inSz, byte** out, if (newKey == NULL) { return WS_MEMORY_E; } - *out = newKey; } else { if (*outSz < inSz) { @@ -1574,15 +1596,23 @@ static int DoAsn1Key(const byte* in, word32 inSz, byte** out, } newKey = *out; } - *outSz = inSz; - WMEMCPY(newKey, in, inSz); ret = IdentifyAsn1Key(in, inSz, 1, heap); + if (ret > 0) { + *out = newKey; + *outSz = inSz; + WMEMCPY(newKey, in, inSz); *outType = (const byte*)IdToName(ret); *outTypeSz = (word32)WSTRLEN((const char*)*outType); ret = WS_SUCCESS; } + else { + WLOG(WS_LOG_DEBUG, "unable to identify key"); + if (*out == NULL) { + WFREE(newKey, heap, DYNTYPE_PRIVKEY); + } + } return ret; } @@ -1599,11 +1629,10 @@ static int DoPemKey(const byte* in, word32 inSz, byte** out, WOLFSSH_UNUSED(heap); if (*out == NULL) { - newKey = (byte*)WMALLOC(newKeySz, heap, DYNTYPE_PRIVKEY); + newKey = (byte*)WMALLOC(inSz, heap, DYNTYPE_PRIVKEY); if (newKey == NULL) { return WS_MEMORY_E; } - *out = newKey; } else { if (*outSz < inSz) { @@ -1626,14 +1655,19 @@ static int DoPemKey(const byte* in, word32 inSz, byte** out, if (ret == WS_SUCCESS) { ret = IdentifyAsn1Key(newKey, newKeySz, 1, heap); - if (ret > 0) { - *outSz = newKeySz; - *outType = (const byte*)IdToName(ret); - *outTypeSz = (word32)WSTRLEN((const char*)*outType); - ret = WS_SUCCESS; - } - else { - WLOG(WS_LOG_DEBUG, "unable to identify key"); + } + + if (ret > 0) { + *out = newKey; + *outSz = newKeySz; + *outType = (const byte*)IdToName(ret); + *outTypeSz = (word32)WSTRLEN((const char*)*outType); + ret = WS_SUCCESS; + } + else { + WLOG(WS_LOG_DEBUG, "unable to identify key"); + if (*out == NULL) { + WFREE(newKey, heap, DYNTYPE_PRIVKEY); } } @@ -1654,7 +1688,6 @@ static int DoOpenSshKey(const byte* in, word32 inSz, byte** out, if (newKey == NULL) { return WS_MEMORY_E; } - *out = newKey; } else { if (*outSz < inSz) { @@ -1669,15 +1702,28 @@ static int DoOpenSshKey(const byte* in, word32 inSz, byte** out, ret = Base64_Decode((byte*)in, inSz, newKey, &newKeySz); if (ret == 0) { + ret = WS_SUCCESS; + } + else { + WLOG(WS_LOG_DEBUG, "Base64 decode of public key failed."); + ret = WS_PARSE_E; + } + + if (ret == WS_SUCCESS) { ret = IdentifyOpenSshKey(newKey, newKeySz, heap); - if (ret > 0) { - *outSz = newKeySz; - *outType = (const byte*)IdToName(ret); - *outTypeSz = (word32)WSTRLEN((const char*)*outType); - ret = WS_SUCCESS; - } - else { - WLOG(WS_LOG_DEBUG, "unable to identify key"); + } + + if (ret > 0) { + *out = newKey; + *outSz = newKeySz; + *outType = (const byte*)IdToName(ret); + *outTypeSz = (word32)WSTRLEN((const char*)*outType); + ret = WS_SUCCESS; + } + else { + WLOG(WS_LOG_DEBUG, "unable to identify key"); + if (*out == NULL) { + WFREE(newKey, heap, DYNTYPE_PRIVKEY); } } From 3b443c01fc8abb58c45af4f11e46135e8e7b716d Mon Sep 17 00:00:00 2001 From: John Safranek Date: Fri, 3 Nov 2023 10:19:07 -0700 Subject: [PATCH 5/9] PR Review 1. Add better error checking to the OpenSSH key code. 2. Add a couple heaps that were missing. --- src/internal.c | 119 ++++++++++++++++++++++++++++++++++++------------- 1 file changed, 87 insertions(+), 32 deletions(-) diff --git a/src/internal.c b/src/internal.c index 863847f14..b9e33888b 100644 --- a/src/internal.c +++ b/src/internal.c @@ -897,7 +897,7 @@ static int wolfSSH_KEY_init(WS_KeySignature* key, byte keyId, void* heap) switch (keyId) { #ifndef WOLFSSH_NO_RSA case ID_SSH_RSA: - ret = wc_InitRsaKey(&key->ks.rsa.key, NULL); + ret = wc_InitRsaKey(&key->ks.rsa.key, heap); break; #endif #ifndef WOLFSSH_NO_ECDSA @@ -1045,39 +1045,84 @@ int IdentifyAsn1Key(const byte* in, word32 inSz, int isPrivate, void* heap) } -static int GetOpenSshKeyRsa(RsaKey* key, +/* + * Utility function to read an Mpint from the stream directly into a mp_int. + */ +static INLINE int GetMpintToMp(mp_int* mp, const byte* buf, word32 len, word32* idx) { const byte* val = NULL; word32 valSz = 0; + int ret; + + ret = GetMpint(&valSz, &val, buf, len, idx); + if (ret == WS_SUCCESS) + ret = mp_read_unsigned_bin(mp, val, valSz); + + return ret; +} + + +/* + * For the given RSA key, calculate p^-1 and q^-1. wolfCrypt's RSA + * code expects them, but the OpenSSH format key doesn't store them. + * TODO: Add a RSA read function to wolfCrypt to handle this condition. + */ +static INLINE int CalcRsaInverses(RsaKey* key) +{ mp_int m; + int ret; + + ret = mp_init(&m); + if (ret == MP_OKAY) { + ret = mp_sub_d(&key->p, 1, &m); + if (ret == MP_OKAY) + ret = mp_mod(&key->d, &m, &key->dP); + if (ret == MP_OKAY) + ret = mp_sub_d(&key->q, 1, &m); + if (ret == MP_OKAY) + ret = mp_mod(&key->d, &m, &key->dQ); + mp_forcezero(&m); + } + + return ret; +} + + +/* + * Utility for GetOpenSshKey() to read in RSA keys. + */ +static int GetOpenSshKeyRsa(RsaKey* key, + const byte* buf, word32 len, word32* idx) +{ + int ret; - GetMpint(&valSz, &val, buf, len, idx); /* n */ - mp_read_unsigned_bin(&key->n, val, valSz); - GetMpint(&valSz, &val, buf, len, idx); /* e */ - mp_read_unsigned_bin(&key->e, val, valSz); - GetMpint(&valSz, &val, buf, len, idx); /* d */ - mp_read_unsigned_bin(&key->d, val, valSz); - GetMpint(&valSz, &val, buf, len, idx); /* iqmp */ - mp_read_unsigned_bin(&key->u, val, valSz); - GetMpint(&valSz, &val, buf, len, idx); /* p */ - mp_read_unsigned_bin(&key->p, val, valSz); - GetMpint(&valSz, &val, buf, len, idx); /* q */ - mp_read_unsigned_bin(&key->q, val, valSz); + ret = GetMpintToMp(&key->n, buf, len, idx); + if (ret == WS_SUCCESS) + ret = GetMpintToMp(&key->e, buf, len, idx); + if (ret == WS_SUCCESS) + ret = GetMpintToMp(&key->d, buf, len, idx); + if (ret == WS_SUCCESS) + ret = GetMpintToMp(&key->u, buf, len, idx); + if (ret == WS_SUCCESS) + ret = GetMpintToMp(&key->p, buf, len, idx); + if (ret == WS_SUCCESS) + ret = GetMpintToMp(&key->q, buf, len, idx); /* Calculate dP and dQ for wolfCrypt. */ - mp_init(&m); - mp_sub_d(&key->p, 1, &m); - mp_mod(&key->d, &m, &key->dP); - mp_sub_d(&key->q, 1, &m); - mp_mod(&key->d, &m, &key->dQ); - mp_forcezero(&m); - mp_free(&m); + if (ret == WS_SUCCESS) + ret = CalcRsaInverses(key); + + if (ret != WS_SUCCESS) + ret = WS_RSA_E; - return 0; + return ret; } +/* + * Utility for GetOpenSshKey() to read in ECDSA keys. + */ static int GetOpenSshKeyEcc(ecc_key* key, const byte* buf, word32 len, word32* idx) { @@ -1085,18 +1130,26 @@ static int GetOpenSshKeyEcc(ecc_key* key, word32 nameSz = 0, privSz = 0, pubSz = 0; int ret; - GetStringRef(&nameSz, &name, buf, len, idx); /* curve name */ - GetStringRef(&pubSz, &pub, buf, len, idx); /* Q */ - GetMpint(&privSz, &priv, buf, len, idx); /* d */ + ret = GetStringRef(&nameSz, &name, buf, len, idx); /* curve name */ + if (ret == WS_SUCCESS) + ret = GetStringRef(&pubSz, &pub, buf, len, idx); /* Q */ + if (ret == WS_SUCCESS) + ret = GetMpint(&privSz, &priv, buf, len, idx); /* d */ - ret = wc_ecc_import_private_key_ex(priv, privSz, pub, pubSz, - key, ECC_CURVE_DEF); + if (ret == WS_SUCCESS) + ret = wc_ecc_import_private_key_ex(priv, privSz, pub, pubSz, + key, ECC_CURVE_DEF); - return ret != 0; -} + if (ret != WS_SUCCESS) + ret = WS_ECC_E; + return ret; +} +/* + * Decodes an OpenSSH format key. + */ static int GetOpenSshKey(WS_KeySignature *key, const byte* buf, word32 len, word32* idx) { @@ -1155,17 +1208,19 @@ static int GetOpenSshKey(WS_KeySignature *key, str, strSz, &subIdx); if (ret == WS_SUCCESS) { keyId = NameToId((const char*)subStr, subStrSz); - wolfSSH_KEY_init(key, keyId, NULL); + ret = wolfSSH_KEY_init(key, keyId, NULL); + } + if (ret == WS_SUCCESS) { switch (keyId) { #ifndef WOLFSSH_NO_RSA case ID_SSH_RSA: - GetOpenSshKeyRsa(&key->ks.rsa.key, + ret = GetOpenSshKeyRsa(&key->ks.rsa.key, str, strSz, &subIdx); break; #endif #ifndef WOLFSSH_NO_ECDSA case ID_ECDSA_SHA2_NISTP256: - GetOpenSshKeyEcc(&key->ks.ecc.key, + ret = GetOpenSshKeyEcc(&key->ks.ecc.key, str, strSz, &subIdx); break; #endif From 23a9bb82a0518037c6d84d9a1f3dce7859d38f69 Mon Sep 17 00:00:00 2001 From: John Safranek Date: Fri, 3 Nov 2023 14:24:28 -0700 Subject: [PATCH 6/9] PR Review 1. Change the block size in the key decoding to a named constant rather than a bare number. 2. Change the comparison from a difference of two unsigned values against zero to comparing them directly. --- src/internal.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/internal.c b/src/internal.c index b9e33888b..00ccf8779 100644 --- a/src/internal.c +++ b/src/internal.c @@ -1239,8 +1239,8 @@ static int GetOpenSshKey(WS_KeySignature *key, * 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) { + if (strSz % MIN_BLOCK_SZ == 0) { + if (strSz > subIdx) { /* The padding starts at 1. */ check2 = strSz - subIdx; for (check1 = 1; From 707104ee3a290bcfec89d041e8e34f006a12167e Mon Sep 17 00:00:00 2001 From: John Safranek Date: Fri, 3 Nov 2023 14:58:54 -0700 Subject: [PATCH 7/9] PR Review: Remove unused struct members from WS_KeySignature. --- src/internal.c | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/src/internal.c b/src/internal.c index 00ccf8779..04fac03bb 100644 --- a/src/internal.c +++ b/src/internal.c @@ -861,25 +861,11 @@ typedef struct WS_KeySignature { #ifndef WOLFSSH_NO_RSA struct { RsaKey key; - byte e[256]; - word32 eSz; - byte ePad; - byte n[256]; - word32 nSz; - byte nPad; } rsa; #endif #ifndef WOLFSSH_NO_ECDSA struct { ecc_key key; - word32 keyBlobSz; - const char *keyBlobName; - word32 keyBlobNameSz; - byte q[256]; - word32 qSz; - byte qPad; - const char *primeName; - word32 primeNameSz; } ecc; #endif } ks; From dba9a6c36c200ddffab8e6ec6f41801369eba86e Mon Sep 17 00:00:00 2001 From: John Safranek Date: Mon, 6 Nov 2023 15:16:39 -0800 Subject: [PATCH 8/9] PR Review 1. Add test keys. 2. Add API test for wolfSSH_ReadKey_buffer(). 3. Fix allocation issue found using the API test. --- keys/id_ecdsa | 9 +++ keys/id_ecdsa.pub | 1 + keys/id_rsa | 27 +++++++ keys/id_rsa.pub | 1 + keys/include.am | 1 + src/ssh.c | 2 +- tests/api.c | 198 ++++++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 238 insertions(+), 1 deletion(-) create mode 100644 keys/id_ecdsa create mode 100644 keys/id_ecdsa.pub create mode 100644 keys/id_rsa create mode 100644 keys/id_rsa.pub diff --git a/keys/id_ecdsa b/keys/id_ecdsa new file mode 100644 index 000000000..a73f1d4fe --- /dev/null +++ b/keys/id_ecdsa @@ -0,0 +1,9 @@ +-----BEGIN OPENSSH PRIVATE KEY----- +b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAaAAAABNlY2RzYS +1zaGEyLW5pc3RwMjU2AAAACG5pc3RwMjU2AAAAQQTAqdBgCp8bYSq2kQQ48/Ud8Iy6Mjnb +/fpB3LfSE/1kx9VaaE4FL3i9Gg2vDV0eLGM3PWksFNPhULxtcYJyjaBjAAAAqJAeleSQHp +XkAAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBMCp0GAKnxthKraR +BDjz9R3wjLoyOdv9+kHct9IT/WTH1VpoTgUveL0aDa8NXR4sYzc9aSwU0+FQvG1xgnKNoG +MAAAAgPrOgktioNqad/wHNC/rt/zVrpNqDnOwg9tNDFMOTwo8AAAANYm9iQGxvY2FsaG9z +dAECAw== +-----END OPENSSH PRIVATE KEY----- diff --git a/keys/id_ecdsa.pub b/keys/id_ecdsa.pub new file mode 100644 index 000000000..22fb1dc32 --- /dev/null +++ b/keys/id_ecdsa.pub @@ -0,0 +1 @@ +ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBMCp0GAKnxthKraRBDjz9R3wjLoyOdv9+kHct9IT/WTH1VpoTgUveL0aDa8NXR4sYzc9aSwU0+FQvG1xgnKNoGM= bob@localhost diff --git a/keys/id_rsa b/keys/id_rsa new file mode 100644 index 000000000..b1cd15885 --- /dev/null +++ b/keys/id_rsa @@ -0,0 +1,27 @@ +-----BEGIN OPENSSH PRIVATE KEY----- +b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABFwAAAAdzc2gtcn +NhAAAAAwEAAQAAAQEAy2cigZDlpBT+X2MJHAoHnfeFf6+LHm6BDkAT8V9ejHA4dY0Aepb6 +NbV6u/oYZlueKPeAZ3GNztR9szoL6FSlMvkd9oqvfoxjTGu71T0981ybJelqqGATGtevHU +6Jko/I0+lgSQFKWQJ7D3Dj2zlZpIXB2Q7xl/i9kFZgaIqFhUHdWO9JMOwCFwoDrhd8v5xk +y1v3OIIZDxiYxVIKbf2J07WbwiSFAxXfiX8TjUBDLFmtqt1AF6LjAyGyaRICXkaGJQ/QJ9 +sX85h9bkiPlGNAtQGQtNUg3tC9GqOkZ9tCKY1Efh/r0zosOA7ufxg6ymLpq1C4LU/4ENGH +kuRPAKvu8wAAA8gztJfmM7SX5gAAAAdzc2gtcnNhAAABAQDLZyKBkOWkFP5fYwkcCged94 +V/r4seboEOQBPxX16McDh1jQB6lvo1tXq7+hhmW54o94BncY3O1H2zOgvoVKUy+R32iq9+ +jGNMa7vVPT3zXJsl6WqoYBMa168dTomSj8jT6WBJAUpZAnsPcOPbOVmkhcHZDvGX+L2QVm +BoioWFQd1Y70kw7AIXCgOuF3y/nGTLW/c4ghkPGJjFUgpt/YnTtZvCJIUDFd+JfxONQEMs +Wa2q3UAXouMDIbJpEgJeRoYlD9An2xfzmH1uSI+UY0C1AZC01SDe0L0ao6Rn20IpjUR+H+ +vTOiw4Du5/GDrKYumrULgtT/gQ0YeS5E8Aq+7zAAAAAwEAAQAAAQEAvbdBiQXkGyn1pHST +/5IfTqia3OCX6td5ChicQUsJvgXBs2rDopQFZmkRxBjd/0K+/0jyfAl/EgZCBBRFHPsuZp +/S4ayzSV6aE6J8vMT1bnLWxwKyl7+csjGwRK6HRKtVzsnjI9TPSrw0mc9ax5PzV6/mgZUd +o/i+nszh+UASj5mYrBGqMiINspzX6YC+qoUHor3rEJOd9p1aO+N5+1fDKiDnlkM5IO0Qsz +GktuwL0fzv9zBnGfnWVJz3CorfP1OW5KCtrDn7BnkQf1eBeVLzq/uoglUjS4DNnVfLA67D +O4ZfwtnoW8Gr2R+KdvnypvHnDeY5X51r5PDgL4+7z47pWQAAAIBNFcAzHHE19ISGN8YRHk +23/r/3zfvzHU68GSKR1Xj/Y4LSdRTpSm3wBrdQ17f5B4V7RVl2CJvoPekTggnBDQlLJ7fU +NU93/nZrY9teYdrNh03buL54VVb5tUM+KN+27zERlTj0/LmYJupN97sZXmlgKsvLbcsnM2 +i7HuQQaFnsIQAAAIEA5wqFVatT9yovt8pS7rAyYUL/cqc50TZ/5Nwfy5uasRyf1BphHwEW +LEimBemVc+VrNwAkt6MFWuloK5ssqb1ubvtRI8Mntd15rRfZtq/foS3J8FJxueXLDWlECy +PmVyfVN1Vv4ZeirBy9BTYLiSuxMes+HYks3HucQhxIN1j8SA0AAACBAOFgRjfWXv1/93Jp +6CCJ5c98MWP+zu1FbLIlklxPb85osZqlazXHNPPEtblC4z+OqRGMCsv2683anU4ZzcTFIk +JS3lzeJ3tdAH4osQ5etKkV4mcdCmeRpjudB9VbaziVhPX02qkPWpM0ckPrgB3hVNUDPz89 +GtJd3mlhyY5IfFL/AAAADWJvYkBsb2NhbGhvc3QBAgMEBQ== +-----END OPENSSH PRIVATE KEY----- diff --git a/keys/id_rsa.pub b/keys/id_rsa.pub new file mode 100644 index 000000000..9cf541905 --- /dev/null +++ b/keys/id_rsa.pub @@ -0,0 +1 @@ +ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDLZyKBkOWkFP5fYwkcCged94V/r4seboEOQBPxX16McDh1jQB6lvo1tXq7+hhmW54o94BncY3O1H2zOgvoVKUy+R32iq9+jGNMa7vVPT3zXJsl6WqoYBMa168dTomSj8jT6WBJAUpZAnsPcOPbOVmkhcHZDvGX+L2QVmBoioWFQd1Y70kw7AIXCgOuF3y/nGTLW/c4ghkPGJjFUgpt/YnTtZvCJIUDFd+JfxONQEMsWa2q3UAXouMDIbJpEgJeRoYlD9An2xfzmH1uSI+UY0C1AZC01SDe0L0ao6Rn20IpjUR+H+vTOiw4Du5/GDrKYumrULgtT/gQ0YeS5E8Aq+7z bob@localhost diff --git a/keys/include.am b/keys/include.am index 5f314bb05..cc2aa720f 100644 --- a/keys/include.am +++ b/keys/include.am @@ -22,5 +22,6 @@ EXTRA_DIST+= \ keys/server-cert.der keys/server-cert.pem \ keys/fred-cert.der keys/fred-cert.pem \ keys/server-key.pem keys/fred-key.der keys/fred-key.pem \ + keys/id_ecdsa keys/id_ecdsa.pub keys/id_rsa keys/id_rsa.pub \ keys/renewcerts.sh keys/renewcerts.cnf diff --git a/src/ssh.c b/src/ssh.c index 1ad8c5c6f..70b5d53d5 100644 --- a/src/ssh.c +++ b/src/ssh.c @@ -1533,7 +1533,7 @@ static int DoSshPubKey(const byte* in, word32 inSz, byte** out, * function */ newKeySz = ((word32)WSTRLEN(key) * 3 + 3) / 4; if (*out == NULL) { - newKey = (byte*)WMALLOC(*outSz, heap, DYNTYPE_PRIVKEY); + newKey = (byte*)WMALLOC(newKeySz, heap, DYNTYPE_PRIVKEY); if (newKey == NULL) { ret = WS_MEMORY_E; } diff --git a/tests/api.c b/tests/api.c index 1e098fdfb..9353c4d2b 100644 --- a/tests/api.c +++ b/tests/api.c @@ -602,6 +602,203 @@ static void test_wolfSSH_CertMan(void) } +#define KEY_BUF_SZ 2048 + +#ifndef WOLFSSH_NO_RSA + +const char id_rsa[] = + "-----BEGIN OPENSSH PRIVATE KEY-----\n" + "b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABFwAAAAdzc2gtcn\n" + "NhAAAAAwEAAQAAAQEAy2cigZDlpBT+X2MJHAoHnfeFf6+LHm6BDkAT8V9ejHA4dY0Aepb6\n" + "NbV6u/oYZlueKPeAZ3GNztR9szoL6FSlMvkd9oqvfoxjTGu71T0981ybJelqqGATGtevHU\n" + "6Jko/I0+lgSQFKWQJ7D3Dj2zlZpIXB2Q7xl/i9kFZgaIqFhUHdWO9JMOwCFwoDrhd8v5xk\n" + "y1v3OIIZDxiYxVIKbf2J07WbwiSFAxXfiX8TjUBDLFmtqt1AF6LjAyGyaRICXkaGJQ/QJ9\n" + "sX85h9bkiPlGNAtQGQtNUg3tC9GqOkZ9tCKY1Efh/r0zosOA7ufxg6ymLpq1C4LU/4ENGH\n" + "kuRPAKvu8wAAA8gztJfmM7SX5gAAAAdzc2gtcnNhAAABAQDLZyKBkOWkFP5fYwkcCged94\n" + "V/r4seboEOQBPxX16McDh1jQB6lvo1tXq7+hhmW54o94BncY3O1H2zOgvoVKUy+R32iq9+\n" + "jGNMa7vVPT3zXJsl6WqoYBMa168dTomSj8jT6WBJAUpZAnsPcOPbOVmkhcHZDvGX+L2QVm\n" + "BoioWFQd1Y70kw7AIXCgOuF3y/nGTLW/c4ghkPGJjFUgpt/YnTtZvCJIUDFd+JfxONQEMs\n" + "Wa2q3UAXouMDIbJpEgJeRoYlD9An2xfzmH1uSI+UY0C1AZC01SDe0L0ao6Rn20IpjUR+H+\n" + "vTOiw4Du5/GDrKYumrULgtT/gQ0YeS5E8Aq+7zAAAAAwEAAQAAAQEAvbdBiQXkGyn1pHST\n" + "/5IfTqia3OCX6td5ChicQUsJvgXBs2rDopQFZmkRxBjd/0K+/0jyfAl/EgZCBBRFHPsuZp\n" + "/S4ayzSV6aE6J8vMT1bnLWxwKyl7+csjGwRK6HRKtVzsnjI9TPSrw0mc9ax5PzV6/mgZUd\n" + "o/i+nszh+UASj5mYrBGqMiINspzX6YC+qoUHor3rEJOd9p1aO+N5+1fDKiDnlkM5IO0Qsz\n" + "GktuwL0fzv9zBnGfnWVJz3CorfP1OW5KCtrDn7BnkQf1eBeVLzq/uoglUjS4DNnVfLA67D\n" + "O4ZfwtnoW8Gr2R+KdvnypvHnDeY5X51r5PDgL4+7z47pWQAAAIBNFcAzHHE19ISGN8YRHk\n" + "23/r/3zfvzHU68GSKR1Xj/Y4LSdRTpSm3wBrdQ17f5B4V7RVl2CJvoPekTggnBDQlLJ7fU\n" + "NU93/nZrY9teYdrNh03buL54VVb5tUM+KN+27zERlTj0/LmYJupN97sZXmlgKsvLbcsnM2\n" + "i7HuQQaFnsIQAAAIEA5wqFVatT9yovt8pS7rAyYUL/cqc50TZ/5Nwfy5uasRyf1BphHwEW\n" + "LEimBemVc+VrNwAkt6MFWuloK5ssqb1ubvtRI8Mntd15rRfZtq/foS3J8FJxueXLDWlECy\n" + "PmVyfVN1Vv4ZeirBy9BTYLiSuxMes+HYks3HucQhxIN1j8SA0AAACBAOFgRjfWXv1/93Jp\n" + "6CCJ5c98MWP+zu1FbLIlklxPb85osZqlazXHNPPEtblC4z+OqRGMCsv2683anU4ZzcTFIk\n" + "JS3lzeJ3tdAH4osQ5etKkV4mcdCmeRpjudB9VbaziVhPX02qkPWpM0ckPrgB3hVNUDPz89\n" + "GtJd3mlhyY5IfFL/AAAADWJvYkBsb2NhbGhvc3QBAgMEBQ==\n" + "-----END OPENSSH PRIVATE KEY-----\n"; + +const char id_rsa_pub[] = + "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDLZyKBkOWkFP5fYwkcCged94V/r4seboEO" + "QBPxX16McDh1jQB6lvo1tXq7+hhmW54o94BncY3O1H2zOgvoVKUy+R32iq9+jGNMa7vVPT3z" + "XJsl6WqoYBMa168dTomSj8jT6WBJAUpZAnsPcOPbOVmkhcHZDvGX+L2QVmBoioWFQd1Y70kw" + "7AIXCgOuF3y/nGTLW/c4ghkPGJjFUgpt/YnTtZvCJIUDFd+JfxONQEMsWa2q3UAXouMDIbJp" + "EgJeRoYlD9An2xfzmH1uSI+UY0C1AZC01SDe0L0ao6Rn20IpjUR+H+vTOiw4Du5/GDrKYumr" + "ULgtT/gQ0YeS5E8Aq+7z bob@localhost\n"; + +#endif /* WOLFSSH_NO_RSA */ + +#ifndef WOLFSSH_NO_ECDSA_SHA2_NISTP256 + +const char id_ecdsa[] = + "-----BEGIN OPENSSH PRIVATE KEY-----\n" + "b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAaAAAABNlY2RzYS\n" + "1zaGEyLW5pc3RwMjU2AAAACG5pc3RwMjU2AAAAQQTAqdBgCp8bYSq2kQQ48/Ud8Iy6Mjnb\n" + "/fpB3LfSE/1kx9VaaE4FL3i9Gg2vDV0eLGM3PWksFNPhULxtcYJyjaBjAAAAqJAeleSQHp\n" + "XkAAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBMCp0GAKnxthKraR\n" + "BDjz9R3wjLoyOdv9+kHct9IT/WTH1VpoTgUveL0aDa8NXR4sYzc9aSwU0+FQvG1xgnKNoG\n" + "MAAAAgPrOgktioNqad/wHNC/rt/zVrpNqDnOwg9tNDFMOTwo8AAAANYm9iQGxvY2FsaG9z\n" + "dAECAw==\n" + "-----END OPENSSH PRIVATE KEY-----\n"; + +const char id_ecdsa_pub[] = + "ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABB" + "BMCp0GAKnxthKraRBDjz9R3wjLoyOdv9+kHct9IT/WTH1VpoTgUveL0aDa8NXR4sYzc9aSwU" + "0+FQvG1xgnKNoGM= bob@localhost\n"; + +#endif /* WOLFSSH_NO_ECDSA_SHA2_NISTP256 */ + +static void test_wolfSSH_ReadKey(void) +{ +#if !defined(WOLFSSH_NO_RSA) || !defined(WOLFSSH_NO_ECDSA_SHA2_NISTP256) + byte *key, *keyCheck, *derKey; + const byte* keyType; + word32 keySz, keyTypeSz, derKeySz; + int ret; +#endif + +#ifndef WOLFSSH_NO_RSA + + /* OpenSSH Format, ssh-rsa, private, need alloc */ + key = NULL; + keySz = 0; + keyType = NULL; + keyTypeSz = 0; + ret = wolfSSH_ReadKey_buffer((const byte*)id_rsa, (word32)WSTRLEN(id_rsa), + WOLFSSH_FORMAT_OPENSSH, &key, &keySz, &keyType, &keyTypeSz, NULL); + AssertIntEQ(ret, WS_SUCCESS); + AssertNotNull(key); + AssertIntGT(keySz, 0); + AssertStrEQ(keyType, "ssh-rsa"); + AssertIntEQ(keyTypeSz, (word32)WSTRLEN("ssh-rsa")); + WFREE(key, NULL, DYNTYPE_FILE); + + /* SSL PEM Format, ssh-rsa, private, need alloc */ + derKey = NULL; + derKeySz = 0; + key = NULL; + keySz = 0; + keyType = NULL; + keyTypeSz = 0; + ret = ConvertHexToBin(serverKeyRsaDer, &derKey, &derKeySz, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL); + AssertIntEQ(ret, 0); + ret = wolfSSH_ReadKey_buffer(derKey, derKeySz, WOLFSSH_FORMAT_ASN1, + &key, &keySz, &keyType, &keyTypeSz, NULL); + AssertIntEQ(ret, WS_SUCCESS); + AssertNotNull(key); + AssertIntGT(keySz, 0); + AssertStrEQ(keyType, "ssh-rsa"); + AssertIntEQ(keyTypeSz, (word32)WSTRLEN("ssh-rsa")); + WFREE(key, NULL, DYNTYPE_FILE); + WFREE(derKey, NULL, 0); + + /* OpenSSH Format, ssh-rsa, public, need alloc */ + key = NULL; + keySz = 0; + keyType = NULL; + keyTypeSz = 0; + ret = wolfSSH_ReadKey_buffer((const byte*)id_rsa_pub, + (word32)WSTRLEN(id_rsa_pub), WOLFSSH_FORMAT_SSH, + &key, &keySz, &keyType, &keyTypeSz, NULL); + AssertIntEQ(ret, WS_SUCCESS); + AssertNotNull(key); + AssertIntGT(keySz, 0); + AssertStrEQ(keyType, "ssh-rsa"); + AssertIntEQ(keyTypeSz, (word32)WSTRLEN("ssh-rsa")); + WFREE(key, NULL, DYNTYPE_FILE); + + /* OpenSSH Format, ssh-rsa, private, no alloc */ + keyCheck = (byte*)WMALLOC(KEY_BUF_SZ, NULL, DYNTYPE_FILE); + AssertNotNull(keyCheck); + key = keyCheck; + keySz = KEY_BUF_SZ; + keyType = NULL; + keyTypeSz = 0; + ret = wolfSSH_ReadKey_buffer((const byte*)id_rsa, (word32)WSTRLEN(id_rsa), + WOLFSSH_FORMAT_OPENSSH, &key, &keySz, &keyType, &keyTypeSz, NULL); + AssertIntEQ(ret, WS_SUCCESS); + AssertTrue(key == keyCheck); + AssertIntGT(keySz, 0); + AssertStrEQ(keyType, "ssh-rsa"); + AssertIntEQ(keyTypeSz, (word32)WSTRLEN("ssh-rsa")); + WFREE(keyCheck, NULL, DYNTYPE_FILE); + +#endif /* WOLFSSH_NO_RSA */ + +#ifndef WOLFSSH_NO_ECDSA_SHA2_NISTP256 + + /* OpenSSH Format, ecdsa-sha2-nistp256, private, need alloc */ + key = NULL; + keySz = 0; + keyType = NULL; + keyTypeSz = 0; + ret = wolfSSH_ReadKey_buffer((const byte*)id_ecdsa, + (word32)WSTRLEN(id_ecdsa), WOLFSSH_FORMAT_OPENSSH, + &key, &keySz, &keyType, &keyTypeSz, NULL); + AssertIntEQ(ret, WS_SUCCESS); + AssertNotNull(key); + AssertIntGT(keySz, 0); + AssertStrEQ(keyType, "ecdsa-sha2-nistp256"); + AssertIntEQ(keyTypeSz, (word32)WSTRLEN("ecdsa-sha2-nistp256")); + WFREE(key, NULL, DYNTYPE_FILE); + + /* SSL DER Format, ecdsa-sha2-nistp256, private, need alloc */ + derKey = NULL; + derKeySz = 0; + key = NULL; + keySz = 0; + keyType = NULL; + keyTypeSz = 0; + ret = ConvertHexToBin(serverKeyEccDer, &derKey, &derKeySz, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL); + AssertIntEQ(ret, WS_SUCCESS); + ret = wolfSSH_ReadKey_buffer(derKey, derKeySz, WOLFSSH_FORMAT_ASN1, + &key, &keySz, &keyType, &keyTypeSz, NULL); + AssertIntEQ(ret, WS_SUCCESS); + AssertNotNull(key); + AssertIntGT(keySz, 0); + AssertStrEQ(keyType, "ecdsa-sha2-nistp256"); + AssertIntEQ(keyTypeSz, (word32)WSTRLEN("ecdsa-sha2-nistp256")); + WFREE(key, NULL, DYNTYPE_FILE); + WFREE(derKey, NULL, 0); + + /* OpenSSH Format, ecdsa-sha2-nistp256, public, need alloc */ + key = NULL; + keySz = 0; + keyType = NULL; + keyTypeSz = 0; + ret = wolfSSH_ReadKey_buffer((const byte*)id_ecdsa_pub, + (word32)WSTRLEN(id_ecdsa_pub), WOLFSSH_FORMAT_SSH, + &key, &keySz, &keyType, &keyTypeSz, NULL); + AssertIntEQ(ret, WS_SUCCESS); + AssertNotNull(key); + AssertIntGT(keySz, 0); + AssertStrEQ(keyType, "ecdsa-sha2-nistp256"); + AssertIntEQ(keyTypeSz, (word32)WSTRLEN("ecdsa-sha2-nistp256")); + WFREE(key, NULL, DYNTYPE_FILE); + +#endif /* WOLFSSH_NO_ECDSA_SHA2_NISTP256 */ +} + + #ifdef WOLFSSH_SCP static int my_ScpRecv(WOLFSSH* ssh, int state, const char* basePath, @@ -1125,6 +1322,7 @@ int wolfSSH_ApiTest(int argc, char** argv) test_wolfSSH_CTX_UsePrivateKey_buffer(); test_wolfSSH_CTX_UseCert_buffer(); test_wolfSSH_CertMan(); + test_wolfSSH_ReadKey(); /* SCP tests */ test_wolfSSH_SCP_CB(); From ec1964dd1c7932944ec7fcfc6e0a821a86296a99 Mon Sep 17 00:00:00 2001 From: John Safranek Date: Thu, 16 Nov 2023 16:33:28 -0800 Subject: [PATCH 9/9] PR Review 1. Rename and move CleanupUserAuthRequestPublicKey() as wolfSSH_KEY_clean(). 2. Restrict the number of keys allowed in an OpenSSH key package to 1. 3. Initialize the Rsa and Ecc keys right before getting them. 4. New error code for an OpenSSH key format error when decoding. --- src/internal.c | 115 ++++++++++++++++----------------------------- src/ssh.c | 4 ++ wolfssh/error.h | 3 +- wolfssh/internal.h | 3 ++ 4 files changed, 50 insertions(+), 75 deletions(-) diff --git a/src/internal.c b/src/internal.c index 04fac03bb..2b722f7d8 100644 --- a/src/internal.c +++ b/src/internal.c @@ -137,6 +137,8 @@ Set when all ECDH algorithms are disabled. Set to disable use of all ECDH algorithms for key agreement. Setting this will force all ECDH key agreement algorithms off. + WOLFSSH_KEY_QUANTITY_REQ + Number of keys required to be in an OpenSSH-style key wrapper. */ static const char sshProtoIdStr[] = "SSH-2.0-wolfSSHv" @@ -425,6 +427,9 @@ const char* GetErrorString(int err) case WS_KEY_CHECK_VAL_E: return "key check value error"; + case WS_KEY_FORMAT_E: + return "key format wrong error"; + default: return "Unknown error code"; } @@ -872,58 +877,22 @@ typedef struct WS_KeySignature { } WS_KeySignature; -static int wolfSSH_KEY_init(WS_KeySignature* key, byte keyId, void* heap) +static void wolfSSH_KEY_clean(WS_KeySignature* key) { - int ret = WS_SUCCESS; - if (key != NULL) { - WMEMSET(key, 0, sizeof(*key)); - key->keySigId = keyId; - - switch (keyId) { + if (key->keySigId == ID_SSH_RSA) { #ifndef WOLFSSH_NO_RSA - case ID_SSH_RSA: - ret = wc_InitRsaKey(&key->ks.rsa.key, heap); - break; -#endif -#ifndef WOLFSSH_NO_ECDSA - case ID_ECDSA_SHA2_NISTP256: - ret = wc_ecc_init_ex(&key->ks.ecc.key, heap, INVALID_DEVID); - break; + wc_FreeRsaKey(&key->ks.rsa.key); #endif - default: - ret = WS_INVALID_ALGO_ID; } - } - - return ret; -} - - -static int wolfSSH_KEY_clean(WS_KeySignature* key) -{ - int ret = WS_SUCCESS; - - if (key != NULL) { - switch (key->keySigId) { -#ifndef WOLFSSH_NO_RSA - case ID_SSH_RSA: - wc_FreeRsaKey(&key->ks.rsa.key); - break; -#endif + else if (key->keySigId == ID_ECDSA_SHA2_NISTP256 || + key->keySigId == ID_ECDSA_SHA2_NISTP384 || + key->keySigId == ID_ECDSA_SHA2_NISTP521) { #ifndef WOLFSSH_NO_ECDSA - case ID_ECDSA_SHA2_NISTP256: - case ID_ECDSA_SHA2_NISTP384: - case ID_ECDSA_SHA2_NISTP521: - wc_ecc_free(&key->ks.ecc.key); - break; + wc_ecc_free(&key->ks.ecc.key); #endif - default: - ret = WS_INVALID_ALGO_ID; } } - - return ret; } @@ -1083,7 +1052,9 @@ static int GetOpenSshKeyRsa(RsaKey* key, { int ret; - ret = GetMpintToMp(&key->n, buf, len, idx); + ret = wc_InitRsaKey(key, NULL); + if (ret == WS_SUCCESS) + ret = GetMpintToMp(&key->n, buf, len, idx); if (ret == WS_SUCCESS) ret = GetMpintToMp(&key->e, buf, len, idx); if (ret == WS_SUCCESS) @@ -1116,7 +1087,9 @@ static int GetOpenSshKeyEcc(ecc_key* key, word32 nameSz = 0, privSz = 0, pubSz = 0; int ret; - ret = GetStringRef(&nameSz, &name, buf, len, idx); /* curve name */ + ret = wc_ecc_init(key); + if (ret == WS_SUCCESS) + ret = GetStringRef(&nameSz, &name, buf, len, idx); /* curve name */ if (ret == WS_SUCCESS) ret = GetStringRef(&pubSz, &pub, buf, len, idx); /* Q */ if (ret == WS_SUCCESS) @@ -1141,7 +1114,7 @@ static int GetOpenSshKey(WS_KeySignature *key, { const char AuthMagic[] = "openssh-key-v1"; const byte* str = NULL; - word32 keyCount = 0, strSz = 0, i; + word32 keyCount = 0, strSz, i; int ret = WS_SUCCESS; if (WSTRCMP(AuthMagic, (const char*)buf) != 0) { @@ -1162,18 +1135,29 @@ static int GetOpenSshKey(WS_KeySignature *key, if (ret == WS_SUCCESS) ret = GetUint32(&keyCount, buf, len, idx); /* key count */ - for (i = 0; i < keyCount; i++) { - if (ret == WS_SUCCESS) - ret = GetStringRef(&strSz, &str, buf, len, idx); /* public buf */ + if (ret == WS_SUCCESS) { + if (keyCount != WOLFSSH_KEY_QUANTITY_REQ) { + ret = WS_KEY_FORMAT_E; + } } - if (keyCount > 0) { - if (ret == WS_SUCCESS) { - ret = GetStringRef(&strSz, &str, buf, len, idx); - /* list of private keys */ + if (ret == WS_SUCCESS) { + strSz = 0; + ret = GetStringRef(&strSz, &str, buf, len, idx); + /* public buf */ + } + + if (ret == WS_SUCCESS) { + strSz = 0; + ret = GetStringRef(&strSz, &str, buf, len, idx); + /* list of private keys */ + + /* If there isn't a private key, the key file is bad. */ + if (ret == WS_SUCCESS && strSz == 0) { + ret = WS_KEY_FORMAT_E; } - if (strSz > 0) { + if (ret == WS_SUCCESS) { const byte* subStr = NULL; word32 subStrSz = 0, subIdx = 0, check1 = 0, check2 = ~0; byte keyId; @@ -1194,7 +1178,7 @@ static int GetOpenSshKey(WS_KeySignature *key, str, strSz, &subIdx); if (ret == WS_SUCCESS) { keyId = NameToId((const char*)subStr, subStrSz); - ret = wolfSSH_KEY_init(key, keyId, NULL); + key->keySigId = keyId; } if (ret == WS_SUCCESS) { switch (keyId) { @@ -1273,7 +1257,7 @@ int IdentifyOpenSshKey(const byte* in, word32 inSz, void* heap) } else { WMEMSET(key, 0, sizeof(*key)); - key->keySigId = ID_UNKNOWN; + key->keySigId = ID_NONE; ret = GetOpenSshKey(key, in, inSz, &idx); @@ -12068,23 +12052,6 @@ static int BuildUserAuthRequestPublicKey(WOLFSSH* ssh, } -static void CleanupUserAuthRequestPublicKey(WS_KeySignature* keySig) -{ - if (keySig != NULL) { - if (keySig->keySigId == ID_SSH_RSA) { -#ifndef WOLFSSH_NO_RSA - wc_FreeRsaKey(&keySig->ks.rsa.key); -#endif - } - else if (keySig->keySigId == ID_ECDSA_SHA2_NISTP256 || - keySig->keySigId == ID_ECDSA_SHA2_NISTP384 || - keySig->keySigId == ID_ECDSA_SHA2_NISTP521) { -#ifndef WOLFSSH_NO_ECDSA - wc_ecc_free(&keySig->ks.ecc.key); -#endif - } - } -} #endif @@ -12234,7 +12201,7 @@ int SendUserAuthRequest(WOLFSSH* ssh, byte authType, int addSig) } if (authId == ID_USERAUTH_PUBLICKEY) - CleanupUserAuthRequestPublicKey(keySig_ptr); + wolfSSH_KEY_clean(keySig_ptr); if (ret == WS_SUCCESS) { ret = wolfSSH_SendPacket(ssh); diff --git a/src/ssh.c b/src/ssh.c index 70b5d53d5..4e3758d72 100644 --- a/src/ssh.c +++ b/src/ssh.c @@ -1824,6 +1824,10 @@ int wolfSSH_ReadKey_file(const char* name, format = WOLFSSH_FORMAT_SSH; in[inSz] = 0; } +#if 0 + else if (WSTRNSTR((const char*)in, PrivBeginOpenSSH, inSz) != NULL && + WSTRNSTR((const char*)in, PrivEndOpenSSH, inSz) != NULL) { +#endif else if (WSTRNSTR((const char*)in, PrivBeginOpenSSH, inSz) != NULL) { *isPrivate = 1; format = WOLFSSH_FORMAT_OPENSSH; diff --git a/wolfssh/error.h b/wolfssh/error.h index 10ed54d3e..598ec1a48 100644 --- a/wolfssh/error.h +++ b/wolfssh/error.h @@ -130,8 +130,9 @@ enum WS_ErrorCodes { 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_KEY_FORMAT_E = -1092, /* OpenSSH key format fail */ - WS_LAST_E = -1091 /* Update this to indicate last error */ + WS_LAST_E = -1092 /* Update this to indicate last error */ }; diff --git a/wolfssh/internal.h b/wolfssh/internal.h index 2c411c076..674f93de2 100644 --- a/wolfssh/internal.h +++ b/wolfssh/internal.h @@ -424,6 +424,9 @@ enum { #ifndef WOLFSSH_MAX_PUB_KEY_ALGO #define WOLFSSH_MAX_PUB_KEY_ALGO (WOLFSSH_MAX_PVT_KEYS + 2) #endif +#ifndef WOLFSSH_KEY_QUANTITY_REQ + #define WOLFSSH_KEY_QUANTITY_REQ 1 +#endif WOLFSSH_LOCAL byte NameToId(const char*, word32); WOLFSSH_LOCAL const char* IdToName(byte);