#!/bin/sh
# Simple script to extract x509 certificates and create a JRE cacerts file.
# http://www.linuxfromscratch.org/blfs/view/svn/general/openjdk.html
export LC_ALL=C
# Most POSIX /bin/sh shells have local, although the dash one is buggy.
# Our current varnames doesn't seem to collide, so this is safe for now.
type local || alias local=''

get_args()
    {
        if test -z "${1}" ; then
            showhelp
            exit 1
        fi

        while test -n "${1}" ; do
            case "${1}" in
                -f | --cafile)
                    check_arg $1 $2
                    CAFILE="${2}"
                    shift 2
                    ;;
                -d | --cadir)
                    check_arg $1 $2
                    CADIR="${2}"
                    shift 2
                    ;;
                -o | --outfile)
                    check_arg $1 $2
                    OUTFILE="${2}"
                    shift 2
                    ;;
                -k | --keytool)
                    check_arg $1 $2
                    KEYTOOL="${2}"
                    shift 2
                    ;;
                -s | --openssl)
                    check_arg $1 $2
                    OPENSSL="${2}"
                    shift 2
                    ;;
                -h | --help)
                    showhelp
                    exit 0
                    ;;
                *)
                    showhelp
                    exit 1
                    ;;
            esac
        done
    }

check_arg()
    {
        case "${2}" in
            -*|'')
                echo >&2 "Error:  $1 requires a valid argument."
                exit 1;;
        esac
    }

# The date binary is not reliable on 32bit systems for dates after 2038
mydate()
    {
        local y; local M; local d; local m; local __discard__
        IFS=' ' read M d __discard__ y __discard__ <<EOF
$1
EOF
        if [ ${d} -lt 10 ]; then d="0${d}"; fi

        case "$M" in
            Jan) m="01";;
            Feb) m="02";;
            Mar) m="03";;
            Apr) m="04";;
            May) m="05";;
            Jun) m="06";;
            Jul) m="07";;
            Aug) m="08";;
            Sep) m="09";;
            Oct) m="10";;
            Nov) m="11";;
            Dec) m="12";;
        esac

        certdate="${y}${m}${d}"
    }

showhelp()
    {
        echo "`basename ${0}` creates a valid cacerts file for use with IcedTea."
        echo ""
        echo "        -f  --cafile     The path to a file containing PEM"
        echo "                         formated CA certificates. May not be"
        echo "                         used with -d/--cadir."
        echo ""
        echo "        -d  --cadir      The path to a directory of PEM formatted"
        echo "                         CA certificates. May not be used with"
        echo "                         -f/--cafile."
        echo ""
        echo "        -o  --outfile    The path to the output file."
        echo ""
        echo "        -k  --keytool    The path to the java keytool utility."
        echo ""
        echo "        -s  --openssl    The path to the openssl utility."
        echo ""
        echo "        -h  --help       Show this help message and exit."
        echo ""
        echo "Exit code: 0 = success; 1 = general failure; 2 = wrong usage."
        echo ""
    } >&2

bad_usage()
    {
        echo "ERROR!  $1"
        echo "\`$(basename ${0}) --help\' for more info."
        echo
        exit 2
    } >&2

# Initialize empty variables so that the shell does not pollute the script
CAFILE=""
CADIR=""
OUTFILE=""
OPENSSL=""
KEYTOOL=""
certdate=""
date=""
today=$( date +%Y%m%d )

# Process command line arguments
get_args "${@}"

# Handle common errors
if test -z "${CAFILE}" && test -z "${CADIR}" ; then
    bad_usage "You must provide an x509 certificate store!"
fi

if test -n "${CAFILE}" && test -n "${CADIR}" ; then
    bad_usage "You cannot provide two x509 certificate stores!"
fi

if test -z "${KEYTOOL}" ; then
    bad_usage "You must provide a valid keytool program!"
fi

if test -z "${OPENSSL}" ; then
    bad_usage "You must provide a valid path to openssl!"
fi

if test -z "${OUTFILE}"; then
    bad_usage "You must provide a valid output file!"
fi

# Get on with the work

# If using a CAFILE, split it into individual files in a temp directory
if test -n "${CAFILE}" ; then
    TEMPDIR=$(mktemp -d)
    CADIR=$TEMPDIR

    # Get a list of staring lines for each cert
    CERTLIST=`grep -n "^-----BEGIN" "${CAFILE}" | cut -d ":" -f 1`

    # Get a list of ending lines for each cert
    ENDCERTLIST=`grep -n "^-----END" "${CAFILE}" | cut -d ":" -f 1`

    # Find smallest begin-end areas. These are our certs.
    for certbegin in ${CERTLIST} ; do
        for certend in ${ENDCERTLIST} ; do
            if test "${certend}" -gt "${certbegin}"; then
                break
            fi
        done
        sed -n "${certbegin},${certend}p" "${CAFILE}" > "${CADIR}/${certbegin}.pem"
        keyhash=`${OPENSSL} x509 -noout -in "${CADIR}/${certbegin}.pem" -hash`
        echo "Generated PEM file with hash:  ${keyhash}."
    done
fi

# Write the output file
tempfile=`mktemp`
for cert in `find "${CADIR}" -type f -name "*.pem" -o -name "*.crt"`
do

    # Make sure the certificate date is valid...
    date=$( ${OPENSSL} x509 -enddate -in "${cert}" -noout | sed 's/^notAfter=//' )
    mydate "${date}"
    if test "${certdate}" -lt "${today}" ; then
        echo "${cert} expired on ${certdate}! Skipping..."
        unset date certdate
        continue
    fi
    unset date certdate
    # ls "${cert}"
    certbegin=`grep -n "^-----BEGIN" "${cert}" | cut -d ":" -f 1`
    certend=`grep -n "^-----END" "${cert}" | cut -d ":" -f 1`
    sed -n "${certbegin},${certend}p" "${cert}" > "${tempfile}"
    echo yes | "${KEYTOOL}" -import                     \
                            -alias `basename "${cert}"` \
                            -keystore "${OUTFILE}"      \
                            -storepass 'changeit'       \
                            -file "${tempfile}" 
done
rm "${tempfile}"

if test -n "${TEMPDIR}" ; then
    rm -rf "${TEMPDIR}"
fi
exit 0
