Skip to content

Commit 7b97ef3

Browse files
committed
agent: let the application open the agent channel
The one server-side site that opens auth-agent@openssh.com sits inside wolfSSH_accept(), so an application driving its own channels cannot reach it: the session records the request and no channel follows. - add wolfSSH_AGENT_ChannelOpen(), the same open lifted out of accept(), which still calls it - it reports WS_BAD_ARGUMENT until the peer asks and is idempotent afterward, so an application can poll it - publish the agent on a queued open too, so a retry after WS_WANT_WRITE finds it rather than opening a second channel and leaking the first - flush what is left of a queued open on the next call, rather than reporting a success the peer never saw
1 parent fb15a05 commit 7b97ef3

4 files changed

Lines changed: 119 additions & 41 deletions

File tree

src/agent.c

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1731,6 +1731,76 @@ int wolfSSH_AGENT_enable(WOLFSSH* ssh, byte isEnabled)
17311731
}
17321732

17331733

1734+
int wolfSSH_AGENT_ChannelOpen(WOLFSSH* ssh)
1735+
{
1736+
WOLFSSH_AGENT_CTX* newAgent = NULL;
1737+
WOLFSSH_CHANNEL* newChannel = NULL;
1738+
int ret = WS_SUCCESS;
1739+
1740+
WLOG_ENTER();
1741+
1742+
if (ssh == NULL)
1743+
ret = WS_SSH_NULL_E;
1744+
else if (!ssh->useAgent) {
1745+
/* Nothing asked for agent forwarding on this session. */
1746+
ret = WS_BAD_ARGUMENT;
1747+
}
1748+
else if (ssh->agent == NULL) {
1749+
/* Server side sets ssh->agent here and nowhere else, so a NULL one
1750+
* is the "not opened yet" test. Idempotent so a caller polling for
1751+
* the peer's request cannot end up with two agent channels. */
1752+
WLOG(WS_LOG_AGENT, "Starting agent channel");
1753+
1754+
newAgent = wolfSSH_AGENT_new(ssh->ctx->heap);
1755+
if (newAgent == NULL)
1756+
ret = WS_MEMORY_E;
1757+
1758+
if (ret == WS_SUCCESS) {
1759+
newChannel = ChannelNew(ssh, ID_CHANTYPE_AUTH_AGENT,
1760+
ssh->ctx->windowSz, ssh->ctx->maxPacketSz);
1761+
if (newChannel == NULL)
1762+
ret = WS_MEMORY_E;
1763+
}
1764+
1765+
if (ret == WS_SUCCESS) {
1766+
ret = SendChannelOpenSession(ssh, newChannel);
1767+
1768+
if (ret < WS_SUCCESS
1769+
&& ret != WS_WANT_WRITE && ret != WS_WANT_READ) {
1770+
ChannelDelete(newChannel, ssh->ctx->heap);
1771+
}
1772+
else {
1773+
/* Publish the agent even when the open is only queued, so
1774+
* a retry takes the already-open path above rather than
1775+
* opening a second channel. */
1776+
ChannelAppend(ssh, newChannel);
1777+
newAgent->channel = newChannel->channel;
1778+
ssh->agent = newAgent;
1779+
newAgent = NULL;
1780+
if (ssh->ctx->agentCb) {
1781+
ssh->ctx->agentCb(WOLFSSH_AGENT_LOCAL_SETUP,
1782+
ssh->agentCbCtx);
1783+
}
1784+
}
1785+
}
1786+
1787+
if (newAgent != NULL)
1788+
wolfSSH_AGENT_free(newAgent);
1789+
}
1790+
else if (wolfSSH_OutputPending(ssh)) {
1791+
/* The open is framed but not on the wire. Flush it rather than
1792+
* report a success the peer hasn't seen. */
1793+
ret = wolfSSH_SendPacket(ssh);
1794+
}
1795+
1796+
if (ssh != NULL)
1797+
ssh->error = ret;
1798+
1799+
WLOG_LEAVE(ret);
1800+
return ret;
1801+
}
1802+
1803+
17341804
int wolfSSH_AGENT_worker(WOLFSSH* ssh)
17351805
{
17361806
int ret = WS_SUCCESS;

src/ssh.c

Lines changed: 1 addition & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -764,52 +764,12 @@ int wolfSSH_accept(WOLFSSH* ssh)
764764
#endif /* WOLFSSH_SFTP and !NO_WOLFSSH_SERVER */
765765
#ifdef WOLFSSH_AGENT
766766
if (ssh->useAgent) {
767-
WOLFSSH_AGENT_CTX* newAgent;
768-
WOLFSSH_CHANNEL* newChannel;
769-
770-
WLOG(WS_LOG_AGENT, "Starting agent channel");
771-
772-
newAgent = wolfSSH_AGENT_new(ssh->ctx->heap);
773-
if (newAgent == NULL) {
774-
ssh->error = WS_MEMORY_E;
775-
WLOG(WS_LOG_DEBUG, acceptError,
776-
"SERVER_USERAUTH_ACCEPT_DONE", ssh->error);
777-
return WS_ERROR;
778-
}
779-
780-
newChannel = ChannelNew(ssh, ID_CHANTYPE_AUTH_AGENT,
781-
ssh->ctx->windowSz, ssh->ctx->maxPacketSz);
782-
if (newChannel == NULL) {
783-
wolfSSH_AGENT_free(newAgent);
784-
ssh->error = WS_MEMORY_E;
785-
WLOG(WS_LOG_DEBUG, acceptError,
786-
"SERVER_USERAUTH_ACCEPT_DONE", ssh->error);
787-
return WS_FATAL_ERROR;
788-
}
789-
790-
ssh->error = SendChannelOpenSession(ssh, newChannel);
767+
ssh->error = wolfSSH_AGENT_ChannelOpen(ssh);
791768
if (ssh->error < WS_SUCCESS) {
792-
if (ssh->error == WS_WANT_WRITE ||
793-
ssh->error == WS_WANT_READ) {
794-
ChannelAppend(ssh, newChannel);
795-
}
796-
else {
797-
ChannelDelete(newChannel, ssh->ctx->heap);
798-
wolfSSH_AGENT_free(newAgent);
799-
}
800769
WLOG(WS_LOG_DEBUG, acceptError,
801770
"SERVER_USERAUTH_ACCEPT_DONE", ssh->error);
802771
return WS_FATAL_ERROR;
803772
}
804-
ChannelAppend(ssh, newChannel);
805-
newAgent->channel = newChannel->channel;
806-
if (ssh->ctx->agentCb) {
807-
ssh->ctx->agentCb(WOLFSSH_AGENT_LOCAL_SETUP,
808-
ssh->agentCbCtx);
809-
}
810-
if (ssh->agent != NULL)
811-
wolfSSH_AGENT_free(ssh->agent);
812-
ssh->agent = newAgent;
813773
}
814774
#endif /* WOLFSSH_AGENT */
815775
ssh->acceptState = ACCEPT_CLIENT_SESSION_ESTABLISHED;

tests/regress.c

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4437,6 +4437,45 @@ static void TestAgentChannelNullAgentSendsOpenFail(void)
44374437

44384438
FreeChannelOpenHarness(&harness);
44394439
}
4440+
4441+
/* Nothing asked for forwarding, so the open is refused rather than started. */
4442+
static void TestAgentChannelOpenWithoutRequest(void)
4443+
{
4444+
ChannelOpenHarness harness;
4445+
4446+
InitChannelOpenHarness(&harness, NULL, 0);
4447+
4448+
AssertIntEQ(wolfSSH_AGENT_ChannelOpen(harness.ssh), WS_BAD_ARGUMENT);
4449+
AssertNull(harness.ssh->agent);
4450+
AssertIntEQ(harness.io.outSz, 0);
4451+
4452+
FreeChannelOpenHarness(&harness);
4453+
}
4454+
4455+
/* A queued open publishes the agent, so the caller's next poll must finish
4456+
* the send rather than report a success the peer never saw, and must not
4457+
* open a second channel. */
4458+
static void TestAgentChannelOpenFlushesQueuedOpen(void)
4459+
{
4460+
ChannelOpenHarness harness;
4461+
4462+
InitChannelOpenHarness(&harness, NULL, 0);
4463+
harness.ssh->useAgent = 1;
4464+
harness.io.blockNext = 1;
4465+
4466+
AssertIntEQ(wolfSSH_AGENT_ChannelOpen(harness.ssh), WS_WANT_WRITE);
4467+
AssertNotNull(harness.ssh->agent);
4468+
AssertIntEQ(harness.ssh->channelListSz, 1);
4469+
AssertIntEQ(harness.io.outSz, 0);
4470+
4471+
AssertIntEQ(wolfSSH_AGENT_ChannelOpen(harness.ssh), WS_SUCCESS);
4472+
AssertIntEQ(harness.ssh->channelListSz, 1);
4473+
AssertTrue(harness.io.outSz > 0);
4474+
AssertIntEQ(ParseMsgId(harness.io.out, harness.io.outSz),
4475+
MSGID_CHANNEL_OPEN);
4476+
4477+
FreeChannelOpenHarness(&harness);
4478+
}
44404479
#endif
44414480

