add security level negotiation between call creds and channel.

reviewable/pr21215/r13
Yihua Zhang 5 years ago
parent 4f0875dd9e
commit e10d90ba27
  1. 28
      include/grpc/grpc_security.h
  2. 5
      include/grpc/grpc_security_constants.h
  3. 4
      include/grpcpp/security/credentials_impl.h
  4. 7
      src/core/lib/security/credentials/composite/composite_credentials.cc
  5. 6
      src/core/lib/security/credentials/composite/composite_credentials.h
  6. 11
      src/core/lib/security/credentials/credentials.h
  7. 3
      src/core/lib/security/credentials/fake/fake_credentials.h
  8. 10
      src/core/lib/security/credentials/plugin/plugin_credentials.cc
  9. 3
      src/core/lib/security/credentials/plugin/plugin_credentials.h
  10. 13
      src/core/lib/security/security_connector/alts/alts_security_connector.cc
  11. 24
      src/core/lib/security/security_connector/fake/fake_security_connector.cc
  12. 32
      src/core/lib/security/security_connector/local/local_security_connector.cc
  13. 32
      src/core/lib/security/security_connector/ssl_utils.cc
  14. 11
      src/core/lib/security/security_connector/ssl_utils.h
  15. 33
      src/core/lib/security/transport/client_auth_filter.cc
  16. 12
      src/core/tsi/alts/handshaker/alts_tsi_handshaker.cc
  17. 2
      src/core/tsi/alts/handshaker/alts_tsi_handshaker.h
  18. 10
      src/core/tsi/fake_transport_security.cc
  19. 2
      src/core/tsi/fake_transport_security.h
  20. 9
      src/core/tsi/ssl_transport_security.cc
  21. 13
      src/core/tsi/transport_security.cc
  22. 12
      src/core/tsi/transport_security_interface.h
  23. 18
      src/cpp/client/secure_credentials.cc
  24. 6
      src/csharp/ext/grpc_csharp_ext.c
  25. 5
      src/php/ext/grpc/call_credentials.c
  26. 4
      src/python/grpcio/grpc/_cython/_cygrpc/credentials.pyx.pxi
  27. 9
      src/python/grpcio/grpc/_cython/_cygrpc/grpc.pxi
  28. 10
      src/python/grpcio_tests/tests/unit/_auth_context_test.py
  29. 5
      src/ruby/ext/grpc/rb_call_credentials.c
  30. 2
      src/ruby/ext/grpc/rb_grpc_imports.generated.h
  31. 1
      test/core/end2end/end2end_tests.h
  32. 3
      test/core/end2end/fixtures/h2_fakesec.cc
  33. 15
      test/core/end2end/tests/call_creds.cc
  34. 40
      test/core/security/alts_security_connector_test.cc
  35. 33
      test/core/security/credentials_test.cc
  36. 58
      test/core/security/security_connector_test.cc
  37. 10
      test/core/tsi/alts/handshaker/alts_tsi_handshaker_test.cc
  38. 5
      test/core/tsi/fake_transport_security_test.cc
  39. 16
      test/core/tsi/ssl_transport_security_test.cc

