Enable the grpc ra-tls demo
Signed-off-by: yuanwu <yuan.wu@intel.com>
This commit is contained in:
		
							parent
							
								
									b62b5e23eb
								
							
						
					
					
						commit
						2810b8e4ce
					
				
							
								
								
									
										48
									
								
								.github/workflows/hw_mode_test.yml
									
									
									
									
										vendored
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										48
									
								
								.github/workflows/hw_mode_test.yml
									
									
									
									
										vendored
									
									
								
							| @ -835,6 +835,54 @@ jobs: | ||||
|       if: ${{ always() }} | ||||
|       run: docker stop ${{ env.CONTAINER_NAME }} | ||||
| 
 | ||||
|   RA_TLS_test: | ||||
|     if: github.event_name == 'push' || ${{ contains(github.event.pull_request.labels.*.name, 'SGX-hardware-test-required') }} | ||||
|     runs-on: ${{ matrix.self_runner }} | ||||
|     strategy: | ||||
|       matrix: | ||||
|         self_runner: [[self-hosted, SGX2-HW]] | ||||
| 
 | ||||
|     steps: | ||||
|     - name: Clean before running | ||||
|       run: | | ||||
|         sudo chown -R ${{ secrets.CI_ADMIN }} "${{ github.workspace }}" | ||||
| 
 | ||||
|     - name: Checkout code | ||||
|       if: github.event_name == 'push' | ||||
|       uses: actions/checkout@v2 | ||||
|       with: | ||||
|         submodules: true | ||||
| 
 | ||||
|     - name: Checkout code from fork | ||||
|       if: ${{ contains(github.event.pull_request.labels.*.name, 'SGX-hardware-test-required') }} | ||||
|       uses: actions/checkout@v2 | ||||
|       with: | ||||
|         ref: refs/pull/${{ github.event.pull_request.number }}/merge | ||||
|         submodules: true | ||||
| 
 | ||||
|     - uses: ./.github/workflows/composite_action/hw | ||||
|       with: | ||||
|         container-name: ${{ github.job }} | ||||
|         build-envs: 'OCCLUM_RELEASE_BUILD=1' | ||||
| 
 | ||||
|     - name: Download and build the pakckages | ||||
|       run: docker exec ${{ env.CONTAINER_NAME }} bash -c "cd /root/occlum/demos/ra_tls; ./prepare_and_build_package.sh" | ||||
|      | ||||
|     - name: Build occlum instances | ||||
|       run: docker exec ${{ env.CONTAINER_NAME }} bash -c "cd /root/occlum/demos/ra_tls; ./build_occlum_instance.sh" | ||||
| 
 | ||||
|     - name: Run gRPC server | ||||
|       run: docker exec ${{ env.CONTAINER_NAME }} bash -c "cd /root/occlum/demos/ra_tls; ./run.sh server &" | ||||
|      | ||||
|     - name: Run gRPC client | ||||
|       run: | | ||||
|         sleep ${{ env.nap_time }}; | ||||
|         docker exec ${{ env.CONTAINER_NAME }} bash -c "cd /root/occlum/demos/ra_tls; ./run.sh client" | ||||
|   | ||||
|     - name: Clean the environment | ||||
|       if: ${{ always() }} | ||||
|       run: docker stop ${{ env.CONTAINER_NAME }} | ||||
| 
 | ||||
|   Stress_test_with_musl: | ||||
|     if: github.event_name == 'schedule' | ||||
|     runs-on: ${{ matrix.self_runner }} | ||||
|  | ||||
							
								
								
									
										25
									
								
								demos/ra_tls/README.md
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										25
									
								
								demos/ra_tls/README.md
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,25 @@ | ||||
| # gRPC Package With RA-TLS | ||||
| 
 | ||||
| 
 | ||||
| #### Executing the demo in Occlum | ||||
| 
 | ||||
| The following command will download the gRPC source code and apply the ra-tls patches, then build gRPC source code and demo. | ||||
| ``` | ||||
| ./prepare_and_build_package.sh  | ||||
| ``` | ||||
| 
 | ||||
| The following command will generate the client and server occlum images. It automatically parses the mr_enclave and mr_signer of the client, and write the value into dynamic_config.json. If you want to verify the other measurements of client, please modify the dynamic_config.json before run the script. | ||||
| ``` | ||||
| ./build_occlum_instance.sh | ||||
| ``` | ||||
| 
 | ||||
| Run the gRPC server & client in occlum. | ||||
| 
 | ||||
| ``` | ||||
| ./run.sh server & | ||||
| ./run.sh client | ||||
| ``` | ||||
| 
 | ||||
| ***Note:*** 1. The demo runs in the same machine by default. If you want to run server and client in different machines. Please modify the examples/cpp/ratls. | ||||
|             2. If you want to test in your local network with your own PCCS server, you need to modify the /etc/sgx_default_qcnl.conf | ||||
| 
 | ||||
							
								
								
									
										55
									
								
								demos/ra_tls/build_occlum_instance.sh
									
									
									
									
									
										Executable file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										55
									
								
								demos/ra_tls/build_occlum_instance.sh
									
									
									
									
									
										Executable file
									
								
							| @ -0,0 +1,55 @@ | ||||
| #!/bin/bash | ||||
| occlum_glibc=/opt/occlum/glibc/lib/ | ||||
| set -ex | ||||
| 
 | ||||
| get_mr() { | ||||
|     sgx_sign dump -enclave ../occlum_instance_$1/build/lib/libocclum-libos.signed.so -dumpfile ../metadata_info_$1.txt | ||||
|     if [ "$2" == "mr_enclave" ]; then | ||||
|         sed -n -e '/enclave_hash.m/,/metadata->enclave_css.body.isv_prod_id/p' ../metadata_info_$1.txt |head -3|tail -2|xargs|sed 's/0x//g'|sed 's/ //g' | ||||
|     elif [ "$2" == "mr_signer" ]; then | ||||
|         tail -2 ../metadata_info_$1.txt |xargs|sed 's/0x//g'|sed 's/ //g' | ||||
|     fi | ||||
| } | ||||
| 
 | ||||
