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.
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);
/** 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
removed after all of its call sites are migrated to
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
of the server root certificates. If this parameter is NULL, 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);
/* 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
of the server root certificates. If this parameter is NULL, 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. */
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(
grpc_channel_credentials* channel_creds, grpc_call_credentials* call_creds,
void* reserved);
@ -431,9 +435,11 @@ typedef struct {
const char* type;
} 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(
grpc_metadata_credentials_plugin plugin, void* reserved);
grpc_metadata_credentials_plugin plugin,
grpc_security_level min_security_level, void* reserved);
/** --- Secure channel creation. --- */
@ -653,8 +659,9 @@ GRPCAPI void grpc_alts_credentials_options_destroy(
grpc_alts_credentials_options* options);
/**
* This method creates an ALTS channel credential object. It is used for
* experimental purpose for now and subject to change.
* This method creates an ALTS channel credential object. The security
* 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.
*
@ -677,8 +684,10 @@ GRPCAPI grpc_server_credentials* grpc_alts_server_credentials_create(
/** --- Local channel/server credentials --- **/
/**
* This method creates a local channel credential object. It is used for
* experimental purpose for now and subject to change.
* This method creates a local channel credential object. The security level
* 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
*
@ -940,7 +949,8 @@ grpc_tls_server_authorization_check_config_create(
/**
* 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.
*

@ -30,6 +30,7 @@ extern "C" {
#define GRPC_X509_SAN_PROPERTY_NAME "x509_subject_alternative_name"
#define GRPC_X509_PEM_CERT_PROPERTY_NAME "x509_pem_cert"
#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
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_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 {
GRPC_SECURITY_MIN,
GRPC_SECURITY_NONE = GRPC_SECURITY_MIN,

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

@ -151,6 +151,13 @@ grpc_composite_call_credentials::grpc_composite_call_credentials(
inner_.reserve(size);
push_to_inner(std::move(creds1), creds1_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>

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

@ -225,7 +225,11 @@ void grpc_credentials_mdelem_array_destroy(grpc_credentials_mdelem_array* list);
struct grpc_call_credentials
: public grpc_core::RefCounted<grpc_call_credentials> {
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;
// 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(
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_; }
private:
const char* type_;
const grpc_security_level min_security_level_;
};
/* 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:
grpc_md_only_test_credentials(const char* md_key, const char* md_value,
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),
grpc_slice_from_copied_string(md_value))),
is_async_(is_async) {}

@ -240,15 +240,17 @@ void grpc_plugin_credentials::cancel_get_request_metadata(
}
grpc_plugin_credentials::grpc_plugin_credentials(
grpc_metadata_credentials_plugin plugin)
: grpc_call_credentials(plugin.type), plugin_(plugin) {
grpc_metadata_credentials_plugin plugin,
grpc_security_level min_security_level)
: grpc_call_credentials(plugin.type, min_security_level), plugin_(plugin) {
gpr_mu_init(&mu_);
}
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,
(reserved));
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;
};
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;
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.");
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. */
const tsi_peer_property* rpc_versions_prop =
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.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())) {
gpr_log(GPR_ERROR, "Invalid unauthenticated peer.");

@ -219,9 +219,9 @@ static void fake_check_peer(
const char* prop_name;
grpc_error* error = GRPC_ERROR_NONE;
*auth_context = nullptr;
if (peer.property_count != 1) {
if (peer.property_count != 2) {
error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"Fake peers should only have 1 property.");
"Fake peers should only have 2 properties.");
goto end;
}
prop_name = peer.properties[0].name;
@ -240,10 +240,30 @@ static void fake_check_peer(
"Invalid value for cert type property.");
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);
grpc_auth_context_add_cstring_property(
auth_context->get(), GRPC_TRANSPORT_SECURITY_TYPE_PROPERTY_NAME,
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:
grpc_core::ExecCtx::Run(DEBUG_LOCATION, on_peer_checked, error);
tsi_peer_destruct(&peer);

@ -46,7 +46,8 @@
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. */
grpc_core::RefCountedPtr<grpc_auth_context> ctx =
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);
GPR_ASSERT(grpc_auth_context_set_peer_identity_property_name(
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;
}
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_core::RefCountedPtr<grpc_auth_context>* auth_context,
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);
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
* {client, server}_auth_filter that verifies if the peer's auth context is
* obtained during handshakes. The auth context is only checked for its
* 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
: GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"Could not create local auth context");

