1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181
|
#!/usr/bin/env bash
#
# Copyright (C) 2023-2024 Red Hat, Inc.
# This file is part of elfutils.
#
# This file 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 3 of the License, or
# (at your option) any later version.
#
# elfutils 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.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
. $srcdir/debuginfod-subr.sh
type rpmsign 2>/dev/null || { echo "need rpmsign"; exit 77; }
cat << EoF > include.c
#include <rpm/rpmlib.h>
#include <rpm/rpmfi.h>
#include <rpm/header.h>
#include <imaevm.h>
#include <openssl/evp.h>
EoF
tempfiles include.c
gcc -H -fsyntax-only include.c 2> /dev/null || { echo "one or more devel packages are missing (rpm-devel, ima-evm-utils-devel, openssl-devel)"; exit 77; }
set -x
export DEBUGINFOD_VERBOSE=1
DB=${PWD}/.debuginfod_tmp.sqlite
tempfiles $DB
export DEBUGINFOD_CACHE_PATH=${PWD}/.client_cache
IMA_POLICY="enforcing"
# This variable is essential and ensures no time-race for claiming ports occurs
# set base to a unique multiple of 100 not used in any other 'run-debuginfod-*' test
base=14000
get_ports
mkdir R
env LD_LIBRARY_PATH=$ldpath DEBUGINFOD_URLS= ${abs_builddir}/../debuginfod/debuginfod $VERBOSE -R \
-d $DB -p $PORT1 -t0 -g0 R > vlog$PORT1 2>&1 &
PID1=$!
tempfiles vlog$PORT1
errfiles vlog$PORT1
########################################################################
cp -pv ${abs_srcdir}/debuginfod-ima/rhel9/hello2-1.0-1.x86_64.rpm signed.rpm
tempfiles signed.rpm
RPM_BUILDID=460912dbc989106ec7325d243384df20c5ccec0c # /usr/local/bin/hello
MIN_IMAEVM_MAJ_VERSION=3
MIN_RPM_MAJ_VERSION=4
# If the correct programs (and versions) exist sign the rpm in the test
if false && \
(command -v openssl &> /dev/null) && \
(command -v rpmsign &> /dev/null) && \
(command -v gpg &> /dev/null) && \
[ $(ldd `which rpmsign` | grep libimaevm | awk -F'[^0-9]+' '{ print $2 }') -ge $MIN_IMAEVM_MAJ_VERSION ] && \
[ $(rpm --version | awk -F'[^0-9]+' '{ print $2 }') -ge $MIN_RPM_MAJ_VERSION ]
then
# SIGN THE RPM
# First remove any old signatures
rpmsign --delsign signed.rpm &> /dev/null
rpmsign --delfilesign signed.rpm &> /dev/null
# Make a gpg keypair (with $PWD as the homedir)
mkdir -m 700 openpgp-revocs.d private-keys-v1.d
gpg --quick-gen-key --yes --homedir ${PWD} --batch --passphrase '' --no-default-keyring --keyring "${PWD}/pubring.kbx" example@elfutils.org 2> /dev/null
# Create a private DER signing key and a public X509 DER format verification key pair
openssl genrsa | openssl pkcs8 -topk8 -nocrypt -outform PEM -out signing.pem
openssl req -x509 -key signing.pem -out imacert.pem -days 365 -keyform PEM \
-subj "/C=CA/ST=ON/L=TO/O=Elfutils/CN=www.sourceware.org\/elfutils"
tempfiles openpgp-revocs.d/* private-keys-v1.d/* * openpgp-revocs.d private-keys-v1.d
rpmsign --addsign --signfiles --fskpath=signing.pem -D "_gpg_name example@elfutils.org" -D "_gpg_path ${PWD}" signed.rpm
cp signed.rpm R/signed.rpm
VERIFICATION_CERT_DIR=${PWD}
# Cleanup
rm -rf openpgp-revocs.d private-keys-v1.d
else
# USE A PRESIGNED RPM
cp signed.rpm R/signed.rpm
# Note we test with no trailing /
VERIFICATION_CERT_DIR=${abs_srcdir}/debuginfod-ima/rhel9
fi
########################################################################
# Server must become ready with R fully scanned and indexed
wait_ready $PORT1 'ready' 1
wait_ready $PORT1 'thread_work_total{role="traverse"}' 1
wait_ready $PORT1 'thread_work_pending{role="scan"}' 0
wait_ready $PORT1 'thread_busy{role="scan"}' 0
export DEBUGINFOD_URLS="ima:$IMA_POLICY http://127.0.0.1:$PORT1"
echo Test 1: Without a certificate the verification should fail
export DEBUGINFOD_IMA_CERT_PATH=
RC=0
testrun ${abs_top_builddir}/debuginfod/debuginfod-find -vv executable $RPM_BUILDID || RC=1
test $RC -ne 0
echo Test 2: It should pass once the certificate is added to the path
export DEBUGINFOD_IMA_CERT_PATH=$VERIFICATION_CERT_DIR
rm -rf $DEBUGINFOD_CACHE_PATH # clean it from previous tests
kill -USR1 $PID1
wait_ready $PORT1 'thread_work_total{role="traverse"}' 2
wait_ready $PORT1 'thread_work_pending{role="scan"}' 0
wait_ready $PORT1 'thread_busy{role="scan"}' 0
testrun ${abs_top_builddir}/debuginfod/debuginfod-find -vv executable $RPM_BUILDID
echo Test 3: Corrupt the data and it should fail
dd if=/dev/zero of=R/signed.rpm bs=1 count=128 seek=1024 conv=notrunc
rm -rf $DEBUGINFOD_CACHE_PATH # clean it from previous tests
kill -USR1 $PID1
wait_ready $PORT1 'thread_work_total{role="traverse"}' 3
wait_ready $PORT1 'thread_work_pending{role="scan"}' 0
wait_ready $PORT1 'thread_busy{role="scan"}' 0
RC=0
testrun ${abs_top_builddir}/debuginfod/debuginfod-find executable $RPM_BUILDID || RC=1
test $RC -ne 0
echo Test 4: A rpm without a signature will fail
cp signed.rpm R/signed.rpm
rpmsign --delfilesign R/signed.rpm
rm -rf $DEBUGINFOD_CACHE_PATH # clean it from previous tests
kill -USR1 $PID1
wait_ready $PORT1 'thread_work_total{role="traverse"}' 4
wait_ready $PORT1 'thread_work_pending{role="scan"}' 0
wait_ready $PORT1 'thread_busy{role="scan"}' 0
RC=0
testrun ${abs_top_builddir}/debuginfod/debuginfod-find executable $RPM_BUILDID || RC=1
test $RC -ne 0
echo Test 5: Only tests 1,2 will result in extracted signature
[[ $(curl -s http://127.0.0.1:$PORT1/metrics | grep 'http_responses_total{extra="ima-sigs-extracted"}' | awk '{print $NF}') -eq 2 ]]
kill $PID1
wait $PID1
PID1=0
#######################################################################
# We also test the --koji-sigcache
cp -pR ${abs_srcdir}/debuginfod-ima/koji R/koji
rm -rf $DEBUGINFOD_CACHE_PATH # clean it from previous tests
env LD_LIBRARY_PATH=$ldpath DEBUGINFOD_URLS= ${abs_builddir}/../debuginfod/debuginfod $VERBOSE -R \
-d $DB -p $PORT2 -t0 -g0 -X /data/ --koji-sigcache R/koji > vlog$PORT1 2>&1 &
#reuse PID1
PID1=$!
tempfiles vlog$PORT2
errfiles vlog$PORT2
RPM_BUILDID=c592a95e45625d7891b90f6b86e63373d540461d #/usr/bin/hello
# Note we test with a trailing slash
VERIFICATION_CERT_DIR=/not/a/dir:${abs_srcdir}/debuginfod-ima/koji/
########################################################################
# Server must become ready with koji fully scanned and indexed
wait_ready $PORT2 'ready' 1
wait_ready $PORT2 'thread_work_total{role="traverse"}' 1
wait_ready $PORT2 'thread_work_pending{role="scan"}' 0
wait_ready $PORT2 'thread_busy{role="scan"}' 0
echo Test 6: The path should be properly mapped and verified using the actual fedora 38 cert
export DEBUGINFOD_URLS="ima:$IMA_POLICY http://127.0.0.1:$PORT2"
export DEBUGINFOD_IMA_CERT_PATH=$VERIFICATION_CERT_DIR
testrun ${abs_top_builddir}/debuginfod/debuginfod-find -vv executable $RPM_BUILDID
kill $PID1
wait $PID1
PID1=0
exit 0
|