| Mimi Zohar | 7e70cb4 | 2010-11-23 18:55:35 -0500 | [diff] [blame] | 1 | /* | 
 | 2 |  * Copyright (C) 2010 IBM Corporation | 
| Roberto Sassu | 4e561d3 | 2011-06-27 13:45:42 +0200 | [diff] [blame] | 3 |  * Copyright (C) 2010 Politecnico di Torino, Italy | 
 | 4 |  *                    TORSEC group -- http://security.polito.it | 
| Mimi Zohar | 7e70cb4 | 2010-11-23 18:55:35 -0500 | [diff] [blame] | 5 |  * | 
| Roberto Sassu | 4e561d3 | 2011-06-27 13:45:42 +0200 | [diff] [blame] | 6 |  * Authors: | 
| Mimi Zohar | 7e70cb4 | 2010-11-23 18:55:35 -0500 | [diff] [blame] | 7 |  * Mimi Zohar <zohar@us.ibm.com> | 
| Roberto Sassu | 4e561d3 | 2011-06-27 13:45:42 +0200 | [diff] [blame] | 8 |  * Roberto Sassu <roberto.sassu@polito.it> | 
| Mimi Zohar | 7e70cb4 | 2010-11-23 18:55:35 -0500 | [diff] [blame] | 9 |  * | 
 | 10 |  * This program is free software; you can redistribute it and/or modify | 
 | 11 |  * it under the terms of the GNU General Public License as published by | 
 | 12 |  * the Free Software Foundation, version 2 of the License. | 
 | 13 |  * | 
| Randy Dunlap | d410fa4 | 2011-05-19 15:59:38 -0700 | [diff] [blame] | 14 |  * See Documentation/security/keys-trusted-encrypted.txt | 
| Mimi Zohar | 7e70cb4 | 2010-11-23 18:55:35 -0500 | [diff] [blame] | 15 |  */ | 
 | 16 |  | 
 | 17 | #include <linux/uaccess.h> | 
 | 18 | #include <linux/module.h> | 
 | 19 | #include <linux/init.h> | 
 | 20 | #include <linux/slab.h> | 
 | 21 | #include <linux/parser.h> | 
 | 22 | #include <linux/string.h> | 
| Mimi Zohar | 93ae86e | 2010-11-29 16:20:04 -0500 | [diff] [blame] | 23 | #include <linux/err.h> | 
| Mimi Zohar | 7e70cb4 | 2010-11-23 18:55:35 -0500 | [diff] [blame] | 24 | #include <keys/user-type.h> | 
 | 25 | #include <keys/trusted-type.h> | 
 | 26 | #include <keys/encrypted-type.h> | 
 | 27 | #include <linux/key-type.h> | 
 | 28 | #include <linux/random.h> | 
 | 29 | #include <linux/rcupdate.h> | 
 | 30 | #include <linux/scatterlist.h> | 
 | 31 | #include <linux/crypto.h> | 
| Roberto Sassu | 79a73d1 | 2011-06-27 13:45:44 +0200 | [diff] [blame] | 32 | #include <linux/ctype.h> | 
| Mimi Zohar | 7e70cb4 | 2010-11-23 18:55:35 -0500 | [diff] [blame] | 33 | #include <crypto/hash.h> | 
 | 34 | #include <crypto/sha.h> | 
 | 35 | #include <crypto/aes.h> | 
 | 36 |  | 
| Mimi Zohar | b970344 | 2011-01-18 09:07:12 -0500 | [diff] [blame] | 37 | #include "encrypted.h" | 
| Roberto Sassu | 79a73d1 | 2011-06-27 13:45:44 +0200 | [diff] [blame] | 38 | #include "ecryptfs_format.h" | 
| Mimi Zohar | 7e70cb4 | 2010-11-23 18:55:35 -0500 | [diff] [blame] | 39 |  | 
| Mimi Zohar | 3b1826c | 2010-12-13 16:53:13 -0500 | [diff] [blame] | 40 | static const char KEY_TRUSTED_PREFIX[] = "trusted:"; | 
 | 41 | static const char KEY_USER_PREFIX[] = "user:"; | 
| Mimi Zohar | 7e70cb4 | 2010-11-23 18:55:35 -0500 | [diff] [blame] | 42 | static const char hash_alg[] = "sha256"; | 
 | 43 | static const char hmac_alg[] = "hmac(sha256)"; | 
 | 44 | static const char blkcipher_alg[] = "cbc(aes)"; | 
| Roberto Sassu | 4e561d3 | 2011-06-27 13:45:42 +0200 | [diff] [blame] | 45 | static const char key_format_default[] = "default"; | 
| Roberto Sassu | 79a73d1 | 2011-06-27 13:45:44 +0200 | [diff] [blame] | 46 | static const char key_format_ecryptfs[] = "ecryptfs"; | 
| Mimi Zohar | 7e70cb4 | 2010-11-23 18:55:35 -0500 | [diff] [blame] | 47 | static unsigned int ivsize; | 
 | 48 | static int blksize; | 
 | 49 |  | 
| Mimi Zohar | 3b1826c | 2010-12-13 16:53:13 -0500 | [diff] [blame] | 50 | #define KEY_TRUSTED_PREFIX_LEN (sizeof (KEY_TRUSTED_PREFIX) - 1) | 
 | 51 | #define KEY_USER_PREFIX_LEN (sizeof (KEY_USER_PREFIX) - 1) | 
| Roberto Sassu | 79a73d1 | 2011-06-27 13:45:44 +0200 | [diff] [blame] | 52 | #define KEY_ECRYPTFS_DESC_LEN 16 | 
| Mimi Zohar | 3b1826c | 2010-12-13 16:53:13 -0500 | [diff] [blame] | 53 | #define HASH_SIZE SHA256_DIGEST_SIZE | 
 | 54 | #define MAX_DATA_SIZE 4096 | 
 | 55 | #define MIN_DATA_SIZE  20 | 
 | 56 |  | 
| Mimi Zohar | 7e70cb4 | 2010-11-23 18:55:35 -0500 | [diff] [blame] | 57 | struct sdesc { | 
 | 58 | 	struct shash_desc shash; | 
 | 59 | 	char ctx[]; | 
 | 60 | }; | 
 | 61 |  | 
 | 62 | static struct crypto_shash *hashalg; | 
 | 63 | static struct crypto_shash *hmacalg; | 
 | 64 |  | 
 | 65 | enum { | 
 | 66 | 	Opt_err = -1, Opt_new, Opt_load, Opt_update | 
 | 67 | }; | 
 | 68 |  | 
| Roberto Sassu | 4e561d3 | 2011-06-27 13:45:42 +0200 | [diff] [blame] | 69 | enum { | 
| Roberto Sassu | 79a73d1 | 2011-06-27 13:45:44 +0200 | [diff] [blame] | 70 | 	Opt_error = -1, Opt_default, Opt_ecryptfs | 
| Roberto Sassu | 4e561d3 | 2011-06-27 13:45:42 +0200 | [diff] [blame] | 71 | }; | 
 | 72 |  | 
 | 73 | static const match_table_t key_format_tokens = { | 
 | 74 | 	{Opt_default, "default"}, | 
| Roberto Sassu | 79a73d1 | 2011-06-27 13:45:44 +0200 | [diff] [blame] | 75 | 	{Opt_ecryptfs, "ecryptfs"}, | 
| Roberto Sassu | 4e561d3 | 2011-06-27 13:45:42 +0200 | [diff] [blame] | 76 | 	{Opt_error, NULL} | 
 | 77 | }; | 
 | 78 |  | 
