aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRoberto Sassu <roberto.sassu@polito.it>2011-06-27 07:45:44 -0400
committerMimi Zohar <zohar@linux.vnet.ibm.com>2011-06-27 09:11:17 -0400
commit79a73d188726b473ca3bf483244bc96096831905 (patch)
tree787ba050c91981cae2524b1e95e415424b067e64
parentf8f8527103a264b5e4ab2ce5c1743b28f3219d90 (diff)
encrypted-keys: add ecryptfs format support
The 'encrypted' key type defines its own payload format which contains a symmetric key randomly generated that cannot be used directly to mount an eCryptfs filesystem, because it expects an authentication token structure. This patch introduces the new format 'ecryptfs' that allows to store an authentication token structure inside the encrypted key payload containing a randomly generated symmetric key, as the same for the format 'default'. More details about the usage of encrypted keys with the eCryptfs filesystem can be found in the file 'Documentation/keys-ecryptfs.txt'. Signed-off-by: Roberto Sassu <roberto.sassu@polito.it> Acked-by: Gianluca Ramunno <ramunno@polito.it> Acked-by: Tyler Hicks <tyhicks@linux.vnet.ibm.com> Signed-off-by: Mimi Zohar <zohar@linux.vnet.ibm.com>
-rw-r--r--Documentation/keys-ecryptfs.txt68
-rw-r--r--Documentation/security/keys-trusted-encrypted.txt6
-rw-r--r--security/keys/Makefile2
-rw-r--r--security/keys/ecryptfs_format.c81
-rw-r--r--security/keys/ecryptfs_format.h30
-rw-r--r--security/keys/encrypted.c75
6 files changed, 252 insertions, 10 deletions
diff --git a/Documentation/keys-ecryptfs.txt b/Documentation/keys-ecryptfs.txt
new file mode 100644
index 000000000000..c3bbeba63562
--- /dev/null
+++ b/Documentation/keys-ecryptfs.txt
@@ -0,0 +1,68 @@
1 Encrypted keys for the eCryptfs filesystem
2
3ECryptfs is a stacked filesystem which transparently encrypts and decrypts each
4file using a randomly generated File Encryption Key (FEK).
5
6Each FEK is in turn encrypted with a File Encryption Key Encryption Key (FEFEK)
7either in kernel space or in user space with a daemon called 'ecryptfsd'. In
8the former case the operation is performed directly by the kernel CryptoAPI
9using a key, the FEFEK, derived from a user prompted passphrase; in the latter
10the FEK is encrypted by 'ecryptfsd' with the help of external libraries in order
11to support other mechanisms like public key cryptography, PKCS#11 and TPM based
12operations.
13
14The data structure defined by eCryptfs to contain information required for the
15FEK decryption is called authentication token and, currently, can be stored in a
16kernel key of the 'user' type, inserted in the user's session specific keyring
17by the userspace utility 'mount.ecryptfs' shipped with the package
18'ecryptfs-utils'.
19
20The 'encrypted' key type has been extended with the introduction of the new
21format 'ecryptfs' in order to be used in conjunction with the eCryptfs
22filesystem. Encrypted keys of the newly introduced format store an
23authentication token in its payload with a FEFEK randomly generated by the
24kernel and protected by the parent master key.
25
26In order to avoid known-plaintext attacks, the datablob obtained through
27commands 'keyctl print' or 'keyctl pipe' does not contain the overall
28authentication token, which content is well known, but only the FEFEK in
29encrypted form.
30
31The eCryptfs filesystem may really benefit from using encrypted keys in that the
32required key can be securely generated by an Administrator and provided at boot
33time after the unsealing of a 'trusted' key in order to perform the mount in a
34controlled environment. Another advantage is that the key is not exposed to
35threats of malicious software, because it is available in clear form only at
36kernel level.
37
38Usage:
39 keyctl add encrypted name "new ecryptfs key-type:master-key-name keylen" ring
40 keyctl add encrypted name "load hex_blob" ring
41 keyctl update keyid "update key-type:master-key-name"
42
43name:= '<16 hexadecimal characters>'
44key-type:= 'trusted' | 'user'
45keylen:= 64
46
47
48Example of encrypted key usage with the eCryptfs filesystem:
49
50Create an encrypted key "1000100010001000" of length 64 bytes with format
51'ecryptfs' and save it using a previously loaded user key "test":
52
53 $ keyctl add encrypted 1000100010001000 "new ecryptfs user:test 64" @u
54 19184530
55
56 $ keyctl print 19184530
57 ecryptfs user:test 64 490045d4bfe48c99f0d465fbbbb79e7500da954178e2de0697
58 dd85091f5450a0511219e9f7cd70dcd498038181466f78ac8d4c19504fcc72402bfc41c2
59 f253a41b7507ccaa4b2b03fff19a69d1cc0b16e71746473f023a95488b6edfd86f7fdd40
60 9d292e4bacded1258880122dd553a661
61
62 $ keyctl pipe 19184530 > ecryptfs.blob
63
64Mount an eCryptfs filesystem using the created encrypted key "1000100010001000"
65into the '/secret' directory:
66
67 $ mount -i -t ecryptfs -oecryptfs_sig=1000100010001000,\
68 ecryptfs_cipher=aes,ecryptfs_key_bytes=32 /secret /secret
diff --git a/Documentation/security/keys-trusted-encrypted.txt b/Documentation/security/keys-trusted-encrypted.txt
index 0afcb5023c75..5f50ccabfc8a 100644
--- a/Documentation/security/keys-trusted-encrypted.txt
+++ b/Documentation/security/keys-trusted-encrypted.txt
@@ -63,7 +63,7 @@ Usage:
63 keyctl add encrypted name "load hex_blob" ring 63 keyctl add encrypted name "load hex_blob" ring
64 keyctl update keyid "update key-type:master-key-name" 64 keyctl update keyid "update key-type:master-key-name"
65 65
66format:= 'default' 66format:= 'default | ecryptfs'
67key-type:= 'trusted' | 'user' 67key-type:= 'trusted' | 'user'
68 68
69 69
@@ -154,4 +154,6 @@ Load an encrypted key "evm" from saved blob:
154 24717c64 5972dcb82ab2dde83376d82b2e3c09ffc 154 24717c64 5972dcb82ab2dde83376d82b2e3c09ffc
155 155
156Other uses for trusted and encrypted keys, such as for disk and file encryption 156Other uses for trusted and encrypted keys, such as for disk and file encryption
157are anticipated. 157are anticipated. In particular the new format 'ecryptfs' has been defined in
158in order to use encrypted keys to mount an eCryptfs filesystem. More details
159about the usage can be found in the file 'Documentation/keys-ecryptfs.txt'.
diff --git a/security/keys/Makefile b/security/keys/Makefile
index 1bf090a885fe..b34cc6ee6900 100644
--- a/security/keys/Makefile
+++ b/security/keys/Makefile
@@ -14,7 +14,7 @@ obj-y := \
14 user_defined.o 14 user_defined.o
15 15
16obj-$(CONFIG_TRUSTED_KEYS) += trusted.o 16obj-$(CONFIG_TRUSTED_KEYS) += trusted.o
17obj-$(CONFIG_ENCRYPTED_KEYS) += encrypted.o 17obj-$(CONFIG_ENCRYPTED_KEYS) += ecryptfs_format.o encrypted.o
18obj-$(CONFIG_KEYS_COMPAT) += compat.o 18obj-$(CONFIG_KEYS_COMPAT) += compat.o
19obj-$(CONFIG_PROC_FS) += proc.o 19obj-$(CONFIG_PROC_FS) += proc.o
20obj-$(CONFIG_SYSCTL) += sysctl.o 20obj-$(CONFIG_SYSCTL) += sysctl.o
diff --git a/security/keys/ecryptfs_format.c b/security/keys/ecryptfs_format.c
new file mode 100644
index 000000000000..6daa3b6ff9ed
--- /dev/null
+++ b/security/keys/ecryptfs_format.c
@@ -0,0 +1,81 @@
1/*
2 * ecryptfs_format.c: helper functions for the encrypted key type
3 *
4 * Copyright (C) 2006 International Business Machines Corp.
5 * Copyright (C) 2010 Politecnico di Torino, Italy
6 * TORSEC group -- http://security.polito.it
7 *
8 * Authors:
9 * Michael A. Halcrow <mahalcro@us.ibm.com>
10 * Tyler Hicks <tyhicks@ou.edu>
11 * Roberto Sassu <roberto.sassu@polito.it>
12 *
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation, version 2 of the License.
16 */
17
18#include <linux/module.h>
19#include "ecryptfs_format.h"
20
21u8 *ecryptfs_get_auth_tok_key(struct ecryptfs_auth_tok *auth_tok)
22{
23 return auth_tok->token.password.session_key_encryption_key;
24}
25EXPORT_SYMBOL(ecryptfs_get_auth_tok_key);
26
27/*
28 * ecryptfs_get_versions()
29 *
30 * Source code taken from the software 'ecryptfs-utils' version 83.
31 *
32 */
33void ecryptfs_get_versions(int *major, int *minor, int *file_version)
34{
35 *major = ECRYPTFS_VERSION_MAJOR;
36 *minor = ECRYPTFS_VERSION_MINOR;
37 if (file_version)
38 *file_version = ECRYPTFS_SUPPORTED_FILE_VERSION;
39}
40EXPORT_SYMBOL(ecryptfs_get_versions);
41
42/*
43 * ecryptfs_fill_auth_tok - fill the ecryptfs_auth_tok structure
44 *
45 * Fill the ecryptfs_auth_tok structure with required ecryptfs data.
46 * The source code is inspired to the original function generate_payload()
47 * shipped with the software 'ecryptfs-utils' version 83.
48 *
49 */
50int ecryptfs_fill_auth_tok(struct ecryptfs_auth_tok *auth_tok,
51 const char *key_desc)
52{
53 int major, minor;
54
55 ecryptfs_get_versions(&major, &minor, NULL);
56 auth_tok->version = (((uint16_t)(major << 8) & 0xFF00)
57 | ((uint16_t)minor & 0x00FF));
58 auth_tok->token_type = ECRYPTFS_PASSWORD;
59 strncpy((char *)auth_tok->token.password.signature, key_desc,
60 ECRYPTFS_PASSWORD_SIG_SIZE);
61 auth_tok->token.password.session_key_encryption_key_bytes =
62 ECRYPTFS_MAX_KEY_BYTES;
63 /*
64 * Removed auth_tok->token.password.salt and
65 * auth_tok->token.password.session_key_encryption_key
66 * initialization from the original code
67 */
68 /* TODO: Make the hash parameterizable via policy */
69 auth_tok->token.password.flags |=
70 ECRYPTFS_SESSION_KEY_ENCRYPTION_KEY_SET;
71 /* The kernel code will encrypt the session key. */
72 auth_tok->session_key.encrypted_key[0] = 0;
73 auth_tok->session_key.encrypted_key_size = 0;
74 /* Default; subject to change by kernel eCryptfs */
75 auth_tok->token.password.hash_algo = PGP_DIGEST_ALGO_SHA512;
76 auth_tok->token.password.flags &= ~(ECRYPTFS_PERSISTENT_PASSWORD);
77 return 0;
78}
79EXPORT_SYMBOL(ecryptfs_fill_auth_tok);
80
81MODULE_LICENSE("GPL");
diff --git a/security/keys/ecryptfs_format.h b/security/keys/ecryptfs_format.h
new file mode 100644
index 000000000000..40294de238bb
--- /dev/null
+++ b/security/keys/ecryptfs_format.h
@@ -0,0 +1,30 @@
1/*
2 * ecryptfs_format.h: helper functions for the encrypted key type
3 *
4 * Copyright (C) 2006 International Business Machines Corp.
5 * Copyright (C) 2010 Politecnico di Torino, Italy
6 * TORSEC group -- http://security.polito.it
7 *
8 * Authors:
9 * Michael A. Halcrow <mahalcro@us.ibm.com>
10 * Tyler Hicks <tyhicks@ou.edu>
11 * Roberto Sassu <roberto.sassu@polito.it>
12 *
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation, version 2 of the License.
16 */
17
18#ifndef __KEYS_ECRYPTFS_H
19#define __KEYS_ECRYPTFS_H
20
21#include <linux/ecryptfs.h>
22
23#define PGP_DIGEST_ALGO_SHA512 10
24
25u8 *ecryptfs_get_auth_tok_key(struct ecryptfs_auth_tok *auth_tok);
26void ecryptfs_get_versions(int *major, int *minor, int *file_version);
27int ecryptfs_fill_auth_tok(struct ecryptfs_auth_tok *auth_tok,
28 const char *key_desc);
29
30#endif /* __KEYS_ECRYPTFS_H */
diff --git a/security/keys/encrypted.c b/security/keys/encrypted.c
index 89981c987ba7..e7eca9ec4c65 100644
--- a/security/keys/encrypted.c
+++ b/security/keys/encrypted.c
@@ -29,11 +29,13 @@
29#include <linux/rcupdate.h> 29#include <linux/rcupdate.h>
30#include <linux/scatterlist.h> 30#include <linux/scatterlist.h>
31#include <linux/crypto.h> 31#include <linux/crypto.h>
32#include <linux/ctype.h>
32#include <crypto/hash.h> 33#include <crypto/hash.h>
33#include <crypto/sha.h> 34#include <crypto/sha.h>
34#include <crypto/aes.h> 35#include <crypto/aes.h>
35 36
36#include "encrypted.h" 37#include "encrypted.h"
38#include "ecryptfs_format.h"
37 39
38static const char KEY_TRUSTED_PREFIX[] = "trusted:"; 40static const char KEY_TRUSTED_PREFIX[] = "trusted:";
39static const char KEY_USER_PREFIX[] = "user:"; 41static const char KEY_USER_PREFIX[] = "user:";
@@ -41,11 +43,13 @@ static const char hash_alg[] = "sha256";
41static const char hmac_alg[] = "hmac(sha256)"; 43static const char hmac_alg[] = "hmac(sha256)";
42static const char blkcipher_alg[] = "cbc(aes)"; 44static const char blkcipher_alg[] = "cbc(aes)";
43static const char key_format_default[] = "default"; 45static const char key_format_default[] = "default";
46static const char key_format_ecryptfs[] = "ecryptfs";
44static unsigned int ivsize; 47static unsigned int ivsize;
45static int blksize; 48static int blksize;
46 49
47#define KEY_TRUSTED_PREFIX_LEN (sizeof (KEY_TRUSTED_PREFIX) - 1) 50#define KEY_TRUSTED_PREFIX_LEN (sizeof (KEY_TRUSTED_PREFIX) - 1)
48#define KEY_USER_PREFIX_LEN (sizeof (KEY_USER_PREFIX) - 1) 51#define KEY_USER_PREFIX_LEN (sizeof (KEY_USER_PREFIX) - 1)
52#define KEY_ECRYPTFS_DESC_LEN 16
49#define HASH_SIZE SHA256_DIGEST_SIZE 53#define HASH_SIZE SHA256_DIGEST_SIZE
50#define MAX_DATA_SIZE 4096 54#define MAX_DATA_SIZE 4096
51#define MIN_DATA_SIZE 20 55#define MIN_DATA_SIZE 20
@@ -63,11 +67,12 @@ enum {
63}; 67};
64 68
65enum { 69enum {
66 Opt_error = -1, Opt_default 70 Opt_error = -1, Opt_default, Opt_ecryptfs
67}; 71};
68 72
69static const match_table_t key_format_tokens = { 73static const match_table_t key_format_tokens = {
70 {Opt_default, "default"}, 74 {Opt_default, "default"},
75 {Opt_ecryptfs, "ecryptfs"},
71 {Opt_error, NULL} 76 {Opt_error, NULL}
72}; 77};
73 78
@@ -95,6 +100,34 @@ static int aes_get_sizes(void)
95} 100}
96 101
97/* 102/*
103 * valid_ecryptfs_desc - verify the description of a new/loaded encrypted key
104 *
105 * The description of a encrypted key with format 'ecryptfs' must contain
106 * exactly 16 hexadecimal characters.
107 *
108 */
109static int valid_ecryptfs_desc(const char *ecryptfs_desc)
110{
111 int i;
112
113 if (strlen(ecryptfs_desc) != KEY_ECRYPTFS_DESC_LEN) {
114 pr_err("encrypted_key: key description must be %d hexadecimal "
115 "characters long\n", KEY_ECRYPTFS_DESC_LEN);
116 return -EINVAL;
117 }
118
119 for (i = 0; i < KEY_ECRYPTFS_DESC_LEN; i++) {
120 if (!isxdigit(ecryptfs_desc[i])) {
121 pr_err("encrypted_key: key description must contain "
122 "only hexadecimal characters\n");
123 return -EINVAL;
124 }
125 }
126
127 return 0;
128}
129
130/*
98 * valid_master_desc - verify the 'key-type:desc' of a new/updated master-key 131 * valid_master_desc - verify the 'key-type:desc' of a new/updated master-key
99 * 132 *
100 * key-type:= "trusted:" | "user:" 133 * key-type:= "trusted:" | "user:"
@@ -158,7 +191,7 @@ static int datablob_parse(char *datablob, const char **format,
158 } 191 }
159 key_cmd = match_token(keyword, key_tokens, args); 192 key_cmd = match_token(keyword, key_tokens, args);
160 193
161 /* Get optional format: default */ 194 /* Get optional format: default | ecryptfs */
162 p = strsep(&datablob, " \t"); 195 p = strsep(&datablob, " \t");
163 if (!p) { 196 if (!p) {
164 pr_err("encrypted_key: insufficient parameters specified\n"); 197 pr_err("encrypted_key: insufficient parameters specified\n");
@@ -167,6 +200,7 @@ static int datablob_parse(char *datablob, const char **format,
167 200
168 key_format = match_token(p, key_format_tokens, args); 201 key_format = match_token(p, key_format_tokens, args);
169 switch (key_format) { 202 switch (key_format) {
203 case Opt_ecryptfs:
170 case Opt_default: 204 case Opt_default:
171 *format = p; 205 *format = p;
172 *master_desc = strsep(&datablob, " \t"); 206 *master_desc = strsep(&datablob, " \t");
@@ -601,6 +635,17 @@ static struct encrypted_key_payload *encrypted_key_alloc(struct key *key,
601 format_len = (!format) ? strlen(key_format_default) : strlen(format); 635 format_len = (!format) ? strlen(key_format_default) : strlen(format);
602 decrypted_datalen = dlen; 636 decrypted_datalen = dlen;
603 payload_datalen = decrypted_datalen; 637 payload_datalen = decrypted_datalen;
638 if (format && !strcmp(format, key_format_ecryptfs)) {
639 if (dlen != ECRYPTFS_MAX_KEY_BYTES) {
640 pr_err("encrypted_key: keylen for the ecryptfs format "
641 "must be equal to %d bytes\n",
642 ECRYPTFS_MAX_KEY_BYTES);
643 return ERR_PTR(-EINVAL);
644 }
645 decrypted_datalen = ECRYPTFS_MAX_KEY_BYTES;
646 payload_datalen = sizeof(struct ecryptfs_auth_tok);
647 }
648
604 encrypted_datalen = roundup(decrypted_datalen, blksize); 649 encrypted_datalen = roundup(decrypted_datalen, blksize);
605 650
606 datablob_len = format_len + 1 + strlen(master_desc) + 1 651 datablob_len = format_len + 1 + strlen(master_desc) + 1
@@ -686,8 +731,14 @@ static void __ekey_init(struct encrypted_key_payload *epayload,
686 731
687 if (!format) 732 if (!format)
688 memcpy(epayload->format, key_format_default, format_len); 733 memcpy(epayload->format, key_format_default, format_len);
689 else 734 else {
735 if (!strcmp(format, key_format_ecryptfs))
736 epayload->decrypted_data =
737 ecryptfs_get_auth_tok_key((struct ecryptfs_auth_tok *)epayload->payload_data);
738
690 memcpy(epayload->format, format, format_len); 739 memcpy(epayload->format, format, format_len);
740 }
741
691 memcpy(epayload->master_desc, master_desc, strlen(master_desc)); 742 memcpy(epayload->master_desc, master_desc, strlen(master_desc));
692 memcpy(epayload->datalen, datalen, strlen(datalen)); 743 memcpy(epayload->datalen, datalen, strlen(datalen));
693} 744}
@@ -699,11 +750,21 @@ static void __ekey_init(struct encrypted_key_payload *epayload,
699 * itself. For an old key, decrypt the hex encoded data. 750 * itself. For an old key, decrypt the hex encoded data.
700 */ 751 */
701static int encrypted_init(struct encrypted_key_payload *epayload, 752static int encrypted_init(struct encrypted_key_payload *epayload,
702 const char *format, const char *master_desc, 753 const char *key_desc, const char *format,
703 const char *datalen, const char *hex_encoded_iv) 754 const char *master_desc, const char *datalen,
755 const char *hex_encoded_iv)
704{ 756{
705 int ret = 0; 757 int ret = 0;
706 758
759 if (format && !strcmp(format, key_format_ecryptfs)) {
760 ret = valid_ecryptfs_desc(key_desc);
761 if (ret < 0)
762 return ret;
763
764 ecryptfs_fill_auth_tok((struct ecryptfs_auth_tok *)epayload->payload_data,
765 key_desc);
766 }
767
707 __ekey_init(epayload, format, master_desc, datalen); 768 __ekey_init(epayload, format, master_desc, datalen);
708 if (!hex_encoded_iv) { 769 if (!hex_encoded_iv) {
709 get_random_bytes(epayload->iv, ivsize); 770 get_random_bytes(epayload->iv, ivsize);
@@ -753,8 +814,8 @@ static int encrypted_instantiate(struct key *key, const void *data,
753 ret = PTR_ERR(epayload); 814 ret = PTR_ERR(epayload);
754 goto out; 815 goto out;
755 } 816 }
756 ret = encrypted_init(epayload, format, master_desc, decrypted_datalen, 817 ret = encrypted_init(epayload, key->description, format, master_desc,
757 hex_encoded_iv); 818 decrypted_datalen, hex_encoded_iv);
758 if (ret < 0) { 819 if (ret < 0) {
759 kfree(epayload); 820 kfree(epayload);
760 goto out; 821 goto out;