| build_instance() { | ||||
|     # 1. Init Occlum Workspace | ||||
|     rm -rf occlum_instance_$postfix | ||||
|     mkdir occlum_instance_$postfix | ||||
|     pushd occlum_instance_$postfix | ||||
|     occlum init | ||||
|     new_json="$(jq '.resource_limits.user_space_size = "320MB" | | ||||
|                     .process.default_mmap_size = "256MB"' Occlum.json)" && \ | ||||
|     echo "${new_json}" > Occlum.json | ||||
|     # 2. Copy files into Occlum Workspace and Build | ||||
|     #cp ../dynamic_config.json image/etc/dynamic_config.json | ||||
|     cp ../dynamic_config.json image/dynamic_config.json | ||||
|     #cp ../dynamic_config_$postfix.json image/dynamic_config.json | ||||
|     if [ "$postfix" == "server" ]; then | ||||
|         jq ' .verify_mr_enclave = "on" | | ||||
|              .verify_mr_signer = "on" | | ||||
| 	     .sgx_mrs[0].mr_enclave = ''"'`get_mr client mr_enclave`'" | | ||||
| 	     .sgx_mrs[0].mr_signer = ''"'`get_mr client mr_signer`'" ' ../dynamic_config.json > image/dynamic_config.json  | ||||
|     fi | ||||
|     mkdir -p image/usr/share/grpc | ||||
|     cp -rf /share/grpc/*  image/usr/share/grpc/ | ||||
|     cp $occlum_glibc/libdl.so.2 image/$occlum_glibc | ||||
|     cp $occlum_glibc/librt.so.1 image/$occlum_glibc | ||||
|     cp $occlum_glibc/libm.so.6 image/$occlum_glibc | ||||
|     cp /lib/x86_64-linux-gnu/libtinfo.so.5 image/$occlum_glibc | ||||
|     cp /lib/x86_64-linux-gnu/libnss*.so.2 image/$occlum_glibc | ||||
|     cp /lib/x86_64-linux-gnu/libresolv.so.2 image/$occlum_glibc | ||||
|     cp -rf /etc/hostname image/etc/ | ||||
|     cp -rf /etc/ssl image/etc/ | ||||
|     cp -rf /etc/passwd image/etc/ | ||||
|     cp -rf /etc/group image/etc/ | ||||
|     cp -rf /etc/nsswitch.conf image/etc/ | ||||
|     cp -rf /grpc/examples/cpp/ratls/build/* image/bin/ | ||||
|     occlum build | ||||
|     popd | ||||
| } | ||||
| 
 | ||||
| postfix=client | ||||
| build_instance | ||||
| postfix=server | ||||
| build_instance | ||||
| 
 | ||||
							
								
								
									
										15
									
								
								demos/ra_tls/dynamic_config.json
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										15
									
								
								demos/ra_tls/dynamic_config.json
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,15 @@ | ||||
| { | ||||
|     "verify_mr_enclave" : "off", | ||||
|     "verify_mr_signer" : "off", | ||||
|     "verify_isv_prod_id" : "off", | ||||
|     "verify_isv_svn" : "off", | ||||
|     "sgx_mrs": [ | ||||
|         { | ||||
|             "mr_enclave" : "", | ||||
|             "mr_signer" : "", | ||||
|             "isv_prod_id" : "0", | ||||
|             "isv_svn" : "0" | ||||
|         } | ||||
|     ], | ||||
|     "other" : [] | ||||
| } | ||||
							
								
								
									
										1
									
								
								demos/ra_tls/grpc/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										1
									
								
								demos/ra_tls/grpc/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1 @@ | ||||
| grpc-* | ||||
							
								
								
									
										46
									
								
								demos/ra_tls/grpc/common/build_cpp.sh
									
									
									
									
									
										Executable file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										46
									
								
								demos/ra_tls/grpc/common/build_cpp.sh
									
									
									
									
									
										Executable file
									
								
							| @ -0,0 +1,46 @@ | ||||
| # | ||||
| # 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 ABSEIL_PATH=${GRPC_PATH}/third_party/abseil-cpp | ||||
| 
 | ||||
| if [ ! -d "${BUILD_TYPE}" ]; then | ||||
|     BUILD_TYPE=Release | ||||
| fi | ||||
| 
 | ||||
| # build and install abseil library | ||||
| # https://abseil.io/docs/cpp/quickstart-cmake.html | ||||
| if [ ! -d "${ABSEIL_PATH}/build" ]; then | ||||
|     mkdir -p ${ABSEIL_PATH}/build | ||||
|     cd ${ABSEIL_PATH}/build | ||||
|     cmake -DCMAKE_CXX_STANDARD=11 -DCMAKE_POSITION_INDEPENDENT_CODE=TRUE \ | ||||
|           -DCMAKE_BUILD_TYPE=${BUILD_TYPE} -DCMAKE_INSTALL_PREFIX=${INSTALL_PREFIX} .. | ||||
|     make -j `nproc` | ||||
|     make install | ||||
|     cd - | ||||
| fi | ||||
| 
 | ||||
| # build and install grpc library | ||||
| mkdir -p ${GRPC_PATH}/build | ||||
| cd ${GRPC_PATH}/build | ||||
| cmake -DgRPC_INSTALL=ON -DgRPC_ABSL_PROVIDER=package -DgRPC_BUILD_TESTS=OFF \ | ||||
|       -DgRPC_BUILD_CSHARP_EXT=OFF -DgRPC_BUILD_GRPC_CSHARP_PLUGIN=OFF \ | ||||
|       -DgRPC_BUILD_GRPC_PHP_PLUGIN=OFF -DgRPC_BUILD_GRPC_RUBY_PLUGIN=OFF \ | ||||
|       -DDEFINE_SGX_RA_TLS_OCCLUM_BACKEND=ON \ | ||||
|       -DCMAKE_BUILD_TYPE=${BUILD_TYPE} -DCMAKE_INSTALL_PREFIX=${INSTALL_PREFIX} .. | ||||
| make -j `nproc` | ||||
| make install | ||||
| cd - | ||||
							
								
								
									
										15754
									
								
								demos/ra_tls/grpc/v1.38.1/CMakeLists.txt
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										15754
									
								
								demos/ra_tls/grpc/v1.38.1/CMakeLists.txt
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										62
									
								
								demos/ra_tls/grpc/v1.38.1/examples/cpp/ratls/CMakeLists.txt
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										62
									
								
								demos/ra_tls/grpc/v1.38.1/examples/cpp/ratls/CMakeLists.txt
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,62 @@ | ||||
| # 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 | ||||
|   ${hw_grpc_srcs} | ||||
|   ${hw_grpc_hdrs} | ||||
|   ${hw_proto_srcs} | ||||
|   ${hw_proto_hdrs}) | ||||
| target_link_libraries(hw_grpc_proto | ||||
|   ${_REFLECTION} | ||||
|   ${_GRPC_GRPCPP} | ||||
|   ${_PROTOBUF_LIBPROTOBUF}) | ||||
| 
 | ||||
| # Targets greeter_[async_](client|server) | ||||
| foreach(_target client server) | ||||
|   add_executable(${_target} "${_target}.cc") | ||||
|   target_link_libraries(${_target} | ||||
|     hw_grpc_proto | ||||
|     ${_REFLECTION} | ||||
|     ${_GRPC_GRPCPP} | ||||
|     ${_PROTOBUF_LIBPROTOBUF}) | ||||
| endforeach() | ||||
							
								
								
									
										15
									
								
								demos/ra_tls/grpc/v1.38.1/examples/cpp/ratls/README.md
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										15
									
								
								demos/ra_tls/grpc/v1.38.1/examples/cpp/ratls/README.md
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,15 @@ | ||||
| # gRPC | ||||
| 
 | ||||
| This directory contains the Makefile and the template manifest for the most | ||||
| recent version of gRPC (as of this writing, version 3.18.0). This was tested | ||||
| on a machine with SGX v1 and Ubuntu 18.04. | ||||
| 
 | ||||
| The Makefile and the template manifest contain extensive comments and are made | ||||
| self-explanatory. Please review them to gain understanding of Gramine-SGX | ||||
| and requirements for applications running under Gramine-SGX. | ||||
| 
 | ||||
| # Quick Start | ||||
| 
 | ||||
| ``` | ||||
| ./build.sh | ||||
| ``` | ||||
							
								
								
									
										29
									
								
								demos/ra_tls/grpc/v1.38.1/examples/cpp/ratls/build.sh
									
									
									
									
									
										Executable file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										29
									
								
								demos/ra_tls/grpc/v1.38.1/examples/cpp/ratls/build.sh
									
									
									
									
									
										Executable file
									
								
							| @ -0,0 +1,29 @@ | ||||
| # | ||||
| # 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` | ||||
| 
 | ||||
| ${GRPC_PATH}/build_cpp.sh | ||||
| 
 | ||||
| # 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 - | ||||
							
								
								
									
										86
									
								
								demos/ra_tls/grpc/v1.38.1/examples/cpp/ratls/client.cc
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										86
									
								
								demos/ra_tls/grpc/v1.38.1/examples/cpp/ratls/client.cc
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,86 @@ | ||||
| /*
 | ||||
|  * | ||||
|  * 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> | ||||
| 
 | ||||
| #ifdef BAZEL_BUILD | ||||
| #include "examples/protos/ratls.grpc.pb.h" | ||||
| #else | ||||
| #include "ratls.grpc.pb.h" | ||||
| #endif | ||||
| 
 | ||||
| #include "../getopt.hpp" | ||||
| 
 | ||||
| using ratls::Greeter; | ||||
| using ratls::HelloReply; | ||||
| using ratls::HelloRequest; | ||||
| 
 | ||||
| struct argparser { | ||||
|     const char* config; | ||||
|     std::string server_address; | ||||
|     argparser() { | ||||
|         server_address = getarg("localhost:50051", "-host", "--host"); | ||||
|         config = getarg("dynamic_config.json", "-cfg", "--config"); | ||||
|     }; | ||||
| }; | ||||
| 
 | ||||
| class GreeterClient { | ||||
|     public: | ||||
|         GreeterClient(std::shared_ptr<grpc::Channel> channel) : stub_(Greeter::NewStub(channel)) {} | ||||
| 
 | ||||
|         std::string SayHello(const std::string& user) { | ||||
|             HelloRequest request; | ||||
|             request.set_name(user); | ||||
| 
 | ||||
|             HelloReply reply; | ||||
| 
 | ||||
|             grpc::ClientContext context; | ||||
| 
 | ||||
|             grpc::Status status = stub_->SayHello(&context, request, &reply); | ||||
| 
 | ||||
|             if (status.ok()) { | ||||
|                 return reply.message(); | ||||
|             } else { | ||||
|                 std::cout << status.error_code() << ": " << status.error_message() << std::endl; | ||||
|                 return "RPC failed"; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|     private: | ||||
|         std::unique_ptr<Greeter::Stub> stub_; | ||||
| }; | ||||
| 
 | ||||
| void run_client() { | ||||
|     argparser args; | ||||
| 
 | ||||
|     auto cred = grpc::sgx::TlsCredentials(args.config); | ||||
|     auto channel = grpc::CreateChannel(args.server_address, cred); | ||||
| 
 | ||||
|     GreeterClient greeter(channel); | ||||
| 
 | ||||
|     std::string user_a = greeter.SayHello("a"); | ||||
|     std::string user_b = greeter.SayHello("b"); | ||||
| 
 | ||||
|     std::cout << "Greeter received: " << user_a << ", "<< user_b << std::endl; | ||||
| }; | ||||
| 
 | ||||
| int main(int argc, char** argv) { | ||||
|     run_client(); | ||||
|     return 0; | ||||
| } | ||||
							
								
								
									
										316
									
								
								demos/ra_tls/grpc/v1.38.1/examples/cpp/ratls/getopt.hpp
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										316
									
								
								demos/ra_tls/grpc/v1.38.1/examples/cpp/ratls/getopt.hpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,316 @@ | ||||
| // Simple getopt replacement class (C++11). 
 | ||||
| // - rlyeh, zlib/libpng licensed.
 | ||||
| // https://github.com/r-lyeh-archived/getopt/blob/master/getopt.hpp
 | ||||
| 
 | ||||
| // Two APIs provided:
 | ||||
| //
 | ||||
| // 1) Simple functional api `getarg(...)`. 
 | ||||
| //    - No initialization required: (argc, argv) pair automatically retrieved.
 | ||||
| //    - First argument is default option value, then all option indentifiers follow.
 | ||||
| //
 | ||||
| // int main() {
 | ||||
| //     bool help = getarg( false, "-h", "--help", "-?" );
 | ||||
| //     int version = getarg( 0, "-v", "--version", "--show-version" );
 | ||||
| //     int depth = getarg( 1, "-d", "--depth", "--max-depth");
 | ||||
| //     std::string file = getarg( "", "-f", "--file" );
 | ||||
| //     [...]
 | ||||
| // }
 | ||||
| //
 | ||||
| // 2) Simple OOP map-based api `getopt class`. Initialization (argc, argv) pair required.
 | ||||
| //
 | ||||
| //    This getopt class is a std::map replacement where key/value are std::string types.
 | ||||
| //    Given invokation './app.out --user=me --pass=123 -h' this class delivers not only:
 | ||||
| //    map[0] = "./app.out", map[1] = "--user=me", map[2]="--pass=123", map[3]='-h'
 | ||||
| //    but also, map["--user"]="me", map["--pass"]="123" and also, map["-h"]=true
 | ||||
| //
 | ||||
| //    Additional API:
 | ||||
| //    - .cmdline() for a print app invokation string
 | ||||
| //    - .str() for pretty map printing
 | ||||
| //    - .size() number of arguments (equivalent to argc), rather than std::map.size()
 | ||||
| //
 | ||||
| // int main( int argc, const char **argv ) {
 | ||||
| //     getopt args( argc, argv );
 | ||||
| //     if( args.has("-h") || args.has("--help") || args.has("-?") || args.size() == 1 ) {
 | ||||
| //         std::cout << args["0"] << " [-?|-h|--help] [-v|--version] [--depth=number]" << std::endl;
 | ||||
| //         return 0;
 | ||||
| //     }
 | ||||
| //     if( args.has("-v") || args.has("--version") ) {
 | ||||
| //         std::cout << args["0"] << " sample v1.0.0. Compiled on " << __DATE__ << std::endl;
 | ||||
| //     }
 | ||||
| //     if( args.has("--depth") ) {
 | ||||
| //         int depth = atoi( args["--depth"].c_str() );
 | ||||
| //         std::cout << "depth set to " << depth << std::endl;
 | ||||
| //     }
 | ||||
| //     [...]
 | ||||
| // }
 | ||||
| 
 | ||||
| #pragma once | ||||
| #include <map> | ||||
| #include <string> | ||||
| #include <sstream> | ||||
| #include <vector> | ||||
| 
 | ||||
| #ifdef _WIN32 | ||||
| #include <io.h> | ||||
| #include <winsock2.h> | ||||
| #include <shellapi.h> | ||||
| #pragma comment(lib, "Shell32.lib") | ||||
| #else | ||||
| #include <fstream> | ||||
| #include <unistd.h> | ||||
| #include <stdio.h> | ||||
| #include <stdlib.h> | ||||
| #include <sstream> | ||||
| #endif | ||||
| 
 | ||||
| #define GETOPT_VERSION "1.0.0" // (2016/04/18) Initial version
 | ||||
| 
 | ||||
| namespace getopt_utils | ||||
| { | ||||
|     // string conversion
 | ||||
| 
 | ||||
|     template< typename T > | ||||
|     inline T as( const std::string &self ) { | ||||
|         T t; | ||||
|         return (std::istringstream(self) >> t) ? t : | ||||
|                (T)(self.size() && (self != "0") && (self != "false")); | ||||
|     } | ||||
| 
 | ||||
|     template<> | ||||
|     inline char as( const std::string &self ) { | ||||
|         return self.size() == 1 ? (char)(self[0]) : (char)(as<int>(self)); | ||||
|     } | ||||
|     template<> | ||||
|     inline signed char as( const std::string &self ) { | ||||
|         return self.size() == 1 ? (signed char)(self[0]) : (signed char)(as<int>(self)); | ||||
|     } | ||||
|     template<> | ||||
|     inline unsigned char as( const std::string &self ) { | ||||
|         return self.size() == 1 ? (unsigned char)(self[0]) : (unsigned char)(as<int>(self)); | ||||
|     } | ||||
| 
 | ||||
|     template<> | ||||
|     inline const char *as( const std::string &self ) { | ||||
|         return self.c_str(); | ||||
|     } | ||||
|     template<> | ||||
|     inline std::string as( const std::string &self ) { | ||||
|         return self; | ||||
|     } | ||||
| 
 | ||||
|     // token split
 | ||||
| 
 | ||||
|     inline size_t split( std::vector<std::string> &tokens, const std::string &self, const std::string &delimiters ) { | ||||
|         std::string str; | ||||
|         tokens.clear(); | ||||
|         for( auto &ch : self ) { | ||||
|             if( delimiters.find_first_of( ch ) != std::string::npos ) { | ||||
|                 if( str.size() ) tokens.push_back( str ), str = ""; | ||||
|                 tokens.push_back( std::string() + ch ); | ||||
|             } else str += ch; | ||||
|         } | ||||
|         return str.empty() ? tokens.size() : ( tokens.push_back( str ), tokens.size() ); | ||||
|     }; | ||||
| 
 | ||||
|     // portable cmdline 
 | ||||
| 
 | ||||
|     inline std::vector<std::string> cmdline() { | ||||
|         std::vector<std::string> args; | ||||
|         std::string arg; | ||||
|     #       ifdef _WIN32 | ||||
|             int argv; | ||||
|             auto *list = CommandLineToArgvW( GetCommandLineW(), &argv ); | ||||
|             if( list ) { | ||||
|                 for( int i = 0; i < argv; ++i ) { | ||||
|                     std::wstring ws( list[i] ); | ||||
|                     args.push_back( std::string( ws.begin(), ws.end() ) ); | ||||
|                 } | ||||
|                 LocalFree(list); | ||||
|             } | ||||
|     #       else | ||||
|             pid_t pid = getpid(); | ||||
| 
 | ||||
|             char fname[32] = {}; | ||||
|             sprintf(fname, "/proc/%d/cmdline", pid); | ||||
|             std::ifstream ifs(fname); | ||||
|             if( ifs.good() ) { | ||||
|                 std::stringstream ss; | ||||
|                 ifs >> ss.rdbuf(); | ||||
|                 arg = ss.str(); | ||||
|             } | ||||
|             for( auto end = arg.size(), i = end - end; i < end; ++i ) { | ||||
|                 auto st = i; | ||||
|                 while (i < arg.size() && arg[i] != '\0') ++i; | ||||
|                 args.push_back( arg.substr(st, i - st) ); | ||||
|             } | ||||
|     #       endif | ||||
|         return args; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| // main map class; explicit initialization
 | ||||
| 
 | ||||
| struct getopt : public std::map< std::string, std::string > | ||||
| { | ||||
|     using super = std::map< std::string, std::string >; | ||||
| 
 | ||||
|     getopt( int argc, const char **argv ) : super() { | ||||
|         // reconstruct vector
 | ||||
|         std::vector<std::string> args( argc, std::string() ); | ||||
|         for( int i = 0; i < argc; ++i ) { | ||||
|             args[ i ] = argv[ i ]; | ||||
|         } | ||||
|         // create key=value and key= args as well
 | ||||
|         for( auto &it : args ) { | ||||
|             std::vector<std::string> tokens; | ||||
|             auto size = getopt_utils::split( tokens, it, "=" ); | ||||
| 
 | ||||
|             if( size == 3 && tokens[1] == "=" ) | ||||
|                 (*this)[ tokens[0] ] = tokens[2]; | ||||
|             else | ||||
|             if( size == 2 && tokens[1] == "=" ) | ||||
|                 (*this)[ tokens[0] ] = true; | ||||
|             else | ||||
|             if( size == 1 && tokens[0] != argv[0] ) | ||||
|                 (*this)[ tokens[0] ] = true; | ||||
|         } | ||||
|         // recreate args
 | ||||
|         while( argc-- ) { | ||||
|             (*this)[ std::to_string(argc) ] = std::string( argv[argc] ); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     getopt( const std::vector<std::string> &args ) : super() { | ||||
|         std::vector<const char *> argv; | ||||
|         for( auto &it : args ) { | ||||
|             argv.push_back( it.c_str() ); | ||||
|         } | ||||
|         *this = getopt( argv.size(), argv.data() ); | ||||
|     } | ||||
| 
 | ||||
|     size_t size() const { | ||||
|         unsigned i = 0; | ||||
|         while( has(std::to_string(i)) ) ++i; | ||||
|         return i; | ||||
|     } | ||||
| 
 | ||||
|     bool has( const std::string &op ) const { | ||||
|         return this->find(op) != this->end(); | ||||
|     } | ||||
| 
 | ||||
|     std::string str() const { | ||||
|         std::stringstream ss; | ||||
|         std::string sep; | ||||
|         for( auto &it : *this ) { | ||||
|             ss << sep << it.first << "=" << it.second; | ||||
|             sep = ','; | ||||
|         } | ||||
|         return ss.str(); | ||||
|     } | ||||
| 
 | ||||
|     std::string cmdline() const { | ||||
|         std::stringstream cmd; | ||||
|         std::string sep; | ||||
|         // concatenate args
 | ||||
|         for( auto end = size(), arg = end - end; arg < end; ++arg ) { | ||||
|             cmd << sep << this->find(std::to_string(arg))->second; | ||||
|             sep = ' '; | ||||
|         } | ||||
|         return cmd.str(); | ||||
|     } | ||||
| }; | ||||
| 
 | ||||
| // variadic syntax sugars {
 | ||||
| 
 | ||||
| template< typename T > | ||||
| inline T getarg( const T &defaults, const char *argv ) { | ||||
|     static struct getopt map( getopt_utils::cmdline() ); | ||||
|     return map.has( argv ) ? getopt_utils::as<T>(map[ argv ]) : defaults; | ||||
| } | ||||
| 
 | ||||
| template< typename T, typename... Args > | ||||
| inline T getarg( const T &defaults, const char *arg0, Args... argv ) { | ||||
|     T t = getarg<T>( defaults, arg0 ); | ||||
|     return t == defaults ? getarg<T>( defaults, argv... ) : t; | ||||
| } | ||||
| 
 | ||||
| inline const char * getarg( const char *defaults, const char *argv ) { | ||||
|     static struct getopt map( getopt_utils::cmdline() ); | ||||
|     return map.has( argv ) ? getopt_utils::as<const char *>(map[ argv ]) : defaults; | ||||
| } | ||||
| 
 | ||||
| template< typename... Args > | ||||
| inline const char * getarg( const char *defaults, const char *arg0, Args... argv ) { | ||||
|     const char *t = getarg( defaults, arg0 ); | ||||
|     return t == defaults ? getarg( defaults, argv... ) : t; | ||||
| } | ||||
| 
 | ||||
| // }
 | ||||
| 
 | ||||
| 
 | ||||
| #ifdef GETOPT_BUILD_DEMO | ||||
| #include <iostream> | ||||
| #include <stdlib.h> | ||||
| 
 | ||||
| int main( int argc, const char **argv ) { | ||||
| 
 | ||||
|     auto show_help = [&]() { | ||||
|         std::cout << argv[0] << " [-h|--help|-?] [-f=path|--file=path] [-v|--version] [-d=number|--depth=number|--max-depth=number]" << std::endl; | ||||
|         exit(0); | ||||
|     }; | ||||
| 
 | ||||
|     // Simple functional api. No initialization required.
 | ||||
| 
 | ||||
|     bool help = getarg( false, "-h", "--help", "-?" ); | ||||
|     int version = getarg( 0, "-v", "--version", "--show-version" ); | ||||
|     int depth = getarg( 0, "-d", "--depth", "--max-depth"); | ||||
|     std::string file = getarg( "", "-f", "--file" ); | ||||
| 
 | ||||
|     if( help || argc <= 1 ) { | ||||
|         show_help(); | ||||
|     } | ||||
| 
 | ||||
|     if( version ) { | ||||
|         std::cout << argv[0] << " demo v1.0.0. Compiled on " << __DATE__ << std::endl; | ||||
|     } | ||||
| 
 | ||||
|     if( depth ) { | ||||
|         std::cout << "provided depth: " << depth << std::endl; | ||||
|     } | ||||
| 
 | ||||
|     if( !file.empty() ) { | ||||
|         std::cout << "provided file: " << file << std::endl; | ||||
|     } | ||||
| 
 | ||||
|     // OOP map-based api. Explicit (argc, argv) initialization required.
 | ||||
| 
 | ||||
|     struct getopt args( argc, argv ); | ||||
| 
 | ||||
|     if( args.has("-h") || args.has("--help") || args.has("-?") || args.size() == 1 ) { | ||||
|         show_help(); | ||||
|     } | ||||
| 
 | ||||
|     if( args.has("-v") || args.has("--version") ) { | ||||
|         std::cout << args["0"] << " demo v1.0.0. Compiled on " << __DATE__ << std::endl; | ||||
|     } | ||||
| 
 | ||||
|     if( args.has("-d") || args.has("--depth") || args.has("--max-depth") ) { | ||||
|         std::string arg = args["-d"]; | ||||
|         if( arg.empty() ) arg = args["--depth"]; | ||||
|         if( arg.empty() ) arg = args["--max-depth"]; | ||||
|         int depth = atoi( arg.c_str() ); | ||||
|         std::cout << "provided depth: " << depth << std::endl; | ||||
|     } | ||||
| 
 | ||||
|     if( args.has("-f") || args.has("--file") ) { | ||||
|         std::string arg = args["-f"]; | ||||
|         if( arg.empty() ) arg = args["--file"]; | ||||
|         std::string fname = arg; | ||||
|         std::cout << "provided file: " << fname << std::endl; | ||||
|     } | ||||
| 
 | ||||
|     std::cout << "---" << std::endl; | ||||
|     std::cout << args.cmdline() << std::endl; | ||||
|     //std::cout << args.size() << " provided args: " << args.str() << std::endl;
 | ||||
| } | ||||
| #endif | ||||
							
								
								
									
										80
									
								
								demos/ra_tls/grpc/v1.38.1/examples/cpp/ratls/server.cc
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										80
									
								
								demos/ra_tls/grpc/v1.38.1/examples/cpp/ratls/server.cc
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,80 @@ | ||||
| /*
 | ||||
|  * | ||||
|  * 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 "../getopt.hpp" | ||||
| 
 | ||||
| using ratls::Greeter; | ||||
| using ratls::HelloReply; | ||||
| using ratls::HelloRequest; | ||||
| 
 | ||||
| struct argparser { | ||||
|     const char* config; | ||||
|     std::string server_address; | ||||
|     argparser() { | ||||
|         server_address = getarg("localhost:50051", "-host", "--host"); | ||||
|         config = getarg("dynamic_config.json", "-cfg", "--config"); | ||||
|     }; | ||||
| }; | ||||
| 
 | ||||
| // Logic and data behind the server's behavior.
 | ||||
| class GreeterServiceImpl final : public Greeter::Service { | ||||
|     grpc::Status SayHello( | ||||
|         grpc::ServerContext* context, const HelloRequest* request, HelloReply* reply) override { | ||||
|         std::string prefix("Hello "); | ||||
|         reply->set_message(prefix + request->name()); | ||||
|         return grpc::Status::OK; | ||||
|     } | ||||
| }; | ||||
| 
 | ||||
| void RunServer() { | ||||
|     argparser args; | ||||
| 
 | ||||
|     GreeterServiceImpl service; | ||||
| 
 | ||||
|     grpc::EnableDefaultHealthCheckService(true); | ||||
|     grpc::reflection::InitProtoReflectionServerBuilderPlugin(); | ||||
| 
 | ||||
|     grpc::ServerBuilder builder; | ||||
| 
 | ||||
|     auto creds = grpc::sgx::TlsServerCredentials(args.config); | ||||
|     GPR_ASSERT(creds.get() != nullptr); | ||||
| 
 | ||||
|     builder.AddListeningPort(args.server_address, creds); | ||||
| 
 | ||||
|     builder.RegisterService(&service); | ||||
| 
 | ||||
|     std::unique_ptr<grpc::Server> server(builder.BuildAndStart()); | ||||
|     std::cout << "Server listening on " << args.server_address << std::endl; | ||||
| 
 | ||||
|     server->Wait(); | ||||
| } | ||||
| 
 | ||||
| int main(int argc, char** argv) { | ||||
|     RunServer(); | ||||
|     return 0; | ||||
| } | ||||
							
								
								
									
										38
									
								
								demos/ra_tls/grpc/v1.38.1/examples/protos/ratls.proto
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										38
									
								
								demos/ra_tls/grpc/v1.38.1/examples/protos/ratls.proto
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,38 @@ | ||||
| // Copyright (c) 2022 Intel Corporation | ||||
| //  | ||||
| // Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| // you may not use this file except in compliance with the License. | ||||
| // You may obtain a copy of the License at | ||||
| //  | ||||
| //     http://www.apache.org/licenses/LICENSE-2.0 | ||||
| //  | ||||
| // Unless required by applicable law or agreed to in writing, software | ||||
| // distributed under the License is distributed on an "AS IS" BASIS, | ||||
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
| // See the License for the specific language governing permissions and | ||||
| // limitations under the License. | ||||
| 
 | ||||
| syntax = "proto3"; | ||||
| 
 | ||||
| option java_multiple_files = true; | ||||
| option java_package = "io.grpc.examples.ratls"; | ||||
| option java_outer_classname = "RATLSProto"; | ||||
| option objc_class_prefix = "HLW"; | ||||
| 
 | ||||
| package ratls; | ||||
| 
 | ||||
| // The greeting service definition. | ||||
| service Greeter { | ||||
|   // Sends a greeting | ||||
|   rpc SayHello (HelloRequest) returns (HelloReply) {} | ||||
| } | ||||
| 
 | ||||
| // The request message containing the user's name. | ||||
| message HelloRequest { | ||||
|   string name = 1; | ||||
| } | ||||
| 
 | ||||
| // The response message containing the greetings | ||||
| message HelloReply { | ||||
|   string message = 1; | ||||
| } | ||||
| @ -0,0 +1,57 @@ | ||||
| /*
 | ||||
|  * | ||||
|  * 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> | ||||
| 
 | ||||
| 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); | ||||
| 
 | ||||
| }  // namespace sgx
 | ||||
| }  // namespace grpc
 | ||||
| 
 | ||||
| #endif  // SGX_RA_TLS_H
 | ||||
| @ -0,0 +1,67 @@ | ||||
| /*
 | ||||
|  * | ||||
|  * Copyright (c) 2022 Intel Corporation | ||||
|  * | ||||
|  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|  * you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * | ||||
|  *     http://www.apache.org/licenses/LICENSE-2.0
 | ||||
|  * | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an "AS IS" BASIS, | ||||
|  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|  * See the License for the specific language governing permissions and | ||||
|  * limitations under the License. | ||||
|  * | ||||
|  */ | ||||
| 
 | ||||
| #ifndef SGX_RA_TLS_OPTIONS_H | ||||
| #define SGX_RA_TLS_OPTIONS_H | ||||
| 
 | ||||
| #include <grpc/grpc_security_constants.h> | ||||
| #include <grpc/status.h> | ||||
| #include <grpc/support/log.h> | ||||
| #include <grpcpp/security/tls_certificate_provider.h> | ||||
| #include <grpcpp/security/tls_credentials_options.h> | ||||
| #include <grpcpp/support/config.h> | ||||
| 
 | ||||
| #include <memory> | ||||
| #include <vector> | ||||
| 
 | ||||
| namespace grpc { | ||||
| namespace sgx { | ||||
| 
 | ||||
| // Contains configurable options on the client side.
 | ||||
| // Client side doesn't need to always use certificate provider. When the
 | ||||
| // certificate provider is not set, we will use the root certificates stored
 | ||||
| // in the system default locations, and assume client won't provide any
 | ||||
| // identity certificates(single side TLS).
 | ||||
| // It is used for experimental purposes for now and it is subject to change.
 | ||||
| class CredentialsOptions final : public grpc::experimental::TlsCredentialsOptions { | ||||
|  public: | ||||
| 
 | ||||
|   explicit CredentialsOptions() : TlsCredentialsOptions() {} | ||||
| 
 | ||||
|   // Sets option to request the certificates from the client.
 | ||||
|   // The default is GRPC_SSL_DONT_REQUEST_CLIENT_CERTIFICATE.
 | ||||
|   void set_cert_request_type( | ||||
|       grpc_ssl_client_certificate_request_type cert_request_type); | ||||
| 
 | ||||
|   // Sets the option to verify the server.
 | ||||
|   // The default is GRPC_TLS_SERVER_VERIFICATION.
 | ||||
|   void set_verification_option( | ||||
|       grpc_tls_server_verification_option server_verification_option); | ||||
| 
 | ||||
|   // Sets the custom authorization config.
 | ||||
|   void set_authorization_check_config( | ||||
|       std::shared_ptr<grpc::experimental::TlsServerAuthorizationCheckConfig> | ||||
|           authorization_check_config); | ||||
| 
 | ||||
|  private: | ||||
| }; | ||||
| 
 | ||||
| }  // namespace sgx
 | ||||
| }  // namespace grpc
 | ||||
| 
 | ||||
| #endif  // SGX_RA_TLS_OPTIONS_H
 | ||||
| @ -0,0 +1,133 @@ | ||||
| /*
 | ||||
|  * | ||||
|  * 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)); | ||||
| } | ||||
							
								
								
									
										863
									
								
								demos/ra_tls/grpc/v1.38.1/src/core/lib/security/security_connector/tls/tls_security_connector.cc
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										863
									
								
								demos/ra_tls/grpc/v1.38.1/src/core/lib/security/security_connector/tls/tls_security_connector.cc
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,863 @@ | ||||
| /*
 | ||||
|  * | ||||
|  * 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
 | ||||
							
								
								
									
										267
									
								
								demos/ra_tls/grpc/v1.38.1/src/core/lib/security/security_connector/tls/tls_security_connector.h
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										267
									
								
								demos/ra_tls/grpc/v1.38.1/src/core/lib/security/security_connector/tls/tls_security_connector.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,267 @@ | ||||
| /*
 | ||||
|  * | ||||
|  * 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
 | ||||
							
								
								
									
										567
									
								
								demos/ra_tls/grpc/v1.38.1/src/cpp/sgx/cJSON.c
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										567
									
								
								demos/ra_tls/grpc/v1.38.1/src/cpp/sgx/cJSON.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,567 @@ | ||||
| /*
 | ||||
|   Copyright (c) 2009 Dave Gamble | ||||
| 
 | ||||
|   Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
|   of this software and associated documentation files (the "Software"), to deal | ||||
|   in the Software without restriction, including without limitation the rights | ||||
|   to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||
|   copies of the Software, and to permit persons to whom the Software is | ||||
|   furnished to do so, subject to the following conditions: | ||||
| 
 | ||||
|   The above copyright notice and this permission notice shall be included in | ||||
|   all copies or substantial portions of the Software. | ||||
| 
 | ||||
|   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
|   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
|   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||
|   AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||
|   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||
|   OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||||
|   THE SOFTWARE. | ||||
| */ | ||||
| 
 | ||||
| /* cJSON */ | ||||
| /* JSON parser in C. */ | ||||
| 
 | ||||
| #include <string.h> | ||||
| #include <stdio.h> | ||||
| #include <math.h> | ||||
| #include <stdlib.h> | ||||
| #include <float.h> | ||||
| #include <limits.h> | ||||
| #include <ctype.h> | ||||
| #include "cJSON.h" | ||||
| 
 | ||||
| static const char *ep; | ||||
| 
 | ||||
| const char *cJSON_GetErrorPtr(void) {return ep;} | ||||
| 
 | ||||
| static int cJSON_strcasecmp(const char *s1,const char *s2) | ||||
| { | ||||
| 	if (!s1) return (s1==s2)?0:1;if (!s2) return 1; | ||||
| 	for(; tolower(*s1) == tolower(*s2); ++s1, ++s2)	if(*s1 == 0)	return 0; | ||||
| 	return tolower(*(const unsigned char *)s1) - tolower(*(const unsigned char *)s2); | ||||
| } | ||||
| 
 | ||||
| static void *(*cJSON_malloc)(size_t sz) = malloc; | ||||
| static void (*cJSON_free)(void *ptr) = free; | ||||
| 
 | ||||
| static char* cJSON_strdup(const char* str) | ||||
| { | ||||
|       size_t len; | ||||
|       char* copy; | ||||
| 
 | ||||
|       len = strlen(str) + 1; | ||||
|       if (!(copy = (char*)cJSON_malloc(len))) return 0; | ||||
|       memcpy(copy,str,len); | ||||
|       return copy; | ||||
| } | ||||
| 
 | ||||
| void cJSON_InitHooks(cJSON_Hooks* hooks) | ||||
| { | ||||
|     if (!hooks) { /* Reset hooks */ | ||||
|         cJSON_malloc = malloc; | ||||
|         cJSON_free = free; | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
| 	cJSON_malloc = (hooks->malloc_fn)?hooks->malloc_fn:malloc; | ||||
| 	cJSON_free	 = (hooks->free_fn)?hooks->free_fn:free; | ||||
| } | ||||
| 
 | ||||
| /* Internal constructor. */ | ||||
| static cJSON *cJSON_New_Item(void) | ||||
| { | ||||
| 	cJSON* node = (cJSON*)cJSON_malloc(sizeof(cJSON)); | ||||
| 	if (node) memset(node,0,sizeof(cJSON)); | ||||
| 	return node; | ||||
| } | ||||
| 
 | ||||
| /* Delete a cJSON structure. */ | ||||
| void cJSON_Delete(cJSON *c) | ||||
| { | ||||
| 	cJSON *next; | ||||
| 	while (c) | ||||
| 	{ | ||||
| 		next=c->next; | ||||
| 		if (!(c->type&cJSON_IsReference) && c->child) cJSON_Delete(c->child); | ||||
| 		if (!(c->type&cJSON_IsReference) && c->valuestring) cJSON_free(c->valuestring); | ||||
| 		if (c->string) cJSON_free(c->string); | ||||
| 		cJSON_free(c); | ||||
| 		c=next; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| /* Parse the input text to generate a number, and populate the result into item. */ | ||||
| static const char *parse_number(cJSON *item,const char *num) | ||||
| { | ||||
| 	double n=0,sign=1,scale=0;int subscale=0,signsubscale=1; | ||||
| 
 | ||||
| 	/* Could use sscanf for this? */ | ||||
| 	if (*num=='-') sign=-1,num++;	/* Has sign? */ | ||||
| 	if (*num=='0') num++;			/* is zero */ | ||||
| 	if (*num>='1' && *num<='9')	do	n=(n*10.0)+(*num++ -'0');	while (*num>='0' && *num<='9');	/* Number? */ | ||||
| 	if (*num=='.' && num[1]>='0' && num[1]<='9') {num++;		do	n=(n*10.0)+(*num++ -'0'),scale--; while (*num>='0' && *num<='9');}	/* Fractional part? */ | ||||
| 	if (*num=='e' || *num=='E')		/* Exponent? */ | ||||
| 	{	num++;if (*num=='+') num++;	else if (*num=='-') signsubscale=-1,num++;		/* With sign? */ | ||||
| 		while (*num>='0' && *num<='9') subscale=(subscale*10)+(*num++ - '0');	/* Number? */ | ||||
| 	} | ||||
| 
 | ||||
| 	n=sign*n*pow(10.0,(scale+subscale*signsubscale));	/* number = +/- number.fraction * 10^+/- exponent */ | ||||
| 	 | ||||
| 	item->valuedouble=n; | ||||
| 	item->valueint=(int)n; | ||||
| 	item->type=cJSON_Number; | ||||
| 	return num; | ||||
| } | ||||
| 
 | ||||
| /* Render the number nicely from the given item into a string. */ | ||||
| static char *print_number(cJSON *item) | ||||
| { | ||||
| 	char *str; | ||||
| 	double d=item->valuedouble; | ||||
| 	if (fabs(((double)item->valueint)-d)<=DBL_EPSILON && d<=INT_MAX && d>=INT_MIN) | ||||
| 	{ | ||||
| 		str=(char*)cJSON_malloc(21);	/* 2^64+1 can be represented in 21 chars. */ | ||||
| 		if (str) sprintf(str,"%d",item->valueint); | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		str=(char*)cJSON_malloc(64);	/* This is a nice tradeoff. */ | ||||
| 		if (str) | ||||
| 		{ | ||||
| 			if (fabs(floor(d)-d)<=DBL_EPSILON && fabs(d)<1.0e60)sprintf(str,"%.0f",d); | ||||
| 			else if (fabs(d)<1.0e-6 || fabs(d)>1.0e9)			sprintf(str,"%e",d); | ||||
| 			else												sprintf(str,"%f",d); | ||||
| 		} | ||||
| 	} | ||||
| 	return str; | ||||
| } | ||||
| 
 | ||||
| /* Parse the input text into an unescaped cstring, and populate item. */ | ||||
| static const unsigned char firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC }; | ||||
| static const char *parse_string(cJSON *item,const char *str) | ||||
| { | ||||
| 	const char *ptr=str+1;char *ptr2;char *out;int len=0;unsigned uc,uc2; | ||||
| 	if (*str!='\"') {ep=str;return 0;}	/* not a string! */ | ||||
| 	 | ||||
| 	while (*ptr!='\"' && *ptr && ++len) if (*ptr++ == '\\') ptr++;	/* Skip escaped quotes. */ | ||||
| 	 | ||||
| 	out=(char*)cJSON_malloc(len+1);	/* This is how long we need for the string, roughly. */ | ||||
| 	if (!out) return 0; | ||||
| 	 | ||||
| 	ptr=str+1;ptr2=out; | ||||
| 	while (*ptr!='\"' && *ptr) | ||||
| 	{ | ||||
| 		if (*ptr!='\\') *ptr2++=*ptr++; | ||||
| 		else | ||||
| 		{ | ||||
| 			ptr++; | ||||
| 			switch (*ptr) | ||||
| 			{ | ||||
| 				case 'b': *ptr2++='\b';	break; | ||||
| 				case 'f': *ptr2++='\f';	break; | ||||
| 				case 'n': *ptr2++='\n';	break; | ||||
| 				case 'r': *ptr2++='\r';	break; | ||||
| 				case 't': *ptr2++='\t';	break; | ||||
| 				case 'u':	 /* transcode utf16 to utf8. */ | ||||
| 					sscanf(ptr+1,"%4x",&uc);ptr+=4;	/* get the unicode char. */ | ||||
| 
 | ||||
| 					if ((uc>=0xDC00 && uc<=0xDFFF) || uc==0)	break;	/* check for invalid.	*/ | ||||
| 
 | ||||
| 					if (uc>=0xD800 && uc<=0xDBFF)	/* UTF16 surrogate pairs.	*/ | ||||
| 					{ | ||||
| 						if (ptr[1]!='\\' || ptr[2]!='u')	break;	/* missing second-half of surrogate.	*/ | ||||
| 						sscanf(ptr+3,"%4x",&uc2);ptr+=6; | ||||
| 						if (uc2<0xDC00 || uc2>0xDFFF)		break;	/* invalid second-half of surrogate.	*/ | ||||
| 						uc=0x10000 + (((uc&0x3FF)<<10) | (uc2&0x3FF)); | ||||
| 					} | ||||
| 
 | ||||
| 					len=4;if (uc<0x80) len=1;else if (uc<0x800) len=2;else if (uc<0x10000) len=3; ptr2+=len; | ||||
| 					 | ||||
| 					switch (len) { | ||||
| 						case 4: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6; | ||||
| 						case 3: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6; | ||||
| 						case 2: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6; | ||||
| 						case 1: *--ptr2 =(uc | firstByteMark[len]); | ||||
| 					} | ||||
| 					ptr2+=len; | ||||
| 					break; | ||||
| 				default:  *ptr2++=*ptr; break; | ||||
| 			} | ||||
| 			ptr++; | ||||
| 		} | ||||
| 	} | ||||
| 	*ptr2=0; | ||||
| 	if (*ptr=='\"') ptr++; | ||||
| 	item->valuestring=out; | ||||
| 	item->type=cJSON_String; | ||||
| 	return ptr; | ||||
| } | ||||
| 
 | ||||
| /* Render the cstring provided to an escaped version that can be printed. */ | ||||
| static char *print_string_ptr(const char *str) | ||||
| { | ||||
| 	const char *ptr;char *ptr2,*out;int len=0;unsigned char token; | ||||
| 	 | ||||
| 	if (!str) return cJSON_strdup(""); | ||||
| 	ptr=str;while ((token=*ptr) && ++len) {if (strchr("\"\\\b\f\n\r\t",token)) len++; else if (token<32) len+=5;ptr++;} | ||||
| 	 | ||||
| 	out=(char*)cJSON_malloc(len+3); | ||||
| 	if (!out) return 0; | ||||
| 
 | ||||
| 	ptr2=out;ptr=str; | ||||
| 	*ptr2++='\"'; | ||||
| 	while (*ptr) | ||||
| 	{ | ||||
| 		if ((unsigned char)*ptr>31 && *ptr!='\"' && *ptr!='\\') *ptr2++=*ptr++; | ||||
| 		else | ||||
| 		{ | ||||
| 			*ptr2++='\\'; | ||||
| 			switch (token=*ptr++) | ||||
| 			{ | ||||
| 				case '\\':	*ptr2++='\\';	break; | ||||
| 				case '\"':	*ptr2++='\"';	break; | ||||
| 				case '\b':	*ptr2++='b';	break; | ||||
| 				case '\f':	*ptr2++='f';	break; | ||||
| 				case '\n':	*ptr2++='n';	break; | ||||
| 				case '\r':	*ptr2++='r';	break; | ||||
| 				case '\t':	*ptr2++='t';	break; | ||||
| 				default: sprintf(ptr2,"u%04x",token);ptr2+=5;	break;	/* escape and print */ | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	*ptr2++='\"';*ptr2++=0; | ||||
| 	return out; | ||||
| } | ||||
| /* Invote print_string_ptr (which is useful) on an item. */ | ||||
| static char *print_string(cJSON *item)	{return print_string_ptr(item->valuestring);} | ||||
| 
 | ||||
| /* Predeclare these prototypes. */ | ||||
| static const char *parse_value(cJSON *item,const char *value); | ||||
| static char *print_value(cJSON *item,int depth,int fmt); | ||||
| static const char *parse_array(cJSON *item,const char *value); | ||||
| static char *print_array(cJSON *item,int depth,int fmt); | ||||
| static const char *parse_object(cJSON *item,const char *value); | ||||
| static char *print_object(cJSON *item,int depth,int fmt); | ||||
| 
 | ||||
| /* Utility to jump whitespace and cr/lf */ | ||||
| static const char *skip(const char *in) {while (in && *in && (unsigned char)*in<=32) in++; return in;} | ||||
| 
 | ||||
| /* Parse an object - create a new root, and populate. */ | ||||
| cJSON *cJSON_ParseWithOpts(const char *value,const char **return_parse_end,int require_null_terminated) | ||||
| { | ||||
| 	const char *end=0; | ||||
| 	cJSON *c=cJSON_New_Item(); | ||||
| 	ep=0; | ||||
| 	if (!c) return 0;       /* memory fail */ | ||||
| 
 | ||||
| 	end=parse_value(c,skip(value)); | ||||
| 	if (!end)	{cJSON_Delete(c);return 0;}	/* parse failure. ep is set. */ | ||||
| 
 | ||||
| 	/* if we require null-terminated JSON without appended garbage, skip and then check for a null terminator */ | ||||
| 	if (require_null_terminated) {end=skip(end);if (*end) {cJSON_Delete(c);ep=end;return 0;}} | ||||
| 	if (return_parse_end) *return_parse_end=end; | ||||
| 	return c; | ||||
| } | ||||
| /* Default options for cJSON_Parse */ | ||||
| cJSON *cJSON_Parse(const char *value) {return cJSON_ParseWithOpts(value,0,0);} | ||||
| 
 | ||||
| /* Render a cJSON item/entity/structure to text. */ | ||||
| char *cJSON_Print(cJSON *item)				{return print_value(item,0,1);} | ||||
| char *cJSON_PrintUnformatted(cJSON *item)	{return print_value(item,0,0);} | ||||
| 
 | ||||
| /* Parser core - when encountering text, process appropriately. */ | ||||
| static const char *parse_value(cJSON *item,const char *value) | ||||
| { | ||||
| 	if (!value)						return 0;	/* Fail on null. */ | ||||
| 	if (!strncmp(value,"null",4))	{ item->type=cJSON_NULL;  return value+4; } | ||||
| 	if (!strncmp(value,"false",5))	{ item->type=cJSON_False; return value+5; } | ||||
| 	if (!strncmp(value,"true",4))	{ item->type=cJSON_True; item->valueint=1;	return value+4; } | ||||
| 	if (*value=='\"')				{ return parse_string(item,value); } | ||||
| 	if (*value=='-' || (*value>='0' && *value<='9'))	{ return parse_number(item,value); } | ||||
| 	if (*value=='[')				{ return parse_array(item,value); } | ||||
| 	if (*value=='{')				{ return parse_object(item,value); } | ||||
| 
 | ||||
| 	ep=value;return 0;	/* failure. */ | ||||
| } | ||||
| 
 | ||||
| /* Render a value to text. */ | ||||
| static char *print_value(cJSON *item,int depth,int fmt) | ||||
| { | ||||
| 	char *out=0; | ||||
| 	if (!item) return 0; | ||||
| 	switch ((item->type)&255) | ||||
| 	{ | ||||
| 		case cJSON_NULL:	out=cJSON_strdup("null");	break; | ||||
| 		case cJSON_False:	out=cJSON_strdup("false");break; | ||||
| 		case cJSON_True:	out=cJSON_strdup("true"); break; | ||||
| 		case cJSON_Number:	out=print_number(item);break; | ||||
| 		case cJSON_String:	out=print_string(item);break; | ||||
| 		case cJSON_Array:	out=print_array(item,depth,fmt);break; | ||||
| 		case cJSON_Object:	out=print_object(item,depth,fmt);break; | ||||
| 	} | ||||
| 	return out; | ||||
| } | ||||
| 
 | ||||
| /* Build an array from input text. */ | ||||
| static const char *parse_array(cJSON *item,const char *value) | ||||
| { | ||||
| 	cJSON *child; | ||||
| 	if (*value!='[')	{ep=value;return 0;}	/* not an array! */ | ||||
| 
 | ||||
| 	item->type=cJSON_Array; | ||||
| 	value=skip(value+1); | ||||
| 	if (*value==']') return value+1;	/* empty array. */ | ||||
| 
 | ||||
| 	item->child=child=cJSON_New_Item(); | ||||
| 	if (!item->child) return 0;		 /* memory fail */ | ||||
| 	value=skip(parse_value(child,skip(value)));	/* skip any spacing, get the value. */ | ||||
| 	if (!value) return 0; | ||||
| 
 | ||||
| 	while (*value==',') | ||||
| 	{ | ||||
| 		cJSON *new_item; | ||||
| 		if (!(new_item=cJSON_New_Item())) return 0; 	/* memory fail */ | ||||
| 		child->next=new_item;new_item->prev=child;child=new_item; | ||||
| 		value=skip(parse_value(child,skip(value+1))); | ||||
| 		if (!value) return 0;	/* memory fail */ | ||||
| 	} | ||||
| 
 | ||||
| 	if (*value==']') return value+1;	/* end of array */ | ||||
| 	ep=value;return 0;	/* malformed. */ | ||||
| } | ||||
| 
 | ||||
| /* Render an array to text */ | ||||
| static char *print_array(cJSON *item,int depth,int fmt) | ||||
| { | ||||
| 	char **entries; | ||||
| 	char *out=0,*ptr,*ret;int len=5; | ||||
| 	cJSON *child=item->child; | ||||
| 	int numentries=0,i=0,fail=0; | ||||
| 	 | ||||
| 	/* How many entries in the array? */ | ||||
| 	while (child) numentries++,child=child->next; | ||||
| 	/* Explicitly handle numentries==0 */ | ||||
| 	if (!numentries) | ||||
| 	{ | ||||
| 		out=(char*)cJSON_malloc(3); | ||||
| 		if (out) strcpy(out,"[]"); | ||||
| 		return out; | ||||
| 	} | ||||
| 	/* Allocate an array to hold the values for each */ | ||||
| 	entries=(char**)cJSON_malloc(numentries*sizeof(char*)); | ||||
| 	if (!entries) return 0; | ||||
| 	memset(entries,0,numentries*sizeof(char*)); | ||||
| 	/* Retrieve all the results: */ | ||||
| 	child=item->child; | ||||
| 	while (child && !fail) | ||||
| 	{ | ||||
| 		ret=print_value(child,depth+1,fmt); | ||||
| 		entries[i++]=ret; | ||||
| 		if (ret) len+=strlen(ret)+2+(fmt?1:0); else fail=1; | ||||
| 		child=child->next; | ||||
| 	} | ||||
| 	 | ||||
| 	/* If we didn't fail, try to malloc the output string */ | ||||
| 	if (!fail) out=(char*)cJSON_malloc(len); | ||||
| 	/* If that fails, we fail. */ | ||||
| 	if (!out) fail=1; | ||||
| 
 | ||||
| 	/* Handle failure. */ | ||||
| 	if (fail) | ||||
| 	{ | ||||
| 		for (i=0;i<numentries;i++) if (entries[i]) cJSON_free(entries[i]); | ||||
| 		cJSON_free(entries); | ||||
| 		return 0; | ||||
| 	} | ||||
| 	 | ||||
| 	/* Compose the output array. */ | ||||
| 	*out='['; | ||||
| 	ptr=out+1;*ptr=0; | ||||
| 	for (i=0;i<numentries;i++) | ||||
| 	{ | ||||
| 		strcpy(ptr,entries[i]);ptr+=strlen(entries[i]); | ||||
| 		if (i!=numentries-1) {*ptr++=',';if(fmt)*ptr++=' ';*ptr=0;} | ||||
| 		cJSON_free(entries[i]); | ||||
| 	} | ||||
| 	cJSON_free(entries); | ||||
| 	*ptr++=']';*ptr++=0; | ||||
| 	return out;	 | ||||
| } | ||||
| 
 | ||||
| /* Build an object from the text. */ | ||||
| static const char *parse_object(cJSON *item,const char *value) | ||||
| { | ||||
| 	cJSON *child; | ||||
| 	if (*value!='{')	{ep=value;return 0;}	/* not an object! */ | ||||
| 	 | ||||
| 	item->type=cJSON_Object; | ||||
| 	value=skip(value+1); | ||||
| 	if (*value=='}') return value+1;	/* empty array. */ | ||||
| 	 | ||||
| 	item->child=child=cJSON_New_Item(); | ||||
| 	if (!item->child) return 0; | ||||
| 	value=skip(parse_string(child,skip(value))); | ||||
| 	if (!value) return 0; | ||||
| 	child->string=child->valuestring;child->valuestring=0; | ||||
| 	if (*value!=':') {ep=value;return 0;}	/* fail! */ | ||||
| 	value=skip(parse_value(child,skip(value+1)));	/* skip any spacing, get the value. */ | ||||
| 	if (!value) return 0; | ||||
| 	 | ||||
| 	while (*value==',') | ||||
| 	{ | ||||
| 		cJSON *new_item; | ||||
| 		if (!(new_item=cJSON_New_Item()))	return 0; /* memory fail */ | ||||
| 		child->next=new_item;new_item->prev=child;child=new_item; | ||||
| 		value=skip(parse_string(child,skip(value+1))); | ||||
| 		if (!value) return 0; | ||||
| 		child->string=child->valuestring;child->valuestring=0; | ||||
| 		if (*value!=':') {ep=value;return 0;}	/* fail! */ | ||||
| 		value=skip(parse_value(child,skip(value+1)));	/* skip any spacing, get the value. */ | ||||
| 		if (!value) return 0; | ||||
| 	} | ||||
| 	 | ||||
| 	if (*value=='}') return value+1;	/* end of array */ | ||||
| 	ep=value;return 0;	/* malformed. */ | ||||
| } | ||||
| 
 | ||||
| /* Render an object to text. */ | ||||
| static char *print_object(cJSON *item,int depth,int fmt) | ||||
| { | ||||
| 	char **entries=0,**names=0; | ||||
| 	char *out=0,*ptr,*ret,*str;int len=7,i=0,j; | ||||
| 	cJSON *child=item->child; | ||||
| 	int numentries=0,fail=0; | ||||
| 	/* Count the number of entries. */ | ||||
| 	while (child) numentries++,child=child->next; | ||||
| 	/* Explicitly handle empty object case */ | ||||
| 	if (!numentries) | ||||
| 	{ | ||||
| 		out=(char*)cJSON_malloc(fmt?depth+3:3); | ||||
| 		if (!out)	return 0; | ||||
| 		ptr=out;*ptr++='{'; | ||||
| 		if (fmt) {*ptr++='\n';for (i=0;i<depth-1;i++) *ptr++='\t';} | ||||
| 		*ptr++='}';*ptr++=0; | ||||
| 		return out; | ||||
| 	} | ||||
| 	/* Allocate space for the names and the objects */ | ||||
| 	entries=(char**)cJSON_malloc(numentries*sizeof(char*)); | ||||
| 	if (!entries) return 0; | ||||
| 	names=(char**)cJSON_malloc(numentries*sizeof(char*)); | ||||
| 	if (!names) {cJSON_free(entries);return 0;} | ||||
| 	memset(entries,0,sizeof(char*)*numentries); | ||||
| 	memset(names,0,sizeof(char*)*numentries); | ||||
| 
 | ||||
| 	/* Collect all the results into our arrays: */ | ||||
| 	child=item->child;depth++;if (fmt) len+=depth; | ||||
| 	while (child) | ||||
| 	{ | ||||
| 		names[i]=str=print_string_ptr(child->string); | ||||
| 		entries[i++]=ret=print_value(child,depth,fmt); | ||||
| 		if (str && ret) len+=strlen(ret)+strlen(str)+2+(fmt?2+depth:0); else fail=1; | ||||
| 		child=child->next; | ||||
| 	} | ||||
| 	 | ||||
| 	/* Try to allocate the output string */ | ||||
| 	if (!fail) out=(char*)cJSON_malloc(len); | ||||
| 	if (!out) fail=1; | ||||
| 
 | ||||
| 	/* Handle failure */ | ||||
| 	if (fail) | ||||
| 	{ | ||||
| 		for (i=0;i<numentries;i++) {if (names[i]) cJSON_free(names[i]);if (entries[i]) cJSON_free(entries[i]);} | ||||
| 		cJSON_free(names);cJSON_free(entries); | ||||
| 		return 0; | ||||
| 	} | ||||
| 	 | ||||
| 	/* Compose the output: */ | ||||
| 	*out='{';ptr=out+1;if (fmt)*ptr++='\n';*ptr=0; | ||||
| 	for (i=0;i<numentries;i++) | ||||
| 	{ | ||||
| 		if (fmt) for (j=0;j<depth;j++) *ptr++='\t'; | ||||
| 		strcpy(ptr,names[i]);ptr+=strlen(names[i]); | ||||
| 		*ptr++=':';if (fmt) *ptr++='\t'; | ||||
| 		strcpy(ptr,entries[i]);ptr+=strlen(entries[i]); | ||||
| 		if (i!=numentries-1) *ptr++=','; | ||||
| 		if (fmt) *ptr++='\n';*ptr=0; | ||||
| 		cJSON_free(names[i]);cJSON_free(entries[i]); | ||||
| 	} | ||||
| 	 | ||||
| 	cJSON_free(names);cJSON_free(entries); | ||||
| 	if (fmt) for (i=0;i<depth-1;i++) *ptr++='\t'; | ||||
| 	*ptr++='}';*ptr++=0; | ||||
| 	return out;	 | ||||
| } | ||||
| 
 | ||||
| /* Get Array size/item / object item. */ | ||||
| int    cJSON_GetArraySize(cJSON *array)							{cJSON *c=array->child;int i=0;while(c)i++,c=c->next;return i;} | ||||
| cJSON *cJSON_GetArrayItem(cJSON *array,int item)				{cJSON *c=array->child;  while (c && item>0) item--,c=c->next; return c;} | ||||
| cJSON *cJSON_GetObjectItem(cJSON *object,const char *string)	{cJSON *c=object->child; while (c && cJSON_strcasecmp(c->string,string)) c=c->next; return c;} | ||||
| 
 | ||||
| /* Utility for array list handling. */ | ||||
| static void suffix_object(cJSON *prev,cJSON *item) {prev->next=item;item->prev=prev;} | ||||
| /* Utility for handling references. */ | ||||
| static cJSON *create_reference(cJSON *item) {cJSON *ref=cJSON_New_Item();if (!ref) return 0;memcpy(ref,item,sizeof(cJSON));ref->string=0;ref->type|=cJSON_IsReference;ref->next=ref->prev=0;return ref;} | ||||
| 
 | ||||
| /* Add item to array/object. */ | ||||
| void   cJSON_AddItemToArray(cJSON *array, cJSON *item)						{cJSON *c=array->child;if (!item) return; if (!c) {array->child=item;} else {while (c && c->next) c=c->next; suffix_object(c,item);}} | ||||
| void   cJSON_AddItemToObject(cJSON *object,const char *string,cJSON *item)	{if (!item) return; if (item->string) cJSON_free(item->string);item->string=cJSON_strdup(string);cJSON_AddItemToArray(object,item);} | ||||
| void	cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item)						{cJSON_AddItemToArray(array,create_reference(item));} | ||||
| void	cJSON_AddItemReferenceToObject(cJSON *object,const char *string,cJSON *item)	{cJSON_AddItemToObject(object,string,create_reference(item));} | ||||
| 
 | ||||
| cJSON *cJSON_DetachItemFromArray(cJSON *array,int which)			{cJSON *c=array->child;while (c && which>0) c=c->next,which--;if (!c) return 0; | ||||
| 	if (c->prev) c->prev->next=c->next;if (c->next) c->next->prev=c->prev;if (c==array->child) array->child=c->next;c->prev=c->next=0;return c;} | ||||
| void   cJSON_DeleteItemFromArray(cJSON *array,int which)			{cJSON_Delete(cJSON_DetachItemFromArray(array,which));} | ||||
| cJSON *cJSON_DetachItemFromObject(cJSON *object,const char *string) {int i=0;cJSON *c=object->child;while (c && cJSON_strcasecmp(c->string,string)) i++,c=c->next;if (c) return cJSON_DetachItemFromArray(object,i);return 0;} | ||||
| void   cJSON_DeleteItemFromObject(cJSON *object,const char *string) {cJSON_Delete(cJSON_DetachItemFromObject(object,string));} | ||||
| 
 | ||||
| /* Replace array/object items with new ones. */ | ||||
| void   cJSON_ReplaceItemInArray(cJSON *array,int which,cJSON *newitem)		{cJSON *c=array->child;while (c && which>0) c=c->next,which--;if (!c) return; | ||||
| 	newitem->next=c->next;newitem->prev=c->prev;if (newitem->next) newitem->next->prev=newitem; | ||||
| 	if (c==array->child) array->child=newitem; else newitem->prev->next=newitem;c->next=c->prev=0;cJSON_Delete(c);} | ||||
| void   cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem){int i=0;cJSON *c=object->child;while(c && cJSON_strcasecmp(c->string,string))i++,c=c->next;if(c){newitem->string=cJSON_strdup(string);cJSON_ReplaceItemInArray(object,i,newitem);}} | ||||
| 
 | ||||
| /* Create basic types: */ | ||||
| cJSON *cJSON_CreateNull(void)					{cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_NULL;return item;} | ||||
| cJSON *cJSON_CreateTrue(void)					{cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_True;return item;} | ||||
| cJSON *cJSON_CreateFalse(void)					{cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_False;return item;} | ||||
| cJSON *cJSON_CreateBool(int b)					{cJSON *item=cJSON_New_Item();if(item)item->type=b?cJSON_True:cJSON_False;return item;} | ||||
| cJSON *cJSON_CreateNumber(double num)			{cJSON *item=cJSON_New_Item();if(item){item->type=cJSON_Number;item->valuedouble=num;item->valueint=(int)num;}return item;} | ||||
| cJSON *cJSON_CreateString(const char *string)	{cJSON *item=cJSON_New_Item();if(item){item->type=cJSON_String;item->valuestring=cJSON_strdup(string);}return item;} | ||||
| cJSON *cJSON_CreateArray(void)					{cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_Array;return item;} | ||||
| cJSON *cJSON_CreateObject(void)					{cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_Object;return item;} | ||||
| 
 | ||||
| /* Create Arrays: */ | ||||
| cJSON *cJSON_CreateIntArray(int *numbers,int count)				{int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && i<count;i++){n=cJSON_CreateNumber(numbers[i]);if(!i)a->child=n;else suffix_object(p,n);p=n;}return a;} | ||||
| cJSON *cJSON_CreateFloatArray(float *numbers,int count)			{int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && i<count;i++){n=cJSON_CreateNumber(numbers[i]);if(!i)a->child=n;else suffix_object(p,n);p=n;}return a;} | ||||
| cJSON *cJSON_CreateDoubleArray(double *numbers,int count)		{int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && i<count;i++){n=cJSON_CreateNumber(numbers[i]);if(!i)a->child=n;else suffix_object(p,n);p=n;}return a;} | ||||
| cJSON *cJSON_CreateStringArray(const char **strings,int count)	{int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && i<count;i++){n=cJSON_CreateString(strings[i]);if(!i)a->child=n;else suffix_object(p,n);p=n;}return a;} | ||||
| 
 | ||||