| Mimi Zohar | 7e70cb4 | 2010-11-23 18:55:35 -0500 | [diff] [blame] | 79 | static const match_table_t key_tokens = { | 
 | 80 | 	{Opt_new, "new"}, | 
 | 81 | 	{Opt_load, "load"}, | 
 | 82 | 	{Opt_update, "update"}, | 
 | 83 | 	{Opt_err, NULL} | 
 | 84 | }; | 
 | 85 |  | 
 | 86 | static int aes_get_sizes(void) | 
 | 87 | { | 
 | 88 | 	struct crypto_blkcipher *tfm; | 
 | 89 |  | 
 | 90 | 	tfm = crypto_alloc_blkcipher(blkcipher_alg, 0, CRYPTO_ALG_ASYNC); | 
 | 91 | 	if (IS_ERR(tfm)) { | 
 | 92 | 		pr_err("encrypted_key: failed to alloc_cipher (%ld)\n", | 
 | 93 | 		       PTR_ERR(tfm)); | 
 | 94 | 		return PTR_ERR(tfm); | 
 | 95 | 	} | 
 | 96 | 	ivsize = crypto_blkcipher_ivsize(tfm); | 
 | 97 | 	blksize = crypto_blkcipher_blocksize(tfm); | 
 | 98 | 	crypto_free_blkcipher(tfm); | 
 | 99 | 	return 0; | 
 | 100 | } | 
 | 101 |  | 
 | 102 | /* | 
| Roberto Sassu | 79a73d1 | 2011-06-27 13:45:44 +0200 | [diff] [blame] | 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 |  */ | 
 | 109 | static 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 | /* | 
| Mimi Zohar | 7e70cb4 | 2010-11-23 18:55:35 -0500 | [diff] [blame] | 131 |  * valid_master_desc - verify the 'key-type:desc' of a new/updated master-key | 
 | 132 |  * | 
| Roberto Sassu | 08fa2aa | 2011-06-27 13:45:40 +0200 | [diff] [blame] | 133 |  * key-type:= "trusted:" | "user:" | 
| Mimi Zohar | 7e70cb4 | 2010-11-23 18:55:35 -0500 | [diff] [blame] | 134 |  * desc:= master-key description | 
 | 135 |  * | 
 | 136 |  * Verify that 'key-type' is valid and that 'desc' exists. On key update, | 
 | 137 |  * only the master key description is permitted to change, not the key-type. | 
 | 138 |  * The key-type remains constant. | 
 | 139 |  * | 
 | 140 |  * On success returns 0, otherwise -EINVAL. | 
 | 141 |  */ | 
 | 142 | static int valid_master_desc(const char *new_desc, const char *orig_desc) | 
 | 143 | { | 
 | 144 | 	if (!memcmp(new_desc, KEY_TRUSTED_PREFIX, KEY_TRUSTED_PREFIX_LEN)) { | 
 | 145 | 		if (strlen(new_desc) == KEY_TRUSTED_PREFIX_LEN) | 
 | 146 | 			goto out; | 
 | 147 | 		if (orig_desc) | 
 | 148 | 			if (memcmp(new_desc, orig_desc, KEY_TRUSTED_PREFIX_LEN)) | 
 | 149 | 				goto out; | 
 | 150 | 	} else if (!memcmp(new_desc, KEY_USER_PREFIX, KEY_USER_PREFIX_LEN)) { | 
 | 151 | 		if (strlen(new_desc) == KEY_USER_PREFIX_LEN) | 
 | 152 | 			goto out; | 
 | 153 | 		if (orig_desc) | 
 | 154 | 			if (memcmp(new_desc, orig_desc, KEY_USER_PREFIX_LEN)) | 
 | 155 | 				goto out; | 
 | 156 | 	} else | 
 | 157 | 		goto out; | 
 | 158 | 	return 0; | 
 | 159 | out: | 
 | 160 | 	return -EINVAL; | 
 | 161 | } | 
 | 162 |  | 
 | 163 | /* | 
 | 164 |  * datablob_parse - parse the keyctl data | 
 | 165 |  * | 
 | 166 |  * datablob format: | 
| Roberto Sassu | 4e561d3 | 2011-06-27 13:45:42 +0200 | [diff] [blame] | 167 |  * new [<format>] <master-key name> <decrypted data length> | 
 | 168 |  * load [<format>] <master-key name> <decrypted data length> | 
 | 169 |  *     <encrypted iv + data> | 
| Mimi Zohar | 7e70cb4 | 2010-11-23 18:55:35 -0500 | [diff] [blame] | 170 |  * update <new-master-key name> | 
 | 171 |  * | 
 | 172 |  * Tokenizes a copy of the keyctl data, returning a pointer to each token, | 
 | 173 |  * which is null terminated. | 
 | 174 |  * | 
 | 175 |  * On success returns 0, otherwise -EINVAL. | 
 | 176 |  */ | 
| Roberto Sassu | 4e561d3 | 2011-06-27 13:45:42 +0200 | [diff] [blame] | 177 | static int datablob_parse(char *datablob, const char **format, | 
 | 178 | 			  char **master_desc, char **decrypted_datalen, | 
 | 179 | 			  char **hex_encoded_iv) | 
| Mimi Zohar | 7e70cb4 | 2010-11-23 18:55:35 -0500 | [diff] [blame] | 180 | { | 
 | 181 | 	substring_t args[MAX_OPT_ARGS]; | 
 | 182 | 	int ret = -EINVAL; | 
 | 183 | 	int key_cmd; | 
| Roberto Sassu | 4e561d3 | 2011-06-27 13:45:42 +0200 | [diff] [blame] | 184 | 	int key_format; | 
 | 185 | 	char *p, *keyword; | 
| Mimi Zohar | 7e70cb4 | 2010-11-23 18:55:35 -0500 | [diff] [blame] | 186 |  | 
| Roberto Sassu | 7103dff | 2011-06-27 13:45:41 +0200 | [diff] [blame] | 187 | 	keyword = strsep(&datablob, " \t"); | 
 | 188 | 	if (!keyword) { | 
 | 189 | 		pr_info("encrypted_key: insufficient parameters specified\n"); | 
| Mimi Zohar | 7e70cb4 | 2010-11-23 18:55:35 -0500 | [diff] [blame] | 190 | 		return ret; | 
| Roberto Sassu | 7103dff | 2011-06-27 13:45:41 +0200 | [diff] [blame] | 191 | 	} | 
 | 192 | 	key_cmd = match_token(keyword, key_tokens, args); | 
| Mimi Zohar | 7e70cb4 | 2010-11-23 18:55:35 -0500 | [diff] [blame] | 193 |  | 
| Roberto Sassu | 79a73d1 | 2011-06-27 13:45:44 +0200 | [diff] [blame] | 194 | 	/* Get optional format: default | ecryptfs */ | 
| Roberto Sassu | 4e561d3 | 2011-06-27 13:45:42 +0200 | [diff] [blame] | 195 | 	p = strsep(&datablob, " \t"); | 
 | 196 | 	if (!p) { | 
 | 197 | 		pr_err("encrypted_key: insufficient parameters specified\n"); | 
 | 198 | 		return ret; | 
 | 199 | 	} | 
 | 200 |  | 
 | 201 | 	key_format = match_token(p, key_format_tokens, args); | 
 | 202 | 	switch (key_format) { | 
| Roberto Sassu | 79a73d1 | 2011-06-27 13:45:44 +0200 | [diff] [blame] | 203 | 	case Opt_ecryptfs: | 
| Roberto Sassu | 4e561d3 | 2011-06-27 13:45:42 +0200 | [diff] [blame] | 204 | 	case Opt_default: | 
 | 205 | 		*format = p; | 
 | 206 | 		*master_desc = strsep(&datablob, " \t"); | 
 | 207 | 		break; | 
 | 208 | 	case Opt_error: | 
 | 209 | 		*master_desc = p; | 
 | 210 | 		break; | 
 | 211 | 	} | 
 | 212 |  | 
| Roberto Sassu | 7103dff | 2011-06-27 13:45:41 +0200 | [diff] [blame] | 213 | 	if (!*master_desc) { | 
 | 214 | 		pr_info("encrypted_key: master key parameter is missing\n"); | 
| Mimi Zohar | 7e70cb4 | 2010-11-23 18:55:35 -0500 | [diff] [blame] | 215 | 		goto out; | 
| Roberto Sassu | 7103dff | 2011-06-27 13:45:41 +0200 | [diff] [blame] | 216 | 	} | 
| Mimi Zohar | 7e70cb4 | 2010-11-23 18:55:35 -0500 | [diff] [blame] | 217 |  | 
| Roberto Sassu | 7103dff | 2011-06-27 13:45:41 +0200 | [diff] [blame] | 218 | 	if (valid_master_desc(*master_desc, NULL) < 0) { | 
 | 219 | 		pr_info("encrypted_key: master key parameter \'%s\' " | 
 | 220 | 			"is invalid\n", *master_desc); | 
| Mimi Zohar | 7e70cb4 | 2010-11-23 18:55:35 -0500 | [diff] [blame] | 221 | 		goto out; | 
| Roberto Sassu | 7103dff | 2011-06-27 13:45:41 +0200 | [diff] [blame] | 222 | 	} | 
| Mimi Zohar | 7e70cb4 | 2010-11-23 18:55:35 -0500 | [diff] [blame] | 223 |  | 
 | 224 | 	if (decrypted_datalen) { | 
 | 225 | 		*decrypted_datalen = strsep(&datablob, " \t"); | 
| Roberto Sassu | 7103dff | 2011-06-27 13:45:41 +0200 | [diff] [blame] | 226 | 		if (!*decrypted_datalen) { | 
 | 227 | 			pr_info("encrypted_key: keylen parameter is missing\n"); | 
| Mimi Zohar | 7e70cb4 | 2010-11-23 18:55:35 -0500 | [diff] [blame] | 228 | 			goto out; | 
| Roberto Sassu | 7103dff | 2011-06-27 13:45:41 +0200 | [diff] [blame] | 229 | 		} | 
| Mimi Zohar | 7e70cb4 | 2010-11-23 18:55:35 -0500 | [diff] [blame] | 230 | 	} | 
 | 231 |  | 
 | 232 | 	switch (key_cmd) { | 
 | 233 | 	case Opt_new: | 
| Roberto Sassu | 7103dff | 2011-06-27 13:45:41 +0200 | [diff] [blame] | 234 | 		if (!decrypted_datalen) { | 
 | 235 | 			pr_info("encrypted_key: keyword \'%s\' not allowed " | 
 | 236 | 				"when called from .update method\n", keyword); | 
| Mimi Zohar | 7e70cb4 | 2010-11-23 18:55:35 -0500 | [diff] [blame] | 237 | 			break; | 
| Roberto Sassu | 7103dff | 2011-06-27 13:45:41 +0200 | [diff] [blame] | 238 | 		} | 
| Mimi Zohar | 7e70cb4 | 2010-11-23 18:55:35 -0500 | [diff] [blame] | 239 | 		ret = 0; | 
 | 240 | 		break; | 
 | 241 | 	case Opt_load: | 
| Roberto Sassu | 7103dff | 2011-06-27 13:45:41 +0200 | [diff] [blame] | 242 | 		if (!decrypted_datalen) { | 
 | 243 | 			pr_info("encrypted_key: keyword \'%s\' not allowed " | 
 | 244 | 				"when called from .update method\n", keyword); | 
| Mimi Zohar | 7e70cb4 | 2010-11-23 18:55:35 -0500 | [diff] [blame] | 245 | 			break; | 
| Roberto Sassu | 7103dff | 2011-06-27 13:45:41 +0200 | [diff] [blame] | 246 | 		} | 
| Mimi Zohar | 7e70cb4 | 2010-11-23 18:55:35 -0500 | [diff] [blame] | 247 | 		*hex_encoded_iv = strsep(&datablob, " \t"); | 
| Roberto Sassu | 7103dff | 2011-06-27 13:45:41 +0200 | [diff] [blame] | 248 | 		if (!*hex_encoded_iv) { | 
 | 249 | 			pr_info("encrypted_key: hex blob is missing\n"); | 
| Mimi Zohar | 7e70cb4 | 2010-11-23 18:55:35 -0500 | [diff] [blame] | 250 | 			break; | 
| Roberto Sassu | 7103dff | 2011-06-27 13:45:41 +0200 | [diff] [blame] | 251 | 		} | 
| Mimi Zohar | 7e70cb4 | 2010-11-23 18:55:35 -0500 | [diff] [blame] | 252 | 		ret = 0; | 
 | 253 | 		break; | 
 | 254 | 	case Opt_update: | 
| Roberto Sassu | 7103dff | 2011-06-27 13:45:41 +0200 | [diff] [blame] | 255 | 		if (decrypted_datalen) { | 
 | 256 | 			pr_info("encrypted_key: keyword \'%s\' not allowed " | 
 | 257 | 				"when called from .instantiate method\n", | 
 | 258 | 				keyword); | 
| Mimi Zohar | 7e70cb4 | 2010-11-23 18:55:35 -0500 | [diff] [blame] | 259 | 			break; | 
| Roberto Sassu | 7103dff | 2011-06-27 13:45:41 +0200 | [diff] [blame] | 260 | 		} | 
| Mimi Zohar | 7e70cb4 | 2010-11-23 18:55:35 -0500 | [diff] [blame] | 261 | 		ret = 0; | 
 | 262 | 		break; | 
 | 263 | 	case Opt_err: | 
| Roberto Sassu | 7103dff | 2011-06-27 13:45:41 +0200 | [diff] [blame] | 264 | 		pr_info("encrypted_key: keyword \'%s\' not recognized\n", | 
 | 265 | 			keyword); | 
| Mimi Zohar | 7e70cb4 | 2010-11-23 18:55:35 -0500 | [diff] [blame] | 266 | 		break; | 
 | 267 | 	} | 
 | 268 | out: | 
 | 269 | 	return ret; | 
 | 270 | } | 
 | 271 |  | 
 | 272 | /* | 
 | 273 |  * datablob_format - format as an ascii string, before copying to userspace | 
 | 274 |  */ | 
 | 275 | static char *datablob_format(struct encrypted_key_payload *epayload, | 
 | 276 | 			     size_t asciiblob_len) | 
 | 277 | { | 
 | 278 | 	char *ascii_buf, *bufp; | 
 | 279 | 	u8 *iv = epayload->iv; | 
 | 280 | 	int len; | 
 | 281 | 	int i; | 
 | 282 |  | 
 | 283 | 	ascii_buf = kmalloc(asciiblob_len + 1, GFP_KERNEL); | 
 | 284 | 	if (!ascii_buf) | 
 | 285 | 		goto out; | 
 | 286 |  | 
 | 287 | 	ascii_buf[asciiblob_len] = '\0'; | 
 | 288 |  | 
 | 289 | 	/* copy datablob master_desc and datalen strings */ | 
| Roberto Sassu | 4e561d3 | 2011-06-27 13:45:42 +0200 | [diff] [blame] | 290 | 	len = sprintf(ascii_buf, "%s %s %s ", epayload->format, | 
 | 291 | 		      epayload->master_desc, epayload->datalen); | 
| Mimi Zohar | 7e70cb4 | 2010-11-23 18:55:35 -0500 | [diff] [blame] | 292 |  | 
 | 293 | 	/* convert the hex encoded iv, encrypted-data and HMAC to ascii */ | 
 | 294 | 	bufp = &ascii_buf[len]; | 
 | 295 | 	for (i = 0; i < (asciiblob_len - len) / 2; i++) | 
| Andy Shevchenko | 0247311 | 2011-10-31 17:12:55 -0700 | [diff] [blame] | 296 | 		bufp = hex_byte_pack(bufp, iv[i]); | 
| Mimi Zohar | 7e70cb4 | 2010-11-23 18:55:35 -0500 | [diff] [blame] | 297 | out: | 
 | 298 | 	return ascii_buf; | 
 | 299 | } | 
 | 300 |  | 
 | 301 | /* | 
| Mimi Zohar | 7e70cb4 | 2010-11-23 18:55:35 -0500 | [diff] [blame] | 302 |  * request_user_key - request the user key | 
 | 303 |  * | 
 | 304 |  * Use a user provided key to encrypt/decrypt an encrypted-key. | 
 | 305 |  */ | 
 | 306 | static struct key *request_user_key(const char *master_desc, u8 **master_key, | 
| Mimi Zohar | 3b1826c | 2010-12-13 16:53:13 -0500 | [diff] [blame] | 307 | 				    size_t *master_keylen) | 
| Mimi Zohar | 7e70cb4 | 2010-11-23 18:55:35 -0500 | [diff] [blame] | 308 | { | 
 | 309 | 	struct user_key_payload *upayload; | 
 | 310 | 	struct key *ukey; | 
 | 311 |  | 
 | 312 | 	ukey = request_key(&key_type_user, master_desc, NULL); | 
 | 313 | 	if (IS_ERR(ukey)) | 
 | 314 | 		goto error; | 
 | 315 |  | 
 | 316 | 	down_read(&ukey->sem); | 
| Mimi Zohar | 6ac6172 | 2012-01-17 20:40:02 +0000 | [diff] [blame] | 317 | 	upayload = ukey->payload.data; | 
| Mimi Zohar | 7e70cb4 | 2010-11-23 18:55:35 -0500 | [diff] [blame] | 318 | 	*master_key = upayload->data; | 
 | 319 | 	*master_keylen = upayload->datalen; | 
 | 320 | error: | 
 | 321 | 	return ukey; | 
 | 322 | } | 
 | 323 |  | 
