0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023 set -u -e -o pipefail
0024
0025 CERT="${1:-}"
0026 BASENAME="$(basename -- "${BASH_SOURCE[0]}")"
0027
0028 if [ $
0029 echo "usage: ${BASENAME} <certificate>" >&2
0030 exit 1
0031 fi
0032
0033
0034
0035 if ! PEM="$(openssl x509 -inform DER -in "${CERT}" 2>/dev/null || openssl x509 -in "${CERT}")"; then
0036 echo "ERROR: Failed to parse certificate" >&2
0037 exit 1
0038 fi
0039
0040
0041
0042
0043
0044
0045
0046
0047
0048
0049
0050
0051 RANGE_AND_DIGEST_RE='
0052 2s/^\s*\([0-9]\+\):d=\s*[0-9]\+\s\+hl=\s*[0-9]\+\s\+l=\s*\([0-9]\+\)\s\+cons:\s*SEQUENCE\s*$/\1 \2/p;
0053 7s/^\s*[0-9]\+:d=\s*[0-9]\+\s\+hl=\s*[0-9]\+\s\+l=\s*[0-9]\+\s\+prim:\s*OBJECT\s*:\(.*\)$/\1/p;
0054 '
0055
0056 RANGE_AND_DIGEST=($(echo "${PEM}" | \
0057 openssl asn1parse -in - | \
0058 sed -n -e "${RANGE_AND_DIGEST_RE}"))
0059
0060 if [ "${#RANGE_AND_DIGEST[@]}" != 3 ]; then
0061 echo "ERROR: Failed to parse TBSCertificate." >&2
0062 exit 1
0063 fi
0064
0065 OFFSET="${RANGE_AND_DIGEST[0]}"
0066 END="$(( OFFSET + RANGE_AND_DIGEST[1] ))"
0067 DIGEST="${RANGE_AND_DIGEST[2]}"
0068
0069
0070
0071 DIGEST_MATCH=""
0072 while read -r DIGEST_ITEM; do
0073 if [ -z "${DIGEST_ITEM}" ]; then
0074 break
0075 fi
0076 if echo "${DIGEST}" | grep -qiF "${DIGEST_ITEM}"; then
0077 DIGEST_MATCH="${DIGEST_ITEM}"
0078 break
0079 fi
0080 done < <(openssl list -digest-commands | tr ' ' '\n' | sort -ur)
0081
0082 if [ -z "${DIGEST_MATCH}" ]; then
0083 echo "ERROR: Unknown digest algorithm: ${DIGEST}" >&2
0084 exit 1
0085 fi
0086
0087 echo "${PEM}" | \
0088 openssl x509 -in - -outform DER | \
0089 dd "bs=1" "skip=${OFFSET}" "count=${END}" "status=none" | \
0090 openssl dgst "-${DIGEST_MATCH}" - | \
0091 awk '{printf "tbs:" $2}'