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