lib: TLS session ticket caching reworked

Described in detail in internal doc TLS-SESSIONS.md

Main points:
- use a new `ssl_peer_key` for cache lookups by connection filters
- recognize differences between TLSv1.3 and other tickets
  * TLSv1.3 tickets are single-use, cache can hold several of them for a peer
  * TLSv1.2 are reused, keep only a single one per peer
- differentiate between ticket BLOB to store (that could be persisted) and object instances
- use put/take/return pattern for cache access
- remember TLS version, ALPN protocol, time received and lifetime of ticket
- auto-expire tickets after their lifetime

Closes #15774
This commit is contained in:
Stefan Eissing 2024-12-18 13:22:35 +01:00 committed by Daniel Stenberg
parent e5e2e09a75
commit fa0ccd9f1f
No known key found for this signature in database
GPG key ID: 5CC908FDB71E12C2
36 changed files with 1784 additions and 780 deletions

View file

@ -38,6 +38,7 @@
#include "multiif.h"
#include "strcase.h"
#include "x509asn1.h"
#include "vtls_scache.h"
#include "strerror.h"
#include "cipher_suite.h"
@ -1020,7 +1021,7 @@ failed:
return ret;
}
static void sectransp_session_free(void *sessionid, size_t idsize)
static void sectransp_session_free(void *sessionid)
{
/* ST, as of iOS 5 and Mountain Lion, has no public method of deleting a
cached session ID inside the Security framework. There is a private
@ -1028,7 +1029,6 @@ static void sectransp_session_free(void *sessionid, size_t idsize)
got your application rejected from the App Store due to the use of a
private API, so the best we can do is free up our own char array that we
created way back in sectransp_connect_step1... */
(void)idsize;
Curl_safefree(sessionid);
}
@ -1337,19 +1337,19 @@ static CURLcode sectransp_connect_step1(struct Curl_cfilter *cf,
char *ssl_sessionid;
size_t ssl_sessionid_len;
Curl_ssl_sessionid_lock(data);
if(!Curl_ssl_getsessionid(cf, data, &connssl->peer,
(void **)&ssl_sessionid, &ssl_sessionid_len,
NULL)) {
Curl_ssl_scache_lock(data);
if(Curl_ssl_scache_get_obj(cf, data, connssl->peer.scache_key,
(void **)&ssl_sessionid)) {
/* we got a session id, use it! */
err = SSLSetPeerID(backend->ssl_ctx, ssl_sessionid, ssl_sessionid_len);
Curl_ssl_sessionid_unlock(data);
err = SSLSetPeerID(backend->ssl_ctx, ssl_sessionid,
strlen(ssl_sessionid));
Curl_ssl_scache_unlock(data);
if(err != noErr) {
failf(data, "SSL: SSLSetPeerID() failed: OSStatus %d", err);
return CURLE_SSL_CONNECT_ERROR;
}
/* Informational message */
infof(data, "SSL reusing session ID");
else
infof(data, "SSL reusing session ID");
}
/* If there is not one, then let's make one up! This has to be done prior
to starting the handshake. */
@ -1363,15 +1363,17 @@ static CURLcode sectransp_connect_step1(struct Curl_cfilter *cf,
err = SSLSetPeerID(backend->ssl_ctx, ssl_sessionid, ssl_sessionid_len);
if(err != noErr) {
Curl_ssl_sessionid_unlock(data);
Curl_ssl_scache_unlock(data);
failf(data, "SSL: SSLSetPeerID() failed: OSStatus %d", err);
return CURLE_SSL_CONNECT_ERROR;
}
result = Curl_ssl_set_sessionid(cf, data, &connssl->peer, NULL,
ssl_sessionid, ssl_sessionid_len,
/* This is all a bit weird, as we have not handshaked yet.
* I hope this backend will go away soon. */
result = Curl_ssl_scache_add_obj(cf, data, connssl->peer.scache_key,
(void *)ssl_sessionid,
sectransp_session_free);
Curl_ssl_sessionid_unlock(data);
Curl_ssl_scache_unlock(data);
if(result)
return result;
}