Botan 3.12.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 (const std::vector< 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 460 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 542 of file tls_extensions.h.

542 {
543 deserialize(reader, side, message_type);
544 }
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 482 of file tls_extensions.h.

482{ 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 154 of file tls_extensions.cpp.

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

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 503 of file tls_extensions.h.

503 {
504 return contains_other_than(allowed_extensions, true);
505 }
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 193 of file tls_extensions.cpp.

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

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

References Botan::TLS::TLS_Data_Reader::get_uint16_t(), 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 478 of file tls_extensions.h.

478{ 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 551 of file tls_extensions.h.

551 {
552 auto it = m_raw_extension_data.find(type);
553 if(it != m_raw_extension_data.end()) {
554 return it->second;
555 }
556 return std::nullopt;
557 }

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

◆ extension_types()

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

Definition at line 271 of file tls_extensions.cpp.

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

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 144 of file tls_extensions.cpp.

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

◆ 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 140 of file tls_extensions.cpp.

140 {
141 return m_extensions.contains(type);
142}

◆ 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 527 of file tls_extensions.h.

527 {
528 if(m_extension_codes.empty()) {
529 return {};
530 } else {
531 return m_extension_codes.back();
532 }
533 }

◆ 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 216 of file tls_extensions.cpp.

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

◆ reorder()

void Botan::TLS::Extensions::reorder ( const std::vector< 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 283 of file tls_extensions.cpp.

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

◆ serialize()

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

Definition at line 229 of file tls_extensions.cpp.

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

476{ return m_extensions.size(); }

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