Security:IntegrityMeasurement/Preparing Tizen image protected by IMA/EVM

From Tizen Wiki
Jump to: navigation, search

HOWTO: Preparing Tizen image protected by IMA/EVM

This instruction describes how to prepare Tizen image protected by IMA/EVM. Links for the newest tizen.org sources prepared to IMA/EVM (kernel, ima-evm-utils, etc.) you will find in "Development" section.

1. Install needed tools on your host machine

You will need:

  • ima-evm-utils
  • keyutils

You will probably need to build ima-evm-utils from sources. (Keyutils package is available for Ubuntu.) Ima-evm-utils mainline source can be found on: http://sourceforge.net/p/linux-ima/ima-evm-utils/ci/master/tree/. You can also use ima-evm-utils Tizen.org source.

2. Generate keys/certificates

Two keys/certificates will be needed:

  1. Kernel built-in self-signed CA x509 certificate.
  2. IMA x509 certificate - signed by the kernel built-in certificate.

To generate key 1. use script ima-gen-local-ca.sh:

#!/bin/sh

GENKEY=ima-local-ca.genkey

cat << __EOF__ >$GENKEY
[ 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__

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

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

This script should generate ima-local-ca.x509 file - this file should be copied to main directory with tizen kernel sources. Name of the file isn't important - the only thing about the file name is: it have to have .x509 extension.

To generate key 2. use script:

#!/bin/sh

GENKEY=ima.genkey

cat << __EOF__ >$GENKEY
[ req ]
default_bits = 1024
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__

openssl req -new -nodes -utf8 -sha1 -days 365 -batch -config $GENKEY \
                -out csr_ima.pem -keyout privkey_ima.pem
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

This script will generate a few files. Two files are important for you: x509_ima.der - this file contains certificate signed by key 1. privkey_ima.pem - private key for the x509_ima.der, this key will be used to sign files on the image. We leave these keys now. We will need it later.

3. Configuring and building the kernel

Build the kernel with these options:

SYSTEM_TRUSTED_KEYRING=y
CONFIG_KEYS=y
CONFIG_TRUSTED_KEYS=y
CONFIG_ENCRYPTED_KEYS=y
CONFIG_KEYS_DEBUG_PROC_KEYS=y
CONFIG_SECURITY=y
CONFIG_SECURITYFS=y
CONFIG_SECURITY_SMACK=y
CONFIG_INTEGRITY=y
CONFIG_INTEGRITY_SIGNATURE=y
CONFIG_INTEGRITY_ASYMMETRIC_KEYS=y
CONFIG_INTEGRITY_AUDIT=y
CONFIG_INTEGRITY_LOAD_KEYS=y
CONFIG_INTEGRITY_FILE_READ=y
CONFIG_INTEGRITY_LOAD_X509=y
CONFIG_INTEGRITY_TRUSTED_KEYRING=y
CONFIG_IMA=y
CONFIG_IMA_MEASURE_PCR_IDX=10
CONFIG_IMA_LSM_RULES=y
CONFIG_IMA_NG_TEMPLATE=y
CONFIG_IMA_DEFAULT_TEMPLATE="ima-ng"
CONFIG_IMA_DEFAULT_HASH_SHA1=y
CONFIG_IMA_DEFAULT_HASH="sha1"
CONFIG_IMA_APPRAISE=y
CONFIG_IMA_TRUSTED_KEYRING=y
CONFIG_IMA_LOAD_X509=y
CONFIG_IMA_X509_PATH="/etc/ima/x509_ima.der"
CONFIG_IMA_POLICY_LOADER=y
CONFIG_IMA_POLICY_REPLACEABLE=y
CONFIG_IMA_LOAD_POLICY=y
CONFIG_IMA_POLICY_PATH="/etc/ima/ima_policy"
CONFIG_IMA_READABLE_POLICY_INTERFACE=y
CONFIG_IMA_STATE_INTERFACE=y
CONFIG_EVM=y
CONFIG_EVM_ATTR_FSUUID=y
# CONFIG_EVM_EXTRA_SMACK_XATTRS is not set #
CONFIG_EVM_LOAD_KEY=y
CONFIG_EVM_KEY_PATH="/etc/ima/evm-key"
CONFIG_EVM_KMK_PATH="/etc/ima/evm-kmk"
CONFIG_EVM_TRUSTED_KEYRING=y
CONFIG_EVM_LOAD_X509=y
CONFIG_EVM_X509_PATH="/etc/ima/x509_evm.der"
CONFIG_EVM_STATE_INTERFACE=y
CONFIG_CRYPTO=y

These option have to be set as above - although you can configure the path as you want. You can also check other IMA/EVM related options and enable if you'd like. Build the kernel. In build log you should see:

X.509 certificate list changed
 CERTS   kernel/x509_certificate_list
  - Including cert ima-local-ca.x509

Which means that you Root CA was included in kernel.

4. Preparing the platform image

Let assume that you've got a Tizen platform image in .img format (e.g. tizen-platform.img). On the image these packages should be installed:

  • keyutils
  • ima-evm-utils
  • attr
  • ima-evm-reference-utils (as a reference solution - you should replace these tools by your own, or remove it)

To prepare the platform image you need to do a few things. First you need to choose your integrity policy - policy that describes for which files to check the integrity. Policy rules can be written based on the various criteria like:

  • using function for opening file (read, exec, etc),
  • mask (file permission, e.g. "may exec"),
  • type of file system (fs magic),
  • current process UID,
  • file owner (UID),
  • filesystem ID (FSUUID),
  • path.

One policy rule descibes one of actions:

  • measure,
  • don't measure,
  • appraise
  • don't appraise.

The default policy (build-in into the kernel, file: security/integrity/ima/ima_policy.c) look like this:

DONT_MEASURE fsmagic=PROC_SUPER_MAGIC
DONT_MEASURE fsmagic=SYSFS_MAGIC
DONT_MEASURE fsmagic=DEBUGFS_MAGIC
DONT_MEASURE fsmagic=TMPFS_MAGIC
DONT_MEASURE fsmagic=DEVPTS_SUPER_MAGIC
DONT_MEASURE fsmagic=BINFMTFS_MAGIC
DONT_MEASURE fsmagic=SECURITYFS_MAGIC
DONT_MEASURE fsmagic=SELINUX_MAGIC
MEASURE func=MMAP_CHECK mask=MAY_EXEC
MEASURE func=BPRM_CHECK mask=MAY_EXEC
MEASURE func=FILE_CHECK mask=MAY_READ uid=GLOBAL_ROOT_UID,
MEASURE func=MODULE_CHECK
MEASURE func=FIRMWARE_CHECK
DONT_APPRAISE fsmagic=PROC_SUPER_MAGIC
DONT_APPRAISE fsmagic=SYSFS_MAGIC
DONT_APPRAISE fsmagic=DEBUGFS_MAGIC
DONT_APPRAISE fsmagic=TMPFS_MAGIC
DONT_APPRAISE fsmagic=RAMFS_MAGIC
DONT_APPRAISE fsmagic=DEVPTS_SUPER_MAGIC
DONT_APPRAISE fsmagic=BINFMTFS_MAGIC
DONT_APPRAISE fsmagic=SECURITYFS_MAGIC
DONT_APPRAISE fsmagic=SELINUX_MAGIC
DONT_APPRAISE fsmagic=CGROUP_SUPER_MAGIC
APPRAISE fowner=GLOBAL_ROOT_UID

You can modify kernel source code, but it isn't necessary. Let's keep it as it is.

We can write our own policy (modifying the original):

dont_measure fsmagic=0x9fa0 
dont_measure fsmagic=0x62656572 
dont_measure fsmagic=0x64626720 
dont_measure fsmagic=0x1021994 
dont_measure fsmagic=0x1cd1 
dont_measure fsmagic=0x42494e4d 
dont_measure fsmagic=0x73636673 
dont_measure fsmagic=0xf97cff8c 
measure func=MMAP_CHECK mask=MAY_EXEC 
measure func=BPRM_CHECK mask=MAY_EXEC 
measure func=FILE_CHECK mask=MAY_READ uid=0 
measure func=MODULE_CHECK 
measure path=vda:/usr/lib 
measure path=vda:/usr/bin 
measure path=vda:/usr/sbin 
measure path=vda:/lib 
measure path=vda:/bin 
measure path=vda:/sbin 
dont_appraise fsmagic=0x9fa0 
dont_appraise fsmagic=0x62656572 
dont_appraise fsmagic=0x64626720 
dont_appraise fsmagic=0x1021994 
dont_appraise fsmagic=0x858458f6 
dont_appraise fsmagic=0x1cd1 
dont_appraise fsmagic=0x42494e4d 
dont_appraise fsmagic=0x73636673 
dont_appraise fsmagic=0xf97cff8c 
dont_appraise fsmagic=0x27e0eb 
appraise path=vda:/usr/lib 
appraise path=vda:/usr/bin 
appraise path=vda:/usr/sbin 
appraise path=vda:/lib 
appraise path=vda:/bin 
appraise path=vda:/sbin 

Notice that all FSMAGIC defines are replaced with numbers. This isn't necessary, but easier for us to use policy in this shape (later you'll see why). Save this policy file on your host machine (e.g. in /home/user/policy). To load the policy into the kernel in runtime the policy must be provided together with signature. To generate signature you need the same key which you've used to sign the files on the image. To generate signature use:

