/src/botan/src/lib/tls/tls_server.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * TLS Server |
3 | | * (C) 2004-2011,2012,2016 Jack Lloyd |
4 | | * 2016 Matthias Gierlings |
5 | | * |
6 | | * Botan is released under the Simplified BSD License (see license.txt) |
7 | | */ |
8 | | |
9 | | #include <botan/tls_server.h> |
10 | | #include <botan/tls_messages.h> |
11 | | #include <botan/internal/tls_handshake_state.h> |
12 | | #include <botan/internal/stl_util.h> |
13 | | #include <botan/tls_magic.h> |
14 | | |
15 | | namespace Botan { |
16 | | |
17 | | namespace TLS { |
18 | | |
19 | | class Server_Handshake_State final : public Handshake_State |
20 | | { |
21 | | public: |
22 | | Server_Handshake_State(std::unique_ptr<Handshake_IO> io, Callbacks& cb) |
23 | 30.9k | : Handshake_State(std::move(io), cb) {} |
24 | | |
25 | 10.9k | Private_Key* server_rsa_kex_key() { return m_server_rsa_kex_key; } |
26 | | void set_server_rsa_kex_key(Private_Key* key) |
27 | 0 | { m_server_rsa_kex_key = key; } |
28 | | |
29 | | bool allow_session_resumption() const |
30 | 22.6k | { return m_allow_session_resumption; } |
31 | | void set_allow_session_resumption(bool allow_session_resumption) |
32 | 0 | { m_allow_session_resumption = allow_session_resumption; } |
33 | | |
34 | | const std::vector<X509_Certificate>& resume_peer_certs() const |
35 | 553 | { return m_resume_peer_certs; } |
36 | | |
37 | | void set_resume_certs(const std::vector<X509_Certificate>& certs) |
38 | 0 | { m_resume_peer_certs = certs; } |
39 | | |
40 | 0 | void mark_as_resumption() { m_is_a_resumption = true; } |
41 | | |
42 | 10 | bool is_a_resumption() const { return m_is_a_resumption; } |
43 | | |
44 | | private: |
45 | | // Used by the server only, in case of RSA key exchange. Not owned |
46 | | Private_Key* m_server_rsa_kex_key = nullptr; |
47 | | |
48 | | /* |
49 | | * Used by the server to know if resumption should be allowed on |
50 | | * a server-initiated renegotiation |
51 | | */ |
52 | | bool m_allow_session_resumption = true; |
53 | | |
54 | | bool m_is_a_resumption = false; |
55 | | |
56 | | std::vector<X509_Certificate> m_resume_peer_certs; |
57 | | }; |
58 | | |
59 | | namespace { |
60 | | |
61 | | bool check_for_resume(Session& session_info, |
62 | | Session_Manager& session_manager, |
63 | | Credentials_Manager& credentials, |
64 | | const Client_Hello* client_hello, |
65 | | std::chrono::seconds session_ticket_lifetime) |
66 | 22.6k | { |
67 | 22.6k | const std::vector<uint8_t>& client_session_id = client_hello->session_id(); |
68 | 22.6k | const std::vector<uint8_t>& session_ticket = client_hello->session_ticket(); |
69 | | |
70 | 22.6k | if(session_ticket.empty()) |
71 | 19.9k | { |
72 | 19.9k | if(client_session_id.empty()) // not resuming |
73 | 19.7k | return false; |
74 | | |
75 | | // not found |
76 | 162 | if(!session_manager.load_from_session_id(client_session_id, session_info)) |
77 | 162 | return false; |
78 | 2.74k | } |
79 | 2.74k | else |
80 | 2.74k | { |
81 | | // If a session ticket was sent, ignore client session ID |
82 | 2.74k | try |
83 | 2.74k | { |
84 | 2.74k | session_info = Session::decrypt( |
85 | 2.74k | session_ticket, |
86 | 2.74k | credentials.psk("tls-server", "session-ticket", "")); |
87 | | |
88 | 2.74k | if(session_ticket_lifetime != std::chrono::seconds(0) && |
89 | 0 | session_info.session_age() > session_ticket_lifetime) |
90 | 0 | return false; // ticket has expired |
91 | 2.74k | } |
92 | 2.74k | catch(...) |
93 | 2.74k | { |
94 | 2.74k | return false; |
95 | 2.74k | } |
96 | 0 | } |
97 | | |
98 | | // wrong version |
99 | 0 | if(client_hello->version() != session_info.version()) |
100 | 0 | return false; |
101 | | |
102 | | // client didn't send original ciphersuite |
103 | 0 | if(!value_exists(client_hello->ciphersuites(), |
104 | 0 | session_info.ciphersuite_code())) |
105 | 0 | return false; |
106 | | |
107 | | // client sent a different SNI hostname |
108 | 0 | if(client_hello->sni_hostname() != "") |
109 | 0 | { |
110 | 0 | if(client_hello->sni_hostname() != session_info.server_info().hostname()) |
111 | 0 | return false; |
112 | 0 | } |
113 | | |
114 | | // Checking extended_master_secret on resume (RFC 7627 section 5.3) |
115 | 0 | if(client_hello->supports_extended_master_secret() != session_info.supports_extended_master_secret()) |
116 | 0 | { |
117 | 0 | if(!session_info.supports_extended_master_secret()) |
118 | 0 | { |
119 | 0 | return false; // force new handshake with extended master secret |
120 | 0 | } |
121 | 0 | else |
122 | 0 | { |
123 | | /* |
124 | | Client previously negotiated session with extended master secret, |
125 | | but has now attempted to resume without the extension: abort |
126 | | */ |
127 | 0 | throw TLS_Exception(Alert::HANDSHAKE_FAILURE, |
128 | 0 | "Client resumed extended ms session without sending extension"); |
129 | 0 | } |
130 | 0 | } |
131 | | |
132 | | // Checking encrypt_then_mac on resume (RFC 7366 section 3.1) |
133 | 0 | if(!client_hello->supports_encrypt_then_mac() && session_info.supports_encrypt_then_mac()) |
134 | 0 | { |
135 | | /* |
136 | | Client previously negotiated session with Encrypt-then-MAC, |
137 | | but has now attempted to resume without the extension: abort |
138 | | */ |
139 | 0 | throw TLS_Exception(Alert::HANDSHAKE_FAILURE, |
140 | 0 | "Client resumed Encrypt-then-MAC session without sending extension"); |
141 | 0 | } |
142 | | |
143 | 0 | return true; |
144 | 0 | } |
145 | | |
146 | | /* |
147 | | * Choose which ciphersuite to use |
148 | | */ |
149 | | uint16_t choose_ciphersuite( |
150 | | const Policy& policy, |
151 | | Protocol_Version version, |
152 | | const std::map<std::string, std::vector<X509_Certificate>>& cert_chains, |
153 | | const Client_Hello& client_hello) |
154 | 22.6k | { |
155 | 22.6k | const bool our_choice = policy.server_uses_own_ciphersuite_preferences(); |
156 | 22.6k | const std::vector<uint16_t> client_suites = client_hello.ciphersuites(); |
157 | 22.6k | const std::vector<uint16_t> server_suites = policy.ciphersuite_list(version); |
158 | | |
159 | 22.6k | if(server_suites.empty()) |
160 | 0 | throw TLS_Exception(Alert::HANDSHAKE_FAILURE, |
161 | 0 | "Policy forbids us from negotiating any ciphersuite"); |
162 | | |
163 | 22.6k | const bool have_shared_ecc_curve = |
164 | 22.6k | (policy.choose_key_exchange_group(client_hello.supported_ecc_curves()) != Group_Params::NONE); |
165 | | |
166 | | /* |
167 | | Walk down one list in preference order |
168 | | */ |
169 | 22.6k | std::vector<uint16_t> pref_list = server_suites; |
170 | 22.6k | std::vector<uint16_t> other_list = client_suites; |
171 | | |
172 | 22.6k | if(!our_choice) |
173 | 0 | std::swap(pref_list, other_list); |
174 | | |
175 | 22.6k | for(auto suite_id : pref_list) |
176 | 1.28M | { |
177 | 1.28M | if(!value_exists(other_list, suite_id)) |
178 | 1.26M | continue; |
179 | | |
180 | 22.4k | const Ciphersuite suite = Ciphersuite::by_id(suite_id); |
181 | | |
182 | 22.4k | if(suite.valid() == false) |
183 | 0 | { |
184 | 0 | continue; |
185 | 0 | } |
186 | | |
187 | 22.4k | if(have_shared_ecc_curve == false && suite.ecc_ciphersuite()) |
188 | 74 | { |
189 | 74 | continue; |
190 | 74 | } |
191 | | |
192 | | // For non-anon ciphersuites |
193 | 22.4k | if(suite.signature_used()) |
194 | 123 | { |
195 | 123 | const std::string sig_algo = suite.sig_algo(); |
196 | | |
197 | | // Do we have any certificates for this sig? |
198 | 123 | if(cert_chains.count(sig_algo) == 0) |
199 | 1 | { |
200 | 1 | continue; |
201 | 1 | } |
202 | | |
203 | 122 | const std::vector<Signature_Scheme> allowed = |
204 | 122 | policy.allowed_signature_schemes(); |
205 | | |
206 | 122 | std::vector<Signature_Scheme> client_sig_methods = |
207 | 122 | client_hello.signature_schemes(); |
208 | | |
209 | | /* |
210 | | Contrary to the wording of draft-ietf-tls-md5-sha1-deprecate we do |
211 | | not enforce that clients do not offer support SHA-1 or MD5 |
212 | | signatures; we just ignore it. |
213 | | */ |
214 | 122 | bool we_support_some_hash_by_client = false; |
215 | | |
216 | 122 | for(Signature_Scheme scheme : client_sig_methods) |
217 | 3.31k | { |
218 | 3.31k | if(signature_scheme_is_known(scheme) == false) |
219 | 2.88k | continue; |
220 | | |
221 | 429 | if(signature_algorithm_of_scheme(scheme) == suite.sig_algo() && |
222 | 258 | policy.allowed_signature_hash(hash_function_of_scheme(scheme))) |
223 | 258 | { |
224 | 258 | we_support_some_hash_by_client = true; |
225 | 258 | } |
226 | 429 | } |
227 | | |
228 | 122 | if(we_support_some_hash_by_client == false) |
229 | 64 | { |
230 | 64 | throw TLS_Exception(Alert::HANDSHAKE_FAILURE, |
231 | 64 | "Policy does not accept any hash function supported by client"); |
232 | 64 | } |
233 | 22.3k | } |
234 | | |
235 | 22.3k | return suite_id; |
236 | 22.3k | } |
237 | | |
238 | 240 | throw TLS_Exception(Alert::HANDSHAKE_FAILURE, |
239 | 240 | "Can't agree on a ciphersuite with client"); |
240 | 22.6k | } |
241 | | |
242 | | std::map<std::string, std::vector<X509_Certificate>> |
243 | | get_server_certs(const std::string& hostname, |
244 | | Credentials_Manager& creds) |
245 | 22.6k | { |
246 | 22.6k | const char* cert_types[] = { "RSA", "ECDSA", "DSA", nullptr }; |
247 | | |
248 | 22.6k | std::map<std::string, std::vector<X509_Certificate>> cert_chains; |
249 | | |
250 | 90.6k | for(size_t i = 0; cert_types[i]; ++i) |
251 | 67.9k | { |
252 | 67.9k | const std::vector<X509_Certificate> certs = |
253 | 67.9k | creds.cert_chain_single_type(cert_types[i], "tls-server", hostname); |
254 | | |
255 | 67.9k | if(!certs.empty()) |
256 | 22.6k | cert_chains[cert_types[i]] = certs; |
257 | 67.9k | } |
258 | | |
259 | 22.6k | return cert_chains; |
260 | 22.6k | } |
261 | | |
262 | | } |
263 | | |
264 | | /* |
265 | | * TLS Server Constructor |
266 | | */ |
267 | | Server::Server(Callbacks& callbacks, |
268 | | Session_Manager& session_manager, |
269 | | Credentials_Manager& creds, |
270 | | const Policy& policy, |
271 | | RandomNumberGenerator& rng, |
272 | | bool is_datagram, |
273 | | size_t io_buf_sz) : |
274 | | Channel(callbacks, session_manager, rng, policy, |
275 | | true, is_datagram, io_buf_sz), |
276 | | m_creds(creds) |
277 | 5.52k | { |
278 | 5.52k | } |
279 | | |
280 | | std::unique_ptr<Handshake_State> Server::new_handshake_state(std::unique_ptr<Handshake_IO> io) |
281 | 30.9k | { |
282 | 30.9k | std::unique_ptr<Handshake_State> state(new Server_Handshake_State(std::move(io), callbacks())); |
283 | 30.9k | state->set_expected_next(CLIENT_HELLO); |
284 | 30.9k | return state; |
285 | 30.9k | } |
286 | | |
287 | | std::vector<X509_Certificate> |
288 | | Server::get_peer_cert_chain(const Handshake_State& state_base) const |
289 | 553 | { |
290 | 553 | const Server_Handshake_State& state = dynamic_cast<const Server_Handshake_State&>(state_base); |
291 | 553 | if(state.resume_peer_certs().size() > 0) |
292 | 0 | return state.resume_peer_certs(); |
293 | | |
294 | 553 | if(state.client_certs()) |
295 | 0 | return state.client_certs()->cert_chain(); |
296 | 553 | return std::vector<X509_Certificate>(); |
297 | 553 | } |
298 | | |
299 | | /* |
300 | | * Send a hello request to the client |
301 | | */ |
302 | | void Server::initiate_handshake(Handshake_State& state, |
303 | | bool force_full_renegotiation) |
304 | 0 | { |
305 | 0 | dynamic_cast<Server_Handshake_State&>(state). |
306 | 0 | set_allow_session_resumption(!force_full_renegotiation); |
307 | |
|
308 | 0 | Hello_Request hello_req(state.handshake_io()); |
309 | 0 | } |
310 | | |
311 | | namespace { |
312 | | |
313 | | Protocol_Version select_version(const Botan::TLS::Policy& policy, |
314 | | Protocol_Version client_offer, |
315 | | Protocol_Version active_version, |
316 | | const std::vector<Protocol_Version>& supported_versions) |
317 | 33.4k | { |
318 | 33.4k | const bool is_datagram = client_offer.is_datagram_protocol(); |
319 | 33.4k | const bool initial_handshake = (active_version.valid() == false); |
320 | | |
321 | 33.4k | const Protocol_Version latest_supported = policy.latest_supported_version(is_datagram); |
322 | | |
323 | 33.4k | if(supported_versions.size() > 0) |
324 | 1.03k | { |
325 | 1.03k | if(is_datagram) |
326 | 1.03k | { |
327 | 1.03k | if(policy.allow_dtls12() && value_exists(supported_versions, Protocol_Version(Protocol_Version::DTLS_V12))) |
328 | 1.02k | return Protocol_Version::DTLS_V12; |
329 | 6 | throw TLS_Exception(Alert::PROTOCOL_VERSION, "No shared DTLS version"); |
330 | 6 | } |
331 | 6 | else |
332 | 6 | { |
333 | 6 | if(policy.allow_tls12() && value_exists(supported_versions, Protocol_Version(Protocol_Version::TLS_V12))) |
334 | 3 | return Protocol_Version::TLS_V12; |
335 | 3 | throw TLS_Exception(Alert::PROTOCOL_VERSION, "No shared TLS version"); |
336 | 3 | } |
337 | 1.03k | } |
338 | | |
339 | 32.3k | const bool client_offer_acceptable = |
340 | 32.3k | client_offer.known_version() && policy.acceptable_protocol_version(client_offer); |
341 | | |
342 | 32.3k | if(!initial_handshake) |
343 | 0 | { |
344 | | /* |
345 | | * If this is a renegotiation, and the client has offered a |
346 | | * later version than what it initially negotiated, negotiate |
347 | | * the old version. This matches OpenSSL's behavior. If the |
348 | | * client is offering a version earlier than what it initially |
349 | | * negotiated, reject as a probable attack. |
350 | | */ |
351 | 0 | if(active_version > client_offer) |
352 | 0 | { |
353 | 0 | throw TLS_Exception(Alert::PROTOCOL_VERSION, |
354 | 0 | "Client negotiated " + |
355 | 0 | active_version.to_string() + |
356 | 0 | " then renegotiated with " + |
357 | 0 | client_offer.to_string()); |
358 | 0 | } |
359 | 0 | else |
360 | 0 | { |
361 | 0 | return active_version; |
362 | 0 | } |
363 | 32.3k | } |
364 | 32.3k | else if(client_offer_acceptable) |
365 | 8.58k | { |
366 | 8.58k | return client_offer; |
367 | 8.58k | } |
368 | 23.7k | else if(!client_offer.known_version() || client_offer > latest_supported) |
369 | 23.7k | { |
370 | | /* |
371 | | The client offered some version newer than the latest we |
372 | | support. Offer them the best we know. |
373 | | */ |
374 | 23.7k | return latest_supported; |
375 | 23.7k | } |
376 | 0 | else |
377 | 0 | { |
378 | 0 | throw TLS_Exception(Alert::PROTOCOL_VERSION, |
379 | 0 | "Client version " + client_offer.to_string() + |
380 | 0 | " is unacceptable by policy"); |
381 | 0 | } |
382 | 32.3k | } |
383 | | |
384 | | } |
385 | | |
386 | | /* |
387 | | * Process a CLIENT HELLO Message |
388 | | */ |
389 | | void Server::process_client_hello_msg(const Handshake_State* active_state, |
390 | | Server_Handshake_State& pending_state, |
391 | | const std::vector<uint8_t>& contents, |
392 | | bool epoch0_restart) |
393 | 34.1k | { |
394 | 34.1k | BOTAN_ASSERT_IMPLICATION(epoch0_restart, active_state != nullptr, "Can't restart with a dead connection"); |
395 | | |
396 | 34.1k | const bool initial_handshake = epoch0_restart || !active_state; |
397 | | |
398 | 34.1k | if(initial_handshake == false && policy().allow_client_initiated_renegotiation() == false) |
399 | 0 | { |
400 | 0 | if(policy().abort_connection_on_undesired_renegotiation()) |
401 | 0 | throw TLS_Exception(Alert::NO_RENEGOTIATION, "Server policy prohibits renegotiation"); |
402 | 0 | else |
403 | 0 | send_warning_alert(Alert::NO_RENEGOTIATION); |
404 | 0 | return; |
405 | 34.1k | } |
406 | | |
407 | 34.1k | if(!policy().allow_insecure_renegotiation() && |
408 | 34.1k | !(initial_handshake || secure_renegotiation_supported())) |
409 | 0 | { |
410 | 0 | send_warning_alert(Alert::NO_RENEGOTIATION); |
411 | 0 | return; |
412 | 0 | } |
413 | | |
414 | 34.1k | if(pending_state.handshake_io().have_more_data()) |
415 | 48 | throw TLS_Exception(Alert::UNEXPECTED_MESSAGE, |
416 | 48 | "Have data remaining in buffer after ClientHello"); |
417 | | |
418 | 34.0k | pending_state.client_hello(new Client_Hello(contents)); |
419 | 34.0k | const Protocol_Version client_offer = pending_state.client_hello()->version(); |
420 | 34.0k | const bool datagram = client_offer.is_datagram_protocol(); |
421 | | |
422 | 34.0k | if(datagram) |
423 | 10.7k | { |
424 | 10.7k | if(client_offer.major_version() == 0xFF) |
425 | 1 | throw TLS_Exception(Alert::PROTOCOL_VERSION, "Client offered DTLS version with major version 0xFF"); |
426 | 23.3k | } |
427 | 23.3k | else |
428 | 23.3k | { |
429 | 23.3k | if(client_offer.major_version() < 3) |
430 | 4 | throw TLS_Exception(Alert::PROTOCOL_VERSION, "Client offered TLS version with major version under 3"); |
431 | 23.3k | if(client_offer.major_version() == 3 && client_offer.minor_version() == 0) |
432 | 1 | throw TLS_Exception(Alert::PROTOCOL_VERSION, "Client offered SSLv3 which is not supported"); |
433 | 34.0k | } |
434 | | |
435 | | /* |
436 | | * BoGo test suite expects that we will send the hello verify with a record |
437 | | * version matching the version that is eventually negotiated. This is wrong |
438 | | * but harmless, so go with it. Also doing the version negotiation step first |
439 | | * allows to immediately close the connection with an alert if the client has |
440 | | * offered a version that we are not going to negotiate anyway, instead of |
441 | | * making them first do the cookie exchange and then telling them no. |
442 | | * |
443 | | * There is no issue with amplification here, since the alert is just 2 bytes. |
444 | | */ |
445 | 34.0k | const Protocol_Version negotiated_version = |
446 | 34.0k | select_version(policy(), client_offer, |
447 | 34.0k | active_state ? active_state->version() : Protocol_Version(), |
448 | 34.0k | pending_state.client_hello()->supported_versions()); |
449 | | |
450 | 34.0k | pending_state.set_version(negotiated_version); |
451 | | |
452 | 34.0k | const auto compression_methods = pending_state.client_hello()->compression_methods(); |
453 | 34.0k | if(!value_exists(compression_methods, uint8_t(0))) |
454 | 58 | throw TLS_Exception(Alert::ILLEGAL_PARAMETER, "Client did not offer NULL compression"); |
455 | | |
456 | 34.0k | if(initial_handshake && datagram) |
457 | 10.6k | { |
458 | 10.6k | SymmetricKey cookie_secret; |
459 | | |
460 | 10.6k | try |
461 | 10.6k | { |
462 | 10.6k | cookie_secret = m_creds.psk("tls-server", "dtls-cookie-secret", ""); |
463 | 10.6k | } |
464 | 0 | catch(...) {} |
465 | | |
466 | 10.6k | if(cookie_secret.size() > 0) |
467 | 10.6k | { |
468 | 10.6k | const std::string client_identity = callbacks().tls_peer_network_identity(); |
469 | 10.6k | Hello_Verify_Request verify(pending_state.client_hello()->cookie_input_data(), client_identity, cookie_secret); |
470 | | |
471 | 10.6k | if(pending_state.client_hello()->cookie() != verify.cookie()) |
472 | 10.6k | { |
473 | 10.6k | if(epoch0_restart) |
474 | 0 | pending_state.handshake_io().send_under_epoch(verify, 0); |
475 | 10.6k | else |
476 | 10.6k | pending_state.handshake_io().send(verify); |
477 | | |
478 | 10.6k | pending_state.client_hello(nullptr); |
479 | 10.6k | pending_state.set_expected_next(CLIENT_HELLO); |
480 | 10.6k | return; |
481 | 10.6k | } |
482 | 0 | } |
483 | 0 | else if(epoch0_restart) |
484 | 0 | { |
485 | 0 | throw TLS_Exception(Alert::HANDSHAKE_FAILURE, "Reuse of DTLS association requires DTLS cookie secret be set"); |
486 | 0 | } |
487 | 23.3k | } |
488 | | |
489 | 23.3k | if(epoch0_restart) |
490 | 0 | { |
491 | | // If we reached here then we were able to verify the cookie |
492 | 0 | reset_active_association_state(); |
493 | 0 | } |
494 | | |
495 | 23.3k | secure_renegotiation_check(pending_state.client_hello()); |
496 | | |
497 | 23.3k | callbacks().tls_examine_extensions(pending_state.client_hello()->extensions(), CLIENT); |
498 | | |
499 | 23.3k | Session session_info; |
500 | 23.3k | const bool resuming = |
501 | 23.3k | pending_state.allow_session_resumption() && |
502 | 22.6k | check_for_resume(session_info, |
503 | 22.6k | session_manager(), |
504 | 22.6k | m_creds, |
505 | 22.6k | pending_state.client_hello(), |
506 | 22.6k | std::chrono::seconds(policy().session_ticket_lifetime())); |
507 | | |
508 | 23.3k | bool have_session_ticket_key = false; |
509 | | |
510 | 23.3k | try |
511 | 23.3k | { |
512 | 23.3k | have_session_ticket_key = |
513 | 23.3k | m_creds.psk("tls-server", "session-ticket", "").length() > 0; |
514 | 23.3k | } |
515 | 0 | catch(...) {} |
516 | | |
517 | 22.6k | m_next_protocol = ""; |
518 | 22.6k | if(pending_state.client_hello()->supports_alpn()) |
519 | 11.2k | { |
520 | 11.2k | m_next_protocol = callbacks().tls_server_choose_app_protocol(pending_state.client_hello()->next_protocols()); |
521 | | |
522 | | // if the callback return was empty, fall back to the (deprecated) std::function |
523 | 11.2k | if(m_next_protocol.empty() && m_choose_next_protocol) |
524 | 0 | { |
525 | 0 | m_next_protocol = m_choose_next_protocol(pending_state.client_hello()->next_protocols()); |
526 | 0 | } |
527 | 11.2k | } |
528 | | |
529 | 22.6k | if(resuming) |
530 | 0 | { |
531 | 0 | this->session_resume(pending_state, have_session_ticket_key, session_info); |
532 | 0 | } |
533 | 22.6k | else // new session |
534 | 22.6k | { |
535 | 22.6k | this->session_create(pending_state, have_session_ticket_key); |
536 | 22.6k | } |
537 | 22.6k | } |
538 | | |
539 | | void Server::process_certificate_msg(Server_Handshake_State& pending_state, |
540 | | const std::vector<uint8_t>& contents) |
541 | 0 | { |
542 | 0 | pending_state.client_certs(new Certificate(contents, policy())); |
543 | | |
544 | | // CERTIFICATE_REQUIRED would make more sense but BoGo expects handshake failure alert |
545 | 0 | if(pending_state.client_certs()->empty() && policy().require_client_certificate_authentication()) |
546 | 0 | throw TLS_Exception(Alert::HANDSHAKE_FAILURE, "Policy requires client send a certificate, but it did not"); |
547 | | |
548 | 0 | pending_state.set_expected_next(CLIENT_KEX); |
549 | 0 | } |
550 | | |
551 | | void Server::process_client_key_exchange_msg(Server_Handshake_State& pending_state, |
552 | | const std::vector<uint8_t>& contents) |
553 | 10.9k | { |
554 | 10.9k | if(pending_state.received_handshake_msg(CERTIFICATE) && !pending_state.client_certs()->empty()) |
555 | 0 | pending_state.set_expected_next(CERTIFICATE_VERIFY); |
556 | 10.9k | else |
557 | 10.9k | pending_state.set_expected_next(HANDSHAKE_CCS); |
558 | | |
559 | 10.9k | pending_state.client_kex(new Client_Key_Exchange(contents, pending_state, |
560 | 10.9k | pending_state.server_rsa_kex_key(), |
561 | 10.9k | m_creds, policy(), rng())); |
562 | | |
563 | 10.9k | pending_state.compute_session_keys(); |
564 | 10.9k | } |
565 | | |
566 | | void Server::process_change_cipher_spec_msg(Server_Handshake_State& pending_state) |
567 | 794 | { |
568 | 794 | pending_state.set_expected_next(FINISHED); |
569 | 794 | change_cipher_spec_reader(SERVER); |
570 | 794 | } |
571 | | |
572 | | void Server::process_certificate_verify_msg(Server_Handshake_State& pending_state, |
573 | | Handshake_Type type, |
574 | | const std::vector<uint8_t>& contents) |
575 | 0 | { |
576 | 0 | pending_state.client_verify(new Certificate_Verify(contents)); |
577 | |
|
578 | 0 | const std::vector<X509_Certificate>& client_certs = |
579 | 0 | pending_state.client_certs()->cert_chain(); |
580 | |
|
581 | 0 | if(client_certs.empty()) |
582 | 0 | throw TLS_Exception(Alert::DECODE_ERROR, "No client certificate sent"); |
583 | | |
584 | 0 | if(!client_certs[0].allowed_usage(DIGITAL_SIGNATURE)) |
585 | 0 | throw TLS_Exception(Alert::BAD_CERTIFICATE, "Client certificate does not support signing"); |
586 | | |
587 | 0 | const bool sig_valid = |
588 | 0 | pending_state.client_verify()->verify(client_certs[0], pending_state, policy()); |
589 | |
|
590 | 0 | pending_state.hash().update(pending_state.handshake_io().format(contents, type)); |
591 | | |
592 | | /* |
593 | | * Using DECRYPT_ERROR looks weird here, but per RFC 4346 is for |
594 | | * "A handshake cryptographic operation failed, including being |
595 | | * unable to correctly verify a signature, ..." |
596 | | */ |
597 | 0 | if(!sig_valid) |
598 | 0 | throw TLS_Exception(Alert::DECRYPT_ERROR, "Client cert verify failed"); |
599 | | |
600 | 0 | try |
601 | 0 | { |
602 | 0 | const std::string sni_hostname = pending_state.client_hello()->sni_hostname(); |
603 | 0 | auto trusted_CAs = m_creds.trusted_certificate_authorities("tls-server", sni_hostname); |
604 | |
|
605 | 0 | callbacks().tls_verify_cert_chain(client_certs, |
606 | 0 | {}, // ocsp |
607 | 0 | trusted_CAs, |
608 | 0 | Usage_Type::TLS_CLIENT_AUTH, |
609 | 0 | sni_hostname, |
610 | 0 | policy()); |
611 | 0 | } |
612 | 0 | catch(std::exception& e) |
613 | 0 | { |
614 | 0 | throw TLS_Exception(Alert::BAD_CERTIFICATE, e.what()); |
615 | 0 | } |
616 | | |
617 | 0 | pending_state.set_expected_next(HANDSHAKE_CCS); |
618 | 0 | } |
619 | | |
620 | | void Server::process_finished_msg(Server_Handshake_State& pending_state, |
621 | | Handshake_Type type, |
622 | | const std::vector<uint8_t>& contents) |
623 | 558 | { |
624 | 558 | pending_state.set_expected_next(HANDSHAKE_NONE); |
625 | | |
626 | 558 | if(pending_state.handshake_io().have_more_data()) |
627 | 5 | throw TLS_Exception(Alert::UNEXPECTED_MESSAGE, |
628 | 5 | "Have data remaining in buffer after Finished"); |
629 | | |
630 | 553 | pending_state.client_finished(new Finished(contents)); |
631 | | |
632 | 553 | if(!pending_state.client_finished()->verify(pending_state, CLIENT)) |
633 | 0 | throw TLS_Exception(Alert::DECRYPT_ERROR, |
634 | 0 | "Finished message didn't verify"); |
635 | | |
636 | 553 | if(!pending_state.server_finished()) |
637 | 553 | { |
638 | | // already sent finished if resuming, so this is a new session |
639 | | |
640 | 553 | pending_state.hash().update(pending_state.handshake_io().format(contents, type)); |
641 | | |
642 | 553 | Session session_info( |
643 | 553 | pending_state.server_hello()->session_id(), |
644 | 553 | pending_state.session_keys().master_secret(), |
645 | 553 | pending_state.server_hello()->version(), |
646 | 553 | pending_state.server_hello()->ciphersuite(), |
647 | 553 | SERVER, |
648 | 553 | pending_state.server_hello()->supports_extended_master_secret(), |
649 | 553 | pending_state.server_hello()->supports_encrypt_then_mac(), |
650 | 553 | get_peer_cert_chain(pending_state), |
651 | 553 | std::vector<uint8_t>(), |
652 | 553 | Server_Information(pending_state.client_hello()->sni_hostname()), |
653 | 553 | pending_state.server_hello()->srtp_profile()); |
654 | | |
655 | 553 | if(save_session(session_info)) |
656 | 553 | { |
657 | 553 | if(pending_state.server_hello()->supports_session_ticket()) |
658 | 357 | { |
659 | 357 | try |
660 | 357 | { |
661 | 357 | const SymmetricKey ticket_key = m_creds.psk("tls-server", "session-ticket", ""); |
662 | | |
663 | 357 | pending_state.new_session_ticket( |
664 | 357 | new New_Session_Ticket(pending_state.handshake_io(), |
665 | 357 | pending_state.hash(), |
666 | 357 | session_info.encrypt(ticket_key, rng()), |
667 | 357 | policy().session_ticket_lifetime())); |
668 | 357 | } |
669 | 0 | catch(...) {} |
670 | 357 | } |
671 | 196 | else |
672 | 196 | session_manager().save(session_info); |
673 | 553 | } |
674 | | |
675 | 553 | if(!pending_state.new_session_ticket() && |
676 | 196 | pending_state.server_hello()->supports_session_ticket()) |
677 | 0 | { |
678 | 0 | pending_state.new_session_ticket( |
679 | 0 | new New_Session_Ticket(pending_state.handshake_io(), pending_state.hash())); |
680 | 0 | } |
681 | | |
682 | 553 | pending_state.handshake_io().send(Change_Cipher_Spec()); |
683 | | |
684 | 553 | change_cipher_spec_writer(SERVER); |
685 | | |
686 | 553 | pending_state.server_finished(new Finished(pending_state.handshake_io(), pending_state, SERVER)); |
687 | 553 | } |
688 | | |
689 | 553 | activate_session(); |
690 | 553 | } |
691 | | |
692 | | /* |
693 | | * Process a handshake message |
694 | | */ |
695 | | void Server::process_handshake_msg(const Handshake_State* active_state, |
696 | | Handshake_State& state_base, |
697 | | Handshake_Type type, |
698 | | const std::vector<uint8_t>& contents, |
699 | | bool epoch0_restart) |
700 | 46.5k | { |
701 | 46.5k | Server_Handshake_State& state = dynamic_cast<Server_Handshake_State&>(state_base); |
702 | 46.5k | state.confirm_transition_to(type); |
703 | | |
704 | | /* |
705 | | * The change cipher spec message isn't technically a handshake |
706 | | * message so it's not included in the hash. The finished and |
707 | | * certificate verify messages are verified based on the current |
708 | | * state of the hash *before* this message so we delay adding them |
709 | | * to the hash computation until we've processed them below. |
710 | | */ |
711 | 46.5k | if(type != HANDSHAKE_CCS && type != FINISHED && type != CERTIFICATE_VERIFY) |
712 | 45.0k | { |
713 | 45.0k | state.hash().update(state.handshake_io().format(contents, type)); |
714 | 45.0k | } |
715 | | |
716 | 46.5k | switch(type) |
717 | 46.5k | { |
718 | 34.1k | case CLIENT_HELLO: |
719 | 34.1k | return this->process_client_hello_msg(active_state, state, contents, epoch0_restart); |
720 | | |
721 | 0 | case CERTIFICATE: |
722 | 0 | return this->process_certificate_msg(state, contents); |
723 | | |
724 | 10.9k | case CLIENT_KEX: |
725 | 10.9k | return this->process_client_key_exchange_msg(state, contents); |
726 | | |
727 | 0 | case CERTIFICATE_VERIFY: |
728 | 0 | return this->process_certificate_verify_msg(state, type, contents); |
729 | | |
730 | 794 | case HANDSHAKE_CCS: |
731 | 794 | return this->process_change_cipher_spec_msg(state); |
732 | | |
733 | 558 | case FINISHED: |
734 | 558 | return this->process_finished_msg(state, type, contents); |
735 | | |
736 | 0 | default: |
737 | 0 | throw Unexpected_Message("Unknown handshake message received"); |
738 | 46.5k | } |
739 | 46.5k | } |
740 | | |
741 | | void Server::session_resume(Server_Handshake_State& pending_state, |
742 | | bool have_session_ticket_key, |
743 | | Session& session_info) |
744 | 0 | { |
745 | | // Only offer a resuming client a new ticket if they didn't send one this time, |
746 | | // ie, resumed via server-side resumption. TODO: also send one if expiring soon? |
747 | |
|
748 | 0 | const bool offer_new_session_ticket = |
749 | 0 | (pending_state.client_hello()->supports_session_ticket() && |
750 | 0 | pending_state.client_hello()->session_ticket().empty() && |
751 | 0 | have_session_ticket_key); |
752 | |
|
753 | 0 | pending_state.server_hello(new Server_Hello( |
754 | 0 | pending_state.handshake_io(), |
755 | 0 | pending_state.hash(), |
756 | 0 | policy(), |
757 | 0 | callbacks(), |
758 | 0 | rng(), |
759 | 0 | secure_renegotiation_data_for_server_hello(), |
760 | 0 | *pending_state.client_hello(), |
761 | 0 | session_info, |
762 | 0 | offer_new_session_ticket, |
763 | 0 | m_next_protocol)); |
764 | |
|
765 | 0 | secure_renegotiation_check(pending_state.server_hello()); |
766 | |
|
767 | 0 | pending_state.mark_as_resumption(); |
768 | 0 | pending_state.compute_session_keys(session_info.master_secret()); |
769 | 0 | pending_state.set_resume_certs(session_info.peer_certs()); |
770 | |
|
771 | 0 | if(!save_session(session_info)) |
772 | 0 | { |
773 | 0 | session_manager().remove_entry(session_info.session_id()); |
774 | |
|
775 | 0 | if(pending_state.server_hello()->supports_session_ticket()) // send an empty ticket |
776 | 0 | { |
777 | 0 | pending_state.new_session_ticket( |
778 | 0 | new New_Session_Ticket(pending_state.handshake_io(), |
779 | 0 | pending_state.hash())); |
780 | 0 | } |
781 | 0 | } |
782 | |
|
783 | 0 | if(pending_state.server_hello()->supports_session_ticket() && !pending_state.new_session_ticket()) |
784 | 0 | { |
785 | 0 | try |
786 | 0 | { |
787 | 0 | const SymmetricKey ticket_key = m_creds.psk("tls-server", "session-ticket", ""); |
788 | |
|
789 | 0 | pending_state.new_session_ticket( |
790 | 0 | new New_Session_Ticket(pending_state.handshake_io(), |
791 | 0 | pending_state.hash(), |
792 | 0 | session_info.encrypt(ticket_key, rng()), |
793 | 0 | policy().session_ticket_lifetime())); |
794 | 0 | } |
795 | 0 | catch(...) {} |
796 | |
|
797 | 0 | if(!pending_state.new_session_ticket()) |
798 | 0 | { |
799 | 0 | pending_state.new_session_ticket( |
800 | 0 | new New_Session_Ticket(pending_state.handshake_io(), pending_state.hash())); |
801 | 0 | } |
802 | 0 | } |
803 | |
|
804 | 0 | pending_state.handshake_io().send(Change_Cipher_Spec()); |
805 | |
|
806 | 0 | change_cipher_spec_writer(SERVER); |
807 | |
|
808 | 0 | pending_state.server_finished(new Finished(pending_state.handshake_io(), pending_state, SERVER)); |
809 | 0 | pending_state.set_expected_next(HANDSHAKE_CCS); |
810 | 0 | } |
811 | | |
812 | | void Server::session_create(Server_Handshake_State& pending_state, |
813 | | bool have_session_ticket_key) |
814 | 22.6k | { |
815 | 22.6k | std::map<std::string, std::vector<X509_Certificate>> cert_chains; |
816 | | |
817 | 22.6k | const std::string sni_hostname = pending_state.client_hello()->sni_hostname(); |
818 | | |
819 | 22.6k | cert_chains = get_server_certs(sni_hostname, m_creds); |
820 | | |
821 | 22.6k | if(sni_hostname != "" && cert_chains.empty()) |
822 | 0 | { |
823 | 0 | cert_chains = get_server_certs("", m_creds); |
824 | | |
825 | | /* |
826 | | * Only send the unrecognized_name alert if we couldn't |
827 | | * find any certs for the requested name but did find at |
828 | | * least one cert to use in general. That avoids sending an |
829 | | * unrecognized_name when a server is configured for purely |
830 | | * anonymous/PSK operation. |
831 | | */ |
832 | 0 | if(!cert_chains.empty()) |
833 | 0 | send_warning_alert(Alert::UNRECOGNIZED_NAME); |
834 | 0 | } |
835 | | |
836 | 22.6k | const uint16_t ciphersuite = choose_ciphersuite(policy(), pending_state.version(), |
837 | 22.6k | cert_chains, |
838 | 22.6k | *pending_state.client_hello()); |
839 | | |
840 | 22.6k | Server_Hello::Settings srv_settings( |
841 | 22.6k | make_hello_random(rng(), policy()), // new session ID |
842 | 22.6k | pending_state.version(), |
843 | 22.6k | ciphersuite, |
844 | 22.6k | have_session_ticket_key); |
845 | | |
846 | 22.6k | pending_state.server_hello(new Server_Hello( |
847 | 22.6k | pending_state.handshake_io(), |
848 | 22.6k | pending_state.hash(), |
849 | 22.6k | policy(), |
850 | 22.6k | callbacks(), |
851 | 22.6k | rng(), |
852 | 22.6k | secure_renegotiation_data_for_server_hello(), |
853 | 22.6k | *pending_state.client_hello(), |
854 | 22.6k | srv_settings, |
855 | 22.6k | m_next_protocol)); |
856 | | |
857 | 22.6k | secure_renegotiation_check(pending_state.server_hello()); |
858 | | |
859 | 22.6k | const Ciphersuite& pending_suite = pending_state.ciphersuite(); |
860 | | |
861 | 22.6k | Private_Key* private_key = nullptr; |
862 | | |
863 | 22.6k | if(pending_suite.signature_used() || pending_suite.kex_method() == Kex_Algo::STATIC_RSA) |
864 | 161 | { |
865 | 161 | const std::string algo_used = |
866 | 103 | pending_suite.signature_used() ? pending_suite.sig_algo() : "RSA"; |
867 | | |
868 | 161 | BOTAN_ASSERT(!cert_chains[algo_used].empty(), |
869 | 161 | "Attempting to send empty certificate chain"); |
870 | | |
871 | 161 | pending_state.server_certs(new Certificate(pending_state.handshake_io(), |
872 | 161 | pending_state.hash(), |
873 | 161 | cert_chains[algo_used])); |
874 | | |
875 | 161 | if(pending_state.client_hello()->supports_cert_status_message() && pending_state.is_a_resumption() == false) |
876 | 10 | { |
877 | 10 | auto csr = pending_state.client_hello()->extensions().get<Certificate_Status_Request>(); |
878 | | // csr is non-null if client_hello()->supports_cert_status_message() |
879 | 10 | BOTAN_ASSERT_NOMSG(csr != nullptr); |
880 | 10 | const auto resp_bytes = callbacks().tls_provide_cert_status(cert_chains[algo_used], *csr); |
881 | 10 | if(resp_bytes.size() > 0) |
882 | 0 | { |
883 | 0 | pending_state.server_cert_status(new Certificate_Status( |
884 | 0 | pending_state.handshake_io(), |
885 | 0 | pending_state.hash(), |
886 | 0 | resp_bytes |
887 | 0 | )); |
888 | 0 | } |
889 | 10 | } |
890 | | |
891 | 161 | private_key = m_creds.private_key_for( |
892 | 161 | pending_state.server_certs()->cert_chain()[0], |
893 | 161 | "tls-server", |
894 | 161 | sni_hostname); |
895 | | |
896 | 161 | if(!private_key) |
897 | 161 | throw Internal_Error("No private key located for associated server cert"); |
898 | 22.4k | } |
899 | | |
900 | 22.4k | if(pending_suite.kex_method() == Kex_Algo::STATIC_RSA) |
901 | 0 | { |
902 | 0 | pending_state.set_server_rsa_kex_key(private_key); |
903 | 0 | } |
904 | 22.4k | else |
905 | 22.4k | { |
906 | 22.4k | pending_state.server_kex(new Server_Key_Exchange(pending_state.handshake_io(), |
907 | 22.4k | pending_state, policy(), |
908 | 22.4k | m_creds, rng(), private_key)); |
909 | 22.4k | } |
910 | | |
911 | 22.4k | auto trusted_CAs = m_creds.trusted_certificate_authorities("tls-server", sni_hostname); |
912 | | |
913 | 22.4k | std::vector<X509_DN> client_auth_CAs; |
914 | | |
915 | 22.4k | for(auto store : trusted_CAs) |
916 | 0 | { |
917 | 0 | auto subjects = store->all_subjects(); |
918 | 0 | client_auth_CAs.insert(client_auth_CAs.end(), subjects.begin(), subjects.end()); |
919 | 0 | } |
920 | | |
921 | 22.4k | const bool request_cert = |
922 | 22.4k | (client_auth_CAs.empty() == false) || |
923 | 22.1k | policy().request_client_certificate_authentication(); |
924 | | |
925 | 22.4k | if(request_cert && pending_state.ciphersuite().signature_used()) |
926 | 0 | { |
927 | 0 | pending_state.cert_req( |
928 | 0 | new Certificate_Req(pending_state.handshake_io(), |
929 | 0 | pending_state.hash(), |
930 | 0 | policy(), |
931 | 0 | client_auth_CAs)); |
932 | | |
933 | | /* |
934 | | SSLv3 allowed clients to skip the Certificate message entirely |
935 | | if they wanted. In TLS v1.0 and later clients must send a |
936 | | (possibly empty) Certificate message |
937 | | */ |
938 | 0 | pending_state.set_expected_next(CERTIFICATE); |
939 | 0 | } |
940 | 22.4k | else |
941 | 22.4k | { |
942 | 22.4k | pending_state.set_expected_next(CLIENT_KEX); |
943 | 22.4k | } |
944 | | |
945 | 22.4k | pending_state.server_hello_done(new Server_Hello_Done(pending_state.handshake_io(), pending_state.hash())); |
946 | 22.4k | } |
947 | | } |
948 | | |
949 | | } |