diff --git a/src/ssh.c b/src/ssh.c index 2afd0cab..98538e46 100644 --- a/src/ssh.c +++ b/src/ssh.c @@ -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, diff --git a/tests/regress.c b/tests/regress.c index 3c638fe8..34324dc6 100644 --- a/tests/regress.c +++ b/tests/regress.c @@ -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(); diff --git a/tests/testsuite.c b/tests/testsuite.c index 48ed5953..77764bdb 100644 --- a/tests/testsuite.c +++ b/tests/testsuite.c @@ -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; diff --git a/tests/unit.c b/tests/unit.c index e8ddc1d2..f7ddcd61 100644 --- a/tests/unit.c +++ b/tests/unit.c @@ -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; diff --git a/wolfssh/ssh.h b/wolfssh/ssh.h index 374ecc0d..44d80f46 100644 --- a/wolfssh/ssh.h +++ b/wolfssh/ssh.h @@ -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);