1a90cf9f2SGordon Ross /*
2a90cf9f2SGordon Ross  * CDDL HEADER START
3a90cf9f2SGordon Ross  *
4a90cf9f2SGordon Ross  * The contents of this file are subject to the terms of the
5a90cf9f2SGordon Ross  * Common Development and Distribution License (the "License").
6a90cf9f2SGordon Ross  * You may not use this file except in compliance with the License.
7a90cf9f2SGordon Ross  *
8a90cf9f2SGordon Ross  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9a90cf9f2SGordon Ross  * or http://www.opensolaris.org/os/licensing.
10a90cf9f2SGordon Ross  * See the License for the specific language governing permissions
11a90cf9f2SGordon Ross  * and limitations under the License.
12a90cf9f2SGordon Ross  *
13a90cf9f2SGordon Ross  * When distributing Covered Code, include this CDDL HEADER in each
14a90cf9f2SGordon Ross  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15a90cf9f2SGordon Ross  * If applicable, add the following below this CDDL HEADER, with the
16a90cf9f2SGordon Ross  * fields enclosed by brackets "[]" replaced with your own identifying
17a90cf9f2SGordon Ross  * information: Portions Copyright [yyyy] [name of copyright owner]
18a90cf9f2SGordon Ross  *
19a90cf9f2SGordon Ross  * CDDL HEADER END
20a90cf9f2SGordon Ross  */
21a90cf9f2SGordon Ross /*
22a90cf9f2SGordon Ross  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
231160dcf7SMatt Barden  * Copyright 2018 Nexenta Systems, Inc.  All rights reserved.
24a4568e19SAlexander Stetsenko  * Copyright 2022 RackTop Systems, Inc.
25a90cf9f2SGordon Ross  */
26a90cf9f2SGordon Ross /*
27a90cf9f2SGordon Ross  * These routines provide the SMB MAC signing for the SMB2 server.
28a90cf9f2SGordon Ross  * The routines calculate the signature of a SMB message in an mbuf chain.
29a90cf9f2SGordon Ross  *
30a90cf9f2SGordon Ross  * The following table describes the client server
31a90cf9f2SGordon Ross  * signing registry relationship
32a90cf9f2SGordon Ross  *
33a90cf9f2SGordon Ross  *		| Required	| Enabled     | Disabled
34a90cf9f2SGordon Ross  * -------------+---------------+------------ +--------------
35a90cf9f2SGordon Ross  * Required	| Signed	| Signed      | Fail
36a90cf9f2SGordon Ross  * -------------+---------------+-------------+-----------------
37a90cf9f2SGordon Ross  * Enabled	| Signed	| Signed      | Not Signed
38a90cf9f2SGordon Ross  * -------------+---------------+-------------+----------------
39a90cf9f2SGordon Ross  * Disabled	| Fail		| Not Signed  | Not Signed
40a90cf9f2SGordon Ross  */
41a90cf9f2SGordon Ross 
42a90cf9f2SGordon Ross #include <sys/uio.h>
431160dcf7SMatt Barden #include <smbsrv/smb2_kproto.h>
441160dcf7SMatt Barden #include <smbsrv/smb_kcrypt.h>
45a90cf9f2SGordon Ross #include <sys/isa_defs.h>
46a90cf9f2SGordon Ross #include <sys/byteorder.h>
47a90cf9f2SGordon Ross #include <sys/cmn_err.h>
48a90cf9f2SGordon Ross 
49a90cf9f2SGordon Ross #define	SMB2_SIG_OFFS	48
50a90cf9f2SGordon Ross #define	SMB2_SIG_SIZE	16
51a90cf9f2SGordon Ross 
52c51c88bdSMatt Barden typedef struct mac_ops {
531160dcf7SMatt Barden 	int (*mac_init)(smb_sign_ctx_t *, smb_crypto_mech_t *,
54c51c88bdSMatt Barden 			uint8_t *, size_t);
55c51c88bdSMatt Barden 	int (*mac_update)(smb_sign_ctx_t, uint8_t *, size_t);
56c51c88bdSMatt Barden 	int (*mac_final)(smb_sign_ctx_t, uint8_t *);
57c51c88bdSMatt Barden } mac_ops_t;
58c51c88bdSMatt Barden 
59c51c88bdSMatt Barden static int smb2_sign_calc_common(smb_request_t *, struct mbuf_chain *,
60c51c88bdSMatt Barden     uint8_t *, mac_ops_t *);
61c51c88bdSMatt Barden 
62c51c88bdSMatt Barden /*
63c51c88bdSMatt Barden  * SMB2 wrapper functions
64c51c88bdSMatt Barden  */
65c51c88bdSMatt Barden 
66c51c88bdSMatt Barden static mac_ops_t
67c51c88bdSMatt Barden smb2_sign_ops = {
68c51c88bdSMatt Barden 	smb2_hmac_init,
69c51c88bdSMatt Barden 	smb2_hmac_update,
70c51c88bdSMatt Barden 	smb2_hmac_final
71c51c88bdSMatt Barden };
72c51c88bdSMatt Barden 
73c51c88bdSMatt Barden static int
smb2_sign_calc(smb_request_t * sr,struct mbuf_chain * mbc,uint8_t * digest16)74c51c88bdSMatt Barden smb2_sign_calc(smb_request_t *sr,
75c51c88bdSMatt Barden     struct mbuf_chain *mbc,
76c51c88bdSMatt Barden     uint8_t *digest16)
77c51c88bdSMatt Barden {
78c51c88bdSMatt Barden 	int rv;
79c51c88bdSMatt Barden 
80c51c88bdSMatt Barden 	rv = smb2_sign_calc_common(sr, mbc, digest16, &smb2_sign_ops);
81c51c88bdSMatt Barden 
82c51c88bdSMatt Barden 	return (rv);
83c51c88bdSMatt Barden }
84c51c88bdSMatt Barden 
85a90cf9f2SGordon Ross /*
86a90cf9f2SGordon Ross  * Called during session destroy.
87a90cf9f2SGordon Ross  */
88a90cf9f2SGordon Ross static void
smb2_sign_fini(smb_session_t * s)89a90cf9f2SGordon Ross smb2_sign_fini(smb_session_t *s)
90a90cf9f2SGordon Ross {
911160dcf7SMatt Barden 	smb_crypto_mech_t *mech;
92a90cf9f2SGordon Ross 
93a90cf9f2SGordon Ross 	if ((mech = s->sign_mech) != NULL) {
94a90cf9f2SGordon Ross 		kmem_free(mech, sizeof (*mech));
95a90cf9f2SGordon Ross 		s->sign_mech = NULL;
96a90cf9f2SGordon Ross 	}
97a90cf9f2SGordon Ross }
98a90cf9f2SGordon Ross 
99c51c88bdSMatt Barden /*
100c51c88bdSMatt Barden  * SMB3 wrapper functions
101c51c88bdSMatt Barden  */
102c51c88bdSMatt Barden 
103c51c88bdSMatt Barden static struct mac_ops
104c51c88bdSMatt Barden smb3_sign_ops = {
105c51c88bdSMatt Barden 	smb3_cmac_init,
106c51c88bdSMatt Barden 	smb3_cmac_update,
107c51c88bdSMatt Barden 	smb3_cmac_final
108c51c88bdSMatt Barden };
109c51c88bdSMatt Barden 
110c51c88bdSMatt Barden static int
smb3_sign_calc(smb_request_t * sr,struct mbuf_chain * mbc,uint8_t * digest16)111c51c88bdSMatt Barden smb3_sign_calc(smb_request_t *sr,
112c51c88bdSMatt Barden     struct mbuf_chain *mbc,
113c51c88bdSMatt Barden     uint8_t *digest16)
114c51c88bdSMatt Barden {
115c51c88bdSMatt Barden 	int rv;
116c51c88bdSMatt Barden 
117c51c88bdSMatt Barden 	rv = smb2_sign_calc_common(sr, mbc, digest16, &smb3_sign_ops);
118c51c88bdSMatt Barden 
119c51c88bdSMatt Barden 	return (rv);
120c51c88bdSMatt Barden }
121c51c88bdSMatt Barden 
122c51c88bdSMatt Barden void
smb2_sign_init_mech(smb_session_t * s)123c51c88bdSMatt Barden smb2_sign_init_mech(smb_session_t *s)
124c51c88bdSMatt Barden {
1251160dcf7SMatt Barden 	smb_crypto_mech_t *mech;
1261160dcf7SMatt Barden 	int (*get_mech)(smb_crypto_mech_t *);
127c51c88bdSMatt Barden 	int (*sign_calc)(smb_request_t *, struct mbuf_chain *, uint8_t *);
128c51c88bdSMatt Barden 	int rc;
129c51c88bdSMatt Barden 
130c51c88bdSMatt Barden 	if (s->sign_mech != NULL)
131c51c88bdSMatt Barden 		return;
132c51c88bdSMatt Barden 
133c51c88bdSMatt Barden 	if (s->dialect >= SMB_VERS_3_0) {
134c51c88bdSMatt Barden 		get_mech = smb3_cmac_getmech;
135c51c88bdSMatt Barden 		sign_calc = smb3_sign_calc;
136c51c88bdSMatt Barden 	} else {
137c51c88bdSMatt Barden 		get_mech = smb2_hmac_getmech;
138c51c88bdSMatt Barden 		sign_calc = smb2_sign_calc;
139c51c88bdSMatt Barden 	}
140c51c88bdSMatt Barden 
141c51c88bdSMatt Barden 	mech = kmem_zalloc(sizeof (*mech), KM_SLEEP);
142c51c88bdSMatt Barden 	rc = get_mech(mech);
143c51c88bdSMatt Barden 	if (rc != 0) {
144c51c88bdSMatt Barden 		kmem_free(mech, sizeof (*mech));
145c51c88bdSMatt Barden 		return;
146c51c88bdSMatt Barden 	}
147c51c88bdSMatt Barden 	s->sign_mech = mech;
148c51c88bdSMatt Barden 	s->sign_calc = sign_calc;
149c51c88bdSMatt Barden 	s->sign_fini = smb2_sign_fini;
150c51c88bdSMatt Barden }
151c51c88bdSMatt Barden 
152a90cf9f2SGordon Ross /*
153a90cf9f2SGordon Ross  * smb2_sign_begin
154c51c88bdSMatt Barden  * Handles both SMB2 & SMB3
155a90cf9f2SGordon Ross  *
156a90cf9f2SGordon Ross  * Get the mechanism info.
157a90cf9f2SGordon Ross  * Intializes MAC key based on the user session key and store it in
158a90cf9f2SGordon Ross  * the signing structure.  This begins signing on this session.
159a90cf9f2SGordon Ross  */
160c51c88bdSMatt Barden void
smb2_sign_begin(smb_request_t * sr,smb_token_t * token)161a90cf9f2SGordon Ross smb2_sign_begin(smb_request_t *sr, smb_token_t *token)
162a90cf9f2SGordon Ross {
163a90cf9f2SGordon Ross 	smb_session_t *s = sr->session;
164a90cf9f2SGordon Ross 	smb_user_t *u = sr->uid_user;
165a90cf9f2SGordon Ross 	struct smb_key *sign_key = &u->u_sign_key;
166c51c88bdSMatt Barden 
167c51c88bdSMatt Barden 	sign_key->len = 0;
168a90cf9f2SGordon Ross 
169a90cf9f2SGordon Ross 	/*
170a90cf9f2SGordon Ross 	 * We should normally have a session key here because
171a90cf9f2SGordon Ross 	 * our caller filters out Anonymous and Guest logons.
172a90cf9f2SGordon Ross 	 * However, buggy clients could get us here without a
173a90cf9f2SGordon Ross 	 * session key, in which case we'll fail later when a
174a90cf9f2SGordon Ross 	 * request that requires signing can't be checked.
175c51c88bdSMatt Barden 	 * Also, don't bother initializing if we don't have a mechanism.
176a90cf9f2SGordon Ross 	 */
177c51c88bdSMatt Barden 	if (token->tkn_ssnkey.val == NULL || token->tkn_ssnkey.len == 0 ||
178c51c88bdSMatt Barden 	    s->sign_mech == NULL)
179c51c88bdSMatt Barden 		return;
180a90cf9f2SGordon Ross 
181a90cf9f2SGordon Ross 	/*
182a90cf9f2SGordon Ross 	 * Compute and store the signing key, which lives in
183a90cf9f2SGordon Ross 	 * the user structure.
184a90cf9f2SGordon Ross 	 */
185c51c88bdSMatt Barden 	if (s->dialect >= SMB_VERS_3_0) {
186c51c88bdSMatt Barden 		/*
187c51c88bdSMatt Barden 		 * For SMB3, the signing key is a "KDF" hash of the
188a4568e19SAlexander Stetsenko 		 * session key.   Limit the SessionKey input to its
189a4568e19SAlexander Stetsenko 		 * maximum size (16 bytes)
190c51c88bdSMatt Barden 		 */
191a4568e19SAlexander Stetsenko 		uint32_t ssnkey_len = MIN(token->tkn_ssnkey.len, SMB2_KEYLEN);
1924e065a9fSAlexander Stetsenko 		if (s->dialect >= SMB_VERS_3_11) {
193a4568e19SAlexander Stetsenko 			if (smb3_kdf(sign_key->key, SMB2_KEYLEN,
194a4568e19SAlexander Stetsenko 			    token->tkn_ssnkey.val, ssnkey_len,
1954e065a9fSAlexander Stetsenko 			    (uint8_t *)"SMBSigningKey", 14,
1964e065a9fSAlexander Stetsenko 			    u->u_preauth_hashval, SHA512_DIGEST_LENGTH)
1974e065a9fSAlexander Stetsenko 			    != 0)
1984e065a9fSAlexander Stetsenko 				return;
1994e065a9fSAlexander Stetsenko 		} else {
200a4568e19SAlexander Stetsenko 			if (smb3_kdf(sign_key->key, SMB2_KEYLEN,
201a4568e19SAlexander Stetsenko 			    token->tkn_ssnkey.val, ssnkey_len,
2024e065a9fSAlexander Stetsenko 			    (uint8_t *)"SMB2AESCMAC", 12,
2034e065a9fSAlexander Stetsenko 			    (uint8_t *)"SmbSign", 8)
2044e065a9fSAlexander Stetsenko 			    != 0)
2054e065a9fSAlexander Stetsenko 				return;
2064e065a9fSAlexander Stetsenko 		}
207a4568e19SAlexander Stetsenko 		sign_key->len = SMB2_KEYLEN;
208c51c88bdSMatt Barden 	} else {
209c51c88bdSMatt Barden 		/*
210c51c88bdSMatt Barden 		 * For SMB2, the signing key is just the first 16 bytes
211c51c88bdSMatt Barden 		 * of the session key (truncated or padded with zeros).
212c51c88bdSMatt Barden 		 * [MS-SMB2] 3.2.5.3.1
213c51c88bdSMatt Barden 		 */
2141160dcf7SMatt Barden 		sign_key->len = SMB2_KEYLEN;
215c51c88bdSMatt Barden 		bcopy(token->tkn_ssnkey.val, sign_key->key,
216c51c88bdSMatt Barden 		    MIN(token->tkn_ssnkey.len, sign_key->len));
217c51c88bdSMatt Barden 	}
218a90cf9f2SGordon Ross 
219a90cf9f2SGordon Ross 	mutex_enter(&u->u_mutex);
2201160dcf7SMatt Barden 	if ((s->srv_secmode & SMB2_NEGOTIATE_SIGNING_ENABLED) != 0)
221a90cf9f2SGordon Ross 		u->u_sign_flags |= SMB_SIGNING_ENABLED;
2221160dcf7SMatt Barden 	if ((s->srv_secmode & SMB2_NEGOTIATE_SIGNING_REQUIRED) != 0 ||
2231160dcf7SMatt Barden 	    (s->cli_secmode & SMB2_NEGOTIATE_SIGNING_REQUIRED) != 0)
224a90cf9f2SGordon Ross 		u->u_sign_flags |=
225a90cf9f2SGordon Ross 		    SMB_SIGNING_ENABLED | SMB_SIGNING_CHECK;
226a90cf9f2SGordon Ross 	mutex_exit(&u->u_mutex);
227a90cf9f2SGordon Ross 
228a90cf9f2SGordon Ross 	/*
229a90cf9f2SGordon Ross 	 * If we just turned on signing, the current request
230a90cf9f2SGordon Ross 	 * (an SMB2 session setup) will have come in without
231a90cf9f2SGordon Ross 	 * SMB2_FLAGS_SIGNED (and not signed) but the response
232a90cf9f2SGordon Ross 	 * is is supposed to be signed. [MS-SMB2] 3.3.5.5
233a90cf9f2SGordon Ross 	 */
234a90cf9f2SGordon Ross 	if (u->u_sign_flags & SMB_SIGNING_ENABLED)
235a90cf9f2SGordon Ross 		sr->smb2_hdr_flags |= SMB2_FLAGS_SIGNED;
236a90cf9f2SGordon Ross }
237a90cf9f2SGordon Ross 
238a90cf9f2SGordon Ross /*
239c51c88bdSMatt Barden  * smb2_sign_calc_common
240a90cf9f2SGordon Ross  *
241a90cf9f2SGordon Ross  * Calculates MAC signature for the given buffer and returns
242a90cf9f2SGordon Ross  * it in the mac_sign parameter.
243a90cf9f2SGordon Ross  *
244c51c88bdSMatt Barden  * The signature algorithm is to compute HMAC SHA256 or AES_CMAC
245c51c88bdSMatt Barden  * over the entire command, with the signature field set to zeros.
246a90cf9f2SGordon Ross  *
247a90cf9f2SGordon Ross  * Return 0 if  success else -1
248a90cf9f2SGordon Ross  */
249c51c88bdSMatt Barden 
250a90cf9f2SGordon Ross static int
smb2_sign_calc_common(smb_request_t * sr,struct mbuf_chain * mbc,uint8_t * digest,mac_ops_t * ops)251c51c88bdSMatt Barden smb2_sign_calc_common(smb_request_t *sr, struct mbuf_chain *mbc,
252c51c88bdSMatt Barden     uint8_t *digest, mac_ops_t *ops)
253a90cf9f2SGordon Ross {
254a90cf9f2SGordon Ross 	uint8_t tmp_hdr[SMB2_HDR_SIZE];
255a90cf9f2SGordon Ross 	smb_sign_ctx_t ctx = 0;
256a90cf9f2SGordon Ross 	smb_session_t *s = sr->session;
257a90cf9f2SGordon Ross 	smb_user_t *u = sr->uid_user;
258a90cf9f2SGordon Ross 	struct smb_key *sign_key = &u->u_sign_key;
259a90cf9f2SGordon Ross 	struct mbuf *mbuf;
260a90cf9f2SGordon Ross 	int offset, resid, tlen, rc;
261a90cf9f2SGordon Ross 
262a90cf9f2SGordon Ross 	if (s->sign_mech == NULL || sign_key->len == 0)
263a90cf9f2SGordon Ross 		return (-1);
264a90cf9f2SGordon Ross 
265c51c88bdSMatt Barden 	/* smb2_hmac_init or smb3_cmac_init */
266c51c88bdSMatt Barden 	rc = ops->mac_init(&ctx, s->sign_mech, sign_key->key, sign_key->len);
267a90cf9f2SGordon Ross 	if (rc != 0)
268a90cf9f2SGordon Ross 		return (rc);
269a90cf9f2SGordon Ross 
270a90cf9f2SGordon Ross 	/*
271a90cf9f2SGordon Ross 	 * Work with a copy of the SMB2 header so we can
272a90cf9f2SGordon Ross 	 * clear the signature field without modifying
273a90cf9f2SGordon Ross 	 * the original message.
274a90cf9f2SGordon Ross 	 */
275a90cf9f2SGordon Ross 	tlen = SMB2_HDR_SIZE;
276a90cf9f2SGordon Ross 	offset = mbc->chain_offset;
277a90cf9f2SGordon Ross 	resid = mbc->max_bytes - offset;
278a90cf9f2SGordon Ross 	if (smb_mbc_peek(mbc, offset, "#c", tlen, tmp_hdr) != 0)
279a90cf9f2SGordon Ross 		return (-1);
280a90cf9f2SGordon Ross 	bzero(tmp_hdr + SMB2_SIG_OFFS, SMB2_SIG_SIZE);
281c51c88bdSMatt Barden 	/* smb2_hmac_update or smb3_cmac_update */
282c51c88bdSMatt Barden 	if ((rc = ops->mac_update(ctx, tmp_hdr, tlen)) != 0)
283a90cf9f2SGordon Ross 		return (rc);
284a90cf9f2SGordon Ross 	offset += tlen;
285a90cf9f2SGordon Ross 	resid -= tlen;
286a90cf9f2SGordon Ross 
287a90cf9f2SGordon Ross 	/*
288a90cf9f2SGordon Ross 	 * Digest the rest of the SMB packet, starting at the data
289a90cf9f2SGordon Ross 	 * just after the SMB header.
290a90cf9f2SGordon Ross 	 *
291a90cf9f2SGordon Ross 	 * Advance to the src mbuf where we start digesting.
292a90cf9f2SGordon Ross 	 */
293a90cf9f2SGordon Ross 	mbuf = mbc->chain;
294a90cf9f2SGordon Ross 	while (mbuf != NULL && (offset >= mbuf->m_len)) {
295a90cf9f2SGordon Ross 		offset -= mbuf->m_len;
296a90cf9f2SGordon Ross 		mbuf = mbuf->m_next;
297a90cf9f2SGordon Ross 	}
298a90cf9f2SGordon Ross 
299a90cf9f2SGordon Ross 	if (mbuf == NULL)
300a90cf9f2SGordon Ross 		return (-1);
301a90cf9f2SGordon Ross 
302a90cf9f2SGordon Ross 	/*
303a90cf9f2SGordon Ross 	 * Digest the remainder of this mbuf, limited to the
304a90cf9f2SGordon Ross 	 * residual count, and starting at the current offset.
305a90cf9f2SGordon Ross 	 * (typically SMB2_HDR_SIZE)
306a90cf9f2SGordon Ross 	 */
307a90cf9f2SGordon Ross 	tlen = mbuf->m_len - offset;
308a90cf9f2SGordon Ross 	if (tlen > resid)
309a90cf9f2SGordon Ross 		tlen = resid;
310c51c88bdSMatt Barden 	/* smb2_hmac_update or smb3_cmac_update */
311c51c88bdSMatt Barden 	rc = ops->mac_update(ctx, (uint8_t *)mbuf->m_data + offset, tlen);
312a90cf9f2SGordon Ross 	if (rc != 0)
313a90cf9f2SGordon Ross 		return (rc);
314a90cf9f2SGordon Ross 	resid -= tlen;
315a90cf9f2SGordon Ross 
316a90cf9f2SGordon Ross 	/*
317a90cf9f2SGordon Ross 	 * Digest any more mbufs in the chain.
318a90cf9f2SGordon Ross 	 */
319a90cf9f2SGordon Ross 	while (resid > 0) {
320a90cf9f2SGordon Ross 		mbuf = mbuf->m_next;
321a90cf9f2SGordon Ross 		if (mbuf == NULL)
322a90cf9f2SGordon Ross 			return (-1);
323a90cf9f2SGordon Ross 		tlen = mbuf->m_len;
324a90cf9f2SGordon Ross 		if (tlen > resid)
325a90cf9f2SGordon Ross 			tlen = resid;
326c51c88bdSMatt Barden 		rc = ops->mac_update(ctx, (uint8_t *)mbuf->m_data, tlen);
327a90cf9f2SGordon Ross 		if (rc != 0)
328a90cf9f2SGordon Ross 			return (rc);
329a90cf9f2SGordon Ross 		resid -= tlen;
330a90cf9f2SGordon Ross 	}
331a90cf9f2SGordon Ross 
332a90cf9f2SGordon Ross 	/*
333c51c88bdSMatt Barden 	 * smb2_hmac_final or smb3_cmac_final
334a90cf9f2SGordon Ross 	 * Note: digest is _always_ SMB2_SIG_SIZE,
335a90cf9f2SGordon Ross 	 * even if the mech uses a longer one.
336c51c88bdSMatt Barden 	 *
337c51c88bdSMatt Barden 	 * smb2_hmac_update or smb3_cmac_update
338a90cf9f2SGordon Ross 	 */
339c51c88bdSMatt Barden 	if ((rc = ops->mac_final(ctx, digest)) != 0)
340a90cf9f2SGordon Ross 		return (rc);
341a90cf9f2SGordon Ross 
342a90cf9f2SGordon Ross 	return (0);
343a90cf9f2SGordon Ross }
344a90cf9f2SGordon Ross 
345a90cf9f2SGordon Ross /*
346a90cf9f2SGordon Ross  * smb2_sign_check_request
347a90cf9f2SGordon Ross  *
348a90cf9f2SGordon Ross  * Calculates MAC signature for the request mbuf chain
349a90cf9f2SGordon Ross  * using the next expected sequence number and compares
350a90cf9f2SGordon Ross  * it to the given signature.
351a90cf9f2SGordon Ross  *
352a90cf9f2SGordon Ross  * Note it does not check the signature for secondary transactions
353a90cf9f2SGordon Ross  * as their sequence number is the same as the original request.
354a90cf9f2SGordon Ross  *
355a90cf9f2SGordon Ross  * Return 0 if the signature verifies, otherwise, returns -1;
356a90cf9f2SGordon Ross  *
357a90cf9f2SGordon Ross  */
358a90cf9f2SGordon Ross int
smb2_sign_check_request(smb_request_t * sr)359a90cf9f2SGordon Ross smb2_sign_check_request(smb_request_t *sr)
360a90cf9f2SGordon Ross {
361a90cf9f2SGordon Ross 	uint8_t req_sig[SMB2_SIG_SIZE];
362a90cf9f2SGordon Ross 	uint8_t vfy_sig[SMB2_SIG_SIZE];
363a90cf9f2SGordon Ross 	struct mbuf_chain *mbc = &sr->smb_data;
364c51c88bdSMatt Barden 	smb_session_t *s = sr->session;
365a90cf9f2SGordon Ross 	smb_user_t *u = sr->uid_user;
366a90cf9f2SGordon Ross 	int sig_off;
367a90cf9f2SGordon Ross 
368a90cf9f2SGordon Ross 	/*
369a90cf9f2SGordon Ross 	 * Don't check commands with a zero session ID.
370a90cf9f2SGordon Ross 	 * [MS-SMB2] 3.3.4.1.1
371a90cf9f2SGordon Ross 	 */
372811599a4SMatt Barden 	if (sr->smb2_ssnid == 0 || u == NULL)
373a90cf9f2SGordon Ross 		return (0);
374a90cf9f2SGordon Ross 
375c51c88bdSMatt Barden 	/* In case _sign_begin failed. */
376c51c88bdSMatt Barden 	if (s->sign_calc == NULL)
377c51c88bdSMatt Barden 		return (-1);
378c51c88bdSMatt Barden 
379a90cf9f2SGordon Ross 	/* Get the request signature. */
380a90cf9f2SGordon Ross 	sig_off = sr->smb2_cmd_hdr + SMB2_SIG_OFFS;
381a90cf9f2SGordon Ross 	if (smb_mbc_peek(mbc, sig_off, "#c", SMB2_SIG_SIZE, req_sig) != 0)
382a90cf9f2SGordon Ross 		return (-1);
383a90cf9f2SGordon Ross 
384a90cf9f2SGordon Ross 	/*
385a90cf9f2SGordon Ross 	 * Compute the correct signature and compare.
386c51c88bdSMatt Barden 	 * smb2_sign_calc() or smb3_sign_calc()
387a90cf9f2SGordon Ross 	 */
388c51c88bdSMatt Barden 	if (s->sign_calc(sr, mbc, vfy_sig) != 0)
389a90cf9f2SGordon Ross 		return (-1);
390*45f8fdd1SGordon Ross 
391*45f8fdd1SGordon Ross 	if (memcmp(vfy_sig, req_sig, SMB2_SIG_SIZE) == 0) {
392*45f8fdd1SGordon Ross 		return (0);
393a90cf9f2SGordon Ross 	}
394a90cf9f2SGordon Ross 
395*45f8fdd1SGordon Ross 	DTRACE_PROBE2(signature__mismatch, smb_request_t *, sr,
396*45f8fdd1SGordon Ross 	    uint8_t *, vfy_sig);
397*45f8fdd1SGordon Ross 
398*45f8fdd1SGordon Ross 	return (-1);
399a90cf9f2SGordon Ross }
400a90cf9f2SGordon Ross 
401a90cf9f2SGordon Ross /*
402a90cf9f2SGordon Ross  * smb2_sign_reply
403a90cf9f2SGordon Ross  *
404a90cf9f2SGordon Ross  * Calculates MAC signature for the given mbuf chain,
405a90cf9f2SGordon Ross  * and write it to the signature field in the mbuf.
406a90cf9f2SGordon Ross  *
407a90cf9f2SGordon Ross  */
408a90cf9f2SGordon Ross void
smb2_sign_reply(smb_request_t * sr)409a90cf9f2SGordon Ross smb2_sign_reply(smb_request_t *sr)
410a90cf9f2SGordon Ross {
411a90cf9f2SGordon Ross 	uint8_t reply_sig[SMB2_SIG_SIZE];
412a90cf9f2SGordon Ross 	struct mbuf_chain tmp_mbc;
413c51c88bdSMatt Barden 	smb_session_t *s = sr->session;
414a90cf9f2SGordon Ross 	smb_user_t *u = sr->uid_user;
415a90cf9f2SGordon Ross 	int hdr_off, msg_len;
416a90cf9f2SGordon Ross 
417a90cf9f2SGordon Ross 	if (u == NULL)
418a90cf9f2SGordon Ross 		return;
419c51c88bdSMatt Barden 	if (s->sign_calc == NULL)
420c51c88bdSMatt Barden 		return;
421a90cf9f2SGordon Ross 
422a90cf9f2SGordon Ross 	msg_len = sr->reply.chain_offset - sr->smb2_reply_hdr;
423a90cf9f2SGordon Ross 	(void) MBC_SHADOW_CHAIN(&tmp_mbc, &sr->reply,
424a90cf9f2SGordon Ross 	    sr->smb2_reply_hdr, msg_len);
425a90cf9f2SGordon Ross 
426a90cf9f2SGordon Ross 	/*
427a90cf9f2SGordon Ross 	 * Calculate the MAC signature for this reply.
428c51c88bdSMatt Barden 	 * smb2_sign_calc() or smb3_sign_calc()
429a90cf9f2SGordon Ross 	 */
430c51c88bdSMatt Barden 	if (s->sign_calc(sr, &tmp_mbc, reply_sig) != 0)
431a90cf9f2SGordon Ross 		return;
432a90cf9f2SGordon Ross 
433a90cf9f2SGordon Ross 	/*
434a90cf9f2SGordon Ross 	 * Poke the signature into the response.
435a90cf9f2SGordon Ross 	 */
436a90cf9f2SGordon Ross 	hdr_off = sr->smb2_reply_hdr + SMB2_SIG_OFFS;
437a90cf9f2SGordon Ross 	(void) smb_mbc_poke(&sr->reply, hdr_off, "#c",
438a90cf9f2SGordon Ross 	    SMB2_SIG_SIZE, reply_sig);
439a90cf9f2SGordon Ross }
440