#!/bin/bash
# Set-up OpenSSL servers with test keys for EC, DSA and RSA.
# Author: Peter Wu <lekensteyn@gmail.com>

rsa_prv=server.pem
rsa_pub=server.crt
dsa_prv=dsa.pem
dsa_pub=dsa.crt
ecd_prv=secp384r1-dsa.pem
ecd_pub=secp384r1-dsa.crt
ecc_prv=secp384r1-rsa.pem
ecc_pub=secp384r1-rsa.crt
PSK=12345678
PSK=0102030405060708091011121314151617181920

pkdir=$1; shift
portbase=4430
if [ -z "$pkdir" ]; then
    cat <<EOF
Usage: $0 path-to-certsdir [port base] [s_server options]"
openssl s_client will listen on three ports,
starting at 'port base' (default 4430)
EOF
    exit 1
fi
# assume that openssl options always start with -
if [ -n "$1" ] && [[ $1 != -* ]]; then
    portbase=$1; shift
    if ! [[ $portbase -gt 0 ]] || ! [[ $portbase -le 65535 ]]; then
        echo "Port must be between 1 and 65535" >&2
        exit 1
    fi
fi

[[ $pkdir == */ ]] || pkdir+=/

if ! mkdir -p "$pkdir"; then
    echo "Could not create directory $pkdir" >&2
    exit 1
fi

pids=()

gen_pk() {
    local type keyfile crtfile x509_opts ca_key ca_crt
    type=$1
    keyfile=$2
    crtfile=$3
    # only necessary
    ca_key=$4
    ca_crt=$5

    if [ -n "$ca_key" ]; then
        x509_opts=(-CA "$ca_crt" -CAkey "$ca_key" -set_serial 1$RANDOM)
    else
        x509_opts=(-signkey "$keyfile")
    fi

    case $type in
    RSA)
        openssl genrsa -out "$keyfile"
        ;;
    DSS)
        openssl dsaparam 1024 | openssl gendsa -out "$keyfile" /dev/stdin
        ;;
    ECDSA)
        openssl ecparam -name secp384r1 -out "$keyfile" -genkey
        ;;
    ECDH)
        openssl ecparam -name secp384r1 -out "$keyfile" -genkey
        ;;
    *)
        echo "Invalid cert type $type" >&2
        return 1
    esac

    openssl req -new -key "$keyfile" -subj "/CN=Test Certificate $type" |
        openssl x509 -req -days 3650 -out "$crtfile" \
        "${x509_opts[@]}"
}

start_server() {
    local keyfile crtfile port auth ca_key= ca_crt= opts=()
    auth=$1; shift
    # remaining arguments should be passed to s_server

    case $auth in
    RSA)
        crtfile=$rsa_pub
        keyfile=$rsa_prv
        port=$portbase
        opts+=(-psk "$PSK")
        ;;
    ECDSA)
        crtfile=$ecd_pub
        keyfile=$ecd_prv
        port=$((portbase+1))
        ;;
    ECDH)
        crtfile=$ecc_pub
        keyfile=$ecc_prv
        ca_key=$rsa_prv
        ca_crt=$rsa_pub
        port=$((portbase+2))
        ;;
    DSS)
        crtfile=$dsa_pub
        keyfile=$dsa_prv
        port=$((portbase+3))
        ;;
    *)
        echo "Invalid cert type $auth" >&2
        return 1
        ;;
    esac

    if [ ! -e "$pkdir$crtfile" ]; then
        gen_pk "$auth" \
            "$pkdir$keyfile" "$pkdir$crtfile" \
            "$pkdirca_key" "$pkdir$ca_crt" || return 1
    fi

    # Enable insecure ciphers too, this script is for generating all possible
    # test samples supported by openssl.
    opts+=( -cipher ALL:COMPLEMENTOFALL )

    openssl s_server -accept $port \
        "${opts[@]}" \
        -cert "$pkdir$crtfile" -key "$pkdir$keyfile" -www "$@" &
    pids+=($!)
}

cleanup() {
    if [ ${#pids[@]} -gt 0 ]; then
        echo "Killing: ${pids[*]}"
        kill "${pids[@]}"
    fi
}
trap cleanup EXIT

for auth in RSA ECDSA ECDH DSS; do
    start_server $auth "$@"
done

wait

# vim: set et sw=4 ts=4:
