зеркало из https://github.com/microsoft/msquic.git
Fuzz Handshake packet (#4074)
* receive packet * populated the packet struct * added ACK frame sending * Initial ACK frame response sent * added handshake decryption * Completed handshake decryption * finshed processing handshake packet * fuzzed handshake packet and sent * fixed Read key not available bug * fixed a bug * Testing to see if pipelines passes * pop packet when decryption fail * minor change * only free packet after we are done processing * attempt to fix the pipeline * packet copy is sent * recv event modified * zeroed out send buffer * minor change * minor * free packet event * redefined few variables to fix memory leak * minor change * fixed recv datagram bug * attempt to fix the pipeline * test * added few checks * minor change * minor change * debug statement * some debug statements for the pipeling * minor change * Few fixes * minor * added allocated check * chain processing changed * cleaned up code * minor change * minor change * minor change * Update src/tools/recvfuzz/recvfuzz.cpp Co-authored-by: Nick Banks <nibanks@microsoft.com> * minor code cleanups: * mode changes * minor * made initial packet and handshake packet fuzzing work together * minor change * debug * minor change * minor change * minor change * Update src/tools/recvfuzz/recvfuzz.cpp Co-authored-by: Nick Banks <nibanks@microsoft.com> * Update src/tools/recvfuzz/recvfuzz.cpp Co-authored-by: Nick Banks <nibanks@microsoft.com> * Update src/tools/recvfuzz/recvfuzz.cpp Co-authored-by: Nick Banks <nibanks@microsoft.com> * Update src/tools/recvfuzz/recvfuzz.cpp Co-authored-by: Nick Banks <nibanks@microsoft.com> * Update src/tools/recvfuzz/recvfuzz.cpp Co-authored-by: Nick Banks <nibanks@microsoft.com> * Update src/tools/recvfuzz/recvfuzz.cpp Co-authored-by: Nick Banks <nibanks@microsoft.com> * Update src/tools/recvfuzz/recvfuzz.cpp Co-authored-by: Nick Banks <nibanks@microsoft.com> * Update src/tools/recvfuzz/recvfuzz.cpp Co-authored-by: Nick Banks <nibanks@microsoft.com> * Update src/tools/recvfuzz/recvfuzz.cpp Co-authored-by: Nick Banks <nibanks@microsoft.com> * Update src/tools/recvfuzz/recvfuzz.cpp Co-authored-by: Nick Banks <nibanks@microsoft.com> * minor change * few cxplatevent changes * few minor changes * handle failure * minor * few minor things * delete state buffer after every iteration * minor * minor * test change * minor change * minor change * added startms * added result flag * cleanup code and few debug statements * cleanup * Made packet as stack variable * reverted change * Update src/tools/recvfuzz/recvfuzz.cpp Co-authored-by: Nick Banks <nibanks@microsoft.com> * Update src/tools/recvfuzz/recvfuzz.cpp Co-authored-by: Nick Banks <nibanks@microsoft.com> * resolved comments * fixed potential memory leak * Update src/tools/recvfuzz/recvfuzz.cpp Co-authored-by: Nick Banks <nibanks@microsoft.com> * resolved comments * New handshake each iteration * removed unnecessary comment * minor change * minor change * Some modifications * fixed memory leaks * minor change * freed up send data * revert * revert * minor change * minor changes * test * add free send data * rest * modified implementation * minor change * few optimisations * attempt to fix * added ASAN option * resolved comments * minor refactoring * minor change --------- Co-authored-by: Nick Banks <nibanks@microsoft.com>
This commit is contained in:
Родитель
55830d38c8
Коммит
1a32822791
|
@ -98,6 +98,7 @@ param (
|
|||
[switch]$UseXdp
|
||||
)
|
||||
|
||||
$env:ASAN_OPTIONS = "allocator_may_return_null=1"
|
||||
Set-StrictMode -Version 'Latest'
|
||||
$PSDefaultParameterValues['*:ErrorAction'] = 'Stop'
|
||||
|
||||
|
|
|
@ -14,6 +14,7 @@ Abstract:
|
|||
#include <map>
|
||||
#include <mutex>
|
||||
#include <algorithm>
|
||||
#include <list>
|
||||
|
||||
#define QUIC_TEST_APIS 1 // Needed for self signed cert API
|
||||
#define QUIC_API_ENABLE_INSECURE_FEATURES 1 // Needed for disabling 1-RTT encryption
|
||||
|
@ -28,13 +29,30 @@ const MsQuicApi* MsQuic;
|
|||
uint64_t MagicCid = 0x989898989898989ull;
|
||||
const QUIC_HKDF_LABELS HkdfLabels = { "quic key", "quic iv", "quic hp", "quic ku" };
|
||||
uint64_t RunTimeMs = 60000;
|
||||
CxPlatEvent RecvPacketEvent(true);
|
||||
std::list<QUIC_RX_PACKET*> PacketQueue;
|
||||
uint64_t CurrSrcCid = 0;
|
||||
|
||||
static const char* Alpn = "fuzz";
|
||||
static uint32_t Version = QUIC_VERSION_DRAFT_29;
|
||||
static uint32_t Version = QUIC_VERSION_1;
|
||||
const char* Sni = "localhost";
|
||||
|
||||
#define QUIC_MIN_INITIAL_LENGTH 1200
|
||||
|
||||
struct PacketParams {
|
||||
uint8_t DestCidLen;
|
||||
uint8_t SourceCidLen;
|
||||
uint8_t* DestCid;
|
||||
uint8_t* SourceCid;
|
||||
uint64_t packetNumber;
|
||||
uint8_t NumFrames;
|
||||
uint8_t NumPackets;
|
||||
QUIC_LONG_HEADER_TYPE_V1 PacketType;
|
||||
uint8_t Mode;
|
||||
QUIC_FRAME_TYPE FrameTypes[2];
|
||||
uint64_t LargestAcknowledge; // For ACK Frame
|
||||
};
|
||||
|
||||
struct StrBuffer {
|
||||
uint8_t* Data;
|
||||
uint16_t Length;
|
||||
|
@ -54,6 +72,8 @@ struct StrBuffer {
|
|||
~StrBuffer() { delete [] Data; }
|
||||
};
|
||||
|
||||
const StrBuffer InitialSalt("38762cf7f55934b34d179ae6a4c80cadccbb7f0a");
|
||||
|
||||
class FuzzingData {
|
||||
const uint8_t* data {nullptr};
|
||||
const size_t size {0};
|
||||
|
@ -105,11 +125,73 @@ _IRQL_requires_max_(DISPATCH_LEVEL)
|
|||
_Function_class_(CXPLAT_DATAPATH_RECEIVE_CALLBACK)
|
||||
void
|
||||
UdpRecvCallback(
|
||||
_In_ CXPLAT_SOCKET* /* Binding */,
|
||||
_In_ void* /* Context */,
|
||||
_In_ CXPLAT_SOCKET* Binding,
|
||||
_In_ void* Context,
|
||||
_In_ CXPLAT_RECV_DATA* RecvBufferChain
|
||||
)
|
||||
{
|
||||
CXPLAT_RECV_DATA* Datagram = RecvBufferChain;
|
||||
while (Datagram != NULL) {
|
||||
uint8_t DestCidLen, SourceCidLen;
|
||||
const uint8_t* DestCid, *SourceCid;
|
||||
QUIC_RX_PACKET Packet;
|
||||
Packet.AvailBuffer = Datagram->Buffer;
|
||||
do {
|
||||
Packet.AvailBufferLength = Datagram->BufferLength;
|
||||
DestCidLen = Packet.Invariant->LONG_HDR.DestCidLength;
|
||||
DestCid = Packet.Invariant->LONG_HDR.DestCid;
|
||||
SourceCidLen = *(DestCid + DestCidLen);
|
||||
SourceCid = DestCid + sizeof(uint8_t) + DestCidLen;
|
||||
uint16_t Offset = MIN_INV_LONG_HDR_LENGTH + DestCidLen + SourceCidLen;
|
||||
Packet.DestCidLen = DestCidLen;
|
||||
Packet.SourceCidLen = SourceCidLen;
|
||||
Packet.DestCid = DestCid;
|
||||
Packet.SourceCid = SourceCid;
|
||||
if (Packet.LH->Type == QUIC_INITIAL_V1) {
|
||||
QUIC_VAR_INT TokenLengthVarInt;
|
||||
QuicVarIntDecode(
|
||||
Packet.AvailBufferLength,
|
||||
Packet.AvailBuffer,
|
||||
&Offset,
|
||||
&TokenLengthVarInt);
|
||||
Offset += (uint16_t)TokenLengthVarInt;
|
||||
}
|
||||
QUIC_VAR_INT LengthVarInt;
|
||||
QuicVarIntDecode(
|
||||
Packet.AvailBufferLength,
|
||||
Packet.AvailBuffer,
|
||||
&Offset,
|
||||
&LengthVarInt);
|
||||
Packet.HeaderLength = Offset;
|
||||
Packet.PayloadLength = (uint16_t)LengthVarInt;
|
||||
Packet.ValidatedHeaderVer = TRUE;
|
||||
if (Packet.LH->Version == QUIC_VERSION_2) {
|
||||
Packet.KeyType = QuicPacketTypeToKeyTypeV2(Packet.LH->Type);
|
||||
} else {
|
||||
Packet.KeyType = QuicPacketTypeToKeyTypeV1(Packet.LH->Type);
|
||||
}
|
||||
Packet.Encrypted = TRUE;
|
||||
if (Packet.AvailBufferLength >= Packet.HeaderLength &&
|
||||
(memcmp(Packet.DestCid, &CurrSrcCid, sizeof(uint64_t)) == 0) &&
|
||||
(Packet.LH->Type == QUIC_INITIAL_V1 || Packet.LH->Type == QUIC_HANDSHAKE_V1)) {
|
||||
Packet.AvailBufferLength = Packet.HeaderLength + Packet.PayloadLength;
|
||||
QUIC_RX_PACKET* PacketCopy = (QUIC_RX_PACKET *)CXPLAT_ALLOC_NONPAGED(sizeof(QUIC_RX_PACKET) + Packet.AvailBufferLength + Packet.DestCidLen + Packet.SourceCidLen, QUIC_POOL_TOOL);
|
||||
memcpy(PacketCopy, &Packet, sizeof(QUIC_RX_PACKET));
|
||||
PacketCopy->AvailBuffer = (uint8_t*)(PacketCopy + 1);
|
||||
memcpy((void *)PacketCopy->AvailBuffer, Packet.AvailBuffer, Packet.AvailBufferLength);
|
||||
PacketCopy->DestCid = PacketCopy->AvailBuffer + Packet.AvailBufferLength;
|
||||
memcpy((void *)PacketCopy->DestCid, Packet.DestCid, Packet.DestCidLen);
|
||||
PacketCopy->SourceCid = PacketCopy->DestCid + Packet.DestCidLen;
|
||||
memcpy((void *)PacketCopy->SourceCid, Packet.SourceCid, Packet.SourceCidLen);
|
||||
PacketQueue.push_back(PacketCopy);
|
||||
}
|
||||
Packet.AvailBuffer += Packet.AvailBufferLength;
|
||||
} while (Packet.AvailBuffer - Datagram->Buffer < Datagram->BufferLength);
|
||||
Datagram = Datagram->Next;
|
||||
}
|
||||
if (!PacketQueue.empty()) {
|
||||
RecvPacketEvent.Set();
|
||||
}
|
||||
CxPlatRecvDataReturn(RecvBufferChain);
|
||||
}
|
||||
|
||||
|
@ -127,18 +209,21 @@ UdpUnreachCallback(
|
|||
struct TlsContext
|
||||
{
|
||||
CXPLAT_TLS* Ptr {nullptr};
|
||||
CXPLAT_SEC_CONFIG* SecConfig {nullptr};
|
||||
CXPLAT_SEC_CONFIG* ClientSecConfig {nullptr};
|
||||
CXPLAT_TLS_PROCESS_STATE State;
|
||||
uint8_t AlpnListBuffer[256];
|
||||
|
||||
TlsContext() {
|
||||
TlsContext() {
|
||||
AlpnListBuffer[0] = (uint8_t)strlen(Alpn);
|
||||
memcpy(&AlpnListBuffer[1], Alpn, AlpnListBuffer[0]);
|
||||
|
||||
CxPlatZeroMemory(&State, sizeof(State));
|
||||
State.Buffer = (uint8_t*)CXPLAT_ALLOC_NONPAGED(8000, QUIC_POOL_TOOL);
|
||||
State.BufferAllocLength = 8000;
|
||||
|
||||
}
|
||||
void CreateContext(uint64_t initSrcCid = MagicCid) {
|
||||
uint8_t *stateBuffer = State.Buffer;
|
||||
CxPlatZeroMemory(&State, sizeof(State));
|
||||
State.Buffer = stateBuffer;
|
||||
State.BufferAllocLength = 8000;
|
||||
QUIC_CREDENTIAL_CONFIG CredConfig = {
|
||||
QUIC_CREDENTIAL_TYPE_NONE,
|
||||
QUIC_CREDENTIAL_FLAG_CLIENT | QUIC_CREDENTIAL_FLAG_NO_CERTIFICATE_VALIDATION,
|
||||
|
@ -154,7 +239,7 @@ struct TlsContext
|
|||
&CredConfig,
|
||||
CXPLAT_TLS_CREDENTIAL_FLAG_NONE,
|
||||
&TlsCallbacks,
|
||||
&SecConfig,
|
||||
&ClientSecConfig,
|
||||
OnSecConfigCreateComplete))) {
|
||||
printf("Failed to create sec config!\n");
|
||||
}
|
||||
|
@ -174,11 +259,11 @@ struct TlsContext
|
|||
TP.InitialMaxUniStreams = 3;
|
||||
TP.Flags |= QUIC_TP_FLAG_INITIAL_SOURCE_CONNECTION_ID;
|
||||
TP.InitialSourceConnectionIDLength = sizeof(uint64_t);
|
||||
*(uint64_t*)&TP.InitialSourceConnectionID[0] = MagicCid;
|
||||
*(uint64_t*)&TP.InitialSourceConnectionID[0] = initSrcCid;
|
||||
|
||||
CXPLAT_TLS_CONFIG Config = {0};
|
||||
Config.IsServer = FALSE;
|
||||
Config.SecConfig = SecConfig;
|
||||
Config.SecConfig = ClientSecConfig;
|
||||
Config.HkdfLabels = &HkdfLabels;
|
||||
Config.AlpnBuffer = AlpnListBuffer;
|
||||
Config.AlpnBufferLength = AlpnListBuffer[0] + 1;
|
||||
|
@ -202,13 +287,22 @@ struct TlsContext
|
|||
|
||||
~TlsContext() {
|
||||
CxPlatTlsUninitialize(Ptr);
|
||||
if (SecConfig) {
|
||||
CxPlatTlsSecConfigDelete(SecConfig);
|
||||
if (ClientSecConfig) {
|
||||
CxPlatTlsSecConfigDelete(ClientSecConfig);
|
||||
}
|
||||
if (State.Buffer != nullptr) {
|
||||
CXPLAT_FREE(State.Buffer, QUIC_POOL_TOOL);
|
||||
State.Buffer = nullptr;
|
||||
}
|
||||
CXPLAT_FREE(State.Buffer, QUIC_POOL_TOOL);
|
||||
for (uint8_t i = 0; i < QUIC_PACKET_KEY_COUNT; ++i) {
|
||||
QuicPacketKeyFree(State.ReadKeys[i]);
|
||||
QuicPacketKeyFree(State.WriteKeys[i]);
|
||||
if (State.ReadKeys[i] != nullptr) {
|
||||
QuicPacketKeyFree(State.ReadKeys[i]);
|
||||
State.ReadKeys[i] = nullptr;
|
||||
}
|
||||
if (State.WriteKeys[i] != nullptr) {
|
||||
QuicPacketKeyFree(State.WriteKeys[i]);
|
||||
State.WriteKeys[i] = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -244,7 +338,6 @@ private:
|
|||
|
||||
if (Result & CXPLAT_TLS_RESULT_ERROR) {
|
||||
printf("Failed to process data!\n");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
return Result;
|
||||
|
@ -318,18 +411,56 @@ private:
|
|||
return TRUE;
|
||||
}
|
||||
};
|
||||
|
||||
void WriteInitialCryptoFrame(
|
||||
|
||||
bool WriteAckFrame(
|
||||
_In_ uint64_t LargestAcknowledge,
|
||||
_Inout_ uint16_t* Offset,
|
||||
_In_ uint16_t BufferLength,
|
||||
_Out_writes_to_(BufferLength, *Offset) uint8_t* Buffer
|
||||
)
|
||||
{
|
||||
QUIC_RANGE AckRange;
|
||||
QuicRangeInitialize(QUIC_MAX_RANGE_DECODE_ACKS, &AckRange);
|
||||
BOOLEAN RangeUpdated;
|
||||
QuicRangeAddRange(&AckRange, LargestAcknowledge, 1, &RangeUpdated);
|
||||
uint64_t AckDelay = 40;
|
||||
if (!QuicAckFrameEncode(
|
||||
&AckRange,
|
||||
AckDelay,
|
||||
nullptr,
|
||||
Offset,
|
||||
BufferLength,
|
||||
Buffer)) {
|
||||
printf("QuicAckFrameEncode failure!\n");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WriteCryptoFrame(
|
||||
_Inout_ uint16_t* Offset,
|
||||
_In_ uint16_t BufferLength,
|
||||
_Out_writes_to_(BufferLength, *Offset)
|
||||
uint8_t* Buffer)
|
||||
uint8_t* Buffer,
|
||||
_In_ TlsContext* ClientContext,
|
||||
_In_ PacketParams* PacketParams
|
||||
)
|
||||
{
|
||||
TlsContext ClientContext;
|
||||
ClientContext.ProcessData();
|
||||
|
||||
if (PacketParams->Mode == 0) {
|
||||
uint64_t SrcCid;
|
||||
CxPlatRandom(sizeof(uint64_t), &SrcCid);
|
||||
if (ClientContext == nullptr) {
|
||||
ClientContext = new TlsContext();
|
||||
PacketParams->SourceCid = (uint8_t *)&SrcCid;
|
||||
ClientContext->CreateContext(SrcCid);
|
||||
auto Result = ClientContext->ProcessData();
|
||||
if (!(Result & CXPLAT_TLS_RESULT_DATA)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
QUIC_CRYPTO_EX Frame = {
|
||||
0, ClientContext.State.BufferLength, ClientContext.State.Buffer
|
||||
0, ClientContext->State.BufferLength, ClientContext->State.Buffer
|
||||
};
|
||||
|
||||
if (!QuicCryptoFrameEncode(
|
||||
|
@ -338,31 +469,76 @@ void WriteInitialCryptoFrame(
|
|||
BufferLength,
|
||||
Buffer)) {
|
||||
printf("QuicCryptoFrameEncode failure!\n");
|
||||
exit(0);
|
||||
return false;
|
||||
}
|
||||
if (PacketParams->Mode == 0) {
|
||||
CxPlatTlsUninitialize(ClientContext->Ptr);
|
||||
if (ClientContext->ClientSecConfig) {
|
||||
CxPlatTlsSecConfigDelete(ClientContext->ClientSecConfig);
|
||||
}
|
||||
if (ClientContext->State.Buffer != nullptr) {
|
||||
CXPLAT_FREE(ClientContext->State.Buffer, QUIC_POOL_TOOL);
|
||||
}
|
||||
for (uint8_t i = 0; i < QUIC_PACKET_KEY_COUNT; ++i) {
|
||||
if (ClientContext->State.ReadKeys[i] != nullptr) {
|
||||
QuicPacketKeyFree(ClientContext->State.ReadKeys[i]);
|
||||
}
|
||||
if (ClientContext->State.WriteKeys[i] != nullptr) {
|
||||
QuicPacketKeyFree(ClientContext->State.WriteKeys[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void WriteClientInitialPacket(
|
||||
bool WriteClientPacket(
|
||||
_In_ uint32_t PacketNumber,
|
||||
_In_ uint8_t CidLength,
|
||||
_In_ uint16_t BufferLength,
|
||||
_Out_writes_to_(BufferLength, *PacketLength)
|
||||
uint8_t* Buffer,
|
||||
_Out_ uint16_t* PacketLength,
|
||||
_Out_ uint16_t* HeaderLength
|
||||
_Out_ uint16_t* HeaderLength,
|
||||
_In_ TlsContext* ClientContext,
|
||||
_In_ PacketParams* PacketParams
|
||||
)
|
||||
{
|
||||
uint32_t QuicVersion = Version;
|
||||
uint8_t CryptoBuffer[4096];
|
||||
uint16_t BufferSize = sizeof(CryptoBuffer);
|
||||
uint16_t CryptoBufferLength = 0;
|
||||
uint8_t FrameBuffer[4096];
|
||||
uint16_t BufferSize = sizeof(FrameBuffer);
|
||||
uint16_t FrameBufferLength = 0;
|
||||
for (int i = 0; i < PacketParams->NumFrames; i++) {
|
||||
if (PacketParams->FrameTypes[i] == QUIC_FRAME_ACK) {
|
||||
if (!WriteAckFrame(
|
||||
PacketParams->LargestAcknowledge,
|
||||
&FrameBufferLength,
|
||||
BufferSize,
|
||||
FrameBuffer)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
WriteInitialCryptoFrame(
|
||||
&CryptoBufferLength, BufferSize, CryptoBuffer);
|
||||
uint8_t CidBuffer[sizeof(QUIC_CID) + 256] = {0};
|
||||
QUIC_CID* Cid = (QUIC_CID*)CidBuffer;
|
||||
Cid->IsInitial = TRUE;
|
||||
Cid->Length = CidLength;
|
||||
if (PacketParams->FrameTypes[i] == QUIC_FRAME_CRYPTO) {
|
||||
if (!WriteCryptoFrame(
|
||||
&FrameBufferLength,
|
||||
BufferSize,
|
||||
FrameBuffer,
|
||||
ClientContext,
|
||||
PacketParams)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
uint8_t DestCidBuffer[sizeof(QUIC_CID) + 256] = {0};
|
||||
uint8_t SourceCidBuffer[sizeof(QUIC_CID) + 256] = {0};
|
||||
|
||||
QUIC_CID* DestCid = (QUIC_CID*)DestCidBuffer;
|
||||
QUIC_CID* SourceCid = (QUIC_CID*)SourceCidBuffer;
|
||||
|
||||
DestCid->IsInitial = TRUE;
|
||||
DestCid->Length = PacketParams->DestCidLen;
|
||||
|
||||
SourceCid->IsInitial = TRUE;
|
||||
SourceCid->Length = PacketParams->SourceCidLen;
|
||||
|
||||
uint16_t PayloadLengthOffset = 0;
|
||||
uint8_t PacketNumberLength;
|
||||
|
@ -370,10 +546,10 @@ void WriteClientInitialPacket(
|
|||
*PacketLength =
|
||||
QuicPacketEncodeLongHeaderV1(
|
||||
QuicVersion,
|
||||
QUIC_INITIAL_V1,
|
||||
(uint8_t)PacketParams->PacketType,
|
||||
1, // Fixed bit must be 1 in this case
|
||||
Cid,
|
||||
Cid,
|
||||
DestCid,
|
||||
SourceCid,
|
||||
0,
|
||||
nullptr,
|
||||
PacketNumber,
|
||||
|
@ -381,19 +557,21 @@ void WriteClientInitialPacket(
|
|||
Buffer,
|
||||
&PayloadLengthOffset,
|
||||
&PacketNumberLength);
|
||||
if (*PacketLength + CryptoBufferLength > BufferLength) {
|
||||
if (*PacketLength + FrameBufferLength > BufferLength) {
|
||||
printf("Crypto Too Big!\n");
|
||||
exit(0);
|
||||
return false;
|
||||
}
|
||||
|
||||
QuicVarIntEncode2Bytes(
|
||||
PacketNumberLength + CryptoBufferLength + CXPLAT_ENCRYPTION_OVERHEAD,
|
||||
PacketNumberLength + FrameBufferLength + CXPLAT_ENCRYPTION_OVERHEAD,
|
||||
Buffer + PayloadLengthOffset);
|
||||
*HeaderLength = *PacketLength;
|
||||
|
||||
CxPlatCopyMemory(Buffer + *PacketLength, CryptoBuffer, CryptoBufferLength);
|
||||
*PacketLength += CryptoBufferLength;
|
||||
CxPlatCopyMemory(Buffer + *PacketLength, FrameBuffer, FrameBufferLength);
|
||||
*PacketLength += FrameBufferLength;
|
||||
*PacketLength += CXPLAT_ENCRYPTION_OVERHEAD;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void fuzzPacket(uint8_t* Packet, uint16_t PacketLength) {
|
||||
|
@ -403,45 +581,50 @@ void fuzzPacket(uint8_t* Packet, uint16_t PacketLength) {
|
|||
}
|
||||
}
|
||||
|
||||
void buildInitialPacket(CXPLAT_SOCKET* Binding, CXPLAT_ROUTE Route, int64_t* PacketCount, int64_t* TotalByteCount, bool fuzzing = true) {
|
||||
const StrBuffer InitialSalt("afbfec289993d24c9e9786f19c6111e04390a899");
|
||||
void sendPacket(
|
||||
CXPLAT_SOCKET* Binding,
|
||||
CXPLAT_ROUTE Route,
|
||||
int64_t* PacketCount,
|
||||
int64_t* TotalByteCount,
|
||||
PacketParams* PacketParams,
|
||||
bool fuzzing = true,
|
||||
TlsContext* ClientContext = nullptr) {
|
||||
const uint16_t DatagramLength = QUIC_MIN_INITIAL_LENGTH;
|
||||
CXPLAT_SEND_CONFIG SendConfig = { &Route, DatagramLength, CXPLAT_ECN_NON_ECT, 0 };
|
||||
CXPLAT_SEND_DATA* SendData = CxPlatSendDataAlloc(Binding, &SendConfig);
|
||||
if (!SendData) {
|
||||
printf("CxPlatSendDataAlloc failed\n");
|
||||
return;
|
||||
}
|
||||
while (!CxPlatSendDataIsFull(SendData)) {
|
||||
const uint64_t PacketNumber = GetRandom(1000);
|
||||
uint8_t numPacketsSent = 0;
|
||||
while (!CxPlatSendDataIsFull(SendData) && numPacketsSent <= PacketParams->NumPackets) {
|
||||
uint8_t Packet[512] = {0};
|
||||
uint16_t PacketLength, HeaderLength;
|
||||
|
||||
WriteClientInitialPacket(
|
||||
(uint32_t)PacketNumber,
|
||||
sizeof(uint64_t),
|
||||
sizeof(Packet),
|
||||
Packet,
|
||||
&PacketLength,
|
||||
&HeaderLength);
|
||||
|
||||
uint16_t PacketNumberOffset = HeaderLength - sizeof(uint32_t);
|
||||
|
||||
uint64_t* DestCid = (uint64_t*)(Packet + sizeof(QUIC_LONG_HEADER_V1));
|
||||
uint64_t* SrcCid = (uint64_t*)(Packet + sizeof(QUIC_LONG_HEADER_V1) + sizeof(uint64_t) + sizeof(uint8_t));
|
||||
|
||||
uint64_t* OrigSrcCid = nullptr;
|
||||
for (uint16_t i = HeaderLength; i < PacketLength; ++i) {
|
||||
if (!memcmp(&MagicCid, Packet+i, sizeof(MagicCid))) {
|
||||
OrigSrcCid = (uint64_t*)&Packet[i];
|
||||
}
|
||||
}
|
||||
if (!OrigSrcCid) {
|
||||
printf("Failed to find OrigSrcCid!\n");
|
||||
uint64_t packetNum = PacketParams->packetNumber++;
|
||||
if (!WriteClientPacket(
|
||||
(uint32_t)packetNum,
|
||||
sizeof(Packet),
|
||||
Packet,
|
||||
&PacketLength,
|
||||
&HeaderLength,
|
||||
ClientContext,
|
||||
PacketParams)) {
|
||||
CxPlatSendDataFree(SendData);
|
||||
return;
|
||||
}
|
||||
|
||||
uint16_t PacketNumberOffset = HeaderLength - sizeof(uint32_t);
|
||||
|
||||
CxPlatRandom(sizeof(uint64_t), DestCid); //fuzz
|
||||
CxPlatRandom(sizeof(uint64_t), SrcCid); //fuzz
|
||||
uint8_t* DestCid = (uint8_t*)(Packet + sizeof(QUIC_LONG_HEADER_V1));
|
||||
uint8_t* SrcCid = (uint8_t*)(Packet + sizeof(QUIC_LONG_HEADER_V1) + PacketParams->DestCidLen + sizeof(uint8_t));
|
||||
if (PacketParams->DestCid == nullptr) {
|
||||
CxPlatRandom(sizeof(uint64_t), DestCid);
|
||||
} else {
|
||||
memcpy(DestCid, PacketParams->DestCid, PacketParams->DestCidLen);
|
||||
}
|
||||
|
||||
memcpy(SrcCid, PacketParams->SourceCid, PacketParams->SourceCidLen);
|
||||
|
||||
if (fuzzing) {
|
||||
fuzzPacket(Packet, sizeof(Packet));
|
||||
}
|
||||
|
@ -449,27 +632,50 @@ void buildInitialPacket(CXPLAT_SOCKET* Binding, CXPLAT_ROUTE Route, int64_t* Pac
|
|||
CxPlatSendDataAllocBuffer(SendData, DatagramLength);
|
||||
if (!SendBuffer) {
|
||||
printf("CxPlatSendDataAllocBuffer failed\n");
|
||||
CxPlatSendDataFree(SendData);
|
||||
return;
|
||||
}
|
||||
*OrigSrcCid = *SrcCid;
|
||||
CxPlatZeroMemory(SendBuffer->Buffer, DatagramLength);
|
||||
memcpy(SendBuffer->Buffer, Packet, PacketLength);
|
||||
QUIC_PACKET_KEY* WriteKey;
|
||||
|
||||
if (QUIC_FAILED(
|
||||
QuicPacketKeyCreateInitial(
|
||||
FALSE,
|
||||
&HkdfLabels,
|
||||
InitialSalt.Data,
|
||||
sizeof(uint64_t),
|
||||
(uint8_t*)DestCid,
|
||||
nullptr,
|
||||
&WriteKey))) {
|
||||
printf("QuicPacketKeyCreateInitial failed\n");
|
||||
return;
|
||||
QUIC_PACKET_KEY* WriteKey = nullptr;
|
||||
QUIC_PACKET_KEY_TYPE KeyType = QuicPacketTypeToKeyTypeV1((uint8_t)PacketParams->PacketType);
|
||||
if (PacketParams->Mode == 0) {
|
||||
if (QUIC_FAILED(
|
||||
QuicPacketKeyCreateInitial(
|
||||
FALSE,
|
||||
&HkdfLabels,
|
||||
InitialSalt.Data,
|
||||
PacketParams->DestCidLen,
|
||||
(uint8_t*)DestCid,
|
||||
nullptr,
|
||||
&WriteKey))) {
|
||||
printf("QuicPacketKeyCreateInitial failed\n");
|
||||
CxPlatSendDataFree(SendData);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
if (ClientContext->State.WriteKeys[0] == nullptr) {
|
||||
if (QUIC_FAILED(
|
||||
QuicPacketKeyCreateInitial(
|
||||
FALSE,
|
||||
&HkdfLabels,
|
||||
InitialSalt.Data,
|
||||
PacketParams->DestCidLen,
|
||||
(uint8_t*)DestCid,
|
||||
&ClientContext->State.ReadKeys[0],
|
||||
&ClientContext->State.WriteKeys[0]))) {
|
||||
printf("QuicPacketKeyCreateInitial failed\n");
|
||||
CxPlatSendDataFree(SendData);
|
||||
return;
|
||||
}
|
||||
ClientContext->State.ReadKey = QUIC_PACKET_KEY_INITIAL;
|
||||
ClientContext->State.WriteKey = QUIC_PACKET_KEY_INITIAL;
|
||||
}
|
||||
WriteKey = ClientContext->State.WriteKeys[KeyType];
|
||||
}
|
||||
uint8_t Iv[CXPLAT_IV_LENGTH];
|
||||
QuicCryptoCombineIvAndPacketNumber(
|
||||
WriteKey->Iv, (uint8_t*)&PacketNumber, Iv);
|
||||
WriteKey->Iv, (uint8_t*)&packetNum, Iv);
|
||||
|
||||
CxPlatEncrypt(
|
||||
WriteKey->PacketKey,
|
||||
|
@ -486,13 +692,16 @@ void buildInitialPacket(CXPLAT_SOCKET* Binding, CXPLAT_ROUTE Route, int64_t* Pac
|
|||
SendBuffer->Buffer + HeaderLength,
|
||||
HpMask);
|
||||
|
||||
QuicPacketKeyFree(WriteKey);
|
||||
SendBuffer->Buffer[0] ^= HpMask[0] & 0x0F;
|
||||
for (uint8_t i = 0; i < 4; ++i) {
|
||||
SendBuffer->Buffer[PacketNumberOffset + i] ^= HpMask[i + 1];
|
||||
}
|
||||
InterlockedExchangeAdd64(PacketCount, 1);
|
||||
InterlockedExchangeAdd64(TotalByteCount, DatagramLength);
|
||||
numPacketsSent++;
|
||||
if (!fuzzing) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (QUIC_FAILED(
|
||||
|
@ -505,25 +714,223 @@ void buildInitialPacket(CXPLAT_SOCKET* Binding, CXPLAT_ROUTE Route, int64_t* Pac
|
|||
}
|
||||
}
|
||||
|
||||
void fuzzHandshakePacket() {
|
||||
// TODO
|
||||
}
|
||||
|
||||
void fuzz(CXPLAT_SOCKET* Binding, CXPLAT_ROUTE Route) {
|
||||
int64_t PacketCount = 0;
|
||||
int64_t InitialPacketCount = 0;
|
||||
int64_t HandshakePacketCount = 0;
|
||||
int64_t TotalByteCount = 0;
|
||||
uint8_t mode;
|
||||
uint64_t StartTimeMs = CxPlatTimeMs64();
|
||||
uint8_t recvBuffer[8192];
|
||||
uint32_t bufferoffset = 0;
|
||||
bool handshakeComplete = FALSE;
|
||||
TlsContext HandshakeClientContext;
|
||||
while (CxPlatTimeDiff64(StartTimeMs, CxPlatTimeMs64()) < RunTimeMs) {
|
||||
mode = 0; //(uint8_t)GetRandom(2);
|
||||
if (mode == 0) {
|
||||
buildInitialPacket(Binding, Route, &PacketCount, &TotalByteCount);
|
||||
} else if (mode == 1) {
|
||||
fuzzHandshakePacket();
|
||||
mode = (uint8_t)GetRandom(10);
|
||||
if (mode < 1) {
|
||||
PacketParams InitialPacketParams = {
|
||||
sizeof(uint64_t),
|
||||
sizeof(uint64_t),
|
||||
nullptr,
|
||||
nullptr,
|
||||
0,
|
||||
1,
|
||||
100
|
||||
};
|
||||
InitialPacketParams.PacketType = QUIC_INITIAL_V1;
|
||||
InitialPacketParams.FrameTypes[0] = QUIC_FRAME_CRYPTO;
|
||||
InitialPacketParams.Mode = 0;
|
||||
sendPacket(Binding, Route, &InitialPacketCount, &TotalByteCount, &InitialPacketParams, true);
|
||||
} else if (mode >= 1) {
|
||||
PacketParams HandshakePacketParams = {
|
||||
sizeof(uint64_t),
|
||||
sizeof(uint64_t),
|
||||
nullptr,
|
||||
nullptr,
|
||||
0,
|
||||
1
|
||||
};
|
||||
HandshakePacketParams.FrameTypes[0] = QUIC_FRAME_CRYPTO;
|
||||
RecvPacketEvent.Reset();
|
||||
bool FirstPacket = TRUE;
|
||||
do {
|
||||
CxPlatRandom(sizeof(uint64_t), &CurrSrcCid);
|
||||
HandshakePacketParams.SourceCid = (uint8_t *)&CurrSrcCid;
|
||||
HandshakeClientContext.CreateContext(CurrSrcCid);
|
||||
HandshakeClientContext.ProcessData();
|
||||
HandshakePacketParams.PacketType = QUIC_INITIAL_V1;
|
||||
HandshakePacketParams.Mode = 1;
|
||||
sendPacket(Binding, Route, &InitialPacketCount, &TotalByteCount, &HandshakePacketParams, false, &HandshakeClientContext);
|
||||
FirstPacket = FALSE;
|
||||
} while (!RecvPacketEvent.WaitTimeout(400) && CxPlatTimeDiff64(StartTimeMs, CxPlatTimeMs64()) < RunTimeMs);
|
||||
|
||||
while (!PacketQueue.empty()) {
|
||||
QUIC_RX_PACKET* packet = PacketQueue.front();
|
||||
if (!packet->DestCidLen ||
|
||||
!packet->DestCid || packet->PayloadLength < 4 + CXPLAT_HP_SAMPLE_LENGTH ||
|
||||
(memcmp(packet->DestCid, &CurrSrcCid, sizeof(uint64_t)) != 0)) {
|
||||
CXPLAT_FREE(packet, QUIC_POOL_TOOL);
|
||||
PacketQueue.pop_front();
|
||||
continue;
|
||||
}
|
||||
if (packet->LH->Type == QUIC_INITIAL_V1) {
|
||||
bufferoffset = 0;
|
||||
}
|
||||
uint8_t Cipher[CXPLAT_HP_SAMPLE_LENGTH];
|
||||
uint8_t HpMask[16];
|
||||
CxPlatCopyMemory(
|
||||
Cipher,
|
||||
packet->AvailBuffer + packet->HeaderLength + 4,
|
||||
CXPLAT_HP_SAMPLE_LENGTH);
|
||||
// same step for all long header packets
|
||||
|
||||
QUIC_PACKET_KEY_TYPE KeyType = packet->KeyType;
|
||||
if (HandshakeClientContext.State.ReadKeys[KeyType] == nullptr) {
|
||||
CXPLAT_FREE(packet, QUIC_POOL_TOOL);
|
||||
PacketQueue.pop_front();
|
||||
continue;
|
||||
}
|
||||
if (QUIC_FAILED(
|
||||
CxPlatHpComputeMask(
|
||||
HandshakeClientContext.State.ReadKeys[KeyType]->HeaderKey,
|
||||
1,
|
||||
Cipher,
|
||||
HpMask))) {
|
||||
printf("Failed to Compute Mask\n");
|
||||
}
|
||||
uint8_t CompressedPacketNumberLength = 0;
|
||||
((uint8_t*)packet->AvailBuffer)[0] ^= HpMask[0] & 0x0F;
|
||||
CompressedPacketNumberLength = packet->LH->PnLength + 1;
|
||||
for (uint8_t i = 0; i < CompressedPacketNumberLength; i++) {
|
||||
((uint8_t*)packet->AvailBuffer)[packet->HeaderLength + i] ^= HpMask[1 + i];
|
||||
}
|
||||
uint64_t CompressedPacketNumber = 0;
|
||||
QuicPktNumDecode(
|
||||
CompressedPacketNumberLength,
|
||||
packet->AvailBuffer + packet->HeaderLength,
|
||||
&CompressedPacketNumber);
|
||||
|
||||
packet->HeaderLength += CompressedPacketNumberLength;
|
||||
packet->PayloadLength -= CompressedPacketNumberLength;
|
||||
QUIC_ENCRYPT_LEVEL EncryptLevel = QuicKeyTypeToEncryptLevel(packet->KeyType);
|
||||
packet->PacketNumber =
|
||||
QuicPktNumDecompress(
|
||||
HandshakePacketParams.packetNumber + 1,
|
||||
CompressedPacketNumber,
|
||||
CompressedPacketNumberLength);
|
||||
packet->PacketNumberSet = TRUE;
|
||||
const uint8_t* Payload = packet->AvailBuffer + packet->HeaderLength;
|
||||
uint8_t Iv[CXPLAT_MAX_IV_LENGTH];
|
||||
QuicCryptoCombineIvAndPacketNumber(
|
||||
HandshakeClientContext.State.ReadKeys[KeyType]->Iv,
|
||||
(uint8_t*)&packet->PacketNumber,
|
||||
Iv);
|
||||
if (QUIC_FAILED(
|
||||
CxPlatDecrypt(
|
||||
HandshakeClientContext.State.ReadKeys[KeyType]->PacketKey,
|
||||
Iv,
|
||||
packet->HeaderLength, // HeaderLength
|
||||
packet->AvailBuffer, // Header
|
||||
packet->PayloadLength, // BufferLength
|
||||
(uint8_t*)Payload))) { // Buffer
|
||||
printf("CxPlatDecrypt failed\n");
|
||||
CXPLAT_FREE(packet, QUIC_POOL_TOOL);
|
||||
PacketQueue.pop_front();
|
||||
continue;
|
||||
}
|
||||
packet->PayloadLength -= CXPLAT_ENCRYPTION_OVERHEAD;
|
||||
|
||||
QUIC_VAR_INT FrameType INIT_NO_SAL(0);
|
||||
uint16_t offset = 0;
|
||||
uint16_t PayloadLength = packet->PayloadLength;
|
||||
while (offset < PayloadLength) {
|
||||
QuicVarIntDecode(PayloadLength, Payload, &offset, &FrameType);
|
||||
if (FrameType == QUIC_FRAME_ACK) {
|
||||
QUIC_VAR_INT temp INIT_NO_SAL(0);
|
||||
for (int i=0; i < 4; i++) {
|
||||
QuicVarIntDecode(PayloadLength, Payload, &offset, &temp);
|
||||
}
|
||||
}
|
||||
if (FrameType == QUIC_FRAME_CRYPTO) {
|
||||
QUIC_CRYPTO_EX Frame;
|
||||
QuicCryptoFrameDecode(packet->PayloadLength, Payload, &offset, &Frame);
|
||||
uint64_t FlowControlLimit = UINT16_MAX;
|
||||
BOOLEAN DataReady;
|
||||
DataReady = FALSE;
|
||||
CxPlatCopyMemory(
|
||||
recvBuffer + (uint32_t)Frame.Offset,
|
||||
Frame.Data,
|
||||
(uint32_t)Frame.Length);
|
||||
uint32_t recvBufferLength = (uint32_t)Frame.Length + (uint32_t)Frame.Offset - bufferoffset;
|
||||
recvBufferLength = QuicCryptoTlsGetCompleteTlsMessagesLength(
|
||||
recvBuffer + bufferoffset, recvBufferLength);
|
||||
auto Result = CxPlatTlsProcessData(
|
||||
HandshakeClientContext.Ptr,
|
||||
CXPLAT_TLS_CRYPTO_DATA,
|
||||
recvBuffer + bufferoffset,
|
||||
&recvBufferLength,
|
||||
&HandshakeClientContext.State);
|
||||
if (Result & CXPLAT_TLS_RESULT_ERROR) {
|
||||
printf("Failed to process handshake data!\n");
|
||||
}
|
||||
bufferoffset += recvBufferLength;
|
||||
HandshakePacketParams.LargestAcknowledge = packet->PacketNumber;
|
||||
if (packet->LH->Type == QUIC_INITIAL_V1) {
|
||||
bufferoffset = 0;
|
||||
HandshakePacketParams.NumFrames = 1;
|
||||
HandshakePacketParams.FrameTypes[0] = QUIC_FRAME_ACK;
|
||||
HandshakePacketParams.LargestAcknowledge = packet->PacketNumber;
|
||||
HandshakePacketParams.SourceCid = (uint8_t *)packet->DestCid;
|
||||
HandshakePacketParams.SourceCidLen = packet->DestCidLen;
|
||||
HandshakePacketParams.DestCid = (uint8_t *)packet->SourceCid;
|
||||
HandshakePacketParams.DestCidLen = packet->SourceCidLen;
|
||||
HandshakePacketParams.PacketType = QUIC_INITIAL_V1;
|
||||
HandshakePacketParams.Mode = 1;
|
||||
sendPacket(Binding, Route, &InitialPacketCount, &TotalByteCount, &HandshakePacketParams, false, &HandshakeClientContext);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (HandshakeClientContext.State.HandshakeComplete) {
|
||||
bufferoffset = 0;
|
||||
HandshakePacketParams.PacketType = QUIC_HANDSHAKE_V1;
|
||||
HandshakePacketParams.NumFrames = 2;
|
||||
HandshakePacketParams.FrameTypes[0] = QUIC_FRAME_ACK;
|
||||
HandshakePacketParams.FrameTypes[1] = QUIC_FRAME_CRYPTO;
|
||||
HandshakePacketParams.SourceCid = (uint8_t *)packet->DestCid;
|
||||
HandshakePacketParams.SourceCidLen = packet->DestCidLen;
|
||||
HandshakePacketParams.DestCid = (uint8_t *)packet->SourceCid;
|
||||
HandshakePacketParams.DestCidLen = packet->SourceCidLen;
|
||||
HandshakePacketParams.Mode = 1;
|
||||
HandshakePacketParams.NumPackets = (uint8_t)GetRandom(3) + 1;
|
||||
sendPacket(Binding, Route, &HandshakePacketCount, &TotalByteCount, &HandshakePacketParams, true, &HandshakeClientContext);
|
||||
handshakeComplete = FALSE;
|
||||
CXPLAT_FREE(packet, QUIC_POOL_TOOL);
|
||||
PacketQueue.pop_front();
|
||||
break;
|
||||
}
|
||||
CXPLAT_FREE(packet, QUIC_POOL_TOOL);
|
||||
PacketQueue.pop_front();
|
||||
}
|
||||
|
||||
for (uint8_t i = 0; i < QUIC_PACKET_KEY_COUNT; ++i) {
|
||||
if (HandshakeClientContext.State.ReadKeys[i] != nullptr) {
|
||||
QuicPacketKeyFree(HandshakeClientContext.State.ReadKeys[i]);
|
||||
HandshakeClientContext.State.ReadKeys[i] = nullptr;
|
||||
}
|
||||
if (HandshakeClientContext.State.WriteKeys[i] != nullptr) {
|
||||
QuicPacketKeyFree(HandshakeClientContext.State.WriteKeys[i]);
|
||||
HandshakeClientContext.State.WriteKeys[i] = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
printf("Total Packets sent: %lld\n", (long long)PacketCount);
|
||||
printf("Total Bytes sent: %lld\n", (long long)TotalByteCount);
|
||||
while (!PacketQueue.empty()) {
|
||||
QUIC_RX_PACKET* packet = PacketQueue.front();
|
||||
CXPLAT_FREE(packet, QUIC_POOL_TOOL);
|
||||
PacketQueue.pop_front();
|
||||
}
|
||||
printf("Total Initial Packets sent: %lld\n", (long long)InitialPacketCount);
|
||||
printf("Total Handshake Packets sent: %lld\n", (long long)HandshakePacketCount);
|
||||
printf("Total Bytes sent: %lld\n", (long long)TotalByteCount);
|
||||
}
|
||||
|
||||
void start() {
|
||||
|
@ -576,10 +983,6 @@ void start() {
|
|||
UdpConfig.Flags = 0;
|
||||
UdpConfig.InterfaceIndex = 0;
|
||||
UdpConfig.CallbackContext = nullptr;
|
||||
QUIC_ADDR_STR str;
|
||||
QuicAddrToString(&sockAddr, &str);
|
||||
printf("Remote address: %s\n", str.Address);
|
||||
|
||||
Status =
|
||||
CxPlatSocketCreateUdp(
|
||||
Datapath,
|
||||
|
@ -593,7 +996,6 @@ void start() {
|
|||
CXPLAT_ROUTE Route = {0};
|
||||
CxPlatSocketGetLocalAddress(Binding, &Route.LocalAddress);
|
||||
Route.RemoteAddress = sockAddr;
|
||||
|
||||
// Fuzzing
|
||||
fuzz(Binding, Route);
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче