#! /bin/bash
# $Id: etoken-mkproxy.in,v 1.3 2007/06/26 12:00:58 dennisvd Exp $

function debug()
{
    if [ -n "${DEBUG:-}" ]
    then
        echo -e "$@"
    fi
}

function info()
{
    if [ -z "${QUIET:-}" ]
    then
        echo -e "$@"
    fi
}

function run_cmd()
{
    if [ -n "${DEBUG:-}" ]
    then
        echo -e "run_cmd: $@"
    fi
    if [ -n "${QUIET:-}" ]
    then
        cmd_output=`eval "$@" 2>&1`
        exitcode=$?
        if [ $exitcode -ne 0 ]
        then
            echo "$cmd_output" >&2
        fi
    else
        eval "$@"
        exitcode=$?
    fi
    return $exitcode
}


VERSION="etoken-mkproxy version 1.32"
USAGE="\
This script will generate a X509 grid proxy using a public/private
key pair found on an attached Aladdin eToken PRO.

  Options
  [--help]          Displays usage.
  [--version]       Displays version.
  [--debug]         Enables extra debug output.
  [--quiet]         Quiet mode, minimal output.
  [--limited]       Creates a limited globus proxy.
  [--old]           Creates a legacy globus proxy (default).
  [--gt3]           Creates a pre-RFC3820 compliant proxy.
  [--rfc]           Creates a RFC3820 compliant proxy.
  [--days=N]        Number of days the proxy is valid.
  [--path-length=N] Allow a chain of at most N proxies to be generated
                    from this one (default=2).
  [--bits=N]        Number of bits in key (512, 1024, 2048, default=512).
  [--out=proxyfile] Non-standard location of new proxy cert.

  [--slot=N]        Slot number where eToken is located (default=0).
  [--label=string]  (Part of) label of X509 certificate on eToken.
  [--id=string]     (Part of) ID of X509 certificate on eToken.
"

LABEL=
ID=
DEBUG=
QUIET=

