Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 16 Mar 2016 23:12:19 +0000 (UTC)
From:      Allan Jude <allanjude@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r296963 - in head/sys/boot: . common geli i386/common i386/gptboot i386/gptzfsboot i386/libi386 i386/loader i386/zfsboot zfs
Message-ID:  <201603162312.u2GNCJdO058299@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: allanjude
Date: Wed Mar 16 23:12:19 2016
New Revision: 296963
URL: https://svnweb.freebsd.org/changeset/base/296963

Log:
  Implement GELI (AES-XTS and AES-CBC only) in gptboot and gptzfsboot
  
  Allows booting from a GELI encrypted root file system, via UFS or ZFS
  
  Reviewed by:	gnn, smh (previous version), delphij (previous version)
  Relnotes:	yes
  Sponsored by:	ScaleEngine Inc.
  Differential Revision:	https://reviews.freebsd.org/D4593

Added:
  head/sys/boot/geli/
  head/sys/boot/geli/Makefile   (contents, props changed)
  head/sys/boot/geli/geliboot.c   (contents, props changed)
  head/sys/boot/geli/geliboot.h   (contents, props changed)
  head/sys/boot/geli/geliboot_crypto.c   (contents, props changed)
  head/sys/boot/geli/pwgets.c   (contents, props changed)
     - copied, changed from r292837, head/lib/libstand/gets.c
Modified:
  head/sys/boot/Makefile.amd64
  head/sys/boot/Makefile.i386
  head/sys/boot/common/disk.c
  head/sys/boot/common/disk.h
  head/sys/boot/common/gpt.c
  head/sys/boot/common/gpt.h
  head/sys/boot/i386/common/bootargs.h
  head/sys/boot/i386/common/cons.c
  head/sys/boot/i386/common/drv.c
  head/sys/boot/i386/common/drv.h
  head/sys/boot/i386/gptboot/Makefile
  head/sys/boot/i386/gptboot/gptboot.c
  head/sys/boot/i386/gptzfsboot/Makefile
  head/sys/boot/i386/libi386/Makefile
  head/sys/boot/i386/libi386/biosdisk.c
  head/sys/boot/i386/loader/Makefile
  head/sys/boot/i386/loader/main.c
  head/sys/boot/i386/zfsboot/zfsboot.c
  head/sys/boot/zfs/libzfs.h

Modified: head/sys/boot/Makefile.amd64
==============================================================================
--- head/sys/boot/Makefile.amd64	Wed Mar 16 23:06:34 2016	(r296962)
+++ head/sys/boot/Makefile.amd64	Wed Mar 16 23:12:19 2016	(r296963)
@@ -3,6 +3,7 @@
 SUBDIR+=		efi
 SUBDIR+=		libstand32
 SUBDIR+=		zfs
+SUBDIR+=		geli
 SUBDIR+=		userboot
 
 .if ${MK_FORTH} != "no"

Modified: head/sys/boot/Makefile.i386
==============================================================================
--- head/sys/boot/Makefile.i386	Wed Mar 16 23:06:34 2016	(r296962)
+++ head/sys/boot/Makefile.i386	Wed Mar 16 23:12:19 2016	(r296963)
@@ -3,3 +3,4 @@
 SUBDIR+=		efi
 SUBDIR+=		libstand32
 SUBDIR+=		zfs
+SUBDIR+=		geli

Modified: head/sys/boot/common/disk.c
==============================================================================
--- head/sys/boot/common/disk.c	Wed Mar 16 23:06:34 2016	(r296962)
+++ head/sys/boot/common/disk.c	Wed Mar 16 23:12:19 2016	(r296963)
@@ -170,7 +170,7 @@ display_size(uint64_t size, u_int sector
 	return (buf);
 }
 
