Merge remote-tracking branch 'origin/topic/awelzel/2326-import-quic'

* origin/topic/awelzel/2326-import-quic:
  ci/btest: Remove spicy-quic helper, disable Spicy on CentOS 7
  btest/core/ppp: Run test in bare mode
  btest/quic: Update other tests
  testing/quic: Fixups and simplification after Zeek integration
  quic: Integrate as default analyzer
  quic: Include Copyright lines to the analyzer's source code contributed by Fox-IT
  quic: Squashed follow-ups: quic.log, tests, various fixes, performance
  quic: Initial implementation
This commit is contained in:
Arne Welzel 2023-10-11 18:02:25 +02:00
commit 007bcefd09
79 changed files with 1606 additions and 15 deletions

View file

@ -204,6 +204,8 @@ centos7_task:
<< : *RESOURCES_TEMPLATE << : *RESOURCES_TEMPLATE
<< : *CI_TEMPLATE << : *CI_TEMPLATE
<< : *SKIP_TASK_ON_PR << : *SKIP_TASK_ON_PR
env:
ZEEK_CI_CONFIGURE_FLAGS: *NO_SPICY_CONFIG
debian12_task: debian12_task:
container: container:

23
CHANGES
View file

@ -1,3 +1,26 @@
6.1.0-dev.547 | 2023-10-11 18:02:25 +0200
* ci/btest: Remove spicy-quic helper, disable Spicy on CentOS 7 (Arne Welzel, Corelight)
The have-quic pattern wasn't great and it wouldn't scale.
* btest/core/ppp: Run test in bare mode (Arne Welzel, Corelight)
* btest/quic: Update other tests (Arne Welzel, Corelight)
* testing/quic: Fixups and simplification after Zeek integration (Arne Welzel, Corelight)
* quic: Integrate as default analyzer (Arne Welzel, Corelight)
* quic: Include Copyright lines to the analyzer's source code contributed by Fox-IT (Arne Welzel, Corelight)
This is primarily such that they stay intact when importing into the
Zeek project. Also move LICENSE to COPYING.
* quic: Squashed follow-ups: quic.log, tests, various fixes, performance (Arne Welzel, Corelight)
* quic: Initial implementation (Joost)
6.1.0-dev.538 | 2023-10-11 15:20:27 +0200 6.1.0-dev.538 | 2023-10-11 15:20:27 +0200
* ci/update-zeekygen-docs.sh: Do output stderr by default (Arne Welzel, Corelight) * ci/update-zeekygen-docs.sh: Do output stderr by default (Arne Welzel, Corelight)

21
NEWS
View file

@ -48,6 +48,27 @@ New Functionality
necessary in your environment. We're also open to general feedback about the necessary in your environment. We're also open to general feedback about the
structure of the new logs. structure of the new logs.
- Zeek now includes the QUIC protocol analyzer from the zeek/spicy-quic
project (https://github.com/zeek/spicy-quic). This project is a fork of
Fox-IT's initial implementation (https://github.com/fox-ds/spicy-quic).
As for the LDAP analyzer, the analyzer's events and the new ``quic.log``
should be considered preliminary and experimental until the arrival of
Zeek's next long-term-stable release (7.0). As above, any feedback and
contributions to this analyzer and the new log are welcome.
The analyzer's functionality is limited to decryption of the INITIAL packets
of QUIC version 1. If decryption of these packets is successful, the
handshake data is forwarded to Zeek's SSL analyzer. An ``ssl.log`` entry
will appear in ``ssl.log`` for QUIC connections. The entry in the ``conn.log``
will contain ``quic`` and ``ssl`` in the service field.
To disable the analyzer in case of issues, use the following snippet:
redef Analyzer::disabled_analyzers += {
Analyzer::ANALYZER_QUIC,
};
- Added a new ``assert`` statement for assertion based testing and asserting - Added a new ``assert`` statement for assertion based testing and asserting
runtime state. runtime state.

View file

@ -1 +1 @@
6.1.0-dev.538 6.1.0-dev.547

2
doc

@ -1 +1 @@
Subproject commit 6492aaeaca49ee434f03984af47310c70d96dafc Subproject commit 44565c3d638ac6e5ebe3445a55244f54c96eefae

View file

@ -66,6 +66,7 @@
@load base/protocols/ntlm @load base/protocols/ntlm
@load base/protocols/ntp @load base/protocols/ntp
@load base/protocols/pop3 @load base/protocols/pop3
@load base/protocols/quic
@load base/protocols/radius @load base/protocols/radius
@load base/protocols/rdp @load base/protocols/rdp
@load base/protocols/rfb @load base/protocols/rfb

View file

@ -0,0 +1,4 @@
@ifdef ( Analyzer::ANALYZER_QUIC )
@load ./consts
@load ./main
@endif

View 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); };
}

View file

@ -0,0 +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);
}

View file

@ -28,6 +28,7 @@ add_subdirectory(ntlm)
add_subdirectory(ntp) add_subdirectory(ntp)
add_subdirectory(pia) add_subdirectory(pia)
add_subdirectory(pop3) add_subdirectory(pop3)
add_subdirectory(quic)
add_subdirectory(radius) add_subdirectory(radius)
add_subdirectory(rdp) add_subdirectory(rdp)
add_subdirectory(rfb) add_subdirectory(rfb)

View file

@ -0,0 +1,15 @@
if (OPENSSL_VERSION VERSION_GREATER_EQUAL "1.1.0")
spicy_add_analyzer(NAME QUIC PACKAGE_NAME QUIC SOURCES QUIC.spicy QUIC.evt decrypt_crypto.cc)
# spicy_QUIC target is conditionally created by spicy_add_analyzer()
if (TARGET spicy_QUIC)
# I don't think this is actually needed as there's an unconditional
# include_directories(BEFORE ${OPENSSL_INCLUDE_DIR}) at the top-level.
target_include_directories(spicy_QUIC PRIVATE "${OPENSSL_INCLUDE_DIR}")
endif ()
else ()
message(
STATUS
"Warning: QUIC analyzer unavailable - requires OpenSSL 1.1 or later (found ${OPENSSL_VERSION})"
)
endif ()

View file

@ -0,0 +1,22 @@
# Copyright (c) 2023, NCC Group / Fox-IT. See COPYING for details.
# Copyright (c) 2023 by the Zeek Project. See COPYING for details.
protocol analyzer QUIC over UDP:
parse originator with QUIC::RequestFrame,
parse responder with QUIC::ResponseFrame;
import QUIC;
# 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);

View file

