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