mirror of https://github.com/grpc/grpc.git
Merge branch 'master' of https://github.com/grpc/grpc into channel-tracing
commit
0c6024b94d
147 changed files with 22497 additions and 674 deletions
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,119 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2018 gRPC authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
* |
||||
*/ |
||||
|
||||
#include <grpc/support/port_platform.h> |
||||
|
||||
#include "src/core/lib/security/credentials/alts/alts_credentials.h" |
||||
|
||||
#include <cstring> |
||||
|
||||
#include <grpc/grpc.h> |
||||
#include <grpc/support/alloc.h> |
||||
#include <grpc/support/log.h> |
||||
#include <grpc/support/string_util.h> |
||||
|
||||
#include "src/core/lib/security/credentials/alts/check_gcp_environment.h" |
||||
#include "src/core/lib/security/security_connector/alts_security_connector.h" |
||||
|
||||
#define GRPC_CREDENTIALS_TYPE_ALTS "Alts" |
||||
#define GRPC_ALTS_HANDSHAKER_SERVICE_URL "metadata.google.internal:8080" |
||||
|
||||
static void alts_credentials_destruct(grpc_channel_credentials* creds) { |
||||
grpc_alts_credentials* alts_creds = |
||||
reinterpret_cast<grpc_alts_credentials*>(creds); |
||||
grpc_alts_credentials_options_destroy(alts_creds->options); |
||||
gpr_free(alts_creds->handshaker_service_url); |
||||
} |
||||
|
||||
static void alts_server_credentials_destruct(grpc_server_credentials* creds) { |
||||
grpc_alts_server_credentials* alts_creds = |
||||
reinterpret_cast<grpc_alts_server_credentials*>(creds); |
||||
grpc_alts_credentials_options_destroy(alts_creds->options); |
||||
gpr_free(alts_creds->handshaker_service_url); |
||||
} |
||||
|
||||
static grpc_security_status alts_create_security_connector( |
||||
grpc_channel_credentials* creds, |
||||
grpc_call_credentials* request_metadata_creds, const char* target_name, |
||||
const grpc_channel_args* args, grpc_channel_security_connector** sc, |
||||
grpc_channel_args** new_args) { |
||||
return grpc_alts_channel_security_connector_create( |
||||
creds, request_metadata_creds, target_name, sc); |
||||
} |
||||
|
||||
static grpc_security_status alts_server_create_security_connector( |
||||
grpc_server_credentials* creds, grpc_server_security_connector** sc) { |
||||
return grpc_alts_server_security_connector_create(creds, sc); |
||||
} |
||||
|
||||
static const grpc_channel_credentials_vtable alts_credentials_vtable = { |
||||
alts_credentials_destruct, alts_create_security_connector, |
||||
/*duplicate_without_call_credentials=*/nullptr}; |
||||
|
||||
static const grpc_server_credentials_vtable alts_server_credentials_vtable = { |
||||
alts_server_credentials_destruct, alts_server_create_security_connector}; |
||||
|
||||
grpc_channel_credentials* grpc_alts_credentials_create_customized( |
||||
const grpc_alts_credentials_options* options, |
||||
const char* handshaker_service_url, bool enable_untrusted_alts) { |
||||
if (!enable_untrusted_alts && !grpc_alts_is_running_on_gcp()) { |
||||
return nullptr; |
||||
} |
||||
auto creds = static_cast<grpc_alts_credentials*>( |
||||
gpr_zalloc(sizeof(grpc_alts_credentials))); |
||||
creds->options = grpc_alts_credentials_options_copy(options); |
||||
creds->handshaker_service_url = |
||||
handshaker_service_url == nullptr |
||||
? gpr_strdup(GRPC_ALTS_HANDSHAKER_SERVICE_URL) |
||||
: gpr_strdup(handshaker_service_url); |
||||
creds->base.type = GRPC_CREDENTIALS_TYPE_ALTS; |
||||
creds->base.vtable = &alts_credentials_vtable; |
||||
gpr_ref_init(&creds->base.refcount, 1); |
||||
return &creds->base; |
||||
} |
||||
|
||||
grpc_server_credentials* grpc_alts_server_credentials_create_customized( |
||||
const grpc_alts_credentials_options* options, |
||||
const char* handshaker_service_url, bool enable_untrusted_alts) { |
||||
if (!enable_untrusted_alts && !grpc_alts_is_running_on_gcp()) { |
||||
return nullptr; |
||||
} |
||||
auto creds = static_cast<grpc_alts_server_credentials*>( |
||||
gpr_zalloc(sizeof(grpc_alts_server_credentials))); |
||||
creds->options = grpc_alts_credentials_options_copy(options); |
||||
creds->handshaker_service_url = |
||||
handshaker_service_url == nullptr |
||||
? gpr_strdup(GRPC_ALTS_HANDSHAKER_SERVICE_URL) |
||||
: gpr_strdup(handshaker_service_url); |
||||
creds->base.type = GRPC_CREDENTIALS_TYPE_ALTS; |
||||
creds->base.vtable = &alts_server_credentials_vtable; |
||||
gpr_ref_init(&creds->base.refcount, 1); |
||||
return &creds->base; |
||||
} |
||||
|
||||
grpc_channel_credentials* grpc_alts_credentials_create( |
||||
const grpc_alts_credentials_options* options) { |
||||
return grpc_alts_credentials_create_customized( |
||||
options, GRPC_ALTS_HANDSHAKER_SERVICE_URL, false); |
||||
} |
||||
|
||||
grpc_server_credentials* grpc_alts_server_credentials_create( |
||||
const grpc_alts_credentials_options* options) { |
||||
return grpc_alts_server_credentials_create_customized( |
||||
options, GRPC_ALTS_HANDSHAKER_SERVICE_URL, false); |
||||
} |
@ -0,0 +1,102 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2018 gRPC authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
* |
||||
*/ |
||||
|
||||
#ifndef GRPC_CORE_LIB_SECURITY_CREDENTIALS_ALTS_ALTS_CREDENTIALS_H |
||||
#define GRPC_CORE_LIB_SECURITY_CREDENTIALS_ALTS_ALTS_CREDENTIALS_H |
||||
|
||||
#include <grpc/support/port_platform.h> |
||||
|
||||
#include <grpc/grpc_security.h> |
||||
|
||||
#include "src/core/lib/security/credentials/alts/grpc_alts_credentials_options.h" |
||||
#include "src/core/lib/security/credentials/credentials.h" |
||||
|
||||
/* Main struct for grpc ALTS channel credential. */ |
||||
typedef struct grpc_alts_credentials { |
||||
grpc_channel_credentials base; |
||||
grpc_alts_credentials_options* options; |
||||
char* handshaker_service_url; |
||||
} grpc_alts_credentials; |
||||
|
||||
/* Main struct for grpc ALTS server credential. */ |
||||
typedef struct grpc_alts_server_credentials { |
||||
grpc_server_credentials base; |
||||
grpc_alts_credentials_options* options; |
||||
char* handshaker_service_url; |
||||
} grpc_alts_server_credentials; |
||||
|
||||
/**
|
||||
* This method creates an ALTS channel credential object. |
||||
* |
||||
* - options: grpc ALTS credentials options instance for client. |
||||
* |
||||
* It returns the created ALTS channel credential object. |
||||
*/ |
||||
grpc_channel_credentials* grpc_alts_credentials_create( |
||||
const grpc_alts_credentials_options* options); |
||||
|
||||
/**
|
||||
* This method creates an ALTS server credential object. |
||||
* |
||||
* - options: grpc ALTS credentials options instance for server. |
||||
* |
||||
* It returns the created ALTS server credential object. |
||||
*/ |
||||
grpc_server_credentials* grpc_alts_server_credentials_create( |
||||
const grpc_alts_credentials_options* options); |
||||
|
||||
/**
|
||||
* This method creates an ALTS channel credential object with customized |
||||
* information provided by caller. |
||||
* |
||||
* - options: grpc ALTS credentials options instance for client. |
||||
* - handshaker_service_url: address of ALTS handshaker service in the format of |
||||
* "host:port". If it's nullptr, the address of default metadata server will |
||||
* be used. |
||||
* - enable_untrusted_alts: a boolean flag used to enable ALTS in untrusted |
||||
* mode. This mode can be enabled when we are sure ALTS is running on GCP or |
||||
* for testing purpose. |
||||
* |
||||
* It returns nullptr if the flag is disabled AND ALTS is not running on GCP. |
||||
* Otherwise, it returns the created credential object. |
||||
*/ |
||||
|
||||
grpc_channel_credentials* grpc_alts_credentials_create_customized( |
||||
const grpc_alts_credentials_options* options, |
||||
const char* handshaker_service_url, bool enable_untrusted_alts); |
||||
|
||||
/**
|
||||
* This method creates an ALTS server credential object with customized |
||||
* information provided by caller. |
||||
* |
||||
* - options: grpc ALTS credentials options instance for server. |
||||
* - handshaker_service_url: address of ALTS handshaker service in the format of |
||||
* "host:port". If it's nullptr, the address of default metadata server will |
||||
* be used. |
||||
* - enable_untrusted_alts: a boolean flag used to enable ALTS in untrusted |
||||
* mode. This mode can be enabled when we are sure ALTS is running on GCP or |
||||
* for testing purpose. |
||||
* |
||||
* It returns nullptr if the flag is disabled and ALTS is not running on GCP. |
||||
* Otherwise, it returns the created credential object. |
||||
*/ |
||||
grpc_server_credentials* grpc_alts_server_credentials_create_customized( |
||||
const grpc_alts_credentials_options* options, |
||||
const char* handshaker_service_url, bool enable_untrusted_alts); |
||||
|
||||
#endif /* GRPC_CORE_LIB_SECURITY_CREDENTIALS_ALTS_ALTS_CREDENTIALS_H */ |
@ -0,0 +1,72 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2018 gRPC authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
* |
||||
*/ |
||||
|
||||
#include <grpc/support/port_platform.h> |
||||
|
||||
#include "src/core/lib/security/credentials/alts/check_gcp_environment.h" |
||||
|
||||
#include <ctype.h> |
||||
#include <stdio.h> |
||||
#include <string.h> |
||||
|
||||
#include <grpc/support/alloc.h> |
||||
#include <grpc/support/log.h> |
||||
|
||||
const size_t kBiosDataBufferSize = 256; |
||||
|
||||
static char* trim(const char* src) { |
||||
if (src == nullptr) { |
||||
return nullptr; |
||||
} |
||||
char* des = nullptr; |
||||
size_t start = 0, end = strlen(src) - 1; |
||||
/* find the last character that is not a whitespace. */ |
||||
while (end != 0 && isspace(src[end])) { |
||||
end--; |
||||
} |
||||
/* find the first character that is not a whitespace. */ |
||||
while (start < strlen(src) && isspace(src[start])) { |
||||
start++; |
||||
} |
||||
if (start <= end) { |
||||
des = static_cast<char*>( |
||||
gpr_zalloc(sizeof(char) * (end - start + 2 /* '\0' */))); |
||||
memcpy(des, src + start, end - start + 1); |
||||
} |
||||
return des; |
||||
} |
||||
|
||||
namespace grpc_core { |
||||
namespace internal { |
||||
|
||||
char* read_bios_file(const char* bios_file) { |
||||
FILE* fp = fopen(bios_file, "r"); |
||||
if (!fp) { |
||||
gpr_log(GPR_ERROR, "BIOS data file cannot be opened."); |
||||
return nullptr; |
||||
} |
||||
char buf[kBiosDataBufferSize + 1]; |
||||
size_t ret = fread(buf, sizeof(char), kBiosDataBufferSize, fp); |
||||
buf[ret] = '\0'; |
||||
char* trimmed_buf = trim(buf); |
||||
fclose(fp); |
||||
return trimmed_buf; |
||||
} |
||||
|
||||
} // namespace internal
|
||||
} // namespace grpc_core
|
@ -0,0 +1,57 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2018 gRPC authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
* |
||||
*/ |
||||
|
||||
#ifndef GRPC_CORE_LIB_SECURITY_CREDENTIALS_ALTS_CHECK_GCP_ENVIRONMENT_H |
||||
#define GRPC_CORE_LIB_SECURITY_CREDENTIALS_ALTS_CHECK_GCP_ENVIRONMENT_H |
||||
|
||||
namespace grpc_core { |
||||
namespace internal { |
||||
|
||||
/**
|
||||
* This method is a helper function that reads a file containing system bios |
||||
* data. Exposed for testing only. |
||||
* |
||||
* - bios_file: a file containing BIOS data used to determine GCE tenancy |
||||
* information. |
||||
* |
||||
* It returns a buffer containing the data read from the file. |
||||
*/ |
||||
char* read_bios_file(const char* bios_file); |
||||
|
||||
/**
|
||||
* This method checks if system BIOS data contains Google-specific phrases. |
||||
* Exposed for testing only. |
||||
* |
||||
* - bios_data: a buffer containing system BIOS data. |
||||
* |
||||
* It returns true if the BIOS data contains Google-specific phrases, and false |
||||
* otherwise. |
||||
*/ |
||||
bool check_bios_data(const char* bios_data); |
||||
|
||||
} // namespace internal
|
||||
} // namespace grpc_core
|
||||
|
||||
/**
|
||||
* This method checks if a VM (Windows or Linux) is running within Google |
||||
* compute Engine (GCE) or not. It returns true if the VM is running in GCE and |
||||
* false otherwise. |
||||
*/ |
||||
bool grpc_alts_is_running_on_gcp(); |
||||
|
||||
#endif /* GRPC_CORE_LIB_SECURITY_CREDENTIALS_ALTS_CHECK_GCP_ENVIRONMENT_H */ |
@ -0,0 +1,67 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2018 gRPC authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
* |
||||
*/ |
||||
|
||||
#include <grpc/support/port_platform.h> |
||||
|
||||
#ifdef GPR_LINUX |
||||
|
||||
#include "src/core/lib/security/credentials/alts/check_gcp_environment.h" |
||||
|
||||
#include <grpc/support/alloc.h> |
||||
#include <grpc/support/sync.h> |
||||
|
||||
#include <string.h> |
||||
|
||||
#define GRPC_ALTS_EXPECT_NAME_GOOGLE "Google" |
||||
#define GRPC_ALTS_EXPECT_NAME_GCE "Google Compute Engine" |
||||
#define GRPC_ALTS_PRODUCT_NAME_FILE "/sys/class/dmi/id/product_name" |
||||
|
||||
static bool g_compute_engine_detection_done = false; |
||||
static bool g_is_on_compute_engine = false; |
||||
static gpr_mu g_mu; |
||||
static gpr_once g_once = GPR_ONCE_INIT; |
||||
|
||||
namespace grpc_core { |
||||
namespace internal { |
||||
|
||||
bool check_bios_data(const char* bios_data_file) { |
||||
char* bios_data = read_bios_file(bios_data_file); |
||||
bool result = (!strcmp(bios_data, GRPC_ALTS_EXPECT_NAME_GOOGLE)) || |
||||
(!strcmp(bios_data, GRPC_ALTS_EXPECT_NAME_GCE)); |
||||
gpr_free(bios_data); |
||||
return result; |
||||
} |
||||
|
||||
} // namespace internal
|
||||
} // namespace grpc_core
|
||||
|
||||
static void init_mu(void) { gpr_mu_init(&g_mu); } |
||||
|
||||
bool grpc_alts_is_running_on_gcp() { |
||||
gpr_once_init(&g_once, init_mu); |
||||
gpr_mu_lock(&g_mu); |
||||
if (!g_compute_engine_detection_done) { |
||||
g_is_on_compute_engine = |
||||
grpc_core::internal::check_bios_data(GRPC_ALTS_PRODUCT_NAME_FILE); |
||||
g_compute_engine_detection_done = true; |
||||
} |
||||
gpr_mu_unlock(&g_mu); |
||||
return g_is_on_compute_engine; |
||||
} |
||||
|
||||
#endif // GPR_LINUX
|
@ -0,0 +1,33 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2018 gRPC authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
* |
||||
*/ |
||||
|
||||
#include <grpc/support/port_platform.h> |
||||
|
||||
#if !defined(GPR_LINUX) && !defined(GPR_WINDOWS) |
||||
|
||||
#include "src/core/lib/security/credentials/alts/check_gcp_environment.h" |
||||
|
||||
#include <grpc/support/log.h> |
||||
|
||||
bool grpc_alts_is_running_on_gcp() { |
||||
gpr_log(GPR_ERROR, |
||||
"Platforms other than Linux and Windows are not supported"); |
||||
return false; |
||||
} |
||||
|
||||
#endif // !defined(LINUX) && !defined(GPR_WINDOWS)
|
@ -0,0 +1,114 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2018 gRPC authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
* |
||||
*/ |
||||
|
||||
#include <grpc/support/port_platform.h> |
||||
|
||||
#ifdef GPR_WINDOWS |
||||
|
||||
#include "src/core/lib/security/credentials/alts/check_gcp_environment.h" |
||||
|
||||
#include <shellapi.h> |
||||
#include <stdio.h> |
||||
#include <tchar.h> |
||||
#include <windows.h> |
||||
|
||||
#include <grpc/support/alloc.h> |
||||
#include <grpc/support/log.h> |
||||
#include <grpc/support/sync.h> |
||||
|
||||
#define GRPC_ALTS_EXPECT_NAME_GOOGLE "Google" |
||||
#define GRPC_ALTS_WINDOWS_CHECK_COMMAND "powershell.exe" |
||||
#define GRPC_ALTS_WINDOWS_CHECK_COMMAND_ARGS \ |
||||
"(Get-WmiObject -Class Win32_BIOS).Manufacturer" |
||||
#define GRPC_ALTS_WINDOWS_CHECK_BIOS_FILE "windows_bios.data" |
||||
|
||||
const size_t kBiosDataBufferSize = 256; |
||||
|
||||
static bool g_compute_engine_detection_done = false; |
||||
static bool g_is_on_compute_engine = false; |
||||
static gpr_mu g_mu; |
||||
static gpr_once g_once = GPR_ONCE_INIT; |
||||
|
||||
namespace grpc_core { |
||||
namespace internal { |
||||
|
||||
bool check_bios_data(const char* bios_data_file) { |
||||
char* bios_data = read_bios_file(bios_data_file); |
||||
bool result = !strcmp(bios_data, GRPC_ALTS_EXPECT_NAME_GOOGLE); |
||||
remove(GRPC_ALTS_WINDOWS_CHECK_BIOS_FILE); |
||||
gpr_free(bios_data); |
||||
return result; |
||||
} |
||||
|
||||
} // namespace internal
|
||||
} // namespace grpc_core
|
||||
|
||||
static void init_mu(void) { gpr_mu_init(&g_mu); } |
||||
|
||||
static bool run_powershell() { |
||||
SECURITY_ATTRIBUTES sa; |
||||
sa.nLength = sizeof(sa); |
||||
sa.lpSecurityDescriptor = NULL; |
||||
sa.bInheritHandle = TRUE; |
||||
HANDLE h = CreateFile(_T(GRPC_ALTS_WINDOWS_CHECK_BIOS_FILE), GENERIC_WRITE, |
||||
FILE_SHARE_WRITE | FILE_SHARE_READ, &sa, OPEN_ALWAYS, |
||||
FILE_ATTRIBUTE_NORMAL, NULL); |
||||
if (h == INVALID_HANDLE_VALUE) { |
||||
gpr_log(GPR_ERROR, "CreateFile failed (%d).", GetLastError()); |
||||
return false; |
||||
} |
||||
PROCESS_INFORMATION pi; |
||||
STARTUPINFO si; |
||||
DWORD flags = CREATE_NO_WINDOW; |
||||
ZeroMemory(&pi, sizeof(pi)); |
||||
ZeroMemory(&si, sizeof(si)); |
||||
si.cb = sizeof(si); |
||||
si.dwFlags |= STARTF_USESTDHANDLES; |
||||
si.hStdInput = NULL; |
||||
si.hStdError = h; |
||||
si.hStdOutput = h; |
||||
TCHAR cmd[kBiosDataBufferSize]; |
||||
_sntprintf(cmd, kBiosDataBufferSize, _T("%s %s"), |
||||
_T(GRPC_ALTS_WINDOWS_CHECK_COMMAND), |
||||
_T(GRPC_ALTS_WINDOWS_CHECK_COMMAND_ARGS)); |
||||
if (!CreateProcess(NULL, cmd, NULL, NULL, TRUE, flags, NULL, NULL, &si, |
||||
&pi)) { |
||||
gpr_log(GPR_ERROR, "CreateProcess failed (%d).\n", GetLastError()); |
||||
return false; |
||||
} |
||||
WaitForSingleObject(pi.hProcess, INFINITE); |
||||
CloseHandle(pi.hProcess); |
||||
CloseHandle(pi.hThread); |
||||
CloseHandle(h); |
||||
return true; |
||||
} |
||||
|
||||
bool grpc_alts_is_running_on_gcp() { |
||||
gpr_once_init(&g_once, init_mu); |
||||
gpr_mu_lock(&g_mu); |
||||
if (!g_compute_engine_detection_done) { |
||||
g_is_on_compute_engine = |
||||
run_powershell() && |
||||
grpc_core::internal::check_bios_data(GRPC_ALTS_WINDOWS_CHECK_BIOS_FILE); |
||||
g_compute_engine_detection_done = true; |
||||
} |
||||
gpr_mu_unlock(&g_mu); |
||||
return g_is_on_compute_engine; |
||||
} |
||||
|
||||
#endif // GPR_WINDOWS
|
@ -0,0 +1,126 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2018 gRPC authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
* |
||||
*/ |
||||
|
||||
#include <grpc/support/port_platform.h> |
||||
|
||||
#include <stdlib.h> |
||||
#include <string.h> |
||||
|
||||
#include <grpc/support/alloc.h> |
||||
#include <grpc/support/log.h> |
||||
#include <grpc/support/string_util.h> |
||||
|
||||
#include "src/core/lib/security/credentials/alts/grpc_alts_credentials_options.h" |
||||
#include "src/core/tsi/alts/handshaker/transport_security_common_api.h" |
||||
|
||||
static grpc_alts_credentials_options* alts_client_options_copy( |
||||
const grpc_alts_credentials_options* options); |
||||
|
||||
static void alts_client_options_destroy(grpc_alts_credentials_options* options); |
||||
|
||||
static target_service_account* target_service_account_create( |
||||
const char* service_account) { |
||||
if (service_account == nullptr) { |
||||
return nullptr; |
||||
} |
||||
auto* sa = static_cast<target_service_account*>( |
||||
gpr_zalloc(sizeof(target_service_account))); |
||||
sa->data = gpr_strdup(service_account); |
||||
return sa; |
||||
} |
||||
|
||||
bool grpc_alts_credentials_client_options_add_target_service_account( |
||||
grpc_alts_credentials_client_options* options, |
||||
const char* service_account) { |
||||
if (options == nullptr || service_account == nullptr) { |
||||
gpr_log( |
||||
GPR_ERROR, |
||||
"Invalid nullptr arguments to " |
||||
"grpc_alts_credentials_client_options_add_target_service_account()"); |
||||
return false; |
||||
} |
||||
target_service_account* node = target_service_account_create(service_account); |
||||
node->next = options->target_account_list_head; |
||||
options->target_account_list_head = node; |
||||
return true; |
||||
} |
||||
|
||||
static void target_service_account_destroy( |
||||
target_service_account* service_account) { |
||||
if (service_account == nullptr) { |
||||
return; |
||||
} |
||||
gpr_free(service_account->data); |
||||
gpr_free(service_account); |
||||
} |
||||
|
||||
static const grpc_alts_credentials_options_vtable vtable = { |
||||
alts_client_options_copy, alts_client_options_destroy}; |
||||
|
||||
grpc_alts_credentials_options* grpc_alts_credentials_client_options_create() { |
||||
auto client_options = static_cast<grpc_alts_credentials_client_options*>( |
||||
gpr_zalloc(sizeof(grpc_alts_credentials_client_options))); |
||||
client_options->base.vtable = &vtable; |
||||
return &client_options->base; |
||||
} |
||||
|
||||
static grpc_alts_credentials_options* alts_client_options_copy( |
||||
const grpc_alts_credentials_options* options) { |
||||
if (options == nullptr) { |
||||
return nullptr; |
||||
} |
||||
grpc_alts_credentials_options* new_options = |
||||
grpc_alts_credentials_client_options_create(); |
||||
auto new_client_options = |
||||
reinterpret_cast<grpc_alts_credentials_client_options*>(new_options); |
||||
/* Copy target service accounts. */ |
||||
target_service_account* prev = nullptr; |
||||
auto node = |
||||
(reinterpret_cast<const grpc_alts_credentials_client_options*>(options)) |
||||
->target_account_list_head; |
||||
while (node != nullptr) { |
||||
target_service_account* new_node = |
||||
target_service_account_create(node->data); |
||||
if (prev == nullptr) { |
||||
new_client_options->target_account_list_head = new_node; |
||||
} else { |
||||
prev->next = new_node; |
||||
} |
||||
prev = new_node; |
||||
node = node->next; |
||||
} |
||||
/* Copy rpc protocol versions. */ |
||||
grpc_gcp_rpc_protocol_versions_copy(&options->rpc_versions, |
||||
&new_options->rpc_versions); |
||||
return new_options; |
||||
} |
||||
|
||||
static void alts_client_options_destroy( |
||||
grpc_alts_credentials_options* options) { |
||||
if (options == nullptr) { |
||||
return; |
||||
} |
||||
auto* client_options = |
||||
reinterpret_cast<grpc_alts_credentials_client_options*>(options); |
||||
target_service_account* node = client_options->target_account_list_head; |
||||
while (node != nullptr) { |
||||
target_service_account* next_node = node->next; |
||||
target_service_account_destroy(node); |
||||
node = next_node; |
||||
} |
||||
} |
@ -0,0 +1,46 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2018 gRPC authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
* |
||||
*/ |
||||
|
||||
#include <grpc/support/port_platform.h> |
||||
|
||||
#include "src/core/lib/security/credentials/alts/grpc_alts_credentials_options.h" |
||||
|
||||
#include <grpc/support/alloc.h> |
||||
#include <grpc/support/log.h> |
||||
|
||||
grpc_alts_credentials_options* grpc_alts_credentials_options_copy( |
||||
const grpc_alts_credentials_options* options) { |
||||
if (options != nullptr && options->vtable != nullptr && |
||||
options->vtable->copy != nullptr) { |
||||
return options->vtable->copy(options); |
||||
} |
||||
/* An error occurred. */ |
||||
gpr_log(GPR_ERROR, |
||||
"Invalid arguments to grpc_alts_credentials_options_copy()"); |
||||
return nullptr; |
||||
} |
||||
|
||||
void grpc_alts_credentials_options_destroy( |
||||
grpc_alts_credentials_options* options) { |
||||
if (options != nullptr) { |
||||
if (options->vtable != nullptr && options->vtable->destruct != nullptr) { |
||||
options->vtable->destruct(options); |
||||
} |
||||
gpr_free(options); |
||||
} |
||||
} |
@ -0,0 +1,112 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2018 gRPC authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
* |
||||
*/ |
||||
|
||||
#ifndef GRPC_CORE_LIB_SECURITY_CREDENTIALS_ALTS_GRPC_ALTS_CREDENTIALS_OPTIONS_H |
||||
#define GRPC_CORE_LIB_SECURITY_CREDENTIALS_ALTS_GRPC_ALTS_CREDENTIALS_OPTIONS_H |
||||
|
||||
#include <grpc/support/port_platform.h> |
||||
|
||||
#include <stdbool.h> |
||||
|
||||
#include "src/core/tsi/alts/handshaker/transport_security_common_api.h" |
||||
|
||||
/**
|
||||
* Main interface for ALTS credentials options. The options will contain |
||||
* information that will be passed from grpc to TSI layer such as RPC protocol |
||||
* versions. ALTS client (channel) and server credentials will have their own |
||||
* implementation of this interface. The APIs listed in this header are |
||||
* thread-compatible. |
||||
*/ |
||||
typedef struct grpc_alts_credentials_options grpc_alts_credentials_options; |
||||
|
||||
/* V-table for grpc_alts_credentials_options */ |
||||
typedef struct grpc_alts_credentials_options_vtable { |
||||
grpc_alts_credentials_options* (*copy)( |
||||
const grpc_alts_credentials_options* options); |
||||
void (*destruct)(grpc_alts_credentials_options* options); |
||||
} grpc_alts_credentials_options_vtable; |
||||
|
||||
struct grpc_alts_credentials_options { |
||||
const struct grpc_alts_credentials_options_vtable* vtable; |
||||
grpc_gcp_rpc_protocol_versions rpc_versions; |
||||
}; |
||||
|
||||
typedef struct target_service_account { |
||||
struct target_service_account* next; |
||||
char* data; |
||||
} target_service_account; |
||||
|
||||
/**
|
||||
* Main struct for ALTS client credentials options. The options contain a |
||||
* a list of target service accounts (if specified) used for secure naming |
||||
* check. |
||||
*/ |
||||
typedef struct grpc_alts_credentials_client_options { |
||||
grpc_alts_credentials_options base; |
||||
target_service_account* target_account_list_head; |
||||
} grpc_alts_credentials_client_options; |
||||
|
||||
/**
|
||||
* Main struct for ALTS server credentials options. The options currently |
||||
* do not contain any server-specific fields. |
||||
*/ |
||||
typedef struct grpc_alts_credentials_server_options { |
||||
grpc_alts_credentials_options base; |
||||
} grpc_alts_credentials_server_options; |
||||
|
||||
/**
|
||||
* This method performs a deep copy on grpc_alts_credentials_options instance. |
||||
* |
||||
* - options: a grpc_alts_credentials_options instance that needs to be copied. |
||||
* |
||||
* It returns a new grpc_alts_credentials_options instance on success and NULL |
||||
* on failure. |
||||
*/ |
||||
grpc_alts_credentials_options* grpc_alts_credentials_options_copy( |
||||
const grpc_alts_credentials_options* options); |
||||
|
||||
/**
|
||||
* This method destroys a grpc_alts_credentials_options instance by |
||||
* de-allocating all of its occupied memory. |
||||
* |
||||
* - options: a grpc_alts_credentials_options instance that needs to be |
||||
* destroyed. |
||||
*/ |
||||
void grpc_alts_credentials_options_destroy( |
||||
grpc_alts_credentials_options* options); |
||||
|
||||
/* This method creates a grpc ALTS credentials client options instance. */ |
||||
grpc_alts_credentials_options* grpc_alts_credentials_client_options_create(); |
||||
|
||||
/* This method creates a grpc ALTS credentials server options instance. */ |
||||
grpc_alts_credentials_options* grpc_alts_credentials_server_options_create(); |
||||
|
||||
/**
|
||||
* This method adds a target service account to grpc ALTS credentials client |
||||
* options instance. |
||||
* |
||||
* - options: grpc ALTS credentials client options instance. |
||||
* - service_account: service account of target endpoint. |
||||
* |
||||
* It returns true on success and false on failure. |
||||
*/ |
||||
bool grpc_alts_credentials_client_options_add_target_service_account( |
||||
grpc_alts_credentials_client_options* options, const char* service_account); |
||||
|
||||
#endif /* GRPC_CORE_LIB_SECURITY_CREDENTIALS_ALTS_GRPC_ALTS_CREDENTIALS_OPTIONS_H \ |
||||
*/ |
@ -0,0 +1,58 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2018 gRPC authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
* |
||||
*/ |
||||
|
||||
#include <grpc/support/port_platform.h> |
||||
|
||||
#include <stdlib.h> |
||||
#include <string.h> |
||||
|
||||
#include <grpc/support/alloc.h> |
||||
#include <grpc/support/log.h> |
||||
|
||||
#include "src/core/lib/security/credentials/alts/grpc_alts_credentials_options.h" |
||||
#include "src/core/tsi/alts/handshaker/transport_security_common_api.h" |
||||
|
||||
static grpc_alts_credentials_options* alts_server_options_copy( |
||||
const grpc_alts_credentials_options* options); |
||||
|
||||
static void alts_server_options_destroy( |
||||
grpc_alts_credentials_options* options) {} |
||||
|
||||
static const grpc_alts_credentials_options_vtable vtable = { |
||||
alts_server_options_copy, alts_server_options_destroy}; |
||||
|
||||
grpc_alts_credentials_options* grpc_alts_credentials_server_options_create() { |
||||
grpc_alts_credentials_server_options* server_options = |
||||
static_cast<grpc_alts_credentials_server_options*>( |
||||
gpr_zalloc(sizeof(*server_options))); |
||||
server_options->base.vtable = &vtable; |
||||
return &server_options->base; |
||||
} |
||||
|
||||
static grpc_alts_credentials_options* alts_server_options_copy( |
||||
const grpc_alts_credentials_options* options) { |
||||
if (options == nullptr) { |
||||
return nullptr; |
||||
} |
||||
grpc_alts_credentials_options* new_options = |
||||
grpc_alts_credentials_server_options_create(); |
||||
/* Copy rpc protocol versions. */ |
||||
grpc_gcp_rpc_protocol_versions_copy(&options->rpc_versions, |
||||
&new_options->rpc_versions); |
||||
return new_options; |
||||
} |
@ -0,0 +1,287 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2018 gRPC authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
* |
||||
*/ |
||||
|
||||
#include <grpc/support/port_platform.h> |
||||
|
||||
#include "src/core/lib/security/security_connector/alts_security_connector.h" |
||||
|
||||
#include <stdbool.h> |
||||
#include <string.h> |
||||
|
||||
#include <grpc/grpc.h> |
||||
#include <grpc/support/alloc.h> |
||||
#include <grpc/support/log.h> |
||||
#include <grpc/support/string_util.h> |
||||
|
||||
#include "src/core/lib/security/credentials/alts/alts_credentials.h" |
||||
#include "src/core/lib/security/transport/security_handshaker.h" |
||||
#include "src/core/lib/transport/transport.h" |
||||
#include "src/core/tsi/alts/handshaker/alts_tsi_handshaker.h" |
||||
|
||||
typedef struct { |
||||
grpc_channel_security_connector base; |
||||
char* target_name; |
||||
} grpc_alts_channel_security_connector; |
||||
|
||||
typedef struct { |
||||
grpc_server_security_connector base; |
||||
} grpc_alts_server_security_connector; |
||||
|
||||
static void alts_channel_destroy(grpc_security_connector* sc) { |
||||
if (sc == nullptr) { |
||||
return; |
||||
} |
||||
auto c = reinterpret_cast<grpc_alts_channel_security_connector*>(sc); |
||||
grpc_call_credentials_unref(c->base.request_metadata_creds); |
||||
grpc_channel_credentials_unref(c->base.channel_creds); |
||||
gpr_free(c->target_name); |
||||
gpr_free(sc); |
||||
} |
||||
|
||||
static void alts_server_destroy(grpc_security_connector* sc) { |
||||
if (sc == nullptr) { |
||||
return; |
||||
} |
||||
auto c = reinterpret_cast<grpc_alts_server_security_connector*>(sc); |
||||
grpc_server_credentials_unref(c->base.server_creds); |
||||
gpr_free(sc); |
||||
} |
||||
|
||||
static void alts_channel_add_handshakers( |
||||
grpc_channel_security_connector* sc, |
||||
grpc_handshake_manager* handshake_manager) { |
||||
tsi_handshaker* handshaker = nullptr; |
||||
auto c = reinterpret_cast<grpc_alts_channel_security_connector*>(sc); |
||||
grpc_alts_credentials* creds = |
||||
reinterpret_cast<grpc_alts_credentials*>(c->base.channel_creds); |
||||
GPR_ASSERT(alts_tsi_handshaker_create(creds->options, c->target_name, |
||||
creds->handshaker_service_url, true, |
||||
&handshaker) == TSI_OK); |
||||
grpc_handshake_manager_add(handshake_manager, grpc_security_handshaker_create( |
||||
handshaker, &sc->base)); |
||||
} |
||||
|
||||
static void alts_server_add_handshakers( |
||||
grpc_server_security_connector* sc, |
||||
grpc_handshake_manager* handshake_manager) { |
||||
tsi_handshaker* handshaker = nullptr; |
||||
auto c = reinterpret_cast<grpc_alts_server_security_connector*>(sc); |
||||
grpc_alts_server_credentials* creds = |
||||
reinterpret_cast<grpc_alts_server_credentials*>(c->base.server_creds); |
||||
GPR_ASSERT(alts_tsi_handshaker_create(creds->options, nullptr, |
||||
creds->handshaker_service_url, false, |
||||
&handshaker) == TSI_OK); |
||||
grpc_handshake_manager_add(handshake_manager, grpc_security_handshaker_create( |
||||
handshaker, &sc->base)); |
||||
} |
||||
|
||||
static void alts_set_rpc_protocol_versions( |
||||
grpc_gcp_rpc_protocol_versions* rpc_versions) { |
||||
grpc_gcp_rpc_protocol_versions_set_max(rpc_versions, |
||||
GRPC_PROTOCOL_VERSION_MAX_MAJOR, |
||||
GRPC_PROTOCOL_VERSION_MAX_MINOR); |
||||
grpc_gcp_rpc_protocol_versions_set_min(rpc_versions, |
||||
GRPC_PROTOCOL_VERSION_MIN_MAJOR, |
||||
GRPC_PROTOCOL_VERSION_MIN_MINOR); |
||||
} |
||||
|
||||
namespace grpc_core { |
||||
namespace internal { |
||||
|
||||
grpc_security_status grpc_alts_auth_context_from_tsi_peer( |
||||
const tsi_peer* peer, grpc_auth_context** ctx) { |
||||
if (peer == nullptr || ctx == nullptr) { |
||||
gpr_log(GPR_ERROR, |
||||
"Invalid arguments to grpc_alts_auth_context_from_tsi_peer()"); |
||||
return GRPC_SECURITY_ERROR; |
||||
} |
||||
*ctx = nullptr; |
||||
/* Validate certificate type. */ |
||||
const tsi_peer_property* cert_type_prop = |
||||
tsi_peer_get_property_by_name(peer, TSI_CERTIFICATE_TYPE_PEER_PROPERTY); |
||||
if (cert_type_prop == nullptr || |
||||
strncmp(cert_type_prop->value.data, TSI_ALTS_CERTIFICATE_TYPE, |
||||
cert_type_prop->value.length) != 0) { |
||||
gpr_log(GPR_ERROR, "Invalid or missing certificate type property."); |
||||
return GRPC_SECURITY_ERROR; |
||||
} |
||||
/* Validate RPC protocol versions. */ |
||||
const tsi_peer_property* rpc_versions_prop = |
||||
tsi_peer_get_property_by_name(peer, TSI_ALTS_RPC_VERSIONS); |
||||
if (rpc_versions_prop == nullptr) { |
||||
gpr_log(GPR_ERROR, "Missing rpc protocol versions property."); |
||||
return GRPC_SECURITY_ERROR; |
||||
} |
||||
grpc_gcp_rpc_protocol_versions local_versions, peer_versions; |
||||
alts_set_rpc_protocol_versions(&local_versions); |
||||
grpc_slice slice = grpc_slice_from_copied_buffer( |
||||
rpc_versions_prop->value.data, rpc_versions_prop->value.length); |
||||
bool decode_result = |
||||
grpc_gcp_rpc_protocol_versions_decode(slice, &peer_versions); |
||||
grpc_slice_unref(slice); |
||||
if (!decode_result) { |
||||
gpr_log(GPR_ERROR, "Invalid peer rpc protocol versions."); |
||||
return GRPC_SECURITY_ERROR; |
||||
} |
||||
/* TODO: Pass highest common rpc protocol version to grpc caller. */ |
||||
bool check_result = grpc_gcp_rpc_protocol_versions_check( |
||||
&local_versions, &peer_versions, nullptr); |
||||
if (!check_result) { |
||||
gpr_log(GPR_ERROR, "Mismatch of local and peer rpc protocol versions."); |
||||
return GRPC_SECURITY_ERROR; |
||||
} |
||||
/* Create auth context. */ |
||||
*ctx = grpc_auth_context_create(nullptr); |
||||
grpc_auth_context_add_cstring_property( |
||||
*ctx, GRPC_TRANSPORT_SECURITY_TYPE_PROPERTY_NAME, |
||||
GRPC_ALTS_TRANSPORT_SECURITY_TYPE); |
||||
size_t i = 0; |
||||
for (i = 0; i < peer->property_count; i++) { |
||||
const tsi_peer_property* tsi_prop = &peer->properties[i]; |
||||
/* Add service account to auth context. */ |
||||
if (strcmp(tsi_prop->name, TSI_ALTS_SERVICE_ACCOUNT_PEER_PROPERTY) == 0) { |
||||
grpc_auth_context_add_property( |
||||
*ctx, TSI_ALTS_SERVICE_ACCOUNT_PEER_PROPERTY, tsi_prop->value.data, |
||||
tsi_prop->value.length); |
||||
GPR_ASSERT(grpc_auth_context_set_peer_identity_property_name( |
||||
*ctx, TSI_ALTS_SERVICE_ACCOUNT_PEER_PROPERTY) == 1); |
||||
} |
||||
} |
||||
if (!grpc_auth_context_peer_is_authenticated(*ctx)) { |
||||
gpr_log(GPR_ERROR, "Invalid unauthenticated peer."); |
||||
GRPC_AUTH_CONTEXT_UNREF(*ctx, "test"); |
||||
*ctx = nullptr; |
||||
return GRPC_SECURITY_ERROR; |
||||
} |
||||
return GRPC_SECURITY_OK; |
||||
} |
||||
|
||||
} // namespace internal
|
||||
} // namespace grpc_core
|
||||
|
||||
static void alts_check_peer(grpc_security_connector* sc, tsi_peer peer, |
||||
grpc_auth_context** auth_context, |
||||
grpc_closure* on_peer_checked) { |
||||
grpc_security_status status; |
||||
status = grpc_core::internal::grpc_alts_auth_context_from_tsi_peer( |
||||
&peer, auth_context); |
||||
tsi_peer_destruct(&peer); |
||||
grpc_error* error = |
||||
status == GRPC_SECURITY_OK |
||||
? GRPC_ERROR_NONE |
||||
: GRPC_ERROR_CREATE_FROM_STATIC_STRING( |
||||
"Could not get ALTS auth context from TSI peer"); |
||||
GRPC_CLOSURE_SCHED(on_peer_checked, error); |
||||
} |
||||
|
||||
static int alts_channel_cmp(grpc_security_connector* sc1, |
||||
grpc_security_connector* sc2) { |
||||
grpc_alts_channel_security_connector* c1 = |
||||
reinterpret_cast<grpc_alts_channel_security_connector*>(sc1); |
||||
grpc_alts_channel_security_connector* c2 = |
||||
reinterpret_cast<grpc_alts_channel_security_connector*>(sc2); |
||||
int c = grpc_channel_security_connector_cmp(&c1->base, &c2->base); |
||||
if (c != 0) return c; |
||||
return strcmp(c1->target_name, c2->target_name); |
||||
} |
||||
|
||||
static int alts_server_cmp(grpc_security_connector* sc1, |
||||
grpc_security_connector* sc2) { |
||||
grpc_alts_server_security_connector* c1 = |
||||
reinterpret_cast<grpc_alts_server_security_connector*>(sc1); |
||||
grpc_alts_server_security_connector* c2 = |
||||
reinterpret_cast<grpc_alts_server_security_connector*>(sc2); |
||||
return grpc_server_security_connector_cmp(&c1->base, &c2->base); |
||||
} |
||||
|
||||
static grpc_security_connector_vtable alts_channel_vtable = { |
||||
alts_channel_destroy, alts_check_peer, alts_channel_cmp}; |
||||
|
||||
static grpc_security_connector_vtable alts_server_vtable = { |
||||
alts_server_destroy, alts_check_peer, alts_server_cmp}; |
||||
|
||||
static bool alts_check_call_host(grpc_channel_security_connector* sc, |
||||
const char* host, |
||||
grpc_auth_context* auth_context, |
||||
grpc_closure* on_call_host_checked, |
||||
grpc_error** error) { |
||||
grpc_alts_channel_security_connector* alts_sc = |
||||
reinterpret_cast<grpc_alts_channel_security_connector*>(sc); |
||||
if (host == nullptr || alts_sc == nullptr || |
||||
strcmp(host, alts_sc->target_name) != 0) { |
||||
*error = GRPC_ERROR_CREATE_FROM_STATIC_STRING( |
||||
"ALTS call host does not match target name"); |
||||
} |
||||
return true; |
||||
} |
||||
|
||||
static void alts_cancel_check_call_host(grpc_channel_security_connector* sc, |
||||
grpc_closure* on_call_host_checked, |
||||
grpc_error* error) { |
||||
GRPC_ERROR_UNREF(error); |
||||
} |
||||
|
||||
grpc_security_status grpc_alts_channel_security_connector_create( |
||||
grpc_channel_credentials* channel_creds, |
||||
grpc_call_credentials* request_metadata_creds, const char* target_name, |
||||
grpc_channel_security_connector** sc) { |
||||
if (channel_creds == nullptr || sc == nullptr || target_name == nullptr) { |
||||
gpr_log( |
||||
GPR_ERROR, |
||||
"Invalid arguments to grpc_alts_channel_security_connector_create()"); |
||||
return GRPC_SECURITY_ERROR; |
||||
} |
||||
auto c = static_cast<grpc_alts_channel_security_connector*>( |
||||
gpr_zalloc(sizeof(grpc_alts_channel_security_connector))); |
||||
gpr_ref_init(&c->base.base.refcount, 1); |
||||
c->base.base.vtable = &alts_channel_vtable; |
||||
c->base.add_handshakers = alts_channel_add_handshakers; |
||||
c->base.channel_creds = grpc_channel_credentials_ref(channel_creds); |
||||
c->base.request_metadata_creds = |
||||
grpc_call_credentials_ref(request_metadata_creds); |
||||
c->base.check_call_host = alts_check_call_host; |
||||
c->base.cancel_check_call_host = alts_cancel_check_call_host; |
||||
grpc_alts_credentials* creds = |
||||
reinterpret_cast<grpc_alts_credentials*>(c->base.channel_creds); |
||||
alts_set_rpc_protocol_versions(&creds->options->rpc_versions); |
||||
c->target_name = gpr_strdup(target_name); |
||||
*sc = &c->base; |
||||
return GRPC_SECURITY_OK; |
||||
} |
||||
|
||||
grpc_security_status grpc_alts_server_security_connector_create( |
||||
grpc_server_credentials* server_creds, |
||||
grpc_server_security_connector** sc) { |
||||
if (server_creds == nullptr || sc == nullptr) { |
||||
gpr_log( |
||||
GPR_ERROR, |
||||
"Invalid arguments to grpc_alts_server_security_connector_create()"); |
||||
return GRPC_SECURITY_ERROR; |
||||
} |
||||
auto c = static_cast<grpc_alts_server_security_connector*>( |
||||
gpr_zalloc(sizeof(grpc_alts_server_security_connector))); |
||||
gpr_ref_init(&c->base.base.refcount, 1); |
||||
c->base.base.vtable = &alts_server_vtable; |
||||
c->base.server_creds = grpc_server_credentials_ref(server_creds); |
||||
c->base.add_handshakers = alts_server_add_handshakers; |
||||
grpc_alts_server_credentials* creds = |
||||
reinterpret_cast<grpc_alts_server_credentials*>(c->base.server_creds); |
||||
alts_set_rpc_protocol_versions(&creds->options->rpc_versions); |
||||
*sc = &c->base; |
||||
return GRPC_SECURITY_OK; |
||||
} |
@ -0,0 +1,69 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2018 gRPC authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
* |
||||
*/ |
||||
|
||||
#ifndef GRPC_CORE_LIB_SECURITY_SECURITY_CONNECTOR_ALTS_SECURITY_CONNECTOR_H |
||||
#define GRPC_CORE_LIB_SECURITY_SECURITY_CONNECTOR_ALTS_SECURITY_CONNECTOR_H |
||||
|
||||
#include <grpc/support/port_platform.h> |
||||
|
||||
#include "src/core/lib/security/context/security_context.h" |
||||
#include "src/core/lib/security/credentials/alts/grpc_alts_credentials_options.h" |
||||
|
||||
#define GRPC_ALTS_TRANSPORT_SECURITY_TYPE "alts" |
||||
|
||||
/**
|
||||
* This method creates an ALTS channel security connector. |
||||
* |
||||
* - channel_creds: channel credential instance. |
||||
* - request_metadata_creds: credential object which will be sent with each |
||||
* request. This parameter can be nullptr. |
||||
* - target_name: the name of the endpoint that the channel is connecting to. |
||||
* - sc: address of ALTS channel security connector instance to be returned from |
||||
* the method. |
||||
* |
||||
* It returns GRPC_SECURITY_OK on success, and an error stauts code on failure. |
||||
*/ |
||||
grpc_security_status grpc_alts_channel_security_connector_create( |
||||
grpc_channel_credentials* channel_creds, |
||||
grpc_call_credentials* request_metadata_creds, const char* target_name, |
||||
grpc_channel_security_connector** sc); |
||||
|
||||
/**
|
||||
* This method creates an ALTS server security connector. |
||||
* |
||||
* - server_creds: server credential instance. |
||||
* - sc: address of ALTS server security connector instance to be returned from |
||||
* the method. |
||||
* |
||||
* It returns GRPC_SECURITY_OK on success, and an error status code on failure. |
||||
*/ |
||||
grpc_security_status grpc_alts_server_security_connector_create( |
||||
grpc_server_credentials* server_creds, grpc_server_security_connector** sc); |
||||
|
||||
namespace grpc_core { |
||||
namespace internal { |
||||
|
||||
/* Exposed only for testing. */ |
||||
grpc_security_status grpc_alts_auth_context_from_tsi_peer( |
||||
const tsi_peer* peer, grpc_auth_context** ctx); |
||||
|
||||
} // namespace internal
|
||||
} // namespace grpc_core
|
||||
|
||||
#endif /* GRPC_CORE_LIB_SECURITY_SECURITY_CONNECTOR_ALTS_SECURITY_CONNECTOR_H \ |
||||
*/ |
@ -0,0 +1,687 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2018 gRPC authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
* |
||||
*/ |
||||
|
||||
#include <grpc/support/port_platform.h> |
||||
|
||||
#include "src/core/tsi/alts/crypt/gsec.h" |
||||
|
||||
#include <openssl/bio.h> |
||||
#include <openssl/buffer.h> |
||||
#include <openssl/err.h> |
||||
#include <openssl/evp.h> |
||||
#include <openssl/hmac.h> |
||||
#include <string.h> |
||||
|
||||
#include <grpc/support/alloc.h> |
||||
|
||||
constexpr size_t kKdfKeyLen = 32; |
||||
constexpr size_t kKdfCounterLen = 6; |
||||
constexpr size_t kKdfCounterOffset = 2; |
||||
constexpr size_t kRekeyAeadKeyLen = kAes128GcmKeyLength; |
||||
|
||||
/* Struct for additional data required if rekeying is enabled. */ |
||||
struct gsec_aes_gcm_aead_rekey_data { |
||||
uint8_t kdf_counter[kKdfCounterLen]; |
||||
uint8_t nonce_mask[kAesGcmNonceLength]; |
||||
}; |
||||
|
||||
/* Main struct for AES_GCM crypter interface. */ |
||||
struct gsec_aes_gcm_aead_crypter { |
||||
gsec_aead_crypter crypter; |
||||
size_t key_length; |
||||
size_t nonce_length; |
||||
size_t tag_length; |
||||
uint8_t* key; |
||||
gsec_aes_gcm_aead_rekey_data* rekey_data; |
||||
EVP_CIPHER_CTX* ctx; |
||||
}; |
||||
|
||||
static char* aes_gcm_get_openssl_errors() { |
||||
BIO* bio = BIO_new(BIO_s_mem()); |
||||
ERR_print_errors(bio); |
||||
BUF_MEM* mem = nullptr; |
||||
char* error_msg = nullptr; |
||||
BIO_get_mem_ptr(bio, &mem); |
||||
if (mem != nullptr) { |
||||
error_msg = static_cast<char*>(gpr_malloc(mem->length + 1)); |
||||
memcpy(error_msg, mem->data, mem->length); |
||||
error_msg[mem->length] = '\0'; |
||||
} |
||||
BIO_free_all(bio); |
||||
return error_msg; |
||||
} |
||||
|
||||
static void aes_gcm_format_errors(const char* error_msg, char** error_details) { |
||||
if (error_details == nullptr) { |
||||
return; |
||||
} |
||||
unsigned long error = ERR_get_error(); |
||||
if (error == 0 && error_msg != nullptr) { |
||||
*error_details = static_cast<char*>(gpr_malloc(strlen(error_msg) + 1)); |
||||
memcpy(*error_details, error_msg, strlen(error_msg) + 1); |
||||
return; |
||||
} |
||||
char* openssl_errors = aes_gcm_get_openssl_errors(); |
||||
if (openssl_errors != nullptr && error_msg != nullptr) { |
||||
size_t len = strlen(error_msg) + strlen(openssl_errors) + 2; /* ", " */ |
||||
*error_details = static_cast<char*>(gpr_malloc(len + 1)); |
||||
snprintf(*error_details, len + 1, "%s, %s", error_msg, openssl_errors); |
||||
gpr_free(openssl_errors); |
||||
} |
||||
} |
||||
|
||||
static grpc_status_code gsec_aes_gcm_aead_crypter_max_ciphertext_and_tag_length( |
||||
const gsec_aead_crypter* crypter, size_t plaintext_length, |
||||
size_t* max_ciphertext_and_tag_length, char** error_details) { |
||||
if (max_ciphertext_and_tag_length == nullptr) { |
||||
aes_gcm_format_errors("max_ciphertext_and_tag_length is nullptr.", |
||||
error_details); |
||||
return GRPC_STATUS_INVALID_ARGUMENT; |
||||
} |
||||
gsec_aes_gcm_aead_crypter* aes_gcm_crypter = |
||||
reinterpret_cast<gsec_aes_gcm_aead_crypter*>( |
||||
const_cast<gsec_aead_crypter*>(crypter)); |
||||
*max_ciphertext_and_tag_length = |
||||
plaintext_length + aes_gcm_crypter->tag_length; |
||||
return GRPC_STATUS_OK; |
||||
} |
||||
|
||||
static grpc_status_code gsec_aes_gcm_aead_crypter_max_plaintext_length( |
||||
const gsec_aead_crypter* crypter, size_t ciphertext_and_tag_length, |
||||
size_t* max_plaintext_length, char** error_details) { |
||||
if (max_plaintext_length == nullptr) { |
||||
aes_gcm_format_errors("max_plaintext_length is nullptr.", error_details); |
||||
return GRPC_STATUS_INVALID_ARGUMENT; |
||||
} |
||||
gsec_aes_gcm_aead_crypter* aes_gcm_crypter = |
||||
reinterpret_cast<gsec_aes_gcm_aead_crypter*>( |
||||
const_cast<gsec_aead_crypter*>(crypter)); |
||||
if (ciphertext_and_tag_length < aes_gcm_crypter->tag_length) { |
||||
*max_plaintext_length = 0; |
||||
aes_gcm_format_errors( |
||||
"ciphertext_and_tag_length is smaller than tag_length.", error_details); |
||||
return GRPC_STATUS_INVALID_ARGUMENT; |
||||
} |
||||
*max_plaintext_length = |
||||
ciphertext_and_tag_length - aes_gcm_crypter->tag_length; |
||||
return GRPC_STATUS_OK; |
||||
} |
||||
|
||||
static grpc_status_code gsec_aes_gcm_aead_crypter_nonce_length( |
||||
const gsec_aead_crypter* crypter, size_t* nonce_length, |
||||
char** error_details) { |
||||
if (nonce_length == nullptr) { |
||||
aes_gcm_format_errors("nonce_length is nullptr.", error_details); |
||||
return GRPC_STATUS_INVALID_ARGUMENT; |
||||
} |
||||
gsec_aes_gcm_aead_crypter* aes_gcm_crypter = |
||||
reinterpret_cast<gsec_aes_gcm_aead_crypter*>( |
||||
const_cast<gsec_aead_crypter*>(crypter)); |
||||
*nonce_length = aes_gcm_crypter->nonce_length; |
||||
return GRPC_STATUS_OK; |
||||
} |
||||
|
||||
static grpc_status_code gsec_aes_gcm_aead_crypter_key_length( |
||||
const gsec_aead_crypter* crypter, size_t* key_length, |
||||
char** error_details) { |
||||
if (key_length == nullptr) { |
||||
aes_gcm_format_errors("key_length is nullptr.", error_details); |
||||
return GRPC_STATUS_INVALID_ARGUMENT; |
||||
} |
||||
gsec_aes_gcm_aead_crypter* aes_gcm_crypter = |
||||
reinterpret_cast<gsec_aes_gcm_aead_crypter*>( |
||||
const_cast<gsec_aead_crypter*>(crypter)); |
||||
*key_length = aes_gcm_crypter->key_length; |
||||
return GRPC_STATUS_OK; |
||||
} |
||||
|
||||
static grpc_status_code gsec_aes_gcm_aead_crypter_tag_length( |
||||
const gsec_aead_crypter* crypter, size_t* tag_length, |
||||
char** error_details) { |
||||
if (tag_length == nullptr) { |
||||
aes_gcm_format_errors("tag_length is nullptr.", error_details); |
||||
return GRPC_STATUS_INVALID_ARGUMENT; |
||||
} |
||||
gsec_aes_gcm_aead_crypter* aes_gcm_crypter = |
||||
reinterpret_cast<gsec_aes_gcm_aead_crypter*>( |
||||
const_cast<gsec_aead_crypter*>(crypter)); |
||||
*tag_length = aes_gcm_crypter->tag_length; |
||||
return GRPC_STATUS_OK; |
||||
} |
||||
|
||||
static void aes_gcm_mask_nonce(uint8_t* dst, const uint8_t* nonce, |
||||
const uint8_t* mask) { |
||||
uint64_t mask1; |
||||
uint32_t mask2; |
||||
memcpy(&mask1, mask, sizeof(mask1)); |
||||
memcpy(&mask2, mask + sizeof(mask1), sizeof(mask2)); |
||||
uint64_t nonce1; |
||||
uint32_t nonce2; |
||||
memcpy(&nonce1, nonce, sizeof(nonce1)); |
||||
memcpy(&nonce2, nonce + sizeof(nonce1), sizeof(nonce2)); |
||||
nonce1 ^= mask1; |
||||
nonce2 ^= mask2; |
||||
memcpy(dst, &nonce1, sizeof(nonce1)); |
||||
memcpy(dst + sizeof(nonce1), &nonce2, sizeof(nonce2)); |
||||
} |
||||
|
||||
static grpc_status_code aes_gcm_derive_aead_key(uint8_t* dst, |
||||
const uint8_t* kdf_key, |
||||
const uint8_t* kdf_counter) { |
||||
unsigned char buf[EVP_MAX_MD_SIZE]; |
||||
unsigned char ctr = 1; |
||||
#if OPENSSL_VERSION_NUMBER < 0x10100000L |
||||
HMAC_CTX hmac; |
||||
HMAC_CTX_init(&hmac); |
||||
if (!HMAC_Init_ex(&hmac, kdf_key, kKdfKeyLen, EVP_sha256(), nullptr) || |
||||
!HMAC_Update(&hmac, kdf_counter, kKdfCounterLen) || |
||||
!HMAC_Update(&hmac, &ctr, 1) || !HMAC_Final(&hmac, buf, nullptr)) { |
||||
HMAC_CTX_cleanup(&hmac); |
||||
return GRPC_STATUS_INTERNAL; |
||||
} |
||||
HMAC_CTX_cleanup(&hmac); |
||||
#else |
||||
HMAC_CTX* hmac = HMAC_CTX_new(); |
||||
if (hmac == nullptr) { |
||||
return GRPC_STATUS_INTERNAL; |
||||
} |
||||
if (!HMAC_Init_ex(hmac, kdf_key, kKdfKeyLen, EVP_sha256(), nullptr) || |
||||
!HMAC_Update(hmac, kdf_counter, kKdfCounterLen) || |
||||
!HMAC_Update(hmac, &ctr, 1) || !HMAC_Final(hmac, buf, nullptr)) { |
||||
HMAC_CTX_free(hmac); |
||||
return GRPC_STATUS_INTERNAL; |
||||
} |
||||
HMAC_CTX_free(hmac); |
||||
#endif |
||||
memcpy(dst, buf, kRekeyAeadKeyLen); |
||||
return GRPC_STATUS_OK; |
||||
} |
||||
|
||||
static grpc_status_code aes_gcm_rekey_if_required( |
||||
gsec_aes_gcm_aead_crypter* aes_gcm_crypter, const uint8_t* nonce, |
||||
char** error_details) { |
||||
// If rekey_data is nullptr, then rekeying is not supported and not required.
|
||||
// If bytes 2-7 of kdf_counter differ from the (per message) nonce, then the
|
||||
// encryption key is recomputed from a new kdf_counter to ensure that we don't
|
||||
// encrypt more than 2^16 messages per encryption key (in each direction).
|
||||
if (aes_gcm_crypter->rekey_data == nullptr || |
||||
memcmp(aes_gcm_crypter->rekey_data->kdf_counter, |
||||
nonce + kKdfCounterOffset, kKdfCounterLen) == 0) { |
||||
return GRPC_STATUS_OK; |
||||
} |
||||
memcpy(aes_gcm_crypter->rekey_data->kdf_counter, nonce + kKdfCounterOffset, |
||||
kKdfCounterLen); |
||||
uint8_t aead_key[kRekeyAeadKeyLen]; |
||||
if (aes_gcm_derive_aead_key(aead_key, aes_gcm_crypter->key, |
||||
aes_gcm_crypter->rekey_data->kdf_counter) != |
||||
GRPC_STATUS_OK) { |
||||
aes_gcm_format_errors("Rekeying failed in key derivation.", error_details); |
||||
return GRPC_STATUS_INTERNAL; |
||||
} |
||||
if (!EVP_DecryptInit_ex(aes_gcm_crypter->ctx, nullptr, nullptr, aead_key, |
||||
nullptr)) { |
||||
aes_gcm_format_errors("Rekeying failed in context update.", error_details); |
||||
return GRPC_STATUS_INTERNAL; |
||||
} |
||||
return GRPC_STATUS_OK; |
||||
} |
||||
|
||||
static grpc_status_code gsec_aes_gcm_aead_crypter_encrypt_iovec( |
||||
gsec_aead_crypter* crypter, const uint8_t* nonce, size_t nonce_length, |
||||
const struct iovec* aad_vec, size_t aad_vec_length, |
||||
const struct iovec* plaintext_vec, size_t plaintext_vec_length, |
||||
struct iovec ciphertext_vec, size_t* ciphertext_bytes_written, |
||||
char** error_details) { |
||||
gsec_aes_gcm_aead_crypter* aes_gcm_crypter = |
||||
reinterpret_cast<gsec_aes_gcm_aead_crypter*>(crypter); |
||||
// Input checks
|
||||
if (nonce == nullptr) { |
||||
aes_gcm_format_errors("Nonce buffer is nullptr.", error_details); |
||||
return GRPC_STATUS_INVALID_ARGUMENT; |
||||
} |
||||
if (kAesGcmNonceLength != nonce_length) { |
||||
aes_gcm_format_errors("Nonce buffer has the wrong length.", error_details); |
||||
return GRPC_STATUS_INVALID_ARGUMENT; |
||||
} |
||||
if (aad_vec_length > 0 && aad_vec == nullptr) { |
||||
aes_gcm_format_errors("Non-zero aad_vec_length but aad_vec is nullptr.", |
||||
error_details); |
||||
return GRPC_STATUS_INVALID_ARGUMENT; |
||||
} |
||||
if (plaintext_vec_length > 0 && plaintext_vec == nullptr) { |
||||
aes_gcm_format_errors( |
||||
"Non-zero plaintext_vec_length but plaintext_vec is nullptr.", |
||||
error_details); |
||||
return GRPC_STATUS_INVALID_ARGUMENT; |
||||
} |
||||
if (ciphertext_bytes_written == nullptr) { |
||||
aes_gcm_format_errors("bytes_written is nullptr.", error_details); |
||||
return GRPC_STATUS_INVALID_ARGUMENT; |
||||
} |
||||
*ciphertext_bytes_written = 0; |
||||
// rekey if required
|
||||
if (aes_gcm_rekey_if_required(aes_gcm_crypter, nonce, error_details) != |
||||
GRPC_STATUS_OK) { |
||||
return GRPC_STATUS_INTERNAL; |
||||
} |
||||
// mask nonce if required
|
||||
const uint8_t* nonce_aead = nonce; |
||||
uint8_t nonce_masked[kAesGcmNonceLength]; |
||||
if (aes_gcm_crypter->rekey_data != nullptr) { |
||||
aes_gcm_mask_nonce(nonce_masked, aes_gcm_crypter->rekey_data->nonce_mask, |
||||
nonce); |
||||
nonce_aead = nonce_masked; |
||||
} |
||||
// init openssl context
|
||||
if (!EVP_EncryptInit_ex(aes_gcm_crypter->ctx, nullptr, nullptr, nullptr, |
||||
nonce_aead)) { |
||||
aes_gcm_format_errors("Initializing nonce failed", error_details); |
||||
return GRPC_STATUS_INTERNAL; |
||||
} |
||||
// process aad
|
||||
size_t i; |
||||
for (i = 0; i < aad_vec_length; i++) { |
||||
const uint8_t* aad = static_cast<uint8_t*>(aad_vec[i].iov_base); |
||||
size_t aad_length = aad_vec[i].iov_len; |
||||
if (aad_length == 0) { |
||||
continue; |
||||
} |
||||
size_t aad_bytes_read = 0; |
||||
if (aad == nullptr) { |
||||
aes_gcm_format_errors("aad is nullptr.", error_details); |
||||
return GRPC_STATUS_INVALID_ARGUMENT; |
||||
} |
||||
if (!EVP_EncryptUpdate(aes_gcm_crypter->ctx, nullptr, |
||||
reinterpret_cast<int*>(&aad_bytes_read), aad, |
||||
static_cast<int>(aad_length)) || |
||||
aad_bytes_read != aad_length) { |
||||
aes_gcm_format_errors("Setting authenticated associated data failed", |
||||
error_details); |
||||
return GRPC_STATUS_INTERNAL; |
||||
} |
||||
} |
||||
uint8_t* ciphertext = static_cast<uint8_t*>(ciphertext_vec.iov_base); |
||||
size_t ciphertext_length = ciphertext_vec.iov_len; |
||||
if (ciphertext == nullptr) { |
||||
aes_gcm_format_errors("ciphertext is nullptr.", error_details); |
||||
return GRPC_STATUS_INVALID_ARGUMENT; |
||||
} |
||||
// process plaintext
|
||||
for (i = 0; i < plaintext_vec_length; i++) { |
||||
const uint8_t* plaintext = static_cast<uint8_t*>(plaintext_vec[i].iov_base); |
||||
size_t plaintext_length = plaintext_vec[i].iov_len; |
||||
if (plaintext == nullptr) { |
||||
if (plaintext_length == 0) { |
||||
continue; |
||||
} |
||||
aes_gcm_format_errors("plaintext is nullptr.", error_details); |
||||
return GRPC_STATUS_INVALID_ARGUMENT; |
||||
} |
||||
if (ciphertext_length < plaintext_length) { |
||||
aes_gcm_format_errors( |
||||
"ciphertext is not large enough to hold the result.", error_details); |
||||
return GRPC_STATUS_INVALID_ARGUMENT; |
||||
} |
||||
int bytes_written = 0; |
||||
int bytes_to_write = static_cast<int>(plaintext_length); |
||||
if (!EVP_EncryptUpdate(aes_gcm_crypter->ctx, ciphertext, &bytes_written, |
||||
plaintext, bytes_to_write)) { |
||||
aes_gcm_format_errors("Encrypting plaintext failed.", error_details); |
||||
return GRPC_STATUS_INTERNAL; |
||||
} |
||||
if (bytes_written > bytes_to_write) { |
||||
aes_gcm_format_errors("More bytes written than expected.", error_details); |
||||
return GRPC_STATUS_INTERNAL; |
||||
} |
||||
ciphertext += bytes_written; |
||||
ciphertext_length -= bytes_written; |
||||
} |
||||
int bytes_written_temp = 0; |
||||
if (!EVP_EncryptFinal_ex(aes_gcm_crypter->ctx, nullptr, |
||||
&bytes_written_temp)) { |
||||
aes_gcm_format_errors("Finalizing encryption failed.", error_details); |
||||
return GRPC_STATUS_INTERNAL; |
||||
} |
||||
if (bytes_written_temp != 0) { |
||||
aes_gcm_format_errors("Openssl wrote some unexpected bytes.", |
||||
error_details); |
||||
return GRPC_STATUS_INTERNAL; |
||||
} |
||||
if (ciphertext_length < kAesGcmTagLength) { |
||||
aes_gcm_format_errors("ciphertext is too small to hold a tag.", |
||||
error_details); |
||||
return GRPC_STATUS_INVALID_ARGUMENT; |
||||
} |
||||
|
||||
if (!EVP_CIPHER_CTX_ctrl(aes_gcm_crypter->ctx, EVP_CTRL_GCM_GET_TAG, |
||||
kAesGcmTagLength, ciphertext)) { |
||||
aes_gcm_format_errors("Writing tag failed.", error_details); |
||||
return GRPC_STATUS_INTERNAL; |
||||
} |
||||
ciphertext += kAesGcmTagLength; |
||||
ciphertext_length -= kAesGcmTagLength; |
||||
*ciphertext_bytes_written = ciphertext_vec.iov_len - ciphertext_length; |
||||
return GRPC_STATUS_OK; |
||||
} |
||||
|
||||
static grpc_status_code gsec_aes_gcm_aead_crypter_decrypt_iovec( |
||||
gsec_aead_crypter* crypter, const uint8_t* nonce, size_t nonce_length, |
||||
const struct iovec* aad_vec, size_t aad_vec_length, |
||||
const struct iovec* ciphertext_vec, size_t ciphertext_vec_length, |
||||
struct iovec plaintext_vec, size_t* plaintext_bytes_written, |
||||
char** error_details) { |
||||
gsec_aes_gcm_aead_crypter* aes_gcm_crypter = |
||||
reinterpret_cast<gsec_aes_gcm_aead_crypter*>( |
||||
const_cast<gsec_aead_crypter*>(crypter)); |
||||
if (nonce == nullptr) { |
||||
aes_gcm_format_errors("Nonce buffer is nullptr.", error_details); |
||||
return GRPC_STATUS_INVALID_ARGUMENT; |
||||
} |
||||
if (kAesGcmNonceLength != nonce_length) { |
||||
aes_gcm_format_errors("Nonce buffer has the wrong length.", error_details); |
||||
return GRPC_STATUS_INVALID_ARGUMENT; |
||||
} |
||||
if (aad_vec_length > 0 && aad_vec == nullptr) { |
||||
aes_gcm_format_errors("Non-zero aad_vec_length but aad_vec is nullptr.", |
||||
error_details); |
||||
return GRPC_STATUS_INVALID_ARGUMENT; |
||||
} |
||||
if (ciphertext_vec_length > 0 && ciphertext_vec == nullptr) { |
||||
aes_gcm_format_errors( |
||||
"Non-zero plaintext_vec_length but plaintext_vec is nullptr.", |
||||
error_details); |
||||
return GRPC_STATUS_INVALID_ARGUMENT; |
||||
} |
||||
// Compute the total length so we can ensure we don't pass the tag into
|
||||
// EVP_decrypt.
|
||||
size_t total_ciphertext_length = 0; |
||||
size_t i; |
||||
for (i = 0; i < ciphertext_vec_length; i++) { |
||||
total_ciphertext_length += ciphertext_vec[i].iov_len; |
||||
} |
||||
if (total_ciphertext_length < kAesGcmTagLength) { |
||||
aes_gcm_format_errors("ciphertext is too small to hold a tag.", |
||||
error_details); |
||||
return GRPC_STATUS_INVALID_ARGUMENT; |
||||
} |
||||
if (plaintext_bytes_written == nullptr) { |
||||
aes_gcm_format_errors("bytes_written is nullptr.", error_details); |
||||
return GRPC_STATUS_INVALID_ARGUMENT; |
||||
} |
||||
*plaintext_bytes_written = 0; |
||||
// rekey if required
|
||||
if (aes_gcm_rekey_if_required(aes_gcm_crypter, nonce, error_details) != |
||||
GRPC_STATUS_OK) { |
||||
aes_gcm_format_errors("Rekeying failed.", error_details); |
||||
return GRPC_STATUS_INTERNAL; |
||||
} |
||||
// mask nonce if required
|
||||
const uint8_t* nonce_aead = nonce; |
||||
uint8_t nonce_masked[kAesGcmNonceLength]; |
||||
if (aes_gcm_crypter->rekey_data != nullptr) { |
||||
aes_gcm_mask_nonce(nonce_masked, aes_gcm_crypter->rekey_data->nonce_mask, |
||||
nonce); |
||||
nonce_aead = nonce_masked; |
||||
} |
||||
// init openssl context
|
||||
if (!EVP_DecryptInit_ex(aes_gcm_crypter->ctx, nullptr, nullptr, nullptr, |
||||
nonce_aead)) { |
||||
aes_gcm_format_errors("Initializing nonce failed.", error_details); |
||||
return GRPC_STATUS_INTERNAL; |
||||
} |
||||
// process aad
|
||||
for (i = 0; i < aad_vec_length; i++) { |
||||
const uint8_t* aad = static_cast<uint8_t*>(aad_vec[i].iov_base); |
||||
size_t aad_length = aad_vec[i].iov_len; |
||||
if (aad_length == 0) { |
||||
continue; |
||||
} |
||||
size_t aad_bytes_read = 0; |
||||
if (aad == nullptr) { |
||||
aes_gcm_format_errors("aad is nullptr.", error_details); |
||||
return GRPC_STATUS_INVALID_ARGUMENT; |
||||
} |
||||
if (!EVP_DecryptUpdate(aes_gcm_crypter->ctx, nullptr, |
||||
reinterpret_cast<int*>(&aad_bytes_read), aad, |
||||
static_cast<int>(aad_length)) || |
||||
aad_bytes_read != aad_length) { |
||||
aes_gcm_format_errors("Setting authenticated associated data failed.", |
||||
error_details); |
||||
return GRPC_STATUS_INTERNAL; |
||||
} |
||||
} |
||||
// process ciphertext
|
||||
uint8_t* plaintext = static_cast<uint8_t*>(plaintext_vec.iov_base); |
||||
size_t plaintext_length = plaintext_vec.iov_len; |
||||
if (plaintext_length > 0 && plaintext == nullptr) { |
||||
aes_gcm_format_errors( |
||||
"plaintext is nullptr, but plaintext_length is positive.", |
||||
error_details); |
||||
return GRPC_STATUS_INVALID_ARGUMENT; |
||||
} |
||||
const uint8_t* ciphertext = nullptr; |
||||
size_t ciphertext_length = 0; |
||||
for (i = 0; |
||||
i < ciphertext_vec_length && total_ciphertext_length > kAesGcmTagLength; |
||||
i++) { |
||||
ciphertext = static_cast<uint8_t*>(ciphertext_vec[i].iov_base); |
||||
ciphertext_length = ciphertext_vec[i].iov_len; |
||||
if (ciphertext == nullptr) { |
||||
if (ciphertext_length == 0) { |
||||
continue; |
||||
} |
||||
aes_gcm_format_errors("ciphertext is nullptr.", error_details); |
||||
memset(plaintext_vec.iov_base, 0x00, plaintext_vec.iov_len); |
||||
return GRPC_STATUS_INVALID_ARGUMENT; |
||||
} |
||||
size_t bytes_written = 0; |
||||
size_t bytes_to_write = ciphertext_length; |
||||
// Don't include the tag
|
||||
if (bytes_to_write > total_ciphertext_length - kAesGcmTagLength) { |
||||
bytes_to_write = total_ciphertext_length - kAesGcmTagLength; |
||||
} |
||||
if (plaintext_length < bytes_to_write) { |
||||
aes_gcm_format_errors( |
||||
"Not enough plaintext buffer to hold encrypted ciphertext.", |
||||
error_details); |
||||
return GRPC_STATUS_INVALID_ARGUMENT; |
||||
} |
||||
if (!EVP_DecryptUpdate(aes_gcm_crypter->ctx, plaintext, |
||||
reinterpret_cast<int*>(&bytes_written), ciphertext, |
||||
static_cast<int>(bytes_to_write))) { |
||||
aes_gcm_format_errors("Decrypting ciphertext failed.", error_details); |
||||
memset(plaintext_vec.iov_base, 0x00, plaintext_vec.iov_len); |
||||
return GRPC_STATUS_INTERNAL; |
||||
} |
||||
if (bytes_written > ciphertext_length) { |
||||
aes_gcm_format_errors("More bytes written than expected.", error_details); |
||||
memset(plaintext_vec.iov_base, 0x00, plaintext_vec.iov_len); |
||||
return GRPC_STATUS_INTERNAL; |
||||
} |
||||
ciphertext += bytes_written; |
||||
ciphertext_length -= bytes_written; |
||||
total_ciphertext_length -= bytes_written; |
||||
plaintext += bytes_written; |
||||
plaintext_length -= bytes_written; |
||||
} |
||||
if (total_ciphertext_length > kAesGcmTagLength) { |
||||
aes_gcm_format_errors( |
||||
"Not enough plaintext buffer to hold encrypted ciphertext.", |
||||
error_details); |
||||
memset(plaintext_vec.iov_base, 0x00, plaintext_vec.iov_len); |
||||
return GRPC_STATUS_INVALID_ARGUMENT; |
||||
} |
||||
uint8_t tag[kAesGcmTagLength]; |
||||
uint8_t* tag_tmp = tag; |
||||
if (ciphertext_length > 0) { |
||||
memcpy(tag_tmp, ciphertext, ciphertext_length); |
||||
tag_tmp += ciphertext_length; |
||||
total_ciphertext_length -= ciphertext_length; |
||||
} |
||||
for (; i < ciphertext_vec_length; i++) { |
||||
ciphertext = static_cast<uint8_t*>(ciphertext_vec[i].iov_base); |
||||
ciphertext_length = ciphertext_vec[i].iov_len; |
||||
if (ciphertext == nullptr) { |
||||
if (ciphertext_length == 0) { |
||||
continue; |
||||
} |
||||
aes_gcm_format_errors("ciphertext is nullptr.", error_details); |
||||
memset(plaintext_vec.iov_base, 0x00, plaintext_vec.iov_len); |
||||
return GRPC_STATUS_INVALID_ARGUMENT; |
||||
} |
||||
memcpy(tag_tmp, ciphertext, ciphertext_length); |
||||
tag_tmp += ciphertext_length; |
||||
total_ciphertext_length -= ciphertext_length; |
||||
} |
||||
if (!EVP_CIPHER_CTX_ctrl(aes_gcm_crypter->ctx, EVP_CTRL_GCM_SET_TAG, |
||||
kAesGcmTagLength, reinterpret_cast<void*>(tag))) { |
||||
aes_gcm_format_errors("Setting tag failed.", error_details); |
||||
memset(plaintext_vec.iov_base, 0x00, plaintext_vec.iov_len); |
||||
return GRPC_STATUS_INTERNAL; |
||||
} |
||||
int bytes_written_temp = 0; |
||||
if (!EVP_DecryptFinal_ex(aes_gcm_crypter->ctx, nullptr, |
||||
&bytes_written_temp)) { |
||||
aes_gcm_format_errors("Checking tag failed.", error_details); |
||||
memset(plaintext_vec.iov_base, 0x00, plaintext_vec.iov_len); |
||||
return GRPC_STATUS_FAILED_PRECONDITION; |
||||
} |
||||
if (bytes_written_temp != 0) { |
||||
aes_gcm_format_errors("Openssl wrote some unexpected bytes.", |
||||
error_details); |
||||
memset(plaintext_vec.iov_base, 0x00, plaintext_vec.iov_len); |
||||
return GRPC_STATUS_INTERNAL; |
||||
} |
||||
*plaintext_bytes_written = plaintext_vec.iov_len - plaintext_length; |
||||
return GRPC_STATUS_OK; |
||||
} |
||||
|
||||
static void gsec_aes_gcm_aead_crypter_destroy(gsec_aead_crypter* crypter) { |
||||
gsec_aes_gcm_aead_crypter* aes_gcm_crypter = |
||||
reinterpret_cast<gsec_aes_gcm_aead_crypter*>( |
||||
const_cast<gsec_aead_crypter*>(crypter)); |
||||
gpr_free(aes_gcm_crypter->key); |
||||
gpr_free(aes_gcm_crypter->rekey_data); |
||||
EVP_CIPHER_CTX_free(aes_gcm_crypter->ctx); |
||||
} |
||||
|
||||
static const gsec_aead_crypter_vtable vtable = { |
||||
gsec_aes_gcm_aead_crypter_encrypt_iovec, |
||||
gsec_aes_gcm_aead_crypter_decrypt_iovec, |
||||
gsec_aes_gcm_aead_crypter_max_ciphertext_and_tag_length, |
||||
gsec_aes_gcm_aead_crypter_max_plaintext_length, |
||||
gsec_aes_gcm_aead_crypter_nonce_length, |
||||
gsec_aes_gcm_aead_crypter_key_length, |
||||
gsec_aes_gcm_aead_crypter_tag_length, |
||||
gsec_aes_gcm_aead_crypter_destroy}; |
||||
|
||||
static grpc_status_code aes_gcm_new_evp_cipher_ctx( |
||||
gsec_aes_gcm_aead_crypter* aes_gcm_crypter, char** error_details) { |
||||
const EVP_CIPHER* cipher = nullptr; |
||||
bool is_rekey = aes_gcm_crypter->rekey_data != nullptr; |
||||
switch (is_rekey ? kRekeyAeadKeyLen : aes_gcm_crypter->key_length) { |
||||
case kAes128GcmKeyLength: |
||||
cipher = EVP_aes_128_gcm(); |
||||
break; |
||||
case kAes256GcmKeyLength: |
||||
cipher = EVP_aes_256_gcm(); |
||||
break; |
||||
} |
||||
const uint8_t* aead_key = aes_gcm_crypter->key; |
||||
uint8_t aead_key_rekey[kRekeyAeadKeyLen]; |
||||
if (is_rekey) { |
||||
if (aes_gcm_derive_aead_key(aead_key_rekey, aes_gcm_crypter->key, |
||||
aes_gcm_crypter->rekey_data->kdf_counter) != |
||||
GRPC_STATUS_OK) { |
||||
aes_gcm_format_errors("Deriving key failed.", error_details); |
||||
return GRPC_STATUS_INTERNAL; |
||||
} |
||||
aead_key = aead_key_rekey; |
||||
} |
||||
if (!EVP_DecryptInit_ex(aes_gcm_crypter->ctx, cipher, nullptr, aead_key, |
||||
nullptr)) { |
||||
aes_gcm_format_errors("Setting key failed.", error_details); |
||||
return GRPC_STATUS_INTERNAL; |
||||
} |
||||
if (!EVP_CIPHER_CTX_ctrl(aes_gcm_crypter->ctx, EVP_CTRL_GCM_SET_IVLEN, |
||||
static_cast<int>(aes_gcm_crypter->nonce_length), |
||||
nullptr)) { |
||||
aes_gcm_format_errors("Setting nonce length failed.", error_details); |
||||
return GRPC_STATUS_INTERNAL; |
||||
} |
||||
return GRPC_STATUS_OK; |
||||
} |
||||
|
||||
grpc_status_code gsec_aes_gcm_aead_crypter_create(const uint8_t* key, |
||||
size_t key_length, |
||||
size_t nonce_length, |
||||
size_t tag_length, bool rekey, |
||||
gsec_aead_crypter** crypter, |
||||
char** error_details) { |
||||
if (key == nullptr) { |
||||
aes_gcm_format_errors("key is nullptr.", error_details); |
||||
return GRPC_STATUS_FAILED_PRECONDITION; |
||||
} |
||||
if (crypter == nullptr) { |
||||
aes_gcm_format_errors("crypter is nullptr.", error_details); |
||||
return GRPC_STATUS_FAILED_PRECONDITION; |
||||
} |
||||
*crypter = nullptr; |
||||
if ((rekey && key_length != kAes128GcmRekeyKeyLength) || |
||||
(!rekey && key_length != kAes128GcmKeyLength && |
||||
key_length != kAes256GcmKeyLength) || |
||||
(tag_length != kAesGcmTagLength) || |
||||
(nonce_length != kAesGcmNonceLength)) { |
||||
aes_gcm_format_errors( |
||||
"Invalid key and/or nonce and/or tag length are provided at AEAD " |
||||
"crypter instance construction time.", |
||||
error_details); |
||||
return GRPC_STATUS_FAILED_PRECONDITION; |
||||
} |
||||
gsec_aes_gcm_aead_crypter* aes_gcm_crypter = |
||||
static_cast<gsec_aes_gcm_aead_crypter*>( |
||||
gpr_malloc(sizeof(gsec_aes_gcm_aead_crypter))); |
||||
aes_gcm_crypter->crypter.vtable = &vtable; |
||||
aes_gcm_crypter->nonce_length = nonce_length; |
||||
aes_gcm_crypter->tag_length = tag_length; |
||||
if (rekey) { |
||||
aes_gcm_crypter->key_length = kKdfKeyLen; |
||||
aes_gcm_crypter->rekey_data = static_cast<gsec_aes_gcm_aead_rekey_data*>( |
||||
gpr_malloc(sizeof(gsec_aes_gcm_aead_rekey_data))); |
||||
memcpy(aes_gcm_crypter->rekey_data->nonce_mask, key + kKdfKeyLen, |
||||
kAesGcmNonceLength); |
||||
// Set kdf_counter to all-zero for initial key derivation.
|
||||
memset(aes_gcm_crypter->rekey_data->kdf_counter, 0, kKdfCounterLen); |
||||
} else { |
||||
aes_gcm_crypter->key_length = key_length; |
||||
aes_gcm_crypter->rekey_data = nullptr; |
||||
} |
||||
aes_gcm_crypter->key = |
||||
static_cast<uint8_t*>(gpr_malloc(aes_gcm_crypter->key_length)); |
||||
memcpy(aes_gcm_crypter->key, key, aes_gcm_crypter->key_length); |
||||
aes_gcm_crypter->ctx = EVP_CIPHER_CTX_new(); |
||||
grpc_status_code status = |
||||
aes_gcm_new_evp_cipher_ctx(aes_gcm_crypter, error_details); |
||||
if (status != GRPC_STATUS_OK) { |
||||
gsec_aes_gcm_aead_crypter_destroy(&aes_gcm_crypter->crypter); |
||||
gpr_free(aes_gcm_crypter); |
||||
return status; |
||||
} |
||||
*crypter = &aes_gcm_crypter->crypter; |
||||
return GRPC_STATUS_OK; |
||||
} |
@ -0,0 +1,189 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2018 gRPC authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
* |
||||
*/ |
||||
|
||||
#include <grpc/support/port_platform.h> |
||||
|
||||
#include "src/core/tsi/alts/crypt/gsec.h" |
||||
|
||||
#include <stdio.h> |
||||
#include <string.h> |
||||
|
||||
#include <grpc/support/alloc.h> |
||||
|
||||
static const char vtable_error_msg[] = |
||||
"crypter or crypter->vtable has not been initialized properly"; |
||||
|
||||
static void maybe_copy_error_msg(const char* src, char** dst) { |
||||
if (dst != nullptr && src != nullptr) { |
||||
*dst = static_cast<char*>(gpr_malloc(strlen(src) + 1)); |
||||
memcpy(*dst, src, strlen(src) + 1); |
||||
} |
||||
} |
||||
|
||||
grpc_status_code gsec_aead_crypter_encrypt( |
||||
gsec_aead_crypter* crypter, const uint8_t* nonce, size_t nonce_length, |
||||
const uint8_t* aad, size_t aad_length, const uint8_t* plaintext, |
||||
size_t plaintext_length, uint8_t* ciphertext_and_tag, |
||||
size_t ciphertext_and_tag_length, size_t* bytes_written, |
||||
char** error_details) { |
||||
if (crypter != nullptr && crypter->vtable != nullptr && |
||||
crypter->vtable->encrypt_iovec != nullptr) { |
||||
struct iovec aad_vec = {(void*)aad, aad_length}; |
||||
struct iovec plaintext_vec = {(void*)plaintext, plaintext_length}; |
||||
struct iovec ciphertext_vec = {ciphertext_and_tag, |
||||
ciphertext_and_tag_length}; |
||||
return crypter->vtable->encrypt_iovec( |
||||
crypter, nonce, nonce_length, &aad_vec, 1, &plaintext_vec, 1, |
||||
ciphertext_vec, bytes_written, error_details); |
||||
} |
||||
/* An error occurred. */ |
||||
maybe_copy_error_msg(vtable_error_msg, error_details); |
||||
return GRPC_STATUS_INVALID_ARGUMENT; |
||||
} |
||||
|
||||
grpc_status_code gsec_aead_crypter_encrypt_iovec( |
||||
gsec_aead_crypter* crypter, const uint8_t* nonce, size_t nonce_length, |
||||
const struct iovec* aad_vec, size_t aad_vec_length, |
||||
const struct iovec* plaintext_vec, size_t plaintext_vec_length, |
||||
struct iovec ciphertext_vec, size_t* ciphertext_bytes_written, |
||||
char** error_details) { |
||||
if (crypter != nullptr && crypter->vtable != nullptr && |
||||
crypter->vtable->encrypt_iovec != nullptr) { |
||||
return crypter->vtable->encrypt_iovec( |
||||
crypter, nonce, nonce_length, aad_vec, aad_vec_length, plaintext_vec, |
||||
plaintext_vec_length, ciphertext_vec, ciphertext_bytes_written, |
||||
error_details); |
||||
} |
||||
/* An error occurred. */ |
||||
maybe_copy_error_msg(vtable_error_msg, error_details); |
||||
return GRPC_STATUS_INVALID_ARGUMENT; |
||||
} |
||||
|
||||
grpc_status_code gsec_aead_crypter_decrypt( |
||||
gsec_aead_crypter* crypter, const uint8_t* nonce, size_t nonce_length, |
||||
const uint8_t* aad, size_t aad_length, const uint8_t* ciphertext_and_tag, |
||||
size_t ciphertext_and_tag_length, uint8_t* plaintext, |
||||
size_t plaintext_length, size_t* bytes_written, char** error_details) { |
||||
if (crypter != nullptr && crypter->vtable != nullptr && |
||||
crypter->vtable->decrypt_iovec != nullptr) { |
||||
struct iovec aad_vec = {(void*)aad, aad_length}; |
||||
struct iovec ciphertext_vec = {(void*)ciphertext_and_tag, |
||||
ciphertext_and_tag_length}; |
||||
struct iovec plaintext_vec = {plaintext, plaintext_length}; |
||||
return crypter->vtable->decrypt_iovec( |
||||
crypter, nonce, nonce_length, &aad_vec, 1, &ciphertext_vec, 1, |
||||
plaintext_vec, bytes_written, error_details); |
||||
} |
||||
/* An error occurred. */ |
||||
maybe_copy_error_msg(vtable_error_msg, error_details); |
||||
return GRPC_STATUS_INVALID_ARGUMENT; |
||||
} |
||||
|
||||
grpc_status_code gsec_aead_crypter_decrypt_iovec( |
||||
gsec_aead_crypter* crypter, const uint8_t* nonce, size_t nonce_length, |
||||
const struct iovec* aad_vec, size_t aad_vec_length, |
||||
const struct iovec* ciphertext_vec, size_t ciphertext_vec_length, |
||||
struct iovec plaintext_vec, size_t* plaintext_bytes_written, |
||||
char** error_details) { |
||||
if (crypter != nullptr && crypter->vtable != nullptr && |
||||
crypter->vtable->encrypt_iovec != nullptr) { |
||||
return crypter->vtable->decrypt_iovec( |
||||
crypter, nonce, nonce_length, aad_vec, aad_vec_length, ciphertext_vec, |
||||
ciphertext_vec_length, plaintext_vec, plaintext_bytes_written, |
||||
error_details); |
||||
} |
||||
/* An error occurred. */ |
||||
maybe_copy_error_msg(vtable_error_msg, error_details); |
||||
return GRPC_STATUS_INVALID_ARGUMENT; |
||||
} |
||||
|
||||
grpc_status_code gsec_aead_crypter_max_ciphertext_and_tag_length( |
||||
const gsec_aead_crypter* crypter, size_t plaintext_length, |
||||
size_t* max_ciphertext_and_tag_length_to_return, char** error_details) { |
||||
if (crypter != nullptr && crypter->vtable != nullptr && |
||||
crypter->vtable->max_ciphertext_and_tag_length != nullptr) { |
||||
return crypter->vtable->max_ciphertext_and_tag_length( |
||||
crypter, plaintext_length, max_ciphertext_and_tag_length_to_return, |
||||
error_details); |
||||
} |
||||
/* An error occurred. */ |
||||
maybe_copy_error_msg(vtable_error_msg, error_details); |
||||
return GRPC_STATUS_INVALID_ARGUMENT; |
||||
} |
||||
|
||||
grpc_status_code gsec_aead_crypter_max_plaintext_length( |
||||
const gsec_aead_crypter* crypter, size_t ciphertext_and_tag_length, |
||||
size_t* max_plaintext_length_to_return, char** error_details) { |
||||
if (crypter != nullptr && crypter->vtable != nullptr && |
||||
crypter->vtable->max_plaintext_length != nullptr) { |
||||
return crypter->vtable->max_plaintext_length( |
||||
crypter, ciphertext_and_tag_length, max_plaintext_length_to_return, |
||||
error_details); |
||||
} |
||||
/* An error occurred. */ |
||||
maybe_copy_error_msg(vtable_error_msg, error_details); |
||||
return GRPC_STATUS_INVALID_ARGUMENT; |
||||
} |
||||
|
||||
grpc_status_code gsec_aead_crypter_nonce_length( |
||||
const gsec_aead_crypter* crypter, size_t* nonce_length_to_return, |
||||
char** error_details) { |
||||
if (crypter != nullptr && crypter->vtable != nullptr && |
||||
crypter->vtable->nonce_length != nullptr) { |
||||
return crypter->vtable->nonce_length(crypter, nonce_length_to_return, |
||||
error_details); |
||||
} |
||||
/* An error occurred. */ |
||||
maybe_copy_error_msg(vtable_error_msg, error_details); |
||||
return GRPC_STATUS_INVALID_ARGUMENT; |
||||
} |
||||
|
||||
grpc_status_code gsec_aead_crypter_key_length(const gsec_aead_crypter* crypter, |
||||
size_t* key_length_to_return, |
||||
char** error_details) { |
||||
if (crypter != nullptr && crypter->vtable != nullptr && |
||||
crypter->vtable->key_length != nullptr) { |
||||
return crypter->vtable->key_length(crypter, key_length_to_return, |
||||
error_details); |
||||
} |
||||
/* An error occurred */ |
||||
maybe_copy_error_msg(vtable_error_msg, error_details); |
||||
return GRPC_STATUS_INVALID_ARGUMENT; |
||||
} |
||||
|
||||
grpc_status_code gsec_aead_crypter_tag_length(const gsec_aead_crypter* crypter, |
||||
size_t* tag_length_to_return, |
||||
char** error_details) { |
||||
if (crypter != nullptr && crypter->vtable != nullptr && |
||||
crypter->vtable->tag_length != nullptr) { |
||||
return crypter->vtable->tag_length(crypter, tag_length_to_return, |
||||
error_details); |
||||
} |
||||
/* An error occurred. */ |
||||
maybe_copy_error_msg(vtable_error_msg, error_details); |
||||
return GRPC_STATUS_INVALID_ARGUMENT; |
||||
} |
||||
|
||||
void gsec_aead_crypter_destroy(gsec_aead_crypter* crypter) { |
||||
if (crypter != nullptr) { |
||||
if (crypter->vtable != nullptr && crypter->vtable->destruct != nullptr) { |
||||
crypter->vtable->destruct(crypter); |
||||
} |
||||
gpr_free(crypter); |
||||
} |
||||
} |
@ -0,0 +1,454 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2018 gRPC authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
* |
||||
*/ |
||||
|
||||
#ifndef GRPC_CORE_TSI_ALTS_CRYPT_GSEC_H |
||||
#define GRPC_CORE_TSI_ALTS_CRYPT_GSEC_H |
||||
|
||||
#include <grpc/support/port_platform.h> |
||||
|
||||
#include <assert.h> |
||||
#include <stdint.h> |
||||
#include <stdlib.h> |
||||
|
||||
#include <grpc/grpc.h> |
||||
|
||||
struct iovec { |
||||
void* iov_base; |
||||
size_t iov_len; |
||||
}; |
||||
|
||||
/**
|
||||
* A gsec interface for AEAD encryption schemes. The API is thread-compatible. |
||||
* Each implementation of this interface should specify supported values for |
||||
* key, nonce, and tag lengths. |
||||
*/ |
||||
|
||||
/* Key, nonce, and tag length in bytes */ |
||||
const size_t kAesGcmNonceLength = 12; |
||||
const size_t kAesGcmTagLength = 16; |
||||
const size_t kAes128GcmKeyLength = 16; |
||||
const size_t kAes256GcmKeyLength = 32; |
||||
|
||||
// The first 32 bytes are used as a KDF key and the remaining 12 bytes are used
|
||||
// to mask the nonce.
|
||||
const size_t kAes128GcmRekeyKeyLength = 44; |
||||
|
||||
typedef struct gsec_aead_crypter gsec_aead_crypter; |
||||
|
||||
/**
|
||||
* The gsec_aead_crypter is an API for different AEAD implementations such as |
||||
* AES_GCM. It encapsulates all AEAD-related operations in the format of |
||||
* V-table that stores pointers to functions implementing those operations. |
||||
* It also provides helper functions to wrap each of those function pointers. |
||||
* |
||||
* A typical usage of this object would be: |
||||
* |
||||
*------------------------------------------------------------------------------ |
||||
* // Declare a gsec_aead_crypter object, and create and assign an instance
|
||||
* // of specific AEAD implementation e.g., AES_GCM to it. We assume both
|
||||
* // key and nonce contain cryptographically secure random bytes, and the key
|
||||
* // can be derived from an upper-layer application.
|
||||
* gsec_aead_crypter* crypter; |
||||
* char* error_in_creation; |
||||
* // User can populate the message with any 100 bytes data.
|
||||
* uint8_t* message = gpr_malloc(100); |
||||
* grpc_status_code creation_status = gsec_aes_gcm_aead_crypter_create(key, |
||||
* kAes128GcmKeyLength, |
||||
* kAesGcmNonceLength, |
||||
* kAesGcmTagLength, |
||||
* &crypter, |
||||
* false, |
||||
* 0 |
||||
* &error_in_creation); |
||||
* |
||||
* if (creation_status == GRPC_STATUS_OK) { |
||||
* // Allocate a correct amount of memory to hold a ciphertext.
|
||||
* size_t clength = 0; |
||||
* gsec_aead_crypter_max_ciphertext_and_tag_length(crypter, 100, &clength, |
||||
* nullptr); |
||||
* uint8_t* ciphertext = gpr_malloc(clength); |
||||
* |
||||
* // Perform encryption
|
||||
* size_t num_encrypted_bytes = 0; |
||||
* char* error_in_encryption = nullptr; |
||||
* grpc_status_code status = gsec_aead_crypter_encrypt(crypter, nonce, |
||||
* kAesGcmNonceLength, |
||||
* nullptr, 0, message, |
||||
* 100, ciphertext, |
||||
* clength, |
||||
* &num_encrypted_bytes, |
||||
* &error_in_encryption); |
||||
* if (status == GRPC_STATUS_OK) { |
||||
* // Allocate a correct amount of memory to hold a plaintext.
|
||||
* size_t plength = 0; |
||||
* gsec_aead_crypter_max_plaintext_length(crypter, num_encrypted_bytes, |
||||
* &plength, nullptr); |
||||
* uint8_t* plaintext = gpr_malloc(plength); |
||||
* |
||||
* // Perform decryption.
|
||||
* size_t num_decrypted_bytes = 0; |
||||
* char* error_in_decryption = nullptr; |
||||
* status = gsec_aead_crypter_decrypt(crypter, nonce, |
||||
* kAesGcmNonceLength, nullptr, 0, |
||||
* ciphertext, num_encrypted_bytes, |
||||
* plaintext, plength, |
||||
* &num_decrypted_bytes, |
||||
* &error_in_decryption); |
||||
* if (status != GRPC_STATUS_OK) { |
||||
* fprintf(stderr, "AEAD decrypt operation failed with error code:" |
||||
* "%d, message: %s\n", status, error_in_decryption); |
||||
* } |
||||
* ... |
||||
* gpr_free(plaintext); |
||||
* gpr_free(error_in_decryption); |
||||
* } else { |
||||
* fprintf(stderr, "AEAD encrypt operation failed with error code:" |
||||
* "%d, message: %s\n", status, error_in_encryption); |
||||
* } |
||||
* ... |
||||
* gpr_free(ciphertext); |
||||
* gpr_free(error_in_encryption); |
||||
* } else { |
||||
* fprintf(stderr, "Creation of AEAD crypter instance failed with error code:" |
||||
* "%d, message: %s\n", creation_status, error_in_creation); |
||||
* } |
||||
* |
||||
* // Destruct AEAD crypter instance.
|
||||
* if (creation_status == GRPC_STATUS_OK) { |
||||
* gsec_aead_crypter_destroy(crypter); |
||||
* } |
||||
* gpr_free(error_in_creation); |
||||
* gpr_free(message); |
||||
* ----------------------------------------------------------------------------- |
||||
*/ |
||||
|
||||
/* V-table for gsec AEAD operations */ |
||||
typedef struct gsec_aead_crypter_vtable { |
||||
grpc_status_code (*encrypt_iovec)( |
||||
gsec_aead_crypter* crypter, const uint8_t* nonce, size_t nonce_length, |
||||
const struct iovec* aad_vec, size_t aad_vec_length, |
||||
const struct iovec* plaintext_vec, size_t plaintext_vec_length, |
||||
struct iovec ciphertext_vec, size_t* ciphertext_bytes_written, |
||||
char** error_details); |
||||
grpc_status_code (*decrypt_iovec)( |
||||
gsec_aead_crypter* crypter, const uint8_t* nonce, size_t nonce_length, |
||||
const struct iovec* aad_vec, size_t aad_vec_length, |
||||
const struct iovec* ciphertext_vec, size_t ciphertext_vec_length, |
||||
struct iovec plaintext_vec, size_t* plaintext_bytes_written, |
||||
char** error_details); |
||||
grpc_status_code (*max_ciphertext_and_tag_length)( |
||||
const gsec_aead_crypter* crypter, size_t plaintext_length, |
||||
size_t* max_ciphertext_and_tag_length_to_return, char** error_details); |
||||
grpc_status_code (*max_plaintext_length)( |
||||
const gsec_aead_crypter* crypter, size_t ciphertext_and_tag_length, |
||||
size_t* max_plaintext_length_to_return, char** error_details); |
||||
grpc_status_code (*nonce_length)(const gsec_aead_crypter* crypter, |
||||
size_t* nonce_length_to_return, |
||||
char** error_details); |
||||
grpc_status_code (*key_length)(const gsec_aead_crypter* crypter, |
||||
size_t* key_length_to_return, |
||||
char** error_details); |
||||
grpc_status_code (*tag_length)(const gsec_aead_crypter* crypter, |
||||
size_t* tag_length_to_return, |
||||
char** error_details); |
||||
void (*destruct)(gsec_aead_crypter* crypter); |
||||
} gsec_aead_crypter_vtable; |
||||
|
||||
/* Main struct for gsec interface */ |
||||
struct gsec_aead_crypter { |
||||
const struct gsec_aead_crypter_vtable* vtable; |
||||
}; |
||||
|
||||
/**
|
||||
* This method performs an AEAD encrypt operation. |
||||
* |
||||
* - crypter: AEAD crypter instance. |
||||
* - nonce: buffer containing a nonce with its size equal to nonce_length. |
||||
* - nonce_length: size of nonce buffer, and must be equal to the value returned |
||||
* from method gsec_aead_crypter_nonce_length. |
||||
* - aad: buffer containing data that needs to be authenticated but not |
||||
* encrypted with its size equal to aad_length. |
||||
* - aad_length: size of aad buffer, which should be zero if the buffer is |
||||
* nullptr. |
||||
* - plaintext: buffer containing data that needs to be both encrypted and |
||||
* authenticated with its size equal to plaintext_length. |
||||
* - plaintext_length: size of plaintext buffer, which should be zero if |
||||
* plaintext is nullptr. |
||||
* - ciphertext_and_tag: buffer that will contain ciphertext and tags the method |
||||
* produced. The buffer should not overlap the plaintext buffer, and pointers |
||||
* to those buffers should not be equal. Also if the ciphertext+tag buffer is |
||||
* nullptr, the plaintext_length should be zero. |
||||
* - ciphertext_and_tag_length: size of ciphertext+tag buffer, which should be |
||||
* at least as long as the one returned from method |
||||
* gsec_aead_crypter_max_ciphertext_and_tag_length. |
||||
* - bytes_written: the actual number of bytes written to the ciphertext+tag |
||||
* buffer. If bytes_written is nullptr, the plaintext_length should be zero. |
||||
* - error_details: a buffer containing an error message if the method does not |
||||
* function correctly. It is legal to pass nullptr into error_details, and |
||||
* otherwise, the parameter should be freed with gpr_free. |
||||
* |
||||
* On the success of encryption, the method returns GRPC_STATUS_OK. Otherwise, |
||||
* it returns an error status code along with its details specified in |
||||
* error_details (if error_details is not nullptr). |
||||
* |
||||
*/ |
||||
grpc_status_code gsec_aead_crypter_encrypt( |
||||
gsec_aead_crypter* crypter, const uint8_t* nonce, size_t nonce_length, |
||||
const uint8_t* aad, size_t aad_length, const uint8_t* plaintext, |
||||
size_t plaintext_length, uint8_t* ciphertext_and_tag, |
||||
size_t ciphertext_and_tag_length, size_t* bytes_written, |
||||
char** error_details); |
||||
|
||||
/**
|
||||
* This method performs an AEAD encrypt operation. |
||||
* |
||||
* - crypter: AEAD crypter instance. |
||||
* - nonce: buffer containing a nonce with its size equal to nonce_length. |
||||
* - nonce_length: size of nonce buffer, and must be equal to the value returned |
||||
* from method gsec_aead_crypter_nonce_length. |
||||
* - aad_vec: an iovec array containing data that needs to be authenticated but |
||||
* not encrypted. |
||||
* - aad_vec_length: the array length of aad_vec. |
||||
* - plaintext_vec: an iovec array containing data that needs to be both |
||||
* encrypted and authenticated. |
||||
* - plaintext_vec_length: the array length of plaintext_vec. |
||||
* - ciphertext_vec: an iovec containing a ciphertext buffer. The buffer should |
||||
* not overlap the plaintext buffer. |
||||
* - ciphertext_bytes_written: the actual number of bytes written to |
||||
* ciphertext_vec. |
||||
* - error_details: a buffer containing an error message if the method does not |
||||
* function correctly. It is legal to pass nullptr into error_details, and |
||||
* otherwise, the parameter should be freed with gpr_free. |
||||
* |
||||
* On the success of encryption, the method returns GRPC_STATUS_OK. Otherwise, |
||||
* it returns an error status code along with its details specified in |
||||
* error_details (if error_details is not nullptr). |
||||
* |
||||
*/ |
||||
grpc_status_code gsec_aead_crypter_encrypt_iovec( |
||||
gsec_aead_crypter* crypter, const uint8_t* nonce, size_t nonce_length, |
||||
const struct iovec* aad_vec, size_t aad_vec_length, |
||||
const struct iovec* plaintext_vec, size_t plaintext_vec_length, |
||||
struct iovec ciphertext_vec, size_t* ciphertext_bytes_written, |
||||
char** error_details); |
||||
|
||||
/**
|
||||
* This method performs an AEAD decrypt operation. |
||||
* |
||||
* - crypter: AEAD crypter instance. |
||||
* - nonce: buffer containing a nonce with its size equal to nonce_length. |
||||
* - nonce_length: size of nonce buffer, and must be equal to the value returned |
||||
* from method gsec_aead_crypter_nonce_length. |
||||
* - aad: buffer containing data that needs to be authenticated only. |
||||
* - aad_length: size of aad buffer, which should be zero if the buffer is |
||||
* nullptr. |
||||
* - ciphertext_and_tag: buffer containing ciphertext and tag. |
||||
* - ciphertext_and_tag_length: length of ciphertext and tag. It should be zero |
||||
* if any of plaintext, ciphertext_and_tag, or bytes_written is nullptr. Also, |
||||
* ciphertext_and_tag_length should be at least as large as the tag length set |
||||
* at AEAD crypter instance construction time. |
||||
* - plaintext: buffer containing decrypted and authenticated data the method |
||||
* produced. The buffer should not overlap with the ciphertext+tag buffer, and |
||||
* pointers to those buffers should not be equal. |
||||
* - plaintext_length: size of plaintext buffer, which should be at least as |
||||
* long as the one returned from gsec_aead_crypter_max_plaintext_length |
||||
* method. |
||||
* - bytes_written: the actual number of bytes written to the plaintext |
||||
* buffer. |
||||
* - error_details: a buffer containing an error message if the method does not |
||||
* function correctly. It is legal to pass nullptr into error_details, and |
||||
* otherwise, the parameter should be freed with gpr_free. |
||||
* |
||||
* On the success of decryption, the method returns GRPC_STATUS_OK. Otherwise, |
||||
* it returns an error status code along with its details specified in |
||||
* error_details (if error_details is not nullptr). |
||||
*/ |
||||
grpc_status_code gsec_aead_crypter_decrypt( |
||||
gsec_aead_crypter* crypter, const uint8_t* nonce, size_t nonce_length, |
||||
const uint8_t* aad, size_t aad_length, const uint8_t* ciphertext_and_tag, |
||||
size_t ciphertext_and_tag_length, uint8_t* plaintext, |
||||
size_t plaintext_length, size_t* bytes_written, char** error_details); |
||||
|
||||
/**
|
||||
* This method performs an AEAD decrypt operation. |
||||
* |
||||
* - crypter: AEAD crypter instance. |
||||
* - nonce: buffer containing a nonce with its size equal to nonce_length. |
||||
* - nonce_length: size of nonce buffer, and must be equal to the value returned |
||||
* from method gsec_aead_crypter_nonce_length. |
||||
* - aad_vec: an iovec array containing data that needs to be authenticated but |
||||
* not encrypted. |
||||
* - aad_vec_length: the array length of aad_vec. |
||||
* - ciphertext_vec: an iovec array containing the ciphertext and tag. |
||||
* - ciphertext_vec_length: the array length of ciphertext_vec. |
||||
* - plaintext_vec: an iovec containing a plaintext buffer. The buffer should |
||||
* not overlap the ciphertext buffer. |
||||
* - plaintext_bytes_written: the actual number of bytes written to |
||||
* plaintext_vec. |
||||
* - error_details: a buffer containing an error message if the method does not |
||||
* function correctly. It is legal to pass nullptr into error_details, and |
||||
* otherwise, the parameter should be freed with gpr_free. |
||||
* |
||||
* On the success of decryption, the method returns GRPC_STATUS_OK. Otherwise, |
||||
* it returns an error status code along with its details specified in |
||||
* error_details (if error_details is not nullptr). |
||||
*/ |
||||
grpc_status_code gsec_aead_crypter_decrypt_iovec( |
||||
gsec_aead_crypter* crypter, const uint8_t* nonce, size_t nonce_length, |
||||
const struct iovec* aad_vec, size_t aad_vec_length, |
||||
const struct iovec* ciphertext_vec, size_t ciphertext_vec_length, |
||||
struct iovec plaintext_vec, size_t* plaintext_bytes_written, |
||||
char** error_details); |
||||
|
||||
/**
|
||||
* This method computes the size of ciphertext+tag buffer that must be passed to |
||||
* gsec_aead_crypter_encrypt function to ensure correct encryption of a |
||||
* plaintext. The actual size of ciphertext+tag written to the buffer could be |
||||
* smaller. |
||||
* |
||||
* - crypter: AEAD crypter instance. |
||||
* - plaintext_length: length of plaintext. |
||||
* - max_ciphertext_and_tag_length_to_return: the size of ciphertext+tag buffer |
||||
* the method returns. |
||||
* - error_details: a buffer containing an error message if the method does not |
||||
* function correctly. It is legal to pass nullptr into error_details, and |
||||
* otherwise, the parameter should be freed with gpr_free. |
||||
* |
||||
* On the success of execution, the method returns GRPC_STATUS_OK. Otherwise, |
||||
* it returns an error status code along with its details specified in |
||||
* error_details (if error_details is not nullptr). |
||||
*/ |
||||
grpc_status_code gsec_aead_crypter_max_ciphertext_and_tag_length( |
||||
const gsec_aead_crypter* crypter, size_t plaintext_length, |
||||
size_t* max_ciphertext_and_tag_length_to_return, char** error_details); |
||||
|
||||
/**
|
||||
* This method computes the size of plaintext buffer that must be passed to |
||||
* gsec_aead_crypter_decrypt function to ensure correct decryption of a |
||||
* ciphertext. The actual size of plaintext written to the buffer could be |
||||
* smaller. |
||||
* |
||||
* - crypter: AEAD crypter instance. |
||||
* - ciphertext_and_tag_length: length of ciphertext and tag. |
||||
* - max_plaintext_length_to_return: the size of plaintext buffer the method |
||||
* returns. |
||||
* - error_details: a buffer containing an error message if the method does not |
||||
* function correctly. It is legal to pass nullptr into error_details, and |
||||
* otherwise, the parameter should be freed with gpr_free. |
||||
* |
||||
* On the success of execution, the method returns GRPC_STATUS_OK. Otherwise, |
||||
* it returns an error status code along with its details specified in |
||||
* error_details (if error_details is not nullptr). |
||||
*/ |
||||
grpc_status_code gsec_aead_crypter_max_plaintext_length( |
||||
const gsec_aead_crypter* crypter, size_t ciphertext_and_tag_length, |
||||
size_t* max_plaintext_length_to_return, char** error_details); |
||||
|
||||
/**
|
||||
* This method returns a valid size of nonce array used at the construction of |
||||
* AEAD crypter instance. It is also the size that should be passed to encrypt |
||||
* and decrypt methods executed on the instance. |
||||
* |
||||
* - crypter: AEAD crypter instance. |
||||
* - nonce_length_to_return: the length of nonce array the method returns. |
||||
* - error_details: a buffer containing an error message if the method does not |
||||
* function correctly. It is legal to pass nullptr into error_details, and |
||||
* otherwise, the parameter should be freed with gpr_free. |
||||
* |
||||
* On the success of execution, the method returns GRPC_STATUS_OK. Otherwise, |
||||
* it returns an error status code along with its details specified in |
||||
* error_details (if error_details is not nullptr). |
||||
*/ |
||||
grpc_status_code gsec_aead_crypter_nonce_length( |
||||
const gsec_aead_crypter* crypter, size_t* nonce_length_to_return, |
||||
char** error_details); |
||||
|
||||
/**
|
||||
* This method returns a valid size of key array used at the construction of |
||||
* AEAD crypter instance. It is also the size that should be passed to encrypt |
||||
* and decrypt methods executed on the instance. |
||||
* |
||||
* - crypter: AEAD crypter instance. |
||||
* - key_length_to_return: the length of key array the method returns. |
||||
* - error_details: a buffer containing an error message if the method does not |
||||
* function correctly. It is legal to pass nullptr into error_details, and |
||||
* otherwise, the parameter should be freed with gpr_free. |
||||
* |
||||
* On the success of execution, the method returns GRPC_STATUS_OK. Otherwise, |
||||
* it returns an error status code along with its details specified in |
||||
* error_details (if error_details is not nullptr). |
||||
*/ |
||||
grpc_status_code gsec_aead_crypter_key_length(const gsec_aead_crypter* crypter, |
||||
size_t* key_length_to_return, |
||||
char** error_details); |
||||
/**
|
||||
* This method returns a valid size of tag array used at the construction of |
||||
* AEAD crypter instance. It is also the size that should be passed to encrypt |
||||
* and decrypt methods executed on the instance. |
||||
* |
||||
* - crypter: AEAD crypter instance. |
||||
* - tag_length_to_return: the length of tag array the method returns. |
||||
* - error_details: a buffer containing an error message if the method does not |
||||
* function correctly. It is legal to pass nullptr into error_details, and |
||||
* otherwise, the parameter should be freed with gpr_free. |
||||
* |
||||
* On the success of execution, the method returns GRPC_STATUS_OK. Otherwise, |
||||
* it returns an error status code along with its details specified in |
||||
* error_details (if error_details is not nullptr). |
||||
*/ |
||||
grpc_status_code gsec_aead_crypter_tag_length(const gsec_aead_crypter* crypter, |
||||
size_t* tag_length_to_return, |
||||
char** error_details); |
||||
|
||||
/**
|
||||
* This method destroys an AEAD crypter instance by de-allocating all of its |
||||
* occupied memory. |
||||
* |
||||
* - crypter: AEAD crypter instance that needs to be destroyed. |
||||
*/ |
||||
void gsec_aead_crypter_destroy(gsec_aead_crypter* crypter); |
||||
|
||||
/**
|
||||
* This method creates an AEAD crypter instance of AES-GCM encryption scheme |
||||
* which supports 16 and 32 bytes long keys, 12 and 16 bytes long nonces, and |
||||
* 16 bytes long tags. It should be noted that once the lengths of key, nonce, |
||||
* and tag are determined at construction time, they cannot be modified later. |
||||
* |
||||
* - key: buffer containing a key which is binded with AEAD crypter instance. |
||||
* - key_length: length of a key in bytes, which should be 44 if rekeying is |
||||
* enabled and 16 or 32 otherwise. |
||||
* - nonce_length: length of a nonce in bytes, which should be either 12 or 16. |
||||
* - tag_length: length of a tag in bytes, which should be always 16. |
||||
* - rekey: enable nonce-based rekeying and nonce-masking. |
||||
* - crypter: address of AES_GCM crypter instance returned from the method. |
||||
* - error_details: a buffer containing an error message if the method does not |
||||
* function correctly. It is legal to pass nullptr into error_details, and |
||||
* otherwise, the parameter should be freed with gpr_free. |
||||
* |
||||
* On success of instance creation, it stores the address of instance at |
||||
* crypter. Otherwise, it returns an error status code together with its details |
||||
* specified in error_details. |
||||
*/ |
||||
grpc_status_code gsec_aes_gcm_aead_crypter_create(const uint8_t* key, |
||||
size_t key_length, |
||||
size_t nonce_length, |
||||
size_t tag_length, bool rekey, |
||||
gsec_aead_crypter** crypter, |
||||
char** error_details); |
||||
|
||||
#endif /* GRPC_CORE_TSI_ALTS_CRYPT_GSEC_H */ |
@ -0,0 +1,118 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2018 gRPC authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
* |
||||
*/ |
||||
|
||||
#include <grpc/support/port_platform.h> |
||||
|
||||
#include "src/core/tsi/alts/frame_protector/alts_counter.h" |
||||
|
||||
#include <string.h> |
||||
|
||||
#include <grpc/support/alloc.h> |
||||
|
||||
static void maybe_copy_error_msg(const char* src, char** dst) { |
||||
if (dst != nullptr && src != nullptr) { |
||||
*dst = static_cast<char*>(gpr_malloc(strlen(src) + 1)); |
||||
memcpy(*dst, src, strlen(src) + 1); |
||||
} |
||||
} |
||||
|
||||
grpc_status_code alts_counter_create(bool is_client, size_t counter_size, |
||||
size_t overflow_size, |
||||
alts_counter** crypter_counter, |
||||
char** error_details) { |
||||
/* Perform input sanity check. */ |
||||
if (counter_size == 0) { |
||||
const char error_msg[] = "counter_size is invalid."; |
||||
maybe_copy_error_msg(error_msg, error_details); |
||||
return GRPC_STATUS_INVALID_ARGUMENT; |
||||
} |
||||
if (overflow_size == 0 || overflow_size >= counter_size) { |
||||
const char error_msg[] = "overflow_size is invalid."; |
||||
maybe_copy_error_msg(error_msg, error_details); |
||||
return GRPC_STATUS_INVALID_ARGUMENT; |
||||
} |
||||
if (crypter_counter == nullptr) { |
||||
const char error_msg[] = "crypter_counter is nullptr."; |
||||
maybe_copy_error_msg(error_msg, error_details); |
||||
return GRPC_STATUS_INVALID_ARGUMENT; |
||||
} |
||||
*crypter_counter = |
||||
static_cast<alts_counter*>(gpr_malloc(sizeof(**crypter_counter))); |
||||
(*crypter_counter)->size = counter_size; |
||||
(*crypter_counter)->overflow_size = overflow_size; |
||||
(*crypter_counter)->counter = |
||||
static_cast<unsigned char*>(gpr_zalloc(counter_size)); |
||||
if (is_client) { |
||||
((*crypter_counter)->counter)[counter_size - 1] = 0x80; |
||||
} |
||||
return GRPC_STATUS_OK; |
||||
} |
||||
|
||||
grpc_status_code alts_counter_increment(alts_counter* crypter_counter, |
||||
bool* is_overflow, |
||||
char** error_details) { |
||||
/* Perform input sanity check. */ |
||||
if (crypter_counter == nullptr) { |
||||
const char error_msg[] = "crypter_counter is nullptr."; |
||||
maybe_copy_error_msg(error_msg, error_details); |
||||
return GRPC_STATUS_INVALID_ARGUMENT; |
||||
} |
||||
if (is_overflow == nullptr) { |
||||
const char error_msg[] = "is_overflow is nullptr."; |
||||
maybe_copy_error_msg(error_msg, error_details); |
||||
return GRPC_STATUS_INVALID_ARGUMENT; |
||||
} |
||||
/* Increment the internal counter. */ |
||||
size_t i = 0; |
||||
for (; i < crypter_counter->overflow_size; i++) { |
||||
(crypter_counter->counter)[i]++; |
||||
if ((crypter_counter->counter)[i] != 0x00) { |
||||
break; |
||||
} |
||||
} |
||||
/**
|
||||
* If the lower overflow_size bytes are all zero, the counter has overflowed. |
||||
*/ |
||||
if (i == crypter_counter->overflow_size) { |
||||
*is_overflow = true; |
||||
return GRPC_STATUS_FAILED_PRECONDITION; |
||||
} |
||||
*is_overflow = false; |
||||
return GRPC_STATUS_OK; |
||||
} |
||||
|
||||
size_t alts_counter_get_size(alts_counter* crypter_counter) { |
||||
if (crypter_counter == nullptr) { |
||||
return 0; |
||||
} |
||||
return crypter_counter->size; |
||||
} |
||||
|
||||
unsigned char* alts_counter_get_counter(alts_counter* crypter_counter) { |
||||
if (crypter_counter == nullptr) { |
||||
return nullptr; |
||||
} |
||||
return crypter_counter->counter; |
||||
} |
||||
|
||||
void alts_counter_destroy(alts_counter* crypter_counter) { |
||||
if (crypter_counter != nullptr) { |
||||
gpr_free(crypter_counter->counter); |
||||
gpr_free(crypter_counter); |
||||
} |
||||
} |
@ -0,0 +1,98 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2018 gRPC authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
* |
||||
*/ |
||||
|
||||
#ifndef GRPC_CORE_TSI_ALTS_FRAME_PROTECTOR_ALTS_COUNTER_H |
||||
#define GRPC_CORE_TSI_ALTS_FRAME_PROTECTOR_ALTS_COUNTER_H |
||||
|
||||
#include <grpc/support/port_platform.h> |
||||
|
||||
#include <stdbool.h> |
||||
#include <stdlib.h> |
||||
|
||||
#include <grpc/grpc.h> |
||||
|
||||
/* Main struct for a crypter counter managed within seal/unseal operations. */ |
||||
typedef struct alts_counter { |
||||
size_t size; |
||||
size_t overflow_size; |
||||
unsigned char* counter; |
||||
} alts_counter; |
||||
|
||||
/**
|
||||
* This method creates and initializes an alts_counter instance. |
||||
* |
||||
* - is_client: a flag indicating if the alts_counter instance will be used |
||||
* at client (is_client = true) or server (is_client = false) side. |
||||
* - counter_size: size of buffer holding the counter value. |
||||
* - overflow_size: overflow size in bytes. The counter instance can be used |
||||
* to produce at most 2^(overflow_size*8) frames. |
||||
* - crypter_counter: an alts_counter instance to be returned from the method. |
||||
* - error_details: a buffer containing an error message if the method does not |
||||
* function correctly. It is legal to pass nullptr into error_details and |
||||
* otherwise, the parameter should be freed with gpr_free. |
||||
* |
||||
* On success, the method returns GRPC_STATUS_OK. Otherwise, |
||||
* it returns an error status code along with its details specified in |
||||
* error_details (if error_details is not nullptr). |
||||
*/ |
||||
grpc_status_code alts_counter_create(bool is_client, size_t counter_size, |
||||
size_t overflow_size, |
||||
alts_counter** crypter_counter, |
||||
char** error_details); |
||||
|
||||
/**
|
||||
* This method increments the internal counter. |
||||
* |
||||
* - crypter_counter: an alts_counter instance. |
||||
* - is_overflow: after incrementing the internal counter, if an overflow |
||||
* occurs, is_overflow is set to true, and no further calls to |
||||
* alts_counter_increment() should be made. Otherwise, is_overflow is set to |
||||
* false. |
||||
* - error_details: a buffer containing an error message if the method does not |
||||
* function correctly. It is legal to pass nullptr into error_details and |
||||
* otherwise, the parameter should be freed with gpr_free. |
||||
* |
||||
* On success, the method returns GRPC_STATUS_OK. Otherwise, |
||||
* it returns an error status code along with its details specified in |
||||
* error_details (if error_details is not nullptr). |
||||
*/ |
||||
grpc_status_code alts_counter_increment(alts_counter* crypter_counter, |
||||
bool* is_overflow, |
||||
char** error_details); |
||||
|
||||
/**
|
||||
* This method returns the size of counter buffer. |
||||
* |
||||
* - crypter_counter: an alts_counter instance. |
||||
*/ |
||||
size_t alts_counter_get_size(alts_counter* crypter_counter); |
||||
|
||||
/**
|
||||
* This method returns the counter buffer. |
||||
* |
||||
* - crypter_counter: an alts_counter instance. |
||||
*/ |
||||
unsigned char* alts_counter_get_counter(alts_counter* crypter_counter); |
||||
|
||||
/**
|
||||
* This method de-allocates all memory allocated to an alts_coutner instance. |
||||
* - crypter_counter: an alts_counter instance. |
||||
*/ |
||||
void alts_counter_destroy(alts_counter* crypter_counter); |
||||
|
||||
#endif /* GRPC_CORE_TSI_ALTS_FRAME_PROTECTOR_ALTS_COUNTER_H */ |
@ -0,0 +1,66 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2018 gRPC authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
* |
||||
*/ |
||||
|
||||
#include <grpc/support/port_platform.h> |
||||
|
||||
#include "src/core/tsi/alts/frame_protector/alts_crypter.h" |
||||
|
||||
#include <string.h> |
||||
|
||||
#include <grpc/support/alloc.h> |
||||
|
||||
static void maybe_copy_error_msg(const char* src, char** dst) { |
||||
if (dst != nullptr && src != nullptr) { |
||||
*dst = static_cast<char*>(gpr_malloc(strlen(src) + 1)); |
||||
memcpy(*dst, src, strlen(src) + 1); |
||||
} |
||||
} |
||||
|
||||
grpc_status_code alts_crypter_process_in_place( |
||||
alts_crypter* crypter, unsigned char* data, size_t data_allocated_size, |
||||
size_t data_size, size_t* output_size, char** error_details) { |
||||
if (crypter != nullptr && crypter->vtable != nullptr && |
||||
crypter->vtable->process_in_place != nullptr) { |
||||
return crypter->vtable->process_in_place(crypter, data, data_allocated_size, |
||||
data_size, output_size, |
||||
error_details); |
||||
} |
||||
/* An error occurred. */ |
||||
const char error_msg[] = |
||||
"crypter or crypter->vtable has not been initialized properly."; |
||||
maybe_copy_error_msg(error_msg, error_details); |
||||
return GRPC_STATUS_INVALID_ARGUMENT; |
||||
} |
||||
|
||||
size_t alts_crypter_num_overhead_bytes(const alts_crypter* crypter) { |
||||
if (crypter != nullptr && crypter->vtable != nullptr && |
||||
crypter->vtable->num_overhead_bytes != nullptr) { |
||||
return crypter->vtable->num_overhead_bytes(crypter); |
||||
} |
||||
/* An error occurred. */ |
||||
return 0; |
||||
} |
||||
|
||||
void alts_crypter_destroy(alts_crypter* crypter) { |
||||
if (crypter != nullptr) { |
||||
if (crypter->vtable != nullptr && crypter->vtable->destruct != nullptr) { |
||||
crypter->vtable->destruct(crypter); |
||||
} |
||||
gpr_free(crypter); |
||||
} |
||||
} |
@ -0,0 +1,255 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2018 gRPC authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
* |
||||
*/ |
||||
|
||||
#ifndef GRPC_CORE_TSI_ALTS_FRAME_PROTECTOR_ALTS_CRYPTER_H |
||||
#define GRPC_CORE_TSI_ALTS_FRAME_PROTECTOR_ALTS_CRYPTER_H |
||||
|
||||
#include <grpc/support/port_platform.h> |
||||
|
||||
#include <stdbool.h> |
||||
#include <string.h> |
||||
|
||||
#include <grpc/grpc.h> |
||||
|
||||
#include "src/core/tsi/alts/crypt/gsec.h" |
||||
|
||||
/**
|
||||
* An alts_crypter interface for an ALTS record protocol providing |
||||
* seal/unseal functionality. The interface is thread-compatible. |
||||
*/ |
||||
|
||||
typedef struct alts_crypter alts_crypter; |
||||
|
||||
/**
|
||||
* A typical usage of the interface would be |
||||
*------------------------------------------------------------------------------ |
||||
* // Perform a seal operation. We assume the gsec_aead_crypter instance -
|
||||
* // client_aead_crypter is created beforehand with a 16-byte key and 12-byte
|
||||
* // nonce length.
|
||||
* |
||||
* alts_crypter* client = nullptr; |
||||
* char* client_error_in_creation = nullptr; |
||||
* unsigned char* data = nullptr; |
||||
* grpc_status_code client_status = |
||||
* alts_seal_crypter_create(client_aead_crypter, 1, 5, &client, |
||||
* &client_error_in_creation); |
||||
* if (client_status == GRPC_STATUS_OK) { |
||||
* size_t data_size = 100; |
||||
* size_t num_overhead_bytes = alts_crypter_num_overhead_bytes(client); |
||||
* size_t data_allocated_size = data_size + num_overhead_bytes; |
||||
* data = gpr_malloc(data_allocated_size); |
||||
* char* client_error_in_seal = nullptr; |
||||
* // Client performs a seal operation.
|
||||
* client_status = alts_crypter_process_in_place(client, data, |
||||
* data_allocated_size, |
||||
* &data_size, |
||||
* &client_error_in_seal); |
||||
* if (client_status != GRPC_STATUS_OK) { |
||||
* fprintf(stderr, "seal operation failed with error code:" |
||||
* "%d, message: %s\n", client_status, |
||||
* client_error_in_seal); |
||||
* } |
||||
* gpr_free(client_error_in_seal); |
||||
* } else { |
||||
* fprintf(stderr, "alts_crypter instance creation failed with error" |
||||
* "code: %d, message: %s\n", client_status, |
||||
* client_error_in_creation); |
||||
* } |
||||
* |
||||
* ... |
||||
* |
||||
* gpr_free(client_error_in_creation); |
||||
* alts_crypter_destroy(client); |
||||
* |
||||
* ... |
||||
* |
||||
* // Perform an unseal operation. We assume the gsec_aead_crypter instance -
|
||||
* // server_aead_crypter is created beforehand with a 16-byte key and 12-byte
|
||||
* // nonce length. The key used in the creation of gsec_aead_crypter instances
|
||||
* // at server and client sides should be identical.
|
||||
* |
||||
* alts_crypter* server = nullptr; |
||||
* char* server_error_in_creation = nullptr; |
||||
* grpc_status_code server_status = |
||||
* alts_unseal_crypter_create(server_aead_crypter, 0, 5, &server, |
||||
* &server_error_in_creation); |
||||
* if (server_status == GRPC_STATUS_OK) { |
||||
* size_t num_overhead_bytes = alts_crypter_num_overhead_bytes(server); |
||||
* size_t data_size = 100 + num_overhead_bytes; |
||||
* size_t data_allocated_size = data_size; |
||||
* char* server_error_in_unseal = nullptr; |
||||
* // Server performs an unseal operation.
|
||||
* server_status = alts_crypter_process_in_place(server, data, |
||||
* data_allocated_size, |
||||
* &data_size, |
||||
* &server_error_in_unseal); |
||||
* if (server_status != GRPC_STATUS_OK) { |
||||
* fprintf(stderr, "unseal operation failed with error code:" |
||||
* "%d, message: %s\n", server_status, |
||||
* server_error_in_unseal); |
||||
* } |
||||
* gpr_free(server_error_in_unseal); |
||||
* } else { |
||||
* fprintf(stderr, "alts_crypter instance creation failed with error" |
||||
* "code: %d, message: %s\n", server_status, |
||||
* server_error_in_creation); |
||||
* } |
||||
* |
||||
* ... |
||||
* |
||||
* gpr_free(data); |
||||
* gpr_free(server_error_in_creation); |
||||
* alts_crypter_destroy(server); |
||||
* |
||||
* ... |
||||
*------------------------------------------------------------------------------ |
||||
*/ |
||||
|
||||
/* V-table for alts_crypter operations */ |
||||
typedef struct alts_crypter_vtable { |
||||
size_t (*num_overhead_bytes)(const alts_crypter* crypter); |
||||
grpc_status_code (*process_in_place)(alts_crypter* crypter, |
||||
unsigned char* data, |
||||
size_t data_allocated_size, |
||||
size_t data_size, size_t* output_size, |
||||
char** error_details); |
||||
void (*destruct)(alts_crypter* crypter); |
||||
} alts_crypter_vtable; |
||||
|
||||
/* Main struct for alts_crypter interface */ |
||||
struct alts_crypter { |
||||
const alts_crypter_vtable* vtable; |
||||
}; |
||||
|
||||
/**
|
||||
* This method gets the number of overhead bytes needed for sealing data that |
||||
* is the difference in size between the protected and raw data. The counter |
||||
* value used in a seal or unseal operation is locally maintained (not sent or |
||||
* received from the other peer) and therefore, will not be counted as part of |
||||
* overhead bytes. |
||||
* |
||||
* - crypter: an alts_crypter instance. |
||||
* |
||||
* On success, the method returns the number of overhead bytes. Otherwise, it |
||||
* returns zero. |
||||
* |
||||
*/ |
||||
size_t alts_crypter_num_overhead_bytes(const alts_crypter* crypter); |
||||
|
||||
/**
|
||||
* This method performs either a seal or an unseal operation depending on the |
||||
* alts_crypter instance - crypter passed to the method. If the crypter is |
||||
* an instance implementing a seal operation, the method will perform a seal |
||||
* operation. That is, it seals raw data and stores the result in-place, and the |
||||
* memory allocated for data must be at least data_length + |
||||
* alts_crypter_num_overhead_bytes(). If the crypter is an instance |
||||
* implementing an unseal operation, the method will perform an unseal |
||||
* operation. That is, it unseals protected data and stores the result in-place. |
||||
* The size of unsealed data will be data_length - |
||||
* alts_crypter_num_overhead_bytes(). Integrity tag will be verified during |
||||
* the unseal operation, and if verification fails, the data will be wiped. |
||||
* The counters used in both seal and unseal operations are managed internally. |
||||
* |
||||
* - crypter: an alts_crypter instance. |
||||
* - data: if the method performs a seal operation, the data represents raw data |
||||
* that needs to be sealed. It also plays the role of buffer to hold the |
||||
* protected data as a result of seal. If the method performs an unseal |
||||
* operation, the data represents protected data that needs to be unsealed. It |
||||
* also plays the role of buffer to hold raw data as a result of unseal. |
||||
* - data_allocated_size: the size of data buffer. The parameter is used to |
||||
* check whether the result of either seal or unseal can be safely written to |
||||
* the data buffer. |
||||
* - data_size: if the method performs a seal operation, data_size |
||||
* represents the size of raw data that needs to be sealed, and if the method |
||||
* performs an unseal operation, data_size represents the size of protected |
||||
* data that needs to be unsealed. |
||||
* - output_size: size of data written to the data buffer after a seal or an |
||||
* unseal operation. |
||||
* - error_details: a buffer containing an error message if the method does not |
||||
* function correctly. It is legal to pass nullptr into error_details and |
||||
* otherwise, the parameter should be freed with gpr_free. |
||||
* |
||||
* On success, the method returns GRPC_STATUS_OK. Otherwise, |
||||
* it returns an error status code along with its details specified in |
||||
* error_details (if error_details is not nullptr). |
||||
*/ |
||||
grpc_status_code alts_crypter_process_in_place( |
||||
alts_crypter* crypter, unsigned char* data, size_t data_allocated_size, |
||||
size_t data_size, size_t* output_size, char** error_details); |
||||
|
||||
/**
|
||||
* This method creates an alts_crypter instance to be used to perform a seal |
||||
* operation, given a gsec_aead_crypter instance and a flag indicating if the |
||||
* created instance will be used at the client or server side. It takes |
||||
* ownership of gsec_aead_crypter instance. |
||||
* |
||||
* - gc: a gsec_aead_crypter instance used to perform AEAD encryption. |
||||
* - is_client: a flag indicating if the alts_crypter instance will be |
||||
* used at the client (is_client = true) or server (is_client = |
||||
* false) side. |
||||
* - overflow_size: overflow size of counter in bytes. |
||||
* - crypter: an alts_crypter instance to be returned from the method. |
||||
* - error_details: a buffer containing an error message if the method does |
||||
* not function correctly. It is legal to pass nullptr into error_details, and |
||||
* otherwise, the parameter should be freed with gpr_free. |
||||
* |
||||
* On success of creation, the method returns GRPC_STATUS_OK. |
||||
* Otherwise, it returns an error status code along with its details specified |
||||
* in error_details (if error_details is not nullptr). |
||||
*/ |
||||
grpc_status_code alts_seal_crypter_create(gsec_aead_crypter* gc, bool is_client, |
||||
size_t overflow_size, |
||||
alts_crypter** crypter, |
||||
char** error_details); |
||||
|
||||
/**
|
||||
* This method creates an alts_crypter instance used to perform an unseal |
||||
* operation, given a gsec_aead_crypter instance and a flag indicating if the |
||||
* created instance will be used at the client or server side. It takes |
||||
* ownership of gsec_aead_crypter instance. |
||||
* |
||||
* - gc: a gsec_aead_crypter instance used to perform AEAD decryption. |
||||
* - is_client: a flag indicating if the alts_crypter instance will be |
||||
* used at the client (is_client = true) or server (is_client = |
||||
* false) side. |
||||
* - overflow_size: overflow size of counter in bytes. |
||||
* - crypter: an alts_crypter instance to be returned from the method. |
||||
* - error_details: a buffer containing an error message if the method does |
||||
* not function correctly. It is legal to pass nullptr into error_details, and |
||||
* otherwise, the parameter should be freed with gpr_free. |
||||
* |
||||
* On success of creation, the method returns GRPC_STATUS_OK. |
||||
* Otherwise, it returns an error status code along with its details specified |
||||
* in error_details (if error_details is not nullptr). |
||||
*/ |
||||
grpc_status_code alts_unseal_crypter_create(gsec_aead_crypter* gc, |
||||
bool is_client, |
||||
size_t overflow_size, |
||||
alts_crypter** crypter, |
||||
char** error_details); |
||||
|
||||
/**
|
||||
* This method destroys an alts_crypter instance by de-allocating all of its |
||||
* occupied memory. A gsec_aead_crypter instance passed in at alts_crypter |
||||
* instance creation time will be destroyed in this method. |
||||
* |
||||
* - crypter: an alts_crypter instance. |
||||
*/ |
||||
void alts_crypter_destroy(alts_crypter* crypter); |
||||
|
||||
#endif /* GRPC_CORE_TSI_ALTS_FRAME_PROTECTOR_ALTS_CRYPTER_H */ |
@ -0,0 +1,407 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2018 gRPC authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
* |
||||
*/ |
||||
|
||||
#include <grpc/support/port_platform.h> |
||||
|
||||
#include "src/core/tsi/alts/frame_protector/alts_frame_protector.h" |
||||
|
||||
#include <stdio.h> |
||||
#include <stdlib.h> |
||||
|
||||
#include <grpc/support/alloc.h> |
||||
#include <grpc/support/log.h> |
||||
|
||||
#include "src/core/lib/gpr/useful.h" |
||||
#include "src/core/tsi/alts/crypt/gsec.h" |
||||
#include "src/core/tsi/alts/frame_protector/alts_crypter.h" |
||||
#include "src/core/tsi/alts/frame_protector/frame_handler.h" |
||||
#include "src/core/tsi/transport_security.h" |
||||
|
||||
constexpr size_t kMinFrameLength = 1024; |
||||
constexpr size_t kDefaultFrameLength = 16 * 1024; |
||||
constexpr size_t kMaxFrameLength = 1024 * 1024; |
||||
|
||||
// Limit k on number of frames such that at most 2^(8 * k) frames can be sent.
|
||||
constexpr size_t kAltsRecordProtocolRekeyFrameLimit = 8; |
||||
constexpr size_t kAltsRecordProtocolFrameLimit = 5; |
||||
|
||||
/* Main struct for alts_frame_protector. */ |
||||
struct alts_frame_protector { |
||||
tsi_frame_protector base; |
||||
alts_crypter* seal_crypter; |
||||
alts_crypter* unseal_crypter; |
||||
alts_frame_writer* writer; |
||||
alts_frame_reader* reader; |
||||
unsigned char* in_place_protect_buffer; |
||||
unsigned char* in_place_unprotect_buffer; |
||||
size_t in_place_protect_bytes_buffered; |
||||
size_t in_place_unprotect_bytes_processed; |
||||
size_t max_protected_frame_size; |
||||
size_t max_unprotected_frame_size; |
||||
size_t overhead_length; |
||||
size_t counter_overflow; |
||||
}; |
||||
|
||||
static tsi_result seal(alts_frame_protector* impl) { |
||||
char* error_details = nullptr; |
||||
size_t output_size = 0; |
||||
grpc_status_code status = alts_crypter_process_in_place( |
||||
impl->seal_crypter, impl->in_place_protect_buffer, |
||||
impl->max_protected_frame_size, impl->in_place_protect_bytes_buffered, |
||||
&output_size, &error_details); |
||||
impl->in_place_protect_bytes_buffered = output_size; |
||||
if (status != GRPC_STATUS_OK) { |
||||
gpr_log(GPR_ERROR, "%s", error_details); |
||||
gpr_free(error_details); |
||||
return TSI_INTERNAL_ERROR; |
||||
} |
||||
return TSI_OK; |
||||
} |
||||
|
||||
static size_t max_encrypted_payload_bytes(alts_frame_protector* impl) { |
||||
return impl->max_protected_frame_size - kFrameHeaderSize; |
||||
} |
||||
|
||||
static tsi_result alts_protect_flush(tsi_frame_protector* self, |
||||
unsigned char* protected_output_frames, |
||||
size_t* protected_output_frames_size, |
||||
size_t* still_pending_size) { |
||||
if (self == nullptr || protected_output_frames == nullptr || |
||||
protected_output_frames_size == nullptr || |
||||
still_pending_size == nullptr) { |
||||
gpr_log(GPR_ERROR, "Invalid nullptr arguments to alts_protect_flush()."); |
||||
return TSI_INVALID_ARGUMENT; |
||||
} |
||||
alts_frame_protector* impl = reinterpret_cast<alts_frame_protector*>(self); |
||||
/**
|
||||
* If there's nothing to flush (i.e., in_place_protect_buffer is empty), |
||||
* we're done. |
||||
*/ |
||||
if (impl->in_place_protect_bytes_buffered == 0) { |
||||
*protected_output_frames_size = 0; |
||||
*still_pending_size = 0; |
||||
return TSI_OK; |
||||
} |
||||
/**
|
||||
* If a new frame can start being processed, we encrypt the payload and reset |
||||
* the frame writer to point to in_place_protect_buffer that holds the newly |
||||
* sealed frame. |
||||
*/ |
||||
if (alts_is_frame_writer_done(impl->writer)) { |
||||
tsi_result result = seal(impl); |
||||
if (result != TSI_OK) { |
||||
return result; |
||||
} |
||||
if (!alts_reset_frame_writer(impl->writer, impl->in_place_protect_buffer, |
||||
impl->in_place_protect_bytes_buffered)) { |
||||
gpr_log(GPR_ERROR, "Couldn't reset frame writer."); |
||||
return TSI_INTERNAL_ERROR; |
||||
} |
||||
} |
||||
/**
|
||||
* Write the sealed frame as much as possible to protected_output_frames. It's |
||||
* possible a frame will not be written out completely by a single flush |
||||
* (i.e., still_pending_size != 0), in which case the flush should be called |
||||
* iteratively until a complete frame has been written out. |
||||
*/ |
||||
size_t written_frame_bytes = *protected_output_frames_size; |
||||
if (!alts_write_frame_bytes(impl->writer, protected_output_frames, |
||||
&written_frame_bytes)) { |
||||
gpr_log(GPR_ERROR, "Couldn't write frame bytes."); |
||||
return TSI_INTERNAL_ERROR; |
||||
} |
||||
*protected_output_frames_size = written_frame_bytes; |
||||
*still_pending_size = alts_get_num_writer_bytes_remaining(impl->writer); |
||||
/**
|
||||
* If the current frame has been finished processing (i.e., sealed and written |
||||
* out completely), we empty in_place_protect_buffer. |
||||
*/ |
||||
if (alts_is_frame_writer_done(impl->writer)) { |
||||
impl->in_place_protect_bytes_buffered = 0; |
||||
} |
||||
return TSI_OK; |
||||
} |
||||
|
||||
static tsi_result alts_protect(tsi_frame_protector* self, |
||||
const unsigned char* unprotected_bytes, |
||||
size_t* unprotected_bytes_size, |
||||
unsigned char* protected_output_frames, |
||||
size_t* protected_output_frames_size) { |
||||
if (self == nullptr || unprotected_bytes == nullptr || |
||||
unprotected_bytes_size == nullptr || protected_output_frames == nullptr || |
||||
protected_output_frames_size == nullptr) { |
||||
gpr_log(GPR_ERROR, "Invalid nullptr arguments to alts_protect()."); |
||||
return TSI_INVALID_ARGUMENT; |
||||
} |
||||
alts_frame_protector* impl = reinterpret_cast<alts_frame_protector*>(self); |
||||
|
||||
/**
|
||||
* If more payload can be buffered, we buffer it as much as possible to |
||||
* in_place_protect_buffer. |
||||
*/ |
||||
if (impl->in_place_protect_bytes_buffered + impl->overhead_length < |
||||
max_encrypted_payload_bytes(impl)) { |
||||
size_t bytes_to_buffer = GPR_MIN(*unprotected_bytes_size, |
||||
max_encrypted_payload_bytes(impl) - |
||||
impl->in_place_protect_bytes_buffered - |
||||
impl->overhead_length); |
||||
*unprotected_bytes_size = bytes_to_buffer; |
||||
if (bytes_to_buffer > 0) { |
||||
memcpy( |
||||
impl->in_place_protect_buffer + impl->in_place_protect_bytes_buffered, |
||||
unprotected_bytes, bytes_to_buffer); |
||||
impl->in_place_protect_bytes_buffered += bytes_to_buffer; |
||||
} |
||||
} else { |
||||
*unprotected_bytes_size = 0; |
||||
} |
||||
/**
|
||||
* If a full frame has been buffered, we output it. If the first condition |
||||
* holds, then there exists an unencrypted full frame. If the second |
||||
* condition holds, then there exists a full frame that has already been |
||||
* encrypted. |
||||
*/ |
||||
if (max_encrypted_payload_bytes(impl) == |
||||
impl->in_place_protect_bytes_buffered + impl->overhead_length || |
||||
max_encrypted_payload_bytes(impl) == |
||||
impl->in_place_protect_bytes_buffered) { |
||||
size_t still_pending_size = 0; |
||||
return alts_protect_flush(self, protected_output_frames, |
||||
protected_output_frames_size, |
||||
&still_pending_size); |
||||
} else { |
||||
*protected_output_frames_size = 0; |
||||
return TSI_OK; |
||||
} |
||||
} |
||||
|
||||
static tsi_result unseal(alts_frame_protector* impl) { |
||||
char* error_details = nullptr; |
||||
size_t output_size = 0; |
||||
grpc_status_code status = alts_crypter_process_in_place( |
||||
impl->unseal_crypter, impl->in_place_unprotect_buffer, |
||||
impl->max_unprotected_frame_size, |
||||
alts_get_output_bytes_read(impl->reader), &output_size, &error_details); |
||||
if (status != GRPC_STATUS_OK) { |
||||
gpr_log(GPR_ERROR, "%s", error_details); |
||||
gpr_free(error_details); |
||||
return TSI_DATA_CORRUPTED; |
||||
} |
||||
return TSI_OK; |
||||
} |
||||
|
||||
static void ensure_buffer_size(alts_frame_protector* impl) { |
||||
if (!alts_has_read_frame_length(impl->reader)) { |
||||
return; |
||||
} |
||||
size_t buffer_space_remaining = impl->max_unprotected_frame_size - |
||||
alts_get_output_bytes_read(impl->reader); |
||||
/**
|
||||
* Check if we need to resize in_place_unprotect_buffer in order to hold |
||||
* remaining bytes of a full frame. |
||||
*/ |
||||
if (buffer_space_remaining < alts_get_reader_bytes_remaining(impl->reader)) { |
||||
size_t buffer_len = alts_get_output_bytes_read(impl->reader) + |
||||
alts_get_reader_bytes_remaining(impl->reader); |
||||
unsigned char* buffer = static_cast<unsigned char*>(gpr_malloc(buffer_len)); |
||||
memcpy(buffer, impl->in_place_unprotect_buffer, |
||||
alts_get_output_bytes_read(impl->reader)); |
||||
impl->max_unprotected_frame_size = buffer_len; |
||||
gpr_free(impl->in_place_unprotect_buffer); |
||||
impl->in_place_unprotect_buffer = buffer; |
||||
alts_reset_reader_output_buffer( |
||||
impl->reader, buffer + alts_get_output_bytes_read(impl->reader)); |
||||
} |
||||
} |
||||
|
||||
static tsi_result alts_unprotect(tsi_frame_protector* self, |
||||
const unsigned char* protected_frames_bytes, |
||||
size_t* protected_frames_bytes_size, |
||||
unsigned char* unprotected_bytes, |
||||
size_t* unprotected_bytes_size) { |
||||
if (self == nullptr || protected_frames_bytes == nullptr || |
||||
protected_frames_bytes_size == nullptr || unprotected_bytes == nullptr || |
||||
unprotected_bytes_size == nullptr) { |
||||
gpr_log(GPR_ERROR, "Invalid nullptr arguments to alts_unprotect()."); |
||||
return TSI_INVALID_ARGUMENT; |
||||
} |
||||
alts_frame_protector* impl = reinterpret_cast<alts_frame_protector*>(self); |
||||
/**
|
||||
* If a new frame can start being processed, we reset the frame reader to |
||||
* point to in_place_unprotect_buffer that will be used to hold deframed |
||||
* result. |
||||
*/ |
||||
if (alts_is_frame_reader_done(impl->reader) && |
||||
((alts_get_output_buffer(impl->reader) == nullptr) || |
||||
(alts_get_output_bytes_read(impl->reader) == |
||||
impl->in_place_unprotect_bytes_processed + impl->overhead_length))) { |
||||
if (!alts_reset_frame_reader(impl->reader, |
||||
impl->in_place_unprotect_buffer)) { |
||||
gpr_log(GPR_ERROR, "Couldn't reset frame reader."); |
||||
return TSI_INTERNAL_ERROR; |
||||
} |
||||
impl->in_place_unprotect_bytes_processed = 0; |
||||
} |
||||
/**
|
||||
* If a full frame has not yet been read, we read more bytes from |
||||
* protected_frames_bytes until a full frame has been read. We also need to |
||||
* make sure in_place_unprotect_buffer is large enough to hold a complete |
||||
* frame. |
||||
*/ |
||||
if (!alts_is_frame_reader_done(impl->reader)) { |
||||
ensure_buffer_size(impl); |
||||
*protected_frames_bytes_size = |
||||
GPR_MIN(impl->max_unprotected_frame_size - |
||||
alts_get_output_bytes_read(impl->reader), |
||||
*protected_frames_bytes_size); |
||||
size_t read_frames_bytes_size = *protected_frames_bytes_size; |
||||
if (!alts_read_frame_bytes(impl->reader, protected_frames_bytes, |
||||
&read_frames_bytes_size)) { |
||||
gpr_log(GPR_ERROR, "Failed to process frame."); |
||||
return TSI_INTERNAL_ERROR; |
||||
} |
||||
*protected_frames_bytes_size = read_frames_bytes_size; |
||||
} else { |
||||
*protected_frames_bytes_size = 0; |
||||
} |
||||
/**
|
||||
* If a full frame has been read, we unseal it, and write out the |
||||
* deframed result to unprotected_bytes. |
||||
*/ |
||||
if (alts_is_frame_reader_done(impl->reader)) { |
||||
if (impl->in_place_unprotect_bytes_processed == 0) { |
||||
tsi_result result = unseal(impl); |
||||
if (result != TSI_OK) { |
||||
return result; |
||||
} |
||||
} |
||||
size_t bytes_to_write = GPR_MIN( |
||||
*unprotected_bytes_size, alts_get_output_bytes_read(impl->reader) - |
||||
impl->in_place_unprotect_bytes_processed - |
||||
impl->overhead_length); |
||||
if (bytes_to_write > 0) { |
||||
memcpy(unprotected_bytes, |
||||
impl->in_place_unprotect_buffer + |
||||
impl->in_place_unprotect_bytes_processed, |
||||
bytes_to_write); |
||||
} |
||||
*unprotected_bytes_size = bytes_to_write; |
||||
impl->in_place_unprotect_bytes_processed += bytes_to_write; |
||||
return TSI_OK; |
||||
} else { |
||||
*unprotected_bytes_size = 0; |
||||
return TSI_OK; |
||||
} |
||||
} |
||||
|
||||
static void alts_destroy(tsi_frame_protector* self) { |
||||
alts_frame_protector* impl = reinterpret_cast<alts_frame_protector*>(self); |
||||
if (impl != nullptr) { |
||||
alts_crypter_destroy(impl->seal_crypter); |
||||
alts_crypter_destroy(impl->unseal_crypter); |
||||
gpr_free(impl->in_place_protect_buffer); |
||||
gpr_free(impl->in_place_unprotect_buffer); |
||||
alts_destroy_frame_writer(impl->writer); |
||||
alts_destroy_frame_reader(impl->reader); |
||||
gpr_free(impl); |
||||
} |
||||
} |
||||
|
||||
static const tsi_frame_protector_vtable alts_frame_protector_vtable = { |
||||
alts_protect, alts_protect_flush, alts_unprotect, alts_destroy}; |
||||
|
||||
static grpc_status_code create_alts_crypters(const uint8_t* key, |
||||
size_t key_size, bool is_client, |
||||
bool is_rekey, |
||||
alts_frame_protector* impl, |
||||
char** error_details) { |
||||
grpc_status_code status; |
||||
gsec_aead_crypter* aead_crypter_seal = nullptr; |
||||
gsec_aead_crypter* aead_crypter_unseal = nullptr; |
||||
status = gsec_aes_gcm_aead_crypter_create(key, key_size, kAesGcmNonceLength, |
||||
kAesGcmTagLength, is_rekey, |
||||
&aead_crypter_seal, error_details); |
||||
if (status != GRPC_STATUS_OK) { |
||||
return status; |
||||
} |
||||
status = gsec_aes_gcm_aead_crypter_create( |
||||
key, key_size, kAesGcmNonceLength, kAesGcmTagLength, is_rekey, |
||||
&aead_crypter_unseal, error_details); |
||||
if (status != GRPC_STATUS_OK) { |
||||
return status; |
||||
} |
||||
size_t overflow_size = is_rekey ? kAltsRecordProtocolRekeyFrameLimit |
||||
: kAltsRecordProtocolFrameLimit; |
||||
status = alts_seal_crypter_create(aead_crypter_seal, is_client, overflow_size, |
||||
&impl->seal_crypter, error_details); |
||||
if (status != GRPC_STATUS_OK) { |
||||
return status; |
||||
} |
||||
status = |
||||
alts_unseal_crypter_create(aead_crypter_unseal, is_client, overflow_size, |
||||
&impl->unseal_crypter, error_details); |
||||
return status; |
||||
} |
||||
|
||||
tsi_result alts_create_frame_protector(const uint8_t* key, size_t key_size, |
||||
bool is_client, bool is_rekey, |
||||
size_t* max_protected_frame_size, |
||||
tsi_frame_protector** self) { |
||||
if (key == nullptr || self == nullptr) { |
||||
gpr_log(GPR_ERROR, |
||||
"Invalid nullptr arguments to alts_create_frame_protector()."); |
||||
return TSI_INTERNAL_ERROR; |
||||
} |
||||
char* error_details = nullptr; |
||||
alts_frame_protector* impl = |
||||
static_cast<alts_frame_protector*>(gpr_zalloc(sizeof(*impl))); |
||||
grpc_status_code status = create_alts_crypters( |
||||
key, key_size, is_client, is_rekey, impl, &error_details); |
||||
if (status != GRPC_STATUS_OK) { |
||||
gpr_log(GPR_ERROR, "Failed to create ALTS crypters, %s.", error_details); |
||||
gpr_free(error_details); |
||||
return TSI_INTERNAL_ERROR; |
||||
} |
||||
/**
|
||||
* Set maximum frame size to be used by a frame protector. If it is nullptr, a |
||||
* default frame size will be used. Otherwise, the provided frame size will be |
||||
* adjusted (if not falling into a valid frame range) and used. |
||||
*/ |
||||
size_t max_protected_frame_size_to_set = kDefaultFrameLength; |
||||
if (max_protected_frame_size != nullptr) { |
||||
*max_protected_frame_size = |
||||
GPR_MIN(*max_protected_frame_size, kMaxFrameLength); |
||||
*max_protected_frame_size = |
||||
GPR_MAX(*max_protected_frame_size, kMinFrameLength); |
||||
max_protected_frame_size_to_set = *max_protected_frame_size; |
||||
} |
||||
impl->max_protected_frame_size = max_protected_frame_size_to_set; |
||||
impl->max_unprotected_frame_size = max_protected_frame_size_to_set; |
||||
impl->in_place_protect_bytes_buffered = 0; |
||||
impl->in_place_unprotect_bytes_processed = 0; |
||||
impl->in_place_protect_buffer = static_cast<unsigned char*>( |
||||
gpr_malloc(sizeof(unsigned char) * max_protected_frame_size_to_set)); |
||||
impl->in_place_unprotect_buffer = static_cast<unsigned char*>( |
||||
gpr_malloc(sizeof(unsigned char) * max_protected_frame_size_to_set)); |
||||
impl->overhead_length = alts_crypter_num_overhead_bytes(impl->seal_crypter); |
||||
impl->writer = alts_create_frame_writer(); |
||||
impl->reader = alts_create_frame_reader(); |
||||
impl->base.vtable = &alts_frame_protector_vtable; |
||||
*self = &impl->base; |
||||
return TSI_OK; |
||||
} |
@ -0,0 +1,55 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2018 gRPC authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
* |
||||
*/ |
||||
|
||||
#ifndef GRPC_CORE_TSI_ALTS_FRAME_PROTECTOR_ALTS_FRAME_PROTECTOR_H |
||||
#define GRPC_CORE_TSI_ALTS_FRAME_PROTECTOR_ALTS_FRAME_PROTECTOR_H |
||||
|
||||
#include <grpc/support/port_platform.h> |
||||
|
||||
#include <stdbool.h> |
||||
|
||||
#include "src/core/tsi/transport_security_interface.h" |
||||
|
||||
typedef struct alts_frame_protector alts_frame_protector; |
||||
|
||||
/**
|
||||
* TODO: Add a parameter to the interface to support the use of |
||||
* different record protocols within a frame protector. |
||||
* |
||||
* This method creates a frame protector. |
||||
* |
||||
* - key: a symmetric key used to seal/unseal frames. |
||||
* - key_size: the size of symmetric key. |
||||
* - is_client: a flag indicating if the frame protector will be used at client |
||||
* (is_client = true) or server (is_client = false) side. |
||||
* - is_rekey: a flag indicating if the frame protector will use an AEAD with |
||||
* rekeying. |
||||
* - max_protected_frame_size: an in/out parameter indicating max frame size |
||||
* to be used by the frame protector. If it is nullptr, the default frame |
||||
* size will be used. Otherwise, the provided frame size will be adjusted (if |
||||
* not falling into a valid frame range) and used. |
||||
* - self: a pointer to the frame protector returned from the method. |
||||
* |
||||
* This method returns TSI_OK on success and TSI_INTERNAL_ERROR otherwise. |
||||
*/ |
||||
tsi_result alts_create_frame_protector(const uint8_t* key, size_t key_size, |
||||
bool is_client, bool is_rekey, |
||||
size_t* max_protected_frame_size, |
||||
tsi_frame_protector** self); |
||||
|
||||
#endif /* GRPC_CORE_TSI_ALTS_FRAME_PROTECTOR_ALTS_FRAME_PROTECTOR_H */ |
@ -0,0 +1,114 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2018 gRPC authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
* |
||||
*/ |
||||
|
||||
#include <grpc/support/port_platform.h> |
||||
|
||||
#include "src/core/tsi/alts/frame_protector/alts_record_protocol_crypter_common.h" |
||||
|
||||
#include <grpc/support/alloc.h> |
||||
|
||||
static void maybe_copy_error_msg(const char* src, char** dst) { |
||||
if (dst != nullptr && src != nullptr) { |
||||
*dst = static_cast<char*>(gpr_malloc(strlen(src) + 1)); |
||||
memcpy(*dst, src, strlen(src) + 1); |
||||
} |
||||
} |
||||
|
||||
grpc_status_code input_sanity_check( |
||||
const alts_record_protocol_crypter* rp_crypter, const unsigned char* data, |
||||
size_t* output_size, char** error_details) { |
||||
if (rp_crypter == nullptr) { |
||||
maybe_copy_error_msg("alts_crypter instance is nullptr.", error_details); |
||||
return GRPC_STATUS_INVALID_ARGUMENT; |
||||
} else if (data == nullptr) { |
||||
maybe_copy_error_msg("data is nullptr.", error_details); |
||||
return GRPC_STATUS_INVALID_ARGUMENT; |
||||
} else if (output_size == nullptr) { |
||||
maybe_copy_error_msg("output_size is nullptr.", error_details); |
||||
return GRPC_STATUS_INVALID_ARGUMENT; |
||||
} |
||||
return GRPC_STATUS_OK; |
||||
} |
||||
|
||||
grpc_status_code increment_counter(alts_record_protocol_crypter* rp_crypter, |
||||
char** error_details) { |
||||
bool is_overflow = false; |
||||
grpc_status_code status = |
||||
alts_counter_increment(rp_crypter->ctr, &is_overflow, error_details); |
||||
if (status != GRPC_STATUS_OK) { |
||||
return status; |
||||
} |
||||
if (is_overflow) { |
||||
const char error_msg[] = |
||||
"crypter counter is wrapped. The connection" |
||||
"should be closed and the key should be deleted."; |
||||
maybe_copy_error_msg(error_msg, error_details); |
||||
return GRPC_STATUS_INTERNAL; |
||||
} |
||||
return GRPC_STATUS_OK; |
||||
} |
||||
|
||||
size_t alts_record_protocol_crypter_num_overhead_bytes(const alts_crypter* c) { |
||||
if (c != nullptr) { |
||||
size_t num_overhead_bytes = 0; |
||||
char* error_details = nullptr; |
||||
const alts_record_protocol_crypter* rp_crypter = |
||||
reinterpret_cast<const alts_record_protocol_crypter*>(c); |
||||
grpc_status_code status = gsec_aead_crypter_tag_length( |
||||
rp_crypter->crypter, &num_overhead_bytes, &error_details); |
||||
if (status == GRPC_STATUS_OK) { |
||||
return num_overhead_bytes; |
||||
} |
||||
} |
||||
return 0; |
||||
} |
||||
|
||||
void alts_record_protocol_crypter_destruct(alts_crypter* c) { |
||||
if (c != nullptr) { |
||||
alts_record_protocol_crypter* rp_crypter = |
||||
reinterpret_cast<alts_record_protocol_crypter*>(c); |
||||
alts_counter_destroy(rp_crypter->ctr); |
||||
gsec_aead_crypter_destroy(rp_crypter->crypter); |
||||
} |
||||
} |
||||
|
||||
alts_record_protocol_crypter* alts_crypter_create_common( |
||||
gsec_aead_crypter* crypter, bool is_client, size_t overflow_size, |
||||
char** error_details) { |
||||
if (crypter != nullptr) { |
||||
auto* rp_crypter = static_cast<alts_record_protocol_crypter*>( |
||||
gpr_malloc(sizeof(alts_record_protocol_crypter))); |
||||
size_t counter_size = 0; |
||||
grpc_status_code status = |
||||
gsec_aead_crypter_nonce_length(crypter, &counter_size, error_details); |
||||
if (status != GRPC_STATUS_OK) { |
||||
return nullptr; |
||||
} |
||||
/* Create a counter. */ |
||||
status = alts_counter_create(is_client, counter_size, overflow_size, |
||||
&rp_crypter->ctr, error_details); |
||||
if (status != GRPC_STATUS_OK) { |
||||
return nullptr; |
||||
} |
||||
rp_crypter->crypter = crypter; |
||||
return rp_crypter; |
||||
} |
||||
const char error_msg[] = "crypter is nullptr."; |
||||
maybe_copy_error_msg(error_msg, error_details); |
||||
return nullptr; |
||||
} |
@ -0,0 +1,114 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2018 gRPC authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
* |
||||
*/ |
||||
|
||||
#ifndef GRPC_CORE_TSI_ALTS_FRAME_PROTECTOR_ALTS_RECORD_PROTOCOL_CRYPTER_COMMON_H |
||||
#define GRPC_CORE_TSI_ALTS_FRAME_PROTECTOR_ALTS_RECORD_PROTOCOL_CRYPTER_COMMON_H |
||||
|
||||
#include <grpc/support/port_platform.h> |
||||
|
||||
#include <grpc/grpc.h> |
||||
|
||||
#include "src/core/tsi/alts/frame_protector/alts_counter.h" |
||||
#include "src/core/tsi/alts/frame_protector/alts_crypter.h" |
||||
|
||||
/**
|
||||
* This file contains common implementation that will be used in both seal and |
||||
* unseal operations. |
||||
*/ |
||||
|
||||
/**
|
||||
* Main struct for alts_record_protocol_crypter that will be used in both |
||||
* seal and unseal operations. |
||||
*/ |
||||
typedef struct alts_record_protocol_crypter { |
||||
alts_crypter base; |
||||
gsec_aead_crypter* crypter; |
||||
alts_counter* ctr; |
||||
} alts_record_protocol_crypter; |
||||
|
||||
/**
|
||||
* This method performs input sanity checks on a subset of inputs to |
||||
* alts_crypter_process_in_place() for both seal and unseal operations. |
||||
* |
||||
* - rp_crypter: an alts_record_protocol_crypter instance. |
||||
* - data: it represents raw data that needs to be sealed in a seal operation or |
||||
* protected data that needs to be unsealed in an unseal operation. |
||||
* - output_size: size of data written to the data buffer after a seal or |
||||
* unseal operation. |
||||
* - error_details: a buffer containing an error message if any of checked |
||||
* inputs is nullptr. It is legal to pass nullptr into error_details and |
||||
* otherwise, the parameter should be freed with gpr_free. |
||||
* |
||||
* On success, the method returns GRPC_STATUS_OK. Otherwise, |
||||
* it returns an error status code along with its details specified in |
||||
* error_details (if error_details is not nullptr). |
||||
*/ |
||||
grpc_status_code input_sanity_check( |
||||
const alts_record_protocol_crypter* rp_crypter, const unsigned char* data, |
||||
size_t* output_size, char** error_details); |
||||
|
||||
/**
|
||||
* This method increments the counter within an alts_record_protocol_crypter |
||||
* instance. |
||||
* |
||||
* - rp_crypter: an alts_record_protocol_crypter instance. |
||||
* - error_details: a buffer containing an error message if the method does not |
||||
* function correctly or the counter is wrapped. It is legal to pass nullptr |
||||
* into error_details and otherwise, the parameter should be freed with |
||||
* gpr_free. |
||||
* |
||||
* On success, the method returns GRPC_STATUS_OK. Otherwise, |
||||
* it returns an error status code along with its details specified in |
||||
* error_details (if error_details is not nullptr). |
||||
*/ |
||||
grpc_status_code increment_counter(alts_record_protocol_crypter* rp_crypter, |
||||
char** error_details); |
||||
|
||||
/**
|
||||
* This method creates an alts_crypter instance, and populates the fields |
||||
* that are common to both seal and unseal operations. |
||||
* |
||||
* - crypter: a gsec_aead_crypter instance used to perform AEAD decryption. The |
||||
* function does not take ownership of crypter. |
||||
* - is_client: a flag indicating if the alts_crypter instance will be |
||||
* used at the client (is_client = true) or server (is_client = |
||||
* false) side. |
||||
* - overflow_size: overflow size of counter in bytes. |
||||
* - error_details: a buffer containing an error message if the method does |
||||
* not function correctly. It is legal to pass nullptr into error_details, and |
||||
* otherwise, the parameter should be freed with gpr_free. |
||||
* |
||||
* On success of creation, the method returns alts_record_protocol_crypter |
||||
* instance. Otherwise, it returns nullptr with its details specified in |
||||
* error_details (if error_details is not nullptr). |
||||
* |
||||
*/ |
||||
alts_record_protocol_crypter* alts_crypter_create_common( |
||||
gsec_aead_crypter* crypter, bool is_client, size_t overflow_size, |
||||
char** error_details); |
||||
|
||||
/**
|
||||
* For the following two methods, please refer to the corresponding API in |
||||
* alts_crypter.h for detailed specifications. |
||||
*/ |
||||
size_t alts_record_protocol_crypter_num_overhead_bytes(const alts_crypter* c); |
||||
|
||||
void alts_record_protocol_crypter_destruct(alts_crypter* c); |
||||
|
||||
#endif /* GRPC_CORE_TSI_ALTS_FRAME_PROTECTOR_ALTS_RECORD_PROTOCOL_CRYPTER_COMMON_H \ |
||||
*/ |
@ -0,0 +1,105 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2018 gRPC authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
* |
||||
*/ |
||||
|
||||
#include <grpc/support/port_platform.h> |
||||
|
||||
#include <grpc/support/alloc.h> |
||||
|
||||
#include "src/core/tsi/alts/frame_protector/alts_counter.h" |
||||
#include "src/core/tsi/alts/frame_protector/alts_crypter.h" |
||||
#include "src/core/tsi/alts/frame_protector/alts_record_protocol_crypter_common.h" |
||||
|
||||
static void maybe_copy_error_msg(const char* src, char** dst) { |
||||
if (dst != nullptr && src != nullptr) { |
||||
*dst = static_cast<char*>(gpr_malloc(strlen(src) + 1)); |
||||
memcpy(*dst, src, strlen(src) + 1); |
||||
} |
||||
} |
||||
|
||||
/* Perform input santity check for a seal operation. */ |
||||
static grpc_status_code seal_check(alts_crypter* c, const unsigned char* data, |
||||
size_t data_allocated_size, size_t data_size, |
||||
size_t* output_size, char** error_details) { |
||||
/* Do common input sanity check. */ |
||||
grpc_status_code status = input_sanity_check( |
||||
reinterpret_cast<const alts_record_protocol_crypter*>(c), data, |
||||
output_size, error_details); |
||||
if (status != GRPC_STATUS_OK) return status; |
||||
/* Do seal-specific check. */ |
||||
size_t num_overhead_bytes = |
||||
alts_crypter_num_overhead_bytes(reinterpret_cast<const alts_crypter*>(c)); |
||||
if (data_size == 0) { |
||||
const char error_msg[] = "data_size is zero."; |
||||
maybe_copy_error_msg(error_msg, error_details); |
||||
return GRPC_STATUS_INVALID_ARGUMENT; |
||||
} |
||||
if (data_size + num_overhead_bytes > data_allocated_size) { |
||||
const char error_msg[] = |
||||
"data_allocated_size is smaller than sum of data_size and " |
||||
"num_overhead_bytes."; |
||||
maybe_copy_error_msg(error_msg, error_details); |
||||
return GRPC_STATUS_INVALID_ARGUMENT; |
||||
} |
||||
return GRPC_STATUS_OK; |
||||
} |
||||
|
||||
static grpc_status_code alts_seal_crypter_process_in_place( |
||||
alts_crypter* c, unsigned char* data, size_t data_allocated_size, |
||||
size_t data_size, size_t* output_size, char** error_details) { |
||||
grpc_status_code status = seal_check(c, data, data_allocated_size, data_size, |
||||
output_size, error_details); |
||||
if (status != GRPC_STATUS_OK) { |
||||
return status; |
||||
} |
||||
/* Do AEAD encryption. */ |
||||
alts_record_protocol_crypter* rp_crypter = |
||||
reinterpret_cast<alts_record_protocol_crypter*>(c); |
||||
status = gsec_aead_crypter_encrypt( |
||||
rp_crypter->crypter, alts_counter_get_counter(rp_crypter->ctr), |
||||
alts_counter_get_size(rp_crypter->ctr), nullptr /* aad */, |
||||
0 /* aad_length */, data, data_size, data, data_allocated_size, |
||||
output_size, error_details); |
||||
if (status != GRPC_STATUS_OK) { |
||||
return status; |
||||
} |
||||
/* Increment the crypter counter. */ |
||||
return increment_counter(rp_crypter, error_details); |
||||
} |
||||
|
||||
static const alts_crypter_vtable vtable = { |
||||
alts_record_protocol_crypter_num_overhead_bytes, |
||||
alts_seal_crypter_process_in_place, alts_record_protocol_crypter_destruct}; |
||||
|
||||
grpc_status_code alts_seal_crypter_create(gsec_aead_crypter* gc, bool is_client, |
||||
size_t overflow_size, |
||||
alts_crypter** crypter, |
||||
char** error_details) { |
||||
if (crypter == nullptr) { |
||||
const char error_msg[] = "crypter is nullptr."; |
||||
maybe_copy_error_msg(error_msg, error_details); |
||||
return GRPC_STATUS_FAILED_PRECONDITION; |
||||
} |
||||
alts_record_protocol_crypter* rp_crypter = |
||||
alts_crypter_create_common(gc, !is_client, overflow_size, error_details); |
||||
if (rp_crypter == nullptr) { |
||||
return GRPC_STATUS_FAILED_PRECONDITION; |
||||
} |
||||
rp_crypter->base.vtable = &vtable; |
||||
*crypter = &rp_crypter->base; |
||||
return GRPC_STATUS_OK; |
||||
} |
@ -0,0 +1,103 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2018 gRPC authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
* |
||||
*/ |
||||
|
||||
#include <grpc/support/port_platform.h> |
||||
|
||||
#include <grpc/support/alloc.h> |
||||
|
||||
#include "src/core/tsi/alts/frame_protector/alts_counter.h" |
||||
#include "src/core/tsi/alts/frame_protector/alts_crypter.h" |
||||
#include "src/core/tsi/alts/frame_protector/alts_record_protocol_crypter_common.h" |
||||
|
||||
static void maybe_copy_error_msg(const char* src, char** dst) { |
||||
if (dst != nullptr && src != nullptr) { |
||||
*dst = static_cast<char*>(gpr_malloc(strlen(src) + 1)); |
||||
memcpy(*dst, src, strlen(src) + 1); |
||||
} |
||||
} |
||||
|
||||
/* Perform input santity check. */ |
||||
static grpc_status_code unseal_check(alts_crypter* c, const unsigned char* data, |
||||
size_t data_allocated_size, |
||||
size_t data_size, size_t* output_size, |
||||
char** error_details) { |
||||
/* Do common input sanity check. */ |
||||
grpc_status_code status = input_sanity_check( |
||||
reinterpret_cast<const alts_record_protocol_crypter*>(c), data, |
||||
output_size, error_details); |
||||
if (status != GRPC_STATUS_OK) { |
||||
return status; |
||||
} |
||||
/* Do unseal-specific input check. */ |
||||
size_t num_overhead_bytes = |
||||
alts_crypter_num_overhead_bytes(reinterpret_cast<const alts_crypter*>(c)); |
||||
if (num_overhead_bytes > data_size) { |
||||
const char error_msg[] = "data_size is smaller than num_overhead_bytes."; |
||||
maybe_copy_error_msg(error_msg, error_details); |
||||
return GRPC_STATUS_INVALID_ARGUMENT; |
||||
} |
||||
return GRPC_STATUS_OK; |
||||
} |
||||
|
||||
static grpc_status_code alts_unseal_crypter_process_in_place( |
||||
alts_crypter* c, unsigned char* data, size_t data_allocated_size, |
||||
size_t data_size, size_t* output_size, char** error_details) { |
||||
grpc_status_code status = unseal_check(c, data, data_allocated_size, |
||||
data_size, output_size, error_details); |
||||
if (status != GRPC_STATUS_OK) { |
||||
return status; |
||||
} |
||||
/* Do AEAD decryption. */ |
||||
alts_record_protocol_crypter* rp_crypter = |
||||
reinterpret_cast<alts_record_protocol_crypter*>(c); |
||||
status = gsec_aead_crypter_decrypt( |
||||
rp_crypter->crypter, alts_counter_get_counter(rp_crypter->ctr), |
||||
alts_counter_get_size(rp_crypter->ctr), nullptr /* aad */, |
||||
0 /* aad_length */, data, data_size, data, data_allocated_size, |
||||
output_size, error_details); |
||||
if (status != GRPC_STATUS_OK) { |
||||
return status; |
||||
} |
||||
/* Increment the crypter counter. */ |
||||
return increment_counter(rp_crypter, error_details); |
||||
} |
||||
|
||||
static const alts_crypter_vtable vtable = { |
||||
alts_record_protocol_crypter_num_overhead_bytes, |
||||
alts_unseal_crypter_process_in_place, |
||||
alts_record_protocol_crypter_destruct}; |
||||
|
||||
grpc_status_code alts_unseal_crypter_create(gsec_aead_crypter* gc, |
||||
bool is_client, |
||||
size_t overflow_size, |
||||
alts_crypter** crypter, |
||||
char** error_details) { |
||||
if (crypter == nullptr) { |
||||
const char error_msg[] = "crypter is nullptr."; |
||||
maybe_copy_error_msg(error_msg, error_details); |
||||
return GRPC_STATUS_FAILED_PRECONDITION; |
||||
} |
||||
alts_record_protocol_crypter* rp_crypter = |
||||
alts_crypter_create_common(gc, is_client, overflow_size, error_details); |
||||
if (rp_crypter == nullptr) { |
||||
return GRPC_STATUS_FAILED_PRECONDITION; |
||||
} |
||||
rp_crypter->base.vtable = &vtable; |
||||
*crypter = &rp_crypter->base; |
||||
return GRPC_STATUS_OK; |
||||
} |
@ -0,0 +1,218 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2018 gRPC authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
* |
||||
*/ |
||||
|
||||
#include <grpc/support/port_platform.h> |
||||
|
||||
#include "src/core/tsi/alts/frame_protector/frame_handler.h" |
||||
|
||||
#include <limits.h> |
||||
#include <stdint.h> |
||||
#include <string.h> |
||||
|
||||
#include <grpc/support/alloc.h> |
||||
#include <grpc/support/log.h> |
||||
|
||||
#include "src/core/lib/gpr/useful.h" |
||||
|
||||
/* Use little endian to interpret a string of bytes as uint32_t. */ |
||||
static uint32_t load_32_le(const unsigned char* buffer) { |
||||
return (((uint32_t)buffer[3]) << 24) | (((uint32_t)buffer[2]) << 16) | |
||||
(((uint32_t)buffer[1]) << 8) | ((uint32_t)buffer[0]); |
||||
} |
||||
|
||||
/* Store uint32_t as a string of little endian bytes. */ |
||||
static void store_32_le(uint32_t value, unsigned char* buffer) { |
||||
buffer[3] = (unsigned char)(value >> 24) & 0xFF; |
||||
buffer[2] = (unsigned char)(value >> 16) & 0xFF; |
||||
buffer[1] = (unsigned char)(value >> 8) & 0xFF; |
||||
buffer[0] = (unsigned char)(value)&0xFF; |
||||
} |
||||
|
||||
/* Frame writer implementation. */ |
||||
alts_frame_writer* alts_create_frame_writer() { |
||||
alts_frame_writer* writer = |
||||
static_cast<alts_frame_writer*>(gpr_zalloc(sizeof(*writer))); |
||||
return writer; |
||||
} |
||||
|
||||
bool alts_reset_frame_writer(alts_frame_writer* writer, |
||||
const unsigned char* buffer, size_t length) { |
||||
if (buffer == nullptr) return false; |
||||
size_t max_input_size = SIZE_MAX - kFrameLengthFieldSize; |
||||
if (length > max_input_size) { |
||||
gpr_log(GPR_ERROR, "length must be at most %zu", max_input_size); |
||||
return false; |
||||
} |
||||
writer->input_buffer = buffer; |
||||
writer->input_size = length; |
||||
writer->input_bytes_written = 0; |
||||
writer->header_bytes_written = 0; |
||||
store_32_le( |
||||
static_cast<uint32_t>(writer->input_size + kFrameMessageTypeFieldSize), |
||||
writer->header_buffer); |
||||
store_32_le(kFrameMessageType, writer->header_buffer + kFrameLengthFieldSize); |
||||
return true; |
||||
} |
||||
|
||||
bool alts_write_frame_bytes(alts_frame_writer* writer, unsigned char* output, |
||||
size_t* bytes_size) { |
||||
if (bytes_size == nullptr || output == nullptr) return false; |
||||
if (alts_is_frame_writer_done(writer)) { |
||||
*bytes_size = 0; |
||||
return true; |
||||
} |
||||
size_t bytes_written = 0; |
||||
/* Write some header bytes, if needed. */ |
||||
if (writer->header_bytes_written != sizeof(writer->header_buffer)) { |
||||
size_t bytes_to_write = |
||||
GPR_MIN(*bytes_size, |
||||
sizeof(writer->header_buffer) - writer->header_bytes_written); |
||||
memcpy(output, writer->header_buffer + writer->header_bytes_written, |
||||
bytes_to_write); |
||||
bytes_written += bytes_to_write; |
||||
*bytes_size -= bytes_to_write; |
||||
writer->header_bytes_written += bytes_to_write; |
||||
output += bytes_to_write; |
||||
if (writer->header_bytes_written != sizeof(writer->header_buffer)) { |
||||
*bytes_size = bytes_written; |
||||
return true; |
||||
} |
||||
} |
||||
/* Write some non-header bytes. */ |
||||
size_t bytes_to_write = |
||||
GPR_MIN(writer->input_size - writer->input_bytes_written, *bytes_size); |
||||
memcpy(output, writer->input_buffer, bytes_to_write); |
||||
writer->input_buffer += bytes_to_write; |
||||
bytes_written += bytes_to_write; |
||||
writer->input_bytes_written += bytes_to_write; |
||||
*bytes_size = bytes_written; |
||||
return true; |
||||
} |
||||
|
||||
bool alts_is_frame_writer_done(alts_frame_writer* writer) { |
||||
return writer->input_buffer == nullptr || |
||||
writer->input_size == writer->input_bytes_written; |
||||
} |
||||
|
||||
size_t alts_get_num_writer_bytes_remaining(alts_frame_writer* writer) { |
||||
return (sizeof(writer->header_buffer) - writer->header_bytes_written) + |
||||
(writer->input_size - writer->input_bytes_written); |
||||
} |
||||
|
||||
void alts_destroy_frame_writer(alts_frame_writer* writer) { gpr_free(writer); } |
||||
|
||||
/* Frame reader implementation. */ |
||||
alts_frame_reader* alts_create_frame_reader() { |
||||
alts_frame_reader* reader = |
||||
static_cast<alts_frame_reader*>(gpr_zalloc(sizeof(*reader))); |
||||
return reader; |
||||
} |
||||
|
||||
bool alts_is_frame_reader_done(alts_frame_reader* reader) { |
||||
return reader->output_buffer == nullptr || |
||||
(reader->header_bytes_read == sizeof(reader->header_buffer) && |
||||
reader->bytes_remaining == 0); |
||||
} |
||||
|
||||
bool alts_has_read_frame_length(alts_frame_reader* reader) { |
||||
return sizeof(reader->header_buffer) == reader->header_bytes_read; |
||||
} |
||||
|
||||
size_t alts_get_reader_bytes_remaining(alts_frame_reader* reader) { |
||||
return alts_has_read_frame_length(reader) ? reader->bytes_remaining : 0; |
||||
} |
||||
|
||||
void alts_reset_reader_output_buffer(alts_frame_reader* reader, |
||||
unsigned char* buffer) { |
||||
reader->output_buffer = buffer; |
||||
} |
||||
|
||||
bool alts_reset_frame_reader(alts_frame_reader* reader, unsigned char* buffer) { |
||||
if (buffer == nullptr) return false; |
||||
reader->output_buffer = buffer; |
||||
reader->bytes_remaining = 0; |
||||
reader->header_bytes_read = 0; |
||||
reader->output_bytes_read = 0; |
||||
return true; |
||||
} |
||||
|
||||
bool alts_read_frame_bytes(alts_frame_reader* reader, |
||||
const unsigned char* bytes, size_t* bytes_size) { |
||||
if (bytes_size == nullptr) return false; |
||||
if (bytes == nullptr) { |
||||
*bytes_size = 0; |
||||
return false; |
||||
} |
||||
if (alts_is_frame_reader_done(reader)) { |
||||
*bytes_size = 0; |
||||
return true; |
||||
} |
||||
size_t bytes_processed = 0; |
||||
/* Process the header, if needed. */ |
||||
if (reader->header_bytes_read != sizeof(reader->header_buffer)) { |
||||
size_t bytes_to_write = GPR_MIN( |
||||
*bytes_size, sizeof(reader->header_buffer) - reader->header_bytes_read); |
||||
memcpy(reader->header_buffer + reader->header_bytes_read, bytes, |
||||
bytes_to_write); |
||||
reader->header_bytes_read += bytes_to_write; |
||||
bytes_processed += bytes_to_write; |
||||
bytes += bytes_to_write; |
||||
*bytes_size -= bytes_to_write; |
||||
if (reader->header_bytes_read != sizeof(reader->header_buffer)) { |
||||
*bytes_size = bytes_processed; |
||||
return true; |
||||
} |
||||
size_t frame_length = load_32_le(reader->header_buffer); |
||||
if (frame_length < kFrameMessageTypeFieldSize || |
||||
frame_length > kFrameMaxSize) { |
||||
gpr_log(GPR_ERROR, |
||||
"Bad frame length (should be at least %zu, and at most %zu)", |
||||
kFrameMessageTypeFieldSize, kFrameMaxSize); |
||||
*bytes_size = 0; |
||||
return false; |
||||
} |
||||
size_t message_type = |
||||
load_32_le(reader->header_buffer + kFrameLengthFieldSize); |
||||
if (message_type != kFrameMessageType) { |
||||
gpr_log(GPR_ERROR, "Unsupported message type %zu (should be %zu)", |
||||
message_type, kFrameMessageType); |
||||
*bytes_size = 0; |
||||
return false; |
||||
} |
||||
reader->bytes_remaining = frame_length - kFrameMessageTypeFieldSize; |
||||
} |
||||
/* Process the non-header bytes. */ |
||||
size_t bytes_to_write = GPR_MIN(*bytes_size, reader->bytes_remaining); |
||||
memcpy(reader->output_buffer, bytes, bytes_to_write); |
||||
reader->output_buffer += bytes_to_write; |
||||
bytes_processed += bytes_to_write; |
||||
reader->bytes_remaining -= bytes_to_write; |
||||
reader->output_bytes_read += bytes_to_write; |
||||
*bytes_size = bytes_processed; |
||||
return true; |
||||
} |
||||
|
||||
size_t alts_get_output_bytes_read(alts_frame_reader* reader) { |
||||
return reader->output_bytes_read; |
||||
} |
||||
|
||||
unsigned char* alts_get_output_buffer(alts_frame_reader* reader) { |
||||
return reader->output_buffer; |
||||
} |
||||
|
||||
void alts_destroy_frame_reader(alts_frame_reader* reader) { gpr_free(reader); } |
@ -0,0 +1,236 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2018 gRPC authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
* |
||||
*/ |
||||
|
||||
#ifndef GRPC_CORE_TSI_ALTS_FRAME_PROTECTOR_FRAME_HANDLER_H |
||||
#define GRPC_CORE_TSI_ALTS_FRAME_PROTECTOR_FRAME_HANDLER_H |
||||
|
||||
#include <grpc/support/port_platform.h> |
||||
|
||||
#include <stdbool.h> |
||||
#include <stdlib.h> |
||||
|
||||
const size_t kFrameMessageType = 0x06; |
||||
const size_t kFrameLengthFieldSize = 4; |
||||
const size_t kFrameMessageTypeFieldSize = 4; |
||||
const size_t kFrameMaxSize = 1024 * 1024; |
||||
const size_t kFrameHeaderSize = |
||||
kFrameLengthFieldSize + kFrameMessageTypeFieldSize; |
||||
|
||||
/**
|
||||
* Implementation of frame reader and frame writer. All APIs in the |
||||
* header are thread-compatible. |
||||
*/ |
||||
|
||||
/**
|
||||
* Main struct for a frame writer. It reads frames from an input buffer, and |
||||
* writes the contents as raw bytes. It does not own the input buffer. |
||||
*/ |
||||
typedef struct alts_frame_writer { |
||||
const unsigned char* input_buffer; |
||||
unsigned char header_buffer[kFrameHeaderSize]; |
||||
size_t input_bytes_written; |
||||
size_t header_bytes_written; |
||||
size_t input_size; |
||||
} alts_frame_writer; |
||||
|
||||
/**
|
||||
* Main struct for a frame reader. It reads raw bytes and puts the framed |
||||
* result into an output buffer. It does not own the output buffer. |
||||
*/ |
||||
typedef struct alts_frame_reader { |
||||
unsigned char* output_buffer; |
||||
unsigned char header_buffer[kFrameHeaderSize]; |
||||
size_t header_bytes_read; |
||||
size_t output_bytes_read; |
||||
size_t bytes_remaining; |
||||
} alts_frame_reader; |
||||
|
||||
/**
|
||||
* This method creates a frame writer instance and initializes its internal |
||||
* states. |
||||
*/ |
||||
alts_frame_writer* alts_create_frame_writer(); |
||||
|
||||
/**
|
||||
* This method resets internal states of a frame writer and prepares to write |
||||
* a single frame. It does not take ownership of payload_buffer. |
||||
* The payload_buffer must outlive the writer. |
||||
* |
||||
* - writer: a frame writer instance. |
||||
* - buffer: a buffer storing full payload data to be framed. |
||||
* - length: size of payload data. |
||||
* |
||||
* The method returns true on success and false otherwise. |
||||
*/ |
||||
bool alts_reset_frame_writer(alts_frame_writer* writer, |
||||
const unsigned char* buffer, size_t length); |
||||
|
||||
/**
|
||||
* This method writes up to bytes_size bytes of a frame to output. |
||||
* |
||||
* - writer: a frame writer instance. |
||||
* - output: an output buffer used to store the frame. |
||||
* - bytes_size: an in/out parameter that stores the size of output buffer |
||||
* before the call, and gets written the number of frame bytes written to the |
||||
* buffer. |
||||
* |
||||
* The method returns true on success and false otherwise. |
||||
*/ |
||||
bool alts_write_frame_bytes(alts_frame_writer* writer, unsigned char* output, |
||||
size_t* bytes_size); |
||||
|
||||
/**
|
||||
* This method checks if a reset can be called to write a new frame. It returns |
||||
* true if it's the first time to frame a payload, or the current frame has |
||||
* been finished processing. It returns false if it's not ready yet to start a |
||||
* new frame (e.g., more payload data needs to be accumulated to process the |
||||
* current frame). |
||||
* |
||||
* if (alts_is_frame_writer_done(writer)) { |
||||
* // a new frame can be written, call reset.
|
||||
* alts_reset_frame_writer(writer, payload_buffer, payload_size); |
||||
* } else { |
||||
* // accumulate more payload data until a full frame can be written.
|
||||
* } |
||||
* |
||||
* - writer: a frame writer instance. |
||||
*/ |
||||
bool alts_is_frame_writer_done(alts_frame_writer* writer); |
||||
|
||||
/**
|
||||
* This method returns the number of bytes left to write before a complete frame |
||||
* is formed. |
||||
* |
||||
* - writer: a frame writer instance. |
||||
*/ |
||||
size_t alts_get_num_writer_bytes_remaining(alts_frame_writer* writer); |
||||
|
||||
/**
|
||||
* This method destroys a frame writer instance. |
||||
* |
||||
* - writer: a frame writer instance. |
||||
*/ |
||||
void alts_destroy_frame_writer(alts_frame_writer* writer); |
||||
|
||||
/**
|
||||
* This method creates a frame reader instance and initializes its internal |
||||
* states. |
||||
*/ |
||||
alts_frame_reader* alts_create_frame_reader(); |
||||
|
||||
/**
|
||||
* This method resets internal states of a frame reader (including setting its |
||||
* output_buffer with buffer), and prepares to write processed bytes to |
||||
* an output_buffer. It does not take ownership of buffer. The buffer must |
||||
* outlive reader. |
||||
* |
||||
* - reader: a frame reader instance. |
||||
* - buffer: an output buffer used to store deframed results. |
||||
* |
||||
* The method returns true on success and false otherwise. |
||||
*/ |
||||
bool alts_reset_frame_reader(alts_frame_reader* reader, unsigned char* buffer); |
||||
|
||||
/**
|
||||
* This method processes up to the number of bytes given in bytes_size. It may |
||||
* choose not to process all the bytes, if, for instance, more bytes are |
||||
* given to the method than required to complete the current frame. |
||||
* |
||||
* - reader: a frame reader instance. |
||||
* - bytes: a buffer that stores data to be processed. |
||||
* - bytes_size: an in/out parameter that stores the size of bytes before the |
||||
* call and gets written the number of bytes processed. |
||||
* |
||||
* The method returns true on success and false otherwise. |
||||
*/ |
||||
bool alts_read_frame_bytes(alts_frame_reader* reader, |
||||
const unsigned char* bytes, size_t* bytes_size); |
||||
|
||||
/**
|
||||
* This method checks if a frame length has been read. |
||||
* |
||||
* - reader: a frame reader instance. |
||||
* |
||||
* The method returns true if a frame length has been read and false otherwise. |
||||
*/ |
||||
bool alts_has_read_frame_length(alts_frame_reader* reader); |
||||
|
||||
/**
|
||||
* This method returns the number of bytes the frame reader intends to write. |
||||
* It may only be called if alts_has_read_frame_length() returns true. |
||||
* |
||||
* - reader: a frame reader instance. |
||||
*/ |
||||
size_t alts_get_reader_bytes_remaining(alts_frame_reader* reader); |
||||
|
||||
/**
|
||||
* This method resets output_buffer but does not otherwise modify other internal |
||||
* states of a frame reader instance. After being set, the new output_buffer |
||||
* will hold the deframed payload held by the original output_buffer. It does |
||||
* not take ownership of buffer. The buffer must outlive the reader. |
||||
* To distinguish between two reset methods on a frame reader, |
||||
* |
||||
* if (alts_fh_is_frame_reader_done(reader)) { |
||||
* // if buffer contains a full payload to be deframed, call reset.
|
||||
* alts_reset_frame_reader(reader, buffer); |
||||
* } |
||||
* |
||||
* // if remaining buffer space is not enough to hold a full payload
|
||||
* if (buffer_space_remaining < alts_get_reader_bytes_remaining(reader)) { |
||||
* // allocate enough space for a new buffer, copy back data processed so far,
|
||||
* // and call reset.
|
||||
* alts_reset_reader_output_buffer(reader, new_buffer). |
||||
* } |
||||
* |
||||
* - reader: a frame reader instance. |
||||
* - buffer: a buffer used to set reader's output_buffer. |
||||
*/ |
||||
void alts_reset_reader_output_buffer(alts_frame_reader* reader, |
||||
unsigned char* buffer); |
||||
|
||||
/**
|
||||
* This method checks if reset can be called to start processing a new frame. |
||||
* If true and reset was previously called, a full frame has been processed and |
||||
* the content of the frame is available in output_buffer. |
||||
|
||||
* - reader: a frame reader instance. |
||||
*/ |
||||
bool alts_is_frame_reader_done(alts_frame_reader* reader); |
||||
|
||||
/**
|
||||
* This method returns output_bytes_read of a frame reader instance. |
||||
* |
||||
* - reader: a frame reader instance. |
||||
*/ |
||||
size_t alts_get_output_bytes_read(alts_frame_reader* reader); |
||||
|
||||
/**
|
||||
* This method returns output_buffer of a frame reader instance. |
||||
* |
||||
* - reader: a frame reader instance. |
||||
*/ |
||||
unsigned char* alts_get_output_buffer(alts_frame_reader* reader); |
||||
|
||||
/**
|
||||
* This method destroys a frame reader instance. |
||||
* |
||||
* - reader: a frame reader instance. |
||||
*/ |
||||
void alts_destroy_frame_reader(alts_frame_reader* reader); |
||||
|
||||
#endif /* GRPC_CORE_TSI_ALTS_FRAME_PROTECTOR_FRAME_HANDLER_H */ |
@ -0,0 +1,316 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2018 gRPC authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
* |
||||
*/ |
||||
|
||||
#include <grpc/support/port_platform.h> |
||||
|
||||
#include "src/core/tsi/alts/handshaker/alts_handshaker_client.h" |
||||
|
||||
#include <grpc/byte_buffer.h> |
||||
#include <grpc/support/alloc.h> |
||||
#include <grpc/support/log.h> |
||||
|
||||
#include "src/core/tsi/alts/handshaker/alts_handshaker_service_api.h" |
||||
|
||||
const int kHandshakerClientOpNum = 4; |
||||
|
||||
typedef struct alts_grpc_handshaker_client { |
||||
alts_handshaker_client base; |
||||
grpc_call* call; |
||||
alts_grpc_caller grpc_caller; |
||||
} alts_grpc_handshaker_client; |
||||
|
||||
static grpc_call_error grpc_start_batch(grpc_call* call, const grpc_op* ops, |
||||
size_t nops, void* tag) { |
||||
return grpc_call_start_batch(call, ops, nops, tag, nullptr); |
||||
} |
||||
|
||||
/**
|
||||
* Populate grpc operation data with the fields of ALTS TSI event and make a |
||||
* grpc call. |
||||
*/ |
||||
static tsi_result make_grpc_call(alts_handshaker_client* client, |
||||
alts_tsi_event* event, bool is_start) { |
||||
GPR_ASSERT(client != nullptr && event != nullptr); |
||||
alts_grpc_handshaker_client* grpc_client = |
||||
reinterpret_cast<alts_grpc_handshaker_client*>(client); |
||||
grpc_op ops[kHandshakerClientOpNum]; |
||||
memset(ops, 0, sizeof(ops)); |
||||
grpc_op* op = ops; |
||||
if (is_start) { |
||||
op->op = GRPC_OP_SEND_INITIAL_METADATA; |
||||
op->data.send_initial_metadata.count = 0; |
||||
op++; |
||||
GPR_ASSERT(op - ops <= kHandshakerClientOpNum); |
||||
op->op = GRPC_OP_RECV_INITIAL_METADATA; |
||||
op->data.recv_initial_metadata.recv_initial_metadata = |
||||
&event->initial_metadata; |
||||
op++; |
||||
GPR_ASSERT(op - ops <= kHandshakerClientOpNum); |
||||
} |
||||
op->op = GRPC_OP_SEND_MESSAGE; |
||||
op->data.send_message.send_message = event->send_buffer; |
||||
op++; |
||||
GPR_ASSERT(op - ops <= kHandshakerClientOpNum); |
||||
op->op = GRPC_OP_RECV_MESSAGE; |
||||
op->data.recv_message.recv_message = &event->recv_buffer; |
||||
op++; |
||||
GPR_ASSERT(op - ops <= kHandshakerClientOpNum); |
||||
GPR_ASSERT(grpc_client->grpc_caller != nullptr); |
||||
if (grpc_client->grpc_caller(grpc_client->call, ops, |
||||
static_cast<size_t>(op - ops), |
||||
(void*)event) != GRPC_CALL_OK) { |
||||
gpr_log(GPR_ERROR, "Start batch operation failed"); |
||||
return TSI_INTERNAL_ERROR; |
||||
} |
||||
return TSI_OK; |
||||
} |
||||
|
||||
/* Create and populate a client_start handshaker request, then serialize it. */ |
||||
static grpc_byte_buffer* get_serialized_start_client(alts_tsi_event* event) { |
||||
bool ok = true; |
||||
grpc_gcp_handshaker_req* req = |
||||
grpc_gcp_handshaker_req_create(CLIENT_START_REQ); |
||||
ok &= grpc_gcp_handshaker_req_set_handshake_protocol( |
||||
req, grpc_gcp_HandshakeProtocol_ALTS); |
||||
ok &= grpc_gcp_handshaker_req_add_application_protocol( |
||||
req, ALTS_APPLICATION_PROTOCOL); |
||||
ok &= grpc_gcp_handshaker_req_add_record_protocol(req, ALTS_RECORD_PROTOCOL); |
||||
grpc_gcp_rpc_protocol_versions* versions = &event->options->rpc_versions; |
||||
ok &= grpc_gcp_handshaker_req_set_rpc_versions( |
||||
req, versions->max_rpc_version.major, versions->max_rpc_version.minor, |
||||
versions->min_rpc_version.major, versions->min_rpc_version.minor); |
||||
char* target_name = grpc_slice_to_c_string(event->target_name); |
||||
ok &= grpc_gcp_handshaker_req_set_target_name(req, target_name); |
||||
target_service_account* ptr = |
||||
(reinterpret_cast<grpc_alts_credentials_client_options*>(event->options)) |
||||
->target_account_list_head; |
||||
while (ptr != nullptr) { |
||||
grpc_gcp_handshaker_req_add_target_identity_service_account(req, ptr->data); |
||||
ptr = ptr->next; |
||||
} |
||||
grpc_slice slice; |
||||
ok &= grpc_gcp_handshaker_req_encode(req, &slice); |
||||
grpc_byte_buffer* buffer = nullptr; |
||||
if (ok) { |
||||
buffer = grpc_raw_byte_buffer_create(&slice, 1 /* number of slices */); |
||||
} |
||||
grpc_slice_unref(slice); |
||||
gpr_free(target_name); |
||||
grpc_gcp_handshaker_req_destroy(req); |
||||
return buffer; |
||||
} |
||||
|
||||
static tsi_result handshaker_client_start_client(alts_handshaker_client* client, |
||||
alts_tsi_event* event) { |
||||
if (client == nullptr || event == nullptr) { |
||||
gpr_log(GPR_ERROR, |
||||
"Invalid arguments to alts_grpc_handshaker_client_start_client()"); |
||||
return TSI_INVALID_ARGUMENT; |
||||
} |
||||
grpc_byte_buffer* buffer = get_serialized_start_client(event); |
||||
if (buffer == nullptr) { |
||||
gpr_log(GPR_ERROR, "get_serialized_start_client() failed"); |
||||
return TSI_INTERNAL_ERROR; |
||||
} |
||||
event->send_buffer = buffer; |
||||
tsi_result result = make_grpc_call(client, event, true /* is_start */); |
||||
if (result != TSI_OK) { |
||||
gpr_log(GPR_ERROR, "make_grpc_call() failed"); |
||||
} |
||||
return result; |
||||
} |
||||
|
||||
/* Create and populate a start_server handshaker request, then serialize it. */ |
||||
static grpc_byte_buffer* get_serialized_start_server( |
||||
alts_tsi_event* event, grpc_slice* bytes_received) { |
||||
GPR_ASSERT(bytes_received != nullptr); |
||||
grpc_gcp_handshaker_req* req = |
||||
grpc_gcp_handshaker_req_create(SERVER_START_REQ); |
||||
bool ok = grpc_gcp_handshaker_req_add_application_protocol( |
||||
req, ALTS_APPLICATION_PROTOCOL); |
||||
ok &= grpc_gcp_handshaker_req_param_add_record_protocol( |
||||
req, grpc_gcp_HandshakeProtocol_ALTS, ALTS_RECORD_PROTOCOL); |
||||
ok &= grpc_gcp_handshaker_req_set_in_bytes( |
||||
req, reinterpret_cast<const char*> GRPC_SLICE_START_PTR(*bytes_received), |
||||
GRPC_SLICE_LENGTH(*bytes_received)); |
||||
grpc_gcp_rpc_protocol_versions* versions = &event->options->rpc_versions; |
||||
ok &= grpc_gcp_handshaker_req_set_rpc_versions( |
||||
req, versions->max_rpc_version.major, versions->max_rpc_version.minor, |
||||
versions->min_rpc_version.major, versions->min_rpc_version.minor); |
||||
grpc_slice req_slice; |
||||
ok &= grpc_gcp_handshaker_req_encode(req, &req_slice); |
||||
grpc_byte_buffer* buffer = nullptr; |
||||
if (ok) { |
||||
buffer = grpc_raw_byte_buffer_create(&req_slice, 1 /* number of slices */); |
||||
} |
||||
grpc_slice_unref(req_slice); |
||||
grpc_gcp_handshaker_req_destroy(req); |
||||
return buffer; |
||||
} |
||||
|
||||
static tsi_result handshaker_client_start_server(alts_handshaker_client* client, |
||||
alts_tsi_event* event, |
||||
grpc_slice* bytes_received) { |
||||
if (client == nullptr || event == nullptr || bytes_received == nullptr) { |
||||
gpr_log(GPR_ERROR, |
||||
"Invalid arguments to alts_grpc_handshaker_client_start_server()"); |
||||
return TSI_INVALID_ARGUMENT; |
||||
} |
||||
grpc_byte_buffer* buffer = get_serialized_start_server(event, bytes_received); |
||||
if (buffer == nullptr) { |
||||
gpr_log(GPR_ERROR, "get_serialized_start_server() failed"); |
||||
return TSI_INTERNAL_ERROR; |
||||
} |
||||
event->send_buffer = buffer; |
||||
tsi_result result = make_grpc_call(client, event, true /* is_start */); |
||||
if (result != TSI_OK) { |
||||
gpr_log(GPR_ERROR, "make_grpc_call() failed"); |
||||
} |
||||
return result; |
||||
} |
||||
|
||||
/* Create and populate a next handshaker request, then serialize it. */ |
||||
static grpc_byte_buffer* get_serialized_next(grpc_slice* bytes_received) { |
||||
GPR_ASSERT(bytes_received != nullptr); |
||||
grpc_gcp_handshaker_req* req = grpc_gcp_handshaker_req_create(NEXT_REQ); |
||||
bool ok = grpc_gcp_handshaker_req_set_in_bytes( |
||||
req, reinterpret_cast<const char*> GRPC_SLICE_START_PTR(*bytes_received), |
||||
GRPC_SLICE_LENGTH(*bytes_received)); |
||||
grpc_slice req_slice; |
||||
ok &= grpc_gcp_handshaker_req_encode(req, &req_slice); |
||||
grpc_byte_buffer* buffer = nullptr; |
||||
if (ok) { |
||||
buffer = grpc_raw_byte_buffer_create(&req_slice, 1 /* number of slices */); |
||||
} |
||||
grpc_slice_unref(req_slice); |
||||
grpc_gcp_handshaker_req_destroy(req); |
||||
return buffer; |
||||
} |
||||
|
||||
static tsi_result handshaker_client_next(alts_handshaker_client* client, |
||||
alts_tsi_event* event, |
||||
grpc_slice* bytes_received) { |
||||
if (client == nullptr || event == nullptr || bytes_received == nullptr) { |
||||
gpr_log(GPR_ERROR, |
||||
"Invalid arguments to alts_grpc_handshaker_client_next()"); |
||||
return TSI_INVALID_ARGUMENT; |
||||
} |
||||
grpc_byte_buffer* buffer = get_serialized_next(bytes_received); |
||||
if (buffer == nullptr) { |
||||
gpr_log(GPR_ERROR, "get_serialized_next() failed"); |
||||
return TSI_INTERNAL_ERROR; |
||||
} |
||||
event->send_buffer = buffer; |
||||
tsi_result result = make_grpc_call(client, event, false /* is_start */); |
||||
if (result != TSI_OK) { |
||||
gpr_log(GPR_ERROR, "make_grpc_call() failed"); |
||||
} |
||||
return result; |
||||
} |
||||
|
||||
static void handshaker_client_destruct(alts_handshaker_client* client) { |
||||
if (client == nullptr) { |
||||
return; |
||||
} |
||||
alts_grpc_handshaker_client* grpc_client = |
||||
reinterpret_cast<alts_grpc_handshaker_client*>(client); |
||||
grpc_call_unref(grpc_client->call); |
||||
} |
||||
|
||||
static const alts_handshaker_client_vtable vtable = { |
||||
handshaker_client_start_client, handshaker_client_start_server, |
||||
handshaker_client_next, handshaker_client_destruct}; |
||||
|
||||
alts_handshaker_client* alts_grpc_handshaker_client_create( |
||||
grpc_channel* channel, grpc_completion_queue* queue, |
||||
const char* handshaker_service_url) { |
||||
if (channel == nullptr || queue == nullptr || |
||||
handshaker_service_url == nullptr) { |
||||
gpr_log(GPR_ERROR, "Invalid arguments to alts_handshaker_client_create()"); |
||||
return nullptr; |
||||
} |
||||
alts_grpc_handshaker_client* client = |
||||
static_cast<alts_grpc_handshaker_client*>(gpr_zalloc(sizeof(*client))); |
||||
client->grpc_caller = grpc_start_batch; |
||||
grpc_slice slice = grpc_slice_from_copied_string(handshaker_service_url); |
||||
client->call = grpc_channel_create_call( |
||||
channel, nullptr, GRPC_PROPAGATE_DEFAULTS, queue, |
||||
grpc_slice_from_static_string(ALTS_SERVICE_METHOD), &slice, |
||||
gpr_inf_future(GPR_CLOCK_REALTIME), nullptr); |
||||
client->base.vtable = &vtable; |
||||
grpc_slice_unref(slice); |
||||
return &client->base; |
||||
} |
||||
|
||||
namespace grpc_core { |
||||
namespace internal { |
||||
|
||||
void alts_handshaker_client_set_grpc_caller_for_testing( |
||||
alts_handshaker_client* client, alts_grpc_caller caller) { |
||||
GPR_ASSERT(client != nullptr && caller != nullptr); |
||||
alts_grpc_handshaker_client* grpc_client = |
||||
reinterpret_cast<alts_grpc_handshaker_client*>(client); |
||||
grpc_client->grpc_caller = caller; |
||||
} |
||||
|
||||
} // namespace internal
|
||||
} // namespace grpc_core
|
||||
|
||||
tsi_result alts_handshaker_client_start_client(alts_handshaker_client* client, |
||||
alts_tsi_event* event) { |
||||
if (client != nullptr && client->vtable != nullptr && |
||||
client->vtable->client_start != nullptr) { |
||||
return client->vtable->client_start(client, event); |
||||
} |
||||
gpr_log(GPR_ERROR, |
||||
"client or client->vtable has not been initialized properly"); |
||||
return TSI_INVALID_ARGUMENT; |
||||
} |
||||
|
||||
tsi_result alts_handshaker_client_start_server(alts_handshaker_client* client, |
||||
alts_tsi_event* event, |
||||
grpc_slice* bytes_received) { |
||||
if (client != nullptr && client->vtable != nullptr && |
||||
client->vtable->server_start != nullptr) { |
||||
return client->vtable->server_start(client, event, bytes_received); |
||||
} |
||||
gpr_log(GPR_ERROR, |
||||
"client or client->vtable has not been initialized properly"); |
||||
return TSI_INVALID_ARGUMENT; |
||||
} |
||||
|
||||
tsi_result alts_handshaker_client_next(alts_handshaker_client* client, |
||||
alts_tsi_event* event, |
||||
grpc_slice* bytes_received) { |
||||
if (client != nullptr && client->vtable != nullptr && |
||||
client->vtable->next != nullptr) { |
||||
return client->vtable->next(client, event, bytes_received); |
||||
} |
||||
gpr_log(GPR_ERROR, |
||||
"client or client->vtable has not been initialized properly"); |
||||
return TSI_INVALID_ARGUMENT; |
||||
} |
||||
|
||||
void alts_handshaker_client_destroy(alts_handshaker_client* client) { |
||||
if (client != nullptr) { |
||||
if (client->vtable != nullptr && client->vtable->destruct != nullptr) { |
||||
client->vtable->destruct(client); |
||||
} |
||||
gpr_free(client); |
||||
} |
||||
} |
@ -0,0 +1,137 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2018 gRPC authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
* |
||||
*/ |
||||
|
||||
#ifndef GRPC_CORE_TSI_ALTS_HANDSHAKER_ALTS_HANDSHAKER_CLIENT_H |
||||
#define GRPC_CORE_TSI_ALTS_HANDSHAKER_ALTS_HANDSHAKER_CLIENT_H |
||||
|
||||
#include <grpc/support/port_platform.h> |
||||
|
||||
#include <grpc/grpc.h> |
||||
|
||||
#include "src/core/tsi/alts/handshaker/alts_tsi_event.h" |
||||
|
||||
#define ALTS_SERVICE_METHOD "/grpc.gcp.HandshakerService/DoHandshake" |
||||
#define ALTS_APPLICATION_PROTOCOL "grpc" |
||||
#define ALTS_RECORD_PROTOCOL "ALTSRP_GCM_AES128_REKEY" |
||||
|
||||
const size_t kAltsAes128GcmRekeyKeyLength = 44; |
||||
|
||||
/**
|
||||
* A ALTS handshaker client interface. It is used to communicate with |
||||
* ALTS handshaker service by scheduling a handshaker request that could be one |
||||
* of client_start, server_start, and next handshaker requests. All APIs in the |
||||
* header are thread-compatible. |
||||
*/ |
||||
typedef struct alts_handshaker_client alts_handshaker_client; |
||||
|
||||
/* A function that makes the grpc call to the handshaker service. */ |
||||
typedef grpc_call_error (*alts_grpc_caller)(grpc_call* call, const grpc_op* ops, |
||||
size_t nops, void* tag); |
||||
|
||||
/* V-table for ALTS handshaker client operations. */ |
||||
typedef struct alts_handshaker_client_vtable { |
||||
tsi_result (*client_start)(alts_handshaker_client* client, |
||||
alts_tsi_event* event); |
||||
tsi_result (*server_start)(alts_handshaker_client* client, |
||||
alts_tsi_event* event, grpc_slice* bytes_received); |
||||
tsi_result (*next)(alts_handshaker_client* client, alts_tsi_event* event, |
||||
grpc_slice* bytes_received); |
||||
void (*destruct)(alts_handshaker_client* client); |
||||
} alts_handshaker_client_vtable; |
||||
|
||||
struct alts_handshaker_client { |
||||
const alts_handshaker_client_vtable* vtable; |
||||
}; |
||||
|
||||
/**
|
||||
* This method schedules a client_start handshaker request to ALTS handshaker |
||||
* service. |
||||
* |
||||
* - client: ALTS handshaker client instance. |
||||
* - event: ALTS TSI event instance. |
||||
* |
||||
* It returns TSI_OK on success and an error status code on failure. |
||||
*/ |
||||
tsi_result alts_handshaker_client_start_client(alts_handshaker_client* client, |
||||
alts_tsi_event* event); |
||||
|
||||
/**
|
||||
* This method schedules a server_start handshaker request to ALTS handshaker |
||||
* service. |
||||
* |
||||
* - client: ALTS handshaker client instance. |
||||
* - event: ALTS TSI event instance. |
||||
* - bytes_received: bytes in out_frames returned from the peer's handshaker |
||||
* response. |
||||
* |
||||
* It returns TSI_OK on success and an error status code on failure. |
||||
*/ |
||||
tsi_result alts_handshaker_client_start_server(alts_handshaker_client* client, |
||||
alts_tsi_event* event, |
||||
grpc_slice* bytes_received); |
||||
|
||||
/**
|
||||
* This method schedules a next handshaker request to ALTS handshaker service. |
||||
* |
||||
* - client: ALTS handshaker client instance. |
||||
* - event: ALTS TSI event instance. |
||||
* - bytes_received: bytes in out_frames returned from the peer's handshaker |
||||
* response. |
||||
* |
||||
* It returns TSI_OK on success and an error status code on failure. |
||||
*/ |
||||
tsi_result alts_handshaker_client_next(alts_handshaker_client* client, |
||||
alts_tsi_event* event, |
||||
grpc_slice* bytes_received); |
||||
|
||||
/**
|
||||
* This method destroys a ALTS handshaker client. |
||||
* |
||||
* - client: a ALTS handshaker client instance. |
||||
*/ |
||||
void alts_handshaker_client_destroy(alts_handshaker_client* client); |
||||
|
||||
/**
|
||||
* This method creates a ALTS handshaker client. |
||||
* |
||||
* - channel: grpc channel to ALTS handshaker service. |
||||
* - queue: grpc completion queue. |
||||
* - handshaker_service_url: address of ALTS handshaker service in the format of |
||||
* "host:port". |
||||
* |
||||
* It returns the created ALTS handshaker client on success, and NULL on |
||||
* failure. |
||||
*/ |
||||
alts_handshaker_client* alts_grpc_handshaker_client_create( |
||||
grpc_channel* channel, grpc_completion_queue* queue, |
||||
const char* handshaker_service_url); |
||||
|
||||
namespace grpc_core { |
||||
namespace internal { |
||||
|
||||
/**
|
||||
* Unsafe, use for testing only. It allows the caller to change the way that |
||||
* GRPC calls are made to the handshaker service. |
||||
*/ |
||||
void alts_handshaker_client_set_grpc_caller_for_testing( |
||||
alts_handshaker_client* client, alts_grpc_caller caller); |
||||
|
||||
} // namespace internal
|
||||
} // namespace grpc_core
|
||||
|
||||
#endif /* GRPC_CORE_TSI_ALTS_HANDSHAKER_ALTS_HANDSHAKER_CLIENT_H */ |
@ -0,0 +1,520 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2018 gRPC authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
* |
||||
*/ |
||||
|
||||
#include <grpc/support/port_platform.h> |
||||
|
||||
#include "src/core/tsi/alts/handshaker/alts_handshaker_service_api.h" |
||||
|
||||
#include <stdio.h> |
||||
#include <stdlib.h> |
||||
|
||||
#include "src/core/tsi/alts/handshaker/transport_security_common_api.h" |
||||
|
||||
/* HandshakerReq */ |
||||
grpc_gcp_handshaker_req* grpc_gcp_handshaker_req_create( |
||||
grpc_gcp_handshaker_req_type type) { |
||||
grpc_gcp_handshaker_req* req = |
||||
static_cast<grpc_gcp_handshaker_req*>(gpr_zalloc(sizeof(*req))); |
||||
switch (type) { |
||||
case CLIENT_START_REQ: |
||||
req->has_client_start = true; |
||||
break; |
||||
case SERVER_START_REQ: |
||||
req->has_server_start = true; |
||||
break; |
||||
case NEXT_REQ: |
||||
req->has_next = true; |
||||
break; |
||||
} |
||||
return req; |
||||
} |
||||
|
||||
void grpc_gcp_handshaker_req_destroy(grpc_gcp_handshaker_req* req) { |
||||
if (req == nullptr) { |
||||
return; |
||||
} |
||||
if (req->has_client_start) { |
||||
/* Destroy client_start request. */ |
||||
destroy_repeated_field_list_identity( |
||||
static_cast<repeated_field*>(req->client_start.target_identities.arg)); |
||||
destroy_repeated_field_list_string(static_cast<repeated_field*>( |
||||
req->client_start.application_protocols.arg)); |
||||
destroy_repeated_field_list_string( |
||||
static_cast<repeated_field*>(req->client_start.record_protocols.arg)); |
||||
if (req->client_start.has_local_identity) { |
||||
destroy_slice(static_cast<grpc_slice*>( |
||||
req->client_start.local_identity.hostname.arg)); |
||||
destroy_slice(static_cast<grpc_slice*>( |
||||
req->client_start.local_identity.service_account.arg)); |
||||
} |
||||
if (req->client_start.has_local_endpoint) { |
||||
destroy_slice(static_cast<grpc_slice*>( |
||||
req->client_start.local_endpoint.ip_address.arg)); |
||||
} |
||||
if (req->client_start.has_remote_endpoint) { |
||||
destroy_slice(static_cast<grpc_slice*>( |
||||
req->client_start.remote_endpoint.ip_address.arg)); |
||||
} |
||||
destroy_slice(static_cast<grpc_slice*>(req->client_start.target_name.arg)); |
||||
} else if (req->has_server_start) { |
||||
/* Destroy server_start request. */ |
||||
size_t i = 0; |
||||
for (i = 0; i < req->server_start.handshake_parameters_count; i++) { |
||||
destroy_repeated_field_list_identity( |
||||
static_cast<repeated_field*>(req->server_start.handshake_parameters[i] |
||||
.value.local_identities.arg)); |
||||
destroy_repeated_field_list_string( |
||||
static_cast<repeated_field*>(req->server_start.handshake_parameters[i] |
||||
.value.record_protocols.arg)); |
||||
} |
||||
destroy_repeated_field_list_string(static_cast<repeated_field*>( |
||||
req->server_start.application_protocols.arg)); |
||||
if (req->server_start.has_local_endpoint) { |
||||
destroy_slice(static_cast<grpc_slice*>( |
||||
req->server_start.local_endpoint.ip_address.arg)); |
||||
} |
||||
if (req->server_start.has_remote_endpoint) { |
||||
destroy_slice(static_cast<grpc_slice*>( |
||||
req->server_start.remote_endpoint.ip_address.arg)); |
||||
} |
||||
destroy_slice(static_cast<grpc_slice*>(req->server_start.in_bytes.arg)); |
||||
} else { |
||||
/* Destroy next request. */ |
||||
destroy_slice(static_cast<grpc_slice*>(req->next.in_bytes.arg)); |
||||
} |
||||
gpr_free(req); |
||||
} |
||||
|
||||
bool grpc_gcp_handshaker_req_set_handshake_protocol( |
||||
grpc_gcp_handshaker_req* req, |
||||
grpc_gcp_handshake_protocol handshake_protocol) { |
||||
if (req == nullptr || !req->has_client_start) { |
||||
gpr_log(GPR_ERROR, |
||||
"Invalid arguments to " |
||||
"grpc_gcp_handshaker_req_set_handshake_protocol()."); |
||||
return false; |
||||
} |
||||
req->client_start.has_handshake_security_protocol = true; |
||||
req->client_start.handshake_security_protocol = handshake_protocol; |
||||
return true; |
||||
} |
||||
|
||||
bool grpc_gcp_handshaker_req_set_target_name(grpc_gcp_handshaker_req* req, |
||||
const char* target_name) { |
||||
if (req == nullptr || target_name == nullptr || !req->has_client_start) { |
||||
gpr_log(GPR_ERROR, |
||||
"Invalid arguments to " |
||||
"grpc_gcp_handshaker_req_set_target_name()."); |
||||
return false; |
||||
} |
||||
grpc_slice* slice = create_slice(target_name, strlen(target_name)); |
||||
req->client_start.target_name.arg = slice; |
||||
req->client_start.target_name.funcs.encode = encode_string_or_bytes_cb; |
||||
return true; |
||||
} |
||||
|
||||
bool grpc_gcp_handshaker_req_add_application_protocol( |
||||
grpc_gcp_handshaker_req* req, const char* application_protocol) { |
||||
if (req == nullptr || application_protocol == nullptr || req->has_next) { |
||||
gpr_log(GPR_ERROR, |
||||
"Invalid arguments to " |
||||
"grpc_gcp_handshaker_req_add_application_protocol()."); |
||||
return false; |
||||
} |
||||
grpc_slice* slice = |
||||
create_slice(application_protocol, strlen(application_protocol)); |
||||
if (req->has_client_start) { |
||||
add_repeated_field(reinterpret_cast<repeated_field**>( |
||||
&req->client_start.application_protocols.arg), |
||||
slice); |
||||
req->client_start.application_protocols.funcs.encode = |
||||
encode_repeated_string_cb; |
||||
} else { |
||||
add_repeated_field(reinterpret_cast<repeated_field**>( |
||||
&req->server_start.application_protocols.arg), |
||||
slice); |
||||
req->server_start.application_protocols.funcs.encode = |
||||
encode_repeated_string_cb; |
||||
} |
||||
return true; |
||||
} |
||||
|
||||
bool grpc_gcp_handshaker_req_add_record_protocol(grpc_gcp_handshaker_req* req, |
||||
const char* record_protocol) { |
||||
if (req == nullptr || record_protocol == nullptr || !req->has_client_start) { |
||||
gpr_log(GPR_ERROR, |
||||
"Invalid arguments to " |
||||
"grpc_gcp_handshaker_req_add_record_protocol()."); |
||||
return false; |
||||
} |
||||
grpc_slice* slice = create_slice(record_protocol, strlen(record_protocol)); |
||||
add_repeated_field(reinterpret_cast<repeated_field**>( |
||||
&req->client_start.record_protocols.arg), |
||||
slice); |
||||
req->client_start.record_protocols.funcs.encode = encode_repeated_string_cb; |
||||
return true; |
||||
} |
||||
|
||||
static void set_identity_hostname(grpc_gcp_identity* identity, |
||||
const char* hostname) { |
||||
grpc_slice* slice = create_slice(hostname, strlen(hostname)); |
||||
identity->hostname.arg = slice; |
||||
identity->hostname.funcs.encode = encode_string_or_bytes_cb; |
||||
} |
||||
|
||||
static void set_identity_service_account(grpc_gcp_identity* identity, |
||||
const char* service_account) { |
||||
grpc_slice* slice = create_slice(service_account, strlen(service_account)); |
||||
identity->service_account.arg = slice; |
||||
identity->service_account.funcs.encode = encode_string_or_bytes_cb; |
||||
} |
||||
|
||||
bool grpc_gcp_handshaker_req_add_target_identity_hostname( |
||||
grpc_gcp_handshaker_req* req, const char* hostname) { |
||||
if (req == nullptr || hostname == nullptr || !req->has_client_start) { |
||||
gpr_log(GPR_ERROR, |
||||
"Invalid nullptr arguments to " |
||||
"grpc_gcp_handshaker_req_add_target_identity_hostname()."); |
||||
return false; |
||||
} |
||||
grpc_gcp_identity* target_identity = |
||||
static_cast<grpc_gcp_identity*>(gpr_zalloc(sizeof(*target_identity))); |
||||
set_identity_hostname(target_identity, hostname); |
||||
req->client_start.target_identities.funcs.encode = |
||||
encode_repeated_identity_cb; |
||||
add_repeated_field(reinterpret_cast<repeated_field**>( |
||||
&req->client_start.target_identities.arg), |
||||
target_identity); |
||||
return true; |
||||
} |
||||
|
||||
bool grpc_gcp_handshaker_req_add_target_identity_service_account( |
||||
grpc_gcp_handshaker_req* req, const char* service_account) { |
||||
if (req == nullptr || service_account == nullptr || !req->has_client_start) { |
||||
gpr_log(GPR_ERROR, |
||||
"Invalid nullptr arguments to " |
||||
"grpc_gcp_handshaker_req_add_target_identity_service_account()."); |
||||
return false; |
||||
} |
||||
grpc_gcp_identity* target_identity = |
||||
static_cast<grpc_gcp_identity*>(gpr_zalloc(sizeof(*target_identity))); |
||||
set_identity_service_account(target_identity, service_account); |
||||
req->client_start.target_identities.funcs.encode = |
||||
encode_repeated_identity_cb; |
||||
add_repeated_field(reinterpret_cast<repeated_field**>( |
||||
&req->client_start.target_identities.arg), |
||||
target_identity); |
||||
return true; |
||||
} |
||||
|
||||
bool grpc_gcp_handshaker_req_set_local_identity_hostname( |
||||
grpc_gcp_handshaker_req* req, const char* hostname) { |
||||
if (req == nullptr || hostname == nullptr || !req->has_client_start) { |
||||
gpr_log(GPR_ERROR, |
||||
"Invalid nullptr arguments to " |
||||
"grpc_gcp_handshaker_req_set_local_identity_hostname()."); |
||||
return false; |
||||
} |
||||
req->client_start.has_local_identity = true; |
||||
set_identity_hostname(&req->client_start.local_identity, hostname); |
||||
return true; |
||||
} |
||||
|
||||
bool grpc_gcp_handshaker_req_set_local_identity_service_account( |
||||
grpc_gcp_handshaker_req* req, const char* service_account) { |
||||
if (req == nullptr || service_account == nullptr || !req->has_client_start) { |
||||
gpr_log(GPR_ERROR, |
||||
"Invalid nullptr arguments to " |
||||
"grpc_gcp_handshaker_req_set_local_identity_service_account()."); |
||||
return false; |
||||
} |
||||
req->client_start.has_local_identity = true; |
||||
set_identity_service_account(&req->client_start.local_identity, |
||||
service_account); |
||||
return true; |
||||
} |
||||
|
||||
static void set_endpoint(grpc_gcp_endpoint* endpoint, const char* ip_address, |
||||
size_t port, grpc_gcp_network_protocol protocol) { |
||||
grpc_slice* slice = create_slice(ip_address, strlen(ip_address)); |
||||
endpoint->ip_address.arg = slice; |
||||
endpoint->ip_address.funcs.encode = encode_string_or_bytes_cb; |
||||
endpoint->has_port = true; |
||||
endpoint->port = static_cast<int32_t>(port); |
||||
endpoint->has_protocol = true; |
||||
endpoint->protocol = protocol; |
||||
} |
||||
|
||||
bool grpc_gcp_handshaker_req_set_rpc_versions(grpc_gcp_handshaker_req* req, |
||||
uint32_t max_major, |
||||
uint32_t max_minor, |
||||
uint32_t min_major, |
||||
uint32_t min_minor) { |
||||
if (req == nullptr || req->has_next) { |
||||
gpr_log(GPR_ERROR, |
||||
"Invalid arguments to " |
||||
"grpc_gcp_handshaker_req_set_rpc_versions()."); |
||||
return false; |
||||
} |
||||
if (req->has_client_start) { |
||||
req->client_start.has_rpc_versions = true; |
||||
grpc_gcp_rpc_protocol_versions_set_max(&req->client_start.rpc_versions, |
||||
max_major, max_minor); |
||||
grpc_gcp_rpc_protocol_versions_set_min(&req->client_start.rpc_versions, |
||||
min_major, min_minor); |
||||
} else { |
||||
req->server_start.has_rpc_versions = true; |
||||
grpc_gcp_rpc_protocol_versions_set_max(&req->server_start.rpc_versions, |
||||
max_major, max_minor); |
||||
grpc_gcp_rpc_protocol_versions_set_min(&req->server_start.rpc_versions, |
||||
min_major, min_minor); |
||||
} |
||||
return true; |
||||
} |
||||
|
||||
bool grpc_gcp_handshaker_req_set_local_endpoint( |
||||
grpc_gcp_handshaker_req* req, const char* ip_address, size_t port, |
||||
grpc_gcp_network_protocol protocol) { |
||||
if (req == nullptr || ip_address == nullptr || port > 65535 || |
||||
req->has_next) { |
||||
gpr_log(GPR_ERROR, |
||||
"Invalid arguments to " |
||||
"grpc_gcp_handshaker_req_set_local_endpoint()."); |
||||
return false; |
||||
} |
||||
if (req->has_client_start) { |
||||
req->client_start.has_local_endpoint = true; |
||||
set_endpoint(&req->client_start.local_endpoint, ip_address, port, protocol); |
||||
} else { |
||||
req->server_start.has_local_endpoint = true; |
||||
set_endpoint(&req->server_start.local_endpoint, ip_address, port, protocol); |
||||
} |
||||
return true; |
||||
} |
||||
|
||||
bool grpc_gcp_handshaker_req_set_remote_endpoint( |
||||
grpc_gcp_handshaker_req* req, const char* ip_address, size_t port, |
||||
grpc_gcp_network_protocol protocol) { |
||||
if (req == nullptr || ip_address == nullptr || port > 65535 || |
||||
req->has_next) { |
||||
gpr_log(GPR_ERROR, |
||||
"Invalid arguments to " |
||||
"grpc_gcp_handshaker_req_set_remote_endpoint()."); |
||||
return false; |
||||
} |
||||
if (req->has_client_start) { |
||||
req->client_start.has_remote_endpoint = true; |
||||
set_endpoint(&req->client_start.remote_endpoint, ip_address, port, |
||||
protocol); |
||||
} else { |
||||
req->server_start.has_remote_endpoint = true; |
||||
set_endpoint(&req->server_start.remote_endpoint, ip_address, port, |
||||
protocol); |
||||
} |
||||
return true; |
||||
} |
||||
|
||||
bool grpc_gcp_handshaker_req_set_in_bytes(grpc_gcp_handshaker_req* req, |
||||
const char* in_bytes, size_t size) { |
||||
if (req == nullptr || in_bytes == nullptr || req->has_client_start) { |
||||
gpr_log(GPR_ERROR, |
||||
"Invalid arguments to " |
||||
"grpc_gcp_handshaker_req_set_in_bytes()."); |
||||
return false; |
||||
} |
||||
grpc_slice* slice = create_slice(in_bytes, size); |
||||
if (req->has_next) { |
||||
req->next.in_bytes.arg = slice; |
||||
req->next.in_bytes.funcs.encode = &encode_string_or_bytes_cb; |
||||
} else { |
||||
req->server_start.in_bytes.arg = slice; |
||||
req->server_start.in_bytes.funcs.encode = &encode_string_or_bytes_cb; |
||||
} |
||||
return true; |
||||
} |
||||
|
||||
static grpc_gcp_server_handshake_parameters* server_start_find_param( |
||||
grpc_gcp_handshaker_req* req, int32_t key) { |
||||
size_t i = 0; |
||||
for (i = 0; i < req->server_start.handshake_parameters_count; i++) { |
||||
if (req->server_start.handshake_parameters[i].key == key) { |
||||
return &req->server_start.handshake_parameters[i].value; |
||||
} |
||||
} |
||||
req->server_start |
||||
.handshake_parameters[req->server_start.handshake_parameters_count] |
||||
.has_key = true; |
||||
req->server_start |
||||
.handshake_parameters[req->server_start.handshake_parameters_count] |
||||
.has_value = true; |
||||
req->server_start |
||||
.handshake_parameters[req->server_start.handshake_parameters_count++] |
||||
.key = key; |
||||
return &req->server_start |
||||
.handshake_parameters |
||||
[req->server_start.handshake_parameters_count - 1] |
||||
.value; |
||||
} |
||||
|
||||
bool grpc_gcp_handshaker_req_param_add_record_protocol( |
||||
grpc_gcp_handshaker_req* req, grpc_gcp_handshake_protocol key, |
||||
const char* record_protocol) { |
||||
if (req == nullptr || record_protocol == nullptr || !req->has_server_start) { |
||||
gpr_log(GPR_ERROR, |
||||
"Invalid arguments to " |
||||
"grpc_gcp_handshaker_req_param_add_record_protocol()."); |
||||
return false; |
||||
} |
||||
grpc_gcp_server_handshake_parameters* param = |
||||
server_start_find_param(req, key); |
||||
grpc_slice* slice = create_slice(record_protocol, strlen(record_protocol)); |
||||
add_repeated_field( |
||||
reinterpret_cast<repeated_field**>(¶m->record_protocols.arg), slice); |
||||
param->record_protocols.funcs.encode = &encode_repeated_string_cb; |
||||
return true; |
||||
} |
||||
|
||||
bool grpc_gcp_handshaker_req_param_add_local_identity_hostname( |
||||
grpc_gcp_handshaker_req* req, grpc_gcp_handshake_protocol key, |
||||
const char* hostname) { |
||||
if (req == nullptr || hostname == nullptr || !req->has_server_start) { |
||||
gpr_log(GPR_ERROR, |
||||
"Invalid arguments to " |
||||
"grpc_gcp_handshaker_req_param_add_local_identity_hostname()."); |
||||
return false; |
||||
} |
||||
grpc_gcp_server_handshake_parameters* param = |
||||
server_start_find_param(req, key); |
||||
grpc_gcp_identity* local_identity = |
||||
static_cast<grpc_gcp_identity*>(gpr_zalloc(sizeof(*local_identity))); |
||||
set_identity_hostname(local_identity, hostname); |
||||
add_repeated_field( |
||||
reinterpret_cast<repeated_field**>(¶m->local_identities.arg), |
||||
local_identity); |
||||
param->local_identities.funcs.encode = &encode_repeated_identity_cb; |
||||
return true; |
||||
} |
||||
|
||||
bool grpc_gcp_handshaker_req_param_add_local_identity_service_account( |
||||
grpc_gcp_handshaker_req* req, grpc_gcp_handshake_protocol key, |
||||
const char* service_account) { |
||||
if (req == nullptr || service_account == nullptr || !req->has_server_start) { |
||||
gpr_log( |
||||
GPR_ERROR, |
||||
"Invalid arguments to " |
||||
"grpc_gcp_handshaker_req_param_add_local_identity_service_account()."); |
||||
return false; |
||||
} |
||||
grpc_gcp_server_handshake_parameters* param = |
||||
server_start_find_param(req, key); |
||||
grpc_gcp_identity* local_identity = |
||||
static_cast<grpc_gcp_identity*>(gpr_zalloc(sizeof(*local_identity))); |
||||
set_identity_service_account(local_identity, service_account); |
||||
add_repeated_field( |
||||
reinterpret_cast<repeated_field**>(¶m->local_identities.arg), |
||||
local_identity); |
||||
param->local_identities.funcs.encode = &encode_repeated_identity_cb; |
||||
return true; |
||||
} |
||||
|
||||
bool grpc_gcp_handshaker_req_encode(grpc_gcp_handshaker_req* req, |
||||
grpc_slice* slice) { |
||||
if (req == nullptr || slice == nullptr) { |
||||
gpr_log(GPR_ERROR, |
||||
"Invalid nullptr arguments to grpc_gcp_handshaker_req_encode()."); |
||||
return false; |
||||
} |
||||
pb_ostream_t size_stream; |
||||
memset(&size_stream, 0, sizeof(pb_ostream_t)); |
||||
if (!pb_encode(&size_stream, grpc_gcp_HandshakerReq_fields, req)) { |
||||
gpr_log(GPR_ERROR, "nanopb error: %s", PB_GET_ERROR(&size_stream)); |
||||
return false; |
||||
} |
||||
size_t encoded_length = size_stream.bytes_written; |
||||
*slice = grpc_slice_malloc(encoded_length); |
||||
pb_ostream_t output_stream = |
||||
pb_ostream_from_buffer(GRPC_SLICE_START_PTR(*slice), encoded_length); |
||||
if (!pb_encode(&output_stream, grpc_gcp_HandshakerReq_fields, req) != 0) { |
||||
gpr_log(GPR_ERROR, "nanopb error: %s", PB_GET_ERROR(&output_stream)); |
||||
return false; |
||||
} |
||||
return true; |
||||
} |
||||
|
||||
/* HandshakerResp. */ |
||||
grpc_gcp_handshaker_resp* grpc_gcp_handshaker_resp_create(void) { |
||||
grpc_gcp_handshaker_resp* resp = |
||||
static_cast<grpc_gcp_handshaker_resp*>(gpr_zalloc(sizeof(*resp))); |
||||
return resp; |
||||
} |
||||
|
||||
void grpc_gcp_handshaker_resp_destroy(grpc_gcp_handshaker_resp* resp) { |
||||
if (resp != nullptr) { |
||||
destroy_slice(static_cast<grpc_slice*>(resp->out_frames.arg)); |
||||
if (resp->has_status) { |
||||
destroy_slice(static_cast<grpc_slice*>(resp->status.details.arg)); |
||||
} |
||||
if (resp->has_result) { |
||||
destroy_slice( |
||||
static_cast<grpc_slice*>(resp->result.application_protocol.arg)); |
||||
destroy_slice(static_cast<grpc_slice*>(resp->result.record_protocol.arg)); |
||||
destroy_slice(static_cast<grpc_slice*>(resp->result.key_data.arg)); |
||||
if (resp->result.has_local_identity) { |
||||
destroy_slice( |
||||
static_cast<grpc_slice*>(resp->result.local_identity.hostname.arg)); |
||||
destroy_slice(static_cast<grpc_slice*>( |
||||
resp->result.local_identity.service_account.arg)); |
||||
} |
||||
if (resp->result.has_peer_identity) { |
||||
destroy_slice( |
||||
static_cast<grpc_slice*>(resp->result.peer_identity.hostname.arg)); |
||||
destroy_slice(static_cast<grpc_slice*>( |
||||
resp->result.peer_identity.service_account.arg)); |
||||
} |
||||
} |
||||
gpr_free(resp); |
||||
} |
||||
} |
||||
|
||||
bool grpc_gcp_handshaker_resp_decode(grpc_slice encoded_handshaker_resp, |
||||
grpc_gcp_handshaker_resp* resp) { |
||||
if (resp == nullptr) { |
||||
gpr_log(GPR_ERROR, |
||||
"Invalid nullptr argument to grpc_gcp_handshaker_resp_decode()."); |
||||
return false; |
||||
} |
||||
pb_istream_t stream = |
||||
pb_istream_from_buffer(GRPC_SLICE_START_PTR(encoded_handshaker_resp), |
||||
GRPC_SLICE_LENGTH(encoded_handshaker_resp)); |
||||
resp->out_frames.funcs.decode = decode_string_or_bytes_cb; |
||||
resp->status.details.funcs.decode = decode_string_or_bytes_cb; |
||||
resp->result.application_protocol.funcs.decode = decode_string_or_bytes_cb; |
||||
resp->result.record_protocol.funcs.decode = decode_string_or_bytes_cb; |
||||
resp->result.key_data.funcs.decode = decode_string_or_bytes_cb; |
||||
resp->result.peer_identity.hostname.funcs.decode = decode_string_or_bytes_cb; |
||||
resp->result.peer_identity.service_account.funcs.decode = |
||||
decode_string_or_bytes_cb; |
||||
resp->result.local_identity.hostname.funcs.decode = decode_string_or_bytes_cb; |
||||
resp->result.local_identity.service_account.funcs.decode = |
||||
decode_string_or_bytes_cb; |
||||
if (!pb_decode(&stream, grpc_gcp_HandshakerResp_fields, resp)) { |
||||
gpr_log(GPR_ERROR, "nanopb error: %s", PB_GET_ERROR(&stream)); |
||||
return false; |
||||
} |
||||
return true; |
||||
} |
@ -0,0 +1,323 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2018 gRPC authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
* |
||||
*/ |
||||
|
||||
#ifndef GRPC_CORE_TSI_ALTS_HANDSHAKER_ALTS_HANDSHAKER_SERVICE_API_H |
||||
#define GRPC_CORE_TSI_ALTS_HANDSHAKER_ALTS_HANDSHAKER_SERVICE_API_H |
||||
|
||||
#include <grpc/support/port_platform.h> |
||||
|
||||
#include "src/core/tsi/alts/handshaker/alts_handshaker_service_api_util.h" |
||||
|
||||
/**
|
||||
* An implementation of nanopb thin wrapper used to set/get and |
||||
* serialize/de-serialize of ALTS handshake requests and responses. |
||||
* |
||||
* All APIs in the header are thread-compatible. A typical usage of this API at |
||||
* the client side is as follows: |
||||
* |
||||
* ----------------------------------------------------------------------------- |
||||
* // Create, populate, and serialize an ALTS client_start handshake request to
|
||||
* // send to the server.
|
||||
* grpc_gcp_handshaker_req* req = |
||||
* grpc_gcp_handshaker_req_create(CLIENT_START_REQ); |
||||
* grpc_gcp_handshaker_req_set_handshake_protocol( |
||||
req, grpc_gcp_HandshakeProtocol_ALTS); |
||||
* grpc_gcp_handshaker_req_add_application_protocol(req, "grpc"); |
||||
* grpc_gcp_handshaker_req_add_record_protocol(req, "ALTSRP_GCM_AES128"); |
||||
* grpc_slice client_slice; |
||||
* if (!grpc_gcp_handshaker_req_encode(req, &client_slice)) { |
||||
* fprintf(stderr, "ALTS handshake request encoding failed."; |
||||
* } |
||||
* |
||||
* // De-serialize a data stream received from the server, and store the result
|
||||
* // at ALTS handshake response.
|
||||
* grpc_gcp_handshaker_resp* resp = grpc_gcp_handshaker_resp_create(); |
||||
* if (!grpc_gcp_handshaker_resp_decode(server_slice, resp)) { |
||||
* fprintf(stderr, "ALTS handshake response decoding failed."); |
||||
* } |
||||
* // To access a variable-length datatype field (i.e., pb_callback_t),
|
||||
* // access its "arg" subfield (if it has been set).
|
||||
* if (resp->out_frames.arg != nullptr) { |
||||
* grpc_slice* slice = resp->out_frames.arg; |
||||
* } |
||||
* // To access a fixed-length datatype field (i.e., not pb_calback_t),
|
||||
* // access the field directly (if it has been set).
|
||||
* if (resp->has_status && resp->status->has_code) { |
||||
* uint32_t code = resp->status->code; |
||||
* } |
||||
*------------------------------------------------------------------------------ |
||||
*/ |
||||
|
||||
/**
|
||||
* This method creates an ALTS handshake request. |
||||
* |
||||
* - type: an enum type value that can be either CLIENT_START_REQ, |
||||
* SERVER_START_REQ, or NEXT_REQ to indicate the created instance will be |
||||
* client_start, server_start, and next handshake request message |
||||
* respectively. |
||||
* |
||||
* The method returns a pointer to the created instance. |
||||
*/ |
||||
grpc_gcp_handshaker_req* grpc_gcp_handshaker_req_create( |
||||
grpc_gcp_handshaker_req_type type); |
||||
|
||||
/**
|
||||
* This method sets the value for handshake_security_protocol field of ALTS |
||||
* client_start handshake request. |
||||
* |
||||
* - req: an ALTS handshake request. |
||||
* - handshake_protocol: a enum type value representing the handshake security |
||||
* protocol. |
||||
* |
||||
* The method returns true on success and false otherwise. |
||||
*/ |
||||
bool grpc_gcp_handshaker_req_set_handshake_protocol( |
||||
grpc_gcp_handshaker_req* req, |
||||
grpc_gcp_handshake_protocol handshake_protocol); |
||||
|
||||
/**
|
||||
* This method sets the value for target_name field of ALTS client_start |
||||
* handshake request. |
||||
* |
||||
* - req: an ALTS handshake request. |
||||
* - target_name: a target name to be set. |
||||
* |
||||
* The method returns true on success and false otherwise. |
||||
*/ |
||||
bool grpc_gcp_handshaker_req_set_target_name(grpc_gcp_handshaker_req* req, |
||||
const char* target_name); |
||||
|
||||
/**
|
||||
* This method adds an application protocol supported by the server (or |
||||
* client) to ALTS server_start (or client_start) handshake request. |
||||
* |
||||
* - req: an ALTS handshake request. |
||||
* - application_protocol: an application protocol (e.g., grpc) to be added. |
||||
* |
||||
* The method returns true on success and false otherwise. |
||||
*/ |
||||
bool grpc_gcp_handshaker_req_add_application_protocol( |
||||
grpc_gcp_handshaker_req* req, const char* application_protocol); |
||||
|
||||
/**
|
||||
* This method adds a record protocol supported by the client to ALTS |
||||
* client_start handshake request. |
||||
* |
||||
* - req: an ALTS handshake request. |
||||
* - record_protocol: a record protocol (e.g., ALTSRP_GCM_AES128) to be |
||||
* added. |
||||
* |
||||
* The method returns true on success and false otherwise. |
||||
*/ |
||||
bool grpc_gcp_handshaker_req_add_record_protocol(grpc_gcp_handshaker_req* req, |
||||
const char* record_protocol); |
||||
|
||||
/**
|
||||
* This method adds a target server identity represented as hostname and |
||||
* acceptable by a client to ALTS client_start handshake request. |
||||
* |
||||
* - req: an ALTS handshake request. |
||||
* - hostname: a string representation of hostname at the connection |
||||
* endpoint to be added. |
||||
* |
||||
* The method returns true on success and false otherwise. |
||||
*/ |
||||
bool grpc_gcp_handshaker_req_add_target_identity_hostname( |
||||
grpc_gcp_handshaker_req* req, const char* hostname); |
||||
|
||||
/**
|
||||
* This method adds a target server identity represented as service account and |
||||
* acceptable by a client to ALTS client_start handshake request. |
||||
* |
||||
* - req: an ALTS handshake request. |
||||
* - service_account: a string representation of service account at the |
||||
* connection endpoint to be added. |
||||
* |
||||
* The method returns true on success and false otherwise. |
||||
*/ |
||||
bool grpc_gcp_handshaker_req_add_target_identity_service_account( |
||||
grpc_gcp_handshaker_req* req, const char* service_account); |
||||
|
||||
/**
|
||||
* This method sets the hostname for local_identity field of ALTS client_start |
||||
* handshake request. |
||||
* |
||||
* - req: an ALTS handshake request. |
||||
* - hostname: a string representation of hostname. |
||||
* |
||||
* The method returns true on success and false otherwise. |
||||
*/ |
||||
bool grpc_gcp_handshaker_req_set_local_identity_hostname( |
||||
grpc_gcp_handshaker_req* req, const char* hostname); |
||||
|
||||
/**
|
||||
* This method sets the service account for local_identity field of ALTS |
||||
* client_start handshake request. |
||||
* |
||||
* - req: an ALTS handshake request. |
||||
* - service_account: a string representation of service account. |
||||
* |
||||
* The method returns true on success and false otherwise. |
||||
*/ |
||||
bool grpc_gcp_handshaker_req_set_local_identity_service_account( |
||||
grpc_gcp_handshaker_req* req, const char* service_account); |
||||
|
||||
/**
|
||||
* This method sets the value for local_endpoint field of either ALTS |
||||
* client_start or server_start handshake request. |
||||
* |
||||
* - req: an ALTS handshake request. |
||||
* - ip_address: a string representation of ip address associated with the |
||||
* local endpoint, that could be either IPv4 or IPv6. |
||||
* - port: a port number associated with the local endpoint. |
||||
* - protocol: a network protocol (e.g., TCP or UDP) associated with the |
||||
* local endpoint. |
||||
* |
||||
* The method returns true on success and false otherwise. |
||||
*/ |
||||
bool grpc_gcp_handshaker_req_set_local_endpoint( |
||||
grpc_gcp_handshaker_req* req, const char* ip_address, size_t port, |
||||
grpc_gcp_network_protocol protocol); |
||||
|
||||
/**
|
||||
* This method sets the value for remote_endpoint field of either ALTS |
||||
* client_start or server_start handshake request. |
||||
* |
||||
* - req: an ALTS handshake request. |
||||
* - ip_address: a string representation of ip address associated with the |
||||
* remote endpoint, that could be either IPv4 or IPv6. |
||||
* - port: a port number associated with the remote endpoint. |
||||
* - protocol: a network protocol (e.g., TCP or UDP) associated with the |
||||
* remote endpoint. |
||||
* |
||||
* The method returns true on success and false otherwise. |
||||
*/ |
||||
bool grpc_gcp_handshaker_req_set_remote_endpoint( |
||||
grpc_gcp_handshaker_req* req, const char* ip_address, size_t port, |
||||
grpc_gcp_network_protocol protocol); |
||||
|
||||
/**
|
||||
* This method sets the value for in_bytes field of either ALTS server_start or |
||||
* next handshake request. |
||||
* |
||||
* - req: an ALTS handshake request. |
||||
* - in_bytes: a buffer containing bytes taken from out_frames of the peer's |
||||
* ALTS handshake response. It is possible that the peer's out_frames are |
||||
* split into multiple handshake request messages. |
||||
* - size: size of in_bytes buffer. |
||||
* |
||||
* The method returns true on success and false otherwise. |
||||
*/ |
||||
bool grpc_gcp_handshaker_req_set_in_bytes(grpc_gcp_handshaker_req* req, |
||||
const char* in_bytes, size_t size); |
||||
|
||||
/**
|
||||
* This method adds a record protocol to handshake parameters mapped by the |
||||
* handshake protocol for ALTS server_start handshake request. |
||||
* |
||||
* - req: an ALTS handshake request. |
||||
* - key: an enum type value representing a handshake security protocol. |
||||
* - record_protocol: a record protocol to be added. |
||||
* |
||||
* The method returns true on success and false otherwise. |
||||
*/ |
||||
bool grpc_gcp_handshaker_req_param_add_record_protocol( |
||||
grpc_gcp_handshaker_req* req, grpc_gcp_handshake_protocol key, |
||||
const char* record_protocol); |
||||
|
||||
/**
|
||||
* This method adds a local identity represented as hostname to handshake |
||||
* parameters mapped by the handshake protocol for ALTS server_start handshake |
||||
* request. |
||||
* |
||||
* - req: an ALTS handshake request. |
||||
* - key: an enum type value representing a handshake security protocol. |
||||
* - hostname: a string representation of hostname to be added. |
||||
* |
||||
* The method returns true on success and false otherwise. |
||||
*/ |
||||
bool grpc_gcp_handshaker_req_param_add_local_identity_hostname( |
||||
grpc_gcp_handshaker_req* req, grpc_gcp_handshake_protocol key, |
||||
const char* hostname); |
||||
|
||||
/**
|
||||
* This method adds a local identity represented as service account to handshake |
||||
* parameters mapped by the handshake protocol for ALTS server_start handshake |
||||
* request. |
||||
* |
||||
* - req: an ALTS handshake request. |
||||
* - key: an enum type value representing a handshake security protocol. |
||||
* - service_account: a string representation of service account to be added. |
||||
* |
||||
* The method returns true on success and false otherwise. |
||||
*/ |
||||
bool grpc_gcp_handshaker_req_param_add_local_identity_service_account( |
||||
grpc_gcp_handshaker_req* req, grpc_gcp_handshake_protocol key, |
||||
const char* service_account); |
||||
|
||||
/**
|
||||
* This method sets the value for rpc_versions field of either ALTS |
||||
* client_start or server_start handshake request. |
||||
* |
||||
* - req: an ALTS handshake request. |
||||
* - max_major: a major version of maximum supported RPC version. |
||||
* - max_minor: a minor version of maximum supported RPC version. |
||||
* - min_major: a major version of minimum supported RPC version. |
||||
* - min_minor: a minor version of minimum supported RPC version. |
||||
* |
||||
* The method returns true on success and false otherwise. |
||||
*/ |
||||
bool grpc_gcp_handshaker_req_set_rpc_versions(grpc_gcp_handshaker_req* req, |
||||
uint32_t max_major, |
||||
uint32_t max_minor, |
||||
uint32_t min_major, |
||||
uint32_t min_minor); |
||||
|
||||
/**
|
||||
* This method serializes an ALTS handshake request and returns a data stream. |
||||
* |
||||
* - req: an ALTS handshake request. |
||||
* - slice: a data stream where the serialized result will be written. |
||||
* |
||||
* The method returns true on success and false otherwise. |
||||
*/ |
||||
bool grpc_gcp_handshaker_req_encode(grpc_gcp_handshaker_req* req, |
||||
grpc_slice* slice); |
||||
|
||||
/* This method destroys an ALTS handshake request. */ |
||||
void grpc_gcp_handshaker_req_destroy(grpc_gcp_handshaker_req* req); |
||||
|
||||
/* This method creates an ALTS handshake response. */ |
||||
grpc_gcp_handshaker_resp* grpc_gcp_handshaker_resp_create(void); |
||||
|
||||
/**
|
||||
* This method de-serializes a data stream and stores the result |
||||
* in an ALTS handshake response. |
||||
* |
||||
* - slice: a data stream containing a serialized ALTS handshake response. |
||||
* - resp: an ALTS handshake response used to hold de-serialized result. |
||||
* |
||||
* The method returns true on success and false otherwise. |
||||
*/ |
||||
bool grpc_gcp_handshaker_resp_decode(grpc_slice slice, |
||||
grpc_gcp_handshaker_resp* resp); |
||||
|
||||
/* This method destroys an ALTS handshake response. */ |
||||
void grpc_gcp_handshaker_resp_destroy(grpc_gcp_handshaker_resp* resp); |
||||
|
||||
#endif /* GRPC_CORE_TSI_ALTS_HANDSHAKER_ALTS_HANDSHAKER_SERVICE_API_H */ |
@ -0,0 +1,143 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2018 gRPC authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
* |
||||
*/ |
||||
|
||||
#include <grpc/support/port_platform.h> |
||||
|
||||
#include "src/core/tsi/alts/handshaker/alts_handshaker_service_api_util.h" |
||||
|
||||
void add_repeated_field(repeated_field** head, const void* data) { |
||||
repeated_field* field = |
||||
static_cast<repeated_field*>(gpr_zalloc(sizeof(*field))); |
||||
field->data = data; |
||||
if (*head == nullptr) { |
||||
*head = field; |
||||
(*head)->next = nullptr; |
||||
} else { |
||||
field->next = *head; |
||||
*head = field; |
||||
} |
||||
} |
||||
|
||||
void destroy_repeated_field_list_identity(repeated_field* head) { |
||||
repeated_field* field = head; |
||||
while (field != nullptr) { |
||||
repeated_field* next_field = field->next; |
||||
const grpc_gcp_identity* identity = |
||||
static_cast<const grpc_gcp_identity*>(field->data); |
||||
destroy_slice(static_cast<grpc_slice*>(identity->hostname.arg)); |
||||
destroy_slice(static_cast<grpc_slice*>(identity->service_account.arg)); |
||||
gpr_free((void*)identity); |
||||
gpr_free(field); |
||||
field = next_field; |
||||
} |
||||
} |
||||
|
||||
void destroy_repeated_field_list_string(repeated_field* head) { |
||||
repeated_field* field = head; |
||||
while (field != nullptr) { |
||||
repeated_field* next_field = field->next; |
||||
destroy_slice((grpc_slice*)field->data); |
||||
gpr_free(field); |
||||
field = next_field; |
||||
} |
||||
} |
||||
|
||||
grpc_slice* create_slice(const char* data, size_t size) { |
||||
grpc_slice slice = grpc_slice_from_copied_buffer(data, size); |
||||
grpc_slice* cb_slice = |
||||
static_cast<grpc_slice*>(gpr_zalloc(sizeof(*cb_slice))); |
||||
memcpy(cb_slice, &slice, sizeof(*cb_slice)); |
||||
return cb_slice; |
||||
} |
||||
|
||||
void destroy_slice(grpc_slice* slice) { |
||||
if (slice != nullptr) { |
||||
grpc_slice_unref(*slice); |
||||
gpr_free(slice); |
||||
} |
||||
} |
||||
|
||||
bool encode_string_or_bytes_cb(pb_ostream_t* stream, const pb_field_t* field, |
||||
void* const* arg) { |
||||
grpc_slice* slice = static_cast<grpc_slice*>(*arg); |
||||
if (!pb_encode_tag_for_field(stream, field)) return false; |
||||
return pb_encode_string(stream, GRPC_SLICE_START_PTR(*slice), |
||||
GRPC_SLICE_LENGTH(*slice)); |
||||
} |
||||
|
||||
bool encode_repeated_identity_cb(pb_ostream_t* stream, const pb_field_t* field, |
||||
void* const* arg) { |
||||
repeated_field* var = static_cast<repeated_field*>(*arg); |
||||
while (var != nullptr) { |
||||
if (!pb_encode_tag_for_field(stream, field)) return false; |
||||
if (!pb_encode_submessage(stream, grpc_gcp_Identity_fields, |
||||
(grpc_gcp_identity*)var->data)) |
||||
return false; |
||||
var = var->next; |
||||
} |
||||
return true; |
||||
} |
||||
|
||||
bool encode_repeated_string_cb(pb_ostream_t* stream, const pb_field_t* field, |
||||
void* const* arg) { |
||||
repeated_field* var = static_cast<repeated_field*>(*arg); |
||||
while (var != nullptr) { |
||||
if (!pb_encode_tag_for_field(stream, field)) return false; |
||||
const grpc_slice* slice = static_cast<const grpc_slice*>(var->data); |
||||
if (!pb_encode_string(stream, GRPC_SLICE_START_PTR(*slice), |
||||
GRPC_SLICE_LENGTH(*slice))) |
||||
return false; |
||||
var = var->next; |
||||
} |
||||
return true; |
||||
} |
||||
|
||||
bool decode_string_or_bytes_cb(pb_istream_t* stream, const pb_field_t* field, |
||||
void** arg) { |
||||
grpc_slice slice = grpc_slice_malloc(stream->bytes_left); |
||||
grpc_slice* cb_slice = |
||||
static_cast<grpc_slice*>(gpr_zalloc(sizeof(*cb_slice))); |
||||
memcpy(cb_slice, &slice, sizeof(*cb_slice)); |
||||
if (!pb_read(stream, GRPC_SLICE_START_PTR(*cb_slice), stream->bytes_left)) |
||||
return false; |
||||
*arg = cb_slice; |
||||
return true; |
||||
} |
||||
|
||||
bool decode_repeated_identity_cb(pb_istream_t* stream, const pb_field_t* field, |
||||
void** arg) { |
||||
grpc_gcp_identity* identity = |
||||
static_cast<grpc_gcp_identity*>(gpr_zalloc(sizeof(*identity))); |
||||
identity->hostname.funcs.decode = decode_string_or_bytes_cb; |
||||
identity->service_account.funcs.decode = decode_string_or_bytes_cb; |
||||
add_repeated_field(reinterpret_cast<repeated_field**>(arg), identity); |
||||
if (!pb_decode(stream, grpc_gcp_Identity_fields, identity)) return false; |
||||
return true; |
||||
} |
||||
|
||||
bool decode_repeated_string_cb(pb_istream_t* stream, const pb_field_t* field, |
||||
void** arg) { |
||||
grpc_slice slice = grpc_slice_malloc(stream->bytes_left); |
||||
grpc_slice* cb_slice = |
||||
static_cast<grpc_slice*>(gpr_zalloc(sizeof(*cb_slice))); |
||||
memcpy(cb_slice, &slice, sizeof(grpc_slice)); |
||||
if (!pb_read(stream, GRPC_SLICE_START_PTR(*cb_slice), stream->bytes_left)) |
||||
return false; |
||||
add_repeated_field(reinterpret_cast<repeated_field**>(arg), cb_slice); |
||||
return true; |
||||
} |
@ -0,0 +1,149 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2018 gRPC authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
* |
||||
*/ |
||||
|
||||
#ifndef GRPC_CORE_TSI_ALTS_HANDSHAKER_ALTS_HANDSHAKER_SERVICE_API_UTIL_H |
||||
#define GRPC_CORE_TSI_ALTS_HANDSHAKER_ALTS_HANDSHAKER_SERVICE_API_UTIL_H |
||||
|
||||
#include <grpc/support/port_platform.h> |
||||
|
||||
#include "third_party/nanopb/pb_decode.h" |
||||
#include "third_party/nanopb/pb_encode.h" |
||||
|
||||
#include <grpc/slice.h> |
||||
#include <grpc/slice_buffer.h> |
||||
#include <grpc/support/alloc.h> |
||||
#include <grpc/support/log.h> |
||||
|
||||
#include "src/core/tsi/alts/handshaker/handshaker.pb.h" |
||||
|
||||
/**
|
||||
* An implementation of utility functions used to serialize/ |
||||
* de-serialize ALTS handshake requests/responses. All APIs in the header |
||||
* are thread-compatible. |
||||
*/ |
||||
|
||||
/* Renaming of message/field structs generated by nanopb compiler. */ |
||||
typedef grpc_gcp_HandshakeProtocol grpc_gcp_handshake_protocol; |
||||
typedef grpc_gcp_NetworkProtocol grpc_gcp_network_protocol; |
||||
typedef grpc_gcp_Identity grpc_gcp_identity; |
||||
typedef grpc_gcp_NextHandshakeMessageReq grpc_gcp_next_handshake_message_req; |
||||
typedef grpc_gcp_ServerHandshakeParameters grpc_gcp_server_handshake_parameters; |
||||
typedef grpc_gcp_Endpoint grpc_gcp_endpoint; |
||||
typedef grpc_gcp_StartServerHandshakeReq_HandshakeParametersEntry |
||||
grpc_gcp_handshake_parameters_entry; |
||||
typedef grpc_gcp_StartClientHandshakeReq grpc_gcp_start_client_handshake_req; |
||||
typedef grpc_gcp_StartServerHandshakeReq grpc_gcp_start_server_handshake_req; |
||||
typedef grpc_gcp_HandshakerReq grpc_gcp_handshaker_req; |
||||
typedef grpc_gcp_HandshakerResult grpc_gcp_handshaker_result; |
||||
typedef grpc_gcp_HandshakerStatus grpc_gcp_handshaker_status; |
||||
typedef grpc_gcp_HandshakerResp grpc_gcp_handshaker_resp; |
||||
|
||||
typedef enum { |
||||
CLIENT_START_REQ = 0, /* StartClientHandshakeReq. */ |
||||
SERVER_START_REQ = 1, /* StartServerHandshakeReq. */ |
||||
NEXT_REQ = 2, /* NextHandshakeMessageReq. */ |
||||
} grpc_gcp_handshaker_req_type; |
||||
|
||||
/**
|
||||
* A struct representing a repeated field. The struct is used to organize all |
||||
* instances of a specific repeated field into a linked list, which then will |
||||
* be used at encode/decode phase. For instance at the encode phase, the encode |
||||
* function will iterate through the list, encode each field, and then output |
||||
* the result to the stream. |
||||
*/ |
||||
typedef struct repeated_field_ { |
||||
struct repeated_field_* next; |
||||
const void* data; |
||||
} repeated_field; |
||||
|
||||
/**
|
||||
* This method adds a repeated field to the head of repeated field list. |
||||
* |
||||
* - head: a head of repeated field list. |
||||
* - field: a repeated field to be added to the list. |
||||
*/ |
||||
void add_repeated_field(repeated_field** head, const void* field); |
||||
|
||||
/**
|
||||
* This method destroys a repeated field list that consists of string type |
||||
* fields. |
||||
* |
||||
* - head: a head of repeated field list. |
||||
*/ |
||||
void destroy_repeated_field_list_string(repeated_field* head); |
||||
|
||||
/**
|
||||
* This method destroys a repeated field list that consists of |
||||
* grpc_gcp_identity type fields. |
||||
* |
||||
* - head: a head of repeated field list. |
||||
*/ |
||||
void destroy_repeated_field_list_identity(repeated_field* head); |
||||
|
||||
/**
|
||||
* This method creates a grpc_slice instance by copying a data buffer. It is |
||||
* similar to grpc_slice_from_copied_buffer() except that it returns an instance |
||||
* allocated from the heap. |
||||
* |
||||
* - data: a data buffer to be copied to grpc_slice instance. |
||||
* - size: size of data buffer. |
||||
*/ |
||||
grpc_slice* create_slice(const char* data, size_t size); |
||||
|
||||
/* This method destroys a grpc_slice instance. */ |
||||
void destroy_slice(grpc_slice* slice); |
||||
|
||||
/**
|
||||
* The following encode/decode functions will be assigned to encode/decode |
||||
* function pointers of pb_callback_t struct (defined in |
||||
* //third_party/nanopb/pb.h), that represent a repeated field with a dynamic
|
||||
* length (e.g., a string type or repeated field). |
||||
*/ |
||||
|
||||
/* This method is an encode callback function for a string or byte array. */ |
||||
bool encode_string_or_bytes_cb(pb_ostream_t* stream, const pb_field_t* field, |
||||
void* const* arg); |
||||
|
||||
/**
|
||||
* This method is an encode callback function for a repeated grpc_gcp_identity |
||||
* field. |
||||
*/ |
||||
bool encode_repeated_identity_cb(pb_ostream_t* stream, const pb_field_t* field, |
||||
void* const* arg); |
||||
|
||||
/* This method is an encode callback function for a repeated string field. */ |
||||
bool encode_repeated_string_cb(pb_ostream_t* stream, const pb_field_t* field, |
||||
void* const* arg); |
||||
|
||||
/**
|
||||
* This method is a decode callback function for a string or byte array field. |
||||
*/ |
||||
bool decode_string_or_bytes_cb(pb_istream_t* stream, const pb_field_t* field, |
||||
void** arg); |
||||
/**
|
||||
* This method is a decode callback function for a repeated grpc_gcp_identity |
||||
* field. |
||||
*/ |
||||
bool decode_repeated_identity_cb(pb_istream_t* stream, const pb_field_t* field, |
||||
void** arg); |
||||
|
||||
/* This method is a decode callback function for a repeated string field. */ |
||||
bool decode_repeated_string_cb(pb_istream_t* stream, const pb_field_t* field, |
||||
void** arg); |
||||
|
||||
#endif /* GRPC_CORE_TSI_ALTS_HANDSHAKER_ALTS_HANDSHAKER_SERVICE_API_UTIL_H */ |
@ -0,0 +1,73 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2018 gRPC authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
* |
||||
*/ |
||||
|
||||
#include <grpc/support/port_platform.h> |
||||
|
||||
#include "src/core/tsi/alts/handshaker/alts_tsi_event.h" |
||||
|
||||
#include <grpc/grpc.h> |
||||
#include <grpc/support/alloc.h> |
||||
#include <grpc/support/log.h> |
||||
|
||||
tsi_result alts_tsi_event_create(alts_tsi_handshaker* handshaker, |
||||
tsi_handshaker_on_next_done_cb cb, |
||||
void* user_data, |
||||
grpc_alts_credentials_options* options, |
||||
grpc_slice target_name, |
||||
alts_tsi_event** event) { |
||||
if (event == nullptr || handshaker == nullptr || cb == nullptr) { |
||||
gpr_log(GPR_ERROR, "Invalid arguments to alts_tsi_event_create()"); |
||||
return TSI_INVALID_ARGUMENT; |
||||
} |
||||
alts_tsi_event* e = static_cast<alts_tsi_event*>(gpr_zalloc(sizeof(*e))); |
||||
e->handshaker = handshaker; |
||||
e->cb = cb; |
||||
e->user_data = user_data; |
||||
e->options = grpc_alts_credentials_options_copy(options); |
||||
e->target_name = grpc_slice_copy(target_name); |
||||
grpc_metadata_array_init(&e->initial_metadata); |
||||
grpc_metadata_array_init(&e->trailing_metadata); |
||||
*event = e; |
||||
return TSI_OK; |
||||
} |
||||
|
||||
void alts_tsi_event_dispatch_to_handshaker(alts_tsi_event* event, bool is_ok) { |
||||
if (event == nullptr) { |
||||
gpr_log( |
||||
GPR_ERROR, |
||||
"ALTS TSI event is nullptr in alts_tsi_event_dispatch_to_handshaker()"); |
||||
return; |
||||
} |
||||
alts_tsi_handshaker_handle_response(event->handshaker, event->recv_buffer, |
||||
event->status, &event->details, event->cb, |
||||
event->user_data, is_ok); |
||||
} |
||||
|
||||
void alts_tsi_event_destroy(alts_tsi_event* event) { |
||||
if (event == nullptr) { |
||||
return; |
||||
} |
||||
grpc_byte_buffer_destroy(event->send_buffer); |
||||
grpc_byte_buffer_destroy(event->recv_buffer); |
||||
grpc_metadata_array_destroy(&event->initial_metadata); |
||||
grpc_metadata_array_destroy(&event->trailing_metadata); |
||||
grpc_slice_unref(event->details); |
||||
grpc_slice_unref(event->target_name); |
||||
grpc_alts_credentials_options_destroy(event->options); |
||||
gpr_free(event); |
||||
} |
@ -0,0 +1,93 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2018 gRPC authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
* |
||||
*/ |
||||
|
||||
#ifndef GRPC_CORE_TSI_ALTS_HANDSHAKER_ALTS_TSI_EVENT_H |
||||
#define GRPC_CORE_TSI_ALTS_HANDSHAKER_ALTS_TSI_EVENT_H |
||||
|
||||
#include <grpc/support/port_platform.h> |
||||
|
||||
#include <grpc/byte_buffer.h> |
||||
#include <grpc/byte_buffer_reader.h> |
||||
|
||||
#include "src/core/tsi/alts/handshaker/alts_tsi_handshaker.h" |
||||
#include "src/core/tsi/transport_security_interface.h" |
||||
|
||||
/**
|
||||
* A ALTS TSI event interface. In asynchronous implementation of |
||||
* tsi_handshaker_next(), the function will exit after scheduling a handshaker |
||||
* request to ALTS handshaker service without waiting for response to return. |
||||
* The event is used to link the scheduled handshaker request with the |
||||
* corresponding response so that enough context information can be inferred |
||||
* from it to handle the response. All APIs in the header are thread-compatible. |
||||
*/ |
||||
|
||||
/**
|
||||
* Main struct for ALTS TSI event. It retains ownership on send_buffer and |
||||
* recv_buffer, but not on handshaker. |
||||
*/ |
||||
typedef struct alts_tsi_event { |
||||
alts_tsi_handshaker* handshaker; |
||||
grpc_byte_buffer* send_buffer; |
||||
grpc_byte_buffer* recv_buffer; |
||||
grpc_status_code status; |
||||
grpc_slice details; |
||||
grpc_metadata_array initial_metadata; |
||||
grpc_metadata_array trailing_metadata; |
||||
tsi_handshaker_on_next_done_cb cb; |
||||
void* user_data; |
||||
grpc_alts_credentials_options* options; |
||||
grpc_slice target_name; |
||||
} alts_tsi_event; |
||||
|
||||
/**
|
||||
* This method creates a ALTS TSI event. |
||||
* |
||||
* - handshaker: ALTS TSI handshaker instance associated with the event to be |
||||
* created. The created event does not own the handshaker instance. |
||||
* - cb: callback function to be called when handling data received from ALTS |
||||
* handshaker service. |
||||
* - user_data: argument to callback function. |
||||
* - options: ALTS credentials options. |
||||
* - target_name: name of endpoint used for secure naming check. |
||||
* - event: address of ALTS TSI event instance to be returned from the method. |
||||
* |
||||
* It returns TSI_OK on success and an error status code on failure. |
||||
*/ |
||||
tsi_result alts_tsi_event_create(alts_tsi_handshaker* handshaker, |
||||
tsi_handshaker_on_next_done_cb cb, |
||||
void* user_data, |
||||
grpc_alts_credentials_options* options, |
||||
grpc_slice target_name, |
||||
alts_tsi_event** event); |
||||
|
||||
/**
|
||||
* This method dispatches a ALTS TSI event received from the handshaker service, |
||||
* and a boolean flag indicating if the event is valid to read to ALTS TSI |
||||
* handshaker to process. It is called by TSI thread. |
||||
* |
||||
* - event: ALTS TSI event instance. |
||||
* - is_ok: a boolean value indicating if the event is valid to read. |
||||
*/ |
||||
void alts_tsi_event_dispatch_to_handshaker(alts_tsi_event* event, bool is_ok); |
||||
|
||||
/**
|
||||
* This method destroys the ALTS TSI event. |
||||
*/ |
||||
void alts_tsi_event_destroy(alts_tsi_event* event); |
||||
|
||||
#endif /* GRPC_CORE_TSI_ALTS_HANDSHAKER_ALTS_TSI_EVENT_H */ |
@ -0,0 +1,483 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2018 gRPC authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
* |
||||
*/ |
||||
|
||||
#include <grpc/support/port_platform.h> |
||||
|
||||
#include "src/core/tsi/alts/handshaker/alts_tsi_handshaker.h" |
||||
|
||||
#include <stdio.h> |
||||
#include <stdlib.h> |
||||
#include <string.h> |
||||
|
||||
#include <grpc/support/alloc.h> |
||||
#include <grpc/support/log.h> |
||||
#include <grpc/support/sync.h> |
||||
#include <grpc/support/thd_id.h> |
||||
|
||||
#include "src/core/lib/gpr/host_port.h" |
||||
#include "src/core/lib/gprpp/thd.h" |
||||
#include "src/core/tsi/alts/frame_protector/alts_frame_protector.h" |
||||
#include "src/core/tsi/alts/handshaker/alts_handshaker_client.h" |
||||
#include "src/core/tsi/alts/handshaker/alts_tsi_utils.h" |
||||
#include "src/core/tsi/alts/zero_copy_frame_protector/alts_zero_copy_grpc_protector.h" |
||||
#include "src/core/tsi/alts_transport_security.h" |
||||
|
||||
#define TSI_ALTS_INITIAL_BUFFER_SIZE 256 |
||||
|
||||
static alts_shared_resource* kSharedResource = alts_get_shared_resource(); |
||||
|
||||
/* Main struct for ALTS TSI handshaker. */ |
||||
typedef struct alts_tsi_handshaker { |
||||
tsi_handshaker base; |
||||
alts_handshaker_client* client; |
||||
grpc_slice recv_bytes; |
||||
grpc_slice target_name; |
||||
unsigned char* buffer; |
||||
size_t buffer_size; |
||||
bool is_client; |
||||
bool has_sent_start_message; |
||||
grpc_alts_credentials_options* options; |
||||
} alts_tsi_handshaker; |
||||
|
||||
/* Main struct for ALTS TSI handshaker result. */ |
||||
typedef struct alts_tsi_handshaker_result { |
||||
tsi_handshaker_result base; |
||||
char* peer_identity; |
||||
char* key_data; |
||||
unsigned char* unused_bytes; |
||||
size_t unused_bytes_size; |
||||
grpc_slice rpc_versions; |
||||
bool is_client; |
||||
} alts_tsi_handshaker_result; |
||||
|
||||
static tsi_result handshaker_result_extract_peer( |
||||
const tsi_handshaker_result* self, tsi_peer* peer) { |
||||
if (self == nullptr || peer == nullptr) { |
||||
gpr_log(GPR_ERROR, "Invalid argument to handshaker_result_extract_peer()"); |
||||
return TSI_INVALID_ARGUMENT; |
||||
} |
||||
alts_tsi_handshaker_result* result = |
||||
reinterpret_cast<alts_tsi_handshaker_result*>( |
||||
const_cast<tsi_handshaker_result*>(self)); |
||||
GPR_ASSERT(kTsiAltsNumOfPeerProperties == 3); |
||||
tsi_result ok = tsi_construct_peer(kTsiAltsNumOfPeerProperties, peer); |
||||
int index = 0; |
||||
if (ok != TSI_OK) { |
||||
gpr_log(GPR_ERROR, "Failed to construct tsi peer"); |
||||
return ok; |
||||
} |
||||
GPR_ASSERT(&peer->properties[index] != nullptr); |
||||
ok = tsi_construct_string_peer_property_from_cstring( |
||||
TSI_CERTIFICATE_TYPE_PEER_PROPERTY, TSI_ALTS_CERTIFICATE_TYPE, |
||||
&peer->properties[index]); |
||||
if (ok != TSI_OK) { |
||||
tsi_peer_destruct(peer); |
||||
gpr_log(GPR_ERROR, "Failed to set tsi peer property"); |
||||
return ok; |
||||
} |
||||
index++; |
||||
GPR_ASSERT(&peer->properties[index] != nullptr); |
||||
ok = tsi_construct_string_peer_property_from_cstring( |
||||
TSI_ALTS_SERVICE_ACCOUNT_PEER_PROPERTY, result->peer_identity, |
||||
&peer->properties[index]); |
||||
if (ok != TSI_OK) { |
||||
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( |
||||
TSI_ALTS_RPC_VERSIONS, |
||||
reinterpret_cast<char*>(GRPC_SLICE_START_PTR(result->rpc_versions)), |
||||
GRPC_SLICE_LENGTH(result->rpc_versions), &peer->properties[2]); |
||||
if (ok != TSI_OK) { |
||||
tsi_peer_destruct(peer); |
||||
gpr_log(GPR_ERROR, "Failed to set tsi peer property"); |
||||
} |
||||
GPR_ASSERT(++index == kTsiAltsNumOfPeerProperties); |
||||
return ok; |
||||
} |
||||
|
||||
static tsi_result handshaker_result_create_zero_copy_grpc_protector( |
||||
const tsi_handshaker_result* self, size_t* max_output_protected_frame_size, |
||||
tsi_zero_copy_grpc_protector** protector) { |
||||
if (self == nullptr || protector == nullptr) { |
||||
gpr_log(GPR_ERROR, |
||||
"Invalid arguments to create_zero_copy_grpc_protector()"); |
||||
return TSI_INVALID_ARGUMENT; |
||||
} |
||||
alts_tsi_handshaker_result* result = |
||||
reinterpret_cast<alts_tsi_handshaker_result*>( |
||||
const_cast<tsi_handshaker_result*>(self)); |
||||
tsi_result ok = alts_zero_copy_grpc_protector_create( |
||||
reinterpret_cast<const uint8_t*>(result->key_data), |
||||
kAltsAes128GcmRekeyKeyLength, /*is_rekey=*/true, result->is_client, |
||||
/*is_integrity_only=*/false, max_output_protected_frame_size, protector); |
||||
if (ok != TSI_OK) { |
||||
gpr_log(GPR_ERROR, "Failed to create zero-copy grpc protector"); |
||||
} |
||||
return ok; |
||||
} |
||||
|
||||
static tsi_result handshaker_result_create_frame_protector( |
||||
const tsi_handshaker_result* self, size_t* max_output_protected_frame_size, |
||||
tsi_frame_protector** protector) { |
||||
if (self == nullptr || protector == nullptr) { |
||||
gpr_log(GPR_ERROR, |
||||
"Invalid arguments to handshaker_result_create_frame_protector()"); |
||||
return TSI_INVALID_ARGUMENT; |
||||
} |
||||
alts_tsi_handshaker_result* result = |
||||
reinterpret_cast<alts_tsi_handshaker_result*>( |
||||
const_cast<tsi_handshaker_result*>(self)); |
||||
tsi_result ok = alts_create_frame_protector( |
||||
reinterpret_cast<const uint8_t*>(result->key_data), |
||||
kAltsAes128GcmRekeyKeyLength, result->is_client, /*is_rekey=*/true, |
||||
max_output_protected_frame_size, protector); |
||||
if (ok != TSI_OK) { |
||||
gpr_log(GPR_ERROR, "Failed to create frame protector"); |
||||
} |
||||
return ok; |
||||
} |
||||
|
||||
static tsi_result handshaker_result_get_unused_bytes( |
||||
const tsi_handshaker_result* self, const unsigned char** bytes, |
||||
size_t* bytes_size) { |
||||
if (self == nullptr || bytes == nullptr || bytes_size == nullptr) { |
||||
gpr_log(GPR_ERROR, |
||||
"Invalid arguments to handshaker_result_get_unused_bytes()"); |
||||
return TSI_INVALID_ARGUMENT; |
||||
} |
||||
alts_tsi_handshaker_result* result = |
||||
reinterpret_cast<alts_tsi_handshaker_result*>( |
||||
const_cast<tsi_handshaker_result*>(self)); |
||||
*bytes = result->unused_bytes; |
||||
*bytes_size = result->unused_bytes_size; |
||||
return TSI_OK; |
||||
} |
||||
|
||||
static void handshaker_result_destroy(tsi_handshaker_result* self) { |
||||
if (self == nullptr) { |
||||
return; |
||||
} |
||||
alts_tsi_handshaker_result* result = |
||||
reinterpret_cast<alts_tsi_handshaker_result*>( |
||||
const_cast<tsi_handshaker_result*>(self)); |
||||
gpr_free(result->peer_identity); |
||||
gpr_free(result->key_data); |
||||
gpr_free(result->unused_bytes); |
||||
grpc_slice_unref(result->rpc_versions); |
||||
gpr_free(result); |
||||
} |
||||
|
||||
static const tsi_handshaker_result_vtable result_vtable = { |
||||
handshaker_result_extract_peer, |
||||
handshaker_result_create_zero_copy_grpc_protector, |
||||
handshaker_result_create_frame_protector, |
||||
handshaker_result_get_unused_bytes, handshaker_result_destroy}; |
||||
|
||||
static tsi_result create_handshaker_result(grpc_gcp_handshaker_resp* resp, |
||||
bool is_client, |
||||
tsi_handshaker_result** self) { |
||||
if (self == nullptr || resp == nullptr) { |
||||
gpr_log(GPR_ERROR, "Invalid arguments to create_handshaker_result()"); |
||||
return TSI_INVALID_ARGUMENT; |
||||
} |
||||
grpc_slice* key = static_cast<grpc_slice*>(resp->result.key_data.arg); |
||||
GPR_ASSERT(key != nullptr); |
||||
grpc_slice* identity = |
||||
static_cast<grpc_slice*>(resp->result.peer_identity.service_account.arg); |
||||
if (identity == nullptr) { |
||||
gpr_log(GPR_ERROR, "Invalid service account"); |
||||
return TSI_FAILED_PRECONDITION; |
||||
} |
||||
if (GRPC_SLICE_LENGTH(*key) < kAltsAes128GcmRekeyKeyLength) { |
||||
gpr_log(GPR_ERROR, "Bad key length"); |
||||
return TSI_FAILED_PRECONDITION; |
||||
} |
||||
alts_tsi_handshaker_result* result = |
||||
static_cast<alts_tsi_handshaker_result*>(gpr_zalloc(sizeof(*result))); |
||||
result->key_data = |
||||
static_cast<char*>(gpr_zalloc(kAltsAes128GcmRekeyKeyLength)); |
||||
memcpy(result->key_data, GRPC_SLICE_START_PTR(*key), |
||||
kAltsAes128GcmRekeyKeyLength); |
||||
result->peer_identity = grpc_slice_to_c_string(*identity); |
||||
if (!resp->result.has_peer_rpc_versions) { |
||||
gpr_log(GPR_ERROR, "Peer does not set RPC protocol versions."); |
||||
return TSI_FAILED_PRECONDITION; |
||||
} |
||||
if (!grpc_gcp_rpc_protocol_versions_encode(&resp->result.peer_rpc_versions, |
||||
&result->rpc_versions)) { |
||||
gpr_log(GPR_ERROR, "Failed to serialize peer's RPC protocol versions."); |
||||
return TSI_FAILED_PRECONDITION; |
||||
} |
||||
result->is_client = is_client; |
||||
result->base.vtable = &result_vtable; |
||||
*self = &result->base; |
||||
return TSI_OK; |
||||
} |
||||
|
||||
static tsi_result handshaker_next( |
||||
tsi_handshaker* self, const unsigned char* received_bytes, |
||||
size_t received_bytes_size, const unsigned char** bytes_to_send, |
||||
size_t* bytes_to_send_size, tsi_handshaker_result** result, |
||||
tsi_handshaker_on_next_done_cb cb, void* user_data) { |
||||
if (self == nullptr || cb == nullptr) { |
||||
gpr_log(GPR_ERROR, "Invalid arguments to handshaker_next()"); |
||||
return TSI_INVALID_ARGUMENT; |
||||
} |
||||
alts_tsi_handshaker* handshaker = |
||||
reinterpret_cast<alts_tsi_handshaker*>(self); |
||||
tsi_result ok = TSI_OK; |
||||
alts_tsi_event* event = nullptr; |
||||
ok = alts_tsi_event_create(handshaker, cb, user_data, handshaker->options, |
||||
handshaker->target_name, &event); |
||||
if (ok != TSI_OK) { |
||||
gpr_log(GPR_ERROR, "Failed to create ALTS TSI event"); |
||||
return ok; |
||||
} |
||||
grpc_slice slice = (received_bytes == nullptr || received_bytes_size == 0) |
||||
? grpc_empty_slice() |
||||
: grpc_slice_from_copied_buffer( |
||||
reinterpret_cast<const char*>(received_bytes), |
||||
received_bytes_size); |
||||
if (!handshaker->has_sent_start_message) { |
||||
ok = handshaker->is_client |
||||
? alts_handshaker_client_start_client(handshaker->client, event) |
||||
: alts_handshaker_client_start_server(handshaker->client, event, |
||||
&slice); |
||||
handshaker->has_sent_start_message = true; |
||||
} else { |
||||
if (!GRPC_SLICE_IS_EMPTY(handshaker->recv_bytes)) { |
||||
grpc_slice_unref(handshaker->recv_bytes); |
||||
} |
||||
handshaker->recv_bytes = grpc_slice_ref(slice); |
||||
ok = alts_handshaker_client_next(handshaker->client, event, &slice); |
||||
} |
||||
grpc_slice_unref(slice); |
||||
if (ok != TSI_OK) { |
||||
gpr_log(GPR_ERROR, "Failed to schedule ALTS handshaker requests"); |
||||
return ok; |
||||
} |
||||
return TSI_ASYNC; |
||||
} |
||||
|
||||
static void handshaker_destroy(tsi_handshaker* self) { |
||||
if (self == nullptr) { |
||||
return; |
||||
} |
||||
alts_tsi_handshaker* handshaker = |
||||
reinterpret_cast<alts_tsi_handshaker*>(self); |
||||
alts_handshaker_client_destroy(handshaker->client); |
||||
grpc_slice_unref(handshaker->recv_bytes); |
||||
grpc_slice_unref(handshaker->target_name); |
||||
grpc_alts_credentials_options_destroy(handshaker->options); |
||||
gpr_free(handshaker->buffer); |
||||
gpr_free(handshaker); |
||||
} |
||||
|
||||
static const tsi_handshaker_vtable handshaker_vtable = { |
||||
nullptr, nullptr, nullptr, nullptr, nullptr, handshaker_destroy, |
||||
handshaker_next}; |
||||
|
||||
static void thread_worker(void* arg) { |
||||
while (true) { |
||||
grpc_event event = grpc_completion_queue_next( |
||||
kSharedResource->cq, gpr_inf_future(GPR_CLOCK_REALTIME), nullptr); |
||||
GPR_ASSERT(event.type != GRPC_QUEUE_TIMEOUT); |
||||
if (event.type == GRPC_QUEUE_SHUTDOWN) { |
||||
/* signal alts_tsi_shutdown() to destroy completion queue. */ |
||||
grpc_tsi_alts_signal_for_cq_destroy(); |
||||
break; |
||||
} |
||||
/* event.type == GRPC_OP_COMPLETE. */ |
||||
alts_tsi_event* alts_event = static_cast<alts_tsi_event*>(event.tag); |
||||
alts_tsi_event_dispatch_to_handshaker(alts_event, event.success); |
||||
alts_tsi_event_destroy(alts_event); |
||||
} |
||||
} |
||||
|
||||
static void init_shared_resources(const char* handshaker_service_url) { |
||||
GPR_ASSERT(handshaker_service_url != nullptr); |
||||
gpr_mu_lock(&kSharedResource->mu); |
||||
if (kSharedResource->channel == nullptr) { |
||||
gpr_cv_init(&kSharedResource->cv); |
||||
kSharedResource->channel = |
||||
grpc_insecure_channel_create(handshaker_service_url, nullptr, nullptr); |
||||
kSharedResource->cq = grpc_completion_queue_create_for_next(nullptr); |
||||
kSharedResource->thread = |
||||
grpc_core::Thread("alts_tsi_handshaker", &thread_worker, nullptr); |
||||
kSharedResource->thread.Start(); |
||||
} |
||||
gpr_mu_unlock(&kSharedResource->mu); |
||||
} |
||||
|
||||
tsi_result alts_tsi_handshaker_create( |
||||
const grpc_alts_credentials_options* options, const char* target_name, |
||||
const char* handshaker_service_url, bool is_client, tsi_handshaker** self) { |
||||
if (handshaker_service_url == nullptr || self == nullptr || |
||||
options == nullptr || (is_client && target_name == nullptr)) { |
||||
gpr_log(GPR_ERROR, "Invalid arguments to alts_tsi_handshaker_create()"); |
||||
return TSI_INVALID_ARGUMENT; |
||||
} |
||||
init_shared_resources(handshaker_service_url); |
||||
alts_handshaker_client* client = alts_grpc_handshaker_client_create( |
||||
kSharedResource->channel, kSharedResource->cq, handshaker_service_url); |
||||
if (client == nullptr) { |
||||
gpr_log(GPR_ERROR, "Failed to create ALTS handshaker client"); |
||||
return TSI_FAILED_PRECONDITION; |
||||
} |
||||
alts_tsi_handshaker* handshaker = |
||||
static_cast<alts_tsi_handshaker*>(gpr_zalloc(sizeof(*handshaker))); |
||||
handshaker->client = client; |
||||
handshaker->buffer_size = TSI_ALTS_INITIAL_BUFFER_SIZE; |
||||
handshaker->buffer = |
||||
static_cast<unsigned char*>(gpr_zalloc(handshaker->buffer_size)); |
||||
handshaker->is_client = is_client; |
||||
handshaker->has_sent_start_message = false; |
||||
handshaker->target_name = target_name == nullptr |
||||
? grpc_empty_slice() |
||||
: grpc_slice_from_static_string(target_name); |
||||
handshaker->options = grpc_alts_credentials_options_copy(options); |
||||
handshaker->base.vtable = &handshaker_vtable; |
||||
*self = &handshaker->base; |
||||
return TSI_OK; |
||||
} |
||||
|
||||
static bool is_handshake_finished_properly(grpc_gcp_handshaker_resp* resp) { |
||||
GPR_ASSERT(resp != nullptr); |
||||
if (resp->has_result) { |
||||
return true; |
||||
} |
||||
return false; |
||||
} |
||||
|
||||
static void set_unused_bytes(tsi_handshaker_result* self, |
||||
grpc_slice* recv_bytes, size_t bytes_consumed) { |
||||
GPR_ASSERT(recv_bytes != nullptr && self != nullptr); |
||||
if (GRPC_SLICE_LENGTH(*recv_bytes) == bytes_consumed) { |
||||
return; |
||||
} |
||||
alts_tsi_handshaker_result* result = |
||||
reinterpret_cast<alts_tsi_handshaker_result*>(self); |
||||
result->unused_bytes_size = GRPC_SLICE_LENGTH(*recv_bytes) - bytes_consumed; |
||||
result->unused_bytes = |
||||
static_cast<unsigned char*>(gpr_zalloc(result->unused_bytes_size)); |
||||
memcpy(result->unused_bytes, |
||||
GRPC_SLICE_START_PTR(*recv_bytes) + bytes_consumed, |
||||
result->unused_bytes_size); |
||||
} |
||||
|
||||
void alts_tsi_handshaker_handle_response(alts_tsi_handshaker* handshaker, |
||||
grpc_byte_buffer* recv_buffer, |
||||
grpc_status_code status, |
||||
grpc_slice* details, |
||||
tsi_handshaker_on_next_done_cb cb, |
||||
void* user_data, bool is_ok) { |
||||
/* Invalid input check. */ |
||||
if (cb == nullptr) { |
||||
gpr_log(GPR_ERROR, |
||||
"cb is nullptr in alts_tsi_handshaker_handle_response()"); |
||||
return; |
||||
} |
||||
if (handshaker == nullptr || recv_buffer == nullptr) { |
||||
gpr_log(GPR_ERROR, |
||||
"Invalid arguments to alts_tsi_handshaker_handle_response()"); |
||||
cb(TSI_INTERNAL_ERROR, user_data, nullptr, 0, nullptr); |
||||
return; |
||||
} |
||||
/* Failed grpc call check. */ |
||||
if (!is_ok || status != GRPC_STATUS_OK) { |
||||
gpr_log(GPR_ERROR, "grpc call made to handshaker service failed"); |
||||
if (details != nullptr) { |
||||
char* error_details = grpc_slice_to_c_string(*details); |
||||
gpr_log(GPR_ERROR, "error details:%s", error_details); |
||||
gpr_free(error_details); |
||||
} |
||||
cb(TSI_INTERNAL_ERROR, user_data, nullptr, 0, nullptr); |
||||
return; |
||||
} |
||||
grpc_gcp_handshaker_resp* resp = |
||||
alts_tsi_utils_deserialize_response(recv_buffer); |
||||
/* Invalid handshaker response check. */ |
||||
if (resp == nullptr) { |
||||
gpr_log(GPR_ERROR, "alts_tsi_utils_deserialize_response() failed"); |
||||
cb(TSI_DATA_CORRUPTED, user_data, nullptr, 0, nullptr); |
||||
return; |
||||
} |
||||
grpc_slice* slice = static_cast<grpc_slice*>(resp->out_frames.arg); |
||||
unsigned char* bytes_to_send = nullptr; |
||||
size_t bytes_to_send_size = 0; |
||||
if (slice != nullptr) { |
||||
bytes_to_send_size = GRPC_SLICE_LENGTH(*slice); |
||||
while (bytes_to_send_size > handshaker->buffer_size) { |
||||
handshaker->buffer_size *= 2; |
||||
handshaker->buffer = static_cast<unsigned char*>( |
||||
gpr_realloc(handshaker->buffer, handshaker->buffer_size)); |
||||
} |
||||
memcpy(handshaker->buffer, GRPC_SLICE_START_PTR(*slice), |
||||
bytes_to_send_size); |
||||
bytes_to_send = handshaker->buffer; |
||||
} |
||||
tsi_handshaker_result* result = nullptr; |
||||
if (is_handshake_finished_properly(resp)) { |
||||
create_handshaker_result(resp, handshaker->is_client, &result); |
||||
set_unused_bytes(result, &handshaker->recv_bytes, resp->bytes_consumed); |
||||
} |
||||
grpc_status_code code = static_cast<grpc_status_code>(resp->status.code); |
||||
grpc_gcp_handshaker_resp_destroy(resp); |
||||
cb(alts_tsi_utils_convert_to_tsi_result(code), user_data, bytes_to_send, |
||||
bytes_to_send_size, result); |
||||
} |
||||
|
||||
namespace grpc_core { |
||||
namespace internal { |
||||
|
||||
bool alts_tsi_handshaker_get_has_sent_start_message_for_testing( |
||||
alts_tsi_handshaker* handshaker) { |
||||
GPR_ASSERT(handshaker != nullptr); |
||||
return handshaker->has_sent_start_message; |
||||
} |
||||
|
||||
bool alts_tsi_handshaker_get_is_client_for_testing( |
||||
alts_tsi_handshaker* handshaker) { |
||||
GPR_ASSERT(handshaker != nullptr); |
||||
return handshaker->is_client; |
||||
} |
||||
|
||||
void alts_tsi_handshaker_set_recv_bytes_for_testing( |
||||
alts_tsi_handshaker* handshaker, grpc_slice* slice) { |
||||
GPR_ASSERT(handshaker != nullptr && slice != nullptr); |
||||
handshaker->recv_bytes = grpc_slice_ref(*slice); |
||||
} |
||||
|
||||
grpc_slice alts_tsi_handshaker_get_recv_bytes_for_testing( |
||||
alts_tsi_handshaker* handshaker) { |
||||
GPR_ASSERT(handshaker != nullptr); |
||||
return handshaker->recv_bytes; |
||||
} |
||||
|
||||
void alts_tsi_handshaker_set_client_for_testing( |
||||
alts_tsi_handshaker* handshaker, alts_handshaker_client* client) { |
||||
GPR_ASSERT(handshaker != nullptr && client != nullptr); |
||||
alts_handshaker_client_destroy(handshaker->client); |
||||
handshaker->client = client; |
||||
} |
||||
|
||||
} // namespace internal
|
||||
} // namespace grpc_core
|
@ -0,0 +1,83 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2018 gRPC authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
* |
||||
*/ |
||||
|
||||
#ifndef GRPC_CORE_TSI_ALTS_HANDSHAKER_ALTS_TSI_HANDSHAKER_H |
||||
#define GRPC_CORE_TSI_ALTS_HANDSHAKER_ALTS_TSI_HANDSHAKER_H |
||||
|
||||
#include <grpc/support/port_platform.h> |
||||
|
||||
#include <grpc/grpc.h> |
||||
|
||||
#include "src/core/lib/security/credentials/alts/grpc_alts_credentials_options.h" |
||||
#include "src/core/tsi/alts_transport_security.h" |
||||
#include "src/core/tsi/transport_security.h" |
||||
#include "src/core/tsi/transport_security_interface.h" |
||||
|
||||
#define TSI_ALTS_SERVICE_ACCOUNT_PEER_PROPERTY "service_accont" |
||||
#define TSI_ALTS_CERTIFICATE_TYPE "ALTS" |
||||
#define TSI_ALTS_RPC_VERSIONS "rpc_versions" |
||||
|
||||
const size_t kTsiAltsNumOfPeerProperties = 3; |
||||
|
||||
/**
|
||||
* Main struct for ALTS TSI handshaker. All APIs in the header are |
||||
* thread-comptabile. |
||||
*/ |
||||
typedef struct alts_tsi_handshaker alts_tsi_handshaker; |
||||
|
||||
/**
|
||||
* This method creates a ALTS TSI handshaker instance. |
||||
* |
||||
* - options: ALTS credentials options containing information passed from TSI |
||||
* caller (e.g., rpc protocol versions). |
||||
* - target_name: the name of the endpoint that the channel is connecting to, |
||||
* and will be used for secure naming check. |
||||
* - handshaker_service_url: address of ALTS handshaker service in the format of |
||||
* "host:port". |
||||
* - is_client: boolean value indicating if the handshaker is used at the client |
||||
* (is_client = true) or server (is_client = false) side. |
||||
* - self: address of ALTS TSI handshaker instance to be returned from the |
||||
* method. |
||||
* |
||||
* It returns TSI_OK on success and an error status code on failure. |
||||
*/ |
||||
tsi_result alts_tsi_handshaker_create( |
||||
const grpc_alts_credentials_options* options, const char* target_name, |
||||
const char* handshaker_service_url, bool is_client, tsi_handshaker** self); |
||||
|
||||
/**
|
||||
* This method handles handshaker response returned from ALTS handshaker |
||||
* service. |
||||
* |
||||
* - handshaker: ALTS TSI handshaker instance. |
||||
* - recv_buffer: buffer holding data received from the handshaker service. |
||||
* - status: status of the grpc call made to the handshaker service. |
||||
* - details: error details of the grpc call made to the handshaker service. |
||||
* - cb: callback function of ALTS TSI event. |
||||
* - user_data: argument of callback function. |
||||
* - is_ok: a boolean value indicating if the handshaker response is ok to read. |
||||
* |
||||
*/ |
||||
void alts_tsi_handshaker_handle_response(alts_tsi_handshaker* handshaker, |
||||
grpc_byte_buffer* recv_buffer, |
||||
grpc_status_code status, |
||||
grpc_slice* details, |
||||
tsi_handshaker_on_next_done_cb cb, |
||||
void* user_data, bool is_ok); |
||||
|
||||
#endif /* GRPC_CORE_TSI_ALTS_HANDSHAKER_ALTS_TSI_HANDSHAKER_H */ |
@ -0,0 +1,52 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2018 gRPC authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
* |
||||
*/ |
||||
|
||||
#ifndef GRPC_CORE_TSI_ALTS_HANDSHAKER_ALTS_TSI_HANDSHAKER_PRIVATE_H |
||||
#define GRPC_CORE_TSI_ALTS_HANDSHAKER_ALTS_TSI_HANDSHAKER_PRIVATE_H |
||||
|
||||
#include <grpc/support/port_platform.h> |
||||
|
||||
#include "src/core/tsi/alts/handshaker/alts_handshaker_client.h" |
||||
|
||||
namespace grpc_core { |
||||
namespace internal { |
||||
|
||||
/**
|
||||
* Unsafe, use for testing only. It allows the caller to change the way the |
||||
* ALTS TSI handshaker schedules handshaker requests. |
||||
*/ |
||||
void alts_tsi_handshaker_set_client_for_testing(alts_tsi_handshaker* handshaker, |
||||
alts_handshaker_client* client); |
||||
|
||||
/* For testing only. */ |
||||
bool alts_tsi_handshaker_get_has_sent_start_message_for_testing( |
||||
alts_tsi_handshaker* handshaker); |
||||
|
||||
bool alts_tsi_handshaker_get_is_client_for_testing( |
||||
alts_tsi_handshaker* handshaker); |
||||
|
||||
void alts_tsi_handshaker_set_recv_bytes_for_testing( |
||||
alts_tsi_handshaker* handshaker, grpc_slice* slice); |
||||
|
||||
grpc_slice alts_tsi_handshaker_get_recv_bytes_for_testing( |
||||
alts_tsi_handshaker* handshaker); |
||||
|
||||
} // namespace internal
|
||||
} // namespace grpc_core
|
||||
|
||||
#endif /* GRPC_CORE_TSI_ALTS_HANDSHAKER_ALTS_TSI_HANDSHAKER_PRIVATE_H */ |
@ -0,0 +1,58 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2018 gRPC authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
* |
||||
*/ |
||||
|
||||
#include <grpc/support/port_platform.h> |
||||
|
||||
#include "src/core/tsi/alts/handshaker/alts_tsi_utils.h" |
||||
|
||||
#include <grpc/byte_buffer_reader.h> |
||||
|
||||
tsi_result alts_tsi_utils_convert_to_tsi_result(grpc_status_code code) { |
||||
switch (code) { |
||||
case GRPC_STATUS_OK: |
||||
return TSI_OK; |
||||
case GRPC_STATUS_UNKNOWN: |
||||
return TSI_UNKNOWN_ERROR; |
||||
case GRPC_STATUS_INVALID_ARGUMENT: |
||||
return TSI_INVALID_ARGUMENT; |
||||
case GRPC_STATUS_NOT_FOUND: |
||||
return TSI_NOT_FOUND; |
||||
case GRPC_STATUS_INTERNAL: |
||||
return TSI_INTERNAL_ERROR; |
||||
default: |
||||
return TSI_UNKNOWN_ERROR; |
||||
} |
||||
} |
||||
|
||||
grpc_gcp_handshaker_resp* alts_tsi_utils_deserialize_response( |
||||
grpc_byte_buffer* resp_buffer) { |
||||
GPR_ASSERT(resp_buffer != nullptr); |
||||
grpc_byte_buffer_reader bbr; |
||||
grpc_byte_buffer_reader_init(&bbr, resp_buffer); |
||||
grpc_slice slice = grpc_byte_buffer_reader_readall(&bbr); |
||||
grpc_gcp_handshaker_resp* resp = grpc_gcp_handshaker_resp_create(); |
||||
bool ok = grpc_gcp_handshaker_resp_decode(slice, resp); |
||||
grpc_slice_unref(slice); |
||||
grpc_byte_buffer_reader_destroy(&bbr); |
||||
if (!ok) { |
||||
grpc_gcp_handshaker_resp_destroy(resp); |
||||
gpr_log(GPR_ERROR, "grpc_gcp_handshaker_resp_decode() failed"); |
||||
return nullptr; |
||||
} |
||||
return resp; |
||||
} |
@ -0,0 +1,52 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2018 gRPC authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
* |
||||
*/ |
||||
|
||||
#ifndef GRPC_CORE_TSI_ALTS_HANDSHAKER_ALTS_TSI_UTILS_H |
||||
#define GRPC_CORE_TSI_ALTS_HANDSHAKER_ALTS_TSI_UTILS_H |
||||
|
||||
#include <grpc/support/port_platform.h> |
||||
|
||||
#include <grpc/byte_buffer.h> |
||||
#include <grpc/grpc.h> |
||||
|
||||
#include "src/core/tsi/alts/handshaker/alts_handshaker_service_api.h" |
||||
#include "src/core/tsi/transport_security_interface.h" |
||||
|
||||
/**
|
||||
* This method converts grpc_status_code code to the corresponding tsi_result |
||||
* code. |
||||
* |
||||
* - code: grpc_status_code code. |
||||
* |
||||
* It returns the converted tsi_result code. |
||||
*/ |
||||
tsi_result alts_tsi_utils_convert_to_tsi_result(grpc_status_code code); |
||||
|
||||
/**
|
||||
* This method deserializes a handshaker response returned from ALTS handshaker |
||||
* service. |
||||
* |
||||
* - bytes_received: data returned from ALTS handshaker service. |
||||
* |
||||
* It returns a deserialized handshaker response on success and nullptr on |
||||
* failure. |
||||
*/ |
||||
grpc_gcp_handshaker_resp* alts_tsi_utils_deserialize_response( |
||||
grpc_byte_buffer* resp_buffer); |
||||
|
||||
#endif /* GRPC_CORE_TSI_ALTS_HANDSHAKER_ALTS_TSI_UTILS_H */ |
@ -0,0 +1,48 @@ |
||||
/* Automatically generated nanopb constant definitions */ |
||||
/* Generated by nanopb-0.3.7-dev */ |
||||
|
||||
#include "src/core/tsi/alts/handshaker/altscontext.pb.h" |
||||
|
||||
/* @@protoc_insertion_point(includes) */ |
||||
#if PB_PROTO_HEADER_VERSION != 30 |
||||
#error Regenerate this file with the current version of nanopb generator. |
||||
#endif |
||||
|
||||
|
||||
|
||||
const pb_field_t grpc_gcp_AltsContext_fields[7] = { |
||||
PB_FIELD( 1, STRING , OPTIONAL, CALLBACK, FIRST, grpc_gcp_AltsContext, application_protocol, application_protocol, 0), |
||||
PB_FIELD( 2, STRING , OPTIONAL, CALLBACK, OTHER, grpc_gcp_AltsContext, record_protocol, application_protocol, 0), |
||||
PB_FIELD( 3, UENUM , OPTIONAL, STATIC , OTHER, grpc_gcp_AltsContext, security_level, record_protocol, 0), |
||||
PB_FIELD( 4, STRING , OPTIONAL, CALLBACK, OTHER, grpc_gcp_AltsContext, peer_service_account, security_level, 0), |
||||
PB_FIELD( 5, STRING , OPTIONAL, CALLBACK, OTHER, grpc_gcp_AltsContext, local_service_account, peer_service_account, 0), |
||||
PB_FIELD( 6, MESSAGE , OPTIONAL, STATIC , OTHER, grpc_gcp_AltsContext, peer_rpc_versions, local_service_account, &grpc_gcp_RpcProtocolVersions_fields), |
||||
PB_LAST_FIELD |
||||
}; |
||||
|
||||
|
||||
/* Check that field information fits in pb_field_t */ |
||||
#if !defined(PB_FIELD_32BIT) |
||||
/* If you get an error here, it means that you need to define PB_FIELD_32BIT
|
||||
* compile-time option. You can do that in pb.h or on compiler command line. |
||||
*
|
||||
* The reason you need to do this is that some of your messages contain tag |
||||
* numbers or field sizes that are larger than what can fit in 8 or 16 bit |
||||
* field descriptors. |
||||
*/ |
||||
PB_STATIC_ASSERT((pb_membersize(grpc_gcp_AltsContext, peer_rpc_versions) < 65536), YOU_MUST_DEFINE_PB_FIELD_32BIT_FOR_MESSAGES_grpc_gcp_AltsContext) |
||||
#endif |
||||
|
||||
#if !defined(PB_FIELD_16BIT) && !defined(PB_FIELD_32BIT) |
||||
/* If you get an error here, it means that you need to define PB_FIELD_16BIT
|
||||
* compile-time option. You can do that in pb.h or on compiler command line. |
||||
*
|
||||
* The reason you need to do this is that some of your messages contain tag |
||||
* numbers or field sizes that are larger than what can fit in the default |
||||
* 8 bit descriptors. |
||||
*/ |
||||
PB_STATIC_ASSERT((pb_membersize(grpc_gcp_AltsContext, peer_rpc_versions) < 256), YOU_MUST_DEFINE_PB_FIELD_16BIT_FOR_MESSAGES_grpc_gcp_AltsContext) |
||||
#endif |
||||
|
||||
|
||||
/* @@protoc_insertion_point(eof) */ |
@ -0,0 +1,64 @@ |
||||
/* Automatically generated nanopb header */ |
||||
/* Generated by nanopb-0.3.7-dev */ |
||||
|
||||
#ifndef PB_GRPC_GCP_ALTSCONTEXT_PB_H_INCLUDED |
||||
#define PB_GRPC_GCP_ALTSCONTEXT_PB_H_INCLUDED |
||||
#include "third_party/nanopb/pb.h" |
||||
#include "src/core/tsi/alts/handshaker/transport_security_common.pb.h" |
||||
|
||||
/* @@protoc_insertion_point(includes) */ |
||||
#if PB_PROTO_HEADER_VERSION != 30 |
||||
#error Regenerate this file with the current version of nanopb generator. |
||||
#endif |
||||
|
||||
#ifdef __cplusplus |
||||
extern "C" { |
||||
#endif |
||||
|
||||
/* Struct definitions */ |
||||
typedef struct _grpc_gcp_AltsContext { |
||||
pb_callback_t application_protocol; |
||||
pb_callback_t record_protocol; |
||||
bool has_security_level; |
||||
grpc_gcp_SecurityLevel security_level; |
||||
pb_callback_t peer_service_account; |
||||
pb_callback_t local_service_account; |
||||
bool has_peer_rpc_versions; |
||||
grpc_gcp_RpcProtocolVersions peer_rpc_versions; |
||||
/* @@protoc_insertion_point(struct:grpc_gcp_AltsContext) */ |
||||
} grpc_gcp_AltsContext; |
||||
|
||||
/* Default values for struct fields */ |
||||
|
||||
/* Initializer values for message structs */ |
||||
#define grpc_gcp_AltsContext_init_default {{{NULL}, NULL}, {{NULL}, NULL}, false, (grpc_gcp_SecurityLevel)0, {{NULL}, NULL}, {{NULL}, NULL}, false, grpc_gcp_RpcProtocolVersions_init_default} |
||||
#define grpc_gcp_AltsContext_init_zero {{{NULL}, NULL}, {{NULL}, NULL}, false, (grpc_gcp_SecurityLevel)0, {{NULL}, NULL}, {{NULL}, NULL}, false, grpc_gcp_RpcProtocolVersions_init_zero} |
||||
|
||||
/* Field tags (for use in manual encoding/decoding) */ |
||||
#define grpc_gcp_AltsContext_application_protocol_tag 1 |
||||
#define grpc_gcp_AltsContext_record_protocol_tag 2 |
||||
#define grpc_gcp_AltsContext_security_level_tag 3 |
||||
#define grpc_gcp_AltsContext_peer_service_account_tag 4 |
||||
#define grpc_gcp_AltsContext_local_service_account_tag 5 |
||||
#define grpc_gcp_AltsContext_peer_rpc_versions_tag 6 |
||||
|
||||
/* Struct field encoding specification for nanopb */ |
||||
extern const pb_field_t grpc_gcp_AltsContext_fields[7]; |
||||
|
||||
/* Maximum encoded size of messages (where known) */ |
||||
/* grpc_gcp_AltsContext_size depends on runtime parameters */ |
||||
|
||||
/* Message IDs (where set with "msgid" option) */ |
||||
#ifdef PB_MSGID |
||||
|
||||
#define ALTSCONTEXT_MESSAGES \ |
||||
|
||||
|
||||
#endif |
||||
|
||||
#ifdef __cplusplus |
||||
} /* extern "C" */ |
||||
#endif |
||||
/* @@protoc_insertion_point(eof) */ |
||||
|
||||
#endif |
@ -0,0 +1,123 @@ |
||||
/* Automatically generated nanopb constant definitions */ |
||||
/* Generated by nanopb-0.3.7-dev */ |
||||
|
||||
#include "src/core/tsi/alts/handshaker/handshaker.pb.h" |
||||
|
||||
/* @@protoc_insertion_point(includes) */ |
||||
#if PB_PROTO_HEADER_VERSION != 30 |
||||
#error Regenerate this file with the current version of nanopb generator. |
||||
#endif |
||||
|
||||
|
||||
|
||||
const pb_field_t grpc_gcp_Endpoint_fields[4] = { |
||||
PB_FIELD( 1, STRING , OPTIONAL, CALLBACK, FIRST, grpc_gcp_Endpoint, ip_address, ip_address, 0), |
||||
PB_FIELD( 2, INT32 , OPTIONAL, STATIC , OTHER, grpc_gcp_Endpoint, port, ip_address, 0), |
||||
PB_FIELD( 3, UENUM , OPTIONAL, STATIC , OTHER, grpc_gcp_Endpoint, protocol, port, 0), |
||||
PB_LAST_FIELD |
||||
}; |
||||
|
||||
const pb_field_t grpc_gcp_Identity_fields[3] = { |
||||
PB_FIELD( 1, STRING , OPTIONAL, CALLBACK, FIRST, grpc_gcp_Identity, service_account, service_account, 0), |
||||
PB_FIELD( 2, STRING , OPTIONAL, CALLBACK, OTHER, grpc_gcp_Identity, hostname, service_account, 0), |
||||
PB_LAST_FIELD |
||||
}; |
||||
|
||||
const pb_field_t grpc_gcp_StartClientHandshakeReq_fields[10] = { |
||||
PB_FIELD( 1, UENUM , OPTIONAL, STATIC , FIRST, grpc_gcp_StartClientHandshakeReq, handshake_security_protocol, handshake_security_protocol, 0), |
||||
PB_FIELD( 2, STRING , REPEATED, CALLBACK, OTHER, grpc_gcp_StartClientHandshakeReq, application_protocols, handshake_security_protocol, 0), |
||||
PB_FIELD( 3, STRING , REPEATED, CALLBACK, OTHER, grpc_gcp_StartClientHandshakeReq, record_protocols, application_protocols, 0), |
||||
PB_FIELD( 4, MESSAGE , REPEATED, CALLBACK, OTHER, grpc_gcp_StartClientHandshakeReq, target_identities, record_protocols, &grpc_gcp_Identity_fields), |
||||
PB_FIELD( 5, MESSAGE , OPTIONAL, STATIC , OTHER, grpc_gcp_StartClientHandshakeReq, local_identity, target_identities, &grpc_gcp_Identity_fields), |
||||
PB_FIELD( 6, MESSAGE , OPTIONAL, STATIC , OTHER, grpc_gcp_StartClientHandshakeReq, local_endpoint, local_identity, &grpc_gcp_Endpoint_fields), |
||||
PB_FIELD( 7, MESSAGE , OPTIONAL, STATIC , OTHER, grpc_gcp_StartClientHandshakeReq, remote_endpoint, local_endpoint, &grpc_gcp_Endpoint_fields), |
||||
PB_FIELD( 8, STRING , OPTIONAL, CALLBACK, OTHER, grpc_gcp_StartClientHandshakeReq, target_name, remote_endpoint, 0), |
||||
PB_FIELD( 9, MESSAGE , OPTIONAL, STATIC , OTHER, grpc_gcp_StartClientHandshakeReq, rpc_versions, target_name, &grpc_gcp_RpcProtocolVersions_fields), |
||||
PB_LAST_FIELD |
||||
}; |
||||
|
||||
const pb_field_t grpc_gcp_ServerHandshakeParameters_fields[3] = { |
||||
PB_FIELD( 1, STRING , REPEATED, CALLBACK, FIRST, grpc_gcp_ServerHandshakeParameters, record_protocols, record_protocols, 0), |
||||
PB_FIELD( 2, MESSAGE , REPEATED, CALLBACK, OTHER, grpc_gcp_ServerHandshakeParameters, local_identities, record_protocols, &grpc_gcp_Identity_fields), |
||||
PB_LAST_FIELD |
||||
}; |
||||
|
||||
const pb_field_t grpc_gcp_StartServerHandshakeReq_fields[7] = { |
||||
PB_FIELD( 1, STRING , REPEATED, CALLBACK, FIRST, grpc_gcp_StartServerHandshakeReq, application_protocols, application_protocols, 0), |
||||
PB_FIELD( 2, MESSAGE , REPEATED, STATIC , OTHER, grpc_gcp_StartServerHandshakeReq, handshake_parameters, application_protocols, &grpc_gcp_StartServerHandshakeReq_HandshakeParametersEntry_fields), |
||||
PB_FIELD( 3, BYTES , OPTIONAL, CALLBACK, OTHER, grpc_gcp_StartServerHandshakeReq, in_bytes, handshake_parameters, 0), |
||||
PB_FIELD( 4, MESSAGE , OPTIONAL, STATIC , OTHER, grpc_gcp_StartServerHandshakeReq, local_endpoint, in_bytes, &grpc_gcp_Endpoint_fields), |
||||
PB_FIELD( 5, MESSAGE , OPTIONAL, STATIC , OTHER, grpc_gcp_StartServerHandshakeReq, remote_endpoint, local_endpoint, &grpc_gcp_Endpoint_fields), |
||||
PB_FIELD( 6, MESSAGE , OPTIONAL, STATIC , OTHER, grpc_gcp_StartServerHandshakeReq, rpc_versions, remote_endpoint, &grpc_gcp_RpcProtocolVersions_fields), |
||||
PB_LAST_FIELD |
||||
}; |
||||
|
||||
const pb_field_t grpc_gcp_StartServerHandshakeReq_HandshakeParametersEntry_fields[3] = { |
||||
PB_FIELD( 1, INT32 , OPTIONAL, STATIC , FIRST, grpc_gcp_StartServerHandshakeReq_HandshakeParametersEntry, key, key, 0), |
||||
PB_FIELD( 2, MESSAGE , OPTIONAL, STATIC , OTHER, grpc_gcp_StartServerHandshakeReq_HandshakeParametersEntry, value, key, &grpc_gcp_ServerHandshakeParameters_fields), |
||||
PB_LAST_FIELD |
||||
}; |
||||
|
||||
const pb_field_t grpc_gcp_NextHandshakeMessageReq_fields[2] = { |
||||
PB_FIELD( 1, BYTES , OPTIONAL, CALLBACK, FIRST, grpc_gcp_NextHandshakeMessageReq, in_bytes, in_bytes, 0), |
||||
PB_LAST_FIELD |
||||
}; |
||||
|
||||
const pb_field_t grpc_gcp_HandshakerReq_fields[4] = { |
||||
PB_FIELD( 1, MESSAGE , OPTIONAL, STATIC , FIRST, grpc_gcp_HandshakerReq, client_start, client_start, &grpc_gcp_StartClientHandshakeReq_fields), |
||||
PB_FIELD( 2, MESSAGE , OPTIONAL, STATIC , OTHER, grpc_gcp_HandshakerReq, server_start, client_start, &grpc_gcp_StartServerHandshakeReq_fields), |
||||
PB_FIELD( 3, MESSAGE , OPTIONAL, STATIC , OTHER, grpc_gcp_HandshakerReq, next, server_start, &grpc_gcp_NextHandshakeMessageReq_fields), |
||||
PB_LAST_FIELD |
||||
}; |
||||
|
||||
const pb_field_t grpc_gcp_HandshakerResult_fields[8] = { |
||||
PB_FIELD( 1, STRING , OPTIONAL, CALLBACK, FIRST, grpc_gcp_HandshakerResult, application_protocol, application_protocol, 0), |
||||
PB_FIELD( 2, STRING , OPTIONAL, CALLBACK, OTHER, grpc_gcp_HandshakerResult, record_protocol, application_protocol, 0), |
||||
PB_FIELD( 3, BYTES , OPTIONAL, CALLBACK, OTHER, grpc_gcp_HandshakerResult, key_data, record_protocol, 0), |
||||
PB_FIELD( 4, MESSAGE , OPTIONAL, STATIC , OTHER, grpc_gcp_HandshakerResult, peer_identity, key_data, &grpc_gcp_Identity_fields), |
||||
PB_FIELD( 5, MESSAGE , OPTIONAL, STATIC , OTHER, grpc_gcp_HandshakerResult, local_identity, peer_identity, &grpc_gcp_Identity_fields), |
||||
PB_FIELD( 6, BOOL , OPTIONAL, STATIC , OTHER, grpc_gcp_HandshakerResult, keep_channel_open, local_identity, 0), |
||||
PB_FIELD( 7, MESSAGE , OPTIONAL, STATIC , OTHER, grpc_gcp_HandshakerResult, peer_rpc_versions, keep_channel_open, &grpc_gcp_RpcProtocolVersions_fields), |
||||
PB_LAST_FIELD |
||||
}; |
||||
|
||||
const pb_field_t grpc_gcp_HandshakerStatus_fields[3] = { |
||||
PB_FIELD( 1, UINT32 , OPTIONAL, STATIC , FIRST, grpc_gcp_HandshakerStatus, code, code, 0), |
||||
PB_FIELD( 2, STRING , OPTIONAL, CALLBACK, OTHER, grpc_gcp_HandshakerStatus, details, code, 0), |
||||
PB_LAST_FIELD |
||||
}; |
||||
|
||||
const pb_field_t grpc_gcp_HandshakerResp_fields[5] = { |
||||
PB_FIELD( 1, BYTES , OPTIONAL, CALLBACK, FIRST, grpc_gcp_HandshakerResp, out_frames, out_frames, 0), |
||||
PB_FIELD( 2, UINT32 , OPTIONAL, STATIC , OTHER, grpc_gcp_HandshakerResp, bytes_consumed, out_frames, 0), |
||||
PB_FIELD( 3, MESSAGE , OPTIONAL, STATIC , OTHER, grpc_gcp_HandshakerResp, result, bytes_consumed, &grpc_gcp_HandshakerResult_fields), |
||||
PB_FIELD( 4, MESSAGE , OPTIONAL, STATIC , OTHER, grpc_gcp_HandshakerResp, status, result, &grpc_gcp_HandshakerStatus_fields), |
||||
PB_LAST_FIELD |
||||
}; |
||||
|
||||
|
||||
/* Check that field information fits in pb_field_t */ |
||||
#if !defined(PB_FIELD_32BIT) |
||||
/* If you get an error here, it means that you need to define PB_FIELD_32BIT
|
||||
* compile-time option. You can do that in pb.h or on compiler command line. |
||||
*
|
||||
* The reason you need to do this is that some of your messages contain tag |
||||
* numbers or field sizes that are larger than what can fit in 8 or 16 bit |
||||
* field descriptors. |
||||
*/ |
||||
PB_STATIC_ASSERT((pb_membersize(grpc_gcp_StartClientHandshakeReq, target_identities) < 65536 && pb_membersize(grpc_gcp_StartClientHandshakeReq, local_identity) < 65536 && pb_membersize(grpc_gcp_StartClientHandshakeReq, local_endpoint) < 65536 && pb_membersize(grpc_gcp_StartClientHandshakeReq, remote_endpoint) < 65536 && pb_membersize(grpc_gcp_StartClientHandshakeReq, rpc_versions) < 65536 && pb_membersize(grpc_gcp_ServerHandshakeParameters, local_identities) < 65536 && pb_membersize(grpc_gcp_StartServerHandshakeReq, handshake_parameters[0]) < 65536 && pb_membersize(grpc_gcp_StartServerHandshakeReq, local_endpoint) < 65536 && pb_membersize(grpc_gcp_StartServerHandshakeReq, remote_endpoint) < 65536 && pb_membersize(grpc_gcp_StartServerHandshakeReq, rpc_versions) < 65536 && pb_membersize(grpc_gcp_StartServerHandshakeReq_HandshakeParametersEntry, value) < 65536 && pb_membersize(grpc_gcp_HandshakerReq, client_start) < 65536 && pb_membersize(grpc_gcp_HandshakerReq, server_start) < 65536 && pb_membersize(grpc_gcp_HandshakerReq, next) < 65536 && pb_membersize(grpc_gcp_HandshakerResult, peer_identity) < 65536 && pb_membersize(grpc_gcp_HandshakerResult, local_identity) < 65536 && pb_membersize(grpc_gcp_HandshakerResult, peer_rpc_versions) < 65536 && pb_membersize(grpc_gcp_HandshakerResp, result) < 65536 && pb_membersize(grpc_gcp_HandshakerResp, status) < 65536), YOU_MUST_DEFINE_PB_FIELD_32BIT_FOR_MESSAGES_grpc_gcp_Endpoint_grpc_gcp_Identity_grpc_gcp_StartClientHandshakeReq_grpc_gcp_ServerHandshakeParameters_grpc_gcp_StartServerHandshakeReq_grpc_gcp_StartServerHandshakeReq_HandshakeParametersEntry_grpc_gcp_NextHandshakeMessageReq_grpc_gcp_HandshakerReq_grpc_gcp_HandshakerResult_grpc_gcp_HandshakerStatus_grpc_gcp_HandshakerResp) |
||||
#endif |
||||
|
||||
#if !defined(PB_FIELD_16BIT) && !defined(PB_FIELD_32BIT) |
||||
/* If you get an error here, it means that you need to define PB_FIELD_16BIT
|
||||
* compile-time option. You can do that in pb.h or on compiler command line. |
||||
*
|
||||
* The reason you need to do this is that some of your messages contain tag |
||||
* numbers or field sizes that are larger than what can fit in the default |
||||
* 8 bit descriptors. |
||||
*/ |
||||
PB_STATIC_ASSERT((pb_membersize(grpc_gcp_StartClientHandshakeReq, target_identities) < 256 && pb_membersize(grpc_gcp_StartClientHandshakeReq, local_identity) < 256 && pb_membersize(grpc_gcp_StartClientHandshakeReq, local_endpoint) < 256 && pb_membersize(grpc_gcp_StartClientHandshakeReq, remote_endpoint) < 256 && pb_membersize(grpc_gcp_StartClientHandshakeReq, rpc_versions) < 256 && pb_membersize(grpc_gcp_ServerHandshakeParameters, local_identities) < 256 && pb_membersize(grpc_gcp_StartServerHandshakeReq, handshake_parameters[0]) < 256 && pb_membersize(grpc_gcp_StartServerHandshakeReq, local_endpoint) < 256 && pb_membersize(grpc_gcp_StartServerHandshakeReq, remote_endpoint) < 256 && pb_membersize(grpc_gcp_StartServerHandshakeReq, rpc_versions) < 256 && pb_membersize(grpc_gcp_StartServerHandshakeReq_HandshakeParametersEntry, value) < 256 && pb_membersize(grpc_gcp_HandshakerReq, client_start) < 256 && pb_membersize(grpc_gcp_HandshakerReq, server_start) < 256 && pb_membersize(grpc_gcp_HandshakerReq, next) < 256 && pb_membersize(grpc_gcp_HandshakerResult, peer_identity) < 256 && pb_membersize(grpc_gcp_HandshakerResult, local_identity) < 256 && pb_membersize(grpc_gcp_HandshakerResult, peer_rpc_versions) < 256 && pb_membersize(grpc_gcp_HandshakerResp, result) < 256 && pb_membersize(grpc_gcp_HandshakerResp, status) < 256), YOU_MUST_DEFINE_PB_FIELD_16BIT_FOR_MESSAGES_grpc_gcp_Endpoint_grpc_gcp_Identity_grpc_gcp_StartClientHandshakeReq_grpc_gcp_ServerHandshakeParameters_grpc_gcp_StartServerHandshakeReq_grpc_gcp_StartServerHandshakeReq_HandshakeParametersEntry_grpc_gcp_NextHandshakeMessageReq_grpc_gcp_HandshakerReq_grpc_gcp_HandshakerResult_grpc_gcp_HandshakerStatus_grpc_gcp_HandshakerResp) |
||||
#endif |
||||
|
||||
|
||||
/* @@protoc_insertion_point(eof) */ |
@ -0,0 +1,255 @@ |
||||
/* Automatically generated nanopb header */ |
||||
/* Generated by nanopb-0.3.7-dev */ |
||||
|
||||
#ifndef PB_GRPC_GCP_HANDSHAKER_PB_H_INCLUDED |
||||
#define PB_GRPC_GCP_HANDSHAKER_PB_H_INCLUDED |
||||
#include "third_party/nanopb/pb.h" |
||||
#include "src/core/tsi/alts/handshaker/transport_security_common.pb.h" |
||||
|
||||
/* @@protoc_insertion_point(includes) */ |
||||
#if PB_PROTO_HEADER_VERSION != 30 |
||||
#error Regenerate this file with the current version of nanopb generator. |
||||
#endif |
||||
|
||||
#ifdef __cplusplus |
||||
extern "C" { |
||||
#endif |
||||
|
||||
/* Enum definitions */ |
||||
typedef enum _grpc_gcp_HandshakeProtocol { |
||||
grpc_gcp_HandshakeProtocol_HANDSHAKE_PROTOCOL_UNSPECIFIED = 0, |
||||
grpc_gcp_HandshakeProtocol_TLS = 1, |
||||
grpc_gcp_HandshakeProtocol_ALTS = 2 |
||||
} grpc_gcp_HandshakeProtocol; |
||||
#define _grpc_gcp_HandshakeProtocol_MIN grpc_gcp_HandshakeProtocol_HANDSHAKE_PROTOCOL_UNSPECIFIED |
||||
#define _grpc_gcp_HandshakeProtocol_MAX grpc_gcp_HandshakeProtocol_ALTS |
||||
#define _grpc_gcp_HandshakeProtocol_ARRAYSIZE ((grpc_gcp_HandshakeProtocol)(grpc_gcp_HandshakeProtocol_ALTS+1)) |
||||
|
||||
typedef enum _grpc_gcp_NetworkProtocol { |
||||
grpc_gcp_NetworkProtocol_NETWORK_PROTOCOL_UNSPECIFIED = 0, |
||||
grpc_gcp_NetworkProtocol_TCP = 1, |
||||
grpc_gcp_NetworkProtocol_UDP = 2 |
||||
} grpc_gcp_NetworkProtocol; |
||||
#define _grpc_gcp_NetworkProtocol_MIN grpc_gcp_NetworkProtocol_NETWORK_PROTOCOL_UNSPECIFIED |
||||
#define _grpc_gcp_NetworkProtocol_MAX grpc_gcp_NetworkProtocol_UDP |
||||
#define _grpc_gcp_NetworkProtocol_ARRAYSIZE ((grpc_gcp_NetworkProtocol)(grpc_gcp_NetworkProtocol_UDP+1)) |
||||
|
||||
/* Struct definitions */ |
||||
typedef struct _grpc_gcp_Identity { |
||||
pb_callback_t service_account; |
||||
pb_callback_t hostname; |
||||
/* @@protoc_insertion_point(struct:grpc_gcp_Identity) */ |
||||
} grpc_gcp_Identity; |
||||
|
||||
typedef struct _grpc_gcp_NextHandshakeMessageReq { |
||||
pb_callback_t in_bytes; |
||||
/* @@protoc_insertion_point(struct:grpc_gcp_NextHandshakeMessageReq) */ |
||||
} grpc_gcp_NextHandshakeMessageReq; |
||||
|
||||
typedef struct _grpc_gcp_ServerHandshakeParameters { |
||||
pb_callback_t record_protocols; |
||||
pb_callback_t local_identities; |
||||
/* @@protoc_insertion_point(struct:grpc_gcp_ServerHandshakeParameters) */ |
||||
} grpc_gcp_ServerHandshakeParameters; |
||||
|
||||
typedef struct _grpc_gcp_Endpoint { |
||||
pb_callback_t ip_address; |
||||
bool has_port; |
||||
int32_t port; |
||||
bool has_protocol; |
||||
grpc_gcp_NetworkProtocol protocol; |
||||
/* @@protoc_insertion_point(struct:grpc_gcp_Endpoint) */ |
||||
} grpc_gcp_Endpoint; |
||||
|
||||
typedef struct _grpc_gcp_HandshakerResult { |
||||
pb_callback_t application_protocol; |
||||
pb_callback_t record_protocol; |
||||
pb_callback_t key_data; |
||||
bool has_peer_identity; |
||||
grpc_gcp_Identity peer_identity; |
||||
bool has_local_identity; |
||||
grpc_gcp_Identity local_identity; |
||||
bool has_keep_channel_open; |
||||
bool keep_channel_open; |
||||
bool has_peer_rpc_versions; |
||||
grpc_gcp_RpcProtocolVersions peer_rpc_versions; |
||||
/* @@protoc_insertion_point(struct:grpc_gcp_HandshakerResult) */ |
||||
} grpc_gcp_HandshakerResult; |
||||
|
||||
typedef struct _grpc_gcp_HandshakerStatus { |
||||
bool has_code; |
||||
uint32_t code; |
||||
pb_callback_t details; |
||||
/* @@protoc_insertion_point(struct:grpc_gcp_HandshakerStatus) */ |
||||
} grpc_gcp_HandshakerStatus; |
||||
|
||||
typedef struct _grpc_gcp_StartServerHandshakeReq_HandshakeParametersEntry { |
||||
bool has_key; |
||||
int32_t key; |
||||
bool has_value; |
||||
grpc_gcp_ServerHandshakeParameters value; |
||||
/* @@protoc_insertion_point(struct:grpc_gcp_StartServerHandshakeReq_HandshakeParametersEntry) */ |
||||
} grpc_gcp_StartServerHandshakeReq_HandshakeParametersEntry; |
||||
|
||||
typedef struct _grpc_gcp_HandshakerResp { |
||||
pb_callback_t out_frames; |
||||
bool has_bytes_consumed; |
||||
uint32_t bytes_consumed; |
||||
bool has_result; |
||||
grpc_gcp_HandshakerResult result; |
||||
bool has_status; |
||||
grpc_gcp_HandshakerStatus status; |
||||
/* @@protoc_insertion_point(struct:grpc_gcp_HandshakerResp) */ |
||||
} grpc_gcp_HandshakerResp; |
||||
|
||||
typedef struct _grpc_gcp_StartClientHandshakeReq { |
||||
bool has_handshake_security_protocol; |
||||
grpc_gcp_HandshakeProtocol handshake_security_protocol; |
||||
pb_callback_t application_protocols; |
||||
pb_callback_t record_protocols; |
||||
pb_callback_t target_identities; |
||||
bool has_local_identity; |
||||
grpc_gcp_Identity local_identity; |
||||
bool has_local_endpoint; |
||||
grpc_gcp_Endpoint local_endpoint; |
||||
bool has_remote_endpoint; |
||||
grpc_gcp_Endpoint remote_endpoint; |
||||
pb_callback_t target_name; |
||||
bool has_rpc_versions; |
||||
grpc_gcp_RpcProtocolVersions rpc_versions; |
||||
/* @@protoc_insertion_point(struct:grpc_gcp_StartClientHandshakeReq) */ |
||||
} grpc_gcp_StartClientHandshakeReq; |
||||
|
||||
typedef struct _grpc_gcp_StartServerHandshakeReq { |
||||
pb_callback_t application_protocols; |
||||
pb_size_t handshake_parameters_count; |
||||
grpc_gcp_StartServerHandshakeReq_HandshakeParametersEntry handshake_parameters[3]; |
||||
pb_callback_t in_bytes; |
||||
bool has_local_endpoint; |
||||
grpc_gcp_Endpoint local_endpoint; |
||||
bool has_remote_endpoint; |
||||
grpc_gcp_Endpoint remote_endpoint; |
||||
bool has_rpc_versions; |
||||
grpc_gcp_RpcProtocolVersions rpc_versions; |
||||
/* @@protoc_insertion_point(struct:grpc_gcp_StartServerHandshakeReq) */ |
||||
} grpc_gcp_StartServerHandshakeReq; |
||||
|
||||
typedef struct _grpc_gcp_HandshakerReq { |
||||
bool has_client_start; |
||||
grpc_gcp_StartClientHandshakeReq client_start; |
||||
bool has_server_start; |
||||
grpc_gcp_StartServerHandshakeReq server_start; |
||||
bool has_next; |
||||
grpc_gcp_NextHandshakeMessageReq next; |
||||
/* @@protoc_insertion_point(struct:grpc_gcp_HandshakerReq) */ |
||||
} grpc_gcp_HandshakerReq; |
||||
|
||||
/* Default values for struct fields */ |
||||
|
||||
/* Initializer values for message structs */ |
||||
#define grpc_gcp_Endpoint_init_default {{{NULL}, NULL}, false, 0, false, (grpc_gcp_NetworkProtocol)0} |
||||
#define grpc_gcp_Identity_init_default {{{NULL}, NULL}, {{NULL}, NULL}} |
||||
#define grpc_gcp_StartClientHandshakeReq_init_default {false, (grpc_gcp_HandshakeProtocol)0, {{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}, false, grpc_gcp_Identity_init_default, false, grpc_gcp_Endpoint_init_default, false, grpc_gcp_Endpoint_init_default, {{NULL}, NULL}, false, grpc_gcp_RpcProtocolVersions_init_default} |
||||
#define grpc_gcp_ServerHandshakeParameters_init_default {{{NULL}, NULL}, {{NULL}, NULL}} |
||||
#define grpc_gcp_StartServerHandshakeReq_init_default {{{NULL}, NULL}, 0, {grpc_gcp_StartServerHandshakeReq_HandshakeParametersEntry_init_default, grpc_gcp_StartServerHandshakeReq_HandshakeParametersEntry_init_default, grpc_gcp_StartServerHandshakeReq_HandshakeParametersEntry_init_default}, {{NULL}, NULL}, false, grpc_gcp_Endpoint_init_default, false, grpc_gcp_Endpoint_init_default, false, grpc_gcp_RpcProtocolVersions_init_default} |
||||
#define grpc_gcp_StartServerHandshakeReq_HandshakeParametersEntry_init_default {false, 0, false, grpc_gcp_ServerHandshakeParameters_init_default} |
||||
#define grpc_gcp_NextHandshakeMessageReq_init_default {{{NULL}, NULL}} |
||||
#define grpc_gcp_HandshakerReq_init_default {false, grpc_gcp_StartClientHandshakeReq_init_default, false, grpc_gcp_StartServerHandshakeReq_init_default, false, grpc_gcp_NextHandshakeMessageReq_init_default} |
||||
#define grpc_gcp_HandshakerResult_init_default {{{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}, false, grpc_gcp_Identity_init_default, false, grpc_gcp_Identity_init_default, false, 0, false, grpc_gcp_RpcProtocolVersions_init_default} |
||||
#define grpc_gcp_HandshakerStatus_init_default {false, 0, {{NULL}, NULL}} |
||||
#define grpc_gcp_HandshakerResp_init_default {{{NULL}, NULL}, false, 0, false, grpc_gcp_HandshakerResult_init_default, false, grpc_gcp_HandshakerStatus_init_default} |
||||
#define grpc_gcp_Endpoint_init_zero {{{NULL}, NULL}, false, 0, false, (grpc_gcp_NetworkProtocol)0} |
||||
#define grpc_gcp_Identity_init_zero {{{NULL}, NULL}, {{NULL}, NULL}} |
||||
#define grpc_gcp_StartClientHandshakeReq_init_zero {false, (grpc_gcp_HandshakeProtocol)0, {{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}, false, grpc_gcp_Identity_init_zero, false, grpc_gcp_Endpoint_init_zero, false, grpc_gcp_Endpoint_init_zero, {{NULL}, NULL}, false, grpc_gcp_RpcProtocolVersions_init_zero} |
||||
#define grpc_gcp_ServerHandshakeParameters_init_zero {{{NULL}, NULL}, {{NULL}, NULL}} |
||||
#define grpc_gcp_StartServerHandshakeReq_init_zero {{{NULL}, NULL}, 0, {grpc_gcp_StartServerHandshakeReq_HandshakeParametersEntry_init_zero, grpc_gcp_StartServerHandshakeReq_HandshakeParametersEntry_init_zero, grpc_gcp_StartServerHandshakeReq_HandshakeParametersEntry_init_zero}, {{NULL}, NULL}, false, grpc_gcp_Endpoint_init_zero, false, grpc_gcp_Endpoint_init_zero, false, grpc_gcp_RpcProtocolVersions_init_zero} |
||||
#define grpc_gcp_StartServerHandshakeReq_HandshakeParametersEntry_init_zero {false, 0, false, grpc_gcp_ServerHandshakeParameters_init_zero} |
||||
#define grpc_gcp_NextHandshakeMessageReq_init_zero {{{NULL}, NULL}} |
||||
#define grpc_gcp_HandshakerReq_init_zero {false, grpc_gcp_StartClientHandshakeReq_init_zero, false, grpc_gcp_StartServerHandshakeReq_init_zero, false, grpc_gcp_NextHandshakeMessageReq_init_zero} |
||||
#define grpc_gcp_HandshakerResult_init_zero {{{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}, false, grpc_gcp_Identity_init_zero, false, grpc_gcp_Identity_init_zero, false, 0, false, grpc_gcp_RpcProtocolVersions_init_zero} |
||||
#define grpc_gcp_HandshakerStatus_init_zero {false, 0, {{NULL}, NULL}} |
||||
#define grpc_gcp_HandshakerResp_init_zero {{{NULL}, NULL}, false, 0, false, grpc_gcp_HandshakerResult_init_zero, false, grpc_gcp_HandshakerStatus_init_zero} |
||||
|
||||
/* Field tags (for use in manual encoding/decoding) */ |
||||
#define grpc_gcp_Identity_service_account_tag 1 |
||||
#define grpc_gcp_Identity_hostname_tag 2 |
||||
#define grpc_gcp_NextHandshakeMessageReq_in_bytes_tag 1 |
||||
#define grpc_gcp_ServerHandshakeParameters_record_protocols_tag 1 |
||||
#define grpc_gcp_ServerHandshakeParameters_local_identities_tag 2 |
||||
#define grpc_gcp_Endpoint_ip_address_tag 1 |
||||
#define grpc_gcp_Endpoint_port_tag 2 |
||||
#define grpc_gcp_Endpoint_protocol_tag 3 |
||||
#define grpc_gcp_HandshakerResult_application_protocol_tag 1 |
||||
#define grpc_gcp_HandshakerResult_record_protocol_tag 2 |
||||
#define grpc_gcp_HandshakerResult_key_data_tag 3 |
||||
#define grpc_gcp_HandshakerResult_peer_identity_tag 4 |
||||
#define grpc_gcp_HandshakerResult_local_identity_tag 5 |
||||
#define grpc_gcp_HandshakerResult_keep_channel_open_tag 6 |
||||
#define grpc_gcp_HandshakerResult_peer_rpc_versions_tag 7 |
||||
#define grpc_gcp_HandshakerStatus_code_tag 1 |
||||
#define grpc_gcp_HandshakerStatus_details_tag 2 |
||||
#define grpc_gcp_StartServerHandshakeReq_HandshakeParametersEntry_key_tag 1 |
||||
#define grpc_gcp_StartServerHandshakeReq_HandshakeParametersEntry_value_tag 2 |
||||
#define grpc_gcp_HandshakerResp_out_frames_tag 1 |
||||
#define grpc_gcp_HandshakerResp_bytes_consumed_tag 2 |
||||
#define grpc_gcp_HandshakerResp_result_tag 3 |
||||
#define grpc_gcp_HandshakerResp_status_tag 4 |
||||
#define grpc_gcp_StartClientHandshakeReq_handshake_security_protocol_tag 1 |
||||
#define grpc_gcp_StartClientHandshakeReq_application_protocols_tag 2 |
||||
#define grpc_gcp_StartClientHandshakeReq_record_protocols_tag 3 |
||||
#define grpc_gcp_StartClientHandshakeReq_target_identities_tag 4 |
||||
#define grpc_gcp_StartClientHandshakeReq_local_identity_tag 5 |
||||
#define grpc_gcp_StartClientHandshakeReq_local_endpoint_tag 6 |
||||
#define grpc_gcp_StartClientHandshakeReq_remote_endpoint_tag 7 |
||||
#define grpc_gcp_StartClientHandshakeReq_target_name_tag 8 |
||||
#define grpc_gcp_StartClientHandshakeReq_rpc_versions_tag 9 |
||||
#define grpc_gcp_StartServerHandshakeReq_application_protocols_tag 1 |
||||
#define grpc_gcp_StartServerHandshakeReq_handshake_parameters_tag 2 |
||||
#define grpc_gcp_StartServerHandshakeReq_in_bytes_tag 3 |
||||
#define grpc_gcp_StartServerHandshakeReq_local_endpoint_tag 4 |
||||
#define grpc_gcp_StartServerHandshakeReq_remote_endpoint_tag 5 |
||||
#define grpc_gcp_StartServerHandshakeReq_rpc_versions_tag 6 |
||||
#define grpc_gcp_HandshakerReq_client_start_tag 1 |
||||
#define grpc_gcp_HandshakerReq_server_start_tag 2 |
||||
#define grpc_gcp_HandshakerReq_next_tag 3 |
||||
|
||||
/* Struct field encoding specification for nanopb */ |
||||
extern const pb_field_t grpc_gcp_Endpoint_fields[4]; |
||||
extern const pb_field_t grpc_gcp_Identity_fields[3]; |
||||
extern const pb_field_t grpc_gcp_StartClientHandshakeReq_fields[10]; |
||||
extern const pb_field_t grpc_gcp_ServerHandshakeParameters_fields[3]; |
||||
extern const pb_field_t grpc_gcp_StartServerHandshakeReq_fields[7]; |
||||
extern const pb_field_t grpc_gcp_StartServerHandshakeReq_HandshakeParametersEntry_fields[3]; |
||||
extern const pb_field_t grpc_gcp_NextHandshakeMessageReq_fields[2]; |
||||
extern const pb_field_t grpc_gcp_HandshakerReq_fields[4]; |
||||
extern const pb_field_t grpc_gcp_HandshakerResult_fields[8]; |
||||
extern const pb_field_t grpc_gcp_HandshakerStatus_fields[3]; |
||||
extern const pb_field_t grpc_gcp_HandshakerResp_fields[5]; |
||||
|
||||
/* Maximum encoded size of messages (where known) */ |
||||
/* grpc_gcp_Endpoint_size depends on runtime parameters */ |
||||
/* grpc_gcp_Identity_size depends on runtime parameters */ |
||||
/* grpc_gcp_StartClientHandshakeReq_size depends on runtime parameters */ |
||||
/* grpc_gcp_ServerHandshakeParameters_size depends on runtime parameters */ |
||||
/* grpc_gcp_StartServerHandshakeReq_size depends on runtime parameters */ |
||||
#define grpc_gcp_StartServerHandshakeReq_HandshakeParametersEntry_size (17 + grpc_gcp_ServerHandshakeParameters_size) |
||||
/* grpc_gcp_NextHandshakeMessageReq_size depends on runtime parameters */ |
||||
#define grpc_gcp_HandshakerReq_size (18 + grpc_gcp_StartClientHandshakeReq_size + grpc_gcp_StartServerHandshakeReq_size + grpc_gcp_NextHandshakeMessageReq_size) |
||||
/* grpc_gcp_HandshakerResult_size depends on runtime parameters */ |
||||
/* grpc_gcp_HandshakerStatus_size depends on runtime parameters */ |
||||
/* grpc_gcp_HandshakerResp_size depends on runtime parameters */ |
||||
|
||||
/* Message IDs (where set with "msgid" option) */ |
||||
#ifdef PB_MSGID |
||||
|
||||
#define HANDSHAKER_MESSAGES \ |
||||
|
||||
|
||||
#endif |
||||
|
||||
#ifdef __cplusplus |
||||
} /* extern "C" */ |
||||
#endif |
||||
/* @@protoc_insertion_point(eof) */ |
||||
|
||||
#endif |
@ -0,0 +1,41 @@ |
||||
// Copyright 2018 gRPC authors. |
||||
// |
||||
// Licensed under the Apache License, Version 2.0 (the "License"); |
||||
// you may not use this file except in compliance with the License. |
||||
// You may obtain a copy of the License at |
||||
// |
||||
// http://www.apache.org/licenses/LICENSE-2.0 |
||||
// |
||||
// Unless required by applicable law or agreed to in writing, software |
||||
// distributed under the License is distributed on an "AS IS" BASIS, |
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
// See the License for the specific language governing permissions and |
||||
// limitations under the License. |
||||
|
||||
syntax = "proto3"; |
||||
|
||||
import "transport_security_common.proto"; |
||||
|
||||
package grpc.gcp; |
||||
|
||||
option java_package = "io.grpc.alts"; |
||||
|
||||
message AltsContext { |
||||
// The application protocol negotiated for this connection. |
||||
string application_protocol = 1; |
||||
|
||||
// The record protocol negotiated for this connection. |
||||
string record_protocol = 2; |
||||
|
||||
// The security level of the created secure channel. |
||||
SecurityLevel security_level = 3; |
||||
|
||||
// The peer service account. |
||||
string peer_service_account = 4; |
||||
|
||||
// The local service account. |
||||
string local_service_account = 5; |
||||
|
||||
// The RPC protocol versions supported by the peer. |
||||
RpcProtocolVersions peer_rpc_versions = 6; |
||||
} |
@ -0,0 +1,2 @@ |
||||
handshaker.proto no_unions:true |
||||
grpc.gcp.StartServerHandshakeReq.handshake_parameters max_count:3 |
@ -0,0 +1,220 @@ |
||||
// Copyright 2018 gRPC authors. |
||||
// |
||||
// Licensed under the Apache License, Version 2.0 (the "License"); |
||||
// you may not use this file except in compliance with the License. |
||||
// You may obtain a copy of the License at |
||||
// |
||||
// http://www.apache.org/licenses/LICENSE-2.0 |
||||
// |
||||
// Unless required by applicable law or agreed to in writing, software |
||||
// distributed under the License is distributed on an "AS IS" BASIS, |
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
// See the License for the specific language governing permissions and |
||||
// limitations under the License. |
||||
|
||||
syntax = "proto3"; |
||||
|
||||
import "transport_security_common.proto"; |
||||
|
||||
package grpc.gcp; |
||||
|
||||
option java_package = "io.grpc.alts"; |
||||
|
||||
enum HandshakeProtocol { |
||||
// Default value. |
||||
HANDSHAKE_PROTOCOL_UNSPECIFIED = 0; |
||||
|
||||
// TLS handshake protocol. |
||||
TLS = 1; |
||||
|
||||
// Application Layer Transport Security handshake protocol. |
||||
ALTS = 2; |
||||
} |
||||
|
||||
enum NetworkProtocol { |
||||
NETWORK_PROTOCOL_UNSPECIFIED = 0; |
||||
TCP = 1; |
||||
UDP = 2; |
||||
} |
||||
|
||||
message Endpoint { |
||||
// IP address. It should contain an IPv4 or IPv6 string literal, e.g. |
||||
// "192.168.0.1" or "2001:db8::1". |
||||
string ip_address = 1; |
||||
|
||||
// Port number. |
||||
int32 port = 2; |
||||
|
||||
// Network protocol (e.g., TCP, UDP) associated with this endpoint. |
||||
NetworkProtocol protocol = 3; |
||||
} |
||||
|
||||
message Identity { |
||||
oneof identity_oneof { |
||||
// Service account of a connection endpoint. |
||||
string service_account = 1; |
||||
|
||||
// Hostname of a connection endpoint. |
||||
string hostname = 2; |
||||
} |
||||
} |
||||
|
||||
message StartClientHandshakeReq { |
||||
// Handshake security protocol requested by the client. |
||||
HandshakeProtocol handshake_security_protocol = 1; |
||||
|
||||
// The application protocols supported by the client, e.g., "h2" (for http2), |
||||
// "grpc". |
||||
repeated string application_protocols = 2; |
||||
|
||||
// The record protocols supported by the client, e.g., |
||||
// "ALTSRP_GCM_AES128". |
||||
repeated string record_protocols = 3; |
||||
|
||||
// (Optional) Describes which server identities are acceptable by the client. |
||||
// If target identities are provided and none of them matches the peer |
||||
// identity of the server, handshake will fail. |
||||
repeated Identity target_identities = 4; |
||||
|
||||
// (Optional) Application may specify a local identity. Otherwise, the |
||||
// handshaker chooses a default local identity. |
||||
Identity local_identity = 5; |
||||
|
||||
// (Optional) Local endpoint information of the connection to the server, |
||||
// such as local IP address, port number, and network protocol. |
||||
Endpoint local_endpoint = 6; |
||||
|
||||
// (Optional) Endpoint information of the remote server, such as IP address, |
||||
// port number, and network protocool. |
||||
Endpoint remote_endpoint = 7; |
||||
|
||||
// (Optional) If target name is provided, a secure naming check is performed |
||||
// to verify that the peer authenticated identity is indeed authorized to run |
||||
// the target name. |
||||
string target_name = 8; |
||||
|
||||
// (Optional) RPC protocol versions supported by the client. |
||||
RpcProtocolVersions rpc_versions = 9; |
||||
} |
||||
|
||||
message ServerHandshakeParameters { |
||||
// The record protocols supported by the server, e.g., |
||||
// "ALTSRP_GCM_AES128". |
||||
repeated string record_protocols = 1; |
||||
|
||||
// (Optional) A list of local identities supported by the server, if |
||||
// specified. Otherwise, the handshaker chooses a default local identity. |
||||
repeated Identity local_identities = 2; |
||||
} |
||||
|
||||
message StartServerHandshakeReq { |
||||
// The application protocols supported by the server, e.g., "h2" (for http2), |
||||
// "grpc". |
||||
repeated string application_protocols = 1; |
||||
|
||||
// Handshake parameters (record protocols and local identities supported by |
||||
// the server) mapped by the handshake protocol. Each handshake security |
||||
// protocol (e.g., TLS or ALTS) has its own set of record protocols and local |
||||
// identities. Since protobuf does not support enum as key to the map, the key |
||||
// to handshake_parameters is the integer value of HandshakeProtocol enum. |
||||
map<int32, ServerHandshakeParameters> handshake_parameters = 2; |
||||
|
||||
// Bytes in out_frames returned from the peer's HandshakerResp. It is possible |
||||
// that the peer's out_frames are split into multiple HandshakReq messages. |
||||
bytes in_bytes = 3; |
||||
|
||||
// (Optional) Local endpoint information of the connection to the client, |
||||
// such as local IP address, port number, and network protocol. |
||||
Endpoint local_endpoint = 4; |
||||
|
||||
// (Optional) Endpoint information of the remote client, such as IP address, |
||||
// port number, and network protocool. |
||||
Endpoint remote_endpoint = 5; |
||||
|
||||
// (Optional) RPC protocol versions supported by the server. |
||||
RpcProtocolVersions rpc_versions = 6; |
||||
} |
||||
|
||||
message NextHandshakeMessageReq { |
||||
// Bytes in out_frames returned from the peer's HandshakerResp. It is possible |
||||
// that the peer's out_frames are split into multiple NextHandshakerMessageReq |
||||
// messages. |
||||
bytes in_bytes = 1; |
||||
} |
||||
|
||||
message HandshakerReq { |
||||
oneof req_oneof { |
||||
// The start client handshake request message. |
||||
StartClientHandshakeReq client_start = 1; |
||||
|
||||
// The start server handshake request message. |
||||
StartServerHandshakeReq server_start = 2; |
||||
|
||||
// The next handshake request message. |
||||
NextHandshakeMessageReq next = 3; |
||||
} |
||||
} |
||||
|
||||
message HandshakerResult { |
||||
// The application protocol negotiated for this connection. |
||||
string application_protocol = 1; |
||||
|
||||
// The record protocol negotiated for this connection. |
||||
string record_protocol = 2; |
||||
|
||||
// Cryptographic key data. The key data may be more than the key length |
||||
// required for the record protocol, thus the client of the handshaker |
||||
// service needs to truncate the key data into the right key length. |
||||
bytes key_data = 3; |
||||
|
||||
// The authenticated identity of the peer. |
||||
Identity peer_identity = 4; |
||||
|
||||
// The local identity used in the handshake. |
||||
Identity local_identity = 5; |
||||
|
||||
// Indicate whether the handshaker service client should keep the channel |
||||
// between the handshaker service open, e.g., in order to handle |
||||
// post-handshake messages in the future. |
||||
bool keep_channel_open = 6; |
||||
|
||||
// The RPC protocol versions supported by the peer. |
||||
RpcProtocolVersions peer_rpc_versions = 7; |
||||
} |
||||
|
||||
message HandshakerStatus { |
||||
// The status code. This could be the gRPC status code. |
||||
uint32 code = 1; |
||||
|
||||
// The status details. |
||||
string details = 2; |
||||
} |
||||
|
||||
message HandshakerResp { |
||||
// Frames to be given to the peer for the NextHandshakeMessageReq. May be |
||||
// empty if no out_frames have to be sent to the peer or if in_bytes in the |
||||
// HandshakerReq are incomplete. All the non-empty out frames must be sent to |
||||
// the peer even if the handshaker status is not OK as these frames may |
||||
// contain the alert frames. |
||||
bytes out_frames = 1; |
||||
|
||||
// Number of bytes in the in_bytes consumed by the handshaker. It is possible |
||||
// that part of in_bytes in HandshakerReq was unrelated to the handshake |
||||
// process. |
||||
uint32 bytes_consumed = 2; |
||||
|
||||
// This is set iff the handshake was successful. out_frames may still be set |
||||
// to frames that needs to be forwarded to the peer. |
||||
HandshakerResult result = 3; |
||||
|
||||
// Status of the handshaker. |
||||
HandshakerStatus status = 4; |
||||
} |
||||
|
||||
service HandshakerService { |
||||
// Accepts a stream of handshaker request, returning a stream of handshaker |
||||
// response. |
||||
rpc DoHandshake(stream HandshakerReq) |
||||
returns (stream HandshakerResp) { |
||||
} |
||||
} |
@ -0,0 +1,40 @@ |
||||
// Copyright 2018 gRPC authors. |
||||
// |
||||
// Licensed under the Apache License, Version 2.0 (the "License"); |
||||
// you may not use this file except in compliance with the License. |
||||
// You may obtain a copy of the License at |
||||
// |
||||
// http://www.apache.org/licenses/LICENSE-2.0 |
||||
// |
||||
// Unless required by applicable law or agreed to in writing, software |
||||
// distributed under the License is distributed on an "AS IS" BASIS, |
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
// See the License for the specific language governing permissions and |
||||
// limitations under the License. |
||||
|
||||
syntax = "proto3"; |
||||
|
||||
package grpc.gcp; |
||||
|
||||
option java_package = "io.grpc.alts"; |
||||
|
||||
// The security level of the created channel. The list is sorted in increasing |
||||
// level of security. This order must always be maintained. |
||||
enum SecurityLevel { |
||||
SECURITY_NONE = 0; |
||||
INTEGRITY_ONLY = 1; |
||||
INTEGRITY_AND_PRIVACY = 2; |
||||
} |
||||
|
||||
// Max and min supported RPC protocol versions. |
||||
message RpcProtocolVersions { |
||||
// RPC version contains a major version and a minor version. |
||||
message Version { |
||||
uint32 major = 1; |
||||
uint32 minor = 2; |
||||
} |
||||
// Maximum supported RPC version. |
||||
Version max_rpc_version = 1; |
||||
// Minimum supported RPC version. |
||||
Version min_rpc_version = 2; |
||||
} |
@ -0,0 +1,50 @@ |
||||
/* Automatically generated nanopb constant definitions */ |
||||
/* Generated by nanopb-0.3.7-dev */ |
||||
|
||||
#include "src/core/tsi/alts/handshaker/transport_security_common.pb.h" |
||||
|
||||
/* @@protoc_insertion_point(includes) */ |
||||
#if PB_PROTO_HEADER_VERSION != 30 |
||||
#error Regenerate this file with the current version of nanopb generator. |
||||
#endif |
||||
|
||||
|
||||
|
||||
const pb_field_t grpc_gcp_RpcProtocolVersions_fields[3] = { |
||||
PB_FIELD( 1, MESSAGE , OPTIONAL, STATIC , FIRST, grpc_gcp_RpcProtocolVersions, max_rpc_version, max_rpc_version, &grpc_gcp_RpcProtocolVersions_Version_fields), |
||||
PB_FIELD( 2, MESSAGE , OPTIONAL, STATIC , OTHER, grpc_gcp_RpcProtocolVersions, min_rpc_version, max_rpc_version, &grpc_gcp_RpcProtocolVersions_Version_fields), |
||||
PB_LAST_FIELD |
||||
}; |
||||
|
||||
const pb_field_t grpc_gcp_RpcProtocolVersions_Version_fields[3] = { |
||||
PB_FIELD( 1, UINT32 , OPTIONAL, STATIC , FIRST, grpc_gcp_RpcProtocolVersions_Version, major, major, 0), |
||||
PB_FIELD( 2, UINT32 , OPTIONAL, STATIC , OTHER, grpc_gcp_RpcProtocolVersions_Version, minor, major, 0), |
||||
PB_LAST_FIELD |
||||
}; |
||||
|
||||
|
||||
/* Check that field information fits in pb_field_t */ |
||||
#if !defined(PB_FIELD_32BIT) |
||||
/* If you get an error here, it means that you need to define PB_FIELD_32BIT
|
||||
* compile-time option. You can do that in pb.h or on compiler command line. |
||||
*
|
||||
* The reason you need to do this is that some of your messages contain tag |
||||
* numbers or field sizes that are larger than what can fit in 8 or 16 bit |
||||
* field descriptors. |
||||
*/ |
||||
PB_STATIC_ASSERT((pb_membersize(grpc_gcp_RpcProtocolVersions, max_rpc_version) < 65536 && pb_membersize(grpc_gcp_RpcProtocolVersions, min_rpc_version) < 65536), YOU_MUST_DEFINE_PB_FIELD_32BIT_FOR_MESSAGES_grpc_gcp_RpcProtocolVersions_grpc_gcp_RpcProtocolVersions_Version) |
||||
#endif |
||||
|
||||
#if !defined(PB_FIELD_16BIT) && !defined(PB_FIELD_32BIT) |
||||
/* If you get an error here, it means that you need to define PB_FIELD_16BIT
|
||||
* compile-time option. You can do that in pb.h or on compiler command line. |
||||
*
|
||||
* The reason you need to do this is that some of your messages contain tag |
||||
* numbers or field sizes that are larger than what can fit in the default |
||||
* 8 bit descriptors. |
||||
*/ |
||||
PB_STATIC_ASSERT((pb_membersize(grpc_gcp_RpcProtocolVersions, max_rpc_version) < 256 && pb_membersize(grpc_gcp_RpcProtocolVersions, min_rpc_version) < 256), YOU_MUST_DEFINE_PB_FIELD_16BIT_FOR_MESSAGES_grpc_gcp_RpcProtocolVersions_grpc_gcp_RpcProtocolVersions_Version) |
||||
#endif |
||||
|
||||
|
||||
/* @@protoc_insertion_point(eof) */ |
@ -0,0 +1,78 @@ |
||||
/* Automatically generated nanopb header */ |
||||
/* Generated by nanopb-0.3.7-dev */ |
||||
|
||||
#ifndef PB_GRPC_GCP_TRANSPORT_SECURITY_COMMON_PB_H_INCLUDED |
||||
#define PB_GRPC_GCP_TRANSPORT_SECURITY_COMMON_PB_H_INCLUDED |
||||
#include "third_party/nanopb/pb.h" |
||||
/* @@protoc_insertion_point(includes) */ |
||||
#if PB_PROTO_HEADER_VERSION != 30 |
||||
#error Regenerate this file with the current version of nanopb generator. |
||||
#endif |
||||
|
||||
#ifdef __cplusplus |
||||
extern "C" { |
||||
#endif |
||||
|
||||
/* Enum definitions */ |
||||
typedef enum _grpc_gcp_SecurityLevel { |
||||
grpc_gcp_SecurityLevel_SECURITY_NONE = 0, |
||||
grpc_gcp_SecurityLevel_INTEGRITY_ONLY = 1, |
||||
grpc_gcp_SecurityLevel_INTEGRITY_AND_PRIVACY = 2 |
||||
} grpc_gcp_SecurityLevel; |
||||
#define _grpc_gcp_SecurityLevel_MIN grpc_gcp_SecurityLevel_SECURITY_NONE |
||||
#define _grpc_gcp_SecurityLevel_MAX grpc_gcp_SecurityLevel_INTEGRITY_AND_PRIVACY |
||||
#define _grpc_gcp_SecurityLevel_ARRAYSIZE ((grpc_gcp_SecurityLevel)(grpc_gcp_SecurityLevel_INTEGRITY_AND_PRIVACY+1)) |
||||
|
||||
/* Struct definitions */ |
||||
typedef struct _grpc_gcp_RpcProtocolVersions_Version { |
||||
bool has_major; |
||||
uint32_t major; |
||||
bool has_minor; |
||||
uint32_t minor; |
||||
/* @@protoc_insertion_point(struct:grpc_gcp_RpcProtocolVersions_Version) */ |
||||
} grpc_gcp_RpcProtocolVersions_Version; |
||||
|
||||
typedef struct _grpc_gcp_RpcProtocolVersions { |
||||
bool has_max_rpc_version; |
||||
grpc_gcp_RpcProtocolVersions_Version max_rpc_version; |
||||
bool has_min_rpc_version; |
||||
grpc_gcp_RpcProtocolVersions_Version min_rpc_version; |
||||
/* @@protoc_insertion_point(struct:grpc_gcp_RpcProtocolVersions) */ |
||||
} grpc_gcp_RpcProtocolVersions; |
||||
|
||||
/* Default values for struct fields */ |
||||
|
||||
/* Initializer values for message structs */ |
||||
#define grpc_gcp_RpcProtocolVersions_init_default {false, grpc_gcp_RpcProtocolVersions_Version_init_default, false, grpc_gcp_RpcProtocolVersions_Version_init_default} |
||||
#define grpc_gcp_RpcProtocolVersions_Version_init_default {false, 0, false, 0} |
||||
#define grpc_gcp_RpcProtocolVersions_init_zero {false, grpc_gcp_RpcProtocolVersions_Version_init_zero, false, grpc_gcp_RpcProtocolVersions_Version_init_zero} |
||||
#define grpc_gcp_RpcProtocolVersions_Version_init_zero {false, 0, false, 0} |
||||
|
||||
/* Field tags (for use in manual encoding/decoding) */ |
||||
#define grpc_gcp_RpcProtocolVersions_Version_major_tag 1 |
||||
#define grpc_gcp_RpcProtocolVersions_Version_minor_tag 2 |
||||
#define grpc_gcp_RpcProtocolVersions_max_rpc_version_tag 1 |
||||
#define grpc_gcp_RpcProtocolVersions_min_rpc_version_tag 2 |
||||
|
||||
/* Struct field encoding specification for nanopb */ |
||||
extern const pb_field_t grpc_gcp_RpcProtocolVersions_fields[3]; |
||||
extern const pb_field_t grpc_gcp_RpcProtocolVersions_Version_fields[3]; |
||||
|
||||
/* Maximum encoded size of messages (where known) */ |
||||
#define grpc_gcp_RpcProtocolVersions_size 28 |
||||
#define grpc_gcp_RpcProtocolVersions_Version_size 12 |
||||
|
||||
/* Message IDs (where set with "msgid" option) */ |
||||
#ifdef PB_MSGID |
||||
|
||||
#define TRANSPORT_SECURITY_COMMON_MESSAGES \ |
||||
|
||||
|
||||
#endif |
||||
|
||||
#ifdef __cplusplus |
||||
} /* extern "C" */ |
||||
#endif |
||||
/* @@protoc_insertion_point(eof) */ |
||||
|
||||
#endif |
@ -0,0 +1,196 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2018 gRPC authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
* |
||||
*/ |
||||
|
||||
#include <grpc/support/port_platform.h> |
||||
|
||||
#include "src/core/tsi/alts/handshaker/transport_security_common_api.h" |
||||
|
||||
bool grpc_gcp_rpc_protocol_versions_set_max( |
||||
grpc_gcp_rpc_protocol_versions* versions, uint32_t max_major, |
||||
uint32_t max_minor) { |
||||
if (versions == nullptr) { |
||||
gpr_log(GPR_ERROR, |
||||
"versions is nullptr in " |
||||
"grpc_gcp_rpc_protocol_versions_set_max()."); |
||||
return false; |
||||
} |
||||
versions->has_max_rpc_version = true; |
||||
versions->max_rpc_version.has_major = true; |
||||
versions->max_rpc_version.has_minor = true; |
||||
versions->max_rpc_version.major = max_major; |
||||
versions->max_rpc_version.minor = max_minor; |
||||
return true; |
||||
} |
||||
|
||||
bool grpc_gcp_rpc_protocol_versions_set_min( |
||||
grpc_gcp_rpc_protocol_versions* versions, uint32_t min_major, |
||||
uint32_t min_minor) { |
||||
if (versions == nullptr) { |
||||
gpr_log(GPR_ERROR, |
||||
"versions is nullptr in " |
||||
"grpc_gcp_rpc_protocol_versions_set_min()."); |
||||
return false; |
||||
} |
||||
versions->has_min_rpc_version = true; |
||||
versions->min_rpc_version.has_major = true; |
||||
versions->min_rpc_version.has_minor = true; |
||||
versions->min_rpc_version.major = min_major; |
||||
versions->min_rpc_version.minor = min_minor; |
||||
return true; |
||||
} |
||||
|
||||
size_t grpc_gcp_rpc_protocol_versions_encode_length( |
||||
const grpc_gcp_rpc_protocol_versions* versions) { |
||||
if (versions == nullptr) { |
||||
gpr_log(GPR_ERROR, |
||||
"Invalid nullptr arguments to " |
||||
"grpc_gcp_rpc_protocol_versions_encode_length()."); |
||||
return 0; |
||||
} |
||||
pb_ostream_t size_stream; |
||||
memset(&size_stream, 0, sizeof(pb_ostream_t)); |
||||
if (!pb_encode(&size_stream, grpc_gcp_RpcProtocolVersions_fields, versions)) { |
||||
gpr_log(GPR_ERROR, "nanopb error: %s", PB_GET_ERROR(&size_stream)); |
||||
return 0; |
||||
} |
||||
return size_stream.bytes_written; |
||||
} |
||||
|
||||
bool grpc_gcp_rpc_protocol_versions_encode_to_raw_bytes( |
||||
const grpc_gcp_rpc_protocol_versions* versions, uint8_t* bytes, |
||||
size_t bytes_length) { |
||||
if (versions == nullptr || bytes == nullptr || bytes_length == 0) { |
||||
gpr_log(GPR_ERROR, |
||||
"Invalid nullptr arguments to " |
||||
"grpc_gcp_rpc_protocol_versions_encode_to_raw_bytes()."); |
||||
return false; |
||||
} |
||||
pb_ostream_t output_stream = pb_ostream_from_buffer(bytes, bytes_length); |
||||
if (!pb_encode(&output_stream, grpc_gcp_RpcProtocolVersions_fields, |
||||
versions)) { |
||||
gpr_log(GPR_ERROR, "nanopb error: %s", PB_GET_ERROR(&output_stream)); |
||||
return false; |
||||
} |
||||
return true; |
||||
} |
||||
|
||||
bool grpc_gcp_rpc_protocol_versions_encode( |
||||
const grpc_gcp_rpc_protocol_versions* versions, grpc_slice* slice) { |
||||
if (versions == nullptr || slice == nullptr) { |
||||
gpr_log(GPR_ERROR, |
||||
"Invalid nullptr arguments to " |
||||
"grpc_gcp_rpc_protocol_versions_encode()."); |
||||
return false; |
||||
} |
||||
size_t encoded_length = |
||||
grpc_gcp_rpc_protocol_versions_encode_length(versions); |
||||
if (encoded_length == 0) return false; |
||||
*slice = grpc_slice_malloc(encoded_length); |
||||
return grpc_gcp_rpc_protocol_versions_encode_to_raw_bytes( |
||||
versions, GRPC_SLICE_START_PTR(*slice), encoded_length); |
||||
} |
||||
|
||||
bool grpc_gcp_rpc_protocol_versions_decode( |
||||
grpc_slice slice, grpc_gcp_rpc_protocol_versions* versions) { |
||||
if (versions == nullptr) { |
||||
gpr_log(GPR_ERROR, |
||||
"version is nullptr in " |
||||
"grpc_gcp_rpc_protocol_versions_decode()."); |
||||
return false; |
||||
} |
||||
pb_istream_t stream = pb_istream_from_buffer(GRPC_SLICE_START_PTR(slice), |
||||
GRPC_SLICE_LENGTH(slice)); |
||||
if (!pb_decode(&stream, grpc_gcp_RpcProtocolVersions_fields, versions)) { |
||||
gpr_log(GPR_ERROR, "nanopb error: %s", PB_GET_ERROR(&stream)); |
||||
return false; |
||||
} |
||||
return true; |
||||
} |
||||
|
||||
bool grpc_gcp_rpc_protocol_versions_copy( |
||||
const grpc_gcp_rpc_protocol_versions* src, |
||||
grpc_gcp_rpc_protocol_versions* dst) { |
||||
if ((src == nullptr && dst != nullptr) || |
||||
(src != nullptr && dst == nullptr)) { |
||||
gpr_log(GPR_ERROR, |
||||
"Invalid arguments to " |
||||
"grpc_gcp_rpc_protocol_versions_copy()."); |
||||
return false; |
||||
} |
||||
if (src == nullptr) { |
||||
return true; |
||||
} |
||||
grpc_gcp_rpc_protocol_versions_set_max(dst, src->max_rpc_version.major, |
||||
src->max_rpc_version.minor); |
||||
grpc_gcp_rpc_protocol_versions_set_min(dst, src->min_rpc_version.major, |
||||
src->min_rpc_version.minor); |
||||
return true; |
||||
} |
||||
|
||||
namespace grpc_core { |
||||
namespace internal { |
||||
|
||||
int grpc_gcp_rpc_protocol_version_compare( |
||||
const grpc_gcp_rpc_protocol_versions_version* v1, |
||||
const grpc_gcp_rpc_protocol_versions_version* v2) { |
||||
if ((v1->major > v2->major) || |
||||
(v1->major == v2->major && v1->minor > v2->minor)) { |
||||
return 1; |
||||
} |
||||
if ((v1->major < v2->major) || |
||||
(v1->major == v2->major && v1->minor < v2->minor)) { |
||||
return -1; |
||||
} |
||||
return 0; |
||||
} |
||||
|
||||
} // namespace internal
|
||||
} // namespace grpc_core
|
||||
|
||||
bool grpc_gcp_rpc_protocol_versions_check( |
||||
const grpc_gcp_rpc_protocol_versions* local_versions, |
||||
const grpc_gcp_rpc_protocol_versions* peer_versions, |
||||
grpc_gcp_rpc_protocol_versions_version* highest_common_version) { |
||||
if (local_versions == nullptr || peer_versions == nullptr) { |
||||
gpr_log(GPR_ERROR, |
||||
"Invalid arguments to " |
||||
"grpc_gcp_rpc_protocol_versions_check()."); |
||||
return false; |
||||
} |
||||
/* max_common_version is MIN(local.max, peer.max) */ |
||||
const grpc_gcp_rpc_protocol_versions_version* max_common_version = |
||||
grpc_core::internal::grpc_gcp_rpc_protocol_version_compare( |
||||
&local_versions->max_rpc_version, &peer_versions->max_rpc_version) > 0 |
||||
? &peer_versions->max_rpc_version |
||||
: &local_versions->max_rpc_version; |
||||
/* min_common_version is MAX(local.min, peer.min) */ |
||||
const grpc_gcp_rpc_protocol_versions_version* min_common_version = |
||||
grpc_core::internal::grpc_gcp_rpc_protocol_version_compare( |
||||
&local_versions->min_rpc_version, &peer_versions->min_rpc_version) > 0 |
||||
? &local_versions->min_rpc_version |
||||
: &peer_versions->min_rpc_version; |
||||
bool result = grpc_core::internal::grpc_gcp_rpc_protocol_version_compare( |
||||
max_common_version, min_common_version) >= 0 |
||||
? true |
||||
: false; |
||||
if (result && highest_common_version != nullptr) { |
||||
memcpy(highest_common_version, max_common_version, |
||||
sizeof(grpc_gcp_rpc_protocol_versions_version)); |
||||
} |
||||
return result; |
||||
} |
@ -0,0 +1,163 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2018 gRPC authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
* |
||||
*/ |
||||
|
||||
#ifndef GRPC_CORE_TSI_ALTS_HANDSHAKER_TRANSPORT_SECURITY_COMMON_API_H |
||||
#define GRPC_CORE_TSI_ALTS_HANDSHAKER_TRANSPORT_SECURITY_COMMON_API_H |
||||
|
||||
#include <grpc/support/port_platform.h> |
||||
|
||||
#include "third_party/nanopb/pb_decode.h" |
||||
#include "third_party/nanopb/pb_encode.h" |
||||
|
||||
#include <grpc/slice.h> |
||||
#include <grpc/slice_buffer.h> |
||||
#include <grpc/support/alloc.h> |
||||
#include <grpc/support/log.h> |
||||
|
||||
#include "src/core/tsi/alts/handshaker/transport_security_common.pb.h" |
||||
|
||||
typedef grpc_gcp_RpcProtocolVersions grpc_gcp_rpc_protocol_versions; |
||||
|
||||
typedef grpc_gcp_RpcProtocolVersions_Version |
||||
grpc_gcp_rpc_protocol_versions_version; |
||||
|
||||
/**
|
||||
* This method sets the value for max_rpc_versions field of rpc protocol |
||||
* versions. |
||||
* |
||||
* - versions: an rpc protocol version instance. |
||||
* - max_major: a major version of maximum supported RPC version. |
||||
* - max_minor: a minor version of maximum supported RPC version. |
||||
* |
||||
* The method returns true on success and false otherwise. |
||||
*/ |
||||
bool grpc_gcp_rpc_protocol_versions_set_max( |
||||
grpc_gcp_rpc_protocol_versions* versions, uint32_t max_major, |
||||
uint32_t max_minor); |
||||
|
||||
/**
|
||||
* This method sets the value for min_rpc_versions field of rpc protocol |
||||
* versions. |
||||
* |
||||
* - versions: an rpc protocol version instance. |
||||
* - min_major: a major version of minimum supported RPC version. |
||||
* - min_minor: a minor version of minimum supported RPC version. |
||||
* |
||||
* The method returns true on success and false otherwise. |
||||
*/ |
||||
bool grpc_gcp_rpc_protocol_versions_set_min( |
||||
grpc_gcp_rpc_protocol_versions* versions, uint32_t min_major, |
||||
uint32_t min_minor); |
||||
|
||||
/**
|
||||
* This method computes serialized byte length of rpc protocol versions. |
||||
* |
||||
* - versions: an rpc protocol versions instance. |
||||
* |
||||
* The method returns serialized byte length. It returns 0 on failure. |
||||
*/ |
||||
size_t grpc_gcp_rpc_protocol_versions_encode_length( |
||||
const grpc_gcp_rpc_protocol_versions* versions); |
||||
|
||||
/**
|
||||
* This method serializes rpc protocol versions and writes the result to |
||||
* the memory buffer provided by the caller. Caller is responsible for |
||||
* allocating sufficient memory to store the serialized data. |
||||
* |
||||
* - versions: an rpc protocol versions instance. |
||||
* - bytes: bytes buffer where the result will be written to. |
||||
* - bytes_length: length of the bytes buffer. |
||||
* |
||||
* The method returns true on success and false otherwise. |
||||
*/ |
||||
bool grpc_gcp_rpc_protocol_versions_encode_to_raw_bytes( |
||||
const grpc_gcp_rpc_protocol_versions* versions, uint8_t* bytes, |
||||
size_t bytes_length); |
||||
|
||||
/**
|
||||
* This method serializes an rpc protocol version and returns serialized rpc |
||||
* versions in grpc slice. |
||||
* |
||||
* - versions: an rpc protocol versions instance. |
||||
* - slice: grpc slice where the serialized result will be written. |
||||
* |
||||
* The method returns true on success and false otherwise. |
||||
*/ |
||||
bool grpc_gcp_rpc_protocol_versions_encode( |
||||
const grpc_gcp_rpc_protocol_versions* versions, grpc_slice* slice); |
||||
|
||||
/**
|
||||
* This method de-serializes input in grpc slice form and stores the result |
||||
* in rpc protocol versions. |
||||
* |
||||
* - slice: a data stream containing a serialized rpc protocol version. |
||||
* - versions: an rpc protocol version instance used to hold de-serialized |
||||
* result. |
||||
* |
||||
* The method returns true on success and false otherwise. |
||||
*/ |
||||
bool grpc_gcp_rpc_protocol_versions_decode( |
||||
grpc_slice slice, grpc_gcp_rpc_protocol_versions* versions); |
||||
|
||||
/**
|
||||
* This method performs a deep copy operation on rpc protocol versions |
||||
* instance. |
||||
* |
||||
* - src: rpc protocol versions instance that needs to be copied. |
||||
* - dst: rpc protocol versions instance that stores the copied result. |
||||
* |
||||
* The method returns true on success and false otherwise. |
||||
*/ |
||||
bool grpc_gcp_rpc_protocol_versions_copy( |
||||
const grpc_gcp_rpc_protocol_versions* src, |
||||
grpc_gcp_rpc_protocol_versions* dst); |
||||
|
||||
/**
|
||||
* This method performs a version check between local and peer rpc protocol |
||||
* versions. |
||||
* |
||||
* - local_versions: local rpc protocol versions instance. |
||||
* - peer_versions: peer rpc protocol versions instance. |
||||
* - highest_common_version: an output parameter that will store the highest |
||||
* common rpc protocol version both parties agreed on. |
||||
* |
||||
* The method returns true if the check passes which means both parties agreed |
||||
* on a common rpc protocol to use, and false otherwise. |
||||
*/ |
||||
bool grpc_gcp_rpc_protocol_versions_check( |
||||
const grpc_gcp_rpc_protocol_versions* local_versions, |
||||
const grpc_gcp_rpc_protocol_versions* peer_versions, |
||||
grpc_gcp_rpc_protocol_versions_version* highest_common_version); |
||||
|
||||
namespace grpc_core { |
||||
namespace internal { |
||||
|
||||
/**
|
||||
* Exposed for testing only. |
||||
* The method returns 0 if v1 = v2, |
||||
* returns 1 if v1 > v2, |
||||
* returns -1 if v1 < v2. |
||||
*/ |
||||
int grpc_gcp_rpc_protocol_version_compare( |
||||
const grpc_gcp_rpc_protocol_versions_version* v1, |
||||
const grpc_gcp_rpc_protocol_versions_version* v2); |
||||
|
||||
} // namespace internal
|
||||
} // namespace grpc_core
|
||||
|
||||
#endif /* GRPC_CORE_TSI_ALTS_HANDSHAKER_TRANSPORT_SECURITY_COMMON_API_H */ |
@ -0,0 +1,180 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2018 gRPC authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
* |
||||
*/ |
||||
|
||||
#include <grpc/support/port_platform.h> |
||||
|
||||
#include "src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_integrity_only_record_protocol.h" |
||||
|
||||
#include <grpc/support/alloc.h> |
||||
#include <grpc/support/log.h> |
||||
|
||||
#include "src/core/lib/slice/slice_internal.h" |
||||
#include "src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_record_protocol_common.h" |
||||
#include "src/core/tsi/alts/zero_copy_frame_protector/alts_iovec_record_protocol.h" |
||||
|
||||
/* Main struct for alts_grpc_integrity_only_record_protocol. */ |
||||
typedef struct alts_grpc_integrity_only_record_protocol { |
||||
alts_grpc_record_protocol base; |
||||
grpc_slice_buffer data_sb; |
||||
unsigned char* tag_buf; |
||||
} alts_grpc_integrity_only_record_protocol; |
||||
|
||||
/* --- alts_grpc_record_protocol methods implementation. --- */ |
||||
|
||||
static tsi_result alts_grpc_integrity_only_protect( |
||||
alts_grpc_record_protocol* rp, grpc_slice_buffer* unprotected_slices, |
||||
grpc_slice_buffer* protected_slices) { |
||||
/* Input sanity check. */ |
||||
if (rp == nullptr || unprotected_slices == nullptr || |
||||
protected_slices == nullptr) { |
||||
gpr_log(GPR_ERROR, |
||||
"Invalid nullptr arguments to alts_grpc_record_protocol protect."); |
||||
return TSI_INVALID_ARGUMENT; |
||||
} |
||||
/* Allocates memory for header and tag slices. */ |
||||
grpc_slice header_slice = GRPC_SLICE_MALLOC(rp->header_length); |
||||
grpc_slice tag_slice = GRPC_SLICE_MALLOC(rp->tag_length); |
||||
/* Calls alts_iovec_record_protocol protect. */ |
||||
char* error_details = nullptr; |
||||
iovec_t header_iovec = {GRPC_SLICE_START_PTR(header_slice), |
||||
GRPC_SLICE_LENGTH(header_slice)}; |
||||
iovec_t tag_iovec = {GRPC_SLICE_START_PTR(tag_slice), |
||||
GRPC_SLICE_LENGTH(tag_slice)}; |
||||
alts_grpc_record_protocol_convert_slice_buffer_to_iovec(rp, |
||||
unprotected_slices); |
||||
grpc_status_code status = alts_iovec_record_protocol_integrity_only_protect( |
||||
rp->iovec_rp, rp->iovec_buf, unprotected_slices->count, header_iovec, |
||||
tag_iovec, &error_details); |
||||
if (status != GRPC_STATUS_OK) { |
||||
gpr_log(GPR_ERROR, "Failed to protect, %s", error_details); |
||||
gpr_free(error_details); |
||||
return TSI_INTERNAL_ERROR; |
||||
} |
||||
/* Appends result to protected_slices. */ |
||||
grpc_slice_buffer_add(protected_slices, header_slice); |
||||
grpc_slice_buffer_move_into(unprotected_slices, protected_slices); |
||||
grpc_slice_buffer_add(protected_slices, tag_slice); |
||||
return TSI_OK; |
||||
} |
||||
|
||||
static tsi_result alts_grpc_integrity_only_unprotect( |
||||
alts_grpc_record_protocol* rp, grpc_slice_buffer* protected_slices, |
||||
grpc_slice_buffer* unprotected_slices) { |
||||
/* Input sanity check. */ |
||||
if (rp == nullptr || protected_slices == nullptr || |
||||
unprotected_slices == nullptr) { |
||||
gpr_log( |
||||
GPR_ERROR, |
||||
"Invalid nullptr arguments to alts_grpc_record_protocol unprotect."); |
||||
return TSI_INVALID_ARGUMENT; |
||||
} |
||||
if (protected_slices->length < rp->header_length + rp->tag_length) { |
||||
gpr_log(GPR_ERROR, "Protected slices do not have sufficient data."); |
||||
return TSI_INVALID_ARGUMENT; |
||||
} |
||||
/* In this method, rp points to alts_grpc_record_protocol struct
|
||||
* and integrity_only_record_protocol points to |
||||
* alts_grpc_integrity_only_record_protocol struct. */ |
||||
alts_grpc_integrity_only_record_protocol* integrity_only_record_protocol = |
||||
reinterpret_cast<alts_grpc_integrity_only_record_protocol*>(rp); |
||||
/* Strips frame header from protected slices. */ |
||||
grpc_slice_buffer_reset_and_unref_internal(&rp->header_sb); |
||||
grpc_slice_buffer_move_first(protected_slices, rp->header_length, |
||||
&rp->header_sb); |
||||
GPR_ASSERT(rp->header_sb.length == rp->header_length); |
||||
iovec_t header_iovec = alts_grpc_record_protocol_get_header_iovec(rp); |
||||
/* Moves protected slices data to data_sb and leaves the remaining tag. */ |
||||
grpc_slice_buffer_reset_and_unref_internal( |
||||
&integrity_only_record_protocol->data_sb); |
||||
grpc_slice_buffer_move_first(protected_slices, |
||||
protected_slices->length - rp->tag_length, |
||||
&integrity_only_record_protocol->data_sb); |
||||
GPR_ASSERT(protected_slices->length == rp->tag_length); |
||||
iovec_t tag_iovec = {nullptr, rp->tag_length}; |
||||
if (protected_slices->count == 1) { |
||||
tag_iovec.iov_base = GRPC_SLICE_START_PTR(protected_slices->slices[0]); |
||||
} else { |
||||
/* Frame tag is in multiple slices, copies the tag bytes from slice
|
||||
* buffer to a single flat buffer. */ |
||||
alts_grpc_record_protocol_copy_slice_buffer( |
||||
protected_slices, integrity_only_record_protocol->tag_buf); |
||||
tag_iovec.iov_base = integrity_only_record_protocol->tag_buf; |
||||
} |
||||
/* Calls alts_iovec_record_protocol unprotect. */ |
||||
char* error_details = nullptr; |
||||
alts_grpc_record_protocol_convert_slice_buffer_to_iovec( |
||||
rp, &integrity_only_record_protocol->data_sb); |
||||
grpc_status_code status = alts_iovec_record_protocol_integrity_only_unprotect( |
||||
rp->iovec_rp, rp->iovec_buf, |
||||
integrity_only_record_protocol->data_sb.count, header_iovec, tag_iovec, |
||||
&error_details); |
||||
if (status != GRPC_STATUS_OK) { |
||||
gpr_log(GPR_ERROR, "Failed to unprotect, %s", error_details); |
||||
gpr_free(error_details); |
||||
return TSI_INTERNAL_ERROR; |
||||
} |
||||
grpc_slice_buffer_reset_and_unref_internal(&rp->header_sb); |
||||
grpc_slice_buffer_reset_and_unref_internal(protected_slices); |
||||
grpc_slice_buffer_move_into(&integrity_only_record_protocol->data_sb, |
||||
unprotected_slices); |
||||
return TSI_OK; |
||||
} |
||||
|
||||
static void alts_grpc_integrity_only_destruct(alts_grpc_record_protocol* rp) { |
||||
if (rp == nullptr) { |
||||
return; |
||||
} |
||||
alts_grpc_integrity_only_record_protocol* integrity_only_rp = |
||||
reinterpret_cast<alts_grpc_integrity_only_record_protocol*>(rp); |
||||
grpc_slice_buffer_destroy_internal(&integrity_only_rp->data_sb); |
||||
gpr_free(integrity_only_rp->tag_buf); |
||||
} |
||||
|
||||
static const alts_grpc_record_protocol_vtable |
||||
alts_grpc_integrity_only_record_protocol_vtable = { |
||||
alts_grpc_integrity_only_protect, alts_grpc_integrity_only_unprotect, |
||||
alts_grpc_integrity_only_destruct}; |
||||
|
||||
tsi_result alts_grpc_integrity_only_record_protocol_create( |
||||
gsec_aead_crypter* crypter, size_t overflow_size, bool is_client, |
||||
bool is_protect, alts_grpc_record_protocol** rp) { |
||||
if (crypter == nullptr || rp == nullptr) { |
||||
gpr_log(GPR_ERROR, |
||||
"Invalid nullptr arguments to alts_grpc_record_protocol create."); |
||||
return TSI_INVALID_ARGUMENT; |
||||
} |
||||
alts_grpc_integrity_only_record_protocol* impl = |
||||
static_cast<alts_grpc_integrity_only_record_protocol*>( |
||||
gpr_zalloc(sizeof(alts_grpc_integrity_only_record_protocol))); |
||||
/* Calls alts_grpc_record_protocol init. */ |
||||
tsi_result result = alts_grpc_record_protocol_init( |
||||
&impl->base, crypter, overflow_size, is_client, |
||||
/*is_integrity_only=*/true, is_protect); |
||||
if (result != TSI_OK) { |
||||
gpr_free(impl); |
||||
return result; |
||||
} |
||||
/* Initializes slice buffer for data_sb. */ |
||||
grpc_slice_buffer_init(&impl->data_sb); |
||||
/* Allocates tag buffer. */ |
||||
impl->tag_buf = |
||||
static_cast<unsigned char*>(gpr_malloc(impl->base.tag_length)); |
||||
impl->base.vtable = &alts_grpc_integrity_only_record_protocol_vtable; |
||||
*rp = &impl->base; |
||||
return TSI_OK; |
||||
} |
@ -0,0 +1,52 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2018 gRPC authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
* |
||||
*/ |
||||
|
||||
#ifndef GRPC_CORE_TSI_ALTS_ZERO_COPY_FRAME_PROTECTOR_ALTS_GRPC_INTEGRITY_ONLY_RECORD_PROTOCOL_H |
||||
#define GRPC_CORE_TSI_ALTS_ZERO_COPY_FRAME_PROTECTOR_ALTS_GRPC_INTEGRITY_ONLY_RECORD_PROTOCOL_H |
||||
|
||||
#include <grpc/support/port_platform.h> |
||||
|
||||
#include <stdbool.h> |
||||
|
||||
#include "src/core/tsi/alts/crypt/gsec.h" |
||||
#include "src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_record_protocol.h" |
||||
|
||||
/**
|
||||
* This method creates an integrity-only alts_grpc_record_protocol instance, |
||||
* given a gsec_aead_crypter instance and a flag indicating if the created |
||||
* instance will be used at the client or server side. The ownership of |
||||
* gsec_aead_crypter instance is transferred to this new object. |
||||
* |
||||
* - crypter: a gsec_aead_crypter instance used to perform AEAD decryption. |
||||
* - overflow_size: overflow size of counter in bytes. |
||||
* - is_client: a flag indicating if the alts_grpc_record_protocol instance will |
||||
* be used at the client or server side. |
||||
* - is_protect: a flag indicating if the alts_grpc_record_protocol instance |
||||
* will be used for protect or unprotect. |
||||
* - rp: an alts_grpc_record_protocol instance to be returned from |
||||
* the method. |
||||
* |
||||
* This method returns TSI_OK in case of success or a specific error code in |
||||
* case of failure. |
||||
*/ |
||||
tsi_result alts_grpc_integrity_only_record_protocol_create( |
||||
gsec_aead_crypter* crypter, size_t overflow_size, bool is_client, |
||||
bool is_protect, alts_grpc_record_protocol** rp); |
||||
|
||||
#endif /* GRPC_CORE_TSI_ALTS_ZERO_COPY_FRAME_PROTECTOR_ALTS_GRPC_INTEGRITY_ONLY_RECORD_PROTOCOL_H \ |
||||
*/ |
@ -0,0 +1,144 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2018 gRPC authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
* |
||||
*/ |
||||
|
||||
#include <grpc/support/port_platform.h> |
||||
|
||||
#include "src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_privacy_integrity_record_protocol.h" |
||||
|
||||
#include <grpc/support/alloc.h> |
||||
#include <grpc/support/log.h> |
||||
|
||||
#include "src/core/lib/slice/slice_internal.h" |
||||
#include "src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_record_protocol_common.h" |
||||
#include "src/core/tsi/alts/zero_copy_frame_protector/alts_iovec_record_protocol.h" |
||||
|
||||
/* Privacy-integrity alts_grpc_record_protocol object uses the same struct
|
||||
* defined in alts_grpc_record_protocol_common.h. */ |
||||
|
||||
/* --- alts_grpc_record_protocol methods implementation. --- */ |
||||
|
||||
static tsi_result alts_grpc_privacy_integrity_protect( |
||||
alts_grpc_record_protocol* rp, grpc_slice_buffer* unprotected_slices, |
||||
grpc_slice_buffer* protected_slices) { |
||||
/* Input sanity check. */ |
||||
if (rp == nullptr || unprotected_slices == nullptr || |
||||
protected_slices == nullptr) { |
||||
gpr_log(GPR_ERROR, |
||||
"Invalid nullptr arguments to alts_grpc_record_protocol protect."); |
||||
return TSI_INVALID_ARGUMENT; |
||||
} |
||||
/* Allocates memory for output frame. In privacy-integrity protect, the
|
||||
* protected frame is stored in a newly allocated buffer. */ |
||||
size_t protected_frame_size = |
||||
unprotected_slices->length + rp->header_length + |
||||
alts_iovec_record_protocol_get_tag_length(rp->iovec_rp); |
||||
grpc_slice protected_slice = GRPC_SLICE_MALLOC(protected_frame_size); |
||||
iovec_t protected_iovec = {GRPC_SLICE_START_PTR(protected_slice), |
||||
GRPC_SLICE_LENGTH(protected_slice)}; |
||||
/* Calls alts_iovec_record_protocol protect. */ |
||||
char* error_details = nullptr; |
||||
alts_grpc_record_protocol_convert_slice_buffer_to_iovec(rp, |
||||
unprotected_slices); |
||||
grpc_status_code status = |
||||
alts_iovec_record_protocol_privacy_integrity_protect( |
||||
rp->iovec_rp, rp->iovec_buf, unprotected_slices->count, |
||||
protected_iovec, &error_details); |
||||
if (status != GRPC_STATUS_OK) { |
||||
gpr_log(GPR_ERROR, "Failed to protect, %s", error_details); |
||||
gpr_free(error_details); |
||||
grpc_slice_unref(protected_slice); |
||||
return TSI_INTERNAL_ERROR; |
||||
} |
||||
grpc_slice_buffer_add(protected_slices, protected_slice); |
||||
grpc_slice_buffer_reset_and_unref_internal(unprotected_slices); |
||||
return TSI_OK; |
||||
} |
||||
|
||||
static tsi_result alts_grpc_privacy_integrity_unprotect( |
||||
alts_grpc_record_protocol* rp, grpc_slice_buffer* protected_slices, |
||||
grpc_slice_buffer* unprotected_slices) { |
||||
/* Input sanity check. */ |
||||
if (rp == nullptr || protected_slices == nullptr || |
||||
unprotected_slices == nullptr) { |
||||
gpr_log( |
||||
GPR_ERROR, |
||||
"Invalid nullptr arguments to alts_grpc_record_protocol unprotect."); |
||||
return TSI_INVALID_ARGUMENT; |
||||
} |
||||
/* Allocates memory for output frame. In privacy-integrity unprotect, the
|
||||
* unprotected data are stored in a newly allocated buffer. */ |
||||
if (protected_slices->length < rp->header_length + rp->tag_length) { |
||||
gpr_log(GPR_ERROR, "Protected slices do not have sufficient data."); |
||||
return TSI_INVALID_ARGUMENT; |
||||
} |
||||
size_t unprotected_frame_size = |
||||
protected_slices->length - rp->header_length - rp->tag_length; |
||||
grpc_slice unprotected_slice = GRPC_SLICE_MALLOC(unprotected_frame_size); |
||||
iovec_t unprotected_iovec = {GRPC_SLICE_START_PTR(unprotected_slice), |
||||
GRPC_SLICE_LENGTH(unprotected_slice)}; |
||||
/* Strips frame header from protected slices. */ |
||||
grpc_slice_buffer_reset_and_unref_internal(&rp->header_sb); |
||||
grpc_slice_buffer_move_first(protected_slices, rp->header_length, |
||||
&rp->header_sb); |
||||
iovec_t header_iovec = alts_grpc_record_protocol_get_header_iovec(rp); |
||||
/* Calls alts_iovec_record_protocol unprotect. */ |
||||
char* error_details = nullptr; |
||||
alts_grpc_record_protocol_convert_slice_buffer_to_iovec(rp, protected_slices); |
||||
grpc_status_code status = |
||||
alts_iovec_record_protocol_privacy_integrity_unprotect( |
||||
rp->iovec_rp, header_iovec, rp->iovec_buf, protected_slices->count, |
||||
unprotected_iovec, &error_details); |
||||
if (status != GRPC_STATUS_OK) { |
||||
gpr_log(GPR_ERROR, "Failed to unprotect, %s", error_details); |
||||
gpr_free(error_details); |
||||
grpc_slice_unref(unprotected_slice); |
||||
return TSI_INTERNAL_ERROR; |
||||
} |
||||
grpc_slice_buffer_reset_and_unref_internal(&rp->header_sb); |
||||
grpc_slice_buffer_reset_and_unref_internal(protected_slices); |
||||
grpc_slice_buffer_add(unprotected_slices, unprotected_slice); |
||||
return TSI_OK; |
||||
} |
||||
|
||||
static const alts_grpc_record_protocol_vtable |
||||
alts_grpc_privacy_integrity_record_protocol_vtable = { |
||||
alts_grpc_privacy_integrity_protect, |
||||
alts_grpc_privacy_integrity_unprotect, nullptr}; |
||||
|
||||
tsi_result alts_grpc_privacy_integrity_record_protocol_create( |
||||
gsec_aead_crypter* crypter, size_t overflow_size, bool is_client, |
||||
bool is_protect, alts_grpc_record_protocol** rp) { |
||||
if (crypter == nullptr || rp == nullptr) { |
||||
gpr_log(GPR_ERROR, |
||||
"Invalid nullptr arguments to alts_grpc_record_protocol create."); |
||||
return TSI_INVALID_ARGUMENT; |
||||
} |
||||
auto* impl = static_cast<alts_grpc_record_protocol*>( |
||||
gpr_zalloc(sizeof(alts_grpc_record_protocol))); |
||||
/* Calls alts_grpc_record_protocol init. */ |
||||
tsi_result result = |
||||
alts_grpc_record_protocol_init(impl, crypter, overflow_size, is_client, |
||||
/*is_integrity_only=*/false, is_protect); |
||||
if (result != TSI_OK) { |
||||
gpr_free(impl); |
||||
return result; |
||||
} |
||||
impl->vtable = &alts_grpc_privacy_integrity_record_protocol_vtable; |
||||
*rp = impl; |
||||
return TSI_OK; |
||||
} |
@ -0,0 +1,49 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2018 gRPC authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
* |
||||
*/ |
||||
|
||||
#ifndef GRPC_CORE_TSI_ALTS_ZERO_COPY_FRAME_PROTECTOR_ALTS_GRPC_PRIVACY_INTEGRITY_RECORD_PROTOCOL_H |
||||
#define GRPC_CORE_TSI_ALTS_ZERO_COPY_FRAME_PROTECTOR_ALTS_GRPC_PRIVACY_INTEGRITY_RECORD_PROTOCOL_H |
||||
|
||||
#include <grpc/support/port_platform.h> |
||||
|
||||
#include <stdbool.h> |
||||
|
||||
#include "src/core/tsi/alts/crypt/gsec.h" |
||||
#include "src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_record_protocol.h" |
||||
|
||||
/**
|
||||
* This method creates a privacy-integrity alts_grpc_record_protocol instance, |
||||
* given a gsec_aead_crypter instance and a flag indicating if the created |
||||
* instance will be used at the client or server side. The ownership of |
||||
* gsec_aead_crypter instance is transferred to this new object. |
||||
* |
||||
* - crypter: a gsec_aead_crypter instance used to perform AEAD decryption. |
||||
* - is_client: a flag indicating if the alts_grpc_record_protocol instance will |
||||
* be used at the client or server side. |
||||
* - rp: an alts_grpc_record_protocol instance to be returned from |
||||
* the method. |
||||
* |
||||
* This method returns TSI_OK in case of success or a specific error code in |
||||
* case of failure. |
||||
*/ |
||||
tsi_result alts_grpc_privacy_integrity_record_protocol_create( |
||||
gsec_aead_crypter* crypter, size_t overflow_size, bool is_client, |
||||
bool is_protect, alts_grpc_record_protocol** rp); |
||||
|
||||
#endif /* GRPC_CORE_TSI_ALTS_ZERO_COPY_FRAME_PROTECTOR_ALTS_GRPC_PRIVACY_INTEGRITY_RECORD_PROTOCOL_H \ |
||||
*/ |
@ -0,0 +1,91 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2018 gRPC authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
* |
||||
*/ |
||||
|
||||
#ifndef GRPC_CORE_TSI_ALTS_ZERO_COPY_FRAME_PROTECTOR_ALTS_GRPC_RECORD_PROTOCOL_H |
||||
#define GRPC_CORE_TSI_ALTS_ZERO_COPY_FRAME_PROTECTOR_ALTS_GRPC_RECORD_PROTOCOL_H |
||||
|
||||
#include <grpc/support/port_platform.h> |
||||
|
||||
#include <grpc/slice_buffer.h> |
||||
|
||||
#include "src/core/tsi/transport_security_interface.h" |
||||
|
||||
/**
|
||||
* This alts_grpc_record_protocol object protects and unprotects a single frame |
||||
* stored in grpc slice buffer with zero or minimized memory copy. |
||||
* Implementations of this object must be thread compatible. |
||||
*/ |
||||
typedef struct alts_grpc_record_protocol alts_grpc_record_protocol; |
||||
|
||||
/**
|
||||
* This methods performs protect operation on unprotected data and appends the |
||||
* protected frame to protected_slices. The caller needs to ensure the length |
||||
* of unprotected data plus the frame overhead is less than or equal to the |
||||
* maximum frame length. The input unprotected data slice buffer will be |
||||
* cleared, although the actual unprotected data bytes are not modified. |
||||
* |
||||
* - self: an alts_grpc_record_protocol instance. |
||||
* - unprotected_slices: the unprotected data to be protected. |
||||
* - protected_slices: slice buffer where the protected frame is appended. |
||||
* |
||||
* This method returns TSI_OK in case of success or a specific error code in |
||||
* case of failure. |
||||
*/ |
||||
tsi_result alts_grpc_record_protocol_protect( |
||||
alts_grpc_record_protocol* self, grpc_slice_buffer* unprotected_slices, |
||||
grpc_slice_buffer* protected_slices); |
||||
|
||||
/**
|
||||
* This methods performs unprotect operation on a full frame of protected data |
||||
* and appends unprotected data to unprotected_slices. It is the caller's |
||||
* responsibility to prepare a full frame of data before calling this method. |
||||
* The input protected frame slice buffer will be cleared, although the actual |
||||
* protected data bytes are not modified. |
||||
* |
||||
* - self: an alts_grpc_record_protocol instance. |
||||
* - protected_slices: a full frame of protected data in grpc slices. |
||||
* - unprotected_slices: slice buffer where unprotected data is appended. |
||||
* |
||||
* This method returns TSI_OK in case of success or a specific error code in |
||||
* case of failure. |
||||
*/ |
||||
tsi_result alts_grpc_record_protocol_unprotect( |
||||
alts_grpc_record_protocol* self, grpc_slice_buffer* protected_slices, |
||||
grpc_slice_buffer* unprotected_slices); |
||||
|
||||
/**
|
||||
* This method returns maximum allowed unprotected data size, given maximum |
||||
* protected frame size. |
||||
* |
||||
* - self: an alts_grpc_record_protocol instance. |
||||
* - max_protected_frame_size: maximum protected frame size. |
||||
* |
||||
* On success, the method returns the maximum allowed unprotected data size. |
||||
* Otherwise, it returns zero. |
||||
*/ |
||||
size_t alts_grpc_record_protocol_max_unprotected_data_size( |
||||
const alts_grpc_record_protocol* self, size_t max_protected_frame_size); |
||||
|
||||
/**
|
||||
* This method destroys an alts_grpc_record_protocol instance by de-allocating |
||||
* all of its occupied memory. |
||||
*/ |
||||
void alts_grpc_record_protocol_destroy(alts_grpc_record_protocol* self); |
||||
|
||||
#endif /* GRPC_CORE_TSI_ALTS_ZERO_COPY_FRAME_PROTECTOR_ALTS_GRPC_RECORD_PROTOCOL_H \ |
||||
*/ |
@ -0,0 +1,173 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2018 gRPC authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
* |
||||
*/ |
||||
|
||||
#include <grpc/support/port_platform.h> |
||||
|
||||
#include "src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_record_protocol_common.h" |
||||
|
||||
#include <string.h> |
||||
|
||||
#include <grpc/support/alloc.h> |
||||
#include <grpc/support/log.h> |
||||
|
||||
#include "src/core/lib/gpr/useful.h" |
||||
#include "src/core/lib/slice/slice_internal.h" |
||||
|
||||
const size_t kInitialIovecBufferSize = 8; |
||||
|
||||
/* Makes sure iovec_buf in alts_grpc_record_protocol is large enough. */ |
||||
static void ensure_iovec_buf_size(alts_grpc_record_protocol* rp, |
||||
const grpc_slice_buffer* sb) { |
||||
GPR_ASSERT(rp != nullptr && sb != nullptr); |
||||
if (sb->count <= rp->iovec_buf_length) { |
||||
return; |
||||
} |
||||
/* At least double the iovec buffer size. */ |
||||
rp->iovec_buf_length = GPR_MAX(sb->count, 2 * rp->iovec_buf_length); |
||||
rp->iovec_buf = static_cast<iovec_t*>( |
||||
gpr_realloc(rp->iovec_buf, rp->iovec_buf_length * sizeof(iovec_t))); |
||||
} |
||||
|
||||
/* --- Implementation of methods defined in tsi_grpc_record_protocol_common.h.
|
||||
* --- */ |
||||
|
||||
void alts_grpc_record_protocol_convert_slice_buffer_to_iovec( |
||||
alts_grpc_record_protocol* rp, const grpc_slice_buffer* sb) { |
||||
GPR_ASSERT(rp != nullptr && sb != nullptr); |
||||
ensure_iovec_buf_size(rp, sb); |
||||
for (size_t i = 0; i < sb->count; i++) { |
||||
rp->iovec_buf[i].iov_base = GRPC_SLICE_START_PTR(sb->slices[i]); |
||||
rp->iovec_buf[i].iov_len = GRPC_SLICE_LENGTH(sb->slices[i]); |
||||
} |
||||
} |
||||
|
||||
void alts_grpc_record_protocol_copy_slice_buffer(const grpc_slice_buffer* src, |
||||
unsigned char* dst) { |
||||
GPR_ASSERT(src != nullptr && dst != nullptr); |
||||
for (size_t i = 0; i < src->count; i++) { |
||||
size_t slice_length = GRPC_SLICE_LENGTH(src->slices[i]); |
||||
memcpy(dst, GRPC_SLICE_START_PTR(src->slices[i]), slice_length); |
||||
dst += slice_length; |
||||
} |
||||
} |
||||
|
||||
iovec_t alts_grpc_record_protocol_get_header_iovec( |
||||
alts_grpc_record_protocol* rp) { |
||||
iovec_t header_iovec = {nullptr, 0}; |
||||
if (rp == nullptr) { |
||||
return header_iovec; |
||||
} |
||||
header_iovec.iov_len = rp->header_length; |
||||
if (rp->header_sb.count == 1) { |
||||
header_iovec.iov_base = GRPC_SLICE_START_PTR(rp->header_sb.slices[0]); |
||||
} else { |
||||
/* Frame header is in multiple slices, copies the header bytes from slice
|
||||
* buffer to a single flat buffer. */ |
||||
alts_grpc_record_protocol_copy_slice_buffer(&rp->header_sb, rp->header_buf); |
||||
header_iovec.iov_base = rp->header_buf; |
||||
} |
||||
return header_iovec; |
||||
} |
||||
|
||||
tsi_result alts_grpc_record_protocol_init(alts_grpc_record_protocol* rp, |
||||
gsec_aead_crypter* crypter, |
||||
size_t overflow_size, bool is_client, |
||||
bool is_integrity_only, |
||||
bool is_protect) { |
||||
if (rp == nullptr || crypter == nullptr) { |
||||
gpr_log(GPR_ERROR, |
||||
"Invalid nullptr arguments to alts_grpc_record_protocol init."); |
||||
return TSI_INVALID_ARGUMENT; |
||||
} |
||||
/* Creates alts_iovec_record_protocol. */ |
||||
char* error_details = nullptr; |
||||
grpc_status_code status = alts_iovec_record_protocol_create( |
||||
crypter, overflow_size, is_client, is_integrity_only, is_protect, |
||||
&rp->iovec_rp, &error_details); |
||||
if (status != GRPC_STATUS_OK) { |
||||
gpr_log(GPR_ERROR, "Failed to create alts_iovec_record_protocol, %s.", |
||||
error_details); |
||||
gpr_free(error_details); |
||||
return TSI_INTERNAL_ERROR; |
||||
} |
||||
/* Allocates header slice buffer. */ |
||||
grpc_slice_buffer_init(&rp->header_sb); |
||||
/* Allocates header buffer. */ |
||||
rp->header_length = alts_iovec_record_protocol_get_header_length(); |
||||
rp->header_buf = static_cast<unsigned char*>(gpr_malloc(rp->header_length)); |
||||
rp->tag_length = alts_iovec_record_protocol_get_tag_length(rp->iovec_rp); |
||||
/* Allocates iovec buffer. */ |
||||
rp->iovec_buf_length = kInitialIovecBufferSize; |
||||
rp->iovec_buf = |
||||
static_cast<iovec_t*>(gpr_malloc(rp->iovec_buf_length * sizeof(iovec_t))); |
||||
return TSI_OK; |
||||
} |
||||
|
||||
/* --- Implementation of methods defined in tsi_grpc_record_protocol.h. --- */ |
||||
tsi_result alts_grpc_record_protocol_protect( |
||||
alts_grpc_record_protocol* self, grpc_slice_buffer* unprotected_slices, |
||||
grpc_slice_buffer* protected_slices) { |
||||
if (grpc_core::ExecCtx::Get() == nullptr || self == nullptr || |
||||
self->vtable == nullptr || unprotected_slices == nullptr || |
||||
protected_slices == nullptr) { |
||||
return TSI_INVALID_ARGUMENT; |
||||
} |
||||
if (self->vtable->protect == nullptr) { |
||||
return TSI_UNIMPLEMENTED; |
||||
} |
||||
return self->vtable->protect(self, unprotected_slices, protected_slices); |
||||
} |
||||
|
||||
tsi_result alts_grpc_record_protocol_unprotect( |
||||
alts_grpc_record_protocol* self, grpc_slice_buffer* protected_slices, |
||||
grpc_slice_buffer* unprotected_slices) { |
||||
if (grpc_core::ExecCtx::Get() == nullptr || self == nullptr || |
||||
self->vtable == nullptr || protected_slices == nullptr || |
||||
unprotected_slices == nullptr) { |
||||
return TSI_INVALID_ARGUMENT; |
||||
} |
||||
if (self->vtable->unprotect == nullptr) { |
||||
return TSI_UNIMPLEMENTED; |
||||
} |
||||
return self->vtable->unprotect(self, protected_slices, unprotected_slices); |
||||
} |
||||
|
||||
void alts_grpc_record_protocol_destroy(alts_grpc_record_protocol* self) { |
||||
if (self == nullptr) { |
||||
return; |
||||
} |
||||
if (self->vtable->destruct != nullptr) { |
||||
self->vtable->destruct(self); |
||||
} |
||||
alts_iovec_record_protocol_destroy(self->iovec_rp); |
||||
grpc_slice_buffer_destroy_internal(&self->header_sb); |
||||
gpr_free(self->header_buf); |
||||
gpr_free(self->iovec_buf); |
||||
gpr_free(self); |
||||
} |
||||
|
||||
/* Integrity-only and privacy-integrity share the same implementation. No need
|
||||
* to call vtable. */ |
||||
size_t alts_grpc_record_protocol_max_unprotected_data_size( |
||||
const alts_grpc_record_protocol* self, size_t max_protected_frame_size) { |
||||
if (self == nullptr) { |
||||
return 0; |
||||
} |
||||
return alts_iovec_record_protocol_max_unprotected_data_size( |
||||
self->iovec_rp, max_protected_frame_size); |
||||
} |
@ -0,0 +1,100 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2018 gRPC authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
* |
||||
*/ |
||||
|
||||
#ifndef GRPC_CORE_TSI_ALTS_ZERO_COPY_FRAME_PROTECTOR_ALTS_GRPC_RECORD_PROTOCOL_COMMON_H |
||||
#define GRPC_CORE_TSI_ALTS_ZERO_COPY_FRAME_PROTECTOR_ALTS_GRPC_RECORD_PROTOCOL_COMMON_H |
||||
|
||||
/**
|
||||
* this file contains alts_grpc_record_protocol internals and internal-only |
||||
* helper functions. The public functions of alts_grpc_record_protocol are |
||||
* defined in the alts_grpc_record_protocol.h. |
||||
*/ |
||||
|
||||
#include <grpc/support/port_platform.h> |
||||
|
||||
#include "src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_record_protocol.h" |
||||
#include "src/core/tsi/alts/zero_copy_frame_protector/alts_iovec_record_protocol.h" |
||||
|
||||
/* V-table for alts_grpc_record_protocol implementations. */ |
||||
typedef struct { |
||||
tsi_result (*protect)(alts_grpc_record_protocol* self, |
||||
grpc_slice_buffer* unprotected_slices, |
||||
grpc_slice_buffer* protected_slices); |
||||
tsi_result (*unprotect)(alts_grpc_record_protocol* self, |
||||
grpc_slice_buffer* protected_slices, |
||||
grpc_slice_buffer* unprotected_slices); |
||||
void (*destruct)(alts_grpc_record_protocol* self); |
||||
} alts_grpc_record_protocol_vtable; |
||||
|
||||
/* Main struct for alts_grpc_record_protocol implementation, shared by both
|
||||
* integrity-only record protocol and privacy-integrity record protocol. |
||||
* Integrity-only record protocol has additional data elements. |
||||
* Privacy-integrity record protocol uses this struct directly. */ |
||||
struct alts_grpc_record_protocol { |
||||
const alts_grpc_record_protocol_vtable* vtable; |
||||
alts_iovec_record_protocol* iovec_rp; |
||||
grpc_slice_buffer header_sb; |
||||
unsigned char* header_buf; |
||||
size_t header_length; |
||||
size_t tag_length; |
||||
iovec_t* iovec_buf; |
||||
size_t iovec_buf_length; |
||||
}; |
||||
|
||||
/**
|
||||
* Converts the slices of input sb into iovec_t's and puts the result into |
||||
* rp->iovec_buf. Note that the actual data are not copied, only |
||||
* pointers and lengths are copied. |
||||
*/ |
||||
void alts_grpc_record_protocol_convert_slice_buffer_to_iovec( |
||||
alts_grpc_record_protocol* rp, const grpc_slice_buffer* sb); |
||||
|
||||
/**
|
||||
* Copies bytes from slice buffer to destination buffer. Caller is responsible |
||||
* for allocating enough memory of destination buffer. This method is used for |
||||
* copying frame header and tag in case they are stored in multiple slices. |
||||
*/ |
||||
void alts_grpc_record_protocol_copy_slice_buffer(const grpc_slice_buffer* src, |
||||
unsigned char* dst); |
||||
|
||||
/**
|
||||
* This method returns an iovec object pointing to the frame header stored in |
||||
* rp->header_sb. If the frame header is stored in multiple slices, |
||||
* this method will copy the bytes in rp->header_sb to |
||||
* rp->header_buf, and return an iovec object pointing to |
||||
* rp->header_buf. |
||||
*/ |
||||
iovec_t alts_grpc_record_protocol_get_header_iovec( |
||||
alts_grpc_record_protocol* rp); |
||||
|
||||
/**
|
||||
* Initializes an alts_grpc_record_protocol object, given a gsec_aead_crypter |
||||
* instance, the overflow size of the counter in bytes, a flag indicating if the |
||||
* object is used for client or server side, a flag indicating if it is used for |
||||
* integrity-only or privacy-integrity mode, and a flag indicating if it is for |
||||
* protect or unprotect. The ownership of gsec_aead_crypter object is |
||||
* transferred to the alts_grpc_record_protocol object. |
||||
*/ |
||||
tsi_result alts_grpc_record_protocol_init(alts_grpc_record_protocol* rp, |
||||
gsec_aead_crypter* crypter, |
||||
size_t overflow_size, bool is_client, |
||||
bool is_integrity_only, |
||||
bool is_protect); |
||||
|
||||
#endif /* GRPC_CORE_TSI_ALTS_ZERO_COPY_FRAME_PROTECTOR_ALTS_GRPC_RECORD_PROTOCOL_COMMON_H \ |
||||
*/ |
@ -0,0 +1,476 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2018 gRPC authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
* |
||||
*/ |
||||
|
||||
#include <grpc/support/port_platform.h> |
||||
|
||||
#include "src/core/tsi/alts/zero_copy_frame_protector/alts_iovec_record_protocol.h" |
||||
|
||||
#include <stdlib.h> |
||||
#include <string.h> |
||||
|
||||
#include <grpc/support/alloc.h> |
||||
#include <grpc/support/log.h> |
||||
|
||||
#include "src/core/tsi/alts/frame_protector/alts_counter.h" |
||||
|
||||
struct alts_iovec_record_protocol { |
||||
alts_counter* ctr; |
||||
gsec_aead_crypter* crypter; |
||||
size_t tag_length; |
||||
bool is_integrity_only; |
||||
bool is_protect; |
||||
}; |
||||
|
||||
/* Copies error message to destination. */ |
||||
static void maybe_copy_error_msg(const char* src, char** dst) { |
||||
if (dst != nullptr && src != nullptr) { |
||||
*dst = static_cast<char*>(gpr_malloc(strlen(src) + 1)); |
||||
memcpy(*dst, src, strlen(src) + 1); |
||||
} |
||||
} |
||||
|
||||
/* Appends error message to destination. */ |
||||
static void maybe_append_error_msg(const char* appendix, char** dst) { |
||||
if (dst != nullptr && appendix != nullptr) { |
||||
int dst_len = static_cast<int>(strlen(*dst)); |
||||
*dst = static_cast<char*>(realloc(*dst, dst_len + strlen(appendix) + 1)); |
||||
assert(*dst != nullptr); |
||||
memcpy(*dst + dst_len, appendix, strlen(appendix) + 1); |
||||
} |
||||
} |
||||
|
||||
/* Use little endian to interpret a string of bytes as uint32_t. */ |
||||
static uint32_t load_32_le(const unsigned char* buffer) { |
||||
return (((uint32_t)buffer[3]) << 24) | (((uint32_t)buffer[2]) << 16) | |
||||
(((uint32_t)buffer[1]) << 8) | ((uint32_t)buffer[0]); |
||||
} |
||||
|
||||
/* Store uint32_t as a string of little endian bytes. */ |
||||
static void store_32_le(uint32_t value, unsigned char* buffer) { |
||||
buffer[3] = (unsigned char)(value >> 24) & 0xFF; |
||||
buffer[2] = (unsigned char)(value >> 16) & 0xFF; |
||||
buffer[1] = (unsigned char)(value >> 8) & 0xFF; |
||||
buffer[0] = (unsigned char)(value)&0xFF; |
||||
} |
||||
|
||||
/* Ensures header and tag iovec have sufficient length. */ |
||||
static grpc_status_code ensure_header_and_tag_length( |
||||
const alts_iovec_record_protocol* rp, iovec_t header, iovec_t tag, |
||||
char** error_details) { |
||||
if (rp == nullptr) { |
||||
return GRPC_STATUS_FAILED_PRECONDITION; |
||||
} |
||||
if (header.iov_base == nullptr) { |
||||
maybe_copy_error_msg("Header is nullptr.", error_details); |
||||
return GRPC_STATUS_INVALID_ARGUMENT; |
||||
} |
||||
if (header.iov_len != alts_iovec_record_protocol_get_header_length()) { |
||||
maybe_copy_error_msg("Header length is incorrect.", error_details); |
||||
return GRPC_STATUS_INVALID_ARGUMENT; |
||||
} |
||||
if (tag.iov_base == nullptr) { |
||||
maybe_copy_error_msg("Tag is nullptr.", error_details); |
||||
return GRPC_STATUS_INVALID_ARGUMENT; |
||||
} |
||||
if (tag.iov_len != rp->tag_length) { |
||||
maybe_copy_error_msg("Tag length is incorrect.", error_details); |
||||
return GRPC_STATUS_INVALID_ARGUMENT; |
||||
} |
||||
return GRPC_STATUS_OK; |
||||
} |
||||
|
||||
/* Increments crypter counter and checks overflow. */ |
||||
static grpc_status_code increment_counter(alts_counter* counter, |
||||
char** error_details) { |
||||
if (counter == nullptr) { |
||||
return GRPC_STATUS_FAILED_PRECONDITION; |
||||
} |
||||
bool is_overflow = false; |
||||
grpc_status_code status = |
||||
alts_counter_increment(counter, &is_overflow, error_details); |
||||
if (status != GRPC_STATUS_OK) { |
||||
return status; |
||||
} |
||||
if (is_overflow) { |
||||
maybe_copy_error_msg("Crypter counter is overflowed.", error_details); |
||||
return GRPC_STATUS_INTERNAL; |
||||
} |
||||
return GRPC_STATUS_OK; |
||||
} |
||||
|
||||
/* Given an array of iovec, computes the total length of buffer. */ |
||||
static size_t get_total_length(const iovec_t* vec, size_t vec_length) { |
||||
size_t total_length = 0; |
||||
for (size_t i = 0; i < vec_length; ++i) { |
||||
total_length += vec[i].iov_len; |
||||
} |
||||
return total_length; |
||||
} |
||||
|
||||
/* Writes frame header given data and tag length. */ |
||||
static grpc_status_code write_frame_header(size_t data_length, |
||||
unsigned char* header, |
||||
char** error_details) { |
||||
if (header == nullptr) { |
||||
maybe_copy_error_msg("Header is nullptr.", error_details); |
||||
return GRPC_STATUS_FAILED_PRECONDITION; |
||||
} |
||||
size_t frame_length = kZeroCopyFrameMessageTypeFieldSize + data_length; |
||||
store_32_le(static_cast<uint32_t>(frame_length), header); |
||||
store_32_le(kZeroCopyFrameMessageType, |
||||
header + kZeroCopyFrameLengthFieldSize); |
||||
return GRPC_STATUS_OK; |
||||
} |
||||
|
||||
/* Verifies frame header given protected data length. */ |
||||
static grpc_status_code verify_frame_header(size_t data_length, |
||||
unsigned char* header, |
||||
char** error_details) { |
||||
if (header == nullptr) { |
||||
maybe_copy_error_msg("Header is nullptr.", error_details); |
||||
return GRPC_STATUS_FAILED_PRECONDITION; |
||||
} |
||||
size_t frame_length = load_32_le(header); |
||||
if (frame_length != kZeroCopyFrameMessageTypeFieldSize + data_length) { |
||||
maybe_copy_error_msg("Bad frame length.", error_details); |
||||
return GRPC_STATUS_INTERNAL; |
||||
} |
||||
size_t message_type = load_32_le(header + kZeroCopyFrameLengthFieldSize); |
||||
if (message_type != kZeroCopyFrameMessageType) { |
||||
maybe_copy_error_msg("Unsupported message type.", error_details); |
||||
return GRPC_STATUS_INTERNAL; |
||||
} |
||||
return GRPC_STATUS_OK; |
||||
} |
||||
|
||||
/* --- alts_iovec_record_protocol methods implementation. --- */ |
||||
|
||||
size_t alts_iovec_record_protocol_get_header_length() { |
||||
return kZeroCopyFrameHeaderSize; |
||||
} |
||||
|
||||
size_t alts_iovec_record_protocol_get_tag_length( |
||||
const alts_iovec_record_protocol* rp) { |
||||
if (rp != nullptr) { |
||||
return rp->tag_length; |
||||
} |
||||
return 0; |
||||
} |
||||
|
||||
size_t alts_iovec_record_protocol_max_unprotected_data_size( |
||||
const alts_iovec_record_protocol* rp, size_t max_protected_frame_size) { |
||||
if (rp == nullptr) { |
||||
return 0; |
||||
} |
||||
size_t overhead_bytes_size = |
||||
kZeroCopyFrameMessageTypeFieldSize + rp->tag_length; |
||||
if (max_protected_frame_size <= overhead_bytes_size) return 0; |
||||
return max_protected_frame_size - overhead_bytes_size; |
||||
} |
||||
|
||||
grpc_status_code alts_iovec_record_protocol_integrity_only_protect( |
||||
alts_iovec_record_protocol* rp, const iovec_t* unprotected_vec, |
||||
size_t unprotected_vec_length, iovec_t header, iovec_t tag, |
||||
char** error_details) { |
||||
/* Input sanity checks. */ |
||||
if (rp == nullptr) { |
||||
maybe_copy_error_msg("Input iovec_record_protocol is nullptr.", |
||||
error_details); |
||||
return GRPC_STATUS_INVALID_ARGUMENT; |
||||
} |
||||
if (!rp->is_integrity_only) { |
||||
maybe_copy_error_msg( |
||||
"Integrity-only operations are not allowed for this object.", |
||||
error_details); |
||||
return GRPC_STATUS_FAILED_PRECONDITION; |
||||
} |
||||
if (!rp->is_protect) { |
||||
maybe_copy_error_msg("Protect operations are not allowed for this object.", |
||||
error_details); |
||||
return GRPC_STATUS_FAILED_PRECONDITION; |
||||
} |
||||
grpc_status_code status = |
||||
ensure_header_and_tag_length(rp, header, tag, error_details); |
||||
if (status != GRPC_STATUS_OK) { |
||||
return status; |
||||
} |
||||
/* Unprotected data should not be zero length. */ |
||||
size_t data_length = |
||||
get_total_length(unprotected_vec, unprotected_vec_length); |
||||
/* Sets frame header. */ |
||||
status = write_frame_header(data_length + rp->tag_length, |
||||
static_cast<unsigned char*>(header.iov_base), |
||||
error_details); |
||||
if (status != GRPC_STATUS_OK) { |
||||
return status; |
||||
} |
||||
/* Computes frame tag by calling AEAD crypter. */ |
||||
size_t bytes_written = 0; |
||||
status = gsec_aead_crypter_encrypt_iovec( |
||||
rp->crypter, alts_counter_get_counter(rp->ctr), |
||||
alts_counter_get_size(rp->ctr), unprotected_vec, unprotected_vec_length, |
||||
/* plaintext_vec = */ nullptr, /* plaintext_vec_length = */ 0, tag, |
||||
&bytes_written, error_details); |
||||
if (status != GRPC_STATUS_OK) { |
||||
return status; |
||||
} |
||||
if (bytes_written != rp->tag_length) { |
||||
maybe_copy_error_msg("Bytes written expects to be the same as tag length.", |
||||
error_details); |
||||
return GRPC_STATUS_INTERNAL; |
||||
} |
||||
/* Increments the crypter counter. */ |
||||
return increment_counter(rp->ctr, error_details); |
||||
} |
||||
|
||||
grpc_status_code alts_iovec_record_protocol_integrity_only_unprotect( |
||||
alts_iovec_record_protocol* rp, const iovec_t* protected_vec, |
||||
size_t protected_vec_length, iovec_t header, iovec_t tag, |
||||
char** error_details) { |
||||
/* Input sanity checks. */ |
||||
if (rp == nullptr) { |
||||
maybe_copy_error_msg("Input iovec_record_protocol is nullptr.", |
||||
error_details); |
||||
return GRPC_STATUS_INVALID_ARGUMENT; |
||||
} |
||||
if (!rp->is_integrity_only) { |
||||
maybe_copy_error_msg( |
||||
"Integrity-only operations are not allowed for this object.", |
||||
error_details); |
||||
return GRPC_STATUS_FAILED_PRECONDITION; |
||||
} |
||||
if (rp->is_protect) { |
||||
maybe_copy_error_msg( |
||||
"Unprotect operations are not allowed for this object.", error_details); |
||||
return GRPC_STATUS_FAILED_PRECONDITION; |
||||
} |
||||
grpc_status_code status = |
||||
ensure_header_and_tag_length(rp, header, tag, error_details); |
||||
if (status != GRPC_STATUS_OK) return status; |
||||
/* Protected data should not be zero length. */ |
||||
size_t data_length = get_total_length(protected_vec, protected_vec_length); |
||||
/* Verifies frame header. */ |
||||
status = verify_frame_header(data_length + rp->tag_length, |
||||
static_cast<unsigned char*>(header.iov_base), |
||||
error_details); |
||||
if (status != GRPC_STATUS_OK) { |
||||
return status; |
||||
} |
||||
/* Verifies frame tag by calling AEAD crypter. */ |
||||
iovec_t plaintext = {nullptr, 0}; |
||||
size_t bytes_written = 0; |
||||
status = gsec_aead_crypter_decrypt_iovec( |
||||
rp->crypter, alts_counter_get_counter(rp->ctr), |
||||
alts_counter_get_size(rp->ctr), protected_vec, protected_vec_length, &tag, |
||||
1, plaintext, &bytes_written, error_details); |
||||
if (status != GRPC_STATUS_OK || bytes_written != 0) { |
||||
maybe_append_error_msg(" Frame tag verification failed.", error_details); |
||||
return GRPC_STATUS_INTERNAL; |
||||
} |
||||
/* Increments the crypter counter. */ |
||||
return increment_counter(rp->ctr, error_details); |
||||
} |
||||
|
||||
grpc_status_code alts_iovec_record_protocol_privacy_integrity_protect( |
||||
alts_iovec_record_protocol* rp, const iovec_t* unprotected_vec, |
||||
size_t unprotected_vec_length, iovec_t protected_frame, |
||||
char** error_details) { |
||||
/* Input sanity checks. */ |
||||
if (rp == nullptr) { |
||||
maybe_copy_error_msg("Input iovec_record_protocol is nullptr.", |
||||
error_details); |
||||
return GRPC_STATUS_INVALID_ARGUMENT; |
||||
} |
||||
if (rp->is_integrity_only) { |
||||
maybe_copy_error_msg( |
||||
"Privacy-integrity operations are not allowed for this object.", |
||||
error_details); |
||||
return GRPC_STATUS_FAILED_PRECONDITION; |
||||
} |
||||
if (!rp->is_protect) { |
||||
maybe_copy_error_msg("Protect operations are not allowed for this object.", |
||||
error_details); |
||||
return GRPC_STATUS_FAILED_PRECONDITION; |
||||
} |
||||
/* Unprotected data should not be zero length. */ |
||||
size_t data_length = |
||||
get_total_length(unprotected_vec, unprotected_vec_length); |
||||
/* Ensures protected frame iovec has sufficient size. */ |
||||
if (protected_frame.iov_base == nullptr) { |
||||
maybe_copy_error_msg("Protected frame is nullptr.", error_details); |
||||
return GRPC_STATUS_INVALID_ARGUMENT; |
||||
} |
||||
if (protected_frame.iov_len != |
||||
alts_iovec_record_protocol_get_header_length() + data_length + |
||||
rp->tag_length) { |
||||
maybe_copy_error_msg("Protected frame size is incorrect.", error_details); |
||||
return GRPC_STATUS_INVALID_ARGUMENT; |
||||
} |
||||
/* Writer frame header. */ |
||||
grpc_status_code status = write_frame_header( |
||||
data_length + rp->tag_length, |
||||
static_cast<unsigned char*>(protected_frame.iov_base), error_details); |
||||
if (status != GRPC_STATUS_OK) { |
||||
return status; |
||||
} |
||||
/* Encrypt unprotected data by calling AEAD crypter. */ |
||||
unsigned char* ciphertext_buffer = |
||||
static_cast<unsigned char*>(protected_frame.iov_base) + |
||||
alts_iovec_record_protocol_get_header_length(); |
||||
iovec_t ciphertext = {ciphertext_buffer, data_length + rp->tag_length}; |
||||
size_t bytes_written = 0; |
||||
status = gsec_aead_crypter_encrypt_iovec( |
||||
rp->crypter, alts_counter_get_counter(rp->ctr), |
||||
alts_counter_get_size(rp->ctr), /* aad_vec = */ nullptr, |
||||
/* aad_vec_length = */ 0, unprotected_vec, unprotected_vec_length, |
||||
ciphertext, &bytes_written, error_details); |
||||
if (status != GRPC_STATUS_OK) { |
||||
return status; |
||||
} |
||||
if (bytes_written != data_length + rp->tag_length) { |
||||
maybe_copy_error_msg( |
||||
"Bytes written expects to be data length plus tag length.", |
||||
error_details); |
||||
return GRPC_STATUS_INTERNAL; |
||||
} |
||||
/* Increments the crypter counter. */ |
||||
return increment_counter(rp->ctr, error_details); |
||||
} |
||||
|
||||
grpc_status_code alts_iovec_record_protocol_privacy_integrity_unprotect( |
||||
alts_iovec_record_protocol* rp, iovec_t header, |
||||
const iovec_t* protected_vec, size_t protected_vec_length, |
||||
iovec_t unprotected_data, char** error_details) { |
||||
/* Input sanity checks. */ |
||||
if (rp == nullptr) { |
||||
maybe_copy_error_msg("Input iovec_record_protocol is nullptr.", |
||||
error_details); |
||||
return GRPC_STATUS_INVALID_ARGUMENT; |
||||
} |
||||
if (rp->is_integrity_only) { |
||||
maybe_copy_error_msg( |
||||
"Privacy-integrity operations are not allowed for this object.", |
||||
error_details); |
||||
return GRPC_STATUS_FAILED_PRECONDITION; |
||||
} |
||||
if (rp->is_protect) { |
||||
maybe_copy_error_msg( |
||||
"Unprotect operations are not allowed for this object.", error_details); |
||||
return GRPC_STATUS_FAILED_PRECONDITION; |
||||
} |
||||
/* Protected data size should be no less than tag size. */ |
||||
size_t protected_data_length = |
||||
get_total_length(protected_vec, protected_vec_length); |
||||
if (protected_data_length < rp->tag_length) { |
||||
maybe_copy_error_msg( |
||||
"Protected data length should be more than the tag length.", |
||||
error_details); |
||||
return GRPC_STATUS_INVALID_ARGUMENT; |
||||
} |
||||
/* Ensures header has sufficient size. */ |
||||
if (header.iov_base == nullptr) { |
||||
maybe_copy_error_msg("Header is nullptr.", error_details); |
||||
return GRPC_STATUS_INVALID_ARGUMENT; |
||||
} |
||||
if (header.iov_len != alts_iovec_record_protocol_get_header_length()) { |
||||
maybe_copy_error_msg("Header length is incorrect.", error_details); |
||||
return GRPC_STATUS_INVALID_ARGUMENT; |
||||
} |
||||
/* Ensures unprotected data iovec has sufficient size. */ |
||||
if (unprotected_data.iov_len != protected_data_length - rp->tag_length) { |
||||
maybe_copy_error_msg("Unprotected data size is incorrect.", error_details); |
||||
return GRPC_STATUS_INVALID_ARGUMENT; |
||||
} |
||||
/* Verify frame header. */ |
||||
grpc_status_code status = verify_frame_header( |
||||
protected_data_length, static_cast<unsigned char*>(header.iov_base), |
||||
error_details); |
||||
if (status != GRPC_STATUS_OK) { |
||||
return status; |
||||
} |
||||
/* Decrypt protected data by calling AEAD crypter. */ |
||||
size_t bytes_written = 0; |
||||
status = gsec_aead_crypter_decrypt_iovec( |
||||
rp->crypter, alts_counter_get_counter(rp->ctr), |
||||
alts_counter_get_size(rp->ctr), /* aad_vec = */ nullptr, |
||||
/* aad_vec_length = */ 0, protected_vec, protected_vec_length, |
||||
unprotected_data, &bytes_written, error_details); |
||||
if (status != GRPC_STATUS_OK) { |
||||
maybe_append_error_msg(" Frame decryption failed.", error_details); |
||||
return GRPC_STATUS_INTERNAL; |
||||
} |
||||
if (bytes_written != protected_data_length - rp->tag_length) { |
||||
maybe_copy_error_msg( |
||||
"Bytes written expects to be protected data length minus tag length.", |
||||
error_details); |
||||
return GRPC_STATUS_INTERNAL; |
||||
} |
||||
/* Increments the crypter counter. */ |
||||
return increment_counter(rp->ctr, error_details); |
||||
} |
||||
|
||||
grpc_status_code alts_iovec_record_protocol_create( |
||||
gsec_aead_crypter* crypter, size_t overflow_size, bool is_client, |
||||
bool is_integrity_only, bool is_protect, alts_iovec_record_protocol** rp, |
||||
char** error_details) { |
||||
if (crypter == nullptr || rp == nullptr) { |
||||
maybe_copy_error_msg( |
||||
"Invalid nullptr arguments to alts_iovec_record_protocol create.", |
||||
error_details); |
||||
return GRPC_STATUS_INVALID_ARGUMENT; |
||||
} |
||||
alts_iovec_record_protocol* impl = static_cast<alts_iovec_record_protocol*>( |
||||
gpr_zalloc(sizeof(alts_iovec_record_protocol))); |
||||
/* Gets counter length. */ |
||||
size_t counter_length = 0; |
||||
grpc_status_code status = |
||||
gsec_aead_crypter_nonce_length(crypter, &counter_length, error_details); |
||||
if (status != GRPC_STATUS_OK) { |
||||
goto cleanup; |
||||
} |
||||
/* Creates counters. */ |
||||
status = |
||||
alts_counter_create(is_protect ? !is_client : is_client, counter_length, |
||||
overflow_size, &impl->ctr, error_details); |
||||
if (status != GRPC_STATUS_OK) { |
||||
goto cleanup; |
||||
} |
||||
/* Gets tag length. */ |
||||
status = |
||||
gsec_aead_crypter_tag_length(crypter, &impl->tag_length, error_details); |
||||
if (status != GRPC_STATUS_OK) { |
||||
goto cleanup; |
||||
} |
||||
impl->crypter = crypter; |
||||
impl->is_integrity_only = is_integrity_only; |
||||
impl->is_protect = is_protect; |
||||
*rp = impl; |
||||
return GRPC_STATUS_OK; |
||||
cleanup: |
||||
alts_counter_destroy(impl->ctr); |
||||
gpr_free(impl); |
||||
return GRPC_STATUS_FAILED_PRECONDITION; |
||||
} |
||||
|
||||
void alts_iovec_record_protocol_destroy(alts_iovec_record_protocol* rp) { |
||||
if (rp != nullptr) { |
||||
alts_counter_destroy(rp->ctr); |
||||
gsec_aead_crypter_destroy(rp->crypter); |
||||
gpr_free(rp); |
||||
} |
||||
} |
@ -0,0 +1,199 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2018 gRPC authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
* |
||||
*/ |
||||
|
||||
#ifndef GRPC_CORE_TSI_ALTS_ZERO_COPY_FRAME_PROTECTOR_ALTS_IOVEC_RECORD_PROTOCOL_H |
||||
#define GRPC_CORE_TSI_ALTS_ZERO_COPY_FRAME_PROTECTOR_ALTS_IOVEC_RECORD_PROTOCOL_H |
||||
|
||||
#include <grpc/support/port_platform.h> |
||||
|
||||
#include <stdbool.h> |
||||
|
||||
#include "src/core/tsi/alts/crypt/gsec.h" |
||||
|
||||
constexpr size_t kZeroCopyFrameMessageType = 0x06; |
||||
constexpr size_t kZeroCopyFrameLengthFieldSize = 4; |
||||
constexpr size_t kZeroCopyFrameMessageTypeFieldSize = 4; |
||||
constexpr size_t kZeroCopyFrameHeaderSize = |
||||
kZeroCopyFrameLengthFieldSize + kZeroCopyFrameMessageTypeFieldSize; |
||||
|
||||
// Limit k on number of frames such that at most 2^(8 * k) frames can be sent.
|
||||
constexpr size_t kAltsRecordProtocolRekeyFrameLimit = 8; |
||||
constexpr size_t kAltsRecordProtocolFrameLimit = 5; |
||||
|
||||
/* An implementation of alts record protocol. The API is thread-compatible. */ |
||||
|
||||
typedef struct iovec iovec_t; |
||||
|
||||
typedef struct alts_iovec_record_protocol alts_iovec_record_protocol; |
||||
|
||||
/**
|
||||
* This method gets the length of record protocol frame header. |
||||
*/ |
||||
size_t alts_iovec_record_protocol_get_header_length(); |
||||
|
||||
/**
|
||||
* This method gets the length of record protocol frame tag. |
||||
* |
||||
* - rp: an alts_iovec_record_protocol instance. |
||||
* |
||||
* On success, the method returns the length of record protocol frame tag. |
||||
* Otherwise, it returns zero. |
||||
*/ |
||||
size_t alts_iovec_record_protocol_get_tag_length( |
||||
const alts_iovec_record_protocol* rp); |
||||
|
||||
/**
|
||||
* This method returns maximum allowed unprotected data size, given maximum |
||||
* protected frame size. |
||||
* |
||||
* - rp: an alts_iovec_record_protocol instance. |
||||
* - max_protected_frame_size: maximum protected frame size. |
||||
* |
||||
* On success, the method returns the maximum allowed unprotected data size. |
||||
* Otherwise, it returns zero. |
||||
*/ |
||||
size_t alts_iovec_record_protocol_max_unprotected_data_size( |
||||
const alts_iovec_record_protocol* rp, size_t max_protected_frame_size); |
||||
|
||||
/**
|
||||
* This method performs integrity-only protect operation on a |
||||
* alts_iovec_record_protocol instance, i.e., compute frame header and tag. The |
||||
* caller needs to allocate the memory for header and tag prior to calling this |
||||
* method. |
||||
* |
||||
* - rp: an alts_iovec_record_protocol instance. |
||||
* - unprotected_vec: an iovec array containing unprotected data. |
||||
* - unprotected_vec_length: the array length of unprotected_vec. |
||||
* - header: an iovec containing the output frame header. |
||||
* - tag: an iovec containing the output frame tag. |
||||
* - error_details: a buffer containing an error message if the method does not |
||||
* function correctly. It is OK to pass nullptr into error_details. |
||||
* |
||||
* On success, the method returns GRPC_STATUS_OK. Otherwise, it returns an |
||||
* error status code along with its details specified in error_details (if |
||||
* error_details is not nullptr). |
||||
*/ |
||||
grpc_status_code alts_iovec_record_protocol_integrity_only_protect( |
||||
alts_iovec_record_protocol* rp, const iovec_t* unprotected_vec, |
||||
size_t unprotected_vec_length, iovec_t header, iovec_t tag, |
||||
char** error_details); |
||||
|
||||
/**
|
||||
* This method performs integrity-only unprotect operation on a |
||||
* alts_iovec_record_protocol instance, i.e., verify frame header and tag. |
||||
* |
||||
* - rp: an alts_iovec_record_protocol instance. |
||||
* - protected_vec: an iovec array containing protected data. |
||||
* - protected_vec_length: the array length of protected_vec. |
||||
* - header: an iovec containing the frame header. |
||||
* - tag: an iovec containing the frame tag. |
||||
* - error_details: a buffer containing an error message if the method does not |
||||
* function correctly. It is OK to pass nullptr into error_details. |
||||
* |
||||
* On success, the method returns GRPC_STATUS_OK. Otherwise, it returns an |
||||
* error status code along with its details specified in error_details (if |
||||
* error_details is not nullptr). |
||||
*/ |
||||
grpc_status_code alts_iovec_record_protocol_integrity_only_unprotect( |
||||
alts_iovec_record_protocol* rp, const iovec_t* protected_vec, |
||||
size_t protected_vec_length, iovec_t header, iovec_t tag, |
||||
char** error_details); |
||||
|
||||
/**
|
||||
* This method performs privacy-integrity protect operation on a |
||||
* alts_iovec_record_protocol instance, i.e., compute a protected frame. The |
||||
* caller needs to allocate the memory for the protected frame prior to calling |
||||
* this method. |
||||
* |
||||
* - rp: an alts_iovec_record_protocol instance. |
||||
* - unprotected_vec: an iovec array containing unprotected data. |
||||
* - unprotected_vec_length: the array length of unprotected_vec. |
||||
* - protected_frame: an iovec containing the output protected frame. |
||||
* - error_details: a buffer containing an error message if the method does not |
||||
* function correctly. It is OK to pass nullptr into error_details. |
||||
* |
||||
* On success, the method returns GRPC_STATUS_OK. Otherwise, it returns an |
||||
* error status code along with its details specified in error_details (if |
||||
* error_details is not nullptr). |
||||
*/ |
||||
grpc_status_code alts_iovec_record_protocol_privacy_integrity_protect( |
||||
alts_iovec_record_protocol* rp, const iovec_t* unprotected_vec, |
||||
size_t unprotected_vec_length, iovec_t protected_frame, |
||||
char** error_details); |
||||
|
||||
/**
|
||||
* This method performs privacy-integrity unprotect operation on a |
||||
* alts_iovec_record_protocol instance given a full protected frame, i.e., |
||||
* compute the unprotected data. The caller needs to allocated the memory for |
||||
* the unprotected data prior to calling this method. |
||||
* |
||||
* - rp: an alts_iovec_record_protocol instance. |
||||
* - header: an iovec containing the frame header. |
||||
* - protected_vec: an iovec array containing protected data including the tag. |
||||
* - protected_vec_length: the array length of protected_vec. |
||||
* - unprotected_data: an iovec containing the output unprotected data. |
||||
* - error_details: a buffer containing an error message if the method does not |
||||
* function correctly. It is OK to pass nullptr into error_details. |
||||
* |
||||
* On success, the method returns GRPC_STATUS_OK. Otherwise, it returns an |
||||
* error status code along with its details specified in error_details (if |
||||
* error_details is not nullptr). |
||||
*/ |
||||
grpc_status_code alts_iovec_record_protocol_privacy_integrity_unprotect( |
||||
alts_iovec_record_protocol* rp, iovec_t header, |
||||
const iovec_t* protected_vec, size_t protected_vec_length, |
||||
iovec_t unprotected_data, char** error_details); |
||||
|
||||
/**
|
||||
* This method creates an alts_iovec_record_protocol instance, given a |
||||
* gsec_aead_crypter instance, a flag indicating if the created instance will be |
||||
* used at the client or server side, and a flag indicating if the created |
||||
* instance will be used for integrity-only mode or privacy-integrity mode. The |
||||
* ownership of gsec_aead_crypter instance is transferred to this new object. |
||||
* |
||||
* - crypter: a gsec_aead_crypter instance used to perform AEAD decryption. |
||||
* - overflow_size: overflow size of counter in bytes. |
||||
* - is_client: a flag indicating if the alts_iovec_record_protocol instance |
||||
* will be used at the client or server side. |
||||
* - is_integrity_only: a flag indicating if the alts_iovec_record_protocol |
||||
* instance will be used for integrity-only or privacy-integrity mode. |
||||
* - is_protect: a flag indicating if the alts_grpc_record_protocol instance |
||||
* will be used for protect or unprotect. |
||||
* - rp: an alts_iovec_record_protocol instance to be returned from |
||||
* the method. |
||||
* - error_details: a buffer containing an error message if the method does not |
||||
* function correctly. It is OK to pass nullptr into error_details. |
||||
* |
||||
* On success, the method returns GRPC_STATUS_OK. Otherwise, it returns an |
||||
* error status code along with its details specified in error_details (if |
||||
* error_details is not nullptr). |
||||
*/ |
||||
grpc_status_code alts_iovec_record_protocol_create( |
||||
gsec_aead_crypter* crypter, size_t overflow_size, bool is_client, |
||||
bool is_integrity_only, bool is_protect, alts_iovec_record_protocol** rp, |
||||
char** error_details); |
||||
|
||||
/**
|
||||
* This method destroys an alts_iovec_record_protocol instance by de-allocating |
||||
* all of its occupied memory. A gsec_aead_crypter instance passed in at |
||||
* gsec_alts_crypter instance creation time will be destroyed in this method. |
||||
*/ |
||||
void alts_iovec_record_protocol_destroy(alts_iovec_record_protocol* rp); |
||||
|
||||
#endif /* GRPC_CORE_TSI_ALTS_ZERO_COPY_FRAME_PROTECTOR_ALTS_IOVEC_RECORD_PROTOCOL_H \ |
||||
*/ |
@ -0,0 +1,295 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2018 gRPC authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
* |
||||
*/ |
||||
|
||||
#include <grpc/support/port_platform.h> |
||||
|
||||
#include "src/core/tsi/alts/zero_copy_frame_protector/alts_zero_copy_grpc_protector.h" |
||||
|
||||
#include <string.h> |
||||
|
||||
#include <grpc/support/alloc.h> |
||||
#include <grpc/support/log.h> |
||||
|
||||
#include "src/core/lib/gpr/useful.h" |
||||
#include "src/core/lib/slice/slice_internal.h" |
||||
#include "src/core/tsi/alts/crypt/gsec.h" |
||||
#include "src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_integrity_only_record_protocol.h" |
||||
#include "src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_privacy_integrity_record_protocol.h" |
||||
#include "src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_record_protocol.h" |
||||
#include "src/core/tsi/alts/zero_copy_frame_protector/alts_iovec_record_protocol.h" |
||||
#include "src/core/tsi/transport_security_grpc.h" |
||||
|
||||
constexpr size_t kMinFrameLength = 1024; |
||||
constexpr size_t kDefaultFrameLength = 16 * 1024; |
||||
constexpr size_t kMaxFrameLength = 1024 * 1024; |
||||
|
||||
/**
|
||||
* Main struct for alts_zero_copy_grpc_protector. |
||||
* We choose to have two alts_grpc_record_protocol objects and two sets of slice |
||||
* buffers: one for protect and the other for unprotect, so that protect and |
||||
* unprotect can be executed in parallel. Implementations of this object must be |
||||
* thread compatible. |
||||
*/ |
||||
typedef struct alts_zero_copy_grpc_protector { |
||||
tsi_zero_copy_grpc_protector base; |
||||
alts_grpc_record_protocol* record_protocol; |
||||
alts_grpc_record_protocol* unrecord_protocol; |
||||
size_t max_protected_frame_size; |
||||
size_t max_unprotected_data_size; |
||||
grpc_slice_buffer unprotected_staging_sb; |
||||
grpc_slice_buffer protected_sb; |
||||
grpc_slice_buffer protected_staging_sb; |
||||
uint32_t parsed_frame_size; |
||||
} alts_zero_copy_grpc_protector; |
||||
|
||||
/**
|
||||
* Given a slice buffer, parses the first 4 bytes little-endian unsigned frame |
||||
* size and returns the total frame size including the frame field. Caller |
||||
* needs to make sure the input slice buffer has at least 4 bytes. Returns true |
||||
* on success and false on failure. |
||||
*/ |
||||
static bool read_frame_size(const grpc_slice_buffer* sb, |
||||
uint32_t* total_frame_size) { |
||||
if (sb == nullptr || sb->length < kZeroCopyFrameLengthFieldSize) { |
||||
return false; |
||||
} |
||||
uint8_t frame_size_buffer[kZeroCopyFrameLengthFieldSize]; |
||||
uint8_t* buf = frame_size_buffer; |
||||
/* Copies the first 4 bytes to a temporary buffer. */ |
||||
size_t remaining = kZeroCopyFrameLengthFieldSize; |
||||
for (size_t i = 0; i < sb->count; i++) { |
||||
size_t slice_length = GRPC_SLICE_LENGTH(sb->slices[i]); |
||||
if (remaining <= slice_length) { |
||||
memcpy(buf, GRPC_SLICE_START_PTR(sb->slices[i]), remaining); |
||||
remaining = 0; |
||||
break; |
||||
} else { |
||||
memcpy(buf, GRPC_SLICE_START_PTR(sb->slices[i]), slice_length); |
||||
buf += slice_length; |
||||
remaining -= slice_length; |
||||
} |
||||
} |
||||
GPR_ASSERT(remaining == 0); |
||||
/* Gets little-endian frame size. */ |
||||
uint32_t frame_size = (((uint32_t)frame_size_buffer[3]) << 24) | |
||||
(((uint32_t)frame_size_buffer[2]) << 16) | |
||||
(((uint32_t)frame_size_buffer[1]) << 8) | |
||||
((uint32_t)frame_size_buffer[0]); |
||||
if (frame_size > kMaxFrameLength) { |
||||
gpr_log(GPR_ERROR, "Frame size is larger than maximum frame size"); |
||||
return false; |
||||
} |
||||
/* Returns frame size including frame length field. */ |
||||
*total_frame_size = |
||||
static_cast<uint32_t>(frame_size + kZeroCopyFrameLengthFieldSize); |
||||
return true; |
||||
} |
||||
|
||||
/**
|
||||
* Creates an alts_grpc_record_protocol object, given key, key size, and flags |
||||
* to indicate whether the record_protocol object uses the rekeying AEAD, |
||||
* whether the object is for client or server, whether the object is for |
||||
* integrity-only or privacy-integrity mode, and whether the object is is used |
||||
* for protect or unprotect. |
||||
*/ |
||||
static tsi_result create_alts_grpc_record_protocol( |
||||
const uint8_t* key, size_t key_size, bool is_rekey, bool is_client, |
||||
bool is_integrity_only, bool is_protect, |
||||
alts_grpc_record_protocol** record_protocol) { |
||||
if (key == nullptr || record_protocol == nullptr) { |
||||
return TSI_INVALID_ARGUMENT; |
||||
} |
||||
grpc_status_code status; |
||||
gsec_aead_crypter* crypter = nullptr; |
||||
char* error_details = nullptr; |
||||
status = gsec_aes_gcm_aead_crypter_create(key, key_size, kAesGcmNonceLength, |
||||
kAesGcmTagLength, is_rekey, |
||||
&crypter, &error_details); |
||||
if (status != GRPC_STATUS_OK) { |
||||
gpr_log(GPR_ERROR, "Failed to create AEAD crypter, %s", error_details); |
||||
gpr_free(error_details); |
||||
return TSI_INTERNAL_ERROR; |
||||
} |
||||
size_t overflow_limit = is_rekey ? kAltsRecordProtocolRekeyFrameLimit |
||||
: kAltsRecordProtocolFrameLimit; |
||||
/* Creates alts_grpc_record_protocol with AEAD crypter ownership transferred.
|
||||
*/ |
||||
tsi_result result = |
||||
is_integrity_only |
||||
? alts_grpc_integrity_only_record_protocol_create( |
||||
crypter, overflow_limit, is_client, is_protect, record_protocol) |
||||
: alts_grpc_privacy_integrity_record_protocol_create( |
||||
crypter, overflow_limit, is_client, is_protect, |
||||
record_protocol); |
||||
if (result != TSI_OK) { |
||||
gsec_aead_crypter_destroy(crypter); |
||||
return result; |
||||
} |
||||
return TSI_OK; |
||||
} |
||||
|
||||
/* --- tsi_zero_copy_grpc_protector methods implementation. --- */ |
||||
|
||||
static tsi_result alts_zero_copy_grpc_protector_protect( |
||||
tsi_zero_copy_grpc_protector* self, grpc_slice_buffer* unprotected_slices, |
||||
grpc_slice_buffer* protected_slices) { |
||||
if (self == nullptr || unprotected_slices == nullptr || |
||||
protected_slices == nullptr) { |
||||
gpr_log(GPR_ERROR, "Invalid nullptr arguments to zero-copy grpc protect."); |
||||
return TSI_INVALID_ARGUMENT; |
||||
} |
||||
alts_zero_copy_grpc_protector* protector = |
||||
reinterpret_cast<alts_zero_copy_grpc_protector*>(self); |
||||
/* Calls alts_grpc_record_protocol protect repeatly. */ |
||||
while (unprotected_slices->length > protector->max_unprotected_data_size) { |
||||
grpc_slice_buffer_move_first(unprotected_slices, |
||||
protector->max_unprotected_data_size, |
||||
&protector->unprotected_staging_sb); |
||||
tsi_result status = alts_grpc_record_protocol_protect( |
||||
protector->record_protocol, &protector->unprotected_staging_sb, |
||||
protected_slices); |
||||
if (status != TSI_OK) { |
||||
return status; |
||||
} |
||||
} |
||||
return alts_grpc_record_protocol_protect( |
||||
protector->record_protocol, unprotected_slices, protected_slices); |
||||
} |
||||
|
||||
static tsi_result alts_zero_copy_grpc_protector_unprotect( |
||||
tsi_zero_copy_grpc_protector* self, grpc_slice_buffer* protected_slices, |
||||
grpc_slice_buffer* unprotected_slices) { |
||||
if (self == nullptr || unprotected_slices == nullptr || |
||||
protected_slices == nullptr) { |
||||
gpr_log(GPR_ERROR, |
||||
"Invalid nullptr arguments to zero-copy grpc unprotect."); |
||||
return TSI_INVALID_ARGUMENT; |
||||
} |
||||
alts_zero_copy_grpc_protector* protector = |
||||
reinterpret_cast<alts_zero_copy_grpc_protector*>(self); |
||||
grpc_slice_buffer_move_into(protected_slices, &protector->protected_sb); |
||||
/* Keep unprotecting each frame if possible. */ |
||||
while (protector->protected_sb.length >= kZeroCopyFrameLengthFieldSize) { |
||||
if (protector->parsed_frame_size == 0) { |
||||
/* We have not parsed frame size yet. Parses frame size. */ |
||||
if (!read_frame_size(&protector->protected_sb, |
||||
&protector->parsed_frame_size)) { |
||||
grpc_slice_buffer_reset_and_unref_internal(&protector->protected_sb); |
||||
return TSI_DATA_CORRUPTED; |
||||
} |
||||
} |
||||
if (protector->protected_sb.length < protector->parsed_frame_size) break; |
||||
/* At this point, protected_sb contains at least one frame of data. */ |
||||
tsi_result status; |
||||
if (protector->protected_sb.length == protector->parsed_frame_size) { |
||||
status = alts_grpc_record_protocol_unprotect(protector->unrecord_protocol, |
||||
&protector->protected_sb, |
||||
unprotected_slices); |
||||
} else { |
||||
grpc_slice_buffer_move_first(&protector->protected_sb, |
||||
protector->parsed_frame_size, |
||||
&protector->protected_staging_sb); |
||||
status = alts_grpc_record_protocol_unprotect( |
||||
protector->unrecord_protocol, &protector->protected_staging_sb, |
||||
unprotected_slices); |
||||
} |
||||
protector->parsed_frame_size = 0; |
||||
if (status != TSI_OK) { |
||||
grpc_slice_buffer_reset_and_unref_internal(&protector->protected_sb); |
||||
return status; |
||||
} |
||||
} |
||||
return TSI_OK; |
||||
} |
||||
|
||||
static void alts_zero_copy_grpc_protector_destroy( |
||||
tsi_zero_copy_grpc_protector* self) { |
||||
if (self == nullptr) { |
||||
return; |
||||
} |
||||
alts_zero_copy_grpc_protector* protector = |
||||
reinterpret_cast<alts_zero_copy_grpc_protector*>(self); |
||||
alts_grpc_record_protocol_destroy(protector->record_protocol); |
||||
alts_grpc_record_protocol_destroy(protector->unrecord_protocol); |
||||
grpc_slice_buffer_destroy_internal(&protector->unprotected_staging_sb); |
||||
grpc_slice_buffer_destroy_internal(&protector->protected_sb); |
||||
grpc_slice_buffer_destroy_internal(&protector->protected_staging_sb); |
||||
gpr_free(protector); |
||||
} |
||||
|
||||
static const tsi_zero_copy_grpc_protector_vtable |
||||
alts_zero_copy_grpc_protector_vtable = { |
||||
alts_zero_copy_grpc_protector_protect, |
||||
alts_zero_copy_grpc_protector_unprotect, |
||||
alts_zero_copy_grpc_protector_destroy}; |
||||
|
||||
tsi_result alts_zero_copy_grpc_protector_create( |
||||
const uint8_t* key, size_t key_size, bool is_rekey, bool is_client, |
||||
bool is_integrity_only, size_t* max_protected_frame_size, |
||||
tsi_zero_copy_grpc_protector** protector) { |
||||
if (grpc_core::ExecCtx::Get() == nullptr || key == nullptr || |
||||
protector == nullptr) { |
||||
gpr_log( |
||||
GPR_ERROR, |
||||
"Invalid nullptr arguments to alts_zero_copy_grpc_protector create."); |
||||
return TSI_INVALID_ARGUMENT; |
||||
} |
||||
/* Creates alts_zero_copy_protector. */ |
||||
alts_zero_copy_grpc_protector* impl = |
||||
static_cast<alts_zero_copy_grpc_protector*>( |
||||
gpr_zalloc(sizeof(alts_zero_copy_grpc_protector))); |
||||
/* Creates alts_grpc_record_protocol objects. */ |
||||
tsi_result status = create_alts_grpc_record_protocol( |
||||
key, key_size, is_rekey, is_client, is_integrity_only, |
||||
/*is_protect=*/true, &impl->record_protocol); |
||||
if (status == TSI_OK) { |
||||
status = create_alts_grpc_record_protocol( |
||||
key, key_size, is_rekey, is_client, is_integrity_only, |
||||
/*is_protect=*/false, &impl->unrecord_protocol); |
||||
if (status == TSI_OK) { |
||||
/* Sets maximum frame size. */ |
||||
size_t max_protected_frame_size_to_set = kDefaultFrameLength; |
||||
if (max_protected_frame_size != nullptr) { |
||||
*max_protected_frame_size = |
||||
GPR_MIN(*max_protected_frame_size, kMaxFrameLength); |
||||
*max_protected_frame_size = |
||||
GPR_MAX(*max_protected_frame_size, kMinFrameLength); |
||||
max_protected_frame_size_to_set = *max_protected_frame_size; |
||||
} |
||||
impl->max_protected_frame_size = max_protected_frame_size_to_set; |
||||
impl->max_unprotected_data_size = |
||||
alts_grpc_record_protocol_max_unprotected_data_size( |
||||
impl->record_protocol, max_protected_frame_size_to_set); |
||||
GPR_ASSERT(impl->max_unprotected_data_size > 0); |
||||
/* Allocates internal slice buffers. */ |
||||
grpc_slice_buffer_init(&impl->unprotected_staging_sb); |
||||
grpc_slice_buffer_init(&impl->protected_sb); |
||||
grpc_slice_buffer_init(&impl->protected_staging_sb); |
||||
impl->parsed_frame_size = 0; |
||||
impl->base.vtable = &alts_zero_copy_grpc_protector_vtable; |
||||
*protector = &impl->base; |
||||
return TSI_OK; |
||||
} |
||||
} |
||||
|
||||
/* Cleanup if create failed. */ |
||||
alts_grpc_record_protocol_destroy(impl->record_protocol); |
||||
alts_grpc_record_protocol_destroy(impl->unrecord_protocol); |
||||
gpr_free(impl); |
||||
return TSI_INTERNAL_ERROR; |
||||
} |
@ -0,0 +1,52 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2018 gRPC authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
* |
||||
*/ |
||||
|
||||
#ifndef GRPC_CORE_TSI_ALTS_ZERO_COPY_FRAME_PROTECTOR_ALTS_ZERO_COPY_GRPC_PROTECTOR_H |
||||
#define GRPC_CORE_TSI_ALTS_ZERO_COPY_FRAME_PROTECTOR_ALTS_ZERO_COPY_GRPC_PROTECTOR_H |
||||
|
||||
#include <grpc/support/port_platform.h> |
||||
|
||||
#include <stdbool.h> |
||||
|
||||
#include "src/core/tsi/transport_security_grpc.h" |
||||
|
||||
/**
|
||||
* This method creates an ALTS zero-copy grpc protector. |
||||
* |
||||
* - key: a symmetric key used to seal/unseal frames. |
||||
* - key_size: the size of symmetric key. |
||||
* - is_rekey: use rekeying AEAD crypter. |
||||
* - is_client: a flag indicating if the protector will be used at client or |
||||
* server side. |
||||
* - is_integrity_only: a flag indicating if the protector instance will be |
||||
* used for integrity-only or privacy-integrity mode. |
||||
* - max_protected_frame_size: an in/out parameter indicating max frame size |
||||
* to be used by the protector. If it is nullptr, the default frame size will |
||||
* be used. Otherwise, the provided frame size will be adjusted (if not |
||||
* falling into a valid frame range) and used. |
||||
* - protector: a pointer to the zero-copy protector returned from the method. |
||||
* |
||||
* This method returns TSI_OK on success or a specific error code otherwise. |
||||
*/ |
||||
tsi_result alts_zero_copy_grpc_protector_create( |
||||
const uint8_t* key, size_t key_size, bool is_rekey, bool is_client, |
||||
bool is_integrity_only, size_t* max_protected_frame_size, |
||||
tsi_zero_copy_grpc_protector** protector); |
||||
|
||||
#endif /* GRPC_CORE_TSI_ALTS_ZERO_COPY_FRAME_PROTECTOR_ALTS_ZERO_COPY_GRPC_PROTECTOR_H \ |
||||
*/ |
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue