Print this page
NEX-16824 SMB client connection setup rework
NEX-17232 SMB client reconnect failures
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Matt Barden <matt.barden@nexenta.com>
and: (improve debug)
SUP-513 Unable to join AD domain (with NtlmMinSeverSec set in the registry)
Implement "Extended Session Security" and "Key Exchange" in NTLMSSP
re #12394 rb3934 Even NULL sessions should use SPNEGO
| Split |
Close |
| Expand all |
| Collapse all |
--- old/usr/src/lib/libsmbfs/smb/ntlm.c
+++ new/usr/src/lib/libsmbfs/smb/ntlm.c
1 1 /*
2 2 * Copyright (c) 2000-2001, Boris Popov
3 3 * All rights reserved.
4 4 *
5 5 * Redistribution and use in source and binary forms, with or without
6 6 * modification, are permitted provided that the following conditions
7 7 * are met:
8 8 * 1. Redistributions of source code must retain the above copyright
9 9 * notice, this list of conditions and the following disclaimer.
10 10 * 2. Redistributions in binary form must reproduce the above copyright
11 11 * notice, this list of conditions and the following disclaimer in the
12 12 * documentation and/or other materials provided with the distribution.
13 13 * 3. All advertising materials mentioning features or use of this software
14 14 * must display the following acknowledgement:
15 15 * This product includes software developed by Boris Popov.
16 16 * 4. Neither the name of the author nor the names of any co-contributors
17 17 * may be used to endorse or promote products derived from this software
18 18 * without specific prior written permission.
19 19 *
20 20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
21 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
24 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
↓ open down ↓ |
26 lines elided |
↑ open up ↑ |
27 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 30 * SUCH DAMAGE.
31 31 *
32 32 * $Id: smb_crypt.c,v 1.13 2005/01/26 23:50:50 lindak Exp $
33 33 */
34 34
35 35 /*
36 36 * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
37 - * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
37 + * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
38 38 */
39 39
40 40 /*
41 41 * NTLM support functions
42 42 *
43 43 * Some code from the driver: smb_smb.c, smb_crypt.c
44 44 */
45 45
46 46 #include <sys/errno.h>
47 47 #include <sys/types.h>
48 48 #include <sys/md4.h>
49 49 #include <sys/md5.h>
50 50
51 51 #include <ctype.h>
52 52 #include <stdlib.h>
53 53 #include <strings.h>
54 54
55 55 #include <netsmb/smb_lib.h>
56 56
57 57 #include "private.h"
58 58 #include "charsets.h"
59 59 #include "smb_crypt.h"
60 60 #include "ntlm.h"
61 61
62 62
63 63 /*
64 64 * ntlm_compute_lm_hash
65 65 *
66 66 * Given a password, compute the LM hash.
67 67 * a.k.a. ResponseKeyLM in [MS-NLMP]
68 68 *
69 69 * Output:
70 70 * hash: 16-byte "LanMan" (LM) hash (normally ctx->ct_lmhash)
71 71 * Inputs:
72 72 * ucpw: User's password, upper-case UTF-8 string.
73 73 *
74 74 * Source: Implementing CIFS (Chris Hertel)
75 75 *
76 76 * P14 = UCPW padded to 14-bytes, or truncated (as needed)
77 77 * result = Encrypt(Key=P14, Data=MagicString)
78 78 */
79 79 int
80 80 ntlm_compute_lm_hash(uchar_t *hash, const char *pass)
81 81 {
82 82 static const uchar_t M8[8] = "KGS!@#$%";
83 83 uchar_t P14[14 + 1];
84 84 int err;
85 85 char *ucpw;
86 86
87 87 /* First, convert the p/w to upper case. */
88 88 ucpw = utf8_str_toupper(pass);
89 89 if (ucpw == NULL)
90 90 return (ENOMEM);
91 91
92 92 /* Pad or truncate the upper-case P/W as needed. */
93 93 bzero(P14, sizeof (P14));
94 94 (void) strncpy((char *)P14, ucpw, 14);
95 95
96 96 /* Compute the hash. */
97 97 err = smb_encrypt_DES(hash, NTLM_HASH_SZ,
98 98 P14, 14, M8, 8);
99 99
100 100 free(ucpw);
101 101 return (err);
102 102 }
103 103
104 104 /*
105 105 * ntlm_compute_nt_hash
106 106 *
107 107 * Given a password, compute the NT hash.
108 108 * a.k.a. the ResponseKeyNT in [MS-NLMP]
109 109 *
110 110 * Output:
111 111 * hash: 16-byte "NT" hash (normally ctx->ct_nthash)
112 112 * Inputs:
113 113 * upw: User's password, mixed-case UCS-2LE.
114 114 * pwlen: Size (in bytes) of upw
115 115 */
116 116 int
117 117 ntlm_compute_nt_hash(uchar_t *hash, const char *pass)
118 118 {
119 119 MD4_CTX ctx;
120 120 uint16_t *unipw = NULL;
121 121 int pwsz;
122 122
123 123 /* First, convert the password to unicode. */
124 124 unipw = convert_utf8_to_leunicode(pass);
125 125 if (unipw == NULL)
126 126 return (ENOMEM);
127 127 pwsz = unicode_strlen(unipw) << 1;
128 128
129 129 /* Compute the hash. */
130 130 MD4Init(&ctx);
131 131 MD4Update(&ctx, unipw, pwsz);
132 132 MD4Final(hash, &ctx);
133 133
134 134 free(unipw);
135 135 return (0);
136 136 }
137 137
138 138 /*
139 139 * ntlm_v1_response
140 140 * a.k.a. DESL() in [MS-NLMP]
141 141 *
142 142 * Create an LM response from the given LM hash and challenge,
143 143 * or an NTLM repsonse from a given NTLM hash and challenge.
144 144 * Both response types are 24 bytes (NTLM_V1_RESP_SZ)
145 145 */
146 146 static int
147 147 ntlm_v1_response(uchar_t *resp,
148 148 const uchar_t *hash,
149 149 const uchar_t *chal, int clen)
150 150 {
151 151 uchar_t S21[21];
152 152 int err;
153 153
154 154 /*
155 155 * 14-byte LM Hash should be padded with 5 nul bytes to create
156 156 * a 21-byte string to be used in producing LM response
157 157 */
158 158 bzero(&S21, sizeof (S21));
159 159 bcopy(hash, S21, NTLM_HASH_SZ);
160 160
161 161 /* padded LM Hash -> LM Response */
162 162 err = smb_encrypt_DES(resp, NTLM_V1_RESP_SZ,
163 163 S21, 21, chal, clen);
164 164 return (err);
165 165 }
166 166
167 167 /*
168 168 * Calculate an NTLMv1 session key (16 bytes).
169 169 */
170 170 static void
171 171 ntlm_v1_session_key(uchar_t *ssn_key, const uchar_t *nt_hash)
172 172 {
173 173 MD4_CTX md4;
174 174
175 175 MD4Init(&md4);
176 176 MD4Update(&md4, nt_hash, NTLM_HASH_SZ);
|
↓ open down ↓ |
129 lines elided |
↑ open up ↑ |
177 177 MD4Final(ssn_key, &md4);
178 178 }
179 179
180 180 /*
181 181 * Compute both the LM(v1) response and the NTLM(v1) response,
182 182 * and put them in the mbdata chains passed. This allocates
183 183 * mbuf chains in the output args, which the caller frees.
184 184 */
185 185 int
186 186 ntlm_put_v1_responses(struct smb_ctx *ctx,
187 - struct mbdata *lm_mbp, struct mbdata *nt_mbp)
187 + struct mbdata *lm_mbp, struct mbdata *nt_mbp,
188 + uchar_t *ssn_key)
188 189 {
189 190 uchar_t *lmresp, *ntresp;
190 191 int err;
191 192
192 193 /* Get mbuf chain for the LM response. */
193 194 if ((err = mb_init_sz(lm_mbp, NTLM_V1_RESP_SZ)) != 0)
194 195 return (err);
195 196
196 197 /* Get mbuf chain for the NT response. */
197 198 if ((err = mb_init_sz(nt_mbp, NTLM_V1_RESP_SZ)) != 0)
198 199 return (err);
199 200
200 201 /*
201 202 * Compute the NTLM response, derived from
202 203 * the challenge and the NT hash (a.k.a ResponseKeyNT)
203 204 */
204 205 err = mb_fit(nt_mbp, NTLM_V1_RESP_SZ, (char **)&ntresp);
205 206 if (err)
206 207 return (err);
207 208 bzero(ntresp, NTLM_V1_RESP_SZ);
208 209 err = ntlm_v1_response(ntresp, ctx->ct_nthash,
209 210 ctx->ct_srv_chal, NTLM_CHAL_SZ);
210 211
211 212 /*
212 213 * Compute the LM response, derived from
213 214 * the challenge and the ASCII password.
214 215 * Per. [MS-NLMP 3.3.1] if NoLmResponse,
215 216 * send the NT response for both NT+LM.
216 217 */
217 218 err = mb_fit(lm_mbp, NTLM_V1_RESP_SZ, (char **)&lmresp);
218 219 if (err)
219 220 return (err);
220 221 memcpy(lmresp, ntresp, NTLM_V1_RESP_SZ);
221 222 if (ctx->ct_authflags & SMB_AT_LM1) {
|
↓ open down ↓ |
24 lines elided |
↑ open up ↑ |
222 223 /* They asked to send the LM hash too. */
223 224 err = ntlm_v1_response(lmresp, ctx->ct_lmhash,
224 225 ctx->ct_srv_chal, NTLM_CHAL_SZ);
225 226 if (err)
226 227 return (err);
227 228 }
228 229
229 230 /*
230 231 * Compute the session key
231 232 */
232 - ntlm_v1_session_key(ctx->ct_ssn_key, ctx->ct_nthash);
233 + ntlm_v1_session_key(ssn_key, ctx->ct_nthash);
233 234
234 235 return (err);
235 236 }
236 237
237 238 /*
238 239 * Compute both the LM(v1x) response and the NTLM(v1x) response,
239 240 * and put them in the mbdata chains passed. "v1x" here refers to
240 241 * NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY used with NTLMSSP,
241 242 * also known by its shorter alias NTLMSSP_NEGOTIATE_NTLM2.
242 243 * [MS-NLMP 3.3.1]
243 244 *
244 245 * This allocates mbuf chains in the output args (caller frees).
245 246 */
246 247 int
247 248 ntlm_put_v1x_responses(struct smb_ctx *ctx,
248 - struct mbdata *lm_mbp, struct mbdata *nt_mbp)
249 + struct mbdata *lm_mbp, struct mbdata *nt_mbp,
250 + uchar_t *ssn_key)
249 251 {
250 252 MD5_CTX context;
251 253 uchar_t challenges[2 * NTLM_CHAL_SZ];
252 254 uchar_t digest[NTLM_HASH_SZ];
253 255 uchar_t *lmresp, *ntresp;
254 256 int err;
255 257
256 258 /* Get mbuf chain for the LM response. */
257 259 if ((err = mb_init_sz(lm_mbp, NTLM_V1_RESP_SZ)) != 0)
258 260 return (err);
259 261
260 262 /* Get mbuf chain for the NT response. */
261 263 if ((err = mb_init_sz(nt_mbp, NTLM_V1_RESP_SZ)) != 0)
262 264 return (err);
263 265
264 266 /*
265 267 * challenges = ConcatenationOf(ServerChallenge, ClientChallenge)
266 268 */
267 269 memcpy(challenges, ctx->ct_srv_chal, NTLM_CHAL_SZ);
268 270 memcpy(challenges + NTLM_CHAL_SZ, ctx->ct_clnonce, NTLM_CHAL_SZ);
269 271
270 272 /*
271 273 * digest = MD5(challenges)
272 274 */
273 275 MD5Init(&context);
274 276 MD5Update(&context, challenges, sizeof (challenges));
275 277 MD5Final(digest, &context);
276 278
277 279 /*
278 280 * Compute the NTLM response, derived from the
279 281 * NT hash (a.k.a ResponseKeyNT) and the first
280 282 * 8 bytes of the MD5 digest of the challenges.
281 283 */
282 284 err = mb_fit(nt_mbp, NTLM_V1_RESP_SZ, (char **)&ntresp);
283 285 if (err)
284 286 return (err);
285 287 bzero(ntresp, NTLM_V1_RESP_SZ);
286 288 err = ntlm_v1_response(ntresp, ctx->ct_nthash,
287 289 digest, NTLM_CHAL_SZ);
288 290
289 291 /*
290 292 * With "Extended Session Security", the LM response
291 293 * is simply the client challenge (nonce) padded out.
|
↓ open down ↓ |
33 lines elided |
↑ open up ↑ |
292 294 */
293 295 err = mb_fit(lm_mbp, NTLM_V1_RESP_SZ, (char **)&lmresp);
294 296 if (err)
295 297 return (err);
296 298 bzero(lmresp, NTLM_V1_RESP_SZ);
297 299 memcpy(lmresp, ctx->ct_clnonce, NTLM_CHAL_SZ);
298 300
299 301 /*
300 302 * Compute the session key
301 303 */
302 - ntlm_v1_session_key(ctx->ct_ssn_key, ctx->ct_nthash);
304 + ntlm_v1_session_key(ssn_key, ctx->ct_nthash);
303 305
304 306 return (err);
305 307 }
306 308
307 309 /*
308 310 * A variation on HMAC-MD5 known as HMACT64 is used by Windows systems.
309 311 * The HMACT64() function is the same as the HMAC-MD5() except that
310 312 * it truncates the input key to 64 bytes rather than hashing it down
311 313 * to 16 bytes using the MD5() function.
312 314 *
313 315 * Output: digest (16-bytes)
314 316 */
315 317 static void
316 318 HMACT64(uchar_t *digest,
317 319 const uchar_t *key, size_t key_len,
318 320 const uchar_t *data, size_t data_len)
319 321 {
320 322 MD5_CTX context;
321 323 uchar_t k_ipad[64]; /* inner padding - key XORd with ipad */
322 324 uchar_t k_opad[64]; /* outer padding - key XORd with opad */
323 325 int i;
324 326
325 327 /* if key is longer than 64 bytes use only the first 64 bytes */
326 328 if (key_len > 64)
327 329 key_len = 64;
328 330
329 331 /*
330 332 * The HMAC-MD5 (and HMACT64) transform looks like:
331 333 *
332 334 * MD5(K XOR opad, MD5(K XOR ipad, data))
333 335 *
334 336 * where K is an n byte key
335 337 * ipad is the byte 0x36 repeated 64 times
336 338 * opad is the byte 0x5c repeated 64 times
337 339 * and data is the data being protected.
338 340 */
339 341
340 342 /* start out by storing key in pads */
341 343 bzero(k_ipad, sizeof (k_ipad));
342 344 bzero(k_opad, sizeof (k_opad));
343 345 bcopy(key, k_ipad, key_len);
344 346 bcopy(key, k_opad, key_len);
345 347
346 348 /* XOR key with ipad and opad values */
347 349 for (i = 0; i < 64; i++) {
348 350 k_ipad[i] ^= 0x36;
349 351 k_opad[i] ^= 0x5c;
350 352 }
351 353
352 354 /*
353 355 * perform inner MD5
354 356 */
355 357 MD5Init(&context); /* init context for 1st pass */
356 358 MD5Update(&context, k_ipad, 64); /* start with inner pad */
357 359 MD5Update(&context, data, data_len); /* then data of datagram */
358 360 MD5Final(digest, &context); /* finish up 1st pass */
359 361
360 362 /*
361 363 * perform outer MD5
362 364 */
363 365 MD5Init(&context); /* init context for 2nd pass */
364 366 MD5Update(&context, k_opad, 64); /* start with outer pad */
365 367 MD5Update(&context, digest, 16); /* then results of 1st hash */
366 368 MD5Final(digest, &context); /* finish up 2nd pass */
367 369 }
368 370
369 371
370 372 /*
371 373 * Compute an NTLMv2 hash given the NTLMv1 hash, the user name,
372 374 * and the destination (machine or domain name).
373 375 *
374 376 * Output:
375 377 * v2hash: 16-byte NTLMv2 hash.
376 378 * Inputs:
377 379 * v1hash: 16-byte NTLMv1 hash.
378 380 * user: User name, UPPER-case UTF-8 string.
379 381 * destination: Domain or server, MIXED-case UTF-8 string.
380 382 */
381 383 static int
382 384 ntlm_v2_hash(uchar_t *v2hash, const uchar_t *v1hash,
383 385 const char *user, const char *destination)
384 386 {
385 387 int ulen, dlen;
386 388 size_t ucs2len;
387 389 uint16_t *ucs2data = NULL;
388 390 char *utf8data = NULL;
389 391 int err = ENOMEM;
390 392
391 393 /*
392 394 * v2hash = HMACT64(v1hash, 16, concat(upcase(user), dest))
393 395 * where "dest" is the domain or server name ("target name")
394 396 * Note: user name is converted to upper-case by the caller.
395 397 */
396 398
397 399 /* utf8data = concat(user, dest) */
398 400 ulen = strlen(user);
399 401 dlen = strlen(destination);
400 402 utf8data = malloc(ulen + dlen + 1);
401 403 if (utf8data == NULL)
402 404 goto out;
403 405 bcopy(user, utf8data, ulen);
404 406 bcopy(destination, utf8data + ulen, dlen + 1);
405 407
406 408 /* Convert to UCS-2LE */
407 409 ucs2data = convert_utf8_to_leunicode(utf8data);
408 410 if (ucs2data == NULL)
409 411 goto out;
410 412 ucs2len = 2 * unicode_strlen(ucs2data);
411 413
412 414 HMACT64(v2hash, v1hash, NTLM_HASH_SZ,
413 415 (uchar_t *)ucs2data, ucs2len);
414 416 err = 0;
415 417 out:
416 418 if (ucs2data)
417 419 free(ucs2data);
418 420 if (utf8data)
419 421 free(utf8data);
420 422 return (err);
421 423 }
422 424
423 425 /*
424 426 * Compute a partial LMv2 or NTLMv2 response (first 16-bytes).
425 427 * The full response is composed by the caller by
426 428 * appending the client_data to the returned hash.
427 429 *
428 430 * Output:
429 431 * rhash: _partial_ LMv2/NTLMv2 response (first 16-bytes)
430 432 * Inputs:
431 433 * v2hash: 16-byte NTLMv2 hash.
432 434 * C8: Challenge from server (8 bytes)
433 435 * client_data: client nonce (for LMv2) or the
434 436 * "blob" from ntlm_build_target_info (NTLMv2)
435 437 */
436 438 static int
437 439 ntlm_v2_resp_hash(uchar_t *rhash,
438 440 const uchar_t *v2hash, const uchar_t *C8,
439 441 const uchar_t *client_data, size_t cdlen)
440 442 {
441 443 size_t dlen;
442 444 uchar_t *data = NULL;
443 445
444 446 /* data = concat(C8, client_data) */
445 447 dlen = 8 + cdlen;
446 448 data = malloc(dlen);
447 449 if (data == NULL)
448 450 return (ENOMEM);
449 451 bcopy(C8, data, 8);
450 452 bcopy(client_data, data + 8, cdlen);
451 453
452 454 HMACT64(rhash, v2hash, NTLM_HASH_SZ, data, dlen);
453 455
454 456 free(data);
455 457 return (0);
456 458 }
457 459
458 460 /*
459 461 * Calculate an NTLMv2 session key (16 bytes).
460 462 */
461 463 static void
462 464 ntlm_v2_session_key(uchar_t *ssn_key,
463 465 const uchar_t *v2hash,
464 466 const uchar_t *ntresp)
465 467 {
466 468
467 469 /* session key uses only 1st 16 bytes of ntresp */
468 470 HMACT64(ssn_key, v2hash, NTLM_HASH_SZ, ntresp, NTLM_HASH_SZ);
469 471 }
|
↓ open down ↓ |
157 lines elided |
↑ open up ↑ |
470 472
471 473
472 474 /*
473 475 * Compute both the LMv2 response and the NTLMv2 response,
474 476 * and put them in the mbdata chains passed. This allocates
475 477 * mbuf chains in the output args, which the caller frees.
476 478 * Also computes the session key.
477 479 */
478 480 int
479 481 ntlm_put_v2_responses(struct smb_ctx *ctx, struct mbdata *ti_mbp,
480 - struct mbdata *lm_mbp, struct mbdata *nt_mbp)
482 + struct mbdata *lm_mbp, struct mbdata *nt_mbp,
483 + uchar_t *ssn_key)
481 484 {
482 485 uchar_t *lmresp, *ntresp;
483 486 int err;
484 487 char *ucuser = NULL; /* upper-case user name */
485 488 uchar_t v2hash[NTLM_HASH_SZ];
486 489 struct mbuf *tim = ti_mbp->mb_top;
487 490
488 491 /*
489 492 * Convert the user name to upper-case, as
490 493 * that's what's used when computing LMv2
491 494 * and NTLMv2 responses. Note that the
492 495 * domain name is NOT upper-cased!
493 496 */
494 497 if (ctx->ct_user[0] == '\0')
495 498 return (EINVAL);
496 499 ucuser = utf8_str_toupper(ctx->ct_user);
497 500 if (ucuser == NULL)
498 501 return (ENOMEM);
499 502
500 503 if ((err = mb_init(lm_mbp)) != 0)
501 504 goto out;
502 505 if ((err = mb_init(nt_mbp)) != 0)
503 506 goto out;
504 507
505 508 /*
506 509 * Compute the NTLMv2 hash
507 510 */
508 511 err = ntlm_v2_hash(v2hash, ctx->ct_nthash,
509 512 ucuser, ctx->ct_domain);
510 513 if (err)
511 514 goto out;
512 515
513 516 /*
514 517 * Compute the LMv2 response, derived from
515 518 * the v2hash, the server challenge, and
516 519 * the client nonce (random bits).
517 520 *
518 521 * We compose it from two parts:
519 522 * 1: 16-byte response hash
520 523 * 2: Client nonce
521 524 */
522 525 lmresp = mb_reserve(lm_mbp, NTLM_HASH_SZ);
523 526 err = ntlm_v2_resp_hash(lmresp,
524 527 v2hash, ctx->ct_srv_chal,
525 528 ctx->ct_clnonce, NTLM_CHAL_SZ);
526 529 if (err)
527 530 goto out;
528 531 mb_put_mem(lm_mbp, ctx->ct_clnonce, NTLM_CHAL_SZ, MB_MSYSTEM);
529 532
530 533 /*
531 534 * Compute the NTLMv2 response, derived
532 535 * from the server challenge and the
533 536 * "target info." blob passed in.
534 537 *
535 538 * Again composed from two parts:
536 539 * 1: 16-byte response hash
537 540 * 2: "target info." blob
538 541 */
539 542 ntresp = mb_reserve(nt_mbp, NTLM_HASH_SZ);
|
↓ open down ↓ |
49 lines elided |
↑ open up ↑ |
540 543 err = ntlm_v2_resp_hash(ntresp,
541 544 v2hash, ctx->ct_srv_chal,
542 545 (uchar_t *)tim->m_data, tim->m_len);
543 546 if (err)
544 547 goto out;
545 548 mb_put_mem(nt_mbp, tim->m_data, tim->m_len, MB_MSYSTEM);
546 549
547 550 /*
548 551 * Compute the session key
549 552 */
550 - ntlm_v2_session_key(ctx->ct_ssn_key, v2hash, ntresp);
553 + ntlm_v2_session_key(ssn_key, v2hash, ntresp);
551 554
552 555 out:
553 556 if (err) {
554 557 mb_done(lm_mbp);
555 558 mb_done(nt_mbp);
556 559 }
557 560 free(ucuser);
558 561
559 562 return (err);
560 563 }
561 564
562 565 /*
563 566 * Helper for ntlm_build_target_info below.
564 567 * Put a name in the NTLMv2 "target info." blob.
565 568 */
566 569 static void
567 570 smb_put_blob_name(struct mbdata *mbp, char *name, int type)
568 571 {
569 572 uint16_t *ucs = NULL;
570 573 int nlen;
571 574
572 575 if (name)
573 576 ucs = convert_utf8_to_leunicode(name);
574 577 if (ucs)
575 578 nlen = unicode_strlen(ucs);
576 579 else
577 580 nlen = 0;
578 581
579 582 nlen <<= 1; /* length in bytes, without null. */
580 583
581 584 mb_put_uint16le(mbp, type);
582 585 mb_put_uint16le(mbp, nlen);
583 586 mb_put_mem(mbp, (char *)ucs, nlen, MB_MSYSTEM);
584 587
585 588 if (ucs)
586 589 free(ucs);
587 590 }
588 591
589 592 /*
590 593 * Build an NTLMv2 "target info." blob. When called from NTLMSSP,
591 594 * the list of names comes from the Type 2 message. Otherwise,
592 595 * we create the name list here.
593 596 */
594 597 int
595 598 ntlm_build_target_info(struct smb_ctx *ctx, struct mbuf *names,
596 599 struct mbdata *mbp)
597 600 {
598 601 struct timeval now;
599 602 uint64_t nt_time;
600 603
601 604 char *ucdom = NULL; /* user's domain */
602 605 int err;
603 606
604 607 /* Get mbuf chain for the "target info". */
605 608 if ((err = mb_init(mbp)) != 0)
606 609 return (err);
607 610
608 611 /*
609 612 * Get the "NT time" for the target info header.
610 613 */
611 614 (void) gettimeofday(&now, 0);
612 615 smb_time_local2NT(&now, 0, &nt_time);
613 616
614 617 /*
615 618 * Build the "target info." block.
616 619 *
617 620 * Based on information at:
618 621 * http://davenport.sourceforge.net/ntlm.html#theNtlmv2Response
619 622 *
620 623 * First the fixed-size part.
621 624 */
622 625 mb_put_uint32le(mbp, 0x101); /* Blob signature */
623 626 mb_put_uint32le(mbp, 0); /* reserved */
624 627 mb_put_uint64le(mbp, nt_time); /* NT time stamp */
625 628 mb_put_mem(mbp, ctx->ct_clnonce, NTLM_CHAL_SZ, MB_MSYSTEM);
626 629 mb_put_uint32le(mbp, 0); /* unknown */
627 630
628 631 /*
629 632 * Now put the list of names, either from the
630 633 * NTLMSSP Type 2 message or composed here.
631 634 */
632 635 if (names) {
633 636 err = mb_put_mem(mbp, names->m_data, names->m_len, MB_MSYSTEM);
634 637 } else {
635 638 /* Get upper-case names. */
636 639 ucdom = utf8_str_toupper(ctx->ct_domain);
637 640 if (ucdom == NULL) {
638 641 err = ENOMEM;
639 642 goto out;
640 643 }
641 644 smb_put_blob_name(mbp, ucdom, NAMETYPE_DOMAIN_NB);
642 645 smb_put_blob_name(mbp, NULL, NAMETYPE_EOL);
|
↓ open down ↓ |
82 lines elided |
↑ open up ↑ |
643 646 /* OK, that's the whole "target info." blob! */
644 647 }
645 648 err = 0;
646 649
647 650 out:
648 651 free(ucdom);
649 652 return (err);
650 653 }
651 654
652 655 /*
653 - * Build the MAC key (for SMB signing)
654 - */
655 -int
656 -ntlm_build_mac_key(struct smb_ctx *ctx, struct mbdata *ntresp_mbp)
657 -{
658 - struct mbuf *m;
659 - size_t len;
660 - char *p;
661 -
662 - /*
663 - * MAC_key = concat(session_key, nt_response)
664 - */
665 - m = ntresp_mbp->mb_top;
666 - len = NTLM_HASH_SZ + m->m_len;
667 - if ((p = malloc(len)) == NULL)
668 - return (ENOMEM);
669 - ctx->ct_mackeylen = len;
670 - ctx->ct_mackey = p;
671 - memcpy(p, ctx->ct_ssn_key, NTLM_HASH_SZ);
672 - memcpy(p + NTLM_HASH_SZ, m->m_data, m->m_len);
673 -
674 - return (0);
675 -}
676 -
677 -/*
678 656 * Helper for ntlmssp_put_type3 - Build the "key exchange key"
679 657 * used when we have both NTLM(v1) and NTLMSSP_NEGOTIATE_NTLM2.
680 658 * HMAC_MD5(SessionBaseKey, concat(ServerChallenge, LmResponse[0..7]))
681 659 */
682 660 void
683 -ntlm2_kxkey(struct smb_ctx *ctx, struct mbdata *lm_mbp, uchar_t *kxkey)
661 +ntlm2_kxkey(struct smb_ctx *ctx, struct mbdata *lm_mbp,
662 + uchar_t *ssn_key, uchar_t *kxkey)
684 663 {
685 664 uchar_t data[NTLM_HASH_SZ];
686 665 uchar_t *p = mtod(lm_mbp->mb_top, uchar_t *);
687 666
688 667 /* concat(ServerChallenge, LmResponse[0..7]) */
689 668 memcpy(data, ctx->ct_srv_chal, NTLM_CHAL_SZ);
690 669 memcpy(data + NTLM_CHAL_SZ, p, NTLM_CHAL_SZ);
691 670
692 671 /* HMAC_MD5(SessionBaseKey, concat(...)) */
693 - HMACT64(kxkey, ctx->ct_ssn_key, NTLM_HASH_SZ,
672 + HMACT64(kxkey, ssn_key, NTLM_HASH_SZ,
694 673 data, NTLM_HASH_SZ);
695 674 }
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX