[toolchain] Update grpc_ratls toolchain with patching way

Signed-off-by: Qi Zheng <huaiqing.zq@antgroup.com>
This commit is contained in:
Qi Zheng 2023-11-14 15:49:01 +08:00 committed by volcano
parent a82cfb87f0
commit cb1ee85605
28 changed files with 2444 additions and 18844 deletions

File diff suppressed because it is too large Load Diff

@ -0,0 +1,26 @@
From 34ac52eb5d694f0ef0cec30c66c8c417cba9789c Mon Sep 17 00:00:00 2001
From: Qi Zheng <huaiqing.zq@antgroup.com>
Date: Tue, 14 Nov 2023 07:43:41 +0000
Subject: [PATCH] Fixes build with glibc 2.34
---
absl/debugging/failure_signal_handler.cc | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/absl/debugging/failure_signal_handler.cc b/absl/debugging/failure_signal_handler.cc
index a9ed6ef9..3ddebd74 100644
--- a/absl/debugging/failure_signal_handler.cc
+++ b/absl/debugging/failure_signal_handler.cc
@@ -136,7 +136,8 @@ static bool SetupAlternateStackOnce() {
#else
const size_t page_mask = sysconf(_SC_PAGESIZE) - 1;
#endif
- size_t stack_size = (std::max(SIGSTKSZ, 65536) + page_mask) & ~page_mask;
+ size_t stack_size =
+ (std::max<size_t>(SIGSTKSZ, 65536) + page_mask) & ~page_mask;
#if defined(ABSL_HAVE_ADDRESS_SANITIZER) || \
defined(ABSL_HAVE_MEMORY_SANITIZER) || defined(ABSL_HAVE_THREAD_SANITIZER)
// Account for sanitizer instrumentation requiring additional stack space.
--
2.34.1

@ -36,9 +36,6 @@ function build_grpc_ratls() {
# Copy occlum dcap lib first to ease linking
cp ${DCAP_LIB_PATH}/libocclum_dcap.so* ${INSTALL_PREFIX}/lib
# Copy ratls added/updated files to grpc source
cp -rf grpc/${GRPC_VERSION}/* ${GRPC_PATH}/
ABSEIL_PATH=${GRPC_PATH}/third_party/abseil-cpp
# build and install abseil library

@ -5,10 +5,10 @@ source ./env.sh
# Download and update cmake
function dl_and_build_cmake() {
# Ubuntu 20.04 has newer enough cmake version
# Ubuntu 20.04/22.04 has newer enough cmake version
if [ -f "/etc/os-release" ]; then
local os_name=$(cat /etc/os-release)
if [[ $os_name =~ "Ubuntu" && $os_name =~ "20.04" ]]; then
if [[ $os_name =~ "Ubuntu" ]]; then
return
fi
fi
@ -27,9 +27,16 @@ function dl_grpc() {
# GRPC source code
rm -rf ${GRPC_PATH}
git clone https://github.com/grpc/grpc -b ${GRPC_VERSION} ${GRPC_PATH}
pushd ${GRPC_PATH} \
&& git checkout ${GRPC_VERSION} \
&& git submodule update --init
pushd ${GRPC_PATH}
git submodule update --init
# Apply occlum patch
git apply ../0001-Add-Occlum-SGX-tls-function.patch
popd
ABSEIL_PATH=${GRPC_PATH}/third_party/abseil-cpp
pushd $ABSEIL_PATH
# Apply patch
git apply ../../../0001-Fixes-build-with-glibc-2.34.patch
popd
}

@ -1 +0,0 @@
grpc-*

File diff suppressed because it is too large Load Diff

@ -1,64 +0,0 @@
# Copyright (c) 2022 Intel Corporation
#
# 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.
cmake_minimum_required(VERSION 3.5.1)
project(RA-TLS C CXX)
include(../cmake/common.cmake)
# Proto file
get_filename_component(hw_proto "../../protos/ratls.proto" ABSOLUTE)
get_filename_component(hw_proto_path "${hw_proto}" PATH)
# Generated sources
set(hw_proto_srcs "${CMAKE_CURRENT_BINARY_DIR}/ratls.pb.cc")
set(hw_proto_hdrs "${CMAKE_CURRENT_BINARY_DIR}/ratls.pb.h")
set(hw_grpc_srcs "${CMAKE_CURRENT_BINARY_DIR}/ratls.grpc.pb.cc")
set(hw_grpc_hdrs "${CMAKE_CURRENT_BINARY_DIR}/ratls.grpc.pb.h")
add_custom_command(
OUTPUT "${hw_proto_srcs}" "${hw_proto_hdrs}" "${hw_grpc_srcs}" "${hw_grpc_hdrs}"
COMMAND ${_PROTOBUF_PROTOC}
ARGS --grpc_out "${CMAKE_CURRENT_BINARY_DIR}"
--cpp_out "${CMAKE_CURRENT_BINARY_DIR}"
-I "${hw_proto_path}"
--plugin=protoc-gen-grpc="${_GRPC_CPP_PLUGIN_EXECUTABLE}"
"${hw_proto}"
DEPENDS "${hw_proto}")
# Include generated *.pb.h files
include_directories("${CMAKE_CURRENT_BINARY_DIR}")
# hw_grpc_proto
add_library(hw_grpc_proto SHARED
${hw_grpc_srcs}
${hw_grpc_hdrs}
${hw_proto_srcs}
${hw_proto_hdrs})
target_link_libraries(hw_grpc_proto
${_REFLECTION}
${_GRPC_GRPCPP}
${_PROTOBUF_LIBPROTOBUF})
foreach(_target grpc_ratls_client grpc_ratls_server)
add_library(${_target} SHARED "${_target}.cc")
target_link_libraries(${_target}
hw_grpc_proto)
endforeach()
foreach(_target client server)
add_executable(${_target} "${_target}.cc")
target_link_libraries(${_target}
grpc_ratls_${_target})
endforeach()

@ -1,15 +0,0 @@
# gRPC
This directory contains the Makefile and the template manifest for the most
recent version of gRPC (as of this writing, version 3.18.0). This was tested
on a machine with SGX v1 and Ubuntu 18.04.
The Makefile and the template manifest contain extensive comments and are made
self-explanatory. Please review them to gain understanding of Gramine-SGX
and requirements for applications running under Gramine-SGX.
# Quick Start
```
./build.sh
```

@ -1,27 +0,0 @@
#
# Copyright (c) 2022 Intel Corporation
#
# 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.
set -ex
export BUILD_TYPE=Release
export EXP_PATH=`dirname $0`
# build c++ example
cd ${EXP_PATH}
mkdir -p build
cd build
cmake -D CMAKE_PREFIX_PATH=${INSTALL_PREFIX} -D CMAKE_BUILD_TYPE=${BUILD_TYPE} ..
make -j `nproc`
cd -

@ -1,41 +0,0 @@
/*
*
* Copyright (c) 2022 Intel Corporation
*
* 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 <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "../grpc_ratls_client.h"
int main(int argc, char** argv) {
// Parse arguments
if (argc < 4) {
printf("[ERROR] Three arguments must be provided\n\n");
printf("Usage: client <grpc-server addr> <request_name> <secret_file_to_be_saved>\n");
return -1;
}
grpc_ratls_get_secret(
argv[1],
"dynamic_config.json",
argv[2],
argv[3]
);
return 0;
}

@ -1,212 +0,0 @@
/*
*
* Copyright (c) 2022 Intel Corporation
*
* 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 <stdio.h>
#include <string.h>
#include <iostream>
#include <fstream>
#include <grpcpp/grpcpp.h>
#include <grpcpp/security/sgx/sgx_ra_tls.h>
#ifdef BAZEL_BUILD
#include "examples/protos/ratls.grpc.pb.h"
#else
#include "ratls.grpc.pb.h"
#endif
#include "../grpc_ratls_client.h"
using ratls::GrSecret;
using ratls::SecretRequest;
using ratls::SecretReply;
typedef enum {
GRPC_RATLS_SUCCESS = 0, /// Success
GRPC_RATLS_ERR = -1, /// General error
GRPC_RATLS_INVALID_PARAM = -2, /// Invalid parameter
GRPC_RATLS_BUF_ERR = -3, /// Invalid buffer or buffer allocation failure
GRPC_RATLS_NO_SECRET = -4, /// No valid secret
GRPC_RATLS_BUF_TOO_SMALL = -5 /// Buffer is too small
} grpc_ratls_result_t;
// Client
class GrSecretClient {
public:
GrSecretClient(std::shared_ptr<grpc::Channel> channel) : stub_(GrSecret::NewStub(channel)) {}
std::string GetSecret(const std::string& name) {
SecretRequest request;
request.set_name(name);
SecretReply reply;
grpc::ClientContext context;
grpc::Status status = stub_->GetSecret(&context, request, &reply);
if (status.ok()) {
return reply.secret();
} else {
std::cout << status.error_code() << ": " << status.error_message() << std::endl;
return "";
}
}
private:
std::unique_ptr<GrSecret::Stub> stub_;
};
static const unsigned char base64_table[65] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
static size_t base64_decode_len(const char *b64input) {
size_t len = strlen(b64input), padding = 0;
if (b64input[len - 1] == '=' && b64input[len - 2] == '=') { //last two chars are =
padding = 2;
} else if (b64input[len - 1] == '=') { //last char is =
padding = 1;
}
return (len * 3) / 4 - padding;
}
/**
* base64_decode - Base64 decode
*/
void base64_decode(const char *b64input, unsigned char *dest, size_t dest_len) {
unsigned char dtable[256], *pos, block[4], tmp;
size_t i, count, olen;
size_t len = strlen(b64input);
memset(dtable, 0x80, 256);
for (i = 0; i < sizeof(base64_table) - 1; i++) {
dtable[base64_table[i]] = (unsigned char) i;
}
dtable['='] = 0;
olen = base64_decode_len(b64input);
if (olen > dest_len) {
printf("Base64 encoded length %ld is biggeer than %ld\n", olen, dest_len);
return;
}
pos = dest;
count = 0;
for (i = 0; i < len; i++) {
tmp = dtable[(unsigned char)b64input[i]];
if (tmp == 0x80) {
continue;
}
block[count] = tmp;
count++;
if (count == 4) {
*pos++ = (block[0] << 2) | (block[1] >> 4);
*pos++ = (block[1] << 4) | (block[2] >> 2);
*pos++ = (block[2] << 6) | block[3];
count = 0;
}
}
}
static grpc_ratls_result_t grpc_ratls_get_secret_string(
const char *server_addr,
const char *config_json,
const char *name,
std::string* secret_string
)
{
auto cred = grpc::sgx::TlsCredentials(config_json);
auto channel = grpc::CreateChannel(server_addr, cred);
GrSecretClient gr_secret(channel);
std::string secret = gr_secret.GetSecret(name);
// std::cout << "secret received: " << secret << "len: " << secret.length() << std::endl;
if (secret.empty()) {
return GRPC_RATLS_NO_SECRET;
} else {
//Decode From Base64
size_t len = base64_decode_len(secret.c_str());
if (len) {
char *secret_orig = (char *)malloc(len);
if (!secret_orig) {
return GRPC_RATLS_BUF_ERR;
}
base64_decode(secret.c_str(), (unsigned char *)secret_orig, len);
secret_string->assign(secret_orig, secret_orig + len - 1);
free(secret_orig);
return GRPC_RATLS_SUCCESS;
}
return GRPC_RATLS_ERR;
}
}
// Get secret to file
int grpc_ratls_get_secret(
const char *server_addr,
const char *config_json,
const char *name,
const char *secret_file
)
{
std::string secret_string;
grpc_ratls_result_t ret = grpc_ratls_get_secret_string(
server_addr, config_json, name, &secret_string
);
if (ret == GRPC_RATLS_SUCCESS) {
//write to file
std::ofstream myfile;
myfile.open(secret_file);
myfile << secret_string;
myfile.close();
}
return ret;
}
// Get secret to buffer
int grpc_ratls_get_secret_to_buf(
const char *server_addr,
const char *config_json,
const char *name,
char *secret_buf,
unsigned int *buf_len
)
{
std::string secret_string;
grpc_ratls_result_t ret = grpc_ratls_get_secret_string(
server_addr, config_json, name, &secret_string
);
if (ret == GRPC_RATLS_SUCCESS) {
if (*buf_len < secret_string.size()) {
std::cout << "buffer size is smaller than the secret string length " << secret_string.size() << std::endl;;
return GRPC_RATLS_BUF_TOO_SMALL;
}
//write to buffer
memcpy(secret_buf, secret_string.data(), secret_string.size());
*buf_len = secret_string.size();
}
return ret;
}

@ -1,28 +0,0 @@
#ifndef _GRPC_RATLS_CLIENT_H_
#define _GRPC_RATLS_CLIENT_H_
#ifdef __cplusplus
extern "C" {
#endif
// client get secret
extern int grpc_ratls_get_secret(
const char *server_addr, // grpc server address+port, such as "localhost:50051"
const char *config_json, // ratls handshake config json file
const char *name, // secret name to be requested
const char *secret_file // secret file to be saved
);
extern int grpc_ratls_get_secret_to_buf(
const char *server_addr, // grpc server address+port, such as "localhost:50051"
const char *config_json, // ratls handshake config json file
const char *name, // secret name to be requested
char *secret_buf, // buffer to save secret
unsigned int *buf_len // buffer size
);
#ifdef __cplusplus
}
#endif
#endif // _GRPC_RATLS_CLIENT_H_

@ -1,96 +0,0 @@
/*
*
* Copyright (c) 2022 Intel Corporation
*
* 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 <grpcpp/grpcpp.h>
#include <grpcpp/security/sgx/sgx_ra_tls.h>
#include <grpcpp/ext/proto_server_reflection_plugin.h>
#ifdef BAZEL_BUILD
#include "examples/protos/ratls.grpc.pb.h"
#else
#include "ratls.grpc.pb.h"
#endif
#include "../grpc_ratls_server.h"
using ratls::GrSecret;
using ratls::SecretRequest;
using ratls::SecretReply;
// Logic and data behind the server's behavior.
class GrSecretServiceImpl final: public GrSecret::Service {
public:
grpc::Status GetSecret(
grpc::ServerContext* context, const SecretRequest* request, SecretReply* reply) override {
//std::cout << "Request: " << request->name() << std::endl;
auto secret = this->get_secret_string(request->name().c_str());
if (!secret.empty()) {
reply->set_secret(secret);
return grpc::Status::OK;
} else {
return grpc::Status::CANCELLED;
}
}
GrSecretServiceImpl(const char* file) : secret_file(nullptr) {
this->secret_file = file;
}
private:
std::string get_secret_string(const char *name) {
std::string secret = "";
class grpc::sgx::json_engine secret_config(this->secret_file);
auto item = secret_config.get_item(secret_config.get_handle(), name);
if (item) {
secret = secret_config.print_item(item);
}
return secret;
}
const char *secret_file;
};
int grpc_ratls_start_server(
const char *server_addr,
const char *config_json,
const char *secret_json
)
{
GrSecretServiceImpl service(secret_json);
grpc::EnableDefaultHealthCheckService(true);
grpc::reflection::InitProtoReflectionServerBuilderPlugin();
grpc::ServerBuilder builder;
auto creds = grpc::sgx::TlsServerCredentials(config_json);
GPR_ASSERT(creds.get() != nullptr);
builder.AddListeningPort(server_addr, creds);
builder.RegisterService(&service);
std::unique_ptr<grpc::Server> server(builder.BuildAndStart());
std::cout << "Server listening on " << server_addr << std::endl;
server->Wait();
return 0;
}

@ -1,19 +0,0 @@
#ifndef _GRPC_RATLS_SERVER_H_
#define _GRPC_RATLS_SERVER_H_
#ifdef __cplusplus
extern "C" {
#endif
// start server
extern int grpc_ratls_start_server(
const char *server_addr, // grpc server address+port, such as "localhost:50051"
const char *config_json, // ratls handshake config json file
const char *secret_json // secret config json file
);
#ifdef __cplusplus
}
#endif
#endif // _GRPC_RATLS_SERVER_H_

@ -1,37 +0,0 @@
/*
*
* Copyright (c) 2022 Intel Corporation
*
* 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 <stdio.h>
#include <stdlib.h>
#include "../grpc_ratls_server.h"
int main(int argc, char** argv) {
if (argc < 2) {
printf("[ERROR] One argument must be provided\n\n");
printf("Usage: server <grpc-server addr>\n");
return -1;
}
grpc_ratls_start_server(
argv[1],
"dynamic_config.json",
"secret_config.json"
);
return 0;
}

@ -1,38 +0,0 @@
// Copyright (c) 2022 Intel Corporation
//
// 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";
option java_multiple_files = true;
option java_package = "io.grpc.examples.ratls";
option java_outer_classname = "RATLSProto";
option objc_class_prefix = "HLW";
package ratls;
// The GRPC_RATLS secret service definition.
service GrSecret {
// Sends a greeting
rpc GetSecret (SecretRequest) returns (SecretReply) {}
}
// The request message containing the request's name.
message SecretRequest {
string name = 1;
}
// The response message containing the secret (base64 encoded string)
message SecretReply {
string secret = 1;
}

@ -1,83 +0,0 @@
/*
*
* Copyright (c) 2022 Intel Corporation
*
* 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 SGX_RA_TLS_H
#define SGX_RA_TLS_H
#include <memory>
#include <grpcpp/security/credentials.h>
#include <grpcpp/security/server_credentials.h>
#include <cjson/cJSON.h>
namespace grpc {
namespace sgx {
struct sgx_config;
std::vector<std::string> ra_tls_get_key_cert();
void ra_tls_parse_sgx_config(sgx_config sgx_cfg);
void ra_tls_parse_sgx_config(const char* file);
void ra_tls_verify_init();
int ra_tls_auth_check_schedule(void* /* config_user_data */,
grpc_tls_server_authorization_check_arg* arg);
std::shared_ptr<grpc::ChannelCredentials> TlsCredentials(sgx_config sgx_cfg);
std::shared_ptr<grpc::ChannelCredentials> TlsCredentials(const char* sgx_cfg_json);
std::shared_ptr<grpc::ServerCredentials> TlsServerCredentials(sgx_config sgx_cfg);
std::shared_ptr<grpc::ServerCredentials> TlsServerCredentials(const char* sgx_cfg_json);
std::shared_ptr<grpc::Channel> CreateSecureChannel(
string target_str, std::shared_ptr<grpc::ChannelCredentials> channel_creds);
class json_engine {
public:
json_engine();
json_engine(const char*);
~json_engine();
bool open(const char*);
void close();
cJSON* get_handle();
cJSON* get_item(cJSON* obj, const char* item);
char* print_item(cJSON* obj);
bool compare_item(cJSON* obj, const char* item);
private:
cJSON* handle;
};
} // namespace sgx
} // namespace grpc
#endif // SGX_RA_TLS_H

