Bug 283043 - gptboot fails to read the encrypted rootfs if geli authentication (geli -a) is used
Summary: gptboot fails to read the encrypted rootfs if geli authentication (geli -a) i...
Status: Open
Alias: None
Product: Base System
Classification: Unclassified
Component: kern (show other bugs)
Version: 14.1-STABLE
Hardware: amd64 Any
: --- Affects Some People
Assignee: freebsd-bugs (Nobody)
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2024-11-29 20:10 UTC by no@spam
Modified: 2024-12-06 17:49 UTC (History)
4 users (show)

See Also:


Attachments
geliboot_auth.patch (1.88 KB, application/mbox)
2024-12-06 17:49 UTC, John Baldwin
no flags Details

Note You need to log in before you can comment on or make changes to this bug.
Description no@spam 2024-11-29 20:10:24 UTC
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
Comment 1 Mark Johnston freebsd_committer freebsd_triage 2024-12-06 17:04:48 UTC
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.
Comment 2 John Baldwin freebsd_committer freebsd_triage 2024-12-06 17:19:17 UTC
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));
Comment 3 John Baldwin freebsd_committer freebsd_triage 2024-12-06 17:23:41 UTC
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.
Comment 4 John Baldwin freebsd_committer freebsd_triage 2024-12-06 17:49:57 UTC
Created attachment 255669 [details]
geliboot_auth.patch

Better patch that also disables writes