#!/bin/sh -ex
# vim: set tabstop=8 shiftwidth=4 softtabstop=4 expandtab smarttab colorcolumn=80:
#
# Copyright (c) 2016 Red Hat, Inc.
# Author: Nathaniel McCallum <npmccallum@redhat.com>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
#

. helpers

trap 'on_exit' EXIT
export TMP=`mktemp -d`
mkdir -p $TMP/db

adv_startup () {
    tangd-keygen $TMP/db sig exc
    # Make sure keys generated by tangd-keygen have proper permissions.
    valid_key_perm "${TMP}/db/sig.jwk"
    valid_key_perm "${TMP}/db/exc.jwk"

    jose jwk gen -i '{"alg": "ES512"}' -o $TMP/db/.sig.jwk
    jose jwk gen -i '{"alg": "ES512"}' -o $TMP/db/.oth.jwk
}

adv_second_phase () {
    # Make sure requests on the root fail
    fetch "${ENDPOINT}"/ && expected_fail

    # The request should fail (404) for non-signature key IDs
    fetch "${ENDPOINT}"/adv/`jose jwk thp -i $TMP/db/exc.jwk` && expected_fail
    fetch "${ENDPOINT}"/adv/`jose jwk thp -a S512 -i $TMP/db/exc.jwk` && expected_fail

    # The default advertisement fetch should succeed and pass verification
    fetch "${ENDPOINT}"/adv
    fetch "${ENDPOINT}"/adv | ver $TMP/db/sig.jwk
    fetch "${ENDPOINT}"/adv/ | ver $TMP/db/sig.jwk

    # Fetching by any thumbprint should work
    fetch "${ENDPOINT}"/adv/`jose jwk thp -i $TMP/db/sig.jwk` | ver $TMP/db/sig.jwk
    fetch "${ENDPOINT}"/adv/`jose jwk thp -a S512 -i $TMP/db/sig.jwk` | ver $TMP/db/sig.jwk

    # Requesting an adv by an advertised key ID should't be signed by hidden keys
    fetch "${ENDPOINT}"/adv/`jose jwk thp -i $TMP/db/sig.jwk` | ver $TMP/db/.sig.jwk && expected_fail
    fetch "${ENDPOINT}"/adv/`jose jwk thp -i $TMP/db/sig.jwk` | ver $TMP/db/.oth.jwk && expected_fail

    # Verify that the default advertisement is not signed with hidden signature keys
    fetch "${ENDPOINT}"/adv/ | ver $TMP/db/.oth.jwk && expected_fail
    fetch "${ENDPOINT}"/adv/ | ver $TMP/db/.sig.jwk && expected_fail

    # A private key advertisement is signed by all advertised keys and the requested private key
    fetch "${ENDPOINT}"/adv/`jose jwk thp -i $TMP/db/.sig.jwk` | ver $TMP/db/sig.jwk
    fetch "${ENDPOINT}"/adv/`jose jwk thp -i $TMP/db/.sig.jwk` | ver $TMP/db/.sig.jwk
    fetch "${ENDPOINT}"/adv/`jose jwk thp -i $TMP/db/.sig.jwk` | ver $TMP/db/.oth.jwk && expected_fail

    # Verify that the advertisements contain the cty parameter
    fetch "${ENDPOINT}"/adv | jose fmt -j- -Og protected -SyOg cty -Sq "jwk-set+json" -E
    fetch "${ENDPOINT}"/adv/`jose jwk thp -i $TMP/db/.sig.jwk` \
        | jose fmt -j- -Og signatures -A \
               -g 0 -Og protected -SyOg cty -Sq "jwk-set+json" -EUUUUU \
               -g 1 -Og protected -SyOg cty -Sq "jwk-set+json" -EUUUUU

    THP_DEFAULT_HASH=S256     # SHA-256.
    test "$(tang-show-keys $PORT $ENDPOINT)" = "$(jose jwk thp -a "${THP_DEFAULT_HASH}" -i $TMP/db/sig.jwk)"

    # Check that new keys will be created if none exist.
    rm -rf "${TMP}/db" && mkdir -p "${TMP}/db"
    fetch "${ENDPOINT}"/adv

    # Now let's make sure the new keys were named using our default thumbprint
    # hash and then rotate them and check if we still create new keys.
    cd "${TMP}/db"
    for k in *.jwk; do
        # Check for the key name (SHA-256).
        test "${k}" = "$(jose jwk thp -a "${THP_DEFAULT_HASH}" -i "${k}")".jwk
        # Rotate the key.
        mv -f -- "${k}" ".${k}"
    done
    cd -
    fetch "${ENDPOINT}"/adv

    # Lets's now test with multiple pairs of keys.
    for i in 1 2 3 4 5 6 7 8 9; do
        tangd-keygen "${TMP}"/db other-sig-${i} other-exc-${i}
        # Make sure the requested keys exist and are valid.
        validate_sig "${TMP}/db/other-sig-${i}.jwk"
        validate_exc "${TMP}/db/other-exc-${i}.jwk"

        # Make sure keys generated by tangd-keygen have proper permissions.
        valid_key_perm "${TMP}/db/other-sig-${i}.jwk"
        valid_key_perm "${TMP}/db/other-exc-${i}.jwk"
    done

    # Verify the advertisement is correct.
    validate "$(fetch "${ENDPOINT}"/adv)"

    # And make sure we can fetch an adv by its thumbprint.
    for jwk in "${TMP}"/db/other-sig-*.jwk; do
	for alg in $(jose alg -k hash); do
		fetch "${ENDPOINT}"/adv/"$(jose jwk thp -a "${alg}" -i "${jwk}")" | ver "${jwk}"
	done
    done

    # Now let's test keys rotation.
    tangd-rotate-keys -d "${TMP}/db"
    for i in 1 2 3 4 5 6 7 8 9; do
	# Make sure keys were excluded from advertisement.
	validate_sig "${TMP}/db/.other-sig-${i}.jwk"
	validate_exc "${TMP}/db/.other-exc-${i}.jwk"
    done

    # And test also that we have valid keys after rotation.
    thp=
    for jwk in "${TMP}"/db/*.jwk; do
	validate_sig "${jwk}" && thp="$(jose jwk thp -a "${THP_DEFAULT_HASH}" \
										-i "${jwk}")"

        # Make sure keys generated by tangd-rotate-keys have proper permissions.
	valid_key_perm "${jwk}"
    done
    [ -z "${thp}" ] && die "There should be valid keys after rotation"
    test "$(tang-show-keys $PORT $ENDPOINT)" = "${thp}"
}
