Skip to content

Commit

Permalink
[release/5.x] Cherry pick: Fixup verify quote script for load balancer (
Browse files Browse the repository at this point in the history
#6454) (#6455)

Co-authored-by: Max <maxtropets@microsoft.com>
  • Loading branch information
CCF [bot] and maxtropets authored Aug 27, 2024
1 parent bb25588 commit eba4a25
Showing 1 changed file with 75 additions and 51 deletions.
126 changes: 75 additions & 51 deletions python/utils/verify_quote.sh
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,10 @@

set -e

quote_file_name="quote.bin"
endorsements_file_name="endorsements.bin"
open_enclave_path=${OPEN_ENCLAVE_PATH:-"/opt/openenclave"}
default_port=443

function usage()
{
function usage() {
echo "Usage:"
echo " $0 https://<node-address> [--mrenclave <mrenclave_hex>] [CURL_OPTIONS]"
echo "Verify target node's remote attestation quote."
Expand All @@ -33,20 +30,21 @@ shift

# Add default port number if not included (required by openssl s_client)
if ! [[ $node_address =~ .*:[0-9]+$ ]]; then
node_address="${node_address}:${default_port}"
node_address="${node_address}:${default_port}"
fi

while [ "$1" != "" ]; do
case $1 in
-h|-\?|--help)
usage
exit 0
;;
--mrenclave)
trusted_mrenclaves=("$2")
;;
*)
break
-h | -\? | --help)
usage
exit 0
;;
--mrenclave)
trusted_mrenclaves=("$2")
;;
*)
break
;;
esac
shift
shift
Expand All @@ -65,55 +63,81 @@ fi
# Temporary directory for storing retrieved quote
tmp_dir=$(mktemp -d)
function cleanup() {
rm -rf "${tmp_dir}"
rm -rf "${tmp_dir}"
}
trap cleanup EXIT

curl_output=$(curl -sS --fail -X GET "${node_address}"/node/quotes/self "${@}")
curl_output=$(curl -sS --fail -X GET "${node_address}"/node/quotes "${@}")

# Query quotes for ALL nodes to support talking to load-balancer with no session tracking, resulting into talking to different nodes during script execution.
# Save quotes in format
# tmp_dir/node_1_id.endorsements
# tmp_dir/node_1_id.quote
# ...
# tmp_dir/node_N_id.endorsements
# tmp_dir/node_N_id.quote
echo "${curl_output}" | jq -r '.quotes[] | .node_id as $id | .endorsements as $endorsements | .raw as $quote | "\($id).endorsements \($endorsements)\n\($id).quote \($quote)"' | while read -r line; do
filename=$(echo "${line}" | awk '{print $1}')
content=$(echo "${line}" | awk '{for (i=2; i<=NF; i++) printf $i;}')
echo "${content}" | base64 --decode >"${tmp_dir}/${filename}"
done

echo "${curl_output}" >out.txt

echo "${curl_output}" | jq -r .raw | base64 --decode > "${tmp_dir}/${quote_file_name}"
echo "${curl_output}" | jq -r .endorsements | base64 --decode > "${tmp_dir}/${endorsements_file_name}"
# At least one quote has to be there.
quotes_count=$(find "${tmp_dir}" -maxdepth 1 -type f -name "*.quote" | wc -l)
if [ "$quotes_count" -eq 0 ]; then
echo "Error: No quotes find"
exit 1
fi

if [ ! -s "${tmp_dir}/${quote_file_name}" ]; then
echo "Error: Node quote is empty. Virtual mode does not support SGX quotes."
# All quotes must be non-empty.
empty_quotes=$(find "${tmp_dir}" -maxdepth 1 -type f -name "*.quote" -empty)
if [ -n "$empty_quotes" ]; then
echo "Error: Empty quote found. Virtual mode does not support SGX quotes."
exit 1
fi

echo "Node quote successfully retrieved."
echo "Nodes quotes successfully retrieved."

oeverify_output=$("${open_enclave_path}"/bin/oeverify -r "${tmp_dir}"/"${quote_file_name}" -e "${tmp_dir}"/"${endorsements_file_name}")
nodes=()
for file in "${tmp_dir}"/*.quote; do
base_name=$(basename "$file" .quote)
nodes+=("$base_name")
done

for node in "${nodes[@]}"; do
quote_file_name="${node}.quote"
endorsements_file_name="${node}.endorsements"

# Extract SGX report data
oeverify_report_data=$(echo "${oeverify_output}" | grep "sgx_report_data" | cut -d ":" -f 2)
# Extract hex sha-256 (64 char) from report data (128 char)
extracted_report_data=$(echo "${oeverify_report_data#*0x}" | head -c 64)
oeverify_output=$("${open_enclave_path}"/bin/oeverify -r "${tmp_dir}"/"${quote_file_name}" -e "${tmp_dir}"/"${endorsements_file_name}")

# Remove protocol and compute hash of target node's public key (DER)
stripped_node_address=${node_address#*//}
node_pubk_hash=$(echo | openssl s_client -showcerts -connect "${stripped_node_address}" 2>/dev/null | openssl x509 -pubkey -noout | openssl ec -pubin -outform der 2>/dev/null | sha256sum | awk '{ print $1 }')
# Extract SGX report data
oeverify_report_data=$(echo "${oeverify_output}" | grep "sgx_report_data" | cut -d ":" -f 2)
# Extract hex sha-256 (64 char) from report data (128 char)
extracted_report_data=$(echo "${oeverify_report_data#*0x}" | head -c 64)

# Extract mrenclave
is_mrenclave_valid=false
oeverify_mrenclave=$(echo "${oeverify_output}" | grep "unique_id" | cut -d ":" -f 2)
extracted_mrenclave="${oeverify_mrenclave#*0x}"
for mrenclave in "${trusted_mrenclaves[@]}"; do
if [ "${mrenclave}" == "${extracted_mrenclave}" ]; then
is_mrenclave_valid=true
# Remove protocol and compute hash of target node's public key (DER)
stripped_node_address=${node_address#*//}
node_pubk_hash=$(echo | openssl s_client -showcerts -connect "${stripped_node_address}" 2>/dev/null | openssl x509 -pubkey -noout | openssl ec -pubin -outform der 2>/dev/null | sha256sum | awk '{ print $1 }')

# Extract mrenclave
is_mrenclave_valid=false
oeverify_mrenclave=$(echo "${oeverify_output}" | grep "unique_id" | cut -d ":" -f 2)
extracted_mrenclave="${oeverify_mrenclave#*0x}"
for mrenclave in "${trusted_mrenclaves[@]}"; do
if [ "${mrenclave}" == "${extracted_mrenclave}" ]; then
is_mrenclave_valid=true
fi
done

if [ "${extracted_report_data}" == "${node_pubk_hash}" ] && [ "${is_mrenclave_valid}" == true ]; then
echo "mrenclave: \"${extracted_mrenclave}\""
echo "Quote verification successful."
exit 0
fi

done

if [ "${extracted_report_data}" != "${node_pubk_hash}" ]; then
echo "Error: quote verification failed."
echo "Reported quote data does not match node certificate public key:"
echo "\"${extracted_report_data}\" != \"${node_pubk_hash}\""
exit 1
elif [ "${is_mrenclave_valid}" != true ]; then
echo "Error: quote verification failed."
echo "Reported mrenclave \"${extracted_mrenclave}\" is not trusted. List of trusted mrenclave:"
echo "${trusted_mrenclaves[@]}"
exit 1
else
echo "mrenclave: \"${extracted_mrenclave}\""
echo "Quote verification successful."
exit 0
fi
echo "Error: quote verification failed. No attested node found"
exit 1

0 comments on commit eba4a25

Please sign in to comment.