aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric Biggers <ebiggers@google.com>2018-04-30 18:51:48 -0400
committerTheodore Ts'o <tytso@mit.edu>2018-05-20 16:21:05 -0400
commit590f497d08eeae883a4fc2dd938c89520ac139fd (patch)
treeb4d2d6feff65b6a880c2666eb966874bcc0f9cf0
parent544d08fde258b4da72b6cfbe2d7172c86ce9860d (diff)
fscrypt: separate key lookup from key derivation
Refactor the confusingly-named function 'validate_user_key()' into a new function 'find_and_derive_key()' which first finds the keyring key, then does the key derivation. Among other benefits this avoids the strange behavior we had previously where if key derivation failed for some reason, then we would fall back to the alternate key prefix. Now, we'll only fall back to the alternate key prefix if a valid key isn't found. This patch also improves the warning messages that are logged when the keyring key's payload is invalid. Signed-off-by: Eric Biggers <ebiggers@google.com> Signed-off-by: Theodore Ts'o <tytso@mit.edu>
-rw-r--r--fs/crypto/keyinfo.c122
1 files changed, 74 insertions, 48 deletions
diff --git a/fs/crypto/keyinfo.c b/fs/crypto/keyinfo.c
index f63bfd6dffd6..f248ee9974fa 100644
--- a/fs/crypto/keyinfo.c
+++ b/fs/crypto/keyinfo.c
@@ -27,7 +27,7 @@ static struct crypto_shash *essiv_hash_tfm;
27 * 27 *
28 * Return: Zero on success; non-zero otherwise. 28 * Return: Zero on success; non-zero otherwise.
29 */ 29 */
30static int derive_key_aes(u8 deriving_key[FS_KEY_DERIVATION_NONCE_SIZE], 30static int derive_key_aes(const u8 deriving_key[FS_KEY_DERIVATION_NONCE_SIZE],
31 const struct fscrypt_key *source_key, 31 const struct fscrypt_key *source_key,
32 u8 derived_raw_key[FS_MAX_KEY_SIZE]) 32 u8 derived_raw_key[FS_MAX_KEY_SIZE])
33{ 33{
@@ -67,52 +67,88 @@ out:
67 return res; 67 return res;
68} 68}
69 69
70static int validate_user_key(struct fscrypt_info *crypt_info, 70/*
71 struct fscrypt_context *ctx, u8 *raw_key, 71 * Search the current task's subscribed keyrings for a "logon" key with
72 const char *prefix, int min_keysize) 72 * description prefix:descriptor, and if found acquire a read lock on it and
73 * return a pointer to its validated payload in *payload_ret.
74 */
75static struct key *
76find_and_lock_process_key(const char *prefix,
77 const u8 descriptor[FS_KEY_DESCRIPTOR_SIZE],
78 unsigned int min_keysize,
79 const struct fscrypt_key **payload_ret)
73{ 80{
74 char *description; 81 char *description;
75 struct key *keyring_key; 82 struct key *key;
76 struct fscrypt_key *master_key;
77 const struct user_key_payload *ukp; 83 const struct user_key_payload *ukp;
78 int res; 84 const struct fscrypt_key *payload;
79 85
80 description = kasprintf(GFP_NOFS, "%s%*phN", prefix, 86 description = kasprintf(GFP_NOFS, "%s%*phN", prefix,
81 FS_KEY_DESCRIPTOR_SIZE, 87 FS_KEY_DESCRIPTOR_SIZE, descriptor);
82 ctx->master_key_descriptor);
83 if (!description) 88 if (!description)
84 return -ENOMEM; 89 return ERR_PTR(-ENOMEM);
85 90
86 keyring_key = request_key(&key_type_logon, description, NULL); 91 key = request_key(&key_type_logon, description, NULL);
87 kfree(description); 92 kfree(description);
88 if (IS_ERR(keyring_key)) 93 if (IS_ERR(key))
89 return PTR_ERR(keyring_key); 94 return key;
90 down_read(&keyring_key->sem); 95
91 96 down_read(&key->sem);
92 ukp = user_key_payload_locked(keyring_key); 97 ukp = user_key_payload_locked(key);
93 if (!ukp) { 98
94 /* key was revoked before we acquired its semaphore */ 99 if (!ukp) /* was the key revoked before we acquired its semaphore? */
95 res = -EKEYREVOKED; 100 goto invalid;
96 goto out; 101
102 payload = (const struct fscrypt_key *)ukp->data;
103
104 if (ukp->datalen != sizeof(struct fscrypt_key) ||
105 payload->size < 1 || payload->size > FS_MAX_KEY_SIZE) {
106 fscrypt_warn(NULL,
107 "key with description '%s' has invalid payload",
108 key->description);
109 goto invalid;
97 } 110 }
98 if (ukp->datalen != sizeof(struct fscrypt_key)) { 111
99 res = -EINVAL; 112 if (payload->size < min_keysize ||
100 goto out; 113 payload->size % AES_BLOCK_SIZE != 0) {
114 fscrypt_warn(NULL,
115 "key with description '%s' is too short or is misaligned (got %u bytes, need %u+ bytes)",
116 key->description, payload->size, min_keysize);
117 goto invalid;
101 } 118 }
102 master_key = (struct fscrypt_key *)ukp->data;
103 119
104 if (master_key->size < min_keysize || master_key->size > FS_MAX_KEY_SIZE 120 *payload_ret = payload;
105 || master_key->size % AES_BLOCK_SIZE != 0) { 121 return key;
106 fscrypt_warn(NULL, "key size incorrect: %u", 122
107 master_key->size); 123invalid:
108 res = -ENOKEY; 124 up_read(&key->sem);
109 goto out; 125 key_put(key);
126 return ERR_PTR(-ENOKEY);
127}
128
129/* Find the master key, then derive the inode's actual encryption key */
130static int find_and_derive_key(const struct inode *inode,
131 const struct fscrypt_context *ctx,
132 u8 *derived_key, unsigned int derived_keysize)
133{
134 struct key *key;
135 const struct fscrypt_key *payload;
136 int err;
137
138 key = find_and_lock_process_key(FS_KEY_DESC_PREFIX,
139 ctx->master_key_descriptor,
140 derived_keysize, &payload);
141 if (key == ERR_PTR(-ENOKEY) && inode->i_sb->s_cop->key_prefix) {
142 key = find_and_lock_process_key(inode->i_sb->s_cop->key_prefix,
143 ctx->master_key_descriptor,
144 derived_keysize, &payload);
110 } 145 }
111 res = derive_key_aes(ctx->nonce, master_key, raw_key); 146 if (IS_ERR(key))
112out: 147 return PTR_ERR(key);
113 up_read(&keyring_key->sem); 148 err = derive_key_aes(ctx->nonce, payload, derived_key);
114 key_put(keyring_key); 149 up_read(&key->sem);
115 return res; 150 key_put(key);
151 return err;
116} 152}
117 153
118static const struct { 154static const struct {
@@ -293,20 +329,10 @@ int fscrypt_get_encryption_info(struct inode *inode)
293 if (!raw_key) 329 if (!raw_key)
294 goto out; 330 goto out;
295 331
296 res = validate_user_key(crypt_info, &ctx, raw_key, FS_KEY_DESC_PREFIX, 332 res = find_and_derive_key(inode, &ctx, raw_key, keysize);
297 keysize); 333 if (res)
298 if (res && inode->i_sb->s_cop->key_prefix) {
299 int res2 = validate_user_key(crypt_info, &ctx, raw_key,
300 inode->i_sb->s_cop->key_prefix,
301 keysize);
302 if (res2) {
303 if (res2 == -ENOKEY)
304 res = -ENOKEY;
305 goto out;
306 }
307 } else if (res) {
308 goto out; 334 goto out;
309 } 335
310 ctfm = crypto_alloc_skcipher(cipher_str, 0, 0); 336 ctfm = crypto_alloc_skcipher(cipher_str, 0, 0);
311 if (IS_ERR(ctfm)) { 337 if (IS_ERR(ctfm)) {
312 res = PTR_ERR(ctfm); 338 res = PTR_ERR(ctfm);