]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - crypto/heimdal/kuser/kdigest.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / crypto / heimdal / kuser / kdigest.c
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
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
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
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
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
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
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
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
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
500 help(void *opt, int argc, char **argv)
501 {
502     sl_slc_help(commands, argc, argv);
503     return 0;
504 }
505
506 int
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 }