linuxboot / heads

A minimal Linux that runs as a coreboot or LinuxBoot ROM payload to provide a secure, flexible boot environment for laptops, workstations and servers.
https://osresearch.net/
GNU General Public License v2.0
1.41k stars 186 forks source link

ISO signing GUI #1438

Open JonathonHall-Purism opened 1 year ago

JonathonHall-Purism commented 1 year ago

We could have a "signing GUI" to sign an ISO with your key. Potentially this could also allow configuring which OS keys (if any) are trusted for ISO signatures, which integrates nicely with Restricted Boot.

Ideally, this should verify the ISO against sha256sums on the device while signing, or otherwise present the sha256 to the user for verification.

Original discussion: https://github.com/osresearch/heads/pull/1419#discussion_r1258631584

tlaurion commented 1 year ago

Some considerations. OSes are now providing hashes in separated file be be checked upon. Historically, fedora was providing detached gpg signatures and stopped doing that, providing detached signatures of hashes instead.

To me, providing gpg detached signature does both steps in one which was better, but OSes slowly stopped doing that.

I will have to gather notes on that and replicate but i remember some kind if issue with busybox trying to support the alternative detached signed hash approach vs detach signing iso directly for user to be able to simply use hash file being signed.

Just to note that providing hashes confirmation to the user to visually verify integrity and manually detach signing ISO requires two times processing ISO which are nomally big files.

If going in that direction we might as well try to support validation against OSes provided digests and hack around busybox limitations, while detached signatures still provide authenticity and integrity validation.

Distributions just now prefer to detach sign digests instead, which are smaller to verify instead of detach verifying against gpg, only because gpg was harder for users to verify, as opposed to sha256sum file that can visually be verified by the user. So detached signature validation is quicker verifying signature on hash file, exiting fast if bad, and then verify against the hash file.

tlaurion commented 1 year ago

@JonathonHall-Purism i don't seem to find a hack to have gnupg output contain the 256sum calculated and be able to just prompt the user to confirm hash is as expected prior of accept created detached signature (otherwise deleting created detached signature at this point).

That would be ideal but haven't found a way. Ideas?

For some reason this doesn't work gpg --print-md SHA256 --detach-sig --output data.txt.sig data.txt > sha256sum.txt

JonathonHall-Purism commented 1 year ago

@tlaurion It seems like what we really want here would be:

  1. hash the ISO
  2. ask user if the hash is correct
  3. If so, detach sign with the hash already computed

But there's no way to do step 3, as far as I can tell - there's no way to have GPG create a signature for an already-known digest, it wants to digest the file itself.

