xref: /spdk/test/sma/crypto.sh (revision c680e3a05b1a903c18bf3f75b732765607126f45)
1#!/usr/bin/env bash
2#  SPDX-License-Identifier: BSD-3-Clause
3#  Copyright (C) 2022 Intel Corporation
4#  All rights reserved.
5#
6
7testdir=$(readlink -f "$(dirname "$0")")
8rootdir=$(readlink -f "$testdir/../..")
9
10source "$rootdir/test/common/autotest_common.sh"
11source "$testdir/common.sh"
12
13rpc_py="$rootdir/scripts/rpc.py"
14localnqn=nqn.2016-06.io.spdk:cnode0
15tgtnqn=nqn.2016-06.io.spdk:tgt0
16key0=1234567890abcdef1234567890abcdef
17key1=deadbeefcafebabefeedbeefbabecafe
18tgtsock=/var/tmp/spdk.sock2
19discovery_port=8009
20
21cleanup() {
22	killprocess $smapid
23	killprocess $hostpid
24	killprocess $tgtpid
25}
26
27gen_volume_params() {
28	local volume_id=$1 cipher=$2 key=$3 key2=$4 config
29	local -a params crypto
30
31	config=$(
32		cat <<- PARAMS
33			"volume_id": "$(uuid2base64 $volume_id)",
34			"nvmf": {
35			  "hostnqn": "nqn.2016-06.io.spdk:host0",
36			  "discovery": {
37			    "discovery_endpoints": [
38			      {
39			        "trtype": "tcp",
40			        "traddr": "127.0.0.1",
41			        "trsvcid": "$discovery_port"
42			      }
43			    ]
44			  }
45			}
46		PARAMS
47	)
48	params+=("$config")
49
50	local IFS=","
51	if [[ -n "$cipher" ]]; then
52		crypto+=("\"cipher\": $(get_cipher $cipher)")
53		crypto+=("\"key\": \"$(format_key $key)\"")
54		if [[ -n "$key2" ]]; then
55			crypto+=("\"key2\": \"$(format_key $key2)\"")
56		fi
57
58		crypto_config=$(
59			cat <<- PARAMS
60				"crypto": {
61				  ${crypto[*]}
62				}
63			PARAMS
64		)
65
66		params+=("$crypto_config")
67	fi
68
69	cat <<- PARAMS
70		"volume": {
71		  ${params[*]}
72		}
73	PARAMS
74}
75
76create_device() {
77	"$rootdir/scripts/sma-client.py" <<- CREATE
78		{
79		  "method": "CreateDevice",
80		  "params": {
81		    "nvmf_tcp": {
82		      "subnqn": "$localnqn",
83		      "adrfam": "ipv4",
84		      "traddr": "127.0.0.1",
85		      "trsvcid": "4420"
86		    }
87		    ${1:+, $(gen_volume_params "$@")}
88		  }
89		}
90	CREATE
91}
92
93delete_device() {
94	"$rootdir/scripts/sma-client.py" <<- DELETE
95		{
96		  "method": "DeleteDevice",
97		  "params": {
98		    "handle": "$1"
99		  }
100		}
101	DELETE
102}
103
104attach_volume() {
105	local device=$1
106	shift
107
108	"$rootdir/scripts/sma-client.py" <<- ATTACH
109		{
110		  "method": "AttachVolume",
111		  "params": {
112		    "device_handle": "$device",
113		    $(gen_volume_params "$@")
114		  }
115		}
116	ATTACH
117}
118
119detach_volume() {
120	"$rootdir/scripts/sma-client.py" <<- DETACH
121		{
122		  "method": "DetachVolume",
123		  "params": {
124		    "device_handle": "$1",
125		    "volume_id": "$(uuid2base64 $2)"
126		  }
127		}
128	DETACH
129}
130
131verify_crypto_volume() {
132	local nqn=$1 uuid=$2 ns ns_bdev
133
134	ns=$(rpc_cmd nvmf_get_subsystems $nqn | jq -r '.[0].namespaces[0]')
135	ns_bdev=$(jq -r '.name' <<< "$ns")
136
137	# Make sure that the namespace is a crypto bdev and that there's only a single crypto bdev
138	[[ $(rpc_cmd bdev_get_bdevs -b "$ns_bdev" | jq -r '.[0].product_name') == crypto ]]
139	[[ $(rpc_cmd bdev_get_bdevs | jq -r '[.[] | select(.product_name == "crypto")] | length') -eq 1 ]]
140	# Check that the namespace's UUID/NGUID matches the one requested by the user
141	[[ $(jq -r '.uuid' <<< "$ns") == "$uuid" ]]
142	[[ $(jq -r '.nguid' <<< "$ns") == "$(uuid2nguid $uuid)" ]]
143}
144
145trap "cleanup; exit 1" SIGINT SIGTERM EXIT
146
147"$rootdir/build/bin/spdk_tgt" -m 0x1 &
148hostpid=$!
149
150"$rootdir/build/bin/spdk_tgt" -r "$tgtsock" -m 0x2 &
151tgtpid=$!
152
153$rootdir/scripts/sma.py -c <(
154	cat <<- CONFIG
155		address: 127.0.0.1
156		port: 8080
157		devices:
158		  - name: 'nvmf_tcp'
159		crypto:
160		  name: 'bdev_crypto'
161		  params:
162		    driver: 'crypto_aesni_mb'
163	CONFIG
164) &
165smapid=$!
166
167# Wait until the SMA starts listening
168sma_waitforlisten
169
170# Prepare the target
171uuid=$(uuidgen)
172waitforlisten "$tgtpid" "$tgtsock"
173$rpc_py -s "$tgtsock" << CONFIG
174	bdev_malloc_create -b malloc0 32 4096 -u $uuid
175	nvmf_create_transport -t tcp
176	nvmf_create_subsystem $tgtnqn -a
177	nvmf_subsystem_add_listener discovery -t tcp -a 127.0.0.1 -s $discovery_port
178	nvmf_subsystem_add_listener -t tcp -a 127.0.0.1 -s 4421 -f ipv4 $tgtnqn
179	nvmf_subsystem_add_ns $tgtnqn malloc0
180CONFIG
181
182# Create an empty device first
183device=$(create_device | jq -r '.handle')
184
185# First attach a volume without crypto
186attach_volume $device $uuid
187
188ns_bdev=$(rpc_cmd nvmf_get_subsystems $localnqn | jq -r '.[0].namespaces[0].name')
189[[ $(rpc_cmd bdev_get_bdevs -b "$ns_bdev" | jq -r '.[0].product_name') == 'NVMe disk' ]]
190[[ $(rpc_cmd bdev_get_bdevs | jq -r '[.[] | select(.product_name == "crypto")] | length') -eq 0 ]]
191[[ $(rpc_cmd nvmf_get_subsystems $localnqn | jq -r '.[0].namespaces[0].uuid') == "$uuid" ]]
192[[ $(rpc_cmd nvmf_get_subsystems $localnqn | jq -r '.[0].namespaces[0].nguid') == "$(uuid2nguid $uuid)" ]]
193
194detach_volume $device $uuid
195
196# Now attach a volume with crypto enabled
197attach_volume $device $uuid AES_CBC $key0
198
199[[ $(rpc_cmd bdev_nvme_get_discovery_info | jq -r '. | length') -eq 1 ]]
200[[ $(rpc_cmd nvmf_get_subsystems $localnqn | jq -r '.[0].namespaces | length') -eq 1 ]]
201# Make sure that the namespace exposed in the subsystem is a crypto bdev and is using malloc bdev's UUID
202verify_crypto_volume $localnqn $uuid
203# Check that it's using correct key
204crypto_bdev=$(rpc_cmd bdev_get_bdevs | jq -r '.[] | select(.product_name == "crypto")')
205[[ $(jq -r '.driver_specific.crypto.key' <<< "$crypto_bdev") == "$key0" ]]
206
207# Attach the same volume again
208attach_volume $device $uuid AES_CBC $key0
209
210# Nothing should change
211[[ $(rpc_cmd bdev_nvme_get_discovery_info | jq -r '. | length') -eq 1 ]]
212[[ $(rpc_cmd nvmf_get_subsystems $localnqn | jq -r '.[0].namespaces | length') -eq 1 ]]
213verify_crypto_volume $localnqn $uuid
214crypto_bdev2=$(rpc_cmd bdev_get_bdevs | jq -r '.[] | select(.product_name == "crypto")')
215[[ $(jq -r '.name' <<< "$crypto_bdev") == $(jq -r '.name' <<< "$crypto_bdev2") ]]
216[[ $(jq -r '.driver_specific.crypto.key' <<< "$crypto_bdev2") == "$key0" ]]
217
218# Try to do attach it again, but this time use a different crypto algorithm
219NOT attach_volume $device $uuid AES_XTS $key0
220# Check the same, this time changing the key
221NOT attach_volume $device $uuid AES_CBC $key1
222# Check the same, this time adding second key
223NOT attach_volume $device $uuid AES_CBC $key0 $key1
224# Check out-of-range cipher value
225NOT attach_volume $device $uuid 8 $key0
226
227# Make sure these failures haven't affected anything
228verify_crypto_volume $localnqn $uuid
229
230detach_volume $device $uuid
231
232# Check that if there's something wrong with crypto params, the volume won't get attached and
233# everything is cleaned up afterwards
234NOT attach_volume $device $uuid 8 $key0
235[[ $(rpc_cmd nvmf_get_subsystems $localnqn | jq -r '.[0].namespaces | length') -eq 0 ]]
236[[ $(rpc_cmd bdev_nvme_get_discovery_info | jq -r '. | length') -eq 0 ]]
237[[ $(rpc_cmd bdev_get_bdevs | jq -r length) -eq 0 ]]
238
239delete_device $device
240
241# Check that it's possible to create a device immediately specyfing a volume with crypto
242device=$(create_device $uuid AES_CBC $key0 | jq -r '.handle')
243verify_crypto_volume $localnqn $uuid
244
245delete_device $device
246
247# Try to create a device with incorrect volume crypto params, check that it fails and everything
248# is cleaned up afterwards
249NOT create_device $uuid 8 $key0
250[[ $(rpc_cmd bdev_nvme_get_discovery_info | jq -r '. | length') -eq 0 ]]
251[[ $(rpc_cmd bdev_get_bdevs | jq -r length) -eq 0 ]]
252[[ $(rpc_cmd nvmf_get_subsystems | jq -r "[.[] | select(.nqn == \"$localnqn\")] | length") -eq 0 ]]
253
254# Check that if crypto is disabled, it's not possible to attach a volume with crypto
255killprocess $smapid
256$rootdir/scripts/sma.py -c <(
257	cat <<- CONFIG
258		address: 127.0.0.1
259		port: 8080
260		devices:
261		  - name: 'nvmf_tcp'
262	CONFIG
263) &
264smapid=$!
265
266sma_waitforlisten
267device=$(create_device | jq -r '.handle')
268
269NOT attach_volume $device $uuid AES_CBC $key0
270[[ $(rpc_cmd bdev_nvme_get_discovery_info | jq -r '. | length') -eq 0 ]]
271[[ $(rpc_cmd bdev_get_bdevs | jq -r length) -eq 0 ]]
272
273cleanup
274trap - SIGINT SIGTERM EXIT
275