Coverage Report

Created: 2023-02-13 06:21

/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
*
7
* Botan is released under the Simplified BSD License (see license.txt)
8
*/
9
10
#include <botan/tls_callbacks.h>
11
#include <botan/tls_policy.h>
12
#include <botan/tls_algos.h>
13
#include <botan/x509path.h>
14
#include <botan/ocsp.h>
15
#include <botan/dh.h>
16
#include <botan/ecdh.h>
17
#include <botan/tls_exceptn.h>
18
#include <botan/internal/ct_utils.h>
19
20
#if defined(BOTAN_HAS_CURVE_25519)
21
  #include <botan/curve25519.h>
22
#endif
23
24
namespace Botan {
25
26
void TLS::Callbacks::tls_inspect_handshake_msg(const Handshake_Message& /*unused*/)
27
99.8k
   {
28
   // default is no op
29
99.8k
   }
30
31
std::string TLS::Callbacks::tls_server_choose_app_protocol(const std::vector<std::string>& /*unused*/)
32
0
   {
33
0
   return "";
34
0
   }
35
36
std::string TLS::Callbacks::tls_peer_network_identity()
37
2.14k
   {
38
2.14k
   return "";
39
2.14k
   }
40
41
std::chrono::system_clock::time_point TLS::Callbacks::tls_current_timestamp()
42
43.0k
   {
43
43.0k
   return std::chrono::system_clock::now();
44
43.0k
   }
45
46
void TLS::Callbacks::tls_modify_extensions(Extensions& /*unused*/, Connection_Side /*unused*/, Handshake_Type /*unused*/)
47
22.6k
   {
48
22.6k
   }
49
50
void TLS::Callbacks::tls_examine_extensions(const Extensions& /*unused*/, Connection_Side /*unused*/, Handshake_Type /*unused*/)
51
20.3k
   {
52
20.3k
   }
53
54
std::string TLS::Callbacks::tls_decode_group_param(Group_Params group_param)
55
17.9k
   {
56
17.9k
   return group_param_to_string(group_param);
57
17.9k
   }
58
59
60
bool TLS::Callbacks::tls_session_ticket_received(const Session& session)
61
0
   {
62
   // RFC 8446 4.6.1
63
   //    [A ticket_lifetime] of zero indicates that the ticket should be discarded
64
   //    immediately.
65
0
   return session.lifetime_hint().count() > 0;
66
0
   }
67
68
void TLS::Callbacks::tls_verify_cert_chain(
69
   const std::vector<X509_Certificate>& cert_chain,
70
   const std::vector<std::optional<OCSP::Response>>& ocsp_responses,
71
   const std::vector<Certificate_Store*>& trusted_roots,
72
   Usage_Type usage,
73
   const std::string& hostname,
74
   const TLS::Policy& policy)
75
0
   {
76
0
   if(cert_chain.empty())
77
0
      throw Invalid_Argument("Certificate chain was empty");
78
79
0
   Path_Validation_Restrictions restrictions(policy.require_cert_revocation_info(),
80
0
                                             policy.minimum_signature_strength());
81
82
0
   Path_Validation_Result result =
83
0
      x509_path_validate(cert_chain,
84
0
                         restrictions,
85
0
                         trusted_roots,
86
0
                         (usage == Usage_Type::TLS_SERVER_AUTH ? hostname : ""),
87
0
                         usage,
88
0
                         tls_current_timestamp(),
89
0
                         tls_verify_cert_chain_ocsp_timeout(),
90
0
                         ocsp_responses);
91
92
0
   if(!result.successful_validation())
93
0
      {
94
0
      throw TLS_Exception(Alert::BadCertificate,
95
0
                          "Certificate validation failure: " + result.result_string());
96
0
      }
97
0
   }
98
99
std::optional<OCSP::Response> TLS::Callbacks::tls_parse_ocsp_response(const std::vector<uint8_t>& raw_response)
100
0
   {
101
0
   try
102
0
      {
103
0
      return OCSP::Response(raw_response);
104
0
      }
105
0
   catch(const Decoding_Error&)
106
0
      {
107
      // ignore parsing errors and just ignore the broken OCSP response
108
0
      return std::nullopt;
109
0
      }
110
0
   }
111
112
113
std::vector<std::vector<uint8_t>> TLS::Callbacks::tls_provide_cert_chain_status(
114
   const std::vector<X509_Certificate>& chain,
115
   const Certificate_Status_Request& csr)
116
0
   {
117
0
   std::vector<std::vector<uint8_t>> result(chain.size());
118
0
   if(!chain.empty())
119
0
      {
120
0
      result[0] = tls_provide_cert_status(chain, csr);
121
0
      }
122
0
   return result;
123
0
   }
124
125
std::vector<uint8_t> TLS::Callbacks::tls_sign_message(
126
   const Private_Key& key,
127
   RandomNumberGenerator& rng,
128
   const std::string& emsa,
129
   Signature_Format format,
130
   const std::vector<uint8_t>& msg)
131
0
   {
132
0
   PK_Signer signer(key, rng, emsa, format);
133
134
0
   return signer.sign_message(msg, rng);
135
0
   }
136
137
bool TLS::Callbacks::tls_verify_message(
138
   const Public_Key& key,
139
   const std::string& emsa,
140
   Signature_Format format,
141
   const std::vector<uint8_t>& msg,
142
   const std::vector<uint8_t>& sig)
143
0
   {
144
0
   PK_Verifier verifier(key, emsa, format);
145
146
0
   return verifier.verify_message(msg, sig);
147
0
   }
148
149
std::pair<secure_vector<uint8_t>, std::vector<uint8_t>> TLS::Callbacks::tls_dh_agree(
150
   const std::vector<uint8_t>& modulus,
151
   const std::vector<uint8_t>& generator,
152
   const std::vector<uint8_t>& peer_public_value,
153
   const Policy& policy,
154
   RandomNumberGenerator& rng)
155
0
   {
156
0
   BigInt p = BigInt::decode(modulus);
157
0
   BigInt g = BigInt::decode(generator);
158
0
   BigInt Y = BigInt::decode(peer_public_value);
159
160
   /*
161
    * A basic check for key validity. As we do not know q here we
162
    * cannot check that Y is in the right subgroup. However since
163
    * our key is ephemeral there does not seem to be any
164
    * advantage to bogus keys anyway.
165
    */
166
0
   if(Y <= 1 || Y >= p - 1)
167
0
      throw TLS_Exception(Alert::IllegalParameter,
168
0
                          "Server sent bad DH key for DHE exchange");
169
170
0
   DL_Group group(p, g);
171
172
0
   if(!group.verify_group(rng, false))
173
0
      throw TLS_Exception(Alert::InsufficientSecurity,
174
0
                          "DH group validation failed");
175
176
0
   DH_PublicKey peer_key(group, Y);
177
178
0
   policy.check_peer_key_acceptable(peer_key);
179
180
0
   DH_PrivateKey priv_key(rng, group);
181
0
   PK_Key_Agreement ka(priv_key, rng, "Raw");
182
0
   secure_vector<uint8_t> dh_secret = CT::strip_leading_zeros(
183
0
      ka.derive_key(0, peer_key.public_value()).bits_of());
184
185
0
   return std::make_pair(dh_secret, priv_key.public_value());
186
0
   }
187
188
std::pair<secure_vector<uint8_t>, std::vector<uint8_t>> TLS::Callbacks::tls_ecdh_agree(
189
   const std::string& curve_name,
190
   const std::vector<uint8_t>& peer_public_value,
191
   const Policy& policy,
192
   RandomNumberGenerator& rng,
193
   bool compressed)
194
0
   {
195
0
   secure_vector<uint8_t> ecdh_secret;
196
0
   std::vector<uint8_t> our_public_value;
197
198
0
   if(curve_name == "x25519")
199
0
      {
200
0
#if defined(BOTAN_HAS_CURVE_25519)
201
0
      if(peer_public_value.size() != 32)
202
0
         {
203
0
         throw TLS_Exception(Alert::HandshakeFailure, "Invalid X25519 key size");
204
0
         }
205
206
0
      Curve25519_PublicKey peer_key(peer_public_value);
207
0
      policy.check_peer_key_acceptable(peer_key);
208
0
      Curve25519_PrivateKey priv_key(rng);
209
0
      PK_Key_Agreement ka(priv_key, rng, "Raw");
210
0
      ecdh_secret = ka.derive_key(0, peer_key.public_value()).bits_of();
211
212
      // X25519 is always compressed but sent as "uncompressed" in TLS
213
0
      our_public_value = priv_key.public_value();
214
#else
215
      throw Internal_Error("Negotiated X25519 somehow, but it is disabled");
216
#endif
217
0
      }
218
0
   else
219
0
      {
220
0
      EC_Group group(OID::from_string(curve_name));
221
0
      ECDH_PublicKey peer_key(group, group.OS2ECP(peer_public_value));
222
0
      policy.check_peer_key_acceptable(peer_key);
223
0
      ECDH_PrivateKey priv_key(rng, group);
224
0
      PK_Key_Agreement ka(priv_key, rng, "Raw");
225
0
      ecdh_secret = ka.derive_key(0, peer_key.public_value()).bits_of();
226
0
      our_public_value = priv_key.public_value(compressed ? EC_Point::COMPRESSED : EC_Point::UNCOMPRESSED);
227
0
      }
228
229
0
   return std::make_pair(ecdh_secret, our_public_value);
230
0
   }
231
232
}