#!/bin/sh # SPDX-License-Identifier: GPL-2.0-or-later # Copyright (c) 2020 Microsoft Corporation # Copyright (c) 2020 Petr Vorel # Author: Lachlan Sneff # # Verify that keys are measured correctly based on policy. TST_NEEDS_CMDS="cmp cut grep sed xxd" TST_CNT=2 TST_NEEDS_DEVICE=1 TST_SETUP=setup TST_CLEANUP=cleanup . ima_setup.sh FUNC_KEYCHECK='func=KEY_CHECK' TEMPLATE_BUF='template=ima-buf' REQUIRED_POLICY="^measure.*($FUNC_KEYCHECK.*$TEMPLATE_BUF|$TEMPLATE_BUF.*$FUNC_KEYCHECK)" setup() { require_ima_policy_content "$REQUIRED_POLICY" '-E' > $TST_TMPDIR/policy.txt } cleanup() { tst_is_num $KEYRING_ID && keyctl clear $KEYRING_ID } check_keys_policy() { local pattern="$1" if ! grep -E "$pattern" $TST_TMPDIR/policy.txt; then tst_res TCONF "IMA policy must specify $pattern, $FUNC_KEYCHECK, $TEMPLATE_BUF" return 1 fi return 0 } # Based on https://lkml.org/lkml/2019/12/13/564. # (450d0fd51564 - "IMA: Call workqueue functions to measure queued keys") test1() { local keycheck_lines i keyrings templates local pattern='keyrings=[^[:space:]]+' local test_file="file.txt" tmp_file="file2.txt" tst_res TINFO "verify key measurement for keyrings and templates specified in IMA policy" check_keys_policy "$pattern" > $tmp_file || return keycheck_lines=$(cat $tmp_file) keyrings=$(for i in $keycheck_lines; do echo "$i" | grep "keyrings" | \ sed "s/\./\\\./g" | cut -d'=' -f2; done | sed ':a;N;$!ba;s/\n/|/g') if [ -z "$keyrings" ]; then tst_res TCONF "IMA policy has a keyring key-value specifier, but no specified keyrings" return fi templates=$(for i in $keycheck_lines; do echo "$i" | grep "template" | \ cut -d'=' -f2; done | sed ':a;N;$!ba;s/\n/|/g') tst_res TINFO "keyrings: '$keyrings'" tst_res TINFO "templates: '$templates'" grep -E "($templates).*($keyrings)" $ASCII_MEASUREMENTS | while read line do local digest expected_digest algorithm digest=$(echo "$line" | cut -d' ' -f4 | cut -d':' -f2) algorithm=$(echo "$line" | cut -d' ' -f4 | cut -d':' -f1) keyring=$(echo "$line" | cut -d' ' -f5) echo "$line" | cut -d' ' -f6 | xxd -r -p > $test_file if ! expected_digest="$(compute_digest $algorithm $test_file)"; then tst_res TCONF "cannot compute digest for $algorithm" return fi if [ "$digest" != "$expected_digest" ]; then tst_res TFAIL "incorrect digest was found for $keyring keyring" return fi done tst_res TPASS "specified keyrings were measured correctly" } # Create a new keyring, import a certificate into it, and verify # that the certificate is measured correctly by IMA. test2() { tst_require_cmds evmctl keyctl openssl local cert_file="$TST_DATAROOT/x509_ima.der" local keyring_name="key_import_test" local pattern="keyrings=[^[:space:]]*$keyring_name" local temp_file="file.txt" tst_res TINFO "verify measurement of certificate imported into a keyring" check_keys_policy "$pattern" >/dev/null || return KEYRING_ID=$(keyctl newring $keyring_name @s) || \ tst_brk TBROK "unable to create a new keyring" if ! tst_is_num $KEYRING_ID; then tst_brk TBROK "unable to parse the new keyring id ('$KEYRING_ID')" fi evmctl import $cert_file $KEYRING_ID > /dev/null || \ tst_brk TBROK "unable to import a certificate into $keyring_name keyring" grep $keyring_name $ASCII_MEASUREMENTS | tail -n1 | cut -d' ' -f6 | \ xxd -r -p > $temp_file if [ ! -s $temp_file ]; then tst_res TFAIL "keyring $keyring_name not found in $ASCII_MEASUREMENTS" return fi if ! openssl x509 -in $temp_file -inform der > /dev/null; then tst_res TFAIL "logged certificate is not a valid x509 certificate" return fi if cmp -s $temp_file $cert_file; then tst_res TPASS "logged certificate matches the original" else tst_res TFAIL "logged certificate does not match original" fi } tst_run