xref: /spdk/module/bdev/crypto/vbdev_crypto_rpc.c (revision 895300d84030b370decaeaac0b3d6b7798227fe9)
1 /*-
2  *   BSD LICENSE
3  *
4  *   Copyright (c) Intel Corporation.
5  *   All rights reserved.
6  *   Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES.
7  *   All rights reserved.
8  *
9  *   Redistribution and use in source and binary forms, with or without
10  *   modification, are permitted provided that the following conditions
11  *   are met:
12  *
13  *     * Redistributions of source code must retain the above copyright
14  *       notice, this list of conditions and the following disclaimer.
15  *     * Redistributions in binary form must reproduce the above copyright
16  *       notice, this list of conditions and the following disclaimer in
17  *       the documentation and/or other materials provided with the
18  *       distribution.
19  *     * Neither the name of Intel Corporation nor the names of its
20  *       contributors may be used to endorse or promote products derived
21  *       from this software without specific prior written permission.
22  *
23  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
26  *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
27  *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28  *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
29  *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
30  *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
31  *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32  *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
33  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34  */
35 
36 #include "vbdev_crypto.h"
37 
38 /* Structure to hold the parameters for this RPC method. */
39 struct rpc_construct_crypto {
40 	char *base_bdev_name;
41 	char *name;
42 	char *crypto_pmd;
43 	char *key;
44 	char *cipher;
45 	char *key2;
46 };
47 
48 /* Free the allocated memory resource after the RPC handling. */
49 static void
50 free_rpc_construct_crypto(struct rpc_construct_crypto *r)
51 {
52 	free(r->base_bdev_name);
53 	free(r->name);
54 	free(r->crypto_pmd);
55 	free(r->key);
56 	free(r->cipher);
57 	free(r->key2);
58 }
59 
60 /* Structure to decode the input parameters for this RPC method. */
61 static const struct spdk_json_object_decoder rpc_construct_crypto_decoders[] = {
62 	{"base_bdev_name", offsetof(struct rpc_construct_crypto, base_bdev_name), spdk_json_decode_string},
63 	{"name", offsetof(struct rpc_construct_crypto, name), spdk_json_decode_string},
64 	{"crypto_pmd", offsetof(struct rpc_construct_crypto, crypto_pmd), spdk_json_decode_string},
65 	{"key", offsetof(struct rpc_construct_crypto, key), spdk_json_decode_string},
66 	{"cipher", offsetof(struct rpc_construct_crypto, cipher), spdk_json_decode_string, true},
67 	{"key2", offsetof(struct rpc_construct_crypto, key2), spdk_json_decode_string, true},
68 };
69 
70 /**
71  * Create crypto opts from rpc @req. Validate req fields and populate the
72  * correspoending fields in @opts.
73  *
74  * \param rpc Pointer to the rpc req.
75  * \param request Pointer to json request.
76  * \return Allocated and populated crypto opts or NULL on failure.
77  */
78 static struct vbdev_crypto_opts *
79 create_crypto_opts(struct rpc_construct_crypto *rpc,
80 		   struct spdk_jsonrpc_request *request)
81 {
82 	struct vbdev_crypto_opts *opts;
83 	int key_size, key2_size;
84 
85 	if (strcmp(rpc->crypto_pmd, AESNI_MB) == 0 && strcmp(rpc->cipher, AES_XTS) == 0) {
86 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
87 						 "Invalid cipher. AES_XTS is not available on AESNI_MB.");
88 		return NULL;
89 	}
90 
91 	if (strcmp(rpc->crypto_pmd, MLX5) == 0 && strcmp(rpc->cipher, AES_XTS) != 0) {
92 		spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
93 						     "Invalid cipher. %s is not available on MLX5.",
94 						     rpc->cipher);
95 		return NULL;
96 	}
97 
98 	if (strcmp(rpc->cipher, AES_XTS) == 0 && rpc->key2 == NULL) {
99 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
100 						 "Invalid key. A 2nd key is needed for AES_XTS.");
101 		return NULL;
102 	}
103 
104 	if (strcmp(rpc->cipher, AES_CBC) == 0 && rpc->key2 != NULL) {
105 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
106 						 "Invalid key. A 2nd key is needed only for AES_XTS.");
107 		return NULL;
108 	}
109 
110 	opts = calloc(1, sizeof(struct vbdev_crypto_opts));
111 	if (!opts) {
112 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
113 						 "Failed to allocate memory for crypto_opts.");
114 		return NULL;
115 	}
116 
117 	opts->bdev_name = strdup(rpc->base_bdev_name);
118 	if (!opts->bdev_name) {
119 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
120 						 "Failed to allocate memory for bdev_name.");
121 		goto error_alloc_bname;
122 	}
123 
124 	opts->vbdev_name = strdup(rpc->name);
125 	if (!opts->vbdev_name) {
126 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
127 						 "Failed to allocate memory for vbdev_name.");
128 		goto error_alloc_vname;
129 	}
130 
131 	opts->drv_name = strdup(rpc->crypto_pmd);
132 	if (!opts->drv_name) {
133 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
134 						 "Failed to allocate memory for drv_name.");
135 		goto error_alloc_dname;
136 	}
137 
138 	if (strcmp(opts->drv_name, MLX5) == 0) {
139 		/* Only AES-XTS supported. */
140 
141 		/* We cannot use strlen() after unhexlify() because of possible \0 chars
142 		 * used in the key. Hexlified version of key is twice as longer. */
143 		key_size = strnlen(rpc->key, (AES_XTS_512_BLOCK_KEY_LENGTH * 2) + 1);
144 		if (key_size != AES_XTS_256_BLOCK_KEY_LENGTH * 2 &&
145 		    key_size != AES_XTS_512_BLOCK_KEY_LENGTH * 2) {
146 			spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
147 							     "Invalid AES_XTS key string length for mlx5: %d. "
148 							     "Supported sizes in hex form: %d or %d.",
149 							     key_size, AES_XTS_256_BLOCK_KEY_LENGTH * 2,
150 							     AES_XTS_512_BLOCK_KEY_LENGTH * 2);
151 			goto error_invalid_key;
152 		}
153 	} else {
154 		if (strncmp(rpc->cipher, AES_XTS, sizeof(AES_XTS)) == 0) {
155 			/* AES_XTS for qat uses 128bit key. */
156 			key_size = strnlen(rpc->key, (AES_XTS_128_BLOCK_KEY_LENGTH * 2) + 1);
157 			if (key_size != AES_XTS_128_BLOCK_KEY_LENGTH * 2) {
158 				spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
159 								     "Invalid AES_XTS key string length: %d. "
160 								     "Supported size in hex form: %d.",
161 								     key_size, AES_XTS_128_BLOCK_KEY_LENGTH * 2);
162 				goto error_invalid_key;
163 			}
164 		} else {
165 			key_size = strnlen(rpc->key, (AES_CBC_KEY_LENGTH * 2) + 1);
166 			if (key_size != AES_CBC_KEY_LENGTH * 2) {
167 				spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
168 								     "Invalid AES_CBC key string length: %d. "
169 								     "Supported size in hex form: %d.",
170 								     key_size, AES_CBC_KEY_LENGTH * 2);
171 				goto error_invalid_key;
172 			}
173 		}
174 	}
175 	opts->key = unhexlify(rpc->key);
176 	if (!opts->key) {
177 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
178 						 "Failed to unhexlify key.");
179 		goto error_alloc_key;
180 	}
181 	opts->key_size = key_size / 2;
182 
183 	if (strncmp(rpc->cipher, AES_XTS, sizeof(AES_XTS)) == 0) {
184 		opts->cipher = AES_XTS;
185 		assert(rpc->key2);
186 		key2_size = strnlen(rpc->key2, (AES_XTS_TWEAK_KEY_LENGTH * 2) + 1);
187 		if (key2_size != AES_XTS_TWEAK_KEY_LENGTH * 2) {
188 			spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
189 							     "Invalid AES_XTS key2 length %d. "
190 							     "Supported size in hex form: %d.",
191 							     key2_size, AES_XTS_TWEAK_KEY_LENGTH * 2);
192 			goto error_invalid_key2;
193 		}
194 		opts->key2 = unhexlify(rpc->key2);
195 		if (!opts->key2) {
196 			spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
197 							 "Failed to unhexlify key2.");
198 			goto error_alloc_key2;
199 		}
200 		opts->key2_size = key2_size / 2;
201 
202 		/* DPDK expects the keys to be concatenated together. */
203 		opts->xts_key = calloc(1, opts->key_size + opts->key2_size + 1);
204 		if (opts->xts_key == NULL) {
205 			spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
206 							 "Failed to allocate memory for XTS key.");
207 			goto error_alloc_xts;
208 		}
209 		memcpy(opts->xts_key, opts->key, opts->key_size);
210 		memcpy(opts->xts_key + opts->key_size, opts->key2, opts->key2_size);
211 	} else if (strncmp(rpc->cipher, AES_CBC, sizeof(AES_CBC)) == 0) {
212 		opts->cipher = AES_CBC;
213 	} else {
214 		spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
215 						     "Invalid param. Cipher %s is not supported.",
216 						     rpc->cipher);
217 		goto error_cipher;
218 	}
219 	return opts;
220 
221 	/* Error cleanup paths. */
222 error_cipher:
223 error_alloc_xts:
224 error_alloc_key2:
225 error_invalid_key2:
226 	if (opts->key) {
227 		memset(opts->key, 0, opts->key_size);
228 		free(opts->key);
229 	}
230 	opts->key_size = 0;
231 error_alloc_key:
232 error_invalid_key:
233 	free(opts->drv_name);
234 error_alloc_dname:
235 	free(opts->vbdev_name);
236 error_alloc_vname:
237 	free(opts->bdev_name);
238 error_alloc_bname:
239 	free(opts);
240 	return NULL;
241 }
242 
243 /* Decode the parameters for this RPC method and properly construct the crypto
244  * device. Error status returned in the failed cases.
245  */
246 static void
247 rpc_bdev_crypto_create(struct spdk_jsonrpc_request *request,
248 		       const struct spdk_json_val *params)
249 {
250 	struct rpc_construct_crypto req = {NULL};
251 	struct vbdev_crypto_opts *crypto_opts;
252 	struct spdk_json_write_ctx *w;
253 	int rc;
254 
255 	if (spdk_json_decode_object(params, rpc_construct_crypto_decoders,
256 				    SPDK_COUNTOF(rpc_construct_crypto_decoders),
257 				    &req)) {
258 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
259 						 "Failed to decode crypto disk create parameters.");
260 		goto cleanup;
261 	}
262 
263 	if (req.cipher == NULL) {
264 		req.cipher = strdup(AES_CBC);
265 		if (req.cipher == NULL) {
266 			spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
267 							 "Unable to allocate memory for req.cipher");
268 			goto cleanup;
269 		}
270 	}
271 
272 	crypto_opts = create_crypto_opts(&req, request);
273 	if (crypto_opts == NULL) {
274 		goto cleanup;
275 	}
276 
277 	rc = create_crypto_disk(crypto_opts);
278 	if (rc) {
279 		spdk_jsonrpc_send_error_response(request, rc, spdk_strerror(-rc));
280 		free_crypto_opts(crypto_opts);
281 		goto cleanup;
282 	}
283 
284 	w = spdk_jsonrpc_begin_result(request);
285 	spdk_json_write_string(w, req.name);
286 	spdk_jsonrpc_end_result(request, w);
287 cleanup:
288 	free_rpc_construct_crypto(&req);
289 }
290 SPDK_RPC_REGISTER("bdev_crypto_create", rpc_bdev_crypto_create, SPDK_RPC_RUNTIME)
291 
292 struct rpc_delete_crypto {
293 	char *name;
294 };
295 
296 static void
297 free_rpc_delete_crypto(struct rpc_delete_crypto *req)
298 {
299 	free(req->name);
300 }
301 
302 static const struct spdk_json_object_decoder rpc_delete_crypto_decoders[] = {
303 	{"name", offsetof(struct rpc_delete_crypto, name), spdk_json_decode_string},
304 };
305 
306 static void
307 rpc_bdev_crypto_delete_cb(void *cb_arg, int bdeverrno)
308 {
309 	struct spdk_jsonrpc_request *request = cb_arg;
310 
311 	if (bdeverrno == 0) {
312 		spdk_jsonrpc_send_bool_response(request, true);
313 	} else {
314 		spdk_jsonrpc_send_error_response(request, bdeverrno, spdk_strerror(-bdeverrno));
315 	}
316 }
317 
318 static void
319 rpc_bdev_crypto_delete(struct spdk_jsonrpc_request *request,
320 		       const struct spdk_json_val *params)
321 {
322 	struct rpc_delete_crypto req = {NULL};
323 
324 	if (spdk_json_decode_object(params, rpc_delete_crypto_decoders,
325 				    SPDK_COUNTOF(rpc_delete_crypto_decoders),
326 				    &req)) {
327 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
328 						 "Invalid parameters");
329 		goto cleanup;
330 	}
331 
332 	delete_crypto_disk(req.name, rpc_bdev_crypto_delete_cb, request);
333 
334 	free_rpc_delete_crypto(&req);
335 
336 	return;
337 
338 cleanup:
339 	free_rpc_delete_crypto(&req);
340 }
341 SPDK_RPC_REGISTER("bdev_crypto_delete", rpc_bdev_crypto_delete, SPDK_RPC_RUNTIME)
342