mirror of
https://github.com/ibm-s390-linux/s390-tools.git
synced 2026-08-05 02:14:52 +00:00
check_hostkeydoc: Move check_hostkeydoc to scripts & deprecation warning
Move the check_hostkeydoc script to scripts. This eliminates the last file in the genprotimg directory. Additionally, add a deprecation warning to that script. Every pv tool can verify the chain itself using the pv library. Acked-by: Jan Höppner <hoeppner@linux.ibm.com> Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
This commit is contained in:
Executable
+357
@@ -0,0 +1,357 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# check_hostkeydoc - Verify an IBM Secure Execution host key document
|
||||
#
|
||||
# Sample script to verify that a host key document is genuine by
|
||||
# verifying the issuer, the validity date and the signature.
|
||||
# Optionally verify the full trust chain using a CA certificate.
|
||||
#
|
||||
# Sample invocation:
|
||||
#
|
||||
# ./check_hostkeydoc HKD1234.crt ibm-z-host-key-signing.crt -c DigiCertCA.crt -r ibm-z-host-key.crl
|
||||
#
|
||||
# Copyright IBM Corp. 2020
|
||||
#
|
||||
# s390-tools is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the MIT license. See LICENSE for details.
|
||||
|
||||
# Allocate temporary files
|
||||
ISSUER_PUBKEY_FILE=$(mktemp)
|
||||
SIGNATURE_FILE=$(mktemp)
|
||||
BODY_FILE=$(mktemp)
|
||||
ISSUER_DN_FILE=$(mktemp)
|
||||
SUBJECT_DN_FILE=$(mktemp)
|
||||
DEF_ISSUER_ARMONK_DN_FILE=$(mktemp)
|
||||
DEF_ISSUER_POUGHKEEPSIE_DN_FILE=$(mktemp)
|
||||
CANONICAL_ISSUER_DN_FILE=$(mktemp)
|
||||
CRL_SERIAL_FILE=$(mktemp)
|
||||
CRL_ISSUER_FILE=$(mktemp)
|
||||
|
||||
# Cleanup on exit
|
||||
cleanup()
|
||||
{
|
||||
rm -f "$ISSUER_PUBKEY_FILE" "$SIGNATURE_FILE" "$BODY_FILE" \
|
||||
"$ISSUER_DN_FILE" "$SUBJECT_DN_FILE" "$DEF_ISSUER_ARMONK_DN_FILE" "$DEF_ISSUER_POUGHKEEPSIE_DN_FILE" \
|
||||
"$CANONICAL_ISSUER_DN_FILE" "$CRL_SERIAL_FILE" "$CRL_ISSUER_FILE"
|
||||
}
|
||||
trap cleanup EXIT
|
||||
|
||||
# Enhanced error checking for bash
|
||||
if [ -n "${BASH}" ]; then
|
||||
# shellcheck disable=SC3040
|
||||
set -o posix
|
||||
# shellcheck disable=SC3040
|
||||
set -o pipefail
|
||||
# shellcheck disable=SC3040
|
||||
set -o nounset
|
||||
fi
|
||||
set -e
|
||||
|
||||
# Usage
|
||||
usage()
|
||||
{
|
||||
cat <<-EOF
|
||||
Usage: $(basename "$1") [-d] [-c CA-cert] [-r CRL] host-key-doc signing-key-cert
|
||||
|
||||
Verify an IBM Secure Execution host key document against a signing key. Use for
|
||||
resolving issues only. Use the built-in functions from pvimg, pvsecret, or
|
||||
pvattest directly to verify the host-key documents. This script should only be
|
||||
used as a last resort for when the distribution provided binaries have
|
||||
unresolved issues regarding the host-key verification. In that case ensure the
|
||||
latest version of this script is used.
|
||||
Find the latest version here https://github.com/ibm-s390-linux/s390-tools
|
||||
|
||||
Options:
|
||||
-d disable default issuer check of host-key-doc
|
||||
-c CA-cert trusted CA certificate
|
||||
-r CRL list of revoked host-key-docs
|
||||
|
||||
Note that in order to have the full trust chain verified
|
||||
it is necessary to provide the issuing CA's certificate.
|
||||
The default issuer check may be disabled if a non-default
|
||||
signing key certificate needs to be verified against the
|
||||
CA certificate.
|
||||
|
||||
EOF
|
||||
}
|
||||
|
||||
curl_crl_by_crt()
|
||||
{
|
||||
CRT="$1"
|
||||
OFFSET=$2
|
||||
CRL_URL="$(openssl x509 -noout -text -in "$CRT" \
|
||||
|grep 'URI:http.*\.crl' | sed -n "$OFFSET"p | xargs)"
|
||||
|
||||
# no CRL at this offset
|
||||
if [ -z "$CRL_URL" ];
|
||||
then
|
||||
return 5
|
||||
fi
|
||||
curl --silent --output "${CRL_ISSUER_FILE}" -- "${CRL_URL#URI:}"
|
||||
}
|
||||
|
||||
check_verify_chain()
|
||||
{
|
||||
# Verify certificate chain in case a CA certificate file/bundle
|
||||
# was specified on the command line.
|
||||
if [ -z "$2" ]; then
|
||||
cat >&2 <<-EOF
|
||||
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
No CA certificate specified! Skipping trust chain verification.
|
||||
Make sure that '$1' is a valid certificate.
|
||||
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
EOF
|
||||
else
|
||||
openssl verify -crl_download -crl_check "$2" || exit 1
|
||||
|
||||
if ! stderr=$(openssl verify -crl_download -crl_check -untrusted "$2" "$1" 3>&2 2>&1 1>&3 3>&-); then
|
||||
if ! printf '%s' "${stderr}" | grep -q 'max resp len exceeded'; then
|
||||
printf '%s\n' "${stderr}"
|
||||
exit 1
|
||||
fi
|
||||
# Turn off exit-on-error locally to be able to retry on invalid URIs
|
||||
set +e
|
||||
off=0;
|
||||
# Search for a CRL in the CRT. If the first link does not work try
|
||||
# again with the next one until either no more URIS are available or a
|
||||
# CRL was found.
|
||||
while [ $off -le 10 ]; do
|
||||
i=$(( i + 1 ))
|
||||
|
||||
CRL=curl_crl_by_crt "$3" $i
|
||||
SUCCESS=$?
|
||||
# No more CRLS available
|
||||
if [ $SUCCESS -eq 5 ]; then
|
||||
exit 1
|
||||
fi
|
||||
# URI was invalid/not reachable
|
||||
if [ $SUCCESS -ne 0 ]; then
|
||||
continue;
|
||||
fi
|
||||
# Found one
|
||||
break
|
||||
done
|
||||
openssl verify -CRLfile "${CRL_ISSUER_FILE}" -crl_check -untrusted "$2" "$1" || exit 1
|
||||
fi
|
||||
set -e
|
||||
fi
|
||||
}
|
||||
|
||||
extract_pubkey()
|
||||
{
|
||||
openssl x509 -in "$1" -pubkey -noout >"$2"
|
||||
}
|
||||
|
||||
extract_signature()
|
||||
{
|
||||
# Assuming that the last field is the signature
|
||||
SIGOFFSET=$(openssl asn1parse -in "$1" | tail -1 | cut -d : -f 1)
|
||||
|
||||
openssl asn1parse -in "$1" -out "$2" -strparse "$SIGOFFSET" -noout
|
||||
}
|
||||
|
||||
extract_body()
|
||||
{
|
||||
# Assuming that the first field is the full cert body
|
||||
SIGOFFSET=$(openssl asn1parse -in "$1" | head -2 | tail -1 | cut -d : -f 1)
|
||||
|
||||
openssl asn1parse -in "$1" -out "$2" -strparse "$SIGOFFSET" -noout
|
||||
}
|
||||
|
||||
verify_signature()
|
||||
{
|
||||
# Assuming that the signature algorithm is SHA512 with RSA
|
||||
openssl sha512 -verify "$1" -signature "$2" "$3"
|
||||
}
|
||||
|
||||
canonical_dn()
|
||||
{
|
||||
OBJTYPE=$1
|
||||
OBJ=$2
|
||||
DNTYPE=$3
|
||||
OUTPUT=$4
|
||||
|
||||
openssl "$OBJTYPE" -in "$OBJ" -"$DNTYPE" -noout -nameopt multiline |
|
||||
LC_ALL=C sort | grep -v "$DNTYPE"= >"$OUTPUT"
|
||||
}
|
||||
|
||||
default_issuer_armonk()
|
||||
{
|
||||
cat <<-EOF
|
||||
commonName = International Business Machines Corporation
|
||||
countryName = US
|
||||
localityName = Armonk
|
||||
organizationName = International Business Machines Corporation
|
||||
organizationalUnitName = Key Signing Service
|
||||
stateOrProvinceName = New York
|
||||
EOF
|
||||
}
|
||||
|
||||
default_issuer_pougkeepsie()
|
||||
{
|
||||
cat <<-EOF
|
||||
commonName = International Business Machines Corporation
|
||||
countryName = US
|
||||
localityName = Poughkeepsie
|
||||
organizationName = International Business Machines Corporation
|
||||
organizationalUnitName = Key Signing Service
|
||||
stateOrProvinceName = New York
|
||||
EOF
|
||||
}
|
||||
|
||||
# As organizationalUnitName can have an arbitrary prefix but must
|
||||
# end with "Key Signing Service" let's normalize the OU name by
|
||||
# stripping off the prefix
|
||||
verify_default_issuer()
|
||||
{
|
||||
default_issuer_pougkeepsie >"$DEF_ISSUER_POUGHKEEPSIE_DN_FILE"
|
||||
default_issuer_armonk >"$DEF_ISSUER_ARMONK_DN_FILE"
|
||||
|
||||
sed "s/\(^[ ]*organizationalUnitName[ ]*=[ ]*\).*\(Key Signing Service$\)/\1\2/" \
|
||||
"$ISSUER_DN_FILE" >"$CANONICAL_ISSUER_DN_FILE"
|
||||
|
||||
if ! {
|
||||
diff "$CANONICAL_ISSUER_DN_FILE" "$DEF_ISSUER_POUGHKEEPSIE_DN_FILE" ||
|
||||
diff "$CANONICAL_ISSUER_DN_FILE" "$DEF_ISSUER_ARMONK_DN_FILE"
|
||||
} >/dev/null 2>&1; then
|
||||
echo Incorrect default issuer >&2 && exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
verify_issuer_files()
|
||||
{
|
||||
if [ "$1" -eq 1 ]; then
|
||||
verify_default_issuer
|
||||
fi
|
||||
}
|
||||
|
||||
cert_time()
|
||||
{
|
||||
DATE=$(openssl x509 -in "$1" -"$2" -noout | sed "s/^.*=//")
|
||||
|
||||
date -d "$DATE" +%s
|
||||
}
|
||||
|
||||
crl_time()
|
||||
{
|
||||
DATE=$(openssl crl -in "$1" -"$2" -noout | sed "s/^.*=//")
|
||||
|
||||
date -d "$DATE" +%s
|
||||
}
|
||||
|
||||
verify_dates()
|
||||
{
|
||||
START="$1"
|
||||
END="$2"
|
||||
MSG="${3:-Certificate}"
|
||||
NOW=$(date +%s)
|
||||
|
||||
if [ "$START" -le "$NOW" ] && [ "$NOW" -le "$END" ]; then
|
||||
echo "${MSG} dates are OK"
|
||||
else
|
||||
echo "${MSG} date verification failed" >&2 && exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
crl_serials()
|
||||
{
|
||||
openssl crl -in "$1" -text -noout |
|
||||
grep "Serial Number" >"$CRL_SERIAL_FILE"
|
||||
}
|
||||
|
||||
check_serial()
|
||||
{
|
||||
CERT_SERIAL=$(openssl x509 -in "$1" -noout -serial | cut -d = -f 2)
|
||||
|
||||
grep -q "$CERT_SERIAL" "$CRL_SERIAL_FILE"
|
||||
}
|
||||
|
||||
check_file()
|
||||
{
|
||||
[ -e "$1" ] ||
|
||||
(echo "File '$1' not found" >&2 && exit 1)
|
||||
}
|
||||
|
||||
# check args
|
||||
CRL_FILE=
|
||||
CA_FILE=
|
||||
CHECK_DEFAULT_ISSUER=1
|
||||
|
||||
while getopts 'dr:c:h' opt; do
|
||||
case $opt in
|
||||
d) CHECK_DEFAULT_ISSUER=0 ;;
|
||||
r) CRL_FILE=$OPTARG ;;
|
||||
c) CA_FILE=$OPTARG ;;
|
||||
h)
|
||||
usage "$0"
|
||||
exit 0
|
||||
;;
|
||||
?)
|
||||
usage "$0"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
shift "$((OPTIND - 1))"
|
||||
|
||||
if [ $# -ne 2 ]; then
|
||||
usage "$0" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
HKD_FILE=$1
|
||||
HKSK_FILE=$2
|
||||
|
||||
printf "DEPRECATED SCRIPT. Use pvimg, pvattest, or pvsecret directly.\n"
|
||||
printf "This script is intended for resolving issues only.\n"
|
||||
printf "This script may be inaccessible in the future.\n"
|
||||
|
||||
# Check whether all specified files exist
|
||||
check_file "$HKD_FILE"
|
||||
check_file "$HKSK_FILE"
|
||||
# CA and CRL are optional arguments
|
||||
[ -n "$CA_FILE" ] && check_file "$CA_FILE"
|
||||
[ -n "$CRL_FILE" ] && check_file "$CRL_FILE"
|
||||
|
||||
# Check trust chain
|
||||
check_verify_chain "$HKSK_FILE" "$CA_FILE" "$HKSK_FILE"
|
||||
|
||||
# Verify host key document signature
|
||||
printf "Checking host key document signature: "
|
||||
extract_pubkey "$HKSK_FILE" "$ISSUER_PUBKEY_FILE" &&
|
||||
extract_signature "$HKD_FILE" "$SIGNATURE_FILE" &&
|
||||
extract_body "$HKD_FILE" "$BODY_FILE" &&
|
||||
verify_signature "$ISSUER_PUBKEY_FILE" "$SIGNATURE_FILE" "$BODY_FILE" ||
|
||||
exit 1
|
||||
|
||||
# Verify the issuer
|
||||
canonical_dn x509 "$HKD_FILE" issuer "$ISSUER_DN_FILE"
|
||||
canonical_dn x509 "$HKSK_FILE" subject "$SUBJECT_DN_FILE"
|
||||
verify_issuer_files $CHECK_DEFAULT_ISSUER
|
||||
|
||||
# Verify dates
|
||||
verify_dates "$(cert_time "$HKD_FILE" startdate)" "$(cert_time "$HKD_FILE" enddate)"
|
||||
|
||||
# Check CRL if specified
|
||||
if [ -n "$CRL_FILE" ]; then
|
||||
printf "Checking CRL signature: "
|
||||
extract_signature "$CRL_FILE" "$SIGNATURE_FILE" &&
|
||||
extract_body "$CRL_FILE" "$BODY_FILE" &&
|
||||
verify_signature "$ISSUER_PUBKEY_FILE" "$SIGNATURE_FILE" "$BODY_FILE" ||
|
||||
exit 1
|
||||
|
||||
printf "CRL "
|
||||
canonical_dn crl "$CRL_FILE" issuer "$ISSUER_DN_FILE"
|
||||
canonical_dn x509 "$HKSK_FILE" subject "$SUBJECT_DN_FILE"
|
||||
verify_issuer_files $CHECK_DEFAULT_ISSUER
|
||||
|
||||
verify_dates "$(crl_time "$CRL_FILE" lastupdate)" "$(crl_time "$CRL_FILE" nextupdate)" 'CRL'
|
||||
|
||||
crl_serials "$CRL_FILE"
|
||||
check_serial "$HKD_FILE" &&
|
||||
echo "Certificate is revoked, do not use it anymore!" >&2 &&
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# We made it
|
||||
echo All checks requested for \'"$HKD_FILE"\' were successful
|
||||
Reference in New Issue
Block a user