[toolchain] Update grpc_ratls toolchain with patching way
Signed-off-by: Qi Zheng <huaiqing.zq@antgroup.com>
This commit is contained in:
		
							parent
							
								
									a82cfb87f0
								
							
						
					
					
						commit
						cb1ee85605
					
				
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @ -0,0 +1,26 @@ | ||||
| From 34ac52eb5d694f0ef0cec30c66c8c417cba9789c Mon Sep 17 00:00:00 2001 | ||||
| From: Qi Zheng <huaiqing.zq@antgroup.com> | ||||
| Date: Tue, 14 Nov 2023 07:43:41 +0000 | ||||
| Subject: [PATCH] Fixes build with glibc 2.34 | ||||
| 
 | ||||
| ---
 | ||||
|  absl/debugging/failure_signal_handler.cc | 3 ++- | ||||
|  1 file changed, 2 insertions(+), 1 deletion(-) | ||||
| 
 | ||||
| diff --git a/absl/debugging/failure_signal_handler.cc b/absl/debugging/failure_signal_handler.cc
 | ||||
| index a9ed6ef9..3ddebd74 100644
 | ||||
| --- a/absl/debugging/failure_signal_handler.cc
 | ||||
| +++ b/absl/debugging/failure_signal_handler.cc
 | ||||
