kmscng/provider.cc (102 lines of code) (raw):

// Copyright 2023 Google LLC // // 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 "kmscng/provider.h" #include <cwchar> #include "absl/container/flat_hash_set.h" #include "common/status_macros.h" #include "kmscng/cng_headers.h" #include "kmscng/util/errors.h" #include "kmscng/util/status_utils.h" #include "kmscng/util/string_utils.h" #include "kmscng/version.h" namespace cloud_kms::kmscng { namespace { static_assert(std::numeric_limits<NCRYPT_PROV_HANDLE>::max == std::numeric_limits<ULONG_PTR>::max, "NCRYPT_PROV_HANDLE width mismatches pointer width."); absl::flat_hash_set<std::wstring> mutable_properties = { {kEndpointAddressProperty.data()}, {kChannelCredentialsProperty.data()}, {kUserProjectProperty.data()}, }; absl::flat_hash_map<std::wstring, std::string> BuildInfo() { const char* env_endpoint_address = std::getenv(kEndpointAddressEnvVariable); std::string endpoint_address = env_endpoint_address ? env_endpoint_address : "cloudkms.googleapis.com:443"; const char* env_channel_credentials = std::getenv(kChannelCredentialsEnvVariable); std::string channel_credentials = env_channel_credentials ? env_channel_credentials : "default"; const char* env_user_project = std::getenv(kUserProjectEnvVariable); std::string user_project = env_user_project ? env_user_project : ""; return { {NCRYPT_IMPL_TYPE_PROPERTY, Uint32ToBytes(NCRYPT_IMPL_HARDWARE_FLAG)}, {NCRYPT_VERSION_PROPERTY, Uint32ToBytes(kLibraryVersionHex)}, {std::wstring(kEndpointAddressProperty), endpoint_address}, {std::wstring(kChannelCredentialsProperty), channel_credentials}, {std::wstring(kUserProjectProperty), user_project}, }; } } // namespace absl::StatusOr<std::unique_ptr<KmsClient>> NewKmsClient( NCRYPT_PROV_HANDLE prov_handle) { ASSIGN_OR_RETURN(Provider * prov, ValidateProviderHandle(prov_handle)); KmsClient::Options options; ASSIGN_OR_RETURN(options.endpoint_address, prov->GetProperty(kEndpointAddressProperty)); ASSIGN_OR_RETURN(std::string_view creds_type, prov->GetProperty(kChannelCredentialsProperty)); options.creds = (creds_type == "insecure") ? grpc::InsecureChannelCredentials() : grpc::GoogleDefaultCredentials(); if (!options.creds) { return NewError(absl::StatusCode::kInvalidArgument, "Invalid Application Default Credentials. See " "https://cloud.google.com/docs/authentication/" "external/about-adc", NTE_INVALID_PARAMETER, SOURCE_LOCATION); } ASSIGN_OR_RETURN(options.user_project_override, prov->GetProperty(kUserProjectProperty)); options.rpc_timeout = absl::Seconds(30); options.version_major = kLibraryVersionMajor; options.version_minor = kLibraryVersionMinor; options.user_agent = UserAgent::kCng; options.error_decorator = [](absl::Status& status) { SetErrorSs(status, NTE_INTERNAL_ERROR); }; return std::make_unique<KmsClient>(options); } absl::StatusOr<Provider*> ValidateProviderHandle( NCRYPT_PROV_HANDLE prov_handle) { if (prov_handle == 0) { return NewInvalidArgumentError("The provider handle cannot be null", NTE_INVALID_HANDLE, SOURCE_LOCATION); } return reinterpret_cast<Provider*>(prov_handle); } Provider::Provider() : provider_info_(BuildInfo()) {} absl::StatusOr<std::string_view> Provider::GetProperty(std::wstring_view name) { auto it = provider_info_.find(name); if (it == provider_info_.end()) { return NewError(absl::StatusCode::kNotFound, "unsupported property specified", NTE_NOT_SUPPORTED, SOURCE_LOCATION); } return it->second; } absl::Status Provider::SetProperty(std::wstring_view name, std::string_view value) { auto it = provider_info_.find(name); if (it == provider_info_.end()) { return NewError(absl::StatusCode::kNotFound, "unsupported property specified", NTE_NOT_SUPPORTED, SOURCE_LOCATION); } if (!mutable_properties.contains(name)) { return NewInvalidArgumentError("the specified property cannot be updated", NTE_INVALID_PARAMETER, SOURCE_LOCATION); } it->second = value; return absl::OkStatus(); } } // namespace cloud_kms::kmscng