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

randombit / botan / 19012754211

02 Nov 2025 01:10PM UTC coverage: 90.677% (+0.006%) from 90.671%
19012754211

push

github

web-flow
Merge pull request #5137 from randombit/jack/clang-tidy-includes

Remove various unused includes flagged by clang-tidy misc-include-cleaner

100457 of 110786 relevant lines covered (90.68%)

12189873.8 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 <iterator>
22
#include <memory>
23

24
namespace Botan::TLS {
25

26
namespace {
27

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

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

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

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

49
   return compatible_schemes;
322✔
50
}
12✔
51

52
}  // namespace
53

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

383
      return;
10✔
384
   }
385

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

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

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

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

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

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

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

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

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

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

442
   return buf;
325✔
443
}
325✔
444

445
}  // 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