linux-security-module.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Roberto Sassu <roberto.sassu@huawei.com>
To: <zohar@linux.ibm.com>
Cc: <linux-integrity@vger.kernel.org>,
	<linux-security-module@vger.kernel.org>,
	<linux-kernel@vger.kernel.org>,
	Roberto Sassu <roberto.sassu@huawei.com>
Subject: [PATCH 6/7] evm: Allow choice of hash algorithm for HMAC
Date: Fri, 9 Apr 2021 13:43:12 +0200	[thread overview]
Message-ID: <20210409114313.4073-7-roberto.sassu@huawei.com> (raw)
In-Reply-To: <20210409114313.4073-1-roberto.sassu@huawei.com>

Commit 5feeb61183dd ("evm: Allow non-SHA1 digital signatures") introduced
the possibility to use a different hash algorithm for signatures, but kept
the algorithm for the HMAC hard-coded (SHA1). Switching to a different
algorithm for HMAC would require to change the code in different places.

This patch introduces a new global variable called evm_hash_algo, and
consistently uses it whenever EVM performs HMAC-related operations. This
variable can be modified at kernel build time with the new configuration
option called CONFIG_EVM_DEFAULT_HASH, or at run-time with the new option
evm_hash=.

Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com>
---
 .../admin-guide/kernel-parameters.txt         |  8 +++
 security/integrity/evm/Kconfig                | 34 ++++++++++++
 security/integrity/evm/evm.h                  |  2 +
 security/integrity/evm/evm_crypto.c           | 55 +++++++++++++++++--
 security/integrity/evm/evm_main.c             | 13 +++--
 security/integrity/integrity.h                |  3 +-
 6 files changed, 105 insertions(+), 10 deletions(-)

diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
index 265f7657f59d..f61ce44c5d8e 100644
--- a/Documentation/admin-guide/kernel-parameters.txt
+++ b/Documentation/admin-guide/kernel-parameters.txt
@@ -1343,6 +1343,14 @@
 			Permit 'security.evm' to be updated regardless of
 			current integrity status.
 
+	evm_hash=	[EVM] Hash algorithm used to calculate the HMAC.
+			Format: { md5 | sha1 | rmd160 | sha256 | sha384
+				   | sha512 | ... }
+			default: "sha256"
+
+			The list of supported hash algorithms is defined
+			in crypto/hash_info.h.
+
 	failslab=
 	fail_usercopy=
 	fail_page_alloc=
diff --git a/security/integrity/evm/Kconfig b/security/integrity/evm/Kconfig
index a6e19d23e700..234077b24283 100644
--- a/security/integrity/evm/Kconfig
+++ b/security/integrity/evm/Kconfig
@@ -13,6 +13,40 @@ config EVM
 
 	  If you are unsure how to answer this question, answer N.
 
+choice
+	prompt "Default EVM hash algorithm"
+	default EVM_DEFAULT_HASH_SHA256
+	depends on EVM
+	help
+	   Select the default hash algorithm used for the HMAC. The compiled
+	   default hash algorithm can be overwritten using the kernel command
+	   line 'evm_hash=' option.
+
+	config EVM_DEFAULT_HASH_SHA1
+		bool "SHA1"
+		depends on CRYPTO_SHA1=y
+
+	config EVM_DEFAULT_HASH_SHA256
+		bool "SHA256 (default)"
+		depends on CRYPTO_SHA256=y
+
+	config EVM_DEFAULT_HASH_SHA512
+		bool "SHA512"
+		depends on CRYPTO_SHA512=y
+
+	config EVM_DEFAULT_HASH_WP512
+		bool "WP512"
+		depends on CRYPTO_WP512=y
+endchoice
+
+config EVM_DEFAULT_HASH
+	string
+	depends on EVM
+	default "sha1" if EVM_DEFAULT_HASH_SHA1
+	default "sha256" if EVM_DEFAULT_HASH_SHA256
+	default "sha512" if EVM_DEFAULT_HASH_SHA512
+	default "wp512" if EVM_DEFAULT_HASH_WP512
+
 config EVM_ATTR_FSUUID
 	bool "FSUUID (version 2)"
 	default y
diff --git a/security/integrity/evm/evm.h b/security/integrity/evm/evm.h
index f2fef2b5ed51..ae590f71ce7d 100644
--- a/security/integrity/evm/evm.h
+++ b/security/integrity/evm/evm.h
@@ -32,6 +32,7 @@ struct xattr_list {
 };
 
 extern int evm_initialized;
