/* [<][>][^][v][top][bottom][index][help] */
DEFINITIONS
This source file includes following definitions.
- heim_ntlm_free_buf
- ascii2ucs2le
- ret_sec_buffer
- store_sec_buffer
- len_string
- ret_string
- put_string
- ret_buf
- put_buf
- heim_ntlm_free_targetinfo
- encode_ti_blob
- heim_ntlm_encode_targetinfo
- heim_ntlm_decode_targetinfo
- heim_ntlm_free_type1
- heim_ntlm_decode_type1
- heim_ntlm_encode_type1
- heim_ntlm_free_type2
- heim_ntlm_decode_type2
- heim_ntlm_encode_type2
- heim_ntlm_free_type3
- heim_ntlm_decode_type3
- heim_ntlm_encode_type3
- splitandenc
- heim_ntlm_nt_key
- heim_ntlm_calculate_ntlm1
- heim_ntlm_build_ntlm1_master
- heim_ntlm_ntlmv2_key
- unix2nttime
- nt2unixtime
- heim_ntlm_calculate_ntlm2
- heim_ntlm_verify_ntlm2
- heim_ntlm_calculate_ntlm2_sess
1 /*
2 * Copyright (c) 2006 - 2008 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 *
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.
16 *
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.
20 *
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
31 * SUCH DAMAGE.
32 */
33
34 #include <config.h>
35
36 RCSID("$Id$");
37
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <assert.h>
41 #include <string.h>
42 #include <ctype.h>
43 #include <errno.h>
44 #include <limits.h>
45
46 #include <krb5.h>
47 #include <roken.h>
48
49 #define HC_DEPRECATED_CRYPTO
50
51 #include "krb5-types.h"
52 #include "crypto-headers.h"
53
54 #include <heimntlm.h>
55
56 /*! \mainpage Heimdal NTLM library
57 *
58 * \section intro Introduction
59 *
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
63 * checking.
64 *
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.
68 *
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).
74 *
75 * More information about the NTLM protocol can found here
76 * http://davenport.sourceforge.net/ntlm.html .
77 *
78 * The Heimdal projects web page: http://www.h5l.org/
79 *
80 * @section ntlm_example NTLM Example
81 *
82 * Example to to use @ref test_ntlm.c .
83 *
84 * @example test_ntlm.c
85 *
86 * Example how to use the NTLM primitives.
87 *
88 */
89
90 /** @defgroup ntlm_core Heimdal NTLM library
91 *
92 * The NTLM core functions implement the string2key generation
93 * function, message encode and decode function, and the hash function
94 * functions.
95 */
96
97 struct sec_buffer {
98 uint16_t length;
99 uint16_t allocated;
100 uint32_t offset;
101 };
102
103 static const unsigned char ntlmsigature[8] = "NTLMSSP\x00";
104
105 /*
106 *
107 */
108
109 #define CHECK(f, e) \
110 do { ret = f ; if (ret != (e)) { ret = EINVAL; goto out; } } while(0)
111
112 /**
113 * heim_ntlm_free_buf frees the ntlm buffer
114 *
115 * @param p buffer to be freed
116 *
117 * @ingroup ntlm_core
118 */
119
120 void
121 heim_ntlm_free_buf(struct ntlm_buf *p)
/* [<][>][^][v][top][bottom][index][help] */
122 {
123 if (p->data)
124 free(p->data);
125 p->data = NULL;
126 p->length = 0;
127 }
128
129
130 static int
131 ascii2ucs2le(const char *string, int up, struct ntlm_buf *buf)
/* [<][>][^][v][top][bottom][index][help] */
132 {
133 unsigned char *p;
134 size_t len, i;
135
136 len = strlen(string);
137 if (len / 2 > UINT_MAX)
138 return ERANGE;
139
140 buf->length = len * 2;
141 buf->data = malloc(buf->length);
142 if (buf->data == NULL && len != 0) {
143 heim_ntlm_free_buf(buf);
144 return ENOMEM;
145 }
146
147 p = buf->data;
148 for (i = 0; i < len; i++) {
149 unsigned char t = (unsigned char)string[i];
150 if (t & 0x80) {
151 heim_ntlm_free_buf(buf);
152 return EINVAL;
153 }
154 if (up)
155 t = toupper(t);
156 p[(i * 2) + 0] = t;
157 p[(i * 2) + 1] = 0;
158 }
159 return 0;
160 }
161
162 /*
163 *
164 */
165
166 static krb5_error_code
167 ret_sec_buffer(krb5_storage *sp, struct sec_buffer *buf)
/* [<][>][^][v][top][bottom][index][help] */
168 {
169 krb5_error_code ret;
170 CHECK(krb5_ret_uint16(sp, &buf->length), 0);
171 CHECK(krb5_ret_uint16(sp, &buf->allocated), 0);
172 CHECK(krb5_ret_uint32(sp, &buf->offset), 0);
173 out:
174 return ret;
175 }
176
177 static krb5_error_code
178 store_sec_buffer(krb5_storage *sp, const struct sec_buffer *buf)
/* [<][>][^][v][top][bottom][index][help] */
179 {
180 krb5_error_code ret;
181 CHECK(krb5_store_uint16(sp, buf->length), 0);
182 CHECK(krb5_store_uint16(sp, buf->allocated), 0);
183 CHECK(krb5_store_uint32(sp, buf->offset), 0);
184 out:
185 return ret;
186 }
187
188 /*
189 * Strings are either OEM or UNICODE. The later is encoded as ucs2 on
190 * wire, but using utf8 in memory.
191 */
192
193 static krb5_error_code
194 len_string(int ucs2, const char *s)
/* [<][>][^][v][top][bottom][index][help] */
195 {
196 size_t len = strlen(s);
197 if (ucs2)
198 len *= 2;
199 return len;
200 }
201
202 static krb5_error_code
203 ret_string(krb5_storage *sp, int ucs2, struct sec_buffer *desc, char **s)
/* [<][>][^][v][top][bottom][index][help] */
204 {
205 krb5_error_code ret;
206
207 *s = malloc(desc->length + 1);
208 CHECK(krb5_storage_seek(sp, desc->offset, SEEK_SET), desc->offset);
209 CHECK(krb5_storage_read(sp, *s, desc->length), desc->length);
210 (*s)[desc->length] = '\0';
211
212 if (ucs2) {
213 size_t i;
214 for (i = 0; i < desc->length / 2; i++) {
215 (*s)[i] = (*s)[i * 2];
216 if ((*s)[i * 2 + 1]) {
217 free(*s);
218 *s = NULL;
219 return EINVAL;
220 }
221 }
222 (*s)[i] = '\0';
223 }
224 ret = 0;
225 out:
226 return ret;
227
228 return 0;
229 }
230
231 static krb5_error_code
232 put_string(krb5_storage *sp, int ucs2, const char *s)
/* [<][>][^][v][top][bottom][index][help] */
233 {
234 krb5_error_code ret;
235 struct ntlm_buf buf;
236
237 if (ucs2) {
238 ret = ascii2ucs2le(s, 0, &buf);
239 if (ret)
240 return ret;
241 } else {
242 buf.data = rk_UNCONST(s);
243 buf.length = strlen(s);
244 }
245
246 CHECK(krb5_storage_write(sp, buf.data, buf.length), buf.length);
247 if (ucs2)
248 heim_ntlm_free_buf(&buf);
249 ret = 0;
250 out:
251 return ret;
252 }
253
254 /*
255 *
256 */
257
258 static krb5_error_code
259 ret_buf(krb5_storage *sp, struct sec_buffer *desc, struct ntlm_buf *buf)
/* [<][>][^][v][top][bottom][index][help] */
260 {
261 krb5_error_code ret;
262
263 buf->data = malloc(desc->length);
264 buf->length = desc->length;
265 CHECK(krb5_storage_seek(sp, desc->offset, SEEK_SET), desc->offset);
266 CHECK(krb5_storage_read(sp, buf->data, buf->length), buf->length);
267 ret = 0;
268 out:
269 return ret;
270 }
271
272 static krb5_error_code
273 put_buf(krb5_storage *sp, const struct ntlm_buf *buf)
/* [<][>][^][v][top][bottom][index][help] */
274 {
275 krb5_error_code ret;
276 CHECK(krb5_storage_write(sp, buf->data, buf->length), buf->length);
277 ret = 0;
278 out:
279 return ret;
280 }
281
282 /**
283 * Frees the ntlm_targetinfo message
284 *
285 * @param ti targetinfo to be freed
286 *
287 * @ingroup ntlm_core
288 */
289
290 void
291 heim_ntlm_free_targetinfo(struct ntlm_targetinfo *ti)
/* [<][>][^][v][top][bottom][index][help] */
292 {
293 free(ti->servername);
294 free(ti->domainname);
295 free(ti->dnsdomainname);
296 free(ti->dnsservername);
297 memset(ti, 0, sizeof(*ti));
298 }
299
300 static int
301 encode_ti_blob(krb5_storage *out, uint16_t type, int ucs2, char *s)
/* [<][>][^][v][top][bottom][index][help] */
302 {
303 krb5_error_code ret;
304 CHECK(krb5_store_uint16(out, type), 0);
305 CHECK(krb5_store_uint16(out, len_string(ucs2, s)), 0);
306 CHECK(put_string(out, ucs2, s), 0);
307 out:
308 return ret;
309 }
310
311 /**
312 * Encodes a ntlm_targetinfo message.
313 *
314 * @param ti the ntlm_targetinfo message to encode.
315 * @param ucs2 if the strings should be encoded with ucs2 (selected by flag in message).
316 * @param data is the return buffer with the encoded message, should be
317 * freed with heim_ntlm_free_buf().
318 *
319 * @return In case of success 0 is return, an errors, a errno in what
320 * went wrong.
321 *
322 * @ingroup ntlm_core
323 */
324
325 int
326 heim_ntlm_encode_targetinfo(const struct ntlm_targetinfo *ti,
/* [<][>][^][v][top][bottom][index][help] */
327 int ucs2,
328 struct ntlm_buf *data)
329 {
330 krb5_error_code ret;
331 krb5_storage *out;
332
333 data->data = NULL;
334 data->length = 0;
335
336 out = krb5_storage_emem();
337 if (out == NULL)
338 return ENOMEM;
339
340 if (ti->servername)
341 CHECK(encode_ti_blob(out, 1, ucs2, ti->servername), 0);
342 if (ti->domainname)
343 CHECK(encode_ti_blob(out, 2, ucs2, ti->domainname), 0);
344 if (ti->dnsservername)
345 CHECK(encode_ti_blob(out, 3, ucs2, ti->dnsservername), 0);
346 if (ti->dnsdomainname)
347 CHECK(encode_ti_blob(out, 4, ucs2, ti->dnsdomainname), 0);
348
349 /* end tag */
350 CHECK(krb5_store_int16(out, 0), 0);
351 CHECK(krb5_store_int16(out, 0), 0);
352
353 {
354 krb5_data d;
355 ret = krb5_storage_to_data(out, &d);
356 data->data = d.data;
357 data->length = d.length;
358 }
359 out:
360 krb5_storage_free(out);
361 return ret;
362 }
363
364 /**
365 * Decodes an NTLM targetinfo message
366 *
367 * @param data input data buffer with the encode NTLM targetinfo message
368 * @param ucs2 if the strings should be encoded with ucs2 (selected by flag in message).
369 * @param ti the decoded target info, should be freed with heim_ntlm_free_targetinfo().
370 *
371 * @return In case of success 0 is return, an errors, a errno in what
372 * went wrong.
373 *
374 * @ingroup ntlm_core
375 */
376
377 int
378 heim_ntlm_decode_targetinfo(const struct ntlm_buf *data,
/* [<][>][^][v][top][bottom][index][help] */
379 int ucs2,
380 struct ntlm_targetinfo *ti)
381 {
382 memset(ti, 0, sizeof(*ti));
383 return 0;
384 }
385
386 /**
387 * Frees the ntlm_type1 message
388 *
389 * @param data message to be freed
390 *
391 * @ingroup ntlm_core
392 */
393
394 void
395 heim_ntlm_free_type1(struct ntlm_type1 *data)
/* [<][>][^][v][top][bottom][index][help] */
396 {
397 if (data->domain)
398 free(data->domain);
399 if (data->hostname)
400 free(data->hostname);
401 memset(data, 0, sizeof(*data));
402 }
403
404 int
405 heim_ntlm_decode_type1(const struct ntlm_buf *buf, struct ntlm_type1 *data)
/* [<][>][^][v][top][bottom][index][help] */
406 {
407 krb5_error_code ret;
408 unsigned char sig[8];
409 uint32_t type;
410 struct sec_buffer domain, hostname;
411 krb5_storage *in;
412
413 memset(data, 0, sizeof(*data));
414
415 in = krb5_storage_from_readonly_mem(buf->data, buf->length);
416 if (in == NULL) {
417 ret = EINVAL;
418 goto out;
419 }
420 krb5_storage_set_byteorder(in, KRB5_STORAGE_BYTEORDER_LE);
421
422 CHECK(krb5_storage_read(in, sig, sizeof(sig)), sizeof(sig));
423 CHECK(memcmp(ntlmsigature, sig, sizeof(ntlmsigature)), 0);
424 CHECK(krb5_ret_uint32(in, &type), 0);
425 CHECK(type, 1);
426 CHECK(krb5_ret_uint32(in, &data->flags), 0);
427 if (data->flags & NTLM_SUPPLIED_DOMAIN)
428 CHECK(ret_sec_buffer(in, &domain), 0);
429 if (data->flags & NTLM_SUPPLIED_WORKSTAION)
430 CHECK(ret_sec_buffer(in, &hostname), 0);
431 #if 0
432 if (domain.offset > 32) {
433 CHECK(krb5_ret_uint32(in, &data->os[0]), 0);
434 CHECK(krb5_ret_uint32(in, &data->os[1]), 0);
435 }
436 #endif
437 if (data->flags & NTLM_SUPPLIED_DOMAIN)
438 CHECK(ret_string(in, 0, &domain, &data->domain), 0);
439 if (data->flags & NTLM_SUPPLIED_WORKSTAION)
440 CHECK(ret_string(in, 0, &hostname, &data->hostname), 0);
441
442 out:
443 krb5_storage_free(in);
444 if (ret)
445 heim_ntlm_free_type1(data);
446
447 return ret;
448 }
449
450 /**
451 * Encodes an ntlm_type1 message.
452 *
453 * @param type1 the ntlm_type1 message to encode.
454 * @param data is the return buffer with the encoded message, should be
455 * freed with heim_ntlm_free_buf().
456 *
457 * @return In case of success 0 is return, an errors, a errno in what
458 * went wrong.
459 *
460 * @ingroup ntlm_core
461 */
462
463 int
464 heim_ntlm_encode_type1(const struct ntlm_type1 *type1, struct ntlm_buf *data)
/* [<][>][^][v][top][bottom][index][help] */
465 {
466 krb5_error_code ret;
467 struct sec_buffer domain, hostname;
468 krb5_storage *out;
469 uint32_t base, flags;
470
471 flags = type1->flags;
472 base = 16;
473
474 if (type1->domain) {
475 base += 8;
476 flags |= NTLM_SUPPLIED_DOMAIN;
477 }
478 if (type1->hostname) {
479 base += 8;
480 flags |= NTLM_SUPPLIED_WORKSTAION;
481 }
482 if (type1->os[0])
483 base += 8;
484
485 if (type1->domain) {
486 domain.offset = base;
487 domain.length = len_string(0, type1->domain);
488 domain.allocated = domain.length;
489 }
490 if (type1->hostname) {
491 hostname.offset = domain.allocated + domain.offset;
492 hostname.length = len_string(0, type1->hostname);
493 hostname.allocated = hostname.length;
494 }
495
496 out = krb5_storage_emem();
497 if (out == NULL)
498 return ENOMEM;
499
500 krb5_storage_set_byteorder(out, KRB5_STORAGE_BYTEORDER_LE);
501 CHECK(krb5_storage_write(out, ntlmsigature, sizeof(ntlmsigature)),
502 sizeof(ntlmsigature));
503 CHECK(krb5_store_uint32(out, 1), 0);
504 CHECK(krb5_store_uint32(out, flags), 0);
505
506 if (type1->domain)
507 CHECK(store_sec_buffer(out, &domain), 0);
508 if (type1->hostname)
509 CHECK(store_sec_buffer(out, &hostname), 0);
510 if (type1->os[0]) {
511 CHECK(krb5_store_uint32(out, type1->os[0]), 0);
512 CHECK(krb5_store_uint32(out, type1->os[1]), 0);
513 }
514 if (type1->domain)
515 CHECK(put_string(out, 0, type1->domain), 0);
516 if (type1->hostname)
517 CHECK(put_string(out, 0, type1->hostname), 0);
518
519 {
520 krb5_data d;
521 ret = krb5_storage_to_data(out, &d);
522 data->data = d.data;
523 data->length = d.length;
524 }
525 out:
526 krb5_storage_free(out);
527
528 return ret;
529 }
530
531 /**
532 * Frees the ntlm_type2 message
533 *
534 * @param data message to be freed
535 *
536 * @ingroup ntlm_core
537 */
538
539 void
540 heim_ntlm_free_type2(struct ntlm_type2 *data)
/* [<][>][^][v][top][bottom][index][help] */
541 {
542 if (data->targetname)
543 free(data->targetname);
544 heim_ntlm_free_buf(&data->targetinfo);
545 memset(data, 0, sizeof(*data));
546 }
547
548 int
549 heim_ntlm_decode_type2(const struct ntlm_buf *buf, struct ntlm_type2 *type2)
/* [<][>][^][v][top][bottom][index][help] */
550 {
551 krb5_error_code ret;
552 unsigned char sig[8];
553 uint32_t type, ctx[2];
554 struct sec_buffer targetname, targetinfo;
555 krb5_storage *in;
556 int ucs2 = 0;
557
558 memset(type2, 0, sizeof(*type2));
559
560 in = krb5_storage_from_readonly_mem(buf->data, buf->length);
561 if (in == NULL) {
562 ret = EINVAL;
563 goto out;
564 }
565 krb5_storage_set_byteorder(in, KRB5_STORAGE_BYTEORDER_LE);
566
567 CHECK(krb5_storage_read(in, sig, sizeof(sig)), sizeof(sig));
568 CHECK(memcmp(ntlmsigature, sig, sizeof(ntlmsigature)), 0);
569 CHECK(krb5_ret_uint32(in, &type), 0);
570 CHECK(type, 2);
571
572 CHECK(ret_sec_buffer(in, &targetname), 0);
573 CHECK(krb5_ret_uint32(in, &type2->flags), 0);
574 if (type2->flags & NTLM_NEG_UNICODE)
575 ucs2 = 1;
576 CHECK(krb5_storage_read(in, type2->challange, sizeof(type2->challange)),
577 sizeof(type2->challange));
578 CHECK(krb5_ret_uint32(in, &ctx[0]), 0); /* context */
579 CHECK(krb5_ret_uint32(in, &ctx[1]), 0);
580 CHECK(ret_sec_buffer(in, &targetinfo), 0);
581 /* os version */
582 #if 0
583 CHECK(krb5_ret_uint32(in, &type2->os[0]), 0);
584 CHECK(krb5_ret_uint32(in, &type2->os[1]), 0);
585 #endif
586
587 CHECK(ret_string(in, ucs2, &targetname, &type2->targetname), 0);
588 CHECK(ret_buf(in, &targetinfo, &type2->targetinfo), 0);
589 ret = 0;
590
591 out:
592 krb5_storage_free(in);
593 if (ret)
594 heim_ntlm_free_type2(type2);
595
596 return ret;
597 }
598
599 /**
600 * Encodes an ntlm_type2 message.
601 *
602 * @param type2 the ntlm_type2 message to encode.
603 * @param data is the return buffer with the encoded message, should be
604 * freed with heim_ntlm_free_buf().
605 *
606 * @return In case of success 0 is return, an errors, a errno in what
607 * went wrong.
608 *
609 * @ingroup ntlm_core
610 */
611
612 int
613 heim_ntlm_encode_type2(const struct ntlm_type2 *type2, struct ntlm_buf *data)
/* [<][>][^][v][top][bottom][index][help] */
614 {
615 struct sec_buffer targetname, targetinfo;
616 krb5_error_code ret;
617 krb5_storage *out = NULL;
618 uint32_t base;
619 int ucs2 = 0;
620
621 if (type2->os[0])
622 base = 56;
623 else
624 base = 48;
625
626 if (type2->flags & NTLM_NEG_UNICODE)
627 ucs2 = 1;
628
629 targetname.offset = base;
630 targetname.length = len_string(ucs2, type2->targetname);
631 targetname.allocated = targetname.length;
632
633 targetinfo.offset = targetname.allocated + targetname.offset;
634 targetinfo.length = type2->targetinfo.length;
635 targetinfo.allocated = type2->targetinfo.length;
636
637 out = krb5_storage_emem();
638 if (out == NULL)
639 return ENOMEM;
640
641 krb5_storage_set_byteorder(out, KRB5_STORAGE_BYTEORDER_LE);
642 CHECK(krb5_storage_write(out, ntlmsigature, sizeof(ntlmsigature)),
643 sizeof(ntlmsigature));
644 CHECK(krb5_store_uint32(out, 2), 0);
645 CHECK(store_sec_buffer(out, &targetname), 0);
646 CHECK(krb5_store_uint32(out, type2->flags), 0);
647 CHECK(krb5_storage_write(out, type2->challange, sizeof(type2->challange)),
648 sizeof(type2->challange));
649 CHECK(krb5_store_uint32(out, 0), 0); /* context */
650 CHECK(krb5_store_uint32(out, 0), 0);
651 CHECK(store_sec_buffer(out, &targetinfo), 0);
652 /* os version */
653 if (type2->os[0]) {
654 CHECK(krb5_store_uint32(out, type2->os[0]), 0);
655 CHECK(krb5_store_uint32(out, type2->os[1]), 0);
656 }
657 CHECK(put_string(out, ucs2, type2->targetname), 0);
658 CHECK(krb5_storage_write(out, type2->targetinfo.data,
659 type2->targetinfo.length),
660 type2->targetinfo.length);
661
662 {
663 krb5_data d;
664 ret = krb5_storage_to_data(out, &d);
665 data->data = d.data;
666 data->length = d.length;
667 }
668
669 out:
670 krb5_storage_free(out);
671
672 return ret;
673 }
674
675 /**
676 * Frees the ntlm_type3 message
677 *
678 * @param data message to be freed
679 *
680 * @ingroup ntlm_core
681 */
682
683 void
684 heim_ntlm_free_type3(struct ntlm_type3 *data)
/* [<][>][^][v][top][bottom][index][help] */
685 {
686 heim_ntlm_free_buf(&data->lm);
687 heim_ntlm_free_buf(&data->ntlm);
688 if (data->targetname)
689 free(data->targetname);
690 if (data->username)
691 free(data->username);
692 if (data->ws)
693 free(data->ws);
694 heim_ntlm_free_buf(&data->sessionkey);
695 memset(data, 0, sizeof(*data));
696 }
697
698 /*
699 *
700 */
701
702 int
703 heim_ntlm_decode_type3(const struct ntlm_buf *buf,
/* [<][>][^][v][top][bottom][index][help] */
704 int ucs2,
705 struct ntlm_type3 *type3)
706 {
707 krb5_error_code ret;
708 unsigned char sig[8];
709 uint32_t type;
710 krb5_storage *in;
711 struct sec_buffer lm, ntlm, target, username, sessionkey, ws;
712
713 memset(type3, 0, sizeof(*type3));
714 memset(&sessionkey, 0, sizeof(sessionkey));
715
716 in = krb5_storage_from_readonly_mem(buf->data, buf->length);
717 if (in == NULL) {
718 ret = EINVAL;
719 goto out;
720 }
721 krb5_storage_set_byteorder(in, KRB5_STORAGE_BYTEORDER_LE);
722
723 CHECK(krb5_storage_read(in, sig, sizeof(sig)), sizeof(sig));
724 CHECK(memcmp(ntlmsigature, sig, sizeof(ntlmsigature)), 0);
725 CHECK(krb5_ret_uint32(in, &type), 0);
726 CHECK(type, 3);
727 CHECK(ret_sec_buffer(in, &lm), 0);
728 CHECK(ret_sec_buffer(in, &ntlm), 0);
729 CHECK(ret_sec_buffer(in, &target), 0);
730 CHECK(ret_sec_buffer(in, &username), 0);
731 CHECK(ret_sec_buffer(in, &ws), 0);
732 if (lm.offset >= 60) {
733 CHECK(ret_sec_buffer(in, &sessionkey), 0);
734 }
735 if (lm.offset >= 64) {
736 CHECK(krb5_ret_uint32(in, &type3->flags), 0);
737 }
738 if (lm.offset >= 72) {
739 CHECK(krb5_ret_uint32(in, &type3->os[0]), 0);
740 CHECK(krb5_ret_uint32(in, &type3->os[1]), 0);
741 }
742 CHECK(ret_buf(in, &lm, &type3->lm), 0);
743 CHECK(ret_buf(in, &ntlm, &type3->ntlm), 0);
744 CHECK(ret_string(in, ucs2, &target, &type3->targetname), 0);
745 CHECK(ret_string(in, ucs2, &username, &type3->username), 0);
746 CHECK(ret_string(in, ucs2, &ws, &type3->ws), 0);
747 if (sessionkey.offset)
748 CHECK(ret_buf(in, &sessionkey, &type3->sessionkey), 0);
749
750 out:
751 krb5_storage_free(in);
752 if (ret)
753 heim_ntlm_free_type3(type3);
754
755 return ret;
756 }
757
758 /**
759 * Encodes an ntlm_type3 message.
760 *
761 * @param type3 the ntlm_type3 message to encode.
762 * @param data is the return buffer with the encoded message, should be
763 * freed with heim_ntlm_free_buf().
764 *
765 * @return In case of success 0 is return, an errors, a errno in what
766 * went wrong.
767 *
768 * @ingroup ntlm_core
769 */
770
771 int
772 heim_ntlm_encode_type3(const struct ntlm_type3 *type3, struct ntlm_buf *data)
/* [<][>][^][v][top][bottom][index][help] */
773 {
774 struct sec_buffer lm, ntlm, target, username, sessionkey, ws;
775 krb5_error_code ret;
776 krb5_storage *out = NULL;
777 uint32_t base;
778 int ucs2 = 0;
779
780 memset(&lm, 0, sizeof(lm));
781 memset(&ntlm, 0, sizeof(ntlm));
782 memset(&target, 0, sizeof(target));
783 memset(&username, 0, sizeof(username));
784 memset(&ws, 0, sizeof(ws));
785 memset(&sessionkey, 0, sizeof(sessionkey));
786
787 base = 52;
788 if (type3->sessionkey.length) {
789 base += 8; /* sessionkey sec buf */
790 base += 4; /* flags */
791 }
792 if (type3->os[0]) {
793 base += 8;
794 }
795
796 if (type3->flags & NTLM_NEG_UNICODE)
797 ucs2 = 1;
798
799 lm.offset = base;
800 lm.length = type3->lm.length;
801 lm.allocated = type3->lm.length;
802
803 ntlm.offset = lm.offset + lm.allocated;
804 ntlm.length = type3->ntlm.length;
805 ntlm.allocated = ntlm.length;
806
807 target.offset = ntlm.offset + ntlm.allocated;
808 target.length = len_string(ucs2, type3->targetname);
809 target.allocated = target.length;
810
811 username.offset = target.offset + target.allocated;
812 username.length = len_string(ucs2, type3->username);
813 username.allocated = username.length;
814
815 ws.offset = username.offset + username.allocated;
816 ws.length = len_string(ucs2, type3->ws);
817 ws.allocated = ws.length;
818
819 sessionkey.offset = ws.offset + ws.allocated;
820 sessionkey.length = type3->sessionkey.length;
821 sessionkey.allocated = type3->sessionkey.length;
822
823 out = krb5_storage_emem();
824 if (out == NULL)
825 return ENOMEM;
826
827 krb5_storage_set_byteorder(out, KRB5_STORAGE_BYTEORDER_LE);
828 CHECK(krb5_storage_write(out, ntlmsigature, sizeof(ntlmsigature)),
829 sizeof(ntlmsigature));
830 CHECK(krb5_store_uint32(out, 3), 0);
831
832 CHECK(store_sec_buffer(out, &lm), 0);
833 CHECK(store_sec_buffer(out, &ntlm), 0);
834 CHECK(store_sec_buffer(out, &target), 0);
835 CHECK(store_sec_buffer(out, &username), 0);
836 CHECK(store_sec_buffer(out, &ws), 0);
837 /* optional */
838 if (type3->sessionkey.length) {
839 CHECK(store_sec_buffer(out, &sessionkey), 0);
840 CHECK(krb5_store_uint32(out, type3->flags), 0);
841 }
842 #if 0
843 CHECK(krb5_store_uint32(out, 0), 0); /* os0 */
844 CHECK(krb5_store_uint32(out, 0), 0); /* os1 */
845 #endif
846
847 CHECK(put_buf(out, &type3->lm), 0);
848 CHECK(put_buf(out, &type3->ntlm), 0);
849 CHECK(put_string(out, ucs2, type3->targetname), 0);
850 CHECK(put_string(out, ucs2, type3->username), 0);
851 CHECK(put_string(out, ucs2, type3->ws), 0);
852 CHECK(put_buf(out, &type3->sessionkey), 0);
853
854 {
855 krb5_data d;
856 ret = krb5_storage_to_data(out, &d);
857 data->data = d.data;
858 data->length = d.length;
859 }
860
861 out:
862 krb5_storage_free(out);
863
864 return ret;
865 }
866
867
868 /*
869 *
870 */
871
872 static void
873 splitandenc(unsigned char *hash,
/* [<][>][^][v][top][bottom][index][help] */
874 unsigned char *challange,
875 unsigned char *answer)
876 {
877 DES_cblock key;
878 DES_key_schedule sched;
879
880 ((unsigned char*)key)[0] = hash[0];
881 ((unsigned char*)key)[1] = (hash[0] << 7) | (hash[1] >> 1);
882 ((unsigned char*)key)[2] = (hash[1] << 6) | (hash[2] >> 2);
883 ((unsigned char*)key)[3] = (hash[2] << 5) | (hash[3] >> 3);
884 ((unsigned char*)key)[4] = (hash[3] << 4) | (hash[4] >> 4);
885 ((unsigned char*)key)[5] = (hash[4] << 3) | (hash[5] >> 5);
886 ((unsigned char*)key)[6] = (hash[5] << 2) | (hash[6] >> 6);
887 ((unsigned char*)key)[7] = (hash[6] << 1);
888
889 DES_set_odd_parity(&key);
890 DES_set_key_unchecked(&key, &sched);
891 DES_ecb_encrypt((DES_cblock *)challange, (DES_cblock *)answer, &sched, 1);
892 memset(&sched, 0, sizeof(sched));
893 memset(key, 0, sizeof(key));
894 }
895
896 /**
897 * Calculate the NTLM key, the password is assumed to be in UTF8.
898 *
899 * @param password password to calcute the key for.
900 * @param key calcuted key, should be freed with heim_ntlm_free_buf().
901 *
902 * @return In case of success 0 is return, an errors, a errno in what
903 * went wrong.
904 *
905 * @ingroup ntlm_core
906 */
907
908 int
909 heim_ntlm_nt_key(const char *password, struct ntlm_buf *key)
/* [<][>][^][v][top][bottom][index][help] */
910 {
911 struct ntlm_buf buf;
912 MD4_CTX ctx;
913 int ret;
914
915 key->data = malloc(MD5_DIGEST_LENGTH);
916 if (key->data == NULL)
917 return ENOMEM;
918 key->length = MD5_DIGEST_LENGTH;
919
920 ret = ascii2ucs2le(password, 0, &buf);
921 if (ret) {
922 heim_ntlm_free_buf(key);
923 return ret;
924 }
925 MD4_Init(&ctx);
926 MD4_Update(&ctx, buf.data, buf.length);
927 MD4_Final(key->data, &ctx);
928 heim_ntlm_free_buf(&buf);
929 return 0;
930 }
931
932 /**
933 * Calculate NTLMv1 response hash
934 *
935 * @param key the ntlm v1 key
936 * @param len length of key
937 * @param challange sent by the server
938 * @param answer calculated answer, should be freed with heim_ntlm_free_buf().
939 *
940 * @return In case of success 0 is return, an errors, a errno in what
941 * went wrong.
942 *
943 * @ingroup ntlm_core
944 */
945
946 int
947 heim_ntlm_calculate_ntlm1(void *key, size_t len,
/* [<][>][^][v][top][bottom][index][help] */
948 unsigned char challange[8],
949 struct ntlm_buf *answer)
950 {
951 unsigned char res[21];
952
953 if (len != MD4_DIGEST_LENGTH)
954 return EINVAL;
955
956 memcpy(res, key, len);
957 memset(&res[MD4_DIGEST_LENGTH], 0, sizeof(res) - MD4_DIGEST_LENGTH);
958
959 answer->data = malloc(24);
960 if (answer->data == NULL)
961 return ENOMEM;
962 answer->length = 24;
963
964 splitandenc(&res[0], challange, ((unsigned char *)answer->data) + 0);
965 splitandenc(&res[7], challange, ((unsigned char *)answer->data) + 8);
966 splitandenc(&res[14], challange, ((unsigned char *)answer->data) + 16);
967
968 return 0;
969 }
970
971 /**
972 * Generates an NTLMv1 session random with assosited session master key.
973 *
974 * @param key the ntlm v1 key
975 * @param len length of key
976 * @param session generated session nonce, should be freed with heim_ntlm_free_buf().
977 * @param master calculated session master key, should be freed with heim_ntlm_free_buf().
978 *
979 * @return In case of success 0 is return, an errors, a errno in what
980 * went wrong.
981 *
982 * @ingroup ntlm_core
983 */
984
985 int
986 heim_ntlm_build_ntlm1_master(void *key, size_t len,
/* [<][>][^][v][top][bottom][index][help] */
987 struct ntlm_buf *session,
988 struct ntlm_buf *master)
989 {
990 RC4_KEY rc4;
991
992 memset(master, 0, sizeof(*master));
993 memset(session, 0, sizeof(*session));
994
995 if (len != MD4_DIGEST_LENGTH)
996 return EINVAL;
997
998 session->length = MD4_DIGEST_LENGTH;
999 session->data = malloc(session->length);
1000 if (session->data == NULL) {
1001 session->length = 0;
1002 return EINVAL;
1003 }
1004 master->length = MD4_DIGEST_LENGTH;
1005 master->data = malloc(master->length);
1006 if (master->data == NULL) {
1007 heim_ntlm_free_buf(master);
1008 heim_ntlm_free_buf(session);
1009 return EINVAL;
1010 }
1011
1012 {
1013 unsigned char sessionkey[MD4_DIGEST_LENGTH];
1014 MD4_CTX ctx;
1015
1016 MD4_Init(&ctx);
1017 MD4_Update(&ctx, key, len);
1018 MD4_Final(sessionkey, &ctx);
1019
1020 RC4_set_key(&rc4, sizeof(sessionkey), sessionkey);
1021 }
1022
1023 if (RAND_bytes(session->data, session->length) != 1) {
1024 heim_ntlm_free_buf(master);
1025 heim_ntlm_free_buf(session);
1026 return EINVAL;
1027 }
1028
1029 RC4(&rc4, master->length, session->data, master->data);
1030 memset(&rc4, 0, sizeof(rc4));
1031
1032 return 0;
1033 }
1034
1035 /**
1036 * Generates an NTLMv2 session key.
1037 *
1038 * @param key the ntlm key
1039 * @param len length of key
1040 * @param username name of the user, as sent in the message, assumed to be in UTF8.
1041 * @param target the name of the target, assumed to be in UTF8.
1042 * @param ntlmv2 the ntlmv2 session key
1043 *
1044 * @ingroup ntlm_core
1045 */
1046
1047 void
1048 heim_ntlm_ntlmv2_key(const void *key, size_t len,
/* [<][>][^][v][top][bottom][index][help] */
1049 const char *username,
1050 const char *target,
1051 unsigned char ntlmv2[16])
1052 {
1053 unsigned int hmaclen;
1054 HMAC_CTX c;
1055
1056 HMAC_CTX_init(&c);
1057 HMAC_Init_ex(&c, key, len, EVP_md5(), NULL);
1058 {
1059 struct ntlm_buf buf;
1060 /* uppercase username and turn it into ucs2-le */
1061 ascii2ucs2le(username, 1, &buf);
1062 HMAC_Update(&c, buf.data, buf.length);
1063 free(buf.data);
1064 /* uppercase target and turn into ucs2-le */
1065 ascii2ucs2le(target, 1, &buf);
1066 HMAC_Update(&c, buf.data, buf.length);
1067 free(buf.data);
1068 }
1069 HMAC_Final(&c, ntlmv2, &hmaclen);
1070 HMAC_CTX_cleanup(&c);
1071
1072 }
1073
1074 /*
1075 *
1076 */
1077
1078 #define NTTIME_EPOCH 0x019DB1DED53E8000LL
1079
1080 static uint64_t
1081 unix2nttime(time_t unix_time)
/* [<][>][^][v][top][bottom][index][help] */
1082 {
1083 long long wt;
1084 wt = unix_time * (uint64_t)10000000 + (uint64_t)NTTIME_EPOCH;
1085 return wt;
1086 }
1087
1088 static time_t
1089 nt2unixtime(uint64_t t)
/* [<][>][^][v][top][bottom][index][help] */
1090 {
1091 t = ((t - (uint64_t)NTTIME_EPOCH) / (uint64_t)10000000);
1092 if (t > (((time_t)(~(uint64_t)0)) >> 1))
1093 return 0;
1094 return (time_t)t;
1095 }
1096
1097
1098 /**
1099 * Calculate NTLMv2 response
1100 *
1101 * @param key the ntlm key
1102 * @param len length of key
1103 * @param username name of the user, as sent in the message, assumed to be in UTF8.
1104 * @param target the name of the target, assumed to be in UTF8.
1105 * @param serverchallange challange as sent by the server in the type2 message.
1106 * @param infotarget infotarget as sent by the server in the type2 message.
1107 * @param ntlmv2 calculated session key
1108 * @param answer ntlm response answer, should be freed with heim_ntlm_free_buf().
1109 *
1110 * @return In case of success 0 is return, an errors, a errno in what
1111 * went wrong.
1112 *
1113 * @ingroup ntlm_core
1114 */
1115
1116 int
1117 heim_ntlm_calculate_ntlm2(const void *key, size_t len,
/* [<][>][^][v][top][bottom][index][help] */
1118 const char *username,
1119 const char *target,
1120 const unsigned char serverchallange[8],
1121 const struct ntlm_buf *infotarget,
1122 unsigned char ntlmv2[16],
1123 struct ntlm_buf *answer)
1124 {
1125 krb5_error_code ret;
1126 krb5_data data;
1127 unsigned int hmaclen;
1128 unsigned char ntlmv2answer[16];
1129 krb5_storage *sp;
1130 unsigned char clientchallange[8];
1131 HMAC_CTX c;
1132 uint64_t t;
1133
1134 t = unix2nttime(time(NULL));
1135
1136 if (RAND_bytes(clientchallange, sizeof(clientchallange)) != 1)
1137 return EINVAL;
1138
1139 /* calculate ntlmv2 key */
1140
1141 heim_ntlm_ntlmv2_key(key, len, username, target, ntlmv2);
1142
1143 /* calculate and build ntlmv2 answer */
1144
1145 sp = krb5_storage_emem();
1146 if (sp == NULL)
1147 return ENOMEM;
1148 krb5_storage_set_flags(sp, KRB5_STORAGE_BYTEORDER_LE);
1149
1150 CHECK(krb5_store_uint32(sp, 0x00000101), 0);
1151 CHECK(krb5_store_uint32(sp, 0), 0);
1152 /* timestamp le 64 bit ts */
1153 CHECK(krb5_store_uint32(sp, t & 0xffffffff), 0);
1154 CHECK(krb5_store_uint32(sp, t >> 32), 0);
1155
1156 CHECK(krb5_storage_write(sp, clientchallange, 8), 8);
1157
1158 CHECK(krb5_store_uint32(sp, 0), 0); /* unknown but zero will work */
1159 CHECK(krb5_storage_write(sp, infotarget->data, infotarget->length),
1160 infotarget->length);
1161 CHECK(krb5_store_uint32(sp, 0), 0); /* unknown but zero will work */
1162
1163 CHECK(krb5_storage_to_data(sp, &data), 0);
1164 krb5_storage_free(sp);
1165 sp = NULL;
1166
1167 HMAC_CTX_init(&c);
1168 HMAC_Init_ex(&c, ntlmv2, 16, EVP_md5(), NULL);
1169 HMAC_Update(&c, serverchallange, 8);
1170 HMAC_Update(&c, data.data, data.length);
1171 HMAC_Final(&c, ntlmv2answer, &hmaclen);
1172 HMAC_CTX_cleanup(&c);
1173
1174 sp = krb5_storage_emem();
1175 if (sp == NULL) {
1176 krb5_data_free(&data);
1177 return ENOMEM;
1178 }
1179
1180 CHECK(krb5_storage_write(sp, ntlmv2answer, 16), 16);
1181 CHECK(krb5_storage_write(sp, data.data, data.length), data.length);
1182 krb5_data_free(&data);
1183
1184 CHECK(krb5_storage_to_data(sp, &data), 0);
1185 krb5_storage_free(sp);
1186 sp = NULL;
1187
1188 answer->data = data.data;
1189 answer->length = data.length;
1190
1191 return 0;
1192 out:
1193 if (sp)
1194 krb5_storage_free(sp);
1195 return ret;
1196 }
1197
1198 static const int authtimediff = 3600 * 2; /* 2 hours */
1199
1200 /**
1201 * Verify NTLMv2 response.
1202 *
1203 * @param key the ntlm key
1204 * @param len length of key
1205 * @param username name of the user, as sent in the message, assumed to be in UTF8.
1206 * @param target the name of the target, assumed to be in UTF8.
1207 * @param now the time now (0 if the library should pick it up itself)
1208 * @param serverchallange challange as sent by the server in the type2 message.
1209 * @param answer ntlm response answer, should be freed with heim_ntlm_free_buf().
1210 * @param infotarget infotarget as sent by the server in the type2 message.
1211 * @param ntlmv2 calculated session key
1212 *
1213 * @return In case of success 0 is return, an errors, a errno in what
1214 * went wrong.
1215 *
1216 * @ingroup ntlm_core
1217 */
1218
1219 int
1220 heim_ntlm_verify_ntlm2(const void *key, size_t len,
/* [<][>][^][v][top][bottom][index][help] */
1221 const char *username,
1222 const char *target,
1223 time_t now,
1224 const unsigned char serverchallange[8],
1225 const struct ntlm_buf *answer,
1226 struct ntlm_buf *infotarget,
1227 unsigned char ntlmv2[16])
1228 {
1229 krb5_error_code ret;
1230 unsigned int hmaclen;
1231 unsigned char clientanswer[16];
1232 unsigned char clientnonce[8];
1233 unsigned char serveranswer[16];
1234 krb5_storage *sp;
1235 HMAC_CTX c;
1236 uint64_t t;
1237 time_t authtime;
1238 uint32_t temp;
1239
1240 infotarget->length = 0;
1241 infotarget->data = NULL;
1242
1243 if (answer->length < 16)
1244 return EINVAL;
1245
1246 if (now == 0)
1247 now = time(NULL);
1248
1249 /* calculate ntlmv2 key */
1250
1251 heim_ntlm_ntlmv2_key(key, len, username, target, ntlmv2);
1252
1253 /* calculate and build ntlmv2 answer */
1254
1255 sp = krb5_storage_from_readonly_mem(answer->data, answer->length);
1256 if (sp == NULL)
1257 return ENOMEM;
1258 krb5_storage_set_flags(sp, KRB5_STORAGE_BYTEORDER_LE);
1259
1260 CHECK(krb5_storage_read(sp, clientanswer, 16), 16);
1261
1262 CHECK(krb5_ret_uint32(sp, &temp), 0);
1263 CHECK(temp, 0x00000101);
1264 CHECK(krb5_ret_uint32(sp, &temp), 0);
1265 CHECK(temp, 0);
1266 /* timestamp le 64 bit ts */
1267 CHECK(krb5_ret_uint32(sp, &temp), 0);
1268 t = temp;
1269 CHECK(krb5_ret_uint32(sp, &temp), 0);
1270 t |= ((uint64_t)temp)<< 32;
1271
1272 authtime = nt2unixtime(t);
1273
1274 if (abs((int)(authtime - now)) > authtimediff) {
1275 ret = EINVAL;
1276 goto out;
1277 }
1278
1279 /* client challange */
1280 CHECK(krb5_storage_read(sp, clientnonce, 8), 8);
1281
1282 CHECK(krb5_ret_uint32(sp, &temp), 0); /* unknown */
1283
1284 /* should really unparse the infotarget, but lets pick up everything */
1285 infotarget->length = answer->length - krb5_storage_seek(sp, 0, SEEK_CUR);
1286 infotarget->data = malloc(infotarget->length);
1287 if (infotarget->data == NULL) {
1288 ret = ENOMEM;
1289 goto out;
1290 }
1291 CHECK(krb5_storage_read(sp, infotarget->data, infotarget->length),
1292 infotarget->length);
1293 /* XXX remove the unknown ?? */
1294 krb5_storage_free(sp);
1295 sp = NULL;
1296
1297 HMAC_CTX_init(&c);
1298 HMAC_Init_ex(&c, ntlmv2, 16, EVP_md5(), NULL);
1299 HMAC_Update(&c, serverchallange, 8);
1300 HMAC_Update(&c, ((unsigned char *)answer->data) + 16, answer->length - 16);
1301 HMAC_Final(&c, serveranswer, &hmaclen);
1302 HMAC_CTX_cleanup(&c);
1303
1304 if (memcmp(serveranswer, clientanswer, 16) != 0) {
1305 heim_ntlm_free_buf(infotarget);
1306 return EINVAL;
1307 }
1308
1309 return 0;
1310 out:
1311 heim_ntlm_free_buf(infotarget);
1312 if (sp)
1313 krb5_storage_free(sp);
1314 return ret;
1315 }
1316
1317
1318 /*
1319 * Calculate the NTLM2 Session Response
1320 *
1321 * @param clnt_nonce client nonce
1322 * @param svr_chal server challage
1323 * @param ntlm2_hash ntlm hash
1324 * @param lm The LM response, should be freed with heim_ntlm_free_buf().
1325 * @param ntlm The NTLM response, should be freed with heim_ntlm_free_buf().
1326 *
1327 * @return In case of success 0 is return, an errors, a errno in what
1328 * went wrong.
1329 *
1330 * @ingroup ntlm_core
1331 */
1332
1333 int
1334 heim_ntlm_calculate_ntlm2_sess(const unsigned char clnt_nonce[8],
/* [<][>][^][v][top][bottom][index][help] */
1335 const unsigned char svr_chal[8],
1336 const unsigned char ntlm_hash[16],
1337 struct ntlm_buf *lm,
1338 struct ntlm_buf *ntlm)
1339 {
1340 unsigned char ntlm2_sess_hash[MD5_DIGEST_LENGTH];
1341 unsigned char res[21], *resp;
1342 MD5_CTX md5;
1343
1344 lm->data = malloc(24);
1345 if (lm->data == NULL)
1346 return ENOMEM;
1347 lm->length = 24;
1348
1349 ntlm->data = malloc(24);
1350 if (ntlm->data == NULL) {
1351 free(lm->data);
1352 lm->data = NULL;
1353 return ENOMEM;
1354 }
1355 ntlm->length = 24;
1356
1357 /* first setup the lm resp */
1358 memset(lm->data, 0, 24);
1359 memcpy(lm->data, clnt_nonce, 8);
1360
1361 MD5_Init(&md5);
1362 MD5_Update(&md5, svr_chal, 8); /* session nonce part 1 */
1363 MD5_Update(&md5, clnt_nonce, 8); /* session nonce part 2 */
1364 MD5_Final(ntlm2_sess_hash, &md5); /* will only use first 8 bytes */
1365
1366 memset(res, 0, sizeof(res));
1367 memcpy(res, ntlm_hash, 16);
1368
1369 resp = ntlm->data;
1370 splitandenc(&res[0], ntlm2_sess_hash, resp + 0);
1371 splitandenc(&res[7], ntlm2_sess_hash, resp + 8);
1372 splitandenc(&res[14], ntlm2_sess_hash, resp + 16);
1373
1374 return 0;
1375 }