@ -84,6 +84,30 @@ const char* grpc_get_ssl_cipher_suites(void) {
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
grpc_get_tsi_client_certificate_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_SSL_SESSION_REUSED_PROPERTY,
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) {
@ -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) {
add_shallow_auth_property_to_peer(&peer, prop,
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_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. */
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();
}
/* 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(
chand->security_connector->url_scheme(), calld->host, calld->method,
chand->auth_context.get(), &calld->auth_md_context);

@ -86,7 +86,7 @@ static tsi_result handshaker_result_extract_peer(
alts_tsi_handshaker_result* result =
reinterpret_cast<alts_tsi_handshaker_result*>(
const_cast<tsi_handshaker_result*>(self));
GPR_ASSERT(kTsiAltsNumOfPeerProperties == 4);
GPR_ASSERT(kTsiAltsNumOfPeerProperties == 5);
tsi_result ok = tsi_construct_peer(kTsiAltsNumOfPeerProperties, peer);
int index = 0;
if (ok != TSI_OK) {
@ -131,6 +131,16 @@ static tsi_result handshaker_result_extract_peer(
tsi_peer_destruct(peer);
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);
return ok;
}

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

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

@ -25,6 +25,8 @@
/* Value for the TSI_CERTIFICATE_TYPE_PEER_PROPERTY property for FAKE certs. */
#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.

@ -1049,7 +1049,7 @@ static tsi_result ssl_handshaker_result_extract_peer(
}
// 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++;
tsi_peer_property* new_properties = static_cast<tsi_peer_property*>(
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;
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";
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. ---
Calls specific implementation after state/input validation. */

@ -46,6 +46,14 @@ typedef enum {
TSI_HANDSHAKE_SHUTDOWN = 14,
} 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 {
// Default option
TSI_DONT_REQUEST_CLIENT_CERTIFICATE,
@ -56,6 +64,7 @@ typedef enum {
} tsi_client_certificate_request_type;
const char* tsi_result_to_string(tsi_result result);
const char* tsi_security_level_to_string(tsi_security_level security_level);
/* --- tsi tracing --- */
@ -185,6 +194,9 @@ void tsi_frame_protector_destroy(tsi_frame_protector* self);
/* This property is of type TSI_PEER_PROPERTY_STRING. */
#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.
The length field gives the length of the string. */
typedef struct tsi_peer_property {

@ -256,6 +256,20 @@ std::shared_ptr<CallCredentials> StsCredentials(
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
std::shared_ptr<ChannelCredentials> AltsCredentials(
const AltsCredentialsOptions& options) {
@ -374,8 +388,8 @@ std::shared_ptr<CallCredentials> MetadataCredentialsFromPlugin(
grpc_metadata_credentials_plugin c_plugin = {
grpc::MetadataCredentialsPluginWrapper::GetMetadata,
grpc::MetadataCredentialsPluginWrapper::Destroy, wrapper, type};
return WrapCallCredentials(
grpc_metadata_credentials_create_from_plugin(c_plugin, nullptr));
return WrapCallCredentials(grpc_metadata_credentials_create_from_plugin(
c_plugin, GRPC_PRIVACY_AND_INTEGRITY, nullptr));
}
} // namespace grpc_impl

@ -1136,7 +1136,11 @@ grpcsharp_metadata_credentials_create_from_plugin(void* callback_tag) {
plugin.destroy = grpcsharp_metadata_credentials_destroy_handler;
plugin.state = callback_tag;
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 */

@ -126,9 +126,10 @@ PHP_METHOD(CallCredentials, createFromPlugin) {
plugin.destroy = plugin_destroy_state;
plugin.state = (void *)state;
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_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);
RETURN_DESTROY_ZVAL(creds_object);
}

@ -76,7 +76,9 @@ cdef class MetadataPluginCallCredentials(CallCredentials):
c_metadata_plugin.type = self._name
cpython.Py_INCREF(self._metadata_plugin)
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):

@ -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_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:
GRPC_SSL_CERTIFICATE_CONFIG_RELOAD_UNCHANGED
GRPC_SSL_CERTIFICATE_CONFIG_RELOAD_NEW
@ -562,7 +569,7 @@ cdef extern from "grpc/grpc_security.h":
const char *type
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:
pass

@ -103,11 +103,11 @@ class AuthContextTest(unittest.TestCase):
auth_data = pickle.loads(response)
self.assertIsNone(auth_data[_ID])
self.assertIsNone(auth_data[_ID_KEY])
self.assertDictEqual(
{
'transport_security_type': [b'ssl'],
'ssl_session_reused': [b'false'],
}, auth_data[_AUTH_CTX])
self.assertDictEqual({
'security_level': [b'TSI_PRIVACY_AND_INTEGRITY'],
'transport_security_type': [b'ssl'],
'ssl_session_reused': [b'false'],
}, auth_data[_AUTH_CTX])
def testSecureClientCert(self):
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.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) {
rb_raise(rb_eRuntimeError, "could not create a credentials, not sure why");
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);
extern grpc_sts_credentials_create_type 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;
#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);

@ -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_NETWORK_STATUS_CHANGE 128
#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"

@ -130,7 +130,8 @@ static grpc_end2end_test_config configs[] = {
{"chttp2/fake_secure_fullstack",
FEATURE_MASK_SUPPORTS_DELAYED_CONNECTION |
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,
chttp2_init_client_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_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; }
@ -174,6 +174,7 @@ static void request_response_with_payload_and_call_creds(
GPR_ASSERT(grpc_call_set_credentials(c, creds) == GRPC_CALL_OK);
break;
case DESTROY:
case FAIL:
GPR_ASSERT(grpc_call_set_credentials(c, nullptr) == GRPC_CALL_OK);
break;
}
@ -312,6 +313,7 @@ static void request_response_with_payload_and_call_creds(
overridden_iam_selector));
break;
case DESTROY:
case FAIL:
GPR_ASSERT(!contains_metadata(&request_metadata_recv,
GRPC_IAM_AUTHORIZATION_TOKEN_METADATA_KEY,
iam_token));
@ -367,6 +369,13 @@ static void test_request_response_with_payload_and_deleted_call_creds(
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(
grpc_end2end_test_config config) {
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_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) {}

@ -74,6 +74,39 @@ static void test_missing_rpc_protocol_versions_property_failure() {
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() {
tsi_peer peer;
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_LENGTH(serialized_peer_versions),
&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";
grpc_slice serialized_alts_ctx = grpc_slice_from_copied_string(test_ctx);
GPR_ASSERT(
@ -142,7 +179,7 @@ static void test_alts_peer_to_auth_context_success() {
TSI_ALTS_CONTEXT,
reinterpret_cast<char*>(GRPC_SLICE_START_PTR(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_alts_auth_context_from_tsi_peer(&peer);
GPR_ASSERT(ctx != nullptr);
@ -161,6 +198,7 @@ int main(int /*argc*/, char** /*argv*/) {
test_empty_peer_property_failure();
test_unknown_peer_property_failure();
test_missing_rpc_protocol_versions_property_failure();
test_missing_security_level_property_failure();
test_alts_peer_to_auth_context_success();
return 0;

@ -404,6 +404,8 @@ static void test_google_iam_creds(void) {
grpc_call_credentials* creds = grpc_google_iam_credentials_create(
test_google_iam_authorization_token, test_google_iam_authority_selector,
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,
nullptr, nullptr};
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,
nullptr, nullptr};
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);
creds->Unref();
}
@ -474,12 +478,20 @@ static void test_oauth2_google_iam_composite_creds(void) {
nullptr, nullptr};
grpc_call_credentials* oauth2_creds = grpc_md_only_test_credentials_create(
"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(
test_google_iam_authorization_token, test_google_iam_authority_selector,
nullptr);
grpc_call_credentials* composite_creds =
grpc_composite_call_credentials_create(oauth2_creds, google_iam_creds,
nullptr);
/* Check security level of composite credentials. */
GPR_ASSERT(composite_creds->min_security_level() ==
GRPC_PRIVACY_AND_INTEGRITY);
oauth2_creds->Unref();
google_iam_creds->Unref();
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(
test_google_iam_authorization_token, test_google_iam_authority_selector,
nullptr);
grpc_channel_credentials* channel_oauth2_iam_creds =
grpc_composite_channel_credentials_create(channel_oauth2_creds,
google_iam_creds, nullptr);
@ -604,6 +617,8 @@ static void test_compute_engine_creds_success() {
grpc_google_compute_engine_credentials_create(nullptr);
grpc_auth_metadata_context auth_md_ctx = {test_service_url, test_method,
nullptr, nullptr};
/* Check security level. */
GPR_ASSERT(creds->min_security_level() == GRPC_PRIVACY_AND_INTEGRITY);
/* First request: http get should be called. */
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(
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. */
request_metadata_state* state =
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_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. */
request_metadata_state* state =
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);
GPR_ASSERT(gpr_time_cmp(creds_as_jwt(jwt_creds)->jwt_lifetime(),
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);
// Shorter lifetime.
@ -1408,8 +1431,10 @@ static void test_metadata_plugin_success(void) {
plugin.get_metadata = plugin_get_metadata_success;
plugin.destroy = plugin_destroy;
grpc_call_credentials* creds =
grpc_metadata_credentials_create_from_plugin(plugin, nullptr);
grpc_call_credentials* creds = grpc_metadata_credentials_create_from_plugin(
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);
run_request_metadata_test(creds, auth_md_ctx, md_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.destroy = plugin_destroy;
grpc_call_credentials* creds =
grpc_metadata_credentials_create_from_plugin(plugin, nullptr);
grpc_call_credentials* creds = grpc_metadata_credentials_create_from_plugin(
plugin, GRPC_PRIVACY_AND_INTEGRITY, nullptr);
GPR_ASSERT(state == PLUGIN_INITIAL_STATE);
run_request_metadata_test(creds, auth_md_ctx, md_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;
}
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) {
tsi_peer peer;
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(
TSI_CERTIFICATE_TYPE_PEER_PROPERTY, TSI_X509_CERTIFICATE_TYPE,
&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_ssl_peer_to_auth_context(&peer, GRPC_SSL_TRANSPORT_SECURITY_TYPE);
GPR_ASSERT(ctx != nullptr);
@ -181,7 +206,7 @@ static void test_cn_only_ssl_peer_to_auth_context(void) {
tsi_peer rpeer;
const char* expected_cn = "cn1";
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(
TSI_CERTIFICATE_TYPE_PEER_PROPERTY, TSI_X509_CERTIFICATE_TYPE,
&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(
TSI_X509_PEM_CERT_PROPERTY, expected_pem_cert,
&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_ssl_peer_to_auth_context(&peer, GRPC_SSL_TRANSPORT_SECURITY_TYPE);
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_san = "san1";
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(
TSI_CERTIFICATE_TYPE_PEER_PROPERTY, TSI_X509_CERTIFICATE_TYPE,
&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(
TSI_X509_PEM_CERT_PROPERTY, expected_pem_cert,
&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_ssl_peer_to_auth_context(&peer, GRPC_SSL_TRANSPORT_SECURITY_TYPE);
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_pem_cert = "pem_cert1";
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);
GPR_ASSERT(tsi_construct_string_peer_property_from_cstring(
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(
TSI_X509_PEM_CERT_PROPERTY, expected_pem_cert,
&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++) {
GPR_ASSERT(tsi_construct_string_peer_property_from_cstring(
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_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_sans[] = {"san1", "san2", "san3"};
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);
GPR_ASSERT(tsi_construct_string_peer_property_from_cstring(
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(
TSI_X509_PEM_CERT_PROPERTY, expected_pem_cert,
&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++) {
GPR_ASSERT(tsi_construct_string_peer_property_from_cstring(
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_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_default_ssl_roots();
test_peer_alpn_check();
test_check_security_level();
grpc_shutdown();
return 0;
}

@ -35,6 +35,7 @@
#define ALTS_TSI_HANDSHAKER_TEST_CONSUMED_BYTES "Hello "
#define ALTS_TSI_HANDSHAKER_TEST_REMAIN_BYTES "Google"
#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 \
"ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKL"
#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);
GPR_ASSERT(memcmp(ALTS_TSI_HANDSHAKER_TEST_LOCAL_IDENTITY, local_account.data,
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);
/* Validate unused bytes. */
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);
GPR_ASSERT(memcmp(ALTS_TSI_HANDSHAKER_TEST_LOCAL_IDENTITY, local_account.data,
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);
/* Validate unused bytes. */
const unsigned char* bytes = nullptr;

@ -50,6 +50,11 @@ static void validate_handshaker_peers(tsi_handshaker_result* result) {
GPR_ASSERT(property != nullptr);
GPR_ASSERT(memcmp(property->value.data, TSI_FAKE_CERTIFICATE_TYPE,
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);
}

@ -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*
check_basic_authenticated_peer_and_get_common_name(const tsi_peer* peer) {
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;
if (!ssl_fixture->force_client_auth) {
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 {
const tsi_peer_property* property =
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);
check_session_reusage(ssl_fixture, &peer);
check_alpn(ssl_fixture, &peer);
check_security_level(&peer);
if (ssl_fixture->server_name_indication != nullptr) {
check_server1_peer(&peer);
} else {
@ -310,6 +320,7 @@ static void ssl_test_check_handshaker_peers(tsi_test_fixture* fixture) {
ssl_fixture->base.server_result, &peer) == TSI_OK);
check_session_reusage(ssl_fixture, &peer);
check_alpn(ssl_fixture, &peer);
check_security_level(&peer);
check_client_peer(ssl_fixture, &peer);
} else {
GPR_ASSERT(ssl_fixture->base.server_result == nullptr);
@ -825,7 +836,8 @@ void ssl_tsi_test_extract_x509_subject_names() {
tsi_peer peer;
GPR_ASSERT(tsi_ssl_extract_x509_subject_names_from_pem_cert(cert, &peer) ==
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;
GPR_ASSERT(peer.property_count == expected_property_count);
// Check common name

Loading…
Cancel
Save