blob: 1ac263eddc4ebc2fe3dacf746f370fbb1c158087 [file] [log] [blame]
Jaegeuk Kim0b81d072015-05-15 16:26:10 -07001/*
2 * key management facility for FS encryption support.
3 *
4 * Copyright (C) 2015, Google, Inc.
5 *
6 * This contains encryption key functions.
7 *
8 * Written by Michael Halcrow, Ildar Muslukhov, and Uday Savagaonkar, 2015.
9 */
10
11#include <keys/encrypted-type.h>
12#include <keys/user-type.h>
13#include <linux/random.h>
14#include <linux/scatterlist.h>
15#include <uapi/linux/keyctl.h>
Jaegeuk Kim0b81d072015-05-15 16:26:10 -070016#include <linux/fscrypto.h>
17
18static void derive_crypt_complete(struct crypto_async_request *req, int rc)
19{
20 struct fscrypt_completion_result *ecr = req->data;
21
22 if (rc == -EINPROGRESS)
23 return;
24
25 ecr->res = rc;
26 complete(&ecr->completion);
27}
28
29/**
30 * derive_key_aes() - Derive a key using AES-128-ECB
31 * @deriving_key: Encryption key used for derivation.
32 * @source_key: Source key to which to apply derivation.
33 * @derived_key: Derived key.
34 *
35 * Return: Zero on success; non-zero otherwise.
36 */
37static int derive_key_aes(u8 deriving_key[FS_AES_128_ECB_KEY_SIZE],
38 u8 source_key[FS_AES_256_XTS_KEY_SIZE],
39 u8 derived_key[FS_AES_256_XTS_KEY_SIZE])
40{
41 int res = 0;
Linus Torvaldsd4075742016-03-21 11:03:02 -070042 struct skcipher_request *req = NULL;
Jaegeuk Kim0b81d072015-05-15 16:26:10 -070043 DECLARE_FS_COMPLETION_RESULT(ecr);
44 struct scatterlist src_sg, dst_sg;
Linus Torvaldsd4075742016-03-21 11:03:02 -070045 struct crypto_skcipher *tfm = crypto_alloc_skcipher("ecb(aes)", 0, 0);
Jaegeuk Kim0b81d072015-05-15 16:26:10 -070046
47 if (IS_ERR(tfm)) {
48 res = PTR_ERR(tfm);
49 tfm = NULL;
50 goto out;
51 }
Linus Torvaldsd4075742016-03-21 11:03:02 -070052 crypto_skcipher_set_flags(tfm, CRYPTO_TFM_REQ_WEAK_KEY);
53 req = skcipher_request_alloc(tfm, GFP_NOFS);
Jaegeuk Kim0b81d072015-05-15 16:26:10 -070054 if (!req) {
55 res = -ENOMEM;
56 goto out;
57 }
Linus Torvaldsd4075742016-03-21 11:03:02 -070058 skcipher_request_set_callback(req,
Jaegeuk Kim0b81d072015-05-15 16:26:10 -070059 CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP,
60 derive_crypt_complete, &ecr);
Linus Torvaldsd4075742016-03-21 11:03:02 -070061 res = crypto_skcipher_setkey(tfm, deriving_key,
Jaegeuk Kim0b81d072015-05-15 16:26:10 -070062 FS_AES_128_ECB_KEY_SIZE);
63 if (res < 0)
64 goto out;
65
66 sg_init_one(&src_sg, source_key, FS_AES_256_XTS_KEY_SIZE);
67 sg_init_one(&dst_sg, derived_key, FS_AES_256_XTS_KEY_SIZE);
Linus Torvaldsd4075742016-03-21 11:03:02 -070068 skcipher_request_set_crypt(req, &src_sg, &dst_sg,
Jaegeuk Kim0b81d072015-05-15 16:26:10 -070069 FS_AES_256_XTS_KEY_SIZE, NULL);
Linus Torvaldsd4075742016-03-21 11:03:02 -070070 res = crypto_skcipher_encrypt(req);
Jaegeuk Kim0b81d072015-05-15 16:26:10 -070071 if (res == -EINPROGRESS || res == -EBUSY) {
72 wait_for_completion(&ecr.completion);
73 res = ecr.res;
74 }
75out:
Linus Torvaldsd4075742016-03-21 11:03:02 -070076 skcipher_request_free(req);
77 crypto_free_skcipher(tfm);
Jaegeuk Kim0b81d072015-05-15 16:26:10 -070078 return res;
79}
80
Jaegeuk Kimb5a7aef2016-05-04 22:05:01 -070081static int validate_user_key(struct fscrypt_info *crypt_info,
82 struct fscrypt_context *ctx, u8 *raw_key,
83 u8 *prefix, int prefix_size)
84{
85 u8 *full_key_descriptor;
86 struct key *keyring_key;
87 struct fscrypt_key *master_key;
88 const struct user_key_payload *ukp;
89 int full_key_len = prefix_size + (FS_KEY_DESCRIPTOR_SIZE * 2) + 1;
90 int res;
91
92 full_key_descriptor = kmalloc(full_key_len, GFP_NOFS);
93 if (!full_key_descriptor)
94 return -ENOMEM;
95
96 memcpy(full_key_descriptor, prefix, prefix_size);
97 sprintf(full_key_descriptor + prefix_size,
98 "%*phN", FS_KEY_DESCRIPTOR_SIZE,
99 ctx->master_key_descriptor);
100 full_key_descriptor[full_key_len - 1] = '\0';
101 keyring_key = request_key(&key_type_logon, full_key_descriptor, NULL);
102 kfree(full_key_descriptor);
103 if (IS_ERR(keyring_key))
104 return PTR_ERR(keyring_key);
105
106 if (keyring_key->type != &key_type_logon) {
107 printk_once(KERN_WARNING
108 "%s: key type must be logon\n", __func__);
109 res = -ENOKEY;
110 goto out;
111 }
112 down_read(&keyring_key->sem);
113 ukp = user_key_payload(keyring_key);
114 if (ukp->datalen != sizeof(struct fscrypt_key)) {
115 res = -EINVAL;
116 up_read(&keyring_key->sem);
117 goto out;
118 }
119 master_key = (struct fscrypt_key *)ukp->data;
120 BUILD_BUG_ON(FS_AES_128_ECB_KEY_SIZE != FS_KEY_DERIVATION_NONCE_SIZE);
121
122 if (master_key->size != FS_AES_256_XTS_KEY_SIZE) {
123 printk_once(KERN_WARNING
124 "%s: key size incorrect: %d\n",
125 __func__, master_key->size);
126 res = -ENOKEY;
127 up_read(&keyring_key->sem);
128 goto out;
129 }
130 res = derive_key_aes(ctx->nonce, master_key->raw, raw_key);
131 up_read(&keyring_key->sem);
132 if (res)
133 goto out;
134
135 crypt_info->ci_keyring_key = keyring_key;
136 return 0;
137out:
138 key_put(keyring_key);
139 return res;
140}
141
Jaegeuk Kim0b81d072015-05-15 16:26:10 -0700142static void put_crypt_info(struct fscrypt_info *ci)
143{
144 if (!ci)
145 return;
146
Linus Torvaldsd4075742016-03-21 11:03:02 -0700147 key_put(ci->ci_keyring_key);
148 crypto_free_skcipher(ci->ci_ctfm);
Jaegeuk Kim0b81d072015-05-15 16:26:10 -0700149 kmem_cache_free(fscrypt_info_cachep, ci);
150}
151
152int get_crypt_info(struct inode *inode)
153{
154 struct fscrypt_info *crypt_info;
Jaegeuk Kim0b81d072015-05-15 16:26:10 -0700155 struct fscrypt_context ctx;
Linus Torvaldsd4075742016-03-21 11:03:02 -0700156 struct crypto_skcipher *ctfm;
Jaegeuk Kim0b81d072015-05-15 16:26:10 -0700157 const char *cipher_str;
158 u8 raw_key[FS_MAX_KEY_SIZE];
159 u8 mode;
160 int res;
161
162 res = fscrypt_initialize();
163 if (res)
164 return res;
165
166 if (!inode->i_sb->s_cop->get_context)
167 return -EOPNOTSUPP;
168retry:
169 crypt_info = ACCESS_ONCE(inode->i_crypt_info);
170 if (crypt_info) {
171 if (!crypt_info->ci_keyring_key ||
172 key_validate(crypt_info->ci_keyring_key) == 0)
173 return 0;
174 fscrypt_put_encryption_info(inode, crypt_info);
175 goto retry;
176 }
177
178 res = inode->i_sb->s_cop->get_context(inode, &ctx, sizeof(ctx));
179 if (res < 0) {
180 if (!fscrypt_dummy_context_enabled(inode))
181 return res;
182 ctx.contents_encryption_mode = FS_ENCRYPTION_MODE_AES_256_XTS;
183 ctx.filenames_encryption_mode = FS_ENCRYPTION_MODE_AES_256_CTS;
184 ctx.flags = 0;
185 } else if (res != sizeof(ctx)) {
186 return -EINVAL;
187 }
188 res = 0;
189
190 crypt_info = kmem_cache_alloc(fscrypt_info_cachep, GFP_NOFS);
191 if (!crypt_info)
192 return -ENOMEM;
193
194 crypt_info->ci_flags = ctx.flags;
195 crypt_info->ci_data_mode = ctx.contents_encryption_mode;
196 crypt_info->ci_filename_mode = ctx.filenames_encryption_mode;
197 crypt_info->ci_ctfm = NULL;
198 crypt_info->ci_keyring_key = NULL;
199 memcpy(crypt_info->ci_master_key, ctx.master_key_descriptor,
200 sizeof(crypt_info->ci_master_key));
201 if (S_ISREG(inode->i_mode))
202 mode = crypt_info->ci_data_mode;
203 else if (S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode))
204 mode = crypt_info->ci_filename_mode;
205 else
206 BUG();
207
208 switch (mode) {
209 case FS_ENCRYPTION_MODE_AES_256_XTS:
210 cipher_str = "xts(aes)";
211 break;
212 case FS_ENCRYPTION_MODE_AES_256_CTS:
213 cipher_str = "cts(cbc(aes))";
214 break;
215 default:
216 printk_once(KERN_WARNING
217 "%s: unsupported key mode %d (ino %u)\n",
218 __func__, mode, (unsigned) inode->i_ino);
219 res = -ENOKEY;
220 goto out;
221 }
222 if (fscrypt_dummy_context_enabled(inode)) {
223 memset(raw_key, 0x42, FS_AES_256_XTS_KEY_SIZE);
224 goto got_key;
225 }
Jaegeuk Kim0b81d072015-05-15 16:26:10 -0700226
Jaegeuk Kimb5a7aef2016-05-04 22:05:01 -0700227 res = validate_user_key(crypt_info, &ctx, raw_key,
228 FS_KEY_DESC_PREFIX, FS_KEY_DESC_PREFIX_SIZE);
229 if (res && inode->i_sb->s_cop->key_prefix) {
230 u8 *prefix = NULL;
231 int prefix_size, res2;
232
233 prefix_size = inode->i_sb->s_cop->key_prefix(inode, &prefix);
234 res2 = validate_user_key(crypt_info, &ctx, raw_key,
235 prefix, prefix_size);
236 if (res2) {
237 if (res2 == -ENOKEY)
238 res = -ENOKEY;
239 goto out;
240 }
241 } else if (res) {
Jaegeuk Kim0b81d072015-05-15 16:26:10 -0700242 goto out;
243 }
Jaegeuk Kim0b81d072015-05-15 16:26:10 -0700244got_key:
Linus Torvaldsd4075742016-03-21 11:03:02 -0700245 ctfm = crypto_alloc_skcipher(cipher_str, 0, 0);
Jaegeuk Kim0b81d072015-05-15 16:26:10 -0700246 if (!ctfm || IS_ERR(ctfm)) {
247 res = ctfm ? PTR_ERR(ctfm) : -ENOMEM;
248 printk(KERN_DEBUG
249 "%s: error %d (inode %u) allocating crypto tfm\n",
250 __func__, res, (unsigned) inode->i_ino);
251 goto out;
252 }
253 crypt_info->ci_ctfm = ctfm;
Linus Torvaldsd4075742016-03-21 11:03:02 -0700254 crypto_skcipher_clear_flags(ctfm, ~0);
255 crypto_skcipher_set_flags(ctfm, CRYPTO_TFM_REQ_WEAK_KEY);
256 res = crypto_skcipher_setkey(ctfm, raw_key, fscrypt_key_size(mode));
Jaegeuk Kim0b81d072015-05-15 16:26:10 -0700257 if (res)
258 goto out;
259
260 memzero_explicit(raw_key, sizeof(raw_key));
261 if (cmpxchg(&inode->i_crypt_info, NULL, crypt_info) != NULL) {
262 put_crypt_info(crypt_info);
263 goto retry;
264 }
265 return 0;
266
267out:
268 if (res == -ENOKEY)
269 res = 0;
270 put_crypt_info(crypt_info);
271 memzero_explicit(raw_key, sizeof(raw_key));
272 return res;
273}
274
275void fscrypt_put_encryption_info(struct inode *inode, struct fscrypt_info *ci)
276{
277 struct fscrypt_info *prev;
278
279 if (ci == NULL)
280 ci = ACCESS_ONCE(inode->i_crypt_info);
281 if (ci == NULL)
282 return;
283
284 prev = cmpxchg(&inode->i_crypt_info, ci, NULL);
285 if (prev != ci)
286 return;
287
288 put_crypt_info(ci);
289}
290EXPORT_SYMBOL(fscrypt_put_encryption_info);
291
292int fscrypt_get_encryption_info(struct inode *inode)
293{
294 struct fscrypt_info *ci = inode->i_crypt_info;
295
296 if (!ci ||
297 (ci->ci_keyring_key &&
298 (ci->ci_keyring_key->flags & ((1 << KEY_FLAG_INVALIDATED) |
299 (1 << KEY_FLAG_REVOKED) |
300 (1 << KEY_FLAG_DEAD)))))
301 return get_crypt_info(inode);
302 return 0;
303}
304EXPORT_SYMBOL(fscrypt_get_encryption_info);