diff options
author | Jeff Vander Stoep <jeffv@google.com> | 2020-11-19 19:03:52 +0100 |
---|---|---|
committer | Jeff Vander Stoep <jeffv@google.com> | 2020-11-23 12:00:30 +0100 |
commit | 08902cf05eddf53e0ba8ccd8a4b12d615d3445e3 (patch) | |
tree | 780528631811bd11e8ff44b3c485e8ee2b1972f9 /grpc/src/core/lib/security/credentials | |
parent | 98a8525e013e1356d5914fbf7a20a142bdc96f7b (diff) | |
download | grpcio-sys-08902cf05eddf53e0ba8ccd8a4b12d615d3445e3.tar.gz |
Upgrade to 0.7.1
Test: build, TH
Change-Id: I3cb2c39b931e2b5c5b1a0bf775c6185c0e521da8
Diffstat (limited to 'grpc/src/core/lib/security/credentials')
18 files changed, 829 insertions, 155 deletions
diff --git a/grpc/src/core/lib/security/credentials/composite/composite_credentials.h b/grpc/src/core/lib/security/credentials/composite/composite_credentials.h index 57967e1b..6b9e9d11 100644 --- a/grpc/src/core/lib/security/credentials/composite/composite_credentials.h +++ b/grpc/src/core/lib/security/credentials/composite/composite_credentials.h @@ -23,7 +23,8 @@ #include <string> -#include "src/core/lib/gprpp/inlined_vector.h" +#include "absl/container/inlined_vector.h" + #include "src/core/lib/gprpp/ref_counted_ptr.h" #include "src/core/lib/security/credentials/credentials.h" @@ -71,8 +72,7 @@ class grpc_composite_channel_credentials : public grpc_channel_credentials { class grpc_composite_call_credentials : public grpc_call_credentials { public: using CallCredentialsList = - grpc_core::InlinedVector<grpc_core::RefCountedPtr<grpc_call_credentials>, - 2>; + absl::InlinedVector<grpc_core::RefCountedPtr<grpc_call_credentials>, 2>; grpc_composite_call_credentials( grpc_core::RefCountedPtr<grpc_call_credentials> creds1, diff --git a/grpc/src/core/lib/security/credentials/credentials.h b/grpc/src/core/lib/security/credentials/credentials.h index e7385537..1cc6e2d6 100644 --- a/grpc/src/core/lib/security/credentials/credentials.h +++ b/grpc/src/core/lib/security/credentials/credentials.h @@ -23,6 +23,8 @@ #include <string.h> +#include <string> + #include <grpc/grpc.h> #include <grpc/grpc_security.h> #include <grpc/support/sync.h> @@ -79,13 +81,13 @@ typedef enum { /* --- Google utils --- */ /* It is the caller's responsibility to gpr_free the result if not NULL. */ -char* grpc_get_well_known_google_credentials_file_path(void); +std::string grpc_get_well_known_google_credentials_file_path(void); /* Implementation function for the different platforms. */ -char* grpc_get_well_known_google_credentials_file_path_impl(void); +std::string grpc_get_well_known_google_credentials_file_path_impl(void); /* Override for testing only. Not thread-safe */ -typedef char* (*grpc_well_known_credentials_path_getter)(void); +typedef std::string (*grpc_well_known_credentials_path_getter)(void); void grpc_override_well_known_credentials_path_getter( grpc_well_known_credentials_path_getter getter); @@ -148,11 +150,10 @@ grpc_channel_credentials* grpc_channel_credentials_find_in_args( /* --- grpc_credentials_mdelem_array. --- */ -typedef struct { +struct grpc_credentials_mdelem_array { grpc_mdelem* md = nullptr; size_t size = 0; -} grpc_credentials_mdelem_array; - +}; /// Takes a new ref to \a md. void grpc_credentials_mdelem_array_add(grpc_credentials_mdelem_array* list, grpc_mdelem md); diff --git a/grpc/src/core/lib/security/credentials/google_default/credentials_generic.cc b/grpc/src/core/lib/security/credentials/google_default/credentials_generic.cc index 10ff0f62..8716edec 100644 --- a/grpc/src/core/lib/security/credentials/google_default/credentials_generic.cc +++ b/grpc/src/core/lib/security/credentials/google_default/credentials_generic.cc @@ -20,22 +20,24 @@ #include "src/core/lib/security/credentials/google_default/google_default_credentials.h" +#include <string> + +#include "absl/strings/str_cat.h" + #include <grpc/support/alloc.h> #include <grpc/support/log.h> -#include <grpc/support/string_util.h> #include "src/core/lib/gpr/env.h" -#include "src/core/lib/gpr/string.h" -char* grpc_get_well_known_google_credentials_file_path_impl(void) { - char* result = nullptr; +std::string grpc_get_well_known_google_credentials_file_path_impl(void) { char* base = gpr_getenv(GRPC_GOOGLE_CREDENTIALS_PATH_ENV_VAR); if (base == nullptr) { gpr_log(GPR_ERROR, "Could not get " GRPC_GOOGLE_CREDENTIALS_PATH_ENV_VAR " environment variable."); - return nullptr; + return ""; } - gpr_asprintf(&result, "%s/%s", base, GRPC_GOOGLE_CREDENTIALS_PATH_SUFFIX); + std::string result = + absl::StrCat(base, "/", GRPC_GOOGLE_CREDENTIALS_PATH_SUFFIX); gpr_free(base); return result; } diff --git a/grpc/src/core/lib/security/credentials/google_default/google_default_credentials.cc b/grpc/src/core/lib/security/credentials/google_default/google_default_credentials.cc index 58e550ed..9162bad4 100644 --- a/grpc/src/core/lib/security/credentials/google_default/google_default_credentials.cc +++ b/grpc/src/core/lib/security/credentials/google_default/google_default_credentials.cc @@ -49,6 +49,8 @@ using grpc_core::Json; /* -- Constants. -- */ #define GRPC_COMPUTE_ENGINE_DETECTION_HOST "metadata.google.internal." +#define GRPC_GOOGLE_CREDENTIAL_CREATION_ERROR \ + "Failed to create Google credentials" /* -- Default credentials. -- */ @@ -57,7 +59,6 @@ using grpc_core::Json; * means the detection is done via network test that is unreliable and the * unreliable result should not be referred by successive calls. */ static int g_metadata_server_available = 0; -static int g_is_on_gce = 0; static gpr_mu g_state_mu; /* Protect a metadata_server_detector instance that can be modified by more than * one gRPC threads */ @@ -68,13 +69,12 @@ static grpc_core::internal::grpc_gce_tenancy_checker g_gce_tenancy_checker = static void init_default_credentials(void) { gpr_mu_init(&g_state_mu); } -typedef struct { +struct metadata_server_detector { grpc_polling_entity pollent; int is_done; int success; grpc_http_response response; -} metadata_server_detector; - +}; grpc_core::RefCountedPtr<grpc_channel_security_connector> grpc_google_default_channel_credentials::create_security_connector( grpc_core::RefCountedPtr<grpc_call_credentials> call_creds, @@ -90,7 +90,7 @@ grpc_google_default_channel_credentials::create_security_connector( bool use_alts = is_grpclb_load_balancer || is_backend_from_grpclb_load_balancer; /* Return failure if ALTS is selected but not running on GCE. */ - if (use_alts && !g_is_on_gce) { + if (use_alts && alts_creds_ == nullptr) { gpr_log(GPR_ERROR, "ALTS is selected, but not running on GCE."); return nullptr; } @@ -217,24 +217,21 @@ static int is_metadata_server_reachable() { /* Takes ownership of creds_path if not NULL. */ static grpc_error* create_default_creds_from_path( - char* creds_path, grpc_core::RefCountedPtr<grpc_call_credentials>* creds) { + const std::string& creds_path, + grpc_core::RefCountedPtr<grpc_call_credentials>* creds) { grpc_auth_json_key key; grpc_auth_refresh_token token; grpc_core::RefCountedPtr<grpc_call_credentials> result; grpc_slice creds_data = grpc_empty_slice(); grpc_error* error = GRPC_ERROR_NONE; Json json; - grpc_core::StringView str; - if (creds_path == nullptr) { + if (creds_path.empty()) { error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("creds_path unset"); goto end; } - error = grpc_load_file(creds_path, 0, &creds_data); + error = grpc_load_file(creds_path.c_str(), 0, &creds_data); if (error != GRPC_ERROR_NONE) goto end; - str = grpc_core::StringView( - reinterpret_cast<char*>(GRPC_SLICE_START_PTR(creds_data)), - GRPC_SLICE_LENGTH(creds_data)); - json = Json::Parse(str, &error); + json = Json::Parse(grpc_core::StringViewFromSlice(creds_data), &error); if (error != GRPC_ERROR_NONE) goto end; if (json.type() != Json::Type::OBJECT) { error = grpc_error_set_str( @@ -272,42 +269,18 @@ static grpc_error* create_default_creds_from_path( end: GPR_ASSERT((result == nullptr) + (error == GRPC_ERROR_NONE) == 1); - if (creds_path != nullptr) gpr_free(creds_path); grpc_slice_unref_internal(creds_data); *creds = result; return error; } -grpc_channel_credentials* grpc_google_default_credentials_create() { - grpc_channel_credentials* result = nullptr; - grpc_core::RefCountedPtr<grpc_call_credentials> call_creds; - grpc_error* error = GRPC_ERROR_CREATE_FROM_STATIC_STRING( - "Failed to create Google credentials"); - grpc_error* err; - grpc_core::ExecCtx exec_ctx; - - GRPC_API_TRACE("grpc_google_default_credentials_create(void)", 0, ()); - +static void update_tenancy() { gpr_once_init(&g_once, init_default_credentials); - - /* First, try the environment variable. */ - err = create_default_creds_from_path( - gpr_getenv(GRPC_GOOGLE_CREDENTIALS_ENV_VAR), &call_creds); - if (err == GRPC_ERROR_NONE) goto end; - error = grpc_error_add_child(error, err); - - /* Then the well-known file. */ - err = create_default_creds_from_path( - grpc_get_well_known_google_credentials_file_path(), &call_creds); - if (err == GRPC_ERROR_NONE) goto end; - error = grpc_error_add_child(error, err); - - gpr_mu_lock(&g_state_mu); + grpc_core::MutexLock lock(&g_state_mu); /* Try a platform-provided hint for GCE. */ if (!g_metadata_server_available) { - g_is_on_gce = g_gce_tenancy_checker(); - g_metadata_server_available = g_is_on_gce; + g_metadata_server_available = g_gce_tenancy_checker(); } /* TODO: Add a platform-provided hint for GAE. */ @@ -315,19 +288,64 @@ grpc_channel_credentials* grpc_google_default_credentials_create() { if (!g_metadata_server_available) { g_metadata_server_available = is_metadata_server_reachable(); } - gpr_mu_unlock(&g_state_mu); +} + +static bool metadata_server_available() { + grpc_core::MutexLock lock(&g_state_mu); + return static_cast<bool>(g_metadata_server_available); +} - if (g_metadata_server_available) { +static grpc_core::RefCountedPtr<grpc_call_credentials> make_default_call_creds( + grpc_error** error) { + grpc_core::RefCountedPtr<grpc_call_credentials> call_creds; + grpc_error* err; + + /* First, try the environment variable. */ + char* path_from_env = gpr_getenv(GRPC_GOOGLE_CREDENTIALS_ENV_VAR); + if (path_from_env != nullptr) { + err = create_default_creds_from_path(path_from_env, &call_creds); + gpr_free(path_from_env); + if (err == GRPC_ERROR_NONE) return call_creds; + *error = grpc_error_add_child(*error, err); + } + + /* Then the well-known file. */ + err = create_default_creds_from_path( + grpc_get_well_known_google_credentials_file_path(), &call_creds); + if (err == GRPC_ERROR_NONE) return call_creds; + *error = grpc_error_add_child(*error, err); + + update_tenancy(); + + if (metadata_server_available()) { call_creds = grpc_core::RefCountedPtr<grpc_call_credentials>( grpc_google_compute_engine_credentials_create(nullptr)); if (call_creds == nullptr) { - error = grpc_error_add_child( - error, GRPC_ERROR_CREATE_FROM_STATIC_STRING( - "Failed to get credentials from network")); + *error = GRPC_ERROR_CREATE_FROM_STATIC_STRING( + GRPC_GOOGLE_CREDENTIAL_CREATION_ERROR); + *error = grpc_error_add_child( + *error, GRPC_ERROR_CREATE_FROM_STATIC_STRING( + "Failed to get credentials from network")); } } -end: + return call_creds; +} + +grpc_channel_credentials* grpc_google_default_credentials_create( + grpc_call_credentials* call_credentials) { + grpc_channel_credentials* result = nullptr; + grpc_core::RefCountedPtr<grpc_call_credentials> call_creds(call_credentials); + grpc_error* error = nullptr; + grpc_core::ExecCtx exec_ctx; + + GRPC_API_TRACE("grpc_google_default_credentials_create(%p)", 1, + (call_credentials)); + + if (call_creds == nullptr) { + call_creds = make_default_call_creds(&error); + } + if (call_creds != nullptr) { /* Create google default credentials. */ grpc_channel_credentials* ssl_creds = @@ -340,10 +358,8 @@ end: grpc_alts_credentials_options_destroy(options); auto creds = grpc_core::MakeRefCounted<grpc_google_default_channel_credentials>( - alts_creds != nullptr ? alts_creds->Ref() : nullptr, - ssl_creds != nullptr ? ssl_creds->Ref() : nullptr); - if (ssl_creds) ssl_creds->Unref(); - if (alts_creds) alts_creds->Unref(); + grpc_core::RefCountedPtr<grpc_channel_credentials>(alts_creds), + grpc_core::RefCountedPtr<grpc_channel_credentials>(ssl_creds)); result = grpc_composite_channel_credentials_create( creds.get(), call_creds.get(), nullptr); GPR_ASSERT(result != nullptr); @@ -377,7 +393,7 @@ void grpc_flush_cached_google_default_credentials(void) { static grpc_well_known_credentials_path_getter creds_path_getter = nullptr; -char* grpc_get_well_known_google_credentials_file_path(void) { +std::string grpc_get_well_known_google_credentials_file_path(void) { if (creds_path_getter != nullptr) return creds_path_getter(); return grpc_get_well_known_google_credentials_file_path_impl(); } diff --git a/grpc/src/core/lib/security/credentials/jwt/json_token.h b/grpc/src/core/lib/security/credentials/jwt/json_token.h index 23887b09..b9a41c6b 100644 --- a/grpc/src/core/lib/security/credentials/jwt/json_token.h +++ b/grpc/src/core/lib/security/credentials/jwt/json_token.h @@ -32,14 +32,13 @@ /* --- auth_json_key parsing. --- */ -typedef struct { +struct grpc_auth_json_key { const char* type; char* private_key_id; char* client_id; char* client_email; RSA* private_key; -} grpc_auth_json_key; - +}; /* Returns 1 if the object is valid, 0 otherwise. */ int grpc_auth_json_key_is_valid(const grpc_auth_json_key* json_key); diff --git a/grpc/src/core/lib/security/credentials/jwt/jwt_credentials.cc b/grpc/src/core/lib/security/credentials/jwt/jwt_credentials.cc index bed594e5..e5edc052 100644 --- a/grpc/src/core/lib/security/credentials/jwt/jwt_credentials.cc +++ b/grpc/src/core/lib/security/credentials/jwt/jwt_credentials.cc @@ -23,8 +23,13 @@ #include <inttypes.h> #include <string.h> +#include <string> + +#include "absl/strings/str_cat.h" + #include "src/core/lib/gprpp/ref_counted.h" #include "src/core/lib/gprpp/ref_counted_ptr.h" +#include "src/core/lib/slice/slice_internal.h" #include "src/core/lib/surface/api_trace.h" #include <grpc/support/alloc.h> @@ -81,16 +86,14 @@ bool grpc_service_account_jwt_access_credentials::get_request_metadata( jwt = grpc_jwt_encode_and_sign(&key_, context.service_url, jwt_lifetime_, nullptr); if (jwt != nullptr) { - char* md_value; - gpr_asprintf(&md_value, "Bearer %s", jwt); + std::string md_value = absl::StrCat("Bearer ", jwt); gpr_free(jwt); cached_.jwt_expiration = gpr_time_add(gpr_now(GPR_CLOCK_REALTIME), jwt_lifetime_); cached_.service_url = gpr_strdup(context.service_url); cached_.jwt_md = grpc_mdelem_from_slices( grpc_slice_from_static_string(GRPC_AUTHORIZATION_METADATA_KEY), - grpc_slice_from_copied_string(md_value)); - gpr_free(md_value); + grpc_slice_from_cpp_string(std::move(md_value))); jwt_md = GRPC_MDELEM_REF(cached_.jwt_md); } gpr_mu_unlock(&cache_mu_); diff --git a/grpc/src/core/lib/security/credentials/jwt/jwt_verifier.cc b/grpc/src/core/lib/security/credentials/jwt/jwt_verifier.cc index 1d082b25..cd8217fd 100644 --- a/grpc/src/core/lib/security/credentials/jwt/jwt_verifier.cc +++ b/grpc/src/core/lib/security/credentials/jwt/jwt_verifier.cc @@ -86,9 +86,7 @@ static Json parse_json_part_from_jwt(const char* str, size_t len) { gpr_log(GPR_ERROR, "Invalid base64."); return Json(); // JSON null } - grpc_core::StringView string( - reinterpret_cast<char*>(GRPC_SLICE_START_PTR(slice)), - GRPC_SLICE_LENGTH(slice)); + absl::string_view string = grpc_core::StringViewFromSlice(slice); grpc_error* error = GRPC_ERROR_NONE; Json json = Json::Parse(string, &error); if (error != GRPC_ERROR_NONE) { @@ -120,14 +118,13 @@ static gpr_timespec validate_time_field(const Json& json, const char* key) { /* --- JOSE header. see http://tools.ietf.org/html/rfc7515#section-4 --- */ -typedef struct { +struct jose_header { const char* alg; const char* kid; const char* typ; /* TODO(jboeuf): Add others as needed (jku, jwk, x5u, x5c and so on...). */ grpc_core::ManualConstructor<Json> json; -} jose_header; - +}; static void jose_header_destroy(jose_header* h) { h->json.Destroy(); gpr_free(h); @@ -337,7 +334,7 @@ typedef enum { HTTP_RESPONSE_COUNT /* must be last */ } http_response_index; -typedef struct { +struct verifier_cb_ctx { grpc_jwt_verifier* verifier; grpc_polling_entity pollent; jose_header* header; @@ -348,8 +345,7 @@ typedef struct { void* user_data; grpc_jwt_verification_done_cb user_cb; grpc_http_response responses[HTTP_RESPONSE_COUNT]; -} verifier_cb_ctx; - +}; /* Takes ownership of the header, claims and signature. */ static verifier_cb_ctx* verifier_cb_ctx_create( grpc_jwt_verifier* verifier, grpc_pollset* pollset, jose_header* header, @@ -394,11 +390,10 @@ gpr_timespec grpc_jwt_verifier_clock_skew = {60, 0, GPR_TIMESPAN}; /* Max delay defaults to one minute. */ grpc_millis grpc_jwt_verifier_max_delay = 60 * GPR_MS_PER_SEC; -typedef struct { +struct email_key_mapping { char* email_domain; char* key_url_prefix; -} email_key_mapping; - +}; struct grpc_jwt_verifier { email_key_mapping* mappings; size_t num_mappings; /* Should be very few, linear search ok. */ @@ -418,7 +413,7 @@ static Json json_from_http(const grpc_httpcli_response* response) { } grpc_error* error = GRPC_ERROR_NONE; Json json = Json::Parse( - grpc_core::StringView(response->body, response->body_length), &error); + absl::string_view(response->body, response->body_length), &error); if (error != GRPC_ERROR_NONE) { gpr_log(GPR_ERROR, "Invalid JSON found in response."); return Json(); // JSON null diff --git a/grpc/src/core/lib/security/credentials/jwt/jwt_verifier.h b/grpc/src/core/lib/security/credentials/jwt/jwt_verifier.h index d4483866..66ddbf22 100644 --- a/grpc/src/core/lib/security/credentials/jwt/jwt_verifier.h +++ b/grpc/src/core/lib/security/credentials/jwt/jwt_verifier.h @@ -71,7 +71,7 @@ gpr_timespec grpc_jwt_claims_not_before(const grpc_jwt_claims* claims); typedef struct grpc_jwt_verifier grpc_jwt_verifier; -typedef struct { +struct grpc_jwt_verifier_email_domain_key_url_mapping { /* The email domain is the part after the @ sign. */ const char* email_domain; @@ -79,8 +79,7 @@ typedef struct { https://<key_url_prefix>/<issuer_email> Therefore the key_url_prefix must NOT contain https://. */ const char* key_url_prefix; -} grpc_jwt_verifier_email_domain_key_url_mapping; - +}; /* Globals to control the verifier. Not thread-safe. */ extern gpr_timespec grpc_jwt_verifier_clock_skew; extern grpc_millis grpc_jwt_verifier_max_delay; diff --git a/grpc/src/core/lib/security/credentials/oauth2/oauth2_credentials.cc b/grpc/src/core/lib/security/credentials/oauth2/oauth2_credentials.cc index c922d35b..322156c9 100644 --- a/grpc/src/core/lib/security/credentials/oauth2/oauth2_credentials.cc +++ b/grpc/src/core/lib/security/credentials/oauth2/oauth2_credentials.cc @@ -23,6 +23,11 @@ #include <string.h> +#include "absl/container/inlined_vector.h" +#include "absl/strings/str_cat.h" +#include "absl/strings/str_format.h" +#include "absl/strings/str_join.h" + #include <grpc/grpc_security.h> #include <grpc/impl/codegen/slice.h> #include <grpc/slice.h> @@ -30,9 +35,7 @@ #include <grpc/support/log.h> #include <grpc/support/string_util.h> -#include "absl/strings/str_format.h" #include "src/core/lib/gpr/string.h" -#include "src/core/lib/gprpp/inlined_vector.h" #include "src/core/lib/gprpp/ref_counted_ptr.h" #include "src/core/lib/iomgr/error.h" #include "src/core/lib/iomgr/load_file.h" @@ -134,7 +137,6 @@ grpc_oauth2_token_fetcher_credentials_parse_server_response( const grpc_http_response* response, grpc_mdelem* token_md, grpc_millis* token_lifetime) { char* null_terminated_body = nullptr; - char* new_access_token = nullptr; grpc_credentials_status status = GRPC_CREDENTIALS_OK; Json json; @@ -200,12 +202,12 @@ grpc_oauth2_token_fetcher_credentials_parse_server_response( goto end; } expires_in = it->second.string_value().c_str(); - gpr_asprintf(&new_access_token, "%s %s", token_type, access_token); *token_lifetime = strtol(expires_in, nullptr, 10) * GPR_MS_PER_SEC; if (!GRPC_MDISNULL(*token_md)) GRPC_MDELEM_UNREF(*token_md); *token_md = grpc_mdelem_from_slices( grpc_core::ExternallyManagedSlice(GRPC_AUTHORIZATION_METADATA_KEY), - grpc_core::UnmanagedMemorySlice(new_access_token)); + grpc_slice_from_cpp_string( + absl::StrCat(token_type, " ", access_token))); status = GRPC_CREDENTIALS_OK; } @@ -214,8 +216,7 @@ end: GRPC_MDELEM_UNREF(*token_md); *token_md = GRPC_MDNULL; } - if (null_terminated_body != nullptr) gpr_free(null_terminated_body); - if (new_access_token != nullptr) gpr_free(new_access_token); + gpr_free(null_terminated_body); return status; } @@ -440,10 +441,9 @@ void grpc_google_refresh_token_credentials::fetch_oauth2( const_cast<char*>("Content-Type"), const_cast<char*>("application/x-www-form-urlencoded")}; grpc_httpcli_request request; - char* body = nullptr; - gpr_asprintf(&body, GRPC_REFRESH_TOKEN_POST_BODY_FORMAT_STRING, - refresh_token_.client_id, refresh_token_.client_secret, - refresh_token_.refresh_token); + std::string body = absl::StrFormat( + GRPC_REFRESH_TOKEN_POST_BODY_FORMAT_STRING, refresh_token_.client_id, + refresh_token_.client_secret, refresh_token_.refresh_token); memset(&request, 0, sizeof(grpc_httpcli_request)); request.host = (char*)GRPC_GOOGLE_OAUTH2_SERVICE_HOST; request.http.path = (char*)GRPC_GOOGLE_OAUTH2_SERVICE_TOKEN_PATH; @@ -455,13 +455,12 @@ void grpc_google_refresh_token_credentials::fetch_oauth2( extreme memory pressure. */ grpc_resource_quota* resource_quota = grpc_resource_quota_create("oauth2_credentials_refresh"); - grpc_httpcli_post(httpcli_context, pollent, resource_quota, &request, body, - strlen(body), deadline, + grpc_httpcli_post(httpcli_context, pollent, resource_quota, &request, + body.c_str(), body.size(), deadline, GRPC_CLOSURE_INIT(&http_post_cb_closure_, response_cb, metadata_req, grpc_schedule_on_exec_ctx), &metadata_req->response); grpc_resource_quota_unref_internal(resource_quota); - gpr_free(body); } grpc_google_refresh_token_credentials::grpc_google_refresh_token_credentials( @@ -485,16 +484,15 @@ std::string grpc_google_refresh_token_credentials::debug_string() { grpc_oauth2_token_fetcher_credentials::debug_string()); } -static char* create_loggable_refresh_token(grpc_auth_refresh_token* token) { +static std::string create_loggable_refresh_token( + grpc_auth_refresh_token* token) { if (strcmp(token->type, GRPC_AUTH_JSON_TYPE_INVALID) == 0) { - return gpr_strdup("<Invalid json token>"); + return "<Invalid json token>"; } - char* loggable_token = nullptr; - gpr_asprintf(&loggable_token, - "{\n type: %s\n client_id: %s\n client_secret: " - "<redacted>\n refresh_token: <redacted>\n}", - token->type, token->client_id); - return loggable_token; + return absl::StrFormat( + "{\n type: %s\n client_id: %s\n client_secret: " + "<redacted>\n refresh_token: <redacted>\n}", + token->type, token->client_id); } grpc_call_credentials* grpc_google_refresh_token_credentials_create( @@ -502,12 +500,10 @@ grpc_call_credentials* grpc_google_refresh_token_credentials_create( grpc_auth_refresh_token token = grpc_auth_refresh_token_create_from_string(json_refresh_token); if (GRPC_TRACE_FLAG_ENABLED(grpc_api_trace)) { - char* loggable_token = create_loggable_refresh_token(&token); gpr_log(GPR_INFO, "grpc_refresh_token_credentials_create(json_refresh_token=%s, " "reserved=%p)", - loggable_token, reserved); - gpr_free(loggable_token); + create_loggable_refresh_token(&token).c_str(), reserved); } GPR_ASSERT(reserved == nullptr); return grpc_refresh_token_credentials_create_from_auth_refresh_token(token) @@ -522,12 +518,10 @@ namespace grpc_core { namespace { -void MaybeAddToBody(gpr_strvec* body_strvec, const char* field_name, - const char* field) { +void MaybeAddToBody(const char* field_name, const char* field, + std::vector<std::string>* body) { if (field == nullptr || strlen(field) == 0) return; - char* new_query; - gpr_asprintf(&new_query, "&%s=%s", field_name, field); - gpr_strvec_add(body_strvec, new_query); + body->push_back(absl::StrFormat("&%s=%s", field_name, field)); } grpc_error* LoadTokenFile(const char* path, gpr_slice* token) { @@ -607,20 +601,18 @@ class StsTokenFetcherCredentials grpc_error* FillBody(char** body, size_t* body_length) { *body = nullptr; - gpr_strvec body_strvec; - gpr_strvec_init(&body_strvec); + std::vector<std::string> body_parts; grpc_slice subject_token = grpc_empty_slice(); grpc_slice actor_token = grpc_empty_slice(); grpc_error* err = GRPC_ERROR_NONE; - auto cleanup = [&body, &body_length, &body_strvec, &subject_token, + auto cleanup = [&body, &body_length, &body_parts, &subject_token, &actor_token, &err]() { if (err == GRPC_ERROR_NONE) { - *body = gpr_strvec_flatten(&body_strvec, body_length); - } else { - gpr_free(*body); + std::string body_str = absl::StrJoin(body_parts, ""); + *body = gpr_strdup(body_str.c_str()); + *body_length = body_str.size(); } - gpr_strvec_destroy(&body_strvec); grpc_slice_unref_internal(subject_token); grpc_slice_unref_internal(actor_token); return err; @@ -628,23 +620,23 @@ class StsTokenFetcherCredentials err = LoadTokenFile(subject_token_path_.get(), &subject_token); if (err != GRPC_ERROR_NONE) return cleanup(); - gpr_asprintf( - body, GRPC_STS_POST_MINIMAL_BODY_FORMAT_STRING, + body_parts.push_back(absl::StrFormat( + GRPC_STS_POST_MINIMAL_BODY_FORMAT_STRING, reinterpret_cast<const char*>(GRPC_SLICE_START_PTR(subject_token)), - subject_token_type_.get()); - gpr_strvec_add(&body_strvec, *body); - MaybeAddToBody(&body_strvec, "resource", resource_.get()); - MaybeAddToBody(&body_strvec, "audience", audience_.get()); - MaybeAddToBody(&body_strvec, "scope", scope_.get()); - MaybeAddToBody(&body_strvec, "requested_token_type", - requested_token_type_.get()); + subject_token_type_.get())); + MaybeAddToBody("resource", resource_.get(), &body_parts); + MaybeAddToBody("audience", audience_.get(), &body_parts); + MaybeAddToBody("scope", scope_.get(), &body_parts); + MaybeAddToBody("requested_token_type", requested_token_type_.get(), + &body_parts); if ((actor_token_path_ != nullptr) && *actor_token_path_ != '\0') { err = LoadTokenFile(actor_token_path_.get(), &actor_token); if (err != GRPC_ERROR_NONE) return cleanup(); MaybeAddToBody( - &body_strvec, "actor_token", - reinterpret_cast<const char*>(GRPC_SLICE_START_PTR(actor_token))); - MaybeAddToBody(&body_strvec, "actor_token_type", actor_token_type_.get()); + "actor_token", + reinterpret_cast<const char*>(GRPC_SLICE_START_PTR(actor_token)), + &body_parts); + MaybeAddToBody("actor_token_type", actor_token_type_.get(), &body_parts); } return cleanup(); } @@ -669,7 +661,7 @@ grpc_error* ValidateStsCredentialsOptions( void operator()(grpc_uri* uri) { grpc_uri_destroy(uri); } }; *sts_url_out = nullptr; - InlinedVector<grpc_error*, 3> error_list; + absl::InlinedVector<grpc_error*, 3> error_list; std::unique_ptr<grpc_uri, GrpcUriDeleter> sts_url( options->token_exchange_service_uri != nullptr ? grpc_uri_parse(options->token_exchange_service_uri, false) @@ -746,13 +738,10 @@ void grpc_access_token_credentials::cancel_get_request_metadata( grpc_access_token_credentials::grpc_access_token_credentials( const char* access_token) : grpc_call_credentials(GRPC_CALL_CREDENTIALS_TYPE_OAUTH2) { - char* token_md_value; - gpr_asprintf(&token_md_value, "Bearer %s", access_token); grpc_core::ExecCtx exec_ctx; access_token_md_ = grpc_mdelem_from_slices( grpc_core::ExternallyManagedSlice(GRPC_AUTHORIZATION_METADATA_KEY), - grpc_core::UnmanagedMemorySlice(token_md_value)); - gpr_free(token_md_value); + grpc_slice_from_cpp_string(absl::StrCat("Bearer ", access_token))); } std::string grpc_access_token_credentials::debug_string() { diff --git a/grpc/src/core/lib/security/credentials/oauth2/oauth2_credentials.h b/grpc/src/core/lib/security/credentials/oauth2/oauth2_credentials.h index 9065da4f..2a9b37e1 100644 --- a/grpc/src/core/lib/security/credentials/oauth2/oauth2_credentials.h +++ b/grpc/src/core/lib/security/credentials/oauth2/oauth2_credentials.h @@ -34,13 +34,12 @@ "s&subject_token_type=%s" // auth_refresh_token parsing. -typedef struct { +struct grpc_auth_refresh_token { const char* type; char* client_id; char* client_secret; char* refresh_token; -} grpc_auth_refresh_token; - +}; /// Returns 1 if the object is valid, 0 otherwise. int grpc_auth_refresh_token_is_valid( const grpc_auth_refresh_token* refresh_token); diff --git a/grpc/src/core/lib/security/credentials/plugin/plugin_credentials.cc b/grpc/src/core/lib/security/credentials/plugin/plugin_credentials.cc index ebe59212..9cb8b815 100644 --- a/grpc/src/core/lib/security/credentials/plugin/plugin_credentials.cc +++ b/grpc/src/core/lib/security/credentials/plugin/plugin_credentials.cc @@ -22,10 +22,11 @@ #include <string.h> +#include "absl/strings/str_cat.h" + #include <grpc/grpc.h> #include <grpc/support/alloc.h> #include <grpc/support/log.h> -#include <grpc/support/string_util.h> #include <grpc/support/sync.h> #include "src/core/lib/slice/slice_internal.h" @@ -86,11 +87,10 @@ static grpc_error* process_plugin_result( size_t num_md, grpc_status_code status, const char* error_details) { grpc_error* error = GRPC_ERROR_NONE; if (status != GRPC_STATUS_OK) { - char* msg; - gpr_asprintf(&msg, "Getting metadata from plugin failed with error: %s", - error_details); - error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg); - gpr_free(msg); + error = GRPC_ERROR_CREATE_FROM_COPIED_STRING( + absl::StrCat("Getting metadata from plugin failed with error: ", + error_details) + .c_str()); } else { bool seen_illegal_header = false; for (size_t i = 0; i < num_md; ++i) { diff --git a/grpc/src/core/lib/security/credentials/ssl/ssl_credentials.cc b/grpc/src/core/lib/security/credentials/ssl/ssl_credentials.cc index 48d78f39..3bb7790f 100644 --- a/grpc/src/core/lib/security/credentials/ssl/ssl_credentials.cc +++ b/grpc/src/core/lib/security/credentials/ssl/ssl_credentials.cc @@ -117,6 +117,16 @@ void grpc_ssl_credentials::build_config( } } +void grpc_ssl_credentials::set_min_tls_version( + grpc_tls_version min_tls_version) { + config_.min_tls_version = min_tls_version; +} + +void grpc_ssl_credentials::set_max_tls_version( + grpc_tls_version max_tls_version) { + config_.max_tls_version = max_tls_version; +} + /* Deprecated in favor of grpc_ssl_credentials_create_ex. Will be removed * once all of its call sites are migrated to grpc_ssl_credentials_create_ex. */ grpc_channel_credentials* grpc_ssl_credentials_create( @@ -213,6 +223,16 @@ void grpc_ssl_server_credentials::build_config( config_.num_key_cert_pairs = num_key_cert_pairs; } +void grpc_ssl_server_credentials::set_min_tls_version( + grpc_tls_version min_tls_version) { + config_.min_tls_version = min_tls_version; +} + +void grpc_ssl_server_credentials::set_max_tls_version( + grpc_tls_version max_tls_version) { + config_.max_tls_version = max_tls_version; +} + grpc_ssl_server_certificate_config* grpc_ssl_server_certificate_config_create( const char* pem_root_certs, const grpc_ssl_pem_key_cert_pair* pem_key_cert_pairs, diff --git a/grpc/src/core/lib/security/credentials/ssl/ssl_credentials.h b/grpc/src/core/lib/security/credentials/ssl/ssl_credentials.h index 545a27f0..4c90813f 100644 --- a/grpc/src/core/lib/security/credentials/ssl/ssl_credentials.h +++ b/grpc/src/core/lib/security/credentials/ssl/ssl_credentials.h @@ -38,6 +38,11 @@ class grpc_ssl_credentials : public grpc_channel_credentials { const char* target, const grpc_channel_args* args, grpc_channel_args** new_args) override; + // TODO(mattstev): Plumb to wrapped languages. Until then, setting the TLS + // version should be done for testing purposes only. + void set_min_tls_version(grpc_tls_version min_tls_version); + void set_max_tls_version(grpc_tls_version max_tls_version); + private: void build_config(const char* pem_root_certs, grpc_ssl_pem_key_cert_pair* pem_key_cert_pair, @@ -77,6 +82,11 @@ class grpc_ssl_server_credentials final : public grpc_server_credentials { config); } + // TODO(mattstev): Plumb to wrapped languages. Until then, setting the TLS + // version should be done for testing purposes only. + void set_min_tls_version(grpc_tls_version min_tls_version); + void set_max_tls_version(grpc_tls_version max_tls_version); + const grpc_ssl_server_config& config() const { return config_; } private: diff --git a/grpc/src/core/lib/security/credentials/tls/grpc_tls_certificate_distributor.cc b/grpc/src/core/lib/security/credentials/tls/grpc_tls_certificate_distributor.cc new file mode 100644 index 00000000..2189865b --- /dev/null +++ b/grpc/src/core/lib/security/credentials/tls/grpc_tls_certificate_distributor.cc @@ -0,0 +1,321 @@ +// +// Copyright 2020 gRPC authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#include <grpc/support/port_platform.h> + +#include "src/core/lib/security/credentials/tls/grpc_tls_certificate_distributor.h" + +#include <grpc/support/alloc.h> +#include <grpc/support/log.h> +#include <grpc/support/string_util.h> +#include <stdlib.h> +#include <string.h> + +void grpc_tls_certificate_distributor::SetKeyMaterials( + const std::string& cert_name, absl::optional<std::string> pem_root_certs, + absl::optional<PemKeyCertPairList> pem_key_cert_pairs) { + GPR_ASSERT(pem_root_certs.has_value() || pem_key_cert_pairs.has_value()); + grpc_core::MutexLock lock(&mu_); + auto& cert_info = certificate_info_map_[cert_name]; + if (pem_root_certs.has_value()) { + // Successful credential updates will clear any pre-existing error. + cert_info.SetRootError(GRPC_ERROR_NONE); + for (auto* watcher_ptr : cert_info.root_cert_watchers) { + GPR_ASSERT(watcher_ptr != nullptr); + const auto watcher_it = watchers_.find(watcher_ptr); + GPR_ASSERT(watcher_it != watchers_.end()); + GPR_ASSERT(watcher_it->second.root_cert_name.has_value()); + absl::optional<PemKeyCertPairList> pem_key_cert_pairs_to_report; + if (pem_key_cert_pairs.has_value() && + watcher_it->second.identity_cert_name == cert_name) { + pem_key_cert_pairs_to_report = pem_key_cert_pairs; + } else if (watcher_it->second.identity_cert_name.has_value()) { + auto& identity_cert_info = + certificate_info_map_[*watcher_it->second.identity_cert_name]; + pem_key_cert_pairs_to_report = identity_cert_info.pem_key_cert_pairs; + } + watcher_ptr->OnCertificatesChanged( + pem_root_certs, std::move(pem_key_cert_pairs_to_report)); + } + cert_info.pem_root_certs = std::move(*pem_root_certs); + } + if (pem_key_cert_pairs.has_value()) { + // Successful credential updates will clear any pre-existing error. + cert_info.SetIdentityError(GRPC_ERROR_NONE); + for (const auto watcher_ptr : cert_info.identity_cert_watchers) { + GPR_ASSERT(watcher_ptr != nullptr); + const auto watcher_it = watchers_.find(watcher_ptr); + GPR_ASSERT(watcher_it != watchers_.end()); + GPR_ASSERT(watcher_it->second.identity_cert_name.has_value()); + absl::optional<absl::string_view> pem_root_certs_to_report; + if (pem_root_certs.has_value() && + watcher_it->second.root_cert_name == cert_name) { + // In this case, We've already sent the credential updates at the time + // when checking pem_root_certs, so we will skip here. + continue; + } else if (watcher_it->second.root_cert_name.has_value()) { + auto& root_cert_info = + certificate_info_map_[*watcher_it->second.root_cert_name]; + pem_root_certs_to_report = root_cert_info.pem_root_certs; + } + watcher_ptr->OnCertificatesChanged(pem_root_certs_to_report, + pem_key_cert_pairs); + } + cert_info.pem_key_cert_pairs = std::move(*pem_key_cert_pairs); + } +} + +bool grpc_tls_certificate_distributor::HasRootCerts( + const std::string& root_cert_name) { + grpc_core::MutexLock lock(&mu_); + const auto it = certificate_info_map_.find(root_cert_name); + return it != certificate_info_map_.end() && + !it->second.pem_root_certs.empty(); +}; + +bool grpc_tls_certificate_distributor::HasKeyCertPairs( + const std::string& identity_cert_name) { + grpc_core::MutexLock lock(&mu_); + const auto it = certificate_info_map_.find(identity_cert_name); + return it != certificate_info_map_.end() && + !it->second.pem_key_cert_pairs.empty(); +}; + +void grpc_tls_certificate_distributor::SetErrorForCert( + const std::string& cert_name, absl::optional<grpc_error*> root_cert_error, + absl::optional<grpc_error*> identity_cert_error) { + GPR_ASSERT(root_cert_error.has_value() || identity_cert_error.has_value()); + grpc_core::MutexLock lock(&mu_); + CertificateInfo& cert_info = certificate_info_map_[cert_name]; + if (root_cert_error.has_value()) { + for (auto* watcher_ptr : cert_info.root_cert_watchers) { + GPR_ASSERT(watcher_ptr != nullptr); + const auto watcher_it = watchers_.find(watcher_ptr); + GPR_ASSERT(watcher_it != watchers_.end()); + // identity_cert_error_to_report is the error of the identity cert this + // watcher is watching, if there is any. + grpc_error* identity_cert_error_to_report = GRPC_ERROR_NONE; + if (identity_cert_error.has_value() && + watcher_it->second.identity_cert_name == cert_name) { + identity_cert_error_to_report = *identity_cert_error; + } else if (watcher_it->second.identity_cert_name.has_value()) { + auto& identity_cert_info = + certificate_info_map_[*watcher_it->second.identity_cert_name]; + identity_cert_error_to_report = identity_cert_info.identity_cert_error; + } + watcher_ptr->OnError(GRPC_ERROR_REF(*root_cert_error), + GRPC_ERROR_REF(identity_cert_error_to_report)); + } + cert_info.SetRootError(*root_cert_error); + } + if (identity_cert_error.has_value()) { + for (auto* watcher_ptr : cert_info.identity_cert_watchers) { + GPR_ASSERT(watcher_ptr != nullptr); + const auto watcher_it = watchers_.find(watcher_ptr); + GPR_ASSERT(watcher_it != watchers_.end()); + // root_cert_error_to_report is the error of the root cert this watcher is + // watching, if there is any. + grpc_error* root_cert_error_to_report = GRPC_ERROR_NONE; + if (root_cert_error.has_value() && + watcher_it->second.root_cert_name == cert_name) { + // In this case, We've already sent the error updates at the time when + // checking root_cert_error, so we will skip here. + continue; + } else if (watcher_it->second.root_cert_name.has_value()) { + auto& root_cert_info = + certificate_info_map_[*watcher_it->second.root_cert_name]; + root_cert_error_to_report = root_cert_info.root_cert_error; + } + watcher_ptr->OnError(GRPC_ERROR_REF(root_cert_error_to_report), + GRPC_ERROR_REF(*identity_cert_error)); + } + cert_info.SetIdentityError(*identity_cert_error); + } +}; + +void grpc_tls_certificate_distributor::SetError(grpc_error* error) { + GPR_ASSERT(error != GRPC_ERROR_NONE); + grpc_core::MutexLock lock(&mu_); + for (const auto& watcher : watchers_) { + const auto watcher_ptr = watcher.first; + GPR_ASSERT(watcher_ptr != nullptr); + const auto& watcher_info = watcher.second; + watcher_ptr->OnError( + watcher_info.root_cert_name.has_value() ? GRPC_ERROR_REF(error) + : GRPC_ERROR_NONE, + watcher_info.identity_cert_name.has_value() ? GRPC_ERROR_REF(error) + : GRPC_ERROR_NONE); + } + for (auto& cert_info_entry : certificate_info_map_) { + auto& cert_info = cert_info_entry.second; + cert_info.SetRootError(GRPC_ERROR_REF(error)); + cert_info.SetIdentityError(GRPC_ERROR_REF(error)); + } + GRPC_ERROR_UNREF(error); +}; + +void grpc_tls_certificate_distributor::WatchTlsCertificates( + std::unique_ptr<TlsCertificatesWatcherInterface> watcher, + absl::optional<std::string> root_cert_name, + absl::optional<std::string> identity_cert_name) { + bool start_watching_root_cert = false; + bool already_watching_identity_for_root_cert = false; + bool start_watching_identity_cert = false; + bool already_watching_root_for_identity_cert = false; + GPR_ASSERT(root_cert_name.has_value() || identity_cert_name.has_value()); + TlsCertificatesWatcherInterface* watcher_ptr = watcher.get(); + GPR_ASSERT(watcher_ptr != nullptr); + // Update watchers_ and certificate_info_map_. + { + grpc_core::MutexLock lock(&mu_); + const auto watcher_it = watchers_.find(watcher_ptr); + // The caller needs to cancel the watcher first if it wants to re-register + // the watcher. + GPR_ASSERT(watcher_it == watchers_.end()); + watchers_[watcher_ptr] = {std::move(watcher), root_cert_name, + identity_cert_name}; + absl::optional<absl::string_view> updated_root_certs; + absl::optional<PemKeyCertPairList> updated_identity_pairs; + grpc_error* root_error = GRPC_ERROR_NONE; + grpc_error* identity_error = GRPC_ERROR_NONE; + if (root_cert_name.has_value()) { + CertificateInfo& cert_info = certificate_info_map_[*root_cert_name]; + start_watching_root_cert = cert_info.root_cert_watchers.empty(); + already_watching_identity_for_root_cert = + !cert_info.identity_cert_watchers.empty(); + cert_info.root_cert_watchers.insert(watcher_ptr); + root_error = GRPC_ERROR_REF(cert_info.root_cert_error); + // Empty credentials will be treated as no updates. + if (!cert_info.pem_root_certs.empty()) { + updated_root_certs = cert_info.pem_root_certs; + } + } + if (identity_cert_name.has_value()) { + CertificateInfo& cert_info = certificate_info_map_[*identity_cert_name]; + start_watching_identity_cert = cert_info.identity_cert_watchers.empty(); + already_watching_root_for_identity_cert = + !cert_info.root_cert_watchers.empty(); + cert_info.identity_cert_watchers.insert(watcher_ptr); + identity_error = GRPC_ERROR_REF(cert_info.identity_cert_error); + // Empty credentials will be treated as no updates. + if (!cert_info.pem_key_cert_pairs.empty()) { + updated_identity_pairs = cert_info.pem_key_cert_pairs; + } + } + // Notify this watcher if the certs it is watching already had some + // contents. Note that an *_cert_error in cert_info only indicates error + // occurred while trying to fetch the latest cert, but the updated_*_certs + // should always be valid. So we will send the updates regardless of + // *_cert_error. + if (updated_root_certs.has_value() || updated_identity_pairs.has_value()) { + watcher_ptr->OnCertificatesChanged(updated_root_certs, + std::move(updated_identity_pairs)); + } + // Notify this watcher if the certs it is watching already had some errors. + if (root_error != GRPC_ERROR_NONE || identity_error != GRPC_ERROR_NONE) { + watcher_ptr->OnError(GRPC_ERROR_REF(root_error), + GRPC_ERROR_REF(identity_error)); + } + GRPC_ERROR_UNREF(root_error); + GRPC_ERROR_UNREF(identity_error); + } + // Invoke watch status callback if needed. + { + grpc_core::MutexLock lock(&callback_mu_); + if (watch_status_callback_ != nullptr) { + if (root_cert_name == identity_cert_name && + (start_watching_root_cert || start_watching_identity_cert)) { + watch_status_callback_(*root_cert_name, start_watching_root_cert, + start_watching_identity_cert); + } else { + if (start_watching_root_cert) { + watch_status_callback_(*root_cert_name, true, + already_watching_identity_for_root_cert); + } + if (start_watching_identity_cert) { + watch_status_callback_(*identity_cert_name, + already_watching_root_for_identity_cert, true); + } + } + } + } +}; + +void grpc_tls_certificate_distributor::CancelTlsCertificatesWatch( + TlsCertificatesWatcherInterface* watcher) { + absl::optional<std::string> root_cert_name; + absl::optional<std::string> identity_cert_name; + bool stop_watching_root_cert = false; + bool already_watching_identity_for_root_cert = false; + bool stop_watching_identity_cert = false; + bool already_watching_root_for_identity_cert = false; + // Update watchers_ and certificate_info_map_. + { + grpc_core::MutexLock lock(&mu_); + auto it = watchers_.find(watcher); + if (it == watchers_.end()) return; + WatcherInfo& watcher_info = it->second; + root_cert_name = std::move(watcher_info.root_cert_name); + identity_cert_name = std::move(watcher_info.identity_cert_name); + watchers_.erase(it); + if (root_cert_name.has_value()) { + auto it = certificate_info_map_.find(*root_cert_name); + GPR_ASSERT(it != certificate_info_map_.end()); + CertificateInfo& cert_info = it->second; + cert_info.root_cert_watchers.erase(watcher); + stop_watching_root_cert = cert_info.root_cert_watchers.empty(); + already_watching_identity_for_root_cert = + !cert_info.identity_cert_watchers.empty(); + if (stop_watching_root_cert && !already_watching_identity_for_root_cert) { + certificate_info_map_.erase(it); + } + } + if (identity_cert_name.has_value()) { + auto it = certificate_info_map_.find(*identity_cert_name); + GPR_ASSERT(it != certificate_info_map_.end()); + CertificateInfo& cert_info = it->second; + cert_info.identity_cert_watchers.erase(watcher); + stop_watching_identity_cert = cert_info.identity_cert_watchers.empty(); + already_watching_root_for_identity_cert = + !cert_info.root_cert_watchers.empty(); + if (stop_watching_identity_cert && + !already_watching_root_for_identity_cert) { + certificate_info_map_.erase(it); + } + } + } + // Invoke watch status callback if needed. + { + grpc_core::MutexLock lock(&callback_mu_); + if (watch_status_callback_ != nullptr) { + if (root_cert_name == identity_cert_name && + (stop_watching_root_cert || stop_watching_identity_cert)) { + watch_status_callback_(*root_cert_name, !stop_watching_root_cert, + !stop_watching_identity_cert); + } else { + if (stop_watching_root_cert) { + watch_status_callback_(*root_cert_name, false, + already_watching_identity_for_root_cert); + } + if (stop_watching_identity_cert) { + watch_status_callback_(*identity_cert_name, + already_watching_root_for_identity_cert, + false); + } + } + } + } +}; diff --git a/grpc/src/core/lib/security/credentials/tls/grpc_tls_certificate_distributor.h b/grpc/src/core/lib/security/credentials/tls/grpc_tls_certificate_distributor.h new file mode 100644 index 00000000..efc9e33e --- /dev/null +++ b/grpc/src/core/lib/security/credentials/tls/grpc_tls_certificate_distributor.h @@ -0,0 +1,214 @@ +// +// Copyright 2020 gRPC authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#ifndef GRPC_CORE_LIB_SECURITY_CREDENTIALS_TLS_GRPC_TLS_CERTIFICATE_DISTRIBUTOR_H +#define GRPC_CORE_LIB_SECURITY_CREDENTIALS_TLS_GRPC_TLS_CERTIFICATE_DISTRIBUTOR_H + +#include <grpc/support/port_platform.h> + +#include <grpc/grpc_security.h> + +#include "absl/container/inlined_vector.h" +#include "absl/types/optional.h" +#include "src/core/lib/gprpp/ref_counted.h" +#include "src/core/lib/security/security_connector/ssl_utils.h" + +// TLS certificate distributor. +struct grpc_tls_certificate_distributor + : public grpc_core::RefCounted<grpc_tls_certificate_distributor> { + public: + typedef absl::InlinedVector<grpc_core::PemKeyCertPair, 1> PemKeyCertPairList; + + // Interface for watching TLS certificates update. + class TlsCertificatesWatcherInterface { + public: + virtual ~TlsCertificatesWatcherInterface() = default; + + // Handles the delivery of the updated root and identity certificates. + // An absl::nullopt value indicates no corresponding contents for + // root_certs or key_cert_pairs. Note that we will send updates of the + // latest contents for both root and identity certificates, even when only + // one side of it got updated. + // + // @param root_certs the contents of the reloaded root certs. + // @param key_cert_pairs the contents of the reloaded identity key-cert + // pairs. + virtual void OnCertificatesChanged( + absl::optional<absl::string_view> root_certs, + absl::optional<PemKeyCertPairList> key_cert_pairs) = 0; + + // Handles an error that occurs while attempting to fetch certificate data. + // Note that if a watcher sees an error, it simply means the Provider is + // having problems renewing new data. If the watcher has previously received + // several OnCertificatesChanged, all the data received from that function + // is valid. + // In that case, watcher might simply log the error. If the watcher hasn't + // received any OnCertificatesChanged before the error occurs, no valid + // data is available yet, and the watcher should either fail or "waiting" + // for the valid data in a non-blocking way. + // + // @param root_cert_error the error occurred while reloading root + // certificates. + // @param identity_cert_error the error occurred while reloading identity + // certificates. + virtual void OnError(grpc_error* root_cert_error, + grpc_error* identity_cert_error) = 0; + }; + + // Sets the key materials based on their certificate name. Note that we are + // not doing any copies for pem_root_certs and pem_key_cert_pairs. For + // pem_root_certs, the original string contents need to outlive the + // distributor; for pem_key_cert_pairs, internally it is taking two + // unique_ptr(s) to the credential string, so the ownership is actually + // transferred. + // + // @param cert_name The name of the certificates being updated. + // @param pem_root_certs The content of root certificates. + // @param pem_key_cert_pairs The content of identity key-cert pairs. + void SetKeyMaterials(const std::string& cert_name, + absl::optional<std::string> pem_root_certs, + absl::optional<PemKeyCertPairList> pem_key_cert_pairs); + + bool HasRootCerts(const std::string& root_cert_name); + + bool HasKeyCertPairs(const std::string& identity_cert_name); + + // Propagates the error that the caller (e.g. Producer) encounters to all the + // watchers watching a particular certificate name. + // + // @param cert_name The watching cert name of the watchers that the caller + // wants to notify when encountering error. + // @param root_cert_error The error that the caller encounters when reloading + // root certs. + // @param identity_cert_error The error that the caller encounters when + // reloading identity certs. + void SetErrorForCert(const std::string& cert_name, + absl::optional<grpc_error*> root_cert_error, + absl::optional<grpc_error*> identity_cert_error); + + // Propagates the error that the caller (e.g. Producer) encounters to all + // watchers. + // + // @param error The error that the caller encounters. + void SetError(grpc_error* error); + + // Sets the TLS certificate watch status callback function. The + // grpc_tls_certificate_distributor will invoke this callback when a new + // certificate name is watched by a newly registered watcher, or when a + // certificate name is no longer watched by any watchers. + // Note that when the callback shows a cert is no longer being watched, the + // distributor will delete the corresponding certificate data from its cache, + // and clear the corresponding error, if there is any. This means that if the + // callback subsequently says the same cert is now being watched again, the + // provider must re-provide the credentials or re-invoke the errors to the + // distributor, to indicate a successful or failed reloading. + // @param callback The callback function being set by the caller, e.g the + // Producer. Note that this callback will be invoked for each certificate + // name. + // + // For the parameters in the callback function: + // string_value The name of the certificates being watched. + // bool_value_1 If the root certificates with the specific name are being + // watched. bool_value_2 If the identity certificates with the specific name + // are being watched. + void SetWatchStatusCallback( + std::function<void(std::string, bool, bool)> callback) { + grpc_core::MutexLock lock(&mu_); + watch_status_callback_ = callback; + }; + + // Registers a watcher. The caller may keep a raw pointer to the watcher, + // which may be used only for cancellation. (Because the caller does not own + // the watcher, the pointer must not be used for any other purpose.) At least + // one of root_cert_name and identity_cert_name must be specified. + // + // @param watcher The watcher being registered. + // @param root_cert_name The name of the root certificates that will be + // watched. If set to absl::nullopt, the root certificates won't be watched. + // @param identity_cert_name The name of the identity certificates that will + // be watched. If set to absl::nullopt, the identity certificates won't be + // watched. + void WatchTlsCertificates( + std::unique_ptr<TlsCertificatesWatcherInterface> watcher, + absl::optional<std::string> root_cert_name, + absl::optional<std::string> identity_cert_name); + + // Cancels a watcher. + // + // @param watcher The watcher being cancelled. + void CancelTlsCertificatesWatch(TlsCertificatesWatcherInterface* watcher); + + private: + // Contains the information about each watcher. + struct WatcherInfo { + std::unique_ptr<TlsCertificatesWatcherInterface> watcher; + absl::optional<std::string> root_cert_name; + absl::optional<std::string> identity_cert_name; + }; + // CertificateInfo contains the credential contents and some additional + // watcher information. + // Note that having errors doesn't indicate the corresponding credentials are + // invalid. For example, if root_cert_error != nullptr but pem_root_certs has + // value, it simply means an error occurs while trying to fetch the latest + // root certs, while pem_root_certs still contains the valid old data. + struct CertificateInfo { + // The contents of the root certificates. + std::string pem_root_certs; + // The contents of the identity key-certificate pairs. + PemKeyCertPairList pem_key_cert_pairs; + // The root cert reloading error propagated by the caller. + grpc_error* root_cert_error = GRPC_ERROR_NONE; + // The identity cert reloading error propagated by the caller. + grpc_error* identity_cert_error = GRPC_ERROR_NONE; + // The set of watchers watching root certificates. + // This is mainly used for quickly looking up the affected watchers while + // performing a credential reloading. + std::set<TlsCertificatesWatcherInterface*> root_cert_watchers; + // The set of watchers watching identity certificates. This is mainly used + // for quickly looking up the affected watchers while performing a + // credential reloading. + std::set<TlsCertificatesWatcherInterface*> identity_cert_watchers; + + ~CertificateInfo() { + GRPC_ERROR_UNREF(root_cert_error); + GRPC_ERROR_UNREF(identity_cert_error); + } + void SetRootError(grpc_error* error) { + GRPC_ERROR_UNREF(root_cert_error); + root_cert_error = error; + } + void SetIdentityError(grpc_error* error) { + GRPC_ERROR_UNREF(identity_cert_error); + identity_cert_error = error; + } + }; + + grpc_core::Mutex mu_; + // We need a dedicated mutex for watch_status_callback_ for allowing + // callers(e.g. Producer) to directly set key materials in the callback + // functions. + grpc_core::Mutex callback_mu_; + // Stores information about each watcher. + std::map<TlsCertificatesWatcherInterface*, WatcherInfo> watchers_; + // The callback to notify the caller, e.g. the Producer, that the watch status + // is changed. + std::function<void(std::string, bool, bool)> watch_status_callback_; + // Stores the names of each certificate, and their corresponding credential + // contents as well as some additional watcher information. + std::map<std::string, CertificateInfo> certificate_info_map_; +}; + +#endif // GRPC_CORE_LIB_SECURITY_CREDENTIALS_TLS_GRPC_TLS_CERTIFICATE_DISTRIBUTOR_H diff --git a/grpc/src/core/lib/security/credentials/tls/grpc_tls_credentials_options.h b/grpc/src/core/lib/security/credentials/tls/grpc_tls_credentials_options.h index c411fb2b..52a1218d 100644 --- a/grpc/src/core/lib/security/credentials/tls/grpc_tls_credentials_options.h +++ b/grpc/src/core/lib/security/credentials/tls/grpc_tls_credentials_options.h @@ -23,7 +23,8 @@ #include <grpc/grpc_security.h> -#include "src/core/lib/gprpp/inlined_vector.h" +#include "absl/container/inlined_vector.h" + #include "src/core/lib/gprpp/ref_counted.h" #include "src/core/lib/security/security_connector/ssl_utils.h" @@ -44,8 +45,7 @@ struct grpc_tls_error_details struct grpc_tls_key_materials_config : public grpc_core::RefCounted<grpc_tls_key_materials_config> { public: - typedef grpc_core::InlinedVector<grpc_core::PemKeyCertPair, 1> - PemKeyCertPairList; + typedef absl::InlinedVector<grpc_core::PemKeyCertPair, 1> PemKeyCertPairList; /** Getters for member fields. **/ const char* pem_root_certs() const { return pem_root_certs_.get(); } @@ -264,6 +264,8 @@ struct grpc_tls_credentials_options grpc_tls_server_verification_option server_verification_option() const { return server_verification_option_; } + grpc_tls_version min_tls_version() const { return min_tls_version_; } + grpc_tls_version max_tls_version() const { return max_tls_version_; } grpc_tls_key_materials_config* key_materials_config() const { return key_materials_config_.get(); } @@ -284,6 +286,12 @@ struct grpc_tls_credentials_options const grpc_tls_server_verification_option server_verification_option) { server_verification_option_ = server_verification_option; } + void set_min_tls_version(grpc_tls_version min_tls_version) { + min_tls_version_ = min_tls_version; + } + void set_max_tls_version(grpc_tls_version max_tls_version) { + max_tls_version_ = max_tls_version; + } void set_key_materials_config( grpc_core::RefCountedPtr<grpc_tls_key_materials_config> config) { key_materials_config_ = std::move(config); @@ -302,6 +310,8 @@ struct grpc_tls_credentials_options grpc_ssl_client_certificate_request_type cert_request_type_; grpc_tls_server_verification_option server_verification_option_ = GRPC_TLS_SERVER_VERIFICATION; + grpc_tls_version min_tls_version_ = grpc_tls_version::TLS1_2; + grpc_tls_version max_tls_version_ = grpc_tls_version::TLS1_3; grpc_core::RefCountedPtr<grpc_tls_key_materials_config> key_materials_config_; grpc_core::RefCountedPtr<grpc_tls_credential_reload_config> credential_reload_config_; diff --git a/grpc/src/core/lib/security/credentials/xds/xds_credentials.cc b/grpc/src/core/lib/security/credentials/xds/xds_credentials.cc new file mode 100644 index 00000000..682d49ba --- /dev/null +++ b/grpc/src/core/lib/security/credentials/xds/xds_credentials.cc @@ -0,0 +1,45 @@ +// +// +// Copyright 2020 gRPC authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// + +#include <grpc/support/port_platform.h> + +#include "src/core/lib/security/credentials/xds/xds_credentials.h" + +namespace grpc_core { + +constexpr const char XdsCredentials::kCredentialsTypeXds[]; + +grpc_core::RefCountedPtr<grpc_channel_security_connector> +XdsCredentials::create_security_connector( + grpc_core::RefCountedPtr<grpc_call_credentials> call_creds, + const char* target_name, const grpc_channel_args* args, + grpc_channel_args** new_args) { + /* TODO(yashkt) : To be filled */ + if (fallback_credentials_ != nullptr) { + return fallback_credentials_->create_security_connector( + std::move(call_creds), target_name, args, new_args); + } + return nullptr; +} + +} // namespace grpc_core + +grpc_channel_credentials* grpc_xds_credentials_create( + grpc_channel_credentials* fallback_credentials) { + return new grpc_core::XdsCredentials(fallback_credentials->Ref()); +} diff --git a/grpc/src/core/lib/security/credentials/xds/xds_credentials.h b/grpc/src/core/lib/security/credentials/xds/xds_credentials.h new file mode 100644 index 00000000..51576dee --- /dev/null +++ b/grpc/src/core/lib/security/credentials/xds/xds_credentials.h @@ -0,0 +1,51 @@ +// +// +// Copyright 2020 gRPC authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// + +#ifndef GRPC_CORE_LIB_SECURITY_CREDENTIALS_XDS_XDS_CREDENTIALS_H +#define GRPC_CORE_LIB_SECURITY_CREDENTIALS_XDS_XDS_CREDENTIALS_H + +#include <grpc/support/port_platform.h> + +#include <grpc/grpc_security.h> + +#include "src/core/lib/security/credentials/credentials.h" + +namespace grpc_core { + +class XdsCredentials final : public grpc_channel_credentials { + public: + static constexpr const char kCredentialsTypeXds[] = "Xds"; + + explicit XdsCredentials( + grpc_core::RefCountedPtr<grpc_channel_credentials> fallback_credentials) + : grpc_channel_credentials(kCredentialsTypeXds), + fallback_credentials_(std::move(fallback_credentials)) {} + + grpc_core::RefCountedPtr<grpc_channel_security_connector> + create_security_connector( + grpc_core::RefCountedPtr<grpc_call_credentials> call_creds, + const char* target_name, const grpc_channel_args* args, + grpc_channel_args** new_args) override; + + private: + grpc_core::RefCountedPtr<grpc_channel_credentials> fallback_credentials_; +}; + +} // namespace grpc_core + +#endif /* GRPC_CORE_LIB_SECURITY_CREDENTIALS_XDS_XDS_CREDENTIALS_H */ |