Using Extended Verification Module in Gentoo
1.
Purpose of EVM
Introduction
Warning:
Using EVM on your system is currently only recommended for development purposes.
|
The Linux kernel offers a security interface that allows new technologies to
properly "hook in" the Linux kernel and extend its capabilities with more
security-related features. This interface is called LSM (Linux Security Modules)
and is used by technologies such as SELinux, SMACK and IMA as well as many
others.
Many of these security technologies use extended attributes for storing
information about the state of resources on the system. SELinux for instance
uses the security.selinux extended attribute to store the SELinux
security context of a file, directory or other resource. The Linux Integrity
Measurement Architecture uses the security.ima extended attribute
to store a valid hash of the file in order to detect and prevent offline
tampering of files.
But if all this information is stored in extended attributes, then offline
tampering of files (and guest images) allows an attacker to circumvent security
rules: he can change the label of a file he wants access to when the guest is
operational (/etc/shadow is an obvious example to this, say making
it etc_t). Once done, and the guest boots, none of the technologies in
place will detect that the extended attribute has been tampered with: SELinux
reads the context and treats the file as a regular /etc file. And
IMA doesn't prevent this either since the file itself has not been tampered
with.
Enter EVM, the Extended Verification Module. With EVM, the security
sensitive extended attributes are verified against offline tampering. To
accomplish this, EVM creates a cryptographic hash (actually an HMAC) or a
signature of the extended attributes made with a key loaded at boot time.
This hash/signature is validated every time the extended attributes of a
resource are consulted and the action is only allowed if the hash or
signature checks out. A malicious person will need access to this key in
order to tamper with the extended attributes (and if IMA is enabled, to
tamper with the files). Although the key needs to be loaded at boot time,
a couple of mechanisms exist to seal it away:
-
Use TPM to seal the key; this creates what is called a trusted key as
it cannot be found (unencrypted) on the file system at any time
-
Use encryption with offloaded passphrase protection for the keys, and ask
for the passphrase early at boot time. With this we can use regular
user keys (the terminology will be used later).
Of course, using entire file system encryption thwarts the need for EVM and IMA,
but yields additional overhead that not all users can endure. And this is where
EVM and IMA can be used.
Hash or signature?
EVM supports both a hash-based message authentication code or a signature,
similar to IMA (which uses a checksum or a signature). The hash is a
cryptographic hash based on an encryption key loaded in at boot time and only
usable by the EVM subsystem (when using a trusted key) or by root-owned
processes with the proper privileges (in which case you can use SELinux to
properly restrict access further).
The signature, as with IMA, allows the administrator to digitally sign security
extended attributes that are not meant to be changed often (immutable
attributes). The public key that is used to verify the signatures is loaded on
the _evm keyring while the private key can remain offline.
The Big Fat Warnings
Using EVM on your system is currently only recommended for development purposes.
Gentoo Hardened is working on integrating EVM properly, so please be aware
that the system might have issues booting if not all files have their hash
registered properly; you are easily warned if this is the case through the
Linux audit subsystem.
We are working on proper guidelines for enabling and working with EVM.
2.
Setting up EVM
Kernel configuration
First of all, enable the EVM subsystem in the Linux kernel configuration. Also
enable support for the kernel keyring with trusted (if using TPM) and encrypted
keys.
Code Listing 2.1: Linux kernel configuration for EVM |
CONFIG_KEYS=y
CONFIG_TRUSTED_KEYS=y
CONFIG_ENCRYPTED_KEYS=y
CONFIG_INTEGRITY=y
CONFIG_INTEGRITY_SIGNATURE=y
CONFIG_EVM=y
CONFIG_TCG_TPM=y
|
Bootloader configuration
Next, configure the bootloader to enable EVM:
Code Listing 2.2: Bootloader configuration to enable EVM policy |
kernel /boot/vmlinuz root=/dev/vda1 ... evm=fix
|
We currently set evm=fix because the extended attributes have not been
checked by EVM yet. We will be signing these later, after which the boot parameter can
be removed.
Reboot with your freshly built kernel.
Enable security file system
Finally, have the security file system mounted (if this is not already the
case):
Code Listing 2.3: Mounting the security file system |
~# mount | grep securityfs
securityfs on /sys/kernel/security type securityfs (rw,nosuid,nodev,noexec,relatime)
|
Setting up the keys (for cryptographic hashing)
We will now be creating the key for EVM. Since the key will be used often, it
has to be a "fast" key to use. As such, we will use a standard user-encrypted
key for this. To properly protect the key, a master key will be created first
from which the EVM key can then be generated. The security of this master key
is important, so if you have a TPM chip that you control, it is wise to use a
trusted key for the master key. The EVM key remains a user key but
is generated (and validated) by the master key.
We will store the blobs (binary dumps of the encrypted keys) in
/etc/keys:
Code Listing 2.4: Generating a trusted master key with user EVM key |
~# keyctl add trusted kmk-trusted "new 32" @u
~# keyctl pipe `keyctl search @u trusted kmk-trusted` > /etc/keys/kmk-trusted.blob
~# keyctl add encrypted evm-key "new trusted:kmk-trusted 32" @u
~# keyctl pipe `keyctl search @u encrypted evm-key` > /etc/keys/evm-trusted.blob
|
Code Listing 2.5: Generating a user master key with user EVM key |
~# keyctl add user kmk-user "`dd if=/dev/urandom bs=1 count=32 2>/dev/null`" @u
~# keyctl pipe `keyctl search @u user kmk-user` > /etc/keys/kmk-user.blob
~# keyctl add encrypted evm-key "new user:kmk-user 32" @u
~# keyctl pipe `keyctl search @u encrypted evm-key` > /etc/keys/evm-user.blob
|
These four commands execute the following tasks:
-
Create a master key named kmk-trusted or mkm-user.
If we asked for a trusted key, then the key is generated by the TPM and
sealed by the TPM (meaning it is encrypted by the TPM itself and can only be
decrypted by the TPM). The key is made 256 bits long (32 bytes) and added to
the user keyring (@u).
-
Look for the key we generated in the first step, and output the key value
into a file. The output is an encrypted value in case of a trusted key, or
the key itself in case of the user key.
-
Next, we generate a user key through the master key. In other words, the
master key is used to encrypt (seal) the user key. The generated user key is
called evm-key.
-
Finally, we search for the key generated in the third step, and output the
value into a file. The output is an encrypted value of the key (encrypted
through the master key).
It is important that the key for EVM is called evm-key as this is the key
searched for by the EVM subsystem on the root's keyring (i.e. the user keyring
for the root Linux user).
Make sure that the keys are loaded at boot time. This can be done through an
initramfs, or through a service script early at boot. The following init script
shows you what needs to be done to load the keys.
Code Listing 2.6: The security_keys init script |
#!/sbin/runscript
# Copyright 1999-2012 Gentoo Foundation
# Distributed under the terms of the GNU General Public License v2
# $Header: /var/cvsroot/gentoo/xml/htdocs/proj/en/hardened/integrity/docs/evm-guide.xml,v 1.4 2013/03/09 13:55:21 swift Exp $
description="Load in the EVM and IMA keys"
start() {
ebegin "Remounting /usr with iversion"
mount -o remount,iversion /usr
eend $?
ebegin "Loading EVM keys"
# Load the master key (this is for a non-TPM system)
keyctl show | grep -q kmk-user || keyctl add user kmk-user "`cat /etc/keys/kmk-user.blob`" @u > /dev/null
keyctl add encrypted evm-key "load `cat /etc/keys/evm-user.blob`" @u > /dev/null
eend $?
ebegin "Loading pubkeys"
ima_id=`keyctl newring _ima @u` && /usr/bin/evmctl import /etc/keys/rsa_public.pem $ima_id > /dev/null
evm_id=`keyctl newring _evm @u` && /usr/bin/evmctl import /etC/keys/rsa_public.pem $evm_id > /dev/null
eend $?
ebegin "Enabling EVM"
echo 1 > /sys/kernel/security/evm
eend $?
}
|
Generating EVM hashes
Now we need to generate the EVM cryptographic hashes. Enable EVM
first by echo'ing 1 into /sys/kernel/security/evm after the keys
are loaded, and then have IMA regenerate all its security.ima
attributes (which as a result will have EVM generate its own cryptographic
hashes).
Boot with ima_appraise=fix evm=fix and run something similar as the
following find command.
Code Listing 2.7: Regenerating IMA and EVM attributes |
# find / \( -fstype rootfs -o -fstype ext4 \) -type f -uid 0 -exec head -c 1 '{}' \;
|
Setting up the keys (for digital signatures)
To use digital signatures, first create a keypair (public and private) to use.
Code Listing 2.8: Generating a public/private key pair |
~# openssl genrsa -out rsa_private.pem 1024
~# openssl genrsa -des3 -out rsa_private.pem 1024
~# openssl rsa -pubout -in rsa_private.pem -out rsa_public.pem
|
Next, we load the public key on the EVM keyring:
Code Listing 2.9: Loading the public key on the EVM keyring |
~# evm_id=`keyctl newring _evm @u`
~# evmctl import /etc/keys/rsa_public.pem $evm_id
|
Now the EVM sub system is able to validate digital signatures. So let's create a
few of those shall we?
Generating EVM signatures
Now we need to generate the EVM digital signatures. We use the evmctl
command provided by ima-evm-utils for this. For instance, to generate
the digital signatures for all binaries in /sbin:
Code Listing 2.10: Generate digital signatures for all sbin binaries |
~# find /sbin -type f -exec evmctl sign --imahash '{}' /etc/keys/rsa_private.pem
|
If the IMA keys are loaded as well, you can have both digital signatures for EVM
as well as for IMA:
Code Listing 2.11: Generate digital signatures (evm and ima) for all sbin binaries |
~# find /sbin -type f -exec evmctl sign --imasig '{}' /etc/keys/rsa_private.pem
|
3.
Using the EVM subsystem
Enable EVM
EVM is by default not enabled until you tell it to start. This is because you
need to load in the EVM keys in the keyring so that EVM can start validating the
signatures. Once that is done, you can start EVM by echo'ing 1 into
/sys/kernel/security/evm
Code Listing 3.1: Enabling EVM |
echo 1 > /sys/kernel/security/evm
|
4.
Asked Questions with Answers
I ran with evm=fix but when I enabled EVM, it still blocked file accesses
If you use evm=fix you also need ima_appraise=fix. This is because
the IMA appraisal code checks the EVM attribute as well and, if the check fails,
the IMA appraisal code will refuse access.
Can I use EVM without IMA to protect SELinux attributes?
Although you can enable EVM to create hashes on the SELinux attributes, you need
the IMA appraisal to be enabled in order for the protection to work. EVM by
itself does not enforce the hashes and would only register changes if you do not
use IMA with the appraisal feature enabled.
The contents of this document, unless otherwise expressly stated, are
licensed under the CC-BY-SA-3.0 license. The Gentoo Name and Logo Usage Guidelines apply.
|