@ -132,7 +132,8 @@ GRPCAPI void grpc_channel_credentials_release(grpc_channel_credentials* creds);
/** Creates default credentials to connect to a google gRPC service. /** Creates default credentials to connect to a google gRPC service.
WARNING: Do NOT use this credentials to connect to a non-google service as WARNING: Do NOT use this credentials to connect to a non-google service as
this could result in an oauth2 token leak. */ this could result in an oauth2 token leak. The security level of the
resulting connection is GRPC_PRIVACY_AND_INTEGRITY. */
GRPCAPI grpc_channel_credentials* grpc_google_default_credentials_create(void); GRPCAPI grpc_channel_credentials* grpc_google_default_credentials_create(void);
/** Callback for getting the SSL roots override from the application. /** Callback for getting the SSL roots override from the application.
@ -208,6 +209,7 @@ typedef struct {
/** Deprecated in favor of grpc_ssl_server_credentials_create_ex. It will be /** Deprecated in favor of grpc_ssl_server_credentials_create_ex. It will be
removed after all of its call sites are migrated to removed after all of its call sites are migrated to
grpc_ssl_server_credentials_create_ex. Creates an SSL credentials object. grpc_ssl_server_credentials_create_ex. Creates an SSL credentials object.
The security level of the resulting connection is GRPC_PRIVACY_AND_INTEGRITY.
- pem_root_certs is the NULL-terminated string containing the PEM encoding - pem_root_certs is the NULL-terminated string containing the PEM encoding
of the server root certificates. If this parameter is NULL, the of the server root certificates. If this parameter is NULL, the
implementation will first try to dereference the file pointed by the implementation will first try to dereference the file pointed by the
@ -239,6 +241,7 @@ GRPCAPI grpc_channel_credentials* grpc_ssl_credentials_create(
const verify_peer_options* verify_options, void* reserved); const verify_peer_options* verify_options, void* reserved);
/* Creates an SSL credentials object. /* Creates an SSL credentials object.
The security level of the resulting connection is GRPC_PRIVACY_AND_INTEGRITY.
- pem_root_certs is the NULL-terminated string containing the PEM encoding - pem_root_certs is the NULL-terminated string containing the PEM encoding
of the server root certificates. If this parameter is NULL, the of the server root certificates. If this parameter is NULL, the
implementation will first try to dereference the file pointed by the implementation will first try to dereference the file pointed by the
@ -281,7 +284,8 @@ typedef struct grpc_call_credentials grpc_call_credentials;
The creator of the credentials object is responsible for its release. */ The creator of the credentials object is responsible for its release. */
GRPCAPI void grpc_call_credentials_release(grpc_call_credentials* creds); GRPCAPI void grpc_call_credentials_release(grpc_call_credentials* creds);
/** Creates a composite channel credentials object. */ /** Creates a composite channel credentials object. The security level of
* resulting connection is determined by channel_creds. */
GRPCAPI grpc_channel_credentials* grpc_composite_channel_credentials_create( GRPCAPI grpc_channel_credentials* grpc_composite_channel_credentials_create(
grpc_channel_credentials* channel_creds, grpc_call_credentials* call_creds, grpc_channel_credentials* channel_creds, grpc_call_credentials* call_creds,
void* reserved); void* reserved);
@ -431,9 +435,11 @@ typedef struct {
const char* type; const char* type;
} grpc_metadata_credentials_plugin; } grpc_metadata_credentials_plugin;
/** Creates a credentials object from a plugin. */ /** Creates a credentials object from a plugin with a specified minimum security
* level. */
GRPCAPI grpc_call_credentials* grpc_metadata_credentials_create_from_plugin( GRPCAPI grpc_call_credentials* grpc_metadata_credentials_create_from_plugin(
grpc_metadata_credentials_plugin plugin, void* reserved); grpc_metadata_credentials_plugin plugin,
grpc_security_level min_security_level, void* reserved);
/** --- Secure channel creation. --- */ /** --- Secure channel creation. --- */
@ -653,8 +659,9 @@ GRPCAPI void grpc_alts_credentials_options_destroy(
grpc_alts_credentials_options* options); grpc_alts_credentials_options* options);
/** /**
* This method creates an ALTS channel credential object. It is used for * This method creates an ALTS channel credential object. The security
* experimental purpose for now and subject to change. * level of the resulting connection is GRPC_PRIVACY_AND_INTEGRITY.
* It is used for experimental purpose for now and subject to change.
* *
* - options: grpc ALTS credentials options instance for client. * - options: grpc ALTS credentials options instance for client.
* *
@ -677,8 +684,10 @@ GRPCAPI grpc_server_credentials* grpc_alts_server_credentials_create(
/** --- Local channel/server credentials --- **/ /** --- Local channel/server credentials --- **/
/** /**
* This method creates a local channel credential object. It is used for * This method creates a local channel credential object. The security level
* experimental purpose for now and subject to change. * of the resulting connection is GRPC_PRIVACY_AND_INTEGRITY for UDS and
* GRPC_SECURITY_NONE for LOCAL_TCP. It is used for experimental purpose
* for now and subject to change.
* *
* - type: local connection type * - type: local connection type
* *
@ -940,7 +949,8 @@ grpc_tls_server_authorization_check_config_create(
/** /**
* This method creates a TLS channel credential object. * This method creates a TLS channel credential object.
* It takes ownership of the options parameter. * It takes ownership of the options parameter. The security level
* of the resulting connection is GRPC_PRIVACY_AND_INTEGRITY.
* *
* - options: grpc TLS credentials options instance. * - options: grpc TLS credentials options instance.
* *

@ -30,6 +30,7 @@ extern "C" {
#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" #define GRPC_X509_PEM_CERT_PROPERTY_NAME "x509_pem_cert"
#define GRPC_SSL_SESSION_REUSED_PROPERTY "ssl_session_reused" #define GRPC_SSL_SESSION_REUSED_PROPERTY "ssl_session_reused"
#define GRPC_TRANSPORT_SECURITY_LEVEL_PROPERTY_NAME "security_level"
/** Environment variable that points to the default SSL roots file. This file /** 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 must be a PEM encoded file with all the roots such as the one that can be
@ -105,7 +106,9 @@ typedef enum {
GRPC_SSL_REQUEST_AND_REQUIRE_CLIENT_CERTIFICATE_AND_VERIFY GRPC_SSL_REQUEST_AND_REQUIRE_CLIENT_CERTIFICATE_AND_VERIFY
} grpc_ssl_client_certificate_request_type; } grpc_ssl_client_certificate_request_type;
/* Security levels of grpc transport security */ /* Security levels of grpc transport security. It represents an inherent
* property of a backend connection and is determined by a channel credential
* used to create the connection. */
typedef enum { typedef enum {
GRPC_SECURITY_MIN, GRPC_SECURITY_MIN,
GRPC_SECURITY_NONE = GRPC_SECURITY_MIN, GRPC_SECURITY_NONE = GRPC_SECURITY_MIN,

@ -321,6 +321,10 @@ grpc::Status StsCredentialsOptionsFromEnv(StsCredentialsOptions* options);
std::shared_ptr<CallCredentials> StsCredentials( std::shared_ptr<CallCredentials> StsCredentials(
const StsCredentialsOptions& options); const StsCredentialsOptions& options);
std::shared_ptr<CallCredentials> MetadataCredentialsFromPlugin(
std::unique_ptr<MetadataCredentialsPlugin> plugin,
grpc_security_level min_security_level);
/// Options used to build AltsCredentials. /// Options used to build AltsCredentials.
struct AltsCredentialsOptions { struct AltsCredentialsOptions {
/// service accounts of target endpoint that will be acceptable /// service accounts of target endpoint that will be acceptable

@ -151,6 +151,13 @@ grpc_composite_call_credentials::grpc_composite_call_credentials(
inner_.reserve(size); inner_.reserve(size);
push_to_inner(std::move(creds1), creds1_is_composite); push_to_inner(std::move(creds1), creds1_is_composite);
push_to_inner(std::move(creds2), creds2_is_composite); push_to_inner(std::move(creds2), creds2_is_composite);
min_security_level_ = GRPC_SECURITY_NONE;
for (size_t i = 0; i < inner_.size(); ++i) {
if (static_cast<int>(min_security_level_) <
static_cast<int>(inner_[i]->min_security_level())) {
min_security_level_ = inner_[i]->min_security_level();
}
}
} }
static grpc_core::RefCountedPtr<grpc_call_credentials> static grpc_core::RefCountedPtr<grpc_call_credentials>

@ -86,12 +86,16 @@ class grpc_composite_call_credentials : public grpc_call_credentials {
void cancel_get_request_metadata(grpc_credentials_mdelem_array* md_array, void cancel_get_request_metadata(grpc_credentials_mdelem_array* md_array,
grpc_error* error) override; grpc_error* error) override;
grpc_security_level min_security_level() const override {
return min_security_level_;
}
const CallCredentialsList& inner() const { return inner_; } const CallCredentialsList& inner() const { return inner_; }
private: private:
void push_to_inner(grpc_core::RefCountedPtr<grpc_call_credentials> creds, void push_to_inner(grpc_core::RefCountedPtr<grpc_call_credentials> creds,
bool is_composite); bool is_composite);
grpc_security_level min_security_level_;
CallCredentialsList inner_; CallCredentialsList inner_;
}; };

@ -225,7 +225,11 @@ void grpc_credentials_mdelem_array_destroy(grpc_credentials_mdelem_array* list);
struct grpc_call_credentials struct grpc_call_credentials
: public grpc_core::RefCounted<grpc_call_credentials> { : public grpc_core::RefCounted<grpc_call_credentials> {
public: public:
explicit grpc_call_credentials(const char* type) : type_(type) {} explicit grpc_call_credentials(
const char* type,
grpc_security_level min_security_level = GRPC_PRIVACY_AND_INTEGRITY)
: type_(type), min_security_level_(min_security_level) {}
virtual ~grpc_call_credentials() = default; virtual ~grpc_call_credentials() = default;
// Returns true if completed synchronously, in which case \a error will // Returns true if completed synchronously, in which case \a error will
@ -244,10 +248,15 @@ struct grpc_call_credentials
virtual void cancel_get_request_metadata( virtual void cancel_get_request_metadata(
grpc_credentials_mdelem_array* md_array, grpc_error* error) = 0; grpc_credentials_mdelem_array* md_array, grpc_error* error) = 0;
virtual grpc_security_level min_security_level() const {
return min_security_level_;
}
const char* type() const { return type_; } const char* type() const { return type_; }
private: private:
const char* type_; const char* type_;
const grpc_security_level min_security_level_;
}; };
/* Metadata-only credentials with the specified key and value where /* Metadata-only credentials with the specified key and value where

@ -59,7 +59,8 @@ class grpc_md_only_test_credentials : public grpc_call_credentials {
public: public:
grpc_md_only_test_credentials(const char* md_key, const char* md_value, grpc_md_only_test_credentials(const char* md_key, const char* md_value,
bool is_async) bool is_async)
: grpc_call_credentials(GRPC_CALL_CREDENTIALS_TYPE_OAUTH2), : grpc_call_credentials(GRPC_CALL_CREDENTIALS_TYPE_OAUTH2,
GRPC_SECURITY_NONE),
md_(grpc_mdelem_from_slices(grpc_slice_from_copied_string(md_key), md_(grpc_mdelem_from_slices(grpc_slice_from_copied_string(md_key),
grpc_slice_from_copied_string(md_value))), grpc_slice_from_copied_string(md_value))),
is_async_(is_async) {} is_async_(is_async) {}

@ -240,15 +240,17 @@ void grpc_plugin_credentials::cancel_get_request_metadata(
} }
grpc_plugin_credentials::grpc_plugin_credentials( grpc_plugin_credentials::grpc_plugin_credentials(
grpc_metadata_credentials_plugin plugin) grpc_metadata_credentials_plugin plugin,
: grpc_call_credentials(plugin.type), plugin_(plugin) { grpc_security_level min_security_level)
: grpc_call_credentials(plugin.type, min_security_level), plugin_(plugin) {
gpr_mu_init(&mu_); gpr_mu_init(&mu_);
} }
grpc_call_credentials* grpc_metadata_credentials_create_from_plugin( grpc_call_credentials* grpc_metadata_credentials_create_from_plugin(
grpc_metadata_credentials_plugin plugin, void* reserved) { grpc_metadata_credentials_plugin plugin,
grpc_security_level min_security_level, void* reserved) {
GRPC_API_TRACE("grpc_metadata_credentials_create_from_plugin(reserved=%p)", 1, GRPC_API_TRACE("grpc_metadata_credentials_create_from_plugin(reserved=%p)", 1,
(reserved)); (reserved));
GPR_ASSERT(reserved == nullptr); GPR_ASSERT(reserved == nullptr);
return new grpc_plugin_credentials(plugin); return new grpc_plugin_credentials(plugin, min_security_level);
} }

@ -39,7 +39,8 @@ struct grpc_plugin_credentials final : public grpc_call_credentials {
struct pending_request* next; struct pending_request* next;
}; };
explicit grpc_plugin_credentials(grpc_metadata_credentials_plugin plugin); explicit grpc_plugin_credentials(grpc_metadata_credentials_plugin plugin,
grpc_security_level min_security_level);
~grpc_plugin_credentials() override; ~grpc_plugin_credentials() override;
bool get_request_metadata(grpc_polling_entity* pollent, bool get_request_metadata(grpc_polling_entity* pollent,

@ -178,6 +178,13 @@ grpc_alts_auth_context_from_tsi_peer(const tsi_peer* peer) {
gpr_log(GPR_ERROR, "Invalid or missing certificate type property."); gpr_log(GPR_ERROR, "Invalid or missing certificate type property.");
return nullptr; return nullptr;
} }
/* Check if security level exists. */
const tsi_peer_property* security_level_prop =
tsi_peer_get_property_by_name(peer, TSI_SECURITY_LEVEL_PEER_PROPERTY);
if (security_level_prop == nullptr) {
gpr_log(GPR_ERROR, "Missing security level property.");
return nullptr;
}
/* Validate RPC protocol versions. */ /* Validate RPC protocol versions. */
const tsi_peer_property* rpc_versions_prop = const tsi_peer_property* rpc_versions_prop =
tsi_peer_get_property_by_name(peer, TSI_ALTS_RPC_VERSIONS); tsi_peer_get_property_by_name(peer, TSI_ALTS_RPC_VERSIONS);
@ -232,6 +239,12 @@ grpc_alts_auth_context_from_tsi_peer(const tsi_peer* peer) {
tsi_prop->value.data, tsi_prop->value.data,
tsi_prop->value.length); tsi_prop->value.length);
} }
/* Add security level to auth context. */
if (strcmp(tsi_prop->name, TSI_SECURITY_LEVEL_PEER_PROPERTY) == 0) {
grpc_auth_context_add_property(
ctx.get(), GRPC_TRANSPORT_SECURITY_LEVEL_PROPERTY_NAME,
tsi_prop->value.data, tsi_prop->value.length);
}
} }
if (!grpc_auth_context_peer_is_authenticated(ctx.get())) { if (!grpc_auth_context_peer_is_authenticated(ctx.get())) {
gpr_log(GPR_ERROR, "Invalid unauthenticated peer."); gpr_log(GPR_ERROR, "Invalid unauthenticated peer.");

@ -219,9 +219,9 @@ static void fake_check_peer(
const char* prop_name; const char* prop_name;
grpc_error* error = GRPC_ERROR_NONE; grpc_error* error = GRPC_ERROR_NONE;
*auth_context = nullptr; *auth_context = nullptr;
if (peer.property_count != 1) { if (peer.property_count != 2) {
error = GRPC_ERROR_CREATE_FROM_STATIC_STRING( error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"Fake peers should only have 1 property."); "Fake peers should only have 2 properties.");
goto end; goto end;
} }
prop_name = peer.properties[0].name; prop_name = peer.properties[0].name;
@ -240,10 +240,30 @@ static void fake_check_peer(
"Invalid value for cert type property."); "Invalid value for cert type property.");
goto end; goto end;
} }
prop_name = peer.properties[1].name;
if (prop_name == nullptr ||
strcmp(prop_name, TSI_SECURITY_LEVEL_PEER_PROPERTY) != 0) {
char* msg;
gpr_asprintf(&msg, "Unexpected property in fake peer: %s.",
prop_name == nullptr ? "<EMPTY>" : prop_name);
error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg);
gpr_free(msg);
goto end;
}
if (strncmp(peer.properties[1].value.data, TSI_FAKE_SECURITY_LEVEL,
peer.properties[1].value.length) != 0) {
error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"Invalid value for security level property.");
goto end;
}
*auth_context = grpc_core::MakeRefCounted<grpc_auth_context>(nullptr); *auth_context = grpc_core::MakeRefCounted<grpc_auth_context>(nullptr);
grpc_auth_context_add_cstring_property( grpc_auth_context_add_cstring_property(
auth_context->get(), GRPC_TRANSPORT_SECURITY_TYPE_PROPERTY_NAME, auth_context->get(), GRPC_TRANSPORT_SECURITY_TYPE_PROPERTY_NAME,
GRPC_FAKE_TRANSPORT_SECURITY_TYPE); GRPC_FAKE_TRANSPORT_SECURITY_TYPE);
grpc_auth_context_add_cstring_property(
auth_context->get(), GRPC_TRANSPORT_SECURITY_LEVEL_PROPERTY_NAME,
TSI_FAKE_SECURITY_LEVEL);
end: end:
grpc_core::ExecCtx::Run(DEBUG_LOCATION, on_peer_checked, error); grpc_core::ExecCtx::Run(DEBUG_LOCATION, on_peer_checked, error);
tsi_peer_destruct(&peer); tsi_peer_destruct(&peer);

