|
@@ -78,6 +78,67 @@ out:
|
|
|
return res;
|
|
|
}
|
|
|
|
|
|
+static int validate_user_key(struct fscrypt_info *crypt_info,
|
|
|
+ struct fscrypt_context *ctx, u8 *raw_key,
|
|
|
+ u8 *prefix, int prefix_size)
|
|
|
+{
|
|
|
+ u8 *full_key_descriptor;
|
|
|
+ struct key *keyring_key;
|
|
|
+ struct fscrypt_key *master_key;
|
|
|
+ const struct user_key_payload *ukp;
|
|
|
+ int full_key_len = prefix_size + (FS_KEY_DESCRIPTOR_SIZE * 2) + 1;
|
|
|
+ int res;
|
|
|
+
|
|
|
+ full_key_descriptor = kmalloc(full_key_len, GFP_NOFS);
|
|
|
+ if (!full_key_descriptor)
|
|
|
+ return -ENOMEM;
|
|
|
+
|
|
|
+ memcpy(full_key_descriptor, prefix, prefix_size);
|
|
|
+ sprintf(full_key_descriptor + prefix_size,
|
|
|
+ "%*phN", FS_KEY_DESCRIPTOR_SIZE,
|
|
|
+ ctx->master_key_descriptor);
|
|
|
+ full_key_descriptor[full_key_len - 1] = '\0';
|
|
|
+ keyring_key = request_key(&key_type_logon, full_key_descriptor, NULL);
|
|
|
+ kfree(full_key_descriptor);
|
|
|
+ if (IS_ERR(keyring_key))
|
|
|
+ return PTR_ERR(keyring_key);
|
|
|
+
|
|
|
+ if (keyring_key->type != &key_type_logon) {
|
|
|
+ printk_once(KERN_WARNING
|
|
|
+ "%s: key type must be logon\n", __func__);
|
|
|
+ res = -ENOKEY;
|
|
|
+ goto out;
|
|
|
+ }
|
|
|
+ down_read(&keyring_key->sem);
|
|
|
+ ukp = user_key_payload(keyring_key);
|
|
|
+ if (ukp->datalen != sizeof(struct fscrypt_key)) {
|
|
|
+ res = -EINVAL;
|
|
|
+ up_read(&keyring_key->sem);
|
|
|
+ goto out;
|
|
|
+ }
|
|
|
+ master_key = (struct fscrypt_key *)ukp->data;
|
|
|
+ BUILD_BUG_ON(FS_AES_128_ECB_KEY_SIZE != FS_KEY_DERIVATION_NONCE_SIZE);
|
|
|
+
|
|
|
+ if (master_key->size != FS_AES_256_XTS_KEY_SIZE) {
|
|
|
+ printk_once(KERN_WARNING
|
|
|
+ "%s: key size incorrect: %d\n",
|
|
|
+ __func__, master_key->size);
|
|
|
+ res = -ENOKEY;
|
|
|
+ up_read(&keyring_key->sem);
|
|
|
+ goto out;
|
|
|
+ }
|
|
|
+ res = derive_key_aes(ctx->nonce, master_key->raw, raw_key);
|
|
|
+ up_read(&keyring_key->sem);
|
|
|
+ if (res)
|
|
|
+ goto out;
|
|
|
+
|
|
|
+ crypt_info->ci_keyring_key = keyring_key;
|
|
|
+ return 0;
|
|
|
+out:
|
|
|
+ key_put(keyring_key);
|
|
|
+ return res;
|
|
|
+}
|
|
|
+
|
|
|
static void put_crypt_info(struct fscrypt_info *ci)
|
|
|
{
|
|
|
if (!ci)
|
|
@@ -91,12 +152,7 @@ static void put_crypt_info(struct fscrypt_info *ci)
|
|
|
int get_crypt_info(struct inode *inode)
|
|
|
{
|
|
|
struct fscrypt_info *crypt_info;
|
|
|
- u8 full_key_descriptor[FS_KEY_DESC_PREFIX_SIZE +
|
|
|
- (FS_KEY_DESCRIPTOR_SIZE * 2) + 1];
|
|
|
- struct key *keyring_key = NULL;
|
|
|
- struct fscrypt_key *master_key;
|
|
|
struct fscrypt_context ctx;
|
|
|
- const struct user_key_payload *ukp;
|
|
|
struct crypto_skcipher *ctfm;
|
|
|
const char *cipher_str;
|
|
|
u8 raw_key[FS_MAX_KEY_SIZE];
|
|
@@ -167,48 +223,24 @@ retry:
|
|
|
memset(raw_key, 0x42, FS_AES_256_XTS_KEY_SIZE);
|
|
|
goto got_key;
|
|
|
}
|
|
|
- memcpy(full_key_descriptor, FS_KEY_DESC_PREFIX,
|
|
|
- FS_KEY_DESC_PREFIX_SIZE);
|
|
|
- sprintf(full_key_descriptor + FS_KEY_DESC_PREFIX_SIZE,
|
|
|
- "%*phN", FS_KEY_DESCRIPTOR_SIZE,
|
|
|
- ctx.master_key_descriptor);
|
|
|
- full_key_descriptor[FS_KEY_DESC_PREFIX_SIZE +
|
|
|
- (2 * FS_KEY_DESCRIPTOR_SIZE)] = '\0';
|
|
|
- keyring_key = request_key(&key_type_logon, full_key_descriptor, NULL);
|
|
|
- if (IS_ERR(keyring_key)) {
|
|
|
- res = PTR_ERR(keyring_key);
|
|
|
- keyring_key = NULL;
|
|
|
- goto out;
|
|
|
- }
|
|
|
- crypt_info->ci_keyring_key = keyring_key;
|
|
|
- if (keyring_key->type != &key_type_logon) {
|
|
|
- printk_once(KERN_WARNING
|
|
|
- "%s: key type must be logon\n", __func__);
|
|
|
- res = -ENOKEY;
|
|
|
- goto out;
|
|
|
- }
|
|
|
- down_read(&keyring_key->sem);
|
|
|
- ukp = user_key_payload(keyring_key);
|
|
|
- if (ukp->datalen != sizeof(struct fscrypt_key)) {
|
|
|
- res = -EINVAL;
|
|
|
- up_read(&keyring_key->sem);
|
|
|
- goto out;
|
|
|
- }
|
|
|
- master_key = (struct fscrypt_key *)ukp->data;
|
|
|
- BUILD_BUG_ON(FS_AES_128_ECB_KEY_SIZE != FS_KEY_DERIVATION_NONCE_SIZE);
|
|
|
|
|
|
- if (master_key->size != FS_AES_256_XTS_KEY_SIZE) {
|
|
|
- printk_once(KERN_WARNING
|
|
|
- "%s: key size incorrect: %d\n",
|
|
|
- __func__, master_key->size);
|
|
|
- res = -ENOKEY;
|
|
|
- up_read(&keyring_key->sem);
|
|
|
+ res = validate_user_key(crypt_info, &ctx, raw_key,
|
|
|
+ FS_KEY_DESC_PREFIX, FS_KEY_DESC_PREFIX_SIZE);
|
|
|
+ if (res && inode->i_sb->s_cop->key_prefix) {
|
|
|
+ u8 *prefix = NULL;
|
|
|
+ int prefix_size, res2;
|
|
|
+
|
|
|
+ prefix_size = inode->i_sb->s_cop->key_prefix(inode, &prefix);
|
|
|
+ res2 = validate_user_key(crypt_info, &ctx, raw_key,
|
|
|
+ prefix, prefix_size);
|
|
|
+ if (res2) {
|
|
|
+ if (res2 == -ENOKEY)
|
|
|
+ res = -ENOKEY;
|
|
|
+ goto out;
|
|
|
+ }
|
|
|
+ } else if (res) {
|
|
|
goto out;
|
|
|
}
|
|
|
- res = derive_key_aes(ctx.nonce, master_key->raw, raw_key);
|
|
|
- up_read(&keyring_key->sem);
|
|
|
- if (res)
|
|
|
- goto out;
|
|
|
got_key:
|
|
|
ctfm = crypto_alloc_skcipher(cipher_str, 0, 0);
|
|
|
if (!ctfm || IS_ERR(ctfm)) {
|