Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 12 additions & 6 deletions apps/wolfssh/wolfssh.c
Original file line number Diff line number Diff line change
Expand Up @@ -877,6 +877,8 @@ static int wolfSSH_AGENT_DefaultActions(WS_AgentCbAction action, void* vCtx)
ret = WS_AGENT_SETUP_E;
err = errno;
fprintf(stderr, "connect() = %d", err);
close(ctx->fd);
ctx->fd = -1;
}
}

Expand All @@ -886,12 +888,15 @@ static int wolfSSH_AGENT_DefaultActions(WS_AgentCbAction action, void* vCtx)
else if (action == WOLFSSH_AGENT_LOCAL_CLEANUP) {
int err;

err = close(ctx->fd);
if (err != 0) {
err = errno;
fprintf(stderr, "close() = %d", err);
if (ret == 0)
ret = WS_AGENT_SETUP_E;
if (ctx->fd >= 0) {
err = close(ctx->fd);
ctx->fd = -1;
if (err != 0) {
err = errno;
fprintf(stderr, "close() = %d", err);
if (ret == 0)
ret = WS_AGENT_SETUP_E;
}
}
}
else
Expand Down Expand Up @@ -1246,6 +1251,7 @@ static THREAD_RETURN WOLFSSH_THREAD wolfSSH_Client(void* args)
#ifdef WOLFSSH_AGENT
if (useAgent) {
WMEMSET(&agentCbCtx, 0, sizeof(agentCbCtx));
agentCbCtx.fd = -1;
agentCbCtx.state = AGENT_STATE_INIT;
wolfSSH_set_agent_cb_ctx(ssh, &agentCbCtx);
}
Expand Down
18 changes: 12 additions & 6 deletions examples/client/client.c
Original file line number Diff line number Diff line change
Expand Up @@ -701,6 +701,8 @@ static int wolfSSH_AGENT_DefaultActions(WS_AgentCbAction action, void* vCtx)
ret = WS_AGENT_SETUP_E;
err = errno;
fprintf(stderr, "connect() = %d", err);
close(ctx->fd);
ctx->fd = -1;
}
}

