Botan 3.13.0
Crypto and TLS for C&
Botan::TLS::Extensions Class Referencefinal

#include <tls_extensions.h>

Public Member Functions

void add (Extension *extn)
void add (std::unique_ptr< Extension > extn)
bool contains_implemented_extensions_other_than (const std::set< Extension_Code > &allowed_extensions) const
bool contains_other_than (const std::set< Extension_Code > &allowed_extensions, bool allow_unknown_extensions=false) const
void deserialize (TLS_Data_Reader &reader, Connection_Side from, Handshake_Type message_type)
bool empty () const
std::optional< std::vector< uint8_t > > extension_raw_bytes (Extension_Code type) const
std::set< Extension_Codeextension_types () const
 Extensions ()=default
 Extensions (const Extensions &)=delete
 Extensions (Extensions &&)=default
 Extensions (TLS_Data_Reader &reader, Connection_Side side, Handshake_Type message_type)
template<typename T>
T * get () const
Extensionget (Extension_Code type) const
template<typename T>
bool has () const
bool has (Extension_Code type) const
std::optional< Extension_Codelast_added () const
Extensionsoperator= (const Extensions &)=delete
Extensionsoperator= (Extensions &&)=default
bool remove_extension (Extension_Code type)
void reorder (std::span< const Extension_Code > order)
std::vector< uint8_t > serialize (Connection_Side whoami) const
size_t size () const
 ~Extensions ()

Detailed Description

Represents a block of extensions in a hello message

Definition at line 473 of file tls_extensions.h.

Constructor & Destructor Documentation

◆ Extensions() [1/4]

Botan::TLS::Extensions::Extensions ( )
default

◆ Extensions() [2/4]

Botan::TLS::Extensions::Extensions ( const Extensions & )
delete

References Extensions().

◆ Extensions() [3/4]

Botan::TLS::Extensions::Extensions ( Extensions && )
default

References Extensions().

◆ ~Extensions()

Botan::TLS::Extensions::~Extensions ( )
default

◆ Extensions() [4/4]

Botan::TLS::Extensions::Extensions ( TLS_Data_Reader & reader,
Connection_Side side,
Handshake_Type message_type )
inline

Definition at line 555 of file tls_extensions.h.

555 {
556 deserialize(reader, side, message_type);
557 }
void deserialize(TLS_Data_Reader &reader, Connection_Side from, Handshake_Type message_type)

References deserialize().

Member Function Documentation

◆ add() [1/2]

void Botan::TLS::Extensions::add ( Extension * extn)
inline

Definition at line 495 of file tls_extensions.h.

495{ add(std::unique_ptr<Extension>(extn)); }
void add(std::unique_ptr< Extension > extn)

References add().

Referenced by add().

◆ add() [2/2]

void Botan::TLS::Extensions::add ( std::unique_ptr< Extension > extn)

Definition at line 157 of file tls_extensions.cpp.

157 {
158 const auto type = extn->type();
159 if(has(type)) {
160 throw Invalid_Argument("cannot add the same extension twice: " + std::to_string(static_cast<uint16_t>(type)));
161 }
162
163 m_extension_codes.push_back(type);
164 m_extensions.emplace(type, std::move(extn));
165}

References has(), and Botan::TLS::Extension::type().

◆ contains_implemented_extensions_other_than()

bool Botan::TLS::Extensions::contains_implemented_extensions_other_than ( const std::set< Extension_Code > & allowed_extensions) const
inline
Parameters
allowed_extensionsextension types that are allowed
Returns
true if this contains any extensions implemented by Botan that are not contained in allowed_extensions.

Definition at line 516 of file tls_extensions.h.

516 {
517 return contains_other_than(allowed_extensions, true);
518 }
bool contains_other_than(const std::set< Extension_Code > &allowed_extensions, bool allow_unknown_extensions=false) const

References contains_other_than().

◆ contains_other_than()

bool Botan::TLS::Extensions::contains_other_than ( const std::set< Extension_Code > & allowed_extensions,
bool allow_unknown_extensions = false ) const
Parameters
allowed_extensionsextension types that are allowed
allow_unknown_extensionsif true, ignores unrecognized extensions
Returns
true if this contains any extensions that are not contained in allowed_extensions.

Definition at line 196 of file tls_extensions.cpp.

