On Tue, 15 Feb 2022 at 19:50, Yael Tzur <yaelt@xxxxxxxxxx> wrote: > > 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. > > Reviewed-by: Mimi Zohar <zohar@xxxxxxxxxxxxx> > Signed-off-by: Yael Tzur <yaelt@xxxxxxxxxx> > --- > > Notes: > v -> v2: fixed compilation error. > > v2 -> v3: modified documentation. > > v3 -> v4: modified commit message. > > v4 -> v5: added config option to enable feature, and modified input validation. > Reviewed-by: Sumit Garg <sumit.garg@xxxxxxxxxx> -Sumit > .../security/keys/trusted-encrypted.rst | 25 +++++-- > security/keys/Kconfig | 19 +++-- > security/keys/encrypted-keys/encrypted.c | 72 ++++++++++++++----- > 3 files changed, 87 insertions(+), 29 deletions(-) > > diff --git a/Documentation/security/keys/trusted-encrypted.rst b/Documentation/security/keys/trusted-encrypted.rst > index 80d5a5af62a1..f614dad7de12 100644 > --- a/Documentation/security/keys/trusted-encrypted.rst > +++ b/Documentation/security/keys/trusted-encrypted.rst > @@ -107,12 +107,13 @@ Encrypted Keys > -------------- > > 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 > -numbers, and are encrypted/decrypted using a specified ‘master’ key. The > -‘master’ key can either be a trusted-key or user-key type. The main disadvantage > -of encrypted keys is that if they are not rooted in a trusted key, they are only > -as secure as the user key encrypting them. The master user key should therefore > -be loaded in as secure a way as possible, preferably early in boot. > +for encryption/decryption. New keys are created either from kernel-generated > +random numbers or user-provided decrypted data, and are encrypted/decrypted > +using a specified ‘master’ key. The ‘master’ key can either be a trusted-key or > +user-key type. The main disadvantage of encrypted keys is that if they are not > +rooted in a trusted key, they are only as secure as the user key encrypting > +them. The master user key should therefore be loaded in as secure a way as > +possible, preferably early in boot. > > > Usage > @@ -199,6 +200,8 @@ Usage:: > > keyctl add encrypted name "new [format] key-type:master-key-name keylen" > 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 update keyid "update key-type:master-key-name" > > @@ -303,6 +306,16 @@ Load an encrypted key "evm" from saved blob:: > 82dbbc55be2a44616e4959430436dc4f2a7a9659aa60bb4652aeb2120f149ed197c564e0 > 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 > are anticipated. In particular the new format 'ecryptfs' has been defined > in order to use encrypted keys to mount an eCryptfs filesystem. More details > diff --git a/security/keys/Kconfig b/security/keys/Kconfig > index 969122c7b92f..0e30b361e1c1 100644 > --- a/security/keys/Kconfig > +++ b/security/keys/Kconfig > @@ -98,10 +98,21 @@ config ENCRYPTED_KEYS > select CRYPTO_RNG > help > This option provides support for create/encrypting/decrypting keys > - in the kernel. Encrypted keys are kernel generated random numbers, > - which are encrypted/decrypted with a 'master' symmetric key. The > - 'master' key can be either a trusted-key or user-key type. > - Userspace only ever sees/stores encrypted blobs. > + in the kernel. Encrypted keys are instantiated using kernel > + generated random numbers or provided decrypted data, and are > + encrypted/decrypted with a 'master' symmetric key. The 'master' > + 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. > > diff --git a/security/keys/encrypted-keys/encrypted.c b/security/keys/encrypted-keys/encrypted.c > index 87432b35d771..ebfb8129fb92 100644 > --- a/security/keys/encrypted-keys/encrypted.c > +++ b/security/keys/encrypted-keys/encrypted.c > @@ -78,6 +78,11 @@ static const match_table_t key_tokens = { > {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) > { > 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 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> > * <encrypted iv + data> > * 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, > char **master_desc, char **decrypted_datalen, > - char **hex_encoded_iv) > + char **hex_encoded_iv, char **decrypted_data) > { > substring_t args[MAX_OPT_ARGS]; > int ret = -EINVAL; > @@ -231,6 +236,7 @@ static int datablob_parse(char *datablob, const char **format, > "when called from .update method\n", keyword); > break; > } > + *decrypted_data = strsep(&datablob, " \t"); > ret = 0; > break; > 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, > const char *format, > const char *master_desc, > - const char *datalen) > + const char *datalen, > + const char *decrypted_data) > { > struct encrypted_key_payload *epayload = NULL; > 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 format_len; > long dlen; > + int i; > int ret; > > ret = kstrtol(datalen, 10, &dlen); > @@ -613,6 +620,24 @@ static struct encrypted_key_payload *encrypted_key_alloc(struct key *key, > format_len = (!format) ? strlen(key_format_default) : strlen(format); > decrypted_datalen = dlen; > 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 (!strcmp(format, key_format_ecryptfs)) { > 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 > * > - * For a new key, use a random number for both the iv and data > - * itself. For an old key, decrypt the hex encoded data. > + * For a new key, use either a random number or user-provided decrypted data in > + * 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, > const char *key_desc, const char *format, > const char *master_desc, const char *datalen, > - const char *hex_encoded_iv) > + const char *hex_encoded_iv, const char *decrypted_data) > { > int ret = 0; > > @@ -760,21 +787,26 @@ static int encrypted_init(struct encrypted_key_payload *epayload, > } > > __ekey_init(epayload, format, master_desc, datalen); > - if (!hex_encoded_iv) { > - get_random_bytes(epayload->iv, ivsize); > - > - get_random_bytes(epayload->decrypted_data, > - epayload->decrypted_datalen); > - } else > + if (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; > } > > /* > * encrypted_instantiate - instantiate an encrypted key > * > - * Decrypt an existing encrypted datablob or create a new encrypted key > - * based on a kernel random number. > + * Instantiates the key: > + * - 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. > */ > @@ -787,6 +819,7 @@ static int encrypted_instantiate(struct key *key, > char *master_desc = NULL; > char *decrypted_datalen = NULL; > char *hex_encoded_iv = NULL; > + char *decrypted_data = NULL; > size_t datalen = prep->datalen; > int ret; > > @@ -799,18 +832,18 @@ static int encrypted_instantiate(struct key *key, > datablob[datalen] = 0; > memcpy(datablob, prep->data, datalen); > ret = datablob_parse(datablob, &format, &master_desc, > - &decrypted_datalen, &hex_encoded_iv); > + &decrypted_datalen, &hex_encoded_iv, &decrypted_data); > if (ret < 0) > goto out; > > epayload = encrypted_key_alloc(key, format, master_desc, > - decrypted_datalen); > + decrypted_datalen, decrypted_data); > if (IS_ERR(epayload)) { > ret = PTR_ERR(epayload); > goto out; > } > ret = encrypted_init(epayload, key->description, format, master_desc, > - decrypted_datalen, hex_encoded_iv); > + decrypted_datalen, hex_encoded_iv, decrypted_data); > if (ret < 0) { > kfree_sensitive(epayload); > goto out; > @@ -860,7 +893,7 @@ static int encrypted_update(struct key *key, struct key_preparsed_payload *prep) > > buf[datalen] = 0; > 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) > goto out; > > @@ -869,7 +902,7 @@ static int encrypted_update(struct key *key, struct key_preparsed_payload *prep) > goto out; > > new_epayload = encrypted_key_alloc(key, epayload->format, > - new_master_desc, epayload->datalen); > + new_master_desc, epayload->datalen, NULL); > if (IS_ERR(new_epayload)) { > ret = PTR_ERR(new_epayload); > goto out; > -- > 2.35.1.265.g69c8d7142f-goog >