forked from mirrors/linux
		
	KEYS: encrypted: Instantiate key with user-provided decrypted data
For availability and performance reasons master keys often need to be released outside of a Key Management Service (KMS) to clients. It would be beneficial to provide a mechanism where the wrapping/unwrapping of data encryption keys (DEKs) is not dependent on a remote call at runtime yet security is not (or only minimally) compromised. Master keys could be securely stored in the Kernel and be used to wrap/unwrap keys from Userspace. The encrypted.c class supports instantiation of encrypted keys with either an already-encrypted key material, or by generating new key material based on random numbers. This patch defines a new datablob format: [<format>] <master-key name> <decrypted data length> <decrypted data> that allows to inject and encrypt user-provided decrypted data. The decrypted data must be hex-ascii encoded. Signed-off-by: Yael Tzur <yaelt@google.com> Reviewed-by: Mimi Zohar <zohar@linux.ibm.com> Reviewed-by: Sumit Garg <sumit.garg@linaro.org> Reviewed-by: Jarkko Sakkinen <jarkko@kernel.org> Signed-off-by: Mimi Zohar <zohar@linux.ibm.com>
This commit is contained in:
		
							parent
							
								
									8c54135e2e
								
							
						
					
					
						commit
						cd3bc044af
					
				
					 3 changed files with 86 additions and 29 deletions
				
			
		| 
						 | 
					@ -107,12 +107,13 @@ Encrypted Keys
 | 
				
			||||||
--------------
 | 
					--------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Encrypted keys do not depend on a trust source, and are faster, as they use AES
 | 
					Encrypted keys do not depend on a trust source, and are faster, as they use AES
 | 
				
			||||||
for encryption/decryption. New keys are created from kernel-generated random
 | 
					for encryption/decryption. New keys are created either from kernel-generated
 | 
				
			||||||
numbers, and are encrypted/decrypted using a specified ‘master’ key. The
 | 
					random numbers or user-provided decrypted data, and are encrypted/decrypted
 | 
				
			||||||
‘master’ key can either be a trusted-key or user-key type. The main disadvantage
 | 
					using a specified ‘master’ key. The ‘master’ key can either be a trusted-key or
 | 
				
			||||||
of encrypted keys is that if they are not rooted in a trusted key, they are only
 | 
					user-key type. The main disadvantage of encrypted keys is that if they are not
 | 
				
			||||||
as secure as the user key encrypting them. The master user key should therefore
 | 
					rooted in a trusted key, they are only as secure as the user key encrypting
 | 
				
			||||||
be loaded in as secure a way as possible, preferably early in boot.
 | 
					them. The master user key should therefore be loaded in as secure a way as
 | 
				
			||||||
 | 
					possible, preferably early in boot.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Usage
 | 
					Usage
 | 
				
			||||||
| 
						 | 
					@ -199,6 +200,8 @@ Usage::
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    keyctl add encrypted name "new [format] key-type:master-key-name keylen"
 | 
					    keyctl add encrypted name "new [format] key-type:master-key-name keylen"
 | 
				
			||||||
        ring
 | 
					        ring
 | 
				
			||||||
 | 
					    keyctl add encrypted name "new [format] key-type:master-key-name keylen
 | 
				
			||||||
 | 
					        decrypted-data" ring
 | 
				
			||||||
    keyctl add encrypted name "load hex_blob" ring
 | 
					    keyctl add encrypted name "load hex_blob" ring
 | 
				
			||||||
    keyctl update keyid "update key-type:master-key-name"
 | 
					    keyctl update keyid "update key-type:master-key-name"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -303,6 +306,16 @@ Load an encrypted key "evm" from saved blob::
 | 
				
			||||||
    82dbbc55be2a44616e4959430436dc4f2a7a9659aa60bb4652aeb2120f149ed197c564e0
 | 
					    82dbbc55be2a44616e4959430436dc4f2a7a9659aa60bb4652aeb2120f149ed197c564e0
 | 
				
			||||||
    24717c64 5972dcb82ab2dde83376d82b2e3c09ffc
 | 
					    24717c64 5972dcb82ab2dde83376d82b2e3c09ffc
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Instantiate an encrypted key "evm" using user-provided decrypted data::
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    $ keyctl add encrypted evm "new default user:kmk 32 `cat evm_decrypted_data.blob`" @u
 | 
				
			||||||
 | 
					    794890253
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    $ keyctl print 794890253
 | 
				
			||||||
 | 
					    default user:kmk 32 2375725ad57798846a9bbd240de8906f006e66c03af53b1b382d
 | 
				
			||||||
 | 
					    bbc55be2a44616e4959430436dc4f2a7a9659aa60bb4652aeb2120f149ed197c564e0247
 | 
				
			||||||
 | 
					    17c64 5972dcb82ab2dde83376d82b2e3c09ffc
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Other uses for trusted and encrypted keys, such as for disk and file encryption
 | 
					Other uses for trusted and encrypted keys, such as for disk and file encryption
 | 
				
			||||||
