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