Botan 3.4.0
Crypto and TLS for C&
tls_callbacks.cpp
Go to the documentation of this file.
1/*
2* TLS Callbacks
3* (C) 2016 Jack Lloyd
4* 2017 Harry Reimann, Rohde & Schwarz Cybersecurity
5* 2022 René Meusel, Hannes Rantzsch - neXenio GmbH
6* 2023 René Meusel - Rohde & Schwarz Cybersecurity
7*
8* Botan is released under the Simplified BSD License (see license.txt)
9*/
10
11#include <botan/tls_callbacks.h>
12
13#include <botan/dh.h>
14#include <botan/dl_group.h>
15#include <botan/ecdh.h>
16#include <botan/ocsp.h>
17#include <botan/pk_algs.h>
18#include <botan/tls_algos.h>
19#include <botan/tls_exceptn.h>
20#include <botan/tls_policy.h>
21#include <botan/x509path.h>
22#include <botan/internal/ct_utils.h>
23#include <botan/internal/stl_util.h>
24
25#if defined(BOTAN_HAS_CURVE_25519)
26 #include <botan/curve25519.h>
27#endif
28
29#if defined(BOTAN_HAS_X448)
30 #include <botan/x448.h>
31#endif
32
33#if defined(BOTAN_HAS_KYBER)
34 #include <botan/kyber.h>
35#endif
36
37#if defined(BOTAN_HAS_FRODOKEM)
38 #include <botan/frodokem.h>
39#endif
40
41#if defined(BOTAN_HAS_TLS_13_PQC)
42 #include <botan/internal/hybrid_public_key.h>
43#endif
44
45namespace Botan {
46
48 // default is no op
49}
50
51std::string TLS::Callbacks::tls_server_choose_app_protocol(const std::vector<std::string>& /*unused*/) {
52 return "";
53}
54
56 return "";
57}
58
59std::chrono::system_clock::time_point TLS::Callbacks::tls_current_timestamp() {
60 return std::chrono::system_clock::now();
61}
62
64 Connection_Side /*unused*/,
65 Handshake_Type /*unused*/) {}
66
68 Connection_Side /*unused*/,
69 Handshake_Type /*unused*/) {}
70
72 // RFC 5077 3.3
73 // The ticket_lifetime_hint field contains a hint from the server about
74 // how long the ticket should be stored. A value of zero is reserved to
75 // indicate that the lifetime of the ticket is unspecified.
76 //
77 // RFC 8446 4.6.1
78 // [A ticket_lifetime] of zero indicates that the ticket should be discarded
79 // immediately.
80 //
81 // By default we opt to keep all sessions, except for TLS 1.3 with a lifetime
82 // hint of zero.
83 return session.lifetime_hint().count() > 0 || session.version().is_pre_tls_13();
84}
85
86void TLS::Callbacks::tls_verify_cert_chain(const std::vector<X509_Certificate>& cert_chain,
87 const std::vector<std::optional<OCSP::Response>>& ocsp_responses,
88 const std::vector<Certificate_Store*>& trusted_roots,
89 Usage_Type usage,
90 std::string_view hostname,
91 const TLS::Policy& policy) {
92 if(cert_chain.empty()) {
93 throw Invalid_Argument("Certificate chain was empty");
94 }
95
98
100 restrictions,
101 trusted_roots,
102 (usage == Usage_Type::TLS_SERVER_AUTH ? hostname : ""),
103 usage,
104 tls_current_timestamp(),
105 tls_verify_cert_chain_ocsp_timeout(),
106 ocsp_responses);
107
108 if(!result.successful_validation()) {
109 throw TLS_Exception(Alert::BadCertificate, "Certificate validation failure: " + result.result_string());
110 }
111}
112
114 Usage_Type usage,
115 std::string_view hostname,
116 const TLS::Policy& policy) {
117 BOTAN_UNUSED(raw_public_key, usage, hostname, policy);
118 // There is no good default implementation for authenticating raw public key.
119 // Applications that wish to use them for authentication, must override this.
120 throw TLS_Exception(Alert::CertificateUnknown, "Application did not provide a means to validate the raw public key");
121}
122
123std::optional<OCSP::Response> TLS::Callbacks::tls_parse_ocsp_response(const std::vector<uint8_t>& raw_response) {
124 try {
125 return OCSP::Response(raw_response);
126 } catch(const Decoding_Error&) {
127 // ignore parsing errors and just ignore the broken OCSP response
128 return std::nullopt;
129 }
130}
131
132std::vector<std::vector<uint8_t>> TLS::Callbacks::tls_provide_cert_chain_status(
133 const std::vector<X509_Certificate>& chain, const Certificate_Status_Request& csr) {
134 std::vector<std::vector<uint8_t>> result(chain.size());
135 if(!chain.empty()) {
136 result[0] = tls_provide_cert_status(chain, csr);
137 }
138 return result;
139}
140
141std::vector<uint8_t> TLS::Callbacks::tls_sign_message(const Private_Key& key,
143 std::string_view padding,
144 Signature_Format format,
145 const std::vector<uint8_t>& msg) {
146 PK_Signer signer(key, rng, padding, format);
147
148 return signer.sign_message(msg, rng);
149}
150
152 std::string_view padding,
153 Signature_Format format,
154 const std::vector<uint8_t>& msg,
155 const std::vector<uint8_t>& sig) {
156 PK_Verifier verifier(key, padding, format);
157
158 return verifier.verify_message(msg, sig);
159}
160
162#if defined(BOTAN_HAS_KYBER)
163 if(group.is_pure_kyber()) {
164 return std::make_unique<Kyber_PrivateKey>(rng, KyberMode(group.to_string().value()));
165 }
166#endif
167
168#if defined(BOTAN_HAS_FRODOKEM)
169 if(group.is_pure_frodokem()) {
170 return std::make_unique<FrodoKEM_PrivateKey>(rng, FrodoKEMMode(group.to_string().value()));
171 }
172#endif
173
174#if defined(BOTAN_HAS_TLS_13_PQC)
175 if(group.is_pqc_hybrid()) {
177 }
178#endif
179
180 return tls_generate_ephemeral_key(group, rng);
181}
182
184 const std::vector<uint8_t>& encoded_public_key,
186 const Policy& policy) {
187 if(group.is_kem()) {
188 auto kem_pub_key = [&]() -> std::unique_ptr<Public_Key> {
189
190#if defined(BOTAN_HAS_TLS_13_PQC)
191 if(group.is_pqc_hybrid()) {
192 return Hybrid_KEM_PublicKey::load_for_group(group, encoded_public_key);
193 }
194#endif
195
196#if defined(BOTAN_HAS_KYBER)
197 if(group.is_pure_kyber()) {
198 return std::make_unique<Kyber_PublicKey>(encoded_public_key, KyberMode(group.to_string().value()));
199 }
200#endif
201
202#if defined(BOTAN_HAS_FRODOKEM)
203 if(group.is_pure_frodokem()) {
204 return std::make_unique<FrodoKEM_PublicKey>(encoded_public_key, FrodoKEMMode(group.to_string().value()));
205 }
206#endif
207
208 throw TLS_Exception(Alert::IllegalParameter, "KEM is not supported");
209 }();
210
211 return PK_KEM_Encryptor(*kem_pub_key, "Raw").encrypt(rng);
212 }
213
214 // TODO: We could use the KEX_to_KEM_Adapter to remove the case distinction
215 // of KEM and KEX. However, the workarounds in this adapter class
216 // should first be addressed.
217 auto ephemeral_keypair = tls_generate_ephemeral_key(group, rng);
218 return KEM_Encapsulation(ephemeral_keypair->public_value(),
219 tls_ephemeral_key_agreement(group, *ephemeral_keypair, encoded_public_key, rng, policy));
220}
221
223 const Private_Key& private_key,
224 const std::vector<uint8_t>& encapsulated_bytes,
226 const Policy& policy) {
227 if(group.is_kem()) {
228 PK_KEM_Decryptor kemdec(private_key, rng, "Raw");
229 return kemdec.decrypt(encapsulated_bytes, 0, {});
230 }
231
232 try {
233 auto& key_agreement_key = dynamic_cast<const PK_Key_Agreement_Key&>(private_key);
234 return tls_ephemeral_key_agreement(group, key_agreement_key, encapsulated_bytes, rng, policy);
235 } catch(const std::bad_cast&) {
236 throw Invalid_Argument("provided ephemeral key is not a PK_Key_Agreement_Key");
237 }
238}
239
240namespace {
241
242bool is_dh_group(const std::variant<TLS::Group_Params, DL_Group>& group) {
243 return std::holds_alternative<DL_Group>(group) || std::get<TLS::Group_Params>(group).is_dh_named_group();
244}
245
246DL_Group get_dl_group(const std::variant<TLS::Group_Params, DL_Group>& group) {
247 BOTAN_ASSERT_NOMSG(is_dh_group(group));
248
249 // TLS 1.2 allows specifying arbitrary DL_Group parameters in-lieu of
250 // a standardized DH group identifier. TLS 1.3 just offers pre-defined
251 // groups.
252 return std::visit(
253 overloaded{[](const DL_Group& dl_group) { return dl_group; },
254 [&](TLS::Group_Params group_param) { return DL_Group(group_param.to_string().value()); }},
255 group);
256}
257
258} // namespace
259
260std::unique_ptr<PK_Key_Agreement_Key> TLS::Callbacks::tls_generate_ephemeral_key(
261 const std::variant<TLS::Group_Params, DL_Group>& group, RandomNumberGenerator& rng) {
262 if(is_dh_group(group)) {
263 const DL_Group dl_group = get_dl_group(group);
264 return std::make_unique<DH_PrivateKey>(rng, dl_group);
265 }
266
267 BOTAN_ASSERT_NOMSG(std::holds_alternative<TLS::Group_Params>(group));
268 const auto group_params = std::get<TLS::Group_Params>(group);
269
270 if(group_params.is_ecdh_named_curve()) {
271 const EC_Group ec_group(group_params.to_string().value());
272 return std::make_unique<ECDH_PrivateKey>(rng, ec_group);
273 }
274
275#if defined(BOTAN_HAS_CURVE_25519)
276 if(group_params.is_x25519()) {
277 return std::make_unique<X25519_PrivateKey>(rng);
278 }
279#endif
280
281#if defined(BOTAN_HAS_X448)
282 if(group_params.is_x448()) {
283 return std::make_unique<X448_PrivateKey>(rng);
284 }
285#endif
286
287 if(group_params.is_kem()) {
288 throw TLS_Exception(Alert::IllegalParameter, "cannot generate an ephemeral KEX key for a KEM");
289 }
290
291 throw TLS_Exception(Alert::DecodeError, "cannot create a key offering without a group definition");
292}
293
295 const std::variant<TLS::Group_Params, DL_Group>& group,
296 const PK_Key_Agreement_Key& private_key,
297 const std::vector<uint8_t>& public_value,
299 const Policy& policy) {
300 auto agree = [&](const PK_Key_Agreement_Key& sk, const auto& pk) {
301 PK_Key_Agreement ka(sk, rng, "Raw");
302 return ka.derive_key(0, pk.public_value()).bits_of();
303 };
304
305 if(is_dh_group(group)) {
306 // TLS 1.2 allows specifying arbitrary DL_Group parameters in-lieu of
307 // a standardized DH group identifier.
308 const auto dl_group = get_dl_group(group);
309
310 auto Y = BigInt::decode(public_value);
311
312 /*
313 * A basic check for key validity. As we do not know q here we
314 * cannot check that Y is in the right subgroup. However since
315 * our key is ephemeral there does not seem to be any
316 * advantage to bogus keys anyway.
317 */
318 if(Y <= 1 || Y >= dl_group.get_p() - 1) {
319 throw TLS_Exception(Alert::IllegalParameter, "Server sent bad DH key for DHE exchange");
320 }
321
322 DH_PublicKey peer_key(dl_group, Y);
323 policy.check_peer_key_acceptable(peer_key);
324
325 return agree(private_key, peer_key);
326 }
327
328 BOTAN_ASSERT_NOMSG(std::holds_alternative<TLS::Group_Params>(group));
329 const auto group_params = std::get<TLS::Group_Params>(group);
330
331 if(group_params.is_ecdh_named_curve()) {
332 const EC_Group ec_group(group_params.to_string().value());
333 ECDH_PublicKey peer_key(ec_group, ec_group.OS2ECP(public_value));
334 policy.check_peer_key_acceptable(peer_key);
335
336 return agree(private_key, peer_key);
337 }
338
339#if defined(BOTAN_HAS_CURVE_25519)
340 if(group_params.is_x25519()) {
341 if(public_value.size() != 32) {
342 throw TLS_Exception(Alert::HandshakeFailure, "Invalid X25519 key size");
343 }
344
345 Curve25519_PublicKey peer_key(public_value);
346 policy.check_peer_key_acceptable(peer_key);
347
348 return agree(private_key, peer_key);
349 }
350#endif
351
352#if defined(BOTAN_HAS_X448)
353 if(group_params.is_x448()) {
354 if(public_value.size() != 56) {
355 throw TLS_Exception(Alert::HandshakeFailure, "Invalid X448 key size");
356 }
357
358 X448_PublicKey peer_key(public_value);
359 policy.check_peer_key_acceptable(peer_key);
360
361 return agree(private_key, peer_key);
362 }
363#endif
364
365 throw TLS_Exception(Alert::IllegalParameter, "Did not recognize the key exchange group");
366}
367
368} // namespace Botan
#define BOTAN_UNUSED
Definition assert.h:118
#define BOTAN_ASSERT_NOMSG(expr)
Definition assert.h:59
static BigInt decode(const uint8_t buf[], size_t length)
Definition bigint.h:773
EC_Point OS2ECP(const uint8_t bits[], size_t len) const
Definition ec_group.cpp:561
secure_vector< uint8_t > bits_of() const
Definition symkey.h:36
void decrypt(std::span< uint8_t > out_shared_key, std::span< const uint8_t > encap_key, size_t desired_shared_key_len=32, std::span< const uint8_t > salt={})
Definition pubkey.cpp:190
KEM_Encapsulation encrypt(RandomNumberGenerator &rng, size_t desired_shared_key_len=32, std::span< const uint8_t > salt={})
Definition pubkey.h:651
SymmetricKey derive_key(size_t key_len, const uint8_t in[], size_t in_len, const uint8_t params[], size_t params_len) const
Definition pubkey.cpp:231
std::vector< uint8_t > sign_message(const uint8_t in[], size_t length, RandomNumberGenerator &rng)
Definition pubkey.h:186
bool verify_message(const uint8_t msg[], size_t msg_length, const uint8_t sig[], size_t sig_length)
Definition pubkey.cpp:368
std::string result_string() const
virtual std::string tls_peer_network_identity()
virtual void tls_modify_extensions(Extensions &extn, Connection_Side which_side, Handshake_Type which_message)
virtual std::vector< std::vector< uint8_t > > tls_provide_cert_chain_status(const std::vector< X509_Certificate > &chain, const Certificate_Status_Request &csr)
virtual std::string tls_server_choose_app_protocol(const std::vector< std::string > &client_protos)
virtual std::optional< OCSP::Response > tls_parse_ocsp_response(const std::vector< uint8_t > &raw_response)
virtual void tls_examine_extensions(const Extensions &extn, Connection_Side which_side, Handshake_Type which_message)
virtual std::vector< uint8_t > tls_sign_message(const Private_Key &key, RandomNumberGenerator &rng, std::string_view padding, Signature_Format format, const std::vector< uint8_t > &msg)
virtual void tls_verify_raw_public_key(const Public_Key &raw_public_key, Usage_Type usage, std::string_view hostname, const TLS::Policy &policy)
virtual KEM_Encapsulation tls_kem_encapsulate(TLS::Group_Params group, const std::vector< uint8_t > &encoded_public_key, RandomNumberGenerator &rng, const Policy &policy)
virtual bool tls_should_persist_resumption_information(const Session &session)
virtual std::unique_ptr< Private_Key > tls_kem_generate_key(TLS::Group_Params group, RandomNumberGenerator &rng)
virtual secure_vector< uint8_t > tls_ephemeral_key_agreement(const std::variant< TLS::Group_Params, DL_Group > &group, const PK_Key_Agreement_Key &private_key, const std::vector< uint8_t > &public_value, RandomNumberGenerator &rng, const Policy &policy)
virtual secure_vector< uint8_t > tls_kem_decapsulate(TLS::Group_Params group, const Private_Key &private_key, const std::vector< uint8_t > &encapsulated_bytes, RandomNumberGenerator &rng, const Policy &policy)
virtual std::chrono::system_clock::time_point tls_current_timestamp()
virtual std::unique_ptr< PK_Key_Agreement_Key > tls_generate_ephemeral_key(const std::variant< TLS::Group_Params, DL_Group > &group, RandomNumberGenerator &rng)
virtual void tls_verify_cert_chain(const std::vector< X509_Certificate > &cert_chain, const std::vector< std::optional< OCSP::Response > > &ocsp_responses, const std::vector< Certificate_Store * > &trusted_roots, Usage_Type usage, std::string_view hostname, const TLS::Policy &policy)
virtual bool tls_verify_message(const Public_Key &key, std::string_view padding, Signature_Format format, const std::vector< uint8_t > &msg, const std::vector< uint8_t > &sig)
virtual void tls_inspect_handshake_msg(const Handshake_Message &message)
constexpr bool is_pqc_hybrid() const
Definition tls_algos.h:215
constexpr bool is_kem() const
Definition tls_algos.h:236
constexpr bool is_pure_frodokem() const
Definition tls_algos.h:202
constexpr bool is_pure_kyber() const
Definition tls_algos.h:197
std::optional< std::string > to_string() const
static std::unique_ptr< Hybrid_KEM_PrivateKey > generate_from_group(Group_Params group, RandomNumberGenerator &rng)
static std::unique_ptr< Hybrid_KEM_PublicKey > load_for_group(Group_Params group, std::span< const uint8_t > concatenated_public_values)
virtual void check_peer_key_acceptable(const Public_Key &public_key) const
virtual bool require_cert_revocation_info() const
virtual size_t minimum_signature_strength() const
Protocol_Version version() const
std::chrono::seconds lifetime_hint() const
A public key for the X448 key agreement scheme according to RFC 7748.
Definition x448.h:19
FE_25519 Y
Definition ge.cpp:26
Path_Validation_Result x509_path_validate(const std::vector< X509_Certificate > &end_certs, const Path_Validation_Restrictions &restrictions, const std::vector< Certificate_Store * > &trusted_roots, std::string_view hostname, Usage_Type usage, std::chrono::system_clock::time_point ref_time, std::chrono::milliseconds ocsp_timeout, const std::vector< std::optional< OCSP::Response > > &ocsp_resp)
Definition x509path.cpp:850
Usage_Type
Definition x509cert.h:22
std::vector< T, secure_allocator< T > > secure_vector
Definition secmem.h:61
Signature_Format
Definition pk_keys.h:31