/src/botan/src/lib/tls/tls_client.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * TLS Client |
3 | | * (C) 2004-2011,2012,2015,2016 Jack Lloyd |
4 | | * 2016 Matthias Gierlings |
5 | | * 2017 Harry Reimann, Rohde & Schwarz Cybersecurity |
6 | | * |
7 | | * Botan is released under the Simplified BSD License (see license.txt) |
8 | | */ |
9 | | |
10 | | #include <botan/tls_client.h> |
11 | | #include <botan/tls_messages.h> |
12 | | #include <botan/internal/tls_handshake_state.h> |
13 | | #include <botan/internal/stl_util.h> |
14 | | #include <iterator> |
15 | | #include <sstream> |
16 | | |
17 | | namespace Botan { |
18 | | |
19 | | namespace TLS { |
20 | | |
21 | | namespace { |
22 | | |
23 | | class Client_Handshake_State final : public Handshake_State |
24 | | { |
25 | | public: |
26 | | Client_Handshake_State(Handshake_IO* io, Callbacks& cb) : |
27 | | Handshake_State(io, cb), |
28 | | m_is_reneg(false) |
29 | 14.5k | {} |
30 | | |
31 | | const Public_Key& get_server_public_key() const |
32 | 369 | { |
33 | 369 | BOTAN_ASSERT(server_public_key, "Server sent us a certificate"); |
34 | 369 | return *server_public_key.get(); |
35 | 369 | } |
36 | | |
37 | 144 | bool is_a_resumption() const { return (resumed_session != nullptr); } |
38 | | |
39 | 0 | bool is_a_renegotiation() const { return m_is_reneg; } |
40 | | |
41 | | const secure_vector<uint8_t>& resume_master_secret() const |
42 | 0 | { |
43 | 0 | BOTAN_STATE_CHECK(is_a_resumption()); |
44 | 0 | return resumed_session->master_secret(); |
45 | 0 | } |
46 | | |
47 | | const std::vector<X509_Certificate>& resume_peer_certs() const |
48 | 0 | { |
49 | 0 | BOTAN_STATE_CHECK(is_a_resumption()); |
50 | 0 | return resumed_session->peer_certs(); |
51 | 0 | } |
52 | | |
53 | | std::unique_ptr<Public_Key> server_public_key; |
54 | | // Used during session resumption |
55 | | std::unique_ptr<Session> resumed_session; |
56 | | bool m_is_reneg = false; |
57 | | }; |
58 | | |
59 | | } |
60 | | |
61 | | /* |
62 | | * TLS Client Constructor |
63 | | */ |
64 | | Client::Client(Callbacks& callbacks, |
65 | | Session_Manager& session_manager, |
66 | | Credentials_Manager& creds, |
67 | | const Policy& policy, |
68 | | RandomNumberGenerator& rng, |
69 | | const Server_Information& info, |
70 | | const Protocol_Version& offer_version, |
71 | | const std::vector<std::string>& next_protos, |
72 | | size_t io_buf_sz) : |
73 | | Channel(callbacks, session_manager, rng, policy, |
74 | | false, offer_version.is_datagram_protocol(), io_buf_sz), |
75 | | m_creds(creds), |
76 | | m_info(info) |
77 | 5.71k | { |
78 | 5.71k | init(offer_version, next_protos); |
79 | 5.71k | } |
80 | | |
81 | | Client::Client(output_fn data_output_fn, |
82 | | data_cb proc_cb, |
83 | | alert_cb recv_alert_cb, |
84 | | handshake_cb hs_cb, |
85 | | Session_Manager& session_manager, |
86 | | Credentials_Manager& creds, |
87 | | const Policy& policy, |
88 | | RandomNumberGenerator& rng, |
89 | | const Server_Information& info, |
90 | | const Protocol_Version& offer_version, |
91 | | const std::vector<std::string>& next_protos, |
92 | | size_t io_buf_sz) : |
93 | | Channel(data_output_fn, proc_cb, recv_alert_cb, hs_cb, Channel::handshake_msg_cb(), |
94 | | session_manager, rng, policy, false, offer_version.is_datagram_protocol(), io_buf_sz), |
95 | | m_creds(creds), |
96 | | m_info(info) |
97 | 0 | { |
98 | 0 | init(offer_version, next_protos); |
99 | 0 | } |
100 | | |
101 | | Client::Client(output_fn data_output_fn, |
102 | | data_cb proc_cb, |
103 | | alert_cb recv_alert_cb, |
104 | | handshake_cb hs_cb, |
105 | | handshake_msg_cb hs_msg_cb, |
106 | | Session_Manager& session_manager, |
107 | | Credentials_Manager& creds, |
108 | | const Policy& policy, |
109 | | RandomNumberGenerator& rng, |
110 | | const Server_Information& info, |
111 | | const Protocol_Version& offer_version, |
112 | | const std::vector<std::string>& next_protos) : |
113 | | Channel(data_output_fn, proc_cb, recv_alert_cb, hs_cb, hs_msg_cb, |
114 | | session_manager, rng, policy, false, offer_version.is_datagram_protocol()), |
115 | | m_creds(creds), |
116 | | m_info(info) |
117 | 0 | { |
118 | 0 | init(offer_version, next_protos); |
119 | 0 | } |
120 | | |
121 | | void Client::init(const Protocol_Version& protocol_version, |
122 | | const std::vector<std::string>& next_protocols) |
123 | 5.71k | { |
124 | 5.71k | const std::string srp_identifier = m_creds.srp_identifier("tls-client", m_info.hostname()); |
125 | 5.71k | |
126 | 5.71k | Handshake_State& state = create_handshake_state(protocol_version); |
127 | 5.71k | send_client_hello(state, false, protocol_version, |
128 | 5.71k | srp_identifier, next_protocols); |
129 | 5.71k | } |
130 | | |
131 | | Handshake_State* Client::new_handshake_state(Handshake_IO* io) |
132 | 14.5k | { |
133 | 14.5k | return new Client_Handshake_State(io, callbacks()); |
134 | 14.5k | } |
135 | | |
136 | | std::vector<X509_Certificate> |
137 | | Client::get_peer_cert_chain(const Handshake_State& state) const |
138 | 100 | { |
139 | 100 | const Client_Handshake_State& cstate = dynamic_cast<const Client_Handshake_State&>(state); |
140 | 100 | |
141 | 100 | if(cstate.is_a_resumption()) |
142 | 0 | return cstate.resume_peer_certs(); |
143 | 100 | |
144 | 100 | if(state.server_certs()) |
145 | 50 | return state.server_certs()->cert_chain(); |
146 | 50 | return std::vector<X509_Certificate>(); |
147 | 50 | } |
148 | | |
149 | | /* |
150 | | * Send a new client hello to renegotiate |
151 | | */ |
152 | | void Client::initiate_handshake(Handshake_State& state, |
153 | | bool force_full_renegotiation) |
154 | 0 | { |
155 | 0 | send_client_hello(state, force_full_renegotiation, |
156 | 0 | policy().latest_supported_version(state.version().is_datagram_protocol())); |
157 | 0 | } |
158 | | |
159 | | void Client::send_client_hello(Handshake_State& state_base, |
160 | | bool force_full_renegotiation, |
161 | | Protocol_Version version, |
162 | | const std::string& srp_identifier, |
163 | | const std::vector<std::string>& next_protocols) |
164 | 5.71k | { |
165 | 5.71k | Client_Handshake_State& state = dynamic_cast<Client_Handshake_State&>(state_base); |
166 | 5.71k | |
167 | 5.71k | if(state.version().is_datagram_protocol()) |
168 | 0 | state.set_expected_next(HELLO_VERIFY_REQUEST); // optional |
169 | 5.71k | state.set_expected_next(SERVER_HELLO); |
170 | 5.71k | |
171 | 5.71k | if(!force_full_renegotiation && !m_info.empty()) |
172 | 5.71k | { |
173 | 5.71k | std::unique_ptr<Session> session_info(new Session);; |
174 | 5.71k | if(session_manager().load_from_server_info(m_info, *session_info)) |
175 | 0 | { |
176 | 0 | /* |
177 | 0 | Ensure that the session protocol cipher and version are acceptable |
178 | 0 | If not skip the resume and establish a new session |
179 | 0 | */ |
180 | 0 | const bool exact_version = session_info->version() == version; |
181 | 0 | const bool ok_version = |
182 | 0 | (session_info->version().is_datagram_protocol() == version.is_datagram_protocol()) && |
183 | 0 | policy().acceptable_protocol_version(session_info->version()); |
184 | 0 |
|
185 | 0 | const bool session_version_ok = policy().only_resume_with_exact_version() ? exact_version : ok_version; |
186 | 0 |
|
187 | 0 | if(policy().acceptable_ciphersuite(session_info->ciphersuite()) && session_version_ok) |
188 | 0 | { |
189 | 0 | if(srp_identifier == "" || session_info->srp_identifier() == srp_identifier) |
190 | 0 | { |
191 | 0 | state.client_hello( |
192 | 0 | new Client_Hello(state.handshake_io(), |
193 | 0 | state.hash(), |
194 | 0 | policy(), |
195 | 0 | callbacks(), |
196 | 0 | rng(), |
197 | 0 | secure_renegotiation_data_for_client_hello(), |
198 | 0 | *session_info, |
199 | 0 | next_protocols)); |
200 | 0 |
|
201 | 0 | state.resumed_session = std::move(session_info); |
202 | 0 | } |
203 | 0 | } |
204 | 0 | } |
205 | 5.71k | } |
206 | 5.71k | |
207 | 5.71k | if(!state.client_hello()) // not resuming |
208 | 5.71k | { |
209 | 5.71k | Client_Hello::Settings client_settings(version, m_info.hostname(), srp_identifier); |
210 | 5.71k | state.client_hello(new Client_Hello( |
211 | 5.71k | state.handshake_io(), |
212 | 5.71k | state.hash(), |
213 | 5.71k | policy(), |
214 | 5.71k | callbacks(), |
215 | 5.71k | rng(), |
216 | 5.71k | secure_renegotiation_data_for_client_hello(), |
217 | 5.71k | client_settings, |
218 | 5.71k | next_protocols)); |
219 | 5.71k | } |
220 | 5.71k | |
221 | 5.71k | secure_renegotiation_check(state.client_hello()); |
222 | 5.71k | } |
223 | | |
224 | | namespace { |
225 | | |
226 | | bool key_usage_matches_ciphersuite(Key_Constraints usage, |
227 | | const Ciphersuite& suite) |
228 | 769 | { |
229 | 769 | if(usage == NO_CONSTRAINTS) |
230 | 757 | return true; // anything goes ... |
231 | 12 | |
232 | 12 | if(suite.kex_method() == Kex_Algo::STATIC_RSA) |
233 | 1 | { |
234 | 1 | return (usage & KEY_ENCIPHERMENT) | (usage & DATA_ENCIPHERMENT); |
235 | 1 | } |
236 | 11 | else |
237 | 11 | { |
238 | 11 | return (usage & DIGITAL_SIGNATURE) | (usage & NON_REPUDIATION); |
239 | 11 | } |
240 | 12 | } |
241 | | |
242 | | } |
243 | | |
244 | | /* |
245 | | * Process a handshake message |
246 | | */ |
247 | | void Client::process_handshake_msg(const Handshake_State* active_state, |
248 | | Handshake_State& state_base, |
249 | | Handshake_Type type, |
250 | | const std::vector<uint8_t>& contents, |
251 | | bool epoch0_restart) |
252 | 11.2k | { |
253 | 11.2k | BOTAN_ASSERT_NOMSG(epoch0_restart == false); // only happens on server side |
254 | 11.2k | |
255 | 11.2k | Client_Handshake_State& state = dynamic_cast<Client_Handshake_State&>(state_base); |
256 | 11.2k | |
257 | 11.2k | if(type == HELLO_REQUEST && active_state) |
258 | 0 | { |
259 | 0 | Hello_Request hello_request(contents); |
260 | 0 |
|
261 | 0 | if(state.client_hello()) |
262 | 0 | { |
263 | 0 | throw TLS_Exception(Alert::HANDSHAKE_FAILURE, "Cannot renegotiate during a handshake"); |
264 | 0 | } |
265 | 0 | |
266 | 0 | if(policy().allow_server_initiated_renegotiation()) |
267 | 0 | { |
268 | 0 | if(secure_renegotiation_supported() || policy().allow_insecure_renegotiation()) |
269 | 0 | { |
270 | 0 | state.m_is_reneg = true; |
271 | 0 | this->initiate_handshake(state, true); |
272 | 0 | } |
273 | 0 | else |
274 | 0 | { |
275 | 0 | throw TLS_Exception(Alert::HANDSHAKE_FAILURE, "Client policy prohibits insecure renegotiation"); |
276 | 0 | } |
277 | 0 | } |
278 | 0 | else |
279 | 0 | { |
280 | 0 | if(policy().abort_connection_on_undesired_renegotiation()) |
281 | 0 | { |
282 | 0 | throw TLS_Exception(Alert::NO_RENEGOTIATION, "Client policy prohibits renegotiation"); |
283 | 0 | } |
284 | 0 | else |
285 | 0 | { |
286 | 0 | // RFC 5746 section 4.2 |
287 | 0 | send_warning_alert(Alert::NO_RENEGOTIATION); |
288 | 0 | } |
289 | 0 | } |
290 | 0 |
|
291 | 0 | return; |
292 | 11.2k | } |
293 | 11.2k | |
294 | 11.2k | state.confirm_transition_to(type); |
295 | 11.2k | |
296 | 11.2k | if(type != HANDSHAKE_CCS && type != FINISHED && type != HELLO_VERIFY_REQUEST) |
297 | 10.3k | state.hash().update(state.handshake_io().format(contents, type)); |
298 | 11.2k | |
299 | 11.2k | if(type == HELLO_VERIFY_REQUEST) |
300 | 0 | { |
301 | 0 | state.set_expected_next(SERVER_HELLO); |
302 | 0 | state.set_expected_next(HELLO_VERIFY_REQUEST); // might get it again |
303 | 0 |
|
304 | 0 | Hello_Verify_Request hello_verify_request(contents); |
305 | 0 | state.hello_verify_request(hello_verify_request); |
306 | 0 | } |
307 | 11.2k | else if(type == SERVER_HELLO) |
308 | 5.12k | { |
309 | 5.12k | state.server_hello(new Server_Hello(contents)); |
310 | 5.12k | |
311 | 5.12k | if(!state.client_hello()->offered_suite(state.server_hello()->ciphersuite())) |
312 | 33 | { |
313 | 33 | throw TLS_Exception(Alert::HANDSHAKE_FAILURE, |
314 | 33 | "Server replied with ciphersuite we didn't send"); |
315 | 33 | } |
316 | 5.09k | |
317 | 5.09k | if(!Ciphersuite::by_id(state.server_hello()->ciphersuite()).usable_in_version(state.server_hello()->version())) |
318 | 1 | { |
319 | 1 | throw TLS_Exception(Alert::HANDSHAKE_FAILURE, |
320 | 1 | "Server replied using a ciphersuite not allowed in version it offered"); |
321 | 1 | } |
322 | 5.09k | |
323 | 5.09k | if(Ciphersuite::is_scsv(state.server_hello()->ciphersuite())) |
324 | 0 | { |
325 | 0 | throw TLS_Exception(Alert::HANDSHAKE_FAILURE, |
326 | 0 | "Server replied with a signaling ciphersuite"); |
327 | 0 | } |
328 | 5.09k | |
329 | 5.09k | if(state.server_hello()->compression_method() != 0) |
330 | 11 | { |
331 | 11 | throw TLS_Exception(Alert::ILLEGAL_PARAMETER, |
332 | 11 | "Server replied with non-null compression method"); |
333 | 11 | } |
334 | 5.08k | |
335 | 5.08k | if(state.client_hello()->version() > state.server_hello()->version()) |
336 | 110 | { |
337 | 110 | if(state.server_hello()->random_signals_downgrade()) |
338 | 1 | throw TLS_Exception(Alert::ILLEGAL_PARAMETER, "Downgrade attack detected"); |
339 | 5.08k | } |
340 | 5.08k | |
341 | 5.08k | auto client_extn = state.client_hello()->extension_types(); |
342 | 5.08k | auto server_extn = state.server_hello()->extension_types(); |
343 | 5.08k | |
344 | 5.08k | std::vector<Handshake_Extension_Type> diff; |
345 | 5.08k | |
346 | 5.08k | std::set_difference(server_extn.begin(), server_extn.end(), |
347 | 5.08k | client_extn.begin(), client_extn.end(), |
348 | 5.08k | std::back_inserter(diff)); |
349 | 5.08k | |
350 | 5.08k | if(!diff.empty()) |
351 | 54 | { |
352 | 54 | // Server sent us back an extension we did not send! |
353 | 54 | |
354 | 54 | std::ostringstream msg; |
355 | 54 | msg << "Server replied with unsupported extensions:"; |
356 | 54 | for(auto&& d : diff) |
357 | 755 | msg << " " << static_cast<int>(d); |
358 | 54 | throw TLS_Exception(Alert::UNSUPPORTED_EXTENSION, msg.str()); |
359 | 54 | } |
360 | 5.02k | |
361 | 5.02k | if(uint16_t srtp = state.server_hello()->srtp_profile()) |
362 | 0 | { |
363 | 0 | if(!value_exists(state.client_hello()->srtp_profiles(), srtp)) |
364 | 0 | throw TLS_Exception(Alert::HANDSHAKE_FAILURE, |
365 | 0 | "Server replied with DTLS-SRTP alg we did not send"); |
366 | 5.02k | } |
367 | 5.02k | |
368 | 5.02k | callbacks().tls_examine_extensions(state.server_hello()->extensions(), SERVER); |
369 | 5.02k | |
370 | 5.02k | state.set_version(state.server_hello()->version()); |
371 | 5.02k | m_application_protocol = state.server_hello()->next_protocol(); |
372 | 5.02k | |
373 | 5.02k | secure_renegotiation_check(state.server_hello()); |
374 | 5.02k | |
375 | 5.02k | const bool server_returned_same_session_id = |
376 | 5.02k | !state.server_hello()->session_id().empty() && |
377 | 5.02k | (state.server_hello()->session_id() == state.client_hello()->session_id()); |
378 | 5.02k | |
379 | 5.02k | if(server_returned_same_session_id) |
380 | 0 | { |
381 | 0 | // successful resumption |
382 | 0 |
|
383 | 0 | /* |
384 | 0 | * In this case, we offered the version used in the original |
385 | 0 | * session, and the server must resume with the same version. |
386 | 0 | */ |
387 | 0 | if(state.server_hello()->version() != state.client_hello()->version()) |
388 | 0 | throw TLS_Exception(Alert::HANDSHAKE_FAILURE, |
389 | 0 | "Server resumed session but with wrong version"); |
390 | 0 | |
391 | 0 | if(state.server_hello()->supports_extended_master_secret() && |
392 | 0 | !state.resumed_session->supports_extended_master_secret()) |
393 | 0 | { |
394 | 0 | throw TLS_Exception(Alert::HANDSHAKE_FAILURE, |
395 | 0 | "Server resumed session but added extended master secret"); |
396 | 0 | } |
397 | 0 | |
398 | 0 | if(!state.server_hello()->supports_extended_master_secret() && |
399 | 0 | state.resumed_session->supports_extended_master_secret()) |
400 | 0 | { |
401 | 0 | throw TLS_Exception(Alert::HANDSHAKE_FAILURE, |
402 | 0 | "Server resumed session and removed extended master secret"); |
403 | 0 | } |
404 | 0 | |
405 | 0 | state.compute_session_keys(state.resume_master_secret()); |
406 | 0 |
|
407 | 0 | if(state.server_hello()->supports_session_ticket()) |
408 | 0 | { |
409 | 0 | state.set_expected_next(NEW_SESSION_TICKET); |
410 | 0 | } |
411 | 0 | else |
412 | 0 | { |
413 | 0 | state.set_expected_next(HANDSHAKE_CCS); |
414 | 0 | } |
415 | 0 | } |
416 | 5.02k | else |
417 | 5.02k | { |
418 | 5.02k | // new session |
419 | 5.02k | |
420 | 5.02k | if(active_state) |
421 | 0 | { |
422 | 0 | // Here we are testing things that should not change during a renegotation, |
423 | 0 | // even if the server creates a new session. Howerver they might change |
424 | 0 | // in a resumption scenario. |
425 | 0 |
|
426 | 0 | if(active_state->version() != state.server_hello()->version()) |
427 | 0 | throw TLS_Exception(Alert::PROTOCOL_VERSION, |
428 | 0 | "Server changed version after renegotiation"); |
429 | 0 | |
430 | 0 | if(state.server_hello()->supports_extended_master_secret() != |
431 | 0 | active_state->server_hello()->supports_extended_master_secret()) |
432 | 0 | { |
433 | 0 | throw TLS_Exception(Alert::HANDSHAKE_FAILURE, |
434 | 0 | "Server changed its mind about extended master secret"); |
435 | 0 | } |
436 | 5.02k | } |
437 | 5.02k | |
438 | 5.02k | state.resumed_session.reset(); // non-null if we were attempting a resumption |
439 | 5.02k | |
440 | 5.02k | if(state.client_hello()->version().is_datagram_protocol() != |
441 | 5.02k | state.server_hello()->version().is_datagram_protocol()) |
442 | 0 | { |
443 | 0 | throw TLS_Exception(Alert::PROTOCOL_VERSION, |
444 | 0 | "Server replied with different protocol type than we offered"); |
445 | 0 | } |
446 | 5.02k | |
447 | 5.02k | if(state.version() > state.client_hello()->version()) |
448 | 16 | { |
449 | 16 | throw TLS_Exception(Alert::HANDSHAKE_FAILURE, |
450 | 16 | "Server replied with later version than client offered"); |
451 | 16 | } |
452 | 5.01k | |
453 | 5.01k | if(state.version().major_version() == 3 && state.version().minor_version() == 0) |
454 | 2 | { |
455 | 2 | throw TLS_Exception(Alert::PROTOCOL_VERSION, |
456 | 2 | "Server attempting to negotiate SSLv3 which is not supported"); |
457 | 2 | } |
458 | 5.00k | |
459 | 5.00k | if(!policy().acceptable_protocol_version(state.version())) |
460 | 98 | { |
461 | 98 | throw TLS_Exception(Alert::PROTOCOL_VERSION, |
462 | 98 | "Server version " + state.version().to_string() + |
463 | 98 | " is unacceptable by policy"); |
464 | 98 | } |
465 | 4.91k | |
466 | 4.91k | if(state.ciphersuite().signature_used() || state.ciphersuite().kex_method() == Kex_Algo::STATIC_RSA) |
467 | 3.21k | { |
468 | 3.21k | state.set_expected_next(CERTIFICATE); |
469 | 3.21k | } |
470 | 1.69k | else if(state.ciphersuite().kex_method() == Kex_Algo::PSK) |
471 | 681 | { |
472 | 681 | /* PSK is anonymous so no certificate/cert req message is |
473 | 681 | ever sent. The server may or may not send a server kex, |
474 | 681 | depending on if it has an identity hint for us. |
475 | 681 | |
476 | 681 | (EC)DHE_PSK always sends a server key exchange for the |
477 | 681 | DH exchange portion, and is covered by block below |
478 | 681 | */ |
479 | 681 | |
480 | 681 | state.set_expected_next(SERVER_KEX); |
481 | 681 | state.set_expected_next(SERVER_HELLO_DONE); |
482 | 681 | } |
483 | 1.01k | else if(state.ciphersuite().kex_method() != Kex_Algo::STATIC_RSA) |
484 | 362 | { |
485 | 362 | state.set_expected_next(SERVER_KEX); |
486 | 362 | } |
487 | 656 | else |
488 | 656 | { |
489 | 656 | state.set_expected_next(CERTIFICATE_REQUEST); // optional |
490 | 656 | state.set_expected_next(SERVER_HELLO_DONE); |
491 | 656 | } |
492 | 4.91k | } |
493 | 5.02k | } |
494 | 6.14k | else if(type == CERTIFICATE) |
495 | 3.18k | { |
496 | 3.18k | state.server_certs(new Certificate(contents, policy())); |
497 | 3.18k | |
498 | 3.18k | const std::vector<X509_Certificate>& server_certs = |
499 | 3.18k | state.server_certs()->cert_chain(); |
500 | 3.18k | |
501 | 3.18k | if(server_certs.empty()) |
502 | 1 | throw TLS_Exception(Alert::HANDSHAKE_FAILURE, |
503 | 1 | "Client: No certificates sent by server"); |
504 | 3.18k | |
505 | 3.18k | /* |
506 | 3.18k | If the server supports certificate status messages, |
507 | 3.18k | certificate verification happens after we receive the server hello done, |
508 | 3.18k | in case an OCSP response was also available |
509 | 3.18k | */ |
510 | 3.18k | |
511 | 3.18k | X509_Certificate server_cert = server_certs[0]; |
512 | 3.18k | |
513 | 3.18k | if(active_state && active_state->server_certs()) |
514 | 0 | { |
515 | 0 | X509_Certificate current_cert = active_state->server_certs()->cert_chain().at(0); |
516 | 0 |
|
517 | 0 | if(current_cert != server_cert) |
518 | 0 | throw TLS_Exception(Alert::BAD_CERTIFICATE, "Server certificate changed during renegotiation"); |
519 | 3.18k | } |
520 | 3.18k | |
521 | 3.18k | std::unique_ptr<Public_Key> peer_key(server_cert.subject_public_key()); |
522 | 3.18k | |
523 | 3.18k | const std::string expected_key_type = |
524 | 3.18k | state.ciphersuite().signature_used() ? state.ciphersuite().sig_algo() : "RSA"; |
525 | 3.18k | |
526 | 3.18k | if(peer_key->algo_name() != expected_key_type) |
527 | 103 | throw TLS_Exception(Alert::ILLEGAL_PARAMETER, |
528 | 103 | "Certificate key type did not match ciphersuite"); |
529 | 3.07k | |
530 | 3.07k | if(!key_usage_matches_ciphersuite(server_cert.constraints(), state.ciphersuite())) |
531 | 1 | throw TLS_Exception(Alert::BAD_CERTIFICATE, |
532 | 1 | "Certificate usage constraints do not allow this ciphersuite"); |
533 | 3.07k | |
534 | 3.07k | state.server_public_key.reset(peer_key.release()); |
535 | 3.07k | |
536 | 3.07k | if(state.ciphersuite().kex_method() != Kex_Algo::STATIC_RSA) |
537 | 698 | { |
538 | 698 | state.set_expected_next(SERVER_KEX); |
539 | 698 | } |
540 | 2.37k | else |
541 | 2.37k | { |
542 | 2.37k | state.set_expected_next(CERTIFICATE_REQUEST); // optional |
543 | 2.37k | state.set_expected_next(SERVER_HELLO_DONE); |
544 | 2.37k | } |
545 | 3.07k | |
546 | 3.07k | if(state.server_hello()->supports_certificate_status_message()) |
547 | 113 | { |
548 | 113 | state.set_expected_next(CERTIFICATE_STATUS); // optional |
549 | 113 | } |
550 | 2.96k | else |
551 | 2.96k | { |
552 | 2.96k | try |
553 | 2.96k | { |
554 | 2.96k | auto trusted_CAs = m_creds.trusted_certificate_authorities("tls-client", m_info.hostname()); |
555 | 2.96k | |
556 | 2.96k | callbacks().tls_verify_cert_chain(server_certs, |
557 | 2.96k | {}, |
558 | 2.96k | trusted_CAs, |
559 | 2.96k | Usage_Type::TLS_SERVER_AUTH, |
560 | 2.96k | m_info.hostname(), |
561 | 2.96k | policy()); |
562 | 2.96k | } |
563 | 2.96k | catch(TLS_Exception&) |
564 | 2.96k | { |
565 | 0 | throw; |
566 | 0 | } |
567 | 0 | catch(std::exception& e) |
568 | 0 | { |
569 | 0 | throw TLS_Exception(Alert::INTERNAL_ERROR, e.what()); |
570 | 0 | } |
571 | 2.96k | } |
572 | 2.96k | } |
573 | 2.96k | else if(type == CERTIFICATE_STATUS) |
574 | 18 | { |
575 | 18 | state.server_cert_status(new Certificate_Status(contents)); |
576 | 18 | |
577 | 18 | if(state.ciphersuite().kex_method() != Kex_Algo::STATIC_RSA) |
578 | 1 | { |
579 | 1 | state.set_expected_next(SERVER_KEX); |
580 | 1 | } |
581 | 17 | else |
582 | 17 | { |
583 | 17 | state.set_expected_next(CERTIFICATE_REQUEST); // optional |
584 | 17 | state.set_expected_next(SERVER_HELLO_DONE); |
585 | 17 | } |
586 | 18 | } |
587 | 2.94k | else if(type == SERVER_KEX) |
588 | 737 | { |
589 | 737 | if(state.ciphersuite().psk_ciphersuite() == false) |
590 | 706 | state.set_expected_next(CERTIFICATE_REQUEST); // optional |
591 | 737 | state.set_expected_next(SERVER_HELLO_DONE); |
592 | 737 | |
593 | 737 | state.server_kex( |
594 | 737 | new Server_Key_Exchange(contents, |
595 | 737 | state.ciphersuite().kex_method(), |
596 | 737 | state.ciphersuite().auth_method(), |
597 | 737 | state.version()) |
598 | 737 | ); |
599 | 737 | |
600 | 737 | if(state.ciphersuite().signature_used()) |
601 | 369 | { |
602 | 369 | const Public_Key& server_key = state.get_server_public_key(); |
603 | 369 | |
604 | 369 | if(!state.server_kex()->verify(server_key, state, policy())) |
605 | 0 | { |
606 | 0 | throw TLS_Exception(Alert::DECRYPT_ERROR, |
607 | 0 | "Bad signature on server key exchange"); |
608 | 0 | } |
609 | 2.20k | } |
610 | 2.20k | } |
611 | 2.20k | else if(type == CERTIFICATE_REQUEST) |
612 | 154 | { |
613 | 154 | state.set_expected_next(SERVER_HELLO_DONE); |
614 | 154 | state.cert_req(new Certificate_Req(contents, state.version())); |
615 | 154 | } |
616 | 2.05k | else if(type == SERVER_HELLO_DONE) |
617 | 1.15k | { |
618 | 1.15k | state.server_hello_done(new Server_Hello_Done(contents)); |
619 | 1.15k | |
620 | 1.15k | if(state.server_certs() != nullptr && |
621 | 1.15k | state.server_hello()->supports_certificate_status_message()) |
622 | 32 | { |
623 | 32 | try |
624 | 32 | { |
625 | 32 | auto trusted_CAs = m_creds.trusted_certificate_authorities("tls-client", m_info.hostname()); |
626 | 32 | |
627 | 32 | std::vector<std::shared_ptr<const OCSP::Response>> ocsp; |
628 | 32 | if(state.server_cert_status() != nullptr) |
629 | 0 | { |
630 | 0 | try { |
631 | 0 | ocsp.push_back(std::make_shared<OCSP::Response>(state.server_cert_status()->response())); |
632 | 0 | } |
633 | 0 | catch(Decoding_Error&) |
634 | 0 | { |
635 | 0 | // ignore it here because it might be our fault |
636 | 0 | } |
637 | 0 | } |
638 | 32 | |
639 | 32 | callbacks().tls_verify_cert_chain(state.server_certs()->cert_chain(), |
640 | 32 | ocsp, |
641 | 32 | trusted_CAs, |
642 | 32 | Usage_Type::TLS_SERVER_AUTH, |
643 | 32 | m_info.hostname(), |
644 | 32 | policy()); |
645 | 32 | } |
646 | 32 | catch(TLS_Exception&) |
647 | 32 | { |
648 | 0 | throw; |
649 | 0 | } |
650 | 0 | catch(std::exception& e) |
651 | 0 | { |
652 | 0 | throw TLS_Exception(Alert::INTERNAL_ERROR, e.what()); |
653 | 0 | } |
654 | 1.15k | } |
655 | 1.15k | |
656 | 1.15k | if(state.received_handshake_msg(CERTIFICATE_REQUEST)) |
657 | 7 | { |
658 | 7 | const auto& types = state.cert_req()->acceptable_cert_types(); |
659 | 7 | |
660 | 7 | std::vector<X509_Certificate> client_certs = |
661 | 7 | m_creds.find_cert_chain(types, |
662 | 7 | state.cert_req()->acceptable_CAs(), |
663 | 7 | "tls-client", |
664 | 7 | m_info.hostname()); |
665 | 7 | |
666 | 7 | state.client_certs(new Certificate(state.handshake_io(), |
667 | 7 | state.hash(), |
668 | 7 | client_certs)); |
669 | 7 | } |
670 | 1.15k | |
671 | 1.15k | state.client_kex( |
672 | 1.15k | new Client_Key_Exchange(state.handshake_io(), |
673 | 1.15k | state, |
674 | 1.15k | policy(), |
675 | 1.15k | m_creds, |
676 | 1.15k | state.server_public_key.get(), |
677 | 1.15k | m_info.hostname(), |
678 | 1.15k | rng()) |
679 | 1.15k | ); |
680 | 1.15k | |
681 | 1.15k | state.compute_session_keys(); |
682 | 1.15k | |
683 | 1.15k | if(state.received_handshake_msg(CERTIFICATE_REQUEST) && |
684 | 1.15k | !state.client_certs()->empty()) |
685 | 0 | { |
686 | 0 | Private_Key* private_key = |
687 | 0 | m_creds.private_key_for(state.client_certs()->cert_chain()[0], |
688 | 0 | "tls-client", |
689 | 0 | m_info.hostname()); |
690 | 0 |
|
691 | 0 | state.client_verify( |
692 | 0 | new Certificate_Verify(state.handshake_io(), |
693 | 0 | state, |
694 | 0 | policy(), |
695 | 0 | rng(), |
696 | 0 | private_key) |
697 | 0 | ); |
698 | 0 | } |
699 | 1.15k | |
700 | 1.15k | state.handshake_io().send(Change_Cipher_Spec()); |
701 | 1.15k | |
702 | 1.15k | change_cipher_spec_writer(CLIENT); |
703 | 1.15k | |
704 | 1.15k | state.client_finished(new Finished(state.handshake_io(), state, CLIENT)); |
705 | 1.15k | |
706 | 1.15k | if(state.server_hello()->supports_session_ticket()) |
707 | 54 | state.set_expected_next(NEW_SESSION_TICKET); |
708 | 1.09k | else |
709 | 1.09k | state.set_expected_next(HANDSHAKE_CCS); |
710 | 1.15k | } |
711 | 901 | else if(type == NEW_SESSION_TICKET) |
712 | 6 | { |
713 | 6 | state.new_session_ticket(new New_Session_Ticket(contents)); |
714 | 6 | |
715 | 6 | state.set_expected_next(HANDSHAKE_CCS); |
716 | 6 | } |
717 | 895 | else if(type == HANDSHAKE_CCS) |
718 | 655 | { |
719 | 655 | state.set_expected_next(FINISHED); |
720 | 655 | |
721 | 655 | change_cipher_spec_reader(CLIENT); |
722 | 655 | } |
723 | 240 | else if(type == FINISHED) |
724 | 100 | { |
725 | 100 | state.server_finished(new Finished(contents)); |
726 | 100 | |
727 | 100 | if(!state.server_finished()->verify(state, SERVER)) |
728 | 0 | throw TLS_Exception(Alert::DECRYPT_ERROR, |
729 | 0 | "Finished message didn't verify"); |
730 | 100 | |
731 | 100 | state.hash().update(state.handshake_io().format(contents, type)); |
732 | 100 | |
733 | 100 | if(!state.client_finished()) // session resume case |
734 | 0 | { |
735 | 0 | state.handshake_io().send(Change_Cipher_Spec()); |
736 | 0 | change_cipher_spec_writer(CLIENT); |
737 | 0 | state.client_finished(new Finished(state.handshake_io(), state, CLIENT)); |
738 | 0 | } |
739 | 100 | |
740 | 100 | std::vector<uint8_t> session_id = state.server_hello()->session_id(); |
741 | 100 | |
742 | 100 | const std::vector<uint8_t>& session_ticket = state.session_ticket(); |
743 | 100 | |
744 | 100 | if(session_id.empty() && !session_ticket.empty()) |
745 | 0 | session_id = make_hello_random(rng(), policy()); |
746 | 100 | |
747 | 100 | Session session_info( |
748 | 100 | session_id, |
749 | 100 | state.session_keys().master_secret(), |
750 | 100 | state.server_hello()->version(), |
751 | 100 | state.server_hello()->ciphersuite(), |
752 | 100 | CLIENT, |
753 | 100 | state.server_hello()->supports_extended_master_secret(), |
754 | 100 | state.server_hello()->supports_encrypt_then_mac(), |
755 | 100 | get_peer_cert_chain(state), |
756 | 100 | session_ticket, |
757 | 100 | m_info, |
758 | 100 | "", |
759 | 100 | state.server_hello()->srtp_profile() |
760 | 100 | ); |
761 | 100 | |
762 | 100 | const bool should_save = save_session(session_info); |
763 | 100 | |
764 | 100 | if(session_id.size() > 0 && state.is_a_resumption() == false) |
765 | 44 | { |
766 | 44 | if(should_save) |
767 | 44 | session_manager().save(session_info); |
768 | 0 | else |
769 | 0 | session_manager().remove_entry(session_info.session_id()); |
770 | 44 | } |
771 | 100 | |
772 | 100 | activate_session(); |
773 | 100 | } |
774 | 140 | else |
775 | 140 | throw Unexpected_Message("Unknown handshake message received"); |
776 | 11.2k | } |
777 | | |
778 | | } |
779 | | |
780 | | } |