From 720cd94a0966c0d3ba3818b98ec94e5ea4e5d4d1 Mon Sep 17 00:00:00 2001 From: Junho Choi Date: Mon, 3 May 2021 12:04:31 -0700 Subject: check the packet length against the buffer size When we queue 0-rtt packets in undecryptable_pkts, there is a case that actual packet length is smaller than the size in the payload (packet length field) which may cause a runtime panic. Such packet is undecryptable in any way, so check it early and return error. --- src/lib.rs | 71 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 70 insertions(+), 1 deletion(-) (limited to 'src/lib.rs') diff --git a/src/lib.rs b/src/lib.rs index 1a3d6d6e..db472c46 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1834,6 +1834,17 @@ impl Connection { })? as usize }; + // Make sure the buffer is same or larger than an explicit + // payload length. + if payload_len > b.cap() { + return Err(drop_pkt_on_err( + Error::InvalidPacket, + self.recv_count, + self.is_server, + &self.trace_id, + )); + } + // Derive initial secrets on the server. if !self.derived_initial_secrets { let (aead_open, aead_seal) = crypto::derive_initial_key_material( @@ -5966,6 +5977,64 @@ mod tests { assert_eq!(&b[..5], b"aaaaa"); } + #[test] + fn handshake_0rtt_truncated() { + let mut buf = [0; 65535]; + + let mut config = Config::new(crate::PROTOCOL_VERSION).unwrap(); + config + .load_cert_chain_from_pem_file("examples/cert.crt") + .unwrap(); + config + .load_priv_key_from_pem_file("examples/cert.key") + .unwrap(); + config + .set_application_protos(b"\x06proto1\x06proto2") + .unwrap(); + config.set_initial_max_data(30); + config.set_initial_max_stream_data_bidi_local(15); + config.set_initial_max_stream_data_bidi_remote(15); + config.set_initial_max_streams_bidi(3); + config.enable_early_data(); + config.verify_peer(false); + + // Perform initial handshake. + let mut pipe = testing::Pipe::with_config(&mut config).unwrap(); + assert_eq!(pipe.handshake(), Ok(())); + + // Extract session, + let session = pipe.client.session().unwrap(); + + // Configure session on new connection. + let mut pipe = testing::Pipe::with_config(&mut config).unwrap(); + assert_eq!(pipe.client.set_session(&session), Ok(())); + + // Client sends initial flight. + pipe.client.send(&mut buf).unwrap(); + + // Client sends 0-RTT packet. + let pkt_type = packet::Type::ZeroRTT; + + let frames = [frame::Frame::Stream { + stream_id: 4, + data: stream::RangeBuf::from(b"aaaaa", 0, true), + }]; + + let len = + testing::encode_pkt(&mut pipe.client, pkt_type, &frames, &mut buf) + .unwrap(); + + // Simulate a truncated packet by sending one byte less. + let mut zrtt = (&buf[..len - 1]).to_vec(); + + // 0-RTT packet is received before the Initial one. + assert_eq!(pipe.server.recv(&mut zrtt), Err(Error::InvalidPacket)); + + assert_eq!(pipe.server.undecryptable_pkts.len(), 0); + + assert!(pipe.server.is_closed()); + } + #[test] /// Tests that a pre-v1 client can connect to a v1-enabled server, by making /// the server downgrade to the pre-v1 version. @@ -7655,7 +7724,7 @@ mod tests { assert_eq!( pipe.server.recv(&mut buf[..written]), - Err(Error::BufferTooShort) + Err(Error::InvalidPacket) ); assert!(pipe.server.is_closed()); -- cgit v1.2.3