Print this page
NEX-10231 SMB logon fails in fksmbd
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Gordon Ross <gordon.ross@nexenta.com>
NEX-5273 SMB 3 Encryption
Reviewed by: Gordon Ross <gordon.ross@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Roman Strashkin <roman.strashkin@nexenta.com>
NEX-3728 SMB1 signing should use KCF like SMB2/3
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Dan Fields <dan.fields@nexenta.com>
NEX-3610 CLONE NEX-3591 SMB3 signing
Reviewed by: Gordon Ross <gwr@nexenta.com>
Reviewed by: Dan Fields <dan.fields@nexenta.com>
NEX-3080 SMB1 signing problem with Kerberos auth.
Reviewed by: Bayard Bell <bayard.bell@nexenta.com>
Reviewed by: Dan Fields <dan.fields@nexenta.com>
Reviewed by: Kevin Crowe <kevin.crowe@nexenta.com>
Reviewed by: Matt Barden <Matt.Barden@nexenta.com>
SMB-55 SMB2 signing
SMB-56 extended security NTLMSSP, inbound
SMB-50 User-mode SMB server
Includes work by these authors:
Thomas Keiser <thomas.keiser@nexenta.com>
Albert Lee <trisk@nexenta.com>
SMB-65 SMB server in non-global zones (kmem_caches)
common kmem_cache instances across zones
separate GZ-only init from NGZ init
| Split |
Close |
| Expand all |
| Collapse all |
--- old/usr/src/uts/common/fs/smbsrv/smb_signing.c
+++ new/usr/src/uts/common/fs/smbsrv/smb_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 *
|
↓ open down ↓ |
12 lines elided |
↑ open up ↑ |
13 13 * When distributing Covered Code, include this CDDL HEADER in each
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 - * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
23 + * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
24 24 */
25 25 /*
26 26 * These routines provide the SMB MAC signing for the SMB server.
27 27 * The routines calculate the signature of a SMB message in an mbuf chain.
28 28 *
29 29 * The following table describes the client server
30 30 * signing registry relationship
31 31 *
32 32 * | Required | Enabled | Disabled
33 33 * -------------+---------------+------------ +--------------
34 34 * Required | Signed | Signed | Fail
35 35 * -------------+---------------+-------------+-----------------
36 36 * Enabled | Signed | Signed | Not Signed
37 37 * -------------+---------------+-------------+----------------
38 38 * Disabled | Fail | Not Signed | Not Signed
39 39 */
40 40
41 41 #include <sys/uio.h>
42 42 #include <smbsrv/smb_kproto.h>
43 -#include <smbsrv/smb_signing.h>
43 +#include <smbsrv/smb_kcrypt.h>
44 44 #include <sys/isa_defs.h>
45 45 #include <sys/byteorder.h>
46 46
47 47 #define SMB_SIG_SIZE 8
48 48 #define SMB_SIG_OFFS 14
49 49 #define SMB_HDRLEN 32
50 50
51 51 #ifdef _LITTLE_ENDIAN
52 52 #define htolel(x) ((uint32_t)(x))
53 53 #else
54 54 #define htolel(x) BSWAP_32(x)
55 55 #endif
56 56
57 57 static int
58 58 smb_sign_calc(smb_request_t *sr, struct mbuf_chain *mbc,
59 59 uint32_t seqnum, unsigned char *sig);
60 60
61 61 #ifdef DEBUG
62 62 uint32_t smb_sign_debug_search = 10;
63 63
64 64 /*
65 65 * Debug code to search +/- for the correct sequence number.
66 66 * If found, correct sign->seqnum and return 0, else return -1
67 67 */
68 68 static int
69 69 smb_sign_find_seqnum(
70 70 smb_request_t *sr,
71 71 struct mbuf_chain *mbc,
72 72 unsigned char *mac_sig,
73 73 unsigned char *sr_sig)
74 74 {
75 75 struct smb_sign *sign = &sr->session->signing;
76 76 uint32_t i, t;
77 77
78 78 for (i = 1; i < smb_sign_debug_search; i++) {
79 79 t = sr->sr_seqnum + i;
80 80 (void) smb_sign_calc(sr, mbc, t, mac_sig);
81 81 if (memcmp(mac_sig, sr_sig, SMB_SIG_SIZE) == 0) {
82 82 goto found;
83 83 }
84 84 t = sr->sr_seqnum - i;
85 85 (void) smb_sign_calc(sr, mbc, t, mac_sig);
86 86 if (memcmp(mac_sig, sr_sig, SMB_SIG_SIZE) == 0) {
87 87 goto found;
88 88 }
89 89 }
90 90 cmn_err(CE_WARN, "smb_sign_find_seqnum: failed after %d", i);
91 91 return (-1);
92 92
93 93 found:
94 94 cmn_err(CE_WARN, "smb_sign_find_seqnum: found! %d <- %d",
95 95 sign->seqnum, t);
96 96 sign->seqnum = t;
|
↓ open down ↓ |
43 lines elided |
↑ open up ↑ |
97 97 return (0);
98 98 }
99 99 #endif
100 100
101 101 /*
102 102 * Called during session destroy.
103 103 */
104 104 static void
105 105 smb_sign_fini(smb_session_t *s)
106 106 {
107 - smb_sign_mech_t *mech;
107 + smb_crypto_mech_t *mech;
108 108
109 109 if ((mech = s->sign_mech) != NULL) {
110 110 kmem_free(mech, sizeof (*mech));
111 111 s->sign_mech = NULL;
112 112 }
113 113 }
114 114
115 115 /*
116 116 * smb_sign_begin
117 117 *
118 118 * Intializes MAC key based on the user session key and
119 119 * NTLM response and store it in the signing structure.
120 120 * This is what begins SMB signing.
121 121 */
122 -int
122 +void
123 123 smb_sign_begin(smb_request_t *sr, smb_token_t *token)
124 124 {
125 125 smb_arg_sessionsetup_t *sinfo = sr->sr_ssetup;
126 126 smb_session_t *session = sr->session;
127 127 struct smb_sign *sign = &session->signing;
128 - smb_sign_mech_t *mech;
128 + smb_crypto_mech_t *mech;
129 129 int rc;
130 130
131 131 /*
132 132 * We should normally have a session key here because
133 133 * our caller filters out Anonymous and Guest logons.
134 134 * However, buggy clients could get us here without a
135 135 * session key, in which case: just don't sign.
136 136 */
137 137 if (token->tkn_ssnkey.val == NULL || token->tkn_ssnkey.len == 0)
138 - return (0);
138 + return;
139 139
140 140 /*
141 141 * Session-level initialization (once per session)
142 142 */
143 143 smb_rwx_rwenter(&session->s_lock, RW_WRITER);
144 144
145 145 /*
146 146 * Signing may already have been setup by a prior logon,
147 147 * in which case we're done here.
148 148 */
149 149 if (sign->mackey != NULL) {
150 150 smb_rwx_rwexit(&session->s_lock);
151 - return (0);
151 + return;
152 152 }
153 153
154 154 /*
155 155 * Get the mech handle
156 156 */
157 157 if (session->sign_mech == NULL) {
158 158 mech = kmem_zalloc(sizeof (*mech), KM_SLEEP);
159 159 rc = smb_md5_getmech(mech);
160 160 if (rc != 0) {
161 161 kmem_free(mech, sizeof (*mech));
162 162 smb_rwx_rwexit(&session->s_lock);
163 - return (rc);
163 + return;
164 164 }
165 165 session->sign_mech = mech;
166 166 session->sign_fini = smb_sign_fini;
167 167 }
168 168
169 169 /*
170 170 * Compute and store the signing (MAC) key.
171 171 *
172 172 * With extended security, the MAC key is the same as the
173 173 * session key (and we'll have sinfo->ssi_ntpwlen == 0).
174 174 * With non-extended security, it's the concatenation of
175 175 * the session key and the "NT response" we received.
176 176 */
177 177 sign->mackey_len = token->tkn_ssnkey.len + sinfo->ssi_ntpwlen;
178 178 sign->mackey = kmem_alloc(sign->mackey_len, KM_SLEEP);
179 179 bcopy(token->tkn_ssnkey.val, sign->mackey, token->tkn_ssnkey.len);
|
↓ open down ↓ |
6 lines elided |
↑ open up ↑ |
180 180 if (sinfo->ssi_ntpwlen > 0) {
181 181 bcopy(sinfo->ssi_ntpwd, sign->mackey + token->tkn_ssnkey.len,
182 182 sinfo->ssi_ntpwlen);
183 183 }
184 184
185 185 session->signing.seqnum = 0;
186 186 sr->sr_seqnum = 2;
187 187 sr->reply_seqnum = 1;
188 188 sign->flags = 0;
189 189
190 - if (session->secmode & NEGOTIATE_SECURITY_SIGNATURES_ENABLED) {
190 + if (session->srv_secmode & NEGOTIATE_SECURITY_SIGNATURES_ENABLED) {
191 191 sign->flags |= SMB_SIGNING_ENABLED;
192 - if (session->secmode & NEGOTIATE_SECURITY_SIGNATURES_REQUIRED)
192 + if (session->srv_secmode &
193 + NEGOTIATE_SECURITY_SIGNATURES_REQUIRED)
193 194 sign->flags |= SMB_SIGNING_CHECK;
194 195 }
195 196
196 197 smb_rwx_rwexit(&session->s_lock);
197 - return (0);
198 198 }
199 199
200 200 /*
201 201 * smb_sign_calc
202 202 *
203 203 * Calculates MAC signature for the given buffer and returns
204 204 * it in the mac_sign parameter.
205 205 *
206 206 * The sequence number is placed in the first four bytes of the signature
207 207 * field of the signature and the other 4 bytes are zeroed.
208 208 * The signature is the first 8 bytes of the MD5 result of the
209 209 * concatenated MAC key and the SMB message.
210 210 *
211 211 * MACsig = head(MD5(concat(MACKey, SMBMsg)), 8)
212 212 *
213 213 * where
214 214 *
215 215 * MACKey = concat( UserSessionKey, NTLMResp )
216 216 *
217 217 * and
218 218 *
219 219 * SMBMsg is the SMB message containing the sequence number.
220 220 *
221 221 * Return 0 if success
222 222 *
223 223 */
224 224 static int
225 225 smb_sign_calc(smb_request_t *sr, struct mbuf_chain *mbc,
226 226 uint32_t seqnum, unsigned char *mac_sign)
227 227 {
228 228 smb_session_t *s = sr->session;
229 229 struct smb_sign *sign = &s->signing;
230 230 smb_sign_ctx_t ctx = 0;
231 231 uchar_t digest[MD5_DIGEST_LENGTH];
232 232 uchar_t *hdrp;
233 233 struct mbuf *mbuf = mbc->chain;
234 234 int offset = mbc->chain_offset;
235 235 int size;
236 236 int rc;
237 237
238 238 /*
239 239 * This union is a little bit of trickery to:
240 240 * (1) get the sequence number int aligned, and
241 241 * (2) reduce the number of digest calls, at the
242 242 * cost of a copying 32 bytes instead of 8.
243 243 * Both sides of this union are 2+32 bytes.
244 244 */
245 245 union {
246 246 struct {
247 247 uint8_t skip[2]; /* not used - just alignment */
248 248 uint8_t raw[SMB_HDRLEN]; /* header length (32) */
249 249 } r;
250 250 struct {
251 251 uint8_t skip[2]; /* not used - just alignment */
252 252 uint8_t hdr[SMB_SIG_OFFS]; /* sig. offset (14) */
253 253 uint32_t sig[2]; /* MAC signature, aligned! */
254 254 uint16_t ids[5]; /* pad, Tid, Pid, Uid, Mid */
255 255 } s;
256 256 } smbhdr;
257 257
258 258 if (s->sign_mech == NULL || sign->mackey == NULL)
259 259 return (-1);
260 260
261 261 if ((rc = smb_md5_init(&ctx, s->sign_mech)) != 0)
262 262 return (rc);
263 263
264 264 /* Digest the MAC Key */
265 265 rc = smb_md5_update(ctx, sign->mackey, sign->mackey_len);
266 266 if (rc != 0)
267 267 return (rc);
268 268
269 269 /*
270 270 * Make an aligned copy of the SMB header,
271 271 * fill in the sequence number, and digest.
272 272 */
273 273 hdrp = (unsigned char *)&smbhdr.r.raw;
274 274 size = SMB_HDRLEN;
275 275 if (smb_mbc_peek(mbc, offset, "#c", size, hdrp) != 0)
276 276 return (-1);
277 277 smbhdr.s.sig[0] = htolel(seqnum);
278 278 smbhdr.s.sig[1] = 0;
279 279
280 280 rc = smb_md5_update(ctx, &smbhdr.r.raw, size);
281 281 if (rc != 0)
282 282 return (rc);
283 283
284 284 /*
285 285 * Digest the rest of the SMB packet, starting at the data
286 286 * just after the SMB header.
287 287 */
288 288 offset += size;
289 289 while (mbuf != NULL && (offset >= mbuf->m_len)) {
290 290 offset -= mbuf->m_len;
291 291 mbuf = mbuf->m_next;
292 292 }
293 293 if (mbuf != NULL && (size = (mbuf->m_len - offset)) > 0) {
294 294 rc = smb_md5_update(ctx, &mbuf->m_data[offset], size);
295 295 if (rc != 0)
296 296 return (rc);
297 297 offset = 0;
298 298 mbuf = mbuf->m_next;
299 299 }
300 300 while (mbuf != NULL) {
301 301 rc = smb_md5_update(ctx, mbuf->m_data, mbuf->m_len);
302 302 if (rc != 0)
303 303 return (rc);
304 304 mbuf = mbuf->m_next;
305 305 }
306 306 rc = smb_md5_final(ctx, digest);
307 307 if (rc == 0)
308 308 bcopy(digest, mac_sign, SMB_SIG_SIZE);
309 309
310 310 return (rc);
311 311 }
312 312
313 313
314 314 /*
315 315 * smb_sign_check_request
316 316 *
317 317 * Calculates MAC signature for the request mbuf chain
318 318 * using the next expected sequence number and compares
319 319 * it to the given signature.
320 320 *
321 321 * Note it does not check the signature for secondary transactions
322 322 * as their sequence number is the same as the original request.
323 323 *
324 324 * Return 0 if the signature verifies, otherwise, returns -1;
325 325 *
326 326 */
327 327 int
328 328 smb_sign_check_request(smb_request_t *sr)
329 329 {
330 330 struct mbuf_chain mbc = sr->command;
331 331 unsigned char mac_sig[SMB_SIG_SIZE];
332 332
333 333 /*
334 334 * Don't check secondary transactions - we dont know the sequence
335 335 * number.
336 336 */
337 337 if (sr->smb_com == SMB_COM_TRANSACTION_SECONDARY ||
338 338 sr->smb_com == SMB_COM_TRANSACTION2_SECONDARY ||
339 339 sr->smb_com == SMB_COM_NT_TRANSACT_SECONDARY)
340 340 return (0);
341 341
342 342 /* Reset the offset to begining of header */
343 343 mbc.chain_offset = sr->orig_request_hdr;
344 344
345 345 /* calculate mac signature */
346 346 if (smb_sign_calc(sr, &mbc, sr->sr_seqnum, mac_sig) != 0)
347 347 return (-1);
348 348
349 349 /* compare the signatures */
350 350 if (memcmp(mac_sig, sr->smb_sig, SMB_SIG_SIZE) == 0) {
351 351 /* They match! OK, we're done. */
352 352 return (0);
353 353 }
354 354
355 355 DTRACE_PROBE2(smb__signature__mismatch, smb_request_t, sr,
356 356 unsigned char *, mac_sig);
357 357 cmn_err(CE_NOTE, "smb_sign_check_request: bad signature");
358 358
359 359 /*
360 360 * check nearby sequence numbers in debug mode
361 361 */
362 362 #ifdef DEBUG
363 363 if (smb_sign_debug) {
364 364 return (smb_sign_find_seqnum(sr, &mbc, mac_sig, sr->smb_sig));
365 365 }
366 366 #endif
367 367 return (-1);
368 368 }
369 369
370 370 /*
371 371 * smb_sign_check_secondary
372 372 *
373 373 * Calculates MAC signature for the secondary transaction mbuf chain
374 374 * and compares it to the given signature.
375 375 * Return 0 if the signature verifies, otherwise, returns -1;
376 376 *
377 377 */
378 378 int
379 379 smb_sign_check_secondary(smb_request_t *sr, unsigned int reply_seqnum)
380 380 {
381 381 struct mbuf_chain mbc = sr->command;
382 382 unsigned char mac_sig[SMB_SIG_SIZE];
383 383 int rtn = 0;
384 384
385 385 /* Reset the offset to begining of header */
386 386 mbc.chain_offset = sr->orig_request_hdr;
387 387
388 388 /* calculate mac signature */
389 389 if (smb_sign_calc(sr, &mbc, reply_seqnum - 1, mac_sig) != 0)
390 390 return (-1);
391 391
392 392
393 393 /* compare the signatures */
394 394 if (memcmp(mac_sig, sr->smb_sig, SMB_SIG_SIZE) != 0) {
395 395 cmn_err(CE_WARN, "SmbSignCheckSecond: bad signature");
396 396 rtn = -1;
397 397 }
398 398 /* Save the reply sequence number */
399 399 sr->reply_seqnum = reply_seqnum;
400 400
401 401 return (rtn);
402 402 }
403 403
404 404 /*
405 405 * smb_sign_reply
406 406 *
407 407 * Calculates MAC signature for the given mbuf chain,
408 408 * and write it to the signature field in the mbuf.
409 409 *
410 410 */
411 411 void
412 412 smb_sign_reply(smb_request_t *sr, struct mbuf_chain *reply)
413 413 {
414 414 struct mbuf_chain mbc;
415 415 unsigned char mac[SMB_SIG_SIZE];
416 416
417 417 if (reply)
418 418 mbc = *reply;
419 419 else
420 420 mbc = sr->reply;
421 421
422 422 /* Reset offset to start of reply */
423 423 mbc.chain_offset = 0;
424 424
425 425 /*
426 426 * Calculate MAC signature
427 427 */
428 428 if (smb_sign_calc(sr, &mbc, sr->reply_seqnum, mac) != 0) {
429 429 cmn_err(CE_WARN, "smb_sign_reply: error in smb_sign_calc");
430 430 return;
431 431 }
432 432
433 433 /*
434 434 * Put signature in the response
435 435 */
436 436 (void) smb_mbc_poke(&mbc, SMB_SIG_OFFS, "#c",
437 437 SMB_SIG_SIZE, mac);
438 438 }
|
↓ open down ↓ |
231 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX