Create verify_peer_options when creating ssl credentials in order to expose a verification callback option.

These options are not yet exposed to languages outside of core.
pull/15274/head
Ian Haken 7 years ago
parent f91adce31c
commit 68eff58df6
  1. 34
      CMakeLists.txt
  2. 36
      Makefile
  3. 15
      build.yaml
  4. 31
      include/grpc/grpc_security.h
  5. 3
      src/core/lib/security/credentials/google_default/google_default_credentials.cc
  6. 20
      src/core/lib/security/credentials/ssl/ssl_credentials.cc
  7. 35
      src/core/lib/security/security_connector/security_connector.cc
  8. 1
      src/core/lib/security/security_connector/security_connector.h
  9. 3
      src/cpp/client/secure_credentials.cc
  10. 5
      src/csharp/ext/grpc_csharp_ext.c
  11. 4
      src/objective-c/GRPCClient/private/GRPCHost.m
  12. 2
      src/php/ext/grpc/channel_credentials.c
  13. 4
      src/python/grpcio/grpc/_cython/_cygrpc/credentials.pyx.pxi
  14. 7
      src/python/grpcio/grpc/_cython/_cygrpc/grpc.pxi
  15. 6
      src/ruby/ext/grpc/rb_channel_credentials.c
  16. 2
      src/ruby/ext/grpc/rb_grpc_imports.generated.h
  17. 2
      test/core/bad_ssl/bad_ssl_test.cc
  18. 2
      test/core/end2end/fixtures/h2_oauth2.cc
  19. 2
      test/core/end2end/fixtures/h2_ssl.cc
  20. 4
      test/core/end2end/fixtures/h2_ssl_proxy.cc
  21. 2
      test/core/end2end/fuzzers/api_fuzzer.cc
  22. 4
      test/core/end2end/h2_ssl_cert_test.cc
  23. 2
      test/core/end2end/h2_ssl_session_reuse_test.cc
  24. 18
      test/core/handshake/BUILD
  25. 4
      test/core/handshake/client_ssl.cc
  26. 275
      test/core/handshake/verify_peer_options.cc
  27. 2
      test/core/surface/num_external_connectivity_watchers_test.cc
  28. 2
      test/core/surface/sequential_connectivity_test.cc
  29. 17
      tools/run_tests/generated/sources_and_headers.json
  30. 20
      tools/run_tests/generated/tests.json

@ -308,6 +308,9 @@ endif()
if(_gRPC_PLATFORM_LINUX)
add_dependencies(buildtests_c handshake_server_with_readahead_handshaker)
endif()
if(_gRPC_PLATFORM_LINUX)
add_dependencies(buildtests_c handshake_verify_peer_options)
endif()
add_dependencies(buildtests_c histogram_test)
add_dependencies(buildtests_c hpack_parser_test)
add_dependencies(buildtests_c hpack_table_test)
@ -7380,6 +7383,37 @@ target_link_libraries(handshake_server_with_readahead_handshaker
gpr
)
endif()
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
if(_gRPC_PLATFORM_LINUX)
add_executable(handshake_verify_peer_options
test/core/handshake/verify_peer_options.cc
)
target_include_directories(handshake_verify_peer_options
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include
PRIVATE ${_gRPC_SSL_INCLUDE_DIR}
PRIVATE ${_gRPC_PROTOBUF_INCLUDE_DIR}
PRIVATE ${_gRPC_ZLIB_INCLUDE_DIR}
PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
)
target_link_libraries(handshake_verify_peer_options
${_gRPC_SSL_LIBRARIES}
${_gRPC_ALLTARGETS_LIBRARIES}
grpc_test_util
grpc
gpr_test_util
gpr
)
endif()
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)

