Blame view
fs/crypto/keyinfo.c
8.52 KB
0adda907f f2fs crypto: add ... |
1 |
/* |
0b81d0779 fs crypto: move p... |
2 |
* key management facility for FS encryption support. |
0adda907f f2fs crypto: add ... |
3 4 5 |
* * Copyright (C) 2015, Google, Inc. * |
0b81d0779 fs crypto: move p... |
6 |
* This contains encryption key functions. |
0adda907f f2fs crypto: add ... |
7 8 9 |
* * Written by Michael Halcrow, Ildar Muslukhov, and Uday Savagaonkar, 2015. */ |
0b81d0779 fs crypto: move p... |
10 |
|
0adda907f f2fs crypto: add ... |
11 |
#include <keys/user-type.h> |
0adda907f f2fs crypto: add ... |
12 |
#include <linux/scatterlist.h> |
0b81d0779 fs crypto: move p... |
13 |
#include <linux/fscrypto.h> |
0adda907f f2fs crypto: add ... |
14 15 16 |
static void derive_crypt_complete(struct crypto_async_request *req, int rc) { |
0b81d0779 fs crypto: move p... |
17 |
struct fscrypt_completion_result *ecr = req->data; |
0adda907f f2fs crypto: add ... |
18 19 20 21 22 23 24 25 26 |
if (rc == -EINPROGRESS) return; ecr->res = rc; complete(&ecr->completion); } /** |
0b81d0779 fs crypto: move p... |
27 |
* derive_key_aes() - Derive a key using AES-128-ECB |
0fac2d501 f2fs crypto: fix ... |
28 |
* @deriving_key: Encryption key used for derivation. |
0adda907f f2fs crypto: add ... |
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. */ |
0b81d0779 fs crypto: move p... |
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]) |
0adda907f f2fs crypto: add ... |
37 38 |
{ int res = 0; |
d407574e7 Merge tag 'for-f2... |
39 |
struct skcipher_request *req = NULL; |
0b81d0779 fs crypto: move p... |
40 |
DECLARE_FS_COMPLETION_RESULT(ecr); |
0adda907f f2fs crypto: add ... |
41 |
struct scatterlist src_sg, dst_sg; |
d407574e7 Merge tag 'for-f2... |
42 |
struct crypto_skcipher *tfm = crypto_alloc_skcipher("ecb(aes)", 0, 0); |
0adda907f f2fs crypto: add ... |
43 44 45 46 47 48 |
if (IS_ERR(tfm)) { res = PTR_ERR(tfm); tfm = NULL; goto out; } |
d407574e7 Merge tag 'for-f2... |
49 50 |
crypto_skcipher_set_flags(tfm, CRYPTO_TFM_REQ_WEAK_KEY); req = skcipher_request_alloc(tfm, GFP_NOFS); |
0adda907f f2fs crypto: add ... |
51 52 53 54 |
if (!req) { res = -ENOMEM; goto out; } |
d407574e7 Merge tag 'for-f2... |
55 |
skcipher_request_set_callback(req, |
0adda907f f2fs crypto: add ... |
56 57 |
CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP, derive_crypt_complete, &ecr); |
d407574e7 Merge tag 'for-f2... |
58 |
res = crypto_skcipher_setkey(tfm, deriving_key, |
0b81d0779 fs crypto: move p... |
59 |
FS_AES_128_ECB_KEY_SIZE); |
0adda907f f2fs crypto: add ... |
60 61 |
if (res < 0) goto out; |
0b81d0779 fs crypto: move p... |
62 63 |
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); |
d407574e7 Merge tag 'for-f2... |
64 |
skcipher_request_set_crypt(req, &src_sg, &dst_sg, |
0b81d0779 fs crypto: move p... |
65 |
FS_AES_256_XTS_KEY_SIZE, NULL); |
d407574e7 Merge tag 'for-f2... |
66 |
res = crypto_skcipher_encrypt(req); |
0adda907f f2fs crypto: add ... |
67 |
if (res == -EINPROGRESS || res == -EBUSY) { |
0adda907f f2fs crypto: add ... |
68 69 70 71 |
wait_for_completion(&ecr.completion); res = ecr.res; } out: |
d407574e7 Merge tag 'for-f2... |
72 73 |
skcipher_request_free(req); crypto_free_skcipher(tfm); |
0adda907f f2fs crypto: add ... |
74 75 |
return res; } |
b5a7aef1e fscrypto/f2fs: al... |
76 77 78 79 80 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 |
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 ", __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 ", __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; } |
8f39850df fscrypto: improve... |
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 167 168 169 170 171 |
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 ", 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 ", ci->ci_filename_mode, inode->i_ino); return -ENOKEY; } pr_warn_once("fscrypto: unsupported file type %d for inode %lu ", (inode->i_mode & S_IFMT), inode->i_ino); return -ENOKEY; } |
0b81d0779 fs crypto: move p... |
172 |
static void put_crypt_info(struct fscrypt_info *ci) |
0adda907f f2fs crypto: add ... |
173 |
{ |
0adda907f f2fs crypto: add ... |
174 175 |
if (!ci) return; |
d407574e7 Merge tag 'for-f2... |
176 177 |
key_put(ci->ci_keyring_key); crypto_free_skcipher(ci->ci_ctfm); |
0b81d0779 fs crypto: move p... |
178 |
kmem_cache_free(fscrypt_info_cachep, ci); |
0adda907f f2fs crypto: add ... |
179 |
} |
0b81d0779 fs crypto: move p... |
180 |
int get_crypt_info(struct inode *inode) |
0adda907f f2fs crypto: add ... |
181 |
{ |
0b81d0779 fs crypto: move p... |
182 |
struct fscrypt_info *crypt_info; |
0b81d0779 fs crypto: move p... |
183 |
struct fscrypt_context ctx; |
d407574e7 Merge tag 'for-f2... |
184 |
struct crypto_skcipher *ctfm; |
26bf3dc7e f2fs crypto: use ... |
185 |
const char *cipher_str; |
8f39850df fscrypto: improve... |
186 |
int keysize; |
0f0909e24 fscrypto: don't u... |
187 |
u8 *raw_key = NULL; |
0adda907f f2fs crypto: add ... |
188 |
int res; |
0b81d0779 fs crypto: move p... |
189 |
res = fscrypt_initialize(); |
cfc4d971d f2fs crypto: spli... |
190 191 |
if (res) return res; |
0b81d0779 fs crypto: move p... |
192 193 194 |
if (!inode->i_sb->s_cop->get_context) return -EOPNOTSUPP; |
26bf3dc7e f2fs crypto: use ... |
195 |
retry: |
0b81d0779 fs crypto: move p... |
196 |
crypt_info = ACCESS_ONCE(inode->i_crypt_info); |
26bf3dc7e f2fs crypto: use ... |
197 198 199 |
if (crypt_info) { if (!crypt_info->ci_keyring_key || key_validate(crypt_info->ci_keyring_key) == 0) |
0adda907f f2fs crypto: add ... |
200 |
return 0; |
0b81d0779 fs crypto: move p... |
201 |
fscrypt_put_encryption_info(inode, crypt_info); |
26bf3dc7e f2fs crypto: use ... |
202 |
goto retry; |
0adda907f f2fs crypto: add ... |
203 |
} |
0b81d0779 fs crypto: move p... |
204 205 206 207 |
res = inode->i_sb->s_cop->get_context(inode, &ctx, sizeof(ctx)); if (res < 0) { if (!fscrypt_dummy_context_enabled(inode)) return res; |
8f39850df fscrypto: improve... |
208 |
ctx.format = FS_ENCRYPTION_CONTEXT_FORMAT_V1; |
0b81d0779 fs crypto: move p... |
209 210 211 212 |
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)) { |
0adda907f f2fs crypto: add ... |
213 |
return -EINVAL; |
0b81d0779 fs crypto: move p... |
214 |
} |
8f39850df fscrypto: improve... |
215 216 217 218 219 220 |
if (ctx.format != FS_ENCRYPTION_CONTEXT_FORMAT_V1) return -EINVAL; if (ctx.flags & ~FS_POLICY_FLAGS_VALID) return -EINVAL; |
0adda907f f2fs crypto: add ... |
221 |
|
0b81d0779 fs crypto: move p... |
222 |
crypt_info = kmem_cache_alloc(fscrypt_info_cachep, GFP_NOFS); |
0adda907f f2fs crypto: add ... |
223 224 225 226 227 228 229 |
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; |
26bf3dc7e f2fs crypto: use ... |
230 |
crypt_info->ci_keyring_key = NULL; |
0adda907f f2fs crypto: add ... |
231 232 |
memcpy(crypt_info->ci_master_key, ctx.master_key_descriptor, sizeof(crypt_info->ci_master_key)); |
640778fbc f2fs crypto: get ... |
233 |
|
8f39850df fscrypto: improve... |
234 235 |
res = determine_cipher_type(crypt_info, inode, &cipher_str, &keysize); if (res) |
26bf3dc7e f2fs crypto: use ... |
236 |
goto out; |
8f39850df fscrypto: improve... |
237 |
|
0f0909e24 fscrypto: don't u... |
238 239 240 241 242 243 244 245 |
/* * 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; |
0b81d0779 fs crypto: move p... |
246 247 248 249 |
if (fscrypt_dummy_context_enabled(inode)) { memset(raw_key, 0x42, FS_AES_256_XTS_KEY_SIZE); goto got_key; } |
0b81d0779 fs crypto: move p... |
250 |
|
b5a7aef1e fscrypto/f2fs: al... |
251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 |
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) { |
66aa3e127 f2fs crypto: repl... |
266 267 |
goto out; } |
0b81d0779 fs crypto: move p... |
268 |
got_key: |
d407574e7 Merge tag 'for-f2... |
269 |
ctfm = crypto_alloc_skcipher(cipher_str, 0, 0); |
26bf3dc7e f2fs crypto: use ... |
270 271 272 273 274 275 276 |
if (!ctfm || IS_ERR(ctfm)) { res = ctfm ? PTR_ERR(ctfm) : -ENOMEM; printk(KERN_DEBUG "%s: error %d (inode %u) allocating crypto tfm ", __func__, res, (unsigned) inode->i_ino); goto out; |
0adda907f f2fs crypto: add ... |
277 |
} |
26bf3dc7e f2fs crypto: use ... |
278 |
crypt_info->ci_ctfm = ctfm; |
d407574e7 Merge tag 'for-f2... |
279 280 |
crypto_skcipher_clear_flags(ctfm, ~0); crypto_skcipher_set_flags(ctfm, CRYPTO_TFM_REQ_WEAK_KEY); |
8f39850df fscrypto: improve... |
281 |
res = crypto_skcipher_setkey(ctfm, raw_key, keysize); |
26bf3dc7e f2fs crypto: use ... |
282 283 |
if (res) goto out; |
0f0909e24 fscrypto: don't u... |
284 285 |
kzfree(raw_key); raw_key = NULL; |
0b81d0779 fs crypto: move p... |
286 287 |
if (cmpxchg(&inode->i_crypt_info, NULL, crypt_info) != NULL) { put_crypt_info(crypt_info); |
26bf3dc7e f2fs crypto: use ... |
288 289 290 291 292 |
goto retry; } return 0; out: |
0b81d0779 fs crypto: move p... |
293 |
if (res == -ENOKEY) |
26bf3dc7e f2fs crypto: use ... |
294 |
res = 0; |
0b81d0779 fs crypto: move p... |
295 |
put_crypt_info(crypt_info); |
0f0909e24 fscrypto: don't u... |
296 |
kzfree(raw_key); |
0adda907f f2fs crypto: add ... |
297 298 |
return res; } |
0b81d0779 fs crypto: move p... |
299 |
void fscrypt_put_encryption_info(struct inode *inode, struct fscrypt_info *ci) |
0adda907f f2fs crypto: add ... |
300 |
{ |
0b81d0779 fs crypto: move p... |
301 302 303 304 305 306 |
struct fscrypt_info *prev; if (ci == NULL) ci = ACCESS_ONCE(inode->i_crypt_info); if (ci == NULL) return; |
0adda907f f2fs crypto: add ... |
307 |
|
0b81d0779 fs crypto: move p... |
308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 |
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; |
0adda907f f2fs crypto: add ... |
327 |
} |
0b81d0779 fs crypto: move p... |
328 |
EXPORT_SYMBOL(fscrypt_get_encryption_info); |