Merge pull request #176 from urisimchoni/signed-kvno
[heimdal.git] / kuser / kdigest.c
blobc53815104b8ae0bf15e800d0778e49d113b53d1f
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 #define HC_DEPRECATED_CRYPTO
36 #include "kuser_locl.h"
38 #include <kdigest-commands.h>
39 #include <hex.h>
40 #include <base64.h>
41 #include <heimntlm.h>
42 #include "crypto-headers.h"
44 static int version_flag = 0;
45 static int help_flag = 0;
46 static char *ccache_string;
47 static krb5_ccache id;
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 }
55 static void
56 usage (int ret)
58 arg_printusage (args, sizeof(args)/sizeof(*args),
59 NULL, "");
60 exit (ret);
63 static krb5_context context;
65 int
66 digest_probe(struct digest_probe_options *opt,
67 int argc, char ** argv)
69 krb5_error_code ret;
70 krb5_realm realm;
71 unsigned flags;
73 realm = opt->realm_string;
75 if (realm == NULL)
76 errx(1, "realm missing");
78 ret = krb5_digest_probe(context, realm, id, &flags);
79 if (ret)
80 krb5_err(context, 1, ret, "digest_probe");
82 printf("flags: %u\n", flags);
84 return 0;
87 int
88 digest_server_init(struct digest_server_init_options *opt,
89 int argc, char ** argv)
91 krb5_error_code ret;
92 krb5_digest digest;
94 ret = krb5_digest_alloc(context, &digest);
95 if (ret)
96 krb5_err(context, 1, ret, "digest_alloc");
98 ret = krb5_digest_set_type(context, digest, opt->type_string);
99 if (ret)
100 krb5_err(context, 1, ret, "krb5_digest_set_type");
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");
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");
116 printf("type=%s\n", opt->type_string);
117 printf("server-nonce=%s\n",
118 krb5_digest_get_server_nonce(context, digest));
120 const char *s = krb5_digest_get_identifier(context, digest);
121 if (s)
122 printf("identifier=%s\n", s);
124 printf("opaque=%s\n", krb5_digest_get_opaque(context, digest));
126 krb5_digest_free(digest);
128 return 0;
132 digest_server_request(struct digest_server_request_options *opt,
133 int argc, char **argv)
135 krb5_error_code ret;
136 krb5_digest digest;
137 const char *status, *rsp;
138 krb5_data session_key;
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");
149 ret = krb5_digest_alloc(context, &digest);
150 if (ret)
151 krb5_err(context, 1, ret, "digest_alloc");
153 if (strcasecmp(opt->type_string, "CHAP") == 0) {
154 if (opt->server_identifier_string == NULL)
155 errx(1, "server identifier missing");
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");
163 ret = krb5_digest_set_type(context, digest, opt->type_string);
164 if (ret)
165 krb5_err(context, 1, ret, "krb5_digest_set_type");
167 ret = krb5_digest_set_username(context, digest, opt->username_string);
168 if (ret)
169 krb5_err(context, 1, ret, "krb5_digest_set_username");
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");
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");
184 ret = krb5_digest_set_opaque(context, digest, opt->opaque_string);
185 if (ret)
186 krb5_err(context, 1, ret, "krb5_digest_set_opaque");
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");
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");
198 status = krb5_digest_rep_get_status(context, digest) ? "ok" : "failed";
199 rsp = krb5_digest_get_rsp(context, digest);
201 printf("status=%s\n", status);
202 if (rsp)
203 printf("rsp=%s\n", rsp);
204 printf("tickets=no\n");
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");
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);
220 krb5_digest_free(digest);
222 return 0;
225 static void
226 client_chap(const void *server_nonce, size_t snoncelen,
227 unsigned char server_identifier,
228 const char *password)
230 EVP_MD_CTX *ctx;
231 unsigned char md[MD5_DIGEST_LENGTH];
232 char *h;
234 ctx = EVP_MD_CTX_create();
235 EVP_DigestInit_ex(ctx, EVP_md5(), NULL);
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);
242 EVP_MD_CTX_destroy(ctx);
244 hex_encode(md, 16, &h);
246 printf("responseData=%s\n", h);
247 free(h);
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
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
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
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)
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;
282 ctx = EVP_MD_CTX_create();
283 EVP_DigestInit_ex(ctx, EVP_sha1(), NULL);
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);
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);
298 EVP_DigestFinal_ex(hctx, hmd, NULL);
301 /* ChallengeResponse */
302 ret = heim_ntlm_calculate_ntlm1(hmd, sizeof(hmd), md, &answer);
303 if (ret)
304 errx(1, "heim_ntlm_calculate_ntlm1");
306 hex_encode(answer.data, answer.length, &h);
307 printf("responseData=%s\n", h);
308 free(h);
310 /* PasswordHash */
311 EVP_DigestInit_ex(hctx, EVP_md4(), NULL);
312 EVP_DigestUpdate(hctx, hmd, sizeof(hmd));
313 EVP_DigestFinal_ex(hctx, hmd, NULL);
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);
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);
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);
336 hex_encode(md, sizeof(md), &h);
337 printf("AuthenticatorResponse=%s\n", h);
338 free(h);
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);
347 free(answer.data);
349 hex_encode(md, 16, &h);
350 printf("session-key=%s\n", h);
351 free(h);
353 EVP_MD_CTX_destroy(hctx);
354 EVP_MD_CTX_destroy(ctx);
359 digest_client_request(struct digest_client_request_options *opt,
360 int argc, char **argv)
362 char *server_nonce, *client_nonce = NULL, server_identifier;
363 ssize_t snoncelen, cnoncelen = 0;
365 if (opt->server_nonce_string == NULL)
366 errx(1, "server nonce missing");
367 if (opt->password_string == NULL)
368 errx(1, "password missing");
370 if (opt->opaque_string == NULL)
371 errx(1, "opaque missing");
373 snoncelen = strlen(opt->server_nonce_string);
374 server_nonce = malloc(snoncelen);
375 if (server_nonce == NULL)
376 errx(1, "server_nonce");
378 snoncelen = hex_decode(opt->server_nonce_string, server_nonce, snoncelen);
379 if (snoncelen <= 0)
380 errx(1, "server nonce wrong");
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");
388 cnoncelen = hex_decode(opt->client_nonce_string,
389 client_nonce, cnoncelen);
390 if (cnoncelen <= 0)
391 errx(1, "client nonce wrong");
394 if (opt->server_identifier_string) {
395 int ret;
397 ret = hex_decode(opt->server_identifier_string, &server_identifier, 1);
398 if (ret != 1)
399 errx(1, "server identifier wrong length");
402 if (strcasecmp(opt->type_string, "CHAP") == 0) {
403 if (opt->server_identifier_string == NULL)
404 errx(1, "server identifier missing");
406 client_chap(server_nonce, snoncelen, server_identifier,
407 opt->password_string);
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");
415 client_mschapv2(server_nonce, snoncelen,
416 client_nonce, cnoncelen,
417 opt->username_string,
418 opt->password_string);
420 if (client_nonce)
421 free(client_nonce);
422 free(server_nonce);
424 return 0;
427 #include <heimntlm.h>
430 ntlm_server_init(struct ntlm_server_init_options *opt,
431 int argc, char ** argv)
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";
441 memset(&type2, 0, sizeof(type2));
443 ret = krb5_ntlm_alloc(context, &ntlm);
444 if (ret)
445 krb5_err(context, 1, ret, "krb5_ntlm_alloc");
447 ret = krb5_ntlm_init_request(context,
448 ntlm,
449 opt->kerberos_realm_string,
451 NTLM_NEG_UNICODE|NTLM_NEG_NTLM,
452 "NUTCRACKER",
453 "L");
454 if (ret)
455 krb5_err(context, 1, ret, "krb5_ntlm_init_request");
461 ret = krb5_ntlm_init_get_challenge(context, ntlm, &challenge);
462 if (ret)
463 krb5_err(context, 1, ret, "krb5_ntlm_init_get_challenge");
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);
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");
474 krb5_ntlm_init_get_targetname(context, ntlm, &type2.targetname);
475 type2.targetinfo.data = zero2;
476 type2.targetinfo.length = 2;
478 ret = heim_ntlm_encode_type2(&type2, &data);
479 if (ret)
480 krb5_errx(context, 1, "heim_ntlm_encode_type2");
482 free(type2.targetname);
488 rk_base64_encode(data.data, data.length, &s);
489 free(data.data);
490 printf("type2=%s\n", s);
491 free(s);
497 ret = krb5_ntlm_init_get_opaque(context, ntlm, &opaque);
498 if (ret)
499 krb5_err(context, 1, ret, "krb5_ntlm_init_get_opaque");
501 rk_base64_encode(opaque.data, opaque.length, &s);
502 krb5_data_free(&opaque);
503 printf("opaque=%s\n", s);
504 free(s);
510 krb5_ntlm_free(context, ntlm);
512 return 0;
521 help(void *opt, int argc, char **argv)
523 sl_slc_help(commands, argc, argv);
524 return 0;
528 main(int argc, char **argv)
530 krb5_error_code ret;
531 int optidx = 0;
533 setprogname(argv[0]);
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);
541 if(getarg(args, sizeof(args) / sizeof(args[0]), argc, argv, &optidx))
542 usage(1);
544 if (help_flag)
545 usage (0);
547 if(version_flag){
548 print_version(NULL);
549 exit(0);
552 argc -= optidx;
553 argv += optidx;
555 if (argc == 0) {
556 help(NULL, argc, argv);
557 return 1;
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");
566 ret = sl_command (commands, argc, argv);
567 if (ret == -1) {
568 help(NULL, argc, argv);
569 return 1;
571 return ret;