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

randombit / botan / 13629762785

03 Mar 2025 11:24AM UTC coverage: 91.686% (-0.008%) from 91.694%
13629762785

push

github

web-flow
Merge pull request #4740 from randombit/jack/more-build-h-cleanup

Small build.h cleanups/removals

95827 of 104516 relevant lines covered (91.69%)

11258003.53 hits per line

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

90.48
/src/lib/tls/tls12/msg_server_kex.cpp
1
/*
2
* Server Key Exchange Message
3
* (C) 2004-2010,2012,2015,2016 Jack Lloyd
4
*     2017 Harry Reimann, Rohde & Schwarz Cybersecurity
5
*
6
* Botan is released under the Simplified BSD License (see license.txt)
7
*/
8

9
#include <botan/tls_messages.h>
10

11
#include <botan/credentials_manager.h>
12
#include <botan/pubkey.h>
13
#include <botan/tls_extensions.h>
14
#include <botan/internal/loadstor.h>
15
#include <botan/internal/target_info.h>
16
#include <botan/internal/tls_handshake_io.h>
17
#include <botan/internal/tls_handshake_state.h>
18
#include <botan/internal/tls_reader.h>
19

20
#include <botan/dh.h>
21
#include <botan/dl_group.h>
22
#include <botan/ecdh.h>
23

24
#if defined(BOTAN_HAS_X25519)
25
   #include <botan/x25519.h>
26
#endif
27
#if defined(BOTAN_HAS_X448)
28
   #include <botan/x448.h>
29
#endif
30

