1 /* 2 * Copyright (c) 2006 - 2007 Kungliga Tekniska H�gskolan 3 * (Royal Institute of Technology, Stockholm, Sweden). 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * 3. Neither the name of the Institute nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 34 #include <config.h> 35 36 RCSID("$Id: ntlm.c 22370 2007-12-28 16:12:01Z lha $"); 37 38 #include <stdio.h> 39 #include <stdlib.h> 40 #include <assert.h> 41 #include <string.h> 42 #include <ctype.h> 43 #include <errno.h> 44 #include <limits.h> 45 46 #include <krb5.h> 47 #include <roken.h> 48 49 #include "krb5-types.h" 50 #include "crypto-headers.h" 51 52 #include <heimntlm.h> 53 54 /*! \mainpage Heimdal NTLM library 55 * 56 * \section intro Introduction 57 * 58 * Heimdal libheimntlm library is a implementation of the NTLM 59 * protocol, both version 1 and 2. The GSS-API mech that uses this 60 * library adds support for transport encryption and integrity 61 * checking. 62 * 63 * NTLM is a protocol for mutual authentication, its still used in 64 * many protocol where Kerberos is not support, one example is 65 * EAP/X802.1x mechanism LEAP from Microsoft and Cisco. 66 * 67 * This is a support library for the core protocol, its used in 68 * Heimdal to implement and GSS-API mechanism. There is also support 69 * in the KDC to do remote digest authenticiation, this to allow 70 * services to authenticate users w/o direct access to the users ntlm 71 * hashes (same as Kerberos arcfour enctype hashes). 72 * 73 * More information about the NTLM protocol can found here 74 * http://davenport.sourceforge.net/ntlm.html . 75 * 76 * The Heimdal projects web page: http://www.h5l.org/ 77 */ 78 79 /** @defgroup ntlm_core Heimdal NTLM library 80 * 81 * The NTLM core functions implement the string2key generation 82 * function, message encode and decode function, and the hash function 83 * functions. 84 */ 85 86 struct sec_buffer { 87 uint16_t length; 88 uint16_t allocated; 89 uint32_t offset; 90 }; 91 92 static const unsigned char ntlmsigature[8] = "NTLMSSP\x00"; 93 94 /* 95 * 96 */ 97 98 #define CHECK(f, e) \ 99 do { ret = f ; if (ret != (e)) { ret = EINVAL; goto out; } } while(0) 100 101 /** 102 * heim_ntlm_free_buf frees the ntlm buffer 103 * 104 * @param p buffer to be freed 105 * 106 * @ingroup ntlm_core 107 */ 108 109 void 110 heim_ntlm_free_buf(struct ntlm_buf *p) 111 { 112 if (p->data) 113 free(p->data); 114 p->data = NULL; 115 p->length = 0; 116 } 117 118 119 static int 120 ascii2ucs2le(const char *string, int up, struct ntlm_buf *buf) 121 { 122 unsigned char *p; 123 size_t len, i; 124 125 len = strlen(string); 126 if (len / 2 > UINT_MAX) 127 return ERANGE; 128 129 buf->length = len * 2; 130 buf->data = malloc(buf->length); 131 if (buf->data == NULL && len != 0) { 132 heim_ntlm_free_buf(buf); 133 return ENOMEM; 134 } 135 136 p = buf->data; 137 for (i = 0; i < len; i++) { 138 unsigned char t = (unsigned char)string[i]; 139 if (t & 0x80) { 140 heim_ntlm_free_buf(buf); 141 return EINVAL; 142 } 143 if (up) 144 t = toupper(t); 145 p[(i * 2) + 0] = t; 146 p[(i * 2) + 1] = 0; 147 } 148 return 0; 149 } 150 151 /* 152 * 153 */ 154 155 static krb5_error_code 156 ret_sec_buffer(krb5_storage *sp, struct sec_buffer *buf) 157 { 158 krb5_error_code ret; 159 CHECK(krb5_ret_uint16(sp, &buf->length), 0); 160 CHECK(krb5_ret_uint16(sp, &buf->allocated), 0); 161 CHECK(krb5_ret_uint32(sp, &buf->offset), 0); 162 out: 163 return ret; 164 } 165 166 static krb5_error_code 167 store_sec_buffer(krb5_storage *sp, const struct sec_buffer *buf) 168 { 169 krb5_error_code ret; 170 CHECK(krb5_store_uint16(sp, buf->length), 0); 171 CHECK(krb5_store_uint16(sp, buf->allocated), 0); 172 CHECK(krb5_store_uint32(sp, buf->offset), 0); 173 out: 174 return ret; 175 } 176 177 /* 178 * Strings are either OEM or UNICODE. The later is encoded as ucs2 on 179 * wire, but using utf8 in memory. 180 */ 181 182 static krb5_error_code 183 len_string(int ucs2, const char *s) 184 { 185 size_t len = strlen(s); 186 if (ucs2) 187 len *= 2; 188 return len; 189 } 190 191 static krb5_error_code 192 ret_string(krb5_storage *sp, int ucs2, struct sec_buffer *desc, char **s) 193 { 194 krb5_error_code ret; 195 196 *s = malloc(desc->length + 1); 197 CHECK(krb5_storage_seek(sp, desc->offset, SEEK_SET), desc->offset); 198 CHECK(krb5_storage_read(sp, *s, desc->length), desc->length); 199 (*s)[desc->length] = '\0'; 200 201 if (ucs2) { 202 size_t i; 203 for (i = 0; i < desc->length / 2; i++) { 204 (*s)[i] = (*s)[i * 2]; 205 if ((*s)[i * 2 + 1]) { 206 free(*s); 207 *s = NULL; 208 return EINVAL; 209 } 210 } 211 (*s)[i] = '\0'; 212 } 213 ret = 0; 214 out: 215 return ret; 216 217 return 0; 218 } 219 220 static krb5_error_code 221 put_string(krb5_storage *sp, int ucs2, const char *s) 222 { 223 krb5_error_code ret; 224 struct ntlm_buf buf; 225 226 if (ucs2) { 227 ret = ascii2ucs2le(s, 0, &buf); 228 if (ret) 229 return ret; 230 } else { 231 buf.data = rk_UNCONST(s); 232 buf.length = strlen(s); 233 } 234 235 CHECK(krb5_storage_write(sp, buf.data, buf.length), buf.length); 236 if (ucs2) 237 heim_ntlm_free_buf(&buf); 238 ret = 0; 239 out: 240 return ret; 241 } 242 243 /* 244 * 245 */ 246 247 static krb5_error_code 248 ret_buf(krb5_storage *sp, struct sec_buffer *desc, struct ntlm_buf *buf) 249 { 250 krb5_error_code ret; 251 252 buf->data = malloc(desc->length); 253 buf->length = desc->length; 254 CHECK(krb5_storage_seek(sp, desc->offset, SEEK_SET), desc->offset); 255 CHECK(krb5_storage_read(sp, buf->data, buf->length), buf->length); 256 ret = 0; 257 out: 258 return ret; 259 } 260 261 static krb5_error_code 262 put_buf(krb5_storage *sp, const struct ntlm_buf *buf) 263 { 264 krb5_error_code ret; 265 CHECK(krb5_storage_write(sp, buf->data, buf->length), buf->length); 266 ret = 0; 267 out: 268 return ret; 269 } 270 271 /** 272 * Frees the ntlm_targetinfo message 273 * 274 * @param ti targetinfo to be freed 275 * 276 * @ingroup ntlm_core 277 */ 278 279 void 280 heim_ntlm_free_targetinfo(struct ntlm_targetinfo *ti) 281 { 282 free(ti->servername); 283 free(ti->domainname); 284 free(ti->dnsdomainname); 285 free(ti->dnsservername); 286 memset(ti, 0, sizeof(*ti)); 287 } 288 289 static int 290 encode_ti_blob(krb5_storage *out, uint16_t type, int ucs2, char *s) 291 { 292 krb5_error_code ret; 293 CHECK(krb5_store_uint16(out, type), 0); 294 CHECK(krb5_store_uint16(out, len_string(ucs2, s)), 0); 295 CHECK(put_string(out, ucs2, s), 0); 296 out: 297 return ret; 298 } 299 300 /** 301 * Encodes a ntlm_targetinfo message. 302 * 303 * @param ti the ntlm_targetinfo message to encode. 304 * @param ucs2 if the strings should be encoded with ucs2 (selected by flag in message). 305 * @param data is the return buffer with the encoded message, should be 306 * freed with heim_ntlm_free_buf(). 307 * 308 * @return In case of success 0 is return, an errors, a errno in what 309 * went wrong. 310 * 311 * @ingroup ntlm_core 312 */ 313 314 int 315 heim_ntlm_encode_targetinfo(const struct ntlm_targetinfo *ti, 316 int ucs2, 317 struct ntlm_buf *data) 318 { 319 krb5_error_code ret; 320 krb5_storage *out; 321 322 data->data = NULL; 323 data->length = 0; 324 325 out = krb5_storage_emem(); 326 if (out == NULL) 327 return ENOMEM; 328 329 if (ti->servername) 330 CHECK(encode_ti_blob(out, 1, ucs2, ti->servername), 0); 331 if (ti->domainname) 332 CHECK(encode_ti_blob(out, 2, ucs2, ti->domainname), 0); 333 if (ti->dnsservername) 334 CHECK(encode_ti_blob(out, 3, ucs2, ti->dnsservername), 0); 335 if (ti->dnsdomainname) 336 CHECK(encode_ti_blob(out, 4, ucs2, ti->dnsdomainname), 0); 337 338 /* end tag */ 339 CHECK(krb5_store_int16(out, 0), 0); 340 CHECK(krb5_store_int16(out, 0), 0); 341 342 { 343 krb5_data d; 344 ret = krb5_storage_to_data(out, &d); 345 data->data = d.data; 346 data->length = d.length; 347 } 348 out: 349 krb5_storage_free(out); 350 return ret; 351 } 352 353 /** 354 * Decodes an NTLM targetinfo message 355 * 356 * @param data input data buffer with the encode NTLM targetinfo message 357 * @param ucs2 if the strings should be encoded with ucs2 (selected by flag in message). 358 * @param ti the decoded target info, should be freed with heim_ntlm_free_targetinfo(). 359 * 360 * @return In case of success 0 is return, an errors, a errno in what 361 * went wrong. 362 * 363 * @ingroup ntlm_core 364 */ 365 366 int 367 heim_ntlm_decode_targetinfo(const struct ntlm_buf *data, 368 int ucs2, 369 struct ntlm_targetinfo *ti) 370 { 371 memset(ti, 0, sizeof(*ti)); 372 return 0; 373 } 374 375 /** 376 * Frees the ntlm_type1 message 377 * 378 * @param data message to be freed 379 * 380 * @ingroup ntlm_core 381 */ 382 383 void 384 heim_ntlm_free_type1(struct ntlm_type1 *data) 385 { 386 if (data->domain) 387 free(data->domain); 388 if (data->hostname) 389 free(data->hostname); 390 memset(data, 0, sizeof(*data)); 391 } 392 393 int 394 heim_ntlm_decode_type1(const struct ntlm_buf *buf, struct ntlm_type1 *data) 395 { 396 krb5_error_code ret; 397 unsigned char sig[8]; 398 uint32_t type; 399 struct sec_buffer domain, hostname; 400 krb5_storage *in; 401 402 memset(data, 0, sizeof(*data)); 403 404 in = krb5_storage_from_readonly_mem(buf->data, buf->length); 405 if (in == NULL) { 406 ret = EINVAL; 407 goto out; 408 } 409 krb5_storage_set_byteorder(in, KRB5_STORAGE_BYTEORDER_LE); 410 411 CHECK(krb5_storage_read(in, sig, sizeof(sig)), sizeof(sig)); 412 CHECK(memcmp(ntlmsigature, sig, sizeof(ntlmsigature)), 0); 413 CHECK(krb5_ret_uint32(in, &type), 0); 414 CHECK(type, 1); 415 CHECK(krb5_ret_uint32(in, &data->flags), 0); 416 if (data->flags & NTLM_SUPPLIED_DOMAIN) 417 CHECK(ret_sec_buffer(in, &domain), 0); 418 if (data->flags & NTLM_SUPPLIED_WORKSTAION) 419 CHECK(ret_sec_buffer(in, &hostname), 0); 420 #if 0 421 if (domain.offset > 32) { 422 CHECK(krb5_ret_uint32(in, &data->os[0]), 0); 423 CHECK(krb5_ret_uint32(in, &data->os[1]), 0); 424 } 425 #endif 426 if (data->flags & NTLM_SUPPLIED_DOMAIN) 427 CHECK(ret_string(in, 0, &domain, &data->domain), 0); 428 if (data->flags & NTLM_SUPPLIED_WORKSTAION) 429 CHECK(ret_string(in, 0, &hostname, &data->hostname), 0); 430 431 out: 432 krb5_storage_free(in); 433 if (ret) 434 heim_ntlm_free_type1(data); 435 436 return ret; 437 } 438 439 /** 440 * Encodes an ntlm_type1 message. 441 * 442 * @param type1 the ntlm_type1 message to encode. 443 * @param data is the return buffer with the encoded message, should be 444 * freed with heim_ntlm_free_buf(). 445 * 446 * @return In case of success 0 is return, an errors, a errno in what 447 * went wrong. 448 * 449 * @ingroup ntlm_core 450 */ 451 452 int 453 heim_ntlm_encode_type1(const struct ntlm_type1 *type1, struct ntlm_buf *data) 454 { 455 krb5_error_code ret; 456 struct sec_buffer domain, hostname; 457 krb5_storage *out; 458 uint32_t base, flags; 459 460 flags = type1->flags; 461 base = 16; 462 463 if (type1->domain) { 464 base += 8; 465 flags |= NTLM_SUPPLIED_DOMAIN; 466 } 467 if (type1->hostname) { 468 base += 8; 469 flags |= NTLM_SUPPLIED_WORKSTAION; 470 } 471 if (type1->os[0]) 472 base += 8; 473 474 if (type1->domain) { 475 domain.offset = base; 476 domain.length = len_string(0, type1->domain); 477 domain.allocated = domain.length; 478 } 479 if (type1->hostname) { 480 hostname.offset = domain.allocated + domain.offset; 481 hostname.length = len_string(0, type1->hostname); 482 hostname.allocated = hostname.length; 483 } 484 485 out = krb5_storage_emem(); 486 if (out == NULL) 487 return ENOMEM; 488 489 krb5_storage_set_byteorder(out, KRB5_STORAGE_BYTEORDER_LE); 490 CHECK(krb5_storage_write(out, ntlmsigature, sizeof(ntlmsigature)), 491 sizeof(ntlmsigature)); 492 CHECK(krb5_store_uint32(out, 1), 0); 493 CHECK(krb5_store_uint32(out, flags), 0); 494 495 if (type1->domain) 496 CHECK(store_sec_buffer(out, &domain), 0); 497 if (type1->hostname) 498 CHECK(store_sec_buffer(out, &hostname), 0); 499 if (type1->os[0]) { 500 CHECK(krb5_store_uint32(out, type1->os[0]), 0); 501 CHECK(krb5_store_uint32(out, type1->os[1]), 0); 502 } 503 if (type1->domain) 504 CHECK(put_string(out, 0, type1->domain), 0); 505 if (type1->hostname) 506 CHECK(put_string(out, 0, type1->hostname), 0); 507 508 { 509 krb5_data d; 510 ret = krb5_storage_to_data(out, &d); 511 data->data = d.data; 512 data->length = d.length; 513 } 514 out: 515 krb5_storage_free(out); 516 517 return ret; 518 } 519 520 /** 521 * Frees the ntlm_type2 message 522 * 523 * @param data message to be freed 524 * 525 * @ingroup ntlm_core 526 */ 527 528 void 529 heim_ntlm_free_type2(struct ntlm_type2 *data) 530 { 531 if (data->targetname) 532 free(data->targetname); 533 heim_ntlm_free_buf(&data->targetinfo); 534 memset(data, 0, sizeof(*data)); 535 } 536 537 int 538 heim_ntlm_decode_type2(const struct ntlm_buf *buf, struct ntlm_type2 *type2) 539 { 540 krb5_error_code ret; 541 unsigned char sig[8]; 542 uint32_t type, ctx[2]; 543 struct sec_buffer targetname, targetinfo; 544 krb5_storage *in; 545 int ucs2 = 0; 546 547 memset(type2, 0, sizeof(*type2)); 548 549 in = krb5_storage_from_readonly_mem(buf->data, buf->length); 550 if (in == NULL) { 551 ret = EINVAL; 552 goto out; 553 } 554 krb5_storage_set_byteorder(in, KRB5_STORAGE_BYTEORDER_LE); 555 556 CHECK(krb5_storage_read(in, sig, sizeof(sig)), sizeof(sig)); 557 CHECK(memcmp(ntlmsigature, sig, sizeof(ntlmsigature)), 0); 558 CHECK(krb5_ret_uint32(in, &type), 0); 559 CHECK(type, 2); 560 561 CHECK(ret_sec_buffer(in, &targetname), 0); 562 CHECK(krb5_ret_uint32(in, &type2->flags), 0); 563 if (type2->flags & NTLM_NEG_UNICODE) 564 ucs2 = 1; 565 CHECK(krb5_storage_read(in, type2->challange, sizeof(type2->challange)), 566 sizeof(type2->challange)); 567 CHECK(krb5_ret_uint32(in, &ctx[0]), 0); /* context */ 568 CHECK(krb5_ret_uint32(in, &ctx[1]), 0); 569 CHECK(ret_sec_buffer(in, &targetinfo), 0); 570 /* os version */ 571 #if 0 572 CHECK(krb5_ret_uint32(in, &type2->os[0]), 0); 573 CHECK(krb5_ret_uint32(in, &type2->os[1]), 0); 574 #endif 575 576 CHECK(ret_string(in, ucs2, &targetname, &type2->targetname), 0); 577 CHECK(ret_buf(in, &targetinfo, &type2->targetinfo), 0); 578 ret = 0; 579 580 out: 581 krb5_storage_free(in); 582 if (ret) 583 heim_ntlm_free_type2(type2); 584 585 return ret; 586 } 587 588 /** 589 * Encodes an ntlm_type2 message. 590 * 591 * @param type2 the ntlm_type2 message to encode. 592 * @param data is the return buffer with the encoded message, should be 593 * freed with heim_ntlm_free_buf(). 594 * 595 * @return In case of success 0 is return, an errors, a errno in what 596 * went wrong. 597 * 598 * @ingroup ntlm_core 599 */ 600 601 int 602 heim_ntlm_encode_type2(const struct ntlm_type2 *type2, struct ntlm_buf *data) 603 { 604 struct sec_buffer targetname, targetinfo; 605 krb5_error_code ret; 606 krb5_storage *out = NULL; 607 uint32_t base; 608 int ucs2 = 0; 609 610 if (type2->os[0]) 611 base = 56; 612 else 613 base = 48; 614 615 if (type2->flags & NTLM_NEG_UNICODE) 616 ucs2 = 1; 617 618 targetname.offset = base; 619 targetname.length = len_string(ucs2, type2->targetname); 620 targetname.allocated = targetname.length; 621 622 targetinfo.offset = targetname.allocated + targetname.offset; 623 targetinfo.length = type2->targetinfo.length; 624 targetinfo.allocated = type2->targetinfo.length; 625 626 out = krb5_storage_emem(); 627 if (out == NULL) 628 return ENOMEM; 629 630 krb5_storage_set_byteorder(out, KRB5_STORAGE_BYTEORDER_LE); 631 CHECK(krb5_storage_write(out, ntlmsigature, sizeof(ntlmsigature)), 632 sizeof(ntlmsigature)); 633 CHECK(krb5_store_uint32(out, 2), 0); 634 CHECK(store_sec_buffer(out, &targetname), 0); 635 CHECK(krb5_store_uint32(out, type2->flags), 0); 636 CHECK(krb5_storage_write(out, type2->challange, sizeof(type2->challange)), 637 sizeof(type2->challange)); 638 CHECK(krb5_store_uint32(out, 0), 0); /* context */ 639 CHECK(krb5_store_uint32(out, 0), 0); 640 CHECK(store_sec_buffer(out, &targetinfo), 0); 641 /* os version */ 642 if (type2->os[0]) { 643 CHECK(krb5_store_uint32(out, type2->os[0]), 0); 644 CHECK(krb5_store_uint32(out, type2->os[1]), 0); 645 } 646 CHECK(put_string(out, ucs2, type2->targetname), 0); 647 CHECK(krb5_storage_write(out, type2->targetinfo.data, 648 type2->targetinfo.length), 649 type2->targetinfo.length); 650 651 { 652 krb5_data d; 653 ret = krb5_storage_to_data(out, &d); 654 data->data = d.data; 655 data->length = d.length; 656 } 657 658 out: 659 krb5_storage_free(out); 660 661 return ret; 662 } 663 664 /** 665 * Frees the ntlm_type3 message 666 * 667 * @param data message to be freed 668 * 669 * @ingroup ntlm_core 670 */ 671 672 void 673 heim_ntlm_free_type3(struct ntlm_type3 *data) 674 { 675 heim_ntlm_free_buf(&data->lm); 676 heim_ntlm_free_buf(&data->ntlm); 677 if (data->targetname) 678 free(data->targetname); 679 if (data->username) 680 free(data->username); 681 if (data->ws) 682 free(data->ws); 683 heim_ntlm_free_buf(&data->sessionkey); 684 memset(data, 0, sizeof(*data)); 685 } 686 687 /* 688 * 689 */ 690 691 int 692 heim_ntlm_decode_type3(const struct ntlm_buf *buf, 693 int ucs2, 694 struct ntlm_type3 *type3) 695 { 696 krb5_error_code ret; 697 unsigned char sig[8]; 698 uint32_t type; 699 krb5_storage *in; 700 struct sec_buffer lm, ntlm, target, username, sessionkey, ws; 701 702 memset(type3, 0, sizeof(*type3)); 703 memset(&sessionkey, 0, sizeof(sessionkey)); 704 705 in = krb5_storage_from_readonly_mem(buf->data, buf->length); 706 if (in == NULL) { 707 ret = EINVAL; 708 goto out; 709 } 710 krb5_storage_set_byteorder(in, KRB5_STORAGE_BYTEORDER_LE); 711 712 CHECK(krb5_storage_read(in, sig, sizeof(sig)), sizeof(sig)); 713 CHECK(memcmp(ntlmsigature, sig, sizeof(ntlmsigature)), 0); 714 CHECK(krb5_ret_uint32(in, &type), 0); 715 CHECK(type, 3); 716 CHECK(ret_sec_buffer(in, &lm), 0); 717 CHECK(ret_sec_buffer(in, &ntlm), 0); 718 CHECK(ret_sec_buffer(in, &target), 0); 719 CHECK(ret_sec_buffer(in, &username), 0); 720 CHECK(ret_sec_buffer(in, &ws), 0); 721 if (lm.offset >= 60) { 722 CHECK(ret_sec_buffer(in, &sessionkey), 0); 723 } 724 if (lm.offset >= 64) { 725 CHECK(krb5_ret_uint32(in, &type3->flags), 0); 726 } 727 if (lm.offset >= 72) { 728 CHECK(krb5_ret_uint32(in, &type3->os[0]), 0); 729 CHECK(krb5_ret_uint32(in, &type3->os[1]), 0); 730 } 731 CHECK(ret_buf(in, &lm, &type3->lm), 0); 732 CHECK(ret_buf(in, &ntlm, &type3->ntlm), 0); 733 CHECK(ret_string(in, ucs2, &target, &type3->targetname), 0); 734 CHECK(ret_string(in, ucs2, &username, &type3->username), 0); 735 CHECK(ret_string(in, ucs2, &ws, &type3->ws), 0); 736 if (sessionkey.offset) 737 CHECK(ret_buf(in, &sessionkey, &type3->sessionkey), 0); 738 739 out: 740 krb5_storage_free(in); 741 if (ret) 742 heim_ntlm_free_type3(type3); 743 744 return ret; 745 } 746 747 /** 748 * Encodes an ntlm_type3 message. 749 * 750 * @param type3 the ntlm_type3 message to encode. 751 * @param data is the return buffer with the encoded message, should be 752 * freed with heim_ntlm_free_buf(). 753 * 754 * @return In case of success 0 is return, an errors, a errno in what 755 * went wrong. 756 * 757 * @ingroup ntlm_core 758 */ 759 760 int 761 heim_ntlm_encode_type3(const struct ntlm_type3 *type3, struct ntlm_buf *data) 762 { 763 struct sec_buffer lm, ntlm, target, username, sessionkey, ws; 764 krb5_error_code ret; 765 krb5_storage *out = NULL; 766 uint32_t base; 767 int ucs2 = 0; 768 769 memset(&lm, 0, sizeof(lm)); 770 memset(&ntlm, 0, sizeof(ntlm)); 771 memset(&target, 0, sizeof(target)); 772 memset(&username, 0, sizeof(username)); 773 memset(&ws, 0, sizeof(ws)); 774 memset(&sessionkey, 0, sizeof(sessionkey)); 775 776 base = 52; 777 if (type3->sessionkey.length) { 778 base += 8; /* sessionkey sec buf */ 779 base += 4; /* flags */ 780 } 781 if (type3->os[0]) { 782 base += 8; 783 } 784 785 if (type3->flags & NTLM_NEG_UNICODE) 786 ucs2 = 1; 787 788 lm.offset = base; 789 lm.length = type3->lm.length; 790 lm.allocated = type3->lm.length; 791 792 ntlm.offset = lm.offset + lm.allocated; 793 ntlm.length = type3->ntlm.length; 794 ntlm.allocated = ntlm.length; 795 796 target.offset = ntlm.offset + ntlm.allocated; 797 target.length = len_string(ucs2, type3->targetname); 798 target.allocated = target.length; 799 800 username.offset = target.offset + target.allocated; 801 username.length = len_string(ucs2, type3->username); 802 username.allocated = username.length; 803 804 ws.offset = username.offset + username.allocated; 805 ws.length = len_string(ucs2, type3->ws); 806 ws.allocated = ws.length; 807 808 sessionkey.offset = ws.offset + ws.allocated; 809 sessionkey.length = type3->sessionkey.length; 810 sessionkey.allocated = type3->sessionkey.length; 811 812 out = krb5_storage_emem(); 813 if (out == NULL) 814 return ENOMEM; 815 816 krb5_storage_set_byteorder(out, KRB5_STORAGE_BYTEORDER_LE); 817 CHECK(krb5_storage_write(out, ntlmsigature, sizeof(ntlmsigature)), 818 sizeof(ntlmsigature)); 819 CHECK(krb5_store_uint32(out, 3), 0); 820 821 CHECK(store_sec_buffer(out, &lm), 0); 822 CHECK(store_sec_buffer(out, &ntlm), 0); 823 CHECK(store_sec_buffer(out, &target), 0); 824 CHECK(store_sec_buffer(out, &username), 0); 825 CHECK(store_sec_buffer(out, &ws), 0); 826 /* optional */ 827 if (type3->sessionkey.length) { 828 CHECK(store_sec_buffer(out, &sessionkey), 0); 829 CHECK(krb5_store_uint32(out, type3->flags), 0); 830 } 831 #if 0 832 CHECK(krb5_store_uint32(out, 0), 0); /* os0 */ 833 CHECK(krb5_store_uint32(out, 0), 0); /* os1 */ 834 #endif 835 836 CHECK(put_buf(out, &type3->lm), 0); 837 CHECK(put_buf(out, &type3->ntlm), 0); 838 CHECK(put_string(out, ucs2, type3->targetname), 0); 839 CHECK(put_string(out, ucs2, type3->username), 0); 840 CHECK(put_string(out, ucs2, type3->ws), 0); 841 CHECK(put_buf(out, &type3->sessionkey), 0); 842 843 { 844 krb5_data d; 845 ret = krb5_storage_to_data(out, &d); 846 data->data = d.data; 847 data->length = d.length; 848 } 849 850 out: 851 krb5_storage_free(out); 852 853 return ret; 854 } 855 856 857 /* 858 * 859 */ 860 861 static void 862 splitandenc(unsigned char *hash, 863 unsigned char *challange, 864 unsigned char *answer) 865 { 866 DES_cblock key; 867 DES_key_schedule sched; 868 869 ((unsigned char*)key)[0] = hash[0]; 870 ((unsigned char*)key)[1] = (hash[0] << 7) | (hash[1] >> 1); 871 ((unsigned char*)key)[2] = (hash[1] << 6) | (hash[2] >> 2); 872 ((unsigned char*)key)[3] = (hash[2] << 5) | (hash[3] >> 3); 873 ((unsigned char*)key)[4] = (hash[3] << 4) | (hash[4] >> 4); 874 ((unsigned char*)key)[5] = (hash[4] << 3) | (hash[5] >> 5); 875 ((unsigned char*)key)[6] = (hash[5] << 2) | (hash[6] >> 6); 876 ((unsigned char*)key)[7] = (hash[6] << 1); 877 878 DES_set_odd_parity(&key); 879 DES_set_key(&key, &sched); 880 DES_ecb_encrypt((DES_cblock *)challange, (DES_cblock *)answer, &sched, 1); 881 memset(&sched, 0, sizeof(sched)); 882 memset(key, 0, sizeof(key)); 883 } 884 885 /** 886 * Calculate the NTLM key, the password is assumed to be in UTF8. 887 * 888 * @param password password to calcute the key for. 889 * @param key calcuted key, should be freed with heim_ntlm_free_buf(). 890 * 891 * @return In case of success 0 is return, an errors, a errno in what 892 * went wrong. 893 * 894 * @ingroup ntlm_core 895 */ 896 897 int 898 heim_ntlm_nt_key(const char *password, struct ntlm_buf *key) 899 { 900 struct ntlm_buf buf; 901 MD4_CTX ctx; 902 int ret; 903 904 key->data = malloc(MD5_DIGEST_LENGTH); 905 if (key->data == NULL) 906 return ENOMEM; 907 key->length = MD5_DIGEST_LENGTH; 908 909 ret = ascii2ucs2le(password, 0, &buf); 910 if (ret) { 911 heim_ntlm_free_buf(key); 912 return ret; 913 } 914 MD4_Init(&ctx); 915 MD4_Update(&ctx, buf.data, buf.length); 916 MD4_Final(key->data, &ctx); 917 heim_ntlm_free_buf(&buf); 918 return 0; 919 } 920 921 /** 922 * Calculate NTLMv1 response hash 923 * 924 * @param key the ntlm v1 key 925 * @param len length of key 926 * @param challange sent by the server 927 * @param answer calculated answer, should be freed with heim_ntlm_free_buf(). 928 * 929 * @return In case of success 0 is return, an errors, a errno in what 930 * went wrong. 931 * 932 * @ingroup ntlm_core 933 */ 934 935 int 936 heim_ntlm_calculate_ntlm1(void *key, size_t len, 937 unsigned char challange[8], 938 struct ntlm_buf *answer) 939 { 940 unsigned char res[21]; 941 942 if (len != MD4_DIGEST_LENGTH) 943 return EINVAL; 944 945 memcpy(res, key, len); 946 memset(&res[MD4_DIGEST_LENGTH], 0, sizeof(res) - MD4_DIGEST_LENGTH); 947 948 answer->data = malloc(24); 949 if (answer->data == NULL) 950 return ENOMEM; 951 answer->length = 24; 952 953 splitandenc(&res[0], challange, ((unsigned char *)answer->data) + 0); 954 splitandenc(&res[7], challange, ((unsigned char *)answer->data) + 8); 955 splitandenc(&res[14], challange, ((unsigned char *)answer->data) + 16); 956 957 return 0; 958 } 959 960 /** 961 * Generates an NTLMv1 session random with assosited session master key. 962 * 963 * @param key the ntlm v1 key 964 * @param len length of key 965 * @param session generated session nonce, should be freed with heim_ntlm_free_buf(). 966 * @param master calculated session master key, should be freed with heim_ntlm_free_buf(). 967 * 968 * @return In case of success 0 is return, an errors, a errno in what 969 * went wrong. 970 * 971 * @ingroup ntlm_core 972 */ 973 974 int 975 heim_ntlm_build_ntlm1_master(void *key, size_t len, 976 struct ntlm_buf *session, 977 struct ntlm_buf *master) 978 { 979 RC4_KEY rc4; 980 981 memset(master, 0, sizeof(*master)); 982 memset(session, 0, sizeof(*session)); 983 984 if (len != MD4_DIGEST_LENGTH) 985 return EINVAL; 986 987 session->length = MD4_DIGEST_LENGTH; 988 session->data = malloc(session->length); 989 if (session->data == NULL) { 990 session->length = 0; 991 return EINVAL; 992 } 993 master->length = MD4_DIGEST_LENGTH; 994 master->data = malloc(master->length); 995 if (master->data == NULL) { 996 heim_ntlm_free_buf(master); 997 heim_ntlm_free_buf(session); 998 return EINVAL; 999 } 1000 1001 { 1002 unsigned char sessionkey[MD4_DIGEST_LENGTH]; 1003 MD4_CTX ctx; 1004 1005 MD4_Init(&ctx); 1006 MD4_Update(&ctx, key, len); 1007 MD4_Final(sessionkey, &ctx); 1008 1009 RC4_set_key(&rc4, sizeof(sessionkey), sessionkey); 1010 } 1011 1012 if (RAND_bytes(session->data, session->length) != 1) { 1013 heim_ntlm_free_buf(master); 1014 heim_ntlm_free_buf(session); 1015 return EINVAL; 1016 } 1017 1018 RC4(&rc4, master->length, session->data, master->data); 1019 memset(&rc4, 0, sizeof(rc4)); 1020 1021 return 0; 1022 } 1023 1024 /** 1025 * Generates an NTLMv2 session key. 1026 * 1027 * @param key the ntlm key 1028 * @param len length of key 1029 * @param username name of the user, as sent in the message, assumed to be in UTF8. 1030 * @param target the name of the target, assumed to be in UTF8. 1031 * @param ntlmv2 the ntlmv2 session key 1032 * 1033 * @ingroup ntlm_core 1034 */ 1035 1036 void 1037 heim_ntlm_ntlmv2_key(const void *key, size_t len, 1038 const char *username, 1039 const char *target, 1040 unsigned char ntlmv2[16]) 1041 { 1042 unsigned int hmaclen; 1043 HMAC_CTX c; 1044 1045 HMAC_CTX_init(&c); 1046 HMAC_Init_ex(&c, key, len, EVP_md5(), NULL); 1047 { 1048 struct ntlm_buf buf; 1049 /* uppercase username and turn it inte ucs2-le */ 1050 ascii2ucs2le(username, 1, &buf); 1051 HMAC_Update(&c, buf.data, buf.length); 1052 free(buf.data); 1053 /* uppercase target and turn into ucs2-le */ 1054 ascii2ucs2le(target, 1, &buf); 1055 HMAC_Update(&c, buf.data, buf.length); 1056 free(buf.data); 1057 } 1058 HMAC_Final(&c, ntlmv2, &hmaclen); 1059 HMAC_CTX_cleanup(&c); 1060 1061 } 1062 1063 /* 1064 * 1065 */ 1066 1067 #define NTTIME_EPOCH 0x019DB1DED53E8000LL 1068 1069 static uint64_t 1070 unix2nttime(time_t unix_time) 1071 { 1072 long long wt; 1073 wt = unix_time * (uint64_t)10000000 + (uint64_t)NTTIME_EPOCH; 1074 return wt; 1075 } 1076 1077 static time_t 1078 nt2unixtime(uint64_t t) 1079 { 1080 t = ((t - (uint64_t)NTTIME_EPOCH) / (uint64_t)10000000); 1081 if (t > (((time_t)(~(uint64_t)0)) >> 1)) 1082 return 0; 1083 return (time_t)t; 1084 } 1085 1086 1087 /** 1088 * Calculate NTLMv2 response 1089 * 1090 * @param key the ntlm key 1091 * @param len length of key 1092 * @param username name of the user, as sent in the message, assumed to be in UTF8. 1093 * @param target the name of the target, assumed to be in UTF8. 1094 * @param serverchallange challange as sent by the server in the type2 message. 1095 * @param infotarget infotarget as sent by the server in the type2 message. 1096 * @param ntlmv2 calculated session key 1097 * @param answer ntlm response answer, should be freed with heim_ntlm_free_buf(). 1098 * 1099 * @return In case of success 0 is return, an errors, a errno in what 1100 * went wrong. 1101 * 1102 * @ingroup ntlm_core 1103 */ 1104 1105 int 1106 heim_ntlm_calculate_ntlm2(const void *key, size_t len, 1107 const char *username, 1108 const char *target, 1109 const unsigned char serverchallange[8], 1110 const struct ntlm_buf *infotarget, 1111 unsigned char ntlmv2[16], 1112 struct ntlm_buf *answer) 1113 { 1114 krb5_error_code ret; 1115 krb5_data data; 1116 unsigned int hmaclen; 1117 unsigned char ntlmv2answer[16]; 1118 krb5_storage *sp; 1119 unsigned char clientchallange[8]; 1120 HMAC_CTX c; 1121 uint64_t t; 1122 1123 t = unix2nttime(time(NULL)); 1124 1125 if (RAND_bytes(clientchallange, sizeof(clientchallange)) != 1) 1126 return EINVAL; 1127 1128 /* calculate ntlmv2 key */ 1129 1130 heim_ntlm_ntlmv2_key(key, len, username, target, ntlmv2); 1131 1132 /* calculate and build ntlmv2 answer */ 1133 1134 sp = krb5_storage_emem(); 1135 if (sp == NULL) 1136 return ENOMEM; 1137 krb5_storage_set_flags(sp, KRB5_STORAGE_BYTEORDER_LE); 1138 1139 CHECK(krb5_store_uint32(sp, 0x00000101), 0); 1140 CHECK(krb5_store_uint32(sp, 0), 0); 1141 /* timestamp le 64 bit ts */ 1142 CHECK(krb5_store_uint32(sp, t & 0xffffffff), 0); 1143 CHECK(krb5_store_uint32(sp, t >> 32), 0); 1144 1145 CHECK(krb5_storage_write(sp, clientchallange, 8), 8); 1146 1147 CHECK(krb5_store_uint32(sp, 0), 0); /* unknown but zero will work */ 1148 CHECK(krb5_storage_write(sp, infotarget->data, infotarget->length), 1149 infotarget->length); 1150 CHECK(krb5_store_uint32(sp, 0), 0); /* unknown but zero will work */ 1151 1152 CHECK(krb5_storage_to_data(sp, &data), 0); 1153 krb5_storage_free(sp); 1154 sp = NULL; 1155 1156 HMAC_CTX_init(&c); 1157 HMAC_Init_ex(&c, ntlmv2, 16, EVP_md5(), NULL); 1158 HMAC_Update(&c, serverchallange, 8); 1159 HMAC_Update(&c, data.data, data.length); 1160 HMAC_Final(&c, ntlmv2answer, &hmaclen); 1161 HMAC_CTX_cleanup(&c); 1162 1163 sp = krb5_storage_emem(); 1164 if (sp == NULL) { 1165 krb5_data_free(&data); 1166 return ENOMEM; 1167 } 1168 1169 CHECK(krb5_storage_write(sp, ntlmv2answer, 16), 16); 1170 CHECK(krb5_storage_write(sp, data.data, data.length), data.length); 1171 krb5_data_free(&data); 1172 1173 CHECK(krb5_storage_to_data(sp, &data), 0); 1174 krb5_storage_free(sp); 1175 sp = NULL; 1176 1177 answer->data = data.data; 1178 answer->length = data.length; 1179 1180 return 0; 1181 out: 1182 if (sp) 1183 krb5_storage_free(sp); 1184 return ret; 1185 } 1186 1187 static const int authtimediff = 3600 * 2; /* 2 hours */ 1188 1189 /** 1190 * Verify NTLMv2 response. 1191 * 1192 * @param key the ntlm key 1193 * @param len length of key 1194 * @param username name of the user, as sent in the message, assumed to be in UTF8. 1195 * @param target the name of the target, assumed to be in UTF8. 1196 * @param now the time now (0 if the library should pick it up itself) 1197 * @param serverchallange challange as sent by the server in the type2 message. 1198 * @param answer ntlm response answer, should be freed with heim_ntlm_free_buf(). 1199 * @param infotarget infotarget as sent by the server in the type2 message. 1200 * @param ntlmv2 calculated session key 1201 * 1202 * @return In case of success 0 is return, an errors, a errno in what 1203 * went wrong. 1204 * 1205 * @ingroup ntlm_core 1206 */ 1207 1208 int 1209 heim_ntlm_verify_ntlm2(const void *key, size_t len, 1210 const char *username, 1211 const char *target, 1212 time_t now, 1213 const unsigned char serverchallange[8], 1214 const struct ntlm_buf *answer, 1215 struct ntlm_buf *infotarget, 1216 unsigned char ntlmv2[16]) 1217 { 1218 krb5_error_code ret; 1219 unsigned int hmaclen; 1220 unsigned char clientanswer[16]; 1221 unsigned char clientnonce[8]; 1222 unsigned char serveranswer[16]; 1223 krb5_storage *sp; 1224 HMAC_CTX c; 1225 uint64_t t; 1226 time_t authtime; 1227 uint32_t temp; 1228 1229 infotarget->length = 0; 1230 infotarget->data = NULL; 1231 1232 if (answer->length < 16) 1233 return EINVAL; 1234 1235 if (now == 0) 1236 now = time(NULL); 1237 1238 /* calculate ntlmv2 key */ 1239 1240 heim_ntlm_ntlmv2_key(key, len, username, target, ntlmv2); 1241 1242 /* calculate and build ntlmv2 answer */ 1243 1244 sp = krb5_storage_from_readonly_mem(answer->data, answer->length); 1245 if (sp == NULL) 1246 return ENOMEM; 1247 krb5_storage_set_flags(sp, KRB5_STORAGE_BYTEORDER_LE); 1248 1249 CHECK(krb5_storage_read(sp, clientanswer, 16), 16); 1250 1251 CHECK(krb5_ret_uint32(sp, &temp), 0); 1252 CHECK(temp, 0x00000101); 1253 CHECK(krb5_ret_uint32(sp, &temp), 0); 1254 CHECK(temp, 0); 1255 /* timestamp le 64 bit ts */ 1256 CHECK(krb5_ret_uint32(sp, &temp), 0); 1257 t = temp; 1258 CHECK(krb5_ret_uint32(sp, &temp), 0); 1259 t |= ((uint64_t)temp)<< 32; 1260 1261 authtime = nt2unixtime(t); 1262 1263 if (abs((int)(authtime - now)) > authtimediff) { 1264 ret = EINVAL; 1265 goto out; 1266 } 1267 1268 /* client challange */ 1269 CHECK(krb5_storage_read(sp, clientnonce, 8), 8); 1270 1271 CHECK(krb5_ret_uint32(sp, &temp), 0); /* unknown */ 1272 1273 /* should really unparse the infotarget, but lets pick up everything */ 1274 infotarget->length = answer->length - krb5_storage_seek(sp, 0, SEEK_CUR); 1275 infotarget->data = malloc(infotarget->length); 1276 if (infotarget->data == NULL) { 1277 ret = ENOMEM; 1278 goto out; 1279 } 1280 CHECK(krb5_storage_read(sp, infotarget->data, infotarget->length), 1281 infotarget->length); 1282 /* XXX remove the unknown ?? */ 1283 krb5_storage_free(sp); 1284 sp = NULL; 1285 1286 HMAC_CTX_init(&c); 1287 HMAC_Init_ex(&c, ntlmv2, 16, EVP_md5(), NULL); 1288 HMAC_Update(&c, serverchallange, 8); 1289 HMAC_Update(&c, ((unsigned char *)answer->data) + 16, answer->length - 16); 1290 HMAC_Final(&c, serveranswer, &hmaclen); 1291 HMAC_CTX_cleanup(&c); 1292 1293 if (memcmp(serveranswer, clientanswer, 16) != 0) { 1294 heim_ntlm_free_buf(infotarget); 1295 return EINVAL; 1296 } 1297 1298 return 0; 1299 out: 1300 heim_ntlm_free_buf(infotarget); 1301 if (sp) 1302 krb5_storage_free(sp); 1303 return ret; 1304 } 1305 1306 1307 /* 1308 * Calculate the NTLM2 Session Response 1309 * 1310 * @param clnt_nonce client nonce 1311 * @param svr_chal server challage 1312 * @param ntlm2_hash ntlm hash 1313 * @param lm The LM response, should be freed with heim_ntlm_free_buf(). 1314 * @param ntlm The NTLM response, should be freed with heim_ntlm_free_buf(). 1315 * 1316 * @return In case of success 0 is return, an errors, a errno in what 1317 * went wrong. 1318 * 1319 * @ingroup ntlm_core 1320 */ 1321 1322 int 1323 heim_ntlm_calculate_ntlm2_sess(const unsigned char clnt_nonce[8], 1324 const unsigned char svr_chal[8], 1325 const unsigned char ntlm_hash[16], 1326 struct ntlm_buf *lm, 1327 struct ntlm_buf *ntlm) 1328 { 1329 unsigned char ntlm2_sess_hash[MD5_DIGEST_LENGTH]; 1330 unsigned char res[21], *resp; 1331 MD5_CTX md5; 1332 1333 lm->data = malloc(24); 1334 if (lm->data == NULL) 1335 return ENOMEM; 1336 lm->length = 24; 1337 1338 ntlm->data = malloc(24); 1339 if (ntlm->data == NULL) { 1340 free(lm->data); 1341 lm->data = NULL; 1342 return ENOMEM; 1343 } 1344 ntlm->length = 24; 1345 1346 /* first setup the lm resp */ 1347 memset(lm->data, 0, 24); 1348 memcpy(lm->data, clnt_nonce, 8); 1349 1350 MD5_Init(&md5); 1351 MD5_Update(&md5, svr_chal, 8); /* session nonce part 1 */ 1352 MD5_Update(&md5, clnt_nonce, 8); /* session nonce part 2 */ 1353 MD5_Final(ntlm2_sess_hash, &md5); /* will only use first 8 bytes */ 1354 1355 memset(res, 0, sizeof(res)); 1356 memcpy(res, ntlm_hash, 16); 1357 1358 resp = ntlm->data; 1359 splitandenc(&res[0], ntlm2_sess_hash, resp + 0); 1360 splitandenc(&res[7], ntlm2_sess_hash, resp + 8); 1361 splitandenc(&res[14], ntlm2_sess_hash, resp + 16); 1362 1363 return 0; 1364 } 1365