keyinfo.c 8.3 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
#include <keys/user-type.h>
#include <linux/scatterlist.h>
13
#include "fscrypt_private.h"
14 15 16

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

	if (rc == -EINPROGRESS)
		return;

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

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

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

63 64
	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);
65
	skcipher_request_set_crypt(req, &src_sg, &dst_sg,
66
					FS_AES_256_XTS_KEY_SIZE, NULL);
67
	res = crypto_skcipher_encrypt(req);
68 69 70 71 72
	if (res == -EINPROGRESS || res == -EBUSY) {
		wait_for_completion(&ecr.completion);
		res = ecr.res;
	}
out:
73 74
	skcipher_request_free(req);
	crypto_free_skcipher(tfm);
75 76 77
	return res;
}

78 79
static int validate_user_key(struct fscrypt_info *crypt_info,
			struct fscrypt_context *ctx, u8 *raw_key,
80
			const char *prefix)
81
{
82
	char *description;
83 84 85 86 87
	struct key *keyring_key;
	struct fscrypt_key *master_key;
	const struct user_key_payload *ukp;
	int res;

88 89 90 91
	description = kasprintf(GFP_NOFS, "%s%*phN", prefix,
				FS_KEY_DESCRIPTOR_SIZE,
				ctx->master_key_descriptor);
	if (!description)
92 93
		return -ENOMEM;

94 95
	keyring_key = request_key(&key_type_logon, description, NULL);
	kfree(description);
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
	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;
}

135 136 137 138 139 140 141 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
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;
}

167
static void put_crypt_info(struct fscrypt_info *ci)
168 169 170 171
{
	if (!ci)
		return;

172 173
	key_put(ci->ci_keyring_key);
	crypto_free_skcipher(ci->ci_ctfm);
174
	kmem_cache_free(fscrypt_info_cachep, ci);
175 176
}

177
int fscrypt_get_crypt_info(struct inode *inode)
178
{
179 180
	struct fscrypt_info *crypt_info;
	struct fscrypt_context ctx;
181
	struct crypto_skcipher *ctfm;
182
	const char *cipher_str;
183
	int keysize;
184
	u8 *raw_key = NULL;
185 186
	int res;

187
	res = fscrypt_initialize(inode->i_sb->s_cop->flags);
188 189
	if (res)
		return res;
190 191 192

	if (!inode->i_sb->s_cop->get_context)
		return -EOPNOTSUPP;
193
retry:
194
	crypt_info = ACCESS_ONCE(inode->i_crypt_info);
195 196 197
	if (crypt_info) {
		if (!crypt_info->ci_keyring_key ||
				key_validate(crypt_info->ci_keyring_key) == 0)
198
			return 0;
199
		fscrypt_put_encryption_info(inode, crypt_info);
200
		goto retry;
201 202
	}

203 204
	res = inode->i_sb->s_cop->get_context(inode, &ctx, sizeof(ctx));
	if (res < 0) {
205 206
		if (!fscrypt_dummy_context_enabled(inode) ||
		    inode->i_sb->s_cop->is_encrypted(inode))
207
			return res;
208 209
		/* Fake up a context for an unencrypted directory */
		memset(&ctx, 0, sizeof(ctx));
210
		ctx.format = FS_ENCRYPTION_CONTEXT_FORMAT_V1;
211 212
		ctx.contents_encryption_mode = FS_ENCRYPTION_MODE_AES_256_XTS;
		ctx.filenames_encryption_mode = FS_ENCRYPTION_MODE_AES_256_CTS;
213
		memset(ctx.master_key_descriptor, 0x42, FS_KEY_DESCRIPTOR_SIZE);
214
	} else if (res != sizeof(ctx)) {
215
		return -EINVAL;
216
	}
217 218 219 220 221 222

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

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

224
	crypt_info = kmem_cache_alloc(fscrypt_info_cachep, GFP_NOFS);
225 226 227 228 229 230 231
	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;
232
	crypt_info->ci_keyring_key = NULL;
233 234
	memcpy(crypt_info->ci_master_key, ctx.master_key_descriptor,
				sizeof(crypt_info->ci_master_key));
235

236 237
	res = determine_cipher_type(crypt_info, inode, &cipher_str, &keysize);
	if (res)
238
		goto out;
239

240 241 242 243 244 245 246 247 248
	/*
	 * This cannot be a stack buffer because it is passed to the scatterlist
	 * crypto API as part of key derivation.
	 */
	res = -ENOMEM;
	raw_key = kmalloc(FS_MAX_KEY_SIZE, GFP_NOFS);
	if (!raw_key)
		goto out;

249
	res = validate_user_key(crypt_info, &ctx, raw_key, FS_KEY_DESC_PREFIX);
250
	if (res && inode->i_sb->s_cop->key_prefix) {
251 252
		int res2 = validate_user_key(crypt_info, &ctx, raw_key,
					     inode->i_sb->s_cop->key_prefix);
253 254 255 256 257 258
		if (res2) {
			if (res2 == -ENOKEY)
				res = -ENOKEY;
			goto out;
		}
	} else if (res) {
259 260
		goto out;
	}
261
	ctfm = crypto_alloc_skcipher(cipher_str, 0, 0);
262 263 264 265 266 267
	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;
268
	}
269
	crypt_info->ci_ctfm = ctfm;
270 271
	crypto_skcipher_clear_flags(ctfm, ~0);
	crypto_skcipher_set_flags(ctfm, CRYPTO_TFM_REQ_WEAK_KEY);
272
	res = crypto_skcipher_setkey(ctfm, raw_key, keysize);
273 274 275
	if (res)
		goto out;

276 277
	kzfree(raw_key);
	raw_key = NULL;
278 279
	if (cmpxchg(&inode->i_crypt_info, NULL, crypt_info) != NULL) {
		put_crypt_info(crypt_info);
280 281 282 283 284
		goto retry;
	}
	return 0;

out:
285
	if (res == -ENOKEY)
286
		res = 0;
287
	put_crypt_info(crypt_info);
288
	kzfree(raw_key);
289 290 291
	return res;
}

292
void fscrypt_put_encryption_info(struct inode *inode, struct fscrypt_info *ci)
293
{
294 295 296 297 298 299
	struct fscrypt_info *prev;

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

301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317
	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)))))
318
		return fscrypt_get_crypt_info(inode);
319
	return 0;
320
}
321
EXPORT_SYMBOL(fscrypt_get_encryption_info);