blob: 2aaa9cc8d637a7598321e4a804e9c33f8fd150b8 [file] [log] [blame]
//
// Copyright 2021 gRPC authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
#include "src/core/lib/security/credentials/tls/grpc_tls_certificate_verifier.h"
#include <deque>
#include <list>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/string_util.h>
#include "src/core/lib/gpr/tmpfile.h"
#include "src/core/lib/gprpp/crash.h"
#include "src/core/lib/iomgr/load_file.h"
#include "src/core/lib/security/security_connector/tls/tls_security_connector.h"
#include "src/core/lib/slice/slice_internal.h"
#include "test/core/util/test_config.h"
#include "test/core/util/tls_utils.h"
namespace grpc_core {
namespace testing {
// Unit tests for grpc_tls_certificate_verifier and all its successors.
// In these tests, |request_| is not outliving the test itself, so it's fine to
// point fields in |request_| directly to the address of local variables. In
// actual implementation, these fields are dynamically allocated.
class GrpcTlsCertificateVerifierTest : public ::testing::Test {
protected:
void SetUp() override { memset(&request_, 0, sizeof(request_)); }
void TearDown() override {}
grpc_tls_custom_verification_check_request request_;
NoOpCertificateVerifier no_op_certificate_verifier_;
HostNameCertificateVerifier hostname_certificate_verifier_;
};
TEST_F(GrpcTlsCertificateVerifierTest, SyncExternalVerifierSucceeds) {
auto* sync_verifier = new SyncExternalVerifier(true);
ExternalCertificateVerifier core_external_verifier(sync_verifier->base());
absl::Status sync_status;
EXPECT_TRUE(core_external_verifier.Verify(
&request_, [](absl::Status) {}, &sync_status));
EXPECT_TRUE(sync_status.ok())
<< sync_status.code() << " " << sync_status.message();
}
TEST_F(GrpcTlsCertificateVerifierTest, SyncExternalVerifierFails) {
auto* sync_verifier = new SyncExternalVerifier(false);
ExternalCertificateVerifier core_external_verifier(sync_verifier->base());
absl::Status sync_status;
EXPECT_TRUE(core_external_verifier.Verify(
&request_, [](absl::Status) {}, &sync_status));
EXPECT_EQ(sync_status.code(), absl::StatusCode::kUnauthenticated);
EXPECT_EQ(sync_status.ToString(),
"UNAUTHENTICATED: SyncExternalVerifier failed");
}
TEST_F(GrpcTlsCertificateVerifierTest, AsyncExternalVerifierSucceeds) {
absl::Status sync_status;
// This is to make sure the callback has already been completed before we
// destroy ExternalCertificateVerifier object.
gpr_event callback_completed_event;
gpr_event_init(&callback_completed_event);
auto* async_verifier = new AsyncExternalVerifier(true);
ExternalCertificateVerifier core_external_verifier(async_verifier->base());
EXPECT_FALSE(core_external_verifier.Verify(
&request_,
[&callback_completed_event](absl::Status async_status) {
EXPECT_TRUE(async_status.ok())
<< async_status.code() << " " << async_status.message();
gpr_event_set(&callback_completed_event, reinterpret_cast<void*>(1));
},
&sync_status));
void* callback_completed =
gpr_event_wait(&callback_completed_event,
gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC),
gpr_time_from_seconds(10, GPR_TIMESPAN)));
EXPECT_NE(callback_completed, nullptr);
}
TEST_F(GrpcTlsCertificateVerifierTest, AsyncExternalVerifierFails) {
absl::Status sync_status;
// This is to make sure the callback has already been completed before we
// destroy ExternalCertificateVerifier object.
gpr_event callback_completed_event;
gpr_event_init(&callback_completed_event);
auto* async_verifier = new AsyncExternalVerifier(false);
ExternalCertificateVerifier core_external_verifier(async_verifier->base());
EXPECT_FALSE(core_external_verifier.Verify(
&request_,
[&callback_completed_event](absl::Status async_status) {
gpr_log(GPR_INFO, "Callback is invoked.");
EXPECT_EQ(async_status.code(), absl::StatusCode::kUnauthenticated);
EXPECT_EQ(async_status.ToString(),
"UNAUTHENTICATED: AsyncExternalVerifier failed");
gpr_event_set(&callback_completed_event, reinterpret_cast<void*>(1));
},
&sync_status));
void* callback_completed =
gpr_event_wait(&callback_completed_event,
gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC),
gpr_time_from_seconds(10, GPR_TIMESPAN)));
EXPECT_NE(callback_completed, nullptr);
}
TEST_F(GrpcTlsCertificateVerifierTest, NoOpCertificateVerifierSucceeds) {
absl::Status sync_status;
EXPECT_TRUE(no_op_certificate_verifier_.Verify(
&request_, [](absl::Status) {}, &sync_status));
EXPECT_TRUE(sync_status.ok())
<< sync_status.code() << " " << sync_status.message();
}
TEST_F(GrpcTlsCertificateVerifierTest, HostnameVerifierNullTargetName) {
absl::Status sync_status;
EXPECT_TRUE(hostname_certificate_verifier_.Verify(
&request_, [](absl::Status) {}, &sync_status));
EXPECT_EQ(sync_status.code(), absl::StatusCode::kUnauthenticated);
EXPECT_EQ(sync_status.ToString(),
"UNAUTHENTICATED: Target name is not specified.");
}
TEST_F(GrpcTlsCertificateVerifierTest, HostnameVerifierInvalidTargetName) {
absl::Status sync_status;
request_.target_name = "[foo.com@443";
EXPECT_TRUE(hostname_certificate_verifier_.Verify(
&request_, [](absl::Status) {}, &sync_status));
EXPECT_EQ(sync_status.code(), absl::StatusCode::kUnauthenticated);
EXPECT_EQ(sync_status.ToString(),
"UNAUTHENTICATED: Failed to split hostname and port.");
}
TEST_F(GrpcTlsCertificateVerifierTest, HostnameVerifierDNSExactCheckSucceeds) {
absl::Status sync_status;
request_.target_name = "foo.com:443";
char* dns_names[] = {const_cast<char*>("foo.com")};
request_.peer_info.san_names.dns_names = dns_names;
request_.peer_info.san_names.dns_names_size = 1;
EXPECT_TRUE(hostname_certificate_verifier_.Verify(
&request_, [](absl::Status) {}, &sync_status));
EXPECT_TRUE(sync_status.ok())
<< sync_status.code() << " " << sync_status.message();
}
TEST_F(GrpcTlsCertificateVerifierTest,
HostnameVerifierDNSWildcardCheckSucceeds) {
absl::Status sync_status;
request_.target_name = "foo.bar.com:443";
char* dns_names[] = {const_cast<char*>("*.bar.com")};
request_.peer_info.san_names.dns_names = dns_names;
request_.peer_info.san_names.dns_names_size = 1;
EXPECT_TRUE(hostname_certificate_verifier_.Verify(
&request_, [](absl::Status) {}, &sync_status));
EXPECT_TRUE(sync_status.ok())
<< sync_status.code() << " " << sync_status.message();
}
TEST_F(GrpcTlsCertificateVerifierTest,
HostnameVerifierDNSWildcardCaseInsensitiveCheckSucceeds) {
absl::Status sync_status;
request_.target_name = "fOo.bar.cOm:443";
char* dns_names[] = {const_cast<char*>("*.BaR.Com")};
request_.peer_info.san_names.dns_names = dns_names;
request_.peer_info.san_names.dns_names_size = 1;
EXPECT_TRUE(hostname_certificate_verifier_.Verify(
&request_, [](absl::Status) {}, &sync_status));
EXPECT_TRUE(sync_status.ok())
<< sync_status.code() << " " << sync_status.message();
}
TEST_F(GrpcTlsCertificateVerifierTest,
HostnameVerifierDNSTopWildcardCheckFails) {
absl::Status sync_status;
request_.target_name = "foo.com:443";
char* dns_names[] = {const_cast<char*>("*.")};
request_.peer_info.san_names.dns_names = dns_names;
request_.peer_info.san_names.dns_names_size = 1;
EXPECT_TRUE(hostname_certificate_verifier_.Verify(
&request_, [](absl::Status) {}, &sync_status));
EXPECT_EQ(sync_status.code(), absl::StatusCode::kUnauthenticated);
EXPECT_EQ(sync_status.ToString(),
"UNAUTHENTICATED: Hostname Verification Check failed.");
}
TEST_F(GrpcTlsCertificateVerifierTest, HostnameVerifierDNSExactCheckFails) {
absl::Status sync_status;
request_.target_name = "foo.com:443";
char* dns_names[] = {const_cast<char*>("bar.com")};
request_.peer_info.san_names.dns_names = dns_names;
request_.peer_info.san_names.dns_names_size = 1;
EXPECT_TRUE(hostname_certificate_verifier_.Verify(
&request_, [](absl::Status) {}, &sync_status));
EXPECT_EQ(sync_status.code(), absl::StatusCode::kUnauthenticated);
EXPECT_EQ(sync_status.ToString(),
"UNAUTHENTICATED: Hostname Verification Check failed.");
}
TEST_F(GrpcTlsCertificateVerifierTest, HostnameVerifierIpCheckSucceeds) {
absl::Status sync_status;
request_.target_name = "192.168.0.1:443";
char* ip_names[] = {const_cast<char*>("192.168.0.1")};
request_.peer_info.san_names.ip_names = ip_names;
request_.peer_info.san_names.ip_names_size = 1;
EXPECT_TRUE(hostname_certificate_verifier_.Verify(
&request_, [](absl::Status) {}, &sync_status));
EXPECT_TRUE(sync_status.ok())
<< sync_status.code() << " " << sync_status.message();
}
TEST_F(GrpcTlsCertificateVerifierTest, HostnameVerifierIpCheckFails) {
absl::Status sync_status;
request_.target_name = "192.168.0.1:443";
char* ip_names[] = {const_cast<char*>("192.168.1.1")};
request_.peer_info.san_names.ip_names = ip_names;
request_.peer_info.san_names.ip_names_size = 1;
EXPECT_TRUE(hostname_certificate_verifier_.Verify(
&request_, [](absl::Status) {}, &sync_status));
EXPECT_EQ(sync_status.code(), absl::StatusCode::kUnauthenticated);
EXPECT_EQ(sync_status.ToString(),
"UNAUTHENTICATED: Hostname Verification Check failed.");
}
TEST_F(GrpcTlsCertificateVerifierTest,
HostnameVerifierCommonNameCheckSucceeds) {
absl::Status sync_status;
request_.target_name = "foo.com:443";
request_.peer_info.common_name = "foo.com";
EXPECT_TRUE(hostname_certificate_verifier_.Verify(
&request_, [](absl::Status) {}, &sync_status));
EXPECT_TRUE(sync_status.ok())
<< sync_status.code() << " " << sync_status.message();
}
TEST_F(GrpcTlsCertificateVerifierTest, HostnameVerifierCommonNameCheckFails) {
absl::Status sync_status;
request_.target_name = "foo.com:443";
request_.peer_info.common_name = "bar.com";
EXPECT_TRUE(hostname_certificate_verifier_.Verify(
&request_, [](absl::Status) {}, &sync_status));
EXPECT_EQ(sync_status.code(), absl::StatusCode::kUnauthenticated);
EXPECT_EQ(sync_status.ToString(),
"UNAUTHENTICATED: Hostname Verification Check failed.");
}
TEST_F(GrpcTlsCertificateVerifierTest, ComparingDifferentObjectTypesFails) {
grpc_tls_certificate_verifier_external verifier = {nullptr, nullptr, nullptr,
nullptr};
ExternalCertificateVerifier external_verifier(&verifier);
HostNameCertificateVerifier hostname_certificate_verifier;
EXPECT_NE(external_verifier.Compare(&hostname_certificate_verifier), 0);
EXPECT_NE(hostname_certificate_verifier.Compare(&external_verifier), 0);
}
TEST_F(GrpcTlsCertificateVerifierTest, HostNameCertificateVerifier) {
HostNameCertificateVerifier hostname_certificate_verifier_1;
HostNameCertificateVerifier hostname_certificate_verifier_2;
EXPECT_EQ(
hostname_certificate_verifier_1.Compare(&hostname_certificate_verifier_2),
0);
EXPECT_EQ(
hostname_certificate_verifier_2.Compare(&hostname_certificate_verifier_1),
0);
}
TEST_F(GrpcTlsCertificateVerifierTest, ExternalCertificateVerifierSuccess) {
grpc_tls_certificate_verifier_external verifier = {nullptr, nullptr, nullptr,
nullptr};
ExternalCertificateVerifier external_verifier_1(&verifier);
ExternalCertificateVerifier external_verifier_2(&verifier);
EXPECT_EQ(external_verifier_1.Compare(&external_verifier_2), 0);
EXPECT_EQ(external_verifier_2.Compare(&external_verifier_1), 0);
}
TEST_F(GrpcTlsCertificateVerifierTest, ExternalCertificateVerifierFailure) {
grpc_tls_certificate_verifier_external verifier_1 = {nullptr, nullptr,
nullptr, nullptr};
ExternalCertificateVerifier external_verifier_1(&verifier_1);
grpc_tls_certificate_verifier_external verifier_2 = {nullptr, nullptr,
nullptr, nullptr};
ExternalCertificateVerifier external_verifier_2(&verifier_2);
EXPECT_NE(external_verifier_1.Compare(&external_verifier_2), 0);
EXPECT_NE(external_verifier_2.Compare(&external_verifier_1), 0);
}
} // namespace testing
} // namespace grpc_core
int main(int argc, char** argv) {
grpc::testing::TestEnvironment env(&argc, argv);
::testing::InitGoogleTest(&argc, argv);
grpc_init();
int ret = RUN_ALL_TESTS();
grpc_shutdown();
return ret;
}