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
47 #include <parse_units.h>
50 #define HC_DEPRECATED_CRYPTO
52 #include "krb5-types.h"
53 #include "crypto-headers.h"
57 /*! \mainpage Heimdal NTLM library
59 * \section intro Introduction
61 * Heimdal libheimntlm library is a implementation of the NTLM
62 * protocol, both version 1 and 2. The GSS-API mech that uses this
63 * library adds support for transport encryption and integrity
66 * NTLM is a protocol for mutual authentication, its still used in
67 * many protocol where Kerberos is not support, one example is
68 * EAP/X802.1x mechanism LEAP from Microsoft and Cisco.
70 * This is a support library for the core protocol, its used in
71 * Heimdal to implement and GSS-API mechanism. There is also support
72 * in the KDC to do remote digest authenticiation, this to allow
73 * services to authenticate users w/o direct access to the users ntlm
74 * hashes (same as Kerberos arcfour enctype keys).
76 * More information about the NTLM protocol can found here
77 * http://davenport.sourceforge.net/ntlm.html .
79 * The Heimdal projects web page: http://www.h5l.org/
81 * @section ntlm_example NTLM Example
83 * Example to to use @ref test_ntlm.c .
85 * @example test_ntlm.c
87 * Example how to use the NTLM primitives.
91 /** @defgroup ntlm_core Heimdal NTLM library
93 * The NTLM core functions implement the string2key generation
94 * function, message encode and decode function, and the hash function
104 static const unsigned char ntlmsigature
[8] = "NTLMSSP\x00";
110 #define CHECK(f, e) \
113 if (ret != (ssize_t)(e)) { \
114 ret = HNTLM_ERR_DECODE; \
117 } while(/*CONSTCOND*/0)
119 static struct units ntlm_flag_units
[] = {
120 #define ntlm_flag(x) { #x, NTLM_##x }
122 ntlm_flag(NEG_KEYEX
),
127 ntlm_flag(NEG_VERSION
),
129 ntlm_flag(NEG_TARGET_INFO
),
130 ntlm_flag(NON_NT_SESSION_KEY
),
132 ntlm_flag(NEG_IDENTIFY
),
133 ntlm_flag(NEG_NTLM2
),
134 ntlm_flag(TARGET_SHARE
),
135 ntlm_flag(TARGET_SERVER
),
136 ntlm_flag(TARGET_DOMAIN
),
137 ntlm_flag(NEG_ALWAYS_SIGN
),
139 ntlm_flag(OEM_SUPPLIED_WORKSTATION
),
140 ntlm_flag(OEM_SUPPLIED_DOMAIN
),
141 ntlm_flag(NEG_ANONYMOUS
),
142 ntlm_flag(NEG_NT_ONLY
),
145 ntlm_flag(NEG_LM_KEY
),
146 ntlm_flag(NEG_DATAGRAM
),
150 ntlm_flag(NEG_TARGET
),
152 ntlm_flag(NEG_UNICODE
),
158 heim_ntlm_unparse_flags(uint32_t flags
, char *s
, size_t len
)
160 return unparse_flags(flags
, ntlm_flag_units
, s
, len
);
165 * heim_ntlm_free_buf frees the ntlm buffer
167 * @param p buffer to be freed
173 heim_ntlm_free_buf(struct ntlm_buf
*p
)
183 ascii2ucs2le(const char *string
, int up
, struct ntlm_buf
*buf
)
188 len
= strlen(string
);
189 if (len
/ 2 > UINT_MAX
)
192 buf
->length
= len
* 2;
193 buf
->data
= malloc(buf
->length
);
194 if (buf
->data
== NULL
&& len
!= 0) {
195 heim_ntlm_free_buf(buf
);
200 for (i
= 0; i
< len
; i
++) {
201 unsigned char t
= (unsigned char)string
[i
];
203 heim_ntlm_free_buf(buf
);
218 static krb5_error_code
219 ret_sec_buffer(krb5_storage
*sp
, struct sec_buffer
*buf
)
222 CHECK(krb5_ret_uint16(sp
, &buf
->length
), 0);
223 CHECK(krb5_ret_uint16(sp
, &buf
->allocated
), 0);
224 CHECK(krb5_ret_uint32(sp
, &buf
->offset
), 0);
229 static krb5_error_code
230 store_sec_buffer(krb5_storage
*sp
, const struct sec_buffer
*buf
)
233 CHECK(krb5_store_uint16(sp
, buf
->length
), 0);
234 CHECK(krb5_store_uint16(sp
, buf
->allocated
), 0);
235 CHECK(krb5_store_uint32(sp
, buf
->offset
), 0);
241 * Strings are either OEM or UNICODE. The later is encoded as ucs2 on
242 * wire, but using utf8 in memory.
245 static krb5_error_code
246 len_string(int ucs2
, const char *s
)
248 size_t len
= strlen(s
);
258 static krb5_error_code
259 ret_string(krb5_storage
*sp
, int ucs2
, size_t len
, char **s
)
263 *s
= malloc(len
+ 1);
266 CHECK(krb5_storage_read(sp
, *s
, len
), len
);
272 for (i
= 0; i
< len
/ 2; i
++) {
273 (*s
)[i
] = (*s
)[i
* 2];
274 if ((*s
)[i
* 2 + 1]) {
289 static krb5_error_code
290 ret_sec_string(krb5_storage
*sp
, int ucs2
, struct sec_buffer
*desc
, char **s
)
292 krb5_error_code ret
= 0;
293 CHECK(krb5_storage_seek(sp
, desc
->offset
, SEEK_SET
), desc
->offset
);
294 CHECK(ret_string(sp
, ucs2
, desc
->length
, s
), 0);
299 static krb5_error_code
300 put_string(krb5_storage
*sp
, int ucs2
, const char *s
)
306 ret
= ascii2ucs2le(s
, 0, &buf
);
310 buf
.data
= rk_UNCONST(s
);
311 buf
.length
= strlen(s
);
314 CHECK(krb5_storage_write(sp
, buf
.data
, buf
.length
), buf
.length
);
316 heim_ntlm_free_buf(&buf
);
326 static krb5_error_code
327 ret_buf(krb5_storage
*sp
, struct sec_buffer
*desc
, struct ntlm_buf
*buf
)
331 buf
->data
= malloc(desc
->length
);
332 buf
->length
= desc
->length
;
333 CHECK(krb5_storage_seek(sp
, desc
->offset
, SEEK_SET
), desc
->offset
);
334 CHECK(krb5_storage_read(sp
, buf
->data
, buf
->length
), buf
->length
);
340 static krb5_error_code
341 put_buf(krb5_storage
*sp
, const struct ntlm_buf
*buf
)
344 CHECK(krb5_storage_write(sp
, buf
->data
, buf
->length
), buf
->length
);
351 * Frees the ntlm_targetinfo message
353 * @param ti targetinfo to be freed
359 heim_ntlm_free_targetinfo(struct ntlm_targetinfo
*ti
)
361 free(ti
->servername
);
362 free(ti
->domainname
);
363 free(ti
->dnsdomainname
);
364 free(ti
->dnsservername
);
365 free(ti
->dnstreename
);
366 memset(ti
, 0, sizeof(*ti
));
370 encode_ti_string(krb5_storage
*out
, uint16_t type
, int ucs2
, char *s
)
373 CHECK(krb5_store_uint16(out
, type
), 0);
374 CHECK(krb5_store_uint16(out
, len_string(ucs2
, s
)), 0);
375 CHECK(put_string(out
, ucs2
, s
), 0);
381 * Encodes a ntlm_targetinfo message.
383 * @param ti the ntlm_targetinfo message to encode.
384 * @param ucs2 ignored
385 * @param data is the return buffer with the encoded message, should be
386 * freed with heim_ntlm_free_buf().
388 * @return In case of success 0 is return, an errors, a errno in what
395 heim_ntlm_encode_targetinfo(const struct ntlm_targetinfo
*ti
,
397 struct ntlm_buf
*data
)
405 out
= krb5_storage_emem();
409 krb5_storage_set_byteorder(out
, KRB5_STORAGE_BYTEORDER_LE
);
412 CHECK(encode_ti_string(out
, 1, ucs2
, ti
->servername
), 0);
414 CHECK(encode_ti_string(out
, 2, ucs2
, ti
->domainname
), 0);
415 if (ti
->dnsservername
)
416 CHECK(encode_ti_string(out
, 3, ucs2
, ti
->dnsservername
), 0);
417 if (ti
->dnsdomainname
)
418 CHECK(encode_ti_string(out
, 4, ucs2
, ti
->dnsdomainname
), 0);
420 CHECK(encode_ti_string(out
, 5, ucs2
, ti
->dnstreename
), 0);
422 CHECK(krb5_store_uint16(out
, 6), 0);
423 CHECK(krb5_store_uint16(out
, 4), 0);
424 CHECK(krb5_store_uint32(out
, ti
->avflags
), 0);
428 CHECK(krb5_store_int16(out
, 0), 0);
429 CHECK(krb5_store_int16(out
, 0), 0);
433 ret
= krb5_storage_to_data(out
, &d
);
435 data
->length
= d
.length
;
438 krb5_storage_free(out
);
443 * Decodes an NTLM targetinfo message
445 * @param data input data buffer with the encode NTLM targetinfo message
446 * @param ucs2 if the strings should be encoded with ucs2 (selected by flag in message).
447 * @param ti the decoded target info, should be freed with heim_ntlm_free_targetinfo().
449 * @return In case of success 0 is return, an errors, a errno in what
456 heim_ntlm_decode_targetinfo(const struct ntlm_buf
*data
,
458 struct ntlm_targetinfo
*ti
)
462 int ret
= 0, done
= 0;
464 memset(ti
, 0, sizeof(*ti
));
466 if (data
->length
== 0)
469 in
= krb5_storage_from_readonly_mem(data
->data
, data
->length
);
472 krb5_storage_set_byteorder(in
, KRB5_STORAGE_BYTEORDER_LE
);
475 CHECK(krb5_ret_uint16(in
, &type
), 0);
476 CHECK(krb5_ret_uint16(in
, &len
), 0);
483 CHECK(ret_string(in
, ucs2
, len
, &ti
->servername
), 0);
486 CHECK(ret_string(in
, ucs2
, len
, &ti
->domainname
), 0);
489 CHECK(ret_string(in
, ucs2
, len
, &ti
->dnsservername
), 0);
492 CHECK(ret_string(in
, ucs2
, len
, &ti
->dnsdomainname
), 0);
495 CHECK(ret_string(in
, ucs2
, len
, &ti
->dnstreename
), 0);
498 CHECK(krb5_ret_uint32(in
, &ti
->avflags
), 0);
501 krb5_storage_seek(in
, len
, SEEK_CUR
);
507 krb5_storage_free(in
);
512 * Frees the ntlm_type1 message
514 * @param data message to be freed
520 heim_ntlm_free_type1(struct ntlm_type1
*data
)
525 free(data
->hostname
);
526 memset(data
, 0, sizeof(*data
));
530 heim_ntlm_decode_type1(const struct ntlm_buf
*buf
, struct ntlm_type1
*data
)
533 unsigned char sig
[8];
535 struct sec_buffer domain
, hostname
;
538 memset(data
, 0, sizeof(*data
));
540 in
= krb5_storage_from_readonly_mem(buf
->data
, buf
->length
);
545 krb5_storage_set_byteorder(in
, KRB5_STORAGE_BYTEORDER_LE
);
547 CHECK(krb5_storage_read(in
, sig
, sizeof(sig
)), sizeof(sig
));
548 CHECK(memcmp(ntlmsigature
, sig
, sizeof(ntlmsigature
)), 0);
549 CHECK(krb5_ret_uint32(in
, &type
), 0);
551 CHECK(krb5_ret_uint32(in
, &data
->flags
), 0);
552 if (data
->flags
& NTLM_OEM_SUPPLIED_DOMAIN
)
553 CHECK(ret_sec_buffer(in
, &domain
), 0);
554 if (data
->flags
& NTLM_OEM_SUPPLIED_WORKSTATION
)
555 CHECK(ret_sec_buffer(in
, &hostname
), 0);
557 if (domain
.offset
> 32) {
558 CHECK(krb5_ret_uint32(in
, &data
->os
[0]), 0);
559 CHECK(krb5_ret_uint32(in
, &data
->os
[1]), 0);
562 if (data
->flags
& NTLM_OEM_SUPPLIED_DOMAIN
)
563 CHECK(ret_sec_string(in
, 0, &domain
, &data
->domain
), 0);
564 if (data
->flags
& NTLM_OEM_SUPPLIED_WORKSTATION
)
565 CHECK(ret_sec_string(in
, 0, &hostname
, &data
->hostname
), 0);
569 krb5_storage_free(in
);
571 heim_ntlm_free_type1(data
);
577 * Encodes an ntlm_type1 message.
579 * @param type1 the ntlm_type1 message to encode.
580 * @param data is the return buffer with the encoded message, should be
581 * freed with heim_ntlm_free_buf().
583 * @return In case of success 0 is return, an errors, a errno in what
590 heim_ntlm_encode_type1(const struct ntlm_type1
*type1
, struct ntlm_buf
*data
)
593 struct sec_buffer domain
, hostname
;
595 uint32_t base
, flags
;
597 flags
= type1
->flags
;
602 flags
|= NTLM_OEM_SUPPLIED_DOMAIN
;
604 if (type1
->hostname
) {
606 flags
|= NTLM_OEM_SUPPLIED_WORKSTATION
;
611 domain
.offset
= base
;
613 domain
.length
= len_string(0, type1
->domain
);
614 domain
.allocated
= domain
.length
;
617 domain
.allocated
= 0;
620 hostname
.offset
= domain
.allocated
+ domain
.offset
;
621 if (type1
->hostname
) {
622 hostname
.length
= len_string(0, type1
->hostname
);
623 hostname
.allocated
= hostname
.length
;
626 hostname
.allocated
= 0;
629 out
= krb5_storage_emem();
633 krb5_storage_set_byteorder(out
, KRB5_STORAGE_BYTEORDER_LE
);
634 CHECK(krb5_storage_write(out
, ntlmsigature
, sizeof(ntlmsigature
)),
635 sizeof(ntlmsigature
));
636 CHECK(krb5_store_uint32(out
, 1), 0);
637 CHECK(krb5_store_uint32(out
, flags
), 0);
639 CHECK(store_sec_buffer(out
, &domain
), 0);
640 CHECK(store_sec_buffer(out
, &hostname
), 0);
642 CHECK(krb5_store_uint32(out
, type1
->os
[0]), 0);
643 CHECK(krb5_store_uint32(out
, type1
->os
[1]), 0);
646 CHECK(put_string(out
, 0, type1
->domain
), 0);
648 CHECK(put_string(out
, 0, type1
->hostname
), 0);
652 ret
= krb5_storage_to_data(out
, &d
);
654 data
->length
= d
.length
;
657 krb5_storage_free(out
);
663 * Frees the ntlm_type2 message
665 * @param data message to be freed
671 heim_ntlm_free_type2(struct ntlm_type2
*data
)
673 if (data
->targetname
)
674 free(data
->targetname
);
675 heim_ntlm_free_buf(&data
->targetinfo
);
676 memset(data
, 0, sizeof(*data
));
680 heim_ntlm_decode_type2(const struct ntlm_buf
*buf
, struct ntlm_type2
*type2
)
683 unsigned char sig
[8];
684 uint32_t type
, ctx
[2];
685 struct sec_buffer targetname
, targetinfo
;
689 memset(type2
, 0, sizeof(*type2
));
691 in
= krb5_storage_from_readonly_mem(buf
->data
, buf
->length
);
696 krb5_storage_set_byteorder(in
, KRB5_STORAGE_BYTEORDER_LE
);
698 CHECK(krb5_storage_read(in
, sig
, sizeof(sig
)), sizeof(sig
));
699 CHECK(memcmp(ntlmsigature
, sig
, sizeof(ntlmsigature
)), 0);
700 CHECK(krb5_ret_uint32(in
, &type
), 0);
703 CHECK(ret_sec_buffer(in
, &targetname
), 0);
704 CHECK(krb5_ret_uint32(in
, &type2
->flags
), 0);
705 if (type2
->flags
& NTLM_NEG_UNICODE
)
707 CHECK(krb5_storage_read(in
, type2
->challenge
, sizeof(type2
->challenge
)),
708 sizeof(type2
->challenge
));
709 CHECK(krb5_ret_uint32(in
, &ctx
[0]), 0); /* context */
710 CHECK(krb5_ret_uint32(in
, &ctx
[1]), 0);
711 CHECK(ret_sec_buffer(in
, &targetinfo
), 0);
713 if (type2
->flags
& NTLM_NEG_VERSION
) {
714 CHECK(krb5_ret_uint32(in
, &type2
->os
[0]), 0);
715 CHECK(krb5_ret_uint32(in
, &type2
->os
[1]), 0);
718 CHECK(ret_sec_string(in
, ucs2
, &targetname
, &type2
->targetname
), 0);
719 CHECK(ret_buf(in
, &targetinfo
, &type2
->targetinfo
), 0);
724 krb5_storage_free(in
);
726 heim_ntlm_free_type2(type2
);
732 * Encodes an ntlm_type2 message.
734 * @param type2 the ntlm_type2 message to encode.
735 * @param data is the return buffer with the encoded message, should be
736 * freed with heim_ntlm_free_buf().
738 * @return In case of success 0 is return, an errors, a errno in what
745 heim_ntlm_encode_type2(const struct ntlm_type2
*type2
, struct ntlm_buf
*data
)
747 struct sec_buffer targetname
, targetinfo
;
749 krb5_storage
*out
= NULL
;
755 if (type2
->flags
& NTLM_NEG_VERSION
)
758 if (type2
->flags
& NTLM_NEG_UNICODE
)
761 targetname
.offset
= base
;
762 targetname
.length
= len_string(ucs2
, type2
->targetname
);
763 targetname
.allocated
= targetname
.length
;
765 targetinfo
.offset
= targetname
.allocated
+ targetname
.offset
;
766 targetinfo
.length
= type2
->targetinfo
.length
;
767 targetinfo
.allocated
= type2
->targetinfo
.length
;
769 out
= krb5_storage_emem();
773 krb5_storage_set_byteorder(out
, KRB5_STORAGE_BYTEORDER_LE
);
774 CHECK(krb5_storage_write(out
, ntlmsigature
, sizeof(ntlmsigature
)),
775 sizeof(ntlmsigature
));
776 CHECK(krb5_store_uint32(out
, 2), 0);
777 CHECK(store_sec_buffer(out
, &targetname
), 0);
778 CHECK(krb5_store_uint32(out
, type2
->flags
), 0);
779 CHECK(krb5_storage_write(out
, type2
->challenge
, sizeof(type2
->challenge
)),
780 sizeof(type2
->challenge
));
781 CHECK(krb5_store_uint32(out
, 0), 0); /* context */
782 CHECK(krb5_store_uint32(out
, 0), 0);
783 CHECK(store_sec_buffer(out
, &targetinfo
), 0);
785 if (type2
->flags
& NTLM_NEG_VERSION
) {
786 CHECK(krb5_store_uint32(out
, type2
->os
[0]), 0);
787 CHECK(krb5_store_uint32(out
, type2
->os
[1]), 0);
789 CHECK(put_string(out
, ucs2
, type2
->targetname
), 0);
790 CHECK(krb5_storage_write(out
, type2
->targetinfo
.data
,
791 type2
->targetinfo
.length
),
792 type2
->targetinfo
.length
);
796 ret
= krb5_storage_to_data(out
, &d
);
798 data
->length
= d
.length
;
802 krb5_storage_free(out
);
808 * Frees the ntlm_type3 message
810 * @param data message to be freed
816 heim_ntlm_free_type3(struct ntlm_type3
*data
)
818 heim_ntlm_free_buf(&data
->lm
);
819 heim_ntlm_free_buf(&data
->ntlm
);
820 if (data
->targetname
)
821 free(data
->targetname
);
823 free(data
->username
);
826 heim_ntlm_free_buf(&data
->sessionkey
);
827 memset(data
, 0, sizeof(*data
));
835 heim_ntlm_decode_type3(const struct ntlm_buf
*buf
,
837 struct ntlm_type3
*type3
)
840 unsigned char sig
[8];
843 struct sec_buffer lm
, ntlm
, target
, username
, sessionkey
, ws
;
844 uint32_t min_offset
= 72;
846 memset(type3
, 0, sizeof(*type3
));
847 memset(&sessionkey
, 0, sizeof(sessionkey
));
849 in
= krb5_storage_from_readonly_mem(buf
->data
, buf
->length
);
854 krb5_storage_set_byteorder(in
, KRB5_STORAGE_BYTEORDER_LE
);
856 CHECK(krb5_storage_read(in
, sig
, sizeof(sig
)), sizeof(sig
));
857 CHECK(memcmp(ntlmsigature
, sig
, sizeof(ntlmsigature
)), 0);
858 CHECK(krb5_ret_uint32(in
, &type
), 0);
860 CHECK(ret_sec_buffer(in
, &lm
), 0);
862 min_offset
= min(min_offset
, lm
.offset
);
863 CHECK(ret_sec_buffer(in
, &ntlm
), 0);
865 min_offset
= min(min_offset
, ntlm
.offset
);
866 CHECK(ret_sec_buffer(in
, &target
), 0);
867 if (target
.allocated
)
868 min_offset
= min(min_offset
, target
.offset
);
869 CHECK(ret_sec_buffer(in
, &username
), 0);
870 if (username
.allocated
)
871 min_offset
= min(min_offset
, username
.offset
);
872 CHECK(ret_sec_buffer(in
, &ws
), 0);
874 min_offset
= min(min_offset
, ws
.offset
);
876 if (min_offset
> 52) {
877 CHECK(ret_sec_buffer(in
, &sessionkey
), 0);
878 min_offset
= max(min_offset
, sessionkey
.offset
);
879 CHECK(krb5_ret_uint32(in
, &type3
->flags
), 0);
881 if (min_offset
> 52 + 8 + 4 + 8) {
882 CHECK(krb5_ret_uint32(in
, &type3
->os
[0]), 0);
883 CHECK(krb5_ret_uint32(in
, &type3
->os
[1]), 0);
885 CHECK(ret_buf(in
, &lm
, &type3
->lm
), 0);
886 CHECK(ret_buf(in
, &ntlm
, &type3
->ntlm
), 0);
887 CHECK(ret_sec_string(in
, ucs2
, &target
, &type3
->targetname
), 0);
888 CHECK(ret_sec_string(in
, ucs2
, &username
, &type3
->username
), 0);
889 CHECK(ret_sec_string(in
, ucs2
, &ws
, &type3
->ws
), 0);
890 if (sessionkey
.offset
)
891 CHECK(ret_buf(in
, &sessionkey
, &type3
->sessionkey
), 0);
895 krb5_storage_free(in
);
897 heim_ntlm_free_type3(type3
);
903 * Encodes an ntlm_type3 message.
905 * @param type3 the ntlm_type3 message to encode.
906 * @param data is the return buffer with the encoded message, should be
907 * freed with heim_ntlm_free_buf().
909 * @return In case of success 0 is return, an errors, a errno in what
916 heim_ntlm_encode_type3(const struct ntlm_type3
*type3
, struct ntlm_buf
*data
)
918 struct sec_buffer lm
, ntlm
, target
, username
, sessionkey
, ws
;
920 krb5_storage
*out
= NULL
;
924 memset(&lm
, 0, sizeof(lm
));
925 memset(&ntlm
, 0, sizeof(ntlm
));
926 memset(&target
, 0, sizeof(target
));
927 memset(&username
, 0, sizeof(username
));
928 memset(&ws
, 0, sizeof(ws
));
929 memset(&sessionkey
, 0, sizeof(sessionkey
));
933 base
+= 8; /* sessionkey sec buf */
934 base
+= 4; /* flags */
940 if (type3
->flags
& NTLM_NEG_UNICODE
)
943 target
.offset
= base
;
944 target
.length
= len_string(ucs2
, type3
->targetname
);
945 target
.allocated
= target
.length
;
947 username
.offset
= target
.offset
+ target
.allocated
;
948 username
.length
= len_string(ucs2
, type3
->username
);
949 username
.allocated
= username
.length
;
951 ws
.offset
= username
.offset
+ username
.allocated
;
952 ws
.length
= len_string(ucs2
, type3
->ws
);
953 ws
.allocated
= ws
.length
;
955 lm
.offset
= ws
.offset
+ ws
.allocated
;
956 lm
.length
= type3
->lm
.length
;
957 lm
.allocated
= type3
->lm
.length
;
959 ntlm
.offset
= lm
.offset
+ lm
.allocated
;
960 ntlm
.length
= type3
->ntlm
.length
;
961 ntlm
.allocated
= ntlm
.length
;
963 sessionkey
.offset
= ntlm
.offset
+ ntlm
.allocated
;
964 sessionkey
.length
= type3
->sessionkey
.length
;
965 sessionkey
.allocated
= type3
->sessionkey
.length
;
967 out
= krb5_storage_emem();
971 krb5_storage_set_byteorder(out
, KRB5_STORAGE_BYTEORDER_LE
);
972 CHECK(krb5_storage_write(out
, ntlmsigature
, sizeof(ntlmsigature
)),
973 sizeof(ntlmsigature
));
974 CHECK(krb5_store_uint32(out
, 3), 0);
976 CHECK(store_sec_buffer(out
, &lm
), 0);
977 CHECK(store_sec_buffer(out
, &ntlm
), 0);
978 CHECK(store_sec_buffer(out
, &target
), 0);
979 CHECK(store_sec_buffer(out
, &username
), 0);
980 CHECK(store_sec_buffer(out
, &ws
), 0);
981 CHECK(store_sec_buffer(out
, &sessionkey
), 0);
982 CHECK(krb5_store_uint32(out
, type3
->flags
), 0);
985 CHECK(krb5_store_uint32(out
, 0), 0); /* os0 */
986 CHECK(krb5_store_uint32(out
, 0), 0); /* os1 */
989 CHECK(put_string(out
, ucs2
, type3
->targetname
), 0);
990 CHECK(put_string(out
, ucs2
, type3
->username
), 0);
991 CHECK(put_string(out
, ucs2
, type3
->ws
), 0);
992 CHECK(put_buf(out
, &type3
->lm
), 0);
993 CHECK(put_buf(out
, &type3
->ntlm
), 0);
994 CHECK(put_buf(out
, &type3
->sessionkey
), 0);
998 ret
= krb5_storage_to_data(out
, &d
);
1000 data
->length
= d
.length
;
1004 krb5_storage_free(out
);
1015 splitandenc(unsigned char *hash
,
1016 unsigned char *challenge
,
1017 unsigned char *answer
)
1020 unsigned char key
[8];
1023 key
[1] = (hash
[0] << 7) | (hash
[1] >> 1);
1024 key
[2] = (hash
[1] << 6) | (hash
[2] >> 2);
1025 key
[3] = (hash
[2] << 5) | (hash
[3] >> 3);
1026 key
[4] = (hash
[3] << 4) | (hash
[4] >> 4);
1027 key
[5] = (hash
[4] << 3) | (hash
[5] >> 5);
1028 key
[6] = (hash
[5] << 2) | (hash
[6] >> 6);
1029 key
[7] = (hash
[6] << 1);
1031 EVP_CIPHER_CTX_init(&ctx
);
1033 EVP_CipherInit_ex(&ctx
, EVP_des_cbc(), NULL
, key
, NULL
, 1);
1034 EVP_Cipher(&ctx
, answer
, challenge
, 8);
1035 EVP_CIPHER_CTX_cleanup(&ctx
);
1036 memset(key
, 0, sizeof(key
));
1040 * Calculate the NTLM key, the password is assumed to be in UTF8.
1042 * @param password password to calcute the key for.
1043 * @param key calcuted key, should be freed with heim_ntlm_free_buf().
1045 * @return In case of success 0 is return, an errors, a errno in what
1048 * @ingroup ntlm_core
1052 heim_ntlm_nt_key(const char *password
, struct ntlm_buf
*key
)
1054 struct ntlm_buf buf
;
1058 key
->data
= malloc(MD5_DIGEST_LENGTH
);
1059 if (key
->data
== NULL
)
1061 key
->length
= MD5_DIGEST_LENGTH
;
1063 ret
= ascii2ucs2le(password
, 0, &buf
);
1065 heim_ntlm_free_buf(key
);
1069 m
= EVP_MD_CTX_create();
1071 heim_ntlm_free_buf(key
);
1072 heim_ntlm_free_buf(&buf
);
1076 EVP_DigestInit_ex(m
, EVP_md4(), NULL
);
1077 EVP_DigestUpdate(m
, buf
.data
, buf
.length
);
1078 EVP_DigestFinal_ex(m
, key
->data
, NULL
);
1079 EVP_MD_CTX_destroy(m
);
1081 heim_ntlm_free_buf(&buf
);
1086 * Calculate NTLMv1 response hash
1088 * @param key the ntlm v1 key
1089 * @param len length of key
1090 * @param challenge sent by the server
1091 * @param answer calculated answer, should be freed with heim_ntlm_free_buf().
1093 * @return In case of success 0 is return, an errors, a errno in what
1096 * @ingroup ntlm_core
1100 heim_ntlm_calculate_ntlm1(void *key
, size_t len
,
1101 unsigned char challenge
[8],
1102 struct ntlm_buf
*answer
)
1104 unsigned char res
[21];
1106 if (len
!= MD4_DIGEST_LENGTH
)
1107 return HNTLM_ERR_INVALID_LENGTH
;
1109 memcpy(res
, key
, len
);
1110 memset(&res
[MD4_DIGEST_LENGTH
], 0, sizeof(res
) - MD4_DIGEST_LENGTH
);
1112 answer
->data
= malloc(24);
1113 if (answer
->data
== NULL
)
1115 answer
->length
= 24;
1117 splitandenc(&res
[0], challenge
, ((unsigned char *)answer
->data
) + 0);
1118 splitandenc(&res
[7], challenge
, ((unsigned char *)answer
->data
) + 8);
1119 splitandenc(&res
[14], challenge
, ((unsigned char *)answer
->data
) + 16);
1125 heim_ntlm_v1_base_session(void *key
, size_t len
,
1126 struct ntlm_buf
*session
)
1130 session
->length
= MD4_DIGEST_LENGTH
;
1131 session
->data
= malloc(session
->length
);
1132 if (session
->data
== NULL
) {
1133 session
->length
= 0;
1137 m
= EVP_MD_CTX_create();
1139 heim_ntlm_free_buf(session
);
1142 EVP_DigestInit_ex(m
, EVP_md4(), NULL
);
1143 EVP_DigestUpdate(m
, key
, len
);
1144 EVP_DigestFinal_ex(m
, session
->data
, NULL
);
1145 EVP_MD_CTX_destroy(m
);
1151 heim_ntlm_v2_base_session(void *key
, size_t len
,
1152 struct ntlm_buf
*ntlmResponse
,
1153 struct ntlm_buf
*session
)
1155 unsigned int hmaclen
;
1158 if (ntlmResponse
->length
<= 16)
1159 return HNTLM_ERR_INVALID_LENGTH
;
1161 session
->data
= malloc(16);
1162 if (session
->data
== NULL
)
1164 session
->length
= 16;
1166 /* Note: key is the NTLMv2 key */
1168 HMAC_Init_ex(&c
, key
, len
, EVP_md5(), NULL
);
1169 HMAC_Update(&c
, ntlmResponse
->data
, 16);
1170 HMAC_Final(&c
, session
->data
, &hmaclen
);
1171 HMAC_CTX_cleanup(&c
);
1178 heim_ntlm_keyex_wrap(struct ntlm_buf
*base_session
,
1179 struct ntlm_buf
*session
,
1180 struct ntlm_buf
*encryptedSession
)
1185 session
->length
= MD4_DIGEST_LENGTH
;
1186 session
->data
= malloc(session
->length
);
1187 if (session
->data
== NULL
) {
1188 session
->length
= 0;
1191 encryptedSession
->length
= MD4_DIGEST_LENGTH
;
1192 encryptedSession
->data
= malloc(encryptedSession
->length
);
1193 if (encryptedSession
->data
== NULL
) {
1194 heim_ntlm_free_buf(session
);
1195 encryptedSession
->length
= 0;
1199 EVP_CIPHER_CTX_init(&c
);
1201 ret
= EVP_CipherInit_ex(&c
, EVP_rc4(), NULL
, base_session
->data
, NULL
, 1);
1203 EVP_CIPHER_CTX_cleanup(&c
);
1204 heim_ntlm_free_buf(encryptedSession
);
1205 heim_ntlm_free_buf(session
);
1206 return HNTLM_ERR_CRYPTO
;
1209 if (RAND_bytes(session
->data
, session
->length
) != 1) {
1210 EVP_CIPHER_CTX_cleanup(&c
);
1211 heim_ntlm_free_buf(encryptedSession
);
1212 heim_ntlm_free_buf(session
);
1213 return HNTLM_ERR_RAND
;
1216 EVP_Cipher(&c
, encryptedSession
->data
, session
->data
, encryptedSession
->length
);
1217 EVP_CIPHER_CTX_cleanup(&c
);
1228 * Generates an NTLMv1 session random with assosited session master key.
1230 * @param key the ntlm v1 key
1231 * @param len length of key
1232 * @param session generated session nonce, should be freed with heim_ntlm_free_buf().
1233 * @param master calculated session master key, should be freed with heim_ntlm_free_buf().
1235 * @return In case of success 0 is return, an errors, a errno in what
1238 * @ingroup ntlm_core
1242 heim_ntlm_build_ntlm1_master(void *key
, size_t len
,
1243 struct ntlm_buf
*session
,
1244 struct ntlm_buf
*master
)
1246 struct ntlm_buf sess
;
1249 ret
= heim_ntlm_v1_base_session(key
, len
, &sess
);
1253 ret
= heim_ntlm_keyex_wrap(&sess
, session
, master
);
1254 heim_ntlm_free_buf(&sess
);
1260 * Generates an NTLMv2 session random with associated session master key.
1262 * @param key the NTLMv2 key
1263 * @param len length of key
1264 * @param blob the NTLMv2 "blob"
1265 * @param session generated session nonce, should be freed with heim_ntlm_free_buf().
1266 * @param master calculated session master key, should be freed with heim_ntlm_free_buf().
1268 * @return In case of success 0 is return, an errors, a errno in what
1271 * @ingroup ntlm_core
1276 heim_ntlm_build_ntlm2_master(void *key
, size_t len
,
1277 struct ntlm_buf
*blob
,
1278 struct ntlm_buf
*session
,
1279 struct ntlm_buf
*master
)
1281 struct ntlm_buf sess
;
1284 ret
= heim_ntlm_v2_base_session(key
, len
, blob
, &sess
);
1288 ret
= heim_ntlm_keyex_wrap(&sess
, session
, master
);
1289 heim_ntlm_free_buf(&sess
);
1295 * Given a key and encrypted session, unwrap the session key
1297 * @param baseKey the sessionBaseKey
1298 * @param encryptedSession encrypted session, type3.session field.
1299 * @param session generated session nonce, should be freed with heim_ntlm_free_buf().
1301 * @return In case of success 0 is return, an errors, a errno in what
1304 * @ingroup ntlm_core
1308 heim_ntlm_keyex_unwrap(struct ntlm_buf
*baseKey
,
1309 struct ntlm_buf
*encryptedSession
,
1310 struct ntlm_buf
*session
)
1314 memset(session
, 0, sizeof(*session
));
1316 if (baseKey
->length
!= MD4_DIGEST_LENGTH
)
1317 return HNTLM_ERR_INVALID_LENGTH
;
1319 session
->length
= MD4_DIGEST_LENGTH
;
1320 session
->data
= malloc(session
->length
);
1321 if (session
->data
== NULL
) {
1322 session
->length
= 0;
1325 EVP_CIPHER_CTX_init(&c
);
1327 if (EVP_CipherInit_ex(&c
, EVP_rc4(), NULL
, baseKey
->data
, NULL
, 0) != 1) {
1328 EVP_CIPHER_CTX_cleanup(&c
);
1329 heim_ntlm_free_buf(session
);
1330 return HNTLM_ERR_CRYPTO
;
1333 EVP_Cipher(&c
, session
->data
, encryptedSession
->data
, session
->length
);
1334 EVP_CIPHER_CTX_cleanup(&c
);
1341 * Generates an NTLMv2 session key.
1343 * @param key the ntlm key
1344 * @param len length of key
1345 * @param username name of the user, as sent in the message, assumed to be in UTF8.
1346 * @param target the name of the target, assumed to be in UTF8.
1347 * @param ntlmv2 the ntlmv2 session key
1349 * @return 0 on success, or an error code on failure.
1351 * @ingroup ntlm_core
1355 heim_ntlm_ntlmv2_key(const void *key
, size_t len
,
1356 const char *username
,
1358 unsigned char ntlmv2
[16])
1361 unsigned int hmaclen
;
1365 HMAC_Init_ex(&c
, key
, len
, EVP_md5(), NULL
);
1367 struct ntlm_buf buf
;
1368 /* uppercase username and turn it into ucs2-le */
1369 ret
= ascii2ucs2le(username
, 1, &buf
);
1372 HMAC_Update(&c
, buf
.data
, buf
.length
);
1374 /* uppercase target and turn into ucs2-le */
1375 ret
= ascii2ucs2le(target
, 1, &buf
);
1378 HMAC_Update(&c
, buf
.data
, buf
.length
);
1381 HMAC_Final(&c
, ntlmv2
, &hmaclen
);
1383 HMAC_CTX_cleanup(&c
);
1392 #define NTTIME_EPOCH 0x019DB1DED53E8000LL
1395 unix2nttime(time_t unix_time
)
1398 wt
= unix_time
* (uint64_t)10000000 + (uint64_t)NTTIME_EPOCH
;
1403 nt2unixtime(uint64_t t
)
1405 t
= ((t
- (uint64_t)NTTIME_EPOCH
) / (uint64_t)10000000);
1406 if (t
> (((uint64_t)(time_t)(~(uint64_t)0)) >> 1))
1412 * Calculate LMv2 response
1414 * @param key the ntlm key
1415 * @param len length of key
1416 * @param username name of the user, as sent in the message, assumed to be in UTF8.
1417 * @param target the name of the target, assumed to be in UTF8.
1418 * @param serverchallenge challenge as sent by the server in the type2 message.
1419 * @param ntlmv2 calculated session key
1420 * @param answer ntlm response answer, should be freed with heim_ntlm_free_buf().
1422 * @return In case of success 0 is return, an errors, a errno in what
1425 * @ingroup ntlm_core
1429 heim_ntlm_calculate_lm2(const void *key
, size_t len
,
1430 const char *username
,
1432 const unsigned char serverchallenge
[8],
1433 unsigned char ntlmv2
[16],
1434 struct ntlm_buf
*answer
)
1436 unsigned char clientchallenge
[8];
1438 if (RAND_bytes(clientchallenge
, sizeof(clientchallenge
)) != 1)
1439 return HNTLM_ERR_RAND
;
1441 /* calculate ntlmv2 key */
1443 heim_ntlm_ntlmv2_key(key
, len
, username
, target
, ntlmv2
);
1445 answer
->data
= malloc(24);
1446 if (answer
->data
== NULL
)
1448 answer
->length
= 24;
1450 heim_ntlm_derive_ntlm2_sess(ntlmv2
, clientchallenge
, 8,
1451 serverchallenge
, answer
->data
);
1453 memcpy(((uint8_t *)answer
->data
) + 16, clientchallenge
, 8);
1460 * Calculate NTLMv2 response
1462 * @param key the ntlm key
1463 * @param len length of key
1464 * @param username name of the user, as sent in the message, assumed to be in UTF8.
1465 * @param target the name of the target, assumed to be in UTF8.
1466 * @param serverchallenge challenge as sent by the server in the type2 message.
1467 * @param infotarget infotarget as sent by the server in the type2 message.
1468 * @param ntlmv2 calculated session key
1469 * @param answer ntlm response answer, should be freed with heim_ntlm_free_buf().
1471 * @return In case of success 0 is return, an errors, a errno in what
1474 * @ingroup ntlm_core
1478 heim_ntlm_calculate_ntlm2(const void *key
, size_t len
,
1479 const char *username
,
1481 const unsigned char serverchallenge
[8],
1482 const struct ntlm_buf
*infotarget
,
1483 unsigned char ntlmv2
[16],
1484 struct ntlm_buf
*answer
)
1486 krb5_error_code ret
;
1488 unsigned char ntlmv2answer
[16];
1490 unsigned char clientchallenge
[8];
1493 t
= unix2nttime(time(NULL
));
1495 if (RAND_bytes(clientchallenge
, sizeof(clientchallenge
)) != 1)
1496 return HNTLM_ERR_RAND
;
1498 /* calculate ntlmv2 key */
1500 heim_ntlm_ntlmv2_key(key
, len
, username
, target
, ntlmv2
);
1502 /* calculate and build ntlmv2 answer */
1504 sp
= krb5_storage_emem();
1507 krb5_storage_set_flags(sp
, KRB5_STORAGE_BYTEORDER_LE
);
1509 CHECK(krb5_store_uint32(sp
, 0x00000101), 0);
1510 CHECK(krb5_store_uint32(sp
, 0), 0);
1511 /* timestamp le 64 bit ts */
1512 CHECK(krb5_store_uint32(sp
, t
& 0xffffffff), 0);
1513 CHECK(krb5_store_uint32(sp
, t
>> 32), 0);
1515 CHECK(krb5_storage_write(sp
, clientchallenge
, 8), 8);
1517 CHECK(krb5_store_uint32(sp
, 0), 0); /* unknown but zero will work */
1518 CHECK(krb5_storage_write(sp
, infotarget
->data
, infotarget
->length
),
1519 infotarget
->length
);
1520 CHECK(krb5_store_uint32(sp
, 0), 0); /* unknown but zero will work */
1522 CHECK(krb5_storage_to_data(sp
, &data
), 0);
1523 krb5_storage_free(sp
);
1526 heim_ntlm_derive_ntlm2_sess(ntlmv2
, data
.data
, data
.length
, serverchallenge
, ntlmv2answer
);
1528 sp
= krb5_storage_emem();
1530 krb5_data_free(&data
);
1534 CHECK(krb5_storage_write(sp
, ntlmv2answer
, 16), 16);
1535 CHECK(krb5_storage_write(sp
, data
.data
, data
.length
), data
.length
);
1536 krb5_data_free(&data
);
1538 CHECK(krb5_storage_to_data(sp
, &data
), 0);
1539 krb5_storage_free(sp
);
1542 answer
->data
= data
.data
;
1543 answer
->length
= data
.length
;
1548 krb5_storage_free(sp
);
1552 static const int authtimediff
= 3600 * 2; /* 2 hours */
1555 * Verify NTLMv2 response.
1557 * @param key the ntlm key
1558 * @param len length of key
1559 * @param username name of the user, as sent in the message, assumed to be in UTF8.
1560 * @param target the name of the target, assumed to be in UTF8.
1561 * @param now the time now (0 if the library should pick it up itself)
1562 * @param serverchallenge challenge as sent by the server in the type2 message.
1563 * @param answer ntlm response answer, should be freed with heim_ntlm_free_buf().
1564 * @param infotarget infotarget as sent by the server in the type2 message.
1565 * @param ntlmv2 calculated session key
1567 * @return In case of success 0 is return, an errors, a errno in what
1570 * @ingroup ntlm_core
1574 heim_ntlm_verify_ntlm2(const void *key
, size_t len
,
1575 const char *username
,
1578 const unsigned char serverchallenge
[8],
1579 const struct ntlm_buf
*answer
,
1580 struct ntlm_buf
*infotarget
,
1581 unsigned char ntlmv2
[16])
1583 krb5_error_code ret
;
1584 unsigned char clientanswer
[16];
1585 unsigned char clientnonce
[8];
1586 unsigned char serveranswer
[16];
1592 infotarget
->length
= 0;
1593 infotarget
->data
= NULL
;
1595 if (answer
->length
< 16)
1596 return HNTLM_ERR_INVALID_LENGTH
;
1601 /* calculate ntlmv2 key */
1603 heim_ntlm_ntlmv2_key(key
, len
, username
, target
, ntlmv2
);
1605 /* calculate and build ntlmv2 answer */
1607 sp
= krb5_storage_from_readonly_mem(answer
->data
, answer
->length
);
1610 krb5_storage_set_flags(sp
, KRB5_STORAGE_BYTEORDER_LE
);
1612 CHECK(krb5_storage_read(sp
, clientanswer
, 16), 16);
1614 CHECK(krb5_ret_uint32(sp
, &temp
), 0);
1615 CHECK(temp
, 0x00000101);
1616 CHECK(krb5_ret_uint32(sp
, &temp
), 0);
1618 /* timestamp le 64 bit ts */
1619 CHECK(krb5_ret_uint32(sp
, &temp
), 0);
1621 CHECK(krb5_ret_uint32(sp
, &temp
), 0);
1622 t
|= ((uint64_t)temp
)<< 32;
1624 authtime
= nt2unixtime(t
);
1626 if (abs((int)(authtime
- now
)) > authtimediff
) {
1627 ret
= HNTLM_ERR_TIME_SKEW
;
1631 /* client challenge */
1632 CHECK(krb5_storage_read(sp
, clientnonce
, 8), 8);
1634 CHECK(krb5_ret_uint32(sp
, &temp
), 0); /* unknown */
1636 /* should really unparse the infotarget, but lets pick up everything */
1637 infotarget
->length
= answer
->length
- krb5_storage_seek(sp
, 0, SEEK_CUR
);
1638 infotarget
->data
= malloc(infotarget
->length
);
1639 if (infotarget
->data
== NULL
) {
1643 CHECK(krb5_storage_read(sp
, infotarget
->data
, infotarget
->length
),
1644 infotarget
->length
);
1645 /* XXX remove the unknown ?? */
1646 krb5_storage_free(sp
);
1649 if (answer
->length
< 16) {
1650 ret
= HNTLM_ERR_INVALID_LENGTH
;
1654 heim_ntlm_derive_ntlm2_sess(ntlmv2
,
1655 ((unsigned char *)answer
->data
) + 16, answer
->length
- 16,
1659 if (memcmp(serveranswer
, clientanswer
, 16) != 0) {
1660 heim_ntlm_free_buf(infotarget
);
1661 return HNTLM_ERR_AUTH
;
1666 heim_ntlm_free_buf(infotarget
);
1668 krb5_storage_free(sp
);
1674 * Calculate the NTLM2 Session Response
1676 * @param clnt_nonce client nonce
1677 * @param svr_chal server challage
1678 * @param ntlm2_hash ntlm hash
1679 * @param lm The LM response, should be freed with heim_ntlm_free_buf().
1680 * @param ntlm The NTLM response, should be freed with heim_ntlm_free_buf().
1682 * @return In case of success 0 is return, an errors, a errno in what
1685 * @ingroup ntlm_core
1689 heim_ntlm_calculate_ntlm2_sess(const unsigned char clnt_nonce
[8],
1690 const unsigned char svr_chal
[8],
1691 const unsigned char ntlm_hash
[16],
1692 struct ntlm_buf
*lm
,
1693 struct ntlm_buf
*ntlm
)
1695 unsigned char ntlm2_sess_hash
[8];
1696 unsigned char res
[21], *resp
;
1699 code
= heim_ntlm_calculate_ntlm2_sess_hash(clnt_nonce
, svr_chal
,
1705 lm
->data
= malloc(24);
1706 if (lm
->data
== NULL
) {
1711 ntlm
->data
= malloc(24);
1712 if (ntlm
->data
== NULL
) {
1719 /* first setup the lm resp */
1720 memset(lm
->data
, 0, 24);
1721 memcpy(lm
->data
, clnt_nonce
, 8);
1723 memset(res
, 0, sizeof(res
));
1724 memcpy(res
, ntlm_hash
, 16);
1727 splitandenc(&res
[0], ntlm2_sess_hash
, resp
+ 0);
1728 splitandenc(&res
[7], ntlm2_sess_hash
, resp
+ 8);
1729 splitandenc(&res
[14], ntlm2_sess_hash
, resp
+ 16);
1736 * Calculate the NTLM2 Session "Verifier"
1738 * @param clnt_nonce client nonce
1739 * @param svr_chal server challage
1740 * @param hash The NTLM session verifier
1742 * @return In case of success 0 is return, an errors, a errno in what
1745 * @ingroup ntlm_core
1749 heim_ntlm_calculate_ntlm2_sess_hash(const unsigned char clnt_nonce
[8],
1750 const unsigned char svr_chal
[8],
1751 unsigned char verifier
[8])
1753 unsigned char ntlm2_sess_hash
[MD5_DIGEST_LENGTH
];
1756 m
= EVP_MD_CTX_create();
1760 EVP_DigestInit_ex(m
, EVP_md5(), NULL
);
1761 EVP_DigestUpdate(m
, svr_chal
, 8); /* session nonce part 1 */
1762 EVP_DigestUpdate(m
, clnt_nonce
, 8); /* session nonce part 2 */
1763 EVP_DigestFinal_ex(m
, ntlm2_sess_hash
, NULL
); /* will only use first 8 bytes */
1764 EVP_MD_CTX_destroy(m
);
1766 memcpy(verifier
, ntlm2_sess_hash
, 8);
1773 * Derive a NTLM2 session key
1775 * @param sessionkey session key from domain controller
1776 * @param clnt_nonce client nonce
1777 * @param svr_chal server challenge
1778 * @param derivedkey salted session key
1780 * @return In case of success 0 is return, an errors, a errno in what
1783 * @ingroup ntlm_core
1787 heim_ntlm_derive_ntlm2_sess(const unsigned char sessionkey
[16],
1788 const unsigned char *clnt_nonce
, size_t clnt_nonce_length
,
1789 const unsigned char svr_chal
[8],
1790 unsigned char derivedkey
[16])
1792 unsigned int hmaclen
;
1795 /* HMAC(Ksession, serverchallenge || clientchallenge) */
1797 HMAC_Init_ex(&c
, sessionkey
, 16, EVP_md5(), NULL
);
1798 HMAC_Update(&c
, svr_chal
, 8);
1799 HMAC_Update(&c
, clnt_nonce
, clnt_nonce_length
);
1800 HMAC_Final(&c
, derivedkey
, &hmaclen
);
1801 HMAC_CTX_cleanup(&c
);