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
  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
 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
 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
 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
 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
 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
 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
 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
 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
 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
 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
 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
 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
 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
 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 }