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