bdev/crypto: Critical fix about using binary keys

- Added hexlify() and unhexlify() for key and key2. This is required
  for keys that contain zero and non-ascii characters. Since binary
  keys may contain zero character, strlen(key) cannot be used and
  key_size and key2_size are used instead. Non-asci chars are not
  allowed in json and using hexlified keys fixes this issue as well.
- Updated documentation to clearly state that hexlified keys must
  be used.
- Updated test scripts.

Signed-off-by: Yuriy Umanets <yumanets@nvidia.com>
Change-Id: I3fce7839f7eaa67d0307071eba80b4cea472d731
Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/11891
Community-CI: Mellanox Build Bot
Tested-by: SPDK CI Jenkins <sys_sgci@intel.com>
Reviewed-by: Jim Harris <james.r.harris@intel.com>
Reviewed-by: Paul Luse <paul.e.luse@intel.com>
Reviewed-by: Shuhei Matsumoto <smatsumoto@nvidia.com>
Reviewed-by: Aleksey Marchuk <alexeymar@mellanox.com>
This commit is contained in:
Yuriy Umanets 2022-03-11 14:15:57 +02:00 committed by Tomasz Zawadzki
parent 45f24aebe7
commit 1434e255ef
7 changed files with 231 additions and 56 deletions

View File

@ -30,6 +30,10 @@ A new flag `ACCEL_FLAG_PERSISTENT` was added to indicate the target memory is PM
Support for AES_XTS was added for MLX5 polled mode driver (pmd).
bdev_crypto_create RPC now requires hexlified 'key' and 'key2' params for all pmd drivers.
Unhexlifying is performed during RPC command processing and the vbdev crypto module runs on
binary keys as before.
### bdev_nvme
Added `bdev_nvme_add_error_injection` and `bdev_nvme_remove_error_injection` RPCs to add and

View File

@ -164,11 +164,25 @@ may cause problems in some use cases.
Example command
`rpc.py bdev_crypto_create NVMe1n1 CryNvmeA crypto_aesni_mb 0123456789123456`
`rpc.py bdev_crypto_create NVMe1n1 CryNvmeA crypto_aesni_mb 01234567891234560123456789123456`
This command will create a crypto vbdev called 'CryNvmeA' on top of the NVMe bdev
'NVMe1n1' and will use the DPDK software driver 'crypto_aesni_mb' and the key
'0123456789123456'.
'01234567891234560123456789123456'.
Please make sure the keys are provided in hexlified format. This means string passed to
rpc.py must be twice as long than the key length in binary form.
Example command
rpc.py bdev_crypto_create -c AES_XTS -k2 7859243a027411e581e0c40a35c8228f NVMe1n1 CryNvmeA \
mlx5_pci d16a2f3a9e9f5b32daefacd7f5984f4578add84425be4a0baa489b9de8884b09
This command will create a crypto vbdev called 'CryNvmeA' on top of the NVMe bdev
'NVMe1n1' and will use the DPDK software driver 'mlx5_pci', the AES key
'd16a2f3a9e9f5b32daefacd7f5984f4578add84425be4a0baa489b9de8884b09' and the XTS key
'7859243a027411e581e0c40a35c8228f'. In other words, the compound AES_XTS key to be used is
'd16a2f3a9e9f5b32daefacd7f5984f4578add84425be4a0baa489b9de8884b097859243a027411e581e0c40a35c8228f'
To remove the vbdev use the bdev_crypto_delete command.

View File

@ -2115,9 +2115,12 @@ Name | Optional | Type | Description
base_bdev_name | Required | string | Name of the base bdev
name | Required | string | Name of the crypto vbdev to create
crypto_pmd | Required | string | Name of the crypto device driver
key | Required | string | Key
key | Required | string | Key in hex form
cipher | Required | string | Cipher to use, AES_CBC or AES_XTS (QAT and MLX5)
key2 | Required | string | 2nd key only required for cipher AET_XTS
key2 | Required | string | 2nd key in hex form only required for cipher AET_XTS
Both key and key2 must be passed in the hexlified form. For example, 256bit AES key may look like this:
afd9477abf50254219ccb75965fbe39f23ebead5676e292582a0a67f66b88215
#### Result
@ -2133,7 +2136,7 @@ Example request:
"base_bdev_name": "Nvme0n1",
"name": "my_crypto_bdev",
"crypto_pmd": "crypto_aesni_mb",
"key": "1234567890123456",
"key": "12345678901234561234567890123456",
"cipher": "AES_CBC"
},
"jsonrpc": "2.0",

