mirror of
https://git.code.sf.net/p/linux-ima/ima-evm-utils
synced 2025-04-26 22:02:31 +02:00
ima-evm-utils: Add some tests for evmctl
Run `make check' to execute the tests. This commit only adds ima_hash test. Signed-off-by: Vitaly Chikunov <vt@altlinux.org> Signed-off-by: Mimi Zohar <zohar@linux.ibm.com>
This commit is contained in:
parent
dc00c92adf
commit
b6ff60e4fa
2
.gitignore
vendored
2
.gitignore
vendored
@ -21,7 +21,7 @@ missing
|
||||
compile
|
||||
libtool
|
||||
ltmain.sh
|
||||
|
||||
test-driver
|
||||
|
||||
# Compiled executables
|
||||
*.o
|
||||
|
@ -1,4 +1,4 @@
|
||||
SUBDIRS = src
|
||||
SUBDIRS = src tests
|
||||
dist_man_MANS = evmctl.1
|
||||
|
||||
doc_DATA = examples/ima-genkey-self.sh examples/ima-genkey.sh examples/ima-gen-local-ca.sh
|
||||
|
@ -72,6 +72,7 @@ EVMCTL_MANPAGE_DOCBOOK_XSL
|
||||
|
||||
AC_CONFIG_FILES([Makefile
|
||||
src/Makefile
|
||||
tests/Makefile
|
||||
packaging/ima-evm-utils.spec
|
||||
])
|
||||
AC_OUTPUT
|
||||
|
16
tests/.gitignore
vendored
Normal file
16
tests/.gitignore
vendored
Normal file
@ -0,0 +1,16 @@
|
||||
# Generated by test driver
|
||||
*.log
|
||||
*.trs
|
||||
|
||||
# Generated by tests
|
||||
*.txt
|
||||
*.out
|
||||
*.sig
|
||||
*.sig2
|
||||
|
||||
# Generated certs and keys (by gen-keys.sh)
|
||||
*.cer
|
||||
*.pub
|
||||
*.key
|
||||
*.conf
|
||||
|
7
tests/Makefile.am
Normal file
7
tests/Makefile.am
Normal file
@ -0,0 +1,7 @@
|
||||
check_SCRIPTS =
|
||||
TESTS = $(check_SCRIPTS)
|
||||
|
||||
check_SCRIPTS += ima_hash.test
|
||||
|
||||
clean-local:
|
||||
-rm -f *.txt *.out *.sig *.sig2
|
274
tests/functions.sh
Executable file
274
tests/functions.sh
Executable file
@ -0,0 +1,274 @@
|
||||
#!/bin/bash
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
#
|
||||
# ima-evm-utils tests bash functions
|
||||
#
|
||||
# Copyright (C) 2020 Vitaly Chikunov <vt@altlinux.org>
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2, or (at your option)
|
||||
# any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
|
||||
# Tests accounting
|
||||
declare -i testspass=0 testsfail=0 testsskip=0
|
||||
|
||||
# Exit codes (compatible with automake)
|
||||
declare -r OK=0
|
||||
declare -r FAIL=1
|
||||
declare -r HARDFAIL=99 # hard failure no matter testing mode
|
||||
declare -r SKIP=77
|
||||
|
||||
# You can set env VERBOSE=1 to see more output from evmctl
|
||||
VERBOSE=${VERBOSE:-0}
|
||||
V=vvvv
|
||||
V=${V:0:$VERBOSE}
|
||||
V=${V:+-$V}
|
||||
|
||||
# Exit if env FAILEARLY is defined.
|
||||
# Used in expect_{pass,fail}.
|
||||
exit_early() {
|
||||
if [ "$FAILEARLY" ]; then
|
||||
exit "$1"
|
||||
fi
|
||||
}
|
||||
|
||||
# Require particular executables to be present
|
||||
_require() {
|
||||
ret=
|
||||
for i; do
|
||||
if ! type $i; then
|
||||
echo "$i is required for test"
|
||||
ret=1
|
||||
fi
|
||||
done
|
||||
[ $ret ] && exit "$HARDFAIL"
|
||||
}
|
||||
|
||||
# Non-TTY output is never colored
|
||||
if [ -t 1 ]; then
|
||||
RED=$'\e[1;31m'
|
||||
GREEN=$'\e[1;32m'
|
||||
YELLOW=$'\e[1;33m'
|
||||
BLUE=$'\e[1;34m'
|
||||
CYAN=$'\e[1;36m'
|
||||
NORM=$'\e[m'
|
||||
export RED GREEN YELLOW BLUE CYAN NORM
|
||||
fi
|
||||
|
||||
# Test mode determined by TFAIL variable:
|
||||
# undefined: to success testing
|
||||
# defined: failure testing
|
||||
TFAIL=
|
||||
TMODE=+ # mode character to prepend running command in log
|
||||
declare -i TNESTED=0 # just for sanity checking
|
||||
|
||||
# Run positive test (one that should pass) and account its result
|
||||
expect_pass() {
|
||||
local -i ret
|
||||
|
||||
if [ $TNESTED -gt 0 ]; then
|
||||
echo $RED"expect_pass should not be run nested"$NORM
|
||||
testsfail+=1
|
||||
exit "$HARDFAIL"
|
||||
fi
|
||||
TFAIL=
|
||||
TMODE=+
|
||||
TNESTED+=1
|
||||
[ "$VERBOSE" -gt 1 ] && echo "____ START positive test: $*"
|
||||
"$@"
|
||||
ret=$?
|
||||
[ "$VERBOSE" -gt 1 ] && echo "^^^^ STOP ($ret) positive test: $*"
|
||||
TNESTED+=-1
|
||||
case $ret in
|
||||
0) testspass+=1 ;;
|
||||
77) testsskip+=1 ;;
|
||||
99) testsfail+=1; exit_early 1 ;;
|
||||
*) testsfail+=1; exit_early 2 ;;
|
||||
esac
|
||||
return $ret
|
||||
}
|
||||
|
||||
# Eval negative test (one that should fail) and account its result
|
||||
expect_fail() {
|
||||
local ret
|
||||
|
||||
if [ $TNESTED -gt 0 ]; then
|
||||
echo $RED"expect_fail should not be run nested"$NORM
|
||||
testsfail+=1
|
||||
exit "$HARDFAIL"
|
||||
fi
|
||||
|
||||
TFAIL=yes
|
||||
TMODE=-
|
||||
TNESTED+=1
|
||||
[ "$VERBOSE" -gt 1 ] && echo "____ START negative test: $*"
|
||||
"$@"
|
||||
ret=$?
|
||||
[ "$VERBOSE" -gt 1 ] && echo "^^^^ STOP ($ret) negative test: $*"
|
||||
TNESTED+=-1
|
||||
case $ret in
|
||||
0) testsfail+=1; exit_early 3 ;;
|
||||
77) testsskip+=1 ;;
|
||||
99) testsfail+=1; exit_early 4 ;;
|
||||
*) testspass+=1 ;;
|
||||
esac
|
||||
# Restore defaults (as in positive tests)
|
||||
# for tests to run without wrappers
|
||||
TFAIL=
|
||||
TMODE=+
|
||||
return $ret
|
||||
}
|
||||
|
||||
# return true if current test is positive
|
||||
_test_expected_to_pass() {
|
||||
[ ! $TFAIL ]
|
||||
}
|
||||
|
||||
# return true if current test is negative
|
||||
_test_expected_to_fail() {
|
||||
[ $TFAIL ]
|
||||
}
|
||||
|
||||
# Show blank line and color following text to red
|
||||
# if it's real error (ie we are in expect_pass mode).
|
||||
color_red_on_failure() {
|
||||
if _test_expected_to_pass; then
|
||||
echo "$RED"
|
||||
COLOR_RESTORE=true
|
||||
fi
|
||||
}
|
||||
|
||||
# For hard errors
|
||||
color_red() {
|
||||
echo "$RED"
|
||||
COLOR_RESTORE=true
|
||||
}
|
||||
|
||||
color_restore() {
|
||||
[ $COLOR_RESTORE ] && echo "$NORM"
|
||||
COLOR_RESTORE=
|
||||
}
|
||||
|
||||
ADD_DEL=
|
||||
ADD_TEXT_FOR=
|
||||
# _evmctl_run should be run as `_evmctl_run ... || return'
|
||||
_evmctl_run() {
|
||||
local op=$1 out=$1-$$.out
|
||||
local text_for=${FOR:+for $ADD_TEXT_FOR}
|
||||
# Additional parameters:
|
||||
# ADD_DEL: additional files to rm on failure
|
||||
# ADD_TEXT_FOR: append to text as 'for $ADD_TEXT_FOR'
|
||||
|
||||
cmd="evmctl $V $EVMCTL_ENGINE $*"
|
||||
echo $YELLOW$TMODE "$cmd"$NORM
|
||||
$cmd >"$out" 2>&1
|
||||
ret=$?
|
||||
|
||||
# Shell special and signal exit codes (except 255)
|
||||
if [ $ret -ge 126 ] && [ $ret -lt 255 ]; then
|
||||
color_red
|
||||
echo "evmctl $op failed hard with ($ret) $text_for"
|
||||
sed 's/^/ /' "$out"
|
||||
color_restore
|
||||
rm "$out" $ADD_DEL
|
||||
ADD_DEL=
|
||||
ADD_TEXT_FOR=
|
||||
return "$HARDFAIL"
|
||||
elif [ $ret -gt 0 ]; then
|
||||
color_red_on_failure
|
||||
echo "evmctl $op failed" ${TFAIL:+properly} "with ($ret) $text_for"
|
||||
# Show evmctl output only in verbose mode or if real failure.
|
||||
if _test_expected_to_pass || [ "$VERBOSE" ]; then
|
||||
sed 's/^/ /' "$out"
|
||||
fi
|
||||
color_restore
|
||||
rm "$out" $ADD_DEL
|
||||
ADD_DEL=
|
||||
ADD_TEXT_FOR=
|
||||
return "$FAIL"
|
||||
elif _test_expected_to_fail; then
|
||||
color_red
|
||||
echo "evmctl $op wrongly succeeded $text_for"
|
||||
sed 's/^/ /' "$out"
|
||||
color_restore
|
||||
else
|
||||
[ "$VERBOSE" ] && sed 's/^/ /' "$out"
|
||||
fi
|
||||
rm "$out"
|
||||
ADD_DEL=
|
||||
ADD_TEXT_FOR=
|
||||
return "$OK"
|
||||
}
|
||||
|
||||
# Extract xattr $attr from $file into $out file skipping $pref'ix
|
||||
_extract_xattr() {
|
||||
local file=$1 attr=$2 out=$3 pref=$4
|
||||
|
||||
getfattr -n "$attr" -e hex "$file" \
|
||||
| grep "^$attr=" \
|
||||
| sed "s/^$attr=$pref//" \
|
||||
| xxd -r -p > "$out"
|
||||
}
|
||||
|
||||
# Test if xattr $attr in $file matches $prefix
|
||||
# Show error and fail otherwise.
|
||||
_test_xattr() {
|
||||
local file=$1 attr=$2 prefix=$3
|
||||
local text_for=${ADD_TEXT_FOR:+ for $ADD_TEXT_FOR}
|
||||
|
||||
if ! getfattr -n "$attr" -e hex "$file" | egrep -qx "$attr=$prefix"; then
|
||||
color_red_on_failure
|
||||
echo "Did not find expected hash$text_for:"
|
||||
echo " $attr=$prefix"
|
||||
echo ""
|
||||
echo "Actual output below:"
|
||||
getfattr -n "$attr" -e hex "$file" | sed 's/^/ /'
|
||||
color_restore
|
||||
rm "$file"
|
||||
ADD_TEXT_FOR=
|
||||
return "$FAIL"
|
||||
fi
|
||||
ADD_TEXT_FOR=
|
||||
}
|
||||
|
||||
# Try to enable gost-engine if needed.
|
||||
_enable_gost_engine() {
|
||||
# Do not enable if it's already working (enabled by user)
|
||||
if ! openssl md_gost12_256 /dev/null >/dev/null 2>&1 \
|
||||
&& openssl engine gost >/dev/null 2>&1; then
|
||||
export EVMCTL_ENGINE="--engine gost"
|
||||
export OPENSSL_ENGINE="-engine gost"
|
||||
fi
|
||||
}
|
||||
|
||||
# Show test stats and exit into automake test system
|
||||
# with proper exit code (same as ours).
|
||||
_report_exit() {
|
||||
if [ $testsfail -gt 0 ]; then
|
||||
echo "================================="
|
||||
echo " Run with FAILEARLY=1 $0 $*"
|
||||
echo " To stop after first failure"
|
||||
echo "================================="
|
||||
fi
|
||||
[ $testspass -gt 0 ] && echo -n "$GREEN" || echo -n "$NORM"
|
||||
echo -n "PASS: $testspass"
|
||||
[ $testsskip -gt 0 ] && echo -n "$YELLOW" || echo -n "$NORM"
|
||||
echo -n " SKIP: $testsskip"
|
||||
[ $testsfail -gt 0 ] && echo -n "$RED" || echo -n "$NORM"
|
||||
echo " FAIL: $testsfail"
|
||||
echo "$NORM"
|
||||
if [ $testsfail -gt 0 ]; then
|
||||
exit "$FAIL"
|
||||
elif [ $testspass -gt 0 ]; then
|
||||
exit "$OK"
|
||||
else
|
||||
exit "$SKIP"
|
||||
fi
|
||||
}
|
||||
|
80
tests/ima_hash.test
Executable file
80
tests/ima_hash.test
Executable file
@ -0,0 +1,80 @@
|
||||
#!/bin/bash
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
#
|
||||
# evmctl ima_hash tests
|
||||
#
|
||||
# Copyright (C) 2020 Vitaly Chikunov <vt@altlinux.org>
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2, or (at your option)
|
||||
# any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
|
||||
cd "$(dirname "$0")" || exit 1
|
||||
PATH=../src:$PATH
|
||||
source ./functions.sh
|
||||
_require evmctl openssl getfattr
|
||||
|
||||
trap _report_exit EXIT
|
||||
set -f # disable globbing
|
||||
|
||||
check() {
|
||||
local alg=$1 prefix=$2 chash=$3 hash
|
||||
local file=$alg-hash.txt
|
||||
|
||||
rm -f "$file"
|
||||
touch "$file"
|
||||
# Generate hash with openssl, if it failed skip test,
|
||||
# unless it's negative test, then pass to evmctl
|
||||
cmd="openssl dgst $OPENSSL_ENGINE -$alg $file"
|
||||
echo - "$cmd"
|
||||
hash=$(set -o pipefail; $cmd 2>/dev/null | cut -d' ' -f2)
|
||||
if [ $? -ne 0 ] && _test_expected_to_pass; then
|
||||
echo "${CYAN}$alg test is skipped$NORM"
|
||||
rm "$file"
|
||||
return "$SKIP"
|
||||
fi
|
||||
if [ "$chash" ] && [ "$chash" != "$hash" ]; then
|
||||
color_red
|
||||
echo "Invalid hash for $alg from openssl"
|
||||
echo "Expected: $chash"
|
||||
echo "Returned: $hash"
|
||||
color_restore
|
||||
rm "$file"
|
||||
return "$HARDFAIL"
|
||||
fi
|
||||
|
||||
ADD_TEXT_FOR=$alg ADD_DEL=$file \
|
||||
_evmctl_run ima_hash --hashalgo "$alg" --xattr-user "$file" || return
|
||||
ADD_TEXT_FOR=$alg \
|
||||
_test_xattr "$file" user.ima "$prefix$hash" || return
|
||||
rm "$file"
|
||||
return "$OK"
|
||||
}
|
||||
|
||||
# check args: algo hdr-prefix canonic-hash
|
||||
expect_pass check md4 0x01 31d6cfe0d16ae931b73c59d7e0c089c0
|
||||
expect_pass check md5 0x01 d41d8cd98f00b204e9800998ecf8427e
|
||||
expect_pass check sha1 0x01 da39a3ee5e6b4b0d3255bfef95601890afd80709
|
||||
expect_fail check SHA1 0x01 # uppercase
|
||||
expect_fail check sha512-224 0x01 # valid for pkcs1
|
||||
expect_fail check sha512-256 0x01 # valid for pkcs1
|
||||
expect_fail check unknown 0x01 # nonexistent
|
||||
expect_pass check sha224 0x0407 d14a028c2a3a2bc9476102bb288234c415a2b01f828ea62ac5b3e42f
|
||||
expect_pass check sha256 0x0404 e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
|
||||
expect_pass check sha384 0x0405 38b060a751ac96384cd9327eb1b1e36a21fdb71114be07434c0cc7bf63f6e1da274edebfe76f65fbd51ad2f14898b95b
|
||||
expect_pass check sha512 0x0406 cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e
|
||||
expect_pass check rmd160 0x0403 9c1185a5c5e9fc54612808977ee8f548b2258d31
|
||||
expect_fail check sm3 0x01
|
||||
expect_fail check sm3-256 0x01
|
||||
_enable_gost_engine
|
||||
expect_pass check md_gost12_256 0x0412 3f539a213e97c802cc229d474c6aa32a825a360b2a933a949fd925208d9ce1bb
|
||||
expect_pass check streebog256 0x0412 3f539a213e97c802cc229d474c6aa32a825a360b2a933a949fd925208d9ce1bb
|
||||
expect_pass check md_gost12_512 0x0413 8e945da209aa869f0455928529bcae4679e9873ab707b55315f56ceb98bef0a7362f715528356ee83cda5f2aac4c6ad2ba3a715c1bcd81cb8e9f90bf4c1c1a8a
|
||||
expect_pass check streebog512 0x0413 8e945da209aa869f0455928529bcae4679e9873ab707b55315f56ceb98bef0a7362f715528356ee83cda5f2aac4c6ad2ba3a715c1bcd81cb8e9f90bf4c1c1a8a
|
||||
|
Loading…
x
Reference in New Issue
Block a user