]> git.saurik.com Git - apple/security.git/blobdiff - SecurityTests/cspxutils/asymCompat/asymCompat.c
Security-57031.1.35.tar.gz
[apple/security.git] / SecurityTests / cspxutils / asymCompat / asymCompat.c
diff --git a/SecurityTests/cspxutils/asymCompat/asymCompat.c b/SecurityTests/cspxutils/asymCompat/asymCompat.c
new file mode 100644 (file)
index 0000000..14dbad8
--- /dev/null
@@ -0,0 +1,826 @@
+/* 
+ * asymCompat.c - test compatibilty of two different implementations of a
+ * RSA and DSA - one in the standard AppleCSP, one in BSAFE.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <time.h>
+#include <Security/cssm.h>
+#include <Security/cssmapple.h>
+#include "cspwrap.h"
+#include "common.h"
+#include "bsafeUtils.h"
+#include <string.h>
+#include "cspdlTesting.h"
+
+/*
+ * Defaults.
+ */
+#define OLOOPS_DEF             10              /* outer loops, one set of keys per loop */
+#define SIG_LOOPS_DEF  100             /* sig loops */
+#define ENC_LOOPS_DEF  100             /* encrypt/decrypt loops */
+#define MAX_TEXT_SIZE  1025
+
+#define LOOP_NOTIFY            20
+
+static void usage(char **argv)
+{
+       printf("usage: %s [options]\n", argv[0]);
+       printf("   Options:\n");
+       printf("   a=algorithm (r=RSA; d=DSA; default=both)\n");
+       printf("   l=outerloops (default=%d; 0=forever)\n", OLOOPS_DEF);
+       printf("   s=sigLoops (default=%d)\n", SIG_LOOPS_DEF);
+       printf("   e=encryptLoops (default=%d)\n", ENC_LOOPS_DEF);
+       printf("   k=keySizeInBits; default is random\n");
+       printf("   S (sign/verify only)\n");
+       printf("   E (encrypt/decrypt only)\n");
+       printf("   r (generate ref keys)\n");
+       printf("   R (generate public ref keys)\n");
+       printf("   p=pauseInterval (default=0, no pause)\n");
+       printf("   D (CSP/DL; default = bare CSP)\n");
+       printf("   v(erbose)\n");
+       printf("   q(uiet)\n");
+       printf("   h(elp)\n");
+       exit(1);
+}
+
+static const char *algToStr(CSSM_ALGORITHMS sigAlg)
+{
+       switch(sigAlg) {
+               case CSSM_ALGID_RSA:                    return "RSA";
+               case CSSM_ALGID_DSA:                    return "DSA";
+               case CSSM_ALGID_SHA1WithRSA:    return "SHA1WithRSA";
+               case CSSM_ALGID_MD5WithRSA:             return "MD5WithRSA";
+               case CSSM_ALGID_SHA1WithDSA:    return "SHA1WithDSA";
+               default:
+                       printf("***Unknown sigAlg\n");
+                       exit(1);
+       }
+       /* NOT REACHED */
+       return "";
+}
+
+/*
+ * CDSA private key decrypt with blinding option.
+ */
+static CSSM_RETURN _cspDecrypt(CSSM_CSP_HANDLE cspHand,
+               uint32 algorithm,                                       // CSSM_ALGID_FEED, etc.
+               uint32 mode,                                            // CSSM_ALGMODE_CBC, etc. - only for symmetric algs
+               CSSM_PADDING padding,                           // CSSM_PADDING_PKCS1, etc. 
+               CSSM_BOOL blinding,
+               const CSSM_KEY *key,                            // public or session key
+               const CSSM_DATA *ctext,
+               CSSM_DATA_PTR ptext)                            // RETURNED
+{
+       CSSM_CC_HANDLE  cryptHand;
+       CSSM_RETURN             crtn;
+       CSSM_RETURN             ocrtn = CSSM_OK;
+       CSSM_SIZE               bytesDecrypted;
+       CSSM_DATA               remData = {0, NULL};
+
+       cryptHand = genCryptHandle(cspHand, 
+               algorithm, 
+               mode, 
+               padding,
+               key, 
+               NULL,           // pubKey, 
+               NULL,           // iv,
+               0,                      // effectiveKeySizeInBits,
+               0);                     // rounds
+       if(cryptHand == 0) {
+               return CSSMERR_CSP_INTERNAL_ERROR;
+       }
+       if(blinding) {
+               CSSM_CONTEXT_ATTRIBUTE  newAttr;        
+               newAttr.AttributeType     = CSSM_ATTRIBUTE_RSA_BLINDING;
+               newAttr.AttributeLength   = sizeof(uint32);
+               newAttr.Attribute.Uint32  = 1;
+               crtn = CSSM_UpdateContextAttributes(cryptHand, 1, &newAttr);
+               if(crtn) {
+                       printError("CSSM_UpdateContextAttributes", crtn);
+                       return crtn;
+               }
+       }
+
+       crtn = CSSM_DecryptData(cryptHand,
+               ctext,
+               1,
+               ptext,
+               1,
+               &bytesDecrypted,
+               &remData);
+       if(crtn == CSSM_OK) {
+               // NOTE: We return the proper length in ptext....
+               ptext->Length = bytesDecrypted;
+               
+               // FIXME - sometimes get mallocd RemData here, but never any valid data
+               // there...side effect of CSPFullPluginSession's buffer handling logic;
+               // but will we ever actually see valid data in RemData? So far we never
+               // have....
+               if(remData.Data != NULL) {
+                       appFree(remData.Data, NULL);
+               }
+       }
+       else {
+               printError("CSSM_DecryptData", crtn);
+               ocrtn = crtn;
+       }
+       crtn = CSSM_DeleteContext(cryptHand);
+       if(crtn) {
+               printError("CSSM_DeleteContext", crtn);
+               ocrtn = crtn;
+       }
+       return ocrtn;
+}
+
+/* sign with RSA blinging option */
+static CSSM_RETURN _cspSign(CSSM_CSP_HANDLE cspHand,
+               uint32 algorithm,                                       // CSSM_ALGID_FEE_MD5, etc.
+               CSSM_KEY_PTR key,                                       // private key
+               const CSSM_DATA *text,
+               CSSM_BOOL rsaBlinding,
+               CSSM_DATA_PTR sig)                                      // RETURNED
+{
+       CSSM_CC_HANDLE  sigHand;
+       CSSM_RETURN             crtn;
+       CSSM_RETURN             ocrtn = CSSM_OK;
+       const CSSM_DATA *ptext;
+       CSSM_DATA               digest = {0, NULL};
+       CSSM_ALGORITHMS digestAlg = CSSM_ALGID_NONE;
+
+       /* handle special cases for raw sign */
+       switch(algorithm) {
+               case CSSM_ALGID_SHA1:
+                       digestAlg = CSSM_ALGID_SHA1;
+                       algorithm = CSSM_ALGID_RSA;
+                       break;
+               case CSSM_ALGID_MD5:
+                       digestAlg = CSSM_ALGID_MD5;
+                       algorithm = CSSM_ALGID_RSA;
+                       break;
+               case CSSM_ALGID_DSA:
+                       digestAlg = CSSM_ALGID_SHA1;
+                       algorithm = CSSM_ALGID_DSA;
+                       break;
+               default:
+                       break;
+       }
+       if(digestAlg != CSSM_ALGID_NONE) {
+               crtn = cspDigest(cspHand,
+                       digestAlg,
+                       CSSM_FALSE,                     // mallocDigest
+                       text,
+                       &digest);
+               if(crtn) {
+                       return crtn;
+               }       
+               /* sign digest with raw RSA/DSA */
+               ptext = &digest;
+       }
+       else {
+               ptext = text;
+       }
+       crtn = CSSM_CSP_CreateSignatureContext(cspHand,
+               algorithm,
+               NULL,                           // passPhrase
+               key,
+               &sigHand);
+       if(crtn) {
+               printError("CSSM_CSP_CreateSignatureContext (1)", crtn);
+               return crtn;
+       }
+       if(rsaBlinding) {
+               CSSM_CONTEXT_ATTRIBUTE  newAttr;        
+               newAttr.AttributeType     = CSSM_ATTRIBUTE_RSA_BLINDING;
+               newAttr.AttributeLength   = sizeof(uint32);
+               newAttr.Attribute.Uint32  = 1;
+               crtn = CSSM_UpdateContextAttributes(sigHand, 1, &newAttr);
+               if(crtn) {
+                       printError("CSSM_UpdateContextAttributes", crtn);
+                       return crtn;
+               }
+       }
+       crtn = CSSM_SignData(sigHand,
+               ptext,
+               1,
+               digestAlg,
+               sig);
+       if(crtn) {
+               printError("CSSM_SignData", crtn);
+               ocrtn = crtn;
+       }
+       crtn = CSSM_DeleteContext(sigHand);
+       if(crtn) {
+               printError("CSSM_DeleteContext", crtn);
+               ocrtn = crtn;
+       }
+       if(digest.Data != NULL) {
+               CSSM_FREE(digest.Data);
+       }
+       return ocrtn;
+}
+
+
+/*
+ * Sign/verify test.
+ *
+ * for specified numLoops {
+ *             generate random text;
+ *             sign with BSAFE priv key, verify with CDSA pub key;
+ *             sign with CDSA priv key, verify with BSAFE pub key;
+ * }
+ */
+static int sigTest(
+       CSSM_CSP_HANDLE         cspHand,
+       unsigned                        numLoops,
+       
+       /* one matched key pair */
+       BU_KEY                          bsafePrivKey,
+       CSSM_KEY_PTR            cdsaPubKey,
+       
+       /* another matched key pair */
+       CSSM_KEY_PTR            cdsaPrivKey,
+       BU_KEY                          bsafePubKey,
+       
+       CSSM_DATA_PTR           ptext,
+       unsigned                        maxPtextSize,   
+       CSSM_ALGORITHMS         sigAlg,
+       CSSM_BOOL                       rsaBlinding,
+       CSSM_BOOL                       quiet,
+       CSSM_BOOL                       verbose)
+{
+       CSSM_RETURN crtn;
+       CSSM_DATA       sig = {0, NULL};
+       unsigned        loop;
+       uint32          keySizeInBits = cdsaPrivKey->KeyHeader.LogicalKeySizeInBits;
+       
+       if(!quiet) {
+               printf("   ...sig alg %s  keySize %u\n", algToStr(sigAlg), (unsigned)keySizeInBits);
+       }
+       for(loop=0; loop<numLoops; loop++) {
+               simpleGenData(ptext, 1, maxPtextSize);
+               if(!quiet) {
+                       if(verbose || ((loop % LOOP_NOTIFY) == 0)) {
+                               printf("      ...loop %d keySize %u textSize %lu\n", 
+                                       loop, (unsigned)cdsaPrivKey->KeyHeader.LogicalKeySizeInBits, 
+                                       (unsigned long)ptext->Length);
+                       }
+               }
+               
+               /* sign with BSAFE, verify with CDSA */
+               crtn = buSign(bsafePrivKey,
+                       sigAlg,
+                       ptext,
+                       keySizeInBits,
+                       &sig);
+               if(crtn) {
+                       return testError(quiet);
+               }
+               crtn = cspSigVerify(cspHand,
+                       sigAlg,
+                       cdsaPubKey,
+                       ptext,
+                       &sig,
+                       CSSM_OK);
+               if(crtn) {
+                       printf("***ERROR: Sign with BSAFE, vfy with CDSA, alg %s\n",
+                               algToStr(sigAlg));
+                       if(testError(quiet)) {
+                               return 1;
+                       }
+               }
+               appFreeCssmData(&sig, CSSM_FALSE);
+       
+               /* sign with CDSA, verify with BSAFE */
+               crtn = _cspSign(cspHand,
+                       sigAlg,
+                       cdsaPrivKey,
+                       ptext,
+                       rsaBlinding,
+                       &sig);
+               if(crtn) {
+                       return testError(quiet);
+               }
+               crtn = buVerify(bsafePubKey,
+                       sigAlg,
+                       ptext,
+                       &sig);
+               if(crtn) {
+                       printf("***ERROR: Sign with CDSA, vfy with BSAFE, alg %s\n",
+                               algToStr(sigAlg));
+                       if(testError(quiet)) {
+                               return 1;
+                       }
+               }
+               appFreeCssmData(&sig, CSSM_FALSE);
+       }
+       return CSSM_OK;
+}
+
+/*
+ * RSA Encrypt/decrypt test.
+ *
+ * for specified numLoops {
+ *             generate random text;
+ *             encrypt with BSAFE pub key, decrypt with CDSA priv key, verify;
+ *             encrypt with CDSA pub key, decrypt with BSAFE priv key, verify;
+ * }
+ */
+static int encryptTest(
+       CSSM_CSP_HANDLE         cspHand,
+       unsigned                        numLoops,
+       
+       /* one matched key pair */
+       BU_KEY                          bsafePrivKey,
+       CSSM_KEY_PTR            cdsaPubKey,
+       
+       /* another matched key pair */
+       CSSM_KEY_PTR            cdsaPrivKey,
+       BU_KEY                          bsafePubKey,
+       
+       CSSM_DATA_PTR           ptext,
+       unsigned                        maxPtextSize,   
+       CSSM_BOOL                       rsaBlinding,
+       CSSM_BOOL                       quiet,
+       CSSM_BOOL                       verbose)
+{
+       CSSM_RETURN crtn;
+       CSSM_DATA       ctext = {0, NULL};
+       CSSM_DATA       rptext = {0, NULL};
+       unsigned        loop;
+       unsigned        actKeySizeBytes;
+       
+       actKeySizeBytes = cdsaPrivKey->KeyHeader.LogicalKeySizeInBits / 8;
+       if(actKeySizeBytes < 12) {
+               printf("***Key with %u key bits is too small for RSA encrypt\n",
+                       (unsigned)cdsaPrivKey->KeyHeader.LogicalKeySizeInBits);
+               return 1;
+       }
+       if(maxPtextSize > (actKeySizeBytes - 11)) {
+               maxPtextSize = actKeySizeBytes - 11;
+       }
+       if(!quiet) {
+               printf("   ...encr alg RSA\n");
+       }
+       for(loop=0; loop<numLoops; loop++) {
+               simpleGenData(ptext, 1, maxPtextSize);
+               if(!quiet) {
+                       if(verbose || ((loop % LOOP_NOTIFY) == 0)) {
+                               printf("      ...loop %d keySize %u textSize %lu\n", 
+                                       loop, (unsigned)cdsaPrivKey->KeyHeader.LogicalKeySizeInBits, 
+                                       (unsigned long)ptext->Length);
+                       }
+               }
+               
+               /* encrypt with BSAFE, decrypt with CDSA */
+               crtn = buEncryptDecrypt(bsafePubKey,
+                       CSSM_TRUE,              // encrypt
+                       CSSM_ALGID_RSA,
+                       CSSM_ALGMODE_NONE,
+                       NULL,                   // iv
+                       cdsaPrivKey->KeyHeader.LogicalKeySizeInBits,    
+                       0,                              // rounds
+                       ptext,
+                       &ctext);
+               if(crtn) {
+                       return testError(quiet);
+               }
+               crtn = _cspDecrypt(cspHand,
+                       CSSM_ALGID_RSA,
+                       CSSM_ALGMODE_NONE,
+                       CSSM_PADDING_PKCS1,
+                       rsaBlinding,
+                       cdsaPrivKey,
+                       &ctext,
+                       &rptext);
+               if(crtn) {
+                       printf("***ERROR: encrypt with BSAFE, decrypt with CDSA\n");
+                       return testError(quiet);
+               }
+               if(!appCompareCssmData(ptext, &rptext)) {
+                       printf("***DATA MISCOMPARE: encrypt with BSAFE, decrypt with CDSA\n");
+                       return testError(quiet);
+               }
+               appFreeCssmData(&ctext, CSSM_FALSE);
+               appFreeCssmData(&rptext, CSSM_FALSE);
+       
+               /* encrypt with CDSA, decrypt with BSAFE */
+               crtn = cspEncrypt(cspHand,
+                       CSSM_ALGID_RSA,
+                       CSSM_ALGMODE_NONE,
+                       CSSM_PADDING_PKCS1,
+                       cdsaPubKey,
+                       NULL,                                   // (FEE) pub key
+                       0,                                              // effectiveKeyBits
+                       0,                                              // rounds
+                       NULL,                                   // IV
+                       ptext,
+                       &ctext,
+                       CSSM_FALSE);                    // mallocCtext
+               if(crtn) {
+                       return testError(quiet);
+               }
+               crtn = buEncryptDecrypt(bsafePrivKey,
+                       CSSM_FALSE,             // encrypt
+                       CSSM_ALGID_RSA,
+                       CSSM_ALGMODE_NONE,
+                       NULL,                   // iv
+                       cdsaPrivKey->KeyHeader.LogicalKeySizeInBits,    
+                       0,                              // rounds
+                       &ctext,
+                       &rptext);
+               if(crtn) {
+                       printf("***ERROR: encrypt with CDSA, decrypt with BSAFE\n");
+                       return testError(quiet);
+               }
+               if(!appCompareCssmData(ptext, &rptext)) {
+                       printf("***DATA MISCOMPARE: encrypt with CDSA, decrypt with BSAFE\n");
+                       return testError(quiet);
+               }
+               appFreeCssmData(&ctext, CSSM_FALSE);
+               appFreeCssmData(&rptext, CSSM_FALSE);
+       }
+       return CSSM_OK;
+}
+
+static int doTest(
+       CSSM_CSP_HANDLE         cspHand,
+       CSSM_ALGORITHMS         keyAlg,                         // RSA/DSA
+       CSSM_ALGORITHMS         sigAlg,
+       unsigned                        sigLoops,                       // may be zero
+       unsigned                        encrLoops,                      // ditto; it will be zero for DSA
+       CSSM_BOOL                       rsaBlinding,
+       CSSM_DATA_PTR           ptext,
+       unsigned                        maxPtextSize,
+       uint32                          keySizeInBits,          // 0 --> random per alg
+       CSSM_BOOL                       pubRefKeys,
+       CSSM_BOOL                       privRefKeys,
+       CSSM_BOOL                       bareCsp,                        // for other workarounds
+       CSSM_BOOL                       quiet,
+       CSSM_BOOL                       verbose)
+{
+       CSSM_KEY                        cdsaGenPubKey;
+       CSSM_KEY                        cdsaGenPrivKey;         // only used to create bsafeDerivePrivKey
+       CSSM_KEY                        cdsaTempKey;            // raw key if privRefKeys true
+       CSSM_KEY                        cdsaDerivePrivKey;      // same as bsafeGenPrivKey
+       BU_KEY                          bsafeGenPubKey;
+       BU_KEY                          bsafeGenPrivKey;        // only used to create cdsaDerivePrivKey
+       BU_KEY                          bsafeDerivePrivKey;     // same as cdsaGenPrivKey
+       unsigned                        actKeySizeBits;
+       CSSM_RETURN                     crtn;
+       int                                     rtn;
+       
+       if(!keySizeInBits) {
+               /* random key size */
+               actKeySizeBits = randKeySizeBits(keyAlg, OT_Encrypt);
+       }
+       else {
+               /* caller/user specified */
+               actKeySizeBits = keySizeInBits;
+       }
+       if(verbose) {
+               printf("   ...generating %s key pair, keySize %d bits...\n",
+                       algToStr(keyAlg), actKeySizeBits);
+       }
+       
+       /* 
+     * Generate two keypairs 
+        */
+       if(keyAlg == CSSM_ALGID_DSA) {
+               CSSM_BOOL doGenParams;
+               
+               if(bareCsp || CSPDL_DSA_GEN_PARAMS) {
+                       doGenParams = CSSM_TRUE;
+               }
+               else {
+                       /* CSPDL - no gen params */
+                       doGenParams = CSSM_FALSE;
+               }
+               crtn = cspGenDSAKeyPair(cspHand,
+                       "foo",
+                       3,
+                       actKeySizeBits,
+                       &cdsaGenPubKey,
+                       pubRefKeys,
+                       CSSM_KEYUSE_ANY,
+                       CSSM_KEYBLOB_RAW_FORMAT_NONE,
+                       &cdsaGenPrivKey,
+                       privRefKeys,
+                       CSSM_KEYUSE_SIGN,
+                       CSSM_KEYBLOB_RAW_FORMAT_NONE,
+                       doGenParams,            // genParams
+                       NULL);                          // params
+       }
+       else {
+               crtn = cspGenKeyPair(cspHand,
+                       keyAlg,
+                       "foo",
+                       3,
+                       actKeySizeBits,
+                       &cdsaGenPubKey,
+                       pubRefKeys,
+                       CSSM_KEYUSE_ANY,
+                       CSSM_KEYBLOB_RAW_FORMAT_NONE,
+                       &cdsaGenPrivKey,
+                       privRefKeys,
+                       CSSM_KEYUSE_ANY,
+                       CSSM_KEYBLOB_RAW_FORMAT_NONE,
+                       CSSM_FALSE);                                    // genSeed not used 
+       }
+       if(crtn) {
+               return testError(quiet);
+       }
+       crtn = buGenKeyPair(actKeySizeBits,
+               keyAlg,
+               &bsafeGenPubKey,
+               &bsafeGenPrivKey);
+       if(crtn) {
+               return testError(quiet);
+       }
+       
+       /* 
+        * Convert private keys to other library. 
+        * NOTE: the reason we're only converting private keys is solely due to the 
+        * fact that BSAFE does not handle PKCS1 formatted public key blobs. Very odd. 
+        * But it's too much of a pain to re-implement that wheel here, and SSL and 
+        * cert handling in general verify the CSP's PKCS1-style public key handling. 
+        */
+       if(privRefKeys) {
+               /* first generate a temporary raw CDSA key */
+               crtn = buBsafePrivKeyToCdsa(keyAlg, 
+                       actKeySizeBits,
+                       bsafeGenPrivKey, 
+                       &cdsaTempKey);
+               if(crtn) {
+                       return testError(quiet);
+               }
+               
+               /* convert it to the ref key we'll actually use */
+               crtn = cspRawKeyToRef(cspHand, &cdsaTempKey, &cdsaDerivePrivKey);
+               cspFreeKey(cspHand, &cdsaTempKey);
+       }
+       else {
+               crtn = buBsafePrivKeyToCdsa(keyAlg, 
+                       actKeySizeBits,
+                       bsafeGenPrivKey, 
+                       &cdsaDerivePrivKey);
+       }
+       if(crtn) {
+               return testError(quiet);
+       }
+       if(privRefKeys) {
+               /* we have a CDSA priv ref key; convert it to raw format */
+               crtn = cspRefKeyToRaw(cspHand, &cdsaGenPrivKey, &cdsaTempKey);
+               if(crtn) {
+                       return testError(quiet);
+               }
+               /* now convert it to BSAFE */
+               crtn = buCdsaPrivKeyToBsafe(&cdsaTempKey, &bsafeDerivePrivKey);
+               cspFreeKey(cspHand, &cdsaTempKey);
+       }
+       else {
+               crtn = buCdsaPrivKeyToBsafe(&cdsaGenPrivKey, &bsafeDerivePrivKey);
+       }
+       if(crtn) {
+               return testError(quiet);
+       }
+       
+       if(sigLoops) {
+               rtn = sigTest(cspHand,
+                       sigLoops,
+                       bsafeDerivePrivKey,
+                       &cdsaGenPubKey,
+                       &cdsaDerivePrivKey,
+                       bsafeGenPubKey,
+                       ptext,
+                       maxPtextSize,
+                       sigAlg,
+                       rsaBlinding,
+                       quiet,
+                       verbose);
+               if(rtn) {
+                       return rtn;
+               }
+       }
+       
+       if(encrLoops) {
+               rtn = encryptTest(cspHand,
+                       encrLoops,
+                       bsafeDerivePrivKey,
+                       &cdsaGenPubKey,
+                       &cdsaDerivePrivKey,
+                       bsafeGenPubKey,
+                       ptext,
+                       maxPtextSize,
+                       rsaBlinding,
+                       quiet,
+                       verbose);
+               if(rtn) {
+                       return rtn;
+               }
+       }
+
+       /* free all six keys */
+       buFreeKey(bsafeGenPubKey);
+       buFreeKey(bsafeGenPrivKey);
+       buFreeKey(bsafeDerivePrivKey);
+       cspFreeKey(cspHand, &cdsaGenPubKey);
+       cspFreeKey(cspHand, &cdsaGenPrivKey);
+       cspFreeKey(cspHand, &cdsaDerivePrivKey);
+       return 0;
+}
+
+int main(int argc, char **argv)
+{
+       int                                     arg;
+       char                            *argp;
+       unsigned                        loop;
+       CSSM_DATA                       ptext;
+       CSSM_CSP_HANDLE         cspHand;
+       int                                     i;
+       int                                     rtn = 0;
+       
+       /*
+        * User-spec'd params
+        */
+       uint32                          keySizeInBits = 0;
+       unsigned                        oloops = OLOOPS_DEF;
+       unsigned                        sigLoops = SIG_LOOPS_DEF;
+       unsigned                        encrLoops = ENC_LOOPS_DEF;
+       CSSM_BOOL                       verbose = CSSM_FALSE;
+       CSSM_BOOL                       quiet = CSSM_FALSE;
+       unsigned                        pauseInterval = 0;
+       CSSM_BOOL                       bareCsp = CSSM_TRUE;
+       CSSM_BOOL                       doDSA = CSSM_TRUE;
+       CSSM_BOOL                       doRSA = CSSM_TRUE;
+       CSSM_BOOL                       pubRefKeys = CSSM_FALSE;
+       CSSM_BOOL                       privRefKeys = CSSM_FALSE;
+       
+       for(arg=1; arg<argc; arg++) {
+               argp = argv[arg];
+               switch(argp[0]) {
+                       case 'a':
+                               if(argp[1] != '=') {
+                                       usage(argv);
+                               }
+                               switch(argp[2]) {
+                                       case 'r':
+                                               doDSA = CSSM_FALSE;
+                                               break;
+                                       case 'd':
+                                               doRSA = CSSM_FALSE;
+                                               break;
+                                       default:
+                                               usage(argv);
+                               }
+                               break;
+                   case 'l':
+                               oloops = atoi(&argp[2]);
+                               break;
+                   case 's':
+                               sigLoops = atoi(&argp[2]);
+                               break;
+                   case 'e':
+                               encrLoops = atoi(&argp[2]);
+                               break;
+                   case 'k':
+                       keySizeInBits = atoi(&argp[2]);
+                               break;
+                   case 'v':
+                       verbose = CSSM_TRUE;
+                               break;
+                       case 'r':
+                               privRefKeys = CSSM_TRUE;
+                               break;
+                       case 'R':
+                               pubRefKeys = CSSM_TRUE;
+                               break;
+                       case 'D':
+                               bareCsp = CSSM_FALSE;
+                               #if     CSPDL_ALL_KEYS_ARE_REF
+                               privRefKeys = CSSM_TRUE;
+                               pubRefKeys = CSSM_TRUE;
+                               #endif
+                               break;
+                   case 'E':
+                       sigLoops = 0;
+                               break;
+                       case 'S':
+                               encrLoops = 0;
+                               break;
+                   case 'q':
+                       quiet = CSSM_TRUE;
+                               break;
+                   case 'p':
+                       pauseInterval = atoi(&argp[2]);;
+                               break;
+                   case 'h':
+                   default:
+                               usage(argv);
+               }
+       }
+       ptext.Data = (uint8 *)CSSM_MALLOC(MAX_TEXT_SIZE);
+       if(ptext.Data == NULL) {
+               printf("Insufficient heap space\n");
+               exit(1);
+       }
+       /* ptext length set in inner test loops */
+       
+       printf("Starting asymCompat; args: ");
+       for(i=1; i<argc; i++) {
+               printf("%s ", argv[i]);
+       }
+       printf("\n");
+       cspHand = cspDlDbStartup(bareCsp, NULL);
+       if(cspHand == 0) {
+               exit(1);
+       }
+       if(pauseInterval) {
+               fpurge(stdin);
+               printf("Top of test; hit CR to proceed: ");
+               getchar();
+       }
+       for(loop=1; ; loop++) {
+               if(!quiet) {
+                       if(verbose || ((loop % LOOP_NOTIFY) == 0)) {
+                               printf("...oloop %d\n", loop);
+                       }
+               }
+               
+               if(doRSA) {
+                       CSSM_ALGORITHMS sigAlg;
+                       if(loop & 1) {
+                               sigAlg = CSSM_ALGID_SHA1WithRSA;
+                       }
+                       else {
+                               sigAlg = CSSM_ALGID_MD5WithRSA;
+                       }
+                       
+                       /* enable RSA blinding on half the loops for RSA */
+                       CSSM_BOOL rsaBlinding = CSSM_FALSE;
+                       if(loop & 2) {
+                               rsaBlinding = CSSM_TRUE;
+                       }
+                       
+                       rtn = doTest(cspHand,
+                               CSSM_ALGID_RSA,
+                               sigAlg,
+                               sigLoops,
+                               encrLoops,
+                               rsaBlinding,
+                               &ptext,
+                               MAX_TEXT_SIZE,
+                               keySizeInBits,
+                               pubRefKeys,
+                               privRefKeys,
+                               bareCsp,
+                               quiet,
+                               verbose);
+                       if(rtn) {
+                               break;
+                       }
+               }
+               if(doDSA) {
+                       rtn = doTest(cspHand,
+                               CSSM_ALGID_DSA,
+                               CSSM_ALGID_SHA1WithDSA,
+                               sigLoops,
+                               0,                                      // encrLoops - none for DSA
+                               CSSM_FALSE,                     // blinding
+                               &ptext,
+                               MAX_TEXT_SIZE,
+                               keySizeInBits,
+                               pubRefKeys,
+                               privRefKeys,
+                               bareCsp,
+                               quiet,
+                               verbose);
+                       if(rtn) {
+                               break;
+                       }
+               }
+               if(oloops && (loop == oloops)) {
+                       break;
+               }
+               if(pauseInterval && (loop % pauseInterval) == 0) {
+                       fpurge(stdin);
+                       printf("hit CR to proceed: ");
+                       getchar();
+               }
+       }
+       
+       cspShutdown(cspHand, bareCsp);
+       if(pauseInterval) {
+               fpurge(stdin);
+               printf("ModuleDetach/Unload complete; hit CR to exit: ");
+               getchar();
+       }
+       if((rtn == 0) && !quiet) {
+               printf("%s test complete\n", argv[0]);
+       }
+       CSSM_FREE(ptext.Data);
+       return rtn;
+}
+
+