send CONNECTION_CLOSE on epoch the peer can decrypt
Currently, during handshake, CONNECTION_CLOSE frames are sent in packets
of the highest epoch level the local endpoint can use. However there is
no guarantee that the peer can actually decrypt packets of that epoch.
Instead, track the highest level the peer has used, and use that level
to send errors, this way the peer is most likely to be able to decrypt
the packet.
diff --git a/src/lib.rs b/src/lib.rs
index 80dcd02..5291ac5 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -894,6 +894,10 @@
/// Peer's flow control limit for the connection.
max_tx_data: u64,
+ /// The highest epoch level that the peer is guaranteed to be able to
+ /// receive.
+ tx_epoch: usize,
+
/// Total number of bytes the server can send before the peer's address
/// is verified.
max_send_bytes: usize,
@@ -1248,6 +1252,8 @@
tx_data: 0,
max_tx_data: 0,
+ tx_epoch: packet::EPOCH_INITIAL,
+
max_send_bytes: 0,
streams: stream::StreamMap::new(
@@ -1816,6 +1822,10 @@
return Err(Error::Done);
}
+ // Packet was successfully decrypted, so assume peer can read packets
+ // of epochs up to the current packet's.
+ self.tx_epoch = cmp::max(self.tx_epoch, epoch);
+
if !self.is_server && !self.got_peer_conn_id {
if self.odcid.is_none() {
self.odcid = Some(self.dcid.clone());
@@ -3899,12 +3909,7 @@
// On error send packet in the latest epoch available, but only send
// 1-RTT ones when the handshake is completed.
if self.error.is_some() {
- let epoch = match self.handshake.lock().unwrap().write_level() {
- crypto::Level::Initial => packet::EPOCH_INITIAL,
- crypto::Level::ZeroRTT => unreachable!(),
- crypto::Level::Handshake => packet::EPOCH_HANDSHAKE,
- crypto::Level::OneRTT => packet::EPOCH_APPLICATION,
- };
+ let epoch = self.tx_epoch;
if epoch == packet::EPOCH_APPLICATION && !self.is_established() {
// Downgrade the epoch to handshake as the handshake is not
diff --git a/src/tls.rs b/src/tls.rs
index 57ebd2f..f149d44 100644
--- a/src/tls.rs
+++ b/src/tls.rs
@@ -455,10 +455,6 @@
map_result_ssl(self, unsafe { SSL_do_handshake(self.as_ptr()) })
}
- pub fn write_level(&self) -> crypto::Level {
- unsafe { SSL_quic_write_level(self.as_ptr()) }
- }
-
pub fn cipher(&self) -> Option<crypto::Algorithm> {
let cipher =
map_result_ptr(unsafe { SSL_get_current_cipher(self.as_ptr()) });
@@ -999,8 +995,6 @@
fn SSL_do_handshake(ssl: *mut SSL) -> c_int;
- fn SSL_quic_write_level(ssl: *mut SSL) -> crypto::Level;
-
fn SSL_session_reused(ssl: *mut SSL) -> c_int;
fn SSL_in_init(ssl: *mut SSL) -> c_int;