Blame tests/sign_verify.test

Packit Service 087331
#!/bin/bash
Packit Service 087331
# SPDX-License-Identifier: GPL-2.0
Packit Service 087331
#
Packit Service 087331
# evmctl {,ima_}{sign,verify} tests
Packit Service 087331
#
Packit Service 087331
# Copyright (C) 2020 Vitaly Chikunov <vt@altlinux.org>
Packit Service 087331
#
Packit Service 087331
# This program is free software; you can redistribute it and/or modify
Packit Service 087331
# it under the terms of the GNU General Public License as published by
Packit Service 087331
# the Free Software Foundation; either version 2, or (at your option)
Packit Service 087331
# any later version.
Packit Service 087331
#
Packit Service 087331
# This program is distributed in the hope that it will be useful,
Packit Service 087331
# but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service 087331
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit Service 087331
# GNU General Public License for more details.
Packit Service 087331
Packit Service 087331
cd "$(dirname "$0")" || exit 1
Packit Service 087331
PATH=../src:$PATH
Packit Service 087331
source ./functions.sh
Packit Service 087331
Packit Service 087331
_require cmp evmctl getfattr openssl xxd
Packit Service 087331
Packit Service 087331
if cmp -b 2>&1 | grep -q "invalid option"; then
Packit Service 087331
	echo "cmp does not support -b (cmp from busybox?) Use cmp from diffutils"
Packit Service 087331
	exit "$HARDFAIL"
