xref: /illumos-gate/usr/src/uts/common/fs/smbsrv/smb3_encrypt.c (revision 4f0ce1da2aeae875aeb13640b681d0ad37a3036b)
1 /*
2  * This file and its contents are supplied under the terms of the
3  * Common Development and Distribution License ("CDDL"), version 1.0.
4  * You may only use this file in accordance with the terms of version
5  * 1.0 of the CDDL.
6  *
7  * A full copy of the text of the CDDL should have accompanied this
8  * source.  A copy of the CDDL is also available via the Internet at
9  * http://www.illumos.org/license/CDDL.
10  */
11 
12 /*
13  * Copyright 2017-2021 Tintri by DDN, Inc.  All rights reserved.
14  * Copyright 2022 RackTop Systems, Inc.
15  */
16 
17 /*
18  * Routines for smb3 encryption.
19  */
20 
21 #include <smbsrv/smb2_kproto.h>
22 #include <smbsrv/smb_kcrypt.h>
23 #include <sys/random.h>
24 #include <sys/cmn_err.h>
25 
26 #define	SMB3_NONCE_OFFS		20
27 #define	SMB3_SIG_OFFS		4
28 
29 /*
30  * Arbitrary value used to prevent nonce reuse via overflow. Currently
31  * 2^64 - 2^32 - 1. Assumes we can't have (or are unlikely to have)
32  * 2^32 concurrent messages when we hit this number.
33  */
34 static uint64_t smb3_max_nonce = 0xffffffff00000000ULL;
35 
36 /*
37  * Nonce generation based on draft-mcgrew-iv-gen-01
38  * "Generation of Deterministic Initialization Vectors (IVs) and Nonces"
39  *
40  * Generate an 8-byte random salt and a 3-byte random 'fixed' value.
41  * then, nonce = (++counter ^ salt) || fixed
42  *
43  * This protects against nonce-reuse (8-byte counter), as well as known
44  * attacks on reusing nonces with different keys
45  */
46 
47 void
smb3_encrypt_init_nonce(smb_user_t * user)48 smb3_encrypt_init_nonce(smb_user_t *user)
49 {
50 	user->u_nonce_cnt = 0;
51 	(void) random_get_pseudo_bytes(user->u_nonce_fixed,
52 	    sizeof (user->u_nonce_fixed));
53 	(void) random_get_pseudo_bytes((uint8_t *)&user->u_salt,
54 	    sizeof (user->u_salt));
55 }
56 
57 static int
smb3_encrypt_gen_nonce(smb_user_t * user,uint8_t * buf,size_t len)58 smb3_encrypt_gen_nonce(smb_user_t *user, uint8_t *buf, size_t len)
59 {
60 	uint64_t cnt;
61 
62 	/*
63 	 * Nonces must be unique per-key for the life of the key.
64 	 * Bail before we roll over to avoid breaking the crypto.
65 	 */
66 	cnt = atomic_inc_64_nv(&user->u_nonce_cnt);
67 	if (cnt > smb3_max_nonce)
68 		return (-1);
69 
70 	cnt ^= user->u_salt;
71 
72 	bcopy((uint8_t *)&cnt, buf, sizeof (cnt));
73 
74 	ASSERT(len <= 16);	// th_nonce
75 	ASSERT(len > sizeof (cnt));
76 	bcopy(user->u_nonce_fixed, buf + sizeof (cnt), len - sizeof (cnt));
77 	return (0);
78 }
79 
80 int
smb3_encrypt_init_mech(smb_session_t * s)81 smb3_encrypt_init_mech(smb_session_t *s)
82 {
83 	smb_crypto_mech_t *mech;
84 	int rc;
85 
86 	if (s->enc_mech != NULL)
87 		return (0);
88 
89 	mech = kmem_zalloc(sizeof (*mech), KM_SLEEP);
90 
91 	switch (s->smb31_enc_cipherid) {
92 	case SMB3_CIPHER_AES256_GCM:
93 	case SMB3_CIPHER_AES128_GCM:
94 		rc = smb3_aes_gcm_getmech(mech);
95 		break;
96 	case SMB3_CIPHER_AES256_CCM:
97 	case SMB3_CIPHER_AES128_CCM:
98 		rc = smb3_aes_ccm_getmech(mech);
99 		break;
100 	default:
101 		rc = -1;
102 		break;
103 	}
104 
105 	if (rc != 0) {
106 		kmem_free(mech, sizeof (*mech));
107 		return (rc);
108 	}
109 	s->enc_mech = mech;
110 
111 	return (0);
112 }
113 
114 /*
115  * Initializes keys/state required for SMB3 Encryption.
116  * Note: If a failure occurs here, don't fail the request.
117  * Instead, return an error when we attempt to encrypt/decrypt.
118  */
119 void
smb3_encrypt_begin(smb_user_t * u,smb_token_t * token)120 smb3_encrypt_begin(smb_user_t *u, smb_token_t *token)
121 {
122 	smb_session_t *s = u->u_session;
123 	struct smb_key *enc_key = &u->u_enc_key;
124 	struct smb_key *dec_key = &u->u_dec_key;
125 	uint32_t derived_keylen, input_keylen;
126 
127 	/*
128 	 * In order to enforce encryption, all users need to
129 	 * have Session.EncryptData properly set, even anon/guest.
130 	 */
131 	u->u_encrypt = s->s_server->sv_cfg.skc_encrypt;
132 	enc_key->len = 0;
133 	dec_key->len = 0;
134 
135 	/*
136 	 * If we don't have a session key, we'll fail later when a
137 	 * request that requires (en/de)cryption can't be (en/de)crypted.
138 	 * Also don't bother initializing if we don't have a mechanism.
139 	 */
140 	if (token->tkn_ssnkey.val == NULL || token->tkn_ssnkey.len == 0 ||
141 	    s->enc_mech == NULL)
142 		return;
143 
144 	/*
145 	 * Compute and store the encryption keys, which live in
146 	 * the user structure.
147 	 */
148 
149 	/*
150 	 * For SMB3, the encrypt/decrypt keys are derived from
151 	 * the session key using KDF in counter mode.
152 	 *
153 	 * AES256 Keys are derived from the 'FullSessionKey', which is the
154 	 * entirety of what we got in the token; AES128 Keys are derived from
155 	 * the 'SessionKey', which is the first 16 bytes of the key we got in
156 	 * the token.
157 	 */
158 	if (s->dialect >= SMB_VERS_3_11) {
159 		if (s->smb31_enc_cipherid == SMB3_CIPHER_AES256_GCM ||
160 		    s->smb31_enc_cipherid == SMB3_CIPHER_AES256_CCM) {
161 			derived_keylen = AES256_KEY_LENGTH;
162 			input_keylen = token->tkn_ssnkey.len;
163 		} else {
164 			derived_keylen = AES128_KEY_LENGTH;
165 			input_keylen = MIN(SMB2_SSN_KEYLEN,
166 			    token->tkn_ssnkey.len);
167 		}
168 
169 		if (smb3_kdf(enc_key->key, derived_keylen,
170 		    token->tkn_ssnkey.val, input_keylen,
171 		    (uint8_t *)"SMBS2CCipherKey", 16,
172 		    u->u_preauth_hashval, SHA512_DIGEST_LENGTH) != 0)
173 			return;
174 
175 		if (smb3_kdf(dec_key->key, derived_keylen,
176 		    token->tkn_ssnkey.val, input_keylen,
177 		    (uint8_t *)"SMBC2SCipherKey", 16,
178 		    u->u_preauth_hashval, SHA512_DIGEST_LENGTH) != 0)
179 			return;
180 
181 		enc_key->len = derived_keylen;
182 		dec_key->len = derived_keylen;
183 	} else {
184 		derived_keylen = AES128_KEY_LENGTH;
185 		input_keylen = MIN(SMB2_SSN_KEYLEN, token->tkn_ssnkey.len);
186 
187 		if (smb3_kdf(enc_key->key, derived_keylen,
188 		    token->tkn_ssnkey.val, input_keylen,
189 		    (uint8_t *)"SMB2AESCCM", 11,
190 		    (uint8_t *)"ServerOut", 10) != 0)
191 			return;
192 
193 		if (smb3_kdf(dec_key->key, derived_keylen,
194 		    token->tkn_ssnkey.val, input_keylen,
195 		    (uint8_t *)"SMB2AESCCM", 11,
196 		    (uint8_t *)"ServerIn ", 10) != 0)
197 			return;
198 
199 		enc_key->len = derived_keylen;
200 		dec_key->len = derived_keylen;
201 	}
202 
203 	smb3_encrypt_init_nonce(u);
204 
205 	/*
206 	 * XXX todo: setup crypto context for enc_key, dec_key.
207 	 * See crypto_create_ctx_template(mech, key, tmpl,...)
208 	 *
209 	 * Will need a new indirect functions eg.
210 	 *	smb3_encrypt_init_templ(s->enc_mech, enc_key);
211 	 *	smb3_encrypt_init_templ(s->enc_mech, dec_key);
212 	 * where struct smb_key gains a new member:
213 	 *	void *template;
214 	 *
215 	 * Already have s->enc_mech from smb3_encrypt_init_mech().
216 	 */
217 }
218 
219 static int
smb3_decode_tform_header(smb_request_t * sr,struct mbuf_chain * mbc)220 smb3_decode_tform_header(smb_request_t *sr, struct mbuf_chain *mbc)
221 {
222 	uint32_t protocolid;
223 	uint16_t flags;
224 	int rc;
225 
226 	rc = smb_mbc_decodef(
227 	    mbc, "l16c16cl..wq",
228 	    &protocolid,	/*  l  */
229 	    sr->smb2_sig,	/* 16c */
230 	    sr->th_nonce,	/* 16c */
231 	    &sr->th_msglen,	/* l */
232 	    /* reserved	  .. */
233 	    &flags,		/* w */
234 	    &sr->th_ssnid);	/* q */
235 	if (rc)
236 		return (rc);
237 
238 	/* This was checked in smb2sr_newrq() */
239 	ASSERT3U(protocolid, ==, SMB3_ENCRYPTED_MAGIC);
240 
241 	if (flags != 1) {
242 #ifdef DEBUG
243 		cmn_err(CE_NOTE, "flags field not 1: %x", flags);
244 #endif
245 		return (-1);
246 	}
247 
248 	return (rc);
249 }
250 
251 static int
smb3_encode_tform_header(smb_request_t * sr,struct mbuf_chain * mbc)252 smb3_encode_tform_header(smb_request_t *sr, struct mbuf_chain *mbc)
253 {
254 	int rc;
255 
256 	rc = smb_mbc_encodef(
257 	    mbc, "l16.16clwwq",
258 	    SMB3_ENCRYPTED_MAGIC, /* l */
259 	    /* signature(16)	   16. (filled in later) */
260 	    sr->th_nonce,	/* 16c */
261 	    sr->th_msglen,	/* l */
262 	    0, /* reserved	   w */
263 	    1, /* flags		   w */
264 	    sr->th_ssnid); /* q */
265 
266 	return (rc);
267 }
268 
269 /*
270  * Get an smb_vdb_t and initialize it.
271  * Free'd via smb_request_free
272  */
273 static smb_vdb_t *
smb3_get_vdb(smb_request_t * sr)274 smb3_get_vdb(smb_request_t *sr)
275 {
276 	smb_vdb_t *vdb;
277 
278 	vdb = smb_srm_zalloc(sr, sizeof (*vdb));
279 	vdb->vdb_uio.uio_iov = &vdb->vdb_iovec[0];
280 	vdb->vdb_uio.uio_iovcnt = MAX_IOVEC;
281 	vdb->vdb_uio.uio_segflg = UIO_SYSSPACE;
282 	vdb->vdb_uio.uio_extflg = UIO_COPY_DEFAULT;
283 
284 	return (vdb);
285 }
286 
287 /*
288  * Decrypt the request in mbc_in into out_mbc which as been
289  * setup by the caller.  The caller will replace sr->command
290  * with out_mbc if this succeeds, or will free which ever one
291  * ends up not being used as sr->command.
292  *
293  * The encrypted request in in_mbc is left unmodified here,
294  * and free'd by the caller when appropriate.
295  *
296  * Error return values here are just for visibility in dtrace.
297  * Anything non-zero results in a connection drop.
298  */
299 int
smb3_decrypt_sr(smb_request_t * sr,struct mbuf_chain * in_mbc,struct mbuf_chain * out_mbc)300 smb3_decrypt_sr(smb_request_t *sr,
301     struct mbuf_chain *in_mbc,	// transform header + ciphertext
302     struct mbuf_chain *out_mbc)	// cleartext
303 {
304 	smb_enc_ctx_t ctx;
305 	uint8_t th_raw[SMB3_TFORM_HDR_SIZE];
306 	uint8_t *authdata;
307 	size_t authlen;
308 	size_t cipherlen;
309 	smb_vdb_t *in_vdb = NULL;
310 	smb_vdb_t *out_vdb = NULL;
311 	smb_session_t *s = sr->session;
312 	smb_user_t *u;
313 	struct smb_key *dec_key;
314 	int cnt, rc;
315 	boolean_t gcm;
316 	size_t nonce_size;
317 	uint_t keylen;
318 
319 	if (s->enc_mech == NULL)
320 		return (SET_ERROR(-1));
321 
322 	switch (s->smb31_enc_cipherid) {
323 	default:
324 		ASSERT(0);
325 		/* fallthrough */
326 	case SMB3_CIPHER_AES128_CCM:	// 1
327 		gcm = B_FALSE;
328 		nonce_size = SMB3_AES_CCM_NONCE_SIZE;
329 		keylen = AES128_KEY_LENGTH;
330 		break;
331 	case SMB3_CIPHER_AES128_GCM:	// 2
332 		gcm = B_TRUE;
333 		nonce_size = SMB3_AES_GCM_NONCE_SIZE;
334 		keylen = AES128_KEY_LENGTH;
335 		break;
336 	case SMB3_CIPHER_AES256_CCM:	// 3
337 		gcm = B_FALSE;
338 		nonce_size = SMB3_AES_CCM_NONCE_SIZE;
339 		keylen = AES256_KEY_LENGTH;
340 		break;
341 	case SMB3_CIPHER_AES256_GCM:	// 4
342 		gcm = B_TRUE;
343 		nonce_size = SMB3_AES_GCM_NONCE_SIZE;
344 		keylen = AES256_KEY_LENGTH;
345 		break;
346 	}
347 
348 	/*
349 	 * Get the transform header, in both raw form and decoded,
350 	 * then remove the transform header from the message.
351 	 * Note: the signature lands in sr->smb2_sig
352 	 */
353 	if (smb_mbc_peek(in_mbc, 0, "#c",
354 	    SMB3_TFORM_HDR_SIZE, th_raw) != 0) {
355 		return (SET_ERROR(-2));
356 	}
357 	rc = smb3_decode_tform_header(sr, in_mbc);
358 	if (rc != 0) {
359 		return (SET_ERROR(-3));
360 	}
361 	m_adjust(in_mbc->chain, SMB3_TFORM_HDR_SIZE);
362 	ASSERT(in_mbc->max_bytes > SMB3_TFORM_HDR_SIZE);
363 	in_mbc->max_bytes -= SMB3_TFORM_HDR_SIZE;
364 	in_mbc->chain_offset = 0;
365 
366 	/*
367 	 * Bounds-check the stated length of the encapsulated message.
368 	 */
369 	if (sr->th_msglen < SMB2_HDR_SIZE ||
370 	    sr->th_msglen > in_mbc->max_bytes) {
371 		return (SET_ERROR(-4));
372 	}
373 	cipherlen = sr->th_msglen + SMB2_SIG_SIZE;
374 
375 	/*
376 	 * Lookup/validate the transform session ID so we'll
377 	 * have the key we'll need.  Release for this happens
378 	 * in smb_request_free().
379 	 */
380 	u = smb_session_lookup_ssnid(s, sr->th_ssnid);
381 	if (u == NULL) {
382 		return (SET_ERROR(-5));
383 	}
384 	sr->th_sid_user = u;
385 	dec_key = &u->u_dec_key;
386 	if (dec_key->len != keylen) {
387 		return (SET_ERROR(-6));
388 	}
389 
390 	/*
391 	 * Initialize crypto I/F: mech, params, key
392 	 *
393 	 * Unlike signing, which uses one global mech struct,
394 	 * encryption requires modifying the mech to add a
395 	 * per-use param struct. Thus, we need to make a copy.
396 	 */
397 	bzero(&ctx, sizeof (ctx));
398 	ctx.mech = *((smb_crypto_mech_t *)s->enc_mech);
399 
400 	/*
401 	 * The transform header, minus the PROTOCOL_ID and the
402 	 * SIGNATURE, is authenticated but not encrypted.
403 	 * (That's the "auth data" passed to init)
404 	 *
405 	 * Param init for CCM also needs the cipher length, which is
406 	 * the clear length + 16, but note that the last 16 bytes is
407 	 * the signature in the transform header.
408 	 */
409 	authdata = th_raw + SMB3_NONCE_OFFS;
410 	authlen = SMB3_TFORM_HDR_SIZE - SMB3_NONCE_OFFS;
411 
412 	if (gcm) {
413 		smb3_crypto_init_gcm_param(&ctx,
414 		    sr->th_nonce, nonce_size,
415 		    authdata, authlen);
416 	} else {
417 		smb3_crypto_init_ccm_param(&ctx,
418 		    sr->th_nonce, nonce_size,
419 		    authdata, authlen, cipherlen);
420 	}
421 
422 	rc = smb3_decrypt_init(&ctx,
423 	    dec_key->key, dec_key->len);
424 	if (rc != 0)
425 		return (SET_ERROR(-7));
426 
427 	/*
428 	 * Build a UIO vector for the ciphertext (in)
429 	 * a: remainder of the 1s segment after the transform header
430 	 * b: all subsequent segments of this message
431 	 * c: final 16 byte signature from the transform header
432 	 */
433 	in_vdb = smb3_get_vdb(sr);
434 	in_vdb->vdb_uio.uio_resid = sr->th_msglen;
435 	rc = smb_mbuf_mkuio(in_mbc->chain, &in_vdb->vdb_uio);
436 	if (rc != 0)
437 		return (SET_ERROR(-8));
438 
439 	/* Add one more uio seg. for the signature. */
440 	cnt = in_vdb->vdb_uio.uio_iovcnt;
441 	if ((cnt + 1) > MAX_IOVEC)
442 		return (SET_ERROR(-9));
443 	in_vdb->vdb_uio.uio_iov[cnt].iov_base = (void *)sr->smb2_sig;
444 	in_vdb->vdb_uio.uio_iov[cnt].iov_len = SMB2_SIG_SIZE;
445 	in_vdb->vdb_uio.uio_iovcnt = cnt + 1;
446 	in_vdb->vdb_uio.uio_resid += SMB2_SIG_SIZE;
447 
448 	/*
449 	 * Build a UIO vector for the cleartext (out)
450 	 */
451 	out_vdb = smb3_get_vdb(sr);
452 	out_vdb->vdb_uio.uio_resid = sr->th_msglen;
453 	rc = smb_mbuf_mkuio(out_mbc->chain, &out_vdb->vdb_uio);
454 	if (rc != 0)
455 		return (SET_ERROR(-10));
456 
457 	/*
458 	 * Have in/out UIO descriptors.  Decrypt!
459 	 */
460 	rc = smb3_decrypt_uio(&ctx, &in_vdb->vdb_uio, &out_vdb->vdb_uio);
461 	if (rc != 0) {
462 #ifdef	DEBUG
463 		cmn_err(CE_WARN, "smb3_decrypt_uio failed");
464 #endif
465 		return (SET_ERROR(-11));
466 	}
467 
468 	return (rc);
469 }
470 
471 /*
472  * Encrypt the response in in_mbc into out_mbc which as been
473  * setup by the caller.  The caller will send out_mbc if this
474  * returns success, and otherwise will free out_mbc.
475  *
476  * The cleartext response in in_mbc is left unmodified here,
477  * and free'd in smb_request_free.
478  *
479  * Error return values here are just for visibility in dtrace.
480  * Anything non-zero results in a connection drop.
481  */
482 int
smb3_encrypt_sr(smb_request_t * sr,struct mbuf_chain * in_mbc,struct mbuf_chain * out_mbc)483 smb3_encrypt_sr(smb_request_t *sr,
484     struct mbuf_chain *in_mbc,	// cleartext
485     struct mbuf_chain *out_mbc)	// transform header + ciphertext
486 {
487 	smb_enc_ctx_t ctx;
488 	uint8_t th_raw[SMB3_TFORM_HDR_SIZE];
489 	uint8_t *authdata;
490 	size_t authlen;
491 	smb_vdb_t *in_vdb = NULL;
492 	smb_vdb_t *out_vdb = NULL;
493 	smb_session_t *s = sr->session;
494 	smb_user_t *u = sr->th_sid_user;
495 	struct smb_key *enc_key = &u->u_enc_key;
496 	int cnt, rc;
497 	boolean_t gcm;
498 	size_t nonce_size;
499 	uint_t keylen;
500 
501 	VERIFY(u != NULL); // and have sr->th_ssnid
502 
503 	switch (s->smb31_enc_cipherid) {
504 	default:
505 		ASSERT(0);
506 		/* fallthrough */
507 	case SMB3_CIPHER_AES128_CCM:	// 1
508 		gcm = B_FALSE;
509 		nonce_size = SMB3_AES_CCM_NONCE_SIZE;
510 		keylen = AES128_KEY_LENGTH;
511 		break;
512 	case SMB3_CIPHER_AES128_GCM:	// 2
513 		gcm = B_TRUE;
514 		nonce_size = SMB3_AES_GCM_NONCE_SIZE;
515 		keylen = AES128_KEY_LENGTH;
516 		break;
517 	case SMB3_CIPHER_AES256_CCM:	// 3
518 		gcm = B_FALSE;
519 		nonce_size = SMB3_AES_CCM_NONCE_SIZE;
520 		keylen = AES256_KEY_LENGTH;
521 		break;
522 	case SMB3_CIPHER_AES256_GCM:	// 4
523 		gcm = B_TRUE;
524 		nonce_size = SMB3_AES_GCM_NONCE_SIZE;
525 		keylen = AES256_KEY_LENGTH;
526 		break;
527 	}
528 	if (s->enc_mech == NULL || enc_key->len != keylen) {
529 		return (SET_ERROR(-1));
530 	}
531 
532 	/*
533 	 * Need to fill in the transform header for everything
534 	 * after the signature, needed as the "auth" data.
535 	 * The signature is stuffed in later.  So we need:
536 	 *   the nonce, msgsize, flags, th_ssnid
537 	 */
538 	rc = smb3_encrypt_gen_nonce(u, sr->th_nonce, nonce_size);
539 	if (rc != 0) {
540 		cmn_err(CE_WARN, "ran out of nonces");
541 		return (SET_ERROR(-2));
542 	}
543 	if (smb3_encode_tform_header(sr, out_mbc) != 0) {
544 		cmn_err(CE_WARN, "couldn't encode transform header");
545 		return (SET_ERROR(-3));
546 	}
547 
548 	/* Get the raw header to use as auth data */
549 	if (smb_mbc_peek(out_mbc, 0, "#c",
550 	    SMB3_TFORM_HDR_SIZE, th_raw) != 0)
551 		return (SET_ERROR(-4));
552 
553 	/*
554 	 * Initialize crypto I/F: mech, params, key
555 	 *
556 	 * Unlike signing, which uses one global mech struct,
557 	 * encryption requires modifying the mech to add a
558 	 * per-use param struct. Thus, we need to make a copy.
559 	 */
560 	bzero(&ctx, sizeof (ctx));
561 	ctx.mech = *((smb_crypto_mech_t *)s->enc_mech);
562 
563 	/*
564 	 * The transform header, minus the PROTOCOL_ID and the
565 	 * SIGNATURE, is authenticated but not encrypted.
566 	 * (That's the "auth data" passed to init)
567 	 *
568 	 * Param init for CCM also needs the cipher length, which is
569 	 * the clear length + 16, but note that the last 16 bytes is
570 	 * the signature in the transform header.
571 	 *
572 	 * Note: sr->th_msglen already set by caller
573 	 */
574 	authdata = th_raw + SMB3_NONCE_OFFS;
575 	authlen = SMB3_TFORM_HDR_SIZE - SMB3_NONCE_OFFS;
576 
577 	if (gcm) {
578 		smb3_crypto_init_gcm_param(&ctx,
579 		    sr->th_nonce, nonce_size,
580 		    authdata, authlen);
581 	} else {
582 		smb3_crypto_init_ccm_param(&ctx,
583 		    sr->th_nonce, nonce_size,
584 		    authdata, authlen, sr->th_msglen);
585 	}
586 
587 	rc = smb3_encrypt_init(&ctx,
588 	    enc_key->key, enc_key->len);
589 	if (rc != 0)
590 		return (SET_ERROR(-5));
591 
592 	/*
593 	 * Build a UIO vector for the cleartext (in)
594 	 */
595 	in_vdb = smb3_get_vdb(sr);
596 	in_vdb->vdb_uio.uio_resid = sr->th_msglen;
597 	rc = smb_mbuf_mkuio(in_mbc->chain, &in_vdb->vdb_uio);
598 	if (rc != 0)
599 		return (SET_ERROR(-6));
600 
601 	/*
602 	 * Build a UIO vector for the ciphertext (out)
603 	 * a: remainder of the 1s segment after the transform header
604 	 * b: all subsequent segments of this message
605 	 * c: final 16 byte signature that will go in the TH
606 	 *
607 	 * Caller puts transform header in its own mblk so we can
608 	 * just skip the first mlbk when building the uio.
609 	 */
610 	out_vdb = smb3_get_vdb(sr);
611 	out_vdb->vdb_uio.uio_resid = sr->th_msglen;
612 	rc = smb_mbuf_mkuio(out_mbc->chain->m_next, &out_vdb->vdb_uio);
613 	if (rc != 0)
614 		return (SET_ERROR(-7));
615 
616 	/* Add one more uio seg. for the signature. */
617 	cnt = out_vdb->vdb_uio.uio_iovcnt;
618 	if ((cnt + 1) > MAX_IOVEC)
619 		return (SET_ERROR(-8));
620 	out_vdb->vdb_uio.uio_iov[cnt].iov_base = (void *)sr->smb2_sig;
621 	out_vdb->vdb_uio.uio_iov[cnt].iov_len = SMB2_SIG_SIZE;
622 	out_vdb->vdb_uio.uio_iovcnt = cnt + 1;
623 	out_vdb->vdb_uio.uio_resid += SMB2_SIG_SIZE;
624 
625 	/*
626 	 * Have in/out UIO descriptors. Encrypt!
627 	 */
628 	rc = smb3_encrypt_uio(&ctx, &in_vdb->vdb_uio, &out_vdb->vdb_uio);
629 	if (rc != 0) {
630 #ifdef	DEBUG
631 		cmn_err(CE_WARN, "smb3_encrypt_uio failed");
632 #endif
633 		return (SET_ERROR(-9));
634 	}
635 
636 	/*
637 	 * Now patch the final signature into the transform header
638 	 */
639 	(void) smb_mbc_poke(out_mbc, SMB3_SIG_OFFS, "#c",
640 	    SMB2_SIG_SIZE, sr->smb2_sig);
641 
642 	return (rc);
643 }
644 
645 void
smb3_encrypt_ssn_fini(smb_session_t * s)646 smb3_encrypt_ssn_fini(smb_session_t *s)
647 {
648 	smb_crypto_mech_t *mech;
649 
650 	if ((mech = s->enc_mech) != NULL) {
651 		kmem_free(mech, sizeof (*mech));
652 		s->enc_mech = NULL;
653 	}
654 }
655