From 71dfad4d108a520ef85922c13cb95395fba0ddef Mon Sep 17 00:00:00 2001 From: David Benjamin Date: Sun, 16 Jul 2017 17:27:39 -0400 Subject: [PATCH] Add new functions for configuring the client CA list. This is needed to switch Chromium's SSLServerSocket and parts of Conscrypt to CRYPTO_BUFFER. Bug: 54 Change-Id: Iacd417970607bc1a162057676b576956a3bdfa3f Reviewed-on: https://boringssl-review.googlesource.com/17965 Reviewed-by: Adam Langley --- include/openssl/pool.h | 2 ++ include/openssl/ssl.h | 12 +++++++ ssl/ssl_cert.cc | 12 +++++++ ssl/ssl_test.cc | 73 ++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 99 insertions(+) diff --git a/include/openssl/pool.h b/include/openssl/pool.h index 8a07af53..4972b93c 100644 --- a/include/openssl/pool.h +++ b/include/openssl/pool.h @@ -82,6 +82,8 @@ namespace bssl { BORINGSSL_MAKE_DELETER(CRYPTO_BUFFER_POOL, CRYPTO_BUFFER_POOL_free) BORINGSSL_MAKE_DELETER(CRYPTO_BUFFER, CRYPTO_BUFFER_free) +BORINGSSL_MAKE_STACK_DELETER(CRYPTO_BUFFER, CRYPTO_BUFFER_free) + } // namespace bssl } /* extern C++ */ diff --git a/include/openssl/ssl.h b/include/openssl/ssl.h index 328ec1c3..cee90a13 100644 --- a/include/openssl/ssl.h +++ b/include/openssl/ssl.h @@ -2440,6 +2440,18 @@ OPENSSL_EXPORT void SSL_set_client_CA_list(SSL *ssl, OPENSSL_EXPORT void SSL_CTX_set_client_CA_list(SSL_CTX *ctx, STACK_OF(X509_NAME) *name_list); +/* SSL_set0_client_CAs sets |ssl|'s client certificate CA list to |name_list|, + * which should contain DER-encoded distinguished names (RFC 5280). It takes + * ownership of |name_list|. */ +OPENSSL_EXPORT void SSL_set0_client_CAs(SSL *ssl, + STACK_OF(CRYPTO_BUFFER) *name_list); + +/* SSL_CTX_set0_client_CAs sets |ctx|'s client certificate CA list to + * |name_list|, which should contain DER-encoded distinguished names (RFC 5280). + * It takes ownership of |name_list|. */ +OPENSSL_EXPORT void SSL_CTX_set0_client_CAs(SSL_CTX *ctx, + STACK_OF(CRYPTO_BUFFER) *name_list); + /* SSL_get_client_CA_list returns |ssl|'s client certificate CA list. If |ssl| * has not been configured as a client, this is the list configured by * |SSL_CTX_set_client_CA_list|. diff --git a/ssl/ssl_cert.cc b/ssl/ssl_cert.cc index a410aefa..a9f334e2 100644 --- a/ssl/ssl_cert.cc +++ b/ssl/ssl_cert.cc @@ -904,3 +904,15 @@ int SSL_set_ocsp_response(SSL *ssl, const uint8_t *response, ssl->cert->ocsp_response = CRYPTO_BUFFER_new(response, response_len, NULL); return ssl->cert->ocsp_response != NULL; } + +void SSL_CTX_set0_client_CAs(SSL_CTX *ctx, STACK_OF(CRYPTO_BUFFER) *name_list) { + ctx->x509_method->ssl_ctx_flush_cached_client_CA(ctx); + sk_CRYPTO_BUFFER_pop_free(ctx->client_CA, CRYPTO_BUFFER_free); + ctx->client_CA = name_list; +} + +void SSL_set0_client_CAs(SSL *ssl, STACK_OF(CRYPTO_BUFFER) *name_list) { + ssl->ctx->x509_method->ssl_flush_cached_client_CA(ssl); + sk_CRYPTO_BUFFER_pop_free(ssl->client_CA, CRYPTO_BUFFER_free); + ssl->client_CA = name_list; +} diff --git a/ssl/ssl_test.cc b/ssl/ssl_test.cc index 640718ae..bf546da4 100644 --- a/ssl/ssl_test.cc +++ b/ssl/ssl_test.cc @@ -1293,6 +1293,15 @@ static bssl::UniquePtr GetChainTestKey() { PEM_read_bio_PrivateKey(bio.get(), nullptr, nullptr, nullptr)); } +static const uint8_t kTestName[] = { + 0x30, 0x45, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, + 0x02, 0x41, 0x55, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, + 0x0c, 0x0a, 0x53, 0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74, 0x65, + 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x18, 0x49, + 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x20, 0x57, 0x69, 0x64, 0x67, + 0x69, 0x74, 0x73, 0x20, 0x50, 0x74, 0x79, 0x20, 0x4c, 0x74, 0x64, +}; + static bool CompleteHandshakes(SSL *client, SSL *server) { // Drive both their handshakes to completion. for (;;) { @@ -3288,6 +3297,70 @@ TEST(SSLTest, SetChainAndKey) { nullptr /* no session */)); } +TEST(SSLTest, ClientCABuffers) { + bssl::UniquePtr client_ctx(SSL_CTX_new(TLS_with_buffers_method())); + ASSERT_TRUE(client_ctx); + bssl::UniquePtr server_ctx(SSL_CTX_new(TLS_with_buffers_method())); + ASSERT_TRUE(server_ctx); + + bssl::UniquePtr key = GetChainTestKey(); + ASSERT_TRUE(key); + bssl::UniquePtr leaf = GetChainTestCertificateBuffer(); + ASSERT_TRUE(leaf); + bssl::UniquePtr intermediate = + GetChainTestIntermediateBuffer(); + ASSERT_TRUE(intermediate); + std::vector chain = { + leaf.get(), + intermediate.get(), + }; + ASSERT_TRUE(SSL_CTX_set_chain_and_key(server_ctx.get(), &chain[0], + chain.size(), key.get(), nullptr)); + + bssl::UniquePtr ca_name( + CRYPTO_BUFFER_new(kTestName, sizeof(kTestName), nullptr)); + ASSERT_TRUE(ca_name); + bssl::UniquePtr ca_names( + sk_CRYPTO_BUFFER_new_null()); + ASSERT_TRUE(ca_names); + ASSERT_TRUE(sk_CRYPTO_BUFFER_push(ca_names.get(), ca_name.get())); + ca_name.release(); + SSL_CTX_set0_client_CAs(server_ctx.get(), ca_names.release()); + + // Configure client and server to accept all certificates. + SSL_CTX_set_custom_verify( + client_ctx.get(), SSL_VERIFY_PEER, + [](SSL *ssl, uint8_t *out_alert) -> ssl_verify_result_t { + return ssl_verify_ok; + }); + SSL_CTX_set_custom_verify( + server_ctx.get(), SSL_VERIFY_PEER, + [](SSL *ssl, uint8_t *out_alert) -> ssl_verify_result_t { + return ssl_verify_ok; + }); + + bool cert_cb_called = false; + SSL_CTX_set_cert_cb( + client_ctx.get(), + [](SSL *ssl, void *arg) -> int { + STACK_OF(CRYPTO_BUFFER) *peer_names = + SSL_get0_server_requested_CAs(ssl); + EXPECT_EQ(1u, sk_CRYPTO_BUFFER_num(peer_names)); + CRYPTO_BUFFER *peer_name = sk_CRYPTO_BUFFER_value(peer_names, 0); + EXPECT_EQ(Bytes(kTestName), Bytes(CRYPTO_BUFFER_data(peer_name), + CRYPTO_BUFFER_len(peer_name))); + *reinterpret_cast(arg) = true; + return 1; + }, + &cert_cb_called); + + bssl::UniquePtr client, server; + ASSERT_TRUE(ConnectClientAndServer(&client, &server, client_ctx.get(), + server_ctx.get(), + nullptr /* no session */)); + EXPECT_TRUE(cert_cb_called); +} + // Configuring the empty cipher list, though an error, should still modify the // configuration. TEST(SSLTest, EmptyCipherList) {