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