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