Skip to content

Commit 0167f51

Browse files
authored
Merge pull request #10 from zarhus/secure-boot-exercises
docs: add secure boot verification
2 parents 8c9e84a + ba8c2f0 commit 0167f51

File tree

4 files changed

+1667
-0
lines changed

4 files changed

+1667
-0
lines changed
+342
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,342 @@
1+
#!/bin/bash
2+
3+
error_exit() {
4+
_error_msg="$1"
5+
echo "$_error_msg"
6+
exit 1
7+
}
8+
9+
error_check() {
10+
_error_code=$?
11+
_error_msg="$1"
12+
[ "$_error_code" -ne 0 ] && error_exit "$_error_msg : ($_error_code)"
13+
return 0
14+
}
15+
16+
check_using_pkg_mng() {
17+
# Get the distribution name
18+
distribution_name=$(lsb_release -is 2>/dev/null || cat /etc/*-release | grep '^ID=' | awk -F= '{print $2}' | tr -d '"')
19+
error_check "Cannot read information about distribution"
20+
21+
# Initialize the variable to an empty string
22+
PKG_MNG=""
23+
24+
# Map distribution names to package managers
25+
case "$distribution_name" in
26+
debian|ubuntu)
27+
PKG_MNG="apt"
28+
;;
29+
redhat|centos|fedora)
30+
PKG_MNG="dnf"
31+
;;
32+
arch)
33+
PKG_MNG="pacman"
34+
;;
35+
openbsd)
36+
PKG_MNG="pkg"
37+
;;
38+
gentoo)
39+
PKG_MNG="emerge"
40+
;;
41+
*)
42+
PKG_MNG="Unknown"
43+
;;
44+
esac
45+
46+
DISTRO=$distribution_name
47+
# Display the detected package manager or "Unknown" if none is detected
48+
if [ "$PKG_MNG" != "Unknown" ]; then
49+
echo "Detected Package Manager: $PKG_MNG"
50+
echo "Detected Distro: $DISTRO"
51+
else
52+
echo "Unknown Package Manager"
53+
exit 1
54+
fi
55+
}
56+
57+
install_deps() {
58+
local deps=(sbsigntools faketime)
59+
local deps_test=(sbsign faketime)
60+
local all_installed="y"
61+
62+
echo -n "checking dependencies: "
63+
for dependency in "${deps_test[@]}"; do
64+
echo -n "$dependency"
65+
if ! command -v "$dependency" >/dev/null; then
66+
echo -n "-"
67+
all_installed="n"
68+
else
69+
echo -n "+"
70+
fi
71+
echo -n ", "
72+
done
73+
echo ""
74+
75+
if [ $all_installed = "y" ]; then
76+
return
77+
fi
78+
79+
echo "Installing dependencies"
80+
check_using_pkg_mng
81+
82+
if [ $DISTRO == "arch" ]; then
83+
sudo $PKG_MNG -S "${deps[@]}" 2>&1
84+
error_check "Cannot install ${deps[*]}"
85+
else
86+
sudo $PKG_MNG install "${deps[@]}" 2>&1
87+
error_check "Cannot install ${deps[*]}"
88+
fi
89+
}
90+
91+
create_rsa_key() {
92+
algo=$1
93+
openssl req -new -x509 -newkey rsa:$algo -subj "/CN=3mdeb_test/" -keyout cert.key -out cert.crt -days 3650 -nodes -sha256 > /dev/null 2>&1
94+
error_check "Cannot create rsa key pair"
95+
openssl x509 -in cert.crt -outform der -out cert.der > /dev/null 2>&1
96+
error_check "Cannot create rsa der cert"
97+
}
98+
99+
create_ecdsa_key() {
100+
algo=$1
101+
openssl req -new -x509 -newkey ec -pkeyopt ec_paramgen_curve:P-$algo -subj "/CN=3mdeb_key/" -keyout cert.key -out cert.crt -days 3650 -nodes -sha256 > /dev/null 2>&1
102+
error_check "Cannot create ecdsa key pair"
103+
openssl base64 -d -in cert.crt -out cert.der > /dev/null 2>&1
104+
error_check "Cannot create ecdsa der cert"
105+
}
106+
107+
create_intermediate_key() {
108+
# generate two key pairs, make CSR
109+
openssl req -new -x509 -newkey rsa:2048 -subj "/CN=3mdeb_test/" -keyout cert.key -out cert.crt -days 3650 -nodes -sha256 > /dev/null 2>&1
110+
error_check "Cannot create rsa first key for intermediate"
111+
openssl req -new -x509 -newkey rsa:2048 -subj "/CN=3mdeb_test/" -keyout PK.key -out PK.crt -days 3650 -nodes -sha256 > /dev/null 2>&1
112+
error_check "Cannot create rsa first key for intermediate"
113+
openssl req -new -key cert.key -out cert.csr -subj "/C=PL/O=3mdeb" > /dev/null 2>&1
114+
error_check "Cannot create csr"
115+
# sign the CSR with the second key pair
116+
# its necessary to `touch cert.ext`, otherwise it says its not there
117+
touch cert.ext
118+
openssl x509 -req -in cert.csr -CA PK.crt -CAkey PK.key -out cert.crt -CAcreateserial -extfile cert.ext > /dev/null 2>&1
119+
error_check "Cannot sign csr"
120+
openssl x509 -in cert.crt -outform der -out cert.der > /dev/null 2>&1
121+
error_check "Cannot create der from signed cert"
122+
}
123+
124+
create_bad_format_key() {
125+
algo=$1
126+
openssl req -new -x509 -newkey rsa:$algo -subj "/CN=3mdeb_test/" -keyout cert.key -out cert.crt -days 3650 -nodes -sha256 > /dev/null 2>&1
127+
error_check "Cannot create rsa key pair"
128+
# here we copy .crt to .der to leave wrong format for BIOS menu
129+
cp cert.crt cert.der
130+
error_check "Cannot create fake cert.der"
131+
}
132+
133+
create_expired_cert() {
134+
faketime '10 days ago' openssl req -new -x509 -newkey rsa:2048 -subj "/CN=ExpiredCert/" -keyout cert.key -out cert.crt -days 10 -nodes -sha256 > /dev/null 2>&1
135+
error_check "Cannot create expired rsa key pair"
136+
openssl x509 -in cert.crt -outform der -out cert.der
137+
error_check "Cannot create expired rsa der cert"
138+
}
139+
140+
# Create FAT image containing everything in $FILES and create
141+
# `add-boot-options.sh` script
142+
create_iso() {
143+
IMAGELABEL="tests"
144+
IMAGEPATH="$TEMPDIR/$IMAGELABEL.img"
145+
local mounted=
146+
local dev=
147+
mounted="/run/media/$(whoami)/$IMAGELABEL"
148+
149+
dd if=/dev/zero of="$IMAGEPATH" bs=1M count=10 > /dev/null 2>&1
150+
error_check "Cannot create empty image file to store created certs and efi files"
151+
# Create GPT table and EFI partition
152+
fdisk "$IMAGEPATH" << EOF
153+
g
154+
n
155+
1
156+
157+
158+
t
159+
1
160+
w
161+
EOF
162+
error_check "fdisk failed"
163+
164+
dev=$(udisksctl loop-setup -f "$IMAGEPATH" | awk '{print substr($NF,1,length($NF)-1)}')
165+
error_check "udisksctl failed to create loop device"
166+
trap "udisksctl loop-delete -b $dev; cleanup" EXIT
167+
echo "Creating fat partition on ${dev}p1"
168+
sudo mkfs.fat -F 12 "${dev}p1" -n $IMAGELABEL > /dev/null 2>&1
169+
error_check "Cannot create fat partition"
170+
mounted=$(udisksctl mount -b "${dev}p1" | awk '{print $NF}')
171+
error_check "Cannot mount ${dev}p1"
172+
trap "umount $mounted; udisksctl loop-delete -b $dev; cleanup" EXIT
173+
174+
# create script that'll add all efi files to boot options
175+
cat << EOF >> "$FILES/add-boot-options.sh"
176+
#!/bin/bash
177+
178+
UUID=$(lsblk -no UUID "${dev}p1")
179+
PARTITION=\$(basename "\$(realpath "/dev/disk/by-uuid/\$UUID")")
180+
PARTITION_DEV=/dev/\$PARTITION
181+
DEV="/dev/\$(basename "\$(realpath /sys/class/block/\$PARTITION/..)")"
182+
TEMP_FILE=\$(mktemp -d)
183+
184+
mount \$PARTITION_DEV \$TEMP_FILE
185+
cd \$TEMP_FILE
186+
find SBO0* -name "*.efi" -exec \\
187+
efibootmgr --create --disk=\$DEV --label="{}" \\
188+
--loader="\$(echo "{}" | sed 's|/|\\\\|g')" \;
189+
EOF
190+
191+
cp -r "$FILES"/* "$mounted"
192+
error_check "Couldn't copy $FILES/ to $mounted"
193+
194+
trap 'cleanup' EXIT
195+
if ! umount "$mounted"; then
196+
udisksctl loop-delete -b "$dev"
197+
error_exit "Failed to umount $mounted"
198+
fi
199+
udisksctl loop-delete -b "$dev"
200+
error_check "Couldn't delete loop device $dev"
201+
}
202+
203+
# create_test <test_name> <sign_efi> <create_key_function> [args...]
204+
create_test() {
205+
local TEST=$1
206+
local SIGN="$2"
207+
shift 2
208+
mkdir "$TEST"
209+
210+
pushd "$TEST" >/dev/null || error_exit "Couldn't enter $TEST"
211+
212+
# call <create_key_function> [args...]
213+
"$@"
214+
error_check "$*: Couldn't create keys and certificate"
215+
if [ "$SIGN" = "y" ]; then
216+
sbsign --key cert.key --cert cert.crt --output "hello.efi" "$HELLO_EFI"
217+
error_check "Couldn't sign $HELLO_EFI"
218+
if [ ! -f "hello.efi" ]; then
219+
error_exit "Couldn't create signed $TEST/hello.efi"
220+
fi
221+
else
222+
cp "$HELLO_EFI" hello.efi
223+
fi
224+
# remove everything except "cert.der" and "hello.efi"
225+
find -maxdepth 1 -type f ! -name "cert.der" ! -name "hello.efi" -exec rm {} \;
226+
error_check "find error"
227+
228+
popd >/dev/null || error_exit "Couldn't popd"
229+
}
230+
231+
# create_provisioning_test <test_name>
232+
create_provisioning_test() {
233+
local TEST=$1
234+
local COMMIT=b2c2716c20afa76575b431e0a4cfd126e6df766f
235+
local DB_CRT_HASH=80aea212df9d1855e00251d80d1b384f9e7d7c48c4d6491f5a346dd52b3c2260
236+
local DB_KEY_HASH=da2bb57a51a7eb7f701c17d9f7e8ade7668fe204af5518e520580328f7e64231
237+
mkdir "$TEST"
238+
239+
pushd "$TEST" >/dev/null || error_exit "Couldn't enter $TEST"
240+
241+
wget https://raw.githubusercontent.com/Wind-River/meta-secure-core/$COMMIT/meta-signing-key/files/uefi_sb_keys/DB.crt
242+
wget https://raw.githubusercontent.com/Wind-River/meta-secure-core/$COMMIT/meta-signing-key/files/uefi_sb_keys/DB.key
243+
if ! diff <(sha256sum DB.crt) <(echo "$DB_CRT_HASH DB.crt") || \
244+
! diff <(sha256sum DB.key) <(echo "$DB_KEY_HASH DB.key")
245+
then
246+
error_exit "Wrong DB.crt/DB.key sha256 hash"
247+
fi
248+
cp "$SCRIPTDIR/LockDown.efi" .
249+
sbsign --key DB.key --cert DB.crt --output "hello.efi" "$HELLO_EFI"
250+
# remove everything except "LockDown.efi" and "hello.efi"
251+
find -maxdepth 1 -type f ! -name "LockDown.efi" ! -name "hello.efi" -exec rm {} \;
252+
253+
popd >/dev/null || error_exit "Couldn't popd"
254+
}
255+
256+
# create_provisioning_kek_test <test_name>
257+
create_provisioning_kek_test() {
258+
local TEST=$1
259+
local COMMIT=b2c2716c20afa76575b431e0a4cfd126e6df766f
260+
local KEK_CRT_HASH=1a67de100cfc909a1a84fc2444e8378a01fe1fecb2cd37a6b4634b10662a21d2
261+
mkdir "$TEST"
262+
263+
pushd "$TEST" >/dev/null || error_exit "Couldn't enter $TEST"
264+
265+
wget https://raw.githubusercontent.com/Wind-River/meta-secure-core/$COMMIT/meta-signing-key/files/uefi_sb_keys/KEK.crt
266+
if ! diff <(sha256sum KEK.crt) <(echo "$KEK_CRT_HASH KEK.crt"); then
267+
error_exit "Wrong KEK.crt sha256 hash"
268+
fi
269+
openssl x509 -fingerprint -in KEK.crt -noout -text > KEK2.crt
270+
mv KEK2.crt KEK.crt
271+
272+
popd >/dev/null || error_exit "Couldn't popd"
273+
}
274+
275+
cleanup() {
276+
echo "removing $TEMPDIR"
277+
rm -r "$TEMPDIR"
278+
}
279+
280+
parse_args() {
281+
positional_args=()
282+
while [[ $# -gt 0 ]]; do
283+
case $1 in
284+
-v|--verbose)
285+
set -x
286+
;;
287+
-*)
288+
print_usage
289+
error_exit "Unknown option $1"
290+
;;
291+
*)
292+
positional_args+=("$1")
293+
;;
294+
esac
295+
shift
296+
done
297+
}
298+
299+
print_usage() {
300+
echo "generate-image.sh [-v]"
301+
}
302+
303+
parse_args "$@"
304+
set -- "${positional_args[@]}"
305+
306+
if [ $# -ne 0 ]; then
307+
print_usage
308+
error_exit "Script doesn't accept positional arguments"
309+
fi
310+
311+
SCRIPTDIR=$(readlink -f "$(dirname "$0")")
312+
HELLO_EFI="$(realpath hello.efi)"
313+
314+
TEMPDIR=$(mktemp -d)
315+
trap "cleanup" EXIT
316+
317+
FILES="$TEMPDIR/files"
318+
mkdir "$FILES"
319+
pushd "$FILES" >/dev/null || error_check "Couldn't create $FILES"
320+
321+
install_deps
322+
323+
create_test SBO003.001 y create_rsa_key 2048
324+
create_test SBO004.001 n create_rsa_key 2048
325+
create_test SBO008.001 n create_bad_format_key 2048
326+
create_test SBO009.001 y create_intermediate_key
327+
create_test SBO010.001 y create_rsa_key 2048
328+
create_test SBO010.002 y create_rsa_key 3072
329+
create_test SBO010.003 y create_rsa_key 4096
330+
create_test SBO010.004 y create_ecdsa_key 256
331+
create_test SBO010.005 y create_ecdsa_key 384
332+
create_test SBO010.006 y create_ecdsa_key 521
333+
create_test SBO011.001 y create_expired_cert
334+
create_provisioning_test SBO013.001
335+
create_provisioning_kek_test SBO013.002
336+
337+
echo "creating iso image"
338+
create_iso
339+
cp "$IMAGEPATH" "$SCRIPTDIR"/
340+
error_check "Couldn't copy $IMAGELABEL.img to $SCRIPTDIR"
341+
echo "Done"
342+
popd >/dev/null || error_check "Couldn't go back to original directory"

0 commit comments

Comments
 (0)