+extern enum hash_algo evm_hash_algo;
 
 #define EVM_ATTR_FSUUID		0x0001
 
@@ -49,6 +50,7 @@ struct evm_digest {
 } __packed;
 
 int evm_init_key(void);
+int __init evm_init_crypto(void);
 int evm_update_evmxattr(struct dentry *dentry,
 			const char *req_xattr_name,
 			const char *req_xattr_value,
diff --git a/security/integrity/evm/evm_crypto.c b/security/integrity/evm/evm_crypto.c
index d76b006cbcc4..b66264b53d5d 100644
--- a/security/integrity/evm/evm_crypto.c
+++ b/security/integrity/evm/evm_crypto.c
@@ -33,7 +33,24 @@ static DEFINE_MUTEX(mutex);
 
 static unsigned long evm_set_key_flags;
 
-static const char evm_hmac[] = "hmac(sha1)";
+enum hash_algo evm_hash_algo __ro_after_init = HASH_ALGO_SHA1;
+
+static int hash_setup_done;
+static int __init hash_setup(char *str)
+{
+	int i;
+
+	i = match_string(hash_algo_name, HASH_ALGO__LAST, str);
+	if (i < 0) {
+		pr_err("invalid hash algorithm \"%s\"", str);
+		return 1;
+	}
+
+	evm_hash_algo = i;
+	hash_setup_done = 1;
+	return 1;
+}
+__setup("evm_hash=", hash_setup);
 
 /**
  * evm_set_key() - set EVM HMAC key from the kernel
@@ -74,8 +91,12 @@ static struct shash_desc *init_desc(char type, uint8_t hash_algo)
 	long rc;
 	const char *algo;
 	struct crypto_shash **tfm, *tmp_tfm = NULL;
+	char evm_hmac[CRYPTO_MAX_ALG_NAME];
 	struct shash_desc *desc;
 
+	snprintf(evm_hmac, sizeof(evm_hmac), "hmac(%s)",
+		 hash_algo_name[evm_hash_algo]);
+
 	if (type == EVM_XATTR_HMAC) {
 		if (!(evm_initialized & EVM_INIT_HMAC)) {
 			pr_err_once("HMAC key is not set\n");
@@ -317,7 +338,7 @@ int evm_update_evmxattr(struct dentry *dentry, const char *xattr_name,
 	if (rc)
 		return -EPERM;
 
-	data.hdr.algo = HASH_ALGO_SHA1;
+	data.hdr.algo = evm_hash_algo;
 	rc = evm_calc_hmac(dentry, xattr_name, xattr_value,
 			   xattr_value_len, &data);
 	if (rc == 0) {
@@ -325,7 +346,8 @@ int evm_update_evmxattr(struct dentry *dentry, const char *xattr_name,
 		rc = __vfs_setxattr_noperm(&init_user_ns, dentry,
 					   XATTR_NAME_EVM,
 					   &data.hdr.xattr.data[1],
-					   SHA1_DIGEST_SIZE + 1, 0);
+					   hash_digest_size[evm_hash_algo] + 1,
+					   0);
 	} else if (rc == -ENODATA && (inode->i_opflags & IOP_XATTR)) {
 		rc = __vfs_removexattr(&init_user_ns, dentry, XATTR_NAME_EVM);
 	}
@@ -337,7 +359,7 @@ int evm_init_hmac(struct inode *inode, const struct xattr *lsm_xattr,
 {
 	struct shash_desc *desc;
 
-	desc = init_desc(EVM_XATTR_HMAC, HASH_ALGO_SHA1);
+	desc = init_desc(EVM_XATTR_HMAC, evm_hash_algo);
 	if (IS_ERR(desc)) {
 		pr_info("init_desc failed\n");
 		return PTR_ERR(desc);
@@ -350,7 +372,7 @@ int evm_init_hmac(struct inode *inode, const struct xattr *lsm_xattr,
 }
 
 /*
- * Get the key from the TPM for the SHA1-HMAC
+ * Get the key from the TPM for the HMAC
  */
 int evm_init_key(void)
 {
@@ -373,3 +395,26 @@ int evm_init_key(void)
 	key_put(evm_key);
 	return rc;
 }
+
+/*
+ * Configure the hash algorithm for the HMAC
+ */
+int __init evm_init_crypto(void)
+{
+	int i;
+
+	if (hash_setup_done)
+		return 0;
+
+	i = match_string(hash_algo_name, HASH_ALGO__LAST,
+			 CONFIG_EVM_DEFAULT_HASH);
+	if (i < 0) {
+		pr_err("invalid hash algorithm \"%s\"",
+		       CONFIG_EVM_DEFAULT_HASH);
+		return -EINVAL;
+	}
+
+	evm_hash_algo = i;
+
+	return 0;
+}
diff --git a/security/integrity/evm/evm_main.c b/security/integrity/evm/evm_main.c
index 8e80af97021e..cb3754e0cc60 100644
--- a/security/integrity/evm/evm_main.c
+++ b/security/integrity/evm/evm_main.c
@@ -187,18 +187,18 @@ static enum integrity_status evm_verify_hmac(struct dentry *dentry,
 	/* check value type */
 	switch (xattr_data->type) {
 	case EVM_XATTR_HMAC:
-		if (xattr_len != sizeof(struct evm_xattr)) {
+		if (xattr_len != hash_digest_size[evm_hash_algo] + 1) {
 			evm_status = INTEGRITY_FAIL;
 			goto out;
 		}
 
-		digest.hdr.algo = HASH_ALGO_SHA1;
+		digest.hdr.algo = evm_hash_algo;
 		rc = evm_calc_hmac(dentry, xattr_name, xattr_value,
 				   xattr_value_len, &digest);
 		if (rc)
 			break;
 		rc = crypto_memneq(xattr_data->data, digest.digest,
-				   SHA1_DIGEST_SIZE);
+				   hash_digest_size[evm_hash_algo]);
 		if (rc)
 			rc = -EINVAL;
 		break;
@@ -722,7 +722,7 @@ int evm_inode_init_security(struct inode *inode,
 		goto out;
 
 	evm_xattr->value = xattr_data;
-	evm_xattr->value_len = sizeof(*xattr_data);
+	evm_xattr->value_len = hash_digest_size[evm_hash_algo] + 1;
 	evm_xattr->name = XATTR_EVM_SUFFIX;
 	return 0;
 out:
@@ -759,6 +759,11 @@ static int __init init_evm(void)
 		goto error;
 	}
 
+	error = evm_init_crypto();
+	if (error < 0) {
+		pr_info("Error initializing crypto\n");
+		goto error;
+	}
 error:
 	if (error != 0) {
 		if (!list_empty(&evm_config_xattrnames)) {
diff --git a/security/integrity/integrity.h b/security/integrity/integrity.h
index be501a63ae30..74919b638f52 100644
--- a/security/integrity/integrity.h
+++ b/security/integrity/integrity.h
@@ -17,6 +17,7 @@
 #include <crypto/sha1.h>
 #include <linux/key.h>
 #include <linux/audit.h>
+#include <crypto/hash_info.h>
 
 /* iint action cache flags */
 #define IMA_MEASURE		0x00000001
@@ -89,7 +90,7 @@ struct evm_ima_xattr_data {
 /* Only used in the EVM HMAC code. */
 struct evm_xattr {
 	struct evm_ima_xattr_data data;
-	u8 digest[SHA1_DIGEST_SIZE];
+	u8 digest[SHA512_DIGEST_SIZE];
 } __packed;
 
 #define IMA_MAX_DIGEST_SIZE	64
-- 
2.26.2


  parent reply	other threads:[~2021-04-09 11:45 UTC|newest]

Thread overview: 8+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-04-09 11:43 [PATCH 0/7] ima/evm: Small enhancements Roberto Sassu
2021-04-09 11:43 ` [PATCH 1/7] ima: Avoid measurement and audit if access to the file will be denied Roberto Sassu
2021-04-09 11:43 ` [PATCH 2/7] ima: Add meta_immutable appraisal type Roberto Sassu
2021-04-09 11:43 ` [PATCH 3/7] ima: Introduce exec_tcb and tmpfs policies Roberto Sassu
2021-04-09 11:43 ` [PATCH 4/7] ima: Introduce appraise_exec_tcb and appraise_tmpfs policies Roberto Sassu
2021-04-09 11:43 ` [PATCH 5/7] ima: Introduce appraise_exec_immutable policy Roberto Sassu
2021-04-09 11:43 ` Roberto Sassu [this message]
2021-04-09 11:43 ` [PATCH 7/7] evm: Extend evm= with allow_metadata_writes and complete values Roberto Sassu

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20210409114313.4073-7-roberto.sassu@huawei.com \
    --to=roberto.sassu@huawei.com \
    --cc=linux-integrity@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-security-module@vger.kernel.org \
    --cc=zohar@linux.ibm.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).