Project

General

Profile

Download (10.5 KB) Statistics
| Branch: | Tag: | Revision:
#!/usr/bin/env bash

# Define colors uses for status output
RED=$(tput setaf 1 2> /dev/null)
GREEN=$(tput setaf 2 2> /dev/null)
RESET=$(tput sgr0 2> /dev/null)

CABUNDLE_MAX_ISSUERS=32

# Branding
BRANDING_FILE=/usr/share/foreman-installer/katello-certs-check-branding
if [[ -f "${BRANDING_FILE}" ]]; then
source "${BRANDING_FILE}"
fi
PROJECT=${PROJECT:-Katello}
SERVER_SCENARIO=${SERVER_SCENARIO:-katello}
INSTALLER=${INSTALLER:-foreman-installer}
CERTS_TOOL=${CERTS_TOOL:-foreman-proxy-certs-generate}
SERVER_TARGET=${SERVER_TARGET:-foreman}
PROXY_TARGET=${PROXY_TARGET:-foreman-proxy}
PROXY_VAR=${PROXY_VAR:-FOREMAN_PROXY}

function usage () {
cat <<HELP >&2
Verifies, that custom SSL certificate files are usable
as part of the ${PROJECT} installation. When passing filenames use absolute paths.

usage: $0 -t [${SERVER_TARGET}|${PROXY_TARGET}] -c CERT_FILE -k KEY_FILE -b CA_BUNDLE_FILE
HELP
}

while getopts "t:c:k:b:" opt; do
case $opt in
t)
TARGET=$(echo $OPTARG|tr '[:upper:]' '[:lower:]')
;;
c)
CERT_FILE="$(readlink -f $OPTARG)"
;;
k)
KEY_FILE="$(readlink -f $OPTARG)"
;;
b)
CA_BUNDLE_FILE="$(readlink -f $OPTARG)"
;;
h)
usage
exit 0
;;
?)
usage
exit 1
;;
esac
done

EXIT_CODE=0

if [ -z "$CERT_FILE" -o -z "$KEY_FILE" -o -z "$CA_BUNDLE_FILE" ]; then
echo 'One of the required parameters is missing.' >&2
usage
exit 1
fi

function error () {
echo -e "\n${RED}[FAIL]${RESET}\n"
CURRENT_EXIT_CODE=$1
EXIT_CODE=$((EXIT_CODE|CURRENT_EXIT_CODE))
echo -e $2 >&2
}

function success () {
echo -e "\n${GREEN}[OK]${RESET}\n"
}

function check-files-exist() {
if [[ ! -f "$CA_BUNDLE_FILE" ]] || [[ ! -f "$CERT_FILE" ]] || [[ ! -f "$KEY_FILE" ]] ; then
echo "One of '${CERT_FILE}', '${KEY_FILE}' or '${CA_BUNDLE_FILE}' not found" >&2
exit 1
fi
}

function check-server-cert-encoding () {
printf 'Checking server certificate encoding: '
openssl x509 -inform pem -in $CERT_FILE -noout -text &> /dev/null
if [[ $? == "0" ]]; then
success
else
openssl x509 -inform der -in $CERT_FILE -noout -text &> /dev/null
if [[ $? == "0" ]]; then
error 8 "The server certificate is in DER encoding, which is incompatible.\n\n"
printf "Run the following command to convert the certificate to PEM encoding,\n"
printf "then test it again.\n"
printf "# openssl x509 -in %s -outform pem -out %s.pem\n\n" $(basename $CERT_FILE) $(basename $CERT_FILE)
printf "When you run $(basename $0) again, use file\n"
printf "%s.pem for the server certificate.\n\n" $(basename $CERT_FILE)
else
error 9 "The encoding of the server certificate is unknown."
fi
fi
}

