=> 7eb72c04d096089fc369128b1ac8583419d098e0
[1mdiff --git a/src/tlsrequest.c b/src/tlsrequest.c[m [1mindex 22fb215..943a493 100644[m [1m--- a/src/tlsrequest.c[m [1m+++ b/src/tlsrequest.c[m [36m@@ -28,6 +28,7 @@[m [mSOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.[m #include "the_Foundation/tlsrequest.h"[m #include "the_Foundation/buffer.h"[m #include "the_Foundation/socket.h"[m [32m+[m[32m#include "the_Foundation/stringhash.h"[m #include "the_Foundation/thread.h"[m #include "the_Foundation/time.h"[m [m [36m@@ -53,13 +54,120 @@[m [mstatic void initContext_(void);[m static iTlsCertificate *newX509Chain_TlsCertificate_(X509 *cert, STACK_OF(X509) *chain);[m static void certificateVerifyFailed_TlsRequest_(iTlsRequest *, const iTlsCertificate *cert);[m [m [32m+[m[32mstatic iBool readAllFromBIO_(BIO *bio, iBlock *out) {[m [32m+[m[32m char buf[DEFAULT_BUF_SIZE];[m [32m+[m[32m int n;[m [32m+[m[32m do {[m [32m+[m[32m n = BIO_read(bio, buf, sizeof(buf));[m [32m+[m[32m if (n > 0) {[m [32m+[m[32m appendData_Block(out, buf, n);[m [32m+[m[32m }[m [32m+[m[32m else if (!BIO_should_retry(bio)) {[m [32m+[m[32m return iFalse;[m [32m+[m[32m }[m [32m+[m[32m } while (n > 0);[m [32m+[m[32m return iTrue;[m [32m+[m[32m}[m [32m+[m [32m+[m[32m/*----------------------------------------------------------------------------------------------*/[m [32m+[m [32m+[m[32miDeclareClass(CachedSession)[m [32m+[m[41m [m [32m+[m[32mstatic const int maxSessionAge_CachedSession_ = 10 * 60; /* seconds */[m [32m+[m[41m [m [32m+[m[32mstruct Impl_CachedSession {[m [32m+[m[32m iObject object;[m [32m+[m[32m iBlock pemSession;[m [32m+[m[32m iTime timestamp;[m [32m+[m[32m iTlsCertificate *cert; /* not sent if session reused */[m [32m+[m[32m};[m [32m+[m [32m+[m[32mstatic void init_CachedSession(iCachedSession *d, SSL_SESSION *sess, const iTlsCertificate *cert) {[m [32m+[m[32m BIO *buf = BIO_new(BIO_s_mem());[m [32m+[m[32m PEM_write_bio_SSL_SESSION(buf, sess);[m [32m+[m[32m init_Block(&d->pemSession, 0);[m [32m+[m[32m readAllFromBIO_(buf, &d->pemSession);[m [32m+[m[32m BIO_free(buf);[m [32m+[m[32m initCurrent_Time(&d->timestamp);[m [32m+[m[32m d->cert = copy_TlsCertificate(cert);[m [32m+[m[32m}[m [32m+[m [32m+[m[32mstatic void deinit_CachedSession(iCachedSession *d) {[m [32m+[m[32m deinit_Block(&d->pemSession);[m [32m+[m[32m delete_TlsCertificate(d->cert);[m [32m+[m[32m}[m [32m+[m [32m+[m[32miDefineClass(CachedSession)[m [32m+[m[32miDefineObjectConstructionArgs(CachedSession,[m [32m+[m[32m (SSL_SESSION *sess, const iTlsCertificate *cert),[m [32m+[m[32m sess, cert)[m [32m+[m [32m+[m[32mstatic void reuse_CachedSession(const iCachedSession *d, SSL *ssl) {[m [32m+[m[32m BIO *buf = BIO_new_mem_buf(constData_Block(&d->pemSession), size_Block(&d->pemSession));[m [32m+[m[32m SSL_SESSION *sess = NULL;[m [32m+[m[32m PEM_read_bio_SSL_SESSION(buf, &sess, NULL, NULL);[m [32m+[m[32m SSL_SESSION_up_ref(sess);[m [32m+[m[32m SSL_set_session(ssl, sess);[m [32m+[m[32m BIO_free(buf);[m [32m+[m[32m SSL_SESSION_free(sess);[m [32m+[m[32m}[m [32m+[m struct Impl_Context {[m SSL_CTX * ctx;[m X509_STORE * certStore;[m iTlsRequestVerifyFunc userVerifyFunc;[m tss_t tssKeyCurrentRequest;[m [32m+[m[32m iMutex cacheMutex;[m [32m+[m[32m iStringHash * cache; /* key is "address:port"; these could be saved persistently */[m };[m [m [32m+[m[32mstatic iString *cacheKey_(const iString *host, uint16_t port) {[m [32m+[m[32m iString *key = copy_String(host);[m [32m+[m[32m appendFormat_String(key, ":%u", port);[m [32m+[m[32m return key;[m [32m+[m[32m}[m [32m+[m [32m+[m[32mstatic iBool isExpired_CachedSession_(const iCachedSession *d) {[m [32m+[m[32m if (!d) return iTrue;[m [32m+[m[32m return elapsedSeconds_Time(&d->timestamp) > maxSessionAge_CachedSession_;[m [32m+[m[32m}[m [32m+[m [32m+[m[32mstatic iTlsCertificate *maybeReuseSession_Context_(iContext *d, SSL *ssl, const iString *host,[m [32m+[m[32m uint16_t port) {[m [32m+[m[32m iTlsCertificate *cert = NULL;[m [32m+[m[32m iString *key = cacheKey_(host, port);[m [32m+[m[32m lock_Mutex(&d->cacheMutex);[m [32m+[m[32m /* Remove old entries from the session cache. */[m [32m+[m[32m iForEach(StringHash, i, d->cache) {[m [32m+[m[32m iCachedSession *cs = i.value->object;[m [32m+[m[32m if (isExpired_CachedSession_(cs)) {[m [32m+[m[32m iDebug("[TlsRequest] session for `%s` has expired\n", cstr_Block(&i.value->keyBlock));[m [32m+[m[32m remove_StringHashIterator(&i);[m [32m+[m[32m }[m [32m+[m[32m }[m [32m+[m[32m iCachedSession *cs = value_StringHash(d->cache, key);[m [32m+[m[32m if (cs) {[m [32m+[m[32m reuse_CachedSession(cs, ssl);[m [32m+[m[32m cert = copy_TlsCertificate(cs->cert);[m [32m+[m[32m iDebug("[TlsRequest] reusing session for `%s`\n", cstr_String(key));[m [32m+[m[32m }[m [32m+[m[32m unlock_Mutex(&d->cacheMutex);[m [32m+[m[32m delete_String(key);[m [32m+[m[32m return cert; /* caller gets ownership */[m [32m+[m[32m}[m [32m+[m [32m+[m[32mstatic void saveSession_Context_(iContext *d, const iString *host, uint16_t port,[m [32m+[m[32m SSL_SESSION *sess, const iTlsCertificate *cert) {[m [32m+[m[32m if (sess && cert) {[m [32m+[m[32m iString *key = cacheKey_(host, port);[m [32m+[m[32m lock_Mutex(&d->cacheMutex);[m [32m+[m[32m insert_StringHash(d->cache, key, new_CachedSession(sess, cert));[m [32m+[m[32m unlock_Mutex(&d->cacheMutex);[m [32m+[m[32m iDebug("[TlsRequest] saved session for `%s`\n", cstr_String(key));[m [32m+[m[32m delete_String(key);[m [32m+[m[32m }[m [32m+[m[32m}[m [32m+[m static iTlsRequest *currentRequestForThread_Context_(iContext *d) {[m return tss_get(context_->tssKeyCurrentRequest);[m }[m [36m@@ -118,17 +226,22 @@[m [mvoid init_Context(iContext *d) {[m ERR_load_BIO_strings();[m d->ctx = SSL_CTX_new(TLS_client_method());[m if (!d->ctx) {[m [31m- iDebug("[TlsRequest] Failed to initialize OpenSSL\n");[m [32m+[m[32m iDebug("[TlsRequest] failed to initialize OpenSSL\n");[m iAssert(d->ctx);[m }[m [32m+[m[32m d->certStore = NULL;[m d->userVerifyFunc = NULL;[m SSL_CTX_set_verify(d->ctx, SSL_VERIFY_PEER, verifyCallback_Context_);[m /* Bug workarounds: https://www.openssl.org/docs/manmaster/man3/SSL_CTX_set_options.html */[m SSL_CTX_set_options(d->ctx, SSL_OP_ALL);[m [31m- d->certStore = NULL;[m [32m+[m[32m init_Mutex(&d->cacheMutex);[m [32m+[m[32m d->cache = new_StringHash();[m [32m+[m[32m SSL_CTX_set_session_cache_mode(d->ctx, SSL_SESS_CACHE_CLIENT | SSL_SESS_CACHE_NO_INTERNAL_STORE);[m }[m [m void deinit_Context(iContext *d) {[m [32m+[m[32m iRelease(d->cache);[m [32m+[m[32m deinit_Mutex(&d->cacheMutex);[m SSL_CTX_free(d->ctx);[m tss_delete(d->tssKeyCurrentRequest);[m }[m [36m@@ -137,6 +250,8 @@[m [miBool isValid_Context(iContext *d) {[m return d->ctx != NULL;[m }[m [m [32m+[m[32m/*----------------------------------------------------------------------------------------------*/[m [32m+[m void setCACertificates_TlsRequest(const iString *caFile, const iString *caPath) {[m initContext_();[m iContext *d = context_;[m [36m@@ -172,21 +287,6 @@[m [mstatic void initContext_(void) {[m }[m }[m [m [31m-static iBool readAllFromBIO_(BIO *bio, iBlock *out) {[m [31m- char buf[DEFAULT_BUF_SIZE];[m [31m- int n;[m [31m- do {[m [31m- n = BIO_read(bio, buf, sizeof(buf));[m [31m- if (n > 0) {[m [31m- appendData_Block(out, buf, n);[m [31m- }[m [31m- else if (!BIO_should_retry(bio)) {[m [31m- return iFalse;[m [31m- }[m [31m- } while (n > 0);[m [31m- return iTrue;[m [31m-}[m [31m-[m /*----------------------------------------------------------------------------------------------*/[m [m struct Impl_TlsCertificate {[m [36m@@ -203,12 +303,19 @@[m [mvoid init_TlsCertificate(iTlsCertificate *d) {[m d->pkey = NULL;[m }[m [m [32m+[m[32mstatic void freeX509Chain_(STACK_OF(X509) *chain) {[m [32m+[m[32m for (int i = 0; i < sk_X509_num(chain); i++) {[m [32m+[m[32m X509_free(sk_X509_value(chain, i));[m [32m+[m[32m }[m [32m+[m[32m sk_X509_free(chain);[m [32m+[m[32m}[m [32m+[m void deinit_TlsCertificate(iTlsCertificate *d) {[m if (d->cert) {[m X509_free(d->cert);[m }[m if (d->chain) {[m [31m- sk_X509_free(d->chain);[m [32m+[m[32m freeX509Chain_(d->chain);[m }[m if (d->pkey) {[m EVP_PKEY_free(d->pkey);[m [36m@@ -355,7 +462,7 @@[m [miTlsCertificate *copy_TlsCertificate(const iTlsCertificate *d) {[m X509_up_ref(d->cert);[m copy->cert = d->cert;[m }[m [31m- copy->chain = d->chain ? sk_X509_dup(d->chain) : NULL;[m [32m+[m[32m copy->chain = d->chain ? X509_chain_up_ref(d->chain) : NULL;[m if (d->pkey) {[m EVP_PKEY_up_ref(d->pkey);[m copy->pkey = d->pkey;[m [36m@@ -796,9 +903,9 @@[m [mstatic int processIncoming_TlsRequest_(iTlsRequest *d, const char *src, size_t l[m }[m }[m if (!d->cert) {[m [31m- const STACK_OF(X509) *chain = SSL_get_peer_cert_chain(d->ssl);[m [32m+[m[32m STACK_OF(X509) *chain = SSL_get_peer_cert_chain(d->ssl);[m d->cert = newX509Chain_TlsCertificate_(SSL_get_peer_certificate(d->ssl),[m [31m- sk_X509_dup(chain));[m [32m+[m[32m X509_chain_up_ref(chain));[m }[m /* The encrypted data is now in the input bio so now we can perform actual[m read of unencrypted data. */[m [36m@@ -881,6 +988,9 @@[m [mstatic iThreadResult run_TlsRequest_(iThread *thread) {[m }[m }[m }[m [32m+[m[32m if (!SSL_session_reused(d->ssl) && d->status != error_TlsRequestStatus) {[m [32m+[m[32m saveSession_Context_(context_, d->hostName, d->port, SSL_get0_session(d->ssl), d->cert);[m [32m+[m[32m }[m readIncoming_TlsRequest_(d);[m iNotifyAudience(d, finished, TlsRequestFinished);[m iDebug("[TlsRequest] finished\n");[m [36m@@ -941,6 +1051,7 @@[m [mvoid submit_TlsRequest(iTlsRequest *d) {[m SSL_use_certificate(d->ssl, d->clientCert->cert);[m SSL_use_PrivateKey(d->ssl, d->clientCert->pkey);[m }[m [32m+[m[32m d->cert = maybeReuseSession_Context_(context_, d->ssl, d->hostName, d->port);[m d->socket = new_Socket(cstr_String(d->hostName), d->port);[m iConnect(Socket, d->socket, connected, d, connected_TlsRequest_);[m iConnect(Socket, d->socket, disconnected, d, disconnected_TlsRequest_);[m
text/gemini; charset=utf-8
This content has been proxied by September (ba2dc).