зеркало из https://github.com/microsoft/CCF.git
155 строки
4.8 KiB
Bash
Executable File
155 строки
4.8 KiB
Bash
Executable File
#!/bin/bash
|
|
# Copyright (c) Microsoft Corporation. All rights reserved.
|
|
# Licensed under the Apache 2.0 License.
|
|
|
|
set -e
|
|
|
|
# Loop through all arguments and find url, request data, command, private key and user cert
|
|
# NB: For simplicity, assume url is the first argument or preceded by --url. curl is slightly more permissive
|
|
next_is_url=false
|
|
next_is_data=false
|
|
next_is_command=false
|
|
next_is_privk=false
|
|
next_is_cert=false
|
|
next_is_signing_privk=false
|
|
next_is_signing_cert=false
|
|
|
|
url=$1
|
|
command="post"
|
|
is_print_digest_to_sign=false
|
|
|
|
fwd_args=()
|
|
for item in "$@" ; do
|
|
if [ "$next_is_url" == true ]; then
|
|
url=$item
|
|
next_is_url=false
|
|
fi
|
|
if [ "$next_is_data" == true ]; then
|
|
request=$item
|
|
next_is_data=false
|
|
fi
|
|
if [ "$next_is_command" == true ]; then
|
|
command=$item
|
|
next_is_command=false
|
|
fi
|
|
if [ "$next_is_privk" == true ]; then
|
|
privk=$item
|
|
next_is_privk=false
|
|
fi
|
|
if [ "$next_is_cert" == true ]; then
|
|
cert=$item
|
|
next_is_cert=false
|
|
fi
|
|
if [ "$next_is_signing_privk" == true ]; then
|
|
signing_privk=$item
|
|
next_is_signing_privk=false
|
|
continue
|
|
fi
|
|
if [ "$next_is_signing_cert" == true ]; then
|
|
signing_cert=$item
|
|
next_is_signing_cert=false
|
|
continue
|
|
fi
|
|
if [ "$item" == "--url" ]; then
|
|
next_is_url=true
|
|
fi
|
|
if [ "$item" == "-d" ] || [ "$item" == "--data" ] || [ "$item" == "--data-binary" ]; then
|
|
next_is_data=true
|
|
fi
|
|
if [ "$item" == "-X" ] || [ "$item" == "--request" ]; then
|
|
next_is_command=true
|
|
fi
|
|
if [ "$item" == "--key" ]; then
|
|
next_is_privk=true
|
|
fi
|
|
if [ "$item" == "--cert" ]; then
|
|
next_is_cert=true
|
|
fi
|
|
if [ "$item" == "--signing-key" ]; then
|
|
next_is_signing_privk=true
|
|
continue
|
|
fi
|
|
if [ "$item" == "--signing-cert" ]; then
|
|
next_is_signing_cert=true
|
|
continue
|
|
fi
|
|
if [ "$item" == "--print-digest-to-sign" ]; then
|
|
is_print_digest_to_sign=true
|
|
continue
|
|
fi
|
|
fwd_args+=("$item")
|
|
done
|
|
|
|
has_required_args=true
|
|
if [ -z "$signing_cert" ]; then
|
|
echo "Error: No signing certificate found in arguments (--signing-cert)."
|
|
if [ -n "$cert" ]; then
|
|
echo " Did you mean: --signing-cert $cert?"
|
|
fi
|
|
has_required_args=false
|
|
fi
|
|
if [ -z "$signing_privk" ] && [ "$is_print_digest_to_sign" == false ]; then
|
|
echo "Error: No signing private key found in arguments (--signing-key)."
|
|
if [ -n "$privk" ]; then
|
|
echo " Did you mean: --signing-key $privk?"
|
|
fi
|
|
has_required_args=false
|
|
fi
|
|
|
|
if [ "$has_required_args" == false ]; then
|
|
exit 1
|
|
fi
|
|
|
|
additional_curl_args=()
|
|
|
|
if [ -z "$request" ]; then
|
|
# If no request is provided, use empty body (content-length and digest calculation proceed as normal)
|
|
request=""
|
|
additional_curl_args+=(-H "content-length: 0")
|
|
fi
|
|
|
|
# If the first letter of the request is @, consider it a filename
|
|
if [ "$(echo "$request" | cut -c1)" == "@" ]; then
|
|
request_path="${request:1}"
|
|
req_digest=$(openssl dgst -sha256 -binary "$request_path" | openssl base64)
|
|
content_length=$(wc -c "$request_path" | awk '{print $1}' )
|
|
else
|
|
req_digest=$(printf "%s" "$request" | openssl dgst -sha256 -binary | openssl base64)
|
|
content_length=${#request}
|
|
fi
|
|
|
|
# Trim URL to just the ":path" pseudo-header
|
|
# https://tools.ietf.org/html/rfc7540#section-8.1.2.3
|
|
url=${url#*//} # Remove protocol
|
|
url=/${url#*/} # Remove domain name, restore leading slash
|
|
url=${url%\#*} # Remove fragment
|
|
|
|
# Construct string to sign
|
|
newline=$'\n'
|
|
string_to_sign="(request-target): ${command,,} ${url}${newline}digest: SHA-256=${req_digest}${newline}content-length: ${content_length}"
|
|
|
|
# https://tools.ietf.org/html/draft-cavage-http-signatures-12#appendix-E.2
|
|
signature_algorithm="hs2019"
|
|
|
|
# Compute key ID, as the SHA-256 fingerprint of the signing certificate
|
|
key_id=$(openssl x509 -in "$signing_cert" -noout -fingerprint -sha256 | cut -d "=" -f 2 | sed 's/://g' | awk '{print tolower($0)}')
|
|
|
|
if [ "$is_print_digest_to_sign" == true ]; then
|
|
hash_to_sign=$(echo -n "$string_to_sign" | openssl dgst -binary -sha384 | openssl base64 -A)
|
|
echo "Hash to sign: $hash_to_sign"
|
|
echo "Request headers:"
|
|
echo "-H 'Digest: SHA-256=$req_digest'"
|
|
echo "-H 'Authorization: Signature keyId=\"$key_id\",algorithm=\"$signature_algorithm\",headers=\"(request-target) digest content-length\",signature=\"<insert_base64_signature_here>\"'"
|
|
echo "${additional_curl_args[@]}"
|
|
exit 0
|
|
fi
|
|
|
|
# Compute signature
|
|
signed_raw=$(echo -n "$string_to_sign" | openssl dgst -sha384 -sign "$signing_privk" | openssl base64 -A)
|
|
|
|
curl \
|
|
-H "Digest: SHA-256=$req_digest" \
|
|
-H "Authorization: Signature keyId=\"$key_id\",algorithm=\"$signature_algorithm\",headers=\"(request-target) digest content-length\",signature=\"$signed_raw\"" \
|
|
"${additional_curl_args[@]}" \
|
|
"${fwd_args[@]}"
|