Catch memory allocation failures [CID-61]
[heimdal.git] / kuser / kdigest.c
blob162e40adfa635ef4a3449666c8b47c40d79f11e4
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);
406 if (client_nonce)
407 free(client_nonce);
408 free(server_nonce);
410 return 0;
413 #include <heimntlm.h>
416 ntlm_server_init(struct ntlm_server_init_options *opt,
417 int argc, char ** argv)
419 krb5_error_code ret;
420 krb5_ntlm ntlm;
421 struct ntlm_type2 type2;
422 krb5_data challange, opaque;
423 struct ntlm_buf data;
424 char *s;
426 memset(&type2, 0, sizeof(type2));
428 ret = krb5_ntlm_alloc(context, &ntlm);
429 if (ret)
430 krb5_err(context, 1, ret, "krb5_ntlm_alloc");
432 ret = krb5_ntlm_init_request(context,
433 ntlm,
434 opt->kerberos_realm_string,
436 NTLM_NEG_UNICODE|NTLM_NEG_NTLM,
437 "NUTCRACKER",
438 "L");
439 if (ret)
440 krb5_err(context, 1, ret, "krb5_ntlm_init_request");
446 ret = krb5_ntlm_init_get_challange(context, ntlm, &challange);
447 if (ret)
448 krb5_err(context, 1, ret, "krb5_ntlm_init_get_challange");
450 if (challange.length != sizeof(type2.challange))
451 krb5_errx(context, 1, "ntlm challange have wrong length");
452 memcpy(type2.challange, challange.data, sizeof(type2.challange));
453 krb5_data_free(&challange);
455 ret = krb5_ntlm_init_get_flags(context, ntlm, &type2.flags);
456 if (ret)
457 krb5_err(context, 1, ret, "krb5_ntlm_init_get_flags");
459 krb5_ntlm_init_get_targetname(context, ntlm, &type2.targetname);
460 type2.targetinfo.data = "\x00\x00";
461 type2.targetinfo.length = 2;
463 ret = heim_ntlm_encode_type2(&type2, &data);
464 if (ret)
465 krb5_errx(context, 1, "heim_ntlm_encode_type2");
467 free(type2.targetname);
473 base64_encode(data.data, data.length, &s);
474 free(data.data);
475 printf("type2=%s\n", s);
476 free(s);
482 ret = krb5_ntlm_init_get_opaque(context, ntlm, &opaque);
483 if (ret)
484 krb5_err(context, 1, ret, "krb5_ntlm_init_get_opaque");
486 base64_encode(opaque.data, opaque.length, &s);
487 krb5_data_free(&opaque);
488 printf("opaque=%s\n", s);
489 free(s);
495 krb5_ntlm_free(context, ntlm);
497 return 0;
506 help(void *opt, int argc, char **argv)
508 sl_slc_help(commands, argc, argv);
509 return 0;
513 main(int argc, char **argv)
515 krb5_error_code ret;
516 int optidx = 0;
518 setprogname(argv[0]);
520 ret = krb5_init_context (&context);
521 if (ret == KRB5_CONFIG_BADFORMAT)
522 errx (1, "krb5_init_context failed to parse configuration file");
523 else if (ret)
524 errx(1, "krb5_init_context failed: %d", ret);
526 if(getarg(args, sizeof(args) / sizeof(args[0]), argc, argv, &optidx))
527 usage(1);
529 if (help_flag)
530 usage (0);
532 if(version_flag){
533 print_version(NULL);
534 exit(0);
537 argc -= optidx;
538 argv += optidx;
540 if (argc == 0) {
541 help(NULL, argc, argv);
542 return 1;
545 if (ccache_string) {
546 ret = krb5_cc_resolve(context, ccache_string, &id);
547 if (ret)
548 krb5_err(context, 1, ret, "krb5_cc_resolve");
551 ret = sl_command (commands, argc, argv);
552 if (ret == -1) {
553 help(NULL, argc, argv);
554 return 1;
556 return ret;