xref: /illumos-gate/usr/src/uts/common/fs/smbclnt/netsmb/smb3_crypt.c (revision 48e11a6ea0245c522078ddb86a73f16c8c28b949)
1*48e11a6eSGordon Ross /*
2*48e11a6eSGordon Ross  * This file and its contents are supplied under the terms of the
3*48e11a6eSGordon Ross  * Common Development and Distribution License ("CDDL"), version 1.0.
4*48e11a6eSGordon Ross  * You may only use this file in accordance with the terms of version
5*48e11a6eSGordon Ross  * 1.0 of the CDDL.
6*48e11a6eSGordon Ross  *
7*48e11a6eSGordon Ross  * A full copy of the text of the CDDL should have accompanied this
8*48e11a6eSGordon Ross  * source.  A copy of the CDDL is also available via the Internet at
9*48e11a6eSGordon Ross  * http://www.illumos.org/license/CDDL.
10*48e11a6eSGordon Ross  */
11*48e11a6eSGordon Ross 
12*48e11a6eSGordon Ross /*
13*48e11a6eSGordon Ross  * Copyright 2019 Nexenta Systems, Inc.  All rights reserved.
14*48e11a6eSGordon Ross  * Copyright 2024 RackTop Systems, Inc.
15*48e11a6eSGordon Ross  */
16*48e11a6eSGordon Ross 
17*48e11a6eSGordon Ross /*
18*48e11a6eSGordon Ross  * Support for SMB3 encryption (message privacy)
19*48e11a6eSGordon Ross  */
20*48e11a6eSGordon Ross 
21*48e11a6eSGordon Ross #include <sys/param.h>
22*48e11a6eSGordon Ross #include <sys/systm.h>
23*48e11a6eSGordon Ross #include <sys/conf.h>
24*48e11a6eSGordon Ross #include <sys/proc.h>
25*48e11a6eSGordon Ross #include <sys/fcntl.h>
26*48e11a6eSGordon Ross #include <sys/socket.h>
27*48e11a6eSGordon Ross #include <sys/kmem.h>
28*48e11a6eSGordon Ross #include <sys/errno.h>
29*48e11a6eSGordon Ross #include <sys/cmn_err.h>
30*48e11a6eSGordon Ross #include <sys/random.h>
31*48e11a6eSGordon Ross #include <sys/stream.h>
32*48e11a6eSGordon Ross #include <sys/strsun.h>
33*48e11a6eSGordon Ross #include <sys/sdt.h>
34*48e11a6eSGordon Ross 
35*48e11a6eSGordon Ross #include <netsmb/smb_osdep.h>
36*48e11a6eSGordon Ross #include <netsmb/smb2.h>
37*48e11a6eSGordon Ross #include <netsmb/smb_conn.h>
38*48e11a6eSGordon Ross #include <netsmb/smb_subr.h>
39*48e11a6eSGordon Ross #include <netsmb/smb_dev.h>
40*48e11a6eSGordon Ross #include <netsmb/smb_rq.h>
41*48e11a6eSGordon Ross 
42*48e11a6eSGordon Ross #include <netsmb/nsmb_kcrypt.h>
43*48e11a6eSGordon Ross 
44*48e11a6eSGordon Ross #define	SMB3_TFORM_HDR_SIZE	52
45*48e11a6eSGordon Ross #define	SMB3_NONCE_OFFS		20
46*48e11a6eSGordon Ross #define	SMB3_SIG_OFFS		4
47*48e11a6eSGordon Ross 
48*48e11a6eSGordon Ross static const uint8_t SMB3_CRYPT_SIG[4] = { 0xFD, 'S', 'M', 'B' };
49*48e11a6eSGordon Ross 
50*48e11a6eSGordon Ross /*
51*48e11a6eSGordon Ross  * Initialize crypto mechanisms we'll need.
52*48e11a6eSGordon Ross  * Called after negotiate.
53*48e11a6eSGordon Ross  */
54*48e11a6eSGordon Ross void
nsmb_crypt_init_mech(struct smb_vc * vcp)55*48e11a6eSGordon Ross nsmb_crypt_init_mech(struct smb_vc *vcp)
56*48e11a6eSGordon Ross {
57*48e11a6eSGordon Ross 	smb_crypto_mech_t *mech;
58*48e11a6eSGordon Ross 	int rc;
59*48e11a6eSGordon Ross 
60*48e11a6eSGordon Ross 	if (vcp->vc3_crypt_mech != NULL)
61*48e11a6eSGordon Ross 		return;
62*48e11a6eSGordon Ross 
63*48e11a6eSGordon Ross 	mech = kmem_zalloc(sizeof (*mech), KM_SLEEP);
64*48e11a6eSGordon Ross 
65*48e11a6eSGordon Ross 	/* Always CCM for now. */
66*48e11a6eSGordon Ross 	rc = nsmb_aes_ccm_getmech(mech);
67*48e11a6eSGordon Ross 	if (rc != 0) {
68*48e11a6eSGordon Ross 		kmem_free(mech, sizeof (*mech));
69*48e11a6eSGordon Ross 		cmn_err(CE_NOTE, "SMB3 found no AES mechanism"
70*48e11a6eSGordon Ross 		    " (encryption disabled)");
71*48e11a6eSGordon Ross 		return;
72*48e11a6eSGordon Ross 	}
73*48e11a6eSGordon Ross 	vcp->vc3_crypt_mech = mech;
74*48e11a6eSGordon Ross }
75*48e11a6eSGordon Ross 
76*48e11a6eSGordon Ross void
nsmb_crypt_free_mech(struct smb_vc * vcp)77*48e11a6eSGordon Ross nsmb_crypt_free_mech(struct smb_vc *vcp)
78*48e11a6eSGordon Ross {
79*48e11a6eSGordon Ross 	smb_crypto_mech_t *mech;
80*48e11a6eSGordon Ross 
81*48e11a6eSGordon Ross 	if ((mech = vcp->vc3_crypt_mech) == NULL)
82*48e11a6eSGordon Ross 		return;
83*48e11a6eSGordon Ross 
84*48e11a6eSGordon Ross 	kmem_free(mech, sizeof (*mech));
85*48e11a6eSGordon Ross }
86*48e11a6eSGordon Ross 
87*48e11a6eSGordon Ross /*
88*48e11a6eSGordon Ross  * Initialize keys for encryption
89*48e11a6eSGordon Ross  * Called after session setup.
90*48e11a6eSGordon Ross  */
91*48e11a6eSGordon Ross void
nsmb_crypt_init_keys(struct smb_vc * vcp)92*48e11a6eSGordon Ross nsmb_crypt_init_keys(struct smb_vc *vcp)
93*48e11a6eSGordon Ross {
94*48e11a6eSGordon Ross 
95*48e11a6eSGordon Ross 	/*
96*48e11a6eSGordon Ross 	 * If we don't have a session key, we'll fail later when a
97*48e11a6eSGordon Ross 	 * request that requires (en/de)cryption can't be (en/de)crypted.
98*48e11a6eSGordon Ross 	 * Also don't bother initializing if we don't have a mechanism.
99*48e11a6eSGordon Ross 	 */
100*48e11a6eSGordon Ross 	if (vcp->vc3_crypt_mech == NULL ||
101*48e11a6eSGordon Ross 	    vcp->vc_ssnkeylen <= 0)
102*48e11a6eSGordon Ross 		return;
103*48e11a6eSGordon Ross 
104*48e11a6eSGordon Ross 	/*
105*48e11a6eSGordon Ross 	 * For SMB3, the encrypt/decrypt keys are derived from
106*48e11a6eSGordon Ross 	 * the session key using KDF in counter mode.
107*48e11a6eSGordon Ross 	 */
108*48e11a6eSGordon Ross 	if (nsmb_kdf(vcp->vc3_encrypt_key, SMB3_KEYLEN,
109*48e11a6eSGordon Ross 	    vcp->vc_ssnkey, vcp->vc_ssnkeylen,
110*48e11a6eSGordon Ross 	    (uint8_t *)"SMB2AESCCM", 11,
111*48e11a6eSGordon Ross 	    (uint8_t *)"ServerIn ", 10) != 0)
112*48e11a6eSGordon Ross 		return;
113*48e11a6eSGordon Ross 
114*48e11a6eSGordon Ross 	if (nsmb_kdf(vcp->vc3_decrypt_key, SMB3_KEYLEN,
115*48e11a6eSGordon Ross 	    vcp->vc_ssnkey, vcp->vc_ssnkeylen,
116*48e11a6eSGordon Ross 	    (uint8_t *)"SMB2AESCCM", 11,
117*48e11a6eSGordon Ross 	    (uint8_t *)"ServerOut", 10) != 0)
118*48e11a6eSGordon Ross 		return;
119*48e11a6eSGordon Ross 
120*48e11a6eSGordon Ross 	vcp->vc3_encrypt_key_len = SMB3_KEYLEN;
121*48e11a6eSGordon Ross 	vcp->vc3_decrypt_key_len = SMB3_KEYLEN;
122*48e11a6eSGordon Ross 
123*48e11a6eSGordon Ross 	(void) random_get_pseudo_bytes(
124*48e11a6eSGordon Ross 	    (uint8_t *)&vcp->vc3_nonce_low,
125*48e11a6eSGordon Ross 	    sizeof (vcp->vc3_nonce_low));
126*48e11a6eSGordon Ross 	(void) random_get_pseudo_bytes(
127*48e11a6eSGordon Ross 	    (uint8_t *)&vcp->vc3_nonce_high,
128*48e11a6eSGordon Ross 	    sizeof (vcp->vc3_nonce_high));
129*48e11a6eSGordon Ross }
130*48e11a6eSGordon Ross 
131*48e11a6eSGordon Ross /*
132*48e11a6eSGordon Ross  * Encrypt the message in *mpp, in place, prepending the
133*48e11a6eSGordon Ross  * SMB3 transform header.
134*48e11a6eSGordon Ross  *
135*48e11a6eSGordon Ross  * Any non-zero return is an error (values not used).
136*48e11a6eSGordon Ross  */
137*48e11a6eSGordon Ross int
smb3_msg_encrypt(struct smb_vc * vcp,mblk_t ** mpp)138*48e11a6eSGordon Ross smb3_msg_encrypt(struct smb_vc *vcp, mblk_t **mpp)
139*48e11a6eSGordon Ross {
140*48e11a6eSGordon Ross 	smb_enc_ctx_t ctx;
141*48e11a6eSGordon Ross 	mblk_t *body, *thdr, *lastm;
142*48e11a6eSGordon Ross 	struct mbchain	mbp_store;
143*48e11a6eSGordon Ross 	struct mbchain *mbp = &mbp_store;
144*48e11a6eSGordon Ross 	uint32_t bodylen;
145*48e11a6eSGordon Ross 	uint8_t *authdata;
146*48e11a6eSGordon Ross 	size_t authlen;
147*48e11a6eSGordon Ross 	int rc;
148*48e11a6eSGordon Ross 
149*48e11a6eSGordon Ross 	ASSERT(RW_WRITE_HELD(&vcp->iod_rqlock));
150*48e11a6eSGordon Ross 
151*48e11a6eSGordon Ross 	if (vcp->vc3_crypt_mech == NULL ||
152*48e11a6eSGordon Ross 	    vcp->vc3_encrypt_key_len != SMB3_KEYLEN) {
153*48e11a6eSGordon Ross 		return (ENOTSUP);
154*48e11a6eSGordon Ross 	}
155*48e11a6eSGordon Ross 
156*48e11a6eSGordon Ross 	bzero(&ctx, sizeof (ctx));
157*48e11a6eSGordon Ross 	ctx.mech = *((smb_crypto_mech_t *)vcp->vc3_crypt_mech);
158*48e11a6eSGordon Ross 
159*48e11a6eSGordon Ross 	body = *mpp;
160*48e11a6eSGordon Ross 	bodylen = msgdsize(body);
161*48e11a6eSGordon Ross 
162*48e11a6eSGordon Ross 	/*
163*48e11a6eSGordon Ross 	 * Get a new "nonce".  Access to these counters is
164*48e11a6eSGordon Ross 	 * serialized by iod_rqlock (assert above).
165*48e11a6eSGordon Ross 	 */
166*48e11a6eSGordon Ross 	vcp->vc3_nonce_low++;
167*48e11a6eSGordon Ross 	if (vcp->vc3_nonce_low == 0) {
168*48e11a6eSGordon Ross 		vcp->vc3_nonce_low++;
169*48e11a6eSGordon Ross 		vcp->vc3_nonce_high++;
170*48e11a6eSGordon Ross 	}
171*48e11a6eSGordon Ross 
172*48e11a6eSGordon Ross 	/*
173*48e11a6eSGordon Ross 	 * Build the transform header, keeping pointers to the various
174*48e11a6eSGordon Ross 	 * parts of it that we'll need to refer to later.
175*48e11a6eSGordon Ross 	 */
176*48e11a6eSGordon Ross 	(void) mb_init(mbp);
177*48e11a6eSGordon Ross 	thdr = mbp->mb_top;
178*48e11a6eSGordon Ross 	ASSERT(MBLKTAIL(thdr) >= SMB3_TFORM_HDR_SIZE);
179*48e11a6eSGordon Ross 	mb_put_mem(mbp, SMB3_CRYPT_SIG, 4, MB_MSYSTEM);
180*48e11a6eSGordon Ross 	mb_put_mem(mbp, NULL, SMB2_SIG_SIZE, MB_MZERO);	// signature (later)
181*48e11a6eSGordon Ross 	mb_put_uint64le(mbp, vcp->vc3_nonce_low);
182*48e11a6eSGordon Ross 	mb_put_uint64le(mbp, vcp->vc3_nonce_high);
183*48e11a6eSGordon Ross 	/* Zero last 5 bytes of nonce per. spec. */
184*48e11a6eSGordon Ross 	bzero(thdr->b_wptr - 5, 5);
185*48e11a6eSGordon Ross 	mb_put_uint32le(mbp, bodylen);
186*48e11a6eSGordon Ross 	mb_put_uint16le(mbp, 0);	// reserved
187*48e11a6eSGordon Ross 	mb_put_uint16le(mbp, 1);	// flags
188*48e11a6eSGordon Ross 	mb_put_uint64le(mbp, vcp->vc2_session_id);
189*48e11a6eSGordon Ross 	mbp->mb_top = NULL; // keeping thdr
190*48e11a6eSGordon Ross 	mb_done(mbp);
191*48e11a6eSGordon Ross 
192*48e11a6eSGordon Ross 	/*
193*48e11a6eSGordon Ross 	 * Need pointers to the part of the transfor header
194*48e11a6eSGordon Ross 	 * after the signature (starting with the nonce).
195*48e11a6eSGordon Ross 	 */
196*48e11a6eSGordon Ross 	authdata = thdr->b_rptr + SMB3_NONCE_OFFS;
197*48e11a6eSGordon Ross 	authlen = SMB3_TFORM_HDR_SIZE - SMB3_NONCE_OFFS;
198*48e11a6eSGordon Ross 
199*48e11a6eSGordon Ross 	nsmb_crypto_init_ccm_param(&ctx,
200*48e11a6eSGordon Ross 	    authdata, SMB2_SIG_SIZE,
201*48e11a6eSGordon Ross 	    authdata, authlen, bodylen);
202*48e11a6eSGordon Ross 
203*48e11a6eSGordon Ross 	rc = nsmb_encrypt_init(&ctx,
204*48e11a6eSGordon Ross 	    vcp->vc3_encrypt_key, vcp->vc3_encrypt_key_len);
205*48e11a6eSGordon Ross 	if (rc != 0)
206*48e11a6eSGordon Ross 		goto errout;
207*48e11a6eSGordon Ross 
208*48e11a6eSGordon Ross 	/*
209*48e11a6eSGordon Ross 	 * Temporarily append the transform header onto the
210*48e11a6eSGordon Ross 	 * body mblk chain with its r/w pointers set to cover
211*48e11a6eSGordon Ross 	 * just the signature, needed for how encrypt works.
212*48e11a6eSGordon Ross 	 * Could just use linkb() but we need to unlink the
213*48e11a6eSGordon Ross 	 * block as well so just find the tail ourselves.
214*48e11a6eSGordon Ross 	 */
215*48e11a6eSGordon Ross 	ASSERT(MBLKL(thdr) == SMB3_TFORM_HDR_SIZE);
216*48e11a6eSGordon Ross 	thdr->b_rptr += SMB3_SIG_OFFS;
217*48e11a6eSGordon Ross 	thdr->b_wptr = thdr->b_rptr + SMB2_SIG_SIZE;
218*48e11a6eSGordon Ross 	lastm = body;
219*48e11a6eSGordon Ross 	while (lastm->b_cont != NULL)
220*48e11a6eSGordon Ross 		lastm = lastm->b_cont;
221*48e11a6eSGordon Ross 	lastm->b_cont = thdr;
222*48e11a6eSGordon Ross 
223*48e11a6eSGordon Ross 	/*
224*48e11a6eSGordon Ross 	 * The mblk chain is ready. Encrypt!
225*48e11a6eSGordon Ross 	 */
226*48e11a6eSGordon Ross 	rc = nsmb_encrypt_mblks(&ctx, body, bodylen);
227*48e11a6eSGordon Ross 	/* check rc below */
228*48e11a6eSGordon Ross 
229*48e11a6eSGordon Ross 	/* Unlink thdr and restore r/w pointers. */
230*48e11a6eSGordon Ross 	lastm->b_cont = NULL;
231*48e11a6eSGordon Ross 	thdr->b_rptr -= SMB3_SIG_OFFS;
232*48e11a6eSGordon Ross 	thdr->b_wptr = thdr->b_rptr + SMB3_TFORM_HDR_SIZE;
233*48e11a6eSGordon Ross 
234*48e11a6eSGordon Ross 	/* Now check rc from encrypt */
235*48e11a6eSGordon Ross 	if (rc != 0)
236*48e11a6eSGordon Ross 		goto errout;
237*48e11a6eSGordon Ross 
238*48e11a6eSGordon Ross 	/*
239*48e11a6eSGordon Ross 	 * Lastly, prepend the transform header.
240*48e11a6eSGordon Ross 	 */
241*48e11a6eSGordon Ross 	thdr->b_cont = body;
242*48e11a6eSGordon Ross 	*mpp = thdr;
243*48e11a6eSGordon Ross 	nsmb_enc_ctx_done(&ctx);
244*48e11a6eSGordon Ross 	return (0);
245*48e11a6eSGordon Ross 
246*48e11a6eSGordon Ross errout:
247*48e11a6eSGordon Ross 	freeb(thdr);
248*48e11a6eSGordon Ross 	nsmb_enc_ctx_done(&ctx);
249*48e11a6eSGordon Ross 	return (rc);
250*48e11a6eSGordon Ross }
251*48e11a6eSGordon Ross 
252*48e11a6eSGordon Ross /*
253*48e11a6eSGordon Ross  * Decrypt the message in *mpp, in place, removing the
254*48e11a6eSGordon Ross  * SMB3 transform header.
255*48e11a6eSGordon Ross  *
256*48e11a6eSGordon Ross  * Any non-zero return is an error (values not used).
257*48e11a6eSGordon Ross  */
258*48e11a6eSGordon Ross int
smb3_msg_decrypt(struct smb_vc * vcp,mblk_t ** mpp)259*48e11a6eSGordon Ross smb3_msg_decrypt(struct smb_vc *vcp, mblk_t **mpp)
260*48e11a6eSGordon Ross {
261*48e11a6eSGordon Ross 	smb_enc_ctx_t ctx;
262*48e11a6eSGordon Ross 	uint8_t th_sig[4];
263*48e11a6eSGordon Ross 	mblk_t *body, *thdr, *lastm;
264*48e11a6eSGordon Ross 	struct mdchain	mdp_store;
265*48e11a6eSGordon Ross 	struct mdchain *mdp = &mdp_store;
266*48e11a6eSGordon Ross 	uint64_t th_ssnid;
267*48e11a6eSGordon Ross 	uint32_t bodylen, tlen;
268*48e11a6eSGordon Ross 	uint16_t th_flags;
269*48e11a6eSGordon Ross 	uint8_t *authdata;
270*48e11a6eSGordon Ross 	size_t authlen;
271*48e11a6eSGordon Ross 	int rc;
272*48e11a6eSGordon Ross 
273*48e11a6eSGordon Ross 	if (vcp->vc3_crypt_mech == NULL ||
274*48e11a6eSGordon Ross 	    vcp->vc3_encrypt_key_len != SMB3_KEYLEN) {
275*48e11a6eSGordon Ross 		return (ENOTSUP);
276*48e11a6eSGordon Ross 	}
277*48e11a6eSGordon Ross 
278*48e11a6eSGordon Ross 	bzero(&ctx, sizeof (ctx));
279*48e11a6eSGordon Ross 	ctx.mech = *((smb_crypto_mech_t *)vcp->vc3_crypt_mech);
280*48e11a6eSGordon Ross 
281*48e11a6eSGordon Ross 	/*
282*48e11a6eSGordon Ross 	 * Split off the transform header
283*48e11a6eSGordon Ross 	 * We need it contiguous.
284*48e11a6eSGordon Ross 	 */
285*48e11a6eSGordon Ross 	thdr = *mpp;
286*48e11a6eSGordon Ross 	body = m_split(thdr, SMB3_TFORM_HDR_SIZE, 1);
287*48e11a6eSGordon Ross 	if (body == NULL)
288*48e11a6eSGordon Ross 		return (ENOSR);
289*48e11a6eSGordon Ross 	thdr = m_pullup(thdr, SMB3_TFORM_HDR_SIZE);
290*48e11a6eSGordon Ross 	if (thdr == NULL)
291*48e11a6eSGordon Ross 		return (ENOSR);
292*48e11a6eSGordon Ross 
293*48e11a6eSGordon Ross 	/*
294*48e11a6eSGordon Ross 	 * Decode the transform header
295*48e11a6eSGordon Ross 	 */
296*48e11a6eSGordon Ross 	(void) md_initm(mdp, thdr);
297*48e11a6eSGordon Ross 	md_get_mem(mdp, th_sig, 4, MB_MSYSTEM);
298*48e11a6eSGordon Ross 	md_get_mem(mdp, NULL, SMB2_SIG_SIZE, MB_MZERO); // signature
299*48e11a6eSGordon Ross 	md_get_mem(mdp, NULL, SMB2_SIG_SIZE, MB_MZERO); // nonce
300*48e11a6eSGordon Ross 	md_get_uint32le(mdp, &bodylen);
301*48e11a6eSGordon Ross 	md_get_uint16le(mdp, NULL);	// reserved
302*48e11a6eSGordon Ross 	md_get_uint16le(mdp, &th_flags);
303*48e11a6eSGordon Ross 	md_get_uint64le(mdp, &th_ssnid);
304*48e11a6eSGordon Ross 	mdp->md_top = NULL; // keeping thdr
305*48e11a6eSGordon Ross 	md_done(mdp);
306*48e11a6eSGordon Ross 
307*48e11a6eSGordon Ross 	/*
308*48e11a6eSGordon Ross 	 * Validate transform header fields
309*48e11a6eSGordon Ross 	 */
310*48e11a6eSGordon Ross 	if (bcmp(th_sig, SMB3_CRYPT_SIG, 4) != 0) {
311*48e11a6eSGordon Ross 		rc = EPROTO;
312*48e11a6eSGordon Ross 		goto errout;
313*48e11a6eSGordon Ross 	}
314*48e11a6eSGordon Ross 	if (th_flags != 1 || th_ssnid != vcp->vc2_session_id) {
315*48e11a6eSGordon Ross 		rc = EINVAL;
316*48e11a6eSGordon Ross 		goto errout;
317*48e11a6eSGordon Ross 	}
318*48e11a6eSGordon Ross 
319*48e11a6eSGordon Ross 	/*
320*48e11a6eSGordon Ross 	 * Check actual body length (trim if necessary)
321*48e11a6eSGordon Ross 	 */
322*48e11a6eSGordon Ross 	tlen = msgdsize(body);
323*48e11a6eSGordon Ross 	if (tlen < bodylen) {
324*48e11a6eSGordon Ross 		rc = EINVAL;
325*48e11a6eSGordon Ross 		goto errout;
326*48e11a6eSGordon Ross 	}
327*48e11a6eSGordon Ross 	if (tlen > bodylen) {
328*48e11a6eSGordon Ross 		/* trim from tail */
329*48e11a6eSGordon Ross 		ssize_t adj;
330*48e11a6eSGordon Ross 
331*48e11a6eSGordon Ross 		adj = bodylen - tlen;
332*48e11a6eSGordon Ross 		ASSERT(adj < 0);
333*48e11a6eSGordon Ross 		(void) adjmsg(body, adj);
334*48e11a6eSGordon Ross 	}
335*48e11a6eSGordon Ross 
336*48e11a6eSGordon Ross 	/*
337*48e11a6eSGordon Ross 	 * Need pointers to the part of the transfor header
338*48e11a6eSGordon Ross 	 * after the signature (starting with the nonce).
339*48e11a6eSGordon Ross 	 * tlen is now length of ciphertext
340*48e11a6eSGordon Ross 	 */
341*48e11a6eSGordon Ross 	authdata = thdr->b_rptr + SMB3_NONCE_OFFS;
342*48e11a6eSGordon Ross 	authlen = SMB3_TFORM_HDR_SIZE - SMB3_NONCE_OFFS;
343*48e11a6eSGordon Ross 	tlen = bodylen + SMB2_SIG_SIZE;
344*48e11a6eSGordon Ross 
345*48e11a6eSGordon Ross 	nsmb_crypto_init_ccm_param(&ctx,
346*48e11a6eSGordon Ross 	    authdata, SMB2_SIG_SIZE,
347*48e11a6eSGordon Ross 	    authdata, authlen, tlen);
348*48e11a6eSGordon Ross 
349*48e11a6eSGordon Ross 	rc = nsmb_decrypt_init(&ctx,
350*48e11a6eSGordon Ross 	    vcp->vc3_decrypt_key, vcp->vc3_decrypt_key_len);
351*48e11a6eSGordon Ross 	if (rc != 0)
352*48e11a6eSGordon Ross 		goto errout;
353*48e11a6eSGordon Ross 
354*48e11a6eSGordon Ross 	/*
355*48e11a6eSGordon Ross 	 * Temporarily append the transform header onto the
356*48e11a6eSGordon Ross 	 * body mblk chain with its r/w pointers set to cover
357*48e11a6eSGordon Ross 	 * just the signature, needed for how decrypt works.
358*48e11a6eSGordon Ross 	 * Could just use linkb() but we need to unlink the
359*48e11a6eSGordon Ross 	 * block as well so just find the tail ourselves.
360*48e11a6eSGordon Ross 	 */
361*48e11a6eSGordon Ross 	thdr->b_rptr += SMB3_SIG_OFFS;
362*48e11a6eSGordon Ross 	thdr->b_wptr = thdr->b_rptr + SMB2_SIG_SIZE;
363*48e11a6eSGordon Ross 	lastm = body;
364*48e11a6eSGordon Ross 	while (lastm->b_cont != NULL)
365*48e11a6eSGordon Ross 		lastm = lastm->b_cont;
366*48e11a6eSGordon Ross 	lastm->b_cont = thdr;
367*48e11a6eSGordon Ross 
368*48e11a6eSGordon Ross 	/*
369*48e11a6eSGordon Ross 	 * The mblk chain is ready. Decrypt!
370*48e11a6eSGordon Ross 	 */
371*48e11a6eSGordon Ross 	rc = nsmb_decrypt_mblks(&ctx, body, tlen);
372*48e11a6eSGordon Ross 	/* check rc below */
373*48e11a6eSGordon Ross 
374*48e11a6eSGordon Ross 	/* Unlink thdr and restore r/w pointers. */
375*48e11a6eSGordon Ross 	lastm->b_cont = NULL;
376*48e11a6eSGordon Ross 	thdr->b_rptr -= SMB3_SIG_OFFS;
377*48e11a6eSGordon Ross 	thdr->b_wptr = thdr->b_rptr + SMB3_TFORM_HDR_SIZE;
378*48e11a6eSGordon Ross 
379*48e11a6eSGordon Ross 	/* Now check rc from decrypt */
380*48e11a6eSGordon Ross 	if (rc != 0)
381*48e11a6eSGordon Ross 		goto errout;
382*48e11a6eSGordon Ross 
383*48e11a6eSGordon Ross 	/*
384*48e11a6eSGordon Ross 	 * Lastly, discard the transform header
385*48e11a6eSGordon Ross 	 * and return the body.
386*48e11a6eSGordon Ross 	 */
387*48e11a6eSGordon Ross 	freeb(thdr);
388*48e11a6eSGordon Ross 	*mpp = body;
389*48e11a6eSGordon Ross 	nsmb_enc_ctx_done(&ctx);
390*48e11a6eSGordon Ross 	return (0);
391*48e11a6eSGordon Ross 
392*48e11a6eSGordon Ross errout:
393*48e11a6eSGordon Ross 	freeb(thdr);
394*48e11a6eSGordon Ross 	nsmb_enc_ctx_done(&ctx);
395*48e11a6eSGordon Ross 	return (rc);
396*48e11a6eSGordon Ross }
397