2 * Copyright (c) 2006 - 2008 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
49 #define HC_DEPRECATED_CRYPTO
51 #include "krb5-types.h"
52 #include "crypto-headers.h"
56 /*! \mainpage Heimdal NTLM library
58 * \section intro Introduction
60 * Heimdal libheimntlm library is a implementation of the NTLM
61 * protocol, both version 1 and 2. The GSS-API mech that uses this
62 * library adds support for transport encryption and integrity
65 * NTLM is a protocol for mutual authentication, its still used in
66 * many protocol where Kerberos is not support, one example is
67 * EAP/X802.1x mechanism LEAP from Microsoft and Cisco.
69 * This is a support library for the core protocol, its used in
70 * Heimdal to implement and GSS-API mechanism. There is also support
71 * in the KDC to do remote digest authenticiation, this to allow
72 * services to authenticate users w/o direct access to the users ntlm
73 * hashes (same as Kerberos arcfour enctype keys).
75 * More information about the NTLM protocol can found here
76 * http://davenport.sourceforge.net/ntlm.html .
78 * The Heimdal projects web page: http://www.h5l.org/
81 /** @defgroup ntlm_core Heimdal NTLM library
83 * The NTLM core functions implement the string2key generation
84 * function, message encode and decode function, and the hash function
94 static const unsigned char ntlmsigature
[8] = "NTLMSSP\x00";
100 #define CHECK(f, e) \
101 do { ret = f ; if (ret != (e)) { ret = EINVAL; goto out; } } while(0)
104 * heim_ntlm_free_buf frees the ntlm buffer
106 * @param p buffer to be freed
112 heim_ntlm_free_buf(struct ntlm_buf
*p
)
122 ascii2ucs2le(const char *string
, int up
, struct ntlm_buf
*buf
)
127 len
= strlen(string
);
128 if (len
/ 2 > UINT_MAX
)
131 buf
->length
= len
* 2;
132 buf
->data
= malloc(buf
->length
);
133 if (buf
->data
== NULL
&& len
!= 0) {
134 heim_ntlm_free_buf(buf
);
139 for (i
= 0; i
< len
; i
++) {
140 unsigned char t
= (unsigned char)string
[i
];
142 heim_ntlm_free_buf(buf
);
157 static krb5_error_code
158 ret_sec_buffer(krb5_storage
*sp
, struct sec_buffer
*buf
)
161 CHECK(krb5_ret_uint16(sp
, &buf
->length
), 0);
162 CHECK(krb5_ret_uint16(sp
, &buf
->allocated
), 0);
163 CHECK(krb5_ret_uint32(sp
, &buf
->offset
), 0);
168 static krb5_error_code
169 store_sec_buffer(krb5_storage
*sp
, const struct sec_buffer
*buf
)
172 CHECK(krb5_store_uint16(sp
, buf
->length
), 0);
173 CHECK(krb5_store_uint16(sp
, buf
->allocated
), 0);
174 CHECK(krb5_store_uint32(sp
, buf
->offset
), 0);
180 * Strings are either OEM or UNICODE. The later is encoded as ucs2 on
181 * wire, but using utf8 in memory.
184 static krb5_error_code
185 len_string(int ucs2
, const char *s
)
187 size_t len
= strlen(s
);
193 static krb5_error_code
194 ret_string(krb5_storage
*sp
, int ucs2
, struct sec_buffer
*desc
, char **s
)
198 *s
= malloc(desc
->length
+ 1);
199 CHECK(krb5_storage_seek(sp
, desc
->offset
, SEEK_SET
), desc
->offset
);
200 CHECK(krb5_storage_read(sp
, *s
, desc
->length
), desc
->length
);
201 (*s
)[desc
->length
] = '\0';
205 for (i
= 0; i
< desc
->length
/ 2; i
++) {
206 (*s
)[i
] = (*s
)[i
* 2];
207 if ((*s
)[i
* 2 + 1]) {
222 static krb5_error_code
223 put_string(krb5_storage
*sp
, int ucs2
, const char *s
)
229 ret
= ascii2ucs2le(s
, 0, &buf
);
233 buf
.data
= rk_UNCONST(s
);
234 buf
.length
= strlen(s
);
237 CHECK(krb5_storage_write(sp
, buf
.data
, buf
.length
), buf
.length
);
239 heim_ntlm_free_buf(&buf
);
249 static krb5_error_code
250 ret_buf(krb5_storage
*sp
, struct sec_buffer
*desc
, struct ntlm_buf
*buf
)
254 buf
->data
= malloc(desc
->length
);
255 buf
->length
= desc
->length
;
256 CHECK(krb5_storage_seek(sp
, desc
->offset
, SEEK_SET
), desc
->offset
);
257 CHECK(krb5_storage_read(sp
, buf
->data
, buf
->length
), buf
->length
);
263 static krb5_error_code
264 put_buf(krb5_storage
*sp
, const struct ntlm_buf
*buf
)
267 CHECK(krb5_storage_write(sp
, buf
->data
, buf
->length
), buf
->length
);
274 * Frees the ntlm_targetinfo message
276 * @param ti targetinfo to be freed
282 heim_ntlm_free_targetinfo(struct ntlm_targetinfo
*ti
)
284 free(ti
->servername
);
285 free(ti
->domainname
);
286 free(ti
->dnsdomainname
);
287 free(ti
->dnsservername
);
288 memset(ti
, 0, sizeof(*ti
));
292 encode_ti_blob(krb5_storage
*out
, uint16_t type
, int ucs2
, char *s
)
295 CHECK(krb5_store_uint16(out
, type
), 0);
296 CHECK(krb5_store_uint16(out
, len_string(ucs2
, s
)), 0);
297 CHECK(put_string(out
, ucs2
, s
), 0);
303 * Encodes a ntlm_targetinfo message.
305 * @param ti the ntlm_targetinfo message to encode.
306 * @param ucs2 if the strings should be encoded with ucs2 (selected by flag in message).
307 * @param data is the return buffer with the encoded message, should be
308 * freed with heim_ntlm_free_buf().
310 * @return In case of success 0 is return, an errors, a errno in what
317 heim_ntlm_encode_targetinfo(const struct ntlm_targetinfo
*ti
,
319 struct ntlm_buf
*data
)
327 out
= krb5_storage_emem();
332 CHECK(encode_ti_blob(out
, 1, ucs2
, ti
->servername
), 0);
334 CHECK(encode_ti_blob(out
, 2, ucs2
, ti
->domainname
), 0);
335 if (ti
->dnsservername
)
336 CHECK(encode_ti_blob(out
, 3, ucs2
, ti
->dnsservername
), 0);
337 if (ti
->dnsdomainname
)
338 CHECK(encode_ti_blob(out
, 4, ucs2
, ti
->dnsdomainname
), 0);
341 CHECK(krb5_store_int16(out
, 0), 0);
342 CHECK(krb5_store_int16(out
, 0), 0);
346 ret
= krb5_storage_to_data(out
, &d
);
348 data
->length
= d
.length
;
351 krb5_storage_free(out
);
356 * Decodes an NTLM targetinfo message
358 * @param data input data buffer with the encode NTLM targetinfo message
359 * @param ucs2 if the strings should be encoded with ucs2 (selected by flag in message).
360 * @param ti the decoded target info, should be freed with heim_ntlm_free_targetinfo().
362 * @return In case of success 0 is return, an errors, a errno in what
369 heim_ntlm_decode_targetinfo(const struct ntlm_buf
*data
,
371 struct ntlm_targetinfo
*ti
)
373 memset(ti
, 0, sizeof(*ti
));
378 * Frees the ntlm_type1 message
380 * @param data message to be freed
386 heim_ntlm_free_type1(struct ntlm_type1
*data
)
391 free(data
->hostname
);
392 memset(data
, 0, sizeof(*data
));
396 heim_ntlm_decode_type1(const struct ntlm_buf
*buf
, struct ntlm_type1
*data
)
399 unsigned char sig
[8];
401 struct sec_buffer domain
, hostname
;
404 memset(data
, 0, sizeof(*data
));
406 in
= krb5_storage_from_readonly_mem(buf
->data
, buf
->length
);
411 krb5_storage_set_byteorder(in
, KRB5_STORAGE_BYTEORDER_LE
);
413 CHECK(krb5_storage_read(in
, sig
, sizeof(sig
)), sizeof(sig
));
414 CHECK(memcmp(ntlmsigature
, sig
, sizeof(ntlmsigature
)), 0);
415 CHECK(krb5_ret_uint32(in
, &type
), 0);
417 CHECK(krb5_ret_uint32(in
, &data
->flags
), 0);
418 if (data
->flags
& NTLM_SUPPLIED_DOMAIN
)
419 CHECK(ret_sec_buffer(in
, &domain
), 0);
420 if (data
->flags
& NTLM_SUPPLIED_WORKSTAION
)
421 CHECK(ret_sec_buffer(in
, &hostname
), 0);
423 if (domain
.offset
> 32) {
424 CHECK(krb5_ret_uint32(in
, &data
->os
[0]), 0);
425 CHECK(krb5_ret_uint32(in
, &data
->os
[1]), 0);
428 if (data
->flags
& NTLM_SUPPLIED_DOMAIN
)
429 CHECK(ret_string(in
, 0, &domain
, &data
->domain
), 0);
430 if (data
->flags
& NTLM_SUPPLIED_WORKSTAION
)
431 CHECK(ret_string(in
, 0, &hostname
, &data
->hostname
), 0);
434 krb5_storage_free(in
);
436 heim_ntlm_free_type1(data
);
442 * Encodes an ntlm_type1 message.
444 * @param type1 the ntlm_type1 message to encode.
445 * @param data is the return buffer with the encoded message, should be
446 * freed with heim_ntlm_free_buf().
448 * @return In case of success 0 is return, an errors, a errno in what
455 heim_ntlm_encode_type1(const struct ntlm_type1
*type1
, struct ntlm_buf
*data
)
458 struct sec_buffer domain
, hostname
;
460 uint32_t base
, flags
;
462 flags
= type1
->flags
;
467 flags
|= NTLM_SUPPLIED_DOMAIN
;
469 if (type1
->hostname
) {
471 flags
|= NTLM_SUPPLIED_WORKSTAION
;
477 domain
.offset
= base
;
478 domain
.length
= len_string(0, type1
->domain
);
479 domain
.allocated
= domain
.length
;
481 if (type1
->hostname
) {
482 hostname
.offset
= domain
.allocated
+ domain
.offset
;
483 hostname
.length
= len_string(0, type1
->hostname
);
484 hostname
.allocated
= hostname
.length
;
487 out
= krb5_storage_emem();
491 krb5_storage_set_byteorder(out
, KRB5_STORAGE_BYTEORDER_LE
);
492 CHECK(krb5_storage_write(out
, ntlmsigature
, sizeof(ntlmsigature
)),
493 sizeof(ntlmsigature
));
494 CHECK(krb5_store_uint32(out
, 1), 0);
495 CHECK(krb5_store_uint32(out
, flags
), 0);
498 CHECK(store_sec_buffer(out
, &domain
), 0);
500 CHECK(store_sec_buffer(out
, &hostname
), 0);
502 CHECK(krb5_store_uint32(out
, type1
->os
[0]), 0);
503 CHECK(krb5_store_uint32(out
, type1
->os
[1]), 0);
506 CHECK(put_string(out
, 0, type1
->domain
), 0);
508 CHECK(put_string(out
, 0, type1
->hostname
), 0);
512 ret
= krb5_storage_to_data(out
, &d
);
514 data
->length
= d
.length
;
517 krb5_storage_free(out
);
523 * Frees the ntlm_type2 message
525 * @param data message to be freed
531 heim_ntlm_free_type2(struct ntlm_type2
*data
)
533 if (data
->targetname
)
534 free(data
->targetname
);
535 heim_ntlm_free_buf(&data
->targetinfo
);
536 memset(data
, 0, sizeof(*data
));
540 heim_ntlm_decode_type2(const struct ntlm_buf
*buf
, struct ntlm_type2
*type2
)
543 unsigned char sig
[8];
544 uint32_t type
, ctx
[2];
545 struct sec_buffer targetname
, targetinfo
;
549 memset(type2
, 0, sizeof(*type2
));
551 in
= krb5_storage_from_readonly_mem(buf
->data
, buf
->length
);
556 krb5_storage_set_byteorder(in
, KRB5_STORAGE_BYTEORDER_LE
);
558 CHECK(krb5_storage_read(in
, sig
, sizeof(sig
)), sizeof(sig
));
559 CHECK(memcmp(ntlmsigature
, sig
, sizeof(ntlmsigature
)), 0);
560 CHECK(krb5_ret_uint32(in
, &type
), 0);
563 CHECK(ret_sec_buffer(in
, &targetname
), 0);
564 CHECK(krb5_ret_uint32(in
, &type2
->flags
), 0);
565 if (type2
->flags
& NTLM_NEG_UNICODE
)
567 CHECK(krb5_storage_read(in
, type2
->challange
, sizeof(type2
->challange
)),
568 sizeof(type2
->challange
));
569 CHECK(krb5_ret_uint32(in
, &ctx
[0]), 0); /* context */
570 CHECK(krb5_ret_uint32(in
, &ctx
[1]), 0);
571 CHECK(ret_sec_buffer(in
, &targetinfo
), 0);
574 CHECK(krb5_ret_uint32(in
, &type2
->os
[0]), 0);
575 CHECK(krb5_ret_uint32(in
, &type2
->os
[1]), 0);
578 CHECK(ret_string(in
, ucs2
, &targetname
, &type2
->targetname
), 0);
579 CHECK(ret_buf(in
, &targetinfo
, &type2
->targetinfo
), 0);
583 krb5_storage_free(in
);
585 heim_ntlm_free_type2(type2
);
591 * Encodes an ntlm_type2 message.
593 * @param type2 the ntlm_type2 message to encode.
594 * @param data is the return buffer with the encoded message, should be
595 * freed with heim_ntlm_free_buf().
597 * @return In case of success 0 is return, an errors, a errno in what
604 heim_ntlm_encode_type2(const struct ntlm_type2
*type2
, struct ntlm_buf
*data
)
606 struct sec_buffer targetname
, targetinfo
;
608 krb5_storage
*out
= NULL
;
617 if (type2
->flags
& NTLM_NEG_UNICODE
)
620 targetname
.offset
= base
;
621 targetname
.length
= len_string(ucs2
, type2
->targetname
);
622 targetname
.allocated
= targetname
.length
;
624 targetinfo
.offset
= targetname
.allocated
+ targetname
.offset
;
625 targetinfo
.length
= type2
->targetinfo
.length
;
626 targetinfo
.allocated
= type2
->targetinfo
.length
;
628 out
= krb5_storage_emem();
632 krb5_storage_set_byteorder(out
, KRB5_STORAGE_BYTEORDER_LE
);
633 CHECK(krb5_storage_write(out
, ntlmsigature
, sizeof(ntlmsigature
)),
634 sizeof(ntlmsigature
));
635 CHECK(krb5_store_uint32(out
, 2), 0);
636 CHECK(store_sec_buffer(out
, &targetname
), 0);
637 CHECK(krb5_store_uint32(out
, type2
->flags
), 0);
638 CHECK(krb5_storage_write(out
, type2
->challange
, sizeof(type2
->challange
)),
639 sizeof(type2
->challange
));
640 CHECK(krb5_store_uint32(out
, 0), 0); /* context */
641 CHECK(krb5_store_uint32(out
, 0), 0);
642 CHECK(store_sec_buffer(out
, &targetinfo
), 0);
645 CHECK(krb5_store_uint32(out
, type2
->os
[0]), 0);
646 CHECK(krb5_store_uint32(out
, type2
->os
[1]), 0);
648 CHECK(put_string(out
, ucs2
, type2
->targetname
), 0);
649 CHECK(krb5_storage_write(out
, type2
->targetinfo
.data
,
650 type2
->targetinfo
.length
),
651 type2
->targetinfo
.length
);
655 ret
= krb5_storage_to_data(out
, &d
);
657 data
->length
= d
.length
;
661 krb5_storage_free(out
);
667 * Frees the ntlm_type3 message
669 * @param data message to be freed
675 heim_ntlm_free_type3(struct ntlm_type3
*data
)
677 heim_ntlm_free_buf(&data
->lm
);
678 heim_ntlm_free_buf(&data
->ntlm
);
679 if (data
->targetname
)
680 free(data
->targetname
);
682 free(data
->username
);
685 heim_ntlm_free_buf(&data
->sessionkey
);
686 memset(data
, 0, sizeof(*data
));
694 heim_ntlm_decode_type3(const struct ntlm_buf
*buf
,
696 struct ntlm_type3
*type3
)
699 unsigned char sig
[8];
702 struct sec_buffer lm
, ntlm
, target
, username
, sessionkey
, ws
;
704 memset(type3
, 0, sizeof(*type3
));
705 memset(&sessionkey
, 0, sizeof(sessionkey
));
707 in
= krb5_storage_from_readonly_mem(buf
->data
, buf
->length
);
712 krb5_storage_set_byteorder(in
, KRB5_STORAGE_BYTEORDER_LE
);
714 CHECK(krb5_storage_read(in
, sig
, sizeof(sig
)), sizeof(sig
));
715 CHECK(memcmp(ntlmsigature
, sig
, sizeof(ntlmsigature
)), 0);
716 CHECK(krb5_ret_uint32(in
, &type
), 0);
718 CHECK(ret_sec_buffer(in
, &lm
), 0);
719 CHECK(ret_sec_buffer(in
, &ntlm
), 0);
720 CHECK(ret_sec_buffer(in
, &target
), 0);
721 CHECK(ret_sec_buffer(in
, &username
), 0);
722 CHECK(ret_sec_buffer(in
, &ws
), 0);
723 if (lm
.offset
>= 60) {
724 CHECK(ret_sec_buffer(in
, &sessionkey
), 0);
726 if (lm
.offset
>= 64) {
727 CHECK(krb5_ret_uint32(in
, &type3
->flags
), 0);
729 if (lm
.offset
>= 72) {
730 CHECK(krb5_ret_uint32(in
, &type3
->os
[0]), 0);
731 CHECK(krb5_ret_uint32(in
, &type3
->os
[1]), 0);
733 CHECK(ret_buf(in
, &lm
, &type3
->lm
), 0);
734 CHECK(ret_buf(in
, &ntlm
, &type3
->ntlm
), 0);
735 CHECK(ret_string(in
, ucs2
, &target
, &type3
->targetname
), 0);
736 CHECK(ret_string(in
, ucs2
, &username
, &type3
->username
), 0);
737 CHECK(ret_string(in
, ucs2
, &ws
, &type3
->ws
), 0);
738 if (sessionkey
.offset
)
739 CHECK(ret_buf(in
, &sessionkey
, &type3
->sessionkey
), 0);
742 krb5_storage_free(in
);
744 heim_ntlm_free_type3(type3
);
750 * Encodes an ntlm_type3 message.
752 * @param type3 the ntlm_type3 message to encode.
753 * @param data is the return buffer with the encoded message, should be
754 * freed with heim_ntlm_free_buf().
756 * @return In case of success 0 is return, an errors, a errno in what
763 heim_ntlm_encode_type3(const struct ntlm_type3
*type3
, struct ntlm_buf
*data
)
765 struct sec_buffer lm
, ntlm
, target
, username
, sessionkey
, ws
;
767 krb5_storage
*out
= NULL
;
771 memset(&lm
, 0, sizeof(lm
));
772 memset(&ntlm
, 0, sizeof(ntlm
));
773 memset(&target
, 0, sizeof(target
));
774 memset(&username
, 0, sizeof(username
));
775 memset(&ws
, 0, sizeof(ws
));
776 memset(&sessionkey
, 0, sizeof(sessionkey
));
779 if (type3
->sessionkey
.length
) {
780 base
+= 8; /* sessionkey sec buf */
781 base
+= 4; /* flags */
787 if (type3
->flags
& NTLM_NEG_UNICODE
)
791 lm
.length
= type3
->lm
.length
;
792 lm
.allocated
= type3
->lm
.length
;
794 ntlm
.offset
= lm
.offset
+ lm
.allocated
;
795 ntlm
.length
= type3
->ntlm
.length
;
796 ntlm
.allocated
= ntlm
.length
;
798 target
.offset
= ntlm
.offset
+ ntlm
.allocated
;
799 target
.length
= len_string(ucs2
, type3
->targetname
);
800 target
.allocated
= target
.length
;
802 username
.offset
= target
.offset
+ target
.allocated
;
803 username
.length
= len_string(ucs2
, type3
->username
);
804 username
.allocated
= username
.length
;
806 ws
.offset
= username
.offset
+ username
.allocated
;
807 ws
.length
= len_string(ucs2
, type3
->ws
);
808 ws
.allocated
= ws
.length
;
810 sessionkey
.offset
= ws
.offset
+ ws
.allocated
;
811 sessionkey
.length
= type3
->sessionkey
.length
;
812 sessionkey
.allocated
= type3
->sessionkey
.length
;
814 out
= krb5_storage_emem();
818 krb5_storage_set_byteorder(out
, KRB5_STORAGE_BYTEORDER_LE
);
819 CHECK(krb5_storage_write(out
, ntlmsigature
, sizeof(ntlmsigature
)),
820 sizeof(ntlmsigature
));
821 CHECK(krb5_store_uint32(out
, 3), 0);
823 CHECK(store_sec_buffer(out
, &lm
), 0);
824 CHECK(store_sec_buffer(out
, &ntlm
), 0);
825 CHECK(store_sec_buffer(out
, &target
), 0);
826 CHECK(store_sec_buffer(out
, &username
), 0);
827 CHECK(store_sec_buffer(out
, &ws
), 0);
829 if (type3
->sessionkey
.length
) {
830 CHECK(store_sec_buffer(out
, &sessionkey
), 0);
831 CHECK(krb5_store_uint32(out
, type3
->flags
), 0);
834 CHECK(krb5_store_uint32(out
, 0), 0); /* os0 */
835 CHECK(krb5_store_uint32(out
, 0), 0); /* os1 */
838 CHECK(put_buf(out
, &type3
->lm
), 0);
839 CHECK(put_buf(out
, &type3
->ntlm
), 0);
840 CHECK(put_string(out
, ucs2
, type3
->targetname
), 0);
841 CHECK(put_string(out
, ucs2
, type3
->username
), 0);
842 CHECK(put_string(out
, ucs2
, type3
->ws
), 0);
843 CHECK(put_buf(out
, &type3
->sessionkey
), 0);
847 ret
= krb5_storage_to_data(out
, &d
);
849 data
->length
= d
.length
;
853 krb5_storage_free(out
);
864 splitandenc(unsigned char *hash
,
865 unsigned char *challange
,
866 unsigned char *answer
)
869 DES_key_schedule sched
;
871 ((unsigned char*)key
)[0] = hash
[0];
872 ((unsigned char*)key
)[1] = (hash
[0] << 7) | (hash
[1] >> 1);
873 ((unsigned char*)key
)[2] = (hash
[1] << 6) | (hash
[2] >> 2);
874 ((unsigned char*)key
)[3] = (hash
[2] << 5) | (hash
[3] >> 3);
875 ((unsigned char*)key
)[4] = (hash
[3] << 4) | (hash
[4] >> 4);
876 ((unsigned char*)key
)[5] = (hash
[4] << 3) | (hash
[5] >> 5);
877 ((unsigned char*)key
)[6] = (hash
[5] << 2) | (hash
[6] >> 6);
878 ((unsigned char*)key
)[7] = (hash
[6] << 1);
880 DES_set_odd_parity(&key
);
881 DES_set_key_unchecked(&key
, &sched
);
882 DES_ecb_encrypt((DES_cblock
*)challange
, (DES_cblock
*)answer
, &sched
, 1);
883 memset(&sched
, 0, sizeof(sched
));
884 memset(key
, 0, sizeof(key
));
888 * Calculate the NTLM key, the password is assumed to be in UTF8.
890 * @param password password to calcute the key for.
891 * @param key calcuted key, should be freed with heim_ntlm_free_buf().
893 * @return In case of success 0 is return, an errors, a errno in what
900 heim_ntlm_nt_key(const char *password
, struct ntlm_buf
*key
)
906 key
->data
= malloc(MD5_DIGEST_LENGTH
);
907 if (key
->data
== NULL
)
909 key
->length
= MD5_DIGEST_LENGTH
;
911 ret
= ascii2ucs2le(password
, 0, &buf
);
913 heim_ntlm_free_buf(key
);
917 MD4_Update(&ctx
, buf
.data
, buf
.length
);
918 MD4_Final(key
->data
, &ctx
);
919 heim_ntlm_free_buf(&buf
);
924 * Calculate NTLMv1 response hash
926 * @param key the ntlm v1 key
927 * @param len length of key
928 * @param challange sent by the server
929 * @param answer calculated answer, should be freed with heim_ntlm_free_buf().
931 * @return In case of success 0 is return, an errors, a errno in what
938 heim_ntlm_calculate_ntlm1(void *key
, size_t len
,
939 unsigned char challange
[8],
940 struct ntlm_buf
*answer
)
942 unsigned char res
[21];
944 if (len
!= MD4_DIGEST_LENGTH
)
947 memcpy(res
, key
, len
);
948 memset(&res
[MD4_DIGEST_LENGTH
], 0, sizeof(res
) - MD4_DIGEST_LENGTH
);
950 answer
->data
= malloc(24);
951 if (answer
->data
== NULL
)
955 splitandenc(&res
[0], challange
, ((unsigned char *)answer
->data
) + 0);
956 splitandenc(&res
[7], challange
, ((unsigned char *)answer
->data
) + 8);
957 splitandenc(&res
[14], challange
, ((unsigned char *)answer
->data
) + 16);
963 * Generates an NTLMv1 session random with assosited session master key.
965 * @param key the ntlm v1 key
966 * @param len length of key
967 * @param session generated session nonce, should be freed with heim_ntlm_free_buf().
968 * @param master calculated session master key, should be freed with heim_ntlm_free_buf().
970 * @return In case of success 0 is return, an errors, a errno in what
977 heim_ntlm_build_ntlm1_master(void *key
, size_t len
,
978 struct ntlm_buf
*session
,
979 struct ntlm_buf
*master
)
983 memset(master
, 0, sizeof(*master
));
984 memset(session
, 0, sizeof(*session
));
986 if (len
!= MD4_DIGEST_LENGTH
)
989 session
->length
= MD4_DIGEST_LENGTH
;
990 session
->data
= malloc(session
->length
);
991 if (session
->data
== NULL
) {
995 master
->length
= MD4_DIGEST_LENGTH
;
996 master
->data
= malloc(master
->length
);
997 if (master
->data
== NULL
) {
998 heim_ntlm_free_buf(master
);
999 heim_ntlm_free_buf(session
);
1004 unsigned char sessionkey
[MD4_DIGEST_LENGTH
];
1008 MD4_Update(&ctx
, key
, len
);
1009 MD4_Final(sessionkey
, &ctx
);
1011 RC4_set_key(&rc4
, sizeof(sessionkey
), sessionkey
);
1014 if (RAND_bytes(session
->data
, session
->length
) != 1) {
1015 heim_ntlm_free_buf(master
);
1016 heim_ntlm_free_buf(session
);
1020 RC4(&rc4
, master
->length
, session
->data
, master
->data
);
1021 memset(&rc4
, 0, sizeof(rc4
));
1027 * Generates an NTLMv2 session key.
1029 * @param key the ntlm key
1030 * @param len length of key
1031 * @param username name of the user, as sent in the message, assumed to be in UTF8.
1032 * @param target the name of the target, assumed to be in UTF8.
1033 * @param ntlmv2 the ntlmv2 session key
1035 * @ingroup ntlm_core
1039 heim_ntlm_ntlmv2_key(const void *key
, size_t len
,
1040 const char *username
,
1042 unsigned char ntlmv2
[16])
1044 unsigned int hmaclen
;
1048 HMAC_Init_ex(&c
, key
, len
, EVP_md5(), NULL
);
1050 struct ntlm_buf buf
;
1051 /* uppercase username and turn it into ucs2-le */
1052 ascii2ucs2le(username
, 1, &buf
);
1053 HMAC_Update(&c
, buf
.data
, buf
.length
);
1055 /* uppercase target and turn into ucs2-le */
1056 ascii2ucs2le(target
, 1, &buf
);
1057 HMAC_Update(&c
, buf
.data
, buf
.length
);
1060 HMAC_Final(&c
, ntlmv2
, &hmaclen
);
1061 HMAC_CTX_cleanup(&c
);
1069 #define NTTIME_EPOCH 0x019DB1DED53E8000LL
1072 unix2nttime(time_t unix_time
)
1075 wt
= unix_time
* (uint64_t)10000000 + (uint64_t)NTTIME_EPOCH
;
1080 nt2unixtime(uint64_t t
)
1082 t
= ((t
- (uint64_t)NTTIME_EPOCH
) / (uint64_t)10000000);
1083 if (t
> (((time_t)(~(uint64_t)0)) >> 1))
1090 * Calculate NTLMv2 response
1092 * @param key the ntlm key
1093 * @param len length of key
1094 * @param username name of the user, as sent in the message, assumed to be in UTF8.
1095 * @param target the name of the target, assumed to be in UTF8.
1096 * @param serverchallange challange as sent by the server in the type2 message.
1097 * @param infotarget infotarget as sent by the server in the type2 message.
1098 * @param ntlmv2 calculated session key
1099 * @param answer ntlm response answer, should be freed with heim_ntlm_free_buf().
1101 * @return In case of success 0 is return, an errors, a errno in what
1104 * @ingroup ntlm_core
1108 heim_ntlm_calculate_ntlm2(const void *key
, size_t len
,
1109 const char *username
,
1111 const unsigned char serverchallange
[8],
1112 const struct ntlm_buf
*infotarget
,
1113 unsigned char ntlmv2
[16],
1114 struct ntlm_buf
*answer
)
1116 krb5_error_code ret
;
1118 unsigned int hmaclen
;
1119 unsigned char ntlmv2answer
[16];
1121 unsigned char clientchallange
[8];
1125 t
= unix2nttime(time(NULL
));
1127 if (RAND_bytes(clientchallange
, sizeof(clientchallange
)) != 1)
1130 /* calculate ntlmv2 key */
1132 heim_ntlm_ntlmv2_key(key
, len
, username
, target
, ntlmv2
);
1134 /* calculate and build ntlmv2 answer */
1136 sp
= krb5_storage_emem();
1139 krb5_storage_set_flags(sp
, KRB5_STORAGE_BYTEORDER_LE
);
1141 CHECK(krb5_store_uint32(sp
, 0x00000101), 0);
1142 CHECK(krb5_store_uint32(sp
, 0), 0);
1143 /* timestamp le 64 bit ts */
1144 CHECK(krb5_store_uint32(sp
, t
& 0xffffffff), 0);
1145 CHECK(krb5_store_uint32(sp
, t
>> 32), 0);
1147 CHECK(krb5_storage_write(sp
, clientchallange
, 8), 8);
1149 CHECK(krb5_store_uint32(sp
, 0), 0); /* unknown but zero will work */
1150 CHECK(krb5_storage_write(sp
, infotarget
->data
, infotarget
->length
),
1151 infotarget
->length
);
1152 CHECK(krb5_store_uint32(sp
, 0), 0); /* unknown but zero will work */
1154 CHECK(krb5_storage_to_data(sp
, &data
), 0);
1155 krb5_storage_free(sp
);
1159 HMAC_Init_ex(&c
, ntlmv2
, 16, EVP_md5(), NULL
);
1160 HMAC_Update(&c
, serverchallange
, 8);
1161 HMAC_Update(&c
, data
.data
, data
.length
);
1162 HMAC_Final(&c
, ntlmv2answer
, &hmaclen
);
1163 HMAC_CTX_cleanup(&c
);
1165 sp
= krb5_storage_emem();
1167 krb5_data_free(&data
);
1171 CHECK(krb5_storage_write(sp
, ntlmv2answer
, 16), 16);
1172 CHECK(krb5_storage_write(sp
, data
.data
, data
.length
), data
.length
);
1173 krb5_data_free(&data
);
1175 CHECK(krb5_storage_to_data(sp
, &data
), 0);
1176 krb5_storage_free(sp
);
1179 answer
->data
= data
.data
;
1180 answer
->length
= data
.length
;
1185 krb5_storage_free(sp
);
1189 static const int authtimediff
= 3600 * 2; /* 2 hours */
1192 * Verify NTLMv2 response.
1194 * @param key the ntlm key
1195 * @param len length of key
1196 * @param username name of the user, as sent in the message, assumed to be in UTF8.
1197 * @param target the name of the target, assumed to be in UTF8.
1198 * @param now the time now (0 if the library should pick it up itself)
1199 * @param serverchallange challange as sent by the server in the type2 message.
1200 * @param answer ntlm response answer, should be freed with heim_ntlm_free_buf().
1201 * @param infotarget infotarget as sent by the server in the type2 message.
1202 * @param ntlmv2 calculated session key
1204 * @return In case of success 0 is return, an errors, a errno in what
1207 * @ingroup ntlm_core
1211 heim_ntlm_verify_ntlm2(const void *key
, size_t len
,
1212 const char *username
,
1215 const unsigned char serverchallange
[8],
1216 const struct ntlm_buf
*answer
,
1217 struct ntlm_buf
*infotarget
,
1218 unsigned char ntlmv2
[16])
1220 krb5_error_code ret
;
1221 unsigned int hmaclen
;
1222 unsigned char clientanswer
[16];
1223 unsigned char clientnonce
[8];
1224 unsigned char serveranswer
[16];
1231 infotarget
->length
= 0;
1232 infotarget
->data
= NULL
;
1234 if (answer
->length
< 16)
1240 /* calculate ntlmv2 key */
1242 heim_ntlm_ntlmv2_key(key
, len
, username
, target
, ntlmv2
);
1244 /* calculate and build ntlmv2 answer */
1246 sp
= krb5_storage_from_readonly_mem(answer
->data
, answer
->length
);
1249 krb5_storage_set_flags(sp
, KRB5_STORAGE_BYTEORDER_LE
);
1251 CHECK(krb5_storage_read(sp
, clientanswer
, 16), 16);
1253 CHECK(krb5_ret_uint32(sp
, &temp
), 0);
1254 CHECK(temp
, 0x00000101);
1255 CHECK(krb5_ret_uint32(sp
, &temp
), 0);
1257 /* timestamp le 64 bit ts */
1258 CHECK(krb5_ret_uint32(sp
, &temp
), 0);
1260 CHECK(krb5_ret_uint32(sp
, &temp
), 0);
1261 t
|= ((uint64_t)temp
)<< 32;
1263 authtime
= nt2unixtime(t
);
1265 if (abs((int)(authtime
- now
)) > authtimediff
) {
1270 /* client challange */
1271 CHECK(krb5_storage_read(sp
, clientnonce
, 8), 8);
1273 CHECK(krb5_ret_uint32(sp
, &temp
), 0); /* unknown */
1275 /* should really unparse the infotarget, but lets pick up everything */
1276 infotarget
->length
= answer
->length
- krb5_storage_seek(sp
, 0, SEEK_CUR
);
1277 infotarget
->data
= malloc(infotarget
->length
);
1278 if (infotarget
->data
== NULL
) {
1282 CHECK(krb5_storage_read(sp
, infotarget
->data
, infotarget
->length
),
1283 infotarget
->length
);
1284 /* XXX remove the unknown ?? */
1285 krb5_storage_free(sp
);
1289 HMAC_Init_ex(&c
, ntlmv2
, 16, EVP_md5(), NULL
);
1290 HMAC_Update(&c
, serverchallange
, 8);
1291 HMAC_Update(&c
, ((unsigned char *)answer
->data
) + 16, answer
->length
- 16);
1292 HMAC_Final(&c
, serveranswer
, &hmaclen
);
1293 HMAC_CTX_cleanup(&c
);
1295 if (memcmp(serveranswer
, clientanswer
, 16) != 0) {
1296 heim_ntlm_free_buf(infotarget
);
1302 heim_ntlm_free_buf(infotarget
);
1304 krb5_storage_free(sp
);
1310 * Calculate the NTLM2 Session Response
1312 * @param clnt_nonce client nonce
1313 * @param svr_chal server challage
1314 * @param ntlm2_hash ntlm hash
1315 * @param lm The LM response, should be freed with heim_ntlm_free_buf().
1316 * @param ntlm The NTLM response, should be freed with heim_ntlm_free_buf().
1318 * @return In case of success 0 is return, an errors, a errno in what
1321 * @ingroup ntlm_core
1325 heim_ntlm_calculate_ntlm2_sess(const unsigned char clnt_nonce
[8],
1326 const unsigned char svr_chal
[8],
1327 const unsigned char ntlm_hash
[16],
1328 struct ntlm_buf
*lm
,
1329 struct ntlm_buf
*ntlm
)
1331 unsigned char ntlm2_sess_hash
[MD5_DIGEST_LENGTH
];
1332 unsigned char res
[21], *resp
;
1335 lm
->data
= malloc(24);
1336 if (lm
->data
== NULL
)
1340 ntlm
->data
= malloc(24);
1341 if (ntlm
->data
== NULL
) {
1348 /* first setup the lm resp */
1349 memset(lm
->data
, 0, 24);
1350 memcpy(lm
->data
, clnt_nonce
, 8);
1353 MD5_Update(&md5
, svr_chal
, 8); /* session nonce part 1 */
1354 MD5_Update(&md5
, clnt_nonce
, 8); /* session nonce part 2 */
1355 MD5_Final(ntlm2_sess_hash
, &md5
); /* will only use first 8 bytes */
1357 memset(res
, 0, sizeof(res
));
1358 memcpy(res
, ntlm_hash
, 16);
1361 splitandenc(&res
[0], ntlm2_sess_hash
, resp
+ 0);
1362 splitandenc(&res
[7], ntlm2_sess_hash
, resp
+ 8);
1363 splitandenc(&res
[14], ntlm2_sess_hash
, resp
+ 16);