mirror of https://github.com/wolfSSL/wolfssh.git
Merge pull request #604 from ejohnstown/wolfssh-client-2
wolfSSH Client with OpenSSH-format Keyspull/554/head
commit
b7aaabc898
|
@ -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) {
|
||||||
|
|
|
@ -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-----
|
|
@ -0,0 +1 @@
|
||||||
|
ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBMCp0GAKnxthKraRBDjz9R3wjLoyOdv9+kHct9IT/WTH1VpoTgUveL0aDa8NXR4sYzc9aSwU0+FQvG1xgnKNoGM= bob@localhost
|
|
@ -0,0 +1,27 @@
|
||||||
|
-----BEGIN OPENSSH PRIVATE KEY-----
|
||||||
|
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
|
||||||
|
-----END OPENSSH PRIVATE KEY-----
|
|
@ -0,0 +1 @@
|
||||||
|
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDLZyKBkOWkFP5fYwkcCged94V/r4seboEOQBPxX16McDh1jQB6lvo1tXq7+hhmW54o94BncY3O1H2zOgvoVKUy+R32iq9+jGNMa7vVPT3zXJsl6WqoYBMa168dTomSj8jT6WBJAUpZAnsPcOPbOVmkhcHZDvGX+L2QVmBoioWFQd1Y70kw7AIXCgOuF3y/nGTLW/c4ghkPGJjFUgpt/YnTtZvCJIUDFd+JfxONQEMsWa2q3UAXouMDIbJpEgJeRoYlD9An2xfzmH1uSI+UY0C1AZC01SDe0L0ao6Rn20IpjUR+H+vTOiw4Du5/GDrKYumrULgtT/gQ0YeS5E8Aq+7z bob@localhost
|
|
@ -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
|
||||||
|
|
||||||
|
|
512
src/internal.c
512
src/internal.c
|
@ -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
377
src/ssh.c
|
@ -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;
|
||||||
|
|
198
tests/api.c
198
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"
|
||||||
|
"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\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();
|
||||||
|
|
|
@ -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 */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue