Enable the grpc ra-tls demo
Signed-off-by: yuanwu <yuan.wu@intel.com>
This commit is contained in:
parent
b62b5e23eb
commit
2810b8e4ce
48
.github/workflows/hw_mode_test.yml
vendored
48
.github/workflows/hw_mode_test.yml
vendored
@ -835,6 +835,54 @@ jobs:
|
||||
if: ${{ always() }}
|
||||
run: docker stop ${{ env.CONTAINER_NAME }}
|
||||
|
||||
RA_TLS_test:
|
||||
if: github.event_name == 'push' || ${{ contains(github.event.pull_request.labels.*.name, 'SGX-hardware-test-required') }}
|
||||
runs-on: ${{ matrix.self_runner }}
|
||||
strategy:
|
||||
matrix:
|
||||
self_runner: [[self-hosted, SGX2-HW]]
|
||||
|
||||
steps:
|
||||
- name: Clean before running
|
||||
run: |
|
||||
sudo chown -R ${{ secrets.CI_ADMIN }} "${{ github.workspace }}"
|
||||
|
||||
- name: Checkout code
|
||||
if: github.event_name == 'push'
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
submodules: true
|
||||
|
||||
- name: Checkout code from fork
|
||||
if: ${{ contains(github.event.pull_request.labels.*.name, 'SGX-hardware-test-required') }}
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
ref: refs/pull/${{ github.event.pull_request.number }}/merge
|
||||
submodules: true
|
||||
|
||||
- uses: ./.github/workflows/composite_action/hw
|
||||
with:
|
||||
container-name: ${{ github.job }}
|
||||
build-envs: 'OCCLUM_RELEASE_BUILD=1'
|
||||
|
||||
- name: Download and build the pakckages
|
||||
run: docker exec ${{ env.CONTAINER_NAME }} bash -c "cd /root/occlum/demos/ra_tls; ./prepare_and_build_package.sh"
|
||||
|
||||
- name: Build occlum instances
|
||||
run: docker exec ${{ env.CONTAINER_NAME }} bash -c "cd /root/occlum/demos/ra_tls; ./build_occlum_instance.sh"
|
||||
|
||||
- name: Run gRPC server
|
||||
run: docker exec ${{ env.CONTAINER_NAME }} bash -c "cd /root/occlum/demos/ra_tls; ./run.sh server &"
|
||||
|
||||
- name: Run gRPC client
|
||||
run: |
|
||||
sleep ${{ env.nap_time }};
|
||||
docker exec ${{ env.CONTAINER_NAME }} bash -c "cd /root/occlum/demos/ra_tls; ./run.sh client"
|
||||
|
||||
- name: Clean the environment
|
||||
if: ${{ always() }}
|
||||
run: docker stop ${{ env.CONTAINER_NAME }}
|
||||
|
||||
Stress_test_with_musl:
|
||||
if: github.event_name == 'schedule'
|
||||
runs-on: ${{ matrix.self_runner }}
|
||||
|
25
demos/ra_tls/README.md
Normal file
25
demos/ra_tls/README.md
Normal file
@ -0,0 +1,25 @@
|
||||
# gRPC Package With RA-TLS
|
||||
|
||||
|
||||
#### Executing the demo in Occlum
|
||||
|
||||
The following command will download the gRPC source code and apply the ra-tls patches, then build gRPC source code and demo.
|
||||
```
|
||||
./prepare_and_build_package.sh
|
||||
```
|
||||
|
||||
The following command will generate the client and server occlum images. It automatically parses the mr_enclave and mr_signer of the client, and write the value into dynamic_config.json. If you want to verify the other measurements of client, please modify the dynamic_config.json before run the script.
|
||||
```
|
||||
./build_occlum_instance.sh
|
||||
```
|
||||
|
||||
Run the gRPC server & client in occlum.
|
||||
|
||||
```
|
||||
./run.sh server &
|
||||
./run.sh client
|
||||
```
|
||||
|
||||
***Note:*** 1. The demo runs in the same machine by default. If you want to run server and client in different machines. Please modify the examples/cpp/ratls.
|
||||
2. If you want to test in your local network with your own PCCS server, you need to modify the /etc/sgx_default_qcnl.conf
|
||||
|
55
demos/ra_tls/build_occlum_instance.sh
Executable file
55
demos/ra_tls/build_occlum_instance.sh
Executable file
@ -0,0 +1,55 @@
|
||||
#!/bin/bash
|
||||
occlum_glibc=/opt/occlum/glibc/lib/
|
||||
set -ex
|
||||
|
||||
get_mr() {
|
||||
sgx_sign dump -enclave ../occlum_instance_$1/build/lib/libocclum-libos.signed.so -dumpfile ../metadata_info_$1.txt
|
||||
if [ "$2" == "mr_enclave" ]; then
|
||||
sed -n -e '/enclave_hash.m/,/metadata->enclave_css.body.isv_prod_id/p' ../metadata_info_$1.txt |head -3|tail -2|xargs|sed 's/0x//g'|sed 's/ //g'
|
||||
elif [ "$2" == "mr_signer" ]; then
|
||||
tail -2 ../metadata_info_$1.txt |xargs|sed 's/0x//g'|sed 's/ //g'
|
||||
fi
|
||||
}
|
||||
|
||||
build_instance() {
|
||||
# 1. Init Occlum Workspace
|
||||
rm -rf occlum_instance_$postfix
|
||||
mkdir occlum_instance_$postfix
|
||||
pushd occlum_instance_$postfix
|
||||
occlum init
|
||||
new_json="$(jq '.resource_limits.user_space_size = "320MB" |
|
||||
.process.default_mmap_size = "256MB"' Occlum.json)" && \
|
||||
echo "${new_json}" > Occlum.json
|
||||
# 2. Copy files into Occlum Workspace and Build
|
||||
#cp ../dynamic_config.json image/etc/dynamic_config.json
|
||||
cp ../dynamic_config.json image/dynamic_config.json
|
||||
#cp ../dynamic_config_$postfix.json image/dynamic_config.json
|
||||
if [ "$postfix" == "server" ]; then
|
||||
jq ' .verify_mr_enclave = "on" |
|
||||
.verify_mr_signer = "on" |
|
||||
.sgx_mrs[0].mr_enclave = ''"'`get_mr client mr_enclave`'" |
|
||||
.sgx_mrs[0].mr_signer = ''"'`get_mr client mr_signer`'" ' ../dynamic_config.json > image/dynamic_config.json
|
||||
fi
|
||||
mkdir -p image/usr/share/grpc
|
||||
cp -rf /share/grpc/* image/usr/share/grpc/
|
||||
cp $occlum_glibc/libdl.so.2 image/$occlum_glibc
|
||||
cp $occlum_glibc/librt.so.1 image/$occlum_glibc
|
||||
cp $occlum_glibc/libm.so.6 image/$occlum_glibc
|
||||
cp /lib/x86_64-linux-gnu/libtinfo.so.5 image/$occlum_glibc
|
||||
cp /lib/x86_64-linux-gnu/libnss*.so.2 image/$occlum_glibc
|
||||
cp /lib/x86_64-linux-gnu/libresolv.so.2 image/$occlum_glibc
|
||||
cp -rf /etc/hostname image/etc/
|
||||
cp -rf /etc/ssl image/etc/
|
||||
cp -rf /etc/passwd image/etc/
|
||||
cp -rf /etc/group image/etc/
|
||||
cp -rf /etc/nsswitch.conf image/etc/
|
||||
cp -rf /grpc/examples/cpp/ratls/build/* image/bin/
|
||||
occlum build
|
||||
popd
|
||||
}
|
||||
|
||||
postfix=client
|
||||
build_instance
|
||||
postfix=server
|
||||
build_instance
|
||||
|
15
demos/ra_tls/dynamic_config.json
Normal file
15
demos/ra_tls/dynamic_config.json
Normal file
@ -0,0 +1,15 @@
|
||||
{
|
||||
"verify_mr_enclave" : "off",
|
||||
"verify_mr_signer" : "off",
|
||||
"verify_isv_prod_id" : "off",
|
||||
"verify_isv_svn" : "off",
|
||||
"sgx_mrs": [
|
||||
{
|
||||
"mr_enclave" : "",
|
||||
"mr_signer" : "",
|
||||
"isv_prod_id" : "0",
|
||||
"isv_svn" : "0"
|
||||
}
|
||||
],
|
||||
"other" : []
|
||||
}
|
1
demos/ra_tls/grpc/.gitignore
vendored
Normal file
1
demos/ra_tls/grpc/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
grpc-*
|
46
demos/ra_tls/grpc/common/build_cpp.sh
Executable file
46
demos/ra_tls/grpc/common/build_cpp.sh
Executable file
@ -0,0 +1,46 @@
|
||||
#
|
||||
# Copyright (c) 2022 Intel Corporation
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
set -ex
|
||||
|
||||
export ABSEIL_PATH=${GRPC_PATH}/third_party/abseil-cpp
|
||||
|
||||
if [ ! -d "${BUILD_TYPE}" ]; then
|
||||
BUILD_TYPE=Release
|
||||
fi
|
||||
|
||||
# build and install abseil library
|
||||
# https://abseil.io/docs/cpp/quickstart-cmake.html
|
||||
if [ ! -d "${ABSEIL_PATH}/build" ]; then
|
||||
mkdir -p ${ABSEIL_PATH}/build
|
||||
cd ${ABSEIL_PATH}/build
|
||||
cmake -DCMAKE_CXX_STANDARD=11 -DCMAKE_POSITION_INDEPENDENT_CODE=TRUE \
|
||||
-DCMAKE_BUILD_TYPE=${BUILD_TYPE} -DCMAKE_INSTALL_PREFIX=${INSTALL_PREFIX} ..
|
||||
make -j `nproc`
|
||||
make install
|
||||
cd -
|
||||
fi
|
||||
|
||||
# build and install grpc library
|
||||
mkdir -p ${GRPC_PATH}/build
|
||||
cd ${GRPC_PATH}/build
|
||||
cmake -DgRPC_INSTALL=ON -DgRPC_ABSL_PROVIDER=package -DgRPC_BUILD_TESTS=OFF \
|
||||
-DgRPC_BUILD_CSHARP_EXT=OFF -DgRPC_BUILD_GRPC_CSHARP_PLUGIN=OFF \
|
||||
-DgRPC_BUILD_GRPC_PHP_PLUGIN=OFF -DgRPC_BUILD_GRPC_RUBY_PLUGIN=OFF \
|
||||
-DDEFINE_SGX_RA_TLS_OCCLUM_BACKEND=ON \
|
||||
-DCMAKE_BUILD_TYPE=${BUILD_TYPE} -DCMAKE_INSTALL_PREFIX=${INSTALL_PREFIX} ..
|
||||
make -j `nproc`
|
||||
make install
|
||||
cd -
|
15754
demos/ra_tls/grpc/v1.38.1/CMakeLists.txt
Normal file
15754
demos/ra_tls/grpc/v1.38.1/CMakeLists.txt
Normal file
File diff suppressed because it is too large
Load Diff
62
demos/ra_tls/grpc/v1.38.1/examples/cpp/ratls/CMakeLists.txt
Normal file
62
demos/ra_tls/grpc/v1.38.1/examples/cpp/ratls/CMakeLists.txt
Normal file
@ -0,0 +1,62 @@
|
||||
# Copyright (c) 2022 Intel Corporation
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
cmake_minimum_required(VERSION 3.5.1)
|
||||
|
||||
project(RA-TLS C CXX)
|
||||
|
||||
include(../cmake/common.cmake)
|
||||
|
||||
# Proto file
|
||||
get_filename_component(hw_proto "../../protos/ratls.proto" ABSOLUTE)
|
||||
get_filename_component(hw_proto_path "${hw_proto}" PATH)
|
||||
|
||||
# Generated sources
|
||||
set(hw_proto_srcs "${CMAKE_CURRENT_BINARY_DIR}/ratls.pb.cc")
|
||||
set(hw_proto_hdrs "${CMAKE_CURRENT_BINARY_DIR}/ratls.pb.h")
|
||||
set(hw_grpc_srcs "${CMAKE_CURRENT_BINARY_DIR}/ratls.grpc.pb.cc")
|
||||
set(hw_grpc_hdrs "${CMAKE_CURRENT_BINARY_DIR}/ratls.grpc.pb.h")
|
||||
add_custom_command(
|
||||
OUTPUT "${hw_proto_srcs}" "${hw_proto_hdrs}" "${hw_grpc_srcs}" "${hw_grpc_hdrs}"
|
||||
COMMAND ${_PROTOBUF_PROTOC}
|
||||
ARGS --grpc_out "${CMAKE_CURRENT_BINARY_DIR}"
|
||||
--cpp_out "${CMAKE_CURRENT_BINARY_DIR}"
|
||||
-I "${hw_proto_path}"
|
||||
--plugin=protoc-gen-grpc="${_GRPC_CPP_PLUGIN_EXECUTABLE}"
|
||||
"${hw_proto}"
|
||||
DEPENDS "${hw_proto}")
|
||||
|
||||
# Include generated *.pb.h files
|
||||
include_directories("${CMAKE_CURRENT_BINARY_DIR}")
|
||||
|
||||
# hw_grpc_proto
|
||||
add_library(hw_grpc_proto
|
||||
${hw_grpc_srcs}
|
||||
${hw_grpc_hdrs}
|
||||
${hw_proto_srcs}
|
||||
${hw_proto_hdrs})
|
||||
target_link_libraries(hw_grpc_proto
|
||||
${_REFLECTION}
|
||||
${_GRPC_GRPCPP}
|
||||
${_PROTOBUF_LIBPROTOBUF})
|
||||
|
||||
# Targets greeter_[async_](client|server)
|
||||
foreach(_target client server)
|
||||
add_executable(${_target} "${_target}.cc")
|
||||
target_link_libraries(${_target}
|
||||
hw_grpc_proto
|
||||
${_REFLECTION}
|
||||
${_GRPC_GRPCPP}
|
||||
${_PROTOBUF_LIBPROTOBUF})
|
||||
endforeach()
|
15
demos/ra_tls/grpc/v1.38.1/examples/cpp/ratls/README.md
Normal file
15
demos/ra_tls/grpc/v1.38.1/examples/cpp/ratls/README.md
Normal file
@ -0,0 +1,15 @@
|
||||
# gRPC
|
||||
|
||||
This directory contains the Makefile and the template manifest for the most
|
||||
recent version of gRPC (as of this writing, version 3.18.0). This was tested
|
||||
on a machine with SGX v1 and Ubuntu 18.04.
|
||||
|
||||
The Makefile and the template manifest contain extensive comments and are made
|
||||
self-explanatory. Please review them to gain understanding of Gramine-SGX
|
||||
and requirements for applications running under Gramine-SGX.
|
||||
|
||||
# Quick Start
|
||||
|
||||
```
|
||||
./build.sh
|
||||
```
|
29
demos/ra_tls/grpc/v1.38.1/examples/cpp/ratls/build.sh
Executable file
29
demos/ra_tls/grpc/v1.38.1/examples/cpp/ratls/build.sh
Executable file
@ -0,0 +1,29 @@
|
||||
#
|
||||
# Copyright (c) 2022 Intel Corporation
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
set -ex
|
||||
|
||||
export BUILD_TYPE=Release
|
||||
export EXP_PATH=`dirname $0`
|
||||
|
||||
${GRPC_PATH}/build_cpp.sh
|
||||
|
||||
# build c++ example
|
||||
cd ${EXP_PATH}
|
||||
mkdir -p build
|
||||
cd build
|
||||
cmake -D CMAKE_PREFIX_PATH=${INSTALL_PREFIX} -D CMAKE_BUILD_TYPE=${BUILD_TYPE} ..
|
||||
make -j `nproc`
|
||||
cd -
|
86
demos/ra_tls/grpc/v1.38.1/examples/cpp/ratls/client.cc
Normal file
86
demos/ra_tls/grpc/v1.38.1/examples/cpp/ratls/client.cc
Normal file
@ -0,0 +1,86 @@
|
||||
/*
|
||||
*
|
||||
* Copyright (c) 2022 Intel Corporation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <grpcpp/grpcpp.h>
|
||||
#include <grpcpp/security/sgx/sgx_ra_tls.h>
|
||||
|
||||
#ifdef BAZEL_BUILD
|
||||
#include "examples/protos/ratls.grpc.pb.h"
|
||||
#else
|
||||
#include "ratls.grpc.pb.h"
|
||||
#endif
|
||||
|
||||
#include "../getopt.hpp"
|
||||
|
||||
using ratls::Greeter;
|
||||
using ratls::HelloReply;
|
||||
using ratls::HelloRequest;
|
||||
|
||||
struct argparser {
|
||||
const char* config;
|
||||
std::string server_address;
|
||||
argparser() {
|
||||
server_address = getarg("localhost:50051", "-host", "--host");
|
||||
config = getarg("dynamic_config.json", "-cfg", "--config");
|
||||
};
|
||||
};
|
||||
|
||||
class GreeterClient {
|
||||
public:
|
||||
GreeterClient(std::shared_ptr<grpc::Channel> channel) : stub_(Greeter::NewStub(channel)) {}
|
||||
|
||||
std::string SayHello(const std::string& user) {
|
||||
HelloRequest request;
|
||||
request.set_name(user);
|
||||
|
||||
HelloReply reply;
|
||||
|
||||
grpc::ClientContext context;
|
||||
|
||||
grpc::Status status = stub_->SayHello(&context, request, &reply);
|
||||
|
||||
if (status.ok()) {
|
||||
return reply.message();
|
||||
} else {
|
||||
std::cout << status.error_code() << ": " << status.error_message() << std::endl;
|
||||
return "RPC failed";
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
std::unique_ptr<Greeter::Stub> stub_;
|
||||
};
|
||||
|
||||
void run_client() {
|
||||
argparser args;
|
||||
|
||||
auto cred = grpc::sgx::TlsCredentials(args.config);
|
||||
auto channel = grpc::CreateChannel(args.server_address, cred);
|
||||
|
||||
GreeterClient greeter(channel);
|
||||
|
||||
std::string user_a = greeter.SayHello("a");
|
||||
std::string user_b = greeter.SayHello("b");
|
||||
|
||||
std::cout << "Greeter received: " << user_a << ", "<< user_b << std::endl;
|
||||
};
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
run_client();
|
||||
return 0;
|
||||
}
|
316
demos/ra_tls/grpc/v1.38.1/examples/cpp/ratls/getopt.hpp
Normal file
316
demos/ra_tls/grpc/v1.38.1/examples/cpp/ratls/getopt.hpp
Normal file
@ -0,0 +1,316 @@
|
||||
// Simple getopt replacement class (C++11).
|
||||
// - rlyeh, zlib/libpng licensed.
|
||||
// https://github.com/r-lyeh-archived/getopt/blob/master/getopt.hpp
|
||||
|
||||
// Two APIs provided:
|
||||
//
|
||||
// 1) Simple functional api `getarg(...)`.
|
||||
// - No initialization required: (argc, argv) pair automatically retrieved.
|
||||
// - First argument is default option value, then all option indentifiers follow.
|
||||
//
|
||||
// int main() {
|
||||
// bool help = getarg( false, "-h", "--help", "-?" );
|
||||
// int version = getarg( 0, "-v", "--version", "--show-version" );
|
||||
// int depth = getarg( 1, "-d", "--depth", "--max-depth");
|
||||
// std::string file = getarg( "", "-f", "--file" );
|
||||
// [...]
|
||||
// }
|
||||
//
|
||||
// 2) Simple OOP map-based api `getopt class`. Initialization (argc, argv) pair required.
|
||||
//
|
||||
// This getopt class is a std::map replacement where key/value are std::string types.
|
||||
// Given invokation './app.out --user=me --pass=123 -h' this class delivers not only:
|
||||
// map[0] = "./app.out", map[1] = "--user=me", map[2]="--pass=123", map[3]='-h'
|
||||
// but also, map["--user"]="me", map["--pass"]="123" and also, map["-h"]=true
|
||||
//
|
||||
// Additional API:
|
||||
// - .cmdline() for a print app invokation string
|
||||
// - .str() for pretty map printing
|
||||
// - .size() number of arguments (equivalent to argc), rather than std::map.size()
|
||||
//
|
||||
// int main( int argc, const char **argv ) {
|
||||
// getopt args( argc, argv );
|
||||
// if( args.has("-h") || args.has("--help") || args.has("-?") || args.size() == 1 ) {
|
||||
// std::cout << args["0"] << " [-?|-h|--help] [-v|--version] [--depth=number]" << std::endl;
|
||||
// return 0;
|
||||
// }
|
||||
// if( args.has("-v") || args.has("--version") ) {
|
||||
// std::cout << args["0"] << " sample v1.0.0. Compiled on " << __DATE__ << std::endl;
|
||||
// }
|
||||
// if( args.has("--depth") ) {
|
||||
// int depth = atoi( args["--depth"].c_str() );
|
||||
// std::cout << "depth set to " << depth << std::endl;
|
||||
// }
|
||||
// [...]
|
||||
// }
|
||||
|
||||
#pragma once
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <io.h>
|
||||
#include <winsock2.h>
|
||||
#include <shellapi.h>
|
||||
#pragma comment(lib, "Shell32.lib")
|
||||
#else
|
||||
#include <fstream>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sstream>
|
||||
#endif
|
||||
|
||||
#define GETOPT_VERSION "1.0.0" // (2016/04/18) Initial version
|
||||
|
||||
namespace getopt_utils
|
||||
{
|
||||
// string conversion
|
||||
|
||||
template< typename T >
|
||||
inline T as( const std::string &self ) {
|
||||
T t;
|
||||
return (std::istringstream(self) >> t) ? t :
|
||||
(T)(self.size() && (self != "0") && (self != "false"));
|
||||
}
|
||||
|
||||
template<>
|
||||
inline char as( const std::string &self ) {
|
||||
return self.size() == 1 ? (char)(self[0]) : (char)(as<int>(self));
|
||||
}
|
||||
template<>
|
||||
inline signed char as( const std::string &self ) {
|
||||
return self.size() == 1 ? (signed char)(self[0]) : (signed char)(as<int>(self));
|
||||
}
|
||||
template<>
|
||||
inline unsigned char as( const std::string &self ) {
|
||||
return self.size() == 1 ? (unsigned char)(self[0]) : (unsigned char)(as<int>(self));
|
||||
}
|
||||
|
||||
template<>
|
||||
inline const char *as( const std::string &self ) {
|
||||
return self.c_str();
|
||||
}
|
||||
template<>
|
||||
inline std::string as( const std::string &self ) {
|
||||
return self;
|
||||
}
|
||||
|
||||
// token split
|
||||
|
||||
inline size_t split( std::vector<std::string> &tokens, const std::string &self, const std::string &delimiters ) {
|
||||
std::string str;
|
||||
tokens.clear();
|
||||
for( auto &ch : self ) {
|
||||
if( delimiters.find_first_of( ch ) != std::string::npos ) {
|
||||
if( str.size() ) tokens.push_back( str ), str = "";
|
||||
tokens.push_back( std::string() + ch );
|
||||
} else str += ch;
|
||||
}
|
||||
return str.empty() ? tokens.size() : ( tokens.push_back( str ), tokens.size() );
|
||||
};
|
||||
|
||||
// portable cmdline
|
||||
|
||||
inline std::vector<std::string> cmdline() {
|
||||
std::vector<std::string> args;
|
||||
std::string arg;
|
||||
# ifdef _WIN32
|
||||
int argv;
|
||||
auto *list = CommandLineToArgvW( GetCommandLineW(), &argv );
|
||||
if( list ) {
|
||||
for( int i = 0; i < argv; ++i ) {
|
||||
std::wstring ws( list[i] );
|
||||
args.push_back( std::string( ws.begin(), ws.end() ) );
|
||||
}
|
||||
LocalFree(list);
|
||||
}
|
||||
# else
|
||||
pid_t pid = getpid();
|
||||
|
||||
char fname[32] = {};
|
||||
sprintf(fname, "/proc/%d/cmdline", pid);
|
||||
std::ifstream ifs(fname);
|
||||
if( ifs.good() ) {
|
||||
std::stringstream ss;
|
||||
ifs >> ss.rdbuf();
|
||||
arg = ss.str();
|
||||
}
|
||||
for( auto end = arg.size(), i = end - end; i < end; ++i ) {
|
||||
auto st = i;
|
||||
while (i < arg.size() && arg[i] != '\0') ++i;
|
||||
args.push_back( arg.substr(st, i - st) );
|
||||
}
|
||||
# endif
|
||||
return args;
|
||||
}
|
||||
}
|
||||
|
||||
// main map class; explicit initialization
|
||||
|
||||
struct getopt : public std::map< std::string, std::string >
|
||||
{
|
||||
using super = std::map< std::string, std::string >;
|
||||
|
||||
getopt( int argc, const char **argv ) : super() {
|
||||
// reconstruct vector
|
||||
std::vector<std::string> args( argc, std::string() );
|
||||
for( int i = 0; i < argc; ++i ) {
|
||||
args[ i ] = argv[ i ];
|
||||
}
|
||||
// create key=value and key= args as well
|
||||
for( auto &it : args ) {
|
||||
std::vector<std::string> tokens;
|
||||
auto size = getopt_utils::split( tokens, it, "=" );
|
||||
|
||||
if( size == 3 && tokens[1] == "=" )
|
||||
(*this)[ tokens[0] ] = tokens[2];
|
||||
else
|
||||
if( size == 2 && tokens[1] == "=" )
|
||||
(*this)[ tokens[0] ] = true;
|
||||
else
|
||||
if( size == 1 && tokens[0] != argv[0] )
|
||||
(*this)[ tokens[0] ] = true;
|
||||
}
|
||||
// recreate args
|
||||
while( argc-- ) {
|
||||
(*this)[ std::to_string(argc) ] = std::string( argv[argc] );
|
||||
}
|
||||
}
|
||||
|
||||
getopt( const std::vector<std::string> &args ) : super() {
|
||||
std::vector<const char *> argv;
|
||||
for( auto &it : args ) {
|
||||
argv.push_back( it.c_str() );
|
||||
}
|
||||
*this = getopt( argv.size(), argv.data() );
|
||||
}
|
||||
|
||||
size_t size() const {
|
||||
unsigned i = 0;
|
||||
while( has(std::to_string(i)) ) ++i;
|
||||
return i;
|
||||
}
|
||||
|
||||
bool has( const std::string &op ) const {
|
||||
return this->find(op) != this->end();
|
||||
}
|
||||
|
||||
std::string str() const {
|
||||
std::stringstream ss;
|
||||
std::string sep;
|
||||
for( auto &it : *this ) {
|
||||
ss << sep << it.first << "=" << it.second;
|
||||
sep = ',';
|
||||
}
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
std::string cmdline() const {
|
||||
std::stringstream cmd;
|
||||
std::string sep;
|
||||
// concatenate args
|
||||
for( auto end = size(), arg = end - end; arg < end; ++arg ) {
|
||||
cmd << sep << this->find(std::to_string(arg))->second;
|
||||
sep = ' ';
|
||||
}
|
||||
return cmd.str();
|
||||
}
|
||||
};
|
||||
|
||||
// variadic syntax sugars {
|
||||
|
||||
template< typename T >
|
||||
inline T getarg( const T &defaults, const char *argv ) {
|
||||
static struct getopt map( getopt_utils::cmdline() );
|
||||
return map.has( argv ) ? getopt_utils::as<T>(map[ argv ]) : defaults;
|
||||
}
|
||||
|
||||
template< typename T, typename... Args >
|
||||
inline T getarg( const T &defaults, const char *arg0, Args... argv ) {
|
||||
T t = getarg<T>( defaults, arg0 );
|
||||
return t == defaults ? getarg<T>( defaults, argv... ) : t;
|
||||
}
|
||||
|
||||
inline const char * getarg( const char *defaults, const char *argv ) {
|
||||
static struct getopt map( getopt_utils::cmdline() );
|
||||
return map.has( argv ) ? getopt_utils::as<const char *>(map[ argv ]) : defaults;
|
||||
}
|
||||
|
||||
template< typename... Args >
|
||||
inline const char * getarg( const char *defaults, const char *arg0, Args... argv ) {
|
||||
const char *t = getarg( defaults, arg0 );
|
||||
return t == defaults ? getarg( defaults, argv... ) : t;
|
||||
}
|
||||
|
||||
// }
|
||||
|
||||
|
||||
#ifdef GETOPT_BUILD_DEMO
|
||||
#include <iostream>
|
||||
#include <stdlib.h>
|
||||
|
||||
int main( int argc, const char **argv ) {
|
||||
|
||||
auto show_help = [&]() {
|
||||
std::cout << argv[0] << " [-h|--help|-?] [-f=path|--file=path] [-v|--version] [-d=number|--depth=number|--max-depth=number]" << std::endl;
|
||||
exit(0);
|
||||
};
|
||||
|
||||
// Simple functional api. No initialization required.
|
||||
|
||||
bool help = getarg( false, "-h", "--help", "-?" );
|
||||
int version = getarg( 0, "-v", "--version", "--show-version" );
|
||||
int depth = getarg( 0, "-d", "--depth", "--max-depth");
|
||||
std::string file = getarg( "", "-f", "--file" );
|
||||
|
||||
if( help || argc <= 1 ) {
|
||||
show_help();
|
||||
}
|
||||
|
||||
if( version ) {
|
||||
std::cout << argv[0] << " demo v1.0.0. Compiled on " << __DATE__ << std::endl;
|
||||
}
|
||||
|
||||
if( depth ) {
|
||||
std::cout << "provided depth: " << depth << std::endl;
|
||||
}
|
||||
|
||||
if( !file.empty() ) {
|
||||
std::cout << "provided file: " << file << std::endl;
|
||||
}
|
||||
|
||||
// OOP map-based api. Explicit (argc, argv) initialization required.
|
||||
|
||||
struct getopt args( argc, argv );
|
||||
|
||||
if( args.has("-h") || args.has("--help") || args.has("-?") || args.size() == 1 ) {
|
||||
show_help();
|
||||
}
|
||||
|
||||
if( args.has("-v") || args.has("--version") ) {
|
||||
std::cout << args["0"] << " demo v1.0.0. Compiled on " << __DATE__ << std::endl;
|
||||
}
|
||||
|
||||
if( args.has("-d") || args.has("--depth") || args.has("--max-depth") ) {
|
||||
std::string arg = args["-d"];
|
||||
if( arg.empty() ) arg = args["--depth"];
|
||||
if( arg.empty() ) arg = args["--max-depth"];
|
||||
int depth = atoi( arg.c_str() );
|
||||
std::cout << "provided depth: " << depth << std::endl;
|
||||
}
|
||||
|
||||
if( args.has("-f") || args.has("--file") ) {
|
||||
std::string arg = args["-f"];
|
||||
if( arg.empty() ) arg = args["--file"];
|
||||
std::string fname = arg;
|
||||
std::cout << "provided file: " << fname << std::endl;
|
||||
}
|
||||
|
||||
std::cout << "---" << std::endl;
|
||||
std::cout << args.cmdline() << std::endl;
|
||||
//std::cout << args.size() << " provided args: " << args.str() << std::endl;
|
||||
}
|
||||
#endif
|
80
demos/ra_tls/grpc/v1.38.1/examples/cpp/ratls/server.cc
Normal file
80
demos/ra_tls/grpc/v1.38.1/examples/cpp/ratls/server.cc
Normal file
@ -0,0 +1,80 @@
|
||||
/*
|
||||
*
|
||||
* Copyright (c) 2022 Intel Corporation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <grpcpp/grpcpp.h>
|
||||
#include <grpcpp/security/sgx/sgx_ra_tls.h>
|
||||
#include <grpcpp/ext/proto_server_reflection_plugin.h>
|
||||
|
||||
#ifdef BAZEL_BUILD
|
||||
#include "examples/protos/ratls.grpc.pb.h"
|
||||
#else
|
||||
#include "ratls.grpc.pb.h"
|
||||
#endif
|
||||
|
||||
#include "../getopt.hpp"
|
||||
|
||||
using ratls::Greeter;
|
||||
using ratls::HelloReply;
|
||||
using ratls::HelloRequest;
|
||||
|
||||
struct argparser {
|
||||
const char* config;
|
||||
std::string server_address;
|
||||
argparser() {
|
||||
server_address = getarg("localhost:50051", "-host", "--host");
|
||||
config = getarg("dynamic_config.json", "-cfg", "--config");
|
||||
};
|
||||
};
|
||||
|
||||
// Logic and data behind the server's behavior.
|
||||
class GreeterServiceImpl final : public Greeter::Service {
|
||||
grpc::Status SayHello(
|
||||
grpc::ServerContext* context, const HelloRequest* request, HelloReply* reply) override {
|
||||
std::string prefix("Hello ");
|
||||
reply->set_message(prefix + request->name());
|
||||
return grpc::Status::OK;
|
||||
}
|
||||
};
|
||||
|
||||
void RunServer() {
|
||||
argparser args;
|
||||
|
||||
GreeterServiceImpl service;
|
||||
|
||||
grpc::EnableDefaultHealthCheckService(true);
|
||||
grpc::reflection::InitProtoReflectionServerBuilderPlugin();
|
||||
|
||||
grpc::ServerBuilder builder;
|
||||
|
||||
auto creds = grpc::sgx::TlsServerCredentials(args.config);
|
||||
GPR_ASSERT(creds.get() != nullptr);
|
||||
|
||||
builder.AddListeningPort(args.server_address, creds);
|
||||
|
||||
builder.RegisterService(&service);
|
||||
|
||||
std::unique_ptr<grpc::Server> server(builder.BuildAndStart());
|
||||
std::cout << "Server listening on " << args.server_address << std::endl;
|
||||
|
||||
server->Wait();
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
RunServer();
|
||||
return 0;
|
||||
}
|
38
demos/ra_tls/grpc/v1.38.1/examples/protos/ratls.proto
Normal file
38
demos/ra_tls/grpc/v1.38.1/examples/protos/ratls.proto
Normal file
@ -0,0 +1,38 @@
|
||||
// Copyright (c) 2022 Intel Corporation
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
syntax = "proto3";
|
||||
|
||||
option java_multiple_files = true;
|
||||
option java_package = "io.grpc.examples.ratls";
|
||||
option java_outer_classname = "RATLSProto";
|
||||
option objc_class_prefix = "HLW";
|
||||
|
||||
package ratls;
|
||||
|
||||
// The greeting service definition.
|
||||
service Greeter {
|
||||
// Sends a greeting
|
||||
rpc SayHello (HelloRequest) returns (HelloReply) {}
|
||||
}
|
||||
|
||||
// The request message containing the user's name.
|
||||
message HelloRequest {
|
||||
string name = 1;
|
||||
}
|
||||
|
||||
// The response message containing the greetings
|
||||
message HelloReply {
|
||||
string message = 1;
|
||||
}
|
@ -0,0 +1,57 @@
|
||||
/*
|
||||
*
|
||||
* Copyright (c) 2022 Intel Corporation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SGX_RA_TLS_H
|
||||
#define SGX_RA_TLS_H
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include <grpcpp/security/credentials.h>
|
||||
#include <grpcpp/security/server_credentials.h>
|
||||
|
||||
namespace grpc {
|
||||
namespace sgx {
|
||||
|
||||
struct sgx_config;
|
||||
|
||||
std::vector<std::string> ra_tls_get_key_cert();
|
||||
|
||||
void ra_tls_parse_sgx_config(sgx_config sgx_cfg);
|
||||
|
||||
void ra_tls_parse_sgx_config(const char* file);
|
||||
|
||||
void ra_tls_verify_init();
|
||||
|
||||
int ra_tls_auth_check_schedule(void* /* config_user_data */,
|
||||
grpc_tls_server_authorization_check_arg* arg);
|
||||
|
||||
std::shared_ptr<grpc::ChannelCredentials> TlsCredentials(sgx_config sgx_cfg);
|
||||
|
||||
std::shared_ptr<grpc::ChannelCredentials> TlsCredentials(const char* sgx_cfg_json);
|
||||
|
||||
std::shared_ptr<grpc::ServerCredentials> TlsServerCredentials(sgx_config sgx_cfg);
|
||||
|
||||
std::shared_ptr<grpc::ServerCredentials> TlsServerCredentials(const char* sgx_cfg_json);
|
||||
|
||||
std::shared_ptr<grpc::Channel> CreateSecureChannel(
|
||||
string target_str, std::shared_ptr<grpc::ChannelCredentials> channel_creds);
|
||||
|
||||
} // namespace sgx
|
||||
} // namespace grpc
|
||||
|
||||
#endif // SGX_RA_TLS_H
|
@ -0,0 +1,67 @@
|
||||
/*
|
||||
*
|
||||
* Copyright (c) 2022 Intel Corporation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SGX_RA_TLS_OPTIONS_H
|
||||
#define SGX_RA_TLS_OPTIONS_H
|
||||
|
||||
#include <grpc/grpc_security_constants.h>
|
||||
#include <grpc/status.h>
|
||||
#include <grpc/support/log.h>
|
||||
#include <grpcpp/security/tls_certificate_provider.h>
|
||||
#include <grpcpp/security/tls_credentials_options.h>
|
||||
#include <grpcpp/support/config.h>
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
namespace grpc {
|
||||
namespace sgx {
|
||||
|
||||
// Contains configurable options on the client side.
|
||||
// Client side doesn't need to always use certificate provider. When the
|
||||
// certificate provider is not set, we will use the root certificates stored
|
||||
// in the system default locations, and assume client won't provide any
|
||||
// identity certificates(single side TLS).
|
||||
// It is used for experimental purposes for now and it is subject to change.
|
||||
class CredentialsOptions final : public grpc::experimental::TlsCredentialsOptions {
|
||||
public:
|
||||
|
||||
explicit CredentialsOptions() : TlsCredentialsOptions() {}
|
||||
|
||||
// Sets option to request the certificates from the client.
|
||||
// The default is GRPC_SSL_DONT_REQUEST_CLIENT_CERTIFICATE.
|
||||
void set_cert_request_type(
|
||||
grpc_ssl_client_certificate_request_type cert_request_type);
|
||||
|
||||
// Sets the option to verify the server.
|
||||
// The default is GRPC_TLS_SERVER_VERIFICATION.
|
||||
void set_verification_option(
|
||||
grpc_tls_server_verification_option server_verification_option);
|
||||
|
||||
// Sets the custom authorization config.
|
||||
void set_authorization_check_config(
|
||||
std::shared_ptr<grpc::experimental::TlsServerAuthorizationCheckConfig>
|
||||
authorization_check_config);
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
} // namespace sgx
|
||||
} // namespace grpc
|
||||
|
||||
#endif // SGX_RA_TLS_OPTIONS_H
|
@ -0,0 +1,133 @@
|
||||
/*
|
||||
*
|
||||
* Copyright 2018 gRPC authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <grpc/support/port_platform.h>
|
||||
|
||||
#include "src/core/lib/security/credentials/tls/tls_credentials.h"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
#include <grpc/grpc.h>
|
||||
#include <grpc/support/alloc.h>
|
||||
#include <grpc/support/log.h>
|
||||
#include <grpc/support/string_util.h>
|
||||
|
||||
#include "src/core/lib/channel/channel_args.h"
|
||||
#include "src/core/lib/security/security_connector/tls/tls_security_connector.h"
|
||||
|
||||
#define GRPC_CREDENTIALS_TYPE_TLS "Tls"
|
||||
|
||||
namespace {
|
||||
|
||||
bool CredentialOptionSanityCheck(const grpc_tls_credentials_options* options,
|
||||
bool is_client) {
|
||||
if (options == nullptr) {
|
||||
gpr_log(GPR_ERROR, "TLS credentials options is nullptr.");
|
||||
return false;
|
||||
}
|
||||
// TODO(ZhenLian): remove this when it is also supported on server side.
|
||||
// if (!is_client && options->server_authorization_check_config() != nullptr) {
|
||||
// gpr_log(GPR_INFO,
|
||||
// "Server's credentials options should not contain server "
|
||||
// "authorization check config.");
|
||||
// }
|
||||
if (options->server_verification_option() != GRPC_TLS_SERVER_VERIFICATION &&
|
||||
options->server_authorization_check_config() == nullptr) {
|
||||
gpr_log(GPR_ERROR,
|
||||
"Should provider custom verifications if bypassing default ones.");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
TlsCredentials::TlsCredentials(
|
||||
grpc_core::RefCountedPtr<grpc_tls_credentials_options> options)
|
||||
: grpc_channel_credentials(GRPC_CREDENTIALS_TYPE_TLS),
|
||||
options_(std::move(options)) {}
|
||||
|
||||
TlsCredentials::~TlsCredentials() {}
|
||||
|
||||
grpc_core::RefCountedPtr<grpc_channel_security_connector>
|
||||
TlsCredentials::create_security_connector(
|
||||
grpc_core::RefCountedPtr<grpc_call_credentials> call_creds,
|
||||
const char* target_name, const grpc_channel_args* args,
|
||||
grpc_channel_args** new_args) {
|
||||
const char* overridden_target_name = nullptr;
|
||||
tsi_ssl_session_cache* ssl_session_cache = nullptr;
|
||||
for (size_t i = 0; args != nullptr && i < args->num_args; i++) {
|
||||
grpc_arg* arg = &args->args[i];
|
||||
if (strcmp(arg->key, GRPC_SSL_TARGET_NAME_OVERRIDE_ARG) == 0 &&
|
||||
arg->type == GRPC_ARG_STRING) {
|
||||
overridden_target_name = arg->value.string;
|
||||
}
|
||||
if (strcmp(arg->key, GRPC_SSL_SESSION_CACHE_ARG) == 0 &&
|
||||
arg->type == GRPC_ARG_POINTER) {
|
||||
ssl_session_cache =
|
||||
static_cast<tsi_ssl_session_cache*>(arg->value.pointer.p);
|
||||
}
|
||||
}
|
||||
grpc_core::RefCountedPtr<grpc_channel_security_connector> sc =
|
||||
grpc_core::TlsChannelSecurityConnector::CreateTlsChannelSecurityConnector(
|
||||
this->Ref(), options_, std::move(call_creds), target_name,
|
||||
overridden_target_name, ssl_session_cache);
|
||||
if (sc == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
if (args != nullptr) {
|
||||
grpc_arg new_arg = grpc_channel_arg_string_create(
|
||||
const_cast<char*>(GRPC_ARG_HTTP2_SCHEME), const_cast<char*>("https"));
|
||||
*new_args = grpc_channel_args_copy_and_add(args, &new_arg, 1);
|
||||
}
|
||||
return sc;
|
||||
}
|
||||
|
||||
TlsServerCredentials::TlsServerCredentials(
|
||||
grpc_core::RefCountedPtr<grpc_tls_credentials_options> options)
|
||||
: grpc_server_credentials(GRPC_CREDENTIALS_TYPE_TLS),
|
||||
options_(std::move(options)) {}
|
||||
|
||||
TlsServerCredentials::~TlsServerCredentials() {}
|
||||
|
||||
grpc_core::RefCountedPtr<grpc_server_security_connector>
|
||||
TlsServerCredentials::create_security_connector(
|
||||
const grpc_channel_args* /* args */) {
|
||||
return grpc_core::TlsServerSecurityConnector::
|
||||
CreateTlsServerSecurityConnector(this->Ref(), options_);
|
||||
}
|
||||
|
||||
/** -- Wrapper APIs declared in grpc_security.h -- **/
|
||||
|
||||
grpc_channel_credentials* grpc_tls_credentials_create(
|
||||
grpc_tls_credentials_options* options) {
|
||||
if (!CredentialOptionSanityCheck(options, true /* is_client */)) {
|
||||
return nullptr;
|
||||
}
|
||||
return new TlsCredentials(
|
||||
grpc_core::RefCountedPtr<grpc_tls_credentials_options>(options));
|
||||
}
|
||||
|
||||
grpc_server_credentials* grpc_tls_server_credentials_create(
|
||||
grpc_tls_credentials_options* options) {
|
||||
if (!CredentialOptionSanityCheck(options, false /* is_client */)) {
|
||||
return nullptr;
|
||||
}
|
||||
return new TlsServerCredentials(
|
||||
grpc_core::RefCountedPtr<grpc_tls_credentials_options>(options));
|
||||
}
|
863
demos/ra_tls/grpc/v1.38.1/src/core/lib/security/security_connector/tls/tls_security_connector.cc
Normal file
863
demos/ra_tls/grpc/v1.38.1/src/core/lib/security/security_connector/tls/tls_security_connector.cc
Normal file
@ -0,0 +1,863 @@
|
||||
/*
|
||||
*
|
||||
* Copyright 2018 gRPC authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <grpc/support/port_platform.h>
|
||||
|
||||
#include "src/core/lib/security/security_connector/tls/tls_security_connector.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "absl/strings/str_cat.h"
|
||||
#include "absl/strings/string_view.h"
|
||||
|
||||
#include <grpc/grpc.h>
|
||||
#include <grpc/support/alloc.h>
|
||||
#include <grpc/support/log.h>
|
||||
#include <grpc/support/string_util.h>
|
||||
|
||||
#include "src/core/lib/gprpp/host_port.h"
|
||||
#include "src/core/lib/security/credentials/ssl/ssl_credentials.h"
|
||||
#include "src/core/lib/security/credentials/tls/tls_credentials.h"
|
||||
#include "src/core/lib/security/security_connector/ssl_utils.h"
|
||||
#include "src/core/lib/security/transport/security_handshaker.h"
|
||||
#include "src/core/lib/slice/slice_internal.h"
|
||||
#include "src/core/lib/transport/transport.h"
|
||||
#include "src/core/tsi/ssl_transport_security.h"
|
||||
#include "src/core/tsi/transport_security.h"
|
||||
|
||||
namespace grpc_core {
|
||||
|
||||
namespace {
|
||||
|
||||
tsi_ssl_pem_key_cert_pair* ConvertToTsiPemKeyCertPair(
|
||||
const PemKeyCertPairList& cert_pair_list) {
|
||||
tsi_ssl_pem_key_cert_pair* tsi_pairs = nullptr;
|
||||
size_t num_key_cert_pairs = cert_pair_list.size();
|
||||
if (num_key_cert_pairs > 0) {
|
||||
GPR_ASSERT(cert_pair_list.data() != nullptr);
|
||||
tsi_pairs = static_cast<tsi_ssl_pem_key_cert_pair*>(
|
||||
gpr_zalloc(num_key_cert_pairs * sizeof(tsi_ssl_pem_key_cert_pair)));
|
||||
}
|
||||
for (size_t i = 0; i < num_key_cert_pairs; i++) {
|
||||
GPR_ASSERT(!cert_pair_list[i].private_key().empty());
|
||||
GPR_ASSERT(!cert_pair_list[i].cert_chain().empty());
|
||||
tsi_pairs[i].cert_chain =
|
||||
gpr_strdup(cert_pair_list[i].cert_chain().c_str());
|
||||
tsi_pairs[i].private_key =
|
||||
gpr_strdup(cert_pair_list[i].private_key().c_str());
|
||||
}
|
||||
return tsi_pairs;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void gpr_check_free(void* p) {
|
||||
if (p) {
|
||||
gpr_free(p);
|
||||
p = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------channel security connector-------------------
|
||||
RefCountedPtr<grpc_channel_security_connector>
|
||||
TlsChannelSecurityConnector::CreateTlsChannelSecurityConnector(
|
||||
RefCountedPtr<grpc_channel_credentials> channel_creds,
|
||||
RefCountedPtr<grpc_tls_credentials_options> options,
|
||||
RefCountedPtr<grpc_call_credentials> request_metadata_creds,
|
||||
const char* target_name, const char* overridden_target_name,
|
||||
tsi_ssl_session_cache* ssl_session_cache) {
|
||||
if (channel_creds == nullptr) {
|
||||
gpr_log(GPR_ERROR,
|
||||
"channel_creds is nullptr in "
|
||||
"TlsChannelSecurityConnectorCreate()");
|
||||
return nullptr;
|
||||
}
|
||||
if (options == nullptr) {
|
||||
gpr_log(GPR_ERROR,
|
||||
"options is nullptr in "
|
||||
"TlsChannelSecurityConnectorCreate()");
|
||||
return nullptr;
|
||||
}
|
||||
if (target_name == nullptr) {
|
||||
gpr_log(GPR_ERROR,
|
||||
"target_name is nullptr in "
|
||||
"TlsChannelSecurityConnectorCreate()");
|
||||
return nullptr;
|
||||
}
|
||||
return MakeRefCounted<TlsChannelSecurityConnector>(
|
||||
std::move(channel_creds), std::move(options),
|
||||
std::move(request_metadata_creds), target_name, overridden_target_name,
|
||||
ssl_session_cache);
|
||||
}
|
||||
|
||||
TlsChannelSecurityConnector::TlsChannelSecurityConnector(
|
||||
RefCountedPtr<grpc_channel_credentials> channel_creds,
|
||||
RefCountedPtr<grpc_tls_credentials_options> options,
|
||||
RefCountedPtr<grpc_call_credentials> request_metadata_creds,
|
||||
const char* target_name, const char* overridden_target_name,
|
||||
tsi_ssl_session_cache* ssl_session_cache)
|
||||
: grpc_channel_security_connector(GRPC_SSL_URL_SCHEME,
|
||||
std::move(channel_creds),
|
||||
std::move(request_metadata_creds)),
|
||||
options_(std::move(options)),
|
||||
overridden_target_name_(
|
||||
overridden_target_name == nullptr ? "" : overridden_target_name),
|
||||
ssl_session_cache_(ssl_session_cache) {
|
||||
if (ssl_session_cache_ != nullptr) {
|
||||
tsi_ssl_session_cache_ref(ssl_session_cache_);
|
||||
}
|
||||
check_arg_ = ServerAuthorizationCheckArgCreate(this);
|
||||
absl::string_view host;
|
||||
absl::string_view port;
|
||||
SplitHostPort(target_name, &host, &port);
|
||||
target_name_ = std::string(host);
|
||||
// Create a watcher.
|
||||
auto watcher_ptr = absl::make_unique<TlsChannelCertificateWatcher>(this);
|
||||
certificate_watcher_ = watcher_ptr.get();
|
||||
// Register the watcher with the distributor.
|
||||
grpc_tls_certificate_distributor* distributor =
|
||||
options_->certificate_distributor();
|
||||
absl::optional<std::string> watched_root_cert_name;
|
||||
if (options_->watch_root_cert()) {
|
||||
watched_root_cert_name = options_->root_cert_name();
|
||||
}
|
||||
absl::optional<std::string> watched_identity_cert_name;
|
||||
if (options_->watch_identity_pair()) {
|
||||
watched_identity_cert_name = options_->identity_cert_name();
|
||||
}
|
||||
// We will use the root certs stored in system default locations if not
|
||||
// watching root certs on the client side. We will handle this case
|
||||
// differently here, because "watching a default roots without the identity
|
||||
// certs" is a valid case(and hence we will need to call
|
||||
// OnCertificatesChanged), but it requires nothing from the provider, and
|
||||
// hence no need to register the watcher.
|
||||
bool use_default_roots = !options_->watch_root_cert();
|
||||
if (use_default_roots && !options_->watch_identity_pair()) {
|
||||
watcher_ptr->OnCertificatesChanged(absl::nullopt, absl::nullopt);
|
||||
} else {
|
||||
distributor->WatchTlsCertificates(std::move(watcher_ptr),
|
||||
watched_root_cert_name,
|
||||
watched_identity_cert_name);
|
||||
}
|
||||
}
|
||||
|
||||
TlsChannelSecurityConnector::~TlsChannelSecurityConnector() {
|
||||
if (ssl_session_cache_ != nullptr) {
|
||||
tsi_ssl_session_cache_unref(ssl_session_cache_);
|
||||
}
|
||||
// Cancel all the watchers.
|
||||
grpc_tls_certificate_distributor* distributor =
|
||||
options_->certificate_distributor();
|
||||
if (distributor != nullptr) {
|
||||
distributor->CancelTlsCertificatesWatch(certificate_watcher_);
|
||||
}
|
||||
if (client_handshaker_factory_ != nullptr) {
|
||||
tsi_ssl_client_handshaker_factory_unref(client_handshaker_factory_);
|
||||
}
|
||||
if (check_arg_ != nullptr) {
|
||||
ServerAuthorizationCheckArgDestroy(check_arg_);
|
||||
}
|
||||
}
|
||||
|
||||
void TlsChannelSecurityConnector::add_handshakers(
|
||||
const grpc_channel_args* args, grpc_pollset_set* /*interested_parties*/,
|
||||
HandshakeManager* handshake_mgr) {
|
||||
MutexLock lock(&mu_);
|
||||
if (client_handshaker_factory_ != nullptr) {
|
||||
// Instantiate TSI handshaker.
|
||||
tsi_handshaker* tsi_hs = nullptr;
|
||||
tsi_result result = tsi_ssl_client_handshaker_factory_create_handshaker(
|
||||
client_handshaker_factory_,
|
||||
overridden_target_name_.empty() ? target_name_.c_str()
|
||||
: overridden_target_name_.c_str(),
|
||||
&tsi_hs);
|
||||
if (result != TSI_OK) {
|
||||
gpr_log(GPR_ERROR, "Handshaker creation failed with error %s.",
|
||||
tsi_result_to_string(result));
|
||||
return;
|
||||
}
|
||||
// Create handshakers.
|
||||
handshake_mgr->Add(SecurityHandshakerCreate(tsi_hs, this, args));
|
||||
return;
|
||||
}
|
||||
// TODO(ZhenLian): Implement the logic(delegation to
|
||||
// BlockOnInitialCredentialHandshaker) when certificates are not ready.
|
||||
gpr_log(GPR_ERROR, "%s not supported yet.",
|
||||
"Client BlockOnInitialCredentialHandshaker");
|
||||
}
|
||||
|
||||
void TlsChannelSecurityConnector::check_peer(
|
||||
tsi_peer peer, grpc_endpoint* /*ep*/,
|
||||
RefCountedPtr<grpc_auth_context>* auth_context,
|
||||
grpc_closure* on_peer_checked) {
|
||||
const char* target_name = overridden_target_name_.empty()
|
||||
? target_name_.c_str()
|
||||
: overridden_target_name_.c_str();
|
||||
grpc_error_handle error = grpc_ssl_check_alpn(&peer);
|
||||
if (error != GRPC_ERROR_NONE) {
|
||||
ExecCtx::Run(DEBUG_LOCATION, on_peer_checked, error);
|
||||
tsi_peer_destruct(&peer);
|
||||
return;
|
||||
}
|
||||
*auth_context =
|
||||
grpc_ssl_peer_to_auth_context(&peer, GRPC_TLS_TRANSPORT_SECURITY_TYPE);
|
||||
if (options_->server_verification_option() == GRPC_TLS_SERVER_VERIFICATION) {
|
||||
/* Do the default host name check if specifying the target name. */
|
||||
error = internal::TlsCheckHostName(target_name, &peer);
|
||||
if (error != GRPC_ERROR_NONE) {
|
||||
ExecCtx::Run(DEBUG_LOCATION, on_peer_checked, error);
|
||||
tsi_peer_destruct(&peer);
|
||||
return;
|
||||
}
|
||||
}
|
||||
/* Do the custom server authorization check, if specified by the user. */
|
||||
const grpc_tls_server_authorization_check_config* config =
|
||||
options_->server_authorization_check_config();
|
||||
/* If server authorization config is not null, use it to perform
|
||||
* server authorization check. */
|
||||
if (config != nullptr) {
|
||||
const tsi_peer_property* p =
|
||||
tsi_peer_get_property_by_name(&peer, TSI_X509_PEM_CERT_PROPERTY);
|
||||
if (p == nullptr) {
|
||||
error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
|
||||
"Cannot check peer: missing pem cert property.");
|
||||
} else {
|
||||
char* peer_pem = static_cast<char*>(gpr_zalloc(p->value.length + 1));
|
||||
memcpy(peer_pem, p->value.data, p->value.length);
|
||||
GPR_ASSERT(check_arg_ != nullptr);
|
||||
check_arg_->peer_cert = check_arg_->peer_cert == nullptr
|
||||
? gpr_strdup(peer_pem)
|
||||
: check_arg_->peer_cert;
|
||||
check_arg_->target_name = check_arg_->target_name == nullptr
|
||||
? gpr_strdup(target_name)
|
||||
: check_arg_->target_name;
|
||||
on_peer_checked_ = on_peer_checked;
|
||||
gpr_check_free(peer_pem);
|
||||
const tsi_peer_property* chain = tsi_peer_get_property_by_name(
|
||||
&peer, TSI_X509_PEM_CERT_CHAIN_PROPERTY);
|
||||
if (chain != nullptr) {
|
||||
char* peer_pem_chain =
|
||||
static_cast<char*>(gpr_zalloc(chain->value.length + 1));
|
||||
memcpy(peer_pem_chain, chain->value.data, chain->value.length);
|
||||
check_arg_->peer_cert_full_chain =
|
||||
check_arg_->peer_cert_full_chain == nullptr
|
||||
? gpr_strdup(peer_pem_chain)
|
||||
: check_arg_->peer_cert_full_chain;
|
||||
gpr_check_free(peer_pem_chain);
|
||||
}
|
||||
// TODO(zhenlian) - This should be cleaned up as part of the custom
|
||||
// verification changes. Fill in the subject alternative names
|
||||
std::vector<char*> subject_alternative_names;
|
||||
for (size_t i = 0; i < peer.property_count; i++) {
|
||||
const tsi_peer_property* prop = &peer.properties[i];
|
||||
if (strcmp(prop->name,
|
||||
TSI_X509_SUBJECT_ALTERNATIVE_NAME_PEER_PROPERTY) == 0) {
|
||||
char* san = new char[prop->value.length + 1];
|
||||
memcpy(san, prop->value.data, prop->value.length);
|
||||
san[prop->value.length] = '\0';
|
||||
subject_alternative_names.emplace_back(san);
|
||||
}
|
||||
}
|
||||
if (check_arg_->subject_alternative_names != nullptr) {
|
||||
for (size_t i = 0; i < check_arg_->subject_alternative_names_size;
|
||||
++i) {
|
||||
delete[] check_arg_->subject_alternative_names[i];
|
||||
}
|
||||
delete[] check_arg_->subject_alternative_names;
|
||||
}
|
||||
check_arg_->subject_alternative_names_size =
|
||||
subject_alternative_names.size();
|
||||
if (subject_alternative_names.empty()) {
|
||||
check_arg_->subject_alternative_names = nullptr;
|
||||
} else {
|
||||
check_arg_->subject_alternative_names =
|
||||
new char*[check_arg_->subject_alternative_names_size];
|
||||
for (size_t i = 0; i < check_arg_->subject_alternative_names_size;
|
||||
++i) {
|
||||
check_arg_->subject_alternative_names[i] =
|
||||
subject_alternative_names[i];
|
||||
}
|
||||
}
|
||||
int callback_status = config->Schedule(check_arg_);
|
||||
/* Server authorization check is handled asynchronously. */
|
||||
if (callback_status) {
|
||||
tsi_peer_destruct(&peer);
|
||||
return;
|
||||
}
|
||||
/* Server authorization check is handled synchronously. */
|
||||
error = ProcessServerAuthorizationCheckResult(check_arg_);
|
||||
}
|
||||
}
|
||||
ExecCtx::Run(DEBUG_LOCATION, on_peer_checked, error);
|
||||
tsi_peer_destruct(&peer);
|
||||
}
|
||||
|
||||
int TlsChannelSecurityConnector::cmp(
|
||||
const grpc_security_connector* other_sc) const {
|
||||
auto* other = reinterpret_cast<const TlsChannelSecurityConnector*>(other_sc);
|
||||
int c = channel_security_connector_cmp(other);
|
||||
if (c != 0) {
|
||||
return c;
|
||||
}
|
||||
return grpc_ssl_cmp_target_name(
|
||||
target_name_.c_str(), other->target_name_.c_str(),
|
||||
overridden_target_name_.c_str(), other->overridden_target_name_.c_str());
|
||||
}
|
||||
|
||||
bool TlsChannelSecurityConnector::check_call_host(
|
||||
absl::string_view host, grpc_auth_context* auth_context,
|
||||
grpc_closure* /*on_call_host_checked*/, grpc_error_handle* error) {
|
||||
if (options_->server_verification_option() ==
|
||||
GRPC_TLS_SKIP_HOSTNAME_VERIFICATION ||
|
||||
options_->server_verification_option() ==
|
||||
GRPC_TLS_SKIP_ALL_SERVER_VERIFICATION) {
|
||||
return true;
|
||||
}
|
||||
return grpc_ssl_check_call_host(host, target_name_.c_str(),
|
||||
overridden_target_name_.c_str(), auth_context,
|
||||
error);
|
||||
}
|
||||
|
||||
void TlsChannelSecurityConnector::cancel_check_call_host(
|
||||
grpc_closure* /*on_call_host_checked*/, grpc_error_handle error) {
|
||||
GRPC_ERROR_UNREF(error);
|
||||
}
|
||||
|
||||
void TlsChannelSecurityConnector::TlsChannelCertificateWatcher::
|
||||
OnCertificatesChanged(absl::optional<absl::string_view> root_certs,
|
||||
absl::optional<PemKeyCertPairList> key_cert_pairs) {
|
||||
GPR_ASSERT(security_connector_ != nullptr);
|
||||
MutexLock lock(&security_connector_->mu_);
|
||||
if (root_certs.has_value()) {
|
||||
security_connector_->pem_root_certs_ = root_certs;
|
||||
}
|
||||
if (key_cert_pairs.has_value()) {
|
||||
security_connector_->pem_key_cert_pair_list_ = std::move(key_cert_pairs);
|
||||
}
|
||||
const bool root_ready = !security_connector_->options_->watch_root_cert() ||
|
||||
security_connector_->pem_root_certs_.has_value();
|
||||
const bool identity_ready =
|
||||
!security_connector_->options_->watch_identity_pair() ||
|
||||
security_connector_->pem_key_cert_pair_list_.has_value();
|
||||
if (root_ready && identity_ready) {
|
||||
if (security_connector_->UpdateHandshakerFactoryLocked() !=
|
||||
GRPC_SECURITY_OK) {
|
||||
gpr_log(GPR_ERROR, "Update handshaker factory failed.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(ZhenLian): implement the logic to signal waiting handshakers once
|
||||
// BlockOnInitialCredentialHandshaker is implemented.
|
||||
void TlsChannelSecurityConnector::TlsChannelCertificateWatcher::OnError(
|
||||
grpc_error_handle root_cert_error, grpc_error_handle identity_cert_error) {
|
||||
if (root_cert_error != GRPC_ERROR_NONE) {
|
||||
gpr_log(GPR_ERROR,
|
||||
"TlsChannelCertificateWatcher getting root_cert_error: %s",
|
||||
grpc_error_std_string(root_cert_error).c_str());
|
||||
}
|
||||
if (identity_cert_error != GRPC_ERROR_NONE) {
|
||||
gpr_log(GPR_ERROR,
|
||||
"TlsChannelCertificateWatcher getting identity_cert_error: %s",
|
||||
grpc_error_std_string(identity_cert_error).c_str());
|
||||
}
|
||||
GRPC_ERROR_UNREF(root_cert_error);
|
||||
GRPC_ERROR_UNREF(identity_cert_error);
|
||||
}
|
||||
|
||||
// TODO(ZhenLian): implement the logic to signal waiting handshakers once
|
||||
// BlockOnInitialCredentialHandshaker is implemented.
|
||||
grpc_security_status
|
||||
TlsChannelSecurityConnector::UpdateHandshakerFactoryLocked() {
|
||||
bool skip_server_certificate_verification =
|
||||
options_->server_verification_option() ==
|
||||
GRPC_TLS_SKIP_ALL_SERVER_VERIFICATION;
|
||||
/* Free the client handshaker factory if exists. */
|
||||
if (client_handshaker_factory_ != nullptr) {
|
||||
tsi_ssl_client_handshaker_factory_unref(client_handshaker_factory_);
|
||||
}
|
||||
std::string pem_root_certs;
|
||||
if (pem_root_certs_.has_value()) {
|
||||
// TODO(ZhenLian): update the underlying TSI layer to use C++ types like
|
||||
// std::string and absl::string_view to avoid making another copy here.
|
||||
pem_root_certs = std::string(*pem_root_certs_);
|
||||
}
|
||||
tsi_ssl_pem_key_cert_pair* pem_key_cert_pair = nullptr;
|
||||
if (pem_key_cert_pair_list_.has_value()) {
|
||||
pem_key_cert_pair = ConvertToTsiPemKeyCertPair(*pem_key_cert_pair_list_);
|
||||
}
|
||||
bool use_default_roots = !options_->watch_root_cert();
|
||||
grpc_security_status status = grpc_ssl_tsi_client_handshaker_factory_init(
|
||||
pem_key_cert_pair,
|
||||
pem_root_certs.empty() || use_default_roots ? nullptr
|
||||
: pem_root_certs.c_str(),
|
||||
skip_server_certificate_verification,
|
||||
grpc_get_tsi_tls_version(options_->min_tls_version()),
|
||||
grpc_get_tsi_tls_version(options_->max_tls_version()), ssl_session_cache_,
|
||||
&client_handshaker_factory_);
|
||||
/* Free memory. */
|
||||
if (pem_key_cert_pair != nullptr) {
|
||||
grpc_tsi_ssl_pem_key_cert_pairs_destroy(pem_key_cert_pair, 1);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
void TlsChannelSecurityConnector::ServerAuthorizationCheckDone(
|
||||
grpc_tls_server_authorization_check_arg* arg) {
|
||||
GPR_ASSERT(arg != nullptr);
|
||||
ExecCtx exec_ctx;
|
||||
grpc_error_handle error = ProcessServerAuthorizationCheckResult(arg);
|
||||
TlsChannelSecurityConnector* connector =
|
||||
static_cast<TlsChannelSecurityConnector*>(arg->cb_user_data);
|
||||
ExecCtx::Run(DEBUG_LOCATION, connector->on_peer_checked_, error);
|
||||
}
|
||||
|
||||
grpc_error_handle
|
||||
TlsChannelSecurityConnector::ProcessServerAuthorizationCheckResult(
|
||||
grpc_tls_server_authorization_check_arg* arg) {
|
||||
grpc_error_handle error = GRPC_ERROR_NONE;
|
||||
/* Server authorization check is cancelled by caller. */
|
||||
if (arg->status == GRPC_STATUS_CANCELLED) {
|
||||
error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(
|
||||
absl::StrCat("Server authorization check is cancelled by the caller "
|
||||
"with error: ",
|
||||
arg->error_details->error_details())
|
||||
.c_str());
|
||||
} else if (arg->status == GRPC_STATUS_OK) {
|
||||
/* Server authorization check completed successfully but returned check
|
||||
* failure. */
|
||||
if (!arg->success) {
|
||||
error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(
|
||||
absl::StrCat("Server authorization check failed with error: ",
|
||||
arg->error_details->error_details())
|
||||
.c_str());
|
||||
}
|
||||
/* Server authorization check did not complete correctly. */
|
||||
} else {
|
||||
error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(
|
||||
absl::StrCat(
|
||||
"Server authorization check did not finish correctly with error: ",
|
||||
arg->error_details->error_details())
|
||||
.c_str());
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
grpc_tls_server_authorization_check_arg*
|
||||
TlsChannelSecurityConnector::ServerAuthorizationCheckArgCreate(
|
||||
void* user_data) {
|
||||
grpc_tls_server_authorization_check_arg* arg =
|
||||
new grpc_tls_server_authorization_check_arg();
|
||||
arg->target_name = nullptr;
|
||||
arg->peer_cert = nullptr;
|
||||
arg->peer_cert_full_chain = nullptr;
|
||||
arg->subject_alternative_names = nullptr;
|
||||
arg->subject_alternative_names_size = 0;
|
||||
arg->error_details = new grpc_tls_error_details();
|
||||
arg->cb = ServerAuthorizationCheckDone;
|
||||
arg->cb_user_data = user_data;
|
||||
arg->status = GRPC_STATUS_OK;
|
||||
return arg;
|
||||
}
|
||||
|
||||
void TlsChannelSecurityConnector::ServerAuthorizationCheckArgDestroy(
|
||||
grpc_tls_server_authorization_check_arg* arg) {
|
||||
if (arg == nullptr) {
|
||||
return;
|
||||
}
|
||||
gpr_check_free(const_cast<char*>(arg->target_name));
|
||||
gpr_check_free(const_cast<char*>(arg->peer_cert));
|
||||
gpr_check_free(const_cast<char*>(arg->peer_cert_full_chain));
|
||||
for (size_t i = 0; i < arg->subject_alternative_names_size; ++i) {
|
||||
delete[] arg->subject_alternative_names[i];
|
||||
}
|
||||
delete[] arg->subject_alternative_names;
|
||||
delete arg->error_details;
|
||||
if (arg->destroy_context != nullptr) {
|
||||
arg->destroy_context(arg->context);
|
||||
}
|
||||
delete arg;
|
||||
arg = nullptr;
|
||||
}
|
||||
|
||||
// -------------------server security connector-------------------
|
||||
RefCountedPtr<grpc_server_security_connector>
|
||||
TlsServerSecurityConnector::CreateTlsServerSecurityConnector(
|
||||
RefCountedPtr<grpc_server_credentials> server_creds,
|
||||
RefCountedPtr<grpc_tls_credentials_options> options) {
|
||||
if (server_creds == nullptr) {
|
||||
gpr_log(GPR_ERROR,
|
||||
"server_creds is nullptr in "
|
||||
"TlsServerSecurityConnectorCreate()");
|
||||
return nullptr;
|
||||
}
|
||||
if (options == nullptr) {
|
||||
gpr_log(GPR_ERROR,
|
||||
"options is nullptr in "
|
||||
"TlsServerSecurityConnectorCreate()");
|
||||
return nullptr;
|
||||
}
|
||||
return MakeRefCounted<TlsServerSecurityConnector>(std::move(server_creds),
|
||||
std::move(options));
|
||||
}
|
||||
|
||||
void TlsServerSecurityConnector::ClientAuthorizationCheckDone(
|
||||
grpc_tls_server_authorization_check_arg* arg) {
|
||||
GPR_ASSERT(arg != nullptr);
|
||||
ExecCtx exec_ctx;
|
||||
grpc_error_handle error = ProcessClientAuthorizationCheckResult(arg);
|
||||
TlsServerSecurityConnector* connector =
|
||||
static_cast<TlsServerSecurityConnector*>(arg->cb_user_data);
|
||||
ExecCtx::Run(DEBUG_LOCATION, connector->on_peer_checked_, error);
|
||||
}
|
||||
|
||||
grpc_error_handle
|
||||
TlsServerSecurityConnector::ProcessClientAuthorizationCheckResult(
|
||||
grpc_tls_server_authorization_check_arg* arg) {
|
||||
grpc_error_handle error = GRPC_ERROR_NONE;
|
||||
/* Client authorization check is cancelled by caller. */
|
||||
if (arg->status == GRPC_STATUS_CANCELLED) {
|
||||
error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(
|
||||
absl::StrCat("Client authorization check is cancelled by the caller "
|
||||
"with error: ",
|
||||
arg->error_details->error_details())
|
||||
.c_str());
|
||||
} else if (arg->status == GRPC_STATUS_OK) {
|
||||
/* Client authorization check completed successfully but returned check
|
||||
* failure. */
|
||||
if (!arg->success) {
|
||||
error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(
|
||||
absl::StrCat("Client authorization check failed with error: ",
|
||||
arg->error_details->error_details())
|
||||
.c_str());
|
||||
}
|
||||
/* Client authorization check did not complete correctly. */
|
||||
} else {
|
||||
error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(
|
||||
absl::StrCat(
|
||||
"Client authorization check did not finish correctly with error: ",
|
||||
arg->error_details->error_details())
|
||||
.c_str());
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
grpc_tls_server_authorization_check_arg*
|
||||
TlsServerSecurityConnector::ClientAuthorizationCheckArgCreate(
|
||||
void* user_data) {
|
||||
grpc_tls_server_authorization_check_arg* arg =
|
||||
new grpc_tls_server_authorization_check_arg();
|
||||
arg->target_name = nullptr;
|
||||
arg->peer_cert = nullptr;
|
||||
arg->peer_cert_full_chain = nullptr;
|
||||
arg->subject_alternative_names = nullptr;
|
||||
arg->subject_alternative_names_size = 0;
|
||||
arg->error_details = new grpc_tls_error_details();
|
||||
arg->cb = ClientAuthorizationCheckDone;
|
||||
arg->cb_user_data = user_data;
|
||||
arg->status = GRPC_STATUS_OK;
|
||||
return arg;
|
||||
}
|
||||
|
||||
void TlsServerSecurityConnector::ClientAuthorizationCheckArgDestroy(
|
||||
grpc_tls_server_authorization_check_arg* arg) {
|
||||
if (arg == nullptr) {
|
||||
return;
|
||||
}
|
||||
gpr_check_free(const_cast<char*>(arg->target_name));
|
||||
gpr_check_free(const_cast<char*>(arg->peer_cert));
|
||||
gpr_check_free(const_cast<char*>(arg->peer_cert_full_chain));
|
||||
for (size_t i = 0; i < arg->subject_alternative_names_size; ++i) {
|
||||
delete[] arg->subject_alternative_names[i];
|
||||
}
|
||||
delete[] arg->subject_alternative_names;
|
||||
delete arg->error_details;
|
||||
if (arg->destroy_context != nullptr) {
|
||||
arg->destroy_context(arg->context);
|
||||
}
|
||||
delete arg;
|
||||
arg = nullptr;
|
||||
}
|
||||
|
||||
TlsServerSecurityConnector::TlsServerSecurityConnector(
|
||||
RefCountedPtr<grpc_server_credentials> server_creds,
|
||||
RefCountedPtr<grpc_tls_credentials_options> options)
|
||||
: grpc_server_security_connector(GRPC_SSL_URL_SCHEME,
|
||||
std::move(server_creds)),
|
||||
options_(std::move(options)) {
|
||||
check_arg_ = ClientAuthorizationCheckArgCreate(this);
|
||||
// Create a watcher.
|
||||
auto watcher_ptr = absl::make_unique<TlsServerCertificateWatcher>(this);
|
||||
certificate_watcher_ = watcher_ptr.get();
|
||||
// Register the watcher with the distributor.
|
||||
grpc_tls_certificate_distributor* distributor =
|
||||
options_->certificate_distributor();
|
||||
absl::optional<std::string> watched_root_cert_name;
|
||||
if (options_->watch_root_cert()) {
|
||||
watched_root_cert_name = options_->root_cert_name();
|
||||
}
|
||||
absl::optional<std::string> watched_identity_cert_name;
|
||||
if (options_->watch_identity_pair()) {
|
||||
watched_identity_cert_name = options_->identity_cert_name();
|
||||
}
|
||||
// Server side won't use default system roots at any time.
|
||||
distributor->WatchTlsCertificates(std::move(watcher_ptr),
|
||||
watched_root_cert_name,
|
||||
watched_identity_cert_name);
|
||||
}
|
||||
|
||||
TlsServerSecurityConnector::~TlsServerSecurityConnector() {
|
||||
// Cancel all the watchers.
|
||||
grpc_tls_certificate_distributor* distributor =
|
||||
options_->certificate_distributor();
|
||||
if (distributor != nullptr) {
|
||||
distributor->CancelTlsCertificatesWatch(certificate_watcher_);
|
||||
}
|
||||
if (server_handshaker_factory_ != nullptr) {
|
||||
tsi_ssl_server_handshaker_factory_unref(server_handshaker_factory_);
|
||||
}
|
||||
if (check_arg_ != nullptr) {
|
||||
ClientAuthorizationCheckArgDestroy(check_arg_);
|
||||
}
|
||||
}
|
||||
|
||||
void TlsServerSecurityConnector::add_handshakers(
|
||||
const grpc_channel_args* args, grpc_pollset_set* /*interested_parties*/,
|
||||
HandshakeManager* handshake_mgr) {
|
||||
MutexLock lock(&mu_);
|
||||
if (server_handshaker_factory_ != nullptr) {
|
||||
// Instantiate TSI handshaker.
|
||||
tsi_handshaker* tsi_hs = nullptr;
|
||||
tsi_result result = tsi_ssl_server_handshaker_factory_create_handshaker(
|
||||
server_handshaker_factory_, &tsi_hs);
|
||||
if (result != TSI_OK) {
|
||||
gpr_log(GPR_ERROR, "Handshaker creation failed with error %s.",
|
||||
tsi_result_to_string(result));
|
||||
return;
|
||||
}
|
||||
// Create handshakers.
|
||||
handshake_mgr->Add(SecurityHandshakerCreate(tsi_hs, this, args));
|
||||
return;
|
||||
}
|
||||
// TODO(ZhenLian): Implement the logic(delegation to
|
||||
// BlockOnInitialCredentialHandshaker) when certificates are not ready.
|
||||
gpr_log(GPR_ERROR, "%s not supported yet.",
|
||||
"Server BlockOnInitialCredentialHandshaker");
|
||||
}
|
||||
|
||||
void TlsServerSecurityConnector::check_peer(
|
||||
tsi_peer peer, grpc_endpoint* /*ep*/,
|
||||
RefCountedPtr<grpc_auth_context>* auth_context,
|
||||
grpc_closure* on_peer_checked) {
|
||||
grpc_error_handle error = grpc_ssl_check_alpn(&peer);
|
||||
if (error != GRPC_ERROR_NONE) {
|
||||
ExecCtx::Run(DEBUG_LOCATION, on_peer_checked, error);
|
||||
tsi_peer_destruct(&peer);
|
||||
return;
|
||||
}
|
||||
*auth_context =
|
||||
grpc_ssl_peer_to_auth_context(&peer, GRPC_TLS_TRANSPORT_SECURITY_TYPE);
|
||||
if (options_->server_verification_option() == GRPC_TLS_SERVER_VERIFICATION) {
|
||||
/* Do the default host name check if specifying the target name. */
|
||||
error = internal::TlsCheckHostName("", &peer);
|
||||
if (error != GRPC_ERROR_NONE) {
|
||||
ExecCtx::Run(DEBUG_LOCATION, on_peer_checked, error);
|
||||
tsi_peer_destruct(&peer);
|
||||
return;
|
||||
}
|
||||
}
|
||||
/* Do the custom client authorization check, if specified by the user. */
|
||||
const grpc_tls_server_authorization_check_config* config =
|
||||
options_->server_authorization_check_config();
|
||||
/* If client authorization config is not null, use it to perform
|
||||
* client authorization check. */
|
||||
if (config != nullptr) {
|
||||
const tsi_peer_property* p =
|
||||
tsi_peer_get_property_by_name(&peer, TSI_X509_PEM_CERT_PROPERTY);
|
||||
if (p == nullptr) {
|
||||
error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
|
||||
"Cannot check peer: missing pem cert property.");
|
||||
} else {
|
||||
char* peer_pem = static_cast<char*>(gpr_zalloc(p->value.length + 1));
|
||||
memcpy(peer_pem, p->value.data, p->value.length);
|
||||
GPR_ASSERT(check_arg_ != nullptr);
|
||||
check_arg_->peer_cert = gpr_strdup(peer_pem);
|
||||
check_arg_->target_name = gpr_strdup("");
|
||||
on_peer_checked_ = on_peer_checked;
|
||||
gpr_check_free(peer_pem);
|
||||
const tsi_peer_property* chain = tsi_peer_get_property_by_name(
|
||||
&peer, TSI_X509_PEM_CERT_CHAIN_PROPERTY);
|
||||
if (chain != nullptr) {
|
||||
char* peer_pem_chain =
|
||||
static_cast<char*>(gpr_zalloc(chain->value.length + 1));
|
||||
memcpy(peer_pem_chain, chain->value.data, chain->value.length);
|
||||
check_arg_->peer_cert_full_chain =
|
||||
check_arg_->peer_cert_full_chain == nullptr
|
||||
? gpr_strdup(peer_pem_chain)
|
||||
: check_arg_->peer_cert_full_chain;
|
||||
gpr_check_free(peer_pem_chain);
|
||||
}
|
||||
// TODO(zhenlian) - This should be cleaned up as part of the custom
|
||||
// verification changes. Fill in the subject alternative names
|
||||
std::vector<char*> subject_alternative_names;
|
||||
for (size_t i = 0; i < peer.property_count; i++) {
|
||||
const tsi_peer_property* prop = &peer.properties[i];
|
||||
if (strcmp(prop->name,
|
||||
TSI_X509_SUBJECT_ALTERNATIVE_NAME_PEER_PROPERTY) == 0) {
|
||||
char* san = new char[prop->value.length + 1];
|
||||
memcpy(san, prop->value.data, prop->value.length);
|
||||
san[prop->value.length] = '\0';
|
||||
subject_alternative_names.emplace_back(san);
|
||||
}
|
||||
}
|
||||
if (check_arg_->subject_alternative_names != nullptr) {
|
||||
for (size_t i = 0; i < check_arg_->subject_alternative_names_size;
|
||||
++i) {
|
||||
delete[] check_arg_->subject_alternative_names[i];
|
||||
}
|
||||
delete[] check_arg_->subject_alternative_names;
|
||||
}
|
||||
check_arg_->subject_alternative_names_size =
|
||||
subject_alternative_names.size();
|
||||
if (subject_alternative_names.empty()) {
|
||||
check_arg_->subject_alternative_names = nullptr;
|
||||
} else {
|
||||
check_arg_->subject_alternative_names =
|
||||
new char*[check_arg_->subject_alternative_names_size];
|
||||
for (size_t i = 0; i < check_arg_->subject_alternative_names_size;
|
||||
++i) {
|
||||
check_arg_->subject_alternative_names[i] =
|
||||
subject_alternative_names[i];
|
||||
}
|
||||
}
|
||||
int callback_status = config->Schedule(check_arg_);
|
||||
/* Client authorization check is handled asynchronously. */
|
||||
if (callback_status) {
|
||||
tsi_peer_destruct(&peer);
|
||||
return;
|
||||
}
|
||||
/* Client authorization check is handled synchronously. */
|
||||
error = ProcessClientAuthorizationCheckResult(check_arg_);
|
||||
}
|
||||
}
|
||||
ExecCtx::Run(DEBUG_LOCATION, on_peer_checked, error);
|
||||
tsi_peer_destruct(&peer);
|
||||
}
|
||||
|
||||
int TlsServerSecurityConnector::cmp(
|
||||
const grpc_security_connector* other) const {
|
||||
return server_security_connector_cmp(
|
||||
static_cast<const grpc_server_security_connector*>(other));
|
||||
}
|
||||
|
||||
void TlsServerSecurityConnector::TlsServerCertificateWatcher::
|
||||
OnCertificatesChanged(absl::optional<absl::string_view> root_certs,
|
||||
absl::optional<PemKeyCertPairList> key_cert_pairs) {
|
||||
GPR_ASSERT(security_connector_ != nullptr);
|
||||
MutexLock lock(&security_connector_->mu_);
|
||||
if (root_certs.has_value()) {
|
||||
security_connector_->pem_root_certs_ = root_certs;
|
||||
}
|
||||
if (key_cert_pairs.has_value()) {
|
||||
security_connector_->pem_key_cert_pair_list_ = std::move(key_cert_pairs);
|
||||
}
|
||||
bool root_being_watched = security_connector_->options_->watch_root_cert();
|
||||
bool root_has_value = security_connector_->pem_root_certs_.has_value();
|
||||
bool identity_being_watched =
|
||||
security_connector_->options_->watch_identity_pair();
|
||||
bool identity_has_value =
|
||||
security_connector_->pem_key_cert_pair_list_.has_value();
|
||||
if ((root_being_watched && root_has_value && identity_being_watched &&
|
||||
identity_has_value) ||
|
||||
(root_being_watched && root_has_value && !identity_being_watched) ||
|
||||
(!root_being_watched && identity_being_watched && identity_has_value)) {
|
||||
if (security_connector_->UpdateHandshakerFactoryLocked() !=
|
||||
GRPC_SECURITY_OK) {
|
||||
gpr_log(GPR_ERROR, "Update handshaker factory failed.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(ZhenLian): implement the logic to signal waiting handshakers once
|
||||
// BlockOnInitialCredentialHandshaker is implemented.
|
||||
void TlsServerSecurityConnector::TlsServerCertificateWatcher::OnError(
|
||||
grpc_error_handle root_cert_error, grpc_error_handle identity_cert_error) {
|
||||
if (root_cert_error != GRPC_ERROR_NONE) {
|
||||
gpr_log(GPR_ERROR,
|
||||
"TlsServerCertificateWatcher getting root_cert_error: %s",
|
||||
grpc_error_std_string(root_cert_error).c_str());
|
||||
}
|
||||
if (identity_cert_error != GRPC_ERROR_NONE) {
|
||||
gpr_log(GPR_ERROR,
|
||||
"TlsServerCertificateWatcher getting identity_cert_error: %s",
|
||||
grpc_error_std_string(identity_cert_error).c_str());
|
||||
}
|
||||
GRPC_ERROR_UNREF(root_cert_error);
|
||||
GRPC_ERROR_UNREF(identity_cert_error);
|
||||
}
|
||||
|
||||
// TODO(ZhenLian): implement the logic to signal waiting handshakers once
|
||||
// BlockOnInitialCredentialHandshaker is implemented.
|
||||
grpc_security_status
|
||||
TlsServerSecurityConnector::UpdateHandshakerFactoryLocked() {
|
||||
/* Free the server handshaker factory if exists. */
|
||||
if (server_handshaker_factory_ != nullptr) {
|
||||
tsi_ssl_server_handshaker_factory_unref(server_handshaker_factory_);
|
||||
}
|
||||
// The identity certs on the server side shouldn't be empty.
|
||||
GPR_ASSERT(pem_key_cert_pair_list_.has_value());
|
||||
GPR_ASSERT(!(*pem_key_cert_pair_list_).empty());
|
||||
std::string pem_root_certs;
|
||||
if (pem_root_certs_.has_value()) {
|
||||
// TODO(ZhenLian): update the underlying TSI layer to use C++ types like
|
||||
// std::string and absl::string_view to avoid making another copy here.
|
||||
pem_root_certs = std::string(*pem_root_certs_);
|
||||
}
|
||||
tsi_ssl_pem_key_cert_pair* pem_key_cert_pairs = nullptr;
|
||||
pem_key_cert_pairs = ConvertToTsiPemKeyCertPair(*pem_key_cert_pair_list_);
|
||||
size_t num_key_cert_pairs = (*pem_key_cert_pair_list_).size();
|
||||
grpc_security_status status = grpc_ssl_tsi_server_handshaker_factory_init(
|
||||
pem_key_cert_pairs, num_key_cert_pairs,
|
||||
pem_root_certs.empty() ? nullptr : pem_root_certs.c_str(),
|
||||
options_->cert_request_type(),
|
||||
grpc_get_tsi_tls_version(options_->min_tls_version()),
|
||||
grpc_get_tsi_tls_version(options_->max_tls_version()),
|
||||
&server_handshaker_factory_);
|
||||
/* Free memory. */
|
||||
grpc_tsi_ssl_pem_key_cert_pairs_destroy(pem_key_cert_pairs,
|
||||
num_key_cert_pairs);
|
||||
return status;
|
||||
}
|
||||
|
||||
namespace internal {
|
||||
|
||||
grpc_error_handle TlsCheckHostName(const char* peer_name,
|
||||
const tsi_peer* peer) {
|
||||
/* Check the peer name if specified. */
|
||||
if (peer_name != nullptr && !grpc_ssl_host_matches_name(peer, peer_name)) {
|
||||
return GRPC_ERROR_CREATE_FROM_COPIED_STRING(
|
||||
absl::StrCat("Peer name ", peer_name, " is not in peer certificate")
|
||||
.c_str());
|
||||
}
|
||||
return GRPC_ERROR_NONE;
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
|
||||
} // namespace grpc_core
|
267
demos/ra_tls/grpc/v1.38.1/src/core/lib/security/security_connector/tls/tls_security_connector.h
Normal file
267
demos/ra_tls/grpc/v1.38.1/src/core/lib/security/security_connector/tls/tls_security_connector.h
Normal file
@ -0,0 +1,267 @@
|
||||
/*
|
||||
*
|
||||
* Copyright 2018 gRPC authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef GRPC_CORE_LIB_SECURITY_SECURITY_CONNECTOR_TLS_TLS_SECURITY_CONNECTOR_H
|
||||
#define GRPC_CORE_LIB_SECURITY_SECURITY_CONNECTOR_TLS_TLS_SECURITY_CONNECTOR_H
|
||||
|
||||
#include <grpc/support/port_platform.h>
|
||||
|
||||
#include "src/core/lib/gprpp/sync.h"
|
||||
#include "src/core/lib/security/context/security_context.h"
|
||||
#include "src/core/lib/security/credentials/tls/grpc_tls_certificate_provider.h"
|
||||
#include "src/core/lib/security/credentials/tls/grpc_tls_credentials_options.h"
|
||||
|
||||
#define GRPC_TLS_TRANSPORT_SECURITY_TYPE "tls"
|
||||
|
||||
namespace grpc_core {
|
||||
|
||||
// Channel security connector using TLS as transport security protocol.
|
||||
class TlsChannelSecurityConnector final
|
||||
: public grpc_channel_security_connector {
|
||||
public:
|
||||
// static factory method to create a TLS channel security connector.
|
||||
static RefCountedPtr<grpc_channel_security_connector>
|
||||
CreateTlsChannelSecurityConnector(
|
||||
RefCountedPtr<grpc_channel_credentials> channel_creds,
|
||||
RefCountedPtr<grpc_tls_credentials_options> options,
|
||||
RefCountedPtr<grpc_call_credentials> request_metadata_creds,
|
||||
const char* target_name, const char* overridden_target_name,
|
||||
tsi_ssl_session_cache* ssl_session_cache);
|
||||
|
||||
TlsChannelSecurityConnector(
|
||||
RefCountedPtr<grpc_channel_credentials> channel_creds,
|
||||
RefCountedPtr<grpc_tls_credentials_options> options,
|
||||
RefCountedPtr<grpc_call_credentials> request_metadata_creds,
|
||||
const char* target_name, const char* overridden_target_name,
|
||||
tsi_ssl_session_cache* ssl_session_cache);
|
||||
|
||||
~TlsChannelSecurityConnector() override;
|
||||
|
||||
void add_handshakers(const grpc_channel_args* args,
|
||||
grpc_pollset_set* interested_parties,
|
||||
HandshakeManager* handshake_mgr) override;
|
||||
|
||||
void check_peer(tsi_peer peer, grpc_endpoint* ep,
|
||||
RefCountedPtr<grpc_auth_context>* auth_context,
|
||||
grpc_closure* on_peer_checked) override;
|
||||
|
||||
void cancel_check_peer(grpc_closure* /*on_peer_checked*/,
|
||||
grpc_error_handle error) override {
|
||||
// TODO(ZhenLian): call verifier->cancel() once the verifier is ready.
|
||||
GRPC_ERROR_UNREF(error);
|
||||
}
|
||||
|
||||
int cmp(const grpc_security_connector* other_sc) const override;
|
||||
|
||||
bool check_call_host(absl::string_view host, grpc_auth_context* auth_context,
|
||||
grpc_closure* on_call_host_checked,
|
||||
grpc_error_handle* error) override;
|
||||
|
||||
void cancel_check_call_host(grpc_closure* on_call_host_checked,
|
||||
grpc_error_handle error) override;
|
||||
|
||||
tsi_ssl_client_handshaker_factory* ClientHandshakerFactoryForTesting() {
|
||||
MutexLock lock(&mu_);
|
||||
return client_handshaker_factory_;
|
||||
};
|
||||
|
||||
absl::optional<absl::string_view> RootCertsForTesting() {
|
||||
MutexLock lock(&mu_);
|
||||
return pem_root_certs_;
|
||||
}
|
||||
|
||||
absl::optional<PemKeyCertPairList> KeyCertPairListForTesting() {
|
||||
MutexLock lock(&mu_);
|
||||
return pem_key_cert_pair_list_;
|
||||
}
|
||||
|
||||
private:
|
||||
// A watcher that watches certificate updates from
|
||||
// grpc_tls_certificate_distributor. It will never outlive
|
||||
// |security_connector_|.
|
||||
class TlsChannelCertificateWatcher : public grpc_tls_certificate_distributor::
|
||||
TlsCertificatesWatcherInterface {
|
||||
public:
|
||||
explicit TlsChannelCertificateWatcher(
|
||||
TlsChannelSecurityConnector* security_connector)
|
||||
: security_connector_(security_connector) {}
|
||||
void OnCertificatesChanged(
|
||||
absl::optional<absl::string_view> root_certs,
|
||||
absl::optional<PemKeyCertPairList> key_cert_pairs) override;
|
||||
void OnError(grpc_error_handle root_cert_error,
|
||||
grpc_error_handle identity_cert_error) override;
|
||||
|
||||
private:
|
||||
TlsChannelSecurityConnector* security_connector_ = nullptr;
|
||||
};
|
||||
|
||||
// Updates |client_handshaker_factory_| when the certificates that
|
||||
// |certificate_watcher_| is watching get updated.
|
||||
grpc_security_status UpdateHandshakerFactoryLocked()
|
||||
ABSL_EXCLUSIVE_LOCKS_REQUIRED(mu_);
|
||||
|
||||
// gRPC-provided callback executed by application, which servers to bring the
|
||||
// control back to gRPC core.
|
||||
static void ServerAuthorizationCheckDone(
|
||||
grpc_tls_server_authorization_check_arg* arg);
|
||||
|
||||
// A util function to process server authorization check result.
|
||||
static grpc_error_handle ProcessServerAuthorizationCheckResult(
|
||||
grpc_tls_server_authorization_check_arg* arg);
|
||||
|
||||
// A util function to create a server authorization check arg instance.
|
||||
static grpc_tls_server_authorization_check_arg*
|
||||
ServerAuthorizationCheckArgCreate(void* user_data);
|
||||
|
||||
// A util function to destroy a server authorization check arg instance.
|
||||
static void ServerAuthorizationCheckArgDestroy(
|
||||
grpc_tls_server_authorization_check_arg* arg);
|
||||
|
||||
RefCountedPtr<grpc_tls_credentials_options> options_;
|
||||
grpc_tls_certificate_distributor::TlsCertificatesWatcherInterface*
|
||||
certificate_watcher_ = nullptr;
|
||||
grpc_closure* on_peer_checked_ = nullptr;
|
||||
std::string target_name_;
|
||||
std::string overridden_target_name_;
|
||||
grpc_tls_server_authorization_check_arg* check_arg_ = nullptr;
|
||||
|
||||
Mutex mu_;
|
||||
tsi_ssl_client_handshaker_factory* client_handshaker_factory_
|
||||
ABSL_GUARDED_BY(mu_) = nullptr;
|
||||
tsi_ssl_session_cache* ssl_session_cache_ ABSL_GUARDED_BY(mu_) = nullptr;
|
||||
absl::optional<absl::string_view> pem_root_certs_ ABSL_GUARDED_BY(mu_);
|
||||
absl::optional<PemKeyCertPairList> pem_key_cert_pair_list_
|
||||
ABSL_GUARDED_BY(mu_);
|
||||
};
|
||||
|
||||
// Server security connector using TLS as transport security protocol.
|
||||
class TlsServerSecurityConnector final : public grpc_server_security_connector {
|
||||
public:
|
||||
// static factory method to create a TLS server security connector.
|
||||
static RefCountedPtr<grpc_server_security_connector>
|
||||
CreateTlsServerSecurityConnector(
|
||||
RefCountedPtr<grpc_server_credentials> server_creds,
|
||||
RefCountedPtr<grpc_tls_credentials_options> options);
|
||||
|
||||
TlsServerSecurityConnector(
|
||||
RefCountedPtr<grpc_server_credentials> server_creds,
|
||||
RefCountedPtr<grpc_tls_credentials_options> options);
|
||||
~TlsServerSecurityConnector() override;
|
||||
|
||||
void add_handshakers(const grpc_channel_args* args,
|
||||
grpc_pollset_set* interested_parties,
|
||||
HandshakeManager* handshake_mgr) override;
|
||||
|
||||
void check_peer(tsi_peer peer, grpc_endpoint* ep,
|
||||
RefCountedPtr<grpc_auth_context>* auth_context,
|
||||
grpc_closure* on_peer_checked) override;
|
||||
|
||||
void cancel_check_peer(grpc_closure* /*on_peer_checked*/,
|
||||
grpc_error_handle error) override {
|
||||
// TODO(ZhenLian): call verifier->cancel() once the verifier is ready.
|
||||
GRPC_ERROR_UNREF(error);
|
||||
}
|
||||
|
||||
int cmp(const grpc_security_connector* other) const override;
|
||||
|
||||
tsi_ssl_server_handshaker_factory* ServerHandshakerFactoryForTesting() {
|
||||
MutexLock lock(&mu_);
|
||||
return server_handshaker_factory_;
|
||||
};
|
||||
|
||||
const absl::optional<absl::string_view>& RootCertsForTesting() {
|
||||
MutexLock lock(&mu_);
|
||||
return pem_root_certs_;
|
||||
}
|
||||
|
||||
const absl::optional<PemKeyCertPairList>& KeyCertPairListForTesting() {
|
||||
MutexLock lock(&mu_);
|
||||
return pem_key_cert_pair_list_;
|
||||
}
|
||||
|
||||
private:
|
||||
// A watcher that watches certificate updates from
|
||||
// grpc_tls_certificate_distributor. It will never outlive
|
||||
// |security_connector_|.
|
||||
class TlsServerCertificateWatcher : public grpc_tls_certificate_distributor::
|
||||
TlsCertificatesWatcherInterface {
|
||||
public:
|
||||
explicit TlsServerCertificateWatcher(
|
||||
TlsServerSecurityConnector* security_connector)
|
||||
: security_connector_(security_connector) {}
|
||||
void OnCertificatesChanged(
|
||||
absl::optional<absl::string_view> root_certs,
|
||||
absl::optional<PemKeyCertPairList> key_cert_pairs) override;
|
||||
void OnError(grpc_error_handle root_cert_error,
|
||||
grpc_error_handle identity_cert_error) override;
|
||||
|
||||
private:
|
||||
TlsServerSecurityConnector* security_connector_ = nullptr;
|
||||
};
|
||||
|
||||
// Updates |server_handshaker_factory_| when the certificates that
|
||||
// |certificate_watcher_| is watching get updated.
|
||||
grpc_security_status UpdateHandshakerFactoryLocked()
|
||||
ABSL_EXCLUSIVE_LOCKS_REQUIRED(mu_);
|
||||
|
||||
// gRPC-provided callback executed by application, which servers to bring the
|
||||
// control back to gRPC core.
|
||||
static void ClientAuthorizationCheckDone(
|
||||
grpc_tls_server_authorization_check_arg* arg);
|
||||
|
||||
// A util function to process server authorization check result.
|
||||
static grpc_error_handle ProcessClientAuthorizationCheckResult(
|
||||
grpc_tls_server_authorization_check_arg* arg);
|
||||
|
||||
// A util function to create a server authorization check arg instance.
|
||||
static grpc_tls_server_authorization_check_arg*
|
||||
ClientAuthorizationCheckArgCreate(void* user_data);
|
||||
|
||||
// A util function to destroy a server authorization check arg instance.
|
||||
static void ClientAuthorizationCheckArgDestroy(
|
||||
grpc_tls_server_authorization_check_arg* arg);
|
||||
|
||||
RefCountedPtr<grpc_tls_credentials_options> options_;
|
||||
|
||||
grpc_tls_certificate_distributor::TlsCertificatesWatcherInterface*
|
||||
certificate_watcher_ = nullptr;
|
||||
grpc_closure* on_peer_checked_ = nullptr;
|
||||
std::string target_name_ = "localhost";
|
||||
std::string overridden_target_name_= "localhost";
|
||||
grpc_tls_server_authorization_check_arg* check_arg_ = nullptr;
|
||||
|
||||
Mutex mu_;
|
||||
tsi_ssl_server_handshaker_factory* server_handshaker_factory_
|
||||
ABSL_GUARDED_BY(mu_) = nullptr;
|
||||
absl::optional<absl::string_view> pem_root_certs_ ABSL_GUARDED_BY(mu_);
|
||||
absl::optional<PemKeyCertPairList> pem_key_cert_pair_list_
|
||||
ABSL_GUARDED_BY(mu_);
|
||||
};
|
||||
|
||||
// ---- Functions below are exposed for testing only -----------------------
|
||||
namespace internal {
|
||||
|
||||
// TlsCheckHostName checks if |peer_name| matches the identity information
|
||||
// contained in |peer|. This is AKA hostname check.
|
||||
grpc_error_handle TlsCheckHostName(const char* peer_name, const tsi_peer* peer);
|
||||
|
||||
} // namespace internal
|
||||
|
||||
} // namespace grpc_core
|
||||
|
||||
#endif // GRPC_CORE_LIB_SECURITY_SECURITY_CONNECTOR_TLS_TLS_SECURITY_CONNECTOR_H
|
567
demos/ra_tls/grpc/v1.38.1/src/cpp/sgx/cJSON.c
Normal file
567
demos/ra_tls/grpc/v1.38.1/src/cpp/sgx/cJSON.c
Normal file
@ -0,0 +1,567 @@
|
||||
/*
|
||||
Copyright (c) 2009 Dave Gamble
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/* cJSON */
|
||||
/* JSON parser in C. */
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
#include <float.h>
|
||||
#include <limits.h>
|
||||
#include <ctype.h>
|
||||
#include "cJSON.h"
|
||||
|
||||
static const char *ep;
|
||||
|
||||
const char *cJSON_GetErrorPtr(void) {return ep;}
|
||||
|
||||
static int cJSON_strcasecmp(const char *s1,const char *s2)
|
||||
{
|
||||
if (!s1) return (s1==s2)?0:1;if (!s2) return 1;
|
||||
for(; tolower(*s1) == tolower(*s2); ++s1, ++s2) if(*s1 == 0) return 0;
|
||||
return tolower(*(const unsigned char *)s1) - tolower(*(const unsigned char *)s2);
|
||||
}
|
||||
|
||||
static void *(*cJSON_malloc)(size_t sz) = malloc;
|
||||
static void (*cJSON_free)(void *ptr) = free;
|
||||
|
||||
static char* cJSON_strdup(const char* str)
|
||||
{
|
||||
size_t len;
|
||||
char* copy;
|
||||
|
||||
len = strlen(str) + 1;
|
||||
if (!(copy = (char*)cJSON_malloc(len))) return 0;
|
||||
memcpy(copy,str,len);
|
||||
return copy;
|
||||
}
|
||||
|
||||
void cJSON_InitHooks(cJSON_Hooks* hooks)
|
||||
{
|
||||
if (!hooks) { /* Reset hooks */
|
||||
cJSON_malloc = malloc;
|
||||
cJSON_free = free;
|
||||
return;
|
||||
}
|
||||
|
||||
cJSON_malloc = (hooks->malloc_fn)?hooks->malloc_fn:malloc;
|
||||
cJSON_free = (hooks->free_fn)?hooks->free_fn:free;
|
||||
}
|
||||
|
||||
/* Internal constructor. */
|
||||
static cJSON *cJSON_New_Item(void)
|
||||
{
|
||||
cJSON* node = (cJSON*)cJSON_malloc(sizeof(cJSON));
|
||||
if (node) memset(node,0,sizeof(cJSON));
|
||||
return node;
|
||||
}
|
||||
|
||||
/* Delete a cJSON structure. */
|
||||
void cJSON_Delete(cJSON *c)
|
||||
{
|
||||
cJSON *next;
|
||||
while (c)
|
||||
{
|
||||
next=c->next;
|
||||
if (!(c->type&cJSON_IsReference) && c->child) cJSON_Delete(c->child);
|
||||
if (!(c->type&cJSON_IsReference) && c->valuestring) cJSON_free(c->valuestring);
|
||||
if (c->string) cJSON_free(c->string);
|
||||
cJSON_free(c);
|
||||
c=next;
|
||||
}
|
||||
}
|
||||
|
||||
/* Parse the input text to generate a number, and populate the result into item. */
|
||||
static const char *parse_number(cJSON *item,const char *num)
|
||||
{
|
||||
double n=0,sign=1,scale=0;int subscale=0,signsubscale=1;
|
||||
|
||||
/* Could use sscanf for this? */
|
||||
if (*num=='-') sign=-1,num++; /* Has sign? */
|
||||
if (*num=='0') num++; /* is zero */
|
||||
if (*num>='1' && *num<='9') do n=(n*10.0)+(*num++ -'0'); while (*num>='0' && *num<='9'); /* Number? */
|
||||
if (*num=='.' && num[1]>='0' && num[1]<='9') {num++; do n=(n*10.0)+(*num++ -'0'),scale--; while (*num>='0' && *num<='9');} /* Fractional part? */
|
||||
if (*num=='e' || *num=='E') /* Exponent? */
|
||||
{ num++;if (*num=='+') num++; else if (*num=='-') signsubscale=-1,num++; /* With sign? */
|
||||
while (*num>='0' && *num<='9') subscale=(subscale*10)+(*num++ - '0'); /* Number? */
|
||||
}
|
||||
|
||||
n=sign*n*pow(10.0,(scale+subscale*signsubscale)); /* number = +/- number.fraction * 10^+/- exponent */
|
||||
|
||||
item->valuedouble=n;
|
||||
item->valueint=(int)n;
|
||||
item->type=cJSON_Number;
|
||||
return num;
|
||||
}
|
||||
|
||||
/* Render the number nicely from the given item into a string. */
|
||||
static char *print_number(cJSON *item)
|
||||
{
|
||||
char *str;
|
||||
double d=item->valuedouble;
|
||||
if (fabs(((double)item->valueint)-d)<=DBL_EPSILON && d<=INT_MAX && d>=INT_MIN)
|
||||
{
|
||||
str=(char*)cJSON_malloc(21); /* 2^64+1 can be represented in 21 chars. */
|
||||
if (str) sprintf(str,"%d",item->valueint);
|
||||
}
|
||||
else
|
||||
{
|
||||
str=(char*)cJSON_malloc(64); /* This is a nice tradeoff. */
|
||||
if (str)
|
||||
{
|
||||
if (fabs(floor(d)-d)<=DBL_EPSILON && fabs(d)<1.0e60)sprintf(str,"%.0f",d);
|
||||
else if (fabs(d)<1.0e-6 || fabs(d)>1.0e9) sprintf(str,"%e",d);
|
||||
else sprintf(str,"%f",d);
|
||||
}
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
/* Parse the input text into an unescaped cstring, and populate item. */
|
||||
static const unsigned char firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
|
||||
static const char *parse_string(cJSON *item,const char *str)
|
||||
{
|
||||
const char *ptr=str+1;char *ptr2;char *out;int len=0;unsigned uc,uc2;
|
||||
if (*str!='\"') {ep=str;return 0;} /* not a string! */
|
||||
|
||||
while (*ptr!='\"' && *ptr && ++len) if (*ptr++ == '\\') ptr++; /* Skip escaped quotes. */
|
||||
|
||||
out=(char*)cJSON_malloc(len+1); /* This is how long we need for the string, roughly. */
|
||||
if (!out) return 0;
|
||||
|
||||
ptr=str+1;ptr2=out;
|
||||
while (*ptr!='\"' && *ptr)
|
||||
{
|
||||
if (*ptr!='\\') *ptr2++=*ptr++;
|
||||
else
|
||||
{
|
||||
ptr++;
|
||||
switch (*ptr)
|
||||
{
|
||||
case 'b': *ptr2++='\b'; break;
|
||||
case 'f': *ptr2++='\f'; break;
|
||||
case 'n': *ptr2++='\n'; break;
|
||||
case 'r': *ptr2++='\r'; break;
|
||||
case 't': *ptr2++='\t'; break;
|
||||
case 'u': /* transcode utf16 to utf8. */
|
||||
sscanf(ptr+1,"%4x",&uc);ptr+=4; /* get the unicode char. */
|
||||
|
||||
if ((uc>=0xDC00 && uc<=0xDFFF) || uc==0) break; /* check for invalid. */
|
||||
|
||||
if (uc>=0xD800 && uc<=0xDBFF) /* UTF16 surrogate pairs. */
|
||||
{
|
||||
if (ptr[1]!='\\' || ptr[2]!='u') break; /* missing second-half of surrogate. */
|
||||
sscanf(ptr+3,"%4x",&uc2);ptr+=6;
|
||||
if (uc2<0xDC00 || uc2>0xDFFF) break; /* invalid second-half of surrogate. */
|
||||
uc=0x10000 + (((uc&0x3FF)<<10) | (uc2&0x3FF));
|
||||
}
|
||||
|
||||
len=4;if (uc<0x80) len=1;else if (uc<0x800) len=2;else if (uc<0x10000) len=3; ptr2+=len;
|
||||
|
||||
switch (len) {
|
||||
case 4: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6;
|
||||
case 3: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6;
|
||||
case 2: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6;
|
||||
case 1: *--ptr2 =(uc | firstByteMark[len]);
|
||||
}
|
||||
ptr2+=len;
|
||||
break;
|
||||
default: *ptr2++=*ptr; break;
|
||||
}
|
||||
ptr++;
|
||||
}
|
||||
}
|
||||
*ptr2=0;
|
||||
if (*ptr=='\"') ptr++;
|
||||
item->valuestring=out;
|
||||
item->type=cJSON_String;
|
||||
return ptr;
|
||||
}
|
||||
|
||||
/* Render the cstring provided to an escaped version that can be printed. */
|
||||
static char *print_string_ptr(const char *str)
|
||||
{
|
||||
const char *ptr;char *ptr2,*out;int len=0;unsigned char token;
|
||||
|
||||
if (!str) return cJSON_strdup("");
|
||||
ptr=str;while ((token=*ptr) && ++len) {if (strchr("\"\\\b\f\n\r\t",token)) len++; else if (token<32) len+=5;ptr++;}
|
||||
|
||||
out=(char*)cJSON_malloc(len+3);
|
||||
if (!out) return 0;
|
||||
|
||||
ptr2=out;ptr=str;
|
||||
*ptr2++='\"';
|
||||
while (*ptr)
|
||||
{
|
||||
if ((unsigned char)*ptr>31 && *ptr!='\"' && *ptr!='\\') *ptr2++=*ptr++;
|
||||
else
|
||||
{
|
||||
*ptr2++='\\';
|
||||
switch (token=*ptr++)
|
||||
{
|
||||
case '\\': *ptr2++='\\'; break;
|
||||
case '\"': *ptr2++='\"'; break;
|
||||
case '\b': *ptr2++='b'; break;
|
||||
case '\f': *ptr2++='f'; break;
|
||||
case '\n': *ptr2++='n'; break;
|
||||
case '\r': *ptr2++='r'; break;
|
||||
case '\t': *ptr2++='t'; break;
|
||||
default: sprintf(ptr2,"u%04x",token);ptr2+=5; break; /* escape and print */
|
||||
}
|
||||
}
|
||||
}
|
||||
*ptr2++='\"';*ptr2++=0;
|
||||
return out;
|
||||
}
|
||||
/* Invote print_string_ptr (which is useful) on an item. */
|
||||
static char *print_string(cJSON *item) {return print_string_ptr(item->valuestring);}
|
||||
|
||||
/* Predeclare these prototypes. */
|
||||
static const char *parse_value(cJSON *item,const char *value);
|
||||
static char *print_value(cJSON *item,int depth,int fmt);
|
||||
static const char *parse_array(cJSON *item,const char *value);
|
||||
static char *print_array(cJSON *item,int depth,int fmt);
|
||||
static const char *parse_object(cJSON *item,const char *value);
|
||||
static char *print_object(cJSON *item,int depth,int fmt);
|
||||
|
||||
/* Utility to jump whitespace and cr/lf */
|
||||
static const char *skip(const char *in) {while (in && *in && (unsigned char)*in<=32) in++; return in;}
|
||||
|
||||
/* Parse an object - create a new root, and populate. */
|
||||
cJSON *cJSON_ParseWithOpts(const char *value,const char **return_parse_end,int require_null_terminated)
|
||||
{
|
||||
const char *end=0;
|
||||
cJSON *c=cJSON_New_Item();
|
||||
ep=0;
|
||||
if (!c) return 0; /* memory fail */
|
||||
|
||||
end=parse_value(c,skip(value));
|
||||
if (!end) {cJSON_Delete(c);return 0;} /* parse failure. ep is set. */
|
||||
|
||||
/* if we require null-terminated JSON without appended garbage, skip and then check for a null terminator */
|
||||
if (require_null_terminated) {end=skip(end);if (*end) {cJSON_Delete(c);ep=end;return 0;}}
|
||||
if (return_parse_end) *return_parse_end=end;
|
||||
return c;
|
||||
}
|
||||
/* Default options for cJSON_Parse */
|
||||
cJSON *cJSON_Parse(const char *value) {return cJSON_ParseWithOpts(value,0,0);}
|
||||
|
||||
/* Render a cJSON item/entity/structure to text. */
|
||||
char *cJSON_Print(cJSON *item) {return print_value(item,0,1);}
|
||||
char *cJSON_PrintUnformatted(cJSON *item) {return print_value(item,0,0);}
|
||||
|
||||
/* Parser core - when encountering text, process appropriately. */
|
||||
static const char *parse_value(cJSON *item,const char *value)
|
||||
{
|
||||
if (!value) return 0; /* Fail on null. */
|
||||
if (!strncmp(value,"null",4)) { item->type=cJSON_NULL; return value+4; }
|
||||
if (!strncmp(value,"false",5)) { item->type=cJSON_False; return value+5; }
|
||||
if (!strncmp(value,"true",4)) { item->type=cJSON_True; item->valueint=1; return value+4; }
|
||||
if (*value=='\"') { return parse_string(item,value); }
|
||||
if (*value=='-' || (*value>='0' && *value<='9')) { return parse_number(item,value); }
|
||||
if (*value=='[') { return parse_array(item,value); }
|
||||
if (*value=='{') { return parse_object(item,value); }
|
||||
|
||||
ep=value;return 0; /* failure. */
|
||||
}
|
||||
|
||||
/* Render a value to text. */
|
||||
static char *print_value(cJSON *item,int depth,int fmt)
|
||||
{
|
||||
char *out=0;
|
||||
if (!item) return 0;
|
||||
switch ((item->type)&255)
|
||||
{
|
||||
case cJSON_NULL: out=cJSON_strdup("null"); break;
|
||||
case cJSON_False: out=cJSON_strdup("false");break;
|
||||
case cJSON_True: out=cJSON_strdup("true"); break;
|
||||
case cJSON_Number: out=print_number(item);break;
|
||||
case cJSON_String: out=print_string(item);break;
|
||||
case cJSON_Array: out=print_array(item,depth,fmt);break;
|
||||
case cJSON_Object: out=print_object(item,depth,fmt);break;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
/* Build an array from input text. */
|
||||
static const char *parse_array(cJSON *item,const char *value)
|
||||
{
|
||||
cJSON *child;
|
||||
if (*value!='[') {ep=value;return 0;} /* not an array! */
|
||||
|
||||
item->type=cJSON_Array;
|
||||
value=skip(value+1);
|
||||
if (*value==']') return value+1; /* empty array. */
|
||||
|
||||
item->child=child=cJSON_New_Item();
|
||||
if (!item->child) return 0; /* memory fail */
|
||||
value=skip(parse_value(child,skip(value))); /* skip any spacing, get the value. */
|
||||
if (!value) return 0;
|
||||
|
||||
while (*value==',')
|
||||
{
|
||||
cJSON *new_item;
|
||||
if (!(new_item=cJSON_New_Item())) return 0; /* memory fail */
|
||||
child->next=new_item;new_item->prev=child;child=new_item;
|
||||
value=skip(parse_value(child,skip(value+1)));
|
||||
if (!value) return 0; /* memory fail */
|
||||
}
|
||||
|
||||
if (*value==']') return value+1; /* end of array */
|
||||
ep=value;return 0; /* malformed. */
|
||||
}
|
||||
|
||||
/* Render an array to text */
|
||||
static char *print_array(cJSON *item,int depth,int fmt)
|
||||
{
|
||||
char **entries;
|
||||
char *out=0,*ptr,*ret;int len=5;
|
||||
cJSON *child=item->child;
|
||||
int numentries=0,i=0,fail=0;
|
||||
|
||||
/* How many entries in the array? */
|
||||
while (child) numentries++,child=child->next;
|
||||
/* Explicitly handle numentries==0 */
|
||||
if (!numentries)
|
||||
{
|
||||
out=(char*)cJSON_malloc(3);
|
||||
if (out) strcpy(out,"[]");
|
||||
return out;
|
||||
}
|
||||
/* Allocate an array to hold the values for each */
|
||||
entries=(char**)cJSON_malloc(numentries*sizeof(char*));
|
||||
if (!entries) return 0;
|
||||
memset(entries,0,numentries*sizeof(char*));
|
||||
/* Retrieve all the results: */
|
||||
child=item->child;
|
||||
while (child && !fail)
|
||||
{
|
||||
ret=print_value(child,depth+1,fmt);
|
||||
entries[i++]=ret;
|
||||
if (ret) len+=strlen(ret)+2+(fmt?1:0); else fail=1;
|
||||
child=child->next;
|
||||
}
|
||||
|
||||
/* If we didn't fail, try to malloc the output string */
|
||||
if (!fail) out=(char*)cJSON_malloc(len);
|
||||
/* If that fails, we fail. */
|
||||
if (!out) fail=1;
|
||||
|
||||
/* Handle failure. */
|
||||
if (fail)
|
||||
{
|
||||
for (i=0;i<numentries;i++) if (entries[i]) cJSON_free(entries[i]);
|
||||
cJSON_free(entries);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Compose the output array. */
|
||||
*out='[';
|
||||
ptr=out+1;*ptr=0;
|
||||
for (i=0;i<numentries;i++)
|
||||
{
|
||||
strcpy(ptr,entries[i]);ptr+=strlen(entries[i]);
|
||||
if (i!=numentries-1) {*ptr++=',';if(fmt)*ptr++=' ';*ptr=0;}
|
||||
cJSON_free(entries[i]);
|
||||
}
|
||||
cJSON_free(entries);
|
||||
*ptr++=']';*ptr++=0;
|
||||
return out;
|
||||
}
|
||||
|
||||
/* Build an object from the text. */
|
||||
static const char *parse_object(cJSON *item,const char *value)
|
||||
{
|
||||
cJSON *child;
|
||||
if (*value!='{') {ep=value;return 0;} /* not an object! */
|
||||
|
||||
item->type=cJSON_Object;
|
||||
value=skip(value+1);
|
||||
if (*value=='}') return value+1; /* empty array. */
|
||||
|
||||
item->child=child=cJSON_New_Item();
|
||||
if (!item->child) return 0;
|
||||
value=skip(parse_string(child,skip(value)));
|
||||
if (!value) return 0;
|
||||
child->string=child->valuestring;child->valuestring=0;
|
||||
if (*value!=':') {ep=value;return 0;} /* fail! */
|
||||
value=skip(parse_value(child,skip(value+1))); /* skip any spacing, get the value. */
|
||||
if (!value) return 0;
|
||||
|
||||
while (*value==',')
|
||||
{
|
||||
cJSON *new_item;
|
||||
if (!(new_item=cJSON_New_Item())) return 0; /* memory fail */
|
||||
child->next=new_item;new_item->prev=child;child=new_item;
|
||||
value=skip(parse_string(child,skip(value+1)));
|
||||
if (!value) return 0;
|
||||
child->string=child->valuestring;child->valuestring=0;
|
||||
if (*value!=':') {ep=value;return 0;} /* fail! */
|
||||
value=skip(parse_value(child,skip(value+1))); /* skip any spacing, get the value. */
|
||||
if (!value) return 0;
|
||||
}
|
||||
|
||||
if (*value=='}') return value+1; /* end of array */
|
||||
ep=value;return 0; /* malformed. */
|
||||
}
|
||||
|
||||
/* Render an object to text. */
|
||||
static char *print_object(cJSON *item,int depth,int fmt)
|
||||
{
|
||||
char **entries=0,**names=0;
|
||||
char *out=0,*ptr,*ret,*str;int len=7,i=0,j;
|
||||
cJSON *child=item->child;
|
||||
int numentries=0,fail=0;
|
||||
/* Count the number of entries. */
|
||||
while (child) numentries++,child=child->next;
|
||||
/* Explicitly handle empty object case */
|
||||
if (!numentries)
|
||||
{
|
||||
out=(char*)cJSON_malloc(fmt?depth+3:3);
|
||||
if (!out) return 0;
|
||||
ptr=out;*ptr++='{';
|
||||
if (fmt) {*ptr++='\n';for (i=0;i<depth-1;i++) *ptr++='\t';}
|
||||
*ptr++='}';*ptr++=0;
|
||||
return out;
|
||||
}
|
||||
/* Allocate space for the names and the objects */
|
||||
entries=(char**)cJSON_malloc(numentries*sizeof(char*));
|
||||
if (!entries) return 0;
|
||||
names=(char**)cJSON_malloc(numentries*sizeof(char*));
|
||||
if (!names) {cJSON_free(entries);return 0;}
|
||||
memset(entries,0,sizeof(char*)*numentries);
|
||||
memset(names,0,sizeof(char*)*numentries);
|
||||
|
||||
/* Collect all the results into our arrays: */
|
||||
child=item->child;depth++;if (fmt) len+=depth;
|
||||
while (child)
|
||||
{
|
||||
names[i]=str=print_string_ptr(child->string);
|
||||
entries[i++]=ret=print_value(child,depth,fmt);
|
||||
if (str && ret) len+=strlen(ret)+strlen(str)+2+(fmt?2+depth:0); else fail=1;
|
||||
child=child->next;
|
||||
}
|
||||
|
||||
/* Try to allocate the output string */
|
||||
if (!fail) out=(char*)cJSON_malloc(len);
|
||||
if (!out) fail=1;
|
||||
|
||||
/* Handle failure */
|
||||
if (fail)
|
||||
{
|
||||
for (i=0;i<numentries;i++) {if (names[i]) cJSON_free(names[i]);if (entries[i]) cJSON_free(entries[i]);}
|
||||
cJSON_free(names);cJSON_free(entries);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Compose the output: */
|
||||
*out='{';ptr=out+1;if (fmt)*ptr++='\n';*ptr=0;
|
||||
for (i=0;i<numentries;i++)
|
||||
{
|
||||
if (fmt) for (j=0;j<depth;j++) *ptr++='\t';
|
||||
strcpy(ptr,names[i]);ptr+=strlen(names[i]);
|
||||
*ptr++=':';if (fmt) *ptr++='\t';
|
||||
strcpy(ptr,entries[i]);ptr+=strlen(entries[i]);
|
||||
if (i!=numentries-1) *ptr++=',';
|
||||
if (fmt) *ptr++='\n';*ptr=0;
|
||||
cJSON_free(names[i]);cJSON_free(entries[i]);
|
||||
}
|
||||
|
||||
cJSON_free(names);cJSON_free(entries);
|
||||
if (fmt) for (i=0;i<depth-1;i++) *ptr++='\t';
|
||||
*ptr++='}';*ptr++=0;
|
||||
return out;
|
||||
}
|
||||
|
||||
/* Get Array size/item / object item. */
|
||||
int cJSON_GetArraySize(cJSON *array) {cJSON *c=array->child;int i=0;while(c)i++,c=c->next;return i;}
|
||||
cJSON *cJSON_GetArrayItem(cJSON *array,int item) {cJSON *c=array->child; while (c && item>0) item--,c=c->next; return c;}
|
||||
cJSON *cJSON_GetObjectItem(cJSON *object,const char *string) {cJSON *c=object->child; while (c && cJSON_strcasecmp(c->string,string)) c=c->next; return c;}
|
||||
|
||||
/* Utility for array list handling. */
|
||||
static void suffix_object(cJSON *prev,cJSON *item) {prev->next=item;item->prev=prev;}
|
||||
/* Utility for handling references. */
|
||||
static cJSON *create_reference(cJSON *item) {cJSON *ref=cJSON_New_Item();if (!ref) return 0;memcpy(ref,item,sizeof(cJSON));ref->string=0;ref->type|=cJSON_IsReference;ref->next=ref->prev=0;return ref;}
|
||||
|
||||
/* Add item to array/object. */
|
||||
void cJSON_AddItemToArray(cJSON *array, cJSON *item) {cJSON *c=array->child;if (!item) return; if (!c) {array->child=item;} else {while (c && c->next) c=c->next; suffix_object(c,item);}}
|
||||
void cJSON_AddItemToObject(cJSON *object,const char *string,cJSON *item) {if (!item) return; if (item->string) cJSON_free(item->string);item->string=cJSON_strdup(string);cJSON_AddItemToArray(object,item);}
|
||||
void cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item) {cJSON_AddItemToArray(array,create_reference(item));}
|
||||
void cJSON_AddItemReferenceToObject(cJSON *object,const char *string,cJSON *item) {cJSON_AddItemToObject(object,string,create_reference(item));}
|
||||
|
||||
cJSON *cJSON_DetachItemFromArray(cJSON *array,int which) {cJSON *c=array->child;while (c && which>0) c=c->next,which--;if (!c) return 0;
|
||||
if (c->prev) c->prev->next=c->next;if (c->next) c->next->prev=c->prev;if (c==array->child) array->child=c->next;c->prev=c->next=0;return c;}
|
||||
void cJSON_DeleteItemFromArray(cJSON *array,int which) {cJSON_Delete(cJSON_DetachItemFromArray(array,which));}
|
||||
cJSON *cJSON_DetachItemFromObject(cJSON *object,const char *string) {int i=0;cJSON *c=object->child;while (c && cJSON_strcasecmp(c->string,string)) i++,c=c->next;if (c) return cJSON_DetachItemFromArray(object,i);return 0;}
|
||||
void cJSON_DeleteItemFromObject(cJSON *object,const char *string) {cJSON_Delete(cJSON_DetachItemFromObject(object,string));}
|
||||
|
||||
/* Replace array/object items with new ones. */
|
||||
void cJSON_ReplaceItemInArray(cJSON *array,int which,cJSON *newitem) {cJSON *c=array->child;while (c && which>0) c=c->next,which--;if (!c) return;
|
||||
newitem->next=c->next;newitem->prev=c->prev;if (newitem->next) newitem->next->prev=newitem;
|
||||
if (c==array->child) array->child=newitem; else newitem->prev->next=newitem;c->next=c->prev=0;cJSON_Delete(c);}
|
||||
void cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem){int i=0;cJSON *c=object->child;while(c && cJSON_strcasecmp(c->string,string))i++,c=c->next;if(c){newitem->string=cJSON_strdup(string);cJSON_ReplaceItemInArray(object,i,newitem);}}
|
||||
|
||||
/* Create basic types: */
|
||||
cJSON *cJSON_CreateNull(void) {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_NULL;return item;}
|
||||
cJSON *cJSON_CreateTrue(void) {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_True;return item;}
|
||||
cJSON *cJSON_CreateFalse(void) {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_False;return item;}
|
||||
cJSON *cJSON_CreateBool(int b) {cJSON *item=cJSON_New_Item();if(item)item->type=b?cJSON_True:cJSON_False;return item;}
|
||||
cJSON *cJSON_CreateNumber(double num) {cJSON *item=cJSON_New_Item();if(item){item->type=cJSON_Number;item->valuedouble=num;item->valueint=(int)num;}return item;}
|
||||
cJSON *cJSON_CreateString(const char *string) {cJSON *item=cJSON_New_Item();if(item){item->type=cJSON_String;item->valuestring=cJSON_strdup(string);}return item;}
|
||||
cJSON *cJSON_CreateArray(void) {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_Array;return item;}
|
||||
cJSON *cJSON_CreateObject(void) {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_Object;return item;}
|
||||
|
||||
/* Create Arrays: */
|
||||
cJSON *cJSON_CreateIntArray(int *numbers,int count) {int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && i<count;i++){n=cJSON_CreateNumber(numbers[i]);if(!i)a->child=n;else suffix_object(p,n);p=n;}return a;}
|
||||
cJSON *cJSON_CreateFloatArray(float *numbers,int count) {int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && i<count;i++){n=cJSON_CreateNumber(numbers[i]);if(!i)a->child=n;else suffix_object(p,n);p=n;}return a;}
|
||||
cJSON *cJSON_CreateDoubleArray(double *numbers,int count) {int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && i<count;i++){n=cJSON_CreateNumber(numbers[i]);if(!i)a->child=n;else suffix_object(p,n);p=n;}return a;}
|
||||
cJSON *cJSON_CreateStringArray(const char **strings,int count) {int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && i<count;i++){n=cJSON_CreateString(strings[i]);if(!i)a->child=n;else suffix_object(p,n);p=n;}return a;}
|
||||
|
||||
/* Duplication */
|
||||
cJSON *cJSON_Duplicate(cJSON *item,int recurse)
|
||||
{
|
||||
cJSON *newitem,*cptr,*nptr=0,*newchild;
|
||||
/* Bail on bad ptr */
|
||||
if (!item) return 0;
|
||||
/* Create new item */
|
||||
newitem=cJSON_New_Item();
|
||||
if (!newitem) return 0;
|
||||
/* Copy over all vars */
|
||||
newitem->type=item->type&(~cJSON_IsReference),newitem->valueint=item->valueint,newitem->valuedouble=item->valuedouble;
|
||||
if (item->valuestring) {newitem->valuestring=cJSON_strdup(item->valuestring); if (!newitem->valuestring) {cJSON_Delete(newitem);return 0;}}
|
||||
if (item->string) {newitem->string=cJSON_strdup(item->string); if (!newitem->string) {cJSON_Delete(newitem);return 0;}}
|
||||
/* If non-recursive, then we're done! */
|
||||
if (!recurse) return newitem;
|
||||
/* Walk the ->next chain for the child. */
|
||||
cptr=item->child;
|
||||
while (cptr)
|
||||
{
|
||||
newchild=cJSON_Duplicate(cptr,1); /* Duplicate (with recurse) each item in the ->next chain */
|
||||
if (!newchild) {cJSON_Delete(newitem);return 0;}
|
||||
if (nptr) {nptr->next=newchild,newchild->prev=nptr;nptr=newchild;} /* If newitem->child already set, then crosswire ->prev and ->next and move on */
|
||||
else {newitem->child=newchild;nptr=newchild;} /* Set newitem->child and move to it */
|
||||
cptr=cptr->next;
|
||||
}
|
||||
return newitem;
|
||||
}
|
140
demos/ra_tls/grpc/v1.38.1/src/cpp/sgx/cJSON.h
Normal file
140
demos/ra_tls/grpc/v1.38.1/src/cpp/sgx/cJSON.h
Normal file
@ -0,0 +1,140 @@
|
||||
/*
|
||||
Copyright (c) 2009 Dave Gamble
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef cJSON__h
|
||||
#define cJSON__h
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
#include <stdio.h>
|
||||
/* cJSON Types: */
|
||||
#define cJSON_False 0
|
||||
#define cJSON_True 1
|
||||
#define cJSON_NULL 2
|
||||
#define cJSON_Number 3
|
||||
#define cJSON_String 4
|
||||
#define cJSON_Array 5
|
||||
#define cJSON_Object 6
|
||||
|
||||
#define cJSON_IsReference 256
|
||||
|
||||
/* The cJSON structure: */
|
||||
typedef struct cJSON {
|
||||
struct cJSON *next,*prev; /* next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem */
|
||||
struct cJSON *child; /* An array or object item will have a child pointer pointing to a chain of the items in the array/object. */
|
||||
|
||||
int type; /* The type of the item, as above. */
|
||||
|
||||
char *valuestring; /* The item's string, if type==cJSON_String */
|
||||
int valueint; /* The item's number, if type==cJSON_Number */
|
||||
double valuedouble; /* The item's number, if type==cJSON_Number */
|
||||
|
||||
char *string; /* The item's name string, if this item is the child of, or is in the list of subitems of an object. */
|
||||
} cJSON;
|
||||
|
||||
typedef struct cJSON_Hooks {
|
||||
void *(*malloc_fn)(size_t sz);
|
||||
void (*free_fn)(void *ptr);
|
||||
} cJSON_Hooks;
|
||||
|
||||
/* Supply malloc, realloc and free functions to cJSON */
|
||||
extern void cJSON_InitHooks(cJSON_Hooks* hooks);
|
||||
|
||||
|
||||
/* Supply a block of JSON, and this returns a cJSON object you can interrogate. Call cJSON_Delete when finished. */
|
||||
extern cJSON *cJSON_Parse(const char *value);
|
||||
/* Render a cJSON entity to text for transfer/storage. Free the char* when finished. */
|
||||
extern char *cJSON_Print(cJSON *item);
|
||||
/* Render a cJSON entity to text for transfer/storage without any formatting. Free the char* when finished. */
|
||||
extern char *cJSON_PrintUnformatted(cJSON *item);
|
||||
/* Delete a cJSON entity and all subentities. */
|
||||
extern void cJSON_Delete(cJSON *c);
|
||||
|
||||
/* Returns the number of items in an array (or object). */
|
||||
extern int cJSON_GetArraySize(cJSON *array);
|
||||
/* Retrieve item number "item" from array "array". Returns NULL if unsuccessful. */
|
||||
extern cJSON *cJSON_GetArrayItem(cJSON *array,int item);
|
||||
/* Get item "string" from object. Case insensitive. */
|
||||
extern cJSON *cJSON_GetObjectItem(cJSON *object,const char *string);
|
||||
|
||||
/* For analysing failed parses. This returns a pointer to the parse error. You'll probably need to look a few chars back to make sense of it. Defined when cJSON_Parse() returns 0. 0 when cJSON_Parse() succeeds. */
|
||||
extern const char *cJSON_GetErrorPtr(void);
|
||||
|
||||
/* These calls create a cJSON item of the appropriate type. */
|
||||
extern cJSON *cJSON_CreateNull(void);
|
||||
extern cJSON *cJSON_CreateTrue(void);
|
||||
extern cJSON *cJSON_CreateFalse(void);
|
||||
extern cJSON *cJSON_CreateBool(int b);
|
||||
extern cJSON *cJSON_CreateNumber(double num);
|
||||
extern cJSON *cJSON_CreateString(const char *string);
|
||||
extern cJSON *cJSON_CreateArray(void);
|
||||
extern cJSON *cJSON_CreateObject(void);
|
||||
|
||||
/* These utilities create an Array of count items. */
|
||||
extern cJSON *cJSON_CreateIntArray(int *numbers,int count);
|
||||
extern cJSON *cJSON_CreateFloatArray(float *numbers,int count);
|
||||
extern cJSON *cJSON_CreateDoubleArray(double *numbers,int count);
|
||||
extern cJSON *cJSON_CreateStringArray(const char **strings,int count);
|
||||
|
||||
/* Append item to the specified array/object. */
|
||||
extern void cJSON_AddItemToArray(cJSON *array, cJSON *item);
|
||||
extern void cJSON_AddItemToObject(cJSON *object,const char *string,cJSON *item);
|
||||
/* Append reference to item to the specified array/object. Use this when you want to add an existing cJSON to a new cJSON, but don't want to corrupt your existing cJSON. */
|
||||
extern void cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item);
|
||||
extern void cJSON_AddItemReferenceToObject(cJSON *object,const char *string,cJSON *item);
|
||||
|
||||
/* Remove/Detatch items from Arrays/Objects. */
|
||||
extern cJSON *cJSON_DetachItemFromArray(cJSON *array,int which);
|
||||
extern void cJSON_DeleteItemFromArray(cJSON *array,int which);
|
||||
extern cJSON *cJSON_DetachItemFromObject(cJSON *object,const char *string);
|
||||
extern void cJSON_DeleteItemFromObject(cJSON *object,const char *string);
|
||||
|
||||
/* Update array items. */
|
||||
extern void cJSON_ReplaceItemInArray(cJSON *array,int which,cJSON *newitem);
|
||||
extern void cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem);
|
||||
|
||||
/* Duplicate a cJSON item */
|
||||
extern cJSON *cJSON_Duplicate(cJSON *item,int recurse);
|
||||
/* Duplicate will create a new, identical cJSON item to the one you pass, in new memory that will
|
||||
need to be released. With recurse!=0, it will duplicate any children connected to the item.
|
||||
The item->next and ->prev pointers are always zero on return from Duplicate. */
|
||||
|
||||
/* ParseWithOpts allows you to require (and check) that the JSON is null terminated, and to retrieve the pointer to the final byte parsed. */
|
||||
extern cJSON *cJSON_ParseWithOpts(const char *value,const char **return_parse_end,int require_null_terminated);
|
||||
|
||||
/* Macros for creating things quickly. */
|
||||
#define cJSON_AddNullToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateNull())
|
||||
#define cJSON_AddTrueToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateTrue())
|
||||
#define cJSON_AddFalseToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateFalse())
|
||||
#define cJSON_AddBoolToObject(object,name,b) cJSON_AddItemToObject(object, name, cJSON_CreateBool(b))
|
||||
#define cJSON_AddNumberToObject(object,name,n) cJSON_AddItemToObject(object, name, cJSON_CreateNumber(n))
|
||||
#define cJSON_AddStringToObject(object,name,s) cJSON_AddItemToObject(object, name, cJSON_CreateString(s))
|
||||
|
||||
/* When assigning an integer value, it needs to be propagated to valuedouble too. */
|
||||
#define cJSON_SetIntValue(object,val) ((object)?(object)->valueint=(object)->valuedouble=(val):(val))
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
567
demos/ra_tls/grpc/v1.38.1/src/cpp/sgx/cjson/cJSON.c
Normal file
567
demos/ra_tls/grpc/v1.38.1/src/cpp/sgx/cjson/cJSON.c
Normal file
@ -0,0 +1,567 @@
|
||||
/*
|
||||
Copyright (c) 2009 Dave Gamble
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/* cJSON */
|
||||
/* JSON parser in C. */
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
#include <float.h>
|
||||
#include <limits.h>
|
||||
#include <ctype.h>
|
||||
#include "cJSON.h"
|
||||
|
||||
static const char *ep;
|
||||
|
||||
const char *cJSON_GetErrorPtr(void) {return ep;}
|
||||
|
||||
static int cJSON_strcasecmp(const char *s1,const char *s2)
|
||||
{
|
||||
if (!s1) return (s1==s2)?0:1;if (!s2) return 1;
|
||||
for(; tolower(*s1) == tolower(*s2); ++s1, ++s2) if(*s1 == 0) return 0;
|
||||
return tolower(*(const unsigned char *)s1) - tolower(*(const unsigned char *)s2);
|
||||
}
|
||||
|
||||
static void *(*cJSON_malloc)(size_t sz) = malloc;
|
||||
static void (*cJSON_free)(void *ptr) = free;
|
||||
|
||||
static char* cJSON_strdup(const char* str)
|
||||
{
|
||||
size_t len;
|
||||
char* copy;
|
||||
|
||||
len = strlen(str) + 1;
|
||||
if (!(copy = (char*)cJSON_malloc(len))) return 0;
|
||||
memcpy(copy,str,len);
|
||||
return copy;
|
||||
}
|
||||
|
||||
void cJSON_InitHooks(cJSON_Hooks* hooks)
|
||||
{
|
||||
if (!hooks) { /* Reset hooks */
|
||||
cJSON_malloc = malloc;
|
||||
cJSON_free = free;
|
||||
return;
|
||||
}
|
||||
|
||||
cJSON_malloc = (hooks->malloc_fn)?hooks->malloc_fn:malloc;
|
||||
cJSON_free = (hooks->free_fn)?hooks->free_fn:free;
|
||||
}
|
||||
|
||||
/* Internal constructor. */
|
||||
static cJSON *cJSON_New_Item(void)
|
||||
{
|
||||
cJSON* node = (cJSON*)cJSON_malloc(sizeof(cJSON));
|
||||
if (node) memset(node,0,sizeof(cJSON));
|
||||
return node;
|
||||
}
|
||||
|
||||
/* Delete a cJSON structure. */
|
||||
void cJSON_Delete(cJSON *c)
|
||||
{
|
||||
cJSON *next;
|
||||
while (c)
|
||||
{
|
||||
next=c->next;
|
||||
if (!(c->type&cJSON_IsReference) && c->child) cJSON_Delete(c->child);
|
||||
if (!(c->type&cJSON_IsReference) && c->valuestring) cJSON_free(c->valuestring);
|
||||
if (c->string) cJSON_free(c->string);
|
||||
cJSON_free(c);
|
||||
c=next;
|
||||
}
|
||||
}
|
||||
|
||||
/* Parse the input text to generate a number, and populate the result into item. */
|
||||
static const char *parse_number(cJSON *item,const char *num)
|
||||
{
|
||||
double n=0,sign=1,scale=0;int subscale=0,signsubscale=1;
|
||||
|
||||
/* Could use sscanf for this? */
|
||||
if (*num=='-') sign=-1,num++; /* Has sign? */
|
||||
if (*num=='0') num++; /* is zero */
|
||||
if (*num>='1' && *num<='9') do n=(n*10.0)+(*num++ -'0'); while (*num>='0' && *num<='9'); /* Number? */
|
||||
if (*num=='.' && num[1]>='0' && num[1]<='9') {num++; do n=(n*10.0)+(*num++ -'0'),scale--; while (*num>='0' && *num<='9');} /* Fractional part? */
|
||||
if (*num=='e' || *num=='E') /* Exponent? */
|
||||
{ num++;if (*num=='+') num++; else if (*num=='-') signsubscale=-1,num++; /* With sign? */
|
||||
while (*num>='0' && *num<='9') subscale=(subscale*10)+(*num++ - '0'); /* Number? */
|
||||
}
|
||||
|
||||
n=sign*n*pow(10.0,(scale+subscale*signsubscale)); /* number = +/- number.fraction * 10^+/- exponent */
|
||||
|
||||
item->valuedouble=n;
|
||||
item->valueint=(int)n;
|
||||
item->type=cJSON_Number;
|
||||
return num;
|
||||
}
|
||||
|
||||
/* Render the number nicely from the given item into a string. */
|
||||
static char *print_number(cJSON *item)
|
||||
{
|
||||
char *str;
|
||||
double d=item->valuedouble;
|
||||
if (fabs(((double)item->valueint)-d)<=DBL_EPSILON && d<=INT_MAX && d>=INT_MIN)
|
||||
{
|
||||
str=(char*)cJSON_malloc(21); /* 2^64+1 can be represented in 21 chars. */
|
||||
if (str) sprintf(str,"%d",item->valueint);
|
||||
}
|
||||
else
|
||||
{
|
||||
str=(char*)cJSON_malloc(64); /* This is a nice tradeoff. */
|
||||
if (str)
|
||||
{
|
||||
if (fabs(floor(d)-d)<=DBL_EPSILON && fabs(d)<1.0e60)sprintf(str,"%.0f",d);
|
||||
else if (fabs(d)<1.0e-6 || fabs(d)>1.0e9) sprintf(str,"%e",d);
|
||||
else sprintf(str,"%f",d);
|
||||
}
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
/* Parse the input text into an unescaped cstring, and populate item. */
|
||||
static const unsigned char firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
|
||||
static const char *parse_string(cJSON *item,const char *str)
|
||||
{
|
||||
const char *ptr=str+1;char *ptr2;char *out;int len=0;unsigned uc,uc2;
|
||||
if (*str!='\"') {ep=str;return 0;} /* not a string! */
|
||||
|
||||
while (*ptr!='\"' && *ptr && ++len) if (*ptr++ == '\\') ptr++; /* Skip escaped quotes. */
|
||||
|
||||
out=(char*)cJSON_malloc(len+1); /* This is how long we need for the string, roughly. */
|
||||
if (!out) return 0;
|
||||
|
||||
ptr=str+1;ptr2=out;
|
||||
while (*ptr!='\"' && *ptr)
|
||||
{
|
||||
if (*ptr!='\\') *ptr2++=*ptr++;
|
||||
else
|
||||
{
|
||||
ptr++;
|
||||
switch (*ptr)
|
||||
{
|
||||
case 'b': *ptr2++='\b'; break;
|
||||
case 'f': *ptr2++='\f'; break;
|
||||
case 'n': *ptr2++='\n'; break;
|
||||
case 'r': *ptr2++='\r'; break;
|
||||
case 't': *ptr2++='\t'; break;
|
||||
case 'u': /* transcode utf16 to utf8. */
|
||||
sscanf(ptr+1,"%4x",&uc);ptr+=4; /* get the unicode char. */
|
||||
|
||||
if ((uc>=0xDC00 && uc<=0xDFFF) || uc==0) break; /* check for invalid. */
|
||||
|
||||
if (uc>=0xD800 && uc<=0xDBFF) /* UTF16 surrogate pairs. */
|
||||
{
|
||||
if (ptr[1]!='\\' || ptr[2]!='u') break; /* missing second-half of surrogate. */
|
||||
sscanf(ptr+3,"%4x",&uc2);ptr+=6;
|
||||
if (uc2<0xDC00 || uc2>0xDFFF) break; /* invalid second-half of surrogate. */
|
||||
uc=0x10000 + (((uc&0x3FF)<<10) | (uc2&0x3FF));
|
||||
}
|
||||
|
||||
len=4;if (uc<0x80) len=1;else if (uc<0x800) len=2;else if (uc<0x10000) len=3; ptr2+=len;
|
||||
|
||||
switch (len) {
|
||||
case 4: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6;
|
||||
case 3: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6;
|
||||
case 2: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6;
|
||||
case 1: *--ptr2 =(uc | firstByteMark[len]);
|
||||
}
|
||||
ptr2+=len;
|
||||
break;
|
||||
default: *ptr2++=*ptr; break;
|
||||
}
|
||||
ptr++;
|
||||
}
|
||||
}
|
||||
*ptr2=0;
|
||||
if (*ptr=='\"') ptr++;
|
||||
item->valuestring=out;
|
||||
item->type=cJSON_String;
|
||||
return ptr;
|
||||
}
|
||||
|
||||
/* Render the cstring provided to an escaped version that can be printed. */
|
||||
static char *print_string_ptr(const char *str)
|
||||
{
|
||||
const char *ptr;char *ptr2,*out;int len=0;unsigned char token;
|
||||
|
||||
if (!str) return cJSON_strdup("");
|
||||
ptr=str;while ((token=*ptr) && ++len) {if (strchr("\"\\\b\f\n\r\t",token)) len++; else if (token<32) len+=5;ptr++;}
|
||||
|
||||
out=(char*)cJSON_malloc(len+3);
|
||||
if (!out) return 0;
|
||||
|
||||
ptr2=out;ptr=str;
|
||||
*ptr2++='\"';
|
||||
while (*ptr)
|
||||
{
|
||||
if ((unsigned char)*ptr>31 && *ptr!='\"' && *ptr!='\\') *ptr2++=*ptr++;
|
||||
else
|
||||
{
|
||||
*ptr2++='\\';
|
||||
switch (token=*ptr++)
|
||||
{
|
||||
case '\\': *ptr2++='\\'; break;
|
||||
case '\"': *ptr2++='\"'; break;
|
||||
case '\b': *ptr2++='b'; break;
|
||||
case '\f': *ptr2++='f'; break;
|
||||
case '\n': *ptr2++='n'; break;
|
||||
case '\r': *ptr2++='r'; break;
|
||||
case '\t': *ptr2++='t'; break;
|
||||
default: sprintf(ptr2,"u%04x",token);ptr2+=5; break; /* escape and print */
|
||||
}
|
||||
}
|
||||
}
|
||||
*ptr2++='\"';*ptr2++=0;
|
||||
return out;
|
||||
}
|
||||
/* Invote print_string_ptr (which is useful) on an item. */
|
||||
static char *print_string(cJSON *item) {return print_string_ptr(item->valuestring);}
|
||||
|
||||
/* Predeclare these prototypes. */
|
||||
static const char *parse_value(cJSON *item,const char *value);
|
||||
static char *print_value(cJSON *item,int depth,int fmt);
|
||||
static const char *parse_array(cJSON *item,const char *value);
|
||||
static char *print_array(cJSON *item,int depth,int fmt);
|
||||
static const char *parse_object(cJSON *item,const char *value);
|
||||
static char *print_object(cJSON *item,int depth,int fmt);
|
||||
|
||||
/* Utility to jump whitespace and cr/lf */
|
||||
static const char *skip(const char *in) {while (in && *in && (unsigned char)*in<=32) in++; return in;}
|
||||
|
||||
/* Parse an object - create a new root, and populate. */
|
||||
cJSON *cJSON_ParseWithOpts(const char *value,const char **return_parse_end,int require_null_terminated)
|
||||
{
|
||||
const char *end=0;
|
||||
cJSON *c=cJSON_New_Item();
|
||||
ep=0;
|
||||
if (!c) return 0; /* memory fail */
|
||||
|
||||
end=parse_value(c,skip(value));
|
||||
if (!end) {cJSON_Delete(c);return 0;} /* parse failure. ep is set. */
|
||||
|
||||
/* if we require null-terminated JSON without appended garbage, skip and then check for a null terminator */
|
||||
if (require_null_terminated) {end=skip(end);if (*end) {cJSON_Delete(c);ep=end;return 0;}}
|
||||
if (return_parse_end) *return_parse_end=end;
|
||||
return c;
|
||||
}
|
||||
/* Default options for cJSON_Parse */
|
||||
cJSON *cJSON_Parse(const char *value) {return cJSON_ParseWithOpts(value,0,0);}
|
||||
|
||||
/* Render a cJSON item/entity/structure to text. */
|
||||
char *cJSON_Print(cJSON *item) {return print_value(item,0,1);}
|
||||
char *cJSON_PrintUnformatted(cJSON *item) {return print_value(item,0,0);}
|
||||
|
||||
/* Parser core - when encountering text, process appropriately. */
|
||||
static const char *parse_value(cJSON *item,const char *value)
|
||||
{
|
||||
if (!value) return 0; /* Fail on null. */
|
||||
if (!strncmp(value,"null",4)) { item->type=cJSON_NULL; return value+4; }
|
||||
if (!strncmp(value,"false",5)) { item->type=cJSON_False; return value+5; }
|
||||
if (!strncmp(value,"true",4)) { item->type=cJSON_True; item->valueint=1; return value+4; }
|
||||
if (*value=='\"') { return parse_string(item,value); }
|
||||
if (*value=='-' || (*value>='0' && *value<='9')) { return parse_number(item,value); }
|
||||
if (*value=='[') { return parse_array(item,value); }
|
||||
if (*value=='{') { return parse_object(item,value); }
|
||||
|
||||
ep=value;return 0; /* failure. */
|
||||
}
|
||||
|
||||
/* Render a value to text. */
|
||||
static char *print_value(cJSON *item,int depth,int fmt)
|
||||
{
|
||||
char *out=0;
|
||||
if (!item) return 0;
|
||||
switch ((item->type)&255)
|
||||
{
|
||||
case cJSON_NULL: out=cJSON_strdup("null"); break;
|
||||
case cJSON_False: out=cJSON_strdup("false");break;
|
||||
case cJSON_True: out=cJSON_strdup("true"); break;
|
||||
case cJSON_Number: out=print_number(item);break;
|
||||
case cJSON_String: out=print_string(item);break;
|
||||
case cJSON_Array: out=print_array(item,depth,fmt);break;
|
||||
case cJSON_Object: out=print_object(item,depth,fmt);break;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
/* Build an array from input text. */
|
||||
static const char *parse_array(cJSON *item,const char *value)
|
||||
{
|
||||
cJSON *child;
|
||||
if (*value!='[') {ep=value;return 0;} /* not an array! */
|
||||
|
||||
item->type=cJSON_Array;
|
||||
value=skip(value+1);
|
||||
if (*value==']') return value+1; /* empty array. */
|
||||
|
||||
item->child=child=cJSON_New_Item();
|
||||
if (!item->child) return 0; /* memory fail */
|
||||
value=skip(parse_value(child,skip(value))); /* skip any spacing, get the value. */
|
||||
if (!value) return 0;
|
||||
|
||||
while (*value==',')
|
||||
{
|
||||
cJSON *new_item;
|
||||
if (!(new_item=cJSON_New_Item())) return 0; /* memory fail */
|
||||
child->next=new_item;new_item->prev=child;child=new_item;
|
||||
value=skip(parse_value(child,skip(value+1)));
|
||||
if (!value) return 0; /* memory fail */
|
||||
}
|
||||
|
||||
if (*value==']') return value+1; /* end of array */
|
||||
ep=value;return 0; /* malformed. */
|
||||
}
|
||||
|
||||
/* Render an array to text */
|
||||
static char *print_array(cJSON *item,int depth,int fmt)
|
||||
{
|
||||
char **entries;
|
||||
char *out=0,*ptr,*ret;int len=5;
|
||||
cJSON *child=item->child;
|
||||
int numentries=0,i=0,fail=0;
|
||||
|
||||
/* How many entries in the array? */
|
||||
while (child) numentries++,child=child->next;
|
||||
/* Explicitly handle numentries==0 */
|
||||
if (!numentries)
|
||||
{
|
||||
out=(char*)cJSON_malloc(3);
|
||||
if (out) strcpy(out,"[]");
|
||||
return out;
|
||||
}
|
||||
/* Allocate an array to hold the values for each */
|
||||
entries=(char**)cJSON_malloc(numentries*sizeof(char*));
|
||||
if (!entries) return 0;
|
||||
memset(entries,0,numentries*sizeof(char*));
|
||||
/* Retrieve all the results: */
|
||||
child=item->child;
|
||||
while (child && !fail)
|
||||
{
|
||||
ret=print_value(child,depth+1,fmt);
|
||||
entries[i++]=ret;
|
||||
if (ret) len+=strlen(ret)+2+(fmt?1:0); else fail=1;
|
||||
child=child->next;
|
||||
}
|
||||
|
||||
/* If we didn't fail, try to malloc the output string */
|
||||
if (!fail) out=(char*)cJSON_malloc(len);
|
||||
/* If that fails, we fail. */
|
||||
if (!out) fail=1;
|
||||
|
||||
/* Handle failure. */
|
||||
if (fail)
|
||||
{
|
||||
for (i=0;i<numentries;i++) if (entries[i]) cJSON_free(entries[i]);
|
||||
cJSON_free(entries);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Compose the output array. */
|
||||
*out='[';
|
||||
ptr=out+1;*ptr=0;
|
||||
for (i=0;i<numentries;i++)
|
||||
{
|
||||
strcpy(ptr,entries[i]);ptr+=strlen(entries[i]);
|
||||
if (i!=numentries-1) {*ptr++=',';if(fmt)*ptr++=' ';*ptr=0;}
|
||||
cJSON_free(entries[i]);
|
||||
}
|
||||
cJSON_free(entries);
|
||||
*ptr++=']';*ptr++=0;
|
||||
return out;
|
||||
}
|
||||
|
||||
/* Build an object from the text. */
|
||||
static const char *parse_object(cJSON *item,const char *value)
|
||||
{
|
||||
cJSON *child;
|
||||
if (*value!='{') {ep=value;return 0;} /* not an object! */
|
||||
|
||||
item->type=cJSON_Object;
|
||||
value=skip(value+1);
|
||||
if (*value=='}') return value+1; /* empty array. */
|
||||
|
||||
item->child=child=cJSON_New_Item();
|
||||
if (!item->child) return 0;
|
||||
value=skip(parse_string(child,skip(value)));
|
||||
if (!value) return 0;
|
||||
child->string=child->valuestring;child->valuestring=0;
|
||||
if (*value!=':') {ep=value;return 0;} /* fail! */
|
||||
value=skip(parse_value(child,skip(value+1))); /* skip any spacing, get the value. */
|
||||
if (!value) return 0;
|
||||
|
||||
while (*value==',')
|
||||
{
|
||||
cJSON *new_item;
|
||||
if (!(new_item=cJSON_New_Item())) return 0; /* memory fail */
|
||||
child->next=new_item;new_item->prev=child;child=new_item;
|
||||
value=skip(parse_string(child,skip(value+1)));
|
||||
if (!value) return 0;
|
||||
child->string=child->valuestring;child->valuestring=0;
|
||||
if (*value!=':') {ep=value;return 0;} /* fail! */
|
||||
value=skip(parse_value(child,skip(value+1))); /* skip any spacing, get the value. */
|
||||
if (!value) return 0;
|
||||
}
|
||||
|
||||
if (*value=='}') return value+1; /* end of array */
|
||||
ep=value;return 0; /* malformed. */
|
||||
}
|
||||
|
||||
/* Render an object to text. */
|
||||
static char *print_object(cJSON *item,int depth,int fmt)
|
||||
{
|
||||
char **entries=0,**names=0;
|
||||
char *out=0,*ptr,*ret,*str;int len=7,i=0,j;
|
||||
cJSON *child=item->child;
|
||||
int numentries=0,fail=0;
|
||||
/* Count the number of entries. */
|
||||
while (child) numentries++,child=child->next;
|
||||
/* Explicitly handle empty object case */
|
||||
if (!numentries)
|
||||
{
|
||||
out=(char*)cJSON_malloc(fmt?depth+3:3);
|
||||
if (!out) return 0;
|
||||
ptr=out;*ptr++='{';
|
||||
if (fmt) {*ptr++='\n';for (i=0;i<depth-1;i++) *ptr++='\t';}
|
||||
*ptr++='}';*ptr++=0;
|
||||
return out;
|
||||
}
|
||||
/* Allocate space for the names and the objects */
|
||||
entries=(char**)cJSON_malloc(numentries*sizeof(char*));
|
||||
if (!entries) return 0;
|
||||
names=(char**)cJSON_malloc(numentries*sizeof(char*));
|
||||
if (!names) {cJSON_free(entries);return 0;}
|
||||
memset(entries,0,sizeof(char*)*numentries);
|
||||
memset(names,0,sizeof(char*)*numentries);
|
||||
|
||||
/* Collect all the results into our arrays: */
|
||||
child=item->child;depth++;if (fmt) len+=depth;
|
||||
while (child)
|
||||
{
|
||||
names[i]=str=print_string_ptr(child->string);
|
||||
entries[i++]=ret=print_value(child,depth,fmt);
|
||||
if (str && ret) len+=strlen(ret)+strlen(str)+2+(fmt?2+depth:0); else fail=1;
|
||||
child=child->next;
|
||||
}
|
||||
|
||||
/* Try to allocate the output string */
|
||||
if (!fail) out=(char*)cJSON_malloc(len);
|
||||
if (!out) fail=1;
|
||||
|
||||
/* Handle failure */
|
||||
if (fail)
|
||||
{
|
||||
for (i=0;i<numentries;i++) {if (names[i]) cJSON_free(names[i]);if (entries[i]) cJSON_free(entries[i]);}
|
||||
cJSON_free(names);cJSON_free(entries);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Compose the output: */
|
||||
*out='{';ptr=out+1;if (fmt)*ptr++='\n';*ptr=0;
|
||||
for (i=0;i<numentries;i++)
|
||||
{
|
||||
if (fmt) for (j=0;j<depth;j++) *ptr++='\t';
|
||||
strcpy(ptr,names[i]);ptr+=strlen(names[i]);
|
||||
*ptr++=':';if (fmt) *ptr++='\t';
|
||||
strcpy(ptr,entries[i]);ptr+=strlen(entries[i]);
|
||||
if (i!=numentries-1) *ptr++=',';
|
||||
if (fmt) *ptr++='\n';*ptr=0;
|
||||
cJSON_free(names[i]);cJSON_free(entries[i]);
|
||||
}
|
||||
|
||||
cJSON_free(names);cJSON_free(entries);
|
||||
if (fmt) for (i=0;i<depth-1;i++) *ptr++='\t';
|
||||
*ptr++='}';*ptr++=0;
|
||||
return out;
|
||||
}
|
||||
|
||||
/* Get Array size/item / object item. */
|
||||
int cJSON_GetArraySize(cJSON *array) {cJSON *c=array->child;int i=0;while(c)i++,c=c->next;return i;}
|
||||
cJSON *cJSON_GetArrayItem(cJSON *array,int item) {cJSON *c=array->child; while (c && item>0) item--,c=c->next; return c;}
|
||||
cJSON *cJSON_GetObjectItem(cJSON *object,const char *string) {cJSON *c=object->child; while (c && cJSON_strcasecmp(c->string,string)) c=c->next; return c;}
|
||||
|
||||
/* Utility for array list handling. */
|
||||
static void suffix_object(cJSON *prev,cJSON *item) {prev->next=item;item->prev=prev;}
|
||||
/* Utility for handling references. */
|
||||
static cJSON *create_reference(cJSON *item) {cJSON *ref=cJSON_New_Item();if (!ref) return 0;memcpy(ref,item,sizeof(cJSON));ref->string=0;ref->type|=cJSON_IsReference;ref->next=ref->prev=0;return ref;}
|
||||
|
||||
/* Add item to array/object. */
|
||||
void cJSON_AddItemToArray(cJSON *array, cJSON *item) {cJSON *c=array->child;if (!item) return; if (!c) {array->child=item;} else {while (c && c->next) c=c->next; suffix_object(c,item);}}
|
||||
void cJSON_AddItemToObject(cJSON *object,const char *string,cJSON *item) {if (!item) return; if (item->string) cJSON_free(item->string);item->string=cJSON_strdup(string);cJSON_AddItemToArray(object,item);}
|
||||
void cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item) {cJSON_AddItemToArray(array,create_reference(item));}
|
||||
void cJSON_AddItemReferenceToObject(cJSON *object,const char *string,cJSON *item) {cJSON_AddItemToObject(object,string,create_reference(item));}
|
||||
|
||||
cJSON *cJSON_DetachItemFromArray(cJSON *array,int which) {cJSON *c=array->child;while (c && which>0) c=c->next,which--;if (!c) return 0;
|
||||
if (c->prev) c->prev->next=c->next;if (c->next) c->next->prev=c->prev;if (c==array->child) array->child=c->next;c->prev=c->next=0;return c;}
|
||||
void cJSON_DeleteItemFromArray(cJSON *array,int which) {cJSON_Delete(cJSON_DetachItemFromArray(array,which));}
|
||||
cJSON *cJSON_DetachItemFromObject(cJSON *object,const char *string) {int i=0;cJSON *c=object->child;while (c && cJSON_strcasecmp(c->string,string)) i++,c=c->next;if (c) return cJSON_DetachItemFromArray(object,i);return 0;}
|
||||
void cJSON_DeleteItemFromObject(cJSON *object,const char *string) {cJSON_Delete(cJSON_DetachItemFromObject(object,string));}
|
||||
|
||||
/* Replace array/object items with new ones. */
|
||||
void cJSON_ReplaceItemInArray(cJSON *array,int which,cJSON *newitem) {cJSON *c=array->child;while (c && which>0) c=c->next,which--;if (!c) return;
|
||||
newitem->next=c->next;newitem->prev=c->prev;if (newitem->next) newitem->next->prev=newitem;
|
||||
if (c==array->child) array->child=newitem; else newitem->prev->next=newitem;c->next=c->prev=0;cJSON_Delete(c);}
|
||||
void cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem){int i=0;cJSON *c=object->child;while(c && cJSON_strcasecmp(c->string,string))i++,c=c->next;if(c){newitem->string=cJSON_strdup(string);cJSON_ReplaceItemInArray(object,i,newitem);}}
|
||||
|
||||
/* Create basic types: */
|
||||
cJSON *cJSON_CreateNull(void) {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_NULL;return item;}
|
||||
cJSON *cJSON_CreateTrue(void) {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_True;return item;}
|
||||
cJSON *cJSON_CreateFalse(void) {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_False;return item;}
|
||||
cJSON *cJSON_CreateBool(int b) {cJSON *item=cJSON_New_Item();if(item)item->type=b?cJSON_True:cJSON_False;return item;}
|
||||
cJSON *cJSON_CreateNumber(double num) {cJSON *item=cJSON_New_Item();if(item){item->type=cJSON_Number;item->valuedouble=num;item->valueint=(int)num;}return item;}
|
||||
cJSON *cJSON_CreateString(const char *string) {cJSON *item=cJSON_New_Item();if(item){item->type=cJSON_String;item->valuestring=cJSON_strdup(string);}return item;}
|
||||
cJSON *cJSON_CreateArray(void) {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_Array;return item;}
|
||||
cJSON *cJSON_CreateObject(void) {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_Object;return item;}
|
||||
|
||||
/* Create Arrays: */
|
||||
cJSON *cJSON_CreateIntArray(int *numbers,int count) {int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && i<count;i++){n=cJSON_CreateNumber(numbers[i]);if(!i)a->child=n;else suffix_object(p,n);p=n;}return a;}
|
||||
cJSON *cJSON_CreateFloatArray(float *numbers,int count) {int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && i<count;i++){n=cJSON_CreateNumber(numbers[i]);if(!i)a->child=n;else suffix_object(p,n);p=n;}return a;}
|
||||
cJSON *cJSON_CreateDoubleArray(double *numbers,int count) {int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && i<count;i++){n=cJSON_CreateNumber(numbers[i]);if(!i)a->child=n;else suffix_object(p,n);p=n;}return a;}
|
||||
cJSON *cJSON_CreateStringArray(const char **strings,int count) {int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && i<count;i++){n=cJSON_CreateString(strings[i]);if(!i)a->child=n;else suffix_object(p,n);p=n;}return a;}
|
||||
|
||||
/* Duplication */
|
||||
cJSON *cJSON_Duplicate(cJSON *item,int recurse)
|
||||
{
|
||||
cJSON *newitem,*cptr,*nptr=0,*newchild;
|
||||
/* Bail on bad ptr */
|
||||
if (!item) return 0;
|
||||
/* Create new item */
|
||||
newitem=cJSON_New_Item();
|
||||
if (!newitem) return 0;
|
||||
/* Copy over all vars */
|
||||
newitem->type=item->type&(~cJSON_IsReference),newitem->valueint=item->valueint,newitem->valuedouble=item->valuedouble;
|
||||
if (item->valuestring) {newitem->valuestring=cJSON_strdup(item->valuestring); if (!newitem->valuestring) {cJSON_Delete(newitem);return 0;}}
|
||||
if (item->string) {newitem->string=cJSON_strdup(item->string); if (!newitem->string) {cJSON_Delete(newitem);return 0;}}
|
||||
/* If non-recursive, then we're done! */
|
||||
if (!recurse) return newitem;
|
||||
/* Walk the ->next chain for the child. */
|
||||
cptr=item->child;
|
||||
while (cptr)
|
||||
{
|
||||
newchild=cJSON_Duplicate(cptr,1); /* Duplicate (with recurse) each item in the ->next chain */
|
||||
if (!newchild) {cJSON_Delete(newitem);return 0;}
|
||||
if (nptr) {nptr->next=newchild,newchild->prev=nptr;nptr=newchild;} /* If newitem->child already set, then crosswire ->prev and ->next and move on */
|
||||
else {newitem->child=newchild;nptr=newchild;} /* Set newitem->child and move to it */
|
||||
cptr=cptr->next;
|
||||
}
|
||||
return newitem;
|
||||
}
|
140
demos/ra_tls/grpc/v1.38.1/src/cpp/sgx/cjson/cJSON.h
Normal file
140
demos/ra_tls/grpc/v1.38.1/src/cpp/sgx/cjson/cJSON.h
Normal file
@ -0,0 +1,140 @@
|
||||
/*
|
||||
Copyright (c) 2009 Dave Gamble
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef cJSON__h
|
||||
#define cJSON__h
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
#include <stdio.h>
|
||||
/* cJSON Types: */
|
||||
#define cJSON_False 0
|
||||
#define cJSON_True 1
|
||||
#define cJSON_NULL 2
|
||||
#define cJSON_Number 3
|
||||
#define cJSON_String 4
|
||||
#define cJSON_Array 5
|
||||
#define cJSON_Object 6
|
||||
|
||||
#define cJSON_IsReference 256
|
||||
|
||||
/* The cJSON structure: */
|
||||
typedef struct cJSON {
|
||||
struct cJSON *next,*prev; /* next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem */
|
||||
struct cJSON *child; /* An array or object item will have a child pointer pointing to a chain of the items in the array/object. */
|
||||
|
||||
int type; /* The type of the item, as above. */
|
||||
|
||||
char *valuestring; /* The item's string, if type==cJSON_String */
|
||||
int valueint; /* The item's number, if type==cJSON_Number */
|
||||
double valuedouble; /* The item's number, if type==cJSON_Number */
|
||||
|
||||
char *string; /* The item's name string, if this item is the child of, or is in the list of subitems of an object. */
|
||||
} cJSON;
|
||||
|
||||
typedef struct cJSON_Hooks {
|
||||
void *(*malloc_fn)(size_t sz);
|
||||
void (*free_fn)(void *ptr);
|
||||
} cJSON_Hooks;
|
||||
|
||||
/* Supply malloc, realloc and free functions to cJSON */
|
||||
extern void cJSON_InitHooks(cJSON_Hooks* hooks);
|
||||
|
||||
|
||||
/* Supply a block of JSON, and this returns a cJSON object you can interrogate. Call cJSON_Delete when finished. */
|
||||
extern cJSON *cJSON_Parse(const char *value);
|
||||
/* Render a cJSON entity to text for transfer/storage. Free the char* when finished. */
|
||||
extern char *cJSON_Print(cJSON *item);
|
||||
/* Render a cJSON entity to text for transfer/storage without any formatting. Free the char* when finished. */
|
||||
extern char *cJSON_PrintUnformatted(cJSON *item);
|
||||
/* Delete a cJSON entity and all subentities. */
|
||||
extern void cJSON_Delete(cJSON *c);
|
||||
|
||||
/* Returns the number of items in an array (or object). */
|
||||
extern int cJSON_GetArraySize(cJSON *array);
|
||||
/* Retrieve item number "item" from array "array". Returns NULL if unsuccessful. */
|
||||
extern cJSON *cJSON_GetArrayItem(cJSON *array,int item);
|
||||
/* Get item "string" from object. Case insensitive. */
|
||||
extern cJSON *cJSON_GetObjectItem(cJSON *object,const char *string);
|
||||
|
||||
/* For analysing failed parses. This returns a pointer to the parse error. You'll probably need to look a few chars back to make sense of it. Defined when cJSON_Parse() returns 0. 0 when cJSON_Parse() succeeds. */
|
||||
extern const char *cJSON_GetErrorPtr(void);
|
||||
|
||||
/* These calls create a cJSON item of the appropriate type. */
|
||||
extern cJSON *cJSON_CreateNull(void);
|
||||
extern cJSON *cJSON_CreateTrue(void);
|
||||
extern cJSON *cJSON_CreateFalse(void);
|
||||
extern cJSON *cJSON_CreateBool(int b);
|
||||
extern cJSON *cJSON_CreateNumber(double num);
|
||||
extern cJSON *cJSON_CreateString(const char *string);
|
||||
extern cJSON *cJSON_CreateArray(void);
|
||||
extern cJSON *cJSON_CreateObject(void);
|
||||
|
||||
/* These utilities create an Array of count items. */
|
||||
extern cJSON *cJSON_CreateIntArray(int *numbers,int count);
|
||||
extern cJSON *cJSON_CreateFloatArray(float *numbers,int count);
|
||||
extern cJSON *cJSON_CreateDoubleArray(double *numbers,int count);
|
||||
extern cJSON *cJSON_CreateStringArray(const char **strings,int count);
|
||||
|
||||
/* Append item to the specified array/object. */
|
||||
extern void cJSON_AddItemToArray(cJSON *array, cJSON *item);
|
||||
extern void cJSON_AddItemToObject(cJSON *object,const char *string,cJSON *item);
|
||||
/* Append reference to item to the specified array/object. Use this when you want to add an existing cJSON to a new cJSON, but don't want to corrupt your existing cJSON. */
|
||||
extern void cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item);
|
||||
extern void cJSON_AddItemReferenceToObject(cJSON *object,const char *string,cJSON *item);
|
||||
|
||||
/* Remove/Detatch items from Arrays/Objects. */
|
||||
extern cJSON *cJSON_DetachItemFromArray(cJSON *array,int which);
|
||||
extern void cJSON_DeleteItemFromArray(cJSON *array,int which);
|
||||
extern cJSON *cJSON_DetachItemFromObject(cJSON *object,const char *string);
|
||||
extern void cJSON_DeleteItemFromObject(cJSON *object,const char *string);
|
||||
|
||||
/* Update array items. */
|
||||
extern void cJSON_ReplaceItemInArray(cJSON *array,int which,cJSON *newitem);
|
||||
extern void cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem);
|
||||
|
||||
/* Duplicate a cJSON item */
|
||||
extern cJSON *cJSON_Duplicate(cJSON *item,int recurse);
|
||||
/* Duplicate will create a new, identical cJSON item to the one you pass, in new memory that will
|
||||
need to be released. With recurse!=0, it will duplicate any children connected to the item.
|
||||
The item->next and ->prev pointers are always zero on return from Duplicate. */
|
||||
|
||||
/* ParseWithOpts allows you to require (and check) that the JSON is null terminated, and to retrieve the pointer to the final byte parsed. */
|
||||
extern cJSON *cJSON_ParseWithOpts(const char *value,const char **return_parse_end,int require_null_terminated);
|
||||
|
||||
/* Macros for creating things quickly. */
|
||||
#define cJSON_AddNullToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateNull())
|
||||
#define cJSON_AddTrueToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateTrue())
|
||||
#define cJSON_AddFalseToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateFalse())
|
||||
#define cJSON_AddBoolToObject(object,name,b) cJSON_AddItemToObject(object, name, cJSON_CreateBool(b))
|
||||
#define cJSON_AddNumberToObject(object,name,n) cJSON_AddItemToObject(object, name, cJSON_CreateNumber(n))
|
||||
#define cJSON_AddStringToObject(object,name,s) cJSON_AddItemToObject(object, name, cJSON_CreateString(s))
|
||||
|
||||
/* When assigning an integer value, it needs to be propagated to valuedouble too. */
|
||||
#define cJSON_SetIntValue(object,val) ((object)?(object)->valueint=(object)->valuedouble=(val):(val))
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
68
demos/ra_tls/grpc/v1.38.1/src/cpp/sgx/sgx_ra_tls_backend.cc
Normal file
68
demos/ra_tls/grpc/v1.38.1/src/cpp/sgx/sgx_ra_tls_backend.cc
Normal file
@ -0,0 +1,68 @@
|
||||
#include "sgx_ra_tls_utils.h"
|
||||
#include "sgx_ra_tls_backend.h"
|
||||
#include "sgx_quote_3.h"
|
||||
#include "dcap_quote.h"
|
||||
|
||||
namespace grpc {
|
||||
namespace sgx {
|
||||
int verify_quote (uint8_t * quote_buffer, size_t quote_size) {
|
||||
void *handle;
|
||||
handle = dcap_quote_open();
|
||||
uint32_t supplemental_size, ret;
|
||||
uint8_t *p_supplemental_buffer;
|
||||
sgx_ql_qv_result_t quote_verification_result = SGX_QL_QV_RESULT_UNSPECIFIED;
|
||||
uint32_t collateral_expiration_status = 1;
|
||||
supplemental_size = dcap_get_supplemental_data_size(handle);
|
||||
p_supplemental_buffer = (uint8_t *)malloc(supplemental_size);
|
||||
if (NULL == p_supplemental_buffer) {
|
||||
printf("Couldn't allocate supplemental buffer\n");
|
||||
}
|
||||
memset(p_supplemental_buffer, 0, supplemental_size);
|
||||
ret = dcap_verify_quote(
|
||||
handle,
|
||||
quote_buffer,
|
||||
quote_size,
|
||||
&collateral_expiration_status,
|
||||
"e_verification_result,
|
||||
supplemental_size,
|
||||
p_supplemental_buffer
|
||||
);
|
||||
|
||||
if (0 != ret) {
|
||||
printf( "Error in dcap_verify_quote.\n");
|
||||
}
|
||||
|
||||
if (collateral_expiration_status != 0) {
|
||||
printf("the verification collateral has expired\n");
|
||||
}
|
||||
dcap_quote_close(handle);
|
||||
}
|
||||
|
||||
int generate_quote(uint8_t *quote_buffer, unsigned char *hash, size_t hash_len) {
|
||||
void *handle;
|
||||
|
||||
handle = dcap_quote_open();
|
||||
|
||||
|
||||
sgx_report_data_t report_data = { 0 };
|
||||
memcpy(report_data.d, hash, hash_len);
|
||||
|
||||
// Get the Quote
|
||||
int ret = dcap_generate_quote(handle, quote_buffer, &report_data);
|
||||
if (0 != ret) {
|
||||
printf( "Error in dcap_generate_quote.\n");
|
||||
}
|
||||
|
||||
dcap_quote_close(handle);
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint32_t get_quote_size() {
|
||||
void *handle = dcap_quote_open();
|
||||
uint32_t quote_size = dcap_get_quote_size(handle);
|
||||
dcap_quote_close(handle);
|
||||
return quote_size;
|
||||
}
|
||||
|
||||
}//namespace grpc
|
||||
}//namesapce sgx
|
41
demos/ra_tls/grpc/v1.38.1/src/cpp/sgx/sgx_ra_tls_backend.h
Normal file
41
demos/ra_tls/grpc/v1.38.1/src/cpp/sgx/sgx_ra_tls_backend.h
Normal file
@ -0,0 +1,41 @@
|
||||
/*
|
||||
*
|
||||
* Copyright 2019 gRPC authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SGX_RA_TLS_BACKEND_H
|
||||
#define SGX_RA_TLS_BACKEND_H
|
||||
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <sstream>
|
||||
|
||||
|
||||
|
||||
namespace grpc {
|
||||
namespace sgx {
|
||||
|
||||
int verify_quote (uint8_t * quote_buffer, size_t quote_size);
|
||||
|
||||
|
||||
int generate_quote(uint8_t *quote_buffer, unsigned char *hash, size_t hash_len);
|
||||
|
||||
|
||||
uint32_t get_quote_size();
|
||||
|
||||
}
|
||||
}
|
||||
#endif // SGX_RA_TLS_BACKEND_H
|
233
demos/ra_tls/grpc/v1.38.1/src/cpp/sgx/sgx_ra_tls_backends.cc
Normal file
233
demos/ra_tls/grpc/v1.38.1/src/cpp/sgx/sgx_ra_tls_backends.cc
Normal file
@ -0,0 +1,233 @@
|
||||
/*
|
||||
*
|
||||
* Copyright (c) 2022 Intel Corporation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "sgx_ra_tls_backends.h"
|
||||
|
||||
namespace grpc {
|
||||
namespace sgx {
|
||||
|
||||
struct ra_tls_context _ctx_;
|
||||
|
||||
std::vector<std::string> ra_tls_get_key_cert() {
|
||||
#ifdef SGX_RA_TLS_OCCLUM_BACKEND
|
||||
return occlum_get_key_cert();
|
||||
#endif
|
||||
}
|
||||
|
||||
static std::vector<grpc::experimental::IdentityKeyCertPair> get_identity_key_cert_pairs(
|
||||
std::vector<std::string> key_cert) {
|
||||
grpc::experimental::IdentityKeyCertPair key_cert_pair;
|
||||
key_cert_pair.private_key = key_cert[0];
|
||||
key_cert_pair.certificate_chain = key_cert[1];
|
||||
std::vector<grpc::experimental::IdentityKeyCertPair> identity_key_cert_pairs;
|
||||
identity_key_cert_pairs.emplace_back(key_cert_pair);
|
||||
return identity_key_cert_pairs;
|
||||
}
|
||||
|
||||
void credential_option_set_certificate_provider(grpc::sgx::CredentialsOptions& options) {
|
||||
std::lock_guard<std::mutex> lock(_ctx_.mtx);
|
||||
|
||||
_ctx_.cache.id++;
|
||||
|
||||
auto certificate_provider = _ctx_.cache.certificate_provider.insert({
|
||||
_ctx_.cache.id,
|
||||
std::make_shared<grpc::experimental::StaticDataCertificateProvider>(
|
||||
get_identity_key_cert_pairs(ra_tls_get_key_cert()))
|
||||
}).first;
|
||||
|
||||
options.set_certificate_provider(certificate_provider->second);
|
||||
options.watch_identity_key_cert_pairs();
|
||||
options.set_cert_request_type(GRPC_SSL_REQUEST_AND_REQUIRE_CLIENT_CERTIFICATE_BUT_DONT_VERIFY);
|
||||
options.set_root_cert_name("");
|
||||
options.set_identity_cert_name("");
|
||||
}
|
||||
|
||||
static sgx_config parse_sgx_config_json(const char* file) {
|
||||
class json_engine sgx_json(file);
|
||||
struct sgx_config sgx_cfg;
|
||||
|
||||
sgx_cfg.verify_mr_enclave = sgx_json.compare_item(sgx_json.get_item(sgx_json.get_handle(), "verify_mr_enclave"), "on");
|
||||
sgx_cfg.verify_mr_signer = sgx_json.compare_item(sgx_json.get_item(sgx_json.get_handle(), "verify_mr_signer"), "on");
|
||||
sgx_cfg.verify_isv_prod_id = sgx_json.compare_item(sgx_json.get_item(sgx_json.get_handle(), "verify_isv_prod_id"), "on");
|
||||
sgx_cfg.verify_isv_svn = sgx_json.compare_item(sgx_json.get_item(sgx_json.get_handle(), "verify_isv_svn"), "on");
|
||||
|
||||
auto objs = sgx_json.get_item(sgx_json.get_handle(), "sgx_mrs");
|
||||
auto obj_num = std::min(cJSON_GetArraySize(objs), SGX_MESUREMENTS_MAX_SIZE);
|
||||
|
||||
sgx_cfg.sgx_mrs = std::vector<sgx_measurement>(obj_num, sgx_measurement());
|
||||
for (auto i = 0; i < obj_num; i++) {
|
||||
auto obj = cJSON_GetArrayItem(objs, i);
|
||||
|
||||
auto mr_enclave = sgx_json.print_item(sgx_json.get_item(obj, "mr_enclave"));
|
||||
memset(sgx_cfg.sgx_mrs[i].mr_enclave, 0, sizeof(sgx_cfg.sgx_mrs[i].mr_enclave));
|
||||
hex_to_byte(mr_enclave+1, sgx_cfg.sgx_mrs[i].mr_enclave, sizeof(sgx_cfg.sgx_mrs[i].mr_enclave));
|
||||
|
||||
auto mr_signer = sgx_json.print_item(sgx_json.get_item(obj, "mr_signer"));
|
||||
memset(sgx_cfg.sgx_mrs[i].mr_signer, 0, sizeof(sgx_cfg.sgx_mrs[i].mr_signer));
|
||||
hex_to_byte(mr_signer+1, sgx_cfg.sgx_mrs[i].mr_signer, sizeof(sgx_cfg.sgx_mrs[i].mr_signer));
|
||||
|
||||
auto isv_prod_id = sgx_json.print_item(sgx_json.get_item(obj, "isv_prod_id"));
|
||||
sgx_cfg.sgx_mrs[i].isv_prod_id = strtoul(isv_prod_id, nullptr, 10);
|
||||
|
||||
auto isv_svn = sgx_json.print_item(sgx_json.get_item(obj, "isv_svn"));
|
||||
sgx_cfg.sgx_mrs[i].isv_svn = strtoul(isv_svn, nullptr, 10);
|
||||
};
|
||||
return sgx_cfg;
|
||||
}
|
||||
|
||||
void ra_tls_parse_sgx_config(sgx_config sgx_cfg) {
|
||||
std::lock_guard<std::mutex> lock(_ctx_.mtx);
|
||||
_ctx_.sgx_cfg = sgx_cfg;
|
||||
}
|
||||
|
||||
void ra_tls_parse_sgx_config(const char* file) {
|
||||
ra_tls_parse_sgx_config(parse_sgx_config_json(file));
|
||||
}
|
||||
|
||||
void ra_tls_verify_init() {
|
||||
std::lock_guard<std::mutex> lock(_ctx_.mtx);
|
||||
}
|
||||
|
||||
static bool verify_measurement_internal(const char* mr_enclave, const char* mr_signer,
|
||||
const char* isv_prod_id, const char* isv_svn) {
|
||||
bool status = false;
|
||||
auto & sgx_cfg = _ctx_.sgx_cfg;
|
||||
for (auto & obj : sgx_cfg.sgx_mrs) {
|
||||
status = true;
|
||||
|
||||
if (status && sgx_cfg.verify_mr_enclave && \
|
||||
memcmp(obj.mr_enclave, mr_enclave, 32)) {
|
||||
status = false;
|
||||
}
|
||||
|
||||
if (status && sgx_cfg.verify_mr_signer && \
|
||||
memcmp(obj.mr_signer, mr_signer, 32)) {
|
||||
status = false;
|
||||
}
|
||||
|
||||
if (status && sgx_cfg.verify_isv_prod_id && \
|
||||
(obj.isv_prod_id != *(uint16_t*)isv_prod_id)) {
|
||||
status = false;
|
||||
}
|
||||
|
||||
if (status && sgx_cfg.verify_isv_svn && \
|
||||
(obj.isv_svn != *(uint16_t*)isv_svn)) {
|
||||
status = false;
|
||||
}
|
||||
|
||||
if (status) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
int verify_measurement(const char* mr_enclave, const char* mr_signer,
|
||||
const char* isv_prod_id, const char* isv_svn) {
|
||||
std::lock_guard<std::mutex> lock(_ctx_.mtx);
|
||||
bool status = false;
|
||||
try {
|
||||
assert(mr_enclave && mr_signer && isv_prod_id && isv_svn);
|
||||
status = verify_measurement_internal(mr_enclave, mr_signer, isv_prod_id, isv_svn);
|
||||
grpc_printf("remote sgx measurements\n");
|
||||
grpc_printf(" |- mr_enclave : %s\n", byte_to_hex(mr_enclave, 32).c_str());
|
||||
grpc_printf(" |- mr_signer : %s\n", byte_to_hex(mr_signer, 32).c_str());
|
||||
grpc_printf(" |- isv_prod_id : %hu\n", *((uint16_t*)isv_prod_id));
|
||||
grpc_printf(" |- isv_svn : %hu\n", *((uint16_t*)isv_svn));
|
||||
if (status) {
|
||||
grpc_printf(" |- verify result : success\n");
|
||||
} else {
|
||||
grpc_printf(" |- verify result : failed\n");
|
||||
}
|
||||
} catch (...) {
|
||||
grpc_printf("unable to verify measurement!");
|
||||
}
|
||||
|
||||
fflush(stdout);
|
||||
return status ? 0 : -1;
|
||||
}
|
||||
|
||||
int TlsAuthorizationCheck::Schedule(grpc::experimental::TlsServerAuthorizationCheckArg* arg) {
|
||||
GPR_ASSERT(arg != nullptr);
|
||||
|
||||
char der_crt[16000] = "";
|
||||
auto peer_cert_buf = arg->peer_cert();
|
||||
peer_cert_buf.copy(der_crt, peer_cert_buf.length(), 0);
|
||||
|
||||
#ifdef SGX_RA_TLS_OCCLUM_BACKEND
|
||||
int ret = occlum_verify_cert((const unsigned char *)der_crt, 16000);
|
||||
#endif
|
||||
|
||||
if (ret != 0) {
|
||||
grpc_printf("something went wrong while verifying quote\n");
|
||||
arg->set_success(0);
|
||||
arg->set_status(GRPC_STATUS_UNAUTHENTICATED);
|
||||
} else {
|
||||
arg->set_success(1);
|
||||
arg->set_status(GRPC_STATUS_OK);
|
||||
}
|
||||
return 0;
|
||||
};
|
||||
|
||||
void TlsAuthorizationCheck::Cancel(grpc::experimental::TlsServerAuthorizationCheckArg* arg) {
|
||||
GPR_ASSERT(arg != nullptr);
|
||||
arg->set_status(GRPC_STATUS_PERMISSION_DENIED);
|
||||
arg->set_error_details("cancelled");
|
||||
};
|
||||
|
||||
int ra_tls_auth_check_schedule(void* /* confiuser_data */,
|
||||
grpc_tls_server_authorization_check_arg* arg) {
|
||||
char der_crt[16000] = "";
|
||||
memcpy(der_crt, arg->peer_cert, strlen(arg->peer_cert));
|
||||
|
||||
#ifdef SGX_RA_TLS_OCCLUM_BACKEND
|
||||
int ret = occlum_verify_cert((const unsigned char *)der_crt, 16000);
|
||||
#endif
|
||||
|
||||
if (ret != 0) {
|
||||
grpc_printf("something went wrong while verifying quote\n");
|
||||
arg->success = 0;
|
||||
arg->status = GRPC_STATUS_UNAUTHENTICATED;
|
||||
} else {
|
||||
arg->success = 1;
|
||||
arg->status = GRPC_STATUS_OK;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void credential_option_set_authorization_check(grpc::sgx::CredentialsOptions& options) {
|
||||
std::lock_guard<std::mutex> lock(_ctx_.mtx);
|
||||
|
||||
_ctx_.cache.id++;
|
||||
|
||||
auto authorization_check = _ctx_.cache.authorization_check.insert({
|
||||
_ctx_.cache.id, std::make_shared<grpc::sgx::TlsAuthorizationCheck>()
|
||||
}).first;
|
||||
|
||||
auto authorization_check_config = _ctx_.cache.authorization_check_config.insert({
|
||||
_ctx_.cache.id,
|
||||
std::make_shared<grpc::experimental::TlsServerAuthorizationCheckConfig>(
|
||||
authorization_check->second)
|
||||
}).first;
|
||||
|
||||
options.set_authorization_check_config(authorization_check_config->second);
|
||||
options.set_verification_option(GRPC_TLS_SKIP_ALL_SERVER_VERIFICATION);
|
||||
}
|
||||
|
||||
} // namespace sgx
|
||||
} // namespace grpc
|
109
demos/ra_tls/grpc/v1.38.1/src/cpp/sgx/sgx_ra_tls_backends.h
Normal file
109
demos/ra_tls/grpc/v1.38.1/src/cpp/sgx/sgx_ra_tls_backends.h
Normal file
@ -0,0 +1,109 @@
|
||||
/*
|
||||
*
|
||||
* Copyright (c) 2022 Intel Corporation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SGX_RA_TLS_BACKENDS_H
|
||||
#define SGX_RA_TLS_BACKENDS_H
|
||||
|
||||
#include "sgx_ra_tls_utils.h"
|
||||
|
||||
#include <mutex>
|
||||
#include <unordered_map>
|
||||
|
||||
#include <grpcpp/grpcpp.h>
|
||||
#include <grpc/grpc_security.h>
|
||||
#include <grpc/grpc_security_constants.h>
|
||||
#include <grpcpp/security/credentials.h>
|
||||
#include <grpcpp/security/tls_certificate_provider.h>
|
||||
#include <grpcpp/security/tls_credentials_options.h>
|
||||
#include <grpcpp/security/server_credentials.h>
|
||||
#include <grpcpp/security/sgx/sgx_ra_tls_options.h>
|
||||
|
||||
// Set 1 for strict safety checks
|
||||
#define SGX_MESUREMENTS_MAX_SIZE 16
|
||||
|
||||
namespace grpc {
|
||||
namespace sgx {
|
||||
|
||||
class TlsAuthorizationCheck
|
||||
: public grpc::experimental::TlsServerAuthorizationCheckInterface {
|
||||
int Schedule(grpc::experimental::TlsServerAuthorizationCheckArg* arg) override;
|
||||
void Cancel(grpc::experimental::TlsServerAuthorizationCheckArg* arg) override;
|
||||
};
|
||||
|
||||
struct sgx_measurement {
|
||||
char mr_enclave[32];
|
||||
char mr_signer[32];
|
||||
uint16_t isv_prod_id;
|
||||
uint16_t isv_svn;
|
||||
};
|
||||
|
||||
struct sgx_config {
|
||||
bool verify_mr_enclave = true;
|
||||
bool verify_mr_signer = true;
|
||||
bool verify_isv_prod_id = true;
|
||||
bool verify_isv_svn = true;
|
||||
std::vector<sgx_measurement> sgx_mrs;
|
||||
};
|
||||
|
||||
struct ra_tls_cache {
|
||||
int id = 0;
|
||||
std::unordered_map<
|
||||
int, std::shared_ptr<grpc::experimental::StaticDataCertificateProvider>
|
||||
> certificate_provider;
|
||||
std::unordered_map<
|
||||
int, std::shared_ptr<grpc::sgx::TlsAuthorizationCheck>
|
||||
> authorization_check;
|
||||
std::unordered_map<
|
||||
int, std::shared_ptr<grpc::experimental::TlsServerAuthorizationCheckConfig>
|
||||
> authorization_check_config;
|
||||
};
|
||||
|
||||
struct ra_tls_context {
|
||||
std::mutex mtx;
|
||||
struct sgx_config sgx_cfg;
|
||||
struct ra_tls_cache cache;
|
||||
};
|
||||
|
||||
extern struct ra_tls_context _ctx_;
|
||||
|
||||
|
||||
#ifdef SGX_RA_TLS_OCCLUM_BACKEND
|
||||
|
||||
std::vector<std::string> occlum_get_key_cert();
|
||||
|
||||
int occlum_verify_cert(const unsigned char * der_crt, size_t len);
|
||||
|
||||
#endif // SGX_RA_TLS_OCCLUM_BACKEND
|
||||
|
||||
void ra_tls_parse_sgx_config(sgx_config sgx_cfg);
|
||||
|
||||
void ra_tls_parse_sgx_config(const char* file);
|
||||
|
||||
void ra_tls_verify_init();
|
||||
|
||||
int verify_measurement(const char* mr_enclave, const char* mr_signer,
|
||||
const char* isv_prod_id, const char* isv_svn);
|
||||
|
||||
void credential_option_set_certificate_provider(grpc::sgx::CredentialsOptions& options);
|
||||
|
||||
void credential_option_set_authorization_check(grpc::sgx::CredentialsOptions& options);
|
||||
|
||||
} // namespace sgx
|
||||
} // namespace grpc
|
||||
|
||||
#endif // SGX_RA_TLS_BACKENDS_H
|
@ -0,0 +1,98 @@
|
||||
/*
|
||||
*
|
||||
* Copyright (c) 2022 Intel Corporation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "sgx_ra_tls_backends.h"
|
||||
|
||||
namespace grpc {
|
||||
namespace sgx {
|
||||
|
||||
/*
|
||||
RA-TLS: on client, only need to register ra_tls_verify_callback() for cert verification
|
||||
1. extract SGX quote from "quote" OID extension from crt
|
||||
2. compare public key's hash from cert against quote's report_data
|
||||
3. prepare user-supplied verification parameter "allow outdated TCB"
|
||||
4. call into libsgx_dcap_quoteverify to verify ECDSA/based SGX quote
|
||||
5. verify all measurements from the SGX quote
|
||||
*/
|
||||
|
||||
std::shared_ptr<grpc::ChannelCredentials> TlsCredentials(sgx_config sgx_cfg) {
|
||||
grpc::sgx::CredentialsOptions options;
|
||||
|
||||
ra_tls_parse_sgx_config(sgx_cfg);
|
||||
|
||||
credential_option_set_certificate_provider(options);
|
||||
|
||||
ra_tls_verify_init();
|
||||
credential_option_set_authorization_check(options);
|
||||
|
||||
return grpc::experimental::TlsCredentials(
|
||||
reinterpret_cast<const grpc::experimental::TlsChannelCredentialsOptions&>(options));
|
||||
};
|
||||
|
||||
std::shared_ptr<grpc::ChannelCredentials> TlsCredentials(const char* sgx_cfg_json) {
|
||||
grpc::sgx::CredentialsOptions options;
|
||||
|
||||
ra_tls_parse_sgx_config(sgx_cfg_json);
|
||||
|
||||
credential_option_set_certificate_provider(options);
|
||||
|
||||
ra_tls_verify_init();
|
||||
credential_option_set_authorization_check(options);
|
||||
|
||||
return grpc::experimental::TlsCredentials(
|
||||
reinterpret_cast<const grpc::experimental::TlsChannelCredentialsOptions&>(options));
|
||||
};
|
||||
|
||||
std::shared_ptr<grpc::ServerCredentials> TlsServerCredentials(sgx_config sgx_cfg) {
|
||||
grpc::sgx::CredentialsOptions options;
|
||||
|
||||
ra_tls_parse_sgx_config(sgx_cfg);
|
||||
|
||||
credential_option_set_certificate_provider(options);
|
||||
|
||||
ra_tls_verify_init();
|
||||
credential_option_set_authorization_check(options);
|
||||
|
||||
return grpc::experimental::TlsServerCredentials(
|
||||
reinterpret_cast<const grpc::experimental::TlsServerCredentialsOptions&>(options));
|
||||
};
|
||||
|
||||
std::shared_ptr<grpc::ServerCredentials> TlsServerCredentials(const char* sgx_cfg_json) {
|
||||
grpc::sgx::CredentialsOptions options;
|
||||
|
||||
ra_tls_parse_sgx_config(sgx_cfg_json);
|
||||
|
||||
credential_option_set_certificate_provider(options);
|
||||
|
||||
ra_tls_verify_init();
|
||||
credential_option_set_authorization_check(options);
|
||||
|
||||
return grpc::experimental::TlsServerCredentials(
|
||||
reinterpret_cast<const grpc::experimental::TlsServerCredentialsOptions&>(options));
|
||||
};
|
||||
|
||||
std::shared_ptr<grpc::Channel> CreateSecureChannel(
|
||||
string target_str, std::shared_ptr<grpc::ChannelCredentials> channel_creds) {
|
||||
GPR_ASSERT(channel_creds.get() != nullptr);
|
||||
auto channel_args = grpc::ChannelArguments();
|
||||
channel_args.SetSslTargetNameOverride("RATLS");
|
||||
return grpc::CreateCustomChannel(target_str, std::move(channel_creds), channel_args);
|
||||
};
|
||||
|
||||
} // namespace sgx
|
||||
} // namespace grpc
|
318
demos/ra_tls/grpc/v1.38.1/src/cpp/sgx/sgx_ra_tls_occlum.cc
Normal file
318
demos/ra_tls/grpc/v1.38.1/src/cpp/sgx/sgx_ra_tls_occlum.cc
Normal file
@ -0,0 +1,318 @@
|
||||
/*
|
||||
*
|
||||
* Copyright (c) 2022 Intel Corporation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "sgx_ra_tls_backends.h"
|
||||
|
||||
namespace grpc {
|
||||
namespace sgx {
|
||||
|
||||
#ifdef SGX_RA_TLS_OCCLUM_BACKEND
|
||||
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/rsa.h>
|
||||
#include <openssl/x509.h>
|
||||
#include <openssl/x509v3.h>
|
||||
#include <openssl/sha.h>
|
||||
#include <openssl/pem.h>
|
||||
#include <openssl/asn1.h>
|
||||
|
||||
#include "sgx_quote_3.h"
|
||||
#include "dcap_quote.h"
|
||||
|
||||
const char * RA_TLS_LONG_NAME = "RA-TLS Extension";
|
||||
const char * RA_TLS_SHORT_NAME = "RA-TLS";
|
||||
|
||||
std::vector<std::string> occlum_get_key_cert() {
|
||||
unsigned char private_key_pem[16000], cert_pem[16000];
|
||||
|
||||
BIGNUM * e = BN_new();
|
||||
BN_set_word(e, RSA_F4);
|
||||
RSA * rsa = RSA_new();
|
||||
RSA_generate_key_ex(rsa, 2048, e, nullptr);
|
||||
|
||||
EVP_PKEY * pkey = EVP_PKEY_new();
|
||||
EVP_PKEY_assign_RSA(pkey, rsa);
|
||||
|
||||
X509 * x509 = X509_new();
|
||||
|
||||
ASN1_INTEGER_set(X509_get_serialNumber(x509), 1);
|
||||
X509_gmtime_adj(X509_get_notBefore(x509), 0);
|
||||
X509_gmtime_adj(X509_get_notAfter(x509), 630720000L);
|
||||
X509_set_pubkey(x509, pkey);
|
||||
|
||||
X509_NAME * name = X509_NAME_new();
|
||||
// X509_NAME * name = X509_get_subject_name(x509);
|
||||
X509_NAME_add_entry_by_txt(name, "C", MBSTRING_ASC,
|
||||
(unsigned char *)"CN", -1, -1, 0);
|
||||
X509_NAME_add_entry_by_txt(name, "O", MBSTRING_ASC,
|
||||
(unsigned char *)"Intel Inc.", -1, -1, 0);
|
||||
X509_NAME_add_entry_by_txt(name, "CN", MBSTRING_ASC,
|
||||
(unsigned char *)"localhost", -1, -1, 0);
|
||||
X509_set_subject_name(x509, name);
|
||||
X509_set_issuer_name(x509, name);
|
||||
|
||||
int32_t ret;
|
||||
size_t key_len = i2d_PUBKEY(pkey, 0);
|
||||
unsigned char *public_key = NULL;
|
||||
// size_t pubkey_len = i2d_PUBKEY(pkey, &public_key);
|
||||
size_t pubkey_len = i2d_X509_PUBKEY(X509_get_X509_PUBKEY(x509), &public_key);
|
||||
|
||||
if (pubkey_len != key_len) {
|
||||
grpc_printf("get public key failed!\n");
|
||||
}
|
||||
|
||||
BIO *bio = BIO_new(BIO_s_mem());
|
||||
if (nullptr == bio) {
|
||||
grpc_printf("create bio failed!\n");
|
||||
}
|
||||
|
||||
ret = PEM_write_bio_RSAPrivateKey(bio, rsa, nullptr, nullptr, 0, nullptr, nullptr);
|
||||
if (ret == 0) {
|
||||
grpc_printf("write private key failed!\n");
|
||||
}
|
||||
|
||||
ret = BIO_read(bio, private_key_pem, bio->num_write);
|
||||
if (ret == 0) {
|
||||
grpc_printf("read private key failed!\n");
|
||||
}
|
||||
|
||||
unsigned char hash[SHA256_DIGEST_LENGTH];
|
||||
SHA256_CTX sha256;
|
||||
SHA256_Init(&sha256);
|
||||
SHA256_Update(&sha256, public_key, key_len);
|
||||
SHA256_Final(hash, &sha256);
|
||||
|
||||
void *handle;
|
||||
uint32_t quote_size;
|
||||
uint8_t *p_quote_buffer;
|
||||
|
||||
handle = dcap_quote_open();
|
||||
quote_size = dcap_get_quote_size(handle);
|
||||
|
||||
p_quote_buffer = (uint8_t*)malloc(quote_size);
|
||||
if (nullptr == p_quote_buffer) {
|
||||
grpc_printf("Couldn't allocate quote_buffer\n");
|
||||
}
|
||||
memset(p_quote_buffer, 0, quote_size);
|
||||
|
||||
sgx_report_data_t report_data = { 0 };
|
||||
memcpy(report_data.d, hash, SHA256_DIGEST_LENGTH);
|
||||
|
||||
ret = dcap_generate_quote(handle, p_quote_buffer, &report_data);
|
||||
if (0 != ret) {
|
||||
grpc_printf( "Error in dcap_generate_quote.\n");
|
||||
}
|
||||
|
||||
int nid = OBJ_create("1.2.840.113741.1", RA_TLS_SHORT_NAME, RA_TLS_LONG_NAME);
|
||||
ASN1_OBJECT* obj = OBJ_nid2obj(nid);
|
||||
ASN1_OCTET_STRING* data = ASN1_OCTET_STRING_new();
|
||||
ASN1_OCTET_STRING_set(data, p_quote_buffer, quote_size);
|
||||
|
||||
X509_EXTENSION* ext = X509_EXTENSION_create_by_OBJ(nullptr, obj, 0, data);
|
||||
X509_add_ext(x509, ext, -1);
|
||||
|
||||
X509_sign(x509, pkey, EVP_sha1());
|
||||
|
||||
BIO *cert_bio = BIO_new(BIO_s_mem());
|
||||
if (nullptr == cert_bio) {
|
||||
grpc_printf("create crt bio failed!\n");
|
||||
}
|
||||
|
||||
if (0 == PEM_write_bio_X509(cert_bio, x509)) {
|
||||
BIO_free(cert_bio);
|
||||
grpc_printf("read crt bio failed!\n");
|
||||
}
|
||||
|
||||
ret = BIO_read(cert_bio, cert_pem, cert_bio->num_write);
|
||||
if (ret == 0) {
|
||||
grpc_printf("read pem cert failed!\n");
|
||||
}
|
||||
|
||||
BIO_free(bio);
|
||||
BIO_free(cert_bio);
|
||||
EVP_PKEY_free(pkey);
|
||||
check_free(p_quote_buffer);
|
||||
dcap_quote_close(handle);
|
||||
|
||||
std::vector<std::string> key_cert;
|
||||
key_cert.emplace_back(std::string((char*) private_key_pem));
|
||||
key_cert.emplace_back(std::string((char*) cert_pem));
|
||||
return key_cert;
|
||||
}
|
||||
|
||||
static int occlum_get_quote(X509 *x509, uint8_t **quote, size_t *len) {
|
||||
STACK_OF(X509_EXTENSION) *exts = x509->cert_info->extensions;
|
||||
int ext_num;
|
||||
int ret = -1;
|
||||
if (exts) {
|
||||
ext_num = sk_X509_EXTENSION_num(exts);
|
||||
|
||||
for (int i = 0; i < ext_num; i++) {
|
||||
X509_EXTENSION *ext = sk_X509_EXTENSION_value(exts, i);
|
||||
ASN1_OBJECT *obj = X509_EXTENSION_get_object(ext);
|
||||
|
||||
unsigned nid = OBJ_obj2nid(obj);
|
||||
if (nid != NID_undef) {
|
||||
const char *ln = OBJ_nid2ln(nid);
|
||||
if (memcmp(RA_TLS_LONG_NAME, ln, sizeof(RA_TLS_LONG_NAME)) == 0) {
|
||||
BIO *ext_bio = BIO_new(BIO_s_mem());
|
||||
|
||||
*len = i2d_ASN1_OCTET_STRING(ext->value, quote);
|
||||
*quote = *quote + 4;
|
||||
*len = *len - 4;
|
||||
ret = 0;
|
||||
BIO_free(ext_bio);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int occlum_verify_pubkey_hash(X509 *x509, uint8_t *pubkey_hash, size_t len) {
|
||||
EVP_PKEY *pkey = X509_get_pubkey(x509);
|
||||
|
||||
int32_t ret;
|
||||
size_t key_len = EVP_PKEY_bits(pkey)/8;
|
||||
unsigned char *public_key = NULL;
|
||||
|
||||
key_len = i2d_X509_PUBKEY(X509_get_X509_PUBKEY(x509), &public_key);
|
||||
|
||||
unsigned char hash[SHA256_DIGEST_LENGTH];
|
||||
SHA256_CTX sha256;
|
||||
SHA256_Init(&sha256);
|
||||
SHA256_Update(&sha256, public_key, key_len);
|
||||
SHA256_Final(hash, &sha256);
|
||||
|
||||
ret = memcmp(hash, pubkey_hash, len);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int occlum_verify_quote(uint8_t * quote_buffer, size_t quote_size) {
|
||||
void *handle;
|
||||
handle = dcap_quote_open();
|
||||
|
||||
uint32_t supplemental_size, ret;
|
||||
uint8_t *p_supplemental_buffer;
|
||||
sgx_ql_qv_result_t quote_verification_result = SGX_QL_QV_RESULT_UNSPECIFIED;
|
||||
uint32_t collateral_expiration_status = 1;
|
||||
|
||||
supplemental_size = dcap_get_supplemental_data_size(handle);
|
||||
p_supplemental_buffer = (uint8_t *)malloc(supplemental_size);
|
||||
if (NULL == p_supplemental_buffer) {
|
||||
grpc_printf("Couldn't allocate supplemental buffer\n");
|
||||
}
|
||||
memset(p_supplemental_buffer, 0, supplemental_size);
|
||||
|
||||
ret = dcap_verify_quote(
|
||||
handle,
|
||||
quote_buffer,
|
||||
quote_size,
|
||||
&collateral_expiration_status,
|
||||
"e_verification_result,
|
||||
supplemental_size,
|
||||
p_supplemental_buffer
|
||||
);
|
||||
|
||||
if (0 != ret) {
|
||||
grpc_printf( "Error in dcap_verify_quote.\n");
|
||||
}
|
||||
|
||||
if (collateral_expiration_status != 0) {
|
||||
grpc_printf("the verification collateral has expired\n");
|
||||
}
|
||||
|
||||
switch (quote_verification_result) {
|
||||
case SGX_QL_QV_RESULT_OK:
|
||||
grpc_printf("Succeed to verify the quote!\n");
|
||||
break;
|
||||
case SGX_QL_QV_RESULT_CONFIG_NEEDED:
|
||||
case SGX_QL_QV_RESULT_OUT_OF_DATE:
|
||||
case SGX_QL_QV_RESULT_OUT_OF_DATE_CONFIG_NEEDED:
|
||||
case SGX_QL_QV_RESULT_SW_HARDENING_NEEDED:
|
||||
case SGX_QL_QV_RESULT_CONFIG_AND_SW_HARDENING_NEEDED:
|
||||
grpc_printf("WARN: App: Verification completed with Non-terminal result: %x\n",
|
||||
quote_verification_result);
|
||||
break;
|
||||
case SGX_QL_QV_RESULT_INVALID_SIGNATURE:
|
||||
case SGX_QL_QV_RESULT_REVOKED:
|
||||
case SGX_QL_QV_RESULT_UNSPECIFIED:
|
||||
default:
|
||||
grpc_printf("\tError: App: Verification completed with Terminal result: %x\n",
|
||||
quote_verification_result);
|
||||
}
|
||||
check_free(p_supplemental_buffer);
|
||||
dcap_quote_close(handle);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int occlum_verify_cert(const unsigned char * der_crt, size_t len) {
|
||||
BIO* bio = BIO_new(BIO_s_mem());
|
||||
BIO_write(bio, der_crt, strlen((const char *)der_crt));
|
||||
X509 *x509 = PEM_read_bio_X509(bio, NULL, NULL, NULL);
|
||||
|
||||
if (x509 == nullptr) {
|
||||
grpc_printf("parse the crt failed! \n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
uint8_t * quote_buf = nullptr;
|
||||
size_t quote_len = 0;
|
||||
int ret = occlum_get_quote(x509, "e_buf, "e_len);
|
||||
if (ret != 0) {
|
||||
grpc_printf("parse quote failed!\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = occlum_verify_quote(quote_buf, quote_len);
|
||||
if (ret != 0) {
|
||||
grpc_printf("verify quote failed!\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
sgx_quote3_t *p_quote = (sgx_quote3_t *)quote_buf;
|
||||
sgx_report_body_t *p_rep_body = (sgx_report_body_t *)(&p_quote->report_body);
|
||||
sgx_report_data_t *p_rep_data =(sgx_report_data_t *)(&p_rep_body->report_data);
|
||||
uint8_t *pubkey_hash = p_rep_data->d;
|
||||
|
||||
|
||||
ret = occlum_verify_pubkey_hash(x509, pubkey_hash, SHA256_DIGEST_LENGTH);
|
||||
if (ret != 0) {
|
||||
grpc_printf("verify the public key hash failed!\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = verify_measurement((const char *)&p_rep_body->mr_enclave,
|
||||
(const char *)&p_rep_body->mr_signer,
|
||||
(const char *)&p_rep_body->isv_prod_id,
|
||||
(const char *)&p_rep_body->isv_svn);
|
||||
if (ret != 0) {
|
||||
grpc_printf("verify the measurement failed!\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
BIO_free(bio);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif // SGX_RA_TLS_OCCLUM_BACKEND
|
||||
|
||||
} // namespace sgx
|
||||
} // namespace grpc
|
55
demos/ra_tls/grpc/v1.38.1/src/cpp/sgx/sgx_ra_tls_options.cc
Normal file
55
demos/ra_tls/grpc/v1.38.1/src/cpp/sgx/sgx_ra_tls_options.cc
Normal file
@ -0,0 +1,55 @@
|
||||
/*
|
||||
*
|
||||
* Copyright (c) 2022 Intel Corporation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <grpc/grpc_security.h>
|
||||
#include <grpc/support/alloc.h>
|
||||
#include <grpcpp/security/sgx/sgx_ra_tls_options.h>
|
||||
|
||||
#include "absl/container/inlined_vector.h"
|
||||
#include "src/cpp/common/tls_credentials_options_util.h"
|
||||
|
||||
namespace grpc {
|
||||
namespace sgx {
|
||||
|
||||
void CredentialsOptions::set_verification_option(
|
||||
grpc_tls_server_verification_option server_verification_option) {
|
||||
grpc_tls_credentials_options* options = c_credentials_options();
|
||||
GPR_ASSERT(options != nullptr);
|
||||
grpc_tls_credentials_options_set_server_verification_option(
|
||||
options, server_verification_option);
|
||||
}
|
||||
|
||||
void CredentialsOptions::set_authorization_check_config(
|
||||
std::shared_ptr<grpc::experimental::TlsServerAuthorizationCheckConfig> config) {
|
||||
grpc_tls_credentials_options* options = c_credentials_options();
|
||||
GPR_ASSERT(options != nullptr);
|
||||
if (config != nullptr) {
|
||||
grpc_tls_credentials_options_set_server_authorization_check_config(
|
||||
options, config->c_config());
|
||||
}
|
||||
}
|
||||
|
||||
void CredentialsOptions::set_cert_request_type(
|
||||
grpc_ssl_client_certificate_request_type cert_request_type) {
|
||||
grpc_tls_credentials_options* options = c_credentials_options();
|
||||
GPR_ASSERT(options != nullptr);
|
||||
grpc_tls_credentials_options_set_cert_request_type(options, cert_request_type);
|
||||
}
|
||||
|
||||
} // namespace sgx
|
||||
} // namespace grpc
|
169
demos/ra_tls/grpc/v1.38.1/src/cpp/sgx/sgx_ra_tls_utils.cc
Normal file
169
demos/ra_tls/grpc/v1.38.1/src/cpp/sgx/sgx_ra_tls_utils.cc
Normal file
@ -0,0 +1,169 @@
|
||||
/*
|
||||
*
|
||||
* Copyright (c) 2022 Intel Corporation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "sgx_ra_tls_utils.h"
|
||||
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
|
||||
namespace grpc {
|
||||
namespace sgx {
|
||||
|
||||
void check_free(void* ptr) {
|
||||
if (ptr) {
|
||||
free(ptr);
|
||||
ptr = nullptr;
|
||||
};
|
||||
}
|
||||
|
||||
bool hex_to_byte(const char *src, char *dst, size_t dst_size) {
|
||||
if (std::strlen(src) < dst_size*2) {
|
||||
return false;
|
||||
} else {
|
||||
for (auto i = 0; i < dst_size; i++) {
|
||||
if (!isxdigit(src[i*2]) || !isxdigit(src[i*2+1])) {
|
||||
return false;
|
||||
} else {
|
||||
sscanf(src+i*2, "%02hhx", dst+i);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
void byte_to_hex(const char *src, char *dst, size_t src_size) {
|
||||
for (auto i = 0; i < src_size; i++) {
|
||||
sprintf(dst+i*2, "%02hhx", src[i]);
|
||||
}
|
||||
};
|
||||
|
||||
std::string byte_to_hex(const char *src, size_t src_size) {
|
||||
char dst[src_size*2];
|
||||
memset(dst, 0, sizeof(dst));
|
||||
byte_to_hex(src, dst, src_size);
|
||||
return std::string(dst);
|
||||
};
|
||||
|
||||
library_engine::library_engine() : handle(nullptr), error(nullptr) {};
|
||||
|
||||
library_engine::library_engine(const char* file, int mode) : handle(nullptr), error(nullptr) {
|
||||
this->open(file, mode);
|
||||
}
|
||||
|
||||
library_engine::~library_engine() {
|
||||
this->close();
|
||||
}
|
||||
|
||||
void library_engine::open(const char* file, int mode) {
|
||||
this->close();
|
||||
handle = dlopen(file, mode);
|
||||
error = dlerror();
|
||||
if (error != nullptr || handle == nullptr) {
|
||||
throw std::runtime_error("dlopen " + std::string(file) + " error, " + std::string(error));
|
||||
}
|
||||
}
|
||||
|
||||
void library_engine::close() {
|
||||
if (handle) {
|
||||
dlclose(handle);
|
||||
}
|
||||
handle = nullptr;
|
||||
error = nullptr;
|
||||
}
|
||||
|
||||
void* library_engine::get_func(const char* name) {
|
||||
auto func = dlsym(handle, name);
|
||||
error = dlerror();
|
||||
if (error != nullptr || func == nullptr) {
|
||||
throw std::runtime_error("dlsym " + std::string(name) + " error, " + std::string(error));
|
||||
return nullptr;
|
||||
} else {
|
||||
return func;
|
||||
}
|
||||
}
|
||||
|
||||
void* library_engine::get_handle() {
|
||||
return handle;
|
||||
}
|
||||
|
||||
json_engine::json_engine() : handle(nullptr) {};
|
||||
|
||||
json_engine::json_engine(const char* file) : handle(nullptr){
|
||||
this->open(file);
|
||||
}
|
||||
|
||||
json_engine::~json_engine() {
|
||||
this->close();
|
||||
}
|
||||
|
||||
bool json_engine::open(const char* file) {
|
||||
if (!file) {
|
||||
grpc_printf("wrong json file path\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
this->close();
|
||||
|
||||
auto file_ptr = fopen(file, "r");
|
||||
fseek(file_ptr, 0, SEEK_END);
|
||||
auto length = ftell(file_ptr);
|
||||
fseek(file_ptr, 0, SEEK_SET);
|
||||
auto buffer = malloc(length);
|
||||
fread(buffer, 1, length, file_ptr);
|
||||
fclose(file_ptr);
|
||||
|
||||
this->handle = cJSON_Parse((const char *)buffer);
|
||||
|
||||
check_free(buffer);
|
||||
|
||||
if (this->handle) {
|
||||
return true;
|
||||
} else {
|
||||
grpc_printf("cjson open %s error: %s", file, cJSON_GetErrorPtr());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void json_engine::close() {
|
||||
if (this->handle) {
|
||||
cJSON_Delete(this->handle);
|
||||
this->handle = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
cJSON* json_engine::get_handle() {
|
||||
return this->handle;
|
||||
}
|
||||
|
||||
cJSON* json_engine::get_item(cJSON* obj, const char* item) {
|
||||
return cJSON_GetObjectItem(obj, item);
|
||||
};
|
||||
|
||||
char* json_engine::print_item(cJSON* obj) {
|
||||
return cJSON_Print(obj);
|
||||
};
|
||||
|
||||
bool json_engine::compare_item(cJSON* obj, const char* item) {
|
||||
auto obj_item = this->print_item(obj);
|
||||
return strncmp(obj_item+1, item, std::min(strlen(item), strlen(obj_item)-2)) == 0;
|
||||
};
|
||||
|
||||
} // namespace sgx
|
||||
} // namespace grpc
|
91
demos/ra_tls/grpc/v1.38.1/src/cpp/sgx/sgx_ra_tls_utils.h
Normal file
91
demos/ra_tls/grpc/v1.38.1/src/cpp/sgx/sgx_ra_tls_utils.h
Normal file
@ -0,0 +1,91 @@
|
||||
/*
|
||||
*
|
||||
* Copyright (c) 2022 Intel Corporation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SGX_RA_TLS_UTILS_H
|
||||
#define SGX_RA_TLS_UTILS_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include <dlfcn.h>
|
||||
|
||||
#define grpc_printf printf
|
||||
#define grpc_fprintf fprintf
|
||||
|
||||
namespace grpc {
|
||||
namespace sgx {
|
||||
|
||||
#include "cjson/cJSON.h"
|
||||
|
||||
class library_engine {
|
||||
public:
|
||||
library_engine();
|
||||
|
||||
library_engine(const char*, int);
|
||||
|
||||
~library_engine();
|
||||
|
||||
void open(const char*, int);
|
||||
|
||||
void close();
|
||||
|
||||
void* get_func(const char*);
|
||||
|
||||
void* get_handle();
|
||||
|
||||
private:
|
||||
void* handle;
|
||||
char* error;
|
||||
};
|
||||
|
||||
class json_engine {
|
||||
public:
|
||||
json_engine();
|
||||
|
||||
json_engine(const char*);
|
||||
|
||||
~json_engine();
|
||||
|
||||
bool open(const char*);
|
||||
|
||||
void close();
|
||||
|
||||
cJSON* get_handle();
|
||||
|
||||
cJSON* get_item(cJSON* obj, const char* item);
|
||||
|
||||
char* print_item(cJSON* obj);
|
||||
|
||||
bool compare_item(cJSON* obj, const char* item);
|
||||
|
||||
private:
|
||||
cJSON* handle;
|
||||
};
|
||||
|
||||
void check_free(void* ptr);
|
||||
|
||||
bool hex_to_byte(const char* src, char* dst, size_t dst_size);
|
||||
|
||||
void byte_to_hex(const char* src, char* dst, size_t src_size);
|
||||
|
||||
std::string byte_to_hex(const char* src, size_t src_size);
|
||||
|
||||
} // namespace sgx
|
||||
} // namespace grpc
|
||||
|
||||
#endif // SGX_RA_TLS_UTILS_H
|
59
demos/ra_tls/prepare_and_build_package.sh
Executable file
59
demos/ra_tls/prepare_and_build_package.sh
Executable file
@ -0,0 +1,59 @@
|
||||
#!/bin/bash
|
||||
INSTALL_PREFIX=/usr/local
|
||||
apt-get update \
|
||||
&& apt-get install -y --no-install-recommends apt-utils \
|
||||
&& apt-get install -y \
|
||||
ca-certificates \
|
||||
build-essential \
|
||||
autoconf \
|
||||
libtool \
|
||||
python3-pip \
|
||||
python3-dev \
|
||||
git \
|
||||
wget \
|
||||
unzip
|
||||
|
||||
mkdir -p ${INSTALL_PREFIX} \
|
||||
&& wget -q -O cmake-linux.sh https://github.com/Kitware/CMake/releases/download/v3.19.6/cmake-3.19.6-Linux-x86_64.sh \
|
||||
&& sh cmake-linux.sh -- --skip-license --prefix=${INSTALL_PREFIX} \
|
||||
&& rm cmake-linux.sh
|
||||
|
||||
# Install cJSON
|
||||
CJSON_PATH=/cJSON
|
||||
git clone https://github.com/DaveGamble/cJSON.git ${CJSON_PATH}
|
||||
pushd ${CJSON_PATH} \
|
||||
&& make static \
|
||||
&& cp -r *.a ${INSTALL_PREFIX}/lib \
|
||||
&& mkdir -p ${INSTALL_PREFIX}/include/cjson \
|
||||
&& cp -r *.h ${INSTALL_PREFIX}/include/cjson
|
||||
popd
|
||||
|
||||
# GRPC env
|
||||
GRPC_VERSION=v1.38.x
|
||||
export GRPC_PATH=/grpc
|
||||
|
||||
# GRPC source code
|
||||
git clone https://github.com/grpc/grpc -b ${GRPC_VERSION} ${GRPC_PATH}
|
||||
pushd ${GRPC_PATH} \
|
||||
&& pip3 install --upgrade pip setuptools==44.1.1 \
|
||||
&& pip3 install -r requirements.txt \
|
||||
&& git checkout v1.38.1 \
|
||||
&& git submodule update --init
|
||||
popd
|
||||
|
||||
cp -rf grpc/common/* ${GRPC_PATH}/
|
||||
cp -rf grpc/v1.38.1/* ${GRPC_PATH}/
|
||||
|
||||
git clone https://github.com/occlum/occlum
|
||||
pushd occlum
|
||||
make submodule
|
||||
cd demos/remote_attestation/dcap/dcap_lib
|
||||
cargo build --all-targets
|
||||
cp target/debug/libdcap_quote.a /usr/local/lib/
|
||||
cp ../c_app/dcap_quote.h /usr/local/include/
|
||||
popd
|
||||
|
||||
pushd ${GRPC_PATH}/examples/cpp/ratls
|
||||
./build.sh
|
||||
popd
|
||||
|
15
demos/ra_tls/run.sh
Executable file
15
demos/ra_tls/run.sh
Executable file
@ -0,0 +1,15 @@
|
||||
#!/bin/bash
|
||||
set -ex
|
||||
|
||||
postfix=$1
|
||||
|
||||
if [ "$postfix" != "server" ] && [ "$postfix" != "client" ]; then
|
||||
echo "input error args, it should be:"
|
||||
echo "./run.sh server"
|
||||
echo "./run.sh client"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
pushd occlum_instance_$postfix
|
||||
occlum run /bin/$postfix
|
||||
popd
|
Loading…
Reference in New Issue
Block a user