summaryrefslogtreecommitdiff
path: root/sys/dev/softraid_crypto.c
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/softraid_crypto.c
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/softraid_crypto.c')
-rw-r--r--sys/dev/softraid_crypto.c148
1 files changed, 147 insertions, 1 deletions
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;