On Fri, Sep 20, 2013 at 10:58:18AM +0200, Stefan Sperling wrote:
> This diff allows boot from crypto volumes that are using a keydisk.
> So far booting only works from passphrase-based crypto volumes.
>
> Tested on i386 and amd64 using USB keydisks.
>
> Note that the BIOS needs to see the keydisk for this to work.
> SD cards or anything else that's usually not bootable won't work in
> many cases. If the keydisk is not present or cannot be found the
> boot loader will keep asking for a passphrase.
>
> The install media still fit with this.
Anyone?
> Index: i386/stand/boot/conf.c
> ===================================================================
> RCS file: /cvs/src/sys/arch/i386/stand/boot/conf.c,v
> retrieving revision 1.50
> diff -u -p -r1.50 conf.c
> --- i386/stand/boot/conf.c 31 Oct 2012 13:57:59 -0000 1.50
> +++ i386/stand/boot/conf.c 18 Sep 2013 14:14:53 -0000
> @@ -43,7 +43,7 @@
> #include <dev/cons.h>
> #include "debug.h"
>
> -const char version[] = "3.21";
> +const char version[] = "3.22";
> int debug = 1;
>
>
> Index: i386/stand/libsa/softraid.c
> ===================================================================
> RCS file: /cvs/src/sys/arch/i386/stand/libsa/softraid.c,v
> retrieving revision 1.4
> diff -u -p -r1.4 softraid.c
> --- i386/stand/libsa/softraid.c 11 Jun 2013 16:42:09 -0000 1.4
> +++ i386/stand/libsa/softraid.c 18 Sep 2013 14:16:07 -0000
> @@ -37,6 +37,14 @@
> /* List of softraid volumes. */
> struct sr_boot_volume_head sr_volumes;
>
> +/* Metadata from keydisks. */
> +struct sr_boot_meta_keydisk {
> + struct sr_metadata *md;
> + SLIST_ENTRY(sr_boot_meta_keydisk) skm_link;
> +};
> +SLIST_HEAD(sr_boot_meta_keydisk_head, sr_boot_meta_keydisk);
> +struct sr_boot_meta_keydisk_head sr_keydisks;
> +
> void
> srprobe_meta_opt_load(struct sr_metadata *sm, struct sr_meta_opt_head *som)
> {
> @@ -97,6 +105,7 @@ srprobe(void)
> struct sr_boot_chunk *bc, *bc1, *bc2;
> struct sr_meta_chunk *mc;
> struct sr_metadata *md;
> + struct sr_boot_meta_keydisk *mk;
> struct diskinfo *dip;
> struct partition *pp;
> int i, error, volno;
> @@ -105,6 +114,7 @@ srprobe(void)
>
> /* Probe for softraid volumes. */
> SLIST_INIT(&sr_volumes);
> + SLIST_INIT(&sr_keydisks);
>
> md = alloc(SR_META_SIZE * 512);
>
> @@ -139,6 +149,15 @@ srprobe(void)
>
> /* XXX - validate checksum. */
>
> + /* Handle key disks separately... later. */
> + if (md->ssdi.ssd_level == SR_KEYDISK_LEVEL) {
> + mk = alloc(sizeof(struct sr_boot_meta_keydisk));
> + mk->md = alloc(SR_META_SIZE * 512);
> + bcopy(md, mk->md, SR_META_SIZE * 512);
> + SLIST_INSERT_HEAD(&sr_keydisks, mk, skm_link);
> + continue;
> + }
> +
> /* Locate chunk-specific metadata for this chunk. */
> mc = (struct sr_meta_chunk *)(md + 1);
> mc += md->ssdi.ssd_chunk_id;
> @@ -157,10 +176,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)
> @@ -248,12 +263,28 @@ srprobe(void)
> bv->sbv_state = BIOC_SVOFFLINE;
> switch (bv->sbv_level) {
> case 0:
> - case 'C':
> case 'c':
> if (bv->sbv_chunk_no == bv->sbv_chunks_found)
> bv->sbv_state = BIOC_SVONLINE;
> break;
>
> + case 'C':
> + if (bv->sbv_chunk_no == bv->sbv_chunks_found) {
> + bv->sbv_state = BIOC_SVONLINE;
> +
> + /* Load keydisk metadata for this volume. */
> + SLIST_FOREACH(mk, &sr_keydisks, skm_link) {
> + if (bcmp(&mk->md->ssdi.ssd_uuid,
> + &bv->sbv_uuid,
> + sizeof(mk->md->ssdi.ssd_uuid)) == 0)
> + break;
> + }
> + if (mk)
> + srprobe_meta_opt_load(mk->md,
> + &bv->sbv_meta_opt);
> + }
> + break;
> +
> case 1:
> if (bv->sbv_chunk_no == bv->sbv_chunks_found)
> bv->sbv_state = BIOC_SVONLINE;
> @@ -382,7 +413,7 @@ sr_getdisklabel(struct sr_boot_volume *b
> 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 +455,7 @@ void
> sr_clear_keys(void)
> {
> struct sr_boot_volume *bv;
> + struct sr_boot_meta_keydisk *mk;
>
> SLIST_FOREACH(bv, &sr_volumes, sbv_link) {
> if (bv->sbv_level != 'C')
> @@ -439,6 +471,11 @@ sr_clear_keys(void)
> bv->sbv_maskkey = NULL;
> }
> }
> + SLIST_FOREACH(mk, &sr_keydisks, skm_link) {
> + explicit_bzero(mk->md, SR_META_SIZE * 512);
> + free(mk->md, 0);
> + mk->md = NULL;
> + }
> }
>
> void
> @@ -467,6 +504,7 @@ int
> sr_crypto_decrypt_keys(struct sr_boot_volume *bv)
> {
> struct sr_meta_crypto *cm;
> + struct sr_meta_keydisk *skm;
> struct sr_meta_opt_item *omi;
> struct sr_crypto_kdf_pbkdf2 *kdfhint;
> struct sr_crypto_kdfinfo kdfinfo;
> @@ -499,26 +537,35 @@ sr_crypto_decrypt_keys(struct sr_boot_vo
> goto done;
> }
>
> - printf("Passphrase: ");
> - for (i = 0; i < PASSPHRASE_LENGTH - 1; i++) {
> - c = cngetc();
> - if (c == '\r' || c == '\n')
> + SLIST_FOREACH(omi, &bv->sbv_meta_opt, omi_link)
> + if (omi->omi_som->som_type == SR_OPT_KEYDISK)
> break;
> - passphrase[i] = (c & 0xff);
> - }
> - passphrase[i] = 0;
> - printf("\n");
> + if (omi) {
> + skm = (struct sr_meta_keydisk*)omi->omi_som;
> + bcopy(&skm->skm_maskkey, &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 +587,11 @@ sr_crypto_decrypt_keys(struct sr_boot_vo
> 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));
> Index: amd64/stand/boot/conf.c
> ===================================================================
> RCS file: /cvs/src/sys/arch/amd64/stand/boot/conf.c,v
> retrieving revision 1.26
> diff -u -p -r1.26 conf.c
> --- amd64/stand/boot/conf.c 27 Oct 2012 15:43:42 -0000 1.26
> +++ amd64/stand/boot/conf.c 18 Sep 2013 14:14:07 -0000
> @@ -42,7 +42,7 @@
> #include <biosdev.h>
> #include <dev/cons.h>
>
> -const char version[] = "3.23";
> +const char version[] = "3.24";
> int debug = 1;
>
>
> Index: amd64/stand/libsa/softraid.c
> ===================================================================
> RCS file: /cvs/src/sys/arch/amd64/stand/libsa/softraid.c,v
> retrieving revision 1.4
> diff -u -p -r1.4 softraid.c
> --- amd64/stand/libsa/softraid.c 11 Jun 2013 16:42:07 -0000 1.4
> +++ amd64/stand/libsa/softraid.c 18 Sep 2013 14:14:07 -0000
> @@ -37,6 +37,14 @@
> /* List of softraid volumes. */
> struct sr_boot_volume_head sr_volumes;
>
> +/* Metadata from keydisks. */
> +struct sr_boot_meta_keydisk {
> + struct sr_metadata *md;
> + SLIST_ENTRY(sr_boot_meta_keydisk) skm_link;
> +};
> +SLIST_HEAD(sr_boot_meta_keydisk_head, sr_boot_meta_keydisk);
> +struct sr_boot_meta_keydisk_head sr_keydisks;
> +
> void
> srprobe_meta_opt_load(struct sr_metadata *sm, struct sr_meta_opt_head *som)
> {
> @@ -97,6 +105,7 @@ srprobe(void)
> struct sr_boot_chunk *bc, *bc1, *bc2;
> struct sr_meta_chunk *mc;
> struct sr_metadata *md;
> + struct sr_boot_meta_keydisk *mk;
> struct diskinfo *dip;
> struct partition *pp;
> int i, error, volno;
> @@ -105,6 +114,7 @@ srprobe(void)
>
> /* Probe for softraid volumes. */
> SLIST_INIT(&sr_volumes);
> + SLIST_INIT(&sr_keydisks);
>
> md = alloc(SR_META_SIZE * 512);
>
> @@ -139,6 +149,15 @@ srprobe(void)
>
> /* XXX - validate checksum. */
>
> + /* Handle key disks separately... later. */
> + if (md->ssdi.ssd_level == SR_KEYDISK_LEVEL) {
> + mk = alloc(sizeof(struct sr_boot_meta_keydisk));
> + mk->md = alloc(SR_META_SIZE * 512);
> + bcopy(md, mk->md, SR_META_SIZE * 512);
> + SLIST_INSERT_HEAD(&sr_keydisks, mk, skm_link);
> + continue;
> + }
> +
> /* Locate chunk-specific metadata for this chunk. */
> mc = (struct sr_meta_chunk *)(md + 1);
> mc += md->ssdi.ssd_chunk_id;
> @@ -157,10 +176,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)
> @@ -248,12 +263,28 @@ srprobe(void)
> bv->sbv_state = BIOC_SVOFFLINE;
> switch (bv->sbv_level) {
> case 0:
> - case 'C':
> case 'c':
> if (bv->sbv_chunk_no == bv->sbv_chunks_found)
> bv->sbv_state = BIOC_SVONLINE;
> break;
>
> + case 'C':
> + if (bv->sbv_chunk_no == bv->sbv_chunks_found) {
> + bv->sbv_state = BIOC_SVONLINE;
> +
> + /* Load keydisk metadata for this volume. */
> + SLIST_FOREACH(mk, &sr_keydisks, skm_link) {
> + if (bcmp(&mk->md->ssdi.ssd_uuid,
> + &bv->sbv_uuid,
> + sizeof(mk->md->ssdi.ssd_uuid)) == 0)
> + break;
> + }
> + if (mk)
> + srprobe_meta_opt_load(mk->md,
> + &bv->sbv_meta_opt);
> + }
> + break;
> +
> case 1:
> if (bv->sbv_chunk_no == bv->sbv_chunks_found)
> bv->sbv_state = BIOC_SVONLINE;
> @@ -382,7 +413,7 @@ sr_getdisklabel(struct sr_boot_volume *b
> 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 +455,7 @@ void
> sr_clear_keys(void)
> {
> struct sr_boot_volume *bv;
> + struct sr_boot_meta_keydisk *mk;
>
> SLIST_FOREACH(bv, &sr_volumes, sbv_link) {
> if (bv->sbv_level != 'C')
> @@ -439,6 +471,11 @@ sr_clear_keys(void)
> bv->sbv_maskkey = NULL;
> }
> }
> + SLIST_FOREACH(mk, &sr_keydisks, skm_link) {
> + explicit_bzero(mk->md, SR_META_SIZE * 512);
> + free(mk->md, 0);
> + mk->md = NULL;
> + }
> }
>
> void
> @@ -467,6 +504,7 @@ int
> sr_crypto_decrypt_keys(struct sr_boot_volume *bv)
> {
> struct sr_meta_crypto *cm;
> + struct sr_meta_keydisk *skm;
> struct sr_meta_opt_item *omi;
> struct sr_crypto_kdf_pbkdf2 *kdfhint;
> struct sr_crypto_kdfinfo kdfinfo;
> @@ -499,26 +537,35 @@ sr_crypto_decrypt_keys(struct sr_boot_vo
> goto done;
> }
>
> - printf("Passphrase: ");
> - for (i = 0; i < PASSPHRASE_LENGTH - 1; i++) {
> - c = cngetc();
> - if (c == '\r' || c == '\n')
> + SLIST_FOREACH(omi, &bv->sbv_meta_opt, omi_link)
> + if (omi->omi_som->som_type == SR_OPT_KEYDISK)
> break;
> - passphrase[i] = (c & 0xff);
> - }
> - passphrase[i] = 0;
> - printf("\n");
> + if (omi) {
> + skm = (struct sr_meta_keydisk*)omi->omi_som;
> + bcopy(&skm->skm_maskkey, &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 +587,11 @@ sr_crypto_decrypt_keys(struct sr_boot_vo
> 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));