/src/botan/build/include/botan/internal/tls_channel_impl.h
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * TLS Channel |
3 | | * (C) 2011,2012,2014,2015 Jack Lloyd |
4 | | * 2016 Matthias Gierlings |
5 | | * 2021 Elektrobit Automotive GmbH |
6 | | * 2022 René Meusel, Hannes Rantzsch - neXenio GmbH |
7 | | * |
8 | | * Botan is released under the Simplified BSD License (see license.txt) |
9 | | */ |
10 | | |
11 | | #ifndef BOTAN_TLS_CHANNEL_IMPL_H_ |
12 | | #define BOTAN_TLS_CHANNEL_IMPL_H_ |
13 | | |
14 | | #include <botan/tls_channel.h> |
15 | | #include <botan/tls_version.h> |
16 | | #include <botan/tls_magic.h> |
17 | | |
18 | | #include <vector> |
19 | | #include <memory> |
20 | | #include <utility> |
21 | | |
22 | | namespace Botan { |
23 | | |
24 | | class Credentials_Manager; |
25 | | class X509_Certificate; |
26 | | |
27 | | namespace TLS { |
28 | | |
29 | | class Client; |
30 | | class Server; |
31 | | |
32 | | class Channel_Impl |
33 | | { |
34 | | public: |
35 | 13.1k | virtual ~Channel_Impl() = default; |
36 | | |
37 | | /** |
38 | | * Inject TLS traffic received from counterparty |
39 | | * @return a hint as the how many more bytes we need to q the |
40 | | * current record (this may be 0 if on a record boundary) |
41 | | */ |
42 | | virtual size_t from_peer(std::span<const uint8_t> data) = 0; |
43 | | |
44 | | /** |
45 | | * Inject plaintext intended for counterparty |
46 | | * Throws an exception if is_active() is false |
47 | | */ |
48 | | virtual void to_peer(std::span<const uint8_t> data) = 0; |
49 | | |
50 | | /** |
51 | | * Send a TLS alert message. If the alert is fatal, the internal |
52 | | * state (keys, etc) will be reset. |
53 | | * @param alert the Alert to send |
54 | | */ |
55 | | virtual void send_alert(const Alert& alert) = 0; |
56 | | |
57 | | /** |
58 | | * Send a warning alert |
59 | | */ |
60 | 627 | void send_warning_alert(Alert::Type type) { send_alert(Alert(type, false)); } |
61 | | |
62 | | /** |
63 | | * Send a fatal alert |
64 | | */ |
65 | 11.7k | void send_fatal_alert(Alert::Type type) { send_alert(Alert(type, true)); } |
66 | | |
67 | | /** |
68 | | * Send a close notification alert |
69 | | */ |
70 | 0 | void close() { send_warning_alert(Alert::CloseNotify); } |
71 | | |
72 | | /** |
73 | | * @return true iff the connection is active for sending application data |
74 | | */ |
75 | | virtual bool is_active() const = 0; |
76 | | |
77 | | /** |
78 | | * @return true iff the connection has been definitely closed |
79 | | */ |
80 | | virtual bool is_closed() const = 0; |
81 | | |
82 | | /** |
83 | | * @return true iff the connection is active for sending application data |
84 | | */ |
85 | | virtual bool is_closed_for_reading() const = 0; |
86 | | |
87 | | /** |
88 | | * @return true iff the connection has been definitely closed |
89 | | */ |
90 | | virtual bool is_closed_for_writing() const = 0; |
91 | | |
92 | | /** |
93 | | * @return certificate chain of the peer (may be empty) |
94 | | */ |
95 | | virtual std::vector<X509_Certificate> peer_cert_chain() const = 0; |
96 | | |
97 | | /** |
98 | | * Key material export (RFC 5705) |
99 | | * @param label a disambiguating label string |
100 | | * @param context a per-association context value |
101 | | * @param length the length of the desired key in bytes |
102 | | * @return key of length bytes |
103 | | */ |
104 | | virtual SymmetricKey key_material_export(const std::string& label, |
105 | | const std::string& context, |
106 | | size_t length) const = 0; |
107 | | |
108 | | /** |
109 | | * Attempt to renegotiate the session |
110 | | * @param force_full_renegotiation if true, require a full renegotiation, |
111 | | * otherwise allow session resumption |
112 | | */ |
113 | | virtual void renegotiate(bool force_full_renegotiation = false) = 0; |
114 | | |
115 | | /** |
116 | | * @return true if this channel can issue TLS 1.3 style session tickets. |
117 | | */ |
118 | 0 | virtual bool new_session_ticket_supported() const { return false; } |
119 | | |
120 | | /** |
121 | | * Send @p tickets new session tickets to the peer. This is only supported |
122 | | * on TLS 1.3 servers. |
123 | | * |
124 | | * If the server's Session_Manager does not accept the generated Session |
125 | | * objects, the server implementation won't be able to send new tickets. |
126 | | * Additionally, anything but TLS 1.3 servers will return 0 (because they |
127 | | * don't support sending such session tickets). |
128 | | * |
129 | | * @returns the number of session tickets successfully sent to the client |
130 | | */ |
131 | 0 | virtual size_t send_new_session_tickets(const size_t /* tickets */) { return 0; } |
132 | | |
133 | | /** |
134 | | * Attempt to update the session's traffic key material |
135 | | * Note that this is possible with a TLS 1.3 channel, only. |
136 | | * |
137 | | * @param request_peer_update if true, require a reciprocal key update |
138 | | */ |
139 | | virtual void update_traffic_keys(bool request_peer_update = false) = 0; |
140 | | |
141 | | /** |
142 | | * @return true iff the counterparty supports the secure |
143 | | * renegotiation extensions. |
144 | | */ |
145 | | virtual bool secure_renegotiation_supported() const = 0; |
146 | | |
147 | | /** |
148 | | * Perform a handshake timeout check. This does nothing unless |
149 | | * this is a DTLS channel with a pending handshake state, in |
150 | | * which case we check for timeout and potentially retransmit |
151 | | * handshake packets. |
152 | | */ |
153 | | virtual bool timeout_check() = 0; |
154 | | |
155 | | /** |
156 | | * Return the protocol notification set for this connection, if any (ALPN). |
157 | | * This value is not tied to the session and a later renegotiation of the |
158 | | * same session can choose a new protocol. |
159 | | */ |
160 | | virtual std::string application_protocol() const = 0; |
161 | | |
162 | | protected: |
163 | | /** |
164 | | * This struct collect all information required to perform a downgrade from TLS 1.3 to TLS 1.2. |
165 | | * |
166 | | * The downgrade process is (currently) triggered when a TLS 1.3 client receives a downgrade request |
167 | | * in the server hello message (@sa `Client_Impl_13::handle(Server_Hello_12)`). As a result, |
168 | | * `Client::received_data` should detect this condition and replace its `Channel_Impl_13` member by a |
169 | | * `Channel_Impl_12`. |
170 | | * |
171 | | * Note that the downgrade process for the server implementation will likely differ. |
172 | | */ |
173 | | struct Downgrade_Information |
174 | | { |
175 | | /// The client hello message including the handshake header bytes as transferred to the peer. |
176 | | std::vector<uint8_t> client_hello_message; |
177 | | |
178 | | /// The full data transcript received from the peer. This will contain the server hello message that forced us to downgrade. |
179 | | std::vector<uint8_t> peer_transcript; |
180 | | |
181 | | /// The TLS 1.2 session information found by a TLS 1.3 client that |
182 | | /// caused it to initiate a downgrade before even sending a client hello. |
183 | | std::optional<Session_with_Handle> tls12_session; |
184 | | |
185 | | Server_Information server_info; |
186 | | std::vector<std::string> next_protocols; |
187 | | size_t io_buffer_size; |
188 | | |
189 | | std::shared_ptr<Callbacks> callbacks; |
190 | | std::shared_ptr<Session_Manager> session_manager; |
191 | | std::shared_ptr<Credentials_Manager> creds; |
192 | | std::shared_ptr<RandomNumberGenerator> rng; |
193 | | std::shared_ptr<const Policy> policy; |
194 | | |
195 | | bool received_tls_13_error_alert; |
196 | | bool will_downgrade; |
197 | | }; |
198 | | |
199 | | std::unique_ptr<Downgrade_Information> m_downgrade_info; |
200 | | |
201 | | void preserve_peer_transcript(std::span<const uint8_t> input) |
202 | 0 | { |
203 | 0 | BOTAN_STATE_CHECK(m_downgrade_info); |
204 | 0 | m_downgrade_info->peer_transcript.insert(m_downgrade_info->peer_transcript.end(), |
205 | 0 | input.begin(), input.end()); |
206 | 0 | } |
207 | | |
208 | | void preserve_client_hello(std::span<const uint8_t> msg) |
209 | 0 | { |
210 | 0 | BOTAN_STATE_CHECK(m_downgrade_info); |
211 | 0 | m_downgrade_info->client_hello_message.assign(msg.begin(), msg.end()); |
212 | 0 | } |
213 | | |
214 | | friend class Client; |
215 | | friend class Server; |
216 | | void set_io_buffer_size(size_t io_buf_sz) |
217 | 0 | { |
218 | 0 | BOTAN_STATE_CHECK(m_downgrade_info); |
219 | 0 | m_downgrade_info->io_buffer_size = io_buf_sz; |
220 | 0 | } |
221 | | |
222 | | /** |
223 | | * Implementations use this to signal that the peer indicated a protocol |
224 | | * version downgrade. After calling `request_downgrade()` no further |
225 | | * state changes must be perfomed by the implementation. Particularly, no |
226 | | * further handshake messages must be emitted. Instead, they must yield |
227 | | * control flow back to the underlying Channel implementation to perform |
228 | | * the protocol version downgrade. |
229 | | */ |
230 | | void request_downgrade() |
231 | 0 | { |
232 | 0 | BOTAN_STATE_CHECK(m_downgrade_info && !m_downgrade_info->will_downgrade); |
233 | 0 | m_downgrade_info->will_downgrade = true; |
234 | 0 | } |
235 | | |
236 | | void request_downgrade_for_resumption(Session_with_Handle session) |
237 | 0 | { |
238 | 0 | BOTAN_STATE_CHECK(m_downgrade_info && |
239 | 0 | m_downgrade_info->client_hello_message.empty() && |
240 | 0 | m_downgrade_info->peer_transcript.empty() && |
241 | 0 | !m_downgrade_info->tls12_session.has_value()); |
242 | 0 | BOTAN_ASSERT_NOMSG(session.session.version().is_pre_tls_13()); |
243 | 0 | m_downgrade_info->tls12_session = std::move(session); |
244 | 0 | request_downgrade(); |
245 | 0 | } |
246 | | |
247 | | public: |
248 | | /** |
249 | | * Indicates whether a downgrade to TLS 1.2 or lower is in progress |
250 | | * |
251 | | * @sa Downgrade_Information |
252 | | */ |
253 | 1.48k | bool is_downgrading() const { return m_downgrade_info && m_downgrade_info->will_downgrade; } |
254 | | |
255 | | /** |
256 | | * @sa Downgrade_Information |
257 | | */ |
258 | 0 | std::unique_ptr<Downgrade_Information> extract_downgrade_info() { return std::exchange(m_downgrade_info, {}); } |
259 | | |
260 | 0 | bool expects_downgrade() const { return m_downgrade_info != nullptr; } |
261 | | }; |
262 | | |
263 | | } |
264 | | |
265 | | } |
266 | | |
267 | | #endif |