@ -1014,6 +1014,7 @@ grpc_verify_jwt: $(BINDIR)/$(CONFIG)/grpc_verify_jwt
handshake_client: $(BINDIR)/$(CONFIG)/handshake_client
handshake_server: $(BINDIR)/$(CONFIG)/handshake_server
handshake_server_with_readahead_handshaker: $(BINDIR)/$(CONFIG)/handshake_server_with_readahead_handshaker
handshake_verify_peer_options: $(BINDIR)/$(CONFIG)/handshake_verify_peer_options
histogram_test: $(BINDIR)/$(CONFIG)/histogram_test
hpack_parser_fuzzer_test: $(BINDIR)/$(CONFIG)/hpack_parser_fuzzer_test
hpack_parser_test: $(BINDIR)/$(CONFIG)/hpack_parser_test
@ -1455,6 +1456,7 @@ buildtests_c: privatelibs_c \
$(BINDIR)/$(CONFIG)/handshake_client \
$(BINDIR)/$(CONFIG)/handshake_server \
$(BINDIR)/$(CONFIG)/handshake_server_with_readahead_handshaker \
$(BINDIR)/$(CONFIG)/handshake_verify_peer_options \
$(BINDIR)/$(CONFIG)/histogram_test \
$(BINDIR)/$(CONFIG)/hpack_parser_test \
$(BINDIR)/$(CONFIG)/hpack_table_test \
@ -2008,6 +2010,8 @@ test_c: buildtests_c
$(Q) $(BINDIR)/$(CONFIG)/handshake_server || ( echo test handshake_server failed ; exit 1 )
$(E) "[RUN] Testing handshake_server_with_readahead_handshaker"
$(Q) $(BINDIR)/$(CONFIG)/handshake_server_with_readahead_handshaker || ( echo test handshake_server_with_readahead_handshaker failed ; exit 1 )
$(E) "[RUN] Testing handshake_verify_peer_options"
$(Q) $(BINDIR)/$(CONFIG)/handshake_verify_peer_options || ( echo test handshake_verify_peer_options failed ; exit 1 )
$(E) "[RUN] Testing histogram_test"
$(Q) $(BINDIR)/$(CONFIG)/histogram_test || ( echo test histogram_test failed ; exit 1 )
$(E) "[RUN] Testing hpack_parser_test"
@ -12467,6 +12471,38 @@ endif
endif
HANDSHAKE_VERIFY_PEER_OPTIONS_SRC = \
test/core/handshake/verify_peer_options.cc \
HANDSHAKE_VERIFY_PEER_OPTIONS_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(HANDSHAKE_VERIFY_PEER_OPTIONS_SRC))))
ifeq ($(NO_SECURE),true)
# You can't build secure targets if you don't have OpenSSL.
$(BINDIR)/$(CONFIG)/handshake_verify_peer_options: openssl_dep_error
else
$(BINDIR)/$(CONFIG)/handshake_verify_peer_options: $(HANDSHAKE_VERIFY_PEER_OPTIONS_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
$(E) "[LD] Linking $@"
$(Q) mkdir -p `dirname $@`
$(Q) $(LD) $(LDFLAGS) $(HANDSHAKE_VERIFY_PEER_OPTIONS_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBS) $(LDLIBS_SECURE) -o $(BINDIR)/$(CONFIG)/handshake_verify_peer_options
endif
$(OBJDIR)/$(CONFIG)/test/core/handshake/verify_peer_options.o: $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
deps_handshake_verify_peer_options: $(HANDSHAKE_VERIFY_PEER_OPTIONS_OBJS:.o=.dep)
ifneq ($(NO_SECURE),true)
ifneq ($(NO_DEPS),true)
-include $(HANDSHAKE_VERIFY_PEER_OPTIONS_OBJS:.o=.dep)
endif
endif
HISTOGRAM_TEST_SRC = \
test/core/util/histogram_test.cc \

@ -2791,6 +2791,21 @@ targets:
platforms:
- linux
secure: true
- name: handshake_verify_peer_options
build: test
language: c
src:
- test/core/handshake/verify_peer_options.cc
deps:
- grpc_test_util
- grpc
- gpr_test_util
- gpr
exclude_iomgrs:
- uv
platforms:
- linux
secure: true
- name: histogram_test
build: test
language: c

@ -163,6 +163,26 @@ typedef struct {
const char* cert_chain;
} grpc_ssl_pem_key_cert_pair;
/** Object that holds additional peer-verification options on a secure
channel. */
typedef struct {
/** If non-NULL this callback will be invoked with the expected
target_name, the peer's certificate (in PEM format), and whatever
userdata pointer is set below. If a non-zero value is returned by this
callback then it is treated as a verification failure. Invocation of
the callback is blocking, so any implementation should be light-weight.
*/
int (*verify_peer_callback)(const char* target_name, const char* peer_pem,
void* userdata);
/** Arbitrary userdata that will be passed as the last argument to
verify_peer_callback. */
void* verify_peer_callback_userdata;
/** A destruct callback that will be invoked when the channel is being
cleaned up. The userdata argument will be passed to it. The intent is
to perform any cleanup associated with that userdata. */
void (*verify_peer_destruct)(void* userdata);
} verify_peer_options;
/** Creates an SSL credentials object.
- pem_root_certs is the NULL-terminated string containing the PEM encoding
of the server root certificates. If this parameter is NULL, the
@ -173,10 +193,17 @@ typedef struct {
disk (in the grpc install directory).
- pem_key_cert_pair is a pointer on the object containing client's private
key and certificate chain. This parameter can be NULL if the client does
not have such a key/cert pair. */
not have such a key/cert pair.
- verify_options is an optional verify_peer_options object which holds
additional options controlling how peer certificates are verified. For
example, you can supply a callback which receives the peer's certificate
with which you can do additional verification. Can be NULL, in which
case verification will retain default behavior. Any settings in
verify_options are copied during this call, so the verify_options
object can be released afterwards. */
GRPCAPI grpc_channel_credentials* grpc_ssl_credentials_create(
const char* pem_root_certs, grpc_ssl_pem_key_cert_pair* pem_key_cert_pair,
void* reserved);
const verify_peer_options* verify_options, void* reserved);
/** --- grpc_call_credentials object.

@ -231,7 +231,8 @@ end:
creds->base.vtable = &google_default_credentials_vtable;
creds->base.type = GRPC_CHANNEL_CREDENTIALS_TYPE_GOOGLE_DEFAULT;
gpr_ref_init(&creds->base.refcount, 1);
creds->ssl_creds = grpc_ssl_credentials_create(nullptr, nullptr, nullptr);
creds->ssl_creds =
grpc_ssl_credentials_create(nullptr, nullptr, nullptr, nullptr);
GPR_ASSERT(creds->ssl_creds != nullptr);
grpc_alts_credentials_options* options =
grpc_alts_credentials_client_options_create();

@ -48,6 +48,10 @@ static void ssl_destruct(grpc_channel_credentials* creds) {
grpc_ssl_credentials* c = reinterpret_cast<grpc_ssl_credentials*>(creds);
gpr_free(c->config.pem_root_certs);
grpc_tsi_ssl_pem_key_cert_pairs_destroy(c->config.pem_key_cert_pair, 1);
if (c->config.verify_options.verify_peer_destruct != nullptr) {
c->config.verify_options.verify_peer_destruct(
c->config.verify_options.verify_peer_callback_userdata);
}
}
static grpc_security_status ssl_create_security_connector(
@ -87,6 +91,7 @@ static grpc_channel_credentials_vtable ssl_vtable = {
static void ssl_build_config(const char* pem_root_certs,
grpc_ssl_pem_key_cert_pair* pem_key_cert_pair,
const verify_peer_options* verify_options,
grpc_ssl_config* config) {
if (pem_root_certs != nullptr) {
config->pem_root_certs = gpr_strdup(pem_root_certs);
@ -101,23 +106,32 @@ static void ssl_build_config(const char* pem_root_certs,
config->pem_key_cert_pair->private_key =
gpr_strdup(pem_key_cert_pair->private_key);
}
if (verify_options != nullptr) {
memcpy(&config->verify_options, verify_options,
sizeof(verify_peer_options));
} else {
// Otherwise set all options to default values
memset(&config->verify_options, 0, sizeof(verify_peer_options));
}
}
grpc_channel_credentials* grpc_ssl_credentials_create(
const char* pem_root_certs, grpc_ssl_pem_key_cert_pair* pem_key_cert_pair,
void* reserved) {
const verify_peer_options* verify_options, void* reserved) {
grpc_ssl_credentials* c = static_cast<grpc_ssl_credentials*>(
gpr_zalloc(sizeof(grpc_ssl_credentials)));
GRPC_API_TRACE(
"grpc_ssl_credentials_create(pem_root_certs=%s, "
"pem_key_cert_pair=%p, "
"verify_options=%p, "
"reserved=%p)",
3, (pem_root_certs, pem_key_cert_pair, reserved));
4, (pem_root_certs, pem_key_cert_pair, verify_options, reserved));
GPR_ASSERT(reserved == nullptr);
c->base.type = GRPC_CHANNEL_CREDENTIALS_TYPE_SSL;
c->base.vtable = &ssl_vtable;
gpr_ref_init(&c->base.refcount, 1);
ssl_build_config(pem_root_certs, pem_key_cert_pair, &c->config);
ssl_build_config(pem_root_certs, pem_key_cert_pair, verify_options,
&c->config);
return &c->base;
}

@ -620,6 +620,7 @@ typedef struct {
tsi_ssl_client_handshaker_factory* client_handshaker_factory;
char* target_name;
char* overridden_target_name;
const verify_peer_options* verify_options;
} grpc_ssl_channel_security_connector;
typedef struct {
@ -878,11 +879,34 @@ static void ssl_channel_check_peer(grpc_security_connector* sc, tsi_peer peer,
grpc_closure* on_peer_checked) {
grpc_ssl_channel_security_connector* c =
reinterpret_cast<grpc_ssl_channel_security_connector*>(sc);
grpc_error* error = ssl_check_peer(sc,
c->overridden_target_name != nullptr
? c->overridden_target_name
: c->target_name,
&peer, auth_context);
const char* target_name = c->overridden_target_name != nullptr
? c->overridden_target_name
: c->target_name;
grpc_error* error = ssl_check_peer(sc, target_name, &peer, auth_context);
if (error == GRPC_ERROR_NONE &&
c->verify_options->verify_peer_callback != nullptr) {
const tsi_peer_property* p =
tsi_peer_get_property_by_name(&peer, TSI_X509_PEM_CERT_PROPERTY);
if (p == nullptr) {
error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"Cannot check peer: missing pem cert property.");
} else {
char* peer_pem = static_cast<char*>(gpr_malloc(p->value.length + 1));
memcpy(peer_pem, p->value.data, p->value.length);
peer_pem[p->value.length] = '\0';
int callback_status = c->verify_options->verify_peer_callback(
target_name, peer_pem,
c->verify_options->verify_peer_callback_userdata);
gpr_free(peer_pem);
if (callback_status) {
char* msg;
gpr_asprintf(&msg, "Verify peer callback returned a failure (%d)",
callback_status);
error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg);
gpr_free(msg);
}
}
}
GRPC_CLOSURE_SCHED(on_peer_checked, error);
tsi_peer_destruct(&peer);
}
@ -1047,6 +1071,7 @@ grpc_security_status grpc_ssl_channel_security_connector_create(
if (overridden_target_name != nullptr) {
c->overridden_target_name = gpr_strdup(overridden_target_name);
}
c->verify_options = &config->verify_options;
has_key_cert_pair = config->pem_key_cert_pair != nullptr &&
config->pem_key_cert_pair->private_key != nullptr &&

@ -193,6 +193,7 @@ grpc_server_security_connector* grpc_fake_server_security_connector_create(
typedef struct {
tsi_ssl_pem_key_cert_pair* pem_key_cert_pair;
char* pem_root_certs;
verify_peer_options verify_options;
} grpc_ssl_config;
/* Creates an SSL channel_security_connector.

@ -83,7 +83,8 @@ std::shared_ptr<ChannelCredentials> SslCredentials(
grpc_channel_credentials* c_creds = grpc_ssl_credentials_create(
options.pem_root_certs.empty() ? nullptr : options.pem_root_certs.c_str(),
options.pem_private_key.empty() ? nullptr : &pem_key_cert_pair, nullptr);
options.pem_private_key.empty() ? nullptr : &pem_key_cert_pair, nullptr,
nullptr);
return WrapChannelCredentials(c_creds);
}

@ -935,11 +935,12 @@ grpcsharp_ssl_credentials_create(const char* pem_root_certs,
if (key_cert_pair_cert_chain || key_cert_pair_private_key) {
key_cert_pair.cert_chain = key_cert_pair_cert_chain;
key_cert_pair.private_key = key_cert_pair_private_key;
return grpc_ssl_credentials_create(pem_root_certs, &key_cert_pair, NULL);
return grpc_ssl_credentials_create(pem_root_certs, &key_cert_pair, NULL,
NULL);
} else {
GPR_ASSERT(!key_cert_pair_cert_chain);
GPR_ASSERT(!key_cert_pair_private_key);
return grpc_ssl_credentials_create(pem_root_certs, NULL, NULL);
return grpc_ssl_credentials_create(pem_root_certs, NULL, NULL, NULL);
}
}

@ -172,7 +172,7 @@ static NSMutableDictionary *kHostCache;
grpc_channel_credentials *creds;
if (pemPrivateKey == nil && pemCertChain == nil) {
creds = grpc_ssl_credentials_create(rootsASCII.bytes, NULL, NULL);
creds = grpc_ssl_credentials_create(rootsASCII.bytes, NULL, NULL, NULL);
} else {
grpc_ssl_pem_key_cert_pair key_cert_pair;
NSData *privateKeyASCII =
@ -181,7 +181,7 @@ static NSMutableDictionary *kHostCache;
[pemCertChain dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES];
key_cert_pair.private_key = privateKeyASCII.bytes;
key_cert_pair.cert_chain = certChainASCII.bytes;
creds = grpc_ssl_credentials_create(rootsASCII.bytes, &key_cert_pair, NULL);
creds = grpc_ssl_credentials_create(rootsASCII.bytes, &key_cert_pair, NULL, NULL);
}
@synchronized(self) {

@ -158,7 +158,7 @@ PHP_METHOD(ChannelCredentials, createSsl) {
grpc_channel_credentials *creds = grpc_ssl_credentials_create(
pem_root_certs,
pem_key_cert_pair.private_key == NULL ? NULL : &pem_key_cert_pair, NULL);
pem_key_cert_pair.private_key == NULL ? NULL : &pem_key_cert_pair, NULL, NULL);
zval *creds_object = grpc_php_wrap_channel_credentials(creds, hashstr, false
TSRMLS_CC);
efree(hashkey);

@ -142,12 +142,12 @@ cdef class SSLChannelCredentials(ChannelCredentials):
c_pem_root_certificates = self._pem_root_certificates
if self._private_key is None and self._certificate_chain is None:
return grpc_ssl_credentials_create(
c_pem_root_certificates, NULL, NULL)
c_pem_root_certificates, NULL, NULL, NULL)
else:
c_pem_key_certificate_pair.private_key = self._private_key
c_pem_key_certificate_pair.certificate_chain = self._certificate_chain
return grpc_ssl_credentials_create(
c_pem_root_certificates, &c_pem_key_certificate_pair, NULL)
c_pem_root_certificates, &c_pem_key_certificate_pair, NULL, NULL)
cdef class CompositeChannelCredentials(ChannelCredentials):

@ -453,11 +453,14 @@ cdef extern from "grpc/grpc_security.h":
# We don't care about the internals (and in fact don't know them)
pass
ctypedef struct grpc_ssl_session_cache:
# We don't care about the internals (and in fact don't know them)
pass
ctypedef struct verify_peer_options:
# We don't care about the internals (and in fact don't know them)
pass
ctypedef void (*grpc_ssl_roots_override_callback)(char **pem_root_certs)
grpc_ssl_session_cache *grpc_ssl_session_cache_create_lru(size_t capacity)
@ -469,7 +472,7 @@ cdef extern from "grpc/grpc_security.h":
grpc_channel_credentials *grpc_google_default_credentials_create() nogil
grpc_channel_credentials *grpc_ssl_credentials_create(
const char *pem_root_certs, grpc_ssl_pem_key_cert_pair *pem_key_cert_pair,
void *reserved) nogil
verify_peer_options *verify_options, void *reserved) nogil
grpc_channel_credentials *grpc_composite_channel_credentials_create(
grpc_channel_credentials *creds1, grpc_call_credentials *creds2,
void *reserved) nogil

@ -159,12 +159,12 @@ static VALUE grpc_rb_channel_credentials_init(int argc, VALUE* argv,
pem_root_certs_cstr = RSTRING_PTR(pem_root_certs);
}
if (pem_private_key == Qnil && pem_cert_chain == Qnil) {
creds = grpc_ssl_credentials_create(pem_root_certs_cstr, NULL, NULL);
creds = grpc_ssl_credentials_create(pem_root_certs_cstr, NULL, NULL, NULL);
} else {
key_cert_pair.private_key = RSTRING_PTR(pem_private_key);
key_cert_pair.cert_chain = RSTRING_PTR(pem_cert_chain);
creds =
grpc_ssl_credentials_create(pem_root_certs_cstr, &key_cert_pair, NULL);
creds = grpc_ssl_credentials_create(pem_root_certs_cstr, &key_cert_pair,
NULL, NULL);
}
if (creds == NULL) {
rb_raise(rb_eRuntimeError, "could not create a credentials, not sure why");

@ -317,7 +317,7 @@ extern grpc_google_default_credentials_create_type grpc_google_default_credentia
typedef void(*grpc_set_ssl_roots_override_callback_type)(grpc_ssl_roots_override_callback cb);
extern grpc_set_ssl_roots_override_callback_type grpc_set_ssl_roots_override_callback_import;
#define grpc_set_ssl_roots_override_callback grpc_set_ssl_roots_override_callback_import
typedef grpc_channel_credentials*(*grpc_ssl_credentials_create_type)(const char* pem_root_certs, grpc_ssl_pem_key_cert_pair* pem_key_cert_pair, void* reserved);
typedef grpc_channel_credentials*(*grpc_ssl_credentials_create_type)(const char* pem_root_certs, grpc_ssl_pem_key_cert_pair* pem_key_cert_pair, const verify_peer_options* verify_options, void* reserved);
extern grpc_ssl_credentials_create_type grpc_ssl_credentials_create_import;
#define grpc_ssl_credentials_create grpc_ssl_credentials_create_import
typedef void(*grpc_call_credentials_release_type)(grpc_call_credentials* creds);

@ -37,7 +37,7 @@ static void* tag(intptr_t t) { return (void*)t; }
static void run_test(const char* target, size_t nops) {
grpc_channel_credentials* ssl_creds =
grpc_ssl_credentials_create(nullptr, nullptr, nullptr);
grpc_ssl_credentials_create(nullptr, nullptr, nullptr, nullptr);
grpc_channel* channel;
grpc_call* c;

@ -146,7 +146,7 @@ static void chttp2_init_client_simple_ssl_with_oauth2_secure_fullstack(
grpc_end2end_test_fixture* f, grpc_channel_args* client_args) {
grpc_core::ExecCtx exec_ctx;
grpc_channel_credentials* ssl_creds =
grpc_ssl_credentials_create(test_root_cert, nullptr, nullptr);
grpc_ssl_credentials_create(test_root_cert, nullptr, nullptr, nullptr);
grpc_call_credentials* oauth2_creds = grpc_md_only_test_credentials_create(
"authorization", oauth2_md, true /* is_async */);
grpc_channel_credentials* ssl_oauth2_creds =

