Add |SSL_CTX_set0_buffer_pool|.
This currently only works for certificates parsed from the network, but
if making several connections that share certificates, some KB of memory
might be saved.
BUG=chromium:671420
Change-Id: I1c7a71d84e1976138641f71830aafff87f795f9d
Reviewed-on: https://boringssl-review.googlesource.com/12706
Reviewed-by: David Benjamin <davidben@google.com>
Commit-Queue: David Benjamin <davidben@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
diff --git a/include/openssl/ssl.h b/include/openssl/ssl.h
index 3d88017..49a3ffd 100644
--- a/include/openssl/ssl.h
+++ b/include/openssl/ssl.h
@@ -729,6 +729,16 @@
* modes enabled for |ssl|. */
OPENSSL_EXPORT uint32_t SSL_get_mode(const SSL *ssl);
+/* SSL_CTX_set0_buffer_pool sets a |CRYPTO_BUFFER_POOL| that will be used to
+ * store certificates. This can allow multiple connections to share
+ * certificates and thus save memory.
+ *
+ * The SSL_CTX does not take ownership of |pool| and the caller must ensure
+ * that |pool| outlives |ctx| and all objects linked to it, including |SSL|,
+ * |X509| and |SSL_SESSION| objects. Basically, don't ever free |pool|. */
+OPENSSL_EXPORT void SSL_CTX_set0_buffer_pool(SSL_CTX *ctx,
+ CRYPTO_BUFFER_POOL *pool);
+
/* Configuring certificates and private keys.
*
@@ -4037,6 +4047,10 @@
* |SSL_CTX_set_current_time_cb|. */
void (*current_time_cb)(const SSL *ssl, struct timeval *out_clock);
+ /* pool is used for all |CRYPTO_BUFFER|s in case we wish to share certificate
+ * memory. */
+ CRYPTO_BUFFER_POOL *pool;
+
/* quiet_shutdown is true if the connection should not send a close_notify on
* shutdown. */
unsigned quiet_shutdown:1;
diff --git a/ssl/handshake_client.c b/ssl/handshake_client.c
index dc806e0..5949020 100644
--- a/ssl/handshake_client.c
+++ b/ssl/handshake_client.c
@@ -1044,7 +1044,8 @@
uint8_t alert;
sk_CRYPTO_BUFFER_pop_free(ssl->s3->new_session->certs, CRYPTO_BUFFER_free);
- ssl->s3->new_session->certs = ssl_parse_cert_chain(&alert, NULL, &cbs);
+ ssl->s3->new_session->certs =
+ ssl_parse_cert_chain(&alert, NULL, &cbs, ssl->ctx->pool);
if (ssl->s3->new_session->certs == NULL) {
ssl3_send_alert(ssl, SSL3_AL_FATAL, alert);
return -1;
diff --git a/ssl/handshake_server.c b/ssl/handshake_server.c
index 9b13023..8847251 100644
--- a/ssl/handshake_server.c
+++ b/ssl/handshake_server.c
@@ -1473,7 +1473,7 @@
ssl_parse_cert_chain(&alert, ssl->retain_only_sha256_of_client_certs
? ssl->s3->new_session->peer_sha256
: NULL,
- &certificate_msg);
+ &certificate_msg, ssl->ctx->pool);
if (ssl->s3->new_session->certs == NULL) {
ssl3_send_alert(ssl, SSL3_AL_FATAL, alert);
return -1;
diff --git a/ssl/internal.h b/ssl/internal.h
index cd5db9e..3640b65 100644
--- a/ssl/internal.h
+++ b/ssl/internal.h
@@ -762,7 +762,8 @@
* |out_leaf_sha256|. */
STACK_OF(CRYPTO_BUFFER) *ssl_parse_cert_chain(uint8_t *out_alert,
uint8_t *out_leaf_sha256,
- CBS *cbs);
+ CBS *cbs,
+ CRYPTO_BUFFER_POOL *pool);
/* ssl_add_cert_to_cbb adds |x509| to |cbb|. It returns one on success and zero
* on error. */
diff --git a/ssl/ssl_asn1.c b/ssl/ssl_asn1.c
index fa2fbc0..a12af77 100644
--- a/ssl/ssl_asn1.c
+++ b/ssl/ssl_asn1.c
@@ -677,6 +677,7 @@
}
if (has_peer) {
+ /* TODO(agl): this should use the |SSL_CTX|'s pool. */
CRYPTO_BUFFER *buffer = CRYPTO_BUFFER_new_from_CBS(&peer, NULL);
if (buffer == NULL ||
!sk_CRYPTO_BUFFER_push(ret->certs, buffer)) {
@@ -694,6 +695,7 @@
goto err;
}
+ /* TODO(agl): this should use the |SSL_CTX|'s pool. */
CRYPTO_BUFFER *buffer = CRYPTO_BUFFER_new_from_CBS(&cert, NULL);
if (buffer == NULL ||
!sk_CRYPTO_BUFFER_push(ret->certs, buffer)) {
diff --git a/ssl/ssl_cert.c b/ssl/ssl_cert.c
index 66ee068..7711cd1 100644
--- a/ssl/ssl_cert.c
+++ b/ssl/ssl_cert.c
@@ -464,7 +464,8 @@
STACK_OF(CRYPTO_BUFFER) *ssl_parse_cert_chain(uint8_t *out_alert,
uint8_t *out_leaf_sha256,
- CBS *cbs) {
+ CBS *cbs,
+ CRYPTO_BUFFER_POOL *pool) {
STACK_OF(CRYPTO_BUFFER) *ret = sk_CRYPTO_BUFFER_new_null();
if (ret == NULL) {
*out_alert = SSL_AD_INTERNAL_ERROR;
@@ -493,7 +494,8 @@
SHA256(CBS_data(&certificate), CBS_len(&certificate), out_leaf_sha256);
}
- CRYPTO_BUFFER *buf = CRYPTO_BUFFER_new_from_CBS(&certificate, NULL);
+ CRYPTO_BUFFER *buf =
+ CRYPTO_BUFFER_new_from_CBS(&certificate, pool);
if (buf == NULL) {
*out_alert = SSL_AD_DECODE_ERROR;
goto err;
diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c
index 8638396..e5c0559 100644
--- a/ssl/ssl_lib.c
+++ b/ssl/ssl_lib.c
@@ -1070,6 +1070,10 @@
uint32_t SSL_get_mode(const SSL *ssl) { return ssl->mode; }
+void SSL_CTX_set0_buffer_pool(SSL_CTX *ctx, CRYPTO_BUFFER_POOL *pool) {
+ ctx->pool = pool;
+}
+
X509 *SSL_get_peer_certificate(const SSL *ssl) {
if (ssl == NULL) {
return NULL;
diff --git a/ssl/test/bssl_shim.cc b/ssl/test/bssl_shim.cc
index 140e666..3ad906b 100644
--- a/ssl/test/bssl_shim.cc
+++ b/ssl/test/bssl_shim.cc
@@ -66,6 +66,8 @@
#include "test_config.h"
+static CRYPTO_BUFFER_POOL *g_pool = nullptr;
+
#if !defined(OPENSSL_WINDOWS)
static int closesocket(int sock) {
return close(sock);
@@ -909,6 +911,8 @@
return nullptr;
}
+ SSL_CTX_set0_buffer_pool(ssl_ctx.get(), g_pool);
+
// Enable TLS 1.3 for tests.
if (!config->is_dtls &&
!SSL_CTX_set_max_proto_version(ssl_ctx.get(), TLS1_3_VERSION)) {
@@ -1915,6 +1919,8 @@
return Usage(argv[0]);
}
+ g_pool = CRYPTO_BUFFER_POOL_new();
+
// Some code treats the zero time special, so initialize the clock to a
// non-zero time.
g_clock.tv_sec = 1234;
diff --git a/ssl/tls13_both.c b/ssl/tls13_both.c
index a47dd26..dd4a041 100644
--- a/ssl/tls13_both.c
+++ b/ssl/tls13_both.c
@@ -206,7 +206,8 @@
ssl->s3->new_session->peer_sha256);
}
- CRYPTO_BUFFER *buf = CRYPTO_BUFFER_new_from_CBS(&certificate, NULL);
+ CRYPTO_BUFFER *buf =
+ CRYPTO_BUFFER_new_from_CBS(&certificate, ssl->ctx->pool);
if (buf == NULL ||
!sk_CRYPTO_BUFFER_push(certs, buf)) {
CRYPTO_BUFFER_free(buf);