197 {
198 const auto found = extension_types();
199
200 std::vector<Extension_Code> diff;
201 std::set_difference(
202 found.cbegin(), found.end(), allowed_extensions.cbegin(), allowed_extensions.cend(), std::back_inserter(diff));
203
204 if(allow_unknown_extensions) {
205 // Go through the found unexpected extensions whether any of those
206 // is known to this TLS implementation.
207 const auto itr = std::find_if(diff.cbegin(), diff.cend(), [this](const auto ext_type) {
208 const auto ext = get(ext_type);
209 return ext && ext->is_implemented();
210 });
211
212 // ... if yes, `contains_other_than` is true
213 return itr != diff.cend();
214 }
215
216 return !diff.empty();
217}
std::set< Extension_Code > extension_types() const

References extension_types().

Referenced by contains_implemented_extensions_other_than().

◆ deserialize()

void Botan::TLS::Extensions::deserialize ( TLS_Data_Reader & reader,
Connection_Side from,
Handshake_Type message_type )

Definition at line 167 of file tls_extensions.cpp.

167 {
168 if(reader.has_remaining()) {
169 const uint16_t all_extn_size = reader.get_uint16_t();
170
171 if(reader.remaining_bytes() != all_extn_size) {
172 throw Decoding_Error("Bad extension size");
173 }
174
175 while(reader.has_remaining()) {
176 const uint16_t extension_code = reader.get_uint16_t();
177 const uint16_t extension_size = reader.get_uint16_t();
178
179 const auto type = static_cast<Extension_Code>(extension_code);
180
181 if(this->has(type)) {
182 throw TLS_Exception(TLS::Alert::DecodeError, "Peer sent duplicated extensions");
183 }
184
185 // TODO offer a function on reader that returns a byte range as a reference
186 // to avoid this copy of the extension data
187 const std::vector<uint8_t> extn_data = reader.get_fixed<uint8_t>(extension_size);
188 m_raw_extension_data[type] = extn_data;
189 TLS_Data_Reader extn_reader("Extension", extn_data);
190 this->add(make_extension(extn_reader, type, from, message_type));
191 extn_reader.assert_done();
192 }
193 }
194}

References Botan::TLS::TLS_Data_Reader::get_uint16_t(), has(), Botan::TLS::TLS_Data_Reader::has_remaining(), and Botan::TLS::TLS_Data_Reader::remaining_bytes().

Referenced by Extensions().

◆ empty()

bool Botan::TLS::Extensions::empty ( ) const
inline

Definition at line 491 of file tls_extensions.h.

491{ return m_extensions.empty(); }

◆ extension_raw_bytes()

std::optional< std::vector< uint8_t > > Botan::TLS::Extensions::extension_raw_bytes ( Extension_Code type) const
inline
Returns
the raw bytes of the extension with the given type as they appeared on the wire during deserialization, or std::nullopt if the extension was not present or was added programmatically.

Definition at line 564 of file tls_extensions.h.

564 {
565 auto it = m_raw_extension_data.find(type);
566 if(it != m_raw_extension_data.end()) {
567 return it->second;
568 }
569 return std::nullopt;
570 }

Referenced by Botan::TLS::Client_Hello_13::validate_updates().

◆ extension_types()

std::set< Extension_Code > Botan::TLS::Extensions::extension_types ( ) const

Definition at line 274 of file tls_extensions.cpp.

274 {
275 std::set<Extension_Code> offers;
276 for(const auto& [extn_type, extn] : m_extensions) {
277 // Consistent with serialize(): empty extensions are not placed on
278 // the wire so they must not appear in the "offered" set either.
279 if(!extn->empty()) {
280 offers.insert(extn_type);
281 }
282 }
283 return offers;
284}

Referenced by contains_other_than().

◆ get() [1/2]

template<typename T>
T * Botan::TLS::Extensions::get ( ) const
inline

◆ get() [2/2]

Extension * Botan::TLS::Extensions::get ( Extension_Code type) const

Definition at line 147 of file tls_extensions.cpp.

147 {
148 const auto i = m_extensions.find(type);
149
150 if(i == m_extensions.end()) {
151 return nullptr;
152 } else {
153 return i->second.get();
154 }
155}

◆ has() [1/2]

template<typename T>
bool Botan::TLS::Extensions::has ( ) const
inline

◆ has() [2/2]

bool Botan::TLS::Extensions::has ( Extension_Code type) const

Definition at line 143 of file tls_extensions.cpp.

143 {
144 return m_extensions.contains(type);
145}

◆ last_added()

std::optional< Extension_Code > Botan::TLS::Extensions::last_added ( ) const
inline

Return the code of the extension that appears last in the encoding This is used for checking the position of PSK extension in TLS 1.3

Definition at line 540 of file tls_extensions.h.

