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

#include <tls_messages_13.h>

Inheritance diagram for Botan::TLS::Certificate_13:
Botan::TLS::Handshake_Message

Classes

class  Certificate_Entry

Public Member Functions

std::vector< X509_Certificatecert_chain () const
 Certificate_13 (const Certificate_Request_13 &cert_request, std::string_view hostname, Credentials_Manager &credentials_manager, Callbacks &callbacks, Certificate_Type cert_type)
 Certificate_13 (const Client_Hello_13 &client_hello, Credentials_Manager &credentials_manager, Callbacks &callbacks, Certificate_Type cert_type)
 Certificate_13 (std::span< const uint8_t > buf, const Policy &policy, Connection_Side side, Certificate_Type cert_type)
size_t count () const
bool empty () const
bool has_certificate_chain () const
bool is_raw_public_key () const
const X509_Certificateleaf () const
std::shared_ptr< const Public_Keypublic_key () const
const std::vector< uint8_t > & request_context () const
std::vector< uint8_t > serialize () const override
Handshake_Type type () const override
std::string type_string () const
void validate_extensions (const std::set< Extension_Code > &requested_extensions, Callbacks &cb) const
void verify (Callbacks &callbacks, const Policy &policy, Credentials_Manager &creds, std::string_view hostname, bool use_ocsp) const
virtual Handshake_Type wire_type () const

Detailed Description

Certificate Message of TLS 1.3

Definition at line 177 of file tls_messages_13.h.

Constructor & Destructor Documentation

◆ Certificate_13() [1/3]

Botan::TLS::Certificate_13::Certificate_13 ( const Certificate_Request_13 & cert_request,
std::string_view hostname,
Credentials_Manager & credentials_manager,
Callbacks & callbacks,
Certificate_Type cert_type )

Create a Client Certificate message ... in response to a Certificate Request message.

Create a Client Certificate message

Definition at line 188 of file msg_certificate_13.cpp.

192 :
193 m_request_context(cert_request.context()), m_side(Connection_Side::Client) {
194 const auto key_types = filter_signature_schemes(cert_request.signature_schemes());
195 const std::string op_type = "tls-client";
196
197 if(cert_type == Certificate_Type::X509) {
198 setup_entries(
199 credentials_manager.find_cert_chain(key_types,
200 to_algorithm_identifiers(cert_request.certificate_signature_schemes()),
201 cert_request.acceptable_CAs(),
202 op_type,
203 std::string(hostname)),
204 cert_request.extensions().get<Certificate_Status_Request>(),
205 callbacks);
206 } else if(cert_type == Certificate_Type::RawPublicKey) {
207 auto raw_public_key = credentials_manager.find_raw_public_key(key_types, op_type, std::string(hostname));
208
209 // RFC 8446 4.4.2
210 // If the RawPublicKey certificate type was negotiated, then the
211 // certificate_list MUST contain no more than one CertificateEntry
212 // [...].
213 // A client will send an empty certificate_list if it does not have
214 // an appropriate certificate to send in response to the server's
215 // authentication request.
216 if(raw_public_key) {
217 setup_entry(std::move(raw_public_key), callbacks);
218 }
219 }
220}
std::vector< AlgorithmIdentifier > to_algorithm_identifiers(const std::vector< Signature_Scheme > &schemes)

References Botan::TLS::Certificate_Request_13::acceptable_CAs(), Botan::TLS::Certificate_Request_13::certificate_signature_schemes(), Botan::TLS::Certificate_Request_13::extensions(), Botan::Credentials_Manager::find_cert_chain(), Botan::Credentials_Manager::find_raw_public_key(), Botan::TLS::Extensions::get(), Botan::TLS::RawPublicKey, Botan::TLS::Certificate_Request_13::signature_schemes(), Botan::TLS::to_algorithm_identifiers(), and Botan::TLS::X509.

◆ Certificate_13() [2/3]

Botan::TLS::Certificate_13::Certificate_13 ( const Client_Hello_13 & client_hello,
Credentials_Manager & credentials_manager,
Callbacks & callbacks,
Certificate_Type cert_type )

Create a Server Certificate message ... in response to a Client Hello indicating the need to authenticate with a server certificate.

Create a Server Certificate message

Definition at line 225 of file msg_certificate_13.cpp.

