1 /* $NetBSD: kdigest.c,v 1.1.1.2 2014/04/24 12:45:28 pettai Exp $ */
4 * Copyright (c) 2006 - 2007 Kungliga Tekniska Högskolan
5 * (Royal Institute of Technology, Stockholm, Sweden).
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
19 * 3. Neither the name of the Institute nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
23 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 #define HC_DEPRECATED_CRYPTO
38 #include "kuser_locl.h"
40 #include <kdigest-commands.h>
42 #include <krb5/base64.h>
43 #include <krb5/heimntlm.h>
44 #include "crypto-headers.h"
46 static int version_flag
= 0;
47 static int help_flag
= 0;
48 static char *ccache_string
;
49 static krb5_ccache id
;
51 static struct getargs args
[] = {
52 {"ccache", 0, arg_string
, &ccache_string
, "credential cache", NULL
},
53 {"version", 0, arg_flag
, &version_flag
, "print version", NULL
},
54 {"help", 0, arg_flag
, &help_flag
, NULL
, NULL
}
60 arg_printusage (args
, sizeof(args
)/sizeof(*args
),
65 static krb5_context context
;
68 digest_probe(struct digest_probe_options
*opt
,
69 int argc
, char ** argv
)
75 realm
= opt
->realm_string
;
78 errx(1, "realm missing");
80 ret
= krb5_digest_probe(context
, realm
, id
, &flags
);
82 krb5_err(context
, 1, ret
, "digest_probe");
84 printf("flags: %u\n", flags
);
90 digest_server_init(struct digest_server_init_options
*opt
,
91 int argc
, char ** argv
)
96 ret
= krb5_digest_alloc(context
, &digest
);
98 krb5_err(context
, 1, ret
, "digest_alloc");
100 ret
= krb5_digest_set_type(context
, digest
, opt
->type_string
);
102 krb5_err(context
, 1, ret
, "krb5_digest_set_type");
104 if (opt
->cb_type_string
&& opt
->cb_value_string
) {
105 ret
= krb5_digest_set_server_cb(context
, digest
,
107 opt
->cb_value_string
);
109 krb5_err(context
, 1, ret
, "krb5_digest_set_server_cb");
111 ret
= krb5_digest_init_request(context
,
113 opt
->kerberos_realm_string
,
116 krb5_err(context
, 1, ret
, "krb5_digest_init_request");
118 printf("type=%s\n", opt
->type_string
);
119 printf("server-nonce=%s\n",
120 krb5_digest_get_server_nonce(context
, digest
));
122 const char *s
= krb5_digest_get_identifier(context
, digest
);
124 printf("identifier=%s\n", s
);
126 printf("opaque=%s\n", krb5_digest_get_opaque(context
, digest
));
128 krb5_digest_free(digest
);
134 digest_server_request(struct digest_server_request_options
*opt
,
135 int argc
, char **argv
)
139 const char *status
, *rsp
;
140 krb5_data session_key
;
142 if (opt
->server_nonce_string
== NULL
)
143 errx(1, "server nonce missing");
144 if (opt
->type_string
== NULL
)
145 errx(1, "type missing");
146 if (opt
->opaque_string
== NULL
)
147 errx(1, "opaque missing");
148 if (opt
->client_response_string
== NULL
)
149 errx(1, "client response missing");
151 ret
= krb5_digest_alloc(context
, &digest
);
153 krb5_err(context
, 1, ret
, "digest_alloc");
155 if (strcasecmp(opt
->type_string
, "CHAP") == 0) {
156 if (opt
->server_identifier_string
== NULL
)
157 errx(1, "server identifier missing");
159 ret
= krb5_digest_set_identifier(context
, digest
,
160 opt
->server_identifier_string
);
162 krb5_err(context
, 1, ret
, "krb5_digest_set_type");
165 ret
= krb5_digest_set_type(context
, digest
, opt
->type_string
);
167 krb5_err(context
, 1, ret
, "krb5_digest_set_type");
169 ret
= krb5_digest_set_username(context
, digest
, opt
->username_string
);
171 krb5_err(context
, 1, ret
, "krb5_digest_set_username");
173 ret
= krb5_digest_set_server_nonce(context
, digest
,
174 opt
->server_nonce_string
);
176 krb5_err(context
, 1, ret
, "krb5_digest_set_server_nonce");
178 if(opt
->client_nonce_string
) {
179 ret
= krb5_digest_set_client_nonce(context
, digest
,
180 opt
->client_nonce_string
);
182 krb5_err(context
, 1, ret
, "krb5_digest_set_client_nonce");
186 ret
= krb5_digest_set_opaque(context
, digest
, opt
->opaque_string
);
188 krb5_err(context
, 1, ret
, "krb5_digest_set_opaque");
190 ret
= krb5_digest_set_responseData(context
, digest
,
191 opt
->client_response_string
);
193 krb5_err(context
, 1, ret
, "krb5_digest_set_responseData");
195 ret
= krb5_digest_request(context
, digest
,
196 opt
->kerberos_realm_string
, id
);
198 krb5_err(context
, 1, ret
, "krb5_digest_request");
200 status
= krb5_digest_rep_get_status(context
, digest
) ? "ok" : "failed";
201 rsp
= krb5_digest_get_rsp(context
, digest
);
203 printf("status=%s\n", status
);
205 printf("rsp=%s\n", rsp
);
206 printf("tickets=no\n");
208 ret
= krb5_digest_get_session_key(context
, digest
, &session_key
);
210 krb5_err(context
, 1, ret
, "krb5_digest_get_session_key");
212 if (session_key
.length
) {
214 hex_encode(session_key
.data
, session_key
.length
, &key
);
216 krb5_errx(context
, 1, "hex_encode");
217 krb5_data_free(&session_key
);
218 printf("session-key=%s\n", key
);
222 krb5_digest_free(digest
);
228 client_chap(const void *server_nonce
, size_t snoncelen
,
229 unsigned char server_identifier
,
230 const char *password
)
233 unsigned char md
[MD5_DIGEST_LENGTH
];
236 ctx
= EVP_MD_CTX_create();
237 EVP_DigestInit_ex(ctx
, EVP_md5(), NULL
);
239 EVP_DigestUpdate(ctx
, &server_identifier
, 1);
240 EVP_DigestUpdate(ctx
, password
, strlen(password
));
241 EVP_DigestUpdate(ctx
, server_nonce
, snoncelen
);
242 EVP_DigestFinal_ex(ctx
, md
, NULL
);
244 EVP_MD_CTX_destroy(ctx
);
246 hex_encode(md
, 16, &h
);
248 printf("responseData=%s\n", h
);
252 static const unsigned char ms_chap_v2_magic1
[39] = {
253 0x4D, 0x61, 0x67, 0x69, 0x63, 0x20, 0x73, 0x65, 0x72, 0x76,
254 0x65, 0x72, 0x20, 0x74, 0x6F, 0x20, 0x63, 0x6C, 0x69, 0x65,
255 0x6E, 0x74, 0x20, 0x73, 0x69, 0x67, 0x6E, 0x69, 0x6E, 0x67,
256 0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x61, 0x6E, 0x74
258 static const unsigned char ms_chap_v2_magic2
[41] = {
259 0x50, 0x61, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x6D, 0x61, 0x6B,
260 0x65, 0x20, 0x69, 0x74, 0x20, 0x64, 0x6F, 0x20, 0x6D, 0x6F,
261 0x72, 0x65, 0x20, 0x74, 0x68, 0x61, 0x6E, 0x20, 0x6F, 0x6E,
262 0x65, 0x20, 0x69, 0x74, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6F,
265 static const unsigned char ms_rfc3079_magic1
[27] = {
266 0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74,
267 0x68, 0x65, 0x20, 0x4d, 0x50, 0x50, 0x45, 0x20, 0x4d,
268 0x61, 0x73, 0x74, 0x65, 0x72, 0x20, 0x4b, 0x65, 0x79
272 client_mschapv2(const void *server_nonce
, size_t snoncelen
,
273 const void *client_nonce
, size_t cnoncelen
,
274 const char *username
,
275 const char *password
)
277 EVP_MD_CTX
*hctx
, *ctx
;
278 unsigned char md
[SHA_DIGEST_LENGTH
], challenge
[SHA_DIGEST_LENGTH
];
279 unsigned char hmd
[MD4_DIGEST_LENGTH
];
280 struct ntlm_buf answer
;
284 ctx
= EVP_MD_CTX_create();
285 EVP_DigestInit_ex(ctx
, EVP_sha1(), NULL
);
287 EVP_DigestUpdate(ctx
, client_nonce
, cnoncelen
);
288 EVP_DigestUpdate(ctx
, server_nonce
, snoncelen
);
289 EVP_DigestUpdate(ctx
, username
, strlen(username
));
290 EVP_DigestFinal_ex(ctx
, md
, NULL
);
293 hctx
= EVP_MD_CTX_create();
294 EVP_DigestInit_ex(hctx
, EVP_md4(), NULL
);
295 len
= strlen(password
);
296 for (i
= 0; i
< len
; i
++) {
297 EVP_DigestUpdate(hctx
, &password
[i
], 1);
298 EVP_DigestUpdate(hctx
, &password
[len
], 1);
300 EVP_DigestFinal_ex(hctx
, hmd
, NULL
);
303 /* ChallengeResponse */
304 ret
= heim_ntlm_calculate_ntlm1(hmd
, sizeof(hmd
), md
, &answer
);
306 errx(1, "heim_ntlm_calculate_ntlm1");
308 hex_encode(answer
.data
, answer
.length
, &h
);
309 printf("responseData=%s\n", h
);
313 EVP_DigestInit_ex(hctx
, EVP_md4(), NULL
);
314 EVP_DigestUpdate(hctx
, hmd
, sizeof(hmd
));
315 EVP_DigestFinal_ex(hctx
, hmd
, NULL
);
318 /* GenerateAuthenticatorResponse */
319 EVP_DigestInit_ex(ctx
, EVP_sha1(), NULL
);
320 EVP_DigestUpdate(ctx
, hmd
, sizeof(hmd
));
321 EVP_DigestUpdate(ctx
, answer
.data
, answer
.length
);
322 EVP_DigestUpdate(ctx
, ms_chap_v2_magic1
, sizeof(ms_chap_v2_magic1
));
323 EVP_DigestFinal_ex(ctx
, md
, NULL
);
326 EVP_DigestInit_ex(ctx
, EVP_sha1(), NULL
);
327 EVP_DigestUpdate(ctx
, client_nonce
, cnoncelen
);
328 EVP_DigestUpdate(ctx
, server_nonce
, snoncelen
);
329 EVP_DigestUpdate(ctx
, username
, strlen(username
));
330 EVP_DigestFinal_ex(ctx
, challenge
, NULL
);
332 EVP_DigestInit_ex(ctx
, EVP_sha1(), NULL
);
333 EVP_DigestUpdate(ctx
, md
, sizeof(md
));
334 EVP_DigestUpdate(ctx
, challenge
, 8);
335 EVP_DigestUpdate(ctx
, ms_chap_v2_magic2
, sizeof(ms_chap_v2_magic2
));
336 EVP_DigestFinal_ex(ctx
, md
, NULL
);
338 hex_encode(md
, sizeof(md
), &h
);
339 printf("AuthenticatorResponse=%s\n", h
);
342 /* get_master, rfc 3079 3.4 */
343 EVP_DigestInit_ex(ctx
, EVP_sha1(), NULL
);
344 EVP_DigestUpdate(ctx
, hmd
, sizeof(hmd
));
345 EVP_DigestUpdate(ctx
, answer
.data
, answer
.length
);
346 EVP_DigestUpdate(ctx
, ms_rfc3079_magic1
, sizeof(ms_rfc3079_magic1
));
347 EVP_DigestFinal_ex(ctx
, md
, NULL
);
351 hex_encode(md
, 16, &h
);
352 printf("session-key=%s\n", h
);
355 EVP_MD_CTX_destroy(hctx
);
356 EVP_MD_CTX_destroy(ctx
);
361 digest_client_request(struct digest_client_request_options
*opt
,
362 int argc
, char **argv
)
364 char *server_nonce
, *client_nonce
= NULL
, server_identifier
;
365 ssize_t snoncelen
, cnoncelen
= 0;
367 if (opt
->server_nonce_string
== NULL
)
368 errx(1, "server nonce missing");
369 if (opt
->password_string
== NULL
)
370 errx(1, "password missing");
372 if (opt
->opaque_string
== NULL
)
373 errx(1, "opaque missing");
375 snoncelen
= strlen(opt
->server_nonce_string
);
376 server_nonce
= malloc(snoncelen
);
377 if (server_nonce
== NULL
)
378 errx(1, "server_nonce");
380 snoncelen
= hex_decode(opt
->server_nonce_string
, server_nonce
, snoncelen
);
382 errx(1, "server nonce wrong");
384 if (opt
->client_nonce_string
) {
385 cnoncelen
= strlen(opt
->client_nonce_string
);
386 client_nonce
= malloc(cnoncelen
);
387 if (client_nonce
== NULL
)
388 errx(1, "client_nonce");
390 cnoncelen
= hex_decode(opt
->client_nonce_string
,
391 client_nonce
, cnoncelen
);
393 errx(1, "client nonce wrong");
396 if (opt
->server_identifier_string
) {
399 ret
= hex_decode(opt
->server_identifier_string
, &server_identifier
, 1);
401 errx(1, "server identifier wrong length");
404 if (strcasecmp(opt
->type_string
, "CHAP") == 0) {
405 if (opt
->server_identifier_string
== NULL
)
406 errx(1, "server identifier missing");
408 client_chap(server_nonce
, snoncelen
, server_identifier
,
409 opt
->password_string
);
411 } else if (strcasecmp(opt
->type_string
, "MS-CHAP-V2") == 0) {
412 if (opt
->client_nonce_string
== NULL
)
413 errx(1, "client nonce missing");
414 if (opt
->username_string
== NULL
)
415 errx(1, "client nonce missing");
417 client_mschapv2(server_nonce
, snoncelen
,
418 client_nonce
, cnoncelen
,
419 opt
->username_string
,
420 opt
->password_string
);
429 #include <krb5/heimntlm.h>
432 ntlm_server_init(struct ntlm_server_init_options
*opt
,
433 int argc
, char ** argv
)
437 struct ntlm_type2 type2
;
438 krb5_data challenge
, opaque
;
439 struct ntlm_buf data
;
441 static char zero2
[] = "\x00\x00";
443 memset(&type2
, 0, sizeof(type2
));
445 ret
= krb5_ntlm_alloc(context
, &ntlm
);
447 krb5_err(context
, 1, ret
, "krb5_ntlm_alloc");
449 ret
= krb5_ntlm_init_request(context
,
451 opt
->kerberos_realm_string
,
453 NTLM_NEG_UNICODE
|NTLM_NEG_NTLM
,
457 krb5_err(context
, 1, ret
, "krb5_ntlm_init_request");
463 ret
= krb5_ntlm_init_get_challange(context
, ntlm
, &challenge
);
465 krb5_err(context
, 1, ret
, "krb5_ntlm_init_get_challange");
467 if (challenge
.length
!= sizeof(type2
.challenge
))
468 krb5_errx(context
, 1, "ntlm challenge have wrong length");
469 memcpy(type2
.challenge
, challenge
.data
, sizeof(type2
.challenge
));
470 krb5_data_free(&challenge
);
472 ret
= krb5_ntlm_init_get_flags(context
, ntlm
, &type2
.flags
);
474 krb5_err(context
, 1, ret
, "krb5_ntlm_init_get_flags");
476 krb5_ntlm_init_get_targetname(context
, ntlm
, &type2
.targetname
);
477 type2
.targetinfo
.data
= zero2
;
478 type2
.targetinfo
.length
= 2;
480 ret
= heim_ntlm_encode_type2(&type2
, &data
);
482 krb5_errx(context
, 1, "heim_ntlm_encode_type2");
484 free(type2
.targetname
);
490 base64_encode(data
.data
, data
.length
, &s
);
492 printf("type2=%s\n", s
);
499 ret
= krb5_ntlm_init_get_opaque(context
, ntlm
, &opaque
);
501 krb5_err(context
, 1, ret
, "krb5_ntlm_init_get_opaque");
503 base64_encode(opaque
.data
, opaque
.length
, &s
);
504 krb5_data_free(&opaque
);
505 printf("opaque=%s\n", s
);
512 krb5_ntlm_free(context
, ntlm
);
523 help(void *opt
, int argc
, char **argv
)
525 sl_slc_help(commands
, argc
, argv
);
530 main(int argc
, char **argv
)
535 setprogname(argv
[0]);
537 ret
= krb5_init_context (&context
);
538 if (ret
== KRB5_CONFIG_BADFORMAT
)
539 errx (1, "krb5_init_context failed to parse configuration file");
541 errx(1, "krb5_init_context failed: %d", ret
);
543 if(getarg(args
, sizeof(args
) / sizeof(args
[0]), argc
, argv
, &optidx
))
558 help(NULL
, argc
, argv
);
563 ret
= krb5_cc_resolve(context
, ccache_string
, &id
);
565 krb5_err(context
, 1, ret
, "krb5_cc_resolve");
568 ret
= sl_command (commands
, argc
, argv
);
570 help(NULL
, argc
, argv
);