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