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
);
411 #include <heimntlm.h>
414 ntlm_server_init(struct ntlm_server_init_options
*opt
,
415 int argc
, char ** argv
)
419 struct ntlm_type2 type2
;
420 krb5_data challange
, opaque
;
421 struct ntlm_buf data
;
424 memset(&type2
, 0, sizeof(type2
));
426 ret
= krb5_ntlm_alloc(context
, &ntlm
);
428 krb5_err(context
, 1, ret
, "krb5_ntlm_alloc");
430 ret
= krb5_ntlm_init_request(context
,
432 opt
->kerberos_realm_string
,
434 NTLM_NEG_UNICODE
|NTLM_NEG_NTLM
,
438 krb5_err(context
, 1, ret
, "krb5_ntlm_init_request");
444 ret
= krb5_ntlm_init_get_challange(context
, ntlm
, &challange
);
446 krb5_err(context
, 1, ret
, "krb5_ntlm_init_get_challange");
448 if (challange
.length
!= sizeof(type2
.challange
))
449 krb5_errx(context
, 1, "ntlm challange have wrong length");
450 memcpy(type2
.challange
, challange
.data
, sizeof(type2
.challange
));
451 krb5_data_free(&challange
);
453 ret
= krb5_ntlm_init_get_flags(context
, ntlm
, &type2
.flags
);
455 krb5_err(context
, 1, ret
, "krb5_ntlm_init_get_flags");
457 krb5_ntlm_init_get_targetname(context
, ntlm
, &type2
.targetname
);
458 type2
.targetinfo
.data
= "\x00\x00";
459 type2
.targetinfo
.length
= 2;
461 ret
= heim_ntlm_encode_type2(&type2
, &data
);
463 krb5_errx(context
, 1, "heim_ntlm_encode_type2");
465 free(type2
.targetname
);
471 base64_encode(data
.data
, data
.length
, &s
);
473 printf("type2=%s\n", s
);
480 ret
= krb5_ntlm_init_get_opaque(context
, ntlm
, &opaque
);
482 krb5_err(context
, 1, ret
, "krb5_ntlm_init_get_opaque");
484 base64_encode(opaque
.data
, opaque
.length
, &s
);
485 krb5_data_free(&opaque
);
486 printf("opaque=%s\n", s
);
493 krb5_ntlm_free(context
, ntlm
);
504 help(void *opt
, int argc
, char **argv
)
506 sl_slc_help(commands
, argc
, argv
);
511 main(int argc
, char **argv
)
516 setprogname(argv
[0]);
518 ret
= krb5_init_context (&context
);
519 if (ret
== KRB5_CONFIG_BADFORMAT
)
520 errx (1, "krb5_init_context failed to parse configuration file");
522 errx(1, "krb5_init_context failed: %d", ret
);
524 if(getarg(args
, sizeof(args
) / sizeof(args
[0]), argc
, argv
, &optidx
))
539 help(NULL
, argc
, argv
);
544 ret
= krb5_cc_resolve(context
, ccache_string
, &id
);
546 krb5_err(context
, 1, ret
, "krb5_cc_resolve");
549 ret
= sl_command (commands
, argc
, argv
);
551 help(NULL
, argc
, argv
);