1#!/usr/bin/env bash 2# SPDX-License-Identifier: BSD-3-Clause 3# Copyright (c) 2024 Intel Corporation 4# 5 6testdir=$(readlink -f "$(dirname "$0")") 7rootdir=$(readlink -f "$testdir/../../../") 8 9source "$rootdir/test/common/autotest_common.sh" 10source "$rootdir/test/nvmf/common.sh" 11 12# shellcheck disable=SC2190 13digests=("sha256" "sha384" "sha512") 14dhgroups=("null" "ffdhe2048" "ffdhe3072" "ffdhe4096" "ffdhe6144" "ffdhe8192") 15subnqn="nqn.2024-03.io.spdk:cnode0" 16hostnqn="$NVME_HOSTNQN" 17hostsock="/var/tmp/host.sock" 18keys=() ckeys=() 19 20cleanup() { 21 killprocess $hostpid || : 22 nvmftestfini || : 23 rm -f "${keys[@]}" "${ckeys[@]}" "$output_dir"/nvm{e,f}-auth.log 24} 25 26dumplogs() { 27 cat "$output_dir/nvme-auth.log" 28 cat "$output_dir/nvmf-auth.log" 29} 30 31hostrpc() { "$rootdir/scripts/rpc.py" -s "$hostsock" "$@"; } 32 33nvme_connect() { 34 # Force 1 I/O queue to speed up the connection and keep ctrlr loss timeout at 0 to ensure 35 # immediate disconnect after unsuccessful reauthentication 36 nvme connect -t "$TEST_TRANSPORT" -a "$NVMF_FIRST_TARGET_IP" -n "$subnqn" -i 1 \ 37 -q "$hostnqn" --hostid "$NVME_HOSTID" -l 0 "$@" 38} 39 40nvme_get_ctrlr() { 41 local dev 42 43 for dev in /sys/devices/virtual/nvme-fabrics/ctl/nvme*; do 44 [[ "$subnqn" == "$(< "$dev/subsysnqn")" ]] && echo "${dev##*/}" && break 45 done || false 46} 47 48nvme_set_keys() { 49 local ctl key ckey dev timeout 50 51 ctl="$1" key="$2" ckey="$3" timeout="$4" 52 dev="/sys/devices/virtual/nvme-fabrics/ctl/$ctl" 53 54 [[ -z "$key" ]] || echo "$key" > "$dev/dhchap_secret" 55 [[ -z "$ckey" ]] || echo "$ckey" > "$dev/dhchap_ctrl_secret" 56 [[ -z "$timeout" ]] || sleep "$timeout" 57} 58 59bdev_connect() { 60 hostrpc bdev_nvme_attach_controller -t "$TEST_TRANSPORT" -f ipv4 \ 61 -a "$NVMF_FIRST_TARGET_IP" -s "$NVMF_PORT" -q "$hostnqn" -n "$subnqn" "$@" 62} 63 64connect_authenticate() { 65 local digest dhgroup key ckey qpairs 66 67 digest="$1" dhgroup="$2" key="key$3" 68 ckey=(${ckeys[$3]:+--dhchap-ctrlr-key "ckey$3"}) 69 70 rpc_cmd nvmf_subsystem_add_host "$subnqn" "$hostnqn" --dhchap-key "$key" "${ckey[@]}" 71 bdev_connect -b "nvme0" --dhchap-key "$key" "${ckey[@]}" 72 73 [[ $(hostrpc bdev_nvme_get_controllers | jq -r '.[].name') == "nvme0" ]] 74 qpairs=$(rpc_cmd nvmf_subsystem_get_qpairs "$subnqn") 75 [[ $(jq -r ".[0].auth.digest" <<< "$qpairs") == "$digest" ]] 76 [[ $(jq -r ".[0].auth.dhgroup" <<< "$qpairs") == "$dhgroup" ]] 77 [[ $(jq -r ".[0].auth.state" <<< "$qpairs") == "completed" ]] 78 hostrpc bdev_nvme_detach_controller nvme0 79 80 nvme_connect --dhchap-secret "$(< "${keys[$3]}")" \ 81 ${ckeys[$3]:+--dhchap-ctrl-secret "$(< "${ckeys[$3]}")"} 82 nvme disconnect -n "$subnqn" 83 rpc_cmd nvmf_subsystem_remove_host "$subnqn" "$hostnqn" 84} 85 86nvmftestinit 87nvmfappstart -L nvmf_auth &> "$output_dir/nvmf-auth.log" 88"$rootdir/build/bin/spdk_tgt" -m 2 -r "$hostsock" -L nvme_auth &> "$output_dir/nvme-auth.log" & 89hostpid=$! 90 91trap "dumplogs; cleanup" SIGINT SIGTERM EXIT 92 93# Set host/ctrlr key pairs with one combination w/o bidirectional authentication 94keys[0]=$(gen_dhchap_key "null" 48) ckeys[0]=$(gen_dhchap_key "sha512" 64) 95keys[1]=$(gen_dhchap_key "sha256" 32) ckeys[1]=$(gen_dhchap_key "sha384" 48) 96keys[2]=$(gen_dhchap_key "sha384" 48) ckeys[2]=$(gen_dhchap_key "sha256" 32) 97keys[3]=$(gen_dhchap_key "sha512" 64) ckeys[3]="" 98 99waitforlisten "$nvmfpid" 100waitforlisten "$hostpid" "$hostsock" 101rpc_cmd <<- CONFIG 102 nvmf_create_transport -t "$TEST_TRANSPORT" 103 nvmf_create_subsystem "$subnqn" 104 nvmf_subsystem_add_listener -t "$TEST_TRANSPORT" -a "$NVMF_FIRST_TARGET_IP" \ 105 -s "$NVMF_PORT" "$subnqn" 106CONFIG 107 108for i in "${!keys[@]}"; do 109 rpc_cmd keyring_file_add_key "key$i" "${keys[i]}" 110 hostrpc keyring_file_add_key "key$i" "${keys[i]}" 111 if [[ -n "${ckeys[i]}" ]]; then 112 rpc_cmd keyring_file_add_key "ckey$i" "${ckeys[i]}" 113 hostrpc keyring_file_add_key "ckey$i" "${ckeys[i]}" 114 fi 115done 116 117# Check all digest/dhgroup/key combinations 118for digest in "${digests[@]}"; do 119 for dhgroup in "${dhgroups[@]}"; do 120 for keyid in "${!keys[@]}"; do 121 hostrpc bdev_nvme_set_options --dhchap-digests "$digest" \ 122 --dhchap-dhgroups "$dhgroup" 123 connect_authenticate "$digest" "$dhgroup" $keyid 124 done 125 done 126done 127 128# Connect with all digests/dhgroups enabled 129hostrpc bdev_nvme_set_options \ 130 --dhchap-digests \ 131 "$( 132 IFS=, 133 printf "%s" "${digests[*]}" 134 )" \ 135 --dhchap-dhgroups \ 136 "$( 137 IFS=, 138 printf "%s" "${dhgroups[*]}" 139 )" 140# The target should select the strongest digest/dhgroup 141connect_authenticate "${digests[-1]}" "${dhgroups[-1]}" 0 142 143# Check that mismatched keys result in failed attach 144rpc_cmd nvmf_subsystem_add_host "$subnqn" "$hostnqn" --dhchap-key "key1" 145NOT bdev_connect -b "nvme0" --dhchap-key "key2" 146rpc_cmd nvmf_subsystem_remove_host "$subnqn" "$hostnqn" 147 148# Check that mismatched controller keys result in failed attach 149rpc_cmd nvmf_subsystem_add_host "$subnqn" "$hostnqn" --dhchap-key "key1" --dhchap-ctrlr-key "ckey1" 150NOT bdev_connect -b "nvme0" --dhchap-key "key1" --dhchap-ctrlr-key "ckey2" 151rpc_cmd nvmf_subsystem_remove_host "$subnqn" "$hostnqn" 152 153# Check that a missing controller key results in a failed attach 154rpc_cmd nvmf_subsystem_add_host "$subnqn" "$hostnqn" --dhchap-key "key1" 155NOT bdev_connect -b "nvme0" --dhchap-key "key1" --dhchap-ctrlr-key "ckey1" 156rpc_cmd nvmf_subsystem_remove_host "$subnqn" "$hostnqn" 157 158# Limit allowed digests/dhgroups on the target 159killprocess "$nvmfpid" 160nvmfappstart --wait-for-rpc -L nvmf_auth &>> "$output_dir/nvmf-auth.log" 161trap "dumplogs; cleanup" SIGINT SIGTERM EXIT 162 163waitforlisten "$nvmfpid" 164rpc_cmd <<- CONFIG 165 nvmf_set_config --dhchap-digests sha384,sha512 --dhchap-dhgroups ffdhe6144,ffdhe8192 166 framework_start_init 167 bdev_null_create null0 100 4096 168 nvmf_create_transport -t "$TEST_TRANSPORT" 169 nvmf_create_subsystem "$subnqn" 170 nvmf_subsystem_add_listener -t "$TEST_TRANSPORT" -a "$NVMF_FIRST_TARGET_IP" \ 171 -s "$NVMF_PORT" "$subnqn" 172 nvmf_subsystem_add_ns "$subnqn" "null0" -n 1 173CONFIG 174for i in "${!keys[@]}"; do 175 rpc_cmd keyring_file_add_key "key$i" "${keys[i]}" 176 [[ -n "${ckeys[i]}" ]] && rpc_cmd keyring_file_add_key "ckey$i" "${ckeys[i]}" 177done 178 179connect_authenticate "sha512" "ffdhe8192" 3 180 181# Check that authentication fails when no common digests are allowed 182rpc_cmd nvmf_subsystem_add_host "$subnqn" "$hostnqn" --dhchap-key key3 183hostrpc bdev_nvme_set_options --dhchap-digests "sha256" 184NOT bdev_connect -b "nvme0" --dhchap-key "key3" 185 186# Check that authentication fails when no common dhgroups are allowed 187hostrpc bdev_nvme_set_options --dhchap-dhgroups "ffdhe2048" \ 188 --dhchap-digests \ 189 "$( 190 IFS=, 191 printf "%s" "${digests[*]}" 192 )" 193NOT bdev_connect -b "nvme0" --dhchap-key "key3" 194 195# Check that the authentication fails when the host wants to authenticate the target (i.e. user set 196# the dhchap_ctrlr_key), but the target doesn't require authentication 197hostrpc bdev_nvme_set_options \ 198 --dhchap-digests \ 199 "$( 200 IFS=, 201 printf "%s" "${digests[*]}" 202 )" \ 203 --dhchap-dhgroups \ 204 "$( 205 IFS=, 206 printf "%s" "${dhgroups[*]}" 207 )" 208rpc_cmd nvmf_subsystem_remove_host "$subnqn" "$hostnqn" 209rpc_cmd nvmf_subsystem_add_host "$subnqn" "$hostnqn" 210NOT bdev_connect -b "nvme0" --dhchap-key "key0" --dhchap-ctrlr-key "key1" 211 212# But it's fine when the host key is set and the controller key is not 213bdev_connect -b "nvme0" --dhchap-key "key0" 214[[ $(hostrpc bdev_nvme_get_controllers | jq -r '.[].name') == "nvme0" ]] 215hostrpc bdev_nvme_detach_controller nvme0 216 217# Check changing the keys 218rpc_cmd nvmf_subsystem_set_keys "$subnqn" "$hostnqn" --dhchap-key "key1" 219bdev_connect -b "nvme0" --dhchap-key "key1" 220[[ $(hostrpc bdev_nvme_get_controllers | jq -r '.[].name') == "nvme0" ]] 221# Change the keys again - this shouldn't affect existing connections 222rpc_cmd nvmf_subsystem_set_keys "$subnqn" "$hostnqn" --dhchap-key "key2" --dhchap-ctrlr-key "key3" 223[[ $(hostrpc bdev_nvme_get_controllers | jq -r '.[].name') == "nvme0" ]] 224# But new connections require new keys 225nvme_connect --dhchap-secret "$(< ${keys[2]})" --dhchap-ctrl-secret "$(< ${keys[3]})" 226nctrlr=$(nvme_get_ctrlr) 227hostrpc bdev_nvme_detach_controller nvme0 228NOT bdev_connect -b "nvme0" --dhchap-key "key1" 229bdev_connect -b "nvme0" --dhchap-key "key2" --dhchap-ctrlr-key "key3" 230[[ $(hostrpc bdev_nvme_get_controllers | jq -r '.[].name') == "nvme0" ]] 231hostrpc bdev_nvme_detach_controller nvme0 232# Clear the keys and check that the host is no longer required to authenticate 233rpc_cmd nvmf_subsystem_set_keys "$subnqn" "$hostnqn" 234bdev_connect -b "nvme0" 235[[ $(hostrpc bdev_nvme_get_controllers | jq -r '.[].name') == "nvme0" ]] 236hostrpc bdev_nvme_detach_controller nvme0 237# Change the keys on the target once again, but this time force reauthentication on the already 238# established connections 239rpc_cmd nvmf_subsystem_set_keys "$subnqn" "$hostnqn" --dhchap-key "key1" --dhchap-ctrlr-key "key3" 240nvme_set_keys "$nctrlr" "$(< ${keys[1]})" "" 2s 241waitforblk "${nctrlr}n1" 242# Change the ctrlr key 243rpc_cmd nvmf_subsystem_set_keys "$subnqn" "$hostnqn" --dhchap-key "key1" --dhchap-ctrlr-key "key2" 244nvme_set_keys "$nctrlr" "" "$(< ${keys[2]})" 2s 245waitforblk "${nctrlr}n1" 246nvme disconnect -n "$subnqn" 247 248# Reauthenticate using bdev_nvme 249rpc_cmd nvmf_subsystem_set_keys "$subnqn" "$hostnqn" --dhchap-key "key0" --dhchap-ctrlr-key "key1" 250bdev_connect -b "nvme0" --dhchap-key "key0" --dhchap-ctrlr-key "key1" --ctrlr-loss-timeout-sec 1 \ 251 --reconnect-delay-sec 1 252rpc_cmd nvmf_subsystem_set_keys "$subnqn" "$hostnqn" --dhchap-key "key2" --dhchap-ctrlr-key "key3" 253hostrpc bdev_nvme_set_keys "nvme0" --dhchap-key "key2" --dhchap-ctrlr-key "key3" 254[[ $(hostrpc bdev_nvme_get_controllers | jq -r '.[].name') == "nvme0" ]] 255# Clear the keys while connected 256rpc_cmd nvmf_subsystem_set_keys "$subnqn" "$hostnqn" 257hostrpc bdev_nvme_set_keys "nvme0" 258[[ $(hostrpc bdev_nvme_get_controllers | jq -r '.[].name') == "nvme0" ]] 259# Use wrong keys and verify that the ctrlr will get disconnected after ctrlr-loss-timeout-sec 260rpc_cmd nvmf_subsystem_set_keys "$subnqn" "$hostnqn" --dhchap-key "key2" --dhchap-ctrlr-key "key3" 261NOT hostrpc bdev_nvme_set_keys "nvme0" --dhchap-key "key1" --dhchap-ctrlr-key "key3" 262while (($(hostrpc bdev_nvme_get_controllers | jq 'length') != 0)); do 263 sleep 1s 264done 265 266# Do the same, but this time try with a valid host key, but bad ctrlr key 267rpc_cmd nvmf_subsystem_set_keys "$subnqn" "$hostnqn" --dhchap-key "key0" --dhchap-ctrlr-key "key1" 268bdev_connect -b "nvme0" --dhchap-key "key0" --dhchap-ctrlr-key "key1" --ctrlr-loss-timeout-sec 1 \ 269 --reconnect-delay-sec 1 270rpc_cmd nvmf_subsystem_set_keys "$subnqn" "$hostnqn" --dhchap-key "key2" --dhchap-ctrlr-key "key3" 271NOT hostrpc bdev_nvme_set_keys "nvme0" --dhchap-key "key2" --dhchap-ctrlr-key "key0" 272while (($(hostrpc bdev_nvme_get_controllers | jq 'length') != 0)); do 273 sleep 1s 274done 275 276trap - SIGINT SIGTERM EXIT 277cleanup 278