#!/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

sanity_check

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

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

export PORT=$(random_port)
start_server "${PORT}"
export PID=$!
sleep 0.5

# Make sure requests on the root fail
fetch / && expected_fail

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

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

# Fetching by any thumbprint should work
fetch /adv/`jose jwk thp -i $TMP/db/sig.jwk` | ver $TMP/db/sig.jwk
fetch /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 /adv/`jose jwk thp -i $TMP/db/sig.jwk` | ver $TMP/db/.sig.jwk && expected_fail
fetch /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 /adv/ | ver $TMP/db/.oth.jwk && expected_fail
fetch /adv/ | ver $TMP/db/.sig.jwk && expected_fail

# A private key advertisement is signed by all advertised keys and the requested private key
fetch /adv/`jose jwk thp -i $TMP/db/.sig.jwk` | ver $TMP/db/sig.jwk
fetch /adv/`jose jwk thp -i $TMP/db/.sig.jwk` | ver $TMP/db/.sig.jwk
fetch /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 /adv | jose fmt -j- -Og protected -SyOg cty -Sq "jwk-set+json" -E
fetch /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)" = "$(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 /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 /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 /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 /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)" = "${thp}"
