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

randombit / botan / 21966968252

12 Feb 2026 10:36PM UTC coverage: 90.07% (+0.003%) from 90.067%
21966968252

Pull #5321

github

web-flow
Merge fd30428c7 into e7443105f
Pull Request #5321: Avoid various unneeded include files

102234 of 113505 relevant lines covered (90.07%)

11432801.46 hits per line

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

91.35
/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_12.h>
10

11
#include <botan/bigint.h>
12
#include <botan/credentials_manager.h>
13
#include <botan/dl_group.h>
14
#include <botan/pubkey.h>
15
#include <botan/tls_callbacks.h>
16
#include <botan/tls_extensions.h>
17
#include <botan/tls_policy.h>
18
#include <botan/internal/loadstor.h>
19
#include <botan/internal/target_info.h>
20
#include <botan/internal/tls_handshake_io.h>
21
#include <botan/internal/tls_handshake_state.h>
22
#include <botan/internal/tls_reader.h>
23

24
#include <botan/dh.h>
25

26
namespace Botan::TLS {
27

28
Server_Key_Exchange::~Server_Key_Exchange() = default;
6,429✔
29

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

42
   if(kex_algo == Kex_Algo::PSK || kex_algo == Kex_Algo::ECDHE_PSK) {
658✔
43
      const std::string identity_hint = creds.psk_identity_hint("tls-server", hostname);
50✔
44

45
      append_tls_length_value(m_params, identity_hint, 2);
100✔
46
   }
50✔
47

48
   if(kex_algo == Kex_Algo::DH) {
658✔
49
      const std::vector<Group_Params> dh_groups = state.client_hello()->supported_dh_groups();
6✔
50

51
      m_shared_group = Group_Params::NONE;
6✔
52

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

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

62
      if(dh_groups.empty()) {
6✔
63
         m_shared_group = policy.default_dh_group();
×
64
      } else {
65
         m_shared_group = policy.choose_key_exchange_group(dh_groups, {});
12✔
66
      }
67

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

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

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

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

95
      if(ec_groups.empty()) {
614✔
96
         throw Internal_Error("Client sent no ECC extension but we negotiated ECDH");
×
97
      }
98

99
      m_shared_group = policy.choose_key_exchange_group(ec_groups, {});
1,228✔
100

101
      if(m_shared_group.value() == Group_Params::NONE) {
614✔
102
         throw TLS_Exception(Alert::HandshakeFailure, "No shared ECC group with client");
×
103
      }
104

105
      m_kex_key = [&] {
1,842✔
106
         if(m_shared_group->is_ecdh_named_curve()) {
614✔
107
            const auto pubkey_point_format = state.client_hello()->prefers_compressed_ec_points()
28✔
108
                                                ? EC_Point_Format::Compressed
28✔
109
                                                : EC_Point_Format::Uncompressed;
28✔
110
            return state.callbacks().tls12_generate_ephemeral_ecdh_key(*m_shared_group, rng, pubkey_point_format);
28✔
111
         } else {
112
            return state.callbacks().tls_generate_ephemeral_key(*m_shared_group, rng);
1,172✔
113
         }
114
      }();
614✔
115

116
      if(!m_kex_key) {
614✔
117
         throw TLS_Exception(Alert::InternalError, "Application did not provide an EC key");
×
118
      }
119

120
      const uint16_t named_curve_id = m_shared_group.value().wire_code();
614✔
121
      m_params.push_back(3);  // named curve
614✔
122
      m_params.push_back(get_byte<0>(named_curve_id));
614✔
123
      m_params.push_back(get_byte<1>(named_curve_id));
614✔
124

125
      // Note: In contrast to public_value(), raw_public_key_bits() takes the
126
      // point format (compressed vs. uncompressed) into account that was set
127
      // in its construction within tls_generate_ephemeral_key().
128
      append_tls_length_value(m_params, m_kex_key->raw_public_key_bits(), 1);
1,842✔
129
   } else if(kex_algo != Kex_Algo::PSK) {
652✔
130
      throw Internal_Error("Server_Key_Exchange: Unknown kex type " + kex_method_to_string(kex_algo));
×
131
   }
132

133
   if(state.ciphersuite().signature_used()) {
658✔
134
      BOTAN_ASSERT(signing_key, "Signing key was set");
608✔
135

136
      const std::pair<std::string, Signature_Format> format =
608✔
137
         state.choose_sig_format(*signing_key, m_scheme, false, policy);
608✔
138

139
      std::vector<uint8_t> buf = state.client_hello()->random();
608✔
140

141
      buf += state.server_hello()->random();
608✔
142
      buf += params();
608✔
143

144
      m_signature = state.callbacks().tls_sign_message(*signing_key, rng, format.first, format.second, buf);
608✔
145
   }
608✔
146

147
   state.hash().update(io.send(*this));
1,972✔
148
}
660✔
149

