2236 lines
91 KiB
C++
2236 lines
91 KiB
C++
|
|
// Copyright (c) 2014, Google Inc.
|
||
|
|
// SPDX-License-Identifier: ISC
|
||
|
|
|
||
|
|
#include <limits.h>
|
||
|
|
#include <stdio.h>
|
||
|
|
#include <string.h>
|
||
|
|
#include <time.h>
|
||
|
|
|
||
|
|
#include <algorithm>
|
||
|
|
#include <array>
|
||
|
|
#include <limits>
|
||
|
|
#include <string>
|
||
|
|
#include <utility>
|
||
|
|
#include <vector>
|
||
|
|
|
||
|
|
#include <gtest/gtest.h>
|
||
|
|
|
||
|
|
#include <openssl/aead.h>
|
||
|
|
#include <openssl/base64.h>
|
||
|
|
#include <openssl/bio.h>
|
||
|
|
#include <openssl/bytestring.h>
|
||
|
|
#include <openssl/cipher.h>
|
||
|
|
#include <openssl/crypto.h>
|
||
|
|
#include <openssl/curve25519.h>
|
||
|
|
#include <openssl/err.h>
|
||
|
|
#include <openssl/hmac.h>
|
||
|
|
#include <openssl/hpke.h>
|
||
|
|
#include <openssl/pem.h>
|
||
|
|
#include <openssl/rand.h>
|
||
|
|
#include <openssl/sha.h>
|
||
|
|
#include <openssl/ssl.h>
|
||
|
|
#include <openssl/x509.h>
|
||
|
|
|
||
|
|
#include "../crypto/fipsmodule/ec/internal.h"
|
||
|
|
#include "../crypto/fipsmodule/ml_kem/ml_kem.h"
|
||
|
|
#include "../crypto/internal.h"
|
||
|
|
#include "../crypto/test/file_util.h"
|
||
|
|
#include "../crypto/test/test_util.h"
|
||
|
|
#include "internal.h"
|
||
|
|
#include "ssl_common_test.h"
|
||
|
|
|
||
|
|
#if defined(OPENSSL_WINDOWS)
|
||
|
|
// Windows defines struct timeval in winsock2.h.
|
||
|
|
OPENSSL_MSVC_PRAGMA(warning(push, 3))
|
||
|
|
#include <winsock2.h>
|
||
|
|
OPENSSL_MSVC_PRAGMA(warning(pop))
|
||
|
|
#else
|
||
|
|
#include <sys/time.h>
|
||
|
|
#endif
|
||
|
|
|
||
|
|
#if defined(OPENSSL_THREADS)
|
||
|
|
#include <thread>
|
||
|
|
#endif
|
||
|
|
|
||
|
|
BSSL_NAMESPACE_BEGIN
|
||
|
|
|
||
|
|
namespace {
|
||
|
|
|
||
|
|
INSTANTIATE_TEST_SUITE_P(SSLTests, SSLTest, testing::ValuesIn(kSSLTestParams),
|
||
|
|
[](const testing::TestParamInfo<SSLTestParam> &i) {
|
||
|
|
if (i.param.transfer_ssl) {
|
||
|
|
return "SSL_Transfer";
|
||
|
|
} else {
|
||
|
|
return "NO_SSL_Transfer";
|
||
|
|
}
|
||
|
|
});
|
||
|
|
|
||
|
|
static bssl::UniquePtr<SSL_CTX> CreateContextWithCertificate(
|
||
|
|
const SSL_METHOD *method, bssl::UniquePtr<X509> cert,
|
||
|
|
bssl::UniquePtr<EVP_PKEY> key) {
|
||
|
|
bssl::UniquePtr<SSL_CTX> ctx(SSL_CTX_new(method));
|
||
|
|
if (!ctx || !cert || !key ||
|
||
|
|
!SSL_CTX_use_certificate(ctx.get(), cert.get()) ||
|
||
|
|
!SSL_CTX_use_PrivateKey(ctx.get(), key.get())) {
|
||
|
|
return nullptr;
|
||
|
|
}
|
||
|
|
return ctx;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Test that |SSL_get_client_CA_list| echoes back the configured parameter even
|
||
|
|
// before configuring as a server.
|
||
|
|
TEST(SSLTest, ClientCAList) {
|
||
|
|
bssl::UniquePtr<SSL_CTX> ctx(SSL_CTX_new(TLS_method()));
|
||
|
|
ASSERT_TRUE(ctx);
|
||
|
|
bssl::UniquePtr<SSL> ssl(SSL_new(ctx.get()));
|
||
|
|
ASSERT_TRUE(ssl);
|
||
|
|
|
||
|
|
bssl::UniquePtr<X509_NAME> name(X509_NAME_new());
|
||
|
|
ASSERT_TRUE(name);
|
||
|
|
|
||
|
|
bssl::UniquePtr<X509_NAME> name_dup(X509_NAME_dup(name.get()));
|
||
|
|
ASSERT_TRUE(name_dup);
|
||
|
|
|
||
|
|
bssl::UniquePtr<STACK_OF(X509_NAME)> stack(sk_X509_NAME_new_null());
|
||
|
|
ASSERT_TRUE(stack);
|
||
|
|
ASSERT_TRUE(PushToStack(stack.get(), std::move(name_dup)));
|
||
|
|
|
||
|
|
// |SSL_set_client_CA_list| takes ownership.
|
||
|
|
SSL_set_client_CA_list(ssl.get(), stack.release());
|
||
|
|
|
||
|
|
STACK_OF(X509_NAME) *result = SSL_get_client_CA_list(ssl.get());
|
||
|
|
ASSERT_TRUE(result);
|
||
|
|
ASSERT_EQ(1u, sk_X509_NAME_num(result));
|
||
|
|
EXPECT_EQ(0, X509_NAME_cmp(sk_X509_NAME_value(result, 0), name.get()));
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST(SSLTest, AddClientCA) {
|
||
|
|
bssl::UniquePtr<SSL_CTX> ctx(SSL_CTX_new(TLS_method()));
|
||
|
|
ASSERT_TRUE(ctx);
|
||
|
|
bssl::UniquePtr<SSL> ssl(SSL_new(ctx.get()));
|
||
|
|
ASSERT_TRUE(ssl);
|
||
|
|
|
||
|
|
bssl::UniquePtr<X509> cert1 = GetTestCertificate();
|
||
|
|
bssl::UniquePtr<X509> cert2 = GetChainTestCertificate();
|
||
|
|
ASSERT_TRUE(cert1 && cert2);
|
||
|
|
X509_NAME *name1 = X509_get_subject_name(cert1.get());
|
||
|
|
X509_NAME *name2 = X509_get_subject_name(cert2.get());
|
||
|
|
|
||
|
|
EXPECT_EQ(0u, sk_X509_NAME_num(SSL_get_client_CA_list(ssl.get())));
|
||
|
|
|
||
|
|
ASSERT_TRUE(SSL_add_client_CA(ssl.get(), cert1.get()));
|
||
|
|
ASSERT_TRUE(SSL_add_client_CA(ssl.get(), cert2.get()));
|
||
|
|
|
||
|
|
STACK_OF(X509_NAME) *list = SSL_get_client_CA_list(ssl.get());
|
||
|
|
ASSERT_EQ(2u, sk_X509_NAME_num(list));
|
||
|
|
EXPECT_EQ(0, X509_NAME_cmp(sk_X509_NAME_value(list, 0), name1));
|
||
|
|
EXPECT_EQ(0, X509_NAME_cmp(sk_X509_NAME_value(list, 1), name2));
|
||
|
|
|
||
|
|
ASSERT_TRUE(SSL_add_client_CA(ssl.get(), cert1.get()));
|
||
|
|
|
||
|
|
list = SSL_get_client_CA_list(ssl.get());
|
||
|
|
ASSERT_EQ(3u, sk_X509_NAME_num(list));
|
||
|
|
EXPECT_EQ(0, X509_NAME_cmp(sk_X509_NAME_value(list, 0), name1));
|
||
|
|
EXPECT_EQ(0, X509_NAME_cmp(sk_X509_NAME_value(list, 1), name2));
|
||
|
|
EXPECT_EQ(0, X509_NAME_cmp(sk_X509_NAME_value(list, 2), name1));
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
TEST(SSLTest, TLS13ExporterAvailability) {
|
||
|
|
bssl::UniquePtr<SSL_CTX> client_ctx(SSL_CTX_new(TLS_method()));
|
||
|
|
bssl::UniquePtr<SSL_CTX> server_ctx =
|
||
|
|
CreateContextWithTestCertificate(TLS_method());
|
||
|
|
ASSERT_TRUE(client_ctx);
|
||
|
|
ASSERT_TRUE(server_ctx);
|
||
|
|
// Configure only TLS 1.3.
|
||
|
|
ASSERT_TRUE(SSL_CTX_set_min_proto_version(client_ctx.get(), TLS1_3_VERSION));
|
||
|
|
ASSERT_TRUE(SSL_CTX_set_max_proto_version(client_ctx.get(), TLS1_3_VERSION));
|
||
|
|
|
||
|
|
bssl::UniquePtr<SSL> client, server;
|
||
|
|
ASSERT_TRUE(CreateClientAndServer(&client, &server, client_ctx.get(),
|
||
|
|
server_ctx.get()));
|
||
|
|
|
||
|
|
std::vector<uint8_t> buffer(32);
|
||
|
|
const char *label = "EXPORTER-test-label";
|
||
|
|
|
||
|
|
// The exporters are not available before the handshake starts.
|
||
|
|
EXPECT_FALSE(SSL_export_keying_material(client.get(), buffer.data(),
|
||
|
|
buffer.size(), label, strlen(label),
|
||
|
|
nullptr, 0, 0));
|
||
|
|
EXPECT_FALSE(SSL_export_keying_material(server.get(), buffer.data(),
|
||
|
|
buffer.size(), label, strlen(label),
|
||
|
|
nullptr, 0, 0));
|
||
|
|
|
||
|
|
// Send the client's first flight of handshake messages.
|
||
|
|
int client_ret = SSL_do_handshake(client.get());
|
||
|
|
EXPECT_EQ(SSL_get_error(client.get(), client_ret), SSL_ERROR_WANT_READ);
|
||
|
|
|
||
|
|
// The handshake isn't far enough for the exporters to work.
|
||
|
|
EXPECT_FALSE(SSL_export_keying_material(client.get(), buffer.data(),
|
||
|
|
buffer.size(), label, strlen(label),
|
||
|
|
nullptr, 0, 0));
|
||
|
|
EXPECT_FALSE(SSL_export_keying_material(server.get(), buffer.data(),
|
||
|
|
buffer.size(), label, strlen(label),
|
||
|
|
nullptr, 0, 0));
|
||
|
|
|
||
|
|
// Send all the server's handshake messages.
|
||
|
|
int server_ret = SSL_do_handshake(server.get());
|
||
|
|
EXPECT_EQ(SSL_get_error(server.get(), server_ret), SSL_ERROR_WANT_READ);
|
||
|
|
|
||
|
|
// At this point in the handshake, the server should have the exporter key
|
||
|
|
// derived since it's sent its Finished message. The client hasn't yet
|
||
|
|
// processed the server's handshake messages, so the exporter shouldn't be
|
||
|
|
// available to the client.
|
||
|
|
EXPECT_FALSE(SSL_export_keying_material(client.get(), buffer.data(),
|
||
|
|
buffer.size(), label, strlen(label),
|
||
|
|
nullptr, 0, 0));
|
||
|
|
EXPECT_TRUE(SSL_export_keying_material(server.get(), buffer.data(),
|
||
|
|
buffer.size(), label, strlen(label),
|
||
|
|
nullptr, 0, 0));
|
||
|
|
|
||
|
|
// Finish the handshake on the client.
|
||
|
|
EXPECT_EQ(SSL_do_handshake(client.get()), 1);
|
||
|
|
|
||
|
|
// The exporter should be available on both endpoints.
|
||
|
|
EXPECT_TRUE(SSL_export_keying_material(client.get(), buffer.data(),
|
||
|
|
buffer.size(), label, strlen(label),
|
||
|
|
nullptr, 0, 0));
|
||
|
|
EXPECT_TRUE(SSL_export_keying_material(server.get(), buffer.data(),
|
||
|
|
buffer.size(), label, strlen(label),
|
||
|
|
nullptr, 0, 0));
|
||
|
|
|
||
|
|
// Finish the handshake on the server.
|
||
|
|
EXPECT_EQ(SSL_do_handshake(server.get()), 1);
|
||
|
|
|
||
|
|
// The exporter should still be available on both endpoints.
|
||
|
|
EXPECT_TRUE(SSL_export_keying_material(client.get(), buffer.data(),
|
||
|
|
buffer.size(), label, strlen(label),
|
||
|
|
nullptr, 0, 0));
|
||
|
|
EXPECT_TRUE(SSL_export_keying_material(server.get(), buffer.data(),
|
||
|
|
buffer.size(), label, strlen(label),
|
||
|
|
nullptr, 0, 0));
|
||
|
|
}
|
||
|
|
|
||
|
|
static void AppendSession(SSL_SESSION *session, void *arg) {
|
||
|
|
std::vector<SSL_SESSION *> *out =
|
||
|
|
reinterpret_cast<std::vector<SSL_SESSION *> *>(arg);
|
||
|
|
out->push_back(session);
|
||
|
|
}
|
||
|
|
|
||
|
|
// CacheEquals returns true if |ctx|'s session cache consists of |expected|, in
|
||
|
|
// order.
|
||
|
|
static bool CacheEquals(SSL_CTX *ctx,
|
||
|
|
const std::vector<SSL_SESSION *> &expected) {
|
||
|
|
// Check the linked list.
|
||
|
|
SSL_SESSION *ptr = ctx->session_cache_head;
|
||
|
|
for (SSL_SESSION *session : expected) {
|
||
|
|
if (ptr != session) {
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
// Redundant w/ above, but avoids static analysis failure
|
||
|
|
if (ptr == nullptr) {
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
// TODO(davidben): This is an absurd way to denote the end of the list.
|
||
|
|
if (ptr->next ==
|
||
|
|
reinterpret_cast<SSL_SESSION *>(&ctx->session_cache_tail)) {
|
||
|
|
ptr = nullptr;
|
||
|
|
} else {
|
||
|
|
ptr = ptr->next;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
if (ptr != nullptr) {
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Check the hash table.
|
||
|
|
std::vector<SSL_SESSION *> actual, expected_copy;
|
||
|
|
lh_SSL_SESSION_doall_arg(ctx->sessions, AppendSession, &actual);
|
||
|
|
expected_copy = expected;
|
||
|
|
|
||
|
|
std::sort(actual.begin(), actual.end());
|
||
|
|
std::sort(expected_copy.begin(), expected_copy.end());
|
||
|
|
|
||
|
|
return actual == expected_copy;
|
||
|
|
}
|
||
|
|
|
||
|
|
static bssl::UniquePtr<SSL_SESSION> CreateTestSession(uint32_t number) {
|
||
|
|
bssl::UniquePtr<SSL_CTX> ssl_ctx(SSL_CTX_new(TLS_method()));
|
||
|
|
if (!ssl_ctx) {
|
||
|
|
return nullptr;
|
||
|
|
}
|
||
|
|
bssl::UniquePtr<SSL_SESSION> ret(SSL_SESSION_new(ssl_ctx.get()));
|
||
|
|
if (!ret) {
|
||
|
|
return nullptr;
|
||
|
|
}
|
||
|
|
|
||
|
|
uint8_t id[SSL3_SSL_SESSION_ID_LENGTH] = {0};
|
||
|
|
OPENSSL_memcpy(id, &number, sizeof(number));
|
||
|
|
if (!SSL_SESSION_set1_id(ret.get(), id, sizeof(id))) {
|
||
|
|
return nullptr;
|
||
|
|
}
|
||
|
|
return ret;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Test that the internal session cache behaves as expected.
|
||
|
|
TEST(SSLTest, InternalSessionCache) {
|
||
|
|
bssl::UniquePtr<SSL_CTX> ctx(SSL_CTX_new(TLS_method()));
|
||
|
|
ASSERT_TRUE(ctx);
|
||
|
|
|
||
|
|
// Prepare 10 test sessions.
|
||
|
|
std::vector<bssl::UniquePtr<SSL_SESSION>> sessions;
|
||
|
|
for (int i = 0; i < 10; i++) {
|
||
|
|
bssl::UniquePtr<SSL_SESSION> session = CreateTestSession(i);
|
||
|
|
ASSERT_TRUE(session);
|
||
|
|
sessions.push_back(std::move(session));
|
||
|
|
}
|
||
|
|
|
||
|
|
SSL_CTX_sess_set_cache_size(ctx.get(), 5);
|
||
|
|
|
||
|
|
// Insert all the test sessions.
|
||
|
|
for (const auto &session : sessions) {
|
||
|
|
ASSERT_TRUE(SSL_CTX_add_session(ctx.get(), session.get()));
|
||
|
|
}
|
||
|
|
|
||
|
|
// Only the last five should be in the list.
|
||
|
|
ASSERT_TRUE(CacheEquals(
|
||
|
|
ctx.get(), {sessions[9].get(), sessions[8].get(), sessions[7].get(),
|
||
|
|
sessions[6].get(), sessions[5].get()}));
|
||
|
|
|
||
|
|
// Inserting an element already in the cache should fail and leave the cache
|
||
|
|
// unchanged.
|
||
|
|
ASSERT_FALSE(SSL_CTX_add_session(ctx.get(), sessions[7].get()));
|
||
|
|
ASSERT_TRUE(CacheEquals(
|
||
|
|
ctx.get(), {sessions[9].get(), sessions[8].get(), sessions[7].get(),
|
||
|
|
sessions[6].get(), sessions[5].get()}));
|
||
|
|
|
||
|
|
// Although collisions should be impossible (256-bit session IDs), the cache
|
||
|
|
// must handle them gracefully.
|
||
|
|
bssl::UniquePtr<SSL_SESSION> collision(CreateTestSession(7));
|
||
|
|
ASSERT_TRUE(collision);
|
||
|
|
ASSERT_TRUE(SSL_CTX_add_session(ctx.get(), collision.get()));
|
||
|
|
ASSERT_TRUE(CacheEquals(
|
||
|
|
ctx.get(), {collision.get(), sessions[9].get(), sessions[8].get(),
|
||
|
|
sessions[6].get(), sessions[5].get()}));
|
||
|
|
|
||
|
|
// Removing sessions behaves correctly.
|
||
|
|
ASSERT_TRUE(SSL_CTX_remove_session(ctx.get(), sessions[6].get()));
|
||
|
|
ASSERT_TRUE(CacheEquals(ctx.get(), {collision.get(), sessions[9].get(),
|
||
|
|
sessions[8].get(), sessions[5].get()}));
|
||
|
|
|
||
|
|
// Removing sessions requires an exact match.
|
||
|
|
ASSERT_FALSE(SSL_CTX_remove_session(ctx.get(), sessions[0].get()));
|
||
|
|
ASSERT_FALSE(SSL_CTX_remove_session(ctx.get(), sessions[7].get()));
|
||
|
|
|
||
|
|
// The cache remains unchanged.
|
||
|
|
ASSERT_TRUE(CacheEquals(ctx.get(), {collision.get(), sessions[9].get(),
|
||
|
|
sessions[8].get(), sessions[5].get()}));
|
||
|
|
}
|
||
|
|
|
||
|
|
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,
|
||
|
|
};
|
||
|
|
|
||
|
|
// Test that, after seeing TLS 1.2 in response to early data, |SSL_write|
|
||
|
|
// continues to report |SSL_R_WRONG_VERSION_ON_EARLY_DATA|. See
|
||
|
|
// https://crbug.com/1078515.
|
||
|
|
TEST(SSLTest, WriteAfterWrongVersionOnEarlyData) {
|
||
|
|
// Set up some 0-RTT-enabled contexts.
|
||
|
|
bssl::UniquePtr<SSL_CTX> client_ctx(SSL_CTX_new(TLS_method()));
|
||
|
|
bssl::UniquePtr<SSL_CTX> server_ctx =
|
||
|
|
CreateContextWithTestCertificate(TLS_method());
|
||
|
|
ASSERT_TRUE(client_ctx);
|
||
|
|
ASSERT_TRUE(server_ctx);
|
||
|
|
SSL_CTX_set_early_data_enabled(client_ctx.get(), 1);
|
||
|
|
SSL_CTX_set_early_data_enabled(server_ctx.get(), 1);
|
||
|
|
SSL_CTX_set_session_cache_mode(client_ctx.get(), SSL_SESS_CACHE_BOTH);
|
||
|
|
SSL_CTX_set_session_cache_mode(server_ctx.get(), SSL_SESS_CACHE_BOTH);
|
||
|
|
|
||
|
|
// Get an early-data-capable session.
|
||
|
|
bssl::UniquePtr<SSL_SESSION> session =
|
||
|
|
CreateClientSession(client_ctx.get(), server_ctx.get());
|
||
|
|
ASSERT_TRUE(session);
|
||
|
|
EXPECT_TRUE(SSL_SESSION_early_data_capable(session.get()));
|
||
|
|
|
||
|
|
// Offer the session to the server, but now the server speaks TLS 1.2.
|
||
|
|
bssl::UniquePtr<SSL> client, server;
|
||
|
|
ASSERT_TRUE(CreateClientAndServer(&client, &server, client_ctx.get(),
|
||
|
|
server_ctx.get()));
|
||
|
|
SSL_set_session(client.get(), session.get());
|
||
|
|
EXPECT_TRUE(SSL_set_max_proto_version(server.get(), TLS1_2_VERSION));
|
||
|
|
|
||
|
|
// The client handshake initially succeeds in the early data state.
|
||
|
|
EXPECT_EQ(1, SSL_do_handshake(client.get()));
|
||
|
|
EXPECT_TRUE(SSL_in_early_data(client.get()));
|
||
|
|
|
||
|
|
// The server processes the ClientHello and negotiates TLS 1.2.
|
||
|
|
EXPECT_EQ(-1, SSL_do_handshake(server.get()));
|
||
|
|
EXPECT_EQ(SSL_ERROR_WANT_READ, SSL_get_error(server.get(), -1));
|
||
|
|
EXPECT_EQ(TLS1_2_VERSION, SSL_version(server.get()));
|
||
|
|
|
||
|
|
// Capture the client's output.
|
||
|
|
bssl::UniquePtr<BIO> mem(BIO_new(BIO_s_mem()));
|
||
|
|
ASSERT_TRUE(mem);
|
||
|
|
SSL_set0_wbio(client.get(), bssl::UpRef(mem).release());
|
||
|
|
|
||
|
|
// The client processes the ServerHello and fails.
|
||
|
|
EXPECT_EQ(-1, SSL_do_handshake(client.get()));
|
||
|
|
EXPECT_EQ(SSL_ERROR_SSL, SSL_get_error(client.get(), -1));
|
||
|
|
EXPECT_TRUE(ErrorEquals(ERR_get_error(), ERR_LIB_SSL,
|
||
|
|
SSL_R_WRONG_VERSION_ON_EARLY_DATA));
|
||
|
|
|
||
|
|
// The client should have written an alert to the transport.
|
||
|
|
const uint8_t *unused = nullptr;
|
||
|
|
size_t len = 0;
|
||
|
|
ASSERT_TRUE(BIO_mem_contents(mem.get(), &unused, &len));
|
||
|
|
EXPECT_NE(0u, len);
|
||
|
|
EXPECT_TRUE(BIO_reset(mem.get()));
|
||
|
|
|
||
|
|
// Writing should fail, with the same error as the handshake.
|
||
|
|
EXPECT_EQ(-1, SSL_write(client.get(), "a", 1));
|
||
|
|
EXPECT_EQ(SSL_ERROR_SSL, SSL_get_error(client.get(), -1));
|
||
|
|
EXPECT_TRUE(ErrorEquals(ERR_get_error(), ERR_LIB_SSL,
|
||
|
|
SSL_R_WRONG_VERSION_ON_EARLY_DATA));
|
||
|
|
|
||
|
|
// Nothing should be written to the transport.
|
||
|
|
ASSERT_TRUE(BIO_mem_contents(mem.get(), &unused, &len));
|
||
|
|
EXPECT_EQ(0u, len);
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST(SSLTest, SessionDuplication) {
|
||
|
|
bssl::UniquePtr<SSL_CTX> client_ctx(SSL_CTX_new(TLS_method()));
|
||
|
|
bssl::UniquePtr<SSL_CTX> server_ctx =
|
||
|
|
CreateContextWithTestCertificate(TLS_method());
|
||
|
|
ASSERT_TRUE(client_ctx);
|
||
|
|
ASSERT_TRUE(server_ctx);
|
||
|
|
|
||
|
|
bssl::UniquePtr<SSL> client, server;
|
||
|
|
ASSERT_TRUE(ConnectClientAndServer(&client, &server, client_ctx.get(),
|
||
|
|
server_ctx.get()));
|
||
|
|
|
||
|
|
SSL_SESSION *session0 = SSL_get_session(client.get());
|
||
|
|
bssl::UniquePtr<SSL_SESSION> session1 =
|
||
|
|
bssl::SSL_SESSION_dup(session0, SSL_SESSION_DUP_ALL);
|
||
|
|
ASSERT_TRUE(session1);
|
||
|
|
|
||
|
|
session1->not_resumable = false;
|
||
|
|
|
||
|
|
uint8_t *s0_bytes = nullptr, *s1_bytes = nullptr;
|
||
|
|
size_t s0_len = 0, s1_len = 0;
|
||
|
|
|
||
|
|
ASSERT_TRUE(SSL_SESSION_to_bytes(session0, &s0_bytes, &s0_len));
|
||
|
|
bssl::UniquePtr<uint8_t> free_s0(s0_bytes);
|
||
|
|
|
||
|
|
ASSERT_TRUE(SSL_SESSION_to_bytes(session1.get(), &s1_bytes, &s1_len));
|
||
|
|
bssl::UniquePtr<uint8_t> free_s1(s1_bytes);
|
||
|
|
|
||
|
|
EXPECT_EQ(Bytes(s0_bytes, s0_len), Bytes(s1_bytes, s1_len));
|
||
|
|
}
|
||
|
|
|
||
|
|
static void ExpectFDs(const SSL *ssl, int rfd, int wfd) {
|
||
|
|
EXPECT_EQ(rfd, SSL_get_fd(ssl));
|
||
|
|
EXPECT_EQ(rfd, SSL_get_rfd(ssl));
|
||
|
|
EXPECT_EQ(wfd, SSL_get_wfd(ssl));
|
||
|
|
|
||
|
|
// The wrapper BIOs are always equal when fds are equal, even if set
|
||
|
|
// individually.
|
||
|
|
if (rfd == wfd) {
|
||
|
|
EXPECT_EQ(SSL_get_rbio(ssl), SSL_get_wbio(ssl));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST(SSLTest, SetFD) {
|
||
|
|
bssl::UniquePtr<SSL_CTX> ctx(SSL_CTX_new(TLS_method()));
|
||
|
|
ASSERT_TRUE(ctx);
|
||
|
|
|
||
|
|
// Test setting different read and write FDs.
|
||
|
|
bssl::UniquePtr<SSL> ssl(SSL_new(ctx.get()));
|
||
|
|
ASSERT_TRUE(ssl);
|
||
|
|
EXPECT_TRUE(SSL_set_rfd(ssl.get(), 1));
|
||
|
|
EXPECT_TRUE(SSL_set_wfd(ssl.get(), 2));
|
||
|
|
ExpectFDs(ssl.get(), 1, 2);
|
||
|
|
|
||
|
|
// Test setting the same FD.
|
||
|
|
ssl.reset(SSL_new(ctx.get()));
|
||
|
|
ASSERT_TRUE(ssl);
|
||
|
|
EXPECT_TRUE(SSL_set_fd(ssl.get(), 1));
|
||
|
|
ExpectFDs(ssl.get(), 1, 1);
|
||
|
|
|
||
|
|
// Test setting the same FD one side at a time.
|
||
|
|
ssl.reset(SSL_new(ctx.get()));
|
||
|
|
ASSERT_TRUE(ssl);
|
||
|
|
EXPECT_TRUE(SSL_set_rfd(ssl.get(), 1));
|
||
|
|
EXPECT_TRUE(SSL_set_wfd(ssl.get(), 1));
|
||
|
|
ExpectFDs(ssl.get(), 1, 1);
|
||
|
|
|
||
|
|
// Test setting the same FD in the other order.
|
||
|
|
ssl.reset(SSL_new(ctx.get()));
|
||
|
|
ASSERT_TRUE(ssl);
|
||
|
|
EXPECT_TRUE(SSL_set_wfd(ssl.get(), 1));
|
||
|
|
EXPECT_TRUE(SSL_set_rfd(ssl.get(), 1));
|
||
|
|
ExpectFDs(ssl.get(), 1, 1);
|
||
|
|
|
||
|
|
// Test changing the read FD partway through.
|
||
|
|
ssl.reset(SSL_new(ctx.get()));
|
||
|
|
ASSERT_TRUE(ssl);
|
||
|
|
EXPECT_TRUE(SSL_set_fd(ssl.get(), 1));
|
||
|
|
EXPECT_TRUE(SSL_set_rfd(ssl.get(), 2));
|
||
|
|
ExpectFDs(ssl.get(), 2, 1);
|
||
|
|
|
||
|
|
// Test changing the write FD partway through.
|
||
|
|
ssl.reset(SSL_new(ctx.get()));
|
||
|
|
ASSERT_TRUE(ssl);
|
||
|
|
EXPECT_TRUE(SSL_set_fd(ssl.get(), 1));
|
||
|
|
EXPECT_TRUE(SSL_set_wfd(ssl.get(), 2));
|
||
|
|
ExpectFDs(ssl.get(), 1, 2);
|
||
|
|
|
||
|
|
// Test a no-op change to the read FD partway through.
|
||
|
|
ssl.reset(SSL_new(ctx.get()));
|
||
|
|
ASSERT_TRUE(ssl);
|
||
|
|
EXPECT_TRUE(SSL_set_fd(ssl.get(), 1));
|
||
|
|
EXPECT_TRUE(SSL_set_rfd(ssl.get(), 1));
|
||
|
|
ExpectFDs(ssl.get(), 1, 1);
|
||
|
|
|
||
|
|
// Test a no-op change to the write FD partway through.
|
||
|
|
ssl.reset(SSL_new(ctx.get()));
|
||
|
|
ASSERT_TRUE(ssl);
|
||
|
|
EXPECT_TRUE(SSL_set_fd(ssl.get(), 1));
|
||
|
|
EXPECT_TRUE(SSL_set_wfd(ssl.get(), 1));
|
||
|
|
ExpectFDs(ssl.get(), 1, 1);
|
||
|
|
|
||
|
|
// ASan builds will implicitly test that the internal |BIO| reference-counting
|
||
|
|
// is correct.
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST(SSLTest, SetBIO) {
|
||
|
|
bssl::UniquePtr<SSL_CTX> ctx(SSL_CTX_new(TLS_method()));
|
||
|
|
ASSERT_TRUE(ctx);
|
||
|
|
|
||
|
|
bssl::UniquePtr<SSL> ssl(SSL_new(ctx.get()));
|
||
|
|
bssl::UniquePtr<BIO> bio1(BIO_new(BIO_s_mem())), bio2(BIO_new(BIO_s_mem())),
|
||
|
|
bio3(BIO_new(BIO_s_mem()));
|
||
|
|
ASSERT_TRUE(ssl);
|
||
|
|
ASSERT_TRUE(bio1);
|
||
|
|
ASSERT_TRUE(bio2);
|
||
|
|
ASSERT_TRUE(bio3);
|
||
|
|
|
||
|
|
// SSL_set_bio takes one reference when the parameters are the same.
|
||
|
|
BIO_up_ref(bio1.get());
|
||
|
|
SSL_set_bio(ssl.get(), bio1.get(), bio1.get());
|
||
|
|
|
||
|
|
// Repeating the call does nothing.
|
||
|
|
SSL_set_bio(ssl.get(), bio1.get(), bio1.get());
|
||
|
|
|
||
|
|
// It takes one reference each when the parameters are different.
|
||
|
|
BIO_up_ref(bio2.get());
|
||
|
|
BIO_up_ref(bio3.get());
|
||
|
|
SSL_set_bio(ssl.get(), bio2.get(), bio3.get());
|
||
|
|
|
||
|
|
// Repeating the call does nothing.
|
||
|
|
SSL_set_bio(ssl.get(), bio2.get(), bio3.get());
|
||
|
|
|
||
|
|
// It takes one reference when changing only wbio.
|
||
|
|
BIO_up_ref(bio1.get());
|
||
|
|
SSL_set_bio(ssl.get(), bio2.get(), bio1.get());
|
||
|
|
|
||
|
|
// It takes one reference when changing only rbio and the two are different.
|
||
|
|
BIO_up_ref(bio3.get());
|
||
|
|
SSL_set_bio(ssl.get(), bio3.get(), bio1.get());
|
||
|
|
|
||
|
|
// If setting wbio to rbio, it takes no additional references.
|
||
|
|
SSL_set_bio(ssl.get(), bio3.get(), bio3.get());
|
||
|
|
|
||
|
|
// From there, wbio may be switched to something else.
|
||
|
|
BIO_up_ref(bio1.get());
|
||
|
|
SSL_set_bio(ssl.get(), bio3.get(), bio1.get());
|
||
|
|
|
||
|
|
// If setting rbio to wbio, it takes no additional references.
|
||
|
|
SSL_set_bio(ssl.get(), bio1.get(), bio1.get());
|
||
|
|
|
||
|
|
// From there, rbio may be switched to something else, but, for historical
|
||
|
|
// reasons, it takes a reference to both parameters.
|
||
|
|
BIO_up_ref(bio1.get());
|
||
|
|
BIO_up_ref(bio2.get());
|
||
|
|
SSL_set_bio(ssl.get(), bio2.get(), bio1.get());
|
||
|
|
|
||
|
|
// ASAN builds will implicitly test that the internal |BIO| reference-counting
|
||
|
|
// is correct.
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
// Tests that our ClientHellos do not change unexpectedly. These are purely
|
||
|
|
// change detection tests. If they fail as part of an intentional ClientHello
|
||
|
|
// change, update the test vector.
|
||
|
|
TEST(SSLTest, ClientHello) {
|
||
|
|
struct {
|
||
|
|
uint16_t max_version;
|
||
|
|
std::vector<uint8_t> expected;
|
||
|
|
} kTests[] = {
|
||
|
|
{TLS1_VERSION,
|
||
|
|
{0x16, 0x03, 0x01, 0x00, 0x58, 0x01, 0x00, 0x00, 0x54, 0x03, 0x01, 0x00,
|
||
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0xc0, 0x09,
|
||
|
|
0xc0, 0x13, 0xc0, 0x0a, 0xc0, 0x14, 0x00, 0x2f, 0x00, 0x35, 0x01, 0x00,
|
||
|
|
0x00, 0x1f, 0x00, 0x17, 0x00, 0x00, 0xff, 0x01, 0x00, 0x01, 0x00, 0x00,
|
||
|
|
0x0a, 0x00, 0x08, 0x00, 0x06, 0x00, 0x1d, 0x00, 0x17, 0x00, 0x18, 0x00,
|
||
|
|
0x0b, 0x00, 0x02, 0x01, 0x00, 0x00, 0x23, 0x00, 0x00}},
|
||
|
|
{TLS1_1_VERSION,
|
||
|
|
{0x16, 0x03, 0x01, 0x00, 0x58, 0x01, 0x00, 0x00, 0x54, 0x03, 0x02, 0x00,
|
||
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0xc0, 0x09,
|
||
|
|
0xc0, 0x13, 0xc0, 0x0a, 0xc0, 0x14, 0x00, 0x2f, 0x00, 0x35, 0x01, 0x00,
|
||
|
|
0x00, 0x1f, 0x00, 0x17, 0x00, 0x00, 0xff, 0x01, 0x00, 0x01, 0x00, 0x00,
|
||
|
|
0x0a, 0x00, 0x08, 0x00, 0x06, 0x00, 0x1d, 0x00, 0x17, 0x00, 0x18, 0x00,
|
||
|
|
0x0b, 0x00, 0x02, 0x01, 0x00, 0x00, 0x23, 0x00, 0x00}},
|
||
|
|
{TLS1_2_VERSION,
|
||
|
|
{0x16, 0x03, 0x01, 0x00, 0x88, 0x01, 0x00, 0x00, 0x84, 0x03, 0x03, 0x00,
|
||
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0xcc, 0xa9,
|
||
|
|
0xcc, 0xa8, 0xc0, 0x2b, 0xc0, 0x2f, 0xc0, 0x2c, 0xc0, 0x30, 0xc0, 0x09,
|
||
|
|
0xc0, 0x13, 0xc0, 0x27, 0xc0, 0x0a, 0xc0, 0x14, 0xc0, 0x28, 0x00, 0x9c,
|
||
|
|
0x00, 0x9d, 0x00, 0x2f, 0x00, 0x3c, 0x00, 0x35, 0x01, 0x00, 0x00, 0x39,
|
||
|
|
0x00, 0x17, 0x00, 0x00, 0xff, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0a, 0x00,
|
||
|
|
0x08, 0x00, 0x06, 0x00, 0x1d, 0x00, 0x17, 0x00, 0x18, 0x00, 0x0b, 0x00,
|
||
|
|
0x02, 0x01, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x16, 0x00,
|
||
|
|
0x14, 0x04, 0x03, 0x08, 0x04, 0x04, 0x01, 0x05, 0x03, 0x08, 0x05, 0x05,
|
||
|
|
0x01, 0x06, 0x03, 0x08, 0x06, 0x06, 0x01, 0x02, 0x01}},
|
||
|
|
{TLS1_3_VERSION,
|
||
|
|
{0x16, 0x03, 0x01, 0x05, 0xb5, 0x01, 0x00, 0x05, 0xb1, 0x03, 0x03, 0x00,
|
||
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x13, 0x01, 0x13, 0x02, 0x13, 0x03,
|
||
|
|
0xcc, 0xa9, 0xcc, 0xa8, 0xc0, 0x2b, 0xc0, 0x2f, 0xc0, 0x2c, 0xc0, 0x30,
|
||
|
|
0xc0, 0x09, 0xc0, 0x13, 0xc0, 0x27, 0xc0, 0x0a, 0xc0, 0x14, 0xc0, 0x28,
|
||
|
|
0x00, 0x9c, 0x00, 0x9d, 0x00, 0x2f, 0x00, 0x3c, 0x00, 0x35, 0x01, 0x00,
|
||
|
|
0x05, 0x40, 0x00, 0x17, 0x00, 0x00, 0xff, 0x01, 0x00, 0x01, 0x00, 0x00,
|
||
|
|
0x0a, 0x00, 0x0e, 0x00, 0x0c, 0x11, 0xec, 0x11, 0xeb, 0x11, 0xed, 0x00,
|
||
|
|
0x1d, 0x00, 0x17, 0x00, 0x18, 0x00, 0x0b, 0x00, 0x02, 0x01, 0x00, 0x00,
|
||
|
|
0x23, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x16, 0x00, 0x14, 0x04, 0x03, 0x08,
|
||
|
|
0x04, 0x04, 0x01, 0x05, 0x03, 0x08, 0x05, 0x05, 0x01, 0x06, 0x03, 0x08,
|
||
|
|
0x06, 0x06, 0x01, 0x02, 0x01, 0x00, 0x33, 0x04, 0xea, 0x04, 0xe8, 0x11,
|
||
|
|
0xec, 0x04, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x20, 0x00,
|
||
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2d, 0x00, 0x02, 0x01,
|
||
|
|
0x01, 0x00, 0x2b, 0x00, 0x09, 0x08, 0x03, 0x04, 0x03, 0x03, 0x03, 0x02,
|
||
|
|
0x03, 0x01}},
|
||
|
|
};
|
||
|
|
|
||
|
|
for (const auto &t : kTests) {
|
||
|
|
SCOPED_TRACE(t.max_version);
|
||
|
|
|
||
|
|
bssl::UniquePtr<SSL_CTX> ctx(SSL_CTX_new(TLS_method()));
|
||
|
|
ASSERT_TRUE(ctx);
|
||
|
|
// Our default cipher list varies by CPU capabilities, so manually place the
|
||
|
|
// ChaCha20 ciphers in front.
|
||
|
|
const char *cipher_list = "CHACHA20:ALL";
|
||
|
|
ASSERT_TRUE(SSL_CTX_set_max_proto_version(ctx.get(), t.max_version));
|
||
|
|
ASSERT_TRUE(SSL_CTX_set_strict_cipher_list(ctx.get(), cipher_list));
|
||
|
|
|
||
|
|
// Explicitly set TLS 1.3 ciphersuites so CPU capabilities don't affect
|
||
|
|
// order
|
||
|
|
ASSERT_TRUE(
|
||
|
|
SSL_CTX_set_ciphersuites(ctx.get(), TLS13_DEFAULT_CIPHER_LIST_AES_HW));
|
||
|
|
|
||
|
|
bssl::UniquePtr<SSL> ssl(SSL_new(ctx.get()));
|
||
|
|
ASSERT_TRUE(ssl);
|
||
|
|
std::vector<uint8_t> client_hello;
|
||
|
|
ASSERT_TRUE(GetClientHello(ssl.get(), &client_hello));
|
||
|
|
|
||
|
|
// Zero the client_random.
|
||
|
|
constexpr size_t kRandomOffset = 1 + 2 + 2 + // record header
|
||
|
|
1 + 3 + // handshake message header
|
||
|
|
2; // client_version
|
||
|
|
|
||
|
|
constexpr size_t kKeyShare1Offset = 195;
|
||
|
|
constexpr size_t kKeyShare1Size = 32 + MLKEM768_PUBLIC_KEY_BYTES;
|
||
|
|
constexpr size_t kKeyShare2Offset = kKeyShare1Offset + kKeyShare1Size
|
||
|
|
+ 2 // KeyShare 2 IANA ID
|
||
|
|
+ 2; // KeyShare 2 Length
|
||
|
|
constexpr size_t kKeyShare2Size = 32;
|
||
|
|
|
||
|
|
int pre = client_hello.size();
|
||
|
|
if (t.max_version == TLS1_3_VERSION) {
|
||
|
|
ASSERT_GE(client_hello.size(),
|
||
|
|
kRandomOffset + SSL3_RANDOM_SIZE + 1 + SSL3_SESSION_ID_SIZE);
|
||
|
|
OPENSSL_memset(client_hello.data() + kRandomOffset, 0,
|
||
|
|
SSL3_RANDOM_SIZE + 1 + SSL3_SESSION_ID_SIZE);
|
||
|
|
// Jump to key share extension and zero out the key
|
||
|
|
OPENSSL_memset(client_hello.data() + kKeyShare1Offset, 0, kKeyShare1Size);
|
||
|
|
OPENSSL_memset(client_hello.data() + kKeyShare2Offset, 0, kKeyShare2Size);
|
||
|
|
} else {
|
||
|
|
ASSERT_GE(client_hello.size(), kRandomOffset + SSL3_RANDOM_SIZE);
|
||
|
|
OPENSSL_memset(client_hello.data() + kRandomOffset, 0, SSL3_RANDOM_SIZE);
|
||
|
|
}
|
||
|
|
int post = client_hello.size();
|
||
|
|
ASSERT_EQ(pre, post);
|
||
|
|
|
||
|
|
if (client_hello != t.expected) {
|
||
|
|
ADD_FAILURE() << "ClientHellos did not match.";
|
||
|
|
// Print the value manually so it is easier to update the test vector.
|
||
|
|
for (size_t i = 0; i < client_hello.size(); i += 12) {
|
||
|
|
printf(" %c", i == 0 ? '{' : ' ');
|
||
|
|
for (size_t j = i; j < client_hello.size() && j < i + 12; j++) {
|
||
|
|
if (j > i) {
|
||
|
|
printf(" ");
|
||
|
|
}
|
||
|
|
printf("0x%02x", client_hello[j]);
|
||
|
|
if (j < client_hello.size() - 1) {
|
||
|
|
printf(",");
|
||
|
|
}
|
||
|
|
}
|
||
|
|
if (i + 12 >= client_hello.size()) {
|
||
|
|
printf("}},");
|
||
|
|
}
|
||
|
|
printf("\n");
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
// Test that the early callback can swap the maximum version.
|
||
|
|
TEST(SSLTest, EarlyCallbackVersionSwitch) {
|
||
|
|
bssl::UniquePtr<SSL_CTX> server_ctx =
|
||
|
|
CreateContextWithTestCertificate(TLS_method());
|
||
|
|
bssl::UniquePtr<SSL_CTX> client_ctx(SSL_CTX_new(TLS_method()));
|
||
|
|
ASSERT_TRUE(server_ctx);
|
||
|
|
ASSERT_TRUE(client_ctx);
|
||
|
|
ASSERT_TRUE(SSL_CTX_set_max_proto_version(client_ctx.get(), TLS1_3_VERSION));
|
||
|
|
ASSERT_TRUE(SSL_CTX_set_max_proto_version(server_ctx.get(), TLS1_3_VERSION));
|
||
|
|
|
||
|
|
SSL_CTX_set_select_certificate_cb(
|
||
|
|
server_ctx.get(),
|
||
|
|
[](const SSL_CLIENT_HELLO *client_hello) -> ssl_select_cert_result_t {
|
||
|
|
if (!SSL_set_max_proto_version(client_hello->ssl, TLS1_2_VERSION)) {
|
||
|
|
return ssl_select_cert_error;
|
||
|
|
}
|
||
|
|
|
||
|
|
return ssl_select_cert_success;
|
||
|
|
});
|
||
|
|
|
||
|
|
bssl::UniquePtr<SSL> client, server;
|
||
|
|
ASSERT_TRUE(ConnectClientAndServer(&client, &server, client_ctx.get(),
|
||
|
|
server_ctx.get()));
|
||
|
|
EXPECT_EQ(TLS1_2_VERSION, SSL_version(client.get()));
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST(SSLTest, SetVersion) {
|
||
|
|
bssl::UniquePtr<SSL_CTX> ctx(SSL_CTX_new(TLS_method()));
|
||
|
|
ASSERT_TRUE(ctx);
|
||
|
|
bssl::UniquePtr<SSL> ssl(SSL_new(ctx.get()));
|
||
|
|
ASSERT_TRUE(ssl);
|
||
|
|
|
||
|
|
// Set valid TLS versions.
|
||
|
|
for (const auto &vers : kAllVersions) {
|
||
|
|
SCOPED_TRACE(vers.name);
|
||
|
|
if (vers.ssl_method == VersionParam::is_tls) {
|
||
|
|
EXPECT_TRUE(SSL_CTX_set_max_proto_version(ctx.get(), vers.version));
|
||
|
|
EXPECT_EQ(SSL_CTX_get_max_proto_version(ctx.get()), vers.version);
|
||
|
|
EXPECT_TRUE(SSL_CTX_set_min_proto_version(ctx.get(), vers.version));
|
||
|
|
EXPECT_EQ(SSL_CTX_get_min_proto_version(ctx.get()), vers.version);
|
||
|
|
EXPECT_TRUE(SSL_set_max_proto_version(ssl.get(), vers.version));
|
||
|
|
EXPECT_EQ(SSL_get_max_proto_version(ssl.get()), vers.version);
|
||
|
|
EXPECT_TRUE(SSL_set_min_proto_version(ssl.get(), vers.version));
|
||
|
|
EXPECT_EQ(SSL_get_min_proto_version(ssl.get()), vers.version);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// Invalid TLS versions are rejected.
|
||
|
|
EXPECT_FALSE(SSL_CTX_set_max_proto_version(ctx.get(), DTLS1_VERSION));
|
||
|
|
EXPECT_FALSE(SSL_CTX_set_max_proto_version(ctx.get(), 0x0200));
|
||
|
|
EXPECT_FALSE(SSL_CTX_set_max_proto_version(ctx.get(), 0x1234));
|
||
|
|
EXPECT_FALSE(SSL_CTX_set_min_proto_version(ctx.get(), DTLS1_VERSION));
|
||
|
|
EXPECT_FALSE(SSL_CTX_set_min_proto_version(ctx.get(), 0x0200));
|
||
|
|
EXPECT_FALSE(SSL_CTX_set_min_proto_version(ctx.get(), 0x1234));
|
||
|
|
EXPECT_FALSE(SSL_set_max_proto_version(ssl.get(), 0x0200));
|
||
|
|
EXPECT_FALSE(SSL_set_max_proto_version(ssl.get(), 0x1234));
|
||
|
|
EXPECT_FALSE(SSL_set_min_proto_version(ssl.get(), DTLS1_VERSION));
|
||
|
|
EXPECT_FALSE(SSL_set_min_proto_version(ssl.get(), 0x0200));
|
||
|
|
EXPECT_FALSE(SSL_set_min_proto_version(ssl.get(), 0x1234));
|
||
|
|
|
||
|
|
// Zero represents the default version.
|
||
|
|
EXPECT_TRUE(SSL_CTX_set_max_proto_version(ctx.get(), 0));
|
||
|
|
EXPECT_EQ(0, SSL_CTX_get_max_proto_version(ctx.get()));
|
||
|
|
EXPECT_TRUE(SSL_CTX_set_min_proto_version(ctx.get(), 0));
|
||
|
|
EXPECT_EQ(0, SSL_CTX_get_min_proto_version(ctx.get()));
|
||
|
|
EXPECT_TRUE(SSL_set_max_proto_version(ssl.get(), 0));
|
||
|
|
EXPECT_EQ(0, SSL_get_max_proto_version(ssl.get()));
|
||
|
|
EXPECT_TRUE(SSL_set_min_proto_version(ssl.get(), 0));
|
||
|
|
EXPECT_EQ(0, SSL_get_min_proto_version(ssl.get()));
|
||
|
|
|
||
|
|
// SSL 3.0 is not available.
|
||
|
|
EXPECT_FALSE(SSL_CTX_set_min_proto_version(ctx.get(), SSL3_VERSION));
|
||
|
|
EXPECT_FALSE(SSL_set_min_proto_version(ssl.get(), SSL3_VERSION));
|
||
|
|
|
||
|
|
ctx.reset(SSL_CTX_new(DTLS_method()));
|
||
|
|
ASSERT_TRUE(ctx);
|
||
|
|
ssl.reset(SSL_new(ctx.get()));
|
||
|
|
ASSERT_TRUE(ssl);
|
||
|
|
|
||
|
|
// Set valid DTLS versions.
|
||
|
|
for (const auto &vers : kAllVersions) {
|
||
|
|
SCOPED_TRACE(vers.name);
|
||
|
|
if (vers.ssl_method == VersionParam::is_dtls) {
|
||
|
|
EXPECT_TRUE(SSL_CTX_set_max_proto_version(ctx.get(), vers.version));
|
||
|
|
EXPECT_EQ(SSL_CTX_get_max_proto_version(ctx.get()), vers.version);
|
||
|
|
EXPECT_TRUE(SSL_CTX_set_min_proto_version(ctx.get(), vers.version));
|
||
|
|
EXPECT_EQ(SSL_CTX_get_min_proto_version(ctx.get()), vers.version);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// Invalid DTLS versions are rejected.
|
||
|
|
EXPECT_FALSE(SSL_CTX_set_max_proto_version(ctx.get(), TLS1_VERSION));
|
||
|
|
EXPECT_FALSE(SSL_CTX_set_max_proto_version(ctx.get(), 0xfefe /* DTLS 1.1 */));
|
||
|
|
EXPECT_FALSE(SSL_CTX_set_max_proto_version(ctx.get(), 0xfffe /* DTLS 0.1 */));
|
||
|
|
EXPECT_FALSE(SSL_CTX_set_max_proto_version(ctx.get(), 0x1234));
|
||
|
|
EXPECT_FALSE(SSL_CTX_set_min_proto_version(ctx.get(), TLS1_VERSION));
|
||
|
|
EXPECT_FALSE(SSL_CTX_set_min_proto_version(ctx.get(), 0xfefe /* DTLS 1.1 */));
|
||
|
|
EXPECT_FALSE(SSL_CTX_set_min_proto_version(ctx.get(), 0xfffe /* DTLS 0.1 */));
|
||
|
|
EXPECT_FALSE(SSL_CTX_set_min_proto_version(ctx.get(), 0x1234));
|
||
|
|
|
||
|
|
// Zero represents the default version.
|
||
|
|
EXPECT_TRUE(SSL_CTX_set_max_proto_version(ctx.get(), 0));
|
||
|
|
EXPECT_EQ(0, SSL_CTX_get_max_proto_version(ctx.get()));
|
||
|
|
EXPECT_TRUE(SSL_CTX_set_min_proto_version(ctx.get(), 0));
|
||
|
|
EXPECT_EQ(0, SSL_CTX_get_min_proto_version(ctx.get()));
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST(SSLTest, SetVerifyResult) {
|
||
|
|
bssl::UniquePtr<SSL_CTX> client_ctx(SSL_CTX_new(TLS_method()));
|
||
|
|
bssl::UniquePtr<SSL_CTX> server_ctx =
|
||
|
|
CreateContextWithTestCertificate(TLS_method());
|
||
|
|
ASSERT_TRUE(client_ctx);
|
||
|
|
ASSERT_TRUE(server_ctx);
|
||
|
|
|
||
|
|
bssl::UniquePtr<SSL> client, server;
|
||
|
|
ASSERT_TRUE(ConnectClientAndServer(&client, &server, client_ctx.get(),
|
||
|
|
server_ctx.get()));
|
||
|
|
|
||
|
|
SSL_SESSION *client_session = SSL_get_session(client.get());
|
||
|
|
SSL_SESSION *server_session = SSL_get_session(server.get());
|
||
|
|
|
||
|
|
// SSL and SSL_SESSION should share the same verify_result after a handshake
|
||
|
|
EXPECT_EQ(SSL_get_verify_result(client.get()), client_session->verify_result);
|
||
|
|
EXPECT_EQ(SSL_get_verify_result(server.get()), server_session->verify_result);
|
||
|
|
|
||
|
|
// Use custom verification result
|
||
|
|
SSL_set_verify_result(client.get(), X509_V_ERR_CERT_REVOKED);
|
||
|
|
EXPECT_EQ(X509_V_ERR_CERT_REVOKED, SSL_get_verify_result(client.get()));
|
||
|
|
EXPECT_NE(SSL_get_verify_result(client.get()), client_session->verify_result);
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST(SSLTest, BuildCertChain) {
|
||
|
|
bssl::UniquePtr<SSL_CTX> ctx(SSL_CTX_new(TLS_method()));
|
||
|
|
|
||
|
|
// No certificate set, so this should fail.
|
||
|
|
EXPECT_FALSE(SSL_CTX_build_cert_chain(ctx.get(), 0));
|
||
|
|
EXPECT_TRUE(ExpectSingleError(ERR_LIB_SSL, SSL_R_NO_CERTIFICATE_SET));
|
||
|
|
|
||
|
|
ASSERT_TRUE(SSL_CTX_use_certificate(ctx.get(), GetLeafPublic().get()));
|
||
|
|
ASSERT_TRUE(SSL_CTX_use_PrivateKey(ctx.get(), GetLeafKey().get()));
|
||
|
|
|
||
|
|
// Verification will fail because there is no valid root cert available.
|
||
|
|
EXPECT_FALSE(SSL_CTX_build_cert_chain(ctx.get(), 0));
|
||
|
|
ERR_clear_error();
|
||
|
|
|
||
|
|
// Should return 2 when |SSL_BUILD_CHAIN_FLAG_IGNORE_ERROR| is set.
|
||
|
|
EXPECT_EQ(
|
||
|
|
SSL_CTX_build_cert_chain(ctx.get(), SSL_BUILD_CHAIN_FLAG_IGNORE_ERROR),
|
||
|
|
2);
|
||
|
|
EXPECT_TRUE(ExpectSingleError(ERR_LIB_SSL, SSL_R_CERTIFICATE_VERIFY_FAILED));
|
||
|
|
ERR_clear_error();
|
||
|
|
|
||
|
|
// Should return 2, but with no error on the stack when
|
||
|
|
// |SSL_BUILD_CHAIN_FLAG_IGNORE_ERROR| and |SSL_BUILD_CHAIN_FLAG_CLEAR_ERROR|
|
||
|
|
// are set.
|
||
|
|
EXPECT_EQ(
|
||
|
|
SSL_CTX_build_cert_chain(ctx.get(), SSL_BUILD_CHAIN_FLAG_IGNORE_ERROR |
|
||
|
|
SSL_BUILD_CHAIN_FLAG_CLEAR_ERROR),
|
||
|
|
2);
|
||
|
|
EXPECT_FALSE(ERR_get_error());
|
||
|
|
|
||
|
|
// Pass in the trust store. |SSL_CTX_build_cert_chain| should succeed now.
|
||
|
|
ASSERT_TRUE(X509_STORE_add_cert(SSL_CTX_get_cert_store(ctx.get()),
|
||
|
|
GetLeafRoot().get()));
|
||
|
|
X509_VERIFY_PARAM_set_flags(SSL_CTX_get0_param(ctx.get()),
|
||
|
|
X509_V_FLAG_NO_CHECK_TIME);
|
||
|
|
EXPECT_EQ(SSL_CTX_build_cert_chain(ctx.get(), 0), 1);
|
||
|
|
STACK_OF(X509) *chain = nullptr;
|
||
|
|
ASSERT_TRUE(SSL_CTX_get0_chain_certs(ctx.get(), &chain));
|
||
|
|
EXPECT_TRUE(ChainsEqual(chain, {GetLeafRoot().get()}));
|
||
|
|
|
||
|
|
// Root cert is self-signed, so |SSL_BUILD_CHAIN_FLAG_UNTRUSTED| will
|
||
|
|
// still pass.
|
||
|
|
ASSERT_TRUE(SSL_CTX_clear_chain_certs(ctx.get()));
|
||
|
|
EXPECT_TRUE(
|
||
|
|
SSL_CTX_build_cert_chain(ctx.get(), SSL_BUILD_CHAIN_FLAG_UNTRUSTED));
|
||
|
|
ASSERT_TRUE(SSL_CTX_get0_chain_certs(ctx.get(), &chain));
|
||
|
|
EXPECT_TRUE(ChainsEqual(chain, {GetLeafRoot().get()}));
|
||
|
|
|
||
|
|
// |SSL_BUILD_CHAIN_FLAG_CHECK| uses the already built cert chain as the trust
|
||
|
|
// store and verifies against it. If we clear the cert chain, there should be
|
||
|
|
// no trust store to compare against if |SSL_BUILD_CHAIN_FLAG_CHECK| is still
|
||
|
|
// set.
|
||
|
|
EXPECT_EQ(SSL_CTX_build_cert_chain(ctx.get(), SSL_BUILD_CHAIN_FLAG_CHECK), 1);
|
||
|
|
ASSERT_TRUE(SSL_CTX_clear_chain_certs(ctx.get()));
|
||
|
|
EXPECT_FALSE(SSL_CTX_build_cert_chain(ctx.get(), SSL_BUILD_CHAIN_FLAG_CHECK));
|
||
|
|
EXPECT_TRUE(ExpectSingleError(ERR_LIB_SSL, SSL_R_CERTIFICATE_VERIFY_FAILED));
|
||
|
|
|
||
|
|
// |SSL_BUILD_CHAIN_FLAG_CHECK| and |SSL_BUILD_CHAIN_FLAG_UNTRUSTED| are
|
||
|
|
// mutually exclusive, with |SSL_BUILD_CHAIN_FLAG_CHECK| taking priority.
|
||
|
|
// The result with both set should be the same as only
|
||
|
|
// |SSL_BUILD_CHAIN_FLAG_CHECK| being set.
|
||
|
|
ASSERT_TRUE(SSL_CTX_clear_chain_certs(ctx.get()));
|
||
|
|
EXPECT_FALSE(SSL_CTX_build_cert_chain(
|
||
|
|
ctx.get(), SSL_BUILD_CHAIN_FLAG_CHECK | SSL_BUILD_CHAIN_FLAG_UNTRUSTED));
|
||
|
|
EXPECT_FALSE(SSL_CTX_build_cert_chain(ctx.get(), SSL_BUILD_CHAIN_FLAG_CHECK));
|
||
|
|
// First call with |SSL_BUILD_CHAIN_FLAG_CHECK| existing will fail, second
|
||
|
|
// call with |SSL_BUILD_CHAIN_FLAG_UNTRUSTED| will succeed.
|
||
|
|
EXPECT_FALSE(SSL_CTX_build_cert_chain(
|
||
|
|
ctx.get(), SSL_BUILD_CHAIN_FLAG_CHECK | SSL_BUILD_CHAIN_FLAG_UNTRUSTED));
|
||
|
|
EXPECT_EQ(SSL_CTX_build_cert_chain(ctx.get(), SSL_BUILD_CHAIN_FLAG_UNTRUSTED),
|
||
|
|
1);
|
||
|
|
// |SSL_BUILD_CHAIN_FLAG_CHECK| will succeed since we have a built chain now.
|
||
|
|
EXPECT_EQ(SSL_CTX_build_cert_chain(ctx.get(), SSL_BUILD_CHAIN_FLAG_CHECK), 1);
|
||
|
|
|
||
|
|
// Test that successful verification with |SSL_BUILD_CHAIN_FLAG_IGNORE_ERROR|
|
||
|
|
// does not return 2.
|
||
|
|
ASSERT_TRUE(SSL_CTX_clear_chain_certs(ctx.get()));
|
||
|
|
EXPECT_EQ(
|
||
|
|
SSL_CTX_build_cert_chain(ctx.get(), SSL_BUILD_CHAIN_FLAG_IGNORE_ERROR),
|
||
|
|
1);
|
||
|
|
|
||
|
|
// Test that successful verification with |SSL_BUILD_CHAIN_FLAG_NO_ROOT|
|
||
|
|
// does include the root cert.
|
||
|
|
ASSERT_TRUE(SSL_CTX_clear_chain_certs(ctx.get()));
|
||
|
|
EXPECT_EQ(SSL_CTX_build_cert_chain(ctx.get(), SSL_BUILD_CHAIN_FLAG_NO_ROOT),
|
||
|
|
1);
|
||
|
|
ASSERT_TRUE(SSL_CTX_get0_chain_certs(ctx.get(), &chain));
|
||
|
|
EXPECT_TRUE(ChainsEqual(chain, {}));
|
||
|
|
}
|
||
|
|
|
||
|
|
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);
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST(SSLTest, GetCertificate) {
|
||
|
|
bssl::UniquePtr<SSL_CTX> ctx(SSL_CTX_new(TLS_method()));
|
||
|
|
ASSERT_TRUE(ctx);
|
||
|
|
bssl::UniquePtr<X509> cert = GetTestCertificate();
|
||
|
|
ASSERT_TRUE(cert);
|
||
|
|
ASSERT_TRUE(SSL_CTX_use_certificate(ctx.get(), cert.get()));
|
||
|
|
bssl::UniquePtr<SSL> ssl(SSL_new(ctx.get()));
|
||
|
|
ASSERT_TRUE(ssl);
|
||
|
|
|
||
|
|
X509 *cert2 = SSL_CTX_get0_certificate(ctx.get());
|
||
|
|
ASSERT_TRUE(cert2);
|
||
|
|
|
||
|
|
X509 *cert3 = SSL_get_certificate(ssl.get());
|
||
|
|
ASSERT_TRUE(cert3);
|
||
|
|
|
||
|
|
// The old and new certificates must be identical.
|
||
|
|
EXPECT_EQ(0, X509_cmp(cert.get(), cert2));
|
||
|
|
EXPECT_EQ(0, X509_cmp(cert.get(), cert3));
|
||
|
|
|
||
|
|
uint8_t *der = nullptr;
|
||
|
|
long der_len = i2d_X509(cert.get(), &der);
|
||
|
|
ASSERT_LT(0, der_len);
|
||
|
|
bssl::UniquePtr<uint8_t> free_der(der);
|
||
|
|
|
||
|
|
uint8_t *der2 = nullptr;
|
||
|
|
long der2_len = i2d_X509(cert2, &der2);
|
||
|
|
ASSERT_LT(0, der2_len);
|
||
|
|
bssl::UniquePtr<uint8_t> free_der2(der2);
|
||
|
|
|
||
|
|
uint8_t *der3 = nullptr;
|
||
|
|
long der3_len = i2d_X509(cert3, &der3);
|
||
|
|
ASSERT_LT(0, der3_len);
|
||
|
|
bssl::UniquePtr<uint8_t> free_der3(der3);
|
||
|
|
|
||
|
|
// They must also encode identically.
|
||
|
|
EXPECT_EQ(Bytes(der, der_len), Bytes(der2, der2_len));
|
||
|
|
EXPECT_EQ(Bytes(der, der_len), Bytes(der3, der3_len));
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST(SSLTest, GetCertificateExData) {
|
||
|
|
bssl::UniquePtr<SSL_CTX> ctx(SSL_CTX_new(TLS_method()));
|
||
|
|
ASSERT_TRUE(ctx);
|
||
|
|
bssl::UniquePtr<X509> cert = GetTestCertificate();
|
||
|
|
ASSERT_TRUE(cert);
|
||
|
|
|
||
|
|
int ex_data_index =
|
||
|
|
X509_get_ex_new_index(0, nullptr, nullptr, nullptr, nullptr);
|
||
|
|
const char ex_data[] = "AWS-LC external data";
|
||
|
|
ASSERT_TRUE(X509_set_ex_data(cert.get(), ex_data_index, (void *)ex_data));
|
||
|
|
ASSERT_TRUE(X509_get_ex_data(cert.get(), ex_data_index));
|
||
|
|
|
||
|
|
ASSERT_TRUE(SSL_CTX_use_certificate(ctx.get(), cert.get()));
|
||
|
|
bssl::UniquePtr<SSL> ssl(SSL_new(ctx.get()));
|
||
|
|
ASSERT_TRUE(ssl);
|
||
|
|
|
||
|
|
X509 *cert2 = SSL_CTX_get0_certificate(ctx.get());
|
||
|
|
ASSERT_TRUE(cert2);
|
||
|
|
const char *ex_data2 = (const char *)X509_get_ex_data(cert2, ex_data_index);
|
||
|
|
EXPECT_TRUE(ex_data2);
|
||
|
|
|
||
|
|
X509 *cert3 = SSL_get_certificate(ssl.get());
|
||
|
|
ASSERT_TRUE(cert3);
|
||
|
|
const char *ex_data3 = (const char *)X509_get_ex_data(cert3, ex_data_index);
|
||
|
|
EXPECT_TRUE(ex_data3);
|
||
|
|
|
||
|
|
// The external data extracted must be identical.
|
||
|
|
EXPECT_EQ(ex_data2, ex_data);
|
||
|
|
EXPECT_EQ(ex_data3, ex_data);
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST(SSLTest, GetCertificateASN1) {
|
||
|
|
bssl::UniquePtr<SSL_CTX> ctx(SSL_CTX_new(TLS_method()));
|
||
|
|
ASSERT_TRUE(ctx);
|
||
|
|
bssl::UniquePtr<X509> cert = GetTestCertificate();
|
||
|
|
ASSERT_TRUE(cert);
|
||
|
|
|
||
|
|
// Convert cert to ASN1 to pass in.
|
||
|
|
uint8_t *der = nullptr;
|
||
|
|
size_t der_len = i2d_X509(cert.get(), &der);
|
||
|
|
bssl::UniquePtr<uint8_t> free_der(der);
|
||
|
|
|
||
|
|
ASSERT_TRUE(SSL_CTX_use_certificate_ASN1(ctx.get(), der_len, der));
|
||
|
|
bssl::UniquePtr<SSL> ssl(SSL_new(ctx.get()));
|
||
|
|
ASSERT_TRUE(ssl);
|
||
|
|
|
||
|
|
X509 *cert2 = SSL_CTX_get0_certificate(ctx.get());
|
||
|
|
ASSERT_TRUE(cert2);
|
||
|
|
|
||
|
|
X509 *cert3 = SSL_get_certificate(ssl.get());
|
||
|
|
ASSERT_TRUE(cert3);
|
||
|
|
|
||
|
|
// The old and new certificates must be identical.
|
||
|
|
EXPECT_EQ(0, X509_cmp(cert.get(), cert2));
|
||
|
|
EXPECT_EQ(0, X509_cmp(cert.get(), cert3));
|
||
|
|
|
||
|
|
uint8_t *der2 = nullptr;
|
||
|
|
long der2_len = i2d_X509(cert2, &der2);
|
||
|
|
ASSERT_LT(0, der2_len);
|
||
|
|
bssl::UniquePtr<uint8_t> free_der2(der2);
|
||
|
|
|
||
|
|
uint8_t *der3 = nullptr;
|
||
|
|
long der3_len = i2d_X509(cert3, &der3);
|
||
|
|
ASSERT_LT(0, der3_len);
|
||
|
|
bssl::UniquePtr<uint8_t> free_der3(der3);
|
||
|
|
|
||
|
|
// They must also encode identically.
|
||
|
|
EXPECT_EQ(Bytes(der, der_len), Bytes(der2, der2_len));
|
||
|
|
EXPECT_EQ(Bytes(der, der_len), Bytes(der3, der3_len));
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST(SSLTest, SetChainAndKeyMismatch) {
|
||
|
|
bssl::UniquePtr<SSL_CTX> ctx(SSL_CTX_new(TLS_with_buffers_method()));
|
||
|
|
ASSERT_TRUE(ctx);
|
||
|
|
|
||
|
|
bssl::UniquePtr<EVP_PKEY> key = GetTestKey();
|
||
|
|
ASSERT_TRUE(key);
|
||
|
|
bssl::UniquePtr<CRYPTO_BUFFER> leaf = GetChainTestCertificateBuffer();
|
||
|
|
ASSERT_TRUE(leaf);
|
||
|
|
std::vector<CRYPTO_BUFFER *> chain = {
|
||
|
|
leaf.get(),
|
||
|
|
};
|
||
|
|
|
||
|
|
// Should fail because |GetTestKey| doesn't match the chain-test certificate.
|
||
|
|
ASSERT_FALSE(SSL_CTX_set_chain_and_key(ctx.get(), &chain[0], chain.size(),
|
||
|
|
key.get(), nullptr));
|
||
|
|
ERR_clear_error();
|
||
|
|
|
||
|
|
// Ensure |SSL_CTX_use_cert_and_key| also fails
|
||
|
|
bssl::UniquePtr<X509> x509_leaf =
|
||
|
|
X509FromBuffer(GetChainTestCertificateBuffer());
|
||
|
|
ASSERT_FALSE(
|
||
|
|
SSL_CTX_use_cert_and_key(ctx.get(), x509_leaf.get(), key.get(), NULL, 1));
|
||
|
|
ERR_clear_error();
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST(SSLTest, SetChainAndKey) {
|
||
|
|
bssl::UniquePtr<SSL_CTX> client_ctx(SSL_CTX_new(TLS_with_buffers_method()));
|
||
|
|
ASSERT_TRUE(client_ctx);
|
||
|
|
bssl::UniquePtr<SSL_CTX> server_ctx(SSL_CTX_new(TLS_with_buffers_method()));
|
||
|
|
ASSERT_TRUE(server_ctx);
|
||
|
|
|
||
|
|
ASSERT_EQ(nullptr, SSL_CTX_get0_chain(server_ctx.get()));
|
||
|
|
|
||
|
|
bssl::UniquePtr<EVP_PKEY> key = GetChainTestKey();
|
||
|
|
ASSERT_TRUE(key);
|
||
|
|
bssl::UniquePtr<CRYPTO_BUFFER> leaf = GetChainTestCertificateBuffer();
|
||
|
|
ASSERT_TRUE(leaf);
|
||
|
|
bssl::UniquePtr<CRYPTO_BUFFER> intermediate =
|
||
|
|
GetChainTestIntermediateBuffer();
|
||
|
|
ASSERT_TRUE(intermediate);
|
||
|
|
std::vector<CRYPTO_BUFFER *> chain = {
|
||
|
|
leaf.get(),
|
||
|
|
intermediate.get(),
|
||
|
|
};
|
||
|
|
ASSERT_TRUE(SSL_CTX_set_chain_and_key(server_ctx.get(), &chain[0],
|
||
|
|
chain.size(), key.get(), nullptr));
|
||
|
|
|
||
|
|
ASSERT_EQ(chain.size(),
|
||
|
|
sk_CRYPTO_BUFFER_num(SSL_CTX_get0_chain(server_ctx.get())));
|
||
|
|
|
||
|
|
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;
|
||
|
|
});
|
||
|
|
|
||
|
|
bssl::UniquePtr<SSL> client, server;
|
||
|
|
ASSERT_TRUE(ConnectClientAndServer(&client, &server, client_ctx.get(),
|
||
|
|
server_ctx.get()));
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST(SSLTest, SetLeafChainAndKey) {
|
||
|
|
bssl::UniquePtr<SSL_CTX> client_ctx(SSL_CTX_new(TLS_method()));
|
||
|
|
ASSERT_TRUE(client_ctx);
|
||
|
|
bssl::UniquePtr<SSL_CTX> server_ctx(SSL_CTX_new(TLS_method()));
|
||
|
|
ASSERT_TRUE(server_ctx);
|
||
|
|
|
||
|
|
ASSERT_EQ(nullptr, SSL_CTX_get0_chain(server_ctx.get()));
|
||
|
|
|
||
|
|
bssl::UniquePtr<EVP_PKEY> key = GetChainTestKey();
|
||
|
|
ASSERT_TRUE(key);
|
||
|
|
bssl::UniquePtr<X509> leaf = GetChainTestCertificate();
|
||
|
|
ASSERT_TRUE(leaf);
|
||
|
|
bssl::UniquePtr<X509> intermediate = GetChainTestIntermediate();
|
||
|
|
bssl::UniquePtr<STACK_OF(X509)> chain(sk_X509_new_null());
|
||
|
|
ASSERT_TRUE(chain);
|
||
|
|
ASSERT_TRUE(PushToStack(chain.get(), std::move(intermediate)));
|
||
|
|
|
||
|
|
ASSERT_TRUE(SSL_CTX_use_cert_and_key(server_ctx.get(), leaf.get(), key.get(),
|
||
|
|
chain.get(), 1));
|
||
|
|
|
||
|
|
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;
|
||
|
|
});
|
||
|
|
|
||
|
|
bssl::UniquePtr<SSL> client, server;
|
||
|
|
ASSERT_TRUE(ConnectClientAndServer(&client, &server, client_ctx.get(),
|
||
|
|
server_ctx.get()));
|
||
|
|
|
||
|
|
// Try setting on previously populated fields without an override
|
||
|
|
ASSERT_FALSE(SSL_CTX_use_cert_and_key(server_ctx.get(), leaf.get(), key.get(),
|
||
|
|
chain.get(), 0));
|
||
|
|
ERR_clear_error();
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST(SSLTest, BuffersFailWithoutCustomVerify) {
|
||
|
|
bssl::UniquePtr<SSL_CTX> client_ctx(SSL_CTX_new(TLS_with_buffers_method()));
|
||
|
|
ASSERT_TRUE(client_ctx);
|
||
|
|
bssl::UniquePtr<SSL_CTX> server_ctx(SSL_CTX_new(TLS_with_buffers_method()));
|
||
|
|
ASSERT_TRUE(server_ctx);
|
||
|
|
|
||
|
|
bssl::UniquePtr<EVP_PKEY> key = GetChainTestKey();
|
||
|
|
ASSERT_TRUE(key);
|
||
|
|
bssl::UniquePtr<CRYPTO_BUFFER> leaf = GetChainTestCertificateBuffer();
|
||
|
|
ASSERT_TRUE(leaf);
|
||
|
|
std::vector<CRYPTO_BUFFER *> chain = {leaf.get()};
|
||
|
|
ASSERT_TRUE(SSL_CTX_set_chain_and_key(server_ctx.get(), &chain[0],
|
||
|
|
chain.size(), key.get(), nullptr));
|
||
|
|
|
||
|
|
// Without SSL_CTX_set_custom_verify(), i.e. with everything in the default
|
||
|
|
// configuration, certificate verification should fail.
|
||
|
|
bssl::UniquePtr<SSL> client, server;
|
||
|
|
ASSERT_FALSE(ConnectClientAndServer(&client, &server, client_ctx.get(),
|
||
|
|
server_ctx.get()));
|
||
|
|
|
||
|
|
// Whereas with a verifier, the connection should succeed.
|
||
|
|
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;
|
||
|
|
});
|
||
|
|
ASSERT_TRUE(ConnectClientAndServer(&client, &server, client_ctx.get(),
|
||
|
|
server_ctx.get()));
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST(SSLTest, CustomVerify) {
|
||
|
|
bssl::UniquePtr<SSL_CTX> client_ctx(SSL_CTX_new(TLS_with_buffers_method()));
|
||
|
|
ASSERT_TRUE(client_ctx);
|
||
|
|
bssl::UniquePtr<SSL_CTX> server_ctx(SSL_CTX_new(TLS_with_buffers_method()));
|
||
|
|
ASSERT_TRUE(server_ctx);
|
||
|
|
|
||
|
|
bssl::UniquePtr<EVP_PKEY> key = GetChainTestKey();
|
||
|
|
ASSERT_TRUE(key);
|
||
|
|
bssl::UniquePtr<CRYPTO_BUFFER> leaf = GetChainTestCertificateBuffer();
|
||
|
|
ASSERT_TRUE(leaf);
|
||
|
|
std::vector<CRYPTO_BUFFER *> chain = {leaf.get()};
|
||
|
|
ASSERT_TRUE(SSL_CTX_set_chain_and_key(server_ctx.get(), &chain[0],
|
||
|
|
chain.size(), key.get(), nullptr));
|
||
|
|
|
||
|
|
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;
|
||
|
|
});
|
||
|
|
|
||
|
|
bssl::UniquePtr<SSL> client, server;
|
||
|
|
ASSERT_TRUE(ConnectClientAndServer(&client, &server, client_ctx.get(),
|
||
|
|
server_ctx.get()));
|
||
|
|
|
||
|
|
// With SSL_VERIFY_PEER, ssl_verify_invalid should result in a dropped
|
||
|
|
// connection.
|
||
|
|
SSL_CTX_set_custom_verify(
|
||
|
|
client_ctx.get(), SSL_VERIFY_PEER,
|
||
|
|
[](SSL *ssl, uint8_t *out_alert) -> ssl_verify_result_t {
|
||
|
|
return ssl_verify_invalid;
|
||
|
|
});
|
||
|
|
|
||
|
|
ASSERT_FALSE(ConnectClientAndServer(&client, &server, client_ctx.get(),
|
||
|
|
server_ctx.get()));
|
||
|
|
|
||
|
|
// But with SSL_VERIFY_NONE, ssl_verify_invalid should not cause a dropped
|
||
|
|
// connection.
|
||
|
|
SSL_CTX_set_custom_verify(
|
||
|
|
client_ctx.get(), SSL_VERIFY_NONE,
|
||
|
|
[](SSL *ssl, uint8_t *out_alert) -> ssl_verify_result_t {
|
||
|
|
return ssl_verify_invalid;
|
||
|
|
});
|
||
|
|
|
||
|
|
ASSERT_TRUE(ConnectClientAndServer(&client, &server, client_ctx.get(),
|
||
|
|
server_ctx.get()));
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST(SSLTest, ClientCABuffers) {
|
||
|
|
bssl::UniquePtr<SSL_CTX> client_ctx(SSL_CTX_new(TLS_with_buffers_method()));
|
||
|
|
ASSERT_TRUE(client_ctx);
|
||
|
|
bssl::UniquePtr<SSL_CTX> server_ctx(SSL_CTX_new(TLS_with_buffers_method()));
|
||
|
|
ASSERT_TRUE(server_ctx);
|
||
|
|
|
||
|
|
bssl::UniquePtr<EVP_PKEY> key = GetChainTestKey();
|
||
|
|
ASSERT_TRUE(key);
|
||
|
|
bssl::UniquePtr<CRYPTO_BUFFER> leaf = GetChainTestCertificateBuffer();
|
||
|
|
ASSERT_TRUE(leaf);
|
||
|
|
bssl::UniquePtr<CRYPTO_BUFFER> intermediate =
|
||
|
|
GetChainTestIntermediateBuffer();
|
||
|
|
ASSERT_TRUE(intermediate);
|
||
|
|
std::vector<CRYPTO_BUFFER *> 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<CRYPTO_BUFFER> ca_name(
|
||
|
|
CRYPTO_BUFFER_new(kTestName, sizeof(kTestName), nullptr));
|
||
|
|
ASSERT_TRUE(ca_name);
|
||
|
|
bssl::UniquePtr<STACK_OF(CRYPTO_BUFFER)> ca_names(
|
||
|
|
sk_CRYPTO_BUFFER_new_null());
|
||
|
|
ASSERT_TRUE(ca_names);
|
||
|
|
ASSERT_TRUE(PushToStack(ca_names.get(), std::move(ca_name)));
|
||
|
|
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 {
|
||
|
|
const 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<bool *>(arg) = true;
|
||
|
|
return 1;
|
||
|
|
},
|
||
|
|
&cert_cb_called);
|
||
|
|
|
||
|
|
bssl::UniquePtr<SSL> client, server;
|
||
|
|
ASSERT_TRUE(ConnectClientAndServer(&client, &server, client_ctx.get(),
|
||
|
|
server_ctx.get()));
|
||
|
|
EXPECT_TRUE(cert_cb_called);
|
||
|
|
}
|
||
|
|
|
||
|
|
// Test that |SSL_get_client_CA_list| returns the server's CA list on the
|
||
|
|
// client both during the cert callback and after the handshake completes.
|
||
|
|
TEST(SSLTest, PeerCANamesX509DuringAndAfterHandshake) {
|
||
|
|
for (uint16_t version : {TLS1_2_VERSION, TLS1_3_VERSION}) {
|
||
|
|
SCOPED_TRACE(version);
|
||
|
|
|
||
|
|
bssl::UniquePtr<SSL_CTX> server_ctx(SSL_CTX_new(TLS_method()));
|
||
|
|
ASSERT_TRUE(server_ctx);
|
||
|
|
ASSERT_TRUE(SSL_CTX_set_min_proto_version(server_ctx.get(), version));
|
||
|
|
ASSERT_TRUE(SSL_CTX_set_max_proto_version(server_ctx.get(), version));
|
||
|
|
|
||
|
|
bssl::UniquePtr<X509> cert = GetChainTestCertificate();
|
||
|
|
bssl::UniquePtr<X509> intermediate = GetChainTestIntermediate();
|
||
|
|
bssl::UniquePtr<EVP_PKEY> key = GetChainTestKey();
|
||
|
|
ASSERT_TRUE(cert && intermediate && key);
|
||
|
|
ASSERT_TRUE(SSL_CTX_use_certificate(server_ctx.get(), cert.get()));
|
||
|
|
ASSERT_TRUE(
|
||
|
|
SSL_CTX_add1_chain_cert(server_ctx.get(), intermediate.get()));
|
||
|
|
ASSERT_TRUE(SSL_CTX_use_PrivateKey(server_ctx.get(), key.get()));
|
||
|
|
|
||
|
|
// Configure the server's CA list using X509_NAMEs.
|
||
|
|
bssl::UniquePtr<X509_NAME> ca_name(X509_NAME_new());
|
||
|
|
ASSERT_TRUE(ca_name);
|
||
|
|
ASSERT_TRUE(X509_NAME_add_entry_by_txt(
|
||
|
|
ca_name.get(), "CN", MBSTRING_ASC,
|
||
|
|
reinterpret_cast<const unsigned char *>("Test CA"), -1, -1, 0));
|
||
|
|
|
||
|
|
bssl::UniquePtr<X509_NAME> ca_name_copy(X509_NAME_dup(ca_name.get()));
|
||
|
|
ASSERT_TRUE(ca_name_copy);
|
||
|
|
bssl::UniquePtr<STACK_OF(X509_NAME)> ca_list(sk_X509_NAME_new_null());
|
||
|
|
ASSERT_TRUE(ca_list);
|
||
|
|
ASSERT_TRUE(PushToStack(ca_list.get(), std::move(ca_name_copy)));
|
||
|
|
// SSL_CTX_set_client_CA_list takes ownership.
|
||
|
|
SSL_CTX_set_client_CA_list(server_ctx.get(), ca_list.release());
|
||
|
|
|
||
|
|
// The server must request client certificates.
|
||
|
|
SSL_CTX_set_verify(server_ctx.get(), SSL_VERIFY_PEER, nullptr);
|
||
|
|
|
||
|
|
bssl::UniquePtr<SSL_CTX> client_ctx(SSL_CTX_new(TLS_method()));
|
||
|
|
ASSERT_TRUE(client_ctx);
|
||
|
|
ASSERT_TRUE(SSL_CTX_set_min_proto_version(client_ctx.get(), version));
|
||
|
|
ASSERT_TRUE(SSL_CTX_set_max_proto_version(client_ctx.get(), version));
|
||
|
|
// Accept any server certificate.
|
||
|
|
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;
|
||
|
|
});
|
||
|
|
|
||
|
|
// Use a cert callback to verify CA names are available during the
|
||
|
|
// handshake via the X509-based API.
|
||
|
|
bool cert_cb_called = false;
|
||
|
|
SSL_CTX_set_cert_cb(
|
||
|
|
client_ctx.get(),
|
||
|
|
[](SSL *ssl, void *arg) -> int {
|
||
|
|
STACK_OF(X509_NAME) *ca_list = SSL_get_client_CA_list(ssl);
|
||
|
|
EXPECT_TRUE(ca_list);
|
||
|
|
EXPECT_EQ(1u, sk_X509_NAME_num(ca_list));
|
||
|
|
*reinterpret_cast<bool *>(arg) = true;
|
||
|
|
return 1;
|
||
|
|
},
|
||
|
|
&cert_cb_called);
|
||
|
|
|
||
|
|
bssl::UniquePtr<SSL> client, server;
|
||
|
|
ASSERT_TRUE(ConnectClientAndServer(&client, &server, client_ctx.get(),
|
||
|
|
server_ctx.get()));
|
||
|
|
EXPECT_TRUE(cert_cb_called);
|
||
|
|
|
||
|
|
// After the handshake, verify the same CA list is still available.
|
||
|
|
// The handshake config has been shed by default, so ssl->config is NULL,
|
||
|
|
// but the client-side peer CA names are persisted in ssl->s3.
|
||
|
|
STACK_OF(X509_NAME) *client_ca_list =
|
||
|
|
SSL_get_client_CA_list(client.get());
|
||
|
|
ASSERT_TRUE(client_ca_list);
|
||
|
|
ASSERT_EQ(1u, sk_X509_NAME_num(client_ca_list));
|
||
|
|
EXPECT_EQ(0,
|
||
|
|
X509_NAME_cmp(sk_X509_NAME_value(client_ca_list, 0),
|
||
|
|
ca_name.get()));
|
||
|
|
|
||
|
|
// Now do a second handshake with the same client context but a server
|
||
|
|
// that does NOT request client certificates (no CertificateRequest).
|
||
|
|
// The client should see no peer CA names after this handshake.
|
||
|
|
bssl::UniquePtr<SSL_CTX> server_ctx2(SSL_CTX_new(TLS_method()));
|
||
|
|
ASSERT_TRUE(server_ctx2);
|
||
|
|
ASSERT_TRUE(SSL_CTX_set_min_proto_version(server_ctx2.get(), version));
|
||
|
|
ASSERT_TRUE(SSL_CTX_set_max_proto_version(server_ctx2.get(), version));
|
||
|
|
ASSERT_TRUE(SSL_CTX_use_certificate(server_ctx2.get(), cert.get()));
|
||
|
|
ASSERT_TRUE(
|
||
|
|
SSL_CTX_add1_chain_cert(server_ctx2.get(), intermediate.get()));
|
||
|
|
ASSERT_TRUE(SSL_CTX_use_PrivateKey(server_ctx2.get(), key.get()));
|
||
|
|
|
||
|
|
bssl::UniquePtr<SSL> client2, server2;
|
||
|
|
ASSERT_TRUE(ConnectClientAndServer(&client2, &server2, client_ctx.get(),
|
||
|
|
server_ctx2.get()));
|
||
|
|
EXPECT_FALSE(SSL_get_client_CA_list(client2.get()));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// Configuring the empty cipher list, though an error, should still modify the
|
||
|
|
// configuration.
|
||
|
|
TEST(SSLTest, EmptyCipherList) {
|
||
|
|
bssl::UniquePtr<SSL_CTX> ctx(SSL_CTX_new(TLS_method()));
|
||
|
|
ASSERT_TRUE(ctx);
|
||
|
|
|
||
|
|
// Initially, the cipher list is not empty.
|
||
|
|
EXPECT_NE(0u, sk_SSL_CIPHER_num(SSL_CTX_get_ciphers(ctx.get())));
|
||
|
|
|
||
|
|
// Configuring the empty cipher list with |SSL_CTX_set_cipher_list|
|
||
|
|
// succeeds.
|
||
|
|
EXPECT_TRUE(SSL_CTX_set_cipher_list(ctx.get(), ""));
|
||
|
|
// The cipher list should only be populated with default TLS 1.3 ciphersuites
|
||
|
|
EXPECT_EQ(3u, sk_SSL_CIPHER_num(SSL_CTX_get_ciphers(ctx.get())));
|
||
|
|
|
||
|
|
// Configuring the empty cipher list with |SSL_CTX_set_ciphersuites| works
|
||
|
|
EXPECT_TRUE(SSL_CTX_set_ciphersuites(ctx.get(), ""));
|
||
|
|
EXPECT_EQ(0u, sk_SSL_CIPHER_num(ctx->tls13_cipher_list->ciphers.get()));
|
||
|
|
EXPECT_EQ(0u, sk_SSL_CIPHER_num(SSL_CTX_get_ciphers(ctx.get())));
|
||
|
|
|
||
|
|
// Configuring the empty cipher list with |SSL_CTX_set_strict_cipher_list|
|
||
|
|
// fails.
|
||
|
|
EXPECT_FALSE(SSL_CTX_set_strict_cipher_list(ctx.get(), ""));
|
||
|
|
ERR_clear_error();
|
||
|
|
|
||
|
|
// But the cipher list is still updated to empty.
|
||
|
|
EXPECT_EQ(0u, sk_SSL_CIPHER_num(SSL_CTX_get_ciphers(ctx.get())));
|
||
|
|
}
|
||
|
|
|
||
|
|
struct TLSVersionTestParams {
|
||
|
|
uint16_t version;
|
||
|
|
};
|
||
|
|
|
||
|
|
const TLSVersionTestParams kTLSVersionTests[] = {
|
||
|
|
{TLS1_VERSION},
|
||
|
|
{TLS1_1_VERSION},
|
||
|
|
{TLS1_2_VERSION},
|
||
|
|
{TLS1_3_VERSION},
|
||
|
|
};
|
||
|
|
|
||
|
|
struct CertificateKeyTestParams {
|
||
|
|
bssl::UniquePtr<X509> (*certificate)();
|
||
|
|
bssl::UniquePtr<EVP_PKEY> (*key)();
|
||
|
|
int slot_index;
|
||
|
|
const char suite[50];
|
||
|
|
uint16_t corresponding_sigalg;
|
||
|
|
};
|
||
|
|
|
||
|
|
const CertificateKeyTestParams kCertificateKeyTests[] = {
|
||
|
|
{GetTestCertificate, GetTestKey, SSL_PKEY_RSA,
|
||
|
|
"TLS_RSA_WITH_AES_256_CBC_SHA:", SSL_SIGN_RSA_PSS_RSAE_SHA256},
|
||
|
|
{GetECDSATestCertificate, GetECDSATestKey, SSL_PKEY_ECC,
|
||
|
|
"TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA:", SSL_SIGN_ECDSA_SECP256R1_SHA256},
|
||
|
|
{GetED25519TestCertificate, GetED25519TestKey, SSL_PKEY_ED25519,
|
||
|
|
"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256:", SSL_SIGN_ED25519},
|
||
|
|
};
|
||
|
|
|
||
|
|
class MultipleCertificateSlotTest
|
||
|
|
: public testing::TestWithParam<
|
||
|
|
std::tuple<TLSVersionTestParams, CertificateKeyTestParams>> {
|
||
|
|
public:
|
||
|
|
MultipleCertificateSlotTest() {
|
||
|
|
this->version = version_param().version;
|
||
|
|
this->slot_index = certificate_key_param().slot_index;
|
||
|
|
}
|
||
|
|
|
||
|
|
uint16_t version = 0;
|
||
|
|
int slot_index = -1;
|
||
|
|
|
||
|
|
static TLSVersionTestParams version_param() {
|
||
|
|
return std::get<0>(GetParam());
|
||
|
|
}
|
||
|
|
static CertificateKeyTestParams certificate_key_param() {
|
||
|
|
return std::get<1>(GetParam());
|
||
|
|
}
|
||
|
|
|
||
|
|
const void StandardCertificateSlotIndexTests(SSL_CTX *client_ctx,
|
||
|
|
SSL_CTX *server_ctx,
|
||
|
|
std::vector<uint16_t> sigalgs,
|
||
|
|
int last_cert_type_set,
|
||
|
|
int should_connect) {
|
||
|
|
EXPECT_TRUE(SSL_CTX_set_signing_algorithm_prefs(client_ctx, sigalgs.data(),
|
||
|
|
sigalgs.size()));
|
||
|
|
EXPECT_TRUE(SSL_CTX_set_verify_algorithm_prefs(client_ctx, sigalgs.data(),
|
||
|
|
sigalgs.size()));
|
||
|
|
|
||
|
|
ASSERT_TRUE(SSL_CTX_set_min_proto_version(client_ctx, version));
|
||
|
|
ASSERT_TRUE(SSL_CTX_set_max_proto_version(client_ctx, version));
|
||
|
|
ASSERT_TRUE(SSL_CTX_set_min_proto_version(server_ctx, version));
|
||
|
|
ASSERT_TRUE(SSL_CTX_set_max_proto_version(server_ctx, version));
|
||
|
|
|
||
|
|
ClientConfig config;
|
||
|
|
bssl::UniquePtr<SSL> client, server;
|
||
|
|
|
||
|
|
EXPECT_EQ(ConnectClientAndServer(&client, &server, client_ctx, server_ctx,
|
||
|
|
config, false),
|
||
|
|
should_connect);
|
||
|
|
if (!should_connect) {
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
ASSERT_TRUE(CompleteHandshakes(client.get(), server.get()));
|
||
|
|
|
||
|
|
// Check the internal slot index to verify that the correct slot was set.
|
||
|
|
// This should be the slot of the last certificate that was set in
|
||
|
|
// |server_ctx|.
|
||
|
|
EXPECT_EQ(server_ctx->cert->cert_private_key_idx, last_cert_type_set);
|
||
|
|
EXPECT_EQ(server->ctx->cert->cert_private_key_idx, last_cert_type_set);
|
||
|
|
|
||
|
|
// Check the internal slot index to verify that the correct slot was used
|
||
|
|
// during the handshake.
|
||
|
|
EXPECT_EQ(server->config->cert->cert_private_key_idx, slot_index);
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
INSTANTIATE_TEST_SUITE_P(
|
||
|
|
MultipleCertificateSlotAllTest, MultipleCertificateSlotTest,
|
||
|
|
testing::Combine(testing::ValuesIn(kTLSVersionTests),
|
||
|
|
testing::ValuesIn(kCertificateKeyTests)));
|
||
|
|
|
||
|
|
// Sets up the |SSL_CTX| with |SSL_CTX_use_certificate| & |SSL_use_PrivateKey|.
|
||
|
|
TEST_P(MultipleCertificateSlotTest, CertificateSlotIndex) {
|
||
|
|
if (version < TLS1_2_VERSION && slot_index == SSL_PKEY_ED25519) {
|
||
|
|
// ED25519 is not supported in versions prior to TLS1.2.
|
||
|
|
GTEST_SKIP();
|
||
|
|
}
|
||
|
|
bssl::UniquePtr<SSL_CTX> client_ctx(SSL_CTX_new(TLS_method()));
|
||
|
|
bssl::UniquePtr<SSL_CTX> server_ctx(CreateContextWithCertificate(
|
||
|
|
TLS_method(), certificate_key_param().certificate(),
|
||
|
|
certificate_key_param().key()));
|
||
|
|
|
||
|
|
StandardCertificateSlotIndexTests(
|
||
|
|
client_ctx.get(), server_ctx.get(),
|
||
|
|
{SSL_SIGN_ED25519, SSL_SIGN_ECDSA_SECP256R1_SHA256,
|
||
|
|
SSL_SIGN_RSA_PSS_RSAE_SHA256},
|
||
|
|
slot_index, true);
|
||
|
|
}
|
||
|
|
|
||
|
|
// Sets up the |SSL_CTX| with |SSL_CTX_set_chain_and_key|.
|
||
|
|
TEST_P(MultipleCertificateSlotTest, SetChainAndKeyIndex) {
|
||
|
|
if (version < TLS1_2_VERSION && slot_index == SSL_PKEY_ED25519) {
|
||
|
|
// ED25519 is not supported in versions prior to TLS1.2.
|
||
|
|
GTEST_SKIP();
|
||
|
|
}
|
||
|
|
bssl::UniquePtr<SSL_CTX> client_ctx(SSL_CTX_new(TLS_method()));
|
||
|
|
bssl::UniquePtr<SSL_CTX> server_ctx(SSL_CTX_new(TLS_method()));
|
||
|
|
|
||
|
|
uint8_t *buf = nullptr;
|
||
|
|
int cert_len = i2d_X509(certificate_key_param().certificate().get(), &buf);
|
||
|
|
bssl::UniquePtr<uint8_t> free_buf(buf);
|
||
|
|
|
||
|
|
bssl::UniquePtr<CRYPTO_BUFFER> leaf(
|
||
|
|
CRYPTO_BUFFER_new(buf, cert_len, nullptr));
|
||
|
|
ASSERT_TRUE(leaf);
|
||
|
|
std::vector<CRYPTO_BUFFER *> chain = {leaf.get()};
|
||
|
|
|
||
|
|
ASSERT_TRUE(
|
||
|
|
SSL_CTX_set_chain_and_key(server_ctx.get(), &chain[0], chain.size(),
|
||
|
|
certificate_key_param().key().get(), nullptr));
|
||
|
|
|
||
|
|
StandardCertificateSlotIndexTests(
|
||
|
|
client_ctx.get(), server_ctx.get(),
|
||
|
|
{SSL_SIGN_ED25519, SSL_SIGN_ECDSA_SECP256R1_SHA256,
|
||
|
|
SSL_SIGN_RSA_PSS_RSAE_SHA256},
|
||
|
|
slot_index, true);
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST_P(MultipleCertificateSlotTest, AutomaticSelectionSigAlgs) {
|
||
|
|
if (version < TLS1_2_VERSION && slot_index == SSL_PKEY_ED25519) {
|
||
|
|
// ED25519 is not supported in versions prior to TLS1.2.
|
||
|
|
GTEST_SKIP();
|
||
|
|
}
|
||
|
|
|
||
|
|
bssl::UniquePtr<SSL_CTX> client_ctx(SSL_CTX_new(TLS_method()));
|
||
|
|
bssl::UniquePtr<SSL_CTX> server_ctx(SSL_CTX_new(TLS_method()));
|
||
|
|
|
||
|
|
ASSERT_TRUE(
|
||
|
|
SSL_CTX_use_certificate(server_ctx.get(), GetTestCertificate().get()));
|
||
|
|
ASSERT_TRUE(SSL_CTX_use_PrivateKey(server_ctx.get(), GetTestKey().get()));
|
||
|
|
ASSERT_TRUE(SSL_CTX_use_certificate(server_ctx.get(),
|
||
|
|
GetECDSATestCertificate().get()));
|
||
|
|
ASSERT_TRUE(
|
||
|
|
SSL_CTX_use_PrivateKey(server_ctx.get(), GetECDSATestKey().get()));
|
||
|
|
ASSERT_TRUE(SSL_CTX_use_certificate(server_ctx.get(),
|
||
|
|
GetED25519TestCertificate().get()));
|
||
|
|
ASSERT_TRUE(
|
||
|
|
SSL_CTX_use_PrivateKey(server_ctx.get(), GetED25519TestKey().get()));
|
||
|
|
|
||
|
|
|
||
|
|
// Versions prior to TLS1.3 need a valid authentication cipher suite to pair
|
||
|
|
// with the certificate.
|
||
|
|
if (version < TLS1_3_VERSION) {
|
||
|
|
ASSERT_TRUE(SSL_CTX_set_cipher_list(client_ctx.get(),
|
||
|
|
certificate_key_param().suite));
|
||
|
|
}
|
||
|
|
|
||
|
|
StandardCertificateSlotIndexTests(
|
||
|
|
client_ctx.get(), server_ctx.get(),
|
||
|
|
{certificate_key_param().corresponding_sigalg}, SSL_PKEY_ED25519, true);
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST_P(MultipleCertificateSlotTest, AutomaticSelectionCipherAuth) {
|
||
|
|
if ((version < TLS1_2_VERSION && slot_index == SSL_PKEY_ED25519) ||
|
||
|
|
version >= TLS1_3_VERSION) {
|
||
|
|
// ED25519 is not supported in versions prior to TLS1.2.
|
||
|
|
// TLS 1.3 not have cipher-based authentication configuration.
|
||
|
|
GTEST_SKIP();
|
||
|
|
}
|
||
|
|
|
||
|
|
bssl::UniquePtr<SSL_CTX> client_ctx(SSL_CTX_new(TLS_method()));
|
||
|
|
bssl::UniquePtr<SSL_CTX> server_ctx(SSL_CTX_new(TLS_method()));
|
||
|
|
|
||
|
|
ASSERT_TRUE(
|
||
|
|
SSL_CTX_use_certificate(server_ctx.get(), GetTestCertificate().get()));
|
||
|
|
ASSERT_TRUE(SSL_CTX_use_PrivateKey(server_ctx.get(), GetTestKey().get()));
|
||
|
|
ASSERT_TRUE(SSL_CTX_use_certificate(server_ctx.get(),
|
||
|
|
GetECDSATestCertificate().get()));
|
||
|
|
ASSERT_TRUE(
|
||
|
|
SSL_CTX_use_PrivateKey(server_ctx.get(), GetECDSATestKey().get()));
|
||
|
|
ASSERT_TRUE(SSL_CTX_use_certificate(server_ctx.get(),
|
||
|
|
GetED25519TestCertificate().get()));
|
||
|
|
ASSERT_TRUE(
|
||
|
|
SSL_CTX_use_PrivateKey(server_ctx.get(), GetED25519TestKey().get()));
|
||
|
|
|
||
|
|
|
||
|
|
// Versions prior to TLS1.3 need a valid authentication cipher suite to pair
|
||
|
|
// with the certificate.
|
||
|
|
if (version < TLS1_3_VERSION) {
|
||
|
|
ASSERT_TRUE(SSL_CTX_set_cipher_list(client_ctx.get(),
|
||
|
|
certificate_key_param().suite));
|
||
|
|
}
|
||
|
|
|
||
|
|
// We allow all possible sigalgs in this test, but either the ECDSA or ED25519
|
||
|
|
// certificate could be chosen when using an |SSL_aECDSA| ciphersuite.
|
||
|
|
std::vector<uint16_t> sigalgs = {SSL_SIGN_RSA_PSS_RSAE_SHA256};
|
||
|
|
if (slot_index == SSL_PKEY_ED25519) {
|
||
|
|
sigalgs.push_back(SSL_SIGN_ED25519);
|
||
|
|
} else {
|
||
|
|
sigalgs.push_back(SSL_SIGN_ECDSA_SECP256R1_SHA256);
|
||
|
|
}
|
||
|
|
|
||
|
|
StandardCertificateSlotIndexTests(client_ctx.get(), server_ctx.get(), sigalgs,
|
||
|
|
SSL_PKEY_ED25519, true);
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST_P(MultipleCertificateSlotTest, MissingCertificate) {
|
||
|
|
if (version < TLS1_2_VERSION && slot_index == SSL_PKEY_ED25519) {
|
||
|
|
// ED25519 is not supported in versions prior to TLS1.2.
|
||
|
|
GTEST_SKIP();
|
||
|
|
}
|
||
|
|
|
||
|
|
bssl::UniquePtr<SSL_CTX> client_ctx(SSL_CTX_new(TLS_method()));
|
||
|
|
bssl::UniquePtr<SSL_CTX> server_ctx(SSL_CTX_new(TLS_method()));
|
||
|
|
|
||
|
|
ASSERT_TRUE(SSL_CTX_use_PrivateKey(server_ctx.get(), GetTestKey().get()));
|
||
|
|
ASSERT_TRUE(
|
||
|
|
SSL_CTX_use_PrivateKey(server_ctx.get(), GetECDSATestKey().get()));
|
||
|
|
ASSERT_TRUE(
|
||
|
|
SSL_CTX_use_PrivateKey(server_ctx.get(), GetED25519TestKey().get()));
|
||
|
|
|
||
|
|
// Versions prior to TLS1.3 need a valid authentication cipher suite to pair
|
||
|
|
// with the certificate.
|
||
|
|
if (version < TLS1_3_VERSION) {
|
||
|
|
ASSERT_TRUE(SSL_CTX_set_cipher_list(client_ctx.get(),
|
||
|
|
certificate_key_param().suite));
|
||
|
|
}
|
||
|
|
|
||
|
|
StandardCertificateSlotIndexTests(
|
||
|
|
client_ctx.get(), server_ctx.get(),
|
||
|
|
{certificate_key_param().corresponding_sigalg}, -1, false);
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST_P(MultipleCertificateSlotTest, MissingPrivateKey) {
|
||
|
|
if (version < TLS1_2_VERSION && slot_index == SSL_PKEY_ED25519) {
|
||
|
|
// ED25519 is not supported in versions prior to TLS1.2.
|
||
|
|
GTEST_SKIP();
|
||
|
|
}
|
||
|
|
|
||
|
|
bssl::UniquePtr<SSL_CTX> client_ctx(SSL_CTX_new(TLS_method()));
|
||
|
|
bssl::UniquePtr<SSL_CTX> server_ctx(SSL_CTX_new(TLS_method()));
|
||
|
|
|
||
|
|
ASSERT_TRUE(
|
||
|
|
SSL_CTX_use_certificate(server_ctx.get(), GetTestCertificate().get()));
|
||
|
|
ASSERT_TRUE(SSL_CTX_use_certificate(server_ctx.get(),
|
||
|
|
GetECDSATestCertificate().get()));
|
||
|
|
ASSERT_TRUE(SSL_CTX_use_certificate(server_ctx.get(),
|
||
|
|
GetED25519TestCertificate().get()));
|
||
|
|
|
||
|
|
// Versions prior to TLS1.3 need a valid authentication cipher suite to pair
|
||
|
|
// with the certificate.
|
||
|
|
if (version < TLS1_3_VERSION) {
|
||
|
|
ASSERT_TRUE(SSL_CTX_set_cipher_list(client_ctx.get(),
|
||
|
|
certificate_key_param().suite));
|
||
|
|
}
|
||
|
|
|
||
|
|
StandardCertificateSlotIndexTests(
|
||
|
|
client_ctx.get(), server_ctx.get(),
|
||
|
|
{certificate_key_param().corresponding_sigalg}, -1, false);
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
struct MultiTransferReadWriteTestParams {
|
||
|
|
const char suite[50];
|
||
|
|
bool tls13;
|
||
|
|
bssl::UniquePtr<X509> (*certificate)();
|
||
|
|
bssl::UniquePtr<EVP_PKEY> (*key)();
|
||
|
|
};
|
||
|
|
|
||
|
|
static const MultiTransferReadWriteTestParams kMultiTransferReadWriteTests[] = {
|
||
|
|
{"TLS_AES_128_GCM_SHA256:", true, GetECDSATestCertificate, GetECDSATestKey},
|
||
|
|
{"TLS_AES_256_GCM_SHA384:", true, GetECDSATestCertificate, GetECDSATestKey},
|
||
|
|
{"TLS_CHACHA20_POLY1305_SHA256:", true, GetECDSATestCertificate,
|
||
|
|
GetECDSATestKey},
|
||
|
|
{"TLS_RSA_WITH_NULL_SHA:", false, GetTestCertificate, GetTestKey},
|
||
|
|
{"TLS_RSA_WITH_3DES_EDE_CBC_SHA:", false, GetTestCertificate, GetTestKey},
|
||
|
|
{"TLS_RSA_WITH_AES_128_CBC_SHA:", false, GetTestCertificate, GetTestKey},
|
||
|
|
{"TLS_RSA_WITH_AES_256_CBC_SHA:", false, GetTestCertificate, GetTestKey},
|
||
|
|
{"TLS_RSA_WITH_AES_128_CBC_SHA256:", false, GetTestCertificate, GetTestKey},
|
||
|
|
{"TLS_RSA_WITH_AES_128_GCM_SHA256:", false, GetTestCertificate, GetTestKey},
|
||
|
|
{"TLS_RSA_WITH_AES_256_GCM_SHA384:", false, GetTestCertificate, GetTestKey},
|
||
|
|
{"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA:", false, GetECDSATestCertificate,
|
||
|
|
GetECDSATestKey},
|
||
|
|
{"TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA:", false, GetECDSATestCertificate,
|
||
|
|
GetECDSATestKey},
|
||
|
|
{"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA:", false, GetTestCertificate,
|
||
|
|
GetTestKey},
|
||
|
|
{"TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA:", false, GetTestCertificate,
|
||
|
|
GetTestKey},
|
||
|
|
{"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256:", false, GetTestCertificate,
|
||
|
|
GetTestKey},
|
||
|
|
{"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256:", false, GetECDSATestCertificate,
|
||
|
|
GetECDSATestKey},
|
||
|
|
{"TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384:", false, GetECDSATestCertificate,
|
||
|
|
GetECDSATestKey},
|
||
|
|
{"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256:", false, GetTestCertificate,
|
||
|
|
GetTestKey},
|
||
|
|
{"TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384:", false, GetTestCertificate,
|
||
|
|
GetTestKey},
|
||
|
|
{"TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256:", false, GetTestCertificate,
|
||
|
|
GetTestKey},
|
||
|
|
{"TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256:", false,
|
||
|
|
GetECDSATestCertificate, GetECDSATestKey}};
|
||
|
|
|
||
|
|
class MultiTransferReadWriteTest
|
||
|
|
: public testing::TestWithParam<MultiTransferReadWriteTestParams> {};
|
||
|
|
|
||
|
|
INSTANTIATE_TEST_SUITE_P(SuiteTests, MultiTransferReadWriteTest,
|
||
|
|
testing::ValuesIn(kMultiTransferReadWriteTests));
|
||
|
|
|
||
|
|
TEST_P(MultiTransferReadWriteTest, SuiteTransfers) {
|
||
|
|
auto params = GetParam();
|
||
|
|
|
||
|
|
bssl::UniquePtr<SSL_CTX> client_ctx(SSL_CTX_new(TLS_method()));
|
||
|
|
bssl::UniquePtr<SSL_CTX> server_ctx(CreateContextWithCertificate(
|
||
|
|
TLS_method(), params.certificate(), params.key()));
|
||
|
|
|
||
|
|
uint16_t version = TLS1_2_VERSION;
|
||
|
|
int (*set_cipher_suites)(SSL_CTX *, const char *) = SSL_CTX_set_cipher_list;
|
||
|
|
if (params.tls13) {
|
||
|
|
version = TLS1_3_VERSION;
|
||
|
|
set_cipher_suites = SSL_CTX_set_ciphersuites;
|
||
|
|
}
|
||
|
|
|
||
|
|
ASSERT_TRUE(set_cipher_suites(client_ctx.get(), params.suite));
|
||
|
|
ASSERT_TRUE(set_cipher_suites(server_ctx.get(), params.suite));
|
||
|
|
|
||
|
|
ASSERT_TRUE(SSL_CTX_set_min_proto_version(client_ctx.get(), version));
|
||
|
|
ASSERT_TRUE(SSL_CTX_set_max_proto_version(client_ctx.get(), version));
|
||
|
|
ASSERT_TRUE(SSL_CTX_set_min_proto_version(server_ctx.get(), version));
|
||
|
|
ASSERT_TRUE(SSL_CTX_set_max_proto_version(server_ctx.get(), version));
|
||
|
|
|
||
|
|
ClientConfig config;
|
||
|
|
bssl::UniquePtr<SSL> client, server;
|
||
|
|
|
||
|
|
ASSERT_TRUE(ConnectClientAndServer(&client, &server, client_ctx.get(),
|
||
|
|
server_ctx.get(), config, true));
|
||
|
|
|
||
|
|
ASSERT_TRUE(CompleteHandshakes(client.get(), server.get()));
|
||
|
|
|
||
|
|
bssl::UniquePtr<SSL> transfer_server;
|
||
|
|
TransferSSL(&server, server_ctx.get(), &transfer_server, false);
|
||
|
|
|
||
|
|
// All Read/Write connection operations should fail now for a transferred server
|
||
|
|
ASSERT_EQ(-1, SSL_connect(server.get()));
|
||
|
|
ASSERT_EQ(ERR_GET_REASON(ERR_get_error()), ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
|
||
|
|
ERR_clear_error();
|
||
|
|
|
||
|
|
ASSERT_EQ(-1, SSL_accept(server.get()));
|
||
|
|
ASSERT_EQ(ERR_GET_REASON(ERR_get_error()), ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
|
||
|
|
ERR_clear_error();
|
||
|
|
|
||
|
|
ASSERT_EQ(-1, SSL_shutdown(server.get()));
|
||
|
|
ASSERT_EQ(ERR_GET_REASON(ERR_get_error()), ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
|
||
|
|
ERR_clear_error();
|
||
|
|
|
||
|
|
ASSERT_EQ(-1, SSL_do_handshake(server.get()));
|
||
|
|
ASSERT_EQ(ERR_GET_REASON(ERR_get_error()), ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
|
||
|
|
ERR_clear_error();
|
||
|
|
|
||
|
|
ASSERT_EQ(-1, SSL_peek(server.get(), nullptr, 0));
|
||
|
|
ASSERT_EQ(ERR_GET_REASON(ERR_get_error()), ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
|
||
|
|
ERR_clear_error();
|
||
|
|
|
||
|
|
ASSERT_EQ(0, SSL_peek_ex(server.get(), nullptr, 0, nullptr));
|
||
|
|
ASSERT_EQ(ERR_GET_REASON(ERR_get_error()), ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
|
||
|
|
ERR_clear_error();
|
||
|
|
|
||
|
|
ASSERT_EQ(-1, SSL_read(server.get(), nullptr, 0));
|
||
|
|
ASSERT_EQ(ERR_GET_REASON(ERR_get_error()), ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
|
||
|
|
ERR_clear_error();
|
||
|
|
|
||
|
|
ASSERT_EQ(0, SSL_read_ex(server.get(), nullptr, 0, nullptr));
|
||
|
|
ASSERT_EQ(ERR_GET_REASON(ERR_get_error()), ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
|
||
|
|
ERR_clear_error();
|
||
|
|
|
||
|
|
ASSERT_EQ(-1, SSL_write(server.get(), nullptr, 0));
|
||
|
|
ASSERT_EQ(ERR_GET_REASON(ERR_get_error()), ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
|
||
|
|
ERR_clear_error();
|
||
|
|
|
||
|
|
ASSERT_EQ(0, SSL_write_ex(server.get(), nullptr, 0, nullptr));
|
||
|
|
ASSERT_EQ(ERR_GET_REASON(ERR_get_error()), ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
|
||
|
|
ERR_clear_error();
|
||
|
|
|
||
|
|
ASSERT_EQ(0, SSL_key_update(server.get(), SSL_KEY_UPDATE_REQUESTED));
|
||
|
|
ASSERT_EQ(ERR_GET_REASON(ERR_get_error()), ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
|
||
|
|
ERR_clear_error();
|
||
|
|
|
||
|
|
server = std::move(transfer_server);
|
||
|
|
|
||
|
|
char buf[3];
|
||
|
|
size_t buf_cap = sizeof(buf);
|
||
|
|
|
||
|
|
size_t server_transfers = 5;
|
||
|
|
size_t read_write_per_instance = 20;
|
||
|
|
|
||
|
|
for (size_t t = 0; t < server_transfers; t++) {
|
||
|
|
for (size_t i = 0; i < read_write_per_instance; i++) {
|
||
|
|
std::string send_str = std::to_string(i);
|
||
|
|
|
||
|
|
if(t > 0 && i == 0) {
|
||
|
|
// Actually read the previously peeked data from the last transfer
|
||
|
|
std::string peeked_str = std::to_string(read_write_per_instance-1);
|
||
|
|
int read = SSL_read(server.get(), buf, buf_cap);
|
||
|
|
ASSERT_TRUE(read);
|
||
|
|
ASSERT_TRUE((size_t)read == peeked_str.length());
|
||
|
|
std::string read_str(buf, read);
|
||
|
|
ASSERT_EQ(peeked_str, read_str);
|
||
|
|
}
|
||
|
|
|
||
|
|
// Assert server open
|
||
|
|
ASSERT_TRUE(SSL_write(client.get(), send_str.c_str(), send_str.length()));
|
||
|
|
int read = SSL_read(server.get(), buf, buf_cap);
|
||
|
|
ASSERT_TRUE(read);
|
||
|
|
ASSERT_TRUE((size_t)read == send_str.length());
|
||
|
|
std::string read_str(buf, read);
|
||
|
|
ASSERT_EQ(send_str, read_str);
|
||
|
|
|
||
|
|
// Assert server seal
|
||
|
|
ASSERT_TRUE(SSL_write(server.get(), send_str.c_str(), send_str.length()));
|
||
|
|
read = SSL_read(client.get(), buf, buf_cap);
|
||
|
|
ASSERT_TRUE(read);
|
||
|
|
ASSERT_TRUE((size_t)read == send_str.length());
|
||
|
|
read_str = std::string(buf, read);
|
||
|
|
ASSERT_EQ(send_str, read_str);
|
||
|
|
|
||
|
|
if(i == read_write_per_instance - 1) {
|
||
|
|
// Peek some client data before serialization
|
||
|
|
ASSERT_TRUE(SSL_write(client.get(), send_str.c_str(), send_str.length()));
|
||
|
|
read = SSL_peek(server.get(), buf, buf_cap);
|
||
|
|
ASSERT_TRUE(read);
|
||
|
|
ASSERT_TRUE((size_t)read == send_str.length());
|
||
|
|
read_str = std::string(buf, read);
|
||
|
|
ASSERT_EQ(send_str, read_str);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
if(version == TLS1_3_VERSION) {
|
||
|
|
// Queue a Key Update to validate pending handshake flight messages are serialized
|
||
|
|
SSL_key_update(server.get(), SSL_KEY_UPDATE_REQUESTED);
|
||
|
|
}
|
||
|
|
TransferSSL(&server, server_ctx.get(), &transfer_server);
|
||
|
|
server = std::move(transfer_server);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST(SSLTest, BIO) {
|
||
|
|
bssl::UniquePtr<SSL_CTX> client_ctx(SSL_CTX_new(TLS_method()));
|
||
|
|
bssl::UniquePtr<SSL_CTX> server_ctx(
|
||
|
|
CreateContextWithTestCertificate(TLS_method()));
|
||
|
|
ASSERT_TRUE(client_ctx);
|
||
|
|
ASSERT_TRUE(server_ctx);
|
||
|
|
|
||
|
|
for (bool take_ownership : {true, false}) {
|
||
|
|
// For simplicity, get the handshake out of the way first.
|
||
|
|
bssl::UniquePtr<SSL> client, server;
|
||
|
|
ASSERT_TRUE(ConnectClientAndServer(&client, &server, client_ctx.get(),
|
||
|
|
server_ctx.get()));
|
||
|
|
|
||
|
|
// Wrap |client| in an SSL BIO.
|
||
|
|
bssl::UniquePtr<BIO> client_bio(BIO_new(BIO_f_ssl()));
|
||
|
|
ASSERT_TRUE(client_bio);
|
||
|
|
ASSERT_EQ(1, BIO_set_ssl(client_bio.get(), client.get(), take_ownership));
|
||
|
|
if (take_ownership) {
|
||
|
|
client.release();
|
||
|
|
}
|
||
|
|
|
||
|
|
// Flushing the BIO should not crash.
|
||
|
|
EXPECT_EQ(1, BIO_flush(client_bio.get()));
|
||
|
|
|
||
|
|
// Exchange some data.
|
||
|
|
EXPECT_EQ(5, BIO_write(client_bio.get(), "hello", 5));
|
||
|
|
uint8_t buf[5];
|
||
|
|
ASSERT_EQ(5, SSL_read(server.get(), buf, sizeof(buf)));
|
||
|
|
EXPECT_EQ(Bytes("hello"), Bytes(buf));
|
||
|
|
|
||
|
|
EXPECT_EQ(5, SSL_write(server.get(), "world", 5));
|
||
|
|
ASSERT_EQ(5, BIO_read(client_bio.get(), buf, sizeof(buf)));
|
||
|
|
EXPECT_EQ(Bytes("world"), Bytes(buf));
|
||
|
|
|
||
|
|
// |BIO_should_read| should work.
|
||
|
|
EXPECT_EQ(-1, BIO_read(client_bio.get(), buf, sizeof(buf)));
|
||
|
|
EXPECT_TRUE(BIO_should_read(client_bio.get()));
|
||
|
|
|
||
|
|
// Writing data should eventually exceed the buffer size and fail, reporting
|
||
|
|
// |BIO_should_write|.
|
||
|
|
int ret = 0;
|
||
|
|
for (int i = 0; i < 1024; i++) {
|
||
|
|
const uint8_t kZeros[1024] = {0};
|
||
|
|
ret = BIO_write(client_bio.get(), kZeros, sizeof(kZeros));
|
||
|
|
if (ret <= 0) {
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
EXPECT_EQ(-1, ret);
|
||
|
|
EXPECT_TRUE(BIO_should_write(client_bio.get()));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST(SSLTest, BIO_2) {
|
||
|
|
bssl::UniquePtr<SSL_CTX> client_ctx(SSL_CTX_new(TLS_method()));
|
||
|
|
bssl::UniquePtr<SSL_CTX> server_ctx(
|
||
|
|
CreateContextWithTestCertificate(TLS_method()));
|
||
|
|
ASSERT_TRUE(client_ctx);
|
||
|
|
ASSERT_TRUE(server_ctx);
|
||
|
|
|
||
|
|
bssl::UniquePtr<BIO> server_bio(BIO_new_ssl(server_ctx.get(), 0));
|
||
|
|
bssl::UniquePtr<BIO> client_bio(BIO_new_ssl_connect(client_ctx.get()));
|
||
|
|
ASSERT_TRUE(server_bio);
|
||
|
|
ASSERT_TRUE(client_bio);
|
||
|
|
|
||
|
|
SSL *server_ssl_ptr = nullptr, *client_ssl_ptr = nullptr;
|
||
|
|
ASSERT_TRUE(BIO_get_ssl(server_bio.get(), &server_ssl_ptr));
|
||
|
|
ASSERT_TRUE(BIO_get_ssl(client_bio.get(), &client_ssl_ptr));
|
||
|
|
ASSERT_TRUE(server_ssl_ptr);
|
||
|
|
ASSERT_TRUE(client_ssl_ptr);
|
||
|
|
|
||
|
|
// Client SSL BIOs typically establish connections to a host using
|
||
|
|
// |BIO_do_connect|, which leverages the underlying connect |BIO| for socket
|
||
|
|
// management. While OpenSSL provides |BIO_new_accept| and |BIO_s_accept| for
|
||
|
|
// server-side socket setup, we haven't yet implemented this functionality.
|
||
|
|
// For these tests, we opt for traditional SSL connection methods instead
|
||
|
|
// until we have support for server-side socket management via |BIO|s.
|
||
|
|
// Adding full socket management on the server side would exceed the scope of
|
||
|
|
// testing |BIO_new_ssl(_connect)|, especially since we have dedicated tests
|
||
|
|
// elsewhere that verify |BIO_do_connect|'s correctness.
|
||
|
|
BIO *bio1 = nullptr, *bio2 = nullptr;
|
||
|
|
ASSERT_TRUE(BIO_new_bio_pair(&bio1, 0, &bio2, 0));
|
||
|
|
SSL_set_bio(client_ssl_ptr, bio1, bio1);
|
||
|
|
SSL_set_bio(server_ssl_ptr, bio2, bio2);
|
||
|
|
ASSERT_TRUE(CompleteHandshakes(client_ssl_ptr, server_ssl_ptr));
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST(SSLTest, ALPNConfig) {
|
||
|
|
bssl::UniquePtr<SSL_CTX> ctx(SSL_CTX_new(TLS_method()));
|
||
|
|
ASSERT_TRUE(ctx);
|
||
|
|
bssl::UniquePtr<X509> cert = GetTestCertificate();
|
||
|
|
bssl::UniquePtr<EVP_PKEY> key = GetTestKey();
|
||
|
|
ASSERT_TRUE(cert);
|
||
|
|
ASSERT_TRUE(key);
|
||
|
|
ASSERT_TRUE(SSL_CTX_use_certificate(ctx.get(), cert.get()));
|
||
|
|
ASSERT_TRUE(SSL_CTX_use_PrivateKey(ctx.get(), key.get()));
|
||
|
|
|
||
|
|
// Set up some machinery to check the configured ALPN against what is actually
|
||
|
|
// sent over the wire. Note that the ALPN callback is only called when the
|
||
|
|
// client offers ALPN.
|
||
|
|
std::vector<uint8_t> observed_alpn;
|
||
|
|
SSL_CTX_set_alpn_select_cb(
|
||
|
|
ctx.get(),
|
||
|
|
[](SSL *ssl, const uint8_t **out, uint8_t *out_len, const uint8_t *in,
|
||
|
|
unsigned in_len, void *arg) -> int {
|
||
|
|
std::vector<uint8_t> *observed_alpn_ptr =
|
||
|
|
static_cast<std::vector<uint8_t> *>(arg);
|
||
|
|
observed_alpn_ptr->assign(in, in + in_len);
|
||
|
|
return SSL_TLSEXT_ERR_NOACK;
|
||
|
|
},
|
||
|
|
&observed_alpn);
|
||
|
|
auto check_alpn_proto = [&](Span<const uint8_t> expected) {
|
||
|
|
observed_alpn.clear();
|
||
|
|
bssl::UniquePtr<SSL> client, server;
|
||
|
|
ASSERT_TRUE(ConnectClientAndServer(&client, &server, ctx.get(), ctx.get()));
|
||
|
|
EXPECT_EQ(Bytes(expected), Bytes(observed_alpn));
|
||
|
|
};
|
||
|
|
|
||
|
|
// Note that |SSL_CTX_set_alpn_protos|'s return value is reversed.
|
||
|
|
static const uint8_t kValidList[] = {0x03, 'f', 'o', 'o',
|
||
|
|
0x03, 'b', 'a', 'r'};
|
||
|
|
EXPECT_EQ(0,
|
||
|
|
SSL_CTX_set_alpn_protos(ctx.get(), kValidList, sizeof(kValidList)));
|
||
|
|
check_alpn_proto(kValidList);
|
||
|
|
|
||
|
|
// Invalid lists are rejected.
|
||
|
|
static const uint8_t kInvalidList[] = {0x04, 'f', 'o', 'o'};
|
||
|
|
EXPECT_EQ(1, SSL_CTX_set_alpn_protos(ctx.get(), kInvalidList,
|
||
|
|
sizeof(kInvalidList)));
|
||
|
|
|
||
|
|
// Empty lists are valid and are interpreted as disabling ALPN.
|
||
|
|
EXPECT_EQ(0, SSL_CTX_set_alpn_protos(ctx.get(), nullptr, 0));
|
||
|
|
check_alpn_proto({});
|
||
|
|
}
|
||
|
|
|
||
|
|
// Test that the key usage checker can correctly handle issuerUID and
|
||
|
|
// subjectUID. See https://crbug.com/1199744.
|
||
|
|
TEST(SSLTest, KeyUsageWithUIDs) {
|
||
|
|
static const char kGoodKeyUsage[] = R"(
|
||
|
|
-----BEGIN CERTIFICATE-----
|
||
|
|
MIIB7DCCAZOgAwIBAgIJANlMBNpJfb/rMAoGCCqGSM49BAMCMEUxCzAJBgNVBAYT
|
||
|
|
AkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBXaWRn
|
||
|
|
aXRzIFB0eSBMdGQwHhcNMTQwNDIzMjMyMTU3WhcNMTQwNTIzMjMyMTU3WjBFMQsw
|
||
|
|
CQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJu
|
||
|
|
ZXQgV2lkZ2l0cyBQdHkgTHRkMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE5itp
|
||
|
|
4r9ln5e+Lx4NlIpM1Zdrt6keDUb73ampHp3culoB59aXqAoY+cPEox5W4nyDSNsW
|
||
|
|
Ghz1HX7xlC1Lz3IiwYEEABI0VoIEABI0VqNgMF4wHQYDVR0OBBYEFKuE0qyrlfCC
|
||
|
|
ThZ4B1VXX+QmjYLRMB8GA1UdIwQYMBaAFKuE0qyrlfCCThZ4B1VXX+QmjYLRMA4G
|
||
|
|
A1UdDwEB/wQEAwIHgDAMBgNVHRMEBTADAQH/MAoGCCqGSM49BAMCA0cAMEQCIEWJ
|
||
|
|
34EcqW5MHwLIA1hZ2Tj/jV2QjN02KLxis9mFsqDKAiAMlMTkzsM51vVs9Ohqa+Rc
|
||
|
|
4Z7qDhjIhiF4dM0uEDYRVA==
|
||
|
|
-----END CERTIFICATE-----
|
||
|
|
)";
|
||
|
|
static const char kBadKeyUsage[] = R"(
|
||
|
|
-----BEGIN CERTIFICATE-----
|
||
|
|
MIIB7jCCAZOgAwIBAgIJANlMBNpJfb/rMAoGCCqGSM49BAMCMEUxCzAJBgNVBAYT
|
||
|
|
AkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBXaWRn
|
||
|
|
aXRzIFB0eSBMdGQwHhcNMTQwNDIzMjMyMTU3WhcNMTQwNTIzMjMyMTU3WjBFMQsw
|
||
|
|
CQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJu
|
||
|
|
ZXQgV2lkZ2l0cyBQdHkgTHRkMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE5itp
|
||
|
|
4r9ln5e+Lx4NlIpM1Zdrt6keDUb73ampHp3culoB59aXqAoY+cPEox5W4nyDSNsW
|
||
|
|
Ghz1HX7xlC1Lz3IiwYEEABI0VoIEABI0VqNgMF4wHQYDVR0OBBYEFKuE0qyrlfCC
|
||
|
|
ThZ4B1VXX+QmjYLRMB8GA1UdIwQYMBaAFKuE0qyrlfCCThZ4B1VXX+QmjYLRMA4G
|
||
|
|
A1UdDwEB/wQEAwIDCDAMBgNVHRMEBTADAQH/MAoGCCqGSM49BAMCA0kAMEYCIQC6
|
||
|
|
taYBUDu2gcZC6EMk79FBHArYI0ucF+kzvETegZCbBAIhANtObFec5gtso/47moPD
|
||
|
|
RHrQbWsFUakETXL9QMlegh5t
|
||
|
|
-----END CERTIFICATE-----
|
||
|
|
)";
|
||
|
|
|
||
|
|
bssl::UniquePtr<X509> good = CertFromPEM(kGoodKeyUsage);
|
||
|
|
ASSERT_TRUE(good);
|
||
|
|
bssl::UniquePtr<X509> bad = CertFromPEM(kBadKeyUsage);
|
||
|
|
ASSERT_TRUE(bad);
|
||
|
|
|
||
|
|
// We check key usage when configuring EC certificates to distinguish ECDSA
|
||
|
|
// and ECDH.
|
||
|
|
bssl::UniquePtr<SSL_CTX> ctx(SSL_CTX_new(TLS_method()));
|
||
|
|
ASSERT_TRUE(ctx);
|
||
|
|
EXPECT_TRUE(SSL_CTX_use_certificate(ctx.get(), good.get()));
|
||
|
|
EXPECT_FALSE(SSL_CTX_use_certificate(ctx.get(), bad.get()));
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
// Test that |SSL_ERROR_SYSCALL| continues to work after a close_notify.
|
||
|
|
TEST(SSLTest, ErrorSyscallAfterCloseNotify) {
|
||
|
|
// Make a custom |BIO| where writes fail, but without pushing to the error
|
||
|
|
// queue.
|
||
|
|
bssl::UniquePtr<BIO_METHOD> method(BIO_meth_new(0, nullptr));
|
||
|
|
ASSERT_TRUE(method);
|
||
|
|
BIO_meth_set_create(method.get(), [](BIO *b) -> int {
|
||
|
|
BIO_set_init(b, 1);
|
||
|
|
return 1;
|
||
|
|
});
|
||
|
|
static bool write_failed = false;
|
||
|
|
BIO_meth_set_write(method.get(), [](BIO *, const char *, int) -> int {
|
||
|
|
// Fail the operation and don't add to the error queue.
|
||
|
|
write_failed = true;
|
||
|
|
return -1;
|
||
|
|
});
|
||
|
|
bssl::UniquePtr<BIO> wbio_silent_error(BIO_new(method.get()));
|
||
|
|
ASSERT_TRUE(wbio_silent_error);
|
||
|
|
|
||
|
|
bssl::UniquePtr<SSL_CTX> client_ctx(SSL_CTX_new(TLS_method()));
|
||
|
|
bssl::UniquePtr<SSL_CTX> server_ctx =
|
||
|
|
CreateContextWithTestCertificate(TLS_method());
|
||
|
|
ASSERT_TRUE(client_ctx);
|
||
|
|
ASSERT_TRUE(server_ctx);
|
||
|
|
bssl::UniquePtr<SSL> client, server;
|
||
|
|
ASSERT_TRUE(ConnectClientAndServer(&client, &server, client_ctx.get(),
|
||
|
|
server_ctx.get()));
|
||
|
|
|
||
|
|
// Replace the write |BIO| with |wbio_silent_error|.
|
||
|
|
SSL_set0_wbio(client.get(), wbio_silent_error.release());
|
||
|
|
|
||
|
|
// Writes should fail. There is nothing in the error queue, so
|
||
|
|
// |SSL_ERROR_SYSCALL| indicates the caller needs to check out-of-band.
|
||
|
|
const uint8_t data[1] = {0};
|
||
|
|
int ret = SSL_write(client.get(), data, sizeof(data));
|
||
|
|
EXPECT_EQ(ret, -1);
|
||
|
|
EXPECT_EQ(SSL_get_error(client.get(), ret), SSL_ERROR_SYSCALL);
|
||
|
|
EXPECT_TRUE(write_failed);
|
||
|
|
write_failed = false;
|
||
|
|
|
||
|
|
// Send a close_notify from the server. It should return 0 because
|
||
|
|
// close_notify was sent, but not received. Confusingly, this is a success
|
||
|
|
// output for |SSL_shutdown|'s API.
|
||
|
|
EXPECT_EQ(SSL_shutdown(server.get()), 0);
|
||
|
|
|
||
|
|
// Read the close_notify on the client.
|
||
|
|
uint8_t buf[1];
|
||
|
|
ret = SSL_read(client.get(), buf, sizeof(buf));
|
||
|
|
EXPECT_EQ(ret, 0);
|
||
|
|
EXPECT_EQ(SSL_get_error(client.get(), ret), SSL_ERROR_ZERO_RETURN);
|
||
|
|
|
||
|
|
// Further calls to |SSL_read| continue to report |SSL_ERROR_ZERO_RETURN|.
|
||
|
|
ret = SSL_read(client.get(), buf, sizeof(buf));
|
||
|
|
EXPECT_EQ(ret, 0);
|
||
|
|
EXPECT_EQ(SSL_get_error(client.get(), ret), SSL_ERROR_ZERO_RETURN);
|
||
|
|
|
||
|
|
// Although the client has seen close_notify, it should continue to report
|
||
|
|
// |SSL_ERROR_SYSCALL| when its writes fail.
|
||
|
|
ret = SSL_write(client.get(), data, sizeof(data));
|
||
|
|
EXPECT_EQ(ret, -1);
|
||
|
|
EXPECT_EQ(SSL_get_error(client.get(), ret), SSL_ERROR_SYSCALL);
|
||
|
|
EXPECT_TRUE(write_failed);
|
||
|
|
write_failed = false;
|
||
|
|
|
||
|
|
// Cause |BIO_write| to fail with a return value of zero instead.
|
||
|
|
// |SSL_get_error| should not misinterpret this as a close_notify.
|
||
|
|
//
|
||
|
|
// This is not actually a correct implementation of |BIO_write|, but the rest
|
||
|
|
// of the code treats zero from |BIO_write| as an error, so ensure it does so
|
||
|
|
// correctly. Fixing https://crbug.com/boringssl/503 will make this case moot.
|
||
|
|
BIO_meth_set_write(method.get(), [](BIO *, const char *, int) -> int {
|
||
|
|
write_failed = true;
|
||
|
|
return 0;
|
||
|
|
});
|
||
|
|
ret = SSL_write(client.get(), data, sizeof(data));
|
||
|
|
EXPECT_EQ(ret, 0);
|
||
|
|
EXPECT_EQ(SSL_get_error(client.get(), ret), SSL_ERROR_SYSCALL);
|
||
|
|
EXPECT_TRUE(write_failed);
|
||
|
|
write_failed = false;
|
||
|
|
}
|
||
|
|
|
||
|
|
} // namespace
|
||
|
|
BSSL_NAMESPACE_END
|