Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/crypto/heimdal/kdc/digest.c
34869 views
1
/*
2
* Copyright (c) 2006 - 2007 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 "kdc_locl.h"
35
#include <hex.h>
36
37
#ifdef DIGEST
38
39
#define MS_CHAP_V2 0x20
40
#define CHAP_MD5 0x10
41
#define DIGEST_MD5 0x08
42
#define NTLM_V2 0x04
43
#define NTLM_V1_SESSION 0x02
44
#define NTLM_V1 0x01
45
46
const struct units _kdc_digestunits[] = {
47
{"ms-chap-v2", 1U << 5},
48
{"chap-md5", 1U << 4},
49
{"digest-md5", 1U << 3},
50
{"ntlm-v2", 1U << 2},
51
{"ntlm-v1-session", 1U << 1},
52
{"ntlm-v1", 1U << 0},
53
{NULL, 0}
54
};
55
56
57
static krb5_error_code
58
get_digest_key(krb5_context context,
59
krb5_kdc_configuration *config,
60
hdb_entry_ex *server,
61
krb5_crypto *crypto)
62
{
63
krb5_error_code ret;
64
krb5_enctype enctype;
65
Key *key;
66
67
ret = _kdc_get_preferred_key(context,
68
config,
69
server,
70
"digest-service",
71
&enctype,
72
&key);
73
if (ret)
74
return ret;
75
return krb5_crypto_init(context, &key->key, 0, crypto);
76
}
77
78
/*
79
*
80
*/
81
82
static char *
83
get_ntlm_targetname(krb5_context context,
84
hdb_entry_ex *client)
85
{
86
char *targetname, *p;
87
88
targetname = strdup(krb5_principal_get_realm(context,
89
client->entry.principal));
90
if (targetname == NULL)
91
return NULL;
92
93
p = strchr(targetname, '.');
94
if (p)
95
*p = '\0';
96
97
strupr(targetname);
98
return targetname;
99
}
100
101
static krb5_error_code
102
fill_targetinfo(krb5_context context,
103
char *targetname,
104
hdb_entry_ex *client,
105
krb5_data *data)
106
{
107
struct ntlm_targetinfo ti;
108
krb5_error_code ret;
109
struct ntlm_buf d;
110
krb5_principal p;
111
const char *str;
112
113
memset(&ti, 0, sizeof(ti));
114
115
ti.domainname = targetname;
116
p = client->entry.principal;
117
str = krb5_principal_get_comp_string(context, p, 0);
118
if (str != NULL &&
119
(strcmp("host", str) == 0 ||
120
strcmp("ftp", str) == 0 ||
121
strcmp("imap", str) == 0 ||
122
strcmp("pop", str) == 0 ||
123
strcmp("smtp", str)))
124
{
125
str = krb5_principal_get_comp_string(context, p, 1);
126
ti.dnsservername = rk_UNCONST(str);
127
}
128
129
ret = heim_ntlm_encode_targetinfo(&ti, 1, &d);
130
if (ret)
131
return ret;
132
133
data->data = d.data;
134
data->length = d.length;
135
136
return 0;
137
}
138
139
140
static const unsigned char ms_chap_v2_magic1[39] = {
141
0x4D, 0x61, 0x67, 0x69, 0x63, 0x20, 0x73, 0x65, 0x72, 0x76,
142
0x65, 0x72, 0x20, 0x74, 0x6F, 0x20, 0x63, 0x6C, 0x69, 0x65,
143
0x6E, 0x74, 0x20, 0x73, 0x69, 0x67, 0x6E, 0x69, 0x6E, 0x67,
144
0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x61, 0x6E, 0x74
145
};
146
static const unsigned char ms_chap_v2_magic2[41] = {
147
0x50, 0x61, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x6D, 0x61, 0x6B,
148
0x65, 0x20, 0x69, 0x74, 0x20, 0x64, 0x6F, 0x20, 0x6D, 0x6F,
149
0x72, 0x65, 0x20, 0x74, 0x68, 0x61, 0x6E, 0x20, 0x6F, 0x6E,
150
0x65, 0x20, 0x69, 0x74, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6F,
151
0x6E
152
};
153
static const unsigned char ms_rfc3079_magic1[27] = {
154
0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74,
155
0x68, 0x65, 0x20, 0x4d, 0x50, 0x50, 0x45, 0x20, 0x4d,
156
0x61, 0x73, 0x74, 0x65, 0x72, 0x20, 0x4b, 0x65, 0x79
157
};
158
159
/*
160
*
161
*/
162
163
static krb5_error_code
164
get_password_entry(krb5_context context,
165
krb5_kdc_configuration *config,
166
const char *username,
167
char **password)
168
{
169
krb5_principal clientprincipal;
170
krb5_error_code ret;
171
hdb_entry_ex *user;
172
HDB *db;
173
174
/* get username */
175
ret = krb5_parse_name(context, username, &clientprincipal);
176
if (ret)
177
return ret;
178
179
ret = _kdc_db_fetch(context, config, clientprincipal,
180
HDB_F_GET_CLIENT, NULL, &db, &user);
181
krb5_free_principal(context, clientprincipal);
182
if (ret)
183
return ret;
184
185
ret = hdb_entry_get_password(context, db, &user->entry, password);
186
if (ret || password == NULL) {
187
if (ret == 0) {
188
ret = EINVAL;
189
krb5_set_error_message(context, ret, "password missing");
190
}
191
memset(user, 0, sizeof(*user));
192
}
193
_kdc_free_ent (context, user);
194
return ret;
195
}
196
197
/*
198
*
199
*/
200
201
krb5_error_code
202
_kdc_do_digest(krb5_context context,
203
krb5_kdc_configuration *config,
204
const struct DigestREQ *req, krb5_data *reply,
205
const char *from, struct sockaddr *addr)
206
{
207
krb5_error_code ret = 0;
208
krb5_ticket *ticket = NULL;
209
krb5_auth_context ac = NULL;
210
krb5_keytab id = NULL;
211
krb5_crypto crypto = NULL;
212
DigestReqInner ireq;
213
DigestRepInner r;
214
DigestREP rep;
215
krb5_flags ap_req_options;
216
krb5_data buf;
217
size_t size;
218
krb5_storage *sp = NULL;
219
Checksum res;
220
hdb_entry_ex *server = NULL, *user = NULL;
221
hdb_entry_ex *client = NULL;
222
char *client_name = NULL, *password = NULL;
223
krb5_data serverNonce;
224
225
if(!config->enable_digest) {
226
kdc_log(context, config, 0,
227
"Rejected digest request (disabled) from %s", from);
228
return KRB5KDC_ERR_POLICY;
229
}
230
231
krb5_data_zero(&buf);
232
krb5_data_zero(reply);
233
krb5_data_zero(&serverNonce);
234
memset(&ireq, 0, sizeof(ireq));
235
memset(&r, 0, sizeof(r));
236
memset(&rep, 0, sizeof(rep));
237
memset(&res, 0, sizeof(res));
238
239
kdc_log(context, config, 0, "Digest request from %s", from);
240
241
ret = krb5_kt_resolve(context, "HDB:", &id);
242
if (ret) {
243
kdc_log(context, config, 0, "Can't open database for digest");
244
goto out;
245
}
246
247
ret = krb5_rd_req(context,
248
&ac,
249
&req->apReq,
250
NULL,
251
id,
252
&ap_req_options,
253
&ticket);
254
if (ret)
255
goto out;
256
257
/* check the server principal in the ticket matches digest/R@R */
258
{
259
krb5_principal principal = NULL;
260
const char *p, *rr;
261
262
ret = krb5_ticket_get_server(context, ticket, &principal);
263
if (ret)
264
goto out;
265
266
ret = EINVAL;
267
krb5_set_error_message(context, ret, "Wrong digest server principal used");
268
p = krb5_principal_get_comp_string(context, principal, 0);
269
if (p == NULL) {
270
krb5_free_principal(context, principal);
271
goto out;
272
}
273
if (strcmp(p, KRB5_DIGEST_NAME) != 0) {
274
krb5_free_principal(context, principal);
275
goto out;
276
}
277
278
p = krb5_principal_get_comp_string(context, principal, 1);
279
if (p == NULL) {
280
krb5_free_principal(context, principal);
281
goto out;
282
}
283
rr = krb5_principal_get_realm(context, principal);
284
if (rr == NULL) {
285
krb5_free_principal(context, principal);
286
goto out;
287
}
288
if (strcmp(p, rr) != 0) {
289
krb5_free_principal(context, principal);
290
goto out;
291
}
292
krb5_clear_error_message(context);
293
294
ret = _kdc_db_fetch(context, config, principal,
295
HDB_F_GET_SERVER, NULL, NULL, &server);
296
if (ret)
297
goto out;
298
299
krb5_free_principal(context, principal);
300
}
301
302
/* check the client is allowed to do digest auth */
303
{
304
krb5_principal principal = NULL;
305
306
ret = krb5_ticket_get_client(context, ticket, &principal);
307
if (ret)
308
goto out;
309
310
ret = krb5_unparse_name(context, principal, &client_name);
311
if (ret) {
312
krb5_free_principal(context, principal);
313
goto out;
314
}
315
316
ret = _kdc_db_fetch(context, config, principal,
317
HDB_F_GET_CLIENT, NULL, NULL, &client);
318
krb5_free_principal(context, principal);
319
if (ret)
320
goto out;
321
322
if (client->entry.flags.allow_digest == 0) {
323
kdc_log(context, config, 0,
324
"Client %s tried to use digest "
325
"but is not allowed to",
326
client_name);
327
ret = KRB5KDC_ERR_POLICY;
328
krb5_set_error_message(context, ret,
329
"Client is not permitted to use digest");
330
goto out;
331
}
332
}
333
334
/* unpack request */
335
{
336
krb5_keyblock *key;
337
338
ret = krb5_auth_con_getremotesubkey(context, ac, &key);
339
if (ret)
340
goto out;
341
if (key == NULL) {
342
ret = EINVAL;
343
krb5_set_error_message(context, ret, "digest: remote subkey not found");
344
goto out;
345
}
346
347
ret = krb5_crypto_init(context, key, 0, &crypto);
348
krb5_free_keyblock (context, key);
349
if (ret)
350
goto out;
351
}
352
353
ret = krb5_decrypt_EncryptedData(context, crypto, KRB5_KU_DIGEST_ENCRYPT,
354
&req->innerReq, &buf);
355
krb5_crypto_destroy(context, crypto);
356
crypto = NULL;
357
if (ret)
358
goto out;
359
360
ret = decode_DigestReqInner(buf.data, buf.length, &ireq, NULL);
361
krb5_data_free(&buf);
362
if (ret) {
363
krb5_set_error_message(context, ret, "Failed to decode digest inner request");
364
goto out;
365
}
366
367
kdc_log(context, config, 0, "Valid digest request from %s (%s)",
368
client_name, from);
369
370
/*
371
* Process the inner request
372
*/
373
374
switch (ireq.element) {
375
case choice_DigestReqInner_init: {
376
unsigned char server_nonce[16], identifier;
377
378
RAND_bytes(&identifier, sizeof(identifier));
379
RAND_bytes(server_nonce, sizeof(server_nonce));
380
381
server_nonce[0] = kdc_time & 0xff;
382
server_nonce[1] = (kdc_time >> 8) & 0xff;
383
server_nonce[2] = (kdc_time >> 16) & 0xff;
384
server_nonce[3] = (kdc_time >> 24) & 0xff;
385
386
r.element = choice_DigestRepInner_initReply;
387
388
hex_encode(server_nonce, sizeof(server_nonce), &r.u.initReply.nonce);
389
if (r.u.initReply.nonce == NULL) {
390
ret = ENOMEM;
391
krb5_set_error_message(context, ret, "Failed to decode server nonce");
392
goto out;
393
}
394
395
sp = krb5_storage_emem();
396
if (sp == NULL) {
397
ret = ENOMEM;
398
krb5_set_error_message(context, ret, "malloc: out of memory");
399
goto out;
400
}
401
ret = krb5_store_stringz(sp, ireq.u.init.type);
402
if (ret) {
403
krb5_clear_error_message(context);
404
goto out;
405
}
406
407
if (ireq.u.init.channel) {
408
char *s;
409
410
asprintf(&s, "%s-%s:%s", r.u.initReply.nonce,
411
ireq.u.init.channel->cb_type,
412
ireq.u.init.channel->cb_binding);
413
if (s == NULL) {
414
ret = ENOMEM;
415
krb5_set_error_message(context, ret,
416
"Failed to allocate channel binding");
417
goto out;
418
}
419
free(r.u.initReply.nonce);
420
r.u.initReply.nonce = s;
421
}
422
423
ret = krb5_store_stringz(sp, r.u.initReply.nonce);
424
if (ret) {
425
krb5_clear_error_message(context);
426
goto out;
427
}
428
429
if (strcasecmp(ireq.u.init.type, "CHAP") == 0) {
430
r.u.initReply.identifier =
431
malloc(sizeof(*r.u.initReply.identifier));
432
if (r.u.initReply.identifier == NULL) {
433
ret = ENOMEM;
434
krb5_set_error_message(context, ret, "malloc: out of memory");
435
goto out;
436
}
437
438
asprintf(r.u.initReply.identifier, "%02X", identifier & 0xff);
439
if (*r.u.initReply.identifier == NULL) {
440
ret = ENOMEM;
441
krb5_set_error_message(context, ret, "malloc: out of memory");
442
goto out;
443
}
444
445
} else
446
r.u.initReply.identifier = NULL;
447
448
if (ireq.u.init.hostname) {
449
ret = krb5_store_stringz(sp, *ireq.u.init.hostname);
450
if (ret) {
451
krb5_clear_error_message(context);
452
goto out;
453
}
454
}
455
456
ret = krb5_storage_to_data(sp, &buf);
457
if (ret) {
458
krb5_clear_error_message(context);
459
goto out;
460
}
461
462
ret = get_digest_key(context, config, server, &crypto);
463
if (ret)
464
goto out;
465
466
ret = krb5_create_checksum(context,
467
crypto,
468
KRB5_KU_DIGEST_OPAQUE,
469
0,
470
buf.data,
471
buf.length,
472
&res);
473
krb5_crypto_destroy(context, crypto);
474
crypto = NULL;
475
krb5_data_free(&buf);
476
if (ret)
477
goto out;
478
479
ASN1_MALLOC_ENCODE(Checksum, buf.data, buf.length, &res, &size, ret);
480
free_Checksum(&res);
481
if (ret) {
482
krb5_set_error_message(context, ret, "Failed to encode "
483
"checksum in digest request");
484
goto out;
485
}
486
if (size != buf.length)
487
krb5_abortx(context, "ASN1 internal error");
488
489
hex_encode(buf.data, buf.length, &r.u.initReply.opaque);
490
free(buf.data);
491
krb5_data_zero(&buf);
492
if (r.u.initReply.opaque == NULL) {
493
krb5_clear_error_message(context);
494
ret = ENOMEM;
495
goto out;
496
}
497
498
kdc_log(context, config, 0, "Digest %s init request successful from %s",
499
ireq.u.init.type, from);
500
501
break;
502
}
503
case choice_DigestReqInner_digestRequest: {
504
sp = krb5_storage_emem();
505
if (sp == NULL) {
506
ret = ENOMEM;
507
krb5_set_error_message(context, ret, "malloc: out of memory");
508
goto out;
509
}
510
ret = krb5_store_stringz(sp, ireq.u.digestRequest.type);
511
if (ret) {
512
krb5_clear_error_message(context);
513
goto out;
514
}
515
516
krb5_store_stringz(sp, ireq.u.digestRequest.serverNonce);
517
518
if (ireq.u.digestRequest.hostname) {
519
ret = krb5_store_stringz(sp, *ireq.u.digestRequest.hostname);
520
if (ret) {
521
krb5_clear_error_message(context);
522
goto out;
523
}
524
}
525
526
buf.length = strlen(ireq.u.digestRequest.opaque);
527
buf.data = malloc(buf.length);
528
if (buf.data == NULL) {
529
ret = ENOMEM;
530
krb5_set_error_message(context, ret, "malloc: out of memory");
531
goto out;
532
}
533
534
ret = hex_decode(ireq.u.digestRequest.opaque, buf.data, buf.length);
535
if (ret <= 0) {
536
ret = ENOMEM;
537
krb5_set_error_message(context, ret, "Failed to decode opaque");
538
goto out;
539
}
540
buf.length = ret;
541
542
ret = decode_Checksum(buf.data, buf.length, &res, NULL);
543
free(buf.data);
544
krb5_data_zero(&buf);
545
if (ret) {
546
krb5_set_error_message(context, ret,
547
"Failed to decode digest Checksum");
548
goto out;
549
}
550
551
ret = krb5_storage_to_data(sp, &buf);
552
if (ret) {
553
krb5_clear_error_message(context);
554
goto out;
555
}
556
557
serverNonce.length = strlen(ireq.u.digestRequest.serverNonce);
558
serverNonce.data = malloc(serverNonce.length);
559
if (serverNonce.data == NULL) {
560
ret = ENOMEM;
561
krb5_set_error_message(context, ret, "malloc: out of memory");
562
goto out;
563
}
564
565
/*
566
* CHAP does the checksum of the raw nonce, but do it for all
567
* types, since we need to check the timestamp.
568
*/
569
{
570
ssize_t ssize;
571
572
ssize = hex_decode(ireq.u.digestRequest.serverNonce,
573
serverNonce.data, serverNonce.length);
574
if (ssize <= 0) {
575
ret = ENOMEM;
576
krb5_set_error_message(context, ret, "Failed to decode serverNonce");
577
goto out;
578
}
579
serverNonce.length = ssize;
580
}
581
582
ret = get_digest_key(context, config, server, &crypto);
583
if (ret)
584
goto out;
585
586
ret = krb5_verify_checksum(context, crypto,
587
KRB5_KU_DIGEST_OPAQUE,
588
buf.data, buf.length, &res);
589
free_Checksum(&res);
590
krb5_data_free(&buf);
591
krb5_crypto_destroy(context, crypto);
592
crypto = NULL;
593
if (ret)
594
goto out;
595
596
/* verify time */
597
{
598
unsigned char *p = serverNonce.data;
599
uint32_t t;
600
601
if (serverNonce.length < 4) {
602
ret = EINVAL;
603
krb5_set_error_message(context, ret, "server nonce too short");
604
goto out;
605
}
606
t = p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24);
607
608
if (abs((kdc_time & 0xffffffff) - t) > context->max_skew) {
609
ret = EINVAL;
610
krb5_set_error_message(context, ret, "time screw in server nonce ");
611
goto out;
612
}
613
}
614
615
if (strcasecmp(ireq.u.digestRequest.type, "CHAP") == 0) {
616
EVP_MD_CTX *ctx;
617
unsigned char md[MD5_DIGEST_LENGTH];
618
char *mdx;
619
char idx;
620
621
if ((config->digests_allowed & CHAP_MD5) == 0) {
622
kdc_log(context, config, 0, "Digest CHAP MD5 not allowed");
623
goto out;
624
}
625
626
if (ireq.u.digestRequest.identifier == NULL) {
627
ret = EINVAL;
628
krb5_set_error_message(context, ret, "Identifier missing "
629
"from CHAP request");
630
goto out;
631
}
632
633
if (hex_decode(*ireq.u.digestRequest.identifier, &idx, 1) != 1) {
634
ret = EINVAL;
635
krb5_set_error_message(context, ret, "failed to decode identifier");
636
goto out;
637
}
638
639
ret = get_password_entry(context, config,
640
ireq.u.digestRequest.username,
641
&password);
642
if (ret)
643
goto out;
644
645
ctx = EVP_MD_CTX_create();
646
647
EVP_DigestInit_ex(ctx, EVP_md5(), NULL);
648
EVP_DigestUpdate(ctx, &idx, 1);
649
EVP_DigestUpdate(ctx, password, strlen(password));
650
EVP_DigestUpdate(ctx, serverNonce.data, serverNonce.length);
651
EVP_DigestFinal_ex(ctx, md, NULL);
652
653
EVP_MD_CTX_destroy(ctx);
654
655
hex_encode(md, sizeof(md), &mdx);
656
if (mdx == NULL) {
657
krb5_clear_error_message(context);
658
ret = ENOMEM;
659
goto out;
660
}
661
662
r.element = choice_DigestRepInner_response;
663
664
ret = strcasecmp(mdx, ireq.u.digestRequest.responseData);
665
free(mdx);
666
if (ret == 0) {
667
r.u.response.success = TRUE;
668
} else {
669
kdc_log(context, config, 0,
670
"CHAP reply mismatch for %s",
671
ireq.u.digestRequest.username);
672
r.u.response.success = FALSE;
673
}
674
675
} else if (strcasecmp(ireq.u.digestRequest.type, "SASL-DIGEST-MD5") == 0) {
676
EVP_MD_CTX *ctx;
677
unsigned char md[MD5_DIGEST_LENGTH];
678
char *mdx;
679
char *A1, *A2;
680
681
if ((config->digests_allowed & DIGEST_MD5) == 0) {
682
kdc_log(context, config, 0, "Digest SASL MD5 not allowed");
683
goto out;
684
}
685
686
if (ireq.u.digestRequest.nonceCount == NULL)
687
goto out;
688
if (ireq.u.digestRequest.clientNonce == NULL)
689
goto out;
690
if (ireq.u.digestRequest.qop == NULL)
691
goto out;
692
if (ireq.u.digestRequest.realm == NULL)
693
goto out;
694
695
ret = get_password_entry(context, config,
696
ireq.u.digestRequest.username,
697
&password);
698
if (ret)
699
goto failed;
700
701
ctx = EVP_MD_CTX_create();
702
703
EVP_DigestInit_ex(ctx, EVP_md5(), NULL);
704
EVP_DigestUpdate(ctx, ireq.u.digestRequest.username,
705
strlen(ireq.u.digestRequest.username));
706
EVP_DigestUpdate(ctx, ":", 1);
707
EVP_DigestUpdate(ctx, *ireq.u.digestRequest.realm,
708
strlen(*ireq.u.digestRequest.realm));
709
EVP_DigestUpdate(ctx, ":", 1);
710
EVP_DigestUpdate(ctx, password, strlen(password));
711
EVP_DigestFinal_ex(ctx, md, NULL);
712
713
EVP_DigestInit_ex(ctx, EVP_md5(), NULL);
714
EVP_DigestUpdate(ctx, md, sizeof(md));
715
EVP_DigestUpdate(ctx, ":", 1);
716
EVP_DigestUpdate(ctx, ireq.u.digestRequest.serverNonce,
717
strlen(ireq.u.digestRequest.serverNonce));
718
EVP_DigestUpdate(ctx, ":", 1);
719
EVP_DigestUpdate(ctx, *ireq.u.digestRequest.nonceCount,
720
strlen(*ireq.u.digestRequest.nonceCount));
721
if (ireq.u.digestRequest.authid) {
722
EVP_DigestUpdate(ctx, ":", 1);
723
EVP_DigestUpdate(ctx, *ireq.u.digestRequest.authid,
724
strlen(*ireq.u.digestRequest.authid));
725
}
726
EVP_DigestFinal_ex(ctx, md, NULL);
727
hex_encode(md, sizeof(md), &A1);
728
if (A1 == NULL) {
729
ret = ENOMEM;
730
krb5_set_error_message(context, ret, "malloc: out of memory");
731
EVP_MD_CTX_destroy(ctx);
732
goto failed;
733
}
734
735
EVP_DigestInit_ex(ctx, EVP_md5(), NULL);
736
EVP_DigestUpdate(ctx,
737
"AUTHENTICATE:", sizeof("AUTHENTICATE:") - 1);
738
EVP_DigestUpdate(ctx, *ireq.u.digestRequest.uri,
739
strlen(*ireq.u.digestRequest.uri));
740
741
/* conf|int */
742
if (strcmp(ireq.u.digestRequest.digest, "clear") != 0) {
743
static char conf_zeros[] = ":00000000000000000000000000000000";
744
EVP_DigestUpdate(ctx, conf_zeros, sizeof(conf_zeros) - 1);
745
}
746
747
EVP_DigestFinal_ex(ctx, md, NULL);
748
749
hex_encode(md, sizeof(md), &A2);
750
if (A2 == NULL) {
751
ret = ENOMEM;
752
krb5_set_error_message(context, ret, "malloc: out of memory");
753
free(A1);
754
goto failed;
755
}
756
757
EVP_DigestInit_ex(ctx, EVP_md5(), NULL);
758
EVP_DigestUpdate(ctx, A1, strlen(A2));
759
EVP_DigestUpdate(ctx, ":", 1);
760
EVP_DigestUpdate(ctx, ireq.u.digestRequest.serverNonce,
761
strlen(ireq.u.digestRequest.serverNonce));
762
EVP_DigestUpdate(ctx, ":", 1);
763
EVP_DigestUpdate(ctx, *ireq.u.digestRequest.nonceCount,
764
strlen(*ireq.u.digestRequest.nonceCount));
765
EVP_DigestUpdate(ctx, ":", 1);
766
EVP_DigestUpdate(ctx, *ireq.u.digestRequest.clientNonce,
767
strlen(*ireq.u.digestRequest.clientNonce));
768
EVP_DigestUpdate(ctx, ":", 1);
769
EVP_DigestUpdate(ctx, *ireq.u.digestRequest.qop,
770
strlen(*ireq.u.digestRequest.qop));
771
EVP_DigestUpdate(ctx, ":", 1);
772
EVP_DigestUpdate(ctx, A2, strlen(A2));
773
774
EVP_DigestFinal_ex(ctx, md, NULL);
775
776
EVP_MD_CTX_destroy(ctx);
777
778
free(A1);
779
free(A2);
780
781
hex_encode(md, sizeof(md), &mdx);
782
if (mdx == NULL) {
783
krb5_clear_error_message(context);
784
ret = ENOMEM;
785
goto out;
786
}
787
788
r.element = choice_DigestRepInner_response;
789
ret = strcasecmp(mdx, ireq.u.digestRequest.responseData);
790
free(mdx);
791
if (ret == 0) {
792
r.u.response.success = TRUE;
793
} else {
794
kdc_log(context, config, 0,
795
"DIGEST-MD5 reply mismatch for %s",
796
ireq.u.digestRequest.username);
797
r.u.response.success = FALSE;
798
}
799
800
} else if (strcasecmp(ireq.u.digestRequest.type, "MS-CHAP-V2") == 0) {
801
unsigned char md[SHA_DIGEST_LENGTH], challange[SHA_DIGEST_LENGTH];
802
krb5_principal clientprincipal = NULL;
803
char *mdx;
804
const char *username;
805
struct ntlm_buf answer;
806
Key *key = NULL;
807
EVP_MD_CTX *ctp;
808
809
if ((config->digests_allowed & MS_CHAP_V2) == 0) {
810
kdc_log(context, config, 0, "MS-CHAP-V2 not allowed");
811
goto failed;
812
}
813
814
if (ireq.u.digestRequest.clientNonce == NULL) {
815
ret = EINVAL;
816
krb5_set_error_message(context, ret,
817
"MS-CHAP-V2 clientNonce missing");
818
goto failed;
819
}
820
if (serverNonce.length != 16) {
821
ret = EINVAL;
822
krb5_set_error_message(context, ret,
823
"MS-CHAP-V2 serverNonce wrong length");
824
goto failed;
825
}
826
827
/* strip of the domain component */
828
username = strchr(ireq.u.digestRequest.username, '\\');
829
if (username == NULL)
830
username = ireq.u.digestRequest.username;
831
else
832
username++;
833
834
ctp = EVP_MD_CTX_create();
835
836
/* ChallangeHash */
837
EVP_DigestInit_ex(ctp, EVP_sha1(), NULL);
838
{
839
ssize_t ssize;
840
krb5_data clientNonce;
841
842
clientNonce.length = strlen(*ireq.u.digestRequest.clientNonce);
843
clientNonce.data = malloc(clientNonce.length);
844
if (clientNonce.data == NULL) {
845
ret = ENOMEM;
846
krb5_set_error_message(context, ret,
847
"malloc: out of memory");
848
EVP_MD_CTX_destroy(ctp);
849
goto out;
850
}
851
852
ssize = hex_decode(*ireq.u.digestRequest.clientNonce,
853
clientNonce.data, clientNonce.length);
854
if (ssize != 16) {
855
ret = ENOMEM;
856
krb5_set_error_message(context, ret,
857
"Failed to decode clientNonce");
858
EVP_MD_CTX_destroy(ctp);
859
goto out;
860
}
861
EVP_DigestUpdate(ctp, clientNonce.data, ssize);
862
free(clientNonce.data);
863
}
864
EVP_DigestUpdate(ctp, serverNonce.data, serverNonce.length);
865
EVP_DigestUpdate(ctp, username, strlen(username));
866
867
EVP_DigestFinal_ex(ctp, challange, NULL);
868
869
EVP_MD_CTX_destroy(ctp);
870
871
/* NtPasswordHash */
872
ret = krb5_parse_name(context, username, &clientprincipal);
873
if (ret)
874
goto failed;
875
876
ret = _kdc_db_fetch(context, config, clientprincipal,
877
HDB_F_GET_CLIENT, NULL, NULL, &user);
878
krb5_free_principal(context, clientprincipal);
879
if (ret) {
880
krb5_set_error_message(context, ret,
881
"MS-CHAP-V2 user %s not in database",
882
username);
883
goto failed;
884
}
885
886
ret = hdb_enctype2key(context, &user->entry,
887
ETYPE_ARCFOUR_HMAC_MD5, &key);
888
if (ret) {
889
krb5_set_error_message(context, ret,
890
"MS-CHAP-V2 missing arcfour key %s",
891
username);
892
goto failed;
893
}
894
895
/* ChallengeResponse */
896
ret = heim_ntlm_calculate_ntlm1(key->key.keyvalue.data,
897
key->key.keyvalue.length,
898
challange, &answer);
899
if (ret) {
900
krb5_set_error_message(context, ret, "NTLM missing arcfour key");
901
goto failed;
902
}
903
904
hex_encode(answer.data, answer.length, &mdx);
905
if (mdx == NULL) {
906
free(answer.data);
907
krb5_clear_error_message(context);
908
ret = ENOMEM;
909
goto out;
910
}
911
912
r.element = choice_DigestRepInner_response;
913
ret = strcasecmp(mdx, ireq.u.digestRequest.responseData);
914
if (ret == 0) {
915
r.u.response.success = TRUE;
916
} else {
917
kdc_log(context, config, 0,
918
"MS-CHAP-V2 hash mismatch for %s",
919
ireq.u.digestRequest.username);
920
r.u.response.success = FALSE;
921
}
922
free(mdx);
923
924
if (r.u.response.success) {
925
unsigned char hashhash[MD4_DIGEST_LENGTH];
926
EVP_MD_CTX *ctxp;
927
928
ctxp = EVP_MD_CTX_create();
929
930
/* hashhash */
931
{
932
EVP_DigestInit_ex(ctxp, EVP_md4(), NULL);
933
EVP_DigestUpdate(ctxp,
934
key->key.keyvalue.data,
935
key->key.keyvalue.length);
936
EVP_DigestFinal_ex(ctxp, hashhash, NULL);
937
}
938
939
/* GenerateAuthenticatorResponse */
940
EVP_DigestInit_ex(ctxp, EVP_sha1(), NULL);
941
EVP_DigestUpdate(ctxp, hashhash, sizeof(hashhash));
942
EVP_DigestUpdate(ctxp, answer.data, answer.length);
943
EVP_DigestUpdate(ctxp, ms_chap_v2_magic1,
944
sizeof(ms_chap_v2_magic1));
945
EVP_DigestFinal_ex(ctxp, md, NULL);
946
947
EVP_DigestInit_ex(ctxp, EVP_sha1(), NULL);
948
EVP_DigestUpdate(ctxp, md, sizeof(md));
949
EVP_DigestUpdate(ctxp, challange, 8);
950
EVP_DigestUpdate(ctxp, ms_chap_v2_magic2,
951
sizeof(ms_chap_v2_magic2));
952
EVP_DigestFinal_ex(ctxp, md, NULL);
953
954
r.u.response.rsp = calloc(1, sizeof(*r.u.response.rsp));
955
if (r.u.response.rsp == NULL) {
956
free(answer.data);
957
krb5_clear_error_message(context);
958
EVP_MD_CTX_destroy(ctxp);
959
ret = ENOMEM;
960
goto out;
961
}
962
963
hex_encode(md, sizeof(md), r.u.response.rsp);
964
if (r.u.response.rsp == NULL) {
965
free(answer.data);
966
krb5_clear_error_message(context);
967
EVP_MD_CTX_destroy(ctxp);
968
ret = ENOMEM;
969
goto out;
970
}
971
972
/* get_master, rfc 3079 3.4 */
973
EVP_DigestInit_ex(ctxp, EVP_sha1(), NULL);
974
EVP_DigestUpdate(ctxp, hashhash, 16);
975
EVP_DigestUpdate(ctxp, answer.data, answer.length);
976
EVP_DigestUpdate(ctxp, ms_rfc3079_magic1,
977
sizeof(ms_rfc3079_magic1));
978
EVP_DigestFinal_ex(ctxp, md, NULL);
979
980
free(answer.data);
981
982
EVP_MD_CTX_destroy(ctxp);
983
984
r.u.response.session_key =
985
calloc(1, sizeof(*r.u.response.session_key));
986
if (r.u.response.session_key == NULL) {
987
krb5_clear_error_message(context);
988
ret = ENOMEM;
989
goto out;
990
}
991
992
ret = krb5_data_copy(r.u.response.session_key, md, 16);
993
if (ret) {
994
krb5_clear_error_message(context);
995
goto out;
996
}
997
}
998
999
} else {
1000
r.element = choice_DigestRepInner_error;
1001
asprintf(&r.u.error.reason, "Unsupported digest type %s",
1002
ireq.u.digestRequest.type);
1003
if (r.u.error.reason == NULL) {
1004
ret = ENOMEM;
1005
krb5_set_error_message(context, ret, "malloc: out of memory");
1006
goto out;
1007
}
1008
r.u.error.code = EINVAL;
1009
}
1010
1011
kdc_log(context, config, 0, "Digest %s request successful %s",
1012
ireq.u.digestRequest.type, ireq.u.digestRequest.username);
1013
1014
break;
1015
}
1016
case choice_DigestReqInner_ntlmInit:
1017
1018
if ((config->digests_allowed & (NTLM_V1|NTLM_V1_SESSION|NTLM_V2)) == 0) {
1019
kdc_log(context, config, 0, "NTLM not allowed");
1020
goto failed;
1021
}
1022
1023
r.element = choice_DigestRepInner_ntlmInitReply;
1024
1025
r.u.ntlmInitReply.flags = NTLM_NEG_UNICODE;
1026
1027
if ((ireq.u.ntlmInit.flags & NTLM_NEG_UNICODE) == 0) {
1028
kdc_log(context, config, 0, "NTLM client have no unicode");
1029
goto failed;
1030
}
1031
1032
if (ireq.u.ntlmInit.flags & NTLM_NEG_NTLM)
1033
r.u.ntlmInitReply.flags |= NTLM_NEG_NTLM;
1034
else {
1035
kdc_log(context, config, 0, "NTLM client doesn't support NTLM");
1036
goto failed;
1037
}
1038
1039
r.u.ntlmInitReply.flags |=
1040
NTLM_NEG_TARGET |
1041
NTLM_TARGET_DOMAIN |
1042
NTLM_ENC_128;
1043
1044
#define ALL \
1045
NTLM_NEG_SIGN| \
1046
NTLM_NEG_SEAL| \
1047
NTLM_NEG_ALWAYS_SIGN| \
1048
NTLM_NEG_NTLM2_SESSION| \
1049
NTLM_NEG_KEYEX
1050
1051
r.u.ntlmInitReply.flags |= (ireq.u.ntlmInit.flags & (ALL));
1052
1053
#undef ALL
1054
1055
r.u.ntlmInitReply.targetname =
1056
get_ntlm_targetname(context, client);
1057
if (r.u.ntlmInitReply.targetname == NULL) {
1058
ret = ENOMEM;
1059
krb5_set_error_message(context, ret, "malloc: out of memory");
1060
goto out;
1061
}
1062
r.u.ntlmInitReply.challange.data = malloc(8);
1063
if (r.u.ntlmInitReply.challange.data == NULL) {
1064
ret = ENOMEM;
1065
krb5_set_error_message(context, ret, "malloc: out of memory");
1066
goto out;
1067
}
1068
r.u.ntlmInitReply.challange.length = 8;
1069
if (RAND_bytes(r.u.ntlmInitReply.challange.data,
1070
r.u.ntlmInitReply.challange.length) != 1)
1071
{
1072
ret = ENOMEM;
1073
krb5_set_error_message(context, ret, "out of random error");
1074
goto out;
1075
}
1076
/* XXX fix targetinfo */
1077
ALLOC(r.u.ntlmInitReply.targetinfo);
1078
if (r.u.ntlmInitReply.targetinfo == NULL) {
1079
ret = ENOMEM;
1080
krb5_set_error_message(context, ret, "malloc: out of memory");
1081
goto out;
1082
}
1083
1084
ret = fill_targetinfo(context,
1085
r.u.ntlmInitReply.targetname,
1086
client,
1087
r.u.ntlmInitReply.targetinfo);
1088
if (ret) {
1089
ret = ENOMEM;
1090
krb5_set_error_message(context, ret, "malloc: out of memory");
1091
goto out;
1092
}
1093
1094
/*
1095
* Save data encryted in opaque for the second part of the
1096
* ntlm authentication
1097
*/
1098
sp = krb5_storage_emem();
1099
if (sp == NULL) {
1100
ret = ENOMEM;
1101
krb5_set_error_message(context, ret, "malloc: out of memory");
1102
goto out;
1103
}
1104
1105
ret = krb5_storage_write(sp, r.u.ntlmInitReply.challange.data, 8);
1106
if (ret != 8) {
1107
ret = ENOMEM;
1108
krb5_set_error_message(context, ret, "storage write challange");
1109
goto out;
1110
}
1111
ret = krb5_store_uint32(sp, r.u.ntlmInitReply.flags);
1112
if (ret) {
1113
krb5_clear_error_message(context);
1114
goto out;
1115
}
1116
1117
ret = krb5_storage_to_data(sp, &buf);
1118
if (ret) {
1119
krb5_clear_error_message(context);
1120
goto out;
1121
}
1122
1123
ret = get_digest_key(context, config, server, &crypto);
1124
if (ret)
1125
goto out;
1126
1127
ret = krb5_encrypt(context, crypto, KRB5_KU_DIGEST_OPAQUE,
1128
buf.data, buf.length, &r.u.ntlmInitReply.opaque);
1129
krb5_data_free(&buf);
1130
krb5_crypto_destroy(context, crypto);
1131
crypto = NULL;
1132
if (ret)
1133
goto out;
1134
1135
kdc_log(context, config, 0, "NTLM init from %s", from);
1136
1137
break;
1138
1139
case choice_DigestReqInner_ntlmRequest: {
1140
krb5_principal clientprincipal;
1141
unsigned char sessionkey[16];
1142
unsigned char challange[8];
1143
uint32_t flags;
1144
Key *key = NULL;
1145
int version;
1146
1147
r.element = choice_DigestRepInner_ntlmResponse;
1148
r.u.ntlmResponse.success = 0;
1149
r.u.ntlmResponse.flags = 0;
1150
r.u.ntlmResponse.sessionkey = NULL;
1151
r.u.ntlmResponse.tickets = NULL;
1152
1153
/* get username */
1154
ret = krb5_parse_name(context,
1155
ireq.u.ntlmRequest.username,
1156
&clientprincipal);
1157
if (ret)
1158
goto failed;
1159
1160
ret = _kdc_db_fetch(context, config, clientprincipal,
1161
HDB_F_GET_CLIENT, NULL, NULL, &user);
1162
krb5_free_principal(context, clientprincipal);
1163
if (ret) {
1164
krb5_set_error_message(context, ret, "NTLM user %s not in database",
1165
ireq.u.ntlmRequest.username);
1166
goto failed;
1167
}
1168
1169
ret = get_digest_key(context, config, server, &crypto);
1170
if (ret)
1171
goto failed;
1172
1173
ret = krb5_decrypt(context, crypto, KRB5_KU_DIGEST_OPAQUE,
1174
ireq.u.ntlmRequest.opaque.data,
1175
ireq.u.ntlmRequest.opaque.length, &buf);
1176
krb5_crypto_destroy(context, crypto);
1177
crypto = NULL;
1178
if (ret) {
1179
kdc_log(context, config, 0,
1180
"Failed to decrypt nonce from %s", from);
1181
goto failed;
1182
}
1183
1184
sp = krb5_storage_from_data(&buf);
1185
if (sp == NULL) {
1186
ret = ENOMEM;
1187
krb5_set_error_message(context, ret, "malloc: out of memory");
1188
goto out;
1189
}
1190
1191
ret = krb5_storage_read(sp, challange, sizeof(challange));
1192
if (ret != sizeof(challange)) {
1193
ret = ENOMEM;
1194
krb5_set_error_message(context, ret, "NTLM storage read challange");
1195
goto out;
1196
}
1197
ret = krb5_ret_uint32(sp, &flags);
1198
if (ret) {
1199
krb5_set_error_message(context, ret, "NTLM storage read flags");
1200
goto out;
1201
}
1202
krb5_storage_free(sp);
1203
sp = NULL;
1204
krb5_data_free(&buf);
1205
1206
if ((flags & NTLM_NEG_NTLM) == 0) {
1207
ret = EINVAL;
1208
krb5_set_error_message(context, ret, "NTLM not negotiated");
1209
goto out;
1210
}
1211
1212
ret = hdb_enctype2key(context, &user->entry,
1213
ETYPE_ARCFOUR_HMAC_MD5, &key);
1214
if (ret) {
1215
krb5_set_error_message(context, ret, "NTLM missing arcfour key");
1216
goto out;
1217
}
1218
1219
/* check if this is NTLMv2 */
1220
if (ireq.u.ntlmRequest.ntlm.length != 24) {
1221
struct ntlm_buf infotarget, answer;
1222
char *targetname;
1223
1224
if ((config->digests_allowed & NTLM_V2) == 0) {
1225
kdc_log(context, config, 0, "NTLM v2 not allowed");
1226
goto out;
1227
}
1228
1229
version = 2;
1230
1231
targetname = get_ntlm_targetname(context, client);
1232
if (targetname == NULL) {
1233
ret = ENOMEM;
1234
krb5_set_error_message(context, ret, "malloc: out of memory");
1235
goto out;
1236
}
1237
1238
answer.length = ireq.u.ntlmRequest.ntlm.length;
1239
answer.data = ireq.u.ntlmRequest.ntlm.data;
1240
1241
ret = heim_ntlm_verify_ntlm2(key->key.keyvalue.data,
1242
key->key.keyvalue.length,
1243
ireq.u.ntlmRequest.username,
1244
targetname,
1245
0,
1246
challange,
1247
&answer,
1248
&infotarget,
1249
sessionkey);
1250
free(targetname);
1251
if (ret) {
1252
krb5_set_error_message(context, ret, "NTLM v2 verify failed");
1253
goto failed;
1254
}
1255
1256
/* XXX verify infotarget matches client (checksum ?) */
1257
1258
free(infotarget.data);
1259
/* */
1260
1261
} else {
1262
struct ntlm_buf answer;
1263
1264
version = 1;
1265
1266
if (flags & NTLM_NEG_NTLM2_SESSION) {
1267
unsigned char sessionhash[MD5_DIGEST_LENGTH];
1268
EVP_MD_CTX *ctx;
1269
1270
if ((config->digests_allowed & NTLM_V1_SESSION) == 0) {
1271
kdc_log(context, config, 0, "NTLM v1-session not allowed");
1272
ret = EINVAL;
1273
goto failed;
1274
}
1275
1276
if (ireq.u.ntlmRequest.lm.length != 24) {
1277
ret = EINVAL;
1278
krb5_set_error_message(context, ret, "LM hash have wrong length "
1279
"for NTLM session key");
1280
goto failed;
1281
}
1282
1283
ctx = EVP_MD_CTX_create();
1284
1285
EVP_DigestInit_ex(ctx, EVP_md5(), NULL);
1286
1287
EVP_DigestUpdate(ctx, challange, sizeof(challange));
1288
EVP_DigestUpdate(ctx, ireq.u.ntlmRequest.lm.data, 8);
1289
EVP_DigestFinal_ex(ctx, sessionhash, NULL);
1290
memcpy(challange, sessionhash, sizeof(challange));
1291
1292
EVP_MD_CTX_destroy(ctx);
1293
1294
} else {
1295
if ((config->digests_allowed & NTLM_V1) == 0) {
1296
kdc_log(context, config, 0, "NTLM v1 not allowed");
1297
goto failed;
1298
}
1299
}
1300
1301
ret = heim_ntlm_calculate_ntlm1(key->key.keyvalue.data,
1302
key->key.keyvalue.length,
1303
challange, &answer);
1304
if (ret) {
1305
krb5_set_error_message(context, ret, "NTLM missing arcfour key");
1306
goto failed;
1307
}
1308
1309
if (ireq.u.ntlmRequest.ntlm.length != answer.length ||
1310
memcmp(ireq.u.ntlmRequest.ntlm.data, answer.data, answer.length) != 0)
1311
{
1312
free(answer.data);
1313
ret = EINVAL;
1314
krb5_set_error_message(context, ret, "NTLM hash mismatch");
1315
goto failed;
1316
}
1317
free(answer.data);
1318
1319
{
1320
EVP_MD_CTX *ctx;
1321
1322
ctx = EVP_MD_CTX_create();
1323
1324
EVP_DigestInit_ex(ctx, EVP_md4(), NULL);
1325
EVP_DigestUpdate(ctx,
1326
key->key.keyvalue.data,
1327
key->key.keyvalue.length);
1328
EVP_DigestFinal_ex(ctx, sessionkey, NULL);
1329
1330
EVP_MD_CTX_destroy(ctx);
1331
}
1332
}
1333
1334
if (ireq.u.ntlmRequest.sessionkey) {
1335
unsigned char masterkey[MD4_DIGEST_LENGTH];
1336
EVP_CIPHER_CTX *rc4;
1337
size_t len;
1338
1339
if ((flags & NTLM_NEG_KEYEX) == 0) {
1340
ret = EINVAL;
1341
krb5_set_error_message(context, ret,
1342
"NTLM client failed to neg key "
1343
"exchange but still sent key");
1344
goto failed;
1345
}
1346
1347
len = ireq.u.ntlmRequest.sessionkey->length;
1348
if (len != sizeof(masterkey)){
1349
ret = EINVAL;
1350
krb5_set_error_message(context, ret,
1351
"NTLM master key wrong length: %lu",
1352
(unsigned long)len);
1353
goto failed;
1354
}
1355
1356
1357
rc4 = EVP_CIPHER_CTX_new();
1358
if (rc4 == NULL) {
1359
ret = ENOMEM;
1360
krb5_set_error_message(context, ret,
1361
"NTLM failed to malloc cipher context");
1362
goto failed;
1363
}
1364
EVP_CipherInit_ex(rc4, EVP_rc4(), NULL, sessionkey, NULL, 1);
1365
EVP_Cipher(rc4,
1366
masterkey, ireq.u.ntlmRequest.sessionkey->data,
1367
sizeof(masterkey));
1368
EVP_CIPHER_CTX_free(rc4);
1369
1370
r.u.ntlmResponse.sessionkey =
1371
malloc(sizeof(*r.u.ntlmResponse.sessionkey));
1372
if (r.u.ntlmResponse.sessionkey == NULL) {
1373
ret = EINVAL;
1374
krb5_set_error_message(context, ret, "malloc: out of memory");
1375
goto out;
1376
}
1377
1378
ret = krb5_data_copy(r.u.ntlmResponse.sessionkey,
1379
masterkey, sizeof(masterkey));
1380
if (ret) {
1381
krb5_set_error_message(context, ret, "malloc: out of memory");
1382
goto out;
1383
}
1384
}
1385
1386
r.u.ntlmResponse.success = 1;
1387
kdc_log(context, config, 0, "NTLM version %d successful for %s",
1388
version, ireq.u.ntlmRequest.username);
1389
break;
1390
}
1391
case choice_DigestReqInner_supportedMechs:
1392
1393
kdc_log(context, config, 0, "digest supportedMechs from %s", from);
1394
1395
r.element = choice_DigestRepInner_supportedMechs;
1396
memset(&r.u.supportedMechs, 0, sizeof(r.u.supportedMechs));
1397
1398
if (config->digests_allowed & NTLM_V1)
1399
r.u.supportedMechs.ntlm_v1 = 1;
1400
if (config->digests_allowed & NTLM_V1_SESSION)
1401
r.u.supportedMechs.ntlm_v1_session = 1;
1402
if (config->digests_allowed & NTLM_V2)
1403
r.u.supportedMechs.ntlm_v2 = 1;
1404
if (config->digests_allowed & DIGEST_MD5)
1405
r.u.supportedMechs.digest_md5 = 1;
1406
if (config->digests_allowed & CHAP_MD5)
1407
r.u.supportedMechs.chap_md5 = 1;
1408
if (config->digests_allowed & MS_CHAP_V2)
1409
r.u.supportedMechs.ms_chap_v2 = 1;
1410
break;
1411
1412
default: {
1413
const char *s;
1414
ret = EINVAL;
1415
krb5_set_error_message(context, ret, "unknown operation to digest");
1416
1417
failed:
1418
1419
s = krb5_get_error_message(context, ret);
1420
if (s == NULL) {
1421
krb5_clear_error_message(context);
1422
goto out;
1423
}
1424
1425
kdc_log(context, config, 0, "Digest failed with: %s", s);
1426
1427
r.element = choice_DigestRepInner_error;
1428
r.u.error.reason = strdup("unknown error");
1429
krb5_free_error_message(context, s);
1430
if (r.u.error.reason == NULL) {
1431
ret = ENOMEM;
1432
krb5_set_error_message(context, ret, "malloc: out of memory");
1433
goto out;
1434
}
1435
r.u.error.code = EINVAL;
1436
break;
1437
}
1438
}
1439
1440
ASN1_MALLOC_ENCODE(DigestRepInner, buf.data, buf.length, &r, &size, ret);
1441
if (ret) {
1442
krb5_set_error_message(context, ret, "Failed to encode inner digest reply");
1443
goto out;
1444
}
1445
if (size != buf.length)
1446
krb5_abortx(context, "ASN1 internal error");
1447
1448
krb5_auth_con_addflags(context, ac, KRB5_AUTH_CONTEXT_USE_SUBKEY, NULL);
1449
1450
ret = krb5_mk_rep (context, ac, &rep.apRep);
1451
if (ret)
1452
goto out;
1453
1454
{
1455
krb5_keyblock *key;
1456
1457
ret = krb5_auth_con_getlocalsubkey(context, ac, &key);
1458
if (ret)
1459
goto out;
1460
1461
ret = krb5_crypto_init(context, key, 0, &crypto);
1462
krb5_free_keyblock (context, key);
1463
if (ret)
1464
goto out;
1465
}
1466
1467
ret = krb5_encrypt_EncryptedData(context, crypto, KRB5_KU_DIGEST_ENCRYPT,
1468
buf.data, buf.length, 0,
1469
&rep.innerRep);
1470
if (ret) {
1471
krb5_prepend_error_message(context, ret, "Failed to encrypt digest: ");
1472
goto out;
1473
}
1474
1475
ASN1_MALLOC_ENCODE(DigestREP, reply->data, reply->length, &rep, &size, ret);
1476
if (ret) {
1477
krb5_set_error_message(context, ret, "Failed to encode digest reply");
1478
goto out;
1479
}
1480
if (size != reply->length)
1481
krb5_abortx(context, "ASN1 internal error");
1482
1483
1484
out:
1485
if (ac)
1486
krb5_auth_con_free(context, ac);
1487
if (ret)
1488
krb5_warn(context, ret, "Digest request from %s failed", from);
1489
if (ticket)
1490
krb5_free_ticket(context, ticket);
1491
if (id)
1492
krb5_kt_close(context, id);
1493
if (crypto)
1494
krb5_crypto_destroy(context, crypto);
1495
if (sp)
1496
krb5_storage_free(sp);
1497
if (user)
1498
_kdc_free_ent (context, user);
1499
if (server)
1500
_kdc_free_ent (context, server);
1501
if (client)
1502
_kdc_free_ent (context, client);
1503
if (password) {
1504
memset(password, 0, strlen(password));
1505
free (password);
1506
}
1507
if (client_name)
1508
free (client_name);
1509
krb5_data_free(&buf);
1510
krb5_data_free(&serverNonce);
1511
free_Checksum(&res);
1512
free_DigestREP(&rep);
1513
free_DigestRepInner(&r);
1514
free_DigestReqInner(&ireq);
1515
1516
return ret;
1517
}
1518
1519
#endif /* DIGEST */
1520
1521