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 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;
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 */ }
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
;
92 string_to_oid(const char *name
)
95 for (i
= 0; i
< sizeof(o2n
)/sizeof(o2n
[0]); i
++)
96 if (strcasecmp(name
, o2n
[i
].name
) == 0)
98 errx(1, "name '%s' not unknown", name
);
102 string_to_oids(gss_OID_set
*oidsetp
, gss_OID_set oidset
,
103 gss_OID_desc
*oidarray
, size_t oidarray_len
,
109 if (names
[0] == '\0') {
110 *oidsetp
= GSS_C_NO_OID_SET
;
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
;
121 for (oidset
->count
= 0, name
= strtok_r(names
, ", ", &s
);
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
;
134 oid_to_string(const gss_OID oid
)
137 for (i
= 0; i
< sizeof(o2n
)/sizeof(o2n
[0]); i
++)
138 if (gss_oid_equal(oid
, o2n
[i
].oid
))
140 return "unknown oid";
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;
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
;
168 flags
|= GSS_C_DCE_STYLE
;
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
,
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
) {
190 gsskrb5_set_time_offset(client_time_offset
);
192 maj_stat
= gss_init_sec_context(&min_stat
,
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
)
213 gsskrb5_get_time_offset(&client_time_offset
);
215 if (client_done
&& server_done
)
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
,
227 GSS_C_NO_CHANNEL_BINDINGS
,
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
)
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
);
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
);
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
;
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");
311 #define USE_HEADER_ONLY 2
312 #define USE_SIGN_ONLY 4
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
;
321 int conf_state
, conf_state2
;
322 gss_iov_buffer_desc iov
[6];
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
;
335 trailer
.data
= trailer_data
;
344 token
.data
= token_data
;
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
;
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
;
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
;
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
;
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
,
393 if (maj_stat
!= GSS_S_COMPLETE
)
394 errx(1, "gss_wrap_iov failed");
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
);
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
);
436 maj_stat
= gss_unwrap_iov(&min_stat
, sctx
, &conf_state2
, &qop_state
,
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
);
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
;
458 input_token
.value
= "bar";
459 input_token
.length
= 3;
461 maj_stat
= gss_get_mic(&min_stat
, cctx
, 0, &input_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
);
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
;
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
}
530 arg_printusage (args
, sizeof(args
)/sizeof(*args
),
531 NULL
, "service@host");
536 main(int argc
, char **argv
)
539 OM_uint32 min_stat
, maj_stat
;
540 gss_ctx_id_t cctx
, sctx
;
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]);
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
))
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
;
586 errx(1, "%s not supported", type_string
);
588 if (mech_string
== NULL
)
589 mechoid
= GSS_KRB5_MECHANISM
;
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
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
615 * We work around this in check-ntlm and check-spnego by adding
616 * --mech-types='' to the invocations of this test program that
620 mechoid_descs
.elements
= &oids
[0];
621 mechoid_descs
.count
= 1;
622 mechoids
= &mechoid_descs
;
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
);
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
);
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
);
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
,
662 if (GSS_ERROR(maj_stat
)) {
663 if (mechoids
!= GSS_C_NO_OID_SET
&& mechoids
->count
== 1)
664 mechoid
= &mechoids
->elements
[0];
666 mechoid
= GSS_C_NO_OID
;
667 errx(1, "gss_acquire_cred_with_password: %s",
668 gssapi_err(maj_stat
, min_stat
, mechoid
));
671 maj_stat
= gss_acquire_cred(&min_stat
,
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
) {
687 ret
= krb5_string_to_enctype(context
,
688 limit_enctype_string
,
691 krb5_err(context
, 1, ret
, "krb5_string_to_enctype");
696 if (client_cred
== NULL
)
697 errx(1, "client_cred missing");
699 maj_stat
= gss_krb5_set_allowable_enctypes(&min_stat
, client_cred
,
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
);
710 printf("resulting mech: %s\n", oid_to_string(actual_mech
));
712 if (ret_mech_string
) {
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",
722 /* XXX should be actual_mech */
723 if (gss_oid_equal(mechoid
, GSS_KRB5_MECHANISM
)) {
725 gss_buffer_desc authz_data
;
726 gss_buffer_desc in
, out1
, out2
;
727 krb5_keyblock
*keyblock
, *keyblock2
;
731 ret
= krb5_timeofday(context
, &now
);
733 errx(1, "krb5_timeofday failed");
736 maj_stat
= gss_krb5_export_lucid_sec_context(&min_stat
,
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
));
751 maj_stat
= gss_krb5_export_lucid_sec_context(&min_stat
,
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
,
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
));
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
,
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
,
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
)
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
,
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
)
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
,
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
);
841 krb5_free_keyblock(context
, keyblock
);
843 krb5_free_keyblock(context
, keyblock2
);
845 maj_stat
= gsskrb5_get_initiator_subkey(&min_stat
,
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
,
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
));
874 gss_pseudo_random(&min_stat
, sctx
, GSS_C_PRF_KEY_FULL
, &in
,
876 gss_pseudo_random(&min_stat
, cctx
, GSS_C_PRF_KEY_FULL
, &in
,
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
,
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
);
900 gss_pseudo_random(&min_stat
, sctx
, GSS_C_PRF_KEY_PARTIAL
, &in
,
902 gss_pseudo_random(&min_stat
, cctx
, GSS_C_PRF_KEY_PARTIAL
, &in
,
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
);
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
);
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
);
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
;
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 */
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 */
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
);
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 */
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
);
1037 gss_release_cred(&min_stat
, &deleg_cred
);
1044 krb5_free_context(context
);