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 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.
189 */
190 if (s->dialect >= SMB_VERS_3_11) {
191 if (smb3_kdf(sign_key->key,
192 token->tkn_ssnkey.val, token->tkn_ssnkey.len,
193 (uint8_t *)"SMBSigningKey", 14,
194 s->smb31_preauth_hashval, SHA512_DIGEST_LENGTH)
195 != 0)
196 return;
197 } else {
198 if (smb3_kdf(sign_key->key,
199 token->tkn_ssnkey.val, token->tkn_ssnkey.len,
200 (uint8_t *)"SMB2AESCMAC", 12,
201 (uint8_t *)"SmbSign", 8)
202 != 0)
203 return;
204 }
205 sign_key->len = SMB3_KEYLEN;
206 } else {
207 /*
208 * For SMB2, the signing key is just the first 16 bytes
209 * of the session key (truncated or padded with zeros).
210 * [MS-SMB2] 3.2.5.3.1
211 */
212 sign_key->len = SMB2_KEYLEN;
213 bcopy(token->tkn_ssnkey.val, sign_key->key,
214 MIN(token->tkn_ssnkey.len, sign_key->len));
215 }
216
217 mutex_enter(&u->u_mutex);
218 if ((s->srv_secmode & SMB2_NEGOTIATE_SIGNING_ENABLED) != 0)
219 u->u_sign_flags |= SMB_SIGNING_ENABLED;
220 if ((s->srv_secmode & SMB2_NEGOTIATE_SIGNING_REQUIRED) != 0 ||
221 (s->cli_secmode & SMB2_NEGOTIATE_SIGNING_REQUIRED) != 0)
222 u->u_sign_flags |=
223 SMB_SIGNING_ENABLED | SMB_SIGNING_CHECK;
224 mutex_exit(&u->u_mutex);
225
226 /*
227 * If we just turned on signing, the current request
228 * (an SMB2 session setup) will have come in without
229 * SMB2_FLAGS_SIGNED (and not signed) but the response
230 * is is supposed to be signed. [MS-SMB2] 3.3.5.5
231 */
232 if (u->u_sign_flags & SMB_SIGNING_ENABLED)
233 sr->smb2_hdr_flags |= SMB2_FLAGS_SIGNED;
234 }
235
236 /*
237 * smb2_sign_calc_common
238 *
239 * Calculates MAC signature for the given buffer and returns
240 * it in the mac_sign parameter.
241 *
242 * The signature algorithm is to compute HMAC SHA256 or AES_CMAC
243 * over the entire command, with the signature field set to zeros.
244 *
245 * Return 0 if success else -1
246 */
247
248 static int
249 smb2_sign_calc_common(smb_request_t *sr, struct mbuf_chain *mbc,
250 uint8_t *digest, mac_ops_t *ops)
251 {
252 uint8_t tmp_hdr[SMB2_HDR_SIZE];
253 smb_sign_ctx_t ctx = 0;
254 smb_session_t *s = sr->session;
255 smb_user_t *u = sr->uid_user;
256 struct smb_key *sign_key = &u->u_sign_key;
257 struct mbuf *mbuf;
258 int offset, resid, tlen, rc;
259
260 if (s->sign_mech == NULL || sign_key->len == 0)
261 return (-1);
262
263 /* smb2_hmac_init or smb3_cmac_init */
264 rc = ops->mac_init(&ctx, s->sign_mech, sign_key->key, sign_key->len);
265 if (rc != 0)
266 return (rc);
267
268 /*
269 * Work with a copy of the SMB2 header so we can
270 * clear the signature field without modifying
271 * the original message.
272 */
273 tlen = SMB2_HDR_SIZE;
274 offset = mbc->chain_offset;
275 resid = mbc->max_bytes - offset;
276 if (smb_mbc_peek(mbc, offset, "#c", tlen, tmp_hdr) != 0)
277 return (-1);
278 bzero(tmp_hdr + SMB2_SIG_OFFS, SMB2_SIG_SIZE);
279 /* smb2_hmac_update or smb3_cmac_update */
280 if ((rc = ops->mac_update(ctx, tmp_hdr, tlen)) != 0)
281 return (rc);
282 offset += tlen;
283 resid -= tlen;
284
285 /*
286 * Digest the rest of the SMB packet, starting at the data
287 * just after the SMB header.
288 *
289 * Advance to the src mbuf where we start digesting.
290 */
291 mbuf = mbc->chain;
292 while (mbuf != NULL && (offset >= mbuf->m_len)) {
293 offset -= mbuf->m_len;
294 mbuf = mbuf->m_next;
295 }
296
297 if (mbuf == NULL)
298 return (-1);
299
300 /*
301 * Digest the remainder of this mbuf, limited to the
302 * residual count, and starting at the current offset.
303 * (typically SMB2_HDR_SIZE)
304 */
305 tlen = mbuf->m_len - offset;
306 if (tlen > resid)
307 tlen = resid;
308 /* smb2_hmac_update or smb3_cmac_update */
309 rc = ops->mac_update(ctx, (uint8_t *)mbuf->m_data + offset, tlen);
310 if (rc != 0)
311 return (rc);
312 resid -= tlen;
313
314 /*
315 * Digest any more mbufs in the chain.
316 */
317 while (resid > 0) {
318 mbuf = mbuf->m_next;
319 if (mbuf == NULL)
320 return (-1);
321 tlen = mbuf->m_len;
322 if (tlen > resid)
323 tlen = resid;
324 rc = ops->mac_update(ctx, (uint8_t *)mbuf->m_data, tlen);
325 if (rc != 0)
326 return (rc);
327 resid -= tlen;
328 }
329
330 /*
331 * smb2_hmac_final or smb3_cmac_final
332 * Note: digest is _always_ SMB2_SIG_SIZE,
333 * even if the mech uses a longer one.
334 *
335 * smb2_hmac_update or smb3_cmac_update
336 */
337 if ((rc = ops->mac_final(ctx, digest)) != 0)
338 return (rc);
339
340 return (0);
341 }
342
343 /*
344 * smb2_sign_check_request
345 *
346 * Calculates MAC signature for the request mbuf chain
347 * using the next expected sequence number and compares
348 * it to the given signature.
349 *
350 * Note it does not check the signature for secondary transactions
351 * as their sequence number is the same as the original request.
352 *
353 * Return 0 if the signature verifies, otherwise, returns -1;
354 *
355 */
356 int
357 smb2_sign_check_request(smb_request_t *sr)
358 {
359 uint8_t req_sig[SMB2_SIG_SIZE];
360 uint8_t vfy_sig[SMB2_SIG_SIZE];
361 struct mbuf_chain *mbc = &sr->smb_data;
362 smb_session_t *s = sr->session;
363 smb_user_t *u = sr->uid_user;
364 int sig_off;
365
366 /*
367 * Don't check commands with a zero session ID.
368 * [MS-SMB2] 3.3.4.1.1
369 */
370 if (sr->smb2_ssnid == 0 || u == NULL)
371 return (0);
372
373 /* In case _sign_begin failed. */
374 if (s->sign_calc == NULL)
375 return (-1);
376
377 /* Get the request signature. */
378 sig_off = sr->smb2_cmd_hdr + SMB2_SIG_OFFS;
379 if (smb_mbc_peek(mbc, sig_off, "#c", SMB2_SIG_SIZE, req_sig) != 0)
380 return (-1);
381
382 /*
383 * Compute the correct signature and compare.
384 * smb2_sign_calc() or smb3_sign_calc()
385 */
386 if (s->sign_calc(sr, mbc, vfy_sig) != 0)
387 return (-1);
388 if (memcmp(vfy_sig, req_sig, SMB2_SIG_SIZE) != 0) {
389 cmn_err(CE_NOTE, "smb2_sign_check_request: bad signature");
390 return (-1);
391 }
392
393 return (0);
394 }
395
396 /*
397 * smb2_sign_reply
398 *
399 * Calculates MAC signature for the given mbuf chain,
400 * and write it to the signature field in the mbuf.
401 *
402 */
403 void
404 smb2_sign_reply(smb_request_t *sr)
405 {
406 uint8_t reply_sig[SMB2_SIG_SIZE];
407 struct mbuf_chain tmp_mbc;
408 smb_session_t *s = sr->session;
409 smb_user_t *u = sr->uid_user;
410 int hdr_off, msg_len;
411
412 if (u == NULL)
413 return;
414 if (s->sign_calc == NULL)
415 return;
416
417 msg_len = sr->reply.chain_offset - sr->smb2_reply_hdr;
418 (void) MBC_SHADOW_CHAIN(&tmp_mbc, &sr->reply,
419 sr->smb2_reply_hdr, msg_len);
420
421 /*
422 * Calculate the MAC signature for this reply.
423 * smb2_sign_calc() or smb3_sign_calc()
424 */
425 if (s->sign_calc(sr, &tmp_mbc, reply_sig) != 0)
426 return;
427
428 /*
429 * Poke the signature into the response.
430 */
431 hdr_off = sr->smb2_reply_hdr + SMB2_SIG_OFFS;
432 (void) smb_mbc_poke(&sr->reply, hdr_off, "#c",
433 SMB2_SIG_SIZE, reply_sig);
434 }