#!/bin/sh
#
# Create certificates suitable for testing of Webfsd.
#
# Copyright 2010, 2013: Mats Erik Andersson <debian@gisladisker.se>
# Licensed under GPL v2.
#
# $Rev: 68 $

set -eu

BITLEN=${BITS:-1024}
KEYFILE=${KEY:-key.pem}
HOST_NAME=${HOST:-`hostname`}
CANAME=${CANAME:-webfs.local}

CAFILE=${CAFILE:-ca.pem}

test $BITLEN -lt 384 && BITLEN=384

# As soon as a key has been built,
# the CA must be regenerated.
newly_built_key=false

if test $# -gt 0 &&
   ( test "$1" = "-h" || test "$1" = "--help" || test "$1" = "help" )
then
    cat <<END_TEXT
Full usage:   BITS=${BITLEN} KEY=${KEYFILE} HOST=$HOST_NAME \\
              CANAME=${CANAME} CAFILE=${CAFILE}  $0  [names]

Simple usage: $0  [names]

The defaults used in the latter case are as indicated above,
but influence by any environment variables in this call.

If non-empty, 'names' is a list of strings. When empty, the single
string "localhost" is used as default.

For each string two client certificates are created:
	"client-localhost.pem" and "client2-localhost.pem".

Signing follows these principles:

	"webfs-localhost.pem"   signed by  "ca.pem"
	"client-localhost.pem"    by	"ca.pem"
	"webfs2-localhost.pem"    by	"sub-ca.pem"
	"client2-localhost.pem"   by	"client-ca.pem"

The certificate "server-localhost.pem" is like "webfs-localhost.pem",
but with a preprended key "key.pem". Similarly for "server2-localhost.pem".

The following examples are based on

	HOST=localhost $0 localhost

The certificate 'server-localhost.pem' can directly be used as

	webfsd ... -S -C server-localhost.pem

and produces a proper response to

	$ wget --ca-certificate=ca-chain.pem   https://localhost:8000/

        $ wget --no-check-certificate   https://localhost:8000/

For verification at either end, proper chains are needed:

	webfsd ... -S -V -A client-chain.pem -C server2-localhost.pem

has verification activated with '-V', which can be checked using

	$ wget --certificate=client2-localhost.pem --private-key=key.pem \\
	       --ca-certificate=ca-chain.pem   https://localhost:8000/

The use of "full-chain.pem" in either of the two last calls is possible.
Since the client needs to identify the server, he uses "ca-chain.pem",
whereas the server verifies the client, so is using "client-ca.pem".

### Warning: All these files are intended as test material,
### as they are all using one and the same cryptographic key.

END_TEXT
    exit 0;
fi

clean_up () {
    rm -f *.info
}

trap clean_up 0 1 2 3 9 15

if test -z "$(command -v certtool)"; then
    cat >&2 <<-SLUT
	------------------------------------------------
	The tool "certtool" is missing.
	You need to install a package like "gnutls-bin".
	------------------------------------------------
	SLUT
    exit 1
fi

if test -r "$KEYFILE"; then
    echo "Using previous keyfile!"
else
    echo "Creating a crypto key:
	$KEYFILE"
    certtool --generate-privkey \
		 --bits $BITLEN \
		 --outfile $KEYFILE 2>/dev/null
    chmod 0600 $KEYFILE
    newly_built_key=true
fi

cat > ca.info <<-SLUT
	cn = $CANAME
	ca
	cert_signing_key
SLUT

cat > subca.info <<-SLUT
	cn = sub-$CANAME
	ca
	cert_signing_key
SLUT

cat > client-ca.info <<-SLUT
	cn = client-$CANAME
	ca
	cert_signing_key
SLUT

cat > server.info <<-SLUT
	organization = $CANAME
	cn = $HOST_NAME
	tls_www_server
	encryption_key
	signing_key
SLUT

for nn in "${@:-localhost}"; do
	NN=$(echo $nn | tr ' ' '_')
	cat > $NN.info <<-SLUT
		organization = $CANAME
		cn = $nn
		tls_www_client
		encryption_key
		signing_key
	SLUT
	cat > pre-$NN.info <<-SLUT
		organization = $CANAME
		cn = $nn
		ca
		cert_signing_key
		tls_www_server
	SLUT
done

if $newly_built_key || test ! -r "$CAFILE"; then
    echo "Creating certificate for authority:
	$CAFILE"
    certtool --generate-self-signed \
		--load-privkey $KEYFILE \
		--template ca.info \
		--outfile $CAFILE 2>/dev/null
else
    echo "Using old \"$CAFILE\"!"
fi

# Create an intermediary ca-certificate.
echo "Creating certificate for sub-authority:
	sub-$CAFILE"
certtool --generate-certificate \
		--load-ca-certificate $CAFILE \
		--load-ca-privkey $KEYFILE \
		--load-privkey $KEYFILE \
		--template subca.info \
		--outfile sub-$CAFILE  2>/dev/null

echo "Creating certificate chain for ca and sub-ca:
	ca-chain.pem"
cat sub-$CAFILE $CAFILE > ca-chain.pem

echo "Creating certificate for Webfs:
	CN: $HOST_NAME
	webfs-$HOST_NAME.pem"
certtool --generate-certificate \
		--load-ca-certificate $CAFILE \
		--load-ca-privkey $KEYFILE \
		--load-privkey $KEYFILE \
		--template server.info \
		--outfile webfs-$HOST_NAME.pem  2>/dev/null

# Create a second level certificate for the server.
#
#   CA from "sub-$CAFILE"

echo "Creating second level certificate for Webfs:
	CN: $HOST_NAME
	webfs2-$HOST_NAME.pem"
certtool --generate-certificate \
		--load-ca-certificate sub-$CAFILE \
		--load-ca-privkey $KEYFILE \
		--load-privkey $KEYFILE \
		--template server.info \
		--outfile webfs2-$HOST_NAME.pem  2>/dev/null

echo "Creating certificate combined with key:
	server-$HOST_NAME.pem"
cat key.pem webfs-$HOST_NAME.pem > server-$HOST_NAME.pem
chmod 600 server-$HOST_NAME.pem

echo "	server2-$HOST_NAME.pem"
cat key.pem webfs2-$HOST_NAME.pem > server2-$HOST_NAME.pem
chmod 600 server2-$HOST_NAME.pem

echo "Creating client side, secondary CA:
	client-$CAFILE"
certtool --generate-certificate \
		--load-ca-certificate $CAFILE \
		--load-ca-privkey $KEYFILE \
		--load-privkey $KEYFILE \
		--template client-ca.info \
		--outfile client-$CAFILE  2>/dev/null

echo "Creating client side CA-chain:
	client-chain.pem"
cat client-$CAFILE $CAFILE > client-chain.pem

echo "Creating a common CA-chain usable for server and client:
	full-chain.pem"
cat sub-$CAFILE client-$CAFILE $CAFILE > full-chain.pem

echo "Creating client certificates:"
for nn in "${@:-localhost}"; do
	NN=$(echo $nn | tr ' ' '_')
	echo "	CN: $nn"
	echo "	client-$NN.pem"
	certtool --generate-certificate \
		--load-ca-certificate $CAFILE \
		--load-ca-privkey $KEYFILE \
		--load-privkey $KEYFILE \
		--template $NN.info \
		--outfile client-$NN.pem  2>/dev/null
	echo "	client2-$NN.pem"
	certtool --generate-certificate \
		--load-ca-certificate client-$CAFILE \
		--load-ca-privkey $KEYFILE \
		--load-privkey $KEYFILE \
		--template $NN.info \
		--outfile client2-${NN}.pem  2>/dev/null
done
