s4:torture: Fix memory leak
[Samba.git] / third_party / heimdal / lib / gssapi / test_context.c
blobe6d505033c3c52c684eddf1204ac83e7814b4d42
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 #ifdef NOTYET
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
49 #endif
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;
92 static gss_OID
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);
100 return oid;
103 static void
104 string_to_oids(gss_OID_set *oidsetp, char *names)
106 OM_uint32 maj_stat, min_stat;
107 char *name;
108 char *s;
110 if (names[0] == '\0') {
111 *oidsetp = GSS_C_NO_OID_SET;
112 return;
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));
120 } else {
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);
127 name != NULL;
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));
139 static void
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;
144 gss_buffer_desc a;
145 OM_uint32 maj, min;
146 int authenticated, complete, more, name_is_MN, found;
147 gss_OID MN_mech;
148 gss_buffer_set_t attrs = GSS_C_NO_BUFFER_SET;
149 size_t i;
151 krb5_error_code ret;
152 krb5_storage *sp = NULL;
153 uint16_t len = 0, *s;
154 uint64_t tmp;
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) {
170 found++;
171 break;
175 gss_release_buffer_set(&min, &attrs);
177 if (!found)
178 errx(1, "gss_inquire_name: attribute %.*s not enumerated",
179 (int)a.length, (char *)a.value);
181 more = 0;
182 maj = gss_get_name_attribute(&min, n, &a, &authenticated, &complete, &v,
183 &dv, &more);
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);
190 if (sp == NULL)
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 */
196 if (ret == 0)
197 ret = krb5_ret_uint16(sp, &len);
198 if (ret || len == 0)
199 errx(1, "show_pac_client_info: invalid PAC logon info length");
201 s = malloc(len);
202 ret = krb5_storage_read(sp, s, len);
203 if (ret != 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;
210 uint16_t *ucs2;
211 size_t u8len;
212 unsigned int flags = WIND_RW_LE;
214 ucs2 = malloc(sizeof(ucs2[0]) * ucs2len);
215 if (ucs2 == NULL)
216 errx(1, "show_pac_client_info: out of memory");
218 ret = wind_ucs2read(s, len, &flags, ucs2, &ucs2len);
219 free(s);
220 if (ret)
221 errx(1, "failed to convert string to UCS-2");
223 ret = wind_ucs2utf8_length(ucs2, ucs2len, &u8len);
224 if (ret)
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);
233 free(ucs2);
234 if (ret)
235 errx(1, "failed to convert to UTF-8");
238 printf("logon name: %s\n", logon_string);
239 free(logon_string);
241 gss_release_buffer(&min, &dv);
242 gss_release_buffer(&min, &v);
245 static void
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;
254 int num_loops = 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;
261 #endif
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;
270 size_t offset = 0;
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;
283 if (anon_flag)
284 flags |= GSS_C_ANON_FLAG;
285 if (dce_style_flag)
286 flags |= GSS_C_DCE_STYLE;
287 if (deleg_flag)
288 flags |= GSS_C_DELEG_FLAG;
289 if (policy_deleg_flag)
290 flags |= GSS_C_DELEG_POLICY_FLAG;
291 if (i_channel_bound)
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,
298 &input_token,
299 nameoid,
300 &gss_target_name);
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;
307 int32_t kret;
308 size_t sz;
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,
315 &e, &sz, kret);
316 if (kret)
317 errx(1, "Could not encode AD-ON-BEHALF-OF AuthorizationDataElement");
318 attr.value =
319 GSS_KRB5_NAME_ATTRIBUTE_BASE_URN "authenticator-authz-data";
320 attr.length =
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,
323 &value);
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));
327 free(value.value);
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) {
353 num_loops++;
354 if (verbose_flag)
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);
376 #endif
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");
401 #endif
403 if (verbose_flag)
404 printf("loop #%d: output_token.length=%zu\n", num_loops,
405 output_token.length);
407 offset = 0;
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) {
417 gss_buffer_desc tmp;
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;
427 } else
428 tmp = output_token;
430 if (verbose_flag)
431 printf("loop #%d: accept offset=%zu len=%zu\n", num_loops,
432 offset, tmp.length);
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,
445 &actual_mech_server,
446 &input_token, &ret_sflags,
447 NULL, deleg_cred);
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);
454 else
455 server_done = 1;
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);
471 if (verbose_flag)
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;
496 attr.value =
497 GSS_KRB5_NAME_ATTRIBUTE_BASE_URN "authz-data#580";
498 attr.length =
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));
519 if (verbose_flag)
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,
528 &lname);
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");
543 if (verbose_flag) {
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);
551 } else
552 warnx("display_name: %s",
553 gssapi_err(maj_stat, min_stat, GSS_C_NO_OID));
554 if (!anon_flag &&
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);
564 if (verbose_flag) {
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);
568 printf("cflags: ");
569 if (ret_cflags & GSS_C_DELEG_FLAG)
570 printf("deleg ");
571 if (ret_cflags & GSS_C_MUTUAL_FLAG)
572 printf("mutual ");
573 if (ret_cflags & GSS_C_REPLAY_FLAG)
574 printf("replay ");
575 if (ret_cflags & GSS_C_SEQUENCE_FLAG)
576 printf("sequence ");
577 if (ret_cflags & GSS_C_CONF_FLAG)
578 printf("conf ");
579 if (ret_cflags & GSS_C_INTEG_FLAG)
580 printf("integ ");
581 if (ret_cflags & GSS_C_ANON_FLAG)
582 printf("anon ");
583 if (ret_cflags & GSS_C_PROT_READY_FLAG)
584 printf("prot-ready ");
585 if (ret_cflags & GSS_C_TRANS_FLAG)
586 printf("trans ");
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 " );
595 printf("\n");
596 printf("sflags: ");
597 if (ret_sflags & GSS_C_CHANNEL_BOUND_FLAG)
598 printf("channel-bound " );
599 printf("\n");
603 static void
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;
608 gss_qop_t qop_state;
609 int conf_state;
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");
632 #endif
635 #define USE_CONF 1
636 #define USE_HEADER_ONLY 2
637 #define USE_SIGN_ONLY 4
638 #define FORCE_IOV 8
639 /* NO_DATA comes from <netdb.h>; we don't use it here; we appropriate it */
640 #ifdef NO_DATA
641 #undef NO_DATA
642 #endif
643 #define NO_DATA 16
645 static void
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;
650 gss_qop_t qop_state;
651 int conf_state, conf_state2;
652 gss_iov_buffer_desc iov[6];
653 unsigned char *p;
654 int iov_len;
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;
664 header.length = 9;
665 trailer.data = trailer_data;
666 trailer.length = 10;
667 } else {
668 header.data = NULL;
669 header.length = 0;
670 trailer.data = NULL;
671 trailer.length = 0;
674 token.data = token_data;
675 token.length = 16;
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;
687 } else {
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;
695 } else {
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;
703 } else {
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;
710 } else {
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;
719 } else {
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,
726 iov, iov_len);
727 if (maj_stat != GSS_S_COMPLETE)
728 errx(1, "gss_wrap_iov failed");
730 token.length =
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);
739 p = token.data;
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);
781 } else {
782 maj_stat = gss_unwrap_iov(&min_stat, sctx, &conf_state2, &qop_state,
783 iov, iov_len);
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);
795 free(token.data);
798 static void
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;
804 gss_qop_t qop_state;
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;
811 assoc.length = 9;
812 } else {
813 assoc.value = NULL;
814 assoc.length = 0;
817 token.value = token_data;
818 token.length = 16;
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));
833 } else {
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);
852 static void
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;
857 gss_qop_t qop_state;
859 input_token.value = "bar";
860 input_token.length = 3;
862 maj_stat = gss_get_mic(&min_stat, cctx, 0, &input_token,
863 &output_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);
877 static void
878 empty_release(void)
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;
884 OM_uint32 junk;
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 }
940 static void
941 usage (int ret)
943 arg_printusage (args, sizeof(args)/sizeof(*args),
944 NULL, "service@host");
945 exit (ret);
949 main(int argc, char **argv)
951 int optidx = 0;
952 OM_uint32 min_stat, maj_stat;
953 gss_ctx_id_t cctx, sctx;
954 void *ctx;
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))
974 usage(1);
976 if (help_flag)
977 usage (0);
979 if(version_flag){
980 print_version(NULL);
981 exit(0);
984 argc -= optidx;
985 argv += optidx;
987 if (argc != 1)
988 usage(1);
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;
999 else
1000 errx(1, "%s not supported", type_string);
1002 if (mech_string == NULL)
1003 mechoid = GSS_KRB5_MECHANISM;
1004 else
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.
1029 oids[0] = *mechoid;
1030 mechoid_descs.elements = &oids[0];
1031 mechoid_descs.count = 1;
1032 mechoids = &mechoid_descs;
1033 } else {
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);
1040 if (maj_stat)
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++;
1071 if (client_name) {
1072 gss_buffer_desc cn;
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);
1078 if (maj_stat)
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,
1085 cname,
1086 &credential_data,
1087 GSS_C_INDEFINITE,
1088 mechoids,
1089 GSS_C_INITIATE,
1090 &client_cred,
1091 &actual_mechs,
1092 NULL);
1093 if (GSS_ERROR(maj_stat)) {
1094 if (mechoids != GSS_C_NO_OID_SET && mechoids->count == 1)
1095 mechoid = &mechoids->elements[0];
1096 else
1097 mechoid = GSS_C_NO_OID;
1098 errx(1, "gss_acquire_cred_with_password: %s",
1099 gssapi_err(maj_stat, min_stat, mechoid));
1101 } else {
1102 maj_stat = gss_acquire_cred_from(&min_stat,
1103 cname,
1104 GSS_C_INDEFINITE,
1105 mechoids,
1106 GSS_C_INITIATE,
1107 client_cred_store.count ? &client_cred_store
1108 : GSS_C_NO_CRED_STORE,
1109 &client_cred,
1110 &actual_mechs,
1111 NULL);
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);
1119 if (verbose_flag) {
1120 size_t i;
1122 printf("cred mechs:");
1123 for (i = 0; i < actual_mechs->count; i++)
1124 printf(" %s", gss_oid_to_name(&actual_mechs->elements[i]));
1125 printf("\n");
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;
1139 if (ei_cred_flag) {
1140 gss_cred_id_t cred2 = GSS_C_NO_CREDENTIAL;
1141 gss_buffer_desc cb;
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,
1163 &limit_enctype);
1164 if (ret)
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,
1174 1, &limit_enctype);
1175 if (maj_stat)
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);
1183 if (verbose_flag)
1184 printf("resulting mech: %s\n", gss_oid_to_name(actual_mech));
1186 if (ret_mech_string) {
1187 gss_OID retoid;
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",
1193 ret_mech_string);
1196 /* XXX should be actual_mech */
1197 if (gss_oid_equal(mechoid, GSS_KRB5_MECHANISM)) {
1198 time_t sc_time;
1199 gss_buffer_desc authz_data;
1200 gss_buffer_desc in, out1, out2;
1201 krb5_keyblock *keyblock, *keyblock2;
1202 krb5_timestamp now;
1203 krb5_error_code ret;
1205 ret = krb5_timeofday(context, &now);
1206 if (ret)
1207 errx(1, "krb5_timeofday failed");
1209 /* client */
1210 maj_stat = gss_krb5_export_lucid_sec_context(&min_stat,
1211 &cctx,
1212 1, /* version */
1213 &ctx);
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));
1224 /* server */
1225 maj_stat = gss_krb5_export_lucid_sec_context(&min_stat,
1226 &sctx,
1227 1, /* version */
1228 &ctx);
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,
1238 sctx,
1239 &sc_time);
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));
1244 if (sc_time > now)
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,
1250 sctx,
1251 &keyblock);
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,
1259 sctx,
1260 &keyblock);
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)
1267 keyblock = NULL;
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,
1272 cctx,
1273 &keyblock2);
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)
1280 keyblock2 = NULL;
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,
1304 &enctype);
1306 if (ret)
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);
1314 if (keyblock)
1315 krb5_free_keyblock(context, keyblock);
1316 if (keyblock2)
1317 krb5_free_keyblock(context, keyblock2);
1319 maj_stat = gsskrb5_get_initiator_subkey(&min_stat,
1320 sctx,
1321 &keyblock);
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,
1335 sctx,
1336 128,
1337 &authz_data);
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));
1345 in.value = "foo";
1346 in.length = 3;
1348 gss_pseudo_random(&min_stat, sctx, GSS_C_PRF_KEY_FULL, &in,
1349 100, &out1);
1350 gss_pseudo_random(&min_stat, cctx, GSS_C_PRF_KEY_FULL, &in,
1351 100, &out2);
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,
1361 100, &out1);
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);
1371 in.value = "bar";
1372 in.length = 3;
1374 gss_pseudo_random(&min_stat, sctx, GSS_C_PRF_KEY_PARTIAL, &in,
1375 100, &out1);
1376 gss_pseudo_random(&min_stat, cctx, GSS_C_PRF_KEY_PARTIAL, &in,
1377 100, &out2);
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;
1391 if (ei_ctx_flag) {
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);
1432 if (iov_flag) {
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);
1448 /* works */
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);
1482 /* works */
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);
1502 if (aead_flag) {
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;
1537 gss_buffer_desc cb;
1539 if (verbose_flag)
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);
1549 #if 0
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 */
1557 if (verbose_flag)
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);
1566 #endif
1568 /* check export/import */
1569 if (ei_cred_flag) {
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);
1584 if (verbose_flag)
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);
1595 #if 0
1596 /* XXX See above */
1597 /* try again using SPNEGO */
1598 if (verbose_flag)
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);
1607 #endif
1609 gss_release_cred(&min_stat, &cred2);
1611 } else {
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);
1621 empty_release();
1623 krb5_free_context(context);
1625 return 0;