150
/**
151
* Deserialize a Server Key Exchange message
152
*/
153
Server_Key_Exchange::Server_Key_Exchange(const std::vector<uint8_t>& buf,
1,005✔
154
                                         const Kex_Algo kex_algo,
155
                                         const Auth_Method auth_method,
156
                                         Protocol_Version version) {
1,005✔
157
   BOTAN_UNUSED(version);  // remove this
1,005✔
158
   TLS_Data_Reader reader("ServerKeyExchange", buf);
1,005✔
159

160
   /*
161
   * Here we are deserializing enough to find out what offset the
162
   * signature is at. All processing is done when the Client Key Exchange
163
   * is prepared.
164
   */
165

166
   if(kex_algo == Kex_Algo::PSK || kex_algo == Kex_Algo::ECDHE_PSK) {
1,005✔
167
      reader.get_string(2, 0, 65535);  // identity hint
114✔
168
   }
169

170
   if(kex_algo == Kex_Algo::DH) {
1,005✔
171
      // 3 bigints, DH p, g, Y
172

173
      for(size_t i = 0; i != 3; ++i) {
95✔
174
         reader.get_range<uint8_t>(2, 1, 65535);
143✔
175
      }
176
   } else if(kex_algo == Kex_Algo::ECDH || kex_algo == Kex_Algo::ECDHE_PSK) {
978✔
177
      reader.get_byte();                     // curve type
947✔
178
      reader.get_uint16_t();                 // curve id
946✔
179
      reader.get_range<uint8_t>(1, 1, 255);  // public key
1,889✔
180
   } else if(kex_algo != Kex_Algo::PSK) {
31✔
181
      throw Decoding_Error("Server_Key_Exchange: Unsupported kex type " + kex_method_to_string(kex_algo));
×
182
   }
183

184
   m_params.assign(buf.data(), buf.data() + reader.read_so_far());
995✔
185

186
   if(auth_method != Auth_Method::IMPLICIT) {
995✔
187
      m_scheme = Signature_Scheme(reader.get_uint16_t());
938✔
188
      m_signature = reader.get_range<uint8_t>(2, 0, 65535);
935✔
189
   }
190

191
   reader.assert_done();
987✔
192
}
1,021✔
193

194
/**
195
* Serialize a Server Key Exchange message
196
*/
197
std::vector<uint8_t> Server_Key_Exchange::serialize() const {
658✔
198
   std::vector<uint8_t> buf = params();
658✔
199

200
   if(!m_signature.empty()) {
658✔
201
      if(m_scheme.is_set()) {
608✔
202
         buf.push_back(get_byte<0>(m_scheme.wire_code()));
608✔
203
         buf.push_back(get_byte<1>(m_scheme.wire_code()));
608✔
204
      }
205

206
      append_tls_length_value(buf, m_signature, 2);
608✔
207
   }
208

209
   return buf;
658✔
210
}
×
211

212
/**
213
* Verify a Server Key Exchange message
214
*/
215
bool Server_Key_Exchange::verify(const Public_Key& server_key,
926✔
216
                                 const Handshake_State& state,
217
                                 const Policy& policy) const {
218
   policy.check_peer_key_acceptable(server_key);
926✔
219

220
   const std::pair<std::string, Signature_Format> format =
877✔
221
      state.parse_sig_format(server_key, m_scheme, state.client_hello()->signature_schemes(), false, policy);
877✔
222

223
   std::vector<uint8_t> buf = state.client_hello()->random();
868✔
224

225
   buf += state.server_hello()->random();
868✔
226
   buf += params();
868✔
227

228
   const bool signature_valid =
868✔
229
      state.callbacks().tls_verify_message(server_key, format.first, format.second, buf, m_signature);
868✔
230

231
#if defined(BOTAN_UNSAFE_FUZZER_MODE)
232
   BOTAN_UNUSED(signature_valid);
233
   return true;
234
#else
235
   return signature_valid;
868✔
236
#endif
237
}
868✔
238

239
const PK_Key_Agreement_Key& Server_Key_Exchange::server_kex_key() const {
605✔
240
   BOTAN_ASSERT_NONNULL(m_kex_key);
605✔
241
   return *m_kex_key;
605✔
242
}
243

244
}  // 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