Coverage Report

Created: 2023-11-19 06:25

/src/botan/src/lib/tls/tls_callbacks.cpp
Line
Count
Source (jump to first uncovered line)
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_KYBER)
30
   #include <botan/kyber.h>
31
#endif
32
33
#if defined(BOTAN_HAS_TLS_13_PQC)
34
   #include <botan/internal/hybrid_public_key.h>
35
#endif
36
37
namespace Botan {
38
39
105k
void TLS::Callbacks::tls_inspect_handshake_msg(const Handshake_Message& /*unused*/) {
40
   // default is no op
41
105k
}
42
43
0
std::string TLS::Callbacks::tls_server_choose_app_protocol(const std::vector<std::string>& /*unused*/) {
44
0
   return "";
45
0
}
46
47
4.03k
std::string TLS::Callbacks::tls_peer_network_identity() {
48
4.03k
   return "";
49
4.03k
}
50
51
47.1k
std::chrono::system_clock::time_point TLS::Callbacks::tls_current_timestamp() {
52
47.1k
   return std::chrono::system_clock::now();
53
47.1k
}
54
55
void TLS::Callbacks::tls_modify_extensions(Extensions& /*unused*/,
56
                                           Connection_Side /*unused*/,
57
23.4k
                                           Handshake_Type /*unused*/) {}
58
59
void TLS::Callbacks::tls_examine_extensions(const Extensions& /*unused*/,
60
                                            Connection_Side /*unused*/,
61
21.2k
                                            Handshake_Type /*unused*/) {}
62
63
207
bool TLS::Callbacks::tls_should_persist_resumption_information(const Session& session) {
64
   // RFC 5077 3.3
65
   //    The ticket_lifetime_hint field contains a hint from the server about
66
   //    how long the ticket should be stored. A value of zero is reserved to
67
   //    indicate that the lifetime of the ticket is unspecified.
68
   //
69
   // RFC 8446 4.6.1
70
   //    [A ticket_lifetime] of zero indicates that the ticket should be discarded
71
   //    immediately.
72
   //
73
   // By default we opt to keep all sessions, except for TLS 1.3 with a lifetime
74
   // hint of zero.
75
207
   return session.lifetime_hint().count() > 0 || session.version().is_pre_tls_13();
76
207
}
77
78
void TLS::Callbacks::tls_verify_cert_chain(const std::vector<X509_Certificate>& cert_chain,
79
                                           const std::vector<std::optional<OCSP::Response>>& ocsp_responses,
80
                                           const std::vector<Certificate_Store*>& trusted_roots,
81
                                           Usage_Type usage,
82
                                           std::string_view hostname,
83
0
                                           const TLS::Policy& policy) {
84
0
   if(cert_chain.empty()) {
85
0
      throw Invalid_Argument("Certificate chain was empty");
86
0
   }
87
88
0
   Path_Validation_Restrictions restrictions(policy.require_cert_revocation_info(),
89
0
                                             policy.minimum_signature_strength());
90
91
0
   Path_Validation_Result result = x509_path_validate(cert_chain,
92
0
                                                      restrictions,
93
0
                                                      trusted_roots,
94
0
                                                      (usage == Usage_Type::TLS_SERVER_AUTH ? hostname : ""),
95
0
                                                      usage,
96
0
                                                      tls_current_timestamp(),
97
0
                                                      tls_verify_cert_chain_ocsp_timeout(),
98
0
                                                      ocsp_responses);
99
100
0
   if(!result.successful_validation()) {
101
0
      throw TLS_Exception(Alert::BadCertificate, "Certificate validation failure: " + result.result_string());
102
0
   }
103
0
}
104
105
void TLS::Callbacks::tls_verify_raw_public_key(const Public_Key& raw_public_key,
106
                                               Usage_Type usage,
107
                                               std::string_view hostname,
108
0
                                               const TLS::Policy& policy) {
109
0
   BOTAN_UNUSED(raw_public_key, usage, hostname, policy);
110
   // There is no good default implementation for authenticating raw public key.
111
   // Applications that wish to use them for authentication, must override this.
112
0
   throw TLS_Exception(Alert::CertificateUnknown, "Application did not provide a means to validate the raw public key");
113
0
}
114
115
0
std::optional<OCSP::Response> TLS::Callbacks::tls_parse_ocsp_response(const std::vector<uint8_t>& raw_response) {
116
0
   try {
117
0
      return OCSP::Response(raw_response);
118
0
   } catch(const Decoding_Error&) {
119
      // ignore parsing errors and just ignore the broken OCSP response
120
0
      return std::nullopt;
121
0
   }
122
0
}
123
124
std::vector<std::vector<uint8_t>> TLS::Callbacks::tls_provide_cert_chain_status(
125
0
   const std::vector<X509_Certificate>& chain, const Certificate_Status_Request& csr) {
126
0
   std::vector<std::vector<uint8_t>> result(chain.size());
127
0
   if(!chain.empty()) {
128
0
      result[0] = tls_provide_cert_status(chain, csr);
129
0
   }
130
0
   return result;
131
0
}
132
133
std::vector<uint8_t> TLS::Callbacks::tls_sign_message(const Private_Key& key,
134
                                                      RandomNumberGenerator& rng,
135
                                                      std::string_view padding,
136
                                                      Signature_Format format,
137
0
                                                      const std::vector<uint8_t>& msg) {
138
0
   PK_Signer signer(key, rng, padding, format);
139
140
0
   return signer.sign_message(msg, rng);
141
0
}
142
143
bool TLS::Callbacks::tls_verify_message(const Public_Key& key,
144
                                        std::string_view padding,
145
                                        Signature_Format format,
146
                                        const std::vector<uint8_t>& msg,
147
0
                                        const std::vector<uint8_t>& sig) {
148
0
   PK_Verifier verifier(key, padding, format);
149
150
0
   return verifier.verify_message(msg, sig);
151
0
}
152
153
0
std::unique_ptr<Private_Key> TLS::Callbacks::tls_kem_generate_key(TLS::Group_Params group, RandomNumberGenerator& rng) {
154
0
#if defined(BOTAN_HAS_KYBER)
155
0
   if(group.is_pure_kyber()) {
156
0
      return std::make_unique<Kyber_PrivateKey>(rng, KyberMode(group.to_string().value()));
157
0
   }
158
0
#endif
159
160
0
#if defined(BOTAN_HAS_TLS_13_PQC)
161
0
   if(group.is_pqc_hybrid()) {
162
0
      return Hybrid_KEM_PrivateKey::generate_from_group(group, rng);
163
0
   }
164
0
#endif
165
166
0
   return tls_generate_ephemeral_key(group, rng);
167
0
}
168
169
KEM_Encapsulation TLS::Callbacks::tls_kem_encapsulate(TLS::Group_Params group,
170
                                                      const std::vector<uint8_t>& encoded_public_key,
171
                                                      RandomNumberGenerator& rng,
172
0
                                                      const Policy& policy) {
173
0
   if(group.is_kem()) {
174
0
      auto kem_pub_key = [&]() -> std::unique_ptr<Public_Key> {
175
176
0
#if defined(BOTAN_HAS_TLS_13_PQC)
177
0
         if(group.is_pqc_hybrid()) {
178
0
            return Hybrid_KEM_PublicKey::load_for_group(group, encoded_public_key);
179
0
         }
180
0
#endif
181
182
0
#if defined(BOTAN_HAS_KYBER)
183
0
         if(group.is_pure_kyber()) {
184
0
            return std::make_unique<Kyber_PublicKey>(encoded_public_key, KyberMode(group.to_string().value()));
185
0
         }
186
0
#endif
187
188
0
         throw TLS_Exception(Alert::IllegalParameter, "KEM is not supported");
189
0
      }();
190
191
0
      return PK_KEM_Encryptor(*kem_pub_key, "Raw").encrypt(rng);
192
0
   }
193
194
   // TODO: We could use the KEX_to_KEM_Adapter to remove the case distinction
195
   //       of KEM and KEX. However, the workarounds in this adapter class
196
   //       should first be addressed.
197
0
   auto ephemeral_keypair = tls_generate_ephemeral_key(group, rng);
198
0
   return KEM_Encapsulation(ephemeral_keypair->public_value(),
199
0
                            tls_ephemeral_key_agreement(group, *ephemeral_keypair, encoded_public_key, rng, policy));
200
0
}
201
202
secure_vector<uint8_t> TLS::Callbacks::tls_kem_decapsulate(TLS::Group_Params group,
203
                                                           const Private_Key& private_key,
204
                                                           const std::vector<uint8_t>& encapsulated_bytes,
205
                                                           RandomNumberGenerator& rng,
206
0
                                                           const Policy& policy) {
207
0
   if(group.is_kem()) {
208
0
      PK_KEM_Decryptor kemdec(private_key, rng, "Raw");
209
0
      return kemdec.decrypt(encapsulated_bytes, 0, {});
210
0
   }
211
212
0
   try {
213
0
      auto& key_agreement_key = dynamic_cast<const PK_Key_Agreement_Key&>(private_key);
214
0
      return tls_ephemeral_key_agreement(group, key_agreement_key, encapsulated_bytes, rng, policy);
215
0
   } catch(const std::bad_cast&) {
216
0
      throw Invalid_Argument("provided ephemeral key is not a PK_Key_Agreement_Key");
217
0
   }
218
0
}
219
220
namespace {
221
222
33.3k
bool is_dh_group(const std::variant<TLS::Group_Params, DL_Group>& group) {
223
33.3k
   return std::holds_alternative<DL_Group>(group) || std::get<TLS::Group_Params>(group).is_dh_named_group();
224
33.3k
}
225
226
0
DL_Group get_dl_group(const std::variant<TLS::Group_Params, DL_Group>& group) {
227
0
   BOTAN_ASSERT_NOMSG(is_dh_group(group));
228
229
   // TLS 1.2 allows specifying arbitrary DL_Group parameters in-lieu of
230
   // a standardized DH group identifier. TLS 1.3 just offers pre-defined
231
   // groups.
232
0
   return std::visit(
233
0
      overloaded{[](const DL_Group& dl_group) { return dl_group; },
234
0
                 [&](TLS::Group_Params group_param) { return DL_Group(group_param.to_string().value()); }},
235
0
      group);
236
0
}
237
238
}  // namespace
239
240
std::unique_ptr<PK_Key_Agreement_Key> TLS::Callbacks::tls_generate_ephemeral_key(
241
19.1k
   const std::variant<TLS::Group_Params, DL_Group>& group, RandomNumberGenerator& rng) {
242
19.1k
   if(is_dh_group(group)) {
243
0
      const DL_Group dl_group = get_dl_group(group);
244
0
      return std::make_unique<DH_PrivateKey>(rng, dl_group);
245
0
   }
246
247
19.1k
   BOTAN_ASSERT_NOMSG(std::holds_alternative<TLS::Group_Params>(group));
248
19.1k
   const auto group_params = std::get<TLS::Group_Params>(group);
249
250
19.1k
   if(group_params.is_ecdh_named_curve()) {
251
18.6k
      const EC_Group ec_group(group_params.to_string().value());
252
18.6k
      return std::make_unique<ECDH_PrivateKey>(rng, ec_group);
253
18.6k
   }
254
255
586
#if defined(BOTAN_HAS_CURVE_25519)
256
586
   if(group_params.is_x25519()) {
257
586
      return std::make_unique<X25519_PrivateKey>(rng);
258
586
   }
259
0
#endif
260
261
0
   if(group_params.is_kem()) {
262
0
      throw TLS_Exception(Alert::IllegalParameter, "cannot generate an ephemeral KEX key for a KEM");
263
0
   }
264
265
0
   throw TLS_Exception(Alert::DecodeError, "cannot create a key offering without a group definition");
266
0
}
267
268
secure_vector<uint8_t> TLS::Callbacks::tls_ephemeral_key_agreement(
269
   const std::variant<TLS::Group_Params, DL_Group>& group,
270
   const PK_Key_Agreement_Key& private_key,
271
   const std::vector<uint8_t>& public_value,
272
   RandomNumberGenerator& rng,
273
14.1k
   const Policy& policy) {
274
14.1k
   auto agree = [&](const PK_Key_Agreement_Key& sk, const auto& pk) {
275
8.30k
      PK_Key_Agreement ka(sk, rng, "Raw");
276
8.30k
      return ka.derive_key(0, pk.public_value()).bits_of();
277
8.30k
   };
Unexecuted instantiation: tls_callbacks.cpp:auto Botan::TLS::Callbacks::tls_ephemeral_key_agreement(std::__1::variant<Botan::TLS::Group_Params, Botan::DL_Group> const&, Botan::PK_Key_Agreement_Key const&, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> > const&, Botan::RandomNumberGenerator&, Botan::TLS::Policy const&)::$_2::operator()<Botan::DH_PublicKey>(Botan::PK_Key_Agreement_Key const&, Botan::DH_PublicKey const&) const
tls_callbacks.cpp:auto Botan::TLS::Callbacks::tls_ephemeral_key_agreement(std::__1::variant<Botan::TLS::Group_Params, Botan::DL_Group> const&, Botan::PK_Key_Agreement_Key const&, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> > const&, Botan::RandomNumberGenerator&, Botan::TLS::Policy const&)::$_2::operator()<Botan::ECDH_PublicKey>(Botan::PK_Key_Agreement_Key const&, Botan::ECDH_PublicKey const&) const
Line
Count
Source
274
8.30k
   auto agree = [&](const PK_Key_Agreement_Key& sk, const auto& pk) {
275
8.30k
      PK_Key_Agreement ka(sk, rng, "Raw");
276
8.30k
      return ka.derive_key(0, pk.public_value()).bits_of();
277
8.30k
   };
tls_callbacks.cpp:auto Botan::TLS::Callbacks::tls_ephemeral_key_agreement(std::__1::variant<Botan::TLS::Group_Params, Botan::DL_Group> const&, Botan::PK_Key_Agreement_Key const&, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> > const&, Botan::RandomNumberGenerator&, Botan::TLS::Policy const&)::$_2::operator()<Botan::Curve25519_PublicKey>(Botan::PK_Key_Agreement_Key const&, Botan::Curve25519_PublicKey const&) const
Line
Count
Source
274
1
   auto agree = [&](const PK_Key_Agreement_Key& sk, const auto& pk) {
275
1
      PK_Key_Agreement ka(sk, rng, "Raw");
276
1
      return ka.derive_key(0, pk.public_value()).bits_of();
277
1
   };
278
279
14.1k
   if(is_dh_group(group)) {
280
      // TLS 1.2 allows specifying arbitrary DL_Group parameters in-lieu of
281
      // a standardized DH group identifier.
282
0
      const auto dl_group = get_dl_group(group);
283
284
0
      auto Y = BigInt::decode(public_value);
285
286
      /*
287
       * A basic check for key validity. As we do not know q here we
288
       * cannot check that Y is in the right subgroup. However since
289
       * our key is ephemeral there does not seem to be any
290
       * advantage to bogus keys anyway.
291
       */
292
0
      if(Y <= 1 || Y >= dl_group.get_p() - 1) {
293
0
         throw TLS_Exception(Alert::IllegalParameter, "Server sent bad DH key for DHE exchange");
294
0
      }
295
296
0
      DH_PublicKey peer_key(dl_group, Y);
297
0
      policy.check_peer_key_acceptable(peer_key);
298
299
0
      return agree(private_key, peer_key);
300
0
   }
301
302
14.1k
   BOTAN_ASSERT_NOMSG(std::holds_alternative<TLS::Group_Params>(group));
303
14.1k
   const auto group_params = std::get<TLS::Group_Params>(group);
304
305
14.1k
   if(group_params.is_ecdh_named_curve()) {
306
14.1k
      const EC_Group ec_group(group_params.to_string().value());
307
14.1k
      ECDH_PublicKey peer_key(ec_group, ec_group.OS2ECP(public_value));
308
14.1k
      policy.check_peer_key_acceptable(peer_key);
309
310
14.1k
      return agree(private_key, peer_key);
311
14.1k
   }
312
313
4
#if defined(BOTAN_HAS_CURVE_25519)
314
4
   if(group_params.is_x25519()) {
315
4
      if(public_value.size() != 32) {
316
3
         throw TLS_Exception(Alert::HandshakeFailure, "Invalid X25519 key size");
317
3
      }
318
319
1
      Curve25519_PublicKey peer_key(public_value);
320
1
      policy.check_peer_key_acceptable(peer_key);
321
322
1
      return agree(private_key, peer_key);
323
4
   }
324
0
#endif
325
326
0
   throw TLS_Exception(Alert::IllegalParameter, "Did not recognize the key exchange group");
327
4
}
328
329
}  // namespace Botan