1/* 2 * Copyright (c) 2006 - 2008 Kungliga Tekniska Högskolan 3 * (Royal Institute of Technology, Stockholm, Sweden). 4 * All rights reserved. 5 * 6 * Portions Copyright (c) 2009 Apple Inc. 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 <getarg.h> 39#include <gssapi.h> 40#include <gssapi_krb5.h> 41#include <gssapi_spnego.h> 42#include <gssapi_ntlm.h> 43#include <gssapi_spi.h> 44#include "test_common.h" 45#include "fuzzer.h" 46 47static char *type_string; 48static char *mech_string; 49static char *cred_string; 50static char *client_name; 51 52static int max_loops = 20; 53static int fuzzer_loops = 1000000; 54static int fuzzer_failure = 0; 55static int fuzzer_slipped_by = 0; 56static int version_flag = 0; 57static char *dumpfile_string = NULL; 58static int verbose_flag = 0; 59static int help_flag = 0; 60 61enum return_value { 62 NEXT_ITERATION = 0, 63 NEXT_TARGET = 1, 64 NEXT_FUZZER = 2 65}; 66 67static heim_fuzz_type_t fuzzers[] = { 68 HEIM_FUZZ_RANDOM, 69 HEIM_FUZZ_BITFLIP, 70 HEIM_FUZZ_BYTEFLIP, 71 HEIM_FUZZ_SHORTFLIP, 72 HEIM_FUZZ_WORDFLIP, 73 HEIM_FUZZ_INTERESTING8, 74 HEIM_FUZZ_INTERESTING16, 75 HEIM_FUZZ_INTERESTING32, 76#if 0 77 HEIM_FUZZ_ASN1, 78#endif 79 NULL 80}; 81 82static enum return_value 83loop(heim_fuzz_type_t fuzzer, gss_OID mechoid, gss_const_OID nameoid, const char *target, gss_cred_id_t init_cred, 84 unsigned long target_loop, 85 unsigned long iteration_count, 86 void **fuzzer_context) 87{ 88 int server_done = 0, client_done = 0; 89 int num_loops = 0; 90 unsigned long current_target = 0; 91 OM_uint32 maj_stat, min_stat; 92 gss_name_t gss_target_name = GSS_C_NO_NAME; 93 gss_buffer_desc input_token, output_token; 94 OM_uint32 flags = 0, ret_cflags, ret_sflags; 95 gss_OID actual_mech_client; 96 gss_OID actual_mech_server; 97 gss_ctx_id_t cctx = NULL, sctx = NULL; 98 int fuzzer_changed = 0; 99 enum return_value return_value = NEXT_ITERATION; 100 101 flags |= GSS_C_INTEG_FLAG; 102 flags |= GSS_C_CONF_FLAG; 103 flags |= GSS_C_MUTUAL_FLAG; 104 105 input_token.value = rk_UNCONST(target); 106 input_token.length = strlen(target); 107 108 maj_stat = gss_import_name(&min_stat, 109 &input_token, 110 nameoid, 111 &gss_target_name); 112 if (GSS_ERROR(maj_stat)) 113 err(1, "import name creds failed with: %d", maj_stat); 114 115 input_token.length = 0; 116 input_token.value = NULL; 117 118 output_token.length = 0; 119 output_token.value = NULL; 120 121 while (!server_done || !client_done) { 122 123 num_loops++; 124 125 if (max_loops && max_loops < num_loops) { 126 errx(1, "num loops %d was larger then max loops %d", 127 num_loops, max_loops); 128 } 129 130 if (target_loop == current_target) { 131 uint8_t *data = (uint8_t *)input_token.value; 132 133 fuzzer_changed = 1; 134 135 if (heim_fuzzer(fuzzer, fuzzer_context, iteration_count, data, input_token.length)) { 136 heim_fuzzer_free(fuzzer, *fuzzer_context); 137 *fuzzer_context = NULL; 138 return_value = NEXT_TARGET; 139 goto out; 140 } 141 142 if (dumpfile_string) 143 rk_dumpdata(dumpfile_string, data, input_token.length); 144 } 145 current_target++; 146 147 maj_stat = gss_init_sec_context(&min_stat, 148 init_cred, 149 &cctx, 150 gss_target_name, 151 mechoid, 152 flags, 153 0, 154 GSS_C_NO_CHANNEL_BINDINGS, 155 &input_token, 156 &actual_mech_client, 157 &output_token, 158 &ret_cflags, 159 NULL); 160 if (dumpfile_string) 161 unlink(dumpfile_string); 162 163 if (GSS_ERROR(maj_stat)) { 164 if (verbose_flag) 165 warnx("init_sec_context: %s", 166 gssapi_err(maj_stat, min_stat, mechoid)); 167 fuzzer_failure++; 168 goto out; 169 } 170 171 if (maj_stat & GSS_S_CONTINUE_NEEDED) 172 ; 173 else 174 client_done = 1; 175 176 177 if (client_done && server_done) 178 break; 179 180 if (input_token.length != 0) 181 gss_release_buffer(&min_stat, &input_token); 182 183 if (target_loop == current_target) { 184 uint8_t *data = (uint8_t *)output_token.value; 185 186 fuzzer_changed = 1; 187 188 if (heim_fuzzer(fuzzer, fuzzer_context, iteration_count, data, output_token.length)) { 189 heim_fuzzer_free(fuzzer, *fuzzer_context); 190 *fuzzer_context = NULL; 191 return_value = NEXT_TARGET; 192 goto out; 193 } 194 195 if (dumpfile_string) 196 rk_dumpdata(dumpfile_string, data, input_token.length); 197 } 198 current_target++; 199 200 maj_stat = gss_accept_sec_context(&min_stat, 201 &sctx, 202 GSS_C_NO_CREDENTIAL, 203 &output_token, 204 GSS_C_NO_CHANNEL_BINDINGS, 205 NULL, 206 &actual_mech_server, 207 &input_token, 208 &ret_sflags, 209 NULL, 210 NULL); 211 if (dumpfile_string) 212 unlink(dumpfile_string); 213 214 if (GSS_ERROR(maj_stat)) { 215 if (verbose_flag) 216 warnx("accept_sec_context: %s", 217 gssapi_err(maj_stat, min_stat, actual_mech_server)); 218 fuzzer_failure++; 219 goto out; 220 } 221 222 223 if (output_token.length != 0) 224 gss_release_buffer(&min_stat, &output_token); 225 226 if (maj_stat & GSS_S_CONTINUE_NEEDED) 227 ; 228 else 229 server_done = 1; 230 231 } 232 233 if (client_done && server_done) { 234 if (!fuzzer_changed) 235 return_value = NEXT_FUZZER; 236 else 237 fuzzer_slipped_by++; 238 } 239 240 out: 241 gss_delete_sec_context(&min_stat, &cctx, NULL); 242 gss_delete_sec_context(&min_stat, &sctx, NULL); 243 244 if (output_token.length != 0) 245 gss_release_buffer(&min_stat, &output_token); 246 if (input_token.length != 0) 247 gss_release_buffer(&min_stat, &input_token); 248 gss_release_name(&min_stat, &gss_target_name); 249 250 return return_value; 251} 252 253 254/* 255 * 256 */ 257 258static struct getargs args[] = { 259 {"name-type",0, arg_string, &type_string, "type of name", NULL }, 260 {"mech-type",0, arg_string, &mech_string, "type of mech", NULL }, 261 262 {"cred-type",0, arg_string, &cred_string, "type of cred", NULL }, 263 {"client-name", 0, arg_string, &client_name, "client name", NULL }, 264 265 {"max-loops", 0, arg_integer, &max_loops, "times", NULL }, 266 {"fuzzer-loops", 0, arg_integer, &fuzzer_loops, "times", NULL }, 267 {"dump-data", 0, arg_string, &dumpfile_string, "file", NULL }, 268 {"version", 0, arg_flag, &version_flag, "print version", NULL }, 269 {"verbose", 'v', arg_flag, &verbose_flag, "verbose", NULL }, 270 {"help", 0, arg_flag, &help_flag, NULL, NULL } 271}; 272 273static void 274usage (int ret) 275{ 276 arg_printusage (args, sizeof(args)/sizeof(*args), 277 NULL, "service@host"); 278 exit (ret); 279} 280 281int 282main(int argc, char **argv) 283{ 284 int optidx = 0; 285 OM_uint32 min_stat, maj_stat; 286 gss_const_OID nameoid, mechoid; 287 gss_cred_id_t client_cred = GSS_C_NO_CREDENTIAL; 288 gss_name_t cname = GSS_C_NO_NAME; 289 unsigned long current_target, current_iteration, current_fuzzer; 290 unsigned long n, divN; 291 int end_of_fuzzer = 0; 292 int ttyp = isatty(STDIN_FILENO); 293 void *fuzzer_context = NULL; 294 295 setprogname(argv[0]); 296 297 if(getarg(args, sizeof(args) / sizeof(args[0]), argc, argv, &optidx)) 298 usage(1); 299 300 if (help_flag) 301 usage (0); 302 303 if(version_flag){ 304 print_version(NULL); 305 exit(0); 306 } 307 308 argc -= optidx; 309 argv += optidx; 310 311 if (argc != 1) 312 usage(1); 313 314 if (fuzzer_loops < 0) 315 errx(1, "invalid number of loops"); 316 317 if (type_string == NULL) 318 nameoid = GSS_C_NT_HOSTBASED_SERVICE; 319 else if (strcmp(type_string, "hostbased-service") == 0) 320 nameoid = GSS_C_NT_HOSTBASED_SERVICE; 321 else if (strcmp(type_string, "krb5-principal-name") == 0) 322 nameoid = GSS_KRB5_NT_PRINCIPAL_NAME; 323 else if (strcmp(type_string, "krb5-principal-name-referral") == 0) 324 nameoid = GSS_KRB5_NT_PRINCIPAL_NAME_REFERRAL; 325 else 326 errx(1, "%s not suppported", type_string); 327 328 if (mech_string == NULL) 329 mechoid = GSS_KRB5_MECHANISM; 330 else { 331 mechoid = gss_name_to_oid(mech_string); 332 if (mechoid == GSS_C_NO_OID) 333 errx(1, "failed to find mech oid: %s", mech_string); 334 } 335 336 if (client_name) { 337 gss_buffer_desc cn; 338 gss_const_OID credoid = GSS_C_NO_OID; 339 gss_OID_set mechs = GSS_C_NULL_OID_SET; 340 341 if (cred_string) { 342 credoid = gss_name_to_oid(cred_string); 343 if (credoid == GSS_C_NO_OID) 344 errx(1, "failed to find cred oid: %s", cred_string); 345 } 346 347 cn.value = client_name; 348 cn.length = strlen(client_name); 349 350 maj_stat = gss_import_name(&min_stat, &cn, GSS_C_NT_USER_NAME, &cname); 351 if (maj_stat) 352 errx(1, "gss_import_name: %s", 353 gssapi_err(maj_stat, min_stat, GSS_C_NO_OID)); 354 355 356 357 if (credoid != GSS_C_NO_OID) { 358 maj_stat = gss_create_empty_oid_set(&min_stat, &mechs); 359 if (maj_stat != GSS_S_COMPLETE) 360 errx(1, "gss_create_empty_oid_set: %s", 361 gssapi_err(maj_stat, min_stat, GSS_C_NO_OID)); 362 363 maj_stat = gss_add_oid_set_member(&min_stat, credoid, &mechs); 364 if (maj_stat != GSS_S_COMPLETE) 365 errx(1, "gss_add_oid_set_member: %s", 366 gssapi_err(maj_stat, min_stat, GSS_C_NO_OID)); 367 } 368 369 maj_stat = gss_acquire_cred(&min_stat, cname, 0, mechs, 370 GSS_C_INITIATE, &client_cred, NULL, NULL); 371 if (GSS_ERROR(maj_stat)) 372 errx(1, "gss_import_name: %s", 373 gssapi_err(maj_stat, min_stat, GSS_C_NO_OID)); 374 375 if (mechs != GSS_C_NULL_OID_SET) 376 gss_release_oid_set(&min_stat, &mechs); 377 378 gss_release_name(&min_stat, &cname); 379 380 } else { 381 maj_stat = gss_acquire_cred(&min_stat, 382 cname, 383 GSS_C_INDEFINITE, 384 GSS_C_NO_OID_SET, 385 GSS_C_INITIATE, 386 &client_cred, 387 NULL, 388 NULL); 389 if (GSS_ERROR(maj_stat)) 390 errx(1, "gss_acquire_cred: %s", 391 gssapi_err(maj_stat, min_stat, GSS_C_NO_OID)); 392 } 393 394 /* 395 * 396 */ 397 398 divN = fuzzer_loops / 10; 399 if (divN == 0) 400 divN = 1; 401 402 current_fuzzer = current_target = current_iteration = 0; 403 404 for (n = 1; n <= (unsigned long)fuzzer_loops && !end_of_fuzzer; n++) { 405 enum return_value return_value; 406 407 return_value = loop(fuzzers[current_fuzzer], rk_UNCONST(mechoid), nameoid, 408 argv[0], client_cred, current_target, current_iteration, &fuzzer_context); 409 switch (return_value) { 410 case NEXT_ITERATION: 411 current_iteration++; 412 break; 413 414 case NEXT_TARGET: 415 if (fuzzer_context != NULL) 416 errx(1, "fuzzer context not NULL at next target state?"); 417 if (ttyp) 418 printf("\b"); 419 printf("fuzzer %s targets next step (%lu) at: %lu\n", 420 heim_fuzzer_name(fuzzers[current_fuzzer]), 421 current_target + 1, 422 (unsigned long)current_iteration); 423 current_iteration = 0; 424 current_target++; 425 break; 426 427 case NEXT_FUZZER: 428 if (ttyp) 429 printf("\b"); 430 printf("fuzzer %s done at: %lu\n", 431 heim_fuzzer_name(fuzzers[current_fuzzer]), n); 432 current_target = 0; 433 current_iteration = 0; 434 435 current_fuzzer++; 436 if (fuzzers[current_fuzzer] == NULL) 437 end_of_fuzzer = 1; 438 break; 439 } 440 441 if ((n % divN) == 0) { 442 if (ttyp) 443 printf("\b"); 444 printf(" try %lu\n", (unsigned long)n); 445 } else if (ttyp && (n & 0xff) == 0) { 446 printf("\b%d", (int)((n >> 8) % 10)); 447 } 448 } 449 450 if (ttyp) 451 printf("\b"); 452 453 if (!end_of_fuzzer) 454 printf("fuzzer: %s step: %lu iteration: %lu\n", 455 heim_fuzzer_name(fuzzers[current_fuzzer]), 456 current_target, 457 current_iteration); 458 459 printf("fuzzer: tries: %lu failure: %d " 460 "modified-but-non-failure: %d end-of-fuzzer: %d\n", 461 (unsigned long)n, 462 fuzzer_failure, 463 fuzzer_slipped_by, 464 end_of_fuzzer); 465 466 return 0; 467} 468