Commit 7f313ff0 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'integrity-v5.18' of git://git.kernel.org/pub/scm/linux/kernel/git/zohar/linux-integrity

Pull integrity subsystem updates from Mimi Zohar:
 "Except for extending the 'encrypted' key type to support user provided
  data, the rest is code cleanup, __setup() usage bug fix, and a trivial
  change"

* tag 'integrity-v5.18' of git://git.kernel.org/pub/scm/linux/kernel/git/zohar/linux-integrity:
  MAINTAINERS: add missing security/integrity/platform_certs
  EVM: fix the evm= __setup handler return value
  KEYS: encrypted: Instantiate key with user-provided decrypted data
  ima: define ima_max_digest_data struct without a flexible array variable
  ima: rename IMA_ACTION_FLAGS to IMA_NONACTION_FLAGS
  ima: Return error code obtained from securityfs functions
  MAINTAINERS: add missing "security/integrity" directory
  ima: Fix trivial typos in the comments
parents 2c5a5358 4a48b4c4
...@@ -107,12 +107,13 @@ Encrypted Keys ...@@ -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:: ...@@ -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:: ...@@ -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
......
...@@ -7280,7 +7280,9 @@ Extended Verification Module (EVM) ...@@ -7280,7 +7280,9 @@ Extended Verification Module (EVM)
M: Mimi Zohar <zohar@linux.ibm.com> M: Mimi Zohar <zohar@linux.ibm.com>
L: linux-integrity@vger.kernel.org L: linux-integrity@vger.kernel.org
S: Supported S: Supported
T: git git://git.kernel.org/pub/scm/linux/kernel/git/zohar/linux-integrity.git
F: security/integrity/evm/ F: security/integrity/evm/
F: security/integrity/
EXTENSIBLE FIRMWARE INTERFACE (EFI) EXTENSIBLE FIRMWARE INTERFACE (EFI)
M: Ard Biesheuvel <ardb@kernel.org> M: Ard Biesheuvel <ardb@kernel.org>
...@@ -9537,6 +9539,7 @@ L: linux-integrity@vger.kernel.org ...@@ -9537,6 +9539,7 @@ L: linux-integrity@vger.kernel.org
S: Supported S: Supported
T: git git://git.kernel.org/pub/scm/linux/kernel/git/zohar/linux-integrity.git T: git git://git.kernel.org/pub/scm/linux/kernel/git/zohar/linux-integrity.git
F: security/integrity/ima/ F: security/integrity/ima/
F: security/integrity/
INTEL 810/815 FRAMEBUFFER DRIVER INTEL 810/815 FRAMEBUFFER DRIVER
M: Antonino Daplas <adaplas@gmail.com> M: Antonino Daplas <adaplas@gmail.com>
...@@ -10675,6 +10678,14 @@ F: include/linux/keyctl.h ...@@ -10675,6 +10678,14 @@ F: include/linux/keyctl.h
F: include/uapi/linux/keyctl.h F: include/uapi/linux/keyctl.h
F: security/keys/ F: security/keys/
KEYS/KEYRINGS_INTEGRITY
M: Jarkko Sakkinen <jarkko@kernel.org>
M: Mimi Zohar <zohar@linux.ibm.com>
L: linux-integrity@vger.kernel.org
L: keyrings@vger.kernel.org
S: Supported
F: security/integrity/platform_certs
KFENCE KFENCE
M: Alexander Potapenko <glider@google.com> M: Alexander Potapenko <glider@google.com>
M: Marco Elver <elver@google.com> M: Marco Elver <elver@google.com>
......
...@@ -86,7 +86,7 @@ static int __init evm_set_fixmode(char *str) ...@@ -86,7 +86,7 @@ static int __init evm_set_fixmode(char *str)
else else
pr_err("invalid \"%s\" mode", str); pr_err("invalid \"%s\" mode", str);
return 0; return 1;
} }
__setup("evm=", evm_set_fixmode); __setup("evm=", evm_set_fixmode);
......
...@@ -217,14 +217,11 @@ int ima_collect_measurement(struct integrity_iint_cache *iint, ...@@ -217,14 +217,11 @@ int ima_collect_measurement(struct integrity_iint_cache *iint,
const char *audit_cause = "failed"; const char *audit_cause = "failed";
struct inode *inode = file_inode(file); struct inode *inode = file_inode(file);
const char *filename = file->f_path.dentry->d_name.name; const char *filename = file->f_path.dentry->d_name.name;
struct ima_max_digest_data hash;
int result = 0; int result = 0;
int length; int length;
void *tmpbuf; void *tmpbuf;
u64 i_version; u64 i_version;
struct {
struct ima_digest_data hdr;
char digest[IMA_MAX_DIGEST_SIZE];
} hash;
/* /*
* Always collect the modsig, because IMA might have already collected * Always collect the modsig, because IMA might have already collected
...@@ -238,9 +235,10 @@ int ima_collect_measurement(struct integrity_iint_cache *iint, ...@@ -238,9 +235,10 @@ int ima_collect_measurement(struct integrity_iint_cache *iint,
goto out; goto out;
/* /*
* Dectecting file change is based on i_version. On filesystems * Detecting file change is based on i_version. On filesystems
* which do not support i_version, support is limited to an initial * which do not support i_version, support was originally limited
* measurement/appraisal/audit. * to an initial measurement/appraisal/audit, but was modified to
* assume the file changed.
*/ */
i_version = inode_query_iversion(inode); i_version = inode_query_iversion(inode);
hash.hdr.algo = algo; hash.hdr.algo = algo;
......
...@@ -452,47 +452,61 @@ static const struct file_operations ima_measure_policy_ops = { ...@@ -452,47 +452,61 @@ static const struct file_operations ima_measure_policy_ops = {
int __init ima_fs_init(void) int __init ima_fs_init(void)
{ {
int ret;
ima_dir = securityfs_create_dir("ima", integrity_dir); ima_dir = securityfs_create_dir("ima", integrity_dir);
if (IS_ERR(ima_dir)) if (IS_ERR(ima_dir))
return -1; return PTR_ERR(ima_dir);
ima_symlink = securityfs_create_symlink("ima", NULL, "integrity/ima", ima_symlink = securityfs_create_symlink("ima", NULL, "integrity/ima",
NULL); NULL);
if (IS_ERR(ima_symlink)) if (IS_ERR(ima_symlink)) {
ret = PTR_ERR(ima_symlink);
goto out; goto out;
}
binary_runtime_measurements = binary_runtime_measurements =
securityfs_create_file("binary_runtime_measurements", securityfs_create_file("binary_runtime_measurements",
S_IRUSR | S_IRGRP, ima_dir, NULL, S_IRUSR | S_IRGRP, ima_dir, NULL,
&ima_measurements_ops); &ima_measurements_ops);
if (IS_ERR(binary_runtime_measurements)) if (IS_ERR(binary_runtime_measurements)) {
ret = PTR_ERR(binary_runtime_measurements);
goto out; goto out;
}
ascii_runtime_measurements = ascii_runtime_measurements =
securityfs_create_file("ascii_runtime_measurements", securityfs_create_file("ascii_runtime_measurements",
S_IRUSR | S_IRGRP, ima_dir, NULL, S_IRUSR | S_IRGRP, ima_dir, NULL,
&ima_ascii_measurements_ops); &ima_ascii_measurements_ops);
if (IS_ERR(ascii_runtime_measurements)) if (IS_ERR(ascii_runtime_measurements)) {
ret = PTR_ERR(ascii_runtime_measurements);
goto out; goto out;
}
runtime_measurements_count = runtime_measurements_count =
securityfs_create_file("runtime_measurements_count", securityfs_create_file("runtime_measurements_count",
S_IRUSR | S_IRGRP, ima_dir, NULL, S_IRUSR | S_IRGRP, ima_dir, NULL,
&ima_measurements_count_ops); &ima_measurements_count_ops);
if (IS_ERR(runtime_measurements_count)) if (IS_ERR(runtime_measurements_count)) {
ret = PTR_ERR(runtime_measurements_count);
goto out; goto out;
}
violations = violations =
securityfs_create_file("violations", S_IRUSR | S_IRGRP, securityfs_create_file("violations", S_IRUSR | S_IRGRP,
ima_dir, NULL, &ima_htable_violations_ops); ima_dir, NULL, &ima_htable_violations_ops);
if (IS_ERR(violations)) if (IS_ERR(violations)) {
ret = PTR_ERR(violations);
goto out; goto out;
}
ima_policy = securityfs_create_file("policy", POLICY_FILE_FLAGS, ima_policy = securityfs_create_file("policy", POLICY_FILE_FLAGS,
ima_dir, NULL, ima_dir, NULL,
&ima_measure_policy_ops); &ima_measure_policy_ops);
if (IS_ERR(ima_policy)) if (IS_ERR(ima_policy)) {
ret = PTR_ERR(ima_policy);
goto out; goto out;
}
return 0; return 0;
out: out:
...@@ -503,5 +517,6 @@ int __init ima_fs_init(void) ...@@ -503,5 +517,6 @@ int __init ima_fs_init(void)
securityfs_remove(binary_runtime_measurements); securityfs_remove(binary_runtime_measurements);
securityfs_remove(ima_symlink); securityfs_remove(ima_symlink);
securityfs_remove(ima_dir); securityfs_remove(ima_dir);
return -1;
return ret;
} }
...@@ -47,12 +47,9 @@ static int __init ima_add_boot_aggregate(void) ...@@ -47,12 +47,9 @@ static int __init ima_add_boot_aggregate(void)
struct integrity_iint_cache tmp_iint, *iint = &tmp_iint; struct integrity_iint_cache tmp_iint, *iint = &tmp_iint;
struct ima_event_data event_data = { .iint = iint, struct ima_event_data event_data = { .iint = iint,
.filename = boot_aggregate_name }; .filename = boot_aggregate_name };
struct ima_max_digest_data hash;
int result = -ENOMEM; int result = -ENOMEM;
int violation = 0; int violation = 0;
struct {
struct ima_digest_data hdr;
char digest[TPM_MAX_DIGEST_SIZE];
} hash;
memset(iint, 0, sizeof(*iint)); memset(iint, 0, sizeof(*iint));
memset(&hash, 0, sizeof(hash)); memset(&hash, 0, sizeof(hash));
......
...@@ -263,7 +263,7 @@ static int process_measurement(struct file *file, const struct cred *cred, ...@@ -263,7 +263,7 @@ static int process_measurement(struct file *file, const struct cred *cred,
/* reset appraisal flags if ima_inode_post_setattr was called */ /* reset appraisal flags if ima_inode_post_setattr was called */
iint->flags &= ~(IMA_APPRAISE | IMA_APPRAISED | iint->flags &= ~(IMA_APPRAISE | IMA_APPRAISED |
IMA_APPRAISE_SUBMASK | IMA_APPRAISED_SUBMASK | IMA_APPRAISE_SUBMASK | IMA_APPRAISED_SUBMASK |
IMA_ACTION_FLAGS); IMA_NONACTION_FLAGS);
/* /*
* Re-evaulate the file if either the xattr has changed or the * Re-evaulate the file if either the xattr has changed or the
...@@ -764,7 +764,7 @@ int ima_post_read_file(struct file *file, void *buf, loff_t size, ...@@ -764,7 +764,7 @@ int ima_post_read_file(struct file *file, void *buf, loff_t size,
* call to ima_post_load_data(). * call to ima_post_load_data().
* *
* Callers of this LSM hook can not measure, appraise, or audit the * Callers of this LSM hook can not measure, appraise, or audit the
* data provided by userspace. Enforce policy rules requring a file * data provided by userspace. Enforce policy rules requiring a file
* signature (eg. kexec'ed kernel image). * signature (eg. kexec'ed kernel image).
* *
* For permission return 0, otherwise return -EACCES. * For permission return 0, otherwise return -EACCES.
...@@ -874,10 +874,7 @@ int process_buffer_measurement(struct user_namespace *mnt_userns, ...@@ -874,10 +874,7 @@ int process_buffer_measurement(struct user_namespace *mnt_userns,
.buf = buf, .buf = buf,
.buf_len = size}; .buf_len = size};
struct ima_template_desc *template; struct ima_template_desc *template;
struct { struct ima_max_digest_data hash;
struct ima_digest_data hdr;
char digest[IMA_MAX_DIGEST_SIZE];
} hash = {};
char digest_hash[IMA_MAX_DIGEST_SIZE]; char digest_hash[IMA_MAX_DIGEST_SIZE];
int digest_hash_len = hash_digest_size[ima_hash_algo]; int digest_hash_len = hash_digest_size[ima_hash_algo];
int violation = 0; int violation = 0;
......
...@@ -428,7 +428,7 @@ static int ima_lsm_update_rule(struct ima_rule_entry *entry) ...@@ -428,7 +428,7 @@ static int ima_lsm_update_rule(struct ima_rule_entry *entry)
/* /*
* ima_lsm_copy_rule() shallow copied all references, except for the * ima_lsm_copy_rule() shallow copied all references, except for the
* LSM references, from entry to nentry so we only want to free the LSM * LSM references, from entry to nentry so we only want to free the LSM
* references and the entry itself. All other memory refrences will now * references and the entry itself. All other memory references will now
* be owned by nentry. * be owned by nentry.
*/ */
ima_lsm_free_rule(entry); ima_lsm_free_rule(entry);
...@@ -711,7 +711,7 @@ int ima_match_policy(struct user_namespace *mnt_userns, struct inode *inode, ...@@ -711,7 +711,7 @@ int ima_match_policy(struct user_namespace *mnt_userns, struct inode *inode,
func, mask, func_data)) func, mask, func_data))
continue; continue;
action |= entry->flags & IMA_ACTION_FLAGS; action |= entry->flags & IMA_NONACTION_FLAGS;
action |= entry->action & IMA_DO_MASK; action |= entry->action & IMA_DO_MASK;
if (entry->action & IMA_APPRAISE) { if (entry->action & IMA_APPRAISE) {
......
...@@ -272,7 +272,7 @@ static int ima_eventdigest_init_common(const u8 *digest, u32 digestsize, ...@@ -272,7 +272,7 @@ static int ima_eventdigest_init_common(const u8 *digest, u32 digestsize,
* digest formats: * digest formats:
* - DATA_FMT_DIGEST: digest * - DATA_FMT_DIGEST: digest
* - DATA_FMT_DIGEST_WITH_ALGO: [<hash algo>] + ':' + '\0' + digest, * - DATA_FMT_DIGEST_WITH_ALGO: [<hash algo>] + ':' + '\0' + digest,
* where <hash algo> is provided if the hash algoritm is not * where <hash algo> is provided if the hash algorithm is not
* SHA1 or MD5 * SHA1 or MD5
*/ */
u8 buffer[CRYPTO_MAX_ALG_NAME + 2 + IMA_MAX_DIGEST_SIZE] = { 0 }; u8 buffer[CRYPTO_MAX_ALG_NAME + 2 + IMA_MAX_DIGEST_SIZE] = { 0 };
...@@ -307,10 +307,7 @@ static int ima_eventdigest_init_common(const u8 *digest, u32 digestsize, ...@@ -307,10 +307,7 @@ static int ima_eventdigest_init_common(const u8 *digest, u32 digestsize,
int ima_eventdigest_init(struct ima_event_data *event_data, int ima_eventdigest_init(struct ima_event_data *event_data,
struct ima_field_data *field_data) struct ima_field_data *field_data)
{ {
struct { struct ima_max_digest_data hash;
struct ima_digest_data hdr;
char digest[IMA_MAX_DIGEST_SIZE];
} hash;
u8 *cur_digest = NULL; u8 *cur_digest = NULL;
u32 cur_digestsize = 0; u32 cur_digestsize = 0;
struct inode *inode; struct inode *inode;
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#include <linux/types.h> #include <linux/types.h>
#include <linux/integrity.h> #include <linux/integrity.h>
#include <crypto/sha1.h> #include <crypto/sha1.h>
#include <crypto/hash.h>
#include <linux/key.h> #include <linux/key.h>
#include <linux/audit.h> #include <linux/audit.h>
...@@ -30,8 +31,8 @@ ...@@ -30,8 +31,8 @@
#define IMA_HASH 0x00000100 #define IMA_HASH 0x00000100
#define IMA_HASHED 0x00000200 #define IMA_HASHED 0x00000200
/* iint cache flags */ /* iint policy rule cache flags */
#define IMA_ACTION_FLAGS 0xff000000 #define IMA_NONACTION_FLAGS 0xff000000
#define IMA_DIGSIG_REQUIRED 0x01000000 #define IMA_DIGSIG_REQUIRED 0x01000000
#define IMA_PERMIT_DIRECTIO 0x02000000 #define IMA_PERMIT_DIRECTIO 0x02000000
#define IMA_NEW_FILE 0x04000000 #define IMA_NEW_FILE 0x04000000
...@@ -110,6 +111,15 @@ struct ima_digest_data { ...@@ -110,6 +111,15 @@ struct ima_digest_data {
u8 digest[]; u8 digest[];
} __packed; } __packed;
/*
* Instead of wrapping the ima_digest_data struct inside a local structure
* with the maximum hash size, define ima_max_digest_data struct.
*/
struct ima_max_digest_data {
struct ima_digest_data hdr;
u8 digest[HASH_MAX_DIGESTSIZE];
} __packed;
/* /*
* signature format v2 - for using with asymmetric keys * signature format v2 - for using with asymmetric keys
*/ */
......
...@@ -98,10 +98,21 @@ config ENCRYPTED_KEYS ...@@ -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 = { ...@@ -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) ...@@ -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) ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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) {
ret = encrypted_key_decrypt(epayload, format, hex_encoded_iv);
} else if (decrypted_data) {
get_random_bytes(epayload->iv, ivsize); get_random_bytes(epayload->iv, ivsize);
memcpy(epayload->decrypted_data, decrypted_data,
get_random_bytes(epayload->decrypted_data,
epayload->decrypted_datalen); epayload->decrypted_datalen);
} else } else {
ret = encrypted_key_decrypt(epayload, format, hex_encoded_iv); 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, ...@@ -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, ...@@ -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) ...@@ -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) ...@@ -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;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment