diff --git a/doc/admin-guide/monitoring/statistics/core/ssl.en.rst b/doc/admin-guide/monitoring/statistics/core/ssl.en.rst index 2c2b60c172b..92b0e4bb498 100644 --- a/doc/admin-guide/monitoring/statistics/core/ssl.en.rst +++ b/doc/admin-guide/monitoring/statistics/core/ssl.en.rst @@ -91,12 +91,18 @@ SSL/TLS .. ts:stat:: global proxy.process.ssl.ssl_session_cache_hit integer :type: counter +.. ts:stat:: global proxy.process.ssl.ssl_origin_session_cache_hit integer + :type: counter + .. ts:stat:: global proxy.process.ssl.ssl_session_cache_lock_contention integer :type: counter .. ts:stat:: global proxy.process.ssl.ssl_session_cache_miss integer :type: counter +.. ts:stat:: global proxy.process.ssl.ssl_origin_session_cache_miss integer + :type: counter + .. ts:stat:: global proxy.process.ssl.ssl_session_cache_new_session integer :type: counter diff --git a/iocore/net/SSLClientUtils.cc b/iocore/net/SSLClientUtils.cc index bef78331a8a..65a807fc01a 100644 --- a/iocore/net/SSLClientUtils.cc +++ b/iocore/net/SSLClientUtils.cc @@ -163,7 +163,7 @@ ssl_new_session_callback(SSL *ssl, SSL_SESSION *sess) if (!sni_addr.empty()) { std::string lookup_key; ts::bwprint(lookup_key, "{}:{}:{}", sni_addr.c_str(), SSL_get_SSL_CTX(ssl), get_verify_str(ssl)); - origin_sess_cache->insert_session(lookup_key, sess); + origin_sess_cache->insert_session(lookup_key, sess, ssl); return 1; } else { if (is_debug_tag_set("ssl.origin_session_cache")) { diff --git a/iocore/net/SSLSessionCache.cc b/iocore/net/SSLSessionCache.cc index 98310527f33..fd8c56e2957 100644 --- a/iocore/net/SSLSessionCache.cc +++ b/iocore/net/SSLSessionCache.cc @@ -317,58 +317,68 @@ SSLSessionBucket::~SSLSessionBucket() {} SSLOriginSessionCache::SSLOriginSessionCache() {} -SSLOriginSessionCache::~SSLOriginSessionCache() -{ - for (auto &x : origin_sessions) { - SSL_SESSION_free(x.second); - } -} +SSLOriginSessionCache::~SSLOriginSessionCache() {} void -SSLOriginSessionCache::insert_session(const std::string &lookup_key, SSL_SESSION *sess) +SSLOriginSessionCache::insert_session(const std::string &lookup_key, SSL_SESSION *sess, SSL *ssl) { if (is_debug_tag_set("ssl.origin_session_cache")) { Debug("ssl.origin_session_cache", "insert session: %s = %p", lookup_key.c_str(), sess); } - std::unique_lock lock(mutex); - auto node = origin_sessions.find(lookup_key); - if (node != origin_sessions.end()) { - SSL_SESSION_free(node->second); - } else if (origin_sessions.size() >= SSLConfigParams::origin_session_cache_size) { - remove_oldest_session(lock); - } - origin_sessions[lookup_key] = sess; -} + size_t len = i2d_SSL_SESSION(sess, nullptr); -void -SSLOriginSessionCache::remove_session(const std::string &lookup_key) -{ - if (is_debug_tag_set("ssl.origin_session_cache")) { - Debug("ssl.origin_session_cache", "remove session: %s", lookup_key.c_str()); - } + Ptr buf; + Ptr buf_exdata; + size_t len_exdata = sizeof(ssl_session_cache_exdata); + buf = new_IOBufferData(buffer_size_to_index(len, MAX_BUFFER_SIZE_INDEX), MEMALIGNED); + ink_release_assert(static_cast(buf->block_size()) >= len); + unsigned char *loc = reinterpret_cast(buf->data()); + i2d_SSL_SESSION(sess, &loc); + buf_exdata = new_IOBufferData(buffer_size_to_index(len, MAX_BUFFER_SIZE_INDEX), MEMALIGNED); + ink_release_assert(static_cast(buf_exdata->block_size()) >= len_exdata); + ssl_session_cache_exdata *exdata = reinterpret_cast(buf_exdata->data()); + // This could be moved to a function in charge of populating exdata + exdata->curve = (ssl == nullptr) ? 0 : SSLGetCurveNID(ssl); + + ats_scoped_obj ssl_orig_session(new SSLOriginSession(lookup_key, buf, len, buf_exdata)); + auto new_node = ssl_orig_session.release(); std::unique_lock lock(mutex); - auto node = origin_sessions.find(lookup_key); - if (node != origin_sessions.end()) { - SSL_SESSION_free(node->second); - origin_sessions.erase(node); + auto entry = orig_sess_map.find(lookup_key); + if (entry != orig_sess_map.end()) { + auto node = entry->second; + orig_sess_que.remove(node); + orig_sess_map.erase(entry); + delete node; + } else if (orig_sess_map.size() >= SSLConfigParams::origin_session_cache_size) { + remove_oldest_session(lock); } + + orig_sess_que.enqueue(new_node); + orig_sess_map[lookup_key] = new_node; } -SSL_SESSION * -SSLOriginSessionCache::get_session(const std::string &lookup_key) +bool +SSLOriginSessionCache::get_session(const std::string &lookup_key, SSL_SESSION **sess, ssl_session_cache_exdata **data) { if (is_debug_tag_set("ssl.origin_session_cache")) { Debug("ssl.origin_session_cache", "get session: %s", lookup_key.c_str()); } std::shared_lock lock(mutex); - auto node = origin_sessions.find(lookup_key); - if (node == origin_sessions.end()) { - return nullptr; + auto entry = orig_sess_map.find(lookup_key); + if (entry == orig_sess_map.end()) { + return false; } - return node->second; + + const unsigned char *loc = reinterpret_cast(entry->second->asn1_data->data()); + *sess = d2i_SSL_SESSION(nullptr, &loc, entry->second->len_asn1_data); + if (data != nullptr) { + ssl_session_cache_exdata *exdata = reinterpret_cast(entry->second->extra_data->data()); + *data = exdata; + } + return true; } void @@ -377,12 +387,12 @@ SSLOriginSessionCache::remove_oldest_session(const std::unique_lockfirst.c_str(), node->second); + while (orig_sess_que.head && orig_sess_que.size >= static_cast(SSLConfigParams::origin_session_cache_size)) { + auto node = orig_sess_que.pop(); + if (is_debug_tag_set("ssl.origin_session_cache")) { + Debug("ssl.origin_session_cache", "remove oldest session: %s", node->key.c_str()); + } + orig_sess_map.erase(node->key); + delete node; } - - SSL_SESSION_free(node->second); - origin_sessions.erase(node); } diff --git a/iocore/net/SSLSessionCache.h b/iocore/net/SSLSessionCache.h index 4d804df0d23..2fa44a50312 100644 --- a/iocore/net/SSLSessionCache.h +++ b/iocore/net/SSLSessionCache.h @@ -183,19 +183,36 @@ class SSLSessionCache size_t nbuckets; }; +class SSLOriginSession +{ +public: + std::string key; + Ptr asn1_data; /* this is the ASN1 representation of the SSL_CTX */ + size_t len_asn1_data; + Ptr extra_data; + + SSLOriginSession(const std::string &lookup_key, const Ptr &ssl_asn1_data, size_t len_asn1, + Ptr &exdata) + : key(lookup_key), asn1_data(ssl_asn1_data), len_asn1_data(len_asn1), extra_data(exdata) + { + } + + LINK(SSLOriginSession, link); +}; + class SSLOriginSessionCache { public: SSLOriginSessionCache(); ~SSLOriginSessionCache(); - void insert_session(const std::string &lookup_key, SSL_SESSION *sess); - void remove_session(const std::string &lookup_key); - SSL_SESSION *get_session(const std::string &lookup_key); + void insert_session(const std::string &lookup_key, SSL_SESSION *sess, SSL *ssl); + bool get_session(const std::string &lookup_key, SSL_SESSION **sess, ssl_session_cache_exdata **data); private: - mutable std::shared_mutex mutex; - std::map origin_sessions; - void remove_oldest_session(const std::unique_lock &lock); + + mutable std::shared_mutex mutex; + CountQueue orig_sess_que; + std::map orig_sess_map; }; diff --git a/iocore/net/SSLStats.cc b/iocore/net/SSLStats.cc index 5abd9947b81..aaf3a8f8cc0 100644 --- a/iocore/net/SSLStats.cc +++ b/iocore/net/SSLStats.cc @@ -161,12 +161,18 @@ SSLInitializeStatistics() RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.ssl_session_cache_hit", RECD_COUNTER, RECP_PERSISTENT, (int)ssl_session_cache_hit, RecRawStatSyncCount); + RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.ssl_origin_session_cache_hit", RECD_COUNTER, RECP_PERSISTENT, + (int)ssl_origin_session_cache_hit, RecRawStatSyncCount); + RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.ssl_session_cache_new_session", RECD_COUNTER, RECP_PERSISTENT, (int)ssl_session_cache_new_session, RecRawStatSyncCount); RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.ssl_session_cache_miss", RECD_COUNTER, RECP_PERSISTENT, (int)ssl_session_cache_miss, RecRawStatSyncCount); + RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.ssl_origin_session_cache_miss", RECD_COUNTER, RECP_PERSISTENT, + (int)ssl_origin_session_cache_miss, RecRawStatSyncCount); + RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.ssl_session_cache_eviction", RECD_COUNTER, RECP_PERSISTENT, (int)ssl_session_cache_eviction, RecRawStatSyncCount); diff --git a/iocore/net/SSLStats.h b/iocore/net/SSLStats.h index 671efa60c78..c46583b57ef 100644 --- a/iocore/net/SSLStats.h +++ b/iocore/net/SSLStats.h @@ -80,7 +80,9 @@ enum SSL_Stats { ssl_total_dyn_max_tls_record_count, ssl_total_dyn_redo_tls_record_count, ssl_session_cache_hit, + ssl_origin_session_cache_hit, ssl_session_cache_miss, + ssl_origin_session_cache_miss, ssl_session_cache_eviction, ssl_session_cache_lock_contention, ssl_session_cache_new_session, diff --git a/iocore/net/SSLUtils.cc b/iocore/net/SSLUtils.cc index 1d57f0b0b14..85ea0d82b81 100644 --- a/iocore/net/SSLUtils.cc +++ b/iocore/net/SSLUtils.cc @@ -2034,7 +2034,12 @@ SSLConnect(SSL *ssl) Debug("ssl.origin_session_cache", "origin session cache lookup key = %s", lookup_key.c_str()); - sess = origin_sess_cache->get_session(lookup_key); + TLSSessionResumptionSupport *srs = TLSSessionResumptionSupport::getInstance(ssl); + ink_assert(srs); + if (srs) { + sess = srs->getOriginSession(ssl, lookup_key); + } + if (sess) { SSL_set_session(ssl, sess); } diff --git a/iocore/net/TLSSessionResumptionSupport.cc b/iocore/net/TLSSessionResumptionSupport.cc index a11ceb3d056..b36633929c1 100644 --- a/iocore/net/TLSSessionResumptionSupport.cc +++ b/iocore/net/TLSSessionResumptionSupport.cc @@ -172,6 +172,30 @@ TLSSessionResumptionSupport::getSession(SSL *ssl, const unsigned char *id, int l return session; } +SSL_SESSION * +TLSSessionResumptionSupport::getOriginSession(SSL *ssl, const std::string &lookup_key) +{ + SSL_SESSION *session = nullptr; + ssl_session_cache_exdata *exdata = nullptr; + if (origin_sess_cache->get_session(lookup_key, &session, &exdata)) { + ink_assert(session); + ink_assert(exdata); + + // Double check the timeout + if (is_ssl_session_timed_out(session)) { + SSL_INCREMENT_DYN_STAT(ssl_origin_session_cache_miss); + session = nullptr; + } else { + SSL_INCREMENT_DYN_STAT(ssl_origin_session_cache_hit); + this->_setSSLSessionCacheHit(true); + this->_setSSLCurveNID(exdata->curve); + } + } else { + SSL_INCREMENT_DYN_STAT(ssl_origin_session_cache_miss); + } + return session; +} + void TLSSessionResumptionSupport::clear() { diff --git a/iocore/net/TLSSessionResumptionSupport.h b/iocore/net/TLSSessionResumptionSupport.h index 26504c3b39c..e91847a25db 100644 --- a/iocore/net/TLSSessionResumptionSupport.h +++ b/iocore/net/TLSSessionResumptionSupport.h @@ -51,6 +51,7 @@ class TLSSessionResumptionSupport ssl_curve_id getSSLCurveNID() const; SSL_SESSION *getSession(SSL *ssl, const unsigned char *id, int len, int *copy); + SSL_SESSION *getOriginSession(SSL *ssl, const std::string &lookup_key); protected: void clear();