| Mimi Zohar | 3b1826c | 2010-12-13 16:53:13 -0500 | [diff] [blame] | 324 | static struct sdesc *alloc_sdesc(struct crypto_shash *alg) | 
| Mimi Zohar | 7e70cb4 | 2010-11-23 18:55:35 -0500 | [diff] [blame] | 325 | { | 
 | 326 | 	struct sdesc *sdesc; | 
 | 327 | 	int size; | 
 | 328 |  | 
 | 329 | 	size = sizeof(struct shash_desc) + crypto_shash_descsize(alg); | 
 | 330 | 	sdesc = kmalloc(size, GFP_KERNEL); | 
 | 331 | 	if (!sdesc) | 
 | 332 | 		return ERR_PTR(-ENOMEM); | 
 | 333 | 	sdesc->shash.tfm = alg; | 
 | 334 | 	sdesc->shash.flags = 0x0; | 
 | 335 | 	return sdesc; | 
 | 336 | } | 
 | 337 |  | 
| Mimi Zohar | 3b1826c | 2010-12-13 16:53:13 -0500 | [diff] [blame] | 338 | static int calc_hmac(u8 *digest, const u8 *key, unsigned int keylen, | 
 | 339 | 		     const u8 *buf, unsigned int buflen) | 
| Mimi Zohar | 7e70cb4 | 2010-11-23 18:55:35 -0500 | [diff] [blame] | 340 | { | 
 | 341 | 	struct sdesc *sdesc; | 
 | 342 | 	int ret; | 
 | 343 |  | 
| Mimi Zohar | 3b1826c | 2010-12-13 16:53:13 -0500 | [diff] [blame] | 344 | 	sdesc = alloc_sdesc(hmacalg); | 
| Mimi Zohar | 7e70cb4 | 2010-11-23 18:55:35 -0500 | [diff] [blame] | 345 | 	if (IS_ERR(sdesc)) { | 
 | 346 | 		pr_info("encrypted_key: can't alloc %s\n", hmac_alg); | 
 | 347 | 		return PTR_ERR(sdesc); | 
 | 348 | 	} | 
 | 349 |  | 
 | 350 | 	ret = crypto_shash_setkey(hmacalg, key, keylen); | 
 | 351 | 	if (!ret) | 
 | 352 | 		ret = crypto_shash_digest(&sdesc->shash, buf, buflen, digest); | 
 | 353 | 	kfree(sdesc); | 
 | 354 | 	return ret; | 
 | 355 | } | 
 | 356 |  | 
