Botan 3.11.0
Crypto and TLS for C&
tls_cipher_state.h
Go to the documentation of this file.
1/*
2* TLS cipher state implementation for TLS 1.3
3* (C) 2022 Jack Lloyd
4* 2022 Hannes Rantzsch, René Meusel - neXenio GmbH
5*
6* Botan is released under the Simplified BSD License (see license.txt)
7*/
8
9#ifndef BOTAN_TLS_CIPHER_STATE_H_
10#define BOTAN_TLS_CIPHER_STATE_H_
11
12#include <botan/secmem.h>
13#include <botan/tls_magic.h>
14
15#include <botan/internal/tls_transcript_hash_13.h>
16
17namespace Botan {
18
19class AEAD_Mode;
20class HashFunction;
21class HKDF_Extract;
22class HKDF_Expand;
23
24} // namespace Botan
25
26namespace Botan::TLS {
27
28class Ciphersuite;
29class Secret_Logger;
30
31/**
32 * This class implements the key schedule for TLS 1.3 as described in RFC 8446 7.1.
33 *
34 * Internally, it reflects the state machine pictured in the same RFC section.
35 * It provides the following entry points and state advancement methods that
36 * each facilitate certain cryptographic functionality:
37 *
38 * * init_with_psk()
39 * sets up the cipher state with a pre-shared key (out of band or via session
40 * ticket). will allow sending early data in the future
41 *
42 * * init_with_server_hello() / advance_with_server_hello()
43 * allows encrypting and decrypting handshake traffic, as well as producing
44 * and validating the client/server handshake finished MACs
45 *
46 * * advance_with_server_finished()
47 * allows encrypting and decrypting application traffic
48 *
49 * * advance_with_client_finished()
50 * allows negotiation of resumption PSKs
51 *
52 * While encrypting and decrypting records (RFC 8446 5.2) Cipher_State
53 * internally keeps track of the current sequence numbers (RFC 8446 5.3) to
54 * calculate the correct Per-Record Nonce. Sequence numbers are reset
55 * appropriately, whenever traffic secrets change.
56 *
57 * Handshake finished MAC calculation and verification is described in RFC 8446 4.4.4.
58 *
59 * PSKs calculation is described in RFC 8446 4.6.1.
60 */
62 public:
63 enum class PSK_Type : uint8_t {
64 Resumption,
65 External, // currently not implemented
66 };
67
68 public:
70
71 Cipher_State(const Cipher_State& other) = delete;
72 Cipher_State(Cipher_State&& other) = delete;
73 Cipher_State& operator=(const Cipher_State& other) = delete;
75
76 /**
77 * Construct a Cipher_State from a Pre-Shared-Key.
78 */
79 static std::unique_ptr<Cipher_State> init_with_psk(Connection_Side side,
80 PSK_Type type,
82 std::string_view prf_algo);
83
84 /**
85 * Construct a Cipher_State after receiving a server hello message.
86 */
87 static std::unique_ptr<Cipher_State> init_with_server_hello(Connection_Side side,
88 secure_vector<uint8_t>&& shared_secret,
89 const Ciphersuite& cipher,
90 const Transcript_Hash& transcript_hash,
91 const Secret_Logger& channel);
92
93 /**
94 * Transition internal secrets/keys for transporting early application data.
95 * Note that this state transition is legal only for handshakes using PSK.
96 */
97 void advance_with_client_hello(const Transcript_Hash& transcript_hash, const Secret_Logger& channel);
98
99 /**
100 * Transition internal secrets/keys for transporting handshake data.
101 */
102 void advance_with_server_hello(const Ciphersuite& cipher,
103 secure_vector<uint8_t>&& shared_secret,
104 const Transcript_Hash& transcript_hash,
105 const Secret_Logger& channel);
106
107 /**
108 * Transition internal secrets/keys for transporting application data.
109 */
110 void advance_with_server_finished(const Transcript_Hash& transcript_hash, const Secret_Logger& channel);
111
112 /**
113 * Transition to the final internal state allowing to create resumptions.
114 */
115 void advance_with_client_finished(const Transcript_Hash& transcript_hash);
116
117 /**
118 * Encrypt a TLS record fragment (RFC 8446 5.2 -- TLSInnerPlaintext) using the
119 * currently available traffic secret keys and the current sequence number.
120 * This will internally increment the sequence number. Hence, multiple
121 * calls with the same input will not produce the same result.
122 *
123 * @returns the sequence number of the encrypted record
124 */
125 uint64_t encrypt_record_fragment(const std::vector<uint8_t>& header, secure_vector<uint8_t>& fragment);
126
127 /**
128 * Decrypt a TLS record fragment (RFC 8446 5.2 -- TLSCiphertext.encrypted_record)
129 * using the currently available traffic secret keys and the current sequence number.
130 * This will internally increment the sequence number. Hence, multiple
131 * calls with the same input will not produce the same result.
132 *
133 * @returns the sequence number of the decrypted record
134 */
135 uint64_t decrypt_record_fragment(const std::vector<uint8_t>& header, secure_vector<uint8_t>& encrypted_fragment);
136
137 /**
138 * @returns number of bytes needed to encrypt \p input_length bytes
139 */
140 size_t encrypt_output_length(size_t input_length) const;
141
142 /**
143 * @returns number of bytes needed to decrypt \p input_length bytes
144 */
145 size_t decrypt_output_length(size_t input_length) const;
146
147 /**
148 * @returns the minimum ciphertext length for decryption
149 */
150 size_t minimum_decryption_input_length() const;
151
152 /**
153 * Calculates the MAC for a PSK binder value in Client Hellos. Note that
154 * the transcript hash passed into this method is computed from a partial
155 * Client Hello (RFC 8446 4.2.11.2)
156 */
157 std::vector<uint8_t> psk_binder_mac(const Transcript_Hash& transcript_hash_with_truncated_client_hello) const;
158
159 /**
160 * Calculate the MAC for a TLS "Finished" handshake message (RFC 8446 4.4.4)
161 */
162 std::vector<uint8_t> finished_mac(const Transcript_Hash& transcript_hash) const;
163
164 /**
165 * Validate a MAC received in a TLS "Finished" handshake message (RFC 8446 4.4.4)
166 */
167 bool verify_peer_finished_mac(const Transcript_Hash& transcript_hash, const std::vector<uint8_t>& peer_mac) const;
168
169 /**
170 * Calculate the PSK for the given nonce (RFC 8446 4.6.1)
171 */
172 secure_vector<uint8_t> psk(const Ticket_Nonce& nonce) const;
173
174 /**
175 * Generates a nonce value that is unique for any given Cipher_State object.
176 * Note that the number of nonces is limited to 2^16 and this method will
177 * throw if more nonces are requested.
178 */
180
181 /**
182 * Derive key material to export (RFC 8446 7.5 and RFC 5705)
183 *
184 * TODO: this does not yet support key export based on the `early_exporter_master_secret`.
185 *
186 * RFC 8446 7.5
187 * Implementations MUST use the exporter_master_secret unless explicitly
188 * specified by the application. The early_exporter_master_secret is
189 * defined for use in settings where an exporter is needed for 0-RTT data.
190 * A separate interface for the early exporter is RECOMMENDED [...].
191 *
192 * @param label a disambiguating label string
193 * @param context a per-association context value
194 * @param length the length of the desired key in bytes
195 * @return key of length bytes
196 */
197 secure_vector<uint8_t> export_key(std::string_view label, std::string_view context, size_t length) const;
198
199 /**
200 * Indicates whether the appropriate secrets to export keys are available
201 */
202 bool can_export_keys() const {
203 return (m_state == State::EarlyTraffic || m_state == State::ServerApplicationTraffic ||
204 m_state == State::Completed) &&
205 !m_exporter_master_secret.empty();
206 }
207
208 /**
209 * Indicates whether unprotected Alert records are to be expected
210 */
211 bool must_expect_unprotected_alert_traffic() const;
212
213 /**
214 * Indicates whether the appropriate secrets to encrypt application traffic are available
215 */
216 bool can_encrypt_application_traffic() const;
217
218 /**
219 * Indicates whether the appropriate secrets to decrypt application traffic are available
220 */
221 bool can_decrypt_application_traffic() const;
222
223 /**
224 * The name of the hash algorithm used for the KDF in this cipher suite
225 */
226 std::string hash_algorithm() const;
227
228 /**
229 * @returns true if the selected cipher primitives are compatible with
230 * the \p cipher suite.
231 *
232 * Note that cipher suites are considered "compatible" as long as the
233 * already selected cipher primitives in this cipher state are compatible.
234 */
235 bool is_compatible_with(const Ciphersuite& cipher) const;
236
237 /**
238 * Updates the key material used for decrypting data
239 * This is triggered after we received a Key_Update from the peer.
240 *
241 * Note that this must not be called before the connection is ready for
242 * application traffic.
243 */
244 void update_read_keys(const Secret_Logger& channel);
245
246 /**
247 * Updates the key material used for encrypting data
248 * This is triggered after we send a Key_Update to the peer.
249 *
250 * Note that this must not be called before the connection is ready for
251 * application traffic.
252 */
253 void update_write_keys(const Secret_Logger& channel);
254
255 /**
256 * Remove handshake/traffic secrets for decrypting data from peer
257 */
258 void clear_read_keys();
259
260 /**
261 * Remove handshake/traffic secrets for encrypting data
262 */
263 void clear_write_keys();
264
265 private:
266 /**
267 * @param whoami whether we play the Server or Client
268 * @param hash_function the negotiated hash function to be used
269 */
270 Cipher_State(Connection_Side whoami, std::string_view hash_function);
271
272 void advance_with_psk(PSK_Type type, secure_vector<uint8_t>&& psk);
273 void advance_without_psk();
274
275 void derive_write_traffic_key(const secure_vector<uint8_t>& traffic_secret,
276 bool handshake_traffic_secret = false);
277 void derive_read_traffic_key(const secure_vector<uint8_t>& traffic_secret, bool handshake_traffic_secret = false);
278
279 /**
280 * HKDF-Extract from RFC 8446 7.1
281 */
282 secure_vector<uint8_t> hkdf_extract(std::span<const uint8_t> ikm) const;
283
284 /**
285 * HKDF-Expand-Label from RFC 8446 7.1
286 */
288 std::string_view label,
289 const std::vector<uint8_t>& context,
290 size_t length) const;
291
292 /**
293 * Derive-Secret from RFC 8446 7.1
294 */
295 secure_vector<uint8_t> derive_secret(const secure_vector<uint8_t>& secret,
296 std::string_view label,
297 const Transcript_Hash& messages_hash) const;
298
299 std::vector<uint8_t> empty_hash() const;
300
301 private:
302 enum class State : uint8_t {
303 Uninitialized,
304 PskBinder,
305 EarlyTraffic,
306 HandshakeTraffic,
307 ServerApplicationTraffic,
308 Completed
309 };
310
311 private:
312 State m_state;
313 Connection_Side m_connection_side;
314
315 std::unique_ptr<AEAD_Mode> m_encrypt;
316 std::unique_ptr<AEAD_Mode> m_decrypt;
317
318 std::unique_ptr<HKDF_Extract> m_extract;
319 std::unique_ptr<HKDF_Expand> m_expand;
320 std::unique_ptr<HashFunction> m_hash;
321
323
324 secure_vector<uint8_t> m_write_application_traffic_secret;
325 secure_vector<uint8_t> m_read_application_traffic_secret;
326
327 secure_vector<uint8_t> m_write_key;
328 secure_vector<uint8_t> m_write_iv;
329 secure_vector<uint8_t> m_read_key;
330 secure_vector<uint8_t> m_read_iv;
331
332 uint64_t m_write_seq_no;
333 uint64_t m_read_seq_no;
334
335 uint32_t m_write_key_update_count;
336 uint32_t m_read_key_update_count;
337
338 uint16_t m_ticket_nonce;
339
340 secure_vector<uint8_t> m_finished_key;
341 secure_vector<uint8_t> m_peer_finished_key;
342 secure_vector<uint8_t> m_exporter_master_secret;
343 secure_vector<uint8_t> m_resumption_master_secret;
344
345 secure_vector<uint8_t> m_early_secret;
346 secure_vector<uint8_t> m_binder_key;
347};
348
349} // namespace Botan::TLS
350
351#endif // BOTAN_TLS_CIPHER_STATE_H_
#define BOTAN_TEST_API
Definition api.h:41
static std::unique_ptr< Cipher_State > init_with_server_hello(Connection_Side side, secure_vector< uint8_t > &&shared_secret, const Ciphersuite &cipher, const Transcript_Hash &transcript_hash, const Secret_Logger &channel)
uint64_t decrypt_record_fragment(const std::vector< uint8_t > &header, secure_vector< uint8_t > &encrypted_fragment)
Cipher_State & operator=(Cipher_State &&other)=delete
size_t minimum_decryption_input_length() const
void advance_with_client_finished(const Transcript_Hash &transcript_hash)
bool verify_peer_finished_mac(const Transcript_Hash &transcript_hash, const std::vector< uint8_t > &peer_mac) const
static std::unique_ptr< Cipher_State > init_with_psk(Connection_Side side, PSK_Type type, secure_vector< uint8_t > &&psk, std::string_view prf_algo)
uint64_t encrypt_record_fragment(const std::vector< uint8_t > &header, secure_vector< uint8_t > &fragment)
void advance_with_client_hello(const Transcript_Hash &transcript_hash, const Secret_Logger &channel)
void advance_with_server_finished(const Transcript_Hash &transcript_hash, const Secret_Logger &channel)
Cipher_State(const Cipher_State &other)=delete
secure_vector< uint8_t > psk(const Ticket_Nonce &nonce) const
void advance_with_server_hello(const Ciphersuite &cipher, secure_vector< uint8_t > &&shared_secret, const Transcript_Hash &transcript_hash, const Secret_Logger &channel)
secure_vector< uint8_t > export_key(std::string_view label, std::string_view context, size_t length) const
Cipher_State(Cipher_State &&other)=delete
size_t encrypt_output_length(size_t input_length) const
std::vector< uint8_t > psk_binder_mac(const Transcript_Hash &transcript_hash_with_truncated_client_hello) const
size_t decrypt_output_length(size_t input_length) const
Cipher_State & operator=(const Cipher_State &other)=delete
std::vector< uint8_t > finished_mac(const Transcript_Hash &transcript_hash) const
std::vector< uint8_t > Transcript_Hash
Definition tls_magic.h:93
Strong< std::vector< uint8_t >, struct Ticket_Nonce_ > Ticket_Nonce
Used to derive the ticket's PSK from the resumption_master_secret.
Definition tls_magic.h:96
secure_vector< uint8_t > hkdf_expand_label(std::string_view hash_fn, std::span< const uint8_t > secret, std::string_view label, std::span< const uint8_t > hash_val, size_t length)
Definition hkdf.cpp:119
std::vector< T, secure_allocator< T > > secure_vector
Definition secmem.h:68