]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - crypto/heimdal/kuser/kdigest.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.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 #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 }