2 * Copyright (c) 2006 - 2007 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the Institute nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 __RCSID("$Heimdal: ntlm.c 22370 2007-12-28 16:12:01Z lha $"
50 #include "krb5-types.h"
51 #include "crypto-headers.h"
55 /*! \mainpage Heimdal NTLM library
57 * \section intro Introduction
59 * Heimdal libheimntlm library is a implementation of the NTLM
60 * protocol, both version 1 and 2. The GSS-API mech that uses this
61 * library adds support for transport encryption and integrity
64 * NTLM is a protocol for mutual authentication, its still used in
65 * many protocol where Kerberos is not support, one example is
66 * EAP/X802.1x mechanism LEAP from Microsoft and Cisco.
68 * This is a support library for the core protocol, its used in
69 * Heimdal to implement and GSS-API mechanism. There is also support
70 * in the KDC to do remote digest authenticiation, this to allow
71 * services to authenticate users w/o direct access to the users ntlm
72 * hashes (same as Kerberos arcfour enctype hashes).
74 * More information about the NTLM protocol can found here
75 * http://davenport.sourceforge.net/ntlm.html .
77 * The Heimdal projects web page: http://www.h5l.org/
80 /** @defgroup ntlm_core Heimdal NTLM library
82 * The NTLM core functions implement the string2key generation
83 * function, message encode and decode function, and the hash function
93 static const unsigned char ntlmsigature
[8] = "NTLMSSP\x00";
100 do { ret = f ; if (ret != (e)) { ret = EINVAL; goto out; } } while(0)
103 * heim_ntlm_free_buf frees the ntlm buffer
105 * @param p buffer to be freed
111 heim_ntlm_free_buf(struct ntlm_buf
*p
)
121 ascii2ucs2le(const char *string
, int up
, struct ntlm_buf
*buf
)
126 len
= strlen(string
);
127 if (len
/ 2 > UINT_MAX
)
130 buf
->length
= len
* 2;
131 buf
->data
= malloc(buf
->length
);
132 if (buf
->data
== NULL
&& len
!= 0) {
133 heim_ntlm_free_buf(buf
);
138 for (i
= 0; i
< len
; i
++) {
139 unsigned char t
= (unsigned char)string
[i
];
141 heim_ntlm_free_buf(buf
);
156 static krb5_error_code
157 ret_sec_buffer(krb5_storage
*sp
, struct sec_buffer
*buf
)
160 CHECK(krb5_ret_uint16(sp
, &buf
->length
), 0);
161 CHECK(krb5_ret_uint16(sp
, &buf
->allocated
), 0);
162 CHECK(krb5_ret_uint32(sp
, &buf
->offset
), 0);
167 static krb5_error_code
168 store_sec_buffer(krb5_storage
*sp
, const struct sec_buffer
*buf
)
171 CHECK(krb5_store_uint16(sp
, buf
->length
), 0);
172 CHECK(krb5_store_uint16(sp
, buf
->allocated
), 0);
173 CHECK(krb5_store_uint32(sp
, buf
->offset
), 0);
179 * Strings are either OEM or UNICODE. The later is encoded as ucs2 on
180 * wire, but using utf8 in memory.
183 static krb5_error_code
184 len_string(int ucs2
, const char *s
)
186 size_t len
= strlen(s
);
192 static krb5_error_code
193 ret_string(krb5_storage
*sp
, int ucs2
, struct sec_buffer
*desc
, char **s
)
197 *s
= malloc(desc
->length
+ 1);
198 CHECK(krb5_storage_seek(sp
, desc
->offset
, SEEK_SET
), desc
->offset
);
199 CHECK(krb5_storage_read(sp
, *s
, desc
->length
), desc
->length
);
200 (*s
)[desc
->length
] = '\0';
204 for (i
= 0; i
< desc
->length
/ 2; i
++) {
205 (*s
)[i
] = (*s
)[i
* 2];
206 if ((*s
)[i
* 2 + 1]) {
221 static krb5_error_code
222 put_string(krb5_storage
*sp
, int ucs2
, const char *s
)
228 ret
= ascii2ucs2le(s
, 0, &buf
);
232 buf
.data
= rk_UNCONST(s
);
233 buf
.length
= strlen(s
);
236 CHECK(krb5_storage_write(sp
, buf
.data
, buf
.length
), buf
.length
);
238 heim_ntlm_free_buf(&buf
);
248 static krb5_error_code
249 ret_buf(krb5_storage
*sp
, struct sec_buffer
*desc
, struct ntlm_buf
*buf
)
253 buf
->data
= malloc(desc
->length
);
254 buf
->length
= desc
->length
;
255 CHECK(krb5_storage_seek(sp
, desc
->offset
, SEEK_SET
), desc
->offset
);
256 CHECK(krb5_storage_read(sp
, buf
->data
, buf
->length
), buf
->length
);
262 static krb5_error_code
263 put_buf(krb5_storage
*sp
, const struct ntlm_buf
*buf
)
266 CHECK(krb5_storage_write(sp
, buf
->data
, buf
->length
), buf
->length
);
273 * Frees the ntlm_targetinfo message
275 * @param ti targetinfo to be freed
281 heim_ntlm_free_targetinfo(struct ntlm_targetinfo
*ti
)
283 free(ti
->servername
);
284 free(ti
->domainname
);
285 free(ti
->dnsdomainname
);
286 free(ti
->dnsservername
);
287 memset(ti
, 0, sizeof(*ti
));
291 encode_ti_blob(krb5_storage
*out
, uint16_t type
, int ucs2
, char *s
)
294 CHECK(krb5_store_uint16(out
, type
), 0);
295 CHECK(krb5_store_uint16(out
, len_string(ucs2
, s
)), 0);
296 CHECK(put_string(out
, ucs2
, s
), 0);
302 * Encodes a ntlm_targetinfo message.
304 * @param ti the ntlm_targetinfo message to encode.
305 * @param ucs2 if the strings should be encoded with ucs2 (selected by flag in message).
306 * @param data is the return buffer with the encoded message, should be
307 * freed with heim_ntlm_free_buf().
309 * @return In case of success 0 is return, an errors, a errno in what
316 heim_ntlm_encode_targetinfo(const struct ntlm_targetinfo
*ti
,
318 struct ntlm_buf
*data
)
326 out
= krb5_storage_emem();
331 CHECK(encode_ti_blob(out
, 1, ucs2
, ti
->servername
), 0);
333 CHECK(encode_ti_blob(out
, 2, ucs2
, ti
->domainname
), 0);
334 if (ti
->dnsservername
)
335 CHECK(encode_ti_blob(out
, 3, ucs2
, ti
->dnsservername
), 0);
336 if (ti
->dnsdomainname
)
337 CHECK(encode_ti_blob(out
, 4, ucs2
, ti
->dnsdomainname
), 0);
340 CHECK(krb5_store_int16(out
, 0), 0);
341 CHECK(krb5_store_int16(out
, 0), 0);
345 ret
= krb5_storage_to_data(out
, &d
);
347 data
->length
= d
.length
;
350 krb5_storage_free(out
);
355 * Decodes an NTLM targetinfo message
357 * @param data input data buffer with the encode NTLM targetinfo message
358 * @param ucs2 if the strings should be encoded with ucs2 (selected by flag in message).
359 * @param ti the decoded target info, should be freed with heim_ntlm_free_targetinfo().
361 * @return In case of success 0 is return, an errors, a errno in what
368 heim_ntlm_decode_targetinfo(const struct ntlm_buf
*data
,
370 struct ntlm_targetinfo
*ti
)
372 memset(ti
, 0, sizeof(*ti
));
377 * Frees the ntlm_type1 message
379 * @param data message to be freed
385 heim_ntlm_free_type1(struct ntlm_type1
*data
)
390 free(data
->hostname
);
391 memset(data
, 0, sizeof(*data
));
395 heim_ntlm_decode_type1(const struct ntlm_buf
*buf
, struct ntlm_type1
*data
)
398 unsigned char sig
[8];
400 struct sec_buffer domain
, hostname
;
403 memset(data
, 0, sizeof(*data
));
405 in
= krb5_storage_from_readonly_mem(buf
->data
, buf
->length
);
410 krb5_storage_set_byteorder(in
, KRB5_STORAGE_BYTEORDER_LE
);
412 CHECK(krb5_storage_read(in
, sig
, sizeof(sig
)), sizeof(sig
));
413 CHECK(memcmp(ntlmsigature
, sig
, sizeof(ntlmsigature
)), 0);
414 CHECK(krb5_ret_uint32(in
, &type
), 0);
416 CHECK(krb5_ret_uint32(in
, &data
->flags
), 0);
417 if (data
->flags
& NTLM_SUPPLIED_DOMAIN
)
418 CHECK(ret_sec_buffer(in
, &domain
), 0);
419 if (data
->flags
& NTLM_SUPPLIED_WORKSTAION
)
420 CHECK(ret_sec_buffer(in
, &hostname
), 0);
422 if (domain
.offset
> 32) {
423 CHECK(krb5_ret_uint32(in
, &data
->os
[0]), 0);
424 CHECK(krb5_ret_uint32(in
, &data
->os
[1]), 0);
427 if (data
->flags
& NTLM_SUPPLIED_DOMAIN
)
428 CHECK(ret_string(in
, 0, &domain
, &data
->domain
), 0);
429 if (data
->flags
& NTLM_SUPPLIED_WORKSTAION
)
430 CHECK(ret_string(in
, 0, &hostname
, &data
->hostname
), 0);
433 krb5_storage_free(in
);
435 heim_ntlm_free_type1(data
);
441 * Encodes an ntlm_type1 message.
443 * @param type1 the ntlm_type1 message to encode.
444 * @param data is the return buffer with the encoded message, should be
445 * freed with heim_ntlm_free_buf().
447 * @return In case of success 0 is return, an errors, a errno in what
454 heim_ntlm_encode_type1(const struct ntlm_type1
*type1
, struct ntlm_buf
*data
)
457 struct sec_buffer domain
, hostname
;
459 uint32_t base
, flags
;
461 flags
= type1
->flags
;
466 flags
|= NTLM_SUPPLIED_DOMAIN
;
468 if (type1
->hostname
) {
470 flags
|= NTLM_SUPPLIED_WORKSTAION
;
476 domain
.offset
= base
;
477 domain
.length
= len_string(0, type1
->domain
);
478 domain
.allocated
= domain
.length
;
480 if (type1
->hostname
) {
481 hostname
.offset
= domain
.allocated
+ domain
.offset
;
482 hostname
.length
= len_string(0, type1
->hostname
);
483 hostname
.allocated
= hostname
.length
;
486 out
= krb5_storage_emem();
490 krb5_storage_set_byteorder(out
, KRB5_STORAGE_BYTEORDER_LE
);
491 CHECK(krb5_storage_write(out
, ntlmsigature
, sizeof(ntlmsigature
)),
492 sizeof(ntlmsigature
));
493 CHECK(krb5_store_uint32(out
, 1), 0);
494 CHECK(krb5_store_uint32(out
, flags
), 0);
497 CHECK(store_sec_buffer(out
, &domain
), 0);
499 CHECK(store_sec_buffer(out
, &hostname
), 0);
501 CHECK(krb5_store_uint32(out
, type1
->os
[0]), 0);
502 CHECK(krb5_store_uint32(out
, type1
->os
[1]), 0);
505 CHECK(put_string(out
, 0, type1
->domain
), 0);
507 CHECK(put_string(out
, 0, type1
->hostname
), 0);
511 ret
= krb5_storage_to_data(out
, &d
);
513 data
->length
= d
.length
;
516 krb5_storage_free(out
);
522 * Frees the ntlm_type2 message
524 * @param data message to be freed
530 heim_ntlm_free_type2(struct ntlm_type2
*data
)
532 if (data
->targetname
)
533 free(data
->targetname
);
534 heim_ntlm_free_buf(&data
->targetinfo
);
535 memset(data
, 0, sizeof(*data
));
539 heim_ntlm_decode_type2(const struct ntlm_buf
*buf
, struct ntlm_type2
*type2
)
542 unsigned char sig
[8];
543 uint32_t type
, ctx
[2];
544 struct sec_buffer targetname
, targetinfo
;
548 memset(type2
, 0, sizeof(*type2
));
550 in
= krb5_storage_from_readonly_mem(buf
->data
, buf
->length
);
555 krb5_storage_set_byteorder(in
, KRB5_STORAGE_BYTEORDER_LE
);
557 CHECK(krb5_storage_read(in
, sig
, sizeof(sig
)), sizeof(sig
));
558 CHECK(memcmp(ntlmsigature
, sig
, sizeof(ntlmsigature
)), 0);
559 CHECK(krb5_ret_uint32(in
, &type
), 0);
562 CHECK(ret_sec_buffer(in
, &targetname
), 0);
563 CHECK(krb5_ret_uint32(in
, &type2
->flags
), 0);
564 if (type2
->flags
& NTLM_NEG_UNICODE
)
566 CHECK(krb5_storage_read(in
, type2
->challange
, sizeof(type2
->challange
)),
567 sizeof(type2
->challange
));
568 CHECK(krb5_ret_uint32(in
, &ctx
[0]), 0); /* context */
569 CHECK(krb5_ret_uint32(in
, &ctx
[1]), 0);
570 CHECK(ret_sec_buffer(in
, &targetinfo
), 0);
573 CHECK(krb5_ret_uint32(in
, &type2
->os
[0]), 0);
574 CHECK(krb5_ret_uint32(in
, &type2
->os
[1]), 0);
577 CHECK(ret_string(in
, ucs2
, &targetname
, &type2
->targetname
), 0);
578 CHECK(ret_buf(in
, &targetinfo
, &type2
->targetinfo
), 0);
582 krb5_storage_free(in
);
584 heim_ntlm_free_type2(type2
);
590 * Encodes an ntlm_type2 message.
592 * @param type2 the ntlm_type2 message to encode.
593 * @param data is the return buffer with the encoded message, should be
594 * freed with heim_ntlm_free_buf().
596 * @return In case of success 0 is return, an errors, a errno in what
603 heim_ntlm_encode_type2(const struct ntlm_type2
*type2
, struct ntlm_buf
*data
)
605 struct sec_buffer targetname
, targetinfo
;
607 krb5_storage
*out
= NULL
;
616 if (type2
->flags
& NTLM_NEG_UNICODE
)
619 targetname
.offset
= base
;
620 targetname
.length
= len_string(ucs2
, type2
->targetname
);
621 targetname
.allocated
= targetname
.length
;
623 targetinfo
.offset
= targetname
.allocated
+ targetname
.offset
;
624 targetinfo
.length
= type2
->targetinfo
.length
;
625 targetinfo
.allocated
= type2
->targetinfo
.length
;
627 out
= krb5_storage_emem();
631 krb5_storage_set_byteorder(out
, KRB5_STORAGE_BYTEORDER_LE
);
632 CHECK(krb5_storage_write(out
, ntlmsigature
, sizeof(ntlmsigature
)),
633 sizeof(ntlmsigature
));
634 CHECK(krb5_store_uint32(out
, 2), 0);
635 CHECK(store_sec_buffer(out
, &targetname
), 0);
636 CHECK(krb5_store_uint32(out
, type2
->flags
), 0);
637 CHECK(krb5_storage_write(out
, type2
->challange
, sizeof(type2
->challange
)),
638 sizeof(type2
->challange
));
639 CHECK(krb5_store_uint32(out
, 0), 0); /* context */
640 CHECK(krb5_store_uint32(out
, 0), 0);
641 CHECK(store_sec_buffer(out
, &targetinfo
), 0);
644 CHECK(krb5_store_uint32(out
, type2
->os
[0]), 0);
645 CHECK(krb5_store_uint32(out
, type2
->os
[1]), 0);
647 CHECK(put_string(out
, ucs2
, type2
->targetname
), 0);
648 CHECK(krb5_storage_write(out
, type2
->targetinfo
.data
,
649 type2
->targetinfo
.length
),
650 type2
->targetinfo
.length
);
654 ret
= krb5_storage_to_data(out
, &d
);
656 data
->length
= d
.length
;
660 krb5_storage_free(out
);
666 * Frees the ntlm_type3 message
668 * @param data message to be freed
674 heim_ntlm_free_type3(struct ntlm_type3
*data
)
676 heim_ntlm_free_buf(&data
->lm
);
677 heim_ntlm_free_buf(&data
->ntlm
);
678 if (data
->targetname
)
679 free(data
->targetname
);
681 free(data
->username
);
684 heim_ntlm_free_buf(&data
->sessionkey
);
685 memset(data
, 0, sizeof(*data
));
693 heim_ntlm_decode_type3(const struct ntlm_buf
*buf
,
695 struct ntlm_type3
*type3
)
698 unsigned char sig
[8];
701 struct sec_buffer lm
, ntlm
, target
, username
, sessionkey
, ws
;
703 memset(type3
, 0, sizeof(*type3
));
704 memset(&sessionkey
, 0, sizeof(sessionkey
));
706 in
= krb5_storage_from_readonly_mem(buf
->data
, buf
->length
);
711 krb5_storage_set_byteorder(in
, KRB5_STORAGE_BYTEORDER_LE
);
713 CHECK(krb5_storage_read(in
, sig
, sizeof(sig
)), sizeof(sig
));
714 CHECK(memcmp(ntlmsigature
, sig
, sizeof(ntlmsigature
)), 0);
715 CHECK(krb5_ret_uint32(in
, &type
), 0);
717 CHECK(ret_sec_buffer(in
, &lm
), 0);
718 CHECK(ret_sec_buffer(in
, &ntlm
), 0);
719 CHECK(ret_sec_buffer(in
, &target
), 0);
720 CHECK(ret_sec_buffer(in
, &username
), 0);
721 CHECK(ret_sec_buffer(in
, &ws
), 0);
722 if (lm
.offset
>= 60) {
723 CHECK(ret_sec_buffer(in
, &sessionkey
), 0);
725 if (lm
.offset
>= 64) {
726 CHECK(krb5_ret_uint32(in
, &type3
->flags
), 0);
728 if (lm
.offset
>= 72) {
729 CHECK(krb5_ret_uint32(in
, &type3
->os
[0]), 0);
730 CHECK(krb5_ret_uint32(in
, &type3
->os
[1]), 0);
732 CHECK(ret_buf(in
, &lm
, &type3
->lm
), 0);
733 CHECK(ret_buf(in
, &ntlm
, &type3
->ntlm
), 0);
734 CHECK(ret_string(in
, ucs2
, &target
, &type3
->targetname
), 0);
735 CHECK(ret_string(in
, ucs2
, &username
, &type3
->username
), 0);
736 CHECK(ret_string(in
, ucs2
, &ws
, &type3
->ws
), 0);
737 if (sessionkey
.offset
)
738 CHECK(ret_buf(in
, &sessionkey
, &type3
->sessionkey
), 0);
741 krb5_storage_free(in
);
743 heim_ntlm_free_type3(type3
);
749 * Encodes an ntlm_type3 message.
751 * @param type3 the ntlm_type3 message to encode.
752 * @param data is the return buffer with the encoded message, should be
753 * freed with heim_ntlm_free_buf().
755 * @return In case of success 0 is return, an errors, a errno in what
762 heim_ntlm_encode_type3(const struct ntlm_type3
*type3
, struct ntlm_buf
*data
)
764 struct sec_buffer lm
, ntlm
, target
, username
, sessionkey
, ws
;
766 krb5_storage
*out
= NULL
;
770 memset(&lm
, 0, sizeof(lm
));
771 memset(&ntlm
, 0, sizeof(ntlm
));
772 memset(&target
, 0, sizeof(target
));
773 memset(&username
, 0, sizeof(username
));
774 memset(&ws
, 0, sizeof(ws
));
775 memset(&sessionkey
, 0, sizeof(sessionkey
));
778 if (type3
->sessionkey
.length
) {
779 base
+= 8; /* sessionkey sec buf */
780 base
+= 4; /* flags */
786 if (type3
->flags
& NTLM_NEG_UNICODE
)
790 lm
.length
= type3
->lm
.length
;
791 lm
.allocated
= type3
->lm
.length
;
793 ntlm
.offset
= lm
.offset
+ lm
.allocated
;
794 ntlm
.length
= type3
->ntlm
.length
;
795 ntlm
.allocated
= ntlm
.length
;
797 target
.offset
= ntlm
.offset
+ ntlm
.allocated
;
798 target
.length
= len_string(ucs2
, type3
->targetname
);
799 target
.allocated
= target
.length
;
801 username
.offset
= target
.offset
+ target
.allocated
;
802 username
.length
= len_string(ucs2
, type3
->username
);
803 username
.allocated
= username
.length
;
805 ws
.offset
= username
.offset
+ username
.allocated
;
806 ws
.length
= len_string(ucs2
, type3
->ws
);
807 ws
.allocated
= ws
.length
;
809 sessionkey
.offset
= ws
.offset
+ ws
.allocated
;
810 sessionkey
.length
= type3
->sessionkey
.length
;
811 sessionkey
.allocated
= type3
->sessionkey
.length
;
813 out
= krb5_storage_emem();
817 krb5_storage_set_byteorder(out
, KRB5_STORAGE_BYTEORDER_LE
);
818 CHECK(krb5_storage_write(out
, ntlmsigature
, sizeof(ntlmsigature
)),
819 sizeof(ntlmsigature
));
820 CHECK(krb5_store_uint32(out
, 3), 0);
822 CHECK(store_sec_buffer(out
, &lm
), 0);
823 CHECK(store_sec_buffer(out
, &ntlm
), 0);
824 CHECK(store_sec_buffer(out
, &target
), 0);
825 CHECK(store_sec_buffer(out
, &username
), 0);
826 CHECK(store_sec_buffer(out
, &ws
), 0);
828 if (type3
->sessionkey
.length
) {
829 CHECK(store_sec_buffer(out
, &sessionkey
), 0);
830 CHECK(krb5_store_uint32(out
, type3
->flags
), 0);
833 CHECK(krb5_store_uint32(out
, 0), 0); /* os0 */
834 CHECK(krb5_store_uint32(out
, 0), 0); /* os1 */
837 CHECK(put_buf(out
, &type3
->lm
), 0);
838 CHECK(put_buf(out
, &type3
->ntlm
), 0);
839 CHECK(put_string(out
, ucs2
, type3
->targetname
), 0);
840 CHECK(put_string(out
, ucs2
, type3
->username
), 0);
841 CHECK(put_string(out
, ucs2
, type3
->ws
), 0);
842 CHECK(put_buf(out
, &type3
->sessionkey
), 0);
846 ret
= krb5_storage_to_data(out
, &d
);
848 data
->length
= d
.length
;
852 krb5_storage_free(out
);
863 splitandenc(unsigned char *hash
,
864 unsigned char *challange
,
865 unsigned char *answer
)
868 DES_key_schedule sched
;
870 ((unsigned char*)key
)[0] = hash
[0];
871 ((unsigned char*)key
)[1] = (hash
[0] << 7) | (hash
[1] >> 1);
872 ((unsigned char*)key
)[2] = (hash
[1] << 6) | (hash
[2] >> 2);
873 ((unsigned char*)key
)[3] = (hash
[2] << 5) | (hash
[3] >> 3);
874 ((unsigned char*)key
)[4] = (hash
[3] << 4) | (hash
[4] >> 4);
875 ((unsigned char*)key
)[5] = (hash
[4] << 3) | (hash
[5] >> 5);
876 ((unsigned char*)key
)[6] = (hash
[5] << 2) | (hash
[6] >> 6);
877 ((unsigned char*)key
)[7] = (hash
[6] << 1);
879 DES_set_odd_parity(&key
);
880 DES_set_key(&key
, &sched
);
881 DES_ecb_encrypt((DES_cblock
*)challange
, (DES_cblock
*)answer
, &sched
, 1);
882 memset(&sched
, 0, sizeof(sched
));
883 memset(key
, 0, sizeof(key
));
887 * Calculate the NTLM key, the password is assumed to be in UTF8.
889 * @param password password to calcute the key for.
890 * @param key calcuted key, should be freed with heim_ntlm_free_buf().
892 * @return In case of success 0 is return, an errors, a errno in what
899 heim_ntlm_nt_key(const char *password
, struct ntlm_buf
*key
)
905 key
->data
= malloc(MD5_DIGEST_LENGTH
);
906 if (key
->data
== NULL
)
908 key
->length
= MD5_DIGEST_LENGTH
;
910 ret
= ascii2ucs2le(password
, 0, &buf
);
912 heim_ntlm_free_buf(key
);
916 MD4_Update(&ctx
, buf
.data
, buf
.length
);
917 MD4_Final(key
->data
, &ctx
);
918 heim_ntlm_free_buf(&buf
);
923 * Calculate NTLMv1 response hash
925 * @param key the ntlm v1 key
926 * @param len length of key
927 * @param challange sent by the server
928 * @param answer calculated answer, should be freed with heim_ntlm_free_buf().
930 * @return In case of success 0 is return, an errors, a errno in what
937 heim_ntlm_calculate_ntlm1(void *key
, size_t len
,
938 unsigned char challange
[8],
939 struct ntlm_buf
*answer
)
941 unsigned char res
[21];
943 if (len
!= MD4_DIGEST_LENGTH
)
946 memcpy(res
, key
, len
);
947 memset(&res
[MD4_DIGEST_LENGTH
], 0, sizeof(res
) - MD4_DIGEST_LENGTH
);
949 answer
->data
= malloc(24);
950 if (answer
->data
== NULL
)
954 splitandenc(&res
[0], challange
, ((unsigned char *)answer
->data
) + 0);
955 splitandenc(&res
[7], challange
, ((unsigned char *)answer
->data
) + 8);
956 splitandenc(&res
[14], challange
, ((unsigned char *)answer
->data
) + 16);
962 * Generates an NTLMv1 session random with assosited session master key.
964 * @param key the ntlm v1 key
965 * @param len length of key
966 * @param session generated session nonce, should be freed with heim_ntlm_free_buf().
967 * @param master calculated session master key, should be freed with heim_ntlm_free_buf().
969 * @return In case of success 0 is return, an errors, a errno in what
976 heim_ntlm_build_ntlm1_master(void *key
, size_t len
,
977 struct ntlm_buf
*session
,
978 struct ntlm_buf
*master
)
982 memset(master
, 0, sizeof(*master
));
983 memset(session
, 0, sizeof(*session
));
985 if (len
!= MD4_DIGEST_LENGTH
)
988 session
->length
= MD4_DIGEST_LENGTH
;
989 session
->data
= malloc(session
->length
);
990 if (session
->data
== NULL
) {
994 master
->length
= MD4_DIGEST_LENGTH
;
995 master
->data
= malloc(master
->length
);
996 if (master
->data
== NULL
) {
997 heim_ntlm_free_buf(master
);
998 heim_ntlm_free_buf(session
);
1003 unsigned char sessionkey
[MD4_DIGEST_LENGTH
];
1007 MD4_Update(&ctx
, key
, len
);
1008 MD4_Final(sessionkey
, &ctx
);
1010 RC4_set_key(&rc4
, sizeof(sessionkey
), sessionkey
);
1013 if (RAND_bytes(session
->data
, session
->length
) != 1) {
1014 heim_ntlm_free_buf(master
);
1015 heim_ntlm_free_buf(session
);
1019 RC4(&rc4
, master
->length
, session
->data
, master
->data
);
1020 memset(&rc4
, 0, sizeof(rc4
));
1026 * Generates an NTLMv2 session key.
1028 * @param key the ntlm key
1029 * @param len length of key
1030 * @param username name of the user, as sent in the message, assumed to be in UTF8.
1031 * @param target the name of the target, assumed to be in UTF8.
1032 * @param ntlmv2 the ntlmv2 session key
1034 * @ingroup ntlm_core
1038 heim_ntlm_ntlmv2_key(const void *key
, size_t len
,
1039 const char *username
,
1041 unsigned char ntlmv2
[16])
1043 unsigned int hmaclen
;
1047 HMAC_Init_ex(&c
, key
, len
, EVP_md5(), NULL
);
1049 struct ntlm_buf buf
;
1050 /* uppercase username and turn it inte ucs2-le */
1051 ascii2ucs2le(username
, 1, &buf
);
1052 HMAC_Update(&c
, buf
.data
, buf
.length
);
1054 /* uppercase target and turn into ucs2-le */
1055 ascii2ucs2le(target
, 1, &buf
);
1056 HMAC_Update(&c
, buf
.data
, buf
.length
);
1059 HMAC_Final(&c
, ntlmv2
, &hmaclen
);
1060 HMAC_CTX_cleanup(&c
);
1068 #define NTTIME_EPOCH 0x019DB1DED53E8000LL
1071 unix2nttime(time_t unix_time
)
1074 wt
= unix_time
* (uint64_t)10000000 + (uint64_t)NTTIME_EPOCH
;
1079 nt2unixtime(uint64_t t
)
1081 t
= ((t
- (uint64_t)NTTIME_EPOCH
) / (uint64_t)10000000);
1082 if (t
> (((time_t)(~(uint64_t)0)) >> 1))
1089 * Calculate NTLMv2 response
1091 * @param key the ntlm key
1092 * @param len length of key
1093 * @param username name of the user, as sent in the message, assumed to be in UTF8.
1094 * @param target the name of the target, assumed to be in UTF8.
1095 * @param serverchallange challange as sent by the server in the type2 message.
1096 * @param infotarget infotarget as sent by the server in the type2 message.
1097 * @param ntlmv2 calculated session key
1098 * @param answer ntlm response answer, should be freed with heim_ntlm_free_buf().
1100 * @return In case of success 0 is return, an errors, a errno in what
1103 * @ingroup ntlm_core
1107 heim_ntlm_calculate_ntlm2(const void *key
, size_t len
,
1108 const char *username
,
1110 const unsigned char serverchallange
[8],
1111 const struct ntlm_buf
*infotarget
,
1112 unsigned char ntlmv2
[16],
1113 struct ntlm_buf
*answer
)
1115 krb5_error_code ret
;
1117 unsigned int hmaclen
;
1118 unsigned char ntlmv2answer
[16];
1120 unsigned char clientchallange
[8];
1124 t
= unix2nttime(time(NULL
));
1126 if (RAND_bytes(clientchallange
, sizeof(clientchallange
)) != 1)
1129 /* calculate ntlmv2 key */
1131 heim_ntlm_ntlmv2_key(key
, len
, username
, target
, ntlmv2
);
1133 /* calculate and build ntlmv2 answer */
1135 sp
= krb5_storage_emem();
1138 krb5_storage_set_flags(sp
, KRB5_STORAGE_BYTEORDER_LE
);
1140 CHECK(krb5_store_uint32(sp
, 0x00000101), 0);
1141 CHECK(krb5_store_uint32(sp
, 0), 0);
1142 /* timestamp le 64 bit ts */
1143 CHECK(krb5_store_uint32(sp
, t
& 0xffffffff), 0);
1144 CHECK(krb5_store_uint32(sp
, t
>> 32), 0);
1146 CHECK(krb5_storage_write(sp
, clientchallange
, 8), 8);
1148 CHECK(krb5_store_uint32(sp
, 0), 0); /* unknown but zero will work */
1149 CHECK(krb5_storage_write(sp
, infotarget
->data
, infotarget
->length
),
1150 infotarget
->length
);
1151 CHECK(krb5_store_uint32(sp
, 0), 0); /* unknown but zero will work */
1153 CHECK(krb5_storage_to_data(sp
, &data
), 0);
1154 krb5_storage_free(sp
);
1158 HMAC_Init_ex(&c
, ntlmv2
, 16, EVP_md5(), NULL
);
1159 HMAC_Update(&c
, serverchallange
, 8);
1160 HMAC_Update(&c
, data
.data
, data
.length
);
1161 HMAC_Final(&c
, ntlmv2answer
, &hmaclen
);
1162 HMAC_CTX_cleanup(&c
);
1164 sp
= krb5_storage_emem();
1166 krb5_data_free(&data
);
1170 CHECK(krb5_storage_write(sp
, ntlmv2answer
, 16), 16);
1171 CHECK(krb5_storage_write(sp
, data
.data
, data
.length
), data
.length
);
1172 krb5_data_free(&data
);
1174 CHECK(krb5_storage_to_data(sp
, &data
), 0);
1175 krb5_storage_free(sp
);
1178 answer
->data
= data
.data
;
1179 answer
->length
= data
.length
;
1184 krb5_storage_free(sp
);
1188 static const int authtimediff
= 3600 * 2; /* 2 hours */
1191 * Verify NTLMv2 response.
1193 * @param key the ntlm key
1194 * @param len length of key
1195 * @param username name of the user, as sent in the message, assumed to be in UTF8.
1196 * @param target the name of the target, assumed to be in UTF8.
1197 * @param now the time now (0 if the library should pick it up itself)
1198 * @param serverchallange challange as sent by the server in the type2 message.
1199 * @param answer ntlm response answer, should be freed with heim_ntlm_free_buf().
1200 * @param infotarget infotarget as sent by the server in the type2 message.
1201 * @param ntlmv2 calculated session key
1203 * @return In case of success 0 is return, an errors, a errno in what
1206 * @ingroup ntlm_core
1210 heim_ntlm_verify_ntlm2(const void *key
, size_t len
,
1211 const char *username
,
1214 const unsigned char serverchallange
[8],
1215 const struct ntlm_buf
*answer
,
1216 struct ntlm_buf
*infotarget
,
1217 unsigned char ntlmv2
[16])
1219 krb5_error_code ret
;
1220 unsigned int hmaclen
;
1221 unsigned char clientanswer
[16];
1222 unsigned char clientnonce
[8];
1223 unsigned char serveranswer
[16];
1230 infotarget
->length
= 0;
1231 infotarget
->data
= NULL
;
1233 if (answer
->length
< 16)
1239 /* calculate ntlmv2 key */
1241 heim_ntlm_ntlmv2_key(key
, len
, username
, target
, ntlmv2
);
1243 /* calculate and build ntlmv2 answer */
1245 sp
= krb5_storage_from_readonly_mem(answer
->data
, answer
->length
);
1248 krb5_storage_set_flags(sp
, KRB5_STORAGE_BYTEORDER_LE
);
1250 CHECK(krb5_storage_read(sp
, clientanswer
, 16), 16);
1252 CHECK(krb5_ret_uint32(sp
, &temp
), 0);
1253 CHECK(temp
, 0x00000101);
1254 CHECK(krb5_ret_uint32(sp
, &temp
), 0);
1256 /* timestamp le 64 bit ts */
1257 CHECK(krb5_ret_uint32(sp
, &temp
), 0);
1259 CHECK(krb5_ret_uint32(sp
, &temp
), 0);
1260 t
|= ((uint64_t)temp
)<< 32;
1262 authtime
= nt2unixtime(t
);
1264 if (abs((int)(authtime
- now
)) > authtimediff
) {
1269 /* client challange */
1270 CHECK(krb5_storage_read(sp
, clientnonce
, 8), 8);
1272 CHECK(krb5_ret_uint32(sp
, &temp
), 0); /* unknown */
1274 /* should really unparse the infotarget, but lets pick up everything */
1275 infotarget
->length
= answer
->length
- krb5_storage_seek(sp
, 0, SEEK_CUR
);
1276 infotarget
->data
= malloc(infotarget
->length
);
1277 if (infotarget
->data
== NULL
) {
1281 CHECK(krb5_storage_read(sp
, infotarget
->data
, infotarget
->length
),
1282 infotarget
->length
);
1283 /* XXX remove the unknown ?? */
1284 krb5_storage_free(sp
);
1288 HMAC_Init_ex(&c
, ntlmv2
, 16, EVP_md5(), NULL
);
1289 HMAC_Update(&c
, serverchallange
, 8);
1290 HMAC_Update(&c
, ((unsigned char *)answer
->data
) + 16, answer
->length
- 16);
1291 HMAC_Final(&c
, serveranswer
, &hmaclen
);
1292 HMAC_CTX_cleanup(&c
);
1294 if (memcmp(serveranswer
, clientanswer
, 16) != 0) {
1295 heim_ntlm_free_buf(infotarget
);
1301 heim_ntlm_free_buf(infotarget
);
1303 krb5_storage_free(sp
);
1309 * Calculate the NTLM2 Session Response
1311 * @param clnt_nonce client nonce
1312 * @param svr_chal server challage
1313 * @param ntlm2_hash ntlm hash
1314 * @param lm The LM response, should be freed with heim_ntlm_free_buf().
1315 * @param ntlm The NTLM response, should be freed with heim_ntlm_free_buf().
1317 * @return In case of success 0 is return, an errors, a errno in what
1320 * @ingroup ntlm_core
1324 heim_ntlm_calculate_ntlm2_sess(const unsigned char clnt_nonce
[8],
1325 const unsigned char svr_chal
[8],
1326 const unsigned char ntlm_hash
[16],
1327 struct ntlm_buf
*lm
,
1328 struct ntlm_buf
*ntlm
)
1330 unsigned char ntlm2_sess_hash
[MD5_DIGEST_LENGTH
];
1331 unsigned char res
[21], *resp
;
1334 lm
->data
= malloc(24);
1335 if (lm
->data
== NULL
)
1339 ntlm
->data
= malloc(24);
1340 if (ntlm
->data
== NULL
) {
1347 /* first setup the lm resp */
1348 memset(lm
->data
, 0, 24);
1349 memcpy(lm
->data
, clnt_nonce
, 8);
1352 MD5_Update(&md5
, svr_chal
, 8); /* session nonce part 1 */
1353 MD5_Update(&md5
, clnt_nonce
, 8); /* session nonce part 2 */
1354 MD5_Final(ntlm2_sess_hash
, &md5
); /* will only use first 8 bytes */
1356 memset(res
, 0, sizeof(res
));
1357 memcpy(res
, ntlm_hash
, 16);
1360 splitandenc(&res
[0], ntlm2_sess_hash
, resp
+ 0);
1361 splitandenc(&res
[7], ntlm2_sess_hash
, resp
+ 8);
1362 splitandenc(&res
[14], ntlm2_sess_hash
, resp
+ 16);