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 SPDK_RPC_REGISTER_ALIAS_DEPRECATED(bdev_crypto_create, construct_crypto_bdev) 292 293 struct rpc_delete_crypto { 294 char *name; 295 }; 296 297 static void 298 free_rpc_delete_crypto(struct rpc_delete_crypto *req) 299 { 300 free(req->name); 301 } 302 303 static const struct spdk_json_object_decoder rpc_delete_crypto_decoders[] = { 304 {"name", offsetof(struct rpc_delete_crypto, name), spdk_json_decode_string}, 305 }; 306 307 static void 308 rpc_bdev_crypto_delete_cb(void *cb_arg, int bdeverrno) 309 { 310 struct spdk_jsonrpc_request *request = cb_arg; 311 312 if (bdeverrno == 0) { 313 spdk_jsonrpc_send_bool_response(request, true); 314 } else { 315 spdk_jsonrpc_send_error_response(request, bdeverrno, spdk_strerror(-bdeverrno)); 316 } 317 } 318 319 static void 320 rpc_bdev_crypto_delete(struct spdk_jsonrpc_request *request, 321 const struct spdk_json_val *params) 322 { 323 struct rpc_delete_crypto req = {NULL}; 324 325 if (spdk_json_decode_object(params, rpc_delete_crypto_decoders, 326 SPDK_COUNTOF(rpc_delete_crypto_decoders), 327 &req)) { 328 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, 329 "Invalid parameters"); 330 goto cleanup; 331 } 332 333 delete_crypto_disk(req.name, rpc_bdev_crypto_delete_cb, request); 334 335 free_rpc_delete_crypto(&req); 336 337 return; 338 339 cleanup: 340 free_rpc_delete_crypto(&req); 341 } 342 SPDK_RPC_REGISTER("bdev_crypto_delete", rpc_bdev_crypto_delete, SPDK_RPC_RUNTIME) 343 SPDK_RPC_REGISTER_ALIAS_DEPRECATED(bdev_crypto_delete, delete_crypto_bdev) 344