diff --git a/bin/tests/system/isctest/mark.py b/bin/tests/system/isctest/mark.py index 250f4ccd3c..f07a53882a 100644 --- a/bin/tests/system/isctest/mark.py +++ b/bin/tests/system/isctest/mark.py @@ -12,6 +12,7 @@ # information regarding copyright ownership. import os +import shutil import subprocess import pytest @@ -58,6 +59,16 @@ with_json_c = pytest.mark.skipif( ) +softhsm2_environment = pytest.mark.skipif( + not ( + os.getenv("SOFTHSM2_CONF") + and os.getenv("SOFTHSM2_MODULE") + and shutil.which("pkcs11-tool") + and shutil.which("softhsm2-util") + ), + reason="SOFTHSM2_CONF and SOFTHSM2_MODULE environmental variables must be set and pkcs11-tool and softhsm2-util tools present", +) + try: import flaky as flaky_pkg # type: ignore except ModuleNotFoundError: diff --git a/bin/tests/system/isctest/run.py b/bin/tests/system/isctest/run.py index dd9dcb5515..c3b37ac059 100644 --- a/bin/tests/system/isctest/run.py +++ b/bin/tests/system/isctest/run.py @@ -28,6 +28,7 @@ def cmd( log_stderr=True, input_text: Optional[bytes] = None, raise_on_exception=True, + env: Optional[dict] = None, ): """Execute a command with given args as subprocess.""" isctest.log.debug(f"command: {' '.join(args)}") @@ -43,6 +44,9 @@ def cmd( f"~~~ cmd stderr ~~~\n{procdata.stderr.decode('utf-8')}\n~~~~~~~~~~~~~~~~~~" ) + if env is None: + env = dict(os.environ) + try: proc = subprocess.run( args, @@ -52,6 +56,7 @@ def cmd( check=True, cwd=cwd, timeout=timeout, + env=env, ) print_debug_logs(proc) return proc diff --git a/bin/tests/system/keyfromlabel/prereq.sh b/bin/tests/system/keyfromlabel/prereq.sh deleted file mode 100644 index be1850a1fa..0000000000 --- a/bin/tests/system/keyfromlabel/prereq.sh +++ /dev/null @@ -1,31 +0,0 @@ -#!/bin/sh -e -# -# Copyright (C) Internet Systems Consortium, Inc. ("ISC") -# -# SPDX-License-Identifier: MPL-2.0 -# -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, you can obtain one at https://mozilla.org/MPL/2.0/. -# -# See the COPYRIGHT file distributed with this work for additional -# information regarding copyright ownership. - -. ../conf.sh - -[ -n "${SOFTHSM2_CONF}" ] || { - echo_i "skip: softhsm2 configuration not available" - exit 255 -} - -[ -f "$SOFTHSM2_MODULE" ] || { - echo_i "skip: softhsm2 module not available" - exit 1 -} - -for _bin in softhsm2-util pkcs11-tool; do - command -v "$_bin" >/dev/null || { - echo_i "skip: $_bin not available" - exit 1 - } -done diff --git a/bin/tests/system/keyfromlabel/setup.sh b/bin/tests/system/keyfromlabel/setup.sh deleted file mode 100644 index e302c60c68..0000000000 --- a/bin/tests/system/keyfromlabel/setup.sh +++ /dev/null @@ -1,23 +0,0 @@ -#!/bin/sh -# -# Copyright (C) Internet Systems Consortium, Inc. ("ISC") -# -# SPDX-License-Identifier: MPL-2.0 -# -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, you can obtain one at https://mozilla.org/MPL/2.0/. -# -# See the COPYRIGHT file distributed with this work for additional -# information regarding copyright ownership. - -# shellcheck source=conf.sh -. ../conf.sh - -set -e - -OPENSSL_CONF= softhsm2-util --delete-token --token "softhsm2-keyfromlabel" >/dev/null 2>&1 || true -OPENSSL_CONF= softhsm2-util --init-token --free --pin 1234 --so-pin 1234 --label "softhsm2-keyfromlabel" | awk '/^The token has been initialized and is reassigned to slot/ { print $NF }' - -printf '%s' "${HSMPIN:-1234}" >pin -PWD=$(pwd) diff --git a/bin/tests/system/keyfromlabel/tests.sh b/bin/tests/system/keyfromlabel/tests.sh deleted file mode 100644 index c3e38d8ae5..0000000000 --- a/bin/tests/system/keyfromlabel/tests.sh +++ /dev/null @@ -1,94 +0,0 @@ -#!/bin/sh -# -# Copyright (C) Internet Systems Consortium, Inc. ("ISC") -# -# SPDX-License-Identifier: MPL-2.0 -# -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, you can obtain one at https://mozilla.org/MPL/2.0/. -# -# See the COPYRIGHT file distributed with this work for additional -# information regarding copyright ownership. - -set -e - -# shellcheck source=conf.sh -. ../conf.sh - -PWD=$(pwd) - -keygen() { - type="$1" - bits="$2" - zone="$3" - id="$4" - - label="${id}-${zone}" - p11id=$(echo "${label}" | openssl sha1 -r | awk '{print $1}') - OPENSSL_CONF= pkcs11-tool --module $SOFTHSM2_MODULE --token-label "softhsm2-keyfromlabel" -l -k --key-type $type:$bits --label "${label}" --id "${p11id}" --pin $(cat $PWD/pin) >pkcs11-tool.out.$zone.$id || return 1 -} - -keyfromlabel() { - alg="$1" - zone="$2" - id="$3" - shift 3 - - $KEYFRLAB -a $alg -l "pkcs11:token=softhsm2-keyfromlabel;object=${id}-${zone};pin-source=$PWD/pin" "$@" $zone >>keyfromlabel.out.$zone.$id || return 1 - cat keyfromlabel.out.$zone.$id -} - -status=0 -infile="template.db.in" -for algtypebits in rsasha256:rsa:2048 rsasha512:rsa:2048 \ - ecdsap256sha256:EC:prime256v1 ecdsap384sha384:EC:prime384v1; do # Edwards curves are not yet supported by OpenSC - # ed25519:EC:edwards25519 ed448:EC:edwards448 - alg=$(echo "$algtypebits" | cut -f 1 -d :) - type=$(echo "$algtypebits" | cut -f 2 -d :) - bits=$(echo "$algtypebits" | cut -f 3 -d :) - alg_upper=$(echo "$alg" | tr '[:lower:]' '[:upper:]') - supported=$(eval "echo \$${alg_upper}_SUPPORTED") - - if [ "${supported}" = 1 ]; then - zone="$alg.example" - zonefile="zone.$alg.example.db" - ret=0 - - echo_i "Generate keys $alg $type:$bits for zone $zone" - keygen $type $bits $zone keyfromlabel-zsk || ret=1 - keygen $type $bits $zone keyfromlabel-ksk || ret=1 - test "$ret" -eq 0 || echo_i "failed" - status=$((status + ret)) - - # Skip dnssec-keyfromlabel if key generation failed. - test $ret -eq 0 || continue - - echo_i "Get ZSK $alg $zone $type:$bits" - ret=0 - zsk=$(keyfromlabel $alg $zone keyfromlabel-zsk) - test -z "$zsk" && ret=1 - test "$ret" -eq 0 || echo_i "failed (zsk=$zsk)" - status=$((status + ret)) - - echo_i "Get KSK $alg $zone $type:$bits" - ret=0 - ksk=$(keyfromlabel $alg $zone keyfromlabel-ksk -f KSK) - test -z "$ksk" && ret=1 - test "$ret" -eq 0 || echo_i "failed (ksk=$ksk)" - status=$((status + ret)) - - # Skip signing if dnssec-keyfromlabel failed. - test $ret -eq 0 || continue - - echo_i "Sign zone with $ksk $zsk" - ret=0 - cat "$infile" "$ksk.key" "$zsk.key" >"$zonefile" - $SIGNER -S -a -g -o "$zone" "$zonefile" >signer.out.$zone || ret=1 - test "$ret" -eq 0 || echo_i "failed" - status=$((status + ret)) - fi -done - -echo_i "exit status: $status" -[ $status -eq 0 ] || exit 1 diff --git a/bin/tests/system/keyfromlabel/tests_keyfromlabel.py b/bin/tests/system/keyfromlabel/tests_keyfromlabel.py new file mode 100644 index 0000000000..37e6888b52 --- /dev/null +++ b/bin/tests/system/keyfromlabel/tests_keyfromlabel.py @@ -0,0 +1,188 @@ +# Copyright (C) Internet Systems Consortium, Inc. ("ISC") +# +# SPDX-License-Identifier: MPL-2.0 +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, you can obtain one at https://mozilla.org/MPL/2.0/. +# +# See the COPYRIGHT file distributed with this work for additional +# information regarding copyright ownership. + +import hashlib +import os +import re +import shutil + +import pytest + +import isctest.mark + + +pytestmark = [ + isctest.mark.softhsm2_environment, + pytest.mark.extra_artifacts( + [ + "*.example.db", + "*.example.db.signed", + "K*", + "dsset-*", + "keyfromlabel.out.*", + "pin", + "pkcs11-tool.out.*", + "signer.out.*", + ], + ), +] + + +EMPTY_OPENSSL_CONF_ENV = {**os.environ, "OPENSSL_CONF": ""} + +HSMPIN = "1234" + + +@pytest.fixture(autouse=True) +def token_init_and_cleanup(): + + # Create pin file for the $KEYFRLAB command + with open("pin", "w", encoding="utf-8") as pinfile: + pinfile.write(HSMPIN) + + token_init_command = [ + "softhsm2-util", + "--init-token", + "--free", + "--pin", + HSMPIN, + "--so-pin", + HSMPIN, + "--label", + "softhsm2-keyfromlabel", + ] + + token_cleanup_command = [ + "softhsm2-util", + "--delete-token", + "--token", + "softhsm2-keyfromlabel", + ] + + isctest.run.cmd( + token_cleanup_command, + env=EMPTY_OPENSSL_CONF_ENV, + log_stderr=False, + raise_on_exception=False, + ) + + try: + output = isctest.run.cmd( + token_init_command, env=EMPTY_OPENSSL_CONF_ENV, log_stdout=True + ).stdout.decode("utf-8") + assert "The token has been initialized and is reassigned to slot" in output + yield + finally: + output = isctest.run.cmd( + token_cleanup_command, env=EMPTY_OPENSSL_CONF_ENV, log_stdout=True + ).stdout.decode("utf-8") + assert re.search("Found token (.*) with matching token label", output) + assert re.search("The token (.*) has been deleted", output) + + +# pylint: disable-msg=too-many-locals +@pytest.mark.parametrize( + "alg_name,alg_type,alg_bits", + [ + ("rsasha256", "rsa", "2048"), + ("rsasha512", "rsa", "2048"), + ("ecdsap256sha256", "EC", "prime256v1"), + ("ecdsap384sha384", "EC", "prime384v1"), + # Edwards curves are not yet supported by OpenSC + # ("ed25519","EC","edwards25519"), + # ("ed448","EC","edwards448") + ], +) +def test_keyfromlabel(alg_name, alg_type, alg_bits): + + def keygen(alg_type, alg_bits, zone, key_id): + label = f"{key_id}-{zone}" + p11_id = hashlib.sha1(label.encode("utf-8")).hexdigest() + + pkcs11_command = [ + "pkcs11-tool", + "--module", + os.environ.get("SOFTHSM2_MODULE"), + "--token-label", + "softhsm2-keyfromlabel", + "-l", + "-k", + "--key-type", + f"{alg_type}:{alg_bits}", + "--label", + label, + "--id", + p11_id, + "--pin", + HSMPIN, + ] + + output = isctest.run.cmd( + pkcs11_command, env=EMPTY_OPENSSL_CONF_ENV, log_stdout=True + ).stdout.decode("utf-8") + + assert "Key pair generated" in output + + def keyfromlabel(alg_name, zone, key_id, key_flag): + key_flag = key_flag.split() if key_flag else [] + + keyfrlab_command = [ + os.environ["KEYFRLAB"], + "-a", + alg_name, + "-l", + f"pkcs11:token=softhsm2-keyfromlabel;object={key_id}-{zone};pin-source=pin", + *key_flag, + zone, + ] + + output = isctest.run.cmd(keyfrlab_command, log_stdout=True) + output_decoded = output.stdout.decode("utf-8").rstrip() + ".key" + + assert os.path.exists(output_decoded) + + return output_decoded + + if f"{alg_name.upper()}_SUPPORTED" not in os.environ: + pytest.skip(f"{alg_name} is not supported") + + # Generate keys for the $zone zone + zone = f"{alg_name}.example" + + keygen(alg_type, alg_bits, zone, "keyfromlabel-zsk") + keygen(alg_type, alg_bits, zone, "keyfromlabel-ksk") + + # Get ZSK + zsk_file = keyfromlabel(alg_name, zone, "keyfromlabel-zsk", "") + + # Get KSK + ksk_file = keyfromlabel(alg_name, zone, "keyfromlabel-ksk", "-f KSK") + + # Sign zone with KSK and ZSK + zone_file = f"zone.{alg_name}.example.db" + + with open(zone_file, "w", encoding="utf-8") as outfile: + for f in ["template.db.in", ksk_file, zsk_file]: + with open(f, "r", encoding="utf-8") as fd: + shutil.copyfileobj(fd, outfile) + + signer_command = [ + os.environ["SIGNER"], + "-S", + "-a", + "-g", + "-o", + zone, + zone_file, + ] + isctest.run.cmd(signer_command, log_stdout=True) + + assert os.path.exists(f"{zone_file}.signed") diff --git a/bin/tests/system/keyfromlabel/tests_sh_keyfromlabel.py b/bin/tests/system/keyfromlabel/tests_sh_keyfromlabel.py deleted file mode 100644 index 93e7154fa5..0000000000 --- a/bin/tests/system/keyfromlabel/tests_sh_keyfromlabel.py +++ /dev/null @@ -1,29 +0,0 @@ -# Copyright (C) Internet Systems Consortium, Inc. ("ISC") -# -# SPDX-License-Identifier: MPL-2.0 -# -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, you can obtain one at https://mozilla.org/MPL/2.0/. -# -# See the COPYRIGHT file distributed with this work for additional -# information regarding copyright ownership. - -import pytest - -pytestmark = pytest.mark.extra_artifacts( - [ - "*.example.db", - "*.example.db.signed", - "K*", - "dsset-*", - "keyfromlabel.out.*", - "pin", - "pkcs11-tool.out.*", - "signer.out.*", - ] -) - - -def test_keyfromlabel(run_tests_sh): - run_tests_sh() diff --git a/bin/tests/system/vulture_ignore_list.py b/bin/tests/system/vulture_ignore_list.py index 7682a478e6..2080fe1d3d 100644 --- a/bin/tests/system/vulture_ignore_list.py +++ b/bin/tests/system/vulture_ignore_list.py @@ -11,3 +11,4 @@ transfers_complete # unused function (cipher-suites/tests_cipher_suites.py:31) transfers_complete # unused variable (cipher-suites/tests_cipher_suites.py:86) +token_init_and_cleanup # unused function (keyfromlabel/tests_keyfromlabel.py:43)