Skip to content

Commit

Permalink
fscrypt: support encrypted and trusted keys
Browse files Browse the repository at this point in the history
For both v1 and v2 key setup mechanisms, userspace supplies the raw key
material to the kernel after which it is never again disclosed to
userspace.

Use of encrypted and trusted keys offers stronger guarantees:
The key material is generated within the kernel and is never disclosed to
userspace in clear text and, in the case of trusted keys, can be
directly rooted to a trust source like a TPM chip.

Add support for trusted and encrypted keys by repurposing
fscrypt_add_key_arg::raw to hold the key description when the new
FSCRYPT_KEY_ARG_TYPE_DESC flag is supplied. The location of the flag
was previously reserved and enforced by ioctl code to be zero, so this
change won't break backwards compatibility.

Corresponding userspace patches are available for fscryptctl:
google/fscryptctl#23

Signed-off-by: Ahmad Fatoum <[email protected]>
  • Loading branch information
a3f authored and intel-lab-lkp committed Jul 27, 2021
1 parent 349a2d5 commit c945f8d
Show file tree
Hide file tree
Showing 3 changed files with 87 additions and 12 deletions.
24 changes: 19 additions & 5 deletions Documentation/filesystems/fscrypt.rst
Original file line number Diff line number Diff line change
Expand Up @@ -681,11 +681,15 @@ It can be executed on any file or directory on the target filesystem,
but using the filesystem's root directory is recommended. It takes in
a pointer to struct fscrypt_add_key_arg, defined as follows::

#define FSCRYPT_KEY_ADD_RAW_ASIS 0
#define FSCRYPT_KEY_ADD_RAW_DESC 1

struct fscrypt_add_key_arg {
struct fscrypt_key_specifier key_spec;
__u32 raw_size;
__u32 key_id;
__u32 __reserved[8];
__u32 raw_flags; /* one of FSCRYPT_KEY_ADD_RAW_* */
__u32 __reserved[7];
__u8 raw[];
};

Expand Down Expand Up @@ -732,8 +736,11 @@ as follows:
Alternatively, if ``key_id`` is nonzero, this field must be 0, since
in that case the size is implied by the specified Linux keyring key.

- ``key_id`` is 0 if the raw key is given directly in the ``raw``
field. Otherwise ``key_id`` is the ID of a Linux keyring key of
- If ``key_id`` is 0, the raw key is given directly in the ``raw``
field if ``raw_flags == FSCRYPT_KEY_ADD_RAW_ASIS``. With
``raw_flags == FSCRYPT_KEY_ADD_RAW_DESC``, ``raw`` is instead
interpreted as the description of an encrypted or trusted key.
Otherwise ``key_id`` is the ID of a Linux keyring key of
type "fscrypt-provisioning" whose payload is
struct fscrypt_provisioning_key_payload whose ``raw`` field contains
the raw key and whose ``type`` field matches ``key_spec.type``.
Expand All @@ -748,8 +755,15 @@ as follows:
without having to store the raw keys in userspace memory.

- ``raw`` is a variable-length field which must contain the actual
key, ``raw_size`` bytes long. Alternatively, if ``key_id`` is
nonzero, then this field is unused.
key when ``raw_flags == FSCRYPT_KEY_ADD_RAW_ASIS``,
``raw_size`` bytes long. Alternatively, if
``raw_flags == FSCRYPT_KEY_ADD_RAW_DESC``, ``raw`` is interpreted
as the key description of an encrypted or trusted key, in that order.
The material of this key will be used as if it were a raw key
supplied by userspace.

In both cases, the buffer is ``raw_size`` bytes long. If ````key_id``
is nonzero, then this field is unused.

For v2 policy keys, the kernel keeps track of which user (identified
by effective user ID) added the key, and only allows the key to be
Expand Down
59 changes: 53 additions & 6 deletions fs/crypto/keyring.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@

