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, ¶m, 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, ¶m, 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