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

Reply via email to