From 26ddabfe96bb7468763c9c92791404d991b16250 Mon Sep 17 00:00:00 2001 From: Dmitry Kasatkin Date: Thu, 22 Oct 2015 21:26:26 +0300 Subject: evm: enable EVM when X509 certificate is loaded In order to enable EVM before starting the 'init' process, evm_initialized needs to be non-zero. Previously non-zero indicated that the HMAC key was loaded. When EVM loads the X509 before calling 'init', with this patch it is now possible to enable EVM to start signature based verification. This patch defines bits to enable EVM if a key of any type is loaded. Changes in v3: * print error message if key is not set Changes in v2: * EVM_STATE_KEY_SET replaced by EVM_INIT_HMAC * EVM_STATE_X509_SET replaced by EVM_INIT_X509 Signed-off-by: Dmitry Kasatkin Signed-off-by: Mimi Zohar --- security/integrity/evm/evm_secfs.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'security/integrity/evm/evm_secfs.c') diff --git a/security/integrity/evm/evm_secfs.c b/security/integrity/evm/evm_secfs.c index cf12a04717d3..3f775dfea868 100644 --- a/security/integrity/evm/evm_secfs.c +++ b/security/integrity/evm/evm_secfs.c @@ -64,7 +64,7 @@ static ssize_t evm_write_key(struct file *file, const char __user *buf, char temp[80]; int i, error; - if (!capable(CAP_SYS_ADMIN) || evm_initialized) + if (!capable(CAP_SYS_ADMIN) || (evm_initialized & EVM_INIT_HMAC)) return -EPERM; if (count >= sizeof(temp) || count == 0) @@ -80,7 +80,7 @@ static ssize_t evm_write_key(struct file *file, const char __user *buf, error = evm_init_key(); if (!error) { - evm_initialized = 1; + evm_initialized |= EVM_INIT_HMAC; pr_info("initialized\n"); } else pr_err("initialization failed\n"); -- cgit v1.2.3 From 7626676320f398980a6bb4490fd58e924c888f6a Mon Sep 17 00:00:00 2001 From: Dmitry Kasatkin Date: Thu, 22 Oct 2015 21:26:32 +0300 Subject: evm: provide a function to set the EVM key from the kernel A crypto HW kernel module can possibly initialize the EVM key from the kernel __init code to enable EVM before calling the 'init' process. This patch provides a function evm_set_key() to set the EVM key directly without using the KEY subsystem. Changes in v4: * kernel-doc style for evm_set_key Changes in v3: * error reporting moved to evm_set_key * EVM_INIT_HMAC moved to evm_set_key * added bitop to prevent key setting race Changes in v2: * use size_t for key size instead of signed int * provide EVM_MAX_KEY_SIZE macro in * provide EVM_MIN_KEY_SIZE macro in Signed-off-by: Dmitry Kasatkin Signed-off-by: Mimi Zohar --- include/linux/evm.h | 7 ++++++ security/integrity/evm/evm_crypto.c | 50 +++++++++++++++++++++++++++++++------ security/integrity/evm/evm_secfs.c | 10 +++----- 3 files changed, 53 insertions(+), 14 deletions(-) (limited to 'security/integrity/evm/evm_secfs.c') diff --git a/include/linux/evm.h b/include/linux/evm.h index 1fcb88ca88de..35ed9a8a403a 100644 --- a/include/linux/evm.h +++ b/include/linux/evm.h @@ -14,6 +14,7 @@ struct integrity_iint_cache; #ifdef CONFIG_EVM +extern int evm_set_key(void *key, size_t keylen); extern enum integrity_status evm_verifyxattr(struct dentry *dentry, const char *xattr_name, void *xattr_value, @@ -42,6 +43,12 @@ static inline int posix_xattr_acl(const char *xattrname) } #endif #else + +static inline int evm_set_key(void *key, size_t keylen) +{ + return -EOPNOTSUPP; +} + #ifdef CONFIG_INTEGRITY static inline enum integrity_status evm_verifyxattr(struct dentry *dentry, const char *xattr_name, diff --git a/security/integrity/evm/evm_crypto.c b/security/integrity/evm/evm_crypto.c index 2c3591eca989..30b6b7d0429f 100644 --- a/security/integrity/evm/evm_crypto.c +++ b/security/integrity/evm/evm_crypto.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include "evm.h" @@ -32,6 +33,44 @@ struct crypto_shash *hash_tfm; static DEFINE_MUTEX(mutex); +#define EVM_SET_KEY_BUSY 0 + +static unsigned long evm_set_key_flags; + +/** + * evm_set_key() - set EVM HMAC key from the kernel + * @key: pointer to a buffer with the key data + * @size: length of the key data + * + * This function allows setting the EVM HMAC key from the kernel + * without using the "encrypted" key subsystem keys. It can be used + * by the crypto HW kernel module which has its own way of managing + * keys. + * + * key length should be between 32 and 128 bytes long + */ +int evm_set_key(void *key, size_t keylen) +{ + int rc; + + rc = -EBUSY; + if (test_and_set_bit(EVM_SET_KEY_BUSY, &evm_set_key_flags)) + goto busy; + rc = -EINVAL; + if (keylen > MAX_KEY_SIZE) + goto inval; + memcpy(evmkey, key, keylen); + evm_initialized |= EVM_INIT_HMAC; + pr_info("key initialized\n"); + return 0; +inval: + clear_bit(EVM_SET_KEY_BUSY, &evm_set_key_flags); +busy: + pr_err("key initialization failed\n"); + return rc; +} +EXPORT_SYMBOL_GPL(evm_set_key); + static struct shash_desc *init_desc(char type) { long rc; @@ -244,7 +283,7 @@ int evm_init_key(void) { struct key *evm_key; struct encrypted_key_payload *ekp; - int rc = 0; + int rc; evm_key = request_key(&key_type_encrypted, EVMKEY, NULL); if (IS_ERR(evm_key)) @@ -252,12 +291,9 @@ int evm_init_key(void) down_read(&evm_key->sem); ekp = evm_key->payload.data[0]; - if (ekp->decrypted_datalen > MAX_KEY_SIZE) { - rc = -EINVAL; - goto out; - } - memcpy(evmkey, ekp->decrypted_data, ekp->decrypted_datalen); -out: + + rc = evm_set_key(ekp->decrypted_data, ekp->decrypted_datalen); + /* burn the original key contents */ memset(ekp->decrypted_data, 0, ekp->decrypted_datalen); up_read(&evm_key->sem); diff --git a/security/integrity/evm/evm_secfs.c b/security/integrity/evm/evm_secfs.c index 3f775dfea868..c8dccd54d501 100644 --- a/security/integrity/evm/evm_secfs.c +++ b/security/integrity/evm/evm_secfs.c @@ -62,7 +62,7 @@ static ssize_t evm_write_key(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { char temp[80]; - int i, error; + int i; if (!capable(CAP_SYS_ADMIN) || (evm_initialized & EVM_INIT_HMAC)) return -EPERM; @@ -78,12 +78,8 @@ static ssize_t evm_write_key(struct file *file, const char __user *buf, if ((sscanf(temp, "%d", &i) != 1) || (i != 1)) return -EINVAL; - error = evm_init_key(); - if (!error) { - evm_initialized |= EVM_INIT_HMAC; - pr_info("initialized\n"); - } else - pr_err("initialization failed\n"); + evm_init_key(); + return count; } -- cgit v1.2.3