xref: /openbsd-src/sys/dev/softraid_crypto.c (revision 87edded1683044e3d2775bb27ee8e9db185147d3)
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