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

randombit / botan / 20160266155

12 Dec 2025 08:01AM UTC coverage: 90.357% (-0.001%) from 90.358%
20160266155

push

github

web-flow
Merge pull request #5172 from randombit/jack/fix-clang-tidy-misc-const-correctness

Fix and enable clang-tidy warning misc-const-correctness

100951 of 111725 relevant lines covered (90.36%)

12817908.54 hits per line

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

91.26
/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

22
namespace Botan::TLS {
23

24
/**
25
* Create a new Server Key Exchange message
26
*/
27
Server_Key_Exchange::Server_Key_Exchange(Handshake_IO& io,
659✔
28
                                         Handshake_State& state,
29
                                         const Policy& policy,
30
                                         Credentials_Manager& creds,
31
                                         RandomNumberGenerator& rng,
32
                                         const Private_Key* signing_key) {
659✔
33
   const std::string hostname = state.client_hello()->sni_hostname();
659✔
34
   const Kex_Algo kex_algo = state.ciphersuite().kex_method();
659✔
35

36
   if(kex_algo == Kex_Algo::PSK || kex_algo == Kex_Algo::ECDHE_PSK) {
659✔
37
      const std::string identity_hint = creds.psk_identity_hint("tls-server", hostname);
50✔
38

39
      append_tls_length_value(m_params, identity_hint, 2);
100✔
40
   }
50✔
41

42
   if(kex_algo == Kex_Algo::DH) {
659✔
43
      const std::vector<Group_Params> dh_groups = state.client_hello()->supported_dh_groups();
5✔
44

45
      m_shared_group = Group_Params::NONE;
5✔
46

47
      /*
48
      RFC 7919 requires that if the client sends any groups in the FFDHE
49
      range, that we must select one of these. If this is not possible,
50
      then we are required to reject the connection.
51

52
      If the client did not send any DH groups, but did offer DH ciphersuites
53
      and we selected one, then consult the policy for which DH group to pick.
54
      */
55

56
      if(dh_groups.empty()) {
5✔
57
         m_shared_group = policy.default_dh_group();
×
58
      } else {
59
         m_shared_group = policy.choose_key_exchange_group(dh_groups, {});
10✔
60
      }
61

62
      if(m_shared_group.value() == Group_Params::NONE) {
5✔
63
         throw TLS_Exception(Alert::HandshakeFailure, "Could not agree on a DH group with the client");
×
64
      }
65

66
      // The policy had better return a group we know about:
67
      BOTAN_ASSERT(m_shared_group.value().is_dh_named_group(), "DH ciphersuite is using a known finite field group");
5✔
68

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

83
      append_tls_length_value(m_params, dh->get_int_field("p").serialize(), 2);
15✔
84
      append_tls_length_value(m_params, dh->get_int_field("g").serialize(), 2);
15✔
85
      append_tls_length_value(m_params, dh->public_value(), 2);
15✔
86
   } else if(kex_algo == Kex_Algo::ECDH || kex_algo == Kex_Algo::ECDHE_PSK) {
659✔
87
      const std::vector<Group_Params> ec_groups = state.client_hello()->supported_ecc_curves();
616✔
88

89
      if(ec_groups.empty()) {
616✔
90
         throw Internal_Error("Client sent no ECC extension but we negotiated ECDH");
×
91
      }
92

93
      m_shared_group = policy.choose_key_exchange_group(ec_groups, {});
1,232✔
94

95
      if(m_shared_group.value() == Group_Params::NONE) {
616✔
96
         throw TLS_Exception(Alert::HandshakeFailure, "No shared ECC group with client");
×
97
      }
98

99
      m_kex_key = [&] {
1,848✔
100
         if(m_shared_group->is_ecdh_named_curve()) {
616✔
101
            const auto pubkey_point_format = state.client_hello()->prefers_compressed_ec_points()
28✔
102
                                                ? EC_Point_Format::Compressed
28✔
103
                                                : EC_Point_Format::Uncompressed;
28✔
104
            return state.callbacks().tls12_generate_ephemeral_ecdh_key(*m_shared_group, rng, pubkey_point_format);
28✔
105
         } else {
106
            return state.callbacks().tls_generate_ephemeral_key(*m_shared_group, rng);
1,176✔
107
         }
108
      }();
616✔
109

110
      if(!m_kex_key) {
616✔
111
         throw TLS_Exception(Alert::InternalError, "Application did not provide an EC key");
×
112
      }
113

114
      const uint16_t named_curve_id = m_shared_group.value().wire_code();
616✔
115
      m_params.push_back(3);  // named curve
616✔
116
      m_params.push_back(get_byte<0>(named_curve_id));
616✔
117
      m_params.push_back(get_byte<1>(named_curve_id));
616✔
118

119
      // Note: In contrast to public_value(), raw_public_key_bits() takes the
120
      // point format (compressed vs. uncompressed) into account that was set
121
      // in its construction within tls_generate_ephemeral_key().
122
      append_tls_length_value(m_params, m_kex_key->raw_public_key_bits(), 1);
1,848✔
123
   } else if(kex_algo != Kex_Algo::PSK) {
654✔
124
      throw Internal_Error("Server_Key_Exchange: Unknown kex type " + kex_method_to_string(kex_algo));
×
125
   }
126

127
   if(state.ciphersuite().signature_used()) {
659✔
128
      BOTAN_ASSERT(signing_key, "Signing key was set");
609✔
129

130
      const std::pair<std::string, Signature_Format> format =
609✔
131
         state.choose_sig_format(*signing_key, m_scheme, false, policy);
609✔
132

133
      std::vector<uint8_t> buf = state.client_hello()->random();
609✔
134

135
      buf += state.server_hello()->random();
609✔
136
      buf += params();
609✔
137

138
      m_signature = state.callbacks().tls_sign_message(*signing_key, rng, format.first, format.second, buf);
609✔
139
   }
609✔
140

141
   state.hash().update(io.send(*this));
1,975✔
142
}
661✔
143

144
/**
145
* Deserialize a Server Key Exchange message
146
*/
147
Server_Key_Exchange::Server_Key_Exchange(const std::vector<uint8_t>& buf,
1,006✔
148
                                         const Kex_Algo kex_algo,
149
                                         const Auth_Method auth_method,
150
                                         Protocol_Version version) {
1,006✔
151
   BOTAN_UNUSED(version);  // remove this
1,006✔
152
   TLS_Data_Reader reader("ServerKeyExchange", buf);
1,006✔
153

154
   /*
155
   * Here we are deserializing enough to find out what offset the
156
   * signature is at. All processing is done when the Client Key Exchange
157
   * is prepared.
158
   */
159

160
   if(kex_algo == Kex_Algo::PSK || kex_algo == Kex_Algo::ECDHE_PSK) {
1,006✔
161
      reader.get_string(2, 0, 65535);  // identity hint
114✔
162
   }
163

164
   if(kex_algo == Kex_Algo::DH) {
1,006✔
165
      // 3 bigints, DH p, g, Y
166

167
      for(size_t i = 0; i != 3; ++i) {
91✔
168
         reader.get_range<uint8_t>(2, 1, 65535);
137✔
169
      }
170
   } else if(kex_algo == Kex_Algo::ECDH || kex_algo == Kex_Algo::ECDHE_PSK) {
980✔
171
      reader.get_byte();                     // curve type
949✔
172
      reader.get_uint16_t();                 // curve id
948✔
173
      reader.get_range<uint8_t>(1, 1, 255);  // public key
1,893✔
174
   } else if(kex_algo != Kex_Algo::PSK) {
31✔
175
      throw Decoding_Error("Server_Key_Exchange: Unsupported kex type " + kex_method_to_string(kex_algo));
×
176
   }
177

178
   m_params.assign(buf.data(), buf.data() + reader.read_so_far());
996✔
179

180
   if(auth_method != Auth_Method::IMPLICIT) {
996✔
181
      m_scheme = Signature_Scheme(reader.get_uint16_t());
939✔
182
      m_signature = reader.get_range<uint8_t>(2, 0, 65535);
936✔
183
   }
184

185
   reader.assert_done();
988✔
186
}
1,022✔
187

188
/**
189
* Serialize a Server Key Exchange message
190
*/
191
std::vector<uint8_t> Server_Key_Exchange::serialize() const {
659✔
192
   std::vector<uint8_t> buf = params();
659✔
193

194
   if(!m_signature.empty()) {
659✔
195
      if(m_scheme.is_set()) {
609✔
196
         buf.push_back(get_byte<0>(m_scheme.wire_code()));
609✔
197
         buf.push_back(get_byte<1>(m_scheme.wire_code()));
609✔
198
      }
199

200
      append_tls_length_value(buf, m_signature, 2);
609✔
201
   }
202

203
   return buf;
659✔
204
}
×
205

206
/**
207
* Verify a Server Key Exchange message
208
*/
209
bool Server_Key_Exchange::verify(const Public_Key& server_key,
927✔
210
                                 const Handshake_State& state,
211
                                 const Policy& policy) const {
212
   policy.check_peer_key_acceptable(server_key);
927✔
213

214
   const std::pair<std::string, Signature_Format> format =
878✔
215
      state.parse_sig_format(server_key, m_scheme, state.client_hello()->signature_schemes(), false, policy);
878✔
216

217
   std::vector<uint8_t> buf = state.client_hello()->random();
869✔
218

219
   buf += state.server_hello()->random();
869✔
220
   buf += params();
869✔
221

222
   const bool signature_valid =
869✔
223
      state.callbacks().tls_verify_message(server_key, format.first, format.second, buf, m_signature);
869✔
224

225
#if defined(BOTAN_UNSAFE_FUZZER_MODE)
226
   BOTAN_UNUSED(signature_valid);
227
   return true;
228
#else
229
   return signature_valid;
869✔
230
#endif
231
}
869✔
232

233
const PK_Key_Agreement_Key& Server_Key_Exchange::server_kex_key() const {
606✔
234
   BOTAN_ASSERT_NONNULL(m_kex_key);
606✔
235
   return *m_kex_key;
606✔
236
}
237

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