add newline at end
[heimdal.git] / kuser / kdigest.c
blob984e1011beade7d04c2d84bd48e8f76bfc9883b2
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 return 0;
128 digest_server_request(struct digest_server_request_options *opt,
129 int argc, char **argv)
131 krb5_error_code ret;
132 krb5_digest digest;
133 const char *status, *rsp;
134 krb5_data session_key;
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");
145 ret = krb5_digest_alloc(context, &digest);
146 if (ret)
147 krb5_err(context, 1, ret, "digest_alloc");
149 if (strcasecmp(opt->type_string, "CHAP") == 0) {
150 if (opt->server_identifier_string == NULL)
151 errx(1, "server identifier missing");
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");
159 ret = krb5_digest_set_type(context, digest, opt->type_string);
160 if (ret)
161 krb5_err(context, 1, ret, "krb5_digest_set_type");
163 ret = krb5_digest_set_username(context, digest, opt->username_string);
164 if (ret)
165 krb5_err(context, 1, ret, "krb5_digest_set_username");
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");
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");
180 ret = krb5_digest_set_opaque(context, digest, opt->opaque_string);
181 if (ret)
182 krb5_err(context, 1, ret, "krb5_digest_set_opaque");
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");
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");
194 status = krb5_digest_rep_get_status(context, digest) ? "ok" : "failed";
195 rsp = krb5_digest_get_rsp(context, digest);
197 printf("status=%s\n", status);
198 if (rsp)
199 printf("rsp=%s\n", rsp);
200 printf("tickets=no\n");
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");
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);
216 return 0;
219 static void
220 client_chap(const void *server_nonce, size_t snoncelen,
221 unsigned char server_identifier,
222 const char *password)
224 MD5_CTX ctx;
225 unsigned char md[MD5_DIGEST_LENGTH];
226 char *h;
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);
234 hex_encode(md, 16, &h);
236 printf("responseData=%s\n", h);
237 free(h);
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
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
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
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)
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;
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);
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);
285 MD4_Final(hmd, &hctx);
287 /* ChallengeResponse */
288 ret = heim_ntlm_calculate_ntlm1(hmd, sizeof(hmd), md, &answer);
289 if (ret)
290 errx(1, "heim_ntlm_calculate_ntlm1");
292 hex_encode(answer.data, answer.length, &h);
293 printf("responseData=%s\n", h);
294 free(h);
296 /* PasswordHash */
297 MD4_Init(&hctx);
298 MD4_Update(&hctx, hmd, sizeof(hmd));
299 MD4_Final(hmd, &hctx);
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);
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);
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);
321 hex_encode(md, sizeof(md), &h);
322 printf("AuthenticatorResponse=%s\n", h);
323 free(h);
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);
332 free(answer.data);
334 hex_encode(md, 16, &h);
335 printf("session-key=%s\n", h);
336 free(h);
341 digest_client_request(struct digest_client_request_options *opt,
342 int argc, char **argv)
344 char *server_nonce, *client_nonce = NULL, server_identifier;
345 ssize_t snoncelen, cnoncelen = 0;
347 if (opt->server_nonce_string == NULL)
348 errx(1, "server nonce missing");
349 if (opt->password_string == NULL)
350 errx(1, "password missing");
352 if (opt->opaque_string == NULL)
353 errx(1, "opaque missing");
355 snoncelen = strlen(opt->server_nonce_string);
356 server_nonce = malloc(snoncelen);
357 if (server_nonce == NULL)
358 errx(1, "server_nonce");
360 snoncelen = hex_decode(opt->server_nonce_string, server_nonce, snoncelen);
361 if (snoncelen <= 0)
362 errx(1, "server nonce wrong");
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");
370 cnoncelen = hex_decode(opt->client_nonce_string,
371 client_nonce, cnoncelen);
372 if (cnoncelen <= 0)
373 errx(1, "client nonce wrong");
376 if (opt->server_identifier_string) {
377 int ret;
379 ret = hex_decode(opt->server_identifier_string, &server_identifier, 1);
380 if (ret != 1)
381 errx(1, "server identifier wrong length");
384 if (strcasecmp(opt->type_string, "CHAP") == 0) {
385 if (opt->server_identifier_string == NULL)
386 errx(1, "server identifier missing");
388 client_chap(server_nonce, snoncelen, server_identifier,
389 opt->password_string);
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");
397 client_mschapv2(server_nonce, snoncelen,
398 client_nonce, cnoncelen,
399 opt->username_string,
400 opt->password_string);
404 return 0;
407 #include <heimntlm.h>
410 ntlm_server_init(struct ntlm_server_init_options *opt,
411 int argc, char ** argv)
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;
420 memset(&type2, 0, sizeof(type2));
422 ret = krb5_ntlm_alloc(context, &ntlm);
423 if (ret)
424 krb5_err(context, 1, ret, "krb5_ntlm_alloc");
426 ret = krb5_ntlm_init_request(context,
427 ntlm,
428 opt->kerberos_realm_string,
430 NTLM_NEG_UNICODE|NTLM_NEG_NTLM,
431 "NUTCRACKER",
432 "L");
433 if (ret)
434 krb5_err(context, 1, ret, "krb5_ntlm_init_request");
440 ret = krb5_ntlm_init_get_challange(context, ntlm, &challange);
441 if (ret)
442 krb5_err(context, 1, ret, "krb5_ntlm_init_get_challange");
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);
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");
453 krb5_ntlm_init_get_targetname(context, ntlm, &type2.targetname);
454 type2.targetinfo.data = "\x00\x00";
455 type2.targetinfo.length = 2;
457 ret = heim_ntlm_encode_type2(&type2, &data);
458 if (ret)
459 krb5_errx(context, 1, "heim_ntlm_encode_type2");
461 free(type2.targetname);
467 base64_encode(data.data, data.length, &s);
468 free(data.data);
469 printf("type2=%s\n", s);
470 free(s);
476 ret = krb5_ntlm_init_get_opaque(context, ntlm, &opaque);
477 if (ret)
478 krb5_err(context, 1, ret, "krb5_ntlm_init_get_opaque");
480 base64_encode(opaque.data, opaque.length, &s);
481 krb5_data_free(&opaque);
482 printf("opaque=%s\n", s);
483 free(s);
489 krb5_ntlm_free(context, ntlm);
491 return 0;
500 help(void *opt, int argc, char **argv)
502 sl_slc_help(commands, argc, argv);
503 return 0;
507 main(int argc, char **argv)
509 krb5_error_code ret;
510 int optidx = 0;
512 setprogname(argv[0]);
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);
520 if(getarg(args, sizeof(args) / sizeof(args[0]), argc, argv, &optidx))
521 usage(1);
523 if (help_flag)
524 usage (0);
526 if(version_flag){
527 print_version(NULL);
528 exit(0);
531 argc -= optidx;
532 argv += optidx;
534 if (argc == 0) {
535 help(NULL, argc, argv);
536 return 1;
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");
545 ret = sl_command (commands, argc, argv);
546 if (ret == -1) {
547 help(NULL, argc, argv);
548 return 1;
550 return ret;