while [ $# -gt 0 ]
do
    case "$1" in
		(--slot|-s)		SLOT=$2
						shift
						;;
		(--slot=*)		SLOT=${1##--slot=}
						;;
		(--label|-l)	LABEL=$2
						shift
						;;
		(--label=*)		LABEL=${1##--label=}
						;;
		(--id|-i)		ID=$2
						shift
						;;
		(--id=*)		ID=${1##--id=}
						;;
		(--days|-d)		DAYS=$2
						shift
						;;
		(--days=*)		DAYS=${1##--days=}
						;;
		(--out|-o)		X509_USERPROXY=$2
						shift
						;;
		(--out=*)		X509_USERPROXY=${1##--proxy=}
						;;
		(--pcpl)		PROXY_PATHLENGTH=$2
						shift
						;;
		(--pcpl=*)		PROXY_PATHLENGTH=${1##--pcpl=}
						;;
		(--path-length)		PROXY_PATHLENGTH=$2
						shift
						;;
		(--path-length=*)	PROXY_PATHLENGTH=${1##--path-length=}
						;;
		(--version|-v)	echo "$VERSION"
						exit 0
						;;
		(--debug)		DEBUG=1
						QUIET=
						;;
		(--quiet|-q)	QUIET=1
						DEBUG=
						;;
		(--limited)		PROXY_POLICY=limited_policy
						;;
		(--old)			PROXY_STYLE=legacy_proxy
						;;
		(--gt3)			PROXY_STYLE=globus_proxy
						;;
		(--rfc)			PROXY_STYLE=rfc3820_proxy
						;;
		(--bits|-b)		BITS=$2
						shift
						;;
		(--bits=*)		BITS=${1##--bits=}
						;;
	 	(*)				echo "$VERSION"
						echo "$USAGE"
						exit 0	
						;;
	esac
	shift
done

info "Starting Aladdin eToken PRO proxy generation"

# Apply defaults
SLOT=${SLOT:-0}
DAYS=${DAYS:-1}
PROXY_SUGGEST=/tmp/x509up_u`id -u`
PROXY="${X509_USERPROXY:-$PROXY_SUGGEST}"
# the next 3 variables are referenced from openssl.cnnf
export PROXY_PATHLENGTH=${PROXY_PATHLENGTH:-2}
export PROXY_POLICY=${PROXY_POLICY:-normal_policy}
export PROXY_STYLE=${PROXY_STYLE:-legacy_proxy}
BITS=${BITS:-512}

debug "Output File: $PROXY"

MYDIR=${0%/*}
if [ "$MYDIR" = "${MYDIR#/}" ]
then
    MYDIR=$PWD/$MYDIR
fi
MYDIR=${MYDIR%/*}

#export LD_LIBRARY_PATH="$MYDIR/lib:$LD_LIBRARY_PATH"
export PKCS11_ENG="/usr/lib/engines/engine_pkcs11.so"
export PKCS11_MOD="/usr/lib/libetpkcs11.so"
export OPENSSL="/usr/bin/openssl"
export OPENSSL_CONF="/etc/etoken-pro-support/openssl.cnf"

if [ ! -r "${PKCS11_ENG:-}" ]
then
    echo "Error: cannot find PKCS11 engine (engine_pkcs11) to use." >&2
	exit 2
fi
if [ ! -r "${PKCS11_MOD:-}" ]
then
    echo "Error: cannot find PKCS11 module (etpkcs11) to use." >&2
	exit 3
fi
 
PKCS11TOOL="/usr/bin/pkcs11-tool --slot $SLOT --module $PKCS11_MOD"
if [ -n "$DEBUG" ]
then
    PKCS11TOOL="$PKCS11TOOL -v -v -v"
fi
debug "running $PKCS11TOOL -O"
ETOKEN_CONTENTS=`$PKCS11TOOL -O`
#ETOKEN_CONTENTS=`cat tt`
if [ $? -ne 0 ]
then
    echo "Warning: cannot read eToken. Aborting." >&2
    exit 4
fi
# Look for a X.509 certificate object with an exact label 
LABEL=`echo $LABEL | sed -e 's/\//\\\\\\//g'`
CERT_LABEL=`echo "$ETOKEN_CONTENTS" | \
            sed -n "/Certificate Object, type = X.509 cert:/N;\
                    s/.*label: *\($LABEL\)/\1/p" | \
            head -1`
if [ -n "$LABEL" -a -z "$CERT_LABEL" ]
then
    # Look for a X.509 certificate object with a specific label 
    CERT_LABEL=`echo "$ETOKEN_CONTENTS" | \
                sed -n "/Certificate Object, type = X.509 cert:/N;\
                        s/.*label: *\(.*$LABEL.*\)/\1/p" | \
                head -1`
fi

if [ -n "$LABEL" -a -z "$CERT_LABEL" ]
then
    echo "No certificates matching label='$LABEL' found on eToken in slot $SLOT" >&2
    exit 5
fi

if [ -z "$ID" ]
then
# No ID specified, look for the matching certificate ID from label
    LABEL=`echo $CERT_LABEL | sed -e 's/\//\\\\\\//g'`
    CERT_ID=`echo "$ETOKEN_CONTENTS" | \
             sed -n "/Certificate Object, type = X.509 cert:/N;N;N;\
                     s/.*label: *$LABEL.*ID: *\(.*\)/\1/p" | \
             head -1`
else
# Look for a X.509 certificate object with an exact ID
    ID=`echo $ID | sed -e 's/\//\\\\\\//g'`
    CERT_ID=`echo "$ETOKEN_CONTENTS" | \
             sed -n "/Certificate Object, type = X.509 cert:/N;N;N;\
                     s/.*ID: *\($ID\)/\1/p" | \
             head -1`
    if [ -z "$CERT_ID" ]
    then
# Look for a X.509 certificate object with a specific ID
        CERT_ID=`echo "$ETOKEN_CONTENTS" | \
                 sed -n "/Certificate Object, type = X.509 cert:/N;N;N;\
                         s/.*ID: *\(.*$ID.*\)/\1/p" | \
                 head -1`
    fi
fi

if [ -n "$ID" -a -z "$CERT_ID" ]
then
    echo "No certificates matching id='$ID' found on eToken in slot $SLOT" >&2
    exit 6
fi

info "Found X.509 certificate on eToken:"
info "  label: $CERT_LABEL"
info "  id:    $CERT_ID"

PROXYREQ=`mktemp proxyrequest.XXXXXX`
PROXYKEY=`mktemp proxykey.XXXXXX`
PROXYCERT=`mktemp proxykey.XXXXXX`
PROXYUSERCERT=`mktemp proxyusercert.XXXXXX`
PROXYUSERDER=`mktemp proxyuserder.XXXXXX`
RND=`expr $RANDOM \* $RANDOM`


# Using a pipe screws up under Cygwin!!
debug "extracting public certificate from token"
$PKCS11TOOL --type cert -r --id "$CERT_ID" -o $PROXYUSERDER
run_cmd $OPENSSL x509 -in $PROXYUSERDER -inform der -out $PROXYUSERCERT

debug "running 'openssl x509 -noout -in $PROXYUSERCERT -subject'"
SUBJ=`$OPENSSL x509 -noout -in $PROXYUSERCERT -subject | sed -e s'/subject= //'`
if [ "$PROXY_STYLE" = "legacy_proxy" ]
then
    if [ "$PROXY_POLICY" = "normal_policy" ]
    then
        PROXY_SUBJ="proxy"
    else
        PROXY_SUBJ="limited proxy"
    fi
    PROXY_EXTENSIONS=""
else
    # for non-legacy proxies the proxy policy (limited, normal) is implemented
    # using X509v3 extensions, which are loaded from the 'extfile'
    PROXY_SUBJ="$RND"
    PROXY_EXTENSIONS="-extfile $OPENSSL_CONF"
fi

info "Your identity: $SUBJ"

run_cmd $OPENSSL req -new -nodes -keyout $PROXYKEY -out $PROXYREQ \
	-newkey rsa:$BITS -subj \"$SUBJ/CN=$PROXY_SUBJ\"

run_cmd $OPENSSL x509 -req \
         -engine pkcs11 -CAkeyform engine \
         -in $PROXYREQ \
         -CA $PROXYUSERCERT \
         -CAkey $CERT_ID \
         -out $PROXYCERT \
         -set_serial $RND -sha1 -days "$DAYS" \
         $PROXY_EXTENSIONS
exitcode=$?

if [ $exitcode -eq 0 ]
then
    cat $PROXYCERT $PROXYKEY $PROXYUSERCERT > "$PROXY"
    chmod 600 "$PROXY"

    # simple proxy validation
    end_date=`$OPENSSL x509 -noout -enddate -in "$PROXY" | sed 's/notAfter=//'`
    info "Your proxy is valid until: `date -d \"$end_date\"`"
fi

rm $PROXYCERT $PROXYKEY $PROXYREQ $PROXYUSERCERT $PROXYUSERDER

exit $exitcode