228 :
229 // RFC 8446 4.4.2:
230 // [In the case of server authentication], the request context
231 // SHALL be zero length
232 m_request_context(/* NOLINT(*-redundant-member-init) */), m_side(Connection_Side::Server) {
233 /*
234 RFC 8446 4.2.3:
235 Clients which desire the server to authenticate itself via a
236 certificate MUST send the "signature_algorithms" extension. If a
237 server is authenticating via a certificate and the client has not sent
238 a "signature_algorithms" extension, then the server MUST abort the
239 handshake with a "missing_extension" alert.
240 */
241 if(!client_hello.extensions().has<Signature_Algorithms>()) {
242 throw TLS_Exception(Alert::MissingExtension, "Client Hello is missing required signature_algorithms extension");
243 }
244
245 const auto key_types = filter_signature_schemes(client_hello.signature_schemes());
246 const std::string op_type = "tls-server";
247 const std::string context = client_hello.sni_hostname();
248
249 if(cert_type == Certificate_Type::X509) {
250 auto cert_chain = credentials_manager.find_cert_chain(
251 key_types, to_algorithm_identifiers(client_hello.certificate_signature_schemes()), {}, op_type, context);
252
253 // RFC 8446 4.4.2
254 // The server's certificate_list MUST always be non-empty.
255 if(cert_chain.empty()) {
256 throw TLS_Exception(Alert::HandshakeFailure, "No sufficient server certificate available");
257 }
258
259 setup_entries(std::move(cert_chain), client_hello.extensions().get<Certificate_Status_Request>(), callbacks);
260 } else if(cert_type == Certificate_Type::RawPublicKey) {
261 auto raw_public_key = credentials_manager.find_raw_public_key(key_types, op_type, context);
262
263 // RFC 8446 4.4.2
264 // If the RawPublicKey certificate type was negotiated, then the
265 // certificate_list MUST contain no more than one CertificateEntry
266 // [...].
267 // The server's certificate_list MUST always be non-empty
268 if(!raw_public_key) {
269 throw TLS_Exception(Alert::HandshakeFailure, "No sufficient server raw public key available");
270 }
271
272 setup_entry(std::move(raw_public_key), callbacks);
273 }
274}
std::vector< X509_Certificate > cert_chain() const

References cert_chain(), Botan::TLS::Client_Hello::extensions(), Botan::TLS::Extensions::get(), Botan::TLS::Extensions::has(), Botan::TLS::Client_Hello::signature_schemes(), Botan::TLS::Client_Hello::sni_hostname(), and Botan::TLS::X509.

◆ Certificate_13() [3/3]

Botan::TLS::Certificate_13::Certificate_13 ( std::span< const uint8_t > buf,
const Policy & policy,
Connection_Side side,
Certificate_Type cert_type )

Deserialize a Certificate message

Parameters
bufthe serialized message
policythe TLS policy
sideis this a Connection_Side::Server or Connection_Side::Client certificate message
cert_typeis the certificate type that was negotiated during the handshake

Deserialize a Certificate message

Definition at line 368 of file msg_certificate_13.cpp.

371 :
372 m_side(side) {
373 TLS_Data_Reader reader("cert message reader", buf);
374
375 m_request_context = reader.get_range<uint8_t>(1, 0, 255);
376
377 // RFC 8446 4.4.2
378 // [...] in the case of server authentication, this field SHALL be zero length.
379 if(m_side == Connection_Side::Server && !m_request_context.empty()) {
380 throw TLS_Exception(Alert::IllegalParameter, "Server Certificate message must not contain a request context");
381 }
382
383 const auto cert_entries_len = reader.get_uint24_t();
384
385 if(reader.remaining_bytes() != cert_entries_len) {
386 throw TLS_Exception(Alert::DecodeError, "Certificate: Message malformed");
387 }
388
389 const size_t max_size = policy.maximum_certificate_chain_size();
390 if(max_size > 0 && cert_entries_len > max_size) {
391 throw Decoding_Error("Certificate chain exceeds policy specified maximum size");
392 }
393
394 while(reader.has_remaining()) {
395 m_entries.emplace_back(reader, side, cert_type);
396 }
397
398 // RFC 8446 4.4.2
399 // The server's certificate_list MUST always be non-empty. A client
400 // will send an empty certificate_list if it does not have an
401 // appropriate certificate to send in response to the server's
402 // authentication request.
403 if(m_entries.empty()) {
404 // RFC 8446 4.4.2.4
405 // If the server supplies an empty Certificate message, the client MUST
406 // abort the handshake with a "decode_error" alert.
407 if(m_side == Connection_Side::Server) {
408 throw TLS_Exception(Alert::DecodeError, "No certificates sent by server");
409 }
410
411 return;
412 }
413
414 BOTAN_ASSERT_NOMSG(!m_entries.empty());
415
416 // RFC 8446 4.4.2.2
417 // The certificate type MUST be X.509v3 [RFC5280], unless explicitly
418 // negotiated otherwise (e.g., [RFC7250]).
419 //
420 // TLS 1.0 through 1.3 all seem to require that the certificate be
421 // precisely a v3 certificate. In fact the strict wording would seem
422 // to require that every certificate in the chain be v3. But often
423 // the intermediates are outside of the control of the server.
424 // But, require that the leaf certificate be v3.
425 if(cert_type == Certificate_Type::X509 && m_entries.front().certificate().x509_version() != 3) {
426 throw TLS_Exception(Alert::BadCertificate, "The leaf certificate must be v3");
427 }
428
429 // RFC 8446 4.4.2
430 // If the RawPublicKey certificate type was negotiated, then the
431 // certificate_list MUST contain no more than one CertificateEntry.
432 if(cert_type == Certificate_Type::RawPublicKey && m_entries.size() != 1) {
433 throw TLS_Exception(Alert::IllegalParameter, "Certificate message contained more than one RawPublicKey");
434 }
435
436 // Validate the provided (certificate) public key against our policy
437 auto pubkey = public_key();
438 policy.check_peer_key_acceptable(*pubkey);
439
440 if(!policy.allowed_signature_method(pubkey->algo_name())) {
441 throw TLS_Exception(Alert::HandshakeFailure, "Rejecting " + pubkey->algo_name() + " signature");
442 }
443}
#define BOTAN_ASSERT_NOMSG(expr)
Definition assert.h:75
std::shared_ptr< const Public_Key > public_key() const

