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"
45 * export/import of sec contexts on the initiator side
46 * don't work properly, yet.
48 #define DO_IMPORT_EXPORT_OF_CLIENT_CONTEXT 1
51 static char *type_string
;
52 static char *mech_string
;
53 static char *mechs_string
;
54 static char *ret_mech_string
;
55 static char *localname_string
;
56 static char *client_name
;
57 static char *client_password
;
58 static char *localname_string
;
59 static char *on_behalf_of_string
;
60 static int dns_canon_flag
= -1;
61 static int mutual_auth_flag
= 0;
62 static int dce_style_flag
= 0;
63 static int wrapunwrap_flag
= 0;
64 static int iov_flag
= 0;
65 static int aead_flag
= 0;
66 static int getverifymic_flag
= 0;
67 static int deleg_flag
= 0;
68 static int anon_flag
= 0;
69 static int policy_deleg_flag
= 0;
70 static int server_no_deleg_flag
= 0;
71 static int ei_cred_flag
= 0;
72 static int ei_ctx_flag
= 0;
73 static char *client_ccache
= NULL
;
74 static char *client_keytab
= NULL
;
75 static char *gsskrb5_acceptor_identity
= NULL
;
76 static char *session_enctype_string
= NULL
;
77 static int client_time_offset
= 0;
78 static int server_time_offset
= 0;
79 static int max_loops
= 0;
80 static char *limit_enctype_string
= NULL
;
81 static int token_split
= 0;
82 static int version_flag
= 0;
83 static int verbose_flag
= 0;
84 static int help_flag
= 0;
85 static int i_channel_bound
= 0;
86 static char *i_channel_bindings
= NULL
;
87 static char *a_channel_bindings
= NULL
;
89 static krb5_context context
;
90 static krb5_enctype limit_enctype
= 0;
93 string_to_oid(const char *name
)
95 gss_OID oid
= gss_name_to_oid(name
);
97 if (oid
== GSS_C_NO_OID
)
98 errx(1, "name '%s' not known", name
);
104 string_to_oids(gss_OID_set
*oidsetp
, char *names
)
106 OM_uint32 maj_stat
, min_stat
;
110 if (names
[0] == '\0') {
111 *oidsetp
= GSS_C_NO_OID_SET
;
115 if (strcasecmp(names
, "all") == 0) {
116 maj_stat
= gss_indicate_mechs(&min_stat
, oidsetp
);
117 if (GSS_ERROR(maj_stat
))
118 errx(1, "gss_indicate_mechs: %s",
119 gssapi_err(maj_stat
, min_stat
, GSS_C_NO_OID
));
121 maj_stat
= gss_create_empty_oid_set(&min_stat
, oidsetp
);
122 if (GSS_ERROR(maj_stat
))
123 errx(1, "gss_create_empty_oid_set: %s",
124 gssapi_err(maj_stat
, min_stat
, GSS_C_NO_OID
));
126 for (name
= strtok_r(names
, ", ", &s
);
128 name
= strtok_r(NULL
, ", ", &s
)) {
129 gss_OID oid
= string_to_oid(name
);
131 maj_stat
= gss_add_oid_set_member(&min_stat
, oid
, oidsetp
);
132 if (GSS_ERROR(maj_stat
))
133 errx(1, "gss_add_oid_set_member: %s",
134 gssapi_err(maj_stat
, min_stat
, GSS_C_NO_OID
));
140 show_pac_client_info(gss_name_t n
)
142 gss_buffer_desc dv
= GSS_C_EMPTY_BUFFER
;
143 gss_buffer_desc v
= GSS_C_EMPTY_BUFFER
;
146 int authenticated
, complete
, more
, name_is_MN
, found
;
148 gss_buffer_set_t attrs
= GSS_C_NO_BUFFER_SET
;
152 krb5_storage
*sp
= NULL
;
153 uint16_t len
= 0, *s
;
155 char *logon_string
= NULL
;
157 maj
= gss_inquire_name(&min
, n
, &name_is_MN
, &MN_mech
, &attrs
);
158 if (maj
!= GSS_S_COMPLETE
)
159 errx(1, "gss_inquire_name: %s",
160 gssapi_err(maj
, min
, GSS_KRB5_MECHANISM
));
162 a
.value
= "urn:mspac:client-info";
163 a
.length
= sizeof("urn:mspac:client-info") - 1;
165 for (found
= 0, i
= 0; i
< attrs
->count
; i
++) {
166 gss_buffer_t attr
= &attrs
->elements
[i
];
168 if (attr
->length
== a
.length
&&
169 memcmp(attr
->value
, a
.value
, a
.length
) == 0) {
175 gss_release_buffer_set(&min
, &attrs
);
178 errx(1, "gss_inquire_name: attribute %.*s not enumerated",
179 (int)a
.length
, (char *)a
.value
);
182 maj
= gss_get_name_attribute(&min
, n
, &a
, &authenticated
, &complete
, &v
,
184 if (maj
!= GSS_S_COMPLETE
)
185 errx(1, "gss_get_name_attribute: %s",
186 gssapi_err(maj
, min
, GSS_KRB5_MECHANISM
));
189 sp
= krb5_storage_from_readonly_mem(v
.value
, v
.length
);
191 errx(1, "show_pac_client_info: out of memory");
193 krb5_storage_set_flags(sp
, KRB5_STORAGE_BYTEORDER_LE
);
195 ret
= krb5_ret_uint64(sp
, &tmp
); /* skip over time */
197 ret
= krb5_ret_uint16(sp
, &len
);
199 errx(1, "show_pac_client_info: invalid PAC logon info length");
202 ret
= krb5_storage_read(sp
, s
, len
);
204 errx(1, "show_pac_client_info:, failed to read PAC logon name");
206 krb5_storage_free(sp
);
209 size_t ucs2len
= len
/ 2;
212 unsigned int flags
= WIND_RW_LE
;
214 ucs2
= malloc(sizeof(ucs2
[0]) * ucs2len
);
216 errx(1, "show_pac_client_info: out of memory");
218 ret
= wind_ucs2read(s
, len
, &flags
, ucs2
, &ucs2len
);
221 errx(1, "failed to convert string to UCS-2");
223 ret
= wind_ucs2utf8_length(ucs2
, ucs2len
, &u8len
);
225 errx(1, "failed to count length of UCS-2 string");
227 u8len
+= 1; /* Add space for NUL */
228 logon_string
= malloc(u8len
);
229 if (logon_string
== NULL
)
230 errx(1, "show_pac_client_info: out of memory");
232 ret
= wind_ucs2utf8(ucs2
, ucs2len
, logon_string
, &u8len
);
235 errx(1, "failed to convert to UTF-8");
238 printf("logon name: %s\n", logon_string
);
241 gss_release_buffer(&min
, &dv
);
242 gss_release_buffer(&min
, &v
);
246 loop(gss_OID mechoid
,
247 gss_OID nameoid
, const char *target
,
248 gss_cred_id_t init_cred
,
249 gss_ctx_id_t
*sctx
, gss_ctx_id_t
*cctx
,
250 gss_OID
*actual_mech
,
251 gss_cred_id_t
*deleg_cred
)
253 int server_done
= 0, client_done
= 0;
255 OM_uint32 maj_stat
, min_stat
;
256 gss_name_t gss_target_name
, src_name
= GSS_C_NO_NAME
;
257 gss_buffer_desc input_token
= GSS_C_EMPTY_BUFFER
;
258 gss_buffer_desc output_token
= GSS_C_EMPTY_BUFFER
;
259 #ifdef DO_IMPORT_EXPORT_OF_CLIENT_CONTEXT
260 gss_buffer_desc cctx_tok
= GSS_C_EMPTY_BUFFER
;
262 gss_buffer_desc sctx_tok
= GSS_C_EMPTY_BUFFER
;
263 OM_uint32 flags
= 0, ret_cflags
= 0, ret_sflags
= 0;
264 gss_OID actual_mech_client
= GSS_C_NO_OID
;
265 gss_OID actual_mech_server
= GSS_C_NO_OID
;
266 struct gss_channel_bindings_struct i_channel_bindings_data
;
267 struct gss_channel_bindings_struct a_channel_bindings_data
;
268 gss_channel_bindings_t i_channel_bindings_p
= GSS_C_NO_CHANNEL_BINDINGS
;
269 gss_channel_bindings_t a_channel_bindings_p
= GSS_C_NO_CHANNEL_BINDINGS
;
272 memset(&i_channel_bindings_data
, 0, sizeof(i_channel_bindings_data
));
273 memset(&a_channel_bindings_data
, 0, sizeof(a_channel_bindings_data
));
275 *actual_mech
= GSS_C_NO_OID
;
277 flags
|= GSS_C_REPLAY_FLAG
;
278 flags
|= GSS_C_INTEG_FLAG
;
279 flags
|= GSS_C_CONF_FLAG
;
281 if (mutual_auth_flag
)
282 flags
|= GSS_C_MUTUAL_FLAG
;
284 flags
|= GSS_C_ANON_FLAG
;
286 flags
|= GSS_C_DCE_STYLE
;
288 flags
|= GSS_C_DELEG_FLAG
;
289 if (policy_deleg_flag
)
290 flags
|= GSS_C_DELEG_POLICY_FLAG
;
292 flags
|= GSS_C_CHANNEL_BOUND_FLAG
;
294 input_token
.value
= rk_UNCONST(target
);
295 input_token
.length
= strlen(target
);
297 maj_stat
= gss_import_name(&min_stat
,
301 if (GSS_ERROR(maj_stat
))
302 err(1, "import name creds failed with: %d", maj_stat
);
304 if (on_behalf_of_string
) {
305 AuthorizationDataElement e
;
306 gss_buffer_desc attr
, value
;
310 memset(&e
, 0, sizeof(e
));
311 e
.ad_type
= KRB5_AUTHDATA_ON_BEHALF_OF
;
312 e
.ad_data
.length
= strlen(on_behalf_of_string
);
313 e
.ad_data
.data
= on_behalf_of_string
;
314 ASN1_MALLOC_ENCODE(AuthorizationDataElement
, value
.value
, value
.length
,
317 errx(1, "Could not encode AD-ON-BEHALF-OF AuthorizationDataElement");
319 GSS_KRB5_NAME_ATTRIBUTE_BASE_URN
"authenticator-authz-data";
321 sizeof(GSS_KRB5_NAME_ATTRIBUTE_BASE_URN
"authenticator-authz-data") - 1;
322 maj_stat
= gss_set_name_attribute(&min_stat
, gss_target_name
, 1, &attr
,
324 if (maj_stat
!= GSS_S_COMPLETE
)
325 errx(1, "gss_set_name_attribute() failed with: %s",
326 gssapi_err(maj_stat
, min_stat
, GSS_KRB5_MECHANISM
));
330 input_token
.length
= 0;
331 input_token
.value
= NULL
;
333 if (i_channel_bindings
) {
334 i_channel_bindings_data
.application_data
.length
= strlen(i_channel_bindings
);
335 i_channel_bindings_data
.application_data
.value
= i_channel_bindings
;
336 i_channel_bindings_p
= &i_channel_bindings_data
;
338 if (a_channel_bindings
) {
339 a_channel_bindings_data
.application_data
.length
= strlen(a_channel_bindings
);
340 a_channel_bindings_data
.application_data
.value
= a_channel_bindings
;
341 a_channel_bindings_p
= &a_channel_bindings_data
;
345 * This loop simulates both the initiator and acceptor sides of
346 * a GSS conversation. We also simulate tokens that are broken
347 * into pieces before handed to gss_accept_sec_context(). Each
348 * iteration of the loop optionally calls gss_init_sec_context()
349 * then optionally calls gss_accept_sec_context().
352 while (!server_done
|| !client_done
) {
355 printf("loop #%d: input_token.length=%zu client_done=%d\n",
356 num_loops
, input_token
.length
, client_done
);
359 * First, we need to call gss_import_sec_context() if we are
360 * running through the loop the first time, or if we have been
361 * given a token (input_token) by gss_accept_sec_context().
362 * We aren't going to be called every time because when we are
363 * using split tokens, we may need to call gss_accept_sec_context()
364 * multiple times because it receives an entire token.
366 if ((num_loops
== 1 || input_token
.length
> 0) && !client_done
) {
367 gsskrb5_set_time_offset(client_time_offset
);
368 #ifdef DO_IMPORT_EXPORT_OF_CLIENT_CONTEXT
369 if (ei_ctx_flag
&& cctx_tok
.length
> 0) {
370 maj_stat
= gss_import_sec_context(&min_stat
, &cctx_tok
, cctx
);
371 if (maj_stat
!= GSS_S_COMPLETE
)
372 errx(1, "import client context failed: %s",
373 gssapi_err(maj_stat
, min_stat
, NULL
));
374 gss_release_buffer(&min_stat
, &cctx_tok
);
378 maj_stat
= gss_init_sec_context(&min_stat
, init_cred
, cctx
,
379 gss_target_name
, mechoid
,
380 flags
, 0, i_channel_bindings_p
,
381 &input_token
, &actual_mech_client
,
382 &output_token
, &ret_cflags
, NULL
);
383 if (GSS_ERROR(maj_stat
))
384 errx(1, "init_sec_context: %s",
385 gssapi_err(maj_stat
, min_stat
, mechoid
));
386 client_done
= !(maj_stat
& GSS_S_CONTINUE_NEEDED
);
388 gss_release_buffer(&min_stat
, &input_token
);
389 input_token
.length
= 0;
390 input_token
.value
= NULL
;
392 #if DO_IMPORT_EXPORT_OF_CLIENT_CONTEXT
393 if (!client_done
&& ei_ctx_flag
) {
394 maj_stat
= gss_export_sec_context(&min_stat
, cctx
, &cctx_tok
);
395 if (maj_stat
!= GSS_S_COMPLETE
)
396 errx(1, "export server context failed: %s",
397 gssapi_err(maj_stat
, min_stat
, NULL
));
398 if (*cctx
!= GSS_C_NO_CONTEXT
)
399 errx(1, "export client context did not release it");
404 printf("loop #%d: output_token.length=%zu\n", num_loops
,
405 output_token
.length
);
411 * We now call gss_accept_sec_context(). To support split
412 * tokens, we keep track of the offset into the token that
413 * we have used and keep handing in chunks until we're done.
416 if (offset
< output_token
.length
&& !server_done
) {
419 gsskrb5_get_time_offset(&client_time_offset
);
420 gsskrb5_set_time_offset(server_time_offset
);
422 if (output_token
.length
&& ((uint8_t *)output_token
.value
)[0] == 0x60) {
423 tmp
.length
= output_token
.length
- offset
;
424 if (token_split
&& tmp
.length
> token_split
)
425 tmp
.length
= token_split
;
426 tmp
.value
= (char *)output_token
.value
+ offset
;
431 printf("loop #%d: accept offset=%zu len=%zu\n", num_loops
,
434 if (ei_ctx_flag
&& sctx_tok
.length
> 0) {
435 maj_stat
= gss_import_sec_context(&min_stat
, &sctx_tok
, sctx
);
436 if (maj_stat
!= GSS_S_COMPLETE
)
437 errx(1, "import server context failed: %s",
438 gssapi_err(maj_stat
, min_stat
, NULL
));
439 gss_release_buffer(&min_stat
, &sctx_tok
);
442 maj_stat
= gss_accept_sec_context(&min_stat
, sctx
,
443 GSS_C_NO_CREDENTIAL
, &tmp
,
444 a_channel_bindings_p
, &src_name
,
446 &input_token
, &ret_sflags
,
448 if (GSS_ERROR(maj_stat
))
449 errx(1, "accept_sec_context: %s",
450 gssapi_err(maj_stat
, min_stat
, actual_mech_server
));
451 offset
+= tmp
.length
;
452 if (maj_stat
& GSS_S_CONTINUE_NEEDED
)
453 gss_release_name(&min_stat
, &src_name
);
457 if (ei_ctx_flag
&& !server_done
) {
458 maj_stat
= gss_export_sec_context(&min_stat
, sctx
, &sctx_tok
);
459 if (maj_stat
!= GSS_S_COMPLETE
)
460 errx(1, "export server context failed: %s",
461 gssapi_err(maj_stat
, min_stat
, NULL
));
462 if (*sctx
!= GSS_C_NO_CONTEXT
)
463 errx(1, "export server context did not release it");
466 gsskrb5_get_time_offset(&server_time_offset
);
468 if (output_token
.length
== offset
)
469 gss_release_buffer(&min_stat
, &output_token
);
472 printf("loop #%d: end\n", num_loops
);
474 if (output_token
.length
!= 0)
475 gss_release_buffer(&min_stat
, &output_token
);
476 if (input_token
.length
!= 0)
477 gss_release_buffer(&min_stat
, &input_token
);
478 gss_release_name(&min_stat
, &gss_target_name
);
480 if (deleg_flag
|| policy_deleg_flag
) {
481 if (server_no_deleg_flag
) {
482 if (*deleg_cred
!= GSS_C_NO_CREDENTIAL
)
483 errx(1, "got delegated cred but didn't expect one");
484 } else if (*deleg_cred
== GSS_C_NO_CREDENTIAL
)
485 errx(1, "asked for delegarated cred but did get one");
486 } else if (*deleg_cred
!= GSS_C_NO_CREDENTIAL
)
487 errx(1, "got deleg_cred cred but didn't ask");
489 if (gss_oid_equal(actual_mech_server
, actual_mech_client
) == 0)
490 errx(1, "mech mismatch");
491 *actual_mech
= actual_mech_server
;
493 if (on_behalf_of_string
) {
494 gss_buffer_desc attr
, value
;
497 GSS_KRB5_NAME_ATTRIBUTE_BASE_URN
"authz-data#580";
499 sizeof(GSS_KRB5_NAME_ATTRIBUTE_BASE_URN
"authz-data#580") - 1;
500 maj_stat
= gss_get_name_attribute(&min_stat
, src_name
, &attr
, NULL
,
501 NULL
, &value
, NULL
, NULL
);
502 if (maj_stat
!= GSS_S_COMPLETE
)
503 errx(1, "gss_get_name_attribute(authz-data#580) failed with %s",
504 gssapi_err(maj_stat
, min_stat
, GSS_KRB5_MECHANISM
));
506 if (value
.length
!= strlen(on_behalf_of_string
) ||
507 strncmp(value
.value
, on_behalf_of_string
,
508 strlen(on_behalf_of_string
)) != 0)
509 errx(1, "AD-ON-BEHALF-OF did not match");
510 (void) gss_release_buffer(&min_stat
, &value
);
512 if (localname_string
) {
513 gss_buffer_desc lname
;
515 maj_stat
= gss_localname(&min_stat
, src_name
, GSS_C_NO_OID
, &lname
);
516 if (maj_stat
!= GSS_S_COMPLETE
)
517 errx(1, "localname: %s",
518 gssapi_err(maj_stat
, min_stat
, GSS_C_NO_OID
));
520 printf("localname: %.*s\n", (int)lname
.length
,
521 (char *)lname
.value
);
522 if (lname
.length
!= strlen(localname_string
) ||
523 strncmp(localname_string
, lname
.value
, lname
.length
) != 0)
524 errx(1, "localname: expected \"%s\", got \"%.*s\" (1)",
525 localname_string
, (int)lname
.length
, (char *)lname
.value
);
526 gss_release_buffer(&min_stat
, &lname
);
527 maj_stat
= gss_localname(&min_stat
, src_name
, actual_mech_server
,
529 if (maj_stat
!= GSS_S_COMPLETE
)
530 errx(1, "localname: %s",
531 gssapi_err(maj_stat
, min_stat
, actual_mech_server
));
532 if (lname
.length
!= strlen(localname_string
) ||
533 strncmp(localname_string
, lname
.value
, lname
.length
) != 0)
534 errx(1, "localname: expected \"%s\", got \"%.*s\" (2)",
535 localname_string
, (int)lname
.length
, (char *)lname
.value
);
536 gss_release_buffer(&min_stat
, &lname
);
538 if (!gss_userok(src_name
, localname_string
))
539 errx(1, "localname is not userok");
540 if (gss_userok(src_name
, "nosuchuser:no"))
541 errx(1, "gss_userok() appears broken");
544 gss_buffer_desc iname
;
546 maj_stat
= gss_display_name(&min_stat
, src_name
, &iname
, NULL
);
547 if (maj_stat
== GSS_S_COMPLETE
) {
548 printf("client name: %.*s\n", (int)iname
.length
,
549 (char *)iname
.value
);
550 gss_release_buffer(&min_stat
, &iname
);
552 warnx("display_name: %s",
553 gssapi_err(maj_stat
, min_stat
, GSS_C_NO_OID
));
555 gss_oid_equal(actual_mech_server
, GSS_KRB5_MECHANISM
))
556 show_pac_client_info(src_name
);
558 gss_release_name(&min_stat
, &src_name
);
560 if (max_loops
&& num_loops
> max_loops
)
561 errx(1, "num loops %d was lager then max loops %d",
562 num_loops
, max_loops
);
565 printf("server time offset: %d\n", server_time_offset
);
566 printf("client time offset: %d\n", client_time_offset
);
567 printf("num loops %d\n", num_loops
);
569 if (ret_cflags
& GSS_C_DELEG_FLAG
)
571 if (ret_cflags
& GSS_C_MUTUAL_FLAG
)
573 if (ret_cflags
& GSS_C_REPLAY_FLAG
)
575 if (ret_cflags
& GSS_C_SEQUENCE_FLAG
)
577 if (ret_cflags
& GSS_C_CONF_FLAG
)
579 if (ret_cflags
& GSS_C_INTEG_FLAG
)
581 if (ret_cflags
& GSS_C_ANON_FLAG
)
583 if (ret_cflags
& GSS_C_PROT_READY_FLAG
)
584 printf("prot-ready ");
585 if (ret_cflags
& GSS_C_TRANS_FLAG
)
587 if (ret_cflags
& GSS_C_DCE_STYLE
)
588 printf("dce-style ");
589 if (ret_cflags
& GSS_C_IDENTIFY_FLAG
)
590 printf("identify " );
591 if (ret_cflags
& GSS_C_EXTENDED_ERROR_FLAG
)
592 printf("extended-error " );
593 if (ret_cflags
& GSS_C_DELEG_POLICY_FLAG
)
594 printf("deleg-policy " );
597 if (ret_sflags
& GSS_C_CHANNEL_BOUND_FLAG
)
598 printf("channel-bound " );
604 wrapunwrap(gss_ctx_id_t cctx
, gss_ctx_id_t sctx
, int flags
, gss_OID mechoid
)
606 gss_buffer_desc input_token
, output_token
, output_token2
;
607 OM_uint32 min_stat
, maj_stat
;
611 input_token
.value
= "foo";
612 input_token
.length
= 3;
614 maj_stat
= gss_wrap(&min_stat
, cctx
, flags
, 0, &input_token
,
615 &conf_state
, &output_token
);
616 if (maj_stat
!= GSS_S_COMPLETE
)
617 errx(1, "gss_wrap failed: %s",
618 gssapi_err(maj_stat
, min_stat
, mechoid
));
620 maj_stat
= gss_unwrap(&min_stat
, sctx
, &output_token
,
621 &output_token2
, &conf_state
, &qop_state
);
622 if (maj_stat
!= GSS_S_COMPLETE
)
623 errx(1, "gss_unwrap failed: %s",
624 gssapi_err(maj_stat
, min_stat
, mechoid
));
626 gss_release_buffer(&min_stat
, &output_token
);
627 gss_release_buffer(&min_stat
, &output_token2
);
629 #if 0 /* doesn't work for NTLM yet */
630 if (!!conf_state
!= !!flags
)
631 errx(1, "conf_state mismatch");
636 #define USE_HEADER_ONLY 2
637 #define USE_SIGN_ONLY 4
639 /* NO_DATA comes from <netdb.h>; we don't use it here; we appropriate it */
646 wrapunwrap_iov(gss_ctx_id_t cctx
, gss_ctx_id_t sctx
, int flags
, gss_OID mechoid
)
648 krb5_data token
, header
, trailer
;
649 OM_uint32 min_stat
, maj_stat
;
651 int conf_state
, conf_state2
;
652 gss_iov_buffer_desc iov
[6];
655 char header_data
[9] = "ABCheader";
656 char trailer_data
[10] = "trailerXYZ";
658 char token_data
[16] = "0123456789abcdef";
660 memset(&iov
, 0, sizeof(iov
));
662 if (flags
& USE_SIGN_ONLY
) {
663 header
.data
= header_data
;
665 trailer
.data
= trailer_data
;
674 token
.data
= token_data
;
677 iov_len
= sizeof(iov
)/sizeof(iov
[0]);
679 memset(iov
, 0, sizeof(iov
));
681 iov
[0].type
= GSS_IOV_BUFFER_TYPE_HEADER
| GSS_IOV_BUFFER_FLAG_ALLOCATE
;
683 if (header
.length
!= 0) {
684 iov
[1].type
= GSS_IOV_BUFFER_TYPE_SIGN_ONLY
;
685 iov
[1].buffer
.length
= header
.length
;
686 iov
[1].buffer
.value
= header
.data
;
688 iov
[1].type
= GSS_IOV_BUFFER_TYPE_EMPTY
;
689 iov
[1].buffer
.length
= 0;
690 iov
[1].buffer
.value
= NULL
;
692 iov
[2].type
= GSS_IOV_BUFFER_TYPE_DATA
;
693 if (flags
& NO_DATA
) {
694 iov
[2].buffer
.length
= 0;
696 iov
[2].buffer
.length
= token
.length
;
698 iov
[2].buffer
.value
= token
.data
;
699 if (trailer
.length
!= 0) {
700 iov
[3].type
= GSS_IOV_BUFFER_TYPE_SIGN_ONLY
;
701 iov
[3].buffer
.length
= trailer
.length
;
702 iov
[3].buffer
.value
= trailer
.data
;
704 iov
[3].type
= GSS_IOV_BUFFER_TYPE_EMPTY
;
705 iov
[3].buffer
.length
= 0;
706 iov
[3].buffer
.value
= NULL
;
708 if (dce_style_flag
) {
709 iov
[4].type
= GSS_IOV_BUFFER_TYPE_EMPTY
;
711 iov
[4].type
= GSS_IOV_BUFFER_TYPE_PADDING
| GSS_IOV_BUFFER_FLAG_ALLOCATE
;
713 iov
[4].buffer
.length
= 0;
714 iov
[4].buffer
.value
= 0;
715 if (dce_style_flag
) {
716 iov
[5].type
= GSS_IOV_BUFFER_TYPE_EMPTY
;
717 } else if (flags
& USE_HEADER_ONLY
) {
718 iov
[5].type
= GSS_IOV_BUFFER_TYPE_EMPTY
;
720 iov
[5].type
= GSS_IOV_BUFFER_TYPE_TRAILER
| GSS_IOV_BUFFER_FLAG_ALLOCATE
;
722 iov
[5].buffer
.length
= 0;
723 iov
[5].buffer
.value
= 0;
725 maj_stat
= gss_wrap_iov(&min_stat
, cctx
, dce_style_flag
|| flags
& USE_CONF
, 0, &conf_state
,
727 if (maj_stat
!= GSS_S_COMPLETE
)
728 errx(1, "gss_wrap_iov failed");
731 iov
[0].buffer
.length
+
732 iov
[1].buffer
.length
+
733 iov
[2].buffer
.length
+
734 iov
[3].buffer
.length
+
735 iov
[4].buffer
.length
+
736 iov
[5].buffer
.length
;
737 token
.data
= emalloc(token
.length
);
741 if (iov
[0].buffer
.length
)
742 memcpy(p
, iov
[0].buffer
.value
, iov
[0].buffer
.length
);
743 p
+= iov
[0].buffer
.length
;
745 if (iov
[1].buffer
.length
)
746 memcpy(p
, iov
[1].buffer
.value
, iov
[1].buffer
.length
);
747 p
+= iov
[1].buffer
.length
;
749 if (iov
[2].buffer
.length
)
750 memcpy(p
, iov
[2].buffer
.value
, iov
[2].buffer
.length
);
751 p
+= iov
[2].buffer
.length
;
753 if (iov
[3].buffer
.length
)
754 memcpy(p
, iov
[3].buffer
.value
, iov
[3].buffer
.length
);
755 p
+= iov
[3].buffer
.length
;
757 if (iov
[4].buffer
.length
)
758 memcpy(p
, iov
[4].buffer
.value
, iov
[4].buffer
.length
);
759 p
+= iov
[4].buffer
.length
;
761 if (iov
[5].buffer
.length
)
762 memcpy(p
, iov
[5].buffer
.value
, iov
[5].buffer
.length
);
763 p
+= iov
[5].buffer
.length
;
765 assert(p
- ((unsigned char *)token
.data
) == token
.length
);
767 if ((flags
& (USE_SIGN_ONLY
|FORCE_IOV
)) == 0) {
768 gss_buffer_desc input
, output
;
770 input
.value
= token
.data
;
771 input
.length
= token
.length
;
773 maj_stat
= gss_unwrap(&min_stat
, sctx
, &input
,
774 &output
, &conf_state2
, &qop_state
);
776 if (maj_stat
!= GSS_S_COMPLETE
)
777 errx(1, "gss_unwrap from gss_wrap_iov failed: %s",
778 gssapi_err(maj_stat
, min_stat
, mechoid
));
780 gss_release_buffer(&min_stat
, &output
);
782 maj_stat
= gss_unwrap_iov(&min_stat
, sctx
, &conf_state2
, &qop_state
,
785 if (maj_stat
!= GSS_S_COMPLETE
)
786 errx(1, "gss_unwrap_iov failed: %x %s", flags
,
787 gssapi_err(maj_stat
, min_stat
, mechoid
));
790 if (conf_state2
!= conf_state
)
791 errx(1, "conf state wrong for iov: %x", flags
);
793 gss_release_iov_buffer(&min_stat
, iov
, iov_len
);
799 wrapunwrap_aead(gss_ctx_id_t cctx
, gss_ctx_id_t sctx
, int flags
, gss_OID mechoid
)
801 gss_buffer_desc token
, assoc
, message
= GSS_C_EMPTY_BUFFER
;
802 gss_buffer_desc output
;
803 OM_uint32 min_stat
, maj_stat
;
805 int conf_state
, conf_state2
;
806 char assoc_data
[9] = "ABCheader";
807 char token_data
[16] = "0123456789abcdef";
809 if (flags
& USE_SIGN_ONLY
) {
810 assoc
.value
= assoc_data
;
817 token
.value
= token_data
;
820 maj_stat
= gss_wrap_aead(&min_stat
, cctx
, dce_style_flag
|| flags
& USE_CONF
,
821 GSS_C_QOP_DEFAULT
, &assoc
, &token
,
822 &conf_state
, &message
);
823 if (maj_stat
!= GSS_S_COMPLETE
)
824 errx(1, "gss_wrap_aead failed");
826 if ((flags
& (USE_SIGN_ONLY
|FORCE_IOV
)) == 0) {
827 maj_stat
= gss_unwrap(&min_stat
, sctx
, &message
,
828 &output
, &conf_state2
, &qop_state
);
830 if (maj_stat
!= GSS_S_COMPLETE
)
831 errx(1, "gss_unwrap from gss_wrap_aead failed: %s",
832 gssapi_err(maj_stat
, min_stat
, mechoid
));
834 maj_stat
= gss_unwrap_aead(&min_stat
, sctx
, &message
, &assoc
,
835 &output
, &conf_state2
, &qop_state
);
836 if (maj_stat
!= GSS_S_COMPLETE
)
837 errx(1, "gss_unwrap_aead failed: %x %s", flags
,
838 gssapi_err(maj_stat
, min_stat
, mechoid
));
841 if (output
.length
!= token
.length
)
842 errx(1, "plaintext length wrong for aead");
843 else if (memcmp(output
.value
, token
.value
, token
.length
) != 0)
844 errx(1, "plaintext wrong for aead");
845 if (conf_state2
!= conf_state
)
846 errx(1, "conf state wrong for aead: %x", flags
);
848 gss_release_buffer(&min_stat
, &message
);
849 gss_release_buffer(&min_stat
, &output
);
853 getverifymic(gss_ctx_id_t cctx
, gss_ctx_id_t sctx
, gss_OID mechoid
)
855 gss_buffer_desc input_token
, output_token
;
856 OM_uint32 min_stat
, maj_stat
;
859 input_token
.value
= "bar";
860 input_token
.length
= 3;
862 maj_stat
= gss_get_mic(&min_stat
, cctx
, 0, &input_token
,
864 if (maj_stat
!= GSS_S_COMPLETE
)
865 errx(1, "gss_get_mic failed: %s",
866 gssapi_err(maj_stat
, min_stat
, mechoid
));
868 maj_stat
= gss_verify_mic(&min_stat
, sctx
, &input_token
,
869 &output_token
, &qop_state
);
870 if (maj_stat
!= GSS_S_COMPLETE
)
871 errx(1, "gss_verify_mic failed: %s",
872 gssapi_err(maj_stat
, min_stat
, mechoid
));
874 gss_release_buffer(&min_stat
, &output_token
);
880 gss_ctx_id_t ctx
= GSS_C_NO_CONTEXT
;
881 gss_cred_id_t cred
= GSS_C_NO_CREDENTIAL
;
882 gss_name_t name
= GSS_C_NO_NAME
;
883 gss_OID_set oidset
= GSS_C_NO_OID_SET
;
886 gss_delete_sec_context(&junk
, &ctx
, NULL
);
887 gss_release_cred(&junk
, &cred
);
888 gss_release_name(&junk
, &name
);
889 gss_release_oid_set(&junk
, &oidset
);
896 static struct getargs args
[] = {
897 {"name-type",0, arg_string
, &type_string
, "type of name", NULL
},
898 {"mech-type",0, arg_string
, &mech_string
, "mech type (name)", NULL
},
899 {"mech-types",0, arg_string
, &mechs_string
, "mech types (names)", NULL
},
900 {"ret-mech-type",0, arg_string
, &ret_mech_string
,
901 "type of return mech", NULL
},
902 {"dns-canonicalize",0,arg_negative_flag
, &dns_canon_flag
,
903 "use dns to canonicalize", NULL
},
904 {"mutual-auth",0, arg_flag
, &mutual_auth_flag
,"mutual auth", NULL
},
905 {"client-ccache",0, arg_string
, &client_ccache
, "client credentials cache", NULL
},
906 {"client-keytab",0, arg_string
, &client_keytab
, "client keytab", NULL
},
907 {"client-name", 0, arg_string
, &client_name
, "client name", NULL
},
908 {"client-password", 0, arg_string
, &client_password
, "client password", NULL
},
909 {"anonymous", 0, arg_flag
, &anon_flag
, "anonymous auth", NULL
},
910 {"i-channel-bound",0, arg_flag
, &i_channel_bound
, "initiator channel bound", NULL
},
911 {"i-channel-bindings", 0, arg_string
, &i_channel_bindings
, "initiator channel binding data", NULL
},
912 {"a-channel-bindings", 0, arg_string
, &a_channel_bindings
, "acceptor channel binding data", NULL
},
913 {"limit-enctype",0, arg_string
, &limit_enctype_string
, "enctype", NULL
},
914 {"dce-style",0, arg_flag
, &dce_style_flag
, "dce-style", NULL
},
915 {"wrapunwrap",0, arg_flag
, &wrapunwrap_flag
, "wrap/unwrap", NULL
},
916 {"iov", 0, arg_flag
, &iov_flag
, "wrap/unwrap iov", NULL
},
917 {"aead", 0, arg_flag
, &aead_flag
, "wrap/unwrap aead", NULL
},
918 {"getverifymic",0, arg_flag
, &getverifymic_flag
,
919 "get and verify mic", NULL
},
920 {"delegate",0, arg_flag
, &deleg_flag
, "delegate credential", NULL
},
921 {"policy-delegate",0, arg_flag
, &policy_deleg_flag
, "policy delegate credential", NULL
},
922 {"server-no-delegate",0, arg_flag
, &server_no_deleg_flag
,
923 "server should get a credential", NULL
},
924 {"export-import-context",0, arg_flag
, &ei_ctx_flag
, "test export/import context", NULL
},
925 {"export-import-cred",0, arg_flag
, &ei_cred_flag
, "test export/import cred", NULL
},
926 {"localname",0, arg_string
, &localname_string
, "expected localname for client", "USERNAME"},
927 {"gsskrb5-acceptor-identity", 0, arg_string
, &gsskrb5_acceptor_identity
, "keytab", NULL
},
928 {"session-enctype", 0, arg_string
, &session_enctype_string
, "enctype", NULL
},
929 {"client-time-offset", 0, arg_integer
, &client_time_offset
, "time", NULL
},
930 {"server-time-offset", 0, arg_integer
, &server_time_offset
, "time", NULL
},
931 {"max-loops", 0, arg_integer
, &max_loops
, "time", NULL
},
932 {"token-split", 0, arg_integer
, &token_split
, "bytes", NULL
},
933 {"on-behalf-of", 0, arg_string
, &on_behalf_of_string
, "principal",
934 "send authenticator authz-data AD-ON-BEHALF-OF" },
935 {"version", 0, arg_flag
, &version_flag
, "print version", NULL
},
936 {"verbose", 'v', arg_flag
, &verbose_flag
, "verbose", NULL
},
937 {"help", 0, arg_flag
, &help_flag
, NULL
, NULL
}
943 arg_printusage (args
, sizeof(args
)/sizeof(*args
),
944 NULL
, "service@host");
949 main(int argc
, char **argv
)
952 OM_uint32 min_stat
, maj_stat
;
953 gss_ctx_id_t cctx
, sctx
;
955 gss_OID nameoid
, mechoid
, actual_mech
, actual_mech2
;
956 gss_cred_id_t client_cred
= GSS_C_NO_CREDENTIAL
, deleg_cred
= GSS_C_NO_CREDENTIAL
;
957 gss_name_t cname
= GSS_C_NO_NAME
;
958 gss_buffer_desc credential_data
= GSS_C_EMPTY_BUFFER
;
959 gss_OID_desc oids
[7];
960 gss_OID_set_desc mechoid_descs
;
961 gss_OID_set mechoids
= GSS_C_NO_OID_SET
;
962 gss_key_value_element_desc client_cred_elements
[2];
963 gss_key_value_set_desc client_cred_store
;
964 gss_OID_set actual_mechs
= GSS_C_NO_OID_SET
;
966 setprogname(argv
[0]);
968 if (krb5_init_context(&context
))
969 errx(1, "krb5_init_context");
971 cctx
= sctx
= GSS_C_NO_CONTEXT
;
973 if(getarg(args
, sizeof(args
) / sizeof(args
[0]), argc
, argv
, &optidx
))
990 if (dns_canon_flag
!= -1)
991 gsskrb5_set_dns_canonicalize(dns_canon_flag
);
993 if (type_string
== NULL
)
994 nameoid
= GSS_C_NT_HOSTBASED_SERVICE
;
995 else if (strcmp(type_string
, "hostbased-service") == 0)
996 nameoid
= GSS_C_NT_HOSTBASED_SERVICE
;
997 else if (strcmp(type_string
, "krb5-principal-name") == 0)
998 nameoid
= GSS_KRB5_NT_PRINCIPAL_NAME
;
1000 errx(1, "%s not supported", type_string
);
1002 if (mech_string
== NULL
)
1003 mechoid
= GSS_KRB5_MECHANISM
;
1005 mechoid
= string_to_oid(mech_string
);
1007 if (mechs_string
== NULL
) {
1009 * We ought to be able to use the OID set of the one mechanism
1010 * OID given. But there's some breakage that conspires to make
1011 * that fail though it should succeed:
1013 * - the NTLM gss_acquire_cred() refuses to work with
1014 * desired_name == GSS_C_NO_NAME
1015 * - gss_acquire_cred() with desired_mechs == GSS_C_NO_OID_SET
1016 * does work here because we happen to have Kerberos
1017 * credentials in check-ntlm, and the subsequent
1018 * gss_init_sec_context() call finds no cred element for NTLM
1019 * but plows on anyways, surprisingly enough, and then the
1020 * NTLM gss_init_sec_context() just works.
1022 * In summary, there's some breakage in gss_init_sec_context()
1023 * and some breakage in NTLM that conspires against us here.
1025 * We work around this in check-ntlm and check-spnego by adding
1026 * --client-name=user1@${R} to the invocations of this test
1027 * program that require it.
1030 mechoid_descs
.elements
= &oids
[0];
1031 mechoid_descs
.count
= 1;
1032 mechoids
= &mechoid_descs
;
1034 string_to_oids(&mechoids
, mechs_string
);
1037 if (gsskrb5_acceptor_identity
) {
1038 /* XXX replace this with cred store, but test suites will need work */
1039 maj_stat
= gsskrb5_register_acceptor_identity(gsskrb5_acceptor_identity
);
1041 errx(1, "gsskrb5_acceptor_identity: %s",
1042 gssapi_err(maj_stat
, 0, GSS_C_NO_OID
));
1045 if (client_password
&& (client_ccache
|| client_keytab
)) {
1046 errx(1, "password option mutually exclusive with ccache or keytab option");
1049 if (client_password
) {
1050 credential_data
.value
= client_password
;
1051 credential_data
.length
= strlen(client_password
);
1054 client_cred_store
.count
= 0;
1055 client_cred_store
.elements
= client_cred_elements
;
1057 if (client_ccache
) {
1058 client_cred_store
.elements
[client_cred_store
.count
].key
= "ccache";
1059 client_cred_store
.elements
[client_cred_store
.count
].value
= client_ccache
;
1061 client_cred_store
.count
++;
1064 if (client_keytab
) {
1065 client_cred_store
.elements
[client_cred_store
.count
].key
= "client_keytab";
1066 client_cred_store
.elements
[client_cred_store
.count
].value
= client_keytab
;
1068 client_cred_store
.count
++;
1074 cn
.value
= client_name
;
1075 cn
.length
= strlen(client_name
);
1077 maj_stat
= gss_import_name(&min_stat
, &cn
, GSS_C_NT_USER_NAME
, &cname
);
1079 errx(1, "gss_import_name: %s",
1080 gssapi_err(maj_stat
, min_stat
, GSS_C_NO_OID
));
1083 if (client_password
) {
1084 maj_stat
= gss_acquire_cred_with_password(&min_stat
,
1093 if (GSS_ERROR(maj_stat
)) {
1094 if (mechoids
!= GSS_C_NO_OID_SET
&& mechoids
->count
== 1)
1095 mechoid
= &mechoids
->elements
[0];
1097 mechoid
= GSS_C_NO_OID
;
1098 errx(1, "gss_acquire_cred_with_password: %s",
1099 gssapi_err(maj_stat
, min_stat
, mechoid
));
1102 maj_stat
= gss_acquire_cred_from(&min_stat
,
1107 client_cred_store
.count
? &client_cred_store
1108 : GSS_C_NO_CRED_STORE
,
1112 if (GSS_ERROR(maj_stat
) && !anon_flag
)
1113 errx(1, "gss_acquire_cred: %s",
1114 gssapi_err(maj_stat
, min_stat
, GSS_C_NO_OID
));
1117 gss_release_name(&min_stat
, &cname
);
1122 printf("cred mechs:");
1123 for (i
= 0; i
< actual_mechs
->count
; i
++)
1124 printf(" %s", gss_oid_to_name(&actual_mechs
->elements
[i
]));
1128 if (gss_oid_equal(mechoid
, GSS_SPNEGO_MECHANISM
) && mechs_string
) {
1129 maj_stat
= gss_set_neg_mechs(&min_stat
, client_cred
, mechoids
);
1130 if (GSS_ERROR(maj_stat
))
1131 errx(1, "gss_set_neg_mechs: %s",
1132 gssapi_err(maj_stat
, min_stat
, GSS_SPNEGO_MECHANISM
));
1134 mechoid_descs
.elements
= GSS_SPNEGO_MECHANISM
;
1135 mechoid_descs
.count
= 1;
1136 mechoids
= &mechoid_descs
;
1140 gss_cred_id_t cred2
= GSS_C_NO_CREDENTIAL
;
1143 maj_stat
= gss_export_cred(&min_stat
, client_cred
, &cb
);
1144 if (maj_stat
!= GSS_S_COMPLETE
)
1145 errx(1, "export cred failed: %s",
1146 gssapi_err(maj_stat
, min_stat
, NULL
));
1148 maj_stat
= gss_import_cred(&min_stat
, &cb
, &cred2
);
1149 if (maj_stat
!= GSS_S_COMPLETE
)
1150 errx(1, "import cred failed: %s",
1151 gssapi_err(maj_stat
, min_stat
, NULL
));
1153 gss_release_buffer(&min_stat
, &cb
);
1154 gss_release_cred(&min_stat
, &client_cred
);
1155 client_cred
= cred2
;
1158 if (limit_enctype_string
) {
1159 krb5_error_code ret
;
1161 ret
= krb5_string_to_enctype(context
,
1162 limit_enctype_string
,
1165 krb5_err(context
, 1, ret
, "krb5_string_to_enctype");
1169 if (limit_enctype
) {
1170 if (client_cred
== NULL
)
1171 errx(1, "client_cred missing");
1173 maj_stat
= gss_krb5_set_allowable_enctypes(&min_stat
, client_cred
,
1176 errx(1, "gss_krb5_set_allowable_enctypes: %s",
1177 gssapi_err(maj_stat
, min_stat
, GSS_C_NO_OID
));
1180 loop(mechoid
, nameoid
, argv
[0], client_cred
,
1181 &sctx
, &cctx
, &actual_mech
, &deleg_cred
);
1184 printf("resulting mech: %s\n", gss_oid_to_name(actual_mech
));
1186 if (ret_mech_string
) {
1189 retoid
= string_to_oid(ret_mech_string
);
1191 if (gss_oid_equal(retoid
, actual_mech
) == 0)
1192 errx(1, "actual_mech mech is not the expected type %s",
1196 /* XXX should be actual_mech */
1197 if (gss_oid_equal(mechoid
, GSS_KRB5_MECHANISM
)) {
1199 gss_buffer_desc authz_data
;
1200 gss_buffer_desc in
, out1
, out2
;
1201 krb5_keyblock
*keyblock
, *keyblock2
;
1203 krb5_error_code ret
;
1205 ret
= krb5_timeofday(context
, &now
);
1207 errx(1, "krb5_timeofday failed");
1210 maj_stat
= gss_krb5_export_lucid_sec_context(&min_stat
,
1214 if (maj_stat
!= GSS_S_COMPLETE
)
1215 errx(1, "gss_krb5_export_lucid_sec_context failed: %s",
1216 gssapi_err(maj_stat
, min_stat
, actual_mech
));
1219 maj_stat
= gss_krb5_free_lucid_sec_context(&maj_stat
, ctx
);
1220 if (maj_stat
!= GSS_S_COMPLETE
)
1221 errx(1, "gss_krb5_free_lucid_sec_context failed: %s",
1222 gssapi_err(maj_stat
, min_stat
, actual_mech
));
1225 maj_stat
= gss_krb5_export_lucid_sec_context(&min_stat
,
1229 if (maj_stat
!= GSS_S_COMPLETE
)
1230 errx(1, "gss_krb5_export_lucid_sec_context failed: %s",
1231 gssapi_err(maj_stat
, min_stat
, actual_mech
));
1232 maj_stat
= gss_krb5_free_lucid_sec_context(&min_stat
, ctx
);
1233 if (maj_stat
!= GSS_S_COMPLETE
)
1234 errx(1, "gss_krb5_free_lucid_sec_context failed: %s",
1235 gssapi_err(maj_stat
, min_stat
, actual_mech
));
1237 maj_stat
= gsskrb5_extract_authtime_from_sec_context(&min_stat
,
1240 if (maj_stat
!= GSS_S_COMPLETE
)
1241 errx(1, "gsskrb5_extract_authtime_from_sec_context failed: %s",
1242 gssapi_err(maj_stat
, min_stat
, actual_mech
));
1245 errx(1, "gsskrb5_extract_authtime_from_sec_context failed: "
1246 "time authtime is before now: %ld %ld",
1247 (long)sc_time
, (long)now
);
1249 maj_stat
= gsskrb5_extract_service_keyblock(&min_stat
,
1252 if (maj_stat
!= GSS_S_COMPLETE
)
1253 errx(1, "gsskrb5_export_service_keyblock failed: %s",
1254 gssapi_err(maj_stat
, min_stat
, actual_mech
));
1256 krb5_free_keyblock(context
, keyblock
);
1258 maj_stat
= gsskrb5_get_subkey(&min_stat
,
1261 if (maj_stat
!= GSS_S_COMPLETE
1262 && (!(maj_stat
== GSS_S_FAILURE
&& min_stat
== GSS_KRB5_S_KG_NO_SUBKEY
)))
1263 errx(1, "gsskrb5_get_subkey server failed: %s",
1264 gssapi_err(maj_stat
, min_stat
, actual_mech
));
1266 if (maj_stat
!= GSS_S_COMPLETE
)
1268 else if (limit_enctype
&& keyblock
->keytype
!= limit_enctype
)
1269 errx(1, "gsskrb5_get_subkey wrong enctype");
1271 maj_stat
= gsskrb5_get_subkey(&min_stat
,
1274 if (maj_stat
!= GSS_S_COMPLETE
1275 && (!(maj_stat
== GSS_S_FAILURE
&& min_stat
== GSS_KRB5_S_KG_NO_SUBKEY
)))
1276 errx(1, "gsskrb5_get_subkey client failed: %s",
1277 gssapi_err(maj_stat
, min_stat
, actual_mech
));
1279 if (maj_stat
!= GSS_S_COMPLETE
)
1281 else if (limit_enctype
&& keyblock
&& keyblock
->keytype
!= limit_enctype
)
1282 errx(1, "gsskrb5_get_subkey wrong enctype");
1284 if (keyblock
|| keyblock2
) {
1285 if (keyblock
== NULL
)
1286 errx(1, "server missing token keyblock");
1287 if (keyblock2
== NULL
)
1288 errx(1, "client missing token keyblock");
1290 if (keyblock
->keytype
!= keyblock2
->keytype
)
1291 errx(1, "enctype mismatch");
1292 if (keyblock
->keyvalue
.length
!= keyblock2
->keyvalue
.length
)
1293 errx(1, "key length mismatch");
1294 if (memcmp(keyblock
->keyvalue
.data
, keyblock2
->keyvalue
.data
,
1295 keyblock2
->keyvalue
.length
) != 0)
1296 errx(1, "key data mismatch");
1299 if (session_enctype_string
) {
1300 krb5_enctype enctype
;
1302 ret
= krb5_string_to_enctype(context
,
1303 session_enctype_string
,
1307 krb5_err(context
, 1, ret
, "krb5_string_to_enctype");
1309 if (keyblock
&& enctype
!= keyblock
->keytype
)
1310 errx(1, "keytype is not the expected %d != %d",
1311 (int)enctype
, (int)keyblock2
->keytype
);
1315 krb5_free_keyblock(context
, keyblock
);
1317 krb5_free_keyblock(context
, keyblock2
);
1319 maj_stat
= gsskrb5_get_initiator_subkey(&min_stat
,
1322 if (maj_stat
!= GSS_S_COMPLETE
1323 && (!(maj_stat
== GSS_S_FAILURE
&& min_stat
== GSS_KRB5_S_KG_NO_SUBKEY
)))
1324 errx(1, "gsskrb5_get_initiator_subkey failed: %s",
1325 gssapi_err(maj_stat
, min_stat
, actual_mech
));
1327 if (maj_stat
== GSS_S_COMPLETE
) {
1329 if (limit_enctype
&& keyblock
->keytype
!= limit_enctype
)
1330 errx(1, "gsskrb5_get_initiator_subkey wrong enctype");
1331 krb5_free_keyblock(context
, keyblock
);
1334 maj_stat
= gsskrb5_extract_authz_data_from_sec_context(&min_stat
,
1338 if (maj_stat
== GSS_S_COMPLETE
)
1339 gss_release_buffer(&min_stat
, &authz_data
);
1342 memset(&out1
, 0, sizeof(out1
));
1343 memset(&out2
, 0, sizeof(out2
));
1348 gss_pseudo_random(&min_stat
, sctx
, GSS_C_PRF_KEY_FULL
, &in
,
1350 gss_pseudo_random(&min_stat
, cctx
, GSS_C_PRF_KEY_FULL
, &in
,
1353 if (out1
.length
!= out2
.length
)
1354 errx(1, "prf len mismatch");
1355 if (out1
.length
&& memcmp(out1
.value
, out2
.value
, out1
.length
) != 0)
1356 errx(1, "prf data mismatch");
1358 gss_release_buffer(&min_stat
, &out1
);
1360 gss_pseudo_random(&min_stat
, sctx
, GSS_C_PRF_KEY_FULL
, &in
,
1363 if (out1
.length
!= out2
.length
)
1364 errx(1, "prf len mismatch");
1365 if (out1
.length
&& memcmp(out1
.value
, out2
.value
, out1
.length
) != 0)
1366 errx(1, "prf data mismatch");
1368 gss_release_buffer(&min_stat
, &out1
);
1369 gss_release_buffer(&min_stat
, &out2
);
1374 gss_pseudo_random(&min_stat
, sctx
, GSS_C_PRF_KEY_PARTIAL
, &in
,
1376 gss_pseudo_random(&min_stat
, cctx
, GSS_C_PRF_KEY_PARTIAL
, &in
,
1379 if (out1
.length
!= out2
.length
)
1380 errx(1, "prf len mismatch");
1381 if (memcmp(out1
.value
, out2
.value
, out1
.length
) != 0)
1382 errx(1, "prf data mismatch");
1384 gss_release_buffer(&min_stat
, &out1
);
1385 gss_release_buffer(&min_stat
, &out2
);
1387 wrapunwrap_flag
= 1;
1388 getverifymic_flag
= 1;
1392 gss_buffer_desc ctx_token
= GSS_C_EMPTY_BUFFER
;
1394 maj_stat
= gss_export_sec_context(&min_stat
, &cctx
, &ctx_token
);
1395 if (maj_stat
!= GSS_S_COMPLETE
)
1396 errx(1, "export client context failed: %s",
1397 gssapi_err(maj_stat
, min_stat
, NULL
));
1399 if (cctx
!= GSS_C_NO_CONTEXT
)
1400 errx(1, "export client context did not release it");
1402 maj_stat
= gss_import_sec_context(&min_stat
, &ctx_token
, &cctx
);
1403 if (maj_stat
!= GSS_S_COMPLETE
)
1404 errx(1, "import client context failed: %s",
1405 gssapi_err(maj_stat
, min_stat
, NULL
));
1407 gss_release_buffer(&min_stat
, &ctx_token
);
1409 maj_stat
= gss_export_sec_context(&min_stat
, &sctx
, &ctx_token
);
1410 if (maj_stat
!= GSS_S_COMPLETE
)
1411 errx(1, "export server context failed: %s",
1412 gssapi_err(maj_stat
, min_stat
, NULL
));
1414 if (sctx
!= GSS_C_NO_CONTEXT
)
1415 errx(1, "export server context did not release it");
1417 maj_stat
= gss_import_sec_context(&min_stat
, &ctx_token
, &sctx
);
1418 if (maj_stat
!= GSS_S_COMPLETE
)
1419 errx(1, "import server context failed: %s",
1420 gssapi_err(maj_stat
, min_stat
, NULL
));
1422 gss_release_buffer(&min_stat
, &ctx_token
);
1425 if (wrapunwrap_flag
) {
1426 wrapunwrap(cctx
, sctx
, 0, actual_mech
);
1427 wrapunwrap(cctx
, sctx
, 1, actual_mech
);
1428 wrapunwrap(sctx
, cctx
, 0, actual_mech
);
1429 wrapunwrap(sctx
, cctx
, 1, actual_mech
);
1433 wrapunwrap_iov(cctx
, sctx
, 0, actual_mech
);
1434 wrapunwrap_iov(cctx
, sctx
, USE_HEADER_ONLY
|FORCE_IOV
, actual_mech
);
1435 wrapunwrap_iov(cctx
, sctx
, USE_HEADER_ONLY
, actual_mech
);
1436 wrapunwrap_iov(cctx
, sctx
, USE_CONF
, actual_mech
);
1437 wrapunwrap_iov(cctx
, sctx
, USE_CONF
|USE_HEADER_ONLY
, actual_mech
);
1439 wrapunwrap_iov(cctx
, sctx
, FORCE_IOV
, actual_mech
);
1440 wrapunwrap_iov(cctx
, sctx
, USE_CONF
|FORCE_IOV
, actual_mech
);
1441 wrapunwrap_iov(cctx
, sctx
, USE_HEADER_ONLY
|FORCE_IOV
, actual_mech
);
1442 wrapunwrap_iov(cctx
, sctx
, USE_CONF
|USE_HEADER_ONLY
|FORCE_IOV
, actual_mech
);
1444 wrapunwrap_iov(cctx
, sctx
, USE_SIGN_ONLY
|FORCE_IOV
, actual_mech
);
1445 wrapunwrap_iov(cctx
, sctx
, USE_CONF
|USE_SIGN_ONLY
|FORCE_IOV
, actual_mech
);
1446 wrapunwrap_iov(cctx
, sctx
, USE_CONF
|USE_HEADER_ONLY
|USE_SIGN_ONLY
|FORCE_IOV
, actual_mech
);
1449 wrapunwrap_iov(cctx
, sctx
, 0, actual_mech
);
1450 wrapunwrap_iov(cctx
, sctx
, FORCE_IOV
, actual_mech
);
1452 wrapunwrap_iov(cctx
, sctx
, USE_CONF
, actual_mech
);
1453 wrapunwrap_iov(cctx
, sctx
, USE_CONF
|FORCE_IOV
, actual_mech
);
1455 wrapunwrap_iov(cctx
, sctx
, USE_SIGN_ONLY
, actual_mech
);
1456 wrapunwrap_iov(cctx
, sctx
, USE_SIGN_ONLY
|FORCE_IOV
, actual_mech
);
1458 wrapunwrap_iov(cctx
, sctx
, USE_CONF
|USE_SIGN_ONLY
, actual_mech
);
1459 wrapunwrap_iov(cctx
, sctx
, USE_CONF
|USE_SIGN_ONLY
|FORCE_IOV
, actual_mech
);
1461 wrapunwrap_iov(cctx
, sctx
, USE_HEADER_ONLY
, actual_mech
);
1462 wrapunwrap_iov(cctx
, sctx
, USE_HEADER_ONLY
|FORCE_IOV
, actual_mech
);
1464 wrapunwrap_iov(cctx
, sctx
, USE_CONF
|USE_HEADER_ONLY
, actual_mech
);
1465 wrapunwrap_iov(cctx
, sctx
, USE_CONF
|USE_HEADER_ONLY
|FORCE_IOV
, actual_mech
);
1467 wrapunwrap_iov(cctx
, sctx
, NO_DATA
, actual_mech
);
1468 wrapunwrap_iov(cctx
, sctx
, NO_DATA
|USE_HEADER_ONLY
|FORCE_IOV
, actual_mech
);
1469 wrapunwrap_iov(cctx
, sctx
, NO_DATA
|USE_HEADER_ONLY
, actual_mech
);
1470 wrapunwrap_iov(cctx
, sctx
, NO_DATA
|USE_CONF
, actual_mech
);
1471 wrapunwrap_iov(cctx
, sctx
, NO_DATA
|USE_CONF
|USE_HEADER_ONLY
, actual_mech
);
1473 wrapunwrap_iov(cctx
, sctx
, NO_DATA
|FORCE_IOV
, actual_mech
);
1474 wrapunwrap_iov(cctx
, sctx
, NO_DATA
|USE_CONF
|FORCE_IOV
, actual_mech
);
1475 wrapunwrap_iov(cctx
, sctx
, NO_DATA
|USE_HEADER_ONLY
|FORCE_IOV
, actual_mech
);
1476 wrapunwrap_iov(cctx
, sctx
, NO_DATA
|USE_CONF
|USE_HEADER_ONLY
|FORCE_IOV
, actual_mech
);
1478 wrapunwrap_iov(cctx
, sctx
, NO_DATA
|USE_SIGN_ONLY
|FORCE_IOV
, actual_mech
);
1479 wrapunwrap_iov(cctx
, sctx
, NO_DATA
|USE_CONF
|USE_SIGN_ONLY
|FORCE_IOV
, actual_mech
);
1480 wrapunwrap_iov(cctx
, sctx
, NO_DATA
|USE_CONF
|USE_HEADER_ONLY
|USE_SIGN_ONLY
|FORCE_IOV
, actual_mech
);
1483 wrapunwrap_iov(cctx
, sctx
, NO_DATA
, actual_mech
);
1484 wrapunwrap_iov(cctx
, sctx
, NO_DATA
|FORCE_IOV
, actual_mech
);
1486 wrapunwrap_iov(cctx
, sctx
, NO_DATA
|USE_CONF
, actual_mech
);
1487 wrapunwrap_iov(cctx
, sctx
, NO_DATA
|USE_CONF
|FORCE_IOV
, actual_mech
);
1489 wrapunwrap_iov(cctx
, sctx
, NO_DATA
|USE_SIGN_ONLY
, actual_mech
);
1490 wrapunwrap_iov(cctx
, sctx
, NO_DATA
|USE_SIGN_ONLY
|FORCE_IOV
, actual_mech
);
1492 wrapunwrap_iov(cctx
, sctx
, NO_DATA
|USE_CONF
|USE_SIGN_ONLY
, actual_mech
);
1493 wrapunwrap_iov(cctx
, sctx
, NO_DATA
|USE_CONF
|USE_SIGN_ONLY
|FORCE_IOV
, actual_mech
);
1495 wrapunwrap_iov(cctx
, sctx
, NO_DATA
|USE_HEADER_ONLY
, actual_mech
);
1496 wrapunwrap_iov(cctx
, sctx
, NO_DATA
|USE_HEADER_ONLY
|FORCE_IOV
, actual_mech
);
1498 wrapunwrap_iov(cctx
, sctx
, NO_DATA
|USE_CONF
|USE_HEADER_ONLY
, actual_mech
);
1499 wrapunwrap_iov(cctx
, sctx
, NO_DATA
|USE_CONF
|USE_HEADER_ONLY
|FORCE_IOV
, actual_mech
);
1503 wrapunwrap_aead(cctx
, sctx
, 0, actual_mech
);
1504 wrapunwrap_aead(cctx
, sctx
, USE_CONF
, actual_mech
);
1506 wrapunwrap_aead(cctx
, sctx
, FORCE_IOV
, actual_mech
);
1507 wrapunwrap_aead(cctx
, sctx
, USE_CONF
|FORCE_IOV
, actual_mech
);
1509 wrapunwrap_aead(cctx
, sctx
, USE_SIGN_ONLY
|FORCE_IOV
, actual_mech
);
1510 wrapunwrap_aead(cctx
, sctx
, USE_CONF
|USE_SIGN_ONLY
|FORCE_IOV
, actual_mech
);
1512 wrapunwrap_aead(cctx
, sctx
, 0, actual_mech
);
1513 wrapunwrap_aead(cctx
, sctx
, FORCE_IOV
, actual_mech
);
1515 wrapunwrap_aead(cctx
, sctx
, USE_CONF
, actual_mech
);
1516 wrapunwrap_aead(cctx
, sctx
, USE_CONF
|FORCE_IOV
, actual_mech
);
1518 wrapunwrap_aead(cctx
, sctx
, USE_SIGN_ONLY
, actual_mech
);
1519 wrapunwrap_aead(cctx
, sctx
, USE_SIGN_ONLY
|FORCE_IOV
, actual_mech
);
1521 wrapunwrap_aead(cctx
, sctx
, USE_CONF
|USE_SIGN_ONLY
, actual_mech
);
1522 wrapunwrap_aead(cctx
, sctx
, USE_CONF
|USE_SIGN_ONLY
|FORCE_IOV
, actual_mech
);
1525 if (getverifymic_flag
) {
1526 getverifymic(cctx
, sctx
, actual_mech
);
1527 getverifymic(cctx
, sctx
, actual_mech
);
1528 getverifymic(sctx
, cctx
, actual_mech
);
1529 getverifymic(sctx
, cctx
, actual_mech
);
1532 gss_delete_sec_context(&min_stat
, &cctx
, NULL
);
1533 gss_delete_sec_context(&min_stat
, &sctx
, NULL
);
1535 if (deleg_cred
!= GSS_C_NO_CREDENTIAL
) {
1536 gss_cred_id_t cred2
= GSS_C_NO_CREDENTIAL
;
1540 printf("checking actual mech (%s) on delegated cred\n",
1541 gss_oid_to_name(actual_mech
));
1542 loop(actual_mech
, nameoid
, argv
[0], deleg_cred
, &sctx
, &cctx
, &actual_mech2
, &cred2
);
1544 gss_delete_sec_context(&min_stat
, &cctx
, NULL
);
1545 gss_delete_sec_context(&min_stat
, &sctx
, NULL
);
1547 gss_release_cred(&min_stat
, &cred2
);
1551 * XXX We can't do this. Delegated credentials only work with
1552 * the actual_mech. We could gss_store_cred the delegated
1553 * credentials *then* gss_add/acquire_cred() with SPNEGO, then
1554 * we could try loop() with those credentials.
1556 /* try again using SPNEGO */
1558 printf("checking spnego on delegated cred\n");
1559 loop(GSS_SPNEGO_MECHANISM
, nameoid
, argv
[0], deleg_cred
, &sctx
, &cctx
,
1560 &actual_mech2
, &cred2
);
1562 gss_delete_sec_context(&min_stat
, &cctx
, NULL
);
1563 gss_delete_sec_context(&min_stat
, &sctx
, NULL
);
1565 gss_release_cred(&min_stat
, &cred2
);
1568 /* check export/import */
1571 maj_stat
= gss_export_cred(&min_stat
, deleg_cred
, &cb
);
1572 if (maj_stat
!= GSS_S_COMPLETE
)
1573 errx(1, "export cred failed: %s",
1574 gssapi_err(maj_stat
, min_stat
, NULL
));
1576 maj_stat
= gss_import_cred(&min_stat
, &cb
, &cred2
);
1577 if (maj_stat
!= GSS_S_COMPLETE
)
1578 errx(1, "import cred failed: %s",
1579 gssapi_err(maj_stat
, min_stat
, NULL
));
1581 gss_release_buffer(&min_stat
, &cb
);
1582 gss_release_cred(&min_stat
, &deleg_cred
);
1585 printf("checking actual mech (%s) on export/imported cred\n",
1586 gss_oid_to_name(actual_mech
));
1587 loop(actual_mech
, nameoid
, argv
[0], cred2
, &sctx
, &cctx
,
1588 &actual_mech2
, &deleg_cred
);
1590 gss_release_cred(&min_stat
, &deleg_cred
);
1592 gss_delete_sec_context(&min_stat
, &cctx
, NULL
);
1593 gss_delete_sec_context(&min_stat
, &sctx
, NULL
);
1597 /* try again using SPNEGO */
1599 printf("checking SPNEGO on export/imported cred\n");
1600 loop(GSS_SPNEGO_MECHANISM
, nameoid
, argv
[0], cred2
, &sctx
, &cctx
,
1601 &actual_mech2
, &deleg_cred
);
1603 gss_release_cred(&min_stat
, &deleg_cred
);
1605 gss_delete_sec_context(&min_stat
, &cctx
, NULL
);
1606 gss_delete_sec_context(&min_stat
, &sctx
, NULL
);
1609 gss_release_cred(&min_stat
, &cred2
);
1612 gss_release_cred(&min_stat
, &deleg_cred
);
1617 gss_release_cred(&min_stat
, &client_cred
);
1618 gss_release_oid_set(&min_stat
, &actual_mechs
);
1619 if (mechoids
!= GSS_C_NO_OID_SET
&& mechoids
!= &mechoid_descs
)
1620 gss_release_oid_set(&min_stat
, &mechoids
);
1623 krb5_free_context(context
);