@ -0,0 +1,533 @@
# Copyright (c) 2023, NCC Group / Fox-IT. See COPYING for details.
# Copyright (c) 2023 by the Zeek Project. See COPYING for details.
module QUIC;
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(
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
##############
# Can we decrypt?
function can_decrypt(long_header: LongHeaderPacket, context: ConnectionIDInfo, is_client: bool): bool {
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
};
##############
# Definitions
##############
type LongPacketType = enum {
INITIAL = 0,
ZERO_RTT = 1,
HANDSHAKE = 2,
RETRY = 3,
};
type HeaderForm = enum {
SHORT = 0,
LONG = 1,
};
type FrameType = enum {
PADDING = 0x00,
PING = 0x01,
ACK1 = 0x02,
ACK2 = 0x03,
RESET_STREAM = 0x04,
STOP_SENDING = 0x05,
CRYPTO = 0x06,
NEW_TOKEN = 0x07,
STREAM1 = 0x08,
STREAM2 = 0x09,
STREAM3 = 0x0a,
STREAM4 = 0x0b,
STREAM5 = 0x0c,
STREAM6 = 0x0d,
STREAM7 = 0x0e,
STREAM8 = 0x0f,
MAX_DATA = 0x10,
MAX_STREAM_DATA = 0x11,
MAX_STREAMS1 = 0x12,
MAX_STREAMS2 = 0x13,
DATA_BLOCKED = 0x14,
STREAM_DATA_BLOCKED = 0x15,
STREAMS_BLOCKED1 = 0x16,
STREAMS_BLOCKED2 = 0x17,
NEW_CONNECTION_ID = 0x18,
RETIRE_CONNECTION_ID = 0x19,
PATH_CHALLENGE = 0x1a,
PATH_RESPONSE = 0x1b,
CONNECTION_CLOSE1 = 0x1c,
CONNECTION_CLOSE2 = 0x1d,
HANDSHAKE_DONE = 0x1e,
};
##############
# Helper units
##############
type VariableLengthInteger = unit {
var bytes_to_parse: uint64;
var result: uint64;
# 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;
on %done {
self.result = (self.first_byte + self.remaining_bytes).to_uint(spicy::ByteOrder::Big);
}
};
##############
# Long packets
# Generic units
##############
public type LongHeaderPacket = unit {
var encrypted_offset: uint64;
var payload_length: uint64;
var client_conn_id_length: uint8;
var server_conn_id_length: uint8;
first_byte: bitfield(8) {
header_form: 7 &convert=cast<HeaderForm>(cast<uint8>($$));
fixed_bit: 6;
packet_type: 4..5 &convert=cast<LongPacketType>(cast<uint8>($$));
type_specific_bits: 0..3 &convert=cast<uint8>($$);
};
version: uint32;
dest_conn_id_len: uint8 { self.server_conn_id_length = $$; }
dest_conn_id: bytes &size=self.server_conn_id_length;
src_conn_id_len: uint8 { self.client_conn_id_length = $$; }
src_conn_id: bytes &size=self.client_conn_id_length;
switch ( self.first_byte.packet_type ) {
LongPacketType::INITIAL -> initial_hdr : InitialPacket(self) {
self.encrypted_offset = self.offset() +
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.length.result;
}
LongPacketType::ZERO_RTT -> zerortt_hdr : ZeroRTTPacket(self);
LongPacketType::HANDSHAKE -> handshake_hdr : HandshakePacket(self);
LongPacketType::RETRY -> retry_hdr : RetryPacket(self);
};
};
# 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) {
# 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);
}
};
};
type CRYPTOPayload = unit(from_client: bool) {
offset: VariableLengthInteger;
length: VariableLengthInteger;
cryptodata: bytes &size=self.length.result;
};
type ACKPayload = unit {
latest_ack: VariableLengthInteger;
ack_delay: VariableLengthInteger;
ack_range_count: VariableLengthInteger;
first_ack_range: VariableLengthInteger;
};
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;
};
##############
# Long packets
# Specific long packet type units
##############
# Remainder of an Initial packet
type InitialPacket = unit(header: LongHeaderPacket) {
var header: LongHeaderPacket = header;
token_length: VariableLengthInteger;
token: bytes &size=self.token_length.result;
# 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
};
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
##############
# TODO: implement
public type ShortHeader = unit(dest_conn_id_length: uint8) {
first_byte: bitfield(8) {
header_form: 7 &convert=cast<HeaderForm>(cast<uint8>($$));
fixed_bit: 6;
spin_bit: 5;
todo: 0..4;
};
dest_conn_id: bytes &size=dest_conn_id_length;
};
# 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 packet parsing
#
# A UDP datagram contains one or more QUIC packets.
##############
type Packet = unit(from_client: bool, context: ConnectionIDInfo&) {
var decrypted_data: bytes;
var full_packet: bytes;
var start: iterator<stream>;
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
}
# Depending on the header, parse it and update the src/dest ConnectionID's
switch ( self.first_byte.header_form ) {
HeaderForm::SHORT -> short_header: ShortHeader(context.client_cid_len);
HeaderForm::LONG -> long_header: LongHeaderPacket {
# For now, only allow a change of src/dest ConnectionID's for INITIAL packets.
# 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;
context.client_cid_len = self.long_header.src_conn_id_len;
# 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.all_data,
self.long_header.dest_conn_id,
self.long_header.encrypted_offset,
self.long_header.payload_length,
from_client
);
# Set this to be the seed for the decryption
if ( |context.initial_destination_conn_id| == 0 ) {
context.initial_destination_conn_id = self.long_header.dest_conn_id;
}
} else {
context.server_cid_len = self.long_header.src_conn_id_len;
context.client_cid_len = self.long_header.dest_conn_id_len;
# 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.all_data,
context.initial_destination_conn_id,
self.long_header.encrypted_offset,
self.long_header.payload_length,
from_client
);
}
# 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.server_initial_processed = True;
context.client_initial_processed = True;
}
}
# 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);
# 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();
}
}
};
##############
# Entrypoints
##############
public type RequestFrame = unit {
%context = ConnectionIDInfo;
: Packet(True, self.context());
};
public type ResponseFrame = unit {
%context = ConnectionIDInfo;
: Packet(False, self.context());
};

