EVMCTL(1)

🌸 NAME 🌸

okay so meet evmctl(1) β€” the IMA/EVM signing utility. Bestie, this is the little tool with main character energy for the Linux kernel integrity subsystem, and we’re gonna get into all of it πŸ’…βœ¨

πŸ¦‹ SYNOPSIS πŸ¦‹

evmctl [options] <command> [OPTIONS]

πŸ’– DESCRIPTION πŸ’–

The evmctl utility can be used for producing and verifying digital signatures, which are used by the Linux kernel integrity subsystem (IMA/EVM). It can also be used to import keys into the kernel keyring. No cap, that’s the whole vibe check 🫢

πŸŽ€ COMMANDS πŸŽ€

Here’s the command menu, and yes, every single one is here β€” no crumbs:

--version
help <command>
import  [--rsa (deprecated)] pubkey keyring
sign [-r] [--imahash | --imasig ] [--key key] [--pass[=<password>] file
verify file
ima_sign [--sigfile] [--key key] [--pass[=<password>]] file
ima_verify file
ima_setxattr [--sigfile file]
ima_hash file
ima_measurement [--ignore-violations] [--verify-sig [--key "key1, key2, ..."]]
  [--pcrs [hash-algorithm,]file [--pcrs hash-algorithm,file] ...]
  [--verify-bank hash-algorithm] file
ima_boot_aggregate [--pcrs hash-algorithm,file] [TPM 1.2 BIOS event log]
  [--hwtpm]
ima_fix [-t fdsxm] path
ima_clear [-t fdsxm] path
sign_hash [--veritysig] [--key key] [--pass=<password>]
hmac [--imahash | --imasig] [--hmackey key] file

✨ OPTIONS ✨

  • -a, --hashalgo β€” sha1, sha224, sha256, sha384, sha512, streebog256, streebog512 (default: sha256)
  • -s, --imasig β€” make IMA signature
  • --veritysig β€” sign an fs-verity file digest hash
  • -d, --imahash β€” make IMA hash
  • -f, --sigfile β€” store IMA signature in .sig file instead of xattr
  • --xattr-user β€” store xattrs in user namespace (for testing purposes)
  • --rsa β€” use RSA key type and signing scheme v1 (deprecated)
  • -k, --key β€” path to signing key (default: /etc/keys/{privkey,pubkey}_evm.pem) or a pkcs11 URI
  • --keyid n β€” overwrite signature keyid with a 32-bit value in hex (for signing)
  • --keyid-from-cert file β€” read keyid value from SKID of a x509 cert file
  • -o, --portable β€” generate portable EVM signatures
  • -p, --pass β€” password for encrypted signing key; use -p<password>
  • -r, --recursive β€” recurse into directories (sign)
  • -t, --type β€” file types to fix 'fxm' (f: file)
    • x β€” skip fixing if both ima and evm xattrs exist (use with caution)
    • m β€” stay on the same filesystem (like 'find -xdev')
  • -n β€” print result to stdout instead of setting xattr
  • -u, --uuid β€” use custom FS UUID for EVM (unspecified: from FS, empty: do not use)
  • --smack β€” use extra SMACK xattrs for EVM
  • --m32 β€” force EVM hmac/signature for 32 bit target system
  • --m64 β€” force EVM hmac/signature for 64 bit target system
  • --ino β€” use custom inode for EVM
  • --uid β€” use custom UID for EVM
  • --gid β€” use custom GID for EVM
  • --mode β€” use custom Mode for EVM
  • --generation β€” use custom Generation for EVM(unspecified: from FS, empty: use 0)
  • --ima β€” use custom IMA signature for EVM
  • --selinux β€” use custom Selinux label for EVM
  • --caps β€” use custom Capabilities for EVM(unspecified: from FS, empty: do not use)
  • --pcrs β€” file containing TPM pcrs, one per hash-algorithm/bank
  • --verify-sig β€” verify the file signature based on the file hash, both stored in the template data.
  • --engine e β€” preload OpenSSL engine e (such as: gost) is deprecated
  • --provider p β€” preload OpenSSL provider (such as: pkcs11)
  • --ignore-violations β€” ignore ToMToU measurement violations
  • --hmackey β€” path to symmetric key (default: /etc/keys/evm-key-plain)
  • -v β€” increase verbosity level
  • -h, --help β€” display this help and exit

🌱 Environment variables 🌱

  • EVMCTL_KEY_PASSWORD : Private key password to use; do not use --pass option

πŸ’œ INTRODUCTION πŸ’œ

Linux kernel integrity subsystem is comprised of a number of different components including the Integrity Measurement Architecture (IMA), Extended Verification Module (EVM), IMA-appraisal extension, digital signature verification extension and audit measurement log support. It’s giving very β€œwhole ecosystem” energy, fr fr.

The evmctl utility is used for producing and verifying digital signatures, which are used by the Linux kernel integrity subsystem. It is also used for importing keys into the kernel keyring.

Linux integrity subsystem allows to use IMA and EVM signatures. EVM signature protects file metadata, such as file attributes and extended attributes. IMA signature protects file content. So EVM is lowkey guarding the metadata fit, and IMA is guarding the content fit πŸ’…

For more detailed information about integrity subsystem it is recommended to follow resources in RESOURCES section. That’s your homework, bestie β€” iykyk.

πŸ¦‹ EVM HMAC AND SIGNATURE METADATA πŸ¦‹

EVM protects file metadata by including following attributes into HMAC and signature calculation: inode number, inode generation, UID, GID, file mode, security.selinux, security.SMACK64, security.ima, security.capability. That’s the whole squad, no substitutions.

EVM HMAC and signature may also include additional file and file system attributes. Currently supported additional attributes are filesystem UUID and extra SMACK extended attributes.

Kernel configuration option CONFIG_EVM_ATTR_FSUUID controls whether to include filesystem UUID into HMAC and enabled by default. Therefore evmctl also includes fsuuid by default. Providing --uuid option without parameter allows to disable usage of fs uuid. Providing --uuid=UUID option with parameter allows to use custom UUID. Providing the --portable option will disable usage of the fs uuid and also the inode number and generation. Periodt.

Kernel configuration option CONFIG_EVM_EXTRA_SMACK_XATTRS controls whether to include additional SMACK extended attributes into HMAC. They are following: security.SMACK64EXEC, security.SMACK64TRANSMUTE and security.SMACK64MMAP. evmctl --smack options enables that.

πŸ”₯ KEY AND SIGNATURE FORMATS πŸ”₯

Linux integrity subsystem supports two type of signature and respectively two key formats.

First key format (v1) is pure RSA key encoded in PEM a format and uses own signature format. It is now non-default format and requires to provide evmctl --rsa option for signing and importing the key. So yeah, v1 is kinda the legacy vibe now.

Second key format uses X509 DER encoded public key certificates and uses asymmetric key support in the kernel (since kernel 3.9). CONFIG_INTEGRITY_ASYMMETRIC_KEYS must be enabled (default). That’s the modern slay.

For v2 signatures x509 certificate (containing the public key) could be appended to the private key (they both are in PEM format) to automatically extract keyid from its Subject Key Identifier (SKID). Cute little auto-detect moment πŸ’–

πŸ‘‘ INTEGRITY KEYRINGS πŸ‘‘

Integrity subsystem uses dedicated IMA/EVM keyrings to search for signature verification keys β€” _ima and _evm respectively.

Since 3.13 IMA allows to declare IMA keyring as trusted. It allows only to load keys, signed by a key from the system keyring (.system). It means self-signed keys are not allowed. This is a default behavior unless CONFIG_IMA_TRUSTED_KEYRING is undefined. IMA trusted keyring has different name .ima. Trusted keyring requires X509 public key certificates. Old version RSA public keys are not compatible with trusted keyring. So no old-RSA shenanigans in the trusted keyring, bestie.

πŸŽ€ GENERATE EVM ENCRYPTED KEYS πŸŽ€

EVM encrypted key is used for EVM HMAC calculation:

# create and save the key kernel master key (user type)
# LMK is used to encrypt encrypted keys
keyctl add user kmk "`dd if=/dev/urandom bs=1 count=32 2>/dev/null`" @u
keyctl pipe `keyctl search @u user kmk` > /etc/keys/kmk

# create the EVM encrypted key
keyctl add encrypted evm-key "new user:kmk 64" @u
keyctl pipe `keyctl search @u encrypted evm-key` >/etc/keys/evm-key

🌈 GENERATE EVM TRUSTED KEYS (TPM BASED) 🌈

Trusted EVM keys are keys which a generate with the help of TPM. They are not related to integrity trusted keys.

# create and save the key kernel master key (user type)
keyctl add trusted kmk "new 32" @u
keyctl pipe `keyctl search @u trusted kmk` >kmk

# create the EVM trusted key
keyctl add encrypted evm-key "new trusted:kmk 32" @u
keyctl pipe `keyctl search @u encrypted evm-key` >evm-key

🌸 GENERATE SIGNING AND VERIFICATION KEYS 🌸

Generate private key in plain text format:

openssl genrsa -out privkey_evm.pem 2048

Generate encrypted private key:

openssl genrsa -des3 -out privkey_evm.pem 2048

Make encrypted private key from unencrypted:

openssl rsa -in /etc/keys/privkey_evm.pem -out privkey_evm_enc.pem -des3

Generate self-signed X509 public key certificate and private key for using kernel asymmetric keys support:

openssl req -new -nodes -utf8 -sha256 -days 36500 -batch \
            -x509 -config x509_evm.genkey \
            -outform DER -out x509_evm.der -keyout privkey_evm.pem

Create an elliptic curve (EC) key (supported since Linux v5.13)

openssl ecparam -name prime256v1 -genkey -out privkey_evm.pem

Generate self-signed x509 EC public key certificate and private key for using kernel asymmetric key support (supported since Linux v5.13):

openssl req -new -nodes -utf8 -sha1 -days 36500 -batch \
             -x509 -config x509_evm.genkey \
             -outform DER -out x509_evm.der -keyout privkey_evm.pem \
             -newkey ec -pkeyopt ec_paramgen_curve:prime256v1

Configuration file x509_evm.genkey:

# Beginning of the file
[ req ]
default_bits = 2048
distinguished_name = req_distinguished_name
prompt = no
string_mask = utf8only
x509_extensions = myexts

[ req_distinguished_name ]
O = Magrathea
CN = Glacier signing key
emailAddress = slartibartfast@magrathea.h2g2

[ myexts ]
basicConstraints=critical,CA:FALSE
keyUsage=digitalSignature
extendedKeyUsage=critical,codeSigning
subjectKeyIdentifier=hash
authorityKeyIdentifier=keyid
# EOF

Generate public key for using RSA key format:

openssl rsa -pubout -in privkey_evm.pem -out pubkey_evm.pem

Similarly generate public EC key:

openssl ec -pubout -in privkey_evm.pem -out pubkey_evm.pem

Copy keys to /etc/keys:

cp pubkey_evm.pem /etc/keys
scp pubkey_evm.pem target:/etc/keys
or
cp x509_evm.pem /etc/keys
scp x509_evm.pem target:/etc/keys

πŸŽ€ GENERATE TRUSTED KEYS πŸŽ€

okay bestie, trusted key generation is a little more complicated, and it’s a whole three-step process:

  • Create a local IMA certification authority (CA). It’s made of a private and public key certificate that are used to sign and verify other keys.
  • Build a Linux kernel with the local IMA CA X509 certificate embedded. That certificate verifies other keys added to the .ima trusted keyring.
  • Generate the IMA private signing key and verification public key certificate, signed with the local IMA CA private key.

Config file ima-local-ca.genkey:

# Beginning of the file
[ req ]
default_bits = 2048
distinguished_name = req_distinguished_name
prompt = no
string_mask = utf8only
x509_extensions = v3_ca

[ req_distinguished_name ]
O = IMA-CA
CN = IMA/EVM certificate signing key
emailAddress = ca@ima-ca

[ v3_ca ]
basicConstraints=CA:TRUE
subjectKeyIdentifier=hash
authorityKeyIdentifier=keyid:always,issuer
keyUsage = cRLSign, keyCertSign
# EOF

Note: to generate elliptic curve keys, add these params to the req commands below (supported since Linux v5.13):

-newkey ec -pkeyopt ec_paramgen_curve:prime256v1

Generate private key and X509 public key certificate:

openssl req -new -x509 -utf8 -sha256 -days 3650 -batch -config $GENKEY \
            -outform DER -out ima-local-ca.x509 -keyout ima-local-ca.priv

Produce X509 in DER format for using while building the kernel:

openssl x509 -inform DER -in ima-local-ca.x509 -out ima-local-ca.pem

Config file ima.genkey β€” and yes, those backticks around hostname and whoami are literally in the file:

# Beginning of the file
[ req ]
default_bits = 2048
distinguished_name = req_distinguished_name
prompt = no
string_mask = utf8only
x509_extensions = v3_usr

[ req_distinguished_name ]
O = `hostname`
CN = `whoami` signing key
emailAddress = `whoami`@`hostname`

[ v3_usr ]
basicConstraints=critical,CA:FALSE
#basicConstraints=CA:FALSE
keyUsage=digitalSignature
#keyUsage = nonRepudiation, digitalSignature, keyEncipherment
subjectKeyIdentifier=hash
authorityKeyIdentifier=keyid
#authorityKeyIdentifier=keyid,issuer
# EOF

Generate private key and X509 public key certificate signing request:

openssl req -new -nodes -utf8 -sha256 -days 365 -batch -config $GENKEY \
            -out csr_ima.pem -keyout privkey_ima.pem

Sign X509 public key certificate signing request with local IMA CA private key:

openssl x509 -req -in csr_ima.pem -days 365 -extfile $GENKEY -extensions v3_usr \
             -CA ima-local-ca.pem -CAkey ima-local-ca.priv -CAcreateserial \
             -outform DER -out x509_ima.der

🌸 SIGN FILE DATA AND METADATA 🌸

Default key locations, bestie:

  • Private RSA key: /etc/keys/privkey_evm.pem
  • Public RSA key: /etc/keys/pubkey_evm.pem
  • X509 certificate: /etc/keys/x509_evm.der

Options to remember: -k, -r, --rsa, --uuid, --smack.

Sign file with EVM signature and calculate hash value for IMA:

evmctl sign --imahash test.txt

Sign file with both IMA and EVM signatures β€” and yes, that trailing colon after test.txt is exactly what the page shows:

evmctl sign --imasig test.txt:

Sign file with IMA signature:

evmctl ima_sign test.txt

Sign recursively whole filesystem:

evmctl -r sign --imahash /

Fix recursively whole filesystem:

evmctl -r ima_fix /

Sign filesystem selectively using find command:

find / \( -fstype rootfs -o -fstype ext4 \) -exec evmctl sign --imahash '{}' \;

Fix filesystem selectively using find command:

find / \( -fstype rootfs -o -fstype ext4 \) -exec sh -c "< '{}'" \;

πŸ¦‹ INITIALIZE IMA/EVM AT EARLY BOOT πŸ¦‹

IMA/EVM initialization should normally be done from the initial RAM file system before mounting the root filesystem.

Here’s the Ubuntu initramfs example script (/etc/initramfs-tools/scripts/local-top/ima.sh):

# mount securityfs if not mounted
SECFS=/sys/kernel/security
grep -q  $SECFS /proc/mounts || mount -n -t securityfs securityfs $SECFS

# search for IMA trusted keyring, then for untrusted
ima_id="`awk '/\.ima/ { printf "%d", "0x"$1; }' /proc/keys`"
if [ -z "$ima_id" ]; then
    ima_id=`keyctl search @u keyring _ima 2>/dev/null`
    if [ -z "$ima_id" ]; then
        ima_id=`keyctl newring _ima @u`
    fi
fi
# import IMA X509 certificate
evmctl import /etc/keys/x509_ima.der $ima_id

# search for EVM keyring
evm_id=`keyctl search @u keyring _evm 2>/dev/null`
if [ -z "$evm_id" ]; then
    evm_id=`keyctl newring _evm @u`
fi
# import EVM X509 certificate
evmctl import /etc/keys/x509_evm.der $evm_id

# a) import EVM encrypted key
cat /etc/keys/kmk | keyctl padd user kmk @u
keyctl add encrypted evm-key "load `cat /etc/keys/evm-key`" @u
# OR
# b) import EVM trusted key
keyctl add trusted kmk "load `cat /etc/keys/kmk`" @u
keyctl add encrypted evm-key "load `cat /etc/keys/evm-key`" @u

# enable EVM
echo "1" > /sys/kernel/security/evm

Optionally it’s also possible to forbid adding and removing new public keys and certificates into keyrings, and revoking keys, using the keyctl setperm command:

# protect EVM keyring
keyctl setperm $evm_id 0x0b0b0000
# protect IMA keyring
keyctl setperm $ima_id 0x0b0b0000
# protecting IMA key from revoking (against DoS)
ima_key=`evmctl import /etc/keys/x509_ima.der $ima_id`
keyctl setperm $ima_key 0x0b0b0000

When using plain RSA public keys in PEM format, use evmctl import --rsa for importing keys:

evmctl import --rsa /etc/keys/pubkey_evm.pem $evm_id

Latest version of keyctl allows importing X509 public key certificates:

cat /etc/keys/x509_ima.der | keyctl padd asymmetric '' $ima_id

πŸŽ€ FILES πŸŽ€

Examples of scripts to generate X509 public key certificates:

  • /usr/share/doc/ima-evm-utils/ima-genkey-self.sh
  • /usr/share/doc/ima-evm-utils/ima-genkey.sh
  • /usr/share/doc/ima-evm-utils/ima-gen-local-ca.sh
  • /usr/share/doc/ima-evm-utils/ima-genkey-self-ecc.sh
  • /usr/share/doc/ima-evm-utils/ima-genkey-ecc.sh
  • /usr/share/doc/ima-evm-utils/ima-gen-local-ca-ecc.sh

πŸ’œ AUTHOR πŸ’œ

Written by Dmitry Kasatkin, <dmitry.kasatkin at gmail.com> and others.


🌈 RESOURCES 🌈


πŸ‘‘ COPYING πŸ‘‘

Copyright (C) 2012 - 2014 Linux Integrity Project. Free use of this software is granted under the terms of the GNU Public License (GPL).


okay that’s the whole page, bestie β€” the footer tags this as EVMCTL(1) and dates it 07/06/2026, so go forth and be iconic πŸ’…βœ¨

πŸ“¦ where this page comes from