diff --git a/common/nvme b/common/nvme index 21647dc6..6ad43c66 100644 --- a/common/nvme +++ b/common/nvme @@ -275,6 +275,8 @@ _nvme_connect_subsys() { local no_wait=false local hdr_digest=false local data_digest=false + local tls=false + local concat=false local port local i local -a ARGS @@ -341,6 +343,14 @@ _nvme_connect_subsys() { data_digest=true shift 1 ;; + --tls) + tls=true + shift 1 + ;; + --concat) + concat=true + shift 1 + ;; *) echo "WARNING: unknown argument: $1" shift @@ -398,6 +408,12 @@ _nvme_connect_subsys() { if [[ ${data_digest} = true ]]; then ARGS+=(--data-digest) fi + if [[ ${tls} = true ]]; then + ARGS+=(--tls) + fi + if [[ ${concat} = true ]]; then + ARGS+=(--concat) + fi ARGS+=(-o json) connect=$(nvme connect "${ARGS[@]}" 2> /dev/null) @@ -470,6 +486,7 @@ _fc_host_traddr() { } _create_nvmet_port() { + local tls="${1:-none}" local trtype="${nvme_trtype}" local traddr="${def_traddr}" local adrfam="${def_adrfam}" @@ -506,7 +523,13 @@ _create_nvmet_port() { [[ "${adrfam}" != "loop" ]] ; then echo "${trsvcid}" > "${portcfs}/addr_trsvcid" fi - + if [[ "${trtype}" == "tcp" ]] && \ + [[ "${tls}" != "none" ]]; then + echo "tls1.3" > "${portcfs}/addr_tsas" + if [[ "${tls}" != "required" ]]; then + echo "not required" > "${portcfs}/addr_treq" + fi + fi echo "${port}" } @@ -871,6 +894,7 @@ _nvmet_target_setup() { local port p local resv_enable="" local num_ports=1 + local tls="none" local -a ARGS while [[ $# -gt 0 ]]; do @@ -903,6 +927,14 @@ _nvmet_target_setup() { num_ports="$2" shift 2 ;; + --tls) + tls="not-required" + shift 1 + ;; + --force-tls) + tls="required" + shift 1 + ;; *) echo "WARNING: unknown argument: $1" shift @@ -949,7 +981,7 @@ _nvmet_target_setup() { p=0 while (( p < num_ports )); do - port="$(_create_nvmet_port)" + port="$(_create_nvmet_port ${tls})" _add_nvmet_subsys_to_port "${port}" "${subsysnqn}" p=$(( p + 1 )) done diff --git a/common/rc b/common/rc index bc6c2e49..ce7f975d 100644 --- a/common/rc +++ b/common/rc @@ -500,6 +500,17 @@ _have_writeable_kmsg() { return 0 } +_have_systemctl_unit() { + local unit="$1" + + _have_program systemctl || return 1 + if ! grep -qe "$unit" < <(systemctl list-unit-files); then + SKIP_REASONS+=("systemctl unit '${unit}' is missing") + return 1 + fi + return 0 +} + # Run the given command as NORMAL_USER _run_user() { su "$NORMAL_USER" -c "$1" diff --git a/tests/nvme/060 b/tests/nvme/060 new file mode 100644 index 00000000..61385ddc --- /dev/null +++ b/tests/nvme/060 @@ -0,0 +1,94 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-3.0+ +# Copyright (C) 2024 Hannes Reinecke, SUSE Labs +# +# Create TLS-encrypted connections + +. tests/nvme/rc + +DESCRIPTION="Create TLS-encrypted connections" +QUICK=1 + +requires() { + _nvme_requires + _have_loop + _have_kernel_option NVME_TCP_TLS + _have_kernel_option NVME_TARGET_TCP_TLS + _require_kernel_nvme_fabrics_feature tls + _require_nvme_trtype tcp + _require_nvme_cli_tls + if ! _have_systemctl_unit tlshd; then + SKIP_REASONS+=("Install ktls-utils for tlshd") + fi +} + +set_conditions() { + _set_nvme_trtype "$@" +} + +test() { + echo "Running ${TEST_NAME}" + + _setup_nvmet + + local hostkey + local ctrl + + hostkey=$(nvme gen-tls-key -n "${def_hostnqn}" -c "${def_subsysnqn}" -m 1 -I 1 -i 2> /dev/null) + if [ -z "$hostkey" ] ; then + echo "nvme gen-tls-key failed" + return 1 + fi + + systemctl start tlshd + + _nvmet_target_setup --blkdev file --tls + + # Test unencrypted connection + echo "Test unencrypted connection w/ tls not required" + _nvme_connect_subsys + + ctrl=$(_find_nvme_dev "${def_subsysnqn}") + if _nvme_ctrl_tls_key "$ctrl" > /dev/null; then + echo "WARNING: connection is encrypted" + fi + + _nvme_disconnect_subsys + + # Test encrypted connection + echo "Test encrypted connection w/ tls not required" + _nvme_connect_subsys --tls + + ctrl=$(_find_nvme_dev "${def_subsysnqn}") + if ! _nvme_ctrl_tls_key "$ctrl" > /dev/null ; then + echo "WARNING: connection is not encrypted" + fi + + _nvme_disconnect_subsys + + # Reset target configuration + _nvmet_target_cleanup + + _nvmet_target_setup --blkdev file --force-tls + + # Test unencrypted connection + echo "Test unencrypted connection w/ tls required (should fail)" + _nvme_connect_subsys + + _nvme_disconnect_subsys + + # Test encrypted connection + echo "Test encrypted connection w/ tls required" + _nvme_connect_subsys --tls + + ctrl=$(_find_nvme_dev "${def_subsysnqn}") + if ! _nvme_ctrl_tls_key "$ctrl" > /dev/null; then + echo "WARNING: connection is not encrypted" + fi + + _nvme_disconnect_subsys + + _nvmet_target_cleanup + + echo "Test complete" +} diff --git a/tests/nvme/060.out b/tests/nvme/060.out new file mode 100644 index 00000000..b2975bb0 --- /dev/null +++ b/tests/nvme/060.out @@ -0,0 +1,10 @@ +Running nvme/060 +Test unencrypted connection w/ tls not required +disconnected 1 controller(s) +Test encrypted connection w/ tls not required +disconnected 1 controller(s) +Test unencrypted connection w/ tls required (should fail) +disconnected 0 controller(s) +Test encrypted connection w/ tls required +disconnected 1 controller(s) +Test complete diff --git a/tests/nvme/061 b/tests/nvme/061 new file mode 100755 index 00000000..031da464 --- /dev/null +++ b/tests/nvme/061 @@ -0,0 +1,104 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-3.0+ +# Copyright (C) 2022 Hannes Reinecke, SUSE Labs +# +# Create secure concatenation for TCP connections + +. tests/nvme/rc + +DESCRIPTION="Create authenticated TCP connections with secure concatenation" +QUICK=1 + +requires() { + _nvme_requires + _have_loop + _have_kernel_option NVME_AUTH + _have_kernel_option NVME_TCP_TLS + _have_kernel_option NVME_TARGET_AUTH + _have_kernel_option NVME_TARGET_TCP_TLS + _require_kernel_nvme_fabrics_feature dhchap_ctrl_secret + _require_kernel_nvme_fabrics_feature concat + _require_nvme_trtype tcp + _require_nvme_cli_auth + if ! _have_systemctl_unit tlshd; then + SKIP_REASONS+=("Install ktls-utils for tlshd") + fi +} + +set_conditions() { + _set_nvme_trtype "$@" +} + +test() { + echo "Running ${TEST_NAME}" + + _setup_nvmet + + local hostkey + + systemctl restart tlshd + + hostkey=$(nvme gen-dhchap-key -m 1 -n "${def_hostnqn}" 2> /dev/null) + if [ -z "$hostkey" ] ; then + echo "nvme gen-dhchap-key failed" + return 1 + fi + + _nvmet_target_setup --blkdev file --hostkey "${hostkey}" --tls + _set_nvmet_hash "${def_hostnqn}" "hmac(sha256)" + _set_nvmet_dhgroup "${def_hostnqn}" "ffdhe2048" + + echo "Test secure concatenation with SHA256" + _nvme_connect_subsys --dhchap-secret "${hostkey}" --concat + + ctrl=$(_find_nvme_dev "${def_subsysnqn}") + if [[ -z "$ctrl" ]]; then + echo "WARNING: connection failed" + exit 1 + fi + tlskey=$(_nvme_ctrl_tls_key "$ctrl" || true) + if [[ -z "$tlskey" ]]; then + echo "WARNING: connection is not encrypted" + exit 1 + fi + + # Reset controller to force re-negotiation + echo "Reset controller" + if ! nvme reset "/dev/${ctrl}" ; then + echo "WARNING: failed to reset controller" + fi + + new_tlskey=$(_nvme_ctrl_tls_key "$ctrl" || true) + if [[ -z "$new_tlskey" ]]; then + echo "WARNING: connection is not encrypted" + elif [[ "$new_tlskey" = "$tlskey" ]]; then + echo "WARNING: TLS key has not been renegotiated" + fi + + _nvme_disconnect_subsys + + hostkey=$(nvme gen-dhchap-key -m 2 -n "${def_hostnqn}" 2> /dev/null) + if [ -z "$hostkey" ] ; then + echo "nvme gen-dhchap-key failed" + return 1 + fi + + _set_nvmet_hostkey "${def_hostnqn}" "${hostkey}" + _set_nvmet_hash "${def_hostnqn}" "hmac(sha384)" + _set_nvmet_dhgroup "${def_hostnqn}" "ffdhe3072" + + echo "Test secure concatenation with SHA384" + _nvme_connect_subsys --dhchap-secret "${hostkey}" --concat + + ctrl=$(_find_nvme_dev "${def_subsysnqn}") + if _nvme_ctrl_tls_key "$ctrl" > /dev/null ; then + echo "WARNING: connection is not encrypted" + exit 1 + fi + + _nvme_disconnect_subsys + + _nvmet_target_cleanup + + echo "Test complete" +} diff --git a/tests/nvme/061.out b/tests/nvme/061.out new file mode 100644 index 00000000..78f9687c --- /dev/null +++ b/tests/nvme/061.out @@ -0,0 +1,7 @@ +Running nvme/060 +Test secure concatenation with SHA256 +Reset controller +disconnected 1 controller(s) +Test secure concatenation with SHA384 +disconnected 1 controller(s) +Test complete diff --git a/tests/nvme/rc b/tests/nvme/rc index de68b31f..c2ba2bf8 100644 --- a/tests/nvme/rc +++ b/tests/nvme/rc @@ -175,6 +175,14 @@ _require_nvme_cli_auth() { return 0 } +_require_nvme_cli_tls() { + if ! nvme gen-tls-key --subsysnqn nvmf-test-subsys > /dev/null 2>&1; then + SKIP_REASON+=("nvme gen-tls-key command missing") + return 1 + fi + return 0 +} + _require_kernel_nvme_fabrics_feature() { local feature="$1" @@ -597,3 +605,9 @@ _nvme_reset_ctrl() { _nvme_delete_ctrl() { echo 1 > /sys/class/nvme/"$1"/delete_controller } + +_nvme_ctrl_tls_key() { + local ctrl="$1" + + cat /sys/class/nvme/"$ctrl"/tls_key 2>/dev/null +}