diff options
-rw-r--r-- | sbin/bioctl/bioctl.8 | 8 | ||||
-rw-r--r-- | sbin/bioctl/bioctl.c | 92 | ||||
-rw-r--r-- | sys/dev/softraid.c | 5 | ||||
-rw-r--r-- | sys/dev/softraid_crypto.c | 148 | ||||
-rw-r--r-- | sys/dev/softraidvar.h | 15 |
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 *); |