summaryrefslogtreecommitdiff
path: root/sys/dev
diff options
context:
space:
mode:
authorJoel Sing <jsing@cvs.openbsd.org>2009-11-24 02:19:36 +0000
committerJoel Sing <jsing@cvs.openbsd.org>2009-11-24 02:19:36 +0000
commitb8dcc6872637a4450b8760cbe6dbf7994a5b7959 (patch)
treee19613e7e1c26839d14183a14cc1f8a46a52c97c /sys/dev
parent1e3336cfd7e7b01e181841b629a4a762695afdc0 (diff)
Allow the passphrase to be changed on softraid crypto volumes. Ensure that
you backup your data and lock up your pets prior to using this. Tested by todd@ ok marco@
Diffstat (limited to 'sys/dev')
-rw-r--r--sys/dev/softraid.c5
-rw-r--r--sys/dev/softraid_crypto.c148
-rw-r--r--sys/dev/softraidvar.h15
3 files changed, 162 insertions, 6 deletions
diff --git a/sys/dev/softraid.c b/sys/dev/softraid.c
index d6c269a9bc7..bc61449e7ed 100644
--- a/sys/dev/softraid.c
+++ b/sys/dev/softraid.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: softraid.c,v 1.181 2009/11/23 16:33:59 jsing Exp $ */
+/* $OpenBSD: softraid.c,v 1.182 2009/11/24 02:19:35 jsing Exp $ */
/*
* Copyright (c) 2007, 2008, 2009 Marco Peereboom <marco@peereboom.us>
* Copyright (c) 2008 Chris Kuethe <ckuethe@openbsd.org>
@@ -116,8 +116,6 @@ void sr_shutdown(void *);
void sr_uuid_get(struct sr_uuid *);
void sr_uuid_print(struct sr_uuid *, int);
void sr_checksum_print(u_int8_t *);
-void sr_checksum(struct sr_softc *, void *, void *,
- u_int32_t);
int sr_boot_assembly(struct sr_softc *);
int sr_already_assembled(struct sr_discipline *);
int sr_hotspare(struct sr_softc *, dev_t);
@@ -144,7 +142,6 @@ int sr_meta_rw(struct sr_discipline *, dev_t, void *,
size_t, daddr64_t, long);
int sr_meta_clear(struct sr_discipline *);
int sr_meta_read(struct sr_discipline *);
-int sr_meta_save(struct sr_discipline *, u_int32_t);
int sr_meta_validate(struct sr_discipline *, dev_t,
struct sr_metadata *, void *);
void sr_meta_chunks_create(struct sr_softc *,
diff --git a/sys/dev/softraid_crypto.c b/sys/dev/softraid_crypto.c
index ceac71829c1..c209f726b7f 100644
--- a/sys/dev/softraid_crypto.c
+++ b/sys/dev/softraid_crypto.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: softraid_crypto.c,v 1.41 2009/11/24 01:03:54 jsing Exp $ */
+/* $OpenBSD: softraid_crypto.c,v 1.42 2009/11/24 02:19:35 jsing Exp $ */
/*
* Copyright (c) 2007 Marco Peereboom <marco@peereboom.us>
* Copyright (c) 2008 Hans-Joerg Hoexer <hshoexer@openbsd.org>
@@ -62,8 +62,12 @@ int sr_crypto_get_kdf(struct bioc_createraid *,
int sr_crypto_decrypt(u_char *, u_char *, u_char *, size_t, int);
int sr_crypto_encrypt(u_char *, u_char *, u_char *, size_t, int);
int sr_crypto_decrypt_key(struct sr_discipline *);
+int sr_crypto_change_maskkey(struct sr_discipline *,
+ struct sr_crypto_kdfinfo *, struct sr_crypto_kdfinfo *);
int sr_crypto_alloc_resources(struct sr_discipline *);
int sr_crypto_free_resources(struct sr_discipline *);
+int sr_crypto_ioctl(struct sr_discipline *,
+ struct bioc_discipline *);
int sr_crypto_write(struct cryptop *);
int sr_crypto_rw(struct sr_workunit *);
int sr_crypto_rw2(struct sr_workunit *, struct cryptop *);
@@ -91,6 +95,7 @@ sr_crypto_discipline_init(struct sr_discipline *sd)
sd->sd_alloc_resources = sr_crypto_alloc_resources;
sd->sd_free_resources = sr_crypto_free_resources;
sd->sd_start_discipline = NULL;
+ sd->sd_ioctl_handler = sr_crypto_ioctl;
sd->sd_scsi_inquiry = sr_raid_inquiry;
sd->sd_scsi_read_cap = sr_raid_read_cap;
sd->sd_scsi_tur = sr_raid_tur;
@@ -441,6 +446,74 @@ sr_crypto_create_keys(struct sr_discipline *sd)
}
int
+sr_crypto_change_maskkey(struct sr_discipline *sd,
+ struct sr_crypto_kdfinfo *kdfinfo1, struct sr_crypto_kdfinfo *kdfinfo2)
+{
+ u_char check_digest[SHA1_DIGEST_LENGTH];
+ u_char *p, *c;
+ size_t ksz;
+ int rv = 1;
+
+ DNPRINTF(SR_D_DIS, "%s: sr_crypto_change_maskkey\n",
+ DEVNAME(sd->sd_sc));
+
+ if (sd->mds.mdd_crypto.scr_meta.scm_check_alg != SR_CRYPTOC_HMAC_SHA1)
+ goto out;
+
+ c = (u_char *)sd->mds.mdd_crypto.scr_meta.scm_key;
+ ksz = sizeof(sd->mds.mdd_crypto.scr_key);
+ p = malloc(ksz, M_DEVBUF, M_WAITOK | M_ZERO);
+ if (p == NULL)
+ goto out;
+
+ if (sr_crypto_decrypt(c, p, kdfinfo1->maskkey, ksz,
+ sd->mds.mdd_crypto.scr_meta.scm_mask_alg) == -1)
+ goto out;
+
+#ifdef SR_DEBUG0
+ sr_crypto_dumpkeys(sd);
+#endif
+
+ sr_crypto_calculate_check_hmac_sha1(kdfinfo1->maskkey,
+ sizeof(kdfinfo1->maskkey), p, ksz, check_digest);
+ if (memcmp(sd->mds.mdd_crypto.scr_meta.chk_hmac_sha1.sch_mac,
+ check_digest, sizeof(check_digest)) != 0) {
+ rv = EPERM;
+ goto out;
+ }
+
+ /* Mask the disk keys. */
+ c = (u_char *)sd->mds.mdd_crypto.scr_meta.scm_key;
+ if (sr_crypto_encrypt(p, c, kdfinfo2->maskkey, ksz,
+ sd->mds.mdd_crypto.scr_meta.scm_mask_alg) == -1)
+ goto out;
+
+ /* Prepare key decryption check code. */
+ sd->mds.mdd_crypto.scr_meta.scm_check_alg = SR_CRYPTOC_HMAC_SHA1;
+ sr_crypto_calculate_check_hmac_sha1(kdfinfo2->maskkey,
+ sizeof(kdfinfo2->maskkey), (u_int8_t *)sd->mds.mdd_crypto.scr_key,
+ sizeof(sd->mds.mdd_crypto.scr_key), check_digest);
+
+ /* Copy new encrypted key and HMAC to metadata. */
+ bcopy(check_digest, sd->mds.mdd_crypto.scr_meta.chk_hmac_sha1.sch_mac,
+ sizeof(sd->mds.mdd_crypto.scr_meta.chk_hmac_sha1.sch_mac));
+
+ rv = 0; /* Success */
+
+out:
+ if (p) {
+ bzero(p, ksz);
+ free(p, M_DEVBUF);
+ }
+
+ bzero(check_digest, sizeof(check_digest));
+ bzero(&kdfinfo1->maskkey, sizeof(kdfinfo1->maskkey));
+ bzero(&kdfinfo2->maskkey, sizeof(kdfinfo2->maskkey));
+
+ return (rv);
+}
+
+int
sr_crypto_alloc_resources(struct sr_discipline *sd)
{
struct cryptoini cri;
@@ -535,6 +608,79 @@ sr_crypto_free_resources(struct sr_discipline *sd)
}
int
+sr_crypto_ioctl(struct sr_discipline *sd, struct bioc_discipline *bd)
+{
+ struct sr_crypto_kdfpair kdfpair;
+ struct sr_crypto_kdfinfo kdfinfo1, kdfinfo2;
+ struct sr_meta_opt *im_so;
+ int size, rv = 1;
+
+ DNPRINTF(SR_D_IOCTL, "%s: sr_crypto_ioctl %u\n", DEVNAME(sc), cmd);
+
+ switch (bd->bd_cmd) {
+ case SR_IOCTL_GET_KDFHINT:
+
+ /* Get KDF hint for userland. */
+ size = sizeof(sd->mds.mdd_crypto.scr_meta.scm_kdfhint);
+ if (bd->bd_data == NULL || bd->bd_size > size)
+ goto bad;
+ if (copyout(sd->mds.mdd_crypto.scr_meta.scm_kdfhint,
+ bd->bd_data, bd->bd_size))
+ goto bad;
+
+ rv = 0;
+
+ break;
+
+ case SR_IOCTL_CHANGE_PASSPHRASE:
+
+ /* Attempt to change passphrase. */
+
+ size = sizeof(kdfpair);
+ if (bd->bd_data == NULL || bd->bd_size > size)
+ goto bad;
+ if (copyin(bd->bd_data, &kdfpair, size))
+ goto bad;
+
+ size = sizeof(kdfinfo1);
+ if (kdfpair.kdfinfo1 == NULL || kdfpair.kdfsize1 > size)
+ goto bad;
+ if (copyin(kdfpair.kdfinfo1, &kdfinfo1, size))
+ goto bad;
+
+ size = sizeof(kdfinfo2);
+ if (kdfpair.kdfinfo2 == NULL || kdfpair.kdfsize2 > size)
+ goto bad;
+ if (copyin(kdfpair.kdfinfo2, &kdfinfo2, size))
+ goto bad;
+
+ if (sr_crypto_change_maskkey(sd, &kdfinfo1, &kdfinfo2))
+ goto bad;
+
+ /*
+ * Copy encrypted key/passphrase into metadata.
+ */
+
+ /* Only one chunk in crypto volumes... */
+ im_so = &sd->sd_vol.sv_chunks[0]->src_opt;
+ bcopy(&sd->mds.mdd_crypto.scr_meta,
+ &im_so->somi.som_meta.smm_crypto,
+ sizeof(im_so->somi.som_meta.smm_crypto));
+
+ sr_checksum(sd->sd_sc, im_so, im_so->som_checksum,
+ sizeof(struct sr_meta_opt_invariant));
+
+ /* Save metadata to disk. */
+ rv = sr_meta_save(sd, SR_META_DIRTY);
+
+ break;
+ }
+
+bad:
+ return (rv);
+}
+
+int
sr_crypto_rw(struct sr_workunit *wu)
{
struct cryptop *crp;
diff --git a/sys/dev/softraidvar.h b/sys/dev/softraidvar.h
index 894ae0dbe5f..da5569b8085 100644
--- a/sys/dev/softraidvar.h
+++ b/sys/dev/softraidvar.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: softraidvar.h,v 1.83 2009/11/23 16:33:59 jsing Exp $ */
+/* $OpenBSD: softraidvar.h,v 1.84 2009/11/24 02:19:35 jsing Exp $ */
/*
* Copyright (c) 2006 Marco Peereboom <marco@peereboom.us>
* Copyright (c) 2008 Chris Kuethe <ckuethe@openbsd.org>
@@ -181,6 +181,16 @@ struct sr_crypto_kdfinfo {
#define pbkdf2 _kdfhint.pbkdf2
};
+#define SR_IOCTL_GET_KDFHINT 0x01 /* Get KDF hint. */
+#define SR_IOCTL_CHANGE_PASSPHRASE 0x02 /* Change passphase. */
+
+struct sr_crypto_kdfpair {
+ void *kdfinfo1;
+ u_int32_t kdfsize1;
+ void *kdfinfo2;
+ u_int32_t kdfsize2;
+};
+
#ifdef _KERNEL
#include <dev/biovar.h>
@@ -532,6 +542,9 @@ void sr_wu_put(struct sr_workunit *);
/* misc functions */
int32_t sr_validate_stripsize(u_int32_t);
void sr_meta_save_callback(void *, void *);
+int sr_meta_save(struct sr_discipline *, u_int32_t);
+void sr_checksum(struct sr_softc *, void *, void *,
+ u_int32_t);
int sr_validate_io(struct sr_workunit *, daddr64_t *,
char *);
int sr_check_io_collision(struct sr_workunit *);