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
ntlm_compute_lm_hash(uchar_t * hash,const char * pass)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
ntlm_compute_nt_hash(uchar_t * hash,const char * pass)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
ntlm_v1_response(uchar_t * resp,const uchar_t * hash,const uchar_t * chal,int clen)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
ntlm_v1_session_key(uchar_t * ssn_key,const uchar_t * nt_hash)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
ntlm_put_v1_responses(struct smb_ctx * ctx,struct mbdata * lm_mbp,struct mbdata * nt_mbp)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
ntlm_put_v1x_responses(struct smb_ctx * ctx,struct mbdata * lm_mbp,struct mbdata * nt_mbp)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
HMACT64(uchar_t * digest,const uchar_t * key,size_t key_len,const uchar_t * data,size_t data_len)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
ntlm_v2_hash(uchar_t * v2hash,const uchar_t * v1hash,const char * user,const char * destination)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
ntlm_v2_resp_hash(uchar_t * rhash,const uchar_t * v2hash,const uchar_t * C8,const uchar_t * client_data,size_t cdlen)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
ntlm_v2_session_key(uchar_t * ssn_key,const uchar_t * v2hash,const uchar_t * ntresp)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
ntlm_put_v2_responses(struct smb_ctx * ctx,struct mbdata * ti_mbp,struct mbdata * lm_mbp,struct mbdata * nt_mbp)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
smb_put_blob_name(struct mbdata * mbp,char * name,int type)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
ntlm_build_target_info(struct smb_ctx * ctx,struct mbuf * names,struct mbdata * mbp)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
ntlm_build_mac_key(struct smb_ctx * ctx,struct mbdata * ntresp_mbp)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
ntlm2_kxkey(struct smb_ctx * ctx,struct mbdata * lm_mbp,uchar_t * kxkey)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