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