@ -46,7 +46,8 @@
namespace { namespace {
grpc_core::RefCountedPtr<grpc_auth_context> local_auth_context_create() { grpc_core::RefCountedPtr<grpc_auth_context> local_auth_context_create(
const tsi_peer* peer) {
/* Create auth context. */ /* Create auth context. */
grpc_core::RefCountedPtr<grpc_auth_context> ctx = grpc_core::RefCountedPtr<grpc_auth_context> ctx =
grpc_core::MakeRefCounted<grpc_auth_context>(nullptr); grpc_core::MakeRefCounted<grpc_auth_context>(nullptr);
@ -55,10 +56,17 @@ grpc_core::RefCountedPtr<grpc_auth_context> local_auth_context_create() {
GRPC_LOCAL_TRANSPORT_SECURITY_TYPE); GRPC_LOCAL_TRANSPORT_SECURITY_TYPE);
GPR_ASSERT(grpc_auth_context_set_peer_identity_property_name( GPR_ASSERT(grpc_auth_context_set_peer_identity_property_name(
ctx.get(), GRPC_TRANSPORT_SECURITY_TYPE_PROPERTY_NAME) == 1); ctx.get(), GRPC_TRANSPORT_SECURITY_TYPE_PROPERTY_NAME) == 1);
GPR_ASSERT(peer->property_count == 1);
const tsi_peer_property* prop = &peer->properties[0];
GPR_ASSERT(prop != nullptr);
GPR_ASSERT(strcmp(prop->name, TSI_SECURITY_LEVEL_PEER_PROPERTY) == 0);
grpc_auth_context_add_property(ctx.get(),
GRPC_TRANSPORT_SECURITY_LEVEL_PROPERTY_NAME,
prop->value.data, prop->value.length);
return ctx; return ctx;
} }
void local_check_peer(grpc_security_connector* /*sc*/, tsi_peer /*peer*/, void local_check_peer(grpc_security_connector* sc, tsi_peer peer,
grpc_endpoint* ep, grpc_endpoint* ep,
grpc_core::RefCountedPtr<grpc_auth_context>* auth_context, grpc_core::RefCountedPtr<grpc_auth_context>* auth_context,
grpc_closure* on_peer_checked, grpc_closure* on_peer_checked,
@ -103,12 +111,30 @@ void local_check_peer(grpc_security_connector* /*sc*/, tsi_peer /*peer*/,
grpc_core::ExecCtx::Run(DEBUG_LOCATION, on_peer_checked, error); grpc_core::ExecCtx::Run(DEBUG_LOCATION, on_peer_checked, error);
return; return;
} }
// Add TSI_SECURITY_LEVEL_PEER_PROPERTY type peer property.
size_t new_property_count = peer.property_count + 1;
tsi_peer_property* new_properties = static_cast<tsi_peer_property*>(
gpr_zalloc(sizeof(*new_properties) * new_property_count));
for (size_t i = 0; i < peer.property_count; i++) {
new_properties[i] = peer.properties[i];
}
if (peer.properties != nullptr) gpr_free(peer.properties);
peer.properties = new_properties;
// TODO(yihuazhang): Set security level of local TCP to TSI_SECURITY_NONE.
const char* security_level =
tsi_security_level_to_string(TSI_PRIVACY_AND_INTEGRITY);
tsi_result result = tsi_construct_string_peer_property_from_cstring(
TSI_SECURITY_LEVEL_PEER_PROPERTY, security_level,
&peer.properties[peer.property_count]);
if (result != TSI_OK) return;
peer.property_count++;
/* Create an auth context which is necessary to pass the santiy check in /* Create an auth context which is necessary to pass the santiy check in
* {client, server}_auth_filter that verifies if the peer's auth context is * {client, server}_auth_filter that verifies if the peer's auth context is
* obtained during handshakes. The auth context is only checked for its * obtained during handshakes. The auth context is only checked for its
* existence and not actually used. * existence and not actually used.
*/ */
*auth_context = local_auth_context_create(); *auth_context = local_auth_context_create(&peer);
tsi_peer_destruct(&peer);
error = *auth_context != nullptr ? GRPC_ERROR_NONE error = *auth_context != nullptr ? GRPC_ERROR_NONE
: GRPC_ERROR_CREATE_FROM_STATIC_STRING( : GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"Could not create local auth context"); "Could not create local auth context");

@ -84,6 +84,30 @@ const char* grpc_get_ssl_cipher_suites(void) {
return cipher_suites; return cipher_suites;
} }
grpc_security_level grpc_tsi_security_level_string_to_enum(
const char* security_level) {
if (strcmp(security_level, "TSI_INTEGRITY_ONLY") == 0) {
return GRPC_INTEGRITY_ONLY;
} else if (strcmp(security_level, "TSI_PRIVACY_AND_INTEGRITY") == 0) {
return GRPC_PRIVACY_AND_INTEGRITY;
}
return GRPC_SECURITY_NONE;
}
const char* grpc_security_level_to_string(grpc_security_level security_level) {
if (security_level == GRPC_PRIVACY_AND_INTEGRITY) {
return "GRPC_PRIVACY_AND_INTEGRITY";
} else if (security_level == GRPC_INTEGRITY_ONLY) {
return "GRPC_INTEGRITY_ONLY";
}
return "GRPC_SECURITY_NONE";
}
bool grpc_check_security_level(grpc_security_level channel_level,
grpc_security_level call_cred_level) {
return static_cast<int>(channel_level) >= static_cast<int>(call_cred_level);
}
tsi_client_certificate_request_type tsi_client_certificate_request_type
grpc_get_tsi_client_certificate_request_type( grpc_get_tsi_client_certificate_request_type(
grpc_ssl_client_certificate_request_type grpc_request_type) { grpc_ssl_client_certificate_request_type grpc_request_type) {
@ -229,6 +253,10 @@ grpc_core::RefCountedPtr<grpc_auth_context> grpc_ssl_peer_to_auth_context(
grpc_auth_context_add_property(ctx.get(), grpc_auth_context_add_property(ctx.get(),
GRPC_SSL_SESSION_REUSED_PROPERTY, GRPC_SSL_SESSION_REUSED_PROPERTY,
prop->value.data, prop->value.length); prop->value.data, prop->value.length);
} else if (strcmp(prop->name, TSI_SECURITY_LEVEL_PEER_PROPERTY) == 0) {
grpc_auth_context_add_property(
ctx.get(), GRPC_TRANSPORT_SECURITY_LEVEL_PROPERTY_NAME,
prop->value.data, prop->value.length);
} }
} }
if (peer_identity_property_name != nullptr) { if (peer_identity_property_name != nullptr) {
@ -272,6 +300,10 @@ tsi_peer grpc_shallow_peer_from_ssl_auth_context(
} else if (strcmp(prop->name, GRPC_X509_PEM_CERT_PROPERTY_NAME) == 0) { } else if (strcmp(prop->name, GRPC_X509_PEM_CERT_PROPERTY_NAME) == 0) {
add_shallow_auth_property_to_peer(&peer, prop, add_shallow_auth_property_to_peer(&peer, prop,
TSI_X509_PEM_CERT_PROPERTY); TSI_X509_PEM_CERT_PROPERTY);
} else if (strcmp(prop->name,
GRPC_TRANSPORT_SECURITY_LEVEL_PROPERTY_NAME) == 0) {
add_shallow_auth_property_to_peer(&peer, prop,
TSI_SECURITY_LEVEL_PEER_PROPERTY);
} }
} }
} }

@ -68,6 +68,17 @@ tsi_client_certificate_request_type
grpc_get_tsi_client_certificate_request_type( grpc_get_tsi_client_certificate_request_type(
grpc_ssl_client_certificate_request_type grpc_request_type); grpc_ssl_client_certificate_request_type grpc_request_type);
/* Map tsi_security_level string to grpc_security_level enum. */
grpc_security_level grpc_tsi_security_level_string_to_enum(
const char* security_level);
/* Map grpc_security_level enum to a string. */
const char* grpc_security_level_to_string(grpc_security_level security_level);
/* Check security level of channel and call credential.*/
bool grpc_check_security_level(grpc_security_level channel_level,
grpc_security_level call_cred_level);
/* Return an array of strings containing alpn protocols. */ /* Return an array of strings containing alpn protocols. */
const char** grpc_fill_alpn_protocol_strings(size_t* num_alpn_protocols); const char** grpc_fill_alpn_protocol_strings(size_t* num_alpn_protocols);

@ -266,6 +266,39 @@ static void send_security_metadata(grpc_call_element* elem,
call_creds_has_md ? ctx->creds->Ref() : channel_call_creds->Ref(); call_creds_has_md ? ctx->creds->Ref() : channel_call_creds->Ref();
} }
/* Check security level of call credential and channel, and do not send
* metadata if the check fails. */
grpc_auth_property_iterator it = grpc_auth_context_find_properties_by_name(
chand->auth_context.get(), GRPC_TRANSPORT_SECURITY_LEVEL_PROPERTY_NAME);
const grpc_auth_property* prop = grpc_auth_property_iterator_next(&it);
if (prop == nullptr) {
grpc_transport_stream_op_batch_finish_with_failure(
batch,
grpc_error_set_int(
GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"Established channel does not have an auth property "
"representing a security level."),
GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_UNAUTHENTICATED),
calld->call_combiner);
return;
}
grpc_security_level call_cred_security_level =
calld->creds->min_security_level();
int is_security_level_ok = grpc_check_security_level(
grpc_tsi_security_level_string_to_enum(prop->value),
call_cred_security_level);
if (!is_security_level_ok) {
grpc_transport_stream_op_batch_finish_with_failure(
batch,
grpc_error_set_int(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"Established channel does not have a sufficient "
"security level to transfer call credential."),
GRPC_ERROR_INT_GRPC_STATUS,
GRPC_STATUS_UNAUTHENTICATED),
calld->call_combiner);
return;
}
grpc_auth_metadata_context_build( grpc_auth_metadata_context_build(
chand->security_connector->url_scheme(), calld->host, calld->method, chand->security_connector->url_scheme(), calld->host, calld->method,
chand->auth_context.get(), &calld->auth_md_context); chand->auth_context.get(), &calld->auth_md_context);

@ -86,7 +86,7 @@ static tsi_result handshaker_result_extract_peer(
alts_tsi_handshaker_result* result = alts_tsi_handshaker_result* result =
reinterpret_cast<alts_tsi_handshaker_result*>( reinterpret_cast<alts_tsi_handshaker_result*>(
const_cast<tsi_handshaker_result*>(self)); const_cast<tsi_handshaker_result*>(self));
GPR_ASSERT(kTsiAltsNumOfPeerProperties == 4); GPR_ASSERT(kTsiAltsNumOfPeerProperties == 5);
tsi_result ok = tsi_construct_peer(kTsiAltsNumOfPeerProperties, peer); tsi_result ok = tsi_construct_peer(kTsiAltsNumOfPeerProperties, peer);
int index = 0; int index = 0;
if (ok != TSI_OK) { if (ok != TSI_OK) {
@ -131,6 +131,16 @@ static tsi_result handshaker_result_extract_peer(
tsi_peer_destruct(peer); tsi_peer_destruct(peer);
gpr_log(GPR_ERROR, "Failed to set tsi peer property"); gpr_log(GPR_ERROR, "Failed to set tsi peer property");
} }
index++;
GPR_ASSERT(&peer->properties[index] != nullptr);
ok = tsi_construct_string_peer_property_from_cstring(
TSI_SECURITY_LEVEL_PEER_PROPERTY,
tsi_security_level_to_string(TSI_PRIVACY_AND_INTEGRITY),
&peer->properties[index]);
if (ok != TSI_OK) {
tsi_peer_destruct(peer);
gpr_log(GPR_ERROR, "Failed to set tsi peer property");
}
GPR_ASSERT(++index == kTsiAltsNumOfPeerProperties); GPR_ASSERT(++index == kTsiAltsNumOfPeerProperties);
return ok; return ok;
} }

