diff options
author | Michael Halcrow <mhalcrow@us.ibm.com> | 2007-10-16 04:27:53 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-10-16 12:43:10 -0400 |
commit | f4aad16adfb8f0a2d666fdf8af4bd0dff2ce75e4 (patch) | |
tree | 42e7f191d1a3a1e1375af24acc5c336b30c5c4d1 /fs/ecryptfs/main.c | |
parent | cce76f9b9696a59974be9ed43478c000c57e597a (diff) |
eCryptfs: add key list structure; search keyring
Add support structures for handling multiple keys. The list in crypt_stat
contains the key identifiers for all of the keys that should be used for
encrypting each file's File Encryption Key (FEK). For now, each inode
inherits this list from the mount-wide crypt_stat struct, via the
ecryptfs_copy_mount_wide_sigs_to_inode_sigs() function.
This patch also removes the global key tfm from the mount-wide crypt_stat
struct, instead keeping a list of tfm's meant for dealing with the various
inode FEK's. eCryptfs will now search the user's keyring for FEK's parsed
from the existing file metadata, so the user can make keys available at any
time before or after mounting.
Now that multiple FEK packets can be written to the file metadata, we need to
be more meticulous about size limits. The updates to the code for writing out
packets to the file metadata makes sizes and limits more explicit, uniformly
expressed, and (hopefully) easier to follow.
Signed-off-by: Michael Halcrow <mhalcrow@us.ibm.com>
Cc: "Serge E. Hallyn" <serge@hallyn.com>
Cc: David Howells <dhowells@redhat.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'fs/ecryptfs/main.c')
-rw-r--r-- | fs/ecryptfs/main.c | 121 |
1 files changed, 44 insertions, 77 deletions
diff --git a/fs/ecryptfs/main.c b/fs/ecryptfs/main.c index a98497264fe8..6e2170c96c02 100644 --- a/fs/ecryptfs/main.c +++ b/fs/ecryptfs/main.c | |||
@@ -179,38 +179,40 @@ static match_table_t tokens = { | |||
179 | {ecryptfs_opt_err, NULL} | 179 | {ecryptfs_opt_err, NULL} |
180 | }; | 180 | }; |
181 | 181 | ||
182 | /** | 182 | static int ecryptfs_init_global_auth_toks( |
183 | * ecryptfs_verify_version | 183 | struct ecryptfs_mount_crypt_stat *mount_crypt_stat) |
184 | * @version: The version number to confirm | ||
185 | * | ||
186 | * Returns zero on good version; non-zero otherwise | ||
187 | */ | ||
188 | static int ecryptfs_verify_version(u16 version) | ||
189 | { | 184 | { |
185 | struct ecryptfs_global_auth_tok *global_auth_tok; | ||
190 | int rc = 0; | 186 | int rc = 0; |
191 | unsigned char major; | 187 | |
192 | unsigned char minor; | 188 | list_for_each_entry(global_auth_tok, |
193 | 189 | &mount_crypt_stat->global_auth_tok_list, | |
194 | major = ((version >> 8) & 0xFF); | 190 | mount_crypt_stat_list) { |
195 | minor = (version & 0xFF); | 191 | if ((rc = ecryptfs_keyring_auth_tok_for_sig( |
196 | if (major != ECRYPTFS_VERSION_MAJOR) { | 192 | &global_auth_tok->global_auth_tok_key, |
197 | ecryptfs_printk(KERN_ERR, "Major version number mismatch. " | 193 | &global_auth_tok->global_auth_tok, |
198 | "Expected [%d]; got [%d]\n", | 194 | global_auth_tok->sig))) { |
199 | ECRYPTFS_VERSION_MAJOR, major); | 195 | printk(KERN_ERR "Could not find valid key in user " |
200 | rc = -EINVAL; | 196 | "session keyring for sig specified in mount " |
201 | goto out; | 197 | "option: [%s]\n", global_auth_tok->sig); |
202 | } | 198 | global_auth_tok->flags |= ECRYPTFS_AUTH_TOK_INVALID; |
203 | if (minor != ECRYPTFS_VERSION_MINOR) { | 199 | rc = 0; |
204 | ecryptfs_printk(KERN_ERR, "Minor version number mismatch. " | 200 | } else |
205 | "Expected [%d]; got [%d]\n", | 201 | global_auth_tok->flags &= ~ECRYPTFS_AUTH_TOK_INVALID; |
206 | ECRYPTFS_VERSION_MINOR, minor); | ||
207 | rc = -EINVAL; | ||
208 | goto out; | ||
209 | } | 202 | } |
210 | out: | ||
211 | return rc; | 203 | return rc; |
212 | } | 204 | } |
213 | 205 | ||
206 | static void ecryptfs_init_mount_crypt_stat( | ||
207 | struct ecryptfs_mount_crypt_stat *mount_crypt_stat) | ||
208 | { | ||
209 | memset((void *)mount_crypt_stat, 0, | ||
210 | sizeof(struct ecryptfs_mount_crypt_stat)); | ||
211 | INIT_LIST_HEAD(&mount_crypt_stat->global_auth_tok_list); | ||
212 | mutex_init(&mount_crypt_stat->global_auth_tok_list_mutex); | ||
213 | mount_crypt_stat->flags |= ECRYPTFS_MOUNT_CRYPT_STAT_INITIALIZED; | ||
214 | } | ||
215 | |||
214 | /** | 216 | /** |
215 | * ecryptfs_parse_options | 217 | * ecryptfs_parse_options |
216 | * @sb: The ecryptfs super block | 218 | * @sb: The ecryptfs super block |
@@ -264,14 +266,13 @@ static int ecryptfs_parse_options(struct super_block *sb, char *options) | |||
264 | case ecryptfs_opt_sig: | 266 | case ecryptfs_opt_sig: |
265 | case ecryptfs_opt_ecryptfs_sig: | 267 | case ecryptfs_opt_ecryptfs_sig: |
266 | sig_src = args[0].from; | 268 | sig_src = args[0].from; |
267 | sig_dst = | 269 | rc = ecryptfs_add_global_auth_tok(mount_crypt_stat, |
268 | mount_crypt_stat->global_auth_tok_sig; | 270 | sig_src); |
269 | memcpy(sig_dst, sig_src, ECRYPTFS_SIG_SIZE_HEX); | 271 | if (rc) { |
270 | sig_dst[ECRYPTFS_SIG_SIZE_HEX] = '\0'; | 272 | printk(KERN_ERR "Error attempting to register " |
271 | ecryptfs_printk(KERN_DEBUG, | 273 | "global sig; rc = [%d]\n", rc); |
272 | "The mount_crypt_stat " | 274 | goto out; |
273 | "global_auth_tok_sig set to: " | 275 | } |
274 | "[%s]\n", sig_dst); | ||
275 | sig_set = 1; | 276 | sig_set = 1; |
276 | break; | 277 | break; |
277 | case ecryptfs_opt_debug: | 278 | case ecryptfs_opt_debug: |
@@ -358,55 +359,21 @@ static int ecryptfs_parse_options(struct super_block *sb, char *options) | |||
358 | if (!cipher_key_bytes_set) { | 359 | if (!cipher_key_bytes_set) { |
359 | mount_crypt_stat->global_default_cipher_key_size = 0; | 360 | mount_crypt_stat->global_default_cipher_key_size = 0; |
360 | } | 361 | } |
361 | rc = ecryptfs_process_cipher( | 362 | if ((rc = ecryptfs_add_new_key_tfm( |
362 | &mount_crypt_stat->global_key_tfm, | 363 | NULL, mount_crypt_stat->global_default_cipher_name, |
363 | mount_crypt_stat->global_default_cipher_name, | 364 | mount_crypt_stat->global_default_cipher_key_size))) { |
364 | &mount_crypt_stat->global_default_cipher_key_size); | 365 | printk(KERN_ERR "Error attempting to initialize cipher with " |
365 | if (rc) { | 366 | "name = [%s] and key size = [%d]; rc = [%d]\n", |
366 | printk(KERN_ERR "Error attempting to initialize cipher [%s] " | ||
367 | "with key size [%Zd] bytes; rc = [%d]\n", | ||
368 | mount_crypt_stat->global_default_cipher_name, | 367 | mount_crypt_stat->global_default_cipher_name, |
369 | mount_crypt_stat->global_default_cipher_key_size, rc); | 368 | mount_crypt_stat->global_default_cipher_key_size, rc); |
370 | mount_crypt_stat->global_key_tfm = NULL; | ||
371 | mount_crypt_stat->global_auth_tok_key = NULL; | ||
372 | rc = -EINVAL; | ||
373 | goto out; | ||
374 | } | ||
375 | mutex_init(&mount_crypt_stat->global_key_tfm_mutex); | ||
376 | ecryptfs_printk(KERN_DEBUG, "Requesting the key with description: " | ||
377 | "[%s]\n", mount_crypt_stat->global_auth_tok_sig); | ||
378 | /* The reference to this key is held until umount is done The | ||
379 | * call to key_put is done in ecryptfs_put_super() */ | ||
380 | auth_tok_key = request_key(&key_type_user, | ||
381 | mount_crypt_stat->global_auth_tok_sig, | ||
382 | NULL); | ||
383 | if (!auth_tok_key || IS_ERR(auth_tok_key)) { | ||
384 | ecryptfs_printk(KERN_ERR, "Could not find key with " | ||
385 | "description: [%s]\n", | ||
386 | mount_crypt_stat->global_auth_tok_sig); | ||
387 | process_request_key_err(PTR_ERR(auth_tok_key)); | ||
388 | rc = -EINVAL; | 369 | rc = -EINVAL; |
389 | goto out; | 370 | goto out; |
390 | } | 371 | } |
391 | auth_tok = ecryptfs_get_key_payload_data(auth_tok_key); | 372 | if ((rc = ecryptfs_init_global_auth_toks(mount_crypt_stat))) { |
392 | if (ecryptfs_verify_version(auth_tok->version)) { | 373 | printk(KERN_WARNING "One or more global auth toks could not " |
393 | ecryptfs_printk(KERN_ERR, "Data structure version mismatch. " | 374 | "properly register; rc = [%d]\n", rc); |
394 | "Userspace tools must match eCryptfs kernel " | ||
395 | "module with major version [%d] and minor " | ||
396 | "version [%d]\n", ECRYPTFS_VERSION_MAJOR, | ||
397 | ECRYPTFS_VERSION_MINOR); | ||
398 | rc = -EINVAL; | ||
399 | goto out; | ||
400 | } | ||
401 | if (auth_tok->token_type != ECRYPTFS_PASSWORD | ||
402 | && auth_tok->token_type != ECRYPTFS_PRIVATE_KEY) { | ||
403 | ecryptfs_printk(KERN_ERR, "Invalid auth_tok structure " | ||
404 | "returned from key query\n"); | ||
405 | rc = -EINVAL; | ||
406 | goto out; | ||
407 | } | 375 | } |
408 | mount_crypt_stat->global_auth_tok_key = auth_tok_key; | 376 | rc = 0; |
409 | mount_crypt_stat->global_auth_tok = auth_tok; | ||
410 | out: | 377 | out: |
411 | return rc; | 378 | return rc; |
412 | } | 379 | } |