| Mimi Zohar | 3b1826c | 2010-12-13 16:53:13 -0500 | [diff] [blame] | 357 | static int calc_hash(u8 *digest, const u8 *buf, unsigned int buflen) | 
| Mimi Zohar | 7e70cb4 | 2010-11-23 18:55:35 -0500 | [diff] [blame] | 358 | { | 
 | 359 | 	struct sdesc *sdesc; | 
 | 360 | 	int ret; | 
 | 361 |  | 
| Mimi Zohar | 3b1826c | 2010-12-13 16:53:13 -0500 | [diff] [blame] | 362 | 	sdesc = alloc_sdesc(hashalg); | 
| Mimi Zohar | 7e70cb4 | 2010-11-23 18:55:35 -0500 | [diff] [blame] | 363 | 	if (IS_ERR(sdesc)) { | 
 | 364 | 		pr_info("encrypted_key: can't alloc %s\n", hash_alg); | 
 | 365 | 		return PTR_ERR(sdesc); | 
 | 366 | 	} | 
 | 367 |  | 
 | 368 | 	ret = crypto_shash_digest(&sdesc->shash, buf, buflen, digest); | 
 | 369 | 	kfree(sdesc); | 
 | 370 | 	return ret; | 
 | 371 | } | 
 | 372 |  | 
 | 373 | enum derived_key_type { ENC_KEY, AUTH_KEY }; | 
 | 374 |  | 
 | 375 | /* Derive authentication/encryption key from trusted key */ | 
 | 376 | static int get_derived_key(u8 *derived_key, enum derived_key_type key_type, | 
| Mimi Zohar | 3b1826c | 2010-12-13 16:53:13 -0500 | [diff] [blame] | 377 | 			   const u8 *master_key, size_t master_keylen) | 
| Mimi Zohar | 7e70cb4 | 2010-11-23 18:55:35 -0500 | [diff] [blame] | 378 | { | 
 | 379 | 	u8 *derived_buf; | 
 | 380 | 	unsigned int derived_buf_len; | 
 | 381 | 	int ret; | 
 | 382 |  | 
 | 383 | 	derived_buf_len = strlen("AUTH_KEY") + 1 + master_keylen; | 
 | 384 | 	if (derived_buf_len < HASH_SIZE) | 
 | 385 | 		derived_buf_len = HASH_SIZE; | 
 | 386 |  | 
 | 387 | 	derived_buf = kzalloc(derived_buf_len, GFP_KERNEL); | 
 | 388 | 	if (!derived_buf) { | 
 | 389 | 		pr_err("encrypted_key: out of memory\n"); | 
 | 390 | 		return -ENOMEM; | 
 | 391 | 	} | 
 | 392 | 	if (key_type) | 
 | 393 | 		strcpy(derived_buf, "AUTH_KEY"); | 
 | 394 | 	else | 
 | 395 | 		strcpy(derived_buf, "ENC_KEY"); | 
 | 396 |  | 
 | 397 | 	memcpy(derived_buf + strlen(derived_buf) + 1, master_key, | 
 | 398 | 	       master_keylen); | 
 | 399 | 	ret = calc_hash(derived_key, derived_buf, derived_buf_len); | 
 | 400 | 	kfree(derived_buf); | 
 | 401 | 	return ret; | 
 | 402 | } | 
 | 403 |  | 
 | 404 | static int init_blkcipher_desc(struct blkcipher_desc *desc, const u8 *key, | 
| Mimi Zohar | 3b1826c | 2010-12-13 16:53:13 -0500 | [diff] [blame] | 405 | 			       unsigned int key_len, const u8 *iv, | 
 | 406 | 			       unsigned int ivsize) | 
| Mimi Zohar | 7e70cb4 | 2010-11-23 18:55:35 -0500 | [diff] [blame] | 407 | { | 
 | 408 | 	int ret; | 
 | 409 |  | 
 | 410 | 	desc->tfm = crypto_alloc_blkcipher(blkcipher_alg, 0, CRYPTO_ALG_ASYNC); | 
 | 411 | 	if (IS_ERR(desc->tfm)) { | 
 | 412 | 		pr_err("encrypted_key: failed to load %s transform (%ld)\n", | 
 | 413 | 		       blkcipher_alg, PTR_ERR(desc->tfm)); | 
 | 414 | 		return PTR_ERR(desc->tfm); | 
 | 415 | 	} | 
 | 416 | 	desc->flags = 0; | 
 | 417 |  | 
 | 418 | 	ret = crypto_blkcipher_setkey(desc->tfm, key, key_len); | 
 | 419 | 	if (ret < 0) { | 
 | 420 | 		pr_err("encrypted_key: failed to setkey (%d)\n", ret); | 
 | 421 | 		crypto_free_blkcipher(desc->tfm); | 
 | 422 | 		return ret; | 
 | 423 | 	} | 
 | 424 | 	crypto_blkcipher_set_iv(desc->tfm, iv, ivsize); | 
 | 425 | 	return 0; | 
 | 426 | } | 
 | 427 |  | 
 | 428 | static struct key *request_master_key(struct encrypted_key_payload *epayload, | 
| Mimi Zohar | 3b1826c | 2010-12-13 16:53:13 -0500 | [diff] [blame] | 429 | 				      u8 **master_key, size_t *master_keylen) | 
| Mimi Zohar | 7e70cb4 | 2010-11-23 18:55:35 -0500 | [diff] [blame] | 430 | { | 
 | 431 | 	struct key *mkey = NULL; | 
 | 432 |  | 
 | 433 | 	if (!strncmp(epayload->master_desc, KEY_TRUSTED_PREFIX, | 
 | 434 | 		     KEY_TRUSTED_PREFIX_LEN)) { | 
 | 435 | 		mkey = request_trusted_key(epayload->master_desc + | 
 | 436 | 					   KEY_TRUSTED_PREFIX_LEN, | 
 | 437 | 					   master_key, master_keylen); | 
 | 438 | 	} else if (!strncmp(epayload->master_desc, KEY_USER_PREFIX, | 
 | 439 | 			    KEY_USER_PREFIX_LEN)) { | 
 | 440 | 		mkey = request_user_key(epayload->master_desc + | 
 | 441 | 					KEY_USER_PREFIX_LEN, | 
 | 442 | 					master_key, master_keylen); | 
 | 443 | 	} else | 
 | 444 | 		goto out; | 
 | 445 |  | 
| Roberto Sassu | f91c2c5 | 2011-06-27 13:45:39 +0200 | [diff] [blame] | 446 | 	if (IS_ERR(mkey)) { | 
| Mimi Zohar | f4a0d5a | 2011-10-24 08:17:42 -0400 | [diff] [blame] | 447 | 		int ret = PTR_ERR(mkey); | 
| Mimi Zohar | 982e617 | 2011-08-27 22:21:26 -0400 | [diff] [blame] | 448 |  | 
 | 449 | 		if (ret == -ENOTSUPP) | 
 | 450 | 			pr_info("encrypted_key: key %s not supported", | 
 | 451 | 				epayload->master_desc); | 
 | 452 | 		else | 
 | 453 | 			pr_info("encrypted_key: key %s not found", | 
 | 454 | 				epayload->master_desc); | 
| Roberto Sassu | f91c2c5 | 2011-06-27 13:45:39 +0200 | [diff] [blame] | 455 | 		goto out; | 
 | 456 | 	} | 
 | 457 |  | 
 | 458 | 	dump_master_key(*master_key, *master_keylen); | 
| Mimi Zohar | 7e70cb4 | 2010-11-23 18:55:35 -0500 | [diff] [blame] | 459 | out: | 
 | 460 | 	return mkey; | 
 | 461 | } | 
 | 462 |  | 
 | 463 | /* Before returning data to userspace, encrypt decrypted data. */ | 
 | 464 | static int derived_key_encrypt(struct encrypted_key_payload *epayload, | 
 | 465 | 			       const u8 *derived_key, | 
| Mimi Zohar | 3b1826c | 2010-12-13 16:53:13 -0500 | [diff] [blame] | 466 | 			       unsigned int derived_keylen) | 
| Mimi Zohar | 7e70cb4 | 2010-11-23 18:55:35 -0500 | [diff] [blame] | 467 | { | 
 | 468 | 	struct scatterlist sg_in[2]; | 
 | 469 | 	struct scatterlist sg_out[1]; | 
 | 470 | 	struct blkcipher_desc desc; | 
 | 471 | 	unsigned int encrypted_datalen; | 
 | 472 | 	unsigned int padlen; | 
 | 473 | 	char pad[16]; | 
 | 474 | 	int ret; | 
 | 475 |  | 
 | 476 | 	encrypted_datalen = roundup(epayload->decrypted_datalen, blksize); | 
 | 477 | 	padlen = encrypted_datalen - epayload->decrypted_datalen; | 
 | 478 |  | 
 | 479 | 	ret = init_blkcipher_desc(&desc, derived_key, derived_keylen, | 
 | 480 | 				  epayload->iv, ivsize); | 
 | 481 | 	if (ret < 0) | 
 | 482 | 		goto out; | 
 | 483 | 	dump_decrypted_data(epayload); | 
 | 484 |  | 
 | 485 | 	memset(pad, 0, sizeof pad); | 
 | 486 | 	sg_init_table(sg_in, 2); | 
 | 487 | 	sg_set_buf(&sg_in[0], epayload->decrypted_data, | 
 | 488 | 		   epayload->decrypted_datalen); | 
 | 489 | 	sg_set_buf(&sg_in[1], pad, padlen); | 
 | 490 |  | 
 | 491 | 	sg_init_table(sg_out, 1); | 
 | 492 | 	sg_set_buf(sg_out, epayload->encrypted_data, encrypted_datalen); | 
 | 493 |  | 
 | 494 | 	ret = crypto_blkcipher_encrypt(&desc, sg_out, sg_in, encrypted_datalen); | 
 | 495 | 	crypto_free_blkcipher(desc.tfm); | 
 | 496 | 	if (ret < 0) | 
 | 497 | 		pr_err("encrypted_key: failed to encrypt (%d)\n", ret); | 
 | 498 | 	else | 
 | 499 | 		dump_encrypted_data(epayload, encrypted_datalen); | 
 | 500 | out: | 
 | 501 | 	return ret; | 
 | 502 | } | 
 | 503 |  | 
 | 504 | static int datablob_hmac_append(struct encrypted_key_payload *epayload, | 
| Mimi Zohar | 3b1826c | 2010-12-13 16:53:13 -0500 | [diff] [blame] | 505 | 				const u8 *master_key, size_t master_keylen) | 
| Mimi Zohar | 7e70cb4 | 2010-11-23 18:55:35 -0500 | [diff] [blame] | 506 | { | 
 | 507 | 	u8 derived_key[HASH_SIZE]; | 
 | 508 | 	u8 *digest; | 
 | 509 | 	int ret; | 
 | 510 |  | 
 | 511 | 	ret = get_derived_key(derived_key, AUTH_KEY, master_key, master_keylen); | 
 | 512 | 	if (ret < 0) | 
 | 513 | 		goto out; | 
 | 514 |  | 
| Roberto Sassu | 4e561d3 | 2011-06-27 13:45:42 +0200 | [diff] [blame] | 515 | 	digest = epayload->format + epayload->datablob_len; | 
| Mimi Zohar | 7e70cb4 | 2010-11-23 18:55:35 -0500 | [diff] [blame] | 516 | 	ret = calc_hmac(digest, derived_key, sizeof derived_key, | 
| Roberto Sassu | 4e561d3 | 2011-06-27 13:45:42 +0200 | [diff] [blame] | 517 | 			epayload->format, epayload->datablob_len); | 
| Mimi Zohar | 7e70cb4 | 2010-11-23 18:55:35 -0500 | [diff] [blame] | 518 | 	if (!ret) | 
 | 519 | 		dump_hmac(NULL, digest, HASH_SIZE); | 
 | 520 | out: | 
 | 521 | 	return ret; | 
 | 522 | } | 
 | 523 |  | 
 | 524 | /* verify HMAC before decrypting encrypted key */ | 
 | 525 | static int datablob_hmac_verify(struct encrypted_key_payload *epayload, | 
| Roberto Sassu | 4e561d3 | 2011-06-27 13:45:42 +0200 | [diff] [blame] | 526 | 				const u8 *format, const u8 *master_key, | 
 | 527 | 				size_t master_keylen) | 
