Skip to content

Add versioning support for Connection resumption ticket #5114

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 13 commits into from
Closed
Show file tree
Hide file tree
Changes from 11 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
7 changes: 7 additions & 0 deletions docs/BUILD.md
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,13 @@ For more info, take a look at the [build.ps1](../scripts/build.ps1) script.

By default the build output will go in the `build` folder and the final build binaries in the `artifacts` folder. Under that it will create per-platform folders with subfolders for architecture/tls combinations. This allows for building different platforms and configurations at the same time.

## Updating Clog Sidecar
Some code changes such as adding/updating new MsQuic traces require updating the CLOG sidecar for successful Linux builds. This is done by running the following command:
```PowerShell
./scripts/update-sidecar.ps1
```
This makes any necessary updates to the clog sidecar manifest and the generated files under `src/generated/` folder. The modified files must be committed along with the rest of the code changes for addressing the Linux build failures.

# Building with CMake

The following section details how to build MsQuic purely with CMake commands.
Expand Down
50 changes: 48 additions & 2 deletions src/core/crypto.c
Original file line number Diff line number Diff line change
Expand Up @@ -2144,6 +2144,22 @@
PacketSpace->CurrentKeyPhaseBytesSent = 0;
}

BOOLEAN
IsQuicIncomingResumptionTicketSupported(
_In_ QUIC_VAR_INT TicketVersion
)
{
if (TicketVersion >= CXPLAT_TLS_RESUMPTION_TICKET_VERSION &&
TicketVersion <= CXPLAT_TLS_RESUMPTION_TICKET_MAX_VERSION) {
return TRUE;
}

return FALSE;

Check warning on line 2157 in src/core/crypto.c

View check run for this annotation

Codecov / codecov/patch

src/core/crypto.c#L2157

Added line #L2157 was not covered by tests
}

//
// Server calls this function to generate the resumption ticket for a specific client
//
QUIC_STATUS
QuicCryptoEncodeServerTicket(
_In_opt_ QUIC_CONNECTION* Connection,
Expand Down Expand Up @@ -2207,6 +2223,7 @@
QuicVarIntSize(AppDataLength) +
AlpnLength +
EncodedTPLength +
RESUMPTION_TICKET_V2_EXTENSION_LENGTH +
AppDataLength);

TicketBuffer = CXPLAT_ALLOC_NONPAGED(TotalTicketLength, QUIC_POOL_SERVER_CRYPTO_TICKET);
Expand All @@ -2233,7 +2250,7 @@
//

_Analysis_assume_(sizeof(*TicketBuffer) >= 8);
uint8_t* TicketCursor = QuicVarIntEncode(CXPLAT_TLS_RESUMPTION_TICKET_VERSION, TicketBuffer);
uint8_t* TicketCursor = QuicVarIntEncode(CXPLAT_TLS_RESUMPTION_TICKET_MAX_VERSION, TicketBuffer);
CxPlatCopyMemory(TicketCursor, &QuicVersion, sizeof(QuicVersion));
TicketCursor += sizeof(QuicVersion);
TicketCursor = QuicVarIntEncode(AlpnLength, TicketCursor);
Expand All @@ -2243,6 +2260,12 @@
TicketCursor += AlpnLength;
CxPlatCopyMemory(TicketCursor, EncodedHSTP + CxPlatTlsTPHeaderSize, EncodedTPLength);
TicketCursor += EncodedTPLength;

//
// TODO: add processing of V2 extension here
//
TicketCursor += RESUMPTION_TICKET_V2_EXTENSION_LENGTH; // Skip the fixed length V2 extension

if (AppDataLength > 0) {
CxPlatCopyMemory(TicketCursor, AppResumptionData, AppDataLength);
TicketCursor += AppDataLength;
Expand All @@ -2263,6 +2286,9 @@
return Status;
}

