summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sbin/bioctl/bioctl.88
-rw-r--r--sbin/bioctl/bioctl.c92
-rw-r--r--sys/dev/softraid.c5
-rw-r--r--sys/dev/softraid_crypto.c148
-rw-r--r--sys/dev/softraidvar.h15
5 files changed, 244 insertions, 24 deletions
diff --git a/sbin/bioctl/bioctl.8 b/sbin/bioctl/bioctl.8
index 3d0c227c3b8..3d2bf9267b5 100644
--- a/sbin/bioctl/bioctl.8
+++ b/sbin/bioctl/bioctl.8
@@ -1,4 +1,4 @@
-.\" $OpenBSD: bioctl.8,v 1.75 2009/10/22 15:27:15 jmc Exp $
+.\" $OpenBSD: bioctl.8,v 1.76 2009/11/24 02:19:35 jsing Exp $
.\"
.\" Copyright (c) 2004, 2005 Marco Peereboom
.\"
@@ -23,7 +23,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd $Mdocdate: October 22 2009 $
+.Dd $Mdocdate: November 24 2009 $
.Dt BIOCTL 8
.Os
.Sh NAME
@@ -43,7 +43,7 @@
.Pp
.Nm bioctl
.Bk -words
-.Op Fl dhiqv
+.Op Fl Pdhiqv
.Op Fl C Ar flag[,flag,...]
.Op Fl c Ar raidlevel
.Op Fl l Ar special[,special,...]
@@ -214,6 +214,8 @@ device list to create within the
framework.
Requires
.Fl c .
+.It Fl P
+Change the passphrase on the selected crypto volume.
.It Fl r Ar rounds
When creating an encrypted volume, specifies the number of iterations of
the algorithm used to convert a passphrase into a key.
diff --git a/sbin/bioctl/bioctl.c b/sbin/bioctl/bioctl.c
index d7a2ffc86c5..1a40d471f31 100644
--- a/sbin/bioctl/bioctl.c
+++ b/sbin/bioctl/bioctl.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: bioctl.c,v 1.84 2009/10/25 17:53:07 marco Exp $ */
+/* $OpenBSD: bioctl.c,v 1.85 2009/11/24 02:19:35 jsing Exp $ */
/*
* Copyright (c) 2004, 2005 Marco Peereboom
@@ -65,10 +65,10 @@ const char *str2locator(const char *, struct locator *);
void cleanup(void);
int bio_parse_devlist(char *, dev_t *);
void bio_kdf_derive(struct sr_crypto_kdfinfo *,
- struct sr_crypto_kdf_pbkdf2 *);
+ struct sr_crypto_kdf_pbkdf2 *, char *, int);
void bio_kdf_generate(struct sr_crypto_kdfinfo *);
void derive_key_pkcs(int, u_int8_t *, size_t, u_int8_t *,
- size_t, int);
+ size_t, char *, int);
void bio_inq(char *);
void bio_alarm(char *);
@@ -78,6 +78,7 @@ void bio_setblink(char *, char *, int);
void bio_blink(char *, int, int);
void bio_createraid(u_int16_t, char *);
void bio_deleteraid(char *);
+void bio_changepass(char *);
u_int32_t bio_createflags(char *);
char *bio_vis(char *);
void bio_diskinq(char *);
@@ -101,13 +102,15 @@ main(int argc, char *argv[])
char *realname = NULL, *al_arg = NULL;
char *bl_arg = NULL, *dev_list = NULL;
const char *errstr;
- int ch, rv, blink = 0, diskinq = 0, ss_func = 0;
+ int ch, rv, blink = 0, changepass = 0, diskinq = 0;
+ int ss_func = 0;
u_int16_t cr_level = 0;
if (argc < 2)
usage();
- while ((ch = getopt(argc, argv, "a:b:C:c:dH:hil:p:qr:R:vu:")) != -1) {
+ while ((ch = getopt(argc, argv, "a:b:C:c:dH:hil:Pp:qr:R:vu:")) !=
+ -1) {
switch (ch) {
case 'a': /* alarm */
func |= BIOC_ALARM;
@@ -152,6 +155,10 @@ main(int argc, char *argv[])
func |= BIOC_DEVLIST;
dev_list = optarg;
break;
+ case 'P':
+ /* Change passphrase. */
+ changepass = 1;
+ break;
case 'p':
password = optarg;
break;
@@ -181,7 +188,7 @@ main(int argc, char *argv[])
argc -= optind;
argv += optind;
- if (argc != 1)
+ if (argc != 1 || (changepass && func != 0))
usage();
if (func == 0)
@@ -213,6 +220,8 @@ main(int argc, char *argv[])
if (diskinq) {
bio_diskinq(sd_dev);
+ } else if (changepass && sd_dev != NULL) {
+ bio_changepass(sd_dev);
} else if (func & BIOC_INQ) {
bio_inq(sd_dev);
} else if (func == BIOC_ALARM) {
@@ -248,7 +257,7 @@ usage(void)
"[-R device | channel:target[.lun]\n"
"\t[-u channel:target[.lun]] "
"device\n"
- " %s [-dhiqv] "
+ " %s [-Pdhiqv] "
"[-C flag[,flag,...]] [-c raidlevel]\n"
"\t[-l special[,special,...]] [-p passfile]\n"
"\t[-R device | channel:target[.lun] [-r rounds] "
@@ -747,7 +756,7 @@ bio_createraid(u_int16_t level, char *dev_list)
err(1, "ioctl");
if (create.bc_opaque_status == BIOC_SOINOUT_OK) {
- bio_kdf_derive(&kdfinfo, &kdfhint);
+ bio_kdf_derive(&kdfinfo, &kdfhint, "Passphrase: ", 0);
memset(&kdfhint, 0, sizeof(kdfhint));
} else {
bio_kdf_generate(&kdfinfo);
@@ -774,7 +783,7 @@ bio_createraid(u_int16_t level, char *dev_list)
void
bio_kdf_derive(struct sr_crypto_kdfinfo *kdfinfo, struct sr_crypto_kdf_pbkdf2
- *kdfhint)
+ *kdfhint, char* prompt, int verify)
{
if (!kdfinfo)
errx(1, "invalid KDF info");
@@ -793,7 +802,7 @@ bio_kdf_derive(struct sr_crypto_kdfinfo *kdfinfo, struct sr_crypto_kdf_pbkdf2
derive_key_pkcs(kdfhint->rounds,
kdfinfo->maskkey, sizeof(kdfinfo->maskkey),
- kdfhint->salt, sizeof(kdfhint->salt), 0);
+ kdfhint->salt, sizeof(kdfhint->salt), prompt, verify);
}
void
@@ -813,7 +822,8 @@ bio_kdf_generate(struct sr_crypto_kdfinfo *kdfinfo)
derive_key_pkcs(kdfinfo->pbkdf2.rounds,
kdfinfo->maskkey, sizeof(kdfinfo->maskkey),
- kdfinfo->pbkdf2.salt, sizeof(kdfinfo->pbkdf2.salt), 1);
+ kdfinfo->pbkdf2.salt, sizeof(kdfinfo->pbkdf2.salt),
+ "New passphrase: ", 1);
}
int
@@ -904,6 +914,58 @@ bio_deleteraid(char *dev)
errx(1, "delete volume %s failed", dev);
}
+void
+bio_changepass(char *dev)
+{
+ struct bioc_discipline bd;
+ struct sr_crypto_kdfpair kdfpair;
+ struct sr_crypto_kdfinfo kdfinfo1, kdfinfo2;
+ struct sr_crypto_kdf_pbkdf2 kdfhint;
+ int rv;
+
+ memset(&bd, 0, sizeof(bd));
+ memset(&kdfhint, 0, sizeof(kdfhint));
+ memset(&kdfinfo1, 0, sizeof(kdfinfo1));
+ memset(&kdfinfo2, 0, sizeof(kdfinfo2));
+
+ /* XXX use dev_t instead of string. */
+ strlcpy(bd.bd_dev, dev, sizeof(bd.bd_dev));
+ bd.bd_cmd = SR_IOCTL_GET_KDFHINT;
+ bd.bd_size = sizeof(kdfhint);
+ bd.bd_data = &kdfhint;
+
+ if (ioctl(devh, BIOCDISCIPLINE, &bd))
+ errx(1, "%s: failed to get KDF hint", dev);
+
+ /* Current passphrase. */
+ bio_kdf_derive(&kdfinfo1, &kdfhint, "Old passphrase: ", 0);
+
+ /* New passphrase. */
+ bio_kdf_derive(&kdfinfo2, &kdfhint, "New passphrase: ", 1);
+
+ kdfpair.kdfinfo1 = &kdfinfo1;
+ kdfpair.kdfsize1 = sizeof(kdfinfo1);
+ kdfpair.kdfinfo2 = &kdfinfo2;
+ kdfpair.kdfsize2 = sizeof(kdfinfo2);
+
+ bd.bd_cmd = SR_IOCTL_CHANGE_PASSPHRASE;
+ bd.bd_size = sizeof(kdfpair);
+ bd.bd_data = &kdfpair;
+
+ rv = ioctl(devh, BIOCDISCIPLINE, &bd);
+
+ memset(&kdfhint, 0, sizeof(kdfhint));
+ memset(&kdfinfo1, 0, sizeof(kdfinfo1));
+ memset(&kdfinfo2, 0, sizeof(kdfinfo2));
+
+ if (rv) {
+ if (errno == EPERM)
+ errx(1, "%s: incorrect passphrase", dev);
+ else
+ errx(1, "%s: failed to change passphrase", dev);
+ }
+}
+
#define BIOCTL_VIS_NBUF 4
#define BIOCTL_VIS_BUFLEN 80
@@ -936,12 +998,12 @@ bio_diskinq(char *sd_dev)
void
derive_key_pkcs(int rounds, u_int8_t *key, size_t keysz, u_int8_t *salt,
- size_t saltsz, int verify)
+ size_t saltsz, char *prompt, int verify)
{
FILE *f;
size_t pl;
struct stat sb;
- char passphrase[1024], verifybuf[1024];
+ char passphrase[1024], verifybuf[1024];
if (!key)
errx(1, "Invalid key");
@@ -975,8 +1037,8 @@ derive_key_pkcs(int rounds, u_int8_t *key, size_t keysz, u_int8_t *salt,
fclose(f);
} else {
- if (readpassphrase("Passphrase: ", passphrase,
- sizeof(passphrase), RPP_REQUIRE_TTY) == NULL)
+ if (readpassphrase(prompt, passphrase, sizeof(passphrase),
+ RPP_REQUIRE_TTY) == NULL)
errx(1, "unable to read passphrase");
}
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 *);