@ -36,7 +36,7 @@
#define TSI_ALTS_RPC_VERSIONS "rpc_versions" #define TSI_ALTS_RPC_VERSIONS "rpc_versions"
#define TSI_ALTS_CONTEXT "alts_context" #define TSI_ALTS_CONTEXT "alts_context"
const size_t kTsiAltsNumOfPeerProperties = 4; const size_t kTsiAltsNumOfPeerProperties = 5;
typedef struct alts_tsi_handshaker alts_tsi_handshaker; typedef struct alts_tsi_handshaker alts_tsi_handshaker;

@ -495,14 +495,18 @@ typedef struct {
} fake_handshaker_result; } fake_handshaker_result;
static tsi_result fake_handshaker_result_extract_peer( static tsi_result fake_handshaker_result_extract_peer(
const tsi_handshaker_result* /*self*/, tsi_peer* peer) { const tsi_handshaker_result* self, tsi_peer* peer) {
/* Construct a tsi_peer with 1 property: certificate type. */ /* Construct a tsi_peer with 1 property: certificate type, security_level. */
tsi_result result = tsi_construct_peer(1, peer); tsi_result result = tsi_construct_peer(2, peer);
if (result != TSI_OK) return result; if (result != TSI_OK) return result;
result = tsi_construct_string_peer_property_from_cstring( result = tsi_construct_string_peer_property_from_cstring(
TSI_CERTIFICATE_TYPE_PEER_PROPERTY, TSI_FAKE_CERTIFICATE_TYPE, TSI_CERTIFICATE_TYPE_PEER_PROPERTY, TSI_FAKE_CERTIFICATE_TYPE,
&peer->properties[0]); &peer->properties[0]);
if (result != TSI_OK) tsi_peer_destruct(peer); if (result != TSI_OK) tsi_peer_destruct(peer);
result = tsi_construct_string_peer_property_from_cstring(
TSI_SECURITY_LEVEL_PEER_PROPERTY,
tsi_security_level_to_string(TSI_SECURITY_NONE), &peer->properties[1]);
if (result != TSI_OK) tsi_peer_destruct(peer);
return result; return result;
} }

@ -25,6 +25,8 @@
/* Value for the TSI_CERTIFICATE_TYPE_PEER_PROPERTY property for FAKE certs. */ /* Value for the TSI_CERTIFICATE_TYPE_PEER_PROPERTY property for FAKE certs. */
#define TSI_FAKE_CERTIFICATE_TYPE "FAKE" #define TSI_FAKE_CERTIFICATE_TYPE "FAKE"
/* Value of the TSI_SECURITY_LEVEL_PEER_PROPERTY property for FAKE certs. */
#define TSI_FAKE_SECURITY_LEVEL "TSI_SECURITY_NONE"
/* Creates a fake handshaker that will create a fake frame protector. /* Creates a fake handshaker that will create a fake frame protector.

@ -1049,7 +1049,7 @@ static tsi_result ssl_handshaker_result_extract_peer(
} }
// 1 is for session reused property. // 1 is for session reused property.
size_t new_property_count = peer->property_count + 1; size_t new_property_count = peer->property_count + 2;
if (alpn_selected != nullptr) new_property_count++; if (alpn_selected != nullptr) new_property_count++;
tsi_peer_property* new_properties = static_cast<tsi_peer_property*>( tsi_peer_property* new_properties = static_cast<tsi_peer_property*>(
gpr_zalloc(sizeof(*new_properties) * new_property_count)); gpr_zalloc(sizeof(*new_properties) * new_property_count));
@ -1067,6 +1067,13 @@ static tsi_result ssl_handshaker_result_extract_peer(
if (result != TSI_OK) return result; if (result != TSI_OK) return result;
peer->property_count++; peer->property_count++;
} }
// Add security_level peer property.
result = tsi_construct_string_peer_property_from_cstring(
TSI_SECURITY_LEVEL_PEER_PROPERTY,
tsi_security_level_to_string(TSI_PRIVACY_AND_INTEGRITY),
&peer->properties[peer->property_count]);
if (result != TSI_OK) return result;
peer->property_count++;
const char* session_reused = SSL_session_reused(impl->ssl) ? "true" : "false"; const char* session_reused = SSL_session_reused(impl->ssl) ? "true" : "false";
result = tsi_construct_string_peer_property_from_cstring( result = tsi_construct_string_peer_property_from_cstring(

@ -67,6 +67,19 @@ const char* tsi_result_to_string(tsi_result result) {
} }
} }
const char* tsi_security_level_to_string(tsi_security_level security_level) {
switch (security_level) {
case TSI_SECURITY_NONE:
return "TSI_SECURITY_NONE";
case TSI_INTEGRITY_ONLY:
return "TSI_INTEGRITY_ONLY";
case TSI_PRIVACY_AND_INTEGRITY:
return "TSI_PRIVACY_AND_INTEGRITY";
default:
return "UNKNOWN";
}
}
/* --- tsi_frame_protector common implementation. --- /* --- tsi_frame_protector common implementation. ---
Calls specific implementation after state/input validation. */ Calls specific implementation after state/input validation. */

@ -46,6 +46,14 @@ typedef enum {
TSI_HANDSHAKE_SHUTDOWN = 14, TSI_HANDSHAKE_SHUTDOWN = 14,
} tsi_result; } tsi_result;
typedef enum {
TSI_SECURITY_MIN,
TSI_SECURITY_NONE = TSI_SECURITY_MIN,
TSI_INTEGRITY_ONLY,
TSI_PRIVACY_AND_INTEGRITY,
TSI_SECURITY_MAX = TSI_PRIVACY_AND_INTEGRITY,
} tsi_security_level;
typedef enum { typedef enum {
// Default option // Default option
TSI_DONT_REQUEST_CLIENT_CERTIFICATE, TSI_DONT_REQUEST_CLIENT_CERTIFICATE,
@ -56,6 +64,7 @@ typedef enum {
} tsi_client_certificate_request_type; } tsi_client_certificate_request_type;
const char* tsi_result_to_string(tsi_result result); const char* tsi_result_to_string(tsi_result result);
const char* tsi_security_level_to_string(tsi_security_level security_level);
/* --- tsi tracing --- */ /* --- tsi tracing --- */
@ -185,6 +194,9 @@ void tsi_frame_protector_destroy(tsi_frame_protector* self);
/* This property is of type TSI_PEER_PROPERTY_STRING. */ /* This property is of type TSI_PEER_PROPERTY_STRING. */
#define TSI_CERTIFICATE_TYPE_PEER_PROPERTY "certificate_type" #define TSI_CERTIFICATE_TYPE_PEER_PROPERTY "certificate_type"
/* This property represents security level of a channel. */
#define TSI_SECURITY_LEVEL_PEER_PROPERTY "security_level"
/* Property values may contain NULL characters just like C++ strings. /* Property values may contain NULL characters just like C++ strings.
The length field gives the length of the string. */ The length field gives the length of the string. */
typedef struct tsi_peer_property { typedef struct tsi_peer_property {

@ -256,6 +256,20 @@ std::shared_ptr<CallCredentials> StsCredentials(
return WrapCallCredentials(grpc_sts_credentials_create(&opts, nullptr)); return WrapCallCredentials(grpc_sts_credentials_create(&opts, nullptr));
} }
std::shared_ptr<CallCredentials> MetadataCredentialsFromPlugin(
std::unique_ptr<MetadataCredentialsPlugin> plugin,
grpc_security_level min_security_level) {
grpc::GrpcLibraryCodegen init; // To call grpc_init().
const char* type = plugin->GetType();
grpc::MetadataCredentialsPluginWrapper* wrapper =
new grpc::MetadataCredentialsPluginWrapper(std::move(plugin));
grpc_metadata_credentials_plugin c_plugin = {
grpc::MetadataCredentialsPluginWrapper::GetMetadata,
grpc::MetadataCredentialsPluginWrapper::Destroy, wrapper, type};
return WrapCallCredentials(grpc_metadata_credentials_create_from_plugin(
c_plugin, min_security_level, nullptr));
}
// Builds ALTS Credentials given ALTS specific options // Builds ALTS Credentials given ALTS specific options
std::shared_ptr<ChannelCredentials> AltsCredentials( std::shared_ptr<ChannelCredentials> AltsCredentials(
const AltsCredentialsOptions& options) { const AltsCredentialsOptions& options) {
@ -374,8 +388,8 @@ std::shared_ptr<CallCredentials> MetadataCredentialsFromPlugin(
grpc_metadata_credentials_plugin c_plugin = { grpc_metadata_credentials_plugin c_plugin = {
grpc::MetadataCredentialsPluginWrapper::GetMetadata, grpc::MetadataCredentialsPluginWrapper::GetMetadata,
grpc::MetadataCredentialsPluginWrapper::Destroy, wrapper, type}; grpc::MetadataCredentialsPluginWrapper::Destroy, wrapper, type};
return WrapCallCredentials( return WrapCallCredentials(grpc_metadata_credentials_create_from_plugin(
grpc_metadata_credentials_create_from_plugin(c_plugin, nullptr)); c_plugin, GRPC_PRIVACY_AND_INTEGRITY, nullptr));
} }
} // namespace grpc_impl } // namespace grpc_impl

@ -1136,7 +1136,11 @@ grpcsharp_metadata_credentials_create_from_plugin(void* callback_tag) {
plugin.destroy = grpcsharp_metadata_credentials_destroy_handler; plugin.destroy = grpcsharp_metadata_credentials_destroy_handler;
plugin.state = callback_tag; plugin.state = callback_tag;
plugin.type = ""; plugin.type = "";
return grpc_metadata_credentials_create_from_plugin(plugin, NULL); // TODO(yihuazhang): Expose min_security_level via the C# API so
// that applications can decide what minimum security level their
// plugins require.
return grpc_metadata_credentials_create_from_plugin(
plugin, GRPC_PRIVACY_AND_INTEGRITY, NULL);
} }
/* Auth context */ /* Auth context */

@ -126,9 +126,10 @@ PHP_METHOD(CallCredentials, createFromPlugin) {
plugin.destroy = plugin_destroy_state; plugin.destroy = plugin_destroy_state;
plugin.state = (void *)state; plugin.state = (void *)state;
plugin.type = ""; plugin.type = "";
// TODO(yihuazhang): Expose min_security_level via the PHP API so that
// applications can decide what minimum security level their plugins require.
grpc_call_credentials *creds = grpc_call_credentials *creds =
grpc_metadata_credentials_create_from_plugin(plugin, NULL); grpc_metadata_credentials_create_from_plugin(plugin, GRPC_PRIVACY_AND_INTEGRITY, NULL);
zval *creds_object = grpc_php_wrap_call_credentials(creds TSRMLS_CC); zval *creds_object = grpc_php_wrap_call_credentials(creds TSRMLS_CC);
RETURN_DESTROY_ZVAL(creds_object); RETURN_DESTROY_ZVAL(creds_object);
} }

