forked from kmille/cryptboot
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcryptboot-efikeys
More file actions
executable file
·378 lines (347 loc) · 14.6 KB
/
cryptboot-efikeys
File metadata and controls
executable file
·378 lines (347 loc) · 14.6 KB
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
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
#!/usr/bin/env bash
###
# File: cryptboot-efikeys
# Author: Leopold Johannes Meinel (leo@meinel.dev)
# -----
# Copyright (c) 2025 Leopold Johannes Meinel & contributors
# SPDX ID: GPL-3.0-only
# URL: https://www.gnu.org/licenses/gpl-3.0
# -----
###
# Fail on error
set -e
# Define functions
log_err() {
/usr/bin/logger -s -p local0.err <<<"$(basename "${0}"): ${*}"
}
log_warning() {
/usr/bin/logger -s -p local0.warning <<<"$(basename "${0}"): ${*}"
}
check_arg() {
if [[ -z "${2}" ]]; then
log_err "You have to specify '[${1}]' as second argument."
exit 1
fi
}
checked_cd() {
cd "${1:?}" ||
{
log_err "Could not 'cd' into '${1:?}'"
exit 1
}
}
exit_no_keys() {
log_err "There are no UEFI Secure Boot keys in '${1:?}'."
log_err "Please generate them first with '${2} create' and then enroll them with '${2} enroll'."
exit 1
}
var_invalid_err_exit() {
log_err "'${1}' is invalid in '${2}'."
exit 1
}
var_invalid_warning() {
log_warning "'${1}' is invalid in '${2}'."
}
# Default path for cryptboot.conf
CONFIGURATION_FILE=/etc/cryptboot.conf
# UEFI Secure Boot keys directory
EFI_KEYS_DIR=/etc/secureboot
# Option ROM
## See: https://github.com/Foxboron/sbctl/wiki/FAQ#option-rom
## Setting ENABLE_OPROM="false" might soft brick your device. Make sure that your hardware doesn't need oproms
## If you plan on changing this setting after enrolling, you will have to issue the following commands again:
## cryptboot-efikeys create
## cryptboot-efikeys enroll [PK.key] [KEK.key]
## cryptboot systemd-boot-sign
ENABLE_OPROM="true"
# Source config
if [[ -f "${CONFIGURATION_FILE}" ]]; then
# shellcheck source=/dev/null
. "${CONFIGURATION_FILE}"
else
log_err "'${CONFIGURATION_FILE}' doesn't exist."
exit 1
fi
# Create UEFI Secure Boot keys directory
mkdir -p "${EFI_KEYS_DIR:?}"/keys
chmod 700 "${EFI_KEYS_DIR:?}"/keys
mkdir -p "${EFI_KEYS_DIR:?}"/backup/keys
chmod 700 "${EFI_KEYS_DIR:?}"/backup/keys
# Check if user is root
if [[ "${UID}" -ne 0 ]]; then
log_err "You can only run this script as root."
exit 1
fi
case "${1}" in
"create")
# cd to EFI_KEYS_DIR/keys
checked_cd "${EFI_KEYS_DIR:?}/keys"
# Prompt to confirm erasure of UEFI Secure Boot keys in EFI_KEYS_DIR/keys
for file in "${EFI_KEYS_DIR:?}"/keys/*; do
[[ -f "${file}" ]] ||
{
var_invalid_warning "${file}" "${EFI_KEYS_DIR:?}/keys/*"
continue
}
DATE="$(date +"%FT%H-%M-%S")"
BACKUP_PATH="${EFI_KEYS_DIR:?}"/backup/keys/"${DATE}".bak
log_warning "UEFI Secure Boot keys in '${EFI_KEYS_DIR:?}/keys' already exists."
log_warning "A backup will be created at '${BACKUP_PATH:?}'."
read -rp "Do you want to delete them and generate new ones? (Type 'yes' in capital letters): " choice
case "${choice}" in
"YES")
cp -R "${EFI_KEYS_DIR:?}"/keys "${BACKUP_PATH:?}"
chmod 000 "${BACKUP_PATH:?}"/*
rm -rf "${EFI_KEYS_DIR:?}"/keys/*
;;
*)
log_err "User aborted generating secureboot keys."
exit 1
;;
esac
break
done
echo "Creating new UEFI Secure Boot keys..."
# Prompt for common name and save to ./NAME
read -rp "Enter a Common Name: " NAME
echo "${NAME}" >NAME
# Generate PEM format private keys for EFI binary and EFI signature list signing and PEM format certificates for sbsign(1), sbvarsign(1) and sign-efi-sig-list(1) -> .key, .crt
# See: https://wiki.archlinux.org/title/Unified_Extensible_Firmware_Interface/Secure_Boot#Creating_keys
openssl req -newkey rsa:4096 -nodes -keyout ./PK.key -new -x509 -sha256 -days 3650 -subj "/CN=${NAME} PK/" -out ./PK.crt
openssl req -newkey rsa:4096 -nodes -keyout ./KEK.key -new -x509 -sha256 -days 3650 -subj "/CN=${NAME} KEK/" -out ./KEK.crt
openssl req -newkey rsa:4096 -nodes -keyout ./db.key -new -x509 -sha256 -days 3650 -subj "/CN=${NAME} db/" -out ./db.crt
# Generate DER format certificates for firmware -> .cer
# See: https://wiki.archlinux.org/title/Unified_Extensible_Firmware_Interface/Secure_Boot#Creating_keys
openssl x509 -outform DER -in ./PK.crt -out ./PK.cer
openssl x509 -outform DER -in ./KEK.crt -out ./KEK.cer
openssl x509 -outform DER -in ./db.crt -out ./db.cer
# Create a GUID for owner identification
# See: https://wiki.archlinux.org/title/Unified_Extensible_Firmware_Interface/Secure_Boot#Creating_keys
GUID="$(uuidgen --random)"
echo "${GUID}" >./GUID
# Generate Certificates in an EFI Signature List for sbvarsign(1), efi-updatevar(1), KeyTool and firmware -> .esl
# See: https://wiki.archlinux.org/title/Unified_Extensible_Firmware_Interface/Secure_Boot#Creating_keys
cert-to-efi-sig-list -g "${GUID}" ./PK.crt ./PK.esl
cert-to-efi-sig-list -g "${GUID}" ./KEK.crt ./KEK.esl
cert-to-efi-sig-list -g "${GUID}" ./db.crt ./db.esl
# Obtain MS_cert_bundle_db.esl
if [[ "${ENABLE_OPROM}" == "true" ]]; then
## Save MSGUID
MSGUID="77fa9abd-0359-4d32-bd60-28f4e78f784b"
echo "${MSGUID}" >./MSGUID
## curl PEM format certificates for sbsign(1), sbvarsign(1) and sign-efi-sig-list(1) -> .crt
curl -Ls https://go.microsoft.com/fwlink/p/?linkid=321194 >./Microsoft_Corporation_UEFI_CA_2011.crt
curl -Ls https://go.microsoft.com/fwlink/?linkid=2239872 >./Microsoft_UEFI_CA_2023.crt
curl -Ls https://go.microsoft.com/fwlink/?linkid=2284009 >./Microsoft_Option_ROM_UEFI_CA_2023.crt
SHA1SUMS="$(
cat <<'EOF'
46def63b5ce61cf8ba0de2e6639c1019d0ed14f3 ./Microsoft_Corporation_UEFI_CA_2011.crt
3fb39e2b8bd183bf9e4594e72183ca60afcd4277 ./Microsoft_Option_ROM_UEFI_CA_2023.crt
b5eeb4a6706048073f0ed296e7f580a790b59eaa ./Microsoft_UEFI_CA_2023.crt
EOF
)"
SHA256SUMS="$(
cat <<'EOF'
48e99b991f57fc52f76149599bff0a58c47154229b9f8d603ac40d3500248507 ./Microsoft_Corporation_UEFI_CA_2011.crt
e5be3e64c6e66a281457ecdece0d6d0787577aad2a3a0144262c10c14ba8d8f1 ./Microsoft_Option_ROM_UEFI_CA_2023.crt
f6124e34125bee3fe6d79a574eaa7b91c0e7bd9d929c1a321178efd611dad901 ./Microsoft_UEFI_CA_2023.crt
EOF
)"
sha1sum -c <<<"${SHA1SUMS}" ||
{
log_err "Could not verify checksums for MS certs with 'sha1sum'."
exit 1
}
sha256sum -c <<<"${SHA256SUMS}" ||
{
log_err "Could not verify checksums for MS certs with 'sha256sum'."
exit 1
}
## Create EFI Signature List for sbvarsign(1), efi-updatevar(1), KeyTool and firmware -> .esl
## See: https://wiki.archlinux.org/title/Unified_Extensible_Firmware_Interface/Secure_Boot#Creating_keys
sbsiglist --owner "${MSGUID}" --type x509 --output ./Microsoft_Corporation_UEFI_CA_2011.esl ./Microsoft_Corporation_UEFI_CA_2011.crt
sbsiglist --owner "${MSGUID}" --type x509 --output ./Microsoft_Option_ROM_UEFI_CA_2023.esl ./Microsoft_Option_ROM_UEFI_CA_2023.crt
sbsiglist --owner "${MSGUID}" --type x509 --output ./Microsoft_UEFI_CA_2023.esl ./Microsoft_UEFI_CA_2023.crt
cat ./Microsoft_Corporation_UEFI_CA_2011.esl ./Microsoft_Option_ROM_UEFI_CA_2023.esl ./Microsoft_UEFI_CA_2023.esl >./MS_cert_bundle_db.esl
fi
# Generate Certificates in an EFI Signature List with an authentication header (i.e. a signed certificate update file) for efi-updatevar(1), sbkeysync, KeyTool and firmware -> .auth
# See: https://wiki.archlinux.org/title/Unified_Extensible_Firmware_Interface/Secure_Boot#Creating_keys
sign-efi-sig-list -g "${GUID}" -k ./PK.key -c ./PK.crt PK ./PK.esl ./PK.auth
## Sign an empty file to allow removing Platform Key when in "User Mode"
## See: https://wiki.archlinux.org/title/Unified_Extensible_Firmware_Interface/Secure_Boot#Creating_keys
sign-efi-sig-list -g "${GUID}" -k ./PK.key -c ./PK.crt PK /dev/null ./PK_null.auth
sign-efi-sig-list -g "${GUID}" -k ./PK.key -c ./PK.crt KEK ./KEK.esl ./KEK.auth
sign-efi-sig-list -g "${GUID}" -k ./KEK.key -c ./KEK.crt db ./db.esl ./db.auth
# Generate Certificates in an EFI Signature List for MS_cert_bundle_db
if [[ "${ENABLE_OPROM}" == "true" ]]; then
## Generate Certificates in an EFI Signature List with an authentication header (i.e. a signed certificate update file) for efi-updatevar(1), sbkeysync, KeyTool and firmware -> .auth
## See: https://wiki.archlinux.org/title/Unified_Extensible_Firmware_Interface/Secure_Boot#Creating_keys
sign-efi-sig-list -g "${MSGUID}" -k ./KEK.key -c ./KEK.crt db ./MS_cert_bundle_db.esl ./MS_cert_bundle_db.auth
fi
# chmod EFI_KEYS_DIR/keys/*
chmod 000 "${EFI_KEYS_DIR:?}"/keys/*
# Synchronize cached writes to persistent storage
sync
# Notify user if script has finished successfully
echo "New UEFI Secure Boot keys created in '${EFI_KEYS_DIR:?}/keys'."
;;
"enroll")
read -rp "Do you understand that this can brick your device? Aborting now leaves secureboot disabled. (Type 'yes i understand' in capital letters): " choice
case "${choice}" in
"YES I UNDERSTAND")
echo "Enrolling UEFI Secure Boot keys..."
;;
*)
log_err "User aborted enrolling secureboot keys."
exit 1
;;
esac
# cd to EFI_KEYS_DIR/keys and check arguments
checked_cd "${EFI_KEYS_DIR:?}/keys"
PK="${2}"
KEK="${3}"
check_arg "PK.key" "${PK}"
check_arg "KEK.key" "${KEK}"
# Check for keys
if [[ "${ENABLE_OPROM}" == "true" ]]; then
if ! [[ -f ./KEK.auth ]] || ! [[ -f ./db.auth ]] || ! [[ -f ./PK.auth ]] || ! [[ -f ./MS_cert_bundle_db.auth ]]; then
exit_no_keys "${EFI_KEYS_DIR:?}/keys" "${0}"
fi
else
if ! [[ -f ./KEK.auth ]] || ! [[ -f ./db.auth ]] || ! [[ -f ./PK.auth ]]; then
exit_no_keys "${EFI_KEYS_DIR:?}/keys" "${0}"
fi
fi
# Enroll KEK.auth and db.auth
## Change file attributes
for file in /sys/firmware/efi/efivars/PK*; do
[[ -f "${file}" ]] ||
{
var_invalid_warning "${file}" "/sys/firmware/efi/efivars/PK*"
continue
}
chattr -i "${file}" || true
done
for file in /sys/firmware/efi/efivars/KEK*; do
[[ -f "${file}" ]] ||
{
var_invalid_warning "${file}" "/sys/firmware/efi/efivars/KEK*"
continue
}
chattr -i "${file}" || true
done
for file in /sys/firmware/efi/efivars/db*; do
[[ -f "${file}" ]] ||
{
var_invalid_warning "${file}" "/sys/firmware/efi/efivars/db*"
continue
}
chattr -i "${file}" || true
done
## Reset system to setup mode
efi-updatevar -d 0 -k "${PK}" PK || true
## Enroll
echo "Enrolling UEFI Secure Boot KEK.auth..."
efi-updatevar -k "${PK}" -f ./KEK.auth KEK
echo "Enrolling UEFI Secure Boot db.auth..."
efi-updatevar -k "${KEK}" -f ./db.auth db
# Enroll MS_cert_bundle_db.auth
if [[ "${ENABLE_OPROM}" == "true" ]]; then
## Change file attributes
for file in /sys/firmware/efi/efivars/db*; do
[[ -f "${file}" ]] ||
{
var_invalid_warning "${file}" "/sys/firmware/efi/efivars/db*"
continue
}
chattr -i "${file}" || true
done
## Enroll
echo "Enrolling UEFI Secure Boot MS_cert_bundle_db.auth..."
efi-updatevar -k "${KEK}" -a -f ./MS_cert_bundle_db.auth db
fi
# Enroll PK.auth
echo "Enrolling UEFI Secure Boot PK.auth..."
efi-updatevar -k "${PK}" -f ./PK.auth PK
# Notify user if script has finished successfully
echo "UEFI Secure Boot keys in '${EFI_KEYS_DIR:?}/keys' enrolled to UEFI firmware."
echo "You should now sign your boot loader and reboot."
;;
"sign")
# cd to EFI_KEYS_DIR/keys and check arguments
checked_cd "${EFI_KEYS_DIR:?}/keys"
FILENAME="${2}"
check_arg "file" "${FILENAME}"
# Check for keys
if ! [[ -f ./db.key ]] || ! [[ -f ./db.crt ]]; then
exit_no_keys "${EFI_KEYS_DIR:?}/keys" "${0}"
fi
# Sign valid files included in FILENAME
for file in ${FILENAME}; do
[[ -f "${file}" ]] ||
var_invalid_err_exit "${file}" "${FILENAME}"
# Sign file
sbverify --cert ./db.crt "${file}" ||
{
echo "Signing file '${file}' with UEFI Secure Boot keys..."
sbsign --key ./db.key --cert ./db.crt --output "${file}" "${file}"
}
done
# Synchronize cached writes to persistent storage
sync
;;
"verify")
# cd to EFI_KEYS_DIR/keys and check arguments
checked_cd "${EFI_KEYS_DIR:?}/keys"
FILENAME="${2}"
check_arg "file" "${FILENAME}"
# Check for keys
if ! [[ -f ./db.crt ]]; then
exit_no_keys "${EFI_KEYS_DIR:?}/keys" "${0}"
fi
# Verify valid files included in FILENAME
for file in ${FILENAME}; do
[[ -f "${file}" ]] ||
var_invalid_err_exit "${file}" "${FILENAME}"
# List signatures in FILENAME
echo "List of all signatures in '${file}':"
sbverify --list "${file}"
echo ""
# Verify FILENAME
echo "Verifying signature with UEFI Secure Boot keys..."
sbverify --cert ./db.crt "${file}"
done
;;
"list")
# List all UEFI Secure Boot keys enrolled in your UEFI firmware
echo "All UEFI Secure Boot keys enrolled in your UEFI firmware:"
efi-readvar
;;
"status")
# Check if UEFI Secure Boot is active or inactive
echo -n "UEFI Secure Boot status: "
SECUREBOOT_ENABLED="$(od -An -t u1 --read-bytes=1 --skip-bytes=4 /sys/firmware/efi/efivars/SecureBoot-*)"
if ! [[ "${SECUREBOOT_ENABLED}" -eq 1 ]]; then
echo "INACTIVE"
exit 1
fi
echo "ACTIVE"
;;
*)
# Print help
echo "Usage: $(basename "${0}") {create,list,status}"
echo " $(basename "${0}") {enroll} [PK.key] [KEK.key]"
echo " $(basename "${0}") {sign,verify} [file]"
echo ""
echo "Manage UEFI Secure Boot keys"
echo ""
echo "Commands:"
echo " create Generate new UEFI Secure Boot keys"
echo " enroll Enroll new UEFI Secure Boot keys to your UEFI firmware"
echo " (you have to clear old keys in your UEFI firmware setup utility first)"
echo " sign Sign EFI boot image file with your UEFI Secure Boot keys"
echo " verify Verify signature of EFI boot image file with your UEFI Secure Boot keys"
echo " list List all UEFI Secure Boot keys enrolled in your UEFI firmware"
echo " status Check if UEFI Secure Boot is active or inactive"
;;
esac