evmctl ima_sign -f -k /path/to/privkey_ima.pem /home/user/policy

A new file will be created - this is the signature:

/home/user/policy.sig

Now we need to sign the files that are included in policy and have set "appraise" action (all files in locations: /root, /usr/lib, etc.). Your should mount tizen platorm image on your host machine. You can use this command:

sudo mount -w -o loop tizen-image.img /home/user/img

Now you need to generate signature for files. For this you will need IMA private key (privkey_ima.pem). This may take a while.

sudo evmctl -r sign -s -k /path/to/privkey_ima.pem /home/user/img/root
sudo evmctl -r sign -s -k /path/to/privkey_ima.pem /home/user/img/usr/lib
sudo evmctl -r sign -s -k /path/to/privkey_ima.pem /home/user/img/usr/bin
sudo evmctl -r sign -s -k /path/to/privkey_ima.pem /home/user/img/usr/sbin
sudo evmctl -r sign -s -k /path/to/privkey_ima.pem /home/user/img/lib
sudo evmctl -r sign -s -k /path/to/privkey_ima.pem /home/user/img/bin
sudo evmctl -r sign -s -k /path/to/privkey_ima.pem /home/user/img/sbin

You can check if generating signatures succed, e.g.:

getfattr -d -m . /home/user/img/usr/bin/bash
# file: /home/user/img/usr/bin/bash
security.SMACK64="_"
security.evm=0sAwICAYjv9ACAbW7Wad5Qdg+RMfcDl9Oq4lq+lu3YZJM8Uzvpcz97j7g62YFzB8PMjWWUty5Txy02TQWLHSv7CDJCCukcVxdjm69aQnh0Hfn2//RdhBSoCSlNkVNiySOcf1jOnUpSoV4Ducp4UWDw/GpvOimNpUbI8vSbv1gWkuvwMXYxQzTzzkM=
security.ima=0sAwICAYjv9ACAHFarFFhNNuvR+v12AKiCmxfZdq5gNq2yZhCuSnb0cTgHl0omVqRk2vvSCPBthOf5OXmUlI+ncnqYBo/0lmW2RnJwROBLNKl659OqNJWNPuJexhTxrzcOm1mxzgby5bI/jgjvbmcXvbLjPWcC+OU+g0pa+Yl9zhG6Jdgc2wjqowg=

