Plumbs SAN fields to tsi_peer. (#25874)

pull/25989/head
Ashitha Santhosh 4 years ago committed by GitHub
parent 2210819f85
commit 0570bd9205
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 3
      include/grpc/grpc_security_constants.h
  2. 18
      src/core/lib/security/security_connector/ssl_utils.cc
  3. 27
      src/core/tsi/ssl_transport_security.cc
  4. 7
      src/core/tsi/ssl_transport_security.h
  5. 83
      test/core/security/security_connector_test.cc
  6. 54
      test/core/tsi/ssl_transport_security_test.cc

@ -43,7 +43,10 @@ extern "C" {
#define GRPC_X509_PEM_CERT_CHAIN_PROPERTY_NAME "x509_pem_cert_chain"
#define GRPC_SSL_SESSION_REUSED_PROPERTY "ssl_session_reused"
#define GRPC_TRANSPORT_SECURITY_LEVEL_PROPERTY_NAME "security_level"
#define GRPC_PEER_DNS_PROPERTY_NAME "peer_dns"
#define GRPC_PEER_SPIFFE_ID_PROPERTY_NAME "peer_spiffe_id"
#define GRPC_PEER_EMAIL_PROPERTY_NAME "peer_email"
#define GRPC_PEER_IP_PROPERTY_NAME "peer_ip"
/** Environment variable that points to the default SSL roots file. This file
must be a PEM encoded file with all the roots such as the one that can be

@ -305,6 +305,9 @@ grpc_core::RefCountedPtr<grpc_auth_context> grpc_ssl_peer_to_auth_context(
grpc_auth_context_add_property(
ctx.get(), GRPC_TRANSPORT_SECURITY_LEVEL_PROPERTY_NAME,
prop->value.data, prop->value.length);
} else if (strcmp(prop->name, TSI_X509_DNS_PEER_PROPERTY) == 0) {
grpc_auth_context_add_property(ctx.get(), GRPC_PEER_DNS_PROPERTY_NAME,
prop->value.data, prop->value.length);
} else if (strcmp(prop->name, TSI_X509_URI_PEER_PROPERTY) == 0) {
uri_count++;
absl::string_view spiffe_id(prop->value.data, prop->value.length);
@ -313,6 +316,12 @@ grpc_core::RefCountedPtr<grpc_auth_context> grpc_ssl_peer_to_auth_context(
spiffe_length = prop->value.length;
has_spiffe_id = true;
}
} else if (strcmp(prop->name, TSI_X509_EMAIL_PEER_PROPERTY) == 0) {
grpc_auth_context_add_property(ctx.get(), GRPC_PEER_EMAIL_PROPERTY_NAME,
prop->value.data, prop->value.length);
} else if (strcmp(prop->name, TSI_X509_IP_PEER_PROPERTY) == 0) {
grpc_auth_context_add_property(ctx.get(), GRPC_PEER_IP_PROPERTY_NAME,
prop->value.data, prop->value.length);
}
}
if (peer_identity_property_name != nullptr) {
@ -376,9 +385,18 @@ tsi_peer grpc_shallow_peer_from_ssl_auth_context(
0) {
add_shallow_auth_property_to_peer(&peer, prop,
TSI_X509_PEM_CERT_CHAIN_PROPERTY);
} else if (strcmp(prop->name, GRPC_PEER_DNS_PROPERTY_NAME) == 0) {
add_shallow_auth_property_to_peer(&peer, prop,
TSI_X509_DNS_PEER_PROPERTY);
} else if (strcmp(prop->name, GRPC_PEER_SPIFFE_ID_PROPERTY_NAME) == 0) {
add_shallow_auth_property_to_peer(&peer, prop,
TSI_X509_URI_PEER_PROPERTY);
} else if (strcmp(prop->name, GRPC_PEER_EMAIL_PROPERTY_NAME) == 0) {
add_shallow_auth_property_to_peer(&peer, prop,
TSI_X509_EMAIL_PEER_PROPERTY);
} else if (strcmp(prop->name, GRPC_PEER_IP_PROPERTY_NAME) == 0) {
add_shallow_auth_property_to_peer(&peer, prop,
TSI_X509_IP_PEER_PROPERTY);
}
}
}

@ -357,13 +357,17 @@ static tsi_result add_subject_alt_names_properties_to_peer(
subject_alt_name->type == GEN_URI) {
unsigned char* name = nullptr;
int name_size;
std::string property_name;
if (subject_alt_name->type == GEN_DNS) {
name_size = ASN1_STRING_to_UTF8(&name, subject_alt_name->d.dNSName);
property_name = TSI_X509_DNS_PEER_PROPERTY;
} else if (subject_alt_name->type == GEN_EMAIL) {
name_size = ASN1_STRING_to_UTF8(&name, subject_alt_name->d.rfc822Name);
property_name = TSI_X509_EMAIL_PEER_PROPERTY;
} else {
name_size = ASN1_STRING_to_UTF8(
&name, subject_alt_name->d.uniformResourceIdentifier);
property_name = TSI_X509_URI_PEER_PROPERTY;
}
if (name_size < 0) {
gpr_log(GPR_ERROR, "Could not get utf8 from asn1 string.");
@ -378,12 +382,10 @@ static tsi_result add_subject_alt_names_properties_to_peer(
OPENSSL_free(name);
break;
}
if (subject_alt_name->type == GEN_URI) {
result = tsi_construct_string_peer_property(
TSI_X509_URI_PEER_PROPERTY, reinterpret_cast<const char*>(name),
static_cast<size_t>(name_size),
&peer->properties[(*current_insert_index)++]);
}
result = tsi_construct_string_peer_property(
property_name.c_str(), reinterpret_cast<const char*>(name),
static_cast<size_t>(name_size),
&peer->properties[(*current_insert_index)++]);
OPENSSL_free(name);
} else if (subject_alt_name->type == GEN_IPADD) {
char ntop_buf[INET6_ADDRSTRLEN];
@ -409,6 +411,10 @@ static tsi_result add_subject_alt_names_properties_to_peer(
result = tsi_construct_string_peer_property_from_cstring(
TSI_X509_SUBJECT_ALTERNATIVE_NAME_PEER_PROPERTY, name,
&peer->properties[(*current_insert_index)++]);
if (result != TSI_OK) break;
result = tsi_construct_string_peer_property_from_cstring(
TSI_X509_IP_PEER_PROPERTY, name,
&peer->properties[(*current_insert_index)++]);
} else {
result = tsi_construct_string_peer_property_from_cstring(
TSI_X509_SUBJECT_ALTERNATIVE_NAME_PEER_PROPERTY, "other types of SAN",
@ -438,7 +444,14 @@ static tsi_result peer_from_x509(X509* cert, int include_certificate_type,
for (int i = 0; i < subject_alt_name_count; i++) {
GENERAL_NAME* subject_alt_name =
sk_GENERAL_NAME_value(subject_alt_names, TSI_SIZE_AS_SIZE(i));
if (subject_alt_name->type == GEN_URI) {
// TODO(zhenlian): Clean up tsi_peer to avoid duplicate entries.
// URI, DNS, email and ip address SAN fields are plumbed to tsi_peer, in
// addition to all SAN fields (results in duplicate values). This code
// snippet updates property_count accordingly.
if (subject_alt_name->type == GEN_URI ||
subject_alt_name->type == GEN_DNS ||
subject_alt_name->type == GEN_EMAIL ||
subject_alt_name->type == GEN_IPADD) {
property_count += 1;
}
}

@ -37,14 +37,13 @@ extern "C" {
#define TSI_X509_SUBJECT_ALTERNATIVE_NAME_PEER_PROPERTY \
"x509_subject_alternative_name"
#define TSI_SSL_SESSION_REUSED_PEER_PROPERTY "ssl_session_reused"
#define TSI_X509_PEM_CERT_PROPERTY "x509_pem_cert"
#define TSI_X509_PEM_CERT_CHAIN_PROPERTY "x509_pem_cert_chain"
#define TSI_SSL_ALPN_SELECTED_PROTOCOL "ssl_alpn_selected_protocol"
#define TSI_X509_DNS_PEER_PROPERTY "x509_dns"
#define TSI_X509_URI_PEER_PROPERTY "x509_uri"
#define TSI_X509_EMAIL_PEER_PROPERTY "x509_email"
#define TSI_X509_IP_PEER_PROPERTY "x509_ip"
/* --- tsi_ssl_root_certs_store object ---

@ -222,6 +222,32 @@ static int check_x509_pem_cert_chain(const grpc_auth_context* ctx,
return 1;
}
static int check_sans(
const grpc_auth_context* ctx, const char* expected_property_name,
const std::vector<std::string>& expected_property_values) {
grpc_auth_property_iterator it =
grpc_auth_context_find_properties_by_name(ctx, expected_property_name);
for (const auto& property_value : expected_property_values) {
const grpc_auth_property* prop = grpc_auth_property_iterator_next(&it);
if (prop == nullptr) {
gpr_log(GPR_ERROR, "Expected value %s not found.",
property_value.c_str());
return 0;
}
if (strncmp(prop->value, property_value.c_str(), prop->value_length) != 0) {
gpr_log(GPR_ERROR, "Expected peer %s and got %s.", property_value.c_str(),
prop->value);
return 0;
}
}
if (grpc_auth_property_iterator_next(&it) != nullptr) {
gpr_log(GPR_ERROR, "Expected only %zu property values.",
expected_property_values.size());
return 0;
}
return 1;
}
static int check_spiffe_id(const grpc_auth_context* ctx,
const char* expected_spiffe_id,
bool expect_spiffe_id) {
@ -444,6 +470,59 @@ static void test_cn_and_multiple_sans_and_others_ssl_peer_to_auth_context(
ctx.reset(DEBUG_LOCATION, "test");
}
static void test_dns_peer_to_auth_context(void) {
tsi_peer peer;
const std::vector<std::string> expected_dns = {"dns1", "dns2", "dns3"};
GPR_ASSERT(tsi_construct_peer(expected_dns.size(), &peer) == TSI_OK);
for (size_t i = 0; i < expected_dns.size(); ++i) {
GPR_ASSERT(tsi_construct_string_peer_property_from_cstring(
TSI_X509_DNS_PEER_PROPERTY, expected_dns[i].c_str(),
&peer.properties[i]) == TSI_OK);
}
grpc_core::RefCountedPtr<grpc_auth_context> ctx =
grpc_ssl_peer_to_auth_context(&peer, GRPC_SSL_TRANSPORT_SECURITY_TYPE);
GPR_ASSERT(ctx != nullptr);
GPR_ASSERT(check_sans(ctx.get(), GRPC_PEER_DNS_PROPERTY_NAME, expected_dns));
tsi_peer_destruct(&peer);
ctx.reset(DEBUG_LOCATION, "test");
}
static void test_email_peer_to_auth_context(void) {
tsi_peer peer;
const std::vector<std::string> expected_emails = {"email1", "email2"};
GPR_ASSERT(tsi_construct_peer(expected_emails.size(), &peer) == TSI_OK);
for (size_t i = 0; i < expected_emails.size(); ++i) {
GPR_ASSERT(tsi_construct_string_peer_property_from_cstring(
TSI_X509_EMAIL_PEER_PROPERTY, expected_emails[i].c_str(),
&peer.properties[i]) == TSI_OK);
}
grpc_core::RefCountedPtr<grpc_auth_context> ctx =
grpc_ssl_peer_to_auth_context(&peer, GRPC_SSL_TRANSPORT_SECURITY_TYPE);
GPR_ASSERT(ctx != nullptr);
GPR_ASSERT(
check_sans(ctx.get(), GRPC_PEER_EMAIL_PROPERTY_NAME, expected_emails));
tsi_peer_destruct(&peer);
ctx.reset(DEBUG_LOCATION, "test");
}
static void test_ip_peer_to_auth_context(void) {
tsi_peer peer;
const std::vector<std::string> expected_ips = {"128.128.128.128",
"255.255.255.255"};
GPR_ASSERT(tsi_construct_peer(expected_ips.size(), &peer) == TSI_OK);
for (size_t i = 0; i < expected_ips.size(); ++i) {
GPR_ASSERT(tsi_construct_string_peer_property_from_cstring(
TSI_X509_IP_PEER_PROPERTY, expected_ips[i].c_str(),
&peer.properties[i]) == TSI_OK);
}
grpc_core::RefCountedPtr<grpc_auth_context> ctx =
grpc_ssl_peer_to_auth_context(&peer, GRPC_SSL_TRANSPORT_SECURITY_TYPE);
GPR_ASSERT(ctx != nullptr);
GPR_ASSERT(check_sans(ctx.get(), GRPC_PEER_IP_PROPERTY_NAME, expected_ips));
tsi_peer_destruct(&peer);
ctx.reset(DEBUG_LOCATION, "test");
}
static void test_spiffe_id_peer_to_auth_context(void) {
// Invalid SPIFFE IDs should not be plumbed.
std::string long_id(2050, 'x');
@ -558,6 +637,7 @@ static void test_ipv6_address_san(void) {
}
tsi_peer_destruct(&peer);
}
namespace grpc_core {
namespace {
@ -672,6 +752,9 @@ int main(int argc, char** argv) {
test_cn_and_one_san_ssl_peer_to_auth_context();
test_cn_and_multiple_sans_ssl_peer_to_auth_context();
test_cn_and_multiple_sans_and_others_ssl_peer_to_auth_context();
test_dns_peer_to_auth_context();
test_email_peer_to_auth_context();
test_ip_peer_to_auth_context();
test_spiffe_id_peer_to_auth_context();
test_ipv6_address_san();
test_default_ssl_roots();

@ -253,13 +253,13 @@ void check_server0_peer(tsi_peer* peer) {
tsi_peer_destruct(peer);
}
static bool check_subject_alt_name(tsi_peer* peer, const char* name) {
static bool check_property(tsi_peer* peer, const char* property_name,
const char* property_value) {
for (size_t i = 0; i < peer->property_count; i++) {
const tsi_peer_property* prop = &peer->properties[i];
if (strcmp(prop->name, TSI_X509_SUBJECT_ALTERNATIVE_NAME_PEER_PROPERTY) ==
0) {
if (strlen(name) == prop->value.length &&
memcmp(prop->value.data, name, prop->value.length) == 0) {
if (strcmp(prop->name, property_name) == 0) {
if (strlen(property_value) == prop->value.length &&
memcmp(prop->value.data, property_value, prop->value.length) == 0) {
return true;
}
}
@ -267,17 +267,25 @@ static bool check_subject_alt_name(tsi_peer* peer, const char* name) {
return false;
}
static bool check_subject_alt_name(tsi_peer* peer, const char* name) {
return check_property(peer, TSI_X509_SUBJECT_ALTERNATIVE_NAME_PEER_PROPERTY,
name);
}
static bool check_dns(tsi_peer* peer, const char* name) {
return check_property(peer, TSI_X509_DNS_PEER_PROPERTY, name);
}
static bool check_uri(tsi_peer* peer, const char* name) {
for (size_t i = 0; i < peer->property_count; i++) {
const tsi_peer_property* prop = &peer->properties[i];
if (strcmp(prop->name, TSI_X509_URI_PEER_PROPERTY) == 0) {
if (strlen(name) == prop->value.length &&
memcmp(prop->value.data, name, prop->value.length) == 0) {
return true;
}
}
}
return false;
return check_property(peer, TSI_X509_URI_PEER_PROPERTY, name);
}
static bool check_email(tsi_peer* peer, const char* name) {
return check_property(peer, TSI_X509_EMAIL_PEER_PROPERTY, name);
}
static bool check_ip(tsi_peer* peer, const char* name) {
return check_property(peer, TSI_X509_IP_PEER_PROPERTY, name);
}
void check_server1_peer(tsi_peer* peer) {
@ -910,8 +918,9 @@ void ssl_tsi_test_extract_x509_subject_names() {
GPR_ASSERT(tsi_ssl_extract_x509_subject_names_from_pem_cert(cert, &peer) ==
TSI_OK);
// tsi_peer should include one common name, one certificate, one security
// level, ten SAN fields, three URI fields.
size_t expected_property_count = 15;
// level, ten SAN fields, two DNS SAN fields, three URI fields, two email
// addresses and two IP addresses.
size_t expected_property_count = 21;
GPR_ASSERT(peer.property_count == expected_property_count);
// Check common name
const char* expected_cn = "xpigors";
@ -927,6 +936,8 @@ void ssl_tsi_test_extract_x509_subject_names() {
// Check DNS
GPR_ASSERT(check_subject_alt_name(&peer, "foo.test.domain.com") == 1);
GPR_ASSERT(check_subject_alt_name(&peer, "bar.test.domain.com") == 1);
GPR_ASSERT(check_dns(&peer, "foo.test.domain.com") == 1);
GPR_ASSERT(check_dns(&peer, "bar.test.domain.com") == 1);
// Check URI
// Note that a valid SPIFFE certificate should only have one URI.
GPR_ASSERT(check_subject_alt_name(&peer, "spiffe://foo.com/bar/baz") == 1);
@ -940,6 +951,15 @@ void ssl_tsi_test_extract_x509_subject_names() {
// Check email address
GPR_ASSERT(check_subject_alt_name(&peer, "foo@test.domain.com") == 1);
GPR_ASSERT(check_subject_alt_name(&peer, "bar@test.domain.com") == 1);
GPR_ASSERT(check_email(&peer, "foo@test.domain.com") == 1);
GPR_ASSERT(check_email(&peer, "bar@test.domain.com") == 1);
// Check ip address
GPR_ASSERT(check_subject_alt_name(&peer, "192.168.7.1") == 1);
GPR_ASSERT(check_subject_alt_name(&peer, "13::17") == 1);
GPR_ASSERT(check_ip(&peer, "192.168.7.1") == 1);
GPR_ASSERT(check_ip(&peer, "13::17") == 1);
// Check other fields
GPR_ASSERT(check_subject_alt_name(&peer, "other types of SAN") == 1);
// Free memory
gpr_free(cert);
tsi_peer_destruct(&peer);

Loading…
Cancel
Save