From 7eb72c04d096089fc369128b1ac8583419d098e0 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jaakko=20Kera=CC=88nen?= jaakko.keranen@iki.fi
Date: Tue, 1 Mar 2022 12:36:28 +0200
Subject: [PATCH 1/1] TlsRequest: Session cache; X509 chain copying
Sessions are now cached for 10 minutes, to avoid repeated handshakes on frequent connections.
There was a problem with duplicating X509 chains: while the stack was duplicated, the contained X509 certs were not. This made it possible that certs in a copied stack had been released when they were needed later.
src/tlsrequest.c | 153 ++++++++++++++++++++++++++++++++++++++++-------
1 file changed, 132 insertions(+), 21 deletions(-)
diff --git a/src/tlsrequest.c b/src/tlsrequest.c
index 22fb215..943a493 100644
--- a/src/tlsrequest.c
+++ b/src/tlsrequest.c
@@ -28,6 +28,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "the_Foundation/tlsrequest.h"
#include "the_Foundation/buffer.h"
#include "the_Foundation/socket.h"
+#include "the_Foundation/stringhash.h"
#include "the_Foundation/thread.h"
#include "the_Foundation/time.h"
@@ -53,13 +54,120 @@ static void initContext_(void);
static iTlsCertificate *newX509Chain_TlsCertificate_(X509 *cert, STACK_OF(X509) *chain);
static void certificateVerifyFailed_TlsRequest_(iTlsRequest *, const iTlsCertificate *cert);
+static iBool readAllFromBIO_(BIO *bio, iBlock *out) {
n = BIO_read(bio, buf, sizeof(buf));
if (n > 0) {
appendData_Block(out, buf, n);
}
else if (!BIO_should_retry(bio)) {
return iFalse;
}
+}
+/----------------------------------------------------------------------------------------------/
+iDeclareClass(CachedSession)
+static const int maxSessionAge_CachedSession_ = 10 * 60; /* seconds */
+struct Impl_CachedSession {
+};
+static void init_CachedSession(iCachedSession *d, SSL_SESSION *sess, const iTlsCertificate *cert) {
+}
+static void deinit_CachedSession(iCachedSession *d) {
+}
+iDefineClass(CachedSession)
+iDefineObjectConstructionArgs(CachedSession,
(SSL_SESSION *sess, const iTlsCertificate *cert),
sess, cert)
+static void reuse_CachedSession(const iCachedSession *d, SSL *ssl) {
+}
struct Impl_Context {
SSL_CTX * ctx;
X509_STORE * certStore;
iTlsRequestVerifyFunc userVerifyFunc;
tss_t tssKeyCurrentRequest;
};
+static iString *cacheKey_(const iString *host, uint16_t port) {
+}
+static iBool isExpired_CachedSession_(const iCachedSession *d) {
+}
+static iTlsCertificate *maybeReuseSession_Context_(iContext *d, SSL *ssl, const iString *host,
uint16_t port) {
iCachedSession *cs = i.value->object;
if (isExpired_CachedSession_(cs)) {
iDebug("[TlsRequest] session for `%s` has expired\n", cstr_Block(&i.value->keyBlock));
remove_StringHashIterator(&i);
}
reuse_CachedSession(cs, ssl);
cert = copy_TlsCertificate(cs->cert);
iDebug("[TlsRequest] reusing session for `%s`\n", cstr_String(key));
+}
+static void saveSession_Context_(iContext *d, const iString *host, uint16_t port,
SSL_SESSION *sess, const iTlsCertificate *cert) {
iString *key = cacheKey_(host, port);
lock_Mutex(&d->cacheMutex);
insert_StringHash(d->cache, key, new_CachedSession(sess, cert));
unlock_Mutex(&d->cacheMutex);
iDebug("[TlsRequest] saved session for `%s`\n", cstr_String(key));
delete_String(key);
+}
static iTlsRequest *currentRequestForThread_Context_(iContext *d) {
return tss_get(context_->tssKeyCurrentRequest);
}
@@ -118,17 +226,22 @@ void init_Context(iContext *d) {
ERR_load_BIO_strings();
d->ctx = SSL_CTX_new(TLS_client_method());
if (!d->ctx) {
iDebug("[TlsRequest] Failed to initialize OpenSSL\n");
iDebug("[TlsRequest] failed to initialize OpenSSL\n");
iAssert(d->ctx);
}
d->userVerifyFunc = NULL;
SSL_CTX_set_verify(d->ctx, SSL_VERIFY_PEER, verifyCallback_Context_);
/* Bug workarounds: https://www.openssl.org/docs/manmaster/man3/SSL_CTX_set_options.html */
SSL_CTX_set_options(d->ctx, SSL_OP_ALL);
}
void deinit_Context(iContext *d) {
SSL_CTX_free(d->ctx);
tss_delete(d->tssKeyCurrentRequest);
}
@@ -137,6 +250,8 @@ iBool isValid_Context(iContext *d) {
return d->ctx != NULL;
}
+/----------------------------------------------------------------------------------------------/
void setCACertificates_TlsRequest(const iString *caFile, const iString *caPath) {
initContext_();
iContext *d = context_;
@@ -172,21 +287,6 @@ static void initContext_(void) {
}
}
-static iBool readAllFromBIO_(BIO *bio, iBlock *out) {
n = BIO_read(bio, buf, sizeof(buf));
if (n > 0) {
appendData_Block(out, buf, n);
}
else if (!BIO_should_retry(bio)) {
return iFalse;
}
-}
/----------------------------------------------------------------------------------------------/
struct Impl_TlsCertificate {
@@ -203,12 +303,19 @@ void init_TlsCertificate(iTlsCertificate *d) {
d->pkey = NULL;
}
+static void freeX509Chain_(STACK_OF(X509) *chain) {
X509_free(sk_X509_value(chain, i));
+}
void deinit_TlsCertificate(iTlsCertificate *d) {
if (d->cert) {
X509_free(d->cert);
}
if (d->chain) {
sk_X509_free(d->chain);
freeX509Chain_(d->chain);
}
if (d->pkey) {
EVP_PKEY_free(d->pkey);
@@ -355,7 +462,7 @@ iTlsCertificate *copy_TlsCertificate(const iTlsCertificate *d) {
X509_up_ref(d->cert);
copy->cert = d->cert;
}
if (d->pkey) {
EVP_PKEY_up_ref(d->pkey);
copy->pkey = d->pkey;
@@ -796,9 +903,9 @@ static int processIncoming_TlsRequest_(iTlsRequest *d, const char *src, size_t l
}
}
if (!d->cert) {
const STACK_OF(X509) *chain = SSL_get_peer_cert_chain(d->ssl);
STACK_OF(X509) *chain = SSL_get_peer_cert_chain(d->ssl);
d->cert = newX509Chain_TlsCertificate_(SSL_get_peer_certificate(d->ssl),
sk_X509_dup(chain));
X509_chain_up_ref(chain));
}
/* The encrypted data is now in the input bio so now we can perform actual
read of unencrypted data. */
@@ -881,6 +988,9 @@ static iThreadResult run_TlsRequest_(iThread *thread) {
}
}
}
saveSession_Context_(context_, d->hostName, d->port, SSL_get0_session(d->ssl), d->cert);
readIncoming_TlsRequest_(d);
iNotifyAudience(d, finished, TlsRequestFinished);
iDebug("[TlsRequest] finished\n");
@@ -941,6 +1051,7 @@ void submit_TlsRequest(iTlsRequest *d) {
SSL_use_certificate(d->ssl, d->clientCert->cert);
SSL_use_PrivateKey(d->ssl, d->clientCert->pkey);
}
d->socket = new_Socket(cstr_String(d->hostName), d->port);
iConnect(Socket, d->socket, connected, d, connected_TlsRequest_);
iConnect(Socket, d->socket, disconnected, d, disconnected_TlsRequest_);
--
2.25.1
text/plain
This content has been proxied by September (ba2dc).