/src/botan/src/lib/tls/tls13/msg_certificate_13.cpp
Line | Count | Source (jump to first uncovered line) |
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/data_src.h> |
14 | | #include <botan/ocsp.h> |
15 | | #include <botan/tls_alert.h> |
16 | | #include <botan/tls_callbacks.h> |
17 | | #include <botan/tls_exceptn.h> |
18 | | #include <botan/tls_extensions.h> |
19 | | #include <botan/x509_key.h> |
20 | | #include <botan/internal/loadstor.h> |
21 | | #include <botan/internal/stl_util.h> |
22 | | #include <botan/internal/tls_handshake_hash.h> |
23 | | #include <botan/internal/tls_handshake_io.h> |
24 | | #include <botan/internal/tls_reader.h> |
25 | | |
26 | | #include <iterator> |
27 | | #include <memory> |
28 | | |
29 | | namespace Botan::TLS { |
30 | | |
31 | | namespace { |
32 | | |
33 | 0 | bool certificate_allows_signing(const X509_Certificate& cert) { |
34 | 0 | const auto constraints = cert.constraints(); |
35 | 0 | if(constraints.empty()) { |
36 | 0 | return true; |
37 | 0 | } |
38 | | |
39 | 0 | return constraints.includes_any(Key_Constraints::DigitalSignature, Key_Constraints::NonRepudiation); |
40 | 0 | } |
41 | | |
42 | 0 | std::vector<std::string> filter_signature_schemes(const std::vector<Signature_Scheme>& peer_scheme_preference) { |
43 | 0 | std::vector<std::string> compatible_schemes; |
44 | 0 | for(const auto& scheme : peer_scheme_preference) { |
45 | 0 | if(scheme.is_available() && scheme.is_compatible_with(Protocol_Version::TLS_V13)) { |
46 | 0 | compatible_schemes.push_back(scheme.algorithm_name()); |
47 | 0 | } |
48 | 0 | } |
49 | |
|
50 | 0 | if(compatible_schemes.empty()) { |
51 | 0 | throw TLS_Exception(Alert::HandshakeFailure, "Failed to agree on any signature algorithm"); |
52 | 0 | } |
53 | | |
54 | 0 | return compatible_schemes; |
55 | 0 | } |
56 | | |
57 | | } // namespace |
58 | | |
59 | 0 | bool Certificate_13::has_certificate_chain() const { |
60 | 0 | return !empty() && m_entries.front().has_certificate(); |
61 | 0 | } |
62 | | |
63 | 0 | bool Certificate_13::is_raw_public_key() const { |
64 | 0 | return !empty() && !has_certificate_chain(); |
65 | 0 | } |
66 | | |
67 | 0 | std::vector<X509_Certificate> Certificate_13::cert_chain() const { |
68 | 0 | BOTAN_STATE_CHECK(has_certificate_chain()); |
69 | 0 | std::vector<X509_Certificate> result; |
70 | 0 | std::transform(m_entries.cbegin(), m_entries.cend(), std::back_inserter(result), [](const auto& cert_entry) { |
71 | 0 | return cert_entry.certificate(); |
72 | 0 | }); |
73 | 0 | return result; |
74 | 0 | } |
75 | | |
76 | 0 | void Certificate_13::validate_extensions(const std::set<Extension_Code>& requested_extensions, Callbacks& cb) const { |
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 | 0 | for(const auto& entry : m_entries) { |
83 | 0 | if(entry.extensions().contains_other_than(requested_extensions)) { |
84 | 0 | throw TLS_Exception(Alert::IllegalParameter, "Certificate Entry contained an extension that was not offered"); |
85 | 0 | } |
86 | | |
87 | 0 | cb.tls_examine_extensions(entry.extensions(), m_side, type()); |
88 | 0 | } |
89 | 0 | } |
90 | | |
91 | 0 | std::shared_ptr<const Public_Key> Certificate_13::public_key() const { |
92 | 0 | BOTAN_STATE_CHECK(!empty()); |
93 | 0 | return m_entries.front().public_key(); |
94 | 0 | } |
95 | | |
96 | 0 | const X509_Certificate& Certificate_13::leaf() const { |
97 | 0 | BOTAN_STATE_CHECK(!empty()); |
98 | 0 | return m_entries.front().certificate(); |
99 | 0 | } |
100 | | |
101 | | void Certificate_13::verify(Callbacks& callbacks, |
102 | | const Policy& policy, |
103 | | Credentials_Manager& creds, |
104 | | std::string_view hostname, |
105 | 0 | bool use_ocsp) const { |
106 | 0 | const auto usage = (m_side == Connection_Side::Client) ? Usage_Type::TLS_CLIENT_AUTH : Usage_Type::TLS_SERVER_AUTH; |
107 | |
|
108 | 0 | if(is_raw_public_key()) { |
109 | 0 | callbacks.tls_verify_raw_public_key(*public_key(), usage, hostname, policy); |
110 | 0 | } else { |
111 | 0 | verify_certificate_chain(callbacks, policy, creds, hostname, use_ocsp, usage); |
112 | 0 | } |
113 | 0 | } |
114 | | |
115 | | void Certificate_13::verify_certificate_chain(Callbacks& callbacks, |
116 | | const Policy& policy, |
117 | | Credentials_Manager& creds, |
118 | | std::string_view hostname, |
119 | | bool use_ocsp, |
120 | 0 | Usage_Type usage_type) const { |
121 | 0 | std::vector<X509_Certificate> certs; |
122 | 0 | std::vector<std::optional<OCSP::Response>> ocsp_responses; |
123 | 0 | for(const auto& entry : m_entries) { |
124 | 0 | certs.push_back(entry.certificate()); |
125 | 0 | if(use_ocsp) { |
126 | 0 | if(entry.extensions().has<Certificate_Status_Request>()) { |
127 | 0 | ocsp_responses.push_back(callbacks.tls_parse_ocsp_response( |
128 | 0 | entry.extensions().get<Certificate_Status_Request>()->get_ocsp_response())); |
129 | 0 | } else { |
130 | 0 | ocsp_responses.emplace_back(); |
131 | 0 | } |
132 | 0 | } |
133 | 0 | } |
134 | |
|
135 | 0 | const auto& server_cert = m_entries.front().certificate(); |
136 | 0 | if(!certificate_allows_signing(server_cert)) { |
137 | 0 | throw TLS_Exception(Alert::BadCertificate, "Certificate usage constraints do not allow signing"); |
138 | 0 | } |
139 | | |
140 | | // Note that m_side represents the sender, so the usages here are swapped |
141 | 0 | const auto trusted_CAs = creds.trusted_certificate_authorities( |
142 | 0 | m_side == Connection_Side::Client ? "tls-server" : "tls-client", std::string(hostname)); |
143 | |
|
144 | 0 | callbacks.tls_verify_cert_chain(certs, ocsp_responses, trusted_CAs, usage_type, hostname, policy); |
145 | 0 | } |
146 | | |
147 | | void Certificate_13::setup_entries(std::vector<X509_Certificate> cert_chain, |
148 | | const Certificate_Status_Request* csr, |
149 | 0 | Callbacks& callbacks) { |
150 | | // RFC 8446 4.4.2.1 |
151 | | // A server MAY request that a client present an OCSP response with its |
152 | | // certificate by sending an empty "status_request" extension in its |
153 | | // CertificateRequest message. |
154 | 0 | const auto ocsp_responses = (csr != nullptr) ? callbacks.tls_provide_cert_chain_status(cert_chain, *csr) |
155 | 0 | : std::vector<std::vector<uint8_t>>(cert_chain.size()); |
156 | |
|
157 | 0 | if(ocsp_responses.size() != cert_chain.size()) { |
158 | 0 | throw TLS_Exception(Alert::InternalError, "Application didn't provide the correct number of OCSP responses"); |
159 | 0 | } |
160 | | |
161 | 0 | for(size_t i = 0; i < cert_chain.size(); ++i) { |
162 | 0 | auto& entry = m_entries.emplace_back(cert_chain[i]); |
163 | 0 | if(!ocsp_responses[i].empty()) { |
164 | 0 | entry.extensions().add(new Certificate_Status_Request(ocsp_responses[i])); |
165 | 0 | } |
166 | | |
167 | | // This will call the modification callback multiple times. Once for |
168 | | // each certificate in the `cert_chain`. Users that want to add an |
169 | | // extension to a specific Certificate Entry might have a hard time |
170 | | // to distinguish them. |
171 | | // |
172 | | // TODO: Callbacks::tls_modify_extensions() might need even more |
173 | | // context depending on the message whose extensions should be |
174 | | // manipulatable. |
175 | 0 | callbacks.tls_modify_extensions(entry.extensions(), m_side, type()); |
176 | 0 | } |
177 | 0 | } |
178 | | |
179 | 0 | void Certificate_13::setup_entry(std::shared_ptr<Public_Key> raw_public_key, Callbacks& callbacks) { |
180 | 0 | BOTAN_ASSERT_NONNULL(raw_public_key); |
181 | 0 | auto& entry = m_entries.emplace_back(std::move(raw_public_key)); |
182 | 0 | callbacks.tls_modify_extensions(entry.extensions(), m_side, type()); |
183 | 0 | } |
184 | | |
185 | | /** |
186 | | * Create a Client Certificate message |
187 | | */ |
188 | | Certificate_13::Certificate_13(const Certificate_Request_13& cert_request, |
189 | | std::string_view hostname, |
190 | | Credentials_Manager& credentials_manager, |
191 | | Callbacks& callbacks, |
192 | | Certificate_Type cert_type) : |
193 | 0 | m_request_context(cert_request.context()), m_side(Connection_Side::Client) { |
194 | 0 | const auto key_types = filter_signature_schemes(cert_request.signature_schemes()); |
195 | 0 | const auto op_type = "tls-client"; |
196 | |
|
197 | 0 | if(cert_type == Certificate_Type::X509) { |
198 | 0 | setup_entries( |
199 | 0 | credentials_manager.find_cert_chain(key_types, |
200 | 0 | to_algorithm_identifiers(cert_request.certificate_signature_schemes()), |
201 | 0 | cert_request.acceptable_CAs(), |
202 | 0 | op_type, |
203 | 0 | std::string(hostname)), |
204 | 0 | cert_request.extensions().get<Certificate_Status_Request>(), |
205 | 0 | callbacks); |
206 | 0 | } else if(cert_type == Certificate_Type::RawPublicKey) { |
207 | 0 | 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 | 0 | if(raw_public_key) { |
217 | 0 | setup_entry(std::move(raw_public_key), callbacks); |
218 | 0 | } |
219 | 0 | } |
220 | 0 | } |
221 | | |
222 | | /** |
223 | | * Create a Server Certificate message |
224 | | */ |
225 | | Certificate_13::Certificate_13(const Client_Hello_13& client_hello, |
226 | | Credentials_Manager& credentials_manager, |
227 | | Callbacks& callbacks, |
228 | | Certificate_Type cert_type) : |
229 | | // RFC 8446 4.4.2: |
230 | | // [In the case of server authentication], this field |
231 | | // SHALL be zero length |
232 | 0 | m_request_context(), m_side(Connection_Side::Server) { |
233 | 0 | BOTAN_ASSERT_NOMSG(client_hello.extensions().has<Signature_Algorithms>()); |
234 | |
|
235 | 0 | const auto key_types = filter_signature_schemes(client_hello.signature_schemes()); |
236 | 0 | const auto op_type = "tls-server"; |
237 | 0 | const auto context = client_hello.sni_hostname(); |
238 | |
|
239 | 0 | if(cert_type == Certificate_Type::X509) { |
240 | 0 | auto cert_chain = credentials_manager.find_cert_chain( |
241 | 0 | key_types, to_algorithm_identifiers(client_hello.certificate_signature_schemes()), {}, op_type, context); |
242 | | |
243 | | // RFC 8446 4.4.2 |
244 | | // The server's certificate_list MUST always be non-empty. |
245 | 0 | if(cert_chain.empty()) { |
246 | 0 | throw TLS_Exception(Alert::HandshakeFailure, "No sufficient server certificate available"); |
247 | 0 | } |
248 | | |
249 | 0 | setup_entries(std::move(cert_chain), client_hello.extensions().get<Certificate_Status_Request>(), callbacks); |
250 | 0 | } else if(cert_type == Certificate_Type::RawPublicKey) { |
251 | 0 | auto raw_public_key = credentials_manager.find_raw_public_key(key_types, op_type, context); |
252 | | |
253 | | // RFC 8446 4.4.2 |
254 | | // If the RawPublicKey certificate type was negotiated, then the |
255 | | // certificate_list MUST contain no more than one CertificateEntry |
256 | | // [...]. |
257 | | // The server's certificate_list MUST always be non-empty |
258 | 0 | if(!raw_public_key) { |
259 | 0 | throw TLS_Exception(Alert::HandshakeFailure, "No sufficient server raw public key available"); |
260 | 0 | } |
261 | | |
262 | 0 | setup_entry(std::move(raw_public_key), callbacks); |
263 | 0 | } |
264 | 0 | } |
265 | | |
266 | | Certificate_13::Certificate_Entry::Certificate_Entry(TLS_Data_Reader& reader, |
267 | | const Connection_Side side, |
268 | 2.40k | const Certificate_Type cert_type) { |
269 | 2.40k | switch(cert_type) { |
270 | 2.40k | case Certificate_Type::X509: |
271 | | // RFC 8446 4.2.2 |
272 | | // [...] each CertificateEntry contains a DER-encoded X.509 |
273 | | // certificate. |
274 | 2.40k | m_certificate = X509_Certificate(reader.get_tls_length_value(3)); |
275 | 2.40k | m_raw_public_key = m_certificate->subject_public_key(); |
276 | 2.40k | break; |
277 | 0 | case Certificate_Type::RawPublicKey: |
278 | | // RFC 7250 3. |
279 | | // This specification uses raw public keys whereby the already |
280 | | // available encoding used in a PKIX certificate in the form of a |
281 | | // SubjectPublicKeyInfo structure is reused. |
282 | 0 | m_raw_public_key = X509::load_key(reader.get_tls_length_value(3)); |
283 | 0 | break; |
284 | 0 | default: |
285 | 0 | throw TLS_Exception(Alert::InternalError, "Unknown certificate type"); |
286 | 2.40k | } |
287 | | |
288 | | // Extensions are simply tacked at the end of the certificate entry. This |
289 | | // is a departure from the typical "tag-length-value" in a sense that the |
290 | | // Extensions deserializer needs the length value of the extensions. |
291 | 0 | const auto extensions_length = reader.peek_uint16_t(); |
292 | 0 | const auto exts_buf = reader.get_fixed<uint8_t>(extensions_length + 2); |
293 | 0 | TLS_Data_Reader exts_reader("extensions reader", exts_buf); |
294 | 0 | m_extensions.deserialize(exts_reader, side, Handshake_Type::Certificate); |
295 | |
|
296 | 0 | if(cert_type == Certificate_Type::X509) { |
297 | | // RFC 8446 4.4.2 |
298 | | // Valid extensions for server certificates at present include the |
299 | | // OCSP Status extension [RFC6066] and the SignedCertificateTimestamp |
300 | | // extension [RFC6962]; future extensions may be defined for this |
301 | | // message as well. |
302 | | // |
303 | | // RFC 8446 4.4.2.1 |
304 | | // A server MAY request that a client present an OCSP response with its |
305 | | // certificate by sending an empty "status_request" extension in its |
306 | | // CertificateRequest message. |
307 | 0 | if(m_extensions.contains_implemented_extensions_other_than({ |
308 | 0 | Extension_Code::CertificateStatusRequest, |
309 | | // Extension_Code::SignedCertificateTimestamp |
310 | 0 | })) { |
311 | 0 | throw TLS_Exception(Alert::IllegalParameter, "Certificate Entry contained an extension that is not allowed"); |
312 | 0 | } |
313 | 0 | } else if(m_extensions.contains_implemented_extensions_other_than({})) { |
314 | 0 | throw TLS_Exception( |
315 | 0 | Alert::IllegalParameter, |
316 | 0 | "Certificate Entry holding something else than a certificate contained unexpected extensions"); |
317 | 0 | } |
318 | 0 | } |
319 | | |
320 | | Certificate_13::Certificate_Entry::Certificate_Entry(X509_Certificate cert) : |
321 | 0 | m_certificate(std::move(cert)), m_raw_public_key(m_certificate->subject_public_key()) {} |
322 | | |
323 | | Certificate_13::Certificate_Entry::Certificate_Entry(std::shared_ptr<Public_Key> raw_public_key) : |
324 | 0 | m_certificate(std::nullopt), m_raw_public_key(std::move(raw_public_key)) { |
325 | 0 | BOTAN_ASSERT_NONNULL(m_raw_public_key); |
326 | 0 | } |
327 | | |
328 | 0 | const X509_Certificate& Certificate_13::Certificate_Entry::certificate() const { |
329 | 0 | BOTAN_STATE_CHECK(has_certificate()); |
330 | 0 | return m_certificate.value(); |
331 | 0 | } |
332 | | |
333 | 0 | std::shared_ptr<const Public_Key> Certificate_13::Certificate_Entry::public_key() const { |
334 | 0 | BOTAN_ASSERT_NONNULL(m_raw_public_key); |
335 | 0 | return m_raw_public_key; |
336 | 0 | } |
337 | | |
338 | 0 | std::vector<uint8_t> Certificate_13::Certificate_Entry::serialize() const { |
339 | 0 | return (has_certificate()) ? m_certificate->BER_encode() : X509::BER_encode(*m_raw_public_key); |
340 | 0 | } |
341 | | |
342 | | /** |
343 | | * Deserialize a Certificate message |
344 | | */ |
345 | | Certificate_13::Certificate_13(const std::vector<uint8_t>& buf, |
346 | | const Policy& policy, |
347 | | Connection_Side side, |
348 | | Certificate_Type cert_type) : |
349 | 2.50k | m_side(side) { |
350 | 2.50k | TLS_Data_Reader reader("cert message reader", buf); |
351 | | |
352 | 2.50k | m_request_context = reader.get_range<uint8_t>(1, 0, 255); |
353 | | |
354 | | // RFC 8446 4.4.2 |
355 | | // [...] in the case of server authentication, this field SHALL be zero length. |
356 | 2.50k | if(m_side == Connection_Side::Server && !m_request_context.empty()) { |
357 | 13 | throw TLS_Exception(Alert::IllegalParameter, "Server Certificate message must not contain a request context"); |
358 | 13 | } |
359 | | |
360 | 2.49k | const auto cert_entries_len = reader.get_uint24_t(); |
361 | | |
362 | 2.49k | if(reader.remaining_bytes() != cert_entries_len) { |
363 | 73 | throw TLS_Exception(Alert::DecodeError, "Certificate: Message malformed"); |
364 | 73 | } |
365 | | |
366 | 2.42k | const size_t max_size = policy.maximum_certificate_chain_size(); |
367 | 2.42k | if(max_size > 0 && cert_entries_len > max_size) { |
368 | 0 | throw Decoding_Error("Certificate chain exceeds policy specified maximum size"); |
369 | 0 | } |
370 | | |
371 | 4.82k | while(reader.has_remaining()) { |
372 | 2.40k | m_entries.emplace_back(reader, side, cert_type); |
373 | 2.40k | } |
374 | | |
375 | | // RFC 8446 4.4.2 |
376 | | // The server's certificate_list MUST always be non-empty. A client |
377 | | // will send an empty certificate_list if it does not have an |
378 | | // appropriate certificate to send in response to the server's |
379 | | // authentication request. |
380 | 2.42k | if(m_entries.empty()) { |
381 | | // RFC 8446 4.4.2.4 |
382 | | // If the server supplies an empty Certificate message, the client MUST |
383 | | // abort the handshake with a "decode_error" alert. |
384 | 3 | if(m_side == Connection_Side::Server) { |
385 | 1 | throw TLS_Exception(Alert::DecodeError, "No certificates sent by server"); |
386 | 1 | } |
387 | | |
388 | 2 | return; |
389 | 3 | } |
390 | | |
391 | 2.41k | BOTAN_ASSERT_NOMSG(!m_entries.empty()); |
392 | | |
393 | | // RFC 8446 4.4.2.2 |
394 | | // The certificate type MUST be X.509v3 [RFC5280], unless explicitly |
395 | | // negotiated otherwise (e.g., [RFC7250]). |
396 | | // |
397 | | // TLS 1.0 through 1.3 all seem to require that the certificate be |
398 | | // precisely a v3 certificate. In fact the strict wording would seem |
399 | | // to require that every certificate in the chain be v3. But often |
400 | | // the intermediates are outside of the control of the server. |
401 | | // But, require that the leaf certificate be v3. |
402 | 2.41k | if(cert_type == Certificate_Type::X509 && m_entries.front().certificate().x509_version() != 3) { |
403 | 0 | throw TLS_Exception(Alert::BadCertificate, "The leaf certificate must be v3"); |
404 | 0 | } |
405 | | |
406 | | // RFC 8446 4.4.2 |
407 | | // If the RawPublicKey certificate type was negotiated, then the |
408 | | // certificate_list MUST contain no more than one CertificateEntry. |
409 | 2.41k | if(cert_type == Certificate_Type::RawPublicKey && m_entries.size() != 1) { |
410 | 0 | throw TLS_Exception(Alert::IllegalParameter, "Certificate message contained more than one RawPublicKey"); |
411 | 0 | } |
412 | | |
413 | | // Validate the provided (certificate) public key against our policy |
414 | 2.41k | auto pubkey = public_key(); |
415 | 2.41k | policy.check_peer_key_acceptable(*pubkey); |
416 | | |
417 | 2.41k | if(!policy.allowed_signature_method(pubkey->algo_name())) { |
418 | 0 | throw TLS_Exception(Alert::HandshakeFailure, "Rejecting " + pubkey->algo_name() + " signature"); |
419 | 0 | } |
420 | 2.41k | } |
421 | | |
422 | | /** |
423 | | * Serialize a Certificate message |
424 | | */ |
425 | 0 | std::vector<uint8_t> Certificate_13::serialize() const { |
426 | 0 | std::vector<uint8_t> buf; |
427 | |
|
428 | 0 | append_tls_length_value(buf, m_request_context, 1); |
429 | |
|
430 | 0 | std::vector<uint8_t> entries; |
431 | 0 | for(const auto& entry : m_entries) { |
432 | 0 | append_tls_length_value(entries, entry.serialize(), 3); |
433 | | |
434 | | // Extensions are tacked at the end of certificate entries. Note that |
435 | | // Extensions::serialize() usually emits the required length field, |
436 | | // except when no extensions are added at all, then it returns an |
437 | | // empty buffer. |
438 | | // |
439 | | // TODO: look into this issue more generally when overhauling the |
440 | | // message marshalling. |
441 | 0 | auto extensions = entry.extensions().serialize(m_side); |
442 | 0 | entries += (!extensions.empty()) ? extensions : std::vector<uint8_t>{0, 0}; |
443 | 0 | } |
444 | |
|
445 | 0 | append_tls_length_value(buf, entries, 3); |
446 | |
|
447 | 0 | return buf; |
448 | 0 | } |
449 | | |
450 | | } // namespace Botan::TLS |