Workaround bugs exposed by test_context changes
[heimdal.git] / lib / gssapi / test_context.c
blobd40f976e2592996b1c4f36441df1ee63e5827ae8
1 /*
2 * Copyright (c) 2006 - 2008 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
4 * All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
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"
35 #include <err.h>
36 #include <getarg.h>
37 #include <gssapi.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 getverifymic_flag = 0;
55 static int deleg_flag = 0;
56 static int policy_deleg_flag = 0;
57 static int server_no_deleg_flag = 0;
58 static int ei_flag = 0;
59 static char *gsskrb5_acceptor_identity = NULL;
60 static char *session_enctype_string = NULL;
61 static int client_time_offset = 0;
62 static int server_time_offset = 0;
63 static int max_loops = 0;
64 static char *limit_enctype_string = NULL;
65 static int version_flag = 0;
66 static int verbose_flag = 0;
67 static int help_flag = 0;
69 static krb5_context context;
70 static krb5_enctype limit_enctype = 0;
72 static struct {
73 const char *name;
74 gss_OID oid;
75 } o2n[] = {
76 { "krb5", NULL /* GSS_KRB5_MECHANISM */ },
77 { "spnego", NULL /* GSS_SPNEGO_MECHANISM */ },
78 { "ntlm", NULL /* GSS_NTLM_MECHANISM */ },
79 { "sasl-digest-md5", NULL /* GSS_SASL_DIGEST_MD5_MECHANISM */ }
82 static void
83 init_o2n(void)
85 o2n[0].oid = GSS_KRB5_MECHANISM;
86 o2n[1].oid = GSS_SPNEGO_MECHANISM;
87 o2n[2].oid = GSS_NTLM_MECHANISM;
88 o2n[3].oid = GSS_SASL_DIGEST_MD5_MECHANISM;
91 static gss_OID
92 string_to_oid(const char *name)
94 size_t i;
95 for (i = 0; i < sizeof(o2n)/sizeof(o2n[0]); i++)
96 if (strcasecmp(name, o2n[i].name) == 0)
97 return o2n[i].oid;
98 errx(1, "name '%s' not unknown", name);
101 static void
102 string_to_oids(gss_OID_set *oidsetp, gss_OID_set oidset,
103 gss_OID_desc *oidarray, size_t oidarray_len,
104 char *names)
106 char *name;
107 char *s;
109 if (names[0] == '\0') {
110 *oidsetp = GSS_C_NO_OID_SET;
111 return;
114 oidset->elements = &oidarray[0];
115 if (strcasecmp(names, "all") == 0) {
116 if (sizeof(o2n)/sizeof(o2n[0]) > oidarray_len)
117 errx(1, "internal error: oidarray must be enlarged");
118 for (oidset->count = 0; oidset->count < oidarray_len; oidset->count++)
119 oidset->elements[oidset->count] = *o2n[oidset->count].oid;
120 } else {
121 for (oidset->count = 0, name = strtok_r(names, ", ", &s);
122 name != NULL;
123 oidset->count++, name = strtok_r(NULL, ", ", &s)) {
124 if (oidset->count >= oidarray_len)
125 errx(1, "too many mech names given");
126 oidset->elements[oidset->count] = *string_to_oid(name);
128 oidset->count = oidset->count;
130 *oidsetp = oidset;
133 static const char *
134 oid_to_string(const gss_OID oid)
136 size_t i;
137 for (i = 0; i < sizeof(o2n)/sizeof(o2n[0]); i++)
138 if (gss_oid_equal(oid, o2n[i].oid))
139 return o2n[i].name;
140 return "unknown oid";
143 static void
144 loop(gss_OID mechoid,
145 gss_OID nameoid, const char *target,
146 gss_cred_id_t init_cred,
147 gss_ctx_id_t *sctx, gss_ctx_id_t *cctx,
148 gss_OID *actual_mech,
149 gss_cred_id_t *deleg_cred)
151 int server_done = 0, client_done = 0;
152 int num_loops = 0;
153 OM_uint32 maj_stat, min_stat;
154 gss_name_t gss_target_name;
155 gss_buffer_desc input_token, output_token;
156 OM_uint32 flags = 0, ret_cflags, ret_sflags;
157 gss_OID actual_mech_client;
158 gss_OID actual_mech_server;
160 *actual_mech = GSS_C_NO_OID;
162 flags |= GSS_C_INTEG_FLAG;
163 flags |= GSS_C_CONF_FLAG;
165 if (mutual_auth_flag)
166 flags |= GSS_C_MUTUAL_FLAG;
167 if (dce_style_flag)
168 flags |= GSS_C_DCE_STYLE;
169 if (deleg_flag)
170 flags |= GSS_C_DELEG_FLAG;
171 if (policy_deleg_flag)
172 flags |= GSS_C_DELEG_POLICY_FLAG;
174 input_token.value = rk_UNCONST(target);
175 input_token.length = strlen(target);
177 maj_stat = gss_import_name(&min_stat,
178 &input_token,
179 nameoid,
180 &gss_target_name);
181 if (GSS_ERROR(maj_stat))
182 err(1, "import name creds failed with: %d", maj_stat);
184 input_token.length = 0;
185 input_token.value = NULL;
187 while (!server_done || !client_done) {
188 num_loops++;
190 gsskrb5_set_time_offset(client_time_offset);
192 maj_stat = gss_init_sec_context(&min_stat,
193 init_cred,
194 cctx,
195 gss_target_name,
196 mechoid,
197 flags,
199 NULL,
200 &input_token,
201 &actual_mech_client,
202 &output_token,
203 &ret_cflags,
204 NULL);
205 if (GSS_ERROR(maj_stat))
206 errx(1, "init_sec_context: %s",
207 gssapi_err(maj_stat, min_stat, mechoid));
208 if (maj_stat & GSS_S_CONTINUE_NEEDED)
210 else
211 client_done = 1;
213 gsskrb5_get_time_offset(&client_time_offset);
215 if (client_done && server_done)
216 break;
218 if (input_token.length != 0)
219 gss_release_buffer(&min_stat, &input_token);
221 gsskrb5_set_time_offset(server_time_offset);
223 maj_stat = gss_accept_sec_context(&min_stat,
224 sctx,
225 GSS_C_NO_CREDENTIAL,
226 &output_token,
227 GSS_C_NO_CHANNEL_BINDINGS,
228 NULL,
229 &actual_mech_server,
230 &input_token,
231 &ret_sflags,
232 NULL,
233 deleg_cred);
234 if (GSS_ERROR(maj_stat))
235 errx(1, "accept_sec_context: %s",
236 gssapi_err(maj_stat, min_stat, actual_mech_server));
238 gsskrb5_get_time_offset(&server_time_offset);
240 if (output_token.length != 0)
241 gss_release_buffer(&min_stat, &output_token);
243 if (maj_stat & GSS_S_CONTINUE_NEEDED)
245 else
246 server_done = 1;
248 if (output_token.length != 0)
249 gss_release_buffer(&min_stat, &output_token);
250 if (input_token.length != 0)
251 gss_release_buffer(&min_stat, &input_token);
252 gss_release_name(&min_stat, &gss_target_name);
254 if (deleg_flag || policy_deleg_flag) {
255 if (server_no_deleg_flag) {
256 if (*deleg_cred != GSS_C_NO_CREDENTIAL)
257 errx(1, "got delegated cred but didn't expect one");
258 } else if (*deleg_cred == GSS_C_NO_CREDENTIAL)
259 errx(1, "asked for delegarated cred but did get one");
260 } else if (*deleg_cred != GSS_C_NO_CREDENTIAL)
261 errx(1, "got deleg_cred cred but didn't ask");
263 if (gss_oid_equal(actual_mech_server, actual_mech_client) == 0)
264 errx(1, "mech mismatch");
265 *actual_mech = actual_mech_server;
267 if (max_loops && num_loops > max_loops)
268 errx(1, "num loops %d was lager then max loops %d",
269 num_loops, max_loops);
271 if (verbose_flag) {
272 printf("server time offset: %d\n", server_time_offset);
273 printf("client time offset: %d\n", client_time_offset);
274 printf("num loops %d\n", num_loops);
278 static void
279 wrapunwrap(gss_ctx_id_t cctx, gss_ctx_id_t sctx, int flags, gss_OID mechoid)
281 gss_buffer_desc input_token, output_token, output_token2;
282 OM_uint32 min_stat, maj_stat;
283 gss_qop_t qop_state;
284 int conf_state;
286 input_token.value = "foo";
287 input_token.length = 3;
289 maj_stat = gss_wrap(&min_stat, cctx, flags, 0, &input_token,
290 &conf_state, &output_token);
291 if (maj_stat != GSS_S_COMPLETE)
292 errx(1, "gss_wrap failed: %s",
293 gssapi_err(maj_stat, min_stat, mechoid));
295 maj_stat = gss_unwrap(&min_stat, sctx, &output_token,
296 &output_token2, &conf_state, &qop_state);
297 if (maj_stat != GSS_S_COMPLETE)
298 errx(1, "gss_unwrap failed: %s",
299 gssapi_err(maj_stat, min_stat, mechoid));
301 gss_release_buffer(&min_stat, &output_token);
302 gss_release_buffer(&min_stat, &output_token2);
304 #if 0 /* doesn't work for NTLM yet */
305 if (!!conf_state != !!flags)
306 errx(1, "conf_state mismatch");
307 #endif
310 #define USE_CONF 1
311 #define USE_HEADER_ONLY 2
312 #define USE_SIGN_ONLY 4
313 #define FORCE_IOV 8
315 static void
316 wrapunwrap_iov(gss_ctx_id_t cctx, gss_ctx_id_t sctx, int flags, gss_OID mechoid)
318 krb5_data token, header, trailer;
319 OM_uint32 min_stat, maj_stat;
320 gss_qop_t qop_state;
321 int conf_state, conf_state2;
322 gss_iov_buffer_desc iov[6];
323 unsigned char *p;
324 int iov_len;
325 char header_data[9] = "ABCheader";
326 char trailer_data[10] = "trailerXYZ";
328 char token_data[16] = "0123456789abcdef";
330 memset(&iov, 0, sizeof(iov));
332 if (flags & USE_SIGN_ONLY) {
333 header.data = header_data;
334 header.length = 9;
335 trailer.data = trailer_data;
336 trailer.length = 10;
337 } else {
338 header.data = NULL;
339 header.length = 0;
340 trailer.data = NULL;
341 trailer.length = 0;
344 token.data = token_data;
345 token.length = 16;
347 iov_len = sizeof(iov)/sizeof(iov[0]);
349 memset(iov, 0, sizeof(iov));
351 iov[0].type = GSS_IOV_BUFFER_TYPE_HEADER | GSS_IOV_BUFFER_TYPE_FLAG_ALLOCATE;
353 if (header.length != 0) {
354 iov[1].type = GSS_IOV_BUFFER_TYPE_SIGN_ONLY;
355 iov[1].buffer.length = header.length;
356 iov[1].buffer.value = header.data;
357 } else {
358 iov[1].type = GSS_IOV_BUFFER_TYPE_EMPTY;
359 iov[1].buffer.length = 0;
360 iov[1].buffer.value = NULL;
362 iov[2].type = GSS_IOV_BUFFER_TYPE_DATA;
363 iov[2].buffer.length = token.length;
364 iov[2].buffer.value = token.data;
365 if (trailer.length != 0) {
366 iov[3].type = GSS_IOV_BUFFER_TYPE_SIGN_ONLY;
367 iov[3].buffer.length = trailer.length;
368 iov[3].buffer.value = trailer.data;
369 } else {
370 iov[3].type = GSS_IOV_BUFFER_TYPE_EMPTY;
371 iov[3].buffer.length = 0;
372 iov[3].buffer.value = NULL;
374 if (dce_style_flag) {
375 iov[4].type = GSS_IOV_BUFFER_TYPE_EMPTY;
376 } else {
377 iov[4].type = GSS_IOV_BUFFER_TYPE_PADDING | GSS_IOV_BUFFER_TYPE_FLAG_ALLOCATE;
379 iov[4].buffer.length = 0;
380 iov[4].buffer.value = 0;
381 if (dce_style_flag) {
382 iov[5].type = GSS_IOV_BUFFER_TYPE_EMPTY;
383 } else if (flags & USE_HEADER_ONLY) {
384 iov[5].type = GSS_IOV_BUFFER_TYPE_EMPTY;
385 } else {
386 iov[5].type = GSS_IOV_BUFFER_TYPE_TRAILER | GSS_IOV_BUFFER_TYPE_FLAG_ALLOCATE;
388 iov[5].buffer.length = 0;
389 iov[5].buffer.value = 0;
391 maj_stat = gss_wrap_iov(&min_stat, cctx, dce_style_flag || flags & USE_CONF, 0, &conf_state,
392 iov, iov_len);
393 if (maj_stat != GSS_S_COMPLETE)
394 errx(1, "gss_wrap_iov failed");
396 token.length =
397 iov[0].buffer.length +
398 iov[1].buffer.length +
399 iov[2].buffer.length +
400 iov[3].buffer.length +
401 iov[4].buffer.length +
402 iov[5].buffer.length;
403 token.data = emalloc(token.length);
405 p = token.data;
406 memcpy(p, iov[0].buffer.value, iov[0].buffer.length);
407 p += iov[0].buffer.length;
408 memcpy(p, iov[1].buffer.value, iov[1].buffer.length);
409 p += iov[1].buffer.length;
410 memcpy(p, iov[2].buffer.value, iov[2].buffer.length);
411 p += iov[2].buffer.length;
412 memcpy(p, iov[3].buffer.value, iov[3].buffer.length);
413 p += iov[3].buffer.length;
414 memcpy(p, iov[4].buffer.value, iov[4].buffer.length);
415 p += iov[4].buffer.length;
416 memcpy(p, iov[5].buffer.value, iov[5].buffer.length);
417 p += iov[5].buffer.length;
419 assert(p - ((unsigned char *)token.data) == token.length);
421 if ((flags & (USE_SIGN_ONLY|FORCE_IOV)) == 0) {
422 gss_buffer_desc input, output;
424 input.value = token.data;
425 input.length = token.length;
427 maj_stat = gss_unwrap(&min_stat, sctx, &input,
428 &output, &conf_state2, &qop_state);
430 if (maj_stat != GSS_S_COMPLETE)
431 errx(1, "gss_unwrap from gss_wrap_iov failed: %s",
432 gssapi_err(maj_stat, min_stat, mechoid));
434 gss_release_buffer(&min_stat, &output);
435 } else {
436 maj_stat = gss_unwrap_iov(&min_stat, sctx, &conf_state2, &qop_state,
437 iov, iov_len);
439 if (maj_stat != GSS_S_COMPLETE)
440 errx(1, "gss_unwrap_iov failed: %x %s", flags,
441 gssapi_err(maj_stat, min_stat, mechoid));
444 if (conf_state2 != conf_state)
445 errx(1, "conf state wrong for iov: %x", flags);
448 free(token.data);
451 static void
452 getverifymic(gss_ctx_id_t cctx, gss_ctx_id_t sctx, gss_OID mechoid)
454 gss_buffer_desc input_token, output_token;
455 OM_uint32 min_stat, maj_stat;
456 gss_qop_t qop_state;
458 input_token.value = "bar";
459 input_token.length = 3;
461 maj_stat = gss_get_mic(&min_stat, cctx, 0, &input_token,
462 &output_token);
463 if (maj_stat != GSS_S_COMPLETE)
464 errx(1, "gss_get_mic failed: %s",
465 gssapi_err(maj_stat, min_stat, mechoid));
467 maj_stat = gss_verify_mic(&min_stat, sctx, &input_token,
468 &output_token, &qop_state);
469 if (maj_stat != GSS_S_COMPLETE)
470 errx(1, "gss_verify_mic failed: %s",
471 gssapi_err(maj_stat, min_stat, mechoid));
473 gss_release_buffer(&min_stat, &output_token);
476 static void
477 empty_release(void)
479 gss_ctx_id_t ctx = GSS_C_NO_CONTEXT;
480 gss_cred_id_t cred = GSS_C_NO_CREDENTIAL;
481 gss_name_t name = GSS_C_NO_NAME;
482 gss_OID_set oidset = GSS_C_NO_OID_SET;
483 OM_uint32 junk;
485 gss_delete_sec_context(&junk, &ctx, NULL);
486 gss_release_cred(&junk, &cred);
487 gss_release_name(&junk, &name);
488 gss_release_oid_set(&junk, &oidset);
495 static struct getargs args[] = {
496 {"name-type",0, arg_string, &type_string, "type of name", NULL },
497 {"mech-type",0, arg_string, &mech_string, "mech type (name)", NULL },
498 {"mech-types",0, arg_string, &mechs_string, "mech types (names)", NULL },
499 {"ret-mech-type",0, arg_string, &ret_mech_string,
500 "type of return mech", NULL },
501 {"dns-canonicalize",0,arg_negative_flag, &dns_canon_flag,
502 "use dns to canonicalize", NULL },
503 {"mutual-auth",0, arg_flag, &mutual_auth_flag,"mutual auth", NULL },
504 {"client-name", 0, arg_string, &client_name, "client name", NULL },
505 {"client-password", 0, arg_string, &client_password, "client password", NULL },
506 {"limit-enctype",0, arg_string, &limit_enctype_string, "enctype", NULL },
507 {"dce-style",0, arg_flag, &dce_style_flag, "dce-style", NULL },
508 {"wrapunwrap",0, arg_flag, &wrapunwrap_flag, "wrap/unwrap", NULL },
509 {"iov", 0, arg_flag, &iov_flag, "wrap/unwrap iov", NULL },
510 {"getverifymic",0, arg_flag, &getverifymic_flag,
511 "get and verify mic", NULL },
512 {"delegate",0, arg_flag, &deleg_flag, "delegate credential", NULL },
513 {"policy-delegate",0, arg_flag, &policy_deleg_flag, "policy delegate credential", NULL },
514 {"server-no-delegate",0, arg_flag, &server_no_deleg_flag,
515 "server should get a credential", NULL },
516 {"export-import-cred",0, arg_flag, &ei_flag, "test export/import cred", NULL },
517 {"gsskrb5-acceptor-identity", 0, arg_string, &gsskrb5_acceptor_identity, "keytab", NULL },
518 {"session-enctype", 0, arg_string, &session_enctype_string, "enctype", NULL },
519 {"client-time-offset", 0, arg_integer, &client_time_offset, "time", NULL },
520 {"server-time-offset", 0, arg_integer, &server_time_offset, "time", NULL },
521 {"max-loops", 0, arg_integer, &max_loops, "time", NULL },
522 {"version", 0, arg_flag, &version_flag, "print version", NULL },
523 {"verbose", 'v', arg_flag, &verbose_flag, "verbose", NULL },
524 {"help", 0, arg_flag, &help_flag, NULL, NULL }
527 static void
528 usage (int ret)
530 arg_printusage (args, sizeof(args)/sizeof(*args),
531 NULL, "service@host");
532 exit (ret);
536 main(int argc, char **argv)
538 int optidx = 0;
539 OM_uint32 min_stat, maj_stat;
540 gss_ctx_id_t cctx, sctx;
541 void *ctx;
542 gss_OID nameoid, mechoid, actual_mech, actual_mech2;
543 gss_cred_id_t client_cred = GSS_C_NO_CREDENTIAL, deleg_cred = GSS_C_NO_CREDENTIAL;
544 gss_name_t cname = GSS_C_NO_NAME;
545 gss_buffer_desc credential_data = GSS_C_EMPTY_BUFFER;
546 gss_OID_desc oids[4];
547 gss_OID_set_desc mechoid_descs;
548 gss_OID_set mechoids = GSS_C_NO_OID_SET;
550 setprogname(argv[0]);
552 init_o2n();
554 if (krb5_init_context(&context))
555 errx(1, "krb5_init_context");
557 cctx = sctx = GSS_C_NO_CONTEXT;
559 if(getarg(args, sizeof(args) / sizeof(args[0]), argc, argv, &optidx))
560 usage(1);
562 if (help_flag)
563 usage (0);
565 if(version_flag){
566 print_version(NULL);
567 exit(0);
570 argc -= optidx;
571 argv += optidx;
573 if (argc != 1)
574 usage(1);
576 if (dns_canon_flag != -1)
577 gsskrb5_set_dns_canonicalize(dns_canon_flag);
579 if (type_string == NULL)
580 nameoid = GSS_C_NT_HOSTBASED_SERVICE;
581 else if (strcmp(type_string, "hostbased-service") == 0)
582 nameoid = GSS_C_NT_HOSTBASED_SERVICE;
583 else if (strcmp(type_string, "krb5-principal-name") == 0)
584 nameoid = GSS_KRB5_NT_PRINCIPAL_NAME;
585 else
586 errx(1, "%s not supported", type_string);
588 if (mech_string == NULL)
589 mechoid = GSS_KRB5_MECHANISM;
590 else
591 mechoid = string_to_oid(mech_string);
593 if (mechs_string == NULL) {
595 * We ought to be able to use the OID set of the one mechanism
596 * OID given. But there's some breakage that conspires to make
597 * that fail though it should succeed:
599 * - the NTLM gss_acquire_cred() refuses to work with
600 * desired_name == GSS_C_NO_NAME
601 * - the NTLM gss_import_name() also fails, so that merely
602 * adding --client-name to this program's invocation doesn't
603 * work around that
604 * - gss_acquire_cred() with desired_mechs == GSS_C_NO_OID_SET
605 * does work here because we happen to have Kerberos
606 * credentials in check-ntlm, and the subsequent
607 * gss_init_sec_context() call finds no cred element for NTLM
608 * but plows on anyways, surprisingly enough, and then the
609 * NTLM gss_init_sec_context() just works.
611 * In summary, there's some breakage in gss_init_sec_context()
612 * and some breakage in NTLM (and SPNEGO) that conspires against
613 * us here.
615 * We work around this in check-ntlm and check-spnego by adding
616 * --mech-types='' to the invocations of this test program that
617 * require it.
619 oids[0] = *mechoid;
620 mechoid_descs.elements = &oids[0];
621 mechoid_descs.count = 1;
622 mechoids = &mechoid_descs;
623 } else {
624 string_to_oids(&mechoids, &mechoid_descs,
625 oids, sizeof(oids)/sizeof(oids[0]), mechs_string);
628 if (gsskrb5_acceptor_identity) {
629 maj_stat = gsskrb5_register_acceptor_identity(gsskrb5_acceptor_identity);
630 if (maj_stat)
631 errx(1, "gsskrb5_acceptor_identity: %s",
632 gssapi_err(maj_stat, 0, GSS_C_NO_OID));
635 if (client_password) {
636 credential_data.value = client_password;
637 credential_data.length = strlen(client_password);
640 if (client_name) {
641 gss_buffer_desc cn;
643 cn.value = client_name;
644 cn.length = strlen(client_name);
646 maj_stat = gss_import_name(&min_stat, &cn, GSS_C_NT_USER_NAME, &cname);
647 if (maj_stat)
648 errx(1, "gss_import_name: %s",
649 gssapi_err(maj_stat, min_stat, GSS_C_NO_OID));
652 if (client_password) {
653 maj_stat = gss_acquire_cred_with_password(&min_stat,
654 cname,
655 &credential_data,
656 GSS_C_INDEFINITE,
657 mechoids,
658 GSS_C_INITIATE,
659 &client_cred,
660 NULL,
661 NULL);
662 if (GSS_ERROR(maj_stat)) {
663 if (mechoids != GSS_C_NO_OID_SET && mechoids->count == 1)
664 mechoid = &mechoids->elements[0];
665 else
666 mechoid = GSS_C_NO_OID;
667 errx(1, "gss_acquire_cred_with_password: %s",
668 gssapi_err(maj_stat, min_stat, mechoid));
670 } else {
671 maj_stat = gss_acquire_cred(&min_stat,
672 cname,
673 GSS_C_INDEFINITE,
674 mechoids,
675 GSS_C_INITIATE,
676 &client_cred,
677 NULL,
678 NULL);
679 if (GSS_ERROR(maj_stat))
680 errx(1, "gss_acquire_cred: %s",
681 gssapi_err(maj_stat, min_stat, GSS_C_NO_OID));
684 if (limit_enctype_string) {
685 krb5_error_code ret;
687 ret = krb5_string_to_enctype(context,
688 limit_enctype_string,
689 &limit_enctype);
690 if (ret)
691 krb5_err(context, 1, ret, "krb5_string_to_enctype");
695 if (limit_enctype) {
696 if (client_cred == NULL)
697 errx(1, "client_cred missing");
699 maj_stat = gss_krb5_set_allowable_enctypes(&min_stat, client_cred,
700 1, &limit_enctype);
701 if (maj_stat)
702 errx(1, "gss_krb5_set_allowable_enctypes: %s",
703 gssapi_err(maj_stat, min_stat, GSS_C_NO_OID));
706 loop(mechoid, nameoid, argv[0], client_cred,
707 &sctx, &cctx, &actual_mech, &deleg_cred);
709 if (verbose_flag)
710 printf("resulting mech: %s\n", oid_to_string(actual_mech));
712 if (ret_mech_string) {
713 gss_OID retoid;
715 retoid = string_to_oid(ret_mech_string);
717 if (gss_oid_equal(retoid, actual_mech) == 0)
718 errx(1, "actual_mech mech is not the expected type %s",
719 ret_mech_string);
722 /* XXX should be actual_mech */
723 if (gss_oid_equal(mechoid, GSS_KRB5_MECHANISM)) {
724 time_t sc_time;
725 gss_buffer_desc authz_data;
726 gss_buffer_desc in, out1, out2;
727 krb5_keyblock *keyblock, *keyblock2;
728 krb5_timestamp now;
729 krb5_error_code ret;
731 ret = krb5_timeofday(context, &now);
732 if (ret)
733 errx(1, "krb5_timeofday failed");
735 /* client */
736 maj_stat = gss_krb5_export_lucid_sec_context(&min_stat,
737 &cctx,
738 1, /* version */
739 &ctx);
740 if (maj_stat != GSS_S_COMPLETE)
741 errx(1, "gss_krb5_export_lucid_sec_context failed: %s",
742 gssapi_err(maj_stat, min_stat, actual_mech));
745 maj_stat = gss_krb5_free_lucid_sec_context(&maj_stat, ctx);
746 if (maj_stat != GSS_S_COMPLETE)
747 errx(1, "gss_krb5_free_lucid_sec_context failed: %s",
748 gssapi_err(maj_stat, min_stat, actual_mech));
750 /* server */
751 maj_stat = gss_krb5_export_lucid_sec_context(&min_stat,
752 &sctx,
753 1, /* version */
754 &ctx);
755 if (maj_stat != GSS_S_COMPLETE)
756 errx(1, "gss_krb5_export_lucid_sec_context failed: %s",
757 gssapi_err(maj_stat, min_stat, actual_mech));
758 maj_stat = gss_krb5_free_lucid_sec_context(&min_stat, ctx);
759 if (maj_stat != GSS_S_COMPLETE)
760 errx(1, "gss_krb5_free_lucid_sec_context failed: %s",
761 gssapi_err(maj_stat, min_stat, actual_mech));
763 maj_stat = gsskrb5_extract_authtime_from_sec_context(&min_stat,
764 sctx,
765 &sc_time);
766 if (maj_stat != GSS_S_COMPLETE)
767 errx(1, "gsskrb5_extract_authtime_from_sec_context failed: %s",
768 gssapi_err(maj_stat, min_stat, actual_mech));
770 if (sc_time > now)
771 errx(1, "gsskrb5_extract_authtime_from_sec_context failed: "
772 "time authtime is before now: %ld %ld",
773 (long)sc_time, (long)now);
775 maj_stat = gsskrb5_extract_service_keyblock(&min_stat,
776 sctx,
777 &keyblock);
778 if (maj_stat != GSS_S_COMPLETE)
779 errx(1, "gsskrb5_export_service_keyblock failed: %s",
780 gssapi_err(maj_stat, min_stat, actual_mech));
782 krb5_free_keyblock(context, keyblock);
784 maj_stat = gsskrb5_get_subkey(&min_stat,
785 sctx,
786 &keyblock);
787 if (maj_stat != GSS_S_COMPLETE
788 && (!(maj_stat == GSS_S_FAILURE && min_stat == GSS_KRB5_S_KG_NO_SUBKEY)))
789 errx(1, "gsskrb5_get_subkey server failed: %s",
790 gssapi_err(maj_stat, min_stat, actual_mech));
792 if (maj_stat != GSS_S_COMPLETE)
793 keyblock = NULL;
794 else if (limit_enctype && keyblock->keytype != limit_enctype)
795 errx(1, "gsskrb5_get_subkey wrong enctype");
797 maj_stat = gsskrb5_get_subkey(&min_stat,
798 cctx,
799 &keyblock2);
800 if (maj_stat != GSS_S_COMPLETE
801 && (!(maj_stat == GSS_S_FAILURE && min_stat == GSS_KRB5_S_KG_NO_SUBKEY)))
802 errx(1, "gsskrb5_get_subkey client failed: %s",
803 gssapi_err(maj_stat, min_stat, actual_mech));
805 if (maj_stat != GSS_S_COMPLETE)
806 keyblock2 = NULL;
807 else if (limit_enctype && keyblock->keytype != limit_enctype)
808 errx(1, "gsskrb5_get_subkey wrong enctype");
810 if (keyblock || keyblock2) {
811 if (keyblock == NULL)
812 errx(1, "server missing token keyblock");
813 if (keyblock2 == NULL)
814 errx(1, "client missing token keyblock");
816 if (keyblock->keytype != keyblock2->keytype)
817 errx(1, "enctype mismatch");
818 if (keyblock->keyvalue.length != keyblock2->keyvalue.length)
819 errx(1, "key length mismatch");
820 if (memcmp(keyblock->keyvalue.data, keyblock2->keyvalue.data,
821 keyblock2->keyvalue.length) != 0)
822 errx(1, "key data mismatch");
825 if (session_enctype_string) {
826 krb5_enctype enctype;
828 ret = krb5_string_to_enctype(context,
829 session_enctype_string,
830 &enctype);
832 if (ret)
833 krb5_err(context, 1, ret, "krb5_string_to_enctype");
835 if (enctype != keyblock->keytype)
836 errx(1, "keytype is not the expected %d != %d",
837 (int)enctype, (int)keyblock2->keytype);
840 if (keyblock)
841 krb5_free_keyblock(context, keyblock);
842 if (keyblock2)
843 krb5_free_keyblock(context, keyblock2);
845 maj_stat = gsskrb5_get_initiator_subkey(&min_stat,
846 sctx,
847 &keyblock);
848 if (maj_stat != GSS_S_COMPLETE
849 && (!(maj_stat == GSS_S_FAILURE && min_stat == GSS_KRB5_S_KG_NO_SUBKEY)))
850 errx(1, "gsskrb5_get_initiator_subkey failed: %s",
851 gssapi_err(maj_stat, min_stat, actual_mech));
853 if (maj_stat == GSS_S_COMPLETE) {
855 if (limit_enctype && keyblock->keytype != limit_enctype)
856 errx(1, "gsskrb5_get_initiator_subkey wrong enctype");
857 krb5_free_keyblock(context, keyblock);
860 maj_stat = gsskrb5_extract_authz_data_from_sec_context(&min_stat,
861 sctx,
862 128,
863 &authz_data);
864 if (maj_stat == GSS_S_COMPLETE)
865 gss_release_buffer(&min_stat, &authz_data);
868 memset(&out1, 0, sizeof(out1));
869 memset(&out2, 0, sizeof(out2));
871 in.value = "foo";
872 in.length = 3;
874 gss_pseudo_random(&min_stat, sctx, GSS_C_PRF_KEY_FULL, &in,
875 100, &out1);
876 gss_pseudo_random(&min_stat, cctx, GSS_C_PRF_KEY_FULL, &in,
877 100, &out2);
879 if (out1.length != out2.length)
880 errx(1, "prf len mismatch");
881 if (memcmp(out1.value, out2.value, out1.length) != 0)
882 errx(1, "prf data mismatch");
884 gss_release_buffer(&min_stat, &out1);
886 gss_pseudo_random(&min_stat, sctx, GSS_C_PRF_KEY_FULL, &in,
887 100, &out1);
889 if (out1.length != out2.length)
890 errx(1, "prf len mismatch");
891 if (memcmp(out1.value, out2.value, out1.length) != 0)
892 errx(1, "prf data mismatch");
894 gss_release_buffer(&min_stat, &out1);
895 gss_release_buffer(&min_stat, &out2);
897 in.value = "bar";
898 in.length = 3;
900 gss_pseudo_random(&min_stat, sctx, GSS_C_PRF_KEY_PARTIAL, &in,
901 100, &out1);
902 gss_pseudo_random(&min_stat, cctx, GSS_C_PRF_KEY_PARTIAL, &in,
903 100, &out2);
905 if (out1.length != out2.length)
906 errx(1, "prf len mismatch");
907 if (memcmp(out1.value, out2.value, out1.length) != 0)
908 errx(1, "prf data mismatch");
910 gss_release_buffer(&min_stat, &out1);
911 gss_release_buffer(&min_stat, &out2);
913 wrapunwrap_flag = 1;
914 getverifymic_flag = 1;
917 if (wrapunwrap_flag) {
918 wrapunwrap(cctx, sctx, 0, actual_mech);
919 wrapunwrap(cctx, sctx, 1, actual_mech);
920 wrapunwrap(sctx, cctx, 0, actual_mech);
921 wrapunwrap(sctx, cctx, 1, actual_mech);
924 if (iov_flag) {
925 wrapunwrap_iov(cctx, sctx, 0, actual_mech);
926 wrapunwrap_iov(cctx, sctx, USE_HEADER_ONLY|FORCE_IOV, actual_mech);
927 wrapunwrap_iov(cctx, sctx, USE_HEADER_ONLY, actual_mech);
928 wrapunwrap_iov(cctx, sctx, USE_CONF, actual_mech);
929 wrapunwrap_iov(cctx, sctx, USE_CONF|USE_HEADER_ONLY, actual_mech);
931 wrapunwrap_iov(cctx, sctx, FORCE_IOV, actual_mech);
932 wrapunwrap_iov(cctx, sctx, USE_CONF|FORCE_IOV, actual_mech);
933 wrapunwrap_iov(cctx, sctx, USE_HEADER_ONLY|FORCE_IOV, actual_mech);
934 wrapunwrap_iov(cctx, sctx, USE_CONF|USE_HEADER_ONLY|FORCE_IOV, actual_mech);
936 wrapunwrap_iov(cctx, sctx, USE_SIGN_ONLY|FORCE_IOV, actual_mech);
937 wrapunwrap_iov(cctx, sctx, USE_CONF|USE_SIGN_ONLY|FORCE_IOV, actual_mech);
938 wrapunwrap_iov(cctx, sctx, USE_CONF|USE_HEADER_ONLY|USE_SIGN_ONLY|FORCE_IOV, actual_mech);
940 /* works */
941 wrapunwrap_iov(cctx, sctx, 0, actual_mech);
942 wrapunwrap_iov(cctx, sctx, FORCE_IOV, actual_mech);
944 wrapunwrap_iov(cctx, sctx, USE_CONF, actual_mech);
945 wrapunwrap_iov(cctx, sctx, USE_CONF|FORCE_IOV, actual_mech);
947 wrapunwrap_iov(cctx, sctx, USE_SIGN_ONLY, actual_mech);
948 wrapunwrap_iov(cctx, sctx, USE_SIGN_ONLY|FORCE_IOV, actual_mech);
950 wrapunwrap_iov(cctx, sctx, USE_CONF|USE_SIGN_ONLY, actual_mech);
951 wrapunwrap_iov(cctx, sctx, USE_CONF|USE_SIGN_ONLY|FORCE_IOV, actual_mech);
953 wrapunwrap_iov(cctx, sctx, USE_HEADER_ONLY, actual_mech);
954 wrapunwrap_iov(cctx, sctx, USE_HEADER_ONLY|FORCE_IOV, actual_mech);
956 wrapunwrap_iov(cctx, sctx, USE_CONF|USE_HEADER_ONLY, actual_mech);
957 wrapunwrap_iov(cctx, sctx, USE_CONF|USE_HEADER_ONLY|FORCE_IOV, actual_mech);
960 if (getverifymic_flag) {
961 getverifymic(cctx, sctx, actual_mech);
962 getverifymic(cctx, sctx, actual_mech);
963 getverifymic(sctx, cctx, actual_mech);
964 getverifymic(sctx, cctx, actual_mech);
968 gss_delete_sec_context(&min_stat, &cctx, NULL);
969 gss_delete_sec_context(&min_stat, &sctx, NULL);
971 if (deleg_cred != GSS_C_NO_CREDENTIAL) {
972 gss_cred_id_t cred2 = GSS_C_NO_CREDENTIAL;
973 gss_buffer_desc cb;
975 if (verbose_flag)
976 printf("checking actual mech (%s) on delegated cred\n",
977 oid_to_string(actual_mech));
978 loop(actual_mech, nameoid, argv[0], deleg_cred, &sctx, &cctx, &actual_mech2, &cred2);
980 gss_delete_sec_context(&min_stat, &cctx, NULL);
981 gss_delete_sec_context(&min_stat, &sctx, NULL);
983 gss_release_cred(&min_stat, &cred2);
985 /* try again using SPNEGO */
986 if (verbose_flag)
987 printf("checking spnego on delegated cred\n");
988 loop(GSS_SPNEGO_MECHANISM, nameoid, argv[0], deleg_cred, &sctx, &cctx,
989 &actual_mech2, &cred2);
991 gss_delete_sec_context(&min_stat, &cctx, NULL);
992 gss_delete_sec_context(&min_stat, &sctx, NULL);
994 gss_release_cred(&min_stat, &cred2);
996 /* check export/import */
997 if (ei_flag) {
999 maj_stat = gss_export_cred(&min_stat, deleg_cred, &cb);
1000 if (maj_stat != GSS_S_COMPLETE)
1001 errx(1, "export failed: %s",
1002 gssapi_err(maj_stat, min_stat, NULL));
1004 maj_stat = gss_import_cred(&min_stat, &cb, &cred2);
1005 if (maj_stat != GSS_S_COMPLETE)
1006 errx(1, "import failed: %s",
1007 gssapi_err(maj_stat, min_stat, NULL));
1009 gss_release_buffer(&min_stat, &cb);
1010 gss_release_cred(&min_stat, &deleg_cred);
1012 if (verbose_flag)
1013 printf("checking actual mech (%s) on export/imported cred\n",
1014 oid_to_string(actual_mech));
1015 loop(actual_mech, nameoid, argv[0], cred2, &sctx, &cctx,
1016 &actual_mech2, &deleg_cred);
1018 gss_release_cred(&min_stat, &deleg_cred);
1020 gss_delete_sec_context(&min_stat, &cctx, NULL);
1021 gss_delete_sec_context(&min_stat, &sctx, NULL);
1023 /* try again using SPNEGO */
1024 if (verbose_flag)
1025 printf("checking SPNEGO on export/imported cred\n");
1026 loop(GSS_SPNEGO_MECHANISM, nameoid, argv[0], cred2, &sctx, &cctx,
1027 &actual_mech2, &deleg_cred);
1029 gss_release_cred(&min_stat, &deleg_cred);
1031 gss_delete_sec_context(&min_stat, &cctx, NULL);
1032 gss_delete_sec_context(&min_stat, &sctx, NULL);
1034 gss_release_cred(&min_stat, &cred2);
1036 } else {
1037 gss_release_cred(&min_stat, &deleg_cred);
1042 empty_release();
1044 krb5_free_context(context);
1046 return 0;