#! /bin/sh
#
#
dir=.
prefix=new
bits=2048
stamp=`date '+%Y%m%d-%H%M%S'`
host=`hostname`
oldkey=

DATE=`date '+%a, %d %b %Y %H:%M:%S %z'`
ID=`whoami 2>/dev/null`
HOST=`hostname 2>/dev/null`
PWDIR=`pwd 2>/dev/null`

DCAVER="DCA-20081216-07"

while :; do
  case "$1" in
  -d )			dir="$2" ; shift 2 ;;
  -o )			prefix="$2" ; shift 2 ;;
  -b )			bits="$2" ; shift 2 ;;
  -k | --inkey )	oldkey="$2" ; shift 2 ;;
  * )			break ;;
  esac
done

case "$#" in 
1 ) certf="$1" ;;
* ) cat <<EOF >&2

Usage: $0 [-h] [-d targetdir] [-o prefix] [-k oldkey] cert.pem

  This script can be run on Unix and Cygwin systems to automatically
  generate a signed rekeying request for your DutchGrid CA certificates.
  You need to provide the file name of your current, STILL VALID,
  certificate as a command-line argument.

  Note: the new certificate will be written to the "targetdir" directory
  and will by default be called "newkey.pem", "newrequest.pem" etcetera.
  The default directory is your current working directory, which would
  now be $PWDIR 
  After you receive the new certificate, you MUST rename the generated
  files to match your current setup, i.e. "newkey.pem" becomes "userkey.pem"
  etcetera. 

  For questions, please contact the CA help desk at ca@dutchgrid.nl

    -k oldkey        filename of your userkey.pem file (default is 
                     derived from the certificate file name)
    -d targetdir     directory where the new key and request are written
    -o prefix        prefix to use for the new keys (default: "new")

EOF
    exit 1 ;;
esac

echo "DCA rekeying script version $DCAVER"

if [ ! -f "$certf" ]; then
  echo "Cannot find your old certificate in $certf" >&2
  echo "Did you specify the proper file? For " >&2
  echo "- personal certificates, it is usually $HOME/.globus/" >&2
  echo "- host certificates, it is usually /etc/grid-security/XXXXcert.pem" >&2
  echo "Please locate your certificate and restart this utility" >&2
  exit 1
fi

if [ ! -d "$dir" ]; then
  echo "The directory $dir does not exist, or is not a directory" >&2
  echo "Please specify a new targer directory, or create it with mkdir" >&2
  exit 1
fi

awktest=`awk 'END { print 1 }' < /dev/null 2>/dev/null`
if [ "$awktest" -ne 1 ]; then
  echo "The AWK system utility could not be found, please install it " >&2
  echo "and only then try again." >&2
  exit 1
fi


openssltest=`openssl version 2>/dev/null | awk '/openssl/i { print $1} '`
if [ x"$openssltest" = x"" ]; then
  echo "The OpenSSL utility could not be found. Please install it first" >&2
  echo "and only then try the rekeying script again" >&2
  exit 1
fi


rq="$dir/$prefix-requestconfig.cnf"
newkey="$dir/${prefix}key.pem"
newreq="$dir/${prefix}cert_request.pem"
newcert="$dir/${prefix}cert.pem"
newmail="$dir/${prefix}rekeypack.txt"

if [ x"$oldkey" = x ]; then
  oldkey=`echo "$certf" | sed -e 's/cert/key/'`
  echo "Notice: private key file not specified, attempting $oldkey" >&2
fi

if [ ! -f "$oldkey" ]; then
  echo "Cannot find old key in $oldkey" >&2
  echo "Please make sure your private key is still available, and specify" >&2
  echo "its location using the --inkey argument to this utility" >&2
  exit 1
fi

[ -f "$newkey" ] && mv "$newkey" "$newkey.bak$$"
[ -f "$newreq" ] && mv "$newreq" "$newreq.bak$$"
[ -f "$newcert" ] && mv "$newcert" "$newcert.bak$$"
[ -f "$newmail" ] && mv "$newmail" "$newmail.bak$$"

