MaxWinterstein

nagios check_ssl with added ssl-version option

Jul 29th, 2013
1,032
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Bash 31.74 KB | None | 0 0
  1.     #!/bin/sh
  2.     #
  3.     # check_ssl_cert
  4.     #
  5.     ################################################################################
  6.     #
  7.     # Custom version: added (-S, --ssl) to specify ssl-version, just like check_http
  8.     # everything else belongs to the creator itself.
  9.     # Max Winterstein - 29.07.2013 -  see
  10.     #   http://stackoverflow.com/questions/17885821/nagios-check-ssl-cert-error-ssl-cert-critical-error-verify-depth-is-6/
  11.     #
  12.     ################################################################################
  13.     # Checks an X.509 certificate:
  14.     # - checks if the server is running and delivers a valid certificate
  15.     # - checks if the CA matches a given pattern
  16.     # - checks the validity
  17.     #
  18.     # See  the INSTALL file for installation instructions
  19.     #
  20.     # Copyright (c) 2007-2012 ETH Zurich.
  21.     #
  22.     # This module is free software; you can redistribute it and/or modify it
  23.     # under the terms of GNU general public license (gpl) version 3.
  24.     # See the LICENSE file for details.
  25.     #
  26.     # RCS information
  27.     # enable substitution with:
  28.     #   $ svn propset svn:keywords "Id Revision HeadURL Source Date"
  29.     #
  30.     #   $Id$
  31.     #   $Revision$
  32.     #   $HeadURL$
  33.     #   $Date$
  34.    
  35.     ################################################################################
  36.     # Constants
  37.    
  38.     VERSION=1.14.6
  39.     SHORTNAME="SSL_CERT"
  40.    
  41.     VALID_ATTRIBUTES=",startdate,enddate,subject,issuer,modulus,serial,hash,email,ocsp_uri,fingerprint,"
  42.    
  43.     ################################################################################
  44.     # Functions
  45.    
  46.     ################################################################################
  47.     # Prints usage information
  48.     # Params
  49.     #   $1 error message (optional)
  50.     usage() {
  51.    
  52.         if [ -n "$1" ] ; then
  53.             echo "Error: $1" 1>&2
  54.         fi
  55.    
  56.         #### The following line is 80 characters long (helps to fit the help text in a standard terminal)
  57.         ######--------------------------------------------------------------------------------
  58.            
  59.         echo
  60.         echo "Usage: check_ssl_cert -H host [OPTIONS]"
  61.         echo
  62.         echo "Arguments:"
  63.         echo "   -H,--host host         server"
  64.         echo
  65.         echo "Options:"
  66.         echo "   -A,--noauth            ignore authority warnings (expiration only)"
  67.         echo "      --altnames          matches the pattern specified in -n with alternate"
  68.         echo "                          names too"
  69.         echo "   -C,--clientcert path   use client certificate to authenticate"
  70.         echo "      --clientpass phrase set passphrase for client certificate."
  71.         echo "   -c,--critical days     minimum number of days a certificate has to be valid"
  72.         echo "                          to issue a critical status"
  73.         echo "   -e,--email address     pattern to match the email address contained in the"
  74.         echo "                          certificate"
  75.         echo "   -f,--file file         local file path (works with -H localhost only)"
  76.         echo "   -h,--help,-?           this help message"
  77.         echo "      --long-output list  append the specified comma separated (no spaces) list"
  78.         echo "                          of attributes to the plugin output on additional lines."
  79.         echo "                          Valid attributes are:"
  80.         echo "                            enddate, startdate, subject, issuer, modulus, serial,"
  81.         echo "                            hash, email, ocsp_uri and fingerprint."
  82.         echo "                          'all' will include all the available attributes."
  83.         echo "   -i,--issuer issuer     pattern to match the issuer of the certificate"
  84.         echo "   -n,--cn name           pattern to match the CN of the certificate"
  85.         echo "   -N,--host-cn           match CN with the host name"
  86.         echo "   -o,--org org           pattern to match the organization of the certificate"
  87.         echo "      --openssl path      path of the openssl binary to be used"
  88.         echo "   -p,--port port         TCP port"
  89.         echo "   -P,--protocol protocol use the specific protocol {http|smtp|pop3|imap|ftp|xmpp}"
  90.         echo "                          http:               default"
  91.         echo "                          smtp,pop3,imap,ftp: switch to TLS"
  92.         echo "   -s,--selfsigned        allows self-signed certificates"
  93.         echo "   -S,--ssln                   SSL-Version to use (1,2,3)"
  94.         echo "   -r,--rootcert path     root certificate or directory to be used for"
  95.         echo "                          certficate validation"
  96.         echo "   -t,--timeout           seconds timeout after the specified time"
  97.         echo "                          (defaults to 15 seconds)"
  98.         echo "      --temp dir          directory where to store the temporary files"
  99.         echo "   -v,--verbose           verbose output"
  100.         echo "   -V,--version           version"
  101.         echo "   -w,--warning days      minimum number of days a certificate has to be valid"
  102.         echo "                          to issue a warning status"
  103.         echo
  104.         echo "Deprecated options:"
  105.         echo "   -d,--days days         minimum number of days a certificate has to be valid"
  106.         echo "                          (see --critical and --warning)"
  107.         echo
  108.         echo "Report bugs to: Matteo Corti <[email protected]>"
  109.         echo
  110.    
  111.         exit 3
  112.    
  113.     }
  114.    
  115.     ################################################################################
  116.     # Exits with a critical message
  117.     # Params
  118.     #   $1 error message
  119.     critical() {
  120.         if [ -n "${CN}" ] ; then
  121.             tmp=" ${CN}"
  122.         fi
  123.         printf "${SHORTNAME} CRITICAL$tmp: $1${PERFORMANCE_DATA}${LONG_OUTPUT}\n"
  124.         exit 2
  125.     }
  126.    
  127.     ################################################################################
  128.     # Exits with a warning message
  129.     # Param
  130.     #   $1 warning message
  131.     warning() {
  132.         if [ -n "${CN}" ] ; then
  133.             tmp=" ${CN}"
  134.         fi
  135.         printf "${SHORTNAME} WARN$tmp: $1${PERFORMANCE_DATA}${LONG_OUTPUT}\n"
  136.         exit 1
  137.     }
  138.    
  139.     ################################################################################
  140.     # Exits with an 'unkown' status
  141.     # Param
  142.     #   $1 message
  143.     unknown() {
  144.         if [ -n "${CN}" ] ; then
  145.             tmp=" ${CN}"
  146.         fi
  147.         printf "${SHORTNAME} UNKNOWN$tmp: $1\n"
  148.         exit 3
  149.     }
  150.    
  151.     ################################################################################
  152.     # Executes command with a timeout
  153.     # Params:
  154.     #   $1 timeout in seconds
  155.     #   $2 command
  156.     # Returns 1 if timed out 0 otherwise
  157.     exec_with_timeout() {
  158.    
  159.         time=$1
  160.    
  161.         # start the command in a subshell to avoid problem with pipes
  162.         # (spawn accepts one command)
  163.         command="/bin/sh -c \"$2\""
  164.    
  165.         if [ -n "${TIMEOUT_BIN}" ] ; then
  166.        
  167.             eval "${TIMEOUT_BIN} $time $command"
  168.    
  169.         elif [ -n "${EXPECT}" ] ; then
  170.    
  171.             expect -c "set echo \"-noecho\"; set timeout $time; spawn -noecho $command; expect timeout { exit 1 } eof { exit 0 }"    
  172.    
  173.             if [ $? = 1 ] ; then
  174.                 critical "Timeout after ${time} seconds"
  175.             fi
  176.    
  177.         else
  178.             eval ${command}
  179.         fi
  180.                
  181.     }
  182.    
  183.     ################################################################################
  184.     # Checks if a given program is available and executable
  185.     # Params
  186.     #   $1 program name
  187.     # Returns 1 if the program exists and is executable
  188.     check_required_prog() {
  189.    
  190.         PROG=$(which $1 2> /dev/null)
  191.    
  192.         if [ -z "$PROG" ] ; then
  193.             critical "cannot find $1"
  194.         fi
  195.    
  196.         if [ ! -x "$PROG" ] ; then
  197.             critical "$PROG is not executable"
  198.         fi
  199.    
  200.     }
  201.    
  202.     ################################################################################
  203.     # Tries to fetch the certificate
  204.    
  205.     fetch_certificate() {
  206.    
  207.         # check if a protocol was specified (if not HTTP switch to TLS)
  208.         if [ -n "${PROTOCOL}" ] && [ "${PROTOCOL}" != "http" ] && [ "${PROTOCOL}" != "https" ] ; then
  209.            
  210.             case "${PROTOCOL}" in
  211.                
  212.                 smtp|pop3|imap|ftp|xmpp)
  213.    
  214.     exec_with_timeout $TIMEOUT "echo 'Q' | $OPENSSL s_client ${CLIENT} ${CLIENTPASS} -starttls ${PROTOCOL} -connect $HOST:$PORT ${SERVERNAME} -verify 6 ${ROOT_CA} ${SSLV} 2> ${ERROR} 1> ${CERT}"
  215.     ;;
  216.    
  217.     *)
  218.    
  219.     unknown "Error: unsupported protocol ${PROTOCOL}"
  220.    
  221.     esac
  222.    
  223.     elif [ -n "${FILE}" ] ; then
  224.    
  225.     if [ "${HOST}" = "localhost" ] ; then
  226.        
  227.         exec_with_timeout $TIMEOUT "/bin/cat '${FILE}' 2> ${ERROR} 1> ${CERT}"
  228.        
  229.     else
  230.        
  231.         unknown "Error: option 'file' works with -H localhost only"
  232.        
  233.     fi
  234.    
  235.     else
  236.    
  237.     exec_with_timeout $TIMEOUT "echo 'Q' | $OPENSSL s_client ${CLIENT} ${CLIENTPASS} -connect $HOST:$PORT ${SERVERNAME} -verify 6 ${ROOT_CA} ${SSLV} 2> ${ERROR} 1> ${CERT}"
  238.    
  239.     fi
  240.    
  241.     if [ $? -ne 0 ] ; then
  242.         critical "Error: $(head -n 1 ${ERROR})"
  243.     fi
  244.    
  245.    
  246.     }
  247.    
  248.    
  249.     main() {
  250.        
  251.         ################################################################################
  252.         # Main
  253.         ################################################################################
  254.    
  255.         # default values
  256.         PORT=443
  257.         TIMEOUT=15
  258.         VERBOSE=""
  259.         OPENSSL=""
  260.    
  261.         # set the default temp dir if not set
  262.         if [ -z "${TMPDIR}" ] ; then
  263.             TMPDIR="/tmp"
  264.         fi
  265.    
  266.         ################################################################################
  267.         # process command line options
  268.         #
  269.         #   we do no use getopts since it is unable to process long options
  270.    
  271.         while true; do
  272.    
  273.             case "$1" in
  274.    
  275.                 ########################################
  276.                 # options without arguments
  277.    
  278.                 -A|--noauth)     NOAUTH=1;               shift  ;;
  279.    
  280.                 --altnames)      ALTNAMES=1;             shift  ;;
  281.    
  282.                 -h|--help|-\?)   usage;                  exit 0 ;;
  283.    
  284.                 -N|--host-cn)    COMMON_NAME="__HOST__"; shift  ;;
  285.    
  286.                 -s|--selfsigned) SELFSIGNED=1;           shift  ;;
  287.                    
  288.                 -v|--verbose)    VERBOSE=1;              shift  ;;
  289.            
  290.                 -V|--version)    echo "check_ssl_cert version ${VERSION}"; exit 3; ;;
  291.    
  292.                 ########################################
  293.                 # options with arguments
  294.            
  295.              
  296.    
  297.                 -S|--ssl) if [ $# -gt 1 ]; then
  298.                         SSLV="-ssl$2"; shift 2
  299.                     else
  300.                         unknown "-S,--ssl requires an argument"
  301.                     fi ;;
  302.    
  303.    
  304.                 -c|--critical) if [ $# -gt 1 ]; then
  305.                         CRITICAL=$2; shift 2            
  306.                     else
  307.                         unknown "-c,--critical requires an argument"
  308.                     fi ;;
  309.    
  310.                 # deprecated option: used to be as --warning
  311.                 -d|--days) if [ $# -gt 1 ]; then
  312.                         WARNING=$2; shift 2            
  313.                     else
  314.                         unknown "-d,--days requires an argument"
  315.                     fi ;;
  316.    
  317.                 -e|--email) if [ $# -gt 1 ]; then
  318.                     ADDR=$2; shift 2            
  319.                 else
  320.                   unknown "-e,--email requires an argument"
  321.                 fi ;;
  322.    
  323.                 -f|--file) if [ $# -gt 1 ]; then
  324.                     FILE=$2; shift 2
  325.                 else
  326.                     unknown "-f,--file requires an argument"
  327.                 fi ;;
  328.                
  329.                 -H|--host) if [ $# -gt 1 ]; then
  330.                     HOST=$2; shift 2
  331.                 else
  332.                     unknown "-H,--host requires an argument"
  333.                 fi ;;
  334.    
  335.                 -i|--issuer) if [ $# -gt 1 ]; then
  336.                     ISSUER=$2; shift 2
  337.                 else
  338.                     unknown "-i,--issuer requires an argument"
  339.                 fi ;;
  340.    
  341.                 --long-output) if [ $# -gt 1 ]; then
  342.                     LONG_OUTPUT_ATTR=$2; shift 2
  343.                 else
  344.                     unknown "--long-output requires an argument"
  345.                 fi ;;
  346.    
  347.                 -n|--cn) if [ $# -gt 1 ]; then
  348.                     COMMON_NAME=$2; shift 2
  349.                 else
  350.                     unknown "-n,--cn requires an argument"
  351.                 fi ;;
  352.    
  353.                 -o|--org) if [ $# -gt 1 ]; then
  354.                     ORGANIZATION=$2; shift 2
  355.                 else
  356.                     unknown "-o,--org requires an argument"
  357.                 fi ;;
  358.    
  359.                 --openssl) if [ $# -gt 1 ]; then
  360.                     OPENSSL=$2; shift 2
  361.                 else
  362.                     unknown "--openssl requires an argument"
  363.                 fi ;;
  364.    
  365.                 -p|--port) if [ $# -gt 1 ]; then
  366.                     PORT=$2; shift 2
  367.                 else
  368.                     unknown "-p,--port requires an argument"
  369.                 fi ;;
  370.    
  371.                 -P|--protocol) if [ $# -gt 1 ]; then
  372.                     PROTOCOL=$2; shift 2
  373.                 else
  374.                     unknown "-P,--protocol requires an argument"
  375.                 fi ;;
  376.    
  377.                 -r|--rootcert) if [ $# -gt 1 ]; then
  378.                     ROOT_CA=$2; shift 2
  379.                 else
  380.                     unknown "-r,--rootcert requires an argument"
  381.                 fi ;;
  382.    
  383.                 -C|--clientcert) if [ $# -gt 1 ]; then
  384.                     CLIENT_CERT=$2; shift 2
  385.                 else
  386.                     unknown "-c,--clientcert requires an argument"
  387.                 fi ;;
  388.    
  389.                 --clientpass) if [ $# -gt 1 ]; then
  390.                     CLIENT_PASS=$2; shift 2
  391.                 else
  392.                     unknown "--clientpass requires an argument"
  393.                 fi ;;
  394.    
  395.                 -t|--timeout) if [ $# -gt 1 ]; then
  396.                     TIMEOUT=$2; shift 2
  397.                 else
  398.                   unknown "-t,--timeout requires an argument"
  399.                 fi ;;
  400.    
  401.                 --temp) if [ $# -gt 1 ] ; then
  402.                     # override TMPDIR
  403.                     TMPDIR=$2; shift 2
  404.                 else
  405.                    unknown "--temp requires an argument"
  406.                 fi ;;
  407.    
  408.                 -w|--warning) if [ $# -gt 1 ]; then
  409.                     WARNING=$2; shift 2            
  410.                 else
  411.                     unknown "-w,--warning requires an argument"
  412.                 fi ;;
  413.    
  414.                 ########################################
  415.                 # special
  416.            
  417.                 --) shift; break;;
  418.                 -*) unknown "invalid option: $1" ;;
  419.                 *)  break;;
  420.            
  421.             esac
  422.    
  423.         done
  424.    
  425.         ################################################################################
  426.         # Set COMMON_NAME to hostname if -N was given as argument
  427.         if [ "$COMMON_NAME" = "__HOST__" ] ; then
  428.             COMMON_NAME=${HOST}
  429.         fi
  430.    
  431.         ################################################################################
  432.         # sanity checks
  433.    
  434.         ###############
  435.         # Check options
  436.         if [ -z "${HOST}" ] ; then
  437.             usage "No host specified"
  438.         fi
  439.    
  440.         if [ -n "${ALTNAMES}" ] && [ -z "${COMMON_NAME}" ] ; then
  441.             unknown "--altnames requires a common name to match (--cn or --host-cn)"
  442.         fi
  443.    
  444.         if [ -n "${ROOT_CA}" ] ; then
  445.             if [ ! -r ${ROOT_CA} ] ; then
  446.                 unknown "Cannot read root certificate ${ROOT_CA}"
  447.             fi
  448.             if [ -d ${ROOT_CA} ] ; then
  449.                 ROOT_CA="-CApath ${ROOT_CA}"
  450.             elif [ -f ${ROOT_CA} ] ; then
  451.                 ROOT_CA="-CAfile ${ROOT_CA}"
  452.             else
  453.                 unknown "Root certificate of unknown type $(file ${ROOT_CA} 2> /dev/null)"
  454.             fi
  455.         fi
  456.        
  457.         if [ -n "${CLIENT_CERT}" ] ; then
  458.             if [ ! -r ${CLIENT_CERT} ] ; then
  459.                 unknown "Cannot read client certificate ${CLIENT_CERT}"
  460.             fi
  461.         fi
  462.        
  463.         if [ -n "${CRITICAL}" ] ; then
  464.             if ! echo "${CRITICAL}" | grep -q '[0-9][0-9]*' ; then
  465.                 unknown "invalid number of days ${CRITICAL}"
  466.             fi
  467.         fi
  468.        
  469.         if [ -n "${WARNING}" ] ; then
  470.             if ! echo ${WARNING} | grep -q '[0-9][0-9]*' ; then
  471.                 unknown "invalid number of days ${WARNING}"
  472.             fi
  473.         fi
  474.        
  475.         if [ -n "${CRITICAL}" ] && [ -n "${WARNING}" ] ; then
  476.             if [ ${WARNING} -le ${CRITICAL} ] ; then
  477.                 unknown "--warning (${WARNING}) is less than or equal to --critical (${CRITICAL})"
  478.             fi
  479.         fi
  480.        
  481.         if [ -n "${TMPDIR}" ] ; then
  482.             if [ ! -d ${TMPDIR} ] ; then
  483.                 unknown "${TMPDIR} is not a directory";
  484.             fi
  485.             if [ ! -w ${TMPDIR} ] ; then
  486.                 unknown "${TMPDIR} is not writable";
  487.             fi
  488.         fi
  489.        
  490.         if [ -n "${OPENSSL}" ] ; then
  491.             if [ ! -x ${OPENSSL} ] ; then
  492.                 unknown "${OPENSSL} ist not an executable"
  493.             fi
  494.             if [ $(basename ${OPENSSL}) != 'openssl' ] ; then
  495.                 unknown "${OPENSSL} ist not an openssl executable"
  496.             fi
  497.         fi
  498.        
  499.         #######################
  500.         # Check needed programs
  501.    
  502.         # OpenSSL
  503.         if [ -z "${OPENSSL}" ] ; then
  504.             check_required_prog openssl
  505.             OPENSSL=$PROG
  506.         fi
  507.    
  508.         # Expect (optional)
  509.         EXPECT=$(which expect 2> /dev/null)
  510.         test -x "${EXPECT}" || EXPECT=""
  511.         if [  -n "${VERBOSE}" ] ; then
  512.             if [ -z "${EXPECT}" ] ; then
  513.                 echo "expect not available"
  514.             else
  515.                 echo "expect available (${EXPECT})"
  516.             fi
  517.         fi
  518.    
  519.         # Timeout (optional)
  520.         TIMEOUT_BIN=$(which timeout 2> /dev/null)
  521.         test -x "${TIMEOUT_BIN}" || TIMEOUT_BIN=""
  522.         if [  -n "${VERBOSE}" ] ; then
  523.             if [ -z "${TIMEOUT_BIN}" ] ; then
  524.                 echo "timeout not available"
  525.             else
  526.                 echo "timeout available (${TIMEOUT_BIN})"
  527.             fi
  528.         fi
  529.    
  530.         if [ -z "${TIMEOUT_BIN}" ] && [ -z "${EXPECT}" ] && [ -n "${VERBOSE}" ] ; then
  531.             echo "disabling timeouts"
  532.         fi
  533.    
  534.         # Perl with Date::Parse (optional)
  535.         PERL=$(which perl 2> /dev/null)
  536.         test -x "${PERL}" || PERL=""
  537.         if [ -z "${PERL}" ] && [ -n "${VERBOSE}" ] ; then
  538.             echo "Perl not found: disabling date computations"    
  539.         fi
  540.         if ! ${PERL} -e "use Date::Parse;" > /dev/null 2>&1 ; then
  541.             if [ -n "${VERBOSE}" ] ; then
  542.                 echo "Perl module Date::Parse not installed: disabling date computations"
  543.             fi
  544.             PERL=        
  545.         fi
  546.        
  547.         ################################################################################
  548.         # check if openssl s_client supports the -servername option
  549.         #
  550.         #   openssl s_client does not have a -help option
  551.         #   => we supply an invalid command line option to get the help
  552.         #      on standard error
  553.         #
  554.         SERVERNAME=
  555.         if ${OPENSSL} s_client not_a_real_option 2>&1 | grep -q -- -servername ; then
  556.    
  557.             if [ -n "${COMMON_NAME}" ] ; then
  558.                 SERVERNAME="-servername ${COMMON_NAME}"
  559.             else
  560.                 SERVERNAME="-servername ${HOST}"
  561.             fi
  562.    
  563.         else
  564.             if [ -n "${VERBOSE}" ] ; then
  565.                 echo "'${OPENSSL} s_client' does not support '-servername': disabling virtual server support"
  566.             fi
  567.         fi
  568.        
  569.         ################################################################################
  570.         # fetch the X.509 certificate
  571.        
  572.         # temporary storage for the certificate and the errors
  573.        
  574.         CERT=$(  mktemp -t "$( basename $0 )XXXXXX" 2> /dev/null )
  575.         if [ -z "${CERT}" ] || [ ! -w "${CERT}" ] ; then
  576.             unknown 'temporary file creation failure.'
  577.         fi
  578.        
  579.         ERROR=$( mktemp -t "$( basename $0 )XXXXXX" 2> /dev/null )
  580.         if [ -z "${ERROR}" ] || [ ! -w "${ERROR}" ] ; then
  581.             unknown 'temporary file creation failure.'
  582.         fi
  583.        
  584.         if [ -n "${VERBOSE}" ] ; then
  585.             echo "downloading certificate to ${TMPDIR}"
  586.         fi
  587.        
  588.         CLIENT=""
  589.         if [ -n "${CLIENT_CERT}" ] ; then
  590.             CLIENT="-cert ${CLIENT_CERT}"
  591.         fi
  592.        
  593.         CLIENTPASS=""
  594.         if [ -n "${CLIENT_PASS}" ] ; then
  595.             CLIENTPASS="-pass pass:${CLIENT_PASS}"
  596.         fi
  597.        
  598.         # cleanup before program termination
  599.         # using named signals to be POSIX compliant
  600.         trap "rm -f $CERT $ERROR" EXIT HUP INT QUIT TERM
  601.        
  602.         fetch_certificate
  603.        
  604.         if grep -q 'sslv3\ alert\ unexpected\ message' ${ERROR} ; then
  605.        
  606.             if [ -n "${SERVERNAME}" ] ; then
  607.        
  608.                 # some OpenSSL versions have problems with the -servername option
  609.                 # we try without
  610.                 if [ -n "${VERBOSE}" ] ; then
  611.                     echo "'${OPENSSL} s_client' returned an error: trying without '-servername'"
  612.                 fi
  613.                
  614.                 SERVERNAME=
  615.                 fetch_certificate
  616.        
  617.             fi
  618.        
  619.             if grep -q 'sslv3\ alert\ unexpected\ message' ${ERROR} ; then
  620.        
  621.                 critical "cannot fetch certificate: OpenSSL got an unexpected message"
  622.        
  623.             fi
  624.        
  625.         fi
  626.        
  627.         if ! grep -q "CERTIFICATE" ${CERT} ; then
  628.             if [ -n "${FILE}" ] ; then
  629.                 critical "'${FILE}' is not a valid certificate file"
  630.             else
  631.        
  632.                 # See
  633.                 # http://stackoverflow.com/questions/1251999/sed-how-can-i-replace-a-newline-n
  634.                 #
  635.                 # - create a branch label via :a
  636.                 # - the N command appends a newline and and the next line of the input
  637.                 #   file to the pattern space
  638.                 # - if we are before the last line, branch to the created label $!ba
  639.                 #   ($! means not to do it on the last line (as there should be one final newline))
  640.                 # - finally the substitution replaces every newline with a space on
  641.                 #   the pattern space
  642.            
  643.                 ERROR_MESSAGE=$(sed -e ':a' -e 'N' -e '$!ba' -e 's/\n/; /g' ${ERROR})
  644.                 if [ -n "${VERBOSE}" ] ; then
  645.                     echo "Error: ${ERROR_MESSAGE}"
  646.                 fi
  647.                 critical "No certificate returned (${ERROR_MESSAGE})"
  648.             fi
  649.         fi
  650.        
  651.         ################################################################################
  652.         # parse the X.509 certificate
  653.        
  654.         DATE=$($OPENSSL x509 -in ${CERT} -enddate -noout | sed -e "s/^notAfter=//")
  655.         CN=$($OPENSSL x509 -in ${CERT} -subject -noout | sed -e "s/^.*\/CN=//" -e "s/\/[A-Za-z][A-Za-z]*=.*$//")
  656.        
  657.         CA_O=$($OPENSSL x509 -in ${CERT} -issuer -noout | sed -e "s/^.*\/O=//" -e "s/\/[A-Z][A-Z]*=.*$//")
  658.         CA_CN=$($OPENSSL x509 -in ${CERT} -issuer -noout  | sed -e "s/^.*\/CN=//" -e "s/\/[A-Za-z][A-Za-z]*=.*$//")
  659.        
  660.        
  661.         ################################################################################
  662.         # Generate the long output
  663.         if [ -n "${LONG_OUTPUT_ATTR}" ] ; then
  664.        
  665.             check_attr() {
  666.                 ATTR=$1
  667.                 if ! echo "${VALID_ATTRIBUTES}" | grep -q ",${ATTR}," ; then
  668.                     unknown "Invalid certificate attribute: ${ATTR}"
  669.                 else      
  670.                     value=$(${OPENSSL} x509 -in ${CERT} -noout -${ATTR} | sed -e "s/.*=//")
  671.                     LONG_OUTPUT="${LONG_OUTPUT}\n${ATTR}: ${value}"
  672.                fi
  673.                
  674.             }
  675.            
  676.             # split on comma
  677.             if [ "${LONG_OUTPUT_ATTR}" = "all" ] ; then
  678.                 LONG_OUTPUT_ATTR=${VALID_ATTRIBUTES}
  679.             fi
  680.             attributes=$( echo ${LONG_OUTPUT_ATTR} | tr ',' "\n" )
  681.             for attribute in $attributes ; do
  682.                 check_attr ${attribute}
  683.             done
  684.        
  685.         fi
  686.        
  687.         ################################################################################
  688.         # compute for how many days the certificate will be valid
  689.        
  690.         if [ -n "${PERL}" ] ; then
  691.        
  692.             CERT_END_DATE=$($OPENSSL x509 -in ${CERT} -noout -enddate | sed -e "s/.*=//")
  693.        
  694.              DAYS_VALID=$( perl - "${CERT_END_DATE}" <<-"EOF"
  695.            
  696.     use strict;
  697.     use warnings;
  698.        
  699.     use Date::Parse;
  700.        
  701.     my $cert_date = str2time( $ARGV[0] );
  702.        
  703.     my $days = int (( $cert_date - time ) / 86400 + 0.5);
  704.        
  705.     print "$days\n";
  706.            
  707.     EOF
  708.    
  709.              )
  710.        
  711.             if [ -n "${VERBOSE}" ] ; then
  712.                 if [ ${DAYS_VALID} -ge 0 ] ; then
  713.                     echo "The certificate will expire in ${DAYS_VALID} day(s)"
  714.                 else
  715.                     echo "The certificate expired "$((- DAYS_VALID))" day(s) ago"
  716.                 fi
  717.                
  718.             fi
  719.            
  720.             PERFORMANCE_DATA="|days=$DAYS_VALID;${WARNING};${CRITICAL};;"
  721.        
  722.         fi
  723.        
  724.        
  725.        
  726.         ################################################################################
  727.         # check the CN (this will not work as expected with wildcard certificates)
  728.        
  729.         if [ -n "$COMMON_NAME" ] ; then
  730.        
  731.             ok=''
  732.        
  733.             case $COMMON_NAME in
  734.                 $CN) ok='true' ;;
  735.             esac
  736.        
  737.             # check alterante names
  738.             if [ -n "${ALTNAMES}" ] ; then
  739.                 for alt_name in $( $OPENSSL x509 -in ${CERT} -text | \
  740.                     grep --after-context=1 '509v3 Subject Alternative Name:' | \
  741.                     tail -n 1 | sed -e "s/DNS://g" | sed -e "s/,//g" ) ; do
  742.                     case $COMMON_NAME in
  743.                         $alt_name) ok='true' ;;
  744.                     esac
  745.                 done
  746.             fi
  747.        
  748.             if [ -z "$ok" ] ; then
  749.                 critical "invalid CN ('$CN' does not match '$COMMON_NAME')"
  750.             fi
  751.            
  752.         fi
  753.        
  754.         ################################################################################
  755.         # check the issuer
  756.        
  757.         if [ -n "$ISSUER" ] ; then
  758.        
  759.             ok=''
  760.             CA_ISSUER_MATCHED=''
  761.        
  762.             if echo $CA_CN | grep -q "^$ISSUER$" ; then
  763.                 ok='true'
  764.                 CA_ISSUER_MATCHED="${CA_CN}"
  765.             fi
  766.        
  767.             if echo $CA_O | grep -q "^$ISSUER$" ; then
  768.                 ok='true'
  769.                 CA_ISSUER_MATCHED="${CA_O}"
  770.             fi
  771.        
  772.             if [ -z "$ok" ] ; then
  773.                 critical "invalid CA ('$ISSUER' does not match '$CA_O' or '$CA_CN')"
  774.             fi
  775.            
  776.         else
  777.        
  778.             CA_ISSUER_MATCHED="${CA_CN}"
  779.        
  780.         fi
  781.        
  782.         ################################################################################
  783.         # check the validity
  784.        
  785.         # we always check expired certificates
  786.         if ! $OPENSSL x509 -in ${CERT} -noout -checkend 0 ; then
  787.             critical "certificate is expired (was valid until $DATE)"
  788.         fi
  789.        
  790.         if [ -n "${CRITICAL}" ] ; then
  791.        
  792.             if ! $OPENSSL x509 -in ${CERT} -noout -checkend $(( ${CRITICAL} * 86400 )) ; then
  793.                 critical "certificate will expire on $DATE"
  794.             fi
  795.        
  796.         fi
  797.        
  798.         if [ -n "${WARNING}" ] ; then
  799.        
  800.             if ! $OPENSSL x509 -in ${CERT} -noout -checkend $(( ${WARNING} * 86400 )) ; then
  801.                 warning "certificate will expire on $DATE"
  802.             fi
  803.        
  804.         fi
  805.        
  806.         ################################################################################
  807.         # check the organization
  808.        
  809.         if [ -n "$ORGANIZATION" ] ; then
  810.        
  811.             ORG=$($OPENSSL x509 -in ${CERT} -subject -noout | sed -e "s/.*\/O=//" -e "s/\/.*//")
  812.        
  813.             if ! echo $ORG | grep -q "^$ORGANIZATION" ; then
  814.                 critical "invalid organization ('$ORGANIZATION' does not match '$ORG')"
  815.             fi
  816.        
  817.         fi
  818.        
  819.         ################################################################################
  820.         # check the organization
  821.        
  822.         if [ -n "$ADDR" ] ; then
  823.        
  824.             EMAIL=$($OPENSSL x509 -in ${CERT} -email -noout)
  825.        
  826.             if [ -n "${VERBOSE}" ] ; then
  827.                 echo "checking email (${ADDR}): ${EMAIL}"
  828.             fi
  829.        
  830.             if [ -z "${EMAIL}" ] ; then
  831.                 critical "the certficate does not contain an email address"
  832.             fi
  833.        
  834.             if ! echo $EMAIL | grep -q "^$ADDR" ; then
  835.                 critical "invalid email ($ADDR does not match $EMAIL)"
  836.             fi
  837.        
  838.         fi
  839.        
  840.         ################################################################################
  841.         # Check if the certificate was verified
  842.        
  843.         if [ -z "${NOAUTH}" ] && grep -q '^verify\ error:' ${ERROR} ; then
  844.        
  845.             if grep -q '^verify\ error:num=[0-9][0-9]*:self\ signed\ certificate' ${ERROR} ; then
  846.        
  847.                 if [ -z "${SELFSIGNED}" ] ; then
  848.                     critical "Cannot verify certificate\nself signed certificate"
  849.                 else
  850.                     SELFSIGNEDCERT="self signed "
  851.                 fi
  852.        
  853.             else
  854.        
  855.                 # process errors
  856.                 details=$(grep  '^verify\ error:' ${ERROR} | sed -e "s/verify\ error:num=[0-9]*:/verification error: /" )
  857.        
  858.                 critical "Cannot verify certificate\n${details}"
  859.        
  860.             fi
  861.            
  862.         fi
  863.        
  864.         ################################################################################
  865.         # If we get this far, assume all is well. :)
  866.        
  867.         # if --altnames was specified we show the specified CN instead of
  868.         # the certificate CN
  869.         if [ -n "${ALTNAMES}" ] && [ -n "${COMMON_NAME}" ] ; then
  870.             CN=${COMMON_NAME}
  871.         fi
  872.        
  873.         if [ -n "${DAYS_VALID}" ] ; then
  874.             # nicer formatting
  875.             if [ ${DAYS_VALID} -gt 1 ] ; then
  876.                 DAYS_VALID=" (expires in ${DAYS_VALID} days)"
  877.             elif [ ${DAYS_VALID} -eq 1 ] ; then
  878.                 DAYS_VALID=" (expires tomorrow)"
  879.             elif [ ${DAYS_VALID} -eq 0 ] ; then
  880.                 DAYS_VALID=" (expires today)"
  881.             elif [ ${DAYS_VALID} -eq -1 ] ; then
  882.                 DAYS_VALID=" (expired yesterday)"
  883.             else
  884.                 DAYS_VALID=" (expired ${DAYS_VALID} days ago)"
  885.             fi
  886.         fi
  887.        
  888.         echo "${SHORTNAME} OK - X.509 ${SELFSIGNEDCERT}certificate for '${CN}' from '${CA_ISSUER_MATCHED}' valid until ${DATE}${DAYS_VALID}${PERFORMANCE_DATA}${LONG_OUTPUT}"
  889.        
  890.         exit 0
  891.        
  892.     }
  893.        
  894.     if [ "${1}" != "--source-only" ]; then
  895.         main "${@}"
  896.     fi
Advertisement
Add Comment
Please, Sign In to add comment