Skip to contentSkip to conversation

evm: digital signature verification extension

RFC In review Dmitry Kasatkin 2 participants 7 messages Sep 6, 2011 – Sep 7, 2011

Subsystems (4)
lore
Share & tools
lore
#0 lore raw

cover evm: digital signature verification extension

Hello,

Updated before LSS.

Changes to version 1.1:
- GnuPG MPI library has been refactored with lindent and checkpatch errors and warnings has been fixed.
- creation of evm keyring has been remove. It is done now in user space.
- related ksign and evm patches has been squashed.
- patch descriptions has been updated.

As EVM patches were recently merged to security-testing-2.6#next, it is a good time to resend evm signature verification patches for active discussion. Last time I forgot --cc linux-crypto. Here it is.

This patchset introduces digital signature extensions for the IMA/EVM kernel integrity subsystem and is applied on the top of the EVM patches posted to LSM mailing list earlier.

Currently EVM stores the HMAC in security.evm to verify integrity of the file's metadata. This is quite sufficient for individually installed systems, where a system unique HMAC key can be provisioned and the initial filesystem labeling can be done.

Software installation for consumer electronics or embedded devices is usually done via flashing a filesystem image. Initial filesystem image labeling is done during image creation process. It either has to be done (1) using a system unique HMAC key or (2) using an image specific HMAC key. In first case, those keys are either unknown, or a unique image has to be created for thousand or millions of devices, which is not feasible. The second case, using an image specific HMAC key, would require (2.1) provisioning of the key to millions of devices, which is not easily feasible or (2.1) encrypting the key with a shared symmetric key which is not a strong security measure.

Digital signature extension for EVM provides a solution to perform labeling of the image using a single digital private key and use a known public key to verify the signature. For performance reasons, after verification, signature is replaced with local HMAC.

Digital signature verification uses RSA algorithm, implemented using cut-down port of multi-precision integers (MPI) library from GnuPG and has been taken from RedHat Enterprise Linux kernel (MODSIGN patches). Decision to use this library was made, because its performance was 2 times better than other ports such as libtommath library.

The motivation for integrity protection, in general, is to protect against offline modifications. The runtime protection is ensured via access control mechanisms. Of particular importance is protecting users or owners from being sold or given tampered devices, which can do nasty things such as spying or stealing personal data. Integrity protection ensures that modifications of the system will not remain undetected. The EVM digital signature extension makes this feasible for consumerelectronics/embedded devices.

There is also a second patchset which implements digital signature support for IMA-appraisal patchset, which is planned to be reviewed right after the IMA-appaisal review.

All patches on the top of ima-2.6 (3.x.x) kernel are available here:
git://git.kernel.org/pub/scm/linux/kernel/git/kasatkin/ima-ksign.git

Supporting utility for key handling and signing is available here:
http://meego.gitorious.org/meego-platform-security/evm-utils

Regards,
Dmitry