Packit Service 087331
fi
Packit Service 087331
Packit Service 087331
./gen-keys.sh >/dev/null 2>&1
Packit Service 087331
Packit Service 087331
trap _report_exit EXIT
Packit Service 087331
set -f # disable globbing
Packit Service 087331
Packit Service 087331
# Determine keyid from a cert
Packit Service 087331
_keyid_from_cert() {
Packit Service 087331
  local cer=${1%.*}.cer cmd
Packit Service 087331
  local tmp
Packit Service 087331
Packit Service 087331
  cer=test-${cer#test-}
Packit Service 087331
  # shellcheck disable=SC2086
Packit Service 087331
  cmd="openssl x509 $OPENSSL_ENGINE \
Packit Service 087331
          -in $cer -inform DER -pubkey -noout"
Packit Service 087331
  id=$($cmd 2>/dev/null \
Packit Service 087331
    | openssl asn1parse \
Packit Service 087331
    | grep BIT.STRING \
Packit Service 087331
    | cut -d: -f1)
Packit Service 087331
  if [ -z "$id" ]; then
Packit Service 087331
    echo - "$cmd" >&2
Packit Service 087331
    echo "Cannot asn1parse $cer to determine keyid" >&2
Packit Service 087331
    exit 1
Packit Service 087331
  fi
Packit Service 087331
  tmp=$(mktemp)
Packit Service 087331
  # shellcheck disable=SC2086
Packit Service 087331
  openssl x509 $OPENSSL_ENGINE \
Packit Service 087331
      -in "$cer" -inform DER -pubkey -noout 2>/dev/null \
Packit Service 087331
    | openssl asn1parse -strparse "$id" -out "$tmp" -noout
Packit Service 087331
  # shellcheck disable=SC2002
Packit Service 087331
  cat "$tmp" \
Packit Service 087331
    | openssl dgst -c -sha1 \
Packit Service 087331
    | cut -d' ' -f2 \
Packit Service 087331
    | grep -o ":..:..:..:..$" \
Packit Service 087331
    | tr -d :
Packit Service 087331
  rm -f "$tmp"
Packit Service 087331
}
Packit Service 087331
Packit Service 087331
# Convert test $type into evmctl op prefix
Packit Service 087331
_op() {
Packit Service 087331
  if [ "$1" = ima ]; then
Packit Service 087331
    echo ima_
Packit Service 087331
  fi
Packit Service 087331
}
Packit Service 087331
Packit Service 087331
# Convert test $type into xattr name
Packit Service 087331
_xattr() {
Packit Service 087331
  if [ "$1" = ima ]; then
Packit Service 087331
    echo user.ima
Packit Service 087331
  else
Packit Service 087331
    echo user.evm
Packit Service 087331
  fi
Packit Service 087331
}
Packit Service 087331
Packit Service 087331
# Check that detached signature matches xattr signature
Packit Service 087331
_test_sigfile() {
Packit Service 087331
  local file=$1 attr=$2 file_sig=$3 file_sig2=$4
Packit Service 087331
Packit Service 087331
  if [ ! -e "$file_sig" ]; then
Packit Service 087331
    color_red
Packit Service 087331
    echo "evmctl ima_sign: no detached signature $file_sig"
Packit Service 087331
    color_restore
Packit Service 087331
    rm "$file"
Packit Service 087331
    return "$FAIL"
Packit Service 087331
  fi
Packit Service 087331
Packit Service 087331
  _extract_xattr "$file" "$attr" "$file_sig2"
Packit Service 087331
  if ! cmp -bl "$file_sig" "$file_sig2"; then
Packit Service 087331
    color_red
Packit Service 087331
    echo "evmctl ima_sign: xattr signature on $file differ from detached $file_sig"
Packit Service 087331
    color_restore
Packit Service 087331
    rm "$file" "$file_sig" "$file_sig2"
Packit Service 087331
    return "$FAIL"
Packit Service 087331
  fi
Packit Service 087331
Packit Service 087331
  # Leave '$file_sig' for ima_verify --sigfile test.
Packit Service 087331
  rm "$file_sig2"
Packit Service 087331
}
Packit Service 087331
Packit Service 087331
# Run single sign command
Packit Service 087331
_evmctl_sign() {
Packit Service 087331
  local type=$1 key=$2 alg=$3 file=$4 opts=$5
Packit Service 087331
Packit Service 087331
  # Can check --sigfile for ima_sign
Packit Service 087331
  [ "$type" = ima ] && opts+=" --sigfile"
Packit Service 087331
Packit Service 087331
  # shellcheck disable=SC2086
Packit Service 087331
  ADD_TEXT_FOR="$alg ($key)" ADD_DEL=$file \
Packit Service 087331
    _evmctl_run "$(_op "$type")sign" $opts \
Packit Service 087331
    --hashalgo "$alg" --key "$key" --xattr-user "$file" || return
Packit Service 087331
Packit Service 087331
  if [ "$type" = ima ]; then
Packit Service 087331
    _test_sigfile "$file" "$(_xattr "$type")" "$file.sig" "$file.sig2"
Packit Service 087331
  fi
Packit Service 087331
}
Packit Service 087331
Packit Service 087331
# Run and test {ima_,}sign operation
Packit Service 087331
check_sign() {
Packit Service 087331
  # Arguments are passed via global vars:
Packit Service 087331
  # TYPE (ima or evm),
Packit Service 087331
  # KEY,
Packit Service 087331
  # ALG (hash algo),
Packit Service 087331
  # PREFIX (signature header prefix in hex),
Packit Service 087331
  # OPTS (additional options for evmctl),
Packit Service 087331
  # FILE (working file to sign).
Packit Service 087331
  local "$@"
Packit Service 087331
  local KEY=${KEY%.*}.key
Packit Service 087331
  local FILE=${FILE:-$ALG.txt}
Packit Service 087331
Packit Service 087331
  # Normalize key filename
Packit Service 087331
  KEY=test-${KEY#test-}
Packit Service 087331
Packit Service 087331
  # Append suffix to files for negative tests, because we may
Packit Service 087331
  # leave only good files for verify tests.
Packit Service 087331
  _test_expected_to_fail && FILE+='~'
Packit Service 087331
Packit Service 087331
  rm -f $FILE
Packit Service 087331
  if ! touch $FILE; then
Packit Service 087331
    color_red
Packit Service 087331
    echo "Can't create test file: $FILE"
Packit Service 087331
    color_restore
Packit Service 087331
    return "$HARDFAIL"
Packit Service 087331
  fi
Packit Service 087331
Packit Service 087331
  if _test_expected_to_pass; then
Packit Service 087331
    # Can openssl work with this digest?
Packit Service 087331
    cmd="openssl dgst $OPENSSL_ENGINE -$ALG $FILE"
Packit Service 087331
    echo - "$cmd"
Packit Service 087331
    if ! $cmd >/dev/null; then
Packit Service 087331
      echo "${CYAN}$ALG ($KEY) test is skipped (openssl is unable to digest)$NORM"
Packit Service 087331
      return "$SKIP"
Packit Service 087331
    fi
Packit Service 087331
Packit Service 087331
    if [ ! -e "$KEY" ]; then
Packit Service 087331
      echo "${CYAN}$ALG ($KEY) test is skipped (key file not found)$NORM"
Packit Service 087331
      return "$SKIP"
Packit Service 087331
    fi
Packit Service 087331
Packit Service 087331
    # Can openssl sign with this digest and key?
Packit Service 087331
    cmd="openssl dgst $OPENSSL_ENGINE -$ALG -sign $KEY -hex $FILE"
Packit Service 087331
    echo - "$cmd"
Packit Service 087331
    if ! $cmd >/dev/null; then
Packit Service 087331
      echo "${CYAN}$ALG ($KEY) test is skipped (openssl is unable to sign)$NORM"
Packit Service 087331
      return "$SKIP"
Packit Service 087331
    fi
Packit Service 087331
  fi
Packit Service 087331
Packit Service 087331
  # Insert keyid from cert into PREFIX in-place of marker `:K:'
Packit Service 087331
  if [[ $PREFIX =~ :K: ]]; then
Packit Service 087331
    keyid=$(_keyid_from_cert "$KEY")
Packit Service 087331
    if [ $? -ne 0 ]; then
Packit Service 087331
      color_red
Packit Service 087331
      echo "Unable to determine keyid for $KEY"
Packit Service 087331
      color_restore
Packit Service 087331
      return "$HARDFAIL"
Packit Service 087331
    fi
Packit Service 087331
    [ "$VERBOSE" -gt 2 ] && echo "  Expected keyid: $keyid"
Packit Service 087331
    PREFIX=${PREFIX/:K:/$keyid}
Packit Service 087331
  fi
Packit Service 087331
Packit Service 087331
  # Perform signing by evmctl
Packit Service 087331
  _evmctl_sign "$TYPE" "$KEY" "$ALG" "$FILE" "$OPTS" || return
Packit Service 087331
Packit Service 087331
  # First simple pattern match the signature.
Packit Service 087331
  ADD_TEXT_FOR=$ALG \
Packit Service 087331
    _test_xattr "$FILE" "$(_xattr "$TYPE")" "$PREFIX.*" || return
Packit Service 087331
Packit Service 087331
  # This is all we can do for v1 signatures.
Packit Service 087331
  [[ "$OPTS" =~ --rsa ]] && return "$OK"
Packit Service 087331
Packit Service 087331
  # This is all we can do for evm.
Packit Service 087331
  [[ "$TYPE" =~ evm ]] && return "$OK"
Packit Service 087331
Packit Service 087331
  # Extract signature to a file
Packit Service 087331
  _extract_xattr "$FILE" "$(_xattr "$TYPE")" "$FILE.sig2" "$PREFIX"
Packit Service 087331
Packit Service 087331
  # Verify extracted signature with openssl
Packit Service 087331
  cmd="openssl dgst $OPENSSL_ENGINE -$ALG -verify ${KEY%.*}.pub \
Packit Service 087331
	-signature $FILE.sig2 $FILE"
Packit Service 087331
  echo - "$cmd"
Packit Service 087331
  if ! $cmd; then
Packit Service 087331
    color_red_on_failure
Packit Service 087331
    echo "Signature v2 verification with openssl is failed."
Packit Service 087331
    color_restore
Packit Service 087331
    rm "$FILE.sig2"
Packit Service 087331
    return "$FAIL"
Packit Service 087331
  fi
Packit Service 087331
Packit Service 087331
  rm "$FILE.sig2"
Packit Service 087331
  return "$OK"
Packit Service 087331
}
Packit Service 087331
Packit Service 087331
# Test verify operation
Packit Service 087331
check_verify() {
Packit Service 087331
  # Arguments are passed via global vars:
Packit Service 087331
  # TYPE (ima or evm),
Packit Service 087331
  # KEY,
Packit Service 087331
  # ALG (hash algo),
Packit Service 087331
  # OPTS (additional options for evmctl),
Packit Service 087331
  # FILE (filename to verify).
Packit Service 087331
  local "$@"
Packit Service 087331
Packit Service 087331
  # shellcheck disable=SC2086
Packit Service 087331
  if ! openssl dgst $OPENSSL_ENGINE -"$ALG" /dev/null >/dev/null 2>&1; then
Packit Service 087331
    echo $CYAN"$ALG ($KEY) test is skipped (openssl does not support $ALG)"$NORM
Packit Service 087331
    return $SKIP
Packit Service 087331
  fi
Packit Service 087331
Packit Service 087331
  # shellcheck disable=SC2086
Packit Service 087331
  ADD_TEXT_FOR="$FILE ($KEY)" \
Packit Service 087331
    _evmctl_run "$(_op "$TYPE")verify" --key "$KEY" --xattr-user $OPTS "$FILE"
Packit Service 087331
}
Packit Service 087331
Packit Service 087331
# Test runners
Packit Service 087331
Packit Service 087331
# Perform sign and verify ima and evm testing
Packit Service 087331
sign_verify() {
Packit Service 087331
  local key=$1 alg=$2 prefix="$3" opts="$4"
Packit Service 087331
  local file=$alg.txt
Packit Service 087331
Packit Service 087331
  # Set defaults:
Packit Service 087331
  # Public key is different for v1 and v2 (where x509 cert is used).
Packit Service 087331
  if [[ $opts =~ --rsa ]]; then
Packit Service 087331
    KEY=test-$key.pub
Packit Service 087331
  else
Packit Service 087331
    KEY=test-$key.cer
Packit Service 087331
  fi
Packit Service 087331
  ALG=$alg
Packit Service 087331
  PREFIX=$prefix
Packit Service 087331
  OPTS=$opts
Packit Service 087331
  FILE=$file
Packit Service 087331
Packit Service 087331
  TYPE=ima
Packit Service 087331
  if expect_pass check_sign; then
Packit Service 087331
Packit Service 087331
    # Normal verify with proper key should pass
Packit Service 087331
    expect_pass check_verify
Packit Service 087331
    expect_pass check_verify OPTS="--sigfile"
Packit Service 087331
Packit Service 087331
    # Multiple files and some don't verify
Packit Service 087331
    expect_fail check_verify FILE="/dev/null $file"
Packit Service 087331
Packit Service 087331
    rm "$FILE.sig"
Packit Service 087331
  fi
Packit Service 087331
Packit Service 087331
  TYPE=evm
Packit Service 087331
  # Avoid running blkid for evm tests which may require root
Packit Service 087331
  # No generation on overlayfs:
Packit Service 087331
  # ioctl(3, FS_IOC_GETVERSION, 0x7ffd8e0bd628) = -1 ENOTTY (Inappropriate ioctl for device)
Packit Service 087331
  OPTS="$opts --uuid --generation 0"
Packit Service 087331
  if expect_pass check_sign; then
Packit Service 087331
Packit Service 087331
    # Normal verify with proper key
Packit Service 087331
    expect_pass check_verify
Packit Service 087331
Packit Service 087331
    # Verify with wrong key
Packit Service 087331
    expect_fail check_verify KEY=rsa2048
Packit Service 087331
  fi
Packit Service 087331
Packit Service 087331
  # Note: Leaving TYPE=evm and file is evm signed
Packit Service 087331
}
Packit Service 087331
Packit Service 087331
# Test --keys
Packit Service 087331
try_different_keys() {
Packit Service 087331
  # This run after sign_verify which leaves
Packit Service 087331
  # TYPE=evm and file is evm signed
Packit Service 087331
Packit Service 087331
  # v2 signing can work with multiple keys in --key option
Packit Service 087331
  if [[ ! $OPTS =~ --rsa ]]; then
Packit Service 087331
Packit Service 087331
    # Have correct key in the key list
Packit Service 087331
    expect_pass check_verify KEY="test-rsa2048.cer,$KEY"
Packit Service 087331
    expect_pass check_verify KEY="/dev/null,$KEY,"
Packit Service 087331
  fi
Packit Service 087331
Packit Service 087331
  # Try key that is not used for signing
Packit Service 087331
  expect_fail check_verify KEY=rsa2048
Packit Service 087331
Packit Service 087331
  # Try completely wrong key files
Packit Service 087331
  expect_fail check_verify KEY=/dev/null
Packit Service 087331
  expect_fail check_verify KEY=/dev/zero
Packit Service 087331
}
Packit Service 087331
Packit Service 087331
try_different_sigs() {
Packit Service 087331
  # TYPE=evm and file is evm signed
Packit Service 087331
Packit Service 087331
  # Test --imasig
Packit Service 087331
  if expect_pass check_sign OPTS="$OPTS --imasig"; then
Packit Service 087331
Packit Service 087331
    # Verify both evm and ima sigs
Packit Service 087331
    expect_pass check_verify
Packit Service 087331
    expect_pass check_verify TYPE=ima
Packit Service 087331
  fi
Packit Service 087331
Packit Service 087331
  # Test --imahash
Packit Service 087331
  if expect_pass check_sign OPTS="$OPTS --imahash"; then
Packit Service 087331
Packit Service 087331
    expect_pass check_verify
Packit Service 087331
Packit Service 087331
    # IMA hash is not verifiable by ima_verify
Packit Service 087331
    expect_fail check_verify TYPE=ima
Packit Service 087331
  fi
Packit Service 087331
Packit Service 087331
  # Test --portable
Packit Service 087331
  expect_pass check_sign OPTS="$OPTS --portable" PREFIX=0x05
Packit Service 087331
  # Cannot be verified for now, until that support is added to evmctl
Packit Service 087331
Packit Service 087331
  # Test -i (immutable)
Packit Service 087331
  expect_pass check_sign OPTS="$OPTS -i" PREFIX=0x0303
Packit Service 087331
  # Cannot be verified for now
Packit Service 087331
}
Packit Service 087331
Packit Service 087331
# Single test args: type key hash signature-prefix "evmctl-options"
Packit Service 087331
# sign_verify args:      key hash signature-prefix "evmctl-options"
Packit Service 087331
# Only single test can be prefixed with expect_{fail,pass}
Packit Service 087331
# `sign_verify' can not be prefixed with expect_{fail,pass} because
Packit Service 087331
# it runs multiple tests inside. See more tests there.
Packit Service 087331
# signature-prefix can contain `:K:' which will be resolved to keyid (v2 only)
Packit Service 087331
Packit Service 087331
## Test v1 signatures
Packit Service 087331
# Signature v1 only supports sha1 and sha256 so any other should fail
Packit Service 087331
expect_fail \
Packit Service 087331
  check_sign TYPE=ima KEY=rsa1024 ALG=md5 PREFIX=0x0301 OPTS=--rsa
Packit Service 087331
Packit Service 087331
sign_verify  rsa1024  sha1    0x0301 --rsa
Packit Service 087331
sign_verify  rsa1024  sha256  0x0301 --rsa
Packit Service 087331
  try_different_keys
Packit Service 087331
  try_different_sigs
Packit Service 087331
Packit Service 087331
## Test v2 signatures with RSA PKCS#1
Packit Service 087331
# List of allowed hashes much greater but not all are supported.
Packit Service 087331
sign_verify  rsa1024  md5     0x030201:K:0080
Packit Service 087331
sign_verify  rsa1024  sha1    0x030202:K:0080
Packit Service 087331
sign_verify  rsa1024  sha224  0x030207:K:0080
Packit Service 087331
sign_verify  rsa1024  sha256  0x030204:K:0080
Packit Service 087331
  try_different_keys
Packit Service 087331
  try_different_sigs
Packit Service 087331
sign_verify  rsa1024  sha384  0x030205:K:0080
Packit Service 087331
sign_verify  rsa1024  sha512  0x030206:K:0080
Packit Service 087331
sign_verify  rsa1024  rmd160  0x030203:K:0080
Packit Service 087331
Packit Service 087331
# Test v2 signatures with EC-RDSA
Packit Service 087331
_enable_gost_engine
Packit Service 087331
sign_verify  gost2012_256-A md_gost12_256 0x030212:K:0040
Packit Service 087331
sign_verify  gost2012_256-B md_gost12_256 0x030212:K:0040
Packit Service 087331
sign_verify  gost2012_256-C md_gost12_256 0x030212:K:0040
Packit Service 087331
sign_verify  gost2012_512-A md_gost12_512 0x030213:K:0080
Packit Service 087331
sign_verify  gost2012_512-B md_gost12_512 0x030213:K:0080
Packit Service 087331
# Test if signing with wrong key length does not work.
Packit Service 087331
expect_fail \
Packit Service 087331
  check_sign TYPE=ima KEY=gost2012_512-B ALG=md_gost12_256 PREFIX=0x0302 OPTS=
Packit Service 087331
expect_fail \
Packit Service 087331
  check_sign TYPE=ima KEY=gost2012_256-B ALG=md_gost12_512 PREFIX=0x0302 OPTS=
Packit Service 087331