2407 lines
79 KiB
Diff
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,
|
|
+ "e_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, "e_buf, "e_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
|
|
|