Botan 3.12.0
Crypto and TLS for C&
tls_handshake_io.h
Go to the documentation of this file.
1/*
2* TLS Handshake Serialization
3* (C) 2012,2014 Jack Lloyd
4*
5* Botan is released under the Simplified BSD License (see license.txt)
6*/
7
8#ifndef BOTAN_TLS_HANDSHAKE_IO_H_
9#define BOTAN_TLS_HANDSHAKE_IO_H_
10
11#include <botan/tls_magic.h>
12#include <botan/tls_version.h>
13#include <deque>
14#include <functional>
15#include <map>
16#include <set>
17#include <utility>
18#include <vector>
19
20namespace Botan::TLS {
21
23
24/**
25* Handshake IO Interface
26*
27* This interface abstracts over stream and datagram processing of handshake
28* messages. It receives individual records from the channel via `add_record` and provides a
29* sending interface via a callback function provided by the channel.
30*
31* Handshake message headers are parsed and removed in `get_next_record`. The
32* result is provided back to the channel via
33* `Handshake_State::get_next_handshake_msg`.
34*
35* `send` is used by individual handshake message implementations, which send
36* themselves, as well as both client and server to dispatch CCS messaged (and
37* Hello_Verify_Request in the server case). Before calling the `writer_fn`,
38* `format` is called to add the handshake message header (except for CCS).
39*
40* The buffer returned by `send` is used to update the transcript record hash
41* (where desired).
42*/
44 public:
46
47 virtual std::vector<uint8_t> send(const Handshake_Message& msg) = 0;
48
49 virtual std::vector<uint8_t> send_under_epoch(const Handshake_Message& msg, uint16_t epoch) = 0;
50
51 virtual bool timeout_check() = 0;
52
53 virtual bool have_more_data() const = 0;
54
55 virtual std::vector<uint8_t> format(const std::vector<uint8_t>& handshake_msg,
56 Handshake_Type handshake_type) const = 0;
57
58 virtual void add_record(const uint8_t record[],
59 size_t record_len,
60 Record_Type type,
61 uint64_t sequence_number) = 0;
62
63 /**
64 * Returns (HANDSHAKE_NONE, std::vector<>()) if no message currently available
65 */
66 virtual std::pair<Handshake_Type, std::vector<uint8_t>> get_next_record(bool expecting_ccs,
67 size_t max_message_size) = 0;
68
69 Handshake_IO() = default;
70
71 Handshake_IO(const Handshake_IO&) = delete;
75
76 virtual ~Handshake_IO() = default;
77};
78
79/**
80* Handshake IO for stream-based handshakes
81*/
82class Stream_Handshake_IO final : public Handshake_IO {
83 public:
84 typedef std::function<void(Record_Type, const std::vector<uint8_t>&)> writer_fn;
85
86 explicit Stream_Handshake_IO(writer_fn writer) : m_send_hs(std::move(writer)) {}
87
89
90 bool timeout_check() override { return false; }
91
92 bool have_more_data() const override { return !m_queue.empty(); }
93
94 std::vector<uint8_t> send(const Handshake_Message& msg) override;
95
96 std::vector<uint8_t> send_under_epoch(const Handshake_Message& msg, uint16_t epoch) override;
97
98 std::vector<uint8_t> format(const std::vector<uint8_t>& handshake_msg,
99 Handshake_Type handshake_type) const override;
100
101 void add_record(const uint8_t record[], size_t record_len, Record_Type type, uint64_t sequence_number) override;
102
103 std::pair<Handshake_Type, std::vector<uint8_t>> get_next_record(bool expecting_ccs,
104 size_t max_message_size) override;
105
106 private:
107 std::deque<uint8_t> m_queue;
108 writer_fn m_send_hs;
109};
110
111/**
112* Handshake IO for datagram-based handshakes
113*/
115 public:
116 typedef std::function<void(uint16_t, Record_Type, const std::vector<uint8_t>&)> writer_fn;
117
120 uint16_t mtu,
121 uint64_t initial_timeout_ms,
122 uint64_t max_timeout_ms,
123 size_t max_handshake_msg_size) :
124 m_seqs(seq),
125 m_flights(1),
126 m_initial_timeout(initial_timeout_ms),
127 m_max_timeout(max_timeout_ms),
128 m_send_hs(std::move(writer)),
129 m_mtu(mtu),
130 m_max_handshake_msg_size(max_handshake_msg_size) {}
131
133
134 bool timeout_check() override;
135
136 bool have_more_data() const override;
137
138 std::vector<uint8_t> send(const Handshake_Message& msg) override;
139
140 std::vector<uint8_t> send_under_epoch(const Handshake_Message& msg, uint16_t epoch) override;
141
142 std::vector<uint8_t> format(const std::vector<uint8_t>& handshake_msg,
143 Handshake_Type handshake_type) const override;
144
145 void add_record(const uint8_t record[], size_t record_len, Record_Type type, uint64_t sequence_number) override;
146
147 std::pair<Handshake_Type, std::vector<uint8_t>> get_next_record(bool expecting_ccs,
148 size_t max_message_size) override;
149
150 private:
151 void retransmit_flight(size_t flight);
152 void retransmit_last_flight();
153
154 std::vector<uint8_t> format_fragment(const uint8_t fragment[],
155 size_t fragment_len,
156 uint32_t frag_offset,
157 uint32_t msg_len,
158 Handshake_Type type,
159 uint16_t msg_sequence) const;
160
161 std::vector<uint8_t> format_w_seq(const std::vector<uint8_t>& handshake_msg,
162 Handshake_Type handshake_type,
163 uint16_t msg_sequence) const;
164
165 std::vector<uint8_t> send_message(uint16_t msg_seq,
166 uint16_t epoch,
167 Handshake_Type msg_type,
168 const std::vector<uint8_t>& msg);
169
170 class Handshake_Reassembly final {
171 public:
172 void add_fragment(const uint8_t fragment[],
173 size_t fragment_length,
174 size_t fragment_offset,
175 uint16_t epoch,
176 Handshake_Type msg_type,
177 size_t msg_length);
178
179 bool complete() const;
180
181 uint16_t epoch() const { return m_epoch; }
182
183 // 0 until the first fragment has set the declared msg_length.
184 size_t msg_length() const { return m_msg_length; }
185
186 std::pair<Handshake_Type, std::vector<uint8_t>> message() const;
187
188 // Release the memory buffers; called after reassembly has completed
189 void release_buffers();
190
191 private:
193 size_t m_msg_length = 0;
194 size_t m_bytes_received = 0;
195 uint16_t m_epoch = 0;
196
197 // Reassembly buffer (sized to m_msg_length once known) and a parallel
198 // byte-mask marking which positions have already been seen.
199 std::vector<uint8_t> m_received_mask;
200 std::vector<uint8_t> m_message;
201 };
202
203 struct Message_Info final {
204 Message_Info(uint16_t e, Handshake_Type mt, const std::vector<uint8_t>& msg) :
205 epoch(e), msg_type(mt), msg_bits(msg) {}
206
207 Message_Info() : epoch(0xFFFF), msg_type(Handshake_Type::None) {}
208
209 uint16_t epoch; // NOLINT(*non-private-member-variable*)
210 Handshake_Type msg_type; // NOLINT(*non-private-member-variable*)
211 std::vector<uint8_t> msg_bits; // NOLINT(*non-private-member-variable*)
212 };
213
214 class Connection_Sequence_Numbers& m_seqs;
215 std::map<uint16_t, Handshake_Reassembly> m_messages;
216 size_t m_pending_reassembly_bytes = 0;
217 std::set<uint16_t> m_ccs_epochs;
218 std::vector<std::vector<uint16_t>> m_flights;
219 std::map<uint16_t, Message_Info> m_flight_data;
220
221 uint64_t m_initial_timeout = 0;
222 uint64_t m_max_timeout = 0;
223
224 uint64_t m_last_write = 0;
225 uint64_t m_next_timeout = 0;
226
227 uint16_t m_in_message_seq = 0;
228 uint16_t m_out_message_seq = 0;
229
230 writer_fn m_send_hs;
231 uint16_t m_mtu;
232 size_t m_max_handshake_msg_size;
233};
234
235} // namespace Botan::TLS
236
237#endif
std::vector< uint8_t > send_under_epoch(const Handshake_Message &msg, uint16_t epoch) override
std::pair< Handshake_Type, std::vector< uint8_t > > get_next_record(bool expecting_ccs, size_t max_message_size) override
void add_record(const uint8_t record[], size_t record_len, Record_Type type, uint64_t sequence_number) override
std::vector< uint8_t > format(const std::vector< uint8_t > &handshake_msg, Handshake_Type handshake_type) const override
Protocol_Version initial_record_version() const override
std::vector< uint8_t > send(const Handshake_Message &msg) override
Datagram_Handshake_IO(writer_fn writer, class Connection_Sequence_Numbers &seq, uint16_t mtu, uint64_t initial_timeout_ms, uint64_t max_timeout_ms, size_t max_handshake_msg_size)
std::function< void(uint16_t, Record_Type, const std::vector< uint8_t > &)> writer_fn
Handshake_IO & operator=(Handshake_IO &&)=delete
virtual std::vector< uint8_t > send_under_epoch(const Handshake_Message &msg, uint16_t epoch)=0
Handshake_IO(const Handshake_IO &)=delete
virtual bool timeout_check()=0
virtual std::vector< uint8_t > send(const Handshake_Message &msg)=0
virtual std::pair< Handshake_Type, std::vector< uint8_t > > get_next_record(bool expecting_ccs, size_t max_message_size)=0
Handshake_IO & operator=(const Handshake_IO &)=delete
virtual void add_record(const uint8_t record[], size_t record_len, Record_Type type, uint64_t sequence_number)=0
virtual Protocol_Version initial_record_version() const =0
Handshake_IO(Handshake_IO &&)=delete
virtual std::vector< uint8_t > format(const std::vector< uint8_t > &handshake_msg, Handshake_Type handshake_type) const =0
virtual ~Handshake_IO()=default
virtual bool have_more_data() const =0
bool have_more_data() const override
std::vector< uint8_t > send_under_epoch(const Handshake_Message &msg, uint16_t epoch) override
std::vector< uint8_t > format(const std::vector< uint8_t > &handshake_msg, Handshake_Type handshake_type) const override
Protocol_Version initial_record_version() const override
std::function< void(Record_Type, const std::vector< uint8_t > &)> writer_fn
std::vector< uint8_t > send(const Handshake_Message &msg) override
std::pair< Handshake_Type, std::vector< uint8_t > > get_next_record(bool expecting_ccs, size_t max_message_size) override
void add_record(const uint8_t record[], size_t record_len, Record_Type type, uint64_t sequence_number) override