-static int
+int
 ptblread(void *d, void *buf, size_t blocks, off_t offset)
 {
 	struct disk_devdesc *dev;

Modified: head/sys/boot/common/disk.h
==============================================================================
--- head/sys/boot/common/disk.h	Wed Mar 16 23:06:34 2016	(r296962)
+++ head/sys/boot/common/disk.h	Wed Mar 16 23:12:19 2016	(r296963)
@@ -107,6 +107,7 @@ extern int disk_read(struct disk_devdesc
     u_int blocks);
 extern int disk_write(struct disk_devdesc *dev, void *buf, off_t offset,
     u_int blocks);
+extern int ptblread(void *d, void *buf, size_t blocks, off_t offset);
 
 /*
  * Print information about slices on a disk.

Modified: head/sys/boot/common/gpt.c
==============================================================================
--- head/sys/boot/common/gpt.c	Wed Mar 16 23:06:34 2016	(r296962)
+++ head/sys/boot/common/gpt.c	Wed Mar 16 23:12:19 2016	(r296963)
@@ -39,8 +39,6 @@ __FBSDID("$FreeBSD$");
 #include "util.h"
 #include "gpt.h"
 
-#define	MAXTBLENTS	128
-
 static struct gpt_hdr hdr_primary, hdr_backup, *gpthdr;
 static uint64_t hdr_primary_lba, hdr_backup_lba;
 static struct gpt_ent table_primary[MAXTBLENTS], table_backup[MAXTBLENTS];

Modified: head/sys/boot/common/gpt.h
==============================================================================
--- head/sys/boot/common/gpt.h	Wed Mar 16 23:06:34 2016	(r296962)
+++ head/sys/boot/common/gpt.h	Wed Mar 16 23:12:19 2016	(r296963)
@@ -32,6 +32,8 @@
 #include <uuid.h>
 #include <drv.h>
 
+#define	MAXTBLENTS	128
+
 int gptread(const uuid_t *uuid, struct dsk *dskp, char *buf);
 int gptfind(const uuid_t *uuid, struct dsk *dskp, int part);
 void gptbootfailed(struct dsk *dskp);

Added: head/sys/boot/geli/Makefile
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/sys/boot/geli/Makefile	Wed Mar 16 23:12:19 2016	(r296963)
@@ -0,0 +1,52 @@
+# $FreeBSD$
+# libgeliboot
+
+MAN=
+
+.include <src.opts.mk>
+MK_SSP=		no
+
+LIB=		geliboot
+INTERNALLIB=
+MK_PROFILE=	no
+NO_PIC=
+
+.if ${MACHINE_CPUARCH} == "i386" || ${MACHINE_CPUARCH} == "amd64"
+CFLAGS+=        -march=i386
+.endif
+.if ${MACHINE_ARCH} == "amd64" || ${MACHINE_ARCH} == "powerpc64"
+CFLAGS+=        -m32
+.endif
+
+WARNS?=		0
+
+# string functions from libc
+.PATH: ${.CURDIR}/../../../lib/libc/string
+SRCS+=  bcmp.c bcopy.c bzero.c
+
+# Our password input method
+SRCS+=  pwgets.c
+
+# sha256 and sha512 from sys/crypto
+.PATH: ${.CURDIR}/../../crypto/sha2
+CFLAGS+=	-DWEAK_REFS
+SRCS+=		sha256c.c sha512c.c
+
+# md5 from libmd
+.PATH: ${.CURDIR}/../../../lib/libmd
+SRCS+=		md5c.c
+
+# AES implementation from sys/crypto
+.PATH: ${.CURDIR}/../../crypto/rijndael
+CFLAGS+=	-I${.CURDIR}/../../
+# Remove asserts
+CFLAGS+=	-DNDEBUG
+SRCS+=		rijndael-alg-fst.c rijndael-api-fst.c rijndael-api.c
+
+# local GELI Implementation
+.PATH: ${.CURDIR}/../../geom/eli
+CFLAGS+=	-D_STAND
+SRCS+=		geliboot_crypto.c g_eli_hmac.c g_eli_key.c g_eli_key_cache.c pkcs5v2.c
+
+.include <bsd.stand.mk>
+.include <bsd.lib.mk>

Added: head/sys/boot/geli/geliboot.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/sys/boot/geli/geliboot.c	Wed Mar 16 23:12:19 2016	(r296963)
@@ -0,0 +1,284 @@
+/*-
+ * Copyright (c) 2015 Allan Jude <allanjude@FreeBSD.org>
+ * Copyright (c) 2005-2011 Pawel Jakub Dawidek <pawel@dawidek.net>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include "geliboot.h"
+
+SLIST_HEAD(geli_list, geli_entry) geli_head = SLIST_HEAD_INITIALIZER(geli_head);
+struct geli_list *geli_headp;
+
+static int
+geli_same_device(struct geli_entry *ge, struct dsk *dskp)
+{
+
+	if (geli_e->dsk->drive == dskp->drive &&
+	    dskp->part == 255 && geli_e->dsk->part == dskp->slice) {
+		/*
+		 * Sometimes slice = slice, and sometimes part = slice
+		 * If the incoming struct dsk has part=255, it means look at
+		 * the slice instead of the part number
+		 */
+		return (0);
+	}
+
+	/* Is this the same device? */
+	if (geli_e->dsk->drive != dskp->drive ||
+	    geli_e->dsk->slice != dskp->slice ||
+	    geli_e->dsk->part != dskp->part) {
+		return (1);
+	}
+
+	return (0);
+}
+
+void
+geli_init(void)
+{
+
+	geli_count = 0;
+	SLIST_INIT(&geli_head);
+}
+
+/*
+ * Read the last sector of the drive or partition pointed to by dsk and see
+ * if it is GELI encrypted
+ */
+int
+geli_taste(int read_func(void *vdev, void *priv, off_t off, void *buf,
+    size_t bytes), struct dsk *dskp, daddr_t lastsector)
+{
+	struct g_eli_metadata md;
+	u_char buf[DEV_BSIZE];
+	int error;
+
+	error = read_func(NULL, dskp, (off_t) lastsector * DEV_BSIZE, &buf,
+	    (size_t) DEV_BSIZE);
+	if (error != 0) {
+		return (error);
+	}
+	error = eli_metadata_decode(buf, &md);
+	if (error != 0) {
+		return (error);
+	}
+
+	if ((md.md_flags & G_ELI_FLAG_ONETIME)) {
+		/* Swap device, skip it */
+		return (1);
+	}
+	if (!(md.md_flags & G_ELI_FLAG_BOOT)) {
+		/* Disk is not GELI boot device, skip it */
+		return (1);
+	}
+	geli_e = malloc(sizeof(struct geli_entry));
+	if (geli_e == NULL)
+		return (2);
+
+	geli_e->dsk = malloc(sizeof(struct dsk));
+	if (geli_e->dsk == NULL)
+		return (2);
+	memcpy(geli_e->dsk, dskp, sizeof(struct dsk));
+	geli_e->part_end = lastsector;
+	if (dskp->part == 255) {
+		geli_e->dsk->part = dskp->slice;
+	}
+
+	geli_e->md = md;
+	eli_metadata_softc(&geli_e->sc, &md, DEV_BSIZE,
+	    (lastsector + DEV_BSIZE) * DEV_BSIZE);
+
+	SLIST_INSERT_HEAD(&geli_head, geli_e, entries);
+	geli_count++;
+
+	return (0);
+}
+
+/*
+ * Attempt to decrypt the device
+ */
+int
+geli_attach(struct dsk *dskp, const char *passphrase)
+{
+	u_char key[G_ELI_USERKEYLEN], mkey[G_ELI_DATAIVKEYLEN], *mkp;
+	u_int keynum;
+	struct hmac_ctx ctx;
+	int error;
+
+	SLIST_FOREACH_SAFE(geli_e, &geli_head, entries, geli_e_tmp) {
+		if (geli_same_device(geli_e, dskp) != 0) {
+			continue;
+		}
+
+		g_eli_crypto_hmac_init(&ctx, NULL, 0);
+		/*
+		 * Prepare Derived-Key from the user passphrase.
+		 */
+		if (geli_e->md.md_iterations == 0) {
+			g_eli_crypto_hmac_update(&ctx, geli_e->md.md_salt,
+			    sizeof(geli_e->md.md_salt));
+			g_eli_crypto_hmac_update(&ctx, passphrase,
+			    strlen(passphrase));
+		} else if (geli_e->md.md_iterations > 0) {
+			printf("Calculating GELI Decryption Key disk%dp%d @ %lu "
+			    "iterations...\n", dskp->unit,
+			    (dskp->slice > 0 ? dskp->slice : dskp->part),
+			    geli_e->md.md_iterations);
+			u_char dkey[G_ELI_USERKEYLEN];
+
+			pkcs5v2_genkey(dkey, sizeof(dkey), geli_e->md.md_salt,
+			    sizeof(geli_e->md.md_salt), passphrase,
+			    geli_e->md.md_iterations);
+			g_eli_crypto_hmac_update(&ctx, dkey, sizeof(dkey));
+			bzero(&dkey, sizeof(dkey));
+		}
+
+		g_eli_crypto_hmac_final(&ctx, key, 0);
+
+		error = g_eli_mkey_decrypt(&geli_e->md, key, mkey, &keynum);
+		bzero(&key, sizeof(key));
+		if (error == -1) {
+			bzero(&mkey, sizeof(mkey));
+			printf("Bad GELI key: %d\n", error);
+			return (error);
+		} else if (error != 0) {
+			bzero(&mkey, sizeof(mkey));
+			printf("Failed to decrypt GELI master key: %d\n", error);
+			return (error);
+		}
+
+		/* Store the keys */
+		bcopy(mkey, geli_e->sc.sc_mkey, sizeof(geli_e->sc.sc_mkey));
+		bcopy(mkey, geli_e->sc.sc_ivkey, sizeof(geli_e->sc.sc_ivkey));
+		mkp = mkey + sizeof(geli_e->sc.sc_ivkey);
+		if ((geli_e->sc.sc_flags & G_ELI_FLAG_AUTH) == 0) {
+			bcopy(mkp, geli_e->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, "\x10", 1,
+			    geli_e->sc.sc_ekey, 0);
+		}
+		bzero(&mkey, sizeof(mkey));
+
+		/* Initialize the per-sector IV */
+		switch (geli_e->sc.sc_ealgo) {
+		case CRYPTO_AES_XTS:
+			break;
+		default:
+			SHA256_Init(&geli_e->sc.sc_ivctx);
+			SHA256_Update(&geli_e->sc.sc_ivctx, geli_e->sc.sc_ivkey,
+			    sizeof(geli_e->sc.sc_ivkey));
+			break;
+		}
+
+		return (0);
+	}
+
+	/* Disk not found */
+	return (2);
+}
+
+int
+is_geli(struct dsk *dskp)
+{
+	SLIST_FOREACH_SAFE(geli_e, &geli_head, entries, geli_e_tmp) {
+		if (geli_same_device(geli_e, dskp) == 0) {
+			return (0);
+		}
+	}
+	
+	return (1);
+}
+
+int
+geli_read(struct dsk *dskp, off_t offset, u_char *buf, size_t bytes)
+{
+	u_char iv[G_ELI_IVKEYLEN];
+	u_char *pbuf;
+	int error;
+	off_t os;
+	uint64_t keyno;
+	size_t n, nb;
+	struct g_eli_key gkey;
+
+	SLIST_FOREACH_SAFE(geli_e, &geli_head, entries, geli_e_tmp) {
+		if (geli_same_device(geli_e, dskp) != 0) {
+			continue;
+		}
+
+		nb = bytes / DEV_BSIZE;
+		for (n = 0; n < nb; n++) {
+			os = offset + (n * DEV_BSIZE);
+			pbuf = buf + (n * DEV_BSIZE);
+
+			g_eli_crypto_ivgen(&geli_e->sc, os, iv, G_ELI_IVKEYLEN);
+
+			/* Get the key that corresponds to this offset */
+			keyno = (os >> G_ELI_KEY_SHIFT) / DEV_BSIZE;
+			g_eli_key_fill(&geli_e->sc, &gkey, keyno);
+
+			error = geliboot_crypt(geli_e->sc.sc_ealgo, 0, pbuf,
+			    DEV_BSIZE, gkey.gek_key, geli_e->sc.sc_ekeylen, iv);
+
+			if (error != 0) {
+				bzero(&gkey, sizeof(gkey));
+				printf("Failed to decrypt in geli_read()!");
+				return (error);
+			}
+		}
+		bzero(&gkey, sizeof(gkey));
+		return (0);
+	}
+
+	printf("GELI provider not found\n");
+	return (1);
+}
+
+int
+geli_passphrase(char *pw, int disk, int parttype, int part, struct dsk *dskp)
+{
+	int i;
+
+	/* TODO: Implement GELI keyfile(s) support */
+	for (i = 0; i < 3; i++) {
+		/* Try cached passphrase */
+		if (i == 0 && pw[0] != '\0') {
+			if (geli_attach(dskp, pw) == 0) {
+				return (0);
+			}
+		}
+		printf("GELI Passphrase for disk%d%c%d: ", disk, parttype, part);
+		pwgets(pw, GELI_PW_MAXLEN);
+		printf("\n");
+		if (geli_attach(dskp, pw) == 0) {
+			return (0);
+		}
+	}
+
+	return (1);
+}