@ -1,67 +0,0 @@
/*
*
* Copyright (c) 2022 Intel Corporation
*
* 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 SGX_RA_TLS_OPTIONS_H
#define SGX_RA_TLS_OPTIONS_H
#include <grpc/grpc_security_constants.h>
#include <grpc/status.h>
#include <grpc/support/log.h>
#include <grpcpp/security/tls_certificate_provider.h>
#include <grpcpp/security/tls_credentials_options.h>
#include <grpcpp/support/config.h>
#include <memory>
#include <vector>
namespace grpc {
namespace sgx {
// Contains configurable options on the client side.
// Client side doesn't need to always use certificate provider. When the
// certificate provider is not set, we will use the root certificates stored
// in the system default locations, and assume client won't provide any
// identity certificates(single side TLS).
// It is used for experimental purposes for now and it is subject to change.
class CredentialsOptions final : public grpc::experimental::TlsCredentialsOptions {
public:
explicit CredentialsOptions() : TlsCredentialsOptions() {}
// Sets option to request the certificates from the client.
// The default is GRPC_SSL_DONT_REQUEST_CLIENT_CERTIFICATE.
void set_cert_request_type(
grpc_ssl_client_certificate_request_type cert_request_type);
// Sets the option to verify the server.
// The default is GRPC_TLS_SERVER_VERIFICATION.
void set_verification_option(
grpc_tls_server_verification_option server_verification_option);
// Sets the custom authorization config.
void set_authorization_check_config(
std::shared_ptr<grpc::experimental::TlsServerAuthorizationCheckConfig>
authorization_check_config);
private:
};
} // namespace sgx
} // namespace grpc
#endif // SGX_RA_TLS_OPTIONS_H

@ -1,133 +0,0 @@
/*
*
* 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/tls/tls_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/channel/channel_args.h"
#include "src/core/lib/security/security_connector/tls/tls_security_connector.h"
#define GRPC_CREDENTIALS_TYPE_TLS "Tls"
namespace {
bool CredentialOptionSanityCheck(const grpc_tls_credentials_options* options,
bool is_client) {
if (options == nullptr) {
gpr_log(GPR_ERROR, "TLS credentials options is nullptr.");
return false;
}
// TODO(ZhenLian): remove this when it is also supported on server side.
// if (!is_client && options->server_authorization_check_config() != nullptr) {
// gpr_log(GPR_INFO,
// "Server's credentials options should not contain server "
// "authorization check config.");
// }
if (options->server_verification_option() != GRPC_TLS_SERVER_VERIFICATION &&
options->server_authorization_check_config() == nullptr) {
gpr_log(GPR_ERROR,
"Should provider custom verifications if bypassing default ones.");
return false;
}
return true;
}
} // namespace
TlsCredentials::TlsCredentials(
grpc_core::RefCountedPtr<grpc_tls_credentials_options> options)
: grpc_channel_credentials(GRPC_CREDENTIALS_TYPE_TLS),
options_(std::move(options)) {}
TlsCredentials::~TlsCredentials() {}
grpc_core::RefCountedPtr<grpc_channel_security_connector>
TlsCredentials::create_security_connector(
grpc_core::RefCountedPtr<grpc_call_credentials> call_creds,
const char* target_name, const grpc_channel_args* args,
grpc_channel_args** new_args) {
const char* overridden_target_name = nullptr;
tsi_ssl_session_cache* ssl_session_cache = nullptr;
for (size_t i = 0; args != nullptr && i < args->num_args; i++) {
grpc_arg* arg = &args->args[i];
if (strcmp(arg->key, GRPC_SSL_TARGET_NAME_OVERRIDE_ARG) == 0 &&
arg->type == GRPC_ARG_STRING) {
overridden_target_name = arg->value.string;
}
if (strcmp(arg->key, GRPC_SSL_SESSION_CACHE_ARG) == 0 &&
arg->type == GRPC_ARG_POINTER) {
ssl_session_cache =
static_cast<tsi_ssl_session_cache*>(arg->value.pointer.p);
}
}
grpc_core::RefCountedPtr<grpc_channel_security_connector> sc =
grpc_core::TlsChannelSecurityConnector::CreateTlsChannelSecurityConnector(
this->Ref(), options_, std::move(call_creds), target_name,
overridden_target_name, ssl_session_cache);
if (sc == nullptr) {
return nullptr;
}
if (args != nullptr) {
grpc_arg new_arg = grpc_channel_arg_string_create(
const_cast<char*>(GRPC_ARG_HTTP2_SCHEME), const_cast<char*>("https"));
*new_args = grpc_channel_args_copy_and_add(args, &new_arg, 1);
}
return sc;
}
TlsServerCredentials::TlsServerCredentials(
grpc_core::RefCountedPtr<grpc_tls_credentials_options> options)
: grpc_server_credentials(GRPC_CREDENTIALS_TYPE_TLS),
options_(std::move(options)) {}
TlsServerCredentials::~TlsServerCredentials() {}
grpc_core::RefCountedPtr<grpc_server_security_connector>
TlsServerCredentials::create_security_connector(
const grpc_channel_args* /* args */) {
return grpc_core::TlsServerSecurityConnector::
CreateTlsServerSecurityConnector(this->Ref(), options_);
}
/** -- Wrapper APIs declared in grpc_security.h -- **/
grpc_channel_credentials* grpc_tls_credentials_create(
grpc_tls_credentials_options* options) {
if (!CredentialOptionSanityCheck(options, true /* is_client */)) {
return nullptr;
}
return new TlsCredentials(
grpc_core::RefCountedPtr<grpc_tls_credentials_options>(options));
}
grpc_server_credentials* grpc_tls_server_credentials_create(
grpc_tls_credentials_options* options) {
if (!CredentialOptionSanityCheck(options, false /* is_client */)) {
return nullptr;
}
return new TlsServerCredentials(
grpc_core::RefCountedPtr<grpc_tls_credentials_options>(options));
}

