Merge pull request #5706 from deepaklukose/dev

Expose pem cert in AuthContext for SSL/TLS channels
pull/5841/head
Jan Tattermusch 9 years ago
commit ee69f42552
  1. 1
      include/grpc/grpc_security.h
  2. 16
      src/core/security/security_connector.c
  3. 27
      src/core/tsi/ssl_transport_security.c
  4. 2
      src/core/tsi/ssl_transport_security.h
  5. 58
      test/core/security/security_connector_test.c

@ -48,6 +48,7 @@ extern "C" {
#define GRPC_X509_CN_PROPERTY_NAME "x509_common_name" #define GRPC_X509_CN_PROPERTY_NAME "x509_common_name"
#define GRPC_X509_SAN_PROPERTY_NAME "x509_subject_alternative_name" #define GRPC_X509_SAN_PROPERTY_NAME "x509_subject_alternative_name"
#define GRPC_X509_PEM_CERT_PROPERTY_NAME "x509_pem_cert"
typedef struct grpc_auth_context grpc_auth_context; typedef struct grpc_auth_context grpc_auth_context;

@ -492,6 +492,9 @@ grpc_auth_context *tsi_ssl_peer_to_auth_context(const tsi_peer *peer) {
peer_identity_property_name = GRPC_X509_SAN_PROPERTY_NAME; peer_identity_property_name = GRPC_X509_SAN_PROPERTY_NAME;
grpc_auth_context_add_property(ctx, GRPC_X509_SAN_PROPERTY_NAME, grpc_auth_context_add_property(ctx, GRPC_X509_SAN_PROPERTY_NAME,
prop->value.data, prop->value.length); prop->value.data, prop->value.length);
} else if (strcmp(prop->name, TSI_X509_PEM_CERT_PROPERTY) == 0) {
grpc_auth_context_add_property(ctx, GRPC_X509_PEM_CERT_PROPERTY_NAME,
prop->value.data, prop->value.length);
} }
} }
if (peer_identity_property_name != NULL) { if (peer_identity_property_name != NULL) {
@ -554,9 +557,9 @@ static void ssl_server_check_peer(grpc_exec_ctx *exec_ctx,
grpc_auth_context_unref(auth_context); grpc_auth_context_unref(auth_context);
} }
static void add_shalow_auth_property_to_peer(tsi_peer *peer, static void add_shallow_auth_property_to_peer(tsi_peer *peer,
const grpc_auth_property *prop, const grpc_auth_property *prop,
const char *tsi_prop_name) { const char *tsi_prop_name) {
tsi_peer_property *tsi_prop = &peer->properties[peer->property_count++]; tsi_peer_property *tsi_prop = &peer->properties[peer->property_count++];
tsi_prop->name = (char *)tsi_prop_name; tsi_prop->name = (char *)tsi_prop_name;
tsi_prop->value.data = prop->value; tsi_prop->value.data = prop->value;
@ -579,11 +582,14 @@ tsi_peer tsi_shallow_peer_from_ssl_auth_context(
it = grpc_auth_context_property_iterator(auth_context); it = grpc_auth_context_property_iterator(auth_context);
while ((prop = grpc_auth_property_iterator_next(&it)) != NULL) { while ((prop = grpc_auth_property_iterator_next(&it)) != NULL) {
if (strcmp(prop->name, GRPC_X509_SAN_PROPERTY_NAME) == 0) { if (strcmp(prop->name, GRPC_X509_SAN_PROPERTY_NAME) == 0) {
add_shalow_auth_property_to_peer( add_shallow_auth_property_to_peer(
&peer, prop, TSI_X509_SUBJECT_ALTERNATIVE_NAME_PEER_PROPERTY); &peer, prop, TSI_X509_SUBJECT_ALTERNATIVE_NAME_PEER_PROPERTY);
} else if (strcmp(prop->name, GRPC_X509_CN_PROPERTY_NAME) == 0) { } else if (strcmp(prop->name, GRPC_X509_CN_PROPERTY_NAME) == 0) {
add_shalow_auth_property_to_peer( add_shallow_auth_property_to_peer(
&peer, prop, TSI_X509_SUBJECT_COMMON_NAME_PEER_PROPERTY); &peer, prop, TSI_X509_SUBJECT_COMMON_NAME_PEER_PROPERTY);
} else if (strcmp(prop->name, GRPC_X509_PEM_CERT_PROPERTY_NAME) == 0) {
add_shallow_auth_property_to_peer(&peer, prop,
TSI_X509_PEM_CERT_PROPERTY);
} }
} }
} }

@ -293,6 +293,26 @@ static tsi_result peer_property_from_x509_common_name(
return result; return result;
} }
/* Gets the X509 cert in PEM format as a tsi_peer_property. */
static tsi_result add_pem_certificate(X509 *cert, tsi_peer_property *property) {
BIO *bio = BIO_new(BIO_s_mem());
if (!PEM_write_bio_X509(bio, cert)) {
BIO_free(bio);
return TSI_INTERNAL_ERROR;
}
char *contents;
long len = BIO_get_mem_data(bio, &contents);
if (len <= 0) {
BIO_free(bio);
return TSI_INTERNAL_ERROR;
}
tsi_result result = tsi_construct_string_peer_property(
TSI_X509_PEM_CERT_PROPERTY, (const char *)contents, (size_t)len,
property);
BIO_free(bio);
return result;
}
/* Gets the subject SANs from an X509 cert as a tsi_peer_property. */ /* Gets the subject SANs from an X509 cert as a tsi_peer_property. */
static tsi_result add_subject_alt_names_properties_to_peer( static tsi_result add_subject_alt_names_properties_to_peer(
tsi_peer *peer, GENERAL_NAMES *subject_alt_names, tsi_peer *peer, GENERAL_NAMES *subject_alt_names,
@ -363,7 +383,8 @@ static tsi_result peer_from_x509(X509 *cert, int include_certificate_type,
tsi_result result; tsi_result result;
GPR_ASSERT(subject_alt_name_count >= 0); GPR_ASSERT(subject_alt_name_count >= 0);
property_count = (include_certificate_type ? (size_t)1 : 0) + property_count = (include_certificate_type ? (size_t)1 : 0) +
1 /* common name */ + (size_t)subject_alt_name_count; 2 /* common name, certificate */ +
(size_t)subject_alt_name_count;
result = tsi_construct_peer(property_count, peer); result = tsi_construct_peer(property_count, peer);
if (result != TSI_OK) return result; if (result != TSI_OK) return result;
do { do {
@ -377,6 +398,10 @@ static tsi_result peer_from_x509(X509 *cert, int include_certificate_type,
cert, &peer->properties[include_certificate_type ? 1 : 0]); cert, &peer->properties[include_certificate_type ? 1 : 0]);
if (result != TSI_OK) break; if (result != TSI_OK) break;
result = add_pem_certificate(
cert, &peer->properties[include_certificate_type ? 2 : 1]);
if (result != TSI_OK) break;
if (subject_alt_name_count != 0) { if (subject_alt_name_count != 0) {
result = add_subject_alt_names_properties_to_peer( result = add_subject_alt_names_properties_to_peer(
peer, subject_alt_names, (size_t)subject_alt_name_count); peer, subject_alt_names, (size_t)subject_alt_name_count);

@ -48,6 +48,8 @@ extern "C" {
#define TSI_X509_SUBJECT_ALTERNATIVE_NAME_PEER_PROPERTY \ #define TSI_X509_SUBJECT_ALTERNATIVE_NAME_PEER_PROPERTY \
"x509_subject_alternative_name" "x509_subject_alternative_name"
#define TSI_X509_PEM_CERT_PROPERTY "x509_pem_cert"
#define TSI_SSL_ALPN_SELECTED_PROTOCOL "ssl_alpn_selected_protocol" #define TSI_SSL_ALPN_SELECTED_PROTOCOL "ssl_alpn_selected_protocol"
/* --- tsi_ssl_handshaker_factory object --- /* --- tsi_ssl_handshaker_factory object ---

@ -80,13 +80,14 @@ static int check_peer_property(const tsi_peer *peer,
static int check_ssl_peer_equivalence(const tsi_peer *original, static int check_ssl_peer_equivalence(const tsi_peer *original,
const tsi_peer *reconstructed) { const tsi_peer *reconstructed) {
/* The reconstructed peer only has CN and SAN properties. */ /* The reconstructed peer only has CN, SAN and pem cert properties. */
size_t i; size_t i;
for (i = 0; i < original->property_count; i++) { for (i = 0; i < original->property_count; i++) {
const tsi_peer_property *prop = &original->properties[i]; const tsi_peer_property *prop = &original->properties[i];
if ((strcmp(prop->name, TSI_X509_SUBJECT_COMMON_NAME_PEER_PROPERTY) == 0) || if ((strcmp(prop->name, TSI_X509_SUBJECT_COMMON_NAME_PEER_PROPERTY) == 0) ||
(strcmp(prop->name, TSI_X509_SUBJECT_ALTERNATIVE_NAME_PEER_PROPERTY) == (strcmp(prop->name, TSI_X509_SUBJECT_ALTERNATIVE_NAME_PEER_PROPERTY) ==
0)) { 0) ||
(strcmp(prop->name, TSI_X509_PEM_CERT_PROPERTY) == 0)) {
if (!check_peer_property(reconstructed, prop)) return 0; if (!check_peer_property(reconstructed, prop)) return 0;
} }
} }
@ -164,24 +165,50 @@ static int check_x509_cn(const grpc_auth_context *ctx,
return 1; return 1;
} }
static int check_x509_pem_cert(const grpc_auth_context *ctx,
const char *expected_pem_cert) {
grpc_auth_property_iterator it = grpc_auth_context_find_properties_by_name(
ctx, GRPC_X509_PEM_CERT_PROPERTY_NAME);
const grpc_auth_property *prop = grpc_auth_property_iterator_next(&it);
if (prop == NULL) {
gpr_log(GPR_ERROR, "Pem certificate property not found.");
return 0;
}
if (strncmp(prop->value, expected_pem_cert, prop->value_length) != 0) {
gpr_log(GPR_ERROR, "Expected pem cert %s and got %s", expected_pem_cert,
prop->value);
return 0;
}
if (grpc_auth_property_iterator_next(&it) != NULL) {
gpr_log(GPR_ERROR, "Expected only one property for pem cert.");
return 0;
}
return 1;
}
static void test_cn_only_ssl_peer_to_auth_context(void) { static void test_cn_only_ssl_peer_to_auth_context(void) {
tsi_peer peer; tsi_peer peer;
tsi_peer rpeer; tsi_peer rpeer;
grpc_auth_context *ctx; grpc_auth_context *ctx;
const char *expected_cn = "cn1"; const char *expected_cn = "cn1";
GPR_ASSERT(tsi_construct_peer(2, &peer) == TSI_OK); const char *expected_pem_cert = "pem_cert1";
GPR_ASSERT(tsi_construct_peer(3, &peer) == TSI_OK);
GPR_ASSERT(tsi_construct_string_peer_property_from_cstring( GPR_ASSERT(tsi_construct_string_peer_property_from_cstring(
TSI_CERTIFICATE_TYPE_PEER_PROPERTY, TSI_X509_CERTIFICATE_TYPE, TSI_CERTIFICATE_TYPE_PEER_PROPERTY, TSI_X509_CERTIFICATE_TYPE,
&peer.properties[0]) == TSI_OK); &peer.properties[0]) == TSI_OK);
GPR_ASSERT(tsi_construct_string_peer_property_from_cstring( GPR_ASSERT(tsi_construct_string_peer_property_from_cstring(
TSI_X509_SUBJECT_COMMON_NAME_PEER_PROPERTY, expected_cn, TSI_X509_SUBJECT_COMMON_NAME_PEER_PROPERTY, expected_cn,
&peer.properties[1]) == TSI_OK); &peer.properties[1]) == TSI_OK);
GPR_ASSERT(tsi_construct_string_peer_property_from_cstring(
TSI_X509_PEM_CERT_PROPERTY, expected_pem_cert,
&peer.properties[2]) == TSI_OK);
ctx = tsi_ssl_peer_to_auth_context(&peer); ctx = tsi_ssl_peer_to_auth_context(&peer);
GPR_ASSERT(ctx != NULL); GPR_ASSERT(ctx != NULL);
GPR_ASSERT(grpc_auth_context_peer_is_authenticated(ctx)); GPR_ASSERT(grpc_auth_context_peer_is_authenticated(ctx));
GPR_ASSERT(check_identity(ctx, GRPC_X509_CN_PROPERTY_NAME, &expected_cn, 1)); GPR_ASSERT(check_identity(ctx, GRPC_X509_CN_PROPERTY_NAME, &expected_cn, 1));
GPR_ASSERT(check_transport_security_type(ctx)); GPR_ASSERT(check_transport_security_type(ctx));
GPR_ASSERT(check_x509_cn(ctx, expected_cn)); GPR_ASSERT(check_x509_cn(ctx, expected_cn));
GPR_ASSERT(check_x509_pem_cert(ctx, expected_pem_cert));
rpeer = tsi_shallow_peer_from_ssl_auth_context(ctx); rpeer = tsi_shallow_peer_from_ssl_auth_context(ctx);
GPR_ASSERT(check_ssl_peer_equivalence(&peer, &rpeer)); GPR_ASSERT(check_ssl_peer_equivalence(&peer, &rpeer));
@ -197,7 +224,8 @@ static void test_cn_and_one_san_ssl_peer_to_auth_context(void) {
grpc_auth_context *ctx; grpc_auth_context *ctx;
const char *expected_cn = "cn1"; const char *expected_cn = "cn1";
const char *expected_san = "san1"; const char *expected_san = "san1";
GPR_ASSERT(tsi_construct_peer(3, &peer) == TSI_OK); const char *expected_pem_cert = "pem_cert1";
GPR_ASSERT(tsi_construct_peer(4, &peer) == TSI_OK);
GPR_ASSERT(tsi_construct_string_peer_property_from_cstring( GPR_ASSERT(tsi_construct_string_peer_property_from_cstring(
TSI_CERTIFICATE_TYPE_PEER_PROPERTY, TSI_X509_CERTIFICATE_TYPE, TSI_CERTIFICATE_TYPE_PEER_PROPERTY, TSI_X509_CERTIFICATE_TYPE,
&peer.properties[0]) == TSI_OK); &peer.properties[0]) == TSI_OK);
@ -207,6 +235,9 @@ static void test_cn_and_one_san_ssl_peer_to_auth_context(void) {
GPR_ASSERT(tsi_construct_string_peer_property_from_cstring( GPR_ASSERT(tsi_construct_string_peer_property_from_cstring(
TSI_X509_SUBJECT_ALTERNATIVE_NAME_PEER_PROPERTY, expected_san, TSI_X509_SUBJECT_ALTERNATIVE_NAME_PEER_PROPERTY, expected_san,
&peer.properties[2]) == TSI_OK); &peer.properties[2]) == TSI_OK);
GPR_ASSERT(tsi_construct_string_peer_property_from_cstring(
TSI_X509_PEM_CERT_PROPERTY, expected_pem_cert,
&peer.properties[3]) == TSI_OK);
ctx = tsi_ssl_peer_to_auth_context(&peer); ctx = tsi_ssl_peer_to_auth_context(&peer);
GPR_ASSERT(ctx != NULL); GPR_ASSERT(ctx != NULL);
GPR_ASSERT(grpc_auth_context_peer_is_authenticated(ctx)); GPR_ASSERT(grpc_auth_context_peer_is_authenticated(ctx));
@ -214,6 +245,7 @@ static void test_cn_and_one_san_ssl_peer_to_auth_context(void) {
check_identity(ctx, GRPC_X509_SAN_PROPERTY_NAME, &expected_san, 1)); check_identity(ctx, GRPC_X509_SAN_PROPERTY_NAME, &expected_san, 1));
GPR_ASSERT(check_transport_security_type(ctx)); GPR_ASSERT(check_transport_security_type(ctx));
GPR_ASSERT(check_x509_cn(ctx, expected_cn)); GPR_ASSERT(check_x509_cn(ctx, expected_cn));
GPR_ASSERT(check_x509_pem_cert(ctx, expected_pem_cert));
rpeer = tsi_shallow_peer_from_ssl_auth_context(ctx); rpeer = tsi_shallow_peer_from_ssl_auth_context(ctx);
GPR_ASSERT(check_ssl_peer_equivalence(&peer, &rpeer)); GPR_ASSERT(check_ssl_peer_equivalence(&peer, &rpeer));
@ -229,8 +261,9 @@ static void test_cn_and_multiple_sans_ssl_peer_to_auth_context(void) {
grpc_auth_context *ctx; grpc_auth_context *ctx;
const char *expected_cn = "cn1"; const char *expected_cn = "cn1";
const char *expected_sans[] = {"san1", "san2", "san3"}; const char *expected_sans[] = {"san1", "san2", "san3"};
const char *expected_pem_cert = "pem_cert1";
size_t i; size_t i;
GPR_ASSERT(tsi_construct_peer(2 + GPR_ARRAY_SIZE(expected_sans), &peer) == GPR_ASSERT(tsi_construct_peer(3 + GPR_ARRAY_SIZE(expected_sans), &peer) ==
TSI_OK); TSI_OK);
GPR_ASSERT(tsi_construct_string_peer_property_from_cstring( GPR_ASSERT(tsi_construct_string_peer_property_from_cstring(
TSI_CERTIFICATE_TYPE_PEER_PROPERTY, TSI_X509_CERTIFICATE_TYPE, TSI_CERTIFICATE_TYPE_PEER_PROPERTY, TSI_X509_CERTIFICATE_TYPE,
@ -238,10 +271,13 @@ static void test_cn_and_multiple_sans_ssl_peer_to_auth_context(void) {
GPR_ASSERT(tsi_construct_string_peer_property_from_cstring( GPR_ASSERT(tsi_construct_string_peer_property_from_cstring(
TSI_X509_SUBJECT_COMMON_NAME_PEER_PROPERTY, expected_cn, TSI_X509_SUBJECT_COMMON_NAME_PEER_PROPERTY, expected_cn,
&peer.properties[1]) == TSI_OK); &peer.properties[1]) == TSI_OK);
GPR_ASSERT(tsi_construct_string_peer_property_from_cstring(
TSI_X509_PEM_CERT_PROPERTY, expected_pem_cert,
&peer.properties[2]) == TSI_OK);
for (i = 0; i < GPR_ARRAY_SIZE(expected_sans); i++) { for (i = 0; i < GPR_ARRAY_SIZE(expected_sans); i++) {
GPR_ASSERT(tsi_construct_string_peer_property_from_cstring( GPR_ASSERT(tsi_construct_string_peer_property_from_cstring(
TSI_X509_SUBJECT_ALTERNATIVE_NAME_PEER_PROPERTY, TSI_X509_SUBJECT_ALTERNATIVE_NAME_PEER_PROPERTY,
expected_sans[i], &peer.properties[2 + i]) == TSI_OK); expected_sans[i], &peer.properties[3 + i]) == TSI_OK);
} }
ctx = tsi_ssl_peer_to_auth_context(&peer); ctx = tsi_ssl_peer_to_auth_context(&peer);
GPR_ASSERT(ctx != NULL); GPR_ASSERT(ctx != NULL);
@ -250,6 +286,7 @@ static void test_cn_and_multiple_sans_ssl_peer_to_auth_context(void) {
GPR_ARRAY_SIZE(expected_sans))); GPR_ARRAY_SIZE(expected_sans)));
GPR_ASSERT(check_transport_security_type(ctx)); GPR_ASSERT(check_transport_security_type(ctx));
GPR_ASSERT(check_x509_cn(ctx, expected_cn)); GPR_ASSERT(check_x509_cn(ctx, expected_cn));
GPR_ASSERT(check_x509_pem_cert(ctx, expected_pem_cert));
rpeer = tsi_shallow_peer_from_ssl_auth_context(ctx); rpeer = tsi_shallow_peer_from_ssl_auth_context(ctx);
GPR_ASSERT(check_ssl_peer_equivalence(&peer, &rpeer)); GPR_ASSERT(check_ssl_peer_equivalence(&peer, &rpeer));
@ -265,9 +302,10 @@ static void test_cn_and_multiple_sans_and_others_ssl_peer_to_auth_context(
tsi_peer rpeer; tsi_peer rpeer;
grpc_auth_context *ctx; grpc_auth_context *ctx;
const char *expected_cn = "cn1"; const char *expected_cn = "cn1";
const char *expected_pem_cert = "pem_cert1";
const char *expected_sans[] = {"san1", "san2", "san3"}; const char *expected_sans[] = {"san1", "san2", "san3"};
size_t i; size_t i;
GPR_ASSERT(tsi_construct_peer(4 + GPR_ARRAY_SIZE(expected_sans), &peer) == GPR_ASSERT(tsi_construct_peer(5 + GPR_ARRAY_SIZE(expected_sans), &peer) ==
TSI_OK); TSI_OK);
GPR_ASSERT(tsi_construct_string_peer_property_from_cstring( GPR_ASSERT(tsi_construct_string_peer_property_from_cstring(
TSI_CERTIFICATE_TYPE_PEER_PROPERTY, TSI_X509_CERTIFICATE_TYPE, TSI_CERTIFICATE_TYPE_PEER_PROPERTY, TSI_X509_CERTIFICATE_TYPE,
@ -279,10 +317,13 @@ static void test_cn_and_multiple_sans_and_others_ssl_peer_to_auth_context(
&peer.properties[2]) == TSI_OK); &peer.properties[2]) == TSI_OK);
GPR_ASSERT(tsi_construct_string_peer_property_from_cstring( GPR_ASSERT(tsi_construct_string_peer_property_from_cstring(
"chapi", "chapo", &peer.properties[3]) == TSI_OK); "chapi", "chapo", &peer.properties[3]) == TSI_OK);
GPR_ASSERT(tsi_construct_string_peer_property_from_cstring(
TSI_X509_PEM_CERT_PROPERTY, expected_pem_cert,
&peer.properties[4]) == TSI_OK);
for (i = 0; i < GPR_ARRAY_SIZE(expected_sans); i++) { for (i = 0; i < GPR_ARRAY_SIZE(expected_sans); i++) {
GPR_ASSERT(tsi_construct_string_peer_property_from_cstring( GPR_ASSERT(tsi_construct_string_peer_property_from_cstring(
TSI_X509_SUBJECT_ALTERNATIVE_NAME_PEER_PROPERTY, TSI_X509_SUBJECT_ALTERNATIVE_NAME_PEER_PROPERTY,
expected_sans[i], &peer.properties[4 + i]) == TSI_OK); expected_sans[i], &peer.properties[5 + i]) == TSI_OK);
} }
ctx = tsi_ssl_peer_to_auth_context(&peer); ctx = tsi_ssl_peer_to_auth_context(&peer);
GPR_ASSERT(ctx != NULL); GPR_ASSERT(ctx != NULL);
@ -291,6 +332,7 @@ static void test_cn_and_multiple_sans_and_others_ssl_peer_to_auth_context(
GPR_ARRAY_SIZE(expected_sans))); GPR_ARRAY_SIZE(expected_sans)));
GPR_ASSERT(check_transport_security_type(ctx)); GPR_ASSERT(check_transport_security_type(ctx));
GPR_ASSERT(check_x509_cn(ctx, expected_cn)); GPR_ASSERT(check_x509_cn(ctx, expected_cn));
GPR_ASSERT(check_x509_pem_cert(ctx, expected_pem_cert));
rpeer = tsi_shallow_peer_from_ssl_auth_context(ctx); rpeer = tsi_shallow_peer_from_ssl_auth_context(ctx);
GPR_ASSERT(check_ssl_peer_equivalence(&peer, &rpeer)); GPR_ASSERT(check_ssl_peer_equivalence(&peer, &rpeer));

Loading…
Cancel
Save