Skip to content

Commit

Permalink
Make GetParam return INVALID_STATE error when TLS has been cleaned up (
Browse files Browse the repository at this point in the history
…#4518)

* Make GetParam return INVALID_STATE error when TLS has been cleaned up

* Add tests to cover this new behavior.

* Fix test failures on linux and kernel
  • Loading branch information
anrossi authored Aug 30, 2024
1 parent 22b7dda commit d730e86
Show file tree
Hide file tree
Showing 2 changed files with 166 additions and 1 deletion.
4 changes: 3 additions & 1 deletion src/core/library.c
Original file line number Diff line number Diff line change
Expand Up @@ -1667,8 +1667,10 @@ QuicLibraryGetParam(

case QUIC_PARAM_PREFIX_TLS:
case QUIC_PARAM_PREFIX_TLS_SCHANNEL:
if (Connection == NULL || Connection->Crypto.TLS == NULL) {
if (Connection == NULL) {
Status = QUIC_STATUS_INVALID_PARAMETER;
} else if (Connection->Crypto.TLS == NULL) {
Status = QUIC_STATUS_INVALID_STATE;
} else {
Status = CxPlatTlsParamGet(Connection->Crypto.TLS, Param, BufferLength, Buffer);
}
Expand Down
163 changes: 163 additions & 0 deletions src/test/lib/ApiTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4484,6 +4484,39 @@ void QuicTestConnectionParam()
QuicTest_QUIC_PARAM_CONN_ORIG_DEST_CID(Registration, ClientConfiguration);
}

struct TestTlsParamServerContext {
MsQuicConnection** Server;
CXPLAT_EVENT Event;
QUIC_STATUS GetParamStatus;
};

bool
TestTlsParamListenerCallback(
_In_ TestListener* Listener,
_In_ HQUIC ConnectionHandle)
{
TestTlsParamServerContext* Context = (TestTlsParamServerContext*)Listener->Context;
*Context->Server = new(std::nothrow) MsQuicConnection(
ConnectionHandle,
CleanUpManual,
[](MsQuicConnection* Connection, void* Context, QUIC_CONNECTION_EVENT* Event) {
if (Event->Type == QUIC_CONNECTION_EVENT_CONNECTED) {
QUIC_HANDSHAKE_INFO Info = {};
uint32_t Length = sizeof(Info);
((TestTlsParamServerContext*)Context)->GetParamStatus =
MsQuic->GetParam(
*Connection,
QUIC_PARAM_TLS_HANDSHAKE_INFO,
&Length,
&Info);
CxPlatEventSet(((TestTlsParamServerContext*)Context)->Event);
}
return QUIC_STATUS_SUCCESS;
},
Context);
return true;
}

//
// This test uses TEST_NOT_EQUAL(XXX, QUIC_STATUS_SUCCESS) to cover both
// OpenSSL and Schannel which return different error code.
Expand Down Expand Up @@ -4557,6 +4590,136 @@ void QuicTestTlsParam()
), QUIC_STATUS_SUCCESS);
}

