/src/boringssl/ssl/ssl_session.cc
Line | Count | Source |
1 | | // Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved. |
2 | | // Copyright 2005 Nokia. All rights reserved. |
3 | | // |
4 | | // Licensed under the Apache License, Version 2.0 (the "License"); |
5 | | // you may not use this file except in compliance with the License. |
6 | | // You may obtain a copy of the License at |
7 | | // |
8 | | // https://www.apache.org/licenses/LICENSE-2.0 |
9 | | // |
10 | | // Unless required by applicable law or agreed to in writing, software |
11 | | // distributed under the License is distributed on an "AS IS" BASIS, |
12 | | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
13 | | // See the License for the specific language governing permissions and |
14 | | // limitations under the License. |
15 | | |
16 | | #include <openssl/ssl.h> |
17 | | |
18 | | #include <assert.h> |
19 | | #include <stdlib.h> |
20 | | #include <string.h> |
21 | | |
22 | | #include <utility> |
23 | | |
24 | | #include <openssl/cipher.h> |
25 | | #include <openssl/err.h> |
26 | | #include <openssl/evp.h> |
27 | | #include <openssl/hmac.h> |
28 | | #include <openssl/mem.h> |
29 | | #include <openssl/pool.h> |
30 | | #include <openssl/rand.h> |
31 | | |
32 | | #include "../crypto/internal.h" |
33 | | #include "internal.h" |
34 | | |
35 | | |
36 | | BSSL_NAMESPACE_BEGIN |
37 | | |
38 | | // The address of this is a magic value, a pointer to which is returned by |
39 | | // SSL_magic_pending_session_ptr(). It allows a session callback to indicate |
40 | | // that it needs to asynchronously fetch session information. |
41 | | static const char g_pending_session_magic = 0; |
42 | | |
43 | | static ExDataClass g_ex_data_class(/*with_app_data=*/true); |
44 | | |
45 | | static void SSL_SESSION_list_remove(SSLContext *ctx, SSL_SESSION *session); |
46 | | static void SSL_SESSION_list_add(SSLContext *ctx, SSL_SESSION *session); |
47 | | |
48 | 241k | UniquePtr<SSL_SESSION> ssl_session_new(const SSL_X509_METHOD *x509_method) { |
49 | 241k | return MakeUnique<SSL_SESSION>(x509_method); |
50 | 241k | } |
51 | | |
52 | 74.5k | uint32_t ssl_hash_session_id(Span<const uint8_t> session_id) { |
53 | | // Take the first four bytes of `session_id`. Session IDs are generated by the |
54 | | // server randomly, so we can assume even using the first four bytes results |
55 | | // in a good distribution. |
56 | 74.5k | uint8_t tmp_storage[sizeof(uint32_t)]; |
57 | 74.5k | if (session_id.size() < sizeof(tmp_storage)) { |
58 | 26.5k | OPENSSL_memset(tmp_storage, 0, sizeof(tmp_storage)); |
59 | 26.5k | OPENSSL_memcpy(tmp_storage, session_id.data(), session_id.size()); |
60 | 26.5k | session_id = tmp_storage; |
61 | 26.5k | } |
62 | | |
63 | 74.5k | uint32_t hash = ((uint32_t)session_id[0]) | ((uint32_t)session_id[1] << 8) | |
64 | 74.5k | ((uint32_t)session_id[2] << 16) | |
65 | 74.5k | ((uint32_t)session_id[3] << 24); |
66 | | |
67 | 74.5k | return hash; |
68 | 74.5k | } |
69 | | |
70 | | UniquePtr<SSL_SESSION> SSL_SESSION_dup(const SSL_SESSION *session, |
71 | 48.1k | int dup_flags) { |
72 | 48.1k | UniquePtr<SSL_SESSION> new_session = ssl_session_new(session->x509_method); |
73 | 48.1k | if (!new_session) { |
74 | 0 | return nullptr; |
75 | 0 | } |
76 | | |
77 | 48.1k | new_session->is_server = session->is_server; |
78 | 48.1k | new_session->ssl_version = session->ssl_version; |
79 | 48.1k | new_session->is_quic = session->is_quic; |
80 | 48.1k | new_session->sid_ctx = session->sid_ctx; |
81 | | |
82 | | // Copy the key material. |
83 | 48.1k | new_session->secret = session->secret; |
84 | 48.1k | new_session->cipher = session->cipher; |
85 | | |
86 | | // Copy authentication state. |
87 | 48.1k | if (session->psk_identity != nullptr) { |
88 | 40 | new_session->psk_identity.reset( |
89 | 40 | OPENSSL_strdup(session->psk_identity.get())); |
90 | 40 | if (new_session->psk_identity == nullptr) { |
91 | 0 | return nullptr; |
92 | 0 | } |
93 | 40 | } |
94 | 48.1k | new_session->peer_cert_type = session->peer_cert_type; |
95 | 48.1k | if (session->certs != nullptr) { |
96 | 46.3k | new_session->certs.reset(sk_CRYPTO_BUFFER_deep_copy( |
97 | 46.3k | session->certs.get(), CRYPTO_BUFFER_dup_ref, CRYPTO_BUFFER_free)); |
98 | 46.3k | if (new_session->certs == nullptr) { |
99 | 0 | return nullptr; |
100 | 0 | } |
101 | 46.3k | } |
102 | 48.1k | if (session->peer_raw_public_key != nullptr) { |
103 | 0 | new_session->peer_raw_public_key = UpRef(session->peer_raw_public_key); |
104 | 0 | } |
105 | | |
106 | 48.1k | if (!session->x509_method->session_dup(new_session.get(), session)) { |
107 | 0 | return nullptr; |
108 | 0 | } |
109 | | |
110 | 48.1k | new_session->verify_result = session->verify_result; |
111 | | |
112 | 48.1k | new_session->ocsp_response = UpRef(session->ocsp_response); |
113 | 48.1k | new_session->signed_cert_timestamp_list = |
114 | 48.1k | UpRef(session->signed_cert_timestamp_list); |
115 | | |
116 | 48.1k | OPENSSL_memcpy(new_session->peer_sha256, session->peer_sha256, |
117 | 48.1k | SHA256_DIGEST_LENGTH); |
118 | 48.1k | new_session->peer_sha256_valid = session->peer_sha256_valid; |
119 | | |
120 | 48.1k | new_session->peer_signature_algorithm = session->peer_signature_algorithm; |
121 | | |
122 | 48.1k | new_session->timeout = session->timeout; |
123 | 48.1k | new_session->auth_timeout = session->auth_timeout; |
124 | 48.1k | new_session->time = session->time; |
125 | | |
126 | | // Copy non-authentication connection properties. |
127 | 48.1k | if (dup_flags & SSL_SESSION_INCLUDE_NONAUTH) { |
128 | 47.7k | new_session->session_id = session->session_id; |
129 | 47.7k | new_session->group_id = session->group_id; |
130 | 47.7k | new_session->original_handshake_hash = session->original_handshake_hash; |
131 | 47.7k | new_session->ticket_lifetime_hint = session->ticket_lifetime_hint; |
132 | 47.7k | new_session->ticket_age_add = session->ticket_age_add; |
133 | 47.7k | new_session->ticket_max_early_data = session->ticket_max_early_data; |
134 | 47.7k | new_session->extended_master_secret = session->extended_master_secret; |
135 | 47.7k | new_session->has_application_settings = session->has_application_settings; |
136 | | |
137 | 47.7k | if (!new_session->early_alpn.CopyFrom(session->early_alpn) || |
138 | 47.7k | !new_session->quic_early_data_context.CopyFrom( |
139 | 47.7k | session->quic_early_data_context) || |
140 | 47.7k | !new_session->local_application_settings.CopyFrom( |
141 | 47.7k | session->local_application_settings) || |
142 | 47.7k | !new_session->peer_application_settings.CopyFrom( |
143 | 47.7k | session->peer_application_settings)) { |
144 | 0 | return nullptr; |
145 | 0 | } |
146 | 47.7k | } |
147 | | |
148 | | // Copy the ticket. |
149 | 48.1k | if (dup_flags & SSL_SESSION_INCLUDE_TICKET && |
150 | 38.9k | !new_session->ticket.CopyFrom(session->ticket)) { |
151 | 0 | return nullptr; |
152 | 0 | } |
153 | | |
154 | | // The new_session does not get a copy of the ex_data. |
155 | | |
156 | 48.1k | new_session->not_resumable = true; |
157 | 48.1k | return new_session; |
158 | 48.1k | } |
159 | | |
160 | 47.1k | void ssl_session_rebase_time(SSL *ssl, SSL_SESSION *session) { |
161 | 47.1k | OPENSSL_timeval now = ssl_ctx_get_current_time(ssl->ctx.get()); |
162 | | |
163 | | // To avoid overflows and underflows, if we've gone back in time, update the |
164 | | // time, but mark the session expired. |
165 | 47.1k | if (session->time > now.tv_sec) { |
166 | 0 | session->time = now.tv_sec; |
167 | 0 | session->timeout = 0; |
168 | 0 | session->auth_timeout = 0; |
169 | 0 | return; |
170 | 0 | } |
171 | | |
172 | | // Adjust the session time and timeouts. If the session has already expired, |
173 | | // clamp the timeouts at zero. |
174 | 47.1k | uint64_t delta = now.tv_sec - session->time; |
175 | 47.1k | session->time = now.tv_sec; |
176 | 47.1k | if (session->timeout < delta) { |
177 | 0 | session->timeout = 0; |
178 | 47.1k | } else { |
179 | 47.1k | session->timeout -= delta; |
180 | 47.1k | } |
181 | 47.1k | if (session->auth_timeout < delta) { |
182 | 58 | session->auth_timeout = 0; |
183 | 47.1k | } else { |
184 | 47.1k | session->auth_timeout -= delta; |
185 | 47.1k | } |
186 | 47.1k | } |
187 | | |
188 | | void ssl_session_renew_timeout(SSL *ssl, SSL_SESSION *session, |
189 | 360 | uint32_t timeout) { |
190 | | // Rebase the timestamp relative to the current time so `timeout` is measured |
191 | | // correctly. |
192 | 360 | ssl_session_rebase_time(ssl, session); |
193 | | |
194 | 360 | if (session->timeout > timeout) { |
195 | 191 | return; |
196 | 191 | } |
197 | | |
198 | 169 | session->timeout = timeout; |
199 | 169 | if (session->timeout > session->auth_timeout) { |
200 | 71 | session->timeout = session->auth_timeout; |
201 | 71 | } |
202 | 169 | } |
203 | | |
204 | 213k | uint16_t ssl_session_protocol_version(const SSL_SESSION *session) { |
205 | 213k | uint16_t ret; |
206 | 213k | if (!ssl_protocol_version_from_wire(&ret, session->ssl_version)) { |
207 | | // An `SSL_SESSION` will never have an invalid version. This is enforced by |
208 | | // the parser. |
209 | 0 | assert(0); |
210 | 0 | return 0; |
211 | 0 | } |
212 | | |
213 | 213k | return ret; |
214 | 213k | } |
215 | | |
216 | 145k | const EVP_MD *ssl_session_get_digest(const SSL_SESSION *session) { |
217 | 145k | return ssl_get_handshake_digest(ssl_session_protocol_version(session), |
218 | 145k | session->cipher); |
219 | 145k | } |
220 | | |
221 | 60.1k | bool ssl_get_new_session(SSL_HANDSHAKE *hs) { |
222 | 60.1k | SSL *const ssl = hs->ssl; |
223 | 60.1k | if (ssl->mode & SSL_MODE_NO_SESSION_CREATION) { |
224 | 0 | OPENSSL_PUT_ERROR(SSL, SSL_R_SESSION_MAY_NOT_BE_CREATED); |
225 | 0 | return false; |
226 | 0 | } |
227 | | |
228 | 60.1k | UniquePtr<SSL_SESSION> session = ssl_session_new(ssl->ctx->x509_method); |
229 | 60.1k | if (session == nullptr) { |
230 | 0 | return false; |
231 | 0 | } |
232 | | |
233 | 60.1k | session->is_server = ssl->server; |
234 | 60.1k | session->ssl_version = ssl->s3->version; |
235 | 60.1k | session->is_quic = SSL_is_quic(ssl); |
236 | | |
237 | | // Fill in the time from the `SSL_CTX`'s clock. |
238 | 60.1k | OPENSSL_timeval now = ssl_ctx_get_current_time(ssl->ctx.get()); |
239 | 60.1k | session->time = now.tv_sec; |
240 | | |
241 | 60.1k | uint16_t version = ssl_protocol_version(ssl); |
242 | 60.1k | if (version >= TLS1_3_VERSION) { |
243 | | // TLS 1.3 uses tickets as authenticators, so we are willing to use them for |
244 | | // longer. |
245 | 6.55k | session->timeout = ssl->session_ctx->session_psk_dhe_timeout; |
246 | 6.55k | session->auth_timeout = SSL_DEFAULT_SESSION_AUTH_TIMEOUT; |
247 | 53.6k | } else { |
248 | | // TLS 1.2 resumption does not incorporate new key material, so we use a |
249 | | // much shorter timeout. |
250 | 53.6k | session->timeout = ssl->session_ctx->session_timeout; |
251 | 53.6k | session->auth_timeout = ssl->session_ctx->session_timeout; |
252 | 53.6k | } |
253 | | |
254 | 60.1k | if (!session->sid_ctx.TryCopyFrom(hs->config->cert->sid_ctx)) { |
255 | 0 | OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); |
256 | 0 | return false; |
257 | 0 | } |
258 | | |
259 | | // The session is marked not resumable until it is completely filled in. |
260 | 60.1k | session->not_resumable = true; |
261 | 60.1k | session->verify_result = X509_V_ERR_INVALID_CALL; |
262 | | |
263 | 60.1k | hs->new_session = std::move(session); |
264 | 60.1k | ssl_set_session(ssl, nullptr); |
265 | 60.1k | return true; |
266 | 60.1k | } |
267 | | |
268 | 1.76k | bool ssl_ctx_rotate_ticket_encryption_key(SSLContext *ctx) { |
269 | 1.76k | OPENSSL_timeval now = ssl_ctx_get_current_time(ctx); |
270 | 1.76k | { |
271 | | // Avoid acquiring a write lock in the common case (i.e. a non-default key |
272 | | // is used or the default keys have not expired yet). |
273 | 1.76k | MutexReadLock lock(&ctx->lock); |
274 | 1.76k | if (ctx->ticket_key_current && |
275 | 1.76k | (ctx->ticket_key_current->next_rotation_tv_sec == 0 || |
276 | 1.76k | ctx->ticket_key_current->next_rotation_tv_sec > now.tv_sec) && |
277 | 1.76k | (!ctx->ticket_key_prev || |
278 | 1.76k | ctx->ticket_key_prev->next_rotation_tv_sec > now.tv_sec)) { |
279 | 1.76k | return true; |
280 | 1.76k | } |
281 | 1.76k | } |
282 | | |
283 | 3 | MutexWriteLock lock(&ctx->lock); |
284 | 3 | if (!ctx->ticket_key_current || |
285 | 0 | (ctx->ticket_key_current->next_rotation_tv_sec != 0 && |
286 | 3 | ctx->ticket_key_current->next_rotation_tv_sec <= now.tv_sec)) { |
287 | | // The current key has not been initialized or it is expired. |
288 | 3 | auto new_key = bssl::MakeUnique<TicketKey>(); |
289 | 3 | if (!new_key) { |
290 | 0 | return false; |
291 | 0 | } |
292 | 3 | RAND_bytes(new_key->name, 16); |
293 | 3 | RAND_bytes(new_key->hmac_key, 16); |
294 | 3 | RAND_bytes(new_key->aes_key, 16); |
295 | 3 | new_key->next_rotation_tv_sec = |
296 | 3 | now.tv_sec + SSL_DEFAULT_TICKET_KEY_ROTATION_INTERVAL; |
297 | 3 | if (ctx->ticket_key_current) { |
298 | | // The current key expired. Rotate it to prev and bump up its rotation |
299 | | // timestamp. Note that even with the new rotation time it may still be |
300 | | // expired and get dropped below. |
301 | 0 | ctx->ticket_key_current->next_rotation_tv_sec += |
302 | 0 | SSL_DEFAULT_TICKET_KEY_ROTATION_INTERVAL; |
303 | 0 | ctx->ticket_key_prev = std::move(ctx->ticket_key_current); |
304 | 0 | } |
305 | 3 | ctx->ticket_key_current = std::move(new_key); |
306 | 3 | } |
307 | | |
308 | | // Drop an expired prev key. |
309 | 3 | if (ctx->ticket_key_prev && |
310 | 0 | ctx->ticket_key_prev->next_rotation_tv_sec <= now.tv_sec) { |
311 | 0 | ctx->ticket_key_prev.reset(); |
312 | 0 | } |
313 | | |
314 | 3 | return true; |
315 | 3 | } |
316 | | |
317 | | static int ssl_encrypt_ticket_with_cipher_ctx(SSL_HANDSHAKE *hs, CBB *out, |
318 | | const uint8_t *session_buf, |
319 | 1.60k | size_t session_len) { |
320 | 1.60k | ScopedEVP_CIPHER_CTX ctx; |
321 | 1.60k | ScopedHMAC_CTX hctx; |
322 | | |
323 | | // If the session is too long, decline to send a ticket. |
324 | 1.60k | static const size_t kMaxTicketOverhead = |
325 | 1.60k | 16 + EVP_MAX_IV_LENGTH + EVP_MAX_BLOCK_LENGTH + EVP_MAX_MD_SIZE; |
326 | 1.60k | if (session_len > 0xffff - kMaxTicketOverhead) { |
327 | 0 | return 1; |
328 | 0 | } |
329 | | |
330 | | // Initialize HMAC and cipher contexts. If callback present it does all the |
331 | | // work otherwise use generated values from parent ctx. |
332 | 1.60k | SSLContext *tctx = hs->ssl->session_ctx.get(); |
333 | 1.60k | uint8_t iv[EVP_MAX_IV_LENGTH]; |
334 | 1.60k | uint8_t key_name[16]; |
335 | 1.60k | if (tctx->ticket_key_cb != nullptr) { |
336 | 0 | int ret = tctx->ticket_key_cb(hs->ssl, key_name, iv, ctx.get(), hctx.get(), |
337 | 0 | 1 /* encrypt */); |
338 | 0 | if (ret < 0) { |
339 | 0 | return 0; |
340 | 0 | } |
341 | 0 | if (ret == 0) { |
342 | | // The caller requested to send no ticket, so write nothing to `out`. |
343 | 0 | return 1; |
344 | 0 | } |
345 | 1.60k | } else { |
346 | | // Rotate ticket key if necessary. |
347 | 1.60k | if (!ssl_ctx_rotate_ticket_encryption_key(tctx)) { |
348 | 0 | return 0; |
349 | 0 | } |
350 | 1.60k | MutexReadLock lock(&tctx->lock); |
351 | 1.60k | if (!RAND_bytes(iv, 16) || |
352 | 1.60k | !EVP_EncryptInit_ex(ctx.get(), EVP_aes_128_cbc(), nullptr, |
353 | 1.60k | tctx->ticket_key_current->aes_key, iv) || |
354 | 1.60k | !HMAC_Init_ex(hctx.get(), tctx->ticket_key_current->hmac_key, 16, |
355 | 1.60k | tlsext_tick_md(), nullptr)) { |
356 | 0 | return 0; |
357 | 0 | } |
358 | 1.60k | OPENSSL_memcpy(key_name, tctx->ticket_key_current->name, 16); |
359 | 1.60k | } |
360 | | |
361 | 1.60k | uint8_t *ptr; |
362 | 1.60k | if (!CBB_add_bytes(out, key_name, 16) || |
363 | 1.60k | !CBB_add_bytes(out, iv, EVP_CIPHER_CTX_iv_length(ctx.get())) || |
364 | 1.60k | !CBB_reserve(out, &ptr, session_len + EVP_MAX_BLOCK_LENGTH)) { |
365 | 0 | return 0; |
366 | 0 | } |
367 | | |
368 | 1.60k | size_t total = 0; |
369 | 1.60k | if (CRYPTO_fuzzer_mode_enabled()) { |
370 | 1.44k | OPENSSL_memcpy(ptr, session_buf, session_len); |
371 | 1.44k | total = session_len; |
372 | 1.44k | } else { |
373 | 161 | size_t len; |
374 | 161 | if (!EVP_EncryptUpdate_ex(ctx.get(), ptr + total, &len, |
375 | 161 | session_len + EVP_MAX_BLOCK_LENGTH - total, |
376 | 161 | session_buf, session_len)) { |
377 | 0 | return 0; |
378 | 0 | } |
379 | 161 | total += len; |
380 | 161 | if (!EVP_EncryptFinal_ex2(ctx.get(), ptr + total, &len, |
381 | 161 | session_len + EVP_MAX_BLOCK_LENGTH - total)) { |
382 | 0 | return 0; |
383 | 0 | } |
384 | 161 | total += len; |
385 | 161 | } |
386 | 1.60k | if (!CBB_did_write(out, total)) { |
387 | 0 | return 0; |
388 | 0 | } |
389 | | |
390 | 1.60k | unsigned hlen; |
391 | 1.60k | if (!HMAC_Update(hctx.get(), CBB_data(out), CBB_len(out)) || // |
392 | 1.60k | !CBB_reserve(out, &ptr, EVP_MAX_MD_SIZE) || // |
393 | 1.60k | !HMAC_Final(hctx.get(), ptr, &hlen) || // |
394 | 1.60k | !CBB_did_write(out, hlen)) { |
395 | 0 | return 0; |
396 | 0 | } |
397 | | |
398 | 1.60k | return 1; |
399 | 1.60k | } |
400 | | |
401 | | static int ssl_encrypt_ticket_with_method(SSL_HANDSHAKE *hs, CBB *out, |
402 | | const uint8_t *session_buf, |
403 | 0 | size_t session_len) { |
404 | 0 | SSL *const ssl = hs->ssl; |
405 | 0 | const SSL_TICKET_AEAD_METHOD *method = ssl->session_ctx->ticket_aead_method; |
406 | 0 | const size_t max_overhead = method->max_overhead(ssl); |
407 | 0 | const size_t max_out = session_len + max_overhead; |
408 | 0 | if (max_out < max_overhead) { |
409 | 0 | OPENSSL_PUT_ERROR(SSL, ERR_R_OVERFLOW); |
410 | 0 | return 0; |
411 | 0 | } |
412 | | |
413 | 0 | uint8_t *ptr; |
414 | 0 | if (!CBB_reserve(out, &ptr, max_out)) { |
415 | 0 | return 0; |
416 | 0 | } |
417 | | |
418 | 0 | size_t out_len; |
419 | 0 | if (!method->seal(ssl, ptr, &out_len, max_out, session_buf, session_len)) { |
420 | 0 | OPENSSL_PUT_ERROR(SSL, SSL_R_TICKET_ENCRYPTION_FAILED); |
421 | 0 | return 0; |
422 | 0 | } |
423 | | |
424 | 0 | if (!CBB_did_write(out, out_len)) { |
425 | 0 | return 0; |
426 | 0 | } |
427 | | |
428 | 0 | return 1; |
429 | 0 | } |
430 | | |
431 | | bool ssl_encrypt_ticket(SSL_HANDSHAKE *hs, CBB *out, |
432 | 1.60k | const SSL_SESSION *session) { |
433 | | // Serialize the SSL_SESSION to be encoded into the ticket. |
434 | 1.60k | uint8_t *session_buf = nullptr; |
435 | 1.60k | size_t session_len; |
436 | 1.60k | if (!SSL_SESSION_to_bytes_for_ticket(session, &session_buf, &session_len)) { |
437 | 0 | return false; |
438 | 0 | } |
439 | 1.60k | bssl::UniquePtr<uint8_t> free_session_buf(session_buf); |
440 | | |
441 | 1.60k | if (hs->ssl->session_ctx->ticket_aead_method) { |
442 | 0 | return ssl_encrypt_ticket_with_method(hs, out, session_buf, session_len); |
443 | 1.60k | } else { |
444 | 1.60k | return ssl_encrypt_ticket_with_cipher_ctx(hs, out, session_buf, |
445 | 1.60k | session_len); |
446 | 1.60k | } |
447 | 1.60k | } |
448 | | |
449 | 47.4k | SSLSessionType ssl_session_get_type(const SSL_SESSION *session) { |
450 | 47.4k | if (session->not_resumable) { |
451 | 37.0k | return SSLSessionType::kNotResumable; |
452 | 37.0k | } |
453 | 10.3k | if (ssl_session_protocol_version(session) >= TLS1_3_VERSION) { |
454 | 4.47k | return session->ticket.empty() ? SSLSessionType::kNotResumable |
455 | 4.47k | : SSLSessionType::kPreSharedKey; |
456 | 4.47k | } |
457 | 5.84k | if (!session->ticket.empty()) { |
458 | 1.63k | return SSLSessionType::kTicket; |
459 | 1.63k | } |
460 | 4.21k | if (!session->session_id.empty()) { |
461 | 3.96k | return SSLSessionType::kID; |
462 | 3.96k | } |
463 | 248 | return SSLSessionType::kNotResumable; |
464 | 4.21k | } |
465 | | |
466 | | bool ssl_session_is_context_valid(const SSL_HANDSHAKE *hs, |
467 | 1.35k | const SSL_SESSION *session) { |
468 | 1.35k | return session != nullptr && |
469 | 1.35k | Span(session->sid_ctx) == hs->config->cert->sid_ctx; |
470 | 1.35k | } |
471 | | |
472 | 2.97k | bool ssl_session_is_time_valid(const SSL *ssl, const SSL_SESSION *session) { |
473 | 2.97k | if (session == nullptr) { |
474 | 0 | return false; |
475 | 0 | } |
476 | | |
477 | 2.97k | OPENSSL_timeval now = ssl_ctx_get_current_time(ssl->ctx.get()); |
478 | | |
479 | | // Reject tickets from the future to avoid underflow. |
480 | 2.97k | if (now.tv_sec < session->time) { |
481 | 95 | return false; |
482 | 95 | } |
483 | | |
484 | 2.88k | return session->timeout > now.tv_sec - session->time; |
485 | 2.97k | } |
486 | | |
487 | | bool ssl_session_is_resumable(const SSL_HANDSHAKE *hs, |
488 | 909 | const SSL_SESSION *session) { |
489 | 909 | const SSL *const ssl = hs->ssl; |
490 | 909 | return ssl_session_is_context_valid(hs, session) && |
491 | | // The session must have been created by the same type of end point as |
492 | | // we're now using it with. |
493 | 906 | ssl->server == session->is_server && |
494 | | // The session must not be expired. |
495 | 903 | ssl_session_is_time_valid(ssl, session) && |
496 | | // Only resume if the session's version matches the negotiated |
497 | | // version. |
498 | 881 | ssl->s3->version == session->ssl_version && |
499 | | // Only resume if the session's cipher matches the negotiated one. This |
500 | | // is stricter than necessary for TLS 1.3, which allows cross-cipher |
501 | | // resumption if the PRF hashes match. We require an exact match for |
502 | | // simplicity. If loosening this, the 0-RTT accept logic must be |
503 | | // updated to check the cipher. |
504 | 818 | hs->new_cipher == session->cipher && |
505 | | // If the session contains a client certificate/RPK (either the full |
506 | | // certificate/RPK or just the hash) then require that the form of the |
507 | | // certificate/RPK matches the current configuration. |
508 | 812 | (!ssl_session_has_peer_cred(session) || |
509 | 12 | session->peer_sha256_valid == |
510 | 12 | hs->config->retain_only_sha256_of_client_certs) && |
511 | | // Only resume if the underlying transport protocol hasn't changed. |
512 | | // This is to prevent cross-protocol resumption between QUIC and TCP. |
513 | 809 | SSL_is_quic(ssl) == int{session->is_quic}; |
514 | 909 | } |
515 | | |
516 | | // ssl_lookup_session looks up `session_id` in the session cache and sets |
517 | | // `*out_session` to an `SSL_SESSION` object if found. |
518 | | static enum ssl_hs_wait_t ssl_lookup_session( |
519 | | SSL_HANDSHAKE *hs, UniquePtr<SSL_SESSION> *out_session, |
520 | 6.93k | Span<const uint8_t> session_id) { |
521 | 6.93k | SSL *const ssl = hs->ssl; |
522 | 6.93k | out_session->reset(); |
523 | | |
524 | 6.93k | if (session_id.empty() || session_id.size() > SSL_MAX_SSL_SESSION_ID_LENGTH) { |
525 | 5.84k | return ssl_hs_ok; |
526 | 5.84k | } |
527 | | |
528 | 1.09k | UniquePtr<SSL_SESSION> session; |
529 | | // Try the internal cache, if it exists. |
530 | 1.09k | if (!(ssl->session_ctx->session_cache_mode & |
531 | 1.09k | SSL_SESS_CACHE_NO_INTERNAL_LOOKUP)) { |
532 | 1.09k | uint32_t hash = ssl_hash_session_id(session_id); |
533 | 1.09k | auto cmp = [](const void *key, const SSL_SESSION *sess) -> int { |
534 | 1.04k | Span<const uint8_t> key_id = |
535 | 1.04k | *reinterpret_cast<const Span<const uint8_t> *>(key); |
536 | 1.04k | return key_id == sess->session_id ? 0 : 1; |
537 | 1.04k | }; |
538 | 1.09k | MutexReadLock lock(&ssl->session_ctx->lock); |
539 | | // `lh_SSL_SESSION_retrieve_key` returns a non-owning pointer. |
540 | 1.09k | session = UpRef(lh_SSL_SESSION_retrieve_key(ssl->session_ctx->sessions, |
541 | 1.09k | &session_id, hash, cmp)); |
542 | | // TODO(davidben): This should probably move it to the front of the list. |
543 | 1.09k | } |
544 | | |
545 | | // Fall back to the external cache, if it exists. |
546 | 1.09k | if (!session && ssl->session_ctx->get_session_cb != nullptr) { |
547 | 0 | int copy = 1; |
548 | 0 | session.reset(ssl->session_ctx->get_session_cb(ssl, session_id.data(), |
549 | 0 | session_id.size(), ©)); |
550 | 0 | if (!session) { |
551 | 0 | return ssl_hs_ok; |
552 | 0 | } |
553 | | |
554 | 0 | if (session.get() == SSL_magic_pending_session_ptr()) { |
555 | 0 | session.release(); // This pointer is not actually owned. |
556 | 0 | return ssl_hs_pending_session; |
557 | 0 | } |
558 | | |
559 | | // Increment reference count now if the session callback asks us to do so |
560 | | // (note that if the session structures returned by the callback are shared |
561 | | // between threads, it must handle the reference count itself [i.e. copy == |
562 | | // 0], or things won't be thread-safe). |
563 | 0 | if (copy) { |
564 | 0 | SSL_SESSION_up_ref(session.get()); |
565 | 0 | } |
566 | | |
567 | | // Add the externally cached session to the internal cache if necessary. |
568 | 0 | if (!(ssl->session_ctx->session_cache_mode & |
569 | 0 | SSL_SESS_CACHE_NO_INTERNAL_STORE)) { |
570 | 0 | SSL_CTX_add_session(ssl->session_ctx.get(), session.get()); |
571 | 0 | } |
572 | 0 | } |
573 | | |
574 | 1.09k | if (session && !ssl_session_is_time_valid(ssl, session.get())) { |
575 | | // The session was from the cache, so remove it. |
576 | 91 | SSL_CTX_remove_session(ssl->session_ctx.get(), session.get()); |
577 | 91 | session.reset(); |
578 | 91 | } |
579 | | |
580 | 1.09k | *out_session = std::move(session); |
581 | 1.09k | return ssl_hs_ok; |
582 | 1.09k | } |
583 | | |
584 | | enum ssl_hs_wait_t ssl_get_prev_session(SSL_HANDSHAKE *hs, |
585 | | UniquePtr<SSL_SESSION> *out_session, |
586 | | bool *out_tickets_supported, |
587 | | bool *out_renew_ticket, |
588 | 7.85k | const SSL_CLIENT_HELLO *client_hello) { |
589 | | // This is used only by servers. |
590 | 7.85k | assert(hs->ssl->server); |
591 | 7.85k | UniquePtr<SSL_SESSION> session; |
592 | 7.85k | bool renew_ticket = false; |
593 | | |
594 | | // If tickets are disabled, always behave as if no tickets are present. |
595 | 7.85k | CBS ticket; |
596 | 7.85k | const bool tickets_supported = |
597 | 7.85k | !(SSL_get_options(hs->ssl) & SSL_OP_NO_TICKET) && |
598 | 7.85k | ssl_client_hello_get_extension(client_hello, &ticket, |
599 | 7.85k | TLSEXT_TYPE_session_ticket); |
600 | 7.85k | if (tickets_supported && CBS_len(&ticket) != 0) { |
601 | 913 | switch (ssl_process_ticket( |
602 | 913 | hs, &session, &renew_ticket, ticket, |
603 | 913 | Span(client_hello->session_id, client_hello->session_id_len), |
604 | 913 | /*save_ticket=*/false)) { |
605 | 324 | case ssl_ticket_aead_success: |
606 | 324 | break; |
607 | 589 | case ssl_ticket_aead_ignore_ticket: |
608 | 589 | assert(!session); |
609 | 589 | break; |
610 | 589 | case ssl_ticket_aead_error: |
611 | 0 | return ssl_hs_error; |
612 | 0 | case ssl_ticket_aead_retry: |
613 | 0 | return ssl_hs_pending_ticket; |
614 | 913 | } |
615 | 6.93k | } else { |
616 | | // The client didn't send a ticket, so the session ID is a real ID. |
617 | 6.93k | enum ssl_hs_wait_t lookup_ret = ssl_lookup_session( |
618 | 6.93k | hs, &session, |
619 | 6.93k | Span(client_hello->session_id, client_hello->session_id_len)); |
620 | 6.93k | if (lookup_ret != ssl_hs_ok) { |
621 | 0 | return lookup_ret; |
622 | 0 | } |
623 | 6.93k | } |
624 | | |
625 | 7.85k | *out_session = std::move(session); |
626 | 7.85k | *out_tickets_supported = tickets_supported; |
627 | 7.85k | *out_renew_ticket = renew_ticket; |
628 | 7.85k | return ssl_hs_ok; |
629 | 7.85k | } |
630 | | |
631 | 91 | static bool remove_session(SSLContext *ctx, SSL_SESSION *session, bool lock) { |
632 | 91 | if (session == nullptr || session->session_id.empty()) { |
633 | 0 | return false; |
634 | 0 | } |
635 | | |
636 | 91 | if (lock) { |
637 | 91 | ctx->lock.LockWrite(); |
638 | 91 | } |
639 | | |
640 | 91 | SSL_SESSION *found_session = lh_SSL_SESSION_retrieve(ctx->sessions, session); |
641 | 91 | bool found = found_session == session; |
642 | 91 | if (found) { |
643 | 91 | found_session = lh_SSL_SESSION_delete(ctx->sessions, session); |
644 | 91 | SSL_SESSION_list_remove(ctx, session); |
645 | 91 | } |
646 | | |
647 | 91 | if (lock) { |
648 | 91 | ctx->lock.UnlockWrite(); |
649 | 91 | } |
650 | | |
651 | 91 | if (found) { |
652 | | // TODO(https://crbug.com/boringssl/251): Callbacks should not be called |
653 | | // under a lock. |
654 | 91 | if (ctx->remove_session_cb != nullptr) { |
655 | 0 | ctx->remove_session_cb(ctx, found_session); |
656 | 0 | } |
657 | 91 | SSL_SESSION_free(found_session); |
658 | 91 | } |
659 | | |
660 | 91 | return found; |
661 | 91 | } |
662 | | |
663 | 168k | void ssl_set_session(SSL *ssl, SSL_SESSION *session) { |
664 | 168k | if (ssl->session.get() == session) { |
665 | 113k | return; |
666 | 113k | } |
667 | | |
668 | 55.2k | ssl->session = UpRef(session); |
669 | 55.2k | } |
670 | | |
671 | | // locked by SSL_CTX in the calling function |
672 | 61.3k | static void SSL_SESSION_list_remove(SSLContext *ctx, SSL_SESSION *session) { |
673 | 61.3k | if (session->next == nullptr || session->prev == nullptr) { |
674 | 0 | return; |
675 | 0 | } |
676 | | |
677 | 61.3k | if (session->next == (SSL_SESSION *)&ctx->session_cache_tail) { |
678 | | // last element in list |
679 | 21.0k | if (session->prev == (SSL_SESSION *)&ctx->session_cache_head) { |
680 | | // only one element in list |
681 | 14.8k | ctx->session_cache_head = nullptr; |
682 | 14.8k | ctx->session_cache_tail = nullptr; |
683 | 14.8k | } else { |
684 | 6.19k | ctx->session_cache_tail = session->prev; |
685 | 6.19k | session->prev->next = (SSL_SESSION *)&(ctx->session_cache_tail); |
686 | 6.19k | } |
687 | 40.3k | } else { |
688 | 40.3k | if (session->prev == (SSL_SESSION *)&ctx->session_cache_head) { |
689 | | // first element in list |
690 | 21.3k | ctx->session_cache_head = session->next; |
691 | 21.3k | session->next->prev = (SSL_SESSION *)&(ctx->session_cache_head); |
692 | 21.3k | } else { // middle of list |
693 | 18.9k | session->next->prev = session->prev; |
694 | 18.9k | session->prev->next = session->next; |
695 | 18.9k | } |
696 | 40.3k | } |
697 | 61.3k | session->prev = session->next = nullptr; |
698 | 61.3k | } |
699 | | |
700 | 61.3k | static void SSL_SESSION_list_add(SSLContext *ctx, SSL_SESSION *session) { |
701 | 61.3k | if (session->next != nullptr && session->prev != nullptr) { |
702 | 0 | SSL_SESSION_list_remove(ctx, session); |
703 | 0 | } |
704 | | |
705 | 61.3k | if (ctx->session_cache_head == nullptr) { |
706 | 14.8k | ctx->session_cache_head = session; |
707 | 14.8k | ctx->session_cache_tail = session; |
708 | 14.8k | session->prev = (SSL_SESSION *)&(ctx->session_cache_head); |
709 | 14.8k | session->next = (SSL_SESSION *)&(ctx->session_cache_tail); |
710 | 46.4k | } else { |
711 | 46.4k | session->next = ctx->session_cache_head; |
712 | 46.4k | session->next->prev = session; |
713 | 46.4k | session->prev = (SSL_SESSION *)&(ctx->session_cache_head); |
714 | 46.4k | ctx->session_cache_head = session; |
715 | 46.4k | } |
716 | 61.3k | } |
717 | | |
718 | | static bool add_session_locked(SSLContext *ctx, |
719 | 61.3k | UniquePtr<SSL_SESSION> session) { |
720 | 61.3k | SSL_SESSION *new_session = session.get(); |
721 | 61.3k | SSL_SESSION *old_session; |
722 | 61.3k | if (!lh_SSL_SESSION_insert(ctx->sessions, &old_session, new_session)) { |
723 | 0 | return false; |
724 | 0 | } |
725 | | // `ctx->sessions` took ownership of `new_session` and gave us back a |
726 | | // reference to `old_session`. (`old_session` may be the same as |
727 | | // `new_session`, in which case we traded identical references with |
728 | | // `ctx->sessions`.) |
729 | 61.3k | session.release(); |
730 | 61.3k | session.reset(old_session); |
731 | | |
732 | 61.3k | if (old_session != nullptr) { |
733 | 49.3k | if (old_session == new_session) { |
734 | | // `session` was already in the cache. There are no linked list pointers |
735 | | // to update. |
736 | 0 | return false; |
737 | 0 | } |
738 | | |
739 | | // There was a session ID collision. `old_session` was replaced with |
740 | | // `session` in the hash table, so `old_session` must be removed from the |
741 | | // linked list to match. |
742 | 49.3k | SSL_SESSION_list_remove(ctx, old_session); |
743 | 49.3k | } |
744 | | |
745 | | // This does not increment the reference count. Although `session` is inserted |
746 | | // into two structures (a doubly-linked list and the hash table), `ctx` only |
747 | | // takes one reference. |
748 | 61.3k | SSL_SESSION_list_add(ctx, new_session); |
749 | | |
750 | | // Enforce any cache size limits. |
751 | 61.3k | if (SSL_CTX_sess_get_cache_size(ctx) > 0) { |
752 | 61.3k | while (lh_SSL_SESSION_num_items(ctx->sessions) > |
753 | 61.3k | SSL_CTX_sess_get_cache_size(ctx)) { |
754 | 0 | if (!remove_session(ctx, ctx->session_cache_tail, |
755 | 0 | /*lock=*/false)) { |
756 | 0 | break; |
757 | 0 | } |
758 | 0 | } |
759 | 61.3k | } |
760 | | |
761 | 61.3k | return true; |
762 | 61.3k | } |
763 | | |
764 | 41.9k | void ssl_update_cache(SSL *ssl) { |
765 | 41.9k | SSLContext *ctx = ssl->session_ctx.get(); |
766 | 41.9k | SSL_SESSION *session = ssl->s3->established_session.get(); |
767 | 41.9k | int mode = SSL_is_server(ssl) ? SSL_SESS_CACHE_SERVER : SSL_SESS_CACHE_CLIENT; |
768 | 41.9k | if (!SSL_SESSION_is_resumable(session) || |
769 | 41.7k | (ctx->session_cache_mode & mode) != mode) { |
770 | 41.7k | return; |
771 | 41.7k | } |
772 | | |
773 | | // Clients never use the internal session cache. |
774 | 151 | if (ssl->server && |
775 | 151 | !(ctx->session_cache_mode & SSL_SESS_CACHE_NO_INTERNAL_STORE)) { |
776 | 151 | UniquePtr<SSL_SESSION> ref = UpRef(session); |
777 | 151 | bool remove_expired_sessions = false; |
778 | 151 | { |
779 | 151 | MutexWriteLock lock(&ctx->lock); |
780 | 151 | add_session_locked(ctx, std::move(ref)); |
781 | | |
782 | 151 | if (!(ctx->session_cache_mode & SSL_SESS_CACHE_NO_AUTO_CLEAR)) { |
783 | | // Automatically flush the internal session cache every 255 connections. |
784 | 151 | ctx->handshakes_since_cache_flush++; |
785 | 151 | if (ctx->handshakes_since_cache_flush >= 255) { |
786 | 0 | remove_expired_sessions = true; |
787 | 0 | ctx->handshakes_since_cache_flush = 0; |
788 | 0 | } |
789 | 151 | } |
790 | 151 | } |
791 | | |
792 | 151 | if (remove_expired_sessions) { |
793 | | // `SSL_CTX_flush_sessions` takes the lock we just released. We could |
794 | | // merge the critical sections, but we'd then call user code under a |
795 | | // lock, or compute `now` earlier, even when not flushing. |
796 | 0 | OPENSSL_timeval now = ssl_ctx_get_current_time(ssl->ctx.get()); |
797 | 0 | SSL_CTX_flush_sessions(ctx, now.tv_sec); |
798 | 0 | } |
799 | 151 | } |
800 | | |
801 | 151 | if (ctx->new_session_cb != nullptr) { |
802 | 0 | UniquePtr<SSL_SESSION> ref = UpRef(session); |
803 | 0 | if (ctx->new_session_cb(ssl, ref.get())) { |
804 | | // `new_session_cb`'s return value signals whether it took ownership. |
805 | 0 | ref.release(); |
806 | 0 | } |
807 | 0 | } |
808 | 151 | } |
809 | | |
810 | 129k | bool ssl_session_has_peer_cred(const SSL_SESSION *session) { |
811 | 129k | return sk_CRYPTO_BUFFER_num(SSL_SESSION_get0_peer_certificates(session)) > |
812 | 129k | 0 || |
813 | 4.10k | SSL_SESSION_get0_peer_rpk(session) != nullptr || |
814 | 4.10k | session->peer_sha256_valid; |
815 | 129k | } |
816 | | |
817 | | BSSL_NAMESPACE_END |
818 | | |
819 | | using namespace bssl; |
820 | | |
821 | | ssl_session_st::ssl_session_st(const SSL_X509_METHOD *method) |
822 | 241k | : RefCounted(CheckSubClass()), |
823 | 241k | x509_method(method), |
824 | 241k | extended_master_secret(false), |
825 | 241k | peer_sha256_valid(false), |
826 | 241k | not_resumable(false), |
827 | 241k | ticket_age_add_valid(false), |
828 | 241k | is_server(false), |
829 | 241k | is_quic(false), |
830 | 241k | has_application_settings(false), |
831 | 241k | is_resumable_across_names(false) { |
832 | 241k | CRYPTO_new_ex_data(&ex_data); |
833 | 241k | time = ::time(nullptr); |
834 | 241k | } |
835 | | |
836 | 241k | ssl_session_st::~ssl_session_st() { |
837 | 241k | CRYPTO_free_ex_data(&g_ex_data_class, &ex_data); |
838 | 241k | x509_method->session_clear(this); |
839 | 241k | } |
840 | | |
841 | 0 | SSL_SESSION *SSL_SESSION_new(const SSL_CTX *ctx) { |
842 | 0 | return ssl_session_new(FromOpaque(ctx)->x509_method).release(); |
843 | 0 | } |
844 | | |
845 | 116k | int SSL_SESSION_up_ref(SSL_SESSION *session) { |
846 | 116k | session->UpRefInternal(); |
847 | 116k | return 1; |
848 | 116k | } |
849 | | |
850 | 358k | void SSL_SESSION_free(SSL_SESSION *session) { |
851 | 358k | if (session == nullptr) { |
852 | 0 | return; |
853 | 0 | } |
854 | 358k | session->DecRefInternal(); |
855 | 358k | } |
856 | | |
857 | | const uint8_t *SSL_SESSION_get_id(const SSL_SESSION *session, |
858 | 0 | unsigned *out_len) { |
859 | 0 | if (out_len != nullptr) { |
860 | 0 | *out_len = session->session_id.size(); |
861 | 0 | } |
862 | 0 | return session->session_id.data(); |
863 | 0 | } |
864 | | |
865 | | int SSL_SESSION_set1_id(SSL_SESSION *session, const uint8_t *sid, |
866 | 0 | size_t sid_len) { |
867 | 0 | if (!session->session_id.TryCopyFrom(Span(sid, sid_len))) { |
868 | 0 | OPENSSL_PUT_ERROR(SSL, SSL_R_SSL_SESSION_ID_TOO_LONG); |
869 | 0 | return 0; |
870 | 0 | } |
871 | | |
872 | 0 | return 1; |
873 | 0 | } |
874 | | |
875 | 0 | uint32_t SSL_SESSION_get_timeout(const SSL_SESSION *session) { |
876 | 0 | return session->timeout; |
877 | 0 | } |
878 | | |
879 | 0 | uint64_t SSL_SESSION_get_time(const SSL_SESSION *session) { |
880 | 0 | if (session == nullptr) { |
881 | | // NULL should crash, but silently accept it here for compatibility. |
882 | 0 | return 0; |
883 | 0 | } |
884 | 0 | return session->time; |
885 | 0 | } |
886 | | |
887 | 0 | X509 *SSL_SESSION_get0_peer(const SSL_SESSION *session) { |
888 | 0 | return session->x509_peer; |
889 | 0 | } |
890 | | |
891 | | const STACK_OF(CRYPTO_BUFFER) *SSL_SESSION_get0_peer_certificates( |
892 | 129k | const SSL_SESSION *session) { |
893 | 129k | return session->certs.get(); |
894 | 129k | } |
895 | | |
896 | 4.10k | EVP_PKEY *SSL_SESSION_get0_peer_rpk(const SSL_SESSION *session) { |
897 | 4.10k | return session->peer_raw_public_key.get(); |
898 | 4.10k | } |
899 | | |
900 | | void SSL_SESSION_get0_signed_cert_timestamp_list(const SSL_SESSION *session, |
901 | | const uint8_t **out, |
902 | 0 | size_t *out_len) { |
903 | 0 | if (session->signed_cert_timestamp_list) { |
904 | 0 | *out = CRYPTO_BUFFER_data(session->signed_cert_timestamp_list.get()); |
905 | 0 | *out_len = CRYPTO_BUFFER_len(session->signed_cert_timestamp_list.get()); |
906 | 0 | } else { |
907 | 0 | *out = nullptr; |
908 | 0 | *out_len = 0; |
909 | 0 | } |
910 | 0 | } |
911 | | |
912 | | void SSL_SESSION_get0_ocsp_response(const SSL_SESSION *session, |
913 | 0 | const uint8_t **out, size_t *out_len) { |
914 | 0 | if (session->ocsp_response) { |
915 | 0 | *out = CRYPTO_BUFFER_data(session->ocsp_response.get()); |
916 | 0 | *out_len = CRYPTO_BUFFER_len(session->ocsp_response.get()); |
917 | 0 | } else { |
918 | 0 | *out = nullptr; |
919 | 0 | *out_len = 0; |
920 | 0 | } |
921 | 0 | } |
922 | | |
923 | | size_t SSL_SESSION_get_master_key(const SSL_SESSION *session, uint8_t *out, |
924 | 0 | size_t max_out) { |
925 | 0 | if (max_out == 0) { |
926 | 0 | return session->secret.size(); |
927 | 0 | } |
928 | 0 | if (max_out > session->secret.size()) { |
929 | 0 | max_out = session->secret.size(); |
930 | 0 | } |
931 | 0 | OPENSSL_memcpy(out, session->secret.data(), max_out); |
932 | 0 | return max_out; |
933 | 0 | } |
934 | | |
935 | 0 | uint64_t SSL_SESSION_set_time(SSL_SESSION *session, uint64_t time) { |
936 | 0 | if (session == nullptr) { |
937 | 0 | return 0; |
938 | 0 | } |
939 | | |
940 | 0 | session->time = time; |
941 | 0 | return time; |
942 | 0 | } |
943 | | |
944 | 0 | uint32_t SSL_SESSION_set_timeout(SSL_SESSION *session, uint32_t timeout) { |
945 | 0 | if (session == nullptr) { |
946 | 0 | return 0; |
947 | 0 | } |
948 | | |
949 | 0 | session->timeout = timeout; |
950 | 0 | session->auth_timeout = timeout; |
951 | 0 | return 1; |
952 | 0 | } |
953 | | |
954 | | const uint8_t *SSL_SESSION_get0_id_context(const SSL_SESSION *session, |
955 | 0 | unsigned *out_len) { |
956 | 0 | if (out_len != nullptr) { |
957 | 0 | *out_len = session->sid_ctx.size(); |
958 | 0 | } |
959 | 0 | return session->sid_ctx.data(); |
960 | 0 | } |
961 | | |
962 | | int SSL_SESSION_set1_id_context(SSL_SESSION *session, const uint8_t *sid_ctx, |
963 | 0 | size_t sid_ctx_len) { |
964 | 0 | if (!session->sid_ctx.TryCopyFrom(Span(sid_ctx, sid_ctx_len))) { |
965 | 0 | OPENSSL_PUT_ERROR(SSL, SSL_R_SSL_SESSION_ID_CONTEXT_TOO_LONG); |
966 | 0 | return 0; |
967 | 0 | } |
968 | | |
969 | 0 | return 1; |
970 | 0 | } |
971 | | |
972 | 0 | int SSL_SESSION_should_be_single_use(const SSL_SESSION *session) { |
973 | 0 | return ssl_session_protocol_version(session) >= TLS1_3_VERSION; |
974 | 0 | } |
975 | | |
976 | 41.9k | int SSL_SESSION_is_resumable(const SSL_SESSION *session) { |
977 | 41.9k | return ssl_session_get_type(session) != SSLSessionType::kNotResumable; |
978 | 41.9k | } |
979 | | |
980 | 0 | int SSL_SESSION_has_ticket(const SSL_SESSION *session) { |
981 | 0 | return !session->ticket.empty(); |
982 | 0 | } |
983 | | |
984 | | void SSL_SESSION_get0_ticket(const SSL_SESSION *session, |
985 | 0 | const uint8_t **out_ticket, size_t *out_len) { |
986 | 0 | if (out_ticket != nullptr) { |
987 | 0 | *out_ticket = session->ticket.data(); |
988 | 0 | } |
989 | 0 | *out_len = session->ticket.size(); |
990 | 0 | } |
991 | | |
992 | | int SSL_SESSION_set_ticket(SSL_SESSION *session, const uint8_t *ticket, |
993 | 0 | size_t ticket_len) { |
994 | 0 | return session->ticket.CopyFrom(Span(ticket, ticket_len)); |
995 | 0 | } |
996 | | |
997 | 0 | uint32_t SSL_SESSION_get_ticket_lifetime_hint(const SSL_SESSION *session) { |
998 | 0 | return session->ticket_lifetime_hint; |
999 | 0 | } |
1000 | | |
1001 | 0 | const SSL_CIPHER *SSL_SESSION_get0_cipher(const SSL_SESSION *session) { |
1002 | 0 | return session->cipher; |
1003 | 0 | } |
1004 | | |
1005 | 0 | int SSL_SESSION_has_peer_sha256(const SSL_SESSION *session) { |
1006 | 0 | return session->peer_sha256_valid; |
1007 | 0 | } |
1008 | | |
1009 | | void SSL_SESSION_get0_peer_sha256(const SSL_SESSION *session, |
1010 | 0 | const uint8_t **out_ptr, size_t *out_len) { |
1011 | 0 | if (session->peer_sha256_valid) { |
1012 | 0 | *out_ptr = session->peer_sha256; |
1013 | 0 | *out_len = sizeof(session->peer_sha256); |
1014 | 0 | } else { |
1015 | 0 | *out_ptr = nullptr; |
1016 | 0 | *out_len = 0; |
1017 | 0 | } |
1018 | 0 | } |
1019 | | |
1020 | 0 | int SSL_SESSION_is_resumable_across_names(const SSL_SESSION *session) { |
1021 | 0 | return session->is_resumable_across_names; |
1022 | 0 | } |
1023 | | |
1024 | 0 | int SSL_SESSION_early_data_capable(const SSL_SESSION *session) { |
1025 | 0 | return ssl_session_protocol_version(session) >= TLS1_3_VERSION && |
1026 | 0 | session->ticket_max_early_data != 0; |
1027 | 0 | } |
1028 | | |
1029 | 0 | SSL_SESSION *SSL_SESSION_copy_without_early_data(SSL_SESSION *session) { |
1030 | 0 | if (!SSL_SESSION_early_data_capable(session)) { |
1031 | 0 | return UpRef(session).release(); |
1032 | 0 | } |
1033 | | |
1034 | 0 | bssl::UniquePtr<SSL_SESSION> copy = |
1035 | 0 | SSL_SESSION_dup(session, SSL_SESSION_DUP_ALL); |
1036 | 0 | if (!copy) { |
1037 | 0 | return nullptr; |
1038 | 0 | } |
1039 | | |
1040 | 0 | copy->ticket_max_early_data = 0; |
1041 | | // Copied sessions are non-resumable until they're completely filled in. |
1042 | 0 | copy->not_resumable = session->not_resumable; |
1043 | 0 | assert(!SSL_SESSION_early_data_capable(copy.get())); |
1044 | 0 | return copy.release(); |
1045 | 0 | } |
1046 | | |
1047 | 0 | SSL_SESSION *SSL_magic_pending_session_ptr() { |
1048 | 0 | return (SSL_SESSION *)&g_pending_session_magic; |
1049 | 0 | } |
1050 | | |
1051 | 37.1k | SSL_SESSION *SSL_get_session(const SSL *ssl) { |
1052 | | // Once the initially handshake completes, we return the most recently |
1053 | | // established session. In particular, if there is a pending renegotiation, we |
1054 | | // do not return information about it until it completes. |
1055 | | // |
1056 | | // Code in the handshake must either use `hs->new_session` (if updating a |
1057 | | // partial session) or `ssl_handshake_session` (if trying to query properties |
1058 | | // consistently across TLS 1.2 resumption and other handshakes). |
1059 | 37.1k | if (ssl->s3->established_session != nullptr) { |
1060 | 37.1k | return ssl->s3->established_session.get(); |
1061 | 37.1k | } |
1062 | | |
1063 | | // Otherwise, we must be in the initial handshake. |
1064 | 0 | SSL_HANDSHAKE *hs = ssl->s3->hs.get(); |
1065 | 0 | assert(hs != nullptr); |
1066 | 0 | assert(!ssl->s3->initial_handshake_complete); |
1067 | | |
1068 | | // Return the 0-RTT session, if in the 0-RTT state. While the handshake has |
1069 | | // not actually completed, the public accessors all report properties as if |
1070 | | // it has. |
1071 | 0 | if (hs->early_session) { |
1072 | 0 | return hs->early_session.get(); |
1073 | 0 | } |
1074 | | |
1075 | | // Otherwise, return the partial session. |
1076 | 0 | return (SSL_SESSION *)ssl_handshake_session(hs); |
1077 | 0 | } |
1078 | | |
1079 | 0 | SSL_SESSION *SSL_get1_session(SSL *ssl) { |
1080 | 0 | SSL_SESSION *ret = SSL_get_session(ssl); |
1081 | 0 | if (ret != nullptr) { |
1082 | 0 | SSL_SESSION_up_ref(ret); |
1083 | 0 | } |
1084 | 0 | return ret; |
1085 | 0 | } |
1086 | | |
1087 | | int SSL_SESSION_get_ex_new_index(long argl, void *argp, |
1088 | | CRYPTO_EX_unused *unused, |
1089 | | CRYPTO_EX_dup *dup_unused, |
1090 | 0 | CRYPTO_EX_free *free_func) { |
1091 | 0 | return CRYPTO_get_ex_new_index_ex(&g_ex_data_class, argl, argp, free_func); |
1092 | 0 | } |
1093 | | |
1094 | 0 | int SSL_SESSION_set_ex_data(SSL_SESSION *session, int idx, void *arg) { |
1095 | 0 | return CRYPTO_set_ex_data(&session->ex_data, idx, arg); |
1096 | 0 | } |
1097 | | |
1098 | 0 | void *SSL_SESSION_get_ex_data(const SSL_SESSION *session, int idx) { |
1099 | 0 | return CRYPTO_get_ex_data(&session->ex_data, idx); |
1100 | 0 | } |
1101 | | |
1102 | 61.2k | int SSL_CTX_add_session(SSL_CTX *ctx, SSL_SESSION *session) { |
1103 | 61.2k | auto *ctx_impl = FromOpaque(ctx); |
1104 | 61.2k | UniquePtr<SSL_SESSION> owned_session = UpRef(session); |
1105 | 61.2k | MutexWriteLock lock(&ctx_impl->lock); |
1106 | 61.2k | return add_session_locked(ctx_impl, std::move(owned_session)); |
1107 | 61.2k | } |
1108 | | |
1109 | 91 | int SSL_CTX_remove_session(SSL_CTX *ctx, SSL_SESSION *session) { |
1110 | 91 | return remove_session(FromOpaque(ctx), session, /*lock=*/true); |
1111 | 91 | } |
1112 | | |
1113 | 54.1k | int SSL_set_session(SSL *ssl, SSL_SESSION *session) { |
1114 | | // SSL_set_session may only be called before the handshake has started. |
1115 | 54.1k | if (ssl->s3->initial_handshake_complete || // |
1116 | 54.1k | ssl->s3->hs == nullptr || // |
1117 | 54.1k | ssl->s3->hs->state != 0) { |
1118 | 0 | abort(); |
1119 | 0 | } |
1120 | | |
1121 | 54.1k | ssl_set_session(ssl, session); |
1122 | 54.1k | return 1; |
1123 | 54.1k | } |
1124 | | |
1125 | 0 | uint32_t SSL_CTX_set_timeout(SSL_CTX *ctx, uint32_t timeout) { |
1126 | 0 | if (ctx == nullptr) { |
1127 | 0 | return 0; |
1128 | 0 | } |
1129 | | |
1130 | | // Historically, zero was treated as `SSL_DEFAULT_SESSION_TIMEOUT`. |
1131 | 0 | if (timeout == 0) { |
1132 | 0 | timeout = SSL_DEFAULT_SESSION_TIMEOUT; |
1133 | 0 | } |
1134 | |
|
1135 | 0 | return std::exchange(FromOpaque(ctx)->session_timeout, timeout); |
1136 | 0 | } |
1137 | | |
1138 | 0 | uint32_t SSL_CTX_get_timeout(const SSL_CTX *ctx) { |
1139 | 0 | if (ctx == nullptr) { |
1140 | 0 | return 0; |
1141 | 0 | } |
1142 | | |
1143 | 0 | return FromOpaque(ctx)->session_timeout; |
1144 | 0 | } |
1145 | | |
1146 | 0 | void SSL_CTX_set_session_psk_dhe_timeout(SSL_CTX *ctx, uint32_t timeout) { |
1147 | 0 | FromOpaque(ctx)->session_psk_dhe_timeout = timeout; |
1148 | 0 | } |
1149 | | |
1150 | | typedef struct timeout_param_st { |
1151 | | SSLContext *ctx; |
1152 | | uint64_t time; |
1153 | | LHASH_OF(SSL_SESSION) *cache; |
1154 | | } TIMEOUT_PARAM; |
1155 | | |
1156 | 11.9k | static void timeout_doall_arg(SSL_SESSION *session, void *void_param) { |
1157 | 11.9k | TIMEOUT_PARAM *param = reinterpret_cast<TIMEOUT_PARAM *>(void_param); |
1158 | | |
1159 | 11.9k | if (param->time == 0 || // |
1160 | 0 | session->time + session->timeout < session->time || // |
1161 | 11.9k | param->time > (session->time + session->timeout)) { |
1162 | | // TODO(davidben): This can probably just call `remove_session`. |
1163 | 11.9k | (void)lh_SSL_SESSION_delete(param->cache, session); |
1164 | 11.9k | SSL_SESSION_list_remove(param->ctx, session); |
1165 | | // TODO(https://crbug.com/boringssl/251): Callbacks should not be called |
1166 | | // under a lock. |
1167 | 11.9k | if (param->ctx->remove_session_cb != nullptr) { |
1168 | 0 | param->ctx->remove_session_cb(param->ctx, session); |
1169 | 0 | } |
1170 | 11.9k | SSL_SESSION_free(session); |
1171 | 11.9k | } |
1172 | 11.9k | } |
1173 | | |
1174 | 65.3k | void SSL_CTX_flush_sessions(SSL_CTX *ctx, uint64_t time) { |
1175 | 65.3k | auto *ctx_impl = FromOpaque(ctx); |
1176 | 65.3k | TIMEOUT_PARAM tp; |
1177 | 65.3k | tp.ctx = ctx_impl; |
1178 | 65.3k | tp.cache = ctx_impl->sessions; |
1179 | 65.3k | if (tp.cache == nullptr) { |
1180 | 0 | return; |
1181 | 0 | } |
1182 | 65.3k | tp.time = time; |
1183 | 65.3k | MutexWriteLock lock(&ctx_impl->lock); |
1184 | 65.3k | lh_SSL_SESSION_doall_arg(tp.cache, timeout_doall_arg, &tp); |
1185 | 65.3k | } |
1186 | | |
1187 | | void SSL_CTX_sess_set_new_cb(SSL_CTX *ctx, |
1188 | 0 | int (*cb)(SSL *ssl, SSL_SESSION *session)) { |
1189 | 0 | FromOpaque(ctx)->new_session_cb = cb; |
1190 | 0 | } |
1191 | | |
1192 | 0 | int (*SSL_CTX_sess_get_new_cb(SSL_CTX *ctx))(SSL *ssl, SSL_SESSION *session) { |
1193 | 0 | return FromOpaque(ctx)->new_session_cb; |
1194 | 0 | } |
1195 | | |
1196 | | void SSL_CTX_sess_set_remove_cb(SSL_CTX *ctx, |
1197 | | void (*cb)(SSL_CTX *ctx, |
1198 | 0 | SSL_SESSION *session)) { |
1199 | 0 | FromOpaque(ctx)->remove_session_cb = cb; |
1200 | 0 | } |
1201 | | |
1202 | | void (*SSL_CTX_sess_get_remove_cb(SSL_CTX *ctx))(SSL_CTX *ctx, |
1203 | 0 | SSL_SESSION *session) { |
1204 | 0 | return FromOpaque(ctx)->remove_session_cb; |
1205 | 0 | } |
1206 | | |
1207 | | void SSL_CTX_sess_set_get_cb(SSL_CTX *ctx, |
1208 | | SSL_SESSION *(*cb)(SSL *ssl, const uint8_t *id, |
1209 | 0 | int id_len, int *out_copy)) { |
1210 | 0 | FromOpaque(ctx)->get_session_cb = cb; |
1211 | 0 | } |
1212 | | |
1213 | | SSL_SESSION *(*SSL_CTX_sess_get_get_cb(SSL_CTX *ctx))(SSL *ssl, |
1214 | | const uint8_t *id, |
1215 | | int id_len, |
1216 | 0 | int *out_copy) { |
1217 | 0 | return FromOpaque(ctx)->get_session_cb; |
1218 | 0 | } |
1219 | | |
1220 | 0 | void SSL_CTX_set_resumption_across_names_enabled(SSL_CTX *ctx, int enabled) { |
1221 | 0 | FromOpaque(ctx)->resumption_across_names_enabled = !!enabled; |
1222 | 0 | } |
1223 | | |
1224 | 0 | void SSL_set_resumption_across_names_enabled(SSL *ssl, int enabled) { |
1225 | 0 | ssl->resumption_across_names_enabled = !!enabled; |
1226 | 0 | } |
1227 | | |
1228 | | void SSL_CTX_set_info_callback(SSL_CTX *ctx, void (*cb)(const SSL *ssl, |
1229 | 0 | int type, int value)) { |
1230 | 0 | FromOpaque(ctx)->info_callback = cb; |
1231 | 0 | } |
1232 | | |
1233 | | void (*SSL_CTX_get_info_callback(SSL_CTX *ctx))(const SSL *ssl, int type, |
1234 | 0 | int value) { |
1235 | 0 | return FromOpaque(ctx)->info_callback; |
1236 | 0 | } |