abstract: when using geli init [-b] -g -a <HMAC>, gptboot cannot access the encrypted rootfs properly. imho this can be a code or documentation error. freebsd version: FreeBSD-14.1-STABLE-amd64-20240926-4f4860c9b07c-268821-disc1.iso (1401502) debugging env was vmware esxi 8.0u3, Releasebuild-24022510, pvscsi adapter failing boot output: GELI Passphrase for disk0p2: *** Calculating GELI Decryption Key for disk0p2: 3124135 iterations... gptboot: No /boot/loader on 0:ad(0p2) gptboot: No /boot/kernel/kernel on 0:ad(0p2) FreeBSD/x86 boot Default: 0:ad(0p2)/boot/kernel/kernel boot: reproduce (live system based install): gpart create -s gpt da0; gpart add -t freebsd-boot -l geli01_boot -s 512K da0; gpart add -t freebsd-ufs -a 1m -l geli01_root -s 40G da0; gpart bootcode -b /boot/pmbr -p /boot/gptboot -i 1 da0; ==> WORKS: geli init -v -b -g -B "/tmp/geli01_root.meta" -d -e 'AES-XTS' -l 256 -s 4096 "/dev/gpt/geli01_root"; ==> FAILS: geli init -v -b -g -a 'HMAC/SHA256' -B "/tmp/geli01_root.meta" -d -e 'AES-XTS' -l 256 -s 4096 "/dev/gpt/geli01_root"; geli attach -v /dev/gpt/geli01_root newfs -j -L root -O 2 -o time -U -i 32768 -b 65536 -f 8192 -c 262144 -m 8 /dev/gpt/geli01_root.eli; mount /dev/gpt/geli01_root.eli /mnt tar xfC /usr/freebsd-dist/base.txz /mnt tar xfC /usr/freebsd-dist/kernel.txz /mnt echo "/dev/da0p2.eli / ufs rw,noatime 1 1" >/mnt/etc/fstab echo "geom_eli_load=\"YES\"" >/mnt/boot/loader.conf echo "cryptodev_load=\"YES\"" >>/mnt/boot/loader.conf umount /mnt geli detach /dev/gpt/geli01_root there's an old bug going into a similar direction, which might be related: bug #161013
Is this a regression relative to an older release? There is some code in the loader to handle authenticated GELI providers, but we're not sure how well it's tested. The installer doesn't appear to enable authentication when configuring boot from GELI.
Hmm, I think we aren't deriving the encryption key correctly when auth is configured. The code in the kernel for this case in sys/geom/eli/g_eli_key.c: /* * Find and decrypt Master Key encrypted with 'key' at slot 'nkey'. * Return 0 on success, > 0 on failure, -1 on bad key. */ int g_eli_mkey_decrypt(const struct g_eli_metadata *md, const unsigned char *key, unsigned char *mkey, unsigned nkey) { unsigned char tmpmkey[G_ELI_MKEYLEN]; unsigned char enckey[SHA512_MDLEN]; /* Key for encryption. */ const unsigned char *mmkey; int bit, error; if (nkey > G_ELI_MKEYLEN) return (-1); /* * The key for encryption is: enckey = HMAC_SHA512(Derived-Key, 1) */ g_eli_crypto_hmac(key, G_ELI_USERKEYLEN, "\x01", 1, enckey, 0); ... but in geliboot.c we have: if ((gdev->sc.sc_flags & G_ELI_FLAG_AUTH) == 0) { bcopy(mkp, gdev->sc.sc_ekey, G_ELI_DATAKEYLEN); } else { /* * The encryption key is: ekey = HMAC_SHA512(Data-Key, 0x10) */ g_eli_crypto_hmac(mkp, G_ELI_MAXKEYLEN, (const uint8_t *)"\x10", 1, gdev->sc.sc_ekey, 0); } Try this change to see if it works: diff --git a/stand/libsa/geli/geliboot.c b/stand/libsa/geli/geliboot.c index 04c53e73b29a..bdb288d2733c 100644 --- a/stand/libsa/geli/geliboot.c +++ b/stand/libsa/geli/geliboot.c @@ -286,9 +286,9 @@ geli_probe(struct geli_dev *gdev, const char *passphrase, u_char *mkeyp) bcopy(mkp, gdev->sc.sc_ekey, G_ELI_DATAKEYLEN); } else { /* - * The encryption key is: ekey = HMAC_SHA512(Data-Key, 0x10) + * The encryption key is: ekey = HMAC_SHA512(Derived-Key, 1) */ - g_eli_crypto_hmac(mkp, G_ELI_MAXKEYLEN, (const uint8_t *)"\x10", 1, + g_eli_crypto_hmac(mkp, G_ELI_MAXKEYLEN, (const uint8_t *)"\x01", 1, gdev->sc.sc_ekey, 0); } explicit_bzero(mkey, sizeof(mkey));
BTW, we don't perform any MAC on data read from a GELI volume, this patch would just ensure we get the right key to decrypt the data. This is not fully ideal but is "ok" for a read-only boot loader. However, GELI has gained write support in the boot loader at some point and we need to reject writes on a volume with auth support unless we implement proper auth support in geliboot.
Created attachment 255669 [details] geliboot_auth.patch Better patch that also disables writes