diff --git a/.typos.toml b/.typos.toml index ab4d9769e4..4fcc006718 100644 --- a/.typos.toml +++ b/.typos.toml @@ -80,6 +80,8 @@ have_2nd = "have_2nd" ot1 = "ot1" ot2 = "ot2" uses_seh = "uses_seh" +ect0 = "ect0" +ect1 = "ect1" [default.extend-words] caf = "caf" diff --git a/CHANGES b/CHANGES index a6edddddbf..4f1ab9f7b0 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,50 @@ +7.2.0-rc1.7 | 2025-05-05 11:17:50 -0700 + + * QUIC: Extract reset_crypto() function (Arne Welzel, Corelight) + + (cherry picked from commit 50ac8d1468603c710e109f1c050b3966dd91deda) + + * QUIC: Rename ConnectionIDInfo to Context (Arne Welzel, Corelight) + + (cherry picked from commit 50ac8d1468603c710e109f1c050b3966dd91deda) + + * QUIC: Switch initial_destination_conn_id to optional (Arne Welzel, Corelight) + + (cherry picked from commit 50ac8d1468603c710e109f1c050b3966dd91deda) + + * QUIC: Use initial destination conn_id for decryption (Arne Welzel, Corelight) + + Ensure the client side also uses the initial destination connection ID + for decryption purposes instead of the one from the current long header + packet. PCAP from local WiFi hotspot. + + (cherry picked from commit 50ac8d1468603c710e109f1c050b3966dd91deda) + + * QUIC: Handle CRYPTO frames across multiple INITIAL packets (Arne Welzel, Corelight) + + Instead of sending the accumulated CRYPTO frames after processing an + INITIAL packet, add logic to determine the total length of the TLS + Client or Server Hello (by peeking into the first 4 byte). Once all + CRYPTO frames have arrived, flush the reassembled data to the TLS + analyzer at once. + + (cherry picked from commit 50ac8d1468603c710e109f1c050b3966dd91deda) + + * QUIC: Do not consume EncryptedLongPacketPayload (Arne Welzel, Corelight) + + The payload is already consumed within the InitialPacket unit. Consuming + it again resulted in UDP datagrams with multiple packets to ignore + the remaining packets in the same UDP datagram. The baseline changes + showing I being followed by a new H indicates that the INITIAL packet + was followed by a HANDSHAKE packet, but previously Zeek discarded + these. + + (cherry picked from commit 50ac8d1468603c710e109f1c050b3966dd91deda) + + * QUIC: Fix ACK frame parsing (Arne Welzel, Corelight) + + (cherry picked from commit 50ac8d1468603c710e109f1c050b3966dd91deda) + 7.2.0-rc1.6 | 2025-04-29 17:51:10 -0700 * fixed incorrect ZAM optimization of expressions seen in single-statement inlined functions (Vern Paxson, Corelight) diff --git a/VERSION b/VERSION index 71e0ba503c..c724575e52 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -7.2.0-rc1.6 +7.2.0-rc1.7 diff --git a/src/analyzer/protocol/quic/QUIC.spicy b/src/analyzer/protocol/quic/QUIC.spicy index 0d6064d4c6..dbac41d761 100644 --- a/src/analyzer/protocol/quic/QUIC.spicy +++ b/src/analyzer/protocol/quic/QUIC.spicy @@ -17,27 +17,104 @@ public function decrypt_crypto_payload( ): 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 { +function can_decrypt(long_header: LongHeaderPacket, context: Context, crypto: CryptoSinkUnit&): bool { if ( ! long_header.is_initial ) return False; - if ( is_client ) - return ! context.client_initial_processed; + if ( crypto == Null ) + return False; - # 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; + # Can only decrypt the responder if we've seen the initial destination conn id. + if ( ! crypto.is_orig && ! context.initial_destination_conn_id ) + return False; + + # Only attempt decryption if we haven't flushed some SSL data yet. + return ! crypto.finished; } -type ConnectionIDInfo = struct { +function reset_crypto(context: Context&) { + # Recreate all the crypto state on the next %init of Packet. + zeek::protocol_handle_close(context.ssl_handle); + unset context.ssl_handle; + context.client_crypto = Null; + context.server_crypto = Null; + context.client_sink = Null; + context.server_sink = Null; + context.initial_destination_conn_id = Null; +} + +# This unit is connected with the server and client sinks receiving +# CRYPTO frames and forwards data to the SSL handle in the context. +type CryptoSinkUnit = unit(is_orig: bool, context: Context&) { + var buffered: bytes; + var length: uint32 = 0; + var is_orig: bool = is_orig; + var finished: bool; + + # The first 4 bytes of crypto data contain the expected tag and a + # 24bit length from the TLS HandshakeMessage. Extract the length + # so we can determine when all CRYPTO frames have arrived. + # + # https://datatracker.ietf.org/doc/html/rfc8446#section-4 + # + # struct { + # HandshakeType msg_type; /* handshake type */ + # uint24 length; /* remaining bytes in message */ + # ... + # + : uint8 { + self.buffered += $$; + } + + len: uint8[3] { + self.length = (cast($$[0]) << 16) + (cast($$[1]) << 8) + cast($$[2]) + 4; + + self.buffered += $$[0]; + self.buffered += $$[1]; + self.buffered += $$[2]; + } + + : void &requires=(self.length <= 2**14 + 256) { # The length MUST NOT exceed 2^14 + 256 bytes (RFC 8446) + + # The client or server hello data is forwarded to the SSL analyzer as a + # TLSPlaintext record with legacy_record_version set to \x03\x03 (1.3). + # + # enum { + # invalid(0), + # change_cipher_spec(20), + # alert(21), + # handshake(22), + # application_data(23), + # (255) + # } ContentType; + # + # struct { + # ContentType type; + # ProtocolVersion legacy_record_version; + # uint16 length; + # opaque fragment[TLSPlaintext.length]; + # } TLSPlaintext; + # + # https://datatracker.ietf.org/doc/html/rfc8446#section-5.1 + local length_bytes = pack(cast(self.length), spicy::ByteOrder::Big); + zeek::protocol_data_in(is_orig, b"\x16\x03\x03" + length_bytes + self.buffered, context.ssl_handle); + } + + : bytes &chunked &size=(self.length - 4) { + zeek::protocol_data_in(is_orig, $$, context.ssl_handle); + } + + : void { + self.finished = True; + } +}; + +############## +## Context +############## +type Context = struct { client_cid_len: uint8; server_cid_len: uint8; @@ -46,26 +123,13 @@ type ConnectionIDInfo = struct { # will make life miserable. # # https://quicwg.org/base-drafts/rfc9001.html#appendix-A - initial_destination_conn_id: bytes; + initial_destination_conn_id: optional; - # 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; + # Track crypto state. + client_crypto: CryptoSinkUnit&; + client_sink: sink&; + server_crypto: CryptoSinkUnit&; + server_sink: sink&; ssl_handle: zeek::ProtocolHandle &optional; }; @@ -272,16 +336,28 @@ public type LongHeaderPacket = unit { }; # A QUIC Frame. -public type Frame = unit(header: LongHeaderPacket, from_client: bool, crypto_sink: sink&) { +public type Frame = unit(header: LongHeaderPacket, from_client: bool, crypto: CryptoSinkUnit, crypto_sink: sink&) { frame_type : uint8 &convert=cast($$); # TODO: add other FrameTypes as well switch ( self.frame_type ) { - FrameType::ACK1 -> a: ACKPayload; - FrameType::ACK2 -> b: ACKPayload; + FrameType::ACK1 -> a: ACKPayload(FrameType::ACK1); + FrameType::ACK2 -> b: ACKPayload(FrameType::ACK2); 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_); + + # If the crypto unit has determined a valid length, ensure we + # don't attempt to write more bytes into the sink. If it doesn't, + # use 2000 bytes as an arbitrary limit required to observe the + # length of the contained Client Hello or Server Hello. + if ( crypto.length > 0 ) { + if ( |crypto_sink| > crypto.length ) + throw "too much crypto data received %s > %s" % ( |crypto_sink|, crypto.length); + } else { + if ( |crypto_sink| > 2000 ) + throw "too much crypto data without length received %s" % |crypto_sink|; + } } FrameType::CONNECTION_CLOSE1 -> : ConnectionClosePayload(header); FrameType::PADDING -> : skip /\x00*/; # eat the padding @@ -298,11 +374,26 @@ type CRYPTOPayload = unit(from_client: bool) { cryptodata: bytes &size=self.length.result_; }; -type ACKPayload = unit { +# https://datatracker.ietf.org/doc/html/rfc9000#ack-ranges +type ACKRange = unit { + gap: VariableLengthInteger; + ack_range_length: VariableLengthInteger; +}; + +type ACKECNCounts = unit { + ect0: VariableLengthInteger; + ect1: VariableLengthInteger; + ecn_ce: VariableLengthInteger; +}; + +# https://datatracker.ietf.org/doc/html/rfc9000#name-ack-frames +type ACKPayload = unit(frame_type: FrameType) { latest_ack: VariableLengthInteger; ack_delay: VariableLengthInteger; ack_range_count: VariableLengthInteger; first_ack_range: VariableLengthInteger; + ack_ranges: ACKRange[self.ack_range_count.result_]; + ecn_counts: ACKECNCounts if(frame_type == FrameType::ACK2); }; type ConnectionClosePayload = unit(header: LongHeaderPacket) { @@ -393,35 +484,18 @@ public type ShortPacketPayload = unit { payload: skip bytes &eod; }; -# TODO: investigate whether we can do something useful with this -public type EncryptedLongPacketPayload = unit { - payload: skip bytes &eod; -}; - -# 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&) { +type Packet = unit(from_client: bool, context: Context&) { var decrypted_data: bytes; var packet_size: uint64 = 0; var start: iterator; - sink crypto_sink; - var crypto_buffer: CryptoBuffer&; + var crypto: CryptoSinkUnit&; + var crypto_sink: sink&; # Attach an SSL analyzer to this connection once. on %init { @@ -430,6 +504,26 @@ type Packet = unit(from_client: bool, context: ConnectionIDInfo&) { } self.start = self.input(); + + # Initialize crypto state in context for both sides if not already done. + if ( context.client_crypto == Null ) { + assert ! context.server_crypto; + context.client_crypto = new CryptoSinkUnit(True, context); + context.client_sink = new sink; + context.client_sink.connect(context.client_crypto); + + context.server_crypto = new CryptoSinkUnit(False, context); + context.server_sink = new sink; + context.server_sink.connect(context.server_crypto); + } + + if ( from_client ) { + self.crypto = context.client_crypto; + self.crypto_sink = context.client_sink; + } else { + self.crypto = context.server_crypto; + self.crypto_sink = context.server_sink; + } } # Peek into the first byte and determine the header type. @@ -443,7 +537,6 @@ type Packet = unit(from_client: bool, context: ConnectionIDInfo&) { 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); @@ -453,19 +546,16 @@ type Packet = unit(from_client: bool, context: ConnectionIDInfo&) { # 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.is_retry ) { - context.client_initial_processed = False; - context.server_initial_processed = False; - context.initial_destination_conn_id = b""; + reset_crypto(context); - # Allow re-opening the SSL analyzer the next time around. - zeek::protocol_handle_close(context.ssl_handle); - unset context.ssl_handle; + self.crypto = Null; + self.crypto_sink = Null; } } }; : void { - if (self?.long_header && can_decrypt(self.long_header, context, from_client)) + if ( self?.long_header && can_decrypt(self.long_header, context, self.crypto ) ) # If we have parsed an initial packet that we can decrypt the payload, # determine the size to store into a buffer. self.packet_size = self.offset(); @@ -473,30 +563,29 @@ type Packet = unit(from_client: bool, context: ConnectionIDInfo&) { # Buffer the whole packet if we determined we have a chance to decrypt. packet_data: bytes &parse-at=self.start &size=self.packet_size if ( self.packet_size > 0 ) { - 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 is the first INITIAL packet we attempt to decrypt and it is + # coming from the client. Use its destination connection ID for + # decryption purposes. + if ( ! context.initial_destination_conn_id ) { + context.initial_destination_conn_id = self.long_header.dest_conn_id; + } + # 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.long_header.version, self.packet_data, - self.long_header.dest_conn_id, + *context.initial_destination_conn_id, self.long_header.encrypted_offset, self.long_header.payload_length, from_client ); - # 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 - 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; @@ -504,7 +593,7 @@ type Packet = unit(from_client: bool, context: ConnectionIDInfo&) { self.decrypted_data = decrypt_crypto_payload( self.long_header.version, self.packet_data, - context.initial_destination_conn_id, + *context.initial_destination_conn_id, self.long_header.encrypted_offset, self.long_header.payload_length, from_client @@ -521,51 +610,24 @@ type Packet = unit(from_client: bool, context: ConnectionIDInfo&) { spicy::accept_input(); } - # Depending on the type of header and whether we were able to decrypt - # some of it, parse the remaining payload. + # If this packet has a SHORT header, consume until &eod, there's nothing + # we can do with it anyhow. : 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(|handshake_data|), spicy::ByteOrder::Big); - zeek::protocol_data_in( - from_client - , b"\x16\x03\x03" + length_bytes + handshake_data - , context.ssl_handle - ); - - # Stop decryption attempts after processing the very first INITIAL - # INITIAL packet for which we forwarded data to the SSL analyzer. - if ( from_client ) - context.client_initial_processed = True; - else - context.server_initial_processed = True; - } - } + frames: Frame(self.long_header, from_client, self.crypto, self.crypto_sink)[] &parse-from=self.decrypted_data if (self.first_byte.header_form == HeaderForm::LONG && |self.decrypted_data| > 0); }; ############## # Entrypoints ############## public type RequestFrame = unit { - %context = ConnectionIDInfo; + %context = Context; : Packet(True, self.context())[]; }; public type ResponseFrame = unit { - %context = ConnectionIDInfo; + %context = Context; : Packet(False, self.context())[]; }; diff --git a/testing/btest/Baseline/scripts.base.protocols.quic.curl-http3/quic.log b/testing/btest/Baseline/scripts.base.protocols.quic.curl-http3/quic.log index 29f634519b..9a2bc00efd 100644 --- a/testing/btest/Baseline/scripts.base.protocols.quic.curl-http3/quic.log +++ b/testing/btest/Baseline/scripts.base.protocols.quic.curl-http3/quic.log @@ -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 client_initial_dcid client_scid server_scid server_name client_protocol history #types time string addr port addr port string string string string string string string -XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 172.17.0.2 34347 64.233.166.94 443 1 815d62c70884f4b51e8ccadd5beed372 e5ec6b26584229be98a164349ae910351c40d10b c15d62c70884f4b5 www.google.de h3 ISishIhHhhH +XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 172.17.0.2 34347 64.233.166.94 443 1 815d62c70884f4b51e8ccadd5beed372 e5ec6b26584229be98a164349ae910351c40d10b c15d62c70884f4b5 www.google.de h3 ISishIHhHhhH #close XXXX-XX-XX-XX-XX-XX diff --git a/testing/btest/Baseline/scripts.base.protocols.quic.decrypt-fail-google-de-51833/conn.log.cut b/testing/btest/Baseline/scripts.base.protocols.quic.decrypt-fail-google-de-51833/conn.log.cut new file mode 100644 index 0000000000..46d72b1541 --- /dev/null +++ b/testing/btest/Baseline/scripts.base.protocols.quic.decrypt-fail-google-de-51833/conn.log.cut @@ -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 diff --git a/testing/btest/Baseline/scripts.base.protocols.quic.decrypt-fail-google-de-51833/quic.log.cut b/testing/btest/Baseline/scripts.base.protocols.quic.decrypt-fail-google-de-51833/quic.log.cut new file mode 100644 index 0000000000..6199e7117b --- /dev/null +++ b/testing/btest/Baseline/scripts.base.protocols.quic.decrypt-fail-google-de-51833/quic.log.cut @@ -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 server_name history +XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 www.google.de ZZZIiIIIISiIIIiiiiiishIIHH diff --git a/testing/btest/Baseline/scripts.base.protocols.quic.decrypt-fail-google-de-51833/ssl.log.cut b/testing/btest/Baseline/scripts.base.protocols.quic.decrypt-fail-google-de-51833/ssl.log.cut new file mode 100644 index 0000000000..e72550284a --- /dev/null +++ b/testing/btest/Baseline/scripts.base.protocols.quic.decrypt-fail-google-de-51833/ssl.log.cut @@ -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 X25519MLKEM768 www.google.de T - - F Cs diff --git a/testing/btest/Baseline/scripts.base.protocols.quic.events/out b/testing/btest/Baseline/scripts.base.protocols.quic.events/out index e377ed39d4..6178826346 100644 --- a/testing/btest/Baseline/scripts.base.protocols.quic.events/out +++ b/testing/btest/Baseline/scripts.base.protocols.quic.events/out @@ -47,3 +47,4 @@ zerortt.pcap 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, +1.0, handshake_packet, T, CtPZjS20MLrsMUOJi2, 1, 3ec82f67, diff --git a/testing/btest/Baseline/scripts.base.protocols.quic.interop.quic-go_quic-go.zerortt/quic.log b/testing/btest/Baseline/scripts.base.protocols.quic.interop.quic-go_quic-go.zerortt/quic.log index f2f8098294..b09e3ac209 100644 --- a/testing/btest/Baseline/scripts.base.protocols.quic.interop.quic-go_quic-go.zerortt/quic.log +++ b/testing/btest/Baseline/scripts.base.protocols.quic.interop.quic-go_quic-go.zerortt/quic.log @@ -7,6 +7,6 @@ #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 client_scid server_scid server_name client_protocol history #types time string addr port addr port string string string string string string string -1.000000 CtPZjS20MLrsMUOJi2 193.167.0.100 49394 193.167.100.100 443 1 15ae5e5e4962163f410b5529fc125bbc (empty) e483a751 server4:443 hq-interop ISZishZZZZZZZZZZZZZZZZZZZZZZZZZZZIH +1.000000 CtPZjS20MLrsMUOJi2 193.167.0.100 49394 193.167.100.100 443 1 15ae5e5e4962163f410b5529fc125bbc (empty) e483a751 server4:443 hq-interop ISZishZZZZZZZZZZZZZZZZZZZZZZZZZZZIHH 1.000000 C4J4Th3PJpwUYZZ6gc 193.167.0.100 60492 193.167.100.100 443 1 b7c7841c64883e3261d840 (empty) 8d2041ac server4:443 hq-interop ISishhIH #close XXXX-XX-XX-XX-XX-XX diff --git a/testing/btest/Baseline/scripts.base.protocols.quic.multiple-initial-fragmented-crypto-only-initial/conn.log.cut b/testing/btest/Baseline/scripts.base.protocols.quic.multiple-initial-fragmented-crypto-only-initial/conn.log.cut new file mode 100644 index 0000000000..06445c01a5 --- /dev/null +++ b/testing/btest/Baseline/scripts.base.protocols.quic.multiple-initial-fragmented-crypto-only-initial/conn.log.cut @@ -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 quic,ssl diff --git a/testing/btest/Baseline/scripts.base.protocols.quic.multiple-initial-fragmented-crypto-only-initial/quic.log.cut b/testing/btest/Baseline/scripts.base.protocols.quic.multiple-initial-fragmented-crypto-only-initial/quic.log.cut new file mode 100644 index 0000000000..13f1e1fa45 --- /dev/null +++ b/testing/btest/Baseline/scripts.base.protocols.quic.multiple-initial-fragmented-crypto-only-initial/quic.log.cut @@ -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 server_name history +XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 googleads.g.doubleclick.net IIIS diff --git a/testing/btest/Baseline/scripts.base.protocols.quic.multiple-initial-fragmented-crypto-only-initial/ssl.log.cut b/testing/btest/Baseline/scripts.base.protocols.quic.multiple-initial-fragmented-crypto-only-initial/ssl.log.cut new file mode 100644 index 0000000000..1929143aa1 --- /dev/null +++ b/testing/btest/Baseline/scripts.base.protocols.quic.multiple-initial-fragmented-crypto-only-initial/ssl.log.cut @@ -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 - - - googleads.g.doubleclick.net F - - F C diff --git a/testing/btest/Baseline/scripts.base.protocols.quic.multiple-initial-fragmented-crypto/conn.log.cut b/testing/btest/Baseline/scripts.base.protocols.quic.multiple-initial-fragmented-crypto/conn.log.cut new file mode 100644 index 0000000000..46d72b1541 --- /dev/null +++ b/testing/btest/Baseline/scripts.base.protocols.quic.multiple-initial-fragmented-crypto/conn.log.cut @@ -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 diff --git a/testing/btest/Baseline/scripts.base.protocols.quic.multiple-initial-fragmented-crypto/quic.log.cut b/testing/btest/Baseline/scripts.base.protocols.quic.multiple-initial-fragmented-crypto/quic.log.cut new file mode 100644 index 0000000000..b8cd8237eb --- /dev/null +++ b/testing/btest/Baseline/scripts.base.protocols.quic.multiple-initial-fragmented-crypto/quic.log.cut @@ -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 server_name history +XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 googleads.g.doubleclick.net IIISZZZiIiIIIIIIZ diff --git a/testing/btest/Baseline/scripts.base.protocols.quic.multiple-initial-fragmented-crypto/ssl.log.cut b/testing/btest/Baseline/scripts.base.protocols.quic.multiple-initial-fragmented-crypto/ssl.log.cut new file mode 100644 index 0000000000..1929143aa1 --- /dev/null +++ b/testing/btest/Baseline/scripts.base.protocols.quic.multiple-initial-fragmented-crypto/ssl.log.cut @@ -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 - - - googleads.g.doubleclick.net F - - F C diff --git a/testing/btest/Baseline/scripts.base.protocols.quic.quicv2-echo-443/quic.log b/testing/btest/Baseline/scripts.base.protocols.quic.quicv2-echo-443/quic.log index a460e7fec8..1d3ecea7b2 100644 --- a/testing/btest/Baseline/scripts.base.protocols.quic.quicv2-echo-443/quic.log +++ b/testing/btest/Baseline/scripts.base.protocols.quic.quicv2-echo-443/quic.log @@ -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 client_initial_dcid client_scid server_scid server_name client_protocol history #types time string addr port addr port string string string string string string string -XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 127.0.0.1 49320 127.0.0.1 443 quicv2 fa603212c8688817af3d3238735bc7 (empty) b168b5cc localhost quic-echo-example ISIIishIH +XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 127.0.0.1 49320 127.0.0.1 443 quicv2 fa603212c8688817af3d3238735bc7 (empty) b168b5cc localhost quic-echo-example ISIIishIHH #close XXXX-XX-XX-XX-XX-XX diff --git a/testing/btest/Traces/quic/quic-decrypt-fail-google-de-51833.pcap b/testing/btest/Traces/quic/quic-decrypt-fail-google-de-51833.pcap new file mode 100644 index 0000000000..cc7d2fec1a Binary files /dev/null and b/testing/btest/Traces/quic/quic-decrypt-fail-google-de-51833.pcap differ diff --git a/testing/btest/Traces/quic/quic-multiple-initial-fragmented-crypto-only-initial.pcap b/testing/btest/Traces/quic/quic-multiple-initial-fragmented-crypto-only-initial.pcap new file mode 100644 index 0000000000..aecc0c7eb9 Binary files /dev/null and b/testing/btest/Traces/quic/quic-multiple-initial-fragmented-crypto-only-initial.pcap differ diff --git a/testing/btest/Traces/quic/quic-multiple-initial-fragmented-crypto.pcap b/testing/btest/Traces/quic/quic-multiple-initial-fragmented-crypto.pcap new file mode 100644 index 0000000000..d4cad58756 Binary files /dev/null and b/testing/btest/Traces/quic/quic-multiple-initial-fragmented-crypto.pcap differ diff --git a/testing/btest/scripts/base/protocols/quic/decrypt-fail-google-de-51833.zeek b/testing/btest/scripts/base/protocols/quic/decrypt-fail-google-de-51833.zeek new file mode 100644 index 0000000000..23c9cdaf0e --- /dev/null +++ b/testing/btest/scripts/base/protocols/quic/decrypt-fail-google-de-51833.zeek @@ -0,0 +1,12 @@ +# @TEST-DOC: PCAP for which decryption failed due to not using the initial destination connection ID consistently. + +# @TEST-REQUIRES: ${SCRIPTS}/have-spicy +# @TEST-EXEC: zeek -Cr $TRACES/quic/quic-decrypt-fail-google-de-51833.pcap base/protocols/quic +# @TEST-EXEC: test ! -f analyzer.log +# @TEST-EXEC: test ! -f dpd.log +# @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 server_name history < quic.log > quic.log.cut +# @TEST-EXEC: btest-diff quic.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 diff --git a/testing/btest/scripts/base/protocols/quic/multiple-initial-fragmented-crypto-only-initial.zeek b/testing/btest/scripts/base/protocols/quic/multiple-initial-fragmented-crypto-only-initial.zeek new file mode 100644 index 0000000000..0537353ecb --- /dev/null +++ b/testing/btest/scripts/base/protocols/quic/multiple-initial-fragmented-crypto-only-initial.zeek @@ -0,0 +1,12 @@ +# @TEST-DOC: Pcap with CRYPTO frames fragemented over multiple INITIAL packets. The pcap only contains 3 INITIAL packets. Check what logs are created. + +# @TEST-REQUIRES: ${SCRIPTS}/have-spicy +# @TEST-EXEC: zeek -Cr $TRACES/quic/quic-multiple-initial-fragmented-crypto-only-initial.pcap base/protocols/quic +# @TEST-EXEC: test ! -f analyzer.log +# @TEST-EXEC: test ! -f dpd.log +# @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 server_name history < quic.log > quic.log.cut +# @TEST-EXEC: btest-diff quic.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 diff --git a/testing/btest/scripts/base/protocols/quic/multiple-initial-fragmented-crypto.zeek b/testing/btest/scripts/base/protocols/quic/multiple-initial-fragmented-crypto.zeek new file mode 100644 index 0000000000..98696053bd --- /dev/null +++ b/testing/btest/scripts/base/protocols/quic/multiple-initial-fragmented-crypto.zeek @@ -0,0 +1,12 @@ +# @TEST-DOC: Pcap with CRYPTO frames fragemented over multiple INITIAL packets. + +# @TEST-REQUIRES: ${SCRIPTS}/have-spicy +# @TEST-EXEC: zeek -Cr $TRACES/quic/quic-multiple-initial-fragmented-crypto.pcap base/protocols/quic +# @TEST-EXEC: test ! -f analyzer.log +# @TEST-EXEC: test ! -f dpd.log +# @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 server_name history < quic.log > quic.log.cut +# @TEST-EXEC: btest-diff quic.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 diff --git a/testing/external/commit-hash.zeek-testing b/testing/external/commit-hash.zeek-testing index 478402fe91..c7c33cec5b 100644 --- a/testing/external/commit-hash.zeek-testing +++ b/testing/external/commit-hash.zeek-testing @@ -1 +1 @@ -b7c465d5a208546bd27801496eb7e6035b208f27 +5fd78ecbdd834feff545f3a3c19b974d927ffb91