Dmitry Kasatkin (3):
crypto: GnuPG based MPI lib
crypto: ksign - digital signature verification support
evm: digital signature verification support

 crypto/Kconfig                      |   19 +
 crypto/Makefile                     |    4 +
 crypto/ksign.c                      |  269 +++++++
 crypto/mpi/Makefile                 |   30 +
 crypto/mpi/generic_mpi-asm-defs.h   |    4 +
 crypto/mpi/generic_mpih-add1.c      |   61 ++
 crypto/mpi/generic_mpih-lshift.c    |   63 ++
 crypto/mpi/generic_mpih-mul1.c      |   57 ++
 crypto/mpi/generic_mpih-mul2.c      |   60 ++
 crypto/mpi/generic_mpih-mul3.c      |   61 ++
 crypto/mpi/generic_mpih-rshift.c    |   63 ++
 crypto/mpi/generic_mpih-sub1.c      |   60 ++
 crypto/mpi/generic_udiv-w-sdiv.c    |  106 +++
 crypto/mpi/longlong.h               | 1478 +++++++++++++++++++++++++++++++++++
 crypto/mpi/mpi-add.c                |  234 ++++++
 crypto/mpi/mpi-bit.c                |  235 ++++++
 crypto/mpi/mpi-cmp.c                |   68 ++
 crypto/mpi/mpi-div.c                |  333 ++++++++
 crypto/mpi/mpi-gcd.c                |   59 ++
 crypto/mpi/mpi-inline.c             |   31 +
 crypto/mpi/mpi-inline.h             |  122 +++
 crypto/mpi/mpi-internal.h           |  260 ++++++
 crypto/mpi/mpi-inv.c                |  187 +++++
 crypto/mpi/mpi-mpow.c               |  133 ++++
 crypto/mpi/mpi-mul.c                |  194 +++++
 crypto/mpi/mpi-pow.c                |  322 ++++++++
 crypto/mpi/mpi-scan.c               |  136 ++++
 crypto/mpi/mpicoder.c               |  361 +++++++++
 crypto/mpi/mpih-cmp.c               |   56 ++
 crypto/mpi/mpih-div.c               |  541 +++++++++++++
 crypto/mpi/mpih-mul.c               |  527 +++++++++++++
 crypto/mpi/mpiutil.c                |  206 +++++
 include/linux/crypto/ksign.h        |   67 ++
 include/linux/crypto/mpi.h          |  146 ++++
 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 +++-
 38 files changed, 6741 insertions(+), 30 deletions(-)
 create mode 100644 crypto/ksign.c
 create mode 100644 crypto/mpi/Makefile
 create mode 100644 crypto/mpi/generic_mpi-asm-defs.h
 create mode 100644 crypto/mpi/generic_mpih-add1.c
 create mode 100644 crypto/mpi/generic_mpih-lshift.c
 create mode 100644 crypto/mpi/generic_mpih-mul1.c
 create mode 100644 crypto/mpi/generic_mpih-mul2.c
 create mode 100644 crypto/mpi/generic_mpih-mul3.c
 create mode 100644 crypto/mpi/generic_mpih-rshift.c
 create mode 100644 crypto/mpi/generic_mpih-sub1.c
 create mode 100644 crypto/mpi/generic_udiv-w-sdiv.c
 create mode 100644 crypto/mpi/longlong.h
 create mode 100644 crypto/mpi/mpi-add.c
 create mode 100644 crypto/mpi/mpi-bit.c
 create mode 100644 crypto/mpi/mpi-cmp.c
 create mode 100644 crypto/mpi/mpi-div.c
 create mode 100644 crypto/mpi/mpi-gcd.c
 create mode 100644 crypto/mpi/mpi-inline.c
 create mode 100644 crypto/mpi/mpi-inline.h
 create mode 100644 crypto/mpi/mpi-internal.h
 create mode 100644 crypto/mpi/mpi-inv.c
 create mode 100644 crypto/mpi/mpi-mpow.c
 create mode 100644 crypto/mpi/mpi-mul.c
 create mode 100644 crypto/mpi/mpi-pow.c
 create mode 100644 crypto/mpi/mpi-scan.c
 create mode 100644 crypto/mpi/mpicoder.c
 create mode 100644 crypto/mpi/mpih-cmp.c
 create mode 100644 crypto/mpi/mpih-div.c
 create mode 100644 crypto/mpi/mpih-mul.c
 create mode 100644 crypto/mpi/mpiutil.c
 create mode 100644 include/linux/crypto/ksign.h
 create mode 100644 include/linux/crypto/mpi.h
Signature · 1 line
1.7.4.1
#2 lore raw

RFC 2/3 crypto: ksign - digital signature verification support

This patch implements RSA digital signature verification using GnuPG library.

Signature and public key have a special format and have special headers. Signature header contains keyid, which is used to identify the key, needed for signature verification.
Payload of the signature and the key are multi-precision integers.

Signing and key management utility "evmctl" is available on
http://meego.gitorious.org/meego-platform-security/evm-utils

Key is added to the kernel keyring with the name equal to a keyid. evm-utils provide support to load PEM key into the keyring, to convert PEM key to the kernel format and to load it into the keyring.

---
 crypto/Kconfig               |   13 ++
 crypto/Makefile              |    3 +
 crypto/ksign.c               |  269 ++++++++++++++++++++++++++++++++++++++++++
 include/linux/crypto/ksign.h |   67 +++++++++++
 4 files changed, 352 insertions(+), 0 deletions(-)
 create mode 100644 crypto/ksign.c
 create mode 100644 include/linux/crypto/ksign.h
crypto/Kconfig +13 -0
index 4b1b9a4..a604b23 100644
@@ -863,6 +863,19 @@ config CRYPTO_MPILIB
 	help
 	  Multiprecision maths library from GnuPG
 
+config CRYPTO_KSIGN
+	bool "In-kernel signature checker (EXPERIMENTAL)"
+	depends on CRYPTO
+	help
+	  Signature checker (used for module sig checking).
+
+config CRYPTO_KSIGN_RSA
+	bool "Handle RSA signatures (EXPERIMENTAL)"
+	select CRYPTO_KSIGN
+	select CRYPTO_MPILIB
+	help
+	  RSA Signature checker.
+
 source "drivers/crypto/Kconfig"
 
 endif	# if CRYPTO
crypto/Makefile +3 -0
index 604006d..4ef05e8 100644
@@ -90,6 +90,9 @@ obj-$(CONFIG_CRYPTO_USER_API_HASH) += algif_hash.o
 obj-$(CONFIG_CRYPTO_USER_API_SKCIPHER) += algif_skcipher.o
 obj-$(CONFIG_CRYPTO_MPILIB) += mpi/
 
+obj-$(CONFIG_CRYPTO_KSIGN) += ksignmod.o
+ksignmod-objs := ksign.o
+
 #
 # generic algorithms and the async_tx api
 #
crypto/ksign.c new file +269 -0

269 lines not on this page · raw message

include/linux/crypto/ksign.h new file +67 -0

67 lines not on this page · raw message

Signature · 1 line
1.7.4.1
#3 lore raw

RFC 3/3 evm: digital signature verification support

In reply to Dmitry Kasatkin

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.

---
 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(-)
security/integrity/evm/Kconfig +15 -0
index 884617d..4397bb6 100644
@@ -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.
security/integrity/evm/evm.h +12 -0
index d320f51..c885247 100644
@@ -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
security/integrity/evm/evm_crypto.c +49 -17

112 lines not on this page · raw message

security/integrity/evm/evm_main.c +112 -13

182 lines not on this page · raw message

Signature · 1 line
1.7.4.1
#1 lore raw

RFC 1/3 crypto: GnuPG based MPI lib

In reply to Dmitry Kasatkin

Adds the multi-precision-integer maths library which was originally taken from GnuPG and ported to the kernel by (among others) David Howells. This version is taken from Fedora kernel 2.6.32-71.14.1.el6.
The difference is that checkpatch reported errors and warning has been fixed.

This library is used to implemenet RSA digital signature verification used in IMA/EVM integrity protection subsystem.

---
 crypto/Kconfig                    |    6 +
 crypto/Makefile                   |    1 +
 crypto/mpi/Makefile               |   30 +
 crypto/mpi/generic_mpi-asm-defs.h |    4 +
 crypto/mpi/generic_mpih-add1.c    |   61 ++
 crypto/mpi/generic_mpih-lshift.c  |   63 ++
 crypto/mpi/generic_mpih-mul1.c    |   57 ++
 crypto/mpi/generic_mpih-mul2.c    |   60 ++
 crypto/mpi/generic_mpih-mul3.c    |   61 ++
 crypto/mpi/generic_mpih-rshift.c  |   63 ++
 crypto/mpi/generic_mpih-sub1.c    |   60 ++
 crypto/mpi/generic_udiv-w-sdiv.c  |  106 +++
 crypto/mpi/longlong.h             | 1478 +++++++++++++++++++++++++++++++++++++
 crypto/mpi/mpi-add.c              |  234 ++++++
 crypto/mpi/mpi-bit.c              |  235 ++++++
 crypto/mpi/mpi-cmp.c              |   68 ++
 crypto/mpi/mpi-div.c              |  333 +++++++++
 crypto/mpi/mpi-gcd.c              |   59 ++
 crypto/mpi/mpi-inline.c           |   31 +
 crypto/mpi/mpi-inline.h           |  122 +++
 crypto/mpi/mpi-internal.h         |  260 +++++++
 crypto/mpi/mpi-inv.c              |  187 +++++
 crypto/mpi/mpi-mpow.c             |  133 ++++
 crypto/mpi/mpi-mul.c              |  194 +++++
 crypto/mpi/mpi-pow.c              |  322 ++++++++
 crypto/mpi/mpi-scan.c             |  136 ++++
 crypto/mpi/mpicoder.c             |  361 +++++++++
 crypto/mpi/mpih-cmp.c             |   56 ++
 crypto/mpi/mpih-div.c             |  541 ++++++++++++++
 crypto/mpi/mpih-mul.c             |  527 +++++++++++++
 crypto/mpi/mpiutil.c              |  206 +++++
 include/linux/crypto/mpi.h        |  146 ++++
 32 files changed, 6201 insertions(+), 0 deletions(-)
 create mode 100644 crypto/mpi/Makefile
 create mode 100644 crypto/mpi/generic_mpi-asm-defs.h
 create mode 100644 crypto/mpi/generic_mpih-add1.c
 create mode 100644 crypto/mpi/generic_mpih-lshift.c
 create mode 100644 crypto/mpi/generic_mpih-mul1.c
 create mode 100644 crypto/mpi/generic_mpih-mul2.c
 create mode 100644 crypto/mpi/generic_mpih-mul3.c
 create mode 100644 crypto/mpi/generic_mpih-rshift.c
 create mode 100644 crypto/mpi/generic_mpih-sub1.c
 create mode 100644 crypto/mpi/generic_udiv-w-sdiv.c
 create mode 100644 crypto/mpi/longlong.h
 create mode 100644 crypto/mpi/mpi-add.c
 create mode 100644 crypto/mpi/mpi-bit.c
 create mode 100644 crypto/mpi/mpi-cmp.c
 create mode 100644 crypto/mpi/mpi-div.c
 create mode 100644 crypto/mpi/mpi-gcd.c
 create mode 100644 crypto/mpi/mpi-inline.c
 create mode 100644 crypto/mpi/mpi-inline.h
 create mode 100644 crypto/mpi/mpi-internal.h
 create mode 100644 crypto/mpi/mpi-inv.c
 create mode 100644 crypto/mpi/mpi-mpow.c
 create mode 100644 crypto/mpi/mpi-mul.c
 create mode 100644 crypto/mpi/mpi-pow.c
 create mode 100644 crypto/mpi/mpi-scan.c
 create mode 100644 crypto/mpi/mpicoder.c
 create mode 100644 crypto/mpi/mpih-cmp.c
 create mode 100644 crypto/mpi/mpih-div.c
 create mode 100644 crypto/mpi/mpih-mul.c
 create mode 100644 crypto/mpi/mpiutil.c
 create mode 100644 include/linux/crypto/mpi.h
crypto/Kconfig +6 -0
index ae27b753..4b1b9a4 100644
@@ -857,6 +857,12 @@ config CRYPTO_USER_API_SKCIPHER
 	  This option enables the user-spaces interface for symmetric
 	  key cipher algorithms.
 
+config CRYPTO_MPILIB
+	bool "Multiprecision maths library (EXPERIMENTAL)"
+	depends on CRYPTO
+	help
+	  Multiprecision maths library from GnuPG
+
 source "drivers/crypto/Kconfig"
 
 endif	# if CRYPTO
crypto/Makefile +1 -0
index ce5a813..604006d 100644
@@ -88,6 +88,7 @@ obj-$(CONFIG_CRYPTO_GHASH) += ghash-generic.o
 obj-$(CONFIG_CRYPTO_USER_API) += af_alg.o
 obj-$(CONFIG_CRYPTO_USER_API_HASH) += algif_hash.o
 obj-$(CONFIG_CRYPTO_USER_API_SKCIPHER) += algif_skcipher.o
+obj-$(CONFIG_CRYPTO_MPILIB) += mpi/
 
 #
 # generic algorithms and the async_tx api
crypto/mpi/Makefile new file +30 -0
new file mode 100644
index 0000000..d000949
@@ -0,0 +1,30 @@
+#
+# MPI multiprecision maths library (from gpg)
+#
+
+obj-$(CONFIG_CRYPTO_MPILIB) = \
+	generic_mpih-lshift.o		\
+	generic_mpih-mul1.o		\
+	generic_mpih-mul2.o		\
+	generic_mpih-mul3.o		\
+	generic_mpih-rshift.o		\
+	generic_mpih-sub1.o		\
+	generic_mpih-add1.o		\
+	generic_udiv-w-sdiv.o		\
+	mpicoder.o			\
+	mpi-add.o			\
+	mpi-bit.o			\
+	mpi-div.o			\
+	mpi-cmp.o			\
+	mpi-gcd.o			\
+	mpih-cmp.o			\
+	mpih-div.o			\
+	mpih-mul.o			\
+	mpi-inline.o			\
+	mpi-inv.o			\
+	mpi-mpow.o			\
+	mpi-mul.o			\
+	mpi-pow.o			\
+	mpi-scan.o			\
+	mpiutil.o
+
crypto/mpi/generic_mpi-asm-defs.h new file +4 -0
new file mode 100644
index 0000000..047d1f5
@@ -0,0 +1,4 @@
+/* This file defines some basic constants for the MPI machinery.  We
+ * need to define the types on a per-CPU basis, so it is done with
+ * this file here.  */
+#define BYTES_PER_MPI_LIMB  (SIZEOF_UNSIGNED_LONG)
crypto/mpi/generic_mpih-add1.c new file +61 -0

61 lines not on this page · raw message

crypto/mpi/generic_mpih-lshift.c new file +63 -0

63 lines not on this page · raw message

crypto/mpi/generic_mpih-mul1.c new file +57 -0

57 lines not on this page · raw message

crypto/mpi/generic_mpih-mul2.c new file +60 -0

60 lines not on this page · raw message

crypto/mpi/generic_mpih-mul3.c new file +61 -0

61 lines not on this page · raw message

crypto/mpi/generic_mpih-rshift.c new file +63 -0

63 lines not on this page · raw message

crypto/mpi/generic_mpih-sub1.c new file +60 -0

60 lines not on this page · raw message

crypto/mpi/generic_udiv-w-sdiv.c new file +106 -0

106 lines not on this page · raw message

crypto/mpi/longlong.h new file +1478 -0

1,478 lines not on this page · raw message

crypto/mpi/mpi-add.c new file +234 -0

234 lines not on this page · raw message

crypto/mpi/mpi-bit.c new file +235 -0

235 lines not on this page · raw message

crypto/mpi/mpi-cmp.c new file +68 -0

68 lines not on this page · raw message

crypto/mpi/mpi-div.c new file +333 -0

333 lines not on this page · raw message

crypto/mpi/mpi-gcd.c new file +59 -0

59 lines not on this page · raw message