References Botan::TLS::Policy::allowed_signature_method(), BOTAN_ASSERT_NOMSG, Botan::TLS::Policy::check_peer_key_acceptable(), Botan::TLS::TLS_Data_Reader::get_range(), Botan::TLS::TLS_Data_Reader::get_uint24_t(), Botan::TLS::TLS_Data_Reader::has_remaining(), Botan::TLS::Policy::maximum_certificate_chain_size(), public_key(), Botan::TLS::RawPublicKey, Botan::TLS::TLS_Data_Reader::remaining_bytes(), Botan::TLS::Server, and Botan::TLS::X509.

Member Function Documentation

◆ cert_chain()

std::vector< X509_Certificate > Botan::TLS::Certificate_13::cert_chain ( ) const

Definition at line 67 of file msg_certificate_13.cpp.

67 {
69 std::vector<X509_Certificate> result;
70 std::transform(m_entries.cbegin(), m_entries.cend(), std::back_inserter(result), [](const auto& cert_entry) {
71 return cert_entry.certificate();
72 });
73 return result;
74}
#define BOTAN_STATE_CHECK(expr)
Definition assert.h:49

References BOTAN_STATE_CHECK, and has_certificate_chain().

Referenced by Certificate_13().

◆ count()

size_t Botan::TLS::Certificate_13::count ( ) const
inline

Definition at line 218 of file tls_messages_13.h.

218{ return m_entries.size(); }

◆ empty()

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

Definition at line 220 of file tls_messages_13.h.

220{ return m_entries.empty(); }

Referenced by Botan::TLS::Certificate_Verify_13::Certificate_Verify_13(), has_certificate_chain(), is_raw_public_key(), leaf(), and public_key().

◆ has_certificate_chain()

bool Botan::TLS::Certificate_13::has_certificate_chain ( ) const

Definition at line 59 of file msg_certificate_13.cpp.

59 {
60 return !empty() && m_entries.front().has_certificate();
61}

References empty().

Referenced by cert_chain(), Botan::TLS::Certificate_Verify_13::Certificate_Verify_13(), and is_raw_public_key().

◆ is_raw_public_key()

bool Botan::TLS::Certificate_13::is_raw_public_key ( ) const

Definition at line 63 of file msg_certificate_13.cpp.

63 {
64 return !empty() && !has_certificate_chain();
65}

References empty(), and has_certificate_chain().

Referenced by verify().

◆ leaf()

const X509_Certificate & Botan::TLS::Certificate_13::leaf ( ) const

Definition at line 96 of file msg_certificate_13.cpp.

96 {
98 return m_entries.front().certificate();
99}

References BOTAN_STATE_CHECK, and empty().

Referenced by Botan::TLS::Certificate_Verify_13::Certificate_Verify_13().

◆ public_key()

std::shared_ptr< const Public_Key > Botan::TLS::Certificate_13::public_key ( ) const

Definition at line 91 of file msg_certificate_13.cpp.

91 {
93 return m_entries.front().public_key();
94}

References BOTAN_STATE_CHECK, and empty().

Referenced by Certificate_13(), Botan::TLS::Certificate_Verify_13::Certificate_Verify_13(), and verify().

◆ request_context()

const std::vector< uint8_t > & Botan::TLS::Certificate_13::request_context ( ) const
inline

Definition at line 225 of file tls_messages_13.h.

