Botan 3.12.0
Crypto and TLS for C&
tls_handshake_layer_13.cpp
Go to the documentation of this file.
1/*
2* TLS handshake state (machine) 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#include <botan/internal/tls_handshake_layer_13.h>
10
11#include <botan/tls_alert.h>
12#include <botan/tls_exceptn.h>
13#include <botan/tls_policy.h>
14#include <botan/internal/concat_util.h>
15#include <botan/internal/fmt.h>
16#include <botan/internal/stl_util.h>
17#include <botan/internal/tls_reader.h>
18#include <botan/internal/tls_transcript_hash_13.h>
19
20namespace Botan::TLS {
21
22void Handshake_Layer::copy_data(std::span<const uint8_t> data_from_peer) {
23 // Compact consumed data before appending new data
24 BOTAN_ASSERT_NOMSG(m_read_offset <= m_read_buffer.size());
25 if(m_read_offset > 0) {
26 m_read_buffer.erase(m_read_buffer.begin(), m_read_buffer.begin() + m_read_offset);
27 m_read_offset = 0;
28 }
29
30 m_read_buffer.insert(m_read_buffer.end(), data_from_peer.begin(), data_from_peer.end());
31}
32
33namespace {
34
35constexpr size_t HEADER_LENGTH = 4;
36
37template <typename Msg_Type>
38Handshake_Type handshake_type_from_byte(uint8_t byte_value) {
39 const auto type = static_cast<Handshake_Type>(byte_value);
40
41 if constexpr(std::is_same_v<Msg_Type, Handshake_Message_13>) {
42 switch(type) {
45 // case Handshake_Type::EndOfEarlyData: // NYI: needs PSK/resumption support -- won't be offered in Client Hello for now
51 return type;
52 default:
53 throw TLS_Exception(AlertType::UnexpectedMessage, "Unknown handshake message received");
54 }
55 } else {
56 switch(type) {
59 // case Handshake_Type::CertificateRequest: // NYI: post-handshake client auth (RFC 8446 4.6.2) -- won't be offered in Client Hello for now
60 return type;
61 default:
62 throw TLS_Exception(AlertType::UnexpectedMessage, "Unknown post-handshake message received");
63 }
64 }
65}
66
67void verify_handshake_message_size(size_t msg_len, size_t max_size) {
68 if(max_size > 0 && msg_len > max_size) {
69 throw TLS_Exception(Alert::HandshakeFailure,
70 Botan::fmt("Handshake message is {} bytes, policy maximum is {}", msg_len, max_size));
71 }
72}
73
74template <typename Msg_Type>
75std::optional<Msg_Type> parse_message(TLS::TLS_Data_Reader& reader,
76 const Policy& policy,
77 const Connection_Side peer_side,
78 const Certificate_Type cert_type) {
79 // read the message header
80 if(reader.remaining_bytes() < HEADER_LENGTH) {
81 return std::nullopt;
82 }
83
84 const Handshake_Type type = handshake_type_from_byte<Msg_Type>(reader.get_byte());
85
86 // make sure we have received the full message
87 const size_t msg_len = reader.get_uint24_t();
88
89 // TODO(Botan4) this is split out due to a GCC 11 ICE, can be inlined
90 verify_handshake_message_size(msg_len, policy.maximum_handshake_message_size());
91
92 if(reader.remaining_bytes() < msg_len) {
93 return std::nullopt;
94 }
95
96 // create the message
97 const auto msg = reader.get_fixed<uint8_t>(msg_len);
98 if constexpr(std::is_same_v<Msg_Type, Handshake_Message_13>) {
99 switch(type) {
100 // Client Hello and Server Hello messages are ambiguous. Both may come
101 // from non-TLS 1.3 peers. Hence, their parsing is somewhat different.
103 // ... might be TLS 1.2 Client Hello or TLS 1.3 Client Hello
106 // ... might be TLS 1.2 Server Hello or TLS 1.3 Server Hello or
107 // a TLS 1.3 Hello Retry Request disguising as a Server Hello
109 // case Handshake_Type::EndOfEarlyData:
110 // return End_Of_Early_Data(msg);
112 return Encrypted_Extensions(msg);
114 return Certificate_13(msg, policy, peer_side, cert_type);
116 return Certificate_Request_13(msg, peer_side);
118 return Certificate_Verify_13(msg, peer_side);
120 return Finished_13(msg);
121 default:
122 BOTAN_ASSERT(false, "cannot be reached"); // make sure to update handshake_type_from_byte
123 }
124 } else {
125 BOTAN_UNUSED(peer_side);
126
127 switch(type) {
129 return New_Session_Ticket_13(msg, peer_side);
131 return Key_Update(msg);
132 default:
133 BOTAN_ASSERT(false, "cannot be reached"); // make sure to update handshake_type_from_byte
134 }
135 }
136}
137
138} // namespace
139
140std::optional<Handshake_Message_13> Handshake_Layer::next_message(const Policy& policy,
141 Transcript_Hash_State& transcript_hash) {
142 BOTAN_ASSERT_NOMSG(m_read_offset <= m_read_buffer.size());
143 auto pending = std::span<const uint8_t>{m_read_buffer}.subspan(m_read_offset);
144 TLS::TLS_Data_Reader reader("handshake message", pending);
145
146 auto msg = parse_message<Handshake_Message_13>(reader, policy, m_peer, m_certificate_type);
147 if(msg.has_value()) {
148 transcript_hash.update(pending.first(reader.read_so_far()));
149 m_read_offset += reader.read_so_far();
150 BOTAN_ASSERT_NOMSG(m_read_offset <= m_read_buffer.size());
151
152 if(m_read_offset == m_read_buffer.size()) {
153 m_read_buffer.clear();
154 m_read_offset = 0;
155 }
156 }
157
158 return msg;
159}
160
161std::optional<Post_Handshake_Message_13> Handshake_Layer::next_post_handshake_message(const Policy& policy) {
162 BOTAN_ASSERT_NOMSG(m_read_offset <= m_read_buffer.size());
163 auto pending = std::span<const uint8_t>{m_read_buffer}.subspan(m_read_offset);
164 TLS::TLS_Data_Reader reader("post handshake message", pending);
165
166 auto msg = parse_message<Post_Handshake_Message_13>(reader, policy, m_peer, m_certificate_type);
167 if(msg.has_value()) {
168 m_read_offset += reader.read_so_far();
169 BOTAN_ASSERT_NOMSG(m_read_offset <= m_read_buffer.size());
170
171 if(m_read_offset == m_read_buffer.size()) {
172 m_read_buffer.clear();
173 m_read_offset = 0;
174 }
175 }
176
177 return msg;
178}
179
180namespace {
181
182template <typename T>
183const T& get(const std::reference_wrapper<T>& v) {
184 return v.get();
185}
186
187template <typename T>
188const T& get(const T& v) {
189 // NOLINTNEXTLINE(bugprone-return-const-ref-from-parameter)
190 return v;
191}
192
193template <typename T>
194std::vector<uint8_t> marshall_message(const T& message) {
195 auto [type, serialized] =
196 std::visit([](const auto& msg) { return std::pair(get(msg).wire_type(), get(msg).serialize()); }, message);
197
198 BOTAN_ASSERT_NOMSG(serialized.size() <= 0xFFFFFF);
199 const uint32_t msg_size = static_cast<uint32_t>(serialized.size());
200
201 std::vector<uint8_t> header{
202 static_cast<uint8_t>(type), get_byte<1>(msg_size), get_byte<2>(msg_size), get_byte<3>(msg_size)};
203
204 return concat(header, serialized);
205}
206
207} //namespace
208
210 Transcript_Hash_State& transcript_hash) {
211 auto msg = marshall_message(message);
212 transcript_hash.update(msg);
213 return msg;
214}
215
217 return marshall_message(message);
218}
219
220} // namespace Botan::TLS
#define BOTAN_UNUSED
Definition assert.h:144
#define BOTAN_ASSERT_NOMSG(expr)
Definition assert.h:75
#define BOTAN_ASSERT(expr, assertion_made)
Definition assert.h:62
static std::variant< Client_Hello_13, Client_Hello_12_Shim > parse(const std::vector< uint8_t > &buf)
static std::vector< uint8_t > prepare_message(Handshake_Message_13_Ref message, Transcript_Hash_State &transcript_hash)
std::optional< Handshake_Message_13 > next_message(const Policy &policy, Transcript_Hash_State &transcript_hash)
std::optional< Post_Handshake_Message_13 > next_post_handshake_message(const Policy &policy)
static std::vector< uint8_t > prepare_post_handshake_message(const Post_Handshake_Message_13 &message)
void copy_data(std::span< const uint8_t > data_from_peer)
static std::variant< Hello_Retry_Request, Server_Hello_13, Server_Hello_12_Shim > parse(const std::vector< uint8_t > &buf)
size_t read_so_far() const
Definition tls_reader.h:35
void update(std::span< const uint8_t > serialized_message_s)
detail::as_wrapped_references_t< Handshake_Message_13 > Handshake_Message_13_Ref
std::variant< New_Session_Ticket_13, Key_Update > Post_Handshake_Message_13
constexpr uint8_t get_byte(T input)
Definition loadstor.h:79
std::string fmt(std::string_view format, const T &... args)
Definition fmt.h:53
constexpr auto concat(Rs &&... ranges)
Definition concat_util.h:90
constexpr GeneralVariantT generalize_to(SpecialT &&specific)
Converts a given variant into another variant-ish whose type states are a super set of the given vari...
Definition stl_util.h:88