#!/bin/sh
#
#
# Copyright (C) 2007 Paul Wouters <paul@xelerance.com>
# Copyright (C) 2012 Paul Wouters <paul@libreswan.org>
#
# Setup a variety of X509 certificates for testcases

OUTDIR=`dirname $0`
pushd $OUTDIR

TOUCH=`which touch`
EXPECT=`which expect`

if [ -z $TOUCH ]
then
       echo "touch needed for dist_certs, not found in path"
       exit 1
fi

if [ -z $EXPECT ]
then
       echo "expect needed for dist_certs, not found in path"
       exit 1
fi

# Clean
rm -f reqs/* certs/* keys/* newcerts/* cacerts/* crls/* pkcs12/mainca/* pkcs12/otherca/* index.txt* serial* nss-pw crlnumber

echo -n "foobar" > nss-pw
# Prep
mkdir -p certs crls newcerts keys reqs pkcs12/mainca pkcs12/otherca cacerts
$TOUCH index.txt
echo "01" > serial
echo "01" > crlnumber
export OPENSSL_CONF=./openssl.cnf

# Get some useful dates. Blame openssl for not being Y2K compatible with its -startdate
YEAR=`date +%y`
MONTH=`date +%m`
MONTHMINONE=$MONTH
DAY=`date +%d`
DAYMINONE=`expr $DAY - 2`
if [ $DAYMINONE -lt 10 ]
then
	DAYMINONE="0$DAYMINONE"
	if [ $DAYMINONE = "00" ]
	then
		# we dont care about 30 vs 31 or 28
		DAYMINONE="28"
		MONTHMINONE=`expr $MONTH - 1`
		if [ $MONTHMINONE -lt 10 ]
		then
			MONTHMINONE="0$MONTHMINONE"
			if [ $MONTHMINONE = "00" ]
			then
				MONTHMINONE="12"
				# 2001 is fine - why check the tests on New Year anyway?
				YEAR="01"
			fi
		fi
	fi
fi
TODAY="$YEAR$MONTH$DAY"
TWODAYSAGO="$YEAR$MONTHMINONE$DAYMINONE"
START="$TWODAYSAGO"000000Z
END="$TWODAYSAGO"235959Z
# future < 10*365 (length of CA validity)
FUTURE="$[ $YEAR + 1]$MONTH$DAY"000000Z
FUTUREEND="$[ $YEAR + 2]$MONTH$DAY"000000Z

echo "------------------------------------------"
echo "Certificate dates being used for this run:"
echo ""
echo "Today: $TODAY"
echo "Two days ago: $TWODAYSAGO"
echo "Start: $START"
echo "End: $END"
echo "Future: $FUTURE"
echo "Year: $YEAR"
echo "Month: $MONTH"
echo "Day: $DAY"
echo "Month-1: $MONTHMINONE"
echo "Day-1: $DAYMINONE"
echo "------------------------------------------"
echo ""

# Generate CA's
for cauth in mainca otherca
do
openssl genrsa -passout pass:foobar -des3 -out keys/$cauth.key 1024
openssl rsa -in keys/$cauth.key -out keys/$cauth.key -passin pass:foobar
# use defaults to ensure the same values for all certs based on openssl.cnf
# req -x509 does not accept -startdate, this might invalidate certs?
$EXPECT  <<EOF
spawn openssl req -x509 -days 3650 -newkey rsa:1024 -keyout keys/$cauth.key -out cacerts/$cauth.crt -passin pass:foobar -passout pass:foobar
expect "Country Name"
send "\n"
expect "State"
send "\n"
expect "Locality"
send "\n"
expect "Organization"
send "\n"
expect "Organizational"
send "\n"
expect "Common"
send "Libreswan test CA for $cauth\n"
expect "Email"
send "testing@libreswan.org\n"
wait
EOF
done

# Generate machine keys/certs
for machine in east west sunset sunrise north south road pole park beet carrot nic japan revoked notyetvalid notvalidanymore signedbyotherca spaceincn bigkey wrongdnorg unwisechar hashsha2 wrongdnnum cnofca
do
# generate host key/cert
$EXPECT  <<EOF
spawn openssl req -newkey rsa:1024 -passin pass:foobar -passout pass:foobar -keyout keys/$machine.key -out reqs/$machine.req
expect "Country Name"
send "\n"
expect "State"
send "\n"
expect "Locality"
send "\n"
expect "Organization"
send "\n"
expect "Organizational"
send "\n"
expect "Common"
send "$machine.testing.libreswan.org\n"
expect "Email"
send "testing@libreswan.org\n"
expect "challenge"
send "\n"
expect "optional"
send "\n"
wait
EOF
# sign machine cert
openssl ca -batch -in reqs/$machine.req -startdate $START -enddate $FUTURE -out certs/$machine.crt -notext -cert cacerts/mainca.crt -keyfile keys/mainca.key  -passin pass:foobar
# package in pkcs#12
openssl pkcs12 -export -inkey keys/$machine.key -in certs/$machine.crt -name "$machine" -certfile cacerts/mainca.crt -caname "mainca" -out pkcs12/mainca/$machine.p12 -passin pass:foobar -passout pass:foobar
done

# Special Cases follow

# large rsa key
$EXPECT  <<EOF
spawn openssl req -newkey rsa:2048 -passin pass:foobar -passout pass:foobar -keyout keys/bigkey.key -out reqs/bigkey.req
expect "Country Name"
send "\n"
expect "State"
send "\n"
expect "Locality"
send "\n"
expect "Organization"
send "\n"
expect "Organizational"
send "\n"
expect "Common"
send "bigkey.testing.libreswan.org\n"
expect "Email"
send "testing@libreswan.org\n"
expect "challenge"
send "\n"
expect "optional"
send "\n"
wait
EOF
openssl ca -batch -in reqs/bigkey.req -startdate $START -days 365 -out certs/bigkey.crt -notext -cert cacerts/mainca.crt -keyfile keys/mainca.key  -passin pass:foobar

# cert that is not yet valid
openssl ca -batch -in reqs/notyetvalid.req -startdate $FUTURE -enddate $FUTUREEND -out certs/notyetvalid.crt -notext -cert cacerts/mainca.crt -keyfile keys/mainca.key  -passin pass:foobar
openssl pkcs12 -export -inkey keys/notyetvalid.key -in certs/notyetvalid.crt -name "$machine" -certfile cacerts/mainca.crt -caname "otherca" -out pkcs12/otherca/notyetvalid.p12 -passin pass:foobar -passout pass:foobar

# cert not valid anymore
openssl ca -batch -in reqs/notvalidanymore.req -startdate $START -enddate $END -out certs/notvalidanymore.crt -notext -cert cacerts/mainca.crt -keyfile keys/mainca.key  -passin pass:foobar
openssl pkcs12 -export -inkey keys/notvalidanymore.key -in certs/notvalidanymore.crt -name "$machine" -certfile cacerts/mainca.crt -caname "otherca" -out pkcs12/otherca/notvalidanymore.p12 -passin pass:foobar -passout pass:foobar

# signed by other ca
rm -f certs/signedbyotherca.crt pkcs12/mainca/signedbyother.p12
openssl ca -batch -in reqs/signedbyotherca.req -startdate $START -days 365 -out certs/signedbyotherca.crt -notext -cert cacerts/otherca.crt -keyfile keys/otherca.key  -passin pass:foobar
openssl pkcs12 -export -inkey keys/signedbyotherca.key -in certs/signedbyotherca.crt -name "$machine" -certfile cacerts/otherca.crt -caname "otherca" -out pkcs12/otherca/signedbyotherca.p12 -passin pass:foobar -passout pass:foobar

# wrong DN (Organisation is different)
$EXPECT  <<EOF
spawn openssl req -newkey rsa:1024 -passin pass:foobar -passout pass:foobar -keyout keys/wrongdnorg.key -out reqs/wrongdnorg.req
expect "Country Name"
send "\n"
expect "State"
send "\n"
expect "Locality"
send "\n"
expect "Organization"
send "Traitors Inc\n"
expect "Organizational"
send "\n"
expect "Common"
send "wrongdnorg.testing.libreswan.org\n"
expect "Email"
send "testing@libreswan.org\n"
expect "challenge"
send "\n"
expect "optional"
send "\n"
wait
EOF
openssl ca -batch -in reqs/wrongdnorg.req -startdate $START -days 365 -out certs/wrongdnorg.crt -notext -cert cacerts/mainca.crt -keyfile keys/mainca.key  -passin pass:foobar
openssl pkcs12 -export -inkey keys/wrongdnorg.key -in certs/wrongdnorg.crt -name "wrongdnorg" -certfile cacerts/mainca.crt -caname "mainca" -out pkcs12/mainca/wrongdnorg.p12 -passin pass:foobar -passout pass:foobar

# wrong number of DN's
$EXPECT  <<EOF
spawn openssl req -newkey rsa:1024 -passin pass:foobar -passout pass:foobar -keyout keys/wrongdnnum.key -out reqs/wrongdnnum.req
expect "Country Name"
send "\n"
expect "State"
send "\n"
expect "Locality"
send "\n"
expect "Organization"
send "\n"
expect "Organizational"
send ".\n"
expect "Common"
send "wrongdnnum.testing.libreswan.org\n"
expect "Email"
send "testing@libreswan.org\n"
expect "challenge"
send "\n"
expect "optional"
send "\n"
wait
EOF
openssl ca -batch -in reqs/wrongdnnum.req -startdate $START -days 365 -out certs/wrongdnnum.crt -notext -cert cacerts/mainca.crt -keyfile keys/mainca.key  -passin pass:foobar
openssl pkcs12 -export -inkey keys/wrongdnorg.key -in certs/wrongdnorg.crt -name "wrongdnorg" -certfile cacerts/mainca.crt -caname "mainca" -out pkcs12/mainca/wrongdnorg.p12 -passin pass:foobar -passout pass:foobar

# Unwise charachters
$EXPECT  <<EOF
spawn openssl req -newkey rsa:1024 -passin pass:foobar -passout pass:foobar -keyout keys/unwisechar.key -out reqs/unwisechar.req
expect "Country Name"
send "\n"
expect "State"
send "\n"
expect "Locality"
send "\n"
expect "Organization"
send "\n"
expect "Organizational"
send "\n"
expect "Common"
send "unwisechar ~!@#$%^&*()-_=+;:/?<>.testing.libreswan.org\n"
expect "Email"
send "testing@libreswan.org\n"
expect "challenge"
send "\n"
expect "optional"
send "\n"
wait
EOF
openssl ca -batch -in reqs/unwisechar.req -startdate $START -days 365 -out certs/unwisechar.crt -notext -cert cacerts/mainca.crt -keyfile keys/mainca.key  -passin pass:foobar
openssl pkcs12 -export -inkey keys/unwisechar.key -in certs/unwisechar.crt -name "unwisechar" -certfile cacerts/mainca.crt -caname "mainca" -out pkcs12/mainca/unwisechar.p12 -passin pass:foobar -passout pass:foobar

# Using SHA2
$EXPECT  <<EOF
spawn openssl req -newkey rsa:1024  -nodes -sha256 -passin pass:foobar -passout pass:foobar -keyout keys/hashsha2.key -out reqs/hashsha2.req
expect "Country Name"
send "\n"
expect "State"
send "\n"
expect "Locality"
send "\n"
expect "Organization"
send "\n"
expect "Organizational"
send "\n"
expect "Common"
send "hashsha2\n"
expect "Email"
send "testing@libreswan.org\n"
expect "challenge"
send "\n"
expect "optional"
send "\n"
wait
EOF
openssl ca -batch -in reqs/hashsha2.req -startdate $START -days 365 -out certs/hashsha2.crt -notext -cert cacerts/mainca.crt -keyfile keys/mainca.key  -passin pass:foobar
openssl pkcs12 -export -inkey keys/hashsha2.key -in certs/hashsha2.crt -name "hashsha2" -certfile cacerts/mainca.crt -caname "mainca" -out pkcs12/mainca/hashsha2.p12 -passin pass:foobar -passout pass:foobar

# Space in CN
$EXPECT  <<EOF
spawn openssl req -newkey rsa:1024 -passin pass:foobar -passout pass:foobar -keyout keys/spaceincn.key -out reqs/spaceincn.req
expect "Country Name"
send "\n"
expect "State"
send "\n"
expect "Locality"
send "\n"
expect "Organization"
send "\n"
expect "Organizational"
send "\n"
expect "Common"
send "space invaders.testing.libreswan.org\n"
expect "Email"
send "testing@libreswan.org\n"
expect "challenge"
send "\n"
expect "optional"
send "\n"
wait
EOF
openssl ca -batch -in reqs/spaceincn.req -startdate $START -days 365 -out certs/spaceincn.crt -notext -cert cacerts/ca.crt -keyfile keys/mainca.key  -passin pass:foobar
openssl pkcs12 -export -inkey keys/spaceincn.key -in certs/spaceincn.crt -name "spaceincn" -certfile cacerts/mainca.crt -caname "mainca" -out pkcs12/mainca/spaceincn.p12 -passin pass:foobar -passout pass:foobar

# CN of client cert is the same as the CA's CN
$EXPECT  <<EOF
spawn openssl req -newkey rsa:1024 -passin pass:foobar -passout pass:foobar -keyout keys/cnofca.key -out reqs/cnofca.req
expect "Country Name"
send "\n"
expect "State"
send "\n"
expect "Locality"
send "\n"
expect "Organization"
send "\n"
expect "Organizational"
send "\n"
expect "Common"
send "Libreswan test CA for mainca\n"
expect "Email"
send "testing@libreswan.org\n"
expect "challenge"
send "\n"
expect "optional"
send "\n"
wait
EOF
openssl ca -batch -in reqs/cnofca.req -startdate $START -days 365 -out certs/cnofca.crt -notext -cert cacerts/mainca.crt -keyfile keys/mainca.key  -passin pass:foobar
openssl pkcs12 -export -inkey keys/cnofca.key -in certs/cnofca.crt -name "cnofca" -certfile cacerts/mainca.crt -caname "mainca" -out pkcs12/mainca/cnofca.p12 -passin pass:foobar -passout pass:foobar


# Revoke and generate CRL
openssl ca -gencrl -crldays 15 -out crls/cacrlvalid.pem  -keyfile keys/mainca.key -cert cacerts/mainca.crt -passin pass:foobar
openssl ca -gencrl -startdate $START -enddate $END -out crls/cacrlexpired.pem  -keyfile keys/mainca.key -cert cacerts/mainca.crt -passin pass:foobar
openssl ca -gencrl -startdate $FUTURE -enddate $FUTUREEND -out crls/cacrlnotyetvalid.pem  -keyfile keys/mainca.key -cert cacerts/mainca.crt -passin pass:foobar
openssl ca -gencrl -crldays 15 -out crls/othercacrl.pem  -keyfile keys/otherca.key -cert cacerts/otherca.crt -passin pass:foobar
openssl ca -revoke certs/revoked.crt -keyfile keys/mainca.key -cert cacerts/mainca.crt -passin pass:foobar
openssl ca -gencrl -crldays 15 -out crls/cacrlvalid.pem -keyfile keys/mainca.key -cert cacerts/mainca.crt -passin pass:foobar

# now we will attempt to create a CRL with a signature that happens to start with 00
# As we need to change something to get a different signature, we change the validity time
echo "Attempting to generate a CRL with leading zero byte - this can take a minute"
days=1
while true
do
        openssl ca -gencrl -crldays $days -out crls/crl-leading-zero-byte.pem -keyfile keys/mainca.key -cert cacerts/mainca.crt -passin pass:foobar >/dev/null
        openssl crl -text -in crls/crl-leading-zero-byte.pem -noout | grep -A1 "Signature Algorithm:"|tail -1| sed "s/ //g" |grep ^00 > /dev/null
        RETVAL=$?
        if [ $RETVAL -eq 0 ]
        then
                echo "Found leading zero CRL signature for days=$days"
                break
        else
                days=$((days+1))
        fi;
done





echo "X509 test material generation complete"
popd
