@@ -272,3 +272,29 @@ _report_exit() {
fi
}
+_at_exit() {
+ _report_exit
+ if [ -n "${WORKDIR}" ]; then
+ rm -f "${WORKDIR}"
+ fi
+}
+
+_softhsm_setup() {
+ local workdir="$1"
+
+ local msg
+
+ export SOFTHSM_SETUP_CONFIGDIR="${workdir}"
+ export SOFTHSM2_CONF="${workdir}/softhsm2.conf"
+
+ msg=$(./softhsm_setup setup 2>&1)
+ if [ $? -eq 0 ]; then
+ echo "softhsm_setup setup succeeded: $msg"
+ PKCS11_KEYURI=$(echo $msg | sed -n 's|^keyuri: \(.*\)|\1|p')
+
+ export OPENSSL_ENGINE="-engine pkcs11"
+ export OPENSSL_KEYFORM="-keyform engine"
+ else
+ echo "softhsm_setup setup failed: ${msg}"
+ fi
+}
@@ -28,7 +28,8 @@ fi
./gen-keys.sh >/dev/null 2>&1
-trap _report_exit EXIT
+trap _at_exit EXIT
+WORKDIR=$(mktemp -d)
set -f # disable globbing
# Determine keyid from a cert
@@ -132,11 +133,16 @@ check_sign() {
# OPTS (additional options for evmctl),
# FILE (working file to sign).
local "$@"
- local KEY=${KEY%.*}.key
+ local key verifykey
local FILE=${FILE:-$ALG.txt}
- # Normalize key filename
- KEY=test-${KEY#test-}
+ # Normalize key filename if it's not a pkcs11 URI
+ if [ ${KEY:0:7} != pkcs11: ]; then
+ key=${KEY%.*}.key
+ key=test-${key#test-}
+ else
+ key=${KEY}
+ fi
# Append suffix to files for negative tests, because we may
# leave only good files for verify tests.
@@ -152,33 +158,33 @@ check_sign() {
if _test_expected_to_pass; then
# Can openssl work with this digest?
- cmd="openssl dgst $OPENSSL_ENGINE -$ALG $FILE"
+ cmd="openssl dgst $OPENSSL_ENGINE $OPENSSL_KEYFORM -$ALG $FILE"
echo - "$cmd"
if ! $cmd >/dev/null; then
- echo "${CYAN}$ALG ($KEY) test is skipped (openssl is unable to digest)$NORM"
+ echo "${CYAN}$ALG ($key) test is skipped (openssl is unable to digest)$NORM"
return "$SKIP"
fi
- if [ ! -e "$KEY" ]; then
- echo "${CYAN}$ALG ($KEY) test is skipped (key file not found)$NORM"
+ if [ "${key:0:7}" != pkcs11: ] && [ ! -e "$key" ]; then
+ echo "${CYAN}$ALG ($key) test is skipped (key file not found)$NORM"
return "$SKIP"
fi
# Can openssl sign with this digest and key?
- cmd="openssl dgst $OPENSSL_ENGINE -$ALG -sign $KEY -hex $FILE"
+ cmd="openssl dgst $OPENSSL_ENGINE $OPENSSL_KEYFORM -$ALG -sign $key -hex $FILE"
echo - "$cmd"
if ! $cmd >/dev/null; then
- echo "${CYAN}$ALG ($KEY) test is skipped (openssl is unable to sign)$NORM"
+ echo "${CYAN}$ALG ($key) test is skipped (openssl is unable to sign)$NORM"
return "$SKIP"
fi
fi
# Insert keyid from cert into PREFIX in-place of marker `:K:'
if [[ $PREFIX =~ :K: ]]; then
- keyid=$(_keyid_from_cert "$KEY")
+ keyid=$(_keyid_from_cert "$key")
if [ $? -ne 0 ]; then
color_red
- echo "Unable to determine keyid for $KEY"
+ echo "Unable to determine keyid for $key"
color_restore
return "$HARDFAIL"
fi
@@ -187,7 +193,7 @@ check_sign() {
fi
# Perform signing by evmctl
- _evmctl_sign "$TYPE" "$KEY" "$ALG" "$FILE" "$OPTS" || return
+ _evmctl_sign "$TYPE" "$key" "$ALG" "$FILE" "$OPTS" || return
# First simple pattern match the signature.
ADD_TEXT_FOR=$ALG \
@@ -207,7 +213,13 @@ check_sign() {
_extract_xattr "$FILE" "$(_xattr "$TYPE")" "$FILE.sig2" "$PREFIX"
# Verify extracted signature with openssl
- cmd="openssl dgst $OPENSSL_ENGINE -$ALG -verify ${KEY%.*}.pub \
+ if [ "${key:0:7}" != pkcs11: ]; then
+ verifykey=${key%.*}.pub
+ else
+ verifykey=${key}
+ fi
+
+ cmd="openssl dgst $OPENSSL_ENGINE $OPENSSL_KEYFORM -$ALG -verify ${verifykey} \
-signature $FILE.sig2 $FILE"
echo - "$cmd"
if ! $cmd; then
@@ -413,3 +425,13 @@ expect_fail \
expect_fail \
check_sign TYPE=ima KEY=gost2012_256-B ALG=md_gost12_512 PREFIX=0x0302 OPTS=
+_softhsm_setup "${WORKDIR}"
+if [ -n "${PKCS11_KEYURI}" ]; then
+ expect_pass check_sign FILE=pkcs11test TYPE=ima KEY=${PKCS11_KEYURI} ALG=sha256 PREFIX=0x030204aabbccdd0100 OPTS=--keyid=aabbccdd
+ expect_pass check_sign FILE=pkcs11test TYPE=ima KEY=${PKCS11_KEYURI} ALG=sha1 PREFIX=0x030202aabbccdd0100 OPTS=--keyid=aabbccdd
+else
+ # skip these two tests
+ __skip() { echo "pkcs11 test is skipped: could not setup softhsm"; return $SKIP; }
+ expect_pass __skip
+ expect_pass __skip
+fi
new file mode 100755
@@ -0,0 +1,290 @@
+#!/usr/bin/env bash
+
+# This program originates from 'swtpm' project (https://github.com/stefanberger/swtpm/)
+# and is provided to ima-evm-utils under a dual license:
+# - BSD 3-clause
+# - GPL-2.0
+
+# This script may not work with softhsm2 2.0.0 but with >= 2.2.0
+
+if [ -z "$(type -P p11tool)" ]; then
+ echo "Need p11tool from gnutls"
+ exit 77
+fi
+
+if [ -z "$(type -P softhsm2-util)" ]; then
+ echo "Need softhsm2-util from softhsm2 package"
+ exit 77
+fi
+
+NAME=swtpm-test
+PIN=${PIN:-1234}
+SO_PIN=${SO_PIN:-1234}
+SOFTHSM_SETUP_CONFIGDIR=${SOFTHSM_SETUP_CONFIGDIR:-~/.config/softhsm2}
+export SOFTHSM2_CONF=${SOFTHSM_SETUP_CONFIGDIR}/softhsm2.conf
+
+UNAME_S="$(uname -s)"
+
+case "${UNAME_S}" in
+Darwin)
+ msg=$(sudo -v -n)
+ if [ $? -ne 0 ]; then
+ echo "Need password-less sudo rights on OS X to change /etc/gnutls/pkcs11.conf"
+ exit 1
+ fi
+ ;;
+esac
+
+teardown_softhsm() {
+ local configdir=${SOFTHSM_SETUP_CONFIGDIR}
+ local configfile=${SOFTHSM2_CONF}
+ local bakconfigfile=${configfile}.bak
+ local tokendir=${configdir}/tokens
+
+ softhsm2-util --token "${NAME}" --delete-token &>/dev/null
+
+ case "${UNAME_S}" in
+ Darwin*)
+ if [ -f /etc/gnutls/pkcs11.conf.bak ]; then
+ sudo rm -f /etc/gnutls/pkcs11.conf
+ sudo mv /etc/gnutls/pkcs11.conf.bak \
+ /etc/gnutls/pkcs11.conf &>/dev/null
+ fi
+ ;;
+ esac
+
+ if [ -f "$bakconfigfile" ]; then
+ mv "$bakconfigfile" "$configfile"
+ else
+ rm -f "$configfile"
+ fi
+ if [ -d "$tokendir" ]; then
+ rm -rf "${tokendir}"
+ fi
+ return 0
+}
+
+setup_softhsm() {
+ local msg tokenuri keyuri
+ local configdir=${SOFTHSM_SETUP_CONFIGDIR}
+ local configfile=${SOFTHSM2_CONF}
+ local bakconfigfile=${configfile}.bak
+ local tokendir=${configdir}/tokens
+ local rc
+
+ case "${UNAME_S}" in
+ Darwin*)
+ if [ -f /etc/gnutls/pkcs11.conf.bak ]; then
+ echo "/etc/gnutls/pkcs11.conf.bak already exists; need to 'teardown' first"
+ return 1
+ fi
+ sudo mv /etc/gnutls/pkcs11.conf \
+ /etc/gnutls/pkcs11.conf.bak &>/dev/null
+ if [ $(id -u) -eq 0 ]; then
+ SONAME="$(sudo -u nobody brew ls --verbose softhsm | \
+ grep -E "\.so$")"
+ else
+ SONAME="$(brew ls --verbose softhsm | \
+ grep -E "\.so$")"
+ fi
+ sudo mkdir -p /etc/gnutls &>/dev/null
+ sudo bash -c "echo "load=${SONAME}" > /etc/gnutls/pkcs11.conf"
+ ;;
+ esac
+
+ if ! [ -d $configdir ]; then
+ mkdir -p $configdir
+ fi
+ mkdir -p ${tokendir}
+
+ if [ -f $configfile ]; then
+ mv "$configfile" "$bakconfigfile"
+ fi
+
+ if ! [ -f $configfile ]; then
+ cat <<_EOF_ > $configfile
+directories.tokendir = ${tokendir}
+objectstore.backend = file
+log.level = DEBUG
+slots.removable = false
+_EOF_
+ fi
+
+ msg=$(p11tool --list-tokens 2>&1 | grep "token=${NAME}" | tail -n1)
+ if [ $? -ne 0 ]; then
+ echo "Could not list existing tokens"
+ echo "$msg"
+ fi
+ tokenuri=$(echo "$msg" | sed -n 's/.*URL: \([[:print:]*]\)/\1/p')
+
+ if [ -z "$tokenuri" ]; then
+ msg=$(softhsm2-util \
+ --init-token --pin ${PIN} --so-pin ${SO_PIN} \
+ --free --label ${NAME} 2>&1)
+ if [ $? -ne 0 ]; then
+ echo "Could not initialize token"
+ echo "$msg"
+ return 2
+ fi
+
+ slot=$(echo "$msg" | \
+ sed -n 's/.* reassigned to slot \([0-9]*\)$/\1/p')
+ if [ -z "$slot" ]; then
+ slot=$(softhsm2-util --show-slots | \
+ grep -E "^Slot " | head -n1 |
+ sed -n 's/Slot \([0-9]*\)/\1/p')
+ if [ -z "$slot" ]; then
+ echo "Could not parse slot number from output."
+ echo "$msg"
+ return 3
+ fi
+ fi
+
+ msg=$(p11tool --list-tokens 2>&1 | \
+ grep "token=${NAME}" | tail -n1)
+ if [ $? -ne 0 ]; then
+ echo "Could not list existing tokens"
+ echo "$msg"
+ fi
+ tokenuri=$(echo "$msg" | sed -n 's/.*URL: \([[:print:]*]\)/\1/p')
+ if [ -z "${tokenuri}" ]; then
+ echo "Could not get tokenuri!"
+ return 4
+ fi
+
+ # more recent versions of p11tool have --generate-privkey ...
+ msg=$(GNUTLS_PIN=$PIN p11tool \
+ --generate-privkey=rsa --bits 2048 --label mykey --login \
+ "${tokenuri}" 2>&1)
+ if [ $? -ne 0 ]; then
+ # ... older versions have --generate-rsa
+ msg=$(GNUTLS_PIN=$PIN p11tool \
+ --generate-rsa --bits 2048 --label mykey --login \
+ "${tokenuri}" 2>&1)
+ if [ $? -ne 0 ]; then
+ echo "Could not create RSA key!"
+ echo "$msg"
+ return 5
+ fi
+ fi
+ fi
+
+ getkeyuri_softhsm $slot
+ rc=$?
+ if [ $rc -ne 0 ]; then
+ teardown_softhsm
+ fi
+
+ return $rc
+}
+
+_getkeyuri_softhsm() {
+ local msg tokenuri keyuri
+
+ msg=$(p11tool --list-tokens 2>&1 | grep "token=${NAME}")
+ if [ $? -ne 0 ]; then
+ echo "Could not list existing tokens"
+ echo "$msg"
+ return 5
+ fi
+ tokenuri=$(echo "$msg" | sed -n 's/.*URL: \([[:print:]*]\)/\1/p')
+ if [ -z "$tokenuri" ]; then
+ echo "Could not get token URL"
+ echo "$msg"
+ return 6
+ fi
+ msg=$(p11tool --list-all ${tokenuri} 2>&1)
+ if [ $? -ne 0 ]; then
+ echo "Could not list object under token $tokenuri"
+ echo "$msg"
+ softhsm2-util --show-slots
+ return 7
+ fi
+
+ keyuri=$(echo "$msg" | sed -n 's/.*URL: \([[:print:]*]\)/\1/p')
+ if [ -z "$keyuri" ]; then
+ echo "Could not get key URL"
+ echo "$msg"
+ return 8
+ fi
+ echo "$keyuri"
+ return 0
+}
+
+getkeyuri_softhsm() {
+ local keyuri rc
+
+ keyuri=$(_getkeyuri_softhsm)
+ rc=$?
+ if [ $rc -ne 0 ]; then
+ return $rc
+ fi
+ echo "keyuri: $keyuri?pin-value=${PIN}" #&module-name=softhsm2"
+ return 0
+}
+
+getpubkey_softhsm() {
+ local keyuri rc
+
+ keyuri=$(_getkeyuri_softhsm)
+ rc=$?
+ if [ $rc -ne 0 ]; then
+ return $rc
+ fi
+ GNUTLS_PIN=${PIN} p11tool --export-pubkey "${keyuri}" --login 2>/dev/null
+ return $?
+}
+
+usage() {
+ cat <<_EOF_
+Usage: $0 [command]
+
+Supported commands are:
+
+setup : Setup the user's account for softhsm and create a
+ token and key with a test configuration
+
+getkeyuri : Get the key's URI; may only be called after setup
+
+getpubkey : Get the public key in PEM format; may only be called after setup
+
+teardown : Remove the temporary softhsm test configuration
+
+_EOF_
+}
+
+main() {
+ local ret
+
+ if [ $# -lt 1 ]; then
+ usage $0
+ echo -e "Missing command.\n\n"
+ return 1
+ fi
+ case "$1" in
+ setup)
+ setup_softhsm
+ ret=$?
+ ;;
+ getkeyuri)
+ getkeyuri_softhsm
+ ret=$?
+ ;;
+ getpubkey)
+ getpubkey_softhsm
+ ret=$?
+ ;;
+ teardown)
+ teardown_softhsm
+ ret=$?
+ ;;
+ *)
+ echo -e "Unsupported command: $1\n\n"
+ usage $0
+ ret=1
+ esac
+ return $ret
+}
+
+main "$@"
+exit $?