src/compare_command.sh: detect change of IBG keys

Criteria:
 - key_manifest.bin files differ in part preceding their signatures and
   neither file is all zeroes
 - length of mismatched range within SI_ME is less than or equal 1024
   (may need to be revised if that grows)

Signed-off-by: Sergii Dmytruk <sergii.dmytruk@3mdeb.com>
This commit is contained in:
Sergii Dmytruk
2025-08-23 20:21:09 +03:00
parent 84b9dd5d05
commit 3924e8cf7d
2 changed files with 136 additions and 4 deletions
+68 -2
View File
@@ -293,6 +293,14 @@ romscope_compare_command() {
WORKDIR=/tmp/romscope
is_km_file() {
[ -f "$1" ] && ! cmp --quiet --bytes="$(stat --printf %s "$1")" /dev/zero "$1"
}
find_file() {
cat a/manifest b/manifest | cut -d ' ' -f 2 | grep -e "$1" | sort -u
}
main () {
if [ -e $WORKDIR ]; then
rm -r $WORKDIR
@@ -328,6 +336,59 @@ romscope_compare_command() {
done
popd > /dev/null
pushd $WORKDIR > /dev/null
ibg_key_change=0
extra_excludes=
km_file=$(find_file "regions/fmap/COREBOOT.cbfs/key_manifest.bin")
if [ -n "$km_file" ]; then
# Key Manifest has the following structure:
# 1. 12 bytes
# 2. 2 bytes specifying offset to KM's signature (OFFSET)
# 3. `OFFSET - 12` bytes that end with a list of hashes, including hash
# of BPM's public key
# 4. KM's signature
#
# 1-3 should be the same for identical keys unless some options have
# changed as well. 4 can differ for the same IBG key used twice.
#
# Not checking if b/ has a different key offset, as we'll be comparing
# offsets as well.
sig_offset=$(xxd -s12 -p -l2 "a/$km_file")
sig_offset=0x${sig_offset:2}${sig_offset:0:2}
is_km_a=$(is_km_file "a/$km_file"; echo $?)
is_km_b=$(is_km_file "b/$km_file"; echo $?)
if [ "$is_km_a" -ne 0 ] || [ "$is_km_b" -ne 0 ]; then
: Dealing with at least one unprovisioned image
elif cmp --quiet --bytes="$sig_offset" "a/$km_file" "b/$km_file"; then
echo "IBG keys match."
else
echo "IBG keys differ."
ibg_key_change=1
fi
# Avoiding reporting changes in these files if at least one image is
# IBG-enabled.
extra_excludes+=" -e regions/fmap/COREBOOT.cbfs/boot_policy_manifest.bin"
extra_excludes+=" -e regions/fmap/COREBOOT.cbfs/key_manifest.bin"
fi
si_me=$(find_file "regions/fmap/SI_ME.bin")
if [ -n "$si_me" ]; then
# Check if the length of a mismatched range is small enough to likely
# indicate a key change rather than an ME update. Resigning IBG-enabled
# binaries with the same IBG but different Vboot keys results results in
# changing ME as well, hence this is not predicated on $ibg_key_change.
#
# `cmp -l` lists mismatching offsets and byte values, the length is
# computed as difference between the last and first offsets plus one.
# The threshold may need to be updated in the future.
if [ "$(cmp -l "a/$si_me" "b/$si_me" | wc -l)" -le 1024 ]; then
# Avoid reporting ME as modified in this case.
extra_excludes+=" -e regions/fmap/SI_ME.bin"
fi
fi
popd > /dev/null
pushd $WORKDIR > /dev/null
files=$(cat a/manifest b/manifest \
| cut -d ' ' -f 2 \
@@ -338,6 +399,7 @@ romscope_compare_command() {
-e "regions/fmap/VBLOCK_B.bin" \
-e "regions/fmap/GBB.bin" \
-e "regions/ifd/flashregion" \
$extra_excludes \
| sort -u
)
files_match=1
@@ -373,11 +435,15 @@ romscope_compare_command() {
done
popd > /dev/null
if [ "$ibg_key_change" -eq 1 ]; then
echo "Binaries are provisioned with different IBG keys."
fi
if [ $files_match -eq 1 ]; then
if [ $vblocks_match -ne 1 ]; then
echo "Files match but signatures differ. Binaries are likely signed using different Vboot keys."
echo "Files match but Vboot signatures differ. Binaries are likely signed using different Vboot keys."
else
echo "All signatures match."
echo "No file differences were detected."
fi
else
echo "Not all files match. Check report for detailed information."
+68 -2
View File
@@ -8,6 +8,14 @@ OUTPUT_DIR="${args[output]}"
WORKDIR=/tmp/romscope
is_km_file() {
[ -f "$1" ] && ! cmp --quiet --bytes="$(stat --printf %s "$1")" /dev/zero "$1"
}
find_file() {
cat a/manifest b/manifest | cut -d ' ' -f 2 | grep -e "$1" | sort -u
}
main () {
if [ -e $WORKDIR ]; then
rm -r $WORKDIR
@@ -43,6 +51,59 @@ main () {
done
popd > /dev/null
pushd $WORKDIR > /dev/null
ibg_key_change=0
extra_excludes=
km_file=$(find_file "regions/fmap/COREBOOT.cbfs/key_manifest.bin")
if [ -n "$km_file" ]; then
# Key Manifest has the following structure:
# 1. 12 bytes
# 2. 2 bytes specifying offset to KM's signature (OFFSET)
# 3. `OFFSET - 12` bytes that end with a list of hashes, including hash
# of BPM's public key
# 4. KM's signature
#
# 1-3 should be the same for identical keys unless some options have
# changed as well. 4 can differ for the same IBG key used twice.
#
# Not checking if b/ has a different key offset, as we'll be comparing
# offsets as well.
sig_offset=$(xxd -s12 -p -l2 "a/$km_file")
sig_offset=0x${sig_offset:2}${sig_offset:0:2}
is_km_a=$(is_km_file "a/$km_file"; echo $?)
is_km_b=$(is_km_file "b/$km_file"; echo $?)
if [ "$is_km_a" -ne 0 ] || [ "$is_km_b" -ne 0 ]; then
: Dealing with at least one unprovisioned image
elif cmp --quiet --bytes="$sig_offset" "a/$km_file" "b/$km_file"; then
echo "IBG keys match."
else
echo "IBG keys differ."
ibg_key_change=1
fi
# Avoiding reporting changes in these files if at least one image is
# IBG-enabled.
extra_excludes+=" -e regions/fmap/COREBOOT.cbfs/boot_policy_manifest.bin"
extra_excludes+=" -e regions/fmap/COREBOOT.cbfs/key_manifest.bin"
fi
si_me=$(find_file "regions/fmap/SI_ME.bin")
if [ -n "$si_me" ]; then
# Check if the length of a mismatched range is small enough to likely
# indicate a key change rather than an ME update. Resigning IBG-enabled
# binaries with the same IBG but different Vboot keys results results in
# changing ME as well, hence this is not predicated on $ibg_key_change.
#
# `cmp -l` lists mismatching offsets and byte values, the length is
# computed as difference between the last and first offsets plus one.
# The threshold may need to be updated in the future.
if [ "$(cmp -l "a/$si_me" "b/$si_me" | wc -l)" -le 1024 ]; then
# Avoid reporting ME as modified in this case.
extra_excludes+=" -e regions/fmap/SI_ME.bin"
fi
fi
popd > /dev/null
pushd $WORKDIR > /dev/null
files=$(cat a/manifest b/manifest \
| cut -d ' ' -f 2 \
@@ -53,6 +114,7 @@ main () {
-e "regions/fmap/VBLOCK_B.bin" \
-e "regions/fmap/GBB.bin" \
-e "regions/ifd/flashregion" \
$extra_excludes \
| sort -u
)
files_match=1
@@ -88,11 +150,15 @@ main () {
done
popd > /dev/null
if [ "$ibg_key_change" -eq 1 ]; then
echo "Binaries are provisioned with different IBG keys."
fi
if [ $files_match -eq 1 ]; then
if [ $vblocks_match -ne 1 ]; then
echo "Files match but signatures differ. Binaries are likely signed using different Vboot keys."
echo "Files match but Vboot signatures differ. Binaries are likely signed using different Vboot keys."
else
echo "All signatures match."
echo "No file differences were detected."
fi
else
echo "Not all files match. Check report for detailed information."