Expand All @@ -710,12 +712,15 @@ static int wolfSSH_AGENT_DefaultActions(WS_AgentCbAction action, void* vCtx)
else if (action == WOLFSSH_AGENT_LOCAL_CLEANUP) {
int err;

err = close(ctx->fd);
if (err != 0) {
err = errno;
fprintf(stderr, "close() = %d", err);
if (ret == 0)
ret = WS_AGENT_SETUP_E;
if (ctx->fd >= 0) {
err = close(ctx->fd);
ctx->fd = -1;
if (err != 0) {
err = errno;
fprintf(stderr, "close() = %d", err);
if (ret == 0)
ret = WS_AGENT_SETUP_E;
}
}
}
else
Expand Down Expand Up @@ -1017,6 +1022,7 @@ THREAD_RETURN WOLFSSH_THREAD client_test(void* args)
#ifdef WOLFSSH_AGENT
if (useAgent) {
WMEMSET(&agentCbCtx, 0, sizeof(agentCbCtx));
agentCbCtx.fd = -1;
agentCbCtx.state = AGENT_STATE_INIT;
wolfSSH_set_agent_cb_ctx(ssh, &agentCbCtx);
}
Expand Down
117 changes: 46 additions & 71 deletions src/agent.c
Original file line number Diff line number Diff line change
Expand Up @@ -66,12 +66,6 @@
#endif


/* Read buffer size for a reply from an agent. Covers a signature and its
* message header for any key up to RSA-8192. */
#ifndef WOLFSSH_AGENT_MAX_RSP_SZ
#define WOLFSSH_AGENT_MAX_RSP_SZ 2048
#endif

/* Largest agent message this build will handle. The peer declares the
* length, so it is bounded before it drives an allocation. */
#ifndef WOLFSSH_AGENT_MAX_MSG_SZ
Expand Down Expand Up @@ -2289,9 +2283,10 @@ int wolfSSH_AGENT_SignRequest(WOLFSSH* ssh,
word32 flags)
{
int ret = WS_SUCCESS;
byte* rxBuf = NULL;
int rxSz;
byte* rsp = NULL;
word32 rspSz = 0;
word32 idx = 0;
byte setUp = 0;
WOLFSSH_AGENT_CTX* agent = NULL;

WLOG_ENTER();
Expand All @@ -2305,102 +2300,82 @@ int wolfSSH_AGENT_SignRequest(WOLFSSH* ssh,
}

if (ret == WS_SUCCESS) {
if (sigSz == NULL)
if (sig == NULL || sigSz == NULL
|| (digest == NULL && digestSz != 0)
|| (keyBlob == NULL && keyBlobSz != 0))
ret = WS_BAD_ARGUMENT;
}

if (ret == WS_SUCCESS) {
rxBuf = (byte*)WMALLOC(WOLFSSH_AGENT_MAX_RSP_SZ,
ssh->agent->heap, DYNTYPE_AGENT_BUFFER);
if (rxBuf == NULL)
ret = WS_MEMORY_E;
}

if (ret == WS_SUCCESS) {
agent = ssh->agent;
agent->requestFailure = 0;
agent->requestSuccess = 0;
agent->msg = NULL;
agent->msgSz = 0;
agent->lastMsgId = 0;
if (ssh->ctx->agentCb)
ret = ssh->ctx->agentCb(WOLFSSH_AGENT_LOCAL_SETUP, ssh->agentCbCtx);
if (ssh->ctx->agentCb) {
/* The callback answers in WS_AgentCbError, where failure is
* positive. */
if (ssh->ctx->agentCb(WOLFSSH_AGENT_LOCAL_SETUP, ssh->agentCbCtx)
!= WS_AGENT_SUCCESS) {
ret = WS_AGENT_CXN_FAIL;
}
else
setUp = 1;
}
}

if (ret == WS_SUCCESS)
ret = SendSignRequest(agent, digest, digestSz,
keyBlob, keyBlobSz, flags);

if (ret == WS_SUCCESS) {
int wrote;

wrote = ssh->ctx->agentIoCb(WOLFSSH_AGENT_IO_WRITE,
agent->msg, agent->msgSz, ssh->agentCbCtx);
if (wrote != (int)agent->msgSz) {
WLOG(WS_LOG_AGENT, "agent write incomplete");
ret = WS_AGENT_CXN_FAIL;
}
}
if (ret == WS_SUCCESS)
ret = AgentWriteAll(ssh, agent->msg, agent->msgSz, NULL);

if (agent != NULL && agent->msg != NULL) {
WFREE(ssh->agent->msg, ssh->agent->heap, DYNTYPE_AGENT_BUFFER);
ssh->agent->msg = NULL;
ssh->agent->msgSz = 0;
WFREE(agent->msg, agent->heap, DYNTYPE_AGENT_BUFFER);
agent->msg = NULL;
agent->msgSz = 0;
}

if (ret == WS_SUCCESS)
ret = AgentReadMessage(ssh, &rsp, &rspSz);

if (ret == WS_SUCCESS)
ret = DoMessage(agent, rsp, rspSz, &idx);

if (ret == WS_SUCCESS) {
rxSz = ssh->ctx->agentIoCb(WOLFSSH_AGENT_IO_READ,
rxBuf, WOLFSSH_AGENT_MAX_RSP_SZ, ssh->agentCbCtx);
if (rxSz > 0) {
ret = DoMessage(ssh->agent, rxBuf, rxSz, &idx);
if (ret == WS_SUCCESS) {
if (ssh->agent->lastMsgId != MSGID_AGENT_SIGN_RESPONSE) {
WLOG(WS_LOG_AGENT,
"agent response was not a signature message");
ret = WS_AGENT_NO_KEY_E;
}
else {
if (ssh->agent->requestFailure ||
ssh->agent->msg == NULL ||
ssh->agent->msgSz == 0) {
ssh->agent->requestFailure = 0;
ret = WS_AGENT_NO_KEY_E;
}
else {
word32 maxSigSz = *sigSz;

if (ssh->agent->msgSz > maxSigSz) {
WLOG(WS_LOG_AGENT,
"agent signature too large for caller buffer");
ret = WS_BUFFER_E;
}
else {
WMEMCPY(sig, ssh->agent->msg, ssh->agent->msgSz);
*sigSz = ssh->agent->msgSz;
}
}
}
}
if (agent->lastMsgId != MSGID_AGENT_SIGN_RESPONSE) {
WLOG(WS_LOG_AGENT, "agent response was not a signature message");
ret = WS_AGENT_NO_KEY_E;
}
else if (agent->requestFailure || agent->msg == NULL ||
agent->msgSz == 0) {
agent->requestFailure = 0;
ret = WS_AGENT_NO_KEY_E;
}
else if (agent->msgSz > *sigSz) {
WLOG(WS_LOG_AGENT, "agent signature too large for caller buffer");
ret = WS_BUFFER_E;
}
else {
WMEMCPY(sig, agent->msg, agent->msgSz);
*sigSz = agent->msgSz;
}
else ret = WS_AGENT_NO_KEY_E;
}

if (ret != WS_SUCCESS && sigSz != NULL)
*sigSz = 0;

if (agent != NULL) {
/* The reply was parsed in place out of rxBuf. */
agent->msg = NULL;
agent->msgSz = 0;
AgentBufferReset(agent->rxBuf);
}

if (ssh != NULL && ssh->ctx != NULL && ssh->ctx->agentCb != NULL) {
if (setUp)
ssh->ctx->agentCb(WOLFSSH_AGENT_LOCAL_CLEANUP, ssh->agentCbCtx);
}

/* The agent's message was parsed in place out of this buffer, so it is
* freed after the last use of agent->msg. */
if (rxBuf != NULL)
WFREE(rxBuf, ssh->agent->heap, DYNTYPE_AGENT_BUFFER);

WLOG_LEAVE(ret);
return ret;
Expand Down
84 changes: 70 additions & 14 deletions src/internal.c
Original file line number Diff line number Diff line change
Expand Up @@ -20959,7 +20959,21 @@ static int PrepareUserAuthRequestEcc(WOLFSSH* ssh, word32* payloadSz,

if (ret == WS_SUCCESS) {
if (authData->sf.publicKey.hasSignature) {
int sigSz = wc_ecc_sig_size(&keySig->ks.ecc.key);
int sigSz;

#ifdef WOLFSSH_AGENT
if (ssh->agentEnabled) {
/* The agent answers with r and s as mpints, each at most a
* pad byte over the curve size. */
sigSz = wc_ecc_size(&keySig->ks.ecc.key);
if (sigSz > 0)
sigSz = 2 * (sigSz + 1);
else
sigSz = WS_ECC_E;
}
else
#endif
sigSz = wc_ecc_sig_size(&keySig->ks.ecc.key);

if (sigSz >= 0) {
*payloadSz += (LENGTH_SZ * 5) + (word32)sigSz +
Expand All @@ -20976,8 +20990,9 @@ static int PrepareUserAuthRequestEcc(WOLFSSH* ssh, word32* payloadSz,
}


/* outputSz bounds the variable-length r/s mpint encoding; the fixed-size
* builders (RSA, Ed25519, ML-DSA) fit PreparePacket()'s estimate unbounded. */
/* outputSz bounds the variable-length r/s mpint encoding and the agent's
* blob; the fixed-size builders (RSA, Ed25519, ML-DSA) fit PreparePacket()'s
* estimate unbounded. */
static int BuildUserAuthRequestEcc(WOLFSSH* ssh,
byte* output, word32 outputSz, word32* idx,
const WS_UserAuthData* authData,
Expand Down Expand Up @@ -21046,23 +21061,64 @@ static int BuildUserAuthRequestEcc(WOLFSSH* ssh,

#ifdef WOLFSSH_AGENT
if (ssh->agentEnabled) {
if (ret == WS_SUCCESS)
/* The room PrepareUserAuthRequestEcc() reserved for the agent's
* signature blob: the algorithm name and the r and s mpints. */
word32 agentSigSz = (LENGTH_SZ * 4) + keySig->sigSz +
authData->sf.publicKey.publicKeyTypeSz;
const byte* agentSigName = NULL;
word32 agentSigNameSz = 0;
word32 nameIdx = 0;
byte effSigId = keySig->sigId;

#ifdef WOLFSSH_OSSH_CERTS
/* An OpenSSH certificate is dispatched by its cert id, but the
* agent signs under the curve's own name. */
switch (keySig->sigId) {
#ifndef WOLFSSH_NO_ECDSA_SHA2_NISTP256
case ID_OSSH_CERT_ECDSA_SHA2_NISTP256:
effSigId = ID_ECDSA_SHA2_NISTP256;
break;
#endif
#ifndef WOLFSSH_NO_ECDSA_SHA2_NISTP384
case ID_OSSH_CERT_ECDSA_SHA2_NISTP384:
effSigId = ID_ECDSA_SHA2_NISTP384;
break;
#endif
#ifndef WOLFSSH_NO_ECDSA_SHA2_NISTP521
case ID_OSSH_CERT_ECDSA_SHA2_NISTP521:
effSigId = ID_ECDSA_SHA2_NISTP521;
break;
#endif
default:
break;
}
#endif

if (ret == WS_SUCCESS && (outputSz <= begin ||
outputSz - begin < LENGTH_SZ + agentSigSz)) {
WLOG(WS_LOG_DEBUG, "SUAR: ECDSA agent sig doesn't fit output");
ret = WS_BUFFER_E;
}
if (ret == WS_SUCCESS) {
WLOG(WS_LOG_INFO, "Signing with ECDSA through the agent.");
ret = wolfSSH_AGENT_SignRequest(ssh, checkData, checkDataSz,
sig_ptr, &sigSz,
output + begin + LENGTH_SZ, &agentSigSz,
authData->sf.publicKey.publicKey,
authData->sf.publicKey.publicKeySz, 0);
}
/* An agent may answer under another algorithm or curve. */
if (ret == WS_SUCCESS) {
/* begin indexes into output, whose capacity is outputSz. */
if (outputSz <= begin || outputSz - begin < LENGTH_SZ + sigSz) {
WLOG(WS_LOG_DEBUG, "SUAR: ECDSA agent sig doesn't fit output");
ret = WS_BUFFER_E;
}
ret = GetStringRef(&agentSigNameSz, &agentSigName,
output + begin + LENGTH_SZ, agentSigSz, &nameIdx);
}
if (ret == WS_SUCCESS && NameToId((const char*)agentSigName,
agentSigNameSz) != effSigId) {
WLOG(WS_LOG_DEBUG, "SUAR: agent signed with another algorithm");
ret = WS_INVALID_ALGO_ID;
}
if (ret == WS_SUCCESS) {
c32toa(sigSz, output + begin);
begin += LENGTH_SZ;
XMEMCPY(output + begin, sig_ptr, sigSz);
begin += sigSz;
c32toa(agentSigSz, output + begin);
begin += LENGTH_SZ + agentSigSz;
}
}
else
Expand Down
Loading
Loading