function check-expiration () {
CERT_EXP=$(openssl x509 -noout -enddate -in $CERT_FILE | sed -e 's/notAfter=//' | awk '{$NF="";}1')
CA_EXP=$(openssl x509 -noout -enddate -in $CA_BUNDLE_FILE | sed -e 's/notAfter=//' | awk '{$NF="";}1')
DATE_TODAY=$(date -u +%Y%m%d%H%M%S)
CERT_DATE=$(date -d"${CERT_EXP}" +%Y%m%d%H%M%S)
CA_DATE=$(date -d"${CA_EXP}" +%Y%m%d%H%M%S)
printf "Checking expiration of certificate: "
if [[ $DATE_TODAY -gt $CERT_DATE ]]; then
error 6 "The certificate \"$CERT_FILE\" has already expired on: $CERT_EXP"
else
success
fi
printf "Checking expiration of CA bundle: "
if [[ $DATE_TODAY -gt $CA_DATE ]]; then
error 7 "The CA bundle \"$CA_BUNDLE_FILE\" has already expired on: $CA_EXP"
else
success
fi
}

function check-cert-ca-flag () {
printf "Checking if server certificate has CA:TRUE flag "
openssl x509 -in $CERT_FILE -noout -text | grep -q CA:TRUE
if [[ $? -ne 0 ]]; then
success
else
error 7 "The server certificate is marked as a CA and can not be used."
fi
}

function check-passphrase () {
printf "Checking for private key passphrase: "
CHECK=$(cat $KEY_FILE | grep ENCRYPTED)
if [[ $? == "0" ]]; then
error 2 "The $KEY_FILE contains a passphrase, remove the key's passphrase by doing:
\nmv $KEY_FILE $KEY_FILE.old
\nopenssl rsa -in $KEY_FILE.old -out $KEY_FILE"
exit 1
else
success
fi
}

function check-priv-key () {
printf "Checking to see if the private key matches the certificate: "
CERT_MOD=$(openssl x509 -noout -modulus -in $CERT_FILE)
KEY_MOD=$(openssl rsa -noout -modulus -in $KEY_FILE)
if [[ "$CERT_MOD" != "$KEY_MOD" ]]; then
error 2 "The $KEY_FILE does not match the $CERT_FILE"
else
success
fi
}

function check-ca-bundle () {
printf "Checking CA bundle against the certificate file: "
ERROR_PATTERN="error [0-9]+ at"
CHECK=$(openssl verify -CAfile $CA_BUNDLE_FILE -purpose sslserver -verbose $CERT_FILE 2>&1)
CHECK_STATUS=$?

if [[ $CHECK_STATUS != "0" || $CHECK =~ $ERROR_PATTERN ]]; then
error 4 "The $CA_BUNDLE_FILE does not verify the $CERT_FILE"
echo -e "${CHECK/OK/}\n"
else
success
fi
}

function check-ca-bundle-size () {
printf "Checking CA bundle size: "
CHECK=$(grep -c "^--*BEGIN" $CA_BUNDLE_FILE)
printf $CHECK
if [[ $CHECK -lt $CABUNDLE_MAX_ISSUERS ]]; then
success
else
CERRTISSUER=$(openssl x509 -noout -in $CERT_FILE -issuer 2>&1)
error 10 "The CA bundle counts $CHECK issuers. Please trim your CA bundle and include only the certs relevant to your cert file"
echo $CERTISSUER
echo
fi
}

function check-ca-bundle-trust-rules () {
printf "Checking if CA bundle has trust rules: "
CHECK=$(grep 'BEGIN TRUSTED CERTIFICATE' $CA_BUNDLE_FILE| wc -l)
printf $CHECK
if [[ $CHECK -lt 1 ]]; then
success
else
error 10 "The CA bundle contains $CHECK certificate(s) with trust rules. This may create problems for older systems to trust the bundle. Please, recreate the bundle using certificates without trust rules"
echo
fi
}

function check-cert-san () {
printf "Checking Subject Alt Name on certificate "
DNS_LIST=$(openssl x509 -noout -text -in $CERT_FILE | grep DNS:)
if [[ $? == "0" ]]; then
success
printf "Checking if any Subject Alt Name on certificate matches the Subject CN"
SUBJECT_CN=$(openssl x509 -in $CERT_FILE -noout -subject -nameopt multiline|grep commonName|cut -d '=' -f 2|tr -d ' ')
for DNS in ${DNS_LIST}
do
DNS_VALUE="$( echo ${DNS//DNS:/} | tr -d ',')"
if [ $SUBJECT_CN == $DNS_VALUE ]
then
success
return
fi
done
error
echo "The $CERT_FILE does not have a Subject Alt Name matching the Subject CN"
else
error
cat <<Explanation
$CERT_FILE does not contain a Subject Alt Name. Common Name is deprecated, use Subject Alt Name instead.
See: https://tools.ietf.org/html/rfc2818#section-3.1

Explanation
fi
}