@ -76,7 +76,9 @@ cdef class MetadataPluginCallCredentials(CallCredentials):
c_metadata_plugin.type = self._name c_metadata_plugin.type = self._name
cpython.Py_INCREF(self._metadata_plugin) cpython.Py_INCREF(self._metadata_plugin)
fork_handlers_and_grpc_init() fork_handlers_and_grpc_init()
return grpc_metadata_credentials_create_from_plugin(c_metadata_plugin, NULL) # TODO(yihuazhang): Expose min_security_level via the Python API so that
# applications can decide what minimum security level their plugins require.
return grpc_metadata_credentials_create_from_plugin(c_metadata_plugin, GRPC_PRIVACY_AND_INTEGRITY, NULL)
cdef grpc_call_credentials *_composition(call_credentialses): cdef grpc_call_credentials *_composition(call_credentialses):

@ -433,6 +433,13 @@ cdef extern from "grpc/grpc_security.h":
GRPC_SSL_REQUEST_AND_REQUIRE_CLIENT_CERTIFICATE_BUT_DONT_VERIFY GRPC_SSL_REQUEST_AND_REQUIRE_CLIENT_CERTIFICATE_BUT_DONT_VERIFY
GRPC_SSL_REQUEST_AND_REQUIRE_CLIENT_CERTIFICATE_AND_VERIFY GRPC_SSL_REQUEST_AND_REQUIRE_CLIENT_CERTIFICATE_AND_VERIFY
ctypedef enum grpc_security_level:
GRPC_SECURITY_MIN
GRPC_SECURITY_NONE = GRPC_SECURITY_MIN
GRPC_INTEGRITY_ONLY
GRPC_PRIVACY_AND_INTEGRITY
GRPC_SECURITY_MAX = GRPC_PRIVACY_AND_INTEGRITY
ctypedef enum grpc_ssl_certificate_config_reload_status: ctypedef enum grpc_ssl_certificate_config_reload_status:
GRPC_SSL_CERTIFICATE_CONFIG_RELOAD_UNCHANGED GRPC_SSL_CERTIFICATE_CONFIG_RELOAD_UNCHANGED
GRPC_SSL_CERTIFICATE_CONFIG_RELOAD_NEW GRPC_SSL_CERTIFICATE_CONFIG_RELOAD_NEW
@ -562,7 +569,7 @@ cdef extern from "grpc/grpc_security.h":
const char *type const char *type
grpc_call_credentials *grpc_metadata_credentials_create_from_plugin( grpc_call_credentials *grpc_metadata_credentials_create_from_plugin(
grpc_metadata_credentials_plugin plugin, void *reserved) nogil grpc_metadata_credentials_plugin plugin, grpc_security_level min_security_level, void *reserved) nogil
ctypedef struct grpc_auth_property_iterator: ctypedef struct grpc_auth_property_iterator:
pass pass