@ -1,863 +0,0 @@
/*
*
* 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/tls/tls_security_connector.h"
#include <stdbool.h>
#include <string.h>
#include "absl/strings/str_cat.h"
#include "absl/strings/string_view.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/gprpp/host_port.h"
#include "src/core/lib/security/credentials/ssl/ssl_credentials.h"
#include "src/core/lib/security/credentials/tls/tls_credentials.h"
#include "src/core/lib/security/security_connector/ssl_utils.h"
#include "src/core/lib/security/transport/security_handshaker.h"
#include "src/core/lib/slice/slice_internal.h"
#include "src/core/lib/transport/transport.h"
#include "src/core/tsi/ssl_transport_security.h"
#include "src/core/tsi/transport_security.h"
namespace grpc_core {
namespace {
tsi_ssl_pem_key_cert_pair* ConvertToTsiPemKeyCertPair(
const PemKeyCertPairList& cert_pair_list) {
tsi_ssl_pem_key_cert_pair* tsi_pairs = nullptr;
size_t num_key_cert_pairs = cert_pair_list.size();
if (num_key_cert_pairs > 0) {
GPR_ASSERT(cert_pair_list.data() != nullptr);
tsi_pairs = static_cast<tsi_ssl_pem_key_cert_pair*>(
gpr_zalloc(num_key_cert_pairs * sizeof(tsi_ssl_pem_key_cert_pair)));
}
for (size_t i = 0; i < num_key_cert_pairs; i++) {
GPR_ASSERT(!cert_pair_list[i].private_key().empty());
GPR_ASSERT(!cert_pair_list[i].cert_chain().empty());
tsi_pairs[i].cert_chain =
gpr_strdup(cert_pair_list[i].cert_chain().c_str());
tsi_pairs[i].private_key =
gpr_strdup(cert_pair_list[i].private_key().c_str());
}
return tsi_pairs;
}
} // namespace
void gpr_check_free(void* p) {
if (p) {
gpr_free(p);
p = nullptr;
}
}
// -------------------channel security connector-------------------
RefCountedPtr<grpc_channel_security_connector>
TlsChannelSecurityConnector::CreateTlsChannelSecurityConnector(
RefCountedPtr<grpc_channel_credentials> channel_creds,
RefCountedPtr<grpc_tls_credentials_options> options,
RefCountedPtr<grpc_call_credentials> request_metadata_creds,
const char* target_name, const char* overridden_target_name,
tsi_ssl_session_cache* ssl_session_cache) {
if (channel_creds == nullptr) {
gpr_log(GPR_ERROR,
"channel_creds is nullptr in "
"TlsChannelSecurityConnectorCreate()");
return nullptr;
}
if (options == nullptr) {
gpr_log(GPR_ERROR,
"options is nullptr in "
"TlsChannelSecurityConnectorCreate()");
return nullptr;
}
if (target_name == nullptr) {
gpr_log(GPR_ERROR,
"target_name is nullptr in "
"TlsChannelSecurityConnectorCreate()");
return nullptr;
}
return MakeRefCounted<TlsChannelSecurityConnector>(
std::move(channel_creds), std::move(options),
std::move(request_metadata_creds), target_name, overridden_target_name,
ssl_session_cache);
}
TlsChannelSecurityConnector::TlsChannelSecurityConnector(
RefCountedPtr<grpc_channel_credentials> channel_creds,
RefCountedPtr<grpc_tls_credentials_options> options,
RefCountedPtr<grpc_call_credentials> request_metadata_creds,
const char* target_name, const char* overridden_target_name,
tsi_ssl_session_cache* ssl_session_cache)
: grpc_channel_security_connector(GRPC_SSL_URL_SCHEME,
std::move(channel_creds),
std::move(request_metadata_creds)),
options_(std::move(options)),
overridden_target_name_(
overridden_target_name == nullptr ? "" : overridden_target_name),
ssl_session_cache_(ssl_session_cache) {
if (ssl_session_cache_ != nullptr) {
tsi_ssl_session_cache_ref(ssl_session_cache_);
}
check_arg_ = ServerAuthorizationCheckArgCreate(this);
absl::string_view host;
absl::string_view port;
SplitHostPort(target_name, &host, &port);
target_name_ = std::string(host);
// Create a watcher.
auto watcher_ptr = absl::make_unique<TlsChannelCertificateWatcher>(this);
certificate_watcher_ = watcher_ptr.get();
// Register the watcher with the distributor.
grpc_tls_certificate_distributor* distributor =
options_->certificate_distributor();
absl::optional<std::string> watched_root_cert_name;
if (options_->watch_root_cert()) {
watched_root_cert_name = options_->root_cert_name();
}
absl::optional<std::string> watched_identity_cert_name;
if (options_->watch_identity_pair()) {
watched_identity_cert_name = options_->identity_cert_name();
}
// We will use the root certs stored in system default locations if not
// watching root certs on the client side. We will handle this case
// differently here, because "watching a default roots without the identity
// certs" is a valid case(and hence we will need to call
// OnCertificatesChanged), but it requires nothing from the provider, and
// hence no need to register the watcher.
bool use_default_roots = !options_->watch_root_cert();
if (use_default_roots && !options_->watch_identity_pair()) {
watcher_ptr->OnCertificatesChanged(absl::nullopt, absl::nullopt);
} else {
distributor->WatchTlsCertificates(std::move(watcher_ptr),
watched_root_cert_name,
watched_identity_cert_name);
}
}
TlsChannelSecurityConnector::~TlsChannelSecurityConnector() {
if (ssl_session_cache_ != nullptr) {
tsi_ssl_session_cache_unref(ssl_session_cache_);
}
// Cancel all the watchers.
grpc_tls_certificate_distributor* distributor =
options_->certificate_distributor();
if (distributor != nullptr) {
distributor->CancelTlsCertificatesWatch(certificate_watcher_);
}
if (client_handshaker_factory_ != nullptr) {
tsi_ssl_client_handshaker_factory_unref(client_handshaker_factory_);
}
if (check_arg_ != nullptr) {
ServerAuthorizationCheckArgDestroy(check_arg_);
}
}
void TlsChannelSecurityConnector::add_handshakers(
const grpc_channel_args* args, grpc_pollset_set* /*interested_parties*/,
HandshakeManager* handshake_mgr) {
MutexLock lock(&mu_);
if (client_handshaker_factory_ != nullptr) {
// Instantiate TSI handshaker.
tsi_handshaker* tsi_hs = nullptr;
tsi_result result = tsi_ssl_client_handshaker_factory_create_handshaker(
client_handshaker_factory_,
overridden_target_name_.empty() ? target_name_.c_str()
: overridden_target_name_.c_str(),
&tsi_hs);
if (result != TSI_OK) {
gpr_log(GPR_ERROR, "Handshaker creation failed with error %s.",
tsi_result_to_string(result));
return;
}
// Create handshakers.
handshake_mgr->Add(SecurityHandshakerCreate(tsi_hs, this, args));
return;
}
// TODO(ZhenLian): Implement the logic(delegation to
// BlockOnInitialCredentialHandshaker) when certificates are not ready.
gpr_log(GPR_ERROR, "%s not supported yet.",
"Client BlockOnInitialCredentialHandshaker");
}
void TlsChannelSecurityConnector::check_peer(
tsi_peer peer, grpc_endpoint* /*ep*/,
RefCountedPtr<grpc_auth_context>* auth_context,
grpc_closure* on_peer_checked) {
const char* target_name = overridden_target_name_.empty()
? target_name_.c_str()
: overridden_target_name_.c_str();
grpc_error_handle error = grpc_ssl_check_alpn(&peer);
if (error != GRPC_ERROR_NONE) {
ExecCtx::Run(DEBUG_LOCATION, on_peer_checked, error);
tsi_peer_destruct(&peer);
return;
}
*auth_context =
grpc_ssl_peer_to_auth_context(&peer, GRPC_TLS_TRANSPORT_SECURITY_TYPE);
if (options_->server_verification_option() == GRPC_TLS_SERVER_VERIFICATION) {
/* Do the default host name check if specifying the target name. */
error = internal::TlsCheckHostName(target_name, &peer);
if (error != GRPC_ERROR_NONE) {
ExecCtx::Run(DEBUG_LOCATION, on_peer_checked, error);
tsi_peer_destruct(&peer);
return;
}
}
/* Do the custom server authorization check, if specified by the user. */
const grpc_tls_server_authorization_check_config* config =
options_->server_authorization_check_config();
/* If server authorization config is not null, use it to perform
* server authorization check. */
if (config != nullptr) {
const tsi_peer_property* p =
tsi_peer_get_property_by_name(&peer, TSI_X509_PEM_CERT_PROPERTY);
if (p == nullptr) {
error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"Cannot check peer: missing pem cert property.");
} else {
char* peer_pem = static_cast<char*>(gpr_zalloc(p->value.length + 1));
memcpy(peer_pem, p->value.data, p->value.length);
GPR_ASSERT(check_arg_ != nullptr);
check_arg_->peer_cert = check_arg_->peer_cert == nullptr
? gpr_strdup(peer_pem)
: check_arg_->peer_cert;
check_arg_->target_name = check_arg_->target_name == nullptr
? gpr_strdup(target_name)
: check_arg_->target_name;
on_peer_checked_ = on_peer_checked;
gpr_check_free(peer_pem);
const tsi_peer_property* chain = tsi_peer_get_property_by_name(
&peer, TSI_X509_PEM_CERT_CHAIN_PROPERTY);
if (chain != nullptr) {
char* peer_pem_chain =
static_cast<char*>(gpr_zalloc(chain->value.length + 1));
memcpy(peer_pem_chain, chain->value.data, chain->value.length);
check_arg_->peer_cert_full_chain =
check_arg_->peer_cert_full_chain == nullptr
? gpr_strdup(peer_pem_chain)
: check_arg_->peer_cert_full_chain;
gpr_check_free(peer_pem_chain);
}
// TODO(zhenlian) - This should be cleaned up as part of the custom
// verification changes. Fill in the subject alternative names
std::vector<char*> subject_alternative_names;
for (size_t i = 0; i < peer.property_count; i++) {
const tsi_peer_property* prop = &peer.properties[i];
if (strcmp(prop->name,
TSI_X509_SUBJECT_ALTERNATIVE_NAME_PEER_PROPERTY) == 0) {
char* san = new char[prop->value.length + 1];
memcpy(san, prop->value.data, prop->value.length);
san[prop->value.length] = '\0';
subject_alternative_names.emplace_back(san);
}
}
if (check_arg_->subject_alternative_names != nullptr) {
for (size_t i = 0; i < check_arg_->subject_alternative_names_size;
++i) {
delete[] check_arg_->subject_alternative_names[i];
}
delete[] check_arg_->subject_alternative_names;
}
check_arg_->subject_alternative_names_size =
subject_alternative_names.size();
if (subject_alternative_names.empty()) {
check_arg_->subject_alternative_names = nullptr;
} else {
check_arg_->subject_alternative_names =
new char*[check_arg_->subject_alternative_names_size];
for (size_t i = 0; i < check_arg_->subject_alternative_names_size;
++i) {
check_arg_->subject_alternative_names[i] =
subject_alternative_names[i];
}
}
int callback_status = config->Schedule(check_arg_);
/* Server authorization check is handled asynchronously. */
if (callback_status) {
tsi_peer_destruct(&peer);
return;
}
/* Server authorization check is handled synchronously. */
error = ProcessServerAuthorizationCheckResult(check_arg_);
}
}
ExecCtx::Run(DEBUG_LOCATION, on_peer_checked, error);
tsi_peer_destruct(&peer);
}
int TlsChannelSecurityConnector::cmp(
const grpc_security_connector* other_sc) const {
auto* other = reinterpret_cast<const TlsChannelSecurityConnector*>(other_sc);
int c = channel_security_connector_cmp(other);
if (c != 0) {
return c;
}
return grpc_ssl_cmp_target_name(
target_name_.c_str(), other->target_name_.c_str(),
overridden_target_name_.c_str(), other->overridden_target_name_.c_str());
}
bool TlsChannelSecurityConnector::check_call_host(
absl::string_view host, grpc_auth_context* auth_context,
grpc_closure* /*on_call_host_checked*/, grpc_error_handle* error) {
if (options_->server_verification_option() ==
GRPC_TLS_SKIP_HOSTNAME_VERIFICATION ||
options_->server_verification_option() ==
GRPC_TLS_SKIP_ALL_SERVER_VERIFICATION) {
return true;
}
return grpc_ssl_check_call_host(host, target_name_.c_str(),
overridden_target_name_.c_str(), auth_context,
error);
}
void TlsChannelSecurityConnector::cancel_check_call_host(
grpc_closure* /*on_call_host_checked*/, grpc_error_handle error) {
GRPC_ERROR_UNREF(error);
}
void TlsChannelSecurityConnector::TlsChannelCertificateWatcher::
OnCertificatesChanged(absl::optional<absl::string_view> root_certs,
absl::optional<PemKeyCertPairList> key_cert_pairs) {
GPR_ASSERT(security_connector_ != nullptr);
MutexLock lock(&security_connector_->mu_);
if (root_certs.has_value()) {
security_connector_->pem_root_certs_ = root_certs;
}
if (key_cert_pairs.has_value()) {
security_connector_->pem_key_cert_pair_list_ = std::move(key_cert_pairs);
}
const bool root_ready = !security_connector_->options_->watch_root_cert() ||
security_connector_->pem_root_certs_.has_value();
const bool identity_ready =
!security_connector_->options_->watch_identity_pair() ||
security_connector_->pem_key_cert_pair_list_.has_value();
if (root_ready && identity_ready) {
if (security_connector_->UpdateHandshakerFactoryLocked() !=
GRPC_SECURITY_OK) {
gpr_log(GPR_ERROR, "Update handshaker factory failed.");
}
}
}
// TODO(ZhenLian): implement the logic to signal waiting handshakers once
// BlockOnInitialCredentialHandshaker is implemented.
void TlsChannelSecurityConnector::TlsChannelCertificateWatcher::OnError(
grpc_error_handle root_cert_error, grpc_error_handle identity_cert_error) {
if (root_cert_error != GRPC_ERROR_NONE) {
gpr_log(GPR_ERROR,
"TlsChannelCertificateWatcher getting root_cert_error: %s",
grpc_error_std_string(root_cert_error).c_str());
}
if (identity_cert_error != GRPC_ERROR_NONE) {
gpr_log(GPR_ERROR,
"TlsChannelCertificateWatcher getting identity_cert_error: %s",
grpc_error_std_string(identity_cert_error).c_str());
}
GRPC_ERROR_UNREF(root_cert_error);
GRPC_ERROR_UNREF(identity_cert_error);
}
// TODO(ZhenLian): implement the logic to signal waiting handshakers once
// BlockOnInitialCredentialHandshaker is implemented.
grpc_security_status
TlsChannelSecurityConnector::UpdateHandshakerFactoryLocked() {
bool skip_server_certificate_verification =
options_->server_verification_option() ==
GRPC_TLS_SKIP_ALL_SERVER_VERIFICATION;
/* Free the client handshaker factory if exists. */
if (client_handshaker_factory_ != nullptr) {
tsi_ssl_client_handshaker_factory_unref(client_handshaker_factory_);
}
std::string pem_root_certs;
if (pem_root_certs_.has_value()) {
// TODO(ZhenLian): update the underlying TSI layer to use C++ types like
// std::string and absl::string_view to avoid making another copy here.
pem_root_certs = std::string(*pem_root_certs_);
}
tsi_ssl_pem_key_cert_pair* pem_key_cert_pair = nullptr;
if (pem_key_cert_pair_list_.has_value()) {
pem_key_cert_pair = ConvertToTsiPemKeyCertPair(*pem_key_cert_pair_list_);
}
bool use_default_roots = !options_->watch_root_cert();
grpc_security_status status = grpc_ssl_tsi_client_handshaker_factory_init(
pem_key_cert_pair,
pem_root_certs.empty() || use_default_roots ? nullptr
: pem_root_certs.c_str(),
skip_server_certificate_verification,
grpc_get_tsi_tls_version(options_->min_tls_version()),
grpc_get_tsi_tls_version(options_->max_tls_version()), ssl_session_cache_,
&client_handshaker_factory_);
/* Free memory. */
if (pem_key_cert_pair != nullptr) {
grpc_tsi_ssl_pem_key_cert_pairs_destroy(pem_key_cert_pair, 1);
}
return status;
}
void TlsChannelSecurityConnector::ServerAuthorizationCheckDone(
grpc_tls_server_authorization_check_arg* arg) {
GPR_ASSERT(arg != nullptr);
ExecCtx exec_ctx;
grpc_error_handle error = ProcessServerAuthorizationCheckResult(arg);
TlsChannelSecurityConnector* connector =
static_cast<TlsChannelSecurityConnector*>(arg->cb_user_data);
ExecCtx::Run(DEBUG_LOCATION, connector->on_peer_checked_, error);
}
grpc_error_handle
TlsChannelSecurityConnector::ProcessServerAuthorizationCheckResult(
grpc_tls_server_authorization_check_arg* arg) {
grpc_error_handle error = GRPC_ERROR_NONE;
/* Server authorization check is cancelled by caller. */
if (arg->status == GRPC_STATUS_CANCELLED) {
error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(
absl::StrCat("Server authorization check is cancelled by the caller "
"with error: ",
arg->error_details->error_details())
.c_str());
} else if (arg->status == GRPC_STATUS_OK) {
/* Server authorization check completed successfully but returned check
* failure. */
if (!arg->success) {
error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(
absl::StrCat("Server authorization check failed with error: ",
arg->error_details->error_details())
.c_str());
}
/* Server authorization check did not complete correctly. */
} else {
error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(
absl::StrCat(
"Server authorization check did not finish correctly with error: ",
arg->error_details->error_details())
.c_str());
}
return error;
}
grpc_tls_server_authorization_check_arg*
TlsChannelSecurityConnector::ServerAuthorizationCheckArgCreate(
void* user_data) {
grpc_tls_server_authorization_check_arg* arg =
new grpc_tls_server_authorization_check_arg();
arg->target_name = nullptr;
arg->peer_cert = nullptr;
arg->peer_cert_full_chain = nullptr;
arg->subject_alternative_names = nullptr;
arg->subject_alternative_names_size = 0;
arg->error_details = new grpc_tls_error_details();
arg->cb = ServerAuthorizationCheckDone;
arg->cb_user_data = user_data;
arg->status = GRPC_STATUS_OK;
return arg;
}
void TlsChannelSecurityConnector::ServerAuthorizationCheckArgDestroy(
grpc_tls_server_authorization_check_arg* arg) {
if (arg == nullptr) {
return;
}
gpr_check_free(const_cast<char*>(arg->target_name));
gpr_check_free(const_cast<char*>(arg->peer_cert));
gpr_check_free(const_cast<char*>(arg->peer_cert_full_chain));
for (size_t i = 0; i < arg->subject_alternative_names_size; ++i) {
delete[] arg->subject_alternative_names[i];
}
delete[] arg->subject_alternative_names;
delete arg->error_details;
if (arg->destroy_context != nullptr) {
arg->destroy_context(arg->context);
}
delete arg;
arg = nullptr;
}
// -------------------server security connector-------------------
RefCountedPtr<grpc_server_security_connector>
TlsServerSecurityConnector::CreateTlsServerSecurityConnector(
RefCountedPtr<grpc_server_credentials> server_creds,
RefCountedPtr<grpc_tls_credentials_options> options) {
if (server_creds == nullptr) {
gpr_log(GPR_ERROR,
"server_creds is nullptr in "
"TlsServerSecurityConnectorCreate()");
return nullptr;
}
if (options == nullptr) {
gpr_log(GPR_ERROR,
"options is nullptr in "
"TlsServerSecurityConnectorCreate()");
return nullptr;
}
return MakeRefCounted<TlsServerSecurityConnector>(std::move(server_creds),
std::move(options));
}
void TlsServerSecurityConnector::ClientAuthorizationCheckDone(
grpc_tls_server_authorization_check_arg* arg) {
GPR_ASSERT(arg != nullptr);
ExecCtx exec_ctx;
grpc_error_handle error = ProcessClientAuthorizationCheckResult(arg);
TlsServerSecurityConnector* connector =
static_cast<TlsServerSecurityConnector*>(arg->cb_user_data);
ExecCtx::Run(DEBUG_LOCATION, connector->on_peer_checked_, error);
}
grpc_error_handle
TlsServerSecurityConnector::ProcessClientAuthorizationCheckResult(
grpc_tls_server_authorization_check_arg* arg) {
grpc_error_handle error = GRPC_ERROR_NONE;
/* Client authorization check is cancelled by caller. */
if (arg->status == GRPC_STATUS_CANCELLED) {
error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(
absl::StrCat("Client authorization check is cancelled by the caller "
"with error: ",
arg->error_details->error_details())
.c_str());
} else if (arg->status == GRPC_STATUS_OK) {
/* Client authorization check completed successfully but returned check
* failure. */
if (!arg->success) {
error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(
absl::StrCat("Client authorization check failed with error: ",
arg->error_details->error_details())
.c_str());
}
/* Client authorization check did not complete correctly. */
} else {
error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(
absl::StrCat(
"Client authorization check did not finish correctly with error: ",
arg->error_details->error_details())
.c_str());
}
return error;
}
grpc_tls_server_authorization_check_arg*
TlsServerSecurityConnector::ClientAuthorizationCheckArgCreate(
void* user_data) {
grpc_tls_server_authorization_check_arg* arg =
new grpc_tls_server_authorization_check_arg();
arg->target_name = nullptr;
arg->peer_cert = nullptr;
arg->peer_cert_full_chain = nullptr;
arg->subject_alternative_names = nullptr;
arg->subject_alternative_names_size = 0;
arg->error_details = new grpc_tls_error_details();
arg->cb = ClientAuthorizationCheckDone;
arg->cb_user_data = user_data;
arg->status = GRPC_STATUS_OK;
return arg;
}
void TlsServerSecurityConnector::ClientAuthorizationCheckArgDestroy(
grpc_tls_server_authorization_check_arg* arg) {
if (arg == nullptr) {
return;
}
gpr_check_free(const_cast<char*>(arg->target_name));
gpr_check_free(const_cast<char*>(arg->peer_cert));
gpr_check_free(const_cast<char*>(arg->peer_cert_full_chain));
for (size_t i = 0; i < arg->subject_alternative_names_size; ++i) {
delete[] arg->subject_alternative_names[i];
}
delete[] arg->subject_alternative_names;
delete arg->error_details;
if (arg->destroy_context != nullptr) {
arg->destroy_context(arg->context);
}
delete arg;
arg = nullptr;
}
TlsServerSecurityConnector::TlsServerSecurityConnector(
RefCountedPtr<grpc_server_credentials> server_creds,
RefCountedPtr<grpc_tls_credentials_options> options)
: grpc_server_security_connector(GRPC_SSL_URL_SCHEME,
std::move(server_creds)),
options_(std::move(options)) {
check_arg_ = ClientAuthorizationCheckArgCreate(this);
// Create a watcher.
auto watcher_ptr = absl::make_unique<TlsServerCertificateWatcher>(this);
certificate_watcher_ = watcher_ptr.get();
// Register the watcher with the distributor.
grpc_tls_certificate_distributor* distributor =
options_->certificate_distributor();
absl::optional<std::string> watched_root_cert_name;
if (options_->watch_root_cert()) {
watched_root_cert_name = options_->root_cert_name();
}
absl::optional<std::string> watched_identity_cert_name;
if (options_->watch_identity_pair()) {
watched_identity_cert_name = options_->identity_cert_name();
}
// Server side won't use default system roots at any time.
distributor->WatchTlsCertificates(std::move(watcher_ptr),
watched_root_cert_name,
watched_identity_cert_name);
}
TlsServerSecurityConnector::~TlsServerSecurityConnector() {
// Cancel all the watchers.
grpc_tls_certificate_distributor* distributor =
options_->certificate_distributor();
if (distributor != nullptr) {
distributor->CancelTlsCertificatesWatch(certificate_watcher_);
}
if (server_handshaker_factory_ != nullptr) {
tsi_ssl_server_handshaker_factory_unref(server_handshaker_factory_);
}
if (check_arg_ != nullptr) {
ClientAuthorizationCheckArgDestroy(check_arg_);
}
}
void TlsServerSecurityConnector::add_handshakers(
const grpc_channel_args* args, grpc_pollset_set* /*interested_parties*/,
HandshakeManager* handshake_mgr) {
MutexLock lock(&mu_);
if (server_handshaker_factory_ != nullptr) {
// Instantiate TSI handshaker.
tsi_handshaker* tsi_hs = nullptr;
tsi_result result = tsi_ssl_server_handshaker_factory_create_handshaker(
server_handshaker_factory_, &tsi_hs);
if (result != TSI_OK) {
gpr_log(GPR_ERROR, "Handshaker creation failed with error %s.",
tsi_result_to_string(result));
return;
}
// Create handshakers.
handshake_mgr->Add(SecurityHandshakerCreate(tsi_hs, this, args));
return;
}
// TODO(ZhenLian): Implement the logic(delegation to
// BlockOnInitialCredentialHandshaker) when certificates are not ready.
gpr_log(GPR_ERROR, "%s not supported yet.",
"Server BlockOnInitialCredentialHandshaker");
}
void TlsServerSecurityConnector::check_peer(
tsi_peer peer, grpc_endpoint* /*ep*/,
RefCountedPtr<grpc_auth_context>* auth_context,
grpc_closure* on_peer_checked) {
grpc_error_handle error = grpc_ssl_check_alpn(&peer);
if (error != GRPC_ERROR_NONE) {
ExecCtx::Run(DEBUG_LOCATION, on_peer_checked, error);
tsi_peer_destruct(&peer);
return;
}
*auth_context =
grpc_ssl_peer_to_auth_context(&peer, GRPC_TLS_TRANSPORT_SECURITY_TYPE);
if (options_->server_verification_option() == GRPC_TLS_SERVER_VERIFICATION) {
/* Do the default host name check if specifying the target name. */
error = internal::TlsCheckHostName("", &peer);
if (error != GRPC_ERROR_NONE) {
ExecCtx::Run(DEBUG_LOCATION, on_peer_checked, error);
tsi_peer_destruct(&peer);
return;
}
}
/* Do the custom client authorization check, if specified by the user. */
const grpc_tls_server_authorization_check_config* config =
options_->server_authorization_check_config();
/* If client authorization config is not null, use it to perform
* client authorization check. */
if (config != nullptr) {
const tsi_peer_property* p =
tsi_peer_get_property_by_name(&peer, TSI_X509_PEM_CERT_PROPERTY);
if (p == nullptr) {
error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"Cannot check peer: missing pem cert property.");
} else {
char* peer_pem = static_cast<char*>(gpr_zalloc(p->value.length + 1));
memcpy(peer_pem, p->value.data, p->value.length);
GPR_ASSERT(check_arg_ != nullptr);
check_arg_->peer_cert = gpr_strdup(peer_pem);
check_arg_->target_name = gpr_strdup("");
on_peer_checked_ = on_peer_checked;
gpr_check_free(peer_pem);
const tsi_peer_property* chain = tsi_peer_get_property_by_name(
&peer, TSI_X509_PEM_CERT_CHAIN_PROPERTY);
if (chain != nullptr) {
char* peer_pem_chain =
static_cast<char*>(gpr_zalloc(chain->value.length + 1));
memcpy(peer_pem_chain, chain->value.data, chain->value.length);
check_arg_->peer_cert_full_chain =
check_arg_->peer_cert_full_chain == nullptr
? gpr_strdup(peer_pem_chain)
: check_arg_->peer_cert_full_chain;
gpr_check_free(peer_pem_chain);
}
// TODO(zhenlian) - This should be cleaned up as part of the custom
// verification changes. Fill in the subject alternative names
std::vector<char*> subject_alternative_names;
for (size_t i = 0; i < peer.property_count; i++) {
const tsi_peer_property* prop = &peer.properties[i];
if (strcmp(prop->name,
TSI_X509_SUBJECT_ALTERNATIVE_NAME_PEER_PROPERTY) == 0) {
char* san = new char[prop->value.length + 1];
memcpy(san, prop->value.data, prop->value.length);
san[prop->value.length] = '\0';
subject_alternative_names.emplace_back(san);
}
}
if (check_arg_->subject_alternative_names != nullptr) {
for (size_t i = 0; i < check_arg_->subject_alternative_names_size;
++i) {
delete[] check_arg_->subject_alternative_names[i];
}
delete[] check_arg_->subject_alternative_names;
}
check_arg_->subject_alternative_names_size =
subject_alternative_names.size();
if (subject_alternative_names.empty()) {
check_arg_->subject_alternative_names = nullptr;
} else {
check_arg_->subject_alternative_names =
new char*[check_arg_->subject_alternative_names_size];
for (size_t i = 0; i < check_arg_->subject_alternative_names_size;
++i) {
check_arg_->subject_alternative_names[i] =
subject_alternative_names[i];
}
}
int callback_status = config->Schedule(check_arg_);
/* Client authorization check is handled asynchronously. */
if (callback_status) {
tsi_peer_destruct(&peer);
return;
}
/* Client authorization check is handled synchronously. */
error = ProcessClientAuthorizationCheckResult(check_arg_);
}
}
ExecCtx::Run(DEBUG_LOCATION, on_peer_checked, error);
tsi_peer_destruct(&peer);
}
int TlsServerSecurityConnector::cmp(
const grpc_security_connector* other) const {
return server_security_connector_cmp(
static_cast<const grpc_server_security_connector*>(other));
}
void TlsServerSecurityConnector::TlsServerCertificateWatcher::
OnCertificatesChanged(absl::optional<absl::string_view> root_certs,
absl::optional<PemKeyCertPairList> key_cert_pairs) {
GPR_ASSERT(security_connector_ != nullptr);
MutexLock lock(&security_connector_->mu_);
if (root_certs.has_value()) {
security_connector_->pem_root_certs_ = root_certs;
}
if (key_cert_pairs.has_value()) {
security_connector_->pem_key_cert_pair_list_ = std::move(key_cert_pairs);
}
bool root_being_watched = security_connector_->options_->watch_root_cert();
bool root_has_value = security_connector_->pem_root_certs_.has_value();
bool identity_being_watched =
security_connector_->options_->watch_identity_pair();
bool identity_has_value =
security_connector_->pem_key_cert_pair_list_.has_value();
if ((root_being_watched && root_has_value && identity_being_watched &&
identity_has_value) ||
(root_being_watched && root_has_value && !identity_being_watched) ||
(!root_being_watched && identity_being_watched && identity_has_value)) {
if (security_connector_->UpdateHandshakerFactoryLocked() !=
GRPC_SECURITY_OK) {
gpr_log(GPR_ERROR, "Update handshaker factory failed.");
}
}
}
// TODO(ZhenLian): implement the logic to signal waiting handshakers once
// BlockOnInitialCredentialHandshaker is implemented.
void TlsServerSecurityConnector::TlsServerCertificateWatcher::OnError(
grpc_error_handle root_cert_error, grpc_error_handle identity_cert_error) {
if (root_cert_error != GRPC_ERROR_NONE) {
gpr_log(GPR_ERROR,
"TlsServerCertificateWatcher getting root_cert_error: %s",
grpc_error_std_string(root_cert_error).c_str());
}
if (identity_cert_error != GRPC_ERROR_NONE) {
gpr_log(GPR_ERROR,
"TlsServerCertificateWatcher getting identity_cert_error: %s",
grpc_error_std_string(identity_cert_error).c_str());
}
GRPC_ERROR_UNREF(root_cert_error);
GRPC_ERROR_UNREF(identity_cert_error);
}
// TODO(ZhenLian): implement the logic to signal waiting handshakers once
// BlockOnInitialCredentialHandshaker is implemented.
grpc_security_status
TlsServerSecurityConnector::UpdateHandshakerFactoryLocked() {
/* Free the server handshaker factory if exists. */
if (server_handshaker_factory_ != nullptr) {
tsi_ssl_server_handshaker_factory_unref(server_handshaker_factory_);
}
// The identity certs on the server side shouldn't be empty.
GPR_ASSERT(pem_key_cert_pair_list_.has_value());
GPR_ASSERT(!(*pem_key_cert_pair_list_).empty());
std::string pem_root_certs;
if (pem_root_certs_.has_value()) {
// TODO(ZhenLian): update the underlying TSI layer to use C++ types like
// std::string and absl::string_view to avoid making another copy here.
pem_root_certs = std::string(*pem_root_certs_);
}
tsi_ssl_pem_key_cert_pair* pem_key_cert_pairs = nullptr;
pem_key_cert_pairs = ConvertToTsiPemKeyCertPair(*pem_key_cert_pair_list_);
size_t num_key_cert_pairs = (*pem_key_cert_pair_list_).size();
grpc_security_status status = grpc_ssl_tsi_server_handshaker_factory_init(
pem_key_cert_pairs, num_key_cert_pairs,
pem_root_certs.empty() ? nullptr : pem_root_certs.c_str(),
options_->cert_request_type(),
grpc_get_tsi_tls_version(options_->min_tls_version()),
grpc_get_tsi_tls_version(options_->max_tls_version()),
&server_handshaker_factory_);
/* Free memory. */
grpc_tsi_ssl_pem_key_cert_pairs_destroy(pem_key_cert_pairs,
num_key_cert_pairs);
return status;
}
namespace internal {
grpc_error_handle TlsCheckHostName(const char* peer_name,
const tsi_peer* peer) {
/* Check the peer name if specified. */
if (peer_name != nullptr && !grpc_ssl_host_matches_name(peer, peer_name)) {
return GRPC_ERROR_CREATE_FROM_COPIED_STRING(
absl::StrCat("Peer name ", peer_name, " is not in peer certificate")
.c_str());
}
return GRPC_ERROR_NONE;
}
} // namespace internal
} // namespace grpc_core

