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); newTerm.c_lflag &= ~(ICANON | ECHOE | ECHOK | ECHONL | ISIG);
} }
else { else {
newTerm.c_lflag |= (ICANON | ECHONL); newTerm.c_lflag |= ICANON;
} }
if (tcsetattr(STDIN_FILENO, TCSANOW, &newTerm) != 0) { 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/server-cert.der keys/server-cert.pem \
keys/fred-cert.der keys/fred-cert.pem \ keys/fred-cert.der keys/fred-cert.pem \
keys/server-key.pem keys/fred-key.der keys/fred-key.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 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 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 for key agreement. Setting this will force all ECDH key agreement
algorithms off. 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" static const char sshProtoIdStr[] = "SSH-2.0-wolfSSHv"
@ -419,6 +421,15 @@ const char* GetErrorString(int err)
case WS_MATCH_UA_KEY_ID_E: case WS_MATCH_UA_KEY_ID_E:
return "unable to match user auth key type"; 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: default:
return "Unknown error code"; return "Unknown error code";
} }
@ -845,21 +856,51 @@ void SshResourceFree(WOLFSSH* ssh, void* heap)
#endif #endif
} }
union wolfSSH_key {
typedef struct WS_KeySignature {
byte keySigId;
word32 sigSz;
const char *name;
word32 nameSz;
union {
#ifndef WOLFSSH_NO_RSA #ifndef WOLFSSH_NO_RSA
RsaKey rsa; struct {
RsaKey key;
} rsa;
#endif #endif
#ifndef WOLFSSH_NO_ECDSA #ifndef WOLFSSH_NO_ECDSA
ecc_key ecc; struct {
ecc_key key;
} ecc;
#endif #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. * Identifies the flavor of an ASN.1 key, RSA or ECDSA, and returns the key
* The process is to decode the key as if it was RSA and if that fails try * type ID. The process is to decode the key as if it was RSA and if that
* to load it as if ECDSA. Both public and private keys can be decoded. * fails try to load it as if ECDSA. Both public and private keys can be
* For RSA keys, the key format is described as "ssh-rsa". * decoded. For RSA keys, the key format is described as "ssh-rsa".
* *
* @param in key to identify * @param in key to identify
* @param inSz size of key * @param inSz size of key
@ -867,88 +908,369 @@ union wolfSSH_key {
* @param heap heap to use for memory allocation * @param heap heap to use for memory allocation
* @return keyId as int, WS_MEMORY_E, WS_UNIMPLEMENTED_E * @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; WS_KeySignature *key = NULL;
int keyId = ID_UNKNOWN;
word32 idx; word32 idx;
int ret; int ret;
int dynType = isPrivate ? DYNTYPE_PRIVKEY : DYNTYPE_PUBKEY; int dynType = isPrivate ? DYNTYPE_PRIVKEY : DYNTYPE_PUBKEY;
WOLFSSH_UNUSED(dynType); 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 #ifndef WOLFSSH_NO_RSA
if (key != NULL) {
/* Check RSA key */ /* Check RSA key */
if (keyId == ID_UNKNOWN) { if (key->keySigId == ID_UNKNOWN) {
idx = 0; idx = 0;
ret = wc_InitRsaKey(&key->rsa, NULL); ret = wc_InitRsaKey(&key->ks.rsa.key, NULL);
if (ret == 0) { if (ret == 0) {
if (isPrivate) { if (isPrivate) {
ret = wc_RsaPrivateKeyDecode(in, &idx, &key->rsa, inSz); ret = wc_RsaPrivateKeyDecode(in, &idx,
&key->ks.rsa.key, inSz);
} }
else { 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 decode was successful, this is an RSA key. */
if (ret == 0) { 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 */ #endif /* WOLFSSH_NO_RSA */
#ifndef WOLFSSH_NO_ECDSA #ifndef WOLFSSH_NO_ECDSA
if (key != NULL) {
/* Check ECDSA key */ /* Check ECDSA key */
if (keyId == ID_UNKNOWN) { if (key->keySigId == ID_UNKNOWN) {
idx = 0; 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 (ret == 0) {
if (isPrivate) { if (isPrivate) {
ret = wc_EccPrivateKeyDecode(in, &idx, &key->ecc, inSz); ret = wc_EccPrivateKeyDecode(in, &idx,
&key->ks.ecc.key, inSz);
} }
else { 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 decode was successful, this is an ECDSA key. */
if (ret == 0) { 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: case ECC_SECP256R1:
keyId = ID_ECDSA_SHA2_NISTP256; key->keySigId = ID_ECDSA_SHA2_NISTP256;
break; break;
case ECC_SECP384R1: case ECC_SECP384R1:
keyId = ID_ECDSA_SHA2_NISTP384; key->keySigId = ID_ECDSA_SHA2_NISTP384;
break; break;
case ECC_SECP521R1: case ECC_SECP521R1:
keyId = ID_ECDSA_SHA2_NISTP521; key->keySigId = ID_ECDSA_SHA2_NISTP521;
break; 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) { if (key == NULL) {
ret = WS_MEMORY_E; ret = WS_MEMORY_E;
} }
else if (keyId == ID_UNKNOWN) {
ret = WS_UNIMPLEMENTED_E;
}
else { 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; 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 * 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 * 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 in certificate to identify
* @param inSz size of certificate * @param inSz size of certificate
@ -1005,7 +1327,7 @@ static int IdentifyCert(const byte* in, word32 inSz, void* heap)
} }
if (ret == 0) { if (ret == 0) {
ret = IdentifyKey(key, keySz, 0, heap); ret = IdentifyAsn1Key(key, keySz, 0, heap);
} }
WFREE(key, heap, DYNTYPE_PUBKEY); WFREE(key, heap, DYNTYPE_PUBKEY);
@ -1288,9 +1610,12 @@ int wolfSSH_ProcessBuffer(WOLFSSH_CTX* ctx,
if (ctx == NULL || in == NULL || inSz == 0) if (ctx == NULL || in == NULL || inSz == 0)
return WS_BAD_ARGUMENT; return WS_BAD_ARGUMENT;
if (format != WOLFSSH_FORMAT_ASN1 && format != WOLFSSH_FORMAT_PEM && if (format != WOLFSSH_FORMAT_ASN1
format != WOLFSSH_FORMAT_RAW) && format != WOLFSSH_FORMAT_PEM
&& format != WOLFSSH_FORMAT_RAW
&& format != WOLFSSH_FORMAT_OPENSSH) {
return WS_BAD_FILETYPE_E; return WS_BAD_FILETYPE_E;
}
if (type == BUFTYPE_CA) { if (type == BUFTYPE_CA) {
dynamicType = DYNTYPE_CA; dynamicType = DYNTYPE_CA;
@ -1341,7 +1666,7 @@ int wolfSSH_ProcessBuffer(WOLFSSH_CTX* ctx,
/* Maybe decrypt */ /* Maybe decrypt */
if (type == BUFTYPE_PRIVKEY) { if (type == BUFTYPE_PRIVKEY) {
ret = IdentifyKey(der, derSz, 1, ctx->heap); ret = IdentifyAsn1Key(der, derSz, 1, ctx->heap);
if (ret < 0) { if (ret < 0) {
WFREE(der, heap, dynamicType); WFREE(der, heap, dynamicType);
return ret; return ret;
@ -1713,6 +2038,11 @@ static const NameIdPair NameIdMap[] = {
/* Ext Info IDs */ /* Ext Info IDs */
{ ID_EXTINFO_SERVER_SIG_ALGS, "server-sig-algs" }, { 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 /* Gets the size of the mpint, and puts the pointer to the start of
* buf's number into *mpint. This function does not copy. */ * buf's number into *mpint. This function does not copy. */
int GetMpint(word32* mpintSz, const byte** mpint, int GetMpint(word32* mpintSz, const byte** mpint,
@ -8814,7 +9164,7 @@ static int SendKexGetSigningKey(WOLFSSH* ssh,
sigKeyBlock_ptr->sk.ecc.primeName = sigKeyBlock_ptr->sk.ecc.primeName =
PrimeNameForId(ssh->handshake->pubKeyId); PrimeNameForId(ssh->handshake->pubKeyId);
sigKeyBlock_ptr->sk.ecc.primeNameSz = 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. */ /* Decode the user-configured ECDSA private key. */
sigKeyBlock_ptr->sk.ecc.qSz = sigKeyBlock_ptr->sk.ecc.qSz =
@ -9104,7 +9454,7 @@ int SendKexDhReply(WOLFSSH* ssh)
sigKeyBlock_ptr->pubKeyName = sigKeyBlock_ptr->pubKeyName =
IdToName(SigTypeForId(sigKeyBlock_ptr->pubKeyId)); IdToName(SigTypeForId(sigKeyBlock_ptr->pubKeyId));
sigKeyBlock_ptr->pubKeyNameSz = sigKeyBlock_ptr->pubKeyNameSz =
(word32)strlen(sigKeyBlock_ptr->pubKeyName); (word32)WSTRLEN(sigKeyBlock_ptr->pubKeyName);
sigKeyBlock_ptr->pubKeyFmtId = sigKeyBlock_ptr->pubKeyId; sigKeyBlock_ptr->pubKeyFmtId = sigKeyBlock_ptr->pubKeyId;
if (sigKeyBlock_ptr->pubKeyId == ID_RSA_SHA2_256 if (sigKeyBlock_ptr->pubKeyId == ID_RSA_SHA2_256
|| sigKeyBlock_ptr->pubKeyId == ID_RSA_SHA2_512) { || sigKeyBlock_ptr->pubKeyId == ID_RSA_SHA2_512) {
@ -9113,7 +9463,7 @@ int SendKexDhReply(WOLFSSH* ssh)
sigKeyBlock_ptr->pubKeyFmtName = sigKeyBlock_ptr->pubKeyFmtName =
IdToName(sigKeyBlock_ptr->pubKeyFmtId); IdToName(sigKeyBlock_ptr->pubKeyFmtId);
sigKeyBlock_ptr->pubKeyFmtNameSz = sigKeyBlock_ptr->pubKeyFmtNameSz =
(word32)strlen(sigKeyBlock_ptr->pubKeyFmtName); (word32)WSTRLEN(sigKeyBlock_ptr->pubKeyFmtName);
switch (ssh->handshake->kexId) { switch (ssh->handshake->kexId) {
#ifndef WOLFSSH_NO_ECDH_SHA2_NISTP256 #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. */ /* Updates the payload size, and maybe loads keys. */
static int PrepareUserAuthRequestPassword(WOLFSSH* ssh, word32* payloadSz, static int PrepareUserAuthRequestPassword(WOLFSSH* ssh, word32* payloadSz,
const WS_UserAuthData* authData) const WS_UserAuthData* authData)
@ -10647,15 +10963,24 @@ static int PrepareUserAuthRequestRsa(WOLFSSH* ssh, word32* payloadSz,
if (ret == WS_SUCCESS) { if (ret == WS_SUCCESS) {
word32 idx = 0; word32 idx = 0;
#ifdef WOLFSSH_AGENT #ifdef WOLFSSH_AGENT
if (ssh->agentEnabled) if (ssh->agentEnabled) {
ret = wc_RsaPublicKeyDecode(authData->sf.publicKey.publicKey, ret = wc_RsaPublicKeyDecode(authData->sf.publicKey.publicKey,
&idx, &keySig->ks.rsa.key, &idx, &keySig->ks.rsa.key,
authData->sf.publicKey.publicKeySz); authData->sf.publicKey.publicKeySz);
}
else else
#endif #endif
{
ret = wc_RsaPrivateKeyDecode(authData->sf.publicKey.privateKey, ret = wc_RsaPrivateKeyDecode(authData->sf.publicKey.privateKey,
&idx, &keySig->ks.rsa.key, &idx, &keySig->ks.rsa.key,
authData->sf.publicKey.privateKeySz); 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) { if (ret == WS_SUCCESS) {
@ -11037,9 +11362,17 @@ static int PrepareUserAuthRequestEcc(WOLFSSH* ssh, word32* payloadSz,
} }
else else
#endif #endif
{
ret = wc_EccPrivateKeyDecode(authData->sf.publicKey.privateKey, ret = wc_EccPrivateKeyDecode(authData->sf.publicKey.privateKey,
&idx, &keySig->ks.ecc.key, &idx, &keySig->ks.ecc.key,
authData->sf.publicKey.privateKeySz); 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) { 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 #endif
@ -11885,7 +12201,7 @@ int SendUserAuthRequest(WOLFSSH* ssh, byte authType, int addSig)
} }
if (authId == ID_USERAUTH_PUBLICKEY) if (authId == ID_USERAUTH_PUBLICKEY)
CleanupUserAuthRequestPublicKey(keySig_ptr); wolfSSH_KEY_clean(keySig_ptr);
if (ret == WS_SUCCESS) { if (ret == WS_SUCCESS) {
ret = wolfSSH_SendPacket(ssh); ret = wolfSSH_SendPacket(ssh);
@ -13491,7 +13807,6 @@ int wolfSSH_CleanPath(WOLFSSH* ssh, char* in)
#endif /* WOLFSSH_SFTP || WOLFSSH_SCP */ #endif /* WOLFSSH_SFTP || WOLFSSH_SCP */
#ifdef DEBUG_WOLFSSH
#define LINE_WIDTH 16 #define LINE_WIDTH 16
void DumpOctetString(const byte* input, word32 inputSz) void DumpOctetString(const byte* input, word32 inputSz)
@ -13527,7 +13842,6 @@ void DumpOctetString(const byte* input, word32 inputSz)
} }
} }
#endif
#ifdef WOLFSSH_SFTP #ifdef WOLFSSH_SFTP

377
src/ssh.c
View File

@ -1323,7 +1323,6 @@ void* wolfSSH_GetPublicKeyCheckCtx(WOLFSSH* ssh)
return NULL; return NULL;
} }
#ifdef WOLFSSH_TERM
#if defined(WOLFSSH_TERM) && !defined(NO_FILESYSTEM) #if defined(WOLFSSH_TERM) && !defined(NO_FILESYSTEM)
/* Used to resize terminal window with shell connections /* Used to resize terminal window with shell connections
@ -1361,8 +1360,6 @@ void wolfSSH_SetTerminalResizeCtx(WOLFSSH* ssh, void* usrCtx)
} }
#endif #endif
#endif
/* Used to set the channel request type sent in wolfSSH connect. The default /* Used to set the channel request type sent in wolfSSH connect. The default
* type set is shell if this function is not called. * type set is shell if this function is not called.
@ -1489,6 +1486,251 @@ union wolfSSH_key {
#endif #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 /* 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 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 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) void* heap)
{ {
int ret = WS_SUCCESS; int ret = WS_SUCCESS;
byte* newKey = NULL;
WOLFSSH_UNUSED(heap);
if (in == NULL || inSz == 0 || out == NULL || outSz == NULL || if (in == NULL || inSz == 0 || out == NULL || outSz == NULL ||
outType == NULL || outTypeSz == NULL) outType == NULL || outTypeSz == NULL)
return WS_BAD_ARGUMENT; return WS_BAD_ARGUMENT;
if (format == WOLFSSH_FORMAT_SSH) { if (format == WOLFSSH_FORMAT_SSH) {
char* c; ret = DoSshPubKey(in, inSz, out, outSz, outType, outTypeSz, heap);
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);
} }
else if (format == WOLFSSH_FORMAT_ASN1) { else if (format == WOLFSSH_FORMAT_ASN1) {
if (*out == NULL) { ret = DoAsn1Key(in, inSz, out, outSz, outType, outTypeSz, heap);
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;
}
} }
else if (format == WOLFSSH_FORMAT_PEM) { else if (format == WOLFSSH_FORMAT_PEM) {
word32 newKeySz = inSz; /* binary will be smaller than PEM */ ret = DoPemKey(in, inSz, out, outSz, outType, outTypeSz, heap);
}
if (*out == NULL) { else if (format == WOLFSSH_FORMAT_OPENSSH) {
newKey = (byte*)WMALLOC(newKeySz, heap, DYNTYPE_PRIVKEY); ret = DoOpenSshKey(in, inSz, out, outSz, outType, outTypeSz, heap);
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");
}
}
} }
else { else {
WLOG(WS_LOG_DEBUG, "Invalid key format"); WLOG(WS_LOG_DEBUG, "Invalid key format");
@ -1687,9 +1824,17 @@ int wolfSSH_ReadKey_file(const char* name,
format = WOLFSSH_FORMAT_SSH; format = WOLFSSH_FORMAT_SSH;
in[inSz] = 0; 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) == (const char*)in)
&& (WSTRNSTR((const char*)in, "PRIVATE KEY-----", inSz) && (WSTRNSTR((const char*)in, PrivSuffix, inSz)
!= NULL)) { != NULL)) {
*isPrivate = 1; *isPrivate = 1;
format = WOLFSSH_FORMAT_PEM; 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 #ifdef WOLFSSH_SCP
static int my_ScpRecv(WOLFSSH* ssh, int state, const char* basePath, 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_UsePrivateKey_buffer();
test_wolfSSH_CTX_UseCert_buffer(); test_wolfSSH_CTX_UseCert_buffer();
test_wolfSSH_CertMan(); test_wolfSSH_CertMan();
test_wolfSSH_ReadKey();
/* SCP tests */ /* SCP tests */
test_wolfSSH_SCP_CB(); test_wolfSSH_SCP_CB();

View File

@ -128,8 +128,11 @@ enum WS_ErrorCodes {
WS_CERT_KEY_SIZE_E = -1087, /* Key size error */ WS_CERT_KEY_SIZE_E = -1087, /* Key size error */
WS_CTX_KEY_COUNT_E = -1088, /* Adding too many private keys */ 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_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_EXTINFO_SERVER_SIG_ALGS,
ID_CURVE_NISTP256,
ID_CURVE_NISTP384,
ID_CURVE_NISTP521,
ID_UNKNOWN ID_UNKNOWN
}; };
@ -420,6 +424,9 @@ enum {
#ifndef WOLFSSH_MAX_PUB_KEY_ALGO #ifndef WOLFSSH_MAX_PUB_KEY_ALGO
#define WOLFSSH_MAX_PUB_KEY_ALGO (WOLFSSH_MAX_PVT_KEYS + 2) #define WOLFSSH_MAX_PUB_KEY_ALGO (WOLFSSH_MAX_PVT_KEYS + 2)
#endif #endif
#ifndef WOLFSSH_KEY_QUANTITY_REQ
#define WOLFSSH_KEY_QUANTITY_REQ 1
#endif
WOLFSSH_LOCAL byte NameToId(const char*, word32); WOLFSSH_LOCAL byte NameToId(const char*, word32);
WOLFSSH_LOCAL const char* IdToName(byte); 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 WOLFSSH_CHANNEL* ChannelFind(WOLFSSH*, word32, byte);
WOLFSSH_LOCAL int ChannelRemove(WOLFSSH*, word32, byte); WOLFSSH_LOCAL int ChannelRemove(WOLFSSH*, word32, byte);
WOLFSSH_LOCAL int ChannelPutData(WOLFSSH_CHANNEL*, byte*, word32); 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); int isPrivate, void* heap);
WOLFSSH_LOCAL int IdentifyOpenSshKey(const byte* in, word32 inSz, void* heap);
WOLFSSH_LOCAL int wolfSSH_ProcessBuffer(WOLFSSH_CTX*, WOLFSSH_LOCAL int wolfSSH_ProcessBuffer(WOLFSSH_CTX*,
const byte*, word32, const byte*, word32,
int, int); int, int);
@ -869,6 +877,7 @@ WOLFSSH_LOCAL int GetUint32(word32* v,
const byte* buf, word32 len, word32* idx); const byte* buf, word32 len, word32* idx);
WOLFSSH_LOCAL int GetSize(word32* v, WOLFSSH_LOCAL int GetSize(word32* v,
const byte* buf, word32 len, word32* idx); 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, WOLFSSH_LOCAL int GetMpint(word32* mpintSz, const byte** mpint,
const byte* buf, word32 len, word32* idx); const byte* buf, word32 len, word32* idx);
WOLFSSH_LOCAL int GetString(char* s, word32* sSz, WOLFSSH_LOCAL int GetString(char* s, word32* sSz,

View File

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

View File

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