| /* Duplication */ | ||||
| cJSON *cJSON_Duplicate(cJSON *item,int recurse) | ||||
| { | ||||
| 	cJSON *newitem,*cptr,*nptr=0,*newchild; | ||||
| 	/* Bail on bad ptr */ | ||||
| 	if (!item) return 0; | ||||
| 	/* Create new item */ | ||||
| 	newitem=cJSON_New_Item(); | ||||
| 	if (!newitem) return 0; | ||||
| 	/* Copy over all vars */ | ||||
| 	newitem->type=item->type&(~cJSON_IsReference),newitem->valueint=item->valueint,newitem->valuedouble=item->valuedouble; | ||||
| 	if (item->valuestring)	{newitem->valuestring=cJSON_strdup(item->valuestring);	if (!newitem->valuestring)	{cJSON_Delete(newitem);return 0;}} | ||||
| 	if (item->string)		{newitem->string=cJSON_strdup(item->string);			if (!newitem->string)		{cJSON_Delete(newitem);return 0;}} | ||||
| 	/* If non-recursive, then we're done! */ | ||||
| 	if (!recurse) return newitem; | ||||
| 	/* Walk the ->next chain for the child. */ | ||||
| 	cptr=item->child; | ||||
| 	while (cptr) | ||||
| 	{ | ||||
| 		newchild=cJSON_Duplicate(cptr,1);		/* Duplicate (with recurse) each item in the ->next chain */ | ||||
| 		if (!newchild) {cJSON_Delete(newitem);return 0;} | ||||
| 		if (nptr)	{nptr->next=newchild,newchild->prev=nptr;nptr=newchild;}	/* If newitem->child already set, then crosswire ->prev and ->next and move on */ | ||||
| 		else		{newitem->child=newchild;nptr=newchild;}					/* Set newitem->child and move to it */ | ||||
| 		cptr=cptr->next; | ||||
| 	} | ||||
| 	return newitem; | ||||
| } | ||||
							
								
								
									
										140
									
								
								demos/ra_tls/grpc/v1.38.1/src/cpp/sgx/cJSON.h
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										140
									
								
								demos/ra_tls/grpc/v1.38.1/src/cpp/sgx/cJSON.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,140 @@ | ||||