@ -1,267 +0,0 @@
/*
*
* 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_TLS_TLS_SECURITY_CONNECTOR_H
#define GRPC_CORE_LIB_SECURITY_SECURITY_CONNECTOR_TLS_TLS_SECURITY_CONNECTOR_H
#include <grpc/support/port_platform.h>
#include "src/core/lib/gprpp/sync.h"
#include "src/core/lib/security/context/security_context.h"
#include "src/core/lib/security/credentials/tls/grpc_tls_certificate_provider.h"
#include "src/core/lib/security/credentials/tls/grpc_tls_credentials_options.h"
#define GRPC_TLS_TRANSPORT_SECURITY_TYPE "tls"
namespace grpc_core {
// Channel security connector using TLS as transport security protocol.
class TlsChannelSecurityConnector final
: public grpc_channel_security_connector {
public:
// static factory method to create a TLS channel security connector.
static RefCountedPtr<grpc_channel_security_connector>
CreateTlsChannelSecurityConnector(
RefCountedPtr<grpc_channel_credentials> channel_creds,
RefCountedPtr<grpc_tls_credentials_options> options,
RefCountedPtr<grpc_call_credentials> request_metadata_creds,
const char* target_name, const char* overridden_target_name,
tsi_ssl_session_cache* ssl_session_cache);
TlsChannelSecurityConnector(
RefCountedPtr<grpc_channel_credentials> channel_creds,
RefCountedPtr<grpc_tls_credentials_options> options,
RefCountedPtr<grpc_call_credentials> request_metadata_creds,
const char* target_name, const char* overridden_target_name,
tsi_ssl_session_cache* ssl_session_cache);
~TlsChannelSecurityConnector() override;
void add_handshakers(const grpc_channel_args* args,
grpc_pollset_set* interested_parties,
HandshakeManager* handshake_mgr) override;
void check_peer(tsi_peer peer, grpc_endpoint* ep,
RefCountedPtr<grpc_auth_context>* auth_context,
grpc_closure* on_peer_checked) override;
void cancel_check_peer(grpc_closure* /*on_peer_checked*/,
grpc_error_handle error) override {
// TODO(ZhenLian): call verifier->cancel() once the verifier is ready.
GRPC_ERROR_UNREF(error);
}
int cmp(const grpc_security_connector* other_sc) const override;
bool check_call_host(absl::string_view host, grpc_auth_context* auth_context,
grpc_closure* on_call_host_checked,
grpc_error_handle* error) override;
void cancel_check_call_host(grpc_closure* on_call_host_checked,
grpc_error_handle error) override;
tsi_ssl_client_handshaker_factory* ClientHandshakerFactoryForTesting() {
MutexLock lock(&mu_);
return client_handshaker_factory_;
};
absl::optional<absl::string_view> RootCertsForTesting() {
MutexLock lock(&mu_);
return pem_root_certs_;
}
absl::optional<PemKeyCertPairList> KeyCertPairListForTesting() {
MutexLock lock(&mu_);
return pem_key_cert_pair_list_;
}
private:
// A watcher that watches certificate updates from
// grpc_tls_certificate_distributor. It will never outlive
// |security_connector_|.
class TlsChannelCertificateWatcher : public grpc_tls_certificate_distributor::
TlsCertificatesWatcherInterface {
public:
explicit TlsChannelCertificateWatcher(
TlsChannelSecurityConnector* security_connector)
: security_connector_(security_connector) {}
void OnCertificatesChanged(
absl::optional<absl::string_view> root_certs,
absl::optional<PemKeyCertPairList> key_cert_pairs) override;
void OnError(grpc_error_handle root_cert_error,
grpc_error_handle identity_cert_error) override;
private:
TlsChannelSecurityConnector* security_connector_ = nullptr;
};
// Updates |client_handshaker_factory_| when the certificates that
// |certificate_watcher_| is watching get updated.
grpc_security_status UpdateHandshakerFactoryLocked()
ABSL_EXCLUSIVE_LOCKS_REQUIRED(mu_);
// gRPC-provided callback executed by application, which servers to bring the
// control back to gRPC core.
static void ServerAuthorizationCheckDone(
grpc_tls_server_authorization_check_arg* arg);
// A util function to process server authorization check result.
static grpc_error_handle ProcessServerAuthorizationCheckResult(
grpc_tls_server_authorization_check_arg* arg);
// A util function to create a server authorization check arg instance.
static grpc_tls_server_authorization_check_arg*
ServerAuthorizationCheckArgCreate(void* user_data);
// A util function to destroy a server authorization check arg instance.
static void ServerAuthorizationCheckArgDestroy(
grpc_tls_server_authorization_check_arg* arg);
RefCountedPtr<grpc_tls_credentials_options> options_;
grpc_tls_certificate_distributor::TlsCertificatesWatcherInterface*
certificate_watcher_ = nullptr;
grpc_closure* on_peer_checked_ = nullptr;
std::string target_name_;
std::string overridden_target_name_;
grpc_tls_server_authorization_check_arg* check_arg_ = nullptr;
Mutex mu_;
tsi_ssl_client_handshaker_factory* client_handshaker_factory_
ABSL_GUARDED_BY(mu_) = nullptr;
tsi_ssl_session_cache* ssl_session_cache_ ABSL_GUARDED_BY(mu_) = nullptr;
absl::optional<absl::string_view> pem_root_certs_ ABSL_GUARDED_BY(mu_);
absl::optional<PemKeyCertPairList> pem_key_cert_pair_list_
ABSL_GUARDED_BY(mu_);
};
// Server security connector using TLS as transport security protocol.
class TlsServerSecurityConnector final : public grpc_server_security_connector {
public:
// static factory method to create a TLS server security connector.
static RefCountedPtr<grpc_server_security_connector>
CreateTlsServerSecurityConnector(
RefCountedPtr<grpc_server_credentials> server_creds,
RefCountedPtr<grpc_tls_credentials_options> options);
TlsServerSecurityConnector(
RefCountedPtr<grpc_server_credentials> server_creds,
RefCountedPtr<grpc_tls_credentials_options> options);
~TlsServerSecurityConnector() override;
void add_handshakers(const grpc_channel_args* args,
grpc_pollset_set* interested_parties,
HandshakeManager* handshake_mgr) override;
void check_peer(tsi_peer peer, grpc_endpoint* ep,
RefCountedPtr<grpc_auth_context>* auth_context,
grpc_closure* on_peer_checked) override;
void cancel_check_peer(grpc_closure* /*on_peer_checked*/,
grpc_error_handle error) override {
// TODO(ZhenLian): call verifier->cancel() once the verifier is ready.
GRPC_ERROR_UNREF(error);
}
int cmp(const grpc_security_connector* other) const override;
tsi_ssl_server_handshaker_factory* ServerHandshakerFactoryForTesting() {
MutexLock lock(&mu_);
return server_handshaker_factory_;
};
const absl::optional<absl::string_view>& RootCertsForTesting() {
MutexLock lock(&mu_);
return pem_root_certs_;
}
const absl::optional<PemKeyCertPairList>& KeyCertPairListForTesting() {
MutexLock lock(&mu_);
return pem_key_cert_pair_list_;
}
private:
// A watcher that watches certificate updates from
// grpc_tls_certificate_distributor. It will never outlive
// |security_connector_|.
class TlsServerCertificateWatcher : public grpc_tls_certificate_distributor::
TlsCertificatesWatcherInterface {
public:
explicit TlsServerCertificateWatcher(
TlsServerSecurityConnector* security_connector)
: security_connector_(security_connector) {}
void OnCertificatesChanged(
absl::optional<absl::string_view> root_certs,
absl::optional<PemKeyCertPairList> key_cert_pairs) override;
void OnError(grpc_error_handle root_cert_error,
grpc_error_handle identity_cert_error) override;
private:
TlsServerSecurityConnector* security_connector_ = nullptr;
};
// Updates |server_handshaker_factory_| when the certificates that
// |certificate_watcher_| is watching get updated.
grpc_security_status UpdateHandshakerFactoryLocked()
ABSL_EXCLUSIVE_LOCKS_REQUIRED(mu_);
// gRPC-provided callback executed by application, which servers to bring the
// control back to gRPC core.
static void ClientAuthorizationCheckDone(
grpc_tls_server_authorization_check_arg* arg);
// A util function to process server authorization check result.
static grpc_error_handle ProcessClientAuthorizationCheckResult(
grpc_tls_server_authorization_check_arg* arg);
// A util function to create a server authorization check arg instance.
static grpc_tls_server_authorization_check_arg*
ClientAuthorizationCheckArgCreate(void* user_data);
// A util function to destroy a server authorization check arg instance.
static void ClientAuthorizationCheckArgDestroy(
grpc_tls_server_authorization_check_arg* arg);
RefCountedPtr<grpc_tls_credentials_options> options_;
grpc_tls_certificate_distributor::TlsCertificatesWatcherInterface*
certificate_watcher_ = nullptr;
grpc_closure* on_peer_checked_ = nullptr;
std::string target_name_ = "localhost";
std::string overridden_target_name_= "localhost";
grpc_tls_server_authorization_check_arg* check_arg_ = nullptr;
Mutex mu_;
tsi_ssl_server_handshaker_factory* server_handshaker_factory_
ABSL_GUARDED_BY(mu_) = nullptr;
absl::optional<absl::string_view> pem_root_certs_ ABSL_GUARDED_BY(mu_);
absl::optional<PemKeyCertPairList> pem_key_cert_pair_list_
ABSL_GUARDED_BY(mu_);
};
// ---- Functions below are exposed for testing only -----------------------
namespace internal {
// TlsCheckHostName checks if |peer_name| matches the identity information
// contained in |peer|. This is AKA hostname check.
grpc_error_handle TlsCheckHostName(const char* peer_name, const tsi_peer* peer);
} // namespace internal
} // namespace grpc_core
#endif // GRPC_CORE_LIB_SECURITY_SECURITY_CONNECTOR_TLS_TLS_SECURITY_CONNECTOR_H