@ -103,11 +103,11 @@ class AuthContextTest(unittest.TestCase):
auth_data = pickle.loads(response) auth_data = pickle.loads(response)
self.assertIsNone(auth_data[_ID]) self.assertIsNone(auth_data[_ID])
self.assertIsNone(auth_data[_ID_KEY]) self.assertIsNone(auth_data[_ID_KEY])
self.assertDictEqual( self.assertDictEqual({
{ 'security_level': [b'TSI_PRIVACY_AND_INTEGRITY'],
'transport_security_type': [b'ssl'], 'transport_security_type': [b'ssl'],
'ssl_session_reused': [b'false'], 'ssl_session_reused': [b'false'],
}, auth_data[_AUTH_CTX]) }, auth_data[_AUTH_CTX])
def testSecureClientCert(self): def testSecureClientCert(self):
handler = grpc.method_handlers_generic_handler('test', { handler = grpc.method_handlers_generic_handler('test', {

@ -229,7 +229,10 @@ static VALUE grpc_rb_call_credentials_init(VALUE self, VALUE proc) {
plugin.state = (void*)proc; plugin.state = (void*)proc;
plugin.type = ""; plugin.type = "";
creds = grpc_metadata_credentials_create_from_plugin(plugin, NULL); // TODO(yihuazhang): Expose min_security_level via the Ruby API so that
// applications can decide what minimum security level their plugins require.
creds = grpc_metadata_credentials_create_from_plugin(
plugin, GRPC_PRIVACY_AND_INTEGRITY, NULL);
if (creds == NULL) { if (creds == NULL) {
rb_raise(rb_eRuntimeError, "could not create a credentials, not sure why"); rb_raise(rb_eRuntimeError, "could not create a credentials, not sure why");
return Qnil; return Qnil;

@ -380,7 +380,7 @@ extern grpc_google_iam_credentials_create_type grpc_google_iam_credentials_creat
typedef grpc_call_credentials*(*grpc_sts_credentials_create_type)(const grpc_sts_credentials_options* options, void* reserved); typedef grpc_call_credentials*(*grpc_sts_credentials_create_type)(const grpc_sts_credentials_options* options, void* reserved);
extern grpc_sts_credentials_create_type grpc_sts_credentials_create_import; extern grpc_sts_credentials_create_type grpc_sts_credentials_create_import;
#define grpc_sts_credentials_create grpc_sts_credentials_create_import #define grpc_sts_credentials_create grpc_sts_credentials_create_import
typedef grpc_call_credentials*(*grpc_metadata_credentials_create_from_plugin_type)(grpc_metadata_credentials_plugin plugin, void* reserved); typedef grpc_call_credentials*(*grpc_metadata_credentials_create_from_plugin_type)(grpc_metadata_credentials_plugin plugin, grpc_security_level min_security_level, void* reserved);
extern grpc_metadata_credentials_create_from_plugin_type grpc_metadata_credentials_create_from_plugin_import; extern grpc_metadata_credentials_create_from_plugin_type grpc_metadata_credentials_create_from_plugin_import;
#define grpc_metadata_credentials_create_from_plugin grpc_metadata_credentials_create_from_plugin_import #define grpc_metadata_credentials_create_from_plugin grpc_metadata_credentials_create_from_plugin_import
typedef grpc_channel*(*grpc_secure_channel_create_type)(grpc_channel_credentials* creds, const char* target, const grpc_channel_args* args, void* reserved); typedef grpc_channel*(*grpc_secure_channel_create_type)(grpc_channel_credentials* creds, const char* target, const grpc_channel_args* args, void* reserved);

@ -34,6 +34,7 @@ typedef struct grpc_end2end_test_config grpc_end2end_test_config;
#define FEATURE_MASK_DOES_NOT_SUPPORT_RESOURCE_QUOTA_SERVER 64 #define FEATURE_MASK_DOES_NOT_SUPPORT_RESOURCE_QUOTA_SERVER 64
#define FEATURE_MASK_DOES_NOT_SUPPORT_NETWORK_STATUS_CHANGE 128 #define FEATURE_MASK_DOES_NOT_SUPPORT_NETWORK_STATUS_CHANGE 128
#define FEATURE_MASK_SUPPORTS_WORKAROUNDS 256 #define FEATURE_MASK_SUPPORTS_WORKAROUNDS 256
#define FEATURE_MASK_DOES_NOT_SUPPORT_SEND_CALL_CREDENTIALS 512
#define FAIL_AUTH_CHECK_SERVER_ARG_NAME "fail_auth_check" #define FAIL_AUTH_CHECK_SERVER_ARG_NAME "fail_auth_check"

@ -130,7 +130,8 @@ static grpc_end2end_test_config configs[] = {
{"chttp2/fake_secure_fullstack", {"chttp2/fake_secure_fullstack",
FEATURE_MASK_SUPPORTS_DELAYED_CONNECTION | FEATURE_MASK_SUPPORTS_DELAYED_CONNECTION |
FEATURE_MASK_SUPPORTS_CLIENT_CHANNEL | FEATURE_MASK_SUPPORTS_CLIENT_CHANNEL |
FEATURE_MASK_SUPPORTS_AUTHORITY_HEADER, FEATURE_MASK_SUPPORTS_AUTHORITY_HEADER |
FEATURE_MASK_DOES_NOT_SUPPORT_SEND_CALL_CREDENTIALS,
nullptr, chttp2_create_fixture_secure_fullstack, nullptr, chttp2_create_fixture_secure_fullstack,
chttp2_init_client_fake_secure_fullstack, chttp2_init_client_fake_secure_fullstack,
chttp2_init_server_fake_secure_fullstack, chttp2_init_server_fake_secure_fullstack,

@ -36,7 +36,7 @@ static const char iam_selector[] = "selector";
static const char overridden_iam_token[] = "overridden_token"; static const char overridden_iam_token[] = "overridden_token";
static const char overridden_iam_selector[] = "overridden_selector"; static const char overridden_iam_selector[] = "overridden_selector";
typedef enum { NONE, OVERRIDE, DESTROY } override_mode; typedef enum { NONE, OVERRIDE, DESTROY, FAIL } override_mode;
static void* tag(intptr_t t) { return (void*)t; } static void* tag(intptr_t t) { return (void*)t; }
@ -174,6 +174,7 @@ static void request_response_with_payload_and_call_creds(
GPR_ASSERT(grpc_call_set_credentials(c, creds) == GRPC_CALL_OK); GPR_ASSERT(grpc_call_set_credentials(c, creds) == GRPC_CALL_OK);
break; break;
case DESTROY: case DESTROY:
case FAIL:
GPR_ASSERT(grpc_call_set_credentials(c, nullptr) == GRPC_CALL_OK); GPR_ASSERT(grpc_call_set_credentials(c, nullptr) == GRPC_CALL_OK);
break; break;
} }
@ -312,6 +313,7 @@ static void request_response_with_payload_and_call_creds(
overridden_iam_selector)); overridden_iam_selector));
break; break;
case DESTROY: case DESTROY:
case FAIL:
GPR_ASSERT(!contains_metadata(&request_metadata_recv, GPR_ASSERT(!contains_metadata(&request_metadata_recv,
GRPC_IAM_AUTHORIZATION_TOKEN_METADATA_KEY, GRPC_IAM_AUTHORIZATION_TOKEN_METADATA_KEY,
iam_token)); iam_token));
@ -367,6 +369,13 @@ static void test_request_response_with_payload_and_deleted_call_creds(
DESTROY); DESTROY);
} }
static void test_request_response_with_payload_fail_to_send_call_creds(
grpc_end2end_test_config config) {
request_response_with_payload_and_call_creds(
"test_request_response_with_payload_fail_to_send_call_creds", config,
FAIL);
}
static void test_request_with_server_rejecting_client_creds( static void test_request_with_server_rejecting_client_creds(
grpc_end2end_test_config config) { grpc_end2end_test_config config) {
grpc_op ops[6]; grpc_op ops[6];
@ -472,6 +481,10 @@ void call_creds(grpc_end2end_test_config config) {
test_request_response_with_payload_and_deleted_call_creds(config); test_request_response_with_payload_and_deleted_call_creds(config);
test_request_with_server_rejecting_client_creds(config); test_request_with_server_rejecting_client_creds(config);
} }
if (config.feature_mask &
FEATURE_MASK_DOES_NOT_SUPPORT_SEND_CALL_CREDENTIALS) {
test_request_response_with_payload_fail_to_send_call_creds(config);
}
} }
void call_creds_pre_init(void) {} void call_creds_pre_init(void) {}

@ -74,6 +74,39 @@ static void test_missing_rpc_protocol_versions_property_failure() {
tsi_peer_destruct(&peer); tsi_peer_destruct(&peer);
} }
static void test_missing_security_level_property_failure() {
tsi_peer peer;
GPR_ASSERT(tsi_construct_peer(kTsiAltsNumOfPeerProperties, &peer) == TSI_OK);
GPR_ASSERT(tsi_construct_string_peer_property_from_cstring(
TSI_CERTIFICATE_TYPE_PEER_PROPERTY, TSI_ALTS_CERTIFICATE_TYPE,
&peer.properties[0]) == TSI_OK);
GPR_ASSERT(tsi_construct_string_peer_property_from_cstring(
TSI_ALTS_SERVICE_ACCOUNT_PEER_PROPERTY, "alice",
&peer.properties[1]) == TSI_OK);
grpc_gcp_rpc_protocol_versions peer_versions;
grpc_gcp_rpc_protocol_versions_set_max(&peer_versions,
GRPC_PROTOCOL_VERSION_MAX_MAJOR,
GRPC_PROTOCOL_VERSION_MAX_MINOR);
grpc_gcp_rpc_protocol_versions_set_min(&peer_versions,
GRPC_PROTOCOL_VERSION_MIN_MAJOR,
GRPC_PROTOCOL_VERSION_MIN_MINOR);
grpc_slice serialized_peer_versions;
GPR_ASSERT(grpc_gcp_rpc_protocol_versions_encode(&peer_versions,
&serialized_peer_versions));
GPR_ASSERT(tsi_construct_string_peer_property(
TSI_ALTS_RPC_VERSIONS,
reinterpret_cast<char*>(
GRPC_SLICE_START_PTR(serialized_peer_versions)),
GRPC_SLICE_LENGTH(serialized_peer_versions),
&peer.properties[2]) == TSI_OK);
grpc_core::RefCountedPtr<grpc_auth_context> ctx =
grpc_alts_auth_context_from_tsi_peer(&peer);
GPR_ASSERT(ctx == nullptr);
grpc_slice_unref(serialized_peer_versions);
tsi_peer_destruct(&peer);
}
static void test_unknown_peer_property_failure() { static void test_unknown_peer_property_failure() {
tsi_peer peer; tsi_peer peer;
GPR_ASSERT(tsi_construct_peer(kTsiAltsNumOfPeerProperties, &peer) == TSI_OK); GPR_ASSERT(tsi_construct_peer(kTsiAltsNumOfPeerProperties, &peer) == TSI_OK);
@ -135,6 +168,10 @@ static void test_alts_peer_to_auth_context_success() {
GRPC_SLICE_START_PTR(serialized_peer_versions)), GRPC_SLICE_START_PTR(serialized_peer_versions)),
GRPC_SLICE_LENGTH(serialized_peer_versions), GRPC_SLICE_LENGTH(serialized_peer_versions),
&peer.properties[2]) == TSI_OK); &peer.properties[2]) == TSI_OK);
GPR_ASSERT(tsi_construct_string_peer_property_from_cstring(
TSI_SECURITY_LEVEL_PEER_PROPERTY,
tsi_security_level_to_string(TSI_PRIVACY_AND_INTEGRITY),
&peer.properties[3]) == TSI_OK);
char test_ctx[] = "test serialized context"; char test_ctx[] = "test serialized context";
grpc_slice serialized_alts_ctx = grpc_slice_from_copied_string(test_ctx); grpc_slice serialized_alts_ctx = grpc_slice_from_copied_string(test_ctx);
GPR_ASSERT( GPR_ASSERT(
@ -142,7 +179,7 @@ static void test_alts_peer_to_auth_context_success() {
TSI_ALTS_CONTEXT, TSI_ALTS_CONTEXT,
reinterpret_cast<char*>(GRPC_SLICE_START_PTR(serialized_alts_ctx)), reinterpret_cast<char*>(GRPC_SLICE_START_PTR(serialized_alts_ctx)),
GRPC_SLICE_LENGTH(serialized_alts_ctx), GRPC_SLICE_LENGTH(serialized_alts_ctx),
&peer.properties[3]) == TSI_OK); &peer.properties[4]) == TSI_OK);
grpc_core::RefCountedPtr<grpc_auth_context> ctx = grpc_core::RefCountedPtr<grpc_auth_context> ctx =
grpc_alts_auth_context_from_tsi_peer(&peer); grpc_alts_auth_context_from_tsi_peer(&peer);
GPR_ASSERT(ctx != nullptr); GPR_ASSERT(ctx != nullptr);
@ -161,6 +198,7 @@ int main(int /*argc*/, char** /*argv*/) {
test_empty_peer_property_failure(); test_empty_peer_property_failure();
test_unknown_peer_property_failure(); test_unknown_peer_property_failure();
test_missing_rpc_protocol_versions_property_failure(); test_missing_rpc_protocol_versions_property_failure();
test_missing_security_level_property_failure();
test_alts_peer_to_auth_context_success(); test_alts_peer_to_auth_context_success();
return 0; return 0;

@ -404,6 +404,8 @@ static void test_google_iam_creds(void) {
grpc_call_credentials* creds = grpc_google_iam_credentials_create( grpc_call_credentials* creds = grpc_google_iam_credentials_create(
test_google_iam_authorization_token, test_google_iam_authority_selector, test_google_iam_authorization_token, test_google_iam_authority_selector,
nullptr); nullptr);
/* Check security level. */
GPR_ASSERT(creds->min_security_level() == GRPC_PRIVACY_AND_INTEGRITY);
grpc_auth_metadata_context auth_md_ctx = {test_service_url, test_method, grpc_auth_metadata_context auth_md_ctx = {test_service_url, test_method,
nullptr, nullptr}; nullptr, nullptr};
run_request_metadata_test(creds, auth_md_ctx, state); run_request_metadata_test(creds, auth_md_ctx, state);
@ -420,6 +422,8 @@ static void test_access_token_creds(void) {
grpc_auth_metadata_context auth_md_ctx = {test_service_url, test_method, grpc_auth_metadata_context auth_md_ctx = {test_service_url, test_method,
nullptr, nullptr}; nullptr, nullptr};
GPR_ASSERT(strcmp(creds->type(), GRPC_CALL_CREDENTIALS_TYPE_OAUTH2) == 0); GPR_ASSERT(strcmp(creds->type(), GRPC_CALL_CREDENTIALS_TYPE_OAUTH2) == 0);
/* Check security level. */
GPR_ASSERT(creds->min_security_level() == GRPC_PRIVACY_AND_INTEGRITY);
run_request_metadata_test(creds, auth_md_ctx, state); run_request_metadata_test(creds, auth_md_ctx, state);
creds->Unref(); creds->Unref();
} }
@ -474,12 +478,20 @@ static void test_oauth2_google_iam_composite_creds(void) {
nullptr, nullptr}; nullptr, nullptr};
grpc_call_credentials* oauth2_creds = grpc_md_only_test_credentials_create( grpc_call_credentials* oauth2_creds = grpc_md_only_test_credentials_create(
"authorization", test_oauth2_bearer_token, 0); "authorization", test_oauth2_bearer_token, 0);
/* Check security level of fake credentials. */
GPR_ASSERT(oauth2_creds->min_security_level() == GRPC_SECURITY_NONE);
grpc_call_credentials* google_iam_creds = grpc_google_iam_credentials_create( grpc_call_credentials* google_iam_creds = grpc_google_iam_credentials_create(
test_google_iam_authorization_token, test_google_iam_authority_selector, test_google_iam_authorization_token, test_google_iam_authority_selector,
nullptr); nullptr);
grpc_call_credentials* composite_creds = grpc_call_credentials* composite_creds =
grpc_composite_call_credentials_create(oauth2_creds, google_iam_creds, grpc_composite_call_credentials_create(oauth2_creds, google_iam_creds,
nullptr); nullptr);
/* Check security level of composite credentials. */
GPR_ASSERT(composite_creds->min_security_level() ==
GRPC_PRIVACY_AND_INTEGRITY);
oauth2_creds->Unref(); oauth2_creds->Unref();
google_iam_creds->Unref(); google_iam_creds->Unref();
GPR_ASSERT(strcmp(composite_creds->type(), GPR_ASSERT(strcmp(composite_creds->type(),
@ -536,6 +548,7 @@ static void test_channel_oauth2_google_iam_composite_creds(void) {
grpc_call_credentials* google_iam_creds = grpc_google_iam_credentials_create( grpc_call_credentials* google_iam_creds = grpc_google_iam_credentials_create(
test_google_iam_authorization_token, test_google_iam_authority_selector, test_google_iam_authorization_token, test_google_iam_authority_selector,
nullptr); nullptr);
grpc_channel_credentials* channel_oauth2_iam_creds = grpc_channel_credentials* channel_oauth2_iam_creds =
grpc_composite_channel_credentials_create(channel_oauth2_creds, grpc_composite_channel_credentials_create(channel_oauth2_creds,
google_iam_creds, nullptr); google_iam_creds, nullptr);
@ -604,6 +617,8 @@ static void test_compute_engine_creds_success() {
grpc_google_compute_engine_credentials_create(nullptr); grpc_google_compute_engine_credentials_create(nullptr);
grpc_auth_metadata_context auth_md_ctx = {test_service_url, test_method, grpc_auth_metadata_context auth_md_ctx = {test_service_url, test_method,
nullptr, nullptr}; nullptr, nullptr};
/* Check security level. */
GPR_ASSERT(creds->min_security_level() == GRPC_PRIVACY_AND_INTEGRITY);
/* First request: http get should be called. */ /* First request: http get should be called. */
request_metadata_state* state = request_metadata_state* state =
@ -695,6 +710,9 @@ static void test_refresh_token_creds_success(void) {
grpc_call_credentials* creds = grpc_google_refresh_token_credentials_create( grpc_call_credentials* creds = grpc_google_refresh_token_credentials_create(
test_refresh_token_str, nullptr); test_refresh_token_str, nullptr);
/* Check security level. */
GPR_ASSERT(creds->min_security_level() == GRPC_PRIVACY_AND_INTEGRITY);
/* First request: http put should be called. */ /* First request: http put should be called. */
request_metadata_state* state = request_metadata_state* state =
make_request_metadata_state(GRPC_ERROR_NONE, emd, GPR_ARRAY_SIZE(emd)); make_request_metadata_state(GRPC_ERROR_NONE, emd, GPR_ARRAY_SIZE(emd));
@ -924,6 +942,9 @@ static void test_sts_creds_success(void) {
grpc_call_credentials* creds = grpc_call_credentials* creds =
grpc_sts_credentials_create(&valid_options, nullptr); grpc_sts_credentials_create(&valid_options, nullptr);
/* Check security level. */
GPR_ASSERT(creds->min_security_level() == GRPC_PRIVACY_AND_INTEGRITY);
/* First request: http put should be called. */ /* First request: http put should be called. */
request_metadata_state* state = request_metadata_state* state =
make_request_metadata_state(GRPC_ERROR_NONE, emd, GPR_ARRAY_SIZE(emd)); make_request_metadata_state(GRPC_ERROR_NONE, emd, GPR_ARRAY_SIZE(emd));
@ -1067,6 +1088,8 @@ static void test_jwt_creds_lifetime(void) {
json_key_string, grpc_max_auth_token_lifetime(), nullptr); json_key_string, grpc_max_auth_token_lifetime(), nullptr);
GPR_ASSERT(gpr_time_cmp(creds_as_jwt(jwt_creds)->jwt_lifetime(), GPR_ASSERT(gpr_time_cmp(creds_as_jwt(jwt_creds)->jwt_lifetime(),
grpc_max_auth_token_lifetime()) == 0); grpc_max_auth_token_lifetime()) == 0);
/* Check security level. */
GPR_ASSERT(jwt_creds->min_security_level() == GRPC_PRIVACY_AND_INTEGRITY);
grpc_call_credentials_release(jwt_creds); grpc_call_credentials_release(jwt_creds);
// Shorter lifetime. // Shorter lifetime.
@ -1408,8 +1431,10 @@ static void test_metadata_plugin_success(void) {
plugin.get_metadata = plugin_get_metadata_success; plugin.get_metadata = plugin_get_metadata_success;
plugin.destroy = plugin_destroy; plugin.destroy = plugin_destroy;
grpc_call_credentials* creds = grpc_call_credentials* creds = grpc_metadata_credentials_create_from_plugin(
grpc_metadata_credentials_create_from_plugin(plugin, nullptr); plugin, GRPC_PRIVACY_AND_INTEGRITY, nullptr);
/* Check security level. */
GPR_ASSERT(creds->min_security_level() == GRPC_PRIVACY_AND_INTEGRITY);
GPR_ASSERT(state == PLUGIN_INITIAL_STATE); GPR_ASSERT(state == PLUGIN_INITIAL_STATE);
run_request_metadata_test(creds, auth_md_ctx, md_state); run_request_metadata_test(creds, auth_md_ctx, md_state);
GPR_ASSERT(state == PLUGIN_GET_METADATA_CALLED_STATE); GPR_ASSERT(state == PLUGIN_GET_METADATA_CALLED_STATE);
@ -1436,8 +1461,8 @@ static void test_metadata_plugin_failure(void) {
plugin.get_metadata = plugin_get_metadata_failure; plugin.get_metadata = plugin_get_metadata_failure;
plugin.destroy = plugin_destroy; plugin.destroy = plugin_destroy;
grpc_call_credentials* creds = grpc_call_credentials* creds = grpc_metadata_credentials_create_from_plugin(
grpc_metadata_credentials_create_from_plugin(plugin, nullptr); plugin, GRPC_PRIVACY_AND_INTEGRITY, nullptr);
GPR_ASSERT(state == PLUGIN_INITIAL_STATE); GPR_ASSERT(state == PLUGIN_INITIAL_STATE);
run_request_metadata_test(creds, auth_md_ctx, md_state); run_request_metadata_test(creds, auth_md_ctx, md_state);
GPR_ASSERT(state == PLUGIN_GET_METADATA_CALLED_STATE); GPR_ASSERT(state == PLUGIN_GET_METADATA_CALLED_STATE);

@ -84,13 +84,38 @@ static int check_ssl_peer_equivalence(const tsi_peer* original,
return 1; return 1;
} }
static void test_check_security_level() {
GPR_ASSERT(grpc_check_security_level(GRPC_PRIVACY_AND_INTEGRITY,
GRPC_PRIVACY_AND_INTEGRITY) == true);
GPR_ASSERT(grpc_check_security_level(GRPC_PRIVACY_AND_INTEGRITY,
GRPC_INTEGRITY_ONLY) == true);
GPR_ASSERT(grpc_check_security_level(GRPC_PRIVACY_AND_INTEGRITY,
GRPC_SECURITY_NONE) == true);
GPR_ASSERT(grpc_check_security_level(GRPC_INTEGRITY_ONLY,
GRPC_PRIVACY_AND_INTEGRITY) == false);
GPR_ASSERT(grpc_check_security_level(GRPC_INTEGRITY_ONLY,
GRPC_INTEGRITY_ONLY) == true);
GPR_ASSERT(grpc_check_security_level(GRPC_INTEGRITY_ONLY,
GRPC_SECURITY_NONE) == true);
GPR_ASSERT(grpc_check_security_level(GRPC_SECURITY_NONE,
GRPC_PRIVACY_AND_INTEGRITY) == false);
GPR_ASSERT(grpc_check_security_level(GRPC_SECURITY_NONE,
GRPC_INTEGRITY_ONLY) == false);
GPR_ASSERT(grpc_check_security_level(GRPC_SECURITY_NONE,
GRPC_SECURITY_NONE) == true);
}
static void test_unauthenticated_ssl_peer(void) { static void test_unauthenticated_ssl_peer(void) {
tsi_peer peer; tsi_peer peer;
tsi_peer rpeer; tsi_peer rpeer;
GPR_ASSERT(tsi_construct_peer(1, &peer) == TSI_OK); GPR_ASSERT(tsi_construct_peer(2, &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(
TSI_SECURITY_LEVEL_PEER_PROPERTY,
tsi_security_level_to_string(TSI_PRIVACY_AND_INTEGRITY),
&peer.properties[1]) == TSI_OK);
grpc_core::RefCountedPtr<grpc_auth_context> ctx = grpc_core::RefCountedPtr<grpc_auth_context> ctx =
grpc_ssl_peer_to_auth_context(&peer, GRPC_SSL_TRANSPORT_SECURITY_TYPE); grpc_ssl_peer_to_auth_context(&peer, GRPC_SSL_TRANSPORT_SECURITY_TYPE);
GPR_ASSERT(ctx != nullptr); GPR_ASSERT(ctx != nullptr);
@ -181,7 +206,7 @@ static void test_cn_only_ssl_peer_to_auth_context(void) {
tsi_peer rpeer; tsi_peer rpeer;
const char* expected_cn = "cn1"; const char* expected_cn = "cn1";
const char* expected_pem_cert = "pem_cert1"; const char* expected_pem_cert = "pem_cert1";
GPR_ASSERT(tsi_construct_peer(3, &peer) == TSI_OK); 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);
@ -191,6 +216,11 @@ static void test_cn_only_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_PEM_CERT_PROPERTY, expected_pem_cert, TSI_X509_PEM_CERT_PROPERTY, expected_pem_cert,
&peer.properties[2]) == TSI_OK); &peer.properties[2]) == TSI_OK);
GPR_ASSERT(tsi_construct_string_peer_property_from_cstring(
TSI_SECURITY_LEVEL_PEER_PROPERTY,
tsi_security_level_to_string(TSI_PRIVACY_AND_INTEGRITY),
&peer.properties[3]) == TSI_OK);
grpc_core::RefCountedPtr<grpc_auth_context> ctx = grpc_core::RefCountedPtr<grpc_auth_context> ctx =
grpc_ssl_peer_to_auth_context(&peer, GRPC_SSL_TRANSPORT_SECURITY_TYPE); grpc_ssl_peer_to_auth_context(&peer, GRPC_SSL_TRANSPORT_SECURITY_TYPE);
GPR_ASSERT(ctx != nullptr); GPR_ASSERT(ctx != nullptr);
@ -215,7 +245,7 @@ static void test_cn_and_one_san_ssl_peer_to_auth_context(void) {
const char* expected_cn = "cn1"; const char* expected_cn = "cn1";
const char* expected_san = "san1"; const char* expected_san = "san1";
const char* expected_pem_cert = "pem_cert1"; const char* expected_pem_cert = "pem_cert1";
GPR_ASSERT(tsi_construct_peer(4, &peer) == TSI_OK); GPR_ASSERT(tsi_construct_peer(5, &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);
@ -228,7 +258,10 @@ 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_PEM_CERT_PROPERTY, expected_pem_cert, TSI_X509_PEM_CERT_PROPERTY, expected_pem_cert,
&peer.properties[3]) == TSI_OK); &peer.properties[3]) == TSI_OK);
GPR_ASSERT(tsi_construct_string_peer_property_from_cstring(
TSI_SECURITY_LEVEL_PEER_PROPERTY,
tsi_security_level_to_string(TSI_PRIVACY_AND_INTEGRITY),
&peer.properties[4]) == TSI_OK);
grpc_core::RefCountedPtr<grpc_auth_context> ctx = grpc_core::RefCountedPtr<grpc_auth_context> ctx =
grpc_ssl_peer_to_auth_context(&peer, GRPC_SSL_TRANSPORT_SECURITY_TYPE); grpc_ssl_peer_to_auth_context(&peer, GRPC_SSL_TRANSPORT_SECURITY_TYPE);
GPR_ASSERT(ctx != nullptr); GPR_ASSERT(ctx != nullptr);
@ -254,7 +287,7 @@ static void test_cn_and_multiple_sans_ssl_peer_to_auth_context(void) {
const char* expected_sans[] = {"san1", "san2", "san3"}; const char* expected_sans[] = {"san1", "san2", "san3"};
const char* expected_pem_cert = "pem_cert1"; const char* expected_pem_cert = "pem_cert1";
size_t i; size_t i;
GPR_ASSERT(tsi_construct_peer(3 + GPR_ARRAY_SIZE(expected_sans), &peer) == GPR_ASSERT(tsi_construct_peer(4 + 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,
@ -265,10 +298,14 @@ 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_PEM_CERT_PROPERTY, expected_pem_cert, TSI_X509_PEM_CERT_PROPERTY, expected_pem_cert,
&peer.properties[2]) == TSI_OK); &peer.properties[2]) == TSI_OK);
GPR_ASSERT(tsi_construct_string_peer_property_from_cstring(
TSI_SECURITY_LEVEL_PEER_PROPERTY,
tsi_security_level_to_string(TSI_PRIVACY_AND_INTEGRITY),
&peer.properties[3]) == 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[3 + i]) == TSI_OK); expected_sans[i], &peer.properties[4 + i]) == TSI_OK);
} }
grpc_core::RefCountedPtr<grpc_auth_context> ctx = grpc_core::RefCountedPtr<grpc_auth_context> ctx =
grpc_ssl_peer_to_auth_context(&peer, GRPC_SSL_TRANSPORT_SECURITY_TYPE); grpc_ssl_peer_to_auth_context(&peer, GRPC_SSL_TRANSPORT_SECURITY_TYPE);
@ -296,7 +333,7 @@ static void test_cn_and_multiple_sans_and_others_ssl_peer_to_auth_context(
const char* expected_pem_cert = "pem_cert1"; 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(5 + GPR_ARRAY_SIZE(expected_sans), &peer) == GPR_ASSERT(tsi_construct_peer(6 + 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,
@ -311,10 +348,14 @@ static void test_cn_and_multiple_sans_and_others_ssl_peer_to_auth_context(
GPR_ASSERT(tsi_construct_string_peer_property_from_cstring( GPR_ASSERT(tsi_construct_string_peer_property_from_cstring(
TSI_X509_PEM_CERT_PROPERTY, expected_pem_cert, TSI_X509_PEM_CERT_PROPERTY, expected_pem_cert,
&peer.properties[4]) == TSI_OK); &peer.properties[4]) == TSI_OK);
GPR_ASSERT(tsi_construct_string_peer_property_from_cstring(
TSI_SECURITY_LEVEL_PEER_PROPERTY,
tsi_security_level_to_string(TSI_PRIVACY_AND_INTEGRITY),
&peer.properties[5]) == 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[5 + i]) == TSI_OK); expected_sans[i], &peer.properties[6 + i]) == TSI_OK);
} }
grpc_core::RefCountedPtr<grpc_auth_context> ctx = grpc_core::RefCountedPtr<grpc_auth_context> ctx =
grpc_ssl_peer_to_auth_context(&peer, GRPC_SSL_TRANSPORT_SECURITY_TYPE); grpc_ssl_peer_to_auth_context(&peer, GRPC_SSL_TRANSPORT_SECURITY_TYPE);
@ -485,6 +526,7 @@ int main(int argc, char** argv) {
test_ipv6_address_san(); test_ipv6_address_san();
test_default_ssl_roots(); test_default_ssl_roots();
test_peer_alpn_check(); test_peer_alpn_check();
test_check_security_level();
grpc_shutdown(); grpc_shutdown();
return 0; return 0;
} }