View file

@ -0,0 +1,316 @@
// Copyright (c) 2023, NCC Group / Fox-IT. See COPYING for details.
// Copyright (c) 2023 by the Zeek Project. See COPYING for details.
/*
WORK-IN-PROGRESS
Initial working version of decrypting the INITIAL packets from
both client & server to be used by the Spicy parser. Might need a few more
refactors as C++ development is not our main profession.
*/
// Default imports
#include <array>
#include <cstdint>
#include <cstdlib>
#include <cstring>
#include <string>
#include <vector>
// OpenSSL imports
#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;
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
such as 'quic key' and 'quic hp'. These labels can obviously be
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> 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> 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> 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
*/
const size_t INITIAL_SECRET_LEN = 32;
const size_t AEAD_KEY_LEN = 16;
const size_t AEAD_IV_LEN = 12;
const size_t AEAD_HP_LEN = 16;
const size_t AEAD_SAMPLE_LENGTH = 16;
const size_t AEAD_TAG_LENGTH = 16;
const size_t MAXIMUM_PACKET_LENGTH = 1500;
const size_t MAXIMUM_PACKET_NUMBER_LENGTH = 4;
/*
HKDF-Extract as described in https://www.rfc-editor.org/rfc/rfc8446.html#section-7.1
*/
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);
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, 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 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, 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);
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);
EVP_PKEY_CTX_set1_hkdf_key(pctx, key.data(), key.size());
EVP_PKEY_CTX_add1_hkdf_info(pctx, info.data(), info.size());
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
*/
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();
auto ctx = EVP_CIPHER_CTX_new();
EVP_CipherInit_ex(ctx, cipher, NULL, NULL, NULL, 1);
EVP_CIPHER_CTX_set_key_length(ctx, client_hp.size());
// Passing an 1 means ENCRYPT
EVP_CipherInit_ex(ctx, NULL, NULL, client_hp.data(), NULL, 1);
static_assert(AEAD_SAMPLE_LENGTH > 0);
assert(all_data.size() >= encrypted_offset + MAXIMUM_PACKET_NUMBER_LENGTH + 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 = data_as_uint8(all_data)[0];
if ( first_byte & 0x80 )
{
first_byte ^= mask[0] & 0x0F;
}
else
{
first_byte ^= first_byte & 0x1F;
}
// And now we can fully recover the correct packet number length...
int recovered_packet_number_length = (first_byte & 0x03) + 1;
// .. and use this to reconstruct the (partially) unprotected header
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 )
{
unprotected_header[encrypted_offset + i] ^= mask[1 + i];
decoded_packet_number = unprotected_header[encrypted_offset + i] |
(decoded_packet_number << 8);
}
// Store the information back in the struct
decryptInfo.packet_number = decoded_packet_number;
decryptInfo.packet_number_length = recovered_packet_number_length;
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)
{
for ( int i = 0; i < 8; ++i )
client_iv[AEAD_IV_LEN - 1 - i] ^= (uint8_t)(packet_number >> 8 * i);
return client_iv;
}
/*
Function that calls the AEAD decryption routine, and returns the
decrypted data
*/
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;
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));
const uint8_t* encrypted_payload = data_as_uint8(all_data) +
decryptInfo.unprotected_header.size();
int encrypted_payload_size = payload_length - decryptInfo.packet_number_length -
AEAD_TAG_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);
// 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_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);
// Set the tag to be validated after decryption
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(),
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.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 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
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)
{
if ( payload_length < 20 )
throw hilti::rt::RuntimeError(hilti::rt::fmt("payload too small %ld < 20", payload_length));
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 )
{
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);
}
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, encrypted_offset, all_data);
// Calculate the correct nonce for the decryption
decryptInfo.nonce = calculate_nonce(iv, decryptInfo.packet_number);
return decrypt(key, all_data, payload_length, decryptInfo);
}

