#!/bin/bash
|
|
# ---------------------------------------------------------------------------
|
|
# checkssl - checks ssl certs for a set of domains
|
|
|
|
# This program is free software: you can redistribute it and/or modify
|
|
# it under the terms of the GNU General Public License as published by
|
|
# the Free Software Foundation, either version 2 of the License, or
|
|
# (at your option) any later version.
|
|
|
|
# This program is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU General Public License at <http://www.gnu.org/licenses/> for
|
|
# more details.
|
|
|
|
# Usage: checkssl [-h|--help] [-d|--debug] [-f|--file filename] [-s|--server stype] [-l|--location] [-e:--expires days] [-r:--renew]
|
|
|
|
# Revision history:
|
|
# 2015-12-05 Created (v0.1)
|
|
# 2015-12-05 Added the ability to automatically search for domains from the Lets Encrypt live directory (v0.2 - sleeps)
|
|
# 2015-12-06 Corrected issue in grep affecting performance on some servers (v0.3 - srvrco)
|
|
# 2015-12-06 corrected typo (srvrco)
|
|
# 2015-12-06 Added --expires days argument to set the timescale you want to know about certs coming to end of life (srvrco)
|
|
# 2015-12-06 Added --renew argument to list domains ready for renew v0.4 - srvrco)
|
|
# ---------------------------------------------------------------------------
|
|
|
|
PROGNAME=${0##*/}
|
|
VERSION="0.4"
|
|
RENEW_ALERT="30" # set to number of days to be alerted for certificate renewal ( default, can be changed with -expires argument)
|
|
|
|
clean_up() { # Perform pre-exit housekeeping
|
|
rm -f LIST_OF_DOMAINS
|
|
rm -f DATA_OUT
|
|
return
|
|
}
|
|
|
|
error_exit() {
|
|
echo -e "${PROGNAME}: ${1:-"Unknown Error"}" >&2
|
|
clean_up
|
|
exit 1
|
|
}
|
|
|
|
graceful_exit() {
|
|
clean_up
|
|
exit
|
|
}
|
|
|
|
signal_exit() { # Handle trapped signals
|
|
case $1 in
|
|
INT)
|
|
error_exit "Program interrupted by user" ;;
|
|
TERM)
|
|
echo -e "\n$PROGNAME: Program terminated" >&2
|
|
graceful_exit ;;
|
|
*)
|
|
error_exit "$PROGNAME: Terminating on unknown signal" ;;
|
|
esac
|
|
}
|
|
|
|
usage() {
|
|
echo -e "Usage: $PROGNAME [-h|--help] [-d|--debug] [-f|--file filename] [-s|--server stype] [-l|--location directory] [-e|--expires days] [-r:--renew]"
|
|
}
|
|
|
|
log() {
|
|
echo "[$(date +%Y-%m-%d\ %H:%M:%S)] $*" >> ${PROGNAME}.log
|
|
}
|
|
|
|
debug() {
|
|
if [[ "${_USE_DEBUG:-"0"}" -eq 1 ]]; then
|
|
echo "$@"
|
|
fi
|
|
}
|
|
|
|
help_message() {
|
|
cat <<- _EOF_
|
|
$PROGNAME ver. $VERSION
|
|
checks ssl certs for a set of domains
|
|
|
|
$(usage)
|
|
|
|
Options:
|
|
-h, --help Display this help message and exit.
|
|
-d, --debug outputs debug information
|
|
-f, --file filename
|
|
Where 'filename' is a file containing a list of domain names
|
|
-s, --server server_type
|
|
Where 'server_type' is the server type (cpanel, ISPconfig, apache2 ...)
|
|
-l, --location directory
|
|
Where 'directory' is where your lets encrypt live directory is
|
|
(typically /etc/letsencrypt/live/)
|
|
-e, --expires days
|
|
Where 'days' is the number of days to alert if cert expires in that time period
|
|
-r, --renew this just lists domain names that need to be renewed. This list could be used by an auto renew script, or to email you.
|
|
|
|
_EOF_
|
|
return
|
|
}
|
|
|
|
# Trap signals
|
|
trap "signal_exit TERM" TERM HUP
|
|
trap "signal_exit INT" INT
|
|
|
|
|
|
|
|
# Parse command-line
|
|
while [[ -n $1 ]]; do
|
|
case $1 in
|
|
-h | --help)
|
|
help_message; graceful_exit ;;
|
|
-d | --debug)
|
|
_USE_DEBUG=1 ;;
|
|
-e | --expires)
|
|
shift; RENEW_ALERT="$1" ;;
|
|
-f | --file)
|
|
FILEARG=true; shift; FILE="$1" ;;
|
|
-r | --renew)
|
|
RENEWARG=true ;;
|
|
-s | --server)
|
|
SERVERARG=true; shift; STYPE="$1" ;;
|
|
-l | --location)
|
|
LOCATIONARG=true; shift; LOC="$1" ;;
|
|
-* | --*)
|
|
usage
|
|
error_exit "Unknown option $1" ;;
|
|
*)
|
|
echo "Argument $1 to process..." ;;
|
|
esac
|
|
shift
|
|
done
|
|
|
|
# Main logic
|
|
|
|
if [[ ! $FILEARG && ! $SERVERARG && ! $LOCATIONARG ]]; then
|
|
help_message
|
|
graceful_exit
|
|
fi
|
|
|
|
# create temporary file for the list of domains, and output
|
|
LIST_OF_DOMAINS=$(mktemp)
|
|
DATA_OUT=$(mktemp)
|
|
debug "created tmp files for input (${LIST_OF_DOMAINS}) and output (${DATA_OUT})"
|
|
echo "Domain|cert issued for|valid until|cert issued by| possible issues?" > $DATA_OUT
|
|
|
|
# check and inport file if specified on command line
|
|
if [ $FILEARG ]; then
|
|
if [ -f $FILE ]; then
|
|
cat $FILE >> $LIST_OF_DOMAINS
|
|
else
|
|
echo "$FILE not found"
|
|
graceful_exit
|
|
fi
|
|
fi
|
|
|
|
# get a list of domains from server (if -s flag used)
|
|
if [ $SERVERARG ]; then
|
|
if [ "$STYPE" == "cpanel" ]; then
|
|
cat /etc/userdomains | cut -d":" -f 1 | grep "\." >> $LIST_OF_DOMAINS
|
|
elif [ "$STYPE" == "ISPconfig" ]; then
|
|
apache2ctl -S | grep namevhost | awk '{print $4}' | sort | uniq >> $LIST_OF_DOMAINS
|
|
else
|
|
echo "unknown server type currently"
|
|
graceful_exit
|
|
fi
|
|
fi
|
|
|
|
if [ $LOCATIONARG ]; then
|
|
LELOC=$LOC/*
|
|
for f in $LELOC; do
|
|
if [[ -d $f ]]; then
|
|
dir=$(basename "$f")
|
|
echo $dir >> $LIST_OF_DOMAINS
|
|
fi
|
|
done
|
|
fi
|
|
|
|
cat $LIST_OF_DOMAINS | while read -d $'\n\b' DOMAIN; do
|
|
PROBLEMS=""
|
|
debug " --------------- domain ${DOMAIN} ---------------------"
|
|
CERTINFO=$(echo | openssl s_client -servername ${DOMAIN} -connect ${DOMAIN}:443 2>/dev/null | openssl x509 2>/dev/null)
|
|
ISSUEDTO=$(echo "$CERTINFO" | openssl x509 -noout -subject 2>/dev/null|cut -d= -f 3-)
|
|
[[ -z $ISSUEDTO ]] && ISSUEDTO="-"
|
|
debug "$ISSUEDTO"
|
|
ISSUER=$(echo "$CERTINFO" | openssl x509 -noout -issuer 2>/dev/null| grep -Eo "/CN=[a-zA-Z' 0-9]*"| cut -c 5-)
|
|
[[ -z $ISSUER ]] && ISSUER="-"
|
|
debug "$ISSUER"
|
|
ENDDATE=$(echo "$CERTINFO" | openssl x509 -noout -enddate 2>/dev/null| cut -d= -f 2-)
|
|
[[ -z $ENDDATE ]] && ENDDATE="-"
|
|
debug "$ENDDATE"
|
|
if [ "${DOMAIN}" != "$ISSUEDTO" ]; then
|
|
if [[ -z $CERTINFO ]]; then
|
|
PROBLEMS=$(echo "${PROBLEMS}- no certificate found")
|
|
else
|
|
ALT_NAMES=$(echo "$CERTINFO" | openssl x509 -noout -text 2>/dev/null| grep "Subject Alternative Name" -A2 |grep -Eo "DNS:[a-zA-Z 0-9.]*" | cut -c 5-)
|
|
if [ "$(echo "$ALT_NAMES" | grep ^${DOMAIN})" == "${DOMAIN}" ]; then
|
|
ISSUEDTO=$(echo "${DOMAIN} (alt)")
|
|
else
|
|
PROBLEMS=$(echo "${PROBLEMS}- possible name mismatch")
|
|
fi
|
|
fi
|
|
fi
|
|
if [[ "$ENDDATE" != "-" ]]; then
|
|
if [[ $(date -d "${RENEW_ALERT} days" +%s) -gt $(date -d "$ENDDATE" +%s) ]]; then
|
|
PROBLEMS=$(echo "${PROBLEMS}- certificate near renewal date")
|
|
fi
|
|
fi
|
|
printf "%s|%s|%s|%s|%s\n" "$DOMAIN" "$ISSUEDTO" "$ENDDATE" "$ISSUER" "$PROBLEMS">> $DATA_OUT
|
|
done
|
|
|
|
if [[ $RENEWARG ]]; then
|
|
grep "certificate near renewal date" $DATA_OUT | awk -F"|" '{print $1}'
|
|
else
|
|
echo ""
|
|
cat $DATA_OUT | column -t -s"|"
|
|
fi
|
|
|
|
graceful_exit
|