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