View file

@ -24,7 +24,7 @@
1 3544 1 3544
2 389 2 389
1 4011 1 4011
2 443 3 443
1 445 1 445
1 4789 1 4789
1 502 1 502
@ -50,11 +50,13 @@
1 6669 1 6669
1 67 1 67
1 68 1 68
1 784
1 79 1 79
1 80 1 80
1 8000 1 8000
1 8080 1 8080
1 81 1 81
1 853
2 88 2 88
1 8888 1 8888
1 989 1 989
@ -62,8 +64,8 @@
1 992 1 992
1 993 1 993
1 995 1 995
70 and 73 and
69 or 72 or
70 port 73 port
46 tcp 46 tcp
24 udp 27 udp

View file

@ -424,6 +424,9 @@ scripts/base/init-default.zeek
scripts/base/protocols/ntp/main.zeek scripts/base/protocols/ntp/main.zeek
scripts/base/protocols/ntp/consts.zeek scripts/base/protocols/ntp/consts.zeek
scripts/base/protocols/pop3/__load__.zeek scripts/base/protocols/pop3/__load__.zeek
scripts/base/protocols/quic/__load__.zeek
scripts/base/protocols/quic/consts.zeek
scripts/base/protocols/quic/main.zeek
scripts/base/protocols/radius/__load__.zeek scripts/base/protocols/radius/__load__.zeek
scripts/base/protocols/radius/main.zeek scripts/base/protocols/radius/main.zeek
scripts/base/protocols/radius/consts.zeek scripts/base/protocols/radius/consts.zeek

View file

@ -42,6 +42,7 @@ openflow
packet_filter packet_filter
pe pe
print_log_path print_log_path
quic
radius radius
rdp rdp
reporter reporter

View file

