2 * Copyright (c) 2006 - 2008 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 KTH nor the names of its contributors may be
18 * used to endorse or promote products derived from this software without
19 * specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY KTH AND ITS CONTRIBUTORS ``AS IS'' AND ANY
22 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL KTH OR ITS CONTRIBUTORS BE
25 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
28 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
29 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
30 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
31 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 #include "krb5/gsskrb5_locl.h"
38 #include <gssapi_krb5.h>
39 #include <gssapi_spnego.h>
40 #include <gssapi_ntlm.h>
41 #include "test_common.h"
43 static char *type_string;
44 static char *mech_string;
45 static char *mechs_string;
46 static char *ret_mech_string;
47 static char *client_name;
48 static char *client_password;
49 static int dns_canon_flag = -1;
50 static int mutual_auth_flag = 0;
51 static int dce_style_flag = 0;
52 static int wrapunwrap_flag = 0;
53 static int iov_flag = 0;
54 static int aead_flag = 0;
55 static int getverifymic_flag = 0;
56 static int deleg_flag = 0;
57 static int policy_deleg_flag = 0;
58 static int server_no_deleg_flag = 0;
59 static int ei_cred_flag = 0;
60 static int ei_ctx_flag = 0;
61 static char *client_ccache = NULL;
62 static char *client_keytab = NULL;
63 static char *gsskrb5_acceptor_identity = NULL;
64 static char *session_enctype_string = NULL;
65 static int client_time_offset = 0;
66 static int server_time_offset = 0;
67 static int max_loops = 0;
68 static char *limit_enctype_string = NULL;
69 static int version_flag = 0;
70 static int verbose_flag = 0;
71 static int help_flag = 0;
73 static krb5_context context;
74 static krb5_enctype limit_enctype = 0;
76 static gss_OID_desc test_negoex_1_mech = { 6, "\x69\x85\xa2\xc0\xac\x66" };
77 static gss_OID_desc test_negoex_2_mech = { 6, "\x69\x84\xb0\xd1\xa8\x2c" };
83 { "krb5", NULL /* GSS_KRB5_MECHANISM */ },
84 { "spnego", NULL /* GSS_SPNEGO_MECHANISM */ },
85 { "ntlm", NULL /* GSS_NTLM_MECHANISM */ },
86 { "sasl-digest-md5", NULL /* GSS_SASL_DIGEST_MD5_MECHANISM */ },
87 { "test_negoex_1", NULL },
88 { "test_negoex_2", NULL },
94 o2n[0].oid = GSS_KRB5_MECHANISM;
95 o2n[1].oid = GSS_SPNEGO_MECHANISM;
96 o2n[2].oid = GSS_NTLM_MECHANISM;
97 o2n[3].oid = GSS_SASL_DIGEST_MD5_MECHANISM;
98 o2n[4].oid = &test_negoex_1_mech;
99 o2n[5].oid = &test_negoex_2_mech;
103 string_to_oid(const char *name)
106 for (i = 0; i < sizeof(o2n)/sizeof(o2n[0]); i++)
107 if (strcasecmp(name, o2n[i].name) == 0)
109 errx(1, "name '%s' not known", name);
113 string_to_oids(gss_OID_set *oidsetp, gss_OID_set oidset,
114 gss_OID_desc *oidarray, size_t oidarray_len,
120 if (names[0] == '\0') {
121 *oidsetp = GSS_C_NO_OID_SET;
125 oidset->elements = &oidarray[0];
126 if (strcasecmp(names, "all") == 0) {
127 if (sizeof(o2n)/sizeof(o2n[0]) > oidarray_len)
128 errx(1, "internal error: oidarray must be enlarged");
129 for (oidset->count = 0; oidset->count < oidarray_len; oidset->count++)
130 oidset->elements[oidset->count] = *o2n[oidset->count].oid;
132 for (oidset->count = 0, name = strtok_r(names, ", ", &s);
134 oidset->count++, name = strtok_r(NULL, ", ", &s)) {
135 if (oidset->count >= oidarray_len)
136 errx(1, "too many mech names given");
137 oidset->elements[oidset->count] = *string_to_oid(name);
144 oid_to_string(const gss_OID oid)
147 for (i = 0; i < sizeof(o2n)/sizeof(o2n[0]); i++)
148 if (gss_oid_equal(oid, o2n[i].oid))
150 return "unknown oid";
154 loop(gss_OID mechoid,
155 gss_OID nameoid, const char *target,
156 gss_cred_id_t init_cred,
157 gss_ctx_id_t *sctx, gss_ctx_id_t *cctx,
158 gss_OID *actual_mech,
159 gss_cred_id_t *deleg_cred)
161 int server_done = 0, client_done = 0;
163 OM_uint32 maj_stat, min_stat;
164 gss_name_t gss_target_name;
165 gss_buffer_desc input_token, output_token;
166 OM_uint32 flags = 0, ret_cflags, ret_sflags;
167 gss_OID actual_mech_client;
168 gss_OID actual_mech_server;
170 *actual_mech = GSS_C_NO_OID;
172 flags |= GSS_C_REPLAY_FLAG;
173 flags |= GSS_C_INTEG_FLAG;
174 flags |= GSS_C_CONF_FLAG;
176 if (mutual_auth_flag)
177 flags |= GSS_C_MUTUAL_FLAG;
179 flags |= GSS_C_DCE_STYLE;
181 flags |= GSS_C_DELEG_FLAG;
182 if (policy_deleg_flag)
183 flags |= GSS_C_DELEG_POLICY_FLAG;
185 input_token.value = rk_UNCONST(target);
186 input_token.length = strlen(target);
188 maj_stat = gss_import_name(&min_stat,
192 if (GSS_ERROR(maj_stat))
193 err(1, "import name creds failed with: %d", maj_stat);
195 input_token.length = 0;
196 input_token.value = NULL;
198 while (!server_done || !client_done) {
201 gsskrb5_set_time_offset(client_time_offset);
203 maj_stat = gss_init_sec_context(&min_stat,
216 if (GSS_ERROR(maj_stat))
217 errx(1, "init_sec_context: %s",
218 gssapi_err(maj_stat, min_stat, mechoid));
219 if (maj_stat & GSS_S_CONTINUE_NEEDED)
224 gsskrb5_get_time_offset(&client_time_offset);
226 if (client_done && server_done)
229 if (input_token.length != 0)
230 gss_release_buffer(&min_stat, &input_token);
232 gsskrb5_set_time_offset(server_time_offset);
234 maj_stat = gss_accept_sec_context(&min_stat,
238 GSS_C_NO_CHANNEL_BINDINGS,
245 if (GSS_ERROR(maj_stat))
246 errx(1, "accept_sec_context: %s",
247 gssapi_err(maj_stat, min_stat, actual_mech_server));
249 gsskrb5_get_time_offset(&server_time_offset);
251 if (output_token.length != 0)
252 gss_release_buffer(&min_stat, &output_token);
254 if (maj_stat & GSS_S_CONTINUE_NEEDED)
259 if (output_token.length != 0)
260 gss_release_buffer(&min_stat, &output_token);
261 if (input_token.length != 0)
262 gss_release_buffer(&min_stat, &input_token);
263 gss_release_name(&min_stat, &gss_target_name);
265 if (deleg_flag || policy_deleg_flag) {
266 if (server_no_deleg_flag) {
267 if (*deleg_cred != GSS_C_NO_CREDENTIAL)
268 errx(1, "got delegated cred but didn't expect one");
269 } else if (*deleg_cred == GSS_C_NO_CREDENTIAL)
270 errx(1, "asked for delegarated cred but did get one");
271 } else if (*deleg_cred != GSS_C_NO_CREDENTIAL)
272 errx(1, "got deleg_cred cred but didn't ask");
274 if (gss_oid_equal(actual_mech_server, actual_mech_client) == 0)
275 errx(1, "mech mismatch");
276 *actual_mech = actual_mech_server;
278 if (max_loops && num_loops > max_loops)
279 errx(1, "num loops %d was lager then max loops %d",
280 num_loops, max_loops);
283 printf("server time offset: %d\n", server_time_offset);
284 printf("client time offset: %d\n", client_time_offset);
285 printf("num loops %d\n", num_loops);
290 wrapunwrap(gss_ctx_id_t cctx, gss_ctx_id_t sctx, int flags, gss_OID mechoid)
292 gss_buffer_desc input_token, output_token, output_token2;
293 OM_uint32 min_stat, maj_stat;
297 input_token.value = "foo";
298 input_token.length = 3;
300 maj_stat = gss_wrap(&min_stat, cctx, flags, 0, &input_token,
301 &conf_state, &output_token);
302 if (maj_stat != GSS_S_COMPLETE)
303 errx(1, "gss_wrap failed: %s",
304 gssapi_err(maj_stat, min_stat, mechoid));
306 maj_stat = gss_unwrap(&min_stat, sctx, &output_token,
307 &output_token2, &conf_state, &qop_state);
308 if (maj_stat != GSS_S_COMPLETE)
309 errx(1, "gss_unwrap failed: %s",
310 gssapi_err(maj_stat, min_stat, mechoid));
312 gss_release_buffer(&min_stat, &output_token);
313 gss_release_buffer(&min_stat, &output_token2);
315 #if 0 /* doesn't work for NTLM yet */
316 if (!!conf_state != !!flags)
317 errx(1, "conf_state mismatch");
322 #define USE_HEADER_ONLY 2
323 #define USE_SIGN_ONLY 4
325 /* NO_DATA comes from <netdb.h>; we don't use it here; we appropriate it */
332 wrapunwrap_iov(gss_ctx_id_t cctx, gss_ctx_id_t sctx, int flags, gss_OID mechoid)
334 krb5_data token, header, trailer;
335 OM_uint32 min_stat, maj_stat;
337 int conf_state, conf_state2;
338 gss_iov_buffer_desc iov[6];
341 char header_data[9] = "ABCheader";
342 char trailer_data[10] = "trailerXYZ";
344 char token_data[16] = "0123456789abcdef";
346 memset(&iov, 0, sizeof(iov));
348 if (flags & USE_SIGN_ONLY) {
349 header.data = header_data;
351 trailer.data = trailer_data;
360 token.data = token_data;
363 iov_len = sizeof(iov)/sizeof(iov[0]);
365 memset(iov, 0, sizeof(iov));
367 iov[0].type = GSS_IOV_BUFFER_TYPE_HEADER | GSS_IOV_BUFFER_TYPE_FLAG_ALLOCATE;
369 if (header.length != 0) {
370 iov[1].type = GSS_IOV_BUFFER_TYPE_SIGN_ONLY;
371 iov[1].buffer.length = header.length;
372 iov[1].buffer.value = header.data;
374 iov[1].type = GSS_IOV_BUFFER_TYPE_EMPTY;
375 iov[1].buffer.length = 0;
376 iov[1].buffer.value = NULL;
378 iov[2].type = GSS_IOV_BUFFER_TYPE_DATA;
379 if (flags & NO_DATA) {
380 iov[2].buffer.length = 0;
382 iov[2].buffer.length = token.length;
384 iov[2].buffer.value = token.data;
385 if (trailer.length != 0) {
386 iov[3].type = GSS_IOV_BUFFER_TYPE_SIGN_ONLY;
387 iov[3].buffer.length = trailer.length;
388 iov[3].buffer.value = trailer.data;
390 iov[3].type = GSS_IOV_BUFFER_TYPE_EMPTY;
391 iov[3].buffer.length = 0;
392 iov[3].buffer.value = NULL;
394 if (dce_style_flag) {
395 iov[4].type = GSS_IOV_BUFFER_TYPE_EMPTY;
397 iov[4].type = GSS_IOV_BUFFER_TYPE_PADDING | GSS_IOV_BUFFER_TYPE_FLAG_ALLOCATE;
399 iov[4].buffer.length = 0;
400 iov[4].buffer.value = 0;
401 if (dce_style_flag) {
402 iov[5].type = GSS_IOV_BUFFER_TYPE_EMPTY;
403 } else if (flags & USE_HEADER_ONLY) {
404 iov[5].type = GSS_IOV_BUFFER_TYPE_EMPTY;
406 iov[5].type = GSS_IOV_BUFFER_TYPE_TRAILER | GSS_IOV_BUFFER_TYPE_FLAG_ALLOCATE;
408 iov[5].buffer.length = 0;
409 iov[5].buffer.value = 0;
411 maj_stat = gss_wrap_iov(&min_stat, cctx, dce_style_flag || flags & USE_CONF, 0, &conf_state,
413 if (maj_stat != GSS_S_COMPLETE)
414 errx(1, "gss_wrap_iov failed");
417 iov[0].buffer.length +
418 iov[1].buffer.length +
419 iov[2].buffer.length +
420 iov[3].buffer.length +
421 iov[4].buffer.length +
422 iov[5].buffer.length;
423 token.data = emalloc(token.length);
426 memcpy(p, iov[0].buffer.value, iov[0].buffer.length);
427 p += iov[0].buffer.length;
428 memcpy(p, iov[1].buffer.value, iov[1].buffer.length);
429 p += iov[1].buffer.length;
430 memcpy(p, iov[2].buffer.value, iov[2].buffer.length);
431 p += iov[2].buffer.length;
432 memcpy(p, iov[3].buffer.value, iov[3].buffer.length);
433 p += iov[3].buffer.length;
434 memcpy(p, iov[4].buffer.value, iov[4].buffer.length);
435 p += iov[4].buffer.length;
436 memcpy(p, iov[5].buffer.value, iov[5].buffer.length);
437 p += iov[5].buffer.length;
439 assert(p - ((unsigned char *)token.data) == token.length);
441 if ((flags & (USE_SIGN_ONLY|FORCE_IOV)) == 0) {
442 gss_buffer_desc input, output;
444 input.value = token.data;
445 input.length = token.length;
447 maj_stat = gss_unwrap(&min_stat, sctx, &input,
448 &output, &conf_state2, &qop_state);
450 if (maj_stat != GSS_S_COMPLETE)
451 errx(1, "gss_unwrap from gss_wrap_iov failed: %s",
452 gssapi_err(maj_stat, min_stat, mechoid));
454 gss_release_buffer(&min_stat, &output);
456 maj_stat = gss_unwrap_iov(&min_stat, sctx, &conf_state2, &qop_state,
459 if (maj_stat != GSS_S_COMPLETE)
460 errx(1, "gss_unwrap_iov failed: %x %s", flags,
461 gssapi_err(maj_stat, min_stat, mechoid));
464 if (conf_state2 != conf_state)
465 errx(1, "conf state wrong for iov: %x", flags);
467 gss_release_iov_buffer(&min_stat, iov, iov_len);
473 wrapunwrap_aead(gss_ctx_id_t cctx, gss_ctx_id_t sctx, int flags, gss_OID mechoid)
475 gss_buffer_desc token, assoc, message = GSS_C_EMPTY_BUFFER;
476 gss_buffer_desc output;
477 OM_uint32 min_stat, maj_stat;
479 int conf_state, conf_state2;
480 char assoc_data[9] = "ABCheader";
481 char token_data[16] = "0123456789abcdef";
483 if (flags & USE_SIGN_ONLY) {
484 assoc.value = assoc_data;
491 token.value = token_data;
494 maj_stat = gss_wrap_aead(&min_stat, cctx, dce_style_flag || flags & USE_CONF,
495 GSS_C_QOP_DEFAULT, &assoc, &token,
496 &conf_state, &message);
497 if (maj_stat != GSS_S_COMPLETE)
498 errx(1, "gss_wrap_aead failed");
500 if ((flags & (USE_SIGN_ONLY|FORCE_IOV)) == 0) {
501 maj_stat = gss_unwrap(&min_stat, sctx, &message,
502 &output, &conf_state2, &qop_state);
504 if (maj_stat != GSS_S_COMPLETE)
505 errx(1, "gss_unwrap from gss_wrap_aead failed: %s",
506 gssapi_err(maj_stat, min_stat, mechoid));
508 maj_stat = gss_unwrap_aead(&min_stat, sctx, &message, &assoc,
509 &output, &conf_state2, &qop_state);
510 if (maj_stat != GSS_S_COMPLETE)
511 errx(1, "gss_unwrap_aead failed: %x %s", flags,
512 gssapi_err(maj_stat, min_stat, mechoid));
515 if (output.length != token.length)
516 errx(1, "plaintext length wrong for aead");
517 else if (memcmp(output.value, token.value, token.length) != 0)
518 errx(1, "plaintext wrong for aead");
519 if (conf_state2 != conf_state)
520 errx(1, "conf state wrong for aead: %x", flags);
522 gss_release_buffer(&min_stat, &message);
523 gss_release_buffer(&min_stat, &output);
527 getverifymic(gss_ctx_id_t cctx, gss_ctx_id_t sctx, gss_OID mechoid)
529 gss_buffer_desc input_token, output_token;
530 OM_uint32 min_stat, maj_stat;
533 input_token.value = "bar";
534 input_token.length = 3;
536 maj_stat = gss_get_mic(&min_stat, cctx, 0, &input_token,
538 if (maj_stat != GSS_S_COMPLETE)
539 errx(1, "gss_get_mic failed: %s",
540 gssapi_err(maj_stat, min_stat, mechoid));
542 maj_stat = gss_verify_mic(&min_stat, sctx, &input_token,
543 &output_token, &qop_state);
544 if (maj_stat != GSS_S_COMPLETE)
545 errx(1, "gss_verify_mic failed: %s",
546 gssapi_err(maj_stat, min_stat, mechoid));
548 gss_release_buffer(&min_stat, &output_token);
554 gss_ctx_id_t ctx = GSS_C_NO_CONTEXT;
555 gss_cred_id_t cred = GSS_C_NO_CREDENTIAL;
556 gss_name_t name = GSS_C_NO_NAME;
557 gss_OID_set oidset = GSS_C_NO_OID_SET;
560 gss_delete_sec_context(&junk, &ctx, NULL);
561 gss_release_cred(&junk, &cred);
562 gss_release_name(&junk, &name);
563 gss_release_oid_set(&junk, &oidset);
570 static struct getargs args[] = {
571 {"name-type",0, arg_string, &type_string, "type of name", NULL },
572 {"mech-type",0, arg_string, &mech_string, "mech type (name)", NULL },
573 {"mech-types",0, arg_string, &mechs_string, "mech types (names)", NULL },
574 {"ret-mech-type",0, arg_string, &ret_mech_string,
575 "type of return mech", NULL },
576 {"dns-canonicalize",0,arg_negative_flag, &dns_canon_flag,
577 "use dns to canonicalize", NULL },
578 {"mutual-auth",0, arg_flag, &mutual_auth_flag,"mutual auth", NULL },
579 {"client-ccache",0, arg_string, &client_ccache, "client credentials cache", NULL },
580 {"client-keytab",0, arg_string, &client_keytab, "client keytab", NULL },
581 {"client-name", 0, arg_string, &client_name, "client name", NULL },
582 {"client-password", 0, arg_string, &client_password, "client password", NULL },
583 {"limit-enctype",0, arg_string, &limit_enctype_string, "enctype", NULL },
584 {"dce-style",0, arg_flag, &dce_style_flag, "dce-style", NULL },
585 {"wrapunwrap",0, arg_flag, &wrapunwrap_flag, "wrap/unwrap", NULL },
586 {"iov", 0, arg_flag, &iov_flag, "wrap/unwrap iov", NULL },
587 {"aead", 0, arg_flag, &aead_flag, "wrap/unwrap aead", NULL },
588 {"getverifymic",0, arg_flag, &getverifymic_flag,
589 "get and verify mic", NULL },
590 {"delegate",0, arg_flag, &deleg_flag, "delegate credential", NULL },
591 {"policy-delegate",0, arg_flag, &policy_deleg_flag, "policy delegate credential", NULL },
592 {"server-no-delegate",0, arg_flag, &server_no_deleg_flag,
593 "server should get a credential", NULL },
594 {"export-import-context",0, arg_flag, &ei_ctx_flag, "test export/import context", NULL },
595 {"export-import-cred",0, arg_flag, &ei_cred_flag, "test export/import cred", NULL },
596 {"gsskrb5-acceptor-identity", 0, arg_string, &gsskrb5_acceptor_identity, "keytab", NULL },
597 {"session-enctype", 0, arg_string, &session_enctype_string, "enctype", NULL },
598 {"client-time-offset", 0, arg_integer, &client_time_offset, "time", NULL },
599 {"server-time-offset", 0, arg_integer, &server_time_offset, "time", NULL },
600 {"max-loops", 0, arg_integer, &max_loops, "time", NULL },
601 {"version", 0, arg_flag, &version_flag, "print version", NULL },
602 {"verbose", 'v', arg_flag, &verbose_flag, "verbose", NULL },
603 {"help", 0, arg_flag, &help_flag, NULL, NULL }
609 arg_printusage (args, sizeof(args)/sizeof(*args),
610 NULL, "service@host");
615 main(int argc, char **argv)
618 OM_uint32 min_stat, maj_stat;
619 gss_ctx_id_t cctx, sctx;
621 gss_OID nameoid, mechoid, actual_mech, actual_mech2;
622 gss_cred_id_t client_cred = GSS_C_NO_CREDENTIAL, deleg_cred = GSS_C_NO_CREDENTIAL;
623 gss_name_t cname = GSS_C_NO_NAME;
624 gss_buffer_desc credential_data = GSS_C_EMPTY_BUFFER;
625 gss_OID_desc oids[6];
626 gss_OID_set_desc mechoid_descs;
627 gss_OID_set mechoids = GSS_C_NO_OID_SET;
628 gss_key_value_element_desc client_cred_elements[2];
629 gss_key_value_set_desc client_cred_store;
631 setprogname(argv[0]);
635 if (krb5_init_context(&context))
636 errx(1, "krb5_init_context");
638 cctx = sctx = GSS_C_NO_CONTEXT;
640 if(getarg(args, sizeof(args) / sizeof(args[0]), argc, argv, &optidx))
657 if (dns_canon_flag != -1)
658 gsskrb5_set_dns_canonicalize(dns_canon_flag);
660 if (type_string == NULL)
661 nameoid = GSS_C_NT_HOSTBASED_SERVICE;
662 else if (strcmp(type_string, "hostbased-service") == 0)
663 nameoid = GSS_C_NT_HOSTBASED_SERVICE;
664 else if (strcmp(type_string, "krb5-principal-name") == 0)
665 nameoid = GSS_KRB5_NT_PRINCIPAL_NAME;
667 errx(1, "%s not supported", type_string);
669 if (mech_string == NULL)
670 mechoid = GSS_KRB5_MECHANISM;
672 mechoid = string_to_oid(mech_string);
674 if (mechs_string == NULL) {
676 * We ought to be able to use the OID set of the one mechanism
677 * OID given. But there's some breakage that conspires to make
678 * that fail though it should succeed:
680 * - the NTLM gss_acquire_cred() refuses to work with
681 * desired_name == GSS_C_NO_NAME
682 * - gss_acquire_cred() with desired_mechs == GSS_C_NO_OID_SET
683 * does work here because we happen to have Kerberos
684 * credentials in check-ntlm, and the subsequent
685 * gss_init_sec_context() call finds no cred element for NTLM
686 * but plows on anyways, surprisingly enough, and then the
687 * NTLM gss_init_sec_context() just works.
689 * In summary, there's some breakage in gss_init_sec_context()
690 * and some breakage in NTLM that conspires against us here.
692 * We work around this in check-ntlm and check-spnego by adding
693 * --client-name=user1@${R} to the invocations of this test
694 * program that require it.
697 mechoid_descs.elements = &oids[0];
698 mechoid_descs.count = 1;
699 mechoids = &mechoid_descs;
701 string_to_oids(&mechoids, &mechoid_descs,
702 oids, sizeof(oids)/sizeof(oids[0]), mechs_string);
705 if (gsskrb5_acceptor_identity) {
706 /* XXX replace this with cred store, but test suites will need work */
707 maj_stat = gsskrb5_register_acceptor_identity(gsskrb5_acceptor_identity);
709 errx(1, "gsskrb5_acceptor_identity: %s",
710 gssapi_err(maj_stat, 0, GSS_C_NO_OID));
713 if (client_password && (client_ccache || client_keytab)) {
714 errx(1, "password option mutually exclusive with ccache or keytab option");
717 if (client_password) {
718 credential_data.value = client_password;
719 credential_data.length = strlen(client_password);
722 client_cred_store.count = 0;
723 client_cred_store.elements = client_cred_elements;
726 client_cred_store.elements[client_cred_store.count].key = "ccache";
727 client_cred_store.elements[client_cred_store.count].value = client_ccache;
729 client_cred_store.count++;
733 client_cred_store.elements[client_cred_store.count].key = "client_keytab";
734 client_cred_store.elements[client_cred_store.count].value = client_keytab;
736 client_cred_store.count++;
742 cn.value = client_name;
743 cn.length = strlen(client_name);
745 maj_stat = gss_import_name(&min_stat, &cn, GSS_C_NT_USER_NAME, &cname);
747 errx(1, "gss_import_name: %s",
748 gssapi_err(maj_stat, min_stat, GSS_C_NO_OID));
751 if (client_password) {
752 maj_stat = gss_acquire_cred_with_password(&min_stat,
761 if (GSS_ERROR(maj_stat)) {
762 if (mechoids != GSS_C_NO_OID_SET && mechoids->count == 1)
763 mechoid = &mechoids->elements[0];
765 mechoid = GSS_C_NO_OID;
766 errx(1, "gss_acquire_cred_with_password: %s",
767 gssapi_err(maj_stat, min_stat, mechoid));
770 maj_stat = gss_acquire_cred_from(&min_stat,
775 client_cred_store.count ? &client_cred_store
776 : GSS_C_NO_CRED_STORE,
780 if (GSS_ERROR(maj_stat))
781 errx(1, "gss_acquire_cred: %s",
782 gssapi_err(maj_stat, min_stat, GSS_C_NO_OID));
785 if (limit_enctype_string) {
788 ret = krb5_string_to_enctype(context,
789 limit_enctype_string,
792 krb5_err(context, 1, ret, "krb5_string_to_enctype");
797 if (client_cred == NULL)
798 errx(1, "client_cred missing");
800 maj_stat = gss_krb5_set_allowable_enctypes(&min_stat, client_cred,
803 errx(1, "gss_krb5_set_allowable_enctypes: %s",
804 gssapi_err(maj_stat, min_stat, GSS_C_NO_OID));
807 loop(mechoid, nameoid, argv[0], client_cred,
808 &sctx, &cctx, &actual_mech, &deleg_cred);
811 printf("resulting mech: %s\n", oid_to_string(actual_mech));
813 if (ret_mech_string) {
816 retoid = string_to_oid(ret_mech_string);
818 if (gss_oid_equal(retoid, actual_mech) == 0)
819 errx(1, "actual_mech mech is not the expected type %s",
823 /* XXX should be actual_mech */
824 if (gss_oid_equal(mechoid, GSS_KRB5_MECHANISM)) {
826 gss_buffer_desc authz_data;
827 gss_buffer_desc in, out1, out2;
828 krb5_keyblock *keyblock, *keyblock2;
832 ret = krb5_timeofday(context, &now);
834 errx(1, "krb5_timeofday failed");
837 maj_stat = gss_krb5_export_lucid_sec_context(&min_stat,
841 if (maj_stat != GSS_S_COMPLETE)
842 errx(1, "gss_krb5_export_lucid_sec_context failed: %s",
843 gssapi_err(maj_stat, min_stat, actual_mech));
846 maj_stat = gss_krb5_free_lucid_sec_context(&maj_stat, ctx);
847 if (maj_stat != GSS_S_COMPLETE)
848 errx(1, "gss_krb5_free_lucid_sec_context failed: %s",
849 gssapi_err(maj_stat, min_stat, actual_mech));
852 maj_stat = gss_krb5_export_lucid_sec_context(&min_stat,
856 if (maj_stat != GSS_S_COMPLETE)
857 errx(1, "gss_krb5_export_lucid_sec_context failed: %s",
858 gssapi_err(maj_stat, min_stat, actual_mech));
859 maj_stat = gss_krb5_free_lucid_sec_context(&min_stat, ctx);
860 if (maj_stat != GSS_S_COMPLETE)
861 errx(1, "gss_krb5_free_lucid_sec_context failed: %s",
862 gssapi_err(maj_stat, min_stat, actual_mech));
864 maj_stat = gsskrb5_extract_authtime_from_sec_context(&min_stat,
867 if (maj_stat != GSS_S_COMPLETE)
868 errx(1, "gsskrb5_extract_authtime_from_sec_context failed: %s",
869 gssapi_err(maj_stat, min_stat, actual_mech));
872 errx(1, "gsskrb5_extract_authtime_from_sec_context failed: "
873 "time authtime is before now: %ld %ld",
874 (long)sc_time, (long)now);
876 maj_stat = gsskrb5_extract_service_keyblock(&min_stat,
879 if (maj_stat != GSS_S_COMPLETE)
880 errx(1, "gsskrb5_export_service_keyblock failed: %s",
881 gssapi_err(maj_stat, min_stat, actual_mech));
883 krb5_free_keyblock(context, keyblock);
885 maj_stat = gsskrb5_get_subkey(&min_stat,
888 if (maj_stat != GSS_S_COMPLETE
889 && (!(maj_stat == GSS_S_FAILURE && min_stat == GSS_KRB5_S_KG_NO_SUBKEY)))
890 errx(1, "gsskrb5_get_subkey server failed: %s",
891 gssapi_err(maj_stat, min_stat, actual_mech));
893 if (maj_stat != GSS_S_COMPLETE)
895 else if (limit_enctype && keyblock->keytype != limit_enctype)
896 errx(1, "gsskrb5_get_subkey wrong enctype");
898 maj_stat = gsskrb5_get_subkey(&min_stat,
901 if (maj_stat != GSS_S_COMPLETE
902 && (!(maj_stat == GSS_S_FAILURE && min_stat == GSS_KRB5_S_KG_NO_SUBKEY)))
903 errx(1, "gsskrb5_get_subkey client failed: %s",
904 gssapi_err(maj_stat, min_stat, actual_mech));
906 if (maj_stat != GSS_S_COMPLETE)
908 else if (limit_enctype && keyblock->keytype != limit_enctype)
909 errx(1, "gsskrb5_get_subkey wrong enctype");
911 if (keyblock || keyblock2) {
912 if (keyblock == NULL)
913 errx(1, "server missing token keyblock");
914 if (keyblock2 == NULL)
915 errx(1, "client missing token keyblock");
917 if (keyblock->keytype != keyblock2->keytype)
918 errx(1, "enctype mismatch");
919 if (keyblock->keyvalue.length != keyblock2->keyvalue.length)
920 errx(1, "key length mismatch");
921 if (memcmp(keyblock->keyvalue.data, keyblock2->keyvalue.data,
922 keyblock2->keyvalue.length) != 0)
923 errx(1, "key data mismatch");
926 if (session_enctype_string) {
927 krb5_enctype enctype;
929 ret = krb5_string_to_enctype(context,
930 session_enctype_string,
934 krb5_err(context, 1, ret, "krb5_string_to_enctype");
936 if (enctype != keyblock->keytype)
937 errx(1, "keytype is not the expected %d != %d",
938 (int)enctype, (int)keyblock2->keytype);
942 krb5_free_keyblock(context, keyblock);
944 krb5_free_keyblock(context, keyblock2);
946 maj_stat = gsskrb5_get_initiator_subkey(&min_stat,
949 if (maj_stat != GSS_S_COMPLETE
950 && (!(maj_stat == GSS_S_FAILURE && min_stat == GSS_KRB5_S_KG_NO_SUBKEY)))
951 errx(1, "gsskrb5_get_initiator_subkey failed: %s",
952 gssapi_err(maj_stat, min_stat, actual_mech));
954 if (maj_stat == GSS_S_COMPLETE) {
956 if (limit_enctype && keyblock->keytype != limit_enctype)
957 errx(1, "gsskrb5_get_initiator_subkey wrong enctype");
958 krb5_free_keyblock(context, keyblock);
961 maj_stat = gsskrb5_extract_authz_data_from_sec_context(&min_stat,
965 if (maj_stat == GSS_S_COMPLETE)
966 gss_release_buffer(&min_stat, &authz_data);
969 memset(&out1, 0, sizeof(out1));
970 memset(&out2, 0, sizeof(out2));
975 gss_pseudo_random(&min_stat, sctx, GSS_C_PRF_KEY_FULL, &in,
977 gss_pseudo_random(&min_stat, cctx, GSS_C_PRF_KEY_FULL, &in,
980 if (out1.length != out2.length)
981 errx(1, "prf len mismatch");
982 if (memcmp(out1.value, out2.value, out1.length) != 0)
983 errx(1, "prf data mismatch");
985 gss_release_buffer(&min_stat, &out1);
987 gss_pseudo_random(&min_stat, sctx, GSS_C_PRF_KEY_FULL, &in,
990 if (out1.length != out2.length)
991 errx(1, "prf len mismatch");
992 if (memcmp(out1.value, out2.value, out1.length) != 0)
993 errx(1, "prf data mismatch");
995 gss_release_buffer(&min_stat, &out1);
996 gss_release_buffer(&min_stat, &out2);
1001 gss_pseudo_random(&min_stat, sctx, GSS_C_PRF_KEY_PARTIAL, &in,
1003 gss_pseudo_random(&min_stat, cctx, GSS_C_PRF_KEY_PARTIAL, &in,
1006 if (out1.length != out2.length)
1007 errx(1, "prf len mismatch");
1008 if (memcmp(out1.value, out2.value, out1.length) != 0)
1009 errx(1, "prf data mismatch");
1011 gss_release_buffer(&min_stat, &out1);
1012 gss_release_buffer(&min_stat, &out2);
1014 wrapunwrap_flag = 1;
1015 getverifymic_flag = 1;
1019 gss_buffer_desc ctx_token = GSS_C_EMPTY_BUFFER;
1021 maj_stat = gss_export_sec_context(&min_stat, &cctx, &ctx_token);
1022 if (maj_stat != GSS_S_COMPLETE)
1023 errx(1, "export client context failed: %s",
1024 gssapi_err(maj_stat, min_stat, NULL));
1026 if (cctx != GSS_C_NO_CONTEXT)
1027 errx(1, "export client context did not release it");
1029 maj_stat = gss_import_sec_context(&min_stat, &ctx_token, &cctx);
1030 if (maj_stat != GSS_S_COMPLETE)
1031 errx(1, "import client context failed: %s",
1032 gssapi_err(maj_stat, min_stat, NULL));
1034 gss_release_buffer(&min_stat, &ctx_token);
1036 maj_stat = gss_export_sec_context(&min_stat, &sctx, &ctx_token);
1037 if (maj_stat != GSS_S_COMPLETE)
1038 errx(1, "export server context failed: %s",
1039 gssapi_err(maj_stat, min_stat, NULL));
1041 if (sctx != GSS_C_NO_CONTEXT)
1042 errx(1, "export server context did not release it");
1044 maj_stat = gss_import_sec_context(&min_stat, &ctx_token, &sctx);
1045 if (maj_stat != GSS_S_COMPLETE)
1046 errx(1, "import server context failed: %s",
1047 gssapi_err(maj_stat, min_stat, NULL));
1049 gss_release_buffer(&min_stat, &ctx_token);
1052 if (wrapunwrap_flag) {
1053 wrapunwrap(cctx, sctx, 0, actual_mech);
1054 wrapunwrap(cctx, sctx, 1, actual_mech);
1055 wrapunwrap(sctx, cctx, 0, actual_mech);
1056 wrapunwrap(sctx, cctx, 1, actual_mech);
1060 wrapunwrap_iov(cctx, sctx, 0, actual_mech);
1061 wrapunwrap_iov(cctx, sctx, USE_HEADER_ONLY|FORCE_IOV, actual_mech);
1062 wrapunwrap_iov(cctx, sctx, USE_HEADER_ONLY, actual_mech);
1063 wrapunwrap_iov(cctx, sctx, USE_CONF, actual_mech);
1064 wrapunwrap_iov(cctx, sctx, USE_CONF|USE_HEADER_ONLY, actual_mech);
1066 wrapunwrap_iov(cctx, sctx, FORCE_IOV, actual_mech);
1067 wrapunwrap_iov(cctx, sctx, USE_CONF|FORCE_IOV, actual_mech);
1068 wrapunwrap_iov(cctx, sctx, USE_HEADER_ONLY|FORCE_IOV, actual_mech);
1069 wrapunwrap_iov(cctx, sctx, USE_CONF|USE_HEADER_ONLY|FORCE_IOV, actual_mech);
1071 wrapunwrap_iov(cctx, sctx, USE_SIGN_ONLY|FORCE_IOV, actual_mech);
1072 wrapunwrap_iov(cctx, sctx, USE_CONF|USE_SIGN_ONLY|FORCE_IOV, actual_mech);
1073 wrapunwrap_iov(cctx, sctx, USE_CONF|USE_HEADER_ONLY|USE_SIGN_ONLY|FORCE_IOV, actual_mech);
1076 wrapunwrap_iov(cctx, sctx, 0, actual_mech);
1077 wrapunwrap_iov(cctx, sctx, FORCE_IOV, actual_mech);
1079 wrapunwrap_iov(cctx, sctx, USE_CONF, actual_mech);
1080 wrapunwrap_iov(cctx, sctx, USE_CONF|FORCE_IOV, actual_mech);
1082 wrapunwrap_iov(cctx, sctx, USE_SIGN_ONLY, actual_mech);
1083 wrapunwrap_iov(cctx, sctx, USE_SIGN_ONLY|FORCE_IOV, actual_mech);
1085 wrapunwrap_iov(cctx, sctx, USE_CONF|USE_SIGN_ONLY, actual_mech);
1086 wrapunwrap_iov(cctx, sctx, USE_CONF|USE_SIGN_ONLY|FORCE_IOV, actual_mech);
1088 wrapunwrap_iov(cctx, sctx, USE_HEADER_ONLY, actual_mech);
1089 wrapunwrap_iov(cctx, sctx, USE_HEADER_ONLY|FORCE_IOV, actual_mech);
1091 wrapunwrap_iov(cctx, sctx, USE_CONF|USE_HEADER_ONLY, actual_mech);
1092 wrapunwrap_iov(cctx, sctx, USE_CONF|USE_HEADER_ONLY|FORCE_IOV, actual_mech);
1094 wrapunwrap_iov(cctx, sctx, NO_DATA, actual_mech);
1095 wrapunwrap_iov(cctx, sctx, NO_DATA|USE_HEADER_ONLY|FORCE_IOV, actual_mech);
1096 wrapunwrap_iov(cctx, sctx, NO_DATA|USE_HEADER_ONLY, actual_mech);
1097 wrapunwrap_iov(cctx, sctx, NO_DATA|USE_CONF, actual_mech);
1098 wrapunwrap_iov(cctx, sctx, NO_DATA|USE_CONF|USE_HEADER_ONLY, actual_mech);
1100 wrapunwrap_iov(cctx, sctx, NO_DATA|FORCE_IOV, actual_mech);
1101 wrapunwrap_iov(cctx, sctx, NO_DATA|USE_CONF|FORCE_IOV, actual_mech);
1102 wrapunwrap_iov(cctx, sctx, NO_DATA|USE_HEADER_ONLY|FORCE_IOV, actual_mech);
1103 wrapunwrap_iov(cctx, sctx, NO_DATA|USE_CONF|USE_HEADER_ONLY|FORCE_IOV, actual_mech);
1105 wrapunwrap_iov(cctx, sctx, NO_DATA|USE_SIGN_ONLY|FORCE_IOV, actual_mech);
1106 wrapunwrap_iov(cctx, sctx, NO_DATA|USE_CONF|USE_SIGN_ONLY|FORCE_IOV, actual_mech);
1107 wrapunwrap_iov(cctx, sctx, NO_DATA|USE_CONF|USE_HEADER_ONLY|USE_SIGN_ONLY|FORCE_IOV, actual_mech);
1110 wrapunwrap_iov(cctx, sctx, NO_DATA, actual_mech);
1111 wrapunwrap_iov(cctx, sctx, NO_DATA|FORCE_IOV, actual_mech);
1113 wrapunwrap_iov(cctx, sctx, NO_DATA|USE_CONF, actual_mech);
1114 wrapunwrap_iov(cctx, sctx, NO_DATA|USE_CONF|FORCE_IOV, actual_mech);
1116 wrapunwrap_iov(cctx, sctx, NO_DATA|USE_SIGN_ONLY, actual_mech);
1117 wrapunwrap_iov(cctx, sctx, NO_DATA|USE_SIGN_ONLY|FORCE_IOV, actual_mech);
1119 wrapunwrap_iov(cctx, sctx, NO_DATA|USE_CONF|USE_SIGN_ONLY, actual_mech);
1120 wrapunwrap_iov(cctx, sctx, NO_DATA|USE_CONF|USE_SIGN_ONLY|FORCE_IOV, actual_mech);
1122 wrapunwrap_iov(cctx, sctx, NO_DATA|USE_HEADER_ONLY, actual_mech);
1123 wrapunwrap_iov(cctx, sctx, NO_DATA|USE_HEADER_ONLY|FORCE_IOV, actual_mech);
1125 wrapunwrap_iov(cctx, sctx, NO_DATA|USE_CONF|USE_HEADER_ONLY, actual_mech);
1126 wrapunwrap_iov(cctx, sctx, NO_DATA|USE_CONF|USE_HEADER_ONLY|FORCE_IOV, actual_mech);
1130 wrapunwrap_aead(cctx, sctx, 0, actual_mech);
1131 wrapunwrap_aead(cctx, sctx, USE_CONF, actual_mech);
1133 wrapunwrap_aead(cctx, sctx, FORCE_IOV, actual_mech);
1134 wrapunwrap_aead(cctx, sctx, USE_CONF|FORCE_IOV, actual_mech);
1136 wrapunwrap_aead(cctx, sctx, USE_SIGN_ONLY|FORCE_IOV, actual_mech);
1137 wrapunwrap_aead(cctx, sctx, USE_CONF|USE_SIGN_ONLY|FORCE_IOV, actual_mech);
1139 wrapunwrap_aead(cctx, sctx, 0, actual_mech);
1140 wrapunwrap_aead(cctx, sctx, FORCE_IOV, actual_mech);
1142 wrapunwrap_aead(cctx, sctx, USE_CONF, actual_mech);
1143 wrapunwrap_aead(cctx, sctx, USE_CONF|FORCE_IOV, actual_mech);
1145 wrapunwrap_aead(cctx, sctx, USE_SIGN_ONLY, actual_mech);
1146 wrapunwrap_aead(cctx, sctx, USE_SIGN_ONLY|FORCE_IOV, actual_mech);
1148 wrapunwrap_aead(cctx, sctx, USE_CONF|USE_SIGN_ONLY, actual_mech);
1149 wrapunwrap_aead(cctx, sctx, USE_CONF|USE_SIGN_ONLY|FORCE_IOV, actual_mech);
1152 if (getverifymic_flag) {
1153 getverifymic(cctx, sctx, actual_mech);
1154 getverifymic(cctx, sctx, actual_mech);
1155 getverifymic(sctx, cctx, actual_mech);
1156 getverifymic(sctx, cctx, actual_mech);
1159 gss_delete_sec_context(&min_stat, &cctx, NULL);
1160 gss_delete_sec_context(&min_stat, &sctx, NULL);
1162 if (deleg_cred != GSS_C_NO_CREDENTIAL) {
1163 gss_cred_id_t cred2 = GSS_C_NO_CREDENTIAL;
1167 printf("checking actual mech (%s) on delegated cred\n",
1168 oid_to_string(actual_mech));
1169 loop(actual_mech, nameoid, argv[0], deleg_cred, &sctx, &cctx, &actual_mech2, &cred2);
1171 gss_delete_sec_context(&min_stat, &cctx, NULL);
1172 gss_delete_sec_context(&min_stat, &sctx, NULL);
1174 gss_release_cred(&min_stat, &cred2);
1178 * XXX We can't do this. Delegated credentials only work with
1179 * the actual_mech. We could gss_store_cred the delegated
1180 * credentials *then* gss_add/acquire_cred() with SPNEGO, then
1181 * we could try loop() with those credentials.
1183 /* try again using SPNEGO */
1185 printf("checking spnego on delegated cred\n");
1186 loop(GSS_SPNEGO_MECHANISM, nameoid, argv[0], deleg_cred, &sctx, &cctx,
1187 &actual_mech2, &cred2);
1189 gss_delete_sec_context(&min_stat, &cctx, NULL);
1190 gss_delete_sec_context(&min_stat, &sctx, NULL);
1192 gss_release_cred(&min_stat, &cred2);
1195 /* check export/import */
1198 maj_stat = gss_export_cred(&min_stat, deleg_cred, &cb);
1199 if (maj_stat != GSS_S_COMPLETE)
1200 errx(1, "export cred failed: %s",
1201 gssapi_err(maj_stat, min_stat, NULL));
1203 maj_stat = gss_import_cred(&min_stat, &cb, &cred2);
1204 if (maj_stat != GSS_S_COMPLETE)
1205 errx(1, "import cred failed: %s",
1206 gssapi_err(maj_stat, min_stat, NULL));
1208 gss_release_buffer(&min_stat, &cb);
1209 gss_release_cred(&min_stat, &deleg_cred);
1212 printf("checking actual mech (%s) on export/imported cred\n",
1213 oid_to_string(actual_mech));
1214 loop(actual_mech, nameoid, argv[0], cred2, &sctx, &cctx,
1215 &actual_mech2, &deleg_cred);
1217 gss_release_cred(&min_stat, &deleg_cred);
1219 gss_delete_sec_context(&min_stat, &cctx, NULL);
1220 gss_delete_sec_context(&min_stat, &sctx, NULL);
1224 /* try again using SPNEGO */
1226 printf("checking SPNEGO on export/imported cred\n");
1227 loop(GSS_SPNEGO_MECHANISM, nameoid, argv[0], cred2, &sctx, &cctx,
1228 &actual_mech2, &deleg_cred);
1230 gss_release_cred(&min_stat, &deleg_cred);
1232 gss_delete_sec_context(&min_stat, &cctx, NULL);
1233 gss_delete_sec_context(&min_stat, &sctx, NULL);
1236 gss_release_cred(&min_stat, &cred2);
1239 gss_release_cred(&min_stat, &deleg_cred);
1246 krb5_free_context(context);