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