keyinfo.c 8.4 KB
Newer Older
1
/*
2
 * key management facility for FS encryption support.
3 4 5
 *
 * Copyright (C) 2015, Google, Inc.
 *
6
 * This contains encryption key functions.
7 8 9
 *
 * Written by Michael Halcrow, Ildar Muslukhov, and Uday Savagaonkar, 2015.
 */
10

11 12 13 14 15
#include <keys/encrypted-type.h>
#include <keys/user-type.h>
#include <linux/random.h>
#include <linux/scatterlist.h>
#include <uapi/linux/keyctl.h>
16
#include <linux/fscrypto.h>
17 18 19

static void derive_crypt_complete(struct crypto_async_request *req, int rc)
{
20
	struct fscrypt_completion_result *ecr = req->data;
21 22 23 24 25 26 27 28 29

	if (rc == -EINPROGRESS)
		return;

	ecr->res = rc;
	complete(&ecr->completion);
}

/**
30
 * derive_key_aes() - Derive a key using AES-128-ECB
31
 * @deriving_key: Encryption key used for derivation.
32 33 34 35 36
 * @source_key:   Source key to which to apply derivation.
 * @derived_key:  Derived key.
 *
 * Return: Zero on success; non-zero otherwise.
 */
37 38 39
static int derive_key_aes(u8 deriving_key[FS_AES_128_ECB_KEY_SIZE],
				u8 source_key[FS_AES_256_XTS_KEY_SIZE],
				u8 derived_key[FS_AES_256_XTS_KEY_SIZE])
40 41
{
	int res = 0;
42
	struct skcipher_request *req = NULL;
43
	DECLARE_FS_COMPLETION_RESULT(ecr);
44
	struct scatterlist src_sg, dst_sg;
45
	struct crypto_skcipher *tfm = crypto_alloc_skcipher("ecb(aes)", 0, 0);
46 47 48 49 50 51

	if (IS_ERR(tfm)) {
		res = PTR_ERR(tfm);
		tfm = NULL;
		goto out;
	}
52 53
	crypto_skcipher_set_flags(tfm, CRYPTO_TFM_REQ_WEAK_KEY);
	req = skcipher_request_alloc(tfm, GFP_NOFS);
54 55 56 57
	if (!req) {
		res = -ENOMEM;
		goto out;
	}
58
	skcipher_request_set_callback(req,
59 60
			CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP,
			derive_crypt_complete, &ecr);
61
	res = crypto_skcipher_setkey(tfm, deriving_key,
62
					FS_AES_128_ECB_KEY_SIZE);
63 64 65
	if (res < 0)
		goto out;

66 67
	sg_init_one(&src_sg, source_key, FS_AES_256_XTS_KEY_SIZE);
	sg_init_one(&dst_sg, derived_key, FS_AES_256_XTS_KEY_SIZE);
68
	skcipher_request_set_crypt(req, &src_sg, &dst_sg,
69
					FS_AES_256_XTS_KEY_SIZE, NULL);
70
	res = crypto_skcipher_encrypt(req);
71 72 73 74 75
	if (res == -EINPROGRESS || res == -EBUSY) {
		wait_for_completion(&ecr.completion);
		res = ecr.res;
	}
out:
76 77
	skcipher_request_free(req);
	crypto_free_skcipher(tfm);
78 79 80
	return res;
}

81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141
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;
}

142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173
static int determine_cipher_type(struct fscrypt_info *ci, struct inode *inode,
				 const char **cipher_str_ret, int *keysize_ret)
{
	if (S_ISREG(inode->i_mode)) {
		if (ci->ci_data_mode == FS_ENCRYPTION_MODE_AES_256_XTS) {
			*cipher_str_ret = "xts(aes)";
			*keysize_ret = FS_AES_256_XTS_KEY_SIZE;
			return 0;
		}
		pr_warn_once("fscrypto: unsupported contents encryption mode "
			     "%d for inode %lu\n",
			     ci->ci_data_mode, inode->i_ino);
		return -ENOKEY;
	}

	if (S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode)) {
		if (ci->ci_filename_mode == FS_ENCRYPTION_MODE_AES_256_CTS) {
			*cipher_str_ret = "cts(cbc(aes))";
			*keysize_ret = FS_AES_256_CTS_KEY_SIZE;
			return 0;
		}
		pr_warn_once("fscrypto: unsupported filenames encryption mode "
			     "%d for inode %lu\n",
			     ci->ci_filename_mode, inode->i_ino);
		return -ENOKEY;
	}

	pr_warn_once("fscrypto: unsupported file type %d for inode %lu\n",
		     (inode->i_mode & S_IFMT), inode->i_ino);
	return -ENOKEY;
}

174
static void put_crypt_info(struct fscrypt_info *ci)
175 176 177 178
{
	if (!ci)
		return;

179 180
	key_put(ci->ci_keyring_key);
	crypto_free_skcipher(ci->ci_ctfm);
181
	kmem_cache_free(fscrypt_info_cachep, ci);
182 183
}

