summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorstsp <stsp@openbsd.org>2014-11-26 19:50:03 +0000
committerstsp <stsp@openbsd.org>2014-11-26 19:50:03 +0000
commit21e2043f619d8d059f7ba46612b6d0a5bbbaf9af (patch)
tree0cad49f9753589d1cd327f064379db253e08d032
parentCopy some Open Firmware interface functions from the kernel to ofwboot. (diff)
downloadwireguard-openbsd-21e2043f619d8d059f7ba46612b6d0a5bbbaf9af.tar.xz
wireguard-openbsd-21e2043f619d8d059f7ba46612b6d0a5bbbaf9af.zip
Add softraid boot support code files ported by me to sparc64 from amd64.
Not hooked to the build yet. ok kettenis@
-rw-r--r--sys/arch/sparc64/stand/ofwboot/softraid.c633
-rw-r--r--sys/arch/sparc64/stand/ofwboot/softraid.h34
2 files changed, 667 insertions, 0 deletions
diff --git a/sys/arch/sparc64/stand/ofwboot/softraid.c b/sys/arch/sparc64/stand/ofwboot/softraid.c
new file mode 100644
index 00000000000..9308a8475ef
--- /dev/null
+++ b/sys/arch/sparc64/stand/ofwboot/softraid.c
@@ -0,0 +1,633 @@
+/* $OpenBSD: softraid.c,v 1.1 2014/11/26 19:50:03 stsp 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/stand.h>
+#include <lib/libsa/aes_xts.h>
+#include <lib/libsa/hmac_sha1.h>
+#include <lib/libsa/pbkdf2.h>
+#include <lib/libsa/rijndael.h>
+
+#include "disk.h"
+#include "ofdev.h"
+#include "softraid.h"
+
+/* 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)
+{
+ 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 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 +
+ SR_OLD_META_OPT_SIZE);
+ 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_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;
+ struct sr_boot_chunk *bc, *bc1, *bc2;
+ struct sr_meta_chunk *mc;
+ struct sr_metadata *md;
+ struct diskinfo *dip;
+ struct partition *pp;
+ struct of_dev ofdev;
+ size_t read;
+ int i, error, diskno, volno, ihandle;
+ dev_t bsd_dev;
+
+ /* Probe for softraid volumes. */
+ SLIST_INIT(&sr_volumes);
+ SLIST_INIT(&sr_keydisks);
+
+ md = alloc(SR_META_SIZE * 512);
+ diskno = 0;
+ ihandle = -1;
+ TAILQ_FOREACH(dip, &disklist, list) {
+ ihandle = OF_open(dip->path);
+ if (ihandle == -1)
+ continue;
+ bzero(&ofdev, sizeof(ofdev));
+ ofdev.handle = ihandle;
+ ofdev.type = OFDEV_DISK;
+ ofdev.bsize = DEV_BSIZE;
+ 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);
+ ofdev.partoff = DL_GETPOFFSET(pp);
+ error = strategy(&ofdev, F_READ, SR_META_OFFSET,
+ SR_META_SIZE * 512, md, &read);
+ if (error || read != SR_META_SIZE * 512)
+ continue;
+
+ /* Is this valid softraid metadata? */
+ if (md->ssdi.ssd_magic != SR_MAGIC)
+ continue;
+
+ /* 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;
+
+ bc = alloc(sizeof(struct sr_boot_chunk));
+ bc->sbc_diskinfo = dip;
+ bc->sbc_disk = diskno++;
+ bc->sbc_part = 'a' + i;
+
+ bsd_dev = MAKEBOOTDEV(
+ dip->disklabel.d_type == DTYPE_SCSI ? 4 : 0,
+ 0, 0, diskno, RAW_PART);
+ 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;
+
+ 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));
+ bzero(bv, sizeof(struct sr_boot_volume));
+ 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++;
+ }
+ OF_close(ihandle);
+ }
+
+ /*
+ * 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\n", bv->sbv_unit,
+ bv->sbv_flags & BIOC_SCBOOTABLE ? "*" : "");
+ }
+
+ explicit_bzero(md, SR_META_SIZE * 512);
+ free(md, SR_META_SIZE * 512);
+}
+
+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 partition *pp;
+ struct sr_boot_chunk *bc;
+ struct aes_xts_ctx ctx;
+ struct of_dev ofdev;
+ size_t i, j, nsect;
+ daddr_t blkno;
+ u_char iv[8];
+ u_char *bp;
+ int err;
+ int ihandle;
+
+ /* We only support read-only softraid. */
+ if (rw != F_READ)
+ return ENOTSUP;
+
+ /* Partition offset within softraid volume. */
+ sr_dip = (struct diskinfo *)bv->sbv_diskinfo;
+ blk +=
+ DL_GETPOFFSET(&sr_dip->disklabel.d_partitions[bv->sbv_part - 'a']);
+
+ 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;
+ pp = &dip->disklabel.d_partitions[bc->sbc_part - 'a'];
+ blk += bv->sbv_data_offset;
+
+ /* XXX - If I/O failed we should try another chunk... */
+ ihandle = OF_open(dip->path);
+ if (ihandle == -1)
+ return EIO;
+ bzero(&ofdev, sizeof(ofdev));
+ ofdev.handle = ihandle;
+ ofdev.type = OFDEV_DISK;
+ ofdev.bsize = DEV_BSIZE;
+ ofdev.partoff = DL_GETPOFFSET(pp);
+ err = strategy(&ofdev, rw, blk, size, buf, rsize);
+ OF_close(ihandle);
+ return err;
+
+ } 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;
+ pp = &dip->disklabel.d_partitions[bc->sbc_part - 'a'];
+
+ ihandle = OF_open(dip->path);
+ if (ihandle == -1)
+ return EIO;
+ bzero(&ofdev, sizeof(ofdev));
+ ofdev.handle = ihandle;
+ ofdev.type = OFDEV_DISK;
+ ofdev.bsize = DEV_BSIZE;
+ ofdev.partoff = DL_GETPOFFSET(pp);
+
+ /* 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 = strategy(&ofdev, rw,
+ bv->sbv_data_offset + blkno,
+ DEV_BSIZE, bp, rsize);
+ if (err != 0 || *rsize != DEV_BSIZE) {
+ printf("Read from crypto volume failed "
+ "(read %d bytes): %s\n", *rsize,
+ strerror(err));
+ OF_close(ihandle);
+ 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);
+ }
+ *rsize = nsect * DEV_BSIZE;
+ OF_close(ihandle);
+ return err;
+
+ } else
+ return ENOTSUP;
+}
+
+const char *
+sr_getdisklabel(struct sr_boot_volume *bv, struct disklabel *label)
+{
+ struct of_dev ofdev;
+ int err;
+#ifdef DEBUG
+ int i;
+#endif
+
+ bzero(&ofdev, sizeof ofdev);
+ ofdev.type = OFDEV_SOFTRAID;
+
+ if (load_disklabel(&ofdev, label))
+ return ("Could not read disklabel from softraid");
+#ifdef DEBUG
+ printf("sr_getdisklabel: magic %lx\n", label->d_magic);
+ for (i = 0; i < MAXPARTITIONS; i++)
+ printf("part %c: type = %d, size = %d, offset = %d\n", 'a' + i,
+ (int)label->d_partitions[i].p_fstype,
+ (int)label->d_partitions[i].p_size,
+ (int)label->d_partitions[i].p_offset);
+#endif
+
+ return (NULL);
+}
+
+
+#define RIJNDAEL128_BLOCK_LEN 16
+#define PASSPHRASE_LENGTH 1024
+
+#define SR_CRYPTO_KEYBLOCK_BYTES SR_CRYPTO_MAXKEYS * SR_CRYPTO_KEYBYTES
+
+#ifdef 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;
+ struct sr_boot_keydisk *kd;
+
+ 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, SR_CRYPTO_KEYBLOCK_BYTES);
+ bv->sbv_keys = NULL;
+ }
+ if (bv->sbv_maskkey != NULL) {
+ explicit_bzero(bv->sbv_maskkey, SR_CRYPTO_MAXKEYBYTES);
+ free(bv->sbv_maskkey, SR_CRYPTO_MAXKEYBYTES);
+ bv->sbv_maskkey = NULL;
+ }
+ }
+ SLIST_FOREACH(kd, &sr_keydisks, kd_link) {
+ explicit_bzero(kd, sizeof(*kd));
+ free(kd, sizeof(*kd));
+ }
+}
+
+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_boot_keydisk *kd;
+ 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;
+ }
+
+ SLIST_FOREACH(kd, &sr_keydisks, kd_link) {
+ if (bcmp(&kd->kd_uuid, &bv->sbv_uuid, sizeof(kd->kd_uuid)) == 0)
+ break;
+ }
+ if (kd) {
+ bcopy(&kd->kd_key, &kdfinfo.maskkey, sizeof(kdfinfo.maskkey));
+ } else {
+ printf("Passphrase: ");
+ for (i = 0; i < PASSPHRASE_LENGTH - 1; i++) {
+ c = getchar();
+ if (c == '\r' || c == '\n')
+ break;
+ passphrase[i] = (c & 0xff);
+ }
+ passphrase[i] = 0;
+ printf("\n");
+
+#ifdef 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 or keydisk\n");
+ goto done;
+ }
+
+ /* 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));
+
+ 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, SR_CRYPTO_KEYBLOCK_BYTES);
+ }
+
+ return (rv);
+}
diff --git a/sys/arch/sparc64/stand/ofwboot/softraid.h b/sys/arch/sparc64/stand/ofwboot/softraid.h
new file mode 100644
index 00000000000..77d43b69e9c
--- /dev/null
+++ b/sys/arch/sparc64/stand/ofwboot/softraid.h
@@ -0,0 +1,34 @@
+/* $OpenBSD: softraid.h,v 1.1 2014/11/26 19:50:03 stsp 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 */