2
0
mirror of https://gitlab.isc.org/isc-projects/bind9 synced 2025-08-29 05:28:00 +00:00

Rewrite keyfromlabel system test to pytest

(cherry picked from commit 409f394d6eb5352f1f7ca38af43b166bc4a1a3bd)
This commit is contained in:
Michal Nowak 2024-07-23 16:17:40 +02:00
parent 8713e2f61c
commit 5d615b4797
8 changed files with 207 additions and 177 deletions

View File

@ -13,6 +13,7 @@
import os
from pathlib import Path
import shutil
import subprocess
import pytest
@ -76,6 +77,16 @@ dnsrps_enabled = 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:

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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 $ENGINE_ARG -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 $ENGINE_ARG -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

View File

@ -0,0 +1,190 @@
# 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"],
*os.environ.get("ENGINE_ARG", "").split(),
"-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"],
*os.environ.get("ENGINE_ARG", "").split(),
"-S",
"-a",
"-g",
"-o",
zone,
zone_file,
]
isctest.run.cmd(signer_command, log_stdout=True)
assert os.path.exists(f"{zone_file}.signed")

View File

@ -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()

View File

@ -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)