All of lore.kernel.org
 help / color / mirror / Atom feed
From: Dmitry Kasatkin <dmitry.kasatkin@intel.com>
To: linux-security-module@vger.kernel.org
Cc: linux-crypto@vger.kernel.org, linux-kernel@vger.kernel.org,
	zohar@linux.vnet.ibm.com, dhowells@redhat.com,
	herbert@gondor.hengli.com.au
Subject: [RFC v2.1 6/6] evm: digital signature verification support
Date: Tue, 13 Sep 2011 17:20:13 +0300	[thread overview]
Message-ID: <7ff1998aaa5f303bf81ade4588fd607587df0c1a.1315921427.git.dmitry.kasatkin@intel.com> (raw)
In-Reply-To: <cover.1315921427.git.dmitry.kasatkin@intel.com>
In-Reply-To: <cover.1315921427.git.dmitry.kasatkin@intel.com>

This option enables digital signature verification support for EVM.
With this feature file metadata can be protected using digital
signature instead of HMAC. When building an image,
which has to be flashed to different devices, an HMAC cannot
be used to sign file metadata, because the HMAC key is different on
every device. File metadata can be protected using digital signature.

Signed-off-by: Dmitry Kasatkin <dmitry.kasatkin@intel.com>
Acked-by: Mimi Zohar <zohar@us.ibm.com>
---
 security/integrity/evm/Kconfig      |   15 ++++
 security/integrity/evm/evm.h        |   12 ++++
 security/integrity/evm/evm_crypto.c |   66 ++++++++++++++-----
 security/integrity/evm/evm_main.c   |  125 +++++++++++++++++++++++++++++++----
 4 files changed, 188 insertions(+), 30 deletions(-)

diff --git a/security/integrity/evm/Kconfig b/security/integrity/evm/Kconfig
index 884617d..4397bb6 100644
--- a/security/integrity/evm/Kconfig
+++ b/security/integrity/evm/Kconfig
@@ -12,3 +12,18 @@ config EVM
 	  integrity attacks.
 
 	  If you are unsure how to answer this question, answer N.
+
+config EVM_DIGSIG
+	boolean "EVM Digital Signature support"
+	depends on EVM
+	default n
+	select CRYPTO_KSIGN_RSA
+	help
+	  This option enables digital signature verification support for EVM.
+	  With this feature file metadata can be protected using digital
+	  signature instead of HMAC. When building an image,
+	  which has to be flashed to different devices, an HMAC cannot
+	  be used to sign file metadata, because the HMAC key is different on
+	  every device. File metadata can be protected using digital signature.
+
+	  If unsure, say N.
diff --git a/security/integrity/evm/evm.h b/security/integrity/evm/evm.h
index d320f51..c885247 100644
--- a/security/integrity/evm/evm.h
+++ b/security/integrity/evm/evm.h
@@ -12,14 +12,21 @@
  * File: evm.h
  *
  */
+
+#ifndef __INTEGRITY_EVM_H
+#define __INTEGRITY_EVM_H
+
 #include <linux/xattr.h>
 #include <linux/security.h>
+
 #include "../integrity.h"
 
 extern int evm_initialized;
 extern char *evm_hmac;
+extern char *evm_hash;
 
 extern struct crypto_shash *hmac_tfm;
+extern struct crypto_shash *hash_tfm;
 
 /* List of EVM protected security xattrs */
 extern char *evm_config_xattrnames[];
