Free digest on completion [CID-106]
[heimdal.git] / kuser / kdigest.c
blob30b6ec9da205d9e2b90c4f930039ad987d613d0a
1 /*
2 * Copyright (c) 2006 - 2007 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
4 * All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
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.
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.
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.
34 #include "kuser_locl.h"
35 RCSID("$Id$");
36 #include <kdigest-commands.h>
37 #include <hex.h>
38 #include <base64.h>
39 #include <heimntlm.h>
40 #include "crypto-headers.h"
42 static int version_flag = 0;
43 static int help_flag = 0;
44 static char *ccache_string;
45 static krb5_ccache id;
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 }
53 static void
54 usage (int ret)
56 arg_printusage (args, sizeof(args)/sizeof(*args),
57 NULL, "");
58 exit (ret);
61 static krb5_context context;
63 int
64 digest_probe(struct digest_probe_options *opt,
65 int argc, char ** argv)
67 krb5_error_code ret;
68 krb5_realm realm;
69 unsigned flags;
71 realm = opt->realm_string;
73 if (realm == NULL)
74 errx(1, "realm missing");
76 ret = krb5_digest_probe(context, realm, id, &flags);
77 if (ret)
78 krb5_err(context, 1, ret, "digest_probe");
80 printf("flags: %u\n", flags);
82 return 0;
85 int
86 digest_server_init(struct digest_server_init_options *opt,
87 int argc, char ** argv)
89 krb5_error_code ret;
90 krb5_digest digest;
92 ret = krb5_digest_alloc(context, &digest);
93 if (ret)
94 krb5_err(context, 1, ret, "digest_alloc");
96 ret = krb5_digest_set_type(context, digest, opt->type_string);
97 if (ret)
98 krb5_err(context, 1, ret, "krb5_digest_set_type");
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");
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");
114 printf("type=%s\n", opt->type_string);
115 printf("server-nonce=%s\n",
116 krb5_digest_get_server_nonce(context, digest));
118 const char *s = krb5_digest_get_identifier(context, digest);
119 if (s)
120 printf("identifier=%s\n", s);
122 printf("opaque=%s\n", krb5_digest_get_opaque(context, digest));
124 krb5_digest_free(digest);
126 return 0;
130 digest_server_request(struct digest_server_request_options *opt,
131 int argc, char **argv)
133 krb5_error_code ret;
134 krb5_digest digest;
135 const char *status, *rsp;
136 krb5_data session_key;
138 if (opt->server_nonce_string == NULL)
139 errx(1, "server nonce missing");
140 if (opt->type_string == NULL)
141 errx(1, "type missing");
142 if (opt->opaque_string == NULL)
143 errx(1, "opaque missing");
144 if (opt->client_response_string == NULL)
145 errx(1, "client response missing");
147 ret = krb5_digest_alloc(context, &digest);
148 if (ret)
149 krb5_err(context, 1, ret, "digest_alloc");
151 if (strcasecmp(opt->type_string, "CHAP") == 0) {
152 if (opt->server_identifier_string == NULL)
153 errx(1, "server identifier missing");
155 ret = krb5_digest_set_identifier(context, digest,
156 opt->server_identifier_string);
157 if (ret)
158 krb5_err(context, 1, ret, "krb5_digest_set_type");
161 ret = krb5_digest_set_type(context, digest, opt->type_string);
162 if (ret)
163 krb5_err(context, 1, ret, "krb5_digest_set_type");
165 ret = krb5_digest_set_username(context, digest, opt->username_string);
166 if (ret)
167 krb5_err(context, 1, ret, "krb5_digest_set_username");
169 ret = krb5_digest_set_server_nonce(context, digest,
170 opt->server_nonce_string);
171 if (ret)
172 krb5_err(context, 1, ret, "krb5_digest_set_server_nonce");
174 if(opt->client_nonce_string) {
175 ret = krb5_digest_set_client_nonce(context, digest,
176 opt->client_nonce_string);
177 if (ret)
178 krb5_err(context, 1, ret, "krb5_digest_set_client_nonce");
182 ret = krb5_digest_set_opaque(context, digest, opt->opaque_string);
183 if (ret)
184 krb5_err(context, 1, ret, "krb5_digest_set_opaque");
186 ret = krb5_digest_set_responseData(context, digest,
187 opt->client_response_string);
188 if (ret)
189 krb5_err(context, 1, ret, "krb5_digest_set_responseData");
191 ret = krb5_digest_request(context, digest,
192 opt->kerberos_realm_string, id);
193 if (ret)
194 krb5_err(context, 1, ret, "krb5_digest_request");
196 status = krb5_digest_rep_get_status(context, digest) ? "ok" : "failed";
197 rsp = krb5_digest_get_rsp(context, digest);
199 printf("status=%s\n", status);
200 if (rsp)
201 printf("rsp=%s\n", rsp);
202 printf("tickets=no\n");
204 ret = krb5_digest_get_session_key(context, digest, &session_key);
205 if (ret)
206 krb5_err(context, 1, ret, "krb5_digest_get_session_key");
208 if (session_key.length) {
209 char *key;
210 hex_encode(session_key.data, session_key.length, &key);
211 if (key == NULL)
212 krb5_errx(context, 1, "hex_encode");
213 krb5_data_free(&session_key);
214 printf("session-key=%s\n", key);
215 free(key);
218 krb5_digest_free(digest);
220 return 0;
223 static void
224 client_chap(const void *server_nonce, size_t snoncelen,
225 unsigned char server_identifier,
226 const char *password)
228 MD5_CTX ctx;
229 unsigned char md[MD5_DIGEST_LENGTH];
230 char *h;
232 MD5_Init(&ctx);
233 MD5_Update(&ctx, &server_identifier, 1);
234 MD5_Update(&ctx, password, strlen(password));
235 MD5_Update(&ctx, server_nonce, snoncelen);
236 MD5_Final(md, &ctx);
238 hex_encode(md, 16, &h);
240 printf("responseData=%s\n", h);
241 free(h);
244 static const unsigned char ms_chap_v2_magic1[39] = {
245 0x4D, 0x61, 0x67, 0x69, 0x63, 0x20, 0x73, 0x65, 0x72, 0x76,
246 0x65, 0x72, 0x20, 0x74, 0x6F, 0x20, 0x63, 0x6C, 0x69, 0x65,
247 0x6E, 0x74, 0x20, 0x73, 0x69, 0x67, 0x6E, 0x69, 0x6E, 0x67,
248 0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x61, 0x6E, 0x74
250 static const unsigned char ms_chap_v2_magic2[41] = {
251 0x50, 0x61, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x6D, 0x61, 0x6B,
252 0x65, 0x20, 0x69, 0x74, 0x20, 0x64, 0x6F, 0x20, 0x6D, 0x6F,
253 0x72, 0x65, 0x20, 0x74, 0x68, 0x61, 0x6E, 0x20, 0x6F, 0x6E,
254 0x65, 0x20, 0x69, 0x74, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6F,
255 0x6E
257 static const unsigned char ms_rfc3079_magic1[27] = {
258 0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74,
259 0x68, 0x65, 0x20, 0x4d, 0x50, 0x50, 0x45, 0x20, 0x4d,
260 0x61, 0x73, 0x74, 0x65, 0x72, 0x20, 0x4b, 0x65, 0x79
263 static void
264 client_mschapv2(const void *server_nonce, size_t snoncelen,
265 const void *client_nonce, size_t cnoncelen,
266 const char *username,
267 const char *password)
269 SHA_CTX ctx;
270 MD4_CTX hctx;
271 unsigned char md[SHA_DIGEST_LENGTH], challange[SHA_DIGEST_LENGTH];
272 unsigned char hmd[MD4_DIGEST_LENGTH];
273 struct ntlm_buf answer;
274 int i, len, ret;
275 char *h;
277 SHA1_Init(&ctx);
278 SHA1_Update(&ctx, client_nonce, cnoncelen);
279 SHA1_Update(&ctx, server_nonce, snoncelen);
280 SHA1_Update(&ctx, username, strlen(username));
281 SHA1_Final(md, &ctx);
283 MD4_Init(&hctx);
284 len = strlen(password);
285 for (i = 0; i < len; i++) {
286 MD4_Update(&hctx, &password[i], 1);
287 MD4_Update(&hctx, &password[len], 1);
289 MD4_Final(hmd, &hctx);
291 /* ChallengeResponse */
292 ret = heim_ntlm_calculate_ntlm1(hmd, sizeof(hmd), md, &answer);
293 if (ret)
294 errx(1, "heim_ntlm_calculate_ntlm1");
296 hex_encode(answer.data, answer.length, &h);
297 printf("responseData=%s\n", h);
298 free(h);
300 /* PasswordHash */
301 MD4_Init(&hctx);
302 MD4_Update(&hctx, hmd, sizeof(hmd));
303 MD4_Final(hmd, &hctx);
305 /* GenerateAuthenticatorResponse */
306 SHA1_Init(&ctx);
307 SHA1_Update(&ctx, hmd, sizeof(hmd));
308 SHA1_Update(&ctx, answer.data, answer.length);
309 SHA1_Update(&ctx, ms_chap_v2_magic1, sizeof(ms_chap_v2_magic1));
310 SHA1_Final(md, &ctx);
312 /* ChallengeHash */
313 SHA1_Init(&ctx);
314 SHA1_Update(&ctx, client_nonce, cnoncelen);
315 SHA1_Update(&ctx, server_nonce, snoncelen);
316 SHA1_Update(&ctx, username, strlen(username));
317 SHA1_Final(challange, &ctx);
319 SHA1_Init(&ctx);
320 SHA1_Update(&ctx, md, sizeof(md));
321 SHA1_Update(&ctx, challange, 8);
322 SHA1_Update(&ctx, ms_chap_v2_magic2, sizeof(ms_chap_v2_magic2));
323 SHA1_Final(md, &ctx);
325 hex_encode(md, sizeof(md), &h);
326 printf("AuthenticatorResponse=%s\n", h);
327 free(h);
329 /* get_master, rfc 3079 3.4 */
330 SHA1_Init(&ctx);
331 SHA1_Update(&ctx, hmd, sizeof(hmd));
332 SHA1_Update(&ctx, answer.data, answer.length);
333 SHA1_Update(&ctx, ms_rfc3079_magic1, sizeof(ms_rfc3079_magic1));
334 SHA1_Final(md, &ctx);
336 free(answer.data);
338 hex_encode(md, 16, &h);
339 printf("session-key=%s\n", h);
340 free(h);
345 digest_client_request(struct digest_client_request_options *opt,
346 int argc, char **argv)
348 char *server_nonce, *client_nonce = NULL, server_identifier;
349 ssize_t snoncelen, cnoncelen = 0;
351 if (opt->server_nonce_string == NULL)
352 errx(1, "server nonce missing");
353 if (opt->password_string == NULL)
354 errx(1, "password missing");
356 if (opt->opaque_string == NULL)
357 errx(1, "opaque missing");
359 snoncelen = strlen(opt->server_nonce_string);
360 server_nonce = malloc(snoncelen);
361 if (server_nonce == NULL)
362 errx(1, "server_nonce");
364 snoncelen = hex_decode(opt->server_nonce_string, server_nonce, snoncelen);
365 if (snoncelen <= 0)
366 errx(1, "server nonce wrong");
368 if (opt->client_nonce_string) {
369 cnoncelen = strlen(opt->client_nonce_string);
370 client_nonce = malloc(cnoncelen);
371 if (client_nonce == NULL)
372 errx(1, "client_nonce");
374 cnoncelen = hex_decode(opt->client_nonce_string,
375 client_nonce, cnoncelen);
376 if (cnoncelen <= 0)
377 errx(1, "client nonce wrong");
380 if (opt->server_identifier_string) {
381 int ret;
383 ret = hex_decode(opt->server_identifier_string, &server_identifier, 1);
384 if (ret != 1)
385 errx(1, "server identifier wrong length");
388 if (strcasecmp(opt->type_string, "CHAP") == 0) {
389 if (opt->server_identifier_string == NULL)
390 errx(1, "server identifier missing");
392 client_chap(server_nonce, snoncelen, server_identifier,
393 opt->password_string);
395 } else if (strcasecmp(opt->type_string, "MS-CHAP-V2") == 0) {
396 if (opt->client_nonce_string == NULL)
397 errx(1, "client nonce missing");
398 if (opt->username_string == NULL)
399 errx(1, "client nonce missing");
401 client_mschapv2(server_nonce, snoncelen,
402 client_nonce, cnoncelen,
403 opt->username_string,
404 opt->password_string);
408 return 0;
411 #include <heimntlm.h>
414 ntlm_server_init(struct ntlm_server_init_options *opt,
415 int argc, char ** argv)
417 krb5_error_code ret;
418 krb5_ntlm ntlm;
419 struct ntlm_type2 type2;
420 krb5_data challange, opaque;
421 struct ntlm_buf data;
422 char *s;
424 memset(&type2, 0, sizeof(type2));
426 ret = krb5_ntlm_alloc(context, &ntlm);
427 if (ret)
428 krb5_err(context, 1, ret, "krb5_ntlm_alloc");
430 ret = krb5_ntlm_init_request(context,
431 ntlm,
432 opt->kerberos_realm_string,
434 NTLM_NEG_UNICODE|NTLM_NEG_NTLM,
435 "NUTCRACKER",
436 "L");
437 if (ret)
438 krb5_err(context, 1, ret, "krb5_ntlm_init_request");
444 ret = krb5_ntlm_init_get_challange(context, ntlm, &challange);
445 if (ret)
446 krb5_err(context, 1, ret, "krb5_ntlm_init_get_challange");
448 if (challange.length != sizeof(type2.challange))
449 krb5_errx(context, 1, "ntlm challange have wrong length");
450 memcpy(type2.challange, challange.data, sizeof(type2.challange));
451 krb5_data_free(&challange);
453 ret = krb5_ntlm_init_get_flags(context, ntlm, &type2.flags);
454 if (ret)
455 krb5_err(context, 1, ret, "krb5_ntlm_init_get_flags");
457 krb5_ntlm_init_get_targetname(context, ntlm, &type2.targetname);
458 type2.targetinfo.data = "\x00\x00";
459 type2.targetinfo.length = 2;
461 ret = heim_ntlm_encode_type2(&type2, &data);
462 if (ret)
463 krb5_errx(context, 1, "heim_ntlm_encode_type2");
465 free(type2.targetname);
471 base64_encode(data.data, data.length, &s);
472 free(data.data);
473 printf("type2=%s\n", s);
474 free(s);
480 ret = krb5_ntlm_init_get_opaque(context, ntlm, &opaque);
481 if (ret)
482 krb5_err(context, 1, ret, "krb5_ntlm_init_get_opaque");
484 base64_encode(opaque.data, opaque.length, &s);
485 krb5_data_free(&opaque);
486 printf("opaque=%s\n", s);
487 free(s);
493 krb5_ntlm_free(context, ntlm);
495 return 0;
504 help(void *opt, int argc, char **argv)
506 sl_slc_help(commands, argc, argv);
507 return 0;
511 main(int argc, char **argv)
513 krb5_error_code ret;
514 int optidx = 0;
516 setprogname(argv[0]);
518 ret = krb5_init_context (&context);
519 if (ret == KRB5_CONFIG_BADFORMAT)
520 errx (1, "krb5_init_context failed to parse configuration file");
521 else if (ret)
522 errx(1, "krb5_init_context failed: %d", ret);
524 if(getarg(args, sizeof(args) / sizeof(args[0]), argc, argv, &optidx))
525 usage(1);
527 if (help_flag)
528 usage (0);
530 if(version_flag){
531 print_version(NULL);
532 exit(0);
535 argc -= optidx;
536 argv += optidx;
538 if (argc == 0) {
539 help(NULL, argc, argv);
540 return 1;
543 if (ccache_string) {
544 ret = krb5_cc_resolve(context, ccache_string, &id);
545 if (ret)
546 krb5_err(context, 1, ret, "krb5_cc_resolve");
549 ret = sl_command (commands, argc, argv);
550 if (ret == -1) {
551 help(NULL, argc, argv);
552 return 1;
554 return ret;