#include <crypto/skcipher.h>
#include <linux/key-type.h>
#include <linux/key-type.h>
#include <keys/encrypted-type.h>
#include <keys/trusted-type.h>
#include <linux/random.h>
#include <linux/seq_file.h>

Expand Down Expand Up @@ -662,13 +665,57 @@ int fscrypt_ioctl_add_key(struct file *filp, void __user *_uarg)
if (err)
goto out_wipe_secret;
} else {
if (arg.raw_size < FSCRYPT_MIN_KEY_SIZE ||
arg.raw_size > FSCRYPT_MAX_KEY_SIZE)
struct key *keyring_key = ERR_PTR(-EINVAL);
const void *key_material;
const char *desc;

switch (arg.raw_flags) {
case FSCRYPT_KEY_ADD_RAW_ASIS:
if (arg.raw_size < FSCRYPT_MIN_KEY_SIZE ||
arg.raw_size > FSCRYPT_MAX_KEY_SIZE)
return -EINVAL;
secret.size = arg.raw_size;
err = -EFAULT;
if (copy_from_user(secret.raw, uarg->raw, secret.size))
goto out_wipe_secret;
break;
case FSCRYPT_KEY_ADD_RAW_DESC:
if (arg.raw_size > 4096)
return -EINVAL;
desc = memdup_user_nul(uarg->raw, arg.raw_size);
if (IS_ERR(desc))
return PTR_ERR(desc);

if (IS_REACHABLE(CONFIG_ENCRYPTED_KEYS))
keyring_key = request_key(&key_type_encrypted, desc, NULL);
if (IS_REACHABLE(CONFIG_TRUSTED_KEYS) && IS_ERR(keyring_key))
keyring_key = request_key(&key_type_trusted, desc, NULL);

kfree(desc);

if (IS_ERR(keyring_key))
return PTR_ERR(keyring_key);

down_read(&keyring_key->sem);

key_material = key_extract_material(keyring_key, &secret.size);
if (!IS_ERR(key_material) && (secret.size < FSCRYPT_MIN_KEY_SIZE ||
secret.size > FSCRYPT_MAX_KEY_SIZE))
key_material = ERR_PTR(-EINVAL);
if (IS_ERR(key_material)) {
up_read(&keyring_key->sem);
key_put(keyring_key);
return PTR_ERR(key_material);
}

memcpy(secret.raw, key_material, secret.size);

up_read(&keyring_key->sem);
key_put(keyring_key);
break;
default:
return -EINVAL;
secret.size = arg.raw_size;
err = -EFAULT;
if (copy_from_user(secret.raw, uarg->raw, secret.size))
goto out_wipe_secret;
}
}

err = add_master_key(sb, &secret, &arg.key_spec);
Expand Down
16 changes: 15 additions & 1 deletion include/uapi/linux/fscrypt.h
Original file line number Diff line number Diff line change
Expand Up @@ -119,12 +119,26 @@ struct fscrypt_provisioning_key_payload {
__u8 raw[];
};

/*
* fscrypt_add_key_arg::raw contains the raw key material directly
* if key_id == 0
*/
#define FSCRYPT_KEY_ADD_RAW_ASIS 0

/*
* fscrypt_add_key_arg::raw is a key descriptor for an already
* existing kernel encrypted or trusted key if key_id == 0.
* The kernel key's material will be used as input for fscrypt.
*/
#define FSCRYPT_KEY_ADD_RAW_DESC 1

/* Struct passed to FS_IOC_ADD_ENCRYPTION_KEY */
struct fscrypt_add_key_arg {
struct fscrypt_key_specifier key_spec;
__u32 raw_size;
__u32 key_id;
__u32 __reserved[8];
__u32 raw_flags; /* one of FSCRYPT_KEY_ADD_RAW_* */
__u32 __reserved[7];
__u8 raw[];
};

Expand Down

0 comments on commit c945f8d

Please sign in to comment.