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