Added: head/sys/boot/geli/geliboot.h
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/sys/boot/geli/geliboot.h	Wed Mar 16 23:12:19 2016	(r296963)
@@ -0,0 +1,86 @@
+/*-
+ * Copyright (c) 2015 Allan Jude <allanjude@FreeBSD.org>
+ * Copyright (c) 2005-2011 Pawel Jakub Dawidek <pawel@dawidek.net>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/endian.h>
+#include <sys/queue.h>
+
+#ifndef _GELIBOOT_H_
+#define _GELIBOOT_H_
+
+#define _STRING_H_
+#define _STRINGS_H_
+#define _STDIO_H_
+#include <geom/eli/g_eli.h>
+#include <geom/eli/pkcs5v2.h>
+
+/* Pull in the md5, sha256, and sha512 implementations */
+#include <md5.h>
+#include <crypto/sha2/sha256.h>
+#include <crypto/sha2/sha512.h>
+
+/* Pull in AES implementation */
+#include <crypto/rijndael/rijndael-api-fst.h>
+
+/* AES-XTS implementation */
+#define _STAND
+#define STAND_H /* We don't want stand.h in {gpt,zfs,gptzfs}boot */
+#include <opencrypto/xform_enc.h>
+
+#ifndef DEV_BSIZE
+#define DEV_BSIZE 			512
+#endif
+
+#ifndef MIN
+#define    MIN(a,b) (((a) < (b)) ? (a) : (b))
+#endif
+
+#define GELI_PW_MAXLEN			256
+extern void pwgets(char *buf, int n);
+
+struct geli_entry {
+	struct dsk		*dsk;
+	off_t			part_end;
+	struct g_eli_softc	sc;
+	struct g_eli_metadata	md;
+	SLIST_ENTRY(geli_entry)	entries;
+} *geli_e, *geli_e_tmp;
+
+int geli_count;
+
+void geli_init(void);
+int geli_taste(int read_func(void *vdev, void *priv, off_t off,
+    void *buf, size_t bytes), struct dsk *dsk, daddr_t lastsector);
+int geli_attach(struct dsk *dskp, const char *passphrase);
+int is_geli(struct dsk *dsk);
+int geli_read(struct dsk *dsk, off_t offset, u_char *buf, size_t bytes);
+int geli_decrypt(u_int algo, u_char *data, size_t datasize,
+    const u_char *key, size_t keysize, const uint8_t* iv);
+int geli_passphrase(char *pw, int disk, int parttype, int part, struct dsk *dskp);
+
+#endif /* _GELIBOOT_H_ */