@ -508,6 +508,21 @@ connection {
* size: count, log=F, optional=F * size: count, log=F, optional=F
* state: count, log=F, optional=F * state: count, log=F, optional=F
} }
* quic: record QUIC::Info, log=F, optional=T
QUIC::Info {
* client_initial_dcid: string, log=T, optional=T
* client_protocol: string, log=T, optional=T
* history: string, log=T, optional=T
* history_state: vector of string, log=F, optional=F
* id: record conn_id, log=T, optional=F
conn_id { ... }
* logged: bool, log=F, optional=T
* server_name: string, log=T, optional=T
* server_scid: string, log=T, optional=T
* ts: time, log=T, optional=F
* uid: string, log=T, optional=F
* version: string, log=T, optional=F
}
* radius: record RADIUS::Info, log=F, optional=T * radius: record RADIUS::Info, log=F, optional=T
RADIUS::Info { RADIUS::Info {
* connect_info: string, log=T, optional=T * connect_info: string, log=T, optional=T

View file

@ -7,10 +7,10 @@
#open XXXX-XX-XX-XX-XX-XX #open XXXX-XX-XX-XX-XX-XX
#fields ts fuid uid id.orig_h id.orig_p id.resp_h id.resp_p source depth analyzers mime_type filename duration local_orig is_orig seen_bytes total_bytes missing_bytes overflow_bytes timedout parent_fuid md5 sha1 sha256 #fields ts fuid uid id.orig_h id.orig_p id.resp_h id.resp_p source depth analyzers mime_type filename duration local_orig is_orig seen_bytes total_bytes missing_bytes overflow_bytes timedout parent_fuid md5 sha1 sha256
#types time string string addr port addr port string count set[string] string string interval bool bool count count count count bool string string string string #types time string string addr port addr port string count set[string] string string interval bool bool count count count count bool string string string string
XXXXXXXXXX.XXXXXX FgN3AE3of2TRIqaeQe CHhAvVGS1DHFjwGM9 192.168.4.149 60623 74.125.239.129 443 SSL 0 X509,SHA256,SHA1,MD5 application/x-x509-user-cert - 0.000000 F F 1859 - 0 0 F - 7af07aca6d5c6e8e87fe4bb34786edc0 548b9e03bc183d1cd39f93a37985cb3950f8f06f 6bacfa4536150ed996f2b0c05ab6e345a257225f449aeb9d2018ccd88f4ede43 XXXXXXXXXX.XXXXXX FgN3AE3of2TRIqaeQe CHhAvVGS1DHFjwGM9 192.168.4.149 60623 74.125.239.129 443 SSL 0 SHA256,X509,SHA1,MD5 application/x-x509-user-cert - 0.000000 F F 1859 - 0 0 F - 7af07aca6d5c6e8e87fe4bb34786edc0 548b9e03bc183d1cd39f93a37985cb3950f8f06f 6bacfa4536150ed996f2b0c05ab6e345a257225f449aeb9d2018ccd88f4ede43
XXXXXXXXXX.XXXXXX Fv2Agc4z5boBOacQi6 CHhAvVGS1DHFjwGM9 192.168.4.149 60623 74.125.239.129 443 SSL 0 X509,SHA256,SHA1,MD5 application/x-x509-ca-cert - 0.000000 F F 1032 - 0 0 F - 9e4ac96474245129d9766700412a1f89 d83c1a7f4d0446bb2081b81a1670f8183451ca24 a047a37fa2d2e118a4f5095fe074d6cfe0e352425a7632bf8659c03919a6c81d XXXXXXXXXX.XXXXXX Fv2Agc4z5boBOacQi6 CHhAvVGS1DHFjwGM9 192.168.4.149 60623 74.125.239.129 443 SSL 0 SHA256,X509,SHA1,MD5 application/x-x509-ca-cert - 0.000000 F F 1032 - 0 0 F - 9e4ac96474245129d9766700412a1f89 d83c1a7f4d0446bb2081b81a1670f8183451ca24 a047a37fa2d2e118a4f5095fe074d6cfe0e352425a7632bf8659c03919a6c81d
XXXXXXXXXX.XXXXXX Ftmyeg2qgI2V38Dt3g CHhAvVGS1DHFjwGM9 192.168.4.149 60623 74.125.239.129 443 SSL 0 X509,SHA256,SHA1,MD5 application/x-x509-ca-cert - 0.000000 F F 897 - 0 0 F - 2e7db2a31d0e3da4b25f49b9542a2e1a 7359755c6df9a0abc3060bce369564c8ec4542a3 3c35cc963eb004451323d3275d05b353235053490d9cd83729a2faf5e7ca1cc0 XXXXXXXXXX.XXXXXX Ftmyeg2qgI2V38Dt3g CHhAvVGS1DHFjwGM9 192.168.4.149 60623 74.125.239.129 443 SSL 0 SHA256,X509,SHA1,MD5 application/x-x509-ca-cert - 0.000000 F F 897 - 0 0 F - 2e7db2a31d0e3da4b25f49b9542a2e1a 7359755c6df9a0abc3060bce369564c8ec4542a3 3c35cc963eb004451323d3275d05b353235053490d9cd83729a2faf5e7ca1cc0
XXXXXXXXXX.XXXXXX FUFNf84cduA0IJCp07 ClEkJM2Vm5giqnMf4h 192.168.4.149 60624 74.125.239.129 443 SSL 0 X509,SHA256,SHA1,MD5 application/x-x509-user-cert - 0.000000 F F 1859 - 0 0 F - 7af07aca6d5c6e8e87fe4bb34786edc0 548b9e03bc183d1cd39f93a37985cb3950f8f06f 6bacfa4536150ed996f2b0c05ab6e345a257225f449aeb9d2018ccd88f4ede43 XXXXXXXXXX.XXXXXX FUFNf84cduA0IJCp07 ClEkJM2Vm5giqnMf4h 192.168.4.149 60624 74.125.239.129 443 SSL 0 SHA256,X509,SHA1,MD5 application/x-x509-user-cert - 0.000000 F F 1859 - 0 0 F - 7af07aca6d5c6e8e87fe4bb34786edc0 548b9e03bc183d1cd39f93a37985cb3950f8f06f 6bacfa4536150ed996f2b0c05ab6e345a257225f449aeb9d2018ccd88f4ede43
XXXXXXXXXX.XXXXXX F1H4bd2OKGbLPEdHm4 ClEkJM2Vm5giqnMf4h 192.168.4.149 60624 74.125.239.129 443 SSL 0 X509,SHA256,SHA1,MD5 application/x-x509-ca-cert - 0.000000 F F 1032 - 0 0 F - 9e4ac96474245129d9766700412a1f89 d83c1a7f4d0446bb2081b81a1670f8183451ca24 a047a37fa2d2e118a4f5095fe074d6cfe0e352425a7632bf8659c03919a6c81d XXXXXXXXXX.XXXXXX F1H4bd2OKGbLPEdHm4 ClEkJM2Vm5giqnMf4h 192.168.4.149 60624 74.125.239.129 443 SSL 0 SHA256,X509,SHA1,MD5 application/x-x509-ca-cert - 0.000000 F F 1032 - 0 0 F - 9e4ac96474245129d9766700412a1f89 d83c1a7f4d0446bb2081b81a1670f8183451ca24 a047a37fa2d2e118a4f5095fe074d6cfe0e352425a7632bf8659c03919a6c81d
XXXXXXXXXX.XXXXXX Fgsbci2jxFXYMOHOhi ClEkJM2Vm5giqnMf4h 192.168.4.149 60624 74.125.239.129 443 SSL 0 X509,SHA256,SHA1,MD5 application/x-x509-ca-cert - 0.000000 F F 897 - 0 0 F - 2e7db2a31d0e3da4b25f49b9542a2e1a 7359755c6df9a0abc3060bce369564c8ec4542a3 3c35cc963eb004451323d3275d05b353235053490d9cd83729a2faf5e7ca1cc0 XXXXXXXXXX.XXXXXX Fgsbci2jxFXYMOHOhi ClEkJM2Vm5giqnMf4h 192.168.4.149 60624 74.125.239.129 443 SSL 0 SHA256,X509,SHA1,MD5 application/x-x509-ca-cert - 0.000000 F F 897 - 0 0 F - 2e7db2a31d0e3da4b25f49b9542a2e1a 7359755c6df9a0abc3060bce369564c8ec4542a3 3c35cc963eb004451323d3275d05b353235053490d9cd83729a2faf5e7ca1cc0
#close XXXX-XX-XX-XX-XX-XX #close XXXX-XX-XX-XX-XX-XX

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -0,0 +1 @@
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.

View file

@ -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,

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -0,0 +1 @@
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -0,0 +1 @@
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.

View file

@ -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.000000 CHhAvVGS1DHFjwGM9 - -
0.016059 ClEkJM2Vm5giqnMf4h - -
0.669020 C4J4Th3PJpwUYZZ6gc Dd quic,ssl

View file

@ -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

View file

@ -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

View file

@ -0,0 +1 @@
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -0,0 +1 @@
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -0,0 +1 @@
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.

View file

@ -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 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

View file

@ -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>)

View file

@ -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 -

View 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

Binary file not shown.

Binary file not shown.

View file

@ -1,4 +1,6 @@
# @TEST-DOC: PCAP from https://interop.seemann.io/ with DLT_PPP linklayer and no HDLC framing. # @TEST-DOC: PCAP from https://interop.seemann.io/ with DLT_PPP linklayer and no HDLC framing.
# #
# @TEST-EXEC: zeek -r $TRACES/ppp/quic-interop-retry.pcap %INPUT # @TEST-EXEC: zeek -b -r $TRACES/ppp/quic-interop-retry.pcap %INPUT
# @TEST-EXEC: btest-diff conn.log # @TEST-EXEC: btest-diff conn.log
@load base/protocols/conn

View file

@ -1,4 +1,4 @@
# @TEST-REQUIRES: have-spicy # @TEST-REQUIRES: $SCRIPTS/have-spicy
# #
# @TEST-EXEC: zeek -r $TRACES/empty.trace >output # @TEST-EXEC: zeek -r $TRACES/empty.trace >output
# @TEST-EXEC: cat packet_filter.log >>output # @TEST-EXEC: cat packet_filter.log >>output

View file

@ -0,0 +1,8 @@
# @TEST-DOC: Test that runs the pcap
# @TEST-REQUIRES: ${SCRIPTS}/have-spicy
# @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

View file

@ -0,0 +1,8 @@
# @TEST-DOC: Test that runs the pcap
# @TEST-REQUIRES: ${SCRIPTS}/have-spicy
# @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

View file

@ -0,0 +1,30 @@
# @TEST-DOC: Supported events so far.
# @TEST-REQUIRES: ${SCRIPTS}/have-spicy
# @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);
}