# Marcel Merk patch
if ! openssl x509 -noout -in "$certf" >/dev/null 2>&1 ; then
  echo "It seems that $certf is not a certificate file."
  echo "Please call this script with your old certificate file"
  echo "in PEM format. Usually it's called usercert.pem."
  exit 1
fi

subject=`openssl x509 -noout -subject -in "$certf" | sed -e 's/^subject= *//'`
chash=`openssl x509 -noout -hash -in "$certf"`

echo "Using" 
echo "  certificate: $certf"
echo "  private key: $oldkey" 
echo "  subject:     $subject"
echo "  chash:       $chash"
echo ""

emailto=`awk '/^To: / { print substr($0,5) }' "$certf"`
emailaddr=""
while [ x"$emailaddr" = x"" ]; do
  rest="nonsense"
  while [ x"$rest" != x"" ]; do
    if [ x"$emailto" = x"" ]; then
      echo "Please enter your email (to send the new certificate to): " >&2
    else
      echo "Please enter your email (for default $emailto press Enter): " >&2
    fi
    read emailaddr rest
    if [ x"$rest" != x"" ]; then
      echo "Error: Your email address should not contain spaces, please retry" >&2
    fi
  done
  if [ x"$emailaddr" = x"" ]; then
    emailaddr=$emailto
  fi
done

if [ x"$emailaddr" = x"" ]; then
  emailaddr="FAILED-TO-RETRIEVE-ADDRESS@example.org"
fi

echo ""
echo "Who is your preferred (original) Registration Authority?" >&2
echo "  (please give an email address if you know it, but" >&2
echo "   it's also OK to leave this empty, just press Enter)" >&2
read rainfo

cat > "$rq" <<EOFA
[ req ]
default_bits            = $bits
default_keyfile         = $newkey
distinguished_name      = req_distinguished_name
prompt                  = no

[ req_distinguished_name ]
EOFA

openssl x509 -noout -subject -nameopt multiline -nameopt sname -in "$certf" |
( io=0 ;
  while read x ; do case "$x" in
    O* ) echo " $io.$x" ; io=`expr $io + 1` ;;
    CN* ) echo " $x" ;;
    OU* ) echo " $x" ;;
  esac
  done
) >> "$rq"

# who was the original issuer???
issuer=`openssl x509 -noout -issuer -in "$certf"`
case "$issuer" in
*medium-security* )
		ca="CA" ;;
*demo* )	ca="DutchDemo" ;;
* )		echo "The issuer of original cert not recognised" >&2
		echo "$issuer" >&2
		exit 1 ;;
esac

# was old key encrypted
encrypted=`grep -c ENCRYPTED "$oldkey"`
if [ $encrypted -eq 0 ]; then
  desoption="-nodes "
fi


# generate new request
echo "">&2
echo "Please enter a passphrase to protect your NEW private key" >&2
echo "(note that you will have to type this same passphrase twice)" >&2
openssl req $desoption -new -config "$rq" -text -out "$newreq" -keyout "$newkey"
if [ $? -ne 0 -o ! \( -s "$newkey" -a -s "$newreq" \) ]; then
  echo "I could not properly generate a new key/request pair" >&2
  echo "The original files are unchanged, please try again" >&2
  exit 1
fi
chmod go-rwx "$newkey"
chmod u-w "$newkey"
chmod ugo-w "$newreq"

newchash=`openssl x509 -req -noout -hash -signkey /dev/null -in "$newreq" 2>/dev/null`
newmodulus=`openssl req -noout -modulus -in "$newreq" | sed -e 's/^Modulus= *\(......\).*/\1/'`

testtr=`echo "ABC" | tr A-Z a-z 2>/dev/null`
if [ "$testtr" = "abc" ]; then
  newmodulus=`echo $newmodulus | tr A-Z a-z`
fi

echo "Generated request file is '$newreq':"
ls -lad "$newreq" | sed -e 's/^/  /'
echo "Allocated reference tag for new request is $newchash-$newmodulus"

if [ x"$newchash" = x"" ]; then
  echo "Error: the generated request file is not valid. Please retry." >&2
  exit 1
fi
if [ x"$newmodulus" = x"" ]; then
  echo "Error: the modulus could not be extracted from the request. Sorry." >&2
  exit 1
fi


# put the request in a signed blob
cat > "$newmail" <<EOFB
===== DutchGrid Renewal Package Version 1.0 =====

  Comment: Mail this message to the DutchGrid Certification Authority 
  Comment: at ca@dutchgrid.nl

  Email address:  $emailaddr
  Timestamp:      $stamp
  Host:           $host
  CA target:      $ca
  RApreference:   $rainfo

  Renew-cwd:      $PWDIR
  Renew-targetd:  $dir
  Renew-DES-opt:  $desoption
  DCA-Version:    $DCAVER

EOFB
cat "$newreq" >> "$newmail" 

echo "***" >&2
echo "*** please enter the passphrase for your OLD private key" >&2
echo "*** in order to sign your e-mail request to the CA" >&2
openssl smime -sign -in "$newmail" -out "$newmail.mime" \
	-signer "$certf" -inkey "$oldkey" -text

if [ `grep -c 'Content-Type: multipart/signed' "$newmail.mime"` -ne 1 ] ; then
  echo "" >&2
  echo "!!! WARNING: an invalid S/MIME message may have been generated" >&2
  echo "             please review the message in $newmail - " >&2
  echo "             If something in this file looks like an error, please " >&2
  echo "             mail the contents of this file to the CA in addition " >&2
  echo "             to mailing the request as instructed" >&2
  if [ ! -s "$newmail.mime" ]; then
    echo "" >&2
    echo "The new request is empty, and does not contain a valid request." >&2
    echo "Please review the error conditions above, or contact the CA" >&2
    echo "helpdesk at <ca@dutchgrid.nl> for support. " >&2
    echo "" >&2
    echo "This rekeying tool will now end." >&2
    echo "" >&2
    exit 1
  fi
  echo "" >&2
  echo "             Note that the request must still be sent off to the CA" >&2
  echo "             Sorry for the trouble." >&2
  echo "" >&2
  preserve=1
else
  preserve=0
fi

rm -f "$newmail"

echo "To: ca@nikhef.nl" > "$newmail"
echo "Subject: [$ca] Renewal for $subject" >> "$newmail"
echo "Date: $DATE" >> "$newmail"
echo "X-Renew-WhoAmI: $ID" >> "$newmail"
echo "X-Renew-Hostname: $HOST" >> "$newmail"
echo "X-Renew-Working-Directory: $PWDIR" >> "$newmail"
echo "X-Renew-Target-Directory: $dir" >> "$newmail"
echo "X-Renew-DES-Option: $desoption" >> "$newmail"
echo "X-Renew-Script-Version: $DCAVER" >> "$newmail"
echo "" >> "$newmail"
echo "Submit this packed request to the DutchGrid CA via email " >> "$newmail"
echo "or web upload. See http://ca.dutchgrid.nl/ for details." >> "$newmail"
echo "" >> "$newmail"
echo "===== BEGIN DUTCHGRID RENEWAL BLOB =====" >> "$newmail"
openssl base64 -in "$newmail.mime" -e >> "$newmail"
echo "===== END DUTCHGRID RENEWAL BLOB =====" >> "$newmail"

[ "$preserve" -ne 1 ] && rm "$newmail.mime"

echo "" >&2
echo "You have successfully generated your renewal (rekeying) request." 
echo "The renewal (rekeying) request is stored in the file $newmail," 
echo "and you MUST now do either of the following:"
echo ""
echo "- send file $newmail by e-mail to ca@dutchgrid.nl, preferably" 
echo "  IN-LINE and not as an attachment (use copy-paste please)"
echo ""
echo "- upload the file $newmail using the renewal web interface at"
echo "    http://ra.dutchgrid.nl/ra/public/submit"
echo ""
echo "You will then receive a confirmation email within a few minutes"
echo "IF YOU DO NOT GET THE CONFIRMATION, please email or submit the"
echo "rekeying request again. The request is NOT sent automatically."
echo ""
echo "Your rekey request will be sent to your RA for acknowledgement,"
echo "so please be patient while your RA processes your request."
echo ""
echo "     Thank you for using the DutchGrid CA Service."
echo ""