Added: head/sys/boot/geli/geliboot_crypto.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/sys/boot/geli/geliboot_crypto.c	Wed Mar 16 23:12:19 2016	(r296963)
@@ -0,0 +1,135 @@
+/*-
+ * Copyright (c) 2005-2010 Pawel Jakub Dawidek <pjd@FreeBSD.org>
+ * Copyright (c) 2015 Allan Jude <allanjude@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include "geliboot.h"
+
+int
+geliboot_crypt(u_int algo, int enc, u_char *data, size_t datasize,
+    const u_char *key, size_t keysize, u_char *iv)
+{
+	keyInstance aeskey;
+	cipherInstance cipher;
+	struct aes_xts_ctx xtsctx, *ctxp;
+	size_t xts_len;
+	int err, blks, i;
+
+	switch (algo) {
+	case CRYPTO_AES_CBC:
+		err = rijndael_makeKey(&aeskey, !enc, keysize, 
+		    (const char *)key);
+		if (err < 0) {
+			printf("Failed to setup decryption keys: %d\n", err);
+			return (err);
+		}
+
+		err = rijndael_cipherInit(&cipher, MODE_CBC, iv);
+		if (err < 0) {
+			printf("Failed to setup IV: %d\n", err);
+			return (err);
+		}
+
+		switch (enc) {
+		case 0: /* decrypt */
+			blks = rijndael_blockDecrypt(&cipher, &aeskey, data, 
+			    datasize * 8, data);
+			break;
+		case 1: /* encrypt */
+			blks = rijndael_blockEncrypt(&cipher, &aeskey, data, 
+			    datasize * 8, data);
+			break;
+		}
+		if (datasize != (blks / 8)) {
+			printf("Failed to decrypt the entire input: "
+			    "%u != %u\n", blks, datasize);
+			return (1);
+		}
+		break;
+	case CRYPTO_AES_XTS:
+		xts_len = keysize << 1;
+		ctxp = &xtsctx;
+
+		rijndael_set_key(&ctxp->key1, key, xts_len / 2);
+		rijndael_set_key(&ctxp->key2, key + (xts_len / 16), xts_len / 2);
+
+		enc_xform_aes_xts.reinit(ctxp, iv);
+
+		switch (enc) {
+		case 0: /* decrypt */
+			for (i = 0; i < datasize; i += AES_XTS_BLOCKSIZE) {
+				enc_xform_aes_xts.decrypt(ctxp, data + i);
+			}
+			break;
+		case 1: /* encrypt */
+			for (i = 0; i < datasize; i += AES_XTS_BLOCKSIZE) {
+				enc_xform_aes_xts.encrypt(ctxp, data + i);
+			}
+			break;
+		}
+		break;
+	default:
+		printf("Unsupported crypto algorithm #%d\n", algo);
+		return (1);
+	}
+
+	return (0);
+}
+
+static int
+g_eli_crypto_cipher(u_int algo, int enc, u_char *data, size_t datasize,
+    const u_char *key, size_t keysize)
+{
+	u_char iv[keysize];
+
+	bzero(iv, sizeof(iv));
+	return (geliboot_crypt(algo, enc, data, datasize, key, keysize, iv));
+}
+
+int
+g_eli_crypto_encrypt(u_int algo, u_char *data, size_t datasize,
+    const u_char *key, size_t keysize)
+{
+
+	/* We prefer AES-CBC for metadata protection. */
+	if (algo == CRYPTO_AES_XTS)
+		algo = CRYPTO_AES_CBC;
+
+	return (g_eli_crypto_cipher(algo, 1, data, datasize, key, keysize));
+}
+
+int
+g_eli_crypto_decrypt(u_int algo, u_char *data, size_t datasize,
+    const u_char *key, size_t keysize)
+{
+
+	/* We prefer AES-CBC for metadata protection. */
+	if (algo == CRYPTO_AES_XTS)
+		algo = CRYPTO_AES_CBC;
+
+	return (g_eli_crypto_cipher(algo, 0, data, datasize, key, keysize));
+}