//
// Server uses this function to decode the resumption ticket presented by the client
//
QUIC_STATUS
QuicCryptoDecodeServerTicket(
_In_ QUIC_CONNECTION* Connection,
Expand Down Expand Up @@ -2292,7 +2318,8 @@
"Resumption Ticket version failed to decode");
goto Error;
}
if (TicketVersion != CXPLAT_TLS_RESUMPTION_TICKET_VERSION) {

if (!IsQuicIncomingResumptionTicketSupported(TicketVersion)) {
QuicTraceEvent(
ConnError,
"[conn][%p] ERROR, %s.",
Expand Down Expand Up @@ -2392,6 +2419,25 @@
}
Offset += (uint16_t)TPLength;

if (TicketVersion == CXPLAT_TLS_RESUMPTION_TICKET_VERSION_V2) {
//
// V2 resumption ticket has a fixed length extension.
//
if (TicketLength < Offset + RESUMPTION_TICKET_V2_EXTENSION_LENGTH) {
QuicTraceEvent(

Check warning on line 2427 in src/core/crypto.c

View check run for this annotation

Codecov / codecov/patch

src/core/crypto.c#L2427

Added line #L2427 was not covered by tests
ConnError,
"[conn][%p] ERROR, %s.",
Connection,
"Resumption Ticket too small for V2 extensions");
goto Error;

Check warning on line 2432 in src/core/crypto.c

View check run for this annotation

Codecov / codecov/patch

src/core/crypto.c#L2432

Added line #L2432 was not covered by tests
}

//
// TODO: add processing of V2 extension here
//
Offset += RESUMPTION_TICKET_V2_EXTENSION_LENGTH;
}

if (TicketLength == Offset + AppTicketLength) {
Status = QUIC_STATUS_SUCCESS;
*AppDataLength = (uint32_t)AppTicketLength;
Expand Down
22 changes: 19 additions & 3 deletions src/core/quicdef.h
Original file line number Diff line number Diff line change
Expand Up @@ -444,11 +444,27 @@ CXPLAT_STATIC_ASSERT(
//
#define QUIC_DEFAULT_SERVER_RESUMPTION_LEVEL QUIC_SERVER_NO_RESUME


//
// Version of the wire-format for resumption tickets.
// This needs to be incremented for each change in order or count of fields.
// Valid Resumption Ticket Versions - these must be contiguous
//
#define CXPLAT_TLS_RESUMPTION_TICKET_VERSION_V1 1
#define CXPLAT_TLS_RESUMPTION_TICKET_VERSION_V2 2

//
// Length in bytes of V2 extension to the resumption ticket
//
#define RESUMPTION_TICKET_V2_EXTENSION_LENGTH 64

//
// Min version of the wire-format for resumption tickets.
//
#define CXPLAT_TLS_RESUMPTION_TICKET_VERSION CXPLAT_TLS_RESUMPTION_TICKET_VERSION_V1

//
// Max version of the wire-format for resumption tickets.
//
#define CXPLAT_TLS_RESUMPTION_TICKET_VERSION 1
#define CXPLAT_TLS_RESUMPTION_TICKET_MAX_VERSION CXPLAT_TLS_RESUMPTION_TICKET_VERSION_V2

//
// Version of the blob for client resumption tickets.
Expand Down
5 changes: 3 additions & 2 deletions src/core/settings.c
Original file line number Diff line number Diff line change
Expand Up @@ -747,6 +747,7 @@ QuicSettingApply(
Destination->StreamMultiReceiveEnabled = Source->StreamMultiReceiveEnabled;
Destination->IsSet.StreamMultiReceiveEnabled = TRUE;
}

return TRUE;
}

Expand Down Expand Up @@ -1819,7 +1820,7 @@ QuicSettingsSettingsToInternal(
_Out_ QUIC_SETTINGS_INTERNAL* InternalSettings
)
{
if (!CXPLAT_STRUCT_HAS_FIELD(QUIC_SETTINGS, SettingsSize, MtuDiscoveryMissingProbeCount)) {
if (!CXPLAT_STRUCT_HAS_FIELD(QUIC_SETTINGS, SettingsSize, StreamRecvWindowUnidiDefault)) {
Comment on lines -1822 to +1823
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Revert?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The existing code seems to be measuring the size of the struct incorrectly. I have updated this to point to the last member of QUIC_SETTINGS (

uint32_t StreamRecvWindowUnidiDefault;
)

return QUIC_STATUS_INVALID_PARAMETER;
}

Expand Down Expand Up @@ -2000,7 +2001,7 @@ QuicSettingsGetSettings(
QUIC_SETTINGS* Settings
)
{
uint32_t MinimumSettingsSize = (uint32_t)CXPLAT_STRUCT_SIZE_THRU_FIELD(QUIC_SETTINGS, MtuDiscoveryMissingProbeCount);
uint32_t MinimumSettingsSize = (uint32_t)CXPLAT_STRUCT_SIZE_THRU_FIELD(QUIC_SETTINGS, StreamRecvWindowUnidiDefault);
Comment on lines -2003 to +2004
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Revert?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Downlevel tests are failing... got to revert this.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it be correct to say that MtuDiscoveryMissingProbeCount is part of the earliest released QUIC_SETTINGS struct and our API contract requires us to accept these smaller sized structs?

Is there reference documentation around this?


if (*SettingsLength == 0) {
*SettingsLength = sizeof(QUIC_SETTINGS);
Expand Down
Loading
Loading