]>
Commit | Line | Data |
---|---|---|
b2441318 | 1 | // SPDX-License-Identifier: GPL-2.0 |
0adda907 | 2 | /* |
0b81d077 | 3 | * key management facility for FS encryption support. |
0adda907 JK |
4 | * |
5 | * Copyright (C) 2015, Google, Inc. | |
6 | * | |
0b81d077 | 7 | * This contains encryption key functions. |
0adda907 JK |
8 | * |
9 | * Written by Michael Halcrow, Ildar Muslukhov, and Uday Savagaonkar, 2015. | |
10 | */ | |
0b81d077 | 11 | |
0adda907 | 12 | #include <keys/user-type.h> |
0adda907 | 13 | #include <linux/scatterlist.h> |
b7e7cf7a DW |
14 | #include <linux/ratelimit.h> |
15 | #include <crypto/aes.h> | |
16 | #include <crypto/sha.h> | |
3325bea5 | 17 | #include "fscrypt_private.h" |
0adda907 | 18 | |
b7e7cf7a DW |
19 | static struct crypto_shash *essiv_hash_tfm; |
20 | ||
0adda907 | 21 | /** |
0b81d077 | 22 | * derive_key_aes() - Derive a key using AES-128-ECB |
0fac2d50 | 23 | * @deriving_key: Encryption key used for derivation. |
0adda907 | 24 | * @source_key: Source key to which to apply derivation. |
b7e7cf7a | 25 | * @derived_raw_key: Derived raw key. |
0adda907 JK |
26 | * |
27 | * Return: Zero on success; non-zero otherwise. | |
28 | */ | |
0b81d077 | 29 | static int derive_key_aes(u8 deriving_key[FS_AES_128_ECB_KEY_SIZE], |
b7e7cf7a DW |
30 | const struct fscrypt_key *source_key, |
31 | u8 derived_raw_key[FS_MAX_KEY_SIZE]) | |
0adda907 JK |
32 | { |
33 | int res = 0; | |
d407574e | 34 | struct skcipher_request *req = NULL; |
d0082e1a | 35 | DECLARE_CRYPTO_WAIT(wait); |
0adda907 | 36 | struct scatterlist src_sg, dst_sg; |
d407574e | 37 | struct crypto_skcipher *tfm = crypto_alloc_skcipher("ecb(aes)", 0, 0); |
0adda907 JK |
38 | |
39 | if (IS_ERR(tfm)) { | |
40 | res = PTR_ERR(tfm); | |
41 | tfm = NULL; | |
42 | goto out; | |
43 | } | |
d407574e LT |
44 | crypto_skcipher_set_flags(tfm, CRYPTO_TFM_REQ_WEAK_KEY); |
45 | req = skcipher_request_alloc(tfm, GFP_NOFS); | |
0adda907 JK |
46 | if (!req) { |
47 | res = -ENOMEM; | |
48 | goto out; | |
49 | } | |
d407574e | 50 | skcipher_request_set_callback(req, |
0adda907 | 51 | CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP, |
d0082e1a | 52 | crypto_req_done, &wait); |
d407574e | 53 | res = crypto_skcipher_setkey(tfm, deriving_key, |
0b81d077 | 54 | FS_AES_128_ECB_KEY_SIZE); |
0adda907 JK |
55 | if (res < 0) |
56 | goto out; | |
57 | ||
b7e7cf7a DW |
58 | sg_init_one(&src_sg, source_key->raw, source_key->size); |
59 | sg_init_one(&dst_sg, derived_raw_key, source_key->size); | |
60 | skcipher_request_set_crypt(req, &src_sg, &dst_sg, source_key->size, | |
61 | NULL); | |
d0082e1a | 62 | res = crypto_wait_req(crypto_skcipher_encrypt(req), &wait); |
0adda907 | 63 | out: |
d407574e LT |
64 | skcipher_request_free(req); |
65 | crypto_free_skcipher(tfm); | |
0adda907 JK |
66 | return res; |
67 | } | |
68 | ||
b5a7aef1 JK |
69 | static int validate_user_key(struct fscrypt_info *crypt_info, |
70 | struct fscrypt_context *ctx, u8 *raw_key, | |
b7e7cf7a | 71 | const char *prefix, int min_keysize) |
b5a7aef1 | 72 | { |
a5d431ef | 73 | char *description; |
b5a7aef1 JK |
74 | struct key *keyring_key; |
75 | struct fscrypt_key *master_key; | |
76 | const struct user_key_payload *ukp; | |
b5a7aef1 JK |
77 | int res; |
78 | ||
a5d431ef EB |
79 | description = kasprintf(GFP_NOFS, "%s%*phN", prefix, |
80 | FS_KEY_DESCRIPTOR_SIZE, | |
81 | ctx->master_key_descriptor); | |
82 | if (!description) | |
b5a7aef1 JK |
83 | return -ENOMEM; |
84 | ||
a5d431ef EB |
85 | keyring_key = request_key(&key_type_logon, description, NULL); |
86 | kfree(description); | |
b5a7aef1 JK |
87 | if (IS_ERR(keyring_key)) |
88 | return PTR_ERR(keyring_key); | |
1b53cf98 | 89 | down_read(&keyring_key->sem); |
b5a7aef1 JK |
90 | |
91 | if (keyring_key->type != &key_type_logon) { | |
92 | printk_once(KERN_WARNING | |
93 | "%s: key type must be logon\n", __func__); | |
94 | res = -ENOKEY; | |
95 | goto out; | |
96 | } | |
0837e49a | 97 | ukp = user_key_payload_locked(keyring_key); |
d60b5b78 EB |
98 | if (!ukp) { |
99 | /* key was revoked before we acquired its semaphore */ | |
100 | res = -EKEYREVOKED; | |
101 | goto out; | |
102 | } | |
b5a7aef1 JK |
103 | if (ukp->datalen != sizeof(struct fscrypt_key)) { |
104 | res = -EINVAL; | |
b5a7aef1 JK |
105 | goto out; |
106 | } | |
107 | master_key = (struct fscrypt_key *)ukp->data; | |
108 | BUILD_BUG_ON(FS_AES_128_ECB_KEY_SIZE != FS_KEY_DERIVATION_NONCE_SIZE); | |
109 | ||
b7e7cf7a DW |
110 | if (master_key->size < min_keysize || master_key->size > FS_MAX_KEY_SIZE |
111 | || master_key->size % AES_BLOCK_SIZE != 0) { | |
b5a7aef1 JK |
112 | printk_once(KERN_WARNING |
113 | "%s: key size incorrect: %d\n", | |
114 | __func__, master_key->size); | |
115 | res = -ENOKEY; | |
b5a7aef1 JK |
116 | goto out; |
117 | } | |
b7e7cf7a | 118 | res = derive_key_aes(ctx->nonce, master_key, raw_key); |
b5a7aef1 | 119 | out: |
1b53cf98 | 120 | up_read(&keyring_key->sem); |
b5a7aef1 JK |
121 | key_put(keyring_key); |
122 | return res; | |
123 | } | |
124 | ||
b7e7cf7a DW |
125 | static const struct { |
126 | const char *cipher_str; | |
127 | int keysize; | |
128 | } available_modes[] = { | |
129 | [FS_ENCRYPTION_MODE_AES_256_XTS] = { "xts(aes)", | |
130 | FS_AES_256_XTS_KEY_SIZE }, | |
131 | [FS_ENCRYPTION_MODE_AES_256_CTS] = { "cts(cbc(aes))", | |
132 | FS_AES_256_CTS_KEY_SIZE }, | |
133 | [FS_ENCRYPTION_MODE_AES_128_CBC] = { "cbc(aes)", | |
134 | FS_AES_128_CBC_KEY_SIZE }, | |
135 | [FS_ENCRYPTION_MODE_AES_128_CTS] = { "cts(cbc(aes))", | |
136 | FS_AES_128_CTS_KEY_SIZE }, | |
137 | }; | |
138 | ||
8f39850d EB |
139 | static int determine_cipher_type(struct fscrypt_info *ci, struct inode *inode, |
140 | const char **cipher_str_ret, int *keysize_ret) | |
141 | { | |
b7e7cf7a DW |
142 | u32 mode; |
143 | ||
144 | if (!fscrypt_valid_enc_modes(ci->ci_data_mode, ci->ci_filename_mode)) { | |
145 | pr_warn_ratelimited("fscrypt: inode %lu uses unsupported encryption modes (contents mode %d, filenames mode %d)\n", | |
146 | inode->i_ino, | |
147 | ci->ci_data_mode, ci->ci_filename_mode); | |
148 | return -EINVAL; | |
8f39850d EB |
149 | } |
150 | ||
b7e7cf7a DW |
151 | if (S_ISREG(inode->i_mode)) { |
152 | mode = ci->ci_data_mode; | |
153 | } else if (S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode)) { | |
154 | mode = ci->ci_filename_mode; | |
155 | } else { | |
156 | WARN_ONCE(1, "fscrypt: filesystem tried to load encryption info for inode %lu, which is not encryptable (file type %d)\n", | |
157 | inode->i_ino, (inode->i_mode & S_IFMT)); | |
158 | return -EINVAL; | |
8f39850d EB |
159 | } |
160 | ||
b7e7cf7a DW |
161 | *cipher_str_ret = available_modes[mode].cipher_str; |
162 | *keysize_ret = available_modes[mode].keysize; | |
163 | return 0; | |
8f39850d EB |
164 | } |
165 | ||
0b81d077 | 166 | static void put_crypt_info(struct fscrypt_info *ci) |
0adda907 | 167 | { |
0adda907 JK |
168 | if (!ci) |
169 | return; | |
170 | ||
d407574e | 171 | crypto_free_skcipher(ci->ci_ctfm); |
b7e7cf7a | 172 | crypto_free_cipher(ci->ci_essiv_tfm); |
0b81d077 | 173 | kmem_cache_free(fscrypt_info_cachep, ci); |
0adda907 JK |
174 | } |
175 | ||
b7e7cf7a DW |
176 | static int derive_essiv_salt(const u8 *key, int keysize, u8 *salt) |
177 | { | |
178 | struct crypto_shash *tfm = READ_ONCE(essiv_hash_tfm); | |
179 | ||
180 | /* init hash transform on demand */ | |
181 | if (unlikely(!tfm)) { | |
182 | struct crypto_shash *prev_tfm; | |
183 | ||
184 | tfm = crypto_alloc_shash("sha256", 0, 0); | |
185 | if (IS_ERR(tfm)) { | |
186 | pr_warn_ratelimited("fscrypt: error allocating SHA-256 transform: %ld\n", | |
187 | PTR_ERR(tfm)); | |
188 | return PTR_ERR(tfm); | |
189 | } | |
190 | prev_tfm = cmpxchg(&essiv_hash_tfm, NULL, tfm); | |
191 | if (prev_tfm) { | |
192 | crypto_free_shash(tfm); | |
193 | tfm = prev_tfm; | |
194 | } | |
195 | } | |
196 | ||
197 | { | |
198 | SHASH_DESC_ON_STACK(desc, tfm); | |
199 | desc->tfm = tfm; | |
200 | desc->flags = 0; | |
201 | ||
202 | return crypto_shash_digest(desc, key, keysize, salt); | |
203 | } | |
204 | } | |
205 | ||
206 | static int init_essiv_generator(struct fscrypt_info *ci, const u8 *raw_key, | |
207 | int keysize) | |
208 | { | |
209 | int err; | |
210 | struct crypto_cipher *essiv_tfm; | |
211 | u8 salt[SHA256_DIGEST_SIZE]; | |
212 | ||
213 | essiv_tfm = crypto_alloc_cipher("aes", 0, 0); | |
214 | if (IS_ERR(essiv_tfm)) | |
215 | return PTR_ERR(essiv_tfm); | |
216 | ||
217 | ci->ci_essiv_tfm = essiv_tfm; | |
218 | ||
219 | err = derive_essiv_salt(raw_key, keysize, salt); | |
220 | if (err) | |
221 | goto out; | |
222 | ||
223 | /* | |
224 | * Using SHA256 to derive the salt/key will result in AES-256 being | |
225 | * used for IV generation. File contents encryption will still use the | |
226 | * configured keysize (AES-128) nevertheless. | |
227 | */ | |
228 | err = crypto_cipher_setkey(essiv_tfm, salt, sizeof(salt)); | |
229 | if (err) | |
230 | goto out; | |
231 | ||
232 | out: | |
233 | memzero_explicit(salt, sizeof(salt)); | |
234 | return err; | |
235 | } | |
236 | ||
237 | void __exit fscrypt_essiv_cleanup(void) | |
238 | { | |
239 | crypto_free_shash(essiv_hash_tfm); | |
240 | } | |
241 | ||
1b53cf98 | 242 | int fscrypt_get_encryption_info(struct inode *inode) |
0adda907 | 243 | { |
0b81d077 | 244 | struct fscrypt_info *crypt_info; |
0b81d077 | 245 | struct fscrypt_context ctx; |
d407574e | 246 | struct crypto_skcipher *ctfm; |
26bf3dc7 | 247 | const char *cipher_str; |
8f39850d | 248 | int keysize; |
a6e08912 | 249 | u8 *raw_key = NULL; |
0adda907 JK |
250 | int res; |
251 | ||
1b53cf98 EB |
252 | if (inode->i_crypt_info) |
253 | return 0; | |
254 | ||
f32d7ac2 | 255 | res = fscrypt_initialize(inode->i_sb->s_cop->flags); |
cfc4d971 JK |
256 | if (res) |
257 | return res; | |
0b81d077 | 258 | |
0b81d077 JK |
259 | res = inode->i_sb->s_cop->get_context(inode, &ctx, sizeof(ctx)); |
260 | if (res < 0) { | |
5bbdcbbb | 261 | if (!fscrypt_dummy_context_enabled(inode) || |
e0428a26 | 262 | IS_ENCRYPTED(inode)) |
0b81d077 | 263 | return res; |
5bbdcbbb TT |
264 | /* Fake up a context for an unencrypted directory */ |
265 | memset(&ctx, 0, sizeof(ctx)); | |
8f39850d | 266 | ctx.format = FS_ENCRYPTION_CONTEXT_FORMAT_V1; |
0b81d077 JK |
267 | ctx.contents_encryption_mode = FS_ENCRYPTION_MODE_AES_256_XTS; |
268 | ctx.filenames_encryption_mode = FS_ENCRYPTION_MODE_AES_256_CTS; | |
5bbdcbbb | 269 | memset(ctx.master_key_descriptor, 0x42, FS_KEY_DESCRIPTOR_SIZE); |
0b81d077 | 270 | } else if (res != sizeof(ctx)) { |
0adda907 | 271 | return -EINVAL; |
0b81d077 | 272 | } |
8f39850d EB |
273 | |
274 | if (ctx.format != FS_ENCRYPTION_CONTEXT_FORMAT_V1) | |
275 | return -EINVAL; | |
276 | ||
277 | if (ctx.flags & ~FS_POLICY_FLAGS_VALID) | |
278 | return -EINVAL; | |
0adda907 | 279 | |
0b81d077 | 280 | crypt_info = kmem_cache_alloc(fscrypt_info_cachep, GFP_NOFS); |
0adda907 JK |
281 | if (!crypt_info) |
282 | return -ENOMEM; | |
283 | ||
284 | crypt_info->ci_flags = ctx.flags; | |
285 | crypt_info->ci_data_mode = ctx.contents_encryption_mode; | |
286 | crypt_info->ci_filename_mode = ctx.filenames_encryption_mode; | |
287 | crypt_info->ci_ctfm = NULL; | |
b7e7cf7a | 288 | crypt_info->ci_essiv_tfm = NULL; |
0adda907 JK |
289 | memcpy(crypt_info->ci_master_key, ctx.master_key_descriptor, |
290 | sizeof(crypt_info->ci_master_key)); | |
640778fb | 291 | |
8f39850d EB |
292 | res = determine_cipher_type(crypt_info, inode, &cipher_str, &keysize); |
293 | if (res) | |
26bf3dc7 | 294 | goto out; |
8f39850d | 295 | |
a6e08912 EB |
296 | /* |
297 | * This cannot be a stack buffer because it is passed to the scatterlist | |
298 | * crypto API as part of key derivation. | |
299 | */ | |
300 | res = -ENOMEM; | |
301 | raw_key = kmalloc(FS_MAX_KEY_SIZE, GFP_NOFS); | |
302 | if (!raw_key) | |
303 | goto out; | |
304 | ||
b7e7cf7a DW |
305 | res = validate_user_key(crypt_info, &ctx, raw_key, FS_KEY_DESC_PREFIX, |
306 | keysize); | |
b5a7aef1 | 307 | if (res && inode->i_sb->s_cop->key_prefix) { |
a5d431ef | 308 | int res2 = validate_user_key(crypt_info, &ctx, raw_key, |
b7e7cf7a DW |
309 | inode->i_sb->s_cop->key_prefix, |
310 | keysize); | |
b5a7aef1 JK |
311 | if (res2) { |
312 | if (res2 == -ENOKEY) | |
313 | res = -ENOKEY; | |
314 | goto out; | |
315 | } | |
316 | } else if (res) { | |
66aa3e12 JK |
317 | goto out; |
318 | } | |
d407574e | 319 | ctfm = crypto_alloc_skcipher(cipher_str, 0, 0); |
26bf3dc7 JK |
320 | if (!ctfm || IS_ERR(ctfm)) { |
321 | res = ctfm ? PTR_ERR(ctfm) : -ENOMEM; | |
b7e7cf7a DW |
322 | pr_debug("%s: error %d (inode %lu) allocating crypto tfm\n", |
323 | __func__, res, inode->i_ino); | |
26bf3dc7 | 324 | goto out; |
0adda907 | 325 | } |
26bf3dc7 | 326 | crypt_info->ci_ctfm = ctfm; |
d407574e LT |
327 | crypto_skcipher_clear_flags(ctfm, ~0); |
328 | crypto_skcipher_set_flags(ctfm, CRYPTO_TFM_REQ_WEAK_KEY); | |
b7e7cf7a DW |
329 | /* |
330 | * if the provided key is longer than keysize, we use the first | |
331 | * keysize bytes of the derived key only | |
332 | */ | |
8f39850d | 333 | res = crypto_skcipher_setkey(ctfm, raw_key, keysize); |
26bf3dc7 JK |
334 | if (res) |
335 | goto out; | |
336 | ||
b7e7cf7a DW |
337 | if (S_ISREG(inode->i_mode) && |
338 | crypt_info->ci_data_mode == FS_ENCRYPTION_MODE_AES_128_CBC) { | |
339 | res = init_essiv_generator(crypt_info, raw_key, keysize); | |
340 | if (res) { | |
341 | pr_debug("%s: error %d (inode %lu) allocating essiv tfm\n", | |
342 | __func__, res, inode->i_ino); | |
343 | goto out; | |
344 | } | |
345 | } | |
1b53cf98 EB |
346 | if (cmpxchg(&inode->i_crypt_info, NULL, crypt_info) == NULL) |
347 | crypt_info = NULL; | |
26bf3dc7 | 348 | out: |
0b81d077 | 349 | if (res == -ENOKEY) |
26bf3dc7 | 350 | res = 0; |
0b81d077 | 351 | put_crypt_info(crypt_info); |
a6e08912 | 352 | kzfree(raw_key); |
0adda907 JK |
353 | return res; |
354 | } | |
1b53cf98 | 355 | EXPORT_SYMBOL(fscrypt_get_encryption_info); |
0adda907 | 356 | |
0b81d077 | 357 | void fscrypt_put_encryption_info(struct inode *inode, struct fscrypt_info *ci) |
0adda907 | 358 | { |
0b81d077 JK |
359 | struct fscrypt_info *prev; |
360 | ||
361 | if (ci == NULL) | |
6aa7de05 | 362 | ci = READ_ONCE(inode->i_crypt_info); |
0b81d077 JK |
363 | if (ci == NULL) |
364 | return; | |
0adda907 | 365 | |
0b81d077 JK |
366 | prev = cmpxchg(&inode->i_crypt_info, ci, NULL); |
367 | if (prev != ci) | |
368 | return; | |
369 | ||
370 | put_crypt_info(ci); | |
371 | } | |
372 | EXPORT_SYMBOL(fscrypt_put_encryption_info); |