//
// After handshake, no resumption
//
{
TestScopeLogger LogScope2("After handshake - no resumption");
MsQuicConfiguration ServerConfiguration(Registration, Alpn, ServerSelfSignedCredConfig);
TEST_TRUE(ServerConfiguration.IsValid());
TestListener Listener(
Registration,
TestTlsParamListenerCallback,
ServerConfiguration);
TEST_QUIC_SUCCEEDED(Listener.IsValid());
UniquePtr<MsQuicConnection> Server;
TestTlsParamServerContext ServerContext = { (MsQuicConnection**)&Server, {}, QUIC_STATUS_SUCCESS };
CxPlatEventInitialize(&ServerContext.Event, FALSE, FALSE);
Listener.Context = &ServerContext;

QuicAddr ServerLocalAddr(QUIC_ADDRESS_FAMILY_INET);
TEST_QUIC_SUCCEEDED(Listener.Start(Alpn));
TEST_QUIC_SUCCEEDED(Listener.GetLocalAddr(ServerLocalAddr));

TestConnection Client(Registration);
TEST_TRUE(Client.IsValid());
TEST_QUIC_SUCCEEDED(
Client.Start(
ClientConfiguration,
QUIC_ADDRESS_FAMILY_INET,
QUIC_LOCALHOST_FOR_AF(QUIC_ADDRESS_FAMILY_INET),
ServerLocalAddr.GetPort()));

TEST_TRUE(Client.WaitForConnectionComplete());
TEST_TRUE(Server);
CxPlatEventWaitForever(ServerContext.Event);

//
// Validate the GetParam succeeded in the CONNECTED callback.
//
TEST_QUIC_SUCCEEDED(ServerContext.GetParamStatus);

QUIC_HANDSHAKE_INFO Info = {};
Length = sizeof(Info);
TEST_QUIC_SUCCEEDED(
MsQuic->GetParam(
Client.GetConnection(),
QUIC_PARAM_TLS_HANDSHAKE_INFO,
&Length,
&Info
));

//
// The server should have freed the TLS state by now, so this
// should fail.
//
Length = sizeof(Info);
TEST_EQUAL(
MsQuic->GetParam(
*Server,
QUIC_PARAM_TLS_HANDSHAKE_INFO,
&Length,
&Info),
QUIC_STATUS_INVALID_STATE);
}

//
// After handshake, with resumption
//
{
TestScopeLogger LogScope2("After handshake - with resumption");
MsQuicSettings Settings;
Settings.SetServerResumptionLevel(QUIC_SERVER_RESUME_ONLY);
MsQuicConfiguration ServerConfiguration(Registration, Alpn, Settings, ServerSelfSignedCredConfig);
TEST_TRUE(ServerConfiguration.IsValid());
TestListener Listener(
Registration,
TestTlsParamListenerCallback,
ServerConfiguration);
TEST_QUIC_SUCCEEDED(Listener.IsValid());
UniquePtr<MsQuicConnection> Server;
TestTlsParamServerContext ServerContext = { (MsQuicConnection**)&Server, {}, QUIC_STATUS_SUCCESS };
CxPlatEventInitialize(&ServerContext.Event, FALSE, FALSE);
Listener.Context = &ServerContext;

QuicAddr ServerLocalAddr(QUIC_ADDRESS_FAMILY_INET);
TEST_QUIC_SUCCEEDED(Listener.Start(Alpn));
TEST_QUIC_SUCCEEDED(Listener.GetLocalAddr(ServerLocalAddr));

TestConnection Client(Registration);
TEST_TRUE(Client.IsValid());
TEST_QUIC_SUCCEEDED(
Client.Start(
ClientConfiguration,
QUIC_ADDRESS_FAMILY_INET,
QUIC_LOCALHOST_FOR_AF(QUIC_ADDRESS_FAMILY_INET),
ServerLocalAddr.GetPort()));

TEST_TRUE(Client.WaitForConnectionComplete());
TEST_TRUE(Server);
CxPlatEventWaitForever(ServerContext.Event);

//
// Validate the GetParam succeeded in the CONNECTED callback.
//
TEST_QUIC_SUCCEEDED(ServerContext.GetParamStatus);

//
// Validate the client always can call GetParam after handshake.
//
QUIC_HANDSHAKE_INFO Info = {};
Length = sizeof(Info);
TEST_QUIC_SUCCEEDED(
MsQuic->GetParam(
Client.GetConnection(),
QUIC_PARAM_TLS_HANDSHAKE_INFO,
&Length,
&Info
));

//
// The server should NOT have freed the TLS state, so this
// should succeed.
//
TEST_EQUAL(
MsQuic->GetParam(
*Server,
QUIC_PARAM_TLS_HANDSHAKE_INFO,
&Length,
&Info),
QUIC_STATUS_SUCCESS);
}

{
TestScopeLogger LogScope2("Successful case is covered by TlsTest.HandshakeParamInfo*");
}
Expand Down

0 comments on commit d730e86

Please sign in to comment.