The C based gRPC (C++, Python, Ruby, Objective-C, PHP, C#) https://grpc.io/
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

189 lines
7.9 KiB

//
// Copyright 2020 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 <memory>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <grpc/grpc.h>
#include <grpc/grpc_security.h>
#include <grpcpp/security/server_credentials.h>
#include <grpcpp/security/tls_credentials_options.h>
#include "src/cpp/client/secure_credentials.h"
#include "test/core/util/port.h"
#include "test/core/util/test_config.h"
#include "test/cpp/util/tls_test_utils.h"
#define CA_CERT_PATH "src/core/tsi/test_creds/ca.pem"
#define SERVER_CERT_PATH "src/core/tsi/test_creds/server1.pem"
#define SERVER_KEY_PATH "src/core/tsi/test_creds/server1.key"
TlsCreds: Support revocation of intermediate in chain. (#32544) This PR is a small code change with a lot of new test data. [In OpenSSL, there are two flags that configure CRL checks. Coping relevant section:](https://www.openssl.org/docs/man1.0.2/man3/X509_VERIFY_PARAM_get_depth.html) > - X509_V_FLAG_CRL_CHECK enables CRL checking for the certificate chain leaf certificate. An error occurs if a suitable CRL cannot be found. > - X509_V_FLAG_CRL_CHECK_ALL enables CRL checking for the entire certificate chain. We currently only set `X509_V_FLAG_CRL_CHECK`, so we will only ever check if the leaf certificate is revoked. We should check the whole chain. I am open to making this a user configuration if we want to do it that way, but we certainly need to be able to check the whole chain. So, this PR contains the small code change in `ssl_transport_security.cc` to use the `X509_V_FLAG_CRL_CHECK_ALL` flag. Then the rest of the changes are in tests. I've added all the necessary files to have a chain built that looks as follows `Root CA -> Revoked Intermediate CA -> Leaf Certificate`, and added a test for this case as well. You can verify that on master this new test will fail (i.e. the handshake will succeed even though the intermediate CA is revoked) by checking out this branch, running `git checkout master -- ./src/core/tsi/ssl_transport_security.cc`, then running the test. I also slightly reorganized test/core/tsi/test_creds/ so that the CRLs are in their own directory, which is the way our API intends to accept CRLs.
2 years ago
#define CRL_DIR_PATH "test/core/tsi/test_creds/crl_data/crls"
namespace {
constexpr const char* kRootCertName = "root_cert_name";
constexpr const char* kRootCertContents = "root_cert_contents";
constexpr const char* kIdentityCertName = "identity_cert_name";
constexpr const char* kIdentityCertPrivateKey = "identity_private_key";
constexpr const char* kIdentityCertContents = "identity_cert_contents";
using ::grpc::experimental::ExternalCertificateVerifier;
using ::grpc::experimental::FileWatcherCertificateProvider;
using ::grpc::experimental::StaticDataCertificateProvider;
} // namespace
namespace grpc {
namespace testing {
namespace {
TEST(
CredentialsTest,
TlsServerCredentialsWithStaticDataCertificateProviderLoadingRootAndIdentity) {
experimental::IdentityKeyCertPair key_cert_pair;
key_cert_pair.private_key = kIdentityCertPrivateKey;
key_cert_pair.certificate_chain = kIdentityCertContents;
std::vector<experimental::IdentityKeyCertPair> identity_key_cert_pairs;
identity_key_cert_pairs.emplace_back(key_cert_pair);
auto certificate_provider = std::make_shared<StaticDataCertificateProvider>(
kRootCertContents, identity_key_cert_pairs);
grpc::experimental::TlsServerCredentialsOptions options(certificate_provider);
options.watch_root_certs();
options.set_root_cert_name(kRootCertName);
options.watch_identity_key_cert_pairs();
options.set_identity_cert_name(kIdentityCertName);
options.set_cert_request_type(
GRPC_SSL_REQUEST_AND_REQUIRE_CLIENT_CERTIFICATE_AND_VERIFY);
auto server_credentials = grpc::experimental::TlsServerCredentials(options);
GPR_ASSERT(server_credentials.get() != nullptr);
}
// ServerCredentials should always have identity credential presented.
// Otherwise gRPC stack will fail.
TEST(CredentialsTest,
TlsServerCredentialsWithStaticDataCertificateProviderLoadingIdentityOnly) {
experimental::IdentityKeyCertPair key_cert_pair;
key_cert_pair.private_key = kIdentityCertPrivateKey;
key_cert_pair.certificate_chain = kIdentityCertContents;
std::vector<experimental::IdentityKeyCertPair> identity_key_cert_pairs;
// Adding two key_cert_pair(s) should still work.
identity_key_cert_pairs.emplace_back(key_cert_pair);
identity_key_cert_pairs.emplace_back(key_cert_pair);
auto certificate_provider =
std::make_shared<StaticDataCertificateProvider>(identity_key_cert_pairs);
grpc::experimental::TlsServerCredentialsOptions options(certificate_provider);
options.watch_identity_key_cert_pairs();
options.set_identity_cert_name(kIdentityCertName);
options.set_cert_request_type(
GRPC_SSL_REQUEST_AND_REQUIRE_CLIENT_CERTIFICATE_AND_VERIFY);
auto server_credentials = grpc::experimental::TlsServerCredentials(options);
GPR_ASSERT(server_credentials.get() != nullptr);
}
TEST(
CredentialsTest,
TlsServerCredentialsWithFileWatcherCertificateProviderLoadingRootAndIdentity) {
auto certificate_provider = std::make_shared<FileWatcherCertificateProvider>(
SERVER_KEY_PATH, SERVER_CERT_PATH, CA_CERT_PATH, 1);
grpc::experimental::TlsServerCredentialsOptions options(certificate_provider);
options.watch_root_certs();
options.set_root_cert_name(kRootCertName);
options.watch_identity_key_cert_pairs();
options.set_identity_cert_name(kIdentityCertName);
options.set_cert_request_type(
GRPC_SSL_REQUEST_AND_REQUIRE_CLIENT_CERTIFICATE_AND_VERIFY);
auto server_credentials = grpc::experimental::TlsServerCredentials(options);
GPR_ASSERT(server_credentials.get() != nullptr);
}
TEST(CredentialsTest, TlsServerCredentialsWithCrlChecking) {
auto certificate_provider = std::make_shared<FileWatcherCertificateProvider>(
SERVER_KEY_PATH, SERVER_CERT_PATH, CA_CERT_PATH, 1);
grpc::experimental::TlsServerCredentialsOptions options(certificate_provider);
options.watch_root_certs();
options.set_root_cert_name(kRootCertName);
options.watch_identity_key_cert_pairs();
options.set_identity_cert_name(kIdentityCertName);
options.set_cert_request_type(
GRPC_SSL_REQUEST_AND_REQUIRE_CLIENT_CERTIFICATE_AND_VERIFY);
options.set_crl_directory(CRL_DIR_PATH);
auto server_credentials = grpc::experimental::TlsServerCredentials(options);
GPR_ASSERT(server_credentials.get() != nullptr);
}
// ServerCredentials should always have identity credential presented.
// Otherwise gRPC stack will fail.
TEST(
CredentialsTest,
TlsServerCredentialsWithFileWatcherCertificateProviderLoadingIdentityOnly) {
auto certificate_provider = std::make_shared<FileWatcherCertificateProvider>(
SERVER_KEY_PATH, SERVER_CERT_PATH, 1);
grpc::experimental::TlsServerCredentialsOptions options(certificate_provider);
options.watch_identity_key_cert_pairs();
options.set_identity_cert_name(kIdentityCertName);
options.set_cert_request_type(
GRPC_SSL_REQUEST_AND_REQUIRE_CLIENT_CERTIFICATE_AND_VERIFY);
auto server_credentials = grpc::experimental::TlsServerCredentials(options);
GPR_ASSERT(server_credentials.get() != nullptr);
}
TEST(CredentialsTest, TlsServerCredentialsWithSyncExternalVerifier) {
auto verifier =
ExternalCertificateVerifier::Create<SyncCertificateVerifier>(true);
auto certificate_provider = std::make_shared<FileWatcherCertificateProvider>(
SERVER_KEY_PATH, SERVER_CERT_PATH, CA_CERT_PATH, 1);
grpc::experimental::TlsServerCredentialsOptions options(certificate_provider);
options.watch_root_certs();
options.set_root_cert_name(kRootCertName);
options.watch_identity_key_cert_pairs();
options.set_identity_cert_name(kIdentityCertName);
options.set_cert_request_type(
GRPC_SSL_REQUEST_AND_REQUIRE_CLIENT_CERTIFICATE_AND_VERIFY);
options.set_certificate_verifier(verifier);
auto server_credentials = grpc::experimental::TlsServerCredentials(options);
GPR_ASSERT(server_credentials.get() != nullptr);
}
TEST(CredentialsTest, TlsServerCredentialsWithAsyncExternalVerifier) {
auto verifier =
ExternalCertificateVerifier::Create<AsyncCertificateVerifier>(true);
auto certificate_provider = std::make_shared<FileWatcherCertificateProvider>(
SERVER_KEY_PATH, SERVER_CERT_PATH, CA_CERT_PATH, 1);
grpc::experimental::TlsServerCredentialsOptions options(certificate_provider);
options.watch_root_certs();
options.set_root_cert_name(kRootCertName);
options.watch_identity_key_cert_pairs();
options.set_identity_cert_name(kIdentityCertName);
options.set_cert_request_type(
GRPC_SSL_REQUEST_AND_REQUIRE_CLIENT_CERTIFICATE_AND_VERIFY);
options.set_certificate_verifier(verifier);
auto server_credentials = grpc::experimental::TlsServerCredentials(options);
GPR_ASSERT(server_credentials.get() != nullptr);
}
} // namespace
} // namespace testing
} // namespace grpc
int main(int argc, char** argv) {
::testing::InitGoogleTest(&argc, argv);
grpc::testing::TestEnvironment env(&argc, argv);
int ret = RUN_ALL_TESTS();
return ret;
}