View file

@ -0,0 +1,8 @@
# @TEST-DOC: Test that runs the pcap
# @TEST-REQUIRES: ${SCRIPTS}/have-spicy
# @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

View file

@ -0,0 +1,8 @@
# @TEST-DOC: Pcap with fragmented and unordered CRYPTO frames.
# @TEST-REQUIRES: ${SCRIPTS}/have-spicy
# @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

View file

@ -0,0 +1,10 @@
# @TEST-DOC: Test interop pcap containing RETRY packet from server side.
# @TEST-REQUIRES: ${SCRIPTS}/have-spicy
# @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

View file

@ -0,0 +1,10 @@
# @TEST-DOC: Test interop pcap containing RETRY packet from server side.
#
# @TEST-REQUIRES: ${SCRIPTS}/have-spicy
# @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

View file

@ -0,0 +1,10 @@
# @TEST-DOC: Test that client initiating connection using 0RTT packet doesn't cause analyzer errors trying to decrypt server side.
#
# @TEST-REQUIRES: ${SCRIPTS}/have-spicy
# @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

View file

@ -0,0 +1,6 @@
# @TEST-DOC: Smoke test the quic.log production
# @TEST-REQUIRES: ${SCRIPTS}/have-spicy
# @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

View file

@ -0,0 +1,8 @@
# @TEST-DOC: Pcap with dns-over-quic lookup using https://github.com/private-octopus/quicdoq
# @TEST-REQUIRES: ${SCRIPTS}/have-spicy
# @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

View file

@ -0,0 +1,7 @@
# @TEST-DOC: Test that runs the pcap
# @TEST-REQUIRES: ${SCRIPTS}/have-spicy
# @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

View file

@ -0,0 +1,11 @@
# @TEST-DOC: Test that runs the pcap
# @TEST-REQUIRES: ${SCRIPTS}/have-spicy
# @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