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}