Merge pull request #604 from ejohnstown/wolfssh-client-2

wolfSSH Client with OpenSSH-format Keys
pull/554/head
JacobBarthelmeh 2023-11-17 10:08:20 -07:00 committed by GitHub
commit b7aaabc898
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 928 additions and 219 deletions

View File

@ -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) {

9
keys/id_ecdsa 100644
View File

@ -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-----

View File

@ -0,0 +1 @@
ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBMCp0GAKnxthKraRBDjz9R3wjLoyOdv9+kHct9IT/WTH1VpoTgUveL0aDa8NXR4sYzc9aSwU0+FQvG1xgnKNoGM= bob@localhost

27
keys/id_rsa 100644
View File

@ -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-----

1
keys/id_rsa.pub 100644
View File

@ -0,0 +1 @@
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDLZyKBkOWkFP5fYwkcCged94V/r4seboEOQBPxX16McDh1jQB6lvo1tXq7+hhmW54o94BncY3O1H2zOgvoVKUy+R32iq9+jGNMa7vVPT3zXJsl6WqoYBMa168dTomSj8jT6WBJAUpZAnsPcOPbOVmkhcHZDvGX+L2QVmBoioWFQd1Y70kw7AIXCgOuF3y/nGTLW/c4ghkPGJjFUgpt/YnTtZvCJIUDFd+JfxONQEMsWa2q3UAXouMDIbJpEgJeRoYlD9An2xfzmH1uSI+UY0C1AZC01SDe0L0ao6Rn20IpjUR+H+vTOiw4Du5/GDrKYumrULgtT/gQ0YeS5E8Aq+7z bob@localhost

View File

@ -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

View File

@ -137,6 +137,8 @@ Flags:
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"
@ -419,6 +421,15 @@ 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";
case WS_KEY_FORMAT_E:
return "key format wrong error";
default:
return "Unknown error code";
}
@ -845,21 +856,51 @@ 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;
} rsa;
#endif
#ifndef WOLFSSH_NO_ECDSA
ecc_key ecc;
struct {
ecc_key key;
} ecc;
#endif
};
} ks;
} WS_KeySignature;
static void wolfSSH_KEY_clean(WS_KeySignature* key)
{
if (key != NULL) {
if (key->keySigId == ID_SSH_RSA) {
#ifndef WOLFSSH_NO_RSA
wc_FreeRsaKey(&key->ks.rsa.key);
#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
wc_ecc_free(&key->ks.ecc.key);
#endif
}
}
}
/*
* 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 +908,369 @@ 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;
}
/*
* 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;
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)
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. */
if (ret == WS_SUCCESS)
ret = CalcRsaInverses(key);
if (ret != WS_SUCCESS)
ret = WS_RSA_E;
return ret;
}
/*
* Utility for GetOpenSshKey() to read in ECDSA keys.
*/
static int GetOpenSshKeyEcc(ecc_key* key,
const byte* buf, word32 len, word32* idx)
{
const byte *name = NULL, *priv = NULL, *pub = NULL;
word32 nameSz = 0, privSz = 0, pubSz = 0;
int ret;
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)
ret = GetMpint(&privSz, &priv, buf, len, idx); /* d */
if (ret == WS_SUCCESS)
ret = wc_ecc_import_private_key_ex(priv, privSz, pub, pubSz,
key, ECC_CURVE_DEF);
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)
{
const char AuthMagic[] = "openssh-key-v1";
const byte* str = NULL;
word32 keyCount = 0, strSz, i;
int ret = WS_SUCCESS;
if (WSTRCMP(AuthMagic, (const char*)buf) != 0) {
ret = WS_KEY_AUTH_MAGIC_E;
}
if (ret == WS_SUCCESS) {
*idx += (word32)WSTRLEN(AuthMagic) + 1;
ret = GetSkip(buf, len, idx); /* ciphername */
}
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 */
if (ret == WS_SUCCESS) {
if (keyCount != WOLFSSH_KEY_QUANTITY_REQ) {
ret = WS_KEY_FORMAT_E;
}
}
#endif /* WOLFSSH_NO_ECDSA */
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 (ret == WS_SUCCESS) {
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;
}
}
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);
key->keySigId = keyId;
}
if (ret == WS_SUCCESS) {
switch (keyId) {
#ifndef WOLFSSH_NO_RSA
case ID_SSH_RSA:
ret = GetOpenSshKeyRsa(&key->ks.rsa.key,
str, strSz, &subIdx);
break;
#endif
#ifndef WOLFSSH_NO_ECDSA
case ID_ECDSA_SHA2_NISTP256:
ret = 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 % MIN_BLOCK_SZ == 0) {
if (strSz > subIdx) {
/* 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_NONE;
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 +1280,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 +1327,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 +1610,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;
@ -1341,7 +1666,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 +2038,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 +2727,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,
@ -8814,7 +9164,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 =
@ -9104,7 +9454,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) {
@ -9113,7 +9463,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
@ -10556,40 +10906,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 +10963,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) {
@ -11037,9 +11362,17 @@ 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);
if (ret != 0) {
idx = 0;
ret = GetOpenSshKey(keySig,
authData->sf.publicKey.privateKey,
authData->sf.publicKey.privateKeySz, &idx);
}
}
}
if (ret == WS_SUCCESS) {
@ -11719,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
@ -11885,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);
@ -13491,7 +13807,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 +13842,6 @@ void DumpOctetString(const byte* input, word32 inputSz)
}
}
#endif
#ifdef WOLFSSH_SFTP

377
src/ssh.c
View File

@ -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,6 +1486,251 @@ union wolfSSH_key {
#endif
};
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)
{
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);
/*
SSH format is:
type AAAABASE64ENCODEDKEYDATA comment
*/
c = WSTRDUP((const char*)in, heap, DYNTYPE_STRING);
if (c != NULL) {
type = WSTRTOK(c, " \n", &last);
key = WSTRTOK(NULL, " \n", &last);
}
else {
ret = WS_MEMORY_E;
}
if (ret == WS_SUCCESS) {
if (type == NULL || key == NULL) {
ret = WS_PARSE_E;
}
}
if (ret == WS_SUCCESS) {
typeSz = (word32)WSTRLEN(type);
/* set size based on sanity check in wolfSSL base64 decode
* function */
newKeySz = ((word32)WSTRLEN(key) * 3 + 3) / 4;
if (*out == NULL) {
newKey = (byte*)WMALLOC(newKeySz, heap, DYNTYPE_PRIVKEY);
if (newKey == NULL) {
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;
}
}
}
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);
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;
}
}
else {
if (*outSz < inSz) {
WLOG(WS_LOG_DEBUG, "DER private key output size too small");
return WS_BUFFER_E;
}
newKey = *out;
}
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;
}
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;
word32 newKeySz = inSz; /* binary will be smaller than PEM */
WOLFSSH_UNUSED(heap);
if (*out == NULL) {
newKey = (byte*)WMALLOC(inSz, 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;
}
/* 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;
}
if (ret == WS_SUCCESS) {
ret = IdentifyAsn1Key(newKey, newKeySz, 1, heap);
}
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);
}
}
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;
}
in += WSTRLEN(PrivBeginOpenSSH);
inSz -= (word32)(WSTRLEN(PrivBeginOpenSSH) + WSTRLEN(PrivEndOpenSSH) + 2);
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) {
*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);
}
}
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
@ -1499,127 +1741,22 @@ int wolfSSH_ReadKey_buffer(const byte* in, word32 inSz, int format,
void* heap)
{
int ret = WS_SUCCESS;
byte* newKey = NULL;
WOLFSSH_UNUSED(heap);
if (in == NULL || inSz == 0 || out == NULL || outSz == NULL ||
outType == NULL || outTypeSz == NULL)
return WS_BAD_ARGUMENT;
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;
}
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);
ret = DoSshPubKey(in, inSz, out, outSz, outType, outTypeSz, heap);
}
else if (format == WOLFSSH_FORMAT_ASN1) {
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 = IdentifyKey(in, inSz, 1, heap);
if (ret > 0) {
*outType = (const byte*)IdToName(ret);
*outTypeSz = (word32)WSTRLEN((const char*)*outType);
ret = WS_SUCCESS;
}
ret = DoAsn1Key(in, inSz, out, outSz, outType, outTypeSz, heap);
}
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;
}
else {
if (*outSz < inSz) {
WLOG(WS_LOG_DEBUG, "PEM private key output size too small");
return WS_BUFFER_E;
}
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;
}
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");
}
}
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 +1824,17 @@ int wolfSSH_ReadKey_file(const char* name,
format = WOLFSSH_FORMAT_SSH;
in[inSz] = 0;
}
else if ((WSTRNSTR((const char*)in, "-----BEGIN ", inSz)
#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;
}
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;

View File

@ -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();

View File

@ -128,8 +128,11 @@ 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_KEY_FORMAT_E = -1092, /* OpenSSH key format fail */
WS_LAST_E = -1089 /* Update this to indicate last error */
WS_LAST_E = -1092 /* Update this to indicate last error */
};

View File

@ -347,6 +347,10 @@ enum {
ID_EXTINFO_SERVER_SIG_ALGS,
ID_CURVE_NISTP256,
ID_CURVE_NISTP384,
ID_CURVE_NISTP521,
ID_UNKNOWN
};
@ -420,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);
@ -855,8 +862,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 +877,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,

View File

@ -1390,7 +1390,7 @@ extern "C" {
#ifndef WOLFSSH_UNUSED
#define WOLFSSH_UNUSED(arg) (void)(arg);
#define WOLFSSH_UNUSED(arg) (void)(arg)
#endif

View File

@ -311,6 +311,7 @@ enum WS_FormatTypes {
WOLFSSH_FORMAT_PEM,
WOLFSSH_FORMAT_RAW,
WOLFSSH_FORMAT_SSH,
WOLFSSH_FORMAT_OPENSSH
};