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

randombit / botan / 16406612795

21 Jul 2025 01:35AM UTC coverage: 90.64% (-0.003%) from 90.643%
16406612795

push

github

web-flow
Merge pull request #5007 from randombit/jack/reduce-tls-header-includes

Remove some unnecessary includes in TLS

99948 of 110269 relevant lines covered (90.64%)

12421094.3 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/ecdh.h>
22

23
namespace Botan::TLS {
24

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

37
   if(kex_algo == Kex_Algo::PSK || kex_algo == Kex_Algo::ECDHE_PSK) {
656✔
38
      std::string identity_hint = creds.psk_identity_hint("tls-server", hostname);
49✔
39

40
      append_tls_length_value(m_params, identity_hint, 2);
98✔
41
   }
49✔
42

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

46
      m_shared_group = Group_Params::NONE;
6✔
47

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

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

57
      if(dh_groups.empty()) {
6✔
58
         m_shared_group = policy.default_dh_group();
×
59
      } else {
60
         m_shared_group = policy.choose_key_exchange_group(dh_groups, {});
12✔
61
      }
62

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

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

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

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

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

94
      m_shared_group = policy.choose_key_exchange_group(ec_groups, {});
1,226✔
95

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

100
      std::vector<uint8_t> ecdh_public_val;
613✔
101

102
      if(m_shared_group.value() == Group_Params::X25519 || m_shared_group.value() == Group_Params::X448) {
613✔
103
         m_kex_key = state.callbacks().tls_generate_ephemeral_key(m_shared_group.value(), rng);
588✔
104
         if(!m_kex_key) {
588✔
105
            throw TLS_Exception(Alert::InternalError, "Application did not provide an EC key");
×
106
         }
107
         ecdh_public_val = m_kex_key->public_value();
1,176✔
108
      } else {
109
         m_kex_key = state.callbacks().tls_generate_ephemeral_key(m_shared_group.value(), rng);
25✔
110
         auto* ecdh = dynamic_cast<ECDH_PrivateKey*>(m_kex_key.get());
25✔
111
         if(!ecdh) {
25✔
112
            throw TLS_Exception(Alert::InternalError, "Application did not provide a EC-Diffie-Hellman key");
×
113
         }
114

115
         // follow client's preference for point compression
116
         ecdh_public_val =
25✔
117
            ecdh->public_value(state.client_hello()->prefers_compressed_ec_points() ? EC_Point_Format::Compressed
75✔
118
                                                                                    : EC_Point_Format::Uncompressed);
25✔
119
      }
120

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

126
      append_tls_length_value(m_params, ecdh_public_val, 1);
1,226✔
127
   } else if(kex_algo != Kex_Algo::PSK) {
1,263✔
128
      throw Internal_Error("Server_Key_Exchange: Unknown kex type " + kex_method_to_string(kex_algo));
×
129
   }
130

131
   if(state.ciphersuite().signature_used()) {
656✔
132
      BOTAN_ASSERT(signing_key, "Signing key was set");
607✔
133

134
      std::pair<std::string, Signature_Format> format = state.choose_sig_format(*signing_key, m_scheme, false, policy);
607✔
135

136
      std::vector<uint8_t> buf = state.client_hello()->random();
607✔
137

138
      buf += state.server_hello()->random();
607✔
139
      buf += params();
607✔
140

141
      m_signature = state.callbacks().tls_sign_message(*signing_key, rng, format.first, format.second, buf);
607✔
142
   }
607✔
143

144
   state.hash().update(io.send(*this));
1,966✔
145
}
658✔
146

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

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

163
   if(kex_algo == Kex_Algo::PSK || kex_algo == Kex_Algo::ECDHE_PSK) {
1,003✔
164
      reader.get_string(2, 0, 65535);  // identity hint
112✔
165
   }
166

167
   if(kex_algo == Kex_Algo::DH) {
1,003✔
168
      // 3 bigints, DH p, g, Y
169

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

181
   m_params.assign(buf.data(), buf.data() + reader.read_so_far());
993✔
182

183
   if(auth_method != Auth_Method::IMPLICIT) {
993✔
184
      m_scheme = Signature_Scheme(reader.get_uint16_t());
937✔
185
      m_signature = reader.get_range<uint8_t>(2, 0, 65535);
934✔
186
   }
187

188
   reader.assert_done();
985✔
189
}
1,019✔
190

191
/**
192
* Serialize a Server Key Exchange message
193
*/
194
std::vector<uint8_t> Server_Key_Exchange::serialize() const {
656✔
195
   std::vector<uint8_t> buf = params();
656✔
196

197
   if(!m_signature.empty()) {
656✔
198
      if(m_scheme.is_set()) {
607✔
199
         buf.push_back(get_byte<0>(m_scheme.wire_code()));
607✔
200
         buf.push_back(get_byte<1>(m_scheme.wire_code()));
607✔
201
      }
202

203
      append_tls_length_value(buf, m_signature, 2);
607✔
204
   }
205

206
   return buf;
656✔
207
}
×
208

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

217
   std::pair<std::string, Signature_Format> format =
876✔
218
      state.parse_sig_format(server_key, m_scheme, state.client_hello()->signature_schemes(), false, policy);
876✔
219

220
   std::vector<uint8_t> buf = state.client_hello()->random();
867✔
221

222
   buf += state.server_hello()->random();
867✔
223
   buf += params();
867✔
224

225
   const bool signature_valid =
867✔
226
      state.callbacks().tls_verify_message(server_key, format.first, format.second, buf, m_signature);
867✔
227

228
#if defined(BOTAN_UNSAFE_FUZZER_MODE)
229
   BOTAN_UNUSED(signature_valid);
230
   return true;
231
#else
232
   return signature_valid;
867✔
233
#endif
234
}
867✔
235

236
const PK_Key_Agreement_Key& Server_Key_Exchange::server_kex_key() const {
604✔
237
   BOTAN_ASSERT_NONNULL(m_kex_key);
604✔
238
   return *m_kex_key;
604✔
239
}
240

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