Implement boot-time encryption key passing (keybuf)
This patch adds a general mechanism for providing encryption keys to the kernel from the boot loader. This is intended to enable GELI support at boot time, providing a better mechanism for passing keys to the kernel than environment variables. It is designed to be extensible to other applications, and can easily handle multiple encrypted volumes with different keys. This mechanism is currently used by the pending GELI EFI work. Additionally, this mechanism can potentially be used to interface with GRUB, opening up options for coreboot+GRUB configurations with completely encrypted disks. Another benefit over the existing system is that it does not require re-deriving the user key from the password at each boot stage. Most of this patch was written by Eric McCorkle. It was extended by Allan Jude with a number of minor enhancements and extending the keybuf feature into boot2. GELI user keys are now derived once, in boot2, then passed to the loader, which reuses the key, then passes it to the kernel, where the GELI module destroys the keybuf after decrypting the volumes. Submitted by: Eric McCorkle <eric@metricspace.net> (Original Version) Reviewed by: oshogbo (earlier version), cem (earlier version) MFC after: 3 weeks Relnotes: yes Sponsored by: ScaleEngine Inc. Differential Revision: https://reviews.freebsd.org/D9575
This commit is contained in:
parent
36721468a4
commit
6a205a3252
@ -39,6 +39,7 @@ SRCS+= md5c.c
|
||||
# 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
|
||||
|
@ -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 @@ geli_same_device(struct geli_entry *ge, struct dsk *dskp)
|
||||
}
|
||||
|
||||
/* 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 @@ geli_taste(int read_func(void *vdev, void *priv, off_t off, void *buf,
|
||||
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 @@ geli_taste(int read_func(void *vdev, void *priv, off_t off, void *buf,
|
||||
* 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 @@ geli_attach(struct dsk *dskp, const char *passphrase)
|
||||
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 @@ is_geli(struct dsk *dskp)
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return (1);
|
||||
}
|
||||
|
||||
@ -293,6 +391,27 @@ geli_read(struct dsk *dskp, off_t offset, u_char *buf, size_t bytes)
|
||||
return (1);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
@ -302,14 +421,14 @@ geli_passphrase(char *pw, int disk, int parttype, int part, struct dsk *dskp)
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
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_ */
|
||||
|
@ -31,6 +31,7 @@
|
||||
#include <string.h>
|
||||
#include <strings.h>
|
||||
|
||||
#include "geliboot_internal.h"
|
||||
#include "geliboot.h"
|
||||
|
||||
int
|
||||
|
69
sys/boot/geli/geliboot_internal.h
Normal file
69
sys/boot/geli/geliboot_internal.h
Normal file
@ -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_ */
|
@ -64,10 +64,28 @@ struct bootargs
|
||||
*/
|
||||
};
|
||||
|
||||
#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__*/
|
||||
|
@ -42,6 +42,7 @@ CFLAGS.gcc+= --param max-inline-insns-single=100
|
||||
.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
|
||||
|
@ -103,7 +103,7 @@ static char *heap_end;
|
||||
|
||||
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 @@ free(void *ptr)
|
||||
#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 @@ gptinit(void)
|
||||
#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 @@ main(void)
|
||||
}
|
||||
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 @@ main(void)
|
||||
getstr(cmd, sizeof(cmd));
|
||||
else if (!OPT_CHECK(RBX_QUIET))
|
||||
putchar('\n');
|
||||
if (parse(cmd, &dskupdated)) {
|
||||
if (parse_cmds(cmd, &dskupdated)) {
|
||||
putchar('\a');
|
||||
continue;
|
||||
}
|
||||
@ -480,8 +482,12 @@ load(void)
|
||||
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;
|
||||
#endif
|
||||
__exec((caddr_t)addr, RB_BOOTINFO | (opts & RBX_MASK),
|
||||
MAKEBOOTDEV(dev_maj[dsk.type], dsk.part + 1, dsk.unit, 0xff),
|
||||
@ -493,7 +499,7 @@ load(void)
|
||||
}
|
||||
|
||||
static int
|
||||
parse(char *cmdstr, int *dskupdated)
|
||||
parse_cmds(char *cmdstr, int *dskupdated)
|
||||
{
|
||||
char *arg = cmdstr;
|
||||
char *ep, *p, *q;
|
||||
|
@ -472,6 +472,11 @@ bd_open(struct open_file *f, ...)
|
||||
}
|
||||
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 @@ bd_open(struct open_file *f, ...)
|
||||
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;
|
||||
|
@ -32,10 +32,18 @@ __FBSDID("$FreeBSD$");
|
||||
#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 @@ bi_load32(char *args, int *howtop, int *bootdevp, vm_offset_t *bip, vm_offset_t
|
||||
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 @@ bi_load32(char *args, int *howtop, int *bootdevp, vm_offset_t *bip, vm_offset_t
|
||||
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 @@ bi_load32(char *args, int *howtop, int *bootdevp, vm_offset_t *bip, vm_offset_t
|
||||
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;
|
||||
|
@ -40,6 +40,13 @@ __FBSDID("$FreeBSD$");
|
||||
#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 @@ bi_load64(char *args, vm_offset_t addr, vm_offset_t *modulep,
|
||||
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 @@ bi_load64(char *args, vm_offset_t addr, vm_offset_t *modulep,
|
||||
|
||||
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 @@ bi_load64(char *args, vm_offset_t addr, vm_offset_t *modulep,
|
||||
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 */
|
||||
|
@ -61,6 +61,7 @@ CFLAGS+= -DLOADER_NANDFS_SUPPORT
|
||||
.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
|
||||
|
@ -39,6 +39,7 @@ __FBSDID("$FreeBSD$");
|
||||
#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 int isa_inb(int port);
|
||||
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 @@ main(void)
|
||||
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 @@ main(void)
|
||||
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));
|
||||
|
@ -121,7 +121,7 @@ static struct dmadat *dmadat;
|
||||
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 @@ strdup(const char *s)
|
||||
#ifdef LOADER_GELI_SUPPORT
|
||||
#include "geliboot.c"
|
||||
static char gelipw[GELI_PW_MAXLEN];
|
||||
static struct keybuf *gelibuf;
|
||||
#endif
|
||||
|
||||
#include "zfsimpl.c"
|
||||
@ -502,7 +503,8 @@ probe_drive(struct dsk *dsk)
|
||||
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 @@ probe_drive(struct dsk *dsk)
|
||||
#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 @@ probe_drive(struct dsk *dsk)
|
||||
#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 @@ main(void)
|
||||
*/
|
||||
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 @@ main(void)
|
||||
|
||||
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 @@ main(void)
|
||||
else if (!autoboot || !OPT_CHECK(RBX_QUIET))
|
||||
putchar('\n');
|
||||
autoboot = 0;
|
||||
if (parse())
|
||||
if (parse_cmd())
|
||||
putchar('\a');
|
||||
else
|
||||
load();
|
||||
@ -925,8 +929,12 @@ load(void)
|
||||
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 @@ zfs_mount_ds(char *dsname)
|
||||
}
|
||||
|
||||
static int
|
||||
parse(void)
|
||||
parse_cmd(void)
|
||||
{
|
||||
char *arg = cmd;
|
||||
char *ep, *p, *q;
|
||||
|
@ -47,6 +47,10 @@ struct zfs_devdesc
|
||||
uint64_t root_guid;
|
||||
};
|
||||
|
||||
#ifdef LOADER_GELI_SUPPORT
|
||||
#include <crypto/intake.h>
|
||||
#endif
|
||||
|
||||
struct zfs_boot_args
|
||||
{
|
||||
uint32_t size;
|
||||
@ -55,7 +59,21 @@ struct zfs_boot_args
|
||||
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,
|
||||
|
64
sys/crypto/intake.h
Normal file
64
sys/crypto/intake.h
Normal file
@ -0,0 +1,64 @@
|
||||
/*-
|
||||
* Copyright (c) 2016 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
|
@ -53,6 +53,8 @@ __FBSDID("$FreeBSD$");
|
||||
#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 @@ fetch_loader_passphrase(void * dummy)
|
||||
}
|
||||
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));
|
||||
}
|
||||
EVENTHANDLER_DEFINE(mountroot, zero_boot_passcache, NULL, 0);
|
||||
|
||||
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_intake_passcache, NULL, 0);
|
||||
|
||||
static eventhandler_tag g_eli_pre_sync = NULL;
|
||||
|
||||
@ -997,6 +1025,7 @@ g_eli_taste(struct g_class *mp, struct g_provider *pp, int flags __unused)
|
||||
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 @@ g_eli_taste(struct g_class *mp, struct g_provider *pp, int flags __unused)
|
||||
tries = g_eli_tries;
|
||||
}
|
||||
|
||||
for (i = 0; i <= tries; i++) {
|
||||
g_eli_crypto_hmac_init(&ctx, NULL, 0);
|
||||
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));
|
||||
|
||||
/*
|
||||
* Load all key files.
|
||||
*/
|
||||
nkeyfiles = g_eli_keyfiles_load(&ctx, pp->name);
|
||||
if (g_eli_mkey_decrypt(&md, key,
|
||||
mkey, &nkey) == 0 ) {
|
||||
explicit_bzero(key, sizeof(key));
|
||||
goto have_key;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
for (i = 0; i <= tries; i++) {
|
||||
g_eli_crypto_hmac_init(&ctx, NULL, 0);
|
||||
|
||||
/* 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));
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Load all key files.
|
||||
*/
|
||||
nkeyfiles = g_eli_keyfiles_load(&ctx, pp->name);
|
||||
|
||||
/*
|
||||
* 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];
|
||||
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);
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
/* 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));
|
||||
}
|
||||
}
|
||||
|
||||
g_eli_crypto_hmac_final(&ctx, key, 0);
|
||||
/*
|
||||
* 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];
|
||||
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
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.
|
||||
|
@ -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;
|
||||
|
@ -63,6 +63,7 @@ __FBSDID("$FreeBSD$");
|
||||
#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 @@ __FBSDID("$FreeBSD$");
|
||||
#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 @@ __FBSDID("$FreeBSD$");
|
||||
#if defined(__i386__) || defined(__amd64__) || defined(__aarch64__)
|
||||
#include <machine/pcb.h>
|
||||
#endif
|
||||
#include <machine/metadata.h>
|
||||
|
||||
SDT_PROVIDER_DEFINE(opencrypto);
|
||||
|
||||
@ -186,6 +189,37 @@ SYSCTL_INT(_debug, OID_AUTO, crypto_timing, CTLFLAG_RW,
|
||||
&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 @@ crypto_init(void)
|
||||
error);
|
||||
goto bad;
|
||||
}
|
||||
|
||||
keybuf_init();
|
||||
|
||||
return 0;
|
||||
bad:
|
||||
crypto_destroy();
|
||||
@ -282,7 +319,7 @@ crypto_destroy(void)
|
||||
|
||||
/* XXX flush queues??? */
|
||||
|
||||
/*
|
||||
/*
|
||||
* Reclaim dynamically allocated resources.
|
||||
*/
|
||||
if (crypto_drivers != NULL)
|
||||
|
@ -143,7 +143,7 @@ int linker_file_foreach(linker_predicate_t *_predicate, void *_context);
|
||||
* 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 @@ int linker_file_lookup_set(linker_file_t _file, const char *_name,
|
||||
/*
|
||||
* 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 @@ void *linker_hwpmc_list_objects(void);
|
||||
#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 */
|
||||
|
Loading…
Reference in New Issue
Block a user