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 2018 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         uchar_t *ssn_key)
 189 {
 190         uchar_t *lmresp, *ntresp;
 191         int err;
 192 
 193         /* Get mbuf chain for the LM response. */
 194         if ((err = mb_init_sz(lm_mbp, NTLM_V1_RESP_SZ)) != 0)
 195                 return (err);
 196 
 197         /* Get mbuf chain for the NT response. */
 198         if ((err = mb_init_sz(nt_mbp, NTLM_V1_RESP_SZ)) != 0)
 199                 return (err);
 200 
 201         /*
 202          * Compute the NTLM response, derived from
 203          * the challenge and the NT hash (a.k.a ResponseKeyNT)
 204          */
 205         err = mb_fit(nt_mbp, NTLM_V1_RESP_SZ, (char **)&ntresp);
 206         if (err)
 207                 return (err);
 208         bzero(ntresp, NTLM_V1_RESP_SZ);
 209         err = ntlm_v1_response(ntresp, ctx->ct_nthash,
 210             ctx->ct_srv_chal, NTLM_CHAL_SZ);
 211 
 212         /*
 213          * Compute the LM response, derived from
 214          * the challenge and the ASCII password.
 215          * Per. [MS-NLMP 3.3.1] if NoLmResponse,
 216          * send the NT response for both NT+LM.
 217          */
 218         err = mb_fit(lm_mbp, NTLM_V1_RESP_SZ, (char **)&lmresp);
 219         if (err)
 220                 return (err);
 221         memcpy(lmresp, ntresp, NTLM_V1_RESP_SZ);
 222         if (ctx->ct_authflags & SMB_AT_LM1) {
 223                 /* They asked to send the LM hash too. */
 224                 err = ntlm_v1_response(lmresp, ctx->ct_lmhash,
 225                     ctx->ct_srv_chal, NTLM_CHAL_SZ);
 226                 if (err)
 227                         return (err);
 228         }
 229 
 230         /*
 231          * Compute the session key
 232          */
 233         ntlm_v1_session_key(ssn_key, ctx->ct_nthash);
 234 
 235         return (err);
 236 }
 237 
 238 /*
 239  * Compute both the LM(v1x) response and the NTLM(v1x) response,
 240  * and put them in the mbdata chains passed.  "v1x" here refers to
 241  * NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY used with NTLMSSP,
 242  * also known by its shorter alias NTLMSSP_NEGOTIATE_NTLM2.
 243  * [MS-NLMP 3.3.1]
 244  *
 245  * This allocates mbuf chains in the output args (caller frees).
 246  */
 247 int
 248 ntlm_put_v1x_responses(struct smb_ctx *ctx,
 249         struct mbdata *lm_mbp, struct mbdata *nt_mbp,
 250         uchar_t *ssn_key)
 251 {
 252         MD5_CTX context;
 253         uchar_t challenges[2 * NTLM_CHAL_SZ];
 254         uchar_t digest[NTLM_HASH_SZ];
 255         uchar_t *lmresp, *ntresp;
 256         int err;
 257 
 258         /* Get mbuf chain for the LM response. */
 259         if ((err = mb_init_sz(lm_mbp, NTLM_V1_RESP_SZ)) != 0)
 260                 return (err);
 261 
 262         /* Get mbuf chain for the NT response. */
 263         if ((err = mb_init_sz(nt_mbp, NTLM_V1_RESP_SZ)) != 0)
 264                 return (err);
 265 
 266         /*
 267          * challenges = ConcatenationOf(ServerChallenge, ClientChallenge)
 268          */
 269         memcpy(challenges, ctx->ct_srv_chal, NTLM_CHAL_SZ);
 270         memcpy(challenges + NTLM_CHAL_SZ, ctx->ct_clnonce, NTLM_CHAL_SZ);
 271 
 272         /*
 273          * digest = MD5(challenges)
 274          */
 275         MD5Init(&context);
 276         MD5Update(&context, challenges, sizeof (challenges));
 277         MD5Final(digest, &context);
 278 
 279         /*
 280          * Compute the NTLM response, derived from the
 281          * NT hash (a.k.a ResponseKeyNT) and the first
 282          * 8 bytes of the MD5 digest of the challenges.
 283          */
 284         err = mb_fit(nt_mbp, NTLM_V1_RESP_SZ, (char **)&ntresp);
 285         if (err)
 286                 return (err);
 287         bzero(ntresp, NTLM_V1_RESP_SZ);
 288         err = ntlm_v1_response(ntresp, ctx->ct_nthash,
 289             digest, NTLM_CHAL_SZ);
 290 
 291         /*
 292          * With "Extended Session Security", the LM response
 293          * is simply the client challenge (nonce) padded out.
 294          */
 295         err = mb_fit(lm_mbp, NTLM_V1_RESP_SZ, (char **)&lmresp);
 296         if (err)
 297                 return (err);
 298         bzero(lmresp, NTLM_V1_RESP_SZ);
 299         memcpy(lmresp, ctx->ct_clnonce, NTLM_CHAL_SZ);
 300 
 301         /*
 302          * Compute the session key
 303          */
 304         ntlm_v1_session_key(ssn_key, ctx->ct_nthash);
 305 
 306         return (err);
 307 }
 308 
 309 /*
 310  * A variation on HMAC-MD5 known as HMACT64 is used by Windows systems.
 311  * The HMACT64() function is the same as the HMAC-MD5() except that
 312  * it truncates the input key to 64 bytes rather than hashing it down
 313  * to 16 bytes using the MD5() function.
 314  *
 315  * Output: digest (16-bytes)
 316  */
 317 static void
 318 HMACT64(uchar_t *digest,
 319     const uchar_t *key, size_t key_len,
 320     const uchar_t *data, size_t data_len)
 321 {
 322         MD5_CTX context;
 323         uchar_t k_ipad[64];     /* inner padding - key XORd with ipad */
 324         uchar_t k_opad[64];     /* outer padding - key XORd with opad */
 325         int i;
 326 
 327         /* if key is longer than 64 bytes use only the first 64 bytes */
 328         if (key_len > 64)
 329                 key_len = 64;
 330 
 331         /*
 332          * The HMAC-MD5 (and HMACT64) transform looks like:
 333          *
 334          * MD5(K XOR opad, MD5(K XOR ipad, data))
 335          *
 336          * where K is an n byte key
 337          * ipad is the byte 0x36 repeated 64 times
 338          * opad is the byte 0x5c repeated 64 times
 339          * and data is the data being protected.
 340          */
 341 
 342         /* start out by storing key in pads */
 343         bzero(k_ipad, sizeof (k_ipad));
 344         bzero(k_opad, sizeof (k_opad));
 345         bcopy(key, k_ipad, key_len);
 346         bcopy(key, k_opad, key_len);
 347 
 348         /* XOR key with ipad and opad values */
 349         for (i = 0; i < 64; i++) {
 350                 k_ipad[i] ^= 0x36;
 351                 k_opad[i] ^= 0x5c;
 352         }
 353 
 354         /*
 355          * perform inner MD5
 356          */
 357         MD5Init(&context);                  /* init context for 1st pass */
 358         MD5Update(&context, k_ipad, 64);    /* start with inner pad */
 359         MD5Update(&context, data, data_len);        /* then data of datagram */
 360         MD5Final(digest, &context);         /* finish up 1st pass */
 361 
 362         /*
 363          * perform outer MD5
 364          */
 365         MD5Init(&context);                  /* init context for 2nd pass */
 366         MD5Update(&context, k_opad, 64);    /* start with outer pad */
 367         MD5Update(&context, digest, 16);    /* then results of 1st hash */
 368         MD5Final(digest, &context);         /* finish up 2nd pass */
 369 }
 370 
 371 
 372 /*
 373  * Compute an NTLMv2 hash given the NTLMv1 hash, the user name,
 374  * and the destination (machine or domain name).
 375  *
 376  * Output:
 377  *      v2hash: 16-byte NTLMv2 hash.
 378  * Inputs:
 379  *      v1hash: 16-byte NTLMv1 hash.
 380  *      user: User name, UPPER-case UTF-8 string.
 381  *      destination: Domain or server, MIXED-case UTF-8 string.
 382  */
 383 static int
 384 ntlm_v2_hash(uchar_t *v2hash, const uchar_t *v1hash,
 385     const char *user, const char *destination)
 386 {
 387         int ulen, dlen;
 388         size_t ucs2len;
 389         uint16_t *ucs2data = NULL;
 390         char *utf8data = NULL;
 391         int err = ENOMEM;
 392 
 393         /*
 394          * v2hash = HMACT64(v1hash, 16, concat(upcase(user), dest))
 395          * where "dest" is the domain or server name ("target name")
 396          * Note: user name is converted to upper-case by the caller.
 397          */
 398 
 399         /* utf8data = concat(user, dest) */
 400         ulen = strlen(user);
 401         dlen = strlen(destination);
 402         utf8data = malloc(ulen + dlen + 1);
 403         if (utf8data == NULL)
 404                 goto out;
 405         bcopy(user, utf8data, ulen);
 406         bcopy(destination, utf8data + ulen, dlen + 1);
 407 
 408         /* Convert to UCS-2LE */
 409         ucs2data = convert_utf8_to_leunicode(utf8data);
 410         if (ucs2data == NULL)
 411                 goto out;
 412         ucs2len = 2 * unicode_strlen(ucs2data);
 413 
 414         HMACT64(v2hash, v1hash, NTLM_HASH_SZ,
 415             (uchar_t *)ucs2data, ucs2len);
 416         err = 0;
 417 out:
 418         if (ucs2data)
 419                 free(ucs2data);
 420         if (utf8data)
 421                 free(utf8data);
 422         return (err);
 423 }
 424 
 425 /*
 426  * Compute a partial LMv2 or NTLMv2 response (first 16-bytes).
 427  * The full response is composed by the caller by
 428  * appending the client_data to the returned hash.
 429  *
 430  * Output:
 431  *      rhash: _partial_ LMv2/NTLMv2 response (first 16-bytes)
 432  * Inputs:
 433  *      v2hash: 16-byte NTLMv2 hash.
 434  *      C8: Challenge from server (8 bytes)
 435  *      client_data: client nonce (for LMv2) or the
 436  *        "blob" from ntlm_build_target_info (NTLMv2)
 437  */
 438 static int
 439 ntlm_v2_resp_hash(uchar_t *rhash,
 440     const uchar_t *v2hash, const uchar_t *C8,
 441     const uchar_t *client_data, size_t cdlen)
 442 {
 443         size_t dlen;
 444         uchar_t *data = NULL;
 445 
 446         /* data = concat(C8, client_data) */
 447         dlen = 8 + cdlen;
 448         data = malloc(dlen);
 449         if (data == NULL)
 450                 return (ENOMEM);
 451         bcopy(C8, data, 8);
 452         bcopy(client_data, data + 8, cdlen);
 453 
 454         HMACT64(rhash, v2hash, NTLM_HASH_SZ, data, dlen);
 455 
 456         free(data);
 457         return (0);
 458 }
 459 
 460 /*
 461  * Calculate an NTLMv2 session key (16 bytes).
 462  */
 463 static void
 464 ntlm_v2_session_key(uchar_t *ssn_key,
 465         const uchar_t *v2hash,
 466         const uchar_t *ntresp)
 467 {
 468 
 469         /* session key uses only 1st 16 bytes of ntresp */
 470         HMACT64(ssn_key, v2hash, NTLM_HASH_SZ, ntresp, NTLM_HASH_SZ);
 471 }
 472 
 473 
 474 /*
 475  * Compute both the LMv2 response and the NTLMv2 response,
 476  * and put them in the mbdata chains passed.  This allocates
 477  * mbuf chains in the output args, which the caller frees.
 478  * Also computes the session key.
 479  */
 480 int
 481 ntlm_put_v2_responses(struct smb_ctx *ctx, struct mbdata *ti_mbp,
 482         struct mbdata *lm_mbp, struct mbdata *nt_mbp,
 483         uchar_t *ssn_key)
 484 {
 485         uchar_t *lmresp, *ntresp;
 486         int err;
 487         char *ucuser = NULL;    /* upper-case user name */
 488         uchar_t v2hash[NTLM_HASH_SZ];
 489         struct mbuf *tim = ti_mbp->mb_top;
 490 
 491         /*
 492          * Convert the user name to upper-case, as
 493          * that's what's used when computing LMv2
 494          * and NTLMv2 responses.  Note that the
 495          * domain name is NOT upper-cased!
 496          */
 497         if (ctx->ct_user[0] == '\0')
 498                 return (EINVAL);
 499         ucuser = utf8_str_toupper(ctx->ct_user);
 500         if (ucuser == NULL)
 501                 return (ENOMEM);
 502 
 503         if ((err = mb_init(lm_mbp)) != 0)
 504                 goto out;
 505         if ((err = mb_init(nt_mbp)) != 0)
 506                 goto out;
 507 
 508         /*
 509          * Compute the NTLMv2 hash
 510          */
 511         err = ntlm_v2_hash(v2hash, ctx->ct_nthash,
 512             ucuser, ctx->ct_domain);
 513         if (err)
 514                 goto out;
 515 
 516         /*
 517          * Compute the LMv2 response, derived from
 518          * the v2hash, the server challenge, and
 519          * the client nonce (random bits).
 520          *
 521          * We compose it from two parts:
 522          *      1: 16-byte response hash
 523          *      2: Client nonce
 524          */
 525         lmresp = mb_reserve(lm_mbp, NTLM_HASH_SZ);
 526         err = ntlm_v2_resp_hash(lmresp,
 527             v2hash, ctx->ct_srv_chal,
 528             ctx->ct_clnonce, NTLM_CHAL_SZ);
 529         if (err)
 530                 goto out;
 531         mb_put_mem(lm_mbp, ctx->ct_clnonce, NTLM_CHAL_SZ, MB_MSYSTEM);
 532 
 533         /*
 534          * Compute the NTLMv2 response, derived
 535          * from the server challenge and the
 536          * "target info." blob passed in.
 537          *
 538          * Again composed from two parts:
 539          *      1: 16-byte response hash
 540          *      2: "target info." blob
 541          */
 542         ntresp = mb_reserve(nt_mbp, NTLM_HASH_SZ);
 543         err = ntlm_v2_resp_hash(ntresp,
 544             v2hash, ctx->ct_srv_chal,
 545             (uchar_t *)tim->m_data, tim->m_len);
 546         if (err)
 547                 goto out;
 548         mb_put_mem(nt_mbp, tim->m_data, tim->m_len, MB_MSYSTEM);
 549 
 550         /*
 551          * Compute the session key
 552          */
 553         ntlm_v2_session_key(ssn_key, v2hash, ntresp);
 554 
 555 out:
 556         if (err) {
 557                 mb_done(lm_mbp);
 558                 mb_done(nt_mbp);
 559         }
 560         free(ucuser);
 561 
 562         return (err);
 563 }
 564 
 565 /*
 566  * Helper for ntlm_build_target_info below.
 567  * Put a name in the NTLMv2 "target info." blob.
 568  */
 569 static void
 570 smb_put_blob_name(struct mbdata *mbp, char *name, int type)
 571 {
 572         uint16_t *ucs = NULL;
 573         int nlen;
 574 
 575         if (name)
 576                 ucs = convert_utf8_to_leunicode(name);
 577         if (ucs)
 578                 nlen = unicode_strlen(ucs);
 579         else
 580                 nlen = 0;
 581 
 582         nlen <<= 1;       /* length in bytes, without null. */
 583 
 584         mb_put_uint16le(mbp, type);
 585         mb_put_uint16le(mbp, nlen);
 586         mb_put_mem(mbp, (char *)ucs, nlen, MB_MSYSTEM);
 587 
 588         if (ucs)
 589                 free(ucs);
 590 }
 591 
 592 /*
 593  * Build an NTLMv2 "target info." blob.  When called from NTLMSSP,
 594  * the list of names comes from the Type 2 message.  Otherwise,
 595  * we create the name list here.
 596  */
 597 int
 598 ntlm_build_target_info(struct smb_ctx *ctx, struct mbuf *names,
 599         struct mbdata *mbp)
 600 {
 601         struct timeval now;
 602         uint64_t nt_time;
 603 
 604         char *ucdom = NULL;     /* user's domain */
 605         int err;
 606 
 607         /* Get mbuf chain for the "target info". */
 608         if ((err = mb_init(mbp)) != 0)
 609                 return (err);
 610 
 611         /*
 612          * Get the "NT time" for the target info header.
 613          */
 614         (void) gettimeofday(&now, 0);
 615         smb_time_local2NT(&now, 0, &nt_time);
 616 
 617         /*
 618          * Build the "target info." block.
 619          *
 620          * Based on information at:
 621          * http://davenport.sourceforge.net/ntlm.html#theNtlmv2Response
 622          *
 623          * First the fixed-size part.
 624          */
 625         mb_put_uint32le(mbp, 0x101);    /* Blob signature */
 626         mb_put_uint32le(mbp, 0);                /* reserved */
 627         mb_put_uint64le(mbp, nt_time);  /* NT time stamp */
 628         mb_put_mem(mbp, ctx->ct_clnonce, NTLM_CHAL_SZ, MB_MSYSTEM);
 629         mb_put_uint32le(mbp, 0);                /* unknown */
 630 
 631         /*
 632          * Now put the list of names, either from the
 633          * NTLMSSP Type 2 message or composed here.
 634          */
 635         if (names) {
 636                 err = mb_put_mem(mbp, names->m_data, names->m_len, MB_MSYSTEM);
 637         } else {
 638                 /* Get upper-case names. */
 639                 ucdom  = utf8_str_toupper(ctx->ct_domain);
 640                 if (ucdom == NULL) {
 641                         err = ENOMEM;
 642                         goto out;
 643                 }
 644                 smb_put_blob_name(mbp, ucdom, NAMETYPE_DOMAIN_NB);
 645                 smb_put_blob_name(mbp, NULL, NAMETYPE_EOL);
 646                 /* OK, that's the whole "target info." blob! */
 647         }
 648         err = 0;
 649 
 650 out:
 651         free(ucdom);
 652         return (err);
 653 }
 654 
 655 /*
 656  * Helper for ntlmssp_put_type3 - Build the "key exchange key"
 657  * used when we have both NTLM(v1) and NTLMSSP_NEGOTIATE_NTLM2.
 658  * HMAC_MD5(SessionBaseKey, concat(ServerChallenge, LmResponse[0..7]))
 659  */
 660 void
 661 ntlm2_kxkey(struct smb_ctx *ctx, struct mbdata *lm_mbp,
 662         uchar_t *ssn_key, uchar_t *kxkey)
 663 {
 664         uchar_t data[NTLM_HASH_SZ];
 665         uchar_t *p = mtod(lm_mbp->mb_top, uchar_t *);
 666 
 667         /* concat(ServerChallenge, LmResponse[0..7]) */
 668         memcpy(data, ctx->ct_srv_chal, NTLM_CHAL_SZ);
 669         memcpy(data + NTLM_CHAL_SZ, p, NTLM_CHAL_SZ);
 670 
 671         /* HMAC_MD5(SessionBaseKey, concat(...)) */
 672         HMACT64(kxkey, ssn_key, NTLM_HASH_SZ,
 673             data, NTLM_HASH_SZ);
 674 }