mirror of
				https://git.code.sf.net/p/linux-ima/ima-evm-utils
				synced 2025-10-31 05:00:41 +01: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:
		 Vitaly Chikunov
					Vitaly Chikunov
				
			
				
					committed by
					
						 Mimi Zohar
						Mimi Zohar
					
				
			
			
				
	
			
			
			 Mimi Zohar
						Mimi Zohar
					
				
			
						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 | ||||
|  | ||||
		Reference in New Issue
	
	Block a user