View File

@ -180,9 +180,11 @@ struct bdev_names {
* use, you must use an RPC to specify the key for security reasons.
*/
uint8_t *key; /* key per bdev */
uint8_t key_size; /* binary key len */
char *drv_name; /* name of the crypto device driver */
char *cipher; /* AES_CBC or AES_XTS */
uint8_t *key2; /* key #2 for AES_XTS, per bdev */
uint8_t key2_size; /* binary key2 len */
TAILQ_ENTRY(bdev_names) link;
};
static TAILQ_HEAD(, bdev_names) g_bdev_names = TAILQ_HEAD_INITIALIZER(g_bdev_names);
@ -195,7 +197,9 @@ struct vbdev_crypto {
struct spdk_bdev_desc *base_desc; /* its descriptor we get from open */
struct spdk_bdev crypto_bdev; /* the crypto virtual bdev */
uint8_t *key; /* key per bdev */
uint8_t key_size; /* binary key len */
uint8_t *key2; /* for XTS */
uint8_t key2_size; /* binary key2 len */
uint8_t *xts_key; /* key + key 2 */
char *drv_name; /* name of the crypto device driver */
char *cipher; /* cipher used */
@ -1421,15 +1425,16 @@ _device_unregister_cb(void *io_device)
rte_cryptodev_sym_session_free(crypto_bdev->session_encrypt);
free(crypto_bdev->drv_name);
if (crypto_bdev->key) {
memset(crypto_bdev->key, 0, strlen(crypto_bdev->key));
memset(crypto_bdev->key, 0, crypto_bdev->key_size);
free(crypto_bdev->key);
}
if (crypto_bdev->key2) {
memset(crypto_bdev->key2, 0, strlen(crypto_bdev->key2));
memset(crypto_bdev->key2, 0, crypto_bdev->key2_size);
free(crypto_bdev->key2);
}
if (crypto_bdev->xts_key) {
memset(crypto_bdev->xts_key, 0, strlen(crypto_bdev->xts_key));
memset(crypto_bdev->xts_key, 0,
crypto_bdev->key_size + crypto_bdev->key2_size);
free(crypto_bdev->xts_key);
}
free(crypto_bdev->crypto_bdev.name);
@ -1499,19 +1504,45 @@ static int
vbdev_crypto_dump_info_json(void *ctx, struct spdk_json_write_ctx *w)
{
struct vbdev_crypto *crypto_bdev = (struct vbdev_crypto *)ctx;
char *hexkey = NULL, *hexkey2 = NULL;
int rc = 0;
hexkey = hexlify(crypto_bdev->key,
crypto_bdev->key_size);
if (!hexkey) {
return -ENOMEM;
}
if (crypto_bdev->key2) {
hexkey2 = hexlify(crypto_bdev->key2,
crypto_bdev->key2_size);
if (!hexkey2) {
rc = -ENOMEM;
goto out_err;
}
}
spdk_json_write_name(w, "crypto");
spdk_json_write_object_begin(w);
spdk_json_write_named_string(w, "base_bdev_name", spdk_bdev_get_name(crypto_bdev->base_bdev));
spdk_json_write_named_string(w, "name", spdk_bdev_get_name(&crypto_bdev->crypto_bdev));
spdk_json_write_named_string(w, "crypto_pmd", crypto_bdev->drv_name);
spdk_json_write_named_string(w, "key", crypto_bdev->key);
if (strcmp(crypto_bdev->cipher, AES_XTS) == 0) {
spdk_json_write_named_string(w, "key2", crypto_bdev->key2);
spdk_json_write_named_string(w, "key", hexkey);
if (hexkey2) {
spdk_json_write_named_string(w, "key2", hexkey2);
}
spdk_json_write_named_string(w, "cipher", crypto_bdev->cipher);
spdk_json_write_object_end(w);
return 0;
out_err:
if (hexkey) {
memset(hexkey, 0, strlen(hexkey));
free(hexkey);
}
if (hexkey2) {
memset(hexkey2, 0, strlen(hexkey2));
free(hexkey2);
}
return rc;
}
static int
@ -1520,19 +1551,46 @@ vbdev_crypto_config_json(struct spdk_json_write_ctx *w)
struct vbdev_crypto *crypto_bdev;
TAILQ_FOREACH(crypto_bdev, &g_vbdev_crypto, link) {
char *hexkey = NULL, *hexkey2 = NULL;
hexkey = hexlify(crypto_bdev->key,
crypto_bdev->key_size);
if (!hexkey) {
return -ENOMEM;
}
if (crypto_bdev->key2) {
hexkey2 = hexlify(crypto_bdev->key2,
crypto_bdev->key2_size);
if (!hexkey2) {
memset(hexkey, 0, strlen(hexkey));
free(hexkey);
return -ENOMEM;
}
}
spdk_json_write_object_begin(w);
spdk_json_write_named_string(w, "method", "bdev_crypto_create");
spdk_json_write_named_object_begin(w, "params");
spdk_json_write_named_string(w, "base_bdev_name", spdk_bdev_get_name(crypto_bdev->base_bdev));
spdk_json_write_named_string(w, "name", spdk_bdev_get_name(&crypto_bdev->crypto_bdev));
spdk_json_write_named_string(w, "crypto_pmd", crypto_bdev->drv_name);
spdk_json_write_named_string(w, "key", crypto_bdev->key);
if (strcmp(crypto_bdev->cipher, AES_XTS) == 0) {
spdk_json_write_named_string(w, "key2", crypto_bdev->key2);
spdk_json_write_named_string(w, "key", hexkey);
if (hexkey2) {
spdk_json_write_named_string(w, "key2", hexkey2);
}
spdk_json_write_named_string(w, "cipher", crypto_bdev->cipher);
spdk_json_write_object_end(w);
spdk_json_write_object_end(w);
if (hexkey) {
memset(hexkey, 0, strlen(hexkey));
free(hexkey);
}
if (hexkey2) {
memset(hexkey2, 0, strlen(hexkey2));
free(hexkey2);
}
}
return 0;
}
@ -1689,62 +1747,65 @@ vbdev_crypto_insert_name(const char *bdev_name, const char *vbdev_name,
if (strcmp(crypto_pmd, MLX5) == 0) {
/* Only AES-XTS supported. */
key_size = strnlen(key, AES_XTS_512_BLOCK_KEY_LENGTH + 1);
if (key_size != AES_XTS_256_BLOCK_KEY_LENGTH &&
key_size != AES_XTS_512_BLOCK_KEY_LENGTH) {
key_size = strnlen(key, (AES_XTS_512_BLOCK_KEY_LENGTH * 2) + 1);
if (key_size != AES_XTS_256_BLOCK_KEY_LENGTH * 2 &&
key_size != AES_XTS_512_BLOCK_KEY_LENGTH * 2) {
SPDK_ERRLOG("Invalid AES_XTS key string length for mlx5: %d. "
"Supported sizes in hex form: %d or %d.\n",
key_size, AES_XTS_256_BLOCK_KEY_LENGTH,
AES_XTS_512_BLOCK_KEY_LENGTH);
key_size, AES_XTS_256_BLOCK_KEY_LENGTH * 2,
AES_XTS_512_BLOCK_KEY_LENGTH * 2);
rc = -EINVAL;
goto error_invalid_key;
}
} else {
if (strncmp(cipher, AES_XTS, sizeof(AES_XTS)) == 0) {
/* AES_XTS for qat uses 128bit key. */
key_size = strnlen(key, AES_XTS_128_BLOCK_KEY_LENGTH + 1);
if (key_size != AES_XTS_128_BLOCK_KEY_LENGTH) {
key_size = strnlen(key, (AES_XTS_128_BLOCK_KEY_LENGTH * 2) + 1);
if (key_size != AES_XTS_128_BLOCK_KEY_LENGTH * 2) {
SPDK_ERRLOG("Invalid AES_XTS key string length: %d. "
"Supported size in hex form: %d.\n",
key_size, AES_XTS_128_BLOCK_KEY_LENGTH);
key_size, AES_XTS_128_BLOCK_KEY_LENGTH * 2);
rc = -EINVAL;
goto error_invalid_key;
}
} else {
key_size = strnlen(key, AES_CBC_KEY_LENGTH + 1);
if (key_size != AES_CBC_KEY_LENGTH) {
key_size = strnlen(key, (AES_CBC_KEY_LENGTH * 2) + 1);
if (key_size != AES_CBC_KEY_LENGTH * 2) {
SPDK_ERRLOG("Invalid AES_CBC key string length: %d. "
"Supported size in hex form: %d.\n",
key_size, AES_CBC_KEY_LENGTH);
key_size, AES_CBC_KEY_LENGTH * 2);
rc = -EINVAL;
goto error_invalid_key;
}
}
}
name->key = strdup(key);
name->key = unhexlify(key);
if (!name->key) {
SPDK_ERRLOG("could not allocate name->key\n");
SPDK_ERRLOG("Failed to allocate key!\n");
rc = -ENOMEM;
goto error_alloc_key;
}
name->key_size = key_size / 2;
if (strncmp(cipher, AES_XTS, sizeof(AES_XTS)) == 0) {
name->cipher = AES_XTS;
assert(key2);
key2_size = strnlen(key2, AES_XTS_TWEAK_KEY_LENGTH + 1);
if (key2_size != AES_XTS_TWEAK_KEY_LENGTH) {
key2_size = strnlen(key2, (AES_XTS_TWEAK_KEY_LENGTH * 2) + 1);
if (key2_size != AES_XTS_TWEAK_KEY_LENGTH * 2) {
SPDK_ERRLOG("Invalid AES_XTS key2 length %d. "
"Supported size in hex form: %d.\n",
key2_size, AES_XTS_TWEAK_KEY_LENGTH);
key2_size, AES_XTS_TWEAK_KEY_LENGTH * 2);
rc = -EINVAL;
goto error_invalid_key2;
}
name->key2 = strdup(key2);
name->key2 = unhexlify(key2);
if (!name->key2) {
SPDK_ERRLOG("could not allocate name->key2\n");
rc = -ENOMEM;
goto error_alloc_key2;
}
name->key2_size = key2_size / 2;
} else if (strncmp(cipher, AES_CBC, sizeof(AES_CBC)) == 0) {
name->cipher = AES_CBC;
} else {
@ -1762,7 +1823,7 @@ error_cipher:
error_alloc_key2:
error_invalid_key2:
if (name->key) {
memset(name->key, 0, strlen(name->key));
memset(name->key, 0, name->key_size);
free(name->key);
}
error_alloc_key:
@ -1827,12 +1888,12 @@ vbdev_crypto_finish(void)
while ((name = TAILQ_FIRST(&g_bdev_names))) {
TAILQ_REMOVE(&g_bdev_names, name, link);
free(name->drv_name);
memset(name->key, 0, strlen(name->key));
memset(name->key, 0, name->key_size);
free(name->key);
free(name->bdev_name);
free(name->vbdev_name);
if (name->key2) {
memset(name->key2, 0, strlen(name->key2));
memset(name->key2, 0, name->key2_size);
free(name->key2);
}
free(name);
@ -1929,8 +1990,6 @@ vbdev_crypto_claim(const char *bdev_name)
struct vbdev_dev *device;
struct spdk_bdev *bdev;
bool found = false;
uint8_t key_size = 0;
uint8_t key2_size = 0;
int rc = 0;
if (g_number_of_claimed_volumes >= MAX_CRYPTO_VOLUMES) {
@ -1962,13 +2021,14 @@ vbdev_crypto_claim(const char *bdev_name)
goto error_bdev_name;
}
vbdev->key = strdup(name->key);
vbdev->key = calloc(1, name->key_size + 1);
if (!vbdev->key) {
SPDK_ERRLOG("could not allocate crypto_bdev key\n");
rc = -ENOMEM;
goto error_alloc_key;
}
key_size = strlen(vbdev->key);
memcpy(vbdev->key, name->key, name->key_size);
vbdev->key_size = name->key_size;
vbdev->drv_name = strdup(name->drv_name);
if (!vbdev->drv_name) {
@ -2018,31 +2078,32 @@ vbdev_crypto_claim(const char *bdev_name)
vbdev->cipher = AES_XTS;
assert(name->key2);
vbdev->key2 = strdup(name->key2);
vbdev->key2 = calloc(1, name->key2_size + 1);
if (!vbdev->key2) {
SPDK_ERRLOG("could not allocate crypto_bdev key2\n");
rc = -ENOMEM;
goto error_alloc_key2;
}
key2_size = strlen(vbdev->key2);
memcpy(vbdev->key2, name->key2, name->key2_size);
vbdev->key2_size = name->key2_size;
/* DPDK expects the keys to be concatenated together. */
vbdev->xts_key = calloc(1, key_size + key2_size + 1);
vbdev->xts_key = calloc(1, vbdev->key_size + vbdev->key2_size + 1);
if (vbdev->xts_key == NULL) {
SPDK_ERRLOG("Failed to allocate memory for XTS key.\n");
rc = -ENOMEM;
goto error_xts_key;
}
memcpy(vbdev->xts_key, vbdev->key, key_size);
memcpy(vbdev->xts_key + key_size, name->key2, key2_size);
memcpy(vbdev->xts_key, vbdev->key, vbdev->key_size);
memcpy(vbdev->xts_key + vbdev->key_size, vbdev->key2, vbdev->key2_size);
vbdev->cipher_xform.cipher.key.data = vbdev->xts_key;
vbdev->cipher_xform.cipher.key.length = key_size + key2_size;
vbdev->cipher_xform.cipher.key.length = vbdev->key_size + vbdev->key2_size;
vbdev->cipher_xform.cipher.algo = RTE_CRYPTO_CIPHER_AES_XTS;
} else if (strcmp(name->cipher, AES_CBC) == 0) {
vbdev->cipher = AES_CBC;
vbdev->cipher_xform.cipher.key.data = vbdev->key;
vbdev->cipher_xform.cipher.key.length = key_size;
vbdev->cipher_xform.cipher.key.length = vbdev->key_size;
vbdev->cipher_xform.cipher.algo = RTE_CRYPTO_CIPHER_AES_CBC;
} else {
SPDK_ERRLOG("Invalid cipher name %s.\n", name->cipher);
@ -2158,12 +2219,12 @@ error_claim:
TAILQ_REMOVE(&g_vbdev_crypto, vbdev, link);
spdk_io_device_unregister(vbdev, NULL);
if (vbdev->xts_key) {
memset(vbdev->xts_key, 0, strlen(vbdev->xts_key));
memset(vbdev->xts_key, 0, vbdev->key_size + vbdev->key2_size);
free(vbdev->xts_key);
}
error_xts_key:
if (vbdev->key2) {
memset(vbdev->key2, 0, strlen(vbdev->key2));
memset(vbdev->key2, 0, vbdev->key2_size);
free(vbdev->key2);
}
error_alloc_key2:
@ -2172,7 +2233,7 @@ error_open:
free(vbdev->drv_name);
error_drv_name:
if (vbdev->key) {
memset(vbdev->key, 0, strlen(vbdev->key));
memset(vbdev->key, 0, vbdev->key_size);
free(vbdev->key);
}
error_alloc_key:
@ -2206,10 +2267,10 @@ delete_crypto_disk(struct spdk_bdev *bdev, spdk_delete_crypto_complete cb_fn,
free(name->bdev_name);
free(name->vbdev_name);
free(name->drv_name);
memset(name->key, 0, strlen(name->key));
memset(name->key, 0, name->key_size);
free(name->key);
if (name->key2) {
memset(name->key2, 0, strlen(name->key2));
memset(name->key2, 0, name->key2_size);
free(name->key2);
}
free(name);

View File

@ -3,6 +3,8 @@
*
* Copyright (c) Intel Corporation.
* All rights reserved.
* Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@ -77,4 +79,95 @@ int create_crypto_disk(const char *bdev_name, const char *vbdev_name,
void delete_crypto_disk(struct spdk_bdev *bdev, spdk_delete_crypto_complete cb_fn,
void *cb_arg);
static inline int
__c2v(char c)
{
if ((c >= '0') && (c <= '9')) {
return c - '0';
}
if ((c >= 'a') && (c <= 'f')) {
return c - 'a' + 10;
}
if ((c >= 'A') && (c <= 'F')) {
return c - 'A' + 10;
}
return -1;
}
static inline char
__v2c(int c)
{
const char hexchar[] = "0123456789abcdef";
if (c < 0 || c > 15) {
return -1;
}
return hexchar[c];
}
/**
* Convert a binary array to hexlified string terminated by zero.
*
* \param bin A binary array pointer.
* \param len Length of the binary array.
* \return Pointer to hexlified version of @bin or NULL on failure.
*/
static inline char *
hexlify(const char *bin, size_t len)
{
char *hex, *phex;
hex = malloc((len * 2) + 1);
if (hex == NULL) {
return NULL;
}
phex = hex;
for (size_t i = 0; i < len; i++) {
char c0 = __v2c((bin[i] >> 4) & 0x0f);
char c1 = __v2c((bin[i]) & 0x0f);
if (c0 < 0 || c1 < 0) {
assert(false);
free(hex);
return NULL;
}
*phex++ = c0;
*phex++ = c1;
}
*phex = '\0';
return hex;
}
/**
* Convert hexlified string to binary array of size strlen(hex) / 2.
*
* \param hex A hexlified string terminated by zero.
* \return Binary array pointer or NULL on failure.
*/
static inline char *
unhexlify(const char *hex)
{
char *res, *pres;
size_t len = strlen(hex);
if (len % 2 != 0) {
SPDK_ERRLOG("Invalid hex string len %d. It must be mod of 2.\n", (int)len);
return NULL;
}
res = malloc(len / 2);
if (res == NULL) {
return NULL;
}
pres = res;
for (size_t i = 0; i < len; i += 2) {
int v0 = __c2v(hex[i]);
int v1 = __c2v(hex[i + 1]);
if (v0 < 0 || v1 < 0) {
SPDK_ERRLOG("Invalid hex string \"%s\"\n", hex);
free(res);
return NULL;
}
*pres++ = (v0 << 4) + v1;
}
return res;
}
#endif /* SPDK_VBDEV_CRYPTO_H */

View File

@ -99,8 +99,8 @@ function setup_crypto_aesni_conf() {
"$rpc_py" <<- RPC
bdev_malloc_create -b Malloc0 16 512
bdev_malloc_create -b Malloc1 16 512
bdev_crypto_create Malloc0 crypto_ram crypto_aesni_mb 0123456789123456
bdev_crypto_create Malloc1 crypto_ram2 crypto_aesni_mb 9012345678912345
bdev_crypto_create Malloc0 crypto_ram crypto_aesni_mb 01234567891234560123456789123456
bdev_crypto_create Malloc1 crypto_ram2 crypto_aesni_mb 90123456789123459012345678912345
RPC
}
@ -110,8 +110,8 @@ function setup_crypto_qat_conf() {
"$rpc_py" <<- RPC
bdev_malloc_create -b Malloc0 16 512
bdev_malloc_create -b Malloc1 16 512
bdev_crypto_create Malloc0 crypto_ram crypto_qat 0123456789123456
bdev_crypto_create -c AES_XTS -k2 0123456789123456 Malloc1 crypto_ram3 crypto_qat 0123456789123456
bdev_crypto_create Malloc0 crypto_ram crypto_qat 01234567891234560123456789123456
bdev_crypto_create -c AES_XTS -k2 01234567891234560123456789123456 Malloc1 crypto_ram3 crypto_qat 01234567891234560123456789123456
bdev_get_bdevs -b Malloc1
RPC
}

View File

@ -203,7 +203,7 @@ function create_bdev_subsystem_config() {
local crypto_driver=crypto_qat
fi
tgt_rpc bdev_crypto_create MallocForCryptoBdev CryptoMallocBdev $crypto_driver 0123456789123456
tgt_rpc bdev_crypto_create MallocForCryptoBdev CryptoMallocBdev $crypto_driver 01234567891234560123456789123456
expected_notifications+=(
bdev_register:MallocForCryptoBdev
bdev_register:CryptoMallocBdev