@ -101,7 +101,7 @@ void chttp2_tear_down_secure_fullstack(grpc_end2end_test_fixture* f) {
static void chttp2_init_client_simple_ssl_secure_fullstack(
grpc_end2end_test_fixture* f, grpc_channel_args* client_args) {
grpc_channel_credentials* ssl_creds =
grpc_ssl_credentials_create(nullptr, nullptr, nullptr);
grpc_ssl_credentials_create(nullptr, nullptr, nullptr, nullptr);
grpc_arg ssl_name_override = {
GRPC_ARG_STRING,
const_cast<char*>(GRPC_SSL_TARGET_NAME_OVERRIDE_ARG),

@ -55,7 +55,7 @@ static grpc_channel* create_proxy_client(const char* target,
grpc_channel_args* client_args) {
grpc_channel* channel;
grpc_channel_credentials* ssl_creds =
grpc_ssl_credentials_create(nullptr, nullptr, nullptr);
grpc_ssl_credentials_create(nullptr, nullptr, nullptr, nullptr);
grpc_arg ssl_name_override = {
GRPC_ARG_STRING,
const_cast<char*>(GRPC_SSL_TARGET_NAME_OVERRIDE_ARG),
@ -138,7 +138,7 @@ void chttp2_tear_down_secure_fullstack(grpc_end2end_test_fixture* f) {
static void chttp2_init_client_simple_ssl_secure_fullstack(
grpc_end2end_test_fixture* f, grpc_channel_args* client_args) {
grpc_channel_credentials* ssl_creds =
grpc_ssl_credentials_create(nullptr, nullptr, nullptr);
grpc_ssl_credentials_create(nullptr, nullptr, nullptr, nullptr);
grpc_arg ssl_name_override = {
GRPC_ARG_STRING,
const_cast<char*>(GRPC_SSL_TARGET_NAME_OVERRIDE_ARG),

@ -222,7 +222,7 @@ static grpc_channel_credentials* read_ssl_channel_creds(input_stream* inp) {
grpc_channel_credentials* creds = grpc_ssl_credentials_create(
root_certs,
private_key != nullptr && certs != nullptr ? &key_cert_pair : nullptr,
nullptr);
nullptr, nullptr);
cred_artifact_ctx_finish(&ctx);
return creds;
}

@ -169,8 +169,8 @@ typedef enum { NONE, SELF_SIGNED, SIGNED, BAD_CERT_PAIR } certtype;
default: \
break; \
} \
ssl_creds = \
grpc_ssl_credentials_create(test_root_cert, key_cert_pair, NULL); \
ssl_creds = grpc_ssl_credentials_create(test_root_cert, key_cert_pair, \
NULL, NULL); \
grpc_arg ssl_name_override = { \
GRPC_ARG_STRING, \
const_cast<char*>(GRPC_SSL_TARGET_NAME_OVERRIDE_ARG), \

@ -66,7 +66,7 @@ grpc_channel* client_create(char* server_addr, grpc_ssl_session_cache* cache) {
grpc_ssl_pem_key_cert_pair signed_client_key_cert_pair = {
test_signed_client_key, test_signed_client_cert};
grpc_channel_credentials* client_creds = grpc_ssl_credentials_create(
test_root_cert, &signed_client_key_cert_pair, nullptr);
test_root_cert, &signed_client_key_cert_pair, nullptr, nullptr);
grpc_arg args[] = {
grpc_channel_arg_string_create(

@ -82,3 +82,21 @@ grpc_cc_test(
"//test/core/util:grpc_test_util",
],
)
grpc_cc_test(
name = "handshake_verify_peer_options",
srcs = ["verify_peer_options.cc"],
language = "C++",
data = [
"//src/core/tsi/test_creds:ca.pem",
"//src/core/tsi/test_creds:server1.key",
"//src/core/tsi/test_creds:server1.pem",
],
deps = [
"//:gpr",
"//:grpc",
"//test/core/util:gpr_test_util",
"//test/core/util:grpc_test_util",
],
)

@ -251,8 +251,8 @@ static bool client_ssl_test(char* server_alpn_preferred) {
reinterpret_cast<const char*> GRPC_SLICE_START_PTR(key_slice);
pem_key_cert_pair.cert_chain =
reinterpret_cast<const char*> GRPC_SLICE_START_PTR(cert_slice);
grpc_channel_credentials* ssl_creds =
grpc_ssl_credentials_create(ca_cert, &pem_key_cert_pair, nullptr);
grpc_channel_credentials* ssl_creds = grpc_ssl_credentials_create(
ca_cert, &pem_key_cert_pair, nullptr, nullptr);
// Establish a channel pointing at the TLS server. Since the gRPC runtime is
// lazy, this won't necessarily establish a connection yet.

@ -0,0 +1,275 @@
/*
*
* Copyright 2018 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 "src/core/lib/iomgr/port.h"
// This test won't work except with posix sockets enabled
#ifdef GRPC_POSIX_SOCKET
#include <arpa/inet.h>
#include <openssl/err.h>
#include <openssl/ssl.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <unistd.h>
#include <grpc/grpc.h>
#include <grpc/grpc_security.h>
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/string_util.h>
#include "src/core/lib/gprpp/thd.h"
#include "src/core/lib/iomgr/load_file.h"
#include "test/core/util/port.h"
#include "test/core/util/test_config.h"
#define SSL_CERT_PATH "src/core/tsi/test_creds/server1.pem"
#define SSL_KEY_PATH "src/core/tsi/test_creds/server1.key"
#define SSL_CA_PATH "src/core/tsi/test_creds/ca.pem"
// Simple gRPC server. This listens until client_handshake_complete occurs.
static gpr_event client_handshake_complete;
static void server_thread(void* arg) {
const int port = *static_cast<int*>(arg);
// Load key pair and establish server SSL credentials.
grpc_ssl_pem_key_cert_pair pem_key_cert_pair;
grpc_slice ca_slice, cert_slice, key_slice;
GPR_ASSERT(GRPC_LOG_IF_ERROR("load_file",
grpc_load_file(SSL_CA_PATH, 1, &ca_slice)));
GPR_ASSERT(GRPC_LOG_IF_ERROR("load_file",
grpc_load_file(SSL_CERT_PATH, 1, &cert_slice)));
GPR_ASSERT(GRPC_LOG_IF_ERROR("load_file",
grpc_load_file(SSL_KEY_PATH, 1, &key_slice)));
const char* ca_cert =
reinterpret_cast<const char*> GRPC_SLICE_START_PTR(ca_slice);
pem_key_cert_pair.private_key =
reinterpret_cast<const char*> GRPC_SLICE_START_PTR(key_slice);
pem_key_cert_pair.cert_chain =
reinterpret_cast<const char*> GRPC_SLICE_START_PTR(cert_slice);
grpc_server_credentials* ssl_creds = grpc_ssl_server_credentials_create(
ca_cert, &pem_key_cert_pair, 1, 0, nullptr);
// Start server listening on local port.
char* addr;
gpr_asprintf(&addr, "127.0.0.1:%d", port);
grpc_server* server = grpc_server_create(nullptr, nullptr);
GPR_ASSERT(grpc_server_add_secure_http2_port(server, addr, ssl_creds));
free(addr);
grpc_completion_queue* cq = grpc_completion_queue_create_for_next(nullptr);
grpc_server_register_completion_queue(server, cq, nullptr);
grpc_server_start(server);
// Wait a bounded number of time until client_handshake_complete is set,
// sleeping between polls. The total time spent (deadline * retries)
// should be strictly greater than the client retry limit so that the
// client will always timeout first.
int retries = 60;
while (!gpr_event_get(&client_handshake_complete) && retries-- > 0) {
const gpr_timespec cq_deadline = grpc_timeout_seconds_to_deadline(1);
grpc_event ev = grpc_completion_queue_next(cq, cq_deadline, nullptr);
GPR_ASSERT(ev.type == GRPC_QUEUE_TIMEOUT);
}
gpr_log(GPR_INFO, "Shutting down server");
grpc_server_shutdown_and_notify(server, cq, nullptr);
grpc_server_cancel_all_calls(server);
grpc_completion_queue_shutdown(cq);
const gpr_timespec cq_deadline = grpc_timeout_seconds_to_deadline(60);
grpc_event ev = grpc_completion_queue_next(cq, cq_deadline, nullptr);
GPR_ASSERT(ev.type == GRPC_OP_COMPLETE);
grpc_server_destroy(server);
grpc_completion_queue_destroy(cq);
grpc_server_credentials_release(ssl_creds);
grpc_slice_unref(cert_slice);
grpc_slice_unref(key_slice);
grpc_slice_unref(ca_slice);
}
// This test launches a minimal TLS grpc server on a separate thread and then
// establishes a TLS handshake via the core library to the server. The client
// uses the supplied verify options.
static bool verify_peer_options_test(verify_peer_options* verify_options) {
bool success = true;
grpc_init();
int port = grpc_pick_unused_port_or_die();
gpr_event_init(&client_handshake_complete);
// Launch the gRPC server thread.
bool ok;
grpc_core::Thread thd("grpc_client_ssl_test", server_thread, &port, &ok);
GPR_ASSERT(ok);
thd.Start();
// Load key pair and establish client SSL credentials.
grpc_ssl_pem_key_cert_pair pem_key_cert_pair;
grpc_slice ca_slice, cert_slice, key_slice;
GPR_ASSERT(GRPC_LOG_IF_ERROR("load_file",
grpc_load_file(SSL_CA_PATH, 1, &ca_slice)));
GPR_ASSERT(GRPC_LOG_IF_ERROR("load_file",
grpc_load_file(SSL_CERT_PATH, 1, &cert_slice)));
GPR_ASSERT(GRPC_LOG_IF_ERROR("load_file",
grpc_load_file(SSL_KEY_PATH, 1, &key_slice)));
const char* ca_cert =
reinterpret_cast<const char*> GRPC_SLICE_START_PTR(ca_slice);
pem_key_cert_pair.private_key =
reinterpret_cast<const char*> GRPC_SLICE_START_PTR(key_slice);
pem_key_cert_pair.cert_chain =
reinterpret_cast<const char*> GRPC_SLICE_START_PTR(cert_slice);
grpc_channel_credentials* ssl_creds = grpc_ssl_credentials_create(
ca_cert, &pem_key_cert_pair, verify_options, nullptr);
// Establish a channel pointing at the TLS server. Since the gRPC runtime is
// lazy, this won't necessarily establish a connection yet.
char* target;
gpr_asprintf(&target, "127.0.0.1:%d", port);
grpc_arg ssl_name_override = {
GRPC_ARG_STRING,
const_cast<char*>(GRPC_SSL_TARGET_NAME_OVERRIDE_ARG),
{const_cast<char*>("foo.test.google.fr")}};
grpc_channel_args grpc_args;
grpc_args.num_args = 1;
grpc_args.args = &ssl_name_override;
grpc_channel* channel =
grpc_secure_channel_create(ssl_creds, target, &grpc_args, nullptr);
GPR_ASSERT(channel);
gpr_free(target);
// Initially the channel will be idle, the
// grpc_channel_check_connectivity_state triggers an attempt to connect.
GPR_ASSERT(grpc_channel_check_connectivity_state(
channel, 1 /* try_to_connect */) == GRPC_CHANNEL_IDLE);
// Wait a bounded number of times for the channel to be ready. When the
// channel is ready, the initial TLS handshake will have successfully
// completed. The total time spent on the client side (retries * deadline)
// should be greater than the server side time limit.
int retries = 10;
grpc_connectivity_state state = GRPC_CHANNEL_IDLE;
grpc_completion_queue* cq = grpc_completion_queue_create_for_next(nullptr);
while (state != GRPC_CHANNEL_READY && retries-- > 0) {
grpc_channel_watch_connectivity_state(
channel, state, grpc_timeout_seconds_to_deadline(3), cq, nullptr);
gpr_timespec cq_deadline = grpc_timeout_seconds_to_deadline(5);
grpc_event ev = grpc_completion_queue_next(cq, cq_deadline, nullptr);
GPR_ASSERT(ev.type == GRPC_OP_COMPLETE);
state =
grpc_channel_check_connectivity_state(channel, 0 /* try_to_connect */);
}
grpc_completion_queue_destroy(cq);
if (retries < 0) {
success = false;
}
grpc_channel_destroy(channel);
grpc_channel_credentials_release(ssl_creds);
grpc_slice_unref(cert_slice);
grpc_slice_unref(key_slice);
grpc_slice_unref(ca_slice);
// Now that the client is completely cleaned up, trigger the server to
// shutdown
gpr_event_set(&client_handshake_complete, &client_handshake_complete);
// Wait for the server to completely shutdown
thd.Join();
grpc_shutdown();
return success;
}
static int callback_return_value = 0;
static char callback_target_host[4096];
static char callback_target_pem[4096];
static void* callback_userdata = nullptr;
static void* destruct_userdata = nullptr;
static int verify_callback(const char* target_host, const char* target_pem,
void* userdata) {
if (target_host != nullptr) {
snprintf(callback_target_host, sizeof(callback_target_host), "%s",
target_host);
} else {
callback_target_host[0] = '\0';
}
if (target_pem != nullptr) {
snprintf(callback_target_pem, sizeof(callback_target_pem), "%s",
target_pem);
} else {
callback_target_pem[0] = '\0';
}
callback_userdata = userdata;
return callback_return_value;
}
static void verify_destruct(void* userdata) { destruct_userdata = userdata; }
int main(int argc, char* argv[]) {
int userdata = 42;
verify_peer_options verify_options;
// Load the server's cert so that we can assert it gets passed to the callback
grpc_slice cert_slice;
GPR_ASSERT(GRPC_LOG_IF_ERROR("load_file",
grpc_load_file(SSL_CERT_PATH, 1, &cert_slice)));
const char* server_cert =
reinterpret_cast<const char*> GRPC_SLICE_START_PTR(cert_slice);
// Running with all-null values should have no effect
verify_options.verify_peer_callback = nullptr;
verify_options.verify_peer_callback_userdata = nullptr;
verify_options.verify_peer_destruct = nullptr;
GPR_ASSERT(verify_peer_options_test(&verify_options));
GPR_ASSERT(strlen(callback_target_host) == 0);
GPR_ASSERT(strlen(callback_target_pem) == 0);
GPR_ASSERT(callback_userdata == nullptr);
GPR_ASSERT(destruct_userdata == nullptr);
// Running with the callbacks and verify we get the expected values
verify_options.verify_peer_callback = verify_callback;
verify_options.verify_peer_callback_userdata = static_cast<void*>(&userdata);
verify_options.verify_peer_destruct = verify_destruct;
GPR_ASSERT(verify_peer_options_test(&verify_options));
GPR_ASSERT(strcmp(callback_target_host, "foo.test.google.fr") == 0);
GPR_ASSERT(strcmp(callback_target_pem, server_cert) == 0);
GPR_ASSERT(callback_userdata == static_cast<void*>(&userdata));
GPR_ASSERT(destruct_userdata == static_cast<void*>(&userdata));
// If the callback returns non-zero, initializing the channel should fail.
callback_return_value = 1;
GPR_ASSERT(!verify_peer_options_test(&verify_options));
grpc_slice_unref(cert_slice);
return 0;
}
#else /* GRPC_POSIX_SOCKET */
int main(int argc, char** argv) { return 1; }
#endif /* GRPC_POSIX_SOCKET */

@ -168,7 +168,7 @@ static const test_fixture insecure_test = {
static grpc_channel* secure_test_create_channel(const char* addr) {
grpc_channel_credentials* ssl_creds =
grpc_ssl_credentials_create(test_root_cert, nullptr, nullptr);
grpc_ssl_credentials_create(test_root_cert, nullptr, nullptr, nullptr);
grpc_arg ssl_name_override = {
GRPC_ARG_STRING,
const_cast<char*>(GRPC_SSL_TARGET_NAME_OVERRIDE_ARG),

@ -144,7 +144,7 @@ static void secure_test_add_port(grpc_server* server, const char* addr) {
static grpc_channel* secure_test_create_channel(const char* addr) {
grpc_channel_credentials* ssl_creds =
grpc_ssl_credentials_create(test_root_cert, nullptr, nullptr);
grpc_ssl_credentials_create(test_root_cert, nullptr, nullptr, nullptr);
grpc_arg ssl_name_override = {
GRPC_ARG_STRING,
const_cast<char*>(GRPC_SSL_TARGET_NAME_OVERRIDE_ARG),

@ -1174,6 +1174,23 @@
"third_party": false,
"type": "target"
},
{
"deps": [
"gpr",
"gpr_test_util",
"grpc",
"grpc_test_util"
],
"headers": [],
"is_filegroup": false,
"language": "c",
"name": "handshake_verify_peer_options",
"src": [
"test/core/handshake/verify_peer_options.cc"
],
"third_party": false,
"type": "target"
},
{
"deps": [
"gpr",

@ -1447,6 +1447,26 @@
],
"uses_polling": true
},
{
"args": [],
"benchmark": false,
"ci_platforms": [
"linux"
],
"cpu_cost": 1.0,
"exclude_configs": [],
"exclude_iomgrs": [
"uv"
],
"flaky": false,
"gtest": false,
"language": "c",
"name": "handshake_verify_peer_options",
"platforms": [
"linux"
],
"uses_polling": true
},
{
"args": [],
"benchmark": false,

Loading…
Cancel
Save