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