blob: 15b8e900fcb851be139ddf9d2c1484fdd85ef646 [file] [log] [blame]
//
//
// 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 <grpc/support/port_platform.h>
#include "src/core/lib/security/credentials/xds/xds_credentials.h"
#include "src/core/ext/filters/client_channel/lb_policy/xds/xds_channel_args.h"
#include "src/core/ext/xds/xds_certificate_provider.h"
#include "src/core/lib/security/credentials/tls/grpc_tls_credentials_options.h"
#include "src/core/lib/security/credentials/tls/tls_credentials.h"
#include "src/core/lib/security/credentials/tls/tls_utils.h"
#include "src/core/lib/uri/uri_parser.h"
namespace grpc_core {
const char kCredentialsTypeXds[] = "Xds";
namespace {
bool XdsVerifySubjectAlternativeNames(
const char* const* subject_alternative_names,
size_t subject_alternative_names_size,
const std::vector<StringMatcher>& matchers) {
if (matchers.empty()) return true;
for (size_t i = 0; i < subject_alternative_names_size; ++i) {
for (const auto& matcher : matchers) {
if (matcher.type() == StringMatcher::Type::kExact) {
// For Exact match, use DNS rules for verifying SANs
// TODO(zhenlian): Right now, the SSL layer does not save the type of
// the SAN, so we are doing a DNS style verification for all SANs when
// the type is EXACT. When we expose the SAN type, change this to only
// do this verification when the SAN type is DNS and match type is
// kExact. For all other cases, we should use matcher.Match().
if (VerifySubjectAlternativeName(subject_alternative_names[i],
matcher.string_matcher())) {
return true;
}
} else {
if (matcher.Match(subject_alternative_names[i])) {
return true;
}
}
}
}
return false;
}
class ServerAuthCheck {
public:
ServerAuthCheck(
RefCountedPtr<XdsCertificateProvider> xds_certificate_provider,
std::string cluster_name)
: xds_certificate_provider_(std::move(xds_certificate_provider)),
cluster_name_(std::move(cluster_name)) {}
static int Schedule(void* config_user_data,
grpc_tls_server_authorization_check_arg* arg) {
return static_cast<ServerAuthCheck*>(config_user_data)->ScheduleImpl(arg);
}
static void Destroy(void* config_user_data) {
delete static_cast<ServerAuthCheck*>(config_user_data);
}
private:
int ScheduleImpl(grpc_tls_server_authorization_check_arg* arg) {
if (XdsVerifySubjectAlternativeNames(
arg->subject_alternative_names, arg->subject_alternative_names_size,
xds_certificate_provider_->GetSanMatchers(cluster_name_))) {
arg->success = 1;
arg->status = GRPC_STATUS_OK;
} else {
arg->success = 0;
arg->status = GRPC_STATUS_UNAUTHENTICATED;
if (arg->error_details) {
arg->error_details->set_error_details(
"SANs from certificate did not match SANs from xDS control plane");
}
}
return 0; /* synchronous check */
}
RefCountedPtr<XdsCertificateProvider> xds_certificate_provider_;
std::string cluster_name_;
};
} // namespace
bool TestOnlyXdsVerifySubjectAlternativeNames(
const char* const* subject_alternative_names,
size_t subject_alternative_names_size,
const std::vector<StringMatcher>& matchers) {
return XdsVerifySubjectAlternativeNames(
subject_alternative_names, subject_alternative_names_size, matchers);
}
//
// XdsCredentials
//
RefCountedPtr<grpc_channel_security_connector>
XdsCredentials::create_security_connector(
RefCountedPtr<grpc_call_credentials> call_creds, const char* target_name,
const grpc_channel_args* args, grpc_channel_args** new_args) {
struct ChannelArgsDeleter {
const grpc_channel_args* args;
bool owned;
~ChannelArgsDeleter() {
if (owned) grpc_channel_args_destroy(args);
}
};
ChannelArgsDeleter temp_args{args, false};
// TODO(yashykt): This arg will no longer need to be added after b/173119596
// is fixed.
grpc_arg override_arg = grpc_channel_arg_string_create(
const_cast<char*>(GRPC_SSL_TARGET_NAME_OVERRIDE_ARG),
const_cast<char*>(target_name));
const char* override_arg_name = GRPC_SSL_TARGET_NAME_OVERRIDE_ARG;
if (grpc_channel_args_find(args, override_arg_name) == nullptr) {
temp_args.args = grpc_channel_args_copy_and_add_and_remove(
args, &override_arg_name, 1, &override_arg, 1);
temp_args.owned = true;
}
RefCountedPtr<grpc_channel_security_connector> security_connector;
auto xds_certificate_provider =
XdsCertificateProvider::GetFromChannelArgs(args);
if (xds_certificate_provider != nullptr) {
std::string cluster_name =
grpc_channel_args_find_string(args, GRPC_ARG_XDS_CLUSTER_NAME);
GPR_ASSERT(cluster_name.data() != nullptr);
const bool watch_root =
xds_certificate_provider->ProvidesRootCerts(cluster_name);
const bool watch_identity =
xds_certificate_provider->ProvidesIdentityCerts(cluster_name);
if (watch_root || watch_identity) {
auto tls_credentials_options =
MakeRefCounted<grpc_tls_credentials_options>();
tls_credentials_options->set_certificate_provider(
xds_certificate_provider);
if (watch_root) {
tls_credentials_options->set_watch_root_cert(true);
tls_credentials_options->set_root_cert_name(cluster_name);
}
if (watch_identity) {
tls_credentials_options->set_watch_identity_pair(true);
tls_credentials_options->set_identity_cert_name(cluster_name);
}
tls_credentials_options->set_server_verification_option(
GRPC_TLS_SKIP_HOSTNAME_VERIFICATION);
auto* server_auth_check = new ServerAuthCheck(xds_certificate_provider,
std::move(cluster_name));
tls_credentials_options->set_server_authorization_check_config(
MakeRefCounted<grpc_tls_server_authorization_check_config>(
server_auth_check, ServerAuthCheck::Schedule, nullptr,
ServerAuthCheck::Destroy));
// TODO(yashkt): Creating a new TlsCreds object each time we create a
// security connector means that the security connector's cmp() method
// returns unequal for each instance, which means that every time an LB
// policy updates, all the subchannels will be recreated. This is
// going to lead to a lot of connection churn. Instead, we should
// either (a) change the TLS security connector's cmp() method to be
// smarter somehow, so that it compares unequal only when the
// tls_credentials_options have changed, or (b) cache the TlsCreds
// objects in the XdsCredentials object so that we can reuse the
// same one when creating new security connectors, swapping out the
// TlsCreds object only when the tls_credentials_options change.
// Option (a) would probably be better, although it may require some
// structural changes to the security connector API.
auto tls_credentials =
MakeRefCounted<TlsCredentials>(std::move(tls_credentials_options));
return tls_credentials->create_security_connector(
std::move(call_creds), target_name, temp_args.args, new_args);
}
}
GPR_ASSERT(fallback_credentials_ != nullptr);
return fallback_credentials_->create_security_connector(
std::move(call_creds), target_name, temp_args.args, new_args);
}
//
// XdsServerCredentials
//
RefCountedPtr<grpc_server_security_connector>
XdsServerCredentials::create_security_connector(const grpc_channel_args* args) {
auto xds_certificate_provider =
XdsCertificateProvider::GetFromChannelArgs(args);
// Identity certs are a must for TLS.
if (xds_certificate_provider != nullptr &&
xds_certificate_provider->ProvidesIdentityCerts("")) {
auto tls_credentials_options =
MakeRefCounted<grpc_tls_credentials_options>();
tls_credentials_options->set_watch_identity_pair(true);
tls_credentials_options->set_certificate_provider(xds_certificate_provider);
if (xds_certificate_provider->ProvidesRootCerts("")) {
tls_credentials_options->set_watch_root_cert(true);
if (xds_certificate_provider->GetRequireClientCertificate("")) {
tls_credentials_options->set_cert_request_type(
GRPC_SSL_REQUEST_AND_REQUIRE_CLIENT_CERTIFICATE_AND_VERIFY);
} else {
tls_credentials_options->set_cert_request_type(
GRPC_SSL_REQUEST_CLIENT_CERTIFICATE_AND_VERIFY);
}
} else {
// Do not request client certificate if there is no way to verify.
tls_credentials_options->set_cert_request_type(
GRPC_SSL_DONT_REQUEST_CLIENT_CERTIFICATE);
}
auto tls_credentials = MakeRefCounted<TlsServerCredentials>(
std::move(tls_credentials_options));
return tls_credentials->create_security_connector(args);
}
return fallback_credentials_->create_security_connector(args);
}
} // namespace grpc_core
grpc_channel_credentials* grpc_xds_credentials_create(
grpc_channel_credentials* fallback_credentials) {
GPR_ASSERT(fallback_credentials != nullptr);
return new grpc_core::XdsCredentials(fallback_credentials->Ref());
}
grpc_server_credentials* grpc_xds_server_credentials_create(
grpc_server_credentials* fallback_credentials) {
GPR_ASSERT(fallback_credentials != nullptr);
return new grpc_core::XdsServerCredentials(fallback_credentials->Ref());
}