1 /* 2 * Copyright (c) 2006 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 "test_common.h" 38 39 RCSID("$Id: test_context.c 20075 2007-01-31 06:05:19Z lha $"); 40 41 static char *type_string; 42 static char *mech_string; 43 static char *ret_mech_string; 44 static int dns_canon_flag = -1; 45 static int mutual_auth_flag = 0; 46 static int dce_style_flag = 0; 47 static int wrapunwrap_flag = 0; 48 static int getverifymic_flag = 0; 49 static int deleg_flag = 0; 50 static int version_flag = 0; 51 static int verbose_flag = 0; 52 static int help_flag = 0; 53 54 static struct { 55 const char *name; 56 gss_OID *oid; 57 } o2n[] = { 58 { "krb5", &GSS_KRB5_MECHANISM }, 59 { "spnego", &GSS_SPNEGO_MECHANISM }, 60 { "ntlm", &GSS_NTLM_MECHANISM }, 61 { "sasl-digest-md5", &GSS_SASL_DIGEST_MD5_MECHANISM } 62 }; 63 64 static gss_OID 65 string_to_oid(const char *name) 66 { 67 int i; 68 for (i = 0; i < sizeof(o2n)/sizeof(o2n[0]); i++) 69 if (strcasecmp(name, o2n[i].name) == 0) 70 return *o2n[i].oid; 71 errx(1, "name %s not unknown", name); 72 } 73 74 static const char * 75 oid_to_string(const gss_OID oid) 76 { 77 int i; 78 for (i = 0; i < sizeof(o2n)/sizeof(o2n[0]); i++) 79 if (gss_oid_equal(oid, *o2n[i].oid)) 80 return o2n[i].name; 81 return "unknown oid"; 82 } 83 84 static void 85 loop(gss_OID mechoid, 86 gss_OID nameoid, const char *target, 87 gss_cred_id_t init_cred, 88 gss_ctx_id_t *sctx, gss_ctx_id_t *cctx, 89 gss_OID *actual_mech, 90 gss_cred_id_t *deleg_cred) 91 { 92 int server_done = 0, client_done = 0; 93 OM_uint32 maj_stat, min_stat; 94 gss_name_t gss_target_name; 95 gss_buffer_desc input_token, output_token; 96 OM_uint32 flags = 0, ret_cflags, ret_sflags; 97 gss_OID actual_mech_client; 98 gss_OID actual_mech_server; 99 100 *actual_mech = GSS_C_NO_OID; 101 102 flags |= GSS_C_INTEG_FLAG; 103 flags |= GSS_C_CONF_FLAG; 104 105 if (mutual_auth_flag) 106 flags |= GSS_C_MUTUAL_FLAG; 107 if (dce_style_flag) 108 flags |= GSS_C_DCE_STYLE; 109 if (deleg_flag) 110 flags |= GSS_C_DELEG_FLAG; 111 112 input_token.value = rk_UNCONST(target); 113 input_token.length = strlen(target); 114 115 maj_stat = gss_import_name(&min_stat, 116 &input_token, 117 nameoid, 118 &gss_target_name); 119 if (GSS_ERROR(maj_stat)) 120 err(1, "import name creds failed with: %d", maj_stat); 121 122 input_token.length = 0; 123 input_token.value = NULL; 124 125 while (!server_done || !client_done) { 126 127 maj_stat = gss_init_sec_context(&min_stat, 128 init_cred, 129 cctx, 130 gss_target_name, 131 mechoid, 132 flags, 133 0, 134 NULL, 135 &input_token, 136 &actual_mech_client, 137 &output_token, 138 &ret_cflags, 139 NULL); 140 if (GSS_ERROR(maj_stat)) 141 errx(1, "init_sec_context: %s", 142 gssapi_err(maj_stat, min_stat, mechoid)); 143 if (maj_stat & GSS_S_CONTINUE_NEEDED) 144 ; 145 else 146 client_done = 1; 147 148 if (client_done && server_done) 149 break; 150 151 if (input_token.length != 0) 152 gss_release_buffer(&min_stat, &input_token); 153 154 maj_stat = gss_accept_sec_context(&min_stat, 155 sctx, 156 GSS_C_NO_CREDENTIAL, 157 &output_token, 158 GSS_C_NO_CHANNEL_BINDINGS, 159 NULL, 160 &actual_mech_server, 161 &input_token, 162 &ret_sflags, 163 NULL, 164 deleg_cred); 165 if (GSS_ERROR(maj_stat)) 166 errx(1, "accept_sec_context: %s", 167 gssapi_err(maj_stat, min_stat, actual_mech_server)); 168 169 if (verbose_flag) 170 printf("%.*s", (int)input_token.length, (char *)input_token.value); 171 172 if (output_token.length != 0) 173 gss_release_buffer(&min_stat, &output_token); 174 175 if (maj_stat & GSS_S_CONTINUE_NEEDED) 176 ; 177 else 178 server_done = 1; 179 } 180 if (output_token.length != 0) 181 gss_release_buffer(&min_stat, &output_token); 182 if (input_token.length != 0) 183 gss_release_buffer(&min_stat, &input_token); 184 gss_release_name(&min_stat, &gss_target_name); 185 186 if (gss_oid_equal(actual_mech_server, actual_mech_client) == 0) 187 errx(1, "mech mismatch"); 188 *actual_mech = actual_mech_server; 189 } 190 191 static void 192 wrapunwrap(gss_ctx_id_t cctx, gss_ctx_id_t sctx, gss_OID mechoid) 193 { 194 gss_buffer_desc input_token, output_token, output_token2; 195 OM_uint32 min_stat, maj_stat; 196 int32_t flags = 0; 197 gss_qop_t qop_state; 198 int conf_state; 199 200 input_token.value = "foo"; 201 input_token.length = 3; 202 203 maj_stat = gss_wrap(&min_stat, cctx, flags, 0, &input_token, 204 &conf_state, &output_token); 205 if (maj_stat != GSS_S_COMPLETE) 206 errx(1, "gss_wrap failed: %s", 207 gssapi_err(maj_stat, min_stat, mechoid)); 208 209 maj_stat = gss_unwrap(&min_stat, sctx, &output_token, 210 &output_token2, &conf_state, &qop_state); 211 if (maj_stat != GSS_S_COMPLETE) 212 errx(1, "gss_unwrap failed: %s", 213 gssapi_err(maj_stat, min_stat, mechoid)); 214 } 215 216 static void 217 getverifymic(gss_ctx_id_t cctx, gss_ctx_id_t sctx, gss_OID mechoid) 218 { 219 gss_buffer_desc input_token, output_token; 220 OM_uint32 min_stat, maj_stat; 221 gss_qop_t qop_state; 222 223 input_token.value = "bar"; 224 input_token.length = 3; 225 226 maj_stat = gss_get_mic(&min_stat, cctx, 0, &input_token, 227 &output_token); 228 if (maj_stat != GSS_S_COMPLETE) 229 errx(1, "gss_get_mic failed: %s", 230 gssapi_err(maj_stat, min_stat, mechoid)); 231 232 maj_stat = gss_verify_mic(&min_stat, sctx, &input_token, 233 &output_token, &qop_state); 234 if (maj_stat != GSS_S_COMPLETE) 235 errx(1, "gss_verify_mic failed: %s", 236 gssapi_err(maj_stat, min_stat, mechoid)); 237 } 238 239 240 /* 241 * 242 */ 243 244 static struct getargs args[] = { 245 {"name-type",0, arg_string, &type_string, "type of name", NULL }, 246 {"mech-type",0, arg_string, &mech_string, "type of mech", NULL }, 247 {"ret-mech-type",0, arg_string, &ret_mech_string, 248 "type of return mech", NULL }, 249 {"dns-canonicalize",0,arg_negative_flag, &dns_canon_flag, 250 "use dns to canonicalize", NULL }, 251 {"mutual-auth",0, arg_flag, &mutual_auth_flag,"mutual auth", NULL }, 252 {"dce-style",0, arg_flag, &dce_style_flag, "dce-style", NULL }, 253 {"wrapunwrap",0, arg_flag, &wrapunwrap_flag, "wrap/unwrap", NULL }, 254 {"getverifymic",0, arg_flag, &getverifymic_flag, 255 "get and verify mic", NULL }, 256 {"delegate",0, arg_flag, &deleg_flag, "delegate credential", NULL }, 257 {"version", 0, arg_flag, &version_flag, "print version", NULL }, 258 {"verbose", 'v', arg_flag, &verbose_flag, "verbose", NULL }, 259 {"help", 0, arg_flag, &help_flag, NULL, NULL } 260 }; 261 262 static void 263 usage (int ret) 264 { 265 arg_printusage (args, sizeof(args)/sizeof(*args), 266 NULL, "service@host"); 267 exit (ret); 268 } 269 270 int 271 main(int argc, char **argv) 272 { 273 int optind = 0; 274 OM_uint32 min_stat, maj_stat; 275 gss_ctx_id_t cctx, sctx; 276 void *ctx; 277 gss_OID nameoid, mechoid, actual_mech; 278 gss_cred_id_t deleg_cred = GSS_C_NO_CREDENTIAL; 279 280 setprogname(argv[0]); 281 282 cctx = sctx = GSS_C_NO_CONTEXT; 283 284 if(getarg(args, sizeof(args) / sizeof(args[0]), argc, argv, &optind)) 285 usage(1); 286 287 if (help_flag) 288 usage (0); 289 290 if(version_flag){ 291 print_version(NULL); 292 exit(0); 293 } 294 295 argc -= optind; 296 argv += optind; 297 298 if (argc != 1) 299 usage(1); 300 301 if (dns_canon_flag != -1) 302 gsskrb5_set_dns_canonicalize(dns_canon_flag); 303 304 if (type_string == NULL) 305 nameoid = GSS_C_NT_HOSTBASED_SERVICE; 306 else if (strcmp(type_string, "hostbased-service") == 0) 307 nameoid = GSS_C_NT_HOSTBASED_SERVICE; 308 else if (strcmp(type_string, "krb5-principal-name") == 0) 309 nameoid = GSS_KRB5_NT_PRINCIPAL_NAME; 310 else 311 errx(1, "%s not suppported", type_string); 312 313 if (mech_string == NULL) 314 mechoid = GSS_KRB5_MECHANISM; 315 else 316 mechoid = string_to_oid(mech_string); 317 318 loop(mechoid, nameoid, argv[0], GSS_C_NO_CREDENTIAL, 319 &sctx, &cctx, &actual_mech, &deleg_cred); 320 321 if (verbose_flag) 322 printf("resulting mech: %s\n", oid_to_string(actual_mech)); 323 324 if (ret_mech_string) { 325 gss_OID retoid; 326 327 retoid = string_to_oid(ret_mech_string); 328 329 if (gss_oid_equal(retoid, actual_mech) == 0) 330 errx(1, "actual_mech mech is not the expected type %s", 331 ret_mech_string); 332 } 333 334 /* XXX should be actual_mech */ 335 if (gss_oid_equal(mechoid, GSS_KRB5_MECHANISM)) { 336 krb5_context context; 337 time_t time, skew; 338 gss_buffer_desc authz_data; 339 gss_buffer_desc in, out1, out2; 340 krb5_keyblock *keyblock, *keyblock2; 341 krb5_timestamp now; 342 krb5_error_code ret; 343 344 ret = krb5_init_context(&context); 345 if (ret) 346 errx(1, "krb5_init_context"); 347 348 ret = krb5_timeofday(context, &now); 349 if (ret) 350 errx(1, "krb5_timeofday failed"); 351 352 /* client */ 353 maj_stat = gss_krb5_export_lucid_sec_context(&min_stat, 354 &cctx, 355 1, /* version */ 356 &ctx); 357 if (maj_stat != GSS_S_COMPLETE) 358 errx(1, "gss_krb5_export_lucid_sec_context failed: %s", 359 gssapi_err(maj_stat, min_stat, actual_mech)); 360 361 362 maj_stat = gss_krb5_free_lucid_sec_context(&maj_stat, ctx); 363 if (maj_stat != GSS_S_COMPLETE) 364 errx(1, "gss_krb5_free_lucid_sec_context failed: %s", 365 gssapi_err(maj_stat, min_stat, actual_mech)); 366 367 /* server */ 368 maj_stat = gss_krb5_export_lucid_sec_context(&min_stat, 369 &sctx, 370 1, /* version */ 371 &ctx); 372 if (maj_stat != GSS_S_COMPLETE) 373 errx(1, "gss_krb5_export_lucid_sec_context failed: %s", 374 gssapi_err(maj_stat, min_stat, actual_mech)); 375 maj_stat = gss_krb5_free_lucid_sec_context(&min_stat, ctx); 376 if (maj_stat != GSS_S_COMPLETE) 377 errx(1, "gss_krb5_free_lucid_sec_context failed: %s", 378 gssapi_err(maj_stat, min_stat, actual_mech)); 379 380 maj_stat = gsskrb5_extract_authtime_from_sec_context(&min_stat, 381 sctx, 382 &time); 383 if (maj_stat != GSS_S_COMPLETE) 384 errx(1, "gsskrb5_extract_authtime_from_sec_context failed: %s", 385 gssapi_err(maj_stat, min_stat, actual_mech)); 386 387 skew = abs(time - now); 388 if (skew > krb5_get_max_time_skew(context)) { 389 errx(1, "gsskrb5_extract_authtime_from_sec_context failed: " 390 "time skew too great %llu > %llu", 391 (unsigned long long)skew, 392 (unsigned long long)krb5_get_max_time_skew(context)); 393 } 394 395 maj_stat = gsskrb5_extract_service_keyblock(&min_stat, 396 sctx, 397 &keyblock); 398 if (maj_stat != GSS_S_COMPLETE) 399 errx(1, "gsskrb5_export_service_keyblock failed: %s", 400 gssapi_err(maj_stat, min_stat, actual_mech)); 401 402 krb5_free_keyblock(context, keyblock); 403 404 maj_stat = gsskrb5_get_subkey(&min_stat, 405 sctx, 406 &keyblock); 407 if (maj_stat != GSS_S_COMPLETE 408 && (!(maj_stat == GSS_S_FAILURE && min_stat == GSS_KRB5_S_KG_NO_SUBKEY))) 409 errx(1, "gsskrb5_get_subkey server failed: %s", 410 gssapi_err(maj_stat, min_stat, actual_mech)); 411 412 if (maj_stat != GSS_S_COMPLETE) 413 keyblock = NULL; 414 415 maj_stat = gsskrb5_get_subkey(&min_stat, 416 cctx, 417 &keyblock2); 418 if (maj_stat != GSS_S_COMPLETE 419 && (!(maj_stat == GSS_S_FAILURE && min_stat == GSS_KRB5_S_KG_NO_SUBKEY))) 420 errx(1, "gsskrb5_get_subkey client failed: %s", 421 gssapi_err(maj_stat, min_stat, actual_mech)); 422 423 if (maj_stat != GSS_S_COMPLETE) 424 keyblock2 = NULL; 425 426 if (keyblock || keyblock2) { 427 if (keyblock == NULL) 428 errx(1, "server missing token keyblock"); 429 if (keyblock2 == NULL) 430 errx(1, "client missing token keyblock"); 431 432 if (keyblock->keytype != keyblock2->keytype) 433 errx(1, "enctype mismatch"); 434 if (keyblock->keyvalue.length != keyblock2->keyvalue.length) 435 errx(1, "key length mismatch"); 436 if (memcmp(keyblock->keyvalue.data, keyblock2->keyvalue.data, 437 keyblock2->keyvalue.length) != 0) 438 errx(1, "key data mismatch"); 439 } 440 441 if (keyblock) 442 krb5_free_keyblock(context, keyblock); 443 if (keyblock2) 444 krb5_free_keyblock(context, keyblock2); 445 446 maj_stat = gsskrb5_get_initiator_subkey(&min_stat, 447 sctx, 448 &keyblock); 449 if (maj_stat != GSS_S_COMPLETE 450 && (!(maj_stat == GSS_S_FAILURE && min_stat == GSS_KRB5_S_KG_NO_SUBKEY))) 451 errx(1, "gsskrb5_get_initiator_subkey failed: %s", 452 gssapi_err(maj_stat, min_stat, actual_mech)); 453 454 if (maj_stat == GSS_S_COMPLETE) 455 krb5_free_keyblock(context, keyblock); 456 457 maj_stat = gsskrb5_extract_authz_data_from_sec_context(&min_stat, 458 sctx, 459 128, 460 &authz_data); 461 if (maj_stat == GSS_S_COMPLETE) 462 gss_release_buffer(&min_stat, &authz_data); 463 464 krb5_free_context(context); 465 466 467 memset(&out1, 0, sizeof(out1)); 468 memset(&out2, 0, sizeof(out2)); 469 470 in.value = "foo"; 471 in.length = 3; 472 473 gss_pseudo_random(&min_stat, sctx, GSS_C_PRF_KEY_FULL, &in, 474 100, &out1); 475 gss_pseudo_random(&min_stat, cctx, GSS_C_PRF_KEY_FULL, &in, 476 100, &out2); 477 478 if (out1.length != out2.length) 479 errx(1, "prf len mismatch"); 480 if (memcmp(out1.value, out2.value, out1.length) != 0) 481 errx(1, "prf data mismatch"); 482 483 gss_release_buffer(&min_stat, &out1); 484 485 gss_pseudo_random(&min_stat, sctx, GSS_C_PRF_KEY_FULL, &in, 486 100, &out1); 487 488 if (out1.length != out2.length) 489 errx(1, "prf len mismatch"); 490 if (memcmp(out1.value, out2.value, out1.length) != 0) 491 errx(1, "prf data mismatch"); 492 493 gss_release_buffer(&min_stat, &out1); 494 gss_release_buffer(&min_stat, &out2); 495 496 in.value = "bar"; 497 in.length = 3; 498 499 gss_pseudo_random(&min_stat, sctx, GSS_C_PRF_KEY_PARTIAL, &in, 500 100, &out1); 501 gss_pseudo_random(&min_stat, cctx, GSS_C_PRF_KEY_PARTIAL, &in, 502 100, &out2); 503 504 if (out1.length != out2.length) 505 errx(1, "prf len mismatch"); 506 if (memcmp(out1.value, out2.value, out1.length) != 0) 507 errx(1, "prf data mismatch"); 508 509 gss_release_buffer(&min_stat, &out1); 510 gss_release_buffer(&min_stat, &out2); 511 512 wrapunwrap_flag = 1; 513 getverifymic_flag = 1; 514 } 515 516 if (wrapunwrap_flag) { 517 wrapunwrap(cctx, sctx, actual_mech); 518 wrapunwrap(cctx, sctx, actual_mech); 519 wrapunwrap(sctx, cctx, actual_mech); 520 wrapunwrap(sctx, cctx, actual_mech); 521 } 522 if (getverifymic_flag) { 523 getverifymic(cctx, sctx, actual_mech); 524 getverifymic(cctx, sctx, actual_mech); 525 getverifymic(sctx, cctx, actual_mech); 526 getverifymic(sctx, cctx, actual_mech); 527 } 528 529 gss_delete_sec_context(&min_stat, &cctx, NULL); 530 gss_delete_sec_context(&min_stat, &sctx, NULL); 531 532 if (deleg_cred != GSS_C_NO_CREDENTIAL) { 533 534 loop(mechoid, nameoid, argv[0], deleg_cred, &cctx, &sctx, &actual_mech, NULL); 535 536 gss_delete_sec_context(&min_stat, &cctx, NULL); 537 gss_delete_sec_context(&min_stat, &sctx, NULL); 538 539 } 540 541 return 0; 542 } 543