2 * Copyright (c) 2006 - 2007 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
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
34 #include "kuser_locl.h"
36 #include <kdigest-commands.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
}
56 arg_printusage (args
, sizeof(args
)/sizeof(*args
),
61 static krb5_context context
;
64 digest_probe(struct digest_probe_options
*opt
,
65 int argc
, char ** argv
)
71 realm
= opt
->realm_string
;
74 errx(1, "realm missing");
76 ret
= krb5_digest_probe(context
, realm
, id
, &flags
);
78 krb5_err(context
, 1, ret
, "digest_probe");
80 printf("flags: %u\n", flags
);
86 digest_server_init(struct digest_server_init_options
*opt
,
87 int argc
, char ** argv
)
92 ret
= krb5_digest_alloc(context
, &digest
);
94 krb5_err(context
, 1, ret
, "digest_alloc");
96 ret
= krb5_digest_set_type(context
, digest
, opt
->type_string
);
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
,
103 opt
->cb_value_string
);
105 krb5_err(context
, 1, ret
, "krb5_digest_set_server_cb");
107 ret
= krb5_digest_init_request(context
,
109 opt
->kerberos_realm_string
,
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
);
120 printf("identifier=%s\n", s
);
122 printf("opaque=%s\n", krb5_digest_get_opaque(context
, digest
));
128 digest_server_request(struct digest_server_request_options
*opt
,
129 int argc
, char **argv
)
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
);
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
);
156 krb5_err(context
, 1, ret
, "krb5_digest_set_type");
159 ret
= krb5_digest_set_type(context
, digest
, opt
->type_string
);
161 krb5_err(context
, 1, ret
, "krb5_digest_set_type");
163 ret
= krb5_digest_set_username(context
, digest
, opt
->username_string
);
165 krb5_err(context
, 1, ret
, "krb5_digest_set_username");
167 ret
= krb5_digest_set_server_nonce(context
, digest
,
168 opt
->server_nonce_string
);
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
);
176 krb5_err(context
, 1, ret
, "krb5_digest_set_client_nonce");
180 ret
= krb5_digest_set_opaque(context
, digest
, opt
->opaque_string
);
182 krb5_err(context
, 1, ret
, "krb5_digest_set_opaque");
184 ret
= krb5_digest_set_responseData(context
, digest
,
185 opt
->client_response_string
);
187 krb5_err(context
, 1, ret
, "krb5_digest_set_responseData");
189 ret
= krb5_digest_request(context
, digest
,
190 opt
->kerberos_realm_string
, id
);
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
);
199 printf("rsp=%s\n", rsp
);
200 printf("tickets=no\n");
202 ret
= krb5_digest_get_session_key(context
, digest
, &session_key
);
204 krb5_err(context
, 1, ret
, "krb5_digest_get_session_key");
206 if (session_key
.length
) {
208 hex_encode(session_key
.data
, session_key
.length
, &key
);
210 krb5_errx(context
, 1, "hex_encode");
211 krb5_data_free(&session_key
);
212 printf("session-key=%s\n", key
);
220 client_chap(const void *server_nonce
, size_t snoncelen
,
221 unsigned char server_identifier
,
222 const char *password
)
225 unsigned char md
[MD5_DIGEST_LENGTH
];
229 MD5_Update(&ctx
, &server_identifier
, 1);
230 MD5_Update(&ctx
, password
, strlen(password
));
231 MD5_Update(&ctx
, server_nonce
, snoncelen
);
234 hex_encode(md
, 16, &h
);
236 printf("responseData=%s\n", 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,
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
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
)
267 unsigned char md
[SHA_DIGEST_LENGTH
], challange
[SHA_DIGEST_LENGTH
];
268 unsigned char hmd
[MD4_DIGEST_LENGTH
];
269 struct ntlm_buf answer
;
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
);
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
);
290 errx(1, "heim_ntlm_calculate_ntlm1");
292 hex_encode(answer
.data
, answer
.length
, &h
);
293 printf("responseData=%s\n", h
);
298 MD4_Update(&hctx
, hmd
, sizeof(hmd
));
299 MD4_Final(hmd
, &hctx
);
301 /* GenerateAuthenticatorResponse */
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
);
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
);
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
);
325 /* get_master, rfc 3079 3.4 */
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
);
334 hex_encode(md
, 16, &h
);
335 printf("session-key=%s\n", 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
);
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
);
373 errx(1, "client nonce wrong");
376 if (opt
->server_identifier_string
) {
379 ret
= hex_decode(opt
->server_identifier_string
, &server_identifier
, 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
);
407 #include <heimntlm.h>
410 ntlm_server_init(struct ntlm_server_init_options
*opt
,
411 int argc
, char ** argv
)
415 struct ntlm_type2 type2
;
416 krb5_data challange
, opaque
;
417 struct ntlm_buf data
;
420 memset(&type2
, 0, sizeof(type2
));
422 ret
= krb5_ntlm_alloc(context
, &ntlm
);
424 krb5_err(context
, 1, ret
, "krb5_ntlm_alloc");
426 ret
= krb5_ntlm_init_request(context
,
428 opt
->kerberos_realm_string
,
430 NTLM_NEG_UNICODE
|NTLM_NEG_NTLM
,
434 krb5_err(context
, 1, ret
, "krb5_ntlm_init_request");
440 ret
= krb5_ntlm_init_get_challange(context
, ntlm
, &challange
);
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
);
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
);
459 krb5_errx(context
, 1, "heim_ntlm_encode_type2");
461 free(type2
.targetname
);
467 base64_encode(data
.data
, data
.length
, &s
);
469 printf("type2=%s\n", s
);
476 ret
= krb5_ntlm_init_get_opaque(context
, ntlm
, &opaque
);
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
);
489 krb5_ntlm_free(context
, ntlm
);
500 help(void *opt
, int argc
, char **argv
)
502 sl_slc_help(commands
, argc
, argv
);
507 main(int argc
, char **argv
)
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");
518 errx(1, "krb5_init_context failed: %d", ret
);
520 if(getarg(args
, sizeof(args
) / sizeof(args
[0]), argc
, argv
, &optidx
))
535 help(NULL
, argc
, argv
);
540 ret
= krb5_cc_resolve(context
, ccache_string
, &id
);
542 krb5_err(context
, 1, ret
, "krb5_cc_resolve");
545 ret
= sl_command (commands
, argc
, argv
);
547 help(NULL
, argc
, argv
);