/src/botan/src/lib/tls/msg_server_kex.cpp
Line | Count | Source (jump to first uncovered line) |
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 | | #include <botan/tls_extensions.h> |
11 | | #include <botan/internal/tls_reader.h> |
12 | | #include <botan/internal/tls_handshake_io.h> |
13 | | #include <botan/internal/tls_handshake_state.h> |
14 | | #include <botan/credentials_manager.h> |
15 | | #include <botan/loadstor.h> |
16 | | #include <botan/pubkey.h> |
17 | | |
18 | | #include <botan/dh.h> |
19 | | #include <botan/ecdh.h> |
20 | | |
21 | | #if defined(BOTAN_HAS_CURVE_25519) |
22 | | #include <botan/curve25519.h> |
23 | | #endif |
24 | | |
25 | | #if defined(BOTAN_HAS_CECPQ1) |
26 | | #include <botan/cecpq1.h> |
27 | | #endif |
28 | | |
29 | | #if defined(BOTAN_HAS_SRP6) |
30 | | #include <botan/srp6.h> |
31 | | #endif |
32 | | |
33 | | namespace Botan { |
34 | | |
35 | | namespace TLS { |
36 | | |
37 | | /** |
38 | | * Create a new Server Key Exchange message |
39 | | */ |
40 | | Server_Key_Exchange::Server_Key_Exchange(Handshake_IO& io, |
41 | | Handshake_State& state, |
42 | | const Policy& policy, |
43 | | Credentials_Manager& creds, |
44 | | RandomNumberGenerator& rng, |
45 | | const Private_Key* signing_key) |
46 | 24.3k | { |
47 | 24.3k | const std::string hostname = state.client_hello()->sni_hostname(); |
48 | 24.3k | const Kex_Algo kex_algo = state.ciphersuite().kex_method(); |
49 | 24.3k | |
50 | 24.3k | if(kex_algo == Kex_Algo::PSK || kex_algo == Kex_Algo::DHE_PSK || kex_algo == Kex_Algo::ECDHE_PSK) |
51 | 21.2k | { |
52 | 21.2k | std::string identity_hint = |
53 | 21.2k | creds.psk_identity_hint("tls-server", hostname); |
54 | 21.2k | |
55 | 21.2k | append_tls_length_value(m_params, identity_hint, 2); |
56 | 21.2k | } |
57 | 24.3k | |
58 | 24.3k | if(kex_algo == Kex_Algo::DH || kex_algo == Kex_Algo::DHE_PSK) |
59 | 5.63k | { |
60 | 5.63k | const std::vector<Group_Params> dh_groups = state.client_hello()->supported_dh_groups(); |
61 | 5.63k | |
62 | 5.63k | Group_Params shared_group = Group_Params::NONE; |
63 | 5.63k | |
64 | 5.63k | /* |
65 | 5.63k | If the client does not send any DH groups in the supported groups |
66 | 5.63k | extension, but does offer DH ciphersuites, we select a group arbitrarily |
67 | 5.63k | */ |
68 | 5.63k | |
69 | 5.63k | if(dh_groups.empty()) |
70 | 3.87k | { |
71 | 3.87k | shared_group = policy.default_dh_group(); |
72 | 3.87k | } |
73 | 1.76k | else |
74 | 1.76k | { |
75 | 1.76k | shared_group = policy.choose_key_exchange_group(dh_groups); |
76 | 1.76k | } |
77 | 5.63k | |
78 | 5.63k | if(shared_group == Group_Params::NONE) |
79 | 10 | throw TLS_Exception(Alert::HANDSHAKE_FAILURE, |
80 | 10 | "Could not agree on a DH group with the client"); |
81 | 5.62k | |
82 | 5.62k | BOTAN_ASSERT(group_param_is_dh(shared_group), "DH groups for the DH ciphersuites god"); |
83 | 5.62k | |
84 | 5.62k | const std::string group_name = state.callbacks().tls_decode_group_param(shared_group); |
85 | 5.62k | std::unique_ptr<DH_PrivateKey> dh(new DH_PrivateKey(rng, DL_Group(group_name))); |
86 | 5.62k | |
87 | 5.62k | append_tls_length_value(m_params, BigInt::encode(dh->get_domain().get_p()), 2); |
88 | 5.62k | append_tls_length_value(m_params, BigInt::encode(dh->get_domain().get_g()), 2); |
89 | 5.62k | append_tls_length_value(m_params, dh->public_value(), 2); |
90 | 5.62k | m_kex_key.reset(dh.release()); |
91 | 5.62k | } |
92 | 18.6k | else if(kex_algo == Kex_Algo::ECDH || kex_algo == Kex_Algo::ECDHE_PSK) |
93 | 18.2k | { |
94 | 18.2k | const std::vector<Group_Params> ec_groups = state.client_hello()->supported_ecc_curves(); |
95 | 18.2k | |
96 | 18.2k | if(ec_groups.empty()) |
97 | 0 | throw Internal_Error("Client sent no ECC extension but we negotiated ECDH"); |
98 | 18.2k | |
99 | 18.2k | Group_Params shared_group = policy.choose_key_exchange_group(ec_groups); |
100 | 18.2k | |
101 | 18.2k | if(shared_group == Group_Params::NONE) |
102 | 0 | throw TLS_Exception(Alert::HANDSHAKE_FAILURE, "No shared ECC group with client"); |
103 | 18.2k | |
104 | 18.2k | std::vector<uint8_t> ecdh_public_val; |
105 | 18.2k | |
106 | 18.2k | if(shared_group == Group_Params::X25519) |
107 | 423 | { |
108 | 423 | #if defined(BOTAN_HAS_CURVE_25519) |
109 | 423 | std::unique_ptr<Curve25519_PrivateKey> x25519(new Curve25519_PrivateKey(rng)); |
110 | 423 | ecdh_public_val = x25519->public_value(); |
111 | 423 | m_kex_key.reset(x25519.release()); |
112 | | #else |
113 | | throw Internal_Error("Negotiated X25519 somehow, but it is disabled"); |
114 | | #endif |
115 | | } |
116 | 17.8k | else |
117 | 17.8k | { |
118 | 17.8k | Group_Params curve = policy.choose_key_exchange_group(ec_groups); |
119 | 17.8k | |
120 | 17.8k | const std::string curve_name = state.callbacks().tls_decode_group_param(curve); |
121 | 17.8k | |
122 | 17.8k | EC_Group ec_group(curve_name); |
123 | 17.8k | std::unique_ptr<ECDH_PrivateKey> ecdh(new ECDH_PrivateKey(rng, ec_group)); |
124 | 17.8k | |
125 | 17.8k | // follow client's preference for point compression |
126 | 17.8k | ecdh_public_val = ecdh->public_value( |
127 | 17.8k | state.client_hello()->prefers_compressed_ec_points() ? |
128 | 17.5k | PointGFp::COMPRESSED : PointGFp::UNCOMPRESSED); |
129 | 17.8k | |
130 | 17.8k | m_kex_key.reset(ecdh.release()); |
131 | 17.8k | } |
132 | 18.2k | |
133 | 18.2k | const uint16_t named_curve_id = static_cast<uint16_t>(shared_group); |
134 | 18.2k | m_params.push_back(3); // named curve |
135 | 18.2k | m_params.push_back(get_byte(0, named_curve_id)); |
136 | 18.2k | m_params.push_back(get_byte(1, named_curve_id)); |
137 | 18.2k | |
138 | 18.2k | append_tls_length_value(m_params, ecdh_public_val, 1); |
139 | 18.2k | } |
140 | 471 | #if defined(BOTAN_HAS_SRP6) |
141 | 471 | else if(kex_algo == Kex_Algo::SRP_SHA) |
142 | 0 | { |
143 | 0 | const std::string srp_identifier = state.client_hello()->srp_identifier(); |
144 | 0 |
|
145 | 0 | std::string group_id; |
146 | 0 | BigInt v; |
147 | 0 | std::vector<uint8_t> salt; |
148 | 0 |
|
149 | 0 | const bool found = creds.srp_verifier("tls-server", hostname, |
150 | 0 | srp_identifier, |
151 | 0 | group_id, v, salt, |
152 | 0 | policy.hide_unknown_users()); |
153 | 0 |
|
154 | 0 | if(!found) |
155 | 0 | throw TLS_Exception(Alert::UNKNOWN_PSK_IDENTITY, |
156 | 0 | "Unknown SRP user " + srp_identifier); |
157 | 0 | |
158 | 0 | m_srp_params.reset(new SRP6_Server_Session); |
159 | 0 |
|
160 | 0 | BigInt B = m_srp_params->step1(v, group_id, |
161 | 0 | "SHA-1", rng); |
162 | 0 |
|
163 | 0 | DL_Group group(group_id); |
164 | 0 |
|
165 | 0 | append_tls_length_value(m_params, BigInt::encode(group.get_p()), 2); |
166 | 0 | append_tls_length_value(m_params, BigInt::encode(group.get_g()), 2); |
167 | 0 | append_tls_length_value(m_params, salt, 1); |
168 | 0 | append_tls_length_value(m_params, BigInt::encode(B), 2); |
169 | 0 | } |
170 | 471 | #endif |
171 | 471 | #if defined(BOTAN_HAS_CECPQ1) |
172 | 471 | else if(kex_algo == Kex_Algo::CECPQ1) |
173 | 0 | { |
174 | 0 | std::vector<uint8_t> cecpq1_offer(CECPQ1_OFFER_BYTES); |
175 | 0 | m_cecpq1_key.reset(new CECPQ1_key); |
176 | 0 | CECPQ1_offer(cecpq1_offer.data(), m_cecpq1_key.get(), rng); |
177 | 0 | append_tls_length_value(m_params, cecpq1_offer, 2); |
178 | 0 | } |
179 | 471 | #endif |
180 | 471 | else if(kex_algo != Kex_Algo::PSK) |
181 | 0 | { |
182 | 0 | throw Internal_Error("Server_Key_Exchange: Unknown kex type " + |
183 | 0 | kex_method_to_string(kex_algo)); |
184 | 0 | } |
185 | 24.3k | |
186 | 24.3k | if(state.ciphersuite().signature_used()) |
187 | 0 | { |
188 | 0 | BOTAN_ASSERT(signing_key, "Signing key was set"); |
189 | 0 |
|
190 | 0 | std::pair<std::string, Signature_Format> format = |
191 | 0 | state.choose_sig_format(*signing_key, m_scheme, false, policy); |
192 | 0 |
|
193 | 0 | std::vector<uint8_t> buf = state.client_hello()->random(); |
194 | 0 |
|
195 | 0 | buf += state.server_hello()->random(); |
196 | 0 | buf += params(); |
197 | 0 |
|
198 | 0 | m_signature = |
199 | 0 | state.callbacks().tls_sign_message(*signing_key, rng, |
200 | 0 | format.first, format.second, buf); |
201 | 0 | } |
202 | 24.3k | |
203 | 24.3k | state.hash().update(io.send(*this)); |
204 | 24.3k | } |
205 | | |
206 | | /** |
207 | | * Deserialize a Server Key Exchange message |
208 | | */ |
209 | | Server_Key_Exchange::Server_Key_Exchange(const std::vector<uint8_t>& buf, |
210 | | const Kex_Algo kex_algo, |
211 | | const Auth_Method auth_method, |
212 | | Protocol_Version version) |
213 | 737 | { |
214 | 737 | TLS_Data_Reader reader("ServerKeyExchange", buf); |
215 | 737 | |
216 | 737 | /* |
217 | 737 | * Here we are deserializing enough to find out what offset the |
218 | 737 | * signature is at. All processing is done when the Client Key Exchange |
219 | 737 | * is prepared. |
220 | 737 | */ |
221 | 737 | |
222 | 737 | if(kex_algo == Kex_Algo::PSK || kex_algo == Kex_Algo::DHE_PSK || kex_algo == Kex_Algo::ECDHE_PSK) |
223 | 31 | { |
224 | 31 | reader.get_string(2, 0, 65535); // identity hint |
225 | 31 | } |
226 | 737 | |
227 | 737 | if(kex_algo == Kex_Algo::DH || kex_algo == Kex_Algo::DHE_PSK) |
228 | 218 | { |
229 | 218 | // 3 bigints, DH p, g, Y |
230 | 218 | |
231 | 866 | for(size_t i = 0; i != 3; ++i) |
232 | 648 | { |
233 | 648 | reader.get_range<uint8_t>(2, 1, 65535); |
234 | 648 | } |
235 | 218 | } |
236 | 519 | else if(kex_algo == Kex_Algo::ECDH || kex_algo == Kex_Algo::ECDHE_PSK) |
237 | 503 | { |
238 | 503 | reader.get_byte(); // curve type |
239 | 503 | reader.get_uint16_t(); // curve id |
240 | 503 | reader.get_range<uint8_t>(1, 1, 255); // public key |
241 | 503 | } |
242 | 16 | else if(kex_algo == Kex_Algo::SRP_SHA) |
243 | 0 | { |
244 | 0 | // 2 bigints (N,g) then salt, then server B |
245 | 0 |
|
246 | 0 | reader.get_range<uint8_t>(2, 1, 65535); |
247 | 0 | reader.get_range<uint8_t>(2, 1, 65535); |
248 | 0 | reader.get_range<uint8_t>(1, 1, 255); |
249 | 0 | reader.get_range<uint8_t>(2, 1, 65535); |
250 | 0 | } |
251 | 16 | else if(kex_algo == Kex_Algo::CECPQ1) |
252 | 1 | { |
253 | 1 | // u16 blob |
254 | 1 | reader.get_range<uint8_t>(2, 1, 65535); |
255 | 1 | } |
256 | 15 | else if(kex_algo != Kex_Algo::PSK) |
257 | 0 | throw Decoding_Error("Server_Key_Exchange: Unsupported kex type " + |
258 | 0 | kex_method_to_string(kex_algo)); |
259 | 737 | |
260 | 737 | m_params.assign(buf.data(), buf.data() + reader.read_so_far()); |
261 | 737 | |
262 | 737 | if(auth_method != Auth_Method::ANONYMOUS && auth_method != Auth_Method::IMPLICIT) |
263 | 372 | { |
264 | 372 | if(version.supports_negotiable_signature_algorithms()) |
265 | 372 | { |
266 | 372 | m_scheme = static_cast<Signature_Scheme>(reader.get_uint16_t()); |
267 | 372 | } |
268 | 372 | |
269 | 372 | m_signature = reader.get_range<uint8_t>(2, 0, 65535); |
270 | 372 | } |
271 | 737 | |
272 | 737 | reader.assert_done(); |
273 | 737 | } |
274 | | |
275 | | /** |
276 | | * Serialize a Server Key Exchange message |
277 | | */ |
278 | | std::vector<uint8_t> Server_Key_Exchange::serialize() const |
279 | 24.3k | { |
280 | 24.3k | std::vector<uint8_t> buf = params(); |
281 | 24.3k | |
282 | 24.3k | if(m_signature.size()) |
283 | 0 | { |
284 | 0 | if(m_scheme != Signature_Scheme::NONE) |
285 | 0 | { |
286 | 0 | const uint16_t scheme_code = static_cast<uint16_t>(m_scheme); |
287 | 0 | buf.push_back(get_byte(0, scheme_code)); |
288 | 0 | buf.push_back(get_byte(1, scheme_code)); |
289 | 0 | } |
290 | 0 |
|
291 | 0 | append_tls_length_value(buf, m_signature, 2); |
292 | 0 | } |
293 | 24.3k | |
294 | 24.3k | return buf; |
295 | 24.3k | } |
296 | | |
297 | | /** |
298 | | * Verify a Server Key Exchange message |
299 | | */ |
300 | | bool Server_Key_Exchange::verify(const Public_Key& server_key, |
301 | | const Handshake_State& state, |
302 | | const Policy& policy) const |
303 | 369 | { |
304 | 369 | policy.check_peer_key_acceptable(server_key); |
305 | 369 | |
306 | 369 | std::pair<std::string, Signature_Format> format = |
307 | 369 | state.parse_sig_format(server_key, m_scheme, false, policy); |
308 | 369 | |
309 | 369 | std::vector<uint8_t> buf = state.client_hello()->random(); |
310 | 369 | |
311 | 369 | buf += state.server_hello()->random(); |
312 | 369 | buf += params(); |
313 | 369 | |
314 | 369 | const bool signature_valid = |
315 | 369 | state.callbacks().tls_verify_message(server_key, format.first, format.second, |
316 | 369 | buf, m_signature); |
317 | 369 | |
318 | 369 | #if defined(BOTAN_UNSAFE_FUZZER_MODE) |
319 | 369 | BOTAN_UNUSED(signature_valid); |
320 | 369 | return true; |
321 | | #else |
322 | | return signature_valid; |
323 | | #endif |
324 | | } |
325 | | |
326 | | const Private_Key& Server_Key_Exchange::server_kex_key() const |
327 | 14.0k | { |
328 | 14.0k | BOTAN_ASSERT_NONNULL(m_kex_key); |
329 | 14.0k | return *m_kex_key; |
330 | 14.0k | } |
331 | | |
332 | | } |
333 | | |
334 | | } |