| Mimi Zohar | 7e70cb4 | 2010-11-23 18:55:35 -0500 | [diff] [blame] | 528 | { | 
 | 529 | 	u8 derived_key[HASH_SIZE]; | 
 | 530 | 	u8 digest[HASH_SIZE]; | 
 | 531 | 	int ret; | 
| Roberto Sassu | 4e561d3 | 2011-06-27 13:45:42 +0200 | [diff] [blame] | 532 | 	char *p; | 
 | 533 | 	unsigned short len; | 
| Mimi Zohar | 7e70cb4 | 2010-11-23 18:55:35 -0500 | [diff] [blame] | 534 |  | 
 | 535 | 	ret = get_derived_key(derived_key, AUTH_KEY, master_key, master_keylen); | 
 | 536 | 	if (ret < 0) | 
 | 537 | 		goto out; | 
 | 538 |  | 
| Roberto Sassu | 4e561d3 | 2011-06-27 13:45:42 +0200 | [diff] [blame] | 539 | 	len = epayload->datablob_len; | 
 | 540 | 	if (!format) { | 
 | 541 | 		p = epayload->master_desc; | 
 | 542 | 		len -= strlen(epayload->format) + 1; | 
 | 543 | 	} else | 
 | 544 | 		p = epayload->format; | 
 | 545 |  | 
 | 546 | 	ret = calc_hmac(digest, derived_key, sizeof derived_key, p, len); | 
| Mimi Zohar | 7e70cb4 | 2010-11-23 18:55:35 -0500 | [diff] [blame] | 547 | 	if (ret < 0) | 
 | 548 | 		goto out; | 
| Roberto Sassu | 4e561d3 | 2011-06-27 13:45:42 +0200 | [diff] [blame] | 549 | 	ret = memcmp(digest, epayload->format + epayload->datablob_len, | 
| Mimi Zohar | 7e70cb4 | 2010-11-23 18:55:35 -0500 | [diff] [blame] | 550 | 		     sizeof digest); | 
 | 551 | 	if (ret) { | 
 | 552 | 		ret = -EINVAL; | 
 | 553 | 		dump_hmac("datablob", | 
| Roberto Sassu | 4e561d3 | 2011-06-27 13:45:42 +0200 | [diff] [blame] | 554 | 			  epayload->format + epayload->datablob_len, | 
| Mimi Zohar | 7e70cb4 | 2010-11-23 18:55:35 -0500 | [diff] [blame] | 555 | 			  HASH_SIZE); | 
 | 556 | 		dump_hmac("calc", digest, HASH_SIZE); | 
 | 557 | 	} | 
 | 558 | out: | 
 | 559 | 	return ret; | 
 | 560 | } | 
 | 561 |  | 
 | 562 | static int derived_key_decrypt(struct encrypted_key_payload *epayload, | 
 | 563 | 			       const u8 *derived_key, | 
| Mimi Zohar | 3b1826c | 2010-12-13 16:53:13 -0500 | [diff] [blame] | 564 | 			       unsigned int derived_keylen) | 
| Mimi Zohar | 7e70cb4 | 2010-11-23 18:55:35 -0500 | [diff] [blame] | 565 | { | 
 | 566 | 	struct scatterlist sg_in[1]; | 
 | 567 | 	struct scatterlist sg_out[2]; | 
 | 568 | 	struct blkcipher_desc desc; | 
 | 569 | 	unsigned int encrypted_datalen; | 
 | 570 | 	char pad[16]; | 
 | 571 | 	int ret; | 
 | 572 |  | 
 | 573 | 	encrypted_datalen = roundup(epayload->decrypted_datalen, blksize); | 
 | 574 | 	ret = init_blkcipher_desc(&desc, derived_key, derived_keylen, | 
 | 575 | 				  epayload->iv, ivsize); | 
 | 576 | 	if (ret < 0) | 
 | 577 | 		goto out; | 
 | 578 | 	dump_encrypted_data(epayload, encrypted_datalen); | 
 | 579 |  | 
 | 580 | 	memset(pad, 0, sizeof pad); | 
 | 581 | 	sg_init_table(sg_in, 1); | 
 | 582 | 	sg_init_table(sg_out, 2); | 
 | 583 | 	sg_set_buf(sg_in, epayload->encrypted_data, encrypted_datalen); | 
 | 584 | 	sg_set_buf(&sg_out[0], epayload->decrypted_data, | 
| Mimi Zohar | 3b1826c | 2010-12-13 16:53:13 -0500 | [diff] [blame] | 585 | 		   epayload->decrypted_datalen); | 
| Mimi Zohar | 7e70cb4 | 2010-11-23 18:55:35 -0500 | [diff] [blame] | 586 | 	sg_set_buf(&sg_out[1], pad, sizeof pad); | 
 | 587 |  | 
 | 588 | 	ret = crypto_blkcipher_decrypt(&desc, sg_out, sg_in, encrypted_datalen); | 
 | 589 | 	crypto_free_blkcipher(desc.tfm); | 
 | 590 | 	if (ret < 0) | 
 | 591 | 		goto out; | 
 | 592 | 	dump_decrypted_data(epayload); | 
 | 593 | out: | 
 | 594 | 	return ret; | 
 | 595 | } | 
 | 596 |  | 
 | 597 | /* Allocate memory for decrypted key and datablob. */ | 
 | 598 | static struct encrypted_key_payload *encrypted_key_alloc(struct key *key, | 
| Roberto Sassu | 4e561d3 | 2011-06-27 13:45:42 +0200 | [diff] [blame] | 599 | 							 const char *format, | 
| Mimi Zohar | 7e70cb4 | 2010-11-23 18:55:35 -0500 | [diff] [blame] | 600 | 							 const char *master_desc, | 
 | 601 | 							 const char *datalen) | 
 | 602 | { | 
 | 603 | 	struct encrypted_key_payload *epayload = NULL; | 
 | 604 | 	unsigned short datablob_len; | 
 | 605 | 	unsigned short decrypted_datalen; | 
| Roberto Sassu | 4e561d3 | 2011-06-27 13:45:42 +0200 | [diff] [blame] | 606 | 	unsigned short payload_datalen; | 
| Mimi Zohar | 7e70cb4 | 2010-11-23 18:55:35 -0500 | [diff] [blame] | 607 | 	unsigned int encrypted_datalen; | 
| Roberto Sassu | 4e561d3 | 2011-06-27 13:45:42 +0200 | [diff] [blame] | 608 | 	unsigned int format_len; | 
| Mimi Zohar | 7e70cb4 | 2010-11-23 18:55:35 -0500 | [diff] [blame] | 609 | 	long dlen; | 
 | 610 | 	int ret; | 
 | 611 |  | 
 | 612 | 	ret = strict_strtol(datalen, 10, &dlen); | 
 | 613 | 	if (ret < 0 || dlen < MIN_DATA_SIZE || dlen > MAX_DATA_SIZE) | 
 | 614 | 		return ERR_PTR(-EINVAL); | 
 | 615 |  | 
| Roberto Sassu | 4e561d3 | 2011-06-27 13:45:42 +0200 | [diff] [blame] | 616 | 	format_len = (!format) ? strlen(key_format_default) : strlen(format); | 
| Mimi Zohar | 7e70cb4 | 2010-11-23 18:55:35 -0500 | [diff] [blame] | 617 | 	decrypted_datalen = dlen; | 
| Roberto Sassu | 4e561d3 | 2011-06-27 13:45:42 +0200 | [diff] [blame] | 618 | 	payload_datalen = decrypted_datalen; | 
| Roberto Sassu | 79a73d1 | 2011-06-27 13:45:44 +0200 | [diff] [blame] | 619 | 	if (format && !strcmp(format, key_format_ecryptfs)) { | 
 | 620 | 		if (dlen != ECRYPTFS_MAX_KEY_BYTES) { | 
 | 621 | 			pr_err("encrypted_key: keylen for the ecryptfs format " | 
 | 622 | 			       "must be equal to %d bytes\n", | 
 | 623 | 			       ECRYPTFS_MAX_KEY_BYTES); | 
 | 624 | 			return ERR_PTR(-EINVAL); | 
 | 625 | 		} | 
 | 626 | 		decrypted_datalen = ECRYPTFS_MAX_KEY_BYTES; | 
 | 627 | 		payload_datalen = sizeof(struct ecryptfs_auth_tok); | 
 | 628 | 	} | 
 | 629 |  | 
| Mimi Zohar | 7e70cb4 | 2010-11-23 18:55:35 -0500 | [diff] [blame] | 630 | 	encrypted_datalen = roundup(decrypted_datalen, blksize); | 
 | 631 |  | 
| Roberto Sassu | 4e561d3 | 2011-06-27 13:45:42 +0200 | [diff] [blame] | 632 | 	datablob_len = format_len + 1 + strlen(master_desc) + 1 | 
 | 633 | 	    + strlen(datalen) + 1 + ivsize + 1 + encrypted_datalen; | 
| Mimi Zohar | 7e70cb4 | 2010-11-23 18:55:35 -0500 | [diff] [blame] | 634 |  | 
| Roberto Sassu | 4e561d3 | 2011-06-27 13:45:42 +0200 | [diff] [blame] | 635 | 	ret = key_payload_reserve(key, payload_datalen + datablob_len | 
| Mimi Zohar | 7e70cb4 | 2010-11-23 18:55:35 -0500 | [diff] [blame] | 636 | 				  + HASH_SIZE + 1); | 
 | 637 | 	if (ret < 0) | 
 | 638 | 		return ERR_PTR(ret); | 
 | 639 |  | 
| Roberto Sassu | 4e561d3 | 2011-06-27 13:45:42 +0200 | [diff] [blame] | 640 | 	epayload = kzalloc(sizeof(*epayload) + payload_datalen + | 
| Mimi Zohar | 7e70cb4 | 2010-11-23 18:55:35 -0500 | [diff] [blame] | 641 | 			   datablob_len + HASH_SIZE + 1, GFP_KERNEL); | 
 | 642 | 	if (!epayload) | 
 | 643 | 		return ERR_PTR(-ENOMEM); | 
 | 644 |  | 
| Roberto Sassu | 4e561d3 | 2011-06-27 13:45:42 +0200 | [diff] [blame] | 645 | 	epayload->payload_datalen = payload_datalen; | 
| Mimi Zohar | 7e70cb4 | 2010-11-23 18:55:35 -0500 | [diff] [blame] | 646 | 	epayload->decrypted_datalen = decrypted_datalen; | 
 | 647 | 	epayload->datablob_len = datablob_len; | 
 | 648 | 	return epayload; | 
 | 649 | } | 
 | 650 |  | 
 | 651 | static int encrypted_key_decrypt(struct encrypted_key_payload *epayload, | 
| Roberto Sassu | 4e561d3 | 2011-06-27 13:45:42 +0200 | [diff] [blame] | 652 | 				 const char *format, const char *hex_encoded_iv) | 
| Mimi Zohar | 7e70cb4 | 2010-11-23 18:55:35 -0500 | [diff] [blame] | 653 | { | 
 | 654 | 	struct key *mkey; | 
 | 655 | 	u8 derived_key[HASH_SIZE]; | 
 | 656 | 	u8 *master_key; | 
 | 657 | 	u8 *hmac; | 
| Mimi Zohar | 1f35065 | 2010-12-13 16:53:12 -0500 | [diff] [blame] | 658 | 	const char *hex_encoded_data; | 
| Mimi Zohar | 7e70cb4 | 2010-11-23 18:55:35 -0500 | [diff] [blame] | 659 | 	unsigned int encrypted_datalen; | 
| Mimi Zohar | 3b1826c | 2010-12-13 16:53:13 -0500 | [diff] [blame] | 660 | 	size_t master_keylen; | 
| Mimi Zohar | 1f35065 | 2010-12-13 16:53:12 -0500 | [diff] [blame] | 661 | 	size_t asciilen; | 
| Mimi Zohar | 7e70cb4 | 2010-11-23 18:55:35 -0500 | [diff] [blame] | 662 | 	int ret; | 
 | 663 |  | 
 | 664 | 	encrypted_datalen = roundup(epayload->decrypted_datalen, blksize); | 
| Mimi Zohar | 1f35065 | 2010-12-13 16:53:12 -0500 | [diff] [blame] | 665 | 	asciilen = (ivsize + 1 + encrypted_datalen + HASH_SIZE) * 2; | 
 | 666 | 	if (strlen(hex_encoded_iv) != asciilen) | 
 | 667 | 		return -EINVAL; | 
 | 668 |  | 
 | 669 | 	hex_encoded_data = hex_encoded_iv + (2 * ivsize) + 2; | 
| Mimi Zohar | 2b3ff63 | 2011-09-20 11:23:55 -0400 | [diff] [blame] | 670 | 	ret = hex2bin(epayload->iv, hex_encoded_iv, ivsize); | 
 | 671 | 	if (ret < 0) | 
 | 672 | 		return -EINVAL; | 
 | 673 | 	ret = hex2bin(epayload->encrypted_data, hex_encoded_data, | 
 | 674 | 		      encrypted_datalen); | 
 | 675 | 	if (ret < 0) | 
 | 676 | 		return -EINVAL; | 
| Mimi Zohar | 7e70cb4 | 2010-11-23 18:55:35 -0500 | [diff] [blame] | 677 |  | 
| Roberto Sassu | 4e561d3 | 2011-06-27 13:45:42 +0200 | [diff] [blame] | 678 | 	hmac = epayload->format + epayload->datablob_len; | 
| Mimi Zohar | 2b3ff63 | 2011-09-20 11:23:55 -0400 | [diff] [blame] | 679 | 	ret = hex2bin(hmac, hex_encoded_data + (encrypted_datalen * 2), | 
 | 680 | 		      HASH_SIZE); | 
 | 681 | 	if (ret < 0) | 
 | 682 | 		return -EINVAL; | 
| Mimi Zohar | 7e70cb4 | 2010-11-23 18:55:35 -0500 | [diff] [blame] | 683 |  | 
 | 684 | 	mkey = request_master_key(epayload, &master_key, &master_keylen); | 
 | 685 | 	if (IS_ERR(mkey)) | 
 | 686 | 		return PTR_ERR(mkey); | 
 | 687 |  | 
| Roberto Sassu | 4e561d3 | 2011-06-27 13:45:42 +0200 | [diff] [blame] | 688 | 	ret = datablob_hmac_verify(epayload, format, master_key, master_keylen); | 
| Mimi Zohar | 7e70cb4 | 2010-11-23 18:55:35 -0500 | [diff] [blame] | 689 | 	if (ret < 0) { | 
 | 690 | 		pr_err("encrypted_key: bad hmac (%d)\n", ret); | 
 | 691 | 		goto out; | 
 | 692 | 	} | 
 | 693 |  | 
 | 694 | 	ret = get_derived_key(derived_key, ENC_KEY, master_key, master_keylen); | 
 | 695 | 	if (ret < 0) | 
 | 696 | 		goto out; | 
 | 697 |  | 
 | 698 | 	ret = derived_key_decrypt(epayload, derived_key, sizeof derived_key); | 
 | 699 | 	if (ret < 0) | 
 | 700 | 		pr_err("encrypted_key: failed to decrypt key (%d)\n", ret); | 
 | 701 | out: | 
 | 702 | 	up_read(&mkey->sem); | 
 | 703 | 	key_put(mkey); | 
 | 704 | 	return ret; | 
 | 705 | } | 
 | 706 |  | 
 | 707 | static void __ekey_init(struct encrypted_key_payload *epayload, | 
| Roberto Sassu | 4e561d3 | 2011-06-27 13:45:42 +0200 | [diff] [blame] | 708 | 			const char *format, const char *master_desc, | 
 | 709 | 			const char *datalen) | 
| Mimi Zohar | 7e70cb4 | 2010-11-23 18:55:35 -0500 | [diff] [blame] | 710 | { | 
| Roberto Sassu | 4e561d3 | 2011-06-27 13:45:42 +0200 | [diff] [blame] | 711 | 	unsigned int format_len; | 
 | 712 |  | 
 | 713 | 	format_len = (!format) ? strlen(key_format_default) : strlen(format); | 
 | 714 | 	epayload->format = epayload->payload_data + epayload->payload_datalen; | 
 | 715 | 	epayload->master_desc = epayload->format + format_len + 1; | 
| Mimi Zohar | 7e70cb4 | 2010-11-23 18:55:35 -0500 | [diff] [blame] | 716 | 	epayload->datalen = epayload->master_desc + strlen(master_desc) + 1; | 
 | 717 | 	epayload->iv = epayload->datalen + strlen(datalen) + 1; | 
 | 718 | 	epayload->encrypted_data = epayload->iv + ivsize + 1; | 
| Roberto Sassu | 4e561d3 | 2011-06-27 13:45:42 +0200 | [diff] [blame] | 719 | 	epayload->decrypted_data = epayload->payload_data; | 
| Mimi Zohar | 7e70cb4 | 2010-11-23 18:55:35 -0500 | [diff] [blame] | 720 |  | 
| Roberto Sassu | 4e561d3 | 2011-06-27 13:45:42 +0200 | [diff] [blame] | 721 | 	if (!format) | 
 | 722 | 		memcpy(epayload->format, key_format_default, format_len); | 
| Roberto Sassu | 79a73d1 | 2011-06-27 13:45:44 +0200 | [diff] [blame] | 723 | 	else { | 
 | 724 | 		if (!strcmp(format, key_format_ecryptfs)) | 
 | 725 | 			epayload->decrypted_data = | 
 | 726 | 				ecryptfs_get_auth_tok_key((struct ecryptfs_auth_tok *)epayload->payload_data); | 
 | 727 |  | 
| Roberto Sassu | 4e561d3 | 2011-06-27 13:45:42 +0200 | [diff] [blame] | 728 | 		memcpy(epayload->format, format, format_len); | 
| Roberto Sassu | 79a73d1 | 2011-06-27 13:45:44 +0200 | [diff] [blame] | 729 | 	} | 
 | 730 |  | 
| Mimi Zohar | 7e70cb4 | 2010-11-23 18:55:35 -0500 | [diff] [blame] | 731 | 	memcpy(epayload->master_desc, master_desc, strlen(master_desc)); | 
 | 732 | 	memcpy(epayload->datalen, datalen, strlen(datalen)); | 
 | 733 | } | 
 | 734 |  | 
 | 735 | /* | 
 | 736 |  * encrypted_init - initialize an encrypted key | 
 | 737 |  * | 
 | 738 |  * For a new key, use a random number for both the iv and data | 
 | 739 |  * itself.  For an old key, decrypt the hex encoded data. | 
 | 740 |  */ | 
 | 741 | static int encrypted_init(struct encrypted_key_payload *epayload, | 
| Roberto Sassu | 79a73d1 | 2011-06-27 13:45:44 +0200 | [diff] [blame] | 742 | 			  const char *key_desc, const char *format, | 
 | 743 | 			  const char *master_desc, const char *datalen, | 
 | 744 | 			  const char *hex_encoded_iv) | 
