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


Reply via email to