184
int get_crypt_info(struct inode *inode)
185
{
186 187
	struct fscrypt_info *crypt_info;
	struct fscrypt_context ctx;
188
	struct crypto_skcipher *ctfm;
189
	const char *cipher_str;
190
	int keysize;
191
	u8 raw_key[FS_MAX_KEY_SIZE];
192 193
	int res;

194
	res = fscrypt_initialize();
195 196
	if (res)
		return res;
197 198 199

	if (!inode->i_sb->s_cop->get_context)
		return -EOPNOTSUPP;
200
retry:
201
	crypt_info = ACCESS_ONCE(inode->i_crypt_info);
202 203 204
	if (crypt_info) {
		if (!crypt_info->ci_keyring_key ||
				key_validate(crypt_info->ci_keyring_key) == 0)
205
			return 0;
206
		fscrypt_put_encryption_info(inode, crypt_info);
207
		goto retry;
208 209
	}

210 211 212 213
	res = inode->i_sb->s_cop->get_context(inode, &ctx, sizeof(ctx));
	if (res < 0) {
		if (!fscrypt_dummy_context_enabled(inode))
			return res;
214
		ctx.format = FS_ENCRYPTION_CONTEXT_FORMAT_V1;
215 216 217 218
		ctx.contents_encryption_mode = FS_ENCRYPTION_MODE_AES_256_XTS;
		ctx.filenames_encryption_mode = FS_ENCRYPTION_MODE_AES_256_CTS;
		ctx.flags = 0;
	} else if (res != sizeof(ctx)) {
219
		return -EINVAL;
220
	}
221 222 223 224 225 226

	if (ctx.format != FS_ENCRYPTION_CONTEXT_FORMAT_V1)
		return -EINVAL;

	if (ctx.flags & ~FS_POLICY_FLAGS_VALID)
		return -EINVAL;
227

228
	crypt_info = kmem_cache_alloc(fscrypt_info_cachep, GFP_NOFS);
229 230 231 232 233 234 235
	if (!crypt_info)
		return -ENOMEM;

	crypt_info->ci_flags = ctx.flags;
	crypt_info->ci_data_mode = ctx.contents_encryption_mode;
	crypt_info->ci_filename_mode = ctx.filenames_encryption_mode;
	crypt_info->ci_ctfm = NULL;
236
	crypt_info->ci_keyring_key = NULL;
237 238
	memcpy(crypt_info->ci_master_key, ctx.master_key_descriptor,
				sizeof(crypt_info->ci_master_key));
239

240 241
	res = determine_cipher_type(crypt_info, inode, &cipher_str, &keysize);
	if (res)
242
		goto out;
243

244 245 246 247 248
	if (fscrypt_dummy_context_enabled(inode)) {
		memset(raw_key, 0x42, FS_AES_256_XTS_KEY_SIZE);
		goto got_key;
	}

249 250 251 252 253 254 255 256 257 258 259 260 261 262 263
	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) {
264 265
		goto out;
	}
266
got_key:
267
	ctfm = crypto_alloc_skcipher(cipher_str, 0, 0);
268 269 270 271 272 273
	if (!ctfm || IS_ERR(ctfm)) {
		res = ctfm ? PTR_ERR(ctfm) : -ENOMEM;
		printk(KERN_DEBUG
		       "%s: error %d (inode %u) allocating crypto tfm\n",
		       __func__, res, (unsigned) inode->i_ino);
		goto out;
274
	}
275
	crypt_info->ci_ctfm = ctfm;
276 277
	crypto_skcipher_clear_flags(ctfm, ~0);
	crypto_skcipher_set_flags(ctfm, CRYPTO_TFM_REQ_WEAK_KEY);
278
	res = crypto_skcipher_setkey(ctfm, raw_key, keysize);
279 280 281 282
	if (res)
		goto out;

	memzero_explicit(raw_key, sizeof(raw_key));
283 284
	if (cmpxchg(&inode->i_crypt_info, NULL, crypt_info) != NULL) {
		put_crypt_info(crypt_info);
285 286 287 288 289
		goto retry;
	}
	return 0;

out:
290
	if (res == -ENOKEY)
291
		res = 0;
292
	put_crypt_info(crypt_info);
293
	memzero_explicit(raw_key, sizeof(raw_key));
294 295 296
	return res;
}

297
void fscrypt_put_encryption_info(struct inode *inode, struct fscrypt_info *ci)
298
{
299 300 301 302 303 304
	struct fscrypt_info *prev;

	if (ci == NULL)
		ci = ACCESS_ONCE(inode->i_crypt_info);
	if (ci == NULL)
		return;
305

306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324
	prev = cmpxchg(&inode->i_crypt_info, ci, NULL);
	if (prev != ci)
		return;

	put_crypt_info(ci);
}
EXPORT_SYMBOL(fscrypt_put_encryption_info);

int fscrypt_get_encryption_info(struct inode *inode)
{
	struct fscrypt_info *ci = inode->i_crypt_info;

	if (!ci ||
		(ci->ci_keyring_key &&
		 (ci->ci_keyring_key->flags & ((1 << KEY_FLAG_INVALIDATED) |
					       (1 << KEY_FLAG_REVOKED) |
					       (1 << KEY_FLAG_DEAD)))))
		return get_crypt_info(inode);
	return 0;
325
}
326
EXPORT_SYMBOL(fscrypt_get_encryption_info);