Page MenuHomeFreeBSD

D9575.id26867.diff
No OneTemporary

D9575.id26867.diff

Index: sys/boot/geli/Makefile
===================================================================
--- sys/boot/geli/Makefile
+++ sys/boot/geli/Makefile
@@ -39,6 +39,7 @@
# AES implementation from sys/crypto
.PATH: ${.CURDIR}/../../crypto/rijndael
CFLAGS+= -I${.CURDIR}/../../
+CFLAGS+= -I${.CURDIR}/../common/
# Remove asserts
CFLAGS+= -DNDEBUG
SRCS+= rijndael-alg-fst.c rijndael-api-fst.c rijndael-api.c
Index: sys/boot/geli/geliboot.h
===================================================================
--- sys/boot/geli/geliboot.h
+++ sys/boot/geli/geliboot.h
@@ -27,32 +27,11 @@
* $FreeBSD$
*/
-#include <sys/endian.h>
-#include <sys/queue.h>
+#include <crypto/intake.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
@@ -64,30 +43,26 @@
#define MIN(a,b) (((a) < (b)) ? (a) : (b))
#endif
+#define GELI_MAX_KEYS 64
#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;
+extern void pwgets(char *buf, int n);
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 geli_attach(struct dsk *dskp, const char *passphrase, const u_char *mkeyp);
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_havekey(struct dsk *dskp);
int geli_passphrase(char *pw, int disk, int parttype, int part, struct dsk *dskp);
int geliboot_crypt(u_int algo, int enc, u_char *data, size_t datasize,
const u_char *key, size_t keysize, u_char *iv);
+void geli_fill_keybuf(struct keybuf *keybuf);
+void geli_save_keybuf(struct keybuf *keybuf);
+
#endif /* _GELIBOOT_H_ */
Index: sys/boot/geli/geliboot.c
===================================================================
--- sys/boot/geli/geliboot.c
+++ sys/boot/geli/geliboot.c
@@ -27,17 +27,75 @@
* $FreeBSD$
*/
+#include "geliboot_internal.h"
#include "geliboot.h"
SLIST_HEAD(geli_list, geli_entry) geli_head = SLIST_HEAD_INITIALIZER(geli_head);
struct geli_list *geli_headp;
+typedef u_char geli_ukey[G_ELI_USERKEYLEN];
+
+static geli_ukey saved_keys[GELI_MAX_KEYS];
+static unsigned int nsaved_keys = 0;
+
+/*
+ * Copy keys from local storage to the keybuf struct.
+ * Destroy the local storage when finished.
+ */
+void
+geli_fill_keybuf(struct keybuf *fkeybuf)
+{
+ unsigned int i;
+
+ for (i = 0; i < nsaved_keys; i++) {
+ fkeybuf->kb_ents[i].ke_type = KEYBUF_TYPE_GELI;
+ memcpy(fkeybuf->kb_ents[i].ke_data, saved_keys[i],
+ G_ELI_USERKEYLEN);
+ }
+ fkeybuf->kb_nents = nsaved_keys;
+ explicit_bzero(saved_keys, sizeof(saved_keys));
+}
+
+/*
+ * Copy keys from a keybuf struct into local storage.
+ * Zero out the keybuf.
+ */
+void
+geli_save_keybuf(struct keybuf *skeybuf)
+{
+ unsigned int i;
+
+ for (i = 0; i < skeybuf->kb_nents && i < GELI_MAX_KEYS; i++) {
+ memcpy(saved_keys[i], skeybuf->kb_ents[i].ke_data,
+ G_ELI_USERKEYLEN);
+ explicit_bzero(skeybuf->kb_ents[i].ke_data,
+ G_ELI_USERKEYLEN);
+ skeybuf->kb_ents[i].ke_type = KEYBUF_TYPE_NONE;
+ }
+ nsaved_keys = skeybuf->kb_nents;
+ skeybuf->kb_nents = 0;
+}
+
+static void
+save_key(geli_ukey key)
+{
+
+ /*
+ * If we run out of key space, the worst that will happen is
+ * it will ask the user for the password again.
+ */
+ if (nsaved_keys < GELI_MAX_KEYS) {
+ memcpy(saved_keys[nsaved_keys], key, G_ELI_USERKEYLEN);
+ nsaved_keys++;
+ }
+}
+
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) {
+ if (ge->dsk->drive == dskp->drive &&
+ dskp->part == 255 && ge->dsk->part == dskp->slice) {
/*
* Sometimes slice = slice, and sometimes part = slice
* If the incoming struct dsk has part=255, it means look at
@@ -47,15 +105,39 @@
}
/* Is this the same device? */
- if (geli_e->dsk->drive != dskp->drive ||
- geli_e->dsk->slice != dskp->slice ||
- geli_e->dsk->part != dskp->part) {
+ if (ge->dsk->drive != dskp->drive ||
+ ge->dsk->slice != dskp->slice ||
+ ge->dsk->part != dskp->part) {
return (1);
}
return (0);
}
+static int
+geli_findkey(struct geli_entry *ge, struct dsk *dskp, u_char *mkey)
+{
+ u_int keynum;
+ int i;
+
+ if (ge->keybuf_slot >= 0) {
+ if (g_eli_mkey_decrypt(&ge->md, saved_keys[ge->keybuf_slot],
+ mkey, &keynum) == 0) {
+ return (0);
+ }
+ }
+
+ for (i = 0; i < nsaved_keys; i++) {
+ if (g_eli_mkey_decrypt(&ge->md, saved_keys[i], mkey,
+ &keynum) == 0) {
+ ge->keybuf_slot = i;
+ return (0);
+ }
+ }
+
+ return (1);
+}
+
void
geli_init(void)
{
@@ -123,6 +205,7 @@
if (dskp->part == 255) {
geli_e->dsk->part = dskp->slice;
}
+ geli_e->keybuf_slot = -1;
geli_e->md = md;
eli_metadata_softc(&geli_e->sc, &md, DEV_BSIZE,
@@ -138,18 +221,27 @@
* Attempt to decrypt the device
*/
int
-geli_attach(struct dsk *dskp, const char *passphrase)
+geli_attach(struct dsk *dskp, const char *passphrase, const u_char *mkeyp)
{
u_char key[G_ELI_USERKEYLEN], mkey[G_ELI_DATAIVKEYLEN], *mkp;
u_int keynum;
struct hmac_ctx ctx;
int error;
+ if (mkeyp != NULL) {
+ memcpy(&mkey, mkeyp, G_ELI_DATAIVKEYLEN);
+ explicit_bzero(mkeyp, G_ELI_DATAIVKEYLEN);
+ }
+
SLIST_FOREACH_SAFE(geli_e, &geli_head, entries, geli_e_tmp) {
if (geli_same_device(geli_e, dskp) != 0) {
continue;
}
+ if (mkeyp != NULL || geli_findkey(geli_e, dskp, mkey) == 0) {
+ goto found_key;
+ }
+
g_eli_crypto_hmac_init(&ctx, NULL, 0);
/*
* Prepare Derived-Key from the user passphrase.
@@ -179,17 +271,23 @@
g_eli_crypto_hmac_final(&ctx, key, 0);
error = g_eli_mkey_decrypt(&geli_e->md, key, mkey, &keynum);
- explicit_bzero(key, sizeof(key));
if (error == -1) {
explicit_bzero(mkey, sizeof(mkey));
- printf("Bad GELI key: %d\n", error);
+ explicit_bzero(key, sizeof(key));
+ printf("Bad GELI key: bad password?\n");
return (error);
} else if (error != 0) {
explicit_bzero(mkey, sizeof(mkey));
- printf("Failed to decrypt GELI master key: %d\n", error);
+ explicit_bzero(key, sizeof(key));
+ printf("Failed to decrypt GELI master key: %d\n", error);
return (error);
- }
+ } else {
+ /* Add key to keychain */
+ save_key(key);
+ explicit_bzero(&key, sizeof(key));
+ }
+found_key:
/* 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));
@@ -231,7 +329,7 @@
return (0);
}
}
-
+
return (1);
}
@@ -294,6 +392,27 @@
}
int
+geli_havekey(struct dsk *dskp)
+{
+ u_char mkey[G_ELI_DATAIVKEYLEN];
+
+ SLIST_FOREACH_SAFE(geli_e, &geli_head, entries, geli_e_tmp) {
+ if (geli_same_device(geli_e, dskp) != 0) {
+ continue;
+ }
+
+ if (geli_findkey(geli_e, dskp, mkey) == 0) {
+ if (geli_attach(dskp, NULL, mkey) == 0) {
+ return (0);
+ }
+ }
+ }
+ explicit_bzero(mkey, sizeof(mkey));
+
+ return (1);
+}
+
+int
geli_passphrase(char *pw, int disk, int parttype, int part, struct dsk *dskp)
{
int i;
@@ -302,14 +421,14 @@
for (i = 0; i < 3; i++) {
/* Try cached passphrase */
if (i == 0 && pw[0] != '\0') {
- if (geli_attach(dskp, pw) == 0) {
+ if (geli_attach(dskp, pw, NULL) == 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) {
+ if (geli_attach(dskp, pw, NULL) == 0) {
return (0);
}
}
Index: sys/boot/geli/geliboot_crypto.c
===================================================================
--- sys/boot/geli/geliboot_crypto.c
+++ sys/boot/geli/geliboot_crypto.c
@@ -31,6 +31,7 @@
#include <string.h>
#include <strings.h>
+#include "geliboot_internal.h"
#include "geliboot.h"
int
Index: sys/boot/geli/geliboot_internal.h
===================================================================
--- /dev/null
+++ sys/boot/geli/geliboot_internal.h
@@ -0,0 +1,69 @@
+/*-
+ * 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$
+ */
+
+#ifndef _GELIBOOT_INTERNAL_H_
+#define _GELIBOOT_INTERNAL_H_
+
+#define _STRING_H_
+#define _STRINGS_H_
+#define _STDIO_H_
+
+#include <sys/endian.h>
+#include <sys/queue.h>
+
+#include <geom/eli/g_eli.h>
+#include <geom/eli/pkcs5v2.h>
+
+#include <bootstrap.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>
+
+struct geli_entry {
+ struct dsk *dsk;
+ off_t part_end;
+ struct g_eli_softc sc;
+ struct g_eli_metadata md;
+ int keybuf_slot;
+ SLIST_ENTRY(geli_entry) entries;
+} *geli_e, *geli_e_tmp;
+
+static int geli_count;
+
+#endif /* _GELIBOOT_INTERNAL_H_ */
Index: sys/boot/i386/common/bootargs.h
===================================================================
--- sys/boot/i386/common/bootargs.h
+++ sys/boot/i386/common/bootargs.h
@@ -64,10 +64,28 @@
*/
};
+#ifdef LOADER_GELI_SUPPORT
+#include <crypto/intake.h>
+#endif
+
struct geli_boot_args
{
uint32_t size;
- char gelipw[256];
+ union {
+ char gelipw[256];
+ struct {
+ char notapw; /*
+ * single null byte to stop keybuf
+ * being interpreted as a password
+ */
+ uint32_t keybuf_sentinel;
+#ifdef LOADER_GELI_SUPPORT
+ struct keybuf *keybuf;
+#else
+ void *keybuf;
+#endif
+ };
+ };
};
#endif /*__ASSEMBLER__*/
Index: sys/boot/i386/gptboot/Makefile
===================================================================
--- sys/boot/i386/gptboot/Makefile
+++ sys/boot/i386/gptboot/Makefile
@@ -42,6 +42,7 @@
.if !defined(LOADER_NO_GELI_SUPPORT)
CFLAGS+= -DLOADER_GELI_SUPPORT
CFLAGS+= -I${.CURDIR}/../../geli
+CFLAGS+= -I${.CURDIR}/../../..
LIBGELIBOOT= ${.OBJDIR}/../../geli/libgeliboot.a
.PATH: ${.CURDIR}/../../../opencrypto
OPENCRYPTO_XTS= xform_aes_xts.o
Index: sys/boot/i386/gptboot/gptboot.c
===================================================================
--- sys/boot/i386/gptboot/gptboot.c
+++ sys/boot/i386/gptboot/gptboot.c
@@ -103,7 +103,7 @@
void exit(int);
static void load(void);
-static int parse(char *, int *);
+static int parse_cmds(char *, int *);
static int dskread(void *, daddr_t, unsigned);
void *malloc(size_t n);
void free(void *ptr);
@@ -139,6 +139,7 @@
#ifdef LOADER_GELI_SUPPORT
#include "geliboot.c"
static char gelipw[GELI_PW_MAXLEN];
+static struct keybuf *gelibuf;
#endif
static inline int
@@ -253,7 +254,8 @@
#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) {
+ if (geli_havekey(&dsk) != 0 && geli_passphrase(&gelipw,
+ dsk.unit, 'p', curent + 1, &dsk) != 0) {
printf("%s: unable to decrypt GELI key\n", BOOTPROG);
return (-1);
}
@@ -318,7 +320,7 @@
}
if (*cmd != '\0') {
memcpy(cmdtmp, cmd, sizeof(cmdtmp));
- if (parse(cmdtmp, &dskupdated))
+ if (parse_cmds(cmdtmp, &dskupdated))
break;
if (dskupdated && gptinit() != 0)
break;
@@ -368,7 +370,7 @@
getstr(cmd, sizeof(cmd));
else if (!OPT_CHECK(RBX_QUIET))
putchar('\n');
- if (parse(cmd, &dskupdated)) {
+ if (parse_cmds(cmd, &dskupdated)) {
putchar('\a');
continue;
}
@@ -479,9 +481,14 @@
bootinfo.bi_kernelname = VTOP(kname);
bootinfo.bi_bios_dev = dsk.drive;
#ifdef LOADER_GELI_SUPPORT
- geliargs.size = sizeof(geliargs);
- bcopy(gelipw, geliargs.gelipw, sizeof(geliargs.gelipw));
explicit_bzero(gelipw, sizeof(gelipw));
+ gelibuf = malloc(sizeof(struct keybuf) + (GELI_MAX_KEYS * sizeof(struct keybuf_ent)));
+ geli_fill_keybuf(gelibuf);
+ geliargs.notapw = '\0';
+ geliargs.keybuf_sentinel = KEYBUF_SENTINEL;
+ geliargs.keybuf = gelibuf;
+#else
+ geliargs.gelipw[0] = '\0';
#endif
__exec((caddr_t)addr, RB_BOOTINFO | (opts & RBX_MASK),
MAKEBOOTDEV(dev_maj[dsk.type], dsk.part + 1, dsk.unit, 0xff),
@@ -493,7 +500,7 @@
}
static int
-parse(char *cmdstr, int *dskupdated)
+parse_cmds(char *cmdstr, int *dskupdated)
{
char *arg = cmdstr;
char *ep, *p, *q;
Index: sys/boot/i386/libi386/biosdisk.c
===================================================================
--- sys/boot/i386/libi386/biosdisk.c
+++ sys/boot/i386/libi386/biosdisk.c
@@ -472,6 +472,11 @@
}
if (geli_taste(bios_read, &dskp,
entry->part.end - entry->part.start) == 0) {
+ if (geli_havekey(&dskp) == 0) {
+ geli_status[dev->d_unit][dskp.slice] = ISGELI_YES;
+ geli_part++;
+ continue;
+ }
if ((passphrase = getenv("kern.geom.eli.passphrase"))
!= NULL) {
/* Use the cached passphrase */
@@ -484,6 +489,7 @@
bzero(gelipw, sizeof(gelipw));
geli_status[dev->d_unit][dskp.slice] = ISGELI_YES;
geli_part++;
+ continue;
}
} else
geli_status[dev->d_unit][dskp.slice] = ISGELI_NO;
Index: sys/boot/i386/libi386/bootinfo32.c
===================================================================
--- sys/boot/i386/libi386/bootinfo32.c
+++ sys/boot/i386/libi386/bootinfo32.c
@@ -32,10 +32,18 @@
#include <sys/reboot.h>
#include <sys/linker.h>
#include <machine/bootinfo.h>
+#include <machine/metadata.h>
#include "bootstrap.h"
#include "libi386.h"
#include "btxv86.h"
+#ifdef LOADER_GELI_SUPPORT
+#include "geliboot.h"
+
+static const size_t keybuf_size = sizeof(struct keybuf) +
+ (GELI_MAX_KEYS * sizeof(struct keybuf_ent));
+#endif
+
static struct bootinfo bi;
/*
@@ -146,11 +154,15 @@
int bootdevnr, i, howto;
char *kernelname;
const char *kernelpath;
+#ifdef LOADER_GELI_SUPPORT
+ char buf[keybuf_size];
+ struct keybuf *keybuf = (struct keybuf *)buf;
+#endif
howto = bi_getboothowto(args);
- /*
- * Allow the environment variable 'rootdev' to override the supplied device
+ /*
+ * Allow the environment variable 'rootdev' to override the supplied device
* This should perhaps go to MI code and/or have $rootdev tested/set by
* MI code before launching the kernel.
*/
@@ -185,7 +197,7 @@
case DEVT_NET:
case DEVT_ZFS:
break;
-
+
default:
printf("WARNING - don't know how to boot from device type %d\n", rootdev->d_type);
}
@@ -221,6 +233,11 @@
file_addmetadata(kfp, MODINFOMD_ENVP, sizeof envp, &envp);
file_addmetadata(kfp, MODINFOMD_KERNEND, sizeof kernend, &kernend);
bios_addsmapdata(kfp);
+#ifdef LOADER_GELI_SUPPORT
+ geli_fill_keybuf(keybuf);
+ file_addmetadata(kfp, MODINFOMD_KEYBUF, keybuf_size, buf);
+ bzero(buf, sizeof(buf));
+#endif
/* Figure out the size and location of the metadata */
*modulep = addr;
Index: sys/boot/i386/libi386/bootinfo64.c
===================================================================
--- sys/boot/i386/libi386/bootinfo64.c
+++ sys/boot/i386/libi386/bootinfo64.c
@@ -40,6 +40,13 @@
#include "libi386.h"
#include "btxv86.h"
+#ifdef LOADER_GELI_SUPPORT
+#include "geliboot.h"
+
+static const size_t keybuf_size = sizeof(struct keybuf) +
+ (GELI_MAX_KEYS * sizeof(struct keybuf_ent));
+#endif
+
/*
* Copy module-related data into the load area, where it can be
* used as a directory for loaded modules.
@@ -189,6 +196,10 @@
vm_offset_t size;
char *rootdevname;
int howto;
+#ifdef LOADER_GELI_SUPPORT
+ char buf[keybuf_size];
+ struct keybuf *keybuf = (struct keybuf *)buf;
+#endif
if (!bi_checkcpu()) {
printf("CPU doesn't support long mode\n");
@@ -197,8 +208,8 @@
howto = bi_getboothowto(args);
- /*
- * Allow the environment variable 'rootdev' to override the supplied device
+ /*
+ * Allow the environment variable 'rootdev' to override the supplied device
* This should perhaps go to MI code and/or have $rootdev tested/set by
* MI code before launching the kernel.
*/
@@ -238,6 +249,12 @@
if (add_smap != 0)
bios_addsmapdata(kfp);
+#ifdef LOADER_GELI_SUPPORT
+ geli_fill_keybuf(keybuf);
+ file_addmetadata(kfp, MODINFOMD_KEYBUF, keybuf_size, buf);
+ bzero(buf, sizeof(buf));
+#endif
+
size = bi_copymodules64(0);
/* copy our environment */
Index: sys/boot/i386/loader/Makefile
===================================================================
--- sys/boot/i386/loader/Makefile
+++ sys/boot/i386/loader/Makefile
@@ -61,6 +61,7 @@
.endif
.if !defined(LOADER_NO_GELI_SUPPORT)
CFLAGS+= -DLOADER_GELI_SUPPORT
+CFLAGS+= -I${.CURDIR}/../../geli
LIBGELIBOOT= ${.OBJDIR}/../../geli/libgeliboot.a
.PATH: ${.CURDIR}/../../../opencrypto
SRCS+= xform_aes_xts.c
Index: sys/boot/i386/loader/main.c
===================================================================
--- sys/boot/i386/loader/main.c
+++ sys/boot/i386/loader/main.c
@@ -39,6 +39,7 @@
#include <machine/cpufunc.h>
#include <machine/psl.h>
#include <sys/reboot.h>
+#include <common/drv.h>
#include "bootstrap.h"
#include "common/bootargs.h"
@@ -69,6 +70,7 @@
static void isa_outb(int port, int value);
void exit(int code);
#ifdef LOADER_GELI_SUPPORT
+#include "geliboot.h"
struct geli_boot_args *gargs;
#endif
#ifdef LOADER_ZFS_SUPPORT
@@ -173,6 +175,10 @@
if ((kargs->bootflags & KARGS_FLAGS_EXTARG) != 0) {
zargs = (struct zfs_boot_args *)(kargs + 1);
if (zargs != NULL && zargs->size >= offsetof(struct zfs_boot_args, gelipw)) {
+ if (zargs->size >= offsetof(struct zfs_boot_args, keybuf_sentinel) &&
+ zargs->keybuf_sentinel == KEYBUF_SENTINEL) {
+ geli_save_keybuf(zargs->keybuf);
+ }
if (zargs->gelipw[0] != '\0') {
setenv("kern.geom.eli.passphrase", zargs->gelipw, 1);
explicit_bzero(zargs->gelipw, sizeof(zargs->gelipw));
@@ -185,6 +191,9 @@
if ((kargs->bootflags & KARGS_FLAGS_EXTARG) != 0) {
gargs = (struct geli_boot_args *)(kargs + 1);
if (gargs != NULL && gargs->size >= offsetof(struct geli_boot_args, gelipw)) {
+ if (gargs->keybuf_sentinel == KEYBUF_SENTINEL) {
+ geli_save_keybuf(gargs->keybuf);
+ }
if (gargs->gelipw[0] != '\0') {
setenv("kern.geom.eli.passphrase", gargs->gelipw, 1);
explicit_bzero(gargs->gelipw, sizeof(gargs->gelipw));
Index: sys/boot/i386/zfsboot/zfsboot.c
===================================================================
--- sys/boot/i386/zfsboot/zfsboot.c
+++ sys/boot/i386/zfsboot/zfsboot.c
@@ -121,7 +121,7 @@
void exit(int);
void reboot(void);
static void load(void);
-static int parse(void);
+static int parse_cmd(void);
static void bios_getmem(void);
void *malloc(size_t n);
void free(void *ptr);
@@ -159,6 +159,7 @@
#ifdef LOADER_GELI_SUPPORT
#include "geliboot.c"
static char gelipw[GELI_PW_MAXLEN];
+static struct keybuf *gelibuf;
#endif
#include "zfsimpl.c"
@@ -398,7 +399,7 @@
v86.ctl = 0;
v86.addr = 0x12; /* int 0x12 */
v86int();
-
+
bios_basemem = (v86.eax & 0xffff) * 1024;
}
@@ -442,7 +443,7 @@
v86.eax = 0x800;
v86.edx = drive;
v86int();
-
+
if (!V86_CY(v86.efl) && /* carry clear */
((v86.edx & 0xff) != (drive & DRV_MASK))) { /* unit # OK */
if ((v86.ecx & 0x3f) == 0) { /* absurd sector size */
@@ -502,7 +503,8 @@
elba--;
}
if (geli_taste(vdev_read, dsk, elba) == 0) {
- if (geli_passphrase(&gelipw, dsk->unit, ':', 0, dsk) == 0) {
+ if (geli_havekey(dsk) == 0 || geli_passphrase(&gelipw, dsk->unit,
+ ':', 0, dsk) == 0) {
if (vdev_probe(vdev_read, dsk, NULL) == 0) {
return;
}
@@ -559,7 +561,8 @@
#ifdef LOADER_GELI_SUPPORT
else if (geli_taste(vdev_read, dsk, ent->ent_lba_end -
ent->ent_lba_start) == 0) {
- if (geli_passphrase(&gelipw, dsk->unit, 'p', dsk->slice, dsk) == 0) {
+ if (geli_havekey(dsk) == 0 || geli_passphrase(&gelipw,
+ dsk->unit, 'p', dsk->slice, dsk) == 0) {
/*
* This slice has GELI, check it for ZFS.
*/
@@ -597,7 +600,8 @@
#ifdef LOADER_GELI_SUPPORT
else if (geli_taste(vdev_read, dsk, dp[i].dp_size -
dp[i].dp_start) == 0) {
- if (geli_passphrase(&gelipw, dsk->unit, 's', i, dsk) == 0) {
+ if (geli_havekey(dsk) == 0 || geli_passphrase(&gelipw, dsk->unit,
+ 's', i, dsk) == 0) {
/*
* This slice has GELI, check it for ZFS.
*/
@@ -729,7 +733,7 @@
*/
nextboot = 1;
memcpy(cmddup, cmd, sizeof(cmd));
- if (parse()) {
+ if (parse_cmd()) {
printf("failed to parse pad2 area of primary vdev\n");
reboot();
}
@@ -756,11 +760,11 @@
if (*cmd) {
/*
- * Note that parse() is destructive to cmd[] and we also want
+ * Note that parse_cmd() is destructive to cmd[] and we also want
* to honor RBX_QUIET option that could be present in cmd[].
*/
memcpy(cmddup, cmd, sizeof(cmd));
- if (parse())
+ if (parse_cmd())
autoboot = 0;
if (!OPT_CHECK(RBX_QUIET))
printf("%s: %s\n", PATH_CONFIG, cmddup);
@@ -810,7 +814,7 @@
else if (!autoboot || !OPT_CHECK(RBX_QUIET))
putchar('\n');
autoboot = 0;
- if (parse())
+ if (parse_cmd())
putchar('\a');
else
load();
@@ -925,8 +929,12 @@
zfsargs.root = zfsmount.rootobj;
zfsargs.primary_pool = primary_spa->spa_guid;
#ifdef LOADER_GELI_SUPPORT
- bcopy(gelipw, zfsargs.gelipw, sizeof(zfsargs.gelipw));
explicit_bzero(gelipw, sizeof(gelipw));
+ gelibuf = malloc(sizeof(struct keybuf) + (GELI_MAX_KEYS * sizeof(struct keybuf_ent)));
+ geli_fill_keybuf(gelibuf);
+ zfsargs.notapw = '\0';
+ zfsargs.keybuf_sentinel = KEYBUF_SENTINEL;
+ zfsargs.keybuf = gelibuf;
#else
zfsargs.gelipw[0] = '\0';
#endif
@@ -979,7 +987,7 @@
}
static int
-parse(void)
+parse_cmd(void)
{
char *arg = cmd;
char *ep, *p, *q;
Index: sys/boot/zfs/libzfs.h
===================================================================
--- sys/boot/zfs/libzfs.h
+++ sys/boot/zfs/libzfs.h
@@ -47,6 +47,10 @@
uint64_t root_guid;
};
+#ifdef LOADER_GELI_SUPPORT
+#include <crypto/intake.h>
+#endif
+
struct zfs_boot_args
{
uint32_t size;
@@ -55,7 +59,21 @@
uint64_t root;
uint64_t primary_pool;
uint64_t primary_vdev;
- char gelipw[256];
+ union {
+ char gelipw[256];
+ struct {
+ char notapw; /*
+ * single null byte to stop keybuf
+ * being interpreted as a password
+ */
+ uint32_t keybuf_sentinel;
+#ifdef LOADER_GELI_SUPPORT
+ struct keybuf *keybuf;
+#else
+ void *keybuf;
+#endif
+ };
+ };
};
int zfs_parsedev(struct zfs_devdesc *dev, const char *devspec,
Index: sys/crypto/intake.h
===================================================================
--- /dev/null
+++ sys/crypto/intake.h
@@ -0,0 +1,64 @@
+/*-
+ * Copyright (c) 2017 Eric McCorkle
+ * 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 AUTHOR 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 AUTHOR 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$
+ */
+
+#ifndef _INTAKE_H_
+#define _INTAKE_H_
+
+#include <sys/param.h>
+
+/*
+ * This file provides an interface for providing keys to the kernel
+ * during boot time.
+ */
+
+#define MAX_KEY_BITS 4096
+#define MAX_KEY_BYTES (MAX_KEY_BITS / NBBY)
+
+#define KEYBUF_SENTINEL 0xcee54b5d /* KEYS4BSD */
+
+enum {
+ KEYBUF_TYPE_NONE,
+ KEYBUF_TYPE_GELI
+};
+
+struct keybuf_ent {
+ unsigned int ke_type;
+ char ke_data[MAX_KEY_BYTES];
+};
+
+struct keybuf {
+ unsigned int kb_nents;
+ struct keybuf_ent kb_ents[];
+};
+
+#ifdef _KERNEL
+/* Get the key intake buffer */
+extern struct keybuf* get_keybuf(void);
+#endif
+
+#endif
Index: sys/geom/eli/g_eli.h
===================================================================
--- sys/geom/eli/g_eli.h
+++ sys/geom/eli/g_eli.h
@@ -41,6 +41,7 @@
#include <sys/lock.h>
#include <sys/mutex.h>
#include <geom/geom.h>
+#include <crypto/intake.h>
#else
#include <assert.h>
#include <stdio.h>
@@ -139,6 +140,10 @@
#define G_ELI_CRYPTO_SW 2
#ifdef _KERNEL
+#if (MAX_KEY_BYTES < G_ELI_DATAIVKEYLEN)
+#error "MAX_KEY_BYTES is less than G_ELI_DATAKEYLEN"
+#endif
+
extern int g_eli_debug;
extern u_int g_eli_overwrites;
extern u_int g_eli_batch;
Index: sys/geom/eli/g_eli.c
===================================================================
--- sys/geom/eli/g_eli.c
+++ sys/geom/eli/g_eli.c
@@ -53,6 +53,8 @@
#include <geom/eli/g_eli.h>
#include <geom/eli/pkcs5v2.h>
+#include <crypto/intake.h>
+
FEATURE(geom_eli, "GEOM crypto module");
MALLOC_DEFINE(M_ELI, "eli data", "GEOM_ELI Data");
@@ -111,13 +113,39 @@
}
SYSINIT(geli_fetch_loader_passphrase, SI_SUB_KMEM + 1, SI_ORDER_ANY,
fetch_loader_passphrase, NULL);
+
static void
-zero_boot_passcache(void * dummy)
+zero_boot_passcache(void)
{
- memset(cached_passphrase, 0, sizeof(cached_passphrase));
+ explicit_bzero(cached_passphrase, sizeof(cached_passphrase));
+}
+
+static void
+zero_geli_intake_keys(void)
+{
+ struct keybuf *keybuf;
+ int i;
+
+ if ((keybuf = get_keybuf()) != NULL) {
+ /* Scan the key buffer, clear all GELI keys. */
+ for (i = 0; i < keybuf->kb_nents; i++) {
+ if (keybuf->kb_ents[i].ke_type == KEYBUF_TYPE_GELI) {
+ explicit_bzero(keybuf->kb_ents[i].ke_data,
+ sizeof(keybuf->kb_ents[i].ke_data));
+ keybuf->kb_ents[i].ke_type = KEYBUF_TYPE_NONE;
+ }
+ }
+ }
+}
+
+static void
+zero_intake_passcache(void *dummy)
+{
+ zero_boot_passcache();
+ zero_geli_intake_keys();
}
-EVENTHANDLER_DEFINE(mountroot, zero_boot_passcache, NULL, 0);
+EVENTHANDLER_DEFINE(mountroot, zero_intake_passcache, NULL, 0);
static eventhandler_tag g_eli_pre_sync = NULL;
@@ -997,6 +1025,7 @@
u_char key[G_ELI_USERKEYLEN], mkey[G_ELI_DATAIVKEYLEN];
u_int i, nkey, nkeyfiles, tries;
int error;
+ struct keybuf *keybuf;
g_trace(G_T_TOPOLOGY, "%s(%s, %s)", __func__, mp->name, pp->name);
g_topology_assert();
@@ -1035,97 +1064,114 @@
tries = g_eli_tries;
}
- for (i = 0; i <= tries; i++) {
- g_eli_crypto_hmac_init(&ctx, NULL, 0);
-
- /*
- * Load all key files.
- */
- nkeyfiles = g_eli_keyfiles_load(&ctx, pp->name);
-
- if (nkeyfiles == 0 && md.md_iterations == -1) {
- /*
- * No key files and no passphrase, something is
- * definitely wrong here.
- * geli(8) doesn't allow for such situation, so assume
- * that there was really no passphrase and in that case
- * key files are no properly defined in loader.conf.
- */
- G_ELI_DEBUG(0,
- "Found no key files in loader.conf for %s.",
- pp->name);
- return (NULL);
- }
-
- /* Ask for the passphrase if defined. */
- if (md.md_iterations >= 0) {
- /* Try first with cached passphrase. */
- if (i == 0) {
- if (!g_eli_boot_passcache)
- continue;
- memcpy(passphrase, cached_passphrase,
- sizeof(passphrase));
- } else {
- printf("Enter passphrase for %s: ", pp->name);
- cngets(passphrase, sizeof(passphrase),
- g_eli_visible_passphrase);
- memcpy(cached_passphrase, passphrase,
- sizeof(passphrase));
- }
- }
-
- /*
- * Prepare Derived-Key from the user passphrase.
- */
- if (md.md_iterations == 0) {
- g_eli_crypto_hmac_update(&ctx, md.md_salt,
- sizeof(md.md_salt));
- g_eli_crypto_hmac_update(&ctx, passphrase,
- strlen(passphrase));
- bzero(passphrase, sizeof(passphrase));
- } else if (md.md_iterations > 0) {
- u_char dkey[G_ELI_USERKEYLEN];
-
- pkcs5v2_genkey(dkey, sizeof(dkey), md.md_salt,
- sizeof(md.md_salt), passphrase, md.md_iterations);
- bzero(passphrase, sizeof(passphrase));
- g_eli_crypto_hmac_update(&ctx, dkey, sizeof(dkey));
- bzero(dkey, sizeof(dkey));
- }
-
- g_eli_crypto_hmac_final(&ctx, key, 0);
-
- /*
- * Decrypt Master-Key.
- */
- error = g_eli_mkey_decrypt(&md, key, mkey, &nkey);
- bzero(key, sizeof(key));
- if (error == -1) {
- if (i == tries) {
- G_ELI_DEBUG(0,
- "Wrong key for %s. No tries left.",
- pp->name);
- g_eli_keyfiles_clear(pp->name);
- return (NULL);
- }
- if (i > 0) {
- G_ELI_DEBUG(0,
- "Wrong key for %s. Tries left: %u.",
- pp->name, tries - i);
- }
- /* Try again. */
- continue;
- } else if (error > 0) {
- G_ELI_DEBUG(0,
- "Cannot decrypt Master Key for %s (error=%d).",
- pp->name, error);
- g_eli_keyfiles_clear(pp->name);
- return (NULL);
- }
- g_eli_keyfiles_clear(pp->name);
- G_ELI_DEBUG(1, "Using Master Key %u for %s.", nkey, pp->name);
- break;
- }
+ if ((keybuf = get_keybuf()) != NULL) {
+ /* Scan the key buffer, try all GELI keys. */
+ for (i = 0; i < keybuf->kb_nents; i++) {
+ if (keybuf->kb_ents[i].ke_type == KEYBUF_TYPE_GELI) {
+ memcpy(key, keybuf->kb_ents[i].ke_data,
+ sizeof(key));
+
+ if (g_eli_mkey_decrypt(&md, key,
+ mkey, &nkey) == 0 ) {
+ explicit_bzero(key, sizeof(key));
+ goto have_key;
+ }
+ }
+ }
+ }
+
+ for (i = 0; i <= tries; i++) {
+ g_eli_crypto_hmac_init(&ctx, NULL, 0);
+
+ /*
+ * Load all key files.
+ */
+ nkeyfiles = g_eli_keyfiles_load(&ctx, pp->name);
+
+ if (nkeyfiles == 0 && md.md_iterations == -1) {
+ /*
+ * No key files and no passphrase, something is
+ * definitely wrong here.
+ * geli(8) doesn't allow for such situation, so assume
+ * that there was really no passphrase and in that case
+ * key files are no properly defined in loader.conf.
+ */
+ G_ELI_DEBUG(0,
+ "Found no key files in loader.conf for %s.",
+ pp->name);
+ return (NULL);
+ }
+
+ /* Ask for the passphrase if defined. */
+ if (md.md_iterations >= 0) {
+ /* Try first with cached passphrase. */
+ if (i == 0) {
+ if (!g_eli_boot_passcache)
+ continue;
+ memcpy(passphrase, cached_passphrase,
+ sizeof(passphrase));
+ } else {
+ printf("Enter passphrase for %s: ", pp->name);
+ cngets(passphrase, sizeof(passphrase),
+ g_eli_visible_passphrase);
+ memcpy(cached_passphrase, passphrase,
+ sizeof(passphrase));
+ }
+ }
+
+ /*
+ * Prepare Derived-Key from the user passphrase.
+ */
+ if (md.md_iterations == 0) {
+ g_eli_crypto_hmac_update(&ctx, md.md_salt,
+ sizeof(md.md_salt));
+ g_eli_crypto_hmac_update(&ctx, passphrase,
+ strlen(passphrase));
+ explicit_bzero(passphrase, sizeof(passphrase));
+ } else if (md.md_iterations > 0) {
+ u_char dkey[G_ELI_USERKEYLEN];
+
+ pkcs5v2_genkey(dkey, sizeof(dkey), md.md_salt,
+ sizeof(md.md_salt), passphrase, md.md_iterations);
+ bzero(passphrase, sizeof(passphrase));
+ g_eli_crypto_hmac_update(&ctx, dkey, sizeof(dkey));
+ explicit_bzero(dkey, sizeof(dkey));
+ }
+
+ g_eli_crypto_hmac_final(&ctx, key, 0);
+
+ /*
+ * Decrypt Master-Key.
+ */
+ error = g_eli_mkey_decrypt(&md, key, mkey, &nkey);
+ bzero(key, sizeof(key));
+ if (error == -1) {
+ if (i == tries) {
+ G_ELI_DEBUG(0,
+ "Wrong key for %s. No tries left.",
+ pp->name);
+ g_eli_keyfiles_clear(pp->name);
+ return (NULL);
+ }
+ if (i > 0) {
+ G_ELI_DEBUG(0,
+ "Wrong key for %s. Tries left: %u.",
+ pp->name, tries - i);
+ }
+ /* Try again. */
+ continue;
+ } else if (error > 0) {
+ G_ELI_DEBUG(0,
+ "Cannot decrypt Master Key for %s (error=%d).",
+ pp->name, error);
+ g_eli_keyfiles_clear(pp->name);
+ return (NULL);
+ }
+ g_eli_keyfiles_clear(pp->name);
+ G_ELI_DEBUG(1, "Using Master Key %u for %s.", nkey, pp->name);
+ break;
+ }
+have_key:
/*
* We have correct key, let's attach provider.
Index: sys/opencrypto/crypto.c
===================================================================
--- sys/opencrypto/crypto.c
+++ sys/opencrypto/crypto.c
@@ -63,6 +63,7 @@
#include <sys/eventhandler.h>
#include <sys/kernel.h>
#include <sys/kthread.h>
+#include <sys/linker.h>
#include <sys/lock.h>
#include <sys/module.h>
#include <sys/mutex.h>
@@ -74,6 +75,7 @@
#include <ddb/ddb.h>
#include <vm/uma.h>
+#include <crypto/intake.h>
#include <opencrypto/cryptodev.h>
#include <opencrypto/xform.h> /* XXX for M_XDATA */
@@ -84,6 +86,7 @@
#if defined(__i386__) || defined(__amd64__) || defined(__aarch64__)
#include <machine/pcb.h>
#endif
+#include <machine/metadata.h>
SDT_PROVIDER_DEFINE(opencrypto);
@@ -186,6 +189,37 @@
&crypto_timing, 0, "Enable/disable crypto timing support");
#endif
+/* Try to avoid directly exposing the key buffer as a symbol */
+static struct keybuf *keybuf;
+
+static struct keybuf empty_keybuf = {
+ .kb_nents = 0
+};
+
+/* Obtain the key buffer from boot metadata */
+static void
+keybuf_init(void)
+{
+ caddr_t kmdp;
+
+ kmdp = preload_search_by_type("elf kernel");
+
+ if (kmdp == NULL)
+ kmdp = preload_search_by_type("elf64 kernel");
+
+ keybuf = (struct keybuf *)preload_search_info(kmdp,
+ MODINFO_METADATA | MODINFOMD_KEYBUF);
+
+ if (keybuf == NULL)
+ keybuf = &empty_keybuf;
+}
+
+/* It'd be nice if we could store these in some kind of secure memory... */
+struct keybuf * get_keybuf(void) {
+
+ return (keybuf);
+}
+
static int
crypto_init(void)
{
@@ -238,6 +272,9 @@
error);
goto bad;
}
+
+ keybuf_init();
+
return 0;
bad:
crypto_destroy();
@@ -282,7 +319,7 @@
/* XXX flush queues??? */
- /*
+ /*
* Reclaim dynamically allocated resources.
*/
if (crypto_drivers != NULL)
Index: sys/sys/linker.h
===================================================================
--- sys/sys/linker.h
+++ sys/sys/linker.h
@@ -143,7 +143,7 @@
* Lookup a symbol in a file. If deps is TRUE, look in dependencies
* if not found in file.
*/
-caddr_t linker_file_lookup_symbol(linker_file_t _file, const char* _name,
+caddr_t linker_file_lookup_symbol(linker_file_t _file, const char* _name,
int _deps);
/*
@@ -157,7 +157,7 @@
/*
* List all functions in a file.
*/
-int linker_file_function_listall(linker_file_t,
+int linker_file_function_listall(linker_file_t,
linker_function_nameval_callback_t, void *);
/*
@@ -217,6 +217,7 @@
#define MODINFOMD_CTORS_ADDR 0x000a /* address of .ctors */
#define MODINFOMD_CTORS_SIZE 0x000b /* size of .ctors */
#define MODINFOMD_FW_HANDLE 0x000c /* Firmware dependent handle */
+#define MODINFOMD_KEYBUF 0x000d /* Crypto key intake buffer */
#define MODINFOMD_NOCOPY 0x8000 /* don't copy this metadata to the kernel */
#define MODINFOMD_DEPLIST (0x4001 | MODINFOMD_NOCOPY) /* depends on */

File Metadata

Mime Type
text/plain
Expires
Thu, Nov 27, 3:44 PM (11 h, 22 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
26258491
Default Alt Text
D9575.id26867.diff (39 KB)

Event Timeline