/* agent.c * * Copyright (C) 2014-2023 wolfSSL Inc. * * This file is part of wolfSSH. * * wolfSSH is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * wolfSSH is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with wolfSSH. If not, see . */ /* */ #ifdef HAVE_CONFIG_H #include #endif #ifdef WOLFSSH_AGENT #include #include #include #include #include #include #ifdef NO_INLINE #include #else #define WOLFSSH_MISC_INCLUDED #include "src/misc.c" #endif #define WLOG_ENTER() do { \ WLOG(WS_LOG_AGENT, "Entering %s()", __func__); \ } while (0) #define WLOG_LEAVE(x) do { \ WLOG(WS_LOG_AGENT, "Leaving %s(), ret = %d", __func__, (x)); \ } while (0) #ifdef DEBUG_WOLFSSH #define DUMP(x,y) do { DumpOctetString((x),(y)); } while (0) #else #define DUMP(x,y) #endif /* payloadSz is an estimate, but it shall be greater-than/equal-to * the actual value. */ static int PrepareMessage(WOLFSSH_AGENT_CTX* agent, word32 payloadSz) { int ret = WS_SUCCESS; byte* msg = NULL; WLOG_ENTER(); if (agent == NULL || payloadSz == 0) ret = WS_BAD_ARGUMENT; if (ret == WS_SUCCESS) { if (agent->msg != NULL) WFREE(agent->msg, agent->heap, DYNTYPE_AGENT_BUFFER); payloadSz += LENGTH_SZ; msg = (byte*)WMALLOC(payloadSz, agent->heap, DYNTYPE_AGENT_BUFFER); if (msg == NULL) ret = WS_MEMORY_E; } if (ret == WS_SUCCESS) { agent->msg = msg; agent->msgSz = payloadSz; agent->msgIdx = LENGTH_SZ; } WLOG_LEAVE(ret); return ret; } /* payloadSz is the actual payload size. */ static int BundleMessage(WOLFSSH_AGENT_CTX* agent, word32 payloadSz) { int ret = WS_SUCCESS; WLOG_ENTER(); if (agent == NULL || payloadSz == 0) ret = WS_BAD_ARGUMENT; if (ret == WS_SUCCESS) { if (LENGTH_SZ + payloadSz > agent->msgSz || agent->msgIdx > agent->msgSz) ret = WS_BUFFER_E; } if (ret == WS_SUCCESS) { c32toa(payloadSz, agent->msg); agent->msgSz = LENGTH_SZ + payloadSz; } WLOG_LEAVE(ret); return ret; } static int SendFailure(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_FAILURE; ret = BundleMessage(agent, MSG_ID_SZ); } if (ret == WS_SUCCESS) { DUMP(agent->msg, agent->msgSz); } WLOG_LEAVE(ret); return ret; } static int SendSuccess(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_SUCCESS; ret = BundleMessage(agent, MSG_ID_SZ); } if (ret == WS_SUCCESS) { DUMP(agent->msg, agent->msgSz); WFREE(agent->msg, agent->heap, DYNTYPE_AGENT_BUFFER); agent->msg = NULL; agent->msgSz = 0; } WLOG_LEAVE(ret); return ret; } #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; word32 msgSz, idCount = 0; int ret = WS_SUCCESS; WLOG_ENTER(); if (agent == NULL) ret = WS_BAD_ARGUMENT; if (ret == WS_SUCCESS) { msgSz = MSG_ID_SZ + UINT32_SZ; id = agent->idList; while (id != NULL) { idCount++; msgSz += LENGTH_SZ * 2 + id->keyBlobSz + id->commentSz; id = id->next; } ret = PrepareMessage(agent, msgSz); } if (ret == WS_SUCCESS) { byte* msg = agent->msg; word32 idx = agent->msgIdx; msg[idx++] = MSGID_AGENT_IDENTITIES_ANSWER; c32toa(idCount, msg + idx); idx += UINT32_SZ; id = agent->idList; while (id != NULL) { c32toa(id->keyBlobSz, msg + idx); idx += LENGTH_SZ; WMEMCPY(msg + idx, id->keyBlob, id->keyBlobSz); idx += id->keyBlobSz; c32toa(id->commentSz, msg + idx); idx += LENGTH_SZ; WMEMCPY(msg + idx, id->comment, id->commentSz); idx += id->commentSz; id = id->next; } agent->msgIdx = idx; ret = BundleMessage(agent, msgSz); } if (ret == WS_SUCCESS) { DUMP(agent->msg, agent->msgSz); WFREE(agent->msg, agent->heap, DYNTYPE_AGENT_BUFFER); agent->msg = NULL; agent->msgSz = 0; } WLOG_LEAVE(ret); return ret; } static int SendSignRequest(WOLFSSH_AGENT_CTX* agent, const byte* data, word32 dataSz, const byte* keyBlob, word32 keyBlobSz, word32 flags) { word32 msgSz; int ret = WS_SUCCESS; WLOG_ENTER(); if (agent == NULL) ret = WS_BAD_ARGUMENT; if (ret == WS_SUCCESS) { msgSz = MSG_ID_SZ + (LENGTH_SZ * 2) + UINT32_SZ + dataSz + keyBlobSz; ret = PrepareMessage(agent, msgSz); } if (ret == WS_SUCCESS) { byte* msg = agent->msg; word32 idx = agent->msgIdx; msg[idx++] = MSGID_AGENT_SIGN_REQUEST; c32toa(keyBlobSz, msg + idx); idx += LENGTH_SZ; WMEMCPY(msg + idx, keyBlob, keyBlobSz); idx += keyBlobSz; c32toa(dataSz, msg + idx); idx += LENGTH_SZ; WMEMCPY(msg + idx, data, dataSz); idx += dataSz; c32toa(flags, msg + idx); idx += UINT32_SZ; agent->msgIdx = idx; ret = BundleMessage(agent, msgSz); } /* if (ret == WS_SUCCESS) { DUMP(agent->msg, agent->msgSz); WFREE(agent->msg, agent->heap, DYNTYPE_AGENT_BUFFER); agent->msg = NULL; agent->msgSz = 0; } */ WLOG_LEAVE(ret); return ret; } static int SendSignResponse(WOLFSSH_AGENT_CTX* agent, const byte* sig, word32 sigSz) { int ret = WS_SUCCESS; word32 msgSz; WLOG_ENTER(); if (agent == NULL || sig == NULL || sigSz == 0) ret = WS_BAD_ARGUMENT; if (ret == WS_SUCCESS) { msgSz = MSG_ID_SZ + LENGTH_SZ + sigSz; ret = PrepareMessage(agent, msgSz); } if (ret == WS_SUCCESS) { agent->msg[agent->msgIdx++] = MSGID_AGENT_SIGN_RESPONSE; c32toa(sigSz, agent->msg + agent->msgIdx); agent->msgIdx += LENGTH_SZ; WMEMCPY(agent->msg + agent->msgIdx, sig, sigSz); agent->msgIdx += sigSz; ret = BundleMessage(agent, msgSz); } if (ret == WS_SUCCESS) { DUMP(agent->msg, agent->msgSz); WFREE(agent->msg, agent->heap, DYNTYPE_AGENT_BUFFER); agent->msg = 0; agent->msgSz = 0; } WLOG_LEAVE(ret); return ret; } static int PostFailure(WOLFSSH_AGENT_CTX* agent) { WLOG(WS_LOG_AGENT, "Posting failure to agent %p", agent); agent->requestFailure = 1; return WS_SUCCESS; } static int PostSuccess(WOLFSSH_AGENT_CTX* agent) { WLOG(WS_LOG_AGENT, "Posting success to agent %p", agent); agent->requestSuccess = 1; return WS_SUCCESS; } static int PostLock(WOLFSSH_AGENT_CTX* agent, const byte* passphrase, word32 passphraseSz) { char pp[32]; word32 ppSz; WLOG(WS_LOG_AGENT, "Posting lock to agent %p", agent); ppSz = sizeof(pp) - 1; if (passphraseSz < ppSz) ppSz = passphraseSz; WMEMCPY(pp, passphrase, passphraseSz); pp[ppSz] = 0; WLOG(WS_LOG_AGENT, "Locking with passphrase '%s'", pp); return WS_SUCCESS; } static int PostUnlock(WOLFSSH_AGENT_CTX* agent, const byte* passphrase, word32 passphraseSz) { char pp[32]; word32 ppSz; WLOG(WS_LOG_AGENT, "Posting unlock to agent %p", agent); ppSz = sizeof(pp) - 1; if (passphraseSz < ppSz) ppSz = passphraseSz; WMEMCPY(pp, passphrase, passphraseSz); pp[ppSz] = 0; WLOG(WS_LOG_AGENT, "Unlocking with passphrase '%s'", pp); return WS_SUCCESS; } #ifndef WOLFSSH_NO_RSA static int PostAddRsaId(WOLFSSH_AGENT_CTX* agent, byte keyType, byte* key, word32 keySz, word32 nSz, word32 eSz, word32 dSz, word32 iqmpSz, word32 pSz, word32 qSz, word32 commentSz) { WOLFSSH_AGENT_ID* id = NULL; wc_Sha256 sha; int ret = WS_SUCCESS; WLOG_ENTER(); DUMP(key, keySz); id = wolfSSH_AGENT_ID_new(keyType, keySz, agent->heap); if (id == NULL) ret = WS_MEMORY_E; if (ret == WS_SUCCESS) { ret = wc_InitSha256(&sha); if (ret == 0) ret = wc_Sha256Update(&sha, key, nSz + eSz + (LENGTH_SZ * 2)); if (ret == 0) ret = wc_Sha256Final(&sha, id->id); if (ret == 0) ret = WS_SUCCESS; else ret = WS_CRYPTO_FAILED; } if (ret == WS_SUCCESS) { WOLFSSH_AGENT_KEY_RSA* rsa = &id->key.rsa; word32 keyIdx = 0; WMEMCPY(id->keyBuffer, key, keySz); id->keyBlob = id->keyBuffer; id->keyBlobSz = nSz + eSz + (LENGTH_SZ * 2); keyIdx += LENGTH_SZ; rsa->n = id->keyBuffer + keyIdx; rsa->nSz = nSz; keyIdx += nSz + LENGTH_SZ; rsa->e = id->keyBuffer + keyIdx; rsa->eSz = eSz; keyIdx += eSz + LENGTH_SZ; rsa->d = id->keyBuffer + keyIdx; rsa->dSz = dSz; keyIdx += dSz + LENGTH_SZ; rsa->iqmp = id->keyBuffer + keyIdx; rsa->iqmpSz = iqmpSz; keyIdx += iqmpSz + LENGTH_SZ; rsa->p = id->keyBuffer + keyIdx; rsa->pSz = pSz; keyIdx += pSz + LENGTH_SZ; rsa->q = id->keyBuffer + keyIdx; rsa->qSz = qSz; keyIdx += qSz + LENGTH_SZ; id->comment = id->keyBuffer + keyIdx; id->commentSz = commentSz; id->next = agent->idList; agent->idList = id; agent->idListSz++; WLOG(WS_LOG_AGENT, "idListSz = %u", agent->idListSz); } else if (id != NULL) wolfSSH_AGENT_ID_free(id, agent->heap); WLOG_LEAVE(ret); return ret; } #endif #ifndef WOLFSSH_NO_ECDSA static int PostAddEcdsaId(WOLFSSH_AGENT_CTX* agent, byte keyType, byte* key, word32 keySz, word32 curveNameSz, word32 qSz, word32 dSz, word32 commentSz) { WOLFSSH_AGENT_ID* id = NULL; wc_Sha256 sha; int ret = WS_SUCCESS; WLOG_ENTER(); DUMP(key, keySz); id = wolfSSH_AGENT_ID_new(keyType, keySz, agent->heap); if (id == NULL) ret = WS_MEMORY_E; if (ret == WS_SUCCESS) { ret = wc_InitSha256(&sha); if (ret == 0) ret = wc_Sha256Update(&sha, key, curveNameSz + qSz + (LENGTH_SZ * 2)); if (ret == 0) ret = wc_Sha256Final(&sha, id->id); if (ret == 0) ret = WS_SUCCESS; else ret = WS_CRYPTO_FAILED; } if (ret == WS_SUCCESS) { WOLFSSH_AGENT_KEY_ECDSA* ecdsa = &id->key.ecdsa; word32 keyIdx = 0; WMEMCPY(id->keyBuffer, key, keySz); id->keyBlob = id->keyBuffer; id->keyBlobSz = curveNameSz + qSz + (LENGTH_SZ * 2); keyIdx += LENGTH_SZ; ecdsa->curveName = id->keyBuffer + keyIdx; ecdsa->curveNameSz = curveNameSz; keyIdx += curveNameSz + LENGTH_SZ; ecdsa->q = id->keyBuffer + keyIdx; ecdsa->qSz = qSz; keyIdx += qSz + LENGTH_SZ; ecdsa->d = id->keyBuffer + keyIdx; ecdsa->dSz = dSz; keyIdx += dSz + LENGTH_SZ; id->comment = id->keyBuffer + keyIdx; id->commentSz = commentSz; id->next = agent->idList; agent->idList = id; agent->idListSz++; WLOG(WS_LOG_AGENT, "idListSz = %u", agent->idListSz); } else if (id != NULL) wolfSSH_AGENT_ID_free(id, agent->heap); WLOG_LEAVE(ret); return ret; } #endif static int PostRemoveId(WOLFSSH_AGENT_CTX* agent, const byte* keyBlob, word32 keyBlobSz) { WOLFSSH_AGENT_ID* cur = NULL; WOLFSSH_AGENT_ID* prev = NULL; byte id[WC_SHA256_DIGEST_SIZE]; int ret = WS_SUCCESS; if (agent == NULL || keyBlob == NULL || keyBlobSz == 0) ret = WS_BAD_ARGUMENT; if (ret == WS_SUCCESS) { wc_Sha256 sha; ret = wc_InitSha256(&sha); if (ret == 0) ret = wc_Sha256Update(&sha, keyBlob, keyBlobSz); if (ret == 0) ret = wc_Sha256Final(&sha, id); ret = (ret == 0) ? WS_SUCCESS : WS_CRYPTO_FAILED; } if (ret == WS_SUCCESS) { cur = agent->idList; while (cur != NULL) { int match; match = WMEMCMP(id, cur->id, WC_SHA256_DIGEST_SIZE); if (!match) { prev = cur; cur = cur->next; } else { if (prev != NULL) prev->next = cur->next; else agent->idList = NULL; wolfSSH_AGENT_ID_free(cur, agent->heap); cur = NULL; agent->idListSz--; WLOG(WS_LOG_AGENT, "idListSz = %u", agent->idListSz); } } } WLOG_LEAVE(ret); return ret; } static int PostRemoveAllIds(WOLFSSH_AGENT_CTX* agent) { WLOG_ENTER(); wolfSSH_AGENT_ID_list_free(agent->idList, agent->heap); agent->idList = NULL; agent->idListSz = 0; WLOG(WS_LOG_AGENT, "idListSz = %u", agent->idListSz); WLOG_LEAVE(WS_SUCCESS); return(WS_SUCCESS); } static int PostRequestIds(WOLFSSH_AGENT_CTX* agent) { int ret = WS_SUCCESS; WLOG_ENTER(); if (agent == NULL) ret = WS_BAD_ARGUMENT; if (ret == WS_SUCCESS) ret = SendIdentitiesAnswer(agent); WLOG_LEAVE(ret); return ret; } 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; } #if !defined(WOLFSSH_NO_RSA_SHA2_256) || \ !defined(WOLFSSH_NO_RSA_SHA2_512) 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; } else { ret = wolfSSH_RsaVerify(sig, *sigSz, encSig, encSigSz, &key, heap, "SignHashRsa"); } } wc_FreeRsaKey(&key); if (ret != 0) ret = WS_RSA_E; return ret; } #endif /* WOLFSSH_NO_RSA_SHA2_256/512 */ #if !defined(WOLFSSH_NO_ECDSA_SHA2_NISTP256) || \ !defined(WOLFSSH_NO_ECDSA_SHA2_NISTP384) || \ !defined(WOLFSSH_NO_ECDSA_SHA2_NISTP521) 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; } #endif /* WOLFSSH_NO_ECDSA_SHA2_NISTP256/384/521 */ static int PostSignRequest(WOLFSSH_AGENT_CTX* agent, const byte* keyBlob, word32 keyBlobSz, const byte* data, word32 dataSz, word32 flags) { 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(); WOLFSSH_UNUSED(flags); WOLFSSH_UNUSED(curveId); if (agent == NULL || keyBlob == NULL || keyBlobSz == 0) ret = WS_BAD_ARGUMENT; if (ret == WS_SUCCESS) { 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) { switch (id->keyType) { #if !defined(WOLFSSH_NO_RSA_SHA2_256) || \ !defined(WOLFSSH_NO_RSA_SHA2_512) case ID_SSH_RSA: signRsa = 1; #ifndef WOLFSSH_NO_RSA_SHA2_256 if (flags & AGENT_SIGN_RSA_SHA2_256) hashType = WC_HASH_TYPE_SHA256; else #endif #ifndef WOLFSSH_NO_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; 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_NISTP521 case ID_ECDSA_SHA2_NISTP521: hashType = WC_HASH_TYPE_SHA512; curveId = ECC_SECP521R1; signEcc = 1; break; #endif default: ret = WS_INVALID_ALGO_ID; } } if (ret == WS_SUCCESS) { ret = wc_Hash(hashType, data, dataSz, digest, digestSz); if (ret != 0) ret = WS_CRYPTO_FAILED; } if (ret == WS_SUCCESS) { #if !defined(WOLFSSH_NO_RSA_SHA2_256) || \ !defined(WOLFSSH_NO_RSA_SHA2_512) if (signRsa) ret = SignHashRsa(&id->key.rsa, hashType, digest, digestSz, sig, &sigSz, &agent->rng, agent->heap); #else WOLFSSH_UNUSED(signRsa); #endif #if !defined(WOLFSSH_NO_ECDSA_SHA2_NISTP256) || \ !defined(WOLFSSH_NO_ECDSA_SHA2_NISTP384) || \ !defined(WOLFSSH_NO_ECDSA_SHA2_NISTP521) if (signEcc) ret = SignHashEcc(&id->key.ecdsa, curveId, digest, digestSz, sig, &sigSz, &agent->rng); #else WOLFSSH_UNUSED(signEcc); #endif if (ret == WS_SUCCESS) ret = SendSignResponse(agent, sig, sigSz); } WLOG_LEAVE(ret); return ret; } static int DoFailure(WOLFSSH_AGENT_CTX* agent, byte* buf, word32 len, word32* idx) { int ret = WS_SUCCESS; WLOG(WS_LOG_AGENT, "Entering DoFailure()"); WOLFSSH_UNUSED(buf); WOLFSSH_UNUSED(idx); if (len != 0) ret = WS_PARSE_E; if (ret == WS_SUCCESS) ret = PostFailure(agent); WLOG(WS_LOG_AGENT, "Leaving DoFailure(), ret = %d", ret); return ret; } static int DoSuccess(WOLFSSH_AGENT_CTX* agent, byte* buf, word32 len, word32* idx) { int ret = WS_SUCCESS; WLOG_ENTER(); WOLFSSH_UNUSED(buf); WOLFSSH_UNUSED(idx); if (len != 0) ret = WS_PARSE_E; if (ret == WS_SUCCESS) ret = PostSuccess(agent); WLOG_LEAVE(ret); return ret; } static int DoRequestIdentities(WOLFSSH_AGENT_CTX* agent, byte* buf, word32 len, word32* idx) { int ret = WS_SUCCESS; WLOG_ENTER(); WOLFSSH_UNUSED(buf); WOLFSSH_UNUSED(idx); if (len != 0) ret = WS_PARSE_E; if (ret == WS_SUCCESS) ret = PostRequestIds(agent); WLOG_LEAVE(ret); return ret; } static int DoIdentitiesAnswer(WOLFSSH_AGENT_CTX* agent, byte* buf, word32 len, word32* idx) { int ret = WS_SUCCESS; WLOG(WS_LOG_AGENT, "Entering DoIdentitiesAnswer()"); WOLFSSH_UNUSED(agent); WOLFSSH_UNUSED(buf); WOLFSSH_UNUSED(len); WOLFSSH_UNUSED(idx); DUMP(buf + *idx, len); WLOG(WS_LOG_AGENT, "Leaving DoIdentitiesAnswer(), ret = %d", ret); return ret; } static int DoSignRequest(WOLFSSH_AGENT_CTX* agent, byte* buf, word32 len, word32* idx) { const byte* keyBlob; const byte* data; word32 begin, keyBlobSz, dataSz, flags; int ret = WS_SUCCESS; WLOG_ENTER(); if (agent == NULL || buf == NULL || len == 0 || idx == NULL) ret = WS_BAD_ARGUMENT; if (ret == WS_SUCCESS) { WLOG(WS_LOG_AGENT, "len = %u, idx = %u", len, *idx); begin = *idx; ret = GetStringRef(&keyBlobSz, &keyBlob, buf, len, &begin); } if (ret == WS_SUCCESS) ret = GetStringRef(&dataSz, &data, buf, len, &begin); if (ret == WS_SUCCESS) ret = GetUint32(&flags, buf, len, &begin); if (ret == WS_SUCCESS) ret = PostSignRequest(agent, keyBlob, keyBlobSz, data, dataSz, flags); if (ret == WS_SUCCESS) *idx = begin; WLOG_LEAVE(ret); return ret; } static int DoSignResponse(WOLFSSH_AGENT_CTX* agent, byte* buf, word32 len, word32* idx) { byte* sig; word32 sigSz; int ret = WS_SUCCESS; WLOG(WS_LOG_AGENT, "Entering DoSignResponse()"); if (agent == NULL || buf == NULL || len == 0 || idx == NULL) ret = WS_BAD_ARGUMENT; if ( ret == WS_SUCCESS) ret = GetStringRef(&sigSz, (const byte**)&sig, buf, len, idx); if (ret == WS_SUCCESS) { agent->msg = sig; agent->msgSz = sigSz; } WLOG(WS_LOG_AGENT, "Leaving DoSignResponse(), ret = %d", ret); return ret; } static int DoAddIdentity(WOLFSSH_AGENT_CTX* agent, byte* buf, word32 len, word32* idx) { int ret = WS_SUCCESS; word32 begin; word32 sz; WLOG_ENTER(); if (agent == NULL || buf == NULL || len == 0 || idx == NULL) ret = WS_BAD_ARGUMENT; if (ret == WS_SUCCESS) { WLOG(WS_LOG_AGENT, "len = %u, idx = %u", len, *idx); begin = *idx; if (begin + LENGTH_SZ > len) { ret = WS_PARSE_E; } } if (ret == WS_SUCCESS) { ato32(buf + begin, &sz); begin += LENGTH_SZ; if (begin + sz > len) ret = WS_PARSE_E; } if (ret == WS_SUCCESS) { byte keyType = NameToId((char*)buf + begin, sz); begin += sz; if (keyType == ID_SSH_RSA) { #ifndef WOLFSSH_NO_RSA byte* key; const byte* scratch; word32 keySz, nSz, eSz, dSz, iqmpSz, pSz, qSz, commentSz; key = buf + begin; /* n */ ret = GetMpint(&nSz, &scratch, buf, len, &begin); /* e */ if (ret == WS_SUCCESS) ret = GetMpint(&eSz, &scratch, buf, len, &begin); /* d */ if (ret == WS_SUCCESS) ret = GetMpint(&dSz, &scratch, buf, len, &begin); /* iqmp */ if (ret == WS_SUCCESS) ret = GetMpint(&iqmpSz, &scratch, buf, len, &begin); /* p */ if (ret == WS_SUCCESS) ret = GetMpint(&pSz, &scratch, buf, len, &begin); /* q */ if (ret == WS_SUCCESS) ret = GetMpint(&qSz, &scratch, buf, len, &begin); /* comment */ if (ret == WS_SUCCESS) ret = GetStringRef(&commentSz, &scratch, buf, len, &begin); if (ret == WS_SUCCESS) { WOLFSSH_UNUSED(scratch); keySz = nSz + eSz + dSz + iqmpSz + pSz + qSz + commentSz + (LENGTH_SZ * 7); ret = PostAddRsaId(agent, keyType, key, keySz, nSz, eSz, dSz, iqmpSz, pSz, qSz, commentSz); } #endif } else if (keyType == ID_ECDSA_SHA2_NISTP256 || keyType == ID_ECDSA_SHA2_NISTP384 || keyType == ID_ECDSA_SHA2_NISTP521) { #ifndef WOLFSSH_NO_ECDSA byte* key; const byte* scratch; word32 keySz, curveNameSz, qSz, dSz, commentSz; key = buf + begin; /* curve name */ if (ret == WS_SUCCESS) ret = GetStringRef(&curveNameSz, &scratch, buf, len, &begin); /* Q */ if (ret == WS_SUCCESS) ret = GetMpint(&qSz, &scratch, buf, len, &begin); /* d */ if (ret == WS_SUCCESS) ret = GetMpint(&dSz, &scratch, buf, len, &begin); /* comment */ if (ret == WS_SUCCESS) ret = GetStringRef(&commentSz, &scratch, buf, len, &begin); if (ret == WS_SUCCESS) { keySz = curveNameSz + qSz + dSz + commentSz + (LENGTH_SZ * 4); ret = PostAddEcdsaId(agent, keyType, key, keySz, curveNameSz, qSz, dSz, commentSz); } #endif } else { ret = WS_PARSE_E; } } if (ret == WS_SUCCESS) *idx = begin; WLOG_LEAVE(ret); return ret; } static int DoRemoveIdentity(WOLFSSH_AGENT_CTX* agent, byte* buf, word32 len, word32* idx) { int ret = WS_SUCCESS; const byte* keyBlob = NULL; word32 keyBlobSz = 0; word32 begin; WLOG_ENTER(); DUMP(buf + *idx, len); if (agent == NULL || buf == NULL || len == 0 || idx == NULL) ret = WS_BAD_ARGUMENT; if (ret == WS_SUCCESS) { WLOG(WS_LOG_AGENT, "len = %u, idx = %u", len, *idx); begin = *idx; if (begin + LENGTH_SZ > len) { ret = WS_PARSE_E; } } if (ret == WS_SUCCESS) ret = GetStringRef(&keyBlobSz, &keyBlob, buf, len, &begin); if (ret == WS_SUCCESS) ret = PostRemoveId(agent, keyBlob, keyBlobSz); if (ret == WS_SUCCESS) *idx = begin; WLOG_LEAVE(ret); return ret; } static int DoRemoveAllIdentities(WOLFSSH_AGENT_CTX* agent, byte* buf, word32 len, word32* idx) { int ret = WS_SUCCESS; WLOG_ENTER(); if (buf == NULL || len != 0 || idx == NULL) ret = WS_BAD_ARGUMENT; if (ret == WS_SUCCESS) { DUMP(buf + *idx, len); } if (ret == WS_SUCCESS) ret = PostRemoveAllIds(agent); WLOG_LEAVE(ret); return ret; } static int DoAgentLock(WOLFSSH_AGENT_CTX* agent, byte* buf, word32 len, word32* idx) { int ret = WS_SUCCESS; word32 begin; byte* passphrase; word32 passphraseSz; WLOG(WS_LOG_AGENT, "Entering DoAgentLock()"); if (agent == NULL || buf == NULL || len == 0 || idx == NULL) ret = WS_BAD_ARGUMENT; if (ret == WS_SUCCESS) { WLOG(WS_LOG_AGENT, "len = %u, idx = %u", len, *idx); begin = *idx; if (begin + LENGTH_SZ > len) { ret = WS_PARSE_E; } } if (ret == WS_SUCCESS) { ato32(buf + begin, &passphraseSz); begin += LENGTH_SZ; if (begin + passphraseSz > len) { ret = WS_PARSE_E; } } if (ret == WS_SUCCESS) { passphrase = buf + begin; begin += passphraseSz; ret = PostLock(agent, passphrase, passphraseSz); } if (ret == WS_SUCCESS) *idx = begin; WLOG(WS_LOG_AGENT, "Leaving DoAgentLock(), ret = %d", ret); return ret; } static int DoAgentUnlock(WOLFSSH_AGENT_CTX* agent, byte* buf, word32 len, word32* idx) { int ret = WS_SUCCESS; word32 begin; byte* passphrase; word32 passphraseSz; WLOG(WS_LOG_AGENT, "Entering DoAgentUnlock()"); if (agent == NULL || buf == NULL || len == 0 || idx == NULL) ret = WS_BAD_ARGUMENT; if (ret == WS_SUCCESS) { begin = *idx; if (begin + LENGTH_SZ > len) ret = WS_PARSE_E; } if (ret == WS_SUCCESS) { ato32(buf + begin, &passphraseSz); begin += LENGTH_SZ; if (begin + passphraseSz > len) ret = WS_PARSE_E; } if (ret == WS_SUCCESS) { passphrase = buf + begin; begin += passphraseSz; ret = PostUnlock(agent, passphrase, passphraseSz); } if (ret == WS_SUCCESS) *idx = begin; WLOG(WS_LOG_AGENT, "Leaving DoAgentUnlock(), ret = %d", ret); return ret; } static int DoUnimplemented(WOLFSSH_AGENT_CTX* agent, byte* buf, word32 len, word32* idx) { int ret = WS_SUCCESS; WLOG_ENTER(); if (agent == NULL || idx == NULL) ret = WS_BAD_ARGUMENT; WOLFSSH_UNUSED(buf); DUMP(buf + *idx, len); /* Just skip the message. */ if (ret == WS_SUCCESS) { *idx = len; ret = SendFailure(agent); } if (ret == WS_SUCCESS) ret = WS_UNIMPLEMENTED_E; WLOG_LEAVE(ret); return ret; } /* len is the length of the blob of received data idx is in the index value into buf */ static int DoMessage(WOLFSSH_AGENT_CTX* agent, byte* buf, word32 len, word32* idx) { int ret = WS_SUCCESS; word32 payloadSz, payloadIdx; word32 begin; byte msg; WLOG(WS_LOG_AGENT, "Entering DoMessage()"); if (agent == NULL) ret = WS_SSH_NULL_E; /* WS_AGENT_NULL_E */ if (ret == WS_SUCCESS) { if (buf == NULL || idx == NULL || len == 0) ret = WS_BAD_ARGUMENT; } if (ret == WS_SUCCESS) { WLOG(WS_LOG_AGENT, "len = %u, idx = %u", len, *idx); begin = *idx; if (begin > len) { ret = WS_OVERFLOW_E; } } if (ret == WS_SUCCESS) { if (LENGTH_SZ + MSG_ID_SZ + begin > len) { ret = WS_OVERFLOW_E; } } if (ret == WS_SUCCESS) { ato32(buf + begin, &payloadSz); WLOG(WS_LOG_AGENT, "payloadSz = %u", payloadSz); begin += LENGTH_SZ; if (payloadSz > len - begin) { ret = WS_OVERFLOW_E; } } if (ret == WS_SUCCESS) { msg = buf[begin++]; payloadIdx = 0; switch (msg) { case MSGID_AGENT_FAILURE: WLOG(WS_LOG_AGENT, "Decoding MSGID_AGENT_FAILURE"); ret = DoFailure(agent, buf + begin, payloadSz - 1, &payloadIdx); break; case MSGID_AGENT_SUCCESS: WLOG(WS_LOG_AGENT, "Decoding MSGID_AGENT_SUCCESS"); ret = DoSuccess(agent, buf + begin, payloadSz - 1, &payloadIdx); break; case MSGID_AGENT_REQUEST_IDENTITIES: WLOG(WS_LOG_AGENT, "Decoding MSGID_AGENT_REQUEST_IDENTITIES"); ret = DoRequestIdentities(agent, buf + begin, payloadSz - 1, &payloadIdx); break; case MSGID_AGENT_IDENTITIES_ANSWER: WLOG(WS_LOG_AGENT, "Decoding MSGID_AGENT_IDENTITIES_ANSWER"); ret = DoIdentitiesAnswer(agent, buf + begin, payloadSz - 1, &payloadIdx); break; case MSGID_AGENT_SIGN_REQUEST: WLOG(WS_LOG_AGENT, "Decoding MSGID_AGENT_SIGN_REQUEST"); ret = DoSignRequest(agent, buf + begin, payloadSz - 1, &payloadIdx); break; case MSGID_AGENT_SIGN_RESPONSE: WLOG(WS_LOG_AGENT, "Decoding MSGID_AGENT_SIGN_RESPONSE"); ret = DoSignResponse(agent, buf + begin, payloadSz - 1, &payloadIdx); break; case MSGID_AGENT_ADD_IDENTITY: WLOG(WS_LOG_AGENT, "Decoding MSGID_AGENT_ADD_IDENTITY"); ret = DoAddIdentity(agent, buf + begin, payloadSz - 1, &payloadIdx); break; case MSGID_AGENT_REMOVE_IDENTITY: WLOG(WS_LOG_AGENT, "Decoding MSGID_AGENT_REMOVE_IDENTITY"); ret = DoRemoveIdentity(agent, buf + begin, payloadSz - 1, &payloadIdx); break; case MSGID_AGENT_REMOVE_ALL_IDENTITIES: WLOG(WS_LOG_AGENT, "Decoding MSGID_AGENT_REMOVE_ALL_IDENTITIES"); ret = DoRemoveAllIdentities(agent, buf + begin, payloadSz - 1, &payloadIdx); break; case MSGID_AGENT_LOCK: WLOG(WS_LOG_AGENT, "Decoding MSGID_AGENT_LOCK"); ret = DoAgentLock(agent, buf + begin, payloadSz - 1, &payloadIdx); break; case MSGID_AGENT_UNLOCK: WLOG(WS_LOG_AGENT, "Decoding MSGID_AGENT_UNLOCK"); ret = DoAgentUnlock(agent, buf + begin, payloadSz - 1, &payloadIdx); break; case MSGID_AGENT_ADD_ID_CONSTRAINED: case MSGID_AGENT_ADD_SMARTCARD_KEY_CONSTRAINED: case MSGID_AGENT_EXTENSION: case MSGID_AGENT_EXTENSION_FAILURE: case MSGID_AGENT_ADD_SMARTCARD_KEY: case MSGID_AGENT_REMOVE_SMARTCARD_KEY: default: WLOG(WS_LOG_AGENT, "Unimplemented message ID (%d)", msg); ret = DoUnimplemented(agent, buf + begin, payloadSz - 1, &payloadIdx); } } if (ret == WS_SUCCESS) { begin += payloadIdx; *idx = begin; } WLOG(WS_LOG_AGENT, "Leaving DoMessage(), ret = %d", ret); return ret; } static WOLFSSH_AGENT_CTX* AgentInit(WOLFSSH_AGENT_CTX* agent, void* heap) { WLOG(WS_LOG_AGENT, "Entering AgentInit()"); if (agent != NULL) { int ret; WMEMSET(agent, 0, sizeof(WOLFSSH_AGENT_CTX)); agent->heap = heap; agent->state = AGENT_STATE_INIT; ret = wc_InitRng(&agent->rng); if (ret != 0) { WMEMSET(agent, 0, sizeof(WOLFSSH_AGENT_CTX)); WFREE(agent, heap, DYNTYPE_AGENT); agent = NULL; } } WLOG(WS_LOG_AGENT, "Leaving AgentInit(), agent = %p", agent); return agent; } WOLFSSH_AGENT_CTX* wolfSSH_AGENT_new(void* heap) { WOLFSSH_AGENT_CTX* agent; WLOG(WS_LOG_AGENT, "Entering wolfSSH_AGENT_new()"); agent = (WOLFSSH_AGENT_CTX*)WMALLOC(sizeof(*agent), heap, DYNTYPE_AGENT); agent = AgentInit(agent, heap); WLOG(WS_LOG_AGENT, "Leaving wolfSSH_AGENT_new(), agent = %p", agent); return agent; } void wolfSSH_AGENT_free(WOLFSSH_AGENT_CTX* agent) { void* heap = agent->heap; WLOG(WS_LOG_AGENT, "Entering wolfSSH_AGENT_free()"); if (agent != NULL) { if (agent->msg != NULL) WFREE(agent->msg, agent->heap, DYNTYPE_AGENT_BUFFER); wc_FreeRng(&agent->rng); wolfSSH_AGENT_ID_list_free(agent->idList, heap); WMEMSET(agent, 0, sizeof(*agent)); WFREE(agent, heap, DYNTYPE_AGENT); } WLOG(WS_LOG_AGENT, "Leaving wolfSSH_AGENT_free()"); } WOLFSSH_AGENT_ID* wolfSSH_AGENT_ID_new(byte keyType, word32 keySz, void* heap) { WOLFSSH_AGENT_ID* id = NULL; byte* buffer = NULL; WLOG(WS_LOG_AGENT, "Entering wolfSSH_AGENT_ID_new()"); id = (WOLFSSH_AGENT_ID*)WMALLOC(sizeof(WOLFSSH_AGENT_ID), heap, DYNTYPE_AGENT_ID); if (id != NULL) { buffer = (byte*)WMALLOC(keySz, heap, DYNTYPE_STRING); if (buffer == NULL) { WFREE(id, heap, DYNTYPE_AGENT_ID); id = NULL; } } if (id != NULL && buffer != NULL) { WMEMSET(id, 0, sizeof(WOLFSSH_AGENT_ID)); WMEMSET(buffer, 0, keySz); id->keyType = keyType; id->keyBuffer = buffer; id->keyBufferSz = keySz; } WLOG(WS_LOG_AGENT, "Leaving wolfSSH_AGENT_ID_new(), id = %p", id); return id; } void wolfSSH_AGENT_ID_free(WOLFSSH_AGENT_ID* id, void* heap) { WLOG(WS_LOG_AGENT, "Entering wolfSSH_AGENT_ID_free()"); WOLFSSH_UNUSED(heap); if (id != NULL) { if (id->keyBuffer != NULL) { WMEMSET(id->keyBuffer, 0, id->keyBufferSz); WFREE(id->keyBuffer, heap, DYNTYPE_STRING); } WMEMSET(id, 0, sizeof(WOLFSSH_AGENT_ID)); WFREE(id, heap, DYNTYPE_AGENT_ID); } WLOG(WS_LOG_AGENT, "Leaving wolfSSH_AGENT_ID_free()"); } void wolfSSH_AGENT_ID_list_free(WOLFSSH_AGENT_ID* id, void* heap) { WLOG(WS_LOG_AGENT, "Entering wolfSSH_AGENT_ID_list_free()"); while (id != NULL) { WOLFSSH_AGENT_ID* next = id->next; wolfSSH_AGENT_ID_free(id, heap); id = next; } WLOG(WS_LOG_AGENT, "Leaving wolfSSH_AGENT_ID_list_free()"); } int wolfSSH_CTX_set_agent_cb(WOLFSSH_CTX* ctx, WS_CallbackAgent agentCb, WS_CallbackAgentIO agentIoCb) { int ret = WS_SUCCESS; if (ctx == NULL) ret = WS_BAD_ARGUMENT; if (ret == WS_SUCCESS) { ctx->agentCb = agentCb; ctx->agentIoCb = agentIoCb; } return ret; } int wolfSSH_set_agent_cb_ctx(WOLFSSH* ssh, void* ctx) { int ret = WS_SUCCESS; if (ssh == NULL) ret = WS_BAD_ARGUMENT; if (ret == WS_SUCCESS) { ssh->agentCbCtx = ctx; } return ret; } int wolfSSH_CTX_AGENT_enable(WOLFSSH_CTX* ctx, byte isEnabled) { int ret = WS_SUCCESS; WLOG_ENTER(); if (ctx == NULL) ret = WS_SSH_CTX_NULL_E; if (ret == WS_SUCCESS) ctx->agentEnabled = isEnabled; WLOG_LEAVE(ret); return ret; } int wolfSSH_AGENT_enable(WOLFSSH* ssh, byte isEnabled) { int ret = WS_SUCCESS; WLOG_ENTER(); if (ssh == NULL) ret = WS_SSH_NULL_E; if (ret == WS_SUCCESS) ssh->agentEnabled = isEnabled; WLOG_LEAVE(ret); return ret; } int wolfSSH_AGENT_worker(WOLFSSH* ssh) { int ret = WS_SUCCESS; WLOG_ENTER(); if (ssh == NULL) ret = WS_SSH_NULL_E; while (1) { if (ret == WS_SUCCESS) { SendSuccess(NULL); DoMessage(NULL, NULL, 0, NULL); ssh->agent->state = AGENT_STATE_DONE; break; } } WLOG_LEAVE(ret); return ret; } int wolfSSH_AGENT_Relay(WOLFSSH* ssh, const byte* msg, word32* msgSz, byte* rsp, word32* rspSz) { WOLFSSH_AGENT_CTX* agent = NULL; int ret = WS_SUCCESS, sz; WLOG_ENTER(); if (ssh == NULL) ret = WS_SSH_NULL_E; if (ret == WS_SUCCESS) { if (ssh->agent == NULL) ret = WS_AGENT_NULL_E; } if (ret == WS_SUCCESS) { if (msg == NULL || msgSz == NULL || rsp == NULL || rspSz == NULL) ret = WS_BAD_ARGUMENT; } if (ret == WS_SUCCESS) { agent = ssh->agent; if (agent->state == AGENT_STATE_INIT) { if (ssh->ctx->agentCb) { ret = ssh->ctx->agentCb(WOLFSSH_AGENT_LOCAL_SETUP, ssh->agentCbCtx); if (ret == WS_AGENT_SUCCESS) agent->state = AGENT_STATE_CONNECTED; else ret = WS_AGENT_CXN_FAIL; } } } if (ret == WS_SUCCESS) { /* Write msg to the agent socket. */ sz = ssh->ctx->agentIoCb(WOLFSSH_AGENT_IO_WRITE, (byte*)msg, *msgSz, ssh->agentCbCtx); if (sz > 0) { *msgSz = (word32)sz; } else { if (ret == WS_CBIO_ERR_GENERAL) { if (ssh->ctx->agentCb) { ret = ssh->ctx->agentCb(WOLFSSH_AGENT_LOCAL_SETUP, ssh->agentCbCtx); if (ret != WS_AGENT_SUCCESS) ret = WS_AGENT_CXN_FAIL; } if (ret == WS_AGENT_SUCCESS) { sz = ssh->ctx->agentIoCb(WOLFSSH_AGENT_IO_WRITE, (byte*)msg, *msgSz, ssh->agentCbCtx); if (sz > 0) *msgSz = (word32)sz; else ret = WS_AGENT_CXN_FAIL; } } } } if (ret == WS_SUCCESS) { sz = ssh->ctx->agentIoCb(WOLFSSH_AGENT_IO_READ, rsp, *rspSz, ssh->agentCbCtx); if (sz > 0) *rspSz = (word32)sz; else ret = WS_AGENT_CXN_FAIL; } if (ret == WS_AGENT_SUCCESS) ret = WS_SUCCESS; else { if (agent != NULL) agent->error = ret; if (ssh != NULL) ssh->error = ret; ret = WS_ERROR; } WLOG_LEAVE(ret); return ret; } int wolfSSH_AGENT_SignRequest(WOLFSSH* ssh, const byte* digest, word32 digestSz, byte* sig, word32* sigSz, const byte* keyBlob, word32 keyBlobSz, word32 flags) { int ret = WS_SUCCESS; byte rxBuf[512]; int rxSz; word32 idx = 0; WOLFSSH_AGENT_CTX* agent = NULL; WLOG_ENTER(); if (ssh == NULL) ret = WS_SSH_NULL_E; if (ret == WS_SUCCESS) { if (ssh->agent == NULL) ret = WS_AGENT_NULL_E; } if (ret == WS_SUCCESS) { if (sigSz == NULL) ret = WS_BAD_ARGUMENT; } if (ret == WS_SUCCESS) { agent = ssh->agent; if (ssh->ctx->agentCb) ret = ssh->ctx->agentCb(WOLFSSH_AGENT_LOCAL_SETUP, ssh->agentCbCtx); } if (ret == WS_SUCCESS) ret = SendSignRequest(agent, digest, digestSz, keyBlob, keyBlobSz, flags); if (ret == WS_SUCCESS) ret = ssh->ctx->agentIoCb(WOLFSSH_AGENT_IO_WRITE, agent->msg, agent->msgSz, ssh->agentCbCtx); if (ret > 0) ret = WS_SUCCESS; if (agent != NULL && agent->msg != NULL) { WFREE(ssh->agent->msg, ssh->agent->heap, DYNTYPE_AGENT_BUFFER); ssh->agent->msg = NULL; ssh->agent->msgSz = 0; } if (ret == WS_SUCCESS) { rxSz = ssh->ctx->agentIoCb(WOLFSSH_AGENT_IO_READ, rxBuf, sizeof(rxBuf), ssh->agentCbCtx); if (rxSz > 0) { ret = DoMessage(ssh->agent, rxBuf, rxSz, &idx); 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; } if (agent != NULL) { agent->msg = NULL; agent->msgSz = 0; } if (ssh != NULL && ssh->ctx != NULL && ssh->ctx->agentCb != NULL) { ssh->ctx->agentCb(WOLFSSH_AGENT_LOCAL_CLEANUP, ssh->agentCbCtx); } WLOG_LEAVE(ret); return ret; } #endif /* WOLFSSH_AGENT */