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