crypto/mpi/mpi-inline.c new file +31 -0
new file mode 100644
index 0000000..654f68a
@@ -0,0 +1,31 @@
+/* mpi-inline.c
+ * Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
[… more lines in the raw message]

Lines of this file are not shown. View the raw message.

crypto/mpi/mpi-inline.h new file +122 -0

122 lines not on this page · raw message

crypto/mpi/mpi-internal.h new file +260 -0

260 lines not on this page · raw message

crypto/mpi/mpi-inv.c new file +187 -0

187 lines not on this page · raw message

crypto/mpi/mpi-mpow.c new file +133 -0

133 lines not on this page · raw message

crypto/mpi/mpi-mul.c new file +194 -0

194 lines not on this page · raw message

crypto/mpi/mpi-pow.c new file +322 -0

322 lines not on this page · raw message

crypto/mpi/mpi-scan.c new file +136 -0

136 lines not on this page · raw message

crypto/mpi/mpicoder.c new file +361 -0

361 lines not on this page · raw message

crypto/mpi/mpih-cmp.c new file +56 -0

56 lines not on this page · raw message

crypto/mpi/mpih-div.c new file +541 -0

541 lines not on this page · raw message

crypto/mpi/mpih-mul.c new file +527 -0

527 lines not on this page · raw message

crypto/mpi/mpiutil.c new file +206 -0

206 lines not on this page · raw message

include/linux/crypto/mpi.h new file +146 -0

146 lines not on this page · raw message

The rest of this diff is not shown. View the raw message.

Signature · 1 line
1.7.4.1

Part of the diff is not shown here. View the raw message.

#4 lore raw

RFC 3/3 evm: digital signature support

In reply to Dmitry Kasatkin

When building an image, which has to be flashed to different devices, an HMAC cannot be used to sign file metadata, as the HMAC key is different on every device. File metadata can be protected using digital signature. This patch enables RSA signature based integrity verification.

---
 security/integrity/evm/Kconfig      |   14 ++++
 security/integrity/evm/evm.h        |   12 ++++
 security/integrity/evm/evm_crypto.c |   66 ++++++++++++++-----
 security/integrity/evm/evm_main.c   |  125 +++++++++++++++++++++++++++++++----
 4 files changed, 187 insertions(+), 30 deletions(-)
security/integrity/evm/Kconfig +14 -0
index 884617d..84eea75 100644
@@ -12,3 +12,17 @@ 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
+	  When building an image, which has to be flashed to different
+	  devices, an HMAC cannot be used to sign file metadata, as
+	  the HMAC key is different on every device.
+	  File metadata can be protected using digital signature.
+	  This option enables RSA signature based integrity verification.
+
+	  If unsure, say N.
security/integrity/evm/evm.h +12 -0
index d320f51..c885247 100644
@@ -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
security/integrity/evm/evm_crypto.c +49 -17

112 lines not on this page · raw message

security/integrity/evm/evm_main.c +112 -13

182 lines not on this page · raw message

Signature · 1 line
1.7.4.1
#5 lore raw

Re: [RFC v2.0 3/3] evm: digital signature support

Please ignore this patch. It was sent by mistake... Check:
evm: digital signature verification support

- Dmitry

Quoted 393 lines · Dmitry Kasatkin

When building an image, which has to be flashed to different devices, an HMAC cannot be used to sign file metadata, as the HMAC key is different on every device. File metadata can be protected using digital signature. This patch enables RSA signature based integrity verification.

---
 security/integrity/evm/Kconfig      |   14 ++++ security/integrity/evm/evm.h        |   12 ++++ security/integrity/evm/evm_crypto.c |   66 ++++++++++++++----- security/integrity/evm/evm_main.c   |  125 +++++++++++++++++++++++++++++++----

 4 files changed, 187 insertions(+), 30 deletions(-)
security/integrity/evm/Kconfig +0 -0
index 884617d..84eea75 100644
@@ -12,3 +12,17 @@ config EVM

         integrity attacks.

         If you are unsure how to answer this question, answer N.

security/integrity/evm/Kconfig +14 -0
+
+config EVM_DIGSIG
+       boolean "EVM Digital Signature support"
+       depends on EVM
+       default n
+       select CRYPTO_KSIGN_RSA
+       help
+         When building an image, which has to be flashed to different
+         devices, an HMAC cannot be used to sign file metadata, as
+         the HMAC key is different on every device.
+         File metadata can be protected using digital signature.
+         This option enables RSA signature based integrity verification.
+
+         If unsure, say N.
security/integrity/evm/evm.h +12 -0
index d320f51..c885247 100644
@@ -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
security/integrity/evm/evm_crypto.c +26 -12
index 5dd5b140..847a2d7 100644
@@ -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) {

security/integrity/evm/evm_crypto.c +23 -5
@@ -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);
security/integrity/evm/evm_main.c +3 -0
index 8b2eff9..d8ac109 100644
@@ -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
 };

security/integrity/evm/evm_main.c +2 -0
+static struct key *evm_keyring;
+

 static int evm_fixmode;
 static int __init evm_set_fixmode(char *str)
 {

security/integrity/evm/evm_main.c +101 -13
@@ -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;
 }

security/integrity/evm/evm_main.c +2 -0
@@ -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;
 }

security/integrity/evm/evm_main.c +3 -1
@@ -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