@ -1,260 +0,0 @@
/*
*
* Copyright (c) 2022 Intel Corporation
*
* 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 "sgx_ra_tls_backends.h"
namespace grpc {
namespace sgx {
struct ra_tls_context _ctx_;
std::vector<std::string> ra_tls_get_key_cert() {
#ifdef SGX_RA_TLS_OCCLUM_BACKEND
return occlum_get_key_cert();
#endif
}
static std::vector<grpc::experimental::IdentityKeyCertPair> get_identity_key_cert_pairs(
std::vector<std::string> key_cert) {
grpc::experimental::IdentityKeyCertPair key_cert_pair;
key_cert_pair.private_key = key_cert[0];
key_cert_pair.certificate_chain = key_cert[1];
std::vector<grpc::experimental::IdentityKeyCertPair> identity_key_cert_pairs;
identity_key_cert_pairs.emplace_back(key_cert_pair);
return identity_key_cert_pairs;
}
void credential_option_set_certificate_provider(grpc::sgx::CredentialsOptions& options) {
std::lock_guard<std::mutex> lock(_ctx_.mtx);
_ctx_.cache.id++;
auto certificate_provider = _ctx_.cache.certificate_provider.insert({
_ctx_.cache.id,
std::make_shared<grpc::experimental::StaticDataCertificateProvider>(
get_identity_key_cert_pairs(ra_tls_get_key_cert()))
}).first;
options.set_certificate_provider(certificate_provider->second);
options.watch_identity_key_cert_pairs();
options.set_cert_request_type(GRPC_SSL_REQUEST_AND_REQUIRE_CLIENT_CERTIFICATE_BUT_DONT_VERIFY);
options.set_root_cert_name("");
options.set_identity_cert_name("");
}
static sgx_config parse_sgx_config_json(const char* file) {
class json_engine sgx_json(file);
struct sgx_config sgx_cfg;
sgx_cfg.verify_mr_enclave = sgx_json.compare_item(sgx_json.get_item(sgx_json.get_handle(), "verify_mr_enclave"), "on");
sgx_cfg.verify_mr_signer = sgx_json.compare_item(sgx_json.get_item(sgx_json.get_handle(), "verify_mr_signer"), "on");
sgx_cfg.verify_isv_prod_id = sgx_json.compare_item(sgx_json.get_item(sgx_json.get_handle(), "verify_isv_prod_id"), "on");
sgx_cfg.verify_isv_svn = sgx_json.compare_item(sgx_json.get_item(sgx_json.get_handle(), "verify_isv_svn"), "on");
sgx_cfg.verify_config_svn = sgx_json.compare_item(sgx_json.get_item(sgx_json.get_handle(), "verify_config_svn"), "on");
sgx_cfg.verify_enclave_debuggable =
sgx_json.compare_item(sgx_json.get_item(sgx_json.get_handle(), "verify_enclave_debuggable"), "on");
auto objs = sgx_json.get_item(sgx_json.get_handle(), "sgx_mrs");
auto obj_num = std::min(cJSON_GetArraySize(objs), SGX_MESUREMENTS_MAX_SIZE);
sgx_cfg.sgx_mrs = std::vector<sgx_measurement>(obj_num, sgx_measurement());
for (auto i = 0; i < obj_num; i++) {
auto obj = cJSON_GetArrayItem(objs, i);
auto mr_enclave = sgx_json.print_item(sgx_json.get_item(obj, "mr_enclave"));
memset(sgx_cfg.sgx_mrs[i].mr_enclave, 0, sizeof(sgx_cfg.sgx_mrs[i].mr_enclave));
hex_to_byte(mr_enclave+1, sgx_cfg.sgx_mrs[i].mr_enclave, sizeof(sgx_cfg.sgx_mrs[i].mr_enclave));
auto mr_signer = sgx_json.print_item(sgx_json.get_item(obj, "mr_signer"));
memset(sgx_cfg.sgx_mrs[i].mr_signer, 0, sizeof(sgx_cfg.sgx_mrs[i].mr_signer));
hex_to_byte(mr_signer+1, sgx_cfg.sgx_mrs[i].mr_signer, sizeof(sgx_cfg.sgx_mrs[i].mr_signer));
auto isv_prod_id = sgx_json.print_item(sgx_json.get_item(obj, "isv_prod_id"));
sgx_cfg.sgx_mrs[i].isv_prod_id = strtoul(isv_prod_id, nullptr, 10);
auto isv_svn = sgx_json.print_item(sgx_json.get_item(obj, "isv_svn"));
sgx_cfg.sgx_mrs[i].isv_svn = strtoul(isv_svn, nullptr, 10);
auto config_svn = sgx_json.print_item(sgx_json.get_item(obj, "config_svn"));
sgx_cfg.sgx_mrs[i].config_svn = strtoul(config_svn, nullptr, 10);
if (cJSON_IsTrue(sgx_json.get_item(obj, "debuggable")) == 0)
sgx_cfg.sgx_mrs[i].debuggable = false;
else
sgx_cfg.sgx_mrs[i].debuggable = true;
};
return sgx_cfg;
}
void ra_tls_parse_sgx_config(sgx_config sgx_cfg) {
std::lock_guard<std::mutex> lock(_ctx_.mtx);
_ctx_.sgx_cfg = sgx_cfg;
}
void ra_tls_parse_sgx_config(const char* file) {
ra_tls_parse_sgx_config(parse_sgx_config_json(file));
}
void ra_tls_verify_init() {
std::lock_guard<std::mutex> lock(_ctx_.mtx);
}
static bool verify_measurement_internal(const char* mr_enclave, const char* mr_signer,
const char* isv_prod_id, const char* isv_svn,
const char* config_svn, bool debuggable) {
bool status = false;
auto & sgx_cfg = _ctx_.sgx_cfg;
for (auto & obj : sgx_cfg.sgx_mrs) {
status = true;
if (status && sgx_cfg.verify_mr_enclave && \
memcmp(obj.mr_enclave, mr_enclave, 32)) {
status = false;
}
if (status && sgx_cfg.verify_mr_signer && \
memcmp(obj.mr_signer, mr_signer, 32)) {
status = false;
}
if (status && sgx_cfg.verify_isv_prod_id && \
(obj.isv_prod_id != *(uint16_t*)isv_prod_id)) {
status = false;
}
if (status && sgx_cfg.verify_isv_svn && \
(obj.isv_svn != *(uint16_t*)isv_svn)) {
status = false;
}
if (status && sgx_cfg.verify_config_svn && \
(obj.config_svn != *(uint16_t*)config_svn)) {
status = false;
}
if (status && sgx_cfg.verify_enclave_debuggable && \
(obj.debuggable != debuggable)) {
status = false;
}
if (status) {
break;
}
}
return status;
}
int verify_measurement(const char* mr_enclave, const char* mr_signer,
const char* isv_prod_id, const char* isv_svn,
const char* config_svn, bool debuggable) {
std::lock_guard<std::mutex> lock(_ctx_.mtx);
bool status = false;
try {
assert(mr_enclave && mr_signer && isv_prod_id && isv_svn && config_svn);
status = verify_measurement_internal(
mr_enclave, mr_signer, isv_prod_id, isv_svn, config_svn, debuggable
);
if (status) {
grpc_printf(" |- verify result : success\n");
} else {
grpc_printf("Below remote sgx measurements is not in the allowable list.\n");
grpc_printf(" |- mr_enclave : %s\n", byte_to_hex(mr_enclave, 32).c_str());
grpc_printf(" |- mr_signer : %s\n", byte_to_hex(mr_signer, 32).c_str());
grpc_printf(" |- isv_prod_id : %hu\n", *((uint16_t*)isv_prod_id));
grpc_printf(" |- isv_svn : %hu\n", *((uint16_t*)isv_svn));
grpc_printf(" |- config_svn : %hu\n", *((uint16_t*)config_svn));
grpc_printf(" |- debuggable : %s\n", debuggable?"true":"false");
grpc_printf(" |- verify result : failed\n");
}
} catch (...) {
grpc_printf("unable to verify measurement!");
}
fflush(stdout);
return status ? 0 : -1;
}
int TlsAuthorizationCheck::Schedule(grpc::experimental::TlsServerAuthorizationCheckArg* arg) {
GPR_ASSERT(arg != nullptr);
char der_crt[16000] = "";
auto peer_cert_buf = arg->peer_cert();
peer_cert_buf.copy(der_crt, peer_cert_buf.length(), 0);
#ifdef SGX_RA_TLS_OCCLUM_BACKEND
int ret = occlum_verify_cert((const unsigned char *)der_crt, 16000);
#endif
if (ret != 0) {
grpc_printf("something went wrong while verifying quote\n");
arg->set_success(0);
arg->set_status(GRPC_STATUS_UNAUTHENTICATED);
} else {
arg->set_success(1);
arg->set_status(GRPC_STATUS_OK);
}
return 0;
};
void TlsAuthorizationCheck::Cancel(grpc::experimental::TlsServerAuthorizationCheckArg* arg) {
GPR_ASSERT(arg != nullptr);
arg->set_status(GRPC_STATUS_PERMISSION_DENIED);
arg->set_error_details("cancelled");
};
int ra_tls_auth_check_schedule(void* /* confiuser_data */,
grpc_tls_server_authorization_check_arg* arg) {
char der_crt[16000] = "";
memcpy(der_crt, arg->peer_cert, strlen(arg->peer_cert));
#ifdef SGX_RA_TLS_OCCLUM_BACKEND
int ret = occlum_verify_cert((const unsigned char *)der_crt, 16000);
#endif
if (ret != 0) {
grpc_printf("something went wrong while verifying quote\n");
arg->success = 0;
arg->status = GRPC_STATUS_UNAUTHENTICATED;
} else {
arg->success = 1;
arg->status = GRPC_STATUS_OK;
}
return 0;
}
void credential_option_set_authorization_check(grpc::sgx::CredentialsOptions& options) {
std::lock_guard<std::mutex> lock(_ctx_.mtx);
_ctx_.cache.id++;
auto authorization_check = _ctx_.cache.authorization_check.insert({
_ctx_.cache.id, std::make_shared<grpc::sgx::TlsAuthorizationCheck>()
}).first;
auto authorization_check_config = _ctx_.cache.authorization_check_config.insert({
_ctx_.cache.id,
std::make_shared<grpc::experimental::TlsServerAuthorizationCheckConfig>(
authorization_check->second)
}).first;
options.set_authorization_check_config(authorization_check_config->second);
options.set_verification_option(GRPC_TLS_SKIP_ALL_SERVER_VERIFICATION);
}
} // namespace sgx
} // namespace grpc

