Test SSL_add_client_CA.
That function actually got a little complicated after the CRYPTO_BUFFER work. Change-Id: Ib679a9f2bcc2c974fe059af49805b8200e77bd03 Reviewed-on: https://boringssl-review.googlesource.com/19764 Commit-Queue: David Benjamin <davidben@google.com> Commit-Queue: Steven Valdez <svaldez@google.com> Reviewed-by: Steven Valdez <svaldez@google.com> CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
This commit is contained in:
parent
3969fdf860
commit
c79ae7aa8b
317
ssl/ssl_test.cc
317
ssl/ssl_test.cc
@ -1104,149 +1104,6 @@ static bool TestPaddingExtension(uint16_t max_version,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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(sk_X509_NAME_push(stack.get(), name_dup.get()));
|
|
||||||
name_dup.release();
|
|
||||||
|
|
||||||
// |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()));
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
// 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(SSL_CTX_sessions(ctx), 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret->session_id_length = SSL3_SSL_SESSION_ID_LENGTH;
|
|
||||||
OPENSSL_memset(ret->session_id, 0, ret->session_id_length);
|
|
||||||
OPENSSL_memcpy(ret->session_id, &number, sizeof(number));
|
|
||||||
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 uint16_t EpochFromSequence(uint64_t seq) {
|
|
||||||
return static_cast<uint16_t>(seq >> 48);
|
|
||||||
}
|
|
||||||
|
|
||||||
static bssl::UniquePtr<X509> GetTestCertificate() {
|
static bssl::UniquePtr<X509> GetTestCertificate() {
|
||||||
static const char kCertPEM[] =
|
static const char kCertPEM[] =
|
||||||
"-----BEGIN CERTIFICATE-----\n"
|
"-----BEGIN CERTIFICATE-----\n"
|
||||||
@ -1437,6 +1294,180 @@ static bssl::UniquePtr<EVP_PKEY> GetChainTestKey() {
|
|||||||
PEM_read_bio_PrivateKey(bio.get(), nullptr, nullptr, nullptr));
|
PEM_read_bio_PrivateKey(bio.get(), nullptr, nullptr, nullptr));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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(sk_X509_NAME_push(stack.get(), name_dup.get()));
|
||||||
|
name_dup.release();
|
||||||
|
|
||||||
|
// |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));
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
// 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(SSL_CTX_sessions(ctx), 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret->session_id_length = SSL3_SSL_SESSION_ID_LENGTH;
|
||||||
|
OPENSSL_memset(ret->session_id, 0, ret->session_id_length);
|
||||||
|
OPENSSL_memcpy(ret->session_id, &number, sizeof(number));
|
||||||
|
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 uint16_t EpochFromSequence(uint64_t seq) {
|
||||||
|
return static_cast<uint16_t>(seq >> 48);
|
||||||
|
}
|
||||||
|
|
||||||
static const uint8_t kTestName[] = {
|
static const uint8_t kTestName[] = {
|
||||||
0x30, 0x45, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
|
0x30, 0x45, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
|
||||||
0x02, 0x41, 0x55, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08,
|
0x02, 0x41, 0x55, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08,
|
||||||
|
Loading…
Reference in New Issue
Block a user