225{ return m_request_context; }

◆ serialize()

std::vector< uint8_t > Botan::TLS::Certificate_13::serialize ( ) const
overridevirtual

Serialize a Certificate message

Implements Botan::TLS::Handshake_Message.

Definition at line 448 of file msg_certificate_13.cpp.

448 {
449 std::vector<uint8_t> buf;
450
451 append_tls_length_value(buf, m_request_context, 1);
452
453 std::vector<uint8_t> entries;
454 for(const auto& entry : m_entries) {
455 append_tls_length_value(entries, entry.serialize(), 3);
456
457 // Extensions are tacked at the end of certificate entries. Note that
458 // Extensions::serialize() usually emits the required length field,
459 // except when no extensions are added at all, then it returns an
460 // empty buffer.
461 //
462 // TODO: look into this issue more generally when overhauling the
463 // message marshalling.
464 auto extensions = entry.extensions().serialize(m_side);
465 entries += (!extensions.empty()) ? extensions : std::vector<uint8_t>{0, 0};
466 }
467
468 append_tls_length_value(buf, entries, 3);
469
470 return buf;
471}
void append_tls_length_value(std::vector< uint8_t, Alloc > &buf, const T *vals, size_t vals_size, size_t tag_size)
Definition tls_reader.h:177

References Botan::TLS::append_tls_length_value().

◆ type()

Handshake_Type Botan::TLS::Certificate_13::type ( ) const
inlineoverridevirtual

Return the TLS handshake type code

Returns
the message type

Implements Botan::TLS::Handshake_Message.

Definition at line 211 of file tls_messages_13.h.

References Botan::TLS::Certificate.

Referenced by validate_extensions().

◆ type_string()

std::string Botan::TLS::Handshake_Message::type_string ( ) const
inherited

Return a free-form string describing this message type

Returns
string representation of this message type

Definition at line 21 of file tls_handshake_state.cpp.

21 {
23}
virtual Handshake_Type type() const =0
const char * handshake_type_to_string(Handshake_Type type)
Definition tls_magic.cpp:15

References Botan::TLS::handshake_type_to_string(), and type().

◆ validate_extensions()

void Botan::TLS::Certificate_13::validate_extensions ( const std::set< Extension_Code > & requested_extensions,
Callbacks & cb ) const

Validate a Certificate message regarding what extensions are expected based on previous handshake messages. Also call the tls_examine_extensions() callback for each entry.

Parameters
requested_extensionsExtensions of Client_Hello or Certificate_Request messages
cbCallback that will be called for each extension.

Definition at line 76 of file msg_certificate_13.cpp.

76 {
77 // RFC 8446 4.4.2
78 // Extensions in the Certificate message from the server MUST
79 // correspond to ones from the ClientHello message. Extensions in
80 // the Certificate message from the client MUST correspond to
81 // extensions in the CertificateRequest message from the server.
82 for(const auto& entry : m_entries) {
83 if(entry.extensions().contains_other_than(requested_extensions)) {
84 throw TLS_Exception(Alert::IllegalParameter, "Certificate Entry contained an extension that was not offered");
85 }
86
87 cb.tls_examine_extensions(entry.extensions(), m_side, type());
88 }
89}
Handshake_Type type() const override

References Botan::TLS::Callbacks::tls_examine_extensions(), and type().

◆ verify()

void Botan::TLS::Certificate_13::verify ( Callbacks & callbacks,
const Policy & policy,
Credentials_Manager & creds,
std::string_view hostname,
bool use_ocsp ) const

Verify the certificate chain

Exceptions
ifverification fails.

Definition at line 101 of file msg_certificate_13.cpp.

105 {
107
108 if(is_raw_public_key()) {
109 callbacks.tls_verify_raw_public_key(*public_key(), usage, hostname, policy);
110 } else {
111 verify_certificate_chain(callbacks, policy, creds, hostname, use_ocsp, usage);
112 }
113}

References Botan::TLS::Client, is_raw_public_key(), public_key(), Botan::TLS_CLIENT_AUTH, Botan::TLS_SERVER_AUTH, and Botan::TLS::Callbacks::tls_verify_raw_public_key().

◆ wire_type()

virtual Handshake_Type Botan::TLS::Handshake_Message::wire_type ( ) const
inlinevirtualinherited

Return the wire encoding of the message type code

Note
This is usually equal to type with the exception of a TLS 1.3 Helloy Retry Request.
Returns
the wire representation of the message's type

Reimplemented in Botan::TLS::Hello_Retry_Request.

Definition at line 47 of file tls_handshake_msg.h.

47{ return type(); }

References type().

Referenced by Botan::TLS::Stream_Handshake_IO::send().


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