blob: f728de299163a5d8175fc6edbe99445fd9e155c1 [file] [log] [blame]
/*
* Copyright 2021 Google LLC
*
* 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 "tlbmc/grpc_tls_options.h"
#include <memory>
#include <optional>
#include <string>
#include <utility>
#include <vector>
#include "absl/log/check.h"
#include "absl/log/log.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/string_view.h"
#include "grpcpp/security/credentials.h"
#include "grpcpp/security/tls_certificate_provider.h"
#include "grpcpp/security/tls_certificate_verifier.h"
#include "grpcpp/security/tls_credentials_options.h"
namespace ecclesia {
namespace {
// gRPC API requires we pass a parsable root cert even if we do not verify the
// cert signature.
const char *kUnusedFakeRootCert =
R"(-----BEGIN CERTIFICATE-----
MIIDiDCCAnCgAwIBAgIIdwMbYuGm3akwDQYJKoZIhvcNAQELBQAwRTEXMBUGA1UE
ChMOR29vZ2xlIFRFU1RJTkcxKjAoBgNVBAMMIUdvb2dsZSBCTUNXZWIgKipUZXN0
aW5nKiogUm9vdCBDQTAgFw03MDAxMDEwMDAwMDBaGA8yMTI1MDEwMTAwMDAwMFow
RTEXMBUGA1UEChMOR29vZ2xlIFRFU1RJTkcxKjAoBgNVBAMMIUdvb2dsZSBCTUNX
ZWIgKipUZXN0aW5nKiogUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC
AQoCggEBAKprOCLzYyqb6Mxo+I3n70P32PQLtUQdgjDXHF2cpwI0w3ezBYn4Dx0H
T7RCRvMMlxnAcRPCTBcU4I+7HnUX+mBZvFkJPJukttCOS3usC6GtD8UMNassFkSL
Vepy5AV1cwXweklebe9gAgC8NsFetqbHz12jTGUfngYDdqhg2haiTTwXyoal+575
c6F2S5krWMnBcm9/bhQufi8nC8AzQ2r1e4/bSe64F+vXzsLODsGs7mtzXeEDB2/N
7pEhQbXmkuBudXtE5CpLwvNa1Y3XLZfXXewlzlxjqQarihEolv6e/XOAJma3XMh8
Ip5QE1F/YvX3PICAbjsaX4wmWNTv7tECAwEAAaN6MHgwDgYDVR0PAQH/BAQDAgIE
MB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAPBgNVHRMBAf8EBTADAQH/
MBkGA1UdDgQSBBCuOIbUVxFjIbMIYjmL68mVMBsGA1UdIwQUMBKAEK44htRXEWMh
swhiOYvryZUwDQYJKoZIhvcNAQELBQADggEBAAZ7KtkYl4CLzPTLUhSiisckk+9K
/dbiG9TjRoiD8iG2j6/lTtZr0dkEq2xgz7kfHTbINzDONn45ea+BojAKSgWcwjzj
TvTX0lubQcTLNBHVAZQ8Ws/7QN2+WF6QPpKWzk44O1Lw1JLhaLSe4GauIQICt0P5
zUVrgX2EP1FdbS/PxgQvwM3gbHJh7iqWr7ASVypLzA5+YfuPRIJAEOimQbrs/0Gq
UEYO7y3ijBKwLs0lm6rCzCjwacWb/tFIJK4FNTg7iTWs2t94HWopoZqp0mouAERe
qOFbsHcmv8mSUfig0AaTorZQpS8htNtcsCl5HhNgAyCQh+QzvBvesrEz5Cw=
-----END CERTIFICATE-----
)";
constexpr unsigned int kRefreshIntervalSec = 60;
} // namespace
void StaticBufferBasedTlsOptions::SetToInsecure() {
auth_type_ = AuthType::kInsecure;
}
void StaticBufferBasedTlsOptions::SetToTls(
absl::string_view root_certs_buffer, absl::string_view key_buffer,
absl::string_view cert_buffer,
std::optional<absl::string_view> crl_directory) {
auth_type_ = AuthType::kTlsVerifyServer;
root_certs_ = root_certs_buffer;
key_cert_ = {.private_key = std::string(key_buffer),
.certificate_chain = std::string(cert_buffer)};
crl_directory_ = crl_directory;
}
void StaticBufferBasedTlsOptions::SetToTls(absl::string_view root_certs_buffer,
absl::string_view key_buffer,
absl::string_view cert_buffer) {
SetToTls(root_certs_buffer, key_buffer, cert_buffer,
/*crl_directory=*/std::nullopt);
}
void StaticBufferBasedTlsOptions::SetToTlsSkipHostname(
absl::string_view root_certs_buffer, absl::string_view key_buffer,
absl::string_view cert_buffer,
std::shared_ptr<grpc::experimental::CertificateVerifier> cert_verifier,
std::optional<absl::string_view> crl_directory) {
auth_type_ = AuthType::kTlsVerifyServerSkipHostname;
root_certs_ = root_certs_buffer;
key_cert_ = {.private_key = std::string(key_buffer),
.certificate_chain = std::string(cert_buffer)};
cert_verifier_ = std::move(cert_verifier);
crl_directory_ = crl_directory;
}
void StaticBufferBasedTlsOptions::SetToTlsSkipHostname(
absl::string_view root_certs_buffer, absl::string_view key_buffer,
absl::string_view cert_buffer,
std::shared_ptr<grpc::experimental::CertificateVerifier> cert_verifier) {
SetToTlsSkipHostname(root_certs_buffer, key_buffer, cert_buffer,
std::move(cert_verifier),
/*crl_directory=*/std::nullopt);
}
void StaticBufferBasedTlsOptions::SetToTlsNotVerifyServer(
absl::string_view key_buffer, absl::string_view cert_buffer,
std::shared_ptr<grpc::experimental::CertificateVerifier> cert_verifier,
std::optional<absl::string_view> crl_directory) {
auth_type_ = AuthType::kTlsNotVerifyServer;
key_cert_ = {.private_key = std::string(key_buffer),
.certificate_chain = std::string(cert_buffer)};
cert_verifier_ = std::move(cert_verifier);
crl_directory_ = crl_directory;
}
void StaticBufferBasedTlsOptions::SetToTlsNotVerifyServer(
absl::string_view key_buffer, absl::string_view cert_buffer,
std::shared_ptr<grpc::experimental::CertificateVerifier> cert_verifier) {
SetToTlsNotVerifyServer(key_buffer, cert_buffer, std::move(cert_verifier),
/*crl_directory=*/std::nullopt);
}
std::shared_ptr<grpc::ChannelCredentials>
StaticBufferBasedTlsOptions::GetChannelCredentials() const {
switch (auth_type_) {
case AuthType::kTlsVerifyServer: {
grpc::experimental::TlsChannelCredentialsOptions tls_options;
tls_options.watch_identity_key_cert_pairs();
tls_options.watch_root_certs();
if (crl_directory_.has_value()) {
tls_options.set_crl_directory(*crl_directory_);
}
tls_options.set_certificate_provider(GetCertificateProvider());
tls_options.set_verify_server_certs(true);
return grpc::experimental::TlsCredentials(tls_options);
}
case AuthType::kTlsVerifyServerSkipHostname: {
grpc::experimental::TlsChannelCredentialsOptions tls_options;
tls_options.watch_identity_key_cert_pairs();
tls_options.watch_root_certs();
if (crl_directory_.has_value()) {
tls_options.set_crl_directory(*crl_directory_);
}
tls_options.set_certificate_provider(GetCertificateProvider());
tls_options.set_certificate_verifier(cert_verifier_);
tls_options.set_verify_server_certs(true);
tls_options.set_check_call_host(false);
return grpc::experimental::TlsCredentials(tls_options);
}
case AuthType::kTlsNotVerifyServer: {
grpc::experimental::TlsChannelCredentialsOptions tls_options;
tls_options.watch_identity_key_cert_pairs();
tls_options.watch_root_certs();
if (crl_directory_.has_value()) {
tls_options.set_crl_directory(*crl_directory_);
}
tls_options.set_certificate_provider(GetCertificateProvider());
tls_options.set_certificate_verifier(cert_verifier_);
tls_options.set_verify_server_certs(false);
tls_options.set_check_call_host(false);
return grpc::experimental::TlsCredentials(tls_options);
}
case AuthType::kInsecure:
return grpc::InsecureChannelCredentials();
// No default. We own the AuthType enum.
}
CHECK(false) << absl::StrCat("Unexpected value for AuthType: ", auth_type_);
return grpc::InsecureChannelCredentials();
}
std::shared_ptr<grpc::experimental::CertificateProviderInterface>
StaticBufferBasedTlsOptions::GetCertificateProvider() const {
switch (auth_type_) {
case AuthType::kTlsVerifyServer: {
return std::make_shared<
grpc::experimental::StaticDataCertificateProvider>(
root_certs_,
std::vector<grpc::experimental::IdentityKeyCertPair>{key_cert_});
}
case AuthType::kTlsVerifyServerSkipHostname: {
return std::make_shared<
grpc::experimental::StaticDataCertificateProvider>(
root_certs_,
std::vector<grpc::experimental::IdentityKeyCertPair>{key_cert_});
}
case AuthType::kTlsNotVerifyServer: {
return std::make_shared<
grpc::experimental::StaticDataCertificateProvider>(
kUnusedFakeRootCert,
std::vector<grpc::experimental::IdentityKeyCertPair>{key_cert_});
}
case AuthType::kInsecure:
return nullptr;
// No default. We own the AuthType enum.
}
CHECK(false) << absl::StrCat("Unexpected value for AuthType: ", auth_type_);
return nullptr;
}
void FileWatcherBasedOptions::SetToTls(
absl::string_view root_certs_path, absl::string_view key_path,
absl::string_view cert_path,
std::optional<absl::string_view> crl_directory) {
auth_type_ = AuthType::kTlsVerifyServer;
root_certs_path_ = root_certs_path;
key_path_ = key_path;
cert_path_ = cert_path;
crl_directory_ = crl_directory;
}
void FileWatcherBasedOptions::SetToTlsSkipHostname(
absl::string_view root_certs_path, absl::string_view key_path,
absl::string_view cert_path,
std::shared_ptr<grpc::experimental::CertificateVerifier> cert_verifier,
std::optional<absl::string_view> crl_directory) {
auth_type_ = AuthType::kTlsVerifyServerSkipHostname;
root_certs_path_ = root_certs_path;
key_path_ = key_path;
cert_path_ = cert_path;
cert_verifier_ = std::move(cert_verifier);
crl_directory_ = crl_directory;
}
void FileWatcherBasedOptions::SetToTlsNotVerifyServer(
absl::string_view key_path, absl::string_view cert_path,
std::shared_ptr<grpc::experimental::CertificateVerifier> cert_verifier,
std::optional<absl::string_view> crl_directory) {
auth_type_ = AuthType::kTlsNotVerifyServer;
key_path_ = key_path;
cert_path_ = cert_path;
cert_verifier_ = std::move(cert_verifier);
crl_directory_ = crl_directory;
}
std::shared_ptr<grpc::experimental::CertificateProviderInterface>
FileWatcherBasedOptions::GetCertificateProvider() const {
switch (auth_type_) {
case AuthType::kTlsVerifyServer: {
return std::make_shared<
grpc::experimental::FileWatcherCertificateProvider>(
key_path_, cert_path_, root_certs_path_, kRefreshIntervalSec);
}
case AuthType::kTlsVerifyServerSkipHostname: {
return std::make_shared<
grpc::experimental::FileWatcherCertificateProvider>(
key_path_, cert_path_, root_certs_path_, kRefreshIntervalSec);
}
case AuthType::kTlsNotVerifyServer: {
return std::make_shared<
grpc::experimental::FileWatcherCertificateProvider>(
key_path_, cert_path_, kRefreshIntervalSec);
}
case AuthType::kInsecure:
return nullptr;
// No default. We own the AuthType enum.
}
CHECK(false) << absl::StrCat("Unexpected value for AuthType: ", auth_type_);
return nullptr;
}
} // namespace ecclesia