Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/crypto/heimdal/kuser/kdigest.c
34859 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
#define HC_DEPRECATED_CRYPTO
35
36
#include "kuser_locl.h"
37
38
#include <kdigest-commands.h>
39
#include <hex.h>
40
#include <base64.h>
41
#include <heimntlm.h>
42
#include "crypto-headers.h"
43
44
static int version_flag = 0;
45
static int help_flag = 0;
46
static char *ccache_string;
47
static krb5_ccache id;
48
49
static struct getargs args[] = {
50
{"ccache", 0, arg_string, &ccache_string, "credential cache", NULL },
51
{"version", 0, arg_flag, &version_flag, "print version", NULL },
52
{"help", 0, arg_flag, &help_flag, NULL, NULL }
53
};
54
55
static void
56
usage (int ret)
57
{
58
arg_printusage (args, sizeof(args)/sizeof(*args),
59
NULL, "");
60
exit (ret);
61
}
62
63
static krb5_context context;
64
65
int
66
digest_probe(struct digest_probe_options *opt,
67
int argc, char ** argv)
68
{
69
krb5_error_code ret;
70
krb5_realm realm;
71
unsigned flags;
72
73
realm = opt->realm_string;
74
75
if (realm == NULL)
76
errx(1, "realm missing");
77
78
ret = krb5_digest_probe(context, realm, id, &flags);
79
if (ret)
80
krb5_err(context, 1, ret, "digest_probe");
81
82
printf("flags: %u\n", flags);
83
84
return 0;
85
}
86
87
int
88
digest_server_init(struct digest_server_init_options *opt,
89
int argc, char ** argv)
90
{
91
krb5_error_code ret;
92
krb5_digest digest;
93
94
ret = krb5_digest_alloc(context, &digest);
95
if (ret)
96
krb5_err(context, 1, ret, "digest_alloc");
97
98
ret = krb5_digest_set_type(context, digest, opt->type_string);
99
if (ret)
100
krb5_err(context, 1, ret, "krb5_digest_set_type");
101
102
if (opt->cb_type_string && opt->cb_value_string) {
103
ret = krb5_digest_set_server_cb(context, digest,
104
opt->cb_type_string,
105
opt->cb_value_string);
106
if (ret)
107
krb5_err(context, 1, ret, "krb5_digest_set_server_cb");
108
}
109
ret = krb5_digest_init_request(context,
110
digest,
111
opt->kerberos_realm_string,
112
id);
113
if (ret)
114
krb5_err(context, 1, ret, "krb5_digest_init_request");
115
116
printf("type=%s\n", opt->type_string);
117
printf("server-nonce=%s\n",
118
krb5_digest_get_server_nonce(context, digest));
119
{
120
const char *s = krb5_digest_get_identifier(context, digest);
121
if (s)
122
printf("identifier=%s\n", s);
123
}
124
printf("opaque=%s\n", krb5_digest_get_opaque(context, digest));
125
126
krb5_digest_free(digest);
127
128
return 0;
129
}
130
131
int
132
digest_server_request(struct digest_server_request_options *opt,
133
int argc, char **argv)
134
{
135
krb5_error_code ret;
136
krb5_digest digest;
137
const char *status, *rsp;
138
krb5_data session_key;
139
140
if (opt->server_nonce_string == NULL)
141
errx(1, "server nonce missing");
142
if (opt->type_string == NULL)
143
errx(1, "type missing");
144
if (opt->opaque_string == NULL)
145
errx(1, "opaque missing");
146
if (opt->client_response_string == NULL)
147
errx(1, "client response missing");
148
149
ret = krb5_digest_alloc(context, &digest);
150
if (ret)
151
krb5_err(context, 1, ret, "digest_alloc");
152
153
if (strcasecmp(opt->type_string, "CHAP") == 0) {
154
if (opt->server_identifier_string == NULL)
155
errx(1, "server identifier missing");
156
157
ret = krb5_digest_set_identifier(context, digest,
158
opt->server_identifier_string);
159
if (ret)
160
krb5_err(context, 1, ret, "krb5_digest_set_type");
161
}
162
163
ret = krb5_digest_set_type(context, digest, opt->type_string);
164
if (ret)
165
krb5_err(context, 1, ret, "krb5_digest_set_type");
166
167
ret = krb5_digest_set_username(context, digest, opt->username_string);
168
if (ret)
169
krb5_err(context, 1, ret, "krb5_digest_set_username");
170
171
ret = krb5_digest_set_server_nonce(context, digest,
172
opt->server_nonce_string);
173
if (ret)
174
krb5_err(context, 1, ret, "krb5_digest_set_server_nonce");
175
176
if(opt->client_nonce_string) {
177
ret = krb5_digest_set_client_nonce(context, digest,
178
opt->client_nonce_string);
179
if (ret)
180
krb5_err(context, 1, ret, "krb5_digest_set_client_nonce");
181
}
182
183
184
ret = krb5_digest_set_opaque(context, digest, opt->opaque_string);
185
if (ret)
186
krb5_err(context, 1, ret, "krb5_digest_set_opaque");
187
188
ret = krb5_digest_set_responseData(context, digest,
189
opt->client_response_string);
190
if (ret)
191
krb5_err(context, 1, ret, "krb5_digest_set_responseData");
192
193
ret = krb5_digest_request(context, digest,
194
opt->kerberos_realm_string, id);
195
if (ret)
196
krb5_err(context, 1, ret, "krb5_digest_request");
197
198
status = krb5_digest_rep_get_status(context, digest) ? "ok" : "failed";
199
rsp = krb5_digest_get_rsp(context, digest);
200
201
printf("status=%s\n", status);
202
if (rsp)
203
printf("rsp=%s\n", rsp);
204
printf("tickets=no\n");
205
206
ret = krb5_digest_get_session_key(context, digest, &session_key);
207
if (ret)
208
krb5_err(context, 1, ret, "krb5_digest_get_session_key");
209
210
if (session_key.length) {
211
char *key;
212
hex_encode(session_key.data, session_key.length, &key);
213
if (key == NULL)
214
krb5_errx(context, 1, "hex_encode");
215
krb5_data_free(&session_key);
216
printf("session-key=%s\n", key);
217
free(key);
218
}
219
220
krb5_digest_free(digest);
221
222
return 0;
223
}
224
225
static void
226
client_chap(const void *server_nonce, size_t snoncelen,
227
unsigned char server_identifier,
228
const char *password)
229
{
230
EVP_MD_CTX *ctx;
231
unsigned char md[MD5_DIGEST_LENGTH];
232
char *h;
233
234
ctx = EVP_MD_CTX_create();
235
EVP_DigestInit_ex(ctx, EVP_md5(), NULL);
236
237
EVP_DigestUpdate(ctx, &server_identifier, 1);
238
EVP_DigestUpdate(ctx, password, strlen(password));
239
EVP_DigestUpdate(ctx, server_nonce, snoncelen);
240
EVP_DigestFinal_ex(ctx, md, NULL);
241
242
EVP_MD_CTX_destroy(ctx);
243
244
hex_encode(md, 16, &h);
245
246
printf("responseData=%s\n", h);
247
free(h);
248
}
249
250
static const unsigned char ms_chap_v2_magic1[39] = {
251
0x4D, 0x61, 0x67, 0x69, 0x63, 0x20, 0x73, 0x65, 0x72, 0x76,
252
0x65, 0x72, 0x20, 0x74, 0x6F, 0x20, 0x63, 0x6C, 0x69, 0x65,
253
0x6E, 0x74, 0x20, 0x73, 0x69, 0x67, 0x6E, 0x69, 0x6E, 0x67,
254
0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x61, 0x6E, 0x74
255
};
256
static const unsigned char ms_chap_v2_magic2[41] = {
257
0x50, 0x61, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x6D, 0x61, 0x6B,
258
0x65, 0x20, 0x69, 0x74, 0x20, 0x64, 0x6F, 0x20, 0x6D, 0x6F,
259
0x72, 0x65, 0x20, 0x74, 0x68, 0x61, 0x6E, 0x20, 0x6F, 0x6E,
260
0x65, 0x20, 0x69, 0x74, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6F,
261
0x6E
262
};
263
static const unsigned char ms_rfc3079_magic1[27] = {
264
0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74,
265
0x68, 0x65, 0x20, 0x4d, 0x50, 0x50, 0x45, 0x20, 0x4d,
266
0x61, 0x73, 0x74, 0x65, 0x72, 0x20, 0x4b, 0x65, 0x79
267
};
268
269
static void
270
client_mschapv2(const void *server_nonce, size_t snoncelen,
271
const void *client_nonce, size_t cnoncelen,
272
const char *username,
273
const char *password)
274
{
275
EVP_MD_CTX *hctx, *ctx;
276
unsigned char md[SHA_DIGEST_LENGTH], challenge[SHA_DIGEST_LENGTH];
277
unsigned char hmd[MD4_DIGEST_LENGTH];
278
struct ntlm_buf answer;
279
int i, len, ret;
280
char *h;
281
282
ctx = EVP_MD_CTX_create();
283
EVP_DigestInit_ex(ctx, EVP_sha1(), NULL);
284
285
EVP_DigestUpdate(ctx, client_nonce, cnoncelen);
286
EVP_DigestUpdate(ctx, server_nonce, snoncelen);
287
EVP_DigestUpdate(ctx, username, strlen(username));
288
EVP_DigestFinal_ex(ctx, md, NULL);
289
290
291
hctx = EVP_MD_CTX_create();
292
EVP_DigestInit_ex(hctx, EVP_md4(), NULL);
293
len = strlen(password);
294
for (i = 0; i < len; i++) {
295
EVP_DigestUpdate(hctx, &password[i], 1);
296
EVP_DigestUpdate(hctx, &password[len], 1);
297
}
298
EVP_DigestFinal_ex(hctx, hmd, NULL);
299
300
301
/* ChallengeResponse */
302
ret = heim_ntlm_calculate_ntlm1(hmd, sizeof(hmd), md, &answer);
303
if (ret)
304
errx(1, "heim_ntlm_calculate_ntlm1");
305
306
hex_encode(answer.data, answer.length, &h);
307
printf("responseData=%s\n", h);
308
free(h);
309
310
/* PasswordHash */
311
EVP_DigestInit_ex(hctx, EVP_md4(), NULL);
312
EVP_DigestUpdate(hctx, hmd, sizeof(hmd));
313
EVP_DigestFinal_ex(hctx, hmd, NULL);
314
315
316
/* GenerateAuthenticatorResponse */
317
EVP_DigestInit_ex(ctx, EVP_sha1(), NULL);
318
EVP_DigestUpdate(ctx, hmd, sizeof(hmd));
319
EVP_DigestUpdate(ctx, answer.data, answer.length);
320
EVP_DigestUpdate(ctx, ms_chap_v2_magic1, sizeof(ms_chap_v2_magic1));
321
EVP_DigestFinal_ex(ctx, md, NULL);
322
323
/* ChallengeHash */
324
EVP_DigestInit_ex(ctx, EVP_sha1(), NULL);
325
EVP_DigestUpdate(ctx, client_nonce, cnoncelen);
326
EVP_DigestUpdate(ctx, server_nonce, snoncelen);
327
EVP_DigestUpdate(ctx, username, strlen(username));
328
EVP_DigestFinal_ex(ctx, challenge, NULL);
329
330
EVP_DigestInit_ex(ctx, EVP_sha1(), NULL);
331
EVP_DigestUpdate(ctx, md, sizeof(md));
332
EVP_DigestUpdate(ctx, challenge, 8);
333
EVP_DigestUpdate(ctx, ms_chap_v2_magic2, sizeof(ms_chap_v2_magic2));
334
EVP_DigestFinal_ex(ctx, md, NULL);
335
336
hex_encode(md, sizeof(md), &h);
337
printf("AuthenticatorResponse=%s\n", h);
338
free(h);
339
340
/* get_master, rfc 3079 3.4 */
341
EVP_DigestInit_ex(ctx, EVP_sha1(), NULL);
342
EVP_DigestUpdate(ctx, hmd, sizeof(hmd));
343
EVP_DigestUpdate(ctx, answer.data, answer.length);
344
EVP_DigestUpdate(ctx, ms_rfc3079_magic1, sizeof(ms_rfc3079_magic1));
345
EVP_DigestFinal_ex(ctx, md, NULL);
346
347
free(answer.data);
348
349
hex_encode(md, 16, &h);
350
printf("session-key=%s\n", h);
351
free(h);
352
353
EVP_MD_CTX_destroy(hctx);
354
EVP_MD_CTX_destroy(ctx);
355
}
356
357
358
int
359
digest_client_request(struct digest_client_request_options *opt,
360
int argc, char **argv)
361
{
362
char *server_nonce, *client_nonce = NULL, server_identifier;
363
ssize_t snoncelen, cnoncelen = 0;
364
365
if (opt->server_nonce_string == NULL)
366
errx(1, "server nonce missing");
367
if (opt->password_string == NULL)
368
errx(1, "password missing");
369
370
if (opt->opaque_string == NULL)
371
errx(1, "opaque missing");
372
373
snoncelen = strlen(opt->server_nonce_string);
374
server_nonce = malloc(snoncelen);
375
if (server_nonce == NULL)
376
errx(1, "server_nonce");
377
378
snoncelen = hex_decode(opt->server_nonce_string, server_nonce, snoncelen);
379
if (snoncelen <= 0)
380
errx(1, "server nonce wrong");
381
382
if (opt->client_nonce_string) {
383
cnoncelen = strlen(opt->client_nonce_string);
384
client_nonce = malloc(cnoncelen);
385
if (client_nonce == NULL)
386
errx(1, "client_nonce");
387
388
cnoncelen = hex_decode(opt->client_nonce_string,
389
client_nonce, cnoncelen);
390
if (cnoncelen <= 0)
391
errx(1, "client nonce wrong");
392
}
393
394
if (opt->server_identifier_string) {
395
int ret;
396
397
ret = hex_decode(opt->server_identifier_string, &server_identifier, 1);
398
if (ret != 1)
399
errx(1, "server identifier wrong length");
400
}
401
402
if (strcasecmp(opt->type_string, "CHAP") == 0) {
403
if (opt->server_identifier_string == NULL)
404
errx(1, "server identifier missing");
405
406
client_chap(server_nonce, snoncelen, server_identifier,
407
opt->password_string);
408
409
} else if (strcasecmp(opt->type_string, "MS-CHAP-V2") == 0) {
410
if (opt->client_nonce_string == NULL)
411
errx(1, "client nonce missing");
412
if (opt->username_string == NULL)
413
errx(1, "client nonce missing");
414
415
client_mschapv2(server_nonce, snoncelen,
416
client_nonce, cnoncelen,
417
opt->username_string,
418
opt->password_string);
419
}
420
if (client_nonce)
421
free(client_nonce);
422
free(server_nonce);
423
424
return 0;
425
}
426
427
#include <heimntlm.h>
428
429
int
430
ntlm_server_init(struct ntlm_server_init_options *opt,
431
int argc, char ** argv)
432
{
433
krb5_error_code ret;
434
krb5_ntlm ntlm;
435
struct ntlm_type2 type2;
436
krb5_data challenge, opaque;
437
struct ntlm_buf data;
438
char *s;
439
static char zero2[] = "\x00\x00";
440
441
memset(&type2, 0, sizeof(type2));
442
443
ret = krb5_ntlm_alloc(context, &ntlm);
444
if (ret)
445
krb5_err(context, 1, ret, "krb5_ntlm_alloc");
446
447
ret = krb5_ntlm_init_request(context,
448
ntlm,
449
opt->kerberos_realm_string,
450
id,
451
NTLM_NEG_UNICODE|NTLM_NEG_NTLM,
452
"NUTCRACKER",
453
"L");
454
if (ret)
455
krb5_err(context, 1, ret, "krb5_ntlm_init_request");
456
457
/*
458
*
459
*/
460
461
ret = krb5_ntlm_init_get_challange(context, ntlm, &challenge);
462
if (ret)
463
krb5_err(context, 1, ret, "krb5_ntlm_init_get_challange");
464
465
if (challenge.length != sizeof(type2.challenge))
466
krb5_errx(context, 1, "ntlm challenge have wrong length");
467
memcpy(type2.challenge, challenge.data, sizeof(type2.challenge));
468
krb5_data_free(&challenge);
469
470
ret = krb5_ntlm_init_get_flags(context, ntlm, &type2.flags);
471
if (ret)
472
krb5_err(context, 1, ret, "krb5_ntlm_init_get_flags");
473
474
krb5_ntlm_init_get_targetname(context, ntlm, &type2.targetname);
475
type2.targetinfo.data = zero2;
476
type2.targetinfo.length = 2;
477
478
ret = heim_ntlm_encode_type2(&type2, &data);
479
if (ret)
480
krb5_errx(context, 1, "heim_ntlm_encode_type2");
481
482
free(type2.targetname);
483
484
/*
485
*
486
*/
487
488
base64_encode(data.data, data.length, &s);
489
free(data.data);
490
printf("type2=%s\n", s);
491
free(s);
492
493
/*
494
*
495
*/
496
497
ret = krb5_ntlm_init_get_opaque(context, ntlm, &opaque);
498
if (ret)
499
krb5_err(context, 1, ret, "krb5_ntlm_init_get_opaque");
500
501
base64_encode(opaque.data, opaque.length, &s);
502
krb5_data_free(&opaque);
503
printf("opaque=%s\n", s);
504
free(s);
505
506
/*
507
*
508
*/
509
510
krb5_ntlm_free(context, ntlm);
511
512
return 0;
513
}
514
515
516
/*
517
*
518
*/
519
520
int
521
help(void *opt, int argc, char **argv)
522
{
523
sl_slc_help(commands, argc, argv);
524
return 0;
525
}
526
527
int
528
main(int argc, char **argv)
529
{
530
krb5_error_code ret;
531
int optidx = 0;
532
533
setprogname(argv[0]);
534
535
ret = krb5_init_context (&context);
536
if (ret == KRB5_CONFIG_BADFORMAT)
537
errx (1, "krb5_init_context failed to parse configuration file");
538
else if (ret)
539
errx(1, "krb5_init_context failed: %d", ret);
540
541
if(getarg(args, sizeof(args) / sizeof(args[0]), argc, argv, &optidx))
542
usage(1);
543
544
if (help_flag)
545
usage (0);
546
547
if(version_flag){
548
print_version(NULL);
549
exit(0);
550
}
551
552
argc -= optidx;
553
argv += optidx;
554
555
if (argc == 0) {
556
help(NULL, argc, argv);
557
return 1;
558
}
559
560
if (ccache_string) {
561
ret = krb5_cc_resolve(context, ccache_string, &id);
562
if (ret)
563
krb5_err(context, 1, ret, "krb5_cc_resolve");
564
}
565
566
ret = sl_command (commands, argc, argv);
567
if (ret == -1) {
568
help(NULL, argc, argv);
569
return 1;
570
}
571
return ret;
572
}
573
574