function check-cert-usage-key-encipherment () {
printf "Checking Key Usage extension on certificate for Key Encipherment "
CHECK=$(openssl x509 -noout -text -in $CERT_FILE | grep -A1 'X509v3 Key Usage:' | grep 'Key Encipherment')
if [[ $? == "0" ]]; then
success
else
error 4 "The $CERT_FILE does not allow for the 'Key Encipherment' key usage."
fi
}

function check-shortname () {
printf "Checking for use of shortname as CN"

SUBJECT_CN=$(openssl x509 -in $CERT_FILE -noout -subject -nameopt multiline|grep commonName|cut -d '=' -f 2|tr -d ' ')
if [[ $SUBJECT_CN != *"."* ]]; then
error 1 "The $(basename $CERT_FILE) is using a shortname for Common Name (CN) and cannot be used with $PROJECT.\n"
fi

DNS_LIST=$(openssl x509 -noout -text -in $CERT_FILE | grep DNS:)
if [[ $? == "0" ]]; then
for DNS in ${DNS_LIST}
do
DNS_VALUE="$( echo ${DNS//DNS:/} | tr -d ',')"

if [[ $DNS_VALUE == *"."* ]]; then
success
return
fi
done
error 1 "The $(basename $CERT_FILE) is using only shortnames for Subject Alt Name and cannot be used with $PROJECT.\n"
fi
}

check-files-exist
check-server-cert-encoding
check-expiration
check-cert-ca-flag
check-passphrase
check-priv-key
check-ca-bundle
check-ca-bundle-size
check-ca-bundle-trust-rules
check-cert-san
check-cert-usage-key-encipherment
check-shortname

if [[ $EXIT_CODE == "0" ]] && ([[ $TARGET == ${SERVER_TARGET} ]] || [[ -z "$TARGET" ]]) ; then
echo -e "${GREEN}Validation succeeded${RESET}\n"
cat <<EOF

To install the ${PROJECT} server with the custom certificates, run:

${INSTALLER} --scenario ${SERVER_SCENARIO} \\
--certs-server-cert "$(readlink -f $CERT_FILE)" \\
--certs-server-key "$(readlink -f $KEY_FILE)" \\
--certs-server-ca-cert "$(readlink -f $CA_BUNDLE_FILE)"

To update the certificates on a currently running ${PROJECT} installation, run:

${INSTALLER} --scenario ${SERVER_SCENARIO} \\
--certs-server-cert "$(readlink -f $CERT_FILE)" \\
--certs-server-key "$(readlink -f $KEY_FILE)" \\
--certs-server-ca-cert "$(readlink -f $CA_BUNDLE_FILE)" \\
--certs-update-server --certs-update-server-ca

To use them inside a NEW \$${PROXY_VAR}, rerun this command with -t ${PROXY_TARGET}
EOF
elif [[ $EXIT_CODE == "0" ]]; then
echo -e "${GREEN}Validation succeeded${RESET}\n"
cat <<EOF

To use them inside a NEW \$${PROXY_VAR}, run this command:

${CERTS_TOOL} --foreman-proxy-fqdn "\$${PROXY_VAR}" \\
--certs-tar "~/\$${PROXY_VAR}-certs.tar" \\
--server-cert "$(readlink -f $CERT_FILE)" \\
--server-key "$(readlink -f $KEY_FILE)" \\
--server-ca-cert "$(readlink -f $CA_BUNDLE_FILE)"

To use them inside an EXISTING \$${PROXY_VAR}, run this command INSTEAD:

${CERTS_TOOL} --foreman-proxy-fqdn "\$${PROXY_VAR}" \\
--certs-tar "~/\$${PROXY_VAR}-certs.tar" \\
--server-cert "$(readlink -f $CERT_FILE)" \\
--server-key "$(readlink -f $KEY_FILE)" \\
--server-ca-cert "$(readlink -f $CA_BUNDLE_FILE)" \\
--certs-update-server
EOF
else
exit $EXIT_CODE
fi
(4-4/5)