Copied and modified: head/sys/boot/geli/pwgets.c (from r292837, head/lib/libstand/gets.c)
==============================================================================
--- head/lib/libstand/gets.c	Mon Dec 28 18:36:00 2015	(r292837, copy source)
+++ head/sys/boot/geli/pwgets.c	Wed Mar 16 23:12:19 2016	(r296963)
@@ -36,10 +36,10 @@ __FBSDID("$FreeBSD$");
 
 #include "stand.h"
 
-/* gets() with constrained input length */
+/* gets() with constrained input length, for passwords */
 
 void
-ngets(char *buf, int n)
+pwgets(char *buf, int n)
 {
     int c;
     char *lp;
@@ -76,37 +76,8 @@ ngets(char *buf, int n)
 	default:
 	    if ((n < 1) || ((lp - buf) < n - 1)) {
 		*lp++ = c;
-		putchar(c);
+		putchar('*');
 	    }
 	}
     /*NOTREACHED*/
 }
-
-int
-fgetstr(char *buf, int size, int fd)
-{
-    char	c;
-    int		err, len;
-    
-    size--;	/* leave space for terminator */
-    len = 0;
-    while (size != 0) {
-	err = read(fd, &c, sizeof(c));
-	if (err < 0)		/* read error */
-	    return(-1);
-	if (err == 0) {		/* EOF */
-	    if (len == 0)
-		return(-1);	/* nothing to read */
-	    break;
-	}
-	if ((c == '\r') ||	/* line terminators */
-	    (c == '\n'))
-	    break;
-	*buf++ = c;		/* keep char */
-	size--;
-	len++;
-    }
-    *buf = 0;
-    return(len);
-}
-

