mirror of
https://github.com/zeek/zeek.git
synced 2025-10-02 06:38:20 +00:00
quic: Squashed follow-ups: quic.log, tests, various fixes, performance
This commit is contained in:
parent
44d7c45723
commit
359f8d2ae6
65 changed files with 1194 additions and 532 deletions
|
@ -1 +1,2 @@
|
|||
@load ./consts
|
||||
@load ./main
|
||||
|
|
7
scripts/base/protocols/quic/consts.zeek
Normal file
7
scripts/base/protocols/quic/consts.zeek
Normal file
|
@ -0,0 +1,7 @@
|
|||
module QUIC;
|
||||
|
||||
export {
|
||||
const version_strings: table[count] of string = {
|
||||
[0x00000001] = "1",
|
||||
} &default=function(version: count): string { return fmt("unknown-%x", version); };
|
||||
}
|
|
@ -1,2 +1,215 @@
|
|||
##! Initial idea for a quic.log.
|
||||
|
||||
@load base/frameworks/notice/weird
|
||||
@load base/protocols/conn/removal-hooks
|
||||
|
||||
@load ./consts
|
||||
|
||||
module QUIC;
|
||||
|
||||
export {
|
||||
redef enum Log::ID += { LOG };
|
||||
|
||||
type Info: record {
|
||||
## Timestamp of first QUIC packet for this entry.
|
||||
ts: time &log;
|
||||
## Unique ID for the connection.
|
||||
uid: string &log;
|
||||
## The connection's 4-tuple of endpoint addresses/ports.
|
||||
id: conn_id &log;
|
||||
|
||||
## QUIC version as found in the first INITIAL packet from
|
||||
## the client.
|
||||
version: string &log;
|
||||
|
||||
## First Destination Connection ID used by client. This is
|
||||
## random and unpredictable, but used for packet protection
|
||||
## by client and server.
|
||||
client_initial_dcid: string &log &optional;
|
||||
|
||||
## Server chosen Connection ID usually from server's first
|
||||
## INITIAL packet. This is to be used by the client in
|
||||
## subsequent packets.
|
||||
server_scid: string &log &optional;
|
||||
|
||||
## Server name extracted from SNI extension in ClientHello
|
||||
## packet if available.
|
||||
server_name: string &log &optional;
|
||||
|
||||
## First protocol extracted from ALPN extension in ClientHello
|
||||
## packet if available.
|
||||
client_protocol: string &log &optional;
|
||||
|
||||
## Experimental QUIC history.
|
||||
##
|
||||
## Letters have the following meaning with client-sent
|
||||
## letters being capitalized:
|
||||
##
|
||||
## ====== ====================================================
|
||||
## Letter Meaning
|
||||
## ====== ====================================================
|
||||
## I INIT packet
|
||||
## H HANDSHAKE packet
|
||||
## Z 0RTT packet
|
||||
## R RETRY packet
|
||||
## C CONNECTION_CLOSE packet
|
||||
## S SSL Client/Server Hello
|
||||
## ====== ====================================================
|
||||
history: string &log &default="";
|
||||
|
||||
# Internal state for the history field.
|
||||
history_state: vector of string;
|
||||
|
||||
# Internal state if this record has already been logged.
|
||||
logged: bool &default=F;
|
||||
};
|
||||
|
||||
global log_quic: event(rec: Info);
|
||||
|
||||
global log_policy: Log::PolicyHook;
|
||||
|
||||
global finalize_quic: Conn::RemovalHook;
|
||||
}
|
||||
|
||||
redef record connection += {
|
||||
# XXX: We may have multiple QUIC connections with different
|
||||
# Connection ID over the same UDP connection.
|
||||
quic: Info &optional;
|
||||
};
|
||||
|
||||
# Faster to modify here than re-compiling .evt files.
|
||||
const quic_ports = {
|
||||
443/udp, # HTTP3-over-QUIC
|
||||
853/udp, # DNS-over-QUIC
|
||||
784/udp, # DNS-over-QUIC early
|
||||
};
|
||||
|
||||
function add_to_history(quic: Info, is_orig: bool, what: string)
|
||||
{
|
||||
if ( |quic$history_state| == 10 )
|
||||
return;
|
||||
|
||||
quic$history_state += is_orig ? to_upper(what[0]) : to_lower(what[0]);
|
||||
}
|
||||
|
||||
function log_record(quic: Info)
|
||||
{
|
||||
quic$history = join_string_vec(quic$history_state, "");
|
||||
Log::write(LOG, quic);
|
||||
quic$logged = T;
|
||||
}
|
||||
|
||||
function set_conn(c: connection, is_orig: bool, version: count, dcid: string, scid: string)
|
||||
{
|
||||
if ( ! c?$quic )
|
||||
{
|
||||
c$quic = Info(
|
||||
$ts=network_time(),
|
||||
$uid=c$uid,
|
||||
$id=c$id,
|
||||
$version=version_strings[version],
|
||||
);
|
||||
|
||||
Conn::register_removal_hook(c, finalize_quic);
|
||||
}
|
||||
|
||||
if ( is_orig && |dcid| > 0 && ! c$quic?$client_initial_dcid )
|
||||
c$quic$client_initial_dcid = bytestring_to_hexstr(dcid);
|
||||
|
||||
if ( ! is_orig && |scid| > 0 )
|
||||
c$quic$server_scid = bytestring_to_hexstr(scid);
|
||||
}
|
||||
|
||||
event QUIC::initial_packet(c: connection, is_orig: bool, version: count, dcid: string, scid: string)
|
||||
{
|
||||
set_conn(c, is_orig, version, dcid, scid);
|
||||
add_to_history(c$quic, is_orig, "INIT");
|
||||
}
|
||||
|
||||
event QUIC::handshake_packet(c: connection, is_orig: bool, version: count, dcid: string, scid: string)
|
||||
{
|
||||
set_conn(c, is_orig, version, dcid, scid);
|
||||
add_to_history(c$quic, is_orig, "HANDSHAKE");
|
||||
}
|
||||
|
||||
event QUIC::zero_rtt_packet(c: connection, is_orig: bool, version: count, dcid: string, scid: string)
|
||||
{
|
||||
set_conn(c, is_orig, version, dcid, scid);
|
||||
add_to_history(c$quic, is_orig, "ZeroRTT");
|
||||
}
|
||||
|
||||
# RETRY packets trigger a log entry and state reset.
|
||||
event QUIC::retry_packet(c: connection, is_orig: bool, version: count, dcid: string, scid: string, retry_token: string, integrity_tag: string)
|
||||
{
|
||||
if ( ! c?$quic )
|
||||
set_conn(c, is_orig, version, dcid, scid);
|
||||
|
||||
add_to_history(c$quic, is_orig, "RETRY");
|
||||
|
||||
log_record(c$quic);
|
||||
|
||||
delete c$quic;
|
||||
}
|
||||
|
||||
# Upon a connection_close_frame(), if any c$quic state is pending to be logged, do so
|
||||
# now and prepare for a new entry.
|
||||
event QUIC::connection_close_frame(c: connection, is_orig: bool, version: count, dcid: string, scid: string, error_code: count, reason_phrase: string)
|
||||
{
|
||||
if ( ! c?$quic )
|
||||
return;
|
||||
|
||||
add_to_history(c$quic, is_orig, "CONNECTION_CLOSE");
|
||||
|
||||
log_record(c$quic);
|
||||
|
||||
delete c$quic;
|
||||
}
|
||||
|
||||
event ssl_extension_server_name(c: connection, is_client: bool, names: string_vec) &priority=5
|
||||
{
|
||||
if ( is_client && c?$quic && |names| > 0 )
|
||||
c$quic$server_name = names[0];
|
||||
}
|
||||
|
||||
event ssl_extension_application_layer_protocol_negotiation(c: connection, is_client: bool, protocols: string_vec)
|
||||
{
|
||||
if ( c?$quic && is_client )
|
||||
{
|
||||
c$quic$client_protocol = protocols[0];
|
||||
if ( |protocols| > 1 )
|
||||
# Probably not overly weird, but the quic.log only
|
||||
# works with the first one in the hope to avoid
|
||||
# vector or concatenation.
|
||||
Reporter::conn_weird("QUIC_many_protocols", c, cat(protocols));
|
||||
}
|
||||
}
|
||||
|
||||
event ssl_client_hello(c: connection, version: count, record_version: count, possible_ts: time, client_random: string, session_id: string, ciphers: index_vec, comp_methods: index_vec)
|
||||
{
|
||||
if ( ! c?$quic )
|
||||
return;
|
||||
|
||||
add_to_history(c$quic, T, "SSL");
|
||||
}
|
||||
|
||||
event ssl_server_hello(c: connection, version: count, record_version: count, possible_ts: time, server_random: string, session_id: string, cipher: count, comp_method: count) &priority=-5
|
||||
{
|
||||
if ( ! c?$quic )
|
||||
return;
|
||||
|
||||
add_to_history(c$quic, F, "SSL");
|
||||
}
|
||||
|
||||
hook finalize_quic(c: connection)
|
||||
{
|
||||
if ( ! c?$quic || c$quic$logged )
|
||||
return;
|
||||
|
||||
log_record(c$quic);
|
||||
}
|
||||
|
||||
event zeek_init()
|
||||
{
|
||||
Log::create_stream(LOG, [$columns=Info, $ev=log_quic, $path="quic", $policy=log_policy]);
|
||||
Analyzer::register_for_ports(Analyzer::ANALYZER_QUIC, quic_ports);
|
||||
}
|
||||
|
|
|
@ -1,5 +1,23 @@
|
|||
spicy_add_analyzer(
|
||||
NAME QUIC
|
||||
PACKAGE_NAME QUIC
|
||||
SOURCES decrypt_crypto.cc QUIC.spicy QUIC.evt zeek_QUIC.spicy
|
||||
SCRIPTS __load__.zeek main.zeek)
|
||||
SOURCES QUIC.spicy QUIC.evt
|
||||
SCRIPTS __load__.zeek main.zeek
|
||||
CXX_LINK ${CMAKE_CURRENT_BINARY_DIR}/libdecrypt_crypto.a)
|
||||
|
||||
add_dependencies(QUIC decrypt_crypto)
|
||||
|
||||
find_program(SPICY_CONFIG name spicy-config REQUIRED)
|
||||
execute_process(
|
||||
COMMAND ${SPICY_CONFIG} --include-dirs
|
||||
OUTPUT_VARIABLE SPICY_INCLUDE_DIRS)
|
||||
string(REPLACE " " ";" SPICY_INCLUDE_DIRS ${SPICY_INCLUDE_DIRS})
|
||||
|
||||
find_package(OpenSSL REQUIRED)
|
||||
add_library(decrypt_crypto STATIC decrypt_crypto.cc)
|
||||
set_target_properties(
|
||||
decrypt_crypto PROPERTIES
|
||||
CXX_STANDARD 17
|
||||
POSITION_INDEPENDENT_CODE ON)
|
||||
target_include_directories(decrypt_crypto PRIVATE "${OPENSSL_INCLUDE_DIR}" "${SPICY_INCLUDE_DIRS}")
|
||||
target_link_libraries(decrypt_crypto ${OpenSSL_LIBRARIES})
|
||||
|
|
|
@ -1,10 +1,19 @@
|
|||
protocol analyzer spicy::QUIC over UDP:
|
||||
protocol analyzer QUIC over UDP:
|
||||
parse originator with QUIC::RequestFrame,
|
||||
parse responder with QUIC::ResponseFrame,
|
||||
ports { 443/udp };
|
||||
parse responder with QUIC::ResponseFrame;
|
||||
|
||||
import QUIC;
|
||||
import Zeek_QUIC;
|
||||
|
||||
# TODO: Add actual events, instead of this dummy event
|
||||
on QUIC::ResponseFrame -> event QUIC::example($conn);
|
||||
# Make the enum available.
|
||||
export QUIC::LongPacketType;
|
||||
|
||||
on QUIC::InitialPacket -> event QUIC::initial_packet($conn, $is_orig, self.header.version, self.header.dest_conn_id, self.header.src_conn_id);
|
||||
|
||||
on QUIC::RetryPacket -> event QUIC::retry_packet($conn, $is_orig, self.header.version, self.header.dest_conn_id, self.header.src_conn_id, self.retry_token, self.integrity_tag);
|
||||
|
||||
on QUIC::HandshakePacket -> event QUIC::handshake_packet($conn, $is_orig, self.header.version, self.header.dest_conn_id, self.header.src_conn_id);
|
||||
|
||||
on QUIC::ZeroRTTPacket -> event QUIC::zero_rtt_packet($conn, $is_orig, self.header.version, self.header.dest_conn_id, self.header.src_conn_id);
|
||||
|
||||
on QUIC::ConnectionClosePayload -> event QUIC::connection_close_frame($conn, $is_orig, self.header.version, self.header.dest_conn_id, self.header.src_conn_id,
|
||||
self.error_code.result, self.reason_phrase);
|
||||
|
|
|
@ -4,26 +4,74 @@ import spicy;
|
|||
import zeek;
|
||||
|
||||
# The interface to the C++ code that handles the decryption of the INITIAL packet payload using well-known keys
|
||||
public function decrypt_crypto_payload(entire_packet: bytes, connection_id: bytes, encrypted_offset: uint64, payload_offset: uint64, from_client: bool): bytes &cxxname="decrypt_crypto_payload";
|
||||
public function decrypt_crypto_payload(
|
||||
all_data: bytes,
|
||||
connection_id: bytes,
|
||||
encrypted_offset: uint64,
|
||||
payload_offset: uint64,
|
||||
from_client: bool
|
||||
): bytes &cxxname="QUIC_decrypt_crypto_payload";
|
||||
|
||||
|
||||
##############
|
||||
## Context - tracked in one connection
|
||||
##############
|
||||
|
||||
type ConnectionIDInfo = unit {
|
||||
var client_cid_len: uint8;
|
||||
var server_cid_len: uint8;
|
||||
var initial_destination_conn_id: bytes;
|
||||
var initial_packets_exchanged: bool;
|
||||
var initialized: bool;
|
||||
# Can we decrypt?
|
||||
function can_decrypt(long_header: LongHeaderPacket, context: ConnectionIDInfo, is_client: bool): bool {
|
||||
|
||||
on %init {
|
||||
self.client_cid_len = 0;
|
||||
self.server_cid_len = 0;
|
||||
self.initial_packets_exchanged = False;
|
||||
self.initialized = False;
|
||||
}
|
||||
if ( long_header.first_byte.packet_type != LongPacketType::INITIAL )
|
||||
return False;
|
||||
|
||||
# decrypt_crypto_payload() has known secrets for version 1, nothing else.
|
||||
if ( long_header.version != 0x00000001 )
|
||||
return False;
|
||||
|
||||
if ( is_client )
|
||||
return ! context.client_initial_processed;
|
||||
|
||||
# This is the responder, can only decrypt if we have an initial
|
||||
# destination_id from the client
|
||||
return context.client_initial_processed
|
||||
&& |context.initial_destination_conn_id| > 0
|
||||
&& ! context.server_initial_processed;
|
||||
}
|
||||
|
||||
type ConnectionIDInfo = struct {
|
||||
client_cid_len: uint8;
|
||||
server_cid_len: uint8;
|
||||
|
||||
# The DCID used by the client is employed by client and
|
||||
# server for packet protection. Packet re-ordering
|
||||
# will make life miserable.
|
||||
#
|
||||
# https://quicwg.org/base-drafts/rfc9001.html#appendix-A
|
||||
initial_destination_conn_id: bytes;
|
||||
|
||||
# Currently, this analyzer assumes that ClientHello
|
||||
# and ServerHello fit into the first INITIAL packet (and
|
||||
# that there is only one that we're interested in.
|
||||
#
|
||||
# But minimally the following section sounds like this might not
|
||||
# hold in general and the Wireshark has samples showing
|
||||
# the handshake spanning across more than two INITIAL packets.
|
||||
# (quic-fragmented-handshakes.pcapng.gz)
|
||||
#
|
||||
# https://datatracker.ietf.org/doc/html/rfc9001#section-4.3
|
||||
#
|
||||
# Possible fix is to buffer up all CRYPTO frames across multiple
|
||||
# INITIAL packets until we see a non-INITIAL frame.
|
||||
#
|
||||
# We also rely heavily on getting originator and responder right.
|
||||
#
|
||||
client_initial_processed: bool;
|
||||
server_initial_processed: bool;
|
||||
|
||||
@if SPICY_VERSION >= 10800
|
||||
ssl_handle: zeek::ProtocolHandle &optional;
|
||||
@else
|
||||
did_ssl_begin: bool;
|
||||
@endif
|
||||
};
|
||||
|
||||
##############
|
||||
|
@ -80,74 +128,26 @@ type FrameType = enum {
|
|||
# Helper units
|
||||
##############
|
||||
|
||||
# Used to peek into the next byte and determine if it's a long or short packet
|
||||
public type InitialByte = unit {
|
||||
initialbyte: bitfield(8) {
|
||||
header_form: 7 &convert=cast<HeaderForm>(cast<uint8>($$));
|
||||
};
|
||||
on %done{
|
||||
self.backtrack();
|
||||
}
|
||||
};
|
||||
|
||||
# Used to peek into the next byte and check it's value
|
||||
type InitialUint8 = unit {
|
||||
var bt: uint8;
|
||||
: uint8 {
|
||||
self.bt = $$;
|
||||
}
|
||||
|
||||
on %done{
|
||||
self.backtrack();
|
||||
}
|
||||
};
|
||||
|
||||
# https://datatracker.ietf.org/doc/rfc9000/
|
||||
# Section 16 and Appendix A
|
||||
type VariableLengthIntegerLength = unit {
|
||||
var length: uint8;
|
||||
|
||||
a: bitfield(8) {
|
||||
length: 6..7 &convert=cast<uint8>($$) &byte-order=spicy::ByteOrder::Big;
|
||||
};
|
||||
|
||||
on %done {
|
||||
self.length = self.a.length;
|
||||
self.backtrack();
|
||||
}
|
||||
};
|
||||
|
||||
type VariableLengthInteger = unit {
|
||||
var bytes_to_parse: uint64;
|
||||
var result: uint64;
|
||||
var result_bytes: bytes;
|
||||
|
||||
: VariableLengthIntegerLength &try {
|
||||
switch ( $$.length ) {
|
||||
case 0:
|
||||
self.bytes_to_parse = 1;
|
||||
case 1:
|
||||
self.bytes_to_parse = 2;
|
||||
case 2:
|
||||
self.bytes_to_parse = 4;
|
||||
case 3:
|
||||
self.bytes_to_parse = 8;
|
||||
}
|
||||
# Value of the two most significant bits indicates number of bytes
|
||||
# to parse for the variable length integer.
|
||||
#
|
||||
# https://datatracker.ietf.org/doc/rfc9000/
|
||||
# Section 16 and Appendix A
|
||||
#
|
||||
first_byte: bytes &size=1 {
|
||||
local uint8_val = uint8($$.to_uint(spicy::ByteOrder::Big));
|
||||
self.bytes_to_parse = 2**((0xC0 & uint8_val) >> 6);
|
||||
# Re-pack without most significant two bits for later use.
|
||||
self.first_byte = pack(0x3f & uint8_val, spicy::ByteOrder::Big);
|
||||
}
|
||||
remaining_bytes: bytes &size=self.bytes_to_parse - 1;
|
||||
|
||||
# Parse the required amount of bytes and apply a mask to clear the
|
||||
# first two bits, leaving the actual length
|
||||
remainder: bytes &size=self.bytes_to_parse {
|
||||
switch ( self.bytes_to_parse ) {
|
||||
case 1:
|
||||
self.result = $$.to_uint(spicy::ByteOrder::Big) & 0x3f;
|
||||
case 2:
|
||||
self.result = $$.to_uint(spicy::ByteOrder::Big) & 0x3fff;
|
||||
case 4:
|
||||
self.result = $$.to_uint(spicy::ByteOrder::Big) & 0x3fffffff;
|
||||
case 8:
|
||||
self.result = $$.to_uint(spicy::ByteOrder::Big) & 0x3fffffffffffffff;
|
||||
}
|
||||
on %done {
|
||||
self.result = (self.first_byte + self.remaining_bytes).to_uint(spicy::ByteOrder::Big);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -156,22 +156,7 @@ type VariableLengthInteger = unit {
|
|||
# Generic units
|
||||
##############
|
||||
|
||||
# Used to capture all data form the entire frame. May be inefficient, but works for now.
|
||||
# This is passed to the decryption function, as this function needs both the header and the payload
|
||||
# Performs a backtrack() at the end
|
||||
type AllData = unit {
|
||||
var data: bytes;
|
||||
|
||||
: bytes &eod {
|
||||
self.data = $$;
|
||||
}
|
||||
|
||||
on %done {
|
||||
self.backtrack();
|
||||
}
|
||||
};
|
||||
|
||||
public type LongHeader = unit {
|
||||
public type LongHeaderPacket = unit {
|
||||
var encrypted_offset: uint64;
|
||||
var payload_length: uint64;
|
||||
var client_conn_id_length: uint8;
|
||||
|
@ -190,84 +175,68 @@ public type LongHeader = unit {
|
|||
src_conn_id_len: uint8 { self.client_conn_id_length = $$; }
|
||||
src_conn_id: bytes &size=self.client_conn_id_length;
|
||||
|
||||
# We pass the type specific 4 bits too and don't parse them again
|
||||
switch ( self.first_byte.packet_type ) {
|
||||
LongPacketType::INITIAL -> initial_hdr : InitialLongPacketHeader(self.first_byte.type_specific_bits) {
|
||||
LongPacketType::INITIAL -> initial_hdr : InitialPacket(self) {
|
||||
self.encrypted_offset = self.offset() +
|
||||
self.initial_hdr.payload_length.bytes_to_parse +
|
||||
self.initial_hdr.length.bytes_to_parse +
|
||||
self.initial_hdr.token_length.bytes_to_parse +
|
||||
self.initial_hdr.token_length.result;
|
||||
self.payload_length = self.initial_hdr.payload_length.result;
|
||||
self.payload_length = self.initial_hdr.length.result;
|
||||
}
|
||||
LongPacketType::ZERO_RTT -> zerortt_hdr : ZeroRTTLongPacketHeader(self.first_byte.type_specific_bits);
|
||||
LongPacketType::HANDSHAKE -> handshake_hdr : HandshakeLongPacketHeader(self.first_byte.type_specific_bits);
|
||||
LongPacketType::RETRY -> retry_hdr : RetryLongPacketHeader(self.first_byte.type_specific_bits);
|
||||
|
||||
LongPacketType::ZERO_RTT -> zerortt_hdr : ZeroRTTPacket(self);
|
||||
LongPacketType::HANDSHAKE -> handshake_hdr : HandshakePacket(self);
|
||||
LongPacketType::RETRY -> retry_hdr : RetryPacket(self);
|
||||
};
|
||||
};
|
||||
|
||||
# Decrypted long packet payload that can actually be parsed
|
||||
public type DecryptedLongPacketPayload = unit(packet_type: LongPacketType, from_client: bool) {
|
||||
# A QUIC Frame.
|
||||
public type Frame = unit(header: LongHeaderPacket, from_client: bool, crypto_sink: sink) {
|
||||
frame_type : uint8 &convert=cast<FrameType>($$);
|
||||
|
||||
# TODO: add other FrameTypes as well
|
||||
switch ( self.frame_type ) {
|
||||
FrameType::ACK1 -> a: ACKPayload;
|
||||
FrameType::ACK2 -> b: ACKPayload;
|
||||
FrameType::CRYPTO -> c: CRYPTOPayload(from_client);
|
||||
FrameType::PADDING -> d: PADDINGPayload;
|
||||
FrameType::CRYPTO -> c: CRYPTOPayload(from_client) {
|
||||
# Have the sink re-assemble potentially out-of-order cryptodata
|
||||
crypto_sink.write(self.c.cryptodata, self.c.offset.result);
|
||||
}
|
||||
FrameType::CONNECTION_CLOSE1 -> : ConnectionClosePayload(header);
|
||||
@if SPICY_VERSION >= 10800
|
||||
FrameType::PADDING -> : skip /\x00*/; # eat the padding
|
||||
@else
|
||||
FrameType::PADDING -> : /\x00*/; # eat the padding
|
||||
@endif
|
||||
FrameType::PING -> : void;
|
||||
* -> : void {
|
||||
throw "unhandled frame type %s in %s" % (self.frame_type, header.first_byte.packet_type);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
# TODO: investigate whether we can do something useful with this
|
||||
public type EncryptedLongPacketPayload = unit {
|
||||
payload: bytes &eod;
|
||||
};
|
||||
|
||||
# Determines how to parse the long packet payload, depending on whether is was decrypted or not
|
||||
public type LongPacketPayload = unit(packet_type: LongPacketType, from_client: bool, encrypted: bool) {
|
||||
: DecryptedLongPacketPayload(packet_type, from_client) if (encrypted == False);
|
||||
: EncryptedLongPacketPayload if (encrypted == True);
|
||||
};
|
||||
|
||||
type CRYPTOPayload = unit(from_client: bool) {
|
||||
var length_in_byte1: bytes;
|
||||
var length_in_byte2: bytes;
|
||||
|
||||
offset: uint8;
|
||||
offset: VariableLengthInteger;
|
||||
length: VariableLengthInteger;
|
||||
cryptodata: bytes &size=self.length.result;
|
||||
|
||||
on %done {
|
||||
# As of 5 Sept. 2022 there is no function to convert a unsigned integer back to bytes.
|
||||
# Therefore, the following (quite dirty) method is used. Should be fixed/improved whenever
|
||||
# a better alternative is available.
|
||||
# It converts a uint16 to its two-byte representation.
|
||||
self.length_in_byte1 = ("%c" % cast<uint8>((self.length.result >> 8) & 0xff)).encode();
|
||||
self.length_in_byte2 = ("%c" % cast<uint8>(self.length.result & 0xff)).encode();
|
||||
|
||||
# The data is passed to the SSL analyzer as part of a HANDSHAKE (0x16) message with TLS1.3 (\x03\x03).
|
||||
# The 2 length bytes are also passed, followed by the actual CRYPTO blob which contains a CLIENT HELLO or SERVER HELLO
|
||||
zeek::protocol_data_in(from_client, b"\x16\x03\x03" + self.length_in_byte1 + self.length_in_byte2 + self.cryptodata);
|
||||
}
|
||||
};
|
||||
|
||||
type ACKPayload = unit {
|
||||
latest_ack: uint8;
|
||||
ack_delay: uint8;
|
||||
ack_range_count: uint8;
|
||||
first_ack_range: uint8;
|
||||
latest_ack: VariableLengthInteger;
|
||||
ack_delay: VariableLengthInteger;
|
||||
ack_range_count: VariableLengthInteger;
|
||||
first_ack_range: VariableLengthInteger;
|
||||
};
|
||||
|
||||
public type NullBytes = unit {
|
||||
: (b"\x00")[];
|
||||
x: InitialUint8 &try;
|
||||
};
|
||||
|
||||
type PADDINGPayload = unit {
|
||||
var padding_length: uint64 = 0;
|
||||
|
||||
# Simply consume all next nullbytes
|
||||
: NullBytes;
|
||||
type ConnectionClosePayload = unit(header: LongHeaderPacket) {
|
||||
var header: LongHeaderPacket = header;
|
||||
error_code: VariableLengthInteger;
|
||||
switch {
|
||||
-> unknown_frame_type: b"\x00";
|
||||
-> frame_type: VariableLengthInteger;
|
||||
};
|
||||
reason_phrase_length: VariableLengthInteger;
|
||||
reason_phrase: bytes &size=self.reason_phrase_length.result;
|
||||
};
|
||||
|
||||
|
||||
|
@ -276,25 +245,68 @@ type PADDINGPayload = unit {
|
|||
# Specific long packet type units
|
||||
##############
|
||||
|
||||
type InitialLongPacketHeader = unit(type_specific_bits: uint8) {
|
||||
var packet_number_length_full: uint8;
|
||||
|
||||
# Remainder of an Initial packet
|
||||
type InitialPacket = unit(header: LongHeaderPacket) {
|
||||
var header: LongHeaderPacket = header;
|
||||
token_length: VariableLengthInteger;
|
||||
token: bytes &size=self.token_length.result;
|
||||
payload_length: VariableLengthInteger;
|
||||
packet_number: bytes &size=self.packet_number_length_full &convert=$$.to_uint(spicy::ByteOrder::Big);
|
||||
|
||||
on %init {
|
||||
# Calculate the packet number length while the initial byte is still encoded.
|
||||
# Will result in 0, 1, 2 or 3. So we need to read n+1 bytes to properly parse the header.
|
||||
self.packet_number_length_full = (type_specific_bits & 0x03) + 1;
|
||||
}
|
||||
# 5.4.2. Header Protection Sample
|
||||
#
|
||||
# That is, in sampling packet ciphertext for header
|
||||
# protection, the Packet Number field is assumed to
|
||||
# be 4 bytes long (its maximum possible encoded length).
|
||||
#
|
||||
# Enforce 4 bytes Packet Number length + 16 bytes sample
|
||||
# ciphertext available.
|
||||
length: VariableLengthInteger &requires=self.length.result >= 20;
|
||||
|
||||
# Consume the remainder of payload. This
|
||||
# includes the packet number field, but we
|
||||
# do not know its length yet. We need the
|
||||
# payload for sampling, however.
|
||||
@if SPICY_VERSION >= 10800
|
||||
payload: skip bytes &size=self.length.result;
|
||||
@else
|
||||
payload: bytes &size=self.length.result;
|
||||
@endif
|
||||
};
|
||||
|
||||
# TODO: implement
|
||||
type ZeroRTTLongPacketHeader = unit(type_specific_bits: uint8) {};
|
||||
type HandshakeLongPacketHeader = unit(type_specific_bits: uint8) {};
|
||||
type RetryLongPacketHeader = unit(type_specific_bits: uint8) {};
|
||||
type ZeroRTTPacket = unit(header: LongHeaderPacket) {
|
||||
var header: LongHeaderPacket = header;
|
||||
length: VariableLengthInteger;
|
||||
@if SPICY_VERSION >= 10800
|
||||
payload: skip bytes &size=self.length.result;
|
||||
@else
|
||||
payload: bytes &size=self.length.result;
|
||||
@endif
|
||||
};
|
||||
|
||||
type HandshakePacket = unit(header: LongHeaderPacket) {
|
||||
var header: LongHeaderPacket = header;
|
||||
length: VariableLengthInteger;
|
||||
@if SPICY_VERSION >= 10800
|
||||
payload: skip bytes &size=self.length.result;
|
||||
@else
|
||||
payload: bytes &size=self.length.result;
|
||||
@endif
|
||||
};
|
||||
|
||||
|
||||
type RetryPacket = unit(header: LongHeaderPacket) {
|
||||
var header: LongHeaderPacket = header;
|
||||
var retry_token: bytes;
|
||||
var integrity_tag: bytes;
|
||||
|
||||
# A retry packet ends with a 128bit / 16 byte integrity
|
||||
# tag, but otherwise we do not know anything about the
|
||||
# size of the retry_token. Slurp the whole datagram and
|
||||
# post split it into the distinct parts.
|
||||
data: bytes &eod {
|
||||
self.retry_token = self.data.sub(0, |self.data| - 16);
|
||||
self.integrity_tag = self.data.sub(|self.data| - 16, |self.data|);
|
||||
}
|
||||
};
|
||||
|
||||
##############
|
||||
# Short packets
|
||||
|
@ -313,34 +325,104 @@ public type ShortHeader = unit(dest_conn_id_length: uint8) {
|
|||
|
||||
# TODO: investigate whether we can parse something useful out of this
|
||||
public type ShortPacketPayload = unit {
|
||||
@if SPICY_VERSION >= 10800
|
||||
payload: skip bytes &eod;
|
||||
@else
|
||||
payload: bytes &eod;
|
||||
@endif
|
||||
};
|
||||
|
||||
# TODO: investigate whether we can do something useful with this
|
||||
public type EncryptedLongPacketPayload = unit {
|
||||
@if SPICY_VERSION >= 10800
|
||||
payload: skip bytes &eod;
|
||||
@else
|
||||
payload: bytes &eod;
|
||||
@endif
|
||||
};
|
||||
|
||||
# Buffer all crypto messages (which might be fragmented and unordered)
|
||||
# into the following unit.
|
||||
type CryptoBuffer = unit() {
|
||||
|
||||
var buffered: bytes;
|
||||
|
||||
: bytes &chunked &eod {
|
||||
self.buffered += $$;
|
||||
# print "crypto_buffer got data", |$$|, |self.buffered|;
|
||||
}
|
||||
};
|
||||
|
||||
##############
|
||||
# QUIC frame parsing
|
||||
# QUIC packet parsing
|
||||
#
|
||||
# A UDP datagram contains one or more QUIC packets.
|
||||
##############
|
||||
type Frame = unit(from_client: bool, context: ConnectionIDInfo&) {
|
||||
var hdr_form: HeaderForm;
|
||||
type Packet = unit(from_client: bool, context: ConnectionIDInfo&) {
|
||||
var decrypted_data: bytes;
|
||||
var full_packet: bytes;
|
||||
var start: iterator<stream>;
|
||||
|
||||
# Peek into the header to check if it's a SHORT or LONG header
|
||||
: InitialByte &try {
|
||||
self.hdr_form = $$.initialbyte.header_form;
|
||||
sink crypto_sink;
|
||||
var crypto_buffer: CryptoBuffer&;
|
||||
|
||||
# Attach an SSL analyzer to this connection once.
|
||||
on %init {
|
||||
@if SPICY_VERSION >= 10800
|
||||
if ( ! context?.ssl_handle ) {
|
||||
context.ssl_handle = zeek::protocol_handle_get_or_create("SSL");
|
||||
}
|
||||
@else
|
||||
if ( ! context.did_ssl_begin ) {
|
||||
zeek::protocol_begin("SSL");
|
||||
context.did_ssl_begin = True;
|
||||
}
|
||||
@endif
|
||||
|
||||
self.start = self.input();
|
||||
}
|
||||
|
||||
# Peek into the first byte and determine the header type.
|
||||
first_byte: bitfield(8) {
|
||||
header_form: 7 &convert=HeaderForm($$);
|
||||
};
|
||||
|
||||
# TODO: Consider bitfield based look-ahead-parsing in the switch below
|
||||
# to avoid this rewinding here. It's a hack.
|
||||
: void {
|
||||
self.set_input(self.start); # rewind
|
||||
}
|
||||
|
||||
# Capture all the packet bytes if we're still have a chance of decrypting the INITIAL PACKETS
|
||||
fpack: AllData &try if (context.initial_packets_exchanged == False);
|
||||
|
||||
# Depending on the header, parse it and update the src/dest ConnectionID's
|
||||
switch ( self.hdr_form ) {
|
||||
switch ( self.first_byte.header_form ) {
|
||||
HeaderForm::SHORT -> short_header: ShortHeader(context.client_cid_len);
|
||||
HeaderForm::LONG -> long_header: LongHeader {
|
||||
HeaderForm::LONG -> long_header: LongHeaderPacket {
|
||||
# For now, only allow a change of src/dest ConnectionID's for INITIAL packets.
|
||||
# TODO: allow this for Retry packets
|
||||
|
||||
if ( self.long_header.first_byte.packet_type == LongPacketType::INITIAL
|
||||
&& context.initial_packets_exchanged == False ) {
|
||||
# If we see a retry packet from the responder, reset the decryption
|
||||
# context such that the next DCID from the client is used for decryption.
|
||||
if ( self.long_header.first_byte.packet_type == LongPacketType::RETRY ) {
|
||||
context.client_initial_processed = False;
|
||||
context.server_initial_processed = False;
|
||||
context.initial_destination_conn_id = b"";
|
||||
|
||||
# Allow re-opening the SSL analyzer the next time around.
|
||||
@if SPICY_VERSION >= 10800
|
||||
zeek::protocol_handle_close(context.ssl_handle);
|
||||
unset context.ssl_handle;
|
||||
@else
|
||||
zeek::protocol_end();
|
||||
context.did_ssl_begin = False;
|
||||
@endif
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
# Slurp in the whole packet if we determined we have a chance to decrypt.
|
||||
all_data: bytes &parse-at=self.start &eod if ( self?.long_header && can_decrypt(self.long_header, context, from_client) ) {
|
||||
self.crypto_buffer = new CryptoBuffer();
|
||||
self.crypto_sink.connect(self.crypto_buffer);
|
||||
|
||||
if ( from_client ) {
|
||||
context.server_cid_len = self.long_header.dest_conn_id_len;
|
||||
|
@ -348,15 +430,16 @@ type Frame = unit(from_client: bool, context: ConnectionIDInfo&) {
|
|||
|
||||
# This means that here, we can try to decrypt the initial packet!
|
||||
# All data is accessible via the `long_header` unit
|
||||
|
||||
self.decrypted_data = decrypt_crypto_payload(self.fpack.data,
|
||||
self.decrypted_data = decrypt_crypto_payload(
|
||||
self.all_data,
|
||||
self.long_header.dest_conn_id,
|
||||
self.long_header.encrypted_offset,
|
||||
self.long_header.payload_length,
|
||||
from_client);
|
||||
from_client
|
||||
);
|
||||
|
||||
# Set this to be the seed for the decryption
|
||||
if ( ! context.initial_packets_exchanged ) {
|
||||
if ( |context.initial_destination_conn_id| == 0 ) {
|
||||
context.initial_destination_conn_id = self.long_header.dest_conn_id;
|
||||
}
|
||||
|
||||
|
@ -366,33 +449,69 @@ type Frame = unit(from_client: bool, context: ConnectionIDInfo&) {
|
|||
|
||||
# Assuming that the client set up the connection, this can be considered the first
|
||||
# received Initial from the client. So disable change of ConnectionID's afterwards
|
||||
self.decrypted_data = decrypt_crypto_payload(self.fpack.data,
|
||||
self.decrypted_data = decrypt_crypto_payload(
|
||||
self.all_data,
|
||||
context.initial_destination_conn_id,
|
||||
self.long_header.encrypted_offset,
|
||||
self.long_header.payload_length,
|
||||
from_client);
|
||||
}
|
||||
from_client
|
||||
);
|
||||
}
|
||||
|
||||
# If it's a reply from the server and it's not a REPLY, we assume the keys are restablished and decryption is no longer possible
|
||||
# We attempted decryption, but it failed. Just reject the
|
||||
# input and assume Zeek will disable the analyzer for this
|
||||
# connection.
|
||||
if ( |self.decrypted_data| == 0 )
|
||||
throw "decryption failed";
|
||||
|
||||
# If this was a reply from the server and it's not a RETRY, we assume the keys
|
||||
# are restablished and decryption is no longer possible
|
||||
#
|
||||
# TODO: verify if this is actually correct per RFC
|
||||
if (self.long_header.first_byte.packet_type != LongPacketType::RETRY && ! from_client) {
|
||||
context.initial_packets_exchanged = True;
|
||||
if ( self.long_header.first_byte.packet_type != LongPacketType::RETRY && ! from_client ) {
|
||||
context.server_initial_processed = True;
|
||||
context.client_initial_processed = True;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
# Depending on the type of header, we parse the remaining payload.
|
||||
switch ( self.hdr_form ) {
|
||||
HeaderForm::SHORT -> remaining_short_payload: ShortPacketPayload;
|
||||
HeaderForm::LONG -> remaining_long_payload : LongPacketPayload(self.long_header.first_byte.packet_type, from_client, context.initial_packets_exchanged)[] &parse-from=self.decrypted_data;
|
||||
};
|
||||
# Depending on the type of header and whether we were able to decrypt
|
||||
# some of it, parse the remaining payload.
|
||||
: ShortPacketPayload if (self.first_byte.header_form == HeaderForm::SHORT);
|
||||
: EncryptedLongPacketPayload if (self.first_byte.header_form == HeaderForm::LONG && |self.decrypted_data| == 0);
|
||||
|
||||
on %init {
|
||||
# Make sure to only attach the SSL analyzer once per QUIC connection
|
||||
if ( ! context.initialized ) {
|
||||
context.initialized = True;
|
||||
zeek::protocol_begin("SSL");
|
||||
# If this was packet with a long header and decrypted data exists, attempt
|
||||
# to parse the plain QUIC frames from it.
|
||||
frames: Frame(self.long_header, from_client, self.crypto_sink)[] &parse-from=self.decrypted_data if (self.first_byte.header_form == HeaderForm::LONG && |self.decrypted_data| > 0);
|
||||
|
||||
# Once the Packet is fully parsed, pass the accumulated CRYPTO frames
|
||||
# to the SSL analyzer as handshake data.
|
||||
on %done {
|
||||
# print "packet done", zeek::is_orig(), self.first_byte.header_form, |self.decrypted_data|;
|
||||
|
||||
if ( self.crypto_buffer != Null && |self.crypto_buffer.buffered| > 0 ) {
|
||||
local handshake_data = self.crypto_buffer.buffered;
|
||||
|
||||
# The data is passed to the SSL analyzer as part of a HANDSHAKE (0x16) message with TLS1.3 (\x03\x03).
|
||||
# The 2 length bytes are also passed, followed by the actual CRYPTO blob which contains a CLIENT HELLO or SERVER HELLO
|
||||
local length_bytes = pack(cast<uint16>(|handshake_data|), spicy::ByteOrder::Big);
|
||||
zeek::protocol_data_in(
|
||||
from_client
|
||||
, b"\x16\x03\x03" + length_bytes + handshake_data
|
||||
# With Spicy 1.8.0, can use the SSL handle directly.
|
||||
@if SPICY_VERSION >= 10800
|
||||
, context.ssl_handle
|
||||
@endif
|
||||
);
|
||||
|
||||
# Stop decryption attempts after processing the very first
|
||||
# INITIAL packet.
|
||||
if ( from_client )
|
||||
context.client_initial_processed = True;
|
||||
else
|
||||
context.server_initial_processed = True;
|
||||
|
||||
# Take buffered crypto data as confirmation signal.
|
||||
spicy::accept_input();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -402,10 +521,10 @@ type Frame = unit(from_client: bool, context: ConnectionIDInfo&) {
|
|||
##############
|
||||
public type RequestFrame = unit {
|
||||
%context = ConnectionIDInfo;
|
||||
: Frame(True, self.context());
|
||||
: Packet(True, self.context());
|
||||
};
|
||||
|
||||
public type ResponseFrame = unit {
|
||||
%context = ConnectionIDInfo;
|
||||
: Frame(False, self.context());
|
||||
: Packet(False, self.context());
|
||||
};
|
||||
|
|
|
@ -8,29 +8,40 @@ refactors as C++ development is not our main profession.
|
|||
*/
|
||||
|
||||
// Default imports
|
||||
#include <stdlib.h>
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <vector>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
// OpenSSL imports
|
||||
#include <openssl/kdf.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/kdf.h>
|
||||
#include <openssl/sha.h>
|
||||
|
||||
// Import HILTI
|
||||
#include <hilti/rt/libhilti.h>
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
// Struct to store decryption info for this specific connection
|
||||
struct DecryptionInformation
|
||||
{
|
||||
{
|
||||
std::vector<uint8_t> unprotected_header;
|
||||
std::vector<uint8_t> protected_header;
|
||||
uint64_t packet_number;
|
||||
std::vector<uint8_t> nonce;
|
||||
uint8_t packet_number_length;
|
||||
};
|
||||
};
|
||||
|
||||
// Return rt::hilti::Bytes::data() value as const uint8_t*
|
||||
//
|
||||
// This should be alright: https://stackoverflow.com/a/15172304
|
||||
inline const uint8_t* data_as_uint8(const hilti::rt::Bytes& b)
|
||||
{
|
||||
return reinterpret_cast<const uint8_t*>(b.data());
|
||||
}
|
||||
|
||||
/*
|
||||
Constants used in the HKDF functions. HKDF-Expand-Label uses labels
|
||||
|
@ -39,41 +50,25 @@ calculated dynamically, but are incluced statically for now, as the
|
|||
goal of this analyser is only to analyze the INITIAL packets.
|
||||
*/
|
||||
|
||||
std::vector<uint8_t> INITIAL_SALT_V1 = {
|
||||
0x38, 0x76, 0x2c, 0xf7, 0xf5,
|
||||
0x59, 0x34, 0xb3, 0x4d, 0x17,
|
||||
0x9a, 0xe6, 0xa4, 0xc8, 0x0c,
|
||||
0xad, 0xcc, 0xbb, 0x7f, 0x0a};
|
||||
std::vector<uint8_t> INITIAL_SALT_V1 = {0x38, 0x76, 0x2c, 0xf7, 0xf5, 0x59, 0x34, 0xb3, 0x4d, 0x17,
|
||||
0x9a, 0xe6, 0xa4, 0xc8, 0x0c, 0xad, 0xcc, 0xbb, 0x7f, 0x0a};
|
||||
|
||||
std::vector<uint8_t> CLIENT_INITIAL_INFO = {
|
||||
0x00, 0x20, 0x0f, 0x74, 0x6c,
|
||||
0x73, 0x31, 0x33, 0x20, 0x63,
|
||||
0x6c, 0x69, 0x65, 0x6e, 0x74,
|
||||
0x20, 0x69, 0x6e, 0x00};
|
||||
std::vector<uint8_t> CLIENT_INITIAL_INFO = {0x00, 0x20, 0x0f, 0x74, 0x6c, 0x73, 0x31,
|
||||
0x33, 0x20, 0x63, 0x6c, 0x69, 0x65, 0x6e,
|
||||
0x74, 0x20, 0x69, 0x6e, 0x00};
|
||||
|
||||
std::vector<uint8_t> SERVER_INITIAL_INFO = {
|
||||
0x00, 0x20, 0x0f, 0x74, 0x6c,
|
||||
0x73, 0x31, 0x33, 0x20, 0x73,
|
||||
0x65, 0x72, 0x76, 0x65, 0x72,
|
||||
0x20, 0x69, 0x6e, 0x00};
|
||||
std::vector<uint8_t> SERVER_INITIAL_INFO = {0x00, 0x20, 0x0f, 0x74, 0x6c, 0x73, 0x31,
|
||||
0x33, 0x20, 0x73, 0x65, 0x72, 0x76, 0x65,
|
||||
0x72, 0x20, 0x69, 0x6e, 0x00};
|
||||
|
||||
std::vector<uint8_t> KEY_INFO = {
|
||||
0x00, 0x10, 0x0e, 0x74, 0x6c,
|
||||
0x73, 0x31, 0x33, 0x20, 0x71,
|
||||
0x75, 0x69, 0x63, 0x20, 0x6b,
|
||||
0x65, 0x79, 0x00};
|
||||
std::vector<uint8_t> KEY_INFO = {0x00, 0x10, 0x0e, 0x74, 0x6c, 0x73, 0x31, 0x33, 0x20,
|
||||
0x71, 0x75, 0x69, 0x63, 0x20, 0x6b, 0x65, 0x79, 0x00};
|
||||
|
||||
std::vector<uint8_t> IV_INFO = {
|
||||
0x00, 0x0c, 0x0d, 0x74, 0x6c,
|
||||
0x73, 0x31, 0x33, 0x20, 0x71,
|
||||
0x75, 0x69, 0x63, 0x20, 0x69,
|
||||
0x76, 0x00};
|
||||
std::vector<uint8_t> IV_INFO = {0x00, 0x0c, 0x0d, 0x74, 0x6c, 0x73, 0x31, 0x33, 0x20,
|
||||
0x71, 0x75, 0x69, 0x63, 0x20, 0x69, 0x76, 0x00};
|
||||
|
||||
std::vector<uint8_t> HP_INFO = {
|
||||
0x00, 0x10, 0x0d, 0x74, 0x6c,
|
||||
0x73, 0x31, 0x33, 0x20, 0x71,
|
||||
0x75, 0x69, 0x63, 0x20, 0x68,
|
||||
0x70, 0x00};
|
||||
std::vector<uint8_t> HP_INFO = {0x00, 0x10, 0x0d, 0x74, 0x6c, 0x73, 0x31, 0x33, 0x20,
|
||||
0x71, 0x75, 0x69, 0x63, 0x20, 0x68, 0x70, 0x00};
|
||||
|
||||
/*
|
||||
Constants used by the different functions
|
||||
|
@ -88,41 +83,34 @@ const size_t MAXIMUM_PACKET_LENGTH = 1500;
|
|||
const size_t MAXIMUM_PACKET_NUMBER_LENGTH = 4;
|
||||
|
||||
/*
|
||||
HKDF-Extract as decribed in https://www.rfc-editor.org/rfc/rfc8446.html#section-7.1
|
||||
HKDF-Extract as described in https://www.rfc-editor.org/rfc/rfc8446.html#section-7.1
|
||||
*/
|
||||
std::vector<uint8_t> hkdf_extract(std::vector<uint8_t> connection_id)
|
||||
{
|
||||
std::vector<uint8_t> hkdf_extract(const hilti::rt::Bytes& connection_id)
|
||||
{
|
||||
std::vector<uint8_t> out_temp(INITIAL_SECRET_LEN);
|
||||
size_t initial_secret_len = out_temp.size();
|
||||
const EVP_MD *digest = EVP_sha256();
|
||||
EVP_PKEY_CTX *pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_HKDF, NULL);
|
||||
const EVP_MD* digest = EVP_sha256();
|
||||
EVP_PKEY_CTX* pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_HKDF, NULL);
|
||||
EVP_PKEY_derive_init(pctx);
|
||||
EVP_PKEY_CTX_hkdf_mode(pctx, EVP_PKEY_HKDEF_MODE_EXTRACT_ONLY);
|
||||
EVP_PKEY_CTX_set_hkdf_md(pctx, digest);
|
||||
EVP_PKEY_CTX_set1_hkdf_key(pctx,
|
||||
connection_id.data(),
|
||||
connection_id.size());
|
||||
EVP_PKEY_CTX_set1_hkdf_salt(pctx,
|
||||
INITIAL_SALT_V1.data(),
|
||||
INITIAL_SALT_V1.size());
|
||||
EVP_PKEY_derive(pctx,
|
||||
out_temp.data(),
|
||||
reinterpret_cast<size_t *>(&initial_secret_len));
|
||||
EVP_PKEY_CTX_set1_hkdf_key(pctx, data_as_uint8(connection_id), connection_id.size());
|
||||
EVP_PKEY_CTX_set1_hkdf_salt(pctx, INITIAL_SALT_V1.data(), INITIAL_SALT_V1.size());
|
||||
EVP_PKEY_derive(pctx, out_temp.data(), &initial_secret_len);
|
||||
EVP_PKEY_CTX_free(pctx);
|
||||
return out_temp;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
HKDF-Expand-Label as decribed in https://www.rfc-editor.org/rfc/rfc8446.html#section-7.1
|
||||
HKDF-Expand-Label as described in https://www.rfc-editor.org/rfc/rfc8446.html#section-7.1
|
||||
that uses the global constant labels such as 'quic hp'.
|
||||
*/
|
||||
std::vector<uint8_t> hkdf_expand(size_t out_len,
|
||||
std::vector<uint8_t> key,
|
||||
std::vector<uint8_t> info)
|
||||
{
|
||||
std::vector<uint8_t> hkdf_expand(size_t out_len, const std::vector<uint8_t>& key,
|
||||
const std::vector<uint8_t>& info)
|
||||
{
|
||||
std::vector<uint8_t> out_temp(out_len);
|
||||
const EVP_MD *digest = EVP_sha256();
|
||||
EVP_PKEY_CTX *pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_HKDF, NULL);
|
||||
const EVP_MD* digest = EVP_sha256();
|
||||
EVP_PKEY_CTX* pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_HKDF, NULL);
|
||||
EVP_PKEY_derive_init(pctx);
|
||||
EVP_PKEY_CTX_hkdf_mode(pctx, EVP_PKEY_HKDEF_MODE_EXPAND_ONLY);
|
||||
EVP_PKEY_CTX_set_hkdf_md(pctx, digest);
|
||||
|
@ -131,13 +119,16 @@ std::vector<uint8_t> hkdf_expand(size_t out_len,
|
|||
EVP_PKEY_derive(pctx, out_temp.data(), &out_len);
|
||||
EVP_PKEY_CTX_free(pctx);
|
||||
return out_temp;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Removes the header protection from the INITIAL packet and returns a DecryptionInformation struct that is partially filled
|
||||
Removes the header protection from the INITIAL packet and returns a DecryptionInformation struct
|
||||
that is partially filled
|
||||
*/
|
||||
DecryptionInformation remove_header_protection(std::vector<uint8_t> client_hp, uint8_t encrypted_offset, std::vector<uint8_t> encrypted_packet)
|
||||
{
|
||||
DecryptionInformation remove_header_protection(const std::vector<uint8_t>& client_hp,
|
||||
uint64_t encrypted_offset,
|
||||
const hilti::rt::Bytes& all_data)
|
||||
{
|
||||
DecryptionInformation decryptInfo;
|
||||
int outlen;
|
||||
auto cipher = EVP_aes_128_ecb();
|
||||
|
@ -147,22 +138,21 @@ DecryptionInformation remove_header_protection(std::vector<uint8_t> client_hp, u
|
|||
// Passing an 1 means ENCRYPT
|
||||
EVP_CipherInit_ex(ctx, NULL, NULL, client_hp.data(), NULL, 1);
|
||||
|
||||
std::vector<uint8_t> sample(encrypted_packet.begin() +
|
||||
encrypted_offset +
|
||||
MAXIMUM_PACKET_NUMBER_LENGTH,
|
||||
static_assert(AEAD_SAMPLE_LENGTH > 0);
|
||||
assert(all_data.size() >= encrypted_offset + MAXIMUM_PACKET_NUMBER_LENGTH + AEAD_SAMPLE_LENGTH);
|
||||
|
||||
encrypted_packet.begin() +
|
||||
encrypted_offset +
|
||||
MAXIMUM_PACKET_NUMBER_LENGTH +
|
||||
AEAD_SAMPLE_LENGTH);
|
||||
std::vector<uint8_t> mask(sample.size());
|
||||
EVP_CipherUpdate(ctx, mask.data(), &outlen, sample.data(), AEAD_SAMPLE_LENGTH);
|
||||
const uint8_t* sample = data_as_uint8(all_data) + encrypted_offset +
|
||||
MAXIMUM_PACKET_NUMBER_LENGTH;
|
||||
|
||||
std::array<uint8_t, AEAD_SAMPLE_LENGTH> mask;
|
||||
EVP_CipherUpdate(ctx, mask.data(), &outlen, sample, AEAD_SAMPLE_LENGTH);
|
||||
EVP_CIPHER_CTX_free(ctx);
|
||||
|
||||
// To determine the actual packet number length,
|
||||
// we have to remove the mask from the first byte
|
||||
uint8_t first_byte = encrypted_packet[0];
|
||||
uint8_t first_byte = data_as_uint8(all_data)[0];
|
||||
|
||||
if (first_byte & 0x80)
|
||||
if ( first_byte & 0x80 )
|
||||
{
|
||||
first_byte ^= mask[0] & 0x0F;
|
||||
}
|
||||
|
@ -175,206 +165,151 @@ DecryptionInformation remove_header_protection(std::vector<uint8_t> client_hp, u
|
|||
int recovered_packet_number_length = (first_byte & 0x03) + 1;
|
||||
|
||||
// .. and use this to reconstruct the (partially) unprotected header
|
||||
std::vector<uint8_t> unprotected_header(
|
||||
encrypted_packet.begin(),
|
||||
|
||||
encrypted_packet.begin() +
|
||||
encrypted_offset +
|
||||
std::vector<uint8_t> unprotected_header(data_as_uint8(all_data),
|
||||
data_as_uint8(all_data) + encrypted_offset +
|
||||
recovered_packet_number_length);
|
||||
|
||||
uint32_t decoded_packet_number = 0;
|
||||
|
||||
unprotected_header[0] = first_byte;
|
||||
for (int i = 0; i < recovered_packet_number_length; ++i)
|
||||
for ( int i = 0; i < recovered_packet_number_length; ++i )
|
||||
{
|
||||
unprotected_header[encrypted_offset + i] ^= mask[1 + i];
|
||||
decoded_packet_number =
|
||||
unprotected_header[encrypted_offset + i] |
|
||||
decoded_packet_number = unprotected_header[encrypted_offset + i] |
|
||||
(decoded_packet_number << 8);
|
||||
}
|
||||
std::vector<uint8_t> protected_header(encrypted_packet.begin(),
|
||||
encrypted_packet.begin() +
|
||||
encrypted_offset +
|
||||
recovered_packet_number_length);
|
||||
|
||||
// Store the information back in the struct
|
||||
decryptInfo.packet_number = decoded_packet_number;
|
||||
decryptInfo.packet_number_length = recovered_packet_number_length;
|
||||
decryptInfo.protected_header = protected_header;
|
||||
decryptInfo.unprotected_header = unprotected_header;
|
||||
decryptInfo.unprotected_header = std::move(unprotected_header);
|
||||
return decryptInfo;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Calculate the nonce for the AEAD by XOR'ing the CLIENT_IV and the
|
||||
decoded packet number, and returns the nonce
|
||||
*/
|
||||
std::vector<uint8_t> calculate_nonce(std::vector<uint8_t> client_iv, uint64_t packet_number)
|
||||
{
|
||||
std::vector<uint8_t> nonce = client_iv;
|
||||
|
||||
for (int i = 0; i < 8; ++i)
|
||||
{
|
||||
nonce[AEAD_IV_LEN - 1 - i] ^=
|
||||
(uint8_t)(packet_number >> 8 * i);
|
||||
}
|
||||
for ( int i = 0; i < 8; ++i )
|
||||
client_iv[AEAD_IV_LEN - 1 - i] ^= (uint8_t)(packet_number >> 8 * i);
|
||||
|
||||
// Return the nonce
|
||||
return nonce;
|
||||
}
|
||||
return client_iv;
|
||||
}
|
||||
|
||||
/*
|
||||
Function that calls the AEAD decryption routine, and returns the
|
||||
decrypted data
|
||||
*/
|
||||
std::vector<uint8_t> decrypt(std::vector<uint8_t> client_key,
|
||||
std::vector<uint8_t> encrypted_packet,
|
||||
uint64_t payload_offset,
|
||||
DecryptionInformation decryptInfo)
|
||||
{
|
||||
|
||||
hilti::rt::Bytes decrypt(const std::vector<uint8_t>& client_key, const hilti::rt::Bytes& all_data,
|
||||
uint64_t payload_length, const DecryptionInformation& decryptInfo)
|
||||
{
|
||||
int out, out2, res;
|
||||
std::vector<uint8_t> encrypted_payload(
|
||||
encrypted_packet.begin() +
|
||||
decryptInfo.protected_header.size(),
|
||||
|
||||
encrypted_packet.begin() +
|
||||
decryptInfo.protected_header.size() +
|
||||
payload_offset -
|
||||
decryptInfo.packet_number_length -
|
||||
AEAD_TAG_LENGTH);
|
||||
if ( payload_length < decryptInfo.packet_number_length + AEAD_TAG_LENGTH )
|
||||
throw hilti::rt::RuntimeError(
|
||||
hilti::rt::fmt("payload too small %ld < %ld", payload_length,
|
||||
decryptInfo.packet_number_length + AEAD_TAG_LENGTH));
|
||||
|
||||
std::vector<uint8_t> tag_to_check(
|
||||
encrypted_packet.begin() +
|
||||
decryptInfo.protected_header.size() +
|
||||
payload_offset -
|
||||
decryptInfo.packet_number_length -
|
||||
AEAD_TAG_LENGTH,
|
||||
const uint8_t* encrypted_payload = data_as_uint8(all_data) +
|
||||
decryptInfo.unprotected_header.size();
|
||||
|
||||
encrypted_packet.begin() +
|
||||
decryptInfo.protected_header.size() +
|
||||
payload_offset -
|
||||
decryptInfo.packet_number_length);
|
||||
int encrypted_payload_size = payload_length - decryptInfo.packet_number_length -
|
||||
AEAD_TAG_LENGTH;
|
||||
|
||||
unsigned char decrypt_buffer[MAXIMUM_PACKET_LENGTH];
|
||||
if ( encrypted_payload_size < 0 )
|
||||
throw hilti::rt::RuntimeError(
|
||||
hilti::rt::fmt("encrypted_payload_size underflow %ld", encrypted_payload_size));
|
||||
|
||||
if ( all_data.size() <
|
||||
decryptInfo.unprotected_header.size() + encrypted_payload_size + AEAD_TAG_LENGTH )
|
||||
throw hilti::rt::RuntimeError(
|
||||
hilti::rt::fmt("all_data too short %ld < %ld", all_data.size(),
|
||||
decryptInfo.unprotected_header.size() + encrypted_payload_size));
|
||||
|
||||
const void* tag_to_check = all_data.data() + decryptInfo.unprotected_header.size() +
|
||||
encrypted_payload_size;
|
||||
int tag_to_check_length = AEAD_TAG_LENGTH;
|
||||
|
||||
std::array<uint8_t, MAXIMUM_PACKET_LENGTH> decrypt_buffer;
|
||||
|
||||
// Setup context
|
||||
auto cipher = EVP_aes_128_gcm();
|
||||
auto ctx = EVP_CIPHER_CTX_new();
|
||||
|
||||
EVP_CipherInit_ex(ctx,
|
||||
cipher,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
0);
|
||||
EVP_CipherInit_ex(ctx, cipher, NULL, NULL, NULL, 0);
|
||||
|
||||
// Set the sizes for the IV and KEY
|
||||
EVP_CIPHER_CTX_ctrl(ctx,
|
||||
EVP_CTRL_CCM_SET_IVLEN,
|
||||
decryptInfo.nonce.size(),
|
||||
NULL);
|
||||
EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_CCM_SET_IVLEN, decryptInfo.nonce.size(), NULL);
|
||||
|
||||
EVP_CIPHER_CTX_set_key_length(ctx,
|
||||
client_key.size());
|
||||
EVP_CIPHER_CTX_set_key_length(ctx, client_key.size());
|
||||
|
||||
// Set the KEY and IV
|
||||
EVP_CipherInit_ex(ctx,
|
||||
NULL,
|
||||
NULL,
|
||||
client_key.data(),
|
||||
decryptInfo.nonce.data(),
|
||||
0);
|
||||
EVP_CipherInit_ex(ctx, NULL, NULL, client_key.data(), decryptInfo.nonce.data(), 0);
|
||||
|
||||
// Set the tag to be validated after decryption
|
||||
EVP_CIPHER_CTX_ctrl(ctx,
|
||||
EVP_CTRL_CCM_SET_TAG,
|
||||
tag_to_check.size(),
|
||||
tag_to_check.data());
|
||||
EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_CCM_SET_TAG, tag_to_check_length,
|
||||
const_cast<void*>(tag_to_check));
|
||||
|
||||
// Setting the second parameter to NULL will pass it as Associated Data
|
||||
EVP_CipherUpdate(ctx,
|
||||
NULL,
|
||||
&out,
|
||||
decryptInfo.unprotected_header.data(),
|
||||
EVP_CipherUpdate(ctx, NULL, &out, decryptInfo.unprotected_header.data(),
|
||||
decryptInfo.unprotected_header.size());
|
||||
|
||||
// Set the actual data to decrypt data into the decrypt_buffer. The amount of
|
||||
// byte decrypted is stored into `out`
|
||||
EVP_CipherUpdate(ctx,
|
||||
decrypt_buffer,
|
||||
&out,
|
||||
encrypted_payload.data(),
|
||||
encrypted_payload.size());
|
||||
EVP_CipherUpdate(ctx, decrypt_buffer.data(), &out, encrypted_payload, encrypted_payload_size);
|
||||
|
||||
// Validate whether the decryption was successful or not
|
||||
EVP_CipherFinal_ex(ctx, NULL, &out2);
|
||||
EVP_CIPHER_CTX_free(ctx);
|
||||
|
||||
// Copy the decrypted data from the decrypted buffer into a new vector and return this
|
||||
// Use the `out` variable to only include relevant bytes
|
||||
std::vector<uint8_t> decrypted_data(decrypt_buffer, decrypt_buffer + out);
|
||||
return decrypted_data;
|
||||
}
|
||||
// Copy the decrypted data from the decrypted buffer into a Bytes instance.
|
||||
return hilti::rt::Bytes(decrypt_buffer.data(), decrypt_buffer.data() + out);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
Function that is called from Spicy. It's a wrapper around `process_data`;
|
||||
it stores all the passed data in a global struct and then calls `process_data`,
|
||||
which will eventually return the decrypted data and pass it back to Spicy.
|
||||
*/
|
||||
hilti::rt::Bytes decrypt_crypto_payload(
|
||||
const hilti::rt::Bytes &entire_packet,
|
||||
const hilti::rt::Bytes &connection_id,
|
||||
const hilti::rt::integer::safe<uint64_t> &encrypted_offset,
|
||||
const hilti::rt::integer::safe<uint64_t> &payload_offset,
|
||||
const hilti::rt::Bool &from_client)
|
||||
{
|
||||
|
||||
// Fill in the entire packet bytes
|
||||
std::vector<uint8_t> e_pkt;
|
||||
for (const auto &singlebyte : entire_packet)
|
||||
hilti::rt::Bytes
|
||||
QUIC_decrypt_crypto_payload(const hilti::rt::Bytes& all_data, const hilti::rt::Bytes& connection_id,
|
||||
const hilti::rt::integer::safe<uint64_t>& encrypted_offset,
|
||||
const hilti::rt::integer::safe<uint64_t>& payload_length,
|
||||
const hilti::rt::Bool& from_client)
|
||||
{
|
||||
e_pkt.push_back(singlebyte);
|
||||
}
|
||||
|
||||
std::vector<uint8_t> cnnid;
|
||||
for (const auto &singlebyte : connection_id)
|
||||
{
|
||||
cnnid.push_back(singlebyte);
|
||||
}
|
||||
if ( payload_length < 20 )
|
||||
throw hilti::rt::RuntimeError(hilti::rt::fmt("payload too small %ld < 20", payload_length));
|
||||
|
||||
std::vector<uint8_t> initial_secret = hkdf_extract(cnnid);
|
||||
if ( (all_data.size() < encrypted_offset + payload_length) )
|
||||
throw hilti::rt::RuntimeError(hilti::rt::fmt("packet too small %ld %ld", all_data.size(),
|
||||
encrypted_offset + payload_length));
|
||||
|
||||
std::vector<uint8_t> initial_secret = hkdf_extract(connection_id);
|
||||
|
||||
std::vector<uint8_t> server_client_secret;
|
||||
if (from_client)
|
||||
if ( from_client )
|
||||
{
|
||||
server_client_secret = hkdf_expand(INITIAL_SECRET_LEN,
|
||||
initial_secret,
|
||||
CLIENT_INITIAL_INFO);
|
||||
server_client_secret = hkdf_expand(INITIAL_SECRET_LEN, initial_secret, CLIENT_INITIAL_INFO);
|
||||
}
|
||||
else
|
||||
{
|
||||
server_client_secret = hkdf_expand(INITIAL_SECRET_LEN,
|
||||
initial_secret,
|
||||
SERVER_INITIAL_INFO);
|
||||
server_client_secret = hkdf_expand(INITIAL_SECRET_LEN, initial_secret, SERVER_INITIAL_INFO);
|
||||
}
|
||||
|
||||
std::vector<uint8_t> key = hkdf_expand(AEAD_KEY_LEN,
|
||||
server_client_secret,
|
||||
KEY_INFO);
|
||||
std::vector<uint8_t> iv = hkdf_expand(AEAD_IV_LEN,
|
||||
server_client_secret,
|
||||
IV_INFO);
|
||||
std::vector<uint8_t> hp = hkdf_expand(AEAD_HP_LEN,
|
||||
server_client_secret,
|
||||
HP_INFO);
|
||||
std::vector<uint8_t> key = hkdf_expand(AEAD_KEY_LEN, server_client_secret, KEY_INFO);
|
||||
std::vector<uint8_t> iv = hkdf_expand(AEAD_IV_LEN, server_client_secret, IV_INFO);
|
||||
std::vector<uint8_t> hp = hkdf_expand(AEAD_HP_LEN, server_client_secret, HP_INFO);
|
||||
|
||||
DecryptionInformation decryptInfo = remove_header_protection(hp, (uint8_t)encrypted_offset, e_pkt);
|
||||
DecryptionInformation decryptInfo = remove_header_protection(hp, encrypted_offset, all_data);
|
||||
|
||||
// Calculate the correct nonce for the decryption
|
||||
decryptInfo.nonce = calculate_nonce(iv, decryptInfo.packet_number);
|
||||
|
||||
std::vector<uint8_t> decrypted_data = decrypt(key, e_pkt, payload_offset, decryptInfo);
|
||||
|
||||
// Return it as hilti Bytes again
|
||||
hilti::rt::Bytes decr(decrypted_data.begin(), decrypted_data.end());
|
||||
return decr;
|
||||
}
|
||||
return decrypt(key, all_data, payload_length, decryptInfo);
|
||||
}
|
||||
|
|
|
@ -1,12 +0,0 @@
|
|||
module Zeek_QUIC;
|
||||
|
||||
import zeek;
|
||||
import QUIC;
|
||||
|
||||
on QUIC::ResponseFrame::%done {
|
||||
zeek::confirm_protocol();
|
||||
}
|
||||
|
||||
on QUIC::ResponseFrame::%error {
|
||||
zeek::reject_protocol("error while parsing QUIC message");
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
|
||||
ts uid history service
|
||||
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 Dd quic,ssl
|
|
@ -0,0 +1,11 @@
|
|||
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
|
||||
#separator \x09
|
||||
#set_separator ,
|
||||
#empty_field (empty)
|
||||
#unset_field -
|
||||
#path quic
|
||||
#open XXXX-XX-XX-XX-XX-XX
|
||||
#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p version client_initial_dcid server_scid server_name client_protocol history
|
||||
#types time string addr port addr port string string string string string string
|
||||
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 82.239.54.117 53727 110.213.53.115 443 1 95412c47018cdfe8 d5412c47018cdfe8 api.cirrus-ci.com h3 ISisH
|
||||
#close XXXX-XX-XX-XX-XX-XX
|
|
@ -0,0 +1,11 @@
|
|||
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
|
||||
#separator \x09
|
||||
#set_separator ,
|
||||
#empty_field (empty)
|
||||
#unset_field -
|
||||
#path ssl
|
||||
#open XXXX-XX-XX-XX-XX-XX
|
||||
#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p version cipher curve server_name resumed last_alert next_protocol established ssl_history cert_chain_fps client_cert_chain_fps sni_matches_cert
|
||||
#types time string addr port addr port string string string string bool string string bool string vector[string] vector[string] bool
|
||||
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 82.239.54.117 53727 110.213.53.115 443 TLSv13 TLS_AES_128_GCM_SHA256 x25519 api.cirrus-ci.com T - - F Cs - - -
|
||||
#close XXXX-XX-XX-XX-XX-XX
|
|
@ -0,0 +1,3 @@
|
|||
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
|
||||
ts uid history service
|
||||
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 Dd quic,ssl
|
|
@ -0,0 +1,11 @@
|
|||
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
|
||||
#separator \x09
|
||||
#set_separator ,
|
||||
#empty_field (empty)
|
||||
#unset_field -
|
||||
#path quic
|
||||
#open XXXX-XX-XX-XX-XX-XX
|
||||
#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p version client_initial_dcid server_scid server_name client_protocol history
|
||||
#types time string addr port addr port string string string string string string
|
||||
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 172.17.0.2 34347 64.233.166.94 443 1 815d62c70884f4b51e8ccadd5beed372 c15d62c70884f4b5 www.google.de h3 ISishIhHhh
|
||||
#close XXXX-XX-XX-XX-XX-XX
|
|
@ -0,0 +1,11 @@
|
|||
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
|
||||
#separator \x09
|
||||
#set_separator ,
|
||||
#empty_field (empty)
|
||||
#unset_field -
|
||||
#path ssl
|
||||
#open XXXX-XX-XX-XX-XX-XX
|
||||
#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p version cipher curve server_name resumed last_alert next_protocol established ssl_history cert_chain_fps client_cert_chain_fps sni_matches_cert
|
||||
#types time string addr port addr port string string string string bool string string bool string vector[string] vector[string] bool
|
||||
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 172.17.0.2 34347 64.233.166.94 443 TLSv13 TLS_AES_128_GCM_SHA256 x25519 www.google.de F - - F Cs - - -
|
||||
#close XXXX-XX-XX-XX-XX-XX
|
|
@ -0,0 +1 @@
|
|||
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
|
|
@ -0,0 +1,46 @@
|
|||
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
|
||||
1.0, initial_packet, C4J4Th3PJpwUYZZ6gc, T, 1, 4a8294bf9201d6cf,
|
||||
1.0, retry_packet, C4J4Th3PJpwUYZZ6gc, F, 1, , 1b036a11, 98, 9b3ac827ccae092e3f8fdf84ec8ee526
|
||||
1.0, initial_packet, C4J4Th3PJpwUYZZ6gc, T, 1, 1b036a11,
|
||||
1.0, initial_packet, C4J4Th3PJpwUYZZ6gc, F, 1, , fc674735
|
||||
1.0, handshake_packet, F, C4J4Th3PJpwUYZZ6gc, 1, , fc674735
|
||||
1.0, initial_packet, C4J4Th3PJpwUYZZ6gc, T, 1, fc674735,
|
||||
1.0, handshake_packet, T, C4J4Th3PJpwUYZZ6gc, 1, ef3a4e06,
|
||||
zerortt.pcap
|
||||
1.0, initial_packet, C4J4Th3PJpwUYZZ6gc, T, 1, b7c7841c64883e3261d840,
|
||||
1.0, initial_packet, C4J4Th3PJpwUYZZ6gc, F, 1, , 8d2041ac
|
||||
1.0, handshake_packet, F, C4J4Th3PJpwUYZZ6gc, 1, , 8d2041ac
|
||||
1.0, initial_packet, C4J4Th3PJpwUYZZ6gc, T, 1, 8d2041ac,
|
||||
1.0, handshake_packet, T, C4J4Th3PJpwUYZZ6gc, 1, 5b7bc400,
|
||||
1.0, initial_packet, CtPZjS20MLrsMUOJi2, T, 1, 15ae5e5e4962163f410b5529fc125bbc,
|
||||
1.0, zero_rtt_packet, T, CtPZjS20MLrsMUOJi2, 1, 15ae5e5e4962163f410b5529fc125bbc,
|
||||
1.0, initial_packet, CtPZjS20MLrsMUOJi2, F, 1, , e483a751
|
||||
1.0, zero_rtt_packet, T, CtPZjS20MLrsMUOJi2, 1, 15ae5e5e4962163f410b5529fc125bbc,
|
||||
1.0, zero_rtt_packet, T, CtPZjS20MLrsMUOJi2, 1, 15ae5e5e4962163f410b5529fc125bbc,
|
||||
1.0, zero_rtt_packet, T, CtPZjS20MLrsMUOJi2, 1, 15ae5e5e4962163f410b5529fc125bbc,
|
||||
1.0, zero_rtt_packet, T, CtPZjS20MLrsMUOJi2, 1, 15ae5e5e4962163f410b5529fc125bbc,
|
||||
1.0, zero_rtt_packet, T, CtPZjS20MLrsMUOJi2, 1, 15ae5e5e4962163f410b5529fc125bbc,
|
||||
1.0, zero_rtt_packet, T, CtPZjS20MLrsMUOJi2, 1, 15ae5e5e4962163f410b5529fc125bbc,
|
||||
1.0, zero_rtt_packet, T, CtPZjS20MLrsMUOJi2, 1, 15ae5e5e4962163f410b5529fc125bbc,
|
||||
1.0, zero_rtt_packet, T, CtPZjS20MLrsMUOJi2, 1, 15ae5e5e4962163f410b5529fc125bbc,
|
||||
1.0, zero_rtt_packet, T, CtPZjS20MLrsMUOJi2, 1, 15ae5e5e4962163f410b5529fc125bbc,
|
||||
1.0, zero_rtt_packet, T, CtPZjS20MLrsMUOJi2, 1, 15ae5e5e4962163f410b5529fc125bbc,
|
||||
1.0, zero_rtt_packet, T, CtPZjS20MLrsMUOJi2, 1, 15ae5e5e4962163f410b5529fc125bbc,
|
||||
1.0, zero_rtt_packet, T, CtPZjS20MLrsMUOJi2, 1, 15ae5e5e4962163f410b5529fc125bbc,
|
||||
1.0, zero_rtt_packet, T, CtPZjS20MLrsMUOJi2, 1, 15ae5e5e4962163f410b5529fc125bbc,
|
||||
1.0, zero_rtt_packet, T, CtPZjS20MLrsMUOJi2, 1, 15ae5e5e4962163f410b5529fc125bbc,
|
||||
1.0, zero_rtt_packet, T, CtPZjS20MLrsMUOJi2, 1, 15ae5e5e4962163f410b5529fc125bbc,
|
||||
1.0, zero_rtt_packet, T, CtPZjS20MLrsMUOJi2, 1, 15ae5e5e4962163f410b5529fc125bbc,
|
||||
1.0, zero_rtt_packet, T, CtPZjS20MLrsMUOJi2, 1, 15ae5e5e4962163f410b5529fc125bbc,
|
||||
1.0, zero_rtt_packet, T, CtPZjS20MLrsMUOJi2, 1, 15ae5e5e4962163f410b5529fc125bbc,
|
||||
1.0, zero_rtt_packet, T, CtPZjS20MLrsMUOJi2, 1, 15ae5e5e4962163f410b5529fc125bbc,
|
||||
1.0, zero_rtt_packet, T, CtPZjS20MLrsMUOJi2, 1, 15ae5e5e4962163f410b5529fc125bbc,
|
||||
1.0, zero_rtt_packet, T, CtPZjS20MLrsMUOJi2, 1, 15ae5e5e4962163f410b5529fc125bbc,
|
||||
1.0, zero_rtt_packet, T, CtPZjS20MLrsMUOJi2, 1, 15ae5e5e4962163f410b5529fc125bbc,
|
||||
1.0, zero_rtt_packet, T, CtPZjS20MLrsMUOJi2, 1, 15ae5e5e4962163f410b5529fc125bbc,
|
||||
1.0, zero_rtt_packet, T, CtPZjS20MLrsMUOJi2, 1, 15ae5e5e4962163f410b5529fc125bbc,
|
||||
1.0, zero_rtt_packet, T, CtPZjS20MLrsMUOJi2, 1, 15ae5e5e4962163f410b5529fc125bbc,
|
||||
1.0, zero_rtt_packet, T, CtPZjS20MLrsMUOJi2, 1, 15ae5e5e4962163f410b5529fc125bbc,
|
||||
1.0, zero_rtt_packet, T, CtPZjS20MLrsMUOJi2, 1, 15ae5e5e4962163f410b5529fc125bbc,
|
||||
1.0, initial_packet, CtPZjS20MLrsMUOJi2, T, 1, 3ec82f67,
|
||||
1.0, handshake_packet, T, CtPZjS20MLrsMUOJi2, 1, 3ec82f67,
|
|
@ -0,0 +1,3 @@
|
|||
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
|
||||
ts uid history service
|
||||
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 Dd quic,ssl
|
|
@ -0,0 +1,11 @@
|
|||
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
|
||||
#separator \x09
|
||||
#set_separator ,
|
||||
#empty_field (empty)
|
||||
#unset_field -
|
||||
#path quic
|
||||
#open XXXX-XX-XX-XX-XX-XX
|
||||
#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p version client_initial_dcid server_scid server_name client_protocol history
|
||||
#types time string addr port addr port string string string string string string
|
||||
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 82.239.54.117 44174 250.58.23.113 443 1 c5a5015ae8f479784a 01275b138ee6aca8a6276b132ae6b3547cf7773f blog.cloudflare.com h3 ISiihIhhhH
|
||||
#close XXXX-XX-XX-XX-XX-XX
|
|
@ -0,0 +1,11 @@
|
|||
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
|
||||
#separator \x09
|
||||
#set_separator ,
|
||||
#empty_field (empty)
|
||||
#unset_field -
|
||||
#path ssl
|
||||
#open XXXX-XX-XX-XX-XX-XX
|
||||
#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p version cipher curve server_name resumed last_alert next_protocol established ssl_history cert_chain_fps client_cert_chain_fps sni_matches_cert
|
||||
#types time string addr port addr port string string string string bool string string bool string vector[string] vector[string] bool
|
||||
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 82.239.54.117 44174 250.58.23.113 443 - - - blog.cloudflare.com F - - F C - - -
|
||||
#close XXXX-XX-XX-XX-XX-XX
|
|
@ -0,0 +1,3 @@
|
|||
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
|
||||
ts uid history service
|
||||
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 Dd quic,ssl
|
|
@ -0,0 +1,3 @@
|
|||
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
|
||||
ts uid version cipher curve server_name resumed last_alert next_protocol established ssl_history
|
||||
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 TLSv13 TLS_AES_128_GCM_SHA256 x25519 www.google.de F - - F Cs
|
|
@ -0,0 +1 @@
|
|||
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
|
|
@ -0,0 +1,5 @@
|
|||
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
|
||||
ts uid history service
|
||||
0.015059 ClEkJM2Vm5giqnMf4h - -
|
||||
0.001000 CHhAvVGS1DHFjwGM9 - -
|
||||
0.648580 C4J4Th3PJpwUYZZ6gc Dd quic,ssl
|
|
@ -0,0 +1,11 @@
|
|||
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
|
||||
#separator \x09
|
||||
#set_separator ,
|
||||
#empty_field (empty)
|
||||
#unset_field -
|
||||
#path quic
|
||||
#open XXXX-XX-XX-XX-XX-XX
|
||||
#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p version client_initial_dcid server_scid server_name client_protocol history
|
||||
#types time string addr port addr port string string string string string string
|
||||
1.000000 C4J4Th3PJpwUYZZ6gc 193.167.0.100 40084 193.167.100.100 443 1 a771f6161a4072c0bf10 5911deff server4:443 hq-interop ISishIH
|
||||
#close XXXX-XX-XX-XX-XX-XX
|
|
@ -0,0 +1,11 @@
|
|||
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
|
||||
#separator \x09
|
||||
#set_separator ,
|
||||
#empty_field (empty)
|
||||
#unset_field -
|
||||
#path ssl
|
||||
#open XXXX-XX-XX-XX-XX-XX
|
||||
#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p version cipher curve server_name resumed last_alert next_protocol established ssl_history cert_chain_fps client_cert_chain_fps sni_matches_cert
|
||||
#types time string addr port addr port string string string string bool string string bool string vector[string] vector[string] bool
|
||||
1.000000 C4J4Th3PJpwUYZZ6gc 193.167.0.100 40084 193.167.100.100 443 TLSv13 TLS_AES_128_GCM_SHA256 x25519 server4:443 F - - F Cs - - -
|
||||
#close XXXX-XX-XX-XX-XX-XX
|
|
@ -0,0 +1 @@
|
|||
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
|
|
@ -0,0 +1,5 @@
|
|||
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
|
||||
ts uid history service
|
||||
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 - -
|
||||
0.016059 ClEkJM2Vm5giqnMf4h - -
|
||||
0.669020 C4J4Th3PJpwUYZZ6gc Dd quic,ssl
|
|
@ -0,0 +1,12 @@
|
|||
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
|
||||
#separator \x09
|
||||
#set_separator ,
|
||||
#empty_field (empty)
|
||||
#unset_field -
|
||||
#path quic
|
||||
#open XXXX-XX-XX-XX-XX-XX
|
||||
#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p version client_initial_dcid server_scid server_name client_protocol history
|
||||
#types time string addr port addr port string string string string string string
|
||||
1.000000 C4J4Th3PJpwUYZZ6gc 193.167.0.100 42834 193.167.100.100 443 1 4a8294bf9201d6cf - server4:443 hq-interop ISr
|
||||
1.000000 C4J4Th3PJpwUYZZ6gc 193.167.0.100 42834 193.167.100.100 443 1 1b036a11 fc674735 server4:443 hq-interop ISishIH
|
||||
#close XXXX-XX-XX-XX-XX-XX
|
|
@ -0,0 +1,11 @@
|
|||
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
|
||||
#separator \x09
|
||||
#set_separator ,
|
||||
#empty_field (empty)
|
||||
#unset_field -
|
||||
#path ssl
|
||||
#open XXXX-XX-XX-XX-XX-XX
|
||||
#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p version cipher curve server_name resumed last_alert next_protocol established ssl_history cert_chain_fps client_cert_chain_fps sni_matches_cert
|
||||
#types time string addr port addr port string string string string bool string string bool string vector[string] vector[string] bool
|
||||
1.000000 C4J4Th3PJpwUYZZ6gc 193.167.0.100 42834 193.167.100.100 443 TLSv13 TLS_AES_128_GCM_SHA256 x25519 server4:443 F - - F CCs - - -
|
||||
#close XXXX-XX-XX-XX-XX-XX
|
|
@ -0,0 +1 @@
|
|||
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
|
|
@ -0,0 +1,6 @@
|
|||
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
|
||||
ts uid history service
|
||||
0.015059 ClEkJM2Vm5giqnMf4h - -
|
||||
0.001000 CHhAvVGS1DHFjwGM9 - -
|
||||
0.790739 CtPZjS20MLrsMUOJi2 Dd quic,ssl
|
||||
0.718160 C4J4Th3PJpwUYZZ6gc Dd quic,ssl
|
|
@ -0,0 +1,12 @@
|
|||
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
|
||||
#separator \x09
|
||||
#set_separator ,
|
||||
#empty_field (empty)
|
||||
#unset_field -
|
||||
#path quic
|
||||
#open XXXX-XX-XX-XX-XX-XX
|
||||
#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p version client_initial_dcid server_scid server_name client_protocol history
|
||||
#types time string addr port addr port string string string string string string
|
||||
1.000000 CtPZjS20MLrsMUOJi2 193.167.0.100 49394 193.167.100.100 443 1 15ae5e5e4962163f410b5529fc125bbc e483a751 server4:443 hq-interop ISZisZZZZZ
|
||||
1.000000 C4J4Th3PJpwUYZZ6gc 193.167.0.100 60492 193.167.100.100 443 1 b7c7841c64883e3261d840 8d2041ac server4:443 hq-interop ISishIH
|
||||
#close XXXX-XX-XX-XX-XX-XX
|
|
@ -0,0 +1,12 @@
|
|||
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
|
||||
#separator \x09
|
||||
#set_separator ,
|
||||
#empty_field (empty)
|
||||
#unset_field -
|
||||
#path ssl
|
||||
#open XXXX-XX-XX-XX-XX-XX
|
||||
#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p version cipher curve server_name resumed last_alert next_protocol established ssl_history cert_chain_fps client_cert_chain_fps sni_matches_cert
|
||||
#types time string addr port addr port string string string string bool string string bool string vector[string] vector[string] bool
|
||||
1.000000 CtPZjS20MLrsMUOJi2 193.167.0.100 49394 193.167.100.100 443 TLSv13 TLS_AES_128_GCM_SHA256 x25519 server4:443 T - - F Cs - - -
|
||||
1.000000 C4J4Th3PJpwUYZZ6gc 193.167.0.100 60492 193.167.100.100 443 TLSv13 TLS_AES_128_GCM_SHA256 x25519 server4:443 F - - F Cs - - -
|
||||
#close XXXX-XX-XX-XX-XX-XX
|
|
@ -0,0 +1 @@
|
|||
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
|
|
@ -0,0 +1,11 @@
|
|||
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
|
||||
#separator \x09
|
||||
#set_separator ,
|
||||
#empty_field (empty)
|
||||
#unset_field -
|
||||
#path quic
|
||||
#open XXXX-XX-XX-XX-XX-XX
|
||||
#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p version client_initial_dcid server_scid server_name client_protocol history
|
||||
#types time string addr port addr port string string string string string string
|
||||
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 669b:cb7a:de99:6a13:4a9b:46ef:3bed:cb6c 57538 6699:ded3:da8c:be73:5a99:ca73:5a99:cadb 443 1 5a37463b0eb7cc5d da37463b0eb7cc5d www.google.de h3 ISishIhHhh
|
||||
#close XXXX-XX-XX-XX-XX-XX
|
|
@ -0,0 +1,3 @@
|
|||
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
|
||||
ts uid history service
|
||||
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 Dd quic,ssl
|
|
@ -0,0 +1,11 @@
|
|||
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
|
||||
#separator \x09
|
||||
#set_separator ,
|
||||
#empty_field (empty)
|
||||
#unset_field -
|
||||
#path quic
|
||||
#open XXXX-XX-XX-XX-XX-XX
|
||||
#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p version client_initial_dcid server_scid server_name client_protocol history
|
||||
#types time string addr port addr port string string string string string string
|
||||
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 127.0.0.1 46907 127.0.0.1 853 1 fda05288ab9ff546 a31f4933d8727231 - doq ISishH
|
||||
#close XXXX-XX-XX-XX-XX-XX
|
|
@ -0,0 +1,11 @@
|
|||
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
|
||||
#separator \x09
|
||||
#set_separator ,
|
||||
#empty_field (empty)
|
||||
#unset_field -
|
||||
#path ssl
|
||||
#open XXXX-XX-XX-XX-XX-XX
|
||||
#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p version cipher curve server_name resumed last_alert next_protocol established ssl_history cert_chain_fps client_cert_chain_fps sni_matches_cert
|
||||
#types time string addr port addr port string string string string bool string string bool string vector[string] vector[string] bool
|
||||
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 127.0.0.1 46907 127.0.0.1 853 TLSv13 TLS_AES_128_GCM_SHA256 secp256r1 - F - - F Cs - - -
|
||||
#close XXXX-XX-XX-XX-XX-XX
|
|
@ -1,11 +0,0 @@
|
|||
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
|
||||
#separator \x09
|
||||
#set_separator ,
|
||||
#empty_field (empty)
|
||||
#unset_field -
|
||||
#path conn
|
||||
#open XXXX-XX-XX-XX-XX-XX
|
||||
#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p proto service duration orig_bytes resp_bytes conn_state local_orig local_resp missed_bytes history orig_pkts orig_ip_bytes resp_pkts resp_ip_bytes tunnel_parents
|
||||
#types time string addr port addr port enum string interval count count string bool bool count string count count count count set[string]
|
||||
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 1.2.3.4 49369 4.3.2.1 443 udp spicy_quic,ssl 18.071102 14371 394242 SF - - 0 Dd 96 17059 345 403902 -
|
||||
#close XXXX-XX-XX-XX-XX-XX
|
|
@ -0,0 +1,3 @@
|
|||
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
|
||||
ts uid history service
|
||||
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 Dd quic,ssl
|
|
@ -7,5 +7,5 @@
|
|||
#open XXXX-XX-XX-XX-XX-XX
|
||||
#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p version cipher curve server_name resumed last_alert next_protocol established ssl_history cert_chain_fps client_cert_chain_fps sni_matches_cert
|
||||
#types time string addr port addr port string string string string bool string string bool string vector[string] vector[string] bool
|
||||
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 1.2.3.4 49369 4.3.2.1 443 - - - www.google.com F - - F C - - -
|
||||
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 1.2.3.4 49369 4.3.2.1 443 TLSv13 TLS_AES_128_GCM_SHA256 x25519 www.google.com F - - F Cs - - -
|
||||
#close XXXX-XX-XX-XX-XX-XX
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
|
||||
ts uid cause analyzer_kind analyzer_name failure_reason
|
||||
1693925959.000001 CHhAvVGS1DHFjwGM9 violation protocol QUIC &requires failed: self.length.result >= 20 (<...>/QUIC.spicy:<line>:<column>)
|
|
@ -0,0 +1,3 @@
|
|||
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
|
||||
ts uid history service
|
||||
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 D -
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
10
testing/btest/Traces/quic/interop/attribution.txt
Normal file
10
testing/btest/Traces/quic/interop/attribution.txt
Normal file
|
@ -0,0 +1,10 @@
|
|||
PCAP files in this directory were gathered from the QUIC interop project webpage.
|
||||
|
||||
Marten Seemann didn't have any concerns or reservations using these as testing
|
||||
material. They require DLT_PPP support in Zeek, unfortunately.
|
||||
|
||||
Some references:
|
||||
|
||||
https://interop.seemann.io/
|
||||
https://github.com/marten-seemann/quic-network-simulator
|
||||
https://github.com/marten-seemann/quic-interop-runner
|
BIN
testing/btest/Traces/quic/interop/quic-go_quic-go/handshake.pcap
Normal file
BIN
testing/btest/Traces/quic/interop/quic-go_quic-go/handshake.pcap
Normal file
Binary file not shown.
BIN
testing/btest/Traces/quic/interop/quic-go_quic-go/retry.pcap
Normal file
BIN
testing/btest/Traces/quic/interop/quic-go_quic-go/retry.pcap
Normal file
Binary file not shown.
BIN
testing/btest/Traces/quic/interop/quic-go_quic-go/zerortt.pcap
Normal file
BIN
testing/btest/Traces/quic/interop/quic-go_quic-go/zerortt.pcap
Normal file
Binary file not shown.
BIN
testing/btest/Traces/quic/quicdoq.pcap
Normal file
BIN
testing/btest/Traces/quic/quicdoq.pcap
Normal file
Binary file not shown.
BIN
testing/btest/Traces/quic/vector-max-size-crash.pcap
Normal file
BIN
testing/btest/Traces/quic/vector-max-size-crash.pcap
Normal file
Binary file not shown.
6
testing/btest/scripts/base/protocols/quic/chromium.zeek
Normal file
6
testing/btest/scripts/base/protocols/quic/chromium.zeek
Normal file
|
@ -0,0 +1,6 @@
|
|||
# @TEST-DOC: Test that runs the pcap
|
||||
# @TEST-EXEC: zeek -Cr $TRACES/quic/chromium-115.0.5790.110-api-cirrus-com.pcap base/protocols/quic
|
||||
# @TEST-EXEC: zeek-cut -m ts uid history service < conn.log > conn.log.cut
|
||||
# @TEST-EXEC: btest-diff conn.log.cut
|
||||
# @TEST-EXEC: btest-diff ssl.log
|
||||
# @TEST-EXEC: btest-diff quic.log
|
|
@ -0,0 +1,6 @@
|
|||
# @TEST-DOC: Test that runs the pcap
|
||||
# @TEST-EXEC: zeek -Cr $TRACES/quic/curl-8.1.2-dev-http3-www-google-de.pcap base/protocols/quic
|
||||
# @TEST-EXEC: zeek-cut -m ts uid history service < conn.log > conn.log.cut
|
||||
# @TEST-EXEC: btest-diff conn.log.cut
|
||||
# @TEST-EXEC: btest-diff ssl.log
|
||||
# @TEST-EXEC: btest-diff quic.log
|
29
testing/btest/scripts/base/protocols/quic/events.zeek
Normal file
29
testing/btest/scripts/base/protocols/quic/events.zeek
Normal file
|
@ -0,0 +1,29 @@
|
|||
# @TEST-DOC: Supported events so far.
|
||||
# @TEST-REQUIRES: zeek -b -e 'print PacketAnalyzer::ANALYZER_PPP == PacketAnalyzer::ANALYZER_PPP'
|
||||
# @TEST-EXEC: zeek -Cr $TRACES/quic/interop/quic-go_quic-go/retry.pcap base/protocols/quic %INPUT >out
|
||||
# @TEST-EXEC: echo "zerortt.pcap" >>out
|
||||
# @TEST-EXEC: zeek -Cr $TRACES/quic/interop/quic-go_quic-go/zerortt.pcap base/protocols/quic %INPUT >>out
|
||||
# @TEST-EXEC: btest-diff out
|
||||
# @TEST-EXEC: btest-diff .stderr
|
||||
#
|
||||
|
||||
function b2hex(s: string):string { return bytestring_to_hexstr(s); }
|
||||
|
||||
event QUIC::initial_packet(c: connection, is_orig: bool, version: count, dcid: string, scid: string)
|
||||
{
|
||||
print network_time(), "initial_packet", c$uid, is_orig, version, b2hex(dcid), b2hex(scid);
|
||||
}
|
||||
|
||||
event QUIC::retry_packet(c: connection, is_orig: bool, version: count, dcid: string, scid: string, retry_token: string, integrity_tag: string)
|
||||
{
|
||||
print network_time(), "retry_packet", c$uid, is_orig, version, b2hex(dcid), b2hex(scid), |retry_token|, b2hex(integrity_tag);
|
||||
}
|
||||
|
||||
event QUIC::handshake_packet(c: connection, is_orig: bool, version: count, dcid: string, scid: string)
|
||||
{
|
||||
print network_time(), "handshake_packet", is_orig, c$uid, version, b2hex(dcid), b2hex(scid);
|
||||
}
|
||||
event QUIC::zero_rtt_packet(c: connection, is_orig: bool, version: count, dcid: string, scid: string)
|
||||
{
|
||||
print network_time(), "zero_rtt_packet", is_orig, c$uid, version, b2hex(dcid), b2hex(scid);
|
||||
}
|
6
testing/btest/scripts/base/protocols/quic/firefox.zeek
Normal file
6
testing/btest/scripts/base/protocols/quic/firefox.zeek
Normal file
|
@ -0,0 +1,6 @@
|
|||
# @TEST-DOC: Test that runs the pcap
|
||||
# @TEST-EXEC: zeek -Cr $TRACES/quic/firefox-102.13.0esr-blog-cloudflare-com.pcap base/protocols/quic
|
||||
# @TEST-EXEC: zeek-cut -m ts uid history service < conn.log > conn.log.cut
|
||||
# @TEST-EXEC: btest-diff conn.log.cut
|
||||
# @TEST-EXEC: btest-diff ssl.log
|
||||
# @TEST-EXEC: btest-diff quic.log
|
|
@ -0,0 +1,7 @@
|
|||
# @TEST-DOC: Pcap with fragmented and unordered CRYPTO frames.
|
||||
#
|
||||
# @TEST-EXEC: zeek -Cr $TRACES/quic/chromium-115.0.5790.110-google-de-fragmented.pcap base/protocols/quic
|
||||
# @TEST-EXEC: zeek-cut -m ts uid history service < conn.log > conn.log.cut
|
||||
# @TEST-EXEC: btest-diff conn.log.cut
|
||||
# @TEST-EXEC: zeek-cut -m ts uid version cipher curve server_name resumed last_alert next_protocol established ssl_history < ssl.log > ssl.log.cut
|
||||
# @TEST-EXEC: btest-diff ssl.log.cut
|
|
@ -0,0 +1,12 @@
|
|||
# @TEST-DOC: Test interop pcap containing RETRY packet from server side.
|
||||
#
|
||||
# interop pcaps have link type DLT_PPP, test for its availability. Available in Zeek 6.1 or later only.
|
||||
# @TEST-REQUIRES: zeek -b -e 'print PacketAnalyzer::ANALYZER_PPP == PacketAnalyzer::ANALYZER_PPP'
|
||||
#
|
||||
# @TEST-EXEC: zeek -Cr $TRACES/quic/interop/quic-go_quic-go/handshake.pcap base/protocols/quic
|
||||
# @TEST-EXEC: zeek-cut -m ts uid history service < conn.log > conn.log.cut
|
||||
# @TEST-EXEC: btest-diff conn.log.cut
|
||||
# @TEST-EXEC: btest-diff ssl.log
|
||||
# @TEST-EXEC: btest-diff quic.log
|
||||
# @TEST-EXEC: btest-diff .stderr
|
||||
# @TEST-EXEC: test ! -f analyzer.log
|
|
@ -0,0 +1,12 @@
|
|||
# @TEST-DOC: Test interop pcap containing RETRY packet from server side.
|
||||
#
|
||||
# interop pcaps have link type DLT_PPP, test for its availability. Available in Zeek 6.1 or later only.
|
||||
# @TEST-REQUIRES: zeek -b -e 'print PacketAnalyzer::ANALYZER_PPP == PacketAnalyzer::ANALYZER_PPP'
|
||||
#
|
||||
# @TEST-EXEC: zeek -Cr $TRACES/quic/interop/quic-go_quic-go/retry.pcap base/protocols/quic
|
||||
# @TEST-EXEC: zeek-cut -m ts uid history service < conn.log > conn.log.cut
|
||||
# @TEST-EXEC: btest-diff conn.log.cut
|
||||
# @TEST-EXEC: btest-diff ssl.log
|
||||
# @TEST-EXEC: btest-diff quic.log
|
||||
# @TEST-EXEC: btest-diff .stderr
|
||||
# @TEST-EXEC: test ! -f analyzer.log
|
|
@ -0,0 +1,12 @@
|
|||
# @TEST-DOC: Test that client initiating connection using 0RTT packet doesn't cause analyzer errors trying to decrypt server side.
|
||||
#
|
||||
# interop pcaps have link type DLT_PPP, test for its availability. Available in Zeek 6.1 or later only.
|
||||
# @TEST-REQUIRES: zeek -b -e 'print PacketAnalyzer::ANALYZER_PPP == PacketAnalyzer::ANALYZER_PPP'
|
||||
#
|
||||
# @TEST-EXEC: zeek -Cr $TRACES/quic/interop/quic-go_quic-go/zerortt.pcap base/protocols/quic
|
||||
# @TEST-EXEC: zeek-cut -m ts uid history service < conn.log > conn.log.cut
|
||||
# @TEST-EXEC: btest-diff conn.log.cut
|
||||
# @TEST-EXEC: btest-diff ssl.log
|
||||
# @TEST-EXEC: btest-diff quic.log
|
||||
# @TEST-EXEC: btest-diff .stderr
|
||||
# @TEST-EXEC: test ! -f analyzer.log
|
5
testing/btest/scripts/base/protocols/quic/quic-log.zeek
Normal file
5
testing/btest/scripts/base/protocols/quic/quic-log.zeek
Normal file
|
@ -0,0 +1,5 @@
|
|||
# @TEST-DOC: Smoke test the quic.log production
|
||||
#
|
||||
# @TEST-EXEC: zeek -Cr $TRACES/quic/chromium-115.0.5790.110-google-de-fragmented.pcap base/protocols/quic
|
||||
# @TEST-EXEC: btest-diff quic.log
|
||||
# @TEST-EXEC: btest-diff .stderr
|
6
testing/btest/scripts/base/protocols/quic/quicdoq.zeek
Normal file
6
testing/btest/scripts/base/protocols/quic/quicdoq.zeek
Normal file
|
@ -0,0 +1,6 @@
|
|||
# @TEST-DOC: Pcap with dns-over-quic lookup using https://github.com/private-octopus/quicdoq
|
||||
# @TEST-EXEC: zeek -Cr $TRACES/quic/quicdoq.pcap base/protocols/quic
|
||||
# @TEST-EXEC: zeek-cut -m ts uid history service < conn.log > conn.log.cut
|
||||
# @TEST-EXEC: btest-diff conn.log.cut
|
||||
# @TEST-EXEC: btest-diff ssl.log
|
||||
# @TEST-EXEC: btest-diff quic.log
|
|
@ -1,4 +1,5 @@
|
|||
# @TEST-DOC: Test that runs the pcap
|
||||
# @TEST-EXEC: zeek -Cr $TRACES/quic/quic_win11_firefox_google.pcap base/protocols/quic >output
|
||||
# @TEST-EXEC: btest-diff conn.log
|
||||
# @TEST-EXEC: zeek -Cr $TRACES/quic/quic_win11_firefox_google.pcap base/protocols/quic
|
||||
# @TEST-EXEC: zeek-cut -m ts uid history service < conn.log > conn.log.cut
|
||||
# @TEST-EXEC: btest-diff conn.log.cut
|
||||
# @TEST-EXEC: btest-diff ssl.log
|
|
@ -0,0 +1,9 @@
|
|||
# @TEST-DOC: Test that runs the pcap
|
||||
# @TEST-EXEC: zeek -Cr $TRACES/quic/vector-max-size-crash.pcap base/protocols/quic
|
||||
# @TEST-EXEC: zeek-cut -m ts uid history service < conn.log > conn.log.cut
|
||||
# @TEST-EXEC: zeek-cut -m ts uid cause analyzer_kind analyzer_name failure_reason < analyzer.log > analyzer.log.cut
|
||||
# @TEST-EXEC: btest-diff conn.log.cut
|
||||
|
||||
# Only run btest-ddiff on analyzer.log with 6.1-dev or later. The violation
|
||||
# reporting has more detail in later versions.
|
||||
# @TEST-EXEC: zeek -b -e 'exit(Version::info$version_number < 60100 ? 0 : 1)' || TEST_DIFF_CANONIFIER='sed -r "s/\((.+)\.spicy:[0-9]+:[0-9]+\)/(\1.spicy:<line>:<column>)/g" | $SCRIPTS/diff-remove-abspath' btest-diff analyzer.log.cut
|
Loading…
Add table
Add a link
Reference in a new issue