]> git.saurik.com Git - apple/security.git/blob - SecurityTests/cspxutils/dhFulltest/dhFulltest.cpp
Security-57031.1.35.tar.gz
[apple/security.git] / SecurityTests / cspxutils / dhFulltest / dhFulltest.cpp
1 /*
2 * dhFullTest - Diffie-Hellman exerciser.
3 */
4 #include <stdlib.h>
5 #include <stdio.h>
6 #include <Security/cssm.h>
7 #include "cspwrap.h"
8 #include "common.h"
9 #include <security_cdsa_utils/cuFileIo.h>
10 #include <strings.h>
11 #include "cspdlTesting.h"
12
13 #define USAGE_DEF "noUsage"
14 #define LOOPS_DEF 10
15 #define KEY_SIZE_DEF 512
16 #define DERIVE_KEY_SIZE 128
17 #define DERIVE_KEY_ALG CSSM_ALGID_AES
18 #define ENCR_ALG CSSM_ALGID_AES
19 #define ENCR_MODE CSSM_ALGMODE_CBCPadIV8
20 #define ENCR_PADDING CSSM_PADDING_PKCS7
21 #define MAX_PTEXT_SIZE 1024
22
23 static void usage(char **argv)
24 {
25 printf("usage: %s [options]\n", argv[0]);
26 printf("Options:\n");
27 printf(" k=keySize (default = %d)\n", KEY_SIZE_DEF);
28 printf(" l=loops (0=forever)\n");
29 printf(" p=pauseInterval (default=0, no pause)\n");
30 printf(" D (CSP/DL; default = bare CSP)\n");
31 printf(" o=fileName (dump key and param blobs to filename)\n");
32 printf(" i=filename (obtain param blobs from filename\n");
33 printf(" q(uiet)\n");
34 printf(" v(erbose))\n");
35 exit(1);
36 }
37
38 /*
39 * Translate blob format to strings.
40 */
41 typedef struct {
42 CSSM_KEYBLOB_FORMAT form;
43 const char *str;
44 } BlobDesc;
45
46 static const BlobDesc BlobDescs[] = {
47 { CSSM_KEYBLOB_RAW_FORMAT_NONE, "NONE" },
48 { CSSM_KEYBLOB_RAW_FORMAT_PKCS3, "PKCS3" },
49 { CSSM_KEYBLOB_RAW_FORMAT_PKCS8, "PKCS8" },
50 { CSSM_KEYBLOB_RAW_FORMAT_X509, "X509" },
51 };
52 #define NUM_BLOB_DESCS (sizeof(BlobDescs) / sizeof(BlobDesc))
53
54 static const char *blobFormStr(
55 CSSM_KEYBLOB_FORMAT form)
56 {
57 for(unsigned i=0; i<NUM_BLOB_DESCS; i++) {
58 const BlobDesc *bdp = &BlobDescs[i];
59 if(bdp->form == form) {
60 return bdp->str;
61 }
62 }
63 return "***UNKNOWN BLOB FORM""";
64 }
65
66 /*
67 * Generate a Diffie-Hellman key pair. Optionally allows specification of
68 * algorithm parameters, and optionally returns algorithm parameters if
69 * we generate them.
70 */
71 static int dhKeyGen(
72 CSSM_CSP_HANDLE cspHand,
73 CSSM_KEY_PTR pubKey,
74 CSSM_BOOL pubIsRef,
75 CSSM_KEYBLOB_FORMAT pubForm, // NONE, PKCS3, X509
76 CSSM_KEYBLOB_FORMAT expectPubForm, // PKCS3, X509
77 CSSM_KEY_PTR privKey,
78 CSSM_BOOL privIsRef,
79 CSSM_KEYBLOB_FORMAT privForm, // NONE, PKCS3, PKCS8
80 CSSM_KEYBLOB_FORMAT expectPrivForm, // PKCS3, PKCS8
81 const CSSM_DATA *inParams, // optional
82 CSSM_DATA_PTR outParams, // optional, we malloc
83 uint32 keySizeInBits,
84 CSSM_BOOL quiet)
85 {
86 CSSM_RETURN crtn;
87 CSSM_CC_HANDLE ccHand;
88 CSSM_DATA labelData = { strlen(USAGE_DEF), (uint8 *)USAGE_DEF };
89
90 if(inParams && outParams) {
91 printf("***dhKeyGen: inParams and outParams are mutually "
92 "exclusive.\n");
93 return -1;
94 }
95 memset(pubKey, 0, sizeof(CSSM_KEY));
96 memset(privKey, 0, sizeof(CSSM_KEY));
97
98 crtn = CSSM_CSP_CreateKeyGenContext(cspHand,
99 CSSM_ALGID_DH,
100 keySizeInBits,
101 NULL, // Seed
102 NULL, // Salt
103 NULL, // StartDate
104 NULL, // EndDate
105 inParams, // Params, may be NULL
106 &ccHand);
107 if(crtn) {
108 printError("CSSM_CSP_CreateKeyGenContext", crtn);
109 return testError(quiet);
110 }
111
112 if((inParams == NULL) && (outParams != NULL)) {
113 /* explicitly generate params and return them to caller */
114 outParams->Data = NULL;
115 outParams->Length = 0;
116 crtn = CSSM_GenerateAlgorithmParams(ccHand,
117 keySizeInBits, outParams);
118 if(crtn) {
119 printError("CSSM_GenerateAlgorithmParams", crtn);
120 return testError(quiet);
121 }
122 }
123
124 if((privForm != CSSM_KEYBLOB_RAW_FORMAT_NONE) && !privIsRef) {
125 crtn = AddContextAttribute(ccHand,
126 CSSM_ATTRIBUTE_PRIVATE_KEY_FORMAT,
127 sizeof(uint32),
128 CAT_Uint32,
129 NULL,
130 privForm);
131 if(crtn) {
132 printError("AddContextAttribute(CSSM_ATTRIBUTE_PRIVATE_KEY_"
133 "FORMAT)", crtn);
134 return crtn;
135 }
136 }
137 if((pubForm != CSSM_KEYBLOB_RAW_FORMAT_NONE) && !pubIsRef) {
138 crtn = AddContextAttribute(ccHand,
139 CSSM_ATTRIBUTE_PUBLIC_KEY_FORMAT,
140 sizeof(uint32),
141 CAT_Uint32,
142 NULL,
143 pubForm);
144 if(crtn) {
145 printError("AddContextAttribute(CSSM_ATTRIBUTE_PUBLIC_KEY_"
146 "FORMAT)", crtn);
147 return crtn;
148 }
149 }
150
151 uint32 privAttr;
152 uint32 pubAttr = CSSM_KEYATTR_EXTRACTABLE;
153 if(pubIsRef) {
154 pubAttr |= CSSM_KEYATTR_RETURN_REF;
155 }
156 else {
157 pubAttr |= CSSM_KEYATTR_RETURN_DATA;
158 }
159 if(privIsRef) {
160 privAttr = CSSM_KEYATTR_RETURN_REF;
161 }
162 else {
163 privAttr = CSSM_KEYATTR_RETURN_DATA | CSSM_KEYATTR_EXTRACTABLE;
164 }
165 crtn = CSSM_GenerateKeyPair(ccHand,
166 /*
167 * Public key specification. We specify raw key format
168 * here since we have to have access to the raw public key
169 * bits in order to perform D-H key exchange.
170 */
171 CSSM_KEYUSE_DERIVE, // only legal use of a Diffie-Hellman key
172 pubAttr,
173 &labelData,
174 pubKey,
175 /* private key specification */
176 CSSM_KEYUSE_DERIVE,
177 privAttr,
178 &labelData, // same labels
179 NULL, // CredAndAclEntry
180 privKey);
181 if(crtn) {
182 printError("CSSM_GenerateKeyPair", crtn);
183 return testError(quiet);
184 }
185 if(!privIsRef && (privKey->KeyHeader.Format != expectPrivForm)) {
186 printf("***Expected priv format %s got %s\n",
187 blobFormStr(expectPrivForm),
188 blobFormStr(privKey->KeyHeader.Format));
189 return testError(quiet);
190 }
191 if(!pubIsRef && (pubKey->KeyHeader.Format != expectPubForm)) {
192 printf("***Expected pub format %s got %s\n",
193 blobFormStr(expectPubForm),
194 blobFormStr(pubKey->KeyHeader.Format));
195 return testError(quiet);
196 }
197 CSSM_DeleteContext(ccHand);
198 return crtn;
199 }
200
201 /*
202 * Perform Diffie-Hellman key exchange.
203 * Given "our" private key (in the form of a CSSM_KEY) and "their" public
204 * key (in the form of a raw blob of bytes), cook up a symmetric key.
205 */
206 static int dhKeyExchange(
207 CSSM_CSP_HANDLE cspHand,
208 CSSM_KEY_PTR myPrivKey,
209 CSSM_KEY_PTR theirPubKey,
210 CSSM_KEY_PTR derivedKey, // RETURNED
211 uint32 deriveKeySizeInBits,
212 CSSM_ALGORITHMS derivedKeyAlg,
213 uint32 derivedKeyUsage,
214 uint32 derivedKeyAttr,
215 CSSM_BOOL quiet)
216 {
217 CSSM_RETURN crtn;
218 CSSM_ACCESS_CREDENTIALS creds;
219 CSSM_CC_HANDLE ccHand;
220 CSSM_DATA labelData =
221 { strlen(USAGE_DEF), (uint8 *)USAGE_DEF };
222
223 memset(&creds, 0, sizeof(CSSM_ACCESS_CREDENTIALS));
224 memset(derivedKey, 0, sizeof(CSSM_KEY));
225
226 crtn = CSSM_CSP_CreateDeriveKeyContext(cspHand,
227 CSSM_ALGID_DH,
228 derivedKeyAlg,
229 deriveKeySizeInBits,
230 &creds,
231 myPrivKey, // BaseKey
232 0, // IterationCount
233 0, // Salt
234 0, // Seed
235 &ccHand);
236 if(crtn) {
237 printError("CSSM_CSP_CreateDeriveKeyContext", crtn);
238 return testError(quiet);
239 }
240
241 /*
242 * Public key passed in as CSSM_DATA *Param - only if
243 * the pub key is in raw PKCS3 form
244 */
245 CSSM_DATA nullParam = {0, NULL};
246 CSSM_DATA_PTR paramPtr;
247 CSSM_KEYHEADER &hdr = theirPubKey->KeyHeader;
248 if((hdr.BlobType == CSSM_KEYBLOB_RAW) &&
249 (hdr.Format == CSSM_KEYBLOB_RAW_FORMAT_PKCS3)) {
250 /* simple case */
251 paramPtr = &theirPubKey->KeyData;
252 }
253 else {
254 /* add this pub key as a context attr */
255 crtn = AddContextAttribute(ccHand,
256 CSSM_ATTRIBUTE_PUBLIC_KEY,
257 sizeof(CSSM_KEY),
258 CAT_Ptr,
259 (void *)theirPubKey,
260 0);
261 if(crtn) {
262 printError("AddContextAttribute(CSSM_ATTRIBUTE_PUBLIC_KEY)",
263 crtn);
264 return crtn;
265 }
266 paramPtr = &nullParam;
267 }
268
269 crtn = CSSM_DeriveKey(ccHand,
270 paramPtr,
271 derivedKeyUsage,
272 derivedKeyAttr,
273 &labelData,
274 NULL, // cread/acl
275 derivedKey);
276 if(crtn) {
277 printError("CSSM_DeriveKey", crtn);
278 }
279 CSSM_DeleteContext(ccHand);
280 return crtn;
281 }
282
283 static CSSM_DATA someIv = {16, (uint8 *)"Some enchanted init vector" };
284
285 /*
286 * Encrypt ptext with myDeriveKey ==> ctext
287 * decrypt ctext with theirDeriveKey ==> rptext
288 * ensure ptext == rptext
289 */
290 static int doEncryptTest(
291 CSSM_CSP_HANDLE cspHand,
292 const CSSM_DATA *ptext,
293 CSSM_KEY_PTR myDeriveKey,
294 CSSM_KEY_PTR theirDeriveKey,
295 CSSM_ALGORITHMS encrAlg,
296 uint32 encrMode,
297 CSSM_PADDING encrPadding,
298 CSSM_BOOL quiet)
299 {
300 CSSM_DATA ctext = {0, NULL};
301 CSSM_DATA rptext = {0, NULL};
302 CSSM_RETURN crtn;
303
304 crtn = cspEncrypt(cspHand,
305 encrAlg,
306 encrMode,
307 encrPadding,
308 myDeriveKey,
309 NULL, // 2nd key
310 0, // effective key size
311 0, // rounds
312 &someIv,
313 ptext,
314 &ctext,
315 CSSM_FALSE); // mallocCtext
316 if(crtn) {
317 return testError(quiet);
318 }
319 crtn = cspDecrypt(cspHand,
320 encrAlg,
321 encrMode,
322 encrPadding,
323 theirDeriveKey,
324 NULL, // 2nd key
325 0, // effective key size
326 0, // rounds
327 &someIv,
328 &ctext,
329 &rptext,
330 CSSM_FALSE); // mallocCtext
331 if(crtn) {
332 return testError(quiet);
333 }
334 if(!appCompareCssmData(ptext, &rptext)) {
335 printf("***DATA MISCOMPARE***\n");
336 return testError(quiet);
337 }
338 appFree(ctext.Data, NULL);
339 appFree(rptext.Data, NULL);
340 return 0;
341 }
342
343 int doTest(
344 CSSM_CSP_HANDLE cspHand,
345 const CSSM_DATA *ptext,
346 CSSM_BOOL pubIsRef,
347 CSSM_KEYBLOB_FORMAT pubForm, // NONE, PKCS3, X509
348 CSSM_KEYBLOB_FORMAT expectPubForm, // PKCS3, X509
349 CSSM_BOOL privIsRef,
350 CSSM_KEYBLOB_FORMAT privForm, // NONE, PKCS3, PKCS8
351 CSSM_KEYBLOB_FORMAT expectPrivForm, // PKCS3, PKCS8
352 CSSM_BOOL sym1IsRef,
353 CSSM_BOOL sym2IsRef,
354 const CSSM_DATA *inParams, // optional
355 CSSM_DATA_PTR outParams, // optional
356 uint32 keySizeInBits,
357 CSSM_BOOL quiet)
358 {
359 CSSM_KEY myPriv;
360 CSSM_KEY myPub;
361 CSSM_KEY theirPriv;
362 CSSM_KEY theirPub;
363 int rtn = 0;
364
365 /* generate two key pairs */
366 if(dhKeyGen(cspHand,
367 &myPub,
368 pubIsRef,
369 pubForm,
370 expectPubForm,
371 &myPriv,
372 privIsRef,
373 privForm,
374 expectPrivForm,
375 inParams,
376 outParams,
377 keySizeInBits,
378 quiet)) {
379 return 1;
380 }
381
382 /* note this MUST match the params either specified or generated
383 * in previous call */
384 if((inParams == NULL) && (outParams == NULL)) {
385 printf("***BRRZAP! Must provide a way to match D-H parameters!\n");
386 exit(1);
387 }
388 const CSSM_DATA *theParams = inParams;
389 if(theParams == NULL) {
390 theParams = outParams;
391 }
392 if(dhKeyGen(cspHand,
393 &theirPub,
394 pubIsRef,
395 /* let's always use default for this pair */
396 CSSM_KEYBLOB_RAW_FORMAT_NONE,
397 CSSM_KEYBLOB_RAW_FORMAT_PKCS3, // we know this is the default
398 &theirPriv,
399 privIsRef,
400 /* let's always use default for this pair */
401 CSSM_KEYBLOB_RAW_FORMAT_NONE,
402 CSSM_KEYBLOB_RAW_FORMAT_PKCS3, // we know this is the default
403 theParams,
404 NULL, // outParams
405 keySizeInBits,
406 quiet)) {
407 return 1;
408 }
409
410 /* derive two keys, ensure they match */
411 CSSM_KEY myDerive;
412 CSSM_KEY theirDerive;
413 uint32 myDeriveAttr;
414 uint32 theirDeriveAttr;
415 if(sym1IsRef) {
416 myDeriveAttr = CSSM_KEYATTR_RETURN_REF;
417 }
418 else {
419 myDeriveAttr =
420 CSSM_KEYATTR_RETURN_DATA | CSSM_KEYATTR_EXTRACTABLE;
421 }
422 if(sym2IsRef) {
423 theirDeriveAttr = CSSM_KEYATTR_RETURN_REF;
424 }
425 else {
426 theirDeriveAttr =
427 CSSM_KEYATTR_RETURN_DATA | CSSM_KEYATTR_EXTRACTABLE;
428 }
429 if(dhKeyExchange(cspHand,
430 &myPriv,
431 &theirPub,
432 &myDerive,
433 DERIVE_KEY_SIZE,
434 DERIVE_KEY_ALG,
435 CSSM_KEYUSE_ENCRYPT,
436 myDeriveAttr,
437 quiet)) {
438 return testError(quiet);
439 }
440 if(dhKeyExchange(cspHand,
441 &theirPriv,
442 &myPub,
443 &theirDerive,
444 DERIVE_KEY_SIZE,
445 DERIVE_KEY_ALG,
446 CSSM_KEYUSE_DECRYPT,
447 theirDeriveAttr,
448 quiet)) {
449 return testError(quiet);
450 }
451
452 if(doEncryptTest(cspHand,
453 ptext,
454 &myDerive,
455 &theirDerive,
456 ENCR_ALG,
457 ENCR_MODE,
458 ENCR_PADDING,
459 quiet)) {
460 return 1;
461 }
462
463 cspFreeKey(cspHand, &myPub);
464 cspFreeKey(cspHand, &myPriv);
465 cspFreeKey(cspHand, &theirPub);
466 cspFreeKey(cspHand, &theirPriv);
467 cspFreeKey(cspHand, &myDerive);
468 cspFreeKey(cspHand, &theirDerive);
469 return rtn;
470 }
471
472 int main(int argc, char **argv)
473 {
474 int arg;
475 char *argp;
476 CSSM_CSP_HANDLE cspHand;
477 unsigned loop;
478 int i;
479 CSSM_DATA inParams = {0, NULL};
480 CSSM_DATA outParams = {0, NULL};
481 CSSM_DATA_PTR inParamPtr = NULL;
482 CSSM_DATA_PTR outParamPtr = NULL;
483 CSSM_DATA ptext;
484 CSSM_BOOL pubIsRef;
485 CSSM_BOOL privIsRef;
486 CSSM_BOOL sym1IsRef;
487 CSSM_BOOL sym2IsRef;
488 CSSM_KEYBLOB_FORMAT pubForm; // NONE, PKCS3, X509
489 CSSM_KEYBLOB_FORMAT expectPubForm; // PKCS3, X509
490 CSSM_KEYBLOB_FORMAT privForm; // NONE, PKCS3, PKCS8
491 CSSM_KEYBLOB_FORMAT expectPrivForm; // PKCS3, PKCS8
492
493 /* user-spec'd parameters */
494 unsigned keySize = KEY_SIZE_DEF;
495 unsigned pauseInterval = 0;
496 unsigned loops = LOOPS_DEF;
497 CSSM_BOOL quiet = CSSM_FALSE;
498 CSSM_BOOL verbose = CSSM_FALSE;
499 CSSM_BOOL bareCsp = CSSM_TRUE;
500 char *inFileName = NULL;
501 char *outFileName = NULL;
502
503 for(arg=1; arg<argc; arg++) {
504 argp = argv[arg];
505 switch(argp[0]) {
506 case 'k':
507 keySize = atoi(&argp[2]);
508 break;
509 case 'l':
510 loops = atoi(&argp[2]);
511 break;
512 case 'p':
513 pauseInterval = atoi(&argp[2]);
514 break;
515 case 'i':
516 inFileName = &argp[2];
517 break;
518 case 'o':
519 outFileName = &argp[2];
520 break;
521 case 'D':
522 bareCsp = CSSM_FALSE;
523 break;
524 case 'q':
525 quiet = CSSM_TRUE;
526 break;
527 case 'v':
528 verbose = CSSM_TRUE;
529 break;
530 default:
531 usage(argv);
532 }
533 }
534
535 cspHand = cspDlDbStartup(bareCsp, NULL);
536 if(cspHand == 0) {
537 exit(1);
538 }
539
540 if(!bareCsp &&
541 !CSPDL_DSA_GEN_PARAMS &&
542 (inFileName == NULL)) {
543 /*
544 * For now, CSPDL can not do gen parameters. This only
545 * works if we're supplied params externally (which most
546 * likely were generated from the bare CSP).
547 */
548 printf("*** %s can't run with CSPDL unless you supply DH "
549 "parameters.\n", argv[0]);
550 exit(1);
551 }
552
553 /* optionally fetch algorithm parameters from a file */
554 if(inFileName) {
555 unsigned len;
556 int r = readFile(inFileName, &inParams.Data, &len);
557 if(r) {
558 printf("***Can't read parameters from %s; aborting.\n",
559 inFileName);
560 exit(1);
561 }
562 inParams.Length = len;
563 /* constant from now on */
564 inParamPtr = &inParams;
565 }
566 else {
567 /* first time thru, no user-supplied parameters; generate them and
568 * save in outParams */
569 outParamPtr = &outParams;
570 }
571
572 ptext.Data = (uint8 *)appMalloc(MAX_PTEXT_SIZE, NULL);
573 /* ptext length set in test loop */
574
575 printf("Starting %s; args: ", argv[0]);
576 for(i=1; i<argc; i++) {
577 printf("%s ", argv[i]);
578 }
579 printf("\n");
580 for(loop=1; ; loop++) {
581 if(!quiet) {
582 printf("...Loop %d\n", loop);
583 }
584 simpleGenData(&ptext, 10, MAX_PTEXT_SIZE);
585
586 /* mix up raw and ref keys, except for CSPDL which
587 * requires all ref keys */
588 if(bareCsp) {
589 pubIsRef = (loop & 1) ? CSSM_TRUE : CSSM_FALSE;
590 privIsRef = (loop & 2) ? CSSM_TRUE : CSSM_FALSE;
591 sym1IsRef = (loop & 4) ? CSSM_TRUE : CSSM_FALSE;
592 sym2IsRef = (loop & 8) ? CSSM_TRUE : CSSM_FALSE;
593 }
594 else {
595 pubIsRef = privIsRef = sym1IsRef = sym2IsRef = CSSM_TRUE;
596 }
597 if(!privIsRef) {
598 int die = genRand(1,3);
599 switch(die) {
600 case 1:
601 privForm = CSSM_KEYBLOB_RAW_FORMAT_NONE;
602 expectPrivForm = CSSM_KEYBLOB_RAW_FORMAT_PKCS3;
603 break;
604 case 2:
605 privForm = expectPrivForm =
606 CSSM_KEYBLOB_RAW_FORMAT_PKCS3;
607 break;
608 case 3:
609 privForm = expectPrivForm =
610 CSSM_KEYBLOB_RAW_FORMAT_PKCS8;
611 break;
612 }
613 if(verbose) {
614 printf("...privIsRef false; form %s, expectForm %s\n",
615 blobFormStr(privForm), blobFormStr(expectPrivForm));
616 }
617 }
618 else {
619 privForm = expectPrivForm = CSSM_KEYBLOB_RAW_FORMAT_NONE;
620 if(verbose) {
621 printf("...privIsRef true\n");
622 }
623 }
624 if(!pubIsRef) {
625 int die = genRand(1,3);
626 switch(die) {
627 case 1:
628 pubForm = CSSM_KEYBLOB_RAW_FORMAT_NONE;
629 expectPubForm = CSSM_KEYBLOB_RAW_FORMAT_PKCS3;
630 break;
631 case 2:
632 pubForm = expectPubForm =
633 CSSM_KEYBLOB_RAW_FORMAT_PKCS3;
634 break;
635 case 3:
636 pubForm = expectPubForm =
637 CSSM_KEYBLOB_RAW_FORMAT_X509;
638 break;
639 }
640 if(verbose) {
641 printf("...pubIsRef false; form %s, expectForm %s\n",
642 blobFormStr(pubForm), blobFormStr(expectPubForm));
643 }
644 }
645 else {
646 pubForm = expectPubForm = CSSM_KEYBLOB_RAW_FORMAT_NONE;
647 if(verbose) {
648 printf("...pubIsRef true\n");
649 }
650 }
651 i = doTest(cspHand,
652 &ptext,
653 pubIsRef,
654 pubForm,
655 expectPubForm,
656 privIsRef,
657 privForm,
658 expectPrivForm,
659 sym1IsRef,
660 sym2IsRef,
661 inParamPtr,
662 outParamPtr,
663 keySize,
664 quiet);
665 if(i) {
666 break;
667 }
668 if(loop == 1) {
669 /* first time thru */
670 if(outFileName) {
671 /* save parameters for another run */
672 i = writeFile(outFileName, outParams.Data, outParams.Length);
673 if(i) {
674 printf("***Error writing params to %s; continuing.\n",
675 outFileName);
676 }
677 else {
678 if(!quiet) {
679 printf("...wrote %lu bytes to %s\n",
680 outParams.Length, outFileName);
681 }
682 }
683 }
684 if(!inFileName) {
685 /* from now on, use the parameters we just generated */
686 inParamPtr = &outParams;
687 }
688 /* and in any case don't fetch any more params */
689 outParamPtr = NULL;
690 }
691 if(loops && (loop == loops)) {
692 break;
693 }
694 if(pauseInterval && ((loop % pauseInterval) == 0)) {
695 char inch;
696
697 fpurge(stdin);
698 printf("Hit CR to proceed, q to quit: ");
699 inch = getchar();
700 if(inch == 'q') {
701 break;
702 }
703 }
704 }
705 appFree(ptext.Data, NULL);
706 CSSM_ModuleDetach(cspHand);
707 if(!quiet) {
708 printf("OK\n");
709 }
710 return 0;
711 }