s2n_quic_core/connection/
close.rs

1// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2// SPDX-License-Identifier: Apache-2.0
3
4use crate::{application, crypto::tls, transport};
5pub use crate::{frame::ConnectionClose, inet::SocketAddress};
6
7/// Provides a hook for applications to rewrite CONNECTION_CLOSE frames
8///
9/// Implementations should take care to not leak potentially sensitive information
10/// to peers. This includes removing `reason` fields and making error codes more general.
11pub trait Formatter: 'static + Send {
12    /// Formats a transport error for use in 1-RTT (application data) packets
13    fn format_transport_error(
14        &self,
15        context: &Context,
16        error: transport::Error,
17    ) -> ConnectionClose<'_>;
18
19    /// Formats an application error for use in 1-RTT (application data) packets
20    fn format_application_error(
21        &self,
22        context: &Context,
23        error: application::Error,
24    ) -> ConnectionClose<'_>;
25
26    /// Formats a transport error for use in early (initial, handshake) packets
27    fn format_early_transport_error(
28        &self,
29        context: &Context,
30        error: transport::Error,
31    ) -> ConnectionClose<'_>;
32
33    /// Formats an application error for use in early (initial, handshake) packets
34    fn format_early_application_error(
35        &self,
36        context: &Context,
37        error: application::Error,
38    ) -> ConnectionClose<'_>;
39}
40
41#[non_exhaustive]
42#[derive(Debug)]
43pub struct Context<'a> {
44    pub remote_address: &'a SocketAddress,
45}
46
47impl<'a> Context<'a> {
48    pub fn new(remote_address: &'a SocketAddress) -> Self {
49        Self { remote_address }
50    }
51}
52
53/// A formatter that passes errors through, unmodified
54///
55/// WARNING: This formatter should only be used in application development,
56///          as it can leak potentially sensitive information to the peer.
57#[derive(Clone, Copy, Debug, Default)]
58pub struct Development;
59
60impl Formatter for Development {
61    fn format_transport_error(
62        &self,
63        _context: &Context,
64        error: transport::Error,
65    ) -> ConnectionClose<'_> {
66        error.into()
67    }
68
69    fn format_application_error(
70        &self,
71        _context: &Context,
72        error: application::Error,
73    ) -> ConnectionClose<'_> {
74        error.into()
75    }
76
77    fn format_early_transport_error(
78        &self,
79        _context: &Context,
80        error: transport::Error,
81    ) -> ConnectionClose<'_> {
82        error.into()
83    }
84
85    fn format_early_application_error(
86        &self,
87        _context: &Context,
88        error: application::Error,
89    ) -> ConnectionClose<'_> {
90        error.into()
91    }
92}
93
94/// A formatter that removes potentially sensitive information
95///
96/// The following is performed:
97///
98/// * Reasons and frame_types are hidden
99/// * INTERNAL_ERROR is transformed into PROTOCOL_VIOLATION
100/// * Application codes are hidden in early (initial, handshake) packets
101/// * Crypto (TLS) alerts are transformed into HANDSHAKE_FAILURE
102#[derive(Clone, Copy, Debug, Default)]
103pub struct Production;
104
105impl Formatter for Production {
106    fn format_transport_error(
107        &self,
108        _context: &Context,
109        error: transport::Error,
110    ) -> ConnectionClose<'_> {
111        // rewrite internal errors as PROTOCOL_VIOLATION
112        if error.code == transport::Error::INTERNAL_ERROR.code {
113            return transport::Error::PROTOCOL_VIOLATION.into();
114        }
115
116        //= https://www.rfc-editor.org/rfc/rfc9001#section-4.8
117        //# QUIC permits the use of a generic code in place of a specific error
118        //# code; see Section 11 of [QUIC-TRANSPORT].  For TLS alerts, this
119        //# includes replacing any alert with a generic alert, such as
120        //# handshake_failure (0x0128 in QUIC).  Endpoints MAY use a generic
121        //# error code to avoid possibly exposing confidential information.
122        if error.try_into_tls_error().is_some() {
123            return transport::Error::from(tls::Error::HANDSHAKE_FAILURE).into();
124        }
125
126        // only preserve the error code
127        transport::Error::new(error.code.as_varint()).into()
128    }
129
130    fn format_application_error(
131        &self,
132        _context: &Context,
133        error: application::Error,
134    ) -> ConnectionClose<'_> {
135        error.into()
136    }
137
138    fn format_early_transport_error(
139        &self,
140        context: &Context,
141        error: transport::Error,
142    ) -> ConnectionClose<'_> {
143        Self.format_transport_error(context, error)
144    }
145
146    fn format_early_application_error(
147        &self,
148        _context: &Context,
149        _error: application::Error,
150    ) -> ConnectionClose<'_> {
151        //= https://www.rfc-editor.org/rfc/rfc9000#section-10.2.3
152        //# Sending a CONNECTION_CLOSE of type 0x1d in an Initial or Handshake
153        //# packet could expose application state or be used to alter application
154        //# state.  A CONNECTION_CLOSE of type 0x1d MUST be replaced by a
155        //# CONNECTION_CLOSE of type 0x1c when sending the frame in Initial or
156        //# Handshake packets.  Otherwise, information about the application
157        //# state might be revealed.  Endpoints MUST clear the value of the
158        //# Reason Phrase field and SHOULD use the APPLICATION_ERROR code when
159        //# converting to a CONNECTION_CLOSE of type 0x1c.
160
161        transport::Error::APPLICATION_ERROR.into()
162    }
163}