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

randombit / botan / 5123321399

30 May 2023 04:06PM UTC coverage: 92.213% (+0.004%) from 92.209%
5123321399

Pull #3558

github

web-flow
Merge dd72f7389 into 057bcbc35
Pull Request #3558: Add braces around all if/else statements

75602 of 81986 relevant lines covered (92.21%)

11859779.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/tls_handshake_io.h>
16
#include <botan/internal/tls_handshake_state.h>
17
#include <botan/internal/tls_reader.h>
18

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

23
#if defined(BOTAN_HAS_CURVE_25519)
24
   #include <botan/curve25519.h>
25
#endif
26

27
namespace Botan::TLS {
28

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

41
   if(kex_algo == Kex_Algo::PSK || kex_algo == Kex_Algo::ECDHE_PSK) {
604✔
42
      std::string identity_hint = creds.psk_identity_hint("tls-server", hostname);
45✔
43

44
      append_tls_length_value(m_params, identity_hint, 2);
90✔
45
   }
45✔
46

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

50
      m_shared_group = Group_Params::NONE;
4✔
51

52
      /*
53
      If the client does not send any DH groups in the supported groups
54
      extension, but does offer DH ciphersuites, we select a group arbitrarily
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, {});
4✔
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
      BOTAN_ASSERT(group_param_is_dh(m_shared_group.value()), "DH ciphersuite is using a finite field group");
4✔
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);
4✔
78
      auto dh = dynamic_cast<DH_PrivateKey*>(m_kex_key.get());
4✔
79
      if(!dh) {
4✔
80
         throw TLS_Exception(Alert::InternalError, "Application did not provide a Diffie-Hellman key");
×
81
      }
82

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

89
      if(ec_groups.empty()) {
566✔
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, {});
566✔
94

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

99
      std::vector<uint8_t> ecdh_public_val;
566✔
100

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

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

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

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

130
   if(state.ciphersuite().signature_used()) {
604✔
131
      BOTAN_ASSERT(signing_key, "Signing key was set");
559✔
132

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

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

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

140
      m_signature = state.callbacks().tls_sign_message(*signing_key, rng, format.first, format.second, buf);
559✔
141
   }
1,008✔
142

143
   state.hash().update(io.send(*this));
1,810✔
144
}
606✔
145

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

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

162
   if(kex_algo == Kex_Algo::PSK || kex_algo == Kex_Algo::ECDHE_PSK) {
745✔
163
      reader.get_string(2, 0, 65535);  // identity hint
104✔
164
   }
165

166
   if(kex_algo == Kex_Algo::DH) {
745✔
167
      // 3 bigints, DH p, g, Y
168

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

180
   m_params.assign(buf.data(), buf.data() + reader.read_so_far());
745✔
181

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

187
   reader.assert_done();
745✔
188
}
749✔
189

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

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

202
      append_tls_length_value(buf, m_signature, 2);
559✔
203
   }
204

205
   return buf;
604✔
206
}
×
207

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

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

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

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

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

227
#if defined(BOTAN_UNSAFE_FUZZER_MODE)
228
   BOTAN_UNUSED(signature_valid);
229
   return true;
230
#else
231
   return signature_valid;
689✔
232
#endif
233
}
1,246✔
234

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

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