| @@ -136,7 +136,8 @@ static bool SetupAlternateStackOnce() {
 | ||||
|  #else | ||||
|    const size_t page_mask = sysconf(_SC_PAGESIZE) - 1; | ||||
|  #endif | ||||
| -  size_t stack_size = (std::max(SIGSTKSZ, 65536) + page_mask) & ~page_mask;
 | ||||
| +  size_t stack_size =
 | ||||
| +      (std::max<size_t>(SIGSTKSZ, 65536) + page_mask) & ~page_mask;
 | ||||
|  #if defined(ABSL_HAVE_ADDRESS_SANITIZER) || \ | ||||
|      defined(ABSL_HAVE_MEMORY_SANITIZER) || defined(ABSL_HAVE_THREAD_SANITIZER) | ||||
|    // Account for sanitizer instrumentation requiring additional stack space. | ||||
| -- 
 | ||||
| 2.34.1 | ||||
| 
 | ||||
| @ -36,9 +36,6 @@ function build_grpc_ratls() { | ||||
|     # Copy occlum dcap lib first to ease linking | ||||
|     cp ${DCAP_LIB_PATH}/libocclum_dcap.so* ${INSTALL_PREFIX}/lib | ||||
| 
 | ||||
|     # Copy ratls added/updated files to grpc source | ||||
|     cp -rf grpc/${GRPC_VERSION}/* ${GRPC_PATH}/ | ||||
| 
 | ||||
|     ABSEIL_PATH=${GRPC_PATH}/third_party/abseil-cpp | ||||
| 
 | ||||
|     # build and install abseil library | ||||
|  | ||||
| @ -5,10 +5,10 @@ source ./env.sh | ||||
| 
 | ||||
| # Download and update cmake | ||||
| function dl_and_build_cmake() { | ||||
|     # Ubuntu 20.04 has newer enough cmake version | ||||
|     # Ubuntu 20.04/22.04 has newer enough cmake version | ||||
|     if [ -f "/etc/os-release" ]; then | ||||
|         local os_name=$(cat /etc/os-release) | ||||
|         if [[ $os_name =~ "Ubuntu" && $os_name =~ "20.04" ]]; then | ||||
|         if [[ $os_name =~ "Ubuntu" ]]; then | ||||
|             return | ||||
|         fi | ||||
|     fi | ||||
| @ -27,9 +27,16 @@ function dl_grpc() { | ||||
|     # GRPC source code | ||||
|     rm -rf ${GRPC_PATH} | ||||
|     git clone https://github.com/grpc/grpc -b ${GRPC_VERSION} ${GRPC_PATH} | ||||
|     pushd ${GRPC_PATH} \ | ||||
|         && git checkout ${GRPC_VERSION} \ | ||||
|         && git submodule update --init | ||||
|     pushd ${GRPC_PATH} | ||||
|     git submodule update --init | ||||
|     # Apply occlum patch | ||||
|     git apply ../0001-Add-Occlum-SGX-tls-function.patch | ||||
|     popd | ||||
| 
 | ||||
|     ABSEIL_PATH=${GRPC_PATH}/third_party/abseil-cpp | ||||
|     pushd $ABSEIL_PATH | ||||
|     # Apply patch | ||||
|     git apply ../../../0001-Fixes-build-with-glibc-2.34.patch | ||||
|     popd | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -1 +0,0 @@ | ||||
| grpc-* | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @ -1,64 +0,0 @@ | ||||
| # Copyright (c) 2022 Intel Corporation | ||||
| # | ||||
| # Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| # you may not use this file except in compliance with the License. | ||||
| # You may obtain a copy of the License at | ||||
| # | ||||
| #     http://www.apache.org/licenses/LICENSE-2.0 | ||||
| # | ||||
| # Unless required by applicable law or agreed to in writing, software | ||||
| # distributed under the License is distributed on an "AS IS" BASIS, | ||||
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
| # See the License for the specific language governing permissions and | ||||
| # limitations under the License. | ||||
| 
 | ||||
| cmake_minimum_required(VERSION 3.5.1) | ||||
| 
 | ||||
| project(RA-TLS C CXX) | ||||
| 
 | ||||
| include(../cmake/common.cmake) | ||||
| 
 | ||||
| # Proto file | ||||
| get_filename_component(hw_proto "../../protos/ratls.proto" ABSOLUTE) | ||||
| get_filename_component(hw_proto_path "${hw_proto}" PATH) | ||||
| 
 | ||||
| # Generated sources | ||||
| set(hw_proto_srcs "${CMAKE_CURRENT_BINARY_DIR}/ratls.pb.cc") | ||||
| set(hw_proto_hdrs "${CMAKE_CURRENT_BINARY_DIR}/ratls.pb.h") | ||||
| set(hw_grpc_srcs "${CMAKE_CURRENT_BINARY_DIR}/ratls.grpc.pb.cc") | ||||
| set(hw_grpc_hdrs "${CMAKE_CURRENT_BINARY_DIR}/ratls.grpc.pb.h") | ||||
| add_custom_command( | ||||
|       OUTPUT "${hw_proto_srcs}" "${hw_proto_hdrs}" "${hw_grpc_srcs}" "${hw_grpc_hdrs}" | ||||
|       COMMAND ${_PROTOBUF_PROTOC} | ||||
|       ARGS --grpc_out "${CMAKE_CURRENT_BINARY_DIR}" | ||||
|         --cpp_out "${CMAKE_CURRENT_BINARY_DIR}" | ||||
|         -I "${hw_proto_path}" | ||||
|         --plugin=protoc-gen-grpc="${_GRPC_CPP_PLUGIN_EXECUTABLE}" | ||||
|         "${hw_proto}" | ||||
|       DEPENDS "${hw_proto}") | ||||
| 
 | ||||
| # Include generated *.pb.h files | ||||
| include_directories("${CMAKE_CURRENT_BINARY_DIR}") | ||||
| 
 | ||||
| # hw_grpc_proto | ||||
| add_library(hw_grpc_proto SHARED | ||||
|   ${hw_grpc_srcs} | ||||
|   ${hw_grpc_hdrs} | ||||
|   ${hw_proto_srcs} | ||||
|   ${hw_proto_hdrs}) | ||||
| target_link_libraries(hw_grpc_proto | ||||
|   ${_REFLECTION} | ||||
|   ${_GRPC_GRPCPP} | ||||
|   ${_PROTOBUF_LIBPROTOBUF}) | ||||
| 
 | ||||
| foreach(_target grpc_ratls_client grpc_ratls_server) | ||||
|   add_library(${_target} SHARED "${_target}.cc") | ||||
|   target_link_libraries(${_target} | ||||
|     hw_grpc_proto) | ||||
| endforeach() | ||||
| 
 | ||||
| foreach(_target client server) | ||||
|   add_executable(${_target} "${_target}.cc") | ||||
|   target_link_libraries(${_target} | ||||
|     grpc_ratls_${_target}) | ||||
| endforeach() | ||||
| @ -1,15 +0,0 @@ | ||||
| # gRPC | ||||
| 
 | ||||
| This directory contains the Makefile and the template manifest for the most | ||||
| recent version of gRPC (as of this writing, version 3.18.0). This was tested | ||||
| on a machine with SGX v1 and Ubuntu 18.04. | ||||
| 
 | ||||
| The Makefile and the template manifest contain extensive comments and are made | ||||
| self-explanatory. Please review them to gain understanding of Gramine-SGX | ||||
| and requirements for applications running under Gramine-SGX. | ||||
| 
 | ||||
| # Quick Start | ||||
| 
 | ||||
| ``` | ||||
| ./build.sh | ||||
| ``` | ||||
| @ -1,27 +0,0 @@ | ||||
| # | ||||
| # Copyright (c) 2022 Intel Corporation | ||||
| # | ||||
| # Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| # you may not use this file except in compliance with the License. | ||||
| # You may obtain a copy of the License at | ||||
| # | ||||
| #     http://www.apache.org/licenses/LICENSE-2.0 | ||||
| # | ||||
| # Unless required by applicable law or agreed to in writing, software | ||||
| # distributed under the License is distributed on an "AS IS" BASIS, | ||||
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
| # See the License for the specific language governing permissions and | ||||
| # limitations under the License. | ||||
| 
 | ||||
| set -ex | ||||
| 
 | ||||
| export BUILD_TYPE=Release | ||||
| export EXP_PATH=`dirname $0` | ||||
| 
 | ||||
| # build c++ example | ||||
| cd ${EXP_PATH} | ||||
| mkdir -p build | ||||
| cd build | ||||
| cmake -D CMAKE_PREFIX_PATH=${INSTALL_PREFIX} -D CMAKE_BUILD_TYPE=${BUILD_TYPE} .. | ||||
| make -j `nproc` | ||||
| cd - | ||||
| @ -1,41 +0,0 @@ | ||||
| /*
 | ||||
|  * | ||||
|  * Copyright (c) 2022 Intel Corporation | ||||
|  * | ||||
|  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|  * you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * | ||||
|  *     http://www.apache.org/licenses/LICENSE-2.0
 | ||||
|  * | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an "AS IS" BASIS, | ||||
|  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|  * See the License for the specific language governing permissions and | ||||
|  * limitations under the License. | ||||
|  * | ||||
|  */ | ||||
| #include <stdio.h> | ||||
| #include <stdlib.h> | ||||
| #include <unistd.h> | ||||
| 
 | ||||
| #include "../grpc_ratls_client.h" | ||||
| 
 | ||||
| 
 | ||||
| int main(int argc, char** argv) { | ||||
|     // Parse arguments
 | ||||
|     if (argc < 4) { | ||||
|         printf("[ERROR] Three arguments must be provided\n\n"); | ||||
|         printf("Usage: client <grpc-server addr> <request_name> <secret_file_to_be_saved>\n"); | ||||
|         return -1; | ||||
|     } | ||||
| 
 | ||||
|     grpc_ratls_get_secret( | ||||
|         argv[1], | ||||
|         "dynamic_config.json", | ||||
|         argv[2], | ||||
|         argv[3] | ||||
|     ); | ||||
| 
 | ||||
|     return 0; | ||||
| } | ||||
| @ -1,212 +0,0 @@ | ||||
| /*
 | ||||
|  * | ||||
|  * Copyright (c) 2022 Intel Corporation | ||||
|  * | ||||
|  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|  * you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * | ||||
|  *     http://www.apache.org/licenses/LICENSE-2.0
 | ||||
|  * | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an "AS IS" BASIS, | ||||
|  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|  * See the License for the specific language governing permissions and | ||||
|  * limitations under the License. | ||||
|  * | ||||
|  */ | ||||
| #include <stdio.h> | ||||
| #include <string.h> | ||||
| #include <iostream> | ||||
| #include <fstream> | ||||
| 
 | ||||
| #include <grpcpp/grpcpp.h> | ||||
| #include <grpcpp/security/sgx/sgx_ra_tls.h> | ||||
| 
 | ||||
| #ifdef BAZEL_BUILD | ||||
| #include "examples/protos/ratls.grpc.pb.h" | ||||
| #else | ||||
| #include "ratls.grpc.pb.h" | ||||
| #endif | ||||
| 
 | ||||
| #include "../grpc_ratls_client.h" | ||||
| 
 | ||||
| using ratls::GrSecret; | ||||
| using ratls::SecretRequest; | ||||
| using ratls::SecretReply; | ||||
| 
 | ||||
| typedef enum { | ||||
|     GRPC_RATLS_SUCCESS = 0,             /// Success
 | ||||
|     GRPC_RATLS_ERR = -1,                /// General error
 | ||||
|     GRPC_RATLS_INVALID_PARAM = -2,      /// Invalid parameter
 | ||||
|     GRPC_RATLS_BUF_ERR = -3,            /// Invalid buffer or buffer allocation failure
 | ||||
|     GRPC_RATLS_NO_SECRET = -4,          /// No valid secret
 | ||||
|     GRPC_RATLS_BUF_TOO_SMALL = -5       /// Buffer is too small
 | ||||
| } grpc_ratls_result_t; | ||||
| 
 | ||||
| // Client
 | ||||
| class GrSecretClient { | ||||
|     public: | ||||
|         GrSecretClient(std::shared_ptr<grpc::Channel> channel) : stub_(GrSecret::NewStub(channel)) {} | ||||
| 
 | ||||
|         std::string GetSecret(const std::string& name) { | ||||
|             SecretRequest request; | ||||
|             request.set_name(name); | ||||
| 
 | ||||
|             SecretReply reply; | ||||
| 
 | ||||
|             grpc::ClientContext context; | ||||
| 
 | ||||
|             grpc::Status status = stub_->GetSecret(&context, request, &reply); | ||||
| 
 | ||||
|             if (status.ok()) { | ||||
|                 return reply.secret(); | ||||
|             } else { | ||||
|                 std::cout << status.error_code() << ": " << status.error_message() << std::endl; | ||||
|                 return ""; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|     private: | ||||
|         std::unique_ptr<GrSecret::Stub> stub_; | ||||
| }; | ||||
| 
 | ||||
| static const unsigned char base64_table[65] = | ||||
|     "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; | ||||
| 
 | ||||
| static size_t base64_decode_len(const char *b64input) { | ||||
|     size_t len = strlen(b64input), padding = 0; | ||||
| 
 | ||||
|     if (b64input[len - 1] == '=' && b64input[len - 2] == '=') { //last two chars are =
 | ||||
|         padding = 2; | ||||
|     } else if (b64input[len - 1] == '=') { //last char is =
 | ||||
|         padding = 1; | ||||
|     } | ||||
| 
 | ||||
|     return (len * 3) / 4 - padding; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * base64_decode - Base64 decode | ||||
|  */ | ||||
| void base64_decode(const char *b64input, unsigned char *dest, size_t dest_len) { | ||||
|     unsigned char dtable[256], *pos, block[4], tmp; | ||||
|     size_t i, count, olen; | ||||
|     size_t len = strlen(b64input); | ||||
| 
 | ||||
|     memset(dtable, 0x80, 256); | ||||
|     for (i = 0; i < sizeof(base64_table) - 1; i++) { | ||||
|         dtable[base64_table[i]] = (unsigned char) i; | ||||
|     } | ||||
|     dtable['='] = 0; | ||||
| 
 | ||||
|     olen = base64_decode_len(b64input); | ||||
|     if (olen > dest_len) { | ||||
|         printf("Base64 encoded length %ld is biggeer than %ld\n", olen, dest_len); | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     pos = dest; | ||||
|     count = 0; | ||||
|     for (i = 0; i < len; i++) { | ||||
|         tmp = dtable[(unsigned char)b64input[i]]; | ||||
|         if (tmp == 0x80) { | ||||
|             continue; | ||||
|         } | ||||
|         block[count] = tmp; | ||||
|         count++; | ||||
|         if (count == 4) { | ||||
|             *pos++ = (block[0] << 2) | (block[1] >> 4); | ||||
|             *pos++ = (block[1] << 4) | (block[2] >> 2); | ||||
|             *pos++ = (block[2] << 6) | block[3]; | ||||
|             count = 0; | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| static grpc_ratls_result_t grpc_ratls_get_secret_string( | ||||
|     const char *server_addr, | ||||
|     const char *config_json, | ||||
|     const char *name, | ||||
|     std::string* secret_string | ||||
| ) | ||||
| { | ||||
|     auto cred = grpc::sgx::TlsCredentials(config_json); | ||||
|     auto channel = grpc::CreateChannel(server_addr, cred); | ||||
| 
 | ||||
|     GrSecretClient gr_secret(channel); | ||||
| 
 | ||||
|     std::string secret = gr_secret.GetSecret(name); | ||||
|     // std::cout << "secret received: " << secret << "len: " << secret.length() << std::endl;
 | ||||
| 
 | ||||
|     if (secret.empty()) { | ||||
|         return GRPC_RATLS_NO_SECRET; | ||||
|     } else { | ||||
|         //Decode From Base64
 | ||||
|         size_t len = base64_decode_len(secret.c_str()); | ||||
|         if (len) { | ||||
|             char *secret_orig = (char *)malloc(len); | ||||
|             if (!secret_orig) { | ||||
|                 return GRPC_RATLS_BUF_ERR; | ||||
|             } | ||||
|             base64_decode(secret.c_str(), (unsigned char *)secret_orig, len); | ||||
|             secret_string->assign(secret_orig, secret_orig + len - 1); | ||||
|             free(secret_orig); | ||||
| 
 | ||||
|             return GRPC_RATLS_SUCCESS; | ||||
|         } | ||||
| 
 | ||||
|         return GRPC_RATLS_ERR; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| // Get secret to file
 | ||||
| int grpc_ratls_get_secret( | ||||
|     const char *server_addr, | ||||
|     const char *config_json, | ||||
|     const char *name, | ||||
|     const char *secret_file | ||||
| ) | ||||
| { | ||||
|     std::string secret_string; | ||||
|     grpc_ratls_result_t ret = grpc_ratls_get_secret_string( | ||||
|         server_addr, config_json, name, &secret_string | ||||
|     ); | ||||
| 
 | ||||
|     if (ret == GRPC_RATLS_SUCCESS) { | ||||
|         //write to file
 | ||||
|         std::ofstream myfile; | ||||
|         myfile.open(secret_file); | ||||
|         myfile << secret_string; | ||||
|         myfile.close(); | ||||
|     } | ||||
| 
 | ||||
|     return ret; | ||||
| } | ||||
| 
 | ||||
| // Get secret to buffer
 | ||||
| int grpc_ratls_get_secret_to_buf( | ||||
|     const char *server_addr, | ||||
|     const char *config_json, | ||||
|     const char *name, | ||||
|     char *secret_buf, | ||||
|     unsigned int *buf_len | ||||
| ) | ||||
| { | ||||
|     std::string secret_string; | ||||
|     grpc_ratls_result_t ret = grpc_ratls_get_secret_string( | ||||
|         server_addr, config_json, name, &secret_string | ||||
|     ); | ||||
| 
 | ||||
|     if (ret == GRPC_RATLS_SUCCESS) { | ||||
|         if (*buf_len < secret_string.size()) { | ||||
|             std::cout << "buffer size is smaller than the secret string length " << secret_string.size() << std::endl;; | ||||
|             return GRPC_RATLS_BUF_TOO_SMALL; | ||||
|         } | ||||
|         //write to buffer
 | ||||
|         memcpy(secret_buf, secret_string.data(), secret_string.size()); | ||||
|         *buf_len = secret_string.size(); | ||||
|     } | ||||
| 
 | ||||
|     return ret; | ||||
| } | ||||
| @ -1,28 +0,0 @@ | ||||
| #ifndef _GRPC_RATLS_CLIENT_H_ | ||||
| #define _GRPC_RATLS_CLIENT_H_ | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| extern "C" { | ||||
| #endif | ||||
| 
 | ||||
| // client get secret
 | ||||
| extern int grpc_ratls_get_secret( | ||||
|     const char *server_addr, // grpc server address+port, such as "localhost:50051"
 | ||||
|     const char *config_json, // ratls handshake config json file
 | ||||
|     const char *name, // secret name to be requested
 | ||||
|     const char *secret_file // secret file to be saved
 | ||||
| ); | ||||
| 
 | ||||
| extern int grpc_ratls_get_secret_to_buf( | ||||
|     const char *server_addr, // grpc server address+port, such as "localhost:50051"
 | ||||
|     const char *config_json, // ratls handshake config json file
 | ||||
|     const char *name, // secret name to be requested
 | ||||
|     char *secret_buf, // buffer to save secret
 | ||||
|     unsigned int *buf_len // buffer size
 | ||||
| ); | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| #endif  // _GRPC_RATLS_CLIENT_H_
 | ||||
| @ -1,96 +0,0 @@ | ||||
| /*
 | ||||
|  * | ||||
|  * Copyright (c) 2022 Intel Corporation | ||||
|  * | ||||
|  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|  * you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * | ||||
|  *     http://www.apache.org/licenses/LICENSE-2.0
 | ||||
|  * | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an "AS IS" BASIS, | ||||
|  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|  * See the License for the specific language governing permissions and | ||||
|  * limitations under the License. | ||||
|  * | ||||
|  */ | ||||
| 
 | ||||
| #include <grpcpp/grpcpp.h> | ||||
| #include <grpcpp/security/sgx/sgx_ra_tls.h> | ||||
| #include <grpcpp/ext/proto_server_reflection_plugin.h> | ||||
| 
 | ||||
| #ifdef BAZEL_BUILD | ||||
| #include "examples/protos/ratls.grpc.pb.h" | ||||
| #else | ||||
| #include "ratls.grpc.pb.h" | ||||
| #endif | ||||
| 
 | ||||
| #include "../grpc_ratls_server.h" | ||||
| 
 | ||||
| using ratls::GrSecret; | ||||
| using ratls::SecretRequest; | ||||
| using ratls::SecretReply; | ||||
| 
 | ||||
| 
 | ||||
| // Logic and data behind the server's behavior.
 | ||||
| class GrSecretServiceImpl final: public GrSecret::Service { | ||||
|     public: | ||||
|         grpc::Status GetSecret( | ||||
|             grpc::ServerContext* context, const SecretRequest* request, SecretReply* reply) override { | ||||
|             //std::cout << "Request:  " << request->name() << std::endl;
 | ||||
|             auto secret = this->get_secret_string(request->name().c_str()); | ||||
|             if (!secret.empty()) { | ||||
|                 reply->set_secret(secret); | ||||
|                 return grpc::Status::OK; | ||||
|             } else { | ||||
|                 return grpc::Status::CANCELLED; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         GrSecretServiceImpl(const char* file) : secret_file(nullptr) { | ||||
|             this->secret_file = file; | ||||
|         } | ||||
| 
 | ||||
|     private: | ||||
|         std::string get_secret_string(const char *name) { | ||||
|             std::string secret = ""; | ||||
|             class grpc::sgx::json_engine secret_config(this->secret_file); | ||||
|             auto item = secret_config.get_item(secret_config.get_handle(), name); | ||||
|             if (item) { | ||||
|                 secret = secret_config.print_item(item); | ||||
|             } | ||||
| 
 | ||||
|             return secret; | ||||
|         } | ||||
| 
 | ||||
|         const char *secret_file; | ||||
| }; | ||||
| 
 | ||||
| 
 | ||||
| int grpc_ratls_start_server( | ||||
|     const char *server_addr, | ||||
|     const char *config_json, | ||||
|     const char *secret_json | ||||
| )  | ||||
| { | ||||
|     GrSecretServiceImpl service(secret_json); | ||||
| 
 | ||||
|     grpc::EnableDefaultHealthCheckService(true); | ||||
|     grpc::reflection::InitProtoReflectionServerBuilderPlugin(); | ||||
|     grpc::ServerBuilder builder; | ||||
| 
 | ||||
|     auto creds = grpc::sgx::TlsServerCredentials(config_json); | ||||
|     GPR_ASSERT(creds.get() != nullptr); | ||||
| 
 | ||||
|     builder.AddListeningPort(server_addr, creds); | ||||
|     builder.RegisterService(&service); | ||||
| 
 | ||||
|     std::unique_ptr<grpc::Server> server(builder.BuildAndStart()); | ||||
|     std::cout << "Server listening on " << server_addr << std::endl; | ||||
| 
 | ||||
|     server->Wait(); | ||||
| 
 | ||||
|     return 0; | ||||
| } | ||||
| 
 | ||||
| @ -1,19 +0,0 @@ | ||||
| #ifndef _GRPC_RATLS_SERVER_H_ | ||||
| #define _GRPC_RATLS_SERVER_H_ | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| extern "C" { | ||||
| #endif | ||||
| 
 | ||||
| // start server
 | ||||
| extern int grpc_ratls_start_server( | ||||
|     const char *server_addr, // grpc server address+port, such as "localhost:50051"
 | ||||
|     const char *config_json, // ratls handshake config json file
 | ||||
|     const char *secret_json  // secret config json file
 | ||||
| ); | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| #endif  // _GRPC_RATLS_SERVER_H_
 | ||||
| @ -1,37 +0,0 @@ | ||||
| /*
 | ||||
|  * | ||||
|  * Copyright (c) 2022 Intel Corporation | ||||
|  * | ||||
|  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|  * you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * | ||||
|  *     http://www.apache.org/licenses/LICENSE-2.0
 | ||||
|  * | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an "AS IS" BASIS, | ||||
|  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|  * See the License for the specific language governing permissions and | ||||
|  * limitations under the License. | ||||
|  * | ||||
|  */ | ||||
| #include <stdio.h> | ||||
| #include <stdlib.h> | ||||
| #include "../grpc_ratls_server.h" | ||||
| 
 | ||||
| 
 | ||||
| int main(int argc, char** argv) { | ||||
|     if (argc < 2) { | ||||
|         printf("[ERROR] One argument must be provided\n\n"); | ||||
|         printf("Usage: server <grpc-server addr>\n"); | ||||
|         return -1; | ||||
|     } | ||||
| 
 | ||||
|     grpc_ratls_start_server( | ||||
|         argv[1], | ||||
|         "dynamic_config.json", | ||||
|         "secret_config.json" | ||||
|     ); | ||||
| 
 | ||||
|     return 0; | ||||
| } | ||||
| @ -1,38 +0,0 @@ | ||||
| // Copyright (c) 2022 Intel Corporation | ||||
| //  | ||||
| // Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| // you may not use this file except in compliance with the License. | ||||
| // You may obtain a copy of the License at | ||||
| //  | ||||
| //     http://www.apache.org/licenses/LICENSE-2.0 | ||||
| //  | ||||
| // Unless required by applicable law or agreed to in writing, software | ||||
| // distributed under the License is distributed on an "AS IS" BASIS, | ||||
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
| // See the License for the specific language governing permissions and | ||||
| // limitations under the License. | ||||
| 
 | ||||
| syntax = "proto3"; | ||||
| 
 | ||||
| option java_multiple_files = true; | ||||
| option java_package = "io.grpc.examples.ratls"; | ||||
| option java_outer_classname = "RATLSProto"; | ||||
| option objc_class_prefix = "HLW"; | ||||
| 
 | ||||
| package ratls; | ||||
| 
 | ||||
| // The GRPC_RATLS secret service definition. | ||||
| service GrSecret { | ||||
|   // Sends a greeting | ||||
|   rpc GetSecret (SecretRequest) returns (SecretReply) {} | ||||
| } | ||||
| 
 | ||||
| // The request message containing the request's name. | ||||
| message SecretRequest { | ||||
|   string name = 1; | ||||
| } | ||||
| 
 | ||||
| // The response message containing the secret (base64 encoded string) | ||||
| message SecretReply { | ||||
|   string secret = 1; | ||||
| } | ||||
| @ -1,83 +0,0 @@ | ||||
| /*
 | ||||
|  * | ||||
|  * Copyright (c) 2022 Intel Corporation | ||||
|  * | ||||
|  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|  * you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * | ||||
|  *     http://www.apache.org/licenses/LICENSE-2.0
 | ||||
|  * | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an "AS IS" BASIS, | ||||
|  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|  * See the License for the specific language governing permissions and | ||||
|  * limitations under the License. | ||||
|  * | ||||
|  */ | ||||
| 
 | ||||
| #ifndef SGX_RA_TLS_H | ||||
| #define SGX_RA_TLS_H | ||||
| 
 | ||||
| #include <memory> | ||||
| 
 | ||||
| #include <grpcpp/security/credentials.h> | ||||
| #include <grpcpp/security/server_credentials.h> | ||||
| 
 | ||||
| #include <cjson/cJSON.h> | ||||
| 
 | ||||
| namespace grpc { | ||||
| namespace sgx { | ||||
| 
 | ||||
| struct sgx_config; | ||||
| 
 | ||||
| std::vector<std::string> ra_tls_get_key_cert(); | ||||
| 
 | ||||
| void ra_tls_parse_sgx_config(sgx_config sgx_cfg); | ||||
| 
 | ||||
| void ra_tls_parse_sgx_config(const char* file); | ||||
| 
 | ||||
| void ra_tls_verify_init(); | ||||
| 
 | ||||
| int ra_tls_auth_check_schedule(void* /* config_user_data */, | ||||
|                                grpc_tls_server_authorization_check_arg* arg); | ||||
| 
 | ||||
| std::shared_ptr<grpc::ChannelCredentials> TlsCredentials(sgx_config sgx_cfg); | ||||
| 
 | ||||
| std::shared_ptr<grpc::ChannelCredentials> TlsCredentials(const char* sgx_cfg_json); | ||||
| 
 | ||||
| std::shared_ptr<grpc::ServerCredentials> TlsServerCredentials(sgx_config sgx_cfg); | ||||
| 
 | ||||
| std::shared_ptr<grpc::ServerCredentials> TlsServerCredentials(const char* sgx_cfg_json); | ||||
| 
 | ||||
| std::shared_ptr<grpc::Channel> CreateSecureChannel( | ||||
|     string target_str, std::shared_ptr<grpc::ChannelCredentials> channel_creds); | ||||
| 
 | ||||
| class json_engine { | ||||
|     public: | ||||
|         json_engine(); | ||||
| 
 | ||||
|         json_engine(const char*); | ||||
| 
 | ||||
|         ~json_engine(); | ||||
| 
 | ||||
|         bool open(const char*); | ||||
| 
 | ||||
|         void close(); | ||||
| 
 | ||||
|         cJSON* get_handle(); | ||||
| 
 | ||||
|         cJSON* get_item(cJSON* obj, const char* item); | ||||
| 
 | ||||
|         char* print_item(cJSON* obj); | ||||
| 
 | ||||
|         bool compare_item(cJSON* obj, const char* item); | ||||
| 
 | ||||
|     private: | ||||
|         cJSON* handle; | ||||
| }; | ||||
| 
 | ||||
| }  // namespace sgx
 | ||||
| }  // namespace grpc
 | ||||
| 
 | ||||
| #endif  // SGX_RA_TLS_H
 | ||||
| @ -1,67 +0,0 @@ | ||||
| /*
 | ||||
|  * | ||||
|  * Copyright (c) 2022 Intel Corporation | ||||
|  * | ||||
|  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|  * you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * | ||||
|  *     http://www.apache.org/licenses/LICENSE-2.0
 | ||||
|  * | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an "AS IS" BASIS, | ||||
|  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|  * See the License for the specific language governing permissions and | ||||
|  * limitations under the License. | ||||
|  * | ||||
|  */ | ||||
| 
 | ||||
| #ifndef SGX_RA_TLS_OPTIONS_H | ||||
| #define SGX_RA_TLS_OPTIONS_H | ||||
| 
 | ||||
| #include <grpc/grpc_security_constants.h> | ||||
| #include <grpc/status.h> | ||||
| #include <grpc/support/log.h> | ||||
| #include <grpcpp/security/tls_certificate_provider.h> | ||||
| #include <grpcpp/security/tls_credentials_options.h> | ||||
| #include <grpcpp/support/config.h> | ||||
| 
 | ||||
| #include <memory> | ||||
| #include <vector> | ||||
| 
 | ||||
| namespace grpc { | ||||
| namespace sgx { | ||||
| 
 | ||||
| // Contains configurable options on the client side.
 | ||||
| // Client side doesn't need to always use certificate provider. When the
 | ||||
| // certificate provider is not set, we will use the root certificates stored
 | ||||
| // in the system default locations, and assume client won't provide any
 | ||||
| // identity certificates(single side TLS).
 | ||||
| // It is used for experimental purposes for now and it is subject to change.
 | ||||
| class CredentialsOptions final : public grpc::experimental::TlsCredentialsOptions { | ||||
|  public: | ||||
| 
 | ||||
|   explicit CredentialsOptions() : TlsCredentialsOptions() {} | ||||
| 
 | ||||
|   // Sets option to request the certificates from the client.
 | ||||
|   // The default is GRPC_SSL_DONT_REQUEST_CLIENT_CERTIFICATE.
 | ||||
|   void set_cert_request_type( | ||||
|       grpc_ssl_client_certificate_request_type cert_request_type); | ||||
| 
 | ||||
|   // Sets the option to verify the server.
 | ||||
|   // The default is GRPC_TLS_SERVER_VERIFICATION.
 | ||||
|   void set_verification_option( | ||||
|       grpc_tls_server_verification_option server_verification_option); | ||||
| 
 | ||||
|   // Sets the custom authorization config.
 | ||||
|   void set_authorization_check_config( | ||||
|       std::shared_ptr<grpc::experimental::TlsServerAuthorizationCheckConfig> | ||||
|           authorization_check_config); | ||||
| 
 | ||||
|  private: | ||||
| }; | ||||
| 
 | ||||
| }  // namespace sgx
 | ||||
| }  // namespace grpc
 | ||||
| 
 | ||||
| #endif  // SGX_RA_TLS_OPTIONS_H
 | ||||
| @ -1,133 +0,0 @@ | ||||
| /*
 | ||||
|  * | ||||
|  * Copyright 2018 gRPC authors. | ||||
|  * | ||||
|  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|  * you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * | ||||
|  *     http://www.apache.org/licenses/LICENSE-2.0
 | ||||
|  * | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an "AS IS" BASIS, | ||||
|  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|  * See the License for the specific language governing permissions and | ||||
|  * limitations under the License. | ||||
|  * | ||||
|  */ | ||||
| 
 | ||||
| #include <grpc/support/port_platform.h> | ||||
| 
 | ||||
| #include "src/core/lib/security/credentials/tls/tls_credentials.h" | ||||
| 
 | ||||
| #include <cstring> | ||||
| 
 | ||||
| #include <grpc/grpc.h> | ||||
| #include <grpc/support/alloc.h> | ||||
| #include <grpc/support/log.h> | ||||
| #include <grpc/support/string_util.h> | ||||
| 
 | ||||
| #include "src/core/lib/channel/channel_args.h" | ||||
| #include "src/core/lib/security/security_connector/tls/tls_security_connector.h" | ||||
| 
 | ||||
| #define GRPC_CREDENTIALS_TYPE_TLS "Tls" | ||||
| 
 | ||||
| namespace { | ||||
| 
 | ||||
| bool CredentialOptionSanityCheck(const grpc_tls_credentials_options* options, | ||||
|                                  bool is_client) { | ||||
|   if (options == nullptr) { | ||||
|     gpr_log(GPR_ERROR, "TLS credentials options is nullptr."); | ||||
|     return false; | ||||
|   } | ||||
|   // TODO(ZhenLian): remove this when it is also supported on server side.
 | ||||
|   // if (!is_client && options->server_authorization_check_config() != nullptr) {
 | ||||
|   //   gpr_log(GPR_INFO,
 | ||||
|   //           "Server's credentials options should not contain server "
 | ||||
|   //           "authorization check config.");
 | ||||
|   // }
 | ||||
|   if (options->server_verification_option() != GRPC_TLS_SERVER_VERIFICATION && | ||||
|       options->server_authorization_check_config() == nullptr) { | ||||
|     gpr_log(GPR_ERROR, | ||||
|             "Should provider custom verifications if bypassing default ones."); | ||||
|     return false; | ||||
|   } | ||||
|   return true; | ||||
| } | ||||
| 
 | ||||
| }  // namespace
 | ||||
| 
 | ||||
| TlsCredentials::TlsCredentials( | ||||
|     grpc_core::RefCountedPtr<grpc_tls_credentials_options> options) | ||||
|     : grpc_channel_credentials(GRPC_CREDENTIALS_TYPE_TLS), | ||||
|       options_(std::move(options)) {} | ||||
| 
 | ||||
| TlsCredentials::~TlsCredentials() {} | ||||
| 
 | ||||
| grpc_core::RefCountedPtr<grpc_channel_security_connector> | ||||
| TlsCredentials::create_security_connector( | ||||
|     grpc_core::RefCountedPtr<grpc_call_credentials> call_creds, | ||||
|     const char* target_name, const grpc_channel_args* args, | ||||
|     grpc_channel_args** new_args) { | ||||
|   const char* overridden_target_name = nullptr; | ||||
|   tsi_ssl_session_cache* ssl_session_cache = nullptr; | ||||
|   for (size_t i = 0; args != nullptr && i < args->num_args; i++) { | ||||
|     grpc_arg* arg = &args->args[i]; | ||||
|     if (strcmp(arg->key, GRPC_SSL_TARGET_NAME_OVERRIDE_ARG) == 0 && | ||||
|         arg->type == GRPC_ARG_STRING) { | ||||
|       overridden_target_name = arg->value.string; | ||||
|     } | ||||
|     if (strcmp(arg->key, GRPC_SSL_SESSION_CACHE_ARG) == 0 && | ||||
|         arg->type == GRPC_ARG_POINTER) { | ||||
|       ssl_session_cache = | ||||
|           static_cast<tsi_ssl_session_cache*>(arg->value.pointer.p); | ||||
|     } | ||||
|   } | ||||
|   grpc_core::RefCountedPtr<grpc_channel_security_connector> sc = | ||||
|       grpc_core::TlsChannelSecurityConnector::CreateTlsChannelSecurityConnector( | ||||
|           this->Ref(), options_, std::move(call_creds), target_name, | ||||
|           overridden_target_name, ssl_session_cache); | ||||
|   if (sc == nullptr) { | ||||
|     return nullptr; | ||||
|   } | ||||
|   if (args != nullptr) { | ||||
|     grpc_arg new_arg = grpc_channel_arg_string_create( | ||||
|         const_cast<char*>(GRPC_ARG_HTTP2_SCHEME), const_cast<char*>("https")); | ||||
|     *new_args = grpc_channel_args_copy_and_add(args, &new_arg, 1); | ||||
|   } | ||||
|   return sc; | ||||
| } | ||||
| 
 | ||||
| TlsServerCredentials::TlsServerCredentials( | ||||
|     grpc_core::RefCountedPtr<grpc_tls_credentials_options> options) | ||||
|     : grpc_server_credentials(GRPC_CREDENTIALS_TYPE_TLS), | ||||
|       options_(std::move(options)) {} | ||||
| 
 | ||||
| TlsServerCredentials::~TlsServerCredentials() {} | ||||
| 
 | ||||
| grpc_core::RefCountedPtr<grpc_server_security_connector> | ||||
| TlsServerCredentials::create_security_connector( | ||||
|     const grpc_channel_args* /* args */) { | ||||
|   return grpc_core::TlsServerSecurityConnector:: | ||||
|       CreateTlsServerSecurityConnector(this->Ref(), options_); | ||||
| } | ||||
| 
 | ||||
| /** -- Wrapper APIs declared in grpc_security.h -- **/ | ||||
| 
 | ||||
| grpc_channel_credentials* grpc_tls_credentials_create( | ||||
|     grpc_tls_credentials_options* options) { | ||||
|   if (!CredentialOptionSanityCheck(options, true /* is_client */)) { | ||||
|     return nullptr; | ||||
|   } | ||||
|   return new TlsCredentials( | ||||
|       grpc_core::RefCountedPtr<grpc_tls_credentials_options>(options)); | ||||
| } | ||||
| 
 | ||||
| grpc_server_credentials* grpc_tls_server_credentials_create( | ||||
|     grpc_tls_credentials_options* options) { | ||||
|   if (!CredentialOptionSanityCheck(options, false /* is_client */)) { | ||||
|     return nullptr; | ||||
|   } | ||||
|   return new TlsServerCredentials( | ||||
|       grpc_core::RefCountedPtr<grpc_tls_credentials_options>(options)); | ||||
| } | ||||
| @ -1,863 +0,0 @@ | ||||
| /*
 | ||||
|  * | ||||
|  * Copyright 2018 gRPC authors. | ||||
|  * | ||||
|  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|  * you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * | ||||
|  *     http://www.apache.org/licenses/LICENSE-2.0
 | ||||
|  * | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an "AS IS" BASIS, | ||||
|  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|  * See the License for the specific language governing permissions and | ||||
|  * limitations under the License. | ||||
|  * | ||||
|  */ | ||||
| 
 | ||||
| #include <grpc/support/port_platform.h> | ||||
| 
 | ||||
| #include "src/core/lib/security/security_connector/tls/tls_security_connector.h" | ||||
| 
 | ||||
| #include <stdbool.h> | ||||
| #include <string.h> | ||||
| 
 | ||||
| #include "absl/strings/str_cat.h" | ||||
| #include "absl/strings/string_view.h" | ||||
| 
 | ||||
| #include <grpc/grpc.h> | ||||
| #include <grpc/support/alloc.h> | ||||
| #include <grpc/support/log.h> | ||||
| #include <grpc/support/string_util.h> | ||||
| 
 | ||||
| #include "src/core/lib/gprpp/host_port.h" | ||||
| #include "src/core/lib/security/credentials/ssl/ssl_credentials.h" | ||||
| #include "src/core/lib/security/credentials/tls/tls_credentials.h" | ||||
| #include "src/core/lib/security/security_connector/ssl_utils.h" | ||||
| #include "src/core/lib/security/transport/security_handshaker.h" | ||||
| #include "src/core/lib/slice/slice_internal.h" | ||||
| #include "src/core/lib/transport/transport.h" | ||||
| #include "src/core/tsi/ssl_transport_security.h" | ||||
| #include "src/core/tsi/transport_security.h" | ||||
| 
 | ||||
| namespace grpc_core { | ||||
| 
 | ||||
| namespace { | ||||
| 
 | ||||
| tsi_ssl_pem_key_cert_pair* ConvertToTsiPemKeyCertPair( | ||||
|     const PemKeyCertPairList& cert_pair_list) { | ||||
|   tsi_ssl_pem_key_cert_pair* tsi_pairs = nullptr; | ||||
|   size_t num_key_cert_pairs = cert_pair_list.size(); | ||||
|   if (num_key_cert_pairs > 0) { | ||||
|     GPR_ASSERT(cert_pair_list.data() != nullptr); | ||||
|     tsi_pairs = static_cast<tsi_ssl_pem_key_cert_pair*>( | ||||
|         gpr_zalloc(num_key_cert_pairs * sizeof(tsi_ssl_pem_key_cert_pair))); | ||||
|   } | ||||
|   for (size_t i = 0; i < num_key_cert_pairs; i++) { | ||||
|     GPR_ASSERT(!cert_pair_list[i].private_key().empty()); | ||||
|     GPR_ASSERT(!cert_pair_list[i].cert_chain().empty()); | ||||
|     tsi_pairs[i].cert_chain = | ||||
|         gpr_strdup(cert_pair_list[i].cert_chain().c_str()); | ||||
|     tsi_pairs[i].private_key = | ||||
|         gpr_strdup(cert_pair_list[i].private_key().c_str()); | ||||
|   } | ||||
|   return tsi_pairs; | ||||
| } | ||||
| 
 | ||||
| }  // namespace
 | ||||
| 
 | ||||
| void gpr_check_free(void* p) { | ||||
|   if (p) { | ||||
|     gpr_free(p); | ||||
|     p = nullptr; | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| // -------------------channel security connector-------------------
 | ||||
| RefCountedPtr<grpc_channel_security_connector> | ||||
| TlsChannelSecurityConnector::CreateTlsChannelSecurityConnector( | ||||
|     RefCountedPtr<grpc_channel_credentials> channel_creds, | ||||
|     RefCountedPtr<grpc_tls_credentials_options> options, | ||||
|     RefCountedPtr<grpc_call_credentials> request_metadata_creds, | ||||
|     const char* target_name, const char* overridden_target_name, | ||||
|     tsi_ssl_session_cache* ssl_session_cache) { | ||||
|   if (channel_creds == nullptr) { | ||||
|     gpr_log(GPR_ERROR, | ||||
|             "channel_creds is nullptr in " | ||||
|             "TlsChannelSecurityConnectorCreate()"); | ||||
|     return nullptr; | ||||
|   } | ||||
|   if (options == nullptr) { | ||||
|     gpr_log(GPR_ERROR, | ||||
|             "options is nullptr in " | ||||
|             "TlsChannelSecurityConnectorCreate()"); | ||||
|     return nullptr; | ||||
|   } | ||||
|   if (target_name == nullptr) { | ||||
|     gpr_log(GPR_ERROR, | ||||
|             "target_name is nullptr in " | ||||
|             "TlsChannelSecurityConnectorCreate()"); | ||||
|     return nullptr; | ||||
|   } | ||||
|   return MakeRefCounted<TlsChannelSecurityConnector>( | ||||
|       std::move(channel_creds), std::move(options), | ||||
|       std::move(request_metadata_creds), target_name, overridden_target_name, | ||||
|       ssl_session_cache); | ||||
| } | ||||
| 
 | ||||
| TlsChannelSecurityConnector::TlsChannelSecurityConnector( | ||||
|     RefCountedPtr<grpc_channel_credentials> channel_creds, | ||||
|     RefCountedPtr<grpc_tls_credentials_options> options, | ||||
|     RefCountedPtr<grpc_call_credentials> request_metadata_creds, | ||||
|     const char* target_name, const char* overridden_target_name, | ||||
|     tsi_ssl_session_cache* ssl_session_cache) | ||||
|     : grpc_channel_security_connector(GRPC_SSL_URL_SCHEME, | ||||
|                                       std::move(channel_creds), | ||||
|                                       std::move(request_metadata_creds)), | ||||
|       options_(std::move(options)), | ||||
|       overridden_target_name_( | ||||
|           overridden_target_name == nullptr ? "" : overridden_target_name), | ||||
|       ssl_session_cache_(ssl_session_cache) { | ||||
|   if (ssl_session_cache_ != nullptr) { | ||||
|     tsi_ssl_session_cache_ref(ssl_session_cache_); | ||||
|   } | ||||
|   check_arg_ = ServerAuthorizationCheckArgCreate(this); | ||||
|   absl::string_view host; | ||||
|   absl::string_view port; | ||||
|   SplitHostPort(target_name, &host, &port); | ||||
|   target_name_ = std::string(host); | ||||
|   // Create a watcher.
 | ||||
|   auto watcher_ptr = absl::make_unique<TlsChannelCertificateWatcher>(this); | ||||
|   certificate_watcher_ = watcher_ptr.get(); | ||||
|   // Register the watcher with the distributor.
 | ||||
|   grpc_tls_certificate_distributor* distributor = | ||||
|       options_->certificate_distributor(); | ||||
|   absl::optional<std::string> watched_root_cert_name; | ||||
|   if (options_->watch_root_cert()) { | ||||
|     watched_root_cert_name = options_->root_cert_name(); | ||||
|   } | ||||
|   absl::optional<std::string> watched_identity_cert_name; | ||||
|   if (options_->watch_identity_pair()) { | ||||
|     watched_identity_cert_name = options_->identity_cert_name(); | ||||
|   } | ||||
|   // We will use the root certs stored in system default locations if not
 | ||||
|   // watching root certs on the client side. We will handle this case
 | ||||
|   // differently here, because "watching a default roots without the identity
 | ||||
|   // certs" is a valid case(and hence we will need to call
 | ||||
|   // OnCertificatesChanged), but it requires nothing from the provider, and
 | ||||
|   // hence no need to register the watcher.
 | ||||
|   bool use_default_roots = !options_->watch_root_cert(); | ||||
|   if (use_default_roots && !options_->watch_identity_pair()) { | ||||
|     watcher_ptr->OnCertificatesChanged(absl::nullopt, absl::nullopt); | ||||
|   } else { | ||||
|     distributor->WatchTlsCertificates(std::move(watcher_ptr), | ||||
|                                       watched_root_cert_name, | ||||
|                                       watched_identity_cert_name); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| TlsChannelSecurityConnector::~TlsChannelSecurityConnector() { | ||||
|   if (ssl_session_cache_ != nullptr) { | ||||
|     tsi_ssl_session_cache_unref(ssl_session_cache_); | ||||
|   } | ||||
|   // Cancel all the watchers.
 | ||||
|   grpc_tls_certificate_distributor* distributor = | ||||
|       options_->certificate_distributor(); | ||||
|   if (distributor != nullptr) { | ||||
|     distributor->CancelTlsCertificatesWatch(certificate_watcher_); | ||||
|   } | ||||
|   if (client_handshaker_factory_ != nullptr) { | ||||
|     tsi_ssl_client_handshaker_factory_unref(client_handshaker_factory_); | ||||
|   } | ||||
|   if (check_arg_ != nullptr) { | ||||
|     ServerAuthorizationCheckArgDestroy(check_arg_); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| void TlsChannelSecurityConnector::add_handshakers( | ||||
|     const grpc_channel_args* args, grpc_pollset_set* /*interested_parties*/, | ||||
|     HandshakeManager* handshake_mgr) { | ||||
|   MutexLock lock(&mu_); | ||||
|   if (client_handshaker_factory_ != nullptr) { | ||||
|     // Instantiate TSI handshaker.
 | ||||
|     tsi_handshaker* tsi_hs = nullptr; | ||||
|     tsi_result result = tsi_ssl_client_handshaker_factory_create_handshaker( | ||||
|         client_handshaker_factory_, | ||||
|         overridden_target_name_.empty() ? target_name_.c_str() | ||||
|                                         : overridden_target_name_.c_str(), | ||||
|         &tsi_hs); | ||||
|     if (result != TSI_OK) { | ||||
|       gpr_log(GPR_ERROR, "Handshaker creation failed with error %s.", | ||||
|               tsi_result_to_string(result)); | ||||
|       return; | ||||
|     } | ||||
|     // Create handshakers.
 | ||||
|     handshake_mgr->Add(SecurityHandshakerCreate(tsi_hs, this, args)); | ||||
|     return; | ||||
|   } | ||||
|   // TODO(ZhenLian): Implement the logic(delegation to
 | ||||
|   // BlockOnInitialCredentialHandshaker) when certificates are not ready.
 | ||||
|   gpr_log(GPR_ERROR, "%s not supported yet.", | ||||
|           "Client BlockOnInitialCredentialHandshaker"); | ||||
| } | ||||
| 
 | ||||
| void TlsChannelSecurityConnector::check_peer( | ||||
|     tsi_peer peer, grpc_endpoint* /*ep*/, | ||||
|     RefCountedPtr<grpc_auth_context>* auth_context, | ||||
|     grpc_closure* on_peer_checked) { | ||||
|   const char* target_name = overridden_target_name_.empty() | ||||
|                                 ? target_name_.c_str() | ||||
|                                 : overridden_target_name_.c_str(); | ||||
|   grpc_error_handle error = grpc_ssl_check_alpn(&peer); | ||||
|   if (error != GRPC_ERROR_NONE) { | ||||
|     ExecCtx::Run(DEBUG_LOCATION, on_peer_checked, error); | ||||
|     tsi_peer_destruct(&peer); | ||||
|     return; | ||||
|   } | ||||
|   *auth_context = | ||||
|       grpc_ssl_peer_to_auth_context(&peer, GRPC_TLS_TRANSPORT_SECURITY_TYPE); | ||||
|   if (options_->server_verification_option() == GRPC_TLS_SERVER_VERIFICATION) { | ||||
|     /* Do the default host name check if specifying the target name. */ | ||||
|     error = internal::TlsCheckHostName(target_name, &peer); | ||||
|     if (error != GRPC_ERROR_NONE) { | ||||
|       ExecCtx::Run(DEBUG_LOCATION, on_peer_checked, error); | ||||
|       tsi_peer_destruct(&peer); | ||||
|       return; | ||||
|     } | ||||
|   } | ||||
|   /* Do the custom server authorization check, if specified by the user. */ | ||||
|   const grpc_tls_server_authorization_check_config* config = | ||||
|       options_->server_authorization_check_config(); | ||||
|   /* If server authorization config is not null, use it to perform
 | ||||
|    * server authorization check. */ | ||||
|   if (config != nullptr) { | ||||
|     const tsi_peer_property* p = | ||||
|         tsi_peer_get_property_by_name(&peer, TSI_X509_PEM_CERT_PROPERTY); | ||||
|     if (p == nullptr) { | ||||
|       error = GRPC_ERROR_CREATE_FROM_STATIC_STRING( | ||||
|           "Cannot check peer: missing pem cert property."); | ||||
|     } else { | ||||
|       char* peer_pem = static_cast<char*>(gpr_zalloc(p->value.length + 1)); | ||||
|       memcpy(peer_pem, p->value.data, p->value.length); | ||||
|       GPR_ASSERT(check_arg_ != nullptr); | ||||
|       check_arg_->peer_cert = check_arg_->peer_cert == nullptr | ||||
|                                   ? gpr_strdup(peer_pem) | ||||
|                                   : check_arg_->peer_cert; | ||||
|       check_arg_->target_name = check_arg_->target_name == nullptr | ||||
|                                     ? gpr_strdup(target_name) | ||||
|                                     : check_arg_->target_name; | ||||
|       on_peer_checked_ = on_peer_checked; | ||||
|       gpr_check_free(peer_pem); | ||||
|       const tsi_peer_property* chain = tsi_peer_get_property_by_name( | ||||
|           &peer, TSI_X509_PEM_CERT_CHAIN_PROPERTY); | ||||
|       if (chain != nullptr) { | ||||
|         char* peer_pem_chain = | ||||
|             static_cast<char*>(gpr_zalloc(chain->value.length + 1)); | ||||
|         memcpy(peer_pem_chain, chain->value.data, chain->value.length); | ||||
|         check_arg_->peer_cert_full_chain = | ||||
|             check_arg_->peer_cert_full_chain == nullptr | ||||
|                 ? gpr_strdup(peer_pem_chain) | ||||
|                 : check_arg_->peer_cert_full_chain; | ||||
|         gpr_check_free(peer_pem_chain); | ||||
|       } | ||||
|       // TODO(zhenlian) - This should be cleaned up as part of the custom
 | ||||
|       // verification changes. Fill in the subject alternative names
 | ||||
|       std::vector<char*> subject_alternative_names; | ||||
|       for (size_t i = 0; i < peer.property_count; i++) { | ||||
|         const tsi_peer_property* prop = &peer.properties[i]; | ||||
|         if (strcmp(prop->name, | ||||
|                    TSI_X509_SUBJECT_ALTERNATIVE_NAME_PEER_PROPERTY) == 0) { | ||||
|           char* san = new char[prop->value.length + 1]; | ||||
|           memcpy(san, prop->value.data, prop->value.length); | ||||
|           san[prop->value.length] = '\0'; | ||||
|           subject_alternative_names.emplace_back(san); | ||||
|         } | ||||
|       } | ||||
|       if (check_arg_->subject_alternative_names != nullptr) { | ||||
|         for (size_t i = 0; i < check_arg_->subject_alternative_names_size; | ||||
|              ++i) { | ||||
|           delete[] check_arg_->subject_alternative_names[i]; | ||||
|         } | ||||
|         delete[] check_arg_->subject_alternative_names; | ||||
|       } | ||||
|       check_arg_->subject_alternative_names_size = | ||||
|           subject_alternative_names.size(); | ||||
|       if (subject_alternative_names.empty()) { | ||||
|         check_arg_->subject_alternative_names = nullptr; | ||||
|       } else { | ||||
|         check_arg_->subject_alternative_names = | ||||
|             new char*[check_arg_->subject_alternative_names_size]; | ||||
|         for (size_t i = 0; i < check_arg_->subject_alternative_names_size; | ||||
|              ++i) { | ||||
|           check_arg_->subject_alternative_names[i] = | ||||
|               subject_alternative_names[i]; | ||||
|         } | ||||
|       } | ||||
|       int callback_status = config->Schedule(check_arg_); | ||||
|       /* Server authorization check is handled asynchronously. */ | ||||
|       if (callback_status) { | ||||
|         tsi_peer_destruct(&peer); | ||||
|         return; | ||||
|       } | ||||
|       /* Server authorization check is handled synchronously. */ | ||||
|       error = ProcessServerAuthorizationCheckResult(check_arg_); | ||||
|     } | ||||
|   } | ||||
|   ExecCtx::Run(DEBUG_LOCATION, on_peer_checked, error); | ||||
|   tsi_peer_destruct(&peer); | ||||
| } | ||||
| 
 | ||||
| int TlsChannelSecurityConnector::cmp( | ||||
|     const grpc_security_connector* other_sc) const { | ||||
|   auto* other = reinterpret_cast<const TlsChannelSecurityConnector*>(other_sc); | ||||
|   int c = channel_security_connector_cmp(other); | ||||
|   if (c != 0) { | ||||
|     return c; | ||||
|   } | ||||
|   return grpc_ssl_cmp_target_name( | ||||
|       target_name_.c_str(), other->target_name_.c_str(), | ||||
|       overridden_target_name_.c_str(), other->overridden_target_name_.c_str()); | ||||
| } | ||||
| 
 | ||||
| bool TlsChannelSecurityConnector::check_call_host( | ||||
|     absl::string_view host, grpc_auth_context* auth_context, | ||||
|     grpc_closure* /*on_call_host_checked*/, grpc_error_handle* error) { | ||||
|   if (options_->server_verification_option() == | ||||
|           GRPC_TLS_SKIP_HOSTNAME_VERIFICATION || | ||||
|       options_->server_verification_option() == | ||||
|           GRPC_TLS_SKIP_ALL_SERVER_VERIFICATION) { | ||||
|     return true; | ||||
|   } | ||||
|   return grpc_ssl_check_call_host(host, target_name_.c_str(), | ||||
|                                   overridden_target_name_.c_str(), auth_context, | ||||
|                                   error); | ||||
| } | ||||
| 
 | ||||
| void TlsChannelSecurityConnector::cancel_check_call_host( | ||||
|     grpc_closure* /*on_call_host_checked*/, grpc_error_handle error) { | ||||
|   GRPC_ERROR_UNREF(error); | ||||
| } | ||||
| 
 | ||||
| void TlsChannelSecurityConnector::TlsChannelCertificateWatcher:: | ||||
|     OnCertificatesChanged(absl::optional<absl::string_view> root_certs, | ||||
|                           absl::optional<PemKeyCertPairList> key_cert_pairs) { | ||||
|   GPR_ASSERT(security_connector_ != nullptr); | ||||
|   MutexLock lock(&security_connector_->mu_); | ||||
|   if (root_certs.has_value()) { | ||||
|     security_connector_->pem_root_certs_ = root_certs; | ||||
|   } | ||||
|   if (key_cert_pairs.has_value()) { | ||||
|     security_connector_->pem_key_cert_pair_list_ = std::move(key_cert_pairs); | ||||
|   } | ||||
|   const bool root_ready = !security_connector_->options_->watch_root_cert() || | ||||
|                           security_connector_->pem_root_certs_.has_value(); | ||||
|   const bool identity_ready = | ||||
|       !security_connector_->options_->watch_identity_pair() || | ||||
|       security_connector_->pem_key_cert_pair_list_.has_value(); | ||||
|   if (root_ready && identity_ready) { | ||||
|     if (security_connector_->UpdateHandshakerFactoryLocked() != | ||||
|         GRPC_SECURITY_OK) { | ||||
|       gpr_log(GPR_ERROR, "Update handshaker factory failed."); | ||||
|     } | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| // TODO(ZhenLian): implement the logic to signal waiting handshakers once
 | ||||
| // BlockOnInitialCredentialHandshaker is implemented.
 | ||||
| void TlsChannelSecurityConnector::TlsChannelCertificateWatcher::OnError( | ||||
|     grpc_error_handle root_cert_error, grpc_error_handle identity_cert_error) { | ||||
|   if (root_cert_error != GRPC_ERROR_NONE) { | ||||
|     gpr_log(GPR_ERROR, | ||||
|             "TlsChannelCertificateWatcher getting root_cert_error: %s", | ||||
|             grpc_error_std_string(root_cert_error).c_str()); | ||||
|   } | ||||
|   if (identity_cert_error != GRPC_ERROR_NONE) { | ||||
|     gpr_log(GPR_ERROR, | ||||
|             "TlsChannelCertificateWatcher getting identity_cert_error: %s", | ||||
|             grpc_error_std_string(identity_cert_error).c_str()); | ||||
|   } | ||||
|   GRPC_ERROR_UNREF(root_cert_error); | ||||
|   GRPC_ERROR_UNREF(identity_cert_error); | ||||
| } | ||||
| 
 | ||||
| // TODO(ZhenLian): implement the logic to signal waiting handshakers once
 | ||||
| // BlockOnInitialCredentialHandshaker is implemented.
 | ||||
| grpc_security_status | ||||
| TlsChannelSecurityConnector::UpdateHandshakerFactoryLocked() { | ||||
|   bool skip_server_certificate_verification = | ||||
|       options_->server_verification_option() == | ||||
|       GRPC_TLS_SKIP_ALL_SERVER_VERIFICATION; | ||||
|   /* Free the client handshaker factory if exists. */ | ||||
|   if (client_handshaker_factory_ != nullptr) { | ||||
|     tsi_ssl_client_handshaker_factory_unref(client_handshaker_factory_); | ||||
|   } | ||||
|   std::string pem_root_certs; | ||||
|   if (pem_root_certs_.has_value()) { | ||||
|     // TODO(ZhenLian): update the underlying TSI layer to use C++ types like
 | ||||
|     // std::string and absl::string_view to avoid making another copy here.
 | ||||
|     pem_root_certs = std::string(*pem_root_certs_); | ||||
|   } | ||||
|   tsi_ssl_pem_key_cert_pair* pem_key_cert_pair = nullptr; | ||||
|   if (pem_key_cert_pair_list_.has_value()) { | ||||
|     pem_key_cert_pair = ConvertToTsiPemKeyCertPair(*pem_key_cert_pair_list_); | ||||
|   } | ||||
|   bool use_default_roots = !options_->watch_root_cert(); | ||||
|   grpc_security_status status = grpc_ssl_tsi_client_handshaker_factory_init( | ||||
|       pem_key_cert_pair, | ||||
|       pem_root_certs.empty() || use_default_roots ? nullptr | ||||
|                                                   : pem_root_certs.c_str(), | ||||
|       skip_server_certificate_verification, | ||||
|       grpc_get_tsi_tls_version(options_->min_tls_version()), | ||||
|       grpc_get_tsi_tls_version(options_->max_tls_version()), ssl_session_cache_, | ||||
|       &client_handshaker_factory_); | ||||
|   /* Free memory. */ | ||||
|   if (pem_key_cert_pair != nullptr) { | ||||
|     grpc_tsi_ssl_pem_key_cert_pairs_destroy(pem_key_cert_pair, 1); | ||||
|   } | ||||
|   return status; | ||||
| } | ||||
| 
 | ||||
| void TlsChannelSecurityConnector::ServerAuthorizationCheckDone( | ||||
|     grpc_tls_server_authorization_check_arg* arg) { | ||||
|   GPR_ASSERT(arg != nullptr); | ||||
|   ExecCtx exec_ctx; | ||||
|   grpc_error_handle error = ProcessServerAuthorizationCheckResult(arg); | ||||
|   TlsChannelSecurityConnector* connector = | ||||
|       static_cast<TlsChannelSecurityConnector*>(arg->cb_user_data); | ||||
|   ExecCtx::Run(DEBUG_LOCATION, connector->on_peer_checked_, error); | ||||
| } | ||||
| 
 | ||||
| grpc_error_handle | ||||
| TlsChannelSecurityConnector::ProcessServerAuthorizationCheckResult( | ||||
|     grpc_tls_server_authorization_check_arg* arg) { | ||||
|   grpc_error_handle error = GRPC_ERROR_NONE; | ||||
|   /* Server authorization check is cancelled by caller. */ | ||||
|   if (arg->status == GRPC_STATUS_CANCELLED) { | ||||
|     error = GRPC_ERROR_CREATE_FROM_COPIED_STRING( | ||||
|         absl::StrCat("Server authorization check is cancelled by the caller " | ||||
|                      "with error: ", | ||||
|                      arg->error_details->error_details()) | ||||
|             .c_str()); | ||||
|   } else if (arg->status == GRPC_STATUS_OK) { | ||||
|     /* Server authorization check completed successfully but returned check
 | ||||
|      * failure. */ | ||||
|     if (!arg->success) { | ||||
|       error = GRPC_ERROR_CREATE_FROM_COPIED_STRING( | ||||
|           absl::StrCat("Server authorization check failed with error: ", | ||||
|                        arg->error_details->error_details()) | ||||
|               .c_str()); | ||||
|     } | ||||
|     /* Server authorization check did not complete correctly. */ | ||||
|   } else { | ||||
|     error = GRPC_ERROR_CREATE_FROM_COPIED_STRING( | ||||
|         absl::StrCat( | ||||
|             "Server authorization check did not finish correctly with error: ", | ||||
|             arg->error_details->error_details()) | ||||
|             .c_str()); | ||||
|   } | ||||
|   return error; | ||||
| } | ||||
| 
 | ||||
| grpc_tls_server_authorization_check_arg* | ||||
| TlsChannelSecurityConnector::ServerAuthorizationCheckArgCreate( | ||||
|     void* user_data) { | ||||
|   grpc_tls_server_authorization_check_arg* arg = | ||||
|       new grpc_tls_server_authorization_check_arg(); | ||||
|   arg->target_name = nullptr; | ||||
|   arg->peer_cert = nullptr; | ||||
|   arg->peer_cert_full_chain = nullptr; | ||||
|   arg->subject_alternative_names = nullptr; | ||||
|   arg->subject_alternative_names_size = 0; | ||||
|   arg->error_details = new grpc_tls_error_details(); | ||||
|   arg->cb = ServerAuthorizationCheckDone; | ||||
|   arg->cb_user_data = user_data; | ||||
|   arg->status = GRPC_STATUS_OK; | ||||
|   return arg; | ||||
| } | ||||
| 
 | ||||
| void TlsChannelSecurityConnector::ServerAuthorizationCheckArgDestroy( | ||||
|     grpc_tls_server_authorization_check_arg* arg) { | ||||
|   if (arg == nullptr) { | ||||
|     return; | ||||
|   } | ||||
|   gpr_check_free(const_cast<char*>(arg->target_name)); | ||||
|   gpr_check_free(const_cast<char*>(arg->peer_cert)); | ||||
|   gpr_check_free(const_cast<char*>(arg->peer_cert_full_chain)); | ||||
|   for (size_t i = 0; i < arg->subject_alternative_names_size; ++i) { | ||||
|     delete[] arg->subject_alternative_names[i]; | ||||
|   } | ||||
|   delete[] arg->subject_alternative_names; | ||||
|   delete arg->error_details; | ||||
|   if (arg->destroy_context != nullptr) { | ||||
|     arg->destroy_context(arg->context); | ||||
|   } | ||||
|   delete arg; | ||||
|   arg = nullptr; | ||||
| } | ||||
| 
 | ||||
| // -------------------server security connector-------------------
 | ||||
| RefCountedPtr<grpc_server_security_connector> | ||||
| TlsServerSecurityConnector::CreateTlsServerSecurityConnector( | ||||
|     RefCountedPtr<grpc_server_credentials> server_creds, | ||||
|     RefCountedPtr<grpc_tls_credentials_options> options) { | ||||
|   if (server_creds == nullptr) { | ||||
|     gpr_log(GPR_ERROR, | ||||
|             "server_creds is nullptr in " | ||||
|             "TlsServerSecurityConnectorCreate()"); | ||||
|     return nullptr; | ||||
|   } | ||||
|   if (options == nullptr) { | ||||
|     gpr_log(GPR_ERROR, | ||||
|             "options is nullptr in " | ||||
|             "TlsServerSecurityConnectorCreate()"); | ||||
|     return nullptr; | ||||
|   } | ||||
|   return MakeRefCounted<TlsServerSecurityConnector>(std::move(server_creds), | ||||
|                                                     std::move(options)); | ||||
| } | ||||
| 
 | ||||
| void TlsServerSecurityConnector::ClientAuthorizationCheckDone( | ||||
|     grpc_tls_server_authorization_check_arg* arg) { | ||||
|   GPR_ASSERT(arg != nullptr); | ||||
|   ExecCtx exec_ctx; | ||||
|   grpc_error_handle error = ProcessClientAuthorizationCheckResult(arg); | ||||
|   TlsServerSecurityConnector* connector = | ||||
|       static_cast<TlsServerSecurityConnector*>(arg->cb_user_data); | ||||
|   ExecCtx::Run(DEBUG_LOCATION, connector->on_peer_checked_, error); | ||||
| } | ||||
| 
 | ||||
| grpc_error_handle | ||||
| TlsServerSecurityConnector::ProcessClientAuthorizationCheckResult( | ||||
|     grpc_tls_server_authorization_check_arg* arg) { | ||||
|   grpc_error_handle error = GRPC_ERROR_NONE; | ||||
|   /* Client authorization check is cancelled by caller. */ | ||||
|   if (arg->status == GRPC_STATUS_CANCELLED) { | ||||
|     error = GRPC_ERROR_CREATE_FROM_COPIED_STRING( | ||||
|         absl::StrCat("Client authorization check is cancelled by the caller " | ||||
|                      "with error: ", | ||||
|                      arg->error_details->error_details()) | ||||
|             .c_str()); | ||||
|   } else if (arg->status == GRPC_STATUS_OK) { | ||||
|     /* Client authorization check completed successfully but returned check
 | ||||
|      * failure. */ | ||||
|     if (!arg->success) { | ||||
|       error = GRPC_ERROR_CREATE_FROM_COPIED_STRING( | ||||
|           absl::StrCat("Client authorization check failed with error: ", | ||||
|                        arg->error_details->error_details()) | ||||
|               .c_str()); | ||||
|     } | ||||
|     /* Client authorization check did not complete correctly. */ | ||||
|   } else { | ||||
|     error = GRPC_ERROR_CREATE_FROM_COPIED_STRING( | ||||
|         absl::StrCat( | ||||
|             "Client authorization check did not finish correctly with error: ", | ||||
|             arg->error_details->error_details()) | ||||
|             .c_str()); | ||||
|   } | ||||
|   return error; | ||||
| } | ||||
| 
 | ||||
| grpc_tls_server_authorization_check_arg* | ||||
| TlsServerSecurityConnector::ClientAuthorizationCheckArgCreate( | ||||
|     void* user_data) { | ||||
|   grpc_tls_server_authorization_check_arg* arg = | ||||
|       new grpc_tls_server_authorization_check_arg(); | ||||
|   arg->target_name = nullptr; | ||||
|   arg->peer_cert = nullptr; | ||||
|   arg->peer_cert_full_chain = nullptr; | ||||
|   arg->subject_alternative_names = nullptr; | ||||
|   arg->subject_alternative_names_size = 0; | ||||
|   arg->error_details = new grpc_tls_error_details(); | ||||
|   arg->cb = ClientAuthorizationCheckDone; | ||||
|   arg->cb_user_data = user_data; | ||||
|   arg->status = GRPC_STATUS_OK; | ||||
|   return arg; | ||||
| } | ||||
| 
 | ||||
| void TlsServerSecurityConnector::ClientAuthorizationCheckArgDestroy( | ||||
|     grpc_tls_server_authorization_check_arg* arg) { | ||||
|   if (arg == nullptr) { | ||||
|     return; | ||||
|   } | ||||
|   gpr_check_free(const_cast<char*>(arg->target_name)); | ||||
|   gpr_check_free(const_cast<char*>(arg->peer_cert)); | ||||
|   gpr_check_free(const_cast<char*>(arg->peer_cert_full_chain)); | ||||
|   for (size_t i = 0; i < arg->subject_alternative_names_size; ++i) { | ||||
|     delete[] arg->subject_alternative_names[i]; | ||||
|   } | ||||
|   delete[] arg->subject_alternative_names; | ||||
|   delete arg->error_details; | ||||
|   if (arg->destroy_context != nullptr) { | ||||
|     arg->destroy_context(arg->context); | ||||
|   } | ||||
|   delete arg; | ||||
|   arg = nullptr; | ||||
| } | ||||
| 
 | ||||
| TlsServerSecurityConnector::TlsServerSecurityConnector( | ||||
|     RefCountedPtr<grpc_server_credentials> server_creds, | ||||
|     RefCountedPtr<grpc_tls_credentials_options> options) | ||||
|     : grpc_server_security_connector(GRPC_SSL_URL_SCHEME, | ||||
|                                      std::move(server_creds)), | ||||
|       options_(std::move(options)) { | ||||
|   check_arg_ = ClientAuthorizationCheckArgCreate(this); | ||||
|   // Create a watcher.
 | ||||
|   auto watcher_ptr = absl::make_unique<TlsServerCertificateWatcher>(this); | ||||
|   certificate_watcher_ = watcher_ptr.get(); | ||||
|   // Register the watcher with the distributor.
 | ||||
|   grpc_tls_certificate_distributor* distributor = | ||||
|       options_->certificate_distributor(); | ||||
|   absl::optional<std::string> watched_root_cert_name; | ||||
|   if (options_->watch_root_cert()) { | ||||
|     watched_root_cert_name = options_->root_cert_name(); | ||||
|   } | ||||
|   absl::optional<std::string> watched_identity_cert_name; | ||||
|   if (options_->watch_identity_pair()) { | ||||
|     watched_identity_cert_name = options_->identity_cert_name(); | ||||
|   } | ||||
|   // Server side won't use default system roots at any time.
 | ||||
|   distributor->WatchTlsCertificates(std::move(watcher_ptr), | ||||
|                                     watched_root_cert_name, | ||||
|                                     watched_identity_cert_name); | ||||
| } | ||||
| 
 | ||||
| TlsServerSecurityConnector::~TlsServerSecurityConnector() { | ||||
|   // Cancel all the watchers.
 | ||||
|   grpc_tls_certificate_distributor* distributor = | ||||
|       options_->certificate_distributor(); | ||||
|   if (distributor != nullptr) { | ||||
|     distributor->CancelTlsCertificatesWatch(certificate_watcher_); | ||||
|   } | ||||
|   if (server_handshaker_factory_ != nullptr) { | ||||
|     tsi_ssl_server_handshaker_factory_unref(server_handshaker_factory_); | ||||
|   } | ||||
|   if (check_arg_ != nullptr) { | ||||
|     ClientAuthorizationCheckArgDestroy(check_arg_); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| void TlsServerSecurityConnector::add_handshakers( | ||||
|     const grpc_channel_args* args, grpc_pollset_set* /*interested_parties*/, | ||||
|     HandshakeManager* handshake_mgr) { | ||||
|   MutexLock lock(&mu_); | ||||
|   if (server_handshaker_factory_ != nullptr) { | ||||
|     // Instantiate TSI handshaker.
 | ||||
|     tsi_handshaker* tsi_hs = nullptr; | ||||
|     tsi_result result = tsi_ssl_server_handshaker_factory_create_handshaker( | ||||
|         server_handshaker_factory_, &tsi_hs); | ||||
|     if (result != TSI_OK) { | ||||
|       gpr_log(GPR_ERROR, "Handshaker creation failed with error %s.", | ||||
|               tsi_result_to_string(result)); | ||||
|       return; | ||||
|     } | ||||
|     // Create handshakers.
 | ||||
|     handshake_mgr->Add(SecurityHandshakerCreate(tsi_hs, this, args)); | ||||
|     return; | ||||
|   } | ||||
|   // TODO(ZhenLian): Implement the logic(delegation to
 | ||||
|   // BlockOnInitialCredentialHandshaker) when certificates are not ready.
 | ||||
|   gpr_log(GPR_ERROR, "%s not supported yet.", | ||||
|           "Server BlockOnInitialCredentialHandshaker"); | ||||
| } | ||||
| 
 | ||||
| void TlsServerSecurityConnector::check_peer( | ||||
|     tsi_peer peer, grpc_endpoint* /*ep*/, | ||||
|     RefCountedPtr<grpc_auth_context>* auth_context, | ||||
|     grpc_closure* on_peer_checked) { | ||||
|   grpc_error_handle error = grpc_ssl_check_alpn(&peer); | ||||
|   if (error != GRPC_ERROR_NONE) { | ||||
|     ExecCtx::Run(DEBUG_LOCATION, on_peer_checked, error); | ||||
|     tsi_peer_destruct(&peer); | ||||
|     return; | ||||
|   } | ||||
|   *auth_context = | ||||
|       grpc_ssl_peer_to_auth_context(&peer, GRPC_TLS_TRANSPORT_SECURITY_TYPE); | ||||
|   if (options_->server_verification_option() == GRPC_TLS_SERVER_VERIFICATION) { | ||||
|     /* Do the default host name check if specifying the target name. */ | ||||
|     error = internal::TlsCheckHostName("", &peer); | ||||
|     if (error != GRPC_ERROR_NONE) { | ||||
|       ExecCtx::Run(DEBUG_LOCATION, on_peer_checked, error); | ||||
|       tsi_peer_destruct(&peer); | ||||
|       return; | ||||
|     } | ||||
|   } | ||||
|   /* Do the custom client authorization check, if specified by the user. */ | ||||
|   const grpc_tls_server_authorization_check_config* config = | ||||
|       options_->server_authorization_check_config(); | ||||
|   /* If client authorization config is not null, use it to perform
 | ||||
|    * client authorization check. */ | ||||
|   if (config != nullptr) { | ||||
|     const tsi_peer_property* p = | ||||
|         tsi_peer_get_property_by_name(&peer, TSI_X509_PEM_CERT_PROPERTY); | ||||
|     if (p == nullptr) { | ||||
|       error = GRPC_ERROR_CREATE_FROM_STATIC_STRING( | ||||
|           "Cannot check peer: missing pem cert property."); | ||||
|     } else { | ||||
|       char* peer_pem = static_cast<char*>(gpr_zalloc(p->value.length + 1)); | ||||
|       memcpy(peer_pem, p->value.data, p->value.length); | ||||
|       GPR_ASSERT(check_arg_ != nullptr); | ||||
|       check_arg_->peer_cert = gpr_strdup(peer_pem); | ||||
|       check_arg_->target_name = gpr_strdup(""); | ||||
|       on_peer_checked_ = on_peer_checked; | ||||
|       gpr_check_free(peer_pem); | ||||
|       const tsi_peer_property* chain = tsi_peer_get_property_by_name( | ||||
|           &peer, TSI_X509_PEM_CERT_CHAIN_PROPERTY); | ||||
|       if (chain != nullptr) { | ||||
|         char* peer_pem_chain = | ||||
|             static_cast<char*>(gpr_zalloc(chain->value.length + 1)); | ||||
|         memcpy(peer_pem_chain, chain->value.data, chain->value.length); | ||||
|         check_arg_->peer_cert_full_chain = | ||||
|             check_arg_->peer_cert_full_chain == nullptr | ||||
|                 ? gpr_strdup(peer_pem_chain) | ||||
|                 : check_arg_->peer_cert_full_chain; | ||||
|         gpr_check_free(peer_pem_chain); | ||||
|       } | ||||
|       // TODO(zhenlian) - This should be cleaned up as part of the custom
 | ||||
|       // verification changes. Fill in the subject alternative names
 | ||||
|       std::vector<char*> subject_alternative_names; | ||||
|       for (size_t i = 0; i < peer.property_count; i++) { | ||||
|         const tsi_peer_property* prop = &peer.properties[i]; | ||||
|         if (strcmp(prop->name, | ||||
|                    TSI_X509_SUBJECT_ALTERNATIVE_NAME_PEER_PROPERTY) == 0) { | ||||
|           char* san = new char[prop->value.length + 1]; | ||||
|           memcpy(san, prop->value.data, prop->value.length); | ||||
|           san[prop->value.length] = '\0'; | ||||
|           subject_alternative_names.emplace_back(san); | ||||
|         } | ||||
|       } | ||||
|       if (check_arg_->subject_alternative_names != nullptr) { | ||||
|         for (size_t i = 0; i < check_arg_->subject_alternative_names_size; | ||||
|              ++i) { | ||||
|           delete[] check_arg_->subject_alternative_names[i]; | ||||
|         } | ||||
|         delete[] check_arg_->subject_alternative_names; | ||||
|       } | ||||
|       check_arg_->subject_alternative_names_size = | ||||
|           subject_alternative_names.size(); | ||||
|       if (subject_alternative_names.empty()) { | ||||
|         check_arg_->subject_alternative_names = nullptr; | ||||
|       } else { | ||||
|         check_arg_->subject_alternative_names = | ||||
|             new char*[check_arg_->subject_alternative_names_size]; | ||||
|         for (size_t i = 0; i < check_arg_->subject_alternative_names_size; | ||||
|              ++i) { | ||||
|           check_arg_->subject_alternative_names[i] = | ||||
|               subject_alternative_names[i]; | ||||
|         } | ||||
|       } | ||||
|       int callback_status = config->Schedule(check_arg_); | ||||
|       /* Client authorization check is handled asynchronously. */ | ||||
|       if (callback_status) { | ||||
|         tsi_peer_destruct(&peer); | ||||
|         return; | ||||
|       } | ||||
|       /* Client authorization check is handled synchronously. */ | ||||
|       error = ProcessClientAuthorizationCheckResult(check_arg_); | ||||
|     } | ||||
|   } | ||||
|   ExecCtx::Run(DEBUG_LOCATION, on_peer_checked, error); | ||||
|   tsi_peer_destruct(&peer); | ||||
| } | ||||
| 
 | ||||
| int TlsServerSecurityConnector::cmp( | ||||
|     const grpc_security_connector* other) const { | ||||
|   return server_security_connector_cmp( | ||||
|       static_cast<const grpc_server_security_connector*>(other)); | ||||
| } | ||||
| 
 | ||||
| void TlsServerSecurityConnector::TlsServerCertificateWatcher:: | ||||
|     OnCertificatesChanged(absl::optional<absl::string_view> root_certs, | ||||
|                           absl::optional<PemKeyCertPairList> key_cert_pairs) { | ||||
|   GPR_ASSERT(security_connector_ != nullptr); | ||||
|   MutexLock lock(&security_connector_->mu_); | ||||
|   if (root_certs.has_value()) { | ||||
|     security_connector_->pem_root_certs_ = root_certs; | ||||
|   } | ||||
|   if (key_cert_pairs.has_value()) { | ||||
|     security_connector_->pem_key_cert_pair_list_ = std::move(key_cert_pairs); | ||||
|   } | ||||
|   bool root_being_watched = security_connector_->options_->watch_root_cert(); | ||||
|   bool root_has_value = security_connector_->pem_root_certs_.has_value(); | ||||
|   bool identity_being_watched = | ||||
|       security_connector_->options_->watch_identity_pair(); | ||||
|   bool identity_has_value = | ||||
|       security_connector_->pem_key_cert_pair_list_.has_value(); | ||||
|   if ((root_being_watched && root_has_value && identity_being_watched && | ||||
|        identity_has_value) || | ||||
|       (root_being_watched && root_has_value && !identity_being_watched) || | ||||
|       (!root_being_watched && identity_being_watched && identity_has_value)) { | ||||
|     if (security_connector_->UpdateHandshakerFactoryLocked() != | ||||
|         GRPC_SECURITY_OK) { | ||||
|       gpr_log(GPR_ERROR, "Update handshaker factory failed."); | ||||
|     } | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| // TODO(ZhenLian): implement the logic to signal waiting handshakers once
 | ||||
| // BlockOnInitialCredentialHandshaker is implemented.
 | ||||
| void TlsServerSecurityConnector::TlsServerCertificateWatcher::OnError( | ||||
|     grpc_error_handle root_cert_error, grpc_error_handle identity_cert_error) { | ||||
|   if (root_cert_error != GRPC_ERROR_NONE) { | ||||
|     gpr_log(GPR_ERROR, | ||||
|             "TlsServerCertificateWatcher getting root_cert_error: %s", | ||||
|             grpc_error_std_string(root_cert_error).c_str()); | ||||
|   } | ||||
|   if (identity_cert_error != GRPC_ERROR_NONE) { | ||||
|     gpr_log(GPR_ERROR, | ||||
|             "TlsServerCertificateWatcher getting identity_cert_error: %s", | ||||
|             grpc_error_std_string(identity_cert_error).c_str()); | ||||
|   } | ||||
|   GRPC_ERROR_UNREF(root_cert_error); | ||||
|   GRPC_ERROR_UNREF(identity_cert_error); | ||||
| } | ||||
| 
 | ||||
| // TODO(ZhenLian): implement the logic to signal waiting handshakers once
 | ||||
| // BlockOnInitialCredentialHandshaker is implemented.
 | ||||
| grpc_security_status | ||||
| TlsServerSecurityConnector::UpdateHandshakerFactoryLocked() { | ||||
|   /* Free the server handshaker factory if exists. */ | ||||
|   if (server_handshaker_factory_ != nullptr) { | ||||
|     tsi_ssl_server_handshaker_factory_unref(server_handshaker_factory_); | ||||
|   } | ||||
|   // The identity certs on the server side shouldn't be empty.
 | ||||
|   GPR_ASSERT(pem_key_cert_pair_list_.has_value()); | ||||
|   GPR_ASSERT(!(*pem_key_cert_pair_list_).empty()); | ||||
|   std::string pem_root_certs; | ||||
|   if (pem_root_certs_.has_value()) { | ||||
|     // TODO(ZhenLian): update the underlying TSI layer to use C++ types like
 | ||||
|     // std::string and absl::string_view to avoid making another copy here.
 | ||||
|     pem_root_certs = std::string(*pem_root_certs_); | ||||
|   } | ||||
|   tsi_ssl_pem_key_cert_pair* pem_key_cert_pairs = nullptr; | ||||
|   pem_key_cert_pairs = ConvertToTsiPemKeyCertPair(*pem_key_cert_pair_list_); | ||||
|   size_t num_key_cert_pairs = (*pem_key_cert_pair_list_).size(); | ||||
|   grpc_security_status status = grpc_ssl_tsi_server_handshaker_factory_init( | ||||
|       pem_key_cert_pairs, num_key_cert_pairs, | ||||
|       pem_root_certs.empty() ? nullptr : pem_root_certs.c_str(), | ||||
|       options_->cert_request_type(), | ||||
|       grpc_get_tsi_tls_version(options_->min_tls_version()), | ||||
|       grpc_get_tsi_tls_version(options_->max_tls_version()), | ||||
|       &server_handshaker_factory_); | ||||
|   /* Free memory. */ | ||||
|   grpc_tsi_ssl_pem_key_cert_pairs_destroy(pem_key_cert_pairs, | ||||
|                                           num_key_cert_pairs); | ||||
|   return status; | ||||
| } | ||||
| 
 | ||||
| namespace internal { | ||||
| 
 | ||||
| grpc_error_handle TlsCheckHostName(const char* peer_name, | ||||
|                                    const tsi_peer* peer) { | ||||
|   /* Check the peer name if specified. */ | ||||
|   if (peer_name != nullptr && !grpc_ssl_host_matches_name(peer, peer_name)) { | ||||
|     return GRPC_ERROR_CREATE_FROM_COPIED_STRING( | ||||
|         absl::StrCat("Peer name ", peer_name, " is not in peer certificate") | ||||
|             .c_str()); | ||||
|   } | ||||
|   return GRPC_ERROR_NONE; | ||||
| } | ||||
| 
 | ||||
| }  // namespace internal
 | ||||
| 
 | ||||
| }  // namespace grpc_core
 | ||||
| @ -1,267 +0,0 @@ | ||||
| /*
 | ||||
|  * | ||||
|  * Copyright 2018 gRPC authors. | ||||
|  * | ||||
|  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|  * you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * | ||||
|  *     http://www.apache.org/licenses/LICENSE-2.0
 | ||||
|  * | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an "AS IS" BASIS, | ||||
|  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|  * See the License for the specific language governing permissions and | ||||
|  * limitations under the License. | ||||
|  * | ||||
|  */ | ||||
| 
 | ||||
| #ifndef GRPC_CORE_LIB_SECURITY_SECURITY_CONNECTOR_TLS_TLS_SECURITY_CONNECTOR_H | ||||
| #define GRPC_CORE_LIB_SECURITY_SECURITY_CONNECTOR_TLS_TLS_SECURITY_CONNECTOR_H | ||||
| 
 | ||||
| #include <grpc/support/port_platform.h> | ||||
| 
 | ||||
| #include "src/core/lib/gprpp/sync.h" | ||||
| #include "src/core/lib/security/context/security_context.h" | ||||
| #include "src/core/lib/security/credentials/tls/grpc_tls_certificate_provider.h" | ||||
| #include "src/core/lib/security/credentials/tls/grpc_tls_credentials_options.h" | ||||
| 
 | ||||
| #define GRPC_TLS_TRANSPORT_SECURITY_TYPE "tls" | ||||
| 
 | ||||
| namespace grpc_core { | ||||
| 
 | ||||
| // Channel security connector using TLS as transport security protocol.
 | ||||
| class TlsChannelSecurityConnector final | ||||
|     : public grpc_channel_security_connector { | ||||
|  public: | ||||
|   // static factory method to create a TLS channel security connector.
 | ||||
|   static RefCountedPtr<grpc_channel_security_connector> | ||||
|   CreateTlsChannelSecurityConnector( | ||||
|       RefCountedPtr<grpc_channel_credentials> channel_creds, | ||||
|       RefCountedPtr<grpc_tls_credentials_options> options, | ||||
|       RefCountedPtr<grpc_call_credentials> request_metadata_creds, | ||||
|       const char* target_name, const char* overridden_target_name, | ||||
|       tsi_ssl_session_cache* ssl_session_cache); | ||||
| 
 | ||||
|   TlsChannelSecurityConnector( | ||||
|       RefCountedPtr<grpc_channel_credentials> channel_creds, | ||||
|       RefCountedPtr<grpc_tls_credentials_options> options, | ||||
|       RefCountedPtr<grpc_call_credentials> request_metadata_creds, | ||||
|       const char* target_name, const char* overridden_target_name, | ||||
|       tsi_ssl_session_cache* ssl_session_cache); | ||||
| 
 | ||||
|   ~TlsChannelSecurityConnector() override; | ||||
| 
 | ||||
|   void add_handshakers(const grpc_channel_args* args, | ||||
|                        grpc_pollset_set* interested_parties, | ||||
|                        HandshakeManager* handshake_mgr) override; | ||||
| 
 | ||||
|   void check_peer(tsi_peer peer, grpc_endpoint* ep, | ||||
|                   RefCountedPtr<grpc_auth_context>* auth_context, | ||||
|                   grpc_closure* on_peer_checked) override; | ||||
| 
 | ||||
|   void cancel_check_peer(grpc_closure* /*on_peer_checked*/, | ||||
|                          grpc_error_handle error) override { | ||||
|     // TODO(ZhenLian): call verifier->cancel() once the verifier is ready.
 | ||||
|     GRPC_ERROR_UNREF(error); | ||||
|   } | ||||
| 
 | ||||
|   int cmp(const grpc_security_connector* other_sc) const override; | ||||
| 
 | ||||
|   bool check_call_host(absl::string_view host, grpc_auth_context* auth_context, | ||||
|                        grpc_closure* on_call_host_checked, | ||||
|                        grpc_error_handle* error) override; | ||||
| 
 | ||||
|   void cancel_check_call_host(grpc_closure* on_call_host_checked, | ||||
|                               grpc_error_handle error) override; | ||||
| 
 | ||||
|   tsi_ssl_client_handshaker_factory* ClientHandshakerFactoryForTesting() { | ||||
|     MutexLock lock(&mu_); | ||||
|     return client_handshaker_factory_; | ||||
|   }; | ||||
| 
 | ||||
|   absl::optional<absl::string_view> RootCertsForTesting() { | ||||
|     MutexLock lock(&mu_); | ||||
|     return pem_root_certs_; | ||||
|   } | ||||
| 
 | ||||
|   absl::optional<PemKeyCertPairList> KeyCertPairListForTesting() { | ||||
|     MutexLock lock(&mu_); | ||||
|     return pem_key_cert_pair_list_; | ||||
|   } | ||||
| 
 | ||||
|  private: | ||||
|   // A watcher that watches certificate updates from
 | ||||
|   // grpc_tls_certificate_distributor. It will never outlive
 | ||||
|   // |security_connector_|.
 | ||||
|   class TlsChannelCertificateWatcher : public grpc_tls_certificate_distributor:: | ||||
|                                            TlsCertificatesWatcherInterface { | ||||
|    public: | ||||
|     explicit TlsChannelCertificateWatcher( | ||||
|         TlsChannelSecurityConnector* security_connector) | ||||
|         : security_connector_(security_connector) {} | ||||
|     void OnCertificatesChanged( | ||||
|         absl::optional<absl::string_view> root_certs, | ||||
|         absl::optional<PemKeyCertPairList> key_cert_pairs) override; | ||||
|     void OnError(grpc_error_handle root_cert_error, | ||||
|                  grpc_error_handle identity_cert_error) override; | ||||
| 
 | ||||
|    private: | ||||
|     TlsChannelSecurityConnector* security_connector_ = nullptr; | ||||
|   }; | ||||
| 
 | ||||
|   // Updates |client_handshaker_factory_| when the certificates that
 | ||||
|   // |certificate_watcher_| is watching get updated.
 | ||||
|   grpc_security_status UpdateHandshakerFactoryLocked() | ||||
|       ABSL_EXCLUSIVE_LOCKS_REQUIRED(mu_); | ||||
| 
 | ||||
|   // gRPC-provided callback executed by application, which servers to bring the
 | ||||
|   // control back to gRPC core.
 | ||||
|   static void ServerAuthorizationCheckDone( | ||||
|       grpc_tls_server_authorization_check_arg* arg); | ||||
| 
 | ||||
|   // A util function to process server authorization check result.
 | ||||
|   static grpc_error_handle ProcessServerAuthorizationCheckResult( | ||||
|       grpc_tls_server_authorization_check_arg* arg); | ||||
| 
 | ||||
|   // A util function to create a server authorization check arg instance.
 | ||||
|   static grpc_tls_server_authorization_check_arg* | ||||
|   ServerAuthorizationCheckArgCreate(void* user_data); | ||||
| 
 | ||||
|   // A util function to destroy a server authorization check arg instance.
 | ||||
|   static void ServerAuthorizationCheckArgDestroy( | ||||
|       grpc_tls_server_authorization_check_arg* arg); | ||||
| 
 | ||||
|   RefCountedPtr<grpc_tls_credentials_options> options_; | ||||
|   grpc_tls_certificate_distributor::TlsCertificatesWatcherInterface* | ||||
|       certificate_watcher_ = nullptr; | ||||
|   grpc_closure* on_peer_checked_ = nullptr; | ||||
|   std::string target_name_; | ||||
|   std::string overridden_target_name_; | ||||
|   grpc_tls_server_authorization_check_arg* check_arg_ = nullptr; | ||||
| 
 | ||||
|   Mutex mu_; | ||||
|   tsi_ssl_client_handshaker_factory* client_handshaker_factory_ | ||||
|       ABSL_GUARDED_BY(mu_) = nullptr; | ||||
|   tsi_ssl_session_cache* ssl_session_cache_ ABSL_GUARDED_BY(mu_) = nullptr; | ||||
|   absl::optional<absl::string_view> pem_root_certs_ ABSL_GUARDED_BY(mu_); | ||||
|   absl::optional<PemKeyCertPairList> pem_key_cert_pair_list_ | ||||
|       ABSL_GUARDED_BY(mu_); | ||||
| }; | ||||
| 
 | ||||
| // Server security connector using TLS as transport security protocol.
 | ||||
| class TlsServerSecurityConnector final : public grpc_server_security_connector { | ||||
|  public: | ||||
|   // static factory method to create a TLS server security connector.
 | ||||
|   static RefCountedPtr<grpc_server_security_connector> | ||||
|   CreateTlsServerSecurityConnector( | ||||
|       RefCountedPtr<grpc_server_credentials> server_creds, | ||||
|       RefCountedPtr<grpc_tls_credentials_options> options); | ||||
| 
 | ||||
|   TlsServerSecurityConnector( | ||||
|       RefCountedPtr<grpc_server_credentials> server_creds, | ||||
|       RefCountedPtr<grpc_tls_credentials_options> options); | ||||
|   ~TlsServerSecurityConnector() override; | ||||
| 
 | ||||
|   void add_handshakers(const grpc_channel_args* args, | ||||
|                        grpc_pollset_set* interested_parties, | ||||
|                        HandshakeManager* handshake_mgr) override; | ||||
| 
 | ||||
|   void check_peer(tsi_peer peer, grpc_endpoint* ep, | ||||
|                   RefCountedPtr<grpc_auth_context>* auth_context, | ||||
|                   grpc_closure* on_peer_checked) override; | ||||
| 
 | ||||
|   void cancel_check_peer(grpc_closure* /*on_peer_checked*/, | ||||
|                          grpc_error_handle error) override { | ||||
|     // TODO(ZhenLian): call verifier->cancel() once the verifier is ready.
 | ||||
|     GRPC_ERROR_UNREF(error); | ||||
|   } | ||||
| 
 | ||||
|   int cmp(const grpc_security_connector* other) const override; | ||||
| 
 | ||||
|   tsi_ssl_server_handshaker_factory* ServerHandshakerFactoryForTesting() { | ||||
|     MutexLock lock(&mu_); | ||||
|     return server_handshaker_factory_; | ||||
|   }; | ||||
| 
 | ||||
|   const absl::optional<absl::string_view>& RootCertsForTesting() { | ||||
|     MutexLock lock(&mu_); | ||||
|     return pem_root_certs_; | ||||
|   } | ||||
| 
 | ||||
|   const absl::optional<PemKeyCertPairList>& KeyCertPairListForTesting() { | ||||
|     MutexLock lock(&mu_); | ||||
|     return pem_key_cert_pair_list_; | ||||
|   } | ||||
| 
 | ||||
|  private: | ||||
|   // A watcher that watches certificate updates from
 | ||||
|   // grpc_tls_certificate_distributor. It will never outlive
 | ||||
|   // |security_connector_|.
 | ||||
|   class TlsServerCertificateWatcher : public grpc_tls_certificate_distributor:: | ||||
|                                           TlsCertificatesWatcherInterface { | ||||
|    public: | ||||
|     explicit TlsServerCertificateWatcher( | ||||
|         TlsServerSecurityConnector* security_connector) | ||||
|         : security_connector_(security_connector) {} | ||||
|     void OnCertificatesChanged( | ||||
|         absl::optional<absl::string_view> root_certs, | ||||
|         absl::optional<PemKeyCertPairList> key_cert_pairs) override; | ||||
|     void OnError(grpc_error_handle root_cert_error, | ||||
|                  grpc_error_handle identity_cert_error) override; | ||||
| 
 | ||||
|    private: | ||||
|     TlsServerSecurityConnector* security_connector_ = nullptr; | ||||
|   }; | ||||
| 
 | ||||
|   // Updates |server_handshaker_factory_| when the certificates that
 | ||||
|   // |certificate_watcher_| is watching get updated.
 | ||||
|   grpc_security_status UpdateHandshakerFactoryLocked() | ||||
|       ABSL_EXCLUSIVE_LOCKS_REQUIRED(mu_); | ||||
| 
 | ||||
|   // gRPC-provided callback executed by application, which servers to bring the
 | ||||
|   // control back to gRPC core.
 | ||||
|   static void ClientAuthorizationCheckDone( | ||||
|       grpc_tls_server_authorization_check_arg* arg); | ||||
| 
 | ||||
|   // A util function to process server authorization check result.
 | ||||
|   static grpc_error_handle ProcessClientAuthorizationCheckResult( | ||||
|       grpc_tls_server_authorization_check_arg* arg); | ||||
| 
 | ||||
|   // A util function to create a server authorization check arg instance.
 | ||||
|   static grpc_tls_server_authorization_check_arg* | ||||
|       ClientAuthorizationCheckArgCreate(void* user_data); | ||||
| 
 | ||||
|   // A util function to destroy a server authorization check arg instance.
 | ||||
|   static void ClientAuthorizationCheckArgDestroy( | ||||
|       grpc_tls_server_authorization_check_arg* arg); | ||||
| 
 | ||||
|   RefCountedPtr<grpc_tls_credentials_options> options_; | ||||
| 
 | ||||
|   grpc_tls_certificate_distributor::TlsCertificatesWatcherInterface* | ||||
|       certificate_watcher_ = nullptr; | ||||
|   grpc_closure* on_peer_checked_ = nullptr; | ||||
|   std::string target_name_ = "localhost"; | ||||
|   std::string overridden_target_name_= "localhost"; | ||||
|   grpc_tls_server_authorization_check_arg* check_arg_ = nullptr; | ||||
| 
 | ||||
|   Mutex mu_; | ||||
|   tsi_ssl_server_handshaker_factory* server_handshaker_factory_ | ||||
|       ABSL_GUARDED_BY(mu_) = nullptr; | ||||
|   absl::optional<absl::string_view> pem_root_certs_ ABSL_GUARDED_BY(mu_); | ||||
|   absl::optional<PemKeyCertPairList> pem_key_cert_pair_list_ | ||||
|       ABSL_GUARDED_BY(mu_); | ||||
| }; | ||||
| 
 | ||||
| // ---- Functions below are exposed for testing only -----------------------
 | ||||
| namespace internal { | ||||
| 
 | ||||
| // TlsCheckHostName checks if |peer_name| matches the identity information
 | ||||
| // contained in |peer|. This is AKA hostname check.
 | ||||
| grpc_error_handle TlsCheckHostName(const char* peer_name, const tsi_peer* peer); | ||||
| 
 | ||||
| }  // namespace internal
 | ||||
| 
 | ||||
| }  // namespace grpc_core
 | ||||
| 
 | ||||
| #endif  // GRPC_CORE_LIB_SECURITY_SECURITY_CONNECTOR_TLS_TLS_SECURITY_CONNECTOR_H
 | ||||
| @ -1,260 +0,0 @@ | ||||
| /*
 | ||||
|  * | ||||
|  * Copyright (c) 2022 Intel Corporation | ||||
|  * | ||||
|  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|  * you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * | ||||
|  *     http://www.apache.org/licenses/LICENSE-2.0
 | ||||
|  * | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an "AS IS" BASIS, | ||||
|  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|  * See the License for the specific language governing permissions and | ||||
|  * limitations under the License. | ||||
|  * | ||||
|  */ | ||||
| 
 | ||||
| #include "sgx_ra_tls_backends.h" | ||||
| 
 | ||||
| namespace grpc { | ||||
| namespace sgx { | ||||
| 
 | ||||
| struct ra_tls_context _ctx_; | ||||
| 
 | ||||
| std::vector<std::string> ra_tls_get_key_cert() { | ||||
| #ifdef SGX_RA_TLS_OCCLUM_BACKEND | ||||
|     return occlum_get_key_cert(); | ||||
| #endif | ||||
| } | ||||
| 
 | ||||
| static std::vector<grpc::experimental::IdentityKeyCertPair> get_identity_key_cert_pairs( | ||||
|     std::vector<std::string> key_cert) { | ||||
|     grpc::experimental::IdentityKeyCertPair key_cert_pair; | ||||
|     key_cert_pair.private_key = key_cert[0]; | ||||
|     key_cert_pair.certificate_chain = key_cert[1]; | ||||
|     std::vector<grpc::experimental::IdentityKeyCertPair> identity_key_cert_pairs; | ||||
|     identity_key_cert_pairs.emplace_back(key_cert_pair); | ||||
|     return identity_key_cert_pairs; | ||||
| } | ||||
| 
 | ||||
| void credential_option_set_certificate_provider(grpc::sgx::CredentialsOptions& options) { | ||||
|     std::lock_guard<std::mutex> lock(_ctx_.mtx); | ||||
| 
 | ||||
|     _ctx_.cache.id++; | ||||
| 
 | ||||
|     auto certificate_provider = _ctx_.cache.certificate_provider.insert({ | ||||
|             _ctx_.cache.id, | ||||
|             std::make_shared<grpc::experimental::StaticDataCertificateProvider>( | ||||
|                 get_identity_key_cert_pairs(ra_tls_get_key_cert())) | ||||
|         }).first; | ||||
| 
 | ||||
|     options.set_certificate_provider(certificate_provider->second); | ||||
|     options.watch_identity_key_cert_pairs(); | ||||
|     options.set_cert_request_type(GRPC_SSL_REQUEST_AND_REQUIRE_CLIENT_CERTIFICATE_BUT_DONT_VERIFY); | ||||
|     options.set_root_cert_name(""); | ||||
|     options.set_identity_cert_name(""); | ||||
| } | ||||
| 
 | ||||
| static sgx_config parse_sgx_config_json(const char* file) { | ||||
|     class json_engine sgx_json(file); | ||||
|     struct sgx_config sgx_cfg; | ||||
| 
 | ||||
|     sgx_cfg.verify_mr_enclave = sgx_json.compare_item(sgx_json.get_item(sgx_json.get_handle(), "verify_mr_enclave"), "on"); | ||||
|     sgx_cfg.verify_mr_signer = sgx_json.compare_item(sgx_json.get_item(sgx_json.get_handle(), "verify_mr_signer"), "on"); | ||||
|     sgx_cfg.verify_isv_prod_id = sgx_json.compare_item(sgx_json.get_item(sgx_json.get_handle(), "verify_isv_prod_id"), "on"); | ||||
|     sgx_cfg.verify_isv_svn = sgx_json.compare_item(sgx_json.get_item(sgx_json.get_handle(), "verify_isv_svn"), "on"); | ||||
|     sgx_cfg.verify_config_svn = sgx_json.compare_item(sgx_json.get_item(sgx_json.get_handle(), "verify_config_svn"), "on"); | ||||
|     sgx_cfg.verify_enclave_debuggable = | ||||
|         sgx_json.compare_item(sgx_json.get_item(sgx_json.get_handle(), "verify_enclave_debuggable"), "on"); | ||||
| 
 | ||||
|     auto objs = sgx_json.get_item(sgx_json.get_handle(), "sgx_mrs"); | ||||
|     auto obj_num = std::min(cJSON_GetArraySize(objs), SGX_MESUREMENTS_MAX_SIZE); | ||||
| 
 | ||||
|     sgx_cfg.sgx_mrs = std::vector<sgx_measurement>(obj_num, sgx_measurement()); | ||||
|     for (auto i = 0; i < obj_num; i++) { | ||||
|         auto obj = cJSON_GetArrayItem(objs, i); | ||||
| 
 | ||||
|         auto mr_enclave = sgx_json.print_item(sgx_json.get_item(obj, "mr_enclave")); | ||||
|         memset(sgx_cfg.sgx_mrs[i].mr_enclave, 0, sizeof(sgx_cfg.sgx_mrs[i].mr_enclave)); | ||||
|         hex_to_byte(mr_enclave+1, sgx_cfg.sgx_mrs[i].mr_enclave, sizeof(sgx_cfg.sgx_mrs[i].mr_enclave)); | ||||
| 
 | ||||
|         auto mr_signer = sgx_json.print_item(sgx_json.get_item(obj, "mr_signer")); | ||||
|         memset(sgx_cfg.sgx_mrs[i].mr_signer, 0, sizeof(sgx_cfg.sgx_mrs[i].mr_signer)); | ||||
|         hex_to_byte(mr_signer+1, sgx_cfg.sgx_mrs[i].mr_signer, sizeof(sgx_cfg.sgx_mrs[i].mr_signer)); | ||||
| 
 | ||||
|         auto isv_prod_id = sgx_json.print_item(sgx_json.get_item(obj, "isv_prod_id")); | ||||
|         sgx_cfg.sgx_mrs[i].isv_prod_id = strtoul(isv_prod_id, nullptr, 10); | ||||
| 
 | ||||
|         auto isv_svn = sgx_json.print_item(sgx_json.get_item(obj, "isv_svn")); | ||||
|         sgx_cfg.sgx_mrs[i].isv_svn = strtoul(isv_svn, nullptr, 10); | ||||
| 
 | ||||
|         auto config_svn = sgx_json.print_item(sgx_json.get_item(obj, "config_svn")); | ||||
|         sgx_cfg.sgx_mrs[i].config_svn = strtoul(config_svn, nullptr, 10); | ||||
| 
 | ||||
|         if (cJSON_IsTrue(sgx_json.get_item(obj, "debuggable")) == 0) | ||||
|             sgx_cfg.sgx_mrs[i].debuggable = false; | ||||
|         else | ||||
|             sgx_cfg.sgx_mrs[i].debuggable = true; | ||||
|     }; | ||||
|     return sgx_cfg; | ||||
| } | ||||
| 
 | ||||
| void ra_tls_parse_sgx_config(sgx_config sgx_cfg) { | ||||
|     std::lock_guard<std::mutex> lock(_ctx_.mtx); | ||||
|     _ctx_.sgx_cfg = sgx_cfg; | ||||
| } | ||||
| 
 | ||||
| void ra_tls_parse_sgx_config(const char* file) { | ||||
|     ra_tls_parse_sgx_config(parse_sgx_config_json(file)); | ||||
| } | ||||
| 
 | ||||
| void ra_tls_verify_init() { | ||||
|     std::lock_guard<std::mutex> lock(_ctx_.mtx); | ||||
| } | ||||
| 
 | ||||
| static bool verify_measurement_internal(const char* mr_enclave, const char* mr_signer, | ||||
|                                         const char* isv_prod_id, const char* isv_svn, | ||||
|                                         const char* config_svn, bool debuggable) { | ||||
|     bool status = false; | ||||
|     auto & sgx_cfg = _ctx_.sgx_cfg; | ||||
|     for (auto & obj : sgx_cfg.sgx_mrs) { | ||||
|         status = true; | ||||
| 
 | ||||
|         if (status && sgx_cfg.verify_mr_enclave && \ | ||||
|             memcmp(obj.mr_enclave, mr_enclave, 32)) { | ||||
|             status = false; | ||||
|         } | ||||
| 
 | ||||
|         if (status && sgx_cfg.verify_mr_signer && \ | ||||
|             memcmp(obj.mr_signer, mr_signer, 32)) { | ||||
|             status = false; | ||||
|         } | ||||
| 
 | ||||
|         if (status && sgx_cfg.verify_isv_prod_id && \ | ||||
|             (obj.isv_prod_id != *(uint16_t*)isv_prod_id)) { | ||||
|             status = false; | ||||
|         } | ||||
| 
 | ||||
|         if (status && sgx_cfg.verify_isv_svn && \ | ||||
|             (obj.isv_svn != *(uint16_t*)isv_svn)) { | ||||
|             status = false; | ||||
|         } | ||||
| 
 | ||||
|         if (status && sgx_cfg.verify_config_svn && \ | ||||
|             (obj.config_svn != *(uint16_t*)config_svn)) { | ||||
|             status = false; | ||||
|         } | ||||
| 
 | ||||
|         if (status && sgx_cfg.verify_enclave_debuggable && \ | ||||
|             (obj.debuggable != debuggable)) { | ||||
|             status = false; | ||||
|         } | ||||
| 
 | ||||
|         if (status) { | ||||
|             break; | ||||
|         } | ||||
|     } | ||||
|     return status; | ||||
| } | ||||
| 
 | ||||
| int verify_measurement(const char* mr_enclave, const char* mr_signer, | ||||
|                        const char* isv_prod_id, const char* isv_svn, | ||||
|                        const char* config_svn, bool debuggable) { | ||||
|     std::lock_guard<std::mutex> lock(_ctx_.mtx); | ||||
|     bool status = false; | ||||
|     try { | ||||
|         assert(mr_enclave && mr_signer && isv_prod_id && isv_svn && config_svn); | ||||
|         status = verify_measurement_internal( | ||||
|             mr_enclave, mr_signer, isv_prod_id, isv_svn, config_svn, debuggable | ||||
|             ); | ||||
|         if (status) { | ||||
|             grpc_printf("  |- verify result  :  success\n"); | ||||
|         } else { | ||||
|             grpc_printf("Below remote sgx measurements is not in the allowable list.\n"); | ||||
|             grpc_printf("  |- mr_enclave     :  %s\n", byte_to_hex(mr_enclave, 32).c_str()); | ||||
|             grpc_printf("  |- mr_signer      :  %s\n", byte_to_hex(mr_signer, 32).c_str()); | ||||
|             grpc_printf("  |- isv_prod_id    :  %hu\n", *((uint16_t*)isv_prod_id)); | ||||
|             grpc_printf("  |- isv_svn        :  %hu\n", *((uint16_t*)isv_svn)); | ||||
|             grpc_printf("  |- config_svn     :  %hu\n", *((uint16_t*)config_svn)); | ||||
|             grpc_printf("  |- debuggable     :  %s\n", debuggable?"true":"false"); | ||||
|             grpc_printf("  |- verify result  :  failed\n"); | ||||
|         } | ||||
|     } catch (...) { | ||||
|         grpc_printf("unable to verify measurement!"); | ||||
|     } | ||||
| 
 | ||||
|     fflush(stdout); | ||||
|     return status ? 0 : -1; | ||||
| } | ||||
| 
 | ||||
| int TlsAuthorizationCheck::Schedule(grpc::experimental::TlsServerAuthorizationCheckArg* arg) { | ||||
|     GPR_ASSERT(arg != nullptr); | ||||
| 
 | ||||
|     char der_crt[16000] = ""; | ||||
|     auto peer_cert_buf = arg->peer_cert(); | ||||
|     peer_cert_buf.copy(der_crt, peer_cert_buf.length(), 0); | ||||
| 
 | ||||
| #ifdef SGX_RA_TLS_OCCLUM_BACKEND | ||||
|     int ret = occlum_verify_cert((const unsigned char *)der_crt, 16000); | ||||
| #endif | ||||
| 
 | ||||
|     if (ret != 0) { | ||||
|         grpc_printf("something went wrong while verifying quote\n"); | ||||
|         arg->set_success(0); | ||||
|         arg->set_status(GRPC_STATUS_UNAUTHENTICATED); | ||||
|     } else { | ||||
|         arg->set_success(1); | ||||
|         arg->set_status(GRPC_STATUS_OK); | ||||
|     } | ||||
|     return 0; | ||||
| }; | ||||
| 
 | ||||
| void TlsAuthorizationCheck::Cancel(grpc::experimental::TlsServerAuthorizationCheckArg* arg) { | ||||
|     GPR_ASSERT(arg != nullptr); | ||||
|     arg->set_status(GRPC_STATUS_PERMISSION_DENIED); | ||||
|     arg->set_error_details("cancelled"); | ||||
| }; | ||||
| 
 | ||||
| int ra_tls_auth_check_schedule(void* /* confiuser_data */, | ||||
|                                grpc_tls_server_authorization_check_arg* arg) { | ||||
|     char der_crt[16000] = ""; | ||||
|     memcpy(der_crt, arg->peer_cert, strlen(arg->peer_cert)); | ||||
| 
 | ||||
| #ifdef SGX_RA_TLS_OCCLUM_BACKEND | ||||
|     int ret = occlum_verify_cert((const unsigned char *)der_crt, 16000); | ||||
| #endif | ||||
| 
 | ||||
|     if (ret != 0) { | ||||
|         grpc_printf("something went wrong while verifying quote\n"); | ||||
|         arg->success = 0; | ||||
|         arg->status = GRPC_STATUS_UNAUTHENTICATED; | ||||
|     } else { | ||||
|         arg->success = 1; | ||||
|         arg->status = GRPC_STATUS_OK; | ||||
|     } | ||||
|     return 0; | ||||
| } | ||||
| 
 | ||||
| void credential_option_set_authorization_check(grpc::sgx::CredentialsOptions& options) { | ||||
|     std::lock_guard<std::mutex> lock(_ctx_.mtx); | ||||
| 
 | ||||
|     _ctx_.cache.id++; | ||||
| 
 | ||||
|     auto authorization_check = _ctx_.cache.authorization_check.insert({ | ||||
|             _ctx_.cache.id, std::make_shared<grpc::sgx::TlsAuthorizationCheck>() | ||||
|         }).first; | ||||
| 
 | ||||
|     auto authorization_check_config = _ctx_.cache.authorization_check_config.insert({ | ||||
|             _ctx_.cache.id, | ||||
|             std::make_shared<grpc::experimental::TlsServerAuthorizationCheckConfig>( | ||||
|                 authorization_check->second) | ||||
|         }).first; | ||||
| 
 | ||||
|     options.set_authorization_check_config(authorization_check_config->second); | ||||
|     options.set_verification_option(GRPC_TLS_SKIP_ALL_SERVER_VERIFICATION); | ||||
| } | ||||
| 
 | ||||
| } // namespace sgx
 | ||||
| } // namespace grpc
 | ||||
| @ -1,114 +0,0 @@ | ||||
| /*
 | ||||
|  * | ||||
|  * Copyright (c) 2022 Intel Corporation | ||||
|  * | ||||
|  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|  * you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * | ||||
|  *     http://www.apache.org/licenses/LICENSE-2.0
 | ||||
|  * | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an "AS IS" BASIS, | ||||
|  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|  * See the License for the specific language governing permissions and | ||||
|  * limitations under the License. | ||||
|  * | ||||
|  */ | ||||
| 
 | ||||
| #ifndef SGX_RA_TLS_BACKENDS_H | ||||
| #define SGX_RA_TLS_BACKENDS_H | ||||
| 
 | ||||
| #include "sgx_ra_tls_utils.h" | ||||
| 
 | ||||
| #include <mutex> | ||||
| #include <unordered_map> | ||||
| 
 | ||||
| #include <grpcpp/grpcpp.h> | ||||
| #include <grpc/grpc_security.h> | ||||
| #include <grpc/grpc_security_constants.h> | ||||
| #include <grpcpp/security/credentials.h> | ||||
| #include <grpcpp/security/tls_certificate_provider.h> | ||||
| #include <grpcpp/security/tls_credentials_options.h> | ||||
| #include <grpcpp/security/server_credentials.h> | ||||
| #include <grpcpp/security/sgx/sgx_ra_tls_options.h> | ||||
| 
 | ||||
| // Set 1 for strict safety checks
 | ||||
| #define SGX_MESUREMENTS_MAX_SIZE 16 | ||||
| 
 | ||||
| namespace grpc { | ||||
| namespace sgx { | ||||
| 
 | ||||
| class TlsAuthorizationCheck | ||||
|     : public grpc::experimental::TlsServerAuthorizationCheckInterface { | ||||
|     int Schedule(grpc::experimental::TlsServerAuthorizationCheckArg* arg) override; | ||||
|     void Cancel(grpc::experimental::TlsServerAuthorizationCheckArg* arg) override; | ||||
| }; | ||||
| 
 | ||||
| struct sgx_measurement { | ||||
|     char mr_enclave[32]; | ||||
|     char mr_signer[32]; | ||||
|     uint16_t isv_prod_id; | ||||
|     uint16_t isv_svn; | ||||
|     uint16_t config_svn; | ||||
|     bool debuggable; | ||||
| }; | ||||
| 
 | ||||
| struct sgx_config { | ||||
|     bool verify_mr_enclave  = true; | ||||
|     bool verify_mr_signer   = true; | ||||
|     bool verify_isv_prod_id = true; | ||||
|     bool verify_isv_svn     = true; | ||||
|     bool verify_config_svn = true; | ||||
|     bool verify_enclave_debuggable = true; | ||||
|     std::vector<sgx_measurement> sgx_mrs; | ||||
| }; | ||||
| 
 | ||||
| struct ra_tls_cache { | ||||
|     int id = 0; | ||||
|     std::unordered_map< | ||||
|             int, std::shared_ptr<grpc::experimental::StaticDataCertificateProvider> | ||||
|         > certificate_provider; | ||||
|     std::unordered_map< | ||||
|             int, std::shared_ptr<grpc::sgx::TlsAuthorizationCheck> | ||||
|         > authorization_check; | ||||
|     std::unordered_map< | ||||
|             int, std::shared_ptr<grpc::experimental::TlsServerAuthorizationCheckConfig> | ||||
|         > authorization_check_config; | ||||
| }; | ||||
| 
 | ||||
| struct ra_tls_context { | ||||
|     std::mutex mtx; | ||||
|     struct sgx_config sgx_cfg; | ||||
|     struct ra_tls_cache cache; | ||||
| }; | ||||
| 
 | ||||
| extern struct ra_tls_context _ctx_; | ||||
| 
 | ||||
| 
 | ||||
| #ifdef SGX_RA_TLS_OCCLUM_BACKEND | ||||
| 
 | ||||
| std::vector<std::string> occlum_get_key_cert(); | ||||
| 
 | ||||
| int occlum_verify_cert(const unsigned char * der_crt, size_t len); | ||||
| 
 | ||||
| #endif // SGX_RA_TLS_OCCLUM_BACKEND
 | ||||
| 
 | ||||
| void ra_tls_parse_sgx_config(sgx_config sgx_cfg); | ||||
| 
 | ||||
| void ra_tls_parse_sgx_config(const char* file); | ||||
| 
 | ||||
| void ra_tls_verify_init(); | ||||
| 
 | ||||
| int verify_measurement(const char* mr_enclave, const char* mr_signer, | ||||
|                        const char* isv_prod_id, const char* isv_svn, | ||||
|                        const char* config_svn, bool debuggable); | ||||
| 
 | ||||
| void credential_option_set_certificate_provider(grpc::sgx::CredentialsOptions& options); | ||||
| 
 | ||||
| void credential_option_set_authorization_check(grpc::sgx::CredentialsOptions& options); | ||||
| 
 | ||||
| } // namespace sgx
 | ||||
| } // namespace grpc
 | ||||
| 
 | ||||
| #endif // SGX_RA_TLS_BACKENDS_H
 | ||||
| @ -1,98 +0,0 @@ | ||||
| /*
 | ||||
|  * | ||||
|  * Copyright (c) 2022 Intel Corporation | ||||
|  * | ||||
|  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|  * you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * | ||||
|  *     http://www.apache.org/licenses/LICENSE-2.0
 | ||||
|  * | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an "AS IS" BASIS, | ||||
|  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|  * See the License for the specific language governing permissions and | ||||
|  * limitations under the License. | ||||
|  * | ||||
|  */ | ||||
| 
 | ||||
| #include "sgx_ra_tls_backends.h" | ||||
| 
 | ||||
| namespace grpc { | ||||
| namespace sgx { | ||||
| 
 | ||||
| /*
 | ||||
| RA-TLS: on client, only need to register ra_tls_verify_callback() for cert verification | ||||
|   1. extract SGX quote from "quote" OID extension from crt | ||||
|   2. compare public key's hash from cert against quote's report_data | ||||
|   3. prepare user-supplied verification parameter "allow outdated TCB" | ||||
|   4. call into libsgx_dcap_quoteverify to verify ECDSA/based SGX quote | ||||
|   5. verify all measurements from the SGX quote | ||||
| */ | ||||
| 
 | ||||
| std::shared_ptr<grpc::ChannelCredentials> TlsCredentials(sgx_config sgx_cfg) { | ||||
|     grpc::sgx::CredentialsOptions options; | ||||
| 
 | ||||
|     ra_tls_parse_sgx_config(sgx_cfg); | ||||
| 
 | ||||
|     credential_option_set_certificate_provider(options); | ||||
| 
 | ||||
|     ra_tls_verify_init(); | ||||
|     credential_option_set_authorization_check(options); | ||||
| 
 | ||||
|     return grpc::experimental::TlsCredentials( | ||||
|         reinterpret_cast<const grpc::experimental::TlsChannelCredentialsOptions&>(options)); | ||||
| }; | ||||
| 
 | ||||
| std::shared_ptr<grpc::ChannelCredentials> TlsCredentials(const char* sgx_cfg_json) { | ||||
|     grpc::sgx::CredentialsOptions options; | ||||
| 
 | ||||
|     ra_tls_parse_sgx_config(sgx_cfg_json); | ||||
| 
 | ||||
|     credential_option_set_certificate_provider(options); | ||||
| 
 | ||||
|     ra_tls_verify_init(); | ||||
|     credential_option_set_authorization_check(options); | ||||
| 
 | ||||
|     return grpc::experimental::TlsCredentials( | ||||
|         reinterpret_cast<const grpc::experimental::TlsChannelCredentialsOptions&>(options)); | ||||
| }; | ||||
| 
 | ||||
| std::shared_ptr<grpc::ServerCredentials> TlsServerCredentials(sgx_config sgx_cfg) { | ||||
|     grpc::sgx::CredentialsOptions options; | ||||
| 
 | ||||
|     ra_tls_parse_sgx_config(sgx_cfg); | ||||
| 
 | ||||
|     credential_option_set_certificate_provider(options); | ||||
| 
 | ||||
|     ra_tls_verify_init(); | ||||
|     credential_option_set_authorization_check(options); | ||||
| 
 | ||||
|     return grpc::experimental::TlsServerCredentials( | ||||
|         reinterpret_cast<const grpc::experimental::TlsServerCredentialsOptions&>(options)); | ||||
| }; | ||||
| 
 | ||||
| std::shared_ptr<grpc::ServerCredentials> TlsServerCredentials(const char* sgx_cfg_json) { | ||||
|     grpc::sgx::CredentialsOptions options; | ||||
| 
 | ||||
|     ra_tls_parse_sgx_config(sgx_cfg_json); | ||||
| 
 | ||||
|     credential_option_set_certificate_provider(options); | ||||
| 
 | ||||
|     ra_tls_verify_init(); | ||||
|     credential_option_set_authorization_check(options); | ||||
| 
 | ||||
|     return grpc::experimental::TlsServerCredentials( | ||||
|         reinterpret_cast<const grpc::experimental::TlsServerCredentialsOptions&>(options)); | ||||
| }; | ||||
| 
 | ||||
| std::shared_ptr<grpc::Channel> CreateSecureChannel( | ||||
|     string target_str, std::shared_ptr<grpc::ChannelCredentials> channel_creds) { | ||||
|     GPR_ASSERT(channel_creds.get() != nullptr); | ||||
|     auto channel_args = grpc::ChannelArguments(); | ||||
|     channel_args.SetSslTargetNameOverride("RATLS"); | ||||
|     return grpc::CreateCustomChannel(target_str, std::move(channel_creds), channel_args); | ||||
| }; | ||||
| 
 | ||||
| } // namespace sgx
 | ||||
| } // namespace grpc
 | ||||
| @ -1,325 +0,0 @@ | ||||
| /*
 | ||||
|  * | ||||
|  * Copyright (c) 2022 Intel Corporation | ||||
|  * | ||||
|  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|  * you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * | ||||
|  *     http://www.apache.org/licenses/LICENSE-2.0
 | ||||
|  * | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an "AS IS" BASIS, | ||||
|  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|  * See the License for the specific language governing permissions and | ||||
|  * limitations under the License. | ||||
|  * | ||||
|  */ | ||||
| 
 | ||||
| #include "sgx_ra_tls_backends.h" | ||||
| 
 | ||||
| namespace grpc { | ||||
| namespace sgx { | ||||
| 
 | ||||
| #ifdef SGX_RA_TLS_OCCLUM_BACKEND | ||||
| 
 | ||||
| #include <openssl/evp.h> | ||||
| #include <openssl/rsa.h> | ||||
| #include <openssl/x509.h> | ||||
| #include <openssl/x509v3.h> | ||||
| #include <openssl/sha.h> | ||||
| #include <openssl/pem.h> | ||||
| #include <openssl/asn1.h> | ||||
| 
 | ||||
| #include "sgx_quote_3.h" | ||||
| #include "occlum_dcap.h" | ||||
| 
 | ||||
| const char * RA_TLS_LONG_NAME = "RA-TLS Extension"; | ||||
| const char * RA_TLS_SHORT_NAME = "RA-TLS"; | ||||
| 
 | ||||
| std::vector<std::string> occlum_get_key_cert() { | ||||
|     unsigned char private_key_pem[16000], cert_pem[16000]; | ||||
| 
 | ||||
|     BIGNUM * e = BN_new(); | ||||
|     BN_set_word(e, RSA_F4); | ||||
|     RSA * rsa = RSA_new(); | ||||
|     RSA_generate_key_ex(rsa, 2048, e, nullptr); | ||||
| 
 | ||||
|     EVP_PKEY * pkey = EVP_PKEY_new(); | ||||
|     EVP_PKEY_assign_RSA(pkey, rsa); | ||||
| 
 | ||||
|     X509 * x509 = X509_new(); | ||||
| 
 | ||||
|     ASN1_INTEGER_set(X509_get_serialNumber(x509), 1); | ||||
|     X509_gmtime_adj(X509_get_notBefore(x509), 0); | ||||
|     X509_gmtime_adj(X509_get_notAfter(x509), 630720000L); | ||||
|     X509_set_pubkey(x509, pkey); | ||||
| 
 | ||||
|     X509_NAME * name = X509_NAME_new(); | ||||
|     // X509_NAME * name = X509_get_subject_name(x509);
 | ||||
|     X509_NAME_add_entry_by_txt(name, "C",  MBSTRING_ASC, | ||||
|                             (unsigned char *)"CN", -1, -1, 0); | ||||
|     X509_NAME_add_entry_by_txt(name, "O",  MBSTRING_ASC, | ||||
|                             (unsigned char *)"Intel Inc.", -1, -1, 0); | ||||
|     X509_NAME_add_entry_by_txt(name, "CN", MBSTRING_ASC, | ||||
|                             (unsigned char *)"localhost", -1, -1, 0); | ||||
|     X509_set_subject_name(x509, name); | ||||
|     X509_set_issuer_name(x509, name); | ||||
| 
 | ||||
|     int32_t ret; | ||||
|     size_t key_len = i2d_PUBKEY(pkey, 0); | ||||
|     unsigned char *public_key = NULL; | ||||
|     // size_t pubkey_len = i2d_PUBKEY(pkey, &public_key);
 | ||||
|     size_t pubkey_len = i2d_X509_PUBKEY(X509_get_X509_PUBKEY(x509), &public_key); | ||||
| 
 | ||||
|     if (pubkey_len != key_len) { | ||||
|         grpc_printf("get public key failed!\n"); | ||||
|     } | ||||
| 
 | ||||
|     BIO *bio = BIO_new(BIO_s_mem()); | ||||
|     if (nullptr == bio) { | ||||
|         grpc_printf("create bio failed!\n"); | ||||
|     } | ||||
| 
 | ||||
|     ret = PEM_write_bio_RSAPrivateKey(bio, rsa, nullptr, nullptr, 0, nullptr, nullptr); | ||||
|     if (ret == 0) { | ||||
|         grpc_printf("write private key failed!\n"); | ||||
|     } | ||||
| 
 | ||||
|     ret = BIO_read(bio, private_key_pem, bio->num_write); | ||||
|     if (ret == 0) { | ||||
|         grpc_printf("read private key failed!\n"); | ||||
|     } | ||||
| 
 | ||||
|     unsigned char hash[SHA256_DIGEST_LENGTH]; | ||||
|     SHA256_CTX sha256; | ||||
|     SHA256_Init(&sha256); | ||||
|     SHA256_Update(&sha256, public_key, key_len); | ||||
|     SHA256_Final(hash, &sha256); | ||||
| 
 | ||||
|     void *handle; | ||||
|     uint32_t quote_size; | ||||
|     uint8_t *p_quote_buffer; | ||||
| 
 | ||||
|     handle = dcap_quote_open(); | ||||
|     quote_size = dcap_get_quote_size(handle); | ||||
| 
 | ||||
|     p_quote_buffer = (uint8_t*)malloc(quote_size); | ||||
|     if (nullptr == p_quote_buffer) { | ||||
|         grpc_printf("Couldn't allocate quote_buffer\n"); | ||||
|     } | ||||
|     memset(p_quote_buffer, 0, quote_size); | ||||
| 
 | ||||
|     sgx_report_data_t report_data = { 0 }; | ||||
|     memcpy(report_data.d, hash, SHA256_DIGEST_LENGTH); | ||||
| 
 | ||||
|     ret = dcap_generate_quote(handle, p_quote_buffer, &report_data); | ||||
|     if (0 != ret) { | ||||
|         grpc_printf( "Error in dcap_generate_quote.\n"); | ||||
|     } | ||||
| 
 | ||||
|     int nid = OBJ_create("1.2.840.113741.1", RA_TLS_SHORT_NAME, RA_TLS_LONG_NAME); | ||||
|     ASN1_OBJECT* obj = OBJ_nid2obj(nid);   | ||||
|     ASN1_OCTET_STRING* data = ASN1_OCTET_STRING_new(); | ||||
|     ASN1_OCTET_STRING_set(data, p_quote_buffer, quote_size); | ||||
| 
 | ||||
|     X509_EXTENSION* ext = X509_EXTENSION_create_by_OBJ(nullptr, obj, 0, data); | ||||
|     X509_add_ext(x509, ext, -1); | ||||
| 
 | ||||
|     X509_sign(x509, pkey, EVP_sha1()); | ||||
| 
 | ||||
|     BIO *cert_bio = BIO_new(BIO_s_mem()); | ||||
|     if (nullptr == cert_bio) { | ||||
|         grpc_printf("create crt bio failed!\n"); | ||||
|     } | ||||
| 
 | ||||
|     if (0 == PEM_write_bio_X509(cert_bio, x509)) { | ||||
|         BIO_free(cert_bio); | ||||
|         grpc_printf("read crt bio failed!\n"); | ||||
|     } | ||||
| 
 | ||||
|     ret = BIO_read(cert_bio, cert_pem, cert_bio->num_write); | ||||
|     if (ret == 0) { | ||||
|         grpc_printf("read pem cert failed!\n"); | ||||
|     } | ||||
| 
 | ||||
|     BIO_free(bio); | ||||
|     BIO_free(cert_bio); | ||||
|     EVP_PKEY_free(pkey); | ||||
|     check_free(p_quote_buffer); | ||||
|     dcap_quote_close(handle); | ||||
| 
 | ||||
|     std::vector<std::string> key_cert; | ||||
|     key_cert.emplace_back(std::string((char*) private_key_pem)); | ||||
|     key_cert.emplace_back(std::string((char*) cert_pem)); | ||||
|     return key_cert; | ||||
| } | ||||
| 
 | ||||
| static int occlum_get_quote(X509 *x509, uint8_t **quote, size_t *len) { | ||||
|     STACK_OF(X509_EXTENSION) *exts = x509->cert_info->extensions; | ||||
|     int ext_num; | ||||
|     int ret = -1;  | ||||
|     if (exts) { | ||||
|         ext_num = sk_X509_EXTENSION_num(exts); | ||||
| 
 | ||||
|         for (int i = 0; i < ext_num; i++) { | ||||
|         X509_EXTENSION *ext = sk_X509_EXTENSION_value(exts, i); | ||||
|         ASN1_OBJECT *obj = X509_EXTENSION_get_object(ext); | ||||
| 
 | ||||
|         unsigned nid = OBJ_obj2nid(obj); | ||||
|         if (nid != NID_undef) { | ||||
|             const char *ln = OBJ_nid2ln(nid); | ||||
|             if (memcmp(RA_TLS_LONG_NAME, ln, sizeof(RA_TLS_LONG_NAME)) == 0) { | ||||
|             BIO *ext_bio = BIO_new(BIO_s_mem()); | ||||
| 
 | ||||
|             *len = i2d_ASN1_OCTET_STRING(ext->value, quote); | ||||
|             *quote = *quote + 4; | ||||
|             *len = *len - 4; | ||||
|             ret = 0; | ||||
|             BIO_free(ext_bio); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     return ret; | ||||
| } | ||||
| 
 | ||||
| static int occlum_verify_pubkey_hash(X509 *x509, uint8_t *pubkey_hash, size_t len) { | ||||
|     EVP_PKEY *pkey = X509_get_pubkey(x509); | ||||
| 
 | ||||
|     int32_t ret; | ||||
|     size_t key_len = EVP_PKEY_bits(pkey)/8; | ||||
|     unsigned char *public_key = NULL; | ||||
| 
 | ||||
|     key_len = i2d_X509_PUBKEY(X509_get_X509_PUBKEY(x509), &public_key); | ||||
| 
 | ||||
|     unsigned char hash[SHA256_DIGEST_LENGTH]; | ||||
|     SHA256_CTX sha256; | ||||
|     SHA256_Init(&sha256); | ||||
|     SHA256_Update(&sha256, public_key, key_len); | ||||
|     SHA256_Final(hash, &sha256); | ||||
| 
 | ||||
|     ret = memcmp(hash, pubkey_hash, len); | ||||
|     return ret; | ||||
| } | ||||
| 
 | ||||
| static int occlum_verify_quote(uint8_t * quote_buffer, size_t quote_size) { | ||||
|     void *handle; | ||||
|     handle = dcap_quote_open(); | ||||
| 
 | ||||
|     uint32_t supplemental_size, ret; | ||||
|     uint8_t *p_supplemental_buffer; | ||||
|     sgx_ql_qv_result_t quote_verification_result = SGX_QL_QV_RESULT_UNSPECIFIED; | ||||
|     uint32_t collateral_expiration_status = 1; | ||||
| 
 | ||||
|     supplemental_size = dcap_get_supplemental_data_size(handle); | ||||
|     p_supplemental_buffer = (uint8_t *)malloc(supplemental_size); | ||||
|     if (NULL == p_supplemental_buffer) { | ||||
|         grpc_printf("Couldn't allocate supplemental buffer\n"); | ||||
|     } | ||||
|     memset(p_supplemental_buffer, 0, supplemental_size); | ||||
| 
 | ||||
|     ret = dcap_verify_quote( | ||||
|         handle, | ||||
|         quote_buffer, | ||||
|         quote_size, | ||||
|         &collateral_expiration_status, | ||||
|         "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
 | ||||
| @ -1,55 +0,0 @@ | ||||
| /*
 | ||||
|  * | ||||
|  * Copyright (c) 2022 Intel Corporation | ||||
|  * | ||||
|  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|  * you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * | ||||
|  *     http://www.apache.org/licenses/LICENSE-2.0
 | ||||
|  * | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an "AS IS" BASIS, | ||||
|  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|  * See the License for the specific language governing permissions and | ||||
|  * limitations under the License. | ||||
|  * | ||||
|  */ | ||||
| 
 | ||||
| #include <grpc/grpc_security.h> | ||||
| #include <grpc/support/alloc.h> | ||||
| #include <grpcpp/security/sgx/sgx_ra_tls_options.h> | ||||
| 
 | ||||
| #include "absl/container/inlined_vector.h" | ||||
| #include "src/cpp/common/tls_credentials_options_util.h" | ||||
| 
 | ||||
| namespace grpc { | ||||
| namespace sgx { | ||||
| 
 | ||||
| void CredentialsOptions::set_verification_option( | ||||
|     grpc_tls_server_verification_option server_verification_option) { | ||||
|     grpc_tls_credentials_options* options = c_credentials_options(); | ||||
|     GPR_ASSERT(options != nullptr); | ||||
|     grpc_tls_credentials_options_set_server_verification_option( | ||||
|         options, server_verification_option); | ||||
| } | ||||
| 
 | ||||
| void CredentialsOptions::set_authorization_check_config( | ||||
|     std::shared_ptr<grpc::experimental::TlsServerAuthorizationCheckConfig> config) { | ||||
|     grpc_tls_credentials_options* options = c_credentials_options(); | ||||
|     GPR_ASSERT(options != nullptr); | ||||
|     if (config != nullptr) { | ||||
|         grpc_tls_credentials_options_set_server_authorization_check_config( | ||||
|             options, config->c_config()); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void CredentialsOptions::set_cert_request_type( | ||||
|     grpc_ssl_client_certificate_request_type cert_request_type) { | ||||
|     grpc_tls_credentials_options* options = c_credentials_options(); | ||||
|     GPR_ASSERT(options != nullptr); | ||||
|     grpc_tls_credentials_options_set_cert_request_type(options, cert_request_type); | ||||
| } | ||||
| 
 | ||||
| } // namespace sgx
 | ||||
| } // namespace grpc
 | ||||
| @ -1,169 +0,0 @@ | ||||
| /*
 | ||||
|  * | ||||
|  * Copyright (c) 2022 Intel Corporation | ||||
|  * | ||||
|  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|  * you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * | ||||
|  *     http://www.apache.org/licenses/LICENSE-2.0
 | ||||
|  * | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an "AS IS" BASIS, | ||||
|  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|  * See the License for the specific language governing permissions and | ||||
|  * limitations under the License. | ||||
|  * | ||||
|  */ | ||||
| 
 | ||||
| #include "sgx_ra_tls_utils.h" | ||||
| 
 | ||||
| #include <cstring> | ||||
| #include <iostream> | ||||
| #include <fstream> | ||||
| #include <sstream> | ||||
| 
 | ||||
| namespace grpc { | ||||
| namespace sgx { | ||||
| 
 | ||||
| void check_free(void* ptr) { | ||||
|     if (ptr) { | ||||
|         free(ptr); | ||||
|         ptr = nullptr; | ||||
|     }; | ||||
| } | ||||
| 
 | ||||
| bool hex_to_byte(const char *src, char *dst, size_t dst_size) { | ||||
|     if (std::strlen(src) < dst_size*2) { | ||||
|         return false; | ||||
|     } else { | ||||
|         for (auto i = 0; i < dst_size; i++) { | ||||
|             if (!isxdigit(src[i*2]) || !isxdigit(src[i*2+1])) { | ||||
|                 return false; | ||||
|             } else { | ||||
|                 sscanf(src+i*2, "%02hhx", dst+i); | ||||
|             } | ||||
|         } | ||||
|         return true; | ||||
|     } | ||||
| }; | ||||
| 
 | ||||
| void byte_to_hex(const char *src, char *dst, size_t src_size) { | ||||
|     for (auto i = 0; i < src_size; i++) { | ||||
|         sprintf(dst+i*2, "%02hhx", src[i]); | ||||
|     } | ||||
| }; | ||||
| 
 | ||||
| std::string byte_to_hex(const char *src, size_t src_size) { | ||||
|     char dst[src_size*2]; | ||||
|     memset(dst, 0, sizeof(dst)); | ||||
|     byte_to_hex(src, dst, src_size); | ||||
|     return std::string(dst); | ||||
| }; | ||||
| 
 | ||||
| library_engine::library_engine() : handle(nullptr), error(nullptr) {}; | ||||
| 
 | ||||
| library_engine::library_engine(const char* file, int mode) : handle(nullptr), error(nullptr) { | ||||
|     this->open(file, mode); | ||||
| } | ||||
| 
 | ||||
| library_engine::~library_engine() { | ||||
|     this->close(); | ||||
| } | ||||
| 
 | ||||
| void library_engine::open(const char* file, int mode) { | ||||
|     this->close(); | ||||
|     handle = dlopen(file, mode); | ||||
|     error = dlerror(); | ||||
|     if (error != nullptr || handle == nullptr) { | ||||
|         throw std::runtime_error("dlopen " + std::string(file) + " error, " + std::string(error)); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void library_engine::close() { | ||||
|     if (handle) { | ||||
|         dlclose(handle); | ||||
|     } | ||||
|     handle = nullptr; | ||||
|     error = nullptr; | ||||
| } | ||||
| 
 | ||||
| void* library_engine::get_func(const char* name) { | ||||
|   auto func = dlsym(handle, name); | ||||
|   error = dlerror(); | ||||
|   if (error != nullptr || func == nullptr) { | ||||
|     throw std::runtime_error("dlsym " + std::string(name) + " error, " + std::string(error)); | ||||
|     return nullptr; | ||||
|   } else { | ||||
|     return func; | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| void* library_engine::get_handle() { | ||||
|     return handle; | ||||
| } | ||||
| 
 | ||||
| json_engine::json_engine() : handle(nullptr) {}; | ||||
| 
 | ||||
| json_engine::json_engine(const char* file) : handle(nullptr){ | ||||
|     this->open(file); | ||||
| } | ||||
| 
 | ||||
| json_engine::~json_engine() { | ||||
|     this->close(); | ||||
| } | ||||
| 
 | ||||
| bool json_engine::open(const char* file) { | ||||
|     if (!file) { | ||||
|         grpc_printf("wrong json file path\n"); | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|     this->close(); | ||||
| 
 | ||||
|     auto file_ptr = fopen(file, "r"); | ||||
|     fseek(file_ptr, 0, SEEK_END); | ||||
|     auto length = ftell(file_ptr); | ||||
|     fseek(file_ptr, 0, SEEK_SET); | ||||
|     auto buffer = malloc(length); | ||||
|     fread(buffer, 1, length, file_ptr); | ||||
|     fclose(file_ptr); | ||||
| 
 | ||||
|     this->handle = cJSON_Parse((const char *)buffer); | ||||
| 
 | ||||
|     check_free(buffer); | ||||
| 
 | ||||
|     if (this->handle) { | ||||
|         return true; | ||||
|     } else { | ||||
|         grpc_printf("cjson open %s error: %s", file, cJSON_GetErrorPtr()); | ||||
|         return false; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void json_engine::close() { | ||||
|     if (this->handle) { | ||||
|         cJSON_Delete(this->handle); | ||||
|         this->handle = nullptr; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| cJSON* json_engine::get_handle() { | ||||
|     return this->handle; | ||||
| } | ||||
| 
 | ||||
| cJSON* json_engine::get_item(cJSON* obj, const char* item) { | ||||
|     return cJSON_GetObjectItem(obj, item); | ||||
| }; | ||||
| 
 | ||||
| char* json_engine::print_item(cJSON* obj) { | ||||
|     return cJSON_Print(obj); | ||||
| }; | ||||
| 
 | ||||
| bool json_engine::compare_item(cJSON* obj, const char* item) { | ||||
|     auto obj_item = this->print_item(obj); | ||||
|     return strncmp(obj_item+1, item, std::min(strlen(item), strlen(obj_item)-2)) == 0; | ||||
| }; | ||||
| 
 | ||||
| } // namespace sgx
 | ||||
| } // namespace grpc
 | ||||
| @ -1,68 +0,0 @@ | ||||
| /*
 | ||||
|  * | ||||
|  * Copyright (c) 2022 Intel Corporation | ||||
|  * | ||||
|  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|  * you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * | ||||
|  *     http://www.apache.org/licenses/LICENSE-2.0
 | ||||
|  * | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an "AS IS" BASIS, | ||||
|  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|  * See the License for the specific language governing permissions and | ||||
|  * limitations under the License. | ||||
|  * | ||||
|  */ | ||||
| 
 | ||||
| #ifndef SGX_RA_TLS_UTILS_H | ||||
| #define SGX_RA_TLS_UTILS_H | ||||
| 
 | ||||
| #include <string> | ||||
| #include <vector> | ||||
| #include <memory> | ||||
| #include <dlfcn.h> | ||||
| 
 | ||||
| #define grpc_printf printf | ||||
| #define grpc_fprintf fprintf | ||||
| 
 | ||||
| #include <grpcpp/security/sgx/sgx_ra_tls.h> | ||||
| 
 | ||||
| namespace grpc { | ||||
| namespace sgx { | ||||
| 
 | ||||
| 
 | ||||
| class library_engine { | ||||
|     public: | ||||
|         library_engine(); | ||||
| 
 | ||||
|         library_engine(const char*, int); | ||||
| 
 | ||||
|         ~library_engine(); | ||||
| 
 | ||||
|         void open(const char*, int); | ||||
| 
 | ||||
|         void close(); | ||||
| 
 | ||||
|         void* get_func(const char*); | ||||
| 
 | ||||
|         void* get_handle(); | ||||
| 
 | ||||
|     private: | ||||
|         void* handle; | ||||
|         char* error; | ||||
| }; | ||||
| 
 | ||||
| void check_free(void* ptr); | ||||
| 
 | ||||
| bool hex_to_byte(const char* src, char* dst, size_t dst_size); | ||||
| 
 | ||||
| void byte_to_hex(const char* src, char* dst, size_t src_size); | ||||
| 
 | ||||
| std::string byte_to_hex(const char* src, size_t src_size); | ||||
| 
 | ||||
| } // namespace sgx
 | ||||
| } // namespace grpc
 | ||||
| 
 | ||||
| #endif // SGX_RA_TLS_UTILS_H
 | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user