Modified: head/sys/boot/i386/common/bootargs.h
==============================================================================
--- head/sys/boot/i386/common/bootargs.h	Wed Mar 16 23:06:34 2016	(r296962)
+++ head/sys/boot/i386/common/bootargs.h	Wed Mar 16 23:12:19 2016	(r296963)
@@ -64,6 +64,12 @@ struct bootargs
 	 */
 };
 
+struct geli_boot_args
+{
+    uint32_t		size;
+    char		gelipw[256];
+};
+
 #endif /*__ASSEMBLER__*/
 
 #endif	/* !_BOOT_I386_ARGS_H_ */

Modified: head/sys/boot/i386/common/cons.c
==============================================================================
--- head/sys/boot/i386/common/cons.c	Wed Mar 16 23:06:34 2016	(r296962)
+++ head/sys/boot/i386/common/cons.c	Wed Mar 16 23:12:19 2016	(r296963)
@@ -97,6 +97,13 @@ xgetc(int fn)
 }
 
 int
+getchar(void)
+{
+
+	return (xgetc(0));
+}
+
+int
 keyhit(unsigned int secs)
 {
 	uint32_t t0, t1;

Modified: head/sys/boot/i386/common/drv.c
==============================================================================
--- head/sys/boot/i386/common/drv.c	Wed Mar 16 23:06:34 2016	(r296962)
+++ head/sys/boot/i386/common/drv.c	Wed Mar 16 23:12:19 2016	(r296963)
@@ -29,7 +29,6 @@ __FBSDID("$FreeBSD$");
 #include "xreadorg.h"
 #endif
 
-#ifdef GPT
 static struct edd_params params;
 
 uint64_t
@@ -50,7 +49,6 @@ drvsize(struct dsk *dskp)
 	}
 	return (params.sectors);
 }
-#endif	/* GPT */
 
 #ifndef USE_XREAD
 static struct edd_packet packet;