44424481

@@ -13427,6 +13466,8 @@ int main(int argc, char** argv)
1342713466
#endif
1342813467
#ifdef WOLFSSH_AGENT
1342913468
TestAgentChannelNullAgentSendsOpenFail();
13469+
TestAgentChannelOpenWithoutRequest();
13470+
TestAgentChannelOpenFlushesQueuedOpen();
1343013471
#endif
1343113472
#endif /* NO_WOLFSSH_SERVER */
1343213473
#if defined(WOLFSSH_AGENT) && !defined(WOLFSSH_NO_ED25519) \

wolfssh/agent.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,13 @@ WOLFSSH_API int wolfSSH_CTX_set_agent_cb(WOLFSSH_CTX* ctx,
181181
WOLFSSH_API int wolfSSH_set_agent_cb_ctx(WOLFSSH* ssh, void* ctx);
182182
WOLFSSH_API int wolfSSH_CTX_AGENT_enable(WOLFSSH_CTX* ctx, byte isEnabled);
183183
WOLFSSH_API int wolfSSH_AGENT_enable(WOLFSSH* ssh, byte isEnabled);
184+
/* Server side. Opens the auth-agent@openssh.com channel to the client once
185+
* the peer's auth-agent-req@openssh.com asks for forwarding. wolfSSH_accept()
186+
* does it on the default path; an application driving its own channels polls
187+
* this instead. Opens one channel, then flushes what of the open is queued.
188+
* Returns WS_SUCCESS, WS_BAD_ARGUMENT before the peer asks, WS_WANT_READ or
189+
* WS_WANT_WRITE with the open queued, WS_SSH_NULL_E, or WS_MEMORY_E. */
190+
WOLFSSH_API int wolfSSH_AGENT_ChannelOpen(WOLFSSH* ssh);
184191
WOLFSSH_LOCAL int wolfSSH_AGENT_worker(WOLFSSH* ssh);
185192
WOLFSSH_API int wolfSSH_AGENT_Relay(WOLFSSH* ssh,
186193
const byte* msg, word32* msgSz, byte* rsp, word32* rspSz);

0 commit comments

Comments
 (0)