| /*
 | ||||
|   Copyright (c) 2009 Dave Gamble | ||||
|   | ||||
|   Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
|   of this software and associated documentation files (the "Software"), to deal | ||||
|   in the Software without restriction, including without limitation the rights | ||||
|   to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||
|   copies of the Software, and to permit persons to whom the Software is | ||||
|   furnished to do so, subject to the following conditions: | ||||
|   | ||||
|   The above copyright notice and this permission notice shall be included in | ||||
|   all copies or substantial portions of the Software. | ||||
|   | ||||
|   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
|   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
|   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||
|   AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||
|   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||
|   OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||||
|   THE SOFTWARE. | ||||
| */ | ||||
| 
 | ||||
| #ifndef cJSON__h | ||||
| #define cJSON__h | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| extern "C" | ||||
| { | ||||
| #endif | ||||
| #include <stdio.h> | ||||
| /* cJSON Types: */ | ||||
| #define cJSON_False 0 | ||||
| #define cJSON_True 1 | ||||
| #define cJSON_NULL 2 | ||||
| #define cJSON_Number 3 | ||||
| #define cJSON_String 4 | ||||
| #define cJSON_Array 5 | ||||
| #define cJSON_Object 6 | ||||
| 	 | ||||
| #define cJSON_IsReference 256 | ||||
| 
 | ||||
| /* The cJSON structure: */ | ||||
| typedef struct cJSON { | ||||
| 	struct cJSON *next,*prev;	/* next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem */ | ||||
| 	struct cJSON *child;		/* An array or object item will have a child pointer pointing to a chain of the items in the array/object. */ | ||||
| 
 | ||||
| 	int type;					/* The type of the item, as above. */ | ||||
| 
 | ||||
| 	char *valuestring;			/* The item's string, if type==cJSON_String */ | ||||
| 	int valueint;				/* The item's number, if type==cJSON_Number */ | ||||
| 	double valuedouble;			/* The item's number, if type==cJSON_Number */ | ||||
| 
 | ||||
| 	char *string;				/* The item's name string, if this item is the child of, or is in the list of subitems of an object. */ | ||||
| } cJSON; | ||||
| 
 | ||||
| typedef struct cJSON_Hooks { | ||||
|       void *(*malloc_fn)(size_t sz); | ||||
|       void (*free_fn)(void *ptr); | ||||
| } cJSON_Hooks; | ||||
| 
 | ||||
| /* Supply malloc, realloc and free functions to cJSON */ | ||||
| extern void cJSON_InitHooks(cJSON_Hooks* hooks); | ||||
| 
 | ||||
| 
 | ||||
| /* Supply a block of JSON, and this returns a cJSON object you can interrogate. Call cJSON_Delete when finished. */ | ||||
| extern cJSON *cJSON_Parse(const char *value); | ||||
| /* Render a cJSON entity to text for transfer/storage. Free the char* when finished. */ | ||||
| extern char  *cJSON_Print(cJSON *item); | ||||
| /* Render a cJSON entity to text for transfer/storage without any formatting. Free the char* when finished. */ | ||||
| extern char  *cJSON_PrintUnformatted(cJSON *item); | ||||
| /* Delete a cJSON entity and all subentities. */ | ||||
| extern void   cJSON_Delete(cJSON *c); | ||||
| 
 | ||||
| /* Returns the number of items in an array (or object). */ | ||||
| extern int	  cJSON_GetArraySize(cJSON *array); | ||||
| /* Retrieve item number "item" from array "array". Returns NULL if unsuccessful. */ | ||||
| extern cJSON *cJSON_GetArrayItem(cJSON *array,int item); | ||||
| /* Get item "string" from object. Case insensitive. */ | ||||
| extern cJSON *cJSON_GetObjectItem(cJSON *object,const char *string); | ||||
| 
 | ||||
| /* For analysing failed parses. This returns a pointer to the parse error. You'll probably need to look a few chars back to make sense of it. Defined when cJSON_Parse() returns 0. 0 when cJSON_Parse() succeeds. */ | ||||
| extern const char *cJSON_GetErrorPtr(void); | ||||
| 	 | ||||
| /* These calls create a cJSON item of the appropriate type. */ | ||||
| extern cJSON *cJSON_CreateNull(void); | ||||
| extern cJSON *cJSON_CreateTrue(void); | ||||
| extern cJSON *cJSON_CreateFalse(void); | ||||
| extern cJSON *cJSON_CreateBool(int b); | ||||
| extern cJSON *cJSON_CreateNumber(double num); | ||||
| extern cJSON *cJSON_CreateString(const char *string); | ||||
| extern cJSON *cJSON_CreateArray(void); | ||||
| extern cJSON *cJSON_CreateObject(void); | ||||
| 
 | ||||
| /* These utilities create an Array of count items. */ | ||||
| extern cJSON *cJSON_CreateIntArray(int *numbers,int count); | ||||
| extern cJSON *cJSON_CreateFloatArray(float *numbers,int count); | ||||
| extern cJSON *cJSON_CreateDoubleArray(double *numbers,int count); | ||||
| extern cJSON *cJSON_CreateStringArray(const char **strings,int count); | ||||
| 
 | ||||
| /* Append item to the specified array/object. */ | ||||
| extern void cJSON_AddItemToArray(cJSON *array, cJSON *item); | ||||
| extern void	cJSON_AddItemToObject(cJSON *object,const char *string,cJSON *item); | ||||
| /* Append reference to item to the specified array/object. Use this when you want to add an existing cJSON to a new cJSON, but don't want to corrupt your existing cJSON. */ | ||||
| extern void cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item); | ||||
| extern void	cJSON_AddItemReferenceToObject(cJSON *object,const char *string,cJSON *item); | ||||
| 
 | ||||
| /* Remove/Detatch items from Arrays/Objects. */ | ||||
| extern cJSON *cJSON_DetachItemFromArray(cJSON *array,int which); | ||||
| extern void   cJSON_DeleteItemFromArray(cJSON *array,int which); | ||||
| extern cJSON *cJSON_DetachItemFromObject(cJSON *object,const char *string); | ||||
| extern void   cJSON_DeleteItemFromObject(cJSON *object,const char *string); | ||||
| 	 | ||||
| /* Update array items. */ | ||||
| extern void cJSON_ReplaceItemInArray(cJSON *array,int which,cJSON *newitem); | ||||
| extern void cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem); | ||||
| 
 | ||||
| /* Duplicate a cJSON item */ | ||||
| extern cJSON *cJSON_Duplicate(cJSON *item,int recurse); | ||||
| /* Duplicate will create a new, identical cJSON item to the one you pass, in new memory that will
 | ||||
| need to be released. With recurse!=0, it will duplicate any children connected to the item. | ||||
| The item->next and ->prev pointers are always zero on return from Duplicate. */ | ||||
| 
 | ||||
| /* ParseWithOpts allows you to require (and check) that the JSON is null terminated, and to retrieve the pointer to the final byte parsed. */ | ||||
| extern cJSON *cJSON_ParseWithOpts(const char *value,const char **return_parse_end,int require_null_terminated); | ||||
| 
 | ||||
| /* Macros for creating things quickly. */ | ||||
| #define cJSON_AddNullToObject(object,name)		cJSON_AddItemToObject(object, name, cJSON_CreateNull()) | ||||
| #define cJSON_AddTrueToObject(object,name)		cJSON_AddItemToObject(object, name, cJSON_CreateTrue()) | ||||
| #define cJSON_AddFalseToObject(object,name)		cJSON_AddItemToObject(object, name, cJSON_CreateFalse()) | ||||
| #define cJSON_AddBoolToObject(object,name,b)	cJSON_AddItemToObject(object, name, cJSON_CreateBool(b)) | ||||
| #define cJSON_AddNumberToObject(object,name,n)	cJSON_AddItemToObject(object, name, cJSON_CreateNumber(n)) | ||||
| #define cJSON_AddStringToObject(object,name,s)	cJSON_AddItemToObject(object, name, cJSON_CreateString(s)) | ||||
| 
 | ||||
| /* When assigning an integer value, it needs to be propagated to valuedouble too. */ | ||||
| #define cJSON_SetIntValue(object,val)			((object)?(object)->valueint=(object)->valuedouble=(val):(val)) | ||||
| #ifdef __cplusplus | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| #endif | ||||
							
								
								
									
										567
									
								
								demos/ra_tls/grpc/v1.38.1/src/cpp/sgx/cjson/cJSON.c
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										567
									
								
								demos/ra_tls/grpc/v1.38.1/src/cpp/sgx/cjson/cJSON.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,567 @@ | ||||
| /*
 | ||||
|   Copyright (c) 2009 Dave Gamble | ||||
| 
 | ||||
|   Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
|   of this software and associated documentation files (the "Software"), to deal | ||||
|   in the Software without restriction, including without limitation the rights | ||||
|   to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||
|   copies of the Software, and to permit persons to whom the Software is | ||||
|   furnished to do so, subject to the following conditions: | ||||
| 
 | ||||
|   The above copyright notice and this permission notice shall be included in | ||||
|   all copies or substantial portions of the Software. | ||||
| 
 | ||||
|   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
|   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
|   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||
|   AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||
|   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||
|   OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||||
|   THE SOFTWARE. | ||||
| */ | ||||
| 
 | ||||
| /* cJSON */ | ||||
| /* JSON parser in C. */ | ||||
| 
 | ||||
| #include <string.h> | ||||
| #include <stdio.h> | ||||
| #include <math.h> | ||||
| #include <stdlib.h> | ||||
| #include <float.h> | ||||
| #include <limits.h> | ||||
| #include <ctype.h> | ||||
| #include "cJSON.h" | ||||
| 
 | ||||
| static const char *ep; | ||||
| 
 | ||||
| const char *cJSON_GetErrorPtr(void) {return ep;} | ||||
| 
 | ||||
| static int cJSON_strcasecmp(const char *s1,const char *s2) | ||||
| { | ||||
| 	if (!s1) return (s1==s2)?0:1;if (!s2) return 1; | ||||
| 	for(; tolower(*s1) == tolower(*s2); ++s1, ++s2)	if(*s1 == 0)	return 0; | ||||
| 	return tolower(*(const unsigned char *)s1) - tolower(*(const unsigned char *)s2); | ||||
| } | ||||
| 
 | ||||
| static void *(*cJSON_malloc)(size_t sz) = malloc; | ||||
| static void (*cJSON_free)(void *ptr) = free; | ||||
| 
 | ||||
| static char* cJSON_strdup(const char* str) | ||||
| { | ||||
|       size_t len; | ||||
|       char* copy; | ||||
| 
 | ||||
|       len = strlen(str) + 1; | ||||
|       if (!(copy = (char*)cJSON_malloc(len))) return 0; | ||||
|       memcpy(copy,str,len); | ||||
|       return copy; | ||||
| } | ||||
| 
 | ||||
| void cJSON_InitHooks(cJSON_Hooks* hooks) | ||||
| { | ||||
|     if (!hooks) { /* Reset hooks */ | ||||
|         cJSON_malloc = malloc; | ||||
|         cJSON_free = free; | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
| 	cJSON_malloc = (hooks->malloc_fn)?hooks->malloc_fn:malloc; | ||||
| 	cJSON_free	 = (hooks->free_fn)?hooks->free_fn:free; | ||||
| } | ||||
| 
 | ||||
| /* Internal constructor. */ | ||||
| static cJSON *cJSON_New_Item(void) | ||||
| { | ||||
| 	cJSON* node = (cJSON*)cJSON_malloc(sizeof(cJSON)); | ||||
| 	if (node) memset(node,0,sizeof(cJSON)); | ||||
| 	return node; | ||||
| } | ||||
| 
 | ||||
| /* Delete a cJSON structure. */ | ||||
| void cJSON_Delete(cJSON *c) | ||||
| { | ||||
| 	cJSON *next; | ||||
| 	while (c) | ||||
| 	{ | ||||
| 		next=c->next; | ||||
| 		if (!(c->type&cJSON_IsReference) && c->child) cJSON_Delete(c->child); | ||||
| 		if (!(c->type&cJSON_IsReference) && c->valuestring) cJSON_free(c->valuestring); | ||||
| 		if (c->string) cJSON_free(c->string); | ||||
| 		cJSON_free(c); | ||||
| 		c=next; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| /* Parse the input text to generate a number, and populate the result into item. */ | ||||
| static const char *parse_number(cJSON *item,const char *num) | ||||
| { | ||||
| 	double n=0,sign=1,scale=0;int subscale=0,signsubscale=1; | ||||
| 
 | ||||
| 	/* Could use sscanf for this? */ | ||||
| 	if (*num=='-') sign=-1,num++;	/* Has sign? */ | ||||
| 	if (*num=='0') num++;			/* is zero */ | ||||
| 	if (*num>='1' && *num<='9')	do	n=(n*10.0)+(*num++ -'0');	while (*num>='0' && *num<='9');	/* Number? */ | ||||
| 	if (*num=='.' && num[1]>='0' && num[1]<='9') {num++;		do	n=(n*10.0)+(*num++ -'0'),scale--; while (*num>='0' && *num<='9');}	/* Fractional part? */ | ||||
| 	if (*num=='e' || *num=='E')		/* Exponent? */ | ||||
| 	{	num++;if (*num=='+') num++;	else if (*num=='-') signsubscale=-1,num++;		/* With sign? */ | ||||
| 		while (*num>='0' && *num<='9') subscale=(subscale*10)+(*num++ - '0');	/* Number? */ | ||||
| 	} | ||||
| 
 | ||||
| 	n=sign*n*pow(10.0,(scale+subscale*signsubscale));	/* number = +/- number.fraction * 10^+/- exponent */ | ||||
| 	 | ||||
| 	item->valuedouble=n; | ||||
| 	item->valueint=(int)n; | ||||
| 	item->type=cJSON_Number; | ||||
| 	return num; | ||||
| } | ||||
| 
 | ||||
| /* Render the number nicely from the given item into a string. */ | ||||
| static char *print_number(cJSON *item) | ||||
| { | ||||
| 	char *str; | ||||
| 	double d=item->valuedouble; | ||||
| 	if (fabs(((double)item->valueint)-d)<=DBL_EPSILON && d<=INT_MAX && d>=INT_MIN) | ||||
| 	{ | ||||
| 		str=(char*)cJSON_malloc(21);	/* 2^64+1 can be represented in 21 chars. */ | ||||
| 		if (str) sprintf(str,"%d",item->valueint); | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		str=(char*)cJSON_malloc(64);	/* This is a nice tradeoff. */ | ||||
| 		if (str) | ||||
| 		{ | ||||
| 			if (fabs(floor(d)-d)<=DBL_EPSILON && fabs(d)<1.0e60)sprintf(str,"%.0f",d); | ||||
| 			else if (fabs(d)<1.0e-6 || fabs(d)>1.0e9)			sprintf(str,"%e",d); | ||||
| 			else												sprintf(str,"%f",d); | ||||
| 		} | ||||
| 	} | ||||
| 	return str; | ||||
| } | ||||
| 
 | ||||
| /* Parse the input text into an unescaped cstring, and populate item. */ | ||||
| static const unsigned char firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC }; | ||||
| static const char *parse_string(cJSON *item,const char *str) | ||||
| { | ||||
| 	const char *ptr=str+1;char *ptr2;char *out;int len=0;unsigned uc,uc2; | ||||
| 	if (*str!='\"') {ep=str;return 0;}	/* not a string! */ | ||||
| 	 | ||||
| 	while (*ptr!='\"' && *ptr && ++len) if (*ptr++ == '\\') ptr++;	/* Skip escaped quotes. */ | ||||
| 	 | ||||
| 	out=(char*)cJSON_malloc(len+1);	/* This is how long we need for the string, roughly. */ | ||||
| 	if (!out) return 0; | ||||
| 	 | ||||
| 	ptr=str+1;ptr2=out; | ||||
| 	while (*ptr!='\"' && *ptr) | ||||
| 	{ | ||||
| 		if (*ptr!='\\') *ptr2++=*ptr++; | ||||
| 		else | ||||
| 		{ | ||||
| 			ptr++; | ||||
| 			switch (*ptr) | ||||
| 			{ | ||||
| 				case 'b': *ptr2++='\b';	break; | ||||
| 				case 'f': *ptr2++='\f';	break; | ||||
| 				case 'n': *ptr2++='\n';	break; | ||||
| 				case 'r': *ptr2++='\r';	break; | ||||
| 				case 't': *ptr2++='\t';	break; | ||||
| 				case 'u':	 /* transcode utf16 to utf8. */ | ||||
| 					sscanf(ptr+1,"%4x",&uc);ptr+=4;	/* get the unicode char. */ | ||||
| 
 | ||||
| 					if ((uc>=0xDC00 && uc<=0xDFFF) || uc==0)	break;	/* check for invalid.	*/ | ||||
| 
 | ||||
| 					if (uc>=0xD800 && uc<=0xDBFF)	/* UTF16 surrogate pairs.	*/ | ||||
| 					{ | ||||
| 						if (ptr[1]!='\\' || ptr[2]!='u')	break;	/* missing second-half of surrogate.	*/ | ||||
| 						sscanf(ptr+3,"%4x",&uc2);ptr+=6; | ||||
| 						if (uc2<0xDC00 || uc2>0xDFFF)		break;	/* invalid second-half of surrogate.	*/ | ||||
| 						uc=0x10000 + (((uc&0x3FF)<<10) | (uc2&0x3FF)); | ||||
| 					} | ||||
| 
 | ||||
| 					len=4;if (uc<0x80) len=1;else if (uc<0x800) len=2;else if (uc<0x10000) len=3; ptr2+=len; | ||||
| 					 | ||||
| 					switch (len) { | ||||
| 						case 4: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6; | ||||
| 						case 3: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6; | ||||
| 						case 2: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6; | ||||
| 						case 1: *--ptr2 =(uc | firstByteMark[len]); | ||||
| 					} | ||||
| 					ptr2+=len; | ||||
| 					break; | ||||
| 				default:  *ptr2++=*ptr; break; | ||||
| 			} | ||||
| 			ptr++; | ||||
| 		} | ||||
| 	} | ||||
| 	*ptr2=0; | ||||
| 	if (*ptr=='\"') ptr++; | ||||
| 	item->valuestring=out; | ||||
| 	item->type=cJSON_String; | ||||
| 	return ptr; | ||||
| } | ||||
| 
 | ||||
| /* Render the cstring provided to an escaped version that can be printed. */ | ||||
| static char *print_string_ptr(const char *str) | ||||
| { | ||||
| 	const char *ptr;char *ptr2,*out;int len=0;unsigned char token; | ||||
| 	 | ||||
| 	if (!str) return cJSON_strdup(""); | ||||
| 	ptr=str;while ((token=*ptr) && ++len) {if (strchr("\"\\\b\f\n\r\t",token)) len++; else if (token<32) len+=5;ptr++;} | ||||
| 	 | ||||
| 	out=(char*)cJSON_malloc(len+3); | ||||
| 	if (!out) return 0; | ||||
| 
 | ||||
| 	ptr2=out;ptr=str; | ||||
| 	*ptr2++='\"'; | ||||
| 	while (*ptr) | ||||
| 	{ | ||||
| 		if ((unsigned char)*ptr>31 && *ptr!='\"' && *ptr!='\\') *ptr2++=*ptr++; | ||||
| 		else | ||||
| 		{ | ||||
| 			*ptr2++='\\'; | ||||
| 			switch (token=*ptr++) | ||||
| 			{ | ||||
| 				case '\\':	*ptr2++='\\';	break; | ||||
| 				case '\"':	*ptr2++='\"';	break; | ||||
| 				case '\b':	*ptr2++='b';	break; | ||||
| 				case '\f':	*ptr2++='f';	break; | ||||
| 				case '\n':	*ptr2++='n';	break; | ||||
| 				case '\r':	*ptr2++='r';	break; | ||||
| 				case '\t':	*ptr2++='t';	break; | ||||
| 				default: sprintf(ptr2,"u%04x",token);ptr2+=5;	break;	/* escape and print */ | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	*ptr2++='\"';*ptr2++=0; | ||||
| 	return out; | ||||
| } | ||||
| /* Invote print_string_ptr (which is useful) on an item. */ | ||||
| static char *print_string(cJSON *item)	{return print_string_ptr(item->valuestring);} | ||||
| 
 | ||||
| /* Predeclare these prototypes. */ | ||||
| static const char *parse_value(cJSON *item,const char *value); | ||||
| static char *print_value(cJSON *item,int depth,int fmt); | ||||
| static const char *parse_array(cJSON *item,const char *value); | ||||
| static char *print_array(cJSON *item,int depth,int fmt); | ||||
| static const char *parse_object(cJSON *item,const char *value); | ||||
| static char *print_object(cJSON *item,int depth,int fmt); | ||||
| 
 | ||||
| /* Utility to jump whitespace and cr/lf */ | ||||
| static const char *skip(const char *in) {while (in && *in && (unsigned char)*in<=32) in++; return in;} | ||||
| 
 | ||||
| /* Parse an object - create a new root, and populate. */ | ||||
| cJSON *cJSON_ParseWithOpts(const char *value,const char **return_parse_end,int require_null_terminated) | ||||
| { | ||||
| 	const char *end=0; | ||||
| 	cJSON *c=cJSON_New_Item(); | ||||
| 	ep=0; | ||||
| 	if (!c) return 0;       /* memory fail */ | ||||
| 
 | ||||
| 	end=parse_value(c,skip(value)); | ||||
| 	if (!end)	{cJSON_Delete(c);return 0;}	/* parse failure. ep is set. */ | ||||
| 
 | ||||
| 	/* if we require null-terminated JSON without appended garbage, skip and then check for a null terminator */ | ||||
| 	if (require_null_terminated) {end=skip(end);if (*end) {cJSON_Delete(c);ep=end;return 0;}} | ||||
| 	if (return_parse_end) *return_parse_end=end; | ||||
| 	return c; | ||||
| } | ||||
| /* Default options for cJSON_Parse */ | ||||
| cJSON *cJSON_Parse(const char *value) {return cJSON_ParseWithOpts(value,0,0);} | ||||
| 
 | ||||
| /* Render a cJSON item/entity/structure to text. */ | ||||
| char *cJSON_Print(cJSON *item)				{return print_value(item,0,1);} | ||||
| char *cJSON_PrintUnformatted(cJSON *item)	{return print_value(item,0,0);} | ||||
| 
 | ||||
| /* Parser core - when encountering text, process appropriately. */ | ||||
| static const char *parse_value(cJSON *item,const char *value) | ||||
| { | ||||
| 	if (!value)						return 0;	/* Fail on null. */ | ||||
| 	if (!strncmp(value,"null",4))	{ item->type=cJSON_NULL;  return value+4; } | ||||
| 	if (!strncmp(value,"false",5))	{ item->type=cJSON_False; return value+5; } | ||||
| 	if (!strncmp(value,"true",4))	{ item->type=cJSON_True; item->valueint=1;	return value+4; } | ||||
| 	if (*value=='\"')				{ return parse_string(item,value); } | ||||
| 	if (*value=='-' || (*value>='0' && *value<='9'))	{ return parse_number(item,value); } | ||||
| 	if (*value=='[')				{ return parse_array(item,value); } | ||||
| 	if (*value=='{')				{ return parse_object(item,value); } | ||||
| 
 | ||||
| 	ep=value;return 0;	/* failure. */ | ||||
| } | ||||
| 
 | ||||
| /* Render a value to text. */ | ||||
| static char *print_value(cJSON *item,int depth,int fmt) | ||||
| { | ||||
| 	char *out=0; | ||||
| 	if (!item) return 0; | ||||
| 	switch ((item->type)&255) | ||||
| 	{ | ||||
| 		case cJSON_NULL:	out=cJSON_strdup("null");	break; | ||||
| 		case cJSON_False:	out=cJSON_strdup("false");break; | ||||
| 		case cJSON_True:	out=cJSON_strdup("true"); break; | ||||
| 		case cJSON_Number:	out=print_number(item);break; | ||||
| 		case cJSON_String:	out=print_string(item);break; | ||||
| 		case cJSON_Array:	out=print_array(item,depth,fmt);break; | ||||
| 		case cJSON_Object:	out=print_object(item,depth,fmt);break; | ||||
| 	} | ||||
| 	return out; | ||||
| } | ||||
| 
 | ||||
| /* Build an array from input text. */ | ||||
| static const char *parse_array(cJSON *item,const char *value) | ||||
| { | ||||
| 	cJSON *child; | ||||
| 	if (*value!='[')	{ep=value;return 0;}	/* not an array! */ | ||||
| 
 | ||||
| 	item->type=cJSON_Array; | ||||
| 	value=skip(value+1); | ||||
| 	if (*value==']') return value+1;	/* empty array. */ | ||||
| 
 | ||||
| 	item->child=child=cJSON_New_Item(); | ||||
| 	if (!item->child) return 0;		 /* memory fail */ | ||||
| 	value=skip(parse_value(child,skip(value)));	/* skip any spacing, get the value. */ | ||||
| 	if (!value) return 0; | ||||
| 
 | ||||
| 	while (*value==',') | ||||
| 	{ | ||||
| 		cJSON *new_item; | ||||
| 		if (!(new_item=cJSON_New_Item())) return 0; 	/* memory fail */ | ||||
| 		child->next=new_item;new_item->prev=child;child=new_item; | ||||
| 		value=skip(parse_value(child,skip(value+1))); | ||||
| 		if (!value) return 0;	/* memory fail */ | ||||
| 	} | ||||
| 
 | ||||
| 	if (*value==']') return value+1;	/* end of array */ | ||||
| 	ep=value;return 0;	/* malformed. */ | ||||
| } | ||||
| 
 | ||||
| /* Render an array to text */ | ||||
| static char *print_array(cJSON *item,int depth,int fmt) | ||||
| { | ||||
| 	char **entries; | ||||
| 	char *out=0,*ptr,*ret;int len=5; | ||||
| 	cJSON *child=item->child; | ||||
| 	int numentries=0,i=0,fail=0; | ||||
| 	 | ||||
| 	/* How many entries in the array? */ | ||||
| 	while (child) numentries++,child=child->next; | ||||
| 	/* Explicitly handle numentries==0 */ | ||||
| 	if (!numentries) | ||||
| 	{ | ||||
| 		out=(char*)cJSON_malloc(3); | ||||
| 		if (out) strcpy(out,"[]"); | ||||
| 		return out; | ||||
| 	} | ||||
| 	/* Allocate an array to hold the values for each */ | ||||
| 	entries=(char**)cJSON_malloc(numentries*sizeof(char*)); | ||||
| 	if (!entries) return 0; | ||||
| 	memset(entries,0,numentries*sizeof(char*)); | ||||
| 	/* Retrieve all the results: */ | ||||
| 	child=item->child; | ||||
| 	while (child && !fail) | ||||
| 	{ | ||||
| 		ret=print_value(child,depth+1,fmt); | ||||
| 		entries[i++]=ret; | ||||
| 		if (ret) len+=strlen(ret)+2+(fmt?1:0); else fail=1; | ||||
| 		child=child->next; | ||||
| 	} | ||||
| 	 | ||||
| 	/* If we didn't fail, try to malloc the output string */ | ||||
| 	if (!fail) out=(char*)cJSON_malloc(len); | ||||
| 	/* If that fails, we fail. */ | ||||
| 	if (!out) fail=1; | ||||
| 
 | ||||
| 	/* Handle failure. */ | ||||
| 	if (fail) | ||||
| 	{ | ||||
| 		for (i=0;i<numentries;i++) if (entries[i]) cJSON_free(entries[i]); | ||||
| 		cJSON_free(entries); | ||||
| 		return 0; | ||||
| 	} | ||||
| 	 | ||||
| 	/* Compose the output array. */ | ||||
| 	*out='['; | ||||
| 	ptr=out+1;*ptr=0; | ||||
| 	for (i=0;i<numentries;i++) | ||||
| 	{ | ||||
| 		strcpy(ptr,entries[i]);ptr+=strlen(entries[i]); | ||||
| 		if (i!=numentries-1) {*ptr++=',';if(fmt)*ptr++=' ';*ptr=0;} | ||||
| 		cJSON_free(entries[i]); | ||||
| 	} | ||||
| 	cJSON_free(entries); | ||||
| 	*ptr++=']';*ptr++=0; | ||||
| 	return out;	 | ||||
| } | ||||
| 
 | ||||
| /* Build an object from the text. */ | ||||
| static const char *parse_object(cJSON *item,const char *value) | ||||
| { | ||||
| 	cJSON *child; | ||||
| 	if (*value!='{')	{ep=value;return 0;}	/* not an object! */ | ||||
| 	 | ||||
| 	item->type=cJSON_Object; | ||||
| 	value=skip(value+1); | ||||
| 	if (*value=='}') return value+1;	/* empty array. */ | ||||
| 	 | ||||
| 	item->child=child=cJSON_New_Item(); | ||||
| 	if (!item->child) return 0; | ||||
| 	value=skip(parse_string(child,skip(value))); | ||||
| 	if (!value) return 0; | ||||
| 	child->string=child->valuestring;child->valuestring=0; | ||||
| 	if (*value!=':') {ep=value;return 0;}	/* fail! */ | ||||
| 	value=skip(parse_value(child,skip(value+1)));	/* skip any spacing, get the value. */ | ||||
| 	if (!value) return 0; | ||||
| 	 | ||||
| 	while (*value==',') | ||||
| 	{ | ||||
| 		cJSON *new_item; | ||||
| 		if (!(new_item=cJSON_New_Item()))	return 0; /* memory fail */ | ||||
| 		child->next=new_item;new_item->prev=child;child=new_item; | ||||
| 		value=skip(parse_string(child,skip(value+1))); | ||||
| 		if (!value) return 0; | ||||
| 		child->string=child->valuestring;child->valuestring=0; | ||||
| 		if (*value!=':') {ep=value;return 0;}	/* fail! */ | ||||
| 		value=skip(parse_value(child,skip(value+1)));	/* skip any spacing, get the value. */ | ||||
| 		if (!value) return 0; | ||||
| 	} | ||||
| 	 | ||||
| 	if (*value=='}') return value+1;	/* end of array */ | ||||
| 	ep=value;return 0;	/* malformed. */ | ||||
| } | ||||
| 
 | ||||
| /* Render an object to text. */ | ||||
| static char *print_object(cJSON *item,int depth,int fmt) | ||||
| { | ||||
| 	char **entries=0,**names=0; | ||||
| 	char *out=0,*ptr,*ret,*str;int len=7,i=0,j; | ||||
| 	cJSON *child=item->child; | ||||
| 	int numentries=0,fail=0; | ||||
| 	/* Count the number of entries. */ | ||||
| 	while (child) numentries++,child=child->next; | ||||
| 	/* Explicitly handle empty object case */ | ||||
| 	if (!numentries) | ||||
| 	{ | ||||
| 		out=(char*)cJSON_malloc(fmt?depth+3:3); | ||||
| 		if (!out)	return 0; | ||||
| 		ptr=out;*ptr++='{'; | ||||
| 		if (fmt) {*ptr++='\n';for (i=0;i<depth-1;i++) *ptr++='\t';} | ||||
| 		*ptr++='}';*ptr++=0; | ||||
| 		return out; | ||||
| 	} | ||||
| 	/* Allocate space for the names and the objects */ | ||||
| 	entries=(char**)cJSON_malloc(numentries*sizeof(char*)); | ||||
| 	if (!entries) return 0; | ||||
| 	names=(char**)cJSON_malloc(numentries*sizeof(char*)); | ||||
| 	if (!names) {cJSON_free(entries);return 0;} | ||||
| 	memset(entries,0,sizeof(char*)*numentries); | ||||
| 	memset(names,0,sizeof(char*)*numentries); | ||||
| 
 | ||||
| 	/* Collect all the results into our arrays: */ | ||||
| 	child=item->child;depth++;if (fmt) len+=depth; | ||||
| 	while (child) | ||||
| 	{ | ||||
| 		names[i]=str=print_string_ptr(child->string); | ||||
| 		entries[i++]=ret=print_value(child,depth,fmt); | ||||
| 		if (str && ret) len+=strlen(ret)+strlen(str)+2+(fmt?2+depth:0); else fail=1; | ||||
| 		child=child->next; | ||||
| 	} | ||||
| 	 | ||||
| 	/* Try to allocate the output string */ | ||||
| 	if (!fail) out=(char*)cJSON_malloc(len); | ||||
| 	if (!out) fail=1; | ||||
| 
 | ||||
| 	/* Handle failure */ | ||||
| 	if (fail) | ||||
| 	{ | ||||
| 		for (i=0;i<numentries;i++) {if (names[i]) cJSON_free(names[i]);if (entries[i]) cJSON_free(entries[i]);} | ||||
| 		cJSON_free(names);cJSON_free(entries); | ||||
| 		return 0; | ||||
| 	} | ||||
| 	 | ||||
| 	/* Compose the output: */ | ||||
| 	*out='{';ptr=out+1;if (fmt)*ptr++='\n';*ptr=0; | ||||
| 	for (i=0;i<numentries;i++) | ||||
| 	{ | ||||
| 		if (fmt) for (j=0;j<depth;j++) *ptr++='\t'; | ||||
| 		strcpy(ptr,names[i]);ptr+=strlen(names[i]); | ||||
| 		*ptr++=':';if (fmt) *ptr++='\t'; | ||||
| 		strcpy(ptr,entries[i]);ptr+=strlen(entries[i]); | ||||
| 		if (i!=numentries-1) *ptr++=','; | ||||
| 		if (fmt) *ptr++='\n';*ptr=0; | ||||
| 		cJSON_free(names[i]);cJSON_free(entries[i]); | ||||
| 	} | ||||
| 	 | ||||
| 	cJSON_free(names);cJSON_free(entries); | ||||
| 	if (fmt) for (i=0;i<depth-1;i++) *ptr++='\t'; | ||||
| 	*ptr++='}';*ptr++=0; | ||||
| 	return out;	 | ||||
| } | ||||
| 
 | ||||
| /* Get Array size/item / object item. */ | ||||
| int    cJSON_GetArraySize(cJSON *array)							{cJSON *c=array->child;int i=0;while(c)i++,c=c->next;return i;} | ||||
| cJSON *cJSON_GetArrayItem(cJSON *array,int item)				{cJSON *c=array->child;  while (c && item>0) item--,c=c->next; return c;} | ||||
| cJSON *cJSON_GetObjectItem(cJSON *object,const char *string)	{cJSON *c=object->child; while (c && cJSON_strcasecmp(c->string,string)) c=c->next; return c;} | ||||
| 
 | ||||
| /* Utility for array list handling. */ | ||||
| static void suffix_object(cJSON *prev,cJSON *item) {prev->next=item;item->prev=prev;} | ||||
| /* Utility for handling references. */ | ||||
| static cJSON *create_reference(cJSON *item) {cJSON *ref=cJSON_New_Item();if (!ref) return 0;memcpy(ref,item,sizeof(cJSON));ref->string=0;ref->type|=cJSON_IsReference;ref->next=ref->prev=0;return ref;} | ||||
| 
 | ||||
| /* Add item to array/object. */ | ||||
| void   cJSON_AddItemToArray(cJSON *array, cJSON *item)						{cJSON *c=array->child;if (!item) return; if (!c) {array->child=item;} else {while (c && c->next) c=c->next; suffix_object(c,item);}} | ||||
| void   cJSON_AddItemToObject(cJSON *object,const char *string,cJSON *item)	{if (!item) return; if (item->string) cJSON_free(item->string);item->string=cJSON_strdup(string);cJSON_AddItemToArray(object,item);} | ||||
| void	cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item)						{cJSON_AddItemToArray(array,create_reference(item));} | ||||
| void	cJSON_AddItemReferenceToObject(cJSON *object,const char *string,cJSON *item)	{cJSON_AddItemToObject(object,string,create_reference(item));} | ||||
| 
 | ||||
| cJSON *cJSON_DetachItemFromArray(cJSON *array,int which)			{cJSON *c=array->child;while (c && which>0) c=c->next,which--;if (!c) return 0; | ||||
| 	if (c->prev) c->prev->next=c->next;if (c->next) c->next->prev=c->prev;if (c==array->child) array->child=c->next;c->prev=c->next=0;return c;} | ||||
| void   cJSON_DeleteItemFromArray(cJSON *array,int which)			{cJSON_Delete(cJSON_DetachItemFromArray(array,which));} | ||||
| cJSON *cJSON_DetachItemFromObject(cJSON *object,const char *string) {int i=0;cJSON *c=object->child;while (c && cJSON_strcasecmp(c->string,string)) i++,c=c->next;if (c) return cJSON_DetachItemFromArray(object,i);return 0;} | ||||
| void   cJSON_DeleteItemFromObject(cJSON *object,const char *string) {cJSON_Delete(cJSON_DetachItemFromObject(object,string));} | ||||
| 
 | ||||
| /* Replace array/object items with new ones. */ | ||||
| void   cJSON_ReplaceItemInArray(cJSON *array,int which,cJSON *newitem)		{cJSON *c=array->child;while (c && which>0) c=c->next,which--;if (!c) return; | ||||
| 	newitem->next=c->next;newitem->prev=c->prev;if (newitem->next) newitem->next->prev=newitem; | ||||
| 	if (c==array->child) array->child=newitem; else newitem->prev->next=newitem;c->next=c->prev=0;cJSON_Delete(c);} | ||||
| void   cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem){int i=0;cJSON *c=object->child;while(c && cJSON_strcasecmp(c->string,string))i++,c=c->next;if(c){newitem->string=cJSON_strdup(string);cJSON_ReplaceItemInArray(object,i,newitem);}} | ||||
| 
 | ||||
| /* Create basic types: */ | ||||
| cJSON *cJSON_CreateNull(void)					{cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_NULL;return item;} | ||||
| cJSON *cJSON_CreateTrue(void)					{cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_True;return item;} | ||||
| cJSON *cJSON_CreateFalse(void)					{cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_False;return item;} | ||||
| cJSON *cJSON_CreateBool(int b)					{cJSON *item=cJSON_New_Item();if(item)item->type=b?cJSON_True:cJSON_False;return item;} | ||||
| cJSON *cJSON_CreateNumber(double num)			{cJSON *item=cJSON_New_Item();if(item){item->type=cJSON_Number;item->valuedouble=num;item->valueint=(int)num;}return item;} | ||||
| cJSON *cJSON_CreateString(const char *string)	{cJSON *item=cJSON_New_Item();if(item){item->type=cJSON_String;item->valuestring=cJSON_strdup(string);}return item;} | ||||
| cJSON *cJSON_CreateArray(void)					{cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_Array;return item;} | ||||
| cJSON *cJSON_CreateObject(void)					{cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_Object;return item;} | ||||
| 
 | ||||
| /* Create Arrays: */ | ||||
| cJSON *cJSON_CreateIntArray(int *numbers,int count)				{int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && i<count;i++){n=cJSON_CreateNumber(numbers[i]);if(!i)a->child=n;else suffix_object(p,n);p=n;}return a;} | ||||
| cJSON *cJSON_CreateFloatArray(float *numbers,int count)			{int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && i<count;i++){n=cJSON_CreateNumber(numbers[i]);if(!i)a->child=n;else suffix_object(p,n);p=n;}return a;} | ||||
| cJSON *cJSON_CreateDoubleArray(double *numbers,int count)		{int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && i<count;i++){n=cJSON_CreateNumber(numbers[i]);if(!i)a->child=n;else suffix_object(p,n);p=n;}return a;} | ||||
| cJSON *cJSON_CreateStringArray(const char **strings,int count)	{int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && i<count;i++){n=cJSON_CreateString(strings[i]);if(!i)a->child=n;else suffix_object(p,n);p=n;}return a;} | ||||
| 
 | ||||
| /* Duplication */ | ||||
| cJSON *cJSON_Duplicate(cJSON *item,int recurse) | ||||
| { | ||||
| 	cJSON *newitem,*cptr,*nptr=0,*newchild; | ||||
| 	/* Bail on bad ptr */ | ||||
| 	if (!item) return 0; | ||||
| 	/* Create new item */ | ||||
| 	newitem=cJSON_New_Item(); | ||||
| 	if (!newitem) return 0; | ||||
| 	/* Copy over all vars */ | ||||
| 	newitem->type=item->type&(~cJSON_IsReference),newitem->valueint=item->valueint,newitem->valuedouble=item->valuedouble; | ||||
| 	if (item->valuestring)	{newitem->valuestring=cJSON_strdup(item->valuestring);	if (!newitem->valuestring)	{cJSON_Delete(newitem);return 0;}} | ||||
| 	if (item->string)		{newitem->string=cJSON_strdup(item->string);			if (!newitem->string)		{cJSON_Delete(newitem);return 0;}} | ||||
| 	/* If non-recursive, then we're done! */ | ||||
| 	if (!recurse) return newitem; | ||||
| 	/* Walk the ->next chain for the child. */ | ||||
| 	cptr=item->child; | ||||
| 	while (cptr) | ||||
| 	{ | ||||
| 		newchild=cJSON_Duplicate(cptr,1);		/* Duplicate (with recurse) each item in the ->next chain */ | ||||
| 		if (!newchild) {cJSON_Delete(newitem);return 0;} | ||||
| 		if (nptr)	{nptr->next=newchild,newchild->prev=nptr;nptr=newchild;}	/* If newitem->child already set, then crosswire ->prev and ->next and move on */ | ||||
| 		else		{newitem->child=newchild;nptr=newchild;}					/* Set newitem->child and move to it */ | ||||
| 		cptr=cptr->next; | ||||
| 	} | ||||
| 	return newitem; | ||||
| } | ||||
							
								
								
									
										140
									
								
								demos/ra_tls/grpc/v1.38.1/src/cpp/sgx/cjson/cJSON.h
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										140
									
								
								demos/ra_tls/grpc/v1.38.1/src/cpp/sgx/cjson/cJSON.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,140 @@ | ||||
| /*
 | ||||
|   Copyright (c) 2009 Dave Gamble | ||||
|   | ||||
|   Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
|   of this software and associated documentation files (the "Software"), to deal | ||||
|   in the Software without restriction, including without limitation the rights | ||||
|   to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||
|   copies of the Software, and to permit persons to whom the Software is | ||||
|   furnished to do so, subject to the following conditions: | ||||
|   | ||||
|   The above copyright notice and this permission notice shall be included in | ||||
|   all copies or substantial portions of the Software. | ||||
|   | ||||
|   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
|   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
|   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||
|   AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||
|   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||
|   OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||||
|   THE SOFTWARE. | ||||
| */ | ||||
| 
 | ||||
| #ifndef cJSON__h | ||||
| #define cJSON__h | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| extern "C" | ||||
| { | ||||
| #endif | ||||
| #include <stdio.h> | ||||
| /* cJSON Types: */ | ||||
| #define cJSON_False 0 | ||||
| #define cJSON_True 1 | ||||
| #define cJSON_NULL 2 | ||||
| #define cJSON_Number 3 | ||||
| #define cJSON_String 4 | ||||
| #define cJSON_Array 5 | ||||
| #define cJSON_Object 6 | ||||
| 	 | ||||
| #define cJSON_IsReference 256 | ||||
| 
 | ||||
| /* The cJSON structure: */ | ||||
| typedef struct cJSON { | ||||
| 	struct cJSON *next,*prev;	/* next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem */ | ||||
| 	struct cJSON *child;		/* An array or object item will have a child pointer pointing to a chain of the items in the array/object. */ | ||||
| 
 | ||||
| 	int type;					/* The type of the item, as above. */ | ||||
| 
 | ||||
| 	char *valuestring;			/* The item's string, if type==cJSON_String */ | ||||
| 	int valueint;				/* The item's number, if type==cJSON_Number */ | ||||
| 	double valuedouble;			/* The item's number, if type==cJSON_Number */ | ||||
| 
 | ||||
| 	char *string;				/* The item's name string, if this item is the child of, or is in the list of subitems of an object. */ | ||||
| } cJSON; | ||||
| 
 | ||||
| typedef struct cJSON_Hooks { | ||||
|       void *(*malloc_fn)(size_t sz); | ||||
|       void (*free_fn)(void *ptr); | ||||
| } cJSON_Hooks; | ||||
| 
 | ||||
| /* Supply malloc, realloc and free functions to cJSON */ | ||||
| extern void cJSON_InitHooks(cJSON_Hooks* hooks); | ||||
| 
 | ||||
| 
 | ||||
| /* Supply a block of JSON, and this returns a cJSON object you can interrogate. Call cJSON_Delete when finished. */ | ||||
| extern cJSON *cJSON_Parse(const char *value); | ||||
| /* Render a cJSON entity to text for transfer/storage. Free the char* when finished. */ | ||||
| extern char  *cJSON_Print(cJSON *item); | ||||
| /* Render a cJSON entity to text for transfer/storage without any formatting. Free the char* when finished. */ | ||||
| extern char  *cJSON_PrintUnformatted(cJSON *item); | ||||
| /* Delete a cJSON entity and all subentities. */ | ||||
| extern void   cJSON_Delete(cJSON *c); | ||||
| 
 | ||||
| /* Returns the number of items in an array (or object). */ | ||||
| extern int	  cJSON_GetArraySize(cJSON *array); | ||||
| /* Retrieve item number "item" from array "array". Returns NULL if unsuccessful. */ | ||||
| extern cJSON *cJSON_GetArrayItem(cJSON *array,int item); | ||||
| /* Get item "string" from object. Case insensitive. */ | ||||
| extern cJSON *cJSON_GetObjectItem(cJSON *object,const char *string); | ||||
| 
 | ||||
| /* For analysing failed parses. This returns a pointer to the parse error. You'll probably need to look a few chars back to make sense of it. Defined when cJSON_Parse() returns 0. 0 when cJSON_Parse() succeeds. */ | ||||
| extern const char *cJSON_GetErrorPtr(void); | ||||
| 	 | ||||
| /* These calls create a cJSON item of the appropriate type. */ | ||||
| extern cJSON *cJSON_CreateNull(void); | ||||
| extern cJSON *cJSON_CreateTrue(void); | ||||
| extern cJSON *cJSON_CreateFalse(void); | ||||
| extern cJSON *cJSON_CreateBool(int b); | ||||
| extern cJSON *cJSON_CreateNumber(double num); | ||||
| extern cJSON *cJSON_CreateString(const char *string); | ||||
| extern cJSON *cJSON_CreateArray(void); | ||||
| extern cJSON *cJSON_CreateObject(void); | ||||
| 
 | ||||
| /* These utilities create an Array of count items. */ | ||||
| extern cJSON *cJSON_CreateIntArray(int *numbers,int count); | ||||
| extern cJSON *cJSON_CreateFloatArray(float *numbers,int count); | ||||
| extern cJSON *cJSON_CreateDoubleArray(double *numbers,int count); | ||||
| extern cJSON *cJSON_CreateStringArray(const char **strings,int count); | ||||
| 
 | ||||
| /* Append item to the specified array/object. */ | ||||
| extern void cJSON_AddItemToArray(cJSON *array, cJSON *item); | ||||
| extern void	cJSON_AddItemToObject(cJSON *object,const char *string,cJSON *item); | ||||
| /* Append reference to item to the specified array/object. Use this when you want to add an existing cJSON to a new cJSON, but don't want to corrupt your existing cJSON. */ | ||||
| extern void cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item); | ||||
| extern void	cJSON_AddItemReferenceToObject(cJSON *object,const char *string,cJSON *item); | ||||
| 
 | ||||
| /* Remove/Detatch items from Arrays/Objects. */ | ||||
| extern cJSON *cJSON_DetachItemFromArray(cJSON *array,int which); | ||||
| extern void   cJSON_DeleteItemFromArray(cJSON *array,int which); | ||||
| extern cJSON *cJSON_DetachItemFromObject(cJSON *object,const char *string); | ||||
| extern void   cJSON_DeleteItemFromObject(cJSON *object,const char *string); | ||||
| 	 | ||||
| /* Update array items. */ | ||||
| extern void cJSON_ReplaceItemInArray(cJSON *array,int which,cJSON *newitem); | ||||
| extern void cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem); | ||||
| 
 | ||||
| /* Duplicate a cJSON item */ | ||||
| extern cJSON *cJSON_Duplicate(cJSON *item,int recurse); | ||||
| /* Duplicate will create a new, identical cJSON item to the one you pass, in new memory that will
 | ||||
| need to be released. With recurse!=0, it will duplicate any children connected to the item. | ||||
| The item->next and ->prev pointers are always zero on return from Duplicate. */ | ||||
| 
 | ||||
| /* ParseWithOpts allows you to require (and check) that the JSON is null terminated, and to retrieve the pointer to the final byte parsed. */ | ||||
| extern cJSON *cJSON_ParseWithOpts(const char *value,const char **return_parse_end,int require_null_terminated); | ||||
| 
 | ||||
| /* Macros for creating things quickly. */ | ||||
| #define cJSON_AddNullToObject(object,name)		cJSON_AddItemToObject(object, name, cJSON_CreateNull()) | ||||
| #define cJSON_AddTrueToObject(object,name)		cJSON_AddItemToObject(object, name, cJSON_CreateTrue()) | ||||
| #define cJSON_AddFalseToObject(object,name)		cJSON_AddItemToObject(object, name, cJSON_CreateFalse()) | ||||
| #define cJSON_AddBoolToObject(object,name,b)	cJSON_AddItemToObject(object, name, cJSON_CreateBool(b)) | ||||
| #define cJSON_AddNumberToObject(object,name,n)	cJSON_AddItemToObject(object, name, cJSON_CreateNumber(n)) | ||||
| #define cJSON_AddStringToObject(object,name,s)	cJSON_AddItemToObject(object, name, cJSON_CreateString(s)) | ||||
| 
 | ||||
| /* When assigning an integer value, it needs to be propagated to valuedouble too. */ | ||||
| #define cJSON_SetIntValue(object,val)			((object)?(object)->valueint=(object)->valuedouble=(val):(val)) | ||||
| #ifdef __cplusplus | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| #endif | ||||
							
								
								
									
										68
									
								
								demos/ra_tls/grpc/v1.38.1/src/cpp/sgx/sgx_ra_tls_backend.cc
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										68
									
								
								demos/ra_tls/grpc/v1.38.1/src/cpp/sgx/sgx_ra_tls_backend.cc
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,68 @@ | ||||
| #include "sgx_ra_tls_utils.h" | ||||
| #include "sgx_ra_tls_backend.h" | ||||
| #include "sgx_quote_3.h" | ||||
| #include "dcap_quote.h" | ||||
| 
 | ||||
| namespace grpc { | ||||
| namespace sgx { | ||||
| int 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) { | ||||
|         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) { | ||||
|         printf( "Error in dcap_verify_quote.\n"); | ||||
|     } | ||||
| 
 | ||||
|     if (collateral_expiration_status != 0) { | ||||
|         printf("the verification collateral has expired\n"); | ||||
|     } | ||||
|     dcap_quote_close(handle); | ||||
| } | ||||
| 
 | ||||
| int generate_quote(uint8_t *quote_buffer, unsigned char *hash, size_t hash_len) { | ||||
|   void *handle; | ||||
| 
 | ||||
|   handle = dcap_quote_open(); | ||||
| 
 | ||||
| 
 | ||||
|   sgx_report_data_t report_data = { 0 }; | ||||
|   memcpy(report_data.d, hash, hash_len); | ||||
| 
 | ||||
|   // Get the Quote
 | ||||
|   int ret = dcap_generate_quote(handle, quote_buffer, &report_data); | ||||
|   if (0 != ret) { | ||||
|     printf( "Error in dcap_generate_quote.\n"); | ||||
|   } | ||||
|   | ||||
|   dcap_quote_close(handle); | ||||
|   return ret; | ||||
| } | ||||
| 
 | ||||
| uint32_t get_quote_size() { | ||||
|   void *handle = dcap_quote_open(); | ||||
|   uint32_t quote_size = dcap_get_quote_size(handle); | ||||
|   dcap_quote_close(handle); | ||||
|   return quote_size; | ||||
| } | ||||
| 
 | ||||
| }//namespace grpc
 | ||||
| }//namesapce sgx
 | ||||
							
								
								
									
										41
									
								
								demos/ra_tls/grpc/v1.38.1/src/cpp/sgx/sgx_ra_tls_backend.h
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										41
									
								
								demos/ra_tls/grpc/v1.38.1/src/cpp/sgx/sgx_ra_tls_backend.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,41 @@ | ||||
| /*
 | ||||
|  * | ||||
|  * Copyright 2019 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 SGX_RA_TLS_BACKEND_H | ||||
| #define SGX_RA_TLS_BACKEND_H | ||||
| 
 | ||||
| #include <string> | ||||
| #include <memory> | ||||
| #include <sstream> | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| namespace grpc { | ||||
| namespace sgx { | ||||
| 
 | ||||
| int verify_quote (uint8_t * quote_buffer, size_t quote_size); | ||||
| 
 | ||||
| 
 | ||||
| int generate_quote(uint8_t *quote_buffer, unsigned char *hash, size_t hash_len); | ||||
| 
 | ||||
| 
 | ||||
| uint32_t get_quote_size(); | ||||
| 
 | ||||
| } | ||||
| } | ||||
| #endif  // SGX_RA_TLS_BACKEND_H
 | ||||
							
								
								
									
										233
									
								
								demos/ra_tls/grpc/v1.38.1/src/cpp/sgx/sgx_ra_tls_backends.cc
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										233
									
								
								demos/ra_tls/grpc/v1.38.1/src/cpp/sgx/sgx_ra_tls_backends.cc
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,233 @@ | ||||
| /*
 | ||||
|  * | ||||
|  * 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"); | ||||
| 
 | ||||
|     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); | ||||
|     }; | ||||
|     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) { | ||||
|     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) { | ||||
|             break; | ||||
|         } | ||||
|     } | ||||
|     return status; | ||||
| } | ||||
| 
 | ||||
| int verify_measurement(const char* mr_enclave, const char* mr_signer, | ||||
|                        const char* isv_prod_id, const char* isv_svn) { | ||||
|     std::lock_guard<std::mutex> lock(_ctx_.mtx); | ||||
|     bool status = false; | ||||
|     try { | ||||
|         assert(mr_enclave && mr_signer && isv_prod_id && isv_svn); | ||||
|         status = verify_measurement_internal(mr_enclave, mr_signer, isv_prod_id, isv_svn); | ||||
|         grpc_printf("remote sgx measurements\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)); | ||||
|         if (status) { | ||||
|             grpc_printf("  |- verify result  :  success\n"); | ||||
|         } else { | ||||
|             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
 | ||||
							
								
								
									
										109
									
								
								demos/ra_tls/grpc/v1.38.1/src/cpp/sgx/sgx_ra_tls_backends.h
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										109
									
								
								demos/ra_tls/grpc/v1.38.1/src/cpp/sgx/sgx_ra_tls_backends.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,109 @@ | ||||
| /*
 | ||||
|  * | ||||
|  * 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; | ||||
| }; | ||||
| 
 | ||||
| struct sgx_config { | ||||
|     bool verify_mr_enclave  = true; | ||||
|     bool verify_mr_signer   = true; | ||||
|     bool verify_isv_prod_id = true; | ||||
|     bool verify_isv_svn     = 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); | ||||
| 
 | ||||
| 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
 | ||||
| @ -0,0 +1,98 @@ | ||||
| /*
 | ||||
|  * | ||||
|  * Copyright (c) 2022 Intel Corporation | ||||
|  * | ||||
|  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|  * you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * | ||||
|  *     http://www.apache.org/licenses/LICENSE-2.0
 | ||||
|  * | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an "AS IS" BASIS, | ||||
|  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|  * See the License for the specific language governing permissions and | ||||
|  * limitations under the License. | ||||
|  * | ||||
|  */ | ||||
| 
 | ||||
| #include "sgx_ra_tls_backends.h" | ||||
| 
 | ||||
| namespace grpc { | ||||
| namespace sgx { | ||||
| 
 | ||||
| /*
 | ||||
| RA-TLS: on client, only need to register ra_tls_verify_callback() for cert verification | ||||
|   1. extract SGX quote from "quote" OID extension from crt | ||||
|   2. compare public key's hash from cert against quote's report_data | ||||
|   3. prepare user-supplied verification parameter "allow outdated TCB" | ||||
|   4. call into libsgx_dcap_quoteverify to verify ECDSA/based SGX quote | ||||
|   5. verify all measurements from the SGX quote | ||||
| */ | ||||
| 
 | ||||
| std::shared_ptr<grpc::ChannelCredentials> TlsCredentials(sgx_config sgx_cfg) { | ||||
|     grpc::sgx::CredentialsOptions options; | ||||
| 
 | ||||
|     ra_tls_parse_sgx_config(sgx_cfg); | ||||
| 
 | ||||
|     credential_option_set_certificate_provider(options); | ||||
| 
 | ||||
|     ra_tls_verify_init(); | ||||
|     credential_option_set_authorization_check(options); | ||||
| 
 | ||||
|     return grpc::experimental::TlsCredentials( | ||||
|         reinterpret_cast<const grpc::experimental::TlsChannelCredentialsOptions&>(options)); | ||||
| }; | ||||
| 
 | ||||
| std::shared_ptr<grpc::ChannelCredentials> TlsCredentials(const char* sgx_cfg_json) { | ||||
|     grpc::sgx::CredentialsOptions options; | ||||
| 
 | ||||
|     ra_tls_parse_sgx_config(sgx_cfg_json); | ||||
| 
 | ||||
|     credential_option_set_certificate_provider(options); | ||||
| 
 | ||||
|     ra_tls_verify_init(); | ||||
|     credential_option_set_authorization_check(options); | ||||
| 
 | ||||
|     return grpc::experimental::TlsCredentials( | ||||
|         reinterpret_cast<const grpc::experimental::TlsChannelCredentialsOptions&>(options)); | ||||
| }; | ||||
| 
 | ||||
| std::shared_ptr<grpc::ServerCredentials> TlsServerCredentials(sgx_config sgx_cfg) { | ||||
|     grpc::sgx::CredentialsOptions options; | ||||
| 
 | ||||
|     ra_tls_parse_sgx_config(sgx_cfg); | ||||
| 
 | ||||
|     credential_option_set_certificate_provider(options); | ||||
| 
 | ||||
|     ra_tls_verify_init(); | ||||
|     credential_option_set_authorization_check(options); | ||||
| 
 | ||||
|     return grpc::experimental::TlsServerCredentials( | ||||
|         reinterpret_cast<const grpc::experimental::TlsServerCredentialsOptions&>(options)); | ||||
| }; | ||||
| 
 | ||||
| std::shared_ptr<grpc::ServerCredentials> TlsServerCredentials(const char* sgx_cfg_json) { | ||||
|     grpc::sgx::CredentialsOptions options; | ||||
| 
 | ||||
|     ra_tls_parse_sgx_config(sgx_cfg_json); | ||||
| 
 | ||||
|     credential_option_set_certificate_provider(options); | ||||
| 
 | ||||
|     ra_tls_verify_init(); | ||||
|     credential_option_set_authorization_check(options); | ||||
| 
 | ||||
|     return grpc::experimental::TlsServerCredentials( | ||||
|         reinterpret_cast<const grpc::experimental::TlsServerCredentialsOptions&>(options)); | ||||
| }; | ||||
| 
 | ||||
| std::shared_ptr<grpc::Channel> CreateSecureChannel( | ||||
|     string target_str, std::shared_ptr<grpc::ChannelCredentials> channel_creds) { | ||||
|     GPR_ASSERT(channel_creds.get() != nullptr); | ||||
|     auto channel_args = grpc::ChannelArguments(); | ||||
|     channel_args.SetSslTargetNameOverride("RATLS"); | ||||
|     return grpc::CreateCustomChannel(target_str, std::move(channel_creds), channel_args); | ||||
| }; | ||||
| 
 | ||||
| } // namespace sgx
 | ||||
| } // namespace grpc
 | ||||
							
								
								
									
										318
									
								
								demos/ra_tls/grpc/v1.38.1/src/cpp/sgx/sgx_ra_tls_occlum.cc
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										318
									
								
								demos/ra_tls/grpc/v1.38.1/src/cpp/sgx/sgx_ra_tls_occlum.cc
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,318 @@ | ||||
| /*
 | ||||
|  * | ||||
|  * 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 "dcap_quote.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; | ||||
|     } | ||||
| 
 | ||||
|     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);  | ||||
|     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
 | ||||
							
								
								
									
										55
									
								
								demos/ra_tls/grpc/v1.38.1/src/cpp/sgx/sgx_ra_tls_options.cc
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										55
									
								
								demos/ra_tls/grpc/v1.38.1/src/cpp/sgx/sgx_ra_tls_options.cc
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,55 @@ | ||||
| /*
 | ||||
|  * | ||||
|  * Copyright (c) 2022 Intel Corporation | ||||
|  * | ||||
|  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|  * you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * | ||||
|  *     http://www.apache.org/licenses/LICENSE-2.0
 | ||||
|  * | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an "AS IS" BASIS, | ||||
|  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|  * See the License for the specific language governing permissions and | ||||
|  * limitations under the License. | ||||
|  * | ||||
|  */ | ||||
| 
 | ||||
| #include <grpc/grpc_security.h> | ||||
| #include <grpc/support/alloc.h> | ||||
| #include <grpcpp/security/sgx/sgx_ra_tls_options.h> | ||||
| 
 | ||||
| #include "absl/container/inlined_vector.h" | ||||
| #include "src/cpp/common/tls_credentials_options_util.h" | ||||
| 
 | ||||
| namespace grpc { | ||||
| namespace sgx { | ||||
| 
 | ||||
| void CredentialsOptions::set_verification_option( | ||||
|     grpc_tls_server_verification_option server_verification_option) { | ||||
|     grpc_tls_credentials_options* options = c_credentials_options(); | ||||
|     GPR_ASSERT(options != nullptr); | ||||
|     grpc_tls_credentials_options_set_server_verification_option( | ||||
|         options, server_verification_option); | ||||
| } | ||||
| 
 | ||||
| void CredentialsOptions::set_authorization_check_config( | ||||
|     std::shared_ptr<grpc::experimental::TlsServerAuthorizationCheckConfig> config) { | ||||
|     grpc_tls_credentials_options* options = c_credentials_options(); | ||||
|     GPR_ASSERT(options != nullptr); | ||||
|     if (config != nullptr) { | ||||
|         grpc_tls_credentials_options_set_server_authorization_check_config( | ||||
|             options, config->c_config()); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void CredentialsOptions::set_cert_request_type( | ||||
|     grpc_ssl_client_certificate_request_type cert_request_type) { | ||||
|     grpc_tls_credentials_options* options = c_credentials_options(); | ||||
|     GPR_ASSERT(options != nullptr); | ||||
|     grpc_tls_credentials_options_set_cert_request_type(options, cert_request_type); | ||||
| } | ||||
| 
 | ||||
| } // namespace sgx
 | ||||
| } // namespace grpc
 | ||||
							
								
								
									
										169
									
								
								demos/ra_tls/grpc/v1.38.1/src/cpp/sgx/sgx_ra_tls_utils.cc
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										169
									
								
								demos/ra_tls/grpc/v1.38.1/src/cpp/sgx/sgx_ra_tls_utils.cc
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,169 @@ | ||||
| /*
 | ||||
|  * | ||||
|  * Copyright (c) 2022 Intel Corporation | ||||
|  * | ||||
|  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|  * you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * | ||||
|  *     http://www.apache.org/licenses/LICENSE-2.0
 | ||||
|  * | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an "AS IS" BASIS, | ||||
|  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|  * See the License for the specific language governing permissions and | ||||
|  * limitations under the License. | ||||
|  * | ||||
|  */ | ||||
| 
 | ||||
| #include "sgx_ra_tls_utils.h" | ||||
| 
 | ||||
| #include <cstring> | ||||
| #include <iostream> | ||||
| #include <fstream> | ||||
| #include <sstream> | ||||
| 
 | ||||
| namespace grpc { | ||||
| namespace sgx { | ||||
| 
 | ||||
| void check_free(void* ptr) { | ||||
|     if (ptr) { | ||||
|         free(ptr); | ||||
|         ptr = nullptr; | ||||
|     }; | ||||
| } | ||||
| 
 | ||||
| bool hex_to_byte(const char *src, char *dst, size_t dst_size) { | ||||
|     if (std::strlen(src) < dst_size*2) { | ||||
|         return false; | ||||
|     } else { | ||||
|         for (auto i = 0; i < dst_size; i++) { | ||||
|             if (!isxdigit(src[i*2]) || !isxdigit(src[i*2+1])) { | ||||
|                 return false; | ||||
|             } else { | ||||
|                 sscanf(src+i*2, "%02hhx", dst+i); | ||||
|             } | ||||
|         } | ||||
|         return true; | ||||
|     } | ||||
| }; | ||||
| 
 | ||||
| void byte_to_hex(const char *src, char *dst, size_t src_size) { | ||||
|     for (auto i = 0; i < src_size; i++) { | ||||
|         sprintf(dst+i*2, "%02hhx", src[i]); | ||||
|     } | ||||
| }; | ||||
| 
 | ||||
| std::string byte_to_hex(const char *src, size_t src_size) { | ||||
|     char dst[src_size*2]; | ||||
|     memset(dst, 0, sizeof(dst)); | ||||
|     byte_to_hex(src, dst, src_size); | ||||
|     return std::string(dst); | ||||
| }; | ||||
| 
 | ||||
| library_engine::library_engine() : handle(nullptr), error(nullptr) {}; | ||||
| 
 | ||||
| library_engine::library_engine(const char* file, int mode) : handle(nullptr), error(nullptr) { | ||||
|     this->open(file, mode); | ||||
| } | ||||
| 
 | ||||
| library_engine::~library_engine() { | ||||
|     this->close(); | ||||
| } | ||||
| 
 | ||||
| void library_engine::open(const char* file, int mode) { | ||||
|     this->close(); | ||||
|     handle = dlopen(file, mode); | ||||
|     error = dlerror(); | ||||
|     if (error != nullptr || handle == nullptr) { | ||||
|         throw std::runtime_error("dlopen " + std::string(file) + " error, " + std::string(error)); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void library_engine::close() { | ||||
|     if (handle) { | ||||
|         dlclose(handle); | ||||
|     } | ||||
|     handle = nullptr; | ||||
|     error = nullptr; | ||||
| } | ||||
| 
 | ||||
| void* library_engine::get_func(const char* name) { | ||||
|   auto func = dlsym(handle, name); | ||||
|   error = dlerror(); | ||||
|   if (error != nullptr || func == nullptr) { | ||||
|     throw std::runtime_error("dlsym " + std::string(name) + " error, " + std::string(error)); | ||||
|     return nullptr; | ||||
|   } else { | ||||
|     return func; | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| void* library_engine::get_handle() { | ||||
|     return handle; | ||||
| } | ||||
| 
 | ||||
| json_engine::json_engine() : handle(nullptr) {}; | ||||
| 
 | ||||
| json_engine::json_engine(const char* file) : handle(nullptr){ | ||||
|     this->open(file); | ||||
| } | ||||
| 
 | ||||
| json_engine::~json_engine() { | ||||
|     this->close(); | ||||
| } | ||||
| 
 | ||||
| bool json_engine::open(const char* file) { | ||||
|     if (!file) { | ||||
|         grpc_printf("wrong json file path\n"); | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|     this->close(); | ||||
| 
 | ||||
|     auto file_ptr = fopen(file, "r"); | ||||
|     fseek(file_ptr, 0, SEEK_END); | ||||
|     auto length = ftell(file_ptr); | ||||
|     fseek(file_ptr, 0, SEEK_SET); | ||||
|     auto buffer = malloc(length); | ||||
|     fread(buffer, 1, length, file_ptr); | ||||
|     fclose(file_ptr); | ||||
| 
 | ||||
|     this->handle = cJSON_Parse((const char *)buffer); | ||||
| 
 | ||||
|     check_free(buffer); | ||||
| 
 | ||||
|     if (this->handle) { | ||||
|         return true; | ||||
|     } else { | ||||
|         grpc_printf("cjson open %s error: %s", file, cJSON_GetErrorPtr()); | ||||
|         return false; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void json_engine::close() { | ||||
|     if (this->handle) { | ||||
|         cJSON_Delete(this->handle); | ||||
|         this->handle = nullptr; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| cJSON* json_engine::get_handle() { | ||||
|     return this->handle; | ||||
| } | ||||
| 
 | ||||
| cJSON* json_engine::get_item(cJSON* obj, const char* item) { | ||||
|     return cJSON_GetObjectItem(obj, item); | ||||
| }; | ||||
| 
 | ||||
| char* json_engine::print_item(cJSON* obj) { | ||||
|     return cJSON_Print(obj); | ||||
| }; | ||||
| 
 | ||||
| bool json_engine::compare_item(cJSON* obj, const char* item) { | ||||
|     auto obj_item = this->print_item(obj); | ||||
|     return strncmp(obj_item+1, item, std::min(strlen(item), strlen(obj_item)-2)) == 0; | ||||
| }; | ||||
| 
 | ||||
| } // namespace sgx
 | ||||
| } // namespace grpc
 | ||||
							
								
								
									
										91
									
								
								demos/ra_tls/grpc/v1.38.1/src/cpp/sgx/sgx_ra_tls_utils.h
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										91
									
								
								demos/ra_tls/grpc/v1.38.1/src/cpp/sgx/sgx_ra_tls_utils.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,91 @@ | ||||
| /*
 | ||||
|  * | ||||
|  * 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 | ||||
| 
 | ||||
| namespace grpc { | ||||
| namespace sgx { | ||||
| 
 | ||||
| #include "cjson/cJSON.h" | ||||
| 
 | ||||
| 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; | ||||
| }; | ||||
| 
 | ||||
| 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; | ||||
| }; | ||||
| 
 | ||||
| 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
 | ||||
							
								
								
									
										59
									
								
								demos/ra_tls/prepare_and_build_package.sh
									
									
									
									
									
										Executable file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										59
									
								
								demos/ra_tls/prepare_and_build_package.sh
									
									
									
									
									
										Executable file
									
								
							| @ -0,0 +1,59 @@ | ||||
| #!/bin/bash | ||||
| INSTALL_PREFIX=/usr/local | ||||
| apt-get update \ | ||||
|     && apt-get install -y --no-install-recommends apt-utils \ | ||||
|     && apt-get install -y \ | ||||
|         ca-certificates \ | ||||
|         build-essential \ | ||||
|         autoconf \ | ||||
|         libtool \ | ||||
|         python3-pip \ | ||||
|         python3-dev \ | ||||
|         git \ | ||||
|         wget \ | ||||
|         unzip | ||||
| 
 | ||||
| mkdir -p ${INSTALL_PREFIX} \ | ||||
|     && wget -q -O cmake-linux.sh https://github.com/Kitware/CMake/releases/download/v3.19.6/cmake-3.19.6-Linux-x86_64.sh \ | ||||
|     && sh cmake-linux.sh -- --skip-license --prefix=${INSTALL_PREFIX} \ | ||||
|     && rm cmake-linux.sh | ||||
| 
 | ||||
| # Install cJSON | ||||
| CJSON_PATH=/cJSON | ||||
| git clone https://github.com/DaveGamble/cJSON.git ${CJSON_PATH} | ||||
| pushd ${CJSON_PATH} \ | ||||
|     && make static \ | ||||
|     && cp -r *.a ${INSTALL_PREFIX}/lib \ | ||||
|     && mkdir -p ${INSTALL_PREFIX}/include/cjson \ | ||||
|     && cp -r *.h ${INSTALL_PREFIX}/include/cjson | ||||
| popd | ||||
| 
 | ||||
| # GRPC env | ||||
| GRPC_VERSION=v1.38.x | ||||
| export GRPC_PATH=/grpc | ||||
| 
 | ||||
| # GRPC source code | ||||
| git clone https://github.com/grpc/grpc -b ${GRPC_VERSION} ${GRPC_PATH} | ||||
| pushd ${GRPC_PATH} \ | ||||
|     && pip3 install --upgrade pip setuptools==44.1.1 \ | ||||
|     && pip3 install -r requirements.txt \ | ||||
|     && git checkout v1.38.1 \ | ||||
|     && git submodule update --init | ||||
| popd | ||||
| 
 | ||||
| cp -rf grpc/common/* ${GRPC_PATH}/ | ||||
| cp -rf grpc/v1.38.1/* ${GRPC_PATH}/ | ||||
| 
 | ||||
| git clone  https://github.com/occlum/occlum | ||||
| pushd occlum | ||||
| make submodule | ||||
| cd demos/remote_attestation/dcap/dcap_lib | ||||
| cargo build --all-targets | ||||
| cp target/debug/libdcap_quote.a /usr/local/lib/ | ||||
| cp ../c_app/dcap_quote.h /usr/local/include/ | ||||
| popd | ||||
| 
 | ||||
| pushd ${GRPC_PATH}/examples/cpp/ratls | ||||
| ./build.sh | ||||
| popd | ||||
| 
 | ||||
							
								
								
									
										15
									
								
								demos/ra_tls/run.sh
									
									
									
									
									
										Executable file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										15
									
								
								demos/ra_tls/run.sh
									
									
									
									
									
										Executable file
									
								
							| @ -0,0 +1,15 @@ | ||||
| #!/bin/bash | ||||
| set -ex | ||||
| 
 | ||||
| postfix=$1 | ||||
| 
 | ||||
| if [ "$postfix" != "server" ] && [ "$postfix" != "client" ]; then | ||||
|     echo "input error args, it should be:"  | ||||
|     echo "./run.sh server" | ||||
|     echo "./run.sh client" | ||||
|     exit 1 | ||||
| fi | ||||
| 
 | ||||
| pushd occlum_instance_$postfix | ||||
| occlum run /bin/$postfix | ||||
| popd | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user