1*87edded1Stobhe /* $OpenBSD: softraid_crypto.c,v 1.145 2021/10/24 14:50:42 tobhe Exp $ */
2f18dcc9cStedu /*
324de7c39Smarco * Copyright (c) 2007 Marco Peereboom <marco@peereboom.us>
41a9d6c4eShshoexer * Copyright (c) 2008 Hans-Joerg Hoexer <hshoexer@openbsd.org>
5f1072292Sdjm * Copyright (c) 2008 Damien Miller <djm@mindrot.org>
6a9cf0b4fSjsing * Copyright (c) 2009 Joel Sing <jsing@openbsd.org>
724de7c39Smarco *
8f18dcc9cStedu * Permission to use, copy, modify, and distribute this software for any
9f18dcc9cStedu * purpose with or without fee is hereby granted, provided that the above
10f18dcc9cStedu * copyright notice and this permission notice appear in all copies.
11f18dcc9cStedu *
12f18dcc9cStedu * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
13f18dcc9cStedu * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
14f18dcc9cStedu * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
15f18dcc9cStedu * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
16f18dcc9cStedu * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17f18dcc9cStedu * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18f18dcc9cStedu * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19f18dcc9cStedu */
20f18dcc9cStedu
21f18dcc9cStedu #include "bio.h"
22f18dcc9cStedu
23f18dcc9cStedu #include <sys/param.h>
24f18dcc9cStedu #include <sys/systm.h>
25f18dcc9cStedu #include <sys/buf.h>
26f18dcc9cStedu #include <sys/device.h>
27f18dcc9cStedu #include <sys/ioctl.h>
28f18dcc9cStedu #include <sys/malloc.h>
295cb575abSthib #include <sys/pool.h>
30f18dcc9cStedu #include <sys/kernel.h>
31f18dcc9cStedu #include <sys/disk.h>
32f18dcc9cStedu #include <sys/rwlock.h>
33f18dcc9cStedu #include <sys/queue.h>
34f18dcc9cStedu #include <sys/fcntl.h>
35f18dcc9cStedu #include <sys/disklabel.h>
36e7d4f752Sderaadt #include <sys/vnode.h>
37f18dcc9cStedu #include <sys/mount.h>
38f18dcc9cStedu #include <sys/sensors.h>
39f18dcc9cStedu #include <sys/stat.h>
40f18dcc9cStedu #include <sys/conf.h>
41f18dcc9cStedu #include <sys/uio.h>
4291f4f7d8Sdlg #include <sys/dkio.h>
43f18dcc9cStedu
44f18dcc9cStedu #include <crypto/cryptodev.h>
451a9d6c4eShshoexer #include <crypto/rijndael.h>
4637fde5f8Sdjm #include <crypto/md5.h>
47f1072292Sdjm #include <crypto/sha1.h>
4837fde5f8Sdjm #include <crypto/sha2.h>
4937fde5f8Sdjm #include <crypto/hmac.h>
50f18dcc9cStedu
51f18dcc9cStedu #include <scsi/scsi_all.h>
52f18dcc9cStedu #include <scsi/scsiconf.h>
53f18dcc9cStedu #include <scsi/scsi_disk.h>
54f18dcc9cStedu
55f18dcc9cStedu #include <dev/softraidvar.h>
56f18dcc9cStedu
57eb0e73bdSstsp struct sr_crypto_wu *sr_crypto_prepare(struct sr_workunit *,
58eb0e73bdSstsp struct sr_crypto *, int);
5987bb77c2Sjsing int sr_crypto_decrypt(u_char *, u_char *, u_char *, size_t, int);
6087bb77c2Sjsing int sr_crypto_encrypt(u_char *, u_char *, u_char *, size_t, int);
61eb0e73bdSstsp int sr_crypto_decrypt_key(struct sr_discipline *,
62eb0e73bdSstsp struct sr_crypto *);
63c6446370Sjsing int sr_crypto_change_maskkey(struct sr_discipline *,
64eb0e73bdSstsp struct sr_crypto *, struct sr_crypto_kdfinfo *,
65eb0e73bdSstsp struct sr_crypto_kdfinfo *);
669847360bSjsing int sr_crypto_create(struct sr_discipline *,
679847360bSjsing struct bioc_createraid *, int, int64_t);
6801de20b5Sstsp int sr_crypto_meta_create(struct sr_discipline *,
69eb0e73bdSstsp struct sr_crypto *, struct bioc_createraid *);
70eb0e73bdSstsp int sr_crypto_set_key(struct sr_discipline *, struct sr_crypto *,
71eb0e73bdSstsp struct bioc_createraid *, int, void *);
729847360bSjsing int sr_crypto_assemble(struct sr_discipline *,
737c003ea3Sjsing struct bioc_createraid *, int, void *);
74eb0e73bdSstsp void sr_crypto_free_sessions(struct sr_discipline *,
75eb0e73bdSstsp struct sr_crypto *);
76eb0e73bdSstsp int sr_crypto_alloc_resources_internal(struct sr_discipline *,
77eb0e73bdSstsp struct sr_crypto *);
781a9d6c4eShshoexer int sr_crypto_alloc_resources(struct sr_discipline *);
79eb0e73bdSstsp void sr_crypto_free_resources_internal(struct sr_discipline *,
80eb0e73bdSstsp struct sr_crypto *);
81820ef724Sjsing void sr_crypto_free_resources(struct sr_discipline *);
82eb0e73bdSstsp int sr_crypto_ioctl_internal(struct sr_discipline *,
83eb0e73bdSstsp struct sr_crypto *, struct bioc_discipline *);
84c6446370Sjsing int sr_crypto_ioctl(struct sr_discipline *,
85c6446370Sjsing struct bioc_discipline *);
86eb0e73bdSstsp int sr_crypto_meta_opt_handler_internal(struct sr_discipline *,
87eb0e73bdSstsp struct sr_crypto *, struct sr_meta_opt_hdr *);
88573449ddSjsing int sr_crypto_meta_opt_handler(struct sr_discipline *,
89ee4e3de1Sjsing struct sr_meta_opt_hdr *);
901a9d6c4eShshoexer int sr_crypto_rw(struct sr_workunit *);
91d8e58a88Sjsing int sr_crypto_dev_rw(struct sr_workunit *, struct sr_crypto_wu *);
92eb0e73bdSstsp void sr_crypto_done_internal(struct sr_workunit *,
93eb0e73bdSstsp struct sr_crypto *);
94e79f9674Sjsing void sr_crypto_done(struct sr_workunit *);
9587bb77c2Sjsing void sr_crypto_calculate_check_hmac_sha1(u_int8_t *, int,
9687bb77c2Sjsing u_int8_t *, int, u_char *);
979b1bb5e7Smarco void sr_crypto_hotplug(struct sr_discipline *, struct disk *, int);
981a9d6c4eShshoexer
991a9d6c4eShshoexer #ifdef SR_DEBUG0
100eb0e73bdSstsp void sr_crypto_dumpkeys(struct sr_crypto *);
1011a9d6c4eShshoexer #endif
1021a9d6c4eShshoexer
103edc270aeSjsing /* Discipline initialisation. */
104edc270aeSjsing void
sr_crypto_discipline_init(struct sr_discipline * sd)105edc270aeSjsing sr_crypto_discipline_init(struct sr_discipline *sd)
106edc270aeSjsing {
1079847360bSjsing int i;
108ac774743Sjsing
109edc270aeSjsing /* Fill out discipline members. */
1102d9211fdSbluhm sd->sd_wu_size = sizeof(struct sr_crypto_wu);
111edc270aeSjsing sd->sd_type = SR_MD_CRYPTO;
1126d81b338Sjsing strlcpy(sd->sd_name, "CRYPTO", sizeof(sd->sd_name));
113bce1c021Sjsing sd->sd_capabilities = SR_CAP_SYSTEM_DISK | SR_CAP_AUTO_ASSEMBLE;
114edc270aeSjsing sd->sd_max_wu = SR_CRYPTO_NOWU;
115edc270aeSjsing
1169847360bSjsing for (i = 0; i < SR_CRYPTO_MAXKEYS; i++)
1179847360bSjsing sd->mds.mdd_crypto.scr_sid[i] = (u_int64_t)-1;
1189847360bSjsing
1195c66ec22Sjsing /* Setup discipline specific function pointers. */
120edc270aeSjsing sd->sd_alloc_resources = sr_crypto_alloc_resources;
1215c66ec22Sjsing sd->sd_assemble = sr_crypto_assemble;
1225c66ec22Sjsing sd->sd_create = sr_crypto_create;
123edc270aeSjsing sd->sd_free_resources = sr_crypto_free_resources;
124c6446370Sjsing sd->sd_ioctl_handler = sr_crypto_ioctl;
125573449ddSjsing sd->sd_meta_opt_handler = sr_crypto_meta_opt_handler;
126edc270aeSjsing sd->sd_scsi_rw = sr_crypto_rw;
127e79f9674Sjsing sd->sd_scsi_done = sr_crypto_done;
128edc270aeSjsing }
129edc270aeSjsing
1309847360bSjsing int
sr_crypto_create(struct sr_discipline * sd,struct bioc_createraid * bc,int no_chunk,int64_t coerced_size)1319847360bSjsing sr_crypto_create(struct sr_discipline *sd, struct bioc_createraid *bc,
1329847360bSjsing int no_chunk, int64_t coerced_size)
1339847360bSjsing {
1349847360bSjsing int rv = EINVAL;
1359847360bSjsing
1365f082130Sjsing if (no_chunk != 1) {
137984c6b2dSjsing sr_error(sd->sd_sc, "%s requires exactly one chunk",
138984c6b2dSjsing sd->sd_name);
13901de20b5Sstsp return (rv);
1405f082130Sjsing }
1419847360bSjsing
14201de20b5Sstsp sd->sd_meta->ssdi.ssd_size = coerced_size;
14301de20b5Sstsp
144eb0e73bdSstsp rv = sr_crypto_meta_create(sd, &sd->mds.mdd_crypto, bc);
14501de20b5Sstsp if (rv)
14601de20b5Sstsp return (rv);
14701de20b5Sstsp
14801de20b5Sstsp sd->sd_max_ccb_per_wu = no_chunk;
14901de20b5Sstsp return (0);
15001de20b5Sstsp }
15101de20b5Sstsp
15201de20b5Sstsp int
sr_crypto_meta_create(struct sr_discipline * sd,struct sr_crypto * mdd_crypto,struct bioc_createraid * bc)153eb0e73bdSstsp sr_crypto_meta_create(struct sr_discipline *sd, struct sr_crypto *mdd_crypto,
154eb0e73bdSstsp struct bioc_createraid *bc)
15501de20b5Sstsp {
15601de20b5Sstsp struct sr_meta_opt_item *omi;
15701de20b5Sstsp int rv = EINVAL;
15801de20b5Sstsp
15901de20b5Sstsp if (sd->sd_meta->ssdi.ssd_size > SR_CRYPTO_MAXSIZE) {
1604fe5a5deSjsing sr_error(sd->sd_sc, "%s exceeds maximum size (%lli > %llu)",
16101de20b5Sstsp sd->sd_name, sd->sd_meta->ssdi.ssd_size,
16201de20b5Sstsp SR_CRYPTO_MAXSIZE);
1634fe5a5deSjsing goto done;
1644fe5a5deSjsing }
1654fe5a5deSjsing
166c907def9Sjsing /* Create crypto optional metadata. */
167c907def9Sjsing omi = malloc(sizeof(struct sr_meta_opt_item), M_DEVBUF,
168c907def9Sjsing M_WAITOK | M_ZERO);
169ee4e3de1Sjsing omi->omi_som = malloc(sizeof(struct sr_meta_crypto), M_DEVBUF,
170ee4e3de1Sjsing M_WAITOK | M_ZERO);
171ee4e3de1Sjsing omi->omi_som->som_type = SR_OPT_CRYPTO;
172ee4e3de1Sjsing omi->omi_som->som_length = sizeof(struct sr_meta_crypto);
173c907def9Sjsing SLIST_INSERT_HEAD(&sd->sd_meta_opt, omi, omi_link);
174eb0e73bdSstsp mdd_crypto->scr_meta = (struct sr_meta_crypto *)omi->omi_som;
175c907def9Sjsing sd->sd_meta->ssdi.ssd_opt_no++;
176c907def9Sjsing
177eb0e73bdSstsp mdd_crypto->key_disk = NULL;
1780054cd36Sjsing
1790054cd36Sjsing if (bc->bc_key_disk != NODEV) {
1800054cd36Sjsing
1810054cd36Sjsing /* Create a key disk. */
182eb0e73bdSstsp if (sr_crypto_get_kdf(bc, sd, mdd_crypto))
1830054cd36Sjsing goto done;
184eb0e73bdSstsp mdd_crypto->key_disk =
185eb0e73bdSstsp sr_crypto_create_key_disk(sd, mdd_crypto, bc->bc_key_disk);
186eb0e73bdSstsp if (mdd_crypto->key_disk == NULL)
1870054cd36Sjsing goto done;
1880054cd36Sjsing sd->sd_capabilities |= SR_CAP_AUTO_ASSEMBLE;
1890054cd36Sjsing
1900054cd36Sjsing } else if (bc->bc_opaque_flags & BIOC_SOOUT) {
1910054cd36Sjsing
1920054cd36Sjsing /* No hint available yet. */
1939847360bSjsing bc->bc_opaque_status = BIOC_SOINOUT_FAILED;
1949847360bSjsing rv = EAGAIN;
1959847360bSjsing goto done;
1969847360bSjsing
197eb0e73bdSstsp } else if (sr_crypto_get_kdf(bc, sd, mdd_crypto))
1989847360bSjsing goto done;
1999847360bSjsing
2000054cd36Sjsing /* Passphrase volumes cannot be automatically assembled. */
2010054cd36Sjsing if (!(bc->bc_flags & BIOC_SCNOAUTOASSEMBLE) && bc->bc_key_disk == NODEV)
2029847360bSjsing goto done;
2039847360bSjsing
204eb0e73bdSstsp sr_crypto_create_keys(sd, mdd_crypto);
2059847360bSjsing
2069847360bSjsing rv = 0;
2079847360bSjsing done:
2089847360bSjsing return (rv);
2099847360bSjsing }
2109847360bSjsing
2119847360bSjsing int
sr_crypto_set_key(struct sr_discipline * sd,struct sr_crypto * mdd_crypto,struct bioc_createraid * bc,int no_chunk,void * data)212eb0e73bdSstsp sr_crypto_set_key(struct sr_discipline *sd, struct sr_crypto *mdd_crypto,
213eb0e73bdSstsp struct bioc_createraid *bc, int no_chunk, void *data)
2149847360bSjsing {
2159847360bSjsing int rv = EINVAL;
2169847360bSjsing
217eb0e73bdSstsp mdd_crypto->key_disk = NULL;
2180054cd36Sjsing
219c907def9Sjsing /* Crypto optional metadata must already exist... */
220eb0e73bdSstsp if (mdd_crypto->scr_meta == NULL)
221c907def9Sjsing goto done;
222c907def9Sjsing
223b7072a3fSjsing if (data != NULL) {
224b7072a3fSjsing /* Kernel already has mask key. */
225eb0e73bdSstsp memcpy(mdd_crypto->scr_maskkey, data,
226eb0e73bdSstsp sizeof(mdd_crypto->scr_maskkey));
227b7072a3fSjsing } else if (bc->bc_key_disk != NODEV) {
2280054cd36Sjsing /* Read the mask key from the key disk. */
229eb0e73bdSstsp mdd_crypto->key_disk =
230eb0e73bdSstsp sr_crypto_read_key_disk(sd, mdd_crypto, bc->bc_key_disk);
231eb0e73bdSstsp if (mdd_crypto->key_disk == NULL)
2320054cd36Sjsing goto done;
2330054cd36Sjsing } else if (bc->bc_opaque_flags & BIOC_SOOUT) {
2349847360bSjsing /* provide userland with kdf hint */
2359847360bSjsing if (bc->bc_opaque == NULL)
2369847360bSjsing goto done;
2379847360bSjsing
238eb0e73bdSstsp if (sizeof(mdd_crypto->scr_meta->scm_kdfhint) <
2399847360bSjsing bc->bc_opaque_size)
2409847360bSjsing goto done;
2419847360bSjsing
242eb0e73bdSstsp if (copyout(mdd_crypto->scr_meta->scm_kdfhint,
2439847360bSjsing bc->bc_opaque, bc->bc_opaque_size))
2449847360bSjsing goto done;
2459847360bSjsing
2469847360bSjsing /* we're done */
2479847360bSjsing bc->bc_opaque_status = BIOC_SOINOUT_OK;
2489847360bSjsing rv = EAGAIN;
2499847360bSjsing goto done;
2500054cd36Sjsing } else if (bc->bc_opaque_flags & BIOC_SOIN) {
2519847360bSjsing /* get kdf with maskkey from userland */
252eb0e73bdSstsp if (sr_crypto_get_kdf(bc, sd, mdd_crypto))
2539847360bSjsing goto done;
254b7072a3fSjsing } else
255b7072a3fSjsing goto done;
2560054cd36Sjsing
2579847360bSjsing
2589847360bSjsing rv = 0;
2599847360bSjsing done:
2609847360bSjsing return (rv);
2619847360bSjsing }
2629847360bSjsing
263eb0e73bdSstsp int
sr_crypto_assemble(struct sr_discipline * sd,struct bioc_createraid * bc,int no_chunk,void * data)264eb0e73bdSstsp sr_crypto_assemble(struct sr_discipline *sd,
265eb0e73bdSstsp struct bioc_createraid *bc, int no_chunk, void *data)
266eb0e73bdSstsp {
267eb0e73bdSstsp int rv;
268eb0e73bdSstsp
269eb0e73bdSstsp rv = sr_crypto_set_key(sd, &sd->mds.mdd_crypto, bc, no_chunk, data);
270eb0e73bdSstsp if (rv)
271eb0e73bdSstsp return (rv);
272eb0e73bdSstsp
273eb0e73bdSstsp sd->sd_max_ccb_per_wu = sd->sd_meta->ssdi.ssd_chunk_no;
274eb0e73bdSstsp return (0);
275eb0e73bdSstsp }
276eb0e73bdSstsp
277117fae6fSoga struct sr_crypto_wu *
sr_crypto_prepare(struct sr_workunit * wu,struct sr_crypto * mdd_crypto,int encrypt)278eb0e73bdSstsp sr_crypto_prepare(struct sr_workunit *wu, struct sr_crypto *mdd_crypto,
279eb0e73bdSstsp int encrypt)
2801a9d6c4eShshoexer {
2811a9d6c4eShshoexer struct scsi_xfer *xs = wu->swu_xs;
282117fae6fSoga struct sr_crypto_wu *crwu;
2831a9d6c4eShshoexer struct cryptodesc *crd;
284117fae6fSoga int flags, i, n;
285d9ec6765Skrw daddr_t blkno;
28675b43c32Sdjm u_int keyndx;
2871a9d6c4eShshoexer
28832917a3bSjsing DNPRINTF(SR_D_DIS, "%s: sr_crypto_prepare wu %p encrypt %d\n",
289eb0e73bdSstsp DEVNAME(wu->swu_dis->sd_sc), wu, encrypt);
2901a9d6c4eShshoexer
29132917a3bSjsing crwu = (struct sr_crypto_wu *)wu;
292117fae6fSoga crwu->cr_uio.uio_iovcnt = 1;
293117fae6fSoga crwu->cr_uio.uio_iov->iov_len = xs->datalen;
2941a9d6c4eShshoexer if (xs->flags & SCSI_DATA_OUT) {
295117fae6fSoga crwu->cr_uio.uio_iov->iov_base = crwu->cr_dmabuf;
296dedb5617Stedu memcpy(crwu->cr_uio.uio_iov->iov_base, xs->data, xs->datalen);
2971a9d6c4eShshoexer } else
298117fae6fSoga crwu->cr_uio.uio_iov->iov_base = xs->data;
2991a9d6c4eShshoexer
300d9ec6765Skrw blkno = wu->swu_blk_start;
3011a9d6c4eShshoexer n = xs->datalen >> DEV_BSHIFT;
302117fae6fSoga
303117fae6fSoga /*
3043aa27e4fSjsing * We preallocated enough crypto descs for up to MAXPHYS of I/O.
305e410e70dSpatrick * Since there may be less than that we need to tweak the amount
306117fae6fSoga * of crypto desc structures to be just long enough for our needs.
307117fae6fSoga */
308e410e70dSpatrick KASSERT(crwu->cr_crp->crp_ndescalloc >= n);
309e410e70dSpatrick crwu->cr_crp->crp_ndesc = n;
3101a9d6c4eShshoexer flags = (encrypt ? CRD_F_ENCRYPT : 0) |
3111a9d6c4eShshoexer CRD_F_IV_PRESENT | CRD_F_IV_EXPLICIT;
3121a9d6c4eShshoexer
313f38a59e0Sjsing /*
314f38a59e0Sjsing * Select crypto session based on block number.
315f38a59e0Sjsing *
316f38a59e0Sjsing * XXX - this does not handle the case where the read/write spans
317f38a59e0Sjsing * across a different key blocks (e.g. 0.5TB boundary). Currently
318f38a59e0Sjsing * this is already broken by the use of scr_key[0] below.
319f38a59e0Sjsing */
320d9ec6765Skrw keyndx = blkno >> SR_CRYPTO_KEY_BLKSHIFT;
321eb0e73bdSstsp crwu->cr_crp->crp_sid = mdd_crypto->scr_sid[keyndx];
32275b43c32Sdjm
323117fae6fSoga crwu->cr_crp->crp_ilen = xs->datalen;
324117fae6fSoga crwu->cr_crp->crp_alloctype = M_DEVBUF;
32587f4b967Santon crwu->cr_crp->crp_flags = CRYPTO_F_IOV;
326117fae6fSoga crwu->cr_crp->crp_buf = &crwu->cr_uio;
327e410e70dSpatrick for (i = 0; i < crwu->cr_crp->crp_ndesc; i++, blkno++) {
328e410e70dSpatrick crd = &crwu->cr_crp->crp_desc[i];
3291a9d6c4eShshoexer crd->crd_skip = i << DEV_BSHIFT;
3301a9d6c4eShshoexer crd->crd_len = DEV_BSIZE;
3311a9d6c4eShshoexer crd->crd_inject = 0;
3321a9d6c4eShshoexer crd->crd_flags = flags;
333eb0e73bdSstsp crd->crd_alg = mdd_crypto->scr_alg;
334eb0e73bdSstsp crd->crd_klen = mdd_crypto->scr_klen;
335eb0e73bdSstsp crd->crd_key = mdd_crypto->scr_key[0];
336d9ec6765Skrw memcpy(crd->crd_iv, &blkno, sizeof(blkno));
3371a9d6c4eShshoexer }
3381a9d6c4eShshoexer
339117fae6fSoga return (crwu);
3401a9d6c4eShshoexer }
3411a9d6c4eShshoexer
3428c887097Smarco int
sr_crypto_get_kdf(struct bioc_createraid * bc,struct sr_discipline * sd,struct sr_crypto * mdd_crypto)343eb0e73bdSstsp sr_crypto_get_kdf(struct bioc_createraid *bc, struct sr_discipline *sd,
344eb0e73bdSstsp struct sr_crypto *mdd_crypto)
345f05efa1dShshoexer {
346f05efa1dShshoexer int rv = EINVAL;
347b61d43ebSmarco struct sr_crypto_kdfinfo *kdfinfo;
348f05efa1dShshoexer
349f05efa1dShshoexer if (!(bc->bc_opaque_flags & BIOC_SOIN))
350f05efa1dShshoexer return (rv);
351f05efa1dShshoexer if (bc->bc_opaque == NULL)
352f05efa1dShshoexer return (rv);
353e844eb46Stedu if (bc->bc_opaque_size != sizeof(*kdfinfo))
354f05efa1dShshoexer return (rv);
355f05efa1dShshoexer
356f05efa1dShshoexer kdfinfo = malloc(bc->bc_opaque_size, M_DEVBUF, M_WAITOK | M_ZERO);
357f05efa1dShshoexer if (copyin(bc->bc_opaque, kdfinfo, bc->bc_opaque_size))
358f05efa1dShshoexer goto out;
359f05efa1dShshoexer
360f05efa1dShshoexer if (kdfinfo->len != bc->bc_opaque_size)
361f05efa1dShshoexer goto out;
362f05efa1dShshoexer
363f05efa1dShshoexer /* copy KDF hint to disk meta data */
364d4aeb512Shshoexer if (kdfinfo->flags & SR_CRYPTOKDF_HINT) {
365eb0e73bdSstsp if (sizeof(mdd_crypto->scr_meta->scm_kdfhint) <
366aef7fe28Shshoexer kdfinfo->genkdf.len)
367f05efa1dShshoexer goto out;
368eb0e73bdSstsp memcpy(mdd_crypto->scr_meta->scm_kdfhint,
369dedb5617Stedu &kdfinfo->genkdf, kdfinfo->genkdf.len);
370d4aeb512Shshoexer }
371f05efa1dShshoexer
372f05efa1dShshoexer /* copy mask key to run-time meta data */
373d4aeb512Shshoexer if ((kdfinfo->flags & SR_CRYPTOKDF_KEY)) {
374eb0e73bdSstsp if (sizeof(mdd_crypto->scr_maskkey) < sizeof(kdfinfo->maskkey))
375d4aeb512Shshoexer goto out;
376eb0e73bdSstsp memcpy(mdd_crypto->scr_maskkey, &kdfinfo->maskkey,
377f05efa1dShshoexer sizeof(kdfinfo->maskkey));
378d4aeb512Shshoexer }
379f05efa1dShshoexer
38083e979edShshoexer bc->bc_opaque_status = BIOC_SOINOUT_OK;
381f05efa1dShshoexer rv = 0;
382f05efa1dShshoexer out:
383dc4ac70fSderaadt explicit_bzero(kdfinfo, bc->bc_opaque_size);
384939b6ccfStedu free(kdfinfo, M_DEVBUF, bc->bc_opaque_size);
385f05efa1dShshoexer
386f05efa1dShshoexer return (rv);
387f05efa1dShshoexer }
388f05efa1dShshoexer
38987bb77c2Sjsing int
sr_crypto_encrypt(u_char * p,u_char * c,u_char * key,size_t size,int alg)39087bb77c2Sjsing sr_crypto_encrypt(u_char *p, u_char *c, u_char *key, size_t size, int alg)
39187bb77c2Sjsing {
39287bb77c2Sjsing rijndael_ctx ctx;
39387bb77c2Sjsing int i, rv = 1;
39487bb77c2Sjsing
39587bb77c2Sjsing switch (alg) {
39687bb77c2Sjsing case SR_CRYPTOM_AES_ECB_256:
39787bb77c2Sjsing if (rijndael_set_key_enc_only(&ctx, key, 256) != 0)
39887bb77c2Sjsing goto out;
39987bb77c2Sjsing for (i = 0; i < size; i += RIJNDAEL128_BLOCK_LEN)
40087bb77c2Sjsing rijndael_encrypt(&ctx, &p[i], &c[i]);
40187bb77c2Sjsing rv = 0;
40287bb77c2Sjsing break;
40387bb77c2Sjsing default:
404aece4913Skrw DNPRINTF(SR_D_DIS, "%s: unsupported encryption algorithm %d\n",
4050054cd36Sjsing "softraid", alg);
40687bb77c2Sjsing rv = -1;
40787bb77c2Sjsing goto out;
40887bb77c2Sjsing }
40987bb77c2Sjsing
41087bb77c2Sjsing out:
411dc4ac70fSderaadt explicit_bzero(&ctx, sizeof(ctx));
41287bb77c2Sjsing return (rv);
41387bb77c2Sjsing }
41487bb77c2Sjsing
41587bb77c2Sjsing int
sr_crypto_decrypt(u_char * c,u_char * p,u_char * key,size_t size,int alg)41687bb77c2Sjsing sr_crypto_decrypt(u_char *c, u_char *p, u_char *key, size_t size, int alg)
41787bb77c2Sjsing {
41887bb77c2Sjsing rijndael_ctx ctx;
41987bb77c2Sjsing int i, rv = 1;
42087bb77c2Sjsing
42187bb77c2Sjsing switch (alg) {
42287bb77c2Sjsing case SR_CRYPTOM_AES_ECB_256:
42387bb77c2Sjsing if (rijndael_set_key(&ctx, key, 256) != 0)
42487bb77c2Sjsing goto out;
42587bb77c2Sjsing for (i = 0; i < size; i += RIJNDAEL128_BLOCK_LEN)
42687bb77c2Sjsing rijndael_decrypt(&ctx, &c[i], &p[i]);
42787bb77c2Sjsing rv = 0;
42887bb77c2Sjsing break;
42987bb77c2Sjsing default:
430aece4913Skrw DNPRINTF(SR_D_DIS, "%s: unsupported encryption algorithm %d\n",
4310054cd36Sjsing "softraid", alg);
43287bb77c2Sjsing rv = -1;
43387bb77c2Sjsing goto out;
43487bb77c2Sjsing }
43587bb77c2Sjsing
43687bb77c2Sjsing out:
437dc4ac70fSderaadt explicit_bzero(&ctx, sizeof(ctx));
43887bb77c2Sjsing return (rv);
43987bb77c2Sjsing }
44087bb77c2Sjsing
441f1072292Sdjm 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)44287bb77c2Sjsing sr_crypto_calculate_check_hmac_sha1(u_int8_t *maskkey, int maskkey_size,
44387bb77c2Sjsing u_int8_t *key, int key_size, u_char *check_digest)
444f1072292Sdjm {
445f1072292Sdjm u_char check_key[SHA1_DIGEST_LENGTH];
44637fde5f8Sdjm HMAC_SHA1_CTX hmacctx;
447f1072292Sdjm SHA1_CTX shactx;
448f1072292Sdjm
449f1072292Sdjm bzero(check_key, sizeof(check_key));
45037fde5f8Sdjm bzero(&hmacctx, sizeof(hmacctx));
45137fde5f8Sdjm bzero(&shactx, sizeof(shactx));
45237fde5f8Sdjm
453f1072292Sdjm /* k = SHA1(mask_key) */
454f1072292Sdjm SHA1Init(&shactx);
45587bb77c2Sjsing SHA1Update(&shactx, maskkey, maskkey_size);
456f1072292Sdjm SHA1Final(check_key, &shactx);
457f1072292Sdjm
45887bb77c2Sjsing /* mac = HMAC_SHA1_k(unencrypted key) */
45937fde5f8Sdjm HMAC_SHA1_Init(&hmacctx, check_key, sizeof(check_key));
46087bb77c2Sjsing HMAC_SHA1_Update(&hmacctx, key, key_size);
46137fde5f8Sdjm HMAC_SHA1_Final(check_digest, &hmacctx);
46237fde5f8Sdjm
463dc4ac70fSderaadt explicit_bzero(check_key, sizeof(check_key));
464dc4ac70fSderaadt explicit_bzero(&hmacctx, sizeof(hmacctx));
465dc4ac70fSderaadt explicit_bzero(&shactx, sizeof(shactx));
466f1072292Sdjm }
467f1072292Sdjm
468f05efa1dShshoexer int
sr_crypto_decrypt_key(struct sr_discipline * sd,struct sr_crypto * mdd_crypto)469eb0e73bdSstsp sr_crypto_decrypt_key(struct sr_discipline *sd, struct sr_crypto *mdd_crypto)
4708c887097Smarco {
471f1072292Sdjm u_char check_digest[SHA1_DIGEST_LENGTH];
47287bb77c2Sjsing int rv = 1;
4731a9d6c4eShshoexer
4744bada3d3Smarco DNPRINTF(SR_D_DIS, "%s: sr_crypto_decrypt_key\n", DEVNAME(sd->sd_sc));
4752b3aca4aSckuethe
476eb0e73bdSstsp if (mdd_crypto->scr_meta->scm_check_alg != SR_CRYPTOC_HMAC_SHA1)
477f1072292Sdjm goto out;
478f1072292Sdjm
479eb0e73bdSstsp if (sr_crypto_decrypt((u_char *)mdd_crypto->scr_meta->scm_key,
480eb0e73bdSstsp (u_char *)mdd_crypto->scr_key,
481eb0e73bdSstsp mdd_crypto->scr_maskkey, sizeof(mdd_crypto->scr_key),
482eb0e73bdSstsp mdd_crypto->scr_meta->scm_mask_alg) == -1)
48387bb77c2Sjsing goto out;
4841a9d6c4eShshoexer
4851a9d6c4eShshoexer #ifdef SR_DEBUG0
486eb0e73bdSstsp sr_crypto_dumpkeys(mdd_crypto);
4871a9d6c4eShshoexer #endif
488772addebSdjm
48987bb77c2Sjsing /* Check that the key decrypted properly. */
490eb0e73bdSstsp sr_crypto_calculate_check_hmac_sha1(mdd_crypto->scr_maskkey,
491eb0e73bdSstsp sizeof(mdd_crypto->scr_maskkey), (u_int8_t *)mdd_crypto->scr_key,
492eb0e73bdSstsp sizeof(mdd_crypto->scr_key), check_digest);
493eb0e73bdSstsp if (memcmp(mdd_crypto->scr_meta->chk_hmac_sha1.sch_mac,
494f1072292Sdjm check_digest, sizeof(check_digest)) != 0) {
495eb0e73bdSstsp explicit_bzero(mdd_crypto->scr_key,
496eb0e73bdSstsp sizeof(mdd_crypto->scr_key));
497f1072292Sdjm goto out;
498f1072292Sdjm }
499f1072292Sdjm
500f1072292Sdjm rv = 0; /* Success */
501772addebSdjm out:
502772addebSdjm /* we don't need the mask key anymore */
503eb0e73bdSstsp explicit_bzero(&mdd_crypto->scr_maskkey,
504eb0e73bdSstsp sizeof(mdd_crypto->scr_maskkey));
50587bb77c2Sjsing
506dc4ac70fSderaadt explicit_bzero(check_digest, sizeof(check_digest));
50787bb77c2Sjsing
508772addebSdjm return rv;
5091a9d6c4eShshoexer }
5101a9d6c4eShshoexer
5118c887097Smarco int
sr_crypto_create_keys(struct sr_discipline * sd,struct sr_crypto * mdd_crypto)512eb0e73bdSstsp sr_crypto_create_keys(struct sr_discipline *sd, struct sr_crypto *mdd_crypto)
5132b3aca4aSckuethe {
5142b3aca4aSckuethe
5152b3aca4aSckuethe DNPRINTF(SR_D_DIS, "%s: sr_crypto_create_keys\n",
5162b3aca4aSckuethe DEVNAME(sd->sd_sc));
5172b3aca4aSckuethe
518eb0e73bdSstsp if (AES_MAXKEYBYTES < sizeof(mdd_crypto->scr_maskkey))
519f05efa1dShshoexer return (1);
5201a9d6c4eShshoexer
521f1072292Sdjm /* XXX allow user to specify */
522eb0e73bdSstsp mdd_crypto->scr_meta->scm_alg = SR_CRYPTOA_AES_XTS_256;
523f1072292Sdjm
5242b3aca4aSckuethe /* generate crypto keys */
525eb0e73bdSstsp arc4random_buf(mdd_crypto->scr_key, sizeof(mdd_crypto->scr_key));
5261a9d6c4eShshoexer
52787bb77c2Sjsing /* Mask the disk keys. */
528eb0e73bdSstsp mdd_crypto->scr_meta->scm_mask_alg = SR_CRYPTOM_AES_ECB_256;
529eb0e73bdSstsp sr_crypto_encrypt((u_char *)mdd_crypto->scr_key,
530eb0e73bdSstsp (u_char *)mdd_crypto->scr_meta->scm_key,
531eb0e73bdSstsp mdd_crypto->scr_maskkey, sizeof(mdd_crypto->scr_key),
532eb0e73bdSstsp mdd_crypto->scr_meta->scm_mask_alg);
533f1072292Sdjm
53487bb77c2Sjsing /* Prepare key decryption check code. */
535eb0e73bdSstsp mdd_crypto->scr_meta->scm_check_alg = SR_CRYPTOC_HMAC_SHA1;
536eb0e73bdSstsp sr_crypto_calculate_check_hmac_sha1(mdd_crypto->scr_maskkey,
537eb0e73bdSstsp sizeof(mdd_crypto->scr_maskkey),
538eb0e73bdSstsp (u_int8_t *)mdd_crypto->scr_key, sizeof(mdd_crypto->scr_key),
539eb0e73bdSstsp mdd_crypto->scr_meta->chk_hmac_sha1.sch_mac);
540f1072292Sdjm
541f1072292Sdjm /* Erase the plaintext disk keys */
542eb0e73bdSstsp explicit_bzero(mdd_crypto->scr_key, sizeof(mdd_crypto->scr_key));
5432b3aca4aSckuethe
5441a9d6c4eShshoexer #ifdef SR_DEBUG0
545eb0e73bdSstsp sr_crypto_dumpkeys(mdd_crypto);
5461a9d6c4eShshoexer #endif
5471a9d6c4eShshoexer
548eb0e73bdSstsp mdd_crypto->scr_meta->scm_flags = SR_CRYPTOF_KEY | SR_CRYPTOF_KDFHINT;
5491a9d6c4eShshoexer
5501a9d6c4eShshoexer return (0);
5512b3aca4aSckuethe }
5522b3aca4aSckuethe
553f18dcc9cStedu int
sr_crypto_change_maskkey(struct sr_discipline * sd,struct sr_crypto * mdd_crypto,struct sr_crypto_kdfinfo * kdfinfo1,struct sr_crypto_kdfinfo * kdfinfo2)554eb0e73bdSstsp sr_crypto_change_maskkey(struct sr_discipline *sd, struct sr_crypto *mdd_crypto,
555c6446370Sjsing struct sr_crypto_kdfinfo *kdfinfo1, struct sr_crypto_kdfinfo *kdfinfo2)
556c6446370Sjsing {
557c6446370Sjsing u_char check_digest[SHA1_DIGEST_LENGTH];
558f4652441Sjsing u_char *c, *p = NULL;
559c6446370Sjsing size_t ksz;
560c6446370Sjsing int rv = 1;
561c6446370Sjsing
562c6446370Sjsing DNPRINTF(SR_D_DIS, "%s: sr_crypto_change_maskkey\n",
563c6446370Sjsing DEVNAME(sd->sd_sc));
564c6446370Sjsing
565eb0e73bdSstsp if (mdd_crypto->scr_meta->scm_check_alg != SR_CRYPTOC_HMAC_SHA1)
566c6446370Sjsing goto out;
567c6446370Sjsing
568eb0e73bdSstsp c = (u_char *)mdd_crypto->scr_meta->scm_key;
569eb0e73bdSstsp ksz = sizeof(mdd_crypto->scr_key);
570e6ca3d0dSmk p = malloc(ksz, M_DEVBUF, M_WAITOK | M_CANFAIL | M_ZERO);
571c6446370Sjsing if (p == NULL)
572c6446370Sjsing goto out;
573c6446370Sjsing
574c6446370Sjsing if (sr_crypto_decrypt(c, p, kdfinfo1->maskkey, ksz,
575eb0e73bdSstsp mdd_crypto->scr_meta->scm_mask_alg) == -1)
576c6446370Sjsing goto out;
577c6446370Sjsing
578c6446370Sjsing #ifdef SR_DEBUG0
579eb0e73bdSstsp sr_crypto_dumpkeys(mdd_crypto);
580c6446370Sjsing #endif
581c6446370Sjsing
582c6446370Sjsing sr_crypto_calculate_check_hmac_sha1(kdfinfo1->maskkey,
583c6446370Sjsing sizeof(kdfinfo1->maskkey), p, ksz, check_digest);
584eb0e73bdSstsp if (memcmp(mdd_crypto->scr_meta->chk_hmac_sha1.sch_mac,
585c6446370Sjsing check_digest, sizeof(check_digest)) != 0) {
5865f082130Sjsing sr_error(sd->sd_sc, "incorrect key or passphrase");
587c6446370Sjsing rv = EPERM;
588c6446370Sjsing goto out;
589c6446370Sjsing }
590c6446370Sjsing
591c0297823Sjsing /* Copy new KDF hint to metadata, if supplied. */
592c0297823Sjsing if (kdfinfo2->flags & SR_CRYPTOKDF_HINT) {
593c0297823Sjsing if (kdfinfo2->genkdf.len >
594eb0e73bdSstsp sizeof(mdd_crypto->scr_meta->scm_kdfhint))
595c0297823Sjsing goto out;
596eb0e73bdSstsp explicit_bzero(mdd_crypto->scr_meta->scm_kdfhint,
597eb0e73bdSstsp sizeof(mdd_crypto->scr_meta->scm_kdfhint));
598eb0e73bdSstsp memcpy(mdd_crypto->scr_meta->scm_kdfhint,
599c0297823Sjsing &kdfinfo2->genkdf, kdfinfo2->genkdf.len);
600c0297823Sjsing }
601c0297823Sjsing
602c6446370Sjsing /* Mask the disk keys. */
603eb0e73bdSstsp c = (u_char *)mdd_crypto->scr_meta->scm_key;
604c6446370Sjsing if (sr_crypto_encrypt(p, c, kdfinfo2->maskkey, ksz,
605eb0e73bdSstsp mdd_crypto->scr_meta->scm_mask_alg) == -1)
606c6446370Sjsing goto out;
607c6446370Sjsing
608c6446370Sjsing /* Prepare key decryption check code. */
609eb0e73bdSstsp mdd_crypto->scr_meta->scm_check_alg = SR_CRYPTOC_HMAC_SHA1;
610c6446370Sjsing sr_crypto_calculate_check_hmac_sha1(kdfinfo2->maskkey,
611eb0e73bdSstsp sizeof(kdfinfo2->maskkey), (u_int8_t *)mdd_crypto->scr_key,
612eb0e73bdSstsp sizeof(mdd_crypto->scr_key), check_digest);
613c6446370Sjsing
614c6446370Sjsing /* Copy new encrypted key and HMAC to metadata. */
615eb0e73bdSstsp memcpy(mdd_crypto->scr_meta->chk_hmac_sha1.sch_mac, check_digest,
616eb0e73bdSstsp sizeof(mdd_crypto->scr_meta->chk_hmac_sha1.sch_mac));
617c6446370Sjsing
618c6446370Sjsing rv = 0; /* Success */
619c6446370Sjsing
620c6446370Sjsing out:
621c6446370Sjsing if (p) {
622dc4ac70fSderaadt explicit_bzero(p, ksz);
623939b6ccfStedu free(p, M_DEVBUF, ksz);
624c6446370Sjsing }
625c6446370Sjsing
626dc4ac70fSderaadt explicit_bzero(check_digest, sizeof(check_digest));
627dc4ac70fSderaadt explicit_bzero(&kdfinfo1->maskkey, sizeof(kdfinfo1->maskkey));
628dc4ac70fSderaadt explicit_bzero(&kdfinfo2->maskkey, sizeof(kdfinfo2->maskkey));
629c6446370Sjsing
630c6446370Sjsing return (rv);
631c6446370Sjsing }
632c6446370Sjsing
6330054cd36Sjsing struct sr_chunk *
sr_crypto_create_key_disk(struct sr_discipline * sd,struct sr_crypto * mdd_crypto,dev_t dev)634eb0e73bdSstsp sr_crypto_create_key_disk(struct sr_discipline *sd,
635eb0e73bdSstsp struct sr_crypto *mdd_crypto, dev_t dev)
6360054cd36Sjsing {
6370054cd36Sjsing struct sr_softc *sc = sd->sd_sc;
6380054cd36Sjsing struct sr_discipline *fakesd = NULL;
6390054cd36Sjsing struct sr_metadata *sm = NULL;
6400054cd36Sjsing struct sr_meta_chunk *km;
641c907def9Sjsing struct sr_meta_opt_item *omi = NULL;
642ee4e3de1Sjsing struct sr_meta_keydisk *skm;
6430054cd36Sjsing struct sr_chunk *key_disk = NULL;
6440054cd36Sjsing struct disklabel label;
6450054cd36Sjsing struct vnode *vn;
6460054cd36Sjsing char devname[32];
6470054cd36Sjsing int c, part, open = 0;
6480054cd36Sjsing
6490054cd36Sjsing /*
6500054cd36Sjsing * Create a metadata structure on the key disk and store
6510054cd36Sjsing * keying material in the optional metadata.
6520054cd36Sjsing */
6530054cd36Sjsing
6540054cd36Sjsing sr_meta_getdevname(sc, dev, devname, sizeof(devname));
6550054cd36Sjsing
6560054cd36Sjsing /* Make sure chunk is not already in use. */
6570054cd36Sjsing c = sr_chunk_in_use(sc, dev);
6580054cd36Sjsing if (c != BIOC_SDINVALID && c != BIOC_SDOFFLINE) {
6595f082130Sjsing sr_error(sc, "%s is already in use", devname);
6600054cd36Sjsing goto done;
6610054cd36Sjsing }
6620054cd36Sjsing
6630054cd36Sjsing /* Open device. */
6640054cd36Sjsing if (bdevvp(dev, &vn)) {
6655f082130Sjsing sr_error(sc, "cannot open key disk %s", devname);
6660054cd36Sjsing goto done;
6670054cd36Sjsing }
668717ea6e5Soga if (VOP_OPEN(vn, FREAD | FWRITE, NOCRED, curproc)) {
669b32544d1Sstsp DNPRINTF(SR_D_META,"%s: sr_crypto_create_key_disk cannot "
670b32544d1Sstsp "open %s\n", DEVNAME(sc), devname);
6710054cd36Sjsing vput(vn);
6727afb22b7Sjsing goto done;
6730054cd36Sjsing }
6740054cd36Sjsing open = 1; /* close dev on error */
6750054cd36Sjsing
6760054cd36Sjsing /* Get partition details. */
6770054cd36Sjsing part = DISKPART(dev);
678717ea6e5Soga if (VOP_IOCTL(vn, DIOCGDINFO, (caddr_t)&label,
679717ea6e5Soga FREAD, NOCRED, curproc)) {
680b32544d1Sstsp DNPRINTF(SR_D_META, "%s: sr_crypto_create_key_disk ioctl "
681b32544d1Sstsp "failed\n", DEVNAME(sc));
6827afb22b7Sjsing goto done;
6830054cd36Sjsing }
6840054cd36Sjsing if (label.d_partitions[part].p_fstype != FS_RAID) {
68531a4dfc2Shalex sr_error(sc, "%s partition not of type RAID (%d)",
6865f082130Sjsing devname, label.d_partitions[part].p_fstype);
6877afb22b7Sjsing goto done;
6880054cd36Sjsing }
6890054cd36Sjsing
6900054cd36Sjsing /*
6910054cd36Sjsing * Create and populate chunk metadata.
6920054cd36Sjsing */
6930054cd36Sjsing
6940054cd36Sjsing key_disk = malloc(sizeof(struct sr_chunk), M_DEVBUF, M_WAITOK | M_ZERO);
6950054cd36Sjsing km = &key_disk->src_meta;
6960054cd36Sjsing
6970054cd36Sjsing key_disk->src_dev_mm = dev;
6980054cd36Sjsing key_disk->src_vn = vn;
6990054cd36Sjsing strlcpy(key_disk->src_devname, devname, sizeof(km->scmi.scm_devname));
7000054cd36Sjsing key_disk->src_size = 0;
7010054cd36Sjsing
7020054cd36Sjsing km->scmi.scm_volid = sd->sd_meta->ssdi.ssd_level;
7030054cd36Sjsing km->scmi.scm_chunk_id = 0;
7040054cd36Sjsing km->scmi.scm_size = 0;
7050054cd36Sjsing km->scmi.scm_coerced_size = 0;
7060054cd36Sjsing strlcpy(km->scmi.scm_devname, devname, sizeof(km->scmi.scm_devname));
707dedb5617Stedu memcpy(&km->scmi.scm_uuid, &sd->sd_meta->ssdi.ssd_uuid,
7080054cd36Sjsing sizeof(struct sr_uuid));
7090054cd36Sjsing
7100054cd36Sjsing sr_checksum(sc, km, &km->scm_checksum,
7110054cd36Sjsing sizeof(struct sr_meta_chunk_invariant));
7120054cd36Sjsing
7130054cd36Sjsing km->scm_status = BIOC_SDONLINE;
7140054cd36Sjsing
7150054cd36Sjsing /*
7160054cd36Sjsing * Create and populate our own discipline and metadata.
7170054cd36Sjsing */
7180054cd36Sjsing
7190054cd36Sjsing sm = malloc(sizeof(struct sr_metadata), M_DEVBUF, M_WAITOK | M_ZERO);
7200054cd36Sjsing sm->ssdi.ssd_magic = SR_MAGIC;
7210054cd36Sjsing sm->ssdi.ssd_version = SR_META_VERSION;
7220054cd36Sjsing sm->ssd_ondisk = 0;
723e5ea34d9Sjsing sm->ssdi.ssd_vol_flags = 0;
724dedb5617Stedu memcpy(&sm->ssdi.ssd_uuid, &sd->sd_meta->ssdi.ssd_uuid,
7250054cd36Sjsing sizeof(struct sr_uuid));
7260054cd36Sjsing sm->ssdi.ssd_chunk_no = 1;
7270054cd36Sjsing sm->ssdi.ssd_volid = SR_KEYDISK_VOLID;
7280054cd36Sjsing sm->ssdi.ssd_level = SR_KEYDISK_LEVEL;
7290054cd36Sjsing sm->ssdi.ssd_size = 0;
7300054cd36Sjsing strlcpy(sm->ssdi.ssd_vendor, "OPENBSD", sizeof(sm->ssdi.ssd_vendor));
7310054cd36Sjsing snprintf(sm->ssdi.ssd_product, sizeof(sm->ssdi.ssd_product),
7320054cd36Sjsing "SR %s", "KEYDISK");
7330054cd36Sjsing snprintf(sm->ssdi.ssd_revision, sizeof(sm->ssdi.ssd_revision),
7340054cd36Sjsing "%03d", SR_META_VERSION);
7350054cd36Sjsing
7360054cd36Sjsing fakesd = malloc(sizeof(struct sr_discipline), M_DEVBUF,
7370054cd36Sjsing M_WAITOK | M_ZERO);
7380054cd36Sjsing fakesd->sd_sc = sd->sd_sc;
7390054cd36Sjsing fakesd->sd_meta = sm;
7400054cd36Sjsing fakesd->sd_meta_type = SR_META_F_NATIVE;
7410054cd36Sjsing fakesd->sd_vol_status = BIOC_SVONLINE;
7420054cd36Sjsing strlcpy(fakesd->sd_name, "KEYDISK", sizeof(fakesd->sd_name));
743c907def9Sjsing SLIST_INIT(&fakesd->sd_meta_opt);
7440054cd36Sjsing
7450054cd36Sjsing /* Add chunk to volume. */
7460054cd36Sjsing fakesd->sd_vol.sv_chunks = malloc(sizeof(struct sr_chunk *), M_DEVBUF,
7470054cd36Sjsing M_WAITOK | M_ZERO);
7480054cd36Sjsing fakesd->sd_vol.sv_chunks[0] = key_disk;
7490054cd36Sjsing SLIST_INIT(&fakesd->sd_vol.sv_chunk_list);
7500054cd36Sjsing SLIST_INSERT_HEAD(&fakesd->sd_vol.sv_chunk_list, key_disk, src_link);
7510054cd36Sjsing
7520054cd36Sjsing /* Generate mask key. */
753eb0e73bdSstsp arc4random_buf(mdd_crypto->scr_maskkey,
754eb0e73bdSstsp sizeof(mdd_crypto->scr_maskkey));
7550054cd36Sjsing
7560054cd36Sjsing /* Copy mask key to optional metadata area. */
757c907def9Sjsing omi = malloc(sizeof(struct sr_meta_opt_item), M_DEVBUF,
758c907def9Sjsing M_WAITOK | M_ZERO);
759ee4e3de1Sjsing omi->omi_som = malloc(sizeof(struct sr_meta_keydisk), M_DEVBUF,
760ee4e3de1Sjsing M_WAITOK | M_ZERO);
761ee4e3de1Sjsing omi->omi_som->som_type = SR_OPT_KEYDISK;
762ee4e3de1Sjsing omi->omi_som->som_length = sizeof(struct sr_meta_keydisk);
763ee4e3de1Sjsing skm = (struct sr_meta_keydisk *)omi->omi_som;
764eb0e73bdSstsp memcpy(&skm->skm_maskkey, mdd_crypto->scr_maskkey,
765ee4e3de1Sjsing sizeof(skm->skm_maskkey));
766c907def9Sjsing SLIST_INSERT_HEAD(&fakesd->sd_meta_opt, omi, omi_link);
767ee4e3de1Sjsing fakesd->sd_meta->ssdi.ssd_opt_no++;
7680054cd36Sjsing
7690054cd36Sjsing /* Save metadata. */
7700054cd36Sjsing if (sr_meta_save(fakesd, SR_META_DIRTY)) {
7715f082130Sjsing sr_error(sc, "could not save metadata to %s", devname);
7720054cd36Sjsing goto fail;
7730054cd36Sjsing }
7740054cd36Sjsing
7750054cd36Sjsing goto done;
7760054cd36Sjsing
7770054cd36Sjsing fail:
778939b6ccfStedu free(key_disk, M_DEVBUF, sizeof(struct sr_chunk));
7790054cd36Sjsing key_disk = NULL;
7800054cd36Sjsing
7810054cd36Sjsing done:
782939b6ccfStedu free(omi, M_DEVBUF, sizeof(struct sr_meta_opt_item));
7830054cd36Sjsing if (fakesd && fakesd->sd_vol.sv_chunks)
784939b6ccfStedu free(fakesd->sd_vol.sv_chunks, M_DEVBUF,
785939b6ccfStedu sizeof(struct sr_chunk *));
786939b6ccfStedu free(fakesd, M_DEVBUF, sizeof(struct sr_discipline));
787939b6ccfStedu free(sm, M_DEVBUF, sizeof(struct sr_metadata));
7880054cd36Sjsing if (open) {
789717ea6e5Soga VOP_CLOSE(vn, FREAD | FWRITE, NOCRED, curproc);
7900054cd36Sjsing vput(vn);
7910054cd36Sjsing }
7920054cd36Sjsing
7930054cd36Sjsing return key_disk;
7940054cd36Sjsing }
7950054cd36Sjsing
7960054cd36Sjsing struct sr_chunk *
sr_crypto_read_key_disk(struct sr_discipline * sd,struct sr_crypto * mdd_crypto,dev_t dev)797eb0e73bdSstsp sr_crypto_read_key_disk(struct sr_discipline *sd, struct sr_crypto *mdd_crypto,
798eb0e73bdSstsp dev_t dev)
7990054cd36Sjsing {
8000054cd36Sjsing struct sr_softc *sc = sd->sd_sc;
8010054cd36Sjsing struct sr_metadata *sm = NULL;
802ee4e3de1Sjsing struct sr_meta_opt_item *omi, *omi_next;
803ee4e3de1Sjsing struct sr_meta_opt_hdr *omh;
804ee4e3de1Sjsing struct sr_meta_keydisk *skm;
805ee4e3de1Sjsing struct sr_meta_opt_head som;
8060054cd36Sjsing struct sr_chunk *key_disk = NULL;
8070054cd36Sjsing struct disklabel label;
808f4652441Sjsing struct vnode *vn = NULL;
8090054cd36Sjsing char devname[32];
8100054cd36Sjsing int c, part, open = 0;
8110054cd36Sjsing
8120054cd36Sjsing /*
8130054cd36Sjsing * Load a key disk and load keying material into memory.
8140054cd36Sjsing */
8150054cd36Sjsing
8166f975bddSjsing SLIST_INIT(&som);
8176f975bddSjsing
8180054cd36Sjsing sr_meta_getdevname(sc, dev, devname, sizeof(devname));
8190054cd36Sjsing
8200054cd36Sjsing /* Make sure chunk is not already in use. */
8210054cd36Sjsing c = sr_chunk_in_use(sc, dev);
8220054cd36Sjsing if (c != BIOC_SDINVALID && c != BIOC_SDOFFLINE) {
8235f082130Sjsing sr_error(sc, "%s is already in use", devname);
8240054cd36Sjsing goto done;
8250054cd36Sjsing }
8260054cd36Sjsing
8270054cd36Sjsing /* Open device. */
8280054cd36Sjsing if (bdevvp(dev, &vn)) {
8295f082130Sjsing sr_error(sc, "cannot open key disk %s", devname);
8300054cd36Sjsing goto done;
8310054cd36Sjsing }
832427d8f53Stedu if (VOP_OPEN(vn, FREAD, NOCRED, curproc)) {
833b32544d1Sstsp DNPRINTF(SR_D_META,"%s: sr_crypto_read_key_disk cannot "
834b32544d1Sstsp "open %s\n", DEVNAME(sc), devname);
8350054cd36Sjsing vput(vn);
8360054cd36Sjsing goto done;
8370054cd36Sjsing }
8380054cd36Sjsing open = 1; /* close dev on error */
8390054cd36Sjsing
8400054cd36Sjsing /* Get partition details. */
8410054cd36Sjsing part = DISKPART(dev);
842717ea6e5Soga if (VOP_IOCTL(vn, DIOCGDINFO, (caddr_t)&label, FREAD,
843717ea6e5Soga NOCRED, curproc)) {
844b32544d1Sstsp DNPRINTF(SR_D_META, "%s: sr_crypto_read_key_disk ioctl "
845b32544d1Sstsp "failed\n", DEVNAME(sc));
8460054cd36Sjsing goto done;
8470054cd36Sjsing }
8480054cd36Sjsing if (label.d_partitions[part].p_fstype != FS_RAID) {
84931a4dfc2Shalex sr_error(sc, "%s partition not of type RAID (%d)",
8505f082130Sjsing devname, label.d_partitions[part].p_fstype);
8510054cd36Sjsing goto done;
8520054cd36Sjsing }
8530054cd36Sjsing
8540054cd36Sjsing /*
8550054cd36Sjsing * Read and validate key disk metadata.
8560054cd36Sjsing */
857db661b81Skrw sm = malloc(SR_META_SIZE * DEV_BSIZE, M_DEVBUF, M_WAITOK | M_ZERO);
8580054cd36Sjsing if (sr_meta_native_read(sd, dev, sm, NULL)) {
8595f082130Sjsing sr_error(sc, "native bootprobe could not read native metadata");
8600054cd36Sjsing goto done;
8610054cd36Sjsing }
8620054cd36Sjsing
8630054cd36Sjsing if (sr_meta_validate(sd, dev, sm, NULL)) {
8640054cd36Sjsing DNPRINTF(SR_D_META, "%s: invalid metadata\n",
8650054cd36Sjsing DEVNAME(sc));
8660054cd36Sjsing goto done;
8670054cd36Sjsing }
8680054cd36Sjsing
8690054cd36Sjsing /* Make sure this is a key disk. */
8700054cd36Sjsing if (sm->ssdi.ssd_level != SR_KEYDISK_LEVEL) {
8715f082130Sjsing sr_error(sc, "%s is not a key disk", devname);
8720054cd36Sjsing goto done;
8730054cd36Sjsing }
8740054cd36Sjsing
8750054cd36Sjsing /* Construct key disk chunk. */
8767af3f0fdSmarco key_disk = malloc(sizeof(struct sr_chunk), M_DEVBUF, M_WAITOK | M_ZERO);
8770054cd36Sjsing key_disk->src_dev_mm = dev;
8780054cd36Sjsing key_disk->src_vn = vn;
8790054cd36Sjsing key_disk->src_size = 0;
8800054cd36Sjsing
881dedb5617Stedu memcpy(&key_disk->src_meta, (struct sr_meta_chunk *)(sm + 1),
8820054cd36Sjsing sizeof(key_disk->src_meta));
8830054cd36Sjsing
8840054cd36Sjsing /* Read mask key from optional metadata. */
885ee4e3de1Sjsing sr_meta_opt_load(sc, sm, &som);
886ee4e3de1Sjsing SLIST_FOREACH(omi, &som, omi_link) {
887ee4e3de1Sjsing omh = omi->omi_som;
888ee4e3de1Sjsing if (omh->som_type == SR_OPT_KEYDISK) {
889ee4e3de1Sjsing skm = (struct sr_meta_keydisk *)omh;
890eb0e73bdSstsp memcpy(mdd_crypto->scr_maskkey, &skm->skm_maskkey,
891eb0e73bdSstsp sizeof(mdd_crypto->scr_maskkey));
892ee4e3de1Sjsing } else if (omh->som_type == SR_OPT_CRYPTO) {
893ee4e3de1Sjsing /* Original keydisk format with key in crypto area. */
894eb0e73bdSstsp memcpy(mdd_crypto->scr_maskkey,
895dedb5617Stedu omh + sizeof(struct sr_meta_opt_hdr),
896eb0e73bdSstsp sizeof(mdd_crypto->scr_maskkey));
8970054cd36Sjsing }
8980054cd36Sjsing }
8990054cd36Sjsing
9000054cd36Sjsing open = 0;
9010054cd36Sjsing
9020054cd36Sjsing done:
903abcbcc4dSdoug for (omi = SLIST_FIRST(&som); omi != NULL; omi = omi_next) {
904ee4e3de1Sjsing omi_next = SLIST_NEXT(omi, omi_link);
905df2ac69fStedu free(omi->omi_som, M_DEVBUF, 0);
9060efc153bSkn free(omi, M_DEVBUF, sizeof(struct sr_meta_opt_item));
907ee4e3de1Sjsing }
908ee4e3de1Sjsing
909db661b81Skrw free(sm, M_DEVBUF, SR_META_SIZE * DEV_BSIZE);
9100054cd36Sjsing
9110054cd36Sjsing if (vn && open) {
912717ea6e5Soga VOP_CLOSE(vn, FREAD, NOCRED, curproc);
9130054cd36Sjsing vput(vn);
9140054cd36Sjsing }
9150054cd36Sjsing
9160054cd36Sjsing return key_disk;
9170054cd36Sjsing }
9180054cd36Sjsing
919eb0e73bdSstsp void
sr_crypto_free_sessions(struct sr_discipline * sd,struct sr_crypto * mdd_crypto)920eb0e73bdSstsp sr_crypto_free_sessions(struct sr_discipline *sd, struct sr_crypto *mdd_crypto)
9212dc30802Sjsing {
9222dc30802Sjsing u_int i;
9232dc30802Sjsing
924f6a8865dSjsing for (i = 0; i < SR_CRYPTO_MAXKEYS; i++) {
925eb0e73bdSstsp if (mdd_crypto->scr_sid[i] != (u_int64_t)-1) {
926eb0e73bdSstsp crypto_freesession(mdd_crypto->scr_sid[i]);
927eb0e73bdSstsp mdd_crypto->scr_sid[i] = (u_int64_t)-1;
9282dc30802Sjsing }
9292dc30802Sjsing }
930f6a8865dSjsing }
9312dc30802Sjsing
932c6446370Sjsing int
sr_crypto_alloc_resources_internal(struct sr_discipline * sd,struct sr_crypto * mdd_crypto)933eb0e73bdSstsp sr_crypto_alloc_resources_internal(struct sr_discipline *sd,
934eb0e73bdSstsp struct sr_crypto *mdd_crypto)
935f18dcc9cStedu {
93632917a3bSjsing struct sr_workunit *wu;
937117fae6fSoga struct sr_crypto_wu *crwu;
93832917a3bSjsing struct cryptoini cri;
93975b43c32Sdjm u_int num_keys, i;
9401a9d6c4eShshoexer
941f18dcc9cStedu DNPRINTF(SR_D_DIS, "%s: sr_crypto_alloc_resources\n",
942f18dcc9cStedu DEVNAME(sd->sd_sc));
943f18dcc9cStedu
944eb0e73bdSstsp mdd_crypto->scr_alg = CRYPTO_AES_XTS;
945eb0e73bdSstsp switch (mdd_crypto->scr_meta->scm_alg) {
9466d198fe3Sjsing case SR_CRYPTOA_AES_XTS_128:
947eb0e73bdSstsp mdd_crypto->scr_klen = 256;
9486d198fe3Sjsing break;
9496d198fe3Sjsing case SR_CRYPTOA_AES_XTS_256:
950eb0e73bdSstsp mdd_crypto->scr_klen = 512;
9516d198fe3Sjsing break;
9526d198fe3Sjsing default:
953b1789a25Sjsing sr_error(sd->sd_sc, "unknown crypto algorithm");
9546d198fe3Sjsing return (EINVAL);
9556d198fe3Sjsing }
9566d198fe3Sjsing
95775b43c32Sdjm for (i = 0; i < SR_CRYPTO_MAXKEYS; i++)
958eb0e73bdSstsp mdd_crypto->scr_sid[i] = (u_int64_t)-1;
95975b43c32Sdjm
9602d9211fdSbluhm if (sr_wu_alloc(sd)) {
9615f082130Sjsing sr_error(sd->sd_sc, "unable to allocate work units");
9621a9d6c4eShshoexer return (ENOMEM);
9635f082130Sjsing }
9645f082130Sjsing if (sr_ccb_alloc(sd)) {
9655f082130Sjsing sr_error(sd->sd_sc, "unable to allocate CCBs");
966f1072292Sdjm return (ENOMEM);
9675f082130Sjsing }
968eb0e73bdSstsp if (sr_crypto_decrypt_key(sd, mdd_crypto)) {
9695f082130Sjsing sr_error(sd->sd_sc, "incorrect key or passphrase");
970f1072292Sdjm return (EPERM);
9715f082130Sjsing }
9725f082130Sjsing
973117fae6fSoga /*
97432917a3bSjsing * For each work unit allocate the uio, iovec and crypto structures.
97532917a3bSjsing * These have to be allocated now because during runtime we cannot
97632917a3bSjsing * fail an allocation without failing the I/O (which can cause real
977117fae6fSoga * problems).
978117fae6fSoga */
97932917a3bSjsing TAILQ_FOREACH(wu, &sd->sd_wu, swu_next) {
98032917a3bSjsing crwu = (struct sr_crypto_wu *)wu;
981117fae6fSoga crwu->cr_uio.uio_iov = &crwu->cr_iov;
982117fae6fSoga crwu->cr_dmabuf = dma_alloc(MAXPHYS, PR_WAITOK);
983117fae6fSoga crwu->cr_crp = crypto_getreq(MAXPHYS >> DEV_BSHIFT);
984117fae6fSoga if (crwu->cr_crp == NULL)
985117fae6fSoga return (ENOMEM);
986117fae6fSoga }
9871a9d6c4eShshoexer
9886d198fe3Sjsing memset(&cri, 0, sizeof(cri));
989eb0e73bdSstsp cri.cri_alg = mdd_crypto->scr_alg;
990eb0e73bdSstsp cri.cri_klen = mdd_crypto->scr_klen;
9911a9d6c4eShshoexer
99232917a3bSjsing /* Allocate a session for every 2^SR_CRYPTO_KEY_BLKSHIFT blocks. */
993b436e181Sjsing num_keys = ((sd->sd_meta->ssdi.ssd_size - 1) >>
994b436e181Sjsing SR_CRYPTO_KEY_BLKSHIFT) + 1;
995b436e181Sjsing if (num_keys > SR_CRYPTO_MAXKEYS)
99675b43c32Sdjm return (EFBIG);
997b436e181Sjsing for (i = 0; i < num_keys; i++) {
998eb0e73bdSstsp cri.cri_key = mdd_crypto->scr_key[i];
999eb0e73bdSstsp if (crypto_newsession(&mdd_crypto->scr_sid[i],
100075b43c32Sdjm &cri, 0) != 0) {
1001eb0e73bdSstsp sr_crypto_free_sessions(sd, mdd_crypto);
100275b43c32Sdjm return (EINVAL);
100375b43c32Sdjm }
100475b43c32Sdjm }
100575b43c32Sdjm
10069b1bb5e7Smarco sr_hotplug_register(sd, sr_crypto_hotplug);
10079b1bb5e7Smarco
100875b43c32Sdjm return (0);
1009f18dcc9cStedu }
1010f18dcc9cStedu
1011eb0e73bdSstsp int
sr_crypto_alloc_resources(struct sr_discipline * sd)1012eb0e73bdSstsp sr_crypto_alloc_resources(struct sr_discipline *sd)
1013eb0e73bdSstsp {
1014eb0e73bdSstsp return sr_crypto_alloc_resources_internal(sd, &sd->mds.mdd_crypto);
1015eb0e73bdSstsp }
1016eb0e73bdSstsp
1017820ef724Sjsing void
sr_crypto_free_resources_internal(struct sr_discipline * sd,struct sr_crypto * mdd_crypto)1018eb0e73bdSstsp sr_crypto_free_resources_internal(struct sr_discipline *sd,
1019eb0e73bdSstsp struct sr_crypto *mdd_crypto)
1020f18dcc9cStedu {
102132917a3bSjsing struct sr_workunit *wu;
1022117fae6fSoga struct sr_crypto_wu *crwu;
10231a9d6c4eShshoexer
1024f18dcc9cStedu DNPRINTF(SR_D_DIS, "%s: sr_crypto_free_resources\n",
1025f18dcc9cStedu DEVNAME(sd->sd_sc));
1026f18dcc9cStedu
1027eb0e73bdSstsp if (mdd_crypto->key_disk != NULL) {
1028eb0e73bdSstsp explicit_bzero(mdd_crypto->key_disk,
1029eb0e73bdSstsp sizeof(*mdd_crypto->key_disk));
1030eb0e73bdSstsp free(mdd_crypto->key_disk, M_DEVBUF,
1031eb0e73bdSstsp sizeof(*mdd_crypto->key_disk));
1032991a346aSmarco }
10330054cd36Sjsing
10349b1bb5e7Smarco sr_hotplug_unregister(sd, sr_crypto_hotplug);
10359b1bb5e7Smarco
1036eb0e73bdSstsp sr_crypto_free_sessions(sd, mdd_crypto);
103775b43c32Sdjm
103832917a3bSjsing TAILQ_FOREACH(wu, &sd->sd_wu, swu_next) {
103932917a3bSjsing crwu = (struct sr_crypto_wu *)wu;
104032917a3bSjsing if (crwu->cr_dmabuf)
1041117fae6fSoga dma_free(crwu->cr_dmabuf, MAXPHYS);
1042e410e70dSpatrick if (crwu->cr_crp)
1043117fae6fSoga crypto_freereq(crwu->cr_crp);
1044117fae6fSoga }
1045117fae6fSoga
1046080cddd5Smarco sr_wu_free(sd);
1047080cddd5Smarco sr_ccb_free(sd);
1048f18dcc9cStedu }
1049f18dcc9cStedu
1050eb0e73bdSstsp void
sr_crypto_free_resources(struct sr_discipline * sd)1051eb0e73bdSstsp sr_crypto_free_resources(struct sr_discipline *sd)
1052eb0e73bdSstsp {
1053eb0e73bdSstsp struct sr_crypto *mdd_crypto = &sd->mds.mdd_crypto;
1054eb0e73bdSstsp sr_crypto_free_resources_internal(sd, mdd_crypto);
1055eb0e73bdSstsp }
1056eb0e73bdSstsp
1057f18dcc9cStedu int
sr_crypto_ioctl_internal(struct sr_discipline * sd,struct sr_crypto * mdd_crypto,struct bioc_discipline * bd)1058eb0e73bdSstsp sr_crypto_ioctl_internal(struct sr_discipline *sd,
1059eb0e73bdSstsp struct sr_crypto *mdd_crypto, struct bioc_discipline *bd)
1060c6446370Sjsing {
1061c6446370Sjsing struct sr_crypto_kdfpair kdfpair;
1062c6446370Sjsing struct sr_crypto_kdfinfo kdfinfo1, kdfinfo2;
1063c6446370Sjsing int size, rv = 1;
1064c6446370Sjsing
10650054cd36Sjsing DNPRINTF(SR_D_IOCTL, "%s: sr_crypto_ioctl %u\n",
10660054cd36Sjsing DEVNAME(sd->sd_sc), bd->bd_cmd);
1067c6446370Sjsing
1068c6446370Sjsing switch (bd->bd_cmd) {
1069c6446370Sjsing case SR_IOCTL_GET_KDFHINT:
1070c6446370Sjsing
1071c6446370Sjsing /* Get KDF hint for userland. */
1072eb0e73bdSstsp size = sizeof(mdd_crypto->scr_meta->scm_kdfhint);
1073c6446370Sjsing if (bd->bd_data == NULL || bd->bd_size > size)
1074c6446370Sjsing goto bad;
1075eb0e73bdSstsp if (copyout(mdd_crypto->scr_meta->scm_kdfhint,
1076c6446370Sjsing bd->bd_data, bd->bd_size))
1077c6446370Sjsing goto bad;
1078c6446370Sjsing
1079c6446370Sjsing rv = 0;
1080c6446370Sjsing
1081c6446370Sjsing break;
1082c6446370Sjsing
1083c6446370Sjsing case SR_IOCTL_CHANGE_PASSPHRASE:
1084c6446370Sjsing
1085c6446370Sjsing /* Attempt to change passphrase. */
1086c6446370Sjsing
1087c6446370Sjsing size = sizeof(kdfpair);
1088c6446370Sjsing if (bd->bd_data == NULL || bd->bd_size > size)
1089c6446370Sjsing goto bad;
1090c6446370Sjsing if (copyin(bd->bd_data, &kdfpair, size))
1091c6446370Sjsing goto bad;
1092c6446370Sjsing
1093c6446370Sjsing size = sizeof(kdfinfo1);
1094c6446370Sjsing if (kdfpair.kdfinfo1 == NULL || kdfpair.kdfsize1 > size)
1095c6446370Sjsing goto bad;
1096c6446370Sjsing if (copyin(kdfpair.kdfinfo1, &kdfinfo1, size))
1097c6446370Sjsing goto bad;
1098c6446370Sjsing
1099c6446370Sjsing size = sizeof(kdfinfo2);
1100c6446370Sjsing if (kdfpair.kdfinfo2 == NULL || kdfpair.kdfsize2 > size)
1101c6446370Sjsing goto bad;
1102c6446370Sjsing if (copyin(kdfpair.kdfinfo2, &kdfinfo2, size))
1103c6446370Sjsing goto bad;
1104c6446370Sjsing
1105eb0e73bdSstsp if (sr_crypto_change_maskkey(sd, mdd_crypto, &kdfinfo1,
1106eb0e73bdSstsp &kdfinfo2))
1107c6446370Sjsing goto bad;
1108c6446370Sjsing
1109c6446370Sjsing /* Save metadata to disk. */
1110c6446370Sjsing rv = sr_meta_save(sd, SR_META_DIRTY);
1111c6446370Sjsing
1112c6446370Sjsing break;
1113c6446370Sjsing }
1114c6446370Sjsing
1115c6446370Sjsing bad:
11161536adc6Sderaadt explicit_bzero(&kdfpair, sizeof(kdfpair));
11171536adc6Sderaadt explicit_bzero(&kdfinfo1, sizeof(kdfinfo1));
1118601c696aSmatthew explicit_bzero(&kdfinfo2, sizeof(kdfinfo2));
11195f082130Sjsing
1120c6446370Sjsing return (rv);
1121c6446370Sjsing }
1122c6446370Sjsing
1123c6446370Sjsing int
sr_crypto_ioctl(struct sr_discipline * sd,struct bioc_discipline * bd)1124eb0e73bdSstsp sr_crypto_ioctl(struct sr_discipline *sd, struct bioc_discipline *bd)
1125eb0e73bdSstsp {
1126eb0e73bdSstsp struct sr_crypto *mdd_crypto = &sd->mds.mdd_crypto;
1127eb0e73bdSstsp return sr_crypto_ioctl_internal(sd, mdd_crypto, bd);
1128eb0e73bdSstsp }
1129eb0e73bdSstsp
1130eb0e73bdSstsp int
sr_crypto_meta_opt_handler_internal(struct sr_discipline * sd,struct sr_crypto * mdd_crypto,struct sr_meta_opt_hdr * om)1131eb0e73bdSstsp sr_crypto_meta_opt_handler_internal(struct sr_discipline *sd,
1132eb0e73bdSstsp struct sr_crypto *mdd_crypto, struct sr_meta_opt_hdr *om)
1133c907def9Sjsing {
1134c907def9Sjsing int rv = EINVAL;
1135c907def9Sjsing
1136ee4e3de1Sjsing if (om->som_type == SR_OPT_CRYPTO) {
1137eb0e73bdSstsp mdd_crypto->scr_meta = (struct sr_meta_crypto *)om;
1138c907def9Sjsing rv = 0;
1139c907def9Sjsing }
1140c907def9Sjsing
11417af3f0fdSmarco return (rv);
1142c907def9Sjsing }
1143c907def9Sjsing
1144c907def9Sjsing int
sr_crypto_meta_opt_handler(struct sr_discipline * sd,struct sr_meta_opt_hdr * om)1145eb0e73bdSstsp sr_crypto_meta_opt_handler(struct sr_discipline *sd, struct sr_meta_opt_hdr *om)
1146eb0e73bdSstsp {
1147eb0e73bdSstsp struct sr_crypto *mdd_crypto = &sd->mds.mdd_crypto;
1148eb0e73bdSstsp return sr_crypto_meta_opt_handler_internal(sd, mdd_crypto, om);
1149eb0e73bdSstsp }
1150eb0e73bdSstsp
1151eb0e73bdSstsp int
sr_crypto_rw(struct sr_workunit * wu)1152f18dcc9cStedu sr_crypto_rw(struct sr_workunit *wu)
1153f18dcc9cStedu {
1154117fae6fSoga struct sr_crypto_wu *crwu;
1155eb0e73bdSstsp struct sr_crypto *mdd_crypto;
1156d9ec6765Skrw daddr_t blkno;
1157*87edded1Stobhe int rv, err;
1158*87edded1Stobhe int s;
11591a9d6c4eShshoexer
1160da6c711cSjsing DNPRINTF(SR_D_DIS, "%s: sr_crypto_rw wu %p\n",
1161f18dcc9cStedu DEVNAME(wu->swu_dis->sd_sc), wu);
1162f18dcc9cStedu
1163d9ec6765Skrw if (sr_validate_io(wu, &blkno, "sr_crypto_rw"))
1164da6c711cSjsing return (1);
1165da6c711cSjsing
11661a9d6c4eShshoexer if (wu->swu_xs->flags & SCSI_DATA_OUT) {
1167eb0e73bdSstsp mdd_crypto = &wu->swu_dis->mds.mdd_crypto;
1168eb0e73bdSstsp crwu = sr_crypto_prepare(wu, mdd_crypto, 1);
1169*87edded1Stobhe rv = crypto_invoke(crwu->cr_crp);
11701a9d6c4eShshoexer
1171*87edded1Stobhe DNPRINTF(SR_D_INTR, "%s: sr_crypto_rw: wu %p xs: %p\n",
11721a9d6c4eShshoexer DEVNAME(wu->swu_dis->sd_sc), wu, wu->swu_xs);
11731a9d6c4eShshoexer
1174*87edded1Stobhe if (rv) {
11751a9d6c4eShshoexer /* fail io */
1176117fae6fSoga wu->swu_xs->error = XS_DRIVER_STUFFUP;
11771a9d6c4eShshoexer s = splbio();
1178005b00e4Sjsing sr_scsi_done(wu->swu_dis, wu->swu_xs);
11791a9d6c4eShshoexer splx(s);
11801a9d6c4eShshoexer }
11811a9d6c4eShshoexer
1182*87edded1Stobhe if ((err = sr_crypto_dev_rw(wu, crwu)) != 0)
1183*87edded1Stobhe return err;
1184*87edded1Stobhe } else
1185*87edded1Stobhe rv = sr_crypto_dev_rw(wu, NULL);
1186*87edded1Stobhe
1187*87edded1Stobhe return (rv);
11881a9d6c4eShshoexer }
11891a9d6c4eShshoexer
11901a9d6c4eShshoexer int
sr_crypto_dev_rw(struct sr_workunit * wu,struct sr_crypto_wu * crwu)1191d8e58a88Sjsing sr_crypto_dev_rw(struct sr_workunit *wu, struct sr_crypto_wu *crwu)
11921a9d6c4eShshoexer {
11931a9d6c4eShshoexer struct sr_discipline *sd = wu->swu_dis;
11941a9d6c4eShshoexer struct scsi_xfer *xs = wu->swu_xs;
11951a9d6c4eShshoexer struct sr_ccb *ccb;
11961a9d6c4eShshoexer struct uio *uio;
1197d9ec6765Skrw daddr_t blkno;
11981a9d6c4eShshoexer
1199d9ec6765Skrw blkno = wu->swu_blk_start;
12001a9d6c4eShshoexer
1201d9ec6765Skrw ccb = sr_ccb_rw(sd, 0, blkno, xs->datalen, xs->data, xs->flags, 0);
12021a9d6c4eShshoexer if (!ccb) {
12031a9d6c4eShshoexer /* should never happen but handle more gracefully */
12041a9d6c4eShshoexer printf("%s: %s: too many ccbs queued\n",
1205080cddd5Smarco DEVNAME(sd->sd_sc), sd->sd_meta->ssd_devname);
12061a9d6c4eShshoexer goto bad;
12071a9d6c4eShshoexer }
1208e79f9674Sjsing if (!ISSET(xs->flags, SCSI_DATA_IN)) {
1209117fae6fSoga uio = crwu->cr_crp->crp_buf;
12101a9d6c4eShshoexer ccb->ccb_buf.b_data = uio->uio_iov->iov_base;
1211117fae6fSoga ccb->ccb_opaque = crwu;
12121a9d6c4eShshoexer }
1213e79f9674Sjsing sr_wu_enqueue_ccb(wu, ccb);
121460781f8cSjsing sr_schedule_wu(wu);
12151a9d6c4eShshoexer
12161a9d6c4eShshoexer return (0);
121760781f8cSjsing
12181a9d6c4eShshoexer bad:
1219*87edded1Stobhe return (EINVAL);
1220f18dcc9cStedu }
12211a9d6c4eShshoexer
12221a9d6c4eShshoexer void
sr_crypto_done_internal(struct sr_workunit * wu,struct sr_crypto * mdd_crypto)1223eb0e73bdSstsp sr_crypto_done_internal(struct sr_workunit *wu, struct sr_crypto *mdd_crypto)
1224e79f9674Sjsing {
1225e79f9674Sjsing struct scsi_xfer *xs = wu->swu_xs;
1226e79f9674Sjsing struct sr_crypto_wu *crwu;
1227*87edded1Stobhe int rv;
1228e79f9674Sjsing int s;
12291a9d6c4eShshoexer
123001de20b5Sstsp if (ISSET(wu->swu_flags, SR_WUF_REBUILD)) /* RAID 1C */
123101de20b5Sstsp return;
123201de20b5Sstsp
1233e79f9674Sjsing /* If this was a successful read, initiate decryption of the data. */
1234e79f9674Sjsing if (ISSET(xs->flags, SCSI_DATA_IN) && xs->error == XS_NOERROR) {
1235eb0e73bdSstsp crwu = sr_crypto_prepare(wu, mdd_crypto, 0);
123612758001Stobhe DNPRINTF(SR_D_INTR, "%s: sr_crypto_done: crypto_invoke %p\n",
1237e79f9674Sjsing DEVNAME(wu->swu_dis->sd_sc), crwu->cr_crp);
1238*87edded1Stobhe rv = crypto_invoke(crwu->cr_crp);
1239*87edded1Stobhe
1240*87edded1Stobhe DNPRINTF(SR_D_INTR, "%s: sr_crypto_done: wu %p xs: %p\n",
1241*87edded1Stobhe DEVNAME(wu->swu_dis->sd_sc), wu, wu->swu_xs);
1242*87edded1Stobhe
1243*87edded1Stobhe if (rv)
1244*87edded1Stobhe wu->swu_xs->error = XS_DRIVER_STUFFUP;
1245*87edded1Stobhe
1246*87edded1Stobhe s = splbio();
1247*87edded1Stobhe sr_scsi_done(wu->swu_dis, wu->swu_xs);
1248*87edded1Stobhe splx(s);
1249e79f9674Sjsing return;
12501a9d6c4eShshoexer }
12511a9d6c4eShshoexer
1252e79f9674Sjsing s = splbio();
1253005b00e4Sjsing sr_scsi_done(wu->swu_dis, wu->swu_xs);
12541a9d6c4eShshoexer splx(s);
12551a9d6c4eShshoexer }
12561a9d6c4eShshoexer
1257faa5c633Sbluhm void
sr_crypto_done(struct sr_workunit * wu)1258eb0e73bdSstsp sr_crypto_done(struct sr_workunit *wu)
1259eb0e73bdSstsp {
1260eb0e73bdSstsp struct sr_crypto *mdd_crypto = &wu->swu_dis->mds.mdd_crypto;
1261eb0e73bdSstsp sr_crypto_done_internal(wu, mdd_crypto);
1262eb0e73bdSstsp }
1263eb0e73bdSstsp
1264eb0e73bdSstsp void
sr_crypto_hotplug(struct sr_discipline * sd,struct disk * diskp,int action)12659b1bb5e7Smarco sr_crypto_hotplug(struct sr_discipline *sd, struct disk *diskp, int action)
12669b1bb5e7Smarco {
12679b1bb5e7Smarco DNPRINTF(SR_D_MISC, "%s: sr_crypto_hotplug: %s %d\n",
12689b1bb5e7Smarco DEVNAME(sd->sd_sc), diskp->dk_name, action);
12699b1bb5e7Smarco }
12709b1bb5e7Smarco
12711a9d6c4eShshoexer #ifdef SR_DEBUG0
12721a9d6c4eShshoexer void
sr_crypto_dumpkeys(struct sr_crypto * mdd_crypto)1273eb0e73bdSstsp sr_crypto_dumpkeys(struct sr_crypto *mdd_crypto)
12741a9d6c4eShshoexer {
12751a9d6c4eShshoexer int i, j;
12761a9d6c4eShshoexer
12771a9d6c4eShshoexer printf("sr_crypto_dumpkeys:\n");
12781a9d6c4eShshoexer for (i = 0; i < SR_CRYPTO_MAXKEYS; i++) {
12791a9d6c4eShshoexer printf("\tscm_key[%d]: 0x", i);
12801a9d6c4eShshoexer for (j = 0; j < SR_CRYPTO_KEYBYTES; j++) {
1281eb0e73bdSstsp printf("%02x", mdd_crypto->scr_meta->scm_key[i][j]);
12821a9d6c4eShshoexer }
12831a9d6c4eShshoexer printf("\n");
12841a9d6c4eShshoexer }
12851a9d6c4eShshoexer printf("sr_crypto_dumpkeys: runtime data keys:\n");
12861a9d6c4eShshoexer for (i = 0; i < SR_CRYPTO_MAXKEYS; i++) {
12871a9d6c4eShshoexer printf("\tscr_key[%d]: 0x", i);
12881a9d6c4eShshoexer for (j = 0; j < SR_CRYPTO_KEYBYTES; j++) {
1289eb0e73bdSstsp printf("%02x", mdd_crypto->scr_key[i][j]);
12901a9d6c4eShshoexer }
12911a9d6c4eShshoexer printf("\n");
12921a9d6c4eShshoexer }
12931a9d6c4eShshoexer }
12941a9d6c4eShshoexer #endif /* SR_DEBUG */
1295