/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/internal/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 | | namespace Botan { |
30 | | |
31 | | namespace TLS { |
32 | | |
33 | | /** |
34 | | * Create a new Server Key Exchange message |
35 | | */ |
36 | | Server_Key_Exchange::Server_Key_Exchange(Handshake_IO& io, |
37 | | Handshake_State& state, |
38 | | const Policy& policy, |
39 | | Credentials_Manager& creds, |
40 | | RandomNumberGenerator& rng, |
41 | | const Private_Key* signing_key) |
42 | 21.4k | { |
43 | 21.4k | const std::string hostname = state.client_hello()->sni_hostname(); |
44 | 21.4k | const Kex_Algo kex_algo = state.ciphersuite().kex_method(); |
45 | | |
46 | 21.4k | if(kex_algo == Kex_Algo::PSK || kex_algo == Kex_Algo::ECDHE_PSK) |
47 | 21.4k | { |
48 | 21.4k | std::string identity_hint = |
49 | 21.4k | creds.psk_identity_hint("tls-server", hostname); |
50 | | |
51 | 21.4k | append_tls_length_value(m_params, identity_hint, 2); |
52 | 21.4k | } |
53 | | |
54 | 21.4k | if(kex_algo == Kex_Algo::DH) |
55 | 0 | { |
56 | 0 | const std::vector<Group_Params> dh_groups = state.client_hello()->supported_dh_groups(); |
57 | |
|
58 | 0 | Group_Params shared_group = Group_Params::NONE; |
59 | | |
60 | | /* |
61 | | If the client does not send any DH groups in the supported groups |
62 | | extension, but does offer DH ciphersuites, we select a group arbitrarily |
63 | | */ |
64 | |
|
65 | 0 | if(dh_groups.empty()) |
66 | 0 | { |
67 | 0 | shared_group = policy.default_dh_group(); |
68 | 0 | } |
69 | 0 | else |
70 | 0 | { |
71 | 0 | shared_group = policy.choose_key_exchange_group(dh_groups); |
72 | 0 | } |
73 | |
|
74 | 0 | if(shared_group == Group_Params::NONE) |
75 | 0 | throw TLS_Exception(Alert::HANDSHAKE_FAILURE, |
76 | 0 | "Could not agree on a DH group with the client"); |
77 | | |
78 | 0 | BOTAN_ASSERT(group_param_is_dh(shared_group), "DH groups for the DH ciphersuites god"); |
79 | |
|
80 | 0 | const std::string group_name = state.callbacks().tls_decode_group_param(shared_group); |
81 | 0 | std::unique_ptr<DH_PrivateKey> dh(new DH_PrivateKey(rng, DL_Group(group_name))); |
82 | |
|
83 | 0 | append_tls_length_value(m_params, BigInt::encode(dh->get_domain().get_p()), 2); |
84 | 0 | append_tls_length_value(m_params, BigInt::encode(dh->get_domain().get_g()), 2); |
85 | 0 | append_tls_length_value(m_params, dh->public_value(), 2); |
86 | 0 | m_kex_key.reset(dh.release()); |
87 | 0 | } |
88 | 21.4k | else if(kex_algo == Kex_Algo::ECDH || kex_algo == Kex_Algo::ECDHE_PSK) |
89 | 20.8k | { |
90 | 20.8k | const std::vector<Group_Params> ec_groups = state.client_hello()->supported_ecc_curves(); |
91 | | |
92 | 20.8k | if(ec_groups.empty()) |
93 | 0 | throw Internal_Error("Client sent no ECC extension but we negotiated ECDH"); |
94 | | |
95 | 20.8k | Group_Params shared_group = policy.choose_key_exchange_group(ec_groups); |
96 | | |
97 | 20.8k | if(shared_group == Group_Params::NONE) |
98 | 0 | throw TLS_Exception(Alert::HANDSHAKE_FAILURE, "No shared ECC group with client"); |
99 | | |
100 | 20.8k | std::vector<uint8_t> ecdh_public_val; |
101 | | |
102 | 20.8k | if(shared_group == Group_Params::X25519) |
103 | 575 | { |
104 | 575 | #if defined(BOTAN_HAS_CURVE_25519) |
105 | 575 | std::unique_ptr<Curve25519_PrivateKey> x25519(new Curve25519_PrivateKey(rng)); |
106 | 575 | ecdh_public_val = x25519->public_value(); |
107 | 575 | m_kex_key.reset(x25519.release()); |
108 | | #else |
109 | | throw Internal_Error("Negotiated X25519 somehow, but it is disabled"); |
110 | | #endif |
111 | 575 | } |
112 | 20.3k | else |
113 | 20.3k | { |
114 | 20.3k | Group_Params curve = policy.choose_key_exchange_group(ec_groups); |
115 | | |
116 | 20.3k | const std::string curve_name = state.callbacks().tls_decode_group_param(curve); |
117 | | |
118 | 20.3k | EC_Group ec_group(curve_name); |
119 | 20.3k | std::unique_ptr<ECDH_PrivateKey> ecdh(new ECDH_PrivateKey(rng, ec_group)); |
120 | | |
121 | | // follow client's preference for point compression |
122 | 20.3k | ecdh_public_val = ecdh->public_value( |
123 | 20.3k | state.client_hello()->prefers_compressed_ec_points() ? |
124 | 12.0k | PointGFp::COMPRESSED : PointGFp::UNCOMPRESSED); |
125 | | |
126 | 20.3k | m_kex_key.reset(ecdh.release()); |
127 | 20.3k | } |
128 | | |
129 | 20.8k | const uint16_t named_curve_id = static_cast<uint16_t>(shared_group); |
130 | 20.8k | m_params.push_back(3); // named curve |
131 | 20.8k | m_params.push_back(get_byte(0, named_curve_id)); |
132 | 20.8k | m_params.push_back(get_byte(1, named_curve_id)); |
133 | | |
134 | 20.8k | append_tls_length_value(m_params, ecdh_public_val, 1); |
135 | 20.8k | } |
136 | 569 | #if defined(BOTAN_HAS_CECPQ1) |
137 | 569 | else if(kex_algo == Kex_Algo::CECPQ1) |
138 | 0 | { |
139 | 0 | std::vector<uint8_t> cecpq1_offer(CECPQ1_OFFER_BYTES); |
140 | 0 | m_cecpq1_key.reset(new CECPQ1_key); |
141 | 0 | CECPQ1_offer(cecpq1_offer.data(), m_cecpq1_key.get(), rng); |
142 | 0 | append_tls_length_value(m_params, cecpq1_offer, 2); |
143 | 0 | } |
144 | 569 | #endif |
145 | 569 | else if(kex_algo != Kex_Algo::PSK) |
146 | 0 | { |
147 | 0 | throw Internal_Error("Server_Key_Exchange: Unknown kex type " + |
148 | 0 | kex_method_to_string(kex_algo)); |
149 | 0 | } |
150 | | |
151 | 21.4k | if(state.ciphersuite().signature_used()) |
152 | 0 | { |
153 | 0 | BOTAN_ASSERT(signing_key, "Signing key was set"); |
154 | |
|
155 | 0 | std::pair<std::string, Signature_Format> format = |
156 | 0 | state.choose_sig_format(*signing_key, m_scheme, false, policy); |
157 | |
|
158 | 0 | std::vector<uint8_t> buf = state.client_hello()->random(); |
159 | |
|
160 | 0 | buf += state.server_hello()->random(); |
161 | 0 | buf += params(); |
162 | |
|
163 | 0 | m_signature = |
164 | 0 | state.callbacks().tls_sign_message(*signing_key, rng, |
165 | 0 | format.first, format.second, buf); |
166 | 0 | } |
167 | | |
168 | 21.4k | state.hash().update(io.send(*this)); |
169 | 21.4k | } |
170 | | |
171 | | /** |
172 | | * Deserialize a Server Key Exchange message |
173 | | */ |
174 | | Server_Key_Exchange::Server_Key_Exchange(const std::vector<uint8_t>& buf, |
175 | | const Kex_Algo kex_algo, |
176 | | const Auth_Method auth_method, |
177 | | Protocol_Version version) |
178 | 1.40k | { |
179 | 1.40k | TLS_Data_Reader reader("ServerKeyExchange", buf); |
180 | | |
181 | | /* |
182 | | * Here we are deserializing enough to find out what offset the |
183 | | * signature is at. All processing is done when the Client Key Exchange |
184 | | * is prepared. |
185 | | */ |
186 | | |
187 | 1.40k | if(kex_algo == Kex_Algo::PSK || kex_algo == Kex_Algo::ECDHE_PSK) |
188 | 1.10k | { |
189 | 1.10k | reader.get_string(2, 0, 65535); // identity hint |
190 | 1.10k | } |
191 | | |
192 | 1.40k | if(kex_algo == Kex_Algo::DH) |
193 | 3 | { |
194 | | // 3 bigints, DH p, g, Y |
195 | | |
196 | 11 | for(size_t i = 0; i != 3; ++i) |
197 | 8 | { |
198 | 8 | reader.get_range<uint8_t>(2, 1, 65535); |
199 | 8 | } |
200 | 3 | } |
201 | 1.40k | else if(kex_algo == Kex_Algo::ECDH || kex_algo == Kex_Algo::ECDHE_PSK) |
202 | 1.03k | { |
203 | 1.03k | reader.get_byte(); // curve type |
204 | 1.03k | reader.get_uint16_t(); // curve id |
205 | 1.03k | reader.get_range<uint8_t>(1, 1, 255); // public key |
206 | 1.03k | } |
207 | 369 | else if(kex_algo == Kex_Algo::CECPQ1) |
208 | 1 | { |
209 | | // u16 blob |
210 | 1 | reader.get_range<uint8_t>(2, 1, 65535); |
211 | 1 | } |
212 | 368 | else if(kex_algo != Kex_Algo::PSK) |
213 | 0 | throw Decoding_Error("Server_Key_Exchange: Unsupported kex type " + |
214 | 0 | kex_method_to_string(kex_algo)); |
215 | | |
216 | 1.40k | m_params.assign(buf.data(), buf.data() + reader.read_so_far()); |
217 | | |
218 | 1.40k | if(auth_method != Auth_Method::IMPLICIT) |
219 | 304 | { |
220 | 304 | if(version.supports_negotiable_signature_algorithms()) |
221 | 304 | { |
222 | 304 | m_scheme = static_cast<Signature_Scheme>(reader.get_uint16_t()); |
223 | 304 | } |
224 | | |
225 | 304 | m_signature = reader.get_range<uint8_t>(2, 0, 65535); |
226 | 304 | } |
227 | | |
228 | 1.40k | reader.assert_done(); |
229 | 1.40k | } |
230 | | |
231 | | /** |
232 | | * Serialize a Server Key Exchange message |
233 | | */ |
234 | | std::vector<uint8_t> Server_Key_Exchange::serialize() const |
235 | 21.4k | { |
236 | 21.4k | std::vector<uint8_t> buf = params(); |
237 | | |
238 | 21.4k | if(m_signature.size()) |
239 | 0 | { |
240 | 0 | if(m_scheme != Signature_Scheme::NONE) |
241 | 0 | { |
242 | 0 | const uint16_t scheme_code = static_cast<uint16_t>(m_scheme); |
243 | 0 | buf.push_back(get_byte(0, scheme_code)); |
244 | 0 | buf.push_back(get_byte(1, scheme_code)); |
245 | 0 | } |
246 | |
|
247 | 0 | append_tls_length_value(buf, m_signature, 2); |
248 | 0 | } |
249 | | |
250 | 21.4k | return buf; |
251 | 21.4k | } |
252 | | |
253 | | /** |
254 | | * Verify a Server Key Exchange message |
255 | | */ |
256 | | bool Server_Key_Exchange::verify(const Public_Key& server_key, |
257 | | const Handshake_State& state, |
258 | | const Policy& policy) const |
259 | 301 | { |
260 | 301 | policy.check_peer_key_acceptable(server_key); |
261 | | |
262 | 301 | std::pair<std::string, Signature_Format> format = |
263 | 301 | state.parse_sig_format(server_key, m_scheme, false, policy); |
264 | | |
265 | 301 | std::vector<uint8_t> buf = state.client_hello()->random(); |
266 | | |
267 | 301 | buf += state.server_hello()->random(); |
268 | 301 | buf += params(); |
269 | | |
270 | 301 | const bool signature_valid = |
271 | 301 | state.callbacks().tls_verify_message(server_key, format.first, format.second, |
272 | 301 | buf, m_signature); |
273 | | |
274 | 301 | #if defined(BOTAN_UNSAFE_FUZZER_MODE) |
275 | 301 | BOTAN_UNUSED(signature_valid); |
276 | 301 | return true; |
277 | | #else |
278 | | return signature_valid; |
279 | | #endif |
280 | 301 | } |
281 | | |
282 | | const Private_Key& Server_Key_Exchange::server_kex_key() const |
283 | 9.30k | { |
284 | 9.30k | BOTAN_ASSERT_NONNULL(m_kex_key); |
285 | 9.30k | return *m_kex_key; |
286 | 9.30k | } |
287 | | |
288 | | } |
289 | | |
290 | | } |