@@ -32,7 +39,12 @@ extern int evm_update_evmxattr(struct dentry *dentry,
 extern int evm_calc_hmac(struct dentry *dentry, const char *req_xattr_name,
 			 const char *req_xattr_value,
 			 size_t req_xattr_value_len, char *digest);
+extern int evm_calc_hash(struct dentry *dentry, const char *req_xattr_name,
+			 const char *req_xattr_value,
+			 size_t req_xattr_value_len, char *digest);
 extern int evm_init_hmac(struct inode *inode, const struct xattr *xattr,
 			 char *hmac_val);
 extern int evm_init_secfs(void);
 extern void evm_cleanup_secfs(void);
+
+#endif
diff --git a/security/integrity/evm/evm_crypto.c b/security/integrity/evm/evm_crypto.c
index 5dd5b140..847a2d7 100644
--- a/security/integrity/evm/evm_crypto.c
+++ b/security/integrity/evm/evm_crypto.c
@@ -26,34 +26,48 @@ static unsigned char evmkey[MAX_KEY_SIZE];
 static int evmkey_len = MAX_KEY_SIZE;
 
 struct crypto_shash *hmac_tfm;
+struct crypto_shash *hash_tfm;
 
-static struct shash_desc *init_desc(void)
+static struct shash_desc *init_desc(const char type)
 {
 	int rc;
+	char *algo;
+	struct crypto_shash **tfm;
 	struct shash_desc *desc;
 
-	if (hmac_tfm == NULL) {
-		hmac_tfm = crypto_alloc_shash(evm_hmac, 0, CRYPTO_ALG_ASYNC);
-		if (IS_ERR(hmac_tfm)) {
+	if (type == EVM_XATTR_HMAC) {
+		tfm = &hmac_tfm;
+		algo = evm_hmac;
+	} else {
+		tfm = &hash_tfm;
+		algo = evm_hash;
+	}
+
+	if (*tfm == NULL) {
+		*tfm = crypto_alloc_shash(algo, 0, CRYPTO_ALG_ASYNC);
+		if (IS_ERR(*tfm)) {
 			pr_err("Can not allocate %s (reason: %ld)\n",
-			       evm_hmac, PTR_ERR(hmac_tfm));
-			rc = PTR_ERR(hmac_tfm);
-			hmac_tfm = NULL;
+			       algo, PTR_ERR(*tfm));
+			rc = PTR_ERR(*tfm);
+			*tfm = NULL;
 			return ERR_PTR(rc);
 		}
 	}
 
-	desc = kmalloc(sizeof(*desc) + crypto_shash_descsize(hmac_tfm),
+	desc = kmalloc(sizeof(*desc) + crypto_shash_descsize(*tfm),
 			GFP_KERNEL);
 	if (!desc)
 		return ERR_PTR(-ENOMEM);
 
-	desc->tfm = hmac_tfm;
+	desc->tfm = *tfm;
 	desc->flags = CRYPTO_TFM_REQ_MAY_SLEEP;
 
-	rc = crypto_shash_setkey(hmac_tfm, evmkey, evmkey_len);
-	if (rc)
-		goto out;
+	if (type == EVM_XATTR_HMAC) {
+		rc = crypto_shash_setkey(*tfm, evmkey, evmkey_len);
+		if (rc)
+			goto out;
+	}
+
 	rc = crypto_shash_init(desc);
 out:
 	if (rc) {
@@ -97,9 +111,11 @@ static void hmac_add_misc(struct shash_desc *desc, struct inode *inode,
  * the hmac using the requested xattr value. Don't alloc/free memory for
  * each xattr, but attempt to re-use the previously allocated memory.
  */
-int evm_calc_hmac(struct dentry *dentry, const char *req_xattr_name,
-		  const char *req_xattr_value, size_t req_xattr_value_len,
-		  char *digest)
+static int evm_calc_hmac_or_hash(struct dentry *dentry,
+				const char *req_xattr_name,
+				const char *req_xattr_value,
+				size_t req_xattr_value_len,
+				char type, char *digest)
 {
 	struct inode *inode = dentry->d_inode;
 	struct shash_desc *desc;
@@ -111,7 +127,7 @@ int evm_calc_hmac(struct dentry *dentry, const char *req_xattr_name,
 
 	if (!inode->i_op || !inode->i_op->getxattr)
 		return -EOPNOTSUPP;
-	desc = init_desc();
+	desc = init_desc(type);
 	if (IS_ERR(desc))
 		return PTR_ERR(desc);
 
@@ -145,6 +161,22 @@ out:
 	return error;
 }
 
+int evm_calc_hmac(struct dentry *dentry, const char *req_xattr_name,
+		  const char *req_xattr_value, size_t req_xattr_value_len,
+		  char *digest)
+{
+	return evm_calc_hmac_or_hash(dentry, req_xattr_name, req_xattr_value,
+				req_xattr_value_len, EVM_XATTR_HMAC, digest);
+}
+
+int evm_calc_hash(struct dentry *dentry, const char *req_xattr_name,
+		  const char *req_xattr_value, size_t req_xattr_value_len,
+		  char *digest)
+{
+	return evm_calc_hmac_or_hash(dentry, req_xattr_name, req_xattr_value,
+				req_xattr_value_len, IMA_XATTR_DIGEST, digest);
+}
+
 /*
  * Calculate the hmac and update security.evm xattr
  *
@@ -175,7 +207,7 @@ int evm_init_hmac(struct inode *inode, const struct xattr *lsm_xattr,
 {
 	struct shash_desc *desc;
 
-	desc = init_desc();
+	desc = init_desc(EVM_XATTR_HMAC);
 	if (IS_ERR(desc)) {
 		printk(KERN_INFO "init_desc failed\n");
 		return PTR_ERR(desc);
diff --git a/security/integrity/evm/evm_main.c b/security/integrity/evm/evm_main.c
index 8b2eff9..d8ac109 100644
--- a/security/integrity/evm/evm_main.c
+++ b/security/integrity/evm/evm_main.c
@@ -18,6 +18,8 @@
 #include <linux/crypto.h>
 #include <linux/xattr.h>
 #include <linux/integrity.h>
+#include <linux/key-type.h>
+#include <linux/crypto/ksign.h>
 #include <linux/evm.h>
 #include <crypto/hash.h>
 #include "evm.h"
@@ -25,6 +27,7 @@
 int evm_initialized;
 
 char *evm_hmac = "hmac(sha1)";
+char *evm_hash = "sha1";
 
 char *evm_config_xattrnames[] = {
 #ifdef CONFIG_SECURITY_SELINUX
@@ -40,6 +43,8 @@ char *evm_config_xattrnames[] = {
 	NULL
 };
 
+static struct key *evm_keyring;
+
 static int evm_fixmode;
 static int __init evm_set_fixmode(char *str)
 {
@@ -49,6 +54,56 @@ static int __init evm_set_fixmode(char *str)
 }
 __setup("evm=", evm_set_fixmode);
 
+static int evm_find_protected_xattrs(struct dentry *dentry)
+{
+	struct inode *inode = dentry->d_inode;
+	char **xattr;
+	int error;
+	int count = 0;
+
+	if (!inode->i_op || !inode->i_op->getxattr)
+		return -EOPNOTSUPP;
+
+	for (xattr = evm_config_xattrnames; *xattr != NULL; xattr++) {
+		error = inode->i_op->getxattr(dentry, *xattr, NULL, 0);
+		if (error < 0) {
+			if (error == -ENODATA)
+				continue;
+			return error;
+		}
+		count++;
+	}
+
+	return count;
+}
+
+#ifdef CONFIG_EVM_DIGSIG
+
+int evm_sign_verify(const char *sig, int siglen,
+		       const char *digest, int digestlen)
+{
+	if (!evm_keyring) {
+		evm_keyring = request_key(&key_type_keyring, "_evm", NULL);
+		if (IS_ERR(evm_keyring)) {
+			pr_err("no evm keyring: %ld\n", PTR_ERR(evm_keyring));
+			evm_keyring = NULL;
+			return PTR_ERR(evm_keyring);
+		}
+	}
+
+	return ksign_verify(evm_keyring, sig, siglen, digest, digestlen);
+}
+
+#else
+
+static inline int evm_sign_verify(const char *sig, int siglen,
+		       const char *digest, int digestlen)
+{
+	return -EOPNOTSUPP;
+}
+
+#endif /* CONFIG_EVM_DIGSIG */
+
 /*
  * evm_verify_hmac - calculate and compare the HMAC with the EVM xattr
  *
@@ -68,32 +123,71 @@ static enum integrity_status evm_verify_hmac(struct dentry *dentry,
 					     size_t xattr_value_len,
 					     struct integrity_iint_cache *iint)
 {
-	struct evm_ima_xattr_data xattr_data;
+	struct evm_ima_xattr_data *xattr_data = NULL;
+	struct evm_ima_xattr_data calc;
 	enum integrity_status evm_status = INTEGRITY_PASS;
-	int rc;
+	int rc, xattr_len;
 
 	if (iint && iint->evm_status == INTEGRITY_PASS)
 		return iint->evm_status;
 
 	/* if status is not PASS, try to check again - against -ENOMEM */
 
-	rc = evm_calc_hmac(dentry, xattr_name, xattr_value,
-			   xattr_value_len, xattr_data.digest);
-	if (rc < 0) {
-		evm_status = (rc == -ENODATA)
-		    ? INTEGRITY_NOXATTRS : INTEGRITY_FAIL;
+	/* first need to know the sig type */
+	rc = vfs_getxattr_alloc(dentry, XATTR_NAME_EVM, (char **)&xattr_data, 0,
+				GFP_NOFS);
+	if (rc <= 0) {
+		if (rc == 0)
+			evm_status = INTEGRITY_FAIL; /* empty */
+		else if (rc == -ENODATA) {
+			rc = evm_find_protected_xattrs(dentry);
+			if (rc > 0)
+				evm_status = INTEGRITY_NOLABEL;
+			else if (rc == 0)
+				evm_status = INTEGRITY_NOXATTRS; /* new file */
+		}
 		goto out;
 	}
 
-	xattr_data.type = EVM_XATTR_HMAC;
-	rc = vfs_xattr_cmp(dentry, XATTR_NAME_EVM, (u8 *)&xattr_data,
-			   sizeof xattr_data, GFP_NOFS);
-	if (rc < 0)
-		evm_status = (rc == -ENODATA)
-		    ? INTEGRITY_NOLABEL : INTEGRITY_FAIL;
+	xattr_len = rc - 1;
+
+	/* check value type */
+	switch (xattr_data->type) {
+	case EVM_XATTR_HMAC:
+		rc = evm_calc_hmac(dentry, xattr_name, xattr_value,
+				   xattr_value_len, calc.digest);
+		if (rc)
+			break;
+		rc = memcmp(xattr_data->digest, calc.digest,
+			    sizeof(calc.digest));
+		if (rc)
+			rc = -EINVAL;
+		break;
+	case EVM_IMA_XATTR_DIGSIG:
+		rc = evm_calc_hash(dentry, xattr_name, xattr_value,
+				xattr_value_len, calc.digest);
+		if (rc)
+			break;
+		rc = evm_sign_verify(xattr_data->digest, xattr_len,
+				     calc.digest, sizeof(calc.digest));
+		if (!rc) {
+			/* we probably want to replace rsa with hmac here */
+			evm_update_evmxattr(dentry, xattr_name, xattr_value,
+				   xattr_value_len);
+		}
+		break;
+	default:
+		rc = -EINVAL;
+		break;
+	}
+
+	if (rc)
+		evm_status = (rc == -ENODATA) ?
+				INTEGRITY_NOXATTRS : INTEGRITY_FAIL;
 out:
 	if (iint)
 		iint->evm_status = evm_status;
+	kfree(xattr_data);
 	return evm_status;
 }
 
@@ -357,6 +451,8 @@ static int __init init_evm(void)
 		printk(KERN_INFO "EVM: Error registering secfs\n");
 		goto err;
 	}
+
+	return 0;
 err:
 	return error;
 }
@@ -364,8 +460,11 @@ err:
 static void __exit cleanup_evm(void)
 {
 	evm_cleanup_secfs();
+	key_put(evm_keyring);
 	if (hmac_tfm)
 		crypto_free_shash(hmac_tfm);
+	if (hash_tfm)
+		crypto_free_shash(hash_tfm);
 }
 
 /*
-- 
1.7.4.1


  parent reply	other threads:[~2011-09-13 14:20 UTC|newest]

Thread overview: 18+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2011-09-13 14:20 [RFC v2.1 0/6] evm: digital signature verification extension Dmitry Kasatkin
2011-09-13 14:20 ` [RFC v2.1 1/6] crypto: GnuPG based MPI lib - source files needed for ksign Dmitry Kasatkin
2011-09-13 14:20 ` [RFC v2.1 2/6] crypto: GnuPG based MPI lib - header " Dmitry Kasatkin
2011-09-13 14:20 ` [RFC v2.1 3/6] crypto: GnuPG based MPI lib - make " Dmitry Kasatkin
2011-09-13 14:20 ` [RFC v2.1 4/6] crypto: GnuPG based MPI lib - extra MPI sources Dmitry Kasatkin
2011-09-13 14:20 ` [RFC v2.1 5/6] crypto: ksign - digital signature verification support Dmitry Kasatkin
2011-09-13 14:20 ` Dmitry Kasatkin [this message]
2011-09-20 13:24 ` [RFC v2.1 0/6] evm: digital signature verification extension Mimi Zohar
2011-09-26  7:33   ` Kasatkin, Dmitry
2011-09-26 23:15     ` James Morris
2011-09-28 15:37       ` Kasatkin, Dmitry
2011-09-28 15:37         ` Kasatkin, Dmitry
2011-09-29  0:14         ` Herbert Xu
2011-09-29  0:14           ` Herbert Xu
2011-09-29  0:42           ` James Morris
2011-09-29 12:13             ` Kasatkin, Dmitry
2011-10-04 19:04             ` Herbert Xu
2011-10-04 19:04               ` Herbert Xu

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=7ff1998aaa5f303bf81ade4588fd607587df0c1a.1315921427.git.dmitry.kasatkin@intel.com \
    --to=dmitry.kasatkin@intel.com \
    --cc=dhowells@redhat.com \
    --cc=herbert@gondor.hengli.com.au \
    --cc=linux-crypto@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-security-module@vger.kernel.org \
    --cc=zohar@linux.vnet.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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.