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

randombit / botan / 20304984263

17 Dec 2025 01:46PM UTC coverage: 90.528% (+0.2%) from 90.358%
20304984263

Pull #5167

github

web-flow
Merge fc6e5fe09 into 3d96b675e
Pull Request #5167: Changes to reduce unnecessary inclusions

101179 of 111766 relevant lines covered (90.53%)

12666117.35 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/tls_policy.h>
15
#include <botan/internal/loadstor.h>
16
#include <botan/internal/target_info.h>
17
#include <botan/internal/tls_handshake_io.h>
18
#include <botan/internal/tls_handshake_state.h>
19
#include <botan/internal/tls_reader.h>
20

21
#include <botan/dh.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
      const 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();
4✔
45

46
      m_shared_group = Group_Params::NONE;
4✔
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()) {
4✔
58
         m_shared_group = policy.default_dh_group();
×
59
      } else {
60
         m_shared_group = policy.choose_key_exchange_group(dh_groups, {});
8✔
61
      }
62

63
      if(m_shared_group.value() == Group_Params::NONE) {
4✔
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");
4✔
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);
4✔
79
      auto* dh = dynamic_cast<DH_PrivateKey*>(m_kex_key.get());
4✔
80
      if(dh == nullptr) {
4✔
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);
12✔
85
      append_tls_length_value(m_params, dh->get_int_field("g").serialize(), 2);
12✔
86
      append_tls_length_value(m_params, dh->public_value(), 2);
12✔
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();
615✔
89

90
      if(ec_groups.empty()) {
615✔
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,230✔
95

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

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

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

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

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

128
   if(state.ciphersuite().signature_used()) {
656✔
129
      BOTAN_ASSERT(signing_key, "Signing key was set");
607✔
130

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

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

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

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

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

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

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

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

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

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

179
   m_params.assign(buf.data(), buf.data() + reader.read_so_far());
993✔
180

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

186
   reader.assert_done();
985✔
187
}
1,019✔
188

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

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

201
      append_tls_length_value(buf, m_signature, 2);
607✔
202
   }
203

204
   return buf;
656✔
205
}
×
206

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

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

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

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

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

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

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

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