Modified: head/sys/boot/i386/common/drv.h
==============================================================================
--- head/sys/boot/i386/common/drv.h	Wed Mar 16 23:06:34 2016	(r296962)
+++ head/sys/boot/i386/common/drv.h	Wed Mar 16 23:12:19 2016	(r296963)
@@ -42,7 +42,7 @@ struct dsk {
 int drvread(struct dsk *dskp, void *buf, daddr_t lba, unsigned nblk);
 #ifdef GPT
 int drvwrite(struct dsk *dskp, void *buf, daddr_t lba, unsigned nblk);
-uint64_t drvsize(struct dsk *dskp);
 #endif	/* GPT */
+uint64_t drvsize(struct dsk *dskp);
 
 #endif	/* !_DRV_H_ */

Modified: head/sys/boot/i386/gptboot/Makefile
==============================================================================
--- head/sys/boot/i386/gptboot/Makefile	Wed Mar 16 23:06:34 2016	(r296962)
+++ head/sys/boot/i386/gptboot/Makefile	Wed Mar 16 23:12:19 2016	(r296963)
@@ -39,6 +39,14 @@ CFLAGS=	-DBOOTPROG=\"gptboot\" \
 
 CFLAGS.gcc+=	--param max-inline-insns-single=100
 
+.if !defined(LOADER_NO_GELI_SUPPORT)
+CFLAGS+=	-DLOADER_GELI_SUPPORT
+CFLAGS+=	-I${.CURDIR}/../../geli
+LIBGELIBOOT=	${.OBJDIR}/../../geli/libgeliboot.a
+.PATH:		${.CURDIR}/../../../opencrypto
+OPENCRYPTO_XTS=	xform_aes_xts.o
+.endif
+
 LD_FLAGS=-static -N --gc-sections
 
 LIBSTAND=	${.OBJDIR}/../../libstand32/libstand.a
@@ -60,14 +68,14 @@ gptldr.bin: gptldr.out
 gptldr.out: gptldr.o
 	${LD} ${LD_FLAGS} -e start -Ttext ${ORG1} -o ${.TARGET} gptldr.o
 
-CLEANFILES+=	gptboot.bin gptboot.out gptboot.o sio.o gpt.o crc32.o drv.o \
-		cons.o util.o
+CLEANFILES+=	gptboot.bin gptboot.out gptboot.o sio.o crc32.o drv.o \
+		cons.o util.o ${OPENCRYPTO_XTS}
 
 gptboot.bin: gptboot.out
 	${OBJCOPY} -S -O binary gptboot.out ${.TARGET}
 
-gptboot.out: ${BTXCRT} gptboot.o sio.o gpt.o crc32.o drv.o cons.o util.o
-	${LD} ${LD_FLAGS} -Ttext ${ORG2} -o ${.TARGET} ${.ALLSRC} ${LIBSTAND}
+gptboot.out: ${BTXCRT} gptboot.o sio.o crc32.o drv.o cons.o util.o ${OPENCRYPTO_XTS}
+	${LD} ${LD_FLAGS} -Ttext ${ORG2} -o ${.TARGET} ${.ALLSRC} ${LIBSTAND} ${LIBGELIBOOT}
 
 gptboot.o: ${.CURDIR}/../../common/ufsread.c
 

Modified: head/sys/boot/i386/gptboot/gptboot.c
==============================================================================
--- head/sys/boot/i386/gptboot/gptboot.c	Wed Mar 16 23:06:34 2016	(r296962)
+++ head/sys/boot/i386/gptboot/gptboot.c	Wed Mar 16 23:12:19 2016	(r296963)
@@ -23,6 +23,7 @@ __FBSDID("$FreeBSD$");
 
 #include <machine/bootinfo.h>
 #include <machine/elf.h>
+#include <machine/pc/bios.h>
 #include <machine/psl.h>
 
 #include <stdarg.h>
@@ -31,6 +32,7 @@ __FBSDID("$FreeBSD$");
 
 #include <btxv86.h>
 
+#include "bootargs.h"
 #include "lib.h"
 #include "rbx.h"
 #include "drv.h"
@@ -82,14 +84,60 @@ static struct dsk dsk;
 static char kname[1024];
 static int comspeed = SIOSPD;
 static struct bootinfo bootinfo;
+static struct geli_boot_args geliargs;
+
+static vm_offset_t	high_heap_base;
+static uint32_t		bios_basemem, bios_extmem, high_heap_size;
+
+static struct bios_smap smap;
+
+/*
+ * The minimum amount of memory to reserve in bios_extmem for the heap.
+ */
+#define	HEAP_MIN	(3 * 1024 * 1024)
+
+static char *heap_next;
+static char *heap_end;
 
 void exit(int);
 static void load(void);
 static int parse(char *, int *);
 static int dskread(void *, daddr_t, unsigned);
-static uint32_t memsize(void);
+void *malloc(size_t n);
+void free(void *ptr);
+#ifdef LOADER_GELI_SUPPORT
+static int vdev_read(void *vdev __unused, void *priv, off_t off, void *buf,
+	size_t bytes);
+#endif
+
+void *
+malloc(size_t n)
+{
+	char *p = heap_next;
+	if (p + n > heap_end) {
+		printf("malloc failure\n");
+		for (;;)
+		    ;
+		/* NOTREACHED */
+		return (0);
+	}
+	heap_next += n;
+	return (p);
+}
+
+void
+free(void *ptr)
+{
+
+	return;
+}
 
 #include "ufsread.c"
+#include "gpt.c"
+#ifdef LOADER_GELI_SUPPORT
+#include "geliboot.c"
+static char gelipw[GELI_PW_MAXLEN];
+#endif
 
 static inline int
 xfsread(ufs_ino_t inode, void *buf, size_t nbyte)
@@ -102,14 +150,90 @@ xfsread(ufs_ino_t inode, void *buf, size
 	return (0);
 }
 
-static inline uint32_t
-memsize(void)
+static void
+bios_getmem(void)
 {
+    uint64_t size;
 
-	v86.addr = MEM_EXT;
+    /* Parse system memory map */
+    v86.ebx = 0;
+    do {
+	v86.ctl = V86_FLAGS;
+	v86.addr = MEM_EXT;		/* int 0x15 function 0xe820*/
+	v86.eax = 0xe820;
+	v86.ecx = sizeof(struct bios_smap);
+	v86.edx = SMAP_SIG;
+	v86.es = VTOPSEG(&smap);
+	v86.edi = VTOPOFF(&smap);
+	v86int();
+	if ((v86.efl & 1) || (v86.eax != SMAP_SIG))
+	    break;
+	/* look for a low-memory segment that's large enough */
+	if ((smap.type == SMAP_TYPE_MEMORY) && (smap.base == 0) &&
+	    (smap.length >= (512 * 1024)))
+	    bios_basemem = smap.length;
+	/* look for the first segment in 'extended' memory */
+	if ((smap.type == SMAP_TYPE_MEMORY) && (smap.base == 0x100000)) {
+	    bios_extmem = smap.length;
+	}
+
+	/*
+	 * Look for the largest segment in 'extended' memory beyond
+	 * 1MB but below 4GB.
+	 */
+	if ((smap.type == SMAP_TYPE_MEMORY) && (smap.base > 0x100000) &&
+	    (smap.base < 0x100000000ull)) {
+	    size = smap.length;
+
+	    /*
+	     * If this segment crosses the 4GB boundary, truncate it.
+	     */
+	    if (smap.base + size > 0x100000000ull)
+		size = 0x100000000ull - smap.base;
+
+	    if (size > high_heap_size) {
+		high_heap_size = size;
+		high_heap_base = smap.base;
+	    }
+	}
+    } while (v86.ebx != 0);
+
+    /* Fall back to the old compatibility function for base memory */
+    if (bios_basemem == 0) {
+	v86.ctl = 0;
+	v86.addr = 0x12;		/* int 0x12 */
+	v86int();
+
+	bios_basemem = (v86.eax & 0xffff) * 1024;
+    }
+
+    /* Fall back through several compatibility functions for extended memory */
+    if (bios_extmem == 0) {
+	v86.ctl = V86_FLAGS;
+	v86.addr = 0x15;		/* int 0x15 function 0xe801*/
+	v86.eax = 0xe801;
+	v86int();
+	if (!(v86.efl & 1)) {
+	    bios_extmem = ((v86.ecx & 0xffff) + ((v86.edx & 0xffff) * 64)) * 1024;
+	}
+    }
+    if (bios_extmem == 0) {
+	v86.ctl = 0;
+	v86.addr = 0x15;		/* int 0x15 function 0x88*/
 	v86.eax = 0x8800;
 	v86int();
-	return (v86.eax);
+	bios_extmem = (v86.eax & 0xffff) * 1024;
+    }
+
+    /*
+     * If we have extended memory and did not find a suitable heap
+     * region in the SMAP, use the last 3MB of 'extended' memory as a
+     * high heap candidate.
+     */
+    if (bios_extmem >= HEAP_MIN && high_heap_size < HEAP_MIN) {
+	high_heap_size = HEAP_MIN;
+	high_heap_base = bios_extmem + 0x100000 - HEAP_MIN;
+    }
 }
 
 static int
@@ -124,6 +248,16 @@ gptinit(void)
 		printf("%s: no UFS partition was found\n", BOOTPROG);
 		return (-1);
 	}
+#ifdef LOADER_GELI_SUPPORT
+	if (geli_taste(vdev_read, &dsk, (gpttable[curent].ent_lba_end -
+	    gpttable[curent].ent_lba_start)) == 0) {
+		if (geli_passphrase(&gelipw, dsk.unit, 'p', curent + 1, &dsk) != 0) {
+			printf("%s: unable to decrypt GELI key\n", BOOTPROG);
+			return (-1);
+		}
+	}
+#endif
+
 	dsk_meta = 0;
 	return (0);
 }
@@ -137,6 +271,17 @@ main(void)
 	ufs_ino_t ino;
 
 	dmadat = (void *)(roundup2(__base + (int32_t)&_end, 0x10000) - __base);
+
+	bios_getmem();
+
+	if (high_heap_size > 0) {
+		heap_end = PTOV(high_heap_base + high_heap_size);
+		heap_next = PTOV(high_heap_base);
+	} else {
+		heap_next = (char *)dmadat + sizeof(*dmadat);
+		heap_end = (char *)PTOV(bios_basemem);
+	}
+
 	v86.ctl = V86_FLAGS;
 	v86.efl = PSL_RESERVED_DEFAULT | PSL_I;
 	dsk.drive = *(uint8_t *)PTOV(ARGS);
@@ -146,10 +291,14 @@ main(void)
 	dsk.start = 0;
 	bootinfo.bi_version = BOOTINFO_VERSION;
 	bootinfo.bi_size = sizeof(bootinfo);
-	bootinfo.bi_basemem = 0;	/* XXX will be filled by loader or kernel */
-	bootinfo.bi_extmem = memsize();
+	bootinfo.bi_basemem = bios_basemem / 1024;
+	bootinfo.bi_extmem = bios_extmem / 1024;
 	bootinfo.bi_memsizes_valid++;
+	bootinfo.bi_bios_dev = dsk.drive;
 

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201603162312.u2GNCJdO058299>