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 #define HC_DEPRECATED_CRYPTO
36 #include "kuser_locl.h"
38 #include <kdigest-commands.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
}
58 arg_printusage (args
, sizeof(args
)/sizeof(*args
),
63 static krb5_context context
;
66 digest_probe(struct digest_probe_options
*opt
,
67 int argc
, char ** argv
)
73 realm
= opt
->realm_string
;
76 errx(1, "realm missing");
78 ret
= krb5_digest_probe(context
, realm
, id
, &flags
);
80 krb5_err(context
, 1, ret
, "digest_probe");
82 printf("flags: %u\n", flags
);
88 digest_server_init(struct digest_server_init_options
*opt
,
89 int argc
, char ** argv
)
94 ret
= krb5_digest_alloc(context
, &digest
);
96 krb5_err(context
, 1, ret
, "digest_alloc");
98 ret
= krb5_digest_set_type(context
, digest
, opt
->type_string
);
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
,
105 opt
->cb_value_string
);
107 krb5_err(context
, 1, ret
, "krb5_digest_set_server_cb");
109 ret
= krb5_digest_init_request(context
,
111 opt
->kerberos_realm_string
,
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
);
122 printf("identifier=%s\n", s
);
124 printf("opaque=%s\n", krb5_digest_get_opaque(context
, digest
));
126 krb5_digest_free(digest
);
132 digest_server_request(struct digest_server_request_options
*opt
,
133 int argc
, char **argv
)
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
);
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
);
160 krb5_err(context
, 1, ret
, "krb5_digest_set_type");
163 ret
= krb5_digest_set_type(context
, digest
, opt
->type_string
);
165 krb5_err(context
, 1, ret
, "krb5_digest_set_type");
167 ret
= krb5_digest_set_username(context
, digest
, opt
->username_string
);
169 krb5_err(context
, 1, ret
, "krb5_digest_set_username");
171 ret
= krb5_digest_set_server_nonce(context
, digest
,
172 opt
->server_nonce_string
);
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
);
180 krb5_err(context
, 1, ret
, "krb5_digest_set_client_nonce");
184 ret
= krb5_digest_set_opaque(context
, digest
, opt
->opaque_string
);
186 krb5_err(context
, 1, ret
, "krb5_digest_set_opaque");
188 ret
= krb5_digest_set_responseData(context
, digest
,
189 opt
->client_response_string
);
191 krb5_err(context
, 1, ret
, "krb5_digest_set_responseData");
193 ret
= krb5_digest_request(context
, digest
,
194 opt
->kerberos_realm_string
, id
);
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
);
203 printf("rsp=%s\n", rsp
);
204 printf("tickets=no\n");
206 ret
= krb5_digest_get_session_key(context
, digest
, &session_key
);
208 krb5_err(context
, 1, ret
, "krb5_digest_get_session_key");
210 if (session_key
.length
) {
212 hex_encode(session_key
.data
, session_key
.length
, &key
);
214 krb5_errx(context
, 1, "hex_encode");
215 krb5_data_free(&session_key
);
216 printf("session-key=%s\n", key
);
220 krb5_digest_free(digest
);
226 client_chap(const void *server_nonce
, size_t snoncelen
,
227 unsigned char server_identifier
,
228 const char *password
)
231 unsigned char md
[MD5_DIGEST_LENGTH
];
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
);
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,
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
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
;
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
);
304 errx(1, "heim_ntlm_calculate_ntlm1");
306 hex_encode(answer
.data
, answer
.length
, &h
);
307 printf("responseData=%s\n", h
);
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
);
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
);
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
);
349 hex_encode(md
, 16, &h
);
350 printf("session-key=%s\n", 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
);
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
);
391 errx(1, "client nonce wrong");
394 if (opt
->server_identifier_string
) {
397 ret
= hex_decode(opt
->server_identifier_string
, &server_identifier
, 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
);
427 #include <heimntlm.h>
430 ntlm_server_init(struct ntlm_server_init_options
*opt
,
431 int argc
, char ** argv
)
435 struct ntlm_type2 type2
;
436 krb5_data challenge
, opaque
;
437 struct ntlm_buf data
;
439 static char zero2
[] = "\x00\x00";
441 memset(&type2
, 0, sizeof(type2
));
443 ret
= krb5_ntlm_alloc(context
, &ntlm
);
445 krb5_err(context
, 1, ret
, "krb5_ntlm_alloc");
447 ret
= krb5_ntlm_init_request(context
,
449 opt
->kerberos_realm_string
,
451 NTLM_NEG_UNICODE
|NTLM_NEG_NTLM
,
455 krb5_err(context
, 1, ret
, "krb5_ntlm_init_request");
461 ret
= krb5_ntlm_init_get_challenge(context
, ntlm
, &challenge
);
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
);
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
);
480 krb5_errx(context
, 1, "heim_ntlm_encode_type2");
482 free(type2
.targetname
);
488 base64_encode(data
.data
, data
.length
, &s
);
490 printf("type2=%s\n", s
);
497 ret
= krb5_ntlm_init_get_opaque(context
, ntlm
, &opaque
);
499 krb5_err(context
, 1, ret
, "krb5_ntlm_init_get_opaque");
501 base64_encode(opaque
.data
, opaque
.length
, &s
);
502 krb5_data_free(&opaque
);
503 printf("opaque=%s\n", s
);
510 krb5_ntlm_free(context
, ntlm
);
521 help(void *opt
, int argc
, char **argv
)
523 sl_slc_help(commands
, argc
, argv
);
528 main(int argc
, char **argv
)
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");
539 errx(1, "krb5_init_context failed: %d", ret
);
541 if(getarg(args
, sizeof(args
) / sizeof(args
[0]), argc
, argv
, &optidx
))
556 help(NULL
, argc
, argv
);
561 ret
= krb5_cc_resolve(context
, ccache_string
, &id
);
563 krb5_err(context
, 1, ret
, "krb5_cc_resolve");
566 ret
= sl_command (commands
, argc
, argv
);
568 help(NULL
, argc
, argv
);