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));