#!/bin/sh
#
# This server pre script was contributed by Jason Haar.

(
cat<<EOF

This burp script is executed before any client command is authorized. If this
script exits with a non-zero value, the client command FAILS.

By default, this script is responsible for CRL and cert age checks. At the end
it will execute $BURP_EXTRA_SCRIPT (third user argument) if present and
executable.
Any local changes should be added to that file instead of alterations made to
this script.

EOF
)>/dev/null

export prog="$(basename $0)"

logEvent()
{
	logger -t "$prog[$X509_PEER_SERIALNUMBER]" "$*"
	echo "$*"
}

export error_peerDate=101
export error_noCRLs=102
export error_revoked=103
export error_crlExpired=104
export error_crlError=105
export error_crlNoArgs=106
export error_crlNoDir=107

usage()
{
	logEvent "usage: $prog <preorpost> <action> <client> <reserved4> <reserved5> <crl dir> <server config file> <optional extra script>"
	exit $error_crlNoArgs
}

# Whether it is a pre or post script.
export preorpost="$1" ; shift
# What the client requested. Ignored.
export action="$1" ; shift
# The burp client name. Ignored.
export client="$1" ; shift
export reserved4="$1" ; shift
export reserved5="$1" ; shift

export BURP_CRLDIR="$1"
export BURP_SERVER_CONFIG="$2"
export BURP_EXTRA_SCRIPT="$3"

[ -z "$BURP_CRLDIR" ] && usage
[ -z "$BURP_SERVER_CONFIG" ] && usage

export SERVER_CERT="`egrep '^ssl_cert[^_]' $BURP_SERVER_CONFIG 2>/dev/null|awk '{print $NF}'`"

#this should never not work
if [ "$X509_PEER_NOT_BEFORE" = "" ] ; then
	logEvent "cannot detect peer cert notBefore date field"
	exit $error_peerDate
fi
#this should never not work
if [ "$X509_PEER_NOT_AFTER" = "" ] ; then
        logEvent "cannot detect peer cert notAfter date field"
	exit $error_peerDate
fi

PEER_DATE_BEGINS=`date --date "$X509_PEER_NOT_BEFORE" +%s`
PEER_DATE_ENDS=`date --date "$X509_PEER_NOT_AFTER" +%s`

NOW=`date +%s`


#if this surprises you and the time checks fail - look at the clock!
if [ $NOW -lt $PEER_DATE_BEGINS ] ; then
	logEvent "EXPIRATION: peer cert not usable until $X509_PEER_NOT_BEFORE"
	exit $error_peerDate
fi

if [ $NOW -gt $PEER_DATE_ENDS ] ; then
        logEvent "EXPIRATION: peer cert expired on $X509_PEER_NOT_AFTER"
	exit $error_peerDate
fi

#crls are defined within the signed certs themselves, if there isn't one, then
#no need for CRL checks
export CRL_POINTS=`(openssl  x509 -noout -inform PEM -text -in $SERVER_CERT 2>/dev/null|| openssl  x509 -inform DER -noout -text -in $SERVER_CERT 2>/dev/null) |grep URI:http|sed -e 's/^.*URI:http/http/g'`

updateCRL()
{
	downloadedCRL=0
        mkdir -p $BURP_CRLDIR
	cd $BURP_CRLDIR
	CRL_FILE="`echo $X509_ISSUER_CN|sed 's/[^0-9a-zA-Z]/_/g'`.crl"
	CRL_AGE=`stat -c %Y "$CRL_FILE" 2>/dev/null`
	CRL_AGE=${CRL_AGE:-0}
	if [ ! -f "$CRL_FILE" -o `expr $NOW - $CRL_AGE` -gt 3600 ] ; then
         for crl in $CRL_POINTS
         do
          if [ $downloadedCRL -eq 0 ] ; then
                wget -O - $crl > tmpfile 2>/dev/null
                if [ -s tmpfile ] ; then
                        mv -f tmpfile "$CRL_FILE"
                        downloadedCRL=1
                fi
          fi
         done
         if [ $downloadedCRL -eq 0 ] ; then
                logEvent "CRL: failed to update CRL cache"
                #don't error on this
         fi
	fi
}


if [ "$CRL_POINTS" = "" ] ; then
	logEvent "CRL: no http CRL points - skipping CRL checks"
else
	updateCRL > /dev/null 2>&1&
	if [ "`/bin/ls $BURP_CRLDIR/*.crl 2>/dev/null`" = "" ] ; then
		#wait 10sec in case this is the first time updateCRL has run
		sleep 10
		if [ "`/bin/ls $BURP_CRLDIR/*.crl 2>/dev/null`" = "" ] ; then
			logEvent "CRL: failed crl checks - no CRL files in $BURP_CRLDIR"
			exit $error_noCRLs
		fi
	fi
	FOUND_CRL=0
	for crl in $BURP_CRLDIR/*.crl 
	do
	 if [ "`(openssl crl -in $crl -inform DER -text -noout 2>/dev/null || openssl crl -in $crl -inform PEM -text -noout 2>/dev/null)|grep Issuer:|egrep \"$X509_ISSUER_CN\"|egrep \"$X509_ISSUER_emailAddress\"`" != "" ] ; then
		FOUND_CRL=1
		if [ "`(openssl crl -in $crl -inform DER -text -noout 2>/dev/null || openssl crl -in $crl -inform PEM -text -noout 2>/dev/null)|egrep \"Serial Number: $X509_PEER_SERIALNUMBER\$\"`" != "" ] ; then
			logEvent "CRL: failed crl checks - serial $X509_PEER_SERIALNUMBER for $X509_PEER_CN revoked"
			exit $error_revoked
		fi
	 fi
	 CRL_EXPIRES=`(openssl crl -in $crl -inform DER  -noout -nextupdate  || openssl crl -in $crl -inform PEM -noout -nextupdate  )|sed 's/nextUpdate=//gi'`
	 CRL_DATE=`date --date "$CRL_EXPIRES" +%s`
	 if [ $NOW -gt $CRL_DATE ] ; then
		logEvent "CRL: failed crl checks - CRL for \"$X509_ISSUER_CN\" out-of-date and no update available (crl file expired $CRL_EXPIRES)"
		exit $error_crlExpired
	 fi
	done

	if [ "$FOUND_CRL" = "0" ] ; then
		logEvent "CRL: failed crl checks - no CRL file matching ISSUER \"$X509_ISSUER_CN\""
		exit $error_crlError
	fi
fi
	
##
## All CRL and cert checks completed, carry on
##

logEvent "INFO: connect from $X509_PEER_CN"

if [ -n "$BURP_EXTRA_SCRIPT" -a -x "$BURP_EXTRA_SCRIPT" ] ; then
	exec "$BURP_EXTRA_SCRIPT"
else
	exit 0
fi
