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