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