@ -1,114 +0,0 @@
/*
*
* Copyright (c) 2022 Intel Corporation
*
* 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 SGX_RA_TLS_BACKENDS_H
#define SGX_RA_TLS_BACKENDS_H
#include "sgx_ra_tls_utils.h"
#include <mutex>
#include <unordered_map>
#include <grpcpp/grpcpp.h>
#include <grpc/grpc_security.h>
#include <grpc/grpc_security_constants.h>
#include <grpcpp/security/credentials.h>
#include <grpcpp/security/tls_certificate_provider.h>
#include <grpcpp/security/tls_credentials_options.h>
#include <grpcpp/security/server_credentials.h>
#include <grpcpp/security/sgx/sgx_ra_tls_options.h>
// Set 1 for strict safety checks
#define SGX_MESUREMENTS_MAX_SIZE 16
namespace grpc {
namespace sgx {
class TlsAuthorizationCheck
: public grpc::experimental::TlsServerAuthorizationCheckInterface {
int Schedule(grpc::experimental::TlsServerAuthorizationCheckArg* arg) override;
void Cancel(grpc::experimental::TlsServerAuthorizationCheckArg* arg) override;
};
struct sgx_measurement {
char mr_enclave[32];
char mr_signer[32];
uint16_t isv_prod_id;
uint16_t isv_svn;
uint16_t config_svn;
bool debuggable;
};
struct sgx_config {
bool verify_mr_enclave = true;
bool verify_mr_signer = true;
bool verify_isv_prod_id = true;
bool verify_isv_svn = true;
bool verify_config_svn = true;
bool verify_enclave_debuggable = true;
std::vector<sgx_measurement> sgx_mrs;
};
struct ra_tls_cache {
int id = 0;
std::unordered_map<
int, std::shared_ptr<grpc::experimental::StaticDataCertificateProvider>
> certificate_provider;
std::unordered_map<
int, std::shared_ptr<grpc::sgx::TlsAuthorizationCheck>
> authorization_check;
std::unordered_map<
int, std::shared_ptr<grpc::experimental::TlsServerAuthorizationCheckConfig>
> authorization_check_config;
};
struct ra_tls_context {
std::mutex mtx;
struct sgx_config sgx_cfg;
struct ra_tls_cache cache;
};
extern struct ra_tls_context _ctx_;
#ifdef SGX_RA_TLS_OCCLUM_BACKEND
std::vector<std::string> occlum_get_key_cert();
int occlum_verify_cert(const unsigned char * der_crt, size_t len);
#endif // SGX_RA_TLS_OCCLUM_BACKEND
void ra_tls_parse_sgx_config(sgx_config sgx_cfg);
void ra_tls_parse_sgx_config(const char* file);
void ra_tls_verify_init();
int verify_measurement(const char* mr_enclave, const char* mr_signer,
const char* isv_prod_id, const char* isv_svn,
const char* config_svn, bool debuggable);
void credential_option_set_certificate_provider(grpc::sgx::CredentialsOptions& options);
void credential_option_set_authorization_check(grpc::sgx::CredentialsOptions& options);
} // namespace sgx
} // namespace grpc
#endif // SGX_RA_TLS_BACKENDS_H

@ -1,98 +0,0 @@
/*
*
* Copyright (c) 2022 Intel Corporation
*
* 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 "sgx_ra_tls_backends.h"
namespace grpc {
namespace sgx {
/*
RA-TLS: on client, only need to register ra_tls_verify_callback() for cert verification
1. extract SGX quote from "quote" OID extension from crt
2. compare public key's hash from cert against quote's report_data
3. prepare user-supplied verification parameter "allow outdated TCB"
4. call into libsgx_dcap_quoteverify to verify ECDSA/based SGX quote
5. verify all measurements from the SGX quote
*/
std::shared_ptr<grpc::ChannelCredentials> TlsCredentials(sgx_config sgx_cfg) {
grpc::sgx::CredentialsOptions options;
ra_tls_parse_sgx_config(sgx_cfg);
credential_option_set_certificate_provider(options);
ra_tls_verify_init();
credential_option_set_authorization_check(options);
return grpc::experimental::TlsCredentials(
reinterpret_cast<const grpc::experimental::TlsChannelCredentialsOptions&>(options));
};
std::shared_ptr<grpc::ChannelCredentials> TlsCredentials(const char* sgx_cfg_json) {
grpc::sgx::CredentialsOptions options;
ra_tls_parse_sgx_config(sgx_cfg_json);
credential_option_set_certificate_provider(options);
ra_tls_verify_init();
credential_option_set_authorization_check(options);
return grpc::experimental::TlsCredentials(
reinterpret_cast<const grpc::experimental::TlsChannelCredentialsOptions&>(options));
};
std::shared_ptr<grpc::ServerCredentials> TlsServerCredentials(sgx_config sgx_cfg) {
grpc::sgx::CredentialsOptions options;
ra_tls_parse_sgx_config(sgx_cfg);
credential_option_set_certificate_provider(options);
ra_tls_verify_init();
credential_option_set_authorization_check(options);
return grpc::experimental::TlsServerCredentials(
reinterpret_cast<const grpc::experimental::TlsServerCredentialsOptions&>(options));
};
std::shared_ptr<grpc::ServerCredentials> TlsServerCredentials(const char* sgx_cfg_json) {
grpc::sgx::CredentialsOptions options;
ra_tls_parse_sgx_config(sgx_cfg_json);
credential_option_set_certificate_provider(options);
ra_tls_verify_init();
credential_option_set_authorization_check(options);
return grpc::experimental::TlsServerCredentials(
reinterpret_cast<const grpc::experimental::TlsServerCredentialsOptions&>(options));
};
std::shared_ptr<grpc::Channel> CreateSecureChannel(
string target_str, std::shared_ptr<grpc::ChannelCredentials> channel_creds) {
GPR_ASSERT(channel_creds.get() != nullptr);
auto channel_args = grpc::ChannelArguments();
channel_args.SetSslTargetNameOverride("RATLS");
return grpc::CreateCustomChannel(target_str, std::move(channel_creds), channel_args);
};
} // namespace sgx
} // namespace grpc

