#!/bin/sh # # Copyright (c) 2006 - 2008 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 R=TEST.H5L.SE port=@port@ kadmin="${kadmin} -l -A -r $R" kdc="${kdc} --addresses=localhost -P $port" server=host/datan.test.h5l.se cache="FILE:${objdir}/cache.krb5" keyfile="${hx509_data}/key.der" keyfile2="${hx509_data}/key2.der" kinit="${kinit} -c $cache ${afs_no_afslog}" klistjson="${klist} --json -c $cache" klistplain="${klist} -c $cache" klist="${klist} --hidden -v -c $cache" kgetcred="${kgetcred} -c $cache" kdestroy="${kdestroy} -c $cache ${afs_no_unlog}" kx509="${kx509} -c $cache" KRB5_CONFIG="${objdir}/krb5-pkinit.conf" export KRB5_CONFIG HEIM_PIDFILE_DIR=$objdir export HEIM_PIDFILE_DIR HEIM_IPC_DIR=$objdir export HEIM_IPC_DIR 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 # If we doesn't support pkinit and have RSA, give up if test "$pkinit" != yes -o "$rsa" != yes ; then exit 77 fi rm -f current-db* rm -f out-* rm -f mkey.file* > messages.log echo Creating database ${kadmin} < ${objdir}/foopassword echo Starting kdc ; > messages.log KRB5_CONFIG="${objdir}/krb5-pkinit2.conf" ${kdc} --detach --testing || { echo "kdc failed to start"; cat messages.log; exit 1; } kdcpid=`getpid kdc` cleanup() { echo signal killing kdc kill -9 ${kdcpid} trap '' EXIT INT TERM cat messages.log cat ca.crt kdc.crt pkinit.crt pkinit-synthetic.crt exit 1 } trap cleanup EXIT INT TERM ec=0 echo "Trying pk-init (principal in cert; longer max_life)"; > messages.log base="${objdir}" ${kinit} --lifetime=5d -C FILE:${base}/pkinit.crt,${keyfile2} bar@${R} || \ { ec=1 ; eval "${testfailed}"; } ${kgetcred} ${server}@${R} || { ec=1 ; eval "${testfailed}"; } ${klist} if jq --version >/dev/null 2>&1 && jq -ne true >/dev/null 2>&1; then ${klistjson} | jq -e '(((.tickets[0].Expires| strptime("%b %d %H:%M:%S %Y")|mktime) - now) / 86400) | (floor < 4)' >/dev/null && { ec=1 ; eval "${testfailed}"; } fi ${kdestroy} echo "Trying pk-init (principal in cert; synthetic)"; > messages.log base="${objdir}" ${kinit} --lifetime=5d -C FILE:${base}/pkinit-synthetic.crt,${keyfile2} synthetized@${R} || \ { ec=1 ; eval "${testfailed}"; } ${kgetcred} ${server}@${R} || { ec=1 ; eval "${testfailed}"; } ${klist} ${kdestroy} echo "Restarting kdc ($kdcpid)" sh ${leaks_kill} kdc $kdcpid || ec=1 KRB5_CONFIG="${objdir}/krb5-pkinit.conf" ${kdc} --detach --testing || { echo "kdc failed to start"; cat messages.log; exit 1; } kdcpid=`getpid kdc` echo "Trying pk-init (principal in cert)"; > messages.log base="${objdir}" ${kinit} -C FILE:${base}/pkinit.crt,${keyfile2} bar@${R} || \ { ec=1 ; eval "${testfailed}"; } ${kgetcred} ${server}@${R} || { ec=1 ; eval "${testfailed}"; } ${klist} if jq --version >/dev/null 2>&1 && jq -ne true >/dev/null 2>&1; then ${klistjson} | jq -e '(((.tickets[0].Expires| strptime("%b %d %H:%M:%S %Y")|mktime) - now) / 86400) | (floor > 1)' >/dev/null && { ec=1 ; eval "${testfailed}"; } fi ${kdestroy} echo "Trying pk-init (principal in cert; longer max_life from cert ext)"; > messages.log # Re-issue cert with --pkinit-max-life=7d ${hxtool} issue-certificate \ --ca-certificate=FILE:$objdir/ca.crt,${keyfile} \ --type="pkinit-client" \ --pk-init-principal="bar@TEST.H5L.SE" \ --req="PKCS10:req-pkinit.der" \ --lifetime=7d \ --pkinit-max-life=7d \ --certificate="FILE:pkinit.crt" || exit 1 base="${objdir}" ${kinit} --lifetime=5d -C FILE:${base}/pkinit.crt,${keyfile2} bar@${R} || \ { ec=1 ; eval "${testfailed}"; } ${kgetcred} ${server}@${R} || { ec=1 ; eval "${testfailed}"; } ${klist} if jq --version >/dev/null 2>&1 && jq -ne true >/dev/null 2>&1; then ${klistjson} | jq -e '(((.tickets[0].Expires| strptime("%b %d %H:%M:%S %Y")|mktime) - now) / 86400) | (floor < 4)' >/dev/null && { ec=1 ; eval "${testfailed}"; } fi echo "Check kx509 certificate acquisition" ${kx509} -s || { ec=1 ; eval "${testfailed}"; } ${kx509} -o PEM-FILE:${objdir}/kx509.pem || { ec=1 ; eval "${testfailed}"; } ${kdestroy} echo "Check PKINIT w/ kx509 certificate" ${kinit} -C PEM-FILE:${objdir}/kx509.pem bar@${R} || \ { ec=1 ; eval "${testfailed}"; } echo "Trying pk-init (principal in pki-mapping file) "; > messages.log ${kinit} -C FILE:${base}/pkinit.crt,${keyfile2} foo@${R} || \ { ec=1 ; eval "${testfailed}"; } ${kgetcred} ${server}@${R} || { ec=1 ; eval "${testfailed}"; } ${kdestroy} echo "Trying pk-init (principal subject in DB)"; > messages.log ${kinit} -C FILE:${base}/pkinit2.crt,${keyfile2} baz@${R} || \ { ec=1 ; eval "${testfailed}"; } ${kgetcred} ${server}@${R} || { ec=1 ; eval "${testfailed}"; } ${kdestroy} echo "Trying pk-init (ms upn)"; > messages.log ${kinit} -C FILE:${base}/pkinit3.crt,${keyfile2} bar@${R} || \ { ec=1 ; eval "${testfailed}"; } ${kgetcred} ${server}@${R} || { ec=1 ; eval "${testfailed}"; } ${kdestroy} echo "Trying pk-init (ms upn, enterprise)"; > messages.log ${kinit} --canonicalize --enterprise \ -C FILE:${base}/pkinit4.crt,${keyfile2} baz2@test.h5l.se || \ { ec=1 ; eval "${testfailed}"; } ${kgetcred} ${server}@${R} || { ec=1 ; eval "${testfailed}"; } ${kdestroy} echo "Trying pk-init (ms upn, enterprise, pk-enterprise)"; > messages.log ${kinit} --canonicalize \ --pk-enterprise \ -C FILE:${base}/pkinit4.crt,${keyfile2} ${R} || \ { ec=1 ; eval "${testfailed}"; } ${kgetcred} ${server}@${R} || { ec=1 ; eval "${testfailed}"; } ${kdestroy} echo "Testing DH group and KDF algorithm options" # Helper function to check that the KDC used the expected key agreement algorithm check_keyagreement() { expected="$1" if grep "AS-REQ SUCCESS" messages.log | grep -q "keyagreement=${expected}"; then echo " OK: keyagreement=${expected}" else echo " FAIL: expected keyagreement=${expected}" grep "AS-REQ SUCCESS" messages.log | head -1 ec=1 fi } # Helper function to check that the KDC used the expected KDF check_kdf() { expected="$1" if grep "AS-REQ SUCCESS" messages.log | grep -q "kdf=${expected}"; then echo " OK: kdf=${expected}" else echo " FAIL: expected kdf=${expected}" grep "AS-REQ SUCCESS" messages.log | head -1 ec=1 fi } # Test various DH groups (RFC 3526 MODP groups) # Note: The KDC logs the moduli name from its built-in/configured moduli file, # not the client's requested group name. The default built-in is rfc3526-MODP-group14. for dh_group in modp_2048 modp_3072; do echo "Trying pk-init with --key-agreement=${dh_group}"; > messages.log ${kinit} --key-agreement=${dh_group} \ -C FILE:${base}/pkinit.crt,${keyfile2} bar@${R} || \ { ec=1 ; eval "${testfailed}"; } # The KDC uses its configured moduli; default is rfc3526-MODP-group14 check_keyagreement "rfc3526-MODP-group14" ${kdestroy} done # Test ECDH curves (NIST curves) # Note: OpenSSL uses different names internally (prime256v1, secp384r1, secp521r1) for curve in P-256:prime256v1 P-384:secp384r1 P-521:secp521r1; do cli_name="${curve%%:*}" log_name="${curve##*:}" echo "Trying pk-init with --key-agreement=${cli_name}"; > messages.log ${kinit} --key-agreement=${cli_name} \ -C FILE:${base}/pkinit.crt,${keyfile2} bar@${R} || \ { ec=1 ; eval "${testfailed}"; } check_keyagreement "${log_name}" ${kdestroy} done # Test RFC 8636 KDF algorithms for kdf in ah-sha256:id_pkinit_kdf_ah_sha256 ah-sha384:id_pkinit_kdf_ah_sha384 ah-sha512:id_pkinit_kdf_ah_sha512; do cli_name="${kdf%%:*}" log_name="${kdf##*:}" echo "Trying pk-init with --kdf=${cli_name}"; > messages.log ${kinit} --kdf=${cli_name} \ -C FILE:${base}/pkinit.crt,${keyfile2} bar@${R} || \ { ec=1 ; eval "${testfailed}"; } check_kdf "${log_name}" ${kdestroy} done # Test legacy RFC 4556 KDF (SHA-1 based octetstring2key) echo "Trying pk-init with --kdf=RFC4556 (legacy)"; > messages.log ${kinit} --kdf=RFC4556 \ -C FILE:${base}/pkinit.crt,${keyfile2} bar@${R} || \ { ec=1 ; eval "${testfailed}"; } check_kdf "RFC4556" ${kdestroy} # Test combinations of DH group and KDF echo "Trying pk-init with --key-agreement=P-256 --kdf=ah-sha256"; > messages.log ${kinit} --key-agreement=P-256 --kdf=ah-sha256 \ -C FILE:${base}/pkinit.crt,${keyfile2} bar@${R} || \ { ec=1 ; eval "${testfailed}"; } check_keyagreement "prime256v1" check_kdf "id_pkinit_kdf_ah_sha256" ${kdestroy} echo "Trying pk-init with --key-agreement=modp_3072 --kdf=ah-sha384"; > messages.log ${kinit} --key-agreement=modp_3072 --kdf=ah-sha384 \ -C FILE:${base}/pkinit.crt,${keyfile2} bar@${R} || \ { ec=1 ; eval "${testfailed}"; } # The KDC uses its configured moduli; default is rfc3526-MODP-group14 check_keyagreement "rfc3526-MODP-group14" check_kdf "id_pkinit_kdf_ah_sha384" ${kdestroy} # Test X25519 if available (may fail if not supported by OpenSSL build) echo "Trying pk-init with --key-agreement=X25519 (may skip if unsupported)"; > messages.log if ${kinit} --key-agreement=X25519 \ -C FILE:${base}/pkinit.crt,${keyfile2} bar@${R} 2>/dev/null; then check_keyagreement "x25519" ${kdestroy} else echo "X25519 not supported (skipped)" fi KRB5_CONFIG="${objdir}/krb5-pkinit-win.conf" export KRB5_CONFIG echo "Duplicated tests, now in windows 2000 mode" echo "Trying pk-init (principal in cert)"; > messages.log base="${objdir}" ${kinit} -C FILE:${base}/pkinit.crt,${keyfile2} bar@${R} || \ { ec=1 ; eval "${testfailed}"; } ${kgetcred} ${server}@${R} || { ec=1 ; eval "${testfailed}"; } ${kdestroy} echo "Trying pk-init (principal in pki-mapping file) "; > messages.log ${kinit} -C FILE:${base}/pkinit.crt,${keyfile2} foo@${R} || \ { ec=1 ; eval "${testfailed}"; } ${kgetcred} ${server}@${R} || { ec=1 ; eval "${testfailed}"; } ${kdestroy} echo "Trying pk-init (principal subject in DB)"; > messages.log ${kinit} -C FILE:${base}/pkinit2.crt,${keyfile2} baz@${R} || \ { ec=1 ; eval "${testfailed}"; } ${kgetcred} ${server}@${R} || { ec=1 ; eval "${testfailed}"; } ${kdestroy} echo "Trying pk-init (ms upn)"; > messages.log ${kinit} -C FILE:${base}/pkinit3.crt,${keyfile2} bar@${R} || \ { ec=1 ; eval "${testfailed}"; } ${kgetcred} ${server}@${R} || { ec=1 ; eval "${testfailed}"; } ${kdestroy} KRB5_CONFIG="${objdir}/krb5-pkinit.conf" export KRB5_CONFIG # PKCS#11 support via OpenSSL pkcs11-provider # Requires --with-openssl-pkcs11-provider=path to be set at configure time openssl_pkcs11_provider="@OPENSSL_PKCS11_PROVIDER@" if [ "x${openssl_pkcs11_provider}" != "x" ] ; then echo "Trying PKCS11 support (via OpenSSL pkcs11-provider)" # Find the soft PKCS#11 module (libhx509.so contains softp11) dir=${base}/../../lib/hx509 p11_module= for a in libhx509.so .libs/libhx509.so libhx509.dylib .libs/libhx509.dylib ; do if [ -f $dir/$a ] ; then p11_module=$(cd $dir && pwd)/$a break fi done if [ "x${p11_module}" != "x" ] ; then # Convert to absolute paths for softp11 config # (softp11 may run from a different working directory context) abs_objdir=$(cd ${objdir} && pwd) abs_pkinit_crt="${abs_objdir}/pkinit.crt" abs_keyfile2=$(cd $(dirname ${keyfile2}) && pwd)/$(basename ${keyfile2}) # Create softp11 config file cat > ${objdir}/test-rc-file.rc < ${objdir}/openssl-pkcs11.cnf < messages.log ${kinit} -C "PKCS11:pkcs11:" foo@${R} || \ { ec=1 ; eval "${testfailed}"; } ${kgetcred} ${server}@${R} || { ec=1 ; eval "${testfailed}"; } ${kdestroy} unset PKCS11_PROVIDER_MODULE unset OPENSSL_CONF unset SOFTPKCS11RC else echo "Skipping PKCS#11 test: soft PKCS#11 module not found" fi else echo "Skipping PKCS#11 test: --with-openssl-pkcs11-provider not configured" fi echo "killing kdc (${kdcpid})" sh ${leaks_kill} kdc $kdcpid || ec=1 trap "" EXIT exit $ec