are anticipated.  In particular the new format 'ecryptfs' has been defined
 | 
					are anticipated.  In particular the new format 'ecryptfs' has been defined
 | 
				
			||||||
in order to use encrypted keys to mount an eCryptfs filesystem.  More details
 | 
					in order to use encrypted keys to mount an eCryptfs filesystem.  More details
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -98,10 +98,21 @@ config ENCRYPTED_KEYS
 | 
				
			||||||
	select CRYPTO_RNG
 | 
						select CRYPTO_RNG
 | 
				
			||||||
	help
 | 
						help
 | 
				
			||||||
	  This option provides support for create/encrypting/decrypting keys
 | 
						  This option provides support for create/encrypting/decrypting keys
 | 
				
			||||||
	  in the kernel.  Encrypted keys are kernel generated random numbers,
 | 
						  in the kernel.  Encrypted keys are instantiated using kernel
 | 
				
			||||||
	  which are encrypted/decrypted with a 'master' symmetric key. The
 | 
						  generated random numbers or provided decrypted data, and are
 | 
				
			||||||
	  'master' key can be either a trusted-key or user-key type.
 | 
						  encrypted/decrypted with a 'master' symmetric key. The 'master'
 | 
				
			||||||
	  Userspace only ever sees/stores encrypted blobs.
 | 
						  key can be either a trusted-key or user-key type. Only encrypted
 | 
				
			||||||
 | 
						  blobs are ever output to Userspace.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						  If you are unsure as to whether this is required, answer N.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					config USER_DECRYPTED_DATA
 | 
				
			||||||
 | 
						bool "Allow encrypted keys with user decrypted data"
 | 
				
			||||||
 | 
						depends on ENCRYPTED_KEYS
 | 
				
			||||||
 | 
						help
 | 
				
			||||||
 | 
						  This option provides support for instantiating encrypted keys using
 | 
				
			||||||
 | 
						  user-provided decrypted data.  The decrypted data must be hex-ascii
 | 
				
			||||||
 | 
						  encoded.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	  If you are unsure as to whether this is required, answer N.
 | 
						  If you are unsure as to whether this is required, answer N.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -78,6 +78,11 @@ static const match_table_t key_tokens = {
 | 
				
			||||||
	{Opt_err, NULL}
 | 
						{Opt_err, NULL}
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static bool user_decrypted_data = IS_ENABLED(CONFIG_USER_DECRYPTED_DATA);
 | 
				
			||||||
 | 
					module_param(user_decrypted_data, bool, 0);
 | 
				
			||||||
 | 
					MODULE_PARM_DESC(user_decrypted_data,
 | 
				
			||||||
 | 
						"Allow instantiation of encrypted keys using provided decrypted data");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int aes_get_sizes(void)
 | 
					static int aes_get_sizes(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct crypto_skcipher *tfm;
 | 
						struct crypto_skcipher *tfm;
 | 
				
			||||||
| 
						 | 
					@ -158,7 +163,7 @@ static int valid_master_desc(const char *new_desc, const char *orig_desc)
 | 
				
			||||||
 * datablob_parse - parse the keyctl data
 | 
					 * datablob_parse - parse the keyctl data
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * datablob format:
 | 
					 * datablob format:
 | 
				
			||||||
 * new [<format>] <master-key name> <decrypted data length>
 | 
					 * new [<format>] <master-key name> <decrypted data length> [<decrypted data>]
 | 
				
			||||||
 * load [<format>] <master-key name> <decrypted data length>
 | 
					 * load [<format>] <master-key name> <decrypted data length>
 | 
				
			||||||
 *     <encrypted iv + data>
 | 
					 *     <encrypted iv + data>
 | 
				
			||||||
 * update <new-master-key name>
 | 
					 * update <new-master-key name>
 | 
				
			||||||
| 
						 | 
					@ -170,7 +175,7 @@ static int valid_master_desc(const char *new_desc, const char *orig_desc)
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
static int datablob_parse(char *datablob, const char **format,
 | 
					static int datablob_parse(char *datablob, const char **format,
 | 
				
			||||||
			  char **master_desc, char **decrypted_datalen,
 | 
								  char **master_desc, char **decrypted_datalen,
 | 
				
			||||||
			  char **hex_encoded_iv)
 | 
								  char **hex_encoded_iv, char **decrypted_data)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	substring_t args[MAX_OPT_ARGS];
 | 
						substring_t args[MAX_OPT_ARGS];
 | 
				
			||||||
	int ret = -EINVAL;
 | 
						int ret = -EINVAL;
 | 
				
			||||||
| 
						 | 
					@ -231,6 +236,7 @@ static int datablob_parse(char *datablob, const char **format,
 | 
				
			||||||
				"when called from .update method\n", keyword);
 | 
									"when called from .update method\n", keyword);
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
							*decrypted_data = strsep(&datablob, " \t");
 | 
				
			||||||
		ret = 0;
 | 
							ret = 0;
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	case Opt_load:
 | 
						case Opt_load:
 | 
				
			||||||
| 
						 | 
					@ -595,7 +601,8 @@ static int derived_key_decrypt(struct encrypted_key_payload *epayload,
 | 
				
			||||||
static struct encrypted_key_payload *encrypted_key_alloc(struct key *key,
 | 
					static struct encrypted_key_payload *encrypted_key_alloc(struct key *key,
 | 
				
			||||||
							 const char *format,
 | 
												 const char *format,
 | 
				
			||||||
							 const char *master_desc,
 | 
												 const char *master_desc,
 | 
				
			||||||
							 const char *datalen)
 | 
												 const char *datalen,
 | 
				
			||||||
 | 
												 const char *decrypted_data)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct encrypted_key_payload *epayload = NULL;
 | 
						struct encrypted_key_payload *epayload = NULL;
 | 
				
			||||||
	unsigned short datablob_len;
 | 
						unsigned short datablob_len;
 | 
				
			||||||
| 
						 | 
					@ -604,6 +611,7 @@ static struct encrypted_key_payload *encrypted_key_alloc(struct key *key,
 | 
				
			||||||
	unsigned int encrypted_datalen;
 | 
						unsigned int encrypted_datalen;
 | 
				
			||||||
	unsigned int format_len;
 | 
						unsigned int format_len;
 | 
				
			||||||
	long dlen;
 | 
						long dlen;
 | 
				
			||||||
 | 
						int i;
 | 
				
			||||||
	int ret;
 | 
						int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ret = kstrtol(datalen, 10, &dlen);
 | 
						ret = kstrtol(datalen, 10, &dlen);
 | 
				
			||||||
| 
						 | 
					@ -613,6 +621,24 @@ static struct encrypted_key_payload *encrypted_key_alloc(struct key *key,
 | 
				
			||||||
	format_len = (!format) ? strlen(key_format_default) : strlen(format);
 | 
						format_len = (!format) ? strlen(key_format_default) : strlen(format);
 | 
				
			||||||
	decrypted_datalen = dlen;
 | 
						decrypted_datalen = dlen;
 | 
				
			||||||
	payload_datalen = decrypted_datalen;
 | 
						payload_datalen = decrypted_datalen;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (decrypted_data) {
 | 
				
			||||||
 | 
							if (!user_decrypted_data) {
 | 
				
			||||||
 | 
								pr_err("encrypted key: instantiation of keys using provided decrypted data is disabled since CONFIG_USER_DECRYPTED_DATA is set to false\n");
 | 
				
			||||||
 | 
								return ERR_PTR(-EINVAL);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if (strlen(decrypted_data) != decrypted_datalen) {
 | 
				
			||||||
 | 
								pr_err("encrypted key: decrypted data provided does not match decrypted data length provided\n");
 | 
				
			||||||
 | 
								return ERR_PTR(-EINVAL);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							for (i = 0; i < strlen(decrypted_data); i++) {
 | 
				
			||||||
 | 
								if (!isxdigit(decrypted_data[i])) {
 | 
				
			||||||
 | 
									pr_err("encrypted key: decrypted data provided must contain only hexadecimal characters\n");
 | 
				
			||||||
 | 
									return ERR_PTR(-EINVAL);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (format) {
 | 
						if (format) {
 | 
				
			||||||
		if (!strcmp(format, key_format_ecryptfs)) {
 | 
							if (!strcmp(format, key_format_ecryptfs)) {
 | 
				
			||||||
			if (dlen != ECRYPTFS_MAX_KEY_BYTES) {
 | 
								if (dlen != ECRYPTFS_MAX_KEY_BYTES) {
 | 
				
			||||||
| 
						 | 
					@ -740,13 +766,14 @@ static void __ekey_init(struct encrypted_key_payload *epayload,
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * encrypted_init - initialize an encrypted key
 | 
					 * encrypted_init - initialize an encrypted key
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * For a new key, use a random number for both the iv and data
 | 
					 * For a new key, use either a random number or user-provided decrypted data in
 | 
				
			||||||
 * itself.  For an old key, decrypt the hex encoded data.
 | 
					 * case it is provided. A random number is used for the iv in both cases. For
 | 
				
			||||||
 | 
					 * an old key, decrypt the hex encoded data.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
static int encrypted_init(struct encrypted_key_payload *epayload,
 | 
					static int encrypted_init(struct encrypted_key_payload *epayload,
 | 
				
			||||||
			  const char *key_desc, const char *format,
 | 
								  const char *key_desc, const char *format,
 | 
				
			||||||
			  const char *master_desc, const char *datalen,
 | 
								  const char *master_desc, const char *datalen,
 | 
				
			||||||
			  const char *hex_encoded_iv)
 | 
								  const char *hex_encoded_iv, const char *decrypted_data)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int ret = 0;
 | 
						int ret = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -760,21 +787,26 @@ static int encrypted_init(struct encrypted_key_payload *epayload,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	__ekey_init(epayload, format, master_desc, datalen);
 | 
						__ekey_init(epayload, format, master_desc, datalen);
 | 
				
			||||||
	if (!hex_encoded_iv) {
 | 
						if (hex_encoded_iv) {
 | 
				
			||||||
		get_random_bytes(epayload->iv, ivsize);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		get_random_bytes(epayload->decrypted_data,
 | 
					 | 
				
			||||||
				 epayload->decrypted_datalen);
 | 
					 | 
				
			||||||
	} else
 | 
					 | 
				
			||||||
		ret = encrypted_key_decrypt(epayload, format, hex_encoded_iv);
 | 
							ret = encrypted_key_decrypt(epayload, format, hex_encoded_iv);
 | 
				
			||||||
 | 
						} else if (decrypted_data) {
 | 
				
			||||||
 | 
							get_random_bytes(epayload->iv, ivsize);
 | 
				
			||||||
 | 
							memcpy(epayload->decrypted_data, decrypted_data,
 | 
				
			||||||
 | 
									   epayload->decrypted_datalen);
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							get_random_bytes(epayload->iv, ivsize);
 | 
				
			||||||
 | 
							get_random_bytes(epayload->decrypted_data, epayload->decrypted_datalen);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	return ret;
 | 
						return ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * encrypted_instantiate - instantiate an encrypted key
 | 
					 * encrypted_instantiate - instantiate an encrypted key
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * Decrypt an existing encrypted datablob or create a new encrypted key
 | 
					 * Instantiates the key:
 | 
				
			||||||
 * based on a kernel random number.
 | 
					 * - by decrypting an existing encrypted datablob, or
 | 
				
			||||||
 | 
					 * - by creating a new encrypted key based on a kernel random number, or
 | 
				
			||||||
 | 
					 * - using provided decrypted data.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * On success, return 0. Otherwise return errno.
 | 
					 * On success, return 0. Otherwise return errno.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
| 
						 | 
					@ -787,6 +819,7 @@ static int encrypted_instantiate(struct key *key,
 | 
				
			||||||
	char *master_desc = NULL;
 | 
						char *master_desc = NULL;
 | 
				
			||||||
	char *decrypted_datalen = NULL;
 | 
						char *decrypted_datalen = NULL;
 | 
				
			||||||
	char *hex_encoded_iv = NULL;
 | 
						char *hex_encoded_iv = NULL;
 | 
				
			||||||
 | 
						char *decrypted_data = NULL;
 | 
				
			||||||
	size_t datalen = prep->datalen;
 | 
						size_t datalen = prep->datalen;
 | 
				
			||||||
	int ret;
 | 
						int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -799,18 +832,18 @@ static int encrypted_instantiate(struct key *key,
 | 
				
			||||||
	datablob[datalen] = 0;
 | 
						datablob[datalen] = 0;
 | 
				
			||||||
	memcpy(datablob, prep->data, datalen);
 | 
						memcpy(datablob, prep->data, datalen);
 | 
				
			||||||
	ret = datablob_parse(datablob, &format, &master_desc,
 | 
						ret = datablob_parse(datablob, &format, &master_desc,
 | 
				
			||||||
			     &decrypted_datalen, &hex_encoded_iv);
 | 
								     &decrypted_datalen, &hex_encoded_iv, &decrypted_data);
 | 
				
			||||||
	if (ret < 0)
 | 
						if (ret < 0)
 | 
				
			||||||
		goto out;
 | 
							goto out;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	epayload = encrypted_key_alloc(key, format, master_desc,
 | 
						epayload = encrypted_key_alloc(key, format, master_desc,
 | 
				
			||||||
				       decrypted_datalen);
 | 
									       decrypted_datalen, decrypted_data);
 | 
				
			||||||
	if (IS_ERR(epayload)) {
 | 
						if (IS_ERR(epayload)) {
 | 
				
			||||||
		ret = PTR_ERR(epayload);
 | 
							ret = PTR_ERR(epayload);
 | 
				
			||||||
		goto out;
 | 
							goto out;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	ret = encrypted_init(epayload, key->description, format, master_desc,
 | 
						ret = encrypted_init(epayload, key->description, format, master_desc,
 | 
				
			||||||
			     decrypted_datalen, hex_encoded_iv);
 | 
								     decrypted_datalen, hex_encoded_iv, decrypted_data);
 | 
				
			||||||
	if (ret < 0) {
 | 
						if (ret < 0) {
 | 
				
			||||||
		kfree_sensitive(epayload);
 | 
							kfree_sensitive(epayload);
 | 
				
			||||||
		goto out;
 | 
							goto out;
 | 
				
			||||||
| 
						 | 
					@ -860,7 +893,7 @@ static int encrypted_update(struct key *key, struct key_preparsed_payload *prep)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	buf[datalen] = 0;
 | 
						buf[datalen] = 0;
 | 
				
			||||||
	memcpy(buf, prep->data, datalen);
 | 
						memcpy(buf, prep->data, datalen);
 | 
				
			||||||
	ret = datablob_parse(buf, &format, &new_master_desc, NULL, NULL);
 | 
						ret = datablob_parse(buf, &format, &new_master_desc, NULL, NULL, NULL);
 | 
				
			||||||
	if (ret < 0)
 | 
						if (ret < 0)
 | 
				
			||||||
		goto out;
 | 
							goto out;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -869,7 +902,7 @@ static int encrypted_update(struct key *key, struct key_preparsed_payload *prep)
 | 
				
			||||||
		goto out;
 | 
							goto out;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	new_epayload = encrypted_key_alloc(key, epayload->format,
 | 
						new_epayload = encrypted_key_alloc(key, epayload->format,
 | 
				
			||||||
					   new_master_desc, epayload->datalen);
 | 
										   new_master_desc, epayload->datalen, NULL);
 | 
				
			||||||
	if (IS_ERR(new_epayload)) {
 | 
						if (IS_ERR(new_epayload)) {
 | 
				
			||||||
		ret = PTR_ERR(new_epayload);
 | 
							ret = PTR_ERR(new_epayload);
 | 
				
			||||||
		goto out;
 | 
							goto out;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue