Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/crypto/heimdal/lib/ntlm/ntlm.c
34889 views
1
/*
2
* Copyright (c) 2006 - 2008 Kungliga Tekniska Högskolan
3
* (Royal Institute of Technology, Stockholm, Sweden).
4
* All rights reserved.
5
*
6
* Portions Copyright (c) 2010 Apple Inc. All rights reserved.
7
*
8
* Redistribution and use in source and binary forms, with or without
9
* modification, are permitted provided that the following conditions
10
* are met:
11
*
12
* 1. Redistributions of source code must retain the above copyright
13
* notice, this list of conditions and the following disclaimer.
14
*
15
* 2. Redistributions in binary form must reproduce the above copyright
16
* notice, this list of conditions and the following disclaimer in the
17
* documentation and/or other materials provided with the distribution.
18
*
19
* 3. Neither the name of the Institute nor the names of its contributors
20
* may be used to endorse or promote products derived from this software
21
* without specific prior written permission.
22
*
23
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
24
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
27
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33
* SUCH DAMAGE.
34
*/
35
36
#include <config.h>
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 <roken.h>
47
#include <parse_units.h>
48
#include <krb5.h>
49
50
#define HC_DEPRECATED_CRYPTO
51
52
#include "krb5-types.h"
53
#include "crypto-headers.h"
54
55
#include <heimntlm.h>
56
57
/*! \mainpage Heimdal NTLM library
58
*
59
* \section intro Introduction
60
*
61
* Heimdal libheimntlm library is a implementation of the NTLM
62
* protocol, both version 1 and 2. The GSS-API mech that uses this
63
* library adds support for transport encryption and integrity
64
* checking.
65
*
66
* NTLM is a protocol for mutual authentication, its still used in
67
* many protocol where Kerberos is not support, one example is
68
* EAP/X802.1x mechanism LEAP from Microsoft and Cisco.
69
*
70
* This is a support library for the core protocol, its used in
71
* Heimdal to implement and GSS-API mechanism. There is also support
72
* in the KDC to do remote digest authenticiation, this to allow
73
* services to authenticate users w/o direct access to the users ntlm
74
* hashes (same as Kerberos arcfour enctype keys).
75
*
76
* More information about the NTLM protocol can found here
77
* http://davenport.sourceforge.net/ntlm.html .
78
*
79
* The Heimdal projects web page: http://www.h5l.org/
80
*
81
* @section ntlm_example NTLM Example
82
*
83
* Example to to use @ref test_ntlm.c .
84
*
85
* @example test_ntlm.c
86
*
87
* Example how to use the NTLM primitives.
88
*
89
*/
90
91
/** @defgroup ntlm_core Heimdal NTLM library
92
*
93
* The NTLM core functions implement the string2key generation
94
* function, message encode and decode function, and the hash function
95
* functions.
96
*/
97
98
struct sec_buffer {
99
uint16_t length;
100
uint16_t allocated;
101
uint32_t offset;
102
};
103
104
static const unsigned char ntlmsigature[8] = "NTLMSSP\x00";
105
106
/*
107
*
108
*/
109
110
#define CHECK(f, e) \
111
do { \
112
ret = f; \
113
if (ret != (ssize_t)(e)) { \
114
ret = HNTLM_ERR_DECODE; \
115
goto out; \
116
} \
117
} while(/*CONSTCOND*/0)
118
119
static struct units ntlm_flag_units[] = {
120
#define ntlm_flag(x) { #x, NTLM_##x }
121
ntlm_flag(ENC_56),
122
ntlm_flag(NEG_KEYEX),
123
ntlm_flag(ENC_128),
124
ntlm_flag(MBZ1),
125
ntlm_flag(MBZ2),
126
ntlm_flag(MBZ3),
127
ntlm_flag(NEG_VERSION),
128
ntlm_flag(MBZ4),
129
ntlm_flag(NEG_TARGET_INFO),
130
ntlm_flag(NON_NT_SESSION_KEY),
131
ntlm_flag(MBZ5),
132
ntlm_flag(NEG_IDENTIFY),
133
ntlm_flag(NEG_NTLM2),
134
ntlm_flag(TARGET_SHARE),
135
ntlm_flag(TARGET_SERVER),
136
ntlm_flag(TARGET_DOMAIN),
137
ntlm_flag(NEG_ALWAYS_SIGN),
138
ntlm_flag(MBZ6),
139
ntlm_flag(OEM_SUPPLIED_WORKSTATION),
140
ntlm_flag(OEM_SUPPLIED_DOMAIN),
141
ntlm_flag(NEG_ANONYMOUS),
142
ntlm_flag(NEG_NT_ONLY),
143
ntlm_flag(NEG_NTLM),
144
ntlm_flag(MBZ8),
145
ntlm_flag(NEG_LM_KEY),
146
ntlm_flag(NEG_DATAGRAM),
147
ntlm_flag(NEG_SEAL),
148
ntlm_flag(NEG_SIGN),
149
ntlm_flag(MBZ9),
150
ntlm_flag(NEG_TARGET),
151
ntlm_flag(NEG_OEM),
152
ntlm_flag(NEG_UNICODE),
153
#undef ntlm_flag
154
{NULL, 0}
155
};
156
157
size_t
158
heim_ntlm_unparse_flags(uint32_t flags, char *s, size_t len)
159
{
160
return unparse_flags(flags, ntlm_flag_units, s, len);
161
}
162
163
164
/**
165
* heim_ntlm_free_buf frees the ntlm buffer
166
*
167
* @param p buffer to be freed
168
*
169
* @ingroup ntlm_core
170
*/
171
172
void
173
heim_ntlm_free_buf(struct ntlm_buf *p)
174
{
175
if (p->data)
176
free(p->data);
177
p->data = NULL;
178
p->length = 0;
179
}
180
181
182
static int
183
ascii2ucs2le(const char *string, int up, struct ntlm_buf *buf)
184
{
185
unsigned char *p;
186
size_t len, i;
187
188
len = strlen(string);
189
if (len / 2 > UINT_MAX)
190
return ERANGE;
191
192
buf->length = len * 2;
193
buf->data = malloc(buf->length);
194
if (buf->data == NULL && len != 0) {
195
heim_ntlm_free_buf(buf);
196
return ENOMEM;
197
}
198
199
p = buf->data;
200
for (i = 0; i < len; i++) {
201
unsigned char t = (unsigned char)string[i];
202
if (t & 0x80) {
203
heim_ntlm_free_buf(buf);
204
return EINVAL;
205
}
206
if (up)
207
t = toupper(t);
208
p[(i * 2) + 0] = t;
209
p[(i * 2) + 1] = 0;
210
}
211
return 0;
212
}
213
214
/*
215
*
216
*/
217
218
static krb5_error_code
219
ret_sec_buffer(krb5_storage *sp, struct sec_buffer *buf)
220
{
221
krb5_error_code ret;
222
CHECK(krb5_ret_uint16(sp, &buf->length), 0);
223
CHECK(krb5_ret_uint16(sp, &buf->allocated), 0);
224
CHECK(krb5_ret_uint32(sp, &buf->offset), 0);
225
out:
226
return ret;
227
}
228
229
static krb5_error_code
230
store_sec_buffer(krb5_storage *sp, const struct sec_buffer *buf)
231
{
232
krb5_error_code ret;
233
CHECK(krb5_store_uint16(sp, buf->length), 0);
234
CHECK(krb5_store_uint16(sp, buf->allocated), 0);
235
CHECK(krb5_store_uint32(sp, buf->offset), 0);
236
out:
237
return ret;
238
}
239
240
/*
241
* Strings are either OEM or UNICODE. The later is encoded as ucs2 on
242
* wire, but using utf8 in memory.
243
*/
244
245
static krb5_error_code
246
len_string(int ucs2, const char *s)
247
{
248
size_t len = strlen(s);
249
if (ucs2)
250
len *= 2;
251
return len;
252
}
253
254
/*
255
*
256
*/
257
258
static krb5_error_code
259
ret_string(krb5_storage *sp, int ucs2, size_t len, char **s)
260
{
261
krb5_error_code ret;
262
263
*s = malloc(len + 1);
264
if (*s == NULL)
265
return ENOMEM;
266
CHECK(krb5_storage_read(sp, *s, len), len);
267
268
(*s)[len] = '\0';
269
270
if (ucs2) {
271
size_t i;
272
for (i = 0; i < len / 2; i++) {
273
(*s)[i] = (*s)[i * 2];
274
if ((*s)[i * 2 + 1]) {
275
free(*s);
276
*s = NULL;
277
return EINVAL;
278
}
279
}
280
(*s)[i] = '\0';
281
}
282
ret = 0;
283
out:
284
return ret;
285
}
286
287
288
289
static krb5_error_code
290
ret_sec_string(krb5_storage *sp, int ucs2, struct sec_buffer *desc, char **s)
291
{
292
krb5_error_code ret = 0;
293
CHECK(krb5_storage_seek(sp, desc->offset, SEEK_SET), desc->offset);
294
CHECK(ret_string(sp, ucs2, desc->length, s), 0);
295
out:
296
return ret;
297
}
298
299
static krb5_error_code
300
put_string(krb5_storage *sp, int ucs2, const char *s)
301
{
302
krb5_error_code ret;
303
struct ntlm_buf buf;
304
305
if (ucs2) {
306
ret = ascii2ucs2le(s, 0, &buf);
307
if (ret)
308
return ret;
309
} else {
310
buf.data = rk_UNCONST(s);
311
buf.length = strlen(s);
312
}
313
314
CHECK(krb5_storage_write(sp, buf.data, buf.length), buf.length);
315
if (ucs2)
316
heim_ntlm_free_buf(&buf);
317
ret = 0;
318
out:
319
return ret;
320
}
321
322
/*
323
*
324
*/
325
326
static krb5_error_code
327
ret_buf(krb5_storage *sp, struct sec_buffer *desc, struct ntlm_buf *buf)
328
{
329
krb5_error_code ret;
330
331
buf->data = malloc(desc->length);
332
buf->length = desc->length;
333
CHECK(krb5_storage_seek(sp, desc->offset, SEEK_SET), desc->offset);
334
CHECK(krb5_storage_read(sp, buf->data, buf->length), buf->length);
335
ret = 0;
336
out:
337
return ret;
338
}
339
340
static krb5_error_code
341
put_buf(krb5_storage *sp, const struct ntlm_buf *buf)
342
{
343
krb5_error_code ret;
344
CHECK(krb5_storage_write(sp, buf->data, buf->length), buf->length);
345
ret = 0;
346
out:
347
return ret;
348
}
349
350
/**
351
* Frees the ntlm_targetinfo message
352
*
353
* @param ti targetinfo to be freed
354
*
355
* @ingroup ntlm_core
356
*/
357
358
void
359
heim_ntlm_free_targetinfo(struct ntlm_targetinfo *ti)
360
{
361
free(ti->servername);
362
free(ti->domainname);
363
free(ti->dnsdomainname);
364
free(ti->dnsservername);
365
free(ti->dnstreename);
366
memset(ti, 0, sizeof(*ti));
367
}
368
369
static int
370
encode_ti_string(krb5_storage *out, uint16_t type, int ucs2, char *s)
371
{
372
krb5_error_code ret;
373
CHECK(krb5_store_uint16(out, type), 0);
374
CHECK(krb5_store_uint16(out, len_string(ucs2, s)), 0);
375
CHECK(put_string(out, ucs2, s), 0);
376
out:
377
return ret;
378
}
379
380
/**
381
* Encodes a ntlm_targetinfo message.
382
*
383
* @param ti the ntlm_targetinfo message to encode.
384
* @param ucs2 ignored
385
* @param data is the return buffer with the encoded message, should be
386
* freed with heim_ntlm_free_buf().
387
*
388
* @return In case of success 0 is return, an errors, a errno in what
389
* went wrong.
390
*
391
* @ingroup ntlm_core
392
*/
393
394
int
395
heim_ntlm_encode_targetinfo(const struct ntlm_targetinfo *ti,
396
int ucs2,
397
struct ntlm_buf *data)
398
{
399
krb5_error_code ret;
400
krb5_storage *out;
401
402
data->data = NULL;
403
data->length = 0;
404
405
out = krb5_storage_emem();
406
if (out == NULL)
407
return ENOMEM;
408
409
krb5_storage_set_byteorder(out, KRB5_STORAGE_BYTEORDER_LE);
410
411
if (ti->servername)
412
CHECK(encode_ti_string(out, 1, ucs2, ti->servername), 0);
413
if (ti->domainname)
414
CHECK(encode_ti_string(out, 2, ucs2, ti->domainname), 0);
415
if (ti->dnsservername)
416
CHECK(encode_ti_string(out, 3, ucs2, ti->dnsservername), 0);
417
if (ti->dnsdomainname)
418
CHECK(encode_ti_string(out, 4, ucs2, ti->dnsdomainname), 0);
419
if (ti->dnstreename)
420
CHECK(encode_ti_string(out, 5, ucs2, ti->dnstreename), 0);
421
if (ti->avflags) {
422
CHECK(krb5_store_uint16(out, 6), 0);
423
CHECK(krb5_store_uint16(out, 4), 0);
424
CHECK(krb5_store_uint32(out, ti->avflags), 0);
425
}
426
427
/* end tag */
428
CHECK(krb5_store_int16(out, 0), 0);
429
CHECK(krb5_store_int16(out, 0), 0);
430
431
{
432
krb5_data d;
433
ret = krb5_storage_to_data(out, &d);
434
data->data = d.data;
435
data->length = d.length;
436
}
437
out:
438
krb5_storage_free(out);
439
return ret;
440
}
441
442
/**
443
* Decodes an NTLM targetinfo message
444
*
445
* @param data input data buffer with the encode NTLM targetinfo message
446
* @param ucs2 if the strings should be encoded with ucs2 (selected by flag in message).
447
* @param ti the decoded target info, should be freed with heim_ntlm_free_targetinfo().
448
*
449
* @return In case of success 0 is return, an errors, a errno in what
450
* went wrong.
451
*
452
* @ingroup ntlm_core
453
*/
454
455
int
456
heim_ntlm_decode_targetinfo(const struct ntlm_buf *data,
457
int ucs2,
458
struct ntlm_targetinfo *ti)
459
{
460
uint16_t type, len;
461
krb5_storage *in;
462
int ret = 0, done = 0;
463
464
memset(ti, 0, sizeof(*ti));
465
466
if (data->length == 0)
467
return 0;
468
469
in = krb5_storage_from_readonly_mem(data->data, data->length);
470
if (in == NULL)
471
return ENOMEM;
472
krb5_storage_set_byteorder(in, KRB5_STORAGE_BYTEORDER_LE);
473
474
while (!done) {
475
CHECK(krb5_ret_uint16(in, &type), 0);
476
CHECK(krb5_ret_uint16(in, &len), 0);
477
478
switch (type) {
479
case 0:
480
done = 1;
481
break;
482
case 1:
483
CHECK(ret_string(in, ucs2, len, &ti->servername), 0);
484
break;
485
case 2:
486
CHECK(ret_string(in, ucs2, len, &ti->domainname), 0);
487
break;
488
case 3:
489
CHECK(ret_string(in, ucs2, len, &ti->dnsservername), 0);
490
break;
491
case 4:
492
CHECK(ret_string(in, ucs2, len, &ti->dnsdomainname), 0);
493
break;
494
case 5:
495
CHECK(ret_string(in, ucs2, len, &ti->dnstreename), 0);
496
break;
497
case 6:
498
CHECK(krb5_ret_uint32(in, &ti->avflags), 0);
499
break;
500
default:
501
krb5_storage_seek(in, len, SEEK_CUR);
502
break;
503
}
504
}
505
out:
506
if (in)
507
krb5_storage_free(in);
508
return ret;
509
}
510
511
/**
512
* Frees the ntlm_type1 message
513
*
514
* @param data message to be freed
515
*
516
* @ingroup ntlm_core
517
*/
518
519
void
520
heim_ntlm_free_type1(struct ntlm_type1 *data)
521
{
522
if (data->domain)
523
free(data->domain);
524
if (data->hostname)
525
free(data->hostname);
526
memset(data, 0, sizeof(*data));
527
}
528
529
int
530
heim_ntlm_decode_type1(const struct ntlm_buf *buf, struct ntlm_type1 *data)
531
{
532
krb5_error_code ret;
533
unsigned char sig[8];
534
uint32_t type;
535
struct sec_buffer domain, hostname;
536
krb5_storage *in;
537
538
memset(data, 0, sizeof(*data));
539
540
in = krb5_storage_from_readonly_mem(buf->data, buf->length);
541
if (in == NULL) {
542
ret = ENOMEM;
543
goto out;
544
}
545
krb5_storage_set_byteorder(in, KRB5_STORAGE_BYTEORDER_LE);
546
547
CHECK(krb5_storage_read(in, sig, sizeof(sig)), sizeof(sig));
548
CHECK(memcmp(ntlmsigature, sig, sizeof(ntlmsigature)), 0);
549
CHECK(krb5_ret_uint32(in, &type), 0);
550
CHECK(type, 1);
551
CHECK(krb5_ret_uint32(in, &data->flags), 0);
552
if (data->flags & NTLM_OEM_SUPPLIED_DOMAIN)
553
CHECK(ret_sec_buffer(in, &domain), 0);
554
if (data->flags & NTLM_OEM_SUPPLIED_WORKSTATION)
555
CHECK(ret_sec_buffer(in, &hostname), 0);
556
#if 0
557
if (domain.offset > 32) {
558
CHECK(krb5_ret_uint32(in, &data->os[0]), 0);
559
CHECK(krb5_ret_uint32(in, &data->os[1]), 0);
560
}
561
#endif
562
if (data->flags & NTLM_OEM_SUPPLIED_DOMAIN)
563
CHECK(ret_sec_string(in, 0, &domain, &data->domain), 0);
564
if (data->flags & NTLM_OEM_SUPPLIED_WORKSTATION)
565
CHECK(ret_sec_string(in, 0, &hostname, &data->hostname), 0);
566
567
out:
568
if (in)
569
krb5_storage_free(in);
570
if (ret)
571
heim_ntlm_free_type1(data);
572
573
return ret;
574
}
575
576
/**
577
* Encodes an ntlm_type1 message.
578
*
579
* @param type1 the ntlm_type1 message to encode.
580
* @param data is the return buffer with the encoded message, should be
581
* freed with heim_ntlm_free_buf().
582
*
583
* @return In case of success 0 is return, an errors, a errno in what
584
* went wrong.
585
*
586
* @ingroup ntlm_core
587
*/
588
589
int
590
heim_ntlm_encode_type1(const struct ntlm_type1 *type1, struct ntlm_buf *data)
591
{
592
krb5_error_code ret;
593
struct sec_buffer domain, hostname;
594
krb5_storage *out;
595
uint32_t base, flags;
596
597
flags = type1->flags;
598
base = 16;
599
600
if (type1->domain) {
601
base += 8;
602
flags |= NTLM_OEM_SUPPLIED_DOMAIN;
603
}
604
if (type1->hostname) {
605
base += 8;
606
flags |= NTLM_OEM_SUPPLIED_WORKSTATION;
607
}
608
if (type1->os[0])
609
base += 8;
610
611
domain.offset = base;
612
if (type1->domain) {
613
domain.length = len_string(0, type1->domain);
614
domain.allocated = domain.length;
615
} else {
616
domain.length = 0;
617
domain.allocated = 0;
618
}
619
620
hostname.offset = domain.allocated + domain.offset;
621
if (type1->hostname) {
622
hostname.length = len_string(0, type1->hostname);
623
hostname.allocated = hostname.length;
624
} else {
625
hostname.length = 0;
626
hostname.allocated = 0;
627
}
628
629
out = krb5_storage_emem();
630
if (out == NULL)
631
return ENOMEM;
632
633
krb5_storage_set_byteorder(out, KRB5_STORAGE_BYTEORDER_LE);
634
CHECK(krb5_storage_write(out, ntlmsigature, sizeof(ntlmsigature)),
635
sizeof(ntlmsigature));
636
CHECK(krb5_store_uint32(out, 1), 0);
637
CHECK(krb5_store_uint32(out, flags), 0);
638
639
CHECK(store_sec_buffer(out, &domain), 0);
640
CHECK(store_sec_buffer(out, &hostname), 0);
641
#if 0
642
CHECK(krb5_store_uint32(out, type1->os[0]), 0);
643
CHECK(krb5_store_uint32(out, type1->os[1]), 0);
644
#endif
645
if (type1->domain)
646
CHECK(put_string(out, 0, type1->domain), 0);
647
if (type1->hostname)
648
CHECK(put_string(out, 0, type1->hostname), 0);
649
650
{
651
krb5_data d;
652
ret = krb5_storage_to_data(out, &d);
653
data->data = d.data;
654
data->length = d.length;
655
}
656
out:
657
krb5_storage_free(out);
658
659
return ret;
660
}
661
662
/**
663
* Frees the ntlm_type2 message
664
*
665
* @param data message to be freed
666
*
667
* @ingroup ntlm_core
668
*/
669
670
void
671
heim_ntlm_free_type2(struct ntlm_type2 *data)
672
{
673
if (data->targetname)
674
free(data->targetname);
675
heim_ntlm_free_buf(&data->targetinfo);
676
memset(data, 0, sizeof(*data));
677
}
678
679
int
680
heim_ntlm_decode_type2(const struct ntlm_buf *buf, struct ntlm_type2 *type2)
681
{
682
krb5_error_code ret;
683
unsigned char sig[8];
684
uint32_t type, ctx[2];
685
struct sec_buffer targetname, targetinfo;
686
krb5_storage *in;
687
int ucs2 = 0;
688
689
memset(type2, 0, sizeof(*type2));
690
691
in = krb5_storage_from_readonly_mem(buf->data, buf->length);
692
if (in == NULL) {
693
ret = ENOMEM;
694
goto out;
695
}
696
krb5_storage_set_byteorder(in, KRB5_STORAGE_BYTEORDER_LE);
697
698
CHECK(krb5_storage_read(in, sig, sizeof(sig)), sizeof(sig));
699
CHECK(memcmp(ntlmsigature, sig, sizeof(ntlmsigature)), 0);
700
CHECK(krb5_ret_uint32(in, &type), 0);
701
CHECK(type, 2);
702
703
CHECK(ret_sec_buffer(in, &targetname), 0);
704
CHECK(krb5_ret_uint32(in, &type2->flags), 0);
705
if (type2->flags & NTLM_NEG_UNICODE)
706
ucs2 = 1;
707
CHECK(krb5_storage_read(in, type2->challenge, sizeof(type2->challenge)),
708
sizeof(type2->challenge));
709
CHECK(krb5_ret_uint32(in, &ctx[0]), 0); /* context */
710
CHECK(krb5_ret_uint32(in, &ctx[1]), 0);
711
CHECK(ret_sec_buffer(in, &targetinfo), 0);
712
/* os version */
713
if (type2->flags & NTLM_NEG_VERSION) {
714
CHECK(krb5_ret_uint32(in, &type2->os[0]), 0);
715
CHECK(krb5_ret_uint32(in, &type2->os[1]), 0);
716
}
717
718
CHECK(ret_sec_string(in, ucs2, &targetname, &type2->targetname), 0);
719
CHECK(ret_buf(in, &targetinfo, &type2->targetinfo), 0);
720
ret = 0;
721
722
out:
723
if (in)
724
krb5_storage_free(in);
725
if (ret)
726
heim_ntlm_free_type2(type2);
727
728
return ret;
729
}
730
731
/**
732
* Encodes an ntlm_type2 message.
733
*
734
* @param type2 the ntlm_type2 message to encode.
735
* @param data is the return buffer with the encoded message, should be
736
* freed with heim_ntlm_free_buf().
737
*
738
* @return In case of success 0 is return, an errors, a errno in what
739
* went wrong.
740
*
741
* @ingroup ntlm_core
742
*/
743
744
int
745
heim_ntlm_encode_type2(const struct ntlm_type2 *type2, struct ntlm_buf *data)
746
{
747
struct sec_buffer targetname, targetinfo;
748
krb5_error_code ret;
749
krb5_storage *out = NULL;
750
uint32_t base;
751
int ucs2 = 0;
752
753
base = 48;
754
755
if (type2->flags & NTLM_NEG_VERSION)
756
base += 8;
757
758
if (type2->flags & NTLM_NEG_UNICODE)
759
ucs2 = 1;
760
761
targetname.offset = base;
762
targetname.length = len_string(ucs2, type2->targetname);
763
targetname.allocated = targetname.length;
764
765
targetinfo.offset = targetname.allocated + targetname.offset;
766
targetinfo.length = type2->targetinfo.length;
767
targetinfo.allocated = type2->targetinfo.length;
768
769
out = krb5_storage_emem();
770
if (out == NULL)
771
return ENOMEM;
772
773
krb5_storage_set_byteorder(out, KRB5_STORAGE_BYTEORDER_LE);
774
CHECK(krb5_storage_write(out, ntlmsigature, sizeof(ntlmsigature)),
775
sizeof(ntlmsigature));
776
CHECK(krb5_store_uint32(out, 2), 0);
777
CHECK(store_sec_buffer(out, &targetname), 0);
778
CHECK(krb5_store_uint32(out, type2->flags), 0);
779
CHECK(krb5_storage_write(out, type2->challenge, sizeof(type2->challenge)),
780
sizeof(type2->challenge));
781
CHECK(krb5_store_uint32(out, 0), 0); /* context */
782
CHECK(krb5_store_uint32(out, 0), 0);
783
CHECK(store_sec_buffer(out, &targetinfo), 0);
784
/* os version */
785
if (type2->flags & NTLM_NEG_VERSION) {
786
CHECK(krb5_store_uint32(out, type2->os[0]), 0);
787
CHECK(krb5_store_uint32(out, type2->os[1]), 0);
788
}
789
CHECK(put_string(out, ucs2, type2->targetname), 0);
790
CHECK(krb5_storage_write(out, type2->targetinfo.data,
791
type2->targetinfo.length),
792
type2->targetinfo.length);
793
794
{
795
krb5_data d;
796
ret = krb5_storage_to_data(out, &d);
797
data->data = d.data;
798
data->length = d.length;
799
}
800
801
out:
802
krb5_storage_free(out);
803
804
return ret;
805
}
806
807
/**
808
* Frees the ntlm_type3 message
809
*
810
* @param data message to be freed
811
*
812
* @ingroup ntlm_core
813
*/
814
815
void
816
heim_ntlm_free_type3(struct ntlm_type3 *data)
817
{
818
heim_ntlm_free_buf(&data->lm);
819
heim_ntlm_free_buf(&data->ntlm);
820
if (data->targetname)
821
free(data->targetname);
822
if (data->username)
823
free(data->username);
824
if (data->ws)
825
free(data->ws);
826
heim_ntlm_free_buf(&data->sessionkey);
827
memset(data, 0, sizeof(*data));
828
}
829
830
/*
831
*
832
*/
833
834
int
835
heim_ntlm_decode_type3(const struct ntlm_buf *buf,
836
int ucs2,
837
struct ntlm_type3 *type3)
838
{
839
krb5_error_code ret;
840
unsigned char sig[8];
841
uint32_t type;
842
krb5_storage *in;
843
struct sec_buffer lm, ntlm, target, username, sessionkey, ws;
844
uint32_t min_offset = 72;
845
846
memset(type3, 0, sizeof(*type3));
847
memset(&sessionkey, 0, sizeof(sessionkey));
848
849
in = krb5_storage_from_readonly_mem(buf->data, buf->length);
850
if (in == NULL) {
851
ret = ENOMEM;
852
goto out;
853
}
854
krb5_storage_set_byteorder(in, KRB5_STORAGE_BYTEORDER_LE);
855
856
CHECK(krb5_storage_read(in, sig, sizeof(sig)), sizeof(sig));
857
CHECK(memcmp(ntlmsigature, sig, sizeof(ntlmsigature)), 0);
858
CHECK(krb5_ret_uint32(in, &type), 0);
859
CHECK(type, 3);
860
CHECK(ret_sec_buffer(in, &lm), 0);
861
if (lm.allocated)
862
min_offset = min(min_offset, lm.offset);
863
CHECK(ret_sec_buffer(in, &ntlm), 0);
864
if (ntlm.allocated)
865
min_offset = min(min_offset, ntlm.offset);
866
CHECK(ret_sec_buffer(in, &target), 0);
867
if (target.allocated)
868
min_offset = min(min_offset, target.offset);
869
CHECK(ret_sec_buffer(in, &username), 0);
870
if (username.allocated)
871
min_offset = min(min_offset, username.offset);
872
CHECK(ret_sec_buffer(in, &ws), 0);
873
if (ws.allocated)
874
min_offset = min(min_offset, ws.offset);
875
876
if (min_offset > 52) {
877
CHECK(ret_sec_buffer(in, &sessionkey), 0);
878
min_offset = max(min_offset, sessionkey.offset);
879
CHECK(krb5_ret_uint32(in, &type3->flags), 0);
880
}
881
if (min_offset > 52 + 8 + 4 + 8) {
882
CHECK(krb5_ret_uint32(in, &type3->os[0]), 0);
883
CHECK(krb5_ret_uint32(in, &type3->os[1]), 0);
884
}
885
CHECK(ret_buf(in, &lm, &type3->lm), 0);
886
CHECK(ret_buf(in, &ntlm, &type3->ntlm), 0);
887
CHECK(ret_sec_string(in, ucs2, &target, &type3->targetname), 0);
888
CHECK(ret_sec_string(in, ucs2, &username, &type3->username), 0);
889
CHECK(ret_sec_string(in, ucs2, &ws, &type3->ws), 0);
890
if (sessionkey.offset)
891
CHECK(ret_buf(in, &sessionkey, &type3->sessionkey), 0);
892
893
out:
894
if (in)
895
krb5_storage_free(in);
896
if (ret)
897
heim_ntlm_free_type3(type3);
898
899
return ret;
900
}
901
902
/**
903
* Encodes an ntlm_type3 message.
904
*
905
* @param type3 the ntlm_type3 message to encode.
906
* @param data is the return buffer with the encoded message, should be
907
* freed with heim_ntlm_free_buf().
908
*
909
* @return In case of success 0 is return, an errors, a errno in what
910
* went wrong.
911
*
912
* @ingroup ntlm_core
913
*/
914
915
int
916
heim_ntlm_encode_type3(const struct ntlm_type3 *type3, struct ntlm_buf *data)
917
{
918
struct sec_buffer lm, ntlm, target, username, sessionkey, ws;
919
krb5_error_code ret;
920
krb5_storage *out = NULL;
921
uint32_t base;
922
int ucs2 = 0;
923
924
memset(&lm, 0, sizeof(lm));
925
memset(&ntlm, 0, sizeof(ntlm));
926
memset(&target, 0, sizeof(target));
927
memset(&username, 0, sizeof(username));
928
memset(&ws, 0, sizeof(ws));
929
memset(&sessionkey, 0, sizeof(sessionkey));
930
931
base = 52;
932
933
base += 8; /* sessionkey sec buf */
934
base += 4; /* flags */
935
936
if (type3->os[0]) {
937
base += 8;
938
}
939
940
if (type3->flags & NTLM_NEG_UNICODE)
941
ucs2 = 1;
942
943
target.offset = base;
944
target.length = len_string(ucs2, type3->targetname);
945
target.allocated = target.length;
946
947
username.offset = target.offset + target.allocated;
948
username.length = len_string(ucs2, type3->username);
949
username.allocated = username.length;
950
951
ws.offset = username.offset + username.allocated;
952
ws.length = len_string(ucs2, type3->ws);
953
ws.allocated = ws.length;
954
955
lm.offset = ws.offset + ws.allocated;
956
lm.length = type3->lm.length;
957
lm.allocated = type3->lm.length;
958
959
ntlm.offset = lm.offset + lm.allocated;
960
ntlm.length = type3->ntlm.length;
961
ntlm.allocated = ntlm.length;
962
963
sessionkey.offset = ntlm.offset + ntlm.allocated;
964
sessionkey.length = type3->sessionkey.length;
965
sessionkey.allocated = type3->sessionkey.length;
966
967
out = krb5_storage_emem();
968
if (out == NULL)
969
return ENOMEM;
970
971
krb5_storage_set_byteorder(out, KRB5_STORAGE_BYTEORDER_LE);
972
CHECK(krb5_storage_write(out, ntlmsigature, sizeof(ntlmsigature)),
973
sizeof(ntlmsigature));
974
CHECK(krb5_store_uint32(out, 3), 0);
975
976
CHECK(store_sec_buffer(out, &lm), 0);
977
CHECK(store_sec_buffer(out, &ntlm), 0);
978
CHECK(store_sec_buffer(out, &target), 0);
979
CHECK(store_sec_buffer(out, &username), 0);
980
CHECK(store_sec_buffer(out, &ws), 0);
981
CHECK(store_sec_buffer(out, &sessionkey), 0);
982
CHECK(krb5_store_uint32(out, type3->flags), 0);
983
984
#if 0
985
CHECK(krb5_store_uint32(out, 0), 0); /* os0 */
986
CHECK(krb5_store_uint32(out, 0), 0); /* os1 */
987
#endif
988
989
CHECK(put_string(out, ucs2, type3->targetname), 0);
990
CHECK(put_string(out, ucs2, type3->username), 0);
991
CHECK(put_string(out, ucs2, type3->ws), 0);
992
CHECK(put_buf(out, &type3->lm), 0);
993
CHECK(put_buf(out, &type3->ntlm), 0);
994
CHECK(put_buf(out, &type3->sessionkey), 0);
995
996
{
997
krb5_data d;
998
ret = krb5_storage_to_data(out, &d);
999
data->data = d.data;
1000
data->length = d.length;
1001
}
1002
1003
out:
1004
krb5_storage_free(out);
1005
1006
return ret;
1007
}
1008
1009
1010
/*
1011
*
1012
*/
1013
1014
static int
1015
splitandenc(unsigned char *hash,
1016
unsigned char *challenge,
1017
unsigned char *answer)
1018
{
1019
EVP_CIPHER_CTX *ctx;
1020
unsigned char key[8];
1021
1022
key[0] = hash[0];
1023
key[1] = (hash[0] << 7) | (hash[1] >> 1);
1024
key[2] = (hash[1] << 6) | (hash[2] >> 2);
1025
key[3] = (hash[2] << 5) | (hash[3] >> 3);
1026
key[4] = (hash[3] << 4) | (hash[4] >> 4);
1027
key[5] = (hash[4] << 3) | (hash[5] >> 5);
1028
key[6] = (hash[5] << 2) | (hash[6] >> 6);
1029
key[7] = (hash[6] << 1);
1030
1031
ctx = EVP_CIPHER_CTX_new();
1032
if (ctx == NULL)
1033
return ENOMEM;
1034
1035
EVP_CipherInit_ex(ctx, EVP_des_cbc(), NULL, key, NULL, 1);
1036
EVP_Cipher(ctx, answer, challenge, 8);
1037
EVP_CIPHER_CTX_free(ctx);
1038
memset(key, 0, sizeof(key));
1039
return 0;
1040
}
1041
1042
/**
1043
* Calculate the NTLM key, the password is assumed to be in UTF8.
1044
*
1045
* @param password password to calcute the key for.
1046
* @param key calcuted key, should be freed with heim_ntlm_free_buf().
1047
*
1048
* @return In case of success 0 is return, an errors, a errno in what
1049
* went wrong.
1050
*
1051
* @ingroup ntlm_core
1052
*/
1053
1054
int
1055
heim_ntlm_nt_key(const char *password, struct ntlm_buf *key)
1056
{
1057
struct ntlm_buf buf;
1058
EVP_MD_CTX *m;
1059
int ret;
1060
1061
key->data = malloc(MD5_DIGEST_LENGTH);
1062
if (key->data == NULL)
1063
return ENOMEM;
1064
key->length = MD5_DIGEST_LENGTH;
1065
1066
ret = ascii2ucs2le(password, 0, &buf);
1067
if (ret) {
1068
heim_ntlm_free_buf(key);
1069
return ret;
1070
}
1071
1072
m = EVP_MD_CTX_create();
1073
if (m == NULL) {
1074
heim_ntlm_free_buf(key);
1075
heim_ntlm_free_buf(&buf);
1076
return ENOMEM;
1077
}
1078
1079
EVP_DigestInit_ex(m, EVP_md4(), NULL);
1080
EVP_DigestUpdate(m, buf.data, buf.length);
1081
EVP_DigestFinal_ex(m, key->data, NULL);
1082
EVP_MD_CTX_destroy(m);
1083
1084
heim_ntlm_free_buf(&buf);
1085
return 0;
1086
}
1087
1088
/**
1089
* Calculate NTLMv1 response hash
1090
*
1091
* @param key the ntlm v1 key
1092
* @param len length of key
1093
* @param challenge sent by the server
1094
* @param answer calculated answer, should be freed with heim_ntlm_free_buf().
1095
*
1096
* @return In case of success 0 is return, an errors, a errno in what
1097
* went wrong.
1098
*
1099
* @ingroup ntlm_core
1100
*/
1101
1102
int
1103
heim_ntlm_calculate_ntlm1(void *key, size_t len,
1104
unsigned char challenge[8],
1105
struct ntlm_buf *answer)
1106
{
1107
unsigned char res[21];
1108
int ret;
1109
1110
if (len != MD4_DIGEST_LENGTH)
1111
return HNTLM_ERR_INVALID_LENGTH;
1112
1113
memcpy(res, key, len);
1114
memset(&res[MD4_DIGEST_LENGTH], 0, sizeof(res) - MD4_DIGEST_LENGTH);
1115
1116
answer->data = malloc(24);
1117
if (answer->data == NULL)
1118
return ENOMEM;
1119
answer->length = 24;
1120
1121
ret = splitandenc(&res[0], challenge, ((unsigned char *)answer->data) + 0);
1122
if (ret)
1123
goto out;
1124
ret = splitandenc(&res[7], challenge, ((unsigned char *)answer->data) + 8);
1125
if (ret)
1126
goto out;
1127
ret = splitandenc(&res[14], challenge, ((unsigned char *)answer->data) + 16);
1128
if (ret)
1129
goto out;
1130
1131
return 0;
1132
1133
out:
1134
heim_ntlm_free_buf(answer);
1135
return ret;
1136
}
1137
1138
int
1139
heim_ntlm_v1_base_session(void *key, size_t len,
1140
struct ntlm_buf *session)
1141
{
1142
EVP_MD_CTX *m;
1143
1144
session->length = MD4_DIGEST_LENGTH;
1145
session->data = malloc(session->length);
1146
if (session->data == NULL) {
1147
session->length = 0;
1148
return ENOMEM;
1149
}
1150
1151
m = EVP_MD_CTX_create();
1152
if (m == NULL) {
1153
heim_ntlm_free_buf(session);
1154
return ENOMEM;
1155
}
1156
EVP_DigestInit_ex(m, EVP_md4(), NULL);
1157
EVP_DigestUpdate(m, key, len);
1158
EVP_DigestFinal_ex(m, session->data, NULL);
1159
EVP_MD_CTX_destroy(m);
1160
1161
return 0;
1162
}
1163
1164
int
1165
heim_ntlm_v2_base_session(void *key, size_t len,
1166
struct ntlm_buf *ntlmResponse,
1167
struct ntlm_buf *session)
1168
{
1169
unsigned int hmaclen;
1170
HMAC_CTX *c;
1171
1172
if (ntlmResponse->length <= 16)
1173
return HNTLM_ERR_INVALID_LENGTH;
1174
1175
session->data = malloc(16);
1176
if (session->data == NULL)
1177
return ENOMEM;
1178
session->length = 16;
1179
1180
/* Note: key is the NTLMv2 key */
1181
c = HMAC_CTX_new();
1182
if (c == NULL) {
1183
heim_ntlm_free_buf(session);
1184
return ENOMEM;
1185
}
1186
HMAC_Init_ex(c, key, len, EVP_md5(), NULL);
1187
HMAC_Update(c, ntlmResponse->data, 16);
1188
HMAC_Final(c, session->data, &hmaclen);
1189
HMAC_CTX_free(c);
1190
1191
return 0;
1192
}
1193
1194
1195
int
1196
heim_ntlm_keyex_wrap(struct ntlm_buf *base_session,
1197
struct ntlm_buf *session,
1198
struct ntlm_buf *encryptedSession)
1199
{
1200
EVP_CIPHER_CTX *c;
1201
int ret;
1202
1203
session->length = MD4_DIGEST_LENGTH;
1204
session->data = malloc(session->length);
1205
if (session->data == NULL) {
1206
session->length = 0;
1207
return ENOMEM;
1208
}
1209
encryptedSession->length = MD4_DIGEST_LENGTH;
1210
encryptedSession->data = malloc(encryptedSession->length);
1211
if (encryptedSession->data == NULL) {
1212
heim_ntlm_free_buf(session);
1213
encryptedSession->length = 0;
1214
return ENOMEM;
1215
}
1216
1217
c = EVP_CIPHER_CTX_new();
1218
if (c == NULL) {
1219
heim_ntlm_free_buf(encryptedSession);
1220
heim_ntlm_free_buf(session);
1221
return ENOMEM;
1222
}
1223
1224
ret = EVP_CipherInit_ex(c, EVP_rc4(), NULL, base_session->data, NULL, 1);
1225
if (ret != 1) {
1226
EVP_CIPHER_CTX_free(c);
1227
heim_ntlm_free_buf(encryptedSession);
1228
heim_ntlm_free_buf(session);
1229
return HNTLM_ERR_CRYPTO;
1230
}
1231
1232
if (RAND_bytes(session->data, session->length) != 1) {
1233
EVP_CIPHER_CTX_free(c);
1234
heim_ntlm_free_buf(encryptedSession);
1235
heim_ntlm_free_buf(session);
1236
return HNTLM_ERR_RAND;
1237
}
1238
1239
EVP_Cipher(c, encryptedSession->data, session->data, encryptedSession->length);
1240
EVP_CIPHER_CTX_free(c);
1241
1242
return 0;
1243
1244
1245
1246
}
1247
1248
1249
1250
/**
1251
* Generates an NTLMv1 session random with assosited session master key.
1252
*
1253
* @param key the ntlm v1 key
1254
* @param len length of key
1255
* @param session generated session nonce, should be freed with heim_ntlm_free_buf().
1256
* @param master calculated session master key, should be freed with heim_ntlm_free_buf().
1257
*
1258
* @return In case of success 0 is return, an errors, a errno in what
1259
* went wrong.
1260
*
1261
* @ingroup ntlm_core
1262
*/
1263
1264
int
1265
heim_ntlm_build_ntlm1_master(void *key, size_t len,
1266
struct ntlm_buf *session,
1267
struct ntlm_buf *master)
1268
{
1269
struct ntlm_buf sess;
1270
int ret;
1271
1272
ret = heim_ntlm_v1_base_session(key, len, &sess);
1273
if (ret)
1274
return ret;
1275
1276
ret = heim_ntlm_keyex_wrap(&sess, session, master);
1277
heim_ntlm_free_buf(&sess);
1278
1279
return ret;
1280
}
1281
1282
/**
1283
* Generates an NTLMv2 session random with associated session master key.
1284
*
1285
* @param key the NTLMv2 key
1286
* @param len length of key
1287
* @param blob the NTLMv2 "blob"
1288
* @param session generated session nonce, should be freed with heim_ntlm_free_buf().
1289
* @param master calculated session master key, should be freed with heim_ntlm_free_buf().
1290
*
1291
* @return In case of success 0 is return, an errors, a errno in what
1292
* went wrong.
1293
*
1294
* @ingroup ntlm_core
1295
*/
1296
1297
1298
int
1299
heim_ntlm_build_ntlm2_master(void *key, size_t len,
1300
struct ntlm_buf *blob,
1301
struct ntlm_buf *session,
1302
struct ntlm_buf *master)
1303
{
1304
struct ntlm_buf sess;
1305
int ret;
1306
1307
ret = heim_ntlm_v2_base_session(key, len, blob, &sess);
1308
if (ret)
1309
return ret;
1310
1311
ret = heim_ntlm_keyex_wrap(&sess, session, master);
1312
heim_ntlm_free_buf(&sess);
1313
1314
return ret;
1315
}
1316
1317
/**
1318
* Given a key and encrypted session, unwrap the session key
1319
*
1320
* @param baseKey the sessionBaseKey
1321
* @param encryptedSession encrypted session, type3.session field.
1322
* @param session generated session nonce, should be freed with heim_ntlm_free_buf().
1323
*
1324
* @return In case of success 0 is return, an errors, a errno in what
1325
* went wrong.
1326
*
1327
* @ingroup ntlm_core
1328
*/
1329
1330
int
1331
heim_ntlm_keyex_unwrap(struct ntlm_buf *baseKey,
1332
struct ntlm_buf *encryptedSession,
1333
struct ntlm_buf *session)
1334
{
1335
EVP_CIPHER_CTX *c;
1336
1337
memset(session, 0, sizeof(*session));
1338
1339
if (baseKey->length != MD4_DIGEST_LENGTH)
1340
return HNTLM_ERR_INVALID_LENGTH;
1341
1342
session->length = MD4_DIGEST_LENGTH;
1343
session->data = malloc(session->length);
1344
if (session->data == NULL) {
1345
session->length = 0;
1346
return ENOMEM;
1347
}
1348
c = EVP_CIPHER_CTX_new();
1349
if (c == NULL) {
1350
heim_ntlm_free_buf(session);
1351
return ENOMEM;
1352
}
1353
1354
if (EVP_CipherInit_ex(c, EVP_rc4(), NULL, baseKey->data, NULL, 0) != 1) {
1355
EVP_CIPHER_CTX_free(c);
1356
heim_ntlm_free_buf(session);
1357
return HNTLM_ERR_CRYPTO;
1358
}
1359
1360
EVP_Cipher(c, session->data, encryptedSession->data, session->length);
1361
EVP_CIPHER_CTX_free(c);
1362
1363
return 0;
1364
}
1365
1366
1367
/**
1368
* Generates an NTLMv2 session key.
1369
*
1370
* @param key the ntlm key
1371
* @param len length of key
1372
* @param username name of the user, as sent in the message, assumed to be in UTF8.
1373
* @param target the name of the target, assumed to be in UTF8.
1374
* @param ntlmv2 the ntlmv2 session key
1375
*
1376
* @return 0 on success, or an error code on failure.
1377
*
1378
* @ingroup ntlm_core
1379
*/
1380
1381
int
1382
heim_ntlm_ntlmv2_key(const void *key, size_t len,
1383
const char *username,
1384
const char *target,
1385
unsigned char ntlmv2[16])
1386
{
1387
int ret;
1388
unsigned int hmaclen;
1389
HMAC_CTX *c;
1390
1391
c = HMAC_CTX_new();
1392
if (c == NULL)
1393
return ENOMEM;
1394
HMAC_Init_ex(c, key, len, EVP_md5(), NULL);
1395
{
1396
struct ntlm_buf buf;
1397
/* uppercase username and turn it into ucs2-le */
1398
ret = ascii2ucs2le(username, 1, &buf);
1399
if (ret)
1400
goto out;
1401
HMAC_Update(c, buf.data, buf.length);
1402
free(buf.data);
1403
/* uppercase target and turn into ucs2-le */
1404
ret = ascii2ucs2le(target, 1, &buf);
1405
if (ret)
1406
goto out;
1407
HMAC_Update(c, buf.data, buf.length);
1408
free(buf.data);
1409
}
1410
HMAC_Final(c, ntlmv2, &hmaclen);
1411
out:
1412
HMAC_CTX_free(c);
1413
1414
return ret;
1415
}
1416
1417
/*
1418
*
1419
*/
1420
1421
#define NTTIME_EPOCH 0x019DB1DED53E8000LL
1422
1423
static uint64_t
1424
unix2nttime(time_t unix_time)
1425
{
1426
long long wt;
1427
wt = unix_time * (uint64_t)10000000 + (uint64_t)NTTIME_EPOCH;
1428
return wt;
1429
}
1430
1431
static time_t
1432
nt2unixtime(uint64_t t)
1433
{
1434
t = ((t - (uint64_t)NTTIME_EPOCH) / (uint64_t)10000000);
1435
if (t > (((uint64_t)(time_t)(~(uint64_t)0)) >> 1))
1436
return 0;
1437
return (time_t)t;
1438
}
1439
1440
/**
1441
* Calculate LMv2 response
1442
*
1443
* @param key the ntlm key
1444
* @param len length of key
1445
* @param username name of the user, as sent in the message, assumed to be in UTF8.
1446
* @param target the name of the target, assumed to be in UTF8.
1447
* @param serverchallenge challenge as sent by the server in the type2 message.
1448
* @param ntlmv2 calculated session key
1449
* @param answer ntlm response answer, should be freed with heim_ntlm_free_buf().
1450
*
1451
* @return In case of success 0 is return, an errors, a errno in what
1452
* went wrong.
1453
*
1454
* @ingroup ntlm_core
1455
*/
1456
1457
int
1458
heim_ntlm_calculate_lm2(const void *key, size_t len,
1459
const char *username,
1460
const char *target,
1461
const unsigned char serverchallenge[8],
1462
unsigned char ntlmv2[16],
1463
struct ntlm_buf *answer)
1464
{
1465
unsigned char clientchallenge[8];
1466
int ret;
1467
1468
if (RAND_bytes(clientchallenge, sizeof(clientchallenge)) != 1)
1469
return HNTLM_ERR_RAND;
1470
1471
/* calculate ntlmv2 key */
1472
1473
heim_ntlm_ntlmv2_key(key, len, username, target, ntlmv2);
1474
1475
answer->data = malloc(24);
1476
if (answer->data == NULL)
1477
return ENOMEM;
1478
answer->length = 24;
1479
1480
ret = heim_ntlm_derive_ntlm2_sess(ntlmv2, clientchallenge, 8,
1481
serverchallenge, answer->data);
1482
if (ret)
1483
return ret;
1484
1485
memcpy(((uint8_t *)answer->data) + 16, clientchallenge, 8);
1486
1487
return 0;
1488
}
1489
1490
1491
/**
1492
* Calculate NTLMv2 response
1493
*
1494
* @param key the ntlm key
1495
* @param len length of key
1496
* @param username name of the user, as sent in the message, assumed to be in UTF8.
1497
* @param target the name of the target, assumed to be in UTF8.
1498
* @param serverchallenge challenge as sent by the server in the type2 message.
1499
* @param infotarget infotarget as sent by the server in the type2 message.
1500
* @param ntlmv2 calculated session key
1501
* @param answer ntlm response answer, should be freed with heim_ntlm_free_buf().
1502
*
1503
* @return In case of success 0 is return, an errors, a errno in what
1504
* went wrong.
1505
*
1506
* @ingroup ntlm_core
1507
*/
1508
1509
int
1510
heim_ntlm_calculate_ntlm2(const void *key, size_t len,
1511
const char *username,
1512
const char *target,
1513
const unsigned char serverchallenge[8],
1514
const struct ntlm_buf *infotarget,
1515
unsigned char ntlmv2[16],
1516
struct ntlm_buf *answer)
1517
{
1518
krb5_error_code ret;
1519
krb5_data data;
1520
unsigned char ntlmv2answer[16];
1521
krb5_storage *sp;
1522
unsigned char clientchallenge[8];
1523
uint64_t t;
1524
int code;
1525
1526
t = unix2nttime(time(NULL));
1527
1528
if (RAND_bytes(clientchallenge, sizeof(clientchallenge)) != 1)
1529
return HNTLM_ERR_RAND;
1530
1531
/* calculate ntlmv2 key */
1532
1533
heim_ntlm_ntlmv2_key(key, len, username, target, ntlmv2);
1534
1535
/* calculate and build ntlmv2 answer */
1536
1537
sp = krb5_storage_emem();
1538
if (sp == NULL)
1539
return ENOMEM;
1540
krb5_storage_set_flags(sp, KRB5_STORAGE_BYTEORDER_LE);
1541
1542
CHECK(krb5_store_uint32(sp, 0x00000101), 0);
1543
CHECK(krb5_store_uint32(sp, 0), 0);
1544
/* timestamp le 64 bit ts */
1545
CHECK(krb5_store_uint32(sp, t & 0xffffffff), 0);
1546
CHECK(krb5_store_uint32(sp, t >> 32), 0);
1547
1548
CHECK(krb5_storage_write(sp, clientchallenge, 8), 8);
1549
1550
CHECK(krb5_store_uint32(sp, 0), 0); /* unknown but zero will work */
1551
CHECK(krb5_storage_write(sp, infotarget->data, infotarget->length),
1552
infotarget->length);
1553
CHECK(krb5_store_uint32(sp, 0), 0); /* unknown but zero will work */
1554
1555
CHECK(krb5_storage_to_data(sp, &data), 0);
1556
krb5_storage_free(sp);
1557
sp = NULL;
1558
1559
code = heim_ntlm_derive_ntlm2_sess(ntlmv2, data.data, data.length, serverchallenge, ntlmv2answer);
1560
if (code) {
1561
krb5_data_free(&data);
1562
return code;
1563
}
1564
1565
sp = krb5_storage_emem();
1566
if (sp == NULL) {
1567
krb5_data_free(&data);
1568
return ENOMEM;
1569
}
1570
1571
CHECK(krb5_storage_write(sp, ntlmv2answer, 16), 16);
1572
CHECK(krb5_storage_write(sp, data.data, data.length), data.length);
1573
krb5_data_free(&data);
1574
1575
CHECK(krb5_storage_to_data(sp, &data), 0);
1576
krb5_storage_free(sp);
1577
sp = NULL;
1578
1579
answer->data = data.data;
1580
answer->length = data.length;
1581
1582
return 0;
1583
out:
1584
if (sp)
1585
krb5_storage_free(sp);
1586
return ret;
1587
}
1588
1589
static const int authtimediff = 3600 * 2; /* 2 hours */
1590
1591
/**
1592
* Verify NTLMv2 response.
1593
*
1594
* @param key the ntlm key
1595
* @param len length of key
1596
* @param username name of the user, as sent in the message, assumed to be in UTF8.
1597
* @param target the name of the target, assumed to be in UTF8.
1598
* @param now the time now (0 if the library should pick it up itself)
1599
* @param serverchallenge challenge as sent by the server in the type2 message.
1600
* @param answer ntlm response answer, should be freed with heim_ntlm_free_buf().
1601
* @param infotarget infotarget as sent by the server in the type2 message.
1602
* @param ntlmv2 calculated session key
1603
*
1604
* @return In case of success 0 is return, an errors, a errno in what
1605
* went wrong.
1606
*
1607
* @ingroup ntlm_core
1608
*/
1609
1610
int
1611
heim_ntlm_verify_ntlm2(const void *key, size_t len,
1612
const char *username,
1613
const char *target,
1614
time_t now,
1615
const unsigned char serverchallenge[8],
1616
const struct ntlm_buf *answer,
1617
struct ntlm_buf *infotarget,
1618
unsigned char ntlmv2[16])
1619
{
1620
krb5_error_code ret;
1621
unsigned char clientanswer[16];
1622
unsigned char clientnonce[8];
1623
unsigned char serveranswer[16];
1624
krb5_storage *sp;
1625
time_t authtime;
1626
uint32_t temp;
1627
uint64_t t;
1628
int code;
1629
1630
infotarget->length = 0;
1631
infotarget->data = NULL;
1632
1633
if (answer->length < 16)
1634
return HNTLM_ERR_INVALID_LENGTH;
1635
1636
if (now == 0)
1637
now = time(NULL);
1638
1639
/* calculate ntlmv2 key */
1640
1641
heim_ntlm_ntlmv2_key(key, len, username, target, ntlmv2);
1642
1643
/* calculate and build ntlmv2 answer */
1644
1645
sp = krb5_storage_from_readonly_mem(answer->data, answer->length);
1646
if (sp == NULL)
1647
return ENOMEM;
1648
krb5_storage_set_flags(sp, KRB5_STORAGE_BYTEORDER_LE);
1649
1650
CHECK(krb5_storage_read(sp, clientanswer, 16), 16);
1651
1652
CHECK(krb5_ret_uint32(sp, &temp), 0);
1653
CHECK(temp, 0x00000101);
1654
CHECK(krb5_ret_uint32(sp, &temp), 0);
1655
CHECK(temp, 0);
1656
/* timestamp le 64 bit ts */
1657
CHECK(krb5_ret_uint32(sp, &temp), 0);
1658
t = temp;
1659
CHECK(krb5_ret_uint32(sp, &temp), 0);
1660
t |= ((uint64_t)temp)<< 32;
1661
1662
authtime = nt2unixtime(t);
1663
1664
if (abs((int)(authtime - now)) > authtimediff) {
1665
ret = HNTLM_ERR_TIME_SKEW;
1666
goto out;
1667
}
1668
1669
/* client challenge */
1670
CHECK(krb5_storage_read(sp, clientnonce, 8), 8);
1671
1672
CHECK(krb5_ret_uint32(sp, &temp), 0); /* unknown */
1673
1674
/* should really unparse the infotarget, but lets pick up everything */
1675
infotarget->length = answer->length - krb5_storage_seek(sp, 0, SEEK_CUR);
1676
infotarget->data = malloc(infotarget->length);
1677
if (infotarget->data == NULL) {
1678
ret = ENOMEM;
1679
goto out;
1680
}
1681
CHECK(krb5_storage_read(sp, infotarget->data, infotarget->length),
1682
infotarget->length);
1683
/* XXX remove the unknown ?? */
1684
krb5_storage_free(sp);
1685
sp = NULL;
1686
1687
if (answer->length < 16) {
1688
ret = HNTLM_ERR_INVALID_LENGTH;
1689
goto out;
1690
}
1691
1692
ret = heim_ntlm_derive_ntlm2_sess(ntlmv2,
1693
((unsigned char *)answer->data) + 16, answer->length - 16,
1694
serverchallenge,
1695
serveranswer);
1696
if (ret)
1697
goto out;
1698
1699
if (memcmp(serveranswer, clientanswer, 16) != 0) {
1700
heim_ntlm_free_buf(infotarget);
1701
return HNTLM_ERR_AUTH;
1702
}
1703
1704
return 0;
1705
out:
1706
heim_ntlm_free_buf(infotarget);
1707
if (sp)
1708
krb5_storage_free(sp);
1709
return ret;
1710
}
1711
1712
1713
/*
1714
* Calculate the NTLM2 Session Response
1715
*
1716
* @param clnt_nonce client nonce
1717
* @param svr_chal server challage
1718
* @param ntlm2_hash ntlm hash
1719
* @param lm The LM response, should be freed with heim_ntlm_free_buf().
1720
* @param ntlm The NTLM response, should be freed with heim_ntlm_free_buf().
1721
*
1722
* @return In case of success 0 is return, an errors, a errno in what
1723
* went wrong.
1724
*
1725
* @ingroup ntlm_core
1726
*/
1727
1728
int
1729
heim_ntlm_calculate_ntlm2_sess(const unsigned char clnt_nonce[8],
1730
const unsigned char svr_chal[8],
1731
const unsigned char ntlm_hash[16],
1732
struct ntlm_buf *lm,
1733
struct ntlm_buf *ntlm)
1734
{
1735
unsigned char ntlm2_sess_hash[8];
1736
unsigned char res[21], *resp;
1737
int code;
1738
1739
code = heim_ntlm_calculate_ntlm2_sess_hash(clnt_nonce, svr_chal,
1740
ntlm2_sess_hash);
1741
if (code) {
1742
return code;
1743
}
1744
1745
lm->data = malloc(24);
1746
if (lm->data == NULL) {
1747
return ENOMEM;
1748
}
1749
lm->length = 24;
1750
1751
ntlm->data = malloc(24);
1752
if (ntlm->data == NULL) {
1753
free(lm->data);
1754
lm->data = NULL;
1755
return ENOMEM;
1756
}
1757
ntlm->length = 24;
1758
1759
/* first setup the lm resp */
1760
memset(lm->data, 0, 24);
1761
memcpy(lm->data, clnt_nonce, 8);
1762
1763
memset(res, 0, sizeof(res));
1764
memcpy(res, ntlm_hash, 16);
1765
1766
resp = ntlm->data;
1767
code = splitandenc(&res[0], ntlm2_sess_hash, resp + 0);
1768
if (code)
1769
goto out;
1770
code = splitandenc(&res[7], ntlm2_sess_hash, resp + 8);
1771
if (code)
1772
goto out;
1773
code = splitandenc(&res[14], ntlm2_sess_hash, resp + 16);
1774
if (code)
1775
goto out;
1776
1777
return 0;
1778
1779
out:
1780
heim_ntlm_free_buf(ntlm);
1781
heim_ntlm_free_buf(lm);
1782
return code;
1783
}
1784
1785
1786
/*
1787
* Calculate the NTLM2 Session "Verifier"
1788
*
1789
* @param clnt_nonce client nonce
1790
* @param svr_chal server challage
1791
* @param hash The NTLM session verifier
1792
*
1793
* @return In case of success 0 is return, an errors, a errno in what
1794
* went wrong.
1795
*
1796
* @ingroup ntlm_core
1797
*/
1798
1799
int
1800
heim_ntlm_calculate_ntlm2_sess_hash(const unsigned char clnt_nonce[8],
1801
const unsigned char svr_chal[8],
1802
unsigned char verifier[8])
1803
{
1804
unsigned char ntlm2_sess_hash[MD5_DIGEST_LENGTH];
1805
EVP_MD_CTX *m;
1806
1807
m = EVP_MD_CTX_create();
1808
if (m == NULL)
1809
return ENOMEM;
1810
1811
EVP_DigestInit_ex(m, EVP_md5(), NULL);
1812
EVP_DigestUpdate(m, svr_chal, 8); /* session nonce part 1 */
1813
EVP_DigestUpdate(m, clnt_nonce, 8); /* session nonce part 2 */
1814
EVP_DigestFinal_ex(m, ntlm2_sess_hash, NULL); /* will only use first 8 bytes */
1815
EVP_MD_CTX_destroy(m);
1816
1817
memcpy(verifier, ntlm2_sess_hash, 8);
1818
1819
return 0;
1820
}
1821
1822
1823
/*
1824
* Derive a NTLM2 session key
1825
*
1826
* @param sessionkey session key from domain controller
1827
* @param clnt_nonce client nonce
1828
* @param svr_chal server challenge
1829
* @param derivedkey salted session key
1830
*
1831
* @return In case of success 0 is return, an errors, a errno in what
1832
* went wrong.
1833
*
1834
* @ingroup ntlm_core
1835
*/
1836
1837
int
1838
heim_ntlm_derive_ntlm2_sess(const unsigned char sessionkey[16],
1839
const unsigned char *clnt_nonce, size_t clnt_nonce_length,
1840
const unsigned char svr_chal[8],
1841
unsigned char derivedkey[16])
1842
{
1843
unsigned int hmaclen;
1844
HMAC_CTX *c;
1845
1846
/* HMAC(Ksession, serverchallenge || clientchallenge) */
1847
c = HMAC_CTX_new();
1848
if (c == NULL)
1849
return ENOMEM;
1850
HMAC_Init_ex(c, sessionkey, 16, EVP_md5(), NULL);
1851
HMAC_Update(c, svr_chal, 8);
1852
HMAC_Update(c, clnt_nonce, clnt_nonce_length);
1853
HMAC_Final(c, derivedkey, &hmaclen);
1854
HMAC_CTX_free(c);
1855
return 0;
1856
}
1857
1858
1859