diff --git a/README.md b/README.md index 5b2adac..d2a021c 100644 --- a/README.md +++ b/README.md @@ -1,17 +1,47 @@ # About This experimental set of scripts attempts to sign and repack Arch ISO for secure boot. -This script(s) requires the `archlinux-x86_64.iso` file to be in the same dir as the `steps.sh` file. +This script(s) requires the `archlinux-x86_64.iso` file to be in the same dir as the `make_sec_boot_iso.py` file. +Otherwise, it will be downloaded. Run: + ```bash -chmod +x ./steps.sh -./steps.sh +# pip install requests +python3 make_sec_boot_iso.py ``` ## Warning -This script(s) is a Work In Progress. You can use it at your own risk. +Use this script at your own risk. Author will NOT be responsible to damages caused not limited to loss of data, corrupted files and others. + +To be run inside an Arch distro. Preferrably, inside an Arch Virtual Machine. + +## Additional Steps + +Apart from building the secure boot supported ISO, you must enroll the `DER` file. This varies between PCs and distros. + +If you have `mokutils` installed on your distro, run: + +```bash +mokutil --import MOK.cer +``` + +where MOK.cer is the certificate file created by the script or otherwise. This command is to be run where the ISO is to be run. +Another way is to use the UEFI Firmware Interface. This varies between devices. Consult your manufacturer. + +## Additional Info + +If the `archlinux-x86_64.iso` file is not found, it will be downloaded. + +If any of `MOK.cer`, `MOK.crt` or `MOK.key` is NOT found, the script will create them with `openssl`. + +The script requires `requests` package from PyPI installed. Additionally, for the operations to be successful, the following packages must be installed: + +- shim-signed from AUR +- libisoburn from Arch REPO +- mtools from Arch REPO +- openssl from Arch REPO ## License diff --git a/make_sec_boot_iso.py b/make_sec_boot_iso.py new file mode 100644 index 0000000..a410282 --- /dev/null +++ b/make_sec_boot_iso.py @@ -0,0 +1,213 @@ +#!/usr/bin/python3 + +import os +import pathlib +import subprocess +import requests + +from shutil import copyfile + + +def is_arch_based(): + """Checks if the current OS is Arch-based using pacman. + + Returns: + True if the OS is likely Arch-based, False otherwise. + """ + + try: + subprocess.check_output(["pacman", "--version"]) + return True + except subprocess.CalledProcessError: + pass + + return False + + +def grab_iso(): + """ + Download Arch ISO + """ + url = "https://geo.mirror.pkgbuild.com/iso/2024.10.01/archlinux-x86_64.iso" + r = requests.get(url, allow_redirects=True) + f = open(url.split('/')[-1], 'wb') + f.write(r.content) + f.close() + + + +def extract_iso(): + """ + Extract the iso to get the bootloader, kernel and other required files. + """ + cmd = "osirrox -indev ../archlinux-x86_64.iso -extract_boot_images ./ -extract /EFI/BOOT/BOOTx64.EFI grubx64.efi -extract /shellx64.efi shellx64.efi -extract /arch/boot/x86_64/vmlinuz-linux vmlinuz-linux" + ret = subprocess.run(cmd, shell=True, capture_output=True) + if ret.returncode != 0: + print(f"Error: {ret.stderr.decode('utf-8')}") + exit(1) + cmd2 = "chmod +w *" + ret2 = subprocess.run(cmd2, shell=True, capture_output=True) + if ret2.returncode != 0: + print(f"Error: {ret2.stderr.decode('utf-8')}") + return 0 + + +def get_shim_bin(): + """ + Get the shim binaries from `shim-signed` + """ + cmd1 = "cp /usr/share/shim-signed/shimx64.efi BOOTx64.EFI" + cmd2 = "cp /usr/share/shim-signed/mmx64.efi ./" + + ret1 = subprocess.run(cmd1, shell=True, capture_output=True) + if ret1.returncode != 0: + print(f"Error: {ret1.stderr.decode('utf-8')}") + exit(1) + + ret2 = subprocess.run(cmd2, shell=True, capture_output=True) + if ret2.returncode != 0: + print(f"Error: {ret2.stderr.decode('utf-8')}") + exit(1) + + return 0 + + +def sign_with_sbsigntools(): + """ + Signs the extracted and copied files with MOK.crt file + """ + cmd1 = "sbsign --key MOK.key --cert MOK.crt --output grubx64.efi grubx64.efi" + cmd2 = "sbsign --key MOK.key --cert MOK.crt --output shellx64.efi shellx64.efi" + cmd3 = "sbsign --key MOK.key --cert MOK.crt --output vmlinuz-linux vmlinuz-linux" + + #### NOTE + #### The following two signatures MAY NOT BE REQUIRED as THEY ARE ALREADY SIGNED. + #### However, absence of the signature using the created MOK keys made the + #### Bootable USB to NOT SHOW UP on my device. + cmd4 = "sbsign --key ../MOK.key --cert MOK.crt --output BOOTx64.EFI BOOTx64.EFI" + cmd5 = "sbsign --key ../MOK.key --cert MOK.crt --output mmx64.efi mmx64.efi" + + ret1 = subprocess.run(cmd1, shell=True, capture_output=True) + if ret1.returncode != 0: + print(f"Error: {ret1.stderr.decode('utf-8')}") + exit(1) + else: + print(f"[INFO]: {ret1.stdout.decode('utf-8')}\n\n") + + ret2 = subprocess.run(cmd2, shell=True, capture_output=True) + if ret2.returncode != 0: + print(f"Error: {ret2.stderr.decode('utf-8')}") + exit(1) + else: + print(f"[INFO]: {ret2.stdout.decode('utf-8')}\n\n") + + ret3 = subprocess.run(cmd3, shell=True, capture_output=True) + if ret3.returncode != 0: + print(f"Error: {ret3.stderr.decode('utf-8')}") + exit(1) + else: + print(f"[INFO]: {ret3.stdout.decode('utf-8')}\n\n") + + ret4 = subprocess.run(cmd4, shell=True, capture_output=True) + if ret4.returncode != 0: + print(f"Error: {ret4.stderr.decode('utf-8')}") + exit(1) + else: + print(f"[INFO]: {ret4.stdout.decode('utf-8')}\n\n") + + ret5 = subprocess.run(cmd5, shell=True, capture_output=True) + if ret5.returncode != 0: + print(f"Error: {ret5.stderr.decode('utf-8')}") + exit(1) + else: + print(f"[INFO]: {ret5.stdout.decode('utf-8')}\n\n") + + return 0 + + +def copy_to_image(): + """ + Copy the signed stuff to be loaded into ISO + """ + cmd1 = "mcopy -D oO -i eltorito_img2_uefi.img vmlinuz-linux ::/arch/boot/x86_64/vmlinuz-linux" + cmd2 = "mcopy -D oO -i eltorito_img2_uefi.img MOK.cer shellx64.efi ::/" + cmd3 = "mcopy -D oO -i eltorito_img2_uefi.img BOOTx64.EFI grubx64.efi mmx64.efi ::/EFI/BOOT/" + + ret1 = subprocess.run(cmd1, shell=True, capture_output=True) + if ret1.returncode != 0: + print(f"Error: {ret1.stderr.decode('utf-8')}") + exit(1) + else: + print(f"[INFO]: {ret1.stdout.decode('utf-8')}\n\n") + + ret2 = subprocess.run(cmd2, shell=True, capture_output=True) + if ret2.returncode != 0: + print(f"Error: {ret2.stderr.decode('utf-8')}") + exit(1) + else: + print(f"[INFO]: {ret2.stdout.decode('utf-8')}\n\n") + + ret3 = subprocess.run(cmd3, shell=True, capture_output=True) + if ret3.returncode != 0: + print(f"Error: {ret3.stderr.decode('utf-8')}") + exit(1) + else: + print(f"[INFO]: {ret3.stdout.decode('utf-8')}\n\n") + + return 0 + + +def repack_iso(): + """ + Repack the ISO file. + """ + cmd = "xorriso -indev ../archlinux-x86_64.iso -outdev archlinux-secure-boot-shim-x86_64.iso -map vmlinuz-linux /arch/boot/x86_64/vmlinuz-linux -map_l ./ / shellx64.efi MOK.cer -- -map_l ./ /EFI/BOOT/ BOOTx64.EFI grubx64.efi mmx64.efi -- -boot_image any replay -append_partition 2 0xef eltorito_img2_uefi.img" + + ret = subprocess.run(cmd, shell=True, capture_output=True) + if ret.returncode != 0: + print(f"Error: {ret.stderr.decode('utf-8')}") + exit(1) + else: + print(f"[INFO]: {ret.stdout.decode('utf-8')}\n\n") + + return 0 + + +def create_mok_keys(): + cmd1 = 'openssl req -x509 -newkey rsa:2048 -keyout MOK.key -out MOK.crt -subj "/CN=Aero/"' # Replace Aero with your name! + cmd2 = "openssl x509 -in MOK.crt -out MOK.cer -outform DER" + + +if __name__ == '__main__': + if not is_arch_based(): + print("This is not an Arch based system. Exiting...") + exit(1) + + print("Arch or Arch based system found. Ensure you have the following packages installed:") + print("shim-signed - AUR") + print("libisoburn - REPO") + print("mtools - REPO") + + cwd = os.getcwd() + os.mkdir(f"{cwd}/archsec") + + if not pathlib.Path(f"{cwd}/archlinux-x86_64.iso").exists(): + grab_iso() + + if not (pathlib.Path(f"{cwd}/MOK.key").exists() or pathlib.Path(f"{cwd}/MOK.crt").exists() or pathlib.Path(f"{cwd}/MOK.cer").exists()): + create_mok_keys() + + os.chdir(f"{cwd}/archsec") + copyfile("../MOK.cer", './MOK.cer') + copyfile("../MOK.crt", './MOK.crt') + copyfile("../MOK.key", './MOK.key') + + extract_iso() + get_shim_bin() + sign_with_sbsigntools() + copy_to_image() + repack_iso() + + + print(f"Done... Check the iso file: archlinux-secure-boot-shim-x86_64.iso at: {cwd}/archsec") + os.chdir(cwd) diff --git a/steps.sh b/steps.sh deleted file mode 100644 index a7cb89e..0000000 --- a/steps.sh +++ /dev/null @@ -1,53 +0,0 @@ -#!/usr/bin/bash - -# This script requires the arch iso be the latest x86_64 iso -# and in the same dir as this script. -# Tools requried are not installed or covered. -# For starters, this scrip needs the following packages in fedora (I used f40 for this): -# openssl -# sbsigntools -# xorriso -# - -# Make a work dir and cd into it -mkdir work_dir -cd work_dir - -# Make machine owner key (MOK) -openssl req -newkey rsa:2048 -nodes -keyout MOK.key -new -x509 -sha256 -days 3650 -subj "/CN=my Machine Owner Key/" -out MOK.crt -openssl x509 -outform DER -in MOK.crt -out MOK.cer - -# Enroll key -# Varies between the tool... for fedora run: sudo mokutil --import mok.cer - -# Extract -osirrox -indev ../archlinux-x86_64.iso \ - -extract_boot_images ./ \ - -cpx /arch/boot/x86_64/vmlinuz-linux \ - /EFI/BOOT/BOOTx64.EFI \ - /EFI/BOOT/BOOTIA32.EFI \ - /shellx64.efi \ - /shellia32.efi ./ - -# Add w bit -chmod +w BOOTx64.EFI BOOTIA32.EFI shellx64.efi shellia32.efi vmlinuz-linux - -# Sign it -sbsign --key MOK.key --cert MOK.crt --output BOOTx64.EFI BOOTx64.EFI -sbsign --key MOK.key --cert MOK.crt --output BOOTIA32.EFI BOOTIA32.EFI -sbsign --key MOK.key --cert MOK.crt --output shellx64.efi shellx64.efi -sbsign --key MOK.key --cert MOK.crt --output shellia32.efi shellia32.efi -sbsign --key MOK.key --cert MOK.crt --output vmlinuz-linux vmlinuz-linux - -# Copy the binaries -mcopy -D oO -i eltorito_img2_uefi.img vmlinuz-linux ::/arch/boot/x86_64/vmlinuz-linux -mcopy -D oO -i eltorito_img2_uefi.img BOOTx64.EFI BOOTIA32.EFI ::/EFI/BOOT/ -mcopy -D oO -i eltorito_img2_uefi.img shellx64.efi shellia32.efi ::/ - -# Repack -xorriso -indev ../archlinux-x86_64.iso -outdev archlinux-secure-boot-x86_64.iso \ - -map vmlinuz-linux /arch/boot/x86_64/vmlinuz-linux \ - -map_l ./ /EFI/BOOT/ BOOTx64.EFI BOOTIA32.EFI -- \ - -map_l ./ / shellx64.efi shellia32.efi -- \ - -boot_image any replay \ - -append_partition 2 0xef eltorito_img2_uefi.img