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