xref: /openbmc/openbmc/meta-security/meta-integrity/classes/ima-evm-rootfs.bbclass (revision 8460358c3d24c71d9d38fd126c745854a6301564)
1# No default! Either this or IMA_EVM_PRIVKEY/IMA_EVM_X509 have to be
2# set explicitly in a local.conf before activating ima-evm-rootfs.
3# To use the insecure (because public) example keys, use
4# IMA_EVM_KEY_DIR = "${INTEGRITY_BASE}/data/debug-keys"
5IMA_EVM_KEY_DIR ?= "IMA_EVM_KEY_DIR_NOT_SET"
6
7# Private key for IMA signing. The default is okay when
8# using the example key directory.
9IMA_EVM_PRIVKEY ?= "${IMA_EVM_KEY_DIR}/privkey_ima.pem"
10
11# Additional option when signing. Allows to for example provide
12# --keyid <id> or --keyid-from-cert <filename>.
13IMA_EVM_PRIVKEY_KEYID_OPT ?= ""
14
15# Password for the private key
16IMA_EVM_EVMCTL_KEY_PASSWORD ?= ""
17
18# Public part of certificates (used for both IMA and EVM).
19# The default is okay when using the example key directory.
20IMA_EVM_X509 ?= "${IMA_EVM_KEY_DIR}/x509_ima.der"
21
22# Root CA to be compiled into the kernel, none by default.
23# Must be the absolute path to a der-encoded x509 CA certificate
24# with a .x509 suffix. See linux-%.bbappend for details.
25#
26# ima-local-ca.x509 is what ima-gen-local-ca.sh creates.
27IMA_EVM_ROOT_CA ?= "${IMA_EVM_KEY_DIR}/ima-local-ca.pem"
28
29# Mount these file systems (identified via their mount point) with
30# the iversion flags (needed by IMA when allowing writing).
31IMA_EVM_ROOTFS_IVERSION ?= ""
32
33# Avoid re-generating fstab when ima is enabled.
34WIC_CREATE_EXTRA_ARGS:append = "${@bb.utils.contains('DISTRO_FEATURES', 'ima', ' --no-fstab-update', '', d)}"
35
36# Add necessary tools (e.g., keyctl) to image
37IMAGE_INSTALL:append = "${@bb.utils.contains('DISTRO_FEATURES', 'ima', ' ima-evm-utils', '', d)}"
38
39ima_evm_sign_rootfs () {
40    cd ${IMAGE_ROOTFS}
41
42    # Beware that all operations below must also work when
43    # ima_evm_sign_rootfs was already called earlier for the same
44    # rootfs. That's because do_image might again run for various
45    # reasons (including a change of the signing keys) without also
46    # re-running do_rootfs.
47
48    # Fix /etc/fstab: it must include the "i_version" mount option for
49    # those file systems where writing files is allowed, otherwise
50    # these changes will not get detected at runtime.
51    #
52    # Note that "i_version" is documented in "man mount" only for ext4,
53    # whereas "iversion" is said to be filesystem-independent. In practice,
54    # there is only one MS_I_VERSION flag in the syscall and ext2/ext3/ext4
55    # all support it.
56    #
57    # coreutils translates "iversion" into MS_I_VERSION. busybox rejects
58    # "iversion" and only understands "i_version". systemd only understands
59    # "iversion". We pick "iversion" here for systemd, whereas rootflags
60    # for initramfs must use "i_version" for busybox.
61    #
62    # Deduplicates iversion in case that this gets called more than once.
63    if [ -f etc/fstab ]; then
64       perl -pi -e 's;(\S+)(\s+)(${@"|".join((d.getVar("IMA_EVM_ROOTFS_IVERSION", True) or "no-such-mount-point").split())})(\s+)(\S+)(\s+)(\S+);\1\2\3\4\5\6\7,iversion;; s/(,iversion)+/,iversion/;' etc/fstab
65    fi
66
67    # Detect 32bit target to pass --m32 to evmctl by looking at libc
68    tmp="$(file "${IMAGE_ROOTFS}/lib/libc.so.6" | grep -o 'ELF .*-bit')"
69    if [ "${tmp}" = "ELF 32-bit" ]; then
70        evmctl_param="--m32"
71    elif [ "${tmp}" = "ELF 64-bit" ]; then
72        evmctl_param=""
73    else
74        bberror "Unknown target architecture bitness: '${tmp}'" >&2
75        exit 1
76    fi
77
78    export EVMCTL_KEY_PASSWORD=${IMA_EVM_EVMCTL_KEY_PASSWORD}
79
80    bbnote "IMA/EVM: Signing root filesystem at ${IMAGE_ROOTFS} with key ${IMA_EVM_PRIVKEY}"
81    evmctl sign --imasig ${evmctl_param} --portable -a sha256 \
82        --key "${IMA_EVM_PRIVKEY}" ${IMA_EVM_PRIVKEY_KEYID_OPT} -r "${IMAGE_ROOTFS}"
83
84    # check signing key and signature verification key
85    evmctl ima_verify ${evmctl_param} --key "${IMA_EVM_X509}" "${IMAGE_ROOTFS}/lib/libc.so.6" || exit 1
86    evmctl verify     ${evmctl_param} --key "${IMA_EVM_X509}" "${IMAGE_ROOTFS}/lib/libc.so.6" || exit 1
87
88    # Optionally install custom policy for loading by systemd.
89    if [ "${IMA_EVM_POLICY}" ]; then
90        install -d ./${sysconfdir}/ima
91        rm -f ./${sysconfdir}/ima/ima-policy
92        install "${IMA_EVM_POLICY}" ./${sysconfdir}/ima/ima-policy
93
94        bbnote "IMA/EVM: Signing IMA policy with key ${IMA_EVM_PRIVKEY}"
95        evmctl sign --imasig ${evmctl_param} --portable -a sha256 \
96          --key "${IMA_EVM_PRIVKEY}" ${IMA_EVM_PRIVKEY_KEYID_OPT} "${IMAGE_ROOTFS}/etc/ima/ima-policy"
97    fi
98
99    # Optionally write the file names and ima and evm signatures into files
100    if [ "${IMA_FILE_SIGNATURES_FILE}" ]; then
101        getfattr -R -m security.ima --e hex --dump ./ 2>/dev/null | \
102          sed -n -e 's|# file: |/|p' -e 's|security.ima=|ima:|p' | \
103          sed '$!N;s/\n/ /' > ./${IMA_FILE_SIGNATURES_FILE}
104    fi
105    if [ "${EVM_FILE_SIGNATURES_FILE}" ]; then
106        getfattr -R -m security.evm --e hex --dump ./ 2>/dev/null | \
107          sed -n -e 's|# file: |/|p' -e 's|security.evm=|evm:|p' | \
108          sed '$!N;s/\n/ /' > ./${EVM_FILE_SIGNATURES_FILE}
109    fi
110}
111
112# Signing must run as late as possible in the do_rootfs task.
113# To guarantee that, we append it to IMAGE_PREPROCESS_COMMAND in
114# RecipePreFinalise event handler, this ensures it's the last
115# function in IMAGE_PREPROCESS_COMMAND.
116python ima_evm_sign_handler () {
117    if not e.data or 'ima' not in e.data.getVar('DISTRO_FEATURES').split():
118        return
119
120    e.data.appendVar('IMAGE_PREPROCESS_COMMAND', ' ima_evm_sign_rootfs; ')
121    e.data.appendVar('IMAGE_INSTALL', ' ima-evm-keys')
122    e.data.appendVarFlag('do_rootfs', 'depends', ' ima-evm-utils-native:do_populate_sysroot')
123}
124addhandler ima_evm_sign_handler
125ima_evm_sign_handler[eventmask] = "bb.event.RecipePreFinalise"
126