@ -35,6 +35,7 @@
#define ALTS_TSI_HANDSHAKER_TEST_CONSUMED_BYTES "Hello " #define ALTS_TSI_HANDSHAKER_TEST_CONSUMED_BYTES "Hello "
#define ALTS_TSI_HANDSHAKER_TEST_REMAIN_BYTES "Google" #define ALTS_TSI_HANDSHAKER_TEST_REMAIN_BYTES "Google"
#define ALTS_TSI_HANDSHAKER_TEST_PEER_IDENTITY "chapi@service.google.com" #define ALTS_TSI_HANDSHAKER_TEST_PEER_IDENTITY "chapi@service.google.com"
#define ALTS_TSI_HANDSHAKER_TEST_SECURITY_LEVEL "TSI_PRIVACY_AND_INTEGRITY"
#define ALTS_TSI_HANDSHAKER_TEST_KEY_DATA \ #define ALTS_TSI_HANDSHAKER_TEST_KEY_DATA \
"ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKL" "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKL"
#define ALTS_TSI_HANDSHAKER_TEST_BUFFER_SIZE 100 #define ALTS_TSI_HANDSHAKER_TEST_BUFFER_SIZE 100
@ -309,6 +310,10 @@ static void on_client_next_success_cb(tsi_result status, void* user_data,
peer_account.size) == 0); peer_account.size) == 0);
GPR_ASSERT(memcmp(ALTS_TSI_HANDSHAKER_TEST_LOCAL_IDENTITY, local_account.data, GPR_ASSERT(memcmp(ALTS_TSI_HANDSHAKER_TEST_LOCAL_IDENTITY, local_account.data,
local_account.size) == 0); local_account.size) == 0);
/* Validate security level. */
GPR_ASSERT(memcmp(ALTS_TSI_HANDSHAKER_TEST_SECURITY_LEVEL,
peer.properties[4].value.data,
peer.properties[4].value.length) == 0);
tsi_peer_destruct(&peer); tsi_peer_destruct(&peer);
/* Validate unused bytes. */ /* Validate unused bytes. */
const unsigned char* bytes = nullptr; const unsigned char* bytes = nullptr;
@ -365,6 +370,11 @@ static void on_server_next_success_cb(tsi_result status, void* user_data,
peer_account.size) == 0); peer_account.size) == 0);
GPR_ASSERT(memcmp(ALTS_TSI_HANDSHAKER_TEST_LOCAL_IDENTITY, local_account.data, GPR_ASSERT(memcmp(ALTS_TSI_HANDSHAKER_TEST_LOCAL_IDENTITY, local_account.data,
local_account.size) == 0); local_account.size) == 0);
/* Check security level. */
GPR_ASSERT(memcmp(ALTS_TSI_HANDSHAKER_TEST_SECURITY_LEVEL,
peer.properties[4].value.data,
peer.properties[4].value.length) == 0);
tsi_peer_destruct(&peer); tsi_peer_destruct(&peer);
/* Validate unused bytes. */ /* Validate unused bytes. */
const unsigned char* bytes = nullptr; const unsigned char* bytes = nullptr;

@ -50,6 +50,11 @@ static void validate_handshaker_peers(tsi_handshaker_result* result) {
GPR_ASSERT(property != nullptr); GPR_ASSERT(property != nullptr);
GPR_ASSERT(memcmp(property->value.data, TSI_FAKE_CERTIFICATE_TYPE, GPR_ASSERT(memcmp(property->value.data, TSI_FAKE_CERTIFICATE_TYPE,
property->value.length) == 0); property->value.length) == 0);
property =
tsi_peer_get_property_by_name(&peer, TSI_SECURITY_LEVEL_PEER_PROPERTY);
GPR_ASSERT(property != nullptr);
GPR_ASSERT(memcmp(property->value.data, TSI_FAKE_SECURITY_LEVEL,
property->value.length) == 0);
tsi_peer_destruct(&peer); tsi_peer_destruct(&peer);
} }

@ -187,6 +187,15 @@ static void check_alpn(ssl_tsi_test_fixture* ssl_fixture,
} }
} }
static void check_security_level(const tsi_peer* peer) {
const tsi_peer_property* security_level =
tsi_peer_get_property_by_name(peer, TSI_SECURITY_LEVEL_PEER_PROPERTY);
GPR_ASSERT(security_level != nullptr);
const char* expected_match = "TSI_PRIVACY_AND_INTEGRITY";
GPR_ASSERT(memcmp(security_level->value.data, expected_match,
security_level->value.length) == 0);
}
static const tsi_peer_property* static const tsi_peer_property*
check_basic_authenticated_peer_and_get_common_name(const tsi_peer* peer) { check_basic_authenticated_peer_and_get_common_name(const tsi_peer* peer) {
const tsi_peer_property* cert_type_property = const tsi_peer_property* cert_type_property =
@ -271,7 +280,7 @@ static void check_client_peer(ssl_tsi_test_fixture* ssl_fixture,
ssl_alpn_lib* alpn_lib = ssl_fixture->alpn_lib; ssl_alpn_lib* alpn_lib = ssl_fixture->alpn_lib;
if (!ssl_fixture->force_client_auth) { if (!ssl_fixture->force_client_auth) {
GPR_ASSERT(peer->property_count == GPR_ASSERT(peer->property_count ==
(alpn_lib->alpn_mode == ALPN_CLIENT_SERVER_OK ? 2 : 1)); (alpn_lib->alpn_mode == ALPN_CLIENT_SERVER_OK ? 3 : 2));
} else { } else {
const tsi_peer_property* property = const tsi_peer_property* property =
check_basic_authenticated_peer_and_get_common_name(peer); check_basic_authenticated_peer_and_get_common_name(peer);
@ -297,6 +306,7 @@ static void ssl_test_check_handshaker_peers(tsi_test_fixture* fixture) {
ssl_fixture->base.client_result, &peer) == TSI_OK); ssl_fixture->base.client_result, &peer) == TSI_OK);
check_session_reusage(ssl_fixture, &peer); check_session_reusage(ssl_fixture, &peer);
check_alpn(ssl_fixture, &peer); check_alpn(ssl_fixture, &peer);
check_security_level(&peer);
if (ssl_fixture->server_name_indication != nullptr) { if (ssl_fixture->server_name_indication != nullptr) {
check_server1_peer(&peer); check_server1_peer(&peer);
} else { } else {
@ -310,6 +320,7 @@ static void ssl_test_check_handshaker_peers(tsi_test_fixture* fixture) {
ssl_fixture->base.server_result, &peer) == TSI_OK); ssl_fixture->base.server_result, &peer) == TSI_OK);
check_session_reusage(ssl_fixture, &peer); check_session_reusage(ssl_fixture, &peer);
check_alpn(ssl_fixture, &peer); check_alpn(ssl_fixture, &peer);
check_security_level(&peer);
check_client_peer(ssl_fixture, &peer); check_client_peer(ssl_fixture, &peer);
} else { } else {
GPR_ASSERT(ssl_fixture->base.server_result == nullptr); GPR_ASSERT(ssl_fixture->base.server_result == nullptr);
@ -825,7 +836,8 @@ void ssl_tsi_test_extract_x509_subject_names() {
tsi_peer peer; tsi_peer peer;
GPR_ASSERT(tsi_ssl_extract_x509_subject_names_from_pem_cert(cert, &peer) == GPR_ASSERT(tsi_ssl_extract_x509_subject_names_from_pem_cert(cert, &peer) ==
TSI_OK); TSI_OK);
// One for common name, one for certificate, and six for SAN fields. // One for common name, one for certificate, one for security level, and six
// for SAN fields.
size_t expected_property_count = 8; size_t expected_property_count = 8;
GPR_ASSERT(peer.property_count == expected_property_count); GPR_ASSERT(peer.property_count == expected_property_count);
// Check common name // Check common name

Loading…
Cancel
Save