#!/bin/bash

# simple set of tests to exercise the msva.

# these tests currently depend on the user having the following tools
# installed locally:

# monkeysphere (for pem2openpgp)
# openssl (for openssl req)
# openssh-client (for ssh-keygen)
# gpg (for obvious reasons)
# bash (yes, this test script isn't posix-compliant)

# note that this test requires the ability to bind on the loopback
# interface, which might not be possible in some build environments.

# Author: Daniel Kahn Gillmor
# Copyright: 2010
# License: This is licensed under the GPL v3 or later
#          (see the top-level COPYING file in this distribution)

set -e

srcdir=$(dirname $0)/..

REPS=5

CERTTYPES="x509pem x509der opensshpubkey rfc4716 openpgp4fpr"

printf "testing %d reps of simple/quick true/false:\n" "$REPS"
for n in $(seq 1 "$REPS") ; do
    "${srcdir}"/test-msva msva-perl true
    printf "+"
    ! "${srcdir}"/test-msva msva-perl false
    printf "-"
done
printf "\ndone\n"

WORKDIR=$(mktemp -d)
mkdir -m 0700 "${WORKDIR}/"{pkc,sec,gnupg}
touch "${WORKDIR}/gnupg/gpg.conf"
export GNUPGHOME="${WORKDIR}/gnupg"

if gpg --quick-random --version ; then
    GPGQR=--quick-random
elif gpg --debug-quick-random --version ; then
    GPGQR=--debug-quick-random
else
    GPGQR=
fi

# make a CA
printf "Key-Type: RSA\nKey-Length: 1024\nKey-Usage: sign\nName-Real: MSVA Test Certificate Authority (DO NOT USE!)\n" | gpg --batch --no-tty $GPGQR --gen-key

# make 3 websites (X, Y, and Z) with self-signed certs:
for name in x y z ; do 
    openssl req -x509 -subj "/CN=${name}.example.net/" -nodes -sha256 -newkey rsa:1024 -keyout "${WORKDIR}/sec/${name}.key" -outform DER -out "${WORKDIR}/pkc/${name}.x509der"
    chmod 0400  "${WORKDIR}/sec/${name}.key"
    openssl x509 -inform DER -outform PEM < "${WORKDIR}/pkc/${name}.x509der" > "${WORKDIR}/pkc/${name}.x509pem"
    ssh-keygen -y -P '' -f "${WORKDIR}/sec/${name}.key" > "${WORKDIR}/pkc/${name}.opensshpubkey"
    ssh-keygen -e -P '' -f "${WORKDIR}/sec/${name}.key" > "${WORKDIR}/pkc/${name}.rfc4716"
done

# make 2 client certs (A and B) with self-signed certs
for name in a b ; do 
    openssl req -x509 -subj "/eMail=${name}@example.net/CN=${name}/" -nodes -sha256 -newkey rsa:1024 -keyout "${WORKDIR}/sec/${name}.key" -outform DER -out "${WORKDIR}/pkc/${name}.x509der"
    chmod 0400  "${WORKDIR}/sec/${name}.key"
    openssl x509 -inform DER -outform PEM < "${WORKDIR}/pkc/${name}.x509der" > "${WORKDIR}/pkc/${name}.x509pem"
    ssh-keygen -y -P '' -f "${WORKDIR}/sec/${name}.key" > "${WORKDIR}/pkc/${name}.opensshpubkey"
    ssh-keygen -e -P '' -f "${WORKDIR}/sec/${name}.key" > "${WORKDIR}/pkc/${name}.rfc4716"
done

# translate X and Y's keys into OpenPGP cert
for name in x y; do
    uid="https://${name}.example.net"
    PEM2OPENPGP_USAGE_FLAGS=authenticate pem2openpgp "$uid" < "${WORKDIR}/sec/${name}.key" | gpg --import
    # export fingerprint for openpgp4fpr
    gpg --with-colons --fingerprint "=${uid}" | grep '^fpr:' | cut -d: -f10 > "${WORKDIR}/pkc/${name}.openpgp4fpr"
done
# touch an empty openpgp4fpr file for z, who is not supposed to be in
# the monkeysphere at all, and therefore has no openpgp4fpr
touch "${WORKDIR}/pkc/z.openpgp4fpr"
# and the same for the clients A and B
for name in a b; do
    uid="${name} <${name}@example.net>"
    # make user keys 'a' and 's' capable
    PEM2OPENPGP_USAGE_FLAGS=authenticate,sign pem2openpgp "$uid" < "${WORKDIR}/sec/${name}.key" | gpg --import
    # export fingerprint for openpgp4fpr
    gpg --with-colons --fingerprint "=${uid}" | grep '^fpr:' | cut -d: -f10 > "${WORKDIR}/pkc/${name}.openpgp4fpr"
done

runtests() {
    # X should not validate as X or Y or Z:
    for name in x y z; do
        for ctype in $CERTTYPES; do
            ! "${srcdir}"/test-msva msva-perl "${srcdir}"/test-msva msva-query-agent https "${name}.example.net" "${ctype}" < "${WORKDIR}/pkc/x.${ctype}"
	    echo
        done
    done
    # A shouldn't validate as A or B:
    for name in a b; do
        for ctype in $CERTTYPES; do
            ! "${srcdir}"/test-msva msva-perl "${srcdir}"/test-msva msva-query-agent https "${name} <${name}@example.net>" "${ctype}" client < "${WORKDIR}/pkc/a.${ctype}"
	    echo
        done
    done
    
    # certify X and A's OpenPGP cert with CA
    gpg --batch --yes --sign-key https://x.example.net
    gpg --batch --yes --sign-key a@example.net

    echo "Testing bad data:"
    # it should fail if we pass it the wrong kind of data:
    ! "${srcdir}"/test-msva msva-perl "${srcdir}"/test-msva msva-query-agent https x.example.net "x509der" < "${WORKDIR}/pkc/x.x509pem"
    echo
    ! "${srcdir}"/test-msva msva-perl "${srcdir}"/test-msva msva-query-agent https x.example.net "x509pem" < "${WORKDIR}/pkc/x.x509der"
    echo
    echo "Done testing bad data."
        
    for ctype in $CERTTYPES; do 
    # X should now validate as X
        "${srcdir}"/test-msva msva-perl "${srcdir}"/test-msva msva-query-agent https x.example.net "${ctype}" < "${WORKDIR}/pkc/x.${ctype}"
	echo
        "${srcdir}"/test-msva msva-perl "${srcdir}"/test-msva msva-query-agent https 'a <a@example.net>' "${ctype}" client < "${WORKDIR}/pkc/a.${ctype}"
	# also test "e-mail" context
        "${srcdir}"/test-msva msva-perl "${srcdir}"/test-msva msva-query-agent e-mail 'a <a@example.net>' "${ctype}" < "${WORKDIR}/pkc/a.${ctype}"
        
    # but X should not validate as Y or Z:
        for name in x y z; do
            ! "${srcdir}"/test-msva msva-perl "${srcdir}"/test-msva msva-query-agent https "${name}.example.net" "${ctype}" < "${WORKDIR}/pkc/x.${ctype}"
	    echo
        done
        # and A shouldn't validate as B:
        ! "${srcdir}"/test-msva msva-perl "${srcdir}"/test-msva msva-query-agent https "b <b@example.net>" "${ctype}" client < "${WORKDIR}/pkc/a.${ctype}"
	echo

    # neither Y nor Z should validate as any of them:
        for src in y z; do
            for targ in x y z; do
                ! "${srcdir}"/test-msva msva-perl "${srcdir}"/test-msva msva-query-agent https "${targ}.example.net" "${ctype}" < "${WORKDIR}/pkc/${src}.${ctype}"
		echo
            done
        done
        # B should also still not validate as itself:
        ! "${srcdir}"/test-msva msva-perl "${srcdir}"/test-msva msva-query-agent https "b <b@example.net>" "${ctype}" client < "${WORKDIR}/pkc/b.${ctype}"
	echo
    done
}

set -x
MSVA_KEYSERVER_POLICY=never runtests
set +x
echo "Completed all tests as expected!"

rm -rf "$WORKDIR"
