diff --git a/configure.ac b/configure.ac index 15069dd4a..bf7820bb3 100644 --- a/configure.ac +++ b/configure.ac @@ -232,10 +232,19 @@ AC_SUBST([MICROHTTPD_LIBS]) dnl mitkrb5 AC_ARG_WITH([mitkrb5], - AC_HELP_STRING([--with-mitkrb5], [Path to MIT Kerberos for interop testing @<:@default=check@:>@]), + AC_HELP_STRING([--with-mitkrb5=PATH], [Path to MIT Kerberos for interop testing]), [], - [with_mikrb5=check]) -AM_CONDITIONAL([MITKRB5], [test "$with_mitkrb5" != "no"]) + [with_mitkrb5=no]) +MITKRB5= +if test "$with_mitkrb5" != "no" && test "$with_mitkrb5" != "yes"; then + if test -d "$with_mitkrb5"; then + MITKRB5="$with_mitkrb5" + else + AC_MSG_WARN([MIT Kerberos directory $with_mitkrb5 does not exist]) + fi +fi +AC_SUBST(MITKRB5) +AM_CONDITIONAL([MITKRB5], [test -n "$MITKRB5"]) dnl Check for sqlite rk_TEST_PACKAGE(sqlite3, diff --git a/tests/kdc/Makefile.am b/tests/kdc/Makefile.am index 0271777d4..7226c01bb 100644 --- a/tests/kdc/Makefile.am +++ b/tests/kdc/Makefile.am @@ -35,6 +35,7 @@ SCRIPT_TESTS = \ check-kdc \ check-kdc-weak \ check-kpasswdd \ + check-mit-kdc \ check-pkinit \ check-bx509 \ check-httpkadmind \ @@ -148,6 +149,11 @@ check-uu: check-uu.in Makefile $(chmod) +x check-uu.tmp && \ mv check-uu.tmp check-uu +check-mit-kdc: check-mit-kdc.in Makefile + $(do_subst) < $(srcdir)/check-mit-kdc.in > check-mit-kdc.tmp && \ + $(chmod) +x check-mit-kdc.tmp && \ + mv check-mit-kdc.tmp check-mit-kdc + check-pkinit: check-pkinit.in Makefile krb5-pkinit.conf krb5-pkinit2.conf $(do_subst) < $(srcdir)/check-pkinit.in > check-pkinit.tmp && \ $(chmod) +x check-pkinit.tmp && \ @@ -385,6 +391,7 @@ EXTRA_DIST = \ check-kdc.in \ check-kinit.in \ check-kpasswdd.in \ + check-mit-kdc.in \ check-pkinit.in \ check-referral.in \ check-tester.in \ diff --git a/tests/kdc/check-mit-kdc.in b/tests/kdc/check-mit-kdc.in new file mode 100644 index 000000000..7ae472cbf --- /dev/null +++ b/tests/kdc/check-mit-kdc.in @@ -0,0 +1,408 @@ +#!/bin/sh +# +# Copyright (c) 2006 - 2024 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. + +# +# Test Heimdal clients against MIT Kerberos KDC +# + +top_builddir="@top_builddir@" +env_setup="@env_setup@" +objdir="@objdir@" + +. ${env_setup} + +# Skip if MIT Kerberos is not available +if [ -z "$MITKRB5" ] || [ ! -d "$MITKRB5" ]; then + echo "MIT Kerberos not available, skipping" + exit 77 +fi + +# Check for required MIT binaries +for prog in kdb5_util krb5kdc kadmin.local; do + if [ ! -x "${MITKRB5}/sbin/${prog}" ] && [ ! -x "${MITKRB5}/bin/${prog}" ]; then + echo "MIT ${prog} not found, skipping" + exit 77 + fi +done + +# Check for PKINIT support +rsa=yes +pkinit=no +if ${hxtool} info | grep 'rsa: hx509 null RSA' > /dev/null ; then + rsa=no +fi +if ${hxtool} info | grep 'rand: not available' > /dev/null ; then + rsa=no +fi +if ${kinit} --help 2>&1 | grep "CA certificates" > /dev/null; then + pkinit=yes +fi + +testfailed="echo test failed; cat messages.log; exit 1" + +R=MIT-TEST.H5L.SE + +port=@port@ +admport=@admport@ + +mitdir="${objdir}/mit-kdc" +cache="FILE:${objdir}/mit-cache.krb5" +keytab="${objdir}/mit-server.keytab" +keyfile="${hx509_data}/key.der" +keyfile2="${hx509_data}/key2.der" + +kinit="${kinit} -c $cache ${afs_no_afslog}" +klist="${klist} -c $cache" +kgetcred="${kgetcred} -c $cache" +kdestroy="${kdestroy} -c $cache ${afs_no_unlog}" + +server=host/localhost + +KRB5_CONFIG="${objdir}/krb5-mit-kdc.conf" +export KRB5_CONFIG + +# Clean up from previous runs +rm -rf "${mitdir}" +rm -f "${objdir}/krb5-mit-kdc.conf" +rm -f "${objdir}/mit-kdc.conf" +rm -f "${cache#FILE:}" +rm -f "${keytab}" +rm -f "${objdir}/mit-ca.crt" +rm -f "${objdir}/mit-kdc.crt" +rm -f "${objdir}/mit-user.crt" +rm -f "${objdir}/mit-user.pem" +rm -f "${objdir}/mit-kdc-key.pem" +rm -f req-mit-kdc.der req-mit-user.der + +mkdir -p "${mitdir}" + +> messages.log + +ec=0 +kdcpid= + +cleanup() { + if [ -n "$kdcpid" ]; then + echo "Killing MIT KDC (pid $kdcpid)" + kill $kdcpid 2>/dev/null + wait $kdcpid 2>/dev/null + fi + trap '' EXIT INT TERM + # cat messages.log + exit $ec +} +trap cleanup EXIT INT TERM + +# +# Set up certificates for PKINIT +# +if [ "$pkinit" = yes ] && [ "$rsa" = yes ]; then + echo "Setting up PKINIT certificates" + + ${hxtool} request-create \ + --subject="CN=MIT KDC,DC=mit-test,DC=h5l,DC=se" \ + --key=FILE:${keyfile2} \ + req-mit-kdc.der || exit 1 + + ${hxtool} request-create \ + --subject="CN=foo,DC=mit-test,DC=h5l,DC=se" \ + --key=FILE:${keyfile2} \ + req-mit-user.der || exit 1 + + echo "Issuing self-signed CA cert" + ${hxtool} issue-certificate \ + --self-signed \ + --issue-ca \ + --ca-private-key=FILE:${keyfile} \ + --subject="CN=MIT Test CA,DC=mit-test,DC=h5l,DC=se" \ + --certificate="PEM-FILE:${objdir}/mit-ca.crt" || exit 1 + + echo "Issuing MIT KDC certificate" + ${hxtool} issue-certificate \ + --ca-certificate=PEM-FILE:${objdir}/mit-ca.crt,${keyfile} \ + --type="pkinit-kdc" \ + --pk-init-principal="krbtgt/${R}@${R}" \ + --req="PKCS10:req-mit-kdc.der" \ + --certificate="PEM-FILE:${objdir}/mit-kdc.crt" || exit 1 + + echo "Issuing user certificate" + ${hxtool} issue-certificate \ + --ca-certificate=PEM-FILE:${objdir}/mit-ca.crt,${keyfile} \ + --type="pkinit-client" \ + --pk-init-principal="foo@${R}" \ + --req="PKCS10:req-mit-user.der" \ + --certificate="PEM-FILE:${objdir}/mit-user.crt" || exit 1 + + # Create combined PEM file for user PKINIT + cat ${objdir}/mit-user.crt > ${objdir}/mit-user.pem + openssl rsa -in ${keyfile2} -outform PEM >> ${objdir}/mit-user.pem 2>/dev/null || \ + ${hxtool} print --content FILE:${keyfile2} >> ${objdir}/mit-user.pem + + # Create KDC key PEM file for MIT PKINIT + openssl rsa -in ${keyfile2} -outform PEM > ${objdir}/mit-kdc-key.pem 2>/dev/null || \ + ${hxtool} print --content FILE:${keyfile2} > ${objdir}/mit-kdc-key.pem + + pkinit_configured=yes +else + pkinit_configured=no +fi + +# +# Create krb5.conf for Heimdal clients (and MIT tools) +# +cat > ${objdir}/krb5-mit-kdc.conf <> ${objdir}/krb5-mit-kdc.conf <> ${objdir}/krb5-mit-kdc.conf <> ${objdir}/krb5-mit-kdc.conf < ${objdir}/mit-kdc.conf <> ${objdir}/mit-kdc.conf <> ${objdir}/mit-kdc.conf < ${mitdir}/kadm5.acl </dev/null; then + echo "MIT KDC failed to start" + cat messages.log + exit 1 +fi +echo "MIT KDC running with PID $kdcpid" + +# +# Test 1: Password authentication with Heimdal kinit +# +echo "" +echo "=== Test 1: Heimdal kinit with password against MIT KDC ===" +echo foo > ${objdir}/foopassword +${kinit} --password-file=${objdir}/foopassword foo@${R} || \ + { ec=1; eval "${testfailed}"; } + +echo "Verifying ticket" +${klist} || { ec=1; eval "${testfailed}"; } +${klist} | grep "krbtgt/${R}@${R}" > /dev/null || { ec=1; echo "No TGT found"; eval "${testfailed}"; } + +echo "Getting service ticket" +${kgetcred} ${server}@${R} || { ec=1; eval "${testfailed}"; } +${klist} | grep "${server}@${R}" > /dev/null || { ec=1; echo "No service ticket found"; eval "${testfailed}"; } + +${kdestroy} +echo "Test 1 PASSED" + +# +# Test 2: PKINIT authentication with Heimdal kinit +# +echo "=== Test 2: Heimdal kinit with PKINIT against MIT KDC (negotiate ECDH curve) ===" + +# Note that MIT does not support X25519, but Heimdal prefers X225519, but we +# should negotiate to P-256: +${kinit} -C FILE:${objdir}/mit-user.pem foo@${R} 2>/dev/null || { ec=1; eval "${testfailed}"; } +${klist} || { ec=1; eval "${testfailed}"; } +${klist} | grep "krbtgt/${R}@${R}" > /dev/null || { ec=1; echo "No TGT found"; eval "${testfailed}"; } +${kgetcred} ${server}@${R} || { ec=1; eval "${testfailed}"; } +${kdestroy} + +echo "Test 2 PASSED" + +# +# Test 3: PKINIT authentication with Heimdal kinit with a preference for an EC +# DH curve (P-256) +# +echo "=== Test 3: Heimdal kinit with PKINIT against MIT KDC (P-256) ===" + +${kinit} --key-agreement=P-256 -C FILE:${objdir}/mit-user.pem foo@${R} 2>/dev/null || { ec=1; eval "${testfailed}"; } +${klist} || { ec=1; eval "${testfailed}"; } +${klist} | grep "krbtgt/${R}@${R}" > /dev/null || { ec=1; echo "No TGT found"; eval "${testfailed}"; } +${kgetcred} ${server}@${R} || { ec=1; eval "${testfailed}"; } +${kdestroy} + +echo "Test 3 PASSED" + +# +# Test 4: PKINIT authentication with Heimdal kinit with a preference for an EC +# DH curve (P-521) +# +echo "=== Test 4: Heimdal kinit with PKINIT against MIT KDC (P-521) ===" + +${kinit} --key-agreement=P-521 -C FILE:${objdir}/mit-user.pem foo@${R} 2>/dev/null || { ec=1; eval "${testfailed}"; } +${klist} || { ec=1; eval "${testfailed}"; } +${klist} | grep "krbtgt/${R}@${R}" > /dev/null || { ec=1; echo "No TGT found"; eval "${testfailed}"; } +${kgetcred} ${server}@${R} || { ec=1; eval "${testfailed}"; } +${kdestroy} + +echo "Test 4 PASSED" + +# +# Test 5: PKINIT authentication with Heimdal kinit with a preference for an EC +# DH curve (P-521) +# +echo "=== Test 5: Heimdal kinit with PKINIT against MIT KDC (modp 2048) ===" + +${kinit} --key-agreement=modp_2048 -C FILE:${objdir}/mit-user.pem foo@${R} 2>/dev/null || { ec=1; eval "${testfailed}"; } +${klist} || { ec=1; eval "${testfailed}"; } +${klist} | grep "krbtgt/${R}@${R}" > /dev/null || { ec=1; echo "No TGT found"; eval "${testfailed}"; } +${kgetcred} ${server}@${R} || { ec=1; eval "${testfailed}"; } +${kdestroy} + +echo "Test 5 PASSED" + +# +# Test 6: FAST with Heimdal kinit (if MIT KDC supports it) +# +echo "" +echo "=== Test 6: Testing with FAST armor ===" + +# Get armor ticket +${kinit} --password-file=${objdir}/foopassword foo@${R} || \ + { ec=1; eval "${testfailed}"; } + +acache="FILE:${objdir}/mit-acache.krb5" +${kinit} -c ${acache} --password-file=${objdir}/foopassword bar@${R} --fast-armor-cache=$cache || \ + { echo "FAST kinit failed (may be expected if MIT KDC does not support it)"; } + +rm -f "${acache#FILE:}" +${kdestroy} +echo "Test 6 completed" + +# +# Done +# +echo "" +echo "All tests passed!" +ec=0 +exit 0