1/* $NetBSD: ntlm.c,v 1.5 2023/06/19 21:41:45 christos Exp $ */ 2 3/* 4 * Copyright (c) 2006 - 2008 Kungliga Tekniska H��gskolan 5 * (Royal Institute of Technology, Stockholm, Sweden). 6 * All rights reserved. 7 * 8 * Portions Copyright (c) 2010 Apple Inc. All rights reserved. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 17 * 2. Redistributions in binary form must reproduce the above copyright 18 * notice, this list of conditions and the following disclaimer in the 19 * documentation and/or other materials provided with the distribution. 20 * 21 * 3. Neither the name of the Institute nor the names of its contributors 22 * may be used to endorse or promote products derived from this software 23 * without specific prior written permission. 24 * 25 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 28 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 29 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 31 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 35 * SUCH DAMAGE. 36 */ 37 38#include <config.h> 39 40#include <stdio.h> 41#include <stdlib.h> 42#include <assert.h> 43#include <string.h> 44#include <ctype.h> 45#include <errno.h> 46#include <limits.h> 47 48#include <krb5/roken.h> 49 50#include <krb5/wind.h> 51#include <krb5/parse_units.h> 52#include <krb5/krb5.h> 53 54 55#define HC_DEPRECATED_CRYPTO 56 57#include <krb5/krb5-types.h> 58#include "crypto-headers.h" 59 60#include <krb5/heimntlm.h> 61 62/*! \mainpage Heimdal NTLM library 63 * 64 * \section intro Introduction 65 * 66 * Heimdal libheimntlm library is a implementation of the NTLM 67 * protocol, both version 1 and 2. The GSS-API mech that uses this 68 * library adds support for transport encryption and integrity 69 * checking. 70 * 71 * NTLM is a protocol for mutual authentication, its still used in 72 * many protocol where Kerberos is not support, one example is 73 * EAP/X802.1x mechanism LEAP from Microsoft and Cisco. 74 * 75 * This is a support library for the core protocol, its used in 76 * Heimdal to implement and GSS-API mechanism. There is also support 77 * in the KDC to do remote digest authenticiation, this to allow 78 * services to authenticate users w/o direct access to the users ntlm 79 * hashes (same as Kerberos arcfour enctype keys). 80 * 81 * More information about the NTLM protocol can found here 82 * http://davenport.sourceforge.net/ntlm.html . 83 * 84 * The Heimdal projects web page: http://www.h5l.org/ 85 * 86 * @section ntlm_example NTLM Example 87 * 88 * Example to to use @ref test_ntlm.c . 89 * 90 * @example test_ntlm.c 91 * 92 * Example how to use the NTLM primitives. 93 * 94 */ 95 96/** @defgroup ntlm_core Heimdal NTLM library 97 * 98 * The NTLM core functions implement the string2key generation 99 * function, message encode and decode function, and the hash function 100 * functions. 101 */ 102 103struct sec_buffer { 104 uint16_t length; 105 uint16_t allocated; 106 uint32_t offset; 107}; 108 109static const unsigned char ntlmsigature[8] = "NTLMSSP\x00"; 110 111time_t heim_ntlm_time_skew = 300; 112 113/* 114 * 115 */ 116 117#define CHECK(f, e) \ 118 do { \ 119 ret = f; \ 120 if (ret != (ssize_t)(e)) { \ 121 ret = HNTLM_ERR_DECODE; \ 122 goto out; \ 123 } \ 124 } while(/*CONSTCOND*/0) 125 126#define CHECK_SIZE(f, e) \ 127 do { \ 128 ssize_t sret = f; \ 129 if (sret != (ssize_t)(e)) { \ 130 ret = HNTLM_ERR_DECODE; \ 131 goto out; \ 132 } \ 133 } while(/*CONSTCOND*/0) 134 135#define CHECK_OFFSET(f, e) \ 136 do { \ 137 off_t sret = f; \ 138 if (sret != (e)) { \ 139 ret = HNTLM_ERR_DECODE; \ 140 goto out; \ 141 } \ 142 } while(/*CONSTCOND*/0) 143 144 145static struct units ntlm_flag_units[] = { 146#define ntlm_flag(x) { #x, NTLM_##x } 147 ntlm_flag(ENC_56), 148 ntlm_flag(NEG_KEYEX), 149 ntlm_flag(ENC_128), 150 ntlm_flag(MBZ1), 151 ntlm_flag(MBZ2), 152 ntlm_flag(MBZ3), 153 ntlm_flag(NEG_VERSION), 154 ntlm_flag(MBZ4), 155 ntlm_flag(NEG_TARGET_INFO), 156 ntlm_flag(NON_NT_SESSION_KEY), 157 ntlm_flag(MBZ5), 158 ntlm_flag(NEG_IDENTIFY), 159 ntlm_flag(NEG_NTLM2), 160 ntlm_flag(TARGET_SHARE), 161 ntlm_flag(TARGET_SERVER), 162 ntlm_flag(TARGET_DOMAIN), 163 ntlm_flag(NEG_ALWAYS_SIGN), 164 ntlm_flag(MBZ6), 165 ntlm_flag(OEM_SUPPLIED_WORKSTATION), 166 ntlm_flag(OEM_SUPPLIED_DOMAIN), 167 ntlm_flag(NEG_ANONYMOUS), 168 ntlm_flag(NEG_NT_ONLY), 169 ntlm_flag(NEG_NTLM), 170 ntlm_flag(MBZ8), 171 ntlm_flag(NEG_LM_KEY), 172 ntlm_flag(NEG_DATAGRAM), 173 ntlm_flag(NEG_SEAL), 174 ntlm_flag(NEG_SIGN), 175 ntlm_flag(MBZ9), 176 ntlm_flag(NEG_TARGET), 177 ntlm_flag(NEG_OEM), 178 ntlm_flag(NEG_UNICODE), 179#undef ntlm_flag 180 {NULL, 0} 181}; 182 183size_t 184heim_ntlm_unparse_flags(uint32_t flags, char *s, size_t len) 185{ 186 return unparse_flags(flags, ntlm_flag_units, s, len); 187} 188 189 190/** 191 * heim_ntlm_free_buf frees the ntlm buffer 192 * 193 * @param p buffer to be freed 194 * 195 * @ingroup ntlm_core 196 */ 197 198void 199heim_ntlm_free_buf(struct ntlm_buf *p) 200{ 201 if (p->data) 202 free(p->data); 203 p->data = NULL; 204 p->length = 0; 205} 206 207 208static int 209ascii2ucs2le(const char *string, int up, struct ntlm_buf *buf) 210{ 211 uint16_t *data; 212 size_t len, n; 213 uint8_t *p; 214 int ret; 215 216 ret = wind_utf8ucs2_length(string, &len); 217 if (ret) 218 return ret; 219 if (len > UINT_MAX / sizeof(data[0])) 220 return ERANGE; 221 222 data = malloc(len * sizeof(data[0])); 223 if (data == NULL) 224 return ENOMEM; 225 226 ret = wind_utf8ucs2(string, data, &len); 227 if (ret) { 228 free(data); 229 return ret; 230 } 231 232 if (len == 0) { 233 free(data); 234 buf->data = NULL; 235 buf->length = 0; 236 return 0; 237 } 238 239 /* uppercase string, only handle ascii right now */ 240 if (up) { 241 for (n = 0; n < len ; n++) { 242 if (data[n] < 128) 243 data[n] = toupper((int)data[n]); 244 } 245 } 246 247 buf->length = len * 2; 248 p = buf->data = malloc(buf->length); 249 if (buf->data == NULL && len != 0) { 250 free(data); 251 heim_ntlm_free_buf(buf); 252 return ENOMEM; 253 } 254 255 for (n = 0; n < len ; n++) { 256 p[(n * 2) + 0] = (data[n] ) & 0xff; 257 p[(n * 2) + 1] = (data[n] >> 8) & 0xff; 258 } 259 memset(data, 0, sizeof(data[0]) * len); 260 free(data); 261 262 return 0; 263} 264 265/* 266 * Sizes in bytes 267 */ 268 269#define SIZE_SEC_BUFFER (2+2+4) 270#define SIZE_OS_VERSION (8) 271 272/* 273 * 274 */ 275 276static krb5_error_code 277ret_sec_buffer(krb5_storage *sp, struct sec_buffer *buf) 278{ 279 krb5_error_code ret; 280 CHECK(krb5_ret_uint16(sp, &buf->length), 0); 281 CHECK(krb5_ret_uint16(sp, &buf->allocated), 0); 282 CHECK(krb5_ret_uint32(sp, &buf->offset), 0); 283out: 284 return ret; 285} 286 287static krb5_error_code 288store_sec_buffer(krb5_storage *sp, const struct sec_buffer *buf) 289{ 290 krb5_error_code ret; 291 CHECK(krb5_store_uint16(sp, buf->length), 0); 292 CHECK(krb5_store_uint16(sp, buf->allocated), 0); 293 CHECK(krb5_store_uint32(sp, buf->offset), 0); 294out: 295 return ret; 296} 297 298/* 299 * Strings are either OEM or UNICODE. The later is encoded as ucs2 on 300 * wire, but using utf8 in memory. 301 */ 302 303static size_t 304len_string(int ucs2, const char *s) 305{ 306 if (ucs2) { 307 size_t len; 308 int ret; 309 310 ret = wind_utf8ucs2_length(s, &len); 311 if (ret == 0) 312 return len * 2; 313 return strlen(s) * 5 * 2; 314 } else { 315 return strlen(s); 316 } 317} 318 319/* 320 * 321 */ 322 323static krb5_error_code 324ret_string(krb5_storage *sp, int ucs2, size_t len, char **s) 325{ 326 krb5_error_code ret; 327 uint16_t *data = NULL; 328 329 *s = malloc(len + 1); 330 if (*s == NULL) 331 return ENOMEM; 332 CHECK_SIZE(krb5_storage_read(sp, *s, len), len); 333 334 (*s)[len] = '\0'; 335 336 if (ucs2) { 337 unsigned int flags = WIND_RW_LE; 338 size_t utf16len = len / 2; 339 size_t utf8len; 340 341 data = malloc(utf16len * sizeof(data[0])); 342 if (data == NULL) { 343 free(*s); *s = NULL; 344 ret = ENOMEM; 345 goto out; 346 } 347 348 ret = wind_ucs2read(*s, len, &flags, data, &utf16len); 349 free(*s); *s = NULL; 350 if (ret) { 351 goto out; 352 } 353 354 CHECK(wind_ucs2utf8_length(data, utf16len, &utf8len), 0); 355 356 utf8len += 1; 357 358 *s = malloc(utf8len); 359 if (s == NULL) { 360 ret = ENOMEM; 361 goto out; 362 } 363 364 CHECK(wind_ucs2utf8(data, utf16len, *s, &utf8len), 0); 365 } 366 ret = 0; 367 out: 368 if (data) 369 free(data); 370 371 return ret; 372} 373 374 375 376static krb5_error_code 377ret_sec_string(krb5_storage *sp, int ucs2, struct sec_buffer *desc, char **s) 378{ 379 krb5_error_code ret = 0; 380 CHECK_OFFSET(krb5_storage_seek(sp, desc->offset, SEEK_SET), desc->offset); 381 CHECK(ret_string(sp, ucs2, desc->length, s), 0); 382 out: 383 return ret; 384} 385 386static krb5_error_code 387put_string(krb5_storage *sp, int ucs2, const char *s) 388{ 389 krb5_error_code ret; 390 struct ntlm_buf buf; 391 392 if (ucs2) { 393 ret = ascii2ucs2le(s, 0, &buf); 394 if (ret) 395 return ret; 396 } else { 397 buf.data = rk_UNCONST(s); 398 buf.length = strlen(s); 399 } 400 401 CHECK_SIZE(krb5_storage_write(sp, buf.data, buf.length), buf.length); 402 if (ucs2) 403 heim_ntlm_free_buf(&buf); 404 ret = 0; 405out: 406 return ret; 407} 408 409/* 410 * 411 */ 412 413static krb5_error_code 414ret_buf(krb5_storage *sp, struct sec_buffer *desc, struct ntlm_buf *buf) 415{ 416 krb5_error_code ret; 417 418 buf->data = malloc(desc->length); 419 buf->length = desc->length; 420 CHECK_OFFSET(krb5_storage_seek(sp, desc->offset, SEEK_SET), desc->offset); 421 CHECK_SIZE(krb5_storage_read(sp, buf->data, buf->length), buf->length); 422 ret = 0; 423out: 424 return ret; 425} 426 427static krb5_error_code 428put_buf(krb5_storage *sp, const struct ntlm_buf *buf) 429{ 430 krb5_error_code ret; 431 CHECK_SIZE(krb5_storage_write(sp, buf->data, buf->length), buf->length); 432 ret = 0; 433out: 434 return ret; 435} 436 437/** 438 * Frees the ntlm_targetinfo message 439 * 440 * @param ti targetinfo to be freed 441 * 442 * @ingroup ntlm_core 443 */ 444 445void 446heim_ntlm_free_targetinfo(struct ntlm_targetinfo *ti) 447{ 448 free(ti->servername); 449 free(ti->domainname); 450 free(ti->dnsdomainname); 451 free(ti->dnsservername); 452 free(ti->dnstreename); 453 free(ti->targetname); 454 heim_ntlm_free_buf(&ti->channel_bindings); 455 memset(ti, 0, sizeof(*ti)); 456} 457 458static int 459encode_ti_string(krb5_storage *out, uint16_t type, int ucs2, char *s) 460{ 461 krb5_error_code ret; 462 CHECK(krb5_store_uint16(out, type), 0); 463 CHECK(krb5_store_uint16(out, len_string(ucs2, s)), 0); 464 CHECK(put_string(out, ucs2, s), 0); 465out: 466 return ret; 467} 468 469/** 470 * Encodes a ntlm_targetinfo message. 471 * 472 * @param ti the ntlm_targetinfo message to encode. 473 * @param ucs2 ignored 474 * @param data is the return buffer with the encoded message, should be 475 * freed with heim_ntlm_free_buf(). 476 * 477 * @return In case of success 0 is return, an errors, a errno in what 478 * went wrong. 479 * 480 * @ingroup ntlm_core 481 */ 482 483int 484heim_ntlm_encode_targetinfo(const struct ntlm_targetinfo *ti, 485 int ucs2, 486 struct ntlm_buf *data) 487{ 488 krb5_error_code ret; 489 krb5_storage *out; 490 491 data->data = NULL; 492 data->length = 0; 493 494 out = krb5_storage_emem(); 495 if (out == NULL) 496 return ENOMEM; 497 498 krb5_storage_set_byteorder(out, KRB5_STORAGE_BYTEORDER_LE); 499 500 if (ti->servername) 501 CHECK(encode_ti_string(out, 1, ucs2, ti->servername), 0); 502 if (ti->domainname) 503 CHECK(encode_ti_string(out, 2, ucs2, ti->domainname), 0); 504 if (ti->dnsservername) 505 CHECK(encode_ti_string(out, 3, ucs2, ti->dnsservername), 0); 506 if (ti->dnsdomainname) 507 CHECK(encode_ti_string(out, 4, ucs2, ti->dnsdomainname), 0); 508 if (ti->dnstreename) 509 CHECK(encode_ti_string(out, 5, ucs2, ti->dnstreename), 0); 510 if (ti->avflags) { 511 CHECK(krb5_store_uint16(out, 6), 0); 512 CHECK(krb5_store_uint16(out, 4), 0); 513 CHECK(krb5_store_uint32(out, ti->avflags), 0); 514 } 515 if (ti->timestamp) { 516 CHECK(krb5_store_uint16(out, 7), 0); 517 CHECK(krb5_store_uint16(out, 8), 0); 518 CHECK(krb5_store_uint32(out, ti->timestamp & 0xffffffff), 0); 519 CHECK(krb5_store_uint32(out, (ti->timestamp >> 32) & 0xffffffff), 0); 520 } 521 if (ti->targetname) { 522 CHECK(encode_ti_string(out, 9, ucs2, ti->targetname), 0); 523 } 524 if (ti->channel_bindings.length) { 525 CHECK(krb5_store_uint16(out, 10), 0); 526 CHECK(krb5_store_uint16(out, ti->channel_bindings.length), 0); 527 CHECK_SIZE(krb5_storage_write(out, ti->channel_bindings.data, ti->channel_bindings.length), ti->channel_bindings.length); 528 } 529 530 /* end tag */ 531 CHECK(krb5_store_int16(out, 0), 0); 532 CHECK(krb5_store_int16(out, 0), 0); 533 534 { 535 krb5_data d; 536 ret = krb5_storage_to_data(out, &d); 537 data->data = d.data; 538 data->length = d.length; 539 } 540out: 541 krb5_storage_free(out); 542 return ret; 543} 544 545/** 546 * Decodes an NTLM targetinfo message 547 * 548 * @param data input data buffer with the encode NTLM targetinfo message 549 * @param ucs2 if the strings should be encoded with ucs2 (selected by flag in message). 550 * @param ti the decoded target info, should be freed with heim_ntlm_free_targetinfo(). 551 * 552 * @return In case of success 0 is return, an errors, a errno in what 553 * went wrong. 554 * 555 * @ingroup ntlm_core 556 */ 557 558int 559heim_ntlm_decode_targetinfo(const struct ntlm_buf *data, 560 int ucs2, 561 struct ntlm_targetinfo *ti) 562{ 563 uint16_t type, len; 564 krb5_storage *in; 565 int ret = 0, done = 0; 566 567 memset(ti, 0, sizeof(*ti)); 568 569 if (data->length == 0) 570 return 0; 571 572 in = krb5_storage_from_readonly_mem(data->data, data->length); 573 if (in == NULL) 574 return ENOMEM; 575 krb5_storage_set_byteorder(in, KRB5_STORAGE_BYTEORDER_LE); 576 577 while (!done) { 578 CHECK(krb5_ret_uint16(in, &type), 0); 579 CHECK(krb5_ret_uint16(in, &len), 0); 580 581 switch (type) { 582 case 0: 583 done = 1; 584 break; 585 case 1: 586 CHECK(ret_string(in, ucs2, len, &ti->servername), 0); 587 break; 588 case 2: 589 CHECK(ret_string(in, ucs2, len, &ti->domainname), 0); 590 break; 591 case 3: 592 CHECK(ret_string(in, ucs2, len, &ti->dnsservername), 0); 593 break; 594 case 4: 595 CHECK(ret_string(in, ucs2, len, &ti->dnsdomainname), 0); 596 break; 597 case 5: 598 CHECK(ret_string(in, ucs2, len, &ti->dnstreename), 0); 599 break; 600 case 6: 601 CHECK(krb5_ret_uint32(in, &ti->avflags), 0); 602 break; 603 case 7: { 604 uint32_t tmp; 605 CHECK(krb5_ret_uint32(in, &tmp), 0); 606 ti->timestamp = tmp; 607 CHECK(krb5_ret_uint32(in, &tmp), 0); 608 ti->timestamp |= ((uint64_t)tmp) << 32; 609 break; 610 } 611 case 9: 612 CHECK(ret_string(in, 1, len, &ti->targetname), 0); 613 break; 614 case 10: 615 ti->channel_bindings.data = malloc(len); 616 if (ti->channel_bindings.data == NULL) { 617 ret = ENOMEM; 618 goto out; 619 } 620 ti->channel_bindings.length = len; 621 CHECK_SIZE(krb5_storage_read(in, ti->channel_bindings.data, len), len); 622 break; 623 default: 624 krb5_storage_seek(in, len, SEEK_CUR); 625 break; 626 } 627 } 628 out: 629 if (in) 630 krb5_storage_free(in); 631 return ret; 632} 633 634static krb5_error_code 635encode_os_version(krb5_storage *out) 636{ 637 krb5_error_code ret; 638 CHECK(krb5_store_uint8(out, 0x06), 0); 639 CHECK(krb5_store_uint8(out, 0x01), 0); 640 CHECK(krb5_store_uint16(out, 0x1db0), 0); 641 CHECK(krb5_store_uint8(out, 0x0f), 0); /* ntlm version 15 */ 642 CHECK(krb5_store_uint8(out, 0x00), 0); 643 CHECK(krb5_store_uint8(out, 0x00), 0); 644 CHECK(krb5_store_uint8(out, 0x00), 0); 645 out: 646 return ret; 647} 648 649/** 650 * Frees the ntlm_type1 message 651 * 652 * @param data message to be freed 653 * 654 * @ingroup ntlm_core 655 */ 656 657void 658heim_ntlm_free_type1(struct ntlm_type1 *data) 659{ 660 if (data->domain) 661 free(data->domain); 662 if (data->hostname) 663 free(data->hostname); 664 memset(data, 0, sizeof(*data)); 665} 666 667int 668heim_ntlm_decode_type1(const struct ntlm_buf *buf, struct ntlm_type1 *data) 669{ 670 krb5_error_code ret; 671 unsigned char sig[8]; 672 uint32_t type; 673 struct sec_buffer domain, hostname; 674 krb5_storage *in; 675 int ucs2; 676 677 memset(data, 0, sizeof(*data)); 678 679 in = krb5_storage_from_readonly_mem(buf->data, buf->length); 680 if (in == NULL) { 681 ret = ENOMEM; 682 goto out; 683 } 684 krb5_storage_set_byteorder(in, KRB5_STORAGE_BYTEORDER_LE); 685 686 CHECK_SIZE(krb5_storage_read(in, sig, sizeof(sig)), sizeof(sig)); 687 CHECK(memcmp(ntlmsigature, sig, sizeof(ntlmsigature)), 0); 688 CHECK(krb5_ret_uint32(in, &type), 0); 689 CHECK(type, 1); 690 CHECK(krb5_ret_uint32(in, &data->flags), 0); 691 692 ucs2 = !!(data->flags & NTLM_NEG_UNICODE); 693 694 /* 695 * domain and hostname are unconditionally encoded regardless of 696 * NTLMSSP_NEGOTIATE_OEM_{HOSTNAME,WORKSTATION}_SUPPLIED flag 697 */ 698 CHECK(ret_sec_buffer(in, &domain), 0); 699 CHECK(ret_sec_buffer(in, &hostname), 0); 700 701 if (data->flags & NTLM_NEG_VERSION) { 702 CHECK(krb5_ret_uint32(in, &data->os[0]), 0); 703 CHECK(krb5_ret_uint32(in, &data->os[1]), 0); 704 } 705 706 if (data->flags & NTLM_OEM_SUPPLIED_DOMAIN) 707 CHECK(ret_sec_string(in, ucs2, &domain, &data->domain), 0); 708 if (data->flags & NTLM_OEM_SUPPLIED_WORKSTATION) 709 CHECK(ret_sec_string(in, ucs2, &hostname, &data->hostname), 0); 710 711out: 712 if (in) 713 krb5_storage_free(in); 714 if (ret) 715 heim_ntlm_free_type1(data); 716 717 return ret; 718} 719 720/** 721 * Encodes an ntlm_type1 message. 722 * 723 * @param type1 the ntlm_type1 message to encode. 724 * @param data is the return buffer with the encoded message, should be 725 * freed with heim_ntlm_free_buf(). 726 * 727 * @return In case of success 0 is return, an errors, a errno in what 728 * went wrong. 729 * 730 * @ingroup ntlm_core 731 */ 732 733int 734heim_ntlm_encode_type1(const struct ntlm_type1 *type1, struct ntlm_buf *data) 735{ 736 krb5_error_code ret; 737 struct sec_buffer domain, hostname; 738 krb5_storage *out; 739 uint32_t base, flags; 740 int ucs2 = 0; 741 742 flags = type1->flags; 743 base = 16; 744 745 if (flags & NTLM_NEG_UNICODE) 746 ucs2 = 1; 747 748 if (type1->domain) { 749 base += SIZE_SEC_BUFFER; 750 flags |= NTLM_OEM_SUPPLIED_DOMAIN; 751 } 752 if (type1->hostname) { 753 base += SIZE_SEC_BUFFER; 754 flags |= NTLM_OEM_SUPPLIED_WORKSTATION; 755 } 756 if (flags & NTLM_NEG_VERSION) 757 base += SIZE_OS_VERSION; /* os */ 758 759 if (type1->domain) { 760 domain.offset = base; 761 domain.length = len_string(ucs2, type1->domain); 762 domain.allocated = domain.length; 763 } else { 764 domain.offset = 0; 765 domain.length = 0; 766 domain.allocated = 0; 767 } 768 769 if (type1->hostname) { 770 hostname.offset = domain.allocated + domain.offset; 771 hostname.length = len_string(ucs2, type1->hostname); 772 hostname.allocated = hostname.length; 773 } else { 774 hostname.offset = 0; 775 hostname.length = 0; 776 hostname.allocated = 0; 777 } 778 779 out = krb5_storage_emem(); 780 if (out == NULL) 781 return ENOMEM; 782 783 krb5_storage_set_byteorder(out, KRB5_STORAGE_BYTEORDER_LE); 784 CHECK_SIZE(krb5_storage_write(out, ntlmsigature, sizeof(ntlmsigature)), 785 sizeof(ntlmsigature)); 786 CHECK(krb5_store_uint32(out, 1), 0); 787 CHECK(krb5_store_uint32(out, flags), 0); 788 789 CHECK(store_sec_buffer(out, &domain), 0); 790 CHECK(store_sec_buffer(out, &hostname), 0); 791 792 if (flags & NTLM_NEG_VERSION) { 793 CHECK(encode_os_version(out), 0); 794 } 795 if (type1->domain) 796 CHECK(put_string(out, ucs2, type1->domain), 0); 797 if (type1->hostname) 798 CHECK(put_string(out, ucs2, type1->hostname), 0); 799 800 { 801 krb5_data d; 802 ret = krb5_storage_to_data(out, &d); 803 data->data = d.data; 804 data->length = d.length; 805 } 806out: 807 krb5_storage_free(out); 808 809 return ret; 810} 811 812/** 813 * Frees the ntlm_type2 message 814 * 815 * @param data message to be freed 816 * 817 * @ingroup ntlm_core 818 */ 819 820void 821heim_ntlm_free_type2(struct ntlm_type2 *data) 822{ 823 if (data->targetname) 824 free(data->targetname); 825 heim_ntlm_free_buf(&data->targetinfo); 826 memset(data, 0, sizeof(*data)); 827} 828 829int 830heim_ntlm_decode_type2(const struct ntlm_buf *buf, struct ntlm_type2 *type2) 831{ 832 krb5_error_code ret; 833 unsigned char sig[8]; 834 uint32_t type, ctx[2]; 835 struct sec_buffer targetname, targetinfo; 836 krb5_storage *in; 837 int ucs2 = 0; 838 839 memset(type2, 0, sizeof(*type2)); 840 841 in = krb5_storage_from_readonly_mem(buf->data, buf->length); 842 if (in == NULL) { 843 ret = ENOMEM; 844 goto out; 845 } 846 krb5_storage_set_byteorder(in, KRB5_STORAGE_BYTEORDER_LE); 847 848 CHECK_SIZE(krb5_storage_read(in, sig, sizeof(sig)), sizeof(sig)); 849 CHECK(memcmp(ntlmsigature, sig, sizeof(ntlmsigature)), 0); 850 CHECK(krb5_ret_uint32(in, &type), 0); 851 CHECK(type, 2); 852 853 CHECK(ret_sec_buffer(in, &targetname), 0); 854 CHECK(krb5_ret_uint32(in, &type2->flags), 0); 855 if (type2->flags & NTLM_NEG_UNICODE) 856 ucs2 = 1; 857 CHECK_SIZE(krb5_storage_read(in, type2->challenge, sizeof(type2->challenge)), 858 sizeof(type2->challenge)); 859 CHECK(krb5_ret_uint32(in, &ctx[0]), 0); /* context */ 860 CHECK(krb5_ret_uint32(in, &ctx[1]), 0); 861 CHECK(ret_sec_buffer(in, &targetinfo), 0); 862 /* os version */ 863 if (type2->flags & NTLM_NEG_VERSION) { 864 CHECK(krb5_ret_uint32(in, &type2->os[0]), 0); 865 CHECK(krb5_ret_uint32(in, &type2->os[1]), 0); 866 } 867 868 CHECK(ret_sec_string(in, ucs2, &targetname, &type2->targetname), 0); 869 CHECK(ret_buf(in, &targetinfo, &type2->targetinfo), 0); 870 ret = 0; 871 872out: 873 if (in) 874 krb5_storage_free(in); 875 if (ret) 876 heim_ntlm_free_type2(type2); 877 878 return ret; 879} 880 881/** 882 * Encodes an ntlm_type2 message. 883 * 884 * @param type2 the ntlm_type2 message to encode. 885 * @param data is the return buffer with the encoded message, should be 886 * freed with heim_ntlm_free_buf(). 887 * 888 * @return In case of success 0 is return, an errors, a errno in what 889 * went wrong. 890 * 891 * @ingroup ntlm_core 892 */ 893 894int 895heim_ntlm_encode_type2(const struct ntlm_type2 *type2, struct ntlm_buf *data) 896{ 897 struct sec_buffer targetname, targetinfo; 898 krb5_error_code ret; 899 krb5_storage *out = NULL; 900 uint32_t base; 901 int ucs2 = 0; 902 903 base = 48; 904 905 if (type2->flags & NTLM_NEG_VERSION) 906 base += SIZE_OS_VERSION; 907 908 if (type2->flags & NTLM_NEG_UNICODE) 909 ucs2 = 1; 910 911 targetname.offset = base; 912 targetname.length = len_string(ucs2, type2->targetname); 913 targetname.allocated = targetname.length; 914 915 targetinfo.offset = targetname.allocated + targetname.offset; 916 targetinfo.length = type2->targetinfo.length; 917 targetinfo.allocated = type2->targetinfo.length; 918 919 out = krb5_storage_emem(); 920 if (out == NULL) 921 return ENOMEM; 922 923 krb5_storage_set_byteorder(out, KRB5_STORAGE_BYTEORDER_LE); 924 CHECK_SIZE(krb5_storage_write(out, ntlmsigature, sizeof(ntlmsigature)), 925 sizeof(ntlmsigature)); 926 CHECK(krb5_store_uint32(out, 2), 0); 927 CHECK(store_sec_buffer(out, &targetname), 0); 928 CHECK(krb5_store_uint32(out, type2->flags), 0); 929 CHECK_SIZE(krb5_storage_write(out, type2->challenge, sizeof(type2->challenge)), 930 sizeof(type2->challenge)); 931 CHECK(krb5_store_uint32(out, 0), 0); /* context */ 932 CHECK(krb5_store_uint32(out, 0), 0); 933 CHECK(store_sec_buffer(out, &targetinfo), 0); 934 /* os version */ 935 if (type2->flags & NTLM_NEG_VERSION) { 936 CHECK(encode_os_version(out), 0); 937 } 938 CHECK(put_string(out, ucs2, type2->targetname), 0); 939 CHECK_SIZE(krb5_storage_write(out, type2->targetinfo.data, 940 type2->targetinfo.length), 941 type2->targetinfo.length); 942 943 { 944 krb5_data d; 945 ret = krb5_storage_to_data(out, &d); 946 data->data = d.data; 947 data->length = d.length; 948 } 949 950out: 951 krb5_storage_free(out); 952 953 return ret; 954} 955 956/** 957 * Frees the ntlm_type3 message 958 * 959 * @param data message to be freed 960 * 961 * @ingroup ntlm_core 962 */ 963 964void 965heim_ntlm_free_type3(struct ntlm_type3 *data) 966{ 967 heim_ntlm_free_buf(&data->lm); 968 heim_ntlm_free_buf(&data->ntlm); 969 if (data->targetname) 970 free(data->targetname); 971 if (data->username) 972 free(data->username); 973 if (data->ws) 974 free(data->ws); 975 heim_ntlm_free_buf(&data->sessionkey); 976 memset(data, 0, sizeof(*data)); 977} 978 979/* 980 * 981 */ 982 983int 984heim_ntlm_decode_type3(const struct ntlm_buf *buf, 985 int ucs2, 986 struct ntlm_type3 *type3) 987{ 988 krb5_error_code ret; 989 unsigned char sig[8]; 990 uint32_t type; 991 krb5_storage *in; 992 struct sec_buffer lm, ntlm, target, username, sessionkey, ws; 993 uint32_t min_offset = 0xffffffff; 994 995 memset(type3, 0, sizeof(*type3)); 996 memset(&sessionkey, 0, sizeof(sessionkey)); 997 998 in = krb5_storage_from_readonly_mem(buf->data, buf->length); 999 if (in == NULL) { 1000 ret = ENOMEM; 1001 goto out; 1002 } 1003 krb5_storage_set_byteorder(in, KRB5_STORAGE_BYTEORDER_LE); 1004 1005 CHECK_SIZE(krb5_storage_read(in, sig, sizeof(sig)), sizeof(sig)); 1006 CHECK(memcmp(ntlmsigature, sig, sizeof(ntlmsigature)), 0); 1007 CHECK(krb5_ret_uint32(in, &type), 0); 1008 CHECK(type, 3); 1009 CHECK(ret_sec_buffer(in, &lm), 0); 1010 if (lm.allocated) 1011 min_offset = min(min_offset, lm.offset); 1012 CHECK(ret_sec_buffer(in, &ntlm), 0); 1013 if (ntlm.allocated) 1014 min_offset = min(min_offset, ntlm.offset); 1015 CHECK(ret_sec_buffer(in, &target), 0); 1016 min_offset = min(min_offset, target.offset); 1017 CHECK(ret_sec_buffer(in, &username), 0); 1018 min_offset = min(min_offset, username.offset); 1019 CHECK(ret_sec_buffer(in, &ws), 0); 1020 if (ws.allocated) 1021 min_offset = min(min_offset, ws.offset); 1022 1023 if (min_offset >= 52) { 1024 CHECK(ret_sec_buffer(in, &sessionkey), 0); 1025 min_offset = min(min_offset, sessionkey.offset); 1026 CHECK(krb5_ret_uint32(in, &type3->flags), 0); 1027 } 1028 if (min_offset >= 52 + SIZE_SEC_BUFFER + 4 + SIZE_OS_VERSION) { 1029 CHECK(krb5_ret_uint32(in, &type3->os[0]), 0); 1030 CHECK(krb5_ret_uint32(in, &type3->os[1]), 0); 1031 } 1032 if (min_offset >= 52 + SIZE_SEC_BUFFER + 4 + SIZE_OS_VERSION + 16) { 1033 type3->mic_offset = 52 + SIZE_SEC_BUFFER + 4 + SIZE_OS_VERSION; 1034 CHECK_SIZE(krb5_storage_read(in, type3->mic, sizeof(type3->mic)), sizeof(type3->mic)); 1035 } else 1036 type3->mic_offset = 0; 1037 CHECK(ret_buf(in, &lm, &type3->lm), 0); 1038 CHECK(ret_buf(in, &ntlm, &type3->ntlm), 0); 1039 CHECK(ret_sec_string(in, ucs2, &target, &type3->targetname), 0); 1040 CHECK(ret_sec_string(in, ucs2, &username, &type3->username), 0); 1041 CHECK(ret_sec_string(in, ucs2, &ws, &type3->ws), 0); 1042 if (sessionkey.offset) 1043 CHECK(ret_buf(in, &sessionkey, &type3->sessionkey), 0); 1044 1045out: 1046 if (in) 1047 krb5_storage_free(in); 1048 if (ret) 1049 heim_ntlm_free_type3(type3); 1050 1051 return ret; 1052} 1053 1054/** 1055 * Encodes an ntlm_type3 message. 1056 * 1057 * @param type3 the ntlm_type3 message to encode. 1058 * @param data is the return buffer with the encoded message, should be 1059 * @param[out] mic_offset offset of message integrity code 1060 * freed with heim_ntlm_free_buf(). 1061 * 1062 * @return In case of success 0 is return, an errors, a errno in what 1063 * went wrong. 1064 * 1065 * @ingroup ntlm_core 1066 */ 1067 1068int 1069heim_ntlm_encode_type3(const struct ntlm_type3 *type3, struct ntlm_buf *data, size_t *mic_offset) 1070{ 1071 struct sec_buffer lm, ntlm, target, username, sessionkey, ws; 1072 krb5_error_code ret; 1073 krb5_storage *out = NULL; 1074 uint32_t base; 1075 int ucs2 = 0; 1076 1077 memset(&lm, 0, sizeof(lm)); 1078 memset(&ntlm, 0, sizeof(ntlm)); 1079 memset(&target, 0, sizeof(target)); 1080 memset(&username, 0, sizeof(username)); 1081 memset(&ws, 0, sizeof(ws)); 1082 memset(&sessionkey, 0, sizeof(sessionkey)); 1083 1084 base = 52; 1085 1086 base += 8; /* sessionkey sec buf */ 1087 base += 4; /* flags */ 1088 if (type3->flags & NTLM_NEG_VERSION) 1089 base += SIZE_OS_VERSION; /* os flags */ 1090 1091 if (mic_offset) { 1092 *mic_offset = base; 1093 base += 16; 1094 } 1095 1096 if (type3->flags & NTLM_NEG_UNICODE) 1097 ucs2 = 1; 1098 1099 target.offset = base; 1100 target.length = len_string(ucs2, type3->targetname); 1101 target.allocated = target.length; 1102 1103 username.offset = target.offset + target.allocated; 1104 username.length = len_string(ucs2, type3->username); 1105 username.allocated = username.length; 1106 1107 ws.offset = username.offset + username.allocated; 1108 ws.length = len_string(ucs2, type3->ws); 1109 ws.allocated = ws.length; 1110 1111 lm.offset = ws.offset + ws.allocated; 1112 lm.length = type3->lm.length; 1113 lm.allocated = type3->lm.length; 1114 1115 ntlm.offset = lm.offset + lm.allocated; 1116 ntlm.length = type3->ntlm.length; 1117 ntlm.allocated = ntlm.length; 1118 1119 sessionkey.offset = ntlm.offset + ntlm.allocated; 1120 sessionkey.length = type3->sessionkey.length; 1121 sessionkey.allocated = type3->sessionkey.length; 1122 1123 out = krb5_storage_emem(); 1124 if (out == NULL) 1125 return ENOMEM; 1126 1127 krb5_storage_set_byteorder(out, KRB5_STORAGE_BYTEORDER_LE); 1128 CHECK_SIZE(krb5_storage_write(out, ntlmsigature, sizeof(ntlmsigature)), 1129 sizeof(ntlmsigature)); 1130 CHECK(krb5_store_uint32(out, 3), 0); 1131 1132 CHECK(store_sec_buffer(out, &lm), 0); 1133 CHECK(store_sec_buffer(out, &ntlm), 0); 1134 CHECK(store_sec_buffer(out, &target), 0); 1135 CHECK(store_sec_buffer(out, &username), 0); 1136 CHECK(store_sec_buffer(out, &ws), 0); 1137 CHECK(store_sec_buffer(out, &sessionkey), 0); 1138 CHECK(krb5_store_uint32(out, type3->flags), 0); 1139 1140 /* os version */ 1141 if (type3->flags & NTLM_NEG_VERSION) { 1142 CHECK(encode_os_version(out), 0); 1143 } 1144 1145 if (mic_offset) { 1146 static const uint8_t buf[16] = { 0 }; 1147 CHECK_SIZE(krb5_storage_write(out, buf, sizeof(buf)), sizeof(buf)); 1148 } 1149 1150 CHECK(put_string(out, ucs2, type3->targetname), 0); 1151 CHECK(put_string(out, ucs2, type3->username), 0); 1152 CHECK(put_string(out, ucs2, type3->ws), 0); 1153 CHECK(put_buf(out, &type3->lm), 0); 1154 CHECK(put_buf(out, &type3->ntlm), 0); 1155 CHECK(put_buf(out, &type3->sessionkey), 0); 1156 1157 { 1158 krb5_data d; 1159 ret = krb5_storage_to_data(out, &d); 1160 data->data = d.data; 1161 data->length = d.length; 1162 } 1163 1164out: 1165 krb5_storage_free(out); 1166 1167 return ret; 1168} 1169 1170 1171/* 1172 * 1173 */ 1174 1175static void 1176splitandenc(unsigned char *hash, 1177 unsigned char *challenge, 1178 unsigned char *answer) 1179{ 1180 EVP_CIPHER_CTX *ctx; 1181 unsigned char key[8]; 1182 1183 key[0] = hash[0]; 1184 key[1] = (hash[0] << 7) | (hash[1] >> 1); 1185 key[2] = (hash[1] << 6) | (hash[2] >> 2); 1186 key[3] = (hash[2] << 5) | (hash[3] >> 3); 1187 key[4] = (hash[3] << 4) | (hash[4] >> 4); 1188 key[5] = (hash[4] << 3) | (hash[5] >> 5); 1189 key[6] = (hash[5] << 2) | (hash[6] >> 6); 1190 key[7] = (hash[6] << 1); 1191 1192#if OPENSSL_VERSION_NUMBER < 0x10100000UL 1193 EVP_CIPHER_CTX ctxst; 1194 ctx = &ctxst; 1195 EVP_CIPHER_CTX_init(ctx); 1196#else 1197 ctx = EVP_CIPHER_CTX_new(); 1198#endif 1199 1200 if (!EVP_CipherInit_ex(ctx, EVP_des_cbc(), NULL, key, NULL, 1)) 1201 abort(); 1202 EVP_Cipher(ctx, answer, challenge, 8); 1203#if OPENSSL_VERSION_NUMBER < 0x10100000UL 1204 EVP_CIPHER_CTX_cleanup(ctx); 1205#else 1206 EVP_CIPHER_CTX_free(ctx); 1207#endif 1208 memset_s(key, sizeof(key), 0, sizeof(key)); 1209} 1210 1211/** 1212 * Calculate the NTLM key, the password is assumed to be in UTF8. 1213 * 1214 * @param password password to calcute the key for. 1215 * @param key calcuted key, should be freed with heim_ntlm_free_buf(). 1216 * 1217 * @return In case of success 0 is return, an errors, a errno in what 1218 * went wrong. 1219 * 1220 * @ingroup ntlm_core 1221 */ 1222 1223int 1224heim_ntlm_nt_key(const char *password, struct ntlm_buf *key) 1225{ 1226 struct ntlm_buf buf; 1227 EVP_MD_CTX *m; 1228 int ret; 1229 1230 key->data = malloc(MD4_DIGEST_LENGTH); 1231 if (key->data == NULL) 1232 return ENOMEM; 1233 key->length = MD4_DIGEST_LENGTH; 1234 1235 ret = ascii2ucs2le(password, 0, &buf); 1236 if (ret) { 1237 heim_ntlm_free_buf(key); 1238 return ret; 1239 } 1240 1241 m = EVP_MD_CTX_create(); 1242 if (m == NULL) { 1243 heim_ntlm_free_buf(key); 1244 heim_ntlm_free_buf(&buf); 1245 return ENOMEM; 1246 } 1247 1248 EVP_DigestInit_ex(m, EVP_md4(), NULL); 1249 EVP_DigestUpdate(m, buf.data, buf.length); 1250 EVP_DigestFinal_ex(m, key->data, NULL); 1251 EVP_MD_CTX_destroy(m); 1252 1253 heim_ntlm_free_buf(&buf); 1254 return 0; 1255} 1256 1257/** 1258 * Calculate NTLMv1 response hash 1259 * 1260 * @param key the ntlm v1 key 1261 * @param len length of key 1262 * @param challenge sent by the server 1263 * @param answer calculated answer, should be freed with heim_ntlm_free_buf(). 1264 * 1265 * @return In case of success 0 is return, an errors, a errno in what 1266 * went wrong. 1267 * 1268 * @ingroup ntlm_core 1269 */ 1270 1271int 1272heim_ntlm_calculate_ntlm1(void *key, size_t len, 1273 unsigned char challenge[8], 1274 struct ntlm_buf *answer) 1275{ 1276 unsigned char res[21]; 1277 1278 if (len != MD4_DIGEST_LENGTH) 1279 return HNTLM_ERR_INVALID_LENGTH; 1280 1281 memcpy(res, key, len); 1282 memset(&res[MD4_DIGEST_LENGTH], 0, sizeof(res) - MD4_DIGEST_LENGTH); 1283 1284 answer->data = malloc(24); 1285 if (answer->data == NULL) 1286 return ENOMEM; 1287 answer->length = 24; 1288 1289 splitandenc(&res[0], challenge, ((unsigned char *)answer->data) + 0); 1290 splitandenc(&res[7], challenge, ((unsigned char *)answer->data) + 8); 1291 splitandenc(&res[14], challenge, ((unsigned char *)answer->data) + 16); 1292 1293 return 0; 1294} 1295 1296int 1297heim_ntlm_v1_base_session(void *key, size_t len, 1298 struct ntlm_buf *session) 1299{ 1300 EVP_MD_CTX *m; 1301 1302 session->length = MD4_DIGEST_LENGTH; 1303 session->data = malloc(session->length); 1304 if (session->data == NULL) { 1305 session->length = 0; 1306 return ENOMEM; 1307 } 1308 1309 m = EVP_MD_CTX_create(); 1310 if (m == NULL) { 1311 heim_ntlm_free_buf(session); 1312 return ENOMEM; 1313 } 1314 EVP_DigestInit_ex(m, EVP_md4(), NULL); 1315 EVP_DigestUpdate(m, key, len); 1316 EVP_DigestFinal_ex(m, session->data, NULL); 1317 EVP_MD_CTX_destroy(m); 1318 1319 return 0; 1320} 1321 1322int 1323heim_ntlm_v2_base_session(void *key, size_t len, 1324 struct ntlm_buf *ntlmResponse, 1325 struct ntlm_buf *session) 1326{ 1327 unsigned int hmaclen; 1328 HMAC_CTX *c; 1329 1330 if (ntlmResponse->length <= 16) 1331 return HNTLM_ERR_INVALID_LENGTH; 1332 1333 session->data = malloc(16); 1334 if (session->data == NULL) 1335 return ENOMEM; 1336 session->length = 16; 1337 1338 /* Note: key is the NTLMv2 key */ 1339#if OPENSSL_VERSION_NUMBER < 0x10100000UL 1340 HMAC_CTX cs; 1341 c = &cs; 1342 HMAC_CTX_init(c); 1343#else 1344 c = HMAC_CTX_new(); 1345#endif 1346 HMAC_Init_ex(c, key, len, EVP_md5(), NULL); 1347 HMAC_Update(c, ntlmResponse->data, 16); 1348 HMAC_Final(c, session->data, &hmaclen); 1349#if OPENSSL_VERSION_NUMBER < 0x10100000UL 1350 HMAC_CTX_cleanup(c); 1351#else 1352 HMAC_CTX_free(c); 1353#endif 1354 1355 return 0; 1356} 1357 1358 1359int 1360heim_ntlm_keyex_wrap(struct ntlm_buf *base_session, 1361 struct ntlm_buf *session, 1362 struct ntlm_buf *encryptedSession) 1363{ 1364 EVP_CIPHER_CTX *c; 1365 int ret; 1366 1367 if (base_session->length != MD4_DIGEST_LENGTH) 1368 return HNTLM_ERR_INVALID_LENGTH; 1369 1370 session->length = MD4_DIGEST_LENGTH; 1371 session->data = malloc(session->length); 1372 if (session->data == NULL) { 1373 session->length = 0; 1374 return ENOMEM; 1375 } 1376 encryptedSession->length = MD4_DIGEST_LENGTH; 1377 encryptedSession->data = malloc(encryptedSession->length); 1378 if (encryptedSession->data == NULL) { 1379 heim_ntlm_free_buf(session); 1380 encryptedSession->length = 0; 1381 return ENOMEM; 1382 } 1383 1384#if OPENSSL_VERSION_NUMBER < 0x10100000UL 1385 EVP_CIPHER_CTX cs; 1386 c = &cs; 1387 EVP_CIPHER_CTX_init(c); 1388#else 1389 c = EVP_CIPHER_CTX_new(); 1390#endif 1391 1392 ret = EVP_CipherInit_ex(c, EVP_rc4(), NULL, base_session->data, NULL, 1); 1393 1394 if (ret != -1 || RAND_bytes(session->data, session->length) != 1) { 1395#if OPENSSL_VERSION_NUMBER < 0x10100000UL 1396 EVP_CIPHER_CTX_cleanup(c); 1397#else 1398 EVP_CIPHER_CTX_free(c); 1399#endif 1400 heim_ntlm_free_buf(encryptedSession); 1401 heim_ntlm_free_buf(session); 1402 return HNTLM_ERR_RAND; 1403 } 1404 1405 EVP_Cipher(c, encryptedSession->data, session->data, encryptedSession->length); 1406#if OPENSSL_VERSION_NUMBER < 0x10100000UL 1407 EVP_CIPHER_CTX_cleanup(c); 1408#else 1409 EVP_CIPHER_CTX_free(c); 1410#endif 1411 1412 return 0; 1413 1414 1415 1416} 1417 1418/** 1419 * Generates an NTLMv1 session random with assosited session master key. 1420 * 1421 * @param key the ntlm v1 key 1422 * @param len length of key 1423 * @param session generated session nonce, should be freed with heim_ntlm_free_buf(). 1424 * @param master calculated session master key, should be freed with heim_ntlm_free_buf(). 1425 * 1426 * @return In case of success 0 is return, an errors, a errno in what 1427 * went wrong. 1428 * 1429 * @ingroup ntlm_core 1430 */ 1431 1432int 1433heim_ntlm_build_ntlm1_master(void *key, size_t len, 1434 struct ntlm_buf *session, 1435 struct ntlm_buf *master) 1436{ 1437 struct ntlm_buf sess; 1438 int ret; 1439 1440 ret = heim_ntlm_v1_base_session(key, len, &sess); 1441 if (ret) 1442 return ret; 1443 1444 ret = heim_ntlm_keyex_wrap(&sess, session, master); 1445 heim_ntlm_free_buf(&sess); 1446 1447 return ret; 1448} 1449 1450/** 1451 * Generates an NTLMv2 session random with associated session master key. 1452 * 1453 * @param key the NTLMv2 key 1454 * @param len length of key 1455 * @param blob the NTLMv2 "blob" 1456 * @param session generated session nonce, should be freed with heim_ntlm_free_buf(). 1457 * @param master calculated session master key, should be freed with heim_ntlm_free_buf(). 1458 * 1459 * @return In case of success 0 is return, an errors, a errno in what 1460 * went wrong. 1461 * 1462 * @ingroup ntlm_core 1463 */ 1464 1465 1466int 1467heim_ntlm_build_ntlm2_master(void *key, size_t len, 1468 struct ntlm_buf *blob, 1469 struct ntlm_buf *session, 1470 struct ntlm_buf *master) 1471{ 1472 struct ntlm_buf sess; 1473 int ret; 1474 1475 ret = heim_ntlm_v2_base_session(key, len, blob, &sess); 1476 if (ret) 1477 return ret; 1478 1479 ret = heim_ntlm_keyex_wrap(&sess, session, master); 1480 heim_ntlm_free_buf(&sess); 1481 1482 return ret; 1483} 1484 1485/** 1486 * Given a key and encrypted session, unwrap the session key 1487 * 1488 * @param baseKey the sessionBaseKey 1489 * @param encryptedSession encrypted session, type3.session field. 1490 * @param session generated session nonce, should be freed with heim_ntlm_free_buf(). 1491 * 1492 * @return In case of success 0 is return, an errors, a errno in what 1493 * went wrong. 1494 * 1495 * @ingroup ntlm_core 1496 */ 1497 1498int 1499heim_ntlm_keyex_unwrap(struct ntlm_buf *baseKey, 1500 struct ntlm_buf *encryptedSession, 1501 struct ntlm_buf *session) 1502{ 1503 EVP_CIPHER_CTX *c; 1504 1505 memset(session, 0, sizeof(*session)); 1506 1507 if (encryptedSession->length != MD4_DIGEST_LENGTH) 1508 return HNTLM_ERR_INVALID_LENGTH; 1509 if (baseKey->length != MD4_DIGEST_LENGTH) 1510 return HNTLM_ERR_INVALID_LENGTH; 1511 1512 session->length = MD4_DIGEST_LENGTH; 1513 session->data = malloc(session->length); 1514 if (session->data == NULL) { 1515 session->length = 0; 1516 return ENOMEM; 1517 } 1518#if OPENSSL_VERSION_NUMBER < 0x10100000UL 1519 EVP_CIPHER_CTX cs; 1520 c = &cs; 1521 EVP_CIPHER_CTX_init(c); 1522#else 1523 c = EVP_CIPHER_CTX_new(); 1524#endif 1525 1526 if (EVP_CipherInit_ex(c, EVP_rc4(), NULL, baseKey->data, NULL, 0) != 1) { 1527#if OPENSSL_VERSION_NUMBER < 0x10100000UL 1528 EVP_CIPHER_CTX_cleanup(c); 1529#else 1530 EVP_CIPHER_CTX_free(c); 1531#endif 1532 heim_ntlm_free_buf(session); 1533 return HNTLM_ERR_CRYPTO; 1534 } 1535 1536 EVP_Cipher(c, session->data, encryptedSession->data, session->length); 1537#if OPENSSL_VERSION_NUMBER < 0x10100000UL 1538 EVP_CIPHER_CTX_cleanup(c); 1539#else 1540 EVP_CIPHER_CTX_free(c); 1541#endif 1542 1543 return 0; 1544} 1545 1546 1547/** 1548 * Generates an NTLMv2 session key. 1549 * 1550 * @param key the ntlm key 1551 * @param len length of key 1552 * @param username name of the user, as sent in the message, assumed to be in UTF8. 1553 * @param target the name of the target, assumed to be in UTF8. 1554 * @param upper_case_target upper case the target, should not be used only for legacy systems 1555 * @param ntlmv2 the ntlmv2 session key 1556 * 1557 * @return 0 on success, or an error code on failure. 1558 * 1559 * @ingroup ntlm_core 1560 */ 1561 1562int 1563heim_ntlm_ntlmv2_key(const void *key, size_t len, 1564 const char *username, 1565 const char *target, 1566 int upper_case_target, 1567 unsigned char ntlmv2[16]) 1568{ 1569 int ret; 1570 unsigned int hmaclen; 1571 HMAC_CTX* c; 1572 1573#if OPENSSL_VERSION_NUMBER < 0x10100000UL 1574 HMAC_CTX cs; 1575 c = &cs; 1576 HMAC_CTX_init(c); 1577#else 1578 c = HMAC_CTX_new(); 1579#endif 1580 HMAC_Init_ex(c, key, len, EVP_md5(), NULL); 1581 { 1582 struct ntlm_buf buf; 1583 /* uppercase username and turn it into ucs2-le */ 1584 ret = ascii2ucs2le(username, 1, &buf); 1585 if (ret) 1586 goto out; 1587 HMAC_Update(c, buf.data, buf.length); 1588 free(buf.data); 1589 /* turn target into ucs2-le */ 1590 ret = ascii2ucs2le(target, upper_case_target, &buf); 1591 if (ret) 1592 goto out; 1593 HMAC_Update(c, buf.data, buf.length); 1594 free(buf.data); 1595 } 1596 HMAC_Final(c, ntlmv2, &hmaclen); 1597 out: 1598#if OPENSSL_VERSION_NUMBER < 0x10100000UL 1599 HMAC_CTX_cleanup(c); 1600#else 1601 HMAC_CTX_free(c); 1602#endif 1603 1604 return ret; 1605} 1606 1607/* 1608 * 1609 */ 1610 1611#define NTTIME_EPOCH 0x019DB1DED53E8000LL 1612 1613uint64_t 1614heim_ntlm_unix2ts_time(time_t unix_time) 1615{ 1616 long long wt; 1617 wt = unix_time * (uint64_t)10000000 + (uint64_t)NTTIME_EPOCH; 1618 return wt; 1619} 1620 1621time_t 1622heim_ntlm_ts2unixtime(uint64_t t) 1623{ 1624 t = ((t - (uint64_t)NTTIME_EPOCH) / (uint64_t)10000000); 1625 if (t > (((uint64_t)(time_t)(~(uint64_t)0)) >> 1)) 1626 return 0; 1627 return (time_t)t; 1628} 1629 1630/** 1631 * Calculate LMv2 response 1632 * 1633 * @param key the ntlm key 1634 * @param len length of key 1635 * @param username name of the user, as sent in the message, assumed to be in UTF8. 1636 * @param target the name of the target, assumed to be in UTF8. 1637 * @param serverchallenge challenge as sent by the server in the type2 message. 1638 * @param ntlmv2 calculated session key 1639 * @param answer ntlm response answer, should be freed with heim_ntlm_free_buf(). 1640 * 1641 * @return In case of success 0 is return, an errors, a errno in what 1642 * went wrong. 1643 * 1644 * @ingroup ntlm_core 1645 */ 1646 1647int 1648heim_ntlm_calculate_lm2(const void *key, size_t len, 1649 const char *username, 1650 const char *target, 1651 const unsigned char serverchallenge[8], 1652 unsigned char ntlmv2[16], 1653 struct ntlm_buf *answer) 1654{ 1655 unsigned char clientchallenge[8]; 1656 1657 if (RAND_bytes(clientchallenge, sizeof(clientchallenge)) != 1) 1658 return HNTLM_ERR_RAND; 1659 1660 /* calculate ntlmv2 key */ 1661 1662 heim_ntlm_ntlmv2_key(key, len, username, target, 0, ntlmv2); 1663 1664 answer->data = malloc(24); 1665 if (answer->data == NULL) 1666 return ENOMEM; 1667 answer->length = 24; 1668 1669 heim_ntlm_derive_ntlm2_sess(ntlmv2, clientchallenge, 8, 1670 serverchallenge, answer->data); 1671 1672 memcpy(((unsigned char *)answer->data) + 16, clientchallenge, 8); 1673 1674 return 0; 1675} 1676 1677 1678/** 1679 * Calculate NTLMv2 response 1680 * 1681 * @param key the ntlm key 1682 * @param len length of key 1683 * @param username name of the user, as sent in the message, assumed to be in UTF8. 1684 * @param target the name of the target, assumed to be in UTF8. 1685 * @param serverchallenge challenge as sent by the server in the type2 message. 1686 * @param infotarget infotarget as sent by the server in the type2 message. 1687 * @param ntlmv2 calculated session key 1688 * @param answer ntlm response answer, should be freed with heim_ntlm_free_buf(). 1689 * 1690 * @return In case of success 0 is return, an errors, a errno in what 1691 * went wrong. 1692 * 1693 * @ingroup ntlm_core 1694 */ 1695 1696int 1697heim_ntlm_calculate_ntlm2(const void *key, size_t len, 1698 const char *username, 1699 const char *target, 1700 const unsigned char serverchallenge[8], 1701 const struct ntlm_buf *infotarget, 1702 unsigned char ntlmv2[16], 1703 struct ntlm_buf *answer) 1704{ 1705 krb5_error_code ret; 1706 krb5_data data; 1707 unsigned char ntlmv2answer[16]; 1708 krb5_storage *sp; 1709 unsigned char clientchallenge[8]; 1710 uint64_t t; 1711 1712 t = heim_ntlm_unix2ts_time(time(NULL)); 1713 1714 if (RAND_bytes(clientchallenge, sizeof(clientchallenge)) != 1) 1715 return HNTLM_ERR_RAND; 1716 1717 /* calculate ntlmv2 key */ 1718 1719 heim_ntlm_ntlmv2_key(key, len, username, target, 0, ntlmv2); 1720 1721 /* calculate and build ntlmv2 answer */ 1722 1723 sp = krb5_storage_emem(); 1724 if (sp == NULL) 1725 return ENOMEM; 1726 krb5_storage_set_flags(sp, KRB5_STORAGE_BYTEORDER_LE); 1727 1728 CHECK(krb5_store_uint32(sp, 0x00000101), 0); 1729 CHECK(krb5_store_uint32(sp, 0), 0); 1730 /* timestamp le 64 bit ts */ 1731 CHECK(krb5_store_uint32(sp, t & 0xffffffff), 0); 1732 CHECK(krb5_store_uint32(sp, t >> 32), 0); 1733 1734 CHECK_SIZE(krb5_storage_write(sp, clientchallenge, 8), 8); 1735 1736 CHECK(krb5_store_uint32(sp, 0), 0); /* Z(4) */ 1737 CHECK_SIZE(krb5_storage_write(sp, infotarget->data, infotarget->length), 1738 infotarget->length); 1739 1740 /* 1741 * These last 4 bytes(Z(4)) are not documented by MicroSoft and 1742 * SnowLeopard doesn't send them, Lion expected them to be there, 1743 * so we have to continue to send them. That is ok, since everyone 1744 * else (except Snow) seems to do that too. 1745 */ 1746 CHECK(krb5_store_uint32(sp, 0), 0); /* Z(4) */ 1747 1748 CHECK(krb5_storage_to_data(sp, &data), 0); 1749 krb5_storage_free(sp); 1750 sp = NULL; 1751 1752 heim_ntlm_derive_ntlm2_sess(ntlmv2, data.data, data.length, serverchallenge, ntlmv2answer); 1753 1754 sp = krb5_storage_emem(); 1755 if (sp == NULL) { 1756 krb5_data_free(&data); 1757 return ENOMEM; 1758 } 1759 1760 CHECK_SIZE(krb5_storage_write(sp, ntlmv2answer, 16), 16); 1761 CHECK_SIZE(krb5_storage_write(sp, data.data, data.length), data.length); 1762 krb5_data_free(&data); 1763 1764 CHECK(krb5_storage_to_data(sp, &data), 0); 1765 krb5_storage_free(sp); 1766 sp = NULL; 1767 1768 answer->data = data.data; 1769 answer->length = data.length; 1770 1771 return 0; 1772out: 1773 if (sp) 1774 krb5_storage_free(sp); 1775 return ret; 1776} 1777 1778static const int authtimediff = 3600 * 2; /* 2 hours */ 1779 1780static int 1781verify_ntlm2(const void *key, size_t len, 1782 const char *username, 1783 const char *target, 1784 int upper_case_target, 1785 time_t now, 1786 const unsigned char serverchallenge[8], 1787 const struct ntlm_buf *answer, 1788 struct ntlm_buf *infotarget, 1789 unsigned char ntlmv2[16]) 1790{ 1791 krb5_error_code ret; 1792 unsigned char clientanswer[16]; 1793 unsigned char clientnonce[8]; 1794 unsigned char serveranswer[16]; 1795 krb5_storage *sp; 1796 uint64_t t; 1797 time_t authtime; 1798 uint32_t temp; 1799 1800 infotarget->length = 0; 1801 infotarget->data = NULL; 1802 1803 if (answer->length < 16) 1804 return HNTLM_ERR_INVALID_LENGTH; 1805 1806 if (now == 0) 1807 now = time(NULL); 1808 1809 /* calculate ntlmv2 key */ 1810 1811 heim_ntlm_ntlmv2_key(key, len, username, target, upper_case_target, ntlmv2); 1812 1813 /* calculate and build ntlmv2 answer */ 1814 1815 sp = krb5_storage_from_readonly_mem(answer->data, answer->length); 1816 if (sp == NULL) 1817 return ENOMEM; 1818 krb5_storage_set_flags(sp, KRB5_STORAGE_BYTEORDER_LE); 1819 1820 CHECK_SIZE(krb5_storage_read(sp, clientanswer, 16), 16); 1821 1822 CHECK(krb5_ret_uint32(sp, &temp), 0); 1823 CHECK(temp, 0x00000101); 1824 CHECK(krb5_ret_uint32(sp, &temp), 0); 1825 CHECK(temp, 0); 1826 /* timestamp le 64 bit ts */ 1827 CHECK(krb5_ret_uint32(sp, &temp), 0); 1828 t = temp; 1829 CHECK(krb5_ret_uint32(sp, &temp), 0); 1830 t |= ((uint64_t)temp)<< 32; 1831 1832 authtime = heim_ntlm_ts2unixtime(t); 1833 1834 if (labs((int)(authtime - now)) > authtimediff) { 1835 ret = HNTLM_ERR_TIME_SKEW; 1836 goto out; 1837 } 1838 1839 /* client challenge */ 1840 CHECK_SIZE(krb5_storage_read(sp, clientnonce, 8), 8); 1841 1842 CHECK(krb5_ret_uint32(sp, &temp), 0); /* Z(4) */ 1843 1844 /* let pick up targetinfo */ 1845 infotarget->length = answer->length - (size_t)krb5_storage_seek(sp, 0, SEEK_CUR); 1846 if (infotarget->length < 4) { 1847 ret = HNTLM_ERR_INVALID_LENGTH; 1848 goto out; 1849 } 1850 infotarget->data = malloc(infotarget->length); 1851 if (infotarget->data == NULL) { 1852 ret = ENOMEM; 1853 goto out; 1854 } 1855 CHECK_SIZE(krb5_storage_read(sp, infotarget->data, infotarget->length), 1856 infotarget->length); 1857 1858 krb5_storage_free(sp); 1859 sp = NULL; 1860 1861 if (answer->length < 16) { 1862 ret = HNTLM_ERR_INVALID_LENGTH; 1863 goto out; 1864 } 1865 1866 heim_ntlm_derive_ntlm2_sess(ntlmv2, 1867 ((unsigned char *)answer->data) + 16, answer->length - 16, 1868 serverchallenge, 1869 serveranswer); 1870 1871 if (memcmp(serveranswer, clientanswer, 16) != 0) { 1872 heim_ntlm_free_buf(infotarget); 1873 return HNTLM_ERR_AUTH; 1874 } 1875 1876 return 0; 1877out: 1878 heim_ntlm_free_buf(infotarget); 1879 if (sp) 1880 krb5_storage_free(sp); 1881 return ret; 1882} 1883 1884/** 1885 * Verify NTLMv2 response. 1886 * 1887 * @param key the ntlm key 1888 * @param len length of key 1889 * @param username name of the user, as sent in the message, assumed to be in UTF8. 1890 * @param target the name of the target, assumed to be in UTF8. 1891 * @param now the time now (0 if the library should pick it up itself) 1892 * @param serverchallenge challenge as sent by the server in the type2 message. 1893 * @param answer ntlm response answer, should be freed with heim_ntlm_free_buf(). 1894 * @param infotarget infotarget as sent by the server in the type2 message. 1895 * @param ntlmv2 calculated session key 1896 * 1897 * @return In case of success 0 is return, an errors, a errno in what 1898 * went wrong. 1899 * 1900 * @ingroup ntlm_core 1901 */ 1902 1903int 1904heim_ntlm_verify_ntlm2(const void *key, size_t len, 1905 const char *username, 1906 const char *target, 1907 time_t now, 1908 const unsigned char serverchallenge[8], 1909 const struct ntlm_buf *answer, 1910 struct ntlm_buf *infotarget, 1911 unsigned char ntlmv2[16]) 1912{ 1913 int ret; 1914 1915 /** 1916 * First check with the domain as the client passed it to the function. 1917 */ 1918 1919 ret = verify_ntlm2(key, len, username, target, 0, now, 1920 serverchallenge, answer, infotarget, ntlmv2); 1921 1922 /** 1923 * Second check with domain uppercased. 1924 */ 1925 1926 if (ret) 1927 ret = verify_ntlm2(key, len, username, target, 1, now, 1928 serverchallenge, answer, infotarget, ntlmv2); 1929 1930 /** 1931 * Third check with empty domain. 1932 */ 1933 if (ret) 1934 ret = verify_ntlm2(key, len, username, "", 0, now, 1935 serverchallenge, answer, infotarget, ntlmv2); 1936 return ret; 1937} 1938 1939/* 1940 * Calculate the NTLM2 Session Response 1941 * 1942 * @param clnt_nonce client nonce 1943 * @param svr_chal server challage 1944 * @param ntlm2_hash ntlm hash 1945 * @param lm The LM response, should be freed with heim_ntlm_free_buf(). 1946 * @param ntlm The NTLM response, should be freed with heim_ntlm_free_buf(). 1947 * 1948 * @return In case of success 0 is return, an errors, a errno in what 1949 * went wrong. 1950 * 1951 * @ingroup ntlm_core 1952 */ 1953 1954int 1955heim_ntlm_calculate_ntlm2_sess(const unsigned char clnt_nonce[8], 1956 const unsigned char svr_chal[8], 1957 const unsigned char ntlm_hash[16], 1958 struct ntlm_buf *lm, 1959 struct ntlm_buf *ntlm) 1960{ 1961 unsigned char ntlm2_sess_hash[8]; 1962 unsigned char res[21], *resp; 1963 int code; 1964 1965 code = heim_ntlm_calculate_ntlm2_sess_hash(clnt_nonce, svr_chal, 1966 ntlm2_sess_hash); 1967 if (code) { 1968 return code; 1969 } 1970 1971 lm->data = malloc(24); 1972 if (lm->data == NULL) { 1973 return ENOMEM; 1974 } 1975 lm->length = 24; 1976 1977 ntlm->data = malloc(24); 1978 if (ntlm->data == NULL) { 1979 free(lm->data); 1980 lm->data = NULL; 1981 return ENOMEM; 1982 } 1983 ntlm->length = 24; 1984 1985 /* first setup the lm resp */ 1986 memset(lm->data, 0, 24); 1987 memcpy(lm->data, clnt_nonce, 8); 1988 1989 memset(res, 0, sizeof(res)); 1990 memcpy(res, ntlm_hash, 16); 1991 1992 resp = ntlm->data; 1993 splitandenc(&res[0], ntlm2_sess_hash, resp + 0); 1994 splitandenc(&res[7], ntlm2_sess_hash, resp + 8); 1995 splitandenc(&res[14], ntlm2_sess_hash, resp + 16); 1996 1997 return 0; 1998} 1999 2000 2001/* 2002 * Calculate the NTLM2 Session "Verifier" 2003 * 2004 * @param clnt_nonce client nonce 2005 * @param svr_chal server challage 2006 * @param hash The NTLM session verifier 2007 * 2008 * @return In case of success 0 is return, an errors, a errno in what 2009 * went wrong. 2010 * 2011 * @ingroup ntlm_core 2012 */ 2013 2014int 2015heim_ntlm_calculate_ntlm2_sess_hash(const unsigned char clnt_nonce[8], 2016 const unsigned char svr_chal[8], 2017 unsigned char verifier[8]) 2018{ 2019 unsigned char ntlm2_sess_hash[MD5_DIGEST_LENGTH]; 2020 EVP_MD_CTX *m; 2021 2022 m = EVP_MD_CTX_create(); 2023 if (m == NULL) 2024 return ENOMEM; 2025 2026 EVP_DigestInit_ex(m, EVP_md5(), NULL); 2027 EVP_DigestUpdate(m, svr_chal, 8); /* session nonce part 1 */ 2028 EVP_DigestUpdate(m, clnt_nonce, 8); /* session nonce part 2 */ 2029 EVP_DigestFinal_ex(m, ntlm2_sess_hash, NULL); /* will only use first 8 bytes */ 2030 EVP_MD_CTX_destroy(m); 2031 2032 memcpy(verifier, ntlm2_sess_hash, 8); 2033 2034 return 0; 2035} 2036 2037 2038/* 2039 * Derive a NTLM2 session key 2040 * 2041 * @param sessionkey session key from domain controller 2042 * @param clnt_nonce client nonce 2043 * @param svr_chal server challenge 2044 * @param derivedkey salted session key 2045 * 2046 * @return In case of success 0 is return, an errors, a errno in what 2047 * went wrong. 2048 * 2049 * @ingroup ntlm_core 2050 */ 2051 2052void 2053heim_ntlm_derive_ntlm2_sess(const unsigned char sessionkey[16], 2054 const unsigned char *clnt_nonce, size_t clnt_nonce_length, 2055 const unsigned char svr_chal[8], 2056 unsigned char derivedkey[16]) 2057{ 2058 unsigned int hmaclen; 2059 HMAC_CTX *c; 2060 2061 /* HMAC(Ksession, serverchallenge || clientchallenge) */ 2062#if OPENSSL_VERSION_NUMBER < 0x10100000UL 2063 HMAC_CTX cs; 2064 c = &cs; 2065 HMAC_CTX_init(c); 2066#else 2067 c = HMAC_CTX_new(); 2068#endif 2069 HMAC_Init_ex(c, sessionkey, 16, EVP_md5(), NULL); 2070 HMAC_Update(c, svr_chal, 8); 2071 HMAC_Update(c, clnt_nonce, clnt_nonce_length); 2072 HMAC_Final(c, derivedkey, &hmaclen); 2073#if OPENSSL_VERSION_NUMBER < 0x10100000UL 2074 HMAC_CTX_cleanup(c); 2075#else 2076 HMAC_CTX_free(c); 2077#endif 2078} 2079