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