xref: /spdk/module/bdev/crypto/vbdev_crypto_rpc.c (revision 588dfe314bb83d86effdf67ec42837b11c2620bf)
1 /*   SPDX-License-Identifier: BSD-3-Clause
2  *   Copyright (C) 2018 Intel Corporation.
3  *   All rights reserved.
4  *   Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES.
5  *   All rights reserved.
6  */
7 
8 #include "vbdev_crypto.h"
9 
10 #include "spdk/hexlify.h"
11 
12 /* Structure to hold the parameters for this RPC method. */
13 struct rpc_construct_crypto {
14 	char *base_bdev_name;
15 	char *name;
16 	char *crypto_pmd;
17 	char *key;
18 	char *cipher;
19 	char *key2;
20 };
21 
22 /* Free the allocated memory resource after the RPC handling. */
23 static void
24 free_rpc_construct_crypto(struct rpc_construct_crypto *r)
25 {
26 	free(r->base_bdev_name);
27 	free(r->name);
28 	free(r->crypto_pmd);
29 	free(r->key);
30 	free(r->cipher);
31 	free(r->key2);
32 }
33 
34 /* Structure to decode the input parameters for this RPC method. */
35 static const struct spdk_json_object_decoder rpc_construct_crypto_decoders[] = {
36 	{"base_bdev_name", offsetof(struct rpc_construct_crypto, base_bdev_name), spdk_json_decode_string},
37 	{"name", offsetof(struct rpc_construct_crypto, name), spdk_json_decode_string},
38 	{"crypto_pmd", offsetof(struct rpc_construct_crypto, crypto_pmd), spdk_json_decode_string},
39 	{"key", offsetof(struct rpc_construct_crypto, key), spdk_json_decode_string},
40 	{"cipher", offsetof(struct rpc_construct_crypto, cipher), spdk_json_decode_string, true},
41 	{"key2", offsetof(struct rpc_construct_crypto, key2), spdk_json_decode_string, true},
42 };
43 
44 /**
45  * Create crypto opts from rpc @req. Validate req fields and populate the
46  * correspoending fields in @opts.
47  *
48  * \param rpc Pointer to the rpc req.
49  * \param request Pointer to json request.
50  * \return Allocated and populated crypto opts or NULL on failure.
51  */
52 static struct vbdev_crypto_opts *
53 create_crypto_opts(struct rpc_construct_crypto *rpc,
54 		   struct spdk_jsonrpc_request *request)
55 {
56 	struct vbdev_crypto_opts *opts;
57 	int key_size, key2_size;
58 
59 	if (strcmp(rpc->crypto_pmd, AESNI_MB) == 0 && strcmp(rpc->cipher, AES_XTS) == 0) {
60 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
61 						 "Invalid cipher. AES_XTS is not available on AESNI_MB.");
62 		return NULL;
63 	}
64 
65 	if (strcmp(rpc->crypto_pmd, MLX5) == 0 && strcmp(rpc->cipher, AES_XTS) != 0) {
66 		spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
67 						     "Invalid cipher. %s is not available on MLX5.",
68 						     rpc->cipher);
69 		return NULL;
70 	}
71 
72 	if (strcmp(rpc->cipher, AES_XTS) == 0 && rpc->key2 == NULL) {
73 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
74 						 "Invalid key. A 2nd key is needed for AES_XTS.");
75 		return NULL;
76 	}
77 
78 	if (strcmp(rpc->cipher, AES_CBC) == 0 && rpc->key2 != NULL) {
79 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
80 						 "Invalid key. A 2nd key is needed only for AES_XTS.");
81 		return NULL;
82 	}
83 
84 	opts = calloc(1, sizeof(struct vbdev_crypto_opts));
85 	if (!opts) {
86 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
87 						 "Failed to allocate memory for crypto_opts.");
88 		return NULL;
89 	}
90 
91 	opts->bdev_name = strdup(rpc->base_bdev_name);
92 	if (!opts->bdev_name) {
93 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
94 						 "Failed to allocate memory for bdev_name.");
95 		goto error_alloc_bname;
96 	}
97 
98 	opts->vbdev_name = strdup(rpc->name);
99 	if (!opts->vbdev_name) {
100 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
101 						 "Failed to allocate memory for vbdev_name.");
102 		goto error_alloc_vname;
103 	}
104 
105 	opts->drv_name = strdup(rpc->crypto_pmd);
106 	if (!opts->drv_name) {
107 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
108 						 "Failed to allocate memory for drv_name.");
109 		goto error_alloc_dname;
110 	}
111 
112 	if (strcmp(opts->drv_name, MLX5) == 0) {
113 		/* Only AES-XTS supported. */
114 
115 		/* We cannot use strlen() after spdk_unhexlify() because of possible \0 chars
116 		 * used in the key. Hexlified version of key is twice as longer. */
117 		key_size = strnlen(rpc->key, (AES_XTS_512_BLOCK_KEY_LENGTH * 2) + 1);
118 		if (key_size != AES_XTS_256_BLOCK_KEY_LENGTH * 2 &&
119 		    key_size != AES_XTS_512_BLOCK_KEY_LENGTH * 2) {
120 			spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
121 							     "Invalid AES_XTS key string length for mlx5: %d. "
122 							     "Supported sizes in hex form: %d or %d.",
123 							     key_size, AES_XTS_256_BLOCK_KEY_LENGTH * 2,
124 							     AES_XTS_512_BLOCK_KEY_LENGTH * 2);
125 			goto error_invalid_key;
126 		}
127 	} else {
128 		if (strncmp(rpc->cipher, AES_XTS, sizeof(AES_XTS)) == 0) {
129 			/* AES_XTS for qat uses 128bit key. */
130 			key_size = strnlen(rpc->key, (AES_XTS_128_BLOCK_KEY_LENGTH * 2) + 1);
131 			if (key_size != AES_XTS_128_BLOCK_KEY_LENGTH * 2) {
132 				spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
133 								     "Invalid AES_XTS key string length: %d. "
134 								     "Supported size in hex form: %d.",
135 								     key_size, AES_XTS_128_BLOCK_KEY_LENGTH * 2);
136 				goto error_invalid_key;
137 			}
138 		} else {
139 			key_size = strnlen(rpc->key, (AES_CBC_KEY_LENGTH * 2) + 1);
140 			if (key_size != AES_CBC_KEY_LENGTH * 2) {
141 				spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
142 								     "Invalid AES_CBC key string length: %d. "
143 								     "Supported size in hex form: %d.",
144 								     key_size, AES_CBC_KEY_LENGTH * 2);
145 				goto error_invalid_key;
146 			}
147 		}
148 	}
149 	opts->key = spdk_unhexlify(rpc->key);
150 	if (!opts->key) {
151 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
152 						 "Failed to unhexlify key.");
153 		goto error_alloc_key;
154 	}
155 	opts->key_size = key_size / 2;
156 
157 	if (strncmp(rpc->cipher, AES_XTS, sizeof(AES_XTS)) == 0) {
158 		opts->cipher = AES_XTS;
159 		assert(rpc->key2);
160 		key2_size = strnlen(rpc->key2, (AES_XTS_TWEAK_KEY_LENGTH * 2) + 1);
161 		if (key2_size != AES_XTS_TWEAK_KEY_LENGTH * 2) {
162 			spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
163 							     "Invalid AES_XTS key2 length %d. "
164 							     "Supported size in hex form: %d.",
165 							     key2_size, AES_XTS_TWEAK_KEY_LENGTH * 2);
166 			goto error_invalid_key2;
167 		}
168 		opts->key2 = spdk_unhexlify(rpc->key2);
169 		if (!opts->key2) {
170 			spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
171 							 "Failed to unhexlify key2.");
172 			goto error_alloc_key2;
173 		}
174 		opts->key2_size = key2_size / 2;
175 
176 		/* DPDK expects the keys to be concatenated together. */
177 		opts->xts_key = calloc(1, opts->key_size + opts->key2_size + 1);
178 		if (opts->xts_key == NULL) {
179 			spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
180 							 "Failed to allocate memory for XTS key.");
181 			goto error_alloc_xts;
182 		}
183 		memcpy(opts->xts_key, opts->key, opts->key_size);
184 		memcpy(opts->xts_key + opts->key_size, opts->key2, opts->key2_size);
185 	} else if (strncmp(rpc->cipher, AES_CBC, sizeof(AES_CBC)) == 0) {
186 		opts->cipher = AES_CBC;
187 	} else {
188 		spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
189 						     "Invalid param. Cipher %s is not supported.",
190 						     rpc->cipher);
191 		goto error_cipher;
192 	}
193 	return opts;
194 
195 	/* Error cleanup paths. */
196 error_cipher:
197 error_alloc_xts:
198 error_alloc_key2:
199 error_invalid_key2:
200 	if (opts->key) {
201 		memset(opts->key, 0, opts->key_size);
202 		free(opts->key);
203 	}
204 	opts->key_size = 0;
205 error_alloc_key:
206 error_invalid_key:
207 	free(opts->drv_name);
208 error_alloc_dname:
209 	free(opts->vbdev_name);
210 error_alloc_vname:
211 	free(opts->bdev_name);
212 error_alloc_bname:
213 	free(opts);
214 	return NULL;
215 }
216 
217 /* Decode the parameters for this RPC method and properly construct the crypto
218  * device. Error status returned in the failed cases.
219  */
220 static void
221 rpc_bdev_crypto_create(struct spdk_jsonrpc_request *request,
222 		       const struct spdk_json_val *params)
223 {
224 	struct rpc_construct_crypto req = {NULL};
225 	struct vbdev_crypto_opts *crypto_opts;
226 	struct spdk_json_write_ctx *w;
227 	int rc;
228 
229 	if (spdk_json_decode_object(params, rpc_construct_crypto_decoders,
230 				    SPDK_COUNTOF(rpc_construct_crypto_decoders),
231 				    &req)) {
232 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
233 						 "Failed to decode crypto disk create parameters.");
234 		goto cleanup;
235 	}
236 
237 	if (req.cipher == NULL) {
238 		req.cipher = strdup(AES_CBC);
239 		if (req.cipher == NULL) {
240 			spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
241 							 "Unable to allocate memory for req.cipher");
242 			goto cleanup;
243 		}
244 	}
245 
246 	crypto_opts = create_crypto_opts(&req, request);
247 	if (crypto_opts == NULL) {
248 		goto cleanup;
249 	}
250 
251 	rc = create_crypto_disk(crypto_opts);
252 	if (rc) {
253 		spdk_jsonrpc_send_error_response(request, rc, spdk_strerror(-rc));
254 		free_crypto_opts(crypto_opts);
255 		goto cleanup;
256 	}
257 
258 	w = spdk_jsonrpc_begin_result(request);
259 	spdk_json_write_string(w, req.name);
260 	spdk_jsonrpc_end_result(request, w);
261 cleanup:
262 	free_rpc_construct_crypto(&req);
263 }
264 SPDK_RPC_REGISTER("bdev_crypto_create", rpc_bdev_crypto_create, SPDK_RPC_RUNTIME)
265 
266 struct rpc_delete_crypto {
267 	char *name;
268 };
269 
270 static void
271 free_rpc_delete_crypto(struct rpc_delete_crypto *req)
272 {
273 	free(req->name);
274 }
275 
276 static const struct spdk_json_object_decoder rpc_delete_crypto_decoders[] = {
277 	{"name", offsetof(struct rpc_delete_crypto, name), spdk_json_decode_string},
278 };
279 
280 static void
281 rpc_bdev_crypto_delete_cb(void *cb_arg, int bdeverrno)
282 {
283 	struct spdk_jsonrpc_request *request = cb_arg;
284 
285 	if (bdeverrno == 0) {
286 		spdk_jsonrpc_send_bool_response(request, true);
287 	} else {
288 		spdk_jsonrpc_send_error_response(request, bdeverrno, spdk_strerror(-bdeverrno));
289 	}
290 }
291 
292 static void
293 rpc_bdev_crypto_delete(struct spdk_jsonrpc_request *request,
294 		       const struct spdk_json_val *params)
295 {
296 	struct rpc_delete_crypto req = {NULL};
297 
298 	if (spdk_json_decode_object(params, rpc_delete_crypto_decoders,
299 				    SPDK_COUNTOF(rpc_delete_crypto_decoders),
300 				    &req)) {
301 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
302 						 "Invalid parameters");
303 		goto cleanup;
304 	}
305 
306 	delete_crypto_disk(req.name, rpc_bdev_crypto_delete_cb, request);
307 
308 	free_rpc_delete_crypto(&req);
309 
310 	return;
311 
312 cleanup:
313 	free_rpc_delete_crypto(&req);
314 }
315 SPDK_RPC_REGISTER("bdev_crypto_delete", rpc_bdev_crypto_delete, SPDK_RPC_RUNTIME)
316