2 * Copyright (c) 2006 - 2008 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
6 * Portions Copyright (c) 2010 Apple Inc. All rights reserved.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
19 * 3. Neither the name of the Institute nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
23 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
49 #include <parse_units.h>
53 #define HC_DEPRECATED_CRYPTO
55 #include "krb5-types.h"
56 #include "crypto-headers.h"
60 /*! \mainpage Heimdal NTLM library
62 * \section intro Introduction
64 * Heimdal libheimntlm library is a implementation of the NTLM
65 * protocol, both version 1 and 2. The GSS-API mech that uses this
66 * library adds support for transport encryption and integrity
69 * NTLM is a protocol for mutual authentication, its still used in
70 * many protocol where Kerberos is not support, one example is
71 * EAP/X802.1x mechanism LEAP from Microsoft and Cisco.
73 * This is a support library for the core protocol, its used in
74 * Heimdal to implement and GSS-API mechanism. There is also support
75 * in the KDC to do remote digest authenticiation, this to allow
76 * services to authenticate users w/o direct access to the users ntlm
77 * hashes (same as Kerberos arcfour enctype keys).
79 * More information about the NTLM protocol can found here
80 * http://davenport.sourceforge.net/ntlm.html .
82 * The Heimdal projects web page: http://www.h5l.org/
84 * @section ntlm_example NTLM Example
86 * Example to to use @ref test_ntlm.c .
88 * @example test_ntlm.c
90 * Example how to use the NTLM primitives.
94 /** @defgroup ntlm_core Heimdal NTLM library
96 * The NTLM core functions implement the string2key generation
97 * function, message encode and decode function, and the hash function
107 static const unsigned char ntlmsigature
[8] = "NTLMSSP\x00";
109 time_t heim_ntlm_time_skew
= 300;
115 #define CHECK(f, e) \
118 if (ret != (ssize_t)(e)) { \
119 ret = HNTLM_ERR_DECODE; \
122 } while(/*CONSTCOND*/0)
124 #define CHECK_SIZE(f, e) \
127 if (sret != (ssize_t)(e)) { \
128 ret = HNTLM_ERR_DECODE; \
131 } while(/*CONSTCOND*/0)
133 #define CHECK_OFFSET(f, e) \
137 ret = HNTLM_ERR_DECODE; \
140 } while(/*CONSTCOND*/0)
143 static struct units ntlm_flag_units
[] = {
144 #define ntlm_flag(x) { #x, NTLM_##x }
146 ntlm_flag(NEG_KEYEX
),
151 ntlm_flag(NEG_VERSION
),
153 ntlm_flag(NEG_TARGET_INFO
),
154 ntlm_flag(NON_NT_SESSION_KEY
),
156 ntlm_flag(NEG_IDENTIFY
),
157 ntlm_flag(NEG_NTLM2
),
158 ntlm_flag(TARGET_SHARE
),
159 ntlm_flag(TARGET_SERVER
),
160 ntlm_flag(TARGET_DOMAIN
),
161 ntlm_flag(NEG_ALWAYS_SIGN
),
163 ntlm_flag(OEM_SUPPLIED_WORKSTATION
),
164 ntlm_flag(OEM_SUPPLIED_DOMAIN
),
165 ntlm_flag(NEG_ANONYMOUS
),
166 ntlm_flag(NEG_NT_ONLY
),
169 ntlm_flag(NEG_LM_KEY
),
170 ntlm_flag(NEG_DATAGRAM
),
174 ntlm_flag(NEG_TARGET
),
176 ntlm_flag(NEG_UNICODE
),
182 heim_ntlm_unparse_flags(uint32_t flags
, char *s
, size_t len
)
184 return unparse_flags(flags
, ntlm_flag_units
, s
, len
);
189 * heim_ntlm_free_buf frees the ntlm buffer
191 * @param p buffer to be freed
197 heim_ntlm_free_buf(struct ntlm_buf
*p
)
207 ascii2ucs2le(const char *string
, int up
, struct ntlm_buf
*buf
)
214 ret
= wind_utf8ucs2_length(string
, &len
);
217 if (len
> UINT_MAX
/ sizeof(data
[0]))
220 data
= malloc(len
* sizeof(data
[0]));
224 ret
= wind_utf8ucs2(string
, data
, &len
);
237 /* uppercase string, only handle ascii right now */
239 for (n
= 0; n
< len
; n
++) {
241 data
[n
] = toupper((int)data
[n
]);
245 buf
->length
= len
* 2;
246 p
= buf
->data
= malloc(buf
->length
);
247 if (buf
->data
== NULL
&& len
!= 0) {
249 heim_ntlm_free_buf(buf
);
253 for (n
= 0; n
< len
; n
++) {
254 p
[(n
* 2) + 0] = (data
[n
] ) & 0xff;
255 p
[(n
* 2) + 1] = (data
[n
] >> 8) & 0xff;
257 memset(data
, 0, sizeof(data
[0]) * len
);
267 #define SIZE_SEC_BUFFER (2+2+4)
268 #define SIZE_OS_VERSION (8)
274 static krb5_error_code
275 ret_sec_buffer(krb5_storage
*sp
, struct sec_buffer
*buf
)
278 CHECK(krb5_ret_uint16(sp
, &buf
->length
), 0);
279 CHECK(krb5_ret_uint16(sp
, &buf
->allocated
), 0);
280 CHECK(krb5_ret_uint32(sp
, &buf
->offset
), 0);
285 static krb5_error_code
286 store_sec_buffer(krb5_storage
*sp
, const struct sec_buffer
*buf
)
289 CHECK(krb5_store_uint16(sp
, buf
->length
), 0);
290 CHECK(krb5_store_uint16(sp
, buf
->allocated
), 0);
291 CHECK(krb5_store_uint32(sp
, buf
->offset
), 0);
297 * Strings are either OEM or UNICODE. The later is encoded as ucs2 on
298 * wire, but using utf8 in memory.
302 len_string(int ucs2
, const char *s
)
308 ret
= wind_utf8ucs2_length(s
, &len
);
311 return strlen(s
) * 5 * 2;
321 static krb5_error_code
322 ret_string(krb5_storage
*sp
, int ucs2
, size_t len
, char **s
)
325 uint16_t *data
= NULL
;
327 *s
= malloc(len
+ 1);
330 CHECK_SIZE(krb5_storage_read(sp
, *s
, len
), len
);
335 unsigned int flags
= WIND_RW_LE
;
336 size_t utf16len
= len
/ 2;
339 data
= malloc(utf16len
* sizeof(data
[0]));
346 ret
= wind_ucs2read(*s
, len
, &flags
, data
, &utf16len
);
352 CHECK(wind_ucs2utf8_length(data
, utf16len
, &utf8len
), 0);
356 *s
= malloc(utf8len
);
362 CHECK(wind_ucs2utf8(data
, utf16len
, *s
, &utf8len
), 0);
374 static krb5_error_code
375 ret_sec_string(krb5_storage
*sp
, int ucs2
, struct sec_buffer
*desc
, char **s
)
377 krb5_error_code ret
= 0;
378 CHECK_OFFSET(krb5_storage_seek(sp
, desc
->offset
, SEEK_SET
), desc
->offset
);
379 CHECK(ret_string(sp
, ucs2
, desc
->length
, s
), 0);
384 static krb5_error_code
385 put_string(krb5_storage
*sp
, int ucs2
, const char *s
)
391 ret
= ascii2ucs2le(s
, 0, &buf
);
395 buf
.data
= rk_UNCONST(s
);
396 buf
.length
= strlen(s
);
399 CHECK_SIZE(krb5_storage_write(sp
, buf
.data
, buf
.length
), buf
.length
);
401 heim_ntlm_free_buf(&buf
);
411 static krb5_error_code
412 ret_buf(krb5_storage
*sp
, struct sec_buffer
*desc
, struct ntlm_buf
*buf
)
416 buf
->data
= malloc(desc
->length
);
417 buf
->length
= desc
->length
;
418 CHECK_OFFSET(krb5_storage_seek(sp
, desc
->offset
, SEEK_SET
), desc
->offset
);
419 CHECK_SIZE(krb5_storage_read(sp
, buf
->data
, buf
->length
), buf
->length
);
425 static krb5_error_code
426 put_buf(krb5_storage
*sp
, const struct ntlm_buf
*buf
)
429 CHECK_SIZE(krb5_storage_write(sp
, buf
->data
, buf
->length
), buf
->length
);
436 * Frees the ntlm_targetinfo message
438 * @param ti targetinfo to be freed
444 heim_ntlm_free_targetinfo(struct ntlm_targetinfo
*ti
)
446 free(ti
->servername
);
447 free(ti
->domainname
);
448 free(ti
->dnsdomainname
);
449 free(ti
->dnsservername
);
450 free(ti
->dnstreename
);
451 free(ti
->targetname
);
452 heim_ntlm_free_buf(&ti
->channel_bindings
);
453 memset(ti
, 0, sizeof(*ti
));
457 encode_ti_string(krb5_storage
*out
, uint16_t type
, int ucs2
, char *s
)
460 CHECK(krb5_store_uint16(out
, type
), 0);
461 CHECK(krb5_store_uint16(out
, len_string(ucs2
, s
)), 0);
462 CHECK(put_string(out
, ucs2
, s
), 0);
468 * Encodes a ntlm_targetinfo message.
470 * @param ti the ntlm_targetinfo message to encode.
471 * @param ucs2 ignored
472 * @param data is the return buffer with the encoded message, should be
473 * freed with heim_ntlm_free_buf().
475 * @return In case of success 0 is return, an errors, a errno in what
482 heim_ntlm_encode_targetinfo(const struct ntlm_targetinfo
*ti
,
484 struct ntlm_buf
*data
)
492 out
= krb5_storage_emem();
496 krb5_storage_set_byteorder(out
, KRB5_STORAGE_BYTEORDER_LE
);
499 CHECK(encode_ti_string(out
, 1, ucs2
, ti
->servername
), 0);
501 CHECK(encode_ti_string(out
, 2, ucs2
, ti
->domainname
), 0);
502 if (ti
->dnsservername
)
503 CHECK(encode_ti_string(out
, 3, ucs2
, ti
->dnsservername
), 0);
504 if (ti
->dnsdomainname
)
505 CHECK(encode_ti_string(out
, 4, ucs2
, ti
->dnsdomainname
), 0);
507 CHECK(encode_ti_string(out
, 5, ucs2
, ti
->dnstreename
), 0);
509 CHECK(krb5_store_uint16(out
, 6), 0);
510 CHECK(krb5_store_uint16(out
, 4), 0);
511 CHECK(krb5_store_uint32(out
, ti
->avflags
), 0);
514 CHECK(krb5_store_uint16(out
, 7), 0);
515 CHECK(krb5_store_uint16(out
, 8), 0);
516 CHECK(krb5_store_uint32(out
, ti
->timestamp
& 0xffffffff), 0);
517 CHECK(krb5_store_uint32(out
, (ti
->timestamp
>> 32) & 0xffffffff), 0);
519 if (ti
->targetname
) {
520 CHECK(encode_ti_string(out
, 9, ucs2
, ti
->targetname
), 0);
522 if (ti
->channel_bindings
.length
) {
523 CHECK(krb5_store_uint16(out
, 10), 0);
524 CHECK(krb5_store_uint16(out
, ti
->channel_bindings
.length
), 0);
525 CHECK_SIZE(krb5_storage_write(out
, ti
->channel_bindings
.data
, ti
->channel_bindings
.length
), ti
->channel_bindings
.length
);
529 CHECK(krb5_store_int16(out
, 0), 0);
530 CHECK(krb5_store_int16(out
, 0), 0);
534 ret
= krb5_storage_to_data(out
, &d
);
536 data
->length
= d
.length
;
539 krb5_storage_free(out
);
544 * Decodes an NTLM targetinfo message
546 * @param data input data buffer with the encode NTLM targetinfo message
547 * @param ucs2 if the strings should be encoded with ucs2 (selected by flag in message).
548 * @param ti the decoded target info, should be freed with heim_ntlm_free_targetinfo().
550 * @return In case of success 0 is return, an errors, a errno in what
557 heim_ntlm_decode_targetinfo(const struct ntlm_buf
*data
,
559 struct ntlm_targetinfo
*ti
)
563 int ret
= 0, done
= 0;
565 memset(ti
, 0, sizeof(*ti
));
567 if (data
->length
== 0)
570 in
= krb5_storage_from_readonly_mem(data
->data
, data
->length
);
573 krb5_storage_set_byteorder(in
, KRB5_STORAGE_BYTEORDER_LE
);
576 CHECK(krb5_ret_uint16(in
, &type
), 0);
577 CHECK(krb5_ret_uint16(in
, &len
), 0);
584 CHECK(ret_string(in
, ucs2
, len
, &ti
->servername
), 0);
587 CHECK(ret_string(in
, ucs2
, len
, &ti
->domainname
), 0);
590 CHECK(ret_string(in
, ucs2
, len
, &ti
->dnsservername
), 0);
593 CHECK(ret_string(in
, ucs2
, len
, &ti
->dnsdomainname
), 0);
596 CHECK(ret_string(in
, ucs2
, len
, &ti
->dnstreename
), 0);
599 CHECK(krb5_ret_uint32(in
, &ti
->avflags
), 0);
603 CHECK(krb5_ret_uint32(in
, &tmp
), 0);
605 CHECK(krb5_ret_uint32(in
, &tmp
), 0);
606 ti
->timestamp
|= ((uint64_t)tmp
) << 32;
610 CHECK(ret_string(in
, 1, len
, &ti
->targetname
), 0);
613 ti
->channel_bindings
.data
= malloc(len
);
614 if (ti
->channel_bindings
.data
== NULL
) {
618 ti
->channel_bindings
.length
= len
;
619 CHECK_SIZE(krb5_storage_read(in
, ti
->channel_bindings
.data
, len
), len
);
622 krb5_storage_seek(in
, len
, SEEK_CUR
);
628 krb5_storage_free(in
);
632 static krb5_error_code
633 encode_os_version(krb5_storage
*out
)
636 CHECK(krb5_store_uint8(out
, 0x06), 0);
637 CHECK(krb5_store_uint8(out
, 0x01), 0);
638 CHECK(krb5_store_uint16(out
, 0x1db0), 0);
639 CHECK(krb5_store_uint8(out
, 0x00), 0);
640 CHECK(krb5_store_uint8(out
, 0x00), 0);
641 CHECK(krb5_store_uint8(out
, 0x00), 0);
642 CHECK(krb5_store_uint8(out
, 0x0f), 0); /* ntlm version 15 */
648 * Frees the ntlm_type1 message
650 * @param data message to be freed
656 heim_ntlm_free_type1(struct ntlm_type1
*data
)
661 free(data
->hostname
);
662 memset(data
, 0, sizeof(*data
));
666 heim_ntlm_decode_type1(const struct ntlm_buf
*buf
, struct ntlm_type1
*data
)
669 unsigned char sig
[8];
671 struct sec_buffer domain
, hostname
;
675 memset(data
, 0, sizeof(*data
));
677 in
= krb5_storage_from_readonly_mem(buf
->data
, buf
->length
);
682 krb5_storage_set_byteorder(in
, KRB5_STORAGE_BYTEORDER_LE
);
684 CHECK_SIZE(krb5_storage_read(in
, sig
, sizeof(sig
)), sizeof(sig
));
685 CHECK(ct_memcmp(ntlmsigature
, sig
, sizeof(ntlmsigature
)), 0);
686 CHECK(krb5_ret_uint32(in
, &type
), 0);
688 CHECK(krb5_ret_uint32(in
, &data
->flags
), 0);
690 ucs2
= !!(data
->flags
& NTLM_NEG_UNICODE
);
693 * domain and hostname are unconditionally encoded regardless of
694 * NTLMSSP_NEGOTIATE_OEM_{HOSTNAME,WORKSTATION}_SUPPLIED flag
696 CHECK(ret_sec_buffer(in
, &domain
), 0);
697 CHECK(ret_sec_buffer(in
, &hostname
), 0);
699 if (data
->flags
& NTLM_NEG_VERSION
) {
700 CHECK(krb5_ret_uint32(in
, &data
->os
[0]), 0);
701 CHECK(krb5_ret_uint32(in
, &data
->os
[1]), 0);
704 if (data
->flags
& NTLM_OEM_SUPPLIED_DOMAIN
)
705 CHECK(ret_sec_string(in
, ucs2
, &domain
, &data
->domain
), 0);
706 if (data
->flags
& NTLM_OEM_SUPPLIED_WORKSTATION
)
707 CHECK(ret_sec_string(in
, ucs2
, &hostname
, &data
->hostname
), 0);
711 krb5_storage_free(in
);
713 heim_ntlm_free_type1(data
);
719 * Encodes an ntlm_type1 message.
721 * @param type1 the ntlm_type1 message to encode.
722 * @param data is the return buffer with the encoded message, should be
723 * freed with heim_ntlm_free_buf().
725 * @return In case of success 0 is return, an errors, a errno in what
732 heim_ntlm_encode_type1(const struct ntlm_type1
*type1
, struct ntlm_buf
*data
)
735 struct sec_buffer domain
, hostname
;
737 uint32_t base
, flags
;
740 flags
= type1
->flags
;
743 if (flags
& NTLM_NEG_UNICODE
)
747 base
+= SIZE_SEC_BUFFER
;
748 flags
|= NTLM_OEM_SUPPLIED_DOMAIN
;
750 if (type1
->hostname
) {
751 base
+= SIZE_SEC_BUFFER
;
752 flags
|= NTLM_OEM_SUPPLIED_WORKSTATION
;
754 if (flags
& NTLM_NEG_VERSION
)
755 base
+= SIZE_OS_VERSION
; /* os */
758 domain
.offset
= base
;
759 domain
.length
= len_string(ucs2
, type1
->domain
);
760 domain
.allocated
= domain
.length
;
764 domain
.allocated
= 0;
767 if (type1
->hostname
) {
768 hostname
.offset
= domain
.allocated
+ domain
.offset
;
769 hostname
.length
= len_string(ucs2
, type1
->hostname
);
770 hostname
.allocated
= hostname
.length
;
774 hostname
.allocated
= 0;
777 out
= krb5_storage_emem();
781 krb5_storage_set_byteorder(out
, KRB5_STORAGE_BYTEORDER_LE
);
782 CHECK_SIZE(krb5_storage_write(out
, ntlmsigature
, sizeof(ntlmsigature
)),
783 sizeof(ntlmsigature
));
784 CHECK(krb5_store_uint32(out
, 1), 0);
785 CHECK(krb5_store_uint32(out
, flags
), 0);
787 CHECK(store_sec_buffer(out
, &domain
), 0);
788 CHECK(store_sec_buffer(out
, &hostname
), 0);
790 if (flags
& NTLM_NEG_VERSION
) {
791 CHECK(encode_os_version(out
), 0);
794 CHECK(put_string(out
, ucs2
, type1
->domain
), 0);
796 CHECK(put_string(out
, ucs2
, type1
->hostname
), 0);
800 ret
= krb5_storage_to_data(out
, &d
);
802 data
->length
= d
.length
;
805 krb5_storage_free(out
);
811 * Frees the ntlm_type2 message
813 * @param data message to be freed
819 heim_ntlm_free_type2(struct ntlm_type2
*data
)
821 if (data
->targetname
)
822 free(data
->targetname
);
823 heim_ntlm_free_buf(&data
->targetinfo
);
824 memset(data
, 0, sizeof(*data
));
828 heim_ntlm_decode_type2(const struct ntlm_buf
*buf
, struct ntlm_type2
*type2
)
831 unsigned char sig
[8];
832 uint32_t type
, ctx
[2];
833 struct sec_buffer targetname
, targetinfo
;
837 memset(type2
, 0, sizeof(*type2
));
839 in
= krb5_storage_from_readonly_mem(buf
->data
, buf
->length
);
844 krb5_storage_set_byteorder(in
, KRB5_STORAGE_BYTEORDER_LE
);
846 CHECK_SIZE(krb5_storage_read(in
, sig
, sizeof(sig
)), sizeof(sig
));
847 CHECK(ct_memcmp(ntlmsigature
, sig
, sizeof(ntlmsigature
)), 0);
848 CHECK(krb5_ret_uint32(in
, &type
), 0);
851 CHECK(ret_sec_buffer(in
, &targetname
), 0);
852 CHECK(krb5_ret_uint32(in
, &type2
->flags
), 0);
853 if (type2
->flags
& NTLM_NEG_UNICODE
)
855 CHECK_SIZE(krb5_storage_read(in
, type2
->challenge
, sizeof(type2
->challenge
)),
856 sizeof(type2
->challenge
));
857 CHECK(krb5_ret_uint32(in
, &ctx
[0]), 0); /* context */
858 CHECK(krb5_ret_uint32(in
, &ctx
[1]), 0);
859 CHECK(ret_sec_buffer(in
, &targetinfo
), 0);
861 if (type2
->flags
& NTLM_NEG_VERSION
) {
862 CHECK(krb5_ret_uint32(in
, &type2
->os
[0]), 0);
863 CHECK(krb5_ret_uint32(in
, &type2
->os
[1]), 0);
866 CHECK(ret_sec_string(in
, ucs2
, &targetname
, &type2
->targetname
), 0);
867 CHECK(ret_buf(in
, &targetinfo
, &type2
->targetinfo
), 0);
872 krb5_storage_free(in
);
874 heim_ntlm_free_type2(type2
);
880 * Encodes an ntlm_type2 message.
882 * @param type2 the ntlm_type2 message to encode.
883 * @param data is the return buffer with the encoded message, should be
884 * freed with heim_ntlm_free_buf().
886 * @return In case of success 0 is return, an errors, a errno in what
893 heim_ntlm_encode_type2(const struct ntlm_type2
*type2
, struct ntlm_buf
*data
)
895 struct sec_buffer targetname
, targetinfo
;
897 krb5_storage
*out
= NULL
;
903 if (type2
->flags
& NTLM_NEG_VERSION
)
904 base
+= SIZE_OS_VERSION
;
906 if (type2
->flags
& NTLM_NEG_UNICODE
)
909 targetname
.offset
= base
;
910 targetname
.length
= len_string(ucs2
, type2
->targetname
);
911 targetname
.allocated
= targetname
.length
;
913 targetinfo
.offset
= targetname
.allocated
+ targetname
.offset
;
914 targetinfo
.length
= type2
->targetinfo
.length
;
915 targetinfo
.allocated
= type2
->targetinfo
.length
;
917 out
= krb5_storage_emem();
921 krb5_storage_set_byteorder(out
, KRB5_STORAGE_BYTEORDER_LE
);
922 CHECK_SIZE(krb5_storage_write(out
, ntlmsigature
, sizeof(ntlmsigature
)),
923 sizeof(ntlmsigature
));
924 CHECK(krb5_store_uint32(out
, 2), 0);
925 CHECK(store_sec_buffer(out
, &targetname
), 0);
926 CHECK(krb5_store_uint32(out
, type2
->flags
), 0);
927 CHECK_SIZE(krb5_storage_write(out
, type2
->challenge
, sizeof(type2
->challenge
)),
928 sizeof(type2
->challenge
));
929 CHECK(krb5_store_uint32(out
, 0), 0); /* context */
930 CHECK(krb5_store_uint32(out
, 0), 0);
931 CHECK(store_sec_buffer(out
, &targetinfo
), 0);
933 if (type2
->flags
& NTLM_NEG_VERSION
) {
934 CHECK(encode_os_version(out
), 0);
936 CHECK(put_string(out
, ucs2
, type2
->targetname
), 0);
937 CHECK_SIZE(krb5_storage_write(out
, type2
->targetinfo
.data
,
938 type2
->targetinfo
.length
),
939 type2
->targetinfo
.length
);
943 ret
= krb5_storage_to_data(out
, &d
);
945 data
->length
= d
.length
;
949 krb5_storage_free(out
);
955 * Frees the ntlm_type3 message
957 * @param data message to be freed
963 heim_ntlm_free_type3(struct ntlm_type3
*data
)
965 heim_ntlm_free_buf(&data
->lm
);
966 heim_ntlm_free_buf(&data
->ntlm
);
967 if (data
->targetname
)
968 free(data
->targetname
);
970 free(data
->username
);
973 heim_ntlm_free_buf(&data
->sessionkey
);
974 memset(data
, 0, sizeof(*data
));
982 heim_ntlm_decode_type3(const struct ntlm_buf
*buf
,
984 struct ntlm_type3
*type3
)
987 unsigned char sig
[8];
990 struct sec_buffer lm
, ntlm
, target
, username
, sessionkey
, ws
;
991 uint32_t min_offset
= 0xffffffff;
993 memset(type3
, 0, sizeof(*type3
));
994 memset(&sessionkey
, 0, sizeof(sessionkey
));
996 in
= krb5_storage_from_readonly_mem(buf
->data
, buf
->length
);
1001 krb5_storage_set_byteorder(in
, KRB5_STORAGE_BYTEORDER_LE
);
1003 CHECK_SIZE(krb5_storage_read(in
, sig
, sizeof(sig
)), sizeof(sig
));
1004 CHECK(ct_memcmp(ntlmsigature
, sig
, sizeof(ntlmsigature
)), 0);
1005 CHECK(krb5_ret_uint32(in
, &type
), 0);
1007 CHECK(ret_sec_buffer(in
, &lm
), 0);
1009 min_offset
= min(min_offset
, lm
.offset
);
1010 CHECK(ret_sec_buffer(in
, &ntlm
), 0);
1012 min_offset
= min(min_offset
, ntlm
.offset
);
1013 CHECK(ret_sec_buffer(in
, &target
), 0);
1014 min_offset
= min(min_offset
, target
.offset
);
1015 CHECK(ret_sec_buffer(in
, &username
), 0);
1016 min_offset
= min(min_offset
, username
.offset
);
1017 CHECK(ret_sec_buffer(in
, &ws
), 0);
1019 min_offset
= min(min_offset
, ws
.offset
);
1021 if (min_offset
>= 52) {
1022 CHECK(ret_sec_buffer(in
, &sessionkey
), 0);
1023 min_offset
= min(min_offset
, sessionkey
.offset
);
1024 CHECK(krb5_ret_uint32(in
, &type3
->flags
), 0);
1026 if (min_offset
>= 52 + SIZE_SEC_BUFFER
+ 4 + SIZE_OS_VERSION
) {
1027 CHECK(krb5_ret_uint32(in
, &type3
->os
[0]), 0);
1028 CHECK(krb5_ret_uint32(in
, &type3
->os
[1]), 0);
1030 if (min_offset
>= 52 + SIZE_SEC_BUFFER
+ 4 + SIZE_OS_VERSION
+ 16) {
1031 type3
->mic_offset
= 52 + SIZE_SEC_BUFFER
+ 4 + SIZE_OS_VERSION
;
1032 CHECK_SIZE(krb5_storage_read(in
, type3
->mic
, sizeof(type3
->mic
)), sizeof(type3
->mic
));
1034 type3
->mic_offset
= 0;
1035 CHECK(ret_buf(in
, &lm
, &type3
->lm
), 0);
1036 CHECK(ret_buf(in
, &ntlm
, &type3
->ntlm
), 0);
1037 CHECK(ret_sec_string(in
, ucs2
, &target
, &type3
->targetname
), 0);
1038 CHECK(ret_sec_string(in
, ucs2
, &username
, &type3
->username
), 0);
1039 CHECK(ret_sec_string(in
, ucs2
, &ws
, &type3
->ws
), 0);
1040 if (sessionkey
.offset
)
1041 CHECK(ret_buf(in
, &sessionkey
, &type3
->sessionkey
), 0);
1045 krb5_storage_free(in
);
1047 heim_ntlm_free_type3(type3
);
1053 * Encodes an ntlm_type3 message.
1055 * @param type3 the ntlm_type3 message to encode.
1056 * @param data is the return buffer with the encoded message, should be
1057 * @param[out] mic_offset offset of message integrity code
1058 * freed with heim_ntlm_free_buf().
1060 * @return In case of success 0 is return, an errors, a errno in what
1063 * @ingroup ntlm_core
1067 heim_ntlm_encode_type3(const struct ntlm_type3
*type3
, struct ntlm_buf
*data
, size_t *mic_offset
)
1069 struct sec_buffer lm
, ntlm
, target
, username
, sessionkey
, ws
;
1070 krb5_error_code ret
;
1071 krb5_storage
*out
= NULL
;
1075 memset(&lm
, 0, sizeof(lm
));
1076 memset(&ntlm
, 0, sizeof(ntlm
));
1077 memset(&target
, 0, sizeof(target
));
1078 memset(&username
, 0, sizeof(username
));
1079 memset(&ws
, 0, sizeof(ws
));
1080 memset(&sessionkey
, 0, sizeof(sessionkey
));
1084 base
+= 8; /* sessionkey sec buf */
1085 base
+= 4; /* flags */
1086 if (type3
->flags
& NTLM_NEG_VERSION
)
1087 base
+= SIZE_OS_VERSION
; /* os flags */
1094 if (type3
->flags
& NTLM_NEG_UNICODE
)
1097 target
.offset
= base
;
1098 target
.length
= len_string(ucs2
, type3
->targetname
);
1099 target
.allocated
= target
.length
;
1101 username
.offset
= target
.offset
+ target
.allocated
;
1102 username
.length
= len_string(ucs2
, type3
->username
);
1103 username
.allocated
= username
.length
;
1105 ws
.offset
= username
.offset
+ username
.allocated
;
1106 ws
.length
= len_string(ucs2
, type3
->ws
);
1107 ws
.allocated
= ws
.length
;
1109 lm
.offset
= ws
.offset
+ ws
.allocated
;
1110 lm
.length
= type3
->lm
.length
;
1111 lm
.allocated
= type3
->lm
.length
;
1113 ntlm
.offset
= lm
.offset
+ lm
.allocated
;
1114 ntlm
.length
= type3
->ntlm
.length
;
1115 ntlm
.allocated
= ntlm
.length
;
1117 sessionkey
.offset
= ntlm
.offset
+ ntlm
.allocated
;
1118 sessionkey
.length
= type3
->sessionkey
.length
;
1119 sessionkey
.allocated
= type3
->sessionkey
.length
;
1121 out
= krb5_storage_emem();
1125 krb5_storage_set_byteorder(out
, KRB5_STORAGE_BYTEORDER_LE
);
1126 CHECK_SIZE(krb5_storage_write(out
, ntlmsigature
, sizeof(ntlmsigature
)),
1127 sizeof(ntlmsigature
));
1128 CHECK(krb5_store_uint32(out
, 3), 0);
1130 CHECK(store_sec_buffer(out
, &lm
), 0);
1131 CHECK(store_sec_buffer(out
, &ntlm
), 0);
1132 CHECK(store_sec_buffer(out
, &target
), 0);
1133 CHECK(store_sec_buffer(out
, &username
), 0);
1134 CHECK(store_sec_buffer(out
, &ws
), 0);
1135 CHECK(store_sec_buffer(out
, &sessionkey
), 0);
1136 CHECK(krb5_store_uint32(out
, type3
->flags
), 0);
1139 if (type3
->flags
& NTLM_NEG_VERSION
) {
1140 CHECK(encode_os_version(out
), 0);
1144 static const uint8_t buf
[16] = { 0 };
1145 CHECK_SIZE(krb5_storage_write(out
, buf
, sizeof(buf
)), sizeof(buf
));
1148 CHECK(put_string(out
, ucs2
, type3
->targetname
), 0);
1149 CHECK(put_string(out
, ucs2
, type3
->username
), 0);
1150 CHECK(put_string(out
, ucs2
, type3
->ws
), 0);
1151 CHECK(put_buf(out
, &type3
->lm
), 0);
1152 CHECK(put_buf(out
, &type3
->ntlm
), 0);
1153 CHECK(put_buf(out
, &type3
->sessionkey
), 0);
1157 ret
= krb5_storage_to_data(out
, &d
);
1158 data
->data
= d
.data
;
1159 data
->length
= d
.length
;
1163 krb5_storage_free(out
);
1174 splitandenc(unsigned char *hash
,
1175 unsigned char *challenge
,
1176 unsigned char *answer
)
1179 unsigned char key
[8];
1182 key
[1] = (hash
[0] << 7) | (hash
[1] >> 1);
1183 key
[2] = (hash
[1] << 6) | (hash
[2] >> 2);
1184 key
[3] = (hash
[2] << 5) | (hash
[3] >> 3);
1185 key
[4] = (hash
[3] << 4) | (hash
[4] >> 4);
1186 key
[5] = (hash
[4] << 3) | (hash
[5] >> 5);
1187 key
[6] = (hash
[5] << 2) | (hash
[6] >> 6);
1188 key
[7] = (hash
[6] << 1);
1190 EVP_CIPHER_CTX_init(&ctx
);
1192 EVP_CipherInit_ex(&ctx
, EVP_des_cbc(), NULL
, key
, NULL
, 1);
1193 EVP_Cipher(&ctx
, answer
, challenge
, 8);
1194 EVP_CIPHER_CTX_cleanup(&ctx
);
1195 memset_s(key
, sizeof(key
), 0, sizeof(key
));
1199 * Calculate the NTLM key, the password is assumed to be in UTF8.
1201 * @param password password to calcute the key for.
1202 * @param key calcuted key, should be freed with heim_ntlm_free_buf().
1204 * @return In case of success 0 is return, an errors, a errno in what
1207 * @ingroup ntlm_core
1211 heim_ntlm_nt_key(const char *password
, struct ntlm_buf
*key
)
1213 struct ntlm_buf buf
;
1217 key
->data
= malloc(MD4_DIGEST_LENGTH
);
1218 if (key
->data
== NULL
)
1220 key
->length
= MD4_DIGEST_LENGTH
;
1222 ret
= ascii2ucs2le(password
, 0, &buf
);
1224 heim_ntlm_free_buf(key
);
1228 m
= EVP_MD_CTX_create();
1230 heim_ntlm_free_buf(key
);
1231 heim_ntlm_free_buf(&buf
);
1235 EVP_DigestInit_ex(m
, EVP_md4(), NULL
);
1236 EVP_DigestUpdate(m
, buf
.data
, buf
.length
);
1237 EVP_DigestFinal_ex(m
, key
->data
, NULL
);
1238 EVP_MD_CTX_destroy(m
);
1240 heim_ntlm_free_buf(&buf
);
1245 * Calculate NTLMv1 response hash
1247 * @param key the ntlm v1 key
1248 * @param len length of key
1249 * @param challenge sent by the server
1250 * @param answer calculated answer, should be freed with heim_ntlm_free_buf().
1252 * @return In case of success 0 is return, an errors, a errno in what
1255 * @ingroup ntlm_core
1259 heim_ntlm_calculate_ntlm1(void *key
, size_t len
,
1260 unsigned char challenge
[8],
1261 struct ntlm_buf
*answer
)
1263 unsigned char res
[21];
1265 if (len
!= MD4_DIGEST_LENGTH
)
1266 return HNTLM_ERR_INVALID_LENGTH
;
1268 memcpy(res
, key
, len
);
1269 memset(&res
[MD4_DIGEST_LENGTH
], 0, sizeof(res
) - MD4_DIGEST_LENGTH
);
1271 answer
->data
= malloc(24);
1272 if (answer
->data
== NULL
)
1274 answer
->length
= 24;
1276 splitandenc(&res
[0], challenge
, ((unsigned char *)answer
->data
) + 0);
1277 splitandenc(&res
[7], challenge
, ((unsigned char *)answer
->data
) + 8);
1278 splitandenc(&res
[14], challenge
, ((unsigned char *)answer
->data
) + 16);
1284 heim_ntlm_v1_base_session(void *key
, size_t len
,
1285 struct ntlm_buf
*session
)
1289 session
->length
= MD4_DIGEST_LENGTH
;
1290 session
->data
= malloc(session
->length
);
1291 if (session
->data
== NULL
) {
1292 session
->length
= 0;
1296 m
= EVP_MD_CTX_create();
1298 heim_ntlm_free_buf(session
);
1301 EVP_DigestInit_ex(m
, EVP_md4(), NULL
);
1302 EVP_DigestUpdate(m
, key
, len
);
1303 EVP_DigestFinal_ex(m
, session
->data
, NULL
);
1304 EVP_MD_CTX_destroy(m
);
1310 heim_ntlm_v2_base_session(void *key
, size_t len
,
1311 struct ntlm_buf
*ntlmResponse
,
1312 struct ntlm_buf
*session
)
1314 unsigned int hmaclen
;
1317 if (ntlmResponse
->length
<= 16)
1318 return HNTLM_ERR_INVALID_LENGTH
;
1320 session
->data
= malloc(16);
1321 if (session
->data
== NULL
)
1323 session
->length
= 16;
1325 /* Note: key is the NTLMv2 key */
1327 if (HMAC_Init_ex(&c
, key
, len
, EVP_md5(), NULL
) == 0) {
1328 HMAC_CTX_cleanup(&c
);
1331 HMAC_Update(&c
, ntlmResponse
->data
, 16);
1332 HMAC_Final(&c
, session
->data
, &hmaclen
);
1333 HMAC_CTX_cleanup(&c
);
1340 heim_ntlm_keyex_wrap(struct ntlm_buf
*base_session
,
1341 struct ntlm_buf
*session
,
1342 struct ntlm_buf
*encryptedSession
)
1347 if (base_session
->length
!= MD4_DIGEST_LENGTH
)
1348 return HNTLM_ERR_INVALID_LENGTH
;
1350 session
->length
= MD4_DIGEST_LENGTH
;
1351 session
->data
= malloc(session
->length
);
1352 if (session
->data
== NULL
) {
1353 session
->length
= 0;
1356 encryptedSession
->length
= MD4_DIGEST_LENGTH
;
1357 encryptedSession
->data
= malloc(encryptedSession
->length
);
1358 if (encryptedSession
->data
== NULL
) {
1359 heim_ntlm_free_buf(session
);
1360 encryptedSession
->length
= 0;
1364 EVP_CIPHER_CTX_init(&c
);
1366 ret
= EVP_CipherInit_ex(&c
, EVP_rc4(), NULL
, base_session
->data
, NULL
, 1);
1368 EVP_CIPHER_CTX_cleanup(&c
);
1369 heim_ntlm_free_buf(encryptedSession
);
1370 heim_ntlm_free_buf(session
);
1371 return HNTLM_ERR_CRYPTO
;
1374 if (RAND_bytes(session
->data
, session
->length
) != 1) {
1375 EVP_CIPHER_CTX_cleanup(&c
);
1376 heim_ntlm_free_buf(encryptedSession
);
1377 heim_ntlm_free_buf(session
);
1378 return HNTLM_ERR_RAND
;
1381 EVP_Cipher(&c
, encryptedSession
->data
, session
->data
, encryptedSession
->length
);
1382 EVP_CIPHER_CTX_cleanup(&c
);
1391 * Generates an NTLMv1 session random with assosited session master key.
1393 * @param key the ntlm v1 key
1394 * @param len length of key
1395 * @param session generated session nonce, should be freed with heim_ntlm_free_buf().
1396 * @param master calculated session master key, should be freed with heim_ntlm_free_buf().
1398 * @return In case of success 0 is return, an errors, a errno in what
1401 * @ingroup ntlm_core
1405 heim_ntlm_build_ntlm1_master(void *key
, size_t len
,
1406 struct ntlm_buf
*session
,
1407 struct ntlm_buf
*master
)
1409 struct ntlm_buf sess
;
1412 ret
= heim_ntlm_v1_base_session(key
, len
, &sess
);
1416 ret
= heim_ntlm_keyex_wrap(&sess
, session
, master
);
1417 heim_ntlm_free_buf(&sess
);
1423 * Generates an NTLMv2 session random with associated session master key.
1425 * @param key the NTLMv2 key
1426 * @param len length of key
1427 * @param blob the NTLMv2 "blob"
1428 * @param session generated session nonce, should be freed with heim_ntlm_free_buf().
1429 * @param master calculated session master key, should be freed with heim_ntlm_free_buf().
1431 * @return In case of success 0 is return, an errors, a errno in what
1434 * @ingroup ntlm_core
1439 heim_ntlm_build_ntlm2_master(void *key
, size_t len
,
1440 struct ntlm_buf
*blob
,
1441 struct ntlm_buf
*session
,
1442 struct ntlm_buf
*master
)
1444 struct ntlm_buf sess
;
1447 ret
= heim_ntlm_v2_base_session(key
, len
, blob
, &sess
);
1451 ret
= heim_ntlm_keyex_wrap(&sess
, session
, master
);
1452 heim_ntlm_free_buf(&sess
);
1458 * Given a key and encrypted session, unwrap the session key
1460 * @param baseKey the sessionBaseKey
1461 * @param encryptedSession encrypted session, type3.session field.
1462 * @param session generated session nonce, should be freed with heim_ntlm_free_buf().
1464 * @return In case of success 0 is return, an errors, a errno in what
1467 * @ingroup ntlm_core
1471 heim_ntlm_keyex_unwrap(struct ntlm_buf
*baseKey
,
1472 struct ntlm_buf
*encryptedSession
,
1473 struct ntlm_buf
*session
)
1477 memset(session
, 0, sizeof(*session
));
1479 if (encryptedSession
->length
!= MD4_DIGEST_LENGTH
)
1480 return HNTLM_ERR_INVALID_LENGTH
;
1481 if (baseKey
->length
!= MD4_DIGEST_LENGTH
)
1482 return HNTLM_ERR_INVALID_LENGTH
;
1484 session
->length
= MD4_DIGEST_LENGTH
;
1485 session
->data
= malloc(session
->length
);
1486 if (session
->data
== NULL
) {
1487 session
->length
= 0;
1490 EVP_CIPHER_CTX_init(&c
);
1492 if (EVP_CipherInit_ex(&c
, EVP_rc4(), NULL
, baseKey
->data
, NULL
, 0) != 1) {
1493 EVP_CIPHER_CTX_cleanup(&c
);
1494 heim_ntlm_free_buf(session
);
1495 return HNTLM_ERR_CRYPTO
;
1498 EVP_Cipher(&c
, session
->data
, encryptedSession
->data
, session
->length
);
1499 EVP_CIPHER_CTX_cleanup(&c
);
1506 * Generates an NTLMv2 session key.
1508 * @param key the ntlm key
1509 * @param len length of key
1510 * @param username name of the user, as sent in the message, assumed to be in UTF8.
1511 * @param target the name of the target, assumed to be in UTF8.
1512 * @param upper_case_target upper case the target, should not be used only for legacy systems
1513 * @param ntlmv2 the ntlmv2 session key
1515 * @return 0 on success, or an error code on failure.
1517 * @ingroup ntlm_core
1521 heim_ntlm_ntlmv2_key(const void *key
, size_t len
,
1522 const char *username
,
1524 int upper_case_target
,
1525 unsigned char ntlmv2
[16])
1528 unsigned int hmaclen
;
1529 struct ntlm_buf buf
;
1533 if (HMAC_Init_ex(&c
, key
, len
, EVP_md5(), NULL
) == 0) {
1537 /* uppercase username and turn it into ucs2-le */
1538 ret
= ascii2ucs2le(username
, 1, &buf
);
1541 HMAC_Update(&c
, buf
.data
, buf
.length
);
1543 /* turn target into ucs2-le */
1544 ret
= ascii2ucs2le(target
, upper_case_target
, &buf
);
1547 HMAC_Update(&c
, buf
.data
, buf
.length
);
1549 HMAC_Final(&c
, ntlmv2
, &hmaclen
);
1551 HMAC_CTX_cleanup(&c
);
1552 memset(&c
, 0, sizeof(c
));
1561 #define NTTIME_EPOCH 0x019DB1DED53E8000LL
1564 heim_ntlm_unix2ts_time(time_t unix_time
)
1567 wt
= unix_time
* (uint64_t)10000000 + (uint64_t)NTTIME_EPOCH
;
1572 heim_ntlm_ts2unixtime(uint64_t t
)
1574 t
= ((t
- (uint64_t)NTTIME_EPOCH
) / (uint64_t)10000000);
1575 if (t
> (((uint64_t)(time_t)(~(uint64_t)0)) >> 1))
1581 * Calculate LMv2 response
1583 * @param key the ntlm key
1584 * @param len length of key
1585 * @param username name of the user, as sent in the message, assumed to be in UTF8.
1586 * @param target the name of the target, assumed to be in UTF8.
1587 * @param serverchallenge challenge as sent by the server in the type2 message.
1588 * @param ntlmv2 calculated session key
1589 * @param answer ntlm response answer, should be freed with heim_ntlm_free_buf().
1591 * @return In case of success 0 is return, an errors, a errno in what
1594 * @ingroup ntlm_core
1598 heim_ntlm_calculate_lm2(const void *key
, size_t len
,
1599 const char *username
,
1601 const unsigned char serverchallenge
[8],
1602 unsigned char ntlmv2
[16],
1603 struct ntlm_buf
*answer
)
1605 unsigned char clientchallenge
[8];
1606 krb5_error_code ret
;
1608 if (RAND_bytes(clientchallenge
, sizeof(clientchallenge
)) != 1)
1609 return HNTLM_ERR_RAND
;
1611 /* calculate ntlmv2 key */
1613 heim_ntlm_ntlmv2_key(key
, len
, username
, target
, 0, ntlmv2
);
1615 answer
->data
= malloc(24);
1616 if (answer
->data
== NULL
)
1618 answer
->length
= 24;
1620 ret
= heim_ntlm_derive_ntlm2_sess(ntlmv2
, clientchallenge
, 8,
1621 serverchallenge
, answer
->data
);
1623 memcpy(((unsigned char *)answer
->data
) + 16, clientchallenge
, 8);
1630 * Calculate NTLMv2 response
1632 * @param key the ntlm key
1633 * @param len length of key
1634 * @param username name of the user, as sent in the message, assumed to be in UTF8.
1635 * @param target the name of the target, assumed to be in UTF8.
1636 * @param serverchallenge challenge as sent by the server in the type2 message.
1637 * @param infotarget infotarget 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().
1641 * @return In case of success 0 is return, an errors, a errno in what
1644 * @ingroup ntlm_core
1648 heim_ntlm_calculate_ntlm2(const void *key
, size_t len
,
1649 const char *username
,
1651 const unsigned char serverchallenge
[8],
1652 const struct ntlm_buf
*infotarget
,
1653 unsigned char ntlmv2
[16],
1654 struct ntlm_buf
*answer
)
1656 krb5_error_code ret
;
1658 unsigned char ntlmv2answer
[16];
1660 unsigned char clientchallenge
[8];
1663 t
= heim_ntlm_unix2ts_time(time(NULL
));
1665 if (RAND_bytes(clientchallenge
, sizeof(clientchallenge
)) != 1)
1666 return HNTLM_ERR_RAND
;
1668 /* calculate ntlmv2 key */
1670 heim_ntlm_ntlmv2_key(key
, len
, username
, target
, 0, ntlmv2
);
1672 /* calculate and build ntlmv2 answer */
1674 sp
= krb5_storage_emem();
1677 krb5_storage_set_flags(sp
, KRB5_STORAGE_BYTEORDER_LE
);
1679 CHECK(krb5_store_uint32(sp
, 0x00000101), 0);
1680 CHECK(krb5_store_uint32(sp
, 0), 0);
1681 /* timestamp le 64 bit ts */
1682 CHECK(krb5_store_uint32(sp
, t
& 0xffffffff), 0);
1683 CHECK(krb5_store_uint32(sp
, t
>> 32), 0);
1685 CHECK_SIZE(krb5_storage_write(sp
, clientchallenge
, 8), 8);
1687 CHECK(krb5_store_uint32(sp
, 0), 0); /* Z(4) */
1688 CHECK_SIZE(krb5_storage_write(sp
, infotarget
->data
, infotarget
->length
),
1689 infotarget
->length
);
1692 * These last 4 bytes(Z(4)) are not documented by MicroSoft and
1693 * SnowLeopard doesn't send them, Lion expected them to be there,
1694 * so we have to continue to send them. That is ok, since everyone
1695 * else (except Snow) seems to do that too.
1697 CHECK(krb5_store_uint32(sp
, 0), 0); /* Z(4) */
1699 CHECK(krb5_storage_to_data(sp
, &data
), 0);
1700 krb5_storage_free(sp
);
1703 ret
= heim_ntlm_derive_ntlm2_sess(ntlmv2
, data
.data
, data
.length
,
1704 serverchallenge
, ntlmv2answer
);
1708 sp
= krb5_storage_emem();
1710 krb5_data_free(&data
);
1714 CHECK_SIZE(krb5_storage_write(sp
, ntlmv2answer
, 16), 16);
1715 CHECK_SIZE(krb5_storage_write(sp
, data
.data
, data
.length
), data
.length
);
1716 krb5_data_free(&data
);
1718 CHECK(krb5_storage_to_data(sp
, &data
), 0);
1719 krb5_storage_free(sp
);
1722 answer
->data
= data
.data
;
1723 answer
->length
= data
.length
;
1728 krb5_storage_free(sp
);
1732 static const int authtimediff
= 3600 * 2; /* 2 hours */
1735 verify_ntlm2(const void *key
, size_t len
,
1736 const char *username
,
1738 int upper_case_target
,
1740 const unsigned char serverchallenge
[8],
1741 const struct ntlm_buf
*answer
,
1742 struct ntlm_buf
*infotarget
,
1743 unsigned char ntlmv2
[16])
1745 krb5_error_code ret
;
1746 unsigned char clientanswer
[16];
1747 unsigned char clientnonce
[8];
1748 unsigned char serveranswer
[16];
1754 infotarget
->length
= 0;
1755 infotarget
->data
= NULL
;
1757 if (answer
->length
< 16)
1758 return HNTLM_ERR_INVALID_LENGTH
;
1763 /* calculate ntlmv2 key */
1765 heim_ntlm_ntlmv2_key(key
, len
, username
, target
, upper_case_target
, ntlmv2
);
1767 /* calculate and build ntlmv2 answer */
1769 sp
= krb5_storage_from_readonly_mem(answer
->data
, answer
->length
);
1772 krb5_storage_set_flags(sp
, KRB5_STORAGE_BYTEORDER_LE
);
1774 CHECK_SIZE(krb5_storage_read(sp
, clientanswer
, 16), 16);
1776 CHECK(krb5_ret_uint32(sp
, &temp
), 0);
1777 CHECK(temp
, 0x00000101);
1778 CHECK(krb5_ret_uint32(sp
, &temp
), 0);
1780 /* timestamp le 64 bit ts */
1781 CHECK(krb5_ret_uint32(sp
, &temp
), 0);
1783 CHECK(krb5_ret_uint32(sp
, &temp
), 0);
1784 t
|= ((uint64_t)temp
)<< 32;
1786 authtime
= heim_ntlm_ts2unixtime(t
);
1788 if (labs((int)(authtime
- now
)) > authtimediff
) {
1789 ret
= HNTLM_ERR_TIME_SKEW
;
1793 /* client challenge */
1794 CHECK_SIZE(krb5_storage_read(sp
, clientnonce
, 8), 8);
1796 CHECK(krb5_ret_uint32(sp
, &temp
), 0); /* Z(4) */
1798 /* let pick up targetinfo */
1799 infotarget
->length
= answer
->length
- (size_t)krb5_storage_seek(sp
, 0, SEEK_CUR
);
1800 if (infotarget
->length
< 4) {
1801 ret
= HNTLM_ERR_INVALID_LENGTH
;
1804 infotarget
->data
= malloc(infotarget
->length
);
1805 if (infotarget
->data
== NULL
) {
1809 CHECK_SIZE(krb5_storage_read(sp
, infotarget
->data
, infotarget
->length
),
1810 infotarget
->length
);
1812 krb5_storage_free(sp
);
1815 if (answer
->length
< 16) {
1816 ret
= HNTLM_ERR_INVALID_LENGTH
;
1820 ret
= heim_ntlm_derive_ntlm2_sess(ntlmv2
,
1821 ((unsigned char *)answer
->data
) + 16,
1822 answer
->length
- 16,
1828 if (ct_memcmp(serveranswer
, clientanswer
, 16) != 0) {
1829 heim_ntlm_free_buf(infotarget
);
1830 return HNTLM_ERR_AUTH
;
1835 heim_ntlm_free_buf(infotarget
);
1837 krb5_storage_free(sp
);
1842 * Verify NTLMv2 response.
1844 * @param key the ntlm key
1845 * @param len length of key
1846 * @param username name of the user, as sent in the message, assumed to be in UTF8.
1847 * @param target the name of the target, assumed to be in UTF8.
1848 * @param now the time now (0 if the library should pick it up itself)
1849 * @param serverchallenge challenge as sent by the server in the type2 message.
1850 * @param answer ntlm response answer, should be freed with heim_ntlm_free_buf().
1851 * @param infotarget infotarget as sent by the server in the type2 message.
1852 * @param ntlmv2 calculated session key
1854 * @return In case of success 0 is return, an errors, a errno in what
1857 * @ingroup ntlm_core
1861 heim_ntlm_verify_ntlm2(const void *key
, size_t len
,
1862 const char *username
,
1865 const unsigned char serverchallenge
[8],
1866 const struct ntlm_buf
*answer
,
1867 struct ntlm_buf
*infotarget
,
1868 unsigned char ntlmv2
[16])
1873 * First check with the domain as the client passed it to the function.
1876 ret
= verify_ntlm2(key
, len
, username
, target
, 0, now
,
1877 serverchallenge
, answer
, infotarget
, ntlmv2
);
1880 * Second check with domain uppercased.
1884 ret
= verify_ntlm2(key
, len
, username
, target
, 1, now
,
1885 serverchallenge
, answer
, infotarget
, ntlmv2
);
1888 * Third check with empty domain.
1891 ret
= verify_ntlm2(key
, len
, username
, "", 0, now
,
1892 serverchallenge
, answer
, infotarget
, ntlmv2
);
1897 * Calculate the NTLM2 Session Response
1899 * @param clnt_nonce client nonce
1900 * @param svr_chal server challage
1901 * @param ntlm2_hash ntlm hash
1902 * @param lm The LM response, should be freed with heim_ntlm_free_buf().
1903 * @param ntlm The NTLM response, should be freed with heim_ntlm_free_buf().
1905 * @return In case of success 0 is return, an errors, a errno in what
1908 * @ingroup ntlm_core
1912 heim_ntlm_calculate_ntlm2_sess(const unsigned char clnt_nonce
[8],
1913 const unsigned char svr_chal
[8],
1914 const unsigned char ntlm_hash
[16],
1915 struct ntlm_buf
*lm
,
1916 struct ntlm_buf
*ntlm
)
1918 unsigned char ntlm2_sess_hash
[8];
1919 unsigned char res
[21], *resp
;
1922 code
= heim_ntlm_calculate_ntlm2_sess_hash(clnt_nonce
, svr_chal
,
1928 lm
->data
= malloc(24);
1929 if (lm
->data
== NULL
) {
1934 ntlm
->data
= malloc(24);
1935 if (ntlm
->data
== NULL
) {
1942 /* first setup the lm resp */
1943 memset(lm
->data
, 0, 24);
1944 memcpy(lm
->data
, clnt_nonce
, 8);
1946 memset(res
, 0, sizeof(res
));
1947 memcpy(res
, ntlm_hash
, 16);
1950 splitandenc(&res
[0], ntlm2_sess_hash
, resp
+ 0);
1951 splitandenc(&res
[7], ntlm2_sess_hash
, resp
+ 8);
1952 splitandenc(&res
[14], ntlm2_sess_hash
, resp
+ 16);
1959 * Calculate the NTLM2 Session "Verifier"
1961 * @param clnt_nonce client nonce
1962 * @param svr_chal server challage
1963 * @param hash The NTLM session verifier
1965 * @return In case of success 0 is return, an errors, a errno in what
1968 * @ingroup ntlm_core
1972 heim_ntlm_calculate_ntlm2_sess_hash(const unsigned char clnt_nonce
[8],
1973 const unsigned char svr_chal
[8],
1974 unsigned char verifier
[8])
1976 unsigned char ntlm2_sess_hash
[MD5_DIGEST_LENGTH
];
1979 m
= EVP_MD_CTX_create();
1983 EVP_DigestInit_ex(m
, EVP_md5(), NULL
);
1984 EVP_DigestUpdate(m
, svr_chal
, 8); /* session nonce part 1 */
1985 EVP_DigestUpdate(m
, clnt_nonce
, 8); /* session nonce part 2 */
1986 EVP_DigestFinal_ex(m
, ntlm2_sess_hash
, NULL
); /* will only use first 8 bytes */
1987 EVP_MD_CTX_destroy(m
);
1989 memcpy(verifier
, ntlm2_sess_hash
, 8);
1996 * Derive a NTLM2 session key
1998 * @param sessionkey session key from domain controller
1999 * @param clnt_nonce client nonce
2000 * @param svr_chal server challenge
2001 * @param derivedkey salted session key
2003 * @return In case of success 0 is return, an errors, a errno in what
2006 * @ingroup ntlm_core
2010 heim_ntlm_derive_ntlm2_sess(const unsigned char sessionkey
[16],
2011 const unsigned char *clnt_nonce
, size_t clnt_nonce_length
,
2012 const unsigned char svr_chal
[8],
2013 unsigned char derivedkey
[16])
2015 unsigned int hmaclen
;
2018 /* HMAC(Ksession, serverchallenge || clientchallenge) */
2020 if (HMAC_Init_ex(&c
, sessionkey
, 16, EVP_md5(), NULL
) == 0) {
2021 HMAC_CTX_cleanup(&c
);
2024 HMAC_Update(&c
, svr_chal
, 8);
2025 HMAC_Update(&c
, clnt_nonce
, clnt_nonce_length
);
2026 HMAC_Final(&c
, derivedkey
, &hmaclen
);
2027 HMAC_CTX_cleanup(&c
);
2028 memset(&c
, 0, sizeof(c
));