ssh: add a rekey-state accessor

- wolfSSH_RekeyPending() reports whether a key exchange is in flight,
  returning 0 for a NULL session so a caller may test it directly in
  a loop condition.
- the wolfSSH_worker() block in ssh.h names it as the way to ask,
  alongside wolfSSH_OutputPending().
- tests/regress.c covers each keying bit alone, both together, and a
  NULL session for both predicates.
- tests/testsuite.c drops its wolfSSH_OutputPending() call; a public
  function without a WOLFSSH_API prototype fails -Wmissing-prototypes
  in src/ssh.c, so the call proved nothing the build did not.
pull/1260/head
Yosuke Shimizu 2026-09-17 15:27:16 +09:00
parent 74491247cb
commit cb902fa0f7
5 changed files with 49 additions and 7 deletions

View File

@ -4715,6 +4715,12 @@ int wolfSSH_OutputPending(const WOLFSSH* ssh)
}
int wolfSSH_RekeyPending(const WOLFSSH* ssh)
{
return (ssh != NULL && ssh->isKeying != 0);
}
#ifdef WOLFSSH_FWD
int wolfSSH_CTX_SetFwdCb(WOLFSSH_CTX* ctx,

View File

@ -5893,6 +5893,39 @@ static void TestChannelGetSessionGrantedAccessor(void)
}
/* Covers each keying bit alone, both together, and a NULL session. */
static void TestRekeyPendingAccessor(void)
{
WOLFSSH_CTX* ctx;
WOLFSSH* ssh;
AssertIntEQ(wolfSSH_RekeyPending(NULL), 0);
AssertIntEQ(wolfSSH_OutputPending(NULL), 0);
ctx = wolfSSH_CTX_new(WOLFSSH_ENDPOINT_CLIENT, NULL);
AssertNotNull(ctx);
ssh = wolfSSH_new(ctx);
AssertNotNull(ssh);
AssertIntEQ(wolfSSH_RekeyPending(ssh), 0);
ssh->isKeying = WOLFSSH_PEER_IS_KEYING;
AssertTrue(wolfSSH_RekeyPending(ssh) != 0);
ssh->isKeying = WOLFSSH_SELF_IS_KEYING;
AssertTrue(wolfSSH_RekeyPending(ssh) != 0);
ssh->isKeying = WOLFSSH_SELF_IS_KEYING | WOLFSSH_PEER_IS_KEYING;
AssertTrue(wolfSSH_RekeyPending(ssh) != 0);
ssh->isKeying = 0;
AssertIntEQ(wolfSSH_RekeyPending(ssh), 0);
wolfSSH_free(ssh);
wolfSSH_CTX_free(ctx);
}
/* A username change after the first userauth request must end the session. */
static void TestUsernameChangeDisconnects(void)
{
@ -16038,6 +16071,7 @@ int main(int argc, char** argv)
TestChannelReqSubsysCallbackRuns();
TestSessionReqCallbackSeesCommandSz();
TestChannelGetSessionGrantedAccessor();
TestRekeyPendingAccessor();
TestMalformedSessionRequestSkipsCallback();
TestSessionReqCallbackMayFreeChannel();
TestAppChannelsAcceptKeepsStopWithPendingOutput();

View File

@ -241,13 +241,6 @@ int wolfSSH_TestsuiteTest(int argc, char** argv)
wolfSSH_Init();
/* Linked against the installed library, so this also proves
* wolfSSH_OutputPending() is exported and not hidden. */
if (wolfSSH_OutputPending(NULL) != 0) {
fprintf(stderr, "wolfSSH_OutputPending(NULL) was not zero\n");
return EXIT_FAILURE;
}
#if defined(FIPS_VERSION_GE) && FIPS_VERSION_GE(5,2)
{
int i;

View File

@ -7189,6 +7189,8 @@ static int test_WorkerKeyingReportsRekey(void)
if (reportedId != ch->channel) { result = -1818; goto done; }
/* The flush ran and drained, which the rekey report is gated on. */
if (ssh->outputBuffer.length != 0) { result = -1817; goto done; }
/* The predicate answers the same pass the status reports. */
if (!wolfSSH_RekeyPending(ssh)) { result = -1819; goto done; }
done:
s_recvPkt = NULL;

View File

@ -104,6 +104,8 @@ WOLFSSH_API void wolfSSH_free(WOLFSSH* ssh);
* the peer's disconnect, which is how most sessions end.
* To ask whether a write is still owed, call wolfSSH_OutputPending() rather
* than reading a status: it answers after any return, including a success.
* To ask whether a key exchange is in flight, call wolfSSH_RekeyPending()
* rather than reading a status: it answers after any return.
*
* For WS_CHAN_RXD, WS_EXTDATA, WS_EOF, WS_SUCCESS and a WS_REKEYING that
* displaced one of those, channelId (when not NULL) names the channel the
@ -118,6 +120,11 @@ WOLFSSH_API int wolfSSH_GetLastRxId(WOLFSSH* ssh, word32* channelId);
/* Returns nonzero if a write is still owed. Session state */
WOLFSSH_API int wolfSSH_OutputPending(const WOLFSSH* ssh);
/* Returns nonzero while a key exchange is in flight, and 0 otherwise,
* including when ssh is NULL. Only NEWKEYS from both sides clears it, so a
* peer that abandons the exchange leaves it set. */
WOLFSSH_API int wolfSSH_RekeyPending(const WOLFSSH* ssh);
WOLFSSH_API int wolfSSH_set_fd(WOLFSSH* ssh, WS_SOCKET_T fd);
WOLFSSH_API WS_SOCKET_T wolfSSH_get_fd(const WOLFSSH* ssh);