xref: /netbsd-src/crypto/external/bsd/heimdal/dist/kuser/kdigest.c (revision d3273b5b76f5afaafe308cead5511dbb8df8c5e9)
1 /*	$NetBSD: kdigest.c,v 1.2 2017/01/28 21:31:45 christos 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
usage(int ret)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
digest_probe(struct digest_probe_options * opt,int argc,char ** argv)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
digest_server_init(struct digest_server_init_options * opt,int argc,char ** argv)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
digest_server_request(struct digest_server_request_options * opt,int argc,char ** argv)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
client_chap(const void * server_nonce,size_t snoncelen,unsigned char server_identifier,const char * password)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
client_mschapv2(const void * server_nonce,size_t snoncelen,const void * client_nonce,size_t cnoncelen,const char * username,const char * password)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
digest_client_request(struct digest_client_request_options * opt,int argc,char ** argv)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
ntlm_server_init(struct ntlm_server_init_options * opt,int argc,char ** argv)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     static char zero2[] = "\x00\x00";
442 
443     memset(&type2, 0, sizeof(type2));
444 
445     ret = krb5_ntlm_alloc(context, &ntlm);
446     if (ret)
447 	krb5_err(context, 1, ret, "krb5_ntlm_alloc");
448 
449     ret = krb5_ntlm_init_request(context,
450 				 ntlm,
451 				 opt->kerberos_realm_string,
452 				 id,
453 				 NTLM_NEG_UNICODE|NTLM_NEG_NTLM,
454 				 "NUTCRACKER",
455 				 "L");
456     if (ret)
457 	krb5_err(context, 1, ret, "krb5_ntlm_init_request");
458 
459     /*
460      *
461      */
462 
463     ret = krb5_ntlm_init_get_challenge(context, ntlm, &challenge);
464     if (ret)
465 	krb5_err(context, 1, ret, "krb5_ntlm_init_get_challenge");
466 
467     if (challenge.length != sizeof(type2.challenge))
468 	krb5_errx(context, 1, "ntlm challenge have wrong length");
469     memcpy(type2.challenge, challenge.data, sizeof(type2.challenge));
470     krb5_data_free(&challenge);
471 
472     ret = krb5_ntlm_init_get_flags(context, ntlm, &type2.flags);
473     if (ret)
474 	krb5_err(context, 1, ret, "krb5_ntlm_init_get_flags");
475 
476     krb5_ntlm_init_get_targetname(context, ntlm, &type2.targetname);
477     type2.targetinfo.data = zero2;
478     type2.targetinfo.length = 2;
479 
480     ret = heim_ntlm_encode_type2(&type2, &data);
481     if (ret)
482 	krb5_errx(context, 1, "heim_ntlm_encode_type2");
483 
484     free(type2.targetname);
485 
486     /*
487      *
488      */
489 
490     rk_base64_encode(data.data, data.length, &s);
491     free(data.data);
492     printf("type2=%s\n", s);
493     free(s);
494 
495     /*
496      *
497      */
498 
499     ret = krb5_ntlm_init_get_opaque(context, ntlm, &opaque);
500     if (ret)
501 	krb5_err(context, 1, ret, "krb5_ntlm_init_get_opaque");
502 
503     rk_base64_encode(opaque.data, opaque.length, &s);
504     krb5_data_free(&opaque);
505     printf("opaque=%s\n", s);
506     free(s);
507 
508     /*
509      *
510      */
511 
512     krb5_ntlm_free(context, ntlm);
513 
514     return 0;
515 }
516 
517 
518 /*
519  *
520  */
521 
522 int
help(void * opt,int argc,char ** argv)523 help(void *opt, int argc, char **argv)
524 {
525     sl_slc_help(commands, argc, argv);
526     return 0;
527 }
528 
529 int
main(int argc,char ** argv)530 main(int argc, char **argv)
531 {
532     krb5_error_code ret;
533     int optidx = 0;
534 
535     setprogname(argv[0]);
536 
537     ret = krb5_init_context (&context);
538     if (ret == KRB5_CONFIG_BADFORMAT)
539 	errx (1, "krb5_init_context failed to parse configuration file");
540     else if (ret)
541 	errx(1, "krb5_init_context failed: %d", ret);
542 
543     if(getarg(args, sizeof(args) / sizeof(args[0]), argc, argv, &optidx))
544 	usage(1);
545 
546     if (help_flag)
547 	usage (0);
548 
549     if(version_flag){
550 	print_version(NULL);
551 	exit(0);
552     }
553 
554     argc -= optidx;
555     argv += optidx;
556 
557     if (argc == 0) {
558 	help(NULL, argc, argv);
559 	return 1;
560     }
561 
562     if (ccache_string) {
563 	ret = krb5_cc_resolve(context, ccache_string, &id);
564 	if (ret)
565 	    krb5_err(context, 1, ret, "krb5_cc_resolve");
566     }
567 
568     ret = sl_command (commands, argc, argv);
569     if (ret == -1) {
570 	help(NULL, argc, argv);
571 	return 1;
572     }
573     return ret;
574 }
575