Keep a reference to |X509|s appended to a chain.
The recent CRYPTO_BUFFER changes meant that |X509| objects passed to
SSL_CTX_add_extra_chain_cert would be |free|ed immediately. However,
some third-party code (at least serf and curl) continue to use the
|X509| even after handing over ownership.
In order to unblock things, keep the past |X509| around for a while to
paper over the issues with those libraries while we try and upstream
changes.
Change-Id: I832b458af9b265749fed964658c5c34c84d518df
Reviewed-on: https://boringssl-review.googlesource.com/13480
Reviewed-by: Adam Langley <agl@google.com>
Commit-Queue: Adam Langley <agl@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
diff --git a/ssl/internal.h b/ssl/internal.h
index a408b0f..5364f99 100644
--- a/ssl/internal.h
+++ b/ssl/internal.h
@@ -1245,6 +1245,11 @@
* a non-owning pointer to the certificate chain. */
X509 *x509_leaf;
+ /* x509_stash contains the last |X509| object append to the chain. This is a
+ * workaround for some third-party code that continue to use an |X509| object
+ * even after passing ownership with an “add0” function. */
+ X509 *x509_stash;
+
/* key_method, if non-NULL, is a set of callbacks to call for private key
* operations. */
const SSL_PRIVATE_KEY_METHOD *key_method;
diff --git a/ssl/ssl_cert.c b/ssl/ssl_cert.c
index ed6ba0d..1ebe4b6 100644
--- a/ssl/ssl_cert.c
+++ b/ssl/ssl_cert.c
@@ -227,6 +227,9 @@
ssl_cert_flush_cached_x509_leaf(cert);
ssl_cert_flush_cached_x509_chain(cert);
+ X509_free(cert->x509_stash);
+ cert->x509_stash = NULL;
+
sk_CRYPTO_BUFFER_pop_free(cert->chain, CRYPTO_BUFFER_free);
cert->chain = NULL;
EVP_PKEY_free(cert->privatekey);
@@ -378,7 +381,8 @@
return 0;
}
- X509_free(x509);
+ X509_free(cert->x509_stash);
+ cert->x509_stash = x509;
ssl_cert_flush_cached_x509_chain(cert);
return 1;
}
diff --git a/ssl/ssl_test.cc b/ssl/ssl_test.cc
index 22a9b7b..99e9af2 100644
--- a/ssl/ssl_test.cc
+++ b/ssl/ssl_test.cc
@@ -3142,6 +3142,21 @@
return true;
}
+TEST(SSLTest, AddChainCertHack) {
+ // Ensure that we don't accidently break the hack that we have in place to
+ // keep curl and serf happy when they use an |X509| even after transfering
+ // ownership.
+
+ bssl::UniquePtr<SSL_CTX> ctx(SSL_CTX_new(TLS_method()));
+ ASSERT_TRUE(ctx);
+ X509 *cert = GetTestCertificate().release();
+ ASSERT_TRUE(cert);
+ SSL_CTX_add0_chain_cert(ctx.get(), cert);
+
+ // This should not trigger a use-after-free.
+ X509_cmp(cert, cert);
+}
+
// TODO(davidben): Convert this file to GTest properly.
TEST(SSLTest, AllTests) {
if (!TestCipherRules() ||