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
));
124 krb5_digest_free(digest
);
130 digest_server_request(struct digest_server_request_options
*opt
,
131 int argc
, char **argv
)
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
);
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
);
158 krb5_err(context
, 1, ret
, "krb5_digest_set_type");
161 ret
= krb5_digest_set_type(context
, digest
, opt
->type_string
);
163 krb5_err(context
, 1, ret
, "krb5_digest_set_type");
165 ret
= krb5_digest_set_username(context
, digest
, opt
->username_string
);
167 krb5_err(context
, 1, ret
, "krb5_digest_set_username");
169 ret
= krb5_digest_set_server_nonce(context
, digest
,
170 opt
->server_nonce_string
);
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
);
178 krb5_err(context
, 1, ret
, "krb5_digest_set_client_nonce");
182 ret
= krb5_digest_set_opaque(context
, digest
, opt
->opaque_string
);
184 krb5_err(context
, 1, ret
, "krb5_digest_set_opaque");
186 ret
= krb5_digest_set_responseData(context
, digest
,
187 opt
->client_response_string
);
189 krb5_err(context
, 1, ret
, "krb5_digest_set_responseData");
191 ret
= krb5_digest_request(context
, digest
,
192 opt
->kerberos_realm_string
, id
);
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
);
201 printf("rsp=%s\n", rsp
);
202 printf("tickets=no\n");
204 ret
= krb5_digest_get_session_key(context
, digest
, &session_key
);
206 krb5_err(context
, 1, ret
, "krb5_digest_get_session_key");
208 if (session_key
.length
) {
210 hex_encode(session_key
.data
, session_key
.length
, &key
);
212 krb5_errx(context
, 1, "hex_encode");
213 krb5_data_free(&session_key
);
214 printf("session-key=%s\n", key
);
218 krb5_digest_free(digest
);
224 client_chap(const void *server_nonce
, size_t snoncelen
,
225 unsigned char server_identifier
,
226 const char *password
)
229 unsigned char md
[MD5_DIGEST_LENGTH
];
233 MD5_Update(&ctx
, &server_identifier
, 1);
234 MD5_Update(&ctx
, password
, strlen(password
));
235 MD5_Update(&ctx
, server_nonce
, snoncelen
);
238 hex_encode(md
, 16, &h
);
240 printf("responseData=%s\n", 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,
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
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
)
271 unsigned char md
[SHA_DIGEST_LENGTH
], challange
[SHA_DIGEST_LENGTH
];
272 unsigned char hmd
[MD4_DIGEST_LENGTH
];
273 struct ntlm_buf answer
;
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
);
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
);
294 errx(1, "heim_ntlm_calculate_ntlm1");
296 hex_encode(answer
.data
, answer
.length
, &h
);
297 printf("responseData=%s\n", h
);
302 MD4_Update(&hctx
, hmd
, sizeof(hmd
));
303 MD4_Final(hmd
, &hctx
);
305 /* GenerateAuthenticatorResponse */
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
);
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
);
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
);
329 /* get_master, rfc 3079 3.4 */
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
);
338 hex_encode(md
, 16, &h
);
339 printf("session-key=%s\n", 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
);
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
);
377 errx(1, "client nonce wrong");
380 if (opt
->server_identifier_string
) {
383 ret
= hex_decode(opt
->server_identifier_string
, &server_identifier
, 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
);
413 #include <heimntlm.h>
416 ntlm_server_init(struct ntlm_server_init_options
*opt
,
417 int argc
, char ** argv
)
421 struct ntlm_type2 type2
;
422 krb5_data challange
, opaque
;
423 struct ntlm_buf data
;
426 memset(&type2
, 0, sizeof(type2
));
428 ret
= krb5_ntlm_alloc(context
, &ntlm
);
430 krb5_err(context
, 1, ret
, "krb5_ntlm_alloc");
432 ret
= krb5_ntlm_init_request(context
,
434 opt
->kerberos_realm_string
,
436 NTLM_NEG_UNICODE
|NTLM_NEG_NTLM
,
440 krb5_err(context
, 1, ret
, "krb5_ntlm_init_request");
446 ret
= krb5_ntlm_init_get_challange(context
, ntlm
, &challange
);
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
);
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
);
465 krb5_errx(context
, 1, "heim_ntlm_encode_type2");
467 free(type2
.targetname
);
473 base64_encode(data
.data
, data
.length
, &s
);
475 printf("type2=%s\n", s
);
482 ret
= krb5_ntlm_init_get_opaque(context
, ntlm
, &opaque
);
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
);
495 krb5_ntlm_free(context
, ntlm
);
506 help(void *opt
, int argc
, char **argv
)
508 sl_slc_help(commands
, argc
, argv
);
513 main(int argc
, char **argv
)
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");
524 errx(1, "krb5_init_context failed: %d", ret
);
526 if(getarg(args
, sizeof(args
) / sizeof(args
[0]), argc
, argv
, &optidx
))
541 help(NULL
, argc
, argv
);
546 ret
= krb5_cc_resolve(context
, ccache_string
, &id
);
548 krb5_err(context
, 1, ret
, "krb5_cc_resolve");
551 ret
= sl_command (commands
, argc
, argv
);
553 help(NULL
, argc
, argv
);