If you see the security.ima and security.evm attributes then everthing is OK. You can also verify the signature using evmctl.

Applaying your policy into the image.

When kernel starts it looks for policy in /etc/ima/ima_policy (this is default path - you can configure it in kernel config). So the signature should be in /etc/ima/ima_policy.sig. If kernel will find the policy there and if the signature is correct it replace the default policy at startup. So you can copy you own policy together with signature to the mounted platform image.

Copy x509 certificate.

Last thing we need to do on the image is to copy IMA x509 certificate to the image in the location set in kernel config. The dafault path is /etc/ima/x509_ima.der. This is the cerficate genrated in step 2. You can use the same certificate to EVM So do:

cp /path/to/x509_ima.der /home/user/img/etc/ima/x509_ima.der
cp /path/to/x509_ima.der /home/user/img/etc/ima/x509_evm.der

Using the same certificate for IMA and EVM should have no bad consequences in this case. But in general case you should consider generate separate key for EVM - use the same script which you've used for generate IMA certificate.

Unmnount the image:

sodu umount /home/user/img

You can also consider labeling file system directly on the device - in IMA/EVM fix mode.

5. Running the system

To make IMA/EVM working you need to pass a few params to the kernel:

rootflags= i_version ima_tcb ima_appraise_tcb ima_template_fmt=d-ng|n-ng|status

If you did everthing correctly, then system should run properly. In case of any problem you can try to debug the system with:

rootflags= i_version ima_tcb ima_appraise=fix ima_appraise_tcb ima_template_fmt=d-ng|n-ng|status evm=fix

This will run the system with IMA/EVM fix mode.

The system is runnig. What next? In general that's all. If system is running in enforce mode then it means that you've done evething correctly. You may want to check or change a few things, e.g.: - check currently policy - update policy - check state of IMA or EVM - change state of IMA or EVM

All these things can be done by reading/writing kernel interfaces. All integrity-related interfaces are in

/sys/kernel/security

To check IMA state

cat /sys/kernel/security/ima/ima_state.

You need to know what these number means - you can check it above (or in kernel souce ima.h and evm.h). To change IMA state do "disabled" write to the kernel interface:

echo "0 > /sys/kernel/security/ima/ima_state.

The same with EVM state:

cat /sys/kernel/security/evm
echo "0" > /sys/kernel/security/evm

To to read current policy you can use:

cat /sys/kernel/security/ima/policy

Here you get FS magic-numbers instead of names. You can use the same format to load policy to the kernel, but remember - policy have to be signed to load it into the kernel (you know how to sign the policy from point 4.). To load policy type:

echo "/path/to/some_policy" > /sys/kernel/security/ima/policy

in this case signature should be located in:

/path/to/some_policy.sig

Remeber to use full path - using reletive path will not work.

You can check list of files that have been cheked from last boot:

cat /sys/kernel/security/ima/ascii_measurement_list


6. Reference tools.

In reference tools you can find: - service (ima-evm-server) - console tool (im-console)

These tools are to demonstrate some IMA/EVM features. First run the service:

ima-evm-serivce &

Then you can use the im-console tool. Run the help to get more informations:

im-console -h