31
namespace Botan::TLS {
32

33
/**
34
* Create a new Server Key Exchange message
35
*/
36
Server_Key_Exchange::Server_Key_Exchange(Handshake_IO& io,
650✔
37
                                         Handshake_State& state,
38
                                         const Policy& policy,
39
                                         Credentials_Manager& creds,
40
                                         RandomNumberGenerator& rng,
41
                                         const Private_Key* signing_key) {
650✔
42
   const std::string hostname = state.client_hello()->sni_hostname();
650✔
43
   const Kex_Algo kex_algo = state.ciphersuite().kex_method();
650✔
44

45
   if(kex_algo == Kex_Algo::PSK || kex_algo == Kex_Algo::ECDHE_PSK) {
650✔
46
      std::string identity_hint = creds.psk_identity_hint("tls-server", hostname);
45✔
47

48
      append_tls_length_value(m_params, identity_hint, 2);
90✔
49
   }
45✔
50

51
   if(kex_algo == Kex_Algo::DH) {
650✔
52
      const std::vector<Group_Params> dh_groups = state.client_hello()->supported_dh_groups();
6✔
53

54
      m_shared_group = Group_Params::NONE;
6✔
55

56
      /*
57
      RFC 7919 requires that if the client sends any groups in the FFDHE
58
      range, that we must select one of these. If this is not possible,
59
      then we are required to reject the connection.
60

61
      If the client did not send any DH groups, but did offer DH ciphersuites
62
      and we selected one, then consult the policy for which DH group to pick.
63
      */
64

65
      if(dh_groups.empty()) {
6✔
66
         m_shared_group = policy.default_dh_group();
×
67
      } else {
68
         m_shared_group = policy.choose_key_exchange_group(dh_groups, {});
12✔
69
      }
70

71
      if(m_shared_group.value() == Group_Params::NONE) {
6✔
72
         throw TLS_Exception(Alert::HandshakeFailure, "Could not agree on a DH group with the client");
×
73
      }
74

75
      // The policy had better return a group we know about:
76
      BOTAN_ASSERT(m_shared_group.value().is_dh_named_group(), "DH ciphersuite is using a known finite field group");
6✔
77

78
      // Note: TLS 1.2 allows defining and using arbitrary DH groups (additional
79
      //       to the named and standardized ones). This API doesn't allow the
80
      //       server to make use of that at the moment. TLS 1.3 does not
81
      //       provide this flexibility!
82
      //
83
      // A possible implementation strategy in case one would ever need that:
84
      // `Policy::default_dh_group()` could return a `std::variant<Group_Params,
85
      // DL_Group>`, allowing it to define arbitrary groups.
86
      m_kex_key = state.callbacks().tls_generate_ephemeral_key(m_shared_group.value(), rng);
6✔
87
      auto dh = dynamic_cast<DH_PrivateKey*>(m_kex_key.get());
6✔
88
      if(!dh) {
6✔
89
         throw TLS_Exception(Alert::InternalError, "Application did not provide a Diffie-Hellman key");
×
90
      }
91

92
      append_tls_length_value(m_params, dh->get_int_field("p").serialize(), 2);
18✔
93
      append_tls_length_value(m_params, dh->get_int_field("g").serialize(), 2);
18✔
94
      append_tls_length_value(m_params, dh->public_value(), 2);
18✔
95
   } else if(kex_algo == Kex_Algo::ECDH || kex_algo == Kex_Algo::ECDHE_PSK) {
650✔
96
      const std::vector<Group_Params> ec_groups = state.client_hello()->supported_ecc_curves();
610✔
97

98
      if(ec_groups.empty()) {
610✔
99
         throw Internal_Error("Client sent no ECC extension but we negotiated ECDH");
×
100
      }
101

102
      m_shared_group = policy.choose_key_exchange_group(ec_groups, {});
1,220✔
103

104
      if(m_shared_group.value() == Group_Params::NONE) {
610✔
105
         throw TLS_Exception(Alert::HandshakeFailure, "No shared ECC group with client");
×
106
      }
107

108
      std::vector<uint8_t> ecdh_public_val;
610✔
109

110
      if(m_shared_group.value() == Group_Params::X25519 || m_shared_group.value() == Group_Params::X448) {
610✔
111
         m_kex_key = state.callbacks().tls_generate_ephemeral_key(m_shared_group.value(), rng);
585✔
112
         if(!m_kex_key) {
585✔
113
            throw TLS_Exception(Alert::InternalError, "Application did not provide an EC key");
×
114
         }
115
         ecdh_public_val = m_kex_key->public_value();
1,170✔
116
      } else {
117
         m_kex_key = state.callbacks().tls_generate_ephemeral_key(m_shared_group.value(), rng);
25✔
118
         auto ecdh = dynamic_cast<ECDH_PrivateKey*>(m_kex_key.get());
25✔
119
         if(!ecdh) {
25✔
120
            throw TLS_Exception(Alert::InternalError, "Application did not provide a EC-Diffie-Hellman key");
×
121
         }
122

123
         // follow client's preference for point compression
124
         ecdh_public_val =
25✔
125
            ecdh->public_value(state.client_hello()->prefers_compressed_ec_points() ? EC_Point_Format::Compressed
75✔
126
                                                                                    : EC_Point_Format::Uncompressed);
25✔
127
      }
128

129
      const uint16_t named_curve_id = m_shared_group.value().wire_code();
610✔
130
      m_params.push_back(3);  // named curve
610✔
131
      m_params.push_back(get_byte<0>(named_curve_id));
610✔
132
      m_params.push_back(get_byte<1>(named_curve_id));
610✔
133

134
      append_tls_length_value(m_params, ecdh_public_val, 1);
1,220✔
135
   } else if(kex_algo != Kex_Algo::PSK) {
1,254✔
136
      throw Internal_Error("Server_Key_Exchange: Unknown kex type " + kex_method_to_string(kex_algo));
×
137
   }
138

139
   if(state.ciphersuite().signature_used()) {
650✔
140
      BOTAN_ASSERT(signing_key, "Signing key was set");
605✔
141

142
      std::pair<std::string, Signature_Format> format = state.choose_sig_format(*signing_key, m_scheme, false, policy);
605✔
143

144
      std::vector<uint8_t> buf = state.client_hello()->random();
605✔
145

146
      buf += state.server_hello()->random();
605✔
147
      buf += params();
605✔
148

149
      m_signature = state.callbacks().tls_sign_message(*signing_key, rng, format.first, format.second, buf);
605✔
150
   }
605✔
151

152
   state.hash().update(io.send(*this));
1,948✔
153
}
652✔
154

155
/**
156
* Deserialize a Server Key Exchange message
157
*/
158
Server_Key_Exchange::Server_Key_Exchange(const std::vector<uint8_t>& buf,
797✔
159
                                         const Kex_Algo kex_algo,
160
                                         const Auth_Method auth_method,
161
                                         Protocol_Version version) {
797✔
162
   BOTAN_UNUSED(version);  // remove this
797✔
163
   TLS_Data_Reader reader("ServerKeyExchange", buf);
797✔
164

165
   /*
166
   * Here we are deserializing enough to find out what offset the
167
   * signature is at. All processing is done when the Client Key Exchange
168
   * is prepared.
169
   */
170

171
   if(kex_algo == Kex_Algo::PSK || kex_algo == Kex_Algo::ECDHE_PSK) {
797✔
172
      reader.get_string(2, 0, 65535);  // identity hint
102✔
173
   }
174

175
   if(kex_algo == Kex_Algo::DH) {
797✔
176
      // 3 bigints, DH p, g, Y
177

178
      for(size_t i = 0; i != 3; ++i) {
24✔
179
         reader.get_range<uint8_t>(2, 1, 65535);
36✔
180
      }
181
   } else if(kex_algo == Kex_Algo::ECDH || kex_algo == Kex_Algo::ECDHE_PSK) {
791✔
182
      reader.get_byte();                     // curve type
764✔
183
      reader.get_uint16_t();                 // curve id
764✔
184
      reader.get_range<uint8_t>(1, 1, 255);  // public key
1,528✔
185
   } else if(kex_algo != Kex_Algo::PSK) {
27✔
186
      throw Decoding_Error("Server_Key_Exchange: Unsupported kex type " + kex_method_to_string(kex_algo));
×
187
   }
188

189
   m_params.assign(buf.data(), buf.data() + reader.read_so_far());
797✔
190

191
   if(auth_method != Auth_Method::IMPLICIT) {
797✔
192
      m_scheme = Signature_Scheme(reader.get_uint16_t());
746✔
193
      m_signature = reader.get_range<uint8_t>(2, 0, 65535);
746✔
194
   }
195

196
   reader.assert_done();
797✔
197
}
801✔
198

199
/**
200
* Serialize a Server Key Exchange message
201
*/
202
std::vector<uint8_t> Server_Key_Exchange::serialize() const {
650✔
203
   std::vector<uint8_t> buf = params();
650✔
204

205
   if(!m_signature.empty()) {
650✔
206
      if(m_scheme.is_set()) {
605✔
207
         buf.push_back(get_byte<0>(m_scheme.wire_code()));
605✔
208
         buf.push_back(get_byte<1>(m_scheme.wire_code()));
605✔
209
      }
210

211
      append_tls_length_value(buf, m_signature, 2);
605✔
212
   }
213

214
   return buf;
650✔
215
}
×
216

217
/**
218
* Verify a Server Key Exchange message
219
*/
220
bool Server_Key_Exchange::verify(const Public_Key& server_key,
744✔
221
                                 const Handshake_State& state,
222
                                 const Policy& policy) const {
223
   policy.check_peer_key_acceptable(server_key);
744✔
224

225
   std::pair<std::string, Signature_Format> format =
744✔
226
      state.parse_sig_format(server_key, m_scheme, state.client_hello()->signature_schemes(), false, policy);
744✔
227

228
   std::vector<uint8_t> buf = state.client_hello()->random();
740✔
229

230
   buf += state.server_hello()->random();
740✔
231
   buf += params();
740✔
232

233
   const bool signature_valid =
740✔
234
      state.callbacks().tls_verify_message(server_key, format.first, format.second, buf, m_signature);
740✔
235

236
#if defined(BOTAN_UNSAFE_FUZZER_MODE)
237
   BOTAN_UNUSED(signature_valid);
238
   return true;
239
#else
240
   return signature_valid;
740✔
241
#endif
242
}
740✔
243

244
const PK_Key_Agreement_Key& Server_Key_Exchange::server_kex_key() const {
601✔
245
   BOTAN_ASSERT_NONNULL(m_kex_key);
601✔
246
   return *m_kex_key;
601✔
247
}
248

249
}  // namespace Botan::TLS
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