1/* Copyright 2006 Apple Computer, Inc. 2 * 3 * ccSymTest.c - test CommonCrypto symmetric encrypt/decrypt. 4 */ 5#include "testmore.h" 6#include "capabilities.h" 7#if (CCSYMREGRESSION == 0) 8entryPoint(CommonCryptoSymRegression,"CommonCrypto Base Behavior Regression Tests") 9#else 10 11 12 13#include <string.h> 14#include <stdlib.h> 15#include <stdio.h> 16#include <sys/types.h> 17#include <CommonCrypto/CommonCryptor.h> 18#include <fcntl.h> 19#include <sys/types.h> 20#include <sys/uio.h> 21#include <unistd.h> 22 23// #include <CoreServices/../Frameworks/CarbonCore.framework/Headers/MacErrors.h> 24 25/* 26 * Defaults. 27 */ 28#define LOOPS_DEF 500 29#define MIN_DATA_SIZE 8 30#define MAX_DATA_SIZE 10000 /* bytes */ 31#define MAX_KEY_SIZE kCCKeySizeMaxRC4 /* bytes */ 32#define MAX_BLOCK_SIZE kCCBlockSizeAES128 /* bytes */ 33#define LOOP_NOTIFY 250 34 35/* 36 * Enumerate algs our own way to allow iteration. 37 */ 38typedef enum { 39 ALG_AES_128 = 1, /* 128 bit block, 128 bit key */ 40 ALG_AES_192, /* 128 bit block, 192 bit key */ 41 ALG_AES_256, /* 128 bit block, 256 bit key */ 42 ALG_DES, 43 ALG_3DES, 44 ALG_CAST, 45 ALG_RC4, 46 /* these aren't in CommonCrypto (yet?) */ 47 ALG_RC2, 48 ALG_RC5, 49 ALG_BFISH, 50 ALG_ASC, 51 ALG_NULL /* normally not used */ 52} SymAlg; 53#define ALG_FIRST ALG_AES_128 54#define ALG_LAST ALG_RC4 55 56 57#define LOG_SIZE 0 58#if LOG_SIZE 59#define logSize(s) diag s 60#else 61#define logSize(s) 62#endif 63 64 65 66 67static void 68appGetRandomBytes(void *keyBytes, size_t keySizeInBytes) 69{ 70 int fd; 71 72 if((fd = open("/dev/random", O_RDONLY)) < 0) { 73 diag("Can't open Random\n"); 74 exit(0); 75 } 76 if(read(fd, keyBytes, keySizeInBytes) != (int) keySizeInBytes) { 77 diag("Can't read Random\n"); 78 exit(0); 79 } 80 close(fd); 81} 82 83/* min <= return <= max */ 84static unsigned 85genRand(unsigned min, unsigned max) 86{ 87 unsigned i; 88 if(min == max) { 89 return min; 90 } 91 appGetRandomBytes(&i, 4); 92 return (min + (i % (max - min + 1))); 93} 94 95 96static void printCCError(const char *str, CCCryptorStatus crtn) 97{ 98 const char *errStr; 99 char unknownStr[200]; 100 101 switch(crtn) { 102 case kCCSuccess: errStr = "kCCSuccess"; break; 103 case kCCParamError: errStr = "kCCParamError"; break; 104 case kCCBufferTooSmall: errStr = "kCCBufferTooSmall"; break; 105 case kCCMemoryFailure: errStr = "kCCMemoryFailure"; break; 106 case kCCAlignmentError: errStr = "kCCAlignmentError"; break; 107 case kCCDecodeError: errStr = "kCCDecodeError"; break; 108 case kCCUnimplemented: errStr = "kCCUnimplemented"; break; 109 default: 110 sprintf(unknownStr, "Unknown(%ld)\n", (long)crtn); 111 errStr = unknownStr; 112 break; 113 } 114 diag("***%s returned %s\n", str, errStr); 115} 116 117/* max context size */ 118#define CC_MAX_CTX_SIZE kCCContextSizeRC4 119 120/* 121 * We write a marker at end of expected output and at end of caller-allocated 122 * CCCryptorRef, and check at the end to make sure they weren't written 123 */ 124#define MARKER_LENGTH 8 125#define MARKER_BYTE 0x7e 126 127/* 128 * Test harness for CCCryptor with lots of options. 129 */ 130static CCCryptorStatus doCCCrypt( 131 bool forEncrypt, 132 CCAlgorithm encrAlg, 133 bool doCbc, 134 bool doPadding, 135 const void *keyBytes, size_t keyLen, 136 const void *iv, 137 bool randUpdates, 138 bool inPlace, /* !doPadding only */ 139 size_t ctxSize, /* if nonzero, we allocate ctx */ 140 bool askOutSize, 141 const uint8_t *inText, size_t inTextLen, 142 uint8_t **outText, size_t *outTextLen) /* both returned, WE malloc */ 143{ 144 CCCryptorRef cryptor = NULL; 145 CCCryptorStatus crtn; 146 CCOperation op = forEncrypt ? kCCEncrypt : kCCDecrypt; 147 CCOptions options = 0; 148 uint8_t *outBuf = NULL; /* mallocd output buffer */ 149 uint8_t *outp; /* running ptr into outBuf */ 150 const uint8_t *inp; /* running ptr into inText */ 151 size_t outLen = 0; /* bytes remaining in outBuf */ 152 size_t toMove; /* bytes remaining in inText */ 153 size_t thisMoveOut; /* output from CCCryptUpdate()/CCCryptFinal() */ 154 size_t outBytes; /* total bytes actually produced in outBuf */ 155 uint8_t ctx[CC_MAX_CTX_SIZE]; /* for CCCryptorCreateFromData() */ 156 uint8_t *textMarker = NULL; /* 8 bytes of marker here after expected end of 157 * output */ 158 uint8_t *ctxMarker = NULL; /* ditto for caller-provided context */ 159 unsigned dex; 160 size_t askedOutSize; /* from the lib */ 161 size_t thisOutLen; /* dataOutAvailable we use */ 162 163 164 if(0) diag("%s %s %s keylen %d %s %s %s %s %s input length %ld\n", 165 forEncrypt ? "Encrypting": "Decrypting", 166 doCbc ? "CBC": "ECB", 167 doPadding ? "Padding ON": "Padding OFF", 168 (int) keyLen, 169 iv ? "IV Provided": "No IV Provided", 170 randUpdates ? "Random Updates": "Non-Random Updates", 171 inPlace ? "In Place": "Separate Buffers", 172 ctxSize ? "We Allocate": "CC Allocated", 173 askOutSize ? "Ask OutSize": "Don't Ask OutSize", 174 inTextLen); 175 176 if(ctxSize > CC_MAX_CTX_SIZE) { 177 diag("***HEY! Adjust CC_MAX_CTX_SIZE!\n"); 178 exit(1); 179 } 180 if(!doCbc) { 181 options |= kCCOptionECBMode; 182 } 183 if(doPadding) { 184 options |= kCCOptionPKCS7Padding; 185 } 186 187 /* just hack this one */ 188 outLen = inTextLen; 189 if(forEncrypt) { 190 outLen += MAX_BLOCK_SIZE; 191 } 192 193 outBuf = (uint8_t *)malloc(outLen + MARKER_LENGTH); 194 memset(outBuf, 0xEE, outLen + MARKER_LENGTH); 195 196 /* library should not touch this memory */ 197 textMarker = outBuf + outLen; 198 memset(textMarker, MARKER_BYTE, MARKER_LENGTH); 199 200 /* subsequent errors to errOut: */ 201 202 if(inPlace) { 203 memmove(outBuf, inText, inTextLen); 204 inp = outBuf; 205 } 206 else { 207 inp = inText; 208 } 209 210 if(!randUpdates) { 211 /* one shot */ 212 if(askOutSize) { 213 crtn = CCCrypt(op, encrAlg, options, 214 keyBytes, keyLen, iv, 215 inp, inTextLen, 216 outBuf, 0, &askedOutSize); 217 if(crtn != kCCBufferTooSmall) { 218 diag("***Did not get kCCBufferTooSmall as expected\n"); 219 diag(" alg %d inTextLen %lu cbc %d padding %d keyLen %lu\n", 220 (int)encrAlg, (unsigned long)inTextLen, (int)doCbc, (int)doPadding, 221 (unsigned long)keyLen); 222 printCCError("CCCrypt", crtn); 223 crtn = -1; 224 goto errOut; 225 } 226 outLen = askedOutSize; 227 } 228 crtn = CCCrypt(op, encrAlg, options, 229 keyBytes, keyLen, iv, 230 inp, inTextLen, 231 outBuf, outLen, &outLen); 232 if(crtn) { 233 printCCError("CCCrypt", crtn); 234 goto errOut; 235 } 236 *outText = outBuf; 237 *outTextLen = outLen; 238 goto errOut; 239 } 240 241 /* random multi updates */ 242 if(ctxSize) { 243 size_t ctxSizeCreated; 244 245 if(askOutSize) { 246 crtn = CCCryptorCreateFromData(op, encrAlg, options, 247 keyBytes, keyLen, iv, 248 ctx, 0 /* ctxSize */, 249 &cryptor, &askedOutSize); 250 if(crtn != kCCBufferTooSmall) { 251 diag("***Did not get kCCBufferTooSmall as expected\n"); 252 printCCError("CCCryptorCreateFromData", crtn); 253 crtn = -1; 254 goto errOut; 255 } 256 ctxSize = askedOutSize; 257 } 258 crtn = CCCryptorCreateFromData(op, encrAlg, options, 259 keyBytes, keyLen, iv, 260 ctx, ctxSize, &cryptor, &ctxSizeCreated); 261 if(crtn) { 262 printCCError("CCCryptorCreateFromData", crtn); 263 return crtn; 264 } 265 ctxMarker = ctx + ctxSizeCreated; 266 memset(ctxMarker, MARKER_BYTE, MARKER_LENGTH); 267 } 268 else { 269 crtn = CCCryptorCreate(op, encrAlg, options, 270 keyBytes, keyLen, iv, 271 &cryptor); 272 if(crtn) { 273 printCCError("CCCryptorCreate", crtn); 274 return crtn; 275 } 276 } 277 278 toMove = inTextLen; /* total to go */ 279 outp = outBuf; 280 outBytes = 0; /* bytes actually produced in outBuf */ 281 282 while(toMove) { 283 size_t thisMoveIn; /* input to CCryptUpdate() */ 284 285 thisMoveIn = (size_t) genRand(1, (unsigned int) toMove); 286 logSize(("###ptext segment len %lu\n", (unsigned long)thisMoveIn)); 287 if(askOutSize) { 288 thisOutLen = CCCryptorGetOutputLength(cryptor, thisMoveIn, false); 289 } 290 else { 291 thisOutLen = outLen; 292 } 293 crtn = CCCryptorUpdate(cryptor, inp, thisMoveIn, 294 outp, thisOutLen, &thisMoveOut); 295 if(crtn) { 296 printCCError("CCCryptorUpdate", crtn); 297 goto errOut; 298 } 299 inp += thisMoveIn; 300 toMove -= thisMoveIn; 301 outp += thisMoveOut; 302 outLen -= thisMoveOut; 303 outBytes += thisMoveOut; 304 } 305 306 if(doPadding) { 307 /* Final is not needed if padding is disabled */ 308 if(askOutSize) { 309 thisOutLen = CCCryptorGetOutputLength(cryptor, 0, true); 310 } 311 else { 312 thisOutLen = outLen; 313 } 314 crtn = CCCryptorFinal(cryptor, outp, thisOutLen, &thisMoveOut); 315 } 316 else { 317 thisMoveOut = 0; 318 crtn = kCCSuccess; 319 } 320 321 if(crtn) { 322 printCCError("CCCryptorFinal", crtn); 323 goto errOut; 324 } 325 326 outBytes += thisMoveOut; 327 *outText = outBuf; 328 *outTextLen = outBytes; 329 crtn = kCCSuccess; 330 331 for(dex=0; dex<MARKER_LENGTH; dex++) { 332 if(textMarker[dex] != MARKER_BYTE) { 333 diag("***lib scribbled on our textMarker memory (op=%s)!\n", 334 forEncrypt ? "encrypt" : "decrypt"); 335 crtn = (CCCryptorStatus)-1; 336 } 337 } 338 if(ctxSize) { 339 for(dex=0; dex<MARKER_LENGTH; dex++) { 340 if(ctxMarker[dex] != MARKER_BYTE) { 341 diag("***lib scribbled on our ctxMarker memory (op=%s)!\n", 342 forEncrypt ? "encrypt" : "decrypt"); 343 crtn = (CCCryptorStatus)-1; 344 } 345 } 346 } 347 348errOut: 349 if(crtn) { 350 if(outBuf) { 351 free(outBuf); 352 } 353 } 354 if(cryptor) { 355 CCCryptorRelease(cryptor); 356 } 357 return crtn; 358} 359 360static int doTest(const uint8_t *ptext, 361 size_t ptextLen, 362 CCAlgorithm encrAlg, 363 bool doCbc, 364 bool doPadding, 365 bool nullIV, /* if CBC, use NULL IV */ 366 uint32_t keySizeInBytes, 367 bool stagedEncr, 368 bool stagedDecr, 369 bool inPlace, 370 size_t ctxSize, 371 bool askOutSize, 372 bool quiet) 373{ 374 uint8_t keyBytes[MAX_KEY_SIZE]; 375 uint8_t iv[MAX_BLOCK_SIZE]; 376 uint8_t *ivPtrEncrypt; 377 uint8_t *ivPtrDecrypt; 378 uint8_t *ctext = NULL; /* mallocd by doCCCrypt */ 379 size_t ctextLen = 0; 380 uint8_t *rptext = NULL; /* mallocd by doCCCrypt */ 381 size_t rptextLen = 0; 382 CCCryptorStatus crtn; 383 int rtn = 0; 384 385 /* random key */ 386 appGetRandomBytes(keyBytes, keySizeInBytes); 387 388 /* random IV if needed */ 389 if(doCbc) { 390 if(nullIV) { 391 memset(iv, 0, MAX_BLOCK_SIZE); 392 393 /* flip a coin, give one side NULL, the other size zeroes */ 394 if(genRand(1,2) == 1) { 395 ivPtrEncrypt = NULL; 396 ivPtrDecrypt = iv; 397 } 398 else { 399 ivPtrEncrypt = iv; 400 ivPtrDecrypt = NULL; 401 } 402 } 403 else { 404 appGetRandomBytes(iv, MAX_BLOCK_SIZE); 405 ivPtrEncrypt = iv; 406 ivPtrDecrypt = iv; 407 } 408 } 409 else { 410 ivPtrEncrypt = NULL; 411 ivPtrDecrypt = NULL; 412 } 413 414 crtn = doCCCrypt(true, encrAlg, doCbc, doPadding, 415 keyBytes, keySizeInBytes, ivPtrEncrypt, 416 stagedEncr, inPlace, ctxSize, askOutSize, 417 ptext, ptextLen, 418 &ctext, &ctextLen); 419 420 ok(crtn == 0, "doCCCrypt"); 421 if(crtn) { 422 diag("Test Failure Encrypt encrAlg = %d dodCbc = %d doPadding %d\n", encrAlg, doCbc, doPadding); 423 } 424 425 logSize(("###ctext len %lu\n", ctextLen)); 426 crtn = doCCCrypt(false, encrAlg, doCbc, doPadding, 427 keyBytes, keySizeInBytes, ivPtrDecrypt, 428 stagedDecr, inPlace, ctxSize, askOutSize, 429 ctext, ctextLen, 430 &rptext, &rptextLen); 431 ok(crtn == 0, "doCCCrypt"); 432 if(crtn) { 433 diag("Test Failure Encrypt encrAlg = %d dodCbc = %d doPadding %d\n", encrAlg, doCbc, doPadding); 434 } 435 436 logSize(("###rptext len %lu\n", rptextLen)); 437 438 /* compare ptext, rptext */ 439 if(ptextLen != rptextLen) { 440 diag("Ptext length mismatch: expect %lu, got %lu\n", ptextLen, rptextLen); 441 } else if(memcmp(ptext, rptext, ptextLen)) { 442 diag("***data miscompare\n"); 443 } 444 445 if(ctext) { 446 free(ctext); 447 } 448 if(rptext) { 449 free(rptext); 450 } 451 return rtn; 452} 453 454static bool isBitSet(unsigned bit, unsigned word) 455{ 456 if(bit > 31) { 457 diag("We don't have that many bits\n"); 458 exit(1); 459 } 460 unsigned mask = 1 << bit; 461 return (word & mask) ? true : false; 462} 463 464 465static int kTestTestCount = 7001; 466 467 468int CommonCryptoSymRegression(int argc, char *const *argv) 469{ 470 unsigned loop; 471 uint8_t *ptext; 472 size_t ptextLen; 473 bool stagedEncr = false; 474 bool stagedDecr = false; 475 bool doPadding; 476 bool doCbc = false; 477 bool nullIV; 478 const char *algStr; 479 CCAlgorithm encrAlg; 480 int i; 481 SymAlg currAlg; // ALG_xxx 482 uint32_t minKeySizeInBytes; 483 uint32_t maxKeySizeInBytes; 484 uint32_t keySizeInBytes = 0; 485 int rtn = 0; 486 uint32_t blockSize; // for noPadding case 487 size_t ctxSize; // always set per alg 488 size_t ctxSizeUsed; // passed to doTest 489 bool askOutSize; // inquire output size each op 490 491 /* 492 * User-spec'd params 493 */ 494 bool keySizeSpec = false; // false: use rand key size 495 SymAlg minAlg = ALG_FIRST; 496 SymAlg maxAlg = ALG_LAST; 497 unsigned loops = LOOPS_DEF; 498 bool verbose = false; 499 size_t minPtextSize = MIN_DATA_SIZE; 500 size_t maxPtextSize = MAX_DATA_SIZE; 501 bool quiet = true; 502 unsigned pauseInterval = 0; 503 bool paddingSpec = false; // true: user calls doPadding, const 504 bool cbcSpec = false; // ditto for doCbc 505 bool stagedSpec = false; // ditto for stagedEncr and stagedDecr 506 bool inPlace = false; // en/decrypt in place for ECB 507 bool allocCtxSpec = false; // use allocCtx 508 bool allocCtx = false; // allocate context ourself 509 510 plan_tests(kTestTestCount); 511 512 513 ptext = (uint8_t *)malloc(maxPtextSize); 514 if(ptext == NULL) { 515 diag("Insufficient heap space\n"); 516 exit(1); 517 } 518 /* ptext length set in test loop */ 519 520 if(!quiet) diag("Starting ccSymTest; args: "); 521 for(i=1; i<argc; i++) { 522 if(!quiet) diag("%s ", argv[i]); 523 } 524 if(!quiet) diag("\n"); 525 526 if(pauseInterval) { 527 fpurge(stdin); 528 diag("Top of test; hit CR to proceed: "); 529 getchar(); 530 } 531 532 for(currAlg=minAlg; currAlg<=maxAlg; currAlg++) { 533 switch(currAlg) { 534 case ALG_DES: 535 encrAlg = kCCAlgorithmDES; 536 blockSize = kCCBlockSizeDES; 537 minKeySizeInBytes = kCCKeySizeDES; 538 maxKeySizeInBytes = minKeySizeInBytes; 539 ctxSize = kCCContextSizeDES; 540 algStr = "DES"; 541 if(verbose) diag("Running DES Tests"); 542 break; 543 case ALG_3DES: 544 encrAlg = kCCAlgorithm3DES; 545 blockSize = kCCBlockSize3DES; 546 minKeySizeInBytes = kCCKeySize3DES; 547 maxKeySizeInBytes = minKeySizeInBytes; 548 ctxSize = kCCContextSize3DES; 549 550 algStr = "3DES"; 551 if(verbose) diag("Running 3DES Tests"); 552 break; 553 case ALG_AES_128: 554 encrAlg = kCCAlgorithmAES128; 555 blockSize = kCCBlockSizeAES128; 556 minKeySizeInBytes = kCCKeySizeAES128; 557 maxKeySizeInBytes = minKeySizeInBytes; 558 ctxSize = kCCContextSizeAES128; 559 algStr = "AES128"; 560 if(verbose) diag("Running AES (128 bit key) Tests"); 561 break; 562 case ALG_AES_192: 563 encrAlg = kCCAlgorithmAES128; 564 blockSize = kCCBlockSizeAES128; 565 minKeySizeInBytes = kCCKeySizeAES192; 566 maxKeySizeInBytes = minKeySizeInBytes; 567 ctxSize = kCCContextSizeAES128; 568 algStr = "AES192"; 569 if(verbose) diag("Running AES (192 bit key) Tests"); 570 break; 571 case ALG_AES_256: 572 encrAlg = kCCAlgorithmAES128; 573 blockSize = kCCBlockSizeAES128; 574 minKeySizeInBytes = kCCKeySizeAES256; 575 maxKeySizeInBytes = minKeySizeInBytes; 576 ctxSize = kCCContextSizeAES128; 577 algStr = "AES256"; 578 if(verbose) diag("Running AES (256 bit key) Tests"); 579 break; 580 case ALG_CAST: 581 encrAlg = kCCAlgorithmCAST; 582 blockSize = kCCBlockSizeCAST; 583 minKeySizeInBytes = kCCKeySizeMinCAST; 584 maxKeySizeInBytes = kCCKeySizeMaxCAST; 585 ctxSize = kCCContextSizeCAST; 586 algStr = "CAST"; 587 if(verbose) diag("Running CAST Tests"); 588 break; 589 case ALG_RC4: 590 encrAlg = kCCAlgorithmRC4; 591 blockSize = 0; 592 minKeySizeInBytes = kCCKeySizeMinRC4; 593 maxKeySizeInBytes = kCCKeySizeMaxRC4; 594 ctxSize = kCCContextSizeRC4; 595 algStr = "RC4"; 596 if(verbose) diag("Running RC4 Tests"); 597 break; 598 default: 599 diag("***BRRZAP!\n"); 600 exit(1); 601 } 602 if(!quiet || verbose) { 603 diag("Testing alg %s\n", algStr); 604 } 605 for(loop=1; ; loop++) { 606 ptextLen = (size_t) genRand((unsigned int) minPtextSize, (unsigned int) maxPtextSize); 607 appGetRandomBytes(ptext, ptextLen); 608 609 /* per-loop settings */ 610 if(!keySizeSpec) { 611 if(minKeySizeInBytes == maxKeySizeInBytes) { 612 keySizeInBytes = minKeySizeInBytes; 613 } 614 else { 615 keySizeInBytes = genRand(minKeySizeInBytes, maxKeySizeInBytes); 616 } 617 } 618 if(blockSize == 0) { 619 /* stream cipher */ 620 doCbc = false; 621 doPadding = false; 622 } 623 else { 624 if(!cbcSpec) { 625 doCbc = isBitSet(0, loop); 626 } 627 if(!paddingSpec) { 628 doPadding = isBitSet(1, loop); 629 } 630 } 631 if(!doPadding && (blockSize != 0)) { 632 /* align plaintext */ 633 ptextLen = (ptextLen / blockSize) * blockSize; 634 if(ptextLen == 0) { 635 ptextLen = blockSize; 636 } 637 } 638 if(!stagedSpec) { 639 stagedEncr = isBitSet(2, loop); 640 stagedDecr = isBitSet(3, loop); 641 } 642 if(doCbc) { 643 nullIV = isBitSet(4, loop); 644 } 645 else { 646 nullIV = false; 647 } 648 inPlace = isBitSet(5, loop); 649 if(allocCtxSpec) { 650 ctxSizeUsed = allocCtx ? ctxSize : 0; 651 } 652 else if(isBitSet(6, loop)) { 653 ctxSizeUsed = ctxSize; 654 } 655 else { 656 ctxSizeUsed = 0; 657 } 658 askOutSize = isBitSet(7, loop); 659 if(!quiet) { 660 if(verbose || ((loop % LOOP_NOTIFY) == 0)) { 661 diag("..loop %3d ptextLen %lu keyLen %d cbc=%d padding=%d stagedEncr=%d " 662 "stagedDecr=%d\n", 663 loop, (unsigned long)ptextLen, (int)keySizeInBytes, 664 (int)doCbc, (int)doPadding, 665 (int)stagedEncr, (int)stagedDecr); 666 diag(" nullIV %d inPlace %d ctxSize %d askOutSize %d\n", 667 (int)nullIV, (int)inPlace, (int)ctxSizeUsed, (int)askOutSize); 668 } 669 } 670 671 if(doTest(ptext, ptextLen, 672 encrAlg, doCbc, doPadding, nullIV, 673 keySizeInBytes, 674 stagedEncr, stagedDecr, inPlace, ctxSizeUsed, askOutSize, 675 quiet)) { 676 rtn = 1; 677 break; 678 } 679 if(pauseInterval && ((loop % pauseInterval) == 0)) { 680 char c; 681 fpurge(stdin); 682 diag("Hit CR to proceed, q to abort: "); 683 c = getchar(); 684 if(c == 'q') { 685 goto testDone; 686 } 687 } 688 if(loops && (loop == loops)) { 689 break; 690 } 691 } /* main loop */ 692 if(rtn) { 693 break; 694 } 695 696 } /* for algs */ 697 698testDone: 699 700 ok(rtn == 0, "ccSymTest"); 701 702 if(pauseInterval) { 703 fpurge(stdin); 704 diag("ModuleDetach/Unload complete; hit CR to exit: "); 705 getchar(); 706 } 707 if((rtn == 0) && !quiet) { 708 diag("%s test complete\n", argv[0]); 709 } 710 free(ptext); 711 return rtn; 712} 713#endif 714