summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStefan Sperling <stsp@cvs.openbsd.org>2013-10-20 13:25:22 +0000
committerStefan Sperling <stsp@cvs.openbsd.org>2013-10-20 13:25:22 +0000
commit4f1aa8321d9150707370a6c40391a5628001177c (patch)
tree2c1d1929e6fe8663886192867ef17cfaeb1eb242
parent61bd4a4131e18bb24f2ad10a92eb864d8c2b205c (diff)
Add i386/amd64 boot(8) support for keydisk-based softraid crypto volumes.
So far, only passphrase-based crypto volumes were bootable. Full disk encryption with keydisks required a non-crypto partition to load the kernel. The bootloader now scans all BIOS-visible disks for RAID partitions and automatically associates keydisk partitions with their crypto volume. Attempting to boot from a volume without its keydisk currently results in a passphrase prompt (this might be changed in the future). There is no need to re-create existing volumes. Moving the root partition onto the crypto disk and running installboot(8) is all that's needed. help & ok jsing
-rw-r--r--sys/arch/amd64/stand/boot/conf.c4
-rw-r--r--sys/arch/amd64/stand/libsa/softraid.c110
-rw-r--r--sys/arch/i386/stand/boot/conf.c4
-rw-r--r--sys/arch/i386/stand/cdboot/conf.c4
-rw-r--r--sys/arch/i386/stand/libsa/softraid.c110
-rw-r--r--sys/arch/i386/stand/pxeboot/conf.c4
6 files changed, 178 insertions, 58 deletions
diff --git a/sys/arch/amd64/stand/boot/conf.c b/sys/arch/amd64/stand/boot/conf.c
index 4587d194a94..152792e4701 100644
--- a/sys/arch/amd64/stand/boot/conf.c
+++ b/sys/arch/amd64/stand/boot/conf.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: conf.c,v 1.26 2012/10/27 15:43:42 jsing Exp $ */
+/* $OpenBSD: conf.c,v 1.27 2013/10/20 13:25:20 stsp Exp $ */
/*
* Copyright (c) 1996 Michael Shalayeff
@@ -42,7 +42,7 @@
#include <biosdev.h>
#include <dev/cons.h>
-const char version[] = "3.23";
+const char version[] = "3.24";
int debug = 1;
diff --git a/sys/arch/amd64/stand/libsa/softraid.c b/sys/arch/amd64/stand/libsa/softraid.c
index c9ef0d6937c..b98ec2ef680 100644
--- a/sys/arch/amd64/stand/libsa/softraid.c
+++ b/sys/arch/amd64/stand/libsa/softraid.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: softraid.c,v 1.4 2013/06/11 16:42:07 deraadt Exp $ */
+/* $OpenBSD: softraid.c,v 1.5 2013/10/20 13:25:20 stsp Exp $ */
/*
* Copyright (c) 2012 Joel Sing <jsing@openbsd.org>
@@ -37,6 +37,15 @@
/* List of softraid volumes. */
struct sr_boot_volume_head sr_volumes;
+/* Metadata from keydisks. */
+struct sr_boot_keydisk {
+ struct sr_uuid kd_uuid;
+ u_int8_t kd_key[SR_CRYPTO_MAXKEYBYTES];
+ SLIST_ENTRY(sr_boot_keydisk) kd_link;
+};
+SLIST_HEAD(sr_boot_keydisk_head, sr_boot_keydisk);
+struct sr_boot_keydisk_head sr_keydisks;
+
void
srprobe_meta_opt_load(struct sr_metadata *sm, struct sr_meta_opt_head *som)
{
@@ -60,7 +69,7 @@ srprobe_meta_opt_load(struct sr_metadata *sm, struct sr_meta_opt_head *som)
/* Unsupported old fixed length optional metadata. */
if (omh->som_length == 0) {
omh = (struct sr_meta_opt_hdr *)((void *)omh +
- omh->som_length);
+ SR_OLD_META_OPT_SIZE);
continue;
}
@@ -91,6 +100,40 @@ srprobe_meta_opt_load(struct sr_metadata *sm, struct sr_meta_opt_head *som)
}
void
+srprobe_keydisk_load(struct sr_metadata *sm)
+{
+ struct sr_meta_opt_hdr *omh;
+ struct sr_meta_keydisk *skm;
+ struct sr_boot_keydisk *kd;
+ int i;
+
+ /* Process optional metadata. */
+ omh = (struct sr_meta_opt_hdr *)((u_int8_t *)(sm + 1) +
+ sizeof(struct sr_meta_chunk) * sm->ssdi.ssd_chunk_no);
+ for (i = 0; i < sm->ssdi.ssd_opt_no; i++) {
+
+ /* Unsupported old fixed length optional metadata. */
+ if (omh->som_length == 0) {
+ omh = (struct sr_meta_opt_hdr *)((void *)omh +
+ SR_OLD_META_OPT_SIZE);
+ continue;
+ }
+
+ if (omh->som_type != SR_OPT_KEYDISK) {
+ omh = (struct sr_meta_opt_hdr *)((void *)omh +
+ omh->som_length);
+ continue;
+ }
+
+ kd = alloc(sizeof(struct sr_boot_keydisk));
+ bcopy(&sm->ssdi.ssd_uuid, &kd->kd_uuid, sizeof(kd->kd_uuid));
+ skm = (struct sr_meta_keydisk*)omh;
+ bcopy(&skm->skm_maskkey, &kd->kd_key, sizeof(kd->kd_key));
+ SLIST_INSERT_HEAD(&sr_keydisks, kd, kd_link);
+ }
+}
+
+void
srprobe(void)
{
struct sr_boot_volume *bv, *bv1, *bv2;
@@ -105,6 +148,7 @@ srprobe(void)
/* Probe for softraid volumes. */
SLIST_INIT(&sr_volumes);
+ SLIST_INIT(&sr_keydisks);
md = alloc(SR_META_SIZE * 512);
@@ -139,6 +183,12 @@ srprobe(void)
/* XXX - validate checksum. */
+ /* Handle key disks separately... */
+ if (md->ssdi.ssd_level == SR_KEYDISK_LEVEL) {
+ srprobe_keydisk_load(md);
+ continue;
+ }
+
/* Locate chunk-specific metadata for this chunk. */
mc = (struct sr_meta_chunk *)(md + 1);
mc += md->ssdi.ssd_chunk_id;
@@ -157,10 +207,6 @@ srprobe(void)
bc->sbc_ondisk = md->ssd_ondisk;
bc->sbc_state = mc->scm_status;
- /* Handle key disks separately... later. */
- if (md->ssdi.ssd_level == SR_KEYDISK_LEVEL)
- continue;
-
SLIST_FOREACH(bv, &sr_volumes, sbv_link) {
if (bcmp(&md->ssdi.ssd_uuid, &bv->sbv_uuid,
sizeof(md->ssdi.ssd_uuid)) == 0)
@@ -268,8 +314,8 @@ srprobe(void)
bv->sbv_flags & BIOC_SCBOOTABLE ? "*" : "");
}
- if (md)
- free(md, 0);
+ explicit_bzero(md, SR_META_SIZE * 512);
+ free(md, 0);
}
int
@@ -382,7 +428,7 @@ sr_getdisklabel(struct sr_boot_volume *bv, struct disklabel *label)
buf = alloca(DEV_BSIZE);
sr_strategy(bv, F_READ, start, sizeof(struct disklabel), buf, NULL);
-#if BIOS_DEBUG
+#ifdef BIOS_DEBUG
printf("sr_getdisklabel: magic %lx\n",
((struct disklabel *)buf)->d_magic);
for (i = 0; i < MAXPARTITIONS; i++)
@@ -424,6 +470,7 @@ void
sr_clear_keys(void)
{
struct sr_boot_volume *bv;
+ struct sr_boot_keydisk *kd;
SLIST_FOREACH(bv, &sr_volumes, sbv_link) {
if (bv->sbv_level != 'C')
@@ -439,6 +486,10 @@ sr_clear_keys(void)
bv->sbv_maskkey = NULL;
}
}
+ SLIST_FOREACH(kd, &sr_keydisks, kd_link) {
+ explicit_bzero(kd, sizeof(*kd));
+ free(kd, 0);
+ }
}
void
@@ -467,6 +518,7 @@ int
sr_crypto_decrypt_keys(struct sr_boot_volume *bv)
{
struct sr_meta_crypto *cm;
+ struct sr_boot_keydisk *kd;
struct sr_meta_opt_item *omi;
struct sr_crypto_kdf_pbkdf2 *kdfhint;
struct sr_crypto_kdfinfo kdfinfo;
@@ -499,26 +551,34 @@ sr_crypto_decrypt_keys(struct sr_boot_volume *bv)
goto done;
}
- printf("Passphrase: ");
- for (i = 0; i < PASSPHRASE_LENGTH - 1; i++) {
- c = cngetc();
- if (c == '\r' || c == '\n')
+ SLIST_FOREACH(kd, &sr_keydisks, kd_link) {
+ if (bcmp(&kd->kd_uuid, &bv->sbv_uuid, sizeof(kd->kd_uuid)) == 0)
break;
- passphrase[i] = (c & 0xff);
}
- passphrase[i] = 0;
- printf("\n");
+ if (kd) {
+ bcopy(&kd->kd_key, &kdfinfo.maskkey, sizeof(kdfinfo.maskkey));
+ } else {
+ printf("Passphrase: ");
+ for (i = 0; i < PASSPHRASE_LENGTH - 1; i++) {
+ c = cngetc();
+ if (c == '\r' || c == '\n')
+ break;
+ passphrase[i] = (c & 0xff);
+ }
+ passphrase[i] = 0;
+ printf("\n");
#ifdef BIOS_DEBUG
- printf("Got passphrase: %s with len %d\n",
- passphrase, strlen(passphrase));
+ printf("Got passphrase: %s with len %d\n",
+ passphrase, strlen(passphrase));
#endif
- if (pkcs5_pbkdf2(passphrase, strlen(passphrase), kdfhint->salt,
- sizeof(kdfhint->salt), kdfinfo.maskkey, sizeof(kdfinfo.maskkey),
- kdfhint->rounds) != 0) {
- printf("pbkdf2 failed\n");
- goto done;
+ if (pkcs5_pbkdf2(passphrase, strlen(passphrase), kdfhint->salt,
+ sizeof(kdfhint->salt), kdfinfo.maskkey,
+ sizeof(kdfinfo.maskkey), kdfhint->rounds) != 0) {
+ printf("pbkdf2 failed\n");
+ goto done;
+ }
}
/* kdfinfo->maskkey now has key. */
@@ -540,11 +600,11 @@ sr_crypto_decrypt_keys(struct sr_boot_volume *bv)
sizeof(kdfinfo.maskkey), keys, SR_CRYPTO_KEYBLOCK_BYTES, digest);
if (bcmp(digest, cm->chk_hmac_sha1.sch_mac, sizeof(digest))) {
- printf("incorrect passphrase\n");
+ printf("incorrect passphrase or keydisk\n");
goto done;
}
- /* Keys will be cleared before boot and from _rtt. */
+ /* Keys and keydisks will be cleared before boot and from _rtt. */
bv->sbv_keys = keys;
bv->sbv_maskkey = alloc(sizeof(kdfinfo.maskkey));
bcopy(&kdfinfo.maskkey, bv->sbv_maskkey, sizeof(kdfinfo.maskkey));
diff --git a/sys/arch/i386/stand/boot/conf.c b/sys/arch/i386/stand/boot/conf.c
index 273f9824e56..5823a1774b7 100644
--- a/sys/arch/i386/stand/boot/conf.c
+++ b/sys/arch/i386/stand/boot/conf.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: conf.c,v 1.50 2012/10/31 13:57:59 jsing Exp $ */
+/* $OpenBSD: conf.c,v 1.51 2013/10/20 13:25:21 stsp Exp $ */
/*
* Copyright (c) 1996 Michael Shalayeff
@@ -43,7 +43,7 @@
#include <dev/cons.h>
#include "debug.h"
-const char version[] = "3.21";
+const char version[] = "3.22";
int debug = 1;
diff --git a/sys/arch/i386/stand/cdboot/conf.c b/sys/arch/i386/stand/cdboot/conf.c
index 23c28be2f06..2930af1a2b8 100644
--- a/sys/arch/i386/stand/cdboot/conf.c
+++ b/sys/arch/i386/stand/cdboot/conf.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: conf.c,v 1.20 2012/10/31 14:32:54 jsing Exp $ */
+/* $OpenBSD: conf.c,v 1.21 2013/10/20 13:25:21 stsp Exp $ */
/*
* Copyright (c) 2004 Tom Cosgrove
@@ -44,7 +44,7 @@
#include <dev/cons.h>
#include "debug.h"
-const char version[] = "3.19";
+const char version[] = "3.20";
int debug = 1;
#undef _TEST
diff --git a/sys/arch/i386/stand/libsa/softraid.c b/sys/arch/i386/stand/libsa/softraid.c
index 0e63e2c641a..a3f4caad640 100644
--- a/sys/arch/i386/stand/libsa/softraid.c
+++ b/sys/arch/i386/stand/libsa/softraid.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: softraid.c,v 1.4 2013/06/11 16:42:09 deraadt Exp $ */
+/* $OpenBSD: softraid.c,v 1.5 2013/10/20 13:25:21 stsp Exp $ */
/*
* Copyright (c) 2012 Joel Sing <jsing@openbsd.org>
@@ -37,6 +37,15 @@
/* List of softraid volumes. */
struct sr_boot_volume_head sr_volumes;
+/* Metadata from keydisks. */
+struct sr_boot_keydisk {
+ struct sr_uuid kd_uuid;
+ u_int8_t kd_key[SR_CRYPTO_MAXKEYBYTES];
+ SLIST_ENTRY(sr_boot_keydisk) kd_link;
+};
+SLIST_HEAD(sr_boot_keydisk_head, sr_boot_keydisk);
+struct sr_boot_keydisk_head sr_keydisks;
+
void
srprobe_meta_opt_load(struct sr_metadata *sm, struct sr_meta_opt_head *som)
{
@@ -60,7 +69,7 @@ srprobe_meta_opt_load(struct sr_metadata *sm, struct sr_meta_opt_head *som)
/* Unsupported old fixed length optional metadata. */
if (omh->som_length == 0) {
omh = (struct sr_meta_opt_hdr *)((void *)omh +
- omh->som_length);
+ SR_OLD_META_OPT_SIZE);
continue;
}
@@ -91,6 +100,40 @@ srprobe_meta_opt_load(struct sr_metadata *sm, struct sr_meta_opt_head *som)
}
void
+srprobe_keydisk_load(struct sr_metadata *sm)
+{
+ struct sr_meta_opt_hdr *omh;
+ struct sr_meta_keydisk *skm;
+ struct sr_boot_keydisk *kd;
+ int i;
+
+ /* Process optional metadata. */
+ omh = (struct sr_meta_opt_hdr *)((u_int8_t *)(sm + 1) +
+ sizeof(struct sr_meta_chunk) * sm->ssdi.ssd_chunk_no);
+ for (i = 0; i < sm->ssdi.ssd_opt_no; i++) {
+
+ /* Unsupported old fixed length optional metadata. */
+ if (omh->som_length == 0) {
+ omh = (struct sr_meta_opt_hdr *)((void *)omh +
+ SR_OLD_META_OPT_SIZE);
+ continue;
+ }
+
+ if (omh->som_type != SR_OPT_KEYDISK) {
+ omh = (struct sr_meta_opt_hdr *)((void *)omh +
+ omh->som_length);
+ continue;
+ }
+
+ kd = alloc(sizeof(struct sr_boot_keydisk));
+ bcopy(&sm->ssdi.ssd_uuid, &kd->kd_uuid, sizeof(kd->kd_uuid));
+ skm = (struct sr_meta_keydisk*)omh;
+ bcopy(&skm->skm_maskkey, &kd->kd_key, sizeof(kd->kd_key));
+ SLIST_INSERT_HEAD(&sr_keydisks, kd, kd_link);
+ }
+}
+
+void
srprobe(void)
{
struct sr_boot_volume *bv, *bv1, *bv2;
@@ -105,6 +148,7 @@ srprobe(void)
/* Probe for softraid volumes. */
SLIST_INIT(&sr_volumes);
+ SLIST_INIT(&sr_keydisks);
md = alloc(SR_META_SIZE * 512);
@@ -139,6 +183,12 @@ srprobe(void)
/* XXX - validate checksum. */
+ /* Handle key disks separately... */
+ if (md->ssdi.ssd_level == SR_KEYDISK_LEVEL) {
+ srprobe_keydisk_load(md);
+ continue;
+ }
+
/* Locate chunk-specific metadata for this chunk. */
mc = (struct sr_meta_chunk *)(md + 1);
mc += md->ssdi.ssd_chunk_id;
@@ -157,10 +207,6 @@ srprobe(void)
bc->sbc_ondisk = md->ssd_ondisk;
bc->sbc_state = mc->scm_status;
- /* Handle key disks separately... later. */
- if (md->ssdi.ssd_level == SR_KEYDISK_LEVEL)
- continue;
-
SLIST_FOREACH(bv, &sr_volumes, sbv_link) {
if (bcmp(&md->ssdi.ssd_uuid, &bv->sbv_uuid,
sizeof(md->ssdi.ssd_uuid)) == 0)
@@ -268,8 +314,8 @@ srprobe(void)
bv->sbv_flags & BIOC_SCBOOTABLE ? "*" : "");
}
- if (md)
- free(md, 0);
+ explicit_bzero(md, SR_META_SIZE * 512);
+ free(md, 0);
}
int
@@ -382,7 +428,7 @@ sr_getdisklabel(struct sr_boot_volume *bv, struct disklabel *label)
buf = alloca(DEV_BSIZE);
sr_strategy(bv, F_READ, start, sizeof(struct disklabel), buf, NULL);
-#if BIOS_DEBUG
+#ifdef BIOS_DEBUG
printf("sr_getdisklabel: magic %lx\n",
((struct disklabel *)buf)->d_magic);
for (i = 0; i < MAXPARTITIONS; i++)
@@ -424,6 +470,7 @@ void
sr_clear_keys(void)
{
struct sr_boot_volume *bv;
+ struct sr_boot_keydisk *kd;
SLIST_FOREACH(bv, &sr_volumes, sbv_link) {
if (bv->sbv_level != 'C')
@@ -439,6 +486,10 @@ sr_clear_keys(void)
bv->sbv_maskkey = NULL;
}
}
+ SLIST_FOREACH(kd, &sr_keydisks, kd_link) {
+ explicit_bzero(kd, sizeof(*kd));
+ free(kd, 0);
+ }
}
void
@@ -467,6 +518,7 @@ int
sr_crypto_decrypt_keys(struct sr_boot_volume *bv)
{
struct sr_meta_crypto *cm;
+ struct sr_boot_keydisk *kd;
struct sr_meta_opt_item *omi;
struct sr_crypto_kdf_pbkdf2 *kdfhint;
struct sr_crypto_kdfinfo kdfinfo;
@@ -499,26 +551,34 @@ sr_crypto_decrypt_keys(struct sr_boot_volume *bv)
goto done;
}
- printf("Passphrase: ");
- for (i = 0; i < PASSPHRASE_LENGTH - 1; i++) {
- c = cngetc();
- if (c == '\r' || c == '\n')
+ SLIST_FOREACH(kd, &sr_keydisks, kd_link) {
+ if (bcmp(&kd->kd_uuid, &bv->sbv_uuid, sizeof(kd->kd_uuid)) == 0)
break;
- passphrase[i] = (c & 0xff);
}
- passphrase[i] = 0;
- printf("\n");
+ if (kd) {
+ bcopy(&kd->kd_key, &kdfinfo.maskkey, sizeof(kdfinfo.maskkey));
+ } else {
+ printf("Passphrase: ");
+ for (i = 0; i < PASSPHRASE_LENGTH - 1; i++) {
+ c = cngetc();
+ if (c == '\r' || c == '\n')
+ break;
+ passphrase[i] = (c & 0xff);
+ }
+ passphrase[i] = 0;
+ printf("\n");
#ifdef BIOS_DEBUG
- printf("Got passphrase: %s with len %d\n",
- passphrase, strlen(passphrase));
+ printf("Got passphrase: %s with len %d\n",
+ passphrase, strlen(passphrase));
#endif
- if (pkcs5_pbkdf2(passphrase, strlen(passphrase), kdfhint->salt,
- sizeof(kdfhint->salt), kdfinfo.maskkey, sizeof(kdfinfo.maskkey),
- kdfhint->rounds) != 0) {
- printf("pbkdf2 failed\n");
- goto done;
+ if (pkcs5_pbkdf2(passphrase, strlen(passphrase), kdfhint->salt,
+ sizeof(kdfhint->salt), kdfinfo.maskkey,
+ sizeof(kdfinfo.maskkey), kdfhint->rounds) != 0) {
+ printf("pbkdf2 failed\n");
+ goto done;
+ }
}
/* kdfinfo->maskkey now has key. */
@@ -540,11 +600,11 @@ sr_crypto_decrypt_keys(struct sr_boot_volume *bv)
sizeof(kdfinfo.maskkey), keys, SR_CRYPTO_KEYBLOCK_BYTES, digest);
if (bcmp(digest, cm->chk_hmac_sha1.sch_mac, sizeof(digest))) {
- printf("incorrect passphrase\n");
+ printf("incorrect passphrase or keydisk\n");
goto done;
}
- /* Keys will be cleared before boot and from _rtt. */
+ /* Keys and keydisks will be cleared before boot and from _rtt. */
bv->sbv_keys = keys;
bv->sbv_maskkey = alloc(sizeof(kdfinfo.maskkey));
bcopy(&kdfinfo.maskkey, bv->sbv_maskkey, sizeof(kdfinfo.maskkey));
diff --git a/sys/arch/i386/stand/pxeboot/conf.c b/sys/arch/i386/stand/pxeboot/conf.c
index a505dbafae3..150ee363340 100644
--- a/sys/arch/i386/stand/pxeboot/conf.c
+++ b/sys/arch/i386/stand/pxeboot/conf.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: conf.c,v 1.25 2012/10/31 14:32:55 jsing Exp $ */
+/* $OpenBSD: conf.c,v 1.26 2013/10/20 13:25:21 stsp Exp $ */
/*
* Copyright (c) 2004 Tom Cosgrove
@@ -46,7 +46,7 @@
#include "pxeboot.h"
#include "pxe_net.h"
-const char version[] = "3.19";
+const char version[] = "3.20";
int debug = 1;
#undef _TEST