@ -1,325 +0,0 @@
/*
*
* Copyright (c) 2022 Intel Corporation
*
* 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 "sgx_ra_tls_backends.h"
namespace grpc {
namespace sgx {
#ifdef SGX_RA_TLS_OCCLUM_BACKEND
#include <openssl/evp.h>
#include <openssl/rsa.h>
#include <openssl/x509.h>
#include <openssl/x509v3.h>
#include <openssl/sha.h>
#include <openssl/pem.h>
#include <openssl/asn1.h>
#include "sgx_quote_3.h"
#include "occlum_dcap.h"
const char * RA_TLS_LONG_NAME = "RA-TLS Extension";
const char * RA_TLS_SHORT_NAME = "RA-TLS";
std::vector<std::string> occlum_get_key_cert() {
unsigned char private_key_pem[16000], cert_pem[16000];
BIGNUM * e = BN_new();
BN_set_word(e, RSA_F4);
RSA * rsa = RSA_new();
RSA_generate_key_ex(rsa, 2048, e, nullptr);
EVP_PKEY * pkey = EVP_PKEY_new();
EVP_PKEY_assign_RSA(pkey, rsa);
X509 * x509 = X509_new();
ASN1_INTEGER_set(X509_get_serialNumber(x509), 1);
X509_gmtime_adj(X509_get_notBefore(x509), 0);
X509_gmtime_adj(X509_get_notAfter(x509), 630720000L);
X509_set_pubkey(x509, pkey);
X509_NAME * name = X509_NAME_new();
// X509_NAME * name = X509_get_subject_name(x509);
X509_NAME_add_entry_by_txt(name, "C", MBSTRING_ASC,
(unsigned char *)"CN", -1, -1, 0);
X509_NAME_add_entry_by_txt(name, "O", MBSTRING_ASC,
(unsigned char *)"Intel Inc.", -1, -1, 0);
X509_NAME_add_entry_by_txt(name, "CN", MBSTRING_ASC,
(unsigned char *)"localhost", -1, -1, 0);
X509_set_subject_name(x509, name);
X509_set_issuer_name(x509, name);
int32_t ret;
size_t key_len = i2d_PUBKEY(pkey, 0);
unsigned char *public_key = NULL;
// size_t pubkey_len = i2d_PUBKEY(pkey, &public_key);
size_t pubkey_len = i2d_X509_PUBKEY(X509_get_X509_PUBKEY(x509), &public_key);
if (pubkey_len != key_len) {
grpc_printf("get public key failed!\n");
}
BIO *bio = BIO_new(BIO_s_mem());
if (nullptr == bio) {
grpc_printf("create bio failed!\n");
}
ret = PEM_write_bio_RSAPrivateKey(bio, rsa, nullptr, nullptr, 0, nullptr, nullptr);
if (ret == 0) {
grpc_printf("write private key failed!\n");
}
ret = BIO_read(bio, private_key_pem, bio->num_write);
if (ret == 0) {
grpc_printf("read private key failed!\n");
}
unsigned char hash[SHA256_DIGEST_LENGTH];
SHA256_CTX sha256;
SHA256_Init(&sha256);
SHA256_Update(&sha256, public_key, key_len);
SHA256_Final(hash, &sha256);
void *handle;
uint32_t quote_size;
uint8_t *p_quote_buffer;
handle = dcap_quote_open();
quote_size = dcap_get_quote_size(handle);
p_quote_buffer = (uint8_t*)malloc(quote_size);
if (nullptr == p_quote_buffer) {
grpc_printf("Couldn't allocate quote_buffer\n");
}
memset(p_quote_buffer, 0, quote_size);
sgx_report_data_t report_data = { 0 };
memcpy(report_data.d, hash, SHA256_DIGEST_LENGTH);
ret = dcap_generate_quote(handle, p_quote_buffer, &report_data);
if (0 != ret) {
grpc_printf( "Error in dcap_generate_quote.\n");
}
int nid = OBJ_create("1.2.840.113741.1", RA_TLS_SHORT_NAME, RA_TLS_LONG_NAME);
ASN1_OBJECT* obj = OBJ_nid2obj(nid);
ASN1_OCTET_STRING* data = ASN1_OCTET_STRING_new();
ASN1_OCTET_STRING_set(data, p_quote_buffer, quote_size);
X509_EXTENSION* ext = X509_EXTENSION_create_by_OBJ(nullptr, obj, 0, data);
X509_add_ext(x509, ext, -1);
X509_sign(x509, pkey, EVP_sha1());
BIO *cert_bio = BIO_new(BIO_s_mem());
if (nullptr == cert_bio) {
grpc_printf("create crt bio failed!\n");
}
if (0 == PEM_write_bio_X509(cert_bio, x509)) {
BIO_free(cert_bio);
grpc_printf("read crt bio failed!\n");
}
ret = BIO_read(cert_bio, cert_pem, cert_bio->num_write);
if (ret == 0) {
grpc_printf("read pem cert failed!\n");
}
BIO_free(bio);
BIO_free(cert_bio);
EVP_PKEY_free(pkey);
check_free(p_quote_buffer);
dcap_quote_close(handle);
std::vector<std::string> key_cert;
key_cert.emplace_back(std::string((char*) private_key_pem));
key_cert.emplace_back(std::string((char*) cert_pem));
return key_cert;
}
static int occlum_get_quote(X509 *x509, uint8_t **quote, size_t *len) {
STACK_OF(X509_EXTENSION) *exts = x509->cert_info->extensions;
int ext_num;
int ret = -1;
if (exts) {
ext_num = sk_X509_EXTENSION_num(exts);
for (int i = 0; i < ext_num; i++) {
X509_EXTENSION *ext = sk_X509_EXTENSION_value(exts, i);
ASN1_OBJECT *obj = X509_EXTENSION_get_object(ext);
unsigned nid = OBJ_obj2nid(obj);
if (nid != NID_undef) {
const char *ln = OBJ_nid2ln(nid);
if (memcmp(RA_TLS_LONG_NAME, ln, sizeof(RA_TLS_LONG_NAME)) == 0) {
BIO *ext_bio = BIO_new(BIO_s_mem());
*len = i2d_ASN1_OCTET_STRING(ext->value, quote);
*quote = *quote + 4;
*len = *len - 4;
ret = 0;
BIO_free(ext_bio);
}
}
}
}
return ret;
}
static int occlum_verify_pubkey_hash(X509 *x509, uint8_t *pubkey_hash, size_t len) {
EVP_PKEY *pkey = X509_get_pubkey(x509);
int32_t ret;
size_t key_len = EVP_PKEY_bits(pkey)/8;
unsigned char *public_key = NULL;
key_len = i2d_X509_PUBKEY(X509_get_X509_PUBKEY(x509), &public_key);
unsigned char hash[SHA256_DIGEST_LENGTH];
SHA256_CTX sha256;
SHA256_Init(&sha256);
SHA256_Update(&sha256, public_key, key_len);
SHA256_Final(hash, &sha256);
ret = memcmp(hash, pubkey_hash, len);
return ret;
}
static int occlum_verify_quote(uint8_t * quote_buffer, size_t quote_size) {
void *handle;
handle = dcap_quote_open();
uint32_t supplemental_size, ret;
uint8_t *p_supplemental_buffer;
sgx_ql_qv_result_t quote_verification_result = SGX_QL_QV_RESULT_UNSPECIFIED;
uint32_t collateral_expiration_status = 1;
supplemental_size = dcap_get_supplemental_data_size(handle);
p_supplemental_buffer = (uint8_t *)malloc(supplemental_size);
if (NULL == p_supplemental_buffer) {
grpc_printf("Couldn't allocate supplemental buffer\n");
}
memset(p_supplemental_buffer, 0, supplemental_size);
ret = dcap_verify_quote(
handle,
quote_buffer,
quote_size,
&collateral_expiration_status,
&quote_verification_result,
supplemental_size,
p_supplemental_buffer
);
if (0 != ret) {
grpc_printf( "Error in dcap_verify_quote.\n");
}
if (collateral_expiration_status != 0) {
grpc_printf("the verification collateral has expired\n");
}
switch (quote_verification_result) {
case SGX_QL_QV_RESULT_OK:
grpc_printf("Succeed to verify the quote!\n");
break;
case SGX_QL_QV_RESULT_CONFIG_NEEDED:
case SGX_QL_QV_RESULT_OUT_OF_DATE:
case SGX_QL_QV_RESULT_OUT_OF_DATE_CONFIG_NEEDED:
case SGX_QL_QV_RESULT_SW_HARDENING_NEEDED:
case SGX_QL_QV_RESULT_CONFIG_AND_SW_HARDENING_NEEDED:
grpc_printf("WARN: App: Verification completed with Non-terminal result: %x\n",
quote_verification_result);
break;
case SGX_QL_QV_RESULT_INVALID_SIGNATURE:
case SGX_QL_QV_RESULT_REVOKED:
case SGX_QL_QV_RESULT_UNSPECIFIED:
default:
grpc_printf("\tError: App: Verification completed with Terminal result: %x\n",
quote_verification_result);
}
check_free(p_supplemental_buffer);
dcap_quote_close(handle);
return ret;
}
int occlum_verify_cert(const unsigned char * der_crt, size_t len) {
BIO* bio = BIO_new(BIO_s_mem());
BIO_write(bio, der_crt, strlen((const char *)der_crt));
X509 *x509 = PEM_read_bio_X509(bio, NULL, NULL, NULL);
if (x509 == nullptr) {
grpc_printf("parse the crt failed! \n");
return -1;
}
uint8_t * quote_buf = nullptr;
size_t quote_len = 0;
int ret = occlum_get_quote(x509, &quote_buf, &quote_len);
if (ret != 0) {
grpc_printf("parse quote failed!\n");
return -1;
}
ret = occlum_verify_quote(quote_buf, quote_len);
if (ret != 0) {
grpc_printf("verify quote failed!\n");
return -1;
}
sgx_quote3_t *p_quote = (sgx_quote3_t *)quote_buf;
sgx_report_body_t *p_rep_body = (sgx_report_body_t *)(&p_quote->report_body);
sgx_report_data_t *p_rep_data =(sgx_report_data_t *)(&p_rep_body->report_data);
uint8_t *pubkey_hash = p_rep_data->d;
ret = occlum_verify_pubkey_hash(x509, pubkey_hash, SHA256_DIGEST_LENGTH);
if (ret != 0) {
grpc_printf("verify the public key hash failed!\n");
return -1;
}
// Check if enclave is debuggable
bool debuggable = false;
if (p_rep_body->attributes.flags & SGX_FLAGS_DEBUG)
debuggable = true;
ret = verify_measurement((const char *)&p_rep_body->mr_enclave,
(const char *)&p_rep_body->mr_signer,
(const char *)&p_rep_body->isv_prod_id,
(const char *)&p_rep_body->isv_svn,
(const char *)&p_rep_body->config_svn,
debuggable);
if (ret != 0) {
grpc_printf("verify the measurement failed!\n");
return -1;
}
BIO_free(bio);
return 0;
}
#endif // SGX_RA_TLS_OCCLUM_BACKEND
} // namespace sgx
} // namespace grpc

@ -1,55 +0,0 @@
/*
*
* Copyright (c) 2022 Intel Corporation
*
* 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/grpc_security.h>
#include <grpc/support/alloc.h>
#include <grpcpp/security/sgx/sgx_ra_tls_options.h>
#include "absl/container/inlined_vector.h"
#include "src/cpp/common/tls_credentials_options_util.h"
namespace grpc {
namespace sgx {
void CredentialsOptions::set_verification_option(
grpc_tls_server_verification_option server_verification_option) {
grpc_tls_credentials_options* options = c_credentials_options();
GPR_ASSERT(options != nullptr);
grpc_tls_credentials_options_set_server_verification_option(
options, server_verification_option);
}
void CredentialsOptions::set_authorization_check_config(
std::shared_ptr<grpc::experimental::TlsServerAuthorizationCheckConfig> config) {
grpc_tls_credentials_options* options = c_credentials_options();
GPR_ASSERT(options != nullptr);
if (config != nullptr) {
grpc_tls_credentials_options_set_server_authorization_check_config(
options, config->c_config());
}
}
void CredentialsOptions::set_cert_request_type(
grpc_ssl_client_certificate_request_type cert_request_type) {
grpc_tls_credentials_options* options = c_credentials_options();
GPR_ASSERT(options != nullptr);
grpc_tls_credentials_options_set_cert_request_type(options, cert_request_type);
}
} // namespace sgx
} // namespace grpc

@ -1,169 +0,0 @@
/*
*
* Copyright (c) 2022 Intel Corporation
*
* 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 "sgx_ra_tls_utils.h"
#include <cstring>
#include <iostream>
#include <fstream>
#include <sstream>
namespace grpc {
namespace sgx {
void check_free(void* ptr) {
if (ptr) {
free(ptr);
ptr = nullptr;
};
}
bool hex_to_byte(const char *src, char *dst, size_t dst_size) {
if (std::strlen(src) < dst_size*2) {
return false;
} else {
for (auto i = 0; i < dst_size; i++) {
if (!isxdigit(src[i*2]) || !isxdigit(src[i*2+1])) {
return false;
} else {
sscanf(src+i*2, "%02hhx", dst+i);
}
}
return true;
}
};
void byte_to_hex(const char *src, char *dst, size_t src_size) {
for (auto i = 0; i < src_size; i++) {
sprintf(dst+i*2, "%02hhx", src[i]);
}
};
std::string byte_to_hex(const char *src, size_t src_size) {
char dst[src_size*2];
memset(dst, 0, sizeof(dst));
byte_to_hex(src, dst, src_size);
return std::string(dst);
};
library_engine::library_engine() : handle(nullptr), error(nullptr) {};
library_engine::library_engine(const char* file, int mode) : handle(nullptr), error(nullptr) {
this->open(file, mode);
}
library_engine::~library_engine() {
this->close();
}
void library_engine::open(const char* file, int mode) {
this->close();
handle = dlopen(file, mode);
error = dlerror();
if (error != nullptr || handle == nullptr) {
throw std::runtime_error("dlopen " + std::string(file) + " error, " + std::string(error));
}
}
void library_engine::close() {
if (handle) {
dlclose(handle);
}
handle = nullptr;
error = nullptr;
}
void* library_engine::get_func(const char* name) {
auto func = dlsym(handle, name);
error = dlerror();
if (error != nullptr || func == nullptr) {
throw std::runtime_error("dlsym " + std::string(name) + " error, " + std::string(error));
return nullptr;
} else {
return func;
}
}
void* library_engine::get_handle() {
return handle;
}
json_engine::json_engine() : handle(nullptr) {};
json_engine::json_engine(const char* file) : handle(nullptr){
this->open(file);
}
json_engine::~json_engine() {
this->close();
}
bool json_engine::open(const char* file) {
if (!file) {
grpc_printf("wrong json file path\n");
return false;
}
this->close();
auto file_ptr = fopen(file, "r");
fseek(file_ptr, 0, SEEK_END);
auto length = ftell(file_ptr);
fseek(file_ptr, 0, SEEK_SET);
auto buffer = malloc(length);
fread(buffer, 1, length, file_ptr);
fclose(file_ptr);
this->handle = cJSON_Parse((const char *)buffer);
check_free(buffer);
if (this->handle) {
return true;
} else {
grpc_printf("cjson open %s error: %s", file, cJSON_GetErrorPtr());
return false;
}
}
void json_engine::close() {
if (this->handle) {
cJSON_Delete(this->handle);
this->handle = nullptr;
}
}
cJSON* json_engine::get_handle() {
return this->handle;
}
cJSON* json_engine::get_item(cJSON* obj, const char* item) {
return cJSON_GetObjectItem(obj, item);
};
char* json_engine::print_item(cJSON* obj) {
return cJSON_Print(obj);
};
bool json_engine::compare_item(cJSON* obj, const char* item) {
auto obj_item = this->print_item(obj);
return strncmp(obj_item+1, item, std::min(strlen(item), strlen(obj_item)-2)) == 0;
};
} // namespace sgx
} // namespace grpc

@ -1,68 +0,0 @@
/*
*
* Copyright (c) 2022 Intel Corporation
*
* 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 SGX_RA_TLS_UTILS_H
#define SGX_RA_TLS_UTILS_H
#include <string>
#include <vector>
#include <memory>
#include <dlfcn.h>
#define grpc_printf printf
#define grpc_fprintf fprintf
#include <grpcpp/security/sgx/sgx_ra_tls.h>
namespace grpc {
namespace sgx {
class library_engine {
public:
library_engine();
library_engine(const char*, int);
~library_engine();
void open(const char*, int);
void close();
void* get_func(const char*);
void* get_handle();
private:
void* handle;
char* error;
};
void check_free(void* ptr);
bool hex_to_byte(const char* src, char* dst, size_t dst_size);
void byte_to_hex(const char* src, char* dst, size_t src_size);
std::string byte_to_hex(const char* src, size_t src_size);
} // namespace sgx
} // namespace grpc
#endif // SGX_RA_TLS_UTILS_H