xref: /spdk/test/nvmf/target/auth.sh (revision 8d3f8fb818735d717730489685debac3c814d0ac)
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