Add support for hardware-wrapped encryption keys to the dm-inlinecrypt target.
Introduce a new parameter <is_wrappedkey> to indicate whether the provided key is a raw key or a hardware-wrapped key. Based on this flag, the appropriate blk-crypto key type is selected when initializing the key. This allows dm-inlinecrypt to work with hardware that requires keys to be wrapped and managed by the underlying inline encryption engine. Update the target argument parsing accordingly and pass the key type to blk_crypto_init_key(). Documentation is also updated to reflect the new parameter and usage. Signed-off-by: Linlin Zhang <[email protected]> --- .../device-mapper/dm-inlinecrypt.rst | 10 ++- drivers/md/dm-inlinecrypt.c | 71 +++++++++++-------- 2 files changed, 50 insertions(+), 31 deletions(-) diff --git a/Documentation/admin-guide/device-mapper/dm-inlinecrypt.rst b/Documentation/admin-guide/device-mapper/dm-inlinecrypt.rst index c71e600efb76..3a4ce2c5f228 100644 --- a/Documentation/admin-guide/device-mapper/dm-inlinecrypt.rst +++ b/Documentation/admin-guide/device-mapper/dm-inlinecrypt.rst @@ -10,7 +10,7 @@ https://docs.kernel.org/block/inline-encryption.html Parameters:: - <cipher> <key> <iv_offset> <device path> \ + <cipher> <key> <is_wrappedkey> <iv_offset> <device path> \ <offset> [<#opt_params> <opt_params>] <cipher> @@ -52,6 +52,10 @@ Parameters:: The kernel keyring key description inlinecrypt target should look for when loading key of <key_type>. +<is_wrappedkey> + The flag used to imply if the key is hardware-wrapped or not. + '0' means a raw key and '1' means a wrapped key. + <iv_offset> The IV offset is a sector count that is added to the sector number before creating the IV. @@ -113,11 +117,11 @@ using dmsetup #!/bin/sh # Create a inlinecrypt device using dmsetup - dmsetup create inlinecrypt1 --table "0 `blockdev --getsz $1` inlinecrypt aes-xts-plain64 babebabebabebabebabebabebabebabebabebabebabebabebabebabebabebabe 0 $1 0" + dmsetup create inlinecrypt1 --table "0 `blockdev --getsz $1` inlinecrypt aes-xts-plain64 babebabebabebabebabebabebabebabebabebabebabebabebabebabebabebabe 0 0 $1 0" :: #!/bin/sh # Create a inlinecrypt device using dmsetup when encryption key is stored in keyring service - dmsetup create inlinecrypt2 --table "0 `blockdev --getsz $1` inlinecrypt aes-xts-plain64 :64:logon:fde:dminlinecrypt_test_key 0 $1 0" + dmsetup create inlinecrypt2 --table "0 `blockdev --getsz $1` inlinecrypt aes-xts-plain64 :64:logon:fde:dminlinecrypt_test_key 0 0 $1 0" diff --git a/drivers/md/dm-inlinecrypt.c b/drivers/md/dm-inlinecrypt.c index bd8e58a028c5..4e49edea59cf 100644 --- a/drivers/md/dm-inlinecrypt.c +++ b/drivers/md/dm-inlinecrypt.c @@ -29,6 +29,7 @@ static const struct dm_inlinecrypt_cipher { * For this purpose a "sector" is 512 bytes. * @cipher_string: the name of the encryption algorithm being used * @key_size: size of the encryption key in bytes + * @is_hw_wrapped: true if the key is a hardware-wrapped key, false for a raw key. * @iv_offset: starting offset for IVs. IVs are generated as if the target were * preceded by @iv_offset 512-byte sectors. * @sector_size: crypto sector size in bytes (usually 4096) @@ -41,6 +42,7 @@ struct inlinecrypt_ctx { sector_t start; const char *cipher_string; unsigned int key_size; + bool is_hw_wrapped; u64 iv_offset; unsigned int sector_size; unsigned int sector_bits; @@ -83,8 +85,8 @@ static bool contains_whitespace(const char *str) return false; } -static int set_key_user(struct key *key, char *bin_key, - const unsigned int bin_key_size) +static int set_key_user(struct key *key, char *key_bytes, + const unsigned int key_bytes_size) { const struct user_key_payload *ukp; @@ -92,23 +94,23 @@ static int set_key_user(struct key *key, char *bin_key, if (!ukp) return -EKEYREVOKED; - if (bin_key_size != ukp->datalen) + if (key_bytes_size != ukp->datalen) return -EINVAL; - memcpy(bin_key, ukp->data, bin_key_size); + memcpy(key_bytes, ukp->data, key_bytes_size); return 0; } -static int inlinecrypt_get_keyring_key(const char *key_string, u8 *bin_key, - const unsigned int bin_key_size) +static int inlinecrypt_get_keyring_key(const char *key_string, u8 *key_bytes, + const unsigned int key_bytes_size) { char *key_desc; int ret; struct key_type *type; struct key *key; - int (*set_key)(struct key *key, char *bin_key, - const unsigned int bin_key_size); + int (*set_key)(struct key *key, char *key_bytes, + const unsigned int key_bytes_size); /* * Reject key_string with whitespace. dm core currently lacks code for @@ -137,7 +139,7 @@ static int inlinecrypt_get_keyring_key(const char *key_string, u8 *bin_key, down_read(&key->sem); - ret = set_key(key, (char *)bin_key, bin_key_size); + ret = set_key(key, (char *)key_bytes, key_bytes_size); up_read(&key->sem); key_put(key); @@ -178,8 +180,8 @@ static int get_key_size(char **key_string) #else -static int inlinecrypt_get_keyring_key(const char *key_string, u8 *bin_key, - const unsigned int bin_key_size) +static int inlinecrypt_get_keyring_key(const char *key_string, u8 *key_bytes, + const unsigned int key_bytes_size) { return -EINVAL; } @@ -284,7 +286,7 @@ static int inlinecrypt_ctr_optional(struct dm_target *ti, /* * Construct an inlinecrypt mapping: - * <cipher> [<key>|:<key_size>:<logon>:<key_description>] <iv_offset> <dev_path> <start> + * <cipher> [<key>|:<key_size>:<logon>:<key_description>] <is_wrappedkey> <iv_offset> <dev_path> <start> * * This syntax matches dm-crypt's, but the set of supported functionality has * been stripped down. @@ -293,13 +295,14 @@ static int inlinecrypt_ctr(struct dm_target *ti, unsigned int argc, char **argv) { struct inlinecrypt_ctx *ctx; const struct dm_inlinecrypt_cipher *cipher; - u8 raw_key[BLK_CRYPTO_MAX_ANY_KEY_SIZE]; + u8 key_bytes[BLK_CRYPTO_MAX_ANY_KEY_SIZE]; + enum blk_crypto_key_type key_type; unsigned int dun_bytes; unsigned long long tmpll; char dummy; int err; - if (argc < 5) { + if (argc < 6) { ti->error = "Not enough arguments"; return -EINVAL; } @@ -333,21 +336,33 @@ static int inlinecrypt_ctr(struct dm_target *ti, unsigned int argc, char **argv) } ctx->key_size = err; - err = inlinecrypt_get_key(argv[1], raw_key, ctx->key_size); + err = inlinecrypt_get_key(argv[1], key_bytes, ctx->key_size); if (err) { ti->error = "Malformed key string"; goto bad; } + /* <is_wrappedkey> */ + if (sscanf(argv[2], "%d%c", &err, &dummy) != 1 || + (err != 0 && err != 1)) { + ti->error = "Invalid is_wrappedkey flag"; + err = -EINVAL; + goto bad; + } + ctx->is_hw_wrapped = err; + key_type = ctx->is_hw_wrapped ? + BLK_CRYPTO_KEY_TYPE_HW_WRAPPED : + BLK_CRYPTO_KEY_TYPE_RAW; + /* <iv_offset> */ - if (sscanf(argv[2], "%llu%c", &ctx->iv_offset, &dummy) != 1) { + if (sscanf(argv[3], "%llu%c", &ctx->iv_offset, &dummy) != 1) { ti->error = "Invalid iv_offset sector"; err = -EINVAL; goto bad; } /* <dev_path> */ - err = dm_get_device(ti, argv[3], dm_table_get_mode(ti->table), + err = dm_get_device(ti, argv[4], dm_table_get_mode(ti->table), &ctx->dev); if (err) { ti->error = "Device lookup failed"; @@ -355,7 +370,7 @@ static int inlinecrypt_ctr(struct dm_target *ti, unsigned int argc, char **argv) } /* <start> */ - if (sscanf(argv[4], "%llu%c", &tmpll, &dummy) != 1 || + if (sscanf(argv[5], "%llu%c", &tmpll, &dummy) != 1 || tmpll != (sector_t)tmpll) { ti->error = "Invalid start sector"; err = -EINVAL; @@ -365,8 +380,8 @@ static int inlinecrypt_ctr(struct dm_target *ti, unsigned int argc, char **argv) /* optional arguments */ ctx->sector_size = SECTOR_SIZE; - if (argc > 5) { - err = inlinecrypt_ctr_optional(ti, argc - 5, &argv[5]); + if (argc > 6) { + err = inlinecrypt_ctr_optional(ti, argc - 6, &argv[6]); if (err) goto bad; } @@ -385,10 +400,9 @@ static int inlinecrypt_ctr(struct dm_target *ti, unsigned int argc, char **argv) (ctx->sector_bits - SECTOR_SHIFT); dun_bytes = DIV_ROUND_UP(fls64(ctx->max_dun), 8); - err = blk_crypto_init_key(&ctx->key, raw_key, ctx->key_size, - BLK_CRYPTO_KEY_TYPE_RAW, - cipher->mode_num, dun_bytes, - ctx->sector_size); + err = blk_crypto_init_key(&ctx->key, key_bytes, ctx->key_size, + key_type, cipher->mode_num, + dun_bytes, ctx->sector_size); if (err) { ti->error = "Error initializing blk-crypto key"; goto bad; @@ -408,7 +422,7 @@ static int inlinecrypt_ctr(struct dm_target *ti, unsigned int argc, char **argv) bad: inlinecrypt_dtr(ti); out: - memzero_explicit(raw_key, sizeof(raw_key)); + memzero_explicit(key_bytes, sizeof(key_bytes)); return err; } @@ -502,9 +516,10 @@ static void inlinecrypt_status(struct dm_target *ti, status_type_t type, * the returned table. Userspace is responsible for redacting * the key when needed. */ - DMEMIT("%s %*phN %llu %s %llu", ctx->cipher_string, - ctx->key.size, ctx->key.bytes, ctx->iv_offset, - ctx->dev->name, ctx->start); + DMEMIT("%s %*phN %u %llu %s %llu", ctx->cipher_string, + ctx->key.size, ctx->key.bytes, + ctx->is_hw_wrapped ? 1 : 0, + ctx->iv_offset, ctx->dev->name, ctx->start); num_feature_args += !!ti->num_discard_bios; if (ctx->sector_size != SECTOR_SIZE) num_feature_args += 2; -- 2.34.1

