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

randombit / botan / 5445949942

03 Jul 2023 03:00PM UTC coverage: 91.732% (-0.006%) from 91.738%
5445949942

push

github

web-flow
Merge pull request #3608 from Rohde-Schwarz/tls13/kem_callbacks

[TLS 1.3] Use a KEM interface in the Callbacks

78216 of 85266 relevant lines covered (91.73%)

12304512.79 hits per line

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

85.71
/src/lib/tls/tls_callbacks.cpp
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
namespace Botan {
30

31
void TLS::Callbacks::tls_inspect_handshake_msg(const Handshake_Message& /*unused*/) {
6,315✔
32
   // default is no op
33
}
6,315✔
34

35
std::string TLS::Callbacks::tls_server_choose_app_protocol(const std::vector<std::string>& /*unused*/) {
×
36
   return "";
×
37
}
38

39
std::string TLS::Callbacks::tls_peer_network_identity() {
734✔
40
   return "";
734✔
41
}
42

43
std::chrono::system_clock::time_point TLS::Callbacks::tls_current_timestamp() {
5,077✔
44
   return std::chrono::system_clock::now();
5,077✔
45
}
46

47
void TLS::Callbacks::tls_modify_extensions(Extensions& /*unused*/,
5,566✔
48
                                           Connection_Side /*unused*/,
49
                                           Handshake_Type /*unused*/) {}
5,566✔
50

51
void TLS::Callbacks::tls_examine_extensions(const Extensions& /*unused*/,
4,080✔
52
                                            Connection_Side /*unused*/,
53
                                            Handshake_Type /*unused*/) {}
4,080✔
54

55
bool TLS::Callbacks::tls_should_persist_resumption_information(const Session& session) {
2,537✔
56
   // RFC 5077 3.3
57
   //    The ticket_lifetime_hint field contains a hint from the server about
58
   //    how long the ticket should be stored. A value of zero is reserved to
59
   //    indicate that the lifetime of the ticket is unspecified.
60
   //
61
   // RFC 8446 4.6.1
62
   //    [A ticket_lifetime] of zero indicates that the ticket should be discarded
63
   //    immediately.
64
   //
65
   // By default we opt to keep all sessions, except for TLS 1.3 with a lifetime
66
   // hint of zero.
67
   return session.lifetime_hint().count() > 0 || session.version().is_pre_tls_13();
2,537✔
68
}
69

70
void TLS::Callbacks::tls_verify_cert_chain(const std::vector<X509_Certificate>& cert_chain,
103✔
71
                                           const std::vector<std::optional<OCSP::Response>>& ocsp_responses,
72
                                           const std::vector<Certificate_Store*>& trusted_roots,
73
                                           Usage_Type usage,
74
                                           std::string_view hostname,
75
                                           const TLS::Policy& policy) {
76
   if(cert_chain.empty()) {
103✔
77
      throw Invalid_Argument("Certificate chain was empty");
×
78
   }
79

80
   Path_Validation_Restrictions restrictions(policy.require_cert_revocation_info(),
103✔
81
                                             policy.minimum_signature_strength());
309✔
82

83
   Path_Validation_Result result = x509_path_validate(cert_chain,
103✔
84
                                                      restrictions,
85
                                                      trusted_roots,
86
                                                      (usage == Usage_Type::TLS_SERVER_AUTH ? hostname : ""),
87
                                                      usage,
88
                                                      tls_current_timestamp(),
103✔
89
                                                      tls_verify_cert_chain_ocsp_timeout(),
103✔
90
                                                      ocsp_responses);
106✔
91

92
   if(!result.successful_validation()) {
103✔
93
      throw TLS_Exception(Alert::BadCertificate, "Certificate validation failure: " + result.result_string());
×
94
   }
95
}
103✔
96

97
std::optional<OCSP::Response> TLS::Callbacks::tls_parse_ocsp_response(const std::vector<uint8_t>& raw_response) {
×
98
   try {
×
99
      return OCSP::Response(raw_response);
×
100
   } catch(const Decoding_Error&) {
×
101
      // ignore parsing errors and just ignore the broken OCSP response
102
      return std::nullopt;
×
103
   }
×
104
}
105

106
std::vector<std::vector<uint8_t>> TLS::Callbacks::tls_provide_cert_chain_status(
245✔
107
   const std::vector<X509_Certificate>& chain, const Certificate_Status_Request& csr) {
108
   std::vector<std::vector<uint8_t>> result(chain.size());
245✔
109
   if(!chain.empty()) {
245✔
110
      result[0] = tls_provide_cert_status(chain, csr);
245✔
111
   }
112
   return result;
237✔
113
}
8✔
114

115
std::vector<uint8_t> TLS::Callbacks::tls_sign_message(const Private_Key& key,
916✔
116
                                                      RandomNumberGenerator& rng,
117
                                                      std::string_view padding,
118
                                                      Signature_Format format,
119
                                                      const std::vector<uint8_t>& msg) {
120
   PK_Signer signer(key, rng, padding, format);
916✔
121

122
   return signer.sign_message(msg, rng);
1,831✔
123
}
916✔
124

125
bool TLS::Callbacks::tls_verify_message(const Public_Key& key,
1,126✔
126
                                        std::string_view padding,
127
                                        Signature_Format format,
128
                                        const std::vector<uint8_t>& msg,
129
                                        const std::vector<uint8_t>& sig) {
130
   PK_Verifier verifier(key, padding, format);
1,126✔
131

132
   return verifier.verify_message(msg, sig);
2,252✔
133
}
1,126✔
134

135
std::unique_ptr<Private_Key> TLS::Callbacks::tls_kem_generate_key(TLS::Group_Params group, RandomNumberGenerator& rng) {
995✔
136
   return tls_generate_ephemeral_key(group, rng);
2,985✔
137
}
138

139
TLS::Callbacks::Encapsulation_Result TLS::Callbacks::tls_kem_encapsulate(TLS::Group_Params group,
357✔
140
                                                                         const std::vector<uint8_t>& encoded_public_key,
141
                                                                         RandomNumberGenerator& rng,
142
                                                                         const Policy& policy) {
143
   auto ephemeral_keypair = tls_generate_ephemeral_key(group, rng);
357✔
144
   return {ephemeral_keypair->public_value(),
357✔
145
           tls_ephemeral_key_agreement(group, *ephemeral_keypair, encoded_public_key, rng, policy)};
714✔
146
}
356✔
147

148
secure_vector<uint8_t> TLS::Callbacks::tls_kem_decapsulate(TLS::Group_Params group,
420✔
149
                                                           const Private_Key& private_key,
150
                                                           const std::vector<uint8_t>& encapsulated_bytes,
151
                                                           RandomNumberGenerator& rng,
152
                                                           const Policy& policy) {
153
   try {
420✔
154
      auto& key_agreement_key = dynamic_cast<const PK_Key_Agreement_Key&>(private_key);
420✔
155
      return tls_ephemeral_key_agreement(group, key_agreement_key, encapsulated_bytes, rng, policy);
840✔
156
   } catch(const std::bad_cast&) {
1✔
157
      throw Invalid_Argument("provided ephemeral key is not a PK_Key_Agreement_Key");
×
158
   }
×
159
}
160

161
namespace {
162

163
bool is_dh_group(const std::variant<TLS::Group_Params, DL_Group>& group) {
4,578✔
164
   return std::holds_alternative<DL_Group>(group) || is_dh(std::get<TLS::Group_Params>(group));
9,140✔
165
}
166

167
DL_Group get_dl_group(const std::variant<TLS::Group_Params, DL_Group>& group) {
20✔
168
   BOTAN_ASSERT_NOMSG(is_dh_group(group));
20✔
169

170
   // TLS 1.2 allows specifying arbitrary DL_Group parameters in-lieu of
171
   // a standardized DH group identifier. TLS 1.3 just offers pre-defined
172
   // groups.
173
   return std::visit(
20✔
174
      overloaded{[](const DL_Group& dl_group) { return dl_group; },
8✔
175
                 [&](TLS::Group_Params group_param) { return DL_Group(group_param_to_string(group_param)); }},
24✔
176
      group);
20✔
177
}
178

179
}  // namespace
180

181
std::unique_ptr<PK_Key_Agreement_Key> TLS::Callbacks::tls_generate_ephemeral_key(
2,574✔
182
   const std::variant<TLS::Group_Params, DL_Group>& group, RandomNumberGenerator& rng) {
183
   if(is_dh_group(group)) {
2,574✔
184
      const DL_Group dl_group = get_dl_group(group);
12✔
185
      return std::make_unique<DH_PrivateKey>(rng, dl_group);
24✔
186
   }
12✔
187

188
   BOTAN_ASSERT_NOMSG(std::holds_alternative<TLS::Group_Params>(group));
2,562✔
189
   const auto group_params = std::get<TLS::Group_Params>(group);
2,562✔
190

191
   if(is_ecdh(group_params)) {
2,562✔
192
      const EC_Group ec_group(group_param_to_string(group_params));
302✔
193
      return std::make_unique<ECDH_PrivateKey>(rng, ec_group);
604✔
194
   }
302✔
195

196
#if defined(BOTAN_HAS_CURVE_25519)
197
   if(is_x25519(group_params)) {
2,260✔
198
      return std::make_unique<X25519_PrivateKey>(rng);
4,520✔
199
   }
200
#endif
201

202
   throw TLS_Exception(Alert::DecodeError, "cannot create a key offering without a group definition");
×
203
}
204

205
secure_vector<uint8_t> TLS::Callbacks::tls_ephemeral_key_agreement(
1,984✔
206
   const std::variant<TLS::Group_Params, DL_Group>& group,
207
   const PK_Key_Agreement_Key& private_key,
208
   const std::vector<uint8_t>& public_value,
209
   RandomNumberGenerator& rng,
210
   const Policy& policy) {
211
   auto agree = [&](const PK_Key_Agreement_Key& sk, const auto& pk) {
3,964✔
212
      PK_Key_Agreement ka(sk, rng, "Raw");
1,980✔
213
      return ka.derive_key(0, pk.public_value()).bits_of();
5,940✔
214
   };
3,964✔
215

216
   if(is_dh_group(group)) {
1,984✔
217
      // TLS 1.2 allows specifying arbitrary DL_Group parameters in-lieu of
218
      // a standardized DH group identifier.
219
      const auto dl_group = get_dl_group(group);
8✔
220

221
      auto Y = BigInt::decode(public_value);
8✔
222

223
      /*
224
       * A basic check for key validity. As we do not know q here we
225
       * cannot check that Y is in the right subgroup. However since
226
       * our key is ephemeral there does not seem to be any
227
       * advantage to bogus keys anyway.
228
       */
229
      if(Y <= 1 || Y >= dl_group.get_p() - 1) {
16✔
230
         throw TLS_Exception(Alert::IllegalParameter, "Server sent bad DH key for DHE exchange");
×
231
      }
232

233
      DH_PublicKey peer_key(dl_group, Y);
8✔
234
      policy.check_peer_key_acceptable(peer_key);
8✔
235

236
      return agree(private_key, peer_key);
8✔
237
   }
24✔
238

239
   BOTAN_ASSERT_NOMSG(std::holds_alternative<TLS::Group_Params>(group));
1,976✔
240
   const auto group_params = std::get<TLS::Group_Params>(group);
1,976✔
241

242
   if(is_ecdh(group_params)) {
1,976✔
243
      const EC_Group ec_group(group_param_to_string(group_params));
231✔
244
      ECDH_PublicKey peer_key(ec_group, ec_group.OS2ECP(public_value));
231✔
245
      policy.check_peer_key_acceptable(peer_key);
227✔
246

247
      return agree(private_key, peer_key);
227✔
248
   }
231✔
249

250
#if defined(BOTAN_HAS_CURVE_25519)
251
   if(is_x25519(group_params)) {
1,745✔
252
      if(public_value.size() != 32) {
1,745✔
253
         throw TLS_Exception(Alert::HandshakeFailure, "Invalid X25519 key size");
×
254
      }
255

256
      Curve25519_PublicKey peer_key(public_value);
1,745✔
257
      policy.check_peer_key_acceptable(peer_key);
1,745✔
258

259
      return agree(private_key, peer_key);
1,745✔
260
   }
1,745✔
261
#endif
262

263
   throw TLS_Exception(Alert::IllegalParameter, "Did not recognize the key exchange group");
×
264
}
265

266
}  // namespace Botan
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