Switch to EVP_MD digest
[heimdal.git] / kuser / kdigest.c
bloba1b02a915b965791427f84ec11b0a053309d8f61
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 EVP_MD_CTX hctx, ctx;
270 unsigned char md[SHA_DIGEST_LENGTH], challange[SHA_DIGEST_LENGTH];
271 unsigned char hmd[MD4_DIGEST_LENGTH];
272 struct ntlm_buf answer;
273 int i, len, ret;
274 char *h;
276 EVP_MD_CTX_init(&ctx);
277 EVP_DigestInit_ex(&ctx, EVP_sha1(), NULL);
279 EVP_DigestUpdate(&ctx, client_nonce, cnoncelen);
280 EVP_DigestUpdate(&ctx, server_nonce, snoncelen);
281 EVP_DigestUpdate(&ctx, username, strlen(username));
282 EVP_DigestFinal_ex(&ctx, md, NULL);
285 EVP_MD_CTX_init(&hctx);
286 EVP_DigestInit_ex(&hctx, EVP_md4(), NULL);
287 len = strlen(password);
288 for (i = 0; i < len; i++) {
289 EVP_DigestUpdate(&hctx, &password[i], 1);
290 EVP_DigestUpdate(&hctx, &password[len], 1);
292 EVP_DigestFinal_ex(&hctx, hmd, NULL);
295 /* ChallengeResponse */
296 ret = heim_ntlm_calculate_ntlm1(hmd, sizeof(hmd), md, &answer);
297 if (ret)
298 errx(1, "heim_ntlm_calculate_ntlm1");
300 hex_encode(answer.data, answer.length, &h);
301 printf("responseData=%s\n", h);
302 free(h);
304 /* PasswordHash */
305 EVP_DigestInit_ex(&hctx, EVP_md4(), NULL);
306 EVP_DigestUpdate(&hctx, hmd, sizeof(hmd));
307 EVP_DigestFinal_ex(&hctx, hmd, NULL);
310 /* GenerateAuthenticatorResponse */
311 EVP_DigestInit_ex(&ctx, EVP_sha1(), NULL);
312 EVP_DigestUpdate(&ctx, hmd, sizeof(hmd));
313 EVP_DigestUpdate(&ctx, answer.data, answer.length);
314 EVP_DigestUpdate(&ctx, ms_chap_v2_magic1, sizeof(ms_chap_v2_magic1));
315 EVP_DigestFinal_ex(&ctx, md, NULL);
317 /* ChallengeHash */
318 EVP_DigestInit_ex(&ctx, EVP_sha1(), NULL);
319 EVP_DigestUpdate(&ctx, client_nonce, cnoncelen);
320 EVP_DigestUpdate(&ctx, server_nonce, snoncelen);
321 EVP_DigestUpdate(&ctx, username, strlen(username));
322 EVP_DigestFinal_ex(&ctx, challange, NULL);
324 EVP_DigestInit_ex(&ctx, EVP_sha1(), NULL);
325 EVP_DigestUpdate(&ctx, md, sizeof(md));
326 EVP_DigestUpdate(&ctx, challange, 8);
327 EVP_DigestUpdate(&ctx, ms_chap_v2_magic2, sizeof(ms_chap_v2_magic2));
328 EVP_DigestFinal_ex(&ctx, md, NULL);
330 hex_encode(md, sizeof(md), &h);
331 printf("AuthenticatorResponse=%s\n", h);
332 free(h);
334 /* get_master, rfc 3079 3.4 */
335 EVP_DigestInit_ex(&ctx, EVP_sha1(), NULL);
336 EVP_DigestUpdate(&ctx, hmd, sizeof(hmd));
337 EVP_DigestUpdate(&ctx, answer.data, answer.length);
338 EVP_DigestUpdate(&ctx, ms_rfc3079_magic1, sizeof(ms_rfc3079_magic1));
339 EVP_DigestFinal_ex(&ctx, md, NULL);
341 free(answer.data);
343 hex_encode(md, 16, &h);
344 printf("session-key=%s\n", h);
345 free(h);
347 EVP_MD_CTX_cleanup(&hctx);
348 EVP_MD_CTX_cleanup(&ctx);
353 digest_client_request(struct digest_client_request_options *opt,
354 int argc, char **argv)
356 char *server_nonce, *client_nonce = NULL, server_identifier;
357 ssize_t snoncelen, cnoncelen = 0;
359 if (opt->server_nonce_string == NULL)
360 errx(1, "server nonce missing");
361 if (opt->password_string == NULL)
362 errx(1, "password missing");
364 if (opt->opaque_string == NULL)
365 errx(1, "opaque missing");
367 snoncelen = strlen(opt->server_nonce_string);
368 server_nonce = malloc(snoncelen);
369 if (server_nonce == NULL)
370 errx(1, "server_nonce");
372 snoncelen = hex_decode(opt->server_nonce_string, server_nonce, snoncelen);
373 if (snoncelen <= 0)
374 errx(1, "server nonce wrong");
376 if (opt->client_nonce_string) {
377 cnoncelen = strlen(opt->client_nonce_string);
378 client_nonce = malloc(cnoncelen);
379 if (client_nonce == NULL)
380 errx(1, "client_nonce");
382 cnoncelen = hex_decode(opt->client_nonce_string,
383 client_nonce, cnoncelen);
384 if (cnoncelen <= 0)
385 errx(1, "client nonce wrong");
388 if (opt->server_identifier_string) {
389 int ret;
391 ret = hex_decode(opt->server_identifier_string, &server_identifier, 1);
392 if (ret != 1)
393 errx(1, "server identifier wrong length");
396 if (strcasecmp(opt->type_string, "CHAP") == 0) {
397 if (opt->server_identifier_string == NULL)
398 errx(1, "server identifier missing");
400 client_chap(server_nonce, snoncelen, server_identifier,
401 opt->password_string);
403 } else if (strcasecmp(opt->type_string, "MS-CHAP-V2") == 0) {
404 if (opt->client_nonce_string == NULL)
405 errx(1, "client nonce missing");
406 if (opt->username_string == NULL)
407 errx(1, "client nonce missing");
409 client_mschapv2(server_nonce, snoncelen,
410 client_nonce, cnoncelen,
411 opt->username_string,
412 opt->password_string);
414 if (client_nonce)
415 free(client_nonce);
416 free(server_nonce);
418 return 0;
421 #include <heimntlm.h>
424 ntlm_server_init(struct ntlm_server_init_options *opt,
425 int argc, char ** argv)
427 krb5_error_code ret;
428 krb5_ntlm ntlm;
429 struct ntlm_type2 type2;
430 krb5_data challange, opaque;
431 struct ntlm_buf data;
432 char *s;
434 memset(&type2, 0, sizeof(type2));
436 ret = krb5_ntlm_alloc(context, &ntlm);
437 if (ret)
438 krb5_err(context, 1, ret, "krb5_ntlm_alloc");
440 ret = krb5_ntlm_init_request(context,
441 ntlm,
442 opt->kerberos_realm_string,
444 NTLM_NEG_UNICODE|NTLM_NEG_NTLM,
445 "NUTCRACKER",
446 "L");
447 if (ret)
448 krb5_err(context, 1, ret, "krb5_ntlm_init_request");
454 ret = krb5_ntlm_init_get_challange(context, ntlm, &challange);
455 if (ret)
456 krb5_err(context, 1, ret, "krb5_ntlm_init_get_challange");
458 if (challange.length != sizeof(type2.challange))
459 krb5_errx(context, 1, "ntlm challange have wrong length");
460 memcpy(type2.challange, challange.data, sizeof(type2.challange));
461 krb5_data_free(&challange);
463 ret = krb5_ntlm_init_get_flags(context, ntlm, &type2.flags);
464 if (ret)
465 krb5_err(context, 1, ret, "krb5_ntlm_init_get_flags");
467 krb5_ntlm_init_get_targetname(context, ntlm, &type2.targetname);
468 type2.targetinfo.data = "\x00\x00";
469 type2.targetinfo.length = 2;
471 ret = heim_ntlm_encode_type2(&type2, &data);
472 if (ret)
473 krb5_errx(context, 1, "heim_ntlm_encode_type2");
475 free(type2.targetname);
481 base64_encode(data.data, data.length, &s);
482 free(data.data);
483 printf("type2=%s\n", s);
484 free(s);
490 ret = krb5_ntlm_init_get_opaque(context, ntlm, &opaque);
491 if (ret)
492 krb5_err(context, 1, ret, "krb5_ntlm_init_get_opaque");
494 base64_encode(opaque.data, opaque.length, &s);
495 krb5_data_free(&opaque);
496 printf("opaque=%s\n", s);
497 free(s);
503 krb5_ntlm_free(context, ntlm);
505 return 0;
514 help(void *opt, int argc, char **argv)
516 sl_slc_help(commands, argc, argv);
517 return 0;
521 main(int argc, char **argv)
523 krb5_error_code ret;
524 int optidx = 0;
526 setprogname(argv[0]);
528 ret = krb5_init_context (&context);
529 if (ret == KRB5_CONFIG_BADFORMAT)
530 errx (1, "krb5_init_context failed to parse configuration file");
531 else if (ret)
532 errx(1, "krb5_init_context failed: %d", ret);
534 if(getarg(args, sizeof(args) / sizeof(args[0]), argc, argv, &optidx))
535 usage(1);
537 if (help_flag)
538 usage (0);
540 if(version_flag){
541 print_version(NULL);
542 exit(0);
545 argc -= optidx;
546 argv += optidx;
548 if (argc == 0) {
549 help(NULL, argc, argv);
550 return 1;
553 if (ccache_string) {
554 ret = krb5_cc_resolve(context, ccache_string, &id);
555 if (ret)
556 krb5_err(context, 1, ret, "krb5_cc_resolve");
559 ret = sl_command (commands, argc, argv);
560 if (ret == -1) {
561 help(NULL, argc, argv);
562 return 1;
564 return ret;