root/source4/heimdal/lib/ntlm/ntlm.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. heim_ntlm_free_buf
  2. ascii2ucs2le
  3. ret_sec_buffer
  4. store_sec_buffer
  5. len_string
  6. ret_string
  7. put_string
  8. ret_buf
  9. put_buf
  10. heim_ntlm_free_targetinfo
  11. encode_ti_blob
  12. heim_ntlm_encode_targetinfo
  13. heim_ntlm_decode_targetinfo
  14. heim_ntlm_free_type1
  15. heim_ntlm_decode_type1
  16. heim_ntlm_encode_type1
  17. heim_ntlm_free_type2
  18. heim_ntlm_decode_type2
  19. heim_ntlm_encode_type2
  20. heim_ntlm_free_type3
  21. heim_ntlm_decode_type3
  22. heim_ntlm_encode_type3
  23. splitandenc
  24. heim_ntlm_nt_key
  25. heim_ntlm_calculate_ntlm1
  26. heim_ntlm_build_ntlm1_master
  27. heim_ntlm_ntlmv2_key
  28. unix2nttime
  29. nt2unixtime
  30. heim_ntlm_calculate_ntlm2
  31. heim_ntlm_verify_ntlm2
  32. heim_ntlm_calculate_ntlm2_sess

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

/* [<][>][^][v][top][bottom][index][help] */