540 {
541 if(m_extension_codes.empty()) {
542 return {};
543 } else {
544 return m_extension_codes.back();
545 }
546 }

◆ operator=() [1/2]

Extensions & Botan::TLS::Extensions::operator= ( const Extensions & )
delete

References Extensions().

◆ operator=() [2/2]

Extensions & Botan::TLS::Extensions::operator= ( Extensions && )
default

References Extensions().

◆ remove_extension()

bool Botan::TLS::Extensions::remove_extension ( Extension_Code type)

Remove an extension from this extensions object, if it exists. Returns true if the extension existed (and thus is now removed), otherwise false (the extension wasn't set in the first place).

Note: not used internally, might be used in Callbacks::tls_modify_extensions()

Definition at line 219 of file tls_extensions.cpp.

219 {
220 auto i = m_extensions.find(type);
221
222 if(i == m_extensions.end()) {
223 return false;
224 } else {
225 m_extensions.erase(i);
226 std::erase(m_extension_codes, type);
227 m_raw_extension_data.erase(type);
228 return true;
229 }
230}

◆ reorder()

void Botan::TLS::Extensions::reorder ( std::span< const Extension_Code > order)

Reorder extensions for serialization. Extensions not mentioned in order retain their relative position at the front; extensions in order are appended in the given order.

Definition at line 286 of file tls_extensions.cpp.

286 {
287 const std::set<Extension_Code> in_order(order.begin(), order.end());
288
289 std::vector<Extension_Code> new_codes;
290 new_codes.reserve(m_extension_codes.size());
291
292 // First: extensions not mentioned in the order (preserving their relative order)
293 for(auto code : m_extension_codes) {
294 if(!in_order.contains(code)) {
295 new_codes.push_back(code);
296 }
297 }
298
299 // Then: extensions in the specified order. Deduplicate so a caller that
300 // accidentally lists the same code twice doesn't cause it to be
301 // serialized twice (which would also break peers that reject duplicate
302 // extension codes per RFC 8446 4.2 / RFC 5246 7.4.1.4).
303 std::unordered_set<Extension_Code> already_pushed;
304 for(auto code : order) {
305 if(m_extensions.contains(code) && already_pushed.insert(code).second) {
306 new_codes.push_back(code);
307 }
308 }
309
310 m_extension_codes = std::move(new_codes);
311}

◆ serialize()

std::vector< uint8_t > Botan::TLS::Extensions::serialize ( Connection_Side whoami) const

Definition at line 232 of file tls_extensions.cpp.

232 {
233 std::vector<uint8_t> buf(2); // 2 bytes for length field
234
235 // Serialize in the order extensions were added, which matters for TLS 1.3
236 for(const auto extn_type : m_extension_codes) {
237 const auto& extn = m_extensions.at(extn_type);
238
239 if(extn->empty()) {
240 continue;
241 }
242
243 const uint16_t extn_code = static_cast<uint16_t>(extn_type);
244
245 const std::vector<uint8_t> extn_val = extn->serialize(whoami);
246
247 // Each extension carries a uint16 length prefix.
248 BOTAN_ASSERT_NOMSG(extn_val.size() <= 0xFFFF);
249
250 buf.push_back(get_byte<0>(extn_code));
251 buf.push_back(get_byte<1>(extn_code));
252
253 buf.push_back(get_byte<0>(static_cast<uint16_t>(extn_val.size())));
254 buf.push_back(get_byte<1>(static_cast<uint16_t>(extn_val.size())));
255
256 buf += extn_val;
257 }
258
259 // The outer extensions block is itself uint16-length-prefixed.
260 BOTAN_ASSERT_NOMSG(buf.size() - 2 <= 0xFFFF);
261 const uint16_t extn_size = static_cast<uint16_t>(buf.size() - 2);
262
263 buf[0] = get_byte<0>(extn_size);
264 buf[1] = get_byte<1>(extn_size);
265
266 // avoid sending a completely empty extensions block
267 if(buf.size() == 2) {
268 return std::vector<uint8_t>();
269 }
270
271 return buf;
272}
#define BOTAN_ASSERT_NOMSG(expr)
Definition assert.h:75
constexpr uint8_t get_byte(T input)
Definition loadstor.h:79

References BOTAN_ASSERT_NOMSG, and Botan::get_byte().

◆ size()

size_t Botan::TLS::Extensions::size ( ) const
inline

Definition at line 489 of file tls_extensions.h.

489{ return m_extensions.size(); }

The documentation for this class was generated from the following files: