From 8daa83a594a2e98f39d764422bfbdbc62c9efd44 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Fri, 19 Apr 2024 19:20:00 +0200 Subject: Adding upstream version 2:4.20.0+dfsg. Signed-off-by: Daniel Baumann --- third_party/heimdal/tests/kdc/check-httpkadmind.in | 842 +++++++++++++++++++++ 1 file changed, 842 insertions(+) create mode 100644 third_party/heimdal/tests/kdc/check-httpkadmind.in (limited to 'third_party/heimdal/tests/kdc/check-httpkadmind.in') diff --git a/third_party/heimdal/tests/kdc/check-httpkadmind.in b/third_party/heimdal/tests/kdc/check-httpkadmind.in new file mode 100644 index 0000000..9707fc1 --- /dev/null +++ b/third_party/heimdal/tests/kdc/check-httpkadmind.in @@ -0,0 +1,842 @@ +#!/bin/sh +# +# Copyright (c) 2020 Kungliga Tekniska Högskolan +# (Royal Institute of Technology, Stockholm, Sweden). +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# 3. Neither the name of the Institute nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. + +top_builddir="@top_builddir@" +env_setup="@env_setup@" +objdir="@objdir@" + +testfailed="echo test failed; cat messages.log; exit 1" + +. ${env_setup} + +# If there is no useful db support compiled in, disable test +${have_db} || exit 77 + +if ! which curl > /dev/null; then + echo "curl is not available -- not testing httpkadmind" + exit 77 +fi +if ! test -x ${objdir}/../../kdc/httpkadmind; then + echo "Configured w/o libmicrohttpd -- not testing httpkadmind" + exit 77 +fi + +R=TEST.H5L.SE +domain=test.h5l.se + +port=@port@ +admport=@admport@ +admport1=@admport@ +admport2=@admport2@ +restport=@restport@ +restport1=@restport@ +restport2=@restport2@ + +server=datan.test.h5l.se +otherserver=other.test.h5l.se +cache="FILE:${objdir}/cache.krb5" +cache2="FILE:${objdir}/cache2.krb5" +admincache="FILE:${objdir}/cache3.krb5" +keyfile="${hx509_data}/key.der" +keyfile2="${hx509_data}/key2.der" +kt=${objdir}/kt +keytab=FILE:${kt} +ukt=${objdir}/ukt +ukeytab=FILE:${ukt} + +kdc="${kdc} --addresses=localhost -P $port" +kadminr="${kadmin} -r $R -a $(uname -n)" +kadmin="${kadmin} -l -r $R" +kadmind2="${kadmind} --keytab=${keytab} --detach -p $admport2 --read-only" +kadmind="${kadmind} --keytab=${keytab} --detach -p $admport" +httpkadmind2="${httpkadmind} --reverse-proxied -T Negotiate -p $restport2" +httpkadmind="${httpkadmind} --reverse-proxied -T Negotiate -p $restport1" + +kinit2="${kinit} -c $cache2 ${afs_no_afslog}" +kinit="${kinit} -c $cache ${afs_no_afslog}" +adminklist="${klist} --hidden -v -c $admincache" +klist2="${klist} --hidden -v -c $cache2" +klist="${klist} --hidden -v -c $cache" +kgetcred2="${kgetcred} -c $cache2" +kgetcred="${kgetcred} -c $cache" +kdestroy2="${kdestroy} -c $cache2 ${afs_no_unlog}" +kdestroy="${kdestroy} -c $cache ${afs_no_unlog}" +kx509="${kx509} -c $cache" + +KRB5_CONFIG="${objdir}/krb5-httpkadmind.conf" +export KRB5_CONFIG +KRB5CCNAME=$cache +export KRB5CCNAME +HEIM_PIDFILE_DIR=$objdir +export HEIM_PIDFILE_DIR +HEIM_IPC_DIR=$objdir +export HEIM_IPC_DIR + +rm -f current-db* +rm -f out-* +rm -f mkey.file* +rm -f *.pem *.crt *.der +rm -rf authz_dir +rm -f extracted_keytab* + +mkdir -p authz_dir + +> messages.log + +# We'll avoid using a KDC for now. For testing /httpkadmind we only need keys +# for Negotiate tokens, and we'll use ktutil and kimpersonate to make it +# possible to create and accept those without a KDC. + +# grant ext-type value grantee_principal +grant() { + mkdir -p "${objdir}/authz_dir/${3}" + touch "${objdir}/authz_dir/${3}/${1}=${2}" +} + +revoke() { + rm -rf "${objdir}/authz_dir" + mkdir -p "${objdir}/authz_dir" +} + +if set -o|grep 'verbose.*on' > /dev/null || + set -o|grep 'xtrace.*on' > /dev/null; then + verbose=-vvv +else + verbose= +fi + +# HTTP curl-opts +HTTP() { + curl -g --resolve ${server}:${restport2}:127.0.0.1 \ + --resolve ${server}:${restport}:127.0.0.1 \ + -u: --negotiate $verbose \ + -D response-headers \ + "$@" +} + +# get_config QPARAMS curl-opts +get_config() { + url="http://${server}:${restport}/get-config?$1" + shift + HTTP $verbose "$@" "$url" +} + +check_age() { + set -- $(grep -i ^Cache-Control: response-headers) + if [ $# -eq 0 ]; then + return 1 + fi + shift + for param in "$@"; do + case "$param" in + no-store) true;; + max-age=0) return 1;; + max-age=*) true;; + *) return 1;; + esac + done + return 0; +} + +# get_keytab QPARAMS curl-opts +get_keytab() { + url="http://${server}:${restport}/get-keys?$1" + shift + HTTP $verbose "$@" "$url" +} + +# get_keytab_POST QPARAMS curl-opts +get_keytab_POST() { + # Curl is awful, so if you don't use -f, you don't get non-zero exit codes on + # error responses, but if you do use -f then -D doesn't work. Ugh. + # + # So first we check that POST w/o CSRF token fails: + q=$1 + shift + + get_keytab "$q" -X POST --data-binary @/dev/null -f "$@" && + { echo "POST succeeded w/o CSRF token!"; return 1; } + get_keytab "$q" -X POST --data-binary @/dev/null "$@" + grep ^X-CSRF-Token: response-headers >/dev/null || return 1 + get_keytab "$q" -X POST --data-binary @/dev/null \ + -H "$(sed -e 's/\r//' response-headers | grep ^X-CSRF-Token:)" "$@" + grep '^HTTP/1.1 200' response-headers >/dev/null || return $? + return 0 +} + +get_keytab_POST_redir() { + url="http://${server}:${restport}/get-keys?$1" + shift + HTTP -X POST --data-binary @/dev/null "$@" "$url" + grep ^X-CSRF-Token: response-headers >/dev/null || + { echo "POST w/o CSRF token had response w/o CSRF token!"; return 1; } + HTTP -X POST --data-binary @/dev/null -f \ + -H "$(sed -e 's/\r//' response-headers | grep ^X-CSRF-Token:)" \ + --location --location-trusted "$@" "$url" +} + +kdcpid= +httpkadmindpid= +httpkadmind2pid= +test_csr_authorizer_pid= +kadmindpid= +kadmind2pid= +cleanup() { + test -n "$kdcpid" && + { echo signal killing kdc; kill -9 "$kdcpid"; } + test -n "$test_csr_authorizer_pid" && + { echo signal killing test_csr_authorizer; kill -9 "$test_csr_authorizer_pid"; } + test -n "$httpkadmindpid" && + { echo signal killing httpkadmind; kill -9 "$httpkadmindpid"; } + test -n "$httpkadmind2pid" && + { echo signal killing second httpkadmind; kill -9 "$httpkadmind2pid"; } + test -n "$kadmindpid" && + { echo signal killing kadmind; kill -9 "$kadmindpid"; } + test -n "$kadmind2pid" && + { echo signal killing kadmind; kill -9 "$kadmind2pid"; } +} +trap cleanup EXIT + +rm -f extracted_keytab + +echo "Creating database" +rm -f $kt $ukt +${kadmin} </dev/null || + { echo "failed to setup kimpersonate credentials"; exit 2; } + +echo "Starting test_csr_authorizer" +${test_csr_authorizer} -A $objdir/authz_dir -S $objdir --server --daemon || + { echo "test_csr_authorizer failed to start"; exit 2; } +test_csr_authorizer_pid=`getpid test_csr_authorizer` +ec=0 + +echo "Starting httpkadmind" +${httpkadmind} -H $server -H localhost --local -t --daemon || + { echo "httpkadmind failed to start"; exit 2; } +httpkadmindpid=`getpid httpkadmind` +ec=0 + +echo "Checking that concrete principal exists" +${kadmin} get HTTP/xyz.${domain} > /dev/null || + { echo "Failed to create HTTP/xyz.${domain}"; exit 1; } +echo "Checking that virtual principal exists" +${kadmin} get HTTP/foo.ns.${domain} > /dev/null || + { echo "Virtual principals not working"; exit 1; } + +hn=xyz.${domain} +p=HTTP/$hn +echo "Fetching krb5.conf for $p" +get_config "princ=$p" -sf -o "${objdir}/extracted_config" || + { echo "Failed to get config for $p"; exit 1; } +read config < "${objdir}/extracted_config" +test "$config" = "include /etc/krb5.conf" || + { echo "Got unexpected default config for $p"; exit 1; } +${kadmin} mod --krb5-config-file="$KRB5_CONFIG" $p || + { echo "Failed to set config for $p"; exit 1; } +get_config "princ=$p" -sf -o "${objdir}/extracted_config" || + { echo "Failed to get config for $p"; exit 1; } +cmp "${objdir}/extracted_config" "$KRB5_CONFIG" || + { echo "Got unexpected config for $p"; exit 1; } + +hn=xyz.${domain} +p=HTTP/$hn +echo "Fetching keytab for concrete principal $p" +rm -f extracted_keytab* +grant san_dnsname $hn foo@${R} +${kadmin} ext_keytab -k extracted_keytab $p || + { echo "Failed to get a keytab for $p with kadmin"; exit 1; } +${ktutil} -k "${objdir}/extracted_keytab" list --keys > extracted_keytab.kadmin || + { echo "Failed to list keytab for $p"; exit 1; } +get_keytab "dNSName=${hn}" -sf -o "${objdir}/extracted_keytab" || + { echo "Failed to get a keytab for $p with curl"; exit 1; } +${ktutil} -k "${objdir}/extracted_keytab" list --keys > extracted_keytab.rest || + { echo "Failed to list keytab for $p"; exit 1; } +cmp extracted_keytab.kadmin extracted_keytab.rest || + { echo "Keytabs for $p don't match!"; exit 1; } + +hn=foo.ns.${domain} +p=HTTP/$hn +echo "Fetching keytab for virtual principal $p" +rm -f extracted_keytab* +grant san_dnsname $hn foo@${R} +${kadmin} ext_keytab -k extracted_keytab $p || + { echo "Failed to get a keytab for $p with kadmin"; exit 1; } +${ktutil} -k "${objdir}/extracted_keytab" list --keys > extracted_keytab.kadmin || + { echo "Failed to list keytab for $p"; exit 1; } +get_keytab "dNSName=${hn}" -sf -o "${objdir}/extracted_keytab" || + { echo "Failed to get a keytab for $p with curl"; exit 1; } +check_age +grep -i ^Cache-Control response-headers +${ktutil} -k "${objdir}/extracted_keytab" list --keys > extracted_keytab.rest || + { echo "Failed to list keytab for $p"; exit 1; } +cmp extracted_keytab.kadmin extracted_keytab.rest || + { echo "Keytabs for $p don't match!"; exit 1; } + +hn1=foo.ns.${domain} +hn2=foobar.ns.${domain} +hn3=xyz.${domain} +p1=HTTP/$hn1 +p2=HTTP/$hn2 +p3=HTTP/$hn3 +echo "Fetching keytabs for more than one principal" +rm -f extracted_keytab* +grant san_dnsname $hn1 foo@${R} +grant san_dnsname $hn2 foo@${R} +grant san_dnsname $hn3 foo@${R} +# Note that httpkadmind will first process dNSName q-params, then the spn +# q-params. +${kadmin} ext_keytab -k extracted_keytab $p1 || + { echo "Failed to get a keytab for $p1 with kadmin"; exit 1; } +${kadmin} ext_keytab -k extracted_keytab $p3 || + { echo "Failed to get a keytab for $p3 with kadmin"; exit 1; } +${kadmin} ext_keytab -k extracted_keytab $p2 || + { echo "Failed to get a keytab for $p2 with kadmin"; exit 1; } +${ktutil} -k "${objdir}/extracted_keytab" list --keys > extracted_keytab.kadmin || + { echo "Failed to list keytab for multiple principals"; exit 1; } +get_keytab "dNSName=${hn1}&spn=${p2}&dNSName=${hn3}" -sf -o "${objdir}/extracted_keytab" || + { echo "Failed to get a keytab for multiple principals with curl"; exit 1; } +${ktutil} -k "${objdir}/extracted_keytab" list --keys > extracted_keytab.rest || + { echo "Failed to list keytab for $p"; exit 1; } +cmp extracted_keytab.kadmin extracted_keytab.rest || + { echo "Keytabs for $p don't match!"; exit 1; } +grep $hn1 extracted_keytab.rest > /dev/null || + { echo "Keytab does not include keys for $p1"; exit 1; } +grep $hn2 extracted_keytab.rest > /dev/null || + { echo "Keytab does not include keys for $p2"; exit 1; } +grep $hn3 extracted_keytab.rest > /dev/null || + { echo "Keytab does not include keys for $p3"; exit 1; } + +p=host/foo.ns.${domain} +echo "Checking that $p doesn't exist (no namespace for host service)" +get_keytab "svc=host&dNSName=foo.ns.${domain}" -sf -o "${objdir}/extracted_keytab.rest" && + { echo "Got a keytab for host/foo.ns.${domain} when not namespaced!"; } + +echo "Checking that authorization is enforced" +revoke +get_keytab "dNSName=xyz.${domain}" -sf -o "${objdir}/extracted_keytab" && + { echo "Got a keytab for HTTP/xyz.${domain} when not authorized!"; exit 1; } +get_keytab "dNSName=foo.ns.${domain}" -sf -o "${objdir}/extracted_keytab" && + { echo "Got a keytab for HTTP/foo.ns.${domain} when not authorized!"; exit 1; } + +echo "Checking that host service keys are not served" +hn=xyz.${domain} +p=host/$hn +echo "Fetching keytab for virtual principal $p" +rm -f extracted_keytab* +grant san_dnsname $hn foo@${R} +get_keytab "service=host&dNSName=xyz.${domain}" -sf -o "${objdir}/extracted_keytab" && + { echo "Got a keytab for $p even though it is a host service!"; exit 1; } +get_keytab "spn=host/xyz.${domain}" -sf -o "${objdir}/extracted_keytab" && + { echo "Got a keytab for $p even though it is a host service!"; exit 1; } +revoke + +hn=xyz.${domain} +p=HTTP/$hn +echo "Checking key rotation for concrete principal $p" +rm -f extracted_keytab* +grant san_dnsname $hn foo@${R} +get_keytab "dNSName=${hn}" -sf -o "${objdir}/extracted_keytab" || + { echo "Failed to get a keytab for $p with curl"; exit 1; } +${ktutil} -k "${objdir}/extracted_keytab" list --keys > extracted_keytab.rest1 || + { echo "Failed to list keytab for $p"; exit 1; } +test "$(grep $p extracted_keytab.rest1 | wc -l)" -eq 1 || + { echo "Wrong number of new keys!"; exit 1; } +get_keytab "dNSName=${hn}&rotate=true" -sf -o "${objdir}/extracted_keytab" && + { echo "GET succeeded for write operation!"; exit 1; } +get_keytab_POST "dNSName=${hn}&rotate=true" -s -o "${objdir}/extracted_keytab" || + { echo "Failed to rotate keys for $p"; exit 1; } +${ktutil} -k "${objdir}/extracted_keytab" list --keys > extracted_keytab.rest2 || + { echo "Failed to list keytab for $p"; exit 1; } +cmp extracted_keytab.rest1 extracted_keytab.rest2 > /dev/null && + { echo "Keys for $p did not change!"; exit 1; } +test "$(grep $p extracted_keytab.rest2 | wc -l)" -eq 2 || + { echo "Wrong number of new keys!"; exit 1; } + +hn=xyz.${domain} +p=HTTP/$hn +echo "Checking key rotation w/ revocation for concrete principal $p" +rm -f extracted_keytab* +grant san_dnsname $hn foo@${R} +get_keytab "dNSName=${hn}" -sf -o "${objdir}/extracted_keytab" || + { echo "Failed to get a keytab for $p with curl"; exit 1; } +${ktutil} -k "${objdir}/extracted_keytab" list --keys > extracted_keytab.rest1 || + { echo "Failed to list keytab for $p"; exit 1; } +get_keytab "dNSName=${hn}&revoke=true" -sf -o "${objdir}/extracted_keytab" && + { echo "GET succeeded for write operation!"; exit 1; } +get_keytab_POST "dNSName=${hn}&revoke=true" -s -o "${objdir}/extracted_keytab" || + { echo "Failed to get a keytab for $p with curl"; exit 1; } +${ktutil} -k "${objdir}/extracted_keytab" list --keys > extracted_keytab.rest2 || + { echo "Failed to list keytab for $p"; exit 1; } +cmp extracted_keytab.rest1 extracted_keytab.rest2 > /dev/null && + { echo "Keys for $p did not change!"; exit 1; } +test "$(grep $p extracted_keytab.rest2 | wc -l)" -eq 1 || + { echo "Wrong number of new keys!"; exit 1; } + +hn=abc.${domain} +p=HTTP/$hn +echo "Checking concrete principal creation ($p)" +rm -f extracted_keytab +grant san_dnsname $hn foo@${R} +get_keytab "dNSName=${hn}&create=true" -sf -o "${objdir}/extracted_keytab" && + { echo "GET succeeded for write operation!"; exit 1; } +get_keytab_POST "dNSName=${hn}&create=true" -s -o "${objdir}/extracted_keytab" || + { echo "Failed to get a keytab for $p with curl"; exit 1; } +${ktutil} -k "${objdir}/extracted_keytab" list --keys > extracted_keytab.rest || + { echo "Failed to list keytab for $p"; exit 1; } +rm -f extracted_keytab +${kadmin} ext_keytab -k extracted_keytab $p || + { echo "Failed to get a keytab for $p with kadmin"; exit 1; } +${ktutil} -k "${objdir}/extracted_keytab" list --keys > extracted_keytab.kadmin || + { echo "Failed to list keytab for $p"; exit 1; } +cmp extracted_keytab.kadmin extracted_keytab.rest || + { echo "Keytabs for $p don't match!"; exit 1; } + +hn=bar.ns.${domain} +p=HTTP/$hn +echo "Checking materialization of virtual principal ($p)" +rm -f extracted_keytab +grant san_dnsname $hn foo@${R} +get_keytab "dNSName=${hn}&materialize=true" -sf -o "${objdir}/extracted_keytab" && + { echo "GET succeeded for write operation!"; exit 1; } +get_keytab_POST "dNSName=${hn}&materialize=true" -s -o "${objdir}/extracted_keytab" || + { echo "Failed to materialize and get a keytab for $p with curl"; exit 1; } +${ktutil} -k "${objdir}/extracted_keytab" list --keys > extracted_keytab.rest || + { echo "Failed to list keytab for $p"; exit 1; } +rm -f extracted_keytab +${kadmin} ext_keytab -k extracted_keytab $p || + { echo "Failed to get a keytab for $p with kadmin"; exit 1; } +${ktutil} -k "${objdir}/extracted_keytab" list --keys > extracted_keytab.kadmin || + { echo "Failed to list keytab for $p"; exit 1; } +cmp extracted_keytab.kadmin extracted_keytab.rest || + { echo "Keytabs for $p don't match!"; exit 1; } + +echo "Starting secondary httpkadmind to test HTTP redirection" +${httpkadmind2} --primary-server-uri=http://localhost:$restport \ + -H $server --local --local-read-only -t --daemon || + { echo "httpkadmind failed to start"; exit 2; } +httpkadmind2pid=`getpid httpkadmind` +ec=0 + +hn=def.${domain} +p=HTTP/$hn +restport=$restport2 +echo "Checking principal creation at secondary yields redirect" +rm -f extracted_keytab +grant san_dnsname $hn foo@${R} +get_keytab_POST_redir "dNSName=${hn}&create=true" \ + -s -o "${objdir}/extracted_keytab" +${ktutil} -k "${objdir}/extracted_keytab" list --keys > extracted_keytab.rest || + { echo "Failed to list keytab for $p"; exit 1; } +rm -f extracted_keytab +${kadmin} ext_keytab -k extracted_keytab $p || + { echo "Failed to get a keytab for $p with kadmin"; exit 1; } +${ktutil} -k "${objdir}/extracted_keytab" list --keys > extracted_keytab.kadmin || + { echo "Failed to list keytab for $p"; exit 1; } +cmp extracted_keytab.kadmin extracted_keytab.rest || + { echo "Keytabs for $p don't match!"; exit 1; } + +echo "killing httpkadmind (${httpkadmindpid} ${httpkadmind2pid})" +sh ${leaks_kill} httpkadmind $httpkadmindpid || ec=1 +sh ${leaks_kill} httpkadmind $httpkadmind2pid || ec=1 +httpkadmindpid= +httpkadmind2pid= +test $ec = 1 && + { echo "Error killing httpkadmind instances or memory errors found"; exit 1; } + +echo "Starting primary kadmind for testing httpkadmind with remote HDB" +${kadmind} || + { echo "Read-write kadmind failed to start"; exit 2; } +kadmindpid=`getpid kadmind` +echo "Starting secondray (read-only) kadmind for testing httpkadmind with remote HDB" +${kadmind2} || + { echo "Read-only kadmind failed to start"; exit 2; } +kadmind2pid=`getpid kadmind` + +# Make a ccache for use with kadmin(1) +$kimpersonate --ticket-flags=initial --ccache=$admincache -k $keytab -t aes128-cts-hmac-sha1-96 \ + -c httpkadmind/admin@${R} -s kadmin/admin@${R} || + { echo "failed to setup kimpersonate credentials"; exit 2; } +$adminklist -t >/dev/null || + { echo "failed to setup kimpersonate credentials"; exit 2; } + + +echo "Making PKINIT certs for KDC" +${hxtool} issue-certificate \ + --self-signed \ + --issue-ca \ + --ca-private-key=FILE:${keyfile} \ + --subject="CN=CA,DC=test,DC=h5l,DC=se" \ + --certificate="FILE:ca.crt" || exit 1 +${hxtool} request-create \ + --subject="CN=kdc,DC=test,DC=h5l,DC=se" \ + --key=FILE:${keyfile2} \ + req-kdc.der || exit 1 +${hxtool} issue-certificate \ + --ca-certificate=FILE:$objdir/ca.crt,${keyfile} \ + --type="pkinit-kdc" \ + --pk-init-principal="krbtgt/TEST.H5L.SE@TEST.H5L.SE" \ + --req="PKCS10:req-kdc.der" \ + --certificate="FILE:kdc.crt" || exit 1 +${hxtool} request-create \ + --subject="CN=bar,DC=test,DC=h5l,DC=se" \ + --key=FILE:${keyfile2} \ + req-pkinit.der || + { echo "Failed to make CSR for PKINIT client cert"; exit 1; } +${hxtool} issue-certificate \ + --ca-certificate=FILE:$objdir/ca.crt,${keyfile} \ + --type="pkinit-client" \ + --pk-init-principal="host/synthesized.${domain}@$R" \ + --req="PKCS10:req-pkinit.der" \ + --lifetime=7d \ + --certificate="FILE:pkinit-synthetic.crt" || + { echo "Failed to make PKINIT client cert"; exit 1; } + +echo "Starting kdc needed for httpkadmind authentication to kadmind" +${kdc} --detach --testing || { echo "kdc failed to start"; cat messages.log; exit 1; } +kdcpid=`getpid kdc` + +echo "Starting httpkadmind with remote HDBs only" +restport=$restport1 +${httpkadmind} -H $server -H localhost -t --daemon \ + --writable-admin-server=$(uname -n):$admport \ + --read-only-admin-server=$(uname -n):$admport2 \ + --kadmin-client-name=httpkadmind/admin@${R} \ + --kadmin-client-keytab=$keytab || + { echo "httpkadmind failed to start"; exit 2; } +httpkadmindpid=`getpid httpkadmind` +ec=0 + +hn=xyz.${domain} +p=HTTP/$hn +echo "Fetching keytab for concrete principal $p using remote HDB" +rm -f extracted_keytab* +grant san_dnsname $hn httpkadmind/admin@${R} +KRB5CCNAME=$admincache ${kadmin} ext_keytab -k extracted_keytab $p || + { echo "Failed to get a keytab for $p with kadmin"; exit 1; } +${ktutil} -k "${objdir}/extracted_keytab" list --keys > extracted_keytab.kadmin || + { echo "Failed to list keytab for $p"; exit 1; } +get_keytab "spn=${p}" -sf -o "${objdir}/extracted_keytab" || + { echo "Failed to get a keytab for $p with curl"; exit 1; } +${ktutil} -k "${objdir}/extracted_keytab" list --keys > extracted_keytab.rest || + { echo "Failed to list keytab for $p"; exit 1; } +cmp extracted_keytab.kadmin extracted_keytab.rest || + { echo "Keytabs for $p don't match!"; exit 1; } + +hn=xyz.${domain} +p=HTTP/$hn +echo "Checking key rotation for concrete principal $p using remote HDB" +rm -f extracted_keytab* +grant san_dnsname $hn foo@${R} +get_keytab "dNSName=${hn}" -sf -o "${objdir}/extracted_keytab" || + { echo "Failed to get a keytab for $p with curl"; exit 1; } +${ktutil} -k "${objdir}/extracted_keytab" list --keys > extracted_keytab.rest1 || + { echo "Failed to list keytab for $p"; exit 1; } +test "$(grep $p extracted_keytab.rest1 | wc -l)" -eq 1 || + { echo "Wrong number of new keys!"; exit 1; } +get_keytab "dNSName=${hn}&rotate=true" -sf -o "${objdir}/extracted_keytab" && + { echo "GET succeeded for write operation!"; exit 1; } +get_keytab_POST "dNSName=${hn}&rotate=true" -s -o "${objdir}/extracted_keytab" || + { echo "Failed to rotate keys for $p"; exit 1; } +${ktutil} -k "${objdir}/extracted_keytab" list --keys > extracted_keytab.rest2 || + { echo "Failed to list keytab for $p"; exit 1; } +cmp extracted_keytab.rest1 extracted_keytab.rest2 > /dev/null && + { echo "Keys for $p did not change!"; exit 1; } +test "$(grep $p extracted_keytab.rest2 | wc -l)" -eq 2 || + { echo "Wrong number of new keys!"; exit 1; } + +sh ${leaks_kill} httpkadmind $httpkadmindpid || ec=1 +httpkadmindpid= + +echo "Starting httpkadmind with local read-only HDB and remote read-write HDB" +${httpkadmind} -H $server -H localhost -t --daemon \ + --local-read-only \ + --writable-admin-server=$(uname -n):$admport \ + --kadmin-client-name=httpkadmind/admin@${R} \ + --kadmin-client-keytab=$keytab || + { echo "httpkadmind failed to start"; exit 2; } +httpkadmindpid=`getpid httpkadmind` +ec=0 + +hn=xyz.${domain} +p=HTTP/$hn +echo "Fetching keytab for concrete principal $p using local read-only HDB" +rm -f extracted_keytab* +grant san_dnsname $hn httpkadmind/admin@${R} +KRB5CCNAME=$admincache ${kadmin} ext_keytab -k extracted_keytab $p || + { echo "Failed to get a keytab for $p with kadmin"; exit 1; } +${ktutil} -k "${objdir}/extracted_keytab" list --keys > extracted_keytab.kadmin || + { echo "Failed to list keytab for $p"; exit 1; } +get_keytab "spn=${p}" -sf -o "${objdir}/extracted_keytab" || + { echo "Failed to get a keytab for $p with curl"; exit 1; } +${ktutil} -k "${objdir}/extracted_keytab" list --keys > extracted_keytab.rest || + { echo "Failed to list keytab for $p"; exit 1; } +cmp extracted_keytab.kadmin extracted_keytab.rest || + { echo "Keytabs for $p don't match!"; exit 1; } + +hn=xyz.${domain} +p=HTTP/$hn +echo "Checking key rotation for concrete principal $p using local read-only HDB and remote HDB" +rm -f extracted_keytab* +grant san_dnsname $hn foo@${R} +get_keytab "dNSName=${hn}" -sf -o "${objdir}/extracted_keytab" || + { echo "Failed to get a keytab for $p with curl"; exit 1; } +${ktutil} -k "${objdir}/extracted_keytab" list --keys > extracted_keytab.rest1 || + { echo "Failed to list keytab for $p"; exit 1; } +test "$(grep $p extracted_keytab.rest1 | wc -l)" -eq 2 || + { echo "Wrong number of new keys!"; exit 1; } +get_keytab "dNSName=${hn}&rotate=true" -sf -o "${objdir}/extracted_keytab" && + { echo "GET succeeded for write operation!"; exit 1; } +get_keytab_POST "dNSName=${hn}&rotate=true" -s -o "${objdir}/extracted_keytab" || + { echo "Failed to rotate keys for $p"; exit 1; } +${ktutil} -k "${objdir}/extracted_keytab" list --keys > extracted_keytab.rest2 || + { echo "Failed to list keytab for $p"; exit 1; } +cmp extracted_keytab.rest1 extracted_keytab.rest2 > /dev/null && + { echo "Keys for $p did not change!"; exit 1; } +test "$(grep $p extracted_keytab.rest2 | wc -l)" -eq 3 || + { echo "Wrong number of new keys!"; exit 1; } + +echo "Checking that host services as clients can self-create" +hn=synthesized.${domain} +p=host/$hn +KRB5CCNAME=$admincache ${kadmin} get -s $p >/dev/null && + { echo "Internal error -- $p exists too soon"; exit 1; } +${kinit2} -C "FILE:${objdir}/pkinit-synthetic.crt,${keyfile2}" ${p}@${R} || \ + { echo "Failed to kinit with PKINIT client cert"; exit 1; } +${kgetcred2} HTTP/localhost@$R || echo WAT +rm -f extracted_keytab* +KRB5CCNAME=$cache2 \ +get_keytab_POST "spn=$p&create=true" -s -o "${objdir}/extracted_keytab" || + { echo "Failed to create and extract host keys for self"; exit 1; } +${ktutil} -k "${objdir}/extracted_keytab" list > /dev/null || + { echo "Failed to create and extract host keys for self (bogus keytab)"; exit 1; } +KRB5CCNAME=$admincache ${kadmin} get -s $p >/dev/null || + { echo "Failed to create and extract host keys for self"; exit 1; } + +echo "Checking that host services can't get other host service principals" +hn=nonexistent.${domain} +p=host/$hn +KRB5CCNAME=$cache2 \ +get_keytab_POST "spn=$p&create=true" -s -o "${objdir}/extracted_keytab2" && + { echo "Failed to fail to create and extract host keys for other!"; exit 1; } +${ktutil} -k "${objdir}/extracted_keytab2" list > /dev/null || true +KRB5CCNAME=$admincache ${kadmin} get -s $p >/dev/null && + { echo "Failed to fail to create and extract host keys for other!"; exit 1; } + +echo "Checking that host services can't get keys for themselves and others" +hn=synthesized.${domain} +p=host/$hn +p2=host/nonexistent.${domain} +${kinit2} -C "FILE:${objdir}/pkinit-synthetic.crt,${keyfile2}" ${p}@${R} || \ + { echo "Failed to kinit with PKINIT client cert"; exit 1; } +${kgetcred2} HTTP/localhost@$R || echo WAT +rm -f extracted_keytab* +KRB5CCNAME=$cache2 \ +get_keytab_POST "spn=$p&spn=$p2&create=true" -s -o "${objdir}/extracted_keytab" && + { echo "Failed to fail to create and extract host keys for other!"; exit 1; } +${ktutil} -k "${objdir}/extracted_keytab2" list > /dev/null || true +KRB5CCNAME=$admincache ${kadmin} get -s $p2 >/dev/null && + { echo "Failed to fail to create and extract host keys for other!"; exit 1; } + +echo "Checking that attributes for new principals can be configured" +hn=a-particular-hostname.test.h5l.se +p=host/$hn +${hxtool} issue-certificate \ + --ca-certificate=FILE:$objdir/ca.crt,${keyfile} \ + --type="pkinit-client" \ + --pk-init-principal="$p@$R" \ + --req="PKCS10:req-pkinit.der" \ + --lifetime=7d \ + --certificate="FILE:pkinit-synthetic.crt" || + { echo "Failed to make PKINIT client cert"; exit 1; } +KRB5CCNAME=$admincache ${kadmin} get -s $p >/dev/null 2>&1 && + { echo "Internal error -- $p exists too soon"; exit 1; } +${kinit2} -C "FILE:${objdir}/pkinit-synthetic.crt,${keyfile2}" ${p}@${R} || \ + { echo "Failed to kinit with PKINIT client cert"; exit 1; } +${kgetcred2} HTTP/localhost@$R || echo WAT +rm -f extracted_keytab* +KRB5CCNAME=$cache2 \ +get_keytab_POST "spn=$p&create=true" -s -o "${objdir}/extracted_keytab" || + { echo "Failed to create and extract host keys for self"; exit 1; } +${ktutil} -k "${objdir}/extracted_keytab" list > /dev/null || + { echo "Failed to create and extract host keys for self (bogus keytab)"; exit 1; } +KRB5CCNAME=$admincache ${kadmin} get -s $p >/dev/null || + { echo "Failed to create and extract host keys for self"; exit 1; } +KRB5CCNAME=$admincache ${kadmin} get $p | + grep 'Attributes:.*ok-as-delegate' > /dev/null || + { echo "Failed to create with configured attributes"; exit 1; } +KRB5CCNAME=$admincache ${kadmin} get $p | + grep 'Attributes:.*no-auth-data-reqd' > /dev/null || + { echo "Failed to create with configured attributes"; exit 1; } + +hn=other-hostname.test.h5l.se +p=host/$hn +${hxtool} issue-certificate \ + --ca-certificate=FILE:$objdir/ca.crt,${keyfile} \ + --type="pkinit-client" \ + --pk-init-principal="$p@$R" \ + --req="PKCS10:req-pkinit.der" \ + --lifetime=7d \ + --certificate="FILE:pkinit-synthetic.crt" || + { echo "Failed to make PKINIT client cert"; exit 1; } +KRB5CCNAME=$admincache ${kadmin} get -s $p >/dev/null 2>&1 && + { echo "Internal error -- $p exists too soon"; exit 1; } +${kinit2} -C "FILE:${objdir}/pkinit-synthetic.crt,${keyfile2}" ${p}@${R} || \ + { echo "Failed to kinit with PKINIT client cert"; exit 1; } +${kgetcred2} HTTP/localhost@$R || echo WAT +rm -f extracted_keytab* +KRB5CCNAME=$cache2 \ +get_keytab_POST "spn=$p&create=true" -s -o "${objdir}/extracted_keytab" || + { echo "Failed to create and extract host keys for self"; exit 1; } +${ktutil} -k "${objdir}/extracted_keytab" list > /dev/null || + { echo "Failed to create and extract host keys for self (bogus keytab)"; exit 1; } +KRB5CCNAME=$admincache ${kadmin} get -s $p >/dev/null || + { echo "Failed to create and extract host keys for self"; exit 1; } +KRB5CCNAME=$admincache ${kadmin} get $p | + grep 'Attributes:.*ok-as-delegate' > /dev/null && + { echo "Create with unexpected attributes"; exit 1; } +KRB5CCNAME=$admincache ${kadmin} get $p | + grep 'Attributes:.*no-auth-data-reqd' > /dev/null && + { echo "Create with unexpected attributes"; exit 1; } + +hn=a-server.prod.test.h5l.se +p=host/$hn +${hxtool} issue-certificate \ + --ca-certificate=FILE:$objdir/ca.crt,${keyfile} \ + --type="pkinit-client" \ + --pk-init-principal="$p@$R" \ + --req="PKCS10:req-pkinit.der" \ + --lifetime=7d \ + --certificate="FILE:pkinit-synthetic.crt" || + { echo "Failed to make PKINIT client cert"; exit 1; } +KRB5CCNAME=$admincache ${kadmin} get -s $p >/dev/null 2>&1 && + { echo "Internal error -- $p exists too soon"; exit 1; } +${kinit2} -C "FILE:${objdir}/pkinit-synthetic.crt,${keyfile2}" ${p}@${R} || \ + { echo "Failed to kinit with PKINIT client cert"; exit 1; } +${kgetcred2} HTTP/localhost@$R || echo WAT +rm -f extracted_keytab* +KRB5CCNAME=$cache2 \ +get_keytab_POST "spn=$p&create=true" -s -o "${objdir}/extracted_keytab" || + { echo "Failed to create and extract host keys for self"; exit 1; } +${ktutil} -k "${objdir}/extracted_keytab" list > /dev/null || + { echo "Failed to create and extract host keys for self (bogus keytab)"; exit 1; } +KRB5CCNAME=$admincache ${kadmin} get -s $p >/dev/null || + { echo "Failed to create and extract host keys for self"; exit 1; } +KRB5CCNAME=$admincache ${kadmin} get $p | + grep 'Attributes:.*ok-as-delegate' > /dev/null || + { echo "Failed to create with configured attributes"; exit 1; } +KRB5CCNAME=$admincache ${kadmin} get $p | + grep 'Attributes:.*no-auth-data-reqd' > /dev/null || + { echo "Failed to create with configured attributes"; exit 1; } + +hn=a-host.ns2.test.h5l.se +p=host/$hn +${hxtool} issue-certificate \ + --ca-certificate=FILE:$objdir/ca.crt,${keyfile} \ + --type="pkinit-client" \ + --pk-init-principal="$p@$R" \ + --req="PKCS10:req-pkinit.der" \ + --lifetime=7d \ + --certificate="FILE:pkinit-synthetic.crt" || + { echo "Failed to make PKINIT client cert"; exit 1; } +KRB5CCNAME=$admincache ${kadmin} get -s $p >/dev/null 2>&1 && + { echo "Internal error -- $p exists too soon"; exit 1; } +${kinit2} -C "FILE:${objdir}/pkinit-synthetic.crt,${keyfile2}" ${p}@${R} || \ + { echo "Failed to kinit with PKINIT client cert"; exit 1; } +${kgetcred2} HTTP/localhost@$R || echo WAT +rm -f extracted_keytab* +KRB5CCNAME=$cache2 \ +get_keytab_POST "spn=$p&create=true" -s -o "${objdir}/extracted_keytab" || + { echo "Failed to create and extract host keys for self"; exit 1; } +${ktutil} -k "${objdir}/extracted_keytab" list > /dev/null || + { echo "Failed to create and extract host keys for self (bogus keytab)"; exit 1; } +KRB5CCNAME=$admincache ${kadmin} get -s $p >/dev/null || + { echo "Failed to create and extract host keys for self"; exit 1; } +KRB5CCNAME=$admincache ${kadmin} get $p | + grep 'Attributes:.*ok-as-delegate' > /dev/null || + { echo "Failed to create with namespace attributes"; exit 1; } +KRB5CCNAME=$admincache ${kadmin} get $p | + grep 'Attributes:.*no-auth-data-reqd' > /dev/null && + { echo "Create with unexpected attributes"; exit 1; } + +grep 'Internal error' messages.log && + { echo "Internal errors in log"; exit 1; } + +sh ${leaks_kill} test_csr_authorizer $test_csr_authorizer_pid || ec=1 +sh ${leaks_kill} httpkadmind $httpkadmindpid || ec=1 +sh ${leaks_kill} kadmind $kadmindpid || ec=1 +sh ${leaks_kill} kadmind $kadmind2pid || ec=1 +sh ${leaks_kill} kdc $kdcpid || ec=1 + +if [ $ec = 0 ]; then + trap "" EXIT + echo "Success" +fi + +# TODO +# +# - implement and test that we can materialize a principal yet leave it with +# virtual keys +# - test new key delay? this one is tricky + +exit $ec -- cgit v1.2.3