• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

randombit / botan / 20283898778

16 Dec 2025 09:52PM UTC coverage: 90.52% (+0.2%) from 90.36%
20283898778

Pull #5167

github

web-flow
Merge 795a38954 into 3d96b675e
Pull Request #5167: Changes to reduce unnecessary inclusions

101154 of 111748 relevant lines covered (90.52%)

12682929.61 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

93.72
/src/lib/tls/tls13/msg_certificate_13.cpp
1
/*
2
* Certificate Message
3
* (C) 2022 Jack Lloyd
4
*     2022 Hannes Rantzsch, René Meusel - neXenio GmbH
5
*     2023 René Meusel, Fabian Albert - Rohde & Schwarz Cybersecurity
6
*
7
* Botan is released under the Simplified BSD License (see license.txt)
8
*/
9

10
#include <botan/tls_messages.h>
11

12
#include <botan/credentials_manager.h>
13
#include <botan/ocsp.h>
14
#include <botan/tls_alert.h>
15
#include <botan/tls_callbacks.h>
16
#include <botan/tls_exceptn.h>
17
#include <botan/tls_extensions.h>
18
#include <botan/x509_key.h>
19
#include <botan/internal/tls_reader.h>
20

21
#include <algorithm>
22
#include <iterator>
23
#include <memory>
24

