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 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 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 * 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 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 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 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 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 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 496 usage (int ret) 497 { 498 arg_printusage (args, sizeof(args)/sizeof(*args), 499 NULL, "service@host"); 500 exit (ret); 501 } 502 503 int 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