| Mimi Zohar | 7e70cb4 | 2010-11-23 18:55:35 -0500 | [diff] [blame] | 745 | { | 
 | 746 | 	int ret = 0; | 
 | 747 |  | 
| Roberto Sassu | 79a73d1 | 2011-06-27 13:45:44 +0200 | [diff] [blame] | 748 | 	if (format && !strcmp(format, key_format_ecryptfs)) { | 
 | 749 | 		ret = valid_ecryptfs_desc(key_desc); | 
 | 750 | 		if (ret < 0) | 
 | 751 | 			return ret; | 
 | 752 |  | 
 | 753 | 		ecryptfs_fill_auth_tok((struct ecryptfs_auth_tok *)epayload->payload_data, | 
 | 754 | 				       key_desc); | 
 | 755 | 	} | 
 | 756 |  | 
| Roberto Sassu | 4e561d3 | 2011-06-27 13:45:42 +0200 | [diff] [blame] | 757 | 	__ekey_init(epayload, format, master_desc, datalen); | 
| Mimi Zohar | 1f35065 | 2010-12-13 16:53:12 -0500 | [diff] [blame] | 758 | 	if (!hex_encoded_iv) { | 
| Mimi Zohar | 7e70cb4 | 2010-11-23 18:55:35 -0500 | [diff] [blame] | 759 | 		get_random_bytes(epayload->iv, ivsize); | 
 | 760 |  | 
 | 761 | 		get_random_bytes(epayload->decrypted_data, | 
 | 762 | 				 epayload->decrypted_datalen); | 
 | 763 | 	} else | 
| Roberto Sassu | 4e561d3 | 2011-06-27 13:45:42 +0200 | [diff] [blame] | 764 | 		ret = encrypted_key_decrypt(epayload, format, hex_encoded_iv); | 
| Mimi Zohar | 7e70cb4 | 2010-11-23 18:55:35 -0500 | [diff] [blame] | 765 | 	return ret; | 
 | 766 | } | 
 | 767 |  | 
 | 768 | /* | 
 | 769 |  * encrypted_instantiate - instantiate an encrypted key | 
 | 770 |  * | 
 | 771 |  * Decrypt an existing encrypted datablob or create a new encrypted key | 
 | 772 |  * based on a kernel random number. | 
 | 773 |  * | 
 | 774 |  * On success, return 0. Otherwise return errno. | 
 | 775 |  */ | 
 | 776 | static int encrypted_instantiate(struct key *key, const void *data, | 
 | 777 | 				 size_t datalen) | 
 | 778 | { | 
 | 779 | 	struct encrypted_key_payload *epayload = NULL; | 
 | 780 | 	char *datablob = NULL; | 
| Roberto Sassu | 4e561d3 | 2011-06-27 13:45:42 +0200 | [diff] [blame] | 781 | 	const char *format = NULL; | 
| Mimi Zohar | 7e70cb4 | 2010-11-23 18:55:35 -0500 | [diff] [blame] | 782 | 	char *master_desc = NULL; | 
 | 783 | 	char *decrypted_datalen = NULL; | 
 | 784 | 	char *hex_encoded_iv = NULL; | 
| Mimi Zohar | 7e70cb4 | 2010-11-23 18:55:35 -0500 | [diff] [blame] | 785 | 	int ret; | 
 | 786 |  | 
 | 787 | 	if (datalen <= 0 || datalen > 32767 || !data) | 
 | 788 | 		return -EINVAL; | 
 | 789 |  | 
 | 790 | 	datablob = kmalloc(datalen + 1, GFP_KERNEL); | 
 | 791 | 	if (!datablob) | 
 | 792 | 		return -ENOMEM; | 
 | 793 | 	datablob[datalen] = 0; | 
 | 794 | 	memcpy(datablob, data, datalen); | 
| Roberto Sassu | 4e561d3 | 2011-06-27 13:45:42 +0200 | [diff] [blame] | 795 | 	ret = datablob_parse(datablob, &format, &master_desc, | 
 | 796 | 			     &decrypted_datalen, &hex_encoded_iv); | 
| Mimi Zohar | 7e70cb4 | 2010-11-23 18:55:35 -0500 | [diff] [blame] | 797 | 	if (ret < 0) | 
 | 798 | 		goto out; | 
 | 799 |  | 
| Roberto Sassu | 4e561d3 | 2011-06-27 13:45:42 +0200 | [diff] [blame] | 800 | 	epayload = encrypted_key_alloc(key, format, master_desc, | 
 | 801 | 				       decrypted_datalen); | 
| Mimi Zohar | 7e70cb4 | 2010-11-23 18:55:35 -0500 | [diff] [blame] | 802 | 	if (IS_ERR(epayload)) { | 
 | 803 | 		ret = PTR_ERR(epayload); | 
 | 804 | 		goto out; | 
 | 805 | 	} | 
| Roberto Sassu | 79a73d1 | 2011-06-27 13:45:44 +0200 | [diff] [blame] | 806 | 	ret = encrypted_init(epayload, key->description, format, master_desc, | 
 | 807 | 			     decrypted_datalen, hex_encoded_iv); | 
| Mimi Zohar | 7e70cb4 | 2010-11-23 18:55:35 -0500 | [diff] [blame] | 808 | 	if (ret < 0) { | 
 | 809 | 		kfree(epayload); | 
 | 810 | 		goto out; | 
 | 811 | 	} | 
 | 812 |  | 
| Mimi Zohar | ee0b31a | 2012-01-17 20:39:51 +0000 | [diff] [blame] | 813 | 	rcu_assign_keypointer(key, epayload); | 
| Mimi Zohar | 7e70cb4 | 2010-11-23 18:55:35 -0500 | [diff] [blame] | 814 | out: | 
 | 815 | 	kfree(datablob); | 
 | 816 | 	return ret; | 
 | 817 | } | 
 | 818 |  | 
 | 819 | static void encrypted_rcu_free(struct rcu_head *rcu) | 
 | 820 | { | 
 | 821 | 	struct encrypted_key_payload *epayload; | 
 | 822 |  | 
 | 823 | 	epayload = container_of(rcu, struct encrypted_key_payload, rcu); | 
 | 824 | 	memset(epayload->decrypted_data, 0, epayload->decrypted_datalen); | 
 | 825 | 	kfree(epayload); | 
 | 826 | } | 
 | 827 |  | 
 | 828 | /* | 
 | 829 |  * encrypted_update - update the master key description | 
 | 830 |  * | 
 | 831 |  * Change the master key description for an existing encrypted key. | 
 | 832 |  * The next read will return an encrypted datablob using the new | 
 | 833 |  * master key description. | 
 | 834 |  * | 
 | 835 |  * On success, return 0. Otherwise return errno. | 
 | 836 |  */ | 
 | 837 | static int encrypted_update(struct key *key, const void *data, size_t datalen) | 
 | 838 | { | 
 | 839 | 	struct encrypted_key_payload *epayload = key->payload.data; | 
 | 840 | 	struct encrypted_key_payload *new_epayload; | 
 | 841 | 	char *buf; | 
 | 842 | 	char *new_master_desc = NULL; | 
| Roberto Sassu | 4e561d3 | 2011-06-27 13:45:42 +0200 | [diff] [blame] | 843 | 	const char *format = NULL; | 
| Mimi Zohar | 7e70cb4 | 2010-11-23 18:55:35 -0500 | [diff] [blame] | 844 | 	int ret = 0; | 
 | 845 |  | 
 | 846 | 	if (datalen <= 0 || datalen > 32767 || !data) | 
 | 847 | 		return -EINVAL; | 
 | 848 |  | 
 | 849 | 	buf = kmalloc(datalen + 1, GFP_KERNEL); | 
 | 850 | 	if (!buf) | 
 | 851 | 		return -ENOMEM; | 
 | 852 |  | 
 | 853 | 	buf[datalen] = 0; | 
 | 854 | 	memcpy(buf, data, datalen); | 
| Roberto Sassu | 4e561d3 | 2011-06-27 13:45:42 +0200 | [diff] [blame] | 855 | 	ret = datablob_parse(buf, &format, &new_master_desc, NULL, NULL); | 
| Mimi Zohar | 7e70cb4 | 2010-11-23 18:55:35 -0500 | [diff] [blame] | 856 | 	if (ret < 0) | 
 | 857 | 		goto out; | 
 | 858 |  | 
 | 859 | 	ret = valid_master_desc(new_master_desc, epayload->master_desc); | 
 | 860 | 	if (ret < 0) | 
 | 861 | 		goto out; | 
 | 862 |  | 
| Roberto Sassu | 4e561d3 | 2011-06-27 13:45:42 +0200 | [diff] [blame] | 863 | 	new_epayload = encrypted_key_alloc(key, epayload->format, | 
 | 864 | 					   new_master_desc, epayload->datalen); | 
| Mimi Zohar | 7e70cb4 | 2010-11-23 18:55:35 -0500 | [diff] [blame] | 865 | 	if (IS_ERR(new_epayload)) { | 
 | 866 | 		ret = PTR_ERR(new_epayload); | 
 | 867 | 		goto out; | 
 | 868 | 	} | 
 | 869 |  | 
| Roberto Sassu | 4e561d3 | 2011-06-27 13:45:42 +0200 | [diff] [blame] | 870 | 	__ekey_init(new_epayload, epayload->format, new_master_desc, | 
 | 871 | 		    epayload->datalen); | 
| Mimi Zohar | 7e70cb4 | 2010-11-23 18:55:35 -0500 | [diff] [blame] | 872 |  | 
 | 873 | 	memcpy(new_epayload->iv, epayload->iv, ivsize); | 
| Roberto Sassu | 4e561d3 | 2011-06-27 13:45:42 +0200 | [diff] [blame] | 874 | 	memcpy(new_epayload->payload_data, epayload->payload_data, | 
 | 875 | 	       epayload->payload_datalen); | 
| Mimi Zohar | 7e70cb4 | 2010-11-23 18:55:35 -0500 | [diff] [blame] | 876 |  | 
| Mimi Zohar | ee0b31a | 2012-01-17 20:39:51 +0000 | [diff] [blame] | 877 | 	rcu_assign_keypointer(key, new_epayload); | 
| Mimi Zohar | 7e70cb4 | 2010-11-23 18:55:35 -0500 | [diff] [blame] | 878 | 	call_rcu(&epayload->rcu, encrypted_rcu_free); | 
 | 879 | out: | 
 | 880 | 	kfree(buf); | 
 | 881 | 	return ret; | 
 | 882 | } | 
 | 883 |  | 
 | 884 | /* | 
 | 885 |  * encrypted_read - format and copy the encrypted data to userspace | 
 | 886 |  * | 
 | 887 |  * The resulting datablob format is: | 
 | 888 |  * <master-key name> <decrypted data length> <encrypted iv> <encrypted data> | 
 | 889 |  * | 
 | 890 |  * On success, return to userspace the encrypted key datablob size. | 
 | 891 |  */ | 
 | 892 | static long encrypted_read(const struct key *key, char __user *buffer, | 
 | 893 | 			   size_t buflen) | 
 | 894 | { | 
 | 895 | 	struct encrypted_key_payload *epayload; | 
 | 896 | 	struct key *mkey; | 
 | 897 | 	u8 *master_key; | 
| Mimi Zohar | 3b1826c | 2010-12-13 16:53:13 -0500 | [diff] [blame] | 898 | 	size_t master_keylen; | 
| Mimi Zohar | 7e70cb4 | 2010-11-23 18:55:35 -0500 | [diff] [blame] | 899 | 	char derived_key[HASH_SIZE]; | 
 | 900 | 	char *ascii_buf; | 
 | 901 | 	size_t asciiblob_len; | 
 | 902 | 	int ret; | 
 | 903 |  | 
| David Howells | 633e804 | 2011-03-07 15:05:51 +0000 | [diff] [blame] | 904 | 	epayload = rcu_dereference_key(key); | 
| Mimi Zohar | 7e70cb4 | 2010-11-23 18:55:35 -0500 | [diff] [blame] | 905 |  | 
 | 906 | 	/* returns the hex encoded iv, encrypted-data, and hmac as ascii */ | 
 | 907 | 	asciiblob_len = epayload->datablob_len + ivsize + 1 | 
 | 908 | 	    + roundup(epayload->decrypted_datalen, blksize) | 
 | 909 | 	    + (HASH_SIZE * 2); | 
 | 910 |  | 
 | 911 | 	if (!buffer || buflen < asciiblob_len) | 
 | 912 | 		return asciiblob_len; | 
 | 913 |  | 
 | 914 | 	mkey = request_master_key(epayload, &master_key, &master_keylen); | 
 | 915 | 	if (IS_ERR(mkey)) | 
 | 916 | 		return PTR_ERR(mkey); | 
 | 917 |  | 
 | 918 | 	ret = get_derived_key(derived_key, ENC_KEY, master_key, master_keylen); | 
 | 919 | 	if (ret < 0) | 
 | 920 | 		goto out; | 
 | 921 |  | 
 | 922 | 	ret = derived_key_encrypt(epayload, derived_key, sizeof derived_key); | 
 | 923 | 	if (ret < 0) | 
 | 924 | 		goto out; | 
 | 925 |  | 
 | 926 | 	ret = datablob_hmac_append(epayload, master_key, master_keylen); | 
 | 927 | 	if (ret < 0) | 
 | 928 | 		goto out; | 
 | 929 |  | 
 | 930 | 	ascii_buf = datablob_format(epayload, asciiblob_len); | 
 | 931 | 	if (!ascii_buf) { | 
 | 932 | 		ret = -ENOMEM; | 
 | 933 | 		goto out; | 
 | 934 | 	} | 
 | 935 |  | 
 | 936 | 	up_read(&mkey->sem); | 
 | 937 | 	key_put(mkey); | 
 | 938 |  | 
 | 939 | 	if (copy_to_user(buffer, ascii_buf, asciiblob_len) != 0) | 
 | 940 | 		ret = -EFAULT; | 
 | 941 | 	kfree(ascii_buf); | 
 | 942 |  | 
 | 943 | 	return asciiblob_len; | 
 | 944 | out: | 
 | 945 | 	up_read(&mkey->sem); | 
 | 946 | 	key_put(mkey); | 
 | 947 | 	return ret; | 
 | 948 | } | 
 | 949 |  | 
 | 950 | /* | 
 | 951 |  * encrypted_destroy - before freeing the key, clear the decrypted data | 
 | 952 |  * | 
 | 953 |  * Before freeing the key, clear the memory containing the decrypted | 
 | 954 |  * key data. | 
 | 955 |  */ | 
 | 956 | static void encrypted_destroy(struct key *key) | 
 | 957 | { | 
 | 958 | 	struct encrypted_key_payload *epayload = key->payload.data; | 
 | 959 |  | 
 | 960 | 	if (!epayload) | 
 | 961 | 		return; | 
 | 962 |  | 
 | 963 | 	memset(epayload->decrypted_data, 0, epayload->decrypted_datalen); | 
 | 964 | 	kfree(key->payload.data); | 
 | 965 | } | 
 | 966 |  | 
 | 967 | struct key_type key_type_encrypted = { | 
 | 968 | 	.name = "encrypted", | 
 | 969 | 	.instantiate = encrypted_instantiate, | 
 | 970 | 	.update = encrypted_update, | 
 | 971 | 	.match = user_match, | 
 | 972 | 	.destroy = encrypted_destroy, | 
 | 973 | 	.describe = user_describe, | 
 | 974 | 	.read = encrypted_read, | 
 | 975 | }; | 
 | 976 | EXPORT_SYMBOL_GPL(key_type_encrypted); | 
 | 977 |  | 
 | 978 | static void encrypted_shash_release(void) | 
 | 979 | { | 
 | 980 | 	if (hashalg) | 
 | 981 | 		crypto_free_shash(hashalg); | 
 | 982 | 	if (hmacalg) | 
 | 983 | 		crypto_free_shash(hmacalg); | 
 | 984 | } | 
 | 985 |  | 
 | 986 | static int __init encrypted_shash_alloc(void) | 
 | 987 | { | 
 | 988 | 	int ret; | 
 | 989 |  | 
 | 990 | 	hmacalg = crypto_alloc_shash(hmac_alg, 0, CRYPTO_ALG_ASYNC); | 
 | 991 | 	if (IS_ERR(hmacalg)) { | 
 | 992 | 		pr_info("encrypted_key: could not allocate crypto %s\n", | 
 | 993 | 			hmac_alg); | 
 | 994 | 		return PTR_ERR(hmacalg); | 
 | 995 | 	} | 
 | 996 |  | 
 | 997 | 	hashalg = crypto_alloc_shash(hash_alg, 0, CRYPTO_ALG_ASYNC); | 
 | 998 | 	if (IS_ERR(hashalg)) { | 
 | 999 | 		pr_info("encrypted_key: could not allocate crypto %s\n", | 
 | 1000 | 			hash_alg); | 
 | 1001 | 		ret = PTR_ERR(hashalg); | 
 | 1002 | 		goto hashalg_fail; | 
 | 1003 | 	} | 
 | 1004 |  | 
 | 1005 | 	return 0; | 
 | 1006 |  | 
 | 1007 | hashalg_fail: | 
 | 1008 | 	crypto_free_shash(hmacalg); | 
 | 1009 | 	return ret; | 
 | 1010 | } | 
 | 1011 |  | 
 | 1012 | static int __init init_encrypted(void) | 
 | 1013 | { | 
 | 1014 | 	int ret; | 
 | 1015 |  | 
 | 1016 | 	ret = encrypted_shash_alloc(); | 
 | 1017 | 	if (ret < 0) | 
 | 1018 | 		return ret; | 
 | 1019 | 	ret = register_key_type(&key_type_encrypted); | 
 | 1020 | 	if (ret < 0) | 
 | 1021 | 		goto out; | 
 | 1022 | 	return aes_get_sizes(); | 
 | 1023 | out: | 
 | 1024 | 	encrypted_shash_release(); | 
 | 1025 | 	return ret; | 
| Mimi Zohar | b970344 | 2011-01-18 09:07:12 -0500 | [diff] [blame] | 1026 |  | 
| Mimi Zohar | 7e70cb4 | 2010-11-23 18:55:35 -0500 | [diff] [blame] | 1027 | } | 
 | 1028 |  | 
 | 1029 | static void __exit cleanup_encrypted(void) | 
 | 1030 | { | 
 | 1031 | 	encrypted_shash_release(); | 
 | 1032 | 	unregister_key_type(&key_type_encrypted); | 
 | 1033 | } | 
 | 1034 |  | 
 | 1035 | late_initcall(init_encrypted); | 
 | 1036 | module_exit(cleanup_encrypted); | 
 | 1037 |  | 
 | 1038 | MODULE_LICENSE("GPL"); |