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
47 #define HC_DEPRECATED_CRYPTO
49 #include "krb5-types.h"
50 #include "crypto-headers.h"
54 /*! \mainpage Heimdal NTLM library
56 * \section intro Introduction
58 * Heimdal libheimntlm library is a implementation of the NTLM
59 * protocol, both version 1 and 2. The GSS-API mech that uses this
60 * library adds support for transport encryption and integrity
63 * NTLM is a protocol for mutual authentication, its still used in
64 * many protocol where Kerberos is not support, one example is
65 * EAP/X802.1x mechanism LEAP from Microsoft and Cisco.
67 * This is a support library for the core protocol, its used in
68 * Heimdal to implement and GSS-API mechanism. There is also support
69 * in the KDC to do remote digest authenticiation, this to allow
70 * services to authenticate users w/o direct access to the users ntlm
71 * hashes (same as Kerberos arcfour enctype keys).
73 * More information about the NTLM protocol can found here
74 * http://davenport.sourceforge.net/ntlm.html .
76 * The Heimdal projects web page: http://www.h5l.org/
78 * @section ntlm_example NTLM Example
80 * Example to to use @ref test_ntlm.c .
82 * @example test_ntlm.c
84 * Example how to use the NTLM primitives.
88 /** @defgroup ntlm_core Heimdal NTLM library
90 * The NTLM core functions implement the string2key generation
91 * function, message encode and decode function, and the hash function
101 static const unsigned char ntlmsigature
[8] = "NTLMSSP\x00";
107 #define CHECK(f, e) \
108 do { ret = f ; if (ret != (e)) { ret = EINVAL; goto out; } } while(0)
111 * heim_ntlm_free_buf frees the ntlm buffer
113 * @param p buffer to be freed
119 heim_ntlm_free_buf(struct ntlm_buf
*p
)
129 ascii2ucs2le(const char *string
, int up
, struct ntlm_buf
*buf
)
134 len
= strlen(string
);
135 if (len
/ 2 > UINT_MAX
)
138 buf
->length
= len
* 2;
139 buf
->data
= malloc(buf
->length
);
140 if (buf
->data
== NULL
&& len
!= 0) {
141 heim_ntlm_free_buf(buf
);
146 for (i
= 0; i
< len
; i
++) {
147 unsigned char t
= (unsigned char)string
[i
];
149 heim_ntlm_free_buf(buf
);
164 static krb5_error_code
165 ret_sec_buffer(krb5_storage
*sp
, struct sec_buffer
*buf
)
168 CHECK(krb5_ret_uint16(sp
, &buf
->length
), 0);
169 CHECK(krb5_ret_uint16(sp
, &buf
->allocated
), 0);
170 CHECK(krb5_ret_uint32(sp
, &buf
->offset
), 0);
175 static krb5_error_code
176 store_sec_buffer(krb5_storage
*sp
, const struct sec_buffer
*buf
)
179 CHECK(krb5_store_uint16(sp
, buf
->length
), 0);
180 CHECK(krb5_store_uint16(sp
, buf
->allocated
), 0);
181 CHECK(krb5_store_uint32(sp
, buf
->offset
), 0);
187 * Strings are either OEM or UNICODE. The later is encoded as ucs2 on
188 * wire, but using utf8 in memory.
191 static krb5_error_code
192 len_string(int ucs2
, const char *s
)
194 size_t len
= strlen(s
);
200 static krb5_error_code
201 ret_string(krb5_storage
*sp
, int ucs2
, struct sec_buffer
*desc
, char **s
)
205 *s
= malloc(desc
->length
+ 1);
206 CHECK(krb5_storage_seek(sp
, desc
->offset
, SEEK_SET
), desc
->offset
);
207 CHECK(krb5_storage_read(sp
, *s
, desc
->length
), desc
->length
);
208 (*s
)[desc
->length
] = '\0';
212 for (i
= 0; i
< desc
->length
/ 2; i
++) {
213 (*s
)[i
] = (*s
)[i
* 2];
214 if ((*s
)[i
* 2 + 1]) {
227 static krb5_error_code
228 put_string(krb5_storage
*sp
, int ucs2
, const char *s
)
234 ret
= ascii2ucs2le(s
, 0, &buf
);
238 buf
.data
= rk_UNCONST(s
);
239 buf
.length
= strlen(s
);
242 CHECK(krb5_storage_write(sp
, buf
.data
, buf
.length
), buf
.length
);
244 heim_ntlm_free_buf(&buf
);
254 static krb5_error_code
255 ret_buf(krb5_storage
*sp
, struct sec_buffer
*desc
, struct ntlm_buf
*buf
)
259 buf
->data
= malloc(desc
->length
);
260 buf
->length
= desc
->length
;
261 CHECK(krb5_storage_seek(sp
, desc
->offset
, SEEK_SET
), desc
->offset
);
262 CHECK(krb5_storage_read(sp
, buf
->data
, buf
->length
), buf
->length
);
268 static krb5_error_code
269 put_buf(krb5_storage
*sp
, const struct ntlm_buf
*buf
)
272 CHECK(krb5_storage_write(sp
, buf
->data
, buf
->length
), buf
->length
);
279 * Frees the ntlm_targetinfo message
281 * @param ti targetinfo to be freed
287 heim_ntlm_free_targetinfo(struct ntlm_targetinfo
*ti
)
289 free(ti
->servername
);
290 free(ti
->domainname
);
291 free(ti
->dnsdomainname
);
292 free(ti
->dnsservername
);
293 memset(ti
, 0, sizeof(*ti
));
297 encode_ti_blob(krb5_storage
*out
, uint16_t type
, int ucs2
, char *s
)
300 CHECK(krb5_store_uint16(out
, type
), 0);
301 CHECK(krb5_store_uint16(out
, len_string(ucs2
, s
)), 0);
302 CHECK(put_string(out
, ucs2
, s
), 0);
308 * Encodes a ntlm_targetinfo message.
310 * @param ti the ntlm_targetinfo message to encode.
311 * @param ucs2 if the strings should be encoded with ucs2 (selected by flag in message).
312 * @param data is the return buffer with the encoded message, should be
313 * freed with heim_ntlm_free_buf().
315 * @return In case of success 0 is return, an errors, a errno in what
322 heim_ntlm_encode_targetinfo(const struct ntlm_targetinfo
*ti
,
324 struct ntlm_buf
*data
)
332 out
= krb5_storage_emem();
337 CHECK(encode_ti_blob(out
, 1, ucs2
, ti
->servername
), 0);
339 CHECK(encode_ti_blob(out
, 2, ucs2
, ti
->domainname
), 0);
340 if (ti
->dnsservername
)
341 CHECK(encode_ti_blob(out
, 3, ucs2
, ti
->dnsservername
), 0);
342 if (ti
->dnsdomainname
)
343 CHECK(encode_ti_blob(out
, 4, ucs2
, ti
->dnsdomainname
), 0);
346 CHECK(krb5_store_int16(out
, 0), 0);
347 CHECK(krb5_store_int16(out
, 0), 0);
351 ret
= krb5_storage_to_data(out
, &d
);
353 data
->length
= d
.length
;
356 krb5_storage_free(out
);
361 * Decodes an NTLM targetinfo message
363 * @param data input data buffer with the encode NTLM targetinfo message
364 * @param ucs2 if the strings should be encoded with ucs2 (selected by flag in message).
365 * @param ti the decoded target info, should be freed with heim_ntlm_free_targetinfo().
367 * @return In case of success 0 is return, an errors, a errno in what
374 heim_ntlm_decode_targetinfo(const struct ntlm_buf
*data
,
376 struct ntlm_targetinfo
*ti
)
378 memset(ti
, 0, sizeof(*ti
));
383 * Frees the ntlm_type1 message
385 * @param data message to be freed
391 heim_ntlm_free_type1(struct ntlm_type1
*data
)
396 free(data
->hostname
);
397 memset(data
, 0, sizeof(*data
));
401 heim_ntlm_decode_type1(const struct ntlm_buf
*buf
, struct ntlm_type1
*data
)
404 unsigned char sig
[8];
406 struct sec_buffer domain
, hostname
;
409 memset(data
, 0, sizeof(*data
));
411 in
= krb5_storage_from_readonly_mem(buf
->data
, buf
->length
);
416 krb5_storage_set_byteorder(in
, KRB5_STORAGE_BYTEORDER_LE
);
418 CHECK(krb5_storage_read(in
, sig
, sizeof(sig
)), sizeof(sig
));
419 CHECK(memcmp(ntlmsigature
, sig
, sizeof(ntlmsigature
)), 0);
420 CHECK(krb5_ret_uint32(in
, &type
), 0);
422 CHECK(krb5_ret_uint32(in
, &data
->flags
), 0);
423 if (data
->flags
& NTLM_OEM_SUPPLIED_DOMAIN
)
424 CHECK(ret_sec_buffer(in
, &domain
), 0);
425 if (data
->flags
& NTLM_OEM_SUPPLIED_WORKSTAION
)
426 CHECK(ret_sec_buffer(in
, &hostname
), 0);
428 if (domain
.offset
> 32) {
429 CHECK(krb5_ret_uint32(in
, &data
->os
[0]), 0);
430 CHECK(krb5_ret_uint32(in
, &data
->os
[1]), 0);
433 if (data
->flags
& NTLM_OEM_SUPPLIED_DOMAIN
)
434 CHECK(ret_string(in
, 0, &domain
, &data
->domain
), 0);
435 if (data
->flags
& NTLM_OEM_SUPPLIED_WORKSTAION
)
436 CHECK(ret_string(in
, 0, &hostname
, &data
->hostname
), 0);
440 krb5_storage_free(in
);
442 heim_ntlm_free_type1(data
);
448 * Encodes an ntlm_type1 message.
450 * @param type1 the ntlm_type1 message to encode.
451 * @param data is the return buffer with the encoded message, should be
452 * freed with heim_ntlm_free_buf().
454 * @return In case of success 0 is return, an errors, a errno in what
461 heim_ntlm_encode_type1(const struct ntlm_type1
*type1
, struct ntlm_buf
*data
)
464 struct sec_buffer domain
, hostname
;
466 uint32_t base
, flags
;
468 flags
= type1
->flags
;
473 flags
|= NTLM_OEM_SUPPLIED_DOMAIN
;
475 if (type1
->hostname
) {
477 flags
|= NTLM_OEM_SUPPLIED_WORKSTAION
;
483 domain
.offset
= base
;
484 domain
.length
= len_string(0, type1
->domain
);
485 domain
.allocated
= domain
.length
;
489 domain
.allocated
= 0;
491 if (type1
->hostname
) {
492 hostname
.offset
= domain
.allocated
+ domain
.offset
;
493 hostname
.length
= len_string(0, type1
->hostname
);
494 hostname
.allocated
= hostname
.length
;
497 out
= krb5_storage_emem();
501 krb5_storage_set_byteorder(out
, KRB5_STORAGE_BYTEORDER_LE
);
502 CHECK(krb5_storage_write(out
, ntlmsigature
, sizeof(ntlmsigature
)),
503 sizeof(ntlmsigature
));
504 CHECK(krb5_store_uint32(out
, 1), 0);
505 CHECK(krb5_store_uint32(out
, flags
), 0);
508 CHECK(store_sec_buffer(out
, &domain
), 0);
510 CHECK(store_sec_buffer(out
, &hostname
), 0);
512 CHECK(krb5_store_uint32(out
, type1
->os
[0]), 0);
513 CHECK(krb5_store_uint32(out
, type1
->os
[1]), 0);
516 CHECK(put_string(out
, 0, type1
->domain
), 0);
518 CHECK(put_string(out
, 0, type1
->hostname
), 0);
522 ret
= krb5_storage_to_data(out
, &d
);
524 data
->length
= d
.length
;
527 krb5_storage_free(out
);
533 * Frees the ntlm_type2 message
535 * @param data message to be freed
541 heim_ntlm_free_type2(struct ntlm_type2
*data
)
543 if (data
->targetname
)
544 free(data
->targetname
);
545 heim_ntlm_free_buf(&data
->targetinfo
);
546 memset(data
, 0, sizeof(*data
));
550 heim_ntlm_decode_type2(const struct ntlm_buf
*buf
, struct ntlm_type2
*type2
)
553 unsigned char sig
[8];
554 uint32_t type
, ctx
[2];
555 struct sec_buffer targetname
, targetinfo
;
559 memset(type2
, 0, sizeof(*type2
));
561 in
= krb5_storage_from_readonly_mem(buf
->data
, buf
->length
);
566 krb5_storage_set_byteorder(in
, KRB5_STORAGE_BYTEORDER_LE
);
568 CHECK(krb5_storage_read(in
, sig
, sizeof(sig
)), sizeof(sig
));
569 CHECK(memcmp(ntlmsigature
, sig
, sizeof(ntlmsigature
)), 0);
570 CHECK(krb5_ret_uint32(in
, &type
), 0);
573 CHECK(ret_sec_buffer(in
, &targetname
), 0);
574 CHECK(krb5_ret_uint32(in
, &type2
->flags
), 0);
575 if (type2
->flags
& NTLM_NEG_UNICODE
)
577 CHECK(krb5_storage_read(in
, type2
->challange
, sizeof(type2
->challange
)),
578 sizeof(type2
->challange
));
579 CHECK(krb5_ret_uint32(in
, &ctx
[0]), 0); /* context */
580 CHECK(krb5_ret_uint32(in
, &ctx
[1]), 0);
581 CHECK(ret_sec_buffer(in
, &targetinfo
), 0);
584 CHECK(krb5_ret_uint32(in
, &type2
->os
[0]), 0);
585 CHECK(krb5_ret_uint32(in
, &type2
->os
[1]), 0);
588 CHECK(ret_string(in
, ucs2
, &targetname
, &type2
->targetname
), 0);
589 CHECK(ret_buf(in
, &targetinfo
, &type2
->targetinfo
), 0);
594 krb5_storage_free(in
);
596 heim_ntlm_free_type2(type2
);
602 * Encodes an ntlm_type2 message.
604 * @param type2 the ntlm_type2 message to encode.
605 * @param data is the return buffer with the encoded message, should be
606 * freed with heim_ntlm_free_buf().
608 * @return In case of success 0 is return, an errors, a errno in what
615 heim_ntlm_encode_type2(const struct ntlm_type2
*type2
, struct ntlm_buf
*data
)
617 struct sec_buffer targetname
, targetinfo
;
619 krb5_storage
*out
= NULL
;
628 if (type2
->flags
& NTLM_NEG_UNICODE
)
631 targetname
.offset
= base
;
632 targetname
.length
= len_string(ucs2
, type2
->targetname
);
633 targetname
.allocated
= targetname
.length
;
635 targetinfo
.offset
= targetname
.allocated
+ targetname
.offset
;
636 targetinfo
.length
= type2
->targetinfo
.length
;
637 targetinfo
.allocated
= type2
->targetinfo
.length
;
639 out
= krb5_storage_emem();
643 krb5_storage_set_byteorder(out
, KRB5_STORAGE_BYTEORDER_LE
);
644 CHECK(krb5_storage_write(out
, ntlmsigature
, sizeof(ntlmsigature
)),
645 sizeof(ntlmsigature
));
646 CHECK(krb5_store_uint32(out
, 2), 0);
647 CHECK(store_sec_buffer(out
, &targetname
), 0);
648 CHECK(krb5_store_uint32(out
, type2
->flags
), 0);
649 CHECK(krb5_storage_write(out
, type2
->challange
, sizeof(type2
->challange
)),
650 sizeof(type2
->challange
));
651 CHECK(krb5_store_uint32(out
, 0), 0); /* context */
652 CHECK(krb5_store_uint32(out
, 0), 0);
653 CHECK(store_sec_buffer(out
, &targetinfo
), 0);
656 CHECK(krb5_store_uint32(out
, type2
->os
[0]), 0);
657 CHECK(krb5_store_uint32(out
, type2
->os
[1]), 0);
659 CHECK(put_string(out
, ucs2
, type2
->targetname
), 0);
660 CHECK(krb5_storage_write(out
, type2
->targetinfo
.data
,
661 type2
->targetinfo
.length
),
662 type2
->targetinfo
.length
);
666 ret
= krb5_storage_to_data(out
, &d
);
668 data
->length
= d
.length
;
672 krb5_storage_free(out
);
678 * Frees the ntlm_type3 message
680 * @param data message to be freed
686 heim_ntlm_free_type3(struct ntlm_type3
*data
)
688 heim_ntlm_free_buf(&data
->lm
);
689 heim_ntlm_free_buf(&data
->ntlm
);
690 if (data
->targetname
)
691 free(data
->targetname
);
693 free(data
->username
);
696 heim_ntlm_free_buf(&data
->sessionkey
);
697 memset(data
, 0, sizeof(*data
));
705 heim_ntlm_decode_type3(const struct ntlm_buf
*buf
,
707 struct ntlm_type3
*type3
)
710 unsigned char sig
[8];
713 struct sec_buffer lm
, ntlm
, target
, username
, sessionkey
, ws
;
715 memset(type3
, 0, sizeof(*type3
));
716 memset(&sessionkey
, 0, sizeof(sessionkey
));
718 in
= krb5_storage_from_readonly_mem(buf
->data
, buf
->length
);
723 krb5_storage_set_byteorder(in
, KRB5_STORAGE_BYTEORDER_LE
);
725 CHECK(krb5_storage_read(in
, sig
, sizeof(sig
)), sizeof(sig
));
726 CHECK(memcmp(ntlmsigature
, sig
, sizeof(ntlmsigature
)), 0);
727 CHECK(krb5_ret_uint32(in
, &type
), 0);
729 CHECK(ret_sec_buffer(in
, &lm
), 0);
730 CHECK(ret_sec_buffer(in
, &ntlm
), 0);
731 CHECK(ret_sec_buffer(in
, &target
), 0);
732 CHECK(ret_sec_buffer(in
, &username
), 0);
733 CHECK(ret_sec_buffer(in
, &ws
), 0);
734 if (lm
.offset
>= 60) {
735 CHECK(ret_sec_buffer(in
, &sessionkey
), 0);
737 if (lm
.offset
>= 64) {
738 CHECK(krb5_ret_uint32(in
, &type3
->flags
), 0);
740 if (lm
.offset
>= 72) {
741 CHECK(krb5_ret_uint32(in
, &type3
->os
[0]), 0);
742 CHECK(krb5_ret_uint32(in
, &type3
->os
[1]), 0);
744 CHECK(ret_buf(in
, &lm
, &type3
->lm
), 0);
745 CHECK(ret_buf(in
, &ntlm
, &type3
->ntlm
), 0);
746 CHECK(ret_string(in
, ucs2
, &target
, &type3
->targetname
), 0);
747 CHECK(ret_string(in
, ucs2
, &username
, &type3
->username
), 0);
748 CHECK(ret_string(in
, ucs2
, &ws
, &type3
->ws
), 0);
749 if (sessionkey
.offset
)
750 CHECK(ret_buf(in
, &sessionkey
, &type3
->sessionkey
), 0);
754 krb5_storage_free(in
);
756 heim_ntlm_free_type3(type3
);
762 * Encodes an ntlm_type3 message.
764 * @param type3 the ntlm_type3 message to encode.
765 * @param data is the return buffer with the encoded message, should be
766 * freed with heim_ntlm_free_buf().
768 * @return In case of success 0 is return, an errors, a errno in what
775 heim_ntlm_encode_type3(const struct ntlm_type3
*type3
, struct ntlm_buf
*data
)
777 struct sec_buffer lm
, ntlm
, target
, username
, sessionkey
, ws
;
779 krb5_storage
*out
= NULL
;
783 memset(&lm
, 0, sizeof(lm
));
784 memset(&ntlm
, 0, sizeof(ntlm
));
785 memset(&target
, 0, sizeof(target
));
786 memset(&username
, 0, sizeof(username
));
787 memset(&ws
, 0, sizeof(ws
));
788 memset(&sessionkey
, 0, sizeof(sessionkey
));
791 if (type3
->sessionkey
.length
) {
792 base
+= 8; /* sessionkey sec buf */
793 base
+= 4; /* flags */
799 if (type3
->flags
& NTLM_NEG_UNICODE
)
803 lm
.length
= type3
->lm
.length
;
804 lm
.allocated
= type3
->lm
.length
;
806 ntlm
.offset
= lm
.offset
+ lm
.allocated
;
807 ntlm
.length
= type3
->ntlm
.length
;
808 ntlm
.allocated
= ntlm
.length
;
810 target
.offset
= ntlm
.offset
+ ntlm
.allocated
;
811 target
.length
= len_string(ucs2
, type3
->targetname
);
812 target
.allocated
= target
.length
;
814 username
.offset
= target
.offset
+ target
.allocated
;
815 username
.length
= len_string(ucs2
, type3
->username
);
816 username
.allocated
= username
.length
;
818 ws
.offset
= username
.offset
+ username
.allocated
;
819 ws
.length
= len_string(ucs2
, type3
->ws
);
820 ws
.allocated
= ws
.length
;
822 sessionkey
.offset
= ws
.offset
+ ws
.allocated
;
823 sessionkey
.length
= type3
->sessionkey
.length
;
824 sessionkey
.allocated
= type3
->sessionkey
.length
;
826 out
= krb5_storage_emem();
830 krb5_storage_set_byteorder(out
, KRB5_STORAGE_BYTEORDER_LE
);
831 CHECK(krb5_storage_write(out
, ntlmsigature
, sizeof(ntlmsigature
)),
832 sizeof(ntlmsigature
));
833 CHECK(krb5_store_uint32(out
, 3), 0);
835 CHECK(store_sec_buffer(out
, &lm
), 0);
836 CHECK(store_sec_buffer(out
, &ntlm
), 0);
837 CHECK(store_sec_buffer(out
, &target
), 0);
838 CHECK(store_sec_buffer(out
, &username
), 0);
839 CHECK(store_sec_buffer(out
, &ws
), 0);
841 if (type3
->sessionkey
.length
) {
842 CHECK(store_sec_buffer(out
, &sessionkey
), 0);
843 CHECK(krb5_store_uint32(out
, type3
->flags
), 0);
846 CHECK(krb5_store_uint32(out
, 0), 0); /* os0 */
847 CHECK(krb5_store_uint32(out
, 0), 0); /* os1 */
850 CHECK(put_buf(out
, &type3
->lm
), 0);
851 CHECK(put_buf(out
, &type3
->ntlm
), 0);
852 CHECK(put_string(out
, ucs2
, type3
->targetname
), 0);
853 CHECK(put_string(out
, ucs2
, type3
->username
), 0);
854 CHECK(put_string(out
, ucs2
, type3
->ws
), 0);
855 CHECK(put_buf(out
, &type3
->sessionkey
), 0);
859 ret
= krb5_storage_to_data(out
, &d
);
861 data
->length
= d
.length
;
865 krb5_storage_free(out
);
876 splitandenc(unsigned char *hash
,
877 unsigned char *challange
,
878 unsigned char *answer
)
881 unsigned char key
[8];
884 key
[1] = (hash
[0] << 7) | (hash
[1] >> 1);
885 key
[2] = (hash
[1] << 6) | (hash
[2] >> 2);
886 key
[3] = (hash
[2] << 5) | (hash
[3] >> 3);
887 key
[4] = (hash
[3] << 4) | (hash
[4] >> 4);
888 key
[5] = (hash
[4] << 3) | (hash
[5] >> 5);
889 key
[6] = (hash
[5] << 2) | (hash
[6] >> 6);
890 key
[7] = (hash
[6] << 1);
892 EVP_CIPHER_CTX_init(&ctx
);
894 EVP_CipherInit_ex(&ctx
, EVP_des_cbc(), NULL
, key
, NULL
, 1);
895 EVP_Cipher(&ctx
, answer
, challange
, 8);
896 EVP_CIPHER_CTX_cleanup(&ctx
);
897 memset(key
, 0, sizeof(key
));
901 * Calculate the NTLM key, the password is assumed to be in UTF8.
903 * @param password password to calcute the key for.
904 * @param key calcuted key, should be freed with heim_ntlm_free_buf().
906 * @return In case of success 0 is return, an errors, a errno in what
913 heim_ntlm_nt_key(const char *password
, struct ntlm_buf
*key
)
919 key
->data
= malloc(MD5_DIGEST_LENGTH
);
920 if (key
->data
== NULL
)
922 key
->length
= MD5_DIGEST_LENGTH
;
924 ret
= ascii2ucs2le(password
, 0, &buf
);
926 heim_ntlm_free_buf(key
);
930 m
= EVP_MD_CTX_create();
932 heim_ntlm_free_buf(key
);
933 heim_ntlm_free_buf(&buf
);
937 EVP_DigestInit_ex(m
, EVP_md4(), NULL
);
938 EVP_DigestUpdate(m
, buf
.data
, buf
.length
);
939 EVP_DigestFinal_ex(m
, key
->data
, NULL
);
940 EVP_MD_CTX_destroy(m
);
942 heim_ntlm_free_buf(&buf
);
947 * Calculate NTLMv1 response hash
949 * @param key the ntlm v1 key
950 * @param len length of key
951 * @param challange sent by the server
952 * @param answer calculated answer, should be freed with heim_ntlm_free_buf().
954 * @return In case of success 0 is return, an errors, a errno in what
961 heim_ntlm_calculate_ntlm1(void *key
, size_t len
,
962 unsigned char challange
[8],
963 struct ntlm_buf
*answer
)
965 unsigned char res
[21];
967 if (len
!= MD4_DIGEST_LENGTH
)
970 memcpy(res
, key
, len
);
971 memset(&res
[MD4_DIGEST_LENGTH
], 0, sizeof(res
) - MD4_DIGEST_LENGTH
);
973 answer
->data
= malloc(24);
974 if (answer
->data
== NULL
)
978 splitandenc(&res
[0], challange
, ((unsigned char *)answer
->data
) + 0);
979 splitandenc(&res
[7], challange
, ((unsigned char *)answer
->data
) + 8);
980 splitandenc(&res
[14], challange
, ((unsigned char *)answer
->data
) + 16);
986 * Generates an NTLMv1 session random with assosited session master key.
988 * @param key the ntlm v1 key
989 * @param len length of key
990 * @param session generated session nonce, should be freed with heim_ntlm_free_buf().
991 * @param master calculated session master key, should be freed with heim_ntlm_free_buf().
993 * @return In case of success 0 is return, an errors, a errno in what
1000 heim_ntlm_build_ntlm1_master(void *key
, size_t len
,
1001 struct ntlm_buf
*session
,
1002 struct ntlm_buf
*master
)
1006 memset(master
, 0, sizeof(*master
));
1007 memset(session
, 0, sizeof(*session
));
1009 if (len
!= MD4_DIGEST_LENGTH
)
1012 session
->length
= MD4_DIGEST_LENGTH
;
1013 session
->data
= malloc(session
->length
);
1014 if (session
->data
== NULL
) {
1015 session
->length
= 0;
1018 master
->length
= MD4_DIGEST_LENGTH
;
1019 master
->data
= malloc(master
->length
);
1020 if (master
->data
== NULL
) {
1021 heim_ntlm_free_buf(master
);
1022 heim_ntlm_free_buf(session
);
1026 EVP_CIPHER_CTX_init(&c
);
1029 unsigned char sessionkey
[MD4_DIGEST_LENGTH
];
1032 m
= EVP_MD_CTX_create();
1034 EVP_CIPHER_CTX_cleanup(&c
);
1035 heim_ntlm_free_buf(master
);
1036 heim_ntlm_free_buf(session
);
1040 EVP_DigestInit_ex(m
, EVP_md4(), NULL
);
1041 EVP_DigestUpdate(m
, key
, len
);
1042 EVP_DigestFinal_ex(m
, sessionkey
, NULL
);
1043 EVP_MD_CTX_destroy(m
);
1045 if (EVP_CipherInit_ex(&c
, EVP_rc4(), NULL
, sessionkey
, NULL
, 1) != 1) {
1046 EVP_CIPHER_CTX_cleanup(&c
);
1047 heim_ntlm_free_buf(master
);
1048 heim_ntlm_free_buf(session
);
1053 if (RAND_bytes(session
->data
, session
->length
) != 1) {
1054 EVP_CIPHER_CTX_cleanup(&c
);
1055 heim_ntlm_free_buf(master
);
1056 heim_ntlm_free_buf(session
);
1060 EVP_Cipher(&c
, master
->data
, session
->data
, master
->length
);
1061 EVP_CIPHER_CTX_cleanup(&c
);
1067 * Generates an NTLMv2 session key.
1069 * @param key the ntlm key
1070 * @param len length of key
1071 * @param username name of the user, as sent in the message, assumed to be in UTF8.
1072 * @param target the name of the target, assumed to be in UTF8.
1073 * @param ntlmv2 the ntlmv2 session key
1075 * @return 0 on success, or an error code on failure.
1077 * @ingroup ntlm_core
1081 heim_ntlm_ntlmv2_key(const void *key
, size_t len
,
1082 const char *username
,
1084 unsigned char ntlmv2
[16])
1087 unsigned int hmaclen
;
1091 HMAC_Init_ex(&c
, key
, len
, EVP_md5(), NULL
);
1093 struct ntlm_buf buf
;
1094 /* uppercase username and turn it into ucs2-le */
1095 ret
= ascii2ucs2le(username
, 1, &buf
);
1098 HMAC_Update(&c
, buf
.data
, buf
.length
);
1100 /* uppercase target and turn into ucs2-le */
1101 ret
= ascii2ucs2le(target
, 1, &buf
);
1104 HMAC_Update(&c
, buf
.data
, buf
.length
);
1107 HMAC_Final(&c
, ntlmv2
, &hmaclen
);
1109 HMAC_CTX_cleanup(&c
);
1118 #define NTTIME_EPOCH 0x019DB1DED53E8000LL
1121 unix2nttime(time_t unix_time
)
1124 wt
= unix_time
* (uint64_t)10000000 + (uint64_t)NTTIME_EPOCH
;
1129 nt2unixtime(uint64_t t
)
1131 t
= ((t
- (uint64_t)NTTIME_EPOCH
) / (uint64_t)10000000);
1132 if (t
> (((time_t)(~(uint64_t)0)) >> 1))
1139 * Calculate NTLMv2 response
1141 * @param key the ntlm key
1142 * @param len length of key
1143 * @param username name of the user, as sent in the message, assumed to be in UTF8.
1144 * @param target the name of the target, assumed to be in UTF8.
1145 * @param serverchallange challange as sent by the server in the type2 message.
1146 * @param infotarget infotarget as sent by the server in the type2 message.
1147 * @param ntlmv2 calculated session key
1148 * @param answer ntlm response answer, should be freed with heim_ntlm_free_buf().
1150 * @return In case of success 0 is return, an errors, a errno in what
1153 * @ingroup ntlm_core
1157 heim_ntlm_calculate_ntlm2(const void *key
, size_t len
,
1158 const char *username
,
1160 const unsigned char serverchallange
[8],
1161 const struct ntlm_buf
*infotarget
,
1162 unsigned char ntlmv2
[16],
1163 struct ntlm_buf
*answer
)
1165 krb5_error_code ret
;
1167 unsigned int hmaclen
;
1168 unsigned char ntlmv2answer
[16];
1170 unsigned char clientchallange
[8];
1174 t
= unix2nttime(time(NULL
));
1176 if (RAND_bytes(clientchallange
, sizeof(clientchallange
)) != 1)
1179 /* calculate ntlmv2 key */
1181 heim_ntlm_ntlmv2_key(key
, len
, username
, target
, ntlmv2
);
1183 /* calculate and build ntlmv2 answer */
1185 sp
= krb5_storage_emem();
1188 krb5_storage_set_flags(sp
, KRB5_STORAGE_BYTEORDER_LE
);
1190 CHECK(krb5_store_uint32(sp
, 0x00000101), 0);
1191 CHECK(krb5_store_uint32(sp
, 0), 0);
1192 /* timestamp le 64 bit ts */
1193 CHECK(krb5_store_uint32(sp
, t
& 0xffffffff), 0);
1194 CHECK(krb5_store_uint32(sp
, t
>> 32), 0);
1196 CHECK(krb5_storage_write(sp
, clientchallange
, 8), 8);
1198 CHECK(krb5_store_uint32(sp
, 0), 0); /* unknown but zero will work */
1199 CHECK(krb5_storage_write(sp
, infotarget
->data
, infotarget
->length
),
1200 infotarget
->length
);
1201 CHECK(krb5_store_uint32(sp
, 0), 0); /* unknown but zero will work */
1203 CHECK(krb5_storage_to_data(sp
, &data
), 0);
1204 krb5_storage_free(sp
);
1208 HMAC_Init_ex(&c
, ntlmv2
, 16, EVP_md5(), NULL
);
1209 HMAC_Update(&c
, serverchallange
, 8);
1210 HMAC_Update(&c
, data
.data
, data
.length
);
1211 HMAC_Final(&c
, ntlmv2answer
, &hmaclen
);
1212 HMAC_CTX_cleanup(&c
);
1214 sp
= krb5_storage_emem();
1216 krb5_data_free(&data
);
1220 CHECK(krb5_storage_write(sp
, ntlmv2answer
, 16), 16);
1221 CHECK(krb5_storage_write(sp
, data
.data
, data
.length
), data
.length
);
1222 krb5_data_free(&data
);
1224 CHECK(krb5_storage_to_data(sp
, &data
), 0);
1225 krb5_storage_free(sp
);
1228 answer
->data
= data
.data
;
1229 answer
->length
= data
.length
;
1234 krb5_storage_free(sp
);
1238 static const int authtimediff
= 3600 * 2; /* 2 hours */
1241 * Verify NTLMv2 response.
1243 * @param key the ntlm key
1244 * @param len length of key
1245 * @param username name of the user, as sent in the message, assumed to be in UTF8.
1246 * @param target the name of the target, assumed to be in UTF8.
1247 * @param now the time now (0 if the library should pick it up itself)
1248 * @param serverchallange challange as sent by the server in the type2 message.
1249 * @param answer ntlm response answer, should be freed with heim_ntlm_free_buf().
1250 * @param infotarget infotarget as sent by the server in the type2 message.
1251 * @param ntlmv2 calculated session key
1253 * @return In case of success 0 is return, an errors, a errno in what
1256 * @ingroup ntlm_core
1260 heim_ntlm_verify_ntlm2(const void *key
, size_t len
,
1261 const char *username
,
1264 const unsigned char serverchallange
[8],
1265 const struct ntlm_buf
*answer
,
1266 struct ntlm_buf
*infotarget
,
1267 unsigned char ntlmv2
[16])
1269 krb5_error_code ret
;
1270 unsigned int hmaclen
;
1271 unsigned char clientanswer
[16];
1272 unsigned char clientnonce
[8];
1273 unsigned char serveranswer
[16];
1280 infotarget
->length
= 0;
1281 infotarget
->data
= NULL
;
1283 if (answer
->length
< 16)
1289 /* calculate ntlmv2 key */
1291 heim_ntlm_ntlmv2_key(key
, len
, username
, target
, ntlmv2
);
1293 /* calculate and build ntlmv2 answer */
1295 sp
= krb5_storage_from_readonly_mem(answer
->data
, answer
->length
);
1298 krb5_storage_set_flags(sp
, KRB5_STORAGE_BYTEORDER_LE
);
1300 CHECK(krb5_storage_read(sp
, clientanswer
, 16), 16);
1302 CHECK(krb5_ret_uint32(sp
, &temp
), 0);
1303 CHECK(temp
, 0x00000101);
1304 CHECK(krb5_ret_uint32(sp
, &temp
), 0);
1306 /* timestamp le 64 bit ts */
1307 CHECK(krb5_ret_uint32(sp
, &temp
), 0);
1309 CHECK(krb5_ret_uint32(sp
, &temp
), 0);
1310 t
|= ((uint64_t)temp
)<< 32;
1312 authtime
= nt2unixtime(t
);
1314 if (abs((int)(authtime
- now
)) > authtimediff
) {
1319 /* client challange */
1320 CHECK(krb5_storage_read(sp
, clientnonce
, 8), 8);
1322 CHECK(krb5_ret_uint32(sp
, &temp
), 0); /* unknown */
1324 /* should really unparse the infotarget, but lets pick up everything */
1325 infotarget
->length
= answer
->length
- krb5_storage_seek(sp
, 0, SEEK_CUR
);
1326 infotarget
->data
= malloc(infotarget
->length
);
1327 if (infotarget
->data
== NULL
) {
1331 CHECK(krb5_storage_read(sp
, infotarget
->data
, infotarget
->length
),
1332 infotarget
->length
);
1333 /* XXX remove the unknown ?? */
1334 krb5_storage_free(sp
);
1338 HMAC_Init_ex(&c
, ntlmv2
, 16, EVP_md5(), NULL
);
1339 HMAC_Update(&c
, serverchallange
, 8);
1340 HMAC_Update(&c
, ((unsigned char *)answer
->data
) + 16, answer
->length
- 16);
1341 HMAC_Final(&c
, serveranswer
, &hmaclen
);
1342 HMAC_CTX_cleanup(&c
);
1344 if (memcmp(serveranswer
, clientanswer
, 16) != 0) {
1345 heim_ntlm_free_buf(infotarget
);
1351 heim_ntlm_free_buf(infotarget
);
1353 krb5_storage_free(sp
);
1359 * Calculate the NTLM2 Session Response
1361 * @param clnt_nonce client nonce
1362 * @param svr_chal server challage
1363 * @param ntlm2_hash ntlm hash
1364 * @param lm The LM response, should be freed with heim_ntlm_free_buf().
1365 * @param ntlm The NTLM response, should be freed with heim_ntlm_free_buf().
1367 * @return In case of success 0 is return, an errors, a errno in what
1370 * @ingroup ntlm_core
1374 heim_ntlm_calculate_ntlm2_sess(const unsigned char clnt_nonce
[8],
1375 const unsigned char svr_chal
[8],
1376 const unsigned char ntlm_hash
[16],
1377 struct ntlm_buf
*lm
,
1378 struct ntlm_buf
*ntlm
)
1380 unsigned char ntlm2_sess_hash
[MD5_DIGEST_LENGTH
];
1381 unsigned char res
[21], *resp
;
1384 m
= EVP_MD_CTX_create();
1388 lm
->data
= malloc(24);
1389 if (lm
->data
== NULL
) {
1390 EVP_MD_CTX_destroy(m
);
1395 ntlm
->data
= malloc(24);
1396 if (ntlm
->data
== NULL
) {
1397 EVP_MD_CTX_destroy(m
);
1404 /* first setup the lm resp */
1405 memset(lm
->data
, 0, 24);
1406 memcpy(lm
->data
, clnt_nonce
, 8);
1408 EVP_DigestInit_ex(m
, EVP_md5(), NULL
);
1409 EVP_DigestUpdate(m
, svr_chal
, 8); /* session nonce part 1 */
1410 EVP_DigestUpdate(m
, clnt_nonce
, 8); /* session nonce part 2 */
1411 EVP_DigestFinal_ex(m
, ntlm2_sess_hash
, NULL
); /* will only use first 8 bytes */
1412 EVP_MD_CTX_destroy(m
);
1414 memset(res
, 0, sizeof(res
));
1415 memcpy(res
, ntlm_hash
, 16);
1418 splitandenc(&res
[0], ntlm2_sess_hash
, resp
+ 0);
1419 splitandenc(&res
[7], ntlm2_sess_hash
, resp
+ 8);
1420 splitandenc(&res
[14], ntlm2_sess_hash
, resp
+ 16);