xref: /illumos-gate/usr/src/uts/common/fs/smbsrv/smb2_signing.c (revision 4e774db12f8cbb6fbac674a432a7946f9db6c012)
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 2020-2023 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 /*
53  * Called during session destroy.
54  */
55 static void
smb2_sign_fini(smb_session_t * s)56 smb2_sign_fini(smb_session_t *s)
57 {
58 	smb_crypto_mech_t *mech;
59 
60 	if ((mech = s->sign_mech) != NULL) {
61 		kmem_free(mech, sizeof (*mech));
62 		s->sign_mech = NULL;
63 	}
64 }
65 
66 void
smb2_sign_init_mech(smb_session_t * s)67 smb2_sign_init_mech(smb_session_t *s)
68 {
69 	smb_crypto_mech_t *mech;
70 	int (*get_mech)(smb_crypto_mech_t *);
71 	int rc;
72 
73 	if (s->sign_mech != NULL)
74 		return;
75 
76 	switch (s->smb31_sign_algid) {
77 	case SMB3_SIGN_SHA256_HMAC:
78 		get_mech = smb2_hmac_getmech;
79 		break;
80 	case SMB3_SIGN_AES128_CMAC:
81 		get_mech = smb3_cmac_getmech;
82 		break;
83 	case SMB3_SIGN_AES128_GMAC:
84 		get_mech = smb3_gmac_getmech;
85 		break;
86 	default:
87 		return;
88 	}
89 
90 	mech = kmem_zalloc(sizeof (*mech), KM_SLEEP);
91 	rc = get_mech(mech);
92 	if (rc != 0) {
93 		kmem_free(mech, sizeof (*mech));
94 		return;
95 	}
96 	s->sign_mech = mech;
97 	s->sign_fini = smb2_sign_fini;
98 }
99 
100 /*
101  * smb2_sign_begin
102  * Handles both SMB2 & SMB3
103  *
104  * Get the mechanism info.
105  * Intializes MAC key based on the user session key and store it in
106  * the signing structure.  This begins signing on this session.
107  */
108 void
smb2_sign_begin(smb_request_t * sr,smb_token_t * token)109 smb2_sign_begin(smb_request_t *sr, smb_token_t *token)
110 {
111 	smb_session_t *s = sr->session;
112 	smb_user_t *u = sr->uid_user;
113 	struct smb_key *sign_key = &u->u_sign_key;
114 
115 	sign_key->len = 0;
116 
117 	/*
118 	 * We should normally have a session key here because
119 	 * our caller filters out Anonymous and Guest logons.
120 	 * However, buggy clients could get us here without a
121 	 * session key, in which case we'll fail later when a
122 	 * request that requires signing can't be checked.
123 	 * Also, don't bother initializing if we don't have a mechanism.
124 	 */
125 	if (token->tkn_ssnkey.val == NULL || token->tkn_ssnkey.len == 0 ||
126 	    s->sign_mech == NULL)
127 		return;
128 
129 	/*
130 	 * Compute and store the signing key, which lives in
131 	 * the user structure.
132 	 */
133 	if (s->dialect >= SMB_VERS_3_0) {
134 		/*
135 		 * For SMB3, the signing key is a "KDF" hash of the
136 		 * session key.   Limit the SessionKey input to its
137 		 * maximum size (16 bytes)
138 		 */
139 		uint32_t ssnkey_len = MIN(token->tkn_ssnkey.len, SMB2_KEYLEN);
140 		if (s->dialect >= SMB_VERS_3_11) {
141 			if (smb3_kdf(sign_key->key, SMB2_KEYLEN,
142 			    token->tkn_ssnkey.val, ssnkey_len,
143 			    (uint8_t *)"SMBSigningKey", 14,
144 			    u->u_preauth_hashval, SHA512_DIGEST_LENGTH)
145 			    != 0)
146 				return;
147 		} else {
148 			if (smb3_kdf(sign_key->key, SMB2_KEYLEN,
149 			    token->tkn_ssnkey.val, ssnkey_len,
150 			    (uint8_t *)"SMB2AESCMAC", 12,
151 			    (uint8_t *)"SmbSign", 8)
152 			    != 0)
153 				return;
154 		}
155 		sign_key->len = SMB2_KEYLEN;
156 	} else {
157 		/*
158 		 * For SMB2, the signing key is just the first 16 bytes
159 		 * of the session key (truncated or padded with zeros).
160 		 * [MS-SMB2] 3.2.5.3.1
161 		 */
162 		sign_key->len = SMB2_KEYLEN;
163 		bcopy(token->tkn_ssnkey.val, sign_key->key,
164 		    MIN(token->tkn_ssnkey.len, sign_key->len));
165 	}
166 
167 	mutex_enter(&u->u_mutex);
168 	if ((s->srv_secmode & SMB2_NEGOTIATE_SIGNING_ENABLED) != 0)
169 		u->u_sign_flags |= SMB_SIGNING_ENABLED;
170 	if ((s->srv_secmode & SMB2_NEGOTIATE_SIGNING_REQUIRED) != 0 ||
171 	    (s->cli_secmode & SMB2_NEGOTIATE_SIGNING_REQUIRED) != 0)
172 		u->u_sign_flags |=
173 		    SMB_SIGNING_ENABLED | SMB_SIGNING_CHECK;
174 	mutex_exit(&u->u_mutex);
175 
176 	/*
177 	 * If we just turned on signing, the current request
178 	 * (an SMB2 session setup) will have come in without
179 	 * SMB2_FLAGS_SIGNED (and not signed) but the response
180 	 * is is supposed to be signed. [MS-SMB2] 3.3.5.5
181 	 */
182 	if (u->u_sign_flags & SMB_SIGNING_ENABLED)
183 		sr->smb2_hdr_flags |= SMB2_FLAGS_SIGNED;
184 }
185 
186 static void
smb2_construct_gmac_iv(smb_request_t * sr,boolean_t is_server_msg,uint8_t * iv)187 smb2_construct_gmac_iv(smb_request_t *sr, boolean_t is_server_msg, uint8_t *iv)
188 {
189 	uint64_t msgid = sr->smb2_messageid;
190 	int i;
191 
192 	/*
193 	 * [MS-SMB2] 3.1.4.1 "Signing an Outgoing Message"
194 	 * The 12-byte IV for AES-GMAC is created as follows:
195 	 *
196 	 * First 8 bytes are the messageid (wire order)
197 	 */
198 	for (i = 0; i < 8; i++) {
199 		iv[i] = msgid & 0xff;
200 		msgid >>= 8;
201 	}
202 
203 	/*
204 	 * Next byte:
205 	 * LSB is 1 iff the message is from the server;
206 	 * 2nd LSB is 1 iff this is a cancel op;
207 	 * Rest are 0.
208 	 */
209 
210 	iv[i] = 0;
211 	if (is_server_msg)
212 		iv[i] |= 1;
213 	if (sr->smb2_cmd_code == SMB2_CANCEL)
214 		iv[i] |= 2;
215 
216 	/* Last 3 bytes are 0 */
217 	for (i++; i < SMB3_AES_GMAC_NONCE_SIZE; i++)
218 		iv[i] = 0;
219 }
220 
221 /*
222  * smb2_sign_calc
223  *
224  * Calculates MAC signature for the given buffer and returns
225  * it in the 'digest' parameter.
226  *
227  * The signature algorithm is to compute HMAC SHA256, AES_CMAC, or AES_GMAC
228  * over the entire command, with the signature field set to zeros.
229  *
230  * Return 0 if  success else non-zero
231  */
232 
233 static int
smb2_sign_calc(smb_request_t * sr,struct mbuf_chain * mbc,uint8_t * digest,boolean_t is_server_msg)234 smb2_sign_calc(smb_request_t *sr, struct mbuf_chain *mbc,
235     uint8_t *digest, boolean_t is_server_msg)
236 {
237 	uint8_t tmp_hdr[SMB2_HDR_SIZE];
238 	uint8_t iv[SMB3_AES_GMAC_NONCE_SIZE];
239 	smb_crypto_mech_t mech;
240 	smb_crypto_param_t param;
241 	smb_session_t *s = sr->session;
242 	smb_user_t *u = sr->uid_user;
243 	struct smb_key *sign_key = &u->u_sign_key;
244 	struct mbuf *mbuf;
245 	smb_vdb_t *in_vdb = NULL;
246 	int offset, resid, tlen, rc;
247 	int hdr_iov_cnt = 0;
248 
249 	if (s->sign_mech == NULL || sign_key->len == 0)
250 		return (-1);
251 
252 	mech = *((smb_crypto_mech_t *)s->sign_mech);
253 
254 	switch (s->smb31_sign_algid) {
255 	case SMB3_SIGN_AES128_CMAC:
256 		/* CMAC has no parameter */
257 		break;
258 	case SMB3_SIGN_SHA256_HMAC:
259 		smb2_sign_init_hmac_param(&mech, &param, SMB2_SIG_SIZE);
260 		break;
261 	case SMB3_SIGN_AES128_GMAC:
262 		smb2_construct_gmac_iv(sr, is_server_msg, iv);
263 		smb3_sign_init_gmac_param(&mech, &param, iv);
264 		break;
265 	default:
266 		ASSERT(0);
267 		return (-1);
268 	}
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 
282 	/* Build a UIO vector for the auth data. */
283 	in_vdb = smb_get_vdb(sr);
284 	in_vdb->vdb_uio.uio_resid = resid;
285 
286 	in_vdb->vdb_uio.uio_iov[hdr_iov_cnt].iov_base = (char *)tmp_hdr;
287 	in_vdb->vdb_uio.uio_iov[hdr_iov_cnt++].iov_len = tlen;
288 
289 	offset += tlen;
290 	resid -= tlen;
291 
292 	/*
293 	 * Digest the rest of the SMB packet, starting at the data
294 	 * just after the SMB header.
295 	 *
296 	 * Advance to the src mbuf where we start digesting.
297 	 */
298 	mbuf = mbc->chain;
299 	while (mbuf != NULL && (offset >= mbuf->m_len)) {
300 		offset -= mbuf->m_len;
301 		mbuf = mbuf->m_next;
302 	}
303 
304 	if (mbuf == NULL)
305 		return (-1);
306 
307 	/*
308 	 * Digest the remainder of this mbuf, limited to the
309 	 * residual count, and starting at the current offset.
310 	 * (typically SMB2_HDR_SIZE)
311 	 */
312 	tlen = mbuf->m_len - offset;
313 	if (tlen > resid)
314 		tlen = resid;
315 
316 	in_vdb->vdb_uio.uio_iov[hdr_iov_cnt].iov_base = mbuf->m_data + offset;
317 	in_vdb->vdb_uio.uio_iov[hdr_iov_cnt++].iov_len = tlen;
318 
319 	/*
320 	 * Digest any more mbufs in the chain.
321 	 */
322 	rc = smb_mbuf_mkuio_cont(mbuf->m_next, &in_vdb->vdb_uio, hdr_iov_cnt);
323 	if (rc != 0)
324 		return (-1);
325 
326 	/*
327 	 * Note: digest is _always_ SMB2_SIG_SIZE,
328 	 * even if the mech uses a longer one.
329 	 */
330 	if ((rc = smb2_mac_uio(&mech, sign_key->key, sign_key->len,
331 	    &in_vdb->vdb_uio, digest)) != 0)
332 		return (rc);
333 
334 	return (0);
335 }
336 
337 /*
338  * smb2_sign_check_request
339  *
340  * Calculates MAC signature for the request mbuf chain
341  * using the next expected sequence number and compares
342  * it to the given signature.
343  *
344  * Note it does not check the signature for secondary transactions
345  * as their sequence number is the same as the original request.
346  *
347  * Return 0 if the signature verifies, otherwise, returns -1;
348  *
349  */
350 int
smb2_sign_check_request(smb_request_t * sr)351 smb2_sign_check_request(smb_request_t *sr)
352 {
353 	uint8_t req_sig[SMB2_SIG_SIZE];
354 	uint8_t vfy_sig[SMB2_SIG_SIZE];
355 	struct mbuf_chain *mbc = &sr->smb_data;
356 	smb_session_t *s = sr->session;
357 	smb_user_t *u = sr->uid_user;
358 	int sig_off;
359 
360 	/*
361 	 * Don't check commands with a zero session ID.
362 	 * [MS-SMB2] 3.3.4.1.1
363 	 */
364 	if (sr->smb2_ssnid == 0 || u == NULL)
365 		return (0);
366 
367 	/*
368 	 * If the negotiated signing mechanism is unavailable
369 	 * (which is not expected, so this is mostly paranoia)
370 	 * smb2_sign_init_mech would leave s->sign_fini = NULL
371 	 * and s->sign_mech invalid.  Checking s->sign_fini is
372 	 * easiest (type of s->sign_mech varies K vs U).
373 	 * If the mech is unsupported, return failure.
374 	 */
375 	if (s->sign_fini == NULL)
376 		return (-1);
377 
378 	/* Get the request signature. */
379 	sig_off = sr->smb2_cmd_hdr + SMB2_SIG_OFFS;
380 	if (smb_mbc_peek(mbc, sig_off, "#c", SMB2_SIG_SIZE, req_sig) != 0)
381 		return (-1);
382 
383 	/*
384 	 * Compute the correct signature and compare.
385 	 */
386 	if (smb2_sign_calc(sr, mbc, vfy_sig, B_FALSE) != 0)
387 		return (-1);
388 
389 	if (memcmp(vfy_sig, req_sig, SMB2_SIG_SIZE) == 0) {
390 		return (0);
391 	}
392 
393 	DTRACE_PROBE2(signature__mismatch, smb_request_t *, sr,
394 	    uint8_t *, vfy_sig);
395 
396 	return (-1);
397 }
398 
399 /*
400  * smb2_sign_reply
401  *
402  * Calculates MAC signature for the given mbuf chain,
403  * and write it to the signature field in the mbuf.
404  *
405  */
406 void
smb2_sign_reply(smb_request_t * sr)407 smb2_sign_reply(smb_request_t *sr)
408 {
409 	uint8_t reply_sig[SMB2_SIG_SIZE];
410 	struct mbuf_chain tmp_mbc;
411 	smb_session_t *s = sr->session;
412 	smb_user_t *u = sr->uid_user;
413 	int hdr_off, msg_len;
414 
415 	if (u == NULL)
416 		return;
417 
418 	/*
419 	 * If the negotiated signing mechanism is unavailable
420 	 * (which is not expected, so this is mostly paranoia)
421 	 * smb2_sign_init_mech would leave s->sign_fini = NULL
422 	 * and s->sign_mech invalid.  Checking s->sign_fini is
423 	 * easiest (type of s->sign_mech varies K vs U).
424 	 * If the mech is unsupported, just don't sign.
425 	 * The (un-signed) reponse will probably cause the
426 	 * client to drop the connection.
427 	 */
428 	if (s->sign_fini == NULL)
429 		return;
430 
431 	msg_len = sr->reply.chain_offset - sr->smb2_reply_hdr;
432 	(void) MBC_SHADOW_CHAIN(&tmp_mbc, &sr->reply,
433 	    sr->smb2_reply_hdr, msg_len);
434 
435 	/*
436 	 * Calculate the MAC signature for this reply.
437 	 */
438 	if (smb2_sign_calc(sr, &tmp_mbc, reply_sig, B_TRUE) != 0)
439 		return;
440 
441 	/*
442 	 * Poke the signature into the response.
443 	 */
444 	hdr_off = sr->smb2_reply_hdr + SMB2_SIG_OFFS;
445 	(void) smb_mbc_poke(&sr->reply, hdr_off, "#c",
446 	    SMB2_SIG_SIZE, reply_sig);
447 }
448