25
namespace Botan::TLS {
26

27
namespace {
28

29
bool certificate_allows_signing(const X509_Certificate& cert) {
402✔
30
   const auto constraints = cert.constraints();
402✔
31
   if(constraints.empty()) {
402✔
32
      return true;
33
   }
34

35
   return constraints.includes_any(Key_Constraints::DigitalSignature, Key_Constraints::NonRepudiation);
11✔
36
}
37

38
std::vector<std::string> filter_signature_schemes(const std::vector<Signature_Scheme>& peer_scheme_preference) {
334✔
39
   std::vector<std::string> compatible_schemes;
334✔
40
   for(const auto& scheme : peer_scheme_preference) {
3,428✔
41
      if(scheme.is_available() && scheme.is_compatible_with(Protocol_Version::TLS_V13)) {
3,094✔
42
         compatible_schemes.push_back(scheme.algorithm_name());
1,276✔
43
      }
44
   }
45

46
   if(compatible_schemes.empty()) {
334✔
47
      throw TLS_Exception(Alert::HandshakeFailure, "Failed to agree on any signature algorithm");
12✔
48
   }
49

50
   return compatible_schemes;
322✔
51
}
12✔
52

53
}  // namespace
54

55
bool Certificate_13::has_certificate_chain() const {
2,991✔
56
   return !empty() && m_entries.front().has_certificate();
2,991✔
57
}
58

59
bool Certificate_13::is_raw_public_key() const {
1,179✔
60
   return !empty() && !has_certificate_chain();
1,179✔
61
}
62

63
std::vector<X509_Certificate> Certificate_13::cert_chain() const {
754✔
64
   BOTAN_STATE_CHECK(has_certificate_chain());
754✔
65
   std::vector<X509_Certificate> result;
754✔
66
   std::transform(m_entries.cbegin(), m_entries.cend(), std::back_inserter(result), [](const auto& cert_entry) {
754✔
67
      return cert_entry.certificate();
909✔
68
   });
69
   return result;
754✔
70
}
×
71

72
void Certificate_13::validate_extensions(const std::set<Extension_Code>& requested_extensions, Callbacks& cb) const {
417✔
73
   // RFC 8446 4.4.2
74
   //    Extensions in the Certificate message from the server MUST
75
   //    correspond to ones from the ClientHello message.  Extensions in
76
   //    the Certificate message from the client MUST correspond to
77
   //    extensions in the CertificateRequest message from the server.
78
   for(const auto& entry : m_entries) {
875✔
79
      if(entry.extensions().contains_other_than(requested_extensions)) {
461✔
80
         throw TLS_Exception(Alert::IllegalParameter, "Certificate Entry contained an extension that was not offered");
3✔
81
      }
82

83
      cb.tls_examine_extensions(entry.extensions(), m_side, type());
458✔
84
   }
85
}
414✔
86

87
std::shared_ptr<const Public_Key> Certificate_13::public_key() const {
755✔
88
   BOTAN_STATE_CHECK(!empty());
755✔
89
   return m_entries.front().public_key();
755✔
90
}
91

92
const X509_Certificate& Certificate_13::leaf() const {
300✔
93
   BOTAN_STATE_CHECK(!empty());
300✔
94
   return m_entries.front().certificate();
300✔
95
}
96

97
void Certificate_13::verify(Callbacks& callbacks,
404✔
98
                            const Policy& policy,
99
                            Credentials_Manager& creds,
100
                            std::string_view hostname,
101
                            bool use_ocsp) const {
102
   const auto usage = (m_side == Connection_Side::Client) ? Usage_Type::TLS_CLIENT_AUTH : Usage_Type::TLS_SERVER_AUTH;
404✔
103

104
   if(is_raw_public_key()) {
404✔
105
      callbacks.tls_verify_raw_public_key(*public_key(), usage, hostname, policy);
4✔
106
   } else {
107
      verify_certificate_chain(callbacks, policy, creds, hostname, use_ocsp, usage);
402✔
108
   }
109
}
352✔
110

111
void Certificate_13::verify_certificate_chain(Callbacks& callbacks,
402✔
112
                                              const Policy& policy,
113
                                              Credentials_Manager& creds,
114
                                              std::string_view hostname,
115
                                              bool use_ocsp,
116
                                              Usage_Type usage_type) const {
117
   std::vector<X509_Certificate> certs;
402✔
118
   std::vector<std::optional<OCSP::Response>> ocsp_responses;
402✔
119
   for(const auto& entry : m_entries) {
858✔
120
      certs.push_back(entry.certificate());
456✔
121
      if(use_ocsp) {
456✔
122
         if(entry.extensions().has<Certificate_Status_Request>()) {
127✔
123
            ocsp_responses.push_back(callbacks.tls_parse_ocsp_response(
48✔
124
               entry.extensions().get<Certificate_Status_Request>()->get_ocsp_response()));
24✔
125
         } else {
126
            ocsp_responses.emplace_back();
103✔
127
         }
128
      }
129
   }
130

131
   const auto& server_cert = m_entries.front().certificate();
402✔
132
   if(!certificate_allows_signing(server_cert)) {
804✔
133
      throw TLS_Exception(Alert::BadCertificate, "Certificate usage constraints do not allow signing");
4✔
134
   }
135

136
   // Note that m_side represents the sender, so the usages here are swapped
137
   const auto trusted_CAs = creds.trusted_certificate_authorities(
796✔
138
      m_side == Connection_Side::Client ? "tls-server" : "tls-client", std::string(hostname));
1,514✔
139

140
   callbacks.tls_verify_cert_chain(certs, ocsp_responses, trusted_CAs, usage_type, hostname, policy);
398✔
141
}
454✔
142

143
void Certificate_13::setup_entries(std::vector<X509_Certificate> cert_chain,
317✔
144
                                   const Certificate_Status_Request* csr,
145
                                   Callbacks& callbacks) {
146
   // RFC 8446 4.4.2.1
147
   //    A server MAY request that a client present an OCSP response with its
148
   //    certificate by sending an empty "status_request" extension in its
149
   //    CertificateRequest message.
150
   const auto ocsp_responses = (csr != nullptr) ? callbacks.tls_provide_cert_chain_status(cert_chain, *csr)
317✔
151
                                                : std::vector<std::vector<uint8_t>>(cert_chain.size());
317✔
152

153
   if(ocsp_responses.size() != cert_chain.size()) {
309✔
154
      throw TLS_Exception(Alert::InternalError, "Application didn't provide the correct number of OCSP responses");
×
155
   }
156

157
   for(size_t i = 0; i < cert_chain.size(); ++i) {
611✔
158
      auto& entry = m_entries.emplace_back(cert_chain[i]);
302✔
159
      if(!ocsp_responses[i].empty()) {
302✔
160
         entry.extensions().add(new Certificate_Status_Request(ocsp_responses[i]));  // NOLINT(*-owning-memory)
32✔
161
      }
162

163
      // This will call the modification callback multiple times. Once for
164
      // each certificate in the `cert_chain`. Users that want to add an
165
      // extension to a specific Certificate Entry might have a hard time
166
      // to distinguish them.
167
      //
168
      // TODO: Callbacks::tls_modify_extensions() might need even more
169
      //       context depending on the message whose extensions should be
170
      //       manipulatable.
171
      callbacks.tls_modify_extensions(entry.extensions(), m_side, type());
302✔
172
   }
173
}
309✔
174

175
void Certificate_13::setup_entry(std::shared_ptr<Public_Key> raw_public_key, Callbacks& callbacks) {
2✔
176
   BOTAN_ASSERT_NONNULL(raw_public_key);
2✔
177
   auto& entry = m_entries.emplace_back(std::move(raw_public_key));
2✔
178
   callbacks.tls_modify_extensions(entry.extensions(), m_side, type());
2✔
179
}
2✔
180

181
/**
182
 * Create a Client Certificate message
183
 */
184
Certificate_13::Certificate_13(const Certificate_Request_13& cert_request,
62✔
185
                               std::string_view hostname,
186
                               Credentials_Manager& credentials_manager,
187
                               Callbacks& callbacks,
188
                               Certificate_Type cert_type) :
62✔
189
      m_request_context(cert_request.context()), m_side(Connection_Side::Client) {
62✔
190
   const auto key_types = filter_signature_schemes(cert_request.signature_schemes());
62✔
191
   const std::string op_type = "tls-client";
56✔
192

193
   if(cert_type == Certificate_Type::X509) {
56✔
194
      setup_entries(
109✔
195
         credentials_manager.find_cert_chain(key_types,
164✔
196
                                             to_algorithm_identifiers(cert_request.certificate_signature_schemes()),
110✔
197
                                             cert_request.acceptable_CAs(),
56✔
198
                                             op_type,
199
                                             std::string(hostname)),
165✔
200
         cert_request.extensions().get<Certificate_Status_Request>(),
55✔
201
         callbacks);
202
   } else if(cert_type == Certificate_Type::RawPublicKey) {
1✔
203
      auto raw_public_key = credentials_manager.find_raw_public_key(key_types, op_type, std::string(hostname));
3✔
204

205
      // RFC 8446 4.4.2
206
      //     If the RawPublicKey certificate type was negotiated, then the
207
      //     certificate_list MUST contain no more than one CertificateEntry
208
      //     [...].
209
      //     A client will send an empty certificate_list if it does not have
210
      //     an appropriate certificate to send in response to the server's
211
      //     authentication request.
212
      if(raw_public_key) {
1✔
213
         setup_entry(std::move(raw_public_key), callbacks);
2✔
214
      }
215
   }
1✔
216
}
70✔
217

218
/**
219
 * Create a Server Certificate message
220
 */
221
Certificate_13::Certificate_13(const Client_Hello_13& client_hello,
272✔
222
                               Credentials_Manager& credentials_manager,
223
                               Callbacks& callbacks,
224
                               Certificate_Type cert_type) :
272✔
225
      // RFC 8446 4.4.2:
226
      //    [In the case of server authentication], the request context
227
      //    SHALL be zero length
228
      m_request_context(/* NOLINT(*-redundant-member-init) */), m_side(Connection_Side::Server) {
272✔
229
   BOTAN_ASSERT_NOMSG(client_hello.extensions().has<Signature_Algorithms>());
272✔
230

231
   const auto key_types = filter_signature_schemes(client_hello.signature_schemes());
272✔
232
   const std::string op_type = "tls-server";
266✔
233
   const std::string context = client_hello.sni_hostname();
266✔
234

235
   if(cert_type == Certificate_Type::X509) {
266✔
236
      auto cert_chain = credentials_manager.find_cert_chain(
265✔
237
         key_types, to_algorithm_identifiers(client_hello.certificate_signature_schemes()), {}, op_type, context);
277✔
238

239
      // RFC 8446 4.4.2
240
      //    The server's certificate_list MUST always be non-empty.
241
      if(cert_chain.empty()) {
264✔
242
         throw TLS_Exception(Alert::HandshakeFailure, "No sufficient server certificate available");
1✔
243
      }
244

245
      setup_entries(std::move(cert_chain), client_hello.extensions().get<Certificate_Status_Request>(), callbacks);
263✔
246
   } else if(cert_type == Certificate_Type::RawPublicKey) {
265✔
247
      auto raw_public_key = credentials_manager.find_raw_public_key(key_types, op_type, context);
1✔
248

249
      // RFC 8446 4.4.2
250
      //     If the RawPublicKey certificate type was negotiated, then the
251
      //     certificate_list MUST contain no more than one CertificateEntry
252
      //     [...].
253
      //     The server's certificate_list MUST always be non-empty
254
      if(!raw_public_key) {
1✔
255
         throw TLS_Exception(Alert::HandshakeFailure, "No sufficient server raw public key available");
×
256
      }
257

258
      setup_entry(std::move(raw_public_key), callbacks);
2✔
259
   }
1✔
260
}
308✔
261

262
Certificate_13::Certificate_Entry::Certificate_Entry(TLS_Data_Reader& reader,
474✔
263
                                                     Connection_Side side,
264
                                                     Certificate_Type cert_type) {
474✔
265
   switch(cert_type) {
474✔
266
      case Certificate_Type::X509:
472✔
267
         // RFC 8446 4.2.2
268
         //    [...] each CertificateEntry contains a DER-encoded X.509
269
         //    certificate.
270
         m_certificate = X509_Certificate(reader.get_tls_length_value(3));
946✔
271
         m_raw_public_key = m_certificate->subject_public_key();
940✔
272
         break;
470✔
273
      case Certificate_Type::RawPublicKey:
2✔
274
         // RFC 7250 3.
275
         //    This specification uses raw public keys whereby the already
276
         //    available encoding used in a PKIX certificate in the form of a
277
         //    SubjectPublicKeyInfo structure is reused.
278
         m_raw_public_key = X509::load_key(reader.get_tls_length_value(3));
6✔
279
         break;
2✔
280
      default:
×
281
         throw TLS_Exception(Alert::InternalError, "Unknown certificate type");
×
282
   }
283

284
   // Extensions are simply tacked at the end of the certificate entry. This
285
   // is a departure from the typical "tag-length-value" in a sense that the
286
   // Extensions deserializer needs the length value of the extensions.
287
   const auto extensions_length = reader.peek_uint16_t();
472✔
288
   const auto exts_buf = reader.get_fixed<uint8_t>(extensions_length + 2);
472✔
289
   TLS_Data_Reader exts_reader("extensions reader", exts_buf);
472✔
290
   m_extensions.deserialize(exts_reader, side, Handshake_Type::Certificate);
472✔
291

292
   if(cert_type == Certificate_Type::X509) {
471✔
293
      // RFC 8446 4.4.2
294
      //    Valid extensions for server certificates at present include the
295
      //    OCSP Status extension [RFC6066] and the SignedCertificateTimestamp
296
      //    extension [RFC6962]; future extensions may be defined for this
297
      //    message as well.
298
      //
299
      // RFC 8446 4.4.2.1
300
      //    A server MAY request that a client present an OCSP response with its
301
      //    certificate by sending an empty "status_request" extension in its
302
      //    CertificateRequest message.
303
      if(m_extensions.contains_implemented_extensions_other_than({
938✔
304
            Extension_Code::CertificateStatusRequest,
305
            // Extension_Code::SignedCertificateTimestamp
306
         })) {
307
         throw TLS_Exception(Alert::IllegalParameter, "Certificate Entry contained an extension that is not allowed");
×
308
      }
309
   } else if(m_extensions.contains_implemented_extensions_other_than({})) {
3✔
310
      throw TLS_Exception(
×
311
         Alert::IllegalParameter,
312
         "Certificate Entry holding something else than a certificate contained unexpected extensions");
×
313
   }
314
}
478✔
315

316
Certificate_13::Certificate_Entry::Certificate_Entry(X509_Certificate cert) :
302✔
317
      m_certificate(std::move(cert)), m_raw_public_key(m_certificate->subject_public_key()) {}
604✔
318

319
Certificate_13::Certificate_Entry::Certificate_Entry(std::shared_ptr<Public_Key> raw_public_key) :
2✔
320
      m_certificate(std::nullopt), m_raw_public_key(std::move(raw_public_key)) {
2✔
321
   BOTAN_ASSERT_NONNULL(m_raw_public_key);
2✔
322
}
2✔
323

324
const X509_Certificate& Certificate_13::Certificate_Entry::certificate() const {
2,482✔
325
   BOTAN_STATE_CHECK(has_certificate());
2,482✔
326
   return m_certificate.value();
2,482✔
327
}
328

329
std::shared_ptr<const Public_Key> Certificate_13::Certificate_Entry::public_key() const {
755✔
330
   BOTAN_ASSERT_NONNULL(m_raw_public_key);
755✔
331
   return m_raw_public_key;
755✔
332
}
333

334
std::vector<uint8_t> Certificate_13::Certificate_Entry::serialize() const {
318✔
335
   return (has_certificate()) ? m_certificate->BER_encode() : X509::BER_encode(*m_raw_public_key);
318✔
336
}
337

338
/**
339
* Deserialize a Certificate message
340
*/
341
Certificate_13::Certificate_13(const std::vector<uint8_t>& buf,
434✔
342
                               const Policy& policy,
343
                               Connection_Side side,
344
                               Certificate_Type cert_type) :
434✔
345
      m_side(side) {
434✔
346
   TLS_Data_Reader reader("cert message reader", buf);
434✔
347

348
   m_request_context = reader.get_range<uint8_t>(1, 0, 255);
434✔
349

350
   // RFC 8446 4.4.2
351
   //    [...] in the case of server authentication, this field SHALL be zero length.
352
   if(m_side == Connection_Side::Server && !m_request_context.empty()) {
434✔
353
      throw TLS_Exception(Alert::IllegalParameter, "Server Certificate message must not contain a request context");
×
354
   }
355

356
   const auto cert_entries_len = reader.get_uint24_t();
434✔
357

358
   if(reader.remaining_bytes() != cert_entries_len) {
434✔
359
      throw TLS_Exception(Alert::DecodeError, "Certificate: Message malformed");
2✔
360
   }
361

362
   const size_t max_size = policy.maximum_certificate_chain_size();
432✔
363
   if(max_size > 0 && cert_entries_len > max_size) {
432✔
364
      throw Decoding_Error("Certificate chain exceeds policy specified maximum size");
1✔
365
   }
366

367
   while(reader.has_remaining()) {
902✔
368
      m_entries.emplace_back(reader, side, cert_type);
474✔
369
   }
370

371
   // RFC 8446 4.4.2
372
   //    The server's certificate_list MUST always be non-empty.  A client
373
   //    will send an empty certificate_list if it does not have an
374
   //    appropriate certificate to send in response to the server's
375
   //    authentication request.
376
   if(m_entries.empty()) {
428✔
377
      // RFC 8446 4.4.2.4
378
      //    If the server supplies an empty Certificate message, the client MUST
379
      //    abort the handshake with a "decode_error" alert.
380
      if(m_side == Connection_Side::Server) {
11✔
381
         throw TLS_Exception(Alert::DecodeError, "No certificates sent by server");
1✔
382
      }
383

384
      return;
10✔
385
   }
386

387
   BOTAN_ASSERT_NOMSG(!m_entries.empty());
417✔
388

389
   // RFC 8446 4.4.2.2
390
   //    The certificate type MUST be X.509v3 [RFC5280], unless explicitly
391
   //    negotiated otherwise (e.g., [RFC7250]).
392
   //
393
   // TLS 1.0 through 1.3 all seem to require that the certificate be
394
   // precisely a v3 certificate. In fact the strict wording would seem
395
   // to require that every certificate in the chain be v3. But often
396
   // the intermediates are outside of the control of the server.
397
   // But, require that the leaf certificate be v3.
398
   if(cert_type == Certificate_Type::X509 && m_entries.front().certificate().x509_version() != 3) {
417✔
399
      throw TLS_Exception(Alert::BadCertificate, "The leaf certificate must be v3");
×
400
   }
401

402
   // RFC 8446 4.4.2
403
   //    If the RawPublicKey certificate type was negotiated, then the
404
   //    certificate_list MUST contain no more than one CertificateEntry.
405
   if(cert_type == Certificate_Type::RawPublicKey && m_entries.size() != 1) {
417✔
406
      throw TLS_Exception(Alert::IllegalParameter, "Certificate message contained more than one RawPublicKey");
×
407
   }
408

409
   // Validate the provided (certificate) public key against our policy
410
   auto pubkey = public_key();
417✔
411
   policy.check_peer_key_acceptable(*pubkey);
417✔
412

413
   if(!policy.allowed_signature_method(pubkey->algo_name())) {
417✔
414
      throw TLS_Exception(Alert::HandshakeFailure, "Rejecting " + pubkey->algo_name() + " signature");
×
415
   }
416
}
438✔
417

418
/**
419
* Serialize a Certificate message
420
*/
421
std::vector<uint8_t> Certificate_13::serialize() const {
325✔
422
   std::vector<uint8_t> buf;
325✔
423

424
   append_tls_length_value(buf, m_request_context, 1);
325✔
425

426
   std::vector<uint8_t> entries;
325✔
427
   for(const auto& entry : m_entries) {
643✔
428
      append_tls_length_value(entries, entry.serialize(), 3);
636✔
429

430
      // Extensions are tacked at the end of certificate entries. Note that
431
      // Extensions::serialize() usually emits the required length field,
432
      // except when no extensions are added at all, then it  returns an
433
      // empty buffer.
434
      //
435
      // TODO: look into this issue more generally when overhauling the
436
      //       message marshalling.
437
      auto extensions = entry.extensions().serialize(m_side);
318✔
438
      entries += (!extensions.empty()) ? extensions : std::vector<uint8_t>{0, 0};
636✔
439
   }
318✔
440

441
   append_tls_length_value(buf, entries, 3);
325✔
442

443
   return buf;
325✔
444
}
325✔
445

446
}  // namespace Botan::TLS
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc