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() }} |       if: ${{ always() }} | ||||||
|       run: docker stop ${{ env.CONTAINER_NAME }} |       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: |   Stress_test_with_musl: | ||||||
|     if: github.event_name == 'schedule' |     if: github.event_name == 'schedule' | ||||||
|     runs-on: ${{ matrix.self_runner }} |     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