1613a2f6bSGordon Ross /* 2613a2f6bSGordon Ross * Copyright (c) 2000-2001, Boris Popov 3613a2f6bSGordon Ross * All rights reserved. 4613a2f6bSGordon Ross * 5613a2f6bSGordon Ross * Redistribution and use in source and binary forms, with or without 6613a2f6bSGordon Ross * modification, are permitted provided that the following conditions 7613a2f6bSGordon Ross * are met: 8613a2f6bSGordon Ross * 1. Redistributions of source code must retain the above copyright 9613a2f6bSGordon Ross * notice, this list of conditions and the following disclaimer. 10613a2f6bSGordon Ross * 2. Redistributions in binary form must reproduce the above copyright 11613a2f6bSGordon Ross * notice, this list of conditions and the following disclaimer in the 12613a2f6bSGordon Ross * documentation and/or other materials provided with the distribution. 13613a2f6bSGordon Ross * 3. All advertising materials mentioning features or use of this software 14613a2f6bSGordon Ross * must display the following acknowledgement: 15613a2f6bSGordon Ross * This product includes software developed by Boris Popov. 16613a2f6bSGordon Ross * 4. Neither the name of the author nor the names of any co-contributors 17613a2f6bSGordon Ross * may be used to endorse or promote products derived from this software 18613a2f6bSGordon Ross * without specific prior written permission. 19613a2f6bSGordon Ross * 20613a2f6bSGordon Ross * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 21613a2f6bSGordon Ross * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22613a2f6bSGordon Ross * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23613a2f6bSGordon Ross * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 24613a2f6bSGordon Ross * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25613a2f6bSGordon Ross * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26613a2f6bSGordon Ross * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27613a2f6bSGordon Ross * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28613a2f6bSGordon Ross * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29613a2f6bSGordon Ross * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30613a2f6bSGordon Ross * SUCH DAMAGE. 31613a2f6bSGordon Ross * 32613a2f6bSGordon Ross * $Id: smb_crypt.c,v 1.13 2005/01/26 23:50:50 lindak Exp $ 33613a2f6bSGordon Ross */ 34613a2f6bSGordon Ross 35613a2f6bSGordon Ross /* 3615359501SGordon Ross * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. 37*85e6b674SGordon Ross * Copyright 2013 Nexenta Systems, Inc. All rights reserved. 38613a2f6bSGordon Ross */ 39613a2f6bSGordon Ross 40613a2f6bSGordon Ross /* 41613a2f6bSGordon Ross * NTLM support functions 42613a2f6bSGordon Ross * 43613a2f6bSGordon Ross * Some code from the driver: smb_smb.c, smb_crypt.c 44613a2f6bSGordon Ross */ 45613a2f6bSGordon Ross 46613a2f6bSGordon Ross #include <sys/errno.h> 47613a2f6bSGordon Ross #include <sys/types.h> 48613a2f6bSGordon Ross #include <sys/md4.h> 49613a2f6bSGordon Ross #include <sys/md5.h> 50613a2f6bSGordon Ross 51613a2f6bSGordon Ross #include <ctype.h> 52613a2f6bSGordon Ross #include <stdlib.h> 53613a2f6bSGordon Ross #include <strings.h> 54613a2f6bSGordon Ross 55613a2f6bSGordon Ross #include <netsmb/smb_lib.h> 56613a2f6bSGordon Ross 57613a2f6bSGordon Ross #include "private.h" 58613a2f6bSGordon Ross #include "charsets.h" 59613a2f6bSGordon Ross #include "smb_crypt.h" 60613a2f6bSGordon Ross #include "ntlm.h" 61613a2f6bSGordon Ross 62613a2f6bSGordon Ross 63613a2f6bSGordon Ross /* 64613a2f6bSGordon Ross * ntlm_compute_lm_hash 65613a2f6bSGordon Ross * 66*85e6b674SGordon Ross * Given a password, compute the LM hash. 67*85e6b674SGordon Ross * a.k.a. ResponseKeyLM in [MS-NLMP] 68613a2f6bSGordon Ross * 69613a2f6bSGordon Ross * Output: 70*85e6b674SGordon Ross * hash: 16-byte "LanMan" (LM) hash (normally ctx->ct_lmhash) 71613a2f6bSGordon Ross * Inputs: 72613a2f6bSGordon Ross * ucpw: User's password, upper-case UTF-8 string. 73613a2f6bSGordon Ross * 74613a2f6bSGordon Ross * Source: Implementing CIFS (Chris Hertel) 75613a2f6bSGordon Ross * 76613a2f6bSGordon Ross * P14 = UCPW padded to 14-bytes, or truncated (as needed) 77613a2f6bSGordon Ross * result = Encrypt(Key=P14, Data=MagicString) 78613a2f6bSGordon Ross */ 79613a2f6bSGordon Ross int 80613a2f6bSGordon Ross ntlm_compute_lm_hash(uchar_t *hash, const char *pass) 81613a2f6bSGordon Ross { 82613a2f6bSGordon Ross static const uchar_t M8[8] = "KGS!@#$%"; 83613a2f6bSGordon Ross uchar_t P14[14 + 1]; 84613a2f6bSGordon Ross int err; 85613a2f6bSGordon Ross char *ucpw; 86613a2f6bSGordon Ross 87613a2f6bSGordon Ross /* First, convert the p/w to upper case. */ 88613a2f6bSGordon Ross ucpw = utf8_str_toupper(pass); 89613a2f6bSGordon Ross if (ucpw == NULL) 90613a2f6bSGordon Ross return (ENOMEM); 91613a2f6bSGordon Ross 92613a2f6bSGordon Ross /* Pad or truncate the upper-case P/W as needed. */ 93613a2f6bSGordon Ross bzero(P14, sizeof (P14)); 94613a2f6bSGordon Ross (void) strncpy((char *)P14, ucpw, 14); 95613a2f6bSGordon Ross 96613a2f6bSGordon Ross /* Compute the hash. */ 97613a2f6bSGordon Ross err = smb_encrypt_DES(hash, NTLM_HASH_SZ, 98613a2f6bSGordon Ross P14, 14, M8, 8); 99613a2f6bSGordon Ross 100613a2f6bSGordon Ross free(ucpw); 101613a2f6bSGordon Ross return (err); 102613a2f6bSGordon Ross } 103613a2f6bSGordon Ross 104613a2f6bSGordon Ross /* 105613a2f6bSGordon Ross * ntlm_compute_nt_hash 106613a2f6bSGordon Ross * 107*85e6b674SGordon Ross * Given a password, compute the NT hash. 108*85e6b674SGordon Ross * a.k.a. the ResponseKeyNT in [MS-NLMP] 109613a2f6bSGordon Ross * 110613a2f6bSGordon Ross * Output: 111*85e6b674SGordon Ross * hash: 16-byte "NT" hash (normally ctx->ct_nthash) 112613a2f6bSGordon Ross * Inputs: 113613a2f6bSGordon Ross * upw: User's password, mixed-case UCS-2LE. 114613a2f6bSGordon Ross * pwlen: Size (in bytes) of upw 115613a2f6bSGordon Ross */ 116613a2f6bSGordon Ross int 117613a2f6bSGordon Ross ntlm_compute_nt_hash(uchar_t *hash, const char *pass) 118613a2f6bSGordon Ross { 119613a2f6bSGordon Ross MD4_CTX ctx; 120613a2f6bSGordon Ross uint16_t *unipw = NULL; 121613a2f6bSGordon Ross int pwsz; 122613a2f6bSGordon Ross 123613a2f6bSGordon Ross /* First, convert the password to unicode. */ 124613a2f6bSGordon Ross unipw = convert_utf8_to_leunicode(pass); 125613a2f6bSGordon Ross if (unipw == NULL) 126613a2f6bSGordon Ross return (ENOMEM); 127613a2f6bSGordon Ross pwsz = unicode_strlen(unipw) << 1; 128613a2f6bSGordon Ross 129613a2f6bSGordon Ross /* Compute the hash. */ 130613a2f6bSGordon Ross MD4Init(&ctx); 131613a2f6bSGordon Ross MD4Update(&ctx, unipw, pwsz); 132613a2f6bSGordon Ross MD4Final(hash, &ctx); 133613a2f6bSGordon Ross 134613a2f6bSGordon Ross free(unipw); 135613a2f6bSGordon Ross return (0); 136613a2f6bSGordon Ross } 137613a2f6bSGordon Ross 138613a2f6bSGordon Ross /* 139613a2f6bSGordon Ross * ntlm_v1_response 140*85e6b674SGordon Ross * a.k.a. DESL() in [MS-NLMP] 141613a2f6bSGordon Ross * 142613a2f6bSGordon Ross * Create an LM response from the given LM hash and challenge, 143613a2f6bSGordon Ross * or an NTLM repsonse from a given NTLM hash and challenge. 144613a2f6bSGordon Ross * Both response types are 24 bytes (NTLM_V1_RESP_SZ) 145613a2f6bSGordon Ross */ 146613a2f6bSGordon Ross static int 147613a2f6bSGordon Ross ntlm_v1_response(uchar_t *resp, 148613a2f6bSGordon Ross const uchar_t *hash, 149613a2f6bSGordon Ross const uchar_t *chal, int clen) 150613a2f6bSGordon Ross { 151613a2f6bSGordon Ross uchar_t S21[21]; 152613a2f6bSGordon Ross int err; 153613a2f6bSGordon Ross 154613a2f6bSGordon Ross /* 155613a2f6bSGordon Ross * 14-byte LM Hash should be padded with 5 nul bytes to create 156613a2f6bSGordon Ross * a 21-byte string to be used in producing LM response 157613a2f6bSGordon Ross */ 158613a2f6bSGordon Ross bzero(&S21, sizeof (S21)); 159613a2f6bSGordon Ross bcopy(hash, S21, NTLM_HASH_SZ); 160613a2f6bSGordon Ross 161613a2f6bSGordon Ross /* padded LM Hash -> LM Response */ 162613a2f6bSGordon Ross err = smb_encrypt_DES(resp, NTLM_V1_RESP_SZ, 163613a2f6bSGordon Ross S21, 21, chal, clen); 164613a2f6bSGordon Ross return (err); 165613a2f6bSGordon Ross } 166613a2f6bSGordon Ross 167613a2f6bSGordon Ross /* 168613a2f6bSGordon Ross * Calculate an NTLMv1 session key (16 bytes). 169613a2f6bSGordon Ross */ 170613a2f6bSGordon Ross static void 171613a2f6bSGordon Ross ntlm_v1_session_key(uchar_t *ssn_key, const uchar_t *nt_hash) 172613a2f6bSGordon Ross { 173613a2f6bSGordon Ross MD4_CTX md4; 174613a2f6bSGordon Ross 175613a2f6bSGordon Ross MD4Init(&md4); 176613a2f6bSGordon Ross MD4Update(&md4, nt_hash, NTLM_HASH_SZ); 177613a2f6bSGordon Ross MD4Final(ssn_key, &md4); 178613a2f6bSGordon Ross } 179613a2f6bSGordon Ross 180613a2f6bSGordon Ross /* 181613a2f6bSGordon Ross * Compute both the LM(v1) response and the NTLM(v1) response, 182613a2f6bSGordon Ross * and put them in the mbdata chains passed. This allocates 183613a2f6bSGordon Ross * mbuf chains in the output args, which the caller frees. 184613a2f6bSGordon Ross */ 185613a2f6bSGordon Ross int 186613a2f6bSGordon Ross ntlm_put_v1_responses(struct smb_ctx *ctx, 187613a2f6bSGordon Ross struct mbdata *lm_mbp, struct mbdata *nt_mbp) 188613a2f6bSGordon Ross { 189613a2f6bSGordon Ross uchar_t *lmresp, *ntresp; 190613a2f6bSGordon Ross int err; 191613a2f6bSGordon Ross 192613a2f6bSGordon Ross /* Get mbuf chain for the LM response. */ 19302d09e03SGordon Ross if ((err = mb_init_sz(lm_mbp, NTLM_V1_RESP_SZ)) != 0) 194613a2f6bSGordon Ross return (err); 195613a2f6bSGordon Ross 196613a2f6bSGordon Ross /* Get mbuf chain for the NT response. */ 19702d09e03SGordon Ross if ((err = mb_init_sz(nt_mbp, NTLM_V1_RESP_SZ)) != 0) 198613a2f6bSGordon Ross return (err); 199613a2f6bSGordon Ross 200613a2f6bSGordon Ross /* 201613a2f6bSGordon Ross * Compute the NTLM response, derived from 202*85e6b674SGordon Ross * the challenge and the NT hash (a.k.a ResponseKeyNT) 203613a2f6bSGordon Ross */ 20402d09e03SGordon Ross err = mb_fit(nt_mbp, NTLM_V1_RESP_SZ, (char **)&ntresp); 20502d09e03SGordon Ross if (err) 20602d09e03SGordon Ross return (err); 207613a2f6bSGordon Ross bzero(ntresp, NTLM_V1_RESP_SZ); 208613a2f6bSGordon Ross err = ntlm_v1_response(ntresp, ctx->ct_nthash, 209*85e6b674SGordon Ross ctx->ct_srv_chal, NTLM_CHAL_SZ); 210*85e6b674SGordon Ross 211*85e6b674SGordon Ross /* 212*85e6b674SGordon Ross * Compute the LM response, derived from 213*85e6b674SGordon Ross * the challenge and the ASCII password. 214*85e6b674SGordon Ross * Per. [MS-NLMP 3.3.1] if NoLmResponse, 215*85e6b674SGordon Ross * send the NT response for both NT+LM. 216*85e6b674SGordon Ross */ 217*85e6b674SGordon Ross err = mb_fit(lm_mbp, NTLM_V1_RESP_SZ, (char **)&lmresp); 218*85e6b674SGordon Ross if (err) 219*85e6b674SGordon Ross return (err); 220*85e6b674SGordon Ross memcpy(lmresp, ntresp, NTLM_V1_RESP_SZ); 221*85e6b674SGordon Ross if (ctx->ct_authflags & SMB_AT_LM1) { 222*85e6b674SGordon Ross /* They asked to send the LM hash too. */ 223*85e6b674SGordon Ross err = ntlm_v1_response(lmresp, ctx->ct_lmhash, 224*85e6b674SGordon Ross ctx->ct_srv_chal, NTLM_CHAL_SZ); 225*85e6b674SGordon Ross if (err) 226*85e6b674SGordon Ross return (err); 227*85e6b674SGordon Ross } 228*85e6b674SGordon Ross 229*85e6b674SGordon Ross /* 230*85e6b674SGordon Ross * Compute the session key 231*85e6b674SGordon Ross */ 232*85e6b674SGordon Ross ntlm_v1_session_key(ctx->ct_ssn_key, ctx->ct_nthash); 233*85e6b674SGordon Ross 234*85e6b674SGordon Ross return (err); 235*85e6b674SGordon Ross } 236*85e6b674SGordon Ross 237*85e6b674SGordon Ross /* 238*85e6b674SGordon Ross * Compute both the LM(v1x) response and the NTLM(v1x) response, 239*85e6b674SGordon Ross * and put them in the mbdata chains passed. "v1x" here refers to 240*85e6b674SGordon Ross * NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY used with NTLMSSP, 241*85e6b674SGordon Ross * also known by its shorter alias NTLMSSP_NEGOTIATE_NTLM2. 242*85e6b674SGordon Ross * [MS-NLMP 3.3.1] 243*85e6b674SGordon Ross * 244*85e6b674SGordon Ross * This allocates mbuf chains in the output args (caller frees). 245*85e6b674SGordon Ross */ 246*85e6b674SGordon Ross int 247*85e6b674SGordon Ross ntlm_put_v1x_responses(struct smb_ctx *ctx, 248*85e6b674SGordon Ross struct mbdata *lm_mbp, struct mbdata *nt_mbp) 249*85e6b674SGordon Ross { 250*85e6b674SGordon Ross MD5_CTX context; 251*85e6b674SGordon Ross uchar_t challenges[2 * NTLM_CHAL_SZ]; 252*85e6b674SGordon Ross uchar_t digest[NTLM_HASH_SZ]; 253*85e6b674SGordon Ross uchar_t *lmresp, *ntresp; 254*85e6b674SGordon Ross int err; 255*85e6b674SGordon Ross 256*85e6b674SGordon Ross /* Get mbuf chain for the LM response. */ 257*85e6b674SGordon Ross if ((err = mb_init_sz(lm_mbp, NTLM_V1_RESP_SZ)) != 0) 258*85e6b674SGordon Ross return (err); 259*85e6b674SGordon Ross 260*85e6b674SGordon Ross /* Get mbuf chain for the NT response. */ 261*85e6b674SGordon Ross if ((err = mb_init_sz(nt_mbp, NTLM_V1_RESP_SZ)) != 0) 262*85e6b674SGordon Ross return (err); 263*85e6b674SGordon Ross 264*85e6b674SGordon Ross /* 265*85e6b674SGordon Ross * challenges = ConcatenationOf(ServerChallenge, ClientChallenge) 266*85e6b674SGordon Ross */ 267*85e6b674SGordon Ross memcpy(challenges, ctx->ct_srv_chal, NTLM_CHAL_SZ); 268*85e6b674SGordon Ross memcpy(challenges + NTLM_CHAL_SZ, ctx->ct_clnonce, NTLM_CHAL_SZ); 269*85e6b674SGordon Ross 270*85e6b674SGordon Ross /* 271*85e6b674SGordon Ross * digest = MD5(challenges) 272*85e6b674SGordon Ross */ 273*85e6b674SGordon Ross MD5Init(&context); 274*85e6b674SGordon Ross MD5Update(&context, challenges, sizeof (challenges)); 275*85e6b674SGordon Ross MD5Final(digest, &context); 276*85e6b674SGordon Ross 277*85e6b674SGordon Ross /* 278*85e6b674SGordon Ross * Compute the NTLM response, derived from the 279*85e6b674SGordon Ross * NT hash (a.k.a ResponseKeyNT) and the first 280*85e6b674SGordon Ross * 8 bytes of the MD5 digest of the challenges. 281*85e6b674SGordon Ross */ 282*85e6b674SGordon Ross err = mb_fit(nt_mbp, NTLM_V1_RESP_SZ, (char **)&ntresp); 283*85e6b674SGordon Ross if (err) 284*85e6b674SGordon Ross return (err); 285*85e6b674SGordon Ross bzero(ntresp, NTLM_V1_RESP_SZ); 286*85e6b674SGordon Ross err = ntlm_v1_response(ntresp, ctx->ct_nthash, 287*85e6b674SGordon Ross digest, NTLM_CHAL_SZ); 288*85e6b674SGordon Ross 289*85e6b674SGordon Ross /* 290*85e6b674SGordon Ross * With "Extended Session Security", the LM response 291*85e6b674SGordon Ross * is simply the client challenge (nonce) padded out. 292*85e6b674SGordon Ross */ 293*85e6b674SGordon Ross err = mb_fit(lm_mbp, NTLM_V1_RESP_SZ, (char **)&lmresp); 294*85e6b674SGordon Ross if (err) 295*85e6b674SGordon Ross return (err); 296*85e6b674SGordon Ross bzero(lmresp, NTLM_V1_RESP_SZ); 297*85e6b674SGordon Ross memcpy(lmresp, ctx->ct_clnonce, NTLM_CHAL_SZ); 298613a2f6bSGordon Ross 299613a2f6bSGordon Ross /* 300613a2f6bSGordon Ross * Compute the session key 301613a2f6bSGordon Ross */ 302613a2f6bSGordon Ross ntlm_v1_session_key(ctx->ct_ssn_key, ctx->ct_nthash); 303613a2f6bSGordon Ross 304613a2f6bSGordon Ross return (err); 305613a2f6bSGordon Ross } 306613a2f6bSGordon Ross 307613a2f6bSGordon Ross /* 308613a2f6bSGordon Ross * A variation on HMAC-MD5 known as HMACT64 is used by Windows systems. 309613a2f6bSGordon Ross * The HMACT64() function is the same as the HMAC-MD5() except that 310613a2f6bSGordon Ross * it truncates the input key to 64 bytes rather than hashing it down 311613a2f6bSGordon Ross * to 16 bytes using the MD5() function. 312613a2f6bSGordon Ross * 313613a2f6bSGordon Ross * Output: digest (16-bytes) 314613a2f6bSGordon Ross */ 315613a2f6bSGordon Ross static void 316613a2f6bSGordon Ross HMACT64(uchar_t *digest, 317613a2f6bSGordon Ross const uchar_t *key, size_t key_len, 318613a2f6bSGordon Ross const uchar_t *data, size_t data_len) 319613a2f6bSGordon Ross { 320613a2f6bSGordon Ross MD5_CTX context; 321613a2f6bSGordon Ross uchar_t k_ipad[64]; /* inner padding - key XORd with ipad */ 322613a2f6bSGordon Ross uchar_t k_opad[64]; /* outer padding - key XORd with opad */ 323613a2f6bSGordon Ross int i; 324613a2f6bSGordon Ross 325613a2f6bSGordon Ross /* if key is longer than 64 bytes use only the first 64 bytes */ 326613a2f6bSGordon Ross if (key_len > 64) 327613a2f6bSGordon Ross key_len = 64; 328613a2f6bSGordon Ross 329613a2f6bSGordon Ross /* 330613a2f6bSGordon Ross * The HMAC-MD5 (and HMACT64) transform looks like: 331613a2f6bSGordon Ross * 332613a2f6bSGordon Ross * MD5(K XOR opad, MD5(K XOR ipad, data)) 333613a2f6bSGordon Ross * 334613a2f6bSGordon Ross * where K is an n byte key 335613a2f6bSGordon Ross * ipad is the byte 0x36 repeated 64 times 336613a2f6bSGordon Ross * opad is the byte 0x5c repeated 64 times 337613a2f6bSGordon Ross * and data is the data being protected. 338613a2f6bSGordon Ross */ 339613a2f6bSGordon Ross 340613a2f6bSGordon Ross /* start out by storing key in pads */ 341613a2f6bSGordon Ross bzero(k_ipad, sizeof (k_ipad)); 342613a2f6bSGordon Ross bzero(k_opad, sizeof (k_opad)); 343613a2f6bSGordon Ross bcopy(key, k_ipad, key_len); 344613a2f6bSGordon Ross bcopy(key, k_opad, key_len); 345613a2f6bSGordon Ross 346613a2f6bSGordon Ross /* XOR key with ipad and opad values */ 347613a2f6bSGordon Ross for (i = 0; i < 64; i++) { 348613a2f6bSGordon Ross k_ipad[i] ^= 0x36; 349613a2f6bSGordon Ross k_opad[i] ^= 0x5c; 350613a2f6bSGordon Ross } 351613a2f6bSGordon Ross 352613a2f6bSGordon Ross /* 353613a2f6bSGordon Ross * perform inner MD5 354613a2f6bSGordon Ross */ 355613a2f6bSGordon Ross MD5Init(&context); /* init context for 1st pass */ 356613a2f6bSGordon Ross MD5Update(&context, k_ipad, 64); /* start with inner pad */ 357613a2f6bSGordon Ross MD5Update(&context, data, data_len); /* then data of datagram */ 358613a2f6bSGordon Ross MD5Final(digest, &context); /* finish up 1st pass */ 359613a2f6bSGordon Ross 360613a2f6bSGordon Ross /* 361613a2f6bSGordon Ross * perform outer MD5 362613a2f6bSGordon Ross */ 363613a2f6bSGordon Ross MD5Init(&context); /* init context for 2nd pass */ 364613a2f6bSGordon Ross MD5Update(&context, k_opad, 64); /* start with outer pad */ 365613a2f6bSGordon Ross MD5Update(&context, digest, 16); /* then results of 1st hash */ 366613a2f6bSGordon Ross MD5Final(digest, &context); /* finish up 2nd pass */ 367613a2f6bSGordon Ross } 368613a2f6bSGordon Ross 369613a2f6bSGordon Ross 370613a2f6bSGordon Ross /* 371613a2f6bSGordon Ross * Compute an NTLMv2 hash given the NTLMv1 hash, the user name, 372613a2f6bSGordon Ross * and the destination (machine or domain name). 373613a2f6bSGordon Ross * 374613a2f6bSGordon Ross * Output: 375613a2f6bSGordon Ross * v2hash: 16-byte NTLMv2 hash. 376613a2f6bSGordon Ross * Inputs: 377613a2f6bSGordon Ross * v1hash: 16-byte NTLMv1 hash. 378613a2f6bSGordon Ross * user: User name, UPPER-case UTF-8 string. 379613a2f6bSGordon Ross * destination: Domain or server, MIXED-case UTF-8 string. 380613a2f6bSGordon Ross */ 381613a2f6bSGordon Ross static int 382613a2f6bSGordon Ross ntlm_v2_hash(uchar_t *v2hash, const uchar_t *v1hash, 383613a2f6bSGordon Ross const char *user, const char *destination) 384613a2f6bSGordon Ross { 385613a2f6bSGordon Ross int ulen, dlen; 386613a2f6bSGordon Ross size_t ucs2len; 387613a2f6bSGordon Ross uint16_t *ucs2data = NULL; 388613a2f6bSGordon Ross char *utf8data = NULL; 389613a2f6bSGordon Ross int err = ENOMEM; 390613a2f6bSGordon Ross 391613a2f6bSGordon Ross /* 392613a2f6bSGordon Ross * v2hash = HMACT64(v1hash, 16, concat(upcase(user), dest)) 393613a2f6bSGordon Ross * where "dest" is the domain or server name ("target name") 394613a2f6bSGordon Ross * Note: user name is converted to upper-case by the caller. 395613a2f6bSGordon Ross */ 396613a2f6bSGordon Ross 397613a2f6bSGordon Ross /* utf8data = concat(user, dest) */ 398613a2f6bSGordon Ross ulen = strlen(user); 399613a2f6bSGordon Ross dlen = strlen(destination); 400613a2f6bSGordon Ross utf8data = malloc(ulen + dlen + 1); 401613a2f6bSGordon Ross if (utf8data == NULL) 402613a2f6bSGordon Ross goto out; 403613a2f6bSGordon Ross bcopy(user, utf8data, ulen); 404613a2f6bSGordon Ross bcopy(destination, utf8data + ulen, dlen + 1); 405613a2f6bSGordon Ross 406613a2f6bSGordon Ross /* Convert to UCS-2LE */ 407613a2f6bSGordon Ross ucs2data = convert_utf8_to_leunicode(utf8data); 408613a2f6bSGordon Ross if (ucs2data == NULL) 409613a2f6bSGordon Ross goto out; 410613a2f6bSGordon Ross ucs2len = 2 * unicode_strlen(ucs2data); 411613a2f6bSGordon Ross 412613a2f6bSGordon Ross HMACT64(v2hash, v1hash, NTLM_HASH_SZ, 413613a2f6bSGordon Ross (uchar_t *)ucs2data, ucs2len); 414613a2f6bSGordon Ross err = 0; 415613a2f6bSGordon Ross out: 416613a2f6bSGordon Ross if (ucs2data) 417613a2f6bSGordon Ross free(ucs2data); 418613a2f6bSGordon Ross if (utf8data) 419613a2f6bSGordon Ross free(utf8data); 420613a2f6bSGordon Ross return (err); 421613a2f6bSGordon Ross } 422613a2f6bSGordon Ross 423613a2f6bSGordon Ross /* 424613a2f6bSGordon Ross * Compute a partial LMv2 or NTLMv2 response (first 16-bytes). 425613a2f6bSGordon Ross * The full response is composed by the caller by 426613a2f6bSGordon Ross * appending the client_data to the returned hash. 427613a2f6bSGordon Ross * 428613a2f6bSGordon Ross * Output: 429613a2f6bSGordon Ross * rhash: _partial_ LMv2/NTLMv2 response (first 16-bytes) 430613a2f6bSGordon Ross * Inputs: 431613a2f6bSGordon Ross * v2hash: 16-byte NTLMv2 hash. 432613a2f6bSGordon Ross * C8: Challenge from server (8 bytes) 433613a2f6bSGordon Ross * client_data: client nonce (for LMv2) or the 434613a2f6bSGordon Ross * "blob" from ntlm_build_target_info (NTLMv2) 435613a2f6bSGordon Ross */ 436613a2f6bSGordon Ross static int 437613a2f6bSGordon Ross ntlm_v2_resp_hash(uchar_t *rhash, 438613a2f6bSGordon Ross const uchar_t *v2hash, const uchar_t *C8, 439613a2f6bSGordon Ross const uchar_t *client_data, size_t cdlen) 440613a2f6bSGordon Ross { 441613a2f6bSGordon Ross size_t dlen; 442613a2f6bSGordon Ross uchar_t *data = NULL; 443613a2f6bSGordon Ross 444613a2f6bSGordon Ross /* data = concat(C8, client_data) */ 445613a2f6bSGordon Ross dlen = 8 + cdlen; 446613a2f6bSGordon Ross data = malloc(dlen); 447613a2f6bSGordon Ross if (data == NULL) 448613a2f6bSGordon Ross return (ENOMEM); 449613a2f6bSGordon Ross bcopy(C8, data, 8); 450613a2f6bSGordon Ross bcopy(client_data, data + 8, cdlen); 451613a2f6bSGordon Ross 452613a2f6bSGordon Ross HMACT64(rhash, v2hash, NTLM_HASH_SZ, data, dlen); 453613a2f6bSGordon Ross 454613a2f6bSGordon Ross free(data); 455613a2f6bSGordon Ross return (0); 456613a2f6bSGordon Ross } 457613a2f6bSGordon Ross 458613a2f6bSGordon Ross /* 459613a2f6bSGordon Ross * Calculate an NTLMv2 session key (16 bytes). 460613a2f6bSGordon Ross */ 461613a2f6bSGordon Ross static void 462613a2f6bSGordon Ross ntlm_v2_session_key(uchar_t *ssn_key, 463613a2f6bSGordon Ross const uchar_t *v2hash, 464613a2f6bSGordon Ross const uchar_t *ntresp) 465613a2f6bSGordon Ross { 466613a2f6bSGordon Ross 467613a2f6bSGordon Ross /* session key uses only 1st 16 bytes of ntresp */ 468613a2f6bSGordon Ross HMACT64(ssn_key, v2hash, NTLM_HASH_SZ, ntresp, NTLM_HASH_SZ); 469613a2f6bSGordon Ross } 470613a2f6bSGordon Ross 471613a2f6bSGordon Ross 472613a2f6bSGordon Ross /* 473613a2f6bSGordon Ross * Compute both the LMv2 response and the NTLMv2 response, 474613a2f6bSGordon Ross * and put them in the mbdata chains passed. This allocates 475613a2f6bSGordon Ross * mbuf chains in the output args, which the caller frees. 476613a2f6bSGordon Ross * Also computes the session key. 477613a2f6bSGordon Ross */ 478613a2f6bSGordon Ross int 479613a2f6bSGordon Ross ntlm_put_v2_responses(struct smb_ctx *ctx, struct mbdata *ti_mbp, 480613a2f6bSGordon Ross struct mbdata *lm_mbp, struct mbdata *nt_mbp) 481613a2f6bSGordon Ross { 482613a2f6bSGordon Ross uchar_t *lmresp, *ntresp; 483613a2f6bSGordon Ross int err; 48415359501SGordon Ross char *ucuser = NULL; /* upper-case user name */ 485613a2f6bSGordon Ross uchar_t v2hash[NTLM_HASH_SZ]; 486613a2f6bSGordon Ross struct mbuf *tim = ti_mbp->mb_top; 487613a2f6bSGordon Ross 488613a2f6bSGordon Ross /* 489613a2f6bSGordon Ross * Convert the user name to upper-case, as 490613a2f6bSGordon Ross * that's what's used when computing LMv2 49115359501SGordon Ross * and NTLMv2 responses. Note that the 49215359501SGordon Ross * domain name is NOT upper-cased! 493613a2f6bSGordon Ross */ 494*85e6b674SGordon Ross if (ctx->ct_user[0] == '\0') 495*85e6b674SGordon Ross return (EINVAL); 496613a2f6bSGordon Ross ucuser = utf8_str_toupper(ctx->ct_user); 497*85e6b674SGordon Ross if (ucuser == NULL) 498*85e6b674SGordon Ross return (ENOMEM); 499*85e6b674SGordon Ross 500*85e6b674SGordon Ross if ((err = mb_init(lm_mbp)) != 0) 501613a2f6bSGordon Ross goto out; 502*85e6b674SGordon Ross if ((err = mb_init(nt_mbp)) != 0) 503*85e6b674SGordon Ross goto out; 504613a2f6bSGordon Ross 505613a2f6bSGordon Ross /* 50615359501SGordon Ross * Compute the NTLMv2 hash 507613a2f6bSGordon Ross */ 50815359501SGordon Ross err = ntlm_v2_hash(v2hash, ctx->ct_nthash, 50915359501SGordon Ross ucuser, ctx->ct_domain); 510613a2f6bSGordon Ross if (err) 511613a2f6bSGordon Ross goto out; 512613a2f6bSGordon Ross 513613a2f6bSGordon Ross /* 514613a2f6bSGordon Ross * Compute the LMv2 response, derived from 515613a2f6bSGordon Ross * the v2hash, the server challenge, and 516613a2f6bSGordon Ross * the client nonce (random bits). 517613a2f6bSGordon Ross * 518613a2f6bSGordon Ross * We compose it from two parts: 519613a2f6bSGordon Ross * 1: 16-byte response hash 520613a2f6bSGordon Ross * 2: Client nonce 521613a2f6bSGordon Ross */ 522*85e6b674SGordon Ross lmresp = mb_reserve(lm_mbp, NTLM_HASH_SZ); 523613a2f6bSGordon Ross err = ntlm_v2_resp_hash(lmresp, 524*85e6b674SGordon Ross v2hash, ctx->ct_srv_chal, 525613a2f6bSGordon Ross ctx->ct_clnonce, NTLM_CHAL_SZ); 526613a2f6bSGordon Ross if (err) 527613a2f6bSGordon Ross goto out; 52802d09e03SGordon Ross mb_put_mem(lm_mbp, ctx->ct_clnonce, NTLM_CHAL_SZ, MB_MSYSTEM); 529613a2f6bSGordon Ross 530613a2f6bSGordon Ross /* 531613a2f6bSGordon Ross * Compute the NTLMv2 response, derived 532613a2f6bSGordon Ross * from the server challenge and the 533613a2f6bSGordon Ross * "target info." blob passed in. 534613a2f6bSGordon Ross * 535613a2f6bSGordon Ross * Again composed from two parts: 536613a2f6bSGordon Ross * 1: 16-byte response hash 537613a2f6bSGordon Ross * 2: "target info." blob 538613a2f6bSGordon Ross */ 539*85e6b674SGordon Ross ntresp = mb_reserve(nt_mbp, NTLM_HASH_SZ); 540613a2f6bSGordon Ross err = ntlm_v2_resp_hash(ntresp, 541*85e6b674SGordon Ross v2hash, ctx->ct_srv_chal, 542613a2f6bSGordon Ross (uchar_t *)tim->m_data, tim->m_len); 543613a2f6bSGordon Ross if (err) 544613a2f6bSGordon Ross goto out; 54502d09e03SGordon Ross mb_put_mem(nt_mbp, tim->m_data, tim->m_len, MB_MSYSTEM); 546613a2f6bSGordon Ross 547613a2f6bSGordon Ross /* 548613a2f6bSGordon Ross * Compute the session key 549613a2f6bSGordon Ross */ 550613a2f6bSGordon Ross ntlm_v2_session_key(ctx->ct_ssn_key, v2hash, ntresp); 551613a2f6bSGordon Ross 552613a2f6bSGordon Ross out: 553613a2f6bSGordon Ross if (err) { 554613a2f6bSGordon Ross mb_done(lm_mbp); 555613a2f6bSGordon Ross mb_done(nt_mbp); 556613a2f6bSGordon Ross } 557613a2f6bSGordon Ross free(ucuser); 558613a2f6bSGordon Ross 559613a2f6bSGordon Ross return (err); 560613a2f6bSGordon Ross } 561613a2f6bSGordon Ross 562613a2f6bSGordon Ross /* 563613a2f6bSGordon Ross * Helper for ntlm_build_target_info below. 564613a2f6bSGordon Ross * Put a name in the NTLMv2 "target info." blob. 565613a2f6bSGordon Ross */ 566613a2f6bSGordon Ross static void 567613a2f6bSGordon Ross smb_put_blob_name(struct mbdata *mbp, char *name, int type) 568613a2f6bSGordon Ross { 569613a2f6bSGordon Ross uint16_t *ucs = NULL; 570613a2f6bSGordon Ross int nlen; 571613a2f6bSGordon Ross 572613a2f6bSGordon Ross if (name) 573613a2f6bSGordon Ross ucs = convert_utf8_to_leunicode(name); 574613a2f6bSGordon Ross if (ucs) 575613a2f6bSGordon Ross nlen = unicode_strlen(ucs); 576613a2f6bSGordon Ross else 577613a2f6bSGordon Ross nlen = 0; 578613a2f6bSGordon Ross 579613a2f6bSGordon Ross nlen <<= 1; /* length in bytes, without null. */ 580613a2f6bSGordon Ross 581613a2f6bSGordon Ross mb_put_uint16le(mbp, type); 582613a2f6bSGordon Ross mb_put_uint16le(mbp, nlen); 58302d09e03SGordon Ross mb_put_mem(mbp, (char *)ucs, nlen, MB_MSYSTEM); 584613a2f6bSGordon Ross 585613a2f6bSGordon Ross if (ucs) 586613a2f6bSGordon Ross free(ucs); 587613a2f6bSGordon Ross } 588613a2f6bSGordon Ross 589613a2f6bSGordon Ross /* 590613a2f6bSGordon Ross * Build an NTLMv2 "target info." blob. When called from NTLMSSP, 591613a2f6bSGordon Ross * the list of names comes from the Type 2 message. Otherwise, 592613a2f6bSGordon Ross * we create the name list here. 593613a2f6bSGordon Ross */ 594613a2f6bSGordon Ross int 595613a2f6bSGordon Ross ntlm_build_target_info(struct smb_ctx *ctx, struct mbuf *names, 596613a2f6bSGordon Ross struct mbdata *mbp) 597613a2f6bSGordon Ross { 598613a2f6bSGordon Ross struct timeval now; 599613a2f6bSGordon Ross uint64_t nt_time; 600613a2f6bSGordon Ross 601613a2f6bSGordon Ross char *ucdom = NULL; /* user's domain */ 602613a2f6bSGordon Ross int err; 603613a2f6bSGordon Ross 604613a2f6bSGordon Ross /* Get mbuf chain for the "target info". */ 60502d09e03SGordon Ross if ((err = mb_init(mbp)) != 0) 606613a2f6bSGordon Ross return (err); 607613a2f6bSGordon Ross 608613a2f6bSGordon Ross /* 609613a2f6bSGordon Ross * Get the "NT time" for the target info header. 610613a2f6bSGordon Ross */ 611613a2f6bSGordon Ross (void) gettimeofday(&now, 0); 612613a2f6bSGordon Ross smb_time_local2NT(&now, 0, &nt_time); 613613a2f6bSGordon Ross 614613a2f6bSGordon Ross /* 615613a2f6bSGordon Ross * Build the "target info." block. 616613a2f6bSGordon Ross * 617613a2f6bSGordon Ross * Based on information at: 618613a2f6bSGordon Ross * http://davenport.sourceforge.net/ntlm.html#theNtlmv2Response 619613a2f6bSGordon Ross * 620613a2f6bSGordon Ross * First the fixed-size part. 621613a2f6bSGordon Ross */ 622613a2f6bSGordon Ross mb_put_uint32le(mbp, 0x101); /* Blob signature */ 623613a2f6bSGordon Ross mb_put_uint32le(mbp, 0); /* reserved */ 624613a2f6bSGordon Ross mb_put_uint64le(mbp, nt_time); /* NT time stamp */ 62502d09e03SGordon Ross mb_put_mem(mbp, ctx->ct_clnonce, NTLM_CHAL_SZ, MB_MSYSTEM); 626613a2f6bSGordon Ross mb_put_uint32le(mbp, 0); /* unknown */ 627613a2f6bSGordon Ross 628613a2f6bSGordon Ross /* 629613a2f6bSGordon Ross * Now put the list of names, either from the 630613a2f6bSGordon Ross * NTLMSSP Type 2 message or composed here. 631613a2f6bSGordon Ross */ 632613a2f6bSGordon Ross if (names) { 63302d09e03SGordon Ross err = mb_put_mem(mbp, names->m_data, names->m_len, MB_MSYSTEM); 634613a2f6bSGordon Ross } else { 635613a2f6bSGordon Ross /* Get upper-case names. */ 636613a2f6bSGordon Ross ucdom = utf8_str_toupper(ctx->ct_domain); 637613a2f6bSGordon Ross if (ucdom == NULL) { 638613a2f6bSGordon Ross err = ENOMEM; 639613a2f6bSGordon Ross goto out; 640613a2f6bSGordon Ross } 641613a2f6bSGordon Ross smb_put_blob_name(mbp, ucdom, NAMETYPE_DOMAIN_NB); 642613a2f6bSGordon Ross smb_put_blob_name(mbp, NULL, NAMETYPE_EOL); 643613a2f6bSGordon Ross /* OK, that's the whole "target info." blob! */ 644613a2f6bSGordon Ross } 645613a2f6bSGordon Ross err = 0; 646613a2f6bSGordon Ross 647613a2f6bSGordon Ross out: 648613a2f6bSGordon Ross free(ucdom); 649613a2f6bSGordon Ross return (err); 650613a2f6bSGordon Ross } 651*85e6b674SGordon Ross 652*85e6b674SGordon Ross /* 653*85e6b674SGordon Ross * Build the MAC key (for SMB signing) 654*85e6b674SGordon Ross */ 655*85e6b674SGordon Ross int 656*85e6b674SGordon Ross ntlm_build_mac_key(struct smb_ctx *ctx, struct mbdata *ntresp_mbp) 657*85e6b674SGordon Ross { 658*85e6b674SGordon Ross struct mbuf *m; 659*85e6b674SGordon Ross size_t len; 660*85e6b674SGordon Ross char *p; 661*85e6b674SGordon Ross 662*85e6b674SGordon Ross /* 663*85e6b674SGordon Ross * MAC_key = concat(session_key, nt_response) 664*85e6b674SGordon Ross */ 665*85e6b674SGordon Ross m = ntresp_mbp->mb_top; 666*85e6b674SGordon Ross len = NTLM_HASH_SZ + m->m_len; 667*85e6b674SGordon Ross if ((p = malloc(len)) == NULL) 668*85e6b674SGordon Ross return (ENOMEM); 669*85e6b674SGordon Ross ctx->ct_mackeylen = len; 670*85e6b674SGordon Ross ctx->ct_mackey = p; 671*85e6b674SGordon Ross memcpy(p, ctx->ct_ssn_key, NTLM_HASH_SZ); 672*85e6b674SGordon Ross memcpy(p + NTLM_HASH_SZ, m->m_data, m->m_len); 673*85e6b674SGordon Ross 674*85e6b674SGordon Ross return (0); 675*85e6b674SGordon Ross } 676*85e6b674SGordon Ross 677*85e6b674SGordon Ross /* 678*85e6b674SGordon Ross * Helper for ntlmssp_put_type3 - Build the "key exchange key" 679*85e6b674SGordon Ross * used when we have both NTLM(v1) and NTLMSSP_NEGOTIATE_NTLM2. 680*85e6b674SGordon Ross * HMAC_MD5(SessionBaseKey, concat(ServerChallenge, LmResponse[0..7])) 681*85e6b674SGordon Ross */ 682*85e6b674SGordon Ross void 683*85e6b674SGordon Ross ntlm2_kxkey(struct smb_ctx *ctx, struct mbdata *lm_mbp, uchar_t *kxkey) 684*85e6b674SGordon Ross { 685*85e6b674SGordon Ross uchar_t data[NTLM_HASH_SZ]; 686*85e6b674SGordon Ross uchar_t *p = mtod(lm_mbp->mb_top, uchar_t *); 687*85e6b674SGordon Ross 688*85e6b674SGordon Ross /* concat(ServerChallenge, LmResponse[0..7]) */ 689*85e6b674SGordon Ross memcpy(data, ctx->ct_srv_chal, NTLM_CHAL_SZ); 690*85e6b674SGordon Ross memcpy(data + NTLM_CHAL_SZ, p, NTLM_CHAL_SZ); 691*85e6b674SGordon Ross 692*85e6b674SGordon Ross /* HMAC_MD5(SessionBaseKey, concat(...)) */ 693*85e6b674SGordon Ross HMACT64(kxkey, ctx->ct_ssn_key, NTLM_HASH_SZ, 694*85e6b674SGordon Ross data, NTLM_HASH_SZ); 695*85e6b674SGordon Ross } 696