ntlm.c revision 1.2
1/* $NetBSD: ntlm.c,v 1.2 2018/02/05 16:00:53 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 EVP_CipherInit_ex(ctx, EVP_des_cbc(), NULL, key, NULL, 1); 1201 EVP_Cipher(ctx, answer, challenge, 8); 1202#if OPENSSL_VERSION_NUMBER < 0x10100000UL 1203 EVP_CIPHER_CTX_cleanup(ctx); 1204#else 1205 EVP_CIPHER_CTX_free(ctx); 1206#endif 1207 memset(key, 0, sizeof(key)); 1208} 1209 1210/** 1211 * Calculate the NTLM key, the password is assumed to be in UTF8. 1212 * 1213 * @param password password to calcute the key for. 1214 * @param key calcuted key, should be freed with heim_ntlm_free_buf(). 1215 * 1216 * @return In case of success 0 is return, an errors, a errno in what 1217 * went wrong. 1218 * 1219 * @ingroup ntlm_core 1220 */ 1221 1222int 1223heim_ntlm_nt_key(const char *password, struct ntlm_buf *key) 1224{ 1225 struct ntlm_buf buf; 1226 EVP_MD_CTX *m; 1227 int ret; 1228 1229 key->data = malloc(MD4_DIGEST_LENGTH); 1230 if (key->data == NULL) 1231 return ENOMEM; 1232 key->length = MD4_DIGEST_LENGTH; 1233 1234 ret = ascii2ucs2le(password, 0, &buf); 1235 if (ret) { 1236 heim_ntlm_free_buf(key); 1237 return ret; 1238 } 1239 1240 m = EVP_MD_CTX_create(); 1241 if (m == NULL) { 1242 heim_ntlm_free_buf(key); 1243 heim_ntlm_free_buf(&buf); 1244 return ENOMEM; 1245 } 1246 1247 EVP_DigestInit_ex(m, EVP_md4(), NULL); 1248 EVP_DigestUpdate(m, buf.data, buf.length); 1249 EVP_DigestFinal_ex(m, key->data, NULL); 1250 EVP_MD_CTX_destroy(m); 1251 1252 heim_ntlm_free_buf(&buf); 1253 return 0; 1254} 1255 1256/** 1257 * Calculate NTLMv1 response hash 1258 * 1259 * @param key the ntlm v1 key 1260 * @param len length of key 1261 * @param challenge sent by the server 1262 * @param answer calculated answer, should be freed with heim_ntlm_free_buf(). 1263 * 1264 * @return In case of success 0 is return, an errors, a errno in what 1265 * went wrong. 1266 * 1267 * @ingroup ntlm_core 1268 */ 1269 1270int 1271heim_ntlm_calculate_ntlm1(void *key, size_t len, 1272 unsigned char challenge[8], 1273 struct ntlm_buf *answer) 1274{ 1275 unsigned char res[21]; 1276 1277 if (len != MD4_DIGEST_LENGTH) 1278 return HNTLM_ERR_INVALID_LENGTH; 1279 1280 memcpy(res, key, len); 1281 memset(&res[MD4_DIGEST_LENGTH], 0, sizeof(res) - MD4_DIGEST_LENGTH); 1282 1283 answer->data = malloc(24); 1284 if (answer->data == NULL) 1285 return ENOMEM; 1286 answer->length = 24; 1287 1288 splitandenc(&res[0], challenge, ((unsigned char *)answer->data) + 0); 1289 splitandenc(&res[7], challenge, ((unsigned char *)answer->data) + 8); 1290 splitandenc(&res[14], challenge, ((unsigned char *)answer->data) + 16); 1291 1292 return 0; 1293} 1294 1295int 1296heim_ntlm_v1_base_session(void *key, size_t len, 1297 struct ntlm_buf *session) 1298{ 1299 EVP_MD_CTX *m; 1300 1301 session->length = MD4_DIGEST_LENGTH; 1302 session->data = malloc(session->length); 1303 if (session->data == NULL) { 1304 session->length = 0; 1305 return ENOMEM; 1306 } 1307 1308 m = EVP_MD_CTX_create(); 1309 if (m == NULL) { 1310 heim_ntlm_free_buf(session); 1311 return ENOMEM; 1312 } 1313 EVP_DigestInit_ex(m, EVP_md4(), NULL); 1314 EVP_DigestUpdate(m, key, len); 1315 EVP_DigestFinal_ex(m, session->data, NULL); 1316 EVP_MD_CTX_destroy(m); 1317 1318 return 0; 1319} 1320 1321int 1322heim_ntlm_v2_base_session(void *key, size_t len, 1323 struct ntlm_buf *ntlmResponse, 1324 struct ntlm_buf *session) 1325{ 1326 unsigned int hmaclen; 1327 HMAC_CTX *c; 1328 1329 if (ntlmResponse->length <= 16) 1330 return HNTLM_ERR_INVALID_LENGTH; 1331 1332 session->data = malloc(16); 1333 if (session->data == NULL) 1334 return ENOMEM; 1335 session->length = 16; 1336 1337 /* Note: key is the NTLMv2 key */ 1338#if OPENSSL_VERSION_NUMBER < 0x10100000UL 1339 HMAC_CTX cs; 1340 c = &cs; 1341 HMAC_CTX_init(c); 1342#else 1343 c = HMAC_CTX_new(); 1344#endif 1345 HMAC_Init_ex(c, key, len, EVP_md5(), NULL); 1346 HMAC_Update(c, ntlmResponse->data, 16); 1347 HMAC_Final(c, session->data, &hmaclen); 1348#if OPENSSL_VERSION_NUMBER < 0x10100000UL 1349 HMAC_CTX_cleanup(c); 1350#else 1351 HMAC_CTX_free(c); 1352#endif 1353 1354 return 0; 1355} 1356 1357 1358int 1359heim_ntlm_keyex_wrap(struct ntlm_buf *base_session, 1360 struct ntlm_buf *session, 1361 struct ntlm_buf *encryptedSession) 1362{ 1363 EVP_CIPHER_CTX *c; 1364 int ret; 1365 1366 if (base_session->length != MD4_DIGEST_LENGTH) 1367 return HNTLM_ERR_INVALID_LENGTH; 1368 1369 session->length = MD4_DIGEST_LENGTH; 1370 session->data = malloc(session->length); 1371 if (session->data == NULL) { 1372 session->length = 0; 1373 return ENOMEM; 1374 } 1375 encryptedSession->length = MD4_DIGEST_LENGTH; 1376 encryptedSession->data = malloc(encryptedSession->length); 1377 if (encryptedSession->data == NULL) { 1378 heim_ntlm_free_buf(session); 1379 encryptedSession->length = 0; 1380 return ENOMEM; 1381 } 1382 1383#if OPENSSL_VERSION_NUMBER < 0x10100000UL 1384 EVP_CIPHER_CTX cs; 1385 c = &cs; 1386 EVP_CIPHER_CTX_init(c); 1387#else 1388 c = EVP_CIPHER_CTX_new(); 1389#endif 1390 1391 ret = EVP_CipherInit_ex(c, EVP_rc4(), NULL, base_session->data, NULL, 1); 1392 1393 if (ret != -1 || RAND_bytes(session->data, session->length) != 1) { 1394#if OPENSSL_VERSION_NUMBER < 0x10100000UL 1395 EVP_CIPHER_CTX_cleanup(c); 1396#else 1397 EVP_CIPHER_CTX_free(c); 1398#endif 1399 heim_ntlm_free_buf(encryptedSession); 1400 heim_ntlm_free_buf(session); 1401 return HNTLM_ERR_RAND; 1402 } 1403 1404 EVP_Cipher(c, encryptedSession->data, session->data, encryptedSession->length); 1405#if OPENSSL_VERSION_NUMBER < 0x10100000UL 1406 EVP_CIPHER_CTX_cleanup(c); 1407#else 1408 EVP_CIPHER_CTX_free(c); 1409#endif 1410 1411 return 0; 1412 1413 1414 1415} 1416 1417/** 1418 * Generates an NTLMv1 session random with assosited session master key. 1419 * 1420 * @param key the ntlm v1 key 1421 * @param len length of key 1422 * @param session generated session nonce, should be freed with heim_ntlm_free_buf(). 1423 * @param master calculated session master key, should be freed with heim_ntlm_free_buf(). 1424 * 1425 * @return In case of success 0 is return, an errors, a errno in what 1426 * went wrong. 1427 * 1428 * @ingroup ntlm_core 1429 */ 1430 1431int 1432heim_ntlm_build_ntlm1_master(void *key, size_t len, 1433 struct ntlm_buf *session, 1434 struct ntlm_buf *master) 1435{ 1436 struct ntlm_buf sess; 1437 int ret; 1438 1439 ret = heim_ntlm_v1_base_session(key, len, &sess); 1440 if (ret) 1441 return ret; 1442 1443 ret = heim_ntlm_keyex_wrap(&sess, session, master); 1444 heim_ntlm_free_buf(&sess); 1445 1446 return ret; 1447} 1448 1449/** 1450 * Generates an NTLMv2 session random with associated session master key. 1451 * 1452 * @param key the NTLMv2 key 1453 * @param len length of key 1454 * @param blob the NTLMv2 "blob" 1455 * @param session generated session nonce, should be freed with heim_ntlm_free_buf(). 1456 * @param master calculated session master key, should be freed with heim_ntlm_free_buf(). 1457 * 1458 * @return In case of success 0 is return, an errors, a errno in what 1459 * went wrong. 1460 * 1461 * @ingroup ntlm_core 1462 */ 1463 1464 1465int 1466heim_ntlm_build_ntlm2_master(void *key, size_t len, 1467 struct ntlm_buf *blob, 1468 struct ntlm_buf *session, 1469 struct ntlm_buf *master) 1470{ 1471 struct ntlm_buf sess; 1472 int ret; 1473 1474 ret = heim_ntlm_v2_base_session(key, len, blob, &sess); 1475 if (ret) 1476 return ret; 1477 1478 ret = heim_ntlm_keyex_wrap(&sess, session, master); 1479 heim_ntlm_free_buf(&sess); 1480 1481 return ret; 1482} 1483 1484/** 1485 * Given a key and encrypted session, unwrap the session key 1486 * 1487 * @param baseKey the sessionBaseKey 1488 * @param encryptedSession encrypted session, type3.session field. 1489 * @param session generated session nonce, should be freed with heim_ntlm_free_buf(). 1490 * 1491 * @return In case of success 0 is return, an errors, a errno in what 1492 * went wrong. 1493 * 1494 * @ingroup ntlm_core 1495 */ 1496 1497int 1498heim_ntlm_keyex_unwrap(struct ntlm_buf *baseKey, 1499 struct ntlm_buf *encryptedSession, 1500 struct ntlm_buf *session) 1501{ 1502 EVP_CIPHER_CTX *c; 1503 1504 memset(session, 0, sizeof(*session)); 1505 1506 if (encryptedSession->length != MD4_DIGEST_LENGTH) 1507 return HNTLM_ERR_INVALID_LENGTH; 1508 if (baseKey->length != MD4_DIGEST_LENGTH) 1509 return HNTLM_ERR_INVALID_LENGTH; 1510 1511 session->length = MD4_DIGEST_LENGTH; 1512 session->data = malloc(session->length); 1513 if (session->data == NULL) { 1514 session->length = 0; 1515 return ENOMEM; 1516 } 1517#if OPENSSL_VERSION_NUMBER < 0x10100000UL 1518 EVP_CIPHER_CTX cs; 1519 c = &cs; 1520 EVP_CIPHER_CTX_init(c); 1521#else 1522 c = EVP_CIPHER_CTX_new(); 1523#endif 1524 1525 if (EVP_CipherInit_ex(c, EVP_rc4(), NULL, baseKey->data, NULL, 0) != 1) { 1526#if OPENSSL_VERSION_NUMBER < 0x10100000UL 1527 EVP_CIPHER_CTX_cleanup(c); 1528#else 1529 EVP_CIPHER_CTX_free(c); 1530#endif 1531 heim_ntlm_free_buf(session); 1532 return HNTLM_ERR_CRYPTO; 1533 } 1534 1535 EVP_Cipher(c, session->data, encryptedSession->data, session->length); 1536#if OPENSSL_VERSION_NUMBER < 0x10100000UL 1537 EVP_CIPHER_CTX_cleanup(c); 1538#else 1539 EVP_CIPHER_CTX_free(c); 1540#endif 1541 1542 return 0; 1543} 1544 1545 1546/** 1547 * Generates an NTLMv2 session key. 1548 * 1549 * @param key the ntlm key 1550 * @param len length of key 1551 * @param username name of the user, as sent in the message, assumed to be in UTF8. 1552 * @param target the name of the target, assumed to be in UTF8. 1553 * @param upper_case_target upper case the target, should not be used only for legacy systems 1554 * @param ntlmv2 the ntlmv2 session key 1555 * 1556 * @return 0 on success, or an error code on failure. 1557 * 1558 * @ingroup ntlm_core 1559 */ 1560 1561int 1562heim_ntlm_ntlmv2_key(const void *key, size_t len, 1563 const char *username, 1564 const char *target, 1565 int upper_case_target, 1566 unsigned char ntlmv2[16]) 1567{ 1568 int ret; 1569 unsigned int hmaclen; 1570 HMAC_CTX* c; 1571 1572#if OPENSSL_VERSION_NUMBER < 0x10100000UL 1573 HMAC_CTX cs; 1574 c = &cs; 1575 HMAC_CTX_init(c); 1576#else 1577 c = HMAC_CTX_new(); 1578#endif 1579 HMAC_Init_ex(c, key, len, EVP_md5(), NULL); 1580 { 1581 struct ntlm_buf buf; 1582 /* uppercase username and turn it into ucs2-le */ 1583 ret = ascii2ucs2le(username, 1, &buf); 1584 if (ret) 1585 goto out; 1586 HMAC_Update(c, buf.data, buf.length); 1587 free(buf.data); 1588 /* turn target into ucs2-le */ 1589 ret = ascii2ucs2le(target, upper_case_target, &buf); 1590 if (ret) 1591 goto out; 1592 HMAC_Update(c, buf.data, buf.length); 1593 free(buf.data); 1594 } 1595 HMAC_Final(c, ntlmv2, &hmaclen); 1596 out: 1597#if OPENSSL_VERSION_NUMBER < 0x10100000UL 1598 HMAC_CTX_cleanup(c); 1599#else 1600 HMAC_CTX_free(c); 1601#endif 1602 1603 return ret; 1604} 1605 1606/* 1607 * 1608 */ 1609 1610#define NTTIME_EPOCH 0x019DB1DED53E8000LL 1611 1612uint64_t 1613heim_ntlm_unix2ts_time(time_t unix_time) 1614{ 1615 long long wt; 1616 wt = unix_time * (uint64_t)10000000 + (uint64_t)NTTIME_EPOCH; 1617 return wt; 1618} 1619 1620time_t 1621heim_ntlm_ts2unixtime(uint64_t t) 1622{ 1623 t = ((t - (uint64_t)NTTIME_EPOCH) / (uint64_t)10000000); 1624 if (t > (((uint64_t)(time_t)(~(uint64_t)0)) >> 1)) 1625 return 0; 1626 return (time_t)t; 1627} 1628 1629/** 1630 * Calculate LMv2 response 1631 * 1632 * @param key the ntlm key 1633 * @param len length of key 1634 * @param username name of the user, as sent in the message, assumed to be in UTF8. 1635 * @param target the name of the target, assumed to be in UTF8. 1636 * @param serverchallenge challenge as sent by the server in the type2 message. 1637 * @param ntlmv2 calculated session key 1638 * @param answer ntlm response answer, should be freed with heim_ntlm_free_buf(). 1639 * 1640 * @return In case of success 0 is return, an errors, a errno in what 1641 * went wrong. 1642 * 1643 * @ingroup ntlm_core 1644 */ 1645 1646int 1647heim_ntlm_calculate_lm2(const void *key, size_t len, 1648 const char *username, 1649 const char *target, 1650 const unsigned char serverchallenge[8], 1651 unsigned char ntlmv2[16], 1652 struct ntlm_buf *answer) 1653{ 1654 unsigned char clientchallenge[8]; 1655 1656 if (RAND_bytes(clientchallenge, sizeof(clientchallenge)) != 1) 1657 return HNTLM_ERR_RAND; 1658 1659 /* calculate ntlmv2 key */ 1660 1661 heim_ntlm_ntlmv2_key(key, len, username, target, 0, ntlmv2); 1662 1663 answer->data = malloc(24); 1664 if (answer->data == NULL) 1665 return ENOMEM; 1666 answer->length = 24; 1667 1668 heim_ntlm_derive_ntlm2_sess(ntlmv2, clientchallenge, 8, 1669 serverchallenge, answer->data); 1670 1671 memcpy(((unsigned char *)answer->data) + 16, clientchallenge, 8); 1672 1673 return 0; 1674} 1675 1676 1677/** 1678 * Calculate NTLMv2 response 1679 * 1680 * @param key the ntlm key 1681 * @param len length of key 1682 * @param username name of the user, as sent in the message, assumed to be in UTF8. 1683 * @param target the name of the target, assumed to be in UTF8. 1684 * @param serverchallenge challenge as sent by the server in the type2 message. 1685 * @param infotarget infotarget as sent by the server in the type2 message. 1686 * @param ntlmv2 calculated session key 1687 * @param answer ntlm response answer, should be freed with heim_ntlm_free_buf(). 1688 * 1689 * @return In case of success 0 is return, an errors, a errno in what 1690 * went wrong. 1691 * 1692 * @ingroup ntlm_core 1693 */ 1694 1695int 1696heim_ntlm_calculate_ntlm2(const void *key, size_t len, 1697 const char *username, 1698 const char *target, 1699 const unsigned char serverchallenge[8], 1700 const struct ntlm_buf *infotarget, 1701 unsigned char ntlmv2[16], 1702 struct ntlm_buf *answer) 1703{ 1704 krb5_error_code ret; 1705 krb5_data data; 1706 unsigned char ntlmv2answer[16]; 1707 krb5_storage *sp; 1708 unsigned char clientchallenge[8]; 1709 uint64_t t; 1710 1711 t = heim_ntlm_unix2ts_time(time(NULL)); 1712 1713 if (RAND_bytes(clientchallenge, sizeof(clientchallenge)) != 1) 1714 return HNTLM_ERR_RAND; 1715 1716 /* calculate ntlmv2 key */ 1717 1718 heim_ntlm_ntlmv2_key(key, len, username, target, 0, ntlmv2); 1719 1720 /* calculate and build ntlmv2 answer */ 1721 1722 sp = krb5_storage_emem(); 1723 if (sp == NULL) 1724 return ENOMEM; 1725 krb5_storage_set_flags(sp, KRB5_STORAGE_BYTEORDER_LE); 1726 1727 CHECK(krb5_store_uint32(sp, 0x00000101), 0); 1728 CHECK(krb5_store_uint32(sp, 0), 0); 1729 /* timestamp le 64 bit ts */ 1730 CHECK(krb5_store_uint32(sp, t & 0xffffffff), 0); 1731 CHECK(krb5_store_uint32(sp, t >> 32), 0); 1732 1733 CHECK_SIZE(krb5_storage_write(sp, clientchallenge, 8), 8); 1734 1735 CHECK(krb5_store_uint32(sp, 0), 0); /* Z(4) */ 1736 CHECK_SIZE(krb5_storage_write(sp, infotarget->data, infotarget->length), 1737 infotarget->length); 1738 1739 /* 1740 * These last 4 bytes(Z(4)) are not documented by MicroSoft and 1741 * SnowLeopard doesn't send them, Lion expected them to be there, 1742 * so we have to continue to send them. That is ok, since everyone 1743 * else (except Snow) seems to do that too. 1744 */ 1745 CHECK(krb5_store_uint32(sp, 0), 0); /* Z(4) */ 1746 1747 CHECK(krb5_storage_to_data(sp, &data), 0); 1748 krb5_storage_free(sp); 1749 sp = NULL; 1750 1751 heim_ntlm_derive_ntlm2_sess(ntlmv2, data.data, data.length, serverchallenge, ntlmv2answer); 1752 1753 sp = krb5_storage_emem(); 1754 if (sp == NULL) { 1755 krb5_data_free(&data); 1756 return ENOMEM; 1757 } 1758 1759 CHECK_SIZE(krb5_storage_write(sp, ntlmv2answer, 16), 16); 1760 CHECK_SIZE(krb5_storage_write(sp, data.data, data.length), data.length); 1761 krb5_data_free(&data); 1762 1763 CHECK(krb5_storage_to_data(sp, &data), 0); 1764 krb5_storage_free(sp); 1765 sp = NULL; 1766 1767 answer->data = data.data; 1768 answer->length = data.length; 1769 1770 return 0; 1771out: 1772 if (sp) 1773 krb5_storage_free(sp); 1774 return ret; 1775} 1776 1777static const int authtimediff = 3600 * 2; /* 2 hours */ 1778 1779static int 1780verify_ntlm2(const void *key, size_t len, 1781 const char *username, 1782 const char *target, 1783 int upper_case_target, 1784 time_t now, 1785 const unsigned char serverchallenge[8], 1786 const struct ntlm_buf *answer, 1787 struct ntlm_buf *infotarget, 1788 unsigned char ntlmv2[16]) 1789{ 1790 krb5_error_code ret; 1791 unsigned char clientanswer[16]; 1792 unsigned char clientnonce[8]; 1793 unsigned char serveranswer[16]; 1794 krb5_storage *sp; 1795 uint64_t t; 1796 time_t authtime; 1797 uint32_t temp; 1798 1799 infotarget->length = 0; 1800 infotarget->data = NULL; 1801 1802 if (answer->length < 16) 1803 return HNTLM_ERR_INVALID_LENGTH; 1804 1805 if (now == 0) 1806 now = time(NULL); 1807 1808 /* calculate ntlmv2 key */ 1809 1810 heim_ntlm_ntlmv2_key(key, len, username, target, upper_case_target, ntlmv2); 1811 1812 /* calculate and build ntlmv2 answer */ 1813 1814 sp = krb5_storage_from_readonly_mem(answer->data, answer->length); 1815 if (sp == NULL) 1816 return ENOMEM; 1817 krb5_storage_set_flags(sp, KRB5_STORAGE_BYTEORDER_LE); 1818 1819 CHECK_SIZE(krb5_storage_read(sp, clientanswer, 16), 16); 1820 1821 CHECK(krb5_ret_uint32(sp, &temp), 0); 1822 CHECK(temp, 0x00000101); 1823 CHECK(krb5_ret_uint32(sp, &temp), 0); 1824 CHECK(temp, 0); 1825 /* timestamp le 64 bit ts */ 1826 CHECK(krb5_ret_uint32(sp, &temp), 0); 1827 t = temp; 1828 CHECK(krb5_ret_uint32(sp, &temp), 0); 1829 t |= ((uint64_t)temp)<< 32; 1830 1831 authtime = heim_ntlm_ts2unixtime(t); 1832 1833 if (labs((int)(authtime - now)) > authtimediff) { 1834 ret = HNTLM_ERR_TIME_SKEW; 1835 goto out; 1836 } 1837 1838 /* client challenge */ 1839 CHECK_SIZE(krb5_storage_read(sp, clientnonce, 8), 8); 1840 1841 CHECK(krb5_ret_uint32(sp, &temp), 0); /* Z(4) */ 1842 1843 /* let pick up targetinfo */ 1844 infotarget->length = answer->length - (size_t)krb5_storage_seek(sp, 0, SEEK_CUR); 1845 if (infotarget->length < 4) { 1846 ret = HNTLM_ERR_INVALID_LENGTH; 1847 goto out; 1848 } 1849 infotarget->data = malloc(infotarget->length); 1850 if (infotarget->data == NULL) { 1851 ret = ENOMEM; 1852 goto out; 1853 } 1854 CHECK_SIZE(krb5_storage_read(sp, infotarget->data, infotarget->length), 1855 infotarget->length); 1856 1857 krb5_storage_free(sp); 1858 sp = NULL; 1859 1860 if (answer->length < 16) { 1861 ret = HNTLM_ERR_INVALID_LENGTH; 1862 goto out; 1863 } 1864 1865 heim_ntlm_derive_ntlm2_sess(ntlmv2, 1866 ((unsigned char *)answer->data) + 16, answer->length - 16, 1867 serverchallenge, 1868 serveranswer); 1869 1870 if (memcmp(serveranswer, clientanswer, 16) != 0) { 1871 heim_ntlm_free_buf(infotarget); 1872 return HNTLM_ERR_AUTH; 1873 } 1874 1875 return 0; 1876out: 1877 heim_ntlm_free_buf(infotarget); 1878 if (sp) 1879 krb5_storage_free(sp); 1880 return ret; 1881} 1882 1883/** 1884 * Verify NTLMv2 response. 1885 * 1886 * @param key the ntlm key 1887 * @param len length of key 1888 * @param username name of the user, as sent in the message, assumed to be in UTF8. 1889 * @param target the name of the target, assumed to be in UTF8. 1890 * @param now the time now (0 if the library should pick it up itself) 1891 * @param serverchallenge challenge as sent by the server in the type2 message. 1892 * @param answer ntlm response answer, should be freed with heim_ntlm_free_buf(). 1893 * @param infotarget infotarget as sent by the server in the type2 message. 1894 * @param ntlmv2 calculated session key 1895 * 1896 * @return In case of success 0 is return, an errors, a errno in what 1897 * went wrong. 1898 * 1899 * @ingroup ntlm_core 1900 */ 1901 1902int 1903heim_ntlm_verify_ntlm2(const void *key, size_t len, 1904 const char *username, 1905 const char *target, 1906 time_t now, 1907 const unsigned char serverchallenge[8], 1908 const struct ntlm_buf *answer, 1909 struct ntlm_buf *infotarget, 1910 unsigned char ntlmv2[16]) 1911{ 1912 int ret; 1913 1914 /** 1915 * First check with the domain as the client passed it to the function. 1916 */ 1917 1918 ret = verify_ntlm2(key, len, username, target, 0, now, 1919 serverchallenge, answer, infotarget, ntlmv2); 1920 1921 /** 1922 * Second check with domain uppercased. 1923 */ 1924 1925 if (ret) 1926 ret = verify_ntlm2(key, len, username, target, 1, now, 1927 serverchallenge, answer, infotarget, ntlmv2); 1928 1929 /** 1930 * Third check with empty domain. 1931 */ 1932 if (ret) 1933 ret = verify_ntlm2(key, len, username, "", 0, now, 1934 serverchallenge, answer, infotarget, ntlmv2); 1935 return ret; 1936} 1937 1938/* 1939 * Calculate the NTLM2 Session Response 1940 * 1941 * @param clnt_nonce client nonce 1942 * @param svr_chal server challage 1943 * @param ntlm2_hash ntlm hash 1944 * @param lm The LM response, should be freed with heim_ntlm_free_buf(). 1945 * @param ntlm The NTLM response, should be freed with heim_ntlm_free_buf(). 1946 * 1947 * @return In case of success 0 is return, an errors, a errno in what 1948 * went wrong. 1949 * 1950 * @ingroup ntlm_core 1951 */ 1952 1953int 1954heim_ntlm_calculate_ntlm2_sess(const unsigned char clnt_nonce[8], 1955 const unsigned char svr_chal[8], 1956 const unsigned char ntlm_hash[16], 1957 struct ntlm_buf *lm, 1958 struct ntlm_buf *ntlm) 1959{ 1960 unsigned char ntlm2_sess_hash[8]; 1961 unsigned char res[21], *resp; 1962 int code; 1963 1964 code = heim_ntlm_calculate_ntlm2_sess_hash(clnt_nonce, svr_chal, 1965 ntlm2_sess_hash); 1966 if (code) { 1967 return code; 1968 } 1969 1970 lm->data = malloc(24); 1971 if (lm->data == NULL) { 1972 return ENOMEM; 1973 } 1974 lm->length = 24; 1975 1976 ntlm->data = malloc(24); 1977 if (ntlm->data == NULL) { 1978 free(lm->data); 1979 lm->data = NULL; 1980 return ENOMEM; 1981 } 1982 ntlm->length = 24; 1983 1984 /* first setup the lm resp */ 1985 memset(lm->data, 0, 24); 1986 memcpy(lm->data, clnt_nonce, 8); 1987 1988 memset(res, 0, sizeof(res)); 1989 memcpy(res, ntlm_hash, 16); 1990 1991 resp = ntlm->data; 1992 splitandenc(&res[0], ntlm2_sess_hash, resp + 0); 1993 splitandenc(&res[7], ntlm2_sess_hash, resp + 8); 1994 splitandenc(&res[14], ntlm2_sess_hash, resp + 16); 1995 1996 return 0; 1997} 1998 1999 2000/* 2001 * Calculate the NTLM2 Session "Verifier" 2002 * 2003 * @param clnt_nonce client nonce 2004 * @param svr_chal server challage 2005 * @param hash The NTLM session verifier 2006 * 2007 * @return In case of success 0 is return, an errors, a errno in what 2008 * went wrong. 2009 * 2010 * @ingroup ntlm_core 2011 */ 2012 2013int 2014heim_ntlm_calculate_ntlm2_sess_hash(const unsigned char clnt_nonce[8], 2015 const unsigned char svr_chal[8], 2016 unsigned char verifier[8]) 2017{ 2018 unsigned char ntlm2_sess_hash[MD5_DIGEST_LENGTH]; 2019 EVP_MD_CTX *m; 2020 2021 m = EVP_MD_CTX_create(); 2022 if (m == NULL) 2023 return ENOMEM; 2024 2025 EVP_DigestInit_ex(m, EVP_md5(), NULL); 2026 EVP_DigestUpdate(m, svr_chal, 8); /* session nonce part 1 */ 2027 EVP_DigestUpdate(m, clnt_nonce, 8); /* session nonce part 2 */ 2028 EVP_DigestFinal_ex(m, ntlm2_sess_hash, NULL); /* will only use first 8 bytes */ 2029 EVP_MD_CTX_destroy(m); 2030 2031 memcpy(verifier, ntlm2_sess_hash, 8); 2032 2033 return 0; 2034} 2035 2036 2037/* 2038 * Derive a NTLM2 session key 2039 * 2040 * @param sessionkey session key from domain controller 2041 * @param clnt_nonce client nonce 2042 * @param svr_chal server challenge 2043 * @param derivedkey salted session key 2044 * 2045 * @return In case of success 0 is return, an errors, a errno in what 2046 * went wrong. 2047 * 2048 * @ingroup ntlm_core 2049 */ 2050 2051void 2052heim_ntlm_derive_ntlm2_sess(const unsigned char sessionkey[16], 2053 const unsigned char *clnt_nonce, size_t clnt_nonce_length, 2054 const unsigned char svr_chal[8], 2055 unsigned char derivedkey[16]) 2056{ 2057 unsigned int hmaclen; 2058 HMAC_CTX *c; 2059 2060 /* HMAC(Ksession, serverchallenge || clientchallenge) */ 2061#if OPENSSL_VERSION_NUMBER < 0x10100000UL 2062 HMAC_CTX cs; 2063 c = &cs; 2064 HMAC_CTX_init(c); 2065#else 2066 c = HMAC_CTX_new(); 2067#endif 2068 HMAC_Init_ex(c, sessionkey, 16, EVP_md5(), NULL); 2069 HMAC_Update(c, svr_chal, 8); 2070 HMAC_Update(c, clnt_nonce, clnt_nonce_length); 2071 HMAC_Final(c, derivedkey, &hmaclen); 2072#if OPENSSL_VERSION_NUMBER < 0x10100000UL 2073 HMAC_CTX_cleanup(c); 2074#else 2075 HMAC_CTX_free(c); 2076#endif 2077} 2078