diff options
author | Joel Sing <jsing@cvs.openbsd.org> | 2012-10-27 15:43:43 +0000 |
---|---|---|
committer | Joel Sing <jsing@cvs.openbsd.org> | 2012-10-27 15:43:43 +0000 |
commit | 03f796e15851d0a9577e7464eb38078cf840ab2b (patch) | |
tree | 6ea5a8f738be83ba53931b95c6040a6c05255f7f /sys | |
parent | 346792a1c9b50fd53cf8423a5ba0a879c61f4820 (diff) |
Move the code for softraid boot into separate files, leaving only minimal
hooks that are called from the normal code path. This allows softraid boot
support to be completely enabled or disabled at compile time. For boot(8)
all softraid boot support is now enabled by default, including support for
booting from crypto volumes. Disable softraid boot support for fdboot,
which further shrinks the binary.
Diffstat (limited to 'sys')
-rw-r--r-- | sys/arch/amd64/stand/boot/Makefile | 17 | ||||
-rw-r--r-- | sys/arch/amd64/stand/boot/conf.c | 4 | ||||
-rw-r--r-- | sys/arch/amd64/stand/libsa/biosdev.c | 327 | ||||
-rw-r--r-- | sys/arch/amd64/stand/libsa/dev_i386.c | 11 | ||||
-rw-r--r-- | sys/arch/amd64/stand/libsa/disk.h | 11 | ||||
-rw-r--r-- | sys/arch/amd64/stand/libsa/diskprobe.c | 260 | ||||
-rw-r--r-- | sys/arch/amd64/stand/libsa/exec_i386.c | 22 | ||||
-rw-r--r-- | sys/arch/amd64/stand/libsa/gidt.S | 4 | ||||
-rw-r--r-- | sys/arch/amd64/stand/libsa/softraid.c | 567 | ||||
-rw-r--r-- | sys/arch/amd64/stand/libsa/softraid.h | 34 |
10 files changed, 661 insertions, 596 deletions
diff --git a/sys/arch/amd64/stand/boot/Makefile b/sys/arch/amd64/stand/boot/Makefile index ff03f477b6a..2705ea74217 100644 --- a/sys/arch/amd64/stand/boot/Makefile +++ b/sys/arch/amd64/stand/boot/Makefile @@ -1,4 +1,4 @@ -# $OpenBSD: Makefile,v 1.16 2012/10/13 14:10:35 jsing Exp $ +# $OpenBSD: Makefile,v 1.17 2012/10/27 15:43:42 jsing Exp $ .include "${.CURDIR}/../Makefile.inc" @@ -9,6 +9,10 @@ MLINKS?=boot.8 boot.conf.5 S =${.CURDIR}/../../../.. SADIR= ${.CURDIR}/.. +.if empty(CFLAGS:M-DFDBOOT) +SOFTRAID=yes +.endif + PROG?= boot SRCS= srt0.S conf.c LD?= ld @@ -21,6 +25,9 @@ LDFLAGS+=-melf_i386 -L/usr/libdata SRCS+= machdep.c dev_i386.c exec_i386.c cmd_i386.c SRCS+= gidt.S alloca.S biosdev.c bioscons.c gateA20.c \ memprobe.c diskprobe.c time.c ## biosprobe.c +.if defined(SOFTRAID) +SRCS+= softraid.c +.endif .PATH: ${S}/stand/boot SRCS+= boot.c cmd.c vars.c bootarg.c @@ -33,8 +40,8 @@ SRCS+= close.c closeall.c dev.c disklabel.c dkcksum.c fstat.c ioctl.c lseek.c \ open.c read.c stat.c write.c cread.c readdir.c cons.c loadfile.c \ elf32.c elf64.c SRCS+= ufs.c -.if defined(BOOT_CRYPTO) -SRCS+= aes_xts.c explicit_bzero.c hmac_sha1.c pbkdf2.c rijndael.c sha1.c +.if defined(SOFTRAID) +SRCS+= aes_xts.c explicit_bzero.c hmac_sha1.c pbkdf2.c rijndael.c sha1.c .endif .PATH: ${S}/lib/libkern/arch/amd64 ${S}/lib/libkern @@ -60,8 +67,8 @@ NOPROG= .include <bsd.prog.mk> -.if defined(BOOT_CRYPTO) -CPPFLAGS+=-DBOOT_CRYPTO +.if defined(SOFTRAID) +CPPFLAGS+=-DSOFTRAID .endif CPPFLAGS+=-DBOOTMAGIC=$(BOOTMAGIC) ${DEBUGFLAGS} -DLINKADDR=${LINKADDR} CPPFLAGS+=-DSLOW -DSMALL -DNOBYFOUR -DNO_GZIP -DDYNAMIC_CRC_TABLE diff --git a/sys/arch/amd64/stand/boot/conf.c b/sys/arch/amd64/stand/boot/conf.c index 91c6fb32225..4587d194a94 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.25 2012/10/12 15:00:33 jsing Exp $ */ +/* $OpenBSD: conf.c,v 1.26 2012/10/27 15:43:42 jsing Exp $ */ /* * Copyright (c) 1996 Michael Shalayeff @@ -42,7 +42,7 @@ #include <biosdev.h> #include <dev/cons.h> -const char version[] = "3.22"; +const char version[] = "3.23"; int debug = 1; diff --git a/sys/arch/amd64/stand/libsa/biosdev.c b/sys/arch/amd64/stand/libsa/biosdev.c index 4cdf9f970b2..d15cb0bafef 100644 --- a/sys/arch/amd64/stand/libsa/biosdev.c +++ b/sys/arch/amd64/stand/libsa/biosdev.c @@ -1,4 +1,4 @@ -/* $OpenBSD: biosdev.c,v 1.18 2012/10/09 13:55:36 jsing Exp $ */ +/* $OpenBSD: biosdev.c,v 1.19 2012/10/27 15:43:42 jsing Exp $ */ /* * Copyright (c) 1996 Michael Shalayeff @@ -31,8 +31,6 @@ #include <sys/param.h> #include <sys/reboot.h> #include <sys/disklabel.h> -#include <dev/biovar.h> -#include <dev/softraidvar.h> #include <isofs/cd9660/iso.h> #include <lib/libsa/saerrno.h> #include <machine/tss.h> @@ -42,11 +40,9 @@ #include "disk.h" #include "libsa.h" -#ifdef BOOT_CRYPTO -#include <lib/libsa/aes_xts.h> -#include <lib/libsa/hmac_sha1.h> -#include <lib/libsa/pbkdf2.h> -#include <lib/libsa/rijndael.h> +#ifdef SOFTRAID +#include <dev/softraidvar.h> +#include "softraid.h" #endif static const char *biosdisk_err(u_int); @@ -57,14 +53,6 @@ static int EDD_rw (int, int, u_int32_t, u_int32_t, void *); static u_int findopenbsd(bios_diskinfo_t *, const char **); -static const char *sr_getdisklabel(struct sr_boot_volume *, struct disklabel *); -static int sr_strategy(struct sr_boot_volume *, int, daddr32_t, size_t, - void *, size_t *); - -#ifdef BOOT_CRYPTO -static int sr_crypto_decrypt_keys(struct sr_boot_volume *); -#endif - extern int debug; int bios_bootdev; int bios_cddev = -1; /* Set by srt0 if coming from CD */ @@ -467,7 +455,9 @@ bios_getdisklabel(bios_diskinfo_t *bd, struct disklabel *label) int biosopen(struct open_file *f, ...) { +#ifdef SOFTRAID struct sr_boot_volume *bv; +#endif register char *cp, **file; dev_t maj, unit, part; struct diskinfo *dip; @@ -520,6 +510,7 @@ biosopen(struct open_file *f, ...) else f->f_flags |= F_RAW; +#ifdef SOFTRAID /* Intercept softraid disks. */ if (strncmp("sr", dev, 2) == 0) { @@ -532,10 +523,8 @@ biosopen(struct open_file *f, ...) return EADAPT; } -#ifdef BOOT_CRYPTO if (bv->sbv_level == 'C' && bv->sbv_keys == NULL) sr_crypto_decrypt_keys(bv); -#endif if (bv->sbv_diskinfo == NULL) { dip = alloc(sizeof(struct diskinfo)); @@ -562,6 +551,7 @@ biosopen(struct open_file *f, ...) return 0; } +#endif for (maj = 0; maj < nbdevs && strncmp(dev, bdevs[maj], devlen); maj++); @@ -721,9 +711,11 @@ biosstrategy(void *devdata, int rw, daddr32_t blk, size_t size, void *buf, u_int8_t error = 0; size_t nsect; +#ifdef SOFTRAID /* Intercept strategy for softraid volumes. */ if (dip->sr_vol) return sr_strategy(dip->sr_vol, rw, blk, size, buf, rsize); +#endif nsect = (size + DEV_BSIZE - 1) / DEV_BSIZE; blk += dip->disklabel.d_partitions[B_PARTITION(dip->bsddev)].p_offset; @@ -761,302 +753,3 @@ biosioctl(struct open_file *f, u_long cmd, void *data) { return 0; } - -static int -sr_strategy(struct sr_boot_volume *bv, int rw, daddr32_t blk, size_t size, - void *buf, size_t *rsize) -{ - struct diskinfo *sr_dip, *dip; - struct sr_boot_chunk *bc; -#ifdef BOOT_CRYPTO - struct aes_xts_ctx ctx; - size_t i, j, nsect; - daddr64_t blkno; - u_char iv[8]; - u_char *bp; - int err; -#endif - - /* We only support read-only softraid. */ - if (rw != F_READ) - return EPERM; - - /* Partition offset within softraid volume. */ - sr_dip = (struct diskinfo *)bv->sbv_diskinfo; - blk += sr_dip->disklabel.d_partitions[bv->sbv_part - 'a'].p_offset; - - if (bv->sbv_level == 0) { - return ENOTSUP; - } else if (bv->sbv_level == 1) { - - /* Select first online chunk. */ - SLIST_FOREACH(bc, &bv->sbv_chunks, sbc_link) - if (bc->sbc_state == BIOC_SDONLINE) - break; - if (bc == NULL) - return EIO; - - dip = (struct diskinfo *)bc->sbc_diskinfo; - dip->bsddev = bc->sbc_mm; - blk += bv->sbv_data_offset; - - /* XXX - If I/O failed we should try another chunk... */ - return biosstrategy(dip, rw, blk, size, buf, rsize); - -#ifdef BOOT_CRYPTO - } else if (bv->sbv_level == 'C') { - - /* Select first online chunk. */ - SLIST_FOREACH(bc, &bv->sbv_chunks, sbc_link) - if (bc->sbc_state == BIOC_SDONLINE) - break; - if (bc == NULL) - return EIO; - - dip = (struct diskinfo *)bc->sbc_diskinfo; - dip->bsddev = bc->sbc_mm; - - /* XXX - select correct key. */ - aes_xts_setkey(&ctx, (u_char *)bv->sbv_keys, 64); - - nsect = (size + DEV_BSIZE - 1) / DEV_BSIZE; - for (i = 0; i < nsect; i++) { - blkno = blk + i; - bp = ((u_char *)buf) + i * DEV_BSIZE; - err = biosstrategy(dip, rw, bv->sbv_data_offset + blkno, - DEV_BSIZE, bp, NULL); - if (err != 0) - return err; - - bcopy(&blkno, iv, sizeof(blkno)); - aes_xts_reinit(&ctx, iv); - for (j = 0; j < DEV_BSIZE; j += AES_XTS_BLOCKSIZE) - aes_xts_decrypt(&ctx, bp + j); - } - if (rsize != NULL) - *rsize = nsect * DEV_BSIZE; - - return err; -#endif - } else - return ENOTSUP; -} - -static const char * -sr_getdisklabel(struct sr_boot_volume *bv, struct disklabel *label) -{ - struct dos_partition *dp; - struct dos_mbr mbr; - u_int start = 0; - char *buf; - int i; - - /* Check for MBR to determine partition offset. */ - bzero(&mbr, sizeof(mbr)); - sr_strategy(bv, F_READ, DOSBBSECTOR, sizeof(struct dos_mbr), - &mbr, NULL); - if (mbr.dmbr_sign == DOSMBR_SIGNATURE) { - - /* Search for OpenBSD partition */ - for (i = 0; i < NDOSPART; i++) { - dp = &mbr.dmbr_parts[i]; - if (!dp->dp_size) - continue; - if (dp->dp_typ == DOSPTYP_OPENBSD) { - if (dp->dp_start > (dp->dp_start + DOSBBSECTOR)) - continue; - start = dp->dp_start + DOSBBSECTOR; - } - } - } - - start += LABELSECTOR; - - /* Read the disklabel. */ - buf = alloca(DEV_BSIZE); - sr_strategy(bv, F_READ, start, sizeof(struct disklabel), buf, NULL); - -#if BIOS_DEBUG - printf("sr_getdisklabel: magic %lx\n", - ((struct disklabel *)buf)->d_magic); - for (i = 0; i < MAXPARTITIONS; i++) - printf("part %c: type = %d, size = %d, offset = %d\n", 'a' + i, - (int)((struct disklabel *)buf)->d_partitions[i].p_fstype, - (int)((struct disklabel *)buf)->d_partitions[i].p_size, - (int)((struct disklabel *)buf)->d_partitions[i].p_offset); -#endif - - /* Fill in disklabel */ - return (getdisklabel(buf, label)); -} - -#ifdef BOOT_CRYPTO - -#define RIJNDAEL128_BLOCK_LEN 16 -#define PASSPHRASE_LENGTH 1024 - -#define SR_CRYPTO_KEYBLOCK_BYTES SR_CRYPTO_MAXKEYS * SR_CRYPTO_KEYBYTES - -#ifdef BIOS_DEBUG -void -printhex(const char *s, const u_int8_t *buf, size_t len) -{ - u_int8_t n1, n2; - size_t i; - - printf("%s: ", s); - for (i = 0; i < len; i++) { - n1 = buf[i] & 0x0f; - n2 = buf[i] >> 4; - printf("%c", n2 > 9 ? n2 + 'a' - 10 : n2 + '0'); - printf("%c", n1 > 9 ? n1 + 'a' - 10 : n1 + '0'); - } - printf("\n"); -} -#endif - -void -sr_clear_keys(void) -{ - struct sr_boot_volume *bv; - - SLIST_FOREACH(bv, &sr_volumes, sbv_link) { - if (bv->sbv_level != 'C') - continue; - if (bv->sbv_keys != NULL) { - explicit_bzero(bv->sbv_keys, SR_CRYPTO_KEYBLOCK_BYTES); - free(bv->sbv_keys, 0); - bv->sbv_keys = NULL; - } - if (bv->sbv_maskkey != NULL) { - explicit_bzero(bv->sbv_maskkey, SR_CRYPTO_MAXKEYBYTES); - free(bv->sbv_maskkey, 0); - bv->sbv_maskkey = NULL; - } - } -} - -void -sr_crypto_calculate_check_hmac_sha1(u_int8_t *maskkey, int maskkey_size, - u_int8_t *key, int key_size, u_char *check_digest) -{ - u_int8_t check_key[SHA1_DIGEST_LENGTH]; - SHA1_CTX shactx; - - explicit_bzero(check_key, sizeof(check_key)); - explicit_bzero(&shactx, sizeof(shactx)); - - /* k = SHA1(mask_key) */ - SHA1Init(&shactx); - SHA1Update(&shactx, maskkey, maskkey_size); - SHA1Final(check_key, &shactx); - - /* mac = HMAC_SHA1_k(unencrypted key) */ - hmac_sha1(key, key_size, check_key, sizeof(check_key), check_digest); - - explicit_bzero(check_key, sizeof(check_key)); - explicit_bzero(&shactx, sizeof(shactx)); -} - -int -sr_crypto_decrypt_keys(struct sr_boot_volume *bv) -{ - struct sr_meta_crypto *cm; - struct sr_meta_opt_item *omi; - struct sr_crypto_kdf_pbkdf2 *kdfhint; - struct sr_crypto_kdfinfo kdfinfo; - char passphrase[PASSPHRASE_LENGTH]; - u_int8_t digest[SHA1_DIGEST_LENGTH]; - u_int8_t *keys = NULL; - u_int8_t *kp, *cp; - rijndael_ctx ctx; - int rv = -1; - int c, i; - - SLIST_FOREACH(omi, &bv->sbv_meta_opt, omi_link) - if (omi->omi_som->som_type == SR_OPT_CRYPTO) - break; - - if (omi == NULL) { - printf("Crypto metadata not found!\n"); - goto done; - } - - cm = (struct sr_meta_crypto *)omi->omi_som; - kdfhint = (struct sr_crypto_kdf_pbkdf2 *)&cm->scm_kdfhint; - - switch (cm->scm_mask_alg) { - case SR_CRYPTOM_AES_ECB_256: - break; - default: - printf("unsupported encryption algorithm %u\n", - cm->scm_mask_alg); - goto done; - } - - printf("Passphrase: "); - i = 0; - 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)); -#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; - } - - /* kdfinfo->maskkey now has key. */ - - /* Decrypt disk keys. */ - keys = alloc(SR_CRYPTO_KEYBLOCK_BYTES); - bzero(keys, SR_CRYPTO_KEYBLOCK_BYTES); - - if (rijndael_set_key(&ctx, kdfinfo.maskkey, 256) != 0) - goto done; - - cp = (u_int8_t *)cm->scm_key; - kp = keys; - for (i = 0; i < SR_CRYPTO_KEYBLOCK_BYTES; i += RIJNDAEL128_BLOCK_LEN) - rijndael_decrypt(&ctx, (u_char *)(cp + i), (u_char *)(kp + i)); - - /* Check that the key decrypted properly. */ - sr_crypto_calculate_check_hmac_sha1(kdfinfo.maskkey, - sizeof(kdfinfo.maskkey), keys, SR_CRYPTO_KEYBLOCK_BYTES, digest); - - if (bcmp(digest, cm->chk_hmac_sha1.sch_mac, sizeof(digest))) { - printf("incorrect passphrase\n"); - goto done; - } - - /* Keys 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)); - - rv = 0; - -done: - explicit_bzero(passphrase, PASSPHRASE_LENGTH); - explicit_bzero(&kdfinfo, sizeof(kdfinfo)); - explicit_bzero(digest, sizeof(digest)); - - if (keys != NULL && rv != 0) { - explicit_bzero(keys, SR_CRYPTO_KEYBLOCK_BYTES); - free(keys, 0); - } - - return (rv); -} -#endif diff --git a/sys/arch/amd64/stand/libsa/dev_i386.c b/sys/arch/amd64/stand/libsa/dev_i386.c index de47768763f..342454a25d3 100644 --- a/sys/arch/amd64/stand/libsa/dev_i386.c +++ b/sys/arch/amd64/stand/libsa/dev_i386.c @@ -1,4 +1,4 @@ -/* $OpenBSD: dev_i386.c,v 1.11 2012/10/08 14:15:23 jsing Exp $ */ +/* $OpenBSD: dev_i386.c,v 1.12 2012/10/27 15:43:42 jsing Exp $ */ /* * Copyright (c) 1996-1999 Michael Shalayeff @@ -32,10 +32,15 @@ #include <dev/cons.h> #include <dev/biovar.h> #include <dev/softraidvar.h> + #include "libsa.h" #include "biosdev.h" #include "disk.h" +#ifdef SOFTRAID +#include "softraid.h" +#endif + extern int debug; /* XXX use slot for 'rd' for 'hd' pseudo-device */ @@ -94,9 +99,11 @@ devopen(struct open_file *f, const char *fname, char **file) void devboot(dev_t bootdev, char *p) { +#ifdef SOFTRAID struct sr_boot_volume *bv; struct sr_boot_chunk *bc; struct diskinfo *dip = NULL; +#endif int sr_boot_vol = -1; int part_type = FS_UNUSED; @@ -109,6 +116,7 @@ devboot(dev_t bootdev, char *p) *p++ = 'r'; #endif +#ifdef SOFTRAID /* * Determine the partition type for the 'a' partition of the * boot device. @@ -130,6 +138,7 @@ devboot(dev_t bootdev, char *p) if (sr_boot_vol != -1) break; } +#endif if (sr_boot_vol != -1 && part_type != FS_BSDFFS) { *p++ = 's'; diff --git a/sys/arch/amd64/stand/libsa/disk.h b/sys/arch/amd64/stand/libsa/disk.h index adbe02d0285..8d4cd1eb40a 100644 --- a/sys/arch/amd64/stand/libsa/disk.h +++ b/sys/arch/amd64/stand/libsa/disk.h @@ -1,4 +1,4 @@ -/* $OpenBSD: disk.h,v 1.3 2012/10/08 14:15:23 jsing Exp $ */ +/* $OpenBSD: disk.h,v 1.4 2012/10/27 15:43:42 jsing Exp $ */ /* * Copyright (c) 1997 Tobias Weingartner @@ -27,8 +27,8 @@ * */ -#ifndef _DISKPROBE_H -#define _DISKPROBE_H +#ifndef _DISK_H +#define _DISK_H #include <sys/queue.h> @@ -50,9 +50,6 @@ extern struct diskinfo *bootdev_dip; /* List of probed disks. */ extern struct disklist_lh disklist; -/* List of softraid volumes. */ -extern struct sr_boot_volume_head sr_volumes; - void dump_diskinfo(void); -#endif /* _DISKPROBE_H */ +#endif /* _DISK_H */ diff --git a/sys/arch/amd64/stand/libsa/diskprobe.c b/sys/arch/amd64/stand/libsa/diskprobe.c index fabd395f7de..6b0af6f103b 100644 --- a/sys/arch/amd64/stand/libsa/diskprobe.c +++ b/sys/arch/amd64/stand/libsa/diskprobe.c @@ -1,8 +1,7 @@ -/* $OpenBSD: diskprobe.c,v 1.10 2012/10/09 13:55:36 jsing Exp $ */ +/* $OpenBSD: diskprobe.c,v 1.11 2012/10/27 15:43:42 jsing Exp $ */ /* * Copyright (c) 1997 Tobias Weingartner - * Copyright (c) 2012 Joel Sing <jsing@openbsd.org> * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -35,15 +34,19 @@ #include <sys/queue.h> #include <sys/reboot.h> #include <sys/disklabel.h> -#include <dev/biovar.h> -#include <dev/softraidvar.h> -#include <stand/boot/bootarg.h> -#include <machine/biosvar.h> + #include <lib/libz/zlib.h> +#include <machine/biosvar.h> +#include <stand/boot/bootarg.h> + #include "disk.h" #include "biosdev.h" #include "libsa.h" +#ifdef SOFTRAID +#include "softraid.h" +#endif + #define MAX_CKSUMLEN MAXBSIZE / DEV_BSIZE /* Max # of blks to cksum */ /* Local Prototypes */ @@ -52,9 +55,6 @@ static int disksum(int); /* List of disk devices we found/probed */ struct disklist_lh disklist; -/* List of softraid volumes. */ -struct sr_boot_volume_head sr_volumes; - /* Pointer to boot device */ struct diskinfo *bootdev_dip; @@ -165,246 +165,6 @@ hardprobe(void) } } -#ifdef BOOT_CRYPTO -void -srprobe_meta_opt_load(struct sr_metadata *sm, struct sr_meta_opt_head *som) -{ - struct sr_meta_opt_hdr *omh; - struct sr_meta_opt_item *omi; -#if 0 - u_int8_t checksum[MD5_DIGEST_LENGTH]; -#endif - 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++) { - -#ifdef BIOS_DEBUG - printf("Found optional metadata of type %u, length %u\n", - omh->som_type, omh->som_length); -#endif - - /* Unsupported old fixed length optional metadata. */ - if (omh->som_length == 0) { - omh = (struct sr_meta_opt_hdr *)((void *)omh + - omh->som_length); - continue; - } - - /* Load variable length optional metadata. */ - omi = alloc(sizeof(struct sr_meta_opt_item)); - bzero(omi, sizeof(struct sr_meta_opt_item)); - SLIST_INSERT_HEAD(som, omi, omi_link); - omi->omi_som = alloc(omh->som_length); - bzero(omi->omi_som, omh->som_length); - bcopy(omh, omi->omi_som, omh->som_length); - -#if 0 - /* XXX - Validate checksum. */ - bcopy(&omi->omi_som->som_checksum, &checksum, - MD5_DIGEST_LENGTH); - bzero(&omi->omi_som->som_checksum, MD5_DIGEST_LENGTH); - sr_checksum(sc, omi->omi_som, - &omi->omi_som->som_checksum, omh->som_length); - if (bcmp(&checksum, &omi->omi_som->som_checksum, - sizeof(checksum))) - panic("%s: invalid optional metadata checksum", - DEVNAME(sc)); -#endif - - omh = (struct sr_meta_opt_hdr *)((void *)omh + - omh->som_length); - } -} -#endif - -static void -srprobe(void) -{ - struct sr_boot_volume *bv, *bv1, *bv2; - struct sr_boot_chunk *bc, *bc1, *bc2; - struct sr_meta_chunk *mc; - struct sr_metadata *md; - struct diskinfo *dip; - struct partition *pp; - int i, error, volno; - dev_t bsd_dev; - daddr_t off; - - /* Probe for softraid volumes. */ - SLIST_INIT(&sr_volumes); - - md = alloc(SR_META_SIZE * 512); - - TAILQ_FOREACH(dip, &disklist, list) { - - /* Only check hard disks, skip those with I/O errors. */ - if ((dip->bios_info.bios_number & 0x80) == 0 || - (dip->bios_info.flags & BDI_INVALID)) - continue; - - /* Make sure disklabel has been read. */ - if ((dip->bios_info.flags & (BDI_BADLABEL|BDI_GOODLABEL)) == 0) - continue; - - for (i = 0; i < MAXPARTITIONS; i++) { - - pp = &dip->disklabel.d_partitions[i]; - if (pp->p_fstype != FS_RAID || pp->p_size == 0) - continue; - - /* Read softraid metadata. */ - bzero(md, SR_META_SIZE * 512); - off = DL_GETPOFFSET(pp) + SR_META_OFFSET; - error = biosd_io(F_READ, &dip->bios_info, off, - SR_META_SIZE, md); - if (error) - continue; - - /* Is this valid softraid metadata? */ - if (md->ssdi.ssd_magic != SR_MAGIC) - continue; - - /* XXX - validate checksum. */ - - /* Locate chunk-specific metadata for this chunk. */ - mc = (struct sr_meta_chunk *)(md + 1); - mc += md->ssdi.ssd_chunk_id; - - bc = alloc(sizeof(struct sr_boot_chunk)); - bc->sbc_diskinfo = dip; - bc->sbc_disk = dip->bios_info.bios_number; - bc->sbc_part = 'a' + i; - - bsd_dev = dip->bios_info.bsd_dev; - bc->sbc_mm = MAKEBOOTDEV(B_TYPE(bsd_dev), - B_ADAPTOR(bsd_dev), B_CONTROLLER(bsd_dev), - B_UNIT(bsd_dev), bc->sbc_part - 'a'); - - bc->sbc_chunk_id = md->ssdi.ssd_chunk_id; - 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) - break; - } - - if (bv == NULL) { - bv = alloc(sizeof(struct sr_boot_volume)); - bv->sbv_diskinfo = NULL; - bv->sbv_keys = NULL; - bv->sbv_level = md->ssdi.ssd_level; - bv->sbv_volid = md->ssdi.ssd_volid; - bv->sbv_chunk_no = md->ssdi.ssd_chunk_no; - bv->sbv_flags = md->ssdi.ssd_vol_flags; - bv->sbv_size = md->ssdi.ssd_size; - bv->sbv_data_offset = md->ssd_data_offset; - bcopy(&md->ssdi.ssd_uuid, &bv->sbv_uuid, - sizeof(md->ssdi.ssd_uuid)); - SLIST_INIT(&bv->sbv_chunks); - SLIST_INIT(&bv->sbv_meta_opt); - -#ifdef BOOT_CRYPTO - /* Load optional metadata for this volume. */ - srprobe_meta_opt_load(md, &bv->sbv_meta_opt); -#endif - - /* Maintain volume order. */ - bv2 = NULL; - SLIST_FOREACH(bv1, &sr_volumes, sbv_link) { - if (bv1->sbv_volid > bv->sbv_volid) - break; - bv2 = bv1; - } - if (bv2 == NULL) - SLIST_INSERT_HEAD(&sr_volumes, bv, - sbv_link); - else - SLIST_INSERT_AFTER(bv2, bv, sbv_link); - } - - /* Maintain chunk order. */ - bc2 = NULL; - SLIST_FOREACH(bc1, &bv->sbv_chunks, sbc_link) { - if (bc1->sbc_chunk_id > bc->sbc_chunk_id) - break; - bc2 = bc1; - } - if (bc2 == NULL) - SLIST_INSERT_HEAD(&bv->sbv_chunks, - bc, sbc_link); - else - SLIST_INSERT_AFTER(bc2, bc, sbc_link); - - bv->sbv_chunks_found++; - } - } - - /* - * Assemble RAID volumes. - */ - volno = 0; - SLIST_FOREACH(bv, &sr_volumes, sbv_link) { - - /* Skip if this is a hotspare "volume". */ - if (bv->sbv_level == SR_HOTSPARE_LEVEL && - bv->sbv_chunk_no == 1) - continue; - - /* Determine current ondisk version. */ - bv->sbv_ondisk = 0; - SLIST_FOREACH(bc, &bv->sbv_chunks, sbc_link) { - if (bc->sbc_ondisk > bv->sbv_ondisk) - bv->sbv_ondisk = bc->sbc_ondisk; - } - SLIST_FOREACH(bc, &bv->sbv_chunks, sbc_link) { - if (bc->sbc_ondisk != bv->sbv_ondisk) - bc->sbc_state = BIOC_SDOFFLINE; - } - - /* XXX - Check for duplicate chunks. */ - - /* - * Validate that volume has sufficient chunks for - * read-only access. - * - * XXX - check chunk states. - */ - 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 1: - if (bv->sbv_chunk_no == bv->sbv_chunks_found) - bv->sbv_state = BIOC_SVONLINE; - else if (bv->sbv_chunks_found > 0) - bv->sbv_state = BIOC_SVDEGRADED; - break; - } - - bv->sbv_unit = volno++; - if (bv->sbv_state != BIOC_SVOFFLINE) - printf(" sr%d%s", bv->sbv_unit, - bv->sbv_flags & BIOC_SCBOOTABLE ? "*" : ""); - } - - if (md) - free(md, 0); -} - /* Probe for all BIOS supported disks */ u_int32_t bios_cksumlen; @@ -428,7 +188,9 @@ diskprobe(void) #endif hardprobe(); +#ifdef SOFTRAID srprobe(); +#endif /* Checksumming of hard disks */ for (i = 0; disksum(i++) && i < MAX_CKSUMLEN; ) diff --git a/sys/arch/amd64/stand/libsa/exec_i386.c b/sys/arch/amd64/stand/libsa/exec_i386.c index 71f2c573399..cdce6ac2cd4 100644 --- a/sys/arch/amd64/stand/libsa/exec_i386.c +++ b/sys/arch/amd64/stand/libsa/exec_i386.c @@ -1,4 +1,4 @@ -/* $OpenBSD: exec_i386.c,v 1.10 2012/10/09 13:55:36 jsing Exp $ */ +/* $OpenBSD: exec_i386.c,v 1.11 2012/10/27 15:43:42 jsing Exp $ */ /* * Copyright (c) 1997-1998 Michael Shalayeff @@ -29,16 +29,18 @@ */ #include <sys/param.h> +#include <sys/disklabel.h> #include <dev/cons.h> -#include <stand/boot/bootarg.h> +#include <lib/libsa/loadfile.h> #include <machine/biosvar.h> -#include <sys/disklabel.h> +#include <stand/boot/bootarg.h> + #include "disk.h" #include "libsa.h" -#include <lib/libsa/loadfile.h> -#ifdef BOOT_CRYPTO +#ifdef SOFTRAID #include <dev/softraidvar.h> +#include "softraid.h" #endif typedef void (*startfuncp)(int, int, int, int, int, int, int, int) @@ -46,10 +48,6 @@ typedef void (*startfuncp)(int, int, int, int, int, int, int, int) char *bootmac = NULL; -#ifdef BOOT_CRYPTO -void sr_clear_keys(); -#endif - void run_loadfile(u_long *marks, int howto) { @@ -66,7 +64,7 @@ run_loadfile(u_long *marks, int howto) bios_ddb_t ddb; extern int db_console; bios_bootduid_t bootduid; -#ifdef BOOT_CRYPTO +#ifdef SOFTRAID bios_bootsr_t bootsr; struct sr_boot_volume *bv; #endif @@ -91,7 +89,7 @@ run_loadfile(u_long *marks, int howto) bcopy(bootdev_dip->disklabel.d_uid, &bootduid.duid, sizeof(bootduid)); addbootarg(BOOTARG_BOOTDUID, sizeof(bootduid), &bootduid); -#ifdef BOOT_CRYPTO +#ifdef SOFTRAID if (bootdev_dip->sr_vol != NULL) { bv = bootdev_dip->sr_vol; bzero(&bootsr, sizeof(bootsr)); @@ -102,9 +100,7 @@ run_loadfile(u_long *marks, int howto) addbootarg(BOOTARG_BOOTSR, sizeof(bios_bootsr_t), &bootsr); explicit_bzero(&bootsr, sizeof(bootsr)); } -#endif -#ifdef BOOT_CRYPTO sr_clear_keys(); #endif diff --git a/sys/arch/amd64/stand/libsa/gidt.S b/sys/arch/amd64/stand/libsa/gidt.S index 2d56d1fb1e2..6a33ba94651 100644 --- a/sys/arch/amd64/stand/libsa/gidt.S +++ b/sys/arch/amd64/stand/libsa/gidt.S @@ -1,4 +1,4 @@ -/* $OpenBSD: gidt.S,v 1.10 2012/10/09 13:57:41 jsing Exp $ */ +/* $OpenBSD: gidt.S,v 1.11 2012/10/27 15:43:42 jsing Exp $ */ /* * Copyright (c) 1997 Michael Shalayeff @@ -123,7 +123,7 @@ .globl _C_LABEL(_rtt) ENTRY(_rtt) -#ifdef BOOT_CRYPTO +#ifdef SOFTRAID call _C_LABEL(sr_clear_keys) #endif #ifdef GIDT_DEBUG diff --git a/sys/arch/amd64/stand/libsa/softraid.c b/sys/arch/amd64/stand/libsa/softraid.c new file mode 100644 index 00000000000..1fb19b8ebb9 --- /dev/null +++ b/sys/arch/amd64/stand/libsa/softraid.c @@ -0,0 +1,567 @@ +/* $OpenBSD: softraid.c,v 1.1 2012/10/27 15:43:42 jsing Exp $ */ + +/* + * Copyright (c) 2012 Joel Sing <jsing@openbsd.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <sys/param.h> +#include <sys/queue.h> +#include <sys/disklabel.h> +#include <sys/reboot.h> + +#include <dev/biovar.h> +#include <dev/softraidvar.h> + +#include <lib/libsa/aes_xts.h> +#include <lib/libsa/hmac_sha1.h> +#include <lib/libsa/pbkdf2.h> +#include <lib/libsa/rijndael.h> + +#include "libsa.h" +#include "biosdev.h" +#include "disk.h" +#include "softraid.h" + +/* List of softraid volumes. */ +struct sr_boot_volume_head sr_volumes; + +void +srprobe_meta_opt_load(struct sr_metadata *sm, struct sr_meta_opt_head *som) +{ + struct sr_meta_opt_hdr *omh; + struct sr_meta_opt_item *omi; +#if 0 + u_int8_t checksum[MD5_DIGEST_LENGTH]; +#endif + 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++) { + +#ifdef BIOS_DEBUG + printf("Found optional metadata of type %u, length %u\n", + omh->som_type, omh->som_length); +#endif + + /* Unsupported old fixed length optional metadata. */ + if (omh->som_length == 0) { + omh = (struct sr_meta_opt_hdr *)((void *)omh + + omh->som_length); + continue; + } + + /* Load variable length optional metadata. */ + omi = alloc(sizeof(struct sr_meta_opt_item)); + bzero(omi, sizeof(struct sr_meta_opt_item)); + SLIST_INSERT_HEAD(som, omi, omi_link); + omi->omi_som = alloc(omh->som_length); + bzero(omi->omi_som, omh->som_length); + bcopy(omh, omi->omi_som, omh->som_length); + +#if 0 + /* XXX - Validate checksum. */ + bcopy(&omi->omi_som->som_checksum, &checksum, + MD5_DIGEST_LENGTH); + bzero(&omi->omi_som->som_checksum, MD5_DIGEST_LENGTH); + sr_checksum(sc, omi->omi_som, + &omi->omi_som->som_checksum, omh->som_length); + if (bcmp(&checksum, &omi->omi_som->som_checksum, + sizeof(checksum))) + panic("%s: invalid optional metadata checksum", + DEVNAME(sc)); +#endif + + omh = (struct sr_meta_opt_hdr *)((void *)omh + + omh->som_length); + } +} + +void +srprobe(void) +{ + struct sr_boot_volume *bv, *bv1, *bv2; + struct sr_boot_chunk *bc, *bc1, *bc2; + struct sr_meta_chunk *mc; + struct sr_metadata *md; + struct diskinfo *dip; + struct partition *pp; + int i, error, volno; + dev_t bsd_dev; + daddr_t off; + + /* Probe for softraid volumes. */ + SLIST_INIT(&sr_volumes); + + md = alloc(SR_META_SIZE * 512); + + TAILQ_FOREACH(dip, &disklist, list) { + + /* Only check hard disks, skip those with I/O errors. */ + if ((dip->bios_info.bios_number & 0x80) == 0 || + (dip->bios_info.flags & BDI_INVALID)) + continue; + + /* Make sure disklabel has been read. */ + if ((dip->bios_info.flags & (BDI_BADLABEL|BDI_GOODLABEL)) == 0) + continue; + + for (i = 0; i < MAXPARTITIONS; i++) { + + pp = &dip->disklabel.d_partitions[i]; + if (pp->p_fstype != FS_RAID || pp->p_size == 0) + continue; + + /* Read softraid metadata. */ + bzero(md, SR_META_SIZE * 512); + off = DL_GETPOFFSET(pp) + SR_META_OFFSET; + error = biosd_io(F_READ, &dip->bios_info, off, + SR_META_SIZE, md); + if (error) + continue; + + /* Is this valid softraid metadata? */ + if (md->ssdi.ssd_magic != SR_MAGIC) + continue; + + /* XXX - validate checksum. */ + + /* Locate chunk-specific metadata for this chunk. */ + mc = (struct sr_meta_chunk *)(md + 1); + mc += md->ssdi.ssd_chunk_id; + + bc = alloc(sizeof(struct sr_boot_chunk)); + bc->sbc_diskinfo = dip; + bc->sbc_disk = dip->bios_info.bios_number; + bc->sbc_part = 'a' + i; + + bsd_dev = dip->bios_info.bsd_dev; + bc->sbc_mm = MAKEBOOTDEV(B_TYPE(bsd_dev), + B_ADAPTOR(bsd_dev), B_CONTROLLER(bsd_dev), + B_UNIT(bsd_dev), bc->sbc_part - 'a'); + + bc->sbc_chunk_id = md->ssdi.ssd_chunk_id; + 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) + break; + } + + if (bv == NULL) { + bv = alloc(sizeof(struct sr_boot_volume)); + bv->sbv_diskinfo = NULL; + bv->sbv_keys = NULL; + bv->sbv_level = md->ssdi.ssd_level; + bv->sbv_volid = md->ssdi.ssd_volid; + bv->sbv_chunk_no = md->ssdi.ssd_chunk_no; + bv->sbv_flags = md->ssdi.ssd_vol_flags; + bv->sbv_size = md->ssdi.ssd_size; + bv->sbv_data_offset = md->ssd_data_offset; + bcopy(&md->ssdi.ssd_uuid, &bv->sbv_uuid, + sizeof(md->ssdi.ssd_uuid)); + SLIST_INIT(&bv->sbv_chunks); + SLIST_INIT(&bv->sbv_meta_opt); + + /* Load optional metadata for this volume. */ + srprobe_meta_opt_load(md, &bv->sbv_meta_opt); + + /* Maintain volume order. */ + bv2 = NULL; + SLIST_FOREACH(bv1, &sr_volumes, sbv_link) { + if (bv1->sbv_volid > bv->sbv_volid) + break; + bv2 = bv1; + } + if (bv2 == NULL) + SLIST_INSERT_HEAD(&sr_volumes, bv, + sbv_link); + else + SLIST_INSERT_AFTER(bv2, bv, sbv_link); + } + + /* Maintain chunk order. */ + bc2 = NULL; + SLIST_FOREACH(bc1, &bv->sbv_chunks, sbc_link) { + if (bc1->sbc_chunk_id > bc->sbc_chunk_id) + break; + bc2 = bc1; + } + if (bc2 == NULL) + SLIST_INSERT_HEAD(&bv->sbv_chunks, + bc, sbc_link); + else + SLIST_INSERT_AFTER(bc2, bc, sbc_link); + + bv->sbv_chunks_found++; + } + } + + /* + * Assemble RAID volumes. + */ + volno = 0; + SLIST_FOREACH(bv, &sr_volumes, sbv_link) { + + /* Skip if this is a hotspare "volume". */ + if (bv->sbv_level == SR_HOTSPARE_LEVEL && + bv->sbv_chunk_no == 1) + continue; + + /* Determine current ondisk version. */ + bv->sbv_ondisk = 0; + SLIST_FOREACH(bc, &bv->sbv_chunks, sbc_link) { + if (bc->sbc_ondisk > bv->sbv_ondisk) + bv->sbv_ondisk = bc->sbc_ondisk; + } + SLIST_FOREACH(bc, &bv->sbv_chunks, sbc_link) { + if (bc->sbc_ondisk != bv->sbv_ondisk) + bc->sbc_state = BIOC_SDOFFLINE; + } + + /* XXX - Check for duplicate chunks. */ + + /* + * Validate that volume has sufficient chunks for + * read-only access. + * + * XXX - check chunk states. + */ + 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 1: + if (bv->sbv_chunk_no == bv->sbv_chunks_found) + bv->sbv_state = BIOC_SVONLINE; + else if (bv->sbv_chunks_found > 0) + bv->sbv_state = BIOC_SVDEGRADED; + break; + } + + bv->sbv_unit = volno++; + if (bv->sbv_state != BIOC_SVOFFLINE) + printf(" sr%d%s", bv->sbv_unit, + bv->sbv_flags & BIOC_SCBOOTABLE ? "*" : ""); + } + + if (md) + free(md, 0); +} + +int +sr_strategy(struct sr_boot_volume *bv, int rw, daddr32_t blk, size_t size, + void *buf, size_t *rsize) +{ + struct diskinfo *sr_dip, *dip; + struct sr_boot_chunk *bc; + struct aes_xts_ctx ctx; + size_t i, j, nsect; + daddr64_t blkno; + u_char iv[8]; + u_char *bp; + int err; + + /* We only support read-only softraid. */ + if (rw != F_READ) + return EPERM; + + /* Partition offset within softraid volume. */ + sr_dip = (struct diskinfo *)bv->sbv_diskinfo; + blk += sr_dip->disklabel.d_partitions[bv->sbv_part - 'a'].p_offset; + + if (bv->sbv_level == 0) { + return ENOTSUP; + } else if (bv->sbv_level == 1) { + + /* Select first online chunk. */ + SLIST_FOREACH(bc, &bv->sbv_chunks, sbc_link) + if (bc->sbc_state == BIOC_SDONLINE) + break; + if (bc == NULL) + return EIO; + + dip = (struct diskinfo *)bc->sbc_diskinfo; + dip->bsddev = bc->sbc_mm; + blk += bv->sbv_data_offset; + + /* XXX - If I/O failed we should try another chunk... */ + return biosstrategy(dip, rw, blk, size, buf, rsize); + + } else if (bv->sbv_level == 'C') { + + /* Select first online chunk. */ + SLIST_FOREACH(bc, &bv->sbv_chunks, sbc_link) + if (bc->sbc_state == BIOC_SDONLINE) + break; + if (bc == NULL) + return EIO; + + dip = (struct diskinfo *)bc->sbc_diskinfo; + dip->bsddev = bc->sbc_mm; + + /* XXX - select correct key. */ + aes_xts_setkey(&ctx, (u_char *)bv->sbv_keys, 64); + + nsect = (size + DEV_BSIZE - 1) / DEV_BSIZE; + for (i = 0; i < nsect; i++) { + blkno = blk + i; + bp = ((u_char *)buf) + i * DEV_BSIZE; + err = biosstrategy(dip, rw, bv->sbv_data_offset + blkno, + DEV_BSIZE, bp, NULL); + if (err != 0) + return err; + + bcopy(&blkno, iv, sizeof(blkno)); + aes_xts_reinit(&ctx, iv); + for (j = 0; j < DEV_BSIZE; j += AES_XTS_BLOCKSIZE) + aes_xts_decrypt(&ctx, bp + j); + } + if (rsize != NULL) + *rsize = nsect * DEV_BSIZE; + + return err; + + } else + return ENOTSUP; +} + +const char * +sr_getdisklabel(struct sr_boot_volume *bv, struct disklabel *label) +{ + struct dos_partition *dp; + struct dos_mbr mbr; + u_int start = 0; + char *buf; + int i; + + /* Check for MBR to determine partition offset. */ + bzero(&mbr, sizeof(mbr)); + sr_strategy(bv, F_READ, DOSBBSECTOR, sizeof(mbr), &mbr, NULL); + if (mbr.dmbr_sign == DOSMBR_SIGNATURE) { + + /* Search for OpenBSD partition */ + for (i = 0; i < NDOSPART; i++) { + dp = &mbr.dmbr_parts[i]; + if (!dp->dp_size) + continue; + if (dp->dp_typ == DOSPTYP_OPENBSD) { + if (dp->dp_start > (dp->dp_start + DOSBBSECTOR)) + continue; + start = dp->dp_start + DOSBBSECTOR; + } + } + } + + start += LABELSECTOR; + + /* Read the disklabel. */ + buf = alloca(DEV_BSIZE); + sr_strategy(bv, F_READ, start, sizeof(struct disklabel), buf, NULL); + +#if BIOS_DEBUG + printf("sr_getdisklabel: magic %lx\n", + ((struct disklabel *)buf)->d_magic); + for (i = 0; i < MAXPARTITIONS; i++) + printf("part %c: type = %d, size = %d, offset = %d\n", 'a' + i, + (int)((struct disklabel *)buf)->d_partitions[i].p_fstype, + (int)((struct disklabel *)buf)->d_partitions[i].p_size, + (int)((struct disklabel *)buf)->d_partitions[i].p_offset); +#endif + + /* Fill in disklabel */ + return (getdisklabel(buf, label)); +} + + +#define RIJNDAEL128_BLOCK_LEN 16 +#define PASSPHRASE_LENGTH 1024 + +#define SR_CRYPTO_KEYBLOCK_BYTES SR_CRYPTO_MAXKEYS * SR_CRYPTO_KEYBYTES + +#ifdef BIOS_DEBUG +void +printhex(const char *s, const u_int8_t *buf, size_t len) +{ + u_int8_t n1, n2; + size_t i; + + printf("%s: ", s); + for (i = 0; i < len; i++) { + n1 = buf[i] & 0x0f; + n2 = buf[i] >> 4; + printf("%c", n2 > 9 ? n2 + 'a' - 10 : n2 + '0'); + printf("%c", n1 > 9 ? n1 + 'a' - 10 : n1 + '0'); + } + printf("\n"); +} +#endif + +void +sr_clear_keys(void) +{ + struct sr_boot_volume *bv; + + SLIST_FOREACH(bv, &sr_volumes, sbv_link) { + if (bv->sbv_level != 'C') + continue; + if (bv->sbv_keys != NULL) { + explicit_bzero(bv->sbv_keys, SR_CRYPTO_KEYBLOCK_BYTES); + free(bv->sbv_keys, 0); + bv->sbv_keys = NULL; + } + if (bv->sbv_maskkey != NULL) { + explicit_bzero(bv->sbv_maskkey, SR_CRYPTO_MAXKEYBYTES); + free(bv->sbv_maskkey, 0); + bv->sbv_maskkey = NULL; + } + } +} + +void +sr_crypto_calculate_check_hmac_sha1(u_int8_t *maskkey, int maskkey_size, + u_int8_t *key, int key_size, u_char *check_digest) +{ + u_int8_t check_key[SHA1_DIGEST_LENGTH]; + SHA1_CTX shactx; + + explicit_bzero(check_key, sizeof(check_key)); + explicit_bzero(&shactx, sizeof(shactx)); + + /* k = SHA1(mask_key) */ + SHA1Init(&shactx); + SHA1Update(&shactx, maskkey, maskkey_size); + SHA1Final(check_key, &shactx); + + /* mac = HMAC_SHA1_k(unencrypted key) */ + hmac_sha1(key, key_size, check_key, sizeof(check_key), check_digest); + + explicit_bzero(check_key, sizeof(check_key)); + explicit_bzero(&shactx, sizeof(shactx)); +} + +int +sr_crypto_decrypt_keys(struct sr_boot_volume *bv) +{ + struct sr_meta_crypto *cm; + struct sr_meta_opt_item *omi; + struct sr_crypto_kdf_pbkdf2 *kdfhint; + struct sr_crypto_kdfinfo kdfinfo; + char passphrase[PASSPHRASE_LENGTH]; + u_int8_t digest[SHA1_DIGEST_LENGTH]; + u_int8_t *keys = NULL; + u_int8_t *kp, *cp; + rijndael_ctx ctx; + int rv = -1; + int c, i; + + SLIST_FOREACH(omi, &bv->sbv_meta_opt, omi_link) + if (omi->omi_som->som_type == SR_OPT_CRYPTO) + break; + + if (omi == NULL) { + printf("Crypto metadata not found!\n"); + goto done; + } + + cm = (struct sr_meta_crypto *)omi->omi_som; + kdfhint = (struct sr_crypto_kdf_pbkdf2 *)&cm->scm_kdfhint; + + switch (cm->scm_mask_alg) { + case SR_CRYPTOM_AES_ECB_256: + break; + default: + printf("unsupported encryption algorithm %u\n", + cm->scm_mask_alg); + goto done; + } + + printf("Passphrase: "); + i = 0; + 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)); +#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; + } + + /* kdfinfo->maskkey now has key. */ + + /* Decrypt disk keys. */ + keys = alloc(SR_CRYPTO_KEYBLOCK_BYTES); + bzero(keys, SR_CRYPTO_KEYBLOCK_BYTES); + + if (rijndael_set_key(&ctx, kdfinfo.maskkey, 256) != 0) + goto done; + + cp = (u_int8_t *)cm->scm_key; + kp = keys; + for (i = 0; i < SR_CRYPTO_KEYBLOCK_BYTES; i += RIJNDAEL128_BLOCK_LEN) + rijndael_decrypt(&ctx, (u_char *)(cp + i), (u_char *)(kp + i)); + + /* Check that the key decrypted properly. */ + sr_crypto_calculate_check_hmac_sha1(kdfinfo.maskkey, + sizeof(kdfinfo.maskkey), keys, SR_CRYPTO_KEYBLOCK_BYTES, digest); + + if (bcmp(digest, cm->chk_hmac_sha1.sch_mac, sizeof(digest))) { + printf("incorrect passphrase\n"); + goto done; + } + + /* Keys 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)); + + rv = 0; + +done: + explicit_bzero(passphrase, PASSPHRASE_LENGTH); + explicit_bzero(&kdfinfo, sizeof(kdfinfo)); + explicit_bzero(digest, sizeof(digest)); + + if (keys != NULL && rv != 0) { + explicit_bzero(keys, SR_CRYPTO_KEYBLOCK_BYTES); + free(keys, 0); + } + + return (rv); +} diff --git a/sys/arch/amd64/stand/libsa/softraid.h b/sys/arch/amd64/stand/libsa/softraid.h new file mode 100644 index 00000000000..603e91493e2 --- /dev/null +++ b/sys/arch/amd64/stand/libsa/softraid.h @@ -0,0 +1,34 @@ +/* $OpenBSD: softraid.h,v 1.1 2012/10/27 15:43:42 jsing Exp $ */ + +/* + * Copyright (c) 2012 Joel Sing <jsing@openbsd.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _SOFTRAID_H_ +#define _SOFTRAID_H_ + +void srprobe(void); + +const char *sr_getdisklabel(struct sr_boot_volume *, struct disklabel *); +int sr_strategy(struct sr_boot_volume *, int, daddr32_t, size_t, + void *, size_t *); + +int sr_crypto_decrypt_keys(struct sr_boot_volume *); +void sr_clear_keys(void); + +/* List of softraid volumes. */ +extern struct sr_boot_volume_head sr_volumes; + +#endif /* _SOFTRAID_H */ |