1 /* $NetBSD: test_context.c,v 1.1.1.2 2014/04/24 12:45:29 pettai Exp $ */
2
3 /*
4 * Copyright (c) 2006 - 2008 Kungliga Tekniska Högskolan
5 * (Royal Institute of Technology, Stockholm, Sweden).
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 *
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 *
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 *
19 * 3. Neither the name of KTH nor the names of its contributors may be
20 * used to endorse or promote products derived from this software without
21 * specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY KTH AND ITS CONTRIBUTORS ``AS IS'' AND ANY
24 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
26 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL KTH OR ITS CONTRIBUTORS BE
27 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
28 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
29 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
30 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
31 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
32 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
33 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 */
35
36 #include "krb5/gsskrb5_locl.h"
37 #include <err.h>
38 #include <krb5/getarg.h>
39 #include <gssapi/gssapi.h>
40 #include <gssapi/gssapi_krb5.h>
41 #include <gssapi/gssapi_spnego.h>
42 #include <gssapi/gssapi_ntlm.h>
43 #include "test_common.h"
44
45 static char *type_string;
46 static char *mech_string;
47 static char *ret_mech_string;
48 static char *client_name;
49 static char *client_password;
50 static int dns_canon_flag = -1;
51 static int mutual_auth_flag = 0;
52 static int dce_style_flag = 0;
53 static int wrapunwrap_flag = 0;
54 static int iov_flag = 0;
55 static int getverifymic_flag = 0;
56 static int deleg_flag = 0;
57 static int policy_deleg_flag = 0;
58 static int server_no_deleg_flag = 0;
59 static int ei_flag = 0;
60 static char *gsskrb5_acceptor_identity = NULL;
61 static char *session_enctype_string = NULL;
62 static int client_time_offset = 0;
63 static int server_time_offset = 0;
64 static int max_loops = 0;
65 static char *limit_enctype_string = NULL;
66 static int version_flag = 0;
67 static int verbose_flag = 0;
68 static int help_flag = 0;
69
70 static krb5_context context;
71 static krb5_enctype limit_enctype = 0;
72
73 static struct {
74 const char *name;
75 gss_OID oid;
76 } o2n[] = {
77 { "krb5", NULL /* GSS_KRB5_MECHANISM */ },
78 { "spnego", NULL /* GSS_SPNEGO_MECHANISM */ },
79 { "ntlm", NULL /* GSS_NTLM_MECHANISM */ },
80 { "sasl-digest-md5", NULL /* GSS_SASL_DIGEST_MD5_MECHANISM */ }
81 };
82
83 static void
init_o2n(void)84 init_o2n(void)
85 {
86 o2n[0].oid = GSS_KRB5_MECHANISM;
87 o2n[1].oid = GSS_SPNEGO_MECHANISM;
88 o2n[2].oid = GSS_NTLM_MECHANISM;
89 o2n[3].oid = GSS_SASL_DIGEST_MD5_MECHANISM;
90 }
91
92 static gss_OID
string_to_oid(const char * name)93 string_to_oid(const char *name)
94 {
95 int i;
96 for (i = 0; i < sizeof(o2n)/sizeof(o2n[0]); i++)
97 if (strcasecmp(name, o2n[i].name) == 0)
98 return o2n[i].oid;
99 errx(1, "name '%s' not unknown", name);
100 }
101
102 static const char *
oid_to_string(const gss_OID oid)103 oid_to_string(const gss_OID oid)
104 {
105 int i;
106 for (i = 0; i < sizeof(o2n)/sizeof(o2n[0]); i++)
107 if (gss_oid_equal(oid, o2n[i].oid))
108 return o2n[i].name;
109 return "unknown oid";
110 }
111
112 static void
loop(gss_OID mechoid,gss_OID nameoid,const char * target,gss_cred_id_t init_cred,gss_ctx_id_t * sctx,gss_ctx_id_t * cctx,gss_OID * actual_mech,gss_cred_id_t * deleg_cred)113 loop(gss_OID mechoid,
114 gss_OID nameoid, const char *target,
115 gss_cred_id_t init_cred,
116 gss_ctx_id_t *sctx, gss_ctx_id_t *cctx,
117 gss_OID *actual_mech,
118 gss_cred_id_t *deleg_cred)
119 {
120 int server_done = 0, client_done = 0;
121 int num_loops = 0;
122 OM_uint32 maj_stat, min_stat;
123 gss_name_t gss_target_name;
124 gss_buffer_desc input_token, output_token;
125 OM_uint32 flags = 0, ret_cflags, ret_sflags;
126 gss_OID actual_mech_client;
127 gss_OID actual_mech_server;
128
129 *actual_mech = GSS_C_NO_OID;
130
131 flags |= GSS_C_INTEG_FLAG;
132 flags |= GSS_C_CONF_FLAG;
133
134 if (mutual_auth_flag)
135 flags |= GSS_C_MUTUAL_FLAG;
136 if (dce_style_flag)
137 flags |= GSS_C_DCE_STYLE;
138 if (deleg_flag)
139 flags |= GSS_C_DELEG_FLAG;
140 if (policy_deleg_flag)
141 flags |= GSS_C_DELEG_POLICY_FLAG;
142
143 input_token.value = rk_UNCONST(target);
144 input_token.length = strlen(target);
145
146 maj_stat = gss_import_name(&min_stat,
147 &input_token,
148 nameoid,
149 &gss_target_name);
150 if (GSS_ERROR(maj_stat))
151 err(1, "import name creds failed with: %d", maj_stat);
152
153 input_token.length = 0;
154 input_token.value = NULL;
155
156 while (!server_done || !client_done) {
157 num_loops++;
158
159 gsskrb5_set_time_offset(client_time_offset);
160
161 maj_stat = gss_init_sec_context(&min_stat,
162 init_cred,
163 cctx,
164 gss_target_name,
165 mechoid,
166 flags,
167 0,
168 NULL,
169 &input_token,
170 &actual_mech_client,
171 &output_token,
172 &ret_cflags,
173 NULL);
174 if (GSS_ERROR(maj_stat))
175 errx(1, "init_sec_context: %s",
176 gssapi_err(maj_stat, min_stat, mechoid));
177 if (maj_stat & GSS_S_CONTINUE_NEEDED)
178 ;
179 else
180 client_done = 1;
181
182 gsskrb5_get_time_offset(&client_time_offset);
183
184 if (client_done && server_done)
185 break;
186
187 if (input_token.length != 0)
188 gss_release_buffer(&min_stat, &input_token);
189
190 gsskrb5_set_time_offset(server_time_offset);
191
192 maj_stat = gss_accept_sec_context(&min_stat,
193 sctx,
194 GSS_C_NO_CREDENTIAL,
195 &output_token,
196 GSS_C_NO_CHANNEL_BINDINGS,
197 NULL,
198 &actual_mech_server,
199 &input_token,
200 &ret_sflags,
201 NULL,
202 deleg_cred);
203 if (GSS_ERROR(maj_stat))
204 errx(1, "accept_sec_context: %s",
205 gssapi_err(maj_stat, min_stat, actual_mech_server));
206
207 gsskrb5_get_time_offset(&server_time_offset);
208
209 if (output_token.length != 0)
210 gss_release_buffer(&min_stat, &output_token);
211
212 if (maj_stat & GSS_S_CONTINUE_NEEDED)
213 ;
214 else
215 server_done = 1;
216 }
217 if (output_token.length != 0)
218 gss_release_buffer(&min_stat, &output_token);
219 if (input_token.length != 0)
220 gss_release_buffer(&min_stat, &input_token);
221 gss_release_name(&min_stat, &gss_target_name);
222
223 if (deleg_flag || policy_deleg_flag) {
224 if (server_no_deleg_flag) {
225 if (*deleg_cred != GSS_C_NO_CREDENTIAL)
226 errx(1, "got delegated cred but didn't expect one");
227 } else if (*deleg_cred == GSS_C_NO_CREDENTIAL)
228 errx(1, "asked for delegarated cred but did get one");
229 } else if (*deleg_cred != GSS_C_NO_CREDENTIAL)
230 errx(1, "got deleg_cred cred but didn't ask");
231
232 if (gss_oid_equal(actual_mech_server, actual_mech_client) == 0)
233 errx(1, "mech mismatch");
234 *actual_mech = actual_mech_server;
235
236 if (max_loops && num_loops > max_loops)
237 errx(1, "num loops %d was lager then max loops %d",
238 num_loops, max_loops);
239
240 if (verbose_flag) {
241 printf("server time offset: %d\n", server_time_offset);
242 printf("client time offset: %d\n", client_time_offset);
243 printf("num loops %d\n", num_loops);
244 }
245 }
246
247 static void
wrapunwrap(gss_ctx_id_t cctx,gss_ctx_id_t sctx,int flags,gss_OID mechoid)248 wrapunwrap(gss_ctx_id_t cctx, gss_ctx_id_t sctx, int flags, gss_OID mechoid)
249 {
250 gss_buffer_desc input_token, output_token, output_token2;
251 OM_uint32 min_stat, maj_stat;
252 gss_qop_t qop_state;
253 int conf_state;
254
255 input_token.value = "foo";
256 input_token.length = 3;
257
258 maj_stat = gss_wrap(&min_stat, cctx, flags, 0, &input_token,
259 &conf_state, &output_token);
260 if (maj_stat != GSS_S_COMPLETE)
261 errx(1, "gss_wrap failed: %s",
262 gssapi_err(maj_stat, min_stat, mechoid));
263
264 maj_stat = gss_unwrap(&min_stat, sctx, &output_token,
265 &output_token2, &conf_state, &qop_state);
266 if (maj_stat != GSS_S_COMPLETE)
267 errx(1, "gss_unwrap failed: %s",
268 gssapi_err(maj_stat, min_stat, mechoid));
269
270 gss_release_buffer(&min_stat, &output_token);
271 gss_release_buffer(&min_stat, &output_token2);
272
273 #if 0 /* doesn't work for NTLM yet */
274 if (!!conf_state != !!flags)
275 errx(1, "conf_state mismatch");
276 #endif
277 }
278
279 #define USE_CONF 1
280 #define USE_HEADER_ONLY 2
281 #define USE_SIGN_ONLY 4
282 #define FORCE_IOV 8
283
284 static void
wrapunwrap_iov(gss_ctx_id_t cctx,gss_ctx_id_t sctx,int flags,gss_OID mechoid)285 wrapunwrap_iov(gss_ctx_id_t cctx, gss_ctx_id_t sctx, int flags, gss_OID mechoid)
286 {
287 krb5_data token, header, trailer;
288 OM_uint32 min_stat, maj_stat;
289 gss_qop_t qop_state;
290 int conf_state, conf_state2;
291 gss_iov_buffer_desc iov[6];
292 unsigned char *p;
293 int iov_len;
294 char header_data[9] = "ABCheader";
295 char trailer_data[10] = "trailerXYZ";
296
297 char token_data[16] = "0123456789abcdef";
298
299 memset(&iov, 0, sizeof(iov));
300
301 if (flags & USE_SIGN_ONLY) {
302 header.data = header_data;
303 header.length = 9;
304 trailer.data = trailer_data;
305 trailer.length = 10;
306 } else {
307 header.data = NULL;
308 header.length = 0;
309 trailer.data = NULL;
310 trailer.length = 0;
311 }
312
313 token.data = token_data;
314 token.length = 16;
315
316 iov_len = sizeof(iov)/sizeof(iov[0]);
317
318 memset(iov, 0, sizeof(iov));
319
320 iov[0].type = GSS_IOV_BUFFER_TYPE_HEADER | GSS_IOV_BUFFER_TYPE_FLAG_ALLOCATE;
321
322 if (header.length != 0) {
323 iov[1].type = GSS_IOV_BUFFER_TYPE_SIGN_ONLY;
324 iov[1].buffer.length = header.length;
325 iov[1].buffer.value = header.data;
326 } else {
327 iov[1].type = GSS_IOV_BUFFER_TYPE_EMPTY;
328 iov[1].buffer.length = 0;
329 iov[1].buffer.value = NULL;
330 }
331 iov[2].type = GSS_IOV_BUFFER_TYPE_DATA;
332 iov[2].buffer.length = token.length;
333 iov[2].buffer.value = token.data;
334 if (trailer.length != 0) {
335 iov[3].type = GSS_IOV_BUFFER_TYPE_SIGN_ONLY;
336 iov[3].buffer.length = trailer.length;
337 iov[3].buffer.value = trailer.data;
338 } else {
339 iov[3].type = GSS_IOV_BUFFER_TYPE_EMPTY;
340 iov[3].buffer.length = 0;
341 iov[3].buffer.value = NULL;
342 }
343 if (dce_style_flag) {
344 iov[4].type = GSS_IOV_BUFFER_TYPE_EMPTY;
345 } else {
346 iov[4].type = GSS_IOV_BUFFER_TYPE_PADDING | GSS_IOV_BUFFER_TYPE_FLAG_ALLOCATE;
347 }
348 iov[4].buffer.length = 0;
349 iov[4].buffer.value = 0;
350 if (dce_style_flag) {
351 iov[5].type = GSS_IOV_BUFFER_TYPE_EMPTY;
352 } else if (flags & USE_HEADER_ONLY) {
353 iov[5].type = GSS_IOV_BUFFER_TYPE_EMPTY;
354 } else {
355 iov[5].type = GSS_IOV_BUFFER_TYPE_TRAILER | GSS_IOV_BUFFER_TYPE_FLAG_ALLOCATE;
356 }
357 iov[5].buffer.length = 0;
358 iov[5].buffer.value = 0;
359
360 maj_stat = gss_wrap_iov(&min_stat, cctx, dce_style_flag || flags & USE_CONF, 0, &conf_state,
361 iov, iov_len);
362 if (maj_stat != GSS_S_COMPLETE)
363 errx(1, "gss_wrap_iov failed");
364
365 token.length =
366 iov[0].buffer.length +
367 iov[1].buffer.length +
368 iov[2].buffer.length +
369 iov[3].buffer.length +
370 iov[4].buffer.length +
371 iov[5].buffer.length;
372 token.data = emalloc(token.length);
373
374 p = token.data;
375 memcpy(p, iov[0].buffer.value, iov[0].buffer.length);
376 p += iov[0].buffer.length;
377 memcpy(p, iov[1].buffer.value, iov[1].buffer.length);
378 p += iov[1].buffer.length;
379 memcpy(p, iov[2].buffer.value, iov[2].buffer.length);
380 p += iov[2].buffer.length;
381 memcpy(p, iov[3].buffer.value, iov[3].buffer.length);
382 p += iov[3].buffer.length;
383 memcpy(p, iov[4].buffer.value, iov[4].buffer.length);
384 p += iov[4].buffer.length;
385 memcpy(p, iov[5].buffer.value, iov[5].buffer.length);
386 p += iov[5].buffer.length;
387
388 assert(p - ((unsigned char *)token.data) == token.length);
389
390 if ((flags & (USE_SIGN_ONLY|FORCE_IOV)) == 0) {
391 gss_buffer_desc input, output;
392
393 input.value = token.data;
394 input.length = token.length;
395
396 maj_stat = gss_unwrap(&min_stat, sctx, &input,
397 &output, &conf_state2, &qop_state);
398
399 if (maj_stat != GSS_S_COMPLETE)
400 errx(1, "gss_unwrap from gss_wrap_iov failed: %s",
401 gssapi_err(maj_stat, min_stat, mechoid));
402
403 gss_release_buffer(&min_stat, &output);
404 } else {
405 maj_stat = gss_unwrap_iov(&min_stat, sctx, &conf_state2, &qop_state,
406 iov, iov_len);
407
408 if (maj_stat != GSS_S_COMPLETE)
409 errx(1, "gss_unwrap_iov failed: %x %s", flags,
410 gssapi_err(maj_stat, min_stat, mechoid));
411
412 }
413 if (conf_state2 != conf_state)
414 errx(1, "conf state wrong for iov: %x", flags);
415
416
417 free(token.data);
418 }
419
420 static void
getverifymic(gss_ctx_id_t cctx,gss_ctx_id_t sctx,gss_OID mechoid)421 getverifymic(gss_ctx_id_t cctx, gss_ctx_id_t sctx, gss_OID mechoid)
422 {
423 gss_buffer_desc input_token, output_token;
424 OM_uint32 min_stat, maj_stat;
425 gss_qop_t qop_state;
426
427 input_token.value = "bar";
428 input_token.length = 3;
429
430 maj_stat = gss_get_mic(&min_stat, cctx, 0, &input_token,
431 &output_token);
432 if (maj_stat != GSS_S_COMPLETE)
433 errx(1, "gss_get_mic failed: %s",
434 gssapi_err(maj_stat, min_stat, mechoid));
435
436 maj_stat = gss_verify_mic(&min_stat, sctx, &input_token,
437 &output_token, &qop_state);
438 if (maj_stat != GSS_S_COMPLETE)
439 errx(1, "gss_verify_mic failed: %s",
440 gssapi_err(maj_stat, min_stat, mechoid));
441
442 gss_release_buffer(&min_stat, &output_token);
443 }
444
445 static void
empty_release(void)446 empty_release(void)
447 {
448 gss_ctx_id_t ctx = GSS_C_NO_CONTEXT;
449 gss_cred_id_t cred = GSS_C_NO_CREDENTIAL;
450 gss_name_t name = GSS_C_NO_NAME;
451 gss_OID_set oidset = GSS_C_NO_OID_SET;
452 OM_uint32 junk;
453
454 gss_delete_sec_context(&junk, &ctx, NULL);
455 gss_release_cred(&junk, &cred);
456 gss_release_name(&junk, &name);
457 gss_release_oid_set(&junk, &oidset);
458 }
459
460 /*
461 *
462 */
463
464 static struct getargs args[] = {
465 {"name-type",0, arg_string, &type_string, "type of name", NULL },
466 {"mech-type",0, arg_string, &mech_string, "type of mech", NULL },
467 {"ret-mech-type",0, arg_string, &ret_mech_string,
468 "type of return mech", NULL },
469 {"dns-canonicalize",0,arg_negative_flag, &dns_canon_flag,
470 "use dns to canonicalize", NULL },
471 {"mutual-auth",0, arg_flag, &mutual_auth_flag,"mutual auth", NULL },
472 {"client-name", 0, arg_string, &client_name, "client name", NULL },
473 {"client-password", 0, arg_string, &client_password, "client password", NULL },
474 {"limit-enctype",0, arg_string, &limit_enctype_string, "enctype", NULL },
475 {"dce-style",0, arg_flag, &dce_style_flag, "dce-style", NULL },
476 {"wrapunwrap",0, arg_flag, &wrapunwrap_flag, "wrap/unwrap", NULL },
477 {"iov", 0, arg_flag, &iov_flag, "wrap/unwrap iov", NULL },
478 {"getverifymic",0, arg_flag, &getverifymic_flag,
479 "get and verify mic", NULL },
480 {"delegate",0, arg_flag, &deleg_flag, "delegate credential", NULL },
481 {"policy-delegate",0, arg_flag, &policy_deleg_flag, "policy delegate credential", NULL },
482 {"server-no-delegate",0, arg_flag, &server_no_deleg_flag,
483 "server should get a credential", NULL },
484 {"export-import-cred",0, arg_flag, &ei_flag, "test export/import cred", NULL },
485 {"gsskrb5-acceptor-identity", 0, arg_string, &gsskrb5_acceptor_identity, "keytab", NULL },
486 {"session-enctype", 0, arg_string, &session_enctype_string, "enctype", NULL },
487 {"client-time-offset", 0, arg_integer, &client_time_offset, "time", NULL },
488 {"server-time-offset", 0, arg_integer, &server_time_offset, "time", NULL },
489 {"max-loops", 0, arg_integer, &max_loops, "time", NULL },
490 {"version", 0, arg_flag, &version_flag, "print version", NULL },
491 {"verbose", 'v', arg_flag, &verbose_flag, "verbose", NULL },
492 {"help", 0, arg_flag, &help_flag, NULL, NULL }
493 };
494
495 static void
usage(int ret)496 usage (int ret)
497 {
498 arg_printusage (args, sizeof(args)/sizeof(*args),
499 NULL, "service@host");
500 exit (ret);
501 }
502
503 int
main(int argc,char ** argv)504 main(int argc, char **argv)
505 {
506 int optind = 0;
507 OM_uint32 min_stat, maj_stat;
508 gss_ctx_id_t cctx, sctx;
509 void *ctx;
510 gss_OID nameoid, mechoid, actual_mech, actual_mech2;
511 gss_cred_id_t client_cred = GSS_C_NO_CREDENTIAL, deleg_cred = GSS_C_NO_CREDENTIAL;
512 gss_name_t cname = GSS_C_NO_NAME;
513 gss_buffer_desc credential_data = GSS_C_EMPTY_BUFFER;
514
515 setprogname(argv[0]);
516
517 init_o2n();
518
519 if (krb5_init_context(&context))
520 errx(1, "krb5_init_context");
521
522 cctx = sctx = GSS_C_NO_CONTEXT;
523
524 if(getarg(args, sizeof(args) / sizeof(args[0]), argc, argv, &optind))
525 usage(1);
526
527 if (help_flag)
528 usage (0);
529
530 if(version_flag){
531 print_version(NULL);
532 exit(0);
533 }
534
535 argc -= optind;
536 argv += optind;
537
538 if (argc != 1)
539 usage(1);
540
541 if (dns_canon_flag != -1)
542 gsskrb5_set_dns_canonicalize(dns_canon_flag);
543
544 if (type_string == NULL)
545 nameoid = GSS_C_NT_HOSTBASED_SERVICE;
546 else if (strcmp(type_string, "hostbased-service") == 0)
547 nameoid = GSS_C_NT_HOSTBASED_SERVICE;
548 else if (strcmp(type_string, "krb5-principal-name") == 0)
549 nameoid = GSS_KRB5_NT_PRINCIPAL_NAME;
550 else
551 errx(1, "%s not suppported", type_string);
552
553 if (mech_string == NULL)
554 mechoid = GSS_KRB5_MECHANISM;
555 else
556 mechoid = string_to_oid(mech_string);
557
558 if (gsskrb5_acceptor_identity) {
559 maj_stat = gsskrb5_register_acceptor_identity(gsskrb5_acceptor_identity);
560 if (maj_stat)
561 errx(1, "gsskrb5_acceptor_identity: %s",
562 gssapi_err(maj_stat, 0, GSS_C_NO_OID));
563 }
564
565 if (client_password) {
566 credential_data.value = client_password;
567 credential_data.length = strlen(client_password);
568 }
569
570 if (client_name) {
571 gss_buffer_desc cn;
572
573 cn.value = client_name;
574 cn.length = strlen(client_name);
575
576 maj_stat = gss_import_name(&min_stat, &cn, GSS_C_NT_USER_NAME, &cname);
577 if (maj_stat)
578 errx(1, "gss_import_name: %s",
579 gssapi_err(maj_stat, min_stat, GSS_C_NO_OID));
580 }
581
582 if (client_password) {
583 maj_stat = gss_acquire_cred_with_password(&min_stat,
584 cname,
585 &credential_data,
586 GSS_C_INDEFINITE,
587 GSS_C_NO_OID_SET,
588 GSS_C_INITIATE,
589 &client_cred,
590 NULL,
591 NULL);
592 if (GSS_ERROR(maj_stat))
593 errx(1, "gss_acquire_cred_with_password: %s",
594 gssapi_err(maj_stat, min_stat, GSS_C_NO_OID));
595 } else {
596 maj_stat = gss_acquire_cred(&min_stat,
597 cname,
598 GSS_C_INDEFINITE,
599 GSS_C_NO_OID_SET,
600 GSS_C_INITIATE,
601 &client_cred,
602 NULL,
603 NULL);
604 if (GSS_ERROR(maj_stat))
605 errx(1, "gss_acquire_cred: %s",
606 gssapi_err(maj_stat, min_stat, GSS_C_NO_OID));
607 }
608
609 if (limit_enctype_string) {
610 krb5_error_code ret;
611
612 ret = krb5_string_to_enctype(context,
613 limit_enctype_string,
614 &limit_enctype);
615 if (ret)
616 krb5_err(context, 1, ret, "krb5_string_to_enctype");
617 }
618
619
620 if (limit_enctype) {
621 if (client_cred == NULL)
622 errx(1, "client_cred missing");
623
624 maj_stat = gss_krb5_set_allowable_enctypes(&min_stat, client_cred,
625 1, &limit_enctype);
626 if (maj_stat)
627 errx(1, "gss_krb5_set_allowable_enctypes: %s",
628 gssapi_err(maj_stat, min_stat, GSS_C_NO_OID));
629 }
630
631 loop(mechoid, nameoid, argv[0], client_cred,
632 &sctx, &cctx, &actual_mech, &deleg_cred);
633
634 if (verbose_flag)
635 printf("resulting mech: %s\n", oid_to_string(actual_mech));
636
637 if (ret_mech_string) {
638 gss_OID retoid;
639
640 retoid = string_to_oid(ret_mech_string);
641
642 if (gss_oid_equal(retoid, actual_mech) == 0)
643 errx(1, "actual_mech mech is not the expected type %s",
644 ret_mech_string);
645 }
646
647 /* XXX should be actual_mech */
648 if (gss_oid_equal(mechoid, GSS_KRB5_MECHANISM)) {
649 time_t time;
650 gss_buffer_desc authz_data;
651 gss_buffer_desc in, out1, out2;
652 krb5_keyblock *keyblock, *keyblock2;
653 krb5_timestamp now;
654 krb5_error_code ret;
655
656 ret = krb5_timeofday(context, &now);
657 if (ret)
658 errx(1, "krb5_timeofday failed");
659
660 /* client */
661 maj_stat = gss_krb5_export_lucid_sec_context(&min_stat,
662 &cctx,
663 1, /* version */
664 &ctx);
665 if (maj_stat != GSS_S_COMPLETE)
666 errx(1, "gss_krb5_export_lucid_sec_context failed: %s",
667 gssapi_err(maj_stat, min_stat, actual_mech));
668
669
670 maj_stat = gss_krb5_free_lucid_sec_context(&maj_stat, ctx);
671 if (maj_stat != GSS_S_COMPLETE)
672 errx(1, "gss_krb5_free_lucid_sec_context failed: %s",
673 gssapi_err(maj_stat, min_stat, actual_mech));
674
675 /* server */
676 maj_stat = gss_krb5_export_lucid_sec_context(&min_stat,
677 &sctx,
678 1, /* version */
679 &ctx);
680 if (maj_stat != GSS_S_COMPLETE)
681 errx(1, "gss_krb5_export_lucid_sec_context failed: %s",
682 gssapi_err(maj_stat, min_stat, actual_mech));
683 maj_stat = gss_krb5_free_lucid_sec_context(&min_stat, ctx);
684 if (maj_stat != GSS_S_COMPLETE)
685 errx(1, "gss_krb5_free_lucid_sec_context failed: %s",
686 gssapi_err(maj_stat, min_stat, actual_mech));
687
688 maj_stat = gsskrb5_extract_authtime_from_sec_context(&min_stat,
689 sctx,
690 &time);
691 if (maj_stat != GSS_S_COMPLETE)
692 errx(1, "gsskrb5_extract_authtime_from_sec_context failed: %s",
693 gssapi_err(maj_stat, min_stat, actual_mech));
694
695 if (time > now)
696 errx(1, "gsskrb5_extract_authtime_from_sec_context failed: "
697 "time authtime is before now: %ld %ld",
698 (long)time, (long)now);
699
700 maj_stat = gsskrb5_extract_service_keyblock(&min_stat,
701 sctx,
702 &keyblock);
703 if (maj_stat != GSS_S_COMPLETE)
704 errx(1, "gsskrb5_export_service_keyblock failed: %s",
705 gssapi_err(maj_stat, min_stat, actual_mech));
706
707 krb5_free_keyblock(context, keyblock);
708
709 maj_stat = gsskrb5_get_subkey(&min_stat,
710 sctx,
711 &keyblock);
712 if (maj_stat != GSS_S_COMPLETE
713 && (!(maj_stat == GSS_S_FAILURE && min_stat == GSS_KRB5_S_KG_NO_SUBKEY)))
714 errx(1, "gsskrb5_get_subkey server failed: %s",
715 gssapi_err(maj_stat, min_stat, actual_mech));
716
717 if (maj_stat != GSS_S_COMPLETE)
718 keyblock = NULL;
719 else if (limit_enctype && keyblock->keytype != limit_enctype)
720 errx(1, "gsskrb5_get_subkey wrong enctype");
721
722 maj_stat = gsskrb5_get_subkey(&min_stat,
723 cctx,
724 &keyblock2);
725 if (maj_stat != GSS_S_COMPLETE
726 && (!(maj_stat == GSS_S_FAILURE && min_stat == GSS_KRB5_S_KG_NO_SUBKEY)))
727 errx(1, "gsskrb5_get_subkey client failed: %s",
728 gssapi_err(maj_stat, min_stat, actual_mech));
729
730 if (maj_stat != GSS_S_COMPLETE)
731 keyblock2 = NULL;
732 else if (limit_enctype && keyblock->keytype != limit_enctype)
733 errx(1, "gsskrb5_get_subkey wrong enctype");
734
735 if (keyblock || keyblock2) {
736 if (keyblock == NULL)
737 errx(1, "server missing token keyblock");
738 if (keyblock2 == NULL)
739 errx(1, "client missing token keyblock");
740
741 if (keyblock->keytype != keyblock2->keytype)
742 errx(1, "enctype mismatch");
743 if (keyblock->keyvalue.length != keyblock2->keyvalue.length)
744 errx(1, "key length mismatch");
745 if (memcmp(keyblock->keyvalue.data, keyblock2->keyvalue.data,
746 keyblock2->keyvalue.length) != 0)
747 errx(1, "key data mismatch");
748 }
749
750 if (session_enctype_string) {
751 krb5_enctype enctype;
752
753 ret = krb5_string_to_enctype(context,
754 session_enctype_string,
755 &enctype);
756
757 if (ret)
758 krb5_err(context, 1, ret, "krb5_string_to_enctype");
759
760 if (enctype != keyblock->keytype)
761 errx(1, "keytype is not the expected %d != %d",
762 (int)enctype, (int)keyblock2->keytype);
763 }
764
765 if (keyblock)
766 krb5_free_keyblock(context, keyblock);
767 if (keyblock2)
768 krb5_free_keyblock(context, keyblock2);
769
770 maj_stat = gsskrb5_get_initiator_subkey(&min_stat,
771 sctx,
772 &keyblock);
773 if (maj_stat != GSS_S_COMPLETE
774 && (!(maj_stat == GSS_S_FAILURE && min_stat == GSS_KRB5_S_KG_NO_SUBKEY)))
775 errx(1, "gsskrb5_get_initiator_subkey failed: %s",
776 gssapi_err(maj_stat, min_stat, actual_mech));
777
778 if (maj_stat == GSS_S_COMPLETE) {
779
780 if (limit_enctype && keyblock->keytype != limit_enctype)
781 errx(1, "gsskrb5_get_initiator_subkey wrong enctype");
782 krb5_free_keyblock(context, keyblock);
783 }
784
785 maj_stat = gsskrb5_extract_authz_data_from_sec_context(&min_stat,
786 sctx,
787 128,
788 &authz_data);
789 if (maj_stat == GSS_S_COMPLETE)
790 gss_release_buffer(&min_stat, &authz_data);
791
792
793 memset(&out1, 0, sizeof(out1));
794 memset(&out2, 0, sizeof(out2));
795
796 in.value = "foo";
797 in.length = 3;
798
799 gss_pseudo_random(&min_stat, sctx, GSS_C_PRF_KEY_FULL, &in,
800 100, &out1);
801 gss_pseudo_random(&min_stat, cctx, GSS_C_PRF_KEY_FULL, &in,
802 100, &out2);
803
804 if (out1.length != out2.length)
805 errx(1, "prf len mismatch");
806 if (memcmp(out1.value, out2.value, out1.length) != 0)
807 errx(1, "prf data mismatch");
808
809 gss_release_buffer(&min_stat, &out1);
810
811 gss_pseudo_random(&min_stat, sctx, GSS_C_PRF_KEY_FULL, &in,
812 100, &out1);
813
814 if (out1.length != out2.length)
815 errx(1, "prf len mismatch");
816 if (memcmp(out1.value, out2.value, out1.length) != 0)
817 errx(1, "prf data mismatch");
818
819 gss_release_buffer(&min_stat, &out1);
820 gss_release_buffer(&min_stat, &out2);
821
822 in.value = "bar";
823 in.length = 3;
824
825 gss_pseudo_random(&min_stat, sctx, GSS_C_PRF_KEY_PARTIAL, &in,
826 100, &out1);
827 gss_pseudo_random(&min_stat, cctx, GSS_C_PRF_KEY_PARTIAL, &in,
828 100, &out2);
829
830 if (out1.length != out2.length)
831 errx(1, "prf len mismatch");
832 if (memcmp(out1.value, out2.value, out1.length) != 0)
833 errx(1, "prf data mismatch");
834
835 gss_release_buffer(&min_stat, &out1);
836 gss_release_buffer(&min_stat, &out2);
837
838 wrapunwrap_flag = 1;
839 getverifymic_flag = 1;
840 }
841
842 if (wrapunwrap_flag) {
843 wrapunwrap(cctx, sctx, 0, actual_mech);
844 wrapunwrap(cctx, sctx, 1, actual_mech);
845 wrapunwrap(sctx, cctx, 0, actual_mech);
846 wrapunwrap(sctx, cctx, 1, actual_mech);
847 }
848
849 if (iov_flag) {
850 wrapunwrap_iov(cctx, sctx, 0, actual_mech);
851 wrapunwrap_iov(cctx, sctx, USE_HEADER_ONLY|FORCE_IOV, actual_mech);
852 wrapunwrap_iov(cctx, sctx, USE_HEADER_ONLY, actual_mech);
853 wrapunwrap_iov(cctx, sctx, USE_CONF, actual_mech);
854 wrapunwrap_iov(cctx, sctx, USE_CONF|USE_HEADER_ONLY, actual_mech);
855
856 wrapunwrap_iov(cctx, sctx, FORCE_IOV, actual_mech);
857 wrapunwrap_iov(cctx, sctx, USE_CONF|FORCE_IOV, actual_mech);
858 wrapunwrap_iov(cctx, sctx, USE_HEADER_ONLY|FORCE_IOV, actual_mech);
859 wrapunwrap_iov(cctx, sctx, USE_CONF|USE_HEADER_ONLY|FORCE_IOV, actual_mech);
860
861 wrapunwrap_iov(cctx, sctx, USE_SIGN_ONLY|FORCE_IOV, actual_mech);
862 wrapunwrap_iov(cctx, sctx, USE_CONF|USE_SIGN_ONLY|FORCE_IOV, actual_mech);
863 wrapunwrap_iov(cctx, sctx, USE_CONF|USE_HEADER_ONLY|USE_SIGN_ONLY|FORCE_IOV, actual_mech);
864
865 /* works */
866 wrapunwrap_iov(cctx, sctx, 0, actual_mech);
867 wrapunwrap_iov(cctx, sctx, FORCE_IOV, actual_mech);
868
869 wrapunwrap_iov(cctx, sctx, USE_CONF, actual_mech);
870 wrapunwrap_iov(cctx, sctx, USE_CONF|FORCE_IOV, actual_mech);
871
872 wrapunwrap_iov(cctx, sctx, USE_SIGN_ONLY, actual_mech);
873 wrapunwrap_iov(cctx, sctx, USE_SIGN_ONLY|FORCE_IOV, actual_mech);
874
875 wrapunwrap_iov(cctx, sctx, USE_CONF|USE_SIGN_ONLY, actual_mech);
876 wrapunwrap_iov(cctx, sctx, USE_CONF|USE_SIGN_ONLY|FORCE_IOV, actual_mech);
877
878 wrapunwrap_iov(cctx, sctx, USE_HEADER_ONLY, actual_mech);
879 wrapunwrap_iov(cctx, sctx, USE_HEADER_ONLY|FORCE_IOV, actual_mech);
880
881 wrapunwrap_iov(cctx, sctx, USE_CONF|USE_HEADER_ONLY, actual_mech);
882 wrapunwrap_iov(cctx, sctx, USE_CONF|USE_HEADER_ONLY|FORCE_IOV, actual_mech);
883 }
884
885 if (getverifymic_flag) {
886 getverifymic(cctx, sctx, actual_mech);
887 getverifymic(cctx, sctx, actual_mech);
888 getverifymic(sctx, cctx, actual_mech);
889 getverifymic(sctx, cctx, actual_mech);
890 }
891
892
893 gss_delete_sec_context(&min_stat, &cctx, NULL);
894 gss_delete_sec_context(&min_stat, &sctx, NULL);
895
896 if (deleg_cred != GSS_C_NO_CREDENTIAL) {
897 gss_cred_id_t cred2 = GSS_C_NO_CREDENTIAL;
898 gss_buffer_desc cb;
899
900 if (verbose_flag)
901 printf("checking actual mech (%s) on delegated cred\n",
902 oid_to_string(actual_mech));
903 loop(actual_mech, nameoid, argv[0], deleg_cred, &sctx, &cctx, &actual_mech2, &cred2);
904
905 gss_delete_sec_context(&min_stat, &cctx, NULL);
906 gss_delete_sec_context(&min_stat, &sctx, NULL);
907
908 gss_release_cred(&min_stat, &cred2);
909
910 /* try again using SPNEGO */
911 if (verbose_flag)
912 printf("checking spnego on delegated cred\n");
913 loop(GSS_SPNEGO_MECHANISM, nameoid, argv[0], deleg_cred, &sctx, &cctx,
914 &actual_mech2, &cred2);
915
916 gss_delete_sec_context(&min_stat, &cctx, NULL);
917 gss_delete_sec_context(&min_stat, &sctx, NULL);
918
919 gss_release_cred(&min_stat, &cred2);
920
921 /* check export/import */
922 if (ei_flag) {
923
924 maj_stat = gss_export_cred(&min_stat, deleg_cred, &cb);
925 if (maj_stat != GSS_S_COMPLETE)
926 errx(1, "export failed: %s",
927 gssapi_err(maj_stat, min_stat, NULL));
928
929 maj_stat = gss_import_cred(&min_stat, &cb, &cred2);
930 if (maj_stat != GSS_S_COMPLETE)
931 errx(1, "import failed: %s",
932 gssapi_err(maj_stat, min_stat, NULL));
933
934 gss_release_buffer(&min_stat, &cb);
935 gss_release_cred(&min_stat, &deleg_cred);
936
937 if (verbose_flag)
938 printf("checking actual mech (%s) on export/imported cred\n",
939 oid_to_string(actual_mech));
940 loop(actual_mech, nameoid, argv[0], cred2, &sctx, &cctx,
941 &actual_mech2, &deleg_cred);
942
943 gss_release_cred(&min_stat, &deleg_cred);
944
945 gss_delete_sec_context(&min_stat, &cctx, NULL);
946 gss_delete_sec_context(&min_stat, &sctx, NULL);
947
948 /* try again using SPNEGO */
949 if (verbose_flag)
950 printf("checking SPNEGO on export/imported cred\n");
951 loop(GSS_SPNEGO_MECHANISM, nameoid, argv[0], cred2, &sctx, &cctx,
952 &actual_mech2, &deleg_cred);
953
954 gss_release_cred(&min_stat, &deleg_cred);
955
956 gss_delete_sec_context(&min_stat, &cctx, NULL);
957 gss_delete_sec_context(&min_stat, &sctx, NULL);
958
959 gss_release_cred(&min_stat, &cred2);
960
961 } else {
962 gss_release_cred(&min_stat, &deleg_cred);
963 }
964
965 }
966
967 empty_release();
968
969 krb5_free_context(context);
970
971 return 0;
972 }
973