Add lh_FOO_retrieve_key to avoid stack-allocating SSL_SESSION.
lh_FOO_retrieve is often called with a dummy instance of FOO that has
only a few fields filled in. This works fine for C, but a C++
SSL_SESSION with destructors is a bit more of a nuisance here.
Instead, teach LHASH to allow queries by some external key type. This
avoids stack-allocating SSL_SESSION. Along the way, fix the
make_macros.sh script.
Change-Id: Ie0b482d4ffe1027049d49db63274c7c17f9398fa
Reviewed-on: https://boringssl-review.googlesource.com/29586
Commit-Queue: David Benjamin <davidben@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
Reviewed-by: Adam Langley <agl@google.com>
diff --git a/ssl/ssl_session.cc b/ssl/ssl_session.cc
index adec8dc..a2a1482 100644
--- a/ssl/ssl_session.cc
+++ b/ssl/ssl_session.cc
@@ -184,6 +184,26 @@
return session;
}
+uint32_t ssl_hash_session_id(Span<const uint8_t> session_id) {
+ // Take the first four bytes of |session_id|. Session IDs are generated by the
+ // server randomly, so we can assume even using the first four bytes results
+ // in a good distribution.
+ uint8_t tmp_storage[sizeof(uint32_t)];
+ if (session_id.size() < sizeof(tmp_storage)) {
+ OPENSSL_memset(tmp_storage, 0, sizeof(tmp_storage));
+ OPENSSL_memcpy(tmp_storage, session_id.data(), session_id.size());
+ session_id = tmp_storage;
+ }
+
+ uint32_t hash =
+ ((uint32_t)session_id[0]) |
+ ((uint32_t)session_id[1] << 8) |
+ ((uint32_t)session_id[2] << 16) |
+ ((uint32_t)session_id[3] << 24);
+
+ return hash;
+}
+
UniquePtr<SSL_SESSION> SSL_SESSION_dup(SSL_SESSION *session, int dup_flags) {
UniquePtr<SSL_SESSION> new_session = ssl_session_new(session->x509_method);
if (!new_session) {
@@ -657,11 +677,11 @@
// |*out_session| to an |SSL_SESSION| object if found.
static enum ssl_hs_wait_t ssl_lookup_session(
SSL_HANDSHAKE *hs, UniquePtr<SSL_SESSION> *out_session,
- const uint8_t *session_id, size_t session_id_len) {
+ Span<const uint8_t> session_id) {
SSL *const ssl = hs->ssl;
out_session->reset();
- if (session_id_len == 0 || session_id_len > SSL_MAX_SSL_SESSION_ID_LENGTH) {
+ if (session_id.empty() || session_id.size() > SSL_MAX_SSL_SESSION_ID_LENGTH) {
return ssl_hs_ok;
}
@@ -669,21 +689,26 @@
// Try the internal cache, if it exists.
if (!(ssl->session_ctx->session_cache_mode &
SSL_SESS_CACHE_NO_INTERNAL_LOOKUP)) {
- SSL_SESSION data;
- data.session_id_length = session_id_len;
- OPENSSL_memcpy(data.session_id, session_id, session_id_len);
-
+ uint32_t hash = ssl_hash_session_id(session_id);
+ auto cmp = [](const void *key, const SSL_SESSION *sess) -> int {
+ Span<const uint8_t> key_id =
+ *reinterpret_cast<const Span<const uint8_t> *>(key);
+ Span<const uint8_t> sess_id =
+ MakeConstSpan(sess->session_id, sess->session_id_length);
+ return key_id == sess_id ? 0 : 1;
+ };
MutexReadLock lock(&ssl->session_ctx->lock);
- // |lh_SSL_SESSION_retrieve| returns a non-owning pointer.
- session = UpRef(lh_SSL_SESSION_retrieve(ssl->session_ctx->sessions, &data));
+ // |lh_SSL_SESSION_retrieve_key| returns a non-owning pointer.
+ session = UpRef(lh_SSL_SESSION_retrieve_key(ssl->session_ctx->sessions,
+ &session_id, hash, cmp));
// TODO(davidben): This should probably move it to the front of the list.
}
// Fall back to the external cache, if it exists.
if (!session && ssl->session_ctx->get_session_cb != nullptr) {
int copy = 1;
- session.reset(ssl->session_ctx->get_session_cb(ssl, session_id,
- session_id_len, ©));
+ session.reset(ssl->session_ctx->get_session_cb(ssl, session_id.data(),
+ session_id.size(), ©));
if (!session) {
return ssl_hs_ok;
}
@@ -752,7 +777,8 @@
} else {
// The client didn't send a ticket, so the session ID is a real ID.
enum ssl_hs_wait_t lookup_ret = ssl_lookup_session(
- hs, &session, client_hello->session_id, client_hello->session_id_len);
+ hs, &session,
+ MakeConstSpan(client_hello->session_id, client_hello->session_id_len));
if (lookup_ret != ssl_hs_ok) {
return lookup_ret;
}