From 88e7919fbf81fe57eeff88a7c6056d0fd5df6f95 Mon Sep 17 00:00:00 2001 From: John Safranek Date: Sun, 1 Nov 2020 19:40:08 -0800 Subject: [PATCH 1/4] SSH-AGENT Add command line option to the client to allow use of the agent. --- examples/client/client.c | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/examples/client/client.c b/examples/client/client.c index cd52f8d..8929a48 100644 --- a/examples/client/client.c +++ b/examples/client/client.c @@ -172,6 +172,9 @@ static void ShowUsage(void) printf(" -R raw untranslated output\n"); #endif #endif +#ifdef WOLFSSH_AGENT + printf(" -a Attempt to use SSH-AGENT\n"); +#endif } @@ -815,6 +818,7 @@ THREAD_RETURN WOLFSSH_THREAD client_test(void* args) byte rawMode = 0; #endif #ifdef WOLFSSH_AGENT + byte useAgent = 0; WS_AgentCbActionCtx agentCbCtx; #endif @@ -888,6 +892,13 @@ THREAD_RETURN WOLFSSH_THREAD client_test(void* args) keepOpen = 1; break; #endif + + #ifdef WOLFSSH_AGENT + case 'a': + useAgent = 1; + break; + #endif + case '?': ShowUsage(); exit(EXIT_SUCCESS); @@ -995,9 +1006,11 @@ THREAD_RETURN WOLFSSH_THREAD client_test(void* args) wolfSSH_SetUserAuth(ctx, ((func_args*)args)->user_auth); #ifdef WOLFSSH_AGENT - wolfSSH_CTX_set_agent_cb(ctx, - wolfSSH_AGENT_DefaultActions, wolfSSH_AGENT_IO_Cb); - wolfSSH_CTX_AGENT_enable(ctx, 1); + if (useAgent) { + wolfSSH_CTX_set_agent_cb(ctx, + wolfSSH_AGENT_DefaultActions, wolfSSH_AGENT_IO_Cb); + wolfSSH_CTX_AGENT_enable(ctx, 1); + } #endif ssh = wolfSSH_new(ctx); @@ -1013,9 +1026,11 @@ THREAD_RETURN WOLFSSH_THREAD client_test(void* args) wolfSSH_SetUserAuthCtx(ssh, (void*)password); #ifdef WOLFSSH_AGENT - memset(&agentCbCtx, 0, sizeof(agentCbCtx)); - agentCbCtx.state = AGENT_STATE_INIT; - wolfSSH_set_agent_cb_ctx(ssh, &agentCbCtx); + if (useAgent) { + memset(&agentCbCtx, 0, sizeof(agentCbCtx)); + agentCbCtx.state = AGENT_STATE_INIT; + wolfSSH_set_agent_cb_ctx(ssh, &agentCbCtx); + } #endif wolfSSH_CTX_SetPublicKeyCheck(ctx, wsPublicKeyCheck); From c26f72cf983c0751127c8a9ec0d076db34de2f44 Mon Sep 17 00:00:00 2001 From: John Safranek Date: Sun, 1 Nov 2020 19:49:03 -0800 Subject: [PATCH 2/4] Maintenance 1. If the public key user authentication fails, don't retry it. 2. Add some more specific logging about the type of a signature getting generated. --- src/internal.c | 10 +++++++--- wolfssh/internal.h | 1 + 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/internal.c b/src/internal.c index f6f73d1..2190e66 100644 --- a/src/internal.c +++ b/src/internal.c @@ -2721,6 +2721,7 @@ static int DoKexDhInit(WOLFSSH* ssh, byte* buf, word32 len, word32* idx) && ssh->handshake->kexIdGuess != ssh->handshake->kexId) { /* skip this message. */ + WLOG(WS_LOG_DEBUG, "Skipping the client's KEX init function."); ssh->handshake->kexPacketFollows = 0; *idx += len; return WS_SUCCESS; @@ -6936,7 +6937,8 @@ int SendKexDhReply(WOLFSSH* ssh) ret = WS_CRYPTO_FAILED; } else { - WLOG(WS_LOG_INFO, "Signing hash with RSA."); + WLOG(WS_LOG_INFO, "Signing hash with %s.", + IdToName(ssh->handshake->pubKeyId)); sigSz = wc_RsaSSL_Sign(encSig, encSigSz, sig, sizeof(sig), &sigKeyBlock.sk.rsa.key, ssh->rng); if (sigSz <= 0) { @@ -6948,7 +6950,8 @@ int SendKexDhReply(WOLFSSH* ssh) } else { #ifndef WOLFSSH_NO_ECDSA - WLOG(WS_LOG_INFO, "Signing hash with ECDSA."); + WLOG(WS_LOG_INFO, "Signing hash with %s.", + IdToName(ssh->handshake->pubKeyId)); sigSz = sizeof(sig); ret = wc_ecc_sign_hash(digest, wc_HashGetDigestSize(sigHashId), sig, &sigSz, @@ -8360,8 +8363,9 @@ int SendUserAuthRequest(WOLFSSH* ssh, byte authId, int addSig) if (authId == ID_USERAUTH_PASSWORD) ret = PrepareUserAuthRequestPassword(ssh, &payloadSz, &authData); - else if (authId == ID_USERAUTH_PUBLICKEY) { + else if (authId == ID_USERAUTH_PUBLICKEY && !ssh->userAuthPkDone) { authData.sf.publicKey.hasSignature = 1; + ssh->userAuthPkDone = 1; ret = PrepareUserAuthRequestPublicKey(ssh, &payloadSz, &authData, &keySig); } diff --git a/wolfssh/internal.h b/wolfssh/internal.h index 683a440..542eea9 100644 --- a/wolfssh/internal.h +++ b/wolfssh/internal.h @@ -610,6 +610,7 @@ struct WOLFSSH { word32 peerProtoIdSz; void* publicKeyCheckCtx; byte sendTerminalRequest; + byte userAuthPkDone; #ifdef USE_WINDOWS_API word32 defaultAttr; /* default windows attributes */ From 2b2a30ca5414c55340fd45b98f14ed7ec28039ca Mon Sep 17 00:00:00 2001 From: John Safranek Date: Wed, 4 Nov 2020 11:19:24 -0800 Subject: [PATCH 3/4] SSH-AGENT Update 1. Remove redundant include from agent.h. 2. Add global disable flags for SSH-RSA using SHA2-256 and SHA2-512. These are possible signatures indications when using the ssh-agent. --- wolfssh/agent.h | 1 - wolfssh/internal.h | 9 +++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/wolfssh/agent.h b/wolfssh/agent.h index fc22cf3..a3a4951 100644 --- a/wolfssh/agent.h +++ b/wolfssh/agent.h @@ -35,7 +35,6 @@ #include #include #include -#include #ifdef __cplusplus diff --git a/wolfssh/internal.h b/wolfssh/internal.h index 542eea9..5700463 100644 --- a/wolfssh/internal.h +++ b/wolfssh/internal.h @@ -160,6 +160,15 @@ extern "C" { #undef WOLFSSH_NO_SSH_RSA_SHA1 #define WOLFSSH_NO_SSH_RSA_SHA1 #endif +#if defined(WOLFSSH_NO_RSA) || defined(NO_SHA256) + #undef WOLFSSH_NO_SSH_RSA_SHA2_256 + #define WOLFSSH_NO_SSH_RSA_SHA2_256 +#endif +#if defined(WOLFSSH_NO_RSA) || !defined(WOLFSSL_SHA512) + #undef WOLFSSH_NO_SSH_RSA_SHA2_512 + #define WOLFSSH_NO_SSH_RSA_SHA2_512 +#endif + #if defined(WOLFSSH_NO_ECDSA) || \ defined(NO_SHA256) || defined(NO_ECC256) #undef WOLFSSH_NO_ECDSA_SHA2_NISTP256 From 351bc7585efc38b08ef03aac95b6fb4097030f3d Mon Sep 17 00:00:00 2001 From: John Safranek Date: Wed, 4 Nov 2020 14:42:23 -0800 Subject: [PATCH 4/4] SSH-AGENT 1. For the client agent command line option, add the flag to the flag string. 2. Update PostSignRequest() to support all flavors of ECDSA and to switch out code for missing algorithms. 3. Hide function SendRequestIdentities(). --- examples/client/client.c | 2 +- src/agent.c | 369 ++++++++++++++++++++++++--------------- 2 files changed, 231 insertions(+), 140 deletions(-) diff --git a/examples/client/client.c b/examples/client/client.c index 8929a48..6ac702a 100644 --- a/examples/client/client.c +++ b/examples/client/client.c @@ -826,7 +826,7 @@ THREAD_RETURN WOLFSSH_THREAD client_test(void* args) char** argv = ((func_args*)args)->argv; ((func_args*)args)->return_code = 0; - while ((ch = mygetopt(argc, argv, "?c:eh:i:j:p:tu:xzNP:R")) != -1) { + while ((ch = mygetopt(argc, argv, "?ac:eh:i:j:p:tu:xzNP:R")) != -1) { switch (ch) { case 'h': host = myoptarg; diff --git a/src/agent.c b/src/agent.c index 5ea7b87..4e1ada3 100644 --- a/src/agent.c +++ b/src/agent.c @@ -173,6 +173,33 @@ static int SendSuccess(WOLFSSH_AGENT_CTX* agent) } +#if 0 +static int SendRequestIdentities(WOLFSSH_AGENT_CTX* agent) +{ + int ret = WS_SUCCESS; + WLOG_ENTER(); + + if (agent == NULL) + ret = WS_BAD_ARGUMENT; + + if (ret == WS_SUCCESS) + ret = PrepareMessage(agent, MSG_ID_SZ); + + if (ret == WS_SUCCESS) { + agent->msg[agent->msgIdx++] = MSGID_AGENT_REQUEST_IDENTITIES; + ret = BundleMessage(agent, MSG_ID_SZ); + } + + if (ret == WS_SUCCESS) { + DUMP(agent->msg, agent->msgSz); + } + + WLOG_LEAVE(ret); + return ret; +} +#endif + + static int SendIdentitiesAnswer(WOLFSSH_AGENT_CTX* agent) { WOLFSSH_AGENT_ID* id; @@ -614,163 +641,221 @@ static int PostRequestIds(WOLFSSH_AGENT_CTX* agent) } +static WOLFSSH_AGENT_ID* FindKeyId(WOLFSSH_AGENT_ID* id, + const byte* keyBlob, word32 keyBlobSz) +{ + int ret; + wc_Sha256 sha; + byte digest[WC_SHA256_DIGEST_SIZE]; + + ret = wc_InitSha256(&sha); + if (ret == 0) + ret = wc_Sha256Update(&sha, keyBlob, keyBlobSz); + if (ret == 0) { + ret = wc_Sha256Final(&sha, digest); + ret = (ret == 0) ? WS_SUCCESS : WS_CRYPTO_FAILED; + } + + if (ret == WS_SUCCESS) { + while (id != NULL && + WMEMCMP(digest, id, WC_SHA256_DIGEST_SIZE) != 0 && + WMEMCMP(keyBlob, id->keyBlob, keyBlobSz)) { + id = id->next; + } + } + + return id; +} + + +static int SignHashRsa(WOLFSSH_AGENT_KEY_RSA* rawKey, enum wc_HashType hashType, + const byte* digest, word32 digestSz, byte* sig, word32* sigSz, + WC_RNG* rng, void* heap) +{ + RsaKey key; + byte encSig[MAX_ENCODED_SIG_SZ]; + int encSigSz; + int ret = 0; + + wc_InitRsaKey(&key, heap); + mp_read_unsigned_bin(&key.n, rawKey->n, rawKey->nSz); + mp_read_unsigned_bin(&key.e, rawKey->e, rawKey->eSz); + mp_read_unsigned_bin(&key.d, rawKey->d, rawKey->dSz); + mp_read_unsigned_bin(&key.p, rawKey->p, rawKey->pSz); + mp_read_unsigned_bin(&key.q, rawKey->q, rawKey->qSz); + mp_read_unsigned_bin(&key.u, rawKey->iqmp, rawKey->iqmpSz); + + encSigSz = wc_EncodeSignature(encSig, digest, digestSz, + wc_HashGetOID(hashType)); + if (encSigSz <= 0) { + WLOG(WS_LOG_DEBUG, "Bad Encode Sig"); + ret = WS_CRYPTO_FAILED; + } + else { + WLOG(WS_LOG_INFO, "Signing hash with RSA."); + *sigSz = wc_RsaSSL_Sign(encSig, encSigSz, sig, *sigSz, &key, rng); + if (*sigSz <= 0) { + WLOG(WS_LOG_DEBUG, "Bad RSA Sign"); + ret = WS_RSA_E; + } + } + + wc_FreeRsaKey(&key); + if (ret != 0) + ret = WS_RSA_E; + + return ret; +} + + +static int SignHashEcc(WOLFSSH_AGENT_KEY_ECDSA* rawKey, int curveId, + const byte* digest, word32 digestSz, + byte* sig, word32* sigSz, WC_RNG* rng) +{ + ecc_key key; + int ret; + + ret = wc_ecc_import_private_key_ex(rawKey->d, rawKey->dSz, + rawKey->q, rawKey->qSz, &key, curveId); + + if (ret == 0) { + ret = wc_ecc_sign_hash(digest, digestSz, sig, sigSz, rng, &key); + } + if (ret != 0) { + WLOG(WS_LOG_DEBUG, "SendKexDhReply: Bad ECDSA Sign"); + ret = WS_ECC_E; + } + else { + byte r[MAX_ECC_BYTES + ECC_MAX_PAD_SZ]; + word32 rSz = sizeof(r); + byte rPad; + byte s[MAX_ECC_BYTES + ECC_MAX_PAD_SZ]; + word32 sSz = sizeof(s); + byte sPad; + int idx; + + ret = wc_ecc_sig_to_rs(sig, *sigSz, r, &rSz, s, &sSz); + if (ret == 0) { + idx = 0; + rPad = (r[0] & 0x80) ? 1 : 0; + sPad = (s[0] & 0x80) ? 1 : 0; + *sigSz = (LENGTH_SZ * 2) + rSz + rPad + sSz + sPad; + + c32toa(rSz + rPad, sig + idx); + idx += LENGTH_SZ; + if (rPad) + sig[idx++] = 0; + WMEMCPY(sig + idx, r, rSz); + idx += rSz; + c32toa(sSz + sPad, sig + idx); + idx += LENGTH_SZ; + if (sPad) + sig[idx++] = 0; + WMEMCPY(sig + idx, s, sSz); + } + } + + wc_ecc_free(&key); + if (ret != 0) + ret = WS_ECC_E; + + return ret; +} + + static int PostSignRequest(WOLFSSH_AGENT_CTX* agent, byte* keyBlob, word32 keyBlobSz, byte* data, word32 dataSz, word32 flags) { - WOLFSSH_AGENT_ID* cur = NULL; - wc_Sha256 sha; - byte digest[WC_SHA256_DIGEST_SIZE]; - + WOLFSSH_AGENT_ID* id = NULL; int ret = WS_SUCCESS; + byte sig[256]; + byte digest[WC_MAX_DIGEST_SIZE]; + word32 sigSz = sizeof(sig); + word32 digestSz = sizeof(digest); + enum wc_HashType hashType; + int curveId = 0, signRsa = 0, signEcc = 0; + + WLOG_ENTER(); + + (void)flags; + (void)curveId; if (agent == NULL || keyBlob == NULL || keyBlobSz == 0) ret = WS_BAD_ARGUMENT; if (ret == WS_SUCCESS) { - ret = wc_InitSha256(&sha); - if (ret == 0) - ret = wc_Sha256Update(&sha, keyBlob, keyBlobSz); - if (ret == 0) { - ret = wc_Sha256Final(&sha, digest); - ret = (ret == 0) ? WS_SUCCESS : WS_CRYPTO_FAILED; - } - - if (ret == WS_SUCCESS) { - cur = agent->idList; - while (cur != NULL && - WMEMCMP(digest, cur->id, WC_SHA256_DIGEST_SIZE) != 0) { - cur = cur->next; - } - - if (cur == NULL) { - WLOG(WS_LOG_AGENT, "Sign: Key not found."); - ret = WS_AGENT_NO_KEY_E; - } + if ((id = FindKeyId(agent->idList, keyBlob, keyBlobSz)) == NULL) { + WLOG(WS_LOG_AGENT, "Sign: Key not found."); + ret = WS_AGENT_NO_KEY_E; } } if (ret == WS_SUCCESS) { - if ((cur->keyType == ID_SSH_RSA && flags & AGENT_SIGN_RSA_SHA2_256) || - cur->keyType == ID_ECDSA_SHA2_NISTP256) { - - ret = wc_InitSha256(&sha); - if (ret == 0) - ret = wc_Sha256Update(&sha, data, dataSz); - if (ret == 0) { - ret = wc_Sha256Final(&sha, digest); - ret = (ret == 0) ? WS_SUCCESS : WS_CRYPTO_FAILED; - } - } - else - ret = WS_INVALID_ALGO_ID; - } - - if (ret == WS_SUCCESS) { - byte sig[256]; - int sigSz = sizeof(sig); - - if (cur->keyType == ID_SSH_RSA) { -#ifndef WOLFSSH_NO_RSA - WOLFSSH_AGENT_KEY_RSA* key; - RsaKey rsa; - byte encSig[MAX_ENCODED_SIG_SZ]; - int encSigSz; - enum wc_HashType hashType = WC_HASH_TYPE_NONE; - - key = &cur->key.rsa; - - if (flags & AGENT_SIGN_RSA_SHA2_256) + switch (id->keyType) { + #if !defined(WOLFSSH_NO_SSH_RSA_SHA2_256) || \ + !defined(WOLFSSH_NO_SSH_RSA_SHA2_512) + case ID_SSH_RSA: + signRsa = 1; + #ifndef WOLFSSH_NO_SSH_RSA_SHA2_256 + if (flags & AGENT_SIGN_RSA_SHA2_256) + hashType = WC_HASH_TYPE_SHA256; + else + #endif + #ifndef WOLFSSH_NO_SSH_RSA_SHA2_512 + if (flags & AGENT_SIGN_RSA_SHA2_512) + hashType = WC_HASH_TYPE_SHA512; + else + #endif + ret = WS_INVALID_ALGO_ID; + break; + #endif + #ifndef WOLFSSH_NO_ECDSA_SHA2_NISTP256 + case ID_ECDSA_SHA2_NISTP256: hashType = WC_HASH_TYPE_SHA256; - else if (flags & AGENT_SIGN_RSA_SHA2_512) + curveId = ECC_SECP256R1; + signEcc = 1; + break; + #endif + #ifndef WOLFSSH_NO_ECDSA_SHA2_NISTP384 + case ID_ECDSA_SHA2_NISTP384: + hashType = WC_HASH_TYPE_SHA384; + curveId = ECC_SECP384R1; + signEcc = 1; + break; + #endif + #ifndef WOLFSSH_NO_ECDSA_SHA2_NISTP512 + case ID_ECDSA_SHA2_NISTP521: hashType = WC_HASH_TYPE_SHA512; - - wc_InitRsaKey(&rsa, agent->heap); - mp_read_unsigned_bin(&rsa.n, key->n, key->nSz); - mp_read_unsigned_bin(&rsa.e, key->e, key->eSz); - mp_read_unsigned_bin(&rsa.d, key->d, key->dSz); - mp_read_unsigned_bin(&rsa.p, key->p, key->pSz); - mp_read_unsigned_bin(&rsa.q, key->q, key->qSz); - mp_read_unsigned_bin(&rsa.u, key->iqmp, key->iqmpSz); - - encSigSz = wc_EncodeSignature(encSig, digest, - wc_HashGetDigestSize(hashType), - wc_HashGetOID(hashType)); - if (encSigSz <= 0) { - WLOG(WS_LOG_DEBUG, "Bad Encode Sig"); - ret = WS_CRYPTO_FAILED; - } - else { - WLOG(WS_LOG_INFO, "Signing hash with RSA."); - sigSz = wc_RsaSSL_Sign(encSig, encSigSz, sig, sizeof(sig), - &rsa, &agent->rng); - if (sigSz <= 0) { - WLOG(WS_LOG_DEBUG, "Bad RSA Sign"); - ret = WS_RSA_E; - } - } - - wc_FreeRsaKey(&rsa); - if (ret != 0) - ret = WS_RSA_E; -#endif + curveId = ECC_SECP521R1; + signEcc = 1; + break; + #endif + default: + ret = WS_INVALID_ALGO_ID; } - else if (cur->keyType == ID_ECDSA_SHA2_NISTP256) { -#ifndef WOLFSSH_NO_ECDSA - WOLFSSH_AGENT_KEY_ECDSA* key; - ecc_key ecc; - enum wc_HashType hashType = WC_HASH_TYPE_SHA256; + } - key = &cur->key.ecdsa; - ret = wc_ecc_import_private_key_ex(key->d, key->dSz, - key->q, key->qSz, - &ecc, ECC_SECP256R1); + if (ret == WS_SUCCESS) { + ret = wc_Hash(hashType, data, dataSz, digest, digestSz); + if (ret != 0) + ret = WS_CRYPTO_FAILED; + } - if (ret == 0) { - ret = wc_ecc_sign_hash(digest, wc_HashGetDigestSize(hashType), - sig, (word32*)&sigSz, &agent->rng, &ecc); - } - if (ret != 0) { - WLOG(WS_LOG_DEBUG, "SendKexDhReply: Bad ECDSA Sign"); - ret = WS_ECC_E; - } - else { - byte r[MAX_ECC_BYTES + ECC_MAX_PAD_SZ]; - word32 rSz = sizeof(r); - byte rPad; - byte s[MAX_ECC_BYTES + ECC_MAX_PAD_SZ]; - word32 sSz = sizeof(s); - byte sPad; - int idx; - - ret = wc_ecc_sig_to_rs(sig, sigSz, r, &rSz, s, &sSz); - if (ret == 0) { - idx = 0; - rPad = (r[0] & 0x80) ? 1 : 0; - sPad = (s[0] & 0x80) ? 1 : 0; - sigSz = (LENGTH_SZ * 2) + rSz + rPad + sSz + sPad; - - c32toa(rSz + rPad, sig + idx); - idx += LENGTH_SZ; - if (rPad) - sig[idx++] = 0; - WMEMCPY(sig + idx, r, rSz); - idx += rSz; - c32toa(sSz + sPad, sig + idx); - idx += LENGTH_SZ; - if (sPad) - sig[idx++] = 0; - WMEMCPY(sig + idx, s, sSz); - } - } - - wc_ecc_free(&ecc); - if (ret != 0) - ret = WS_ECC_E; + if (ret == WS_SUCCESS) { +#if !defined(WOLFSSH_NO_SSH_RSA_SHA2_256) || \ + !defined(WOLFSSH_NO_SSH_RSA_SHA2_512) + if (signRsa) + ret = SignHashRsa(&id->key.rsa, hashType, + digest, digestSz, sig, &sigSz, &agent->rng, agent->heap); +#endif +#if !defined(WOLFSSH_NO_ECDSA_SHA2_NISTP256) || \ + !defined(WOLFSSH_NO_ECDSA_SHA2_NISTP384) || \ + !defined(WOLFSSH_NO_ECDSA_SHA2_NISTP512) + if (signEcc) + ret = SignHashEcc(&id->key.ecdsa, curveId, digest, digestSz, + sig, &sigSz, &agent->rng); #endif - } - else - ret = WS_INVALID_ALGO_ID; if (ret == WS_SUCCESS) ret = SendSignResponse(agent, sig, sigSz); @@ -1708,8 +1793,14 @@ int wolfSSH_AGENT_SignRequest(WOLFSSH* ssh, rxBuf, sizeof(rxBuf), ssh->agentCbCtx); if (rxSz > 0) { ret = DoMessage(ssh->agent, rxBuf, rxSz, &idx); - WMEMCPY(sig, ssh->agent->msg, ssh->agent->msgSz); - *sigSz = ssh->agent->msgSz; + if (ssh->agent->requestFailure) { + ssh->agent->requestFailure = 0; + ret = WS_AGENT_NO_KEY_E; + } + else { + WMEMCPY(sig, ssh->agent->msg, ssh->agent->msgSz); + *sigSz = ssh->agent->msgSz; + } } else ret = WS_AGENT_NO_KEY_E; }