occlum/tools/toolchains/grpc_ratls/ra_tls/0001-Add-Occlum-SGX-tls-function.patch
Qi Zheng cb1ee85605 [toolchain] Update grpc_ratls toolchain with patching way
Signed-off-by: Qi Zheng <huaiqing.zq@antgroup.com>
2024-03-14 16:23:34 +08:00

2407 lines
79 KiB
Diff

From 00d3a4744aa7fecea3c07dc70be26aa55ffdfa2b Mon Sep 17 00:00:00 2001
From: Qi Zheng <huaiqing.zq@antgroup.com>
Date: Tue, 14 Nov 2023 03:43:34 +0000
Subject: [PATCH] Add Occlum SGX tls function
---
CMakeLists.txt | 58 +++-
examples/cpp/ratls/CMakeLists.txt | 64 ++++
examples/cpp/ratls/README.md | 15 +
examples/cpp/ratls/build.sh | 27 ++
examples/cpp/ratls/client.cc | 41 +++
examples/cpp/ratls/grpc_ratls_client.cc | 212 ++++++++++++
examples/cpp/ratls/grpc_ratls_client.h | 28 ++
examples/cpp/ratls/grpc_ratls_server.cc | 96 ++++++
examples/cpp/ratls/grpc_ratls_server.h | 19 +
examples/cpp/ratls/server.cc | 37 ++
examples/protos/ratls.proto | 38 ++
include/grpcpp/security/sgx/sgx_ra_tls.h | 83 +++++
.../grpcpp/security/sgx/sgx_ra_tls_options.h | 67 ++++
.../credentials/tls/tls_credentials.cc | 10 +-
.../tls/tls_security_connector.cc | 194 ++++++++++-
.../tls/tls_security_connector.h | 22 ++
src/cpp/sgx/sgx_ra_tls_backends.cc | 260 ++++++++++++++
src/cpp/sgx/sgx_ra_tls_backends.h | 114 ++++++
src/cpp/sgx/sgx_ra_tls_credentials.cc | 98 ++++++
src/cpp/sgx/sgx_ra_tls_occlum.cc | 325 ++++++++++++++++++
src/cpp/sgx/sgx_ra_tls_options.cc | 55 +++
src/cpp/sgx/sgx_ra_tls_utils.cc | 169 +++++++++
src/cpp/sgx/sgx_ra_tls_utils.h | 68 ++++
23 files changed, 2071 insertions(+), 29 deletions(-)
create mode 100644 examples/cpp/ratls/CMakeLists.txt
create mode 100644 examples/cpp/ratls/README.md
create mode 100644 examples/cpp/ratls/build.sh
create mode 100644 examples/cpp/ratls/client.cc
create mode 100644 examples/cpp/ratls/grpc_ratls_client.cc
create mode 100644 examples/cpp/ratls/grpc_ratls_client.h
create mode 100644 examples/cpp/ratls/grpc_ratls_server.cc
create mode 100644 examples/cpp/ratls/grpc_ratls_server.h
create mode 100644 examples/cpp/ratls/server.cc
create mode 100644 examples/protos/ratls.proto
create mode 100644 include/grpcpp/security/sgx/sgx_ra_tls.h
create mode 100644 include/grpcpp/security/sgx/sgx_ra_tls_options.h
create mode 100644 src/cpp/sgx/sgx_ra_tls_backends.cc
create mode 100644 src/cpp/sgx/sgx_ra_tls_backends.h
create mode 100644 src/cpp/sgx/sgx_ra_tls_credentials.cc
create mode 100644 src/cpp/sgx/sgx_ra_tls_occlum.cc
create mode 100644 src/cpp/sgx/sgx_ra_tls_options.cc
create mode 100644 src/cpp/sgx/sgx_ra_tls_utils.cc
create mode 100644 src/cpp/sgx/sgx_ra_tls_utils.h
diff --git a/CMakeLists.txt b/CMakeLists.txt
index eeaf0b43c7..d648e4237a 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -49,6 +49,16 @@ option(gRPC_BUILD_CODEGEN "Build codegen" ON)
option(gRPC_BUILD_CSHARP_EXT "Build C# extensions" ON)
option(gRPC_BACKWARDS_COMPATIBILITY_MODE "Build libraries that are binary compatible across a larger number of OS and libc versions" OFF)
+option(DEFINE_SGX_RA_TLS_OCCLUM_BACKEND "SGX Occlum Backend" OFF)
+
+
+if(DEFINE_SGX_RA_TLS_OCCLUM_BACKEND)
+ message("SGX_RA_TLS_OCCLUM_BACKEND is defined")
+ include_directories(/opt/intel/sgxsdk/include)
+ include_directories(/opt/occlum/toolchains/dcap_lib/inc)
+ add_definitions(-DSGX_RA_TLS_OCCLUM_BACKEND)
+endif()
+
set(gRPC_INSTALL_default ON)
if(NOT CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR)
# Disable gRPC_INSTALL by default if building as a submodule
@@ -2064,22 +2074,28 @@ target_include_directories(grpc
${_gRPC_XXHASH_INCLUDE_DIR}
${_gRPC_ZLIB_INCLUDE_DIR}
)
-target_link_libraries(grpc
- ${_gRPC_BASELIB_LIBRARIES}
- ${_gRPC_ZLIB_LIBRARIES}
- ${_gRPC_CARES_LIBRARIES}
- ${_gRPC_ADDRESS_SORTING_LIBRARIES}
- ${_gRPC_RE2_LIBRARIES}
- ${_gRPC_UPB_LIBRARIES}
- ${_gRPC_ALLTARGETS_LIBRARIES}
- absl::flat_hash_map
- absl::inlined_vector
- absl::bind_front
- absl::statusor
- gpr
- ${_gRPC_SSL_LIBRARIES}
- address_sorting
-)
+
+if(DEFINE_SGX_RA_TLS_OCCLUM_BACKEND)
+ target_link_libraries(grpc
+ ${_gRPC_BASELIB_LIBRARIES}
+ ${_gRPC_ZLIB_LIBRARIES}
+ ${_gRPC_CARES_LIBRARIES}
+ ${_gRPC_ADDRESS_SORTING_LIBRARIES}
+ ${_gRPC_RE2_LIBRARIES}
+ ${_gRPC_UPB_LIBRARIES}
+ ${_gRPC_ALLTARGETS_LIBRARIES}
+ absl::flat_hash_map
+ absl::inlined_vector
+ absl::bind_front
+ absl::statusor
+ gpr
+ ${_gRPC_SSL_LIBRARIES}
+ address_sorting
+ occlum_dcap
+ cjson
+ )
+endif()
+
if(_gRPC_PLATFORM_IOS OR _gRPC_PLATFORM_MAC)
target_link_libraries(grpc "-framework CoreFoundation")
endif()
@@ -2775,6 +2791,11 @@ add_library(grpc++
src/cpp/util/status.cc
src/cpp/util/string_ref.cc
src/cpp/util/time_cc.cc
+ src/cpp/sgx/sgx_ra_tls_credentials.cc
+ src/cpp/sgx/sgx_ra_tls_options.cc
+ src/cpp/sgx/sgx_ra_tls_backends.cc
+ src/cpp/sgx/sgx_ra_tls_occlum.cc
+ src/cpp/sgx/sgx_ra_tls_utils.cc
)
set_target_properties(grpc++ PROPERTIES
@@ -2972,7 +2993,8 @@ foreach(_hdr
include/grpcpp/security/credentials.h
include/grpcpp/security/server_credentials.h
include/grpcpp/security/tls_certificate_provider.h
- include/grpcpp/security/tls_credentials_options.h
+ include/grpcpp/security/sgx/sgx_ra_tls.h
+ include/grpcpp/security/sgx/sgx_ra_tls_options.h
include/grpcpp/server.h
include/grpcpp/server_builder.h
include/grpcpp/server_context.h
@@ -3620,6 +3642,8 @@ foreach(_hdr
include/grpcpp/security/server_credentials.h
include/grpcpp/security/tls_certificate_provider.h
include/grpcpp/security/tls_credentials_options.h
+ include/grpcpp/security/sgx/sgx_ra_tls.h
+ include/grpcpp/security/sgx/sgx_ra_tls_options.h
include/grpcpp/server.h
include/grpcpp/server_builder.h
include/grpcpp/server_context.h
diff --git a/examples/cpp/ratls/CMakeLists.txt b/examples/cpp/ratls/CMakeLists.txt
new file mode 100644
index 0000000000..200583db23
--- /dev/null
+++ b/examples/cpp/ratls/CMakeLists.txt
@@ -0,0 +1,64 @@
+# 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()
diff --git a/examples/cpp/ratls/README.md b/examples/cpp/ratls/README.md
new file mode 100644
index 0000000000..4b3d8307e8
--- /dev/null
+++ b/examples/cpp/ratls/README.md
@@ -0,0 +1,15 @@
+# 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
+```
diff --git a/examples/cpp/ratls/build.sh b/examples/cpp/ratls/build.sh
new file mode 100644
index 0000000000..b6ed9c8aea
--- /dev/null
+++ b/examples/cpp/ratls/build.sh
@@ -0,0 +1,27 @@
+#
+# 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 -
diff --git a/examples/cpp/ratls/client.cc b/examples/cpp/ratls/client.cc
new file mode 100644
index 0000000000..db13031d7f
--- /dev/null
+++ b/examples/cpp/ratls/client.cc
@@ -0,0 +1,41 @@
+/*
+ *
+ * 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;
+}
diff --git a/examples/cpp/ratls/grpc_ratls_client.cc b/examples/cpp/ratls/grpc_ratls_client.cc
new file mode 100644
index 0000000000..1c2fd75a7e
--- /dev/null
+++ b/examples/cpp/ratls/grpc_ratls_client.cc
@@ -0,0 +1,212 @@
+/*
+ *
+ * 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;
+}
diff --git a/examples/cpp/ratls/grpc_ratls_client.h b/examples/cpp/ratls/grpc_ratls_client.h
new file mode 100644
index 0000000000..10b39c7459
--- /dev/null
+++ b/examples/cpp/ratls/grpc_ratls_client.h
@@ -0,0 +1,28 @@
+#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_
\ No newline at end of file
diff --git a/examples/cpp/ratls/grpc_ratls_server.cc b/examples/cpp/ratls/grpc_ratls_server.cc
new file mode 100644
index 0000000000..0a88c301d5
--- /dev/null
+++ b/examples/cpp/ratls/grpc_ratls_server.cc
@@ -0,0 +1,96 @@
+/*
+ *
+ * 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;
+}
+
diff --git a/examples/cpp/ratls/grpc_ratls_server.h b/examples/cpp/ratls/grpc_ratls_server.h
new file mode 100644
index 0000000000..1aee644a49
--- /dev/null
+++ b/examples/cpp/ratls/grpc_ratls_server.h
@@ -0,0 +1,19 @@
+#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_
\ No newline at end of file
diff --git a/examples/cpp/ratls/server.cc b/examples/cpp/ratls/server.cc
new file mode 100644
index 0000000000..38479703a9
--- /dev/null
+++ b/examples/cpp/ratls/server.cc
@@ -0,0 +1,37 @@
+/*
+ *
+ * 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;
+}
\ No newline at end of file
diff --git a/examples/protos/ratls.proto b/examples/protos/ratls.proto
new file mode 100644
index 0000000000..0bae704719
--- /dev/null
+++ b/examples/protos/ratls.proto
@@ -0,0 +1,38 @@
+// 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;
+}
diff --git a/include/grpcpp/security/sgx/sgx_ra_tls.h b/include/grpcpp/security/sgx/sgx_ra_tls.h
new file mode 100644
index 0000000000..2ea167d2f9
--- /dev/null
+++ b/include/grpcpp/security/sgx/sgx_ra_tls.h
@@ -0,0 +1,83 @@
+/*
+ *
+ * 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
diff --git a/include/grpcpp/security/sgx/sgx_ra_tls_options.h b/include/grpcpp/security/sgx/sgx_ra_tls_options.h
new file mode 100644
index 0000000000..cb942b0911
--- /dev/null
+++ b/include/grpcpp/security/sgx/sgx_ra_tls_options.h
@@ -0,0 +1,67 @@
+/*
+ *
+ * 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
diff --git a/src/core/lib/security/credentials/tls/tls_credentials.cc b/src/core/lib/security/credentials/tls/tls_credentials.cc
index f5b05d8a01..ab80b22554 100644
--- a/src/core/lib/security/credentials/tls/tls_credentials.cc
+++ b/src/core/lib/security/credentials/tls/tls_credentials.cc
@@ -41,11 +41,11 @@ bool CredentialOptionSanityCheck(const grpc_tls_credentials_options* options,
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 (!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,
diff --git a/src/core/lib/security/security_connector/tls/tls_security_connector.cc b/src/core/lib/security/security_connector/tls/tls_security_connector.cc
index ea6b42e07d..db21ed0f4c 100644
--- a/src/core/lib/security/security_connector/tls/tls_security_connector.cc
+++ b/src/core/lib/security/security_connector/tls/tls_security_connector.cc
@@ -67,6 +67,13 @@ tsi_ssl_pem_key_cert_pair* ConvertToTsiPemKeyCertPair(
} // namespace
+void gpr_check_free(void* p) {
+ if (p) {
+ gpr_free(p);
+ p = nullptr;
+ }
+}
+
// -------------------channel security connector-------------------
RefCountedPtr<grpc_channel_security_connector>
TlsChannelSecurityConnector::CreateTlsChannelSecurityConnector(
@@ -241,7 +248,7 @@ void TlsChannelSecurityConnector::check_peer(
? gpr_strdup(target_name)
: check_arg_->target_name;
on_peer_checked_ = on_peer_checked;
- gpr_free(peer_pem);
+ 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) {
@@ -252,7 +259,7 @@ void TlsChannelSecurityConnector::check_peer(
check_arg_->peer_cert_full_chain == nullptr
? gpr_strdup(peer_pem_chain)
: check_arg_->peer_cert_full_chain;
- gpr_free(peer_pem_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
@@ -474,9 +481,9 @@ void TlsChannelSecurityConnector::ServerAuthorizationCheckArgDestroy(
if (arg == nullptr) {
return;
}
- gpr_free(const_cast<char*>(arg->target_name));
- gpr_free(const_cast<char*>(arg->peer_cert));
- gpr_free(const_cast<char*>(arg->peer_cert_full_chain));
+ 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];
}
@@ -486,6 +493,7 @@ void TlsChannelSecurityConnector::ServerAuthorizationCheckArgDestroy(
arg->destroy_context(arg->context);
}
delete arg;
+ arg = nullptr;
}
// -------------------server security connector-------------------
@@ -509,12 +517,91 @@ TlsServerSecurityConnector::CreateTlsServerSecurityConnector(
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();
@@ -539,10 +626,15 @@ TlsServerSecurityConnector::~TlsServerSecurityConnector() {
// Cancel all the watchers.
grpc_tls_certificate_distributor* distributor =
options_->certificate_distributor();
- distributor->CancelTlsCertificatesWatch(certificate_watcher_);
+ 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(
@@ -574,10 +666,98 @@ void TlsServerSecurityConnector::check_peer(
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);
- tsi_peer_destruct(&peer);
+ 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(
diff --git a/src/core/lib/security/security_connector/tls/tls_security_connector.h b/src/core/lib/security/security_connector/tls/tls_security_connector.h
index 80c26954ac..cd830b9b7a 100644
--- a/src/core/lib/security/security_connector/tls/tls_security_connector.h
+++ b/src/core/lib/security/security_connector/tls/tls_security_connector.h
@@ -219,9 +219,31 @@ class TlsServerSecurityConnector final : public grpc_server_security_connector {
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_
diff --git a/src/cpp/sgx/sgx_ra_tls_backends.cc b/src/cpp/sgx/sgx_ra_tls_backends.cc
new file mode 100644
index 0000000000..2ac4bff09f
--- /dev/null
+++ b/src/cpp/sgx/sgx_ra_tls_backends.cc
@@ -0,0 +1,260 @@
+/*
+ *
+ * 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
diff --git a/src/cpp/sgx/sgx_ra_tls_backends.h b/src/cpp/sgx/sgx_ra_tls_backends.h
new file mode 100644
index 0000000000..0c28518e46
--- /dev/null
+++ b/src/cpp/sgx/sgx_ra_tls_backends.h
@@ -0,0 +1,114 @@
+/*
+ *
+ * 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
diff --git a/src/cpp/sgx/sgx_ra_tls_credentials.cc b/src/cpp/sgx/sgx_ra_tls_credentials.cc
new file mode 100644
index 0000000000..c0acf5fbd0
--- /dev/null
+++ b/src/cpp/sgx/sgx_ra_tls_credentials.cc
@@ -0,0 +1,98 @@
+/*
+ *
+ * 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
diff --git a/src/cpp/sgx/sgx_ra_tls_occlum.cc b/src/cpp/sgx/sgx_ra_tls_occlum.cc
new file mode 100644
index 0000000000..ef0086aedf
--- /dev/null
+++ b/src/cpp/sgx/sgx_ra_tls_occlum.cc
@@ -0,0 +1,325 @@
+/*
+ *
+ * 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
diff --git a/src/cpp/sgx/sgx_ra_tls_options.cc b/src/cpp/sgx/sgx_ra_tls_options.cc
new file mode 100644
index 0000000000..c5a9fa499c
--- /dev/null
+++ b/src/cpp/sgx/sgx_ra_tls_options.cc
@@ -0,0 +1,55 @@
+/*
+ *
+ * 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
diff --git a/src/cpp/sgx/sgx_ra_tls_utils.cc b/src/cpp/sgx/sgx_ra_tls_utils.cc
new file mode 100644
index 0000000000..68c57beacb
--- /dev/null
+++ b/src/cpp/sgx/sgx_ra_tls_utils.cc
@@ -0,0 +1,169 @@
+/*
+ *
+ * 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
diff --git a/src/cpp/sgx/sgx_ra_tls_utils.h b/src/cpp/sgx/sgx_ra_tls_utils.h
new file mode 100644
index 0000000000..35bfde9342
--- /dev/null
+++ b/src/cpp/sgx/sgx_ra_tls_utils.h
@@ -0,0 +1,68 @@
+/*
+ *
+ * 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
--
2.34.1