In theory maybe that could be added to GPG? Not sure though. Otherwise, only options I can think of:

  1. Hash the ISO, then sign the hash file (a la SHA256SUMS) instead of signing the ISO directly - I don't love the extra level of indirection, but maybe this is why ISO signatures are often published this way?
  2. Sign the ISO, then somehow dump the hash from the signature (it's in there). GPG doesn't seem to support this as-is either - --list-packets on a signature unhelpfully abbreviates the digest as begin of digest cd a3 (and doc says --list-packets is not considered a stable interface). I don't love creating a signature that we might throw away either.
  3. Accept the amount of time it takes to hash these ISOs and let GPG be happy repeating the digest :-/

BTW, your command above doesn't work because --print-md and --detach-sign are both commands, you can only use one command at a time.

tlaurion commented 1 year ago

Sign the ISO, then somehow dump the hash from the signature (it's in there). GPG doesn't seem to support this as-is either - --list-packets on a signature unhelpfully abbreviates the digest as begin of digest cd a3 (and doc says --list-packets is not considered a stable interface). I don't love creating a signature that we might throw away either.

This is actually the other way I dog down.

One option is to use the --debug 1024 option when you sign the file. This will write debugging data to STDOUT and show you the line containing the text SETHASH. This will be followed by the hash algorithm ID (8 for SHA256) a space, then the full hash.

Dismissing the detached signature file seems the way to go in the sense that the hash is computed prior of signing so that output could be shown to the user for him to visually verify against hash files that sit alongside iso downloaded or can be compared visually on the host computer where the file was outputted.

Not to be confused with supporting what other OSes are doing right now, which is to produce hashes and detached signatures of those hash files. That would deserve another issue.

Tldr: the goal here would be to not hash two times the same file but once and producing hash to be outputted to screen to the user for the user to verify it visually prior of accepting the created detach signature, which is personal authenticity mark against manual integrity check.

@JonathonHall-Purism you wouldn't consider accepting such implementation if implemented?

tlaurion commented 1 year ago

@JonathonHall-Purism cannot do it that way. The debug info contains hash of iso +signature related bits which don't match sha256sum output for same file.

What we could do is try generating sha256sum files for iso and when confirmed by user detach sign the hash file and modify iso verification code to take into account presence of such hash files alongside iso.

JonathonHall-Purism commented 1 year ago

What we could do is try generating sha256sum files for iso and when confirmed by user detach sign the hash file and modify iso verification code to take into account presence of such hash files alongside iso.

Yeah, based on what we both found this seems like the path of least resistance.

tlaurion commented 1 year ago

Also supporting what other OS distributions switched to would be nice in the same effort

See https://github.com/osresearch/heads/issues/1320#issuecomment-1722304791_ and next posts

tlaurion commented 1 year ago

Something like this could cover it all.

#!/bin/bash
# verify-or-sign.sh: Verify or create a hash file and a detached signature for an iso file

# Source the /etc/functions file to use the die function
. /etc/functions

# Check if an iso file is provided as an argument
if [ $# -ne 1 ]; then
    die "Usage: $0 ISO"
fi

# Check if the iso file provided exists using test command
if [ ! -f $1 ]; then
    die "The iso file does not exist."
fi

# Extract only the directory name from the iso file argument using dirname
iso_dir=$(dirname $1)

# Search for a hash file that matches the iso file name with a wildcard pattern using find with -maxdepth 1 option
hash_file=$(find $iso_dir -maxdepth 1 -type f -name "$1-*")

# Define a function to delete the temporary file using rm command with -f option
cleanup() {
    rm -f /tmp/$signature_file.asc
}

# Use trap command to call the cleanup function when the script exits
trap cleanup EXIT

# Check if a hash file is found
if [ -z "$hash_file" ]; then # No hash file found
    # Generate a hash file for the iso file using sha256sum command with -b option and redirect output to a file with .sha256 extension in /tmp directory
    sha256sum -b $1 > /tmp/$1.sha256 || die "The hash file cannot be created."

    # Show the SHA256 hash output and ask for confirmation before signing it using whiptail command with --yesno, --title and --defaultno options
    whiptail --yesno "The SHA256 hash of $1 is: $ (cat /tmp/$1.sha256)\nDo you want to sign it?" --title "Confirm Hash" --defaultno 10 60

    # Check the exit status of the whiptail command using $? variable and use an if statement to handle different cases
    if [ $? -eq 0 ]; then # Yes button was pressed
        # Mount the USB drive in read-write mode using mount-usb command
        mount-usb --mode rw || die "The USB drive cannot be mounted."
        # Create a detached signature for the hash file using gpg command with --detach-sign and -o options in /tmp directory
        gpg --detach-sign -o /tmp/$1.sha256.sig /tmp/$1.sha256 || die "The signature file cannot be created."
        # Move the hash file and the signature file from /tmp directory to iso directory using mv command
        mv /tmp/$1.sha256 /tmp/$1.sha256.sig $iso_dir || die "The files cannot be moved."
        # Remount the USB drive in read-only mode using mount command with -o remount,ro option
        mount -o remount,ro || die "The USB drive cannot be remounted."
    else # No button or escape key was pressed
        # Delete the temporary hash file from /tmp directory using rm command with -f option
        rm -f /tmp/$1.sha256
        # Exit the script without signing anything
        exit 0
    fi

    # Print a success message
    echo "The hash file and the signature file are created."
else # Hash file found
    # Search for a signature file that matches the hash file name with either .asc or .sig extension using find with -maxdepth 1 option
    signature_file=$(find $iso_dir -maxdepth 1 -type f \( -name "$hash_file.asc" -o -name "$hash_file.sig" \))

    # Check if a signature file is found
    if [ -z "$signature_file" ]; then # No signature file found
        die "No signature file found."
    fi

    # Check the content of the signature file using head command
    signature_head=$(head -n 1 $signature_file)

    # Handle different types of signatures using if statement
    if [ "$signature_head" = "-----BEGIN PGP SIGNATURE-----" ]; then # ASCII armored signature
        # No need to convert, use the original signature file for verification
    else # Binary or unknown signature type
        # Convert the binary signature to ASCII armored format using gpg with --enarmor option and save it in /tmp directory
        gpg --enarmor $signature_file > /tmp/$signature_file.asc || die "The signature file cannot be converted."
        # Use the converted signature file for verification
        signature_file=/tmp/$signature_file.asc
    fi

    # Verify the hash file against its detached signature using gpg with --status option
    gpg --status --verify $signature_file $hash_file || die "The hash file is not verified."

    # Extract only the SHA256 hash from the hash file using grep with -w option
    sha256=$(grep -woP 'SHA256 \(\S+\) = \K\S+' $hash_file) || die "The hash file is not valid."

    # Compare the SHA256 hash with the iso file using sha256sum with --status option
    echo "$sha256  $1" | sha256sum --status -c || die "The iso file is not verified."

    # Delete the temporary signature file from /tmp directory using rm command with -f option
    rm -f $signature_file

    # Print a success message
    echo "The hash file and the iso file are verified."
fi

To be tested and added properly in code base through PR.

tlaurion commented 1 month ago

Interest for Ventoy restated at https://matrix.to/#/!RNcjJXCGHiyxXCHpKv:matrix.org/$oVg45lpw9Wev7EL3NTlgBGZin1C-NFVZ8YIAUeHlFU4?via=matrix.org&via=nitro.chat&via=matrix.3mdeb.com (Dasharo premier support channel: subscribers only)

Should heads support booting from unverified ISO and support ventoy? https://github.com/linuxboot/heads/issues/1320#issuecomment-1722354703

JonathonHall-Purism commented 4 weeks ago

Should heads support booting from unverified ISO and support ventoy?

That's two questions :slightly_smiling_face:

booting from unverified ISO

I'd very much agree with supporting booting an unsigned ISO from Heads. This seems relatively simple.

From a security and reliability standpoint, that's no worse than booting raw USB (dd'ed image), there's no integrity or authenticity check. Many distributions have integrity checks built into the ISO itself as well (though that's not an authenticity check, and they don't all do it in the default boot option).

If we supported that, then AFAIK there would be no benefit to using Ventoy on Heads. Heads could do what Ventoy does, as I understand it. If there are other benefits to using Ventoy though I'd be happy to understand them, that's just what I gathered from reading about it.

support ventoy

I believe that actually being able to boot Ventoy from Heads would be a monumental effort. Ventoy is not an ELF executable or anything that we can kexec. It's a BIOS and UEFI bootloader (both provided). Booting that is not trivial because we do not have either BIOS or UEFI services available when Heads is executed as coreboot's payload.

If we supported booting unsigned ISOs, there's little benefit of actually supporting Ventoy (correct me if I am wrong), so the cost/benefit analysis doesn't make sense to me.

That said, being able to boot a BIOS or UEFI payload may have other advantages (we could actually invoke GRUB instead of trying to reimplement it, etc.). It's still a monumental effort, but it would eliminate large swaths of compatibility issues, maybe that could justify the cost.