aboutsummaryrefslogtreecommitdiffstats
path: root/security
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 /security
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>
Diffstat (limited to 'security')
-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
4 files changed, 180 insertions, 8 deletions
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;