Simple script to check expiry dates on a java keystore (.jks) file

Here in my company we regularly need to check for expired certificates or just to have a proactive management checking which certificates are close to their expiry dates and issue new ones to avoid service disruption.

For that reason I’ve created a simple bash script which can be used in conjunction with nagios to check for expiring certicates.

#!/bin/sh
 
########################################################
#
#       Check certificates inside a java keystore
#
########################################################
TIMEOUT="timeout -k 10s 5s "
KEYTOOL="$TIMEOUT keytool"
THRESHOLD_IN_DAYS="30"
KEYSTORE=""
PASSWORD=""
RET=0
 
ARGS=`getopt -o "p:k:t:" -l "password:,keystore:,threshold:" -n "$0" -- "$@"`
 
function usage {
        echo "Usage: $0 --keystore <keystore> [--password <password>] [--threshold <number of days until expiry>]"
        exit
}
 
 
 
function start {
        CURRENT=`date +%s`
 
        THRESHOLD=$(($CURRENT + ($THRESHOLD_IN_DAYS*24*60*60)))
        if [ $THRESHOLD -le $CURRENT ]; then
                echo "[ERROR] Invalid date."
                exit 1
        fi
        echo "Looking for certificates inside the keystore $(basename $KEYSTORE) expiring in $THRESHOLD_IN_DAYS day(s)..."
 
        $KEYTOOL -list -v -keystore "$KEYSTORE"  $PASSWORD 2>&1 > /dev/null
        if [ $? -gt 0 ]; then echo "Error opening the keystore."; exit 1; fi
 
        $KEYTOOL -list -v -keystore "$KEYSTORE"  $PASSWORD | grep Alias | awk '{print $3}' | while read ALIAS
        do
                #Iterate through all the certificate alias
                EXPIRACY=`$KEYTOOL -list -v -keystore "$KEYSTORE"  $PASSWORD -alias $ALIAS | grep Valid`
                UNTIL=`$KEYTOOL -list -v -keystore "$KEYSTORE"  $PASSWORD -alias $ALIAS | grep Valid | perl -ne 'if(/until: (.*?)\n/) { print "$1\n"; }'`
                UNTIL_SECONDS=`date -d "$UNTIL" +%s`
                REMAINING_DAYS=$(( ($UNTIL_SECONDS -  $(date +%s)) / 60 / 60 / 24 ))
                if [ $THRESHOLD -le $UNTIL_SECONDS ]; then
                        echo "[OK]      Certificate $ALIAS expires in '$UNTIL' ($REMAINING_DAYS day(s) remaining)."
                else
                        echo "[WARNING] Certificate $ALIAS expires in '$UNTIL' ($REMAINING_DAYS day(s) remaining)."
                        RET=1
                fi
 
        done
        echo "Finished..."
        exit $RET
}
 
eval set -- "$ARGS"
 
while true
do
        case "$1" in
                -p|--password)
                        if [ -n "$2" ]; then PASSWORD=" -storepass $2"; else echo "Invalid password"; exit 1; fi
                        shift 2;;
                -k|--keystore)
                        if [ ! -f "$2" ]; then echo "Keystore not found: $1"; exit 1; else KEYSTORE=$2; fi
                        shift 2;;
                -t|--threshold)
                        if [ -n "$2" ] && [[ $2 =~ ^[0-9]+$ ]]; then THRESHOLD_IN_DAYS=$2; else echo "Invalid threshold"; exit 1; fi
                        shift 2;;
                --)
                        shift
                        break;;
        esac
done
 
if [ -n "$KEYSTORE" ]
then
        start
else
        usage
fi

All you have to do is call it like this:

./checkCertificate --keystore [YOUR_KEYSTORE_FILE] --password [YOUR_PASSWORD] --threshold [THRESHOLD_IN_DAYS]

The threshold indicates how many days are left until the expiry date is reached. I’m sure that there are several other ways of doing it but this is my own :-)

6 comments

  1. The root_ca.cert expiration date of my company is in 30 years (2043) and this far long date seems to cause an issue when checking the validity of keystores that contain that root_ca.cert…
    Do you have an idea on how to get it working in my case ?

    But are you talking about an error being raised by my script? Can you please share the output of the script you you run it against the keystore that holds that certificate?

  2. Thank you for this nice script!
    I just had to exchange the awk expression
    ‘{print $3}’
    in line 37 with
    ‘{print $NF}’
    because the position of the alias name is language dependent (“Aliasname: xyz” => $2 in German). But it should always be the last token in the line ( => $NF ).

  3. Found this via Google, very useful thanks!
    As you say, there are several ways of doing it, but the one thing that stood out was the unnecessary calling up of PERL just to cut out a column, in this bit here:
    UNTIL=`$KEYTOOL -list -v -keystore “$KEYSTORE” $PASSWORD -alias $ALIAS | grep Valid | perl -ne ‘if(/until: (.*?)\n/) { print “$1\n”; }’`
    UNTIL_SECONDS=`date -d “$UNTIL” +%s`

    This could be done with awk of course, but seeing as we are writing shell code then (assuming bash or Korn available) more efficient code could be something like:

    VALIDITY=$($KEYTOOL -list -v -keystore “$KEYSTORE” $PASSWORD -alias $ALIAS | grep Valid)
    UNTIL_SECONDS=$(date -d “${VALIDITY##*until: }” +%s)

    Saves forking for external processes. :-)

  4. i am running the script in ksh i am getting an error in this line please help me

    -t|–threshold)
    if [ -n “$2″ ] && [[ $2 =~ ^[0-9]+$ ]]; then THRESHOLD_IN_DAYS=$2; else echo “Invalid threshold”; exit 1; fi
    shift 2;;

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre lang="" line="" escaped="" cssfile="">