From 00d3a4744aa7fecea3c07dc70be26aa55ffdfa2b Mon Sep 17 00:00:00 2001 From: Qi Zheng 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 +#include +#include + +#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 \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 +#include +#include +#include + +#include +#include + +#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 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 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 +#include +#include + +#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 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 +#include +#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 \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 + +#include +#include + +#include + +namespace grpc { +namespace sgx { + +struct sgx_config; + +std::vector 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 TlsCredentials(sgx_config sgx_cfg); + +std::shared_ptr TlsCredentials(const char* sgx_cfg_json); + +std::shared_ptr TlsServerCredentials(sgx_config sgx_cfg); + +std::shared_ptr TlsServerCredentials(const char* sgx_cfg_json); + +std::shared_ptr CreateSecureChannel( + string target_str, std::shared_ptr 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 +#include +#include +#include +#include +#include + +#include +#include + +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 + 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 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(arg->target_name)); - gpr_free(const_cast(arg->peer_cert)); - gpr_free(const_cast(arg->peer_cert_full_chain)); + gpr_check_free(const_cast(arg->target_name)); + gpr_check_free(const_cast(arg->peer_cert)); + gpr_check_free(const_cast(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(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(arg->target_name)); + gpr_check_free(const_cast(arg->peer_cert)); + gpr_check_free(const_cast(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 server_creds, RefCountedPtr 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(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* 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(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(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 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 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 ra_tls_get_key_cert() { +#ifdef SGX_RA_TLS_OCCLUM_BACKEND + return occlum_get_key_cert(); +#endif +} + +static std::vector get_identity_key_cert_pairs( + std::vector 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 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 lock(_ctx_.mtx); + + _ctx_.cache.id++; + + auto certificate_provider = _ctx_.cache.certificate_provider.insert({ + _ctx_.cache.id, + std::make_shared( + 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(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 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 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 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 lock(_ctx_.mtx); + + _ctx_.cache.id++; + + auto authorization_check = _ctx_.cache.authorization_check.insert({ + _ctx_.cache.id, std::make_shared() + }).first; + + auto authorization_check_config = _ctx_.cache.authorization_check_config.insert({ + _ctx_.cache.id, + std::make_shared( + 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 +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +// 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_mrs; +}; + +struct ra_tls_cache { + int id = 0; + std::unordered_map< + int, std::shared_ptr + > certificate_provider; + std::unordered_map< + int, std::shared_ptr + > authorization_check; + std::unordered_map< + int, std::shared_ptr + > 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 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 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(options)); +}; + +std::shared_ptr 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(options)); +}; + +std::shared_ptr 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(options)); +}; + +std::shared_ptr 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(options)); +}; + +std::shared_ptr CreateSecureChannel( + string target_str, std::shared_ptr 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 +#include +#include +#include +#include +#include +#include + +#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 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 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 +#include +#include + +#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 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 +#include +#include +#